Scriptlets


#1

Scriptlets are shell scripts sourced directly from your snapcraft.yaml, to change the behaviour of a plugin as it builds its part. Each step of the part’s lifecycle (pull, build, stage, and prime) can be customised. These scripts are run with /bin/sh, which by default on Ubuntu is dash.

Scriptlets are declared with the following syntax:

parts:
  <part name>:
    <scriptlet keyword>: <shell script>

You can use a pipe on the first line to declare a multi-line script:

parts:
  <part name>:
    <scriptlet keyword>: |
      <multi-line>
      <shell script>

Overriding the pull step

This can be done by utilising the override-pull scriptlet. Its working directory is the part’s source directory in parts/<part name>/src/. In order to run the default pull step, call snapcraftctl pull from within the scriptlet.

Example

Let’s say you want to patch the source code of the part you’re pulling:

parts:
  foo:
    plugin: dump
    # ...
    override-pull: |
      snapcraftctl pull
      patch -p1 < $SNAPCRAFT_STAGE/my.patch

Overriding the build step

This can be done by utilising the override-build scriptlet. Its working directory is the part’s base build directory in parts/<part name>/build/. In order to run the default build step, call snapcraftctl build from within the scriptlet.

Example

Let’s say the default build/install process ends up installing files with absolute paths in them, which need to be fixed up to look inside the snap:

parts:
  foo:
    plugin: dump
    # ...
    override-build: |
      snapcraftctl build
      sed -i 's|/usr/bin|$SNAP/usr/bin|g' $SNAPCRAFT_PART_INSTALL/my-bin-artifact.sh

Overriding the stage step

This can be done by utilising the override-stage scriptlet. Its working directory is the staging area in stage/. In order to run the default stage step, call snapcraftctl stage from within the scriptlet.

Example

Let’s say you wanted to tweak a file installed by another part:

parts:
  foo:
    plugin: dump
    # ...
    after: [other-part]
    override-stage: |
      snapcraftctl stage
      sed -i 's|/usr/bin|$SNAP/usr/bin|g' other/parts/file

Overriding the prime step

This can be done by utilising the override-prime scriptlet. Its working directory is the primeing area in prime/. In order to run the default prime step, call snapcraftctl prime from within the scriptlet.

Example

Let’s say you wanted to compile gsetting schemas for the entire priming area

parts:
  foo:
    plugin: nil
    after: [all, other, parts]
    override-prime: |
      snapcraftctl prime
      glib-compile-schemas usr/share/glib-2.0/schemas

Please help me with my snap
Deprecation notice: 7
Snap Documentation (page deprecated)
Parts environment variables
Struggling to build a snap for PHP composer
Snapcraft implicit source
Building a Python Snap Package
Deprecation notices
GNU Hello (again, for snapcrafters)
Using external metadata
Set version from command line?
Snap documentation
Using parts
Parts lifecycle
#2

Should this mention that the scriptlet is dash (not bash)?


#3

What, that matters? Aren’t these all the same? cough fixed thanks :slight_smile: .


#4

Please add a list of all the steps and what overriding each one will prevent from occurring unless you add the snapcraftctl $step to reinstate the default behaviour of the plugin.


#5

Thanks for the docs, Kyle! We should link into this from somewhere in the publication docs.

Another idea: can we rename “snapcraftctl” to “craftctl” perhaps? The former seems a bit over-verbose.


#6

@niemeyer you mean from the outline topic? Yeah, we should chat about how to best organize that, I figured I’d start with just adding the info for now.

Regarding the name, we wanted to mirror the snap -> snapctl relationship with snapcraft -> snapcraftctl. It’s a bit long, perhaps, but it’s intuitive: in snap, use snapctl to communicate with the orchestrator of the snap (snapd), in snapcraft, use snapcraftctl to communicate with the orchestrator of the build (snapcraft).

When I see *ctl, I think “it controls something.” What does it control? Intuitively, the *. So for snapctl, it controls the snap (its services, its config, etc.). For snapcraftctl, it controls snapcraft. For craftctl, I ask “what is craft?”


#7

I can see the relationship, but these tools are different, and unless you know how to use it and where you can use it, there’s no way to just guess. Having something nice to read and write sounds more important than just mimicking the etymology.


#8

How to find out project root or location of snapcraft.yml? I don’t see any environment variables pointing to it. Why? There is a custom version file in project root, maintained by other people, and all parts should be built for version specified there.

I am doing out of tree builds, and usual “parent of stage” doesn’t work here.


#9

Added SNAPCRAFT_PROJECT_DIR is a part of “out of tree build” PR.

Tests are not easy.


#10

I would like to ask if the shell environment of the scriptlet has defined any shell options like errexit and nounset?

UPDATE: It seems that only errexit is enforced:


#11

while we should stop execution on errors, nounset should really be in the hands of the developer (i personally am for example not a fan of it since it makes scripts a lot bigger and harder to read if you have to zero-init variables everywhere)


#12

@degville hey there! Just had a thought about making this less about scriptlets and more about overriding steps.


#13

Good idea! I’ve linked to this from the new Snapcraft build, debug and publishing docs roadmap plan we have so we can update this page to reflect that ideal.


#14

This is helpful, but for me at least left me with more questions. The content by Dan at Proposal: Expose SNAPCRAFT_SNAP and SNAPCRAFT_PARTS environment variables completed the picture on how to apply a patch.


#15

@degville hey, just a mention that the prime example is missing a call to snapcraftctl prime.
I would fix it myself, but I have no edit button :slight_smile:


#16

Thanks! I’ve made this a wiki and added the missing command.


#17

The proper way to apply a patch is to install them to the /stage tree by a different part and applying them in the consuming part’s override-{pull,build} scriptlets, refer the following one for an example: