Struggling to build a snap for PHP composer

I’m trying to build my first Snap for PHP composer, as it’s one of those pieces of software which is released too regularly for the normal Ubuntu packaging cycle to keep up, and so a Snap seems like a way of getting around this problem (I guess the other way would be a PPA?).

I’m using a clean Ubuntu 16.04 LTS VM (using Vagrant) for development.

Composer doesn’t have tagged releases on Git, the only way to reference a specific version is by using its commit hash. So far my snapcraft.yaml has the following:

name: composer
version: '1.7.2'
summary: PHP dependency management system
description: |
  Composer is a dependency management system for PHP libraries.

grade: devel
confinement: devmode

    command: composer

    plugin: dump
    source-type: git
    source-commit: 7cf90ec1d9540d586f6ac80babbc342033adf6b6

If I run snapcraft I get the following output:

Pulling composer-src 
Cloning into '/vagrant/composer/parts/composer-src/src'...
remote: Counting objects: 1915, done.
remote: Compressing objects: 100% (24/24), done.
remote: Total 1915 (delta 9), reused 21 (delta 4), pack-reused 1887
Receiving objects: 100% (1915/1915), 14.64 MiB | 4.14 MiB/s, done.
Resolving deltas: 100% (989/989), done.
Checking connectivity... done.
Note: checking out '7cf90ec1d9540d586f6ac80babbc342033adf6b6'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b <new-branch-name>

HEAD is now at 7cf90ec... Add 1.7.2 build
Building composer-src 
Staging composer-src 
Priming composer-src 
Failed to generate snap metadata: The specified command 'composer' defined in the app 'composer' does not exist or is not executable

I’m not sure how to accomplish the next steps though. If I was installing composer manually I would run:

php parts/composer-src/src/web/installer

This creates a composer.phar file in the current directory, which I would then copy to somewhere in $PATH.

What is the best way to accomplish this in Snap? Or is Snap completely the wrong tool for this task and I should be looking at a PPA instead? :slight_smile:

This indicates that the composer command isn’t available in the snap’s runtime command search PATHs: PATH="$SNAP/usr/sbin:$SNAP/usr/bin:$SNAP/sbin:$SNAP/bin:$PATH" and thus Snapcraft bails out with error.

I would suggest creating the file in the composer-src part’s override-build scriptlet and move it to $SNAPCRAFT_PART_INSTALL/bin/composer, which will end up at the proper location of the executable search path $SNAP/bin. Note that composer needs to have the executable bit set.

Thanks, I’ve managed to get an override-build script set as follows:

override-build: |
      snapcraftctl build
      /usr/bin/php web/installer
      mv composer.phar $SNAPCRAFT_PART_INSTALL/bin/composer

That works, in that I end up with a composer_1.7.2_amd64.snap file which I can install. However, when I do so and run composer I get the following error:

/usr/bin/env: 'php': No such file or directory

Presumably that’s because I haven’t set the executable bit. How would I do that in Snap? I’ve tried adding a chmod 755 composer.phar line before the mv composer.phar command but that blows up with an error message:

Snapping 'composer' /                                            

Read failed because Protocol error

Read on destination failed

Failed to checksum data from output filesystem

FATAL ERROR:Output filesystem corrupted?
Parallel mksquashfs: Using 2 processors
Creating 4.0 filesystem on composer_1.7.2_amd64.snap, block size 131072.
[==============/                                                 ] 200/886  22%
Sorry, Snapcraft ran into an error when trying to running through its
lifecycle that generated a trace that has been put in '/tmp/tmpvr2y2u64/trace.txt'.
You can anonymously report this issue to the snapcraft developers.
No other data than this traceback and the version of snapcraft in
use will be sent.
Would you like send this error data? (Yes/No/Always) [no]: 

The problem is not about the executable bit, but the PHP interpreter isn’t shipped via the snap (snap can’t access most of the programs outside the snap, if you requires one you must bundle it in the snap)

Add the PHP interpreter package to the stage-packages and try again.

1 Like

if you call this you need to make sure that a package shipping /usr/bin/php is listed in your build-packages: … you likely want the php7.0-cli package …

1 Like

I’ve added php-cli to both stage-packages and build-packages but I’m still getting the same error. I’ve also tried debugging the composer command:

$ which composer
$ ls -l /snap/bin/composer 
lrwxrwxrwx 1 root root 13 Sep  2 19:54 /snap/bin/composer -> /usr/bin/snap
$ /snap/bin/composer 
/usr/bin/env: 'php': No such file or directory

However, the following command does work:

$ /snap/composer/current/bin/composer --version
Composer version 1.7.2 2018-08-16 16:57:12

Check the prime/ folder for the exact files that will appear in the final snap. For instance, the php executable should be available at prime/usr/bin/php .

That will work because composer is run by the host’s PHP interpreter, which won’t be the case for other snap users who can only access the in-snap PHP interpreter.

Always use snap run _snap_name_ or snap run _snap_name_._app_name_ to simulate an execution.

There isn’t a php executable at prime/usr/bin/php, there is only prime/usr/bin/php7.0. I don’t understand why because if I install php-cli outside of Snap then /usr/bin/php works (it symlinks to /etc/alternatives/php which in turn points to /usr/bin/php7.0). Do symlinks not work in Snap?

Likely not as snap doesn’t use the Debian’s alternative system and just simply extract all the stage-packages’ content to the stage/ folder, you’ll have to create a symbolic link yourself in the override-stage scriptlet:

    override-stage: |
      set -eu

      snapcraftctl stage

      ln \
        --force \
        --verbose \
        php7.0 \

NOTE: In stage step the working directory is the stage/ folder (a.k.a. $SNAPCRAFT_STAGE )

Okay, that sounds like Snap isn’t a good solution for this problem then if I end up having to manually redo everything that the Debian packaging system does for potentially every dependency (if it uses the alternatives system). I’ll just use a local installation of Composer instead.

Thanks for your help anyway.

@pwaring It would probably need to be a classic snap because composer relies on your PHP installation and it wouldn’t make sense to bundle PHP alongside composer because people may want to use different versions, etc.

I still think this is doable though.