Вопрос или проблема
Я пытаюсь создать бинарный пакет на операционной системе FreeBSD. Все найденные мной руководства в основном утверждают, что нужно создавать бинарный пакет из уже установленного программного обеспечения, используя порты. Я ищу способ сделать это без установки портов.
Это возможно?
Мой код написан на Go. Таким образом, исходный код содержит один бинарный файл, скомпилированный из кода Go, а также файлы конфигурации.
Документацию по формату пакетов можно найти здесь: https://wiki.freebsd.org/pkgng#Package_format
Вам не нужно устанавливать программное обеспечение для создания пакета. Во время выполнения команды make package в порту он устанавливается в промежуточную директорию, а затем архивируется.
Документация по формату пакета (поскольку pkgng стал pkg) теперь находится по адресу https://github.com/freebsd/pkg#pkgfmt.
Файл .pkg
по сути является архивом tar, дополнительно сжатым с помощью одного из нескольких стандартных инструментов и с несколькими дополнительными ограничениями.
Во-первых, первые файлы в архиве представляют собой метаданные. Указаны два файла, названные +MANIFEST
и +COMPACT_MANIFEST
, без пути и без начального /
. Эти файлы сопровождаются файлами, которые необходимо установить, каждый из которых имеет полный путь назначения (начиная с /
).
Метаданные
+MANIFEST
, в соответствии со спецификациями, является файлом в формате UCL, который представляет собой нечто среднее между YAML и JSON. Чистый JSON будет работать (при установке пакета с помощью pkg add blah.pkg
) и именно его я обнаружил при изучении пакета из репозитория FreeBSD.
Значения манифеста в значительной степени соответствуют переменным makefile, как описано в https://docs.freebsd.org/en/books/porters-handbook. В частности:
name
— это имя, которое вы выбрали для пакета.
version
— это версия, соответствующая некоторым конвенциям для определения, какая из двух заданных версий новее.
origin
— физическое местоположение пакета в репозитории, в виде category/name
, где name
идентично значению name
. Дополнительные категории могут быть указаны в categories
.
comment
— это однострочное описание пакета.
arch
принимает форму, подобную freebsd:13:x86:64
. Шаблонные значения, такие как freebsd:*
, работали при установке для пакетов, которые не зависят от конкретной архитектуры и/или версии ОС.
www
и maintainer
— это URL веб-сайта и адрес электронной почты, соответственно, для проекта.
prefix
обычно равен /usr/local
, но, похоже, не влияет на время установки, даже если пакет устанавливается в /opt
и /etc
.
licenselogic
: single
, если есть только одна лицензия, or
, если есть выбор между несколькими.
licenses
— это список лицензий, на которые ссылаются такие идентификаторы, как GPLv3+
, GPLv2
, BSD
. См. Руководство портера для подробностей.
flatsize
кажется совокупным размером всех установленных файлов. Не на 100% уверен, так как значения немного отличались в пакете, который я изучал, но пакет, который я создал на этом предположении, установился нормально с pkg add
.
users
, groups
представляют собой пользователей и группы, которые необходимо создать при установке пакета (не пробовал, так что не могу сказать, срабатывают ли эти записи на самом деле для создания упомянутых пользователей и групп).
options
: не уверен, мой пакет установился нормально без них.
desc
— это более длинное (более одного предложения) описание пакета.
categories
— это список дополнительных категорий, в которых пакет должен быть указан. Категория из origin
кажется повторяется здесь.
deps
— это зависимости, т.е. другие пакеты, необходимые для работы этого пакета. Обычно они принимают следующую форму:
name: {origin: category/name, version: 1.2.3}
(обязывающее минимальная версия) или простоname: {origin: category/name}
(для любой версии)
directories
представляют собой каталоги, созданные пакетом. Записи имеют форму /usr/local/share/foo-1.0: y
; не уверен, что значит это значение – должно ли удаляться директория при удалении? Тем не менее, пакет будет установиться нормально (и создать каталоги по мере необходимости) без этой записи.
files
: Файлы с их SHA256 контрольной суммой. Не уверен, что происходит, если файл в архиве не имеет записи здесь – устанавливается ли он вообще или устанавливается, но без проверки SHA256?
scripts
— это скрипты, которые запускаются до, во время или после установки или удаления.
+COMPACT_MANIFEST
— это просто +MANIFEST
с опущенными некоторыми значениями. Первое предназначено для перечисления пакета в репозиториях, последнее используется для выполнения самой установки. Установка пакета только с +MANIFEST
, но без +COMPACT_MANIFEST
, кажется, работает, хотя могут быть побочные эффекты, когда вы пытаетесь добавить пакет в официальный репозиторий.
Сборка пакета
Мне удалось собрать пакет, который устанавливается на FreeBSD всего с помощью простого скрипта оболочки. Это имеет приятный побочный эффект, что мне даже не нужна BSD для его сборки, что удобно, если нет нативного кода.
Легче всего создать скелет манIFEST в формате YAML, генерировать files
и flatsize
на лету, а затем конвертировать все в JSON.
Образец скрипта оболочки:
FLATSIZE=0
create_files_entry() {
# TODO если файл является ссылкой, просто вставьте '-'
sha256sum $1 | sed -E 's,([a-fA-F0-9]*) *(.*), \2: \1,' | sed $2
}
add_file() {
[ -d $1 ] && return
create_files_entry $1 $2 >> $(dirname $0)/cache/files.yaml
tar -Pr -f $(dirname $0)/cache/data.tar --transform=$2 $1
case `uname` in
Linux)
FLATSIZE=$(( FLATSIZE + $(stat -c %s $1) ))
;;
FreeBSD)
FLATSIZE=$(( FLATSIZE + $(stat -f %d $1) ))
;;
*)
echo "ERROR: неподдерживаемая платформа для сборки: `uname`"
exit 1
;;
esac
}
echo "files:" > cache/files.yaml
# второй параметр - это преобразование, чтобы изменить путь к файлу
add_file path/to/file 's,\./path/to/,/usr/local/foo/,'
# добавьте больше файлов таким образом по мере необходимости
echo "flatsize: $FLATSIZE" >> files.yaml
cat $manifest.yaml $cache/files.yaml | python3 -c 'import sys, yaml, json; print(json.dumps(yaml.safe_load(sys.stdin.read())))' > cache/+MANIFEST
cat cache/+MANIFEST | python3 -c 'import sys, json; manifest = json.loads(sys.stdin.read()); manifest.pop("files", None); manifest.pop("directories", None); manifest.pop("scripts", None); print(json.dumps(manifest))' > cache/+COMPACT_MANIFEST
# создайте новый архив с +MANIFEST и +COMPACT_MANIFEST (без начального /)
tar -c -f cache/full.tar --transform='s,\./cache/,,' cache/+MANIFEST cache/+COMPACT_MANIFEST
tar -A cache/data.tar -f cache/full.tar
# сжать и переместить в конечное место
xz cache/full.tar
mv cache/full.tar.xz out/$PKGNAME-$PKGVER.pkg
Установка
Полученный файл pkg теперь можно установить с помощью:
pkg add /path/to/foo-1.2.3.pkg
Ответ или решение
Создание бинарных пакетов в операционной системе FreeBSD можно осуществить без использования системы портов, что является полезной альтернативой, особенно когда вы разрабатываете программное обеспечение, написанное на языках, таких как Go. В данной статье мы подробно рассмотрим, как можно создать бинарный пакет в формате .pkg
, начиная с исходного кода и без установки портов.
Понимание структуры пакета
Бинарный пакет FreeBSD в формате .pkg
представляет собой архив tar
, который может быть сжат стандартными инструментами. Он включает в себя метаданные и файлы, необходимые для установки. Основные файлы, которые вы должны включить в пакет, это:
+MANIFEST
: файл метаданных в формате UCL (похож на YAML или JSON), который содержит информацию о вашем пакете, такую как имя, версия, разрешения и зависимости.+COMPACT_MANIFEST
: сокращенная версия+MANIFEST
без некоторых полей, используемая для отображения в репозиториях.
Создание пакета без портов
Для создания пакета без использования системы портов FreeBSD вы можете воспользоваться простым скриптом на Shell. Ниже приведен пример, который поможет вам в этом процессе.
Шаг 1: Определение метаданных
Сначала создадим скелетный файл манифеста. Пример структуры YAML для +MANIFEST
может выглядеть следующим образом:
name: my-go-app
version: 1.0.0
origin: mycategory/my-go-app
comment: My Go Application
arch: freebsd:13:x86:64
maintainer: example@example.com
flatsize: 0
files:
Шаг 2: Сбор файлов
Создайте функцию для генерации записей о файлах и добавления их в архив:
create_files_entry() {
sha256sum "$1" | sed -E 's,([a-fA-F0-9]*) *(.*), \2: \1,' | sed "$2"
}
add_file() {
if [ -d "$1" ]; then return; fi
create_files_entry "$1" "$2" >> cache/files.yaml
tar -Pr -f cache/data.tar --transform="$2" "$1"
FLATSIZE=$(( FLATSIZE + $(stat -f %z "$1") ))
}
Ваша задача – добавить все необходимые файлы с помощью вызова add_file
. Пример:
add_file path/to/your/binary 's,./path/to/,/usr/local/bin/,'
Шаг 3: Генерация манифеста
После того как все файлы добавлены, создавайте финальные файлы манифеста и получайте сжатый архив:
cat $manifest.yaml cache/files.yaml | python3 -c 'import sys, yaml, json; print(json.dumps(yaml.safe_load(sys.stdin.read())))' > cache/+MANIFEST
cat cache/+MANIFEST | python3 -c 'import sys, json; manifest = json.loads(sys.stdin.read()); manifest.pop("files", None); print(json.dumps(manifest))' > cache/+COMPACT_MANIFEST
# Создайте новый архив с +MANIFEST и +COMPACT_MANIFEST
tar -c -f cache/full.tar --transform='s,\./cache/,,' cache/+MANIFEST cache/+COMPACT_MANIFEST
tar -A cache/data.tar -f cache/full.tar
xz cache/full.tar
mv cache/full.tar.xz out/my-go-app-1.0.0.pkg
Шаг 4: Установка пакета
Теперь, когда у вас есть пакет my-go-app-1.0.0.pkg
, вы можете установить его на любой системе FreeBSD с помощью команды:
pkg add /path/to/my-go-app-1.0.0.pkg
Заключение
Создание бинарного пакета в FreeBSD без использования системы портов совершенно возможно и может быть выполнено с помощью простого скрипта на Shell. Следуя описанным шагам, вы сможете собрать и упаковать ваши приложения, увеличивая гибкость и удобство в развертывании программного обеспечения. Со знанием формата и структуры пакета, вы сможете адаптировать процесс под свои нужды, что позволит вам эффективно управлять своими программными проектами.