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
snap help Descrive i comandi utilizzabili
snap find "game" Elenca gli snap dello store che hanno a che fare con la parola data (in questo caso: game)
snap find --section="games" Elenca gli snap nella sezione dei giochi ( per l'elenco delle sezioni vedi: https://snapcraft.io/docs/quickstart-guide )
snap list Lista gli snap presenti nel sistema
snap info lostmem Mostra informazioni sullo snap di nome lostmem
snap install lostmem Scarica dallo snap store lo snap di nome "lostmem" e lo installa nel sistema Questo comando va dato come utente root o con sudo
snap remove vlc Elimina lo snap di nome vlc (anche questo richiede i privilegi di root)
snap refresh Aggiorna gli snap con l'ultima versione disponibile sullo snap store (richede permessi di root)
snap connections Fa vedere i canali con cui gli snap installati interagiscono col sistema Esistono comandi "snap connect" e "snap disconnection" per controllare queste connessioni
snap login Per collegarsi ai servizi della Canonical. Chiede la password per il sito della Canonical e poi quella del sistema su cui si lavora. C'è' anche comando snap logout
snap disable Disabilita momentaneamente uno snap, snap enable lo riattiva
snap save e snap restore permettono di gestire uno snapsht, una specie di backup dello snap.
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)
$SNAP_NAME : il nome dello snap
$SNAP : la cartella dello snap :/snap/$SNAP_NAME/current
$SNAP_COMMON : cartella coi dati dello snap: /var/snap/$SNAP_NAME/common
$SNAP_DATA : cartella coi dati dell'ultima versione : /var/snap/$SNAP_NAME/current
$SNAP_USER_COMMON : dati dello snap dell'utente: ~/snap/$SNAP_NAME/common
$SNAP_USER_DATA : dati per l'ultima versione: ~/snap/$SNAP_NAME/current (anche $HOME)
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:
Poi guardate se il nome scelto per il programmam e'già in uso. Per vederlo si prova a registrare il nome in:
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:
si crea una directory di lavoro per la vostra applicazione
si fa: /snap/bin/snapcraft init e viene creata una sottodirectory con un file snapcraft.yaml. Se ci sono problemi coi profili di apparmor potete caricarli a mano (come root): apparmor_parser /var/lib/snapd/apparmor/profiles/*
editate il file snapcraft.yaml mettendoci una completa descrizione del vostro applicativo, con l'elenco delle librerie che servono, dove e' il source, come compilarlo etc.etc.
eseguite /snap/bin/snapcraft e tutto dovrebbe essere automatico e dovreste ottenere il file snap da caricare sullo snap store (se siete molto, molto, molto fortunati e precisi).
Prima di caricarlo sullo snap store lo provate , installandolo sulla macchina su cui lavorate. Vi ritrovate lo snap in /snap/nomesnap , e lo fate correre con: /snap/bin/nomesnap .
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:
all'inizio informazioni generali: nome, versione , titolo, il sommario (massimo 79 caratteri) e una descrizione, su piu' linee (nota il caratteree "|") Ci puo' essere anche un sito internet di riferimeneto ed una informazione di contatto (come un E-mail)
Altre informazioni sono la licenza, la lista di cpu su cui corre (qui AMD64), l'icona che lo rappresenta nello snap store
core22 e' lo snap di base, che contiene un mini-ubuntu versione 22.04. Può essere anche core18 o core20, se come base e' usata una versione più' vecchia di Ubuntu (in futuro sarà' core24)
grade e' il canale in cui volete caricarlo sullo snap store. Essenzialmente il livello di sviluppo: devel: in fase di sviluppo, candidate: pronto per il rilascio, stable: versione stabile.
confinement: come e' isolato dal sistema in cui corre,
devmode: in fase di sviluppo e poco isolato
strict: interagisce solo con collegamenti predefiniti
classic: usa parti del sistema su cui corre
Abbiamo poi le applicazioni, cioè' i programmi che facciamo correre. Qui ne abbiamo uno solo, di nome lostmem, le applicazioni hanno:
plugs: la lista dei collegamenti col sistema, qui:
home: i files dell'utente
opengl,x11 : la grafica
audio-playback: l'audio
command: il comando eseguito quando si chiama l'applicativo con: /snap/bin/lostmem (qui bin/desktop-launch $SNAP/bin/lostmem.sh) destop-launch e' un sistema per interfaccia col desktop.
environment: sono le variabili di ambiente per il programma.
Parts sono le parti che compongono lo snap, qui abbiamo:
desktop-glib-only: l'applicatico della canonical per interfaccia col desktop. (vedi: https://forum.snapcraft.io/t/desktop-applications/13034 ma anche: https://forum.snapcraft.io/t/the-desktop-interfaces/2042 per un sistema più' moderno.
media: le mie immagini e oggetti grafici per il gioco.
dati: i dati per il gioco
code: il codice C++ con cui e' scritto l'applicativo.
Ogni parte ha degli attributi:
source: dove si trovano i contenuti, qui li ho messi in files di tipo archivio "tar" nella mia directory di lavoro
source-type: come fornisco i dati, apppunto dei "tar". Potrebbe essere "git" se sono in archivi git in rete, o altro
plugin: il programma usato per trattare i dati, qui ho il sistema make per compilare il programma, e dovro' mettere il file makefile, usato da make, nell'archivio tar. Per dati e media ho dump, che semplicemente spacchetta l'archivio tar e copia i dati.
build-packages: li lista delle librerie necessarie a compilare il programma (qui non le ho riportate tutte)
stage-packages: le librerie che servono al programma quando corre (anche qui non le ho messe tutte).
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.