Pacchettizzare SPKG vecchio stile

Questo capitolo spiega gli spkg vecchio stile; si applica solo agli spkgs opzionali legacy ed agli spkg sperimentali. Vedi Pacchettizzare codice di terze parti per un modo moderno di pacchettizzare il software di terze parti.

Creare un SPKG vecchio stile

Se stai producendo codice per aggiungere nuove funzionalit`a a Sage, potresti considerare di farne un pacchetto (un “spkg”) anzich`e un patch file. Se il tuo codice `e molto lungo (ad esempio) e dev’essere offerto come download opzionale, un pacchetto `e la scelta giusta. Similmente, se il tuo codicee dipende da qualche altro componente opzionale di Sage, dovresti produrre un pacchetto. Nel dubbio, chiedi consiglio sulla mailing-list sage-devel.

L’abbreviazione “spkg” sta per “Sage package”. La directory SAGE_ROOT/spkg/standard contiene degli spkg. In una installazione da codice sorgente, questo `e costituito da file spkg di Sage (in realt`a file .tar o .tar.bz2, che sono il codice sorgente che definisce Sage. In una istallazione da file binario, alcuni di questi posso essere dei file segnaposto per risparmiare spazio.

I pacchetti Sage sono distributiti come file .spkg, che sono file .tar.bz2 (o file tar) ma hanno l’estensione .spkg per evitare confusioni. Sebbene i pacchetti Sage siano fatti con tar e/o bzip2, nota che i file .spkg contengono informationi di controllo (script di installazione e metadata) che sono necessari per compilarli ed installarli. Quando compili Sage da codice sorgente (o quando lanci sage -i <pkg> o sage -f <pkg>), il file SAGE_ROOT/src/bin/sage-spkg provvede a spacchettare, compilare, ed installare i pacchetti Sage. Puoi digitare:

tar -jxvf mypackage-version.spkg

per estrarre un spkg e vedere com’`e fatto dentro. Se vuoi creare un nuovo pacchetto Sage, ti raccomandiamo di iniziare con l’esaminarne uno esistente. All’URL http://www.sagemath.org/download-packages.html vi `e una lista di spkg disponibili per il download.

Nominare il tuo SPKG

Ogni pacchetto spkg di Sage ha un nome della seguente forma:

BASENAME-VERSION.spkg

BASENAME `e il nome del pacchetto; pu`o contenere lettere minuscole, numeri, e caratteri di sottolineatura, ma non trattini. VERSION `e il numero di versione; dovrebbe iniziare con un numero e pu`o contenere numeri, lettere, punti, e trattini; pu`o terminare con una stringa della forma “pNUM”, dove “NUM” `e un intero non negativo. Se il tuo spkg `e una versione “vanilla” (cio`e non modificata) di un qualche software, ad esempio la versione 5.3 di “my-python-package”, allora BASENAME dovrebbe essere “my_python_package” – nota il cambiamento dei trattini in sottolineature, poich`e BASENAME non deve contenere alcun trattino – e VERSION essere “5.3”. Se hai bisogno di modificare il software per usarlo con Sage (come descritto sotto e nel capitolo Panoramica sulle patch agli SPKG), allora VERSION dovrebbe esseree “5.3.p0”, dove la “p0” indica un livello di patch a 0. Se qualcuno aggiunge altre patch, successivamente, questo diverrebbe “p1”, poi “p2”, ecc.

La stringa VERSION dev’essere presente. Se stai usando un software senza un numero di versione ovvio, usa una data. Per dare al tuo spkg un nome come questo, crea una directory chiamata BASENAME-VERSION e metti i tuoi file in quella directory – la prossima sezione descrive la struttura della directory.

Struttura della directory

Metti i tuoi file in una directory di nome simile a mypackage-0.1, come descritto sopra. Se stai facendo il porting di un altro pacchetto software, allora la directory dovrebbe contenere una sottodirectory src/, in cui vi sia una copia non alterata del pacchetto. Ogni file non in src/ dovrebbe essere sotto controllo versione, cio`e ne dovrebbe essere stato fatto il check in un repository hg.

Pi`u precisamente, la directory dovrebbe contenere i seguenti:

  • src/: questa directory contiene codice vanilla upstream, con poche eccezioni, ad esempio quando lo spkg incluso in Sage `e in effetti upstream, e lo sviluppo su quel codice base sta avvenendo in stretto contatto e coordinamento con Sage. Vedi il pacchetto eclib spkg di John Cremona, ad esempio. La directory src/ non dev’essere sotto controllo di revisione.

  • .hg, .hgignore, e .hgtags: gli spkg vecchi stile usano Mercurial come sistema di controllo di revisione. La directory nascosta .hg `e parte del layout standard di un spkg di Sage. Contiene il repository Mercurial per tutti i file non nella directory src/. Per creare questo repository Mercurial da zero, puoi fare:

    hg init
    

    I file .hgignore e .hgtags appartengono anche al repository Mercurial. Il file .hgtags `e opzionale, ed `e frequentemente omesso. Dovresti accertarti che il file .hgignore contenga “src/”, dal momento che non stiamo tracciando il suo contenuto. Invero, frequentemente questo file contiene solo una singola linea:

    src/
    
  • spkg-install: questo file contiene lo script di installazione. Vedi Il File spkg-install per maggiori informazioni ed un template.

  • SPKG.txt: questo file descrive lo spkg in formato wiki. Ogni nuova revisione necessita di una voce “changelog” aggiornata o lo spkg ricever`a automaticamente un “needs work” alla revisione. Vedi Il file SPKG.txt per un template.

  • spkg-check: questo file lancia la suite di test. Questo `e in un certo qual modo opzionale poich`e non tutti gli spkg hanno delle suite di test. Se possibile, accertarsi di creare uno script del genere poich`e aiuta ad isolare i bachi nei pacchetti upstream.

  • patches/: questa directory contiene delle patch ai file sorgentge in src/. Vedi Panoramica sulle patch agli SPKG. Le patch ai file in src/ dovrebbero essere applicate in spkg-install, e tutte le patch devono essere auto-documentanti, cio`e la testata deve contenere cosa fanno, se sono specifiche di una piattaforma, se ne deve essere fatta la push upstream, ecc. Per assicurarsi che tutte le versioni patch-ate di file sorgenti upstream sotto src/ siano sotto controllo di revisione, l’intera directory patches/ dev’essere sotto controllo di revisione.

Mai applicare patch a file sorgente upstream sotto src/ e poi impacchettare un spkg. Un tale miscuglio di codice sorgente upstream con le versione patch-ate specifiche di Sage `e una ricetta per la confusione. Dev’esserci una netta separazione fra il sorgente fornito dal progetto upstream e le versioni patch-ate che il progetto Sage genera sulla base di quanto fornisce il sorgente upstream.

La sola eccezione a questa regola `e la rimozione di file o directory inutilizzate. Alcuni pacchetti contengono parti che non sono necessarie a Sage. Per risparmiare spazio, queste possono essere rimosse direttamente da src/. Ma accertati di documentarlo nella sezione “Special Update/Build Instructions” in SPKG.txt!

Il File spkg-install

Lo script spkg-install `e lanciato durante l’installazione del pacchetto Sage. In questo script, puoi presumere le seguenti cose:

  • PATH contiene, in cima, le locazioni di sage e python (dall’installazione di Sage). Pertanto il comando:

    python setup.py install
    

    eseguir`a la versione corretta di Python con tutto quanto impostato correttamente. Inoltre, lanciando gap o Singular, ad esempio, sar`a eseguita la versione corretta.

  • La variabile d’ambiente SAGE_ROOT punta alla directory radice dell’installazione di Sage.

  • La variabile d’ambiente SAGE_LOCAL punta alla directory SAGE_ROOT/local dell’installazione di Sage.

  • Le variabili d’ambiente LD_LIBRARY_PATH e DYLD_LIBRARY_PATH hanno entrambe SAGE_ROOT/local/lib in cima.

Lo script spkg-install dovrebbe copiare i tuoi file nel posto giusto dopo aver fatto qualunque compilazione fosse necessaria. Questo `e un template:

#!/usr/bin/env bash

if [ -z "$SAGE_LOCAL" ]; then
    echo >&2 "SAGE_LOCAL undefined ... exiting"
    echo >&2 "Maybe run 'sage --sh'?"
    exit 1
fi

cd src

# Apply patches.  See SPKG.txt for information about what each patch
# does.
for patch in ../patches/*.patch; do
    [ -r "$patch" ] || continue  # Skip non-existing or non-readable patches
    patch -p1 <"$patch"
    if [ $? -ne 0 ]; then
        echo >&2 "Error applying '$patch'"
        exit 1
    fi
done

./configure --prefix="$SAGE_LOCAL"
if [ $? -ne 0 ]; then
    echo >&2 "Error configuring PACKAGE_NAME."
    exit 1
fi

$MAKE
if [ $? -ne 0 ]; then
    echo >&2 "Error building PACKAGE_NAME."
    exit 1
fi

$MAKE install
if [ $? -ne 0 ]; then
    echo >&2 "Error installing PACKAGE_NAME."
    exit 1
fi

if [ "$SAGE_SPKG_INSTALL_DOCS" = yes ] ; then
    # Before trying to build the documentation, check if any
    # needed programs are present. In the example below, we
    # check for 'latex', but this will depend on the package.
    # Some packages may need no extra tools installed, others
    # may require some.  We use 'command -v' for testing this,
    # and not 'which' since 'which' is not portable, whereas
    # 'command -v' is defined by POSIX.

    # if [ `command -v latex` ] ; then
    #    echo "Good, latex was found, so building the documentation"
    # else
    #    echo "Sorry, can't build the documentation for PACKAGE_NAME as latex is not installed"
    #    exit 1
    # fi


    # make the documentation in a package-specific way
    # for example, we might have
    # cd doc
    # $MAKE html

    if [ $? -ne 0 ]; then
        echo >&2 "Error building PACKAGE_NAME docs."
        exit 1
    fi
    mkdir -p "$SAGE_ROOT/local/share/doc/PACKAGE_NAME"
    # assuming the docs are in doc/*
    cp -R doc/* "$SAGE_ROOT/local/share/doc/PACKAGE_NAME"
fi

Nota che la prima linea `e #!/usr/bin/env bash; questo `e importante per la portabilit`a. Poi, lo script verifica che SAGE_LOCAL sia definita per accertarsi che l’ambiente di Sage sia stato sistemato. Dopo questo, lo script potrebbe semplicemnte eseguire cd src e poi invocare o python setup.py install o la sequenza degli autotools ./configure && make && make install, o qualcos’altro di simile.

A volte, per`o, pu`o essere pi`u complicato. Ad esempio, potresti aver bisogno di applicare delle patch dalla directory patches in un ordine particolare. Inoltre, dovresti prima compilare (ad esempio con python setup.py build, uscendo se c’`e un errore), prima di installare (ad esempio con python setup.py install). In questo modo, non sovrascriverai una vecchia versione del spkg funzionante con una nuova non funzionante.

Quando copi la documentazione in $SAGE_ROOT/local/share/doc/PACKAGE_NAME, pu`o essere necessario verificare che solo i file di documentazione pensati per l’utente finale sono copiati. Ad esempio, se la documentazione `e compilata dai file .tex, ti potrebbe bastare copiare i file pdf risultanti, anzich`e l’intera directory “doc”. Quando si genera documentazione usando Sphinx, il copiare la directory build/html in generale copier`a solo l’output inteso per l’utente finale.

Il file SPKG.txt

Il file SPKG.txt vecchio stile `e lo stesso descritto in Il file SPKG.txt, ma con un “changelog” manuale aggiunto, poich`e i contenuti non sono parte del repository di Sage. Dovrebbe seguire il pattern seguente:

== Changelog ==

Mettere qui un changelog del spkg, dove le entrate hanno questo formato:

=== mypackage-0.1.p0 (Mary Smith, 1 Jan 2012) ===

 * Patch src/configure so it builds on Solaris. See Sage trac #137.

=== mypackage-0.1 (Leonhard Euler, 17 September 1783) ===

 * Initial release.  See Sage trac #007.

Quando la directory (diciamo, mypackage-0.1) `e pronta, il comando

sage --pkg mypackage-0.1

creer`a il file mypackage-0.1.spkg. Come notato sopra, questo crea un tar file compresso. Eseguendo sage --pkg_nc mypackage-0.1 si crea un tar file non compresso.

Quando il tuo spkg `e pronto, dovresti farne una segnalazione su sage-devel. Se la gente l`i pensa che sia una buona idea, allora fa un post del link al spkg sul Trac server di Sage (vedi The Sage Trac Server) cos`i che possa essere giudicato. Non fare un post del spkg stesso sul server Trac: ti basta fornire un link al tuo spkg. Se il tuo spkg ottiene una revisione positiva, potr`a essere incluso nella libreria core di Sage, o potr`a diventare un download opzionale dal sito web di Sage, cos`i che ciunque possa installarlo automaticamente digitando sage -i mypackage-version.spkg.

Note

Per qualunque spkg:

  • Accertati che il repository hg contenga ogni file al di fuori della directory src, che questi siano tutti aggiornati e che ne sia stato fatto il commit nel repository.
  • Includi un file spkg-check se possibile (vedi trac ticket #299).

Note

Il codice Magma esterno va in SAGE_ROOT/src/ext/magma/user, cos`i se vuoi redistribuire il codice Magma con Sage come un pacchetto che gli utenti con Magma possano usare, l`i `e dove va messo. Dovresti anche disporre codice Python utile a rendere il codice Magma facilmente utilizzabile.

Evitare guai

Questa sezione contiene alcune linee guida su cosa un spkg non deve mai fare ad una installazione di Sage. Sei incorraggiato a produrre un spkg che `e tanto indipendente dal resto quanto possibile.

  1. Un spkg non deve modificare un file sorgente esistente nella libreria Sage.
  2. Non permettere ad un spkg di modificare un altro spkg. Un spkg pu`o dipendere da un altro spkg – vedi sopra. Verifica l’esistenza di un spkg richiesto come prerequisito prima di installare un spkg che dipende da lui.

Panoramica sulle patch agli SPKG

Accertati di essere familiare con la struttura e le conventioni degli spkg; vedi il capitolo Pacchettizzare SPKG vecchio stile per dettagli. Fare la patch di un spkg implica fare la patch dello script di installazione del spkg e/o del codice sorgente upstream contenuto nel spkg. Diciamo che vuoi fare una patch al pacchetto Matplotlib matplotlib-1.0.1.p0. Nota che la “p0” denotea il livello della patch sul spkg, mentre “1.0.1” si riferisce alla versione upstream di Matplotlib cos`i come contenuta in matplotlib-1.0.1.p0/src/. Lo script di installazione di tale spkg `e:

matplotlib-1.0.1.p0/spkg-install

In generale, uno script di nome spkg-install `e uno script di installazione per un spkg. Per fare la patch allo script di installazione, usa un text editor per modificare lo script. Poi nel file di log SPKG.txt fornisci una descrizione ad alto livello delle tue modifiche. Quando sei soddisfatto delle tue modifiche nello script d’installazione nel file di log SPKG.txt, usa Mercurial per fare il check-in delle tue modifiche ed accertati di fornire un messaggio di commit significativo.

La directory src/ contiene il codice sorgente fornito dal progetto upstream. Ad esempio, codice sorgente di Matplotlib 1.0.1 `e contenuto in

matplotlib-1.0.1.p0/src/

Per fare una patch al codice sorgente upstream, devi modificare una copia del file interessato – i file nella directory src/ non dovrebbero essere toccati, essendo versioni “vanilla” del codice sorgente. Ad esempio, puoi copiare l’intera directory src/

$ pwd
matplotlib-1.0.1.p0
$ cp -pR src src-patched

Poi modificare i file in src-patched/. Quando sei soddisfatto delle tue modifiche, genererai una lista diff unificata fra il file originale e quello modificato, e la salverai in patches/:

$ diff -u src/configure src-patched/configure > patches/configure.patch

Salva la lista diff unificata in un file con lo stesso nome del file sorgente di cui hai fatto la patch, ma usa l’estensione ”.patch”. Nota che la directory src/ non dovrebbe essere sotto controllo revisione, laddove patches/ deve esserlo. Il file di configurazione di Mercurial .hgignore dovrebbe contenere la seguente linea:

src/

Assicurati che lo script di installazione spkg-install contenga codice per applicare le patch ai file opportuni sotto src/. Ad esempio, il file

matplotlib-1.0.1.p0/patches/finance.py.patch

`e una patch per il file

matplotlib-1.0.1.p0/src/lib/matplotlib/finance.py

Lo script di installazione matplotlib-1.0.1.p0/spkg-install contiene il seguente codice per installare le patch necessarie:

cd src

# Apply patches.  See SPKG.txt for information about what each patch
# does.
for patch in ../patches/*.patch; do
    patch -p1 <"$patch"
    if [ $? -ne 0 ]; then
        echo >&2 "Error applying '$patch'"
        exit 1
    fi
done

Naturalmente, questo pu`o essere modificato se l’order in cui le patch vanno applicate `e importante, o se qualche patch `e dipendente dalla piattaforma. Ad esempio:

if [ "$UNAME" = "Darwin" ]; then
    for patch in ../patches/darwin/*.patch; do
        patch -p1 <"$patch"
        if [ $? -ne 0 ]; then
            echo >&2 "Error applying '$patch'"
            exit 1
        fi
    done
fi

(La variabile d’ambiente UNAME `e definita dallo script sage-env, ed `e disponibile quando spkg-install `e eseguito.)

Ora fornisci una spiegazione a grandi linee delle tue modifiche in SPKG.txt. Nota il formato di SPKG.txt – vedi il capitolo Pacchettizzare SPKG vecchio stile per dettagli. Quando sei soddisfatto delle tue modifiche, usa Mercurial per fare il check-in delle tue modifiche, dando un messaggio di commit significativo. Poi usa il comando hg tag per mettere un nuovo numero di versione (usando “p1” invece di “p0”: abbiamo fatto dei cambiamenti, quindi dobbiamo aggiornare il livello della patch):

$ hg tag matplotlib-1.0.1.p1

Poi rinomina la directory matplotlib-1.0.1.p0 a matplotlib-1.0.1.p1 per farla coincidere con il nuovo livello di patch. Per produrre il file spkg vero e proprio, spostati nella directory genitore di matplotlib-1.0.1.p1 ed esegui

$ /path/to/sage-x.y.z/sage --pkg matplotlib-1.0.1.p1
Creating Sage package matplotlib-1.0.1.p1

Created package matplotlib-1.0.1.p1.spkg.

    NAME: matplotlib
 VERSION: 1.0.1.p1
    SIZE: 11.8M
 HG REPO: Good
SPKG.txt: Good

I file spkg sono o degli archivi tar compressi con bzip o tar semplici; il comando sage --pkg ... produce la versione compressa. Se il tuo spkg contiene per lo pi`u file binari che si comprimono poco, puoi usare sage --pkg_nc ... per produrre una versione non compressa, cio`e un file tar normale:

$ sage --pkg_nc matplotlib-1.0.1.p0/
Creating Sage package matplotlib-1.0.1.p0/ with no compression

Created package matplotlib-1.0.1.p0.spkg.

    NAME: matplotlib
 VERSION: 1.0.1.p0
    SIZE: 32.8M
 HG REPO: Good
SPKG.txt: Good

Nota che questo `e quasi un 3 volte la versione compressa, quindi dovremmo usare la compressione!

A questo punto, potresti voler sottoporre il tuo spkg patch-ato per la revisione. Allora fornisci un link (URL) al tuo spkg sul ticket di Trac relativo e/o in una email alla mailing list relativa. Di solito non si dovrebbe fare l’upload del spkg vero e proprio al ticket Trac relativo – non inviare grandi file binari al server Trac.

Gestione delle versioni degli SPKG

Se vuoi aggiornare la versione di un spkg, devi seguire alcune convenzioni di denominazione. Usa il nome ed il numero di versione com’`e dato dal progetto upstream, ad esempio matplotlib-1.0.1. Se il pacchetto upstream `e preso da qualche revisione che non `e una versione stabile, aggiungi la data a cui `e stata fatta la revisione, ad esempio il pacchetto Singular singular-3-1-0-4-20090818.p3.spkg ha la revisione 2009-08-18. Se inizi da zero da una release upstream senza patch al suo sorgente, il spkg risultante non ha bisogno di avere alcuna etichetta di livello di patch (si pu`o aggiungere ”.p0”, ma `e opzionale). Ad esempio, sagenb-0.6.spkg `e preso dalla versione stabile upstream sagenb-0.6 senza alcuna patch applicata al suo codice sorgente. Per cui non vedrai delle numerazioni di livello di patch come .p0 or .p1.

Diciamo che inizi con matplotlib-1.0.1.p0 e vuoi sostituire Matplotlib 1.0.1 con la versione 1.0.2. Questo implica sostituire il codice sorgente di Matplotlib 1.0.1 sotto matplotlib-1.0.1.p0/src/ con il nuovo codice sorgente. Per incominciare, segui le convenzioni di denominazione come descritto nella sezione Panoramica sulle patch agli SPKG. Se necessario, rimuovi qualunque patch obsoleta e crea quelle nuove, mettendole sotto la directory patches/. Modifica lo script spkg-install per prendere in considerazione qualunque cambiamento delle patch; potresti aver a che fare con modifiche a come la nuova versione del codice compila. Poi pacchettizza il tuo spkg sostitutivo usando le opzioni a riga di comando di Sage --pkg o --pkg_nc (tar con o senza bzip2).

Per installare il tuo spkg sostitutivo, usa:

sage -f http://URL/to/package-x.y.z.spkg

oppure:

sage -f /path/to/package-x.y.z.spkg

Per compilare Sage da sorgente con lo (standard) spkg sostituivo, esegui untar del tarball del sorgente di Sage e rimuovi il spkg esistente da SAGE_ROOT/spkg/standard/. Al suo posto metti il tuo spkg sostitutivo. Poi esegui make da SAGE_ROOT.