SNAP bundle della Canonical

Distribuire software per Linux e' reso complicato dal fatto che le distribuzione di Linux sono tutte diverse, essenzialmente per le diverse versioni delle librerie shared. Per cui un programma compilato su una distribuzione, non e' detto che vada su un'altra; non trova le librerie della giusta versione. Bisogna ricompilare, cosa che, per programmi complicati, non e' cosi' semplice. Risolvere eventuali problemi può' non essere alla portata dell'utente medio.

Per ovviare a questo la Canonical (quella che fa Ubuntu) si e' inventata gli "snap bundle" , cioè' dei pacchetti che si portano dietro tutte le librerie da cui dipendono, per cui dovrebbero andare su tutte le distribuzioni. Inoltre non seminano files qua' e la' per tutto il sistema, ma solo in pochi posti predefiniti (vedi snapcraft.io ).

C'e' un archivio, con tutti gli snap, lo lo "snap store" , ed un servizio, il "daemon snapd" Questo offre il comando snap che gestisce questi pacchetti, li scarica dallo snap store, controlla dove scrivono, e soprattutto gestisce l'interazione col sistema Questo e' fatto con un sistema di "slots" e "plugs", che sono canali per la connessione all'audio, alla grafica, ai files del sistema etc. etc..

Sul sito snapcraft.io , c'è' un po' di documentazione, ma veri manuali, con la scusa che nessuno li leggeva, nessuno li scrive più' e sembrano ormai passati di moda. Pero' alla fine di ogni pagina c'è' il link con la scritta "Help improve this document in the forum", cioe' sperano che la documentazione gliela facciano gli utenti e certe cose infatti bisogna andarsele a cercare nel forum, sperando che ci siano.

Comando snap

Vediamo brevemente gli utilizza principali del comando snap, che si interfaccia con il daemon snapd e permette di installare, rimuovere, cercare gli snap, e ha altre funzioni, un po' documentate sul sito della Canonical. Quasi tutte le distribuzioni di Linux hanno un pacchetto che installa snapd, vedi: https://snapcraft.io/snapd. In ogni modo qui tutto e' "open source" e snapd si trova su github

Struttura degli snap

Sono dei filesystem, compressi, di tipo SquashFS. Si espandono col comando unsquashfs, mentre mksquashfs permette di crearli.

snapd li scarica in /var/lib/snapd/snaps , e poi li monta , in sola lettura, sotto la directory (cartella) /snap. Se volete guardare come sono i vostri snap andate a curiosare nella directory , c'e' una sottocartella per ogni snap installato con sottocartelle per le diverse versioni, "current" punta all'ultima. La descrizione del formato bisogna cercarsela nel forum

Assieme all'applicativo vero e proprio ci sono varie cartelle; meta/ e snap/ contengono dei metadati (informazioni ausiliarie sull'applicativo) e informazioni su come lo snap e' stato creato. Ci sono poi le tipiche cartelle con librerie di sistema tipo: lib/ , lib64/, lib32/ una cartrella etc/ per le configurazioni, poi bin/ *usr/ , trovo anche un usr/share/man/ ed usr/share/doc/ che non so proprio cosa ci stia a fare, visto che nessuno andrà mai a cercarsi li' della documentazione, ma forse l'hanno messa per problemi legali, c'è' il file con il copyright di ogni cosa. Insomma c'è' un vero e proprio mini sistema.

Assieme agli snap che avete installato c'è' qualcosa come "core20", "core22", che sono dei mini-Ubuntu (le long term releases) che servono per ricreare l'ambiente virtuale in cui far correre l'applicativo.

L'applicativo corre in genere in un ambiente isolato; il sistema apparmor e' utilizzato per definire in modo puntuale a cosa l'applicazione puo' accedere, in /var/lib/snapd/apparmor/profiles ci sono files per ogni snap installato.

In certi sistemi occorre abilitare questi "profili apparmor" con:

apparmor_parser /var/lib/snapd/apparmor/profiles/*

Nell'ambiente dell'applicazione sono anche definite parecchie variabili di shell, utilizzabili entro l'applicazione, fra queste: ( "~" indica la cartella home dell'utente)

Le directory di cui sopra sono posti in cui lo snap puo' leggere e scrivere. Quelle "common" servono per dati comuni alle diverse versioni dello snap, le altre per dati dell'ultima versione.

Per far correre gli snap ci sono links in /snap/bin, in genere si mette /snap/bin nella variabile $PATH (lista cartelle in cui si cercano i programmi), poi basta digitare il nome dello snap.

Procurarsi un account

Se volete pubblicare il vostro snap sullo snap store della Canonical vi conviene, da subito, procurarvi un account. andando sul sito:

http://snapcraft.io/account

Poi guardate se il nome scelto per il programmam e'già in uso. Per vederlo si prova a registrare il nome in:

https://snapcraft.io/register-snap

Se il nome e' già un uso dovrete sceglierne un altro, altrimenti avete già' a disposizione una pagina di tipo :

https://snapcraft.io/nomesnap (qui nomesnap e' il nome del vostro applicativo):

Questa pagina verrà' poi usata per la descrizione dello snap che apparirà' nello snap store

Creare gli snap

Gli snap si creano col programma snapcraft, che e' distribuito lui stesso come uno snap. Per cui come prima cosa si fa: "snap install snapcraft". Conviene utilizzare una macchina con installato Ubuntu, la "long version support" ad esempio la 22.04. Con una distribuzione diversa può' sorgere qualche difficolta' in piu'. Eventualmente uno si fa una macchina virtuale dedicata alla creazione di snap, con Virtualbox e' relativamente facile.

In snapcraft.io potete trovare una guida per costruire gli snap

Essenzialmente:

Il file snapcraft.yaml

La struttura del file e' descritta in: https://snapcraft.io/docs/snapcraft-schema ; assieme agli snap, nella sotto-cartella snap/ trovate il file snapcraft.yaml usato per crearlo. Per il formato yaml potete guardare: yaml.org Essenzialmente sono nomi di variabili, seguiti da ":" e poi i valori. Se i valori sono liste si racchiudono fra parentesi quadre, oppure sono ognuno su una riga, preceduto da "-". I rientri sono importanti, l'ordine delle variabilii no.

Di seguito,come esempio, semplificato, il file snapcraft.yaml che ho usato per creare lo snap del gioco "Lost Memories"

name:        lostmem
version:     '0.2'
title:       Lost Memories
summary: A simple free game
description: |
  This game has been developed in spare time
  as an exercize in C++ and computer graphics
  by Marcello Galli. It isn't well tested,
  and graphics is naive, but it is free.
  See http://thegame.helldragon.eu/ for details.
website: http://thegame.helldragon.eu/
contact: https://www.facebook.com/profile.php?id=61552109027801
license:     CC-BY-NC-SA-4.0
architectures: [amd64]
icon:       snap/gui/sword.png
architectures: [amd64]
base:        core22
grade:       stable
confinement:  strict
type:        app

apps:
  lostmem:
    plugs: [home,removable-media,opengl,x11,audio-playback]
    command: bin/desktop-launch  $SNAP/bin/lostmem.sh
    environment:
      LD_LIBRARY_PATH: "$SNAP/lib:/usr/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu/pulseaudio:$LD_LIBRARY_PATH"
      OGRE_CONFIG_DIR: "$SNAP/bin"

parts:
desktop-glib-only:
    source: https://github.com/ubuntu/snapcraft-desktop-helpers.git
    source-subdir: glib-only
    plugin: make
media:
       source:      media.tar
       source-type: tar
       plugin:      dump
dati:
       source:      dati.tar
       source-type: tar
       plugin:      dump
code:
 source:      lostmem.tar # contiene libs di Ogre e includes di Ogre
 source-type: tar
 plugin:      make
 build-packages:
        * libxaw7-dev
        * libxrandr-dev
        * libfreetype6-dev
        * libsdl2-dev
        * libopenal-dev
        * libalut-dev
 stage-packages:
        * libfreetype6
        * libsdl2-2.0-0

Vediamo le singole parti:

Abbiamo poi le applicazioni, cioè' i programmi che facciamo correre. Qui ne abbiamo uno solo, di nome lostmem, le applicazioni hanno:

Parts sono le parti che compongono lo snap, qui abbiamo:

Ogni parte ha degli attributi:

Il file snapcraft.yaml può avere molti altri parametri, sono descritti nella documentazione su snapcraft.io, vedi: https://snapcraft.io/docs/snapcraft-schema ma anche: https://snapcraft.io/docs/snapcraft-yaml-reference

Cosa fa snapcraft

Come prima cosa si crea un container in cui lavorare, le ultime versioni usano LXD (i containers sono specie di macchine virtuali, ma con un software minimale, e usano il kernel dell'host).

Questo ambiente virtuale ha la seguente struttura: ( code e dati sono i nomi delle parti in snapcraft.yaml)

root/projects  => questa e' la cartella di lavoro, che
                  ritrovo nel container, non e' un copia,
                  e' proprio lei; se faccio modifiche
                  me le ritrovo qui

root/parts/code/build/        => qui fa il build (col make)
               /install/bin/ => quello che produce il make
               /layer/
               /run/         => un suo programma che fa correre il
                                 make (il plugin)
               /src/         => qui copia il mio tar con i source
                                 e lo spacchetta
               /state/       => un file con specifiche
                                 sui passi fatti da snapcraft


               /stage_packages => le librerie indicate in *stage packages*
                                  (pacchetti in formato *deb*)

               /etc/  => files inseriti snapcraft per la fase di built
               /lib/  => librerie inserite da snapcraft per la fase di built


 root/parts/dati/build/    => la fase build copia i dati qui
                 /install  => e anche qui (il plugin dump copia i files)
                 /layer
                 /run      => il plugin dump che copia i files in install
                 /src/     => il mio filedati.tar, spacchettato dalla fase pull
                 /state    => qui files che descrivono i passi fatti



 root/stage/   vanno qui i files nella fase "stage"
 root/prime/   vanno qui i files nella fase "prime"

 snap/     qui files di snapcraft

Sopra la cartella root c'e' un mini sistema ubuntu (il core22), creato dal container, con le solite cartelle: bin,boot,dev,etc,home,lib ...

Snapcraft procede per fasi, nella prima. la fase di pull, quanto specificato dal parametro source di ogni parte viene recuperato e messo nella sottocartella src della parte, nel nostro esempio root/parts/code/src per il C++, root/parts/dati/src per la parte dati. A seconda del parametro source-type vengono effettuate operazioni diverse, per esempio un repository git viene clonato, un file tar viene espanso.

La seconda fase e' quella di build, il contenuto della directory src viene ricopiato nella directory build, e si esegue il programma specificato dalla variabile plugin del file snapcraft.yaml, relativo alla parte. Nell'esempio si e' usato il plugin "dump" per effettuare una semplice copia della parte "dati" e *make* per fare la compilazione e link della parte "code". Ci sono plugin specifici per i diversi linguaggi, Per la lista dei plugin vedi: https://snapcraft.io/docs/snapcraft-plugins . Il plugin richiesto viene messo nella directory "run", e poi eseguito. Per make, nell'esempio fa:

make -j"1" install DESTDIR="/root/parts/code/install"

cioè' esegue il mio file: makefile che ho messo assieme ai files C++, con una precisa definizione delle directory di destinazione. Per cui il mio makefile deve essere coerente con questa convenzione e mettere il programma compilato nella directory "install", eventualmente usando la variabile $DESTDIR definita dal plugin. A volte bisogna guardare dentro il plugin per capire come procedere, perché' la documentazione e' piuttosto carente.

La terza fase e' quella di stage ove quello che sta nelle subdirectory "install" delle parti viene copiato in root/stage/ In questo modo snapcraft mette insieme le diverse parti.

La quarta fase e' quella di prime. In questa fase i files vengono copiati dalla cartella "stage/" alla cartella "prime/" E' possibile, con istruzioni nel file snapcraft.yaml, decidere che certi files vengano ignorati nella copia. In questa fase vengono anche preparati metadati, messi in: "root/prime/meta/"

La fase finale e' quella di pack, dai files nella cartella "prime/" viene creato lo snap.

E' possibile, nel file snapcraft.yaml, inserire i parametri "override-prime", "overrade-stage" , "override-pull" ed "override-build" per sostituire la varie fasi con una propria procedura personalizzata. Con i parametri "stage" e "prime" si possono filtrare i files trattati dalle fasi omonime. La documentazione di tutte le opzione e' sul solito sito: snapcraft.io

snapcraft puo' anche essere usato per fare una fase alla volta, con "snapcraft buid", "snapcraft prime", etc. Se si usa il parametro debug: "snapcraft --debug" , in caso di errore, ci si trova in una shell dentro il container. snapcraft può' essere anche chiamato da dentro il container (da dentro la cartella project). I parametri "--shell-after" o "--shell" permettono di fermarsi ad una delle fasi con una shell entro il container.

Quando si ri-esegue snapcraft ricordarsi di dare il comando "snapcraft clean" oppure le fasi già' effettuate (eventualmente errate) non vengono ri-eseguite.

snapcraft produce files di log, in: ~/.local/state/snapcraft/log

Caricare lo snap sullo snap store

Quando, (dopo vari tentativi) si e' riusciti a creare lo snap e si ottiene un file con nome tipo: nomeapp_0.1_amd64.snap, lo si prova in locale, sul computer su cui si sta lavorando.

Con i privilegi di root lo si installa con il parametro "--devmode" in modo che non sia ben isolato dal sistema e si possa provare con meno problemi.

snap install --devmode nomeapp_0.1_amd64.snap

/snap/bin/nomeapp # per provarlo (non servono i privilegi di root)

Se va bene lo si carica sullo store.

Vi collegate col vostro account Canonical, si usa ancora snapcraft:

/snap/bin/snapcraft login
/snap/bin/snapcraft upload --release=candidate nomesnap_0.1_amd64.snap

L'applicativo viene caricato sullo snap store. Con la pagina dell'applicativo sulla snap store, potete sistemare la descrizione, inserire immagini e spostare lo snap nel canale "stable", quando siete sicuri che funziona tutto bene.