Syntax for build-snaps


For those not aware, we are planning on supporting build-snaps as a core primitive for for parts in snapcraft.yaml.

The behavior for this entry would be very similar to build-packages, which at the time of this writing installs deb packages with apt from the archive in order to build the parts in a snapcraft.yaml (in the future and combined with bases we will support more formats like rpm through dnf).

This new entry adds the possibility to similarly install snaps to satisfy building requirements for a part, such that, instead of for example installing go from the apt archive we could alternatively install go as a snap.


There is not much more to say but define the syntax, which to keep simple (solving the case of the majorities) could be something like:

        source: .
        plugin: make
        build-snaps: [go] 

Which would install go from the implicit latest track.
Now what if we want to specify a different track, a risk level or a branch?
My proposal would be to do <snap-name>/<channel>, so for the case of wanting to use go from the 1.7 track, we would write something like:

        source: .
        plugin: make
            - go/1.7

The <channel> semantics should behave just like it does across the ecosystem for the snap and snapcraft command.


Awesome, I’m really looking forward to that!

+1 to the suggested syntax

The proposal seems to mix ‘channel’ and ‘track’. The example is certainly
using a track. How do you intend to disambiguate between channels and
tracks in the syntax? (Is it legal to have a ‘stable’ track, or are the
names of channels reserved so that they are never used as track names?)

What does the syntax look like if you specify both a channel and a track?
You say that the semantics should be the same as for the snap and snapcraft
commands, but I’m not familiar with usage of either of these that
concatenate package+track+channel into a single string. (E.g. snap takes a
–channel= argument.)

1 Like

A channel is comprised of Track, Risk and Branch and has a well-defined syntax: track/risk/branch

where track and branch are optional - track defaults to 'latest', risk is one of [stable, candidate, beta, edge] and branch is empty.

So one can snap install foo --channel 2.0/stable/fix-the-problem (or indeed build-snaps: [foo@2.0/stable/fix-the-problem])


A channel is a triplet of <track>/<risk>/<branch>, the track is implicitly latest if not defined and the branch is optional. So if all these combinations would be possible

  • go@beta would get go from beta on the latest track
  • go@1.6/edge would get go from edge on the 1.6 track.
  • go@1.7/stable/hotfix-1 would get go from the hotfix-1 branch
  • go@stable/hotfix-2 would get go from the hotfix-2 branch

These are all cases supported today by snapcraft and snap/snapd


I understand that base snaps will let us bring rpm into the picture, but what happens if a build-snap specifies a base:?

1 Like

What about the confinement type of a build snap? go requires --classic to be installed. Should that be specified in the YAML as well?

Why would that be needed? snapcraft can determine if the given snap (revision) requires classic or not, and Do The Right Thing™ - there’s nothing that the user is usefully controlling by specifying the confinement type.

It would install that snap using it’s preferred base, and execute the commands that are exposed to the build environment as it would with a homogeneous base. Is there a problem you foresee?

classic snaps are not installable on ubuntu core (not even inside the classic mode there), so you could not build on a core system …

though i think a proper error message that “go is not installable on this system” would be sufficient, no need to have any additional tag in the yaml IMHO

1 Like

The classic flag exists for security reasons, though. Having it be magically implied in build-snaps doesn’t sound clearly safe.


snapcraft isn’t installable on Ubuntu Core either.

1 Like

not true, i use its deb every day inside the classic mode :wink:

1 Like

Well, it the snap command provides the appropriate error message it should be fine.


I’m on the fence between, say, go@1.7/stable and go/1.7/stable… the latter seems more clear for some reason. Perhaps because it gives a feeling of parenthood with stable/1.7 being under “go”, which more correctly reflects reality than the idea of go@1.7/stable, which makes it feel slightly like 1.7/stable is a place where we can find more things than simply go itself. The use of a single punctuation character also feels like a win in this case… less noise.

I’ve just been trying to come up with potential issues that might exist with this syntax. So far it seems fine, because we never have a context where both a channel and a snap name would make sense. So the potential ambiguity which might happen with snap name being interpreted as a track is irrelevant.

So yeah, this feels a bit nicer. Can anyone come up with relevant issues with that?

If that goes forward, we should accept it in the command line as well.

As others pointed out, there’s a bit of confusion here. We have a good document explaining the terminology in detail.

The base should be installed just as usual.

As @wgrant pointed out, it would not make sense to allow them to be installed by default. I suggest supporting a flag such as –allow-classic in snapcraft which would enable these snaps to be installed, and when it’s not provided failing with a clear message.

Agreed. Would just like to emphasize here that bases are strictly defined rather than just preferred.


Interesting that you propose / as a separator, I had the same initial thought and actually had a presentation with that for some reason (instead of using channel) a couple of days ago.

I am all aboard with the proposal, it has a nice launchpad/bzr series connotation to it. If it technically works (I think it does), then yeah, let’s use it. For snapcraft the work would probably be to support

snapcraft release go/1.8 5

Today that is (<snap-name> <revisions> <channel>):

snapcraft release go 5 1.8

I don’t see us changing this though:

snapcraft push go.snap --release 1.8

Which could be confusing to the causal user.

The only reason to choose @ is the way you would read it go at 1.8.

This would need UI integration though. In my mind I was of the thought that 80% of the build-snaps would be classic snaps, this conversation however triggered in my mind that we also want some mechanism to connect required interfaces for the cases of confined snaps.

Can we approach this conversation similarly to the conversation about privileged/unprivileged users by applying language to snapcraft.yaml instead.

I don’t see how that’s an issue for These are VMs specifically prepared for building things, which need to install debs, rpms, classic snaps, or whatever else is necessary for getting the thing to build.

We’ll need to discuss this in more details as it seems to cross a strange line between building a piece of software and modifying the host system.

It’s not just about compromising an existing host system, but also about dirtying or compromising a build. My snapcraft.yaml might use some weird network client snap to acquire a signed build resource, but not want to trust that snap with full access to the system – either because the snap publisher is not 100% trustworthy, or because it has complex protocol handling C code that probably has vulnerabilities so should be sandboxed.

As @sergiusens says, we’ll also need to handle connections, and probably devmode as well, so it seems like a single top-level flag is insufficient regardless.

A full YAML installation specification sounds potentially useful in general. A model assertion or system management tool needs the same sort of behaviour that snapcraft.yaml does.