Install system dependencies as snap runtime environment

Hello I have a shell script which installs several system dependencies using complicated shell commands both as a build and runtime environments. I want to implement the following behaviour:

When a user installs my snap: sudo snap install mysnap

This should first run my script to make all system dependencies ready. Then it should run another script which builds my project and installs a systemd service. I also need to access network, $HOME and tpm interfaces during build and runtime.

Is this possible to implement with Snap?

while this is technically possible (but very complex), you would normally not do any build steps on the users machine but deliver everything needed as binaries and have your code set up in a way that you can adjust it via configuration options.

that said, you could take a look at my nore-red-rpi package which ships a toolchain and build dependencies inside to allow npm install ... to work …

this needs a pretty complex setup of the environment variables to make the toolchain work though …

but i’d really suggest pre-building all binaries and properly shipping all dependencies without running any build scripts on the users box, the other way is putting a massive amount of complex maintenance work on you to manage updates etc …

1 Like

I’d agree with Ogra, is it doable; yes. Is it ideal? Not really, try avoid it for your own sanity. The whole point of snaps is that a single build should ideally work everywhere, so it doesn’t really make sense to build something in the Snap runtime environment itself in the vast majority of scenarios.

I have a snap that like Ogra’s NodeRed snap bundles GCC & friends, and infact, it’s core functionality is actually acting as a C++ Interpreter. It works very well for certain tasks, but absolutely can’t be made workable for others. (ROOT snap incase you’re curious).

Particularly, what you’re likely to experience is that the build systems will make assumptions about the snap layout that will break constantly. The most trivial example will be that you’ll likely find libraries/scripts/etc end up hardcoding $SNAP or $SNAP_USER_DATA as if it was a constant, and then anytime you’ll push an update, it’ll break any compiled packages for everyone, since they now can’t find binaries/libraries/config/etc.

Managing that properly is difficult at best, and likely impossible in some scenarios.

So can it be done? Sure. Is it recommended? Absolutely not, unless there’s some significant advantages elsewhere to it.

Hello thanks for the tips. I am trying to package an Elixir project which has several important system dependencies such has OpenSSL, Libsodium, nodejs etc. Also I need to install Scylladb database with predefined configuration in the user’s machine. How do I package/ship all these within a single installable snap folder?

you make a part for each of these in your snapcraft.yaml …

So any dependencies I install in a part (database for ex.) will be still available at runtime for my service?

right, you might need to make adjustments in their configs to adapt to the snap environment indeed …

Thanks. One last thing, suppose if I run some commands under override-stage, will they also run when user installs my snap? I want to setup database configurations at user’s end during my snap’s installation.

for doing things at install time you would use a hook:

note though that things done there are global to your snap … if there is something that should be user specific, you would use a command-chain script that processes everything as the user on first start of your application …