Dotfiles, część 3: GNU Stow

Od publikacji ostatniej części serii Dotfiles minęło już trochę czasu i biję się sam ze sobą czy publikować kolejną. Powód jest prozaiczny - dwa poprzednie artykuły niemal wyczerpały temat mojego sposobu na zarządzanie plikami konfiguracyjnymi. Obiecywałem jednak, że opiszę pokrótce program GNU Stow oraz skrypty, które pomagają mi w sytuacjach kryzysowych, więc obietnicy dotrzymam. W tym odcinku przyjrzymy się bliżej wyśmienitemu programowi GNU Stow, który odwala za mnie lwią część roboty.

Jak działa GNU Stow

GNU Stow jest managerem instalacji wielu programów (zwanych w nomenklaturze twórców programu “paczkami”) we wspólnych katalogach docelowych. Osiąga to poprzez tworzenie dowiązań symbolicznych do plików i katalogów położonych w innych lokacjach niż te, do których są instalowane.

Czemu miałoby to być przydatniejsze niż zwyczajowe make && make install? Żeby to lepiej zobrazować, posłużę się przykładem z manuala Stowa: gdybyśmy chcieli zainstalować Perla i Emacsa w katalogu /usr/local, musielibyśmy, między innymi, skopiować manuale obu tych programów do katalogu /usr/local/man/man1. Są to następujące pliki: a2p.1, ctags.1, emacs.1, etags.1, h2ph.1, perl.1 i s2p.1. Robi się tam śmietnik i w przypadku chęci odinstalowania lub aktualizacji np. Perla, administrator systemu musi ręcznie sprawdzić, który plik należy do Perla, a który do Emacsa.

Stow ułatwia administrację instalowanymi programami dzięki instalacji każdego z nich w jego własnym poddrzewie katalogów, które jednak powinno odzwierciedlać strukturę wspólnego katalogu docelowego (/usr/local). Na przykład wspomniany Perl i Emacs mogłyby zostać zainstalowane do katalogów /usr/local/stow/{perl,emacs}, wewnątrz których znajdowałyby się takie katalogi jak bin, man, share itd. Następnie pliki wewnątrz tych katalogów zostałyby zsymlinkowane do /usr/local/{bin,man,share}.

Wiele build systemów domyślnie tworzy poprawne poddrzewa katalogów, możliwe do użycia bez żadnych dodatkowych modyfikacji. Na przykład autotools obsługuje przełącznik --prefix oraz zmienną środowiskową $DESTDIR, które umożliwiają zainstalowanie poszczególnych fragmentów programu w katalogach $DESTDIR$PREFIX/{bin,share,share/man} (zwracam uwagę na brak separatora między zmiennymi $DESTDIR i $PREFIX związany z tym, że prefix jest ścieżką absolutną, domyślnie ustawioną na /usr).

Dokumentacja Stowa sugeruje utworzenie jednego katalogu-repozytorium. Jest to o tyle wygodne, że wystarczy wejść do danego katalogu i wywołać komendę stow <package>, żeby zainstalować daną paczkę w katalogu o poziom wyżej (czyli wewnątrz rodzica bieżącego katalogu). Ta akcja, oprócz tego, że stworzy symlinki dla żądanej paczki, dodatkowo sprawdzi czy inne pliki w modyfikowanych katalogach są zarządzane przez GNU Stow i odpowiednio je zmodyfikuje, jeśli będzie taka potrzeba (GNU Stow stara się tworzyć jak najmniejszą liczbę dowiązań symbolicznych).

Wszystkie akcje Stowa są przy tym domyślnie bezpieczne: program nie dotknie plików, które nie są przez niego zarządzane (czyli zwykłych plików oraz linków symbolicznych wskazujących gdzieś poza repozytorium Stowa).

Aby usunąć daną paczkę (czyli usunąć jej dowiązania symboliczne), należy użyć opcji -D: stow -D <package>. Przeinstalowanie paczki wiąże się natomiast z użyciem opcji -R: stow -R <package>. Proste jak drut.

Wykorzystanie Stowa

Moje repozytorium dotfile’ów jest w dużej mierze repozytorium paczek Stowa, które symlinkuję do katalogu domowego $HOME.

Mój plik config.ini (dla programu config-manage opisanego w poprzednich częściach) posiada następującą sekcję domyślną:

[DEFAULT]
stow_install = stow -R ${targetname} -t ${var:home}
stow_uninstall = stow -D ${targetname} -t ${var:home}

install_cmd = ${stow_install}
uninstall_cmd = ${stow_uninstall}

Dzięki temu nie muszę w ogóle tworzyć sekcji w pliku konfiguracyjnym dla prostych modułów, które muszą zaledwie zsymlinkować kilka plików - dla wszystkich innych modułów mogę natomiast użyć komend zapisanych pod zmiennymi ${stow_install} i ${stow_uninstall}, które automatycznie będą znały nazwę stow-owanych paczek.

W następnej części

W następnej części (lub częściach) opiszę skrypty pomocnicze dostarczane razem z frameworkiem konfiguracyjnym. Opiszę również sposób, w jaki konfiguracje są dzielone między różnymi komputerami i jak to wszystko jest razem połączone.

Ciąg dalszy nastąpi…