Pubblicare un package su Ubuntu PPA

Repository e package managers

Una repository è una collezione di file che contiene dei pacchetti software. Questi, a loro volta, indicano quali sono le dipendenze necessarie per il loro funzionamento, la versione, e altre informazioni utili, oltre a contenere il software stesso.

Ubuntu repository

Ogni version di Ubuntu ha quattro repository ufficiali:

  • Main: per software supportato da Canonical
  • Universe: per software open source supportato dalla comunità
  • Restricted: per software proprietario
  • Multiverse: per software con licenze o copyright restrittivi

Configurazione dei repository

Le informazioni relative ai repository che verranno consultati da apt sono contenute nel file /etc/apt/sources.list.
Ogni volta che si esegue il comando apt update, apt scarica la lista dei pacchetti disponibili nei repository e le salva in una cache locale.

Cos'è un PPA

Per assicurarsi di raggiungere quante più persone possibile, assicurarsi che il proprio programma sia installabile tramite apt è fondamentale.

Tuttavia, i repository ufficiali sono (giustamente) molto selettivi, senza contare che il processo può richiedere molto, moltissimo tempo, da un paio di settimane a diversi mesi.

PPA è l'acronimo di Personal Package Archive, un servizio offerto da Launchpad che permette agli sviluppatori di distribuire pacchetti software per Ubuntu.

Le PPA rappresentano una scorciatoia per non sacrificare troppo la comodità di apt.

Utilizza una PPA come un utente

Per utilizzare un PPA come un utente, è sufficiente aggiungere il repository al file /etc/apt/sources.list o creare un file .list nella directory /etc/apt/sources.list.d/ con il comando add-apt-repository.

sudo add-apt-repository ppa:username/ppaname # Aggiunge il repository
sudo apt update # Aggiorna la cache dei pacchetti
sudo apt install packagename # Installa il pacchetto

PPA vs deb

Il vantaggio di utilizzare un PPA rispetto a un pacchetto deb è che il software verrà aggiornato automaticamente tramite apt insieme al resto del sistema. Inoltre, a seconda dei gusti personali, poter gestire tutto da un unico posto, ovvero apt, risulta generalmente molto comodo.

D'altra parte, un utente abituato al workflow comune per altri sistemi operativi (Windows) potrebbe trovare più intuitivo scaricare l'installer e seguire la procedura grafica guidata.

Official PPA vs Unofficial PPA

Un PPA è considerato ufficiale se viene prodotto e distribuito dagli sviluppatori del software stesso.

Il processo per creare un PPA però non è banale e lo sviluppatore originale potrebbe non essere più disponibile o non avere interesse a spendere tempo in questa attività.
In questi casi, è possibile che un terzo crei un PPA non ufficiale per facilitare l'adozione del software.

Creare un PPA

Vediamo quali sono tutti i passaggi necessari per creare un PPA e pubblicare un pacchetto software.

Launchpad

Launchpad è un servizio offerto da Canonical che offre servizi di hosting per progetti open source. In questo contesto, il service che ci interessa è quello per la creazione e la gestione di PPA.

Creare un account su Launchpad

Il primo passo è creare un account su Launchpad. Questo richiederà anche la registrazione di un utente su Ubuntu One.

Dalla propria dashboard, sarà possibile creare direttamente un nuovo PPA o un team a cui associare il PPA.

Collegare una chiave GPG al proprio account

La verifica del software che viene pubblicato avviene tramite firma crittografica. Per questo motivo è necessario collegare una chiave GPG al proprio account Launchpad.

Se non si ha una chiave GPG, è possibile crearne una con il comando gpg --gen-key (o gpg --full-generate-key per avere più opzioni, come i commenti).

Pubblicare la chiave

La chiave deve essere poi pubblicata su un server di chiavi. Nel caso di Ubuntu è necessario usare l'URL keyserver.ubuntu.com con il comando gpg --keyserver <key server> --send-keys <key id>.

Sarà quindi necessario indicare a Launchpad la fingerprint della chiave appena pubblicata, visibile tramite il comando gpg --fingerprint. Potrebbe essere necessario attendere un po' di tempo prima che la chiave sia effettivamente disponibile.

Launchpad sfiderà l'utente tramite una email di verifica contenente un codice cifrato con la chiave appena pubblicata. Basterà ottenere il testo e decifrarlo con il comando gpg --decrypt <message> per ultimare la procedura.

Per maggiori dettagli, si può consultare la documentazione ufficiale o la mia guida.

Pacchetti sorgente e pacchetti binari

I pacchetti sorgente sono una collezione di file sorgente (ad esempio di un programma).

Una volta compilati, o più genericamente buildati, seguendo le regole indicate dallo sviluppatore, in genere tramite un Makefle e dei file di meta-dati per la configurazione e le dipendenze, si ottiene un pacchetto binario. Questo contiene gli eseguibili, le librerie e tutto ciò che l'utente avrà bisogno per utilizzare il prodotto, pronto per essere installato.

Sebbene lavorare con pacchetti binari, quindi precompilati, sia più comodo, i PPA richiedono l'upload di source package.

Esempio di creazione di un source package

Invece di fornire una descrizione meticolosa, ma astratta, di come creare e pubblicare un source package, preferisco mostrare un esempio pratico.

Se si è più interessati alla documentazione, si può una fra le guide ufficiali:

Formato

Esistono diversi formati per i source package. In questo esempio utilizzeremo il 3.0 (quilt).

Di conseguenza, ci si aspetta che pacchetto contenga:

  • orig.tar.gz: il sorgente originale
  • debian.tar.gz: i meta-file di configurazione
  • dsc: il file di controllo di versione

Requisiti

  • dpkg-dev (sudo apt install dpkg-dev)
  • build-essential (sudo apt install build-essential)
  • devscripts (sudo apt install devscripts)
  • debsign (sudo apt install debsign)
  • fakeroot (sudo apt install fakeroot)
  • lintian (sudo apt install lintian)

dpkg

Gli strumenti per il packaging in Debian possono risultare un po' complessi, soprattutto per un neofita.
Lanciare il comando dpkg-buildpackage -us -uc in una directory con il sorgente e la cartella debian eseguirà:

  • pulizia della cartella (debian/rules clean)
  • creazione del source package (dpkg-source -b)
  • compilazione del programma (debian/rules build)
  • creazione dei pacchetti binari (fakeroot debian/rules binary)
  • creazione del file .dsc
  • creazione del file .changes, utilizzando dpkg-genchanges

Se il procedimento è andato a buon fine, i file .dsc e .changes vanno firmati con la propria chiave privata usando il comando debsign. Se si è interessati ad un singolo passaggio fra quelli elencati in precedenza, eseguire il comando corrispondente potrebbe essere sufficiente, anche se non include alcun check, creazione automatica dei file .dsc e .changes e firma del package, rendendo impossibile l'upload su un repository ppa. Alternativamente, dpkg-buildpackage offre la possibilità di indicare il target desiderato, che può essere:

  • source: creazione del source package
  • any: crea il binary package per una specifica architettura (esempio: amd64)
  • all: crea i binary package indipendenti dalla architettura (esempio: documentazione, package Java o Python)
  • binary: crea tutti i package binary, includendo quindi sia any che all
  • full: include tutti i target precedenti, quindi source e binary

Per creare il package source, quindi è consigliabile utilizzare, nella cartella che contiene il codice sorgente e la cartella debian con la configurazione, il seguente comando:

dpkg-buildpackage --build=source

Struttura di un source package

packagename/
├── debian/
   ├── changelog
   ├── compat
   ├── control
   ├── control
   ├── rules
   └── source/format
├── src/
   ├── packagename.l
   └── packagename.c
└── Makefile

Manual page file, packagename.1:

.TH PAKAGENAME 1 "30 May 2024" "packagename"
.SH NAME
packagename \- print hello deb
.SH SYNOPSIS
packagename
.SH DESCRIPTION
packagename is a minimal package for PPA Debian packaging.
.SH OPTIONS
packagename does not take any options.
.SH SEE ALSO
dpkg-buildpackage(1)
.SH BUGS
No known bugs.
.SH AUTHOR
Ernesto Casablanca (casablancaernesto@gmail.com)

Source file packagename.c:

// src/packagename.c
#include <stdio.h>

int main() {
  printf("hello deb\n");
  return 0;
}