Глава 8. Продвинутые практики pkg-plist

Этот перевод может быть устаревшим. Для того, чтобы помочь с переводом, пожалуйста, обратитесь к Сервер переводов FreeBSD.

8.1. Изменение содержимого pkg-plist в зависимости от make-переменных

Некоторые порты, в частности, порты p5-, должны менять содержимое своих файлов pkg-plist в зависимости от того, с какими параметрами они были отконфигурированы (или в зависимости от версии языка perl в случае портов p5-). Чтобы облегчить этот процесс, любые вхождения ключевых слов %%OSREL%%, %%PERL_VER%% и %%PERL_VERSION%% в файле pkg-plist будут заменяться соответствующими значениями. Значением %%OSREL%% является номер версии операционной системы (например, 4.9). %%PERL_VERSION%% и %%PERL_VER%% обозначают полный номер версии perl (например, 5.8.9). Некоторые другие %%VARS%%, имеющие отношение к файлам документации порта, описаны в соответствующем разделе.

Если вам нужно сделать другие подстановки, вы можете указать в переменной PLIST_SUB список пар VAR=VALUE, и все вхождения %%VAR%% в файле pkg-plist будут заменяться на значение VALUE.

Например, если порт устанавливает множество файлов в подкаталоге, зависящем от версии, используйте заполнитель для версии, чтобы файл pkg-plist не требовал перегенерации при каждом обновлении порта. Например, укажите:

OCTAVE_VERSION=	${PORTREVISION}
PLIST_SUB=	OCTAVE_VERSION=${OCTAVE_VERSION}

в файле Makefile и использовать %%OCTAVE_VERSION%% везде, где нужно указать номер версии в файле pkg-plist. Таким образом, при обновлении порта вам не нужно будет менять десятки (а в некоторых случаях и сотни) строк в файле pkg-plist.

Если файлы устанавливаются по условию в зависимости от опций, установленных в порте, обычный способ обработки — это добавление префикса %%OPT%% для строк в pkg-plist, которые нужны при включении опции, или %%NO_OPT%%, когда опция отключена, а также добавление OPTIONS_SUB=yes в Makefile. Подробнее см. OPTIONS_SUB.

Например, если есть файлы, которые устанавливаются только при включении опции X11, и в Makefile указано:

OPTIONS_DEFINE=	X11
OPTIONS_SUB=	yes

В pkg-plist укажите %%X11%% перед строками, которые устанавливаются только при включении опции, например:

%%X11%%bin/foo-gui

Эта подстановка будет сделана между выполнением целей pre-install и do-install, посредством чтения файла PLIST и записью в файл TMPPLIST (по умолчанию это файл WRKDIR/.PLIST.mktmp). Так что если ваш порт строит PLIST на лету, делайте это во время или до выполнения цели pre-install. Кроме того, если вашему порту требуется отредактировать получающийся файл, делайте это в цели post-install изменением файла TMPPLIST.

Ещё один способ изменения списка упаковки порта основан на установке переменных PLIST_FILES и PLIST_DIRS. Значение каждой переменной рассматривается как список путей для записи в TMPPLIST вместе с содержимым PLIST. Хотя имена, перечисленные в PLIST_FILES и PLIST_DIRS, подлежат замене %%VAR%%, как описано выше, лучше использовать ${VAR} напрямую. За исключением этого, имена из PLIST_FILES появятся в итоговом списке упаковки без изменений, тогда как к именам из PLIST_DIRS будет добавлен префикс @dir. Чтобы вступить в силу, PLIST_FILES и PLIST_DIRS должны быть установлены до записи TMPPLIST, то есть в pre-install или ранее.

Время от времени использования OPTIONS_SUB недостаточно. В таких случаях добавление специфичного TAG в PLIST_SUB внутри Makefile со специальным значением @comment заставляет инструменты пакетирования игнорировать строку. Например, если некоторые файлы устанавливаются только при включённой опции X11 и архитектуре i386:

.include <bsd.port.pre.mk>

.if ${PORT_OPTIONS:MX11} && ${ARCH} == "i386"
PLIST_SUB+=	X11I386=""
.else
PLIST_SUB+=	X11I386="@comment "
.endif

8.2. Пустые каталоги

8.2.1. Очистка пустых каталогов

При удалении порт должен удалить пустые каталоги, которые он создал. Большинство этих каталогов автоматически удаляются с помощью pkg(8), но для каталогов, созданных вне ${PREFIX}, или пустых каталогов требуется дополнительная работа. Обычно это делается добавлением строк @dir для таких каталогов. Подкаталоги должны быть удалены до удаления родительских каталогов.

[...]
@dir /var/games/oneko/saved-games
@dir /var/games/oneko

8.2.2. Создание пустых каталогов

Пустые каталоги, созданные во время установки порта, требуют особого внимания. Они должны присутствовать при создании пакета. Если они не созданы кодом порта, создайте их в Makefile:

post-install:
	${MKDIR} ${STAGEDIR}${PREFIX}/some/directory

Добавьте директорию в pkg-plist так же, как и любую другую. Например:

@dir some/directory

8.3. Файлы конфигурации

Если порт устанавливает файлы конфигурации в PREFIX/etc (или в другое место), не указывайте их в pkg-plist. Это приведёт к тому, что pkg delete удалит файлы, которые были тщательно отредактированы пользователем, а повторная установка перезапишет их.

Вместо этого устанавливайте образцы файлов с расширением filename.sample. Макрос @sample автоматизирует этот процесс; подробности его работы см. в разделе Расширение списка пакетов с помощью ключевых слов. Для каждого образца файла добавьте строку в pkg-plist:

@sample etc/orbit.conf.sample

Если существует очень веская причина не устанавливать рабочий файл конфигурации по умолчанию, укажите только имя примера файла в pkg-plist, без части @sample с последующим пробелом, и добавьте сообщение, указывающее, что пользователь должен скопировать и отредактировать файл перед тем, как программа заработает.

Когда порт устанавливает свою конфигурацию в подкаталоге ${PREFIX}/etc, используйте ETCDIR, который по умолчанию равен ${PREFIX}/etc/${PORTNAME}. Это значение может быть переопределено в Makefile порта, если для порта принято использовать другой каталог. Макрос %%ETCDIR%% будет использоваться вместо этого в pkg-plist.

Примеры конфигурационных файлов всегда должны иметь суффикс .sample. Если по каким-то историческим причинам использование стандартного суффикса невозможно, или если примеры файлов взяты из другого каталога, используйте эту конструкцию:

@sample etc/orbit.conf-dist etc/orbit.conf

или

@sample %%EXAMPLESDIR%%/orbit.conf etc/orbit.conf

Формат: @sample файл-образец фактический-конфигурационный-файл.

8.4. Динамический или статический список упаковки

Статический список упаковки — это список упаковки, который доступен в Коллекции Портов или как файл pkg-plist (с подстановкой переменных или без неё), или как встроенный в Makefile через PLIST_FILES и PLIST_DIRS. Даже если содержимое было автоматически сгенерировано инструментом или целью в Makefile до включения в Коллекцию портов коммиттером (например, с использованием make makeplist), такой список всё равно считается статическим, поскольку его можно посмотреть без необходимости загрузки или компиляции distfile.

Динамический список упаковки — это список упаковки, который генерируется во время компиляции порта на основе установленных файлов и каталогов. Невозможно изучить его до загрузки и компиляции исходного кода портированного приложения или после выполнения команды make clean.

Хотя использование динамических списков упаковки не запрещено, сопровождающие должны использовать статические списки упаковки везде, где это возможно, поскольку это позволяет пользователям выполнять grep(1) по доступным портам для обнаружения, например, какой порт устанавливает определенный файл. Динамические списки должны быть использованы в основном для сложных портов, для которых изменения в списке упаковки кардинальным образом основаны на возможностях порта, настраиваемых параметрами, (и, таким образом, делая сопровождение статических списков упаковки невозможным), или портов, которые изменяют список упаковки на основе версии используемого им программного обеспечения (например, порты, которые порождают документы при помощи Javadoc).

8.5. Автоматическое создание списка упаковки

Сначала убедитесь, что порт почти готов, и отсутствует только файл pkg-plist. Запуск команды make makeplist покажет пример для файла pkg-plist. Вывод makeplist необходимо дважды перепроверять на корректность, так как он пытается автоматически угадать некоторые вещи и может ошибаться.

Файлы конфигурации пользователя должны устанавливаться как filename.sample, как описано в разделе Файлы конфигурации. info/dir не должен быть указан, а соответствующие строки install-info должны быть добавлены, как указано в разделе info-файлы. Любые библиотеки, устанавливаемые портом, должны быть перечислены, как указано в разделе общие библиотеки.

8.5.1. Расширение PLIST_SUB с помощью регулярных выражений

Строки, которые нужно заменить, иногда должны быть очень конкретными, чтобы избежать нежелательных замен. Это распространённая проблема с короткими значениями.

Для решения этой проблемы для каждого PLACEHOLDER=значение можно задать PLACEHOLDER_regex=регулярное_выражение, где часть regex более точно соответствует значению.

Пример 1. Использование PLIST_SUB с регулярными выражениями

Порты Perl могут устанавливать архитектурно-зависимые файлы в специальное дерево. В FreeBSD для упрощения портирования это дерево называется mach. Например, порт, который устанавливает файл, чей путь содержит mach, может иметь эту часть строки пути заменённой неправильными значениями. Рассмотрим этот Makefile:

PORTNAME=	Machine-Build
DISTVERSION=	1
CATEGORIES=	devel perl5
MASTER_SITES=	CPAN
PKGNAMEPREFIX=	p5-

MAINTAINER=	perl@FreeBSD.org
COMMENT=	Building machine
WWW=		https://search.cpan.org/dist/Machine-Build

USES=		perl5
USE_PERL5=	configure

PLIST_SUB=	PERL_ARCH=mach

Файлы, установленные портом:

/usr/local/bin/machine-build
/usr/local/lib/perl5/site_perl/man/man1/machine-build.1.gz
/usr/local/lib/perl5/site_perl/man/man3/Machine::Build.3.gz
/usr/local/lib/perl5/site_perl/Machine/Build.pm
/usr/local/lib/perl5/site_perl/mach/5.20/Machine/Build/Build.so

Запуск make makeplist ошибочно создает:

bin/%%PERL_ARCH%%ine-build
%%PERL5_MAN1%%/%%PERL_ARCH%%ine-build.1.gz
%%PERL5_MAN3%%/Machine::Build.3.gz
%%SITE_PERL%%/Machine/Build.pm
%%SITE_PERL%%/%%PERL_ARCH%%/%%PERL_VER%%/Machine/Build/Build.so

Измените строку PLIST_SUB в Makefile на:

PLIST_SUB=	PERL_ARCH=mach \
		PERL_ARCH_regex=\bmach\b

Теперь make makeplist правильно генерирует:

bin/machine-build
%%PERL5_MAN1%%/machine-build.1.gz
%%PERL5_MAN3%%/Machine::Build.3.gz
%%SITE_PERL%%/Machine/Build.pm
%%SITE_PERL%%/%%PERL_ARCH%%/%%PERL_VER%%/Machine/Build/Build.so

8.6. Расширение списка пакетов используя ключевые слова

Все ключевые слова также могут принимать необязательные аргументы в скобках. Аргументами являются владелец, группа и режим доступа. Этот аргумент применяется к файлу или каталогу, на который ссылаются. Чтобы изменить владельца, группу и режим доступа конфигурационного файла, используйте:

@sample(games,games,640) etc/config.sample

Аргументы являются необязательными. Если необходимо изменить только группу и режим, используйте:

@sample(,games,660) etc/config.sample

Если ключевое слово используется в необязательной записи, оно должно быть добавлено после помощника:

%%FOO%%@sample etc/orbit.conf.sample

Это происходит потому, что вспомогательные функции plist для опций используются для закомментирования строки, поэтому они должны быть указаны первыми. Дополнительную информацию см. в OPTIONS_SUB.

8.6.1. @desktop-file-utils

Будет выполнять update-desktop-database -q после установки и удаления. Никогда не используйте напрямую, добавьте USES=desktop-file-utils в Makefile.

8.6.2. @fc каталог

Добавить запись @dir для каталога, переданного в качестве аргумента, и выполнить fc-cache -fs для этого каталога после установки и удаления.

8.6.3. @fontsdir каталог

Добавить запись @dir для каталога, переданного в качестве аргумента, и запустить mkfontscale и mkfontdir в этом каталоге после установки и удаления. Кроме того, при удалении удаляются кэш-файлы fonts.scale и fonts.dir, если они пусты.

8.6.4. @info файл

Добавляет файл, переданный в качестве аргумента, в plist и обновляет индекс документа info при установке и удалении. Кроме того, удаляет индекс, если он пуст, при удалении. Это никогда не следует использовать вручную, а только через INFO. Подробнее см. в Файлы Info.

8.6.5. @kld каталог

Выполняет kldxref для каталога при установке и удалении. Дополнительно при удалении каталог будет удалён, если он пуст.

8.6.6. @rmtry файл

Удаляет файл при удалении и не выдает ошибку, если файл отсутствует.

8.6.7. @sample файл [файл]

Это используется для обработки установки файлов конфигурации, используя примеры файлов, поставляемых с пакетом. "Реальный" файл (не пример) — это либо второе имя файла, если оно присутствует, либо первое имя файла без расширения .sample.

Это делает три вещи. Во-первых, добавляет первый переданный файл в качестве аргумента, образец файла, в plist. Затем, при установке, если фактический файл не найден, копирует образец файла в фактический файл. И наконец, при удалении, удаляет фактический файл, если он не был изменён. Дополнительную информацию см. в Файлы конфигурации.

8.6.8. @shared-mime-info каталог

Выполняет update-mime-database для указанного каталога при установке и удалении.

8.6.9. @shell файл

Добавить файл, переданный в качестве аргумента, в plist.

При установке добавить полный путь к file в /etc/shells, убедившись, что он не добавлен повторно. При удалении удалите его из /etc/shells.

8.6.10. @terminfo

Не использовать самостоятельно. Если порт устанавливает файлы *.terminfo, добавьте USES=terminfo в его Makefile.

При установке и удалении, если присутствует tic, обновить ${PREFIX}/shared/misc/terminfo.db из файлов *.terminfo в ${PREFIX}/shared/misc.

8.6.11. Основные ключевые слова

Есть несколько ключевых слов, которые жестко закодированы и документированы в pkg-create(8). Для полноты изложения они также документированы здесь.

8.6.11.1. @ [файл]

Ключевое слово empty является заполнителем, используемым, когда необходимо изменить владельца, группу или права доступа к файлу. Например, чтобы установить группу файла в games и добавить бит setgid, добавьте:

@(,games,2755) sbin/daemon

8.6.11.2. @preexec команда, @postexec команда, @preunexec команда, @postunexec команда

Выполнить комманду как часть процесса установки или удаления пакета.

@preexec команда

Выполнить команду как часть скриптов pre-install.

@postexec команда

Выполнить команду как часть скриптов post-install.

@preunexec команда

Выполнить команду как часть скриптов pre-deinstall.

@postunexec команда

Выполнить команду как часть скриптов post-deinstall.

Если в команде содержится любая из этих последовательностей, они раскрываются непосредственно. Для следующих примеров предположим, что @cwd установлен в /usr/local, а последним извлечённым файлом был bin/emacs.

%F

Раскрывается до последнего извлеченного имени файла (как указано). В примере bin/emacs.

%D

Раскрыть до текущего префикса директории, установленного с помощью @cwd. В этом примере /usr/local.

%B

Раскрыть до базового имени полного имени файла, то есть префикс текущего каталога плюс последняя спецификация файла, за вычетом имени файла в конце спецификации. В данном примере это будет /usr/local/bin.

%f

Раскрывается до части имени файла в полном квалифицированном имени, или противоположный случай для %B. В примере, emacs.

Эти ключевые слова предназначены для помощи в настройке пакета, чтобы он был максимально готов к использованию. Они не должны использоваться для запуска служб, остановки служб или выполнения любых других команд, которые изменяют текущую работающую систему.

8.6.11.3. @mode режим

Установить разрешения по умолчанию для всех последующих извлекаемых файлов в режим. Формат такой же, как используется в chmod(1). Использование без аргумента вернёт разрешения по умолчанию (режим файла при упаковке).

Это должен быть числовой режим, например 644, 4755 или 600. Нельзя использовать относительный режим, например u+s.

8.6.11.4. @owner пользователь

Установить владельца по умолчанию для всех последующих файлов в пользователь. Использование без аргумента вернёт владельца по умолчанию (root).

8.6.11.5. @group группа

Установить группу-владельца по умолчанию для всех последующих файлов в группу. Использование без аргумента вернёт группу-владельца по умолчанию (wheel).

8.6.11.6. @comment строка

Эта строка игнорируется при упаковке.

8.6.11.7. @dir каталог

Объявить имя каталога. По умолчанию каталоги, созданные в PREFIX при установке пакета, автоматически удаляются. Используйте эту опцию, если необходимо создать пустой каталог в PREFIX или если каталогу требуется нестандартный владелец, группа или права. Каталоги за пределами PREFIX необходимо регистрировать. Например, /var/db/${PORTNAME} требует записи @dir, тогда как ${PREFIX}/shared/${PORTNAME} — нет, если он содержит файлы или использует стандартные владельца, группу и права.

8.6.11.8. @exec команда, @unexec команда (Устарело)

Выполнить команду как часть процесса установки или удаления. Рекомендуется использовать @preexec команда вместо этого.

8.6.11.9. @dirrm каталог (Устарело)

Объявить имя каталога для удаления при деинсталляции. По умолчанию каталоги, созданные в PREFIX при установке пакета, удаляются при его деинсталляции.

8.6.11.10. @dirrmtry каталог (Устарело)

Объявить имя каталога для удаления, аналогично @dirrm, но не выводить предупреждение, если каталог не может быть удален.

8.6.12. Создание новых ключевых слов

Файлы списка пакетов могут быть расширены ключевыми словами, которые определены в каталоге ${PORTSDIR}/Keywords. Настройки каждого ключевого слова хранятся в файле UCL с именем keyword.ucl. Файл должен содержать как минимум один из следующих разделов:

  • attributes

  • action

  • pre-install

  • post-install

  • pre-deinstall

  • post-deinstall

  • pre-upgrade

  • post-upgrade

8.6.12.1. attributes

Изменяет владельца, группу или режим доступа, используемые ключевым словом. Содержит ассоциативный массив, в котором возможными ключами являются owner, group и mode. Значениями являются, соответственно, имя пользователя, имя группы и режим доступа к файлу. Например:

attributes: { owner: "games", group: "games", mode: 0555 }

8.6.12.2. action

Определяет, что происходит с параметром ключевого слова. Содержит массив, где возможные значения:

setprefix

Установите префикс для следующих записей в plist.

dir

Зарегистрировать каталог для создания при установке и удаления при деинсталляции.

dirrm

Зарегистрировать каталог для удаления при деинсталляции. Устарело.

dirrmtry

Зарегистрировать каталог для попытки удаления при деинсталляции. Устарело.

file

Зарегистрировать файл.

setmode

Установить режим для следующих записей plist.

setowner

Установить владельца для следующих записей plist.

setgroup

Установить группу для следующих записей в plist.

comment

Не выполняет никаких действий, эквивалентно отсутствию раздела action.

ignore_next

Игнорировать следующую запись в plist.

8.6.12.3. arguments

Если установлено значение true, добавляется обработка аргументов, разделяя всю строку, %@, на нумерованные аргументы, %1, %2, и так далее. Например, для такой строки:

@foo some.content other.content

%1 и %2 будут содержать:

some.content
other.content

Это также влияет на работу записи action. Если аргументов больше одного, необходимо указать номер аргумента. Например:

actions: [file(1)]

8.6.12.4. pre-install, post-install, pre-deinstall, post-deinstall, pre-upgrade, post-upgrade

Эти ключевые слова содержат sh(1) скрипт, который выполняется до или после установки, удаления или обновления пакета. В дополнение к обычным заполнителям @exec %foo, описанным в @preexec команда, существует новый заполнитель %@, который представляет аргумент ключевого слова.

8.6.12.5. Примеры пользовательских ключевых слов

Пример 2. Пример ключевого слова @dirrmtryecho

Это ключевое слово выполняет две функции: добавляет строку @dirrmtry directory в список упаковки и сообщает о том, что директория удаляется при деинсталляции пакета.

actions: [dirrmtry]
post-deinstall: <<EOD
  echo "Directory %D/%@ removed."
EOD
Пример 3. Реальный пример, как реализован @sample

Этот ключевое слово выполняет три действия. Оно добавляет первый filename, переданный в качестве аргумента @sample, в список упаковки, добавляет в скрипт post-install инструкции для копирования образца в фактический файл конфигурации, если он ещё не существует, и добавляет в инструкции post-deinstall удаление файла конфигурации, если он не был изменён.

actions: [file(1)]
arguments: true
post-install: <<EOD
  case "%1" in
  /*) sample_file="%1" ;;
  *) sample_file="%D/%1" ;;
  esac
  target_file="${sample_file%.sample}"
  set -- %@
  if [ $# -eq 2 ]; then
      target_file=${2}
  fi
  case "${target_file}" in
  /*) target_file="${target_file}" ;;
  *) target_file="%D/${target_file}" ;;
  esac
  if ! [ -f "${target_file}" ]; then
    /bin/cp -p "${sample_file}" "${target_file}" && \
      /bin/chmod u+w "${target_file}"
  fi
EOD
pre-deinstall: <<EOD
  case "%1" in
  /*) sample_file="%1" ;;
  *) sample_file="%D/%1" ;;
  esac
  target_file="${sample_file%.sample}"
  set -- %@
  if [ $# -eq 2 ]; then
      set -- %@
      target_file=${2}
  fi
  case "${target_file}" in
  /*) target_file="${target_file}" ;;
  *) target_file="%D/${target_file}" ;;
  esac
  if cmp -s "${target_file}" "${sample_file}"; then
    rm -f "${target_file}"
  else
    echo "You may need to manually remove ${target_file} if it is no longer needed."
  fi
EOD

Изменено: 18 сентября 2025 г. by Vladlen Popolitov