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(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(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 %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.
%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}