How to use OBS service cargo_vendor

What is it?

OBS is Open Build Service, a rather magnificant tool from openSUSE. It has the ability to run additional services which are scripts or programs to aid in the building of software packages. The one I've focused on here is obs-service-cargo_vendor.

Packaging Rust apps

The reason obs-service-cargo_vendor exists, is to aid packagers in maintaining Rust written applications. Typically these applications have many source dependencies (crates in Rust parlance) which are fetched from a crates repository. This makes developing Rust applications easier, particularly with the cargo tooling available. However, when packaging for a Linux distro you are almost always restricted from fetching such external sources and so a cargo tool named cargo-vendor exists - this will fetch only the required dependencies and plonk them in a ./vendor dir in your project.

Using obs-service-cargo_vendor and OBS services

If you have a Rust app you want to package which has standard tarball style releases it is fairly easy to get started. Create your RPM packaging as normal then follow these steps:

  1. Create a _service file with the following contents:
<services>
  <service name="cargo_vendor" mode="disabled">
  </service>
</services>

This file tells OBS there is a service to use, although currently it is set to disabled. The reason for this is only because OBS isn't completely set up to run this service on it's own yet. When it is you can change mode="disabled" to mode="buildtime" and OBS will run it automatically. The service can take arguments, but should autodetect everything you need.

  1. Step 1 produces two artifacts in the project directory: cargo_config and vendor.tar.* where the compression of vendor.tar is the same as the tarballed source you are using. You now need to modify the RPM spec file.

  2. Add the artifacts as source files:

Source1:        vendor.tar.xz
Source2:        cargo_config
  1. Adjust the %prep step:
%setup -qa1                 # extract all sources
mkdir .cargo                # cargo automatically uses this dir
cp %{SOURCE2} .cargo/config # and automatically uses this config
  1. Run osc service disabledrun to actually generate the artifacts cargo_config and vendor.tar.*. These need to be added to the repo with osc ar.

And that's pretty much all there is to it. But recently I wanted to use the obs_scm service in conjunction with cargo_vendor and have submitted a PR add the required modifications to cargo_vendor to make this easier. Using obs_scm is as above but with a _service file similar to the following:

<services>
  <service name="obs_scm" mode="disabled">
    <param name="scm">git</param>
    <param name="url">https://github.com/jwilm/alacritty.git</param>
    <param name="versionformat">%cd</param>
    <param name="changesgenerate">enable</param>
  </service>
  <service name="cargo_vendor" mode="disabled">
    <param name="compression">xz</param>
  </service>
  <service name="tar" mode="buildtime"/>
  <service name="recompress" mode="buildtime">
    <param name="file">*.tar</param>
    <param name="compression">xz</param>
  </service>
  <service name="set_version" mode="disabled"/>
</services>

A brief overview of this is obs_scm clones the sources from github, and adjusts the package version number in the spec file to %cd which is the current date. It also updates the package changelog with the git commit messages (you will want to edit this after). It will then run the cargo_vendor service, followed by tar, compression, and version setting.

Where mode= is set, this dictates when/how each service is run and helps prevent unrequired services running. buildtime will run when the package is built by OBS, and disabled will not run unless done so manually. For both _service examples here we need to run osc service disabledrun on our local machine and add the artifacts to the osc repo.

Service options and how it works

There are a few options that you can supply to the service. The default behaviour without these options is to autodetect the archive type, and in the case where a directory is found with a Cargo.toml in the root, then the default compression of gzip is used.

  • <param name="strategy">vendor</param>

The default here is vendor which will use cargo vendor to fetch the crate dependencies. As of this writing there is no alternative to this.

  • <param name="archive">archivename.tar.gz</param>

The name of the required archive. The option is used in the case where there may be multiple archives available in the package build. This can also be used to specify a directory - useful in the case of using the obs_scm service.

  • <param name="compression">xz</param>

The compression to use for the vendor.tar. If the option is not supplied it will default to gz or the same compression as the source archive. Available compressions are those supported by tar.

Example

<services>
  <service name="cargo_vendor" mode="disabled">
    <param name="strategy">vendor</param>
    <param name="archive">some_git_repo</param>
    <param name="compression">xz</param>
  </service>
</services>