Ricky Kresslein

How to Package a Rust App on openSUSE’s OBS


There’s an app I love called espanso. It’s a text expander, like PhraseExpress, but it’s cross-platform, lightweight, and open-source. It’s one of the first applications I install when I install a new Linux distro.

When I used to use Arch, installing espanso was as easy as typing yay -S espanso into a terminal. However, on openSUSE Tumbleweed, espanso is not an official package and no one had packaged it in the Open Build Service (OBS). The only way to install espanso was with Snap.

For various reasons, I prefer not to use Snap when possible. I like having repos and everything installed using Zypper, to keep everything up to date with one simple command in one place on my system. I do have Flatpaks and Snaps, but I will work hard to use Zypper instead when possible.

So, for that reason and several others, I set out to teach myself how to use OBS. The best guide I found by far was this one by openSUSE, but I’m sure there are others as well. However, most of the tutorials were geared toward C++ or Python apps, not Rust.

The biggest issue with the OBS is that it cannot access the internet, so all packages must be built offline. Fortunately, Cargo makes it very easy to download all the dependencies of a Rust app to be used offline.

I didn’t plan on having such a long introduction, so let me get to the examples. There are three things you need in your OBS sources. The actual source code of the app as a tarball, a spec file, and a change log. The change log can be created using the command osc vc in a terminal. The source will need to be downloaded from the project’s website or their Github page. The spec file is the most difficult and important piece, so you can use the one I built for espanso as a template.


# spec file for package espanso
# Copyright (c) 2021 SUSE LLC
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
# Please submit bugfixes or comments via https://bugs.opensuse.org/
Name:           espanso
Version:        0.7.3
Release:        0
Summary:     A cross-platform Text Expander written in Rust
License:        GPL-3.0-only
Group:          Productivity/Text/Convertors
URL:            https://github.com/federico-terzi/espanso/archive/v%{version}.tar.gz
Source0:        %{name}-%{version}.tar.gz
Source1:        vendor.tar.gz
BuildRequires:  rust
BuildRequires:  cargo
BuildRequires:  gcc-c++
BuildRequires:  cmake
BuildRequires:  libopenssl-devel
BuildRequires:  git
BuildRequires:  libnotify4
BuildRequires:  libXtst6
BuildRequires:  libXtst-devel
BuildRequires:  xdotool
BuildRequires:  xdotool-devel
BuildRequires:  xclip
BuildRequires:  rust-packaging
Requires:       xclip
Requires:       xdotool
ExclusiveArch:  %{rust_arches}
%if %{__cargo_skip_build}
BuildArch:      noarch
A cross-platform Text Expander written in Rust. espanso detects when you type a keyword and replaces it while you're typing.
%autosetup -a1
%define cargo_registry $(pwd)/vendor
install -D -m 0755 target/release/%{name} \
%license LICENSE

For your project, you will obviously need to change the name, version, requirements, etc. The important part here is the second source, Source1: vendor.tar.gz. That is a tarball of all the rust crates, in unzipped folders.

Now, download all the dependencies. To do so, enter the package directory in a terminal and type cargo vendor. That will automatically download every required dependency to build the package offline. Zip that up into an archive named whatever you named it above in Source1. Then, add the following to the .cargo/config.toml file (if it doesn't exist, create it):

replace-with = "vendored-sources"
directory = "vendor"

That part may not be necessary, because the OBS may take care of it for you using the data you put in Source1, but better safe than sorry.

Once you have all the crates downloaded, you can go ahead and try building the package using the command osc build --local-package. This will do a trial build on your own computer so there is no need to upload it to the main server yet where the whole world can watch your build fail. Because it will fail. Mine failed many, many times.

Once it builds locally you can upload everything with osc commit and you should have a working repo for your Rust app that the world of openSUSE users can access and install on their own machines.

If you don’t use espanso already, or if you do and want an alternative to installing it via Snap, you can get it from my repo here.