Unul dintre cele mai bune lucruri legate de Perl este existența modulelor open-source disponibile pe CPAN. Dar gestionarea acestor module este dificilă. În fiecare săptămână sunt sute de noi lansări și nu poți ști dacă noua versiune a unui modul nu va introduce o hibă care să-ți afecteze aplicația.
This article was originally published on Pragmatic Perl
Una dintre strategiile de rezolvare a acestei probleme este să-ți construiești propriul depozit CPAN care să conțină doar versiunile modulelor pe care le dorești. Astfel poți folosi uneltele CPAN pentru a construi aplicația folosind modulele din depozitul propriu fără a mai fi expus la potențialele probleme date de depozitul public CPAN.
De-a lungul anilor, am construit mai multe depozite CPAN la comandă folosind unelte ca CPAN::Mini și CPAN::Site.
Dar întotdeauna mi s-au părut greoaie, nu am fost niciodată mulțumit de ele. Cu vreo doi ani în urmă un client m-a angajat să-i construiesc un alt depozit CPAN. Dar de data acesta am avut oportunitatea de a începe de la zero. Pinto este rezultatul acestui efort.
Pinto este o unealtă robustă pentru crearea și administrarea de depozite CPAN, la comandă. Are mai multe caracteristici puternice care te ajută să administrezi în siguranță toate modulele Perl de care are nevoie aplicația ta. Acest tutorial îți va arăta cum să creezi un depozit CPAN cu Pinto și-ți va demonstra unele dintre acele caracteristici.
Instalarea Pinto
Pinto este disponibil pe CPAN și poate fi instalat ca orice alt modul
folosind utilitarele CPAN sau cpanm
. Dar Pinto este mai mult
o aplicație decât o bibliotecă de funcții. Este o unealtă pe care o
poți folosi să administrezi codul aplicației, dar Pinto nu este în
fapt parte a aplicației tale. Deci îți recomand să instalezi Pinto ca pe
o aplicație de sine stătătoare cu aceste comenzi:
curl -L http://getpinto.stratopan.com | bash
source ~/opt/local/pinto/etc/bashrc
Acestea vor instala Pinto în ~/opt/local/pinto
și vor adăuga
directoarele necesare la PATH
și MANPATH
.
Aplicația este autonomă, conține tot ce este necesar, deci instalarea
Pinto nu va afecta mediul tău de dezvoltare și nici schimbările
acestuia nu vor afecta Pinto.
Explorând Pinto
Așa cum se face cu orice nouă unealtă, primul lucru pe care ar trebui să-l înveți este cum să ceri ajutor:
pinto commands # Arată o listă a comenzilor disponibile
pinto help <COMMAND> # Arată un sumar al opțiunilor și al argumentelor pentru <COMMAND>
pinto manual <COMMAND> # Arată manualul complet pentru <COMMAND>
Pinto vine de asemenea și cu alte documentații, incluzând un tutorial și un ghid de referință rapidă. Poți accesa această documentație folosind comenzile:
man Pinto::Manual::Introduction # Explică conceptele de bază Pinto
man Pinto::Manual::Installing # Sugestii pentru instalarea Pinto
man Pinto::Manual::Tutorial # Un ghid descriptiv pentru Pinto
man Pinto::Manual::QuickStart # Un sumar al comenzilor de bază
Crearea Unui Depozit
Primul pas pentru folosirea Pinto este crearea depozitului folosind comanda
init
:
pinto -r ~/repo init
Acesta va crea un nou depozit în directorul ~/repo
. Dacă
acest director nu există, va fi creat. Dacă există deja, atunci
trebuie să fie gol.
Opțiunea -r (or --root) specifică unde este localizat depozitul.
Această opțiune este obligatorie pentru toate comenzile pinto.
Dacă te-ai plictisit să o tot tastezi, poți seta variabila de
mediu PINTO_REPOSITORY_ROOT
să indice calea către depozit și
să omiți opțiunea -r.
Inspectarea Depozitului
Acum că ai un depozit, hai să vedem ce conține. Pentru a vedea conținutul unui depozit, folosește comanda "list":
pinto -r ~/repo list
În acest moment, nu va lista nimic pentru că nu depozitul este gol deocamdată. Dar vei folosi comanda "list" destul de des în acest tutorial.
Adăugarea De Module CPAN
Să presupunem că lucrezi la o aplicație numită My-App care conține
un modul numit My::App, care depinde de modulul URI. Poți adăuga
modulul URI în depozitul tău folosind comanda pull
:
pinto -r ~/repo pull URI
Vei fi solicitat să introduci un mesaj de log care să descrie modificarea. Partea de început a șablonului mesajului va include un mesaj eșantion care poate fi editat. Restul mesajului va cuprinde ce module vor fi adăugate. Salvează fișierul și închide editorul după ce ai terminat.
Acum ar trebui să ai modulul URI în depozit. Hai să vedem ce am
obținut. Încă odată, folosește comanda list
pentru a vedea
ce conține depozitul:
pinto -r ~/repo list
De acestă dată, rezultatul va arăta cam așa:
rf URI 1.60 GAAS/URI-1.60.tar.gz
rf URI::Escape 3.31 GAAS/URI-1.60.tar.gz
rf URI::Heuristic 4.20 GAAS/URI-1.60.tar.gz
...
Se poate vedea că modulul URI a fost adăugat la depozit, împreună cu toate dependențele modulului URI, și toate dependențele acestora, și așa mai departe.
Adăugarea Modulelor Private
Să presupunem că ai terminat lucrul la My-App și ești gata să lansezi
prima versiune. Folosind unealta preferată (de
ex. ExtUtils::MakeMaker, Module::Build, Module::Install etc.) creezi
un pachet denumit My-App-1.0.tar.gz. Adaugi distribuția la depozitul
Pinto folosind comanda add
:
$> pinto -r ~/repo add path/to/My-App-1.0.tar.gz
De asemenea vei fi solicitat să introduci un mesaj care să descrie modificarea. Când vei lista conținutul depozitului, va include modulul My::App și numele autorului distribuției:
rl My::App 1.0 JEFF/My-App-1.0.tar.gz
rf URI 1.60 GAAS/URI-1.60.tar.gz
rf URI::Escape 3.31 GAAS/URI-1.60.tar.gz
rf URI::Heuristic 4.20 GAAS/URI-1.60.tar.gz
...
Instalarea Modulelor
Acum că ai modulele în depozitul Pinto, următorul pas este să încerci să le instalezi undeva. Sub capotă, un depozit Pinto este organizat exact ca un depozit CPAN, deci este perfect compatibil cu cpanm și orice altă unealtă pentru instalat module Perl. Tot ce trebuie să faci este să indici locația depozitului Pinto:
cpanm --mirror file://$HOME/repo --mirror-only My::App
Acesta va instala My::App folosind numai modulele din depozitul tău Pinto. În consecință vei obține exact aceleași versiuni ale acelor module de fiecare dată, chiar dacă modulul este eliminat sau actualizat pe CPAN.
La folosirea utilitarului cpanm, opțiunea --mirror-only este
importantă pentru că împiedică folosirea sitului public CPAN în cazul
în care nu găsește un anumit modul în depozitul tău. De obicei când
se întâmplă aceasta, înseamnă că o anumită distribuție din depozit nu
are toate dependențele declarate corect în fișierul său META. Pentru
a rezolva problema, folosește comanda pull
pentru a adăuga
modulele care lipsesc.
Actualizarea Modulelor
Să presupunem că au trecut câteva săptămâni de când ai lansat
aplicația My-App și acum versiunea 1.62 a modulului URI este
disponibilă pe CPAN. Are niște corecții critice pe care ai dori să le incluzi. Tot așa putem include noua versiune în depozit folosind comanda
pull
. Dar deoarece depozitul tău conține deja o versiune a
modulului URI, trebui să indici că dorești o versiune mai nouă
specificând versiunea minimă dorită:
pinto -r ~/repo pull URI~1.62
Dacă te uiți la rezultatul comenzii de listare din nou, de acestă dată vei vedea noua versiune a modulului URI (și posibil de asemenea și pentru alte module):
rl My::App 1.0 JEFF/My-App-1.0.tar.gz
rf URI 1.62 GAAS/URI-1.62.tar.gz
rf URI::Escape 3.38 GAAS/URI-1.62.tar.gz
rf URI::Heuristic 4.20 GAAS/URI-1.62.tar.gz
...
Dacă noua versiune a modului URI necesită actualizări ale modulelor dependente sau dependențe suplimentare, acelea vor fi de asemenea adăugate în depozit. Iar la instalarea My::App, vei obține versiunea 1.62 a modulului URI.
Lucrul Cu Stive - Stacks
Până acum am tratat depozitul ca pe o resursă singulară. La actualizarea modulului URI în secțiunea de mai sus, au fost afectate toate persoanele și toate aplicațiile care ar fi utilizat depozitul. Acest fel de impact larg nu este de dorit. Este de preferat să faci modificări în izolare și să le testezi înainte de a forța pe toți ceilalți utilizatori să facă actualizarea. Pentru aceasta sunt folosite stivele: stacks.
Toate depozitele de tip CPAN au un index care leagă ultima versiune al fiecărui modul de arhiva care-l conține. Uzual, există doar un singur index pentru fiecare depozit. Dar în depozitele Pinto, pot fi mai multe indexuri. Fiecare dintre aceste indexuri poartă denumirea "stack". Aceasta permite crearea de stive diferite pentru dependențele dintr-un depozit. Deci poți avea o stivă "development", una "production", sau una "perl-5.8" și una "perl-5.16". De câte ori adaugi sau actualizezi un modul, va fi afectată o singură stivă.
Înainte de a merge mai departe, trebuie să vorbim despre stiva implicită. Pentru majoritatea operațiunilor, numele stivei este un parametru opțional. Dacă nu este specificat explicit, atunci comanda este aplicată la stiva marcată ca implicită.
Într-un depozit nu este decât o singură stivă implicită. Când a fost creat depozitul, a fost creată și o stivă numită "master" și marcată ca implicită. Poți schimba stiva implicită sau numele ei, dar nu vom intra în detalii aici. Este de ținut minte că "master" este numele stivei care a fost creată când a fost inițializat depozitul.
Crearea Unei Stive
Să presupunem că depozitul tău conține versiunea 1.60 a modulului URI dar versiune 1.62 a fost lansată pe CPAN, cu puțin timp în urmă. Dorești să încerci actualizarea, dar de data asta vei face-o pe o stivă separată.
Până acum tot ce ai adăugat în depozit a utilizat stiva "master". Vom
face o clonă a acelei stive folosind comanda copy
:
pinto -r ~/repo copy master uri_upgrade
Această comandă va crea o nouă stivă numită "uri_upgrade". Dacă
dorești să vezi conținutul stivei, folosește comanda list
cu
opțiunea "--stack":
pinto -r ~/repo list --stack uri_upgrade
Lista ar trebui să fie identică cu cea a stivei "master":
rl My::App 1.0 JEFF/My-App-1.0.tar.gz
rf URI 1.60 GAAS/URI-1.60.tar.gz
...
Actualizarea Unei Stive
Acum că avem o stivă separată, putem încerca să actualizăm modulul
URI. Ca și până acum vom folosi comanda pull
. Dar de acestă
dată, vom instrui Pinto să adauge modulele la stiva "uri_upgrade":
pinto -r ~/repo pull --stack uri_upgrade URI~1.62
Putem să comparăm stivele "master" și "uri_upgrade" folosind comanda "diff":
pinto -r ~/repo diff master uri_upgrade
+rf URI 1.62 GAAS/URI-1.62.tar.gz
+rf URI::Escape 3.31 GAAS/URI-1.62.tar.gz
+rf URI::Heuristic 4.20 GAAS/URI-1.62.tar.gz
...
-rf URI 1.60 GAAS/URI-1.60.tar.gz
-rf URI::Escape 3.31 GAAS/URI-1.60.tar.gz
-rf URI::Heuristic 4.20 GAAS/URI-1.60.tar.gz
Rezultatul este similar cu cel al comenzii diff(1). Înregistrările care încep cu "+" au fost adăugate iar cele care încep cu "-" au fost șterse. Se poate vedea că modulele din distribuția URI-1.60 au fost înlocuite cu modulele din distribuția URI-1.62.
Instalare Dintr-o Stivă
Odată ce ai modulele noi în stiva "uri_upgrade", poți încerca să construiești aplicația indicând comenzii cpanm stiva. Fiecare stivă este doar un subdirector din depozit, deci tot ce trebuie să faci este să-l adaugi la URL:
cpanm --mirror file://$HOME/repo/stacks/uri_upgrade --mirror-only My::App
Dacă toate teste sunt încheiate cu succes, atunci poți actualiza, cu
încredere, modulul URI la versiunea 1.62 și în stiva "master" folosind
comanda pull
. Stiva "master" fiind stiva implicită, poți
omite parametrul "--stack":
pinto -r ~/repo pull URI~1.62
Comanda Pin
Stivele sunt un mod bun de a testa efectul schimbării dependențelor aplicației tale. Dar dacă testele eșuează? Dacă problema ține de My-App și poți să o corectezi rapid, ai putea să modifici codul, să lansezi versiunea 2.0 a My-App, și după aceea să actualizezi URI din stiva "master".
Dar dacă problema este o hibă în URI sau va dura mult pentru a remedia My-App, atunci ai o problemă. Nu vei dori ca altcineva să actualizeze URI, nici să fie actualizată pe șest ca urmare a unor dependențe pe care My-App le-ar putea avea. Trebuie prevenită actualizarea URI până când problema este rezolvată. Pentru aceasta există comanda "pin".
Utilizarea Comenzii Pin
Când folosești comanda "pin" asupra unui modul, acea versiune a
modulului este forțată să stea în stivă. Orice încercare de
actualizare (directă sau via dependințe) va eșua. Acest efect se
obține folosind comanda pin
:
pinto -r ~/repo pin URI
Dacă analizezi listingul stivei "master" încă o dată, vei vedea ceva de genul acesta:
...
rl My::App 1.0 JEFF/My-App-1.0.tar.gz
rf! URI 1.60 GAAS/URI-1.60.tar.gz
rf! URI::Escape 3.31 GAAS/URI-1.60.tar.gz
...
Semnul "!" de lângă începutul unei înregistrări indică starea de blocare a versiunii modulului în urma comenzii "pin". Oricine ar încerca să actualizeze URI sau să adauge o distribuție care necesită o versiune mai nouă a URI, va primi o atenționare din partea Pinto care va refuza să accepte noile distribuții. Notați că toate modulele din distribuția URI-1.60 sunt marcate, deci este imposibil să actualizezi parțial o distribuție (acestă situație poate apărea atunci când un modul este mutat în altă distribuție).
Ridicarea Restricției Comenzii Pin
După un timp, să presupunem că ai rezolvat problemele din My-App sau a
fost lansată o nouă versiune a URI care rezolvă hiba. În această
situație, poți să folosești comanda unpin
asupra URI pentru a
ridica restricția de actualizare.
pinto -r ~/repo unpin URI
În acest moment ești liber să actualizezi URI la cea mai nouă versiune. La fel ca în cazul comenzii pin, unpin afectează toate modulele distribuției.
Pin şi Stack Împreună
Funcțiile pin și stack sunt deseori folosite împreună pentru a ajuta la administrarea modificărilor din timpul ciclului de dezvoltare. De exemplu, ai putea crea o stivă numită "prod" care conține dependențele știute a fi fără probleme. În același timp, ai putea crea o stivă numită "dev" care conține dependențe experimentale pentru noua ta lansare. Inițial, stiva "dev" este doar o copie a stivei "prod".
În cursul procesului de dezvoltare, poți actualiza sau adăuga module în stiva "dev". Dacă vreunul dintre modulele actualizate afectează aplicația, atunci poți bloca actualizarea acelui modul în stiva "prod" folosind comanda "pin".
Pin Și Petece
Pot apărea situații când o nouă versiune a unei distribuții CPAN are o hibă pe care autorul nu dorește sau nu poate să o rezolve (cel puțin până la termenul limită al noii tale lansări). În această situație, poți decide să aplici un petec local la acea distribuție CPAN.
Să presupunem că ai creat o ramificație a codului (fork) pentru URI și
o versiune locală a distribuției numită URI-1.60_PATCHED.tar.gz. Poți
s-o adaugi la depozit folosind comanda add
:
pinto -r ~/repo add path/to/URI-1.60_PATCHED.tar.gz
În această situație, este necesar să aplici și comanda pin, pentru că nu este de dorit ca distribuția să fie actualizată până când nu ești sigur că noua versiune de pe CPAN include petecul tău sau că autorul a rezolvat hiba prin alte mijloace.
pinto -r ~/repo pin URI
Când autorul URI lansează versiunea 1.62, vei dori să o testezi înainte
de a decide să permiți actualizarea (unpin) versiunii locale peticite. La
fel ca mai înainte acesta se poate face clonând stiva cu ajutorul comenzii copy
.
S-o numim stiva "trial" de această dată:
pinto -r ~/repo copy master trial
Dar înainte de a putea face actualizarea URI, trebuie să ridicăm restricția de pe stiva "trial", folosind comanda "unpin":
pinto -r ~/repo unpin --stack trial URI
Acum poți să actualizezi URI pe stivă și poți să încerci să construiești My::App astfel:
pinto -r ~/repo pull --stack trial URI~1.62
cpanm --mirror file://$HOME/repo/stacks/trial --mirror-only My::App
Dacă totul este bine, ridică restricția și de pe stiva "master" și adaugă noua versiune a URI.
pinto -r ~/repo unpin URI
pinto -r ~/repo pull URI~1.62
Recenzia Modificărilor Din Trecut
Așa cum probabil ați remarcat deja până acum, fiecare comandă care
schimbă starea unei stive necesită un mesaj care să o descrie. Poți
recenza acele mesaje folosind comanda log
:
pinto -r ~/repo log
Rezultatul ar trebui să arate cam așa:
revision 4a62d7ce-245c-45d4-89f8-987080a90112
Date: Mar 15, 2013 1:58:05 PM
User: jeff
Pin GAAS/URI-1.59.tar.gz
Pinning URI because it is not causes our foo.t script to fail
revision 4a62d7ce-245c-45d4-89f8-987080a90112
Date: Mar 15, 2013 1:58:05 PM
User: jeff
Pull GAAS/URI-1.59.tar.gz
URI is required for HTTP support in our application
...
Antetul fiecărui mesaj arată autorul și data modificării. Are de asemenea un identificator unic similar codificării SHA-1 folosit de Git. Poți folosi acești identificatori pentru a vedea diferențele dintre diverse revizii sau ca să resetezi stiva la o revizie anterioară [NB: această funcționalitate nu este încă implementată].
Concluzii
În acest tutorial, ai văzut comenzile de bază pentru crearea și popularea unui depozit Pinto. De asemenea ai văzut cum să folosești stivele și comanda "pin" pentru a administra dependențele pentru a trece de obstacolele întâlnite în cursul dezvoltării de software.
Fiecare comandă are mai multe opțiuni pe care nu le-am discutat în acest tutorial, și de asemenea comenzi pe care nu le-am menționat aici deloc. În consecință te încurajez să explorezi paginile de manual ale fiecărei comenzi și să înveți mai mult.