Format źródeł 3.0 (git) przy budowaniu paczek Debiana

Spis treści

Pisząc jakiś czas temu poradnik na temat budowania paczek .deb dla dystrybucji linux'a Debian, poruszyłem w nim kwestię związaną z aktualizacją paczki, która zawierała projekt utrzymywany w systemie kontroli wersji (CVS), np. git. Rozchodzi się tutaj o format źródeł. Do niedawna myślałem, że są w zasadzie dwa formaty (tych, z których się zwykle korzysta): 3.0 (native) oraz 3.0 (quilt) . Wszystkie moje pakiety budowane do tej pory miały ten drugi format. Podglądając ostatnio kilka paczek .deb , natrafiłem w jednej z nich na format źródeł 3.0 (git) . Okazuje się, że ten format jest w stanie bardzo łatwo ogarnąć projekty hostowane w takich serwisach jak GitHub, czy GitLab i można za jego sprawą nieco ułatwić sobie życie. Wypadałoby zatem rzucić na niego okiem i ocenić go pod kątem przydatności przy budowaniu pakietów dla Debiana.

Formaty źródeł native, quilt i git

Po zajrzeniu do manuala dpkg-source , można odnaleźć z nim dział SOURCE PACKAGE FORMATS . Jest tam opisanych szereg formatów źródeł, które mechanizm budowy pakietów Debiana jest w stanie obsłużyć. Jest też tam informacja, że jeśli format źródeł budowanego projektu jest nieznany, to powinno się skorzystać z 3.0 (native) lub 3.0 (quilt) . Czym się różnią te dwa formaty od siebie? W zasadzie to łatkami, które w przypadku tego drugiego formatu są nakładane na źródła po ich wypakowaniu, a całym tym przedsięwzięciem kieruje quilt . Gdy w grę wchodzi teraz repozytorium git, to wszelkie zmiany w nim są rejestrowane przez CVS i zamiast nakładania patch'a na źródła, to tworzy się zwykły commit podebrany ze zdalnej gałęzi/repo, przez co odpada nam bawienie się w ręczne nakładanie łat -- wystarczy zsynchronizować repozytorium, by pobrać wszystkie nowe zmiany i można budować nowszą wersję aplikacji.

Przygotowanie źródeł

Przygotowanie źródeł do budowy pakietu .deb w przypadku formatu 3.0 (git) nie różni się zbytnio w stosunku do formatu 3.0 (quilt) czy 3.0 (native) . Dlatego też wypadałoby się pierw zaznajomić z podlinkowanym we wstępie artykułem, bo w nim są zawarte wszystkie niezbędne informacje na temat tego jak zdebianizować źródła, by nadawały się pod mechanizm budowy pakietów Debiana.

Problemy związane z formatem źródeł git

Jako, że format źródeł 3.0 (git) odnosi się do budowania paczki z repozytorium git, to nie może ono podlegać jakimkolwiek zmianom z naszej strony. Chodzi generalnie o to, że nawet poprawienie najdrobniejszej literówki skutkować będzie tym, że VCS będzie widział zmianę (w końcu od tego jest ten system). Niemniej jednak, mając zmiany w lokalnym repozytorium, dpkg-source nie będzie chciał zezwolić na budowę takiego pakietu i zwróci nam poniższy błąd:

$ debuild -S -sa -d -i
...
dpkg-source: info: using source format '3.0 (git)'
dpkg-source: error: uncommitted, not-ignored changes in working directory:
...
dpkg-buildpackage: error: dpkg-source -i -b . subprocess returned exit status 255
debuild: fatal error at line 1182:
dpkg-buildpackage -us -uc -ui -S -sa -d -i failed

Jeśli źródła są odpowiednio przygotowane przez upstream, to wszystkie zbędne pliki powinny zostać uwzględnione w .gitignore .

Kolejny problem dotyczy katalogu debian/ . Jeśli upstream go nie stworzył i nie utrzymuje, to w zasadzie jest pozamiatane, bo stworzenie takiego katalogu będzie widziane jako zewnętrzna zmiana w źródłach. Co prawda, można by stworzyć stworzyć plik .gitignore wewnątrz katalogu debian/ i umieścić w nim * , przez co CVS przestanie widzieć zmiany w tym katalogu, jak i sam katalog. Niemniej jednak, gdybyśmy chcieli zbudować taki pakiet przy pomocy pbuilder , to on nam z kolei zwróci taki błąd:

$ sudo pbuilder --build nftables_0.9.0-3\~git20190312.1.dsc
...
I: Extracting source
...
dpkg-source: info: extracting nftables in nftables-0.9.0
dpkg-source: info: cloning nftables_0.9.0-3~git20190312.1.git
warning: unable to access '/root/.config/git/attributes': Permission denied
dpkg-source: error: cannot write nftables-0.9.0/debian/source/format: No such file or directory
E: pbuilder: Failed extracting the source
...

Ten błąd uniemożliwia dalszy proces budowy pakietu. W zasadzie to się on nawet nie zdążył rozpocząć. Wszystko przez ten zignorowany katalog debian/ , którego teraz nie ma wewnątrz środowiska chroot.

Oczywiście te powyższe problemy znikną jak tylko zostaną stworzone lokalne commit'y ale one z kolei sprawią, że nasze zmiany (jeśli ich nie pchniemy do upstream'u) będą tracone za każdym jak będziemy chcieli zsynchronizować zdalne repozytorium (albo będziemy musieli się bawić w merge). Podobnie sprawa wygląda z nakładaniem zewnętrznych łat. Tego też nie damy rady zrobić bez ingerencji w historię zmian VCS.

Widać już zatem, że ten format źródeł 3.0 (git) nie jest taki miły jakby się mogło na pierwszy rzut oka wydawać. No chyba, że źródła zostaną odpowiednio przygotowane w upstream'ie. Tak czy inaczej niektóre repozytoria mają już przygotowane odpowiednie drzewo katalogów, np. hw-probe. Postanowiłem zatem na jego przykładzie sprawdzić jak się operuje na tym eksperymentalnym formacie źródeł 3.0 (git) .

Gdy pojawiają się nowe commit'y w repo git

Deweloperzy rozwijając dany projekt niekoniecznie chcą co każdy kolejny commit wypuszczać nową wersję programu. Sporo problemów i/lub błędów jest naprawianych chwilę po ich zgłoszeniu, co owocuje kolejnymi commit'ami. Gdy tych commit'ów zbierze się jakaś większa ilość (lub będą łatać krytyczne dziury), to wtedy dopiero autor projektu decyduje się na wydanie nowej wersji appki.

Przez cały ten czas od jednego wydania do drugiego korzystamy ze starszej wersji programu do momentu, aż zostanie wypuszczony nowy release, mimo, że pewne zmiany w projekcie już się dokonały. Jeśli nie chce nam się czekać na moment wypuszczenia kolejnego release, to możemy zsynchronizować sobie repozytorium git i z tego świeżego snapshot'a źródeł aplikacji zbudować pakiet .deb . Pamiętajmy przy tym, że tak zbudowana aplikacja może być bardzo niestabilna -- w końcu deweloper nie odważył się wypuścić stabilnego release, więc można przypuszczać, że appka nie jest jeszcze gotowa. Jeśli jednak ten fakt nas nie odstrasza, to trzeba pobrać repozytorium projektu, z którego zamierzamy zbudować paczkę .deb :

$ git clone https://github.com/linuxhw/hw-probe/

Możemy teraz zbudować źródła przy pomocy debuild -S -sa -d -i :

$ debuild -S -sa -d -i
 dpkg-buildpackage -us -uc -ui -S -sa -d -i
dpkg-buildpackage: info: source package hw-probe
dpkg-buildpackage: info: source version 1.4-6-git20190103
dpkg-buildpackage: info: source distribution unstable
dpkg-buildpackage: info: source changed by Mikhail Novosyolov <mikhailnov@dumalogiya.ru>
 dpkg-source -i --before-build .
 fakeroot debian/rules clean
dh clean
   dh_auto_clean
        make -j1 clean
make[1]: Entering directory '/media/Kabi/debian_sources/git-hw-probe/hw-probe'
echo "Nothing to clean up."
Nothing to clean up.
make[1]: Leaving directory '/media/Kabi/debian_sources/git-hw-probe/hw-probe'
   dh_clean
 dpkg-source -i -b .
dpkg-source: info: using source format '3.0 (git)'
dpkg-source: info: bundling: --all
dpkg-source: info: building hw-probe in hw-probe_1.4-6-git20190103.dsc
 dpkg-genbuildinfo --build=source
 dpkg-genchanges -sa --build=source >../hw-probe_1.4-6-git20190103_source.changes
dpkg-genchanges: info: including full source code in upload
 dpkg-source -i --after-build .
dpkg-buildpackage: info: source-only upload: Debian-native package
Now running lintian hw-probe_1.4-6-git20190103_source.changes ...
N: Using profile debian/main.
N: Starting on group hw-probe/1.4-6-git20190103
N: Unpacking packages in group hw-probe/1.4-6-git20190103
...
N: ----
N: Processing changes file hw-probe (version 1.4-6-git20190103, arch source) ...
N: ----
N: Processing buildinfo package hw-probe (version 1.4-6-git20190103, arch source) ...
N: Finished processing group hw-probe/1.4-6-git20190103
Finished running lintian.
Now signing changes and any dsc files...
...

Successfully signed dsc, buildinfo, changes files

Przy budowaniu źródeł w formacie 3.0 (git) wyrzucany jest błąd internal error: could not find the source tarball (bo nie mamy oryginalnej paczki .tar ze źródłami), a przez to lintian nie jest w stanie poddać źródeł analizie warning: skipping check of source package hw-probe . Te błędy jednak nie wpływają na sam proces budowania pakietu .deb ale mogą się odbić na jego jakości przez niespełnienie pewnych wytycznych narzuconych przez Debiana.

Mając zbudowane źródła, możemy zbudować paczkę:

$ cd ..
$ sudo pbuilder --build hw-probe_1.4-6-git20190103.dsc

W procesie budowania paczki .deb , pbuilder wyrzucił również ostrzeżenie warning: unable to access '/root/.config/git/attributes': Permission denied ale nie ma się co nim przejmować. Paczka powinna się zbudować po dłuższej chwili.

Synchronizacja repozytorium git

Być może za jakiś czas zostaną dodane nowe commit'y do repozytorium hw-probe i będziemy chcieli zbudować nowszą jego wersję. W takiej sytuacji wystarczy przejść do katalogu, gdzie mamy repozytorium tego projektu i wydać to poniższe polecenie:

$ git remote update && git status
Fetching origin
On branch master
Your branch is behind 'origin/master' by 3 commits, and can be fast-forwarded.
  (use "git pull" to update your local branch)

nothing to commit, working tree clean

Nasze lokalne repozytorium jest 3 commit'y z tyłu w stosunku do upstream'u. Wypadałoby zatem się zsynchronizować:

$ git pull
Updating cba9de1..6352a26
Fast-forward
 README.md   |  11 ++++++
 hw-probe.pl | 234 +++++++++++++++++++++++++++++++++--------------------
 2 files changed, 168 insertions(+), 77 deletions(-)

I już można budować pakiet .deb sposobem opisanym wyżej. Niemniej jednak, trzeba w tym miejscu zaznaczyć, że jeśli upstream nie podbije wersji z 1.4-6-git20190103 , to paczka będzie co prawda zawierała wszystkie zmiany wprowadzone w nowych commit'ach ale zastąpi nam te wcześniej zbudowaną. Ma to spore znaczenie, gdy w grę wchodzi wrzucanie takiego pakietu do repozytorium pakietów, np. gdy mamy lokalnie wdrożone reprepro.

Podsumowanie

Mnie jakoś specjalnie ten format źródeł 3.0 (git) nie przekonuje. W zasadzie upstream bardzo rzadko dostosowuje źródła pod kątem wytycznych konkretnej dystrybucji, a nawet jeżeli się to już zdarzy, to i tak zwykle nie dba się o to, by te pliki były aktualne.

Z kolei problematyczność lokalnego poprawiania błędów przez nakładanie łatek, tak jak to można robić w przypadku formatu 3.0 (quilt) , sprawia, że ja jednak będę korzystał z tego rozwiązania co do tej pory, tj.

$ git clone git://git.app.org/app
$ tar --exclude='.git*' --exclude='.pc' -cf - app | xz -9 -c - > app_1.2.3~git20190312.orig.tar.xz

I mamy można się bawić.

Mikhail Morfikov avatar
Mikhail Morfikov
Po ponad 10 latach spędzonych z różnej maści linux'ami (Debian/Ubuntu, OpenWRT, Android) mogę śmiało powiedzieć, że nie ma rzeczy niemożliwych i problemów, których nie da się rozwiązać. Jedną umiejętność, którą ludzki umysł musi posiąść, by wybrnąć nawet z tej najbardziej nieprzyjemniej sytuacji, to zdolność logicznego rozumowania.