How to use Snapcraft v2 on Trusty

There are currently two major versions of Snapcraft: v1 and v2. Snapcraft v1 creates snaps that target Ubuntu Core 15, and Snapcraft v2 creates snaps that target Ubuntu Core 16. Series 16 snaps are much more widely used, being supported not only in Ubuntu Core 16 but also classic Ubuntu Xenial (desktop and server) and more recently even Trusty! It's also supported across a range of other Linux distributions. However, while series 16 snaps can run in a number of places, currently Snapcraft v2 (which makes series 16 snaps) only runs in Xenial. The Trusty archives contains Snapcraft v1. For the vast majority of cases this works fine: build your snaps on Xenial, run them anywhere. However, there are cases when you really need to run Snapcraft on Trusty. Case in point: ROS (Robot Operating System) Indigo.

ROS maintains a number of releases at a time. The ones most heavily used tend to be the LTS releases: that is, the releases that correspond to the LTS releases of Ubuntu. There are two LTS versions of Ubuntu supported right now, Trusty and Xenial. The corresponding versions of ROS are Indigo and Kinetic, respectively.

These are the most popular releases because switching one's entire project to another release of ROS is not an easy task. In my experience, most teams tend to stick with a single release until it's either no longer supported or new versions introduce features they need. Indeed, this is backed up by the metrics presented at ROSCon last year: over 70% of ROS users are still using Indigo, and about 10% are using Kinetic.

This (among other things) has made making Snapcraft v2 available on Trusty a priority for us. However, due to the SRU process (i.e. the process of updating software in already-released versions of Ubuntu), it's not as simple as just releasing an update upgrading the Snapcraft v1 already in the Trusty archives to v2. There are a lot of dependencies that are Xenial-only. The perfect solution is to start shipping Snapcraft as a snap, which we're doing, but it's still early days there. When running the Snapcraft snap on Trusty, it's currently only intended to serve as an entry point into cleanbuild, which uses a Xenial container to build a snap. That won't work for Indigo: we need to build on Trusty, and use Trusty's archives for dependencies. We're still working out the kinks to support exactly that, but until then, I know some folks who are blocked by this. If you're part of that group, then this post is for you: I'll walk you through running Snapcraft v2 from source on Trusty.

Prerequisites

Python 3.5

Snapcraft uses circular imports, which means it requires at least Python v3.5. Trusty's archives have v3.4. In the Ruby community we run into this problem all the time, and have tools like rvm to solve it. Python has a similar tool: pyenv. We'll use it to get Python v3.5. First, you need git:

$ sudo apt install git

Now you can use the pyenv installer to get up and running (it places pyenv into ~/.pyenv):

$ curl -L https://raw.githubusercontent.com/pyenv/pyenv-installer/master/bin/pyenv-installer | bash

When that has finished, you'll see it recommending you place a few lines into ~/.bash_profile. I just placed those lines at the end of my ~/.bashrc:

export PATH="/home/ubuntu/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"

Now either start a new terminal session or simply re-source it, and verify that it works by running an update (which should do nothing other than say stuff is up-to-date):

$ source ~/.bashrc
$ pyenv update

pyenv will build Python, for which you'll need a few dependencies:

$ sudo apt install gcc make libssl-dev libbz2-dev libreadline-dev liblzma-dev libsqlite3-dev

Now we're ready to build Python v3.5, but we have a small issue. pyenv will build upstream Python, which doesn't actually detect Ubuntu correctly. Snapcraft does different things depending on the OS, so Ubuntu needs to be detected correctly. Fortunately there's a distro patch for that, so let's just use it. You'll need a few tools:

$ sudo apt install bzr patchutils

Now fetch the Ubuntu source for Python v3.5:

$ bzr branch lp:~doko/python/pkg3.5-debian

Alright, now let's get Python v3.5 (specifically v3.5.2, which is what's currently in Xenial), and tell pyenv to apply that distro patch before building:

$ cat pkg3.5-debian/patches/platform-lsbrelease.diff | filterdiff --strip=1 | pyenv install -p 3.5.2
Downloading Python-3.5.2.tar.xz...
-> https://www.python.org/ftp/python/3.5.2/Python-3.5.2.tar.xz
Installing Python-3.5.2...
patching file Lib/platform.py
Hunk #1 succeeded at 268 (offset 2 lines).
Hunk #2 succeeded at 297 (offset 2 lines).
Hunk #3 succeeded at 333 (offset 1 line).
patching file Lib/test/test_platform.py
Hunk #1 succeeded at 320 (offset 16 lines).
Installed Python-3.5.2 to /home/ubuntu/.pyenv/versions/3.5.2

Now you can see that you have multiple Python versions available (with the current one represented by the asterisk):

$ pyenv versions
* system (set by /home/ubuntu/.pyenv/version)
3.5.2

Let's go ahead and change the active one to 3.5.2:

$ pyenv global 3.5.2
$ pyenv versions
system
* 3.5.2 (set by /home/ubuntu/.pyenv/version)
$ python3 --version
Python 3.5.2

Now we're using v3.5.2. You can set it back later by using pyenv global system if you like.

libsodium

Snapcraft depends on libsodium for communication with the store, but it's only in the Xenial archives, not Trusty's. Thankfully there's a PPA that provides it:

$ sudo add-apt-repository ppa:chris-lea/libsodium
$ sudo apt update
$ sudo apt install libsodium-dev

Install Snapcraft

We're going to install Snapcraft via pip, as outlined in its hacking guide. Doing that on Trusty requires a few tweaks, so use my special trusty-support branch:

$ git clone -b trusty-support https://github.com/kyrofa/snapcraft
Cloning into 'snapcraft'...
remote: Counting objects: 18235, done.
remote: Compressing objects: 100% (26/26), done.
remote: Total 18235 (delta 9), reused 13 (delta 5), pack-reused 18204
Receiving objects: 100% (18235/18235), 6.84 MiB | 6.46 MiB/s, done.
Resolving deltas: 100% (12342/12342), done.
Checking connectivity... done.

Now install its dependencies (taken from the hacking guide):

$ sudo apt install g++ libffi-dev libapt-pkg-dev libarchive13

As far as how/where to actually install Snapcraft, that's up to you. Personally, I like to use virtualenv so I don't clutter my system. Pretty much exactly as outlined in the hacking guide:

$ mkdir ~/venv
$ python3 -m venv ~/venv/snapcraft
$ source ~/venv/snapcraft/bin/activate
(snapcraft) $ pip install --upgrade pip
(snapcraft) $ pip install -r requirements.txt .

As long as you're within that virtual environment (by sourcing its activate script) you'll have Snapcraft v2 available to you! Now you can go build your snaps like normal, but you're running on Trusty now, using the Trusty archives for stage-packages, etc. I've tested this specifically for ROS Indigo, but of course other things should work as well unless there's a hard dependency on Xenial. I hope this is helpful until the snap fully supports Trusty!

Comments