diff --git a/doc/functions.xml b/doc/functions.xml index 1f2d00b9e1af..3b60f46d81da 100644 --- a/doc/functions.xml +++ b/doc/functions.xml @@ -16,6 +16,7 @@ + diff --git a/doc/functions/snaptools.xml b/doc/functions/snaptools.xml new file mode 100644 index 000000000000..a951c36730d3 --- /dev/null +++ b/doc/functions/snaptools.xml @@ -0,0 +1,74 @@ +
+ pkgs.snapTools + + + pkgs.snapTools is a set of functions for creating + Snapcraft images. Snap and Snapcraft is not used to perform these operations. + + +
+ The makeSnap Function + + + makeSnap takes a single named argument, + meta. This argument mirrors + the upstream + snap.yaml format exactly. + + + + The base should not be be specified, as + makeSnap will force set it. + + + + Currently, makeSnap does not support creating GUI + stubs. + +
+ +
+ Build a Hello World Snap + + + Making a Hello World Snap + + The following expression packages GNU Hello as a Snapcraft snap. + + + + nix-build this expression and install it with + snap install ./result --dangerous. + hello will now be the Snapcraft version of the package. + + +
+ +
+ Build a Hello World Snap + + + Making a Graphical Snap + + Graphical programs require many more integrations with the host. This + example uses Firefox as an example, because it is one of the most + complicated programs we could package. + + + + nix-build this expression and install it with + snap install ./result --dangerous. + nix-example-firefox will now be the Snapcraft version of + the Firefox package. + + + The specific meaning behind plugs can be looked up in the + Snapcraft + interface documentation. + + +
+
diff --git a/pkgs/build-support/snap/default.nix b/pkgs/build-support/snap/default.nix new file mode 100644 index 000000000000..ba5271868911 --- /dev/null +++ b/pkgs/build-support/snap/default.nix @@ -0,0 +1,4 @@ +{ callPackage, hello }: +{ + makeSnap = callPackage ./make-snap.nix { }; +} diff --git a/pkgs/build-support/snap/example-firefox.nix b/pkgs/build-support/snap/example-firefox.nix new file mode 100644 index 000000000000..d58c98a65a2e --- /dev/null +++ b/pkgs/build-support/snap/example-firefox.nix @@ -0,0 +1,28 @@ +let + inherit (import { }) snapTools firefox; +in snapTools.makeSnap { + meta = { + name = "nix-example-firefox"; + summary = firefox.meta.description; + architectures = [ "amd64" ]; + apps.nix-example-firefox = { + command = "${firefox}/bin/firefox"; + plugs = [ + "pulseaudio" + "camera" + "browser-support" + "avahi-observe" + "cups-control" + "desktop" + "desktop-legacy" + "gsettings" + "home" + "network" + "mount-observe" + "removable-media" + "x11" + ]; + }; + confinement = "strict"; + }; +} diff --git a/pkgs/build-support/snap/example-hello.nix b/pkgs/build-support/snap/example-hello.nix new file mode 100644 index 000000000000..123da80c5477 --- /dev/null +++ b/pkgs/build-support/snap/example-hello.nix @@ -0,0 +1,12 @@ +let + inherit (import { }) snapTools hello; +in snapTools.makeSnap { + meta = { + name = "hello"; + summary = hello.meta.description; + description = hello.meta.longDescription; + architectures = [ "amd64" ]; + confinement = "strict"; + apps.hello.command = "${hello}/bin/hello"; + }; +} diff --git a/pkgs/build-support/snap/make-snap.nix b/pkgs/build-support/snap/make-snap.nix new file mode 100644 index 000000000000..cef7500bcbaf --- /dev/null +++ b/pkgs/build-support/snap/make-snap.nix @@ -0,0 +1,84 @@ +{ + runCommand, squashfsTools, closureInfo, lib, jq, writeText +}: + +{ + # The meta parameter is the contents of the `snap.yaml`, NOT the + # `snapcraft.yaml`. + # + # - `snap.yaml` is what is inside of the final Snap, + # - `snapcraft.yaml` is used by `snapcraft` to build snaps + # + # Since we skip the `snapcraft` tool, we skip the `snapcraft.yaml` + # file. For more information: + # + # https://docs.snapcraft.io/snap-format + # + # Note: unsquashfs'ing an existing snap from the store can be helpful + # for determining what you you're missing. + # + meta +}: let + snap_yaml = let + # Validate the snap's meta contains a name. + # Also: automatically set the `base` parameter and the layout for + # the `/nix` bind. + validate = { name, ... } @ args: + args // { + # Combine the provided arguments with the required options. + + # base: built from https://github.com/NixOS/snapd-nix-base + # and published as The NixOS Foundation on the Snapcraft store. + base = "nix-base"; + layout = (args.layout or {}) // { + # Bind mount the Snap's root nix directory to `/nix` in the + # execution environment's filesystem namespace. + "/nix".bind = "$SNAP/nix"; + }; + }; + in writeText "snap.yaml" + (builtins.toJSON (validate meta)); + + # These are specifically required by snapd, so don't change them + # unless you've verified snapcraft / snapd can handle them. Best bet + # is to just mirror this list against how snapcraft creates images. + # from: https://github.com/snapcore/snapcraft/blob/b88e378148134383ffecf3658e3a940b67c9bcc9/snapcraft/internal/lifecycle/_packer.py#L96-L98 + mksquashfs_args = [ + "-noappend" "-comp" "xz" "-no-xattrs" "-no-fragments" + + # Note: We want -all-root every time, since all the files are + # owned by root anyway. This is true for Nix, but not true for + # other builds. + # from: https://github.com/snapcore/snapcraft/blob/b88e378148134383ffecf3658e3a940b67c9bcc9/snapcraft/internal/lifecycle/_packer.py#L100 + "-all-root" + ]; + +in runCommand "squashfs.img" { + nativeBuildInputs = [ squashfsTools jq ]; + + closureInfo = closureInfo { + rootPaths = [ snap_yaml ]; + }; +} '' + root=$PWD/root + mkdir $root + + ( + # Put the snap.yaml in to `/meta/snap.yaml`, setting the version + # to the hash part of the store path + mkdir $root/meta + version=$(echo $out | cut -d/ -f4 | cut -d- -f1) + cat ${snap_yaml} | jq ". + { version: \"$version\" }" \ + > $root/meta/snap.yaml + ) + + ( + # Copy the store closure in to the root + mkdir -p $root/nix/store + cat $closureInfo/store-paths | xargs -I{} cp -r {} $root/nix/store/ + ) + + # Generate the squashfs image. + mksquashfs $root $out \ + ${lib.concatStringsSep " " mksquashfs_args} +'' diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 09a2f6c391db..8cbe329d2e9b 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -175,6 +175,8 @@ in dockerTools = callPackage ../build-support/docker { }; + snapTools = callPackage ../build-support/snap { }; + nix-prefetch-docker = callPackage ../build-support/docker/nix-prefetch-docker.nix { }; docker-compose = python3Packages.callPackage ../applications/virtualization/docker-compose {};