From Fedora Project Wiki
No edit summary
Line 7: Line 7:
=== Dependencies ===
=== Dependencies ===


Vagrant plugins are essentially RubyGems so they '''must''' require Ruby and RubyGems packages. They also '''must''' require Vagrant for runtime, buildtime, %posttrans and %preun actions. Specify:
Vagrant plugins are essentially RubyGems so they '''must''' require Ruby and RubyGems packages. They also '''must''' require Vagrant for runtime, buildtime, %posttrans and %preun actions. And it '''must''' require <code>shadow-utils</code> package for %pre action. This can be specifed as:


<pre>
<pre>

Revision as of 12:56, 3 November 2015

This page is a draft only
It is still under construction and content may change. Do not rely on the information on this page.

Vagrant plugins are esentially RubyGems that are installed to a specific Vagrant plugin directory and that need to be registered in Vagrant plugin configuration file upon installation. As most of the RubyGems guidelines apply to them, this guide discusses only specifics in which Vagrant plugins differ.

Requirements

Dependencies

Vagrant plugins are essentially RubyGems so they must require Ruby and RubyGems packages. They also must require Vagrant for runtime, buildtime, %posttrans and %preun actions. And it must require shadow-utils package for %pre action. This can be specifed as:

Requires: ruby(release)
Requires: ruby(rubygems)
Requires: vagrant
BuildRequires: ruby(release)
BuildRequires: ruby
BuildRequires: rubygems
BuildRequires: vagrant
Requires(pre): shadow-utils
Requires(posttrans): vagrant
Requires(preun): vagrant

Vagrant and its plugins current does not work with alternative Ruby interpreters, but you do not need to specify the requirement on ruby package in plugins spec files though.

Provides

All Vagrant plugins must provide vagrant(%{vagrant_plugin_name}) virtual provide. This effectively replaces the rubygem(%{gem_name}) required for RubyGems packages.

Provides: vagrant(%{vagrant_plugin_name}) = %{version}

Naming Guidelines

Plugins should follow upstream name that usually starts with vagrant-. Do not add the rubygem- prefix.

Macros

Vagrant plugins must be installed to certain standard locations. The vagrant package contains usuful macros that should be used to achieve that.

Macro Expanded path Usage
From vagrant; intended for Vagrant plugin packages.
%{vagrant_dir} %{_datadir}/vagrant Vagrant installation directory.
%{vagrant_plugin_conf_dir} %{_sharedstatedir}/vagrant Plugin configuration files.
%{vagrant_plugin_conf} %{vagrant_plugin_conf_dir}/plugins.json Configuration file for system-wide plugins.
%{vagrant_plugin_dir} %{vagrant_dir}/gems Common locations for Vagrant plugin gems.
%{vagrant_plugin_instdir} %{vagrant_plugin_dir}/gems/%{vagrant_plugin_name}-%{version} Directory with the actual content of the plugin.
%{vagrant_plugin_libdir} %{vagrant_plugin_instdir}/lib The lib folder of the plugin.
%{vagrant_plugin_cache} %{vagrant_plugin_dir}/cache/%{vagrant_plugin_name}-%{version}.gem The cached plugin.
%{vagrant_plugin_spec} %{vagrant_plugin_dir}/specifications/%{vagrant_plugin_name}-%{version}.gemspec The plugin's specification file.
%{vagrant_plugin_docdir} %{vagrant_plugin_dir}/doc/%{vagrant_plugin_name}-%{version} The rdoc documentation of the plugin.
%{vagrant_plugin_extdir} %{_libdir}/vagrant/gems/ruby/%{vagrant_plugin_name}-%{version} The directory for MRI Ruby plugin extensions. Currently unused.

Building Vagrant plugins

A sample spec for building a Vagrant plugin would look like this:

%global vagrant_plugin_name vagrant-registration

Name: %{vagrant_plugin_name}
Version: 0.0.19
Release: 2%{?dist}
Summary: Automatic guest registration for Vagrant
Group: Development/Languages
License: GPLv2
URL: https://rubygems.org/gems/vagrant-registration 
Source0: https://rubygems.org/gems/%{vagrant_plugin_name}-%{version}.gem
Requires(pre): shadow-utils
Requires(posttrans): vagrant
Requires(preun): vagrant
Requires: ruby(release)
Requires: ruby(rubygems) >= 1.3.6
Requires: vagrant
BuildRequires: ruby(release)
BuildRequires: rubygems-devel >= 1.3.6
BuildRequires: ruby 
BuildRequires: vagrant
BuildArch: noarch
Provides: vagrant(%{vagrant_plugin_name}) = %{version}

%description
Enables guests to be registered automatically which is especially useful
for RHEL or SLES guests.

%package doc
Summary: Documentation for %{name}
Group: Documentation
Requires: %{name} = %{version}-%{release}
BuildArch: noarch

%description doc
Documentation for %{name}.

%prep
gem unpack %{SOURCE0}

%setup -q -D -T -n  %{vagrant_plugin_name}-%{version}

gem spec %{SOURCE0} -l --ruby > %{vagrant_plugin_name}.gemspec

%build
# Create the gem as gem install only works on a gem file
gem build %{vagrant_plugin_name}.gemspec
%vagrant_plugin_install

%install
mkdir -p %{buildroot}%{vagrant_plugin_dir}
cp -a .%{vagrant_plugin_dir}/* \
        %{buildroot}%{vagrant_plugin_dir}/

# We can't run test suite because it requires virtualization
%check
pushd .%{vagrant_plugin_instdir}

popd

%pre
getent group vagrant >/dev/null || groupadd -r vagrant

%posttrans
%vagrant_plugin_register %{vagrant_plugin_name}

%preun
%vagrant_plugin_unregister %{vagrant_plugin_name}

%files
%license %{vagrant_plugin_instdir}/LICENSE.md
%{vagrant_plugin_instdir}/plugins/*
%{vagrant_plugin_libdir}
%exclude %{vagrant_plugin_cache}
%{vagrant_plugin_spec}

%files doc
%doc %{vagrant_plugin_instdir}/README.md
%doc %{vagrant_plugin_instdir}/CHANGELOG.md
%doc %{vagrant_plugin_docdir}
%{vagrant_plugin_instdir}/Rakefile
%{vagrant_plugin_instdir}/Gemfile
%{vagrant_plugin_instdir}/vagrant-registration.gemspec
%{vagrant_plugin_instdir}/tests

%changelog

%prep

Since gems aren't an archive format that RPM recognizes, the first thing we have to do is explicitly use gem unpack to extract the source from the gem. Then we call %setup -n %{vagrant_plugin_name}-%{version} to tell RPM what the directory the gem has unpacked into. The -T and -D flags tell %setup that we've already unpacked the code

We then run gem spec to output the metadata from the gem into a file. This .gemspec file will be used to rebuild the gem later. If we need to modify the .gemspec (for instance, if the version of dependencies is wrong for Fedora or the .gemspec is using old, no longer supported fields) we would do it here. Patches to the code itself can also be done here.

%build

Next we build the gem. Because %vagrant_plugin_install only operates on gem archives, we next recreate the gem with gem build. The gem file that is created is then used by %vagrant_plugin_install to build and install the code into the temporary directory, which is ./%{vagrant_plugin_dir} by default. We do this because the %vagrant_plugin_install command both builds and installs the code in one step so we need to have a temporary directory to place the built sources before installing them in %install section.

%vagrant_plugin_install macro accepts two additional options:

-n <gem_file>
Allows to override gem used for installation. This might get useful for converting legacy spec, so you might specify %{SOURCE0} as a gem for installation.
-d <install_dir>
Might override the gem installation destination. However we do not suggest to use this option.
The %vagrant_plugin_install macro must not be used to install into the %{buildroot}

%install

Here we actually install the plugin files into the %{buildroot}. We create the directories that we need and then copy what was installed into the temporary directories into the %{buildroot} hierarchy.

%check

In check section we execute the test suite if we can. This is often not possible because Vagrant requires virtualization to run.

%pre

In the %pre section we must check that vargant group exists. If not, we create it. This is why we required shadow-utils package earlier.

To do so, we write:

getent group vagrant >/dev/null || groupadd -r vagrant

%posttrans

After the files are installed we still need to tell Vagrant about the new plugin that has been installed and register it. There is %vagrant_plugin_register macro that must be used.

%vagrant_plugin_register %{vagrant_plugin_name}

%preun

After the files are uninstalled we still need to tell Vagrant about the plugin being removed and unregister it. There is %vagrant_plugin_unregister macro that must be used.

%vagrant_plugin_unregister %{vagrant_plugin_name}