Управление программными пакетами при помощи Stow

Автор: (C) Allan Peda ([email protected])
Перевод: (C) Александр Куприн

Когда на компьютере установлены надёжные и правильно настроенные программы, контроль за их версиями может быть простым и не требовать много времени. Не играет особой роли, какой именно дистрибутив вы используете: Red Hat, Debian или Sun (да-да, именно Sun, т.к. в этой статье я хочу заодно коснуться темы не-Linux дистрибутивов). Но что делать, если вы не смогли найти или создать требуемый пакет? Или представьте ситуацию: ваш компьютер работает как часы вот уже несколько лет и все, что вам нужно -- Emacs последней версии? Что, если вы разрабатываете собственное программное обеспечение и не хотите заново создавать RPM'ы или пакеты dpkg для каждой новой версии? А может, вы не доверяете пакетам четырнадцатилетней давности из далёкой и затерянной страны, где правительство менялось чуть ли не каждую неделю? А что если вы придерживаетесь совета Obi-Wan Kenobe и используете только исходники? (имеется в виду знаменитая в *nix-мире перефразировка. В Звездных Войнах Оби-Ван советовал Люку использовать силу "use the force, Luke". В unix-кругах советуют при затруднениях использовать исходники: "use the source, Luke". Речь идет об этой популярной в хакерских кругах рифме. -- прим. ред.:) Как не запутаться в этом хороводе конфигурационных файлов, справочных руководств, бинарников и библиотек, когда подойдёт время их менять?

Если вы немного подумаете, то поймете, что Unix уже содержит решение этой проблемы. Оно называется символической ссылкой или симлинком. Символические ссылки -- мощный инструмент, позволяющий вам конфигурировать программное обеспечение так, что отпадает необходимость в непосредственной связи между реализацией и интерфейсом (звучит знакомо?). Я позволил себе небольшую вольность в терминологии, но чтобы вам стало понятно о чём же это я говорю, вспомните, например, имитацию postfix'ом функций sendmail'а, являющегося de facto стандартом интерфейса к почтовому транспортному агенту Unix ( MTA).

Используя символические ссылки, вы могли бы "связать" программу /opt/bin/new_cat с /opt/bin/cat. При этом достаточно одного взгляда, чтобы понять какая именно программа запущена под видом cat, но для "заинтересованных сторон" будет казаться, что это все та же знакомая программа. Так мы получаем возможность заменить реально существующее приложение на другое, использующее более эффективный код.1 Да, конечно, переменные среды (и алиасы), используемые в скриптах, позволяют сделать тоже самое, но попробуйте перенастроить все необходимые переменные окружения после того, как программа установлена. Символические ссылки -- вот решение проблемы. К примеру, они используются утилитой lndir для упрощения сборки из исходников пакета motif. Конечно, не следует слишком злоупотреблять механизмом символических ссылок, иначе вы можете запутаться и потерять над ними контроль. Но всё-таки это хорошая идея. И ею воспользовались парни из проекта GNU и написали небольшой скрипт на Perl, который полностью автоматизирует процесс. Следует заметить, что жёсткие ссылки отличаются от символических тем, что не имеют различий между оригинальным файлом и ссылкой на него (это связано с тем, что жёсткие ссылки, как и имя файла, указывают на индексный дескриптор файловой системы, поэтому они идентичны).2 Я пришёл к выводу о необходимости минимизировать использование жёстких ссылок, т.к. легко запутаться какое из имён файла должно быть удалено, а какое оставлено.

Введение в Stow

Сразу же хочу подчеркнуть, что stow не является полноценной заменой менеджерам пакетов, но позволяет воспользоваться многими удобствами, предоставляемыми системой комплексного управления пакетами, и всё это благодаря небольшому скрипту на perl'е. Среди программ этого типа особняком стоит пакет checkinstall, который позволяет включать информацию о программах, собранных из "тарболов" с исходным кодом в базы данных пакетов RPM, Debian или Slackware. В качестве примера я покажу вам, как шаг за шагом установить stow и как его использовать при инсталляции почтовой программы ( MUA) nail. Пример хорош тем, что nail включает в себя множество файлов, так что прекрасно видно, как можно столкнуться с непреднамеренными коллизиями файлов из разных версий. К тому же, nail является прекрасным расширением стандартной программы Berkeley mail, позволяя отправлять вложения с двоичными файлами через командную строку и в тоже время предоставляя базовые функциональные возможности.

Stow настолько прост в установке, что это не требует развёрнутой и углублённой дискуссии. Он будет работать, если у вас установлен Perl 5.005 или более поздней версии (эта версия является основной для Solaris 8 AFAIK). Возьмите исходники на web-сайте проекта GNU или с локальных зеркал, распакуйте (tar xzf) и выполните "отче наш" для компиляции из "сырцов": ./configure, make и make install (последняя команда с правами root'а). Не смотря на то, что при выполнении команды make ничего не компилируется (о чём она и сообщает), она нужна для сборки страниц справочного руководства. Команда make install размещает stow в подкаталоге /usr/local/bin. Это каталог, где по умолчанию размещаются пакеты собранные из "тарболов". Я оставил его как есть, чтобы не усложнять дискуссию. Причины, по которым я поступил именно так, станут понятны в конце статьи. Каталог, где будет располагаться скрипт stow дан ниже в последней строке дампа стандартного выхода. Для того, чтобы выяснить, где же всё-таки находится stow, я использую команду type, но вы можете воспользоваться which или whereis

Распаковка и установка stow
[zippy@mybox zippy]$ cd src/
[zippy@mybox src]$ gunzip -c ./stow-1.3.3.tar.gz | tar xf -
[zippy@mybox src]$ ll
total 8
drwxrwxr-x 2 zippy zippy 4096 Jan 6 06:19 stow-1.3.3
[zippy@mybox stow-1.3.3]$ ./configure
creating cache ./config.cache
checking for a BSD compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for mawk... no
checking for gawk... gawk
checking whether make sets ${MAKE}... yes
checking for a BSD compatible install... /usr/bin/install -c
checking for perl... /usr/bin/perl
updating cache ./config.cache
creating ./config.status
creating Makefile
creating stow
[zippy@mybox stow-1.3.3]$ make
make: Nothing to be done for all'.
[zippy@mybox stow-1.3.3]$ sudo make install
make[1]: Entering directory /home/zippy/src/stow-1.3.3'
/bin/sh ./mkinstalldirs /usr/local/bin
/usr/bin/install -c stow /usr/local/bin/stow
/bin/sh ./mkinstalldirs /usr/local/info
/usr/bin/install -c -m 644 ./stow.info /usr/local/info/stow.info
/bin/sh ./mkinstalldirs /usr/local/man/man8
/usr/bin/install -c -m 644 ./stow.8 /usr/local/man/man8/stow.8
make[1]: Leaving directory /home/zippy/src/stow-1.3.3'
[zippy@mybox stow-1.3.3]$ type stow
stow is /usr/local/bin/stow

Теперь stow установлен в /usr/local/bin. Убедитесь, что на этот каталог есть указание в переменной $PATH

Что там под капотом или как всё это работает

Прежде чем приступить к описанию возможностей stow, необходимо понимание принципов работы скрипта configure, потому что эти два скрипта работают вместе. Скрипт configure отвечает за предварительную настройку всех программных компонент и установку их на вашей машине. Он удивительно гибок и удобен. "Вынюхивая" по всем закоулкам системы, он собирает информацию о предустановленном программном обеспечении, которое понадобиться на этапе компиляции и для дальнейшего использования приложения. Результаты этих изысканий используются для формирования Makefile, который создаёт и устанавливает программное обеспечение таким образом, чтобы оно соответствовало вашей системе. Существует множество опций предварительного конфигурирования, также существует несколько версий скрипта configure, но одна опция представляет для нас особый интерес: --prefix. Обращаю ваше внимание на то, что существует ещё один ключ, который позволяет производить настройку более тонко: --exec-prefix, но эта опция не будет здесь детально обсуждаться.

Теперь мы понимаем, что configure создаёт скрипты, в свою очередь строящие код, и что пути, где этот код будет размещён задается при помощи опции --prefix. Если вы выберите для установки отдельный каталог (отличающийся от /usr/local), то stow сможет автоматизировать создание символических ссылок к инсталлированному коду, так что собственно дерево файлов и каталогов, составляющих программный пакет, можно будет легко заменить или удалить. Например, такой вызов конфигурационного скрипта ./configure --prefix=/opt/stow/foo-1.2.1 заставит установить пакет foo-1.2.1 в каталог /opt/stow/foo-1.2.1.

Я всё ещё в недоумении. Что это за "зверь" такой exec-prefix?

Не стоит комплексовать по поводу того, что этот раздел будет вам непонятен. Пропустите его при первом чтении и вернитесь к нему позже, когда "переварите" оставшуюся часть статьи. Если же вы чувствуете себя комфортно с такими понятиями как фактическое расположение программы в противоположность ее кажущемуся расположению, то вы можете приступить к рассмотрению той части головоломки, которая не подходит под этот идеальный сценарий. Представьте себе вариант, когда программное обеспечение установлено на нескольких машинах, и всё оно расположено в "залинкованном" дереве каталогов, изолированном от "кажущегося" местоположения (на которое, как обычно, указывают переменные $PATH и $MANPATH. В зависимости от ваших намерений, это может быть не совсем то, что нужно. Рассмотрим ситуацию, когда приложение может быть собрано для систем Solaris и Linux вот таким способом (допуская существование идентичных, "перекрестно-смонтированных" по сети деревьев файловой системы, но раздельных "сборочных деревьев" [build directories]:

sun$ cd sunsparc
sun$ ./foolib-1.1/configure --prefix=/usr/local \
> --exec-prefix=/usr/local/sunsparc
sun$ make
sun$ make install

После этого в другом окне терминала:

sun$ ssh pengie
pengie$ cd linux
pengie$ ./foolib-1.1/configure --prefix=/usr/local \
> --exec-prefix=/usr/local/linux
pengie$ make
pengie$ make install

В конечном счете, разработчик должен решить сам -- являются эти файлы архитектуро-независимыми, или нет. Вы можете с этим не соглашаться. Очевидно, что документация и, возможно, конфигурационные файлы могут не зависеть от архитектуры. Однако, если вы используете stow, вы можете удалить символические ссылки, выполнив "unstowing". Поскольку обновление не будет записано поверх старого кода, а только "побьет" ссылки, вы можете вручную скопировать конфигурационные файлы назад. Просто "перегрузите" ("restow") пакет при помощи stow и попробуйте снова сделать обновление. Лично я, почти не использую опцию --exec-prefix, предпочитая вместо этого настраивать вручную те файлы конфигурации, с которыми хочу обращаться по-особенному, исправляя потерянные связи после обновления. Думаю, это более приемлемый подход для простых ситуаций, с которыми мне приходилось сталкиваться.

Установка приложений при помощи Stow

Когда несколько лет назад я впервые использовал stow, я испытал некоторое разочарование. Я уже начал настраивать систему (сервер HP-UX) без этой утилиты. Встречались частые коллизии между info-файлами и man-страницами, по иронии судьбы большая часть из них приходилась на emacs. Естественно, то, что изложено ниже, проще сделать для небольших пакетов. Структура приложения nail не слишком сложна, но в тоже время содержит в себе исполняемый файл, файлы документации и конфигурационные файлы (так что вы могли бы связать их с /etc).

Конфигурирование для альтернативного размещения пакета
[zippy@mybox src]$ gunzip -c ./nail-9.29.tar.gz  | tar xf -
[zippy@mybox src]$ cd nail-9.29/
[zippy@mybox nail-9.29]$ ./configure --prefix=/opt/stow/nail-9.29
creating cache ./config.cache
checking for a BSD compatible install... /usr/bin/install -c
checking for iswprint... yes
...
..... lots of stuff ...
updating cache ./config.cache
creating ./config.status
creating Makefile
creating config.h
[zippy@mybox nail-9.29]$

Здесь мы говорим скрипту configure размещать файлы в /opt/stow/nail-9.29, но подразумевается (поскольку речь идет о stow) что будет "казаться", что пакеты находятся в /opt. (Если вам любопытно, то можете просмотреть сгенерированный Makefile и увидеть, что значение переменной prefix было изменено при помощи опции --prefix).

Компиляция
[zippy@mybox nail-9.29]$
[zippy@mybox nail-9.29]$ make
gcc -DHAVE_CONFIG_H -I. -I. -I. -g -O2 -c version.c
gcc -DHAVE_CONFIG_H -I. -I. -I. -g -O2 -c aux.c
... more stuff ...
gcc -DHAVE_CONFIG_H -I. -I. -I. -g -O2 -c tty.c
gcc -DHAVE_CONFIG_H -I. -I. -I. -g -O2 -c vars.c
gcc -g -O2 -o nail version.o aux.o base64.o cmd1.o cmd2.o \
cmd3.o cmdtab.o collect.o dotlock.o edit.o fio.o getname.o \
head.o v7.local.o lex.o list.o main.o mime.o names.o popen.o \
quit.o send.o sendout.o smtp.o strings.o temp.o tty.o vars.o
[zippy@mybox nail-9.29]$

Теперь у нас всё откомпилировано и мы можем приступить к установке.

Инсталляция
[zippy@mybox nail-9.29]$ sudo make install
make[1]: Entering directory /home/zippy/src/nail-9.29'
/bin/sh ./mkinstalldirs /opt/stow/nail-9.29/bin
mkdir /opt/stow
mkdir /opt/stow/nail-9.29
mkdir /opt/stow/nail-9.29/bin
/usr/bin/install -c nail /opt/stow/nail-9.29/bin/nail
/bin/sh ./mkinstalldirs /opt/stow/nail-9.29/man/man1
mkdir /opt/stow/nail-9.29/man
mkdir /opt/stow/nail-9.29/man/man1
/usr/bin/install -c -m 644 ./nail.1 /opt/stow/nail-9.29/man/man1/nail.1
test -f /etc/nail.rc || \
{ /bin/sh ./mkinstalldirs /etc; \
/usr/bin/install -c -m 644 ./nail.rc /etc/nail.rc; }
make[1]: Leaving directory /home/zippy/src/nail-9.29'
[zippy@mybox nail-9.29]$

Итак, как видно из предыдущего листинга, файлы пакета были размещены в каталоге /opt/stow/nail-9.29, что нам и было нужно. Stow предполагает, что все подкаталоги пакета расположены относительно --prefix (или ${prefix}, если вы посмотрите в Makefile), поэтому при формировании символических ссылок мы получаем дерево ссылок, в котором /opt/stow/nail-9.29/bin становится /opt/bin, /opt/stow/nail-9.29/man/man1 становится /opt/man/man1 и т.д. Такие соглашения делают очень простой изоляцию файлов, используемых из установочных каталогов. Осталось сделать всего один шаг для того, чтобы создать символические ссылки, используя stow.

"Погрузка"3 двоичных файлов
[zippy@mybox nail-9.29]$ cd /opt/stow/
[zippy@mybox stow]$ sudo stow -vv nail-9.29/
Stowing package nail-9.29...
Stowing contents of nail-9.29
Stowing directory nail-9.29/bin
LINK /opt/bin to stow/nail-9.29/bin
Stowing directory nail-9.29/man
LINK /opt/man to stow/nail-9.29/man
[zippy@mybox stow]$ ls -ltr /opt/
[zippy@mybox stow]$ ls -ltr /opt
total 4
drwxr-xr-x 3 root root 4096 Jan 9 16:33 stow
lrwxrwxrwx 1 root root 18 Jan 9 16:33 man -> stow/nail-9.29/man
lrwxrwxrwx 1 root root 18 Jan 9 16:33 bin -> stow/nail-9.29/bin
stow/nail-9.29/bin
[zippy@mybox stow]$ PATH=/opt/bin:$PATH type nail
nail is /opt/bin/nail

Позвольте объяснить, что здесь к чему: я перешёл в каталог stow (по умолчанию ${prefix}/stow) и ввёл команду stow -vv плюс имя поддиректории для рекурсивной ссылки. Ключ -vv заставляет stow показывать в стандартном выходе максимально возможный объём информации в процессе создания и настройки дерева символических ссылок. Теперь всё что нужно, это добавить к переменной $PATH значения подкаталогов (вернее символических ссылок на них), в которых расположен исполняемый файл пакета nail ($PATH=/opt/bin:$PATH). Всё готово к использованию -- stow создал ссылки, вы добавили в переменную $PATH указание на них. Обратите внимание на то, что для того чтобы деинсталлировать файлы, вам достаточно удалить ссылки (или воспользоваться аналогичной функцией в stow, см. ниже). При этом ни один из файлов не будет удалён, что очень удобно и безопасно.

"Разгрузка" каталога
[zippy@mybox stow]$ pwd
/opt/stow
[zippy@mybox stow]$ ls -l
total 4
drwxr-xr-x 4 root root 4096 Jan 9 16:33 nail-9.29
[zippy@mybox stow]$ sudo stow -Dvv nail-9.29/
Unstowing in /opt
UNLINK /opt/bin
UNLINK /opt/man
[zippy@mybox stow]$


И все установленные файлы "отложим" аккуратно в сторону. Конечно, чтобы повторно "загрузить" файлы, вам понадобится лишь повторить описанные ранее команды. Возможно, с непривычки при использовании stow может возникнуть ощущение дискомфорта, но как только вы "распробуете" его возможности, то поймёте, что дело того стоит. Несомненно, вы могли бы установить nail сами и использовать его посредством алиасов или функций оболочки, как замену пакета mail. Но процесс настройки тянет сам по себе на отдельную статью.

Вот и всё. Удачно хака!

Ссылки

  1. GNU stow
    Размещено Guillaume Morin
    http://www.gnu.org/software/stow/stow.html
    Страница GNU stow на Savannah
    http://savannah.gnu.org/projects/stow
  2. Checkinstall
    автор Itzo http://freshmeat.net/projects/checkinstall/
  3. Nail, замена для MUA mail
    автор Gunnar Ritter http://omnibus.ruf.uni-freiburg.de/~gritter/
  4. Linux Filesystem Hierarchy Standard, (FHS)
    Размещено freestandards.org http://www.pathname.com/fhs/
  5. GNU Autoconf, Automake, и libtool
    авторы: Gary V. Vaughan, Ben Elliston, Tom Tromey, и Ian Lance Taylor
    предлагает великолепный обзор концепций использования опций exec-prefix в скрипте configure
    http://sources.redhat.com/autobook/ ISBN 1-57870-190-2

Примечания переводчика


1 И что очень удобно (и элегантно), сам факт подмены остаётся "за кадром", т.е. как вы использовали программу cat, так вы её и продолжаете использовать, всё остальное вас, как пользователя, интересовать не должно.
2 Это накладывает ограничения на жёсткие ссылки -- они могут быть использованы только в пределах данной файловой системы. Кроме этого, если вы удалите оригинальный файл, на который ссылалась жёсткая ссылка, то физически файл удалён не будет, т.к. на него ссылается жёсткая ссылка. И только после того как будет удалена последняя ссылка, индексный дескриптор, закреплённый за этим файлом будет освобождён и дисковое пространство занимаемое этим файлом тоже. Если же вы удалите оригинальный файл, на который ссылалась символическая ссылка, то файл будет удалён, но ссылка на него останется.
3 "Погрузка" -- производная от слова "stowing".

Allan Peda

Allan имеет счастье пользоваться Linux примерно с 1995 года, чуть позже он открыл для себя Perl. Сейчас он работает экспертом-консультантом по Linux в Нью-Йорке. Ему нравится серфинг и плавание на парусных судах. Временами он мечтает о том, как однажды приобретет свою собственную яхту и будет на ней плавать в тихих водах Коста Рики.


Copyright 2002, Allan Peda.
Copying license http://www.linuxgazette.com/copying.html
Published in Issue 75 of Linux Gazette, February 2002

Команда переводчиков:
Владимир Меренков, Александр Михайлов, Иван Песин, Сергей Скороходов, Александр Саввин, Роман Шумихин, Александр Куприн, Андрей Киселев

Со всеми предложениями, идеями и комментариями обращайтесь к Сергею Скороходову ([email protected]). Убедительная просьба: указывайте сразу, не возражаете ли Вы против публикации Ваших отзывов в рассылке.

Сайт рассылки: http://gazette.linux.ru.net
Эту статью можно взять здесь: http://gazette.linux.ru.net/lg75/articles/rus-peda.html