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.
Dependencies
Vagrant plugins are essentially RubyGems so they require Ruby and RubyGems. They also require Vagrant to be present as well for both runtime and buildtime. Specify:
Requires: ruby(release) Requires: ruby(rubygems) Requires: vagrant BuildRequires: ruby(release) BuildRequires: rubygems BuildRequires: 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.
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.
%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}