Impacchettare progetti Python per Debian / Raspbian con dh-virtualenv
Questo articolo ha lo scopo di spiegare alcune cose agli sviluppatori che non usano molto Python, e potrebbero lottare con alcuni dei concetti altrimenti.
Consiglio vivamente la lettura del seguente articolo come introduzione ai concetti qui discussi:
pypi.org
pypi.org è un repository ufficiale di software per il linguaggio di programmazione Python. Include librerie che vogliamo usare nei nostri progetti, che non sono fornite di default con Python.
Il problema
Il nostro obiettivo è quello di impacchettare un'applicazione scritta in Python (mirando a Python3) come pacchetto .deb per Raspbian (che è, tutto sommato, davvero equivalente a Debian).
La nostra applicazione ha dipendenze da diverse librerie Python.
Per esempio, vorremmo usare l'elemento richieste libreria. La stessa libreria delle richieste dipende da altre librerie, per esempio chardet, urllib3, ecc.
Gestire manualmente queste dipendenze e spedire manualmente il codice di libreria richiesto è intrinsecamente poco pratico.
pip
Python ha un proprio sistema di gestione dei pacchetti e delle dipendenze, chiamato pip
pip vi permette di installare librerie e applicazioni python, in modo che il vostro codice possa usare queste librerie.
Qui ci sono due problemi:
- vogliamo spedire il pacchetto come Pacchetto Debianper gli utenti finali da installare facilmente. Possiamo assumere con sicurezza che su un numero significativo di sistemi di destinazione le librerie python appropriate non saranno state installate dall'utente
- se cerchiamo di installare queste librerie a livello di sistema per conto dell'utentepotremmo rompere la compatibilità con alcuni altri pacchetti (ad esempio a causa di cambiamenti API tra le versioni delle librerie)
Perciò abbiamo bisogno di una soluzione.
virtualenv
virtualenv ci permetterà di creare ambienti virtuali per Python.
In questi ambienti virtuali abbiamo:
- il nostro interprete Python
- copie delle librerie standard richieste
- il nostro pip
- la nostra biblioteca "di sistema
Parte pratica: Provare virtualenv
Installare virtualenv (come parte di dh-virtualenv, a cui arriveremo tra poco) facendo:
sudo apt install dh-virtualenv
Poiché le richieste sono già installate a livello di sistema sulla mia scatola di prova, useremo un pacchetto diverso come esempio. randstr vi permetterà di generare una stringa casuale.
Controllare se randstr è installato in tutto il sistema:
pip3 mostra randstr
Questo non dovrebbe restituire nulla. Indica che questo pacchetto non è installato in tutto il sistema:
Ora creeremo un ambiente virtuale. La cartella dell'ambiente virtuale NON deve vivere all'interno della tua cartella del codice, ma può farlo. Dovresti ignorarla in GIT.
diciamo che abbiamo una directory /home/pi/tutorial
Entrate in questa directory e create una nuova cartella di ambiente env:
cd /home/pi/tutorial
quale python3
virtualenv -p /usr/bin/python3 env
Nota: devi specificare l'interprete Python se vuoi Python 3, altrimenti verrà usato Python 2. Io sto usando Python 3. (Esecuzione di virtualenv con interprete /usr/bin/python2)
che python3 vi dirà dove risiede il binario python3, regolate il percorso per virtualenv di conseguenza.
attivare l'ambiente:
fonte env/bin/activate
(Questo percorso di comando presuppone che siate rimasti nella directory del tutorial). Notate anche che questo non è uno script eseguibile - dovete usare fonte per usarlo con il vostro terminale bash.
Notate come (env) viene anteposto al vostro prompt dei comandi:
Questo significa che l'ambiente è attivo. Ora è possibile eseguire nuovamente pip3, ma questa volta pip3 eseguirà il suo lavoro sull'ambiente virtuale:
pip3 mostra randstr
pip3 mostra le richieste
non dovrebbe ancora produrre nulla. Anche la seconda linea non mostrerà nulla - mostrando che (se le richieste sono installate a livello di sistema) siamo davvero in un ambiente virtuale.
Ora installate randstr:
pip3 installa randstr
e controllare di nuovo se è installato:
pip3 mostra randstr
Questa volta mostra che randstr è installato. È stato installato in env/lib/python3.5/site-packages:
Mentre l'ambiente è ancora attivato, scriviamo una piccola applicazione Python di esempio:
nano sample.py
incollare il seguente codice, generando una stringa casuale utilizzando la nuova libreria che abbiamo appena installato:
da randstr importare randstr
stampa("ciao mondo")
stampa(randstr())
e salvare.
Eseguite il codice usando python3:
python3 campione.py
mentre l'ambiente è ancora attivo, questo funzionerà :
Ora è il momento di uscire dall'ambiente, per vedere se il codice funzionerà ancora:
disattivare
Il tuo prompt tornerà alla normalità . E
python3 campione.py
lancerà un messaggio di errore sul fatto che non esiste alcun modulo 'randstr' sul vostro sistema. Questo è esattamente il comportamento che vogliamo!
Puoi dare un'occhiata alla cartella env, vedendo come spedisce tutte le cose necessarie per eseguire il tuo codice Python, comprese le librerie, l'eseguibile python, pip e altro.
Pacchetti Debian virtualenv con dh-virtualenv
OK, ora che le basi sono state eliminate, quello che vogliamo è impacchettare un virtualenv insieme al nostro codice, in modo che la nostra applicazione venga eseguita in modo affidabile e senza disturbare le altre applicazioni sui computer dei nostri utenti.
Qui è dove dh-virtualenv entra in scena. dh-virtualenv è un'aggiunta agli script di compilazione di Debian, che permette di pacchettizzare ambienti virtuali.
Dobbiamo creare una struttura di base per il nostro nuovo pacchetto. Qui è dove cookiecutter sarà d'aiuto.
cookiecutter
cookiecutter crea nuovi progetti per voi a partire da modelli, riducendo così l'overhead e il tempo che spendete per sviluppare e farvi capire i molti file che sono necessari.
https://cookiecutter.readthedocs.io/en/latest/
sudo apt install cookiecutter
Nota: il pacchetto python3-cookiecutter fornirà un modulo Python per Python 3. Quello che vogliamo è l'applicazione stessa, che è installata con il pacchetto cookiecutter come visto sopra. Questo potrebbe tirare in Python 2, ma - oh bene.
cookiecutter non è necessario per i vostri utenti finali, è usato solo per creare diversi file per il vostro pacchetto.
creare una directory di progetto di esempio, nella quale applicheremo il modello (sono ancora nella directory del tutorial):
mkdir sampleproject
cd sampleproject
Usando uno stampo speciale per dh-virtualenv possiamo impostare molti dei file necessari:
https://github.com/Springerle/dh-virtualenv-mold
cookiecutter https://github.com/Springerle/dh-virtualenv-mold.git
Questo vi porrà diverse domande.
Si noti che la cartella dovrebbe essere chiamata debian, anche quando si impacchetta per Raspbian - quindi mantenere il nome come debian.
Questo installerà i seguenti file:
Ora è necessario eseguire i seguenti comandi, come da istruzioni sotto il dh-virtualenv-mold:
sudo apt-get install build-essential debhelper devscripts equivssudo mk-build-deps --install debian/control
Per costruire il pacchetto in seguito, eseguirete il seguente comando dalla directory di primo livello del vostro progetto:
dpkg-buildpackage -uc -us -b
In questo momento, però, il comando fallirà perché manca setup.py. Arriveremo al setup.py e al requirements.txt tra poco:
/usr/bin/python3: impossibile aprire il file 'setup.py': [Errno 2] No such file or directory
Informazioni sui singoli file
changelog
Questo file conterrà le informazioni sul rilascio e sulla versione del pacchetto. Puoi aggiornarlo usando uno strumento speciale, dch.
Questo file non è un changelog per la tua applicazione, ma solo un changelog per il confezionamento della tua applicazione.
compat
Questo file include un numero magico speciale "9". (per questioni di compatibilità , va bene lasciarlo così com'è)
controllare
Questo è il file principale per impostare le impostazioni dei pacchetti e le dipendenze a livello Debian. Se la tua applicazione dipende, per esempio, dall'installazione di omxplayer, questo dovrà essere inserito qui come dipendenza:
Fonte: sampleproject
Sezione: contrib/python
Priorità : extra
Manutentore: Maximilian Batz
Build-Depends: debhelper (>= 9), python, python-dev, dh-virtualenv (>= 0.10), tar
Versione standard: 3.9.5
Homepage: https://picockpit.com
Pacchetto: sampleproject
Architettura: qualsiasi
Pre-Depends: dpkg (>= 1.16.1), python2.7 | python3, ${misc:Pre-Depends}
Dipende: ${python:Depends}, ${misc:Depends}
Descrizione: Un pacchetto di esempio per dimostrare il packaging di virtualenv Debian con dh-virtualenv
.
Questa è una distribuzione di "sampleproject" come un progetto autonomo
Python virtualenv avvolto in un pacchetto Debian (pacchetto "omnibus",
tutti i passeggeri a bordo). Il virtualenv confezionato è tenuto in sincronia con
l'interprete dell'host automaticamente.
.
Vedere https://github.com/spotify/dh-virtualenv per maggiori dettagli.
Vorrai anche modificare la Descrizione lunga.
cookiecutter.json
Include le impostazioni iniziali. Non necessario per l'imballaggio.
copyright
Il tuo file di copyright, con la tua licenza (per esempio MIT). È precompilato con il tuo nome, anno, e-Mail e "alcuni diritti riservati".
regole
Questo è un Makefile, per costruire effettivamente il tuo pacchetto. È precompilato dal modello cookiecutter.
progetto-campione.link
Questo file permette di creare collegamenti durante l'installazione. Il nome del file includerà il nome del vostro progetto invece di progetto campione.
Rif: https://stackoverflow.com/questions/9965717/debian-rules-file-make-a-symlink
progettocampione.postinst
Questo file ti permette di eseguire ulteriori passi di configurazione dopo l'installazione (ad esempio attivare il tuo script python come servizio). Il nome del file includerà il nome del tuo progetto invece di progetto campione.
progettocampione.trigger
Per quanto ho capito questo serve a dh-virtualenv per installare un nuovo interprete python nell'ambiente virtuale da spedire, se quello del sistema (la tua scatola di sviluppo) è aggiornato. Il nome del file includerà il tuo nome di progetto invece di progetto campione.
Questo potrebbe essere o non essere il caso, non l'ho testato.
setup.py
Come detto sopra, abbiamo bisogno di un setup.py file. Questo è il modo standard in cui le applicazioni sono impacchettate sotto Python (vengono spedite con un setup.py, che viene eseguito per vari compiti relativi al packaging).
Un semplice setup.py può essere visto in questa pagina:
https://github.com/benjaminirving/python-debian-packaging-example/blob/master/setup.py
Non tutte le voci di questo file sono necessarie. Per esempio, si possono tralasciare i classificatori. Ho il seguente setup.py:
Nota: il numero di versione e altre informazioni qui dentro sono per il tuo pacchetto Python (che sarà creato nel corso della costruzione di un pacchetto Debian con il tuo virtualenv).
Struttura per il tuo codice
Il vostro codice vivrà ora in una sottodirectory della directory principale di sampleproject:
La sottodirectory ha lo stesso nome della directory principale in questo caso.
Nota il file __init__.py
Il sample.py è quello che abbiamo usato sopra, ma un po' rielaborato per assomigliare a questo:
Inoltre, ho impostato un ambiente virtuale per i test durante lo sviluppo all'interno della directory principale (livello superiore) sampleproject:
virtualenv -p /usr/bin/python3 sp_env
chiamato sp_env per l'ambiente del progetto campione
Entrare nell'ambiente:
fonte sp_env/bin/activate
Installare la libreria randstr in questo ambiente:
pip3 installa randstr
e ora possiamo eseguire il codice:
python3 sampleproject/sample.py
OK. Uscire dall'ambiente (! importante!)e provare a costruire di nuovo il pacchetto:
disattivare
dpkg-buildpackage -us -uc
Per impostazione predefinita (a causa del cookie cutter), il vostro pacchetto sarà creato per l'installazione in /opt/venvs/:
Nuovo eseguibile python in /home/pi/tutorial/sampleproject/debian/sampleproject/opt/venvs/sampleproject/bin/python3
Questo può essere cambiato nel file debian/regole file.
Ora il pacchetto è stato costruito e depositato fuori dalla directory principale di sampleproject (dentro la directory tutorial):
Puoi installare il file .deb usando dpkg:
sudo dpkg -i sampleproject_0.2.1+nmu1_armhf.deb
Vedere i risultati dell'installazione con
albero /opt/venvs
Sono state installate 127 directory e 945 file.
Ora potete provare a eseguire il progetto campione usando
/opt/venvs/sampleproject/bin/sampleproject
requisiti / dipendenze
L'applicazione non viene eseguita come (forse) ci si aspetta, ma lancia un errore su randstr che non è presente. Cosa succede?
La ragione è che dh-virtualenv non conosce il requisito che abbiamo, di mettere in bundle il pacchetto randstr durante il processo di costruzione. Questo è l'ultimo pezzo del puzzle.
I requisiti devono essere aggiunti al setup.pycome un modo per far sapere a pip quali pacchetti aggiuntivi devono essere installati nell'ambiente virtuale che si sta creando.
aggiungere il seguente a setup.py:
install_requires=[
'randstr'
]
L'intero file avrà quindi questo aspetto:
Nei miei test il requirements.txt posto al livello superiore ha fatto non influenzare il comportamento di dh-virtualenv e dei pacchetti Python effettivamente inclusi nel pacchetto Debian. Se lo volete ancora, ecco come fare:
pip vi offre un modo per mettere fuori le esatte dipendenze che avete usato per sviluppare nell'ambiente virtuale. Entrate nell'ambiente virtuale:
fonte sp_env/bin/activate
E creare il file requirements.txt:
pip3 freeze > requirements.txt
Ora potete dare un'occhiata a quel file:
cat requirements.txt
Anche se questo file sembra non essere usato da dh-virtualenv (forse ha bisogno di andare in una sottodirectory diversa), è un buon riferimento per te, per vedere quali pacchetti dovresti mettere come dipendenze nella parte install_requires di setup.py.
Notate che il file sampleproject.links ci ha offerto un modo conveniente per collegare questo nella cartella /usr/bin, quindi rimuoverò il segno di commento per la prossima build:
Con questo fuori dai piedi, è il momento di eliminare il progetto campione, e costruirlo di nuovo, poi installarlo. Non dimenticare di disattivare prima!
disattivare
sudo apt purge sampleproject
dpkg-buildpackage -us -uc
cd ...
sudo dpkg -i sampleproject_0.2.1+nmu1_armhf.deb
Questa volta, il pacchetto dovrebbe essere accessibile usando sampleproject:
quale progetto campione
progetto campione
Rif: https://packaging.python.org/discussions/install-requires-vs-requirements/
Suggerimento bonus: cambiare il luogo di installazione
/opt/venvs non è un "posto" molto Debian per mettere un pacchetto.
Le specifiche sono qui:
http://refspecs.linuxfoundation.org/FHS_3.0/fhs/index.html
https://unix.stackexchange.com/questions/10127/why-did-my-package-get-installed-to-opt
- /usr/local è non per i pacchetti
- /opt non è per i pacchetti Debian propriamente detti (è per il software di terze parti installato dall'utente)
http://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch04s06.html
Le applicazioni possono usare una singola sottodirectory sotto /usr/lib
. Se un'applicazione usa una sottodirectory, tutti i dati dipendenti dall'architettura usati esclusivamente dall'applicazione devono essere collocati in quella sottodirectory.
https://wiki.debian.org/HowToPackageForDebian
https://www.debian.org/doc/debian-policy/ch-opersys.html#file-system-hierarchy
"Il requisito FHS che i file statici specifici dell'applicazione indipendenti dall'architettura siano situati in /usr/share
è rilassato a un suggerimento. In particolare, una sottodirectory di /usr/lib
può essere usato da un pacchetto (o un insieme di pacchetti) per contenere un misto di file indipendenti dall'architettura e dipendenti dall'architettura. Tuttavia, quando una directory è interamente composta da file indipendenti dall'architettura, dovrebbe essere situata in /usr/share
."
La posizione migliore mi sembra essere /usr/share
Dobbiamo modificare due file:
in debian/rules DH_VIRTUALENV_INSTALL_ROOT deve essere cambiato in /usr/share, come questo:
e debian/sampleproject.links devono essere cambiati:
Inoltre, faremo una nuova voce nel changelog:
dch -i
semplicemente modificare il testo, per riflettere un nuovo numero di versione, e una voce per il changelog.
Poi il progetto può essere costruito di nuovo:
dpkg-buildpackage -us -uc
Dopo l'installazione, potete verificare che effettivamente la nuova posizione sia utilizzata:
Il pacchetto occuperà circa 16 MB sul vostro sistema di destinazione, grazie all'ambiente virtuale e a tutto ciò che viene fornito con esso. Questo probabilmente potrebbe essere ridotto da alcuni parametri, ma questo esercizio è lasciato al lettore.
Divertitevi a impacchettare!