Scroll to navigation

DEBCONF-DEVEL(7) Miscellaneous Information Manual DEBCONF-DEVEL(7)

NUME

debconf - ghidul dezvoltatorilor

DESCRIERE

Acesta este un ghid pentru dezvoltarea de pachete care utilizează debconf.

Acest manual presupune că sunteți familiarizat cu debconf în calitate de utilizator și că sunteți familiarizat cu elementele de bază ale construcției pachetelor debian.

Acest manual începe prin a explica două fișiere noi care sunt adăugate la pachetele debian care utilizează debconf. Apoi explică modul în care funcționează protocolul debconf și vă indică câteva biblioteci care vor permite programelor dvs. să utilizeze protocolul. Sunt discutate și alte scripturi de întreținere în care debconf este utilizat în mod obișnuit: scripturile „postinst” și „postrm”. Apoi trece la subiecte mai avansate, cum ar fi șabloanele debconf partajate, depanarea și unele tehnici și capcane comune ale programării cu debconf. Se încheie cu o discuție despre deficiențele actuale ale debconf.

SCRIPTUL DE CONFIGURARE

Debconf adaugă un script de întreținere suplimentar, scriptul „config”, la setul de scripturi de întreținere care pot fi în pachetele debian („postinst”, „preinst”, „postrm” și „prerm”). Scriptul config este responsabil cu adresarea oricăror întrebări necesare pentru configurarea pachetului.

Notă: Este puțin confuz faptul că dpkg se referă la rularea scriptului „postinst” al unui pachet ca la „configurarea” pachetului, deoarece un pachet care utilizează debconf este adesea complet pre-configurat, prin scriptul său de configurare, înainte ca scriptul „postinst” să fie rulat vreodată. În fine!

La fel ca „postinst”, scriptul „config” primește doi parametri atunci când este rulat. Primul spune ce acțiune este efectuată, iar al doilea este versiunea pachetului care este instalat în prezent. Astfel, la fel ca în „postinst”, puteți utiliza dpkg --compare-versions pe $2 pentru a face ca un anumit comportament să se întâmple numai la actualizarea de la o anumită versiune a unui pachet și alte lucruri de acest gen.

Scriptul de configurare poate fi rulat în trei moduri:

1
Dacă un pachet este preconfigurat, cu dpkg-preconfigure, scriptul său de configurare este rulat și i se transmit parametrii „configure” și installed-version.
2
Atunci când scriptul „postinst” al unui pachet este rulat, debconf va încerca să ruleze și scriptul „config”, iar acestuia i se vor pasa aceiași parametri care i-au fost pasați atunci când a fost preconfigurat. Acest lucru este necesar deoarece este posibil ca pachetul să nu fi fost preconfigurat, iar scriptul „config” trebuie să aibă în continuare șansa de a se executa. Consultați secțiunea TRUCURI pentru detalii.
3
Dacă un pachet este reconfigurat, cu dpkg-reconfigure, scriptul său „config” este rulat și i se transmit parametrii „reconfigure” și installed-version.

Rețineți că, deoarece o instalare sau o actualizare tipică a unui pachet utilizând apt execută pașii 1 și 2, scriptul „config” va fi de obicei executat de două ori. Acesta nu ar trebui să facă nimic a doua oară (a pune întrebări de două ori la rând este enervant) și ar trebui cu siguranță să fie idempotent. Din fericire, debconf evită implicit repetarea întrebărilor, astfel încât acest lucru este în general ușor de realizat.

Rețineți că scriptul „config” este rulat înainte ca pachetul să fie despachetat. Acesta ar trebui să utilizeze numai comenzile care se află în pachetele esențiale. Singura dependență a pachetului dvs. care este garantată a fi îndeplinită atunci când scriptul config este rulat este o dependență (posibil cu o versiune specificată) de debconf însuși.

Scriptul „config” nu ar trebui să fie nevoit să modifice deloc sistemul de fișiere. Acesta examinează doar starea sistemului și pune întrebări, iar debconf stochează răspunsurile pentru a fi utilizate ulterior de scriptul „postinst”. În schimb, scriptul „postinst” nu ar trebui să utilizeze aproape niciodată debconf pentru a pune întrebări, ci ar trebui să acționeze pe baza răspunsurilor la întrebările puse de scriptul „config”.

FIȘIERUL DE ȘABLOANE „TEMPLATES”

Un pachet care utilizează debconf dorește probabil să pună câteva întrebări. Aceste întrebări sunt stocate, sub formă de șablon, în fișierul templates.

La fel ca scriptul config, fișierul templates este pus în secțiunea control.tar.gz a unui deb. Formatul său este similar cu cel al unui fișier de control debian; un set de strofe separate prin linii goale, fiecare strofă având o formă similară formatului RFC822:


Template: foo/bar
Type: string
Defult: foo
Description: Aceasta este un exemplu de chestionar.
Aceasta este descrierea sa extinsă.
.
Rețineți că:n
- Ca în descrierea unui pachet debian, un punct plasat
singur pe linie marchează începutul unui nou paragraf.
- Majoritatea textului este încadrat în cuvinte, dar textul
cu dublă aliniere este lăsat singur, deci îl puteți folosi
pentru liste de elemente, precum această listă. Fiți atenți,
deoarece acesta nu este încadrat în cuvinte, dacă este
prea lat va arăta urât. Utilizarea lui pentru elemente scurte
este cel mai potrivit (deci acesta este un exemplu prost).


Template: foo/baz
Type: boolean
Description: Destul de clar, nu?
Aceasta este o altă întrebare, de tip boolean.

Pentru câteva exemple reale de fișiere șablon, consultați „/var/lib/dpkg/info/debconf.templates” și alte fișiere „.templates” din acel director.

Să analizăm pe rând fiecare dintre câmpuri.

Numele șablonului, în câmpul „Template”, este în general precedat de numele pachetului. După aceea, spațiul de nume este foarte liber; puteți utiliza un aspect plat simplu, precum cel de mai sus, sau puteți crea „subdirectoare” care să conțină întrebări conexe.
Tipul șablonului determină ce tip de element de meniu este afișat utilizatorului. Tipurile acceptate în prezent sunt:
Rezultă un câmp de intrare cu formă liberă în care utilizatorul poate introduce orice șir de caractere.
Solicită utilizatorului o parolă. Utilizați această opțiune cu precauție; fiți conștienți de faptul că parola introdusă de utilizator va fi scrisă în baza de date a debconf. Probabil ar trebui să eliminați această valoare din baza de date cât mai curând posibil.
O alegere adevărat/fals (true/false).
O alegere între una dintre mai multe valori. Opțiunile trebuie specificate într-un câmp numit „Choices”. Separați valorile posibile cu virgule și spații, astfel:

Choices: da, nu, poate
La fel ca tipul de date de selectare, cu excepția faptului că utilizatorul poate alege orice număr de elemente din lista de opțiuni (sau poate să nu aleagă niciuna dintre ele).
Mai degrabă decât o întrebare în sine, acest tip de date indică o notă care poate fi afișată utilizatorului. Ar trebui utilizat numai pentru note importante pe care utilizatorul ar trebui să le vadă, deoarece debconf se va strădui foarte mult să se asigure că utilizatorul le vede, oprind instalarea pentru ca acesta să apese o tastă. Cel mai bine este să le folosiți doar pentru avertizări cu privire la probleme foarte grave, iar tipul de date error este adesea mai potrivit.
Acest tip de date este utilizat pentru mesajele de eroare, cum ar fi erorile de validare a intrărilor. Debconf va afișa o întrebare de acest tip chiar dacă prioritatea este prea mare sau dacă utilizatorul a văzut-o deja.
Acest tip de date este utilizat pentru titluri, pentru a fi definite cu comanda SETTITLE.
Acest tip de date poate fi utilizat pentru fragmente de text, cum ar fi etichetele, care pot fi utilizate din motive cosmetice în afișajele unor interfețe. Alte interfețe nu îl vor utiliza deloc. Deocamdată nu are rost să utilizați acest tip de date, deoarece nicio interfață nu îl acceptă bine. Acesta ar putea fi chiar eliminat în viitor.
Câmpul „Default” indică debconf care ar trebui să fie valoarea implicită. Pentru multiselect, aceasta poate fi o listă de opțiuni, separate prin virgule și spații, similar câmpului „Choices”. Pentru select, ar trebui să fie una dintre opțiuni. Pentru boolean, este „true” sau „false”, în timp ce poate fi orice pentru un string și este ignorat pentru password.

Nu faceți greșeala de a crede că câmpul Default conține „valoarea” întrebării sau că poate fi utilizat pentru a modifica valoarea întrebării. Nu este așa și nici nu poate fi, ci doar oferă o valoare implicită pentru prima dată când este afișată întrebarea. Pentru a furniza o valoare implicită care se modifică din mers, ar trebui să utilizați comanda SET pentru a modifica valoarea unei întrebări.

Câmpul „ Description ”, ca și descrierea unui pachet Debian, are două părți: O descriere scurtă și o descriere extinsă. Rețineți că unele interfețe debconf nu afișează descrierea lungă sau o pot afișa doar dacă utilizatorul cere ajutor. Așadar, descrierea scurtă ar trebui să fie capabilă „să se descurce” singură.

Dacă nu vă puteți gândi la o descriere lungă, atunci mai întâi, gândiți-vă mai mult. Adresați-vă la debian-devel. Cereți ajutor. Luați un curs de scriere! Acea descriere extinsă este importantă. Dacă după toate astea tot nu vă vine nimic în minte, lăsați-o goală. Nu are rost să duplicați descrierea scurtă.

Textul din descrierea extinsă va fi încadrat în cuvinte, cu excepția cazului în care este prefixat de un spațiu alb suplimentar (în afară de spațiul necesar). Îl puteți împărți în paragrafe separate punând „ .” pe o linie de sine stătătoare între ele.

ÎNTREBĂRI

O întrebare este o instanță a unui șablon. Solicitând debconf să afișeze o întrebare, scriptul dvs. „config” poate interacționa cu utilizatorul. Atunci când debconf încarcă un fișier de șabloane (acest lucru se întâmplă ori de câte ori se execută un script „config” sau „postinst”), acesta creează automat o instanță de întrebare din fiecare șablon. De fapt, este posibilă crearea de instanțe de mai multe întrebări independente din același șablon (utilizând comanda REGISTER), dar acest lucru este rareori necesar. Șabloanele sunt date statice care provin din fișierul de șabloane, în timp ce întrebările sunt utilizate pentru a stoca date dinamice, cum ar fi valoarea curentă a întrebării, dacă un utilizator a văzut o întrebare și așa mai departe. Țineți cont de distincția dintre un șablon și o întrebare, dar nu vă faceți prea multe griji cu privire la aceasta.

ȘABLOANE PARTAJATE

De fapt, este posibil să existe un șablon și o întrebare care sunt partajate între un set de pachete. Toate pachetele trebuie să furnizeze o copie identică a șablonului în fișierele lor de șabloane. Acest lucru poate fi util dacă o serie de pachete trebuie să pună aceeași întrebare și doriți să deranjați utilizatorul o singură dată cu aceasta. Șabloanele partajate sunt în general plasate în pseudo-directorul shared/ din spațiul de nume al șabloanelor debconf.

PROTOCOLUL DEBCONF

Scripturile „config” comunică cu debconf utilizând protocolul debconf. Acesta este un protocol simplu orientat pe linii, similar protocoalelor comune de Internet, cum ar fi SMTP. Scriptul „config” trimite o comandă către debconf prin scrierea comenzii la ieșirea standard. Apoi poate citi răspunsul debconf de la intrarea standard.

Răspunsul Debconf poate fi împărțit în două părți: Un cod de rezultat numeric (primul cuvânt al răspunsului) și un cod de rezultat extins opțional (restul răspunsului). Codul numeric utilizează 0 pentru a indica succesul, iar alte numere pentru a indica diferite tipuri de eșecuri. Pentru detalii complete, consultați tabelul din documentul de specificații debconf al politicii Debian.

Codul de returnare extins este, în general, liber și nespecificat, astfel încât, în general, ar trebui să îl ignorați și cu siguranță nu ar trebui să încercați să îl analizați într-un program pentru a afla ce face debconf. Excepție fac comenzile precum GET, care fac ca o valoare să fie returnată în codul de răspuns extins.

În general, veți dori să utilizați o bibliotecă specifică limbajului care să se ocupe de configurarea acestor conexiuni la debconf și de comunicarea cu acesta.

Pentru moment, aici sunt comenzile din protocol. Aceasta nu este definiția definitivă, consultați documentul de specificații debconf al politicii Debian pentru aceasta.

În general, nu este necesar să utilizați această comandă. Aceasta schimbă cu debconf numărul versiunii protocolului care este utilizat. Versiunea actuală a protocolului este 2.0, iar versiunile din seria 2.x vor fi retrocompatibile. Puteți specifica numărul versiunii protocolului pe care îl vorbiți, iar debconf va returna versiunea protocolului pe care îl vorbește în codul de rezultat extins. Dacă versiunea pe care o specificați este prea mică, debconf va răspunde cu codul numeric 30.
În general, nu este necesar să utilizați această comandă. Aceasta schimbă cu debconf o listă de capacități acceptate (separate prin spații). Capacitățile pe care atât dumneavoastră, cât și debconf le acceptați vor fi utilizate, iar debconf va răspunde cu toate capacitățile pe care le acceptă.

Dacă „escape” se găsește printre capacitățile dvs., debconf se va aștepta ca comenzile pe care i le trimiteți să aibă bare oblice și linii noi eludate (ca \\ și respectiv \n) și va eluda la rândul său bare oblice și linii noi în răspunsurile sale. Acest lucru poate fi utilizat, de exemplu, pentru a înlocui șiruri de caractere cu mai multe linii în șabloane sau pentru a obține descrieri extinse cu mai multe linii în mod fiabil utilizând METAGET. În acest mod, trebuie să eludați singuri textul de intrare (dacă doriți, puteți utiliza debconf-escape(1) pentru a vă ajuta în acest sens), iar bibliotecile confmodule vor elimina eludarea din răspunsuri pentru dumneavoastră.

Aceasta definește titlul pe care debconf îl afișează utilizatorului, utilizând descrierea scurtă a șablonului pentru întrebarea specificată. Șablonul trebuie să fie de tip title. Rareori trebuie să utilizați această comandă, deoarece debconf poate genera automat un titlu bazat pe numele pachetului dvs.

Definirea titlurilor dintr-un șablon înseamnă că acestea sunt stocate în același loc ca și restul întrebărilor debconf și permite traducerea lor.

Aceasta stabilește titlul pe care debconf îl afișează utilizatorului la șirul specificat. Utilizarea comenzii SETTITLE este în mod normal de preferat, deoarece permite traducerea titlului.
Solicită debconf să se pregătească pentru a afișa o întrebare utilizatorului. Întrebarea nu este afișată efectiv până când nu este emisă o comandă GO; acest lucru permite ca mai multe comenzi INPUT să fie date în serie, pentru a construi un set de întrebări, care ar putea fi adresate toate pe un singur ecran.

Câmpul de prioritate îi indică lui debconf cât de important este ca această întrebare să fie afișată utilizatorului. Valorile priorității sunt:

Elemente foarte banale care au valori implicite care vor funcționa în marea majoritate a cazurilor; doar obsedații de control le văd.
Elemente normale care au valori implicite rezonabile.
Elemente care nu au o valoare implicită rezonabilă.
Elemente care probabil vor distruge sistemul fără intervenția utilizatorului.

Debconf decide dacă întrebarea este afișată efectiv, pe baza priorității sale, dacă utilizatorul a mai văzut-o înainte și ce interfață este utilizată. Dacă întrebarea nu va fi afișată, debconf răspunde cu codul 30.

Îi indică lui debconf să afișeze utilizatorului setul acumulat de întrebări (din comenzile INPUT).

Dacă capacitatea de copiere de rezervă este acceptată și utilizatorul indică faptul că dorește să copieze de rezervă un pas, debconf răspunde cu codul 30.

Șterge setul acumulat de întrebări (de la comenzile INPUT) fără a le afișa.
Unele interfețe debconf pot afișa utilizatorului un număr de întrebări simultan. Poate că în viitor o interfață va putea chiar să grupeze aceste întrebări în blocuri pe ecran. BEGINBLOCK și ENDBLOCK pot fi plasate în jurul unui set de comenzi INPUT pentru a indica blocuri de întrebări (iar blocurile pot fi chiar imbricate). Deoarece nicio interfață debconf nu este încă atât de sofisticată, aceste comenzi sunt ignorate pentru moment.
Această comandă îi indică lui debconf că ați terminat de dialogat cu el. Adesea, debconf poate detecta terminarea programului dvs. și această comandă nu este necesară.
După ce utilizați INPUT și GO pentru a afișa o întrebare, puteți utiliza această comandă pentru a obține valoarea introdusă de utilizator. Valoarea este returnată în codul de rezultat extins.
Aceasta stabilește valoarea unei întrebări și poate fi utilizată pentru a înlocui valoarea implicită cu ceva ce programul dvs. calculează din mers.
Aceasta readuce întrebarea la valoarea sa implicită (așa cum este specificată în câmpul „ Default ” al șablonului său).
Întrebările pot avea substituții încorporate în câmpurile „Description” și „Choices” (utilizarea substituțiilor în câmpurile „Choices” este un pic de improvizație; un mecanism mai bun va fi dezvoltat în cele din urmă). Aceste substituții arată ca „${key}”. Atunci când întrebarea este afișată, substituțiile sunt înlocuite cu valorile lor. Această comandă poate fi utilizată pentru a defini valoarea unei substituții. Acest lucru este util dacă trebuie să afișați utilizatorului un mesaj pe care nu îl puteți codifica în interiorul codului din fișierul de șabloane.
Nu încercați să utilizați SUBST pentru a schimba valoarea implicită a unei întrebări; nu va funcționa, deoarece există o comandă SET explicită pentru acest scop.
Întrebările pot avea asociate fanioane. Fanioanele pot avea o valoare de „true” sau „false”. Această comandă returnează valoarea unui fanion.
Aceasta stabilește valoarea fanionului unei întrebări. Valoarea trebuie să fie „true” sau „false”.

Un fanion comun este fanionul „seen”. În mod normal, acesta este activat numai dacă un utilizator a văzut deja o întrebare. De obicei, Debconf afișează întrebările utilizatorilor numai dacă aceștia au fanionul seen definit la „false” (sau dacă reconfigurează un pachet). Uneori doriți ca utilizatorul să vadă din nou o întrebare - în aceste cazuri, puteți defini fanionul seen la „false” pentru a forța debconf să o afișeze din nou.

Aceasta returnează valoarea oricărui câmp din șablonul asociat unei întrebări ( descrierea Description, de exemplu).
Aceasta creează o întrebare nouă care este legată de un șablon. În mod implicit, fiecare șablon are asociată o întrebare cu același nume. Cu toate acestea, orice număr de întrebări poate fi asociat cu un șablon, iar acest lucru vă permite să creați mai multe astfel de întrebări.
Aceasta elimină o întrebare din baza de date.
Apelați această comandă în scriptul dvs. „postrm” atunci când pachetul dvs. este purjat. Aceasta elimină toate întrebările pachetului dvs. din baza de date a debconf.
Această extensie încarcă fișierul șablon specificat în baza de date a debconf. Proprietarul este implicit pachetul care este configurat cu debconf.

Iată un exemplu simplu de protocol debconf în acțiune.


INPUT medium debconf/frontend
30 question skipped
FSET debconf/frontend seen false
0 false
INPUT high debconf/frontend
0 question will be asked
GO
[ Aici debconf afișează o întrebare pentru utilizator. ]
0 ok
GET no/such/question
10 no/such/question doesn't exist
GET debconf/frontend
0 Dialog

BIBLIOTECI

Configurarea lucrurilor astfel încât să puteți comunica cu debconf și să dialogați cu el prin intermediul protocolului debconf este un pic prea mult de lucru, așa că există câteva biblioteci mici pentru a ușura această corvoadă minoră.

Pentru programarea în shell, există biblioteca „/usr/share/debconf/confmodule”, pe care o puteți utiliza ca sursă în partea de sus a unui script de tip shell și care vă permite să comunicați cu debconf într-un mod destul de natural, utilizând versiuni cu minuscule ale comenzilor protocolului debconf, care sunt prefixate cu „db_” (de exemplu, „db_input” și „db_go”). Pentru detalii, consultați confmodule(3) .

Programatorii Perl pot utiliza modulul perl Debconf::Client::ConfModule(3pm), iar programatorii python pot utiliza modulul python debconf.

Restul acestui manual va utiliza biblioteca „/usr/share/debconf/confmodule” în exemple de scripturi shell. Iată un exemplu de script de configurare care utilizează această bibliotecă, care pune doar o întrebare:


#!/bin/sh
set -e
. /usr/share/debconf/confmodule
db_set mypackage/reboot-now false
db_input high mypackage/reboot-now || true
db_go || true

Observați utilizarea lui „|| true” pentru a preveni moartea scriptului dacă debconf decide că nu poate afișa o întrebare sau dacă utilizatorul încearcă să dea înapoi. În aceste situații, debconf returnează un cod de ieșire diferit de zero și, din moment ce acest script shell este definit cu „ -e”, un cod de ieșire nepreluat l-ar face să abandoneze.

Și aici este un script „postinst” corespunzător, care utilizează răspunsul utilizatorului la întrebare pentru a vedea dacă sistemul ar trebui repornit (un exemplu destul de absurd..):


#!/bin/sh
set -e
. /usr/share/debconf/confmodule
db_get mypackage/reboot-now
if [ "$RET" = true ]; then
shutdown -r now
fi

Observați utilizarea variabilei $RET pentru a obține codul de răspuns extins de la comanda GET, care conține răspunsul utilizatorului la întrebare.

SCRIPTUL POSTINST

Ultima secțiune conținea un exemplu de script „postinst” care utilizează debconf pentru a obține valoarea unei întrebări și pentru a acționa în funcție de aceasta. Iată câteva lucruri de care trebuie să țineți cont atunci când scrieți scripturi „postinst” care utilizează debconf:

*
Evitați să puneți întrebări în „postinst”. În schimb, scriptul „config” ar trebui să pună întrebări utilizând debconf, astfel încât pre-configurarea să funcționeze.
*
Întotdeauna sursa „/usr/share/debconf/confmodule” în partea de sus a scriptului dvs. „postinst”, chiar dacă nu veți executa nicio comandă db_* în acesta. Acest lucru este necesar pentru a vă asigura că scriptul „config” are șansa de a rula (consultați secțiunea TRUCURI pentru detalii).
*
Evitați să trimiteți ceva la ieșirea standard (stdout) în „postinst”, deoarece acest lucru poate crea confuzie în debconf, iar „postinst” nu ar trebui să fie oricum prea „vorbăreț”. Ieșirea la ieșirea de eroare standard este ok, dacă este necesar.
*
Dacă scriptul dvs. „postinst” lansează un demon, asigurați-vă că îi indicați lui debconf să efectueze STOP la sfârșit, deoarece debconf poate deveni puțin confuz cu privire la momentul în care scriptul dvs. postinst este gata.
*
Asigurați-vă că scriptul „postinst” acceptă un prim parametru „reconfigure”. Acesta îl poate trata la fel ca „configure”. Acesta va fi utilizat într-o versiune ulterioară a debconf pentru a anunța scripturile „postinist” atunci când sunt reconfigurate.

ALTE SCRIPTURI

Pe lângă scripturile „config” și „postinst”, puteți utiliza debconf în oricare dintre celelalte scripturi ale întreținătorului. Cel mai frecvent, veți utiliza debconf în „postrm”, pentru a apela comanda PURGE atunci când pachetul dvs. este purjat, pentru a curăța intrările sale din baza de date debconf. (Apropo, acest lucru este configurat automat pentru dvs. de dh_installdebconf(1),).

O utilizare mai implicată a debconf ar fi dacă doriți să o utilizați în „postrm” atunci când pachetul dvs. este curățat, pentru a pune o întrebare despre ștergerea a ceva. Sau poate descoperiți că trebuie să îl folosiți în „preinst” sau „prerm” pentru un motiv oarecare. Toate aceste utilizări vor funcționa, deși vor implica probabil adresarea de întrebări și luarea de măsuri în funcție de răspunsuri în același program, mai degrabă decât separarea celor două activități, așa cum se face în scripturile „config” și „postinst”.

Rețineți că, dacă singura utilizare a debconf de către pachetul dvs. este în „postrm”, ar trebui să faceți ca scriptul „postinst” a pachetului dvs. să includă „/usr/share/debconf/confmodule”, pentru a da debconf o șansă de a încărca fișierul șabloanelor dvs. în baza sa de date. Apoi, șabloanele vor fi disponibile atunci când pachetul dvs. este purjat.

De asemenea, puteți utiliza debconf în alte programe de sine stătătoare. Problema la care trebuie să fiți atenți aici este că debconf nu este destinat să fie și nu trebuie să fie utilizat ca un registru. La urma urmei, acesta este unix, iar programele sunt configurate de fișiere din „/etc”, nu de o bază de date nebuloasă debconf (care oricum este doar o cache și ar putea fi distrusă). Așa că gândiți-vă bine înainte de a utiliza debconf într-un program autonom.

Există momente în care poate avea sens, cum ar fi în programul apt-setup care utilizează debconf pentru a solicita utilizatorului o manieră consecventă cu restul procesului de instalare debian și acționează imediat în funcție de răspunsurile acestuia pentru a configura fișierul sources.list al apt.

LOCALIZAREA

Debconf acceptă traducerea fișierelor șablon. Acest lucru se realizează prin adăugarea mai multor câmpuri, cu text tradus în ele. Oricare dintre câmpuri poate fi tradus. De exemplu, ați putea dori să traduceți descrierea în română. Trebuie doar să creați un câmp numit „Description-ro” care să conțină traducerea. Dacă un câmp tradus nu este disponibil, debconf revine la câmpul normal în limba engleză.

Pe lângă câmpul „Description”, trebuie să traduceți câmpul „Choices” al unui șablon select sau multiselect. Asigurați-vă că listați opțiunile traduse în aceeași ordine în care apar în câmpul principal „Choices”. Nu este necesar să traduceți câmpul „Default” al unei întrebări select sau multiselect, iar valoarea întrebării va fi returnată automat în limba engleză.

Vă va fi mai ușor să gestionați traducerile dacă le păstrați în fișiere separate; un fișier pentru fiecare traducere. În trecut, programele debconf-getlang(1) și debconf-mergetemplate(1) erau utilizate pentru a gestiona fișierele debian/template.ll. Acestea au fost înlocuite de pachetul po-debconf(7), care vă permite să gestionați traducerile debconf în fișiere .po, la fel ca orice alte traduceri. Traducătorii dvs. vă vor mulțumi pentru utilizarea acestui nou mecanism îmbunătățit.

Pentru detalii despre po-debconf, consultați pagina sa de manual. Dacă utilizați debhelper, convertirea la po-debconf este la fel de simplă ca și rularea comenzii debconf-gettextize(1) o dată și adăugarea unui Build-Dependency în po-debconf și în debhelper (>= 4.1.13).

PUNÂND TOTUL CAP LA CAP

Deci, aveți un script „config”, un fișier templates, un script „postinst” care utilizează debconf și așa mai departe. Punerea acestor piese împreună într-un pachet debian nu este dificilă. O puteți face manual sau puteți utiliza dh_installdebconf(1), care va fuziona șabloanele traduse, va copia fișierele în locurile potrivite pentru dvs. și poate chiar genera apelul la PURGE care ar trebui să apară în scriptul „postrm”. Asigurați-vă că pachetul dvs. depinde de debconf (>= 0.5), deoarece versiunile anterioare nu erau compatibile cu tot ceea ce este descris în acest manual. Și ați terminat.

Este în regulă, cu excepția testării, a depanării și a utilizării debconf pentru lucruri mai interesante decât adresarea unor întrebări de bază. Pentru asta, citiți mai departe..

DEPANAREA

Deci, aveți un pachet care ar trebui să utilizeze debconf, dar nu prea funcționează. Poate că debconf pur și simplu nu pune întrebarea pe care ați stabilit-o. Sau poate se întâmplă ceva mai ciudat; se învârte la nesfârșit într-un fel de buclă, sau mai rău. Din fericire, debconf are o mulțime de facilități de depanare.

Primul lucru pe care trebuie să îl căutați este variabila de mediu DEBCONF_DEBUG. Dacă definiți și exportați DEBCONF_DEBUG=developer, debconf va afișa la ieșirea de eroare standard o captură a protocolului debconf în timp ce programul dvs. rulează. Acesta va arăta cam așa - greșeala de tastare este evidențiată:


debconf (developer): <-- input high debconf/frontand
debconf (developer): --> 10 "debconf/frontand" doesn't exist
debconf (developer): <-- go
debconf (developer): --> 0 ok

Este destul de util să utilizați interfața „readline” a debconf atunci când depanați (în opinia autorului), deoarece întrebările nu vă încurcă, iar toate rezultatele de depanare sunt ușor de păstrat și de înregistrat.

Dacă această variabilă de mediu este definită la „true”, interfața va afișa valorile din câmpurile Choices-C (dacă sunt prezente) ale șabloanelor select și multiselect mai degrabă decât valorile descriptive.
Un alt instrument util este programul debconf-communicate(1). Porniți-l și puteți comunica cu protocolul debconf în mod interactiv cu debconf. Aceasta este o modalitate excelentă de a încerca lucruri din mers.
Dacă un utilizator raportează o problemă, debconf-show(1) poate fi utilizat pentru a afișa toate întrebările deținute de pachetul dvs., afișând valorile acestora și dacă utilizatorul le-a văzut.
.debconfrc
Pentru a evita ciclul adesea plictisitor de compilare/ instalare/depanare, poate fi util să vă încărcați șabloanele cu debconf-loadtemplate(1) și să vă rulați manual scriptul „config” cu comanda debconf(1). Cu toate acestea, trebuie să faceți toate acestea ca root, nu? Nu este prea grozav. Și ideal ar fi să puteți vedea cum arată o instalare proaspătă a pachetului dumneavoastră, cu o bază de date debconf curată.

Se pare că, dacă configurați un fișier „~/.debconfrc” pentru un utilizator normal, care indică un fișier config.dat și template.dat personal pentru utilizator, puteți încărca șabloane și rula scripturi „config” cât doriți, fără acces root. Dacă doriți să începeți din nou cu o bază de date curată, pur și simplu îndepărtați fișierele *.dat.

Pentru detalii despre această configurare, consultați debconf.conf(5), și rețineți că „/etc/debconf.conf” este un model bun pentru un fișier „~/.debconfrc” personal.

PROGRAMARE AVANSATĂ CU DEBCONF

Gestionarea fișierelor de configurare

Mulți dintre dvs. par să dorească să utilizeze debconf pentru a ajuta la gestionarea fișierelor de configurare care fac parte din pachetul dvs. Poate că nu există o valoare implicită bună pentru a fi livrată într-un pachet și, prin urmare, doriți să utilizați debconf pentru a întreba utilizatorul și a scrie un fișier de configurare pe baza răspunsurilor sale. Acest lucru pare destul de ușor de făcut, dar apoi vă gândiți la actualizări și ce să faceți atunci când cineva modifică fișierul de configurare pe care îl generați, și dpkg-reconfigure, și ...

Există o mulțime de modalități de a face acest lucru, iar cele mai multe dintre ele sunt greșite și vă vor aduce deseori rapoarte de eroare enervante. Iată o modalitate corectă de a face acest lucru. Aceasta presupune că fișierul dvs. de configurare este de fapt doar o serie de variabile shell care trebuiesc definite, cu comentarii între ele, și astfel tot ce aveți de făcut, este doar să includeți sursa fișierului (ce conține valorile acestor variabile) pentru a-l „încărca”. Dacă aveți un format mai complicat, citirea (și scrierea) acestuia devine un pic mai complicată.

Scriptul dvs. de configurare va arăta cam așa:


#!/bin/sh
CONFIGFILE=/etc/foo.conf
set -e
. /usr/share/debconf/confmodule


# Încarcă fișierul de configurare, dacă există.
if [ -e $CONFIGFILE ]; then
. $CONFIGFILE || true


# Stochează valorile din fișierul de configurare
# în debconf db.
db_set mypackage/foo "$FOO"
db_set mypackage/bar "$BAR"
fi


# Pune întrebări.
db_input medium mypackage/foo || true
db_input medium mypackage/bar || true
db_go || true

Iar scriptul „postinst” va arăta cam așa:


#!/bin/sh
CONFIGFILE=/etc/foo.conf
set -e
. /usr/share/debconf/confmodule


# Generează fișierul de configurare, dacă acesta nu există.
# O alternativă este să copiați un fișier șablon din altă parte.
if [ ! -e $CONFIGFILE ]; then
echo "# Fișierul de configurare pentru pachetul meu" > $CONFIGFILE
echo "FOO=" >> $CONFIGFILE
echo "BAR=" >> $CONFIGFILE
fi


# Înlocuiește valorile din db debconf.
# Sunt posibile optimizări evidente aici.
# «cp» înainte de «sed» ne asigură că nu încurcăm
# proprietarul și permisiunile fișierului de configurare.
# the config file's ownership and permissions.
db_get mypackage/foo
FOO="$RET"
db_get mypackage/bar
BAR="$RET"
cp -a -f $CONFIGFILE $CONFIGFILE.tmp


# Dacă administratorul a șters sau a comentat unele variabile,
# dar apoi le-a definit prin debconf, (re)adăugați-le în conffile.
test -z "$FOO" || grep -Eq '^ *FOO=' $CONFIGFILE || \
echo "FOO=" >> $CONFIGFILE
test -z "$BAR" || grep -Eq '^ *BAR=' $CONFIGFILE || \
echo "BAR=" >> $CONFIGFILE


sed -e "s/^ *FOO=.*/FOO=\"$FOO\"/" \
-e "s/^ *BAR=.*/BAR=\"$BAR\"/" \
< $CONFIGFILE > $CONFIGFILE.tmp
mv -f $CONFIGFILE.tmp $CONFIGFILE

Luați în considerare modul în care aceste două scripturi tratează toate cazurile. La noile instalări, întrebările sunt adresate de scriptul „config”, iar un nou fișier se configurare este generat de „postinst”. La actualizări și reconfigurări, fișierul de configurare este citit, iar valorile din acesta sunt utilizate pentru a modifica valorile din baza de date debconf, astfel încât modificările manuale ale administratorului să nu fie pierdute. Întrebările sunt puse din nou (și pot fi afișate sau nu). Apoi „postinst” înlocuiește valorile înapoi în fișierul de configurare, lăsând restul acestuia neschimbat.

Permițând utilizatorului să revină la întrebarea anterioară

Puține lucruri sunt mai frustrante atunci când folosești un sistem precum debconf decât să ți se pună o întrebare, să răspunzi la ea, apoi să treci la un alt ecran cu o nouă întrebare pe el și să-ți dai seama că ai făcut o greșeală cu ultima întrebare și vrei să te întorci la ea și să descoperi că nu poți.

Deoarece debconf este condus de scriptul dvs. de configurare, acesta nu poate reveni singur la o întrebare anterioară, dar cu puțin ajutor din partea dvs., poate realiza această „performanță”. Primul pas este să faceți ca scriptul dvs. de configurare să informeze debconf că este capabil să gestioneze apăsarea unui buton înapoi de către utilizator. Utilizați comanda CAPB pentru a face acest lucru, trecând „backup” ca parametru.

Apoi, după fiecare comandă GO, trebuie să verificați dacă utilizatorul a cerut să revină la întrebarea anterioară (debconf returnează un cod de 30) și, în caz afirmativ, să săriți înapoi la întrebarea anterioară.

Există mai multe moduri de a scrie structurile de control ale programului dvs. astfel încât acesta să poată reveni la întrebările anterioare atunci când este necesar. Puteți scrie cod „spaghetti” încărcat de goto-uri. Sau puteți crea mai multe funcții și folosi recursivitatea. Dar poate cea mai curată și mai ușoară modalitate este să construiți o mașină de stare. Iată un schelet de mașină de stare pe care îl puteți completa și extinde.


#!/bin/sh
set -e
. /usr/share/debconf/confmodule
db_capb backup


STATE=1
while true; do
case "$STATE" in
1)
# Două întrebări care nu au legătură.
db_input medium my/question || true
db_input medium my/other_question || true
;;
2)
# Puneți această întrebare numai dacă
# răspunsul la prima întrebare a fost
# afirmativ.
db_get my/question
if [ "$RET" = "true" ]; then
db_input medium my/dep_question || true
fi
;;
*)
# Cazul implicit este detectat atunci când $STATE este mai mare
# decât ultima stare implementată și iese din buclă. Acest lucru
# necesită ca stările să fie numerotate consecutiv de la 1 fără
# întreruperi, deoarece cazul implicit va fi introdus și dacă există
# o întrerupere în numerotare
break # iese din bucla „while”.
;;
esac


if db_go; then
STATE=$((STATE + 1))
else
STATE=$((STATE - 1))
fi
done


if [ $STATE -eq 0 ]; then
# Utilizatorul a cerut să revină de la prima întrebare.
# Acest caz este problematic. Instalarea obișnuită a
# pachetelor dpkg și apt nu este capabilă să facă o
# copie de rezervă a întrebărilor între pachete, așa
# cum este scris acest lucru, astfel încât va ieși
# lăsând pachetul neconfigurat - probabil cel mai
# bun mod de a gestiona situația.
exit 10
fi

Rețineți că, dacă scriptul dvs. de configurare nu face decât să pună câteva întrebări fără legătură între ele, atunci nu este nevoie de mașina de stare. Doar puneți-le pe toate și „GO”; debconf va face tot posibilul să le prezinte pe toate într-un singur ecran, iar utilizatorul nu va trebui să se întoarcă.

Prevenirea buclelor infinite

O problemă cu debconf apare dacă aveți o buclă în scriptul de configurare. Să presupunem că solicitați o intrare și o validați, iar dacă aceasta nu este validă, faceți o buclă:


ok=”
do while [ ! "$ok" ];
db_input low foo/bar || true
db_go || true
db_get foo/bar
if [ "$RET" ]; then
ok=1
fi
done

Acest lucru pare în regulă la prima vedere. Dar gândiți-vă ce se întâmplă dacă valoarea lui foo/bar este „” atunci când se intră în această buclă, iar utilizatorul are stabilită o prioritate ridicată sau utilizează o interfață neinteractivă și, prin urmare, nu i se solicită cu adevărat un răspuns. Valoarea lui foo/bar nu este modificată de db_input și, prin urmare, nu trece testul și intră în buclă. Și bucle ...

O soluție este să vă asigurați că, înainte de a intra în buclă, valoarea foo/bar este stabilită la ceva care va trece testul în buclă. Astfel, de exemplu, dacă valoarea implicită a foo/bar este „1”, atunci puteți pune RESET foo/bar chiar înainte de a intra în buclă.

O altă soluție este să verificați codul de răspuns al comenzii INPUT. Dacă este 30, atunci utilizatorului nu i se arată întrebarea pe care i-ați pus-o și ar trebui să ieșiți din buclă.

Alegerea dintre pachetele conexe

Uneori poate fi instalat un set de pachete conexe și doriți să întrebați utilizatorul care dintre acestea ar trebui să fie utilizate în mod implicit. Exemple de astfel de seturi sunt administratorii de ferestre sau fișierele de dicționar ispell.

Deși ar fi posibil ca fiecare pachet din set să solicite pur și simplu „Acest pachet ar trebui să fie implicit?”, acest lucru duce la o mulțime de întrebări repetitive dacă sunt instalate mai multe pachete. Este posibil ca debconf să prezinte o listă a tuturor pachetelor din set și să permită utilizatorului să aleagă între ele. Iată cum.

Faceți ca toate pachetele din set să utilizeze un șablon comun. Ceva de genul acesta:


Template: shared/window-manager
Type: select
Choices: ${choices}
Description: Selectați administratorul implicit de ferestre.
Selectați administratorul de ferestre care va fi pornit
implicit la pornirea X.

Fiecare pachet ar trebui să includă o copie a șablonului. Apoi ar trebui să includă un cod ca acesta în scriptul său „config”:


db_metaget shared/window-manager owners
OWNERS=$RET
db_metaget shared/window-manager choices
CHOICES=$RET


if [ "$OWNERS" != "$CHOICES" ]; then
db_subst shared/window-manager choices $OWNERS
db_fset shared/window-manager seen false
fi


db_input medium shared/window-manager || true
db_go || true

Este necesară o mică explicație. În momentul în care scriptul dvs. de configurare rulează, debconf a citit deja toate șabloanele pentru pachetele care sunt instalate. Deoarece setul de pachete are o întrebare comună, debconf înregistrează acest fapt în câmpul „owners”. Printr-o coincidență ciudată, formatul câmpului owners este același cu cel al câmpului „choices” (o listă de valori delimitată prin virgule și spații).

Comanda METAGET poate fi utilizată pentru a obține lista de proprietari și lista de opțiuni. Dacă acestea sunt diferite, atunci a fost instalat un pachet nou. Prin urmare, utilizați comanda SUBST pentru a modifica lista de opțiuni pentru a fi aceeași cu lista de proprietari și puneți întrebarea.

Atunci când un pachet este eliminat, probabil doriți să vedeți dacă acel pachet este alegerea selectată în prezent și, în caz afirmativ, să solicitați utilizatorului să selecteze un alt pachet pentru a-l înlocui.

Acest lucru poate fi realizat prin adăugarea unui text ca acesta în scripturile „prerm” ale tuturor pachetelor aferente (înlocuind <package> cu numele pachetului):


if [ -e /usr/share/debconf/confmodule ]; then
. /usr/share/debconf/confmodule
# Nu mai solicit această întrebare.
db_unregister shared/window-manager


# Vedeți dacă întrebarea comună mai există.
if db_get shared/window-manager; then
db_metaget shared/window-manager owners
db_subst shared/window-manager choices $RET
db_metaget shared/window-manager value
if [ "<package>" = "$RET" ] ; then
db_fset shared/window-manager seen false
db_input high shared/window-manager || true
db_go || true
fi


# Acum faceți orice a făcut scriptul „postinst” pentru a actualiza
# legătura simbolică a administratorului de ferestre.
fi
fi

TRUCURI

Debconf nu este în prezent complet integrat în dpkg (dar vreau să schimb acest lucru în viitor) și, prin urmare, sunt necesare unele trucuri murdare.

Cea mai gravă dintre acestea implică rularea scriptului „config”. Modul în care funcționează acum este că scriptul „config” va fi rulat atunci când pachetul este preconfigurat. Apoi, când se execută scriptul „postinst”, se pornește din nou debconf. Debconf observă că este utilizat de scriptul „postinst”, așa că pornește și rulează scriptul „config”. Totuși, acest lucru poate funcționa numai dacă scriptul dvs. „postinst” încarcă una dintre bibliotecile debconf, astfel încât scripturile „postinst” trebuie să aibă întotdeauna grijă să facă acest lucru. Sperăm să rezolvăm această problemă mai târziu prin adăugarea unui suport explicit pentru debconf în dpkg. Programul debconf(1) este un pas în această direcție.

O problemă conexă este să faceți debconf să ruleze atunci când un script „config”, „postinst” sau alt program care îl utilizează pornește. La urma urmei, acestea se așteaptă să poată comunica imediat cu debconf. Modul în care se realizează acest lucru pentru moment este că, atunci când un astfel de script încarcă o bibliotecă debconf (cum ar fi „/usr/share/debconf/confmodule”), iar debconf nu rulează deja, acesta este pornit și o nouă copie a scriptului este re-executată. Singurul rezultat notabil este că trebuie să puneți linia care încarcă o bibliotecă debconf chiar în partea de sus a scriptului, altfel se vor întâmpla lucruri ciudate. Sperăm să rezolvăm această problemă mai târziu, schimbând modul în care debconf este invocat și transformându-l în ceva mai asemănător unui demon tranzitoriu.

Este destul de complicat modul în care debconf își dă seama ce fișiere de șabloane să încarce și când să le încarce. Atunci când scripturile „config”, „preinst” și „postinst” apelează debconf, acesta își va da seama automat unde se află fișierul de șabloane și îl va încărca. Programele autonome care utilizează debconf vor face ca debconf să caute fișiere de tip șablon în „/usr/share/debconf/templates/progname.templates”. Iar dacă un script „postrm” dorește să utilizeze debconf la momentul purjării, șabloanele nu vor fi disponibile decât dacă debconf a avut ocazia să le încarce în scriptul său „postinst”. Acest lucru este murdar, dar mai degrabă inevitabil. În viitor, unele dintre aceste programe ar putea fi capabile să utilizeze manual debconf-loadtemplate.

Comportamentul istoric al „/usr/share/debconf/confmodule” de a se juca cu descriptorii de fișiere și de a configura un fd #3 care comunică cu debconf, poate cauza tot felul de probleme atunci când un script „postinst” rulează un demon, deoarece demonul ajunge să comunice cu debconf, iar debconf nu își poate da seama când se termină scriptul. Comanda STOP poate rezolva această problemă. În viitor, ne gândim să facem ca comunicarea debconf să se realizeze prin intermediul unui soclu sau al unui alt mecanism decât intrarea/ieșirea standard.

Debconf stabilește DEBCONF_RECONFIGURE=1 înainte de a rula scripturile „postinst”, astfel încât un script „postinst” care trebuie să evite o operație costisitoare atunci când este reconfigurat se poate uita la această variabilă. Acesta este un „truc”, deoarece lucrul corect ar fi să treceți $1 = „reconfigure”, dar este dificil să faceți acest lucru fără a rupe toate scripturile „postinst” care utilizează debconf. Planul de migrare departe de acest „truc” este de a încuraja oamenii să scrie scripturi „postinst” care acceptă „reconfigure” și, odată ce toți o fac, să înceapă să treacă acest parametru.

CONSULTAȚI ȘI

debconf(7) este ghidul utilizatorului debconf.

Specificația debconf din politica debian este definiția canonică a protocolului debconf, și anume „/usr/share/doc/debian-policy/debconf_specification.txt.gz”.

debconf.conf(5) conține multe informații utile, inclusiv unele informații despre baza de date principală.

AUTOR

Joey Hess <joeyh@debian.org>

TRADUERE

Remus-Gabriel Chelu <remusgabriel.chelu@disroot.org>, 2024

Dacă găsiți o greșeală în traducere, vă rugăm să o raportați autorului acestei traduceri, pe lista de discuții <debian-l10n-romanian@lists.debian.org> sau trimițând un raport de eroare contra pachetului „debconf” către sistemul de urmărire al erorilor din Debian (BTS).