Create rpm on windows

I finally got tired of build RPMs in a VM. Its ridiculously slow because its done on a shared Windows partition.
I started looking around to see if it was possible, all indications where that it hasn’t really been done…
I found a few Java libraries that allows you to manipulate RPM files but using them would require writing a maven plugin before I can get anything done… Have a look at http://jrpm.sourceforge.net/ and http://redline-rpm.org/ to see what if they’re useful for you…

<!— more —>Using maven I’ve configured the Maven RPM plugin (see http://mojo.codehaus.org/rpm-maven-plugin/) to generate an RPM from my project. I’ll include the POM section for that in a while. To get started however you need Cygwin installed…

Visit http://cygwin.com/ , download and install setup.exe. On the screen which asks you to select packages to be installed search for «RPM»

Install the three packages as shown above in the screenshot, rpm,rpmbuild and optionally rpm-doc.
Also ensure the packages libintl2 and sed are selected for installation.

If you already have Cygwin installed then just re-run setup.exe and add the packages above as necessary.

The next thing to do is identify your cygwin bin directory. For example, I installed Cygwin in «C:\bin\cygwin» So my  cygwin bin directory is «C:\bin\cygwin\bin«.

Add this directory to the system path. (Start -> Right click «Computer» ->Properties -> Advanced System settings -> Environment variables and under «System paths», append the directory to the «Path» variable.)

In that folder create a file called rpmbuild.bat and add the following contents to that file:

SETLOCAL
PUSHD .

REM Update buildroot path
FOR /F "tokens=*" %%i in ('cygpath %3') do SET NEW_BUILDROOT=%%i

REM Update topdir path
SET TOPDIR=%5
SET TOPDIR=%TOPDIR:~9,-1%
FOR /F "tokens=*" %%i in ('cygpath "%TOPDIR%"') do SET NEW_TOPDIR=%%i

REM Replace path in spec-file
SET OLD_PATH=%TOPDIR:\=\\%
SET NEW_PATH=%NEW_TOPDIR:/=\/%

REM Original sed command
REM sed -s -i -e s/%OLD_PATH%\\/%NEW_PATH%\//g %8

REM replace \ with / i.e. escape \\ replace with escape \/
sed -s -i -e s/\\/\//g %8

REM Execute rpmbuild

bash -c "rpmbuild %1 %2 %NEW_BUILDROOT% %4 ""_topdir %NEW_TOPDIR%"" %6 "%7" --define ""_build_name_fmt %%{ARCH}/%%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm"" %8"

POPD
ENDLOCAL

NOTE: I didn’t write it, I found it when I ran into issues trying to get my RPM setup to work see https://jira.codehaus.org/browse/MRPM-4 for the original source.
The above script replaces backslashes in the spec file generated with Windows paths.
It then executes the «real rpmbuild» using Cygwin’s bash (to provide a linuxish environment)…

This executes fairly quickly and writes the RPM as expected.

I finally got tired of build RPMs in a VM. Its ridiculously slow because its done on a shared Windows partition.
I started looking around to see if it was possible, all indications where that it hasn’t really been done…
I found a few Java libraries that allows you to manipulate RPM files but using them would require writing a maven plugin before I can get anything done… Have a look at http://jrpm.sourceforge.net/ and http://redline-rpm.org/ to see what if they’re useful for you…

Using maven I’ve configured the Maven RPM plugin (see http://mojo.codehaus.org/rpm-maven-plugin/) to generate an RPM from my project. I’ll include the POM section for that in a while. To get started however you need Cygwin installed…

Visit http://cygwin.com/ , download and install setup.exe. On the screen which asks you to select packages to be installed search for “RPM”

Install the three packages as shown above in the screenshot, rpm,rpmbuild and optionally rpm-doc.
Also ensure the packages libintl2 and sed are selected for installation.

If you already have Cygwin installed then just re-run setup.exe and add the packages above as necessary.

The next thing to do is identify your cygwin bin directory. For example, I installed Cygwin in “C:\bin\cygwin” So my  cygwin bin directory is “C:\bin\cygwin\bin“.

Add this directory to the system path. (Start -> Right click “Computer” ->Properties -> Advanced System settings -> Environment variables and under “System paths”, append the directory to the “Path” variable.)

In that folder create a file called rpmbuild.bat and add the following contents to that file:

SETLOCAL
PUSHD .

REM Update buildroot path
FOR /F "tokens=*" %%i in ('cygpath %3') do SET NEW_BUILDROOT=%%i

REM Update topdir path
SET TOPDIR=%5
SET TOPDIR=%TOPDIR:~9,-1%
FOR /F "tokens=*" %%i in ('cygpath "%TOPDIR%"') do SET NEW_TOPDIR=%%i

REM Replace path in spec-file
SET OLD_PATH=%TOPDIR:\=\\%
SET NEW_PATH=%NEW_TOPDIR:/=\/%

REM Original sed command
REM sed -s -i -e s/%OLD_PATH%\\/%NEW_PATH%\//g %8

REM replace \ with / i.e. escape \\ replace with escape \/
sed -s -i -e s/\\/\//g %8

REM Execute rpmbuild

bash -c "rpmbuild %1 %2 %NEW_BUILDROOT% %4 ""_topdir %NEW_TOPDIR%"" %6 "%7" --define ""_build_name_fmt %%{ARCH}/%%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm"" %8"

POPD
ENDLOCAL

NOTE: I didn’t write it, I found it when I ran into issues trying to get my RPM setup to work see https://jira.codehaus.org/browse/MRPM-4 for the original source.
The above script replaces backslashes in the spec file generated with Windows paths.
It then executes the “real rpmbuild” using Cygwin’s bash (to provide a linuxish environment)…

This executes fairly quickly and writes the RPM as expected.

Обновлено:
Опубликовано:

В данной инструкции мы научимся готовить Linux-среду для работы и рассмотрим примеры по созданию своих пакетов RPM. Также приведем описание файла SPEC, который используется для описания процесса сборки пакета.

Мы будем работать в системе CentOS (Red Hat / Fedora).

Подготовка системы к работе
Сборка пакета из исходников
Описание файла SPEC
Возможные ошибки

Подготовка системы

Для работы по сборке пакетов лучше использовать отдельный компьютер, виртуальную машину или контейнер Docker.

1. Установим пакеты:

yum install rpmdevtools rpmlint

* где: 

  • rpmdevtools — позволит нам использовать утилиту rpmdev-setuptree, с помощью которой мы сможем создать рабочую среду в виде каталогов для сборки.
  • rpmlint — позволяет протестировать пакет RPM.

А также ставим:

yum group install «Development Tools»

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

2. Создаем пользователя.

Делать готовые установочные сборки пакетов очень опасно от пользователя root. Если мы допустим ошибку с путями, файлы могут перетереть или удалить важные для работы директории. Стоит создать отдельного пользователя и работать под ним. Однако, если мы работаем в виртуальной среде или контейнере Docker, нам это не страшно. Тогда данный пункт можно пропустить и работать из под root.

Выполняем команду:

useradd builder -m

* в данном примере мы создадим пользователя builder. Опция -m сразу создаст домашний каталог для пользователя.

Теперь заходим под данным пользователем — последующие команды мы будем выполнять от него:

su — builder

3. Создадим структуру каталогов для сборки:

rpmdev-setuptree

В нашей текущем каталоге должна появиться папка rpmbuild — а в ней:

  1. BUILD — содержит все файлы, которые появляются при создании пакета.
  2. RPMS — сюда будут складываться готовые пакеты.
  3. SOURCES — для исходников, из которых и будут собираться RPM-пакеты.
  4. SPECS — для файлов с описанием процесса сборки.
  5. SRPMS — для исходников RPM-файлов.

Мы готовы к сборке.

Сборка из исходников

Рассмотрим пример создания RPM из пакета, который нужно собирать из исходников с помощью команды make. Например, возьмем данную программу: github.com/brettlaforge/pg_redis_pubsub.

Создадим файл spec:

rpmdev-newspec rpmbuild/SPECS/pg_redis_pubsub.spec

Теперь откроем его и приведем к виду:

vi rpmbuild/SPECS/pg_redis_pubsub.spec

Name:           pg_redis_pubsub
Version:        1.0.2
Release:        1%{?dist}
Summary:        Redis Publish from PostgreSQL
License:        X11 License
URL:            https://github.com/brettlaforge/pg_redis_pubsub
Source0:        %{name}-%{version}.tar.gz

BuildRequires:  postgresql-devel postgresql-server-devel
BuildRequires:  hiredis-devel
Requires:       postgresql
%if 0%{?rhel} < 8
Requires:       hiredis-last >= 0.13.3-1
%else
Requires:       hiredis = 0.15
%endif

%define         _build_id_links none

%description
Redis Publish from PostgreSQL

%prep
%{__rm} -rf %{name}-%{version}
%{__mkdir} -p %{name}-%{version}
%{__tar} -xzvf %{SOURCE0} -C %{_builddir}/%{name}-%{version} —strip-components 1

%build
cd %{name}-%{version}
%{__make}

%install
cd %{name}-%{version}
%{__make} install DESTDIR=%{buildroot}

%clean
%{__rm} -rf $RPM_BUILD_ROOT
%{__rm} -rf $RPM_BUILD_DIR/*

%files
%defattr(-,root,root)
%{_libdir}/pgsql/redis.so
%{_datadir}/pgsql/extension/redis.control
%{_datadir}/pgsql/extension/redis—0.0.1.sql
%doc %{_docdir}/extension/redis.md

%changelog
* Fri Jul  9 2021 root

* чтобы понять, как заполнить spec-файл, рекомендуется для начала собрать и установить приложение вручную с помощью make и make install. Также необходимо изучить документацию устанавливаемого пакета или (при наличие возможности) поговорить с разработчиками программного обеспечения.

Установим зависимости, которые необходимы для сборки (BuildRequires):

yum-builddep rpmbuild/SPECS/pg_redis_pubsub.spec

* утилита yum-builddep сама читает зависимости, необходимые для сборки и устанавливает недостающие пакеты.

Можно это сделать и вручную. В данном примере это: 

yum install epel-release

yum install postgresql-devel postgresql-server-devel hiredis-devel

* конкретно, в моем примере для установки hiredis-devel необходимо поставить репозиторий epel-release. Список пакетов, необходимый для сборки конкретного пакета необходимо уточнить в документации.

Теперь копируем исходник на свой компьютер. В моем примере клонируем репозиторий:

git clone https://github.com/brettlaforge/pg_redis_pubsub.git

Готовим архив и помещаем его в каталог rpmbuild/SOURCES:

tar -czvf rpmbuild/SOURCES/pg_redis_pubsub-1.0.2.tar.gz pg_redis_pubsub

Если бы в качестве Source мы указали внешний URL, можно было бы предварительно загрузить исходники командой:

spectool -g -R rpmbuild/SPECS/pg_redis_pubsub.spec

Данная команда разместит загруженные файлы в каталоге rpmbuild/SOURCES/. Если нужно указать другой путь, используем опцию -C:

spectool -g -R rpmbuild/SPECS/pg_redis_pubsub.spec -C /tmp/

Проверяем корректность SPEC-файла:

rpmlint rpmbuild/SPECS/pg_redis_pubsub.spec

В моем примере команда вернула ответ:

rpmbuild/SPECS/pg_redis_pubsub.spec: W: invalid-url Source0: pg_redis_pubsub-1.0.2.tar.gz
0 packages and 1 specfiles checked; 0 errors, 1 warnings.

Данное предупреждение можно проигнорировать.

Выполняем сборку:

rpmbuild -bb rpmbuild/SPECS/pg_redis_pubsub.spec

Если она пройдет без ошибок, мы должны найти RPM-пакет в каталоге rpmbuild/RPMS/x86_64, где x86_64 — архитектура пакета.

Описание файла SPEC

Данный файл является инструкцией по сборке пакета. В нем мы описываем сам пакет, задаем метаданные и указываем, как извлекать файлы и куда их копировать при установке пакета. Синтаксис файла включает такие элементы, как разделы, макросы, операторы, опции. Рассмотрим их отдельно.

Опции заголовка

Определяют описание пакета, а также некоторые важные для сборки параметры.

Опция Описание Пример значения
Name Название для пакета RPM pg_redis_pubsub
Version Версия собираемого пакета 1.0.2
Release Релиз или версия программы 1%{?dist}
?dist обозначение версии доработки
Summary Краткое описание пакета Redis Publish from PostgreSQL
License Способ лицензирования X11 License
URL Адрес источника пакета https://github.com/brettlaforge/pg_redis_pubsub
Source0 Источник данных, из которых должен собираться пакет.
Можно указать несколько источников: Source1, Source2 … SourceN
%{name}-%{version}.tar.gz
Данная запись означает, что сборщик будет искать архив 
pg_redis_pubsub-1.0.2.tar.gz в каталоге rpmbuild/SOURCES/
BuildRequires Требования к пакетам, которые нужны для сборки пакета. Можно написать большим списком, а можно добавить несколько отдельных строк BuildRequires. Также мы можем задать требование к версии пакета. postgresql-devel postgresql-server-devel hiredis-devel
Requires Требования к пакетам, которые нужны для установки собранного пакета. Можно написать большим списком, а можно добавить несколько отдельных строк Requires. Также мы можем задать требование к версии пакета. С версии rpm 4.13 поддерживаются логические операторы and, or, if. hiredis >= 0.13.3-1, (postgrespro-std-15-client or postgrespro-ent-15-client)
Provides Имя предоставляемого пакета. Данная опция важна для Requires других пакетов. Например, мы можем делать сборку пакета с разными назвваниями, которые зависят от версии или среды, но у всех этих пакетов будет общее поле Provides, таким образом, при зависимостях можно будет указать только данное общее значение. pg_pubsub
Obsoletes Объявляет пакеты устаревшими. Установщик выполнит их удаление при установке собранного пакета. hiredis < 0.13.3-1

Теги для определения переменных

С помощью тега %define можно определять переменные. Предоставлены разные возможности это сделать:

Пример определения Описание
%define debug_package 1 Простое создание переменной debug_package со значением 1. Обращение к данной перемнной возможно с помощью написания %{debug_package}.
%{!?osname: %define osname «redos»} Данная переменная osname будет определена со значением redos, если она не определена ранее.

Также мы можем определить переменную с помощью %global, например:

%global debug_package %{nil}

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

Основные рабочие разделы

В каждом разделе описывается своя часть логики процесса сборки пакета.

Раздел Описание
%description Описание пакета. Может состоять из нескольких строк, но каждая строка должна содержать до 73 символов.
%package -n <имя пакета> Будет создан дополнительный пакет с именем <имя пакета>. Для данного подраздела можно указать свои опции Summary, Requires и так далее. В одном файле spec можно указать сколько угодно данных разделов со своими поднастройками. Это значит, что при сборке будет созданно несколько пакетов с разными названиями.
%description -n <имя пакета> Описание для создаваемого дополнительного пакета.
%package devel Добавленный devel указывает на то, что будет создан дополнительный пакет devel.
%description devel Описание для пакета devel.
%prep Предварительная обработка. Используется для подготовки исходников. Как правило, в данном разделе происходит их распаковка. Также на данном этапе могут применяться патчи.
%build Этап сборки пакета. Как правило, это make.
%install Установка пакета. Это может быть make install или копирование конкретных файлов в конкретные директории или запуск произвольного скрипта.
%clean Раздел содержит инструкции по удалению устаревших файлов, которые больше не нужны.
%files Перечисляем файлы, которые должны попасть в конечную систему при установке пакета.
%files -n <имя пакета> Список файлов для дополнительного пакета.
%files devel Список файлов, которые должны войти в пакет devel.
%changelog Список изменений в работе программного обеспечения.

Макросы разделов

У каждого из разделов могут быть свои макросы.

%files:

Макрос Описание
<путь до файла или папки> Добавляем файл или каталог в пакет без указания дополнительных опций.
%doc Указываем, что конкретные файлы относятся к документации. Такие файлы будут установлены в раздел /usr/doc/
%config Помечаем файлы как конфигурационные. Это задает действие при удалении пакета — если файлы были изменены, они будут переименованы с добавлением .rpmsave.
%dir Обозначает директорию, которой владеет пакет. При удалении пакета, также будет удаляться данная директория.
%files -f Позволяет перечислить файлы во внешнем файле и передать его как аргумент.
%defattr(<file rights>,<user>,<group>,<dir rights>) Задаем права для файлов и каталогов, которые будут назначены при установке пакета. Данный макрос применяется глобально ко всем файлам. Например: %defattr(644,root,root).
%attr(<mode>,<user>,<group>) Задаем права на файл или каталог, которые должны быть назначены при установке пакета. Данный макрос применяется к конкретному перечню файлов. Например: %attr(644,postgres,postgres) %{_libdir}/pgsql/redis.so.
%attr(<mode>,<user>,<group>) %config(noreplace) В данном примере мы зададим и атрибут, и укажем, что файл является конфигурационным.
%license Указываем, что файл является файлом лицензии.

Сценарии

Мы можем описать команды, которые будут выполняться на конечном компьютере при установке или удалении пакета:

Сценарий Описание
%pre Выполняется перед установкой пакета в систему
%post Выполняется после установки пакета в систему
%preun Выполняется перед удалением пакета из системы
%postun Выполняется после удаления пакета из системы

Пример для %post 

%post
case «$1» in
    1)
      post_install.sh
    ;;

    2)
      post_upgrade.sh
    ;;

    *)
        echo «postinst called with unknown argument \`$1′» >&2
        exit 1
    ;;
esac
exit 0

* макрос %post принимает аргумент $1, который говорит нам как был установлен пакет — новая установка (1) или обновление (2). Это важно, так как действия, как правило, отличаются, в зависимости от того, чистая это установка или обновление.

В зависимости от момента запуска сценария (%pre, %preun …) значения для $1 меняются. Используйте в качестве шпаргалки данную таблицу:

  Установка Обновление Удаление
%pre $1 == 1 $1 == 2
%post $1 == 1 $1 == 2
%preun $1 == 1 $1 == 0
%postun $1 == 1 $1 == 0

Макросы для сценариев

Внутри сценариев могут быть запущены свои макросы:

Сценарий Макрос Описание
%post %systemd_post Запускается процедура установки и регистрации сервиса.
%preun  %systemd_preun Запрещается автозапуск сервиса (systemctl —no-reload disable …)
%postun %systemd_postun_with_restart Отмечает сервис для перезагрузки

Макросы для команд

Некоторые системные команды лучше писать не напрямую, а через макросы. Это позволит добиться большей стабильности при сборке на различных системах. Приведем в пример данные команды:

Макрос Команда Описание
%{__rm}  rm Удаление файлов
%{__mv} mv Перенос файлов
%{__tar} tar Распаковка или создание архивов формата gz
%{__unzip} unzip Распаковка архивов формата zip
%{__sed} sed Поиск по шаблону текста и его замена
%{__ln_s} ln -s Создание симлинка
%{__mkdir} mkdir Создание каталога
%{__mkdir_p} mkdir -p Рекурсивное создание каталога (создает папки по пути)
%{__chmod} chmod Назначение прав доступа на файл или каталог
%{__chown} chown Назначение владельца на файл или каталог
%{__install} install Копирование файлов с выставлением аттрибутов
%{__cp} cp Копирование файлов
%{__cat} cat Отображение содержимого файла

* полный список макросов можно получить командой rpm —showrc.

Макросы для каталогов

Каталоги лучше писать не буквально, а через макросы:

Макрос Путь Итоговый путь
%{_prefix} /usr /usr
%{_usr} /usr /usr
%{_libdir}  %{_prefix}/lib64 /usr/lib64
%{_datarootdir} %{_prefix}/share /usr/share
%{_datadir} %{_datarootdir} /usr/share
%{_sysconfdir} /etc /etc
%{_var} /var /var
%{_localstatedir} /var /var
%{_sharedstatedir} /var/lib /var/lib
%{_docdir} %{_datadir}/doc /usr/share/doc
%{_unitdir} /usr/lib/systemd/system /usr/lib/systemd/system
%{_exec_prefix} %{_prefix} /usr
%{_bindir} %{_exec_prefix}/bin /usr/bin
%{_sbindir} %{_exec_prefix}/sbin /usr/sbin

* обратите внимание, что некоторые макросы ведут не на конкретные пути, а на другие макросы.
* полный список макросов можно получить командой rpm —showrc.

Раздел %files

Стоит немного подробнее рассмотреть раздел %files. В нем мы описываем файлы, которые должны быть упакованы в пакет. Приведем пример:

%files
%defattr(0640,postgres,postgres,0750)
%attr(0644,postgres,postgres) %{_libdir}/pgsql/redis.so
%{_datadir}/pgsql/extension/redis.control
%{_datadir}/pgsql/extension/redis—0.0.1.sql
%attr(0640,root,root) %doc %{_datadir}/doc/extension/redis.mmd
%config(noreplace) %{prefix}/redis_ext.conf

* в данном примере:

  • По умолчанию всем файлам присваиваются права 0640, каталогам — 0750. В качестве пользователя-владельца по умолчанию назначается postgres.
  • Для файла redis.so мы решили поменять права на 0644.
  • Файлу redis.mmd будет назначен владелец root.
  • Файл redis_ext.conf обозначен как конфигурационный файл и он не будет заменяться при обновлении пакета.

Служебные переменные

Ранее мы рассмотрели возможность определения переменных в файле spec с помощью директив %define или %global. Переменные могут нами использовать для подстановки значений в определенные блоки сценария. Но также, мы можем определять некоторую логику с помощью специальных переменных. Рассмотрим это на конкретных примерах:

Переменная Описание Варианты
debug_package Определяем необходимость создания пакета debuginfo (с отладочной информацией). По умолчанию значение 1 и при сборке пакета также собирается пакет с суффиксом debuginfo.
При значении %{nil} сборка проходит без создания debuginfo.
__python Путь до интерпретатора python. Если Наша система использует по умолчанию python не той версии, для которой собрано приложение, мы можем переопределить его сами. Можно задать как короткий путь, таки и полный:
python3
/usr/bin/python3
_build_id_links Позволяет указать, нужно ли создавать идентификаторы сборки в /usr/lib. Если не указан, то сборка будет выполняться с созданием идентификаторов.
Если задать значение none, то идентификаторы создаваться не будут.
__brp_check_rpaths При создании пакета rpmbuild проверяет пути библиотек с помощью check-rpaths. Данная опция позволяет указать, нужно ли это делать. Для отключения проверки путей задаем переменную со значением %{nil}.
__requires_exclude Инструмент rpmbuild при создании пакета автоматически генерирует зависимости (помимо того, что мы перечислим Requires). Данная опция позволяет исключить некоторые значения. Принимаются регулярные выражения, например:
^libssl.so.1.0.0
^libwidevinecdm.so.*
[.]so[.][0-2][a-f]
[.]so[.][0-2][a-f]*|^libwidevinecdm.so.*
* в последнем варианте перечислено 2 паттерна, разделенных символом |

Дополнительные опции

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

Опция Описание Значения
AutoReqProv Указывает, нужно ли делать автоматическую обработку зависимостей RPM. yes/no или 1/0.

Операторы сравнения

SPEC файл позволяет задавать логику с помощью операторов сравнения. Приведем примеры их использования:

Пример Описание
%if 0%{?rhel} < 8
Requires:       hiredis-last >= 0.13.3-1
%else
Requires:       hiredis
%endif
В данном примере мы проверяем версию системы, на которой идет сборка. Если rhel (релиз системы) меньше 8, то мы указываем в качестве требования hiredis-last. В данном примере это имеет смысл, так как в CentOS 8 пакет hiredis-last переименовали в hiredis.
%if 0%{?rhel} == 8

%endif
В данном условии мы проверяем, является ли версия релиза 8.
%if %{?osname} != «el»

%endif
Проверяем значение переменной osname. Если она не равна «el», выполняем действие.

Возможные ошибки

Рассмотрим примеры ошибко, с которыми мы можем столкнуться.

Installed (but unpackaged) file(s) found

Ошибка появляется в конце процесса сборки пакета.

Причина: обнаружены файлы, которые были установлены с помощью make install, но которые не были перечислены в %files. Таким образом, сборщик пакета не знает, что с ними делать.

Решение: секция %files должна содержать все файлы, необходимые для работы приложения. Их нужно перечислить.

Но если у нас есть полная уверенность, что мы перечислили все необходимое, а оставшиеся файлы нам ни к чему, то добавляем в файл spec:

%define _unpackaged_files_terminate_build 0

* в верхнюю часть.

Время на прочтение5 мин

Количество просмотров18K

Процесс развёртывания программ обычно состоит из множества этапов. Некоторые из этих этапов могут представлять собой довольно-таки сложные последовательности действий. В наши дни имеется широкое разнообразие инструментов, позволяющих создавать описания процессов развёртывания программ, которые можно воспроизводить на разных системах.

А именно, в мире Linux уже довольно давно существуют менеджеры пакетов. Например — это RPM и YUM. Они упрощают установку, обновление и удаление программ в Linux-системах. Собственно говоря, в этой статье я хочу рассказать о том, как создать собственный простой RPM-пакет, хочу показать, что это совсем несложно.

Надо отметить, что во многих организациях менеджеры пакетов используются лишь для установки программ, предлагаемых разработчиком используемого этими организациями дистрибутива Linux. Для управления развёртываниями собственных программ менеджеры пакетов не применяются. Тому, кто попытается собрать свой первый RPM-пакет, может показаться, что это не так уж и просто. Но обычно тот, кто учится создавать такие пакеты, тратит время с пользой. Дело в том, что соответствующие знания способны помочь ему в деле оптимизации его рабочих процессов. Здесь мы рассмотрим процесс создания RPM-пакета, содержащего простую программу, написанную на Go.

Создание пакета

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

tasks:
    - name: 'Copy the artifact'
      copy:
        src: 'my_app'
        dest: '/usr/bin/my_app'
      
    - name: 'Copy configuration files'
      template:
        src: config.json
        dest: /etc/my_app/config.json

Конечно, в плейбуках, применяющихся в реальных проектах, будет описано большее число этапов. Например, это может быть проверка ранее установленного ПО или управление сервисами. А почему бы не использовать нечто вроде следующей конструкции?

  tasks:
    - name: 'Install my_app'
      yum:
        name: 'my_app'

Теперь давайте посмотрим на наше Go-приложение. Это — простой сервер, поддерживающий работу веб-страницы. Вот код файла main.go:

package main

import (
    "encoding/json"
    "flag"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
)

type config struct {
    Text string `json:"string"`
}

func main() {

    var filename = flag.String("config", "config.json", "")
    flag.Parse()

    data, err := ioutil.ReadFile(*filename)
    if err != nil {
        log.Fatalln(err)
    }

    var config config
    err = json.Unmarshal(data, &config)

    if err != nil {
        log.Fatalln(err)
    }

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, config.Text)
    })

    log.Fatal(http.ListenAndServe(":8081", nil))

}

Вот — содержимое config.json:

{
    "string": "Hello world :)"
}

Если запустить эту программу, то, обратившись к ней, учитывая то, что сервер ожидает подключения на порту 8081, можно увидеть веб-страницу с текстом из config.json. Программа эта, конечно, далека от готовности к продакшну, но для наших экспериментов она вполне подойдёт.

Добавление сервисов

А как насчёт сервисов? Использование сервисов — это отличный способ унификации управления приложением. Поэтому создадим файл my_app.service:

[Unit]
Description=My App

[Service]
Type=simple
ExecStart=/usr/bin/my_app -config /etc/my_app/config.json

[Install]
WantedBy=multi-user.target

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

  1. Скомпилировать проект.
  2. Скопировать его в /usr/bin/my_app.
  3. Скопировать файл config.json в /etc/my_app/config.json.
  4. Скопировать my_app.service в /etc/systemd/system/.
  5. Запустить сервис.

Создание .spec-файла

RPM, что характерно и для Ansible, нуждается в файле определений, в котором описываются этапы установки программы, её зависимости, и другие действия, которые может понадобиться выполнить для установки программы на сервер:

$ sudo dnf install git
$ sudo dnf module install go-toolset
$ sudo dnf groupinstall "RPM Development Tools"

После того, как всё это установлено, мы готовы к тому, чтобы создать файл определений для пакета, известный ещё как .spec-файл:

$ rpmdev-newspec my_app.spec

Составить подобный файл может быть непросто. Нам, в деле создания этого файла, поможет утилита rpmdev-newspec. Вот его содержимое:

Name:           my_app
Version:        1.0
Release:        1%{?dist}
Summary:        A simple web app

License:        GPLv3
Source0:        %{name}-%{version}.tar.gz

BuildRequires:  golang
BuildRequires:  systemd-rpm-macros

Provides:       %{name} = %{version}

%description
A simple web app

%global debug_package %{nil}

%prep
%autosetup

%build
go build -v -o %{name}

%install
install -Dpm 0755 %{name} %{buildroot}%{_bindir}/%{name}
install -Dpm 0755 config.json %{buildroot}%{_sysconfdir}/%{name}/config.json
install -Dpm 644 %{name}.service %{buildroot}%{_unitdir}/%{name}.service

%check
# go test should be here... :)

%post
%systemd_post %{name}.service

%preun
%systemd_preun %{name}.service

%files
%dir %{_sysconfdir}/%{name}
%{_bindir}/%{name}
%{_unitdir}/%{name}.service
%config(noreplace) %{_sysconfdir}/%{name}/config.json

%changelog
* Wed May 19 2021 John Doe - 1.0-1
- First release%changelog

Тут мне хотелось бы обратить ваше внимание на несколько моментов:

  • Запись Source0 может представлять собой ссылку на репозиторий с исходным кодом. Например, она может выглядеть так: https://github.com/user/my_app/archive/v%version.tar.gz.
  • Если в Source0 используется URL, то для загрузки исходного кода приложения можно воспользоваться командой spectool -g my_app.spec.
  • Git позволяет быстро, не создавая удалённый репозиторий, генерировать tar-архивы:
    $ git archive --format=tar.gz --prefix=my_app-1.0/ -o my_app-1.0.tar.gz HEAD
    
  • Содержимое tar-архива может выглядеть примерно так, как показано ниже:
    $tar tf my_app-1.0.tar.gz 
    my_app-1.0/
    my_app-1.0/config.json
    my_app-1.0/main.go
    my_app-1.0/my_app.service
    

Сборка RPM-пакета

Первым делом нам надо создать структуру директорий rpmbuild и поместить наш tar-архив в директорию SOURCES:

$ rpmdev-setuptree
$ mv my_app-1.0.tar.gz ~/rpmbuild/SOURCES

После этого соберём RPM-пакет для Red Hat Enterprise Linux 8:

$ rpmbuild -ba my_app.spec

Вот и всё.

Теперь у нас должна появиться возможность установить RPM-пакет и запустить наш сервис:

$ sudo dnf install ~/rpmbuild/RPMS/x86_64/my_app-1.0-1.el8.x86_64.rpm
$ sudo systemctl start my_app
$ curl -L http://localhost:8081

Если всё было сделано правильно, то, выполнив вышеописанную последовательность команд, вы должны увидеть содержимое файла config.json (который, кстати, находится в папке /etc/my_app).

А что если появится новая версия нашего приложения? Как создать новый пакет для её установки? Сделать это очень просто — достаточно увеличить номер версии программы в .spec-файле и снова собрать пакет. А DNF обнаружит, что появилось обновление нашей программы.

А если вы пользуетесь репозиторием пакетов — нужно лишь выполнить команду dnf update my_app.

Итоги

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

Кроме того, существует множество восхитительных инструментов, способных помочь в деле сборки RPM-пакетов. Есть и инструменты, умеющие создавать репозитории, которыми может воспользоваться разработчик. Это, например, mock, fedpkg, COPR и Koji. Эти инструменты могут пригодиться в проектах, где реализуются сложные сценарии развёртывания ПО. Например — там, где есть множество зависимостей, где в процессе развёртывания имеются сложные этапы, или там, где нужна поддержка нескольких архитектур.

Применяете ли вы RPM-пакеты, созданные самостоятельно?

The BUILD directory is used during the build process of the RPM package. This is where the temporary files are stored, moved around, etc. The RPMS directory holds RPM packages built for different architectures and noarch if specified in . spec file or during the build.

What is RPM spec file?

The spec file, short for specification file, defines all the actions the rpmbuild command should take to build your application, as well as all the actions necessary for the rpm command to install and remove the application. Each source RPM should have the necessary spec file for building a binary RPM.

How do I create an RPM in Windows?

Building RPMs on Windows with Maven

  1. Configure RPM building in your pom (see mine for an example)
  2. Download cygwin.
  3. Run the installer, and select rpm and rpm-build as packages that you’d like to have installed.
  4. Add your Cygwin bin folder (e.g. C:\cygwin\bin) to your PATH.
  5. Rename the ‘system file’ (actually a symlink) at cygwin\bin\rpmbuild to cygwin\bin\rpmb.

How do I create an RPM spec?

To create your own RPM, you need to create your own spec file (and put it in the SPECS directory) and gather into a tarball the executables, scripts, user documentation files, and configuration files you want included in the RPM. You can create your spec file by simply copying an existing spec file and modifying it.

How do I extract an RPM?

Extract files from an RPM package’s cpio archive The rpm2cpio command will output (to stdout) a cpio archive from the RPM package. To extract the package files we’ll use the output from rpm2cpio and then use the cpio command to extract and create the files we need. The cpio command copies files to and from archives.

How do I run an RPM file?

Open/Extract RPM File on Windows

  1. Free Download Easy 7-Zip.
  2. Install Easy 7-Zip by step-by-step instructions.
  3. The installation will associate RPM with Easy 7-Zip automatically.
  4. Double-click on RPM file to open RPM file with Easy 7-Zip.
  5. Alternatively, Right-click on RPM file on Windows Explorer.
  6. Done.

How do I read an RPM?

How to Read an Rpm Gauge

  1. Look at your rpm gauge and notice that it is composed of a needle and ascending numbers from left to right.
  2. Inspect your rpm gauge to see if it has been scaled down.
  3. Multiply the number indicated by your rpm gauge needle with the proper scale if necessary.

How do I check my RPM spec?

Install rpmrebuild and “extract” (actually re-create) the spec file of your rpm file or your already installed package. There you have a website and an email address, respectively, where you could ask about a spec file or srpm file. spec files are usually not in rpm. They are in source rpm.

How can I see RPM contents without installing?

You can do this with the below rpm commands:

  1. If the rpm file available locally: [root@linux_server1 ~]# rpm -qlp telnet-0.17-48.el6.x86_64.rpm.
  2. If you want to check the contents of a rpm located in a remote repository:
  3. If you want to extract the rpm contents without installing it.

How do I list an RPM in Linux?

Linux rpm list installed packages command syntax

  1. List all installed packages using rpm -a option. Open the Terminal or login to the remote server using ssh client.
  2. Getting info about specific packages. You can display more information about package using the following command:
  3. List all files installed by the RPM package.

What is Rpmrebuild?

rpmrebuild is a tool to build easily rpm package. it can be used to build an rpm file from an installed package (lost rpm) or to quickly make change to a package: just have your change on installed files and call rpmrebuild.

How do I rebuild an RPM?

The quickest way to rebuild the SRPM is to use the rpmbuild –rebuild command. This command will unpack the SRPM file into the specfile and the source files, and then it will build the RPM from the instructions on the specfile.

How do I edit an RPM source?

Modify an srpm

  1. 1) Install rpmbuild. yum install rpmbuild.
  2. 2) Install the srpm. rpm -ivh http://server/package-1.0.1.src.rpm.
  3. 3) Unpack the tarball. cd ~/rpmbuild/SOURCE/ tar -zxf package1.0.1.tar.gz.
  4. 4) Edit the contents.
  5. 5) Re-package the files.
  6. 6) Update the spec file.
  7. 7) Build the RPM.
  8. 8) Upload the resulting RPM and SRPM.

How unpack repack rpm?

2 Answers. The best way to modify an RPM you do not have the source for is to follow these steps: Unpack the rpm into a directory with the rpm2cpio command. Make the necessary changes inside that subdirectory.

How do I open an RPM file in Windows?

How to open, view, browse, or extract RPM files?

  1. Download and install Altap Salamander 4.0 File Manager.
  2. Choose the desired file and press the F3 (View command).
  3. Press the Enter key to open archive.
  4. To view inner file using associated viewer press the F3 key (Files / View command).

How do I apply a RPM patch?

HowTo Create A Patch File For A RPM

  1. 1 Get A Base Copy Of The Original Source Tree.
  2. 2 Make a Copy of the Original Source Tree.
  3. 3 Make Changes.
  4. 4 Use diff to Create the Patch File.
  5. 5 Update the RPM Spec File to Apply the Patch.
  6. 6 Build the RPM.

Where does SRC RPM install?

For example, you can use the rpm -i command to install a source RPM. This installs the sources provided by the source RPM, not the actual application. Normally, when you install a source RPM on a Red Hat Linux system, the package gets installed into /usr/src/redhat.

How do I copy an RPM in Linux?

If you want to save a copy of the package as currently installed before upgrading or removing it, use rpm –repackage — it’ll save the RPMs in /var/tmp or /var/spool/repackage or elsewhere, depending on your configuration. Otherwise, there exists rpmrebuild , which does exactly what you ask for.

What are source RPMs?

A source RPM captures the source code and patches as they were at RPM build time. On RPM-based systems (CentOS, Red Hat Enterprise Linux, Oracle Linux, and many more) source RPMs are RPM files that contain a tarball of source code, patches, auxiliary files that are used during the build process, and a .

What is the difference between RPM and SRC RPM?

src. rpm is an rpm (RedHat Package Manager = RPM) package which has the source code of a program inside, whereas plain . rpm is an rpm package which has the binary files of a program inside.

What is source package?

The definition of a source package Source packages provide you with all of the necessary files to compile or otherwise, build the desired piece of software. It consists, in its simplest form, of three files: The upstream tarball with .tar.gz ending. A description file with . dsc ending.

What is a spec file?

Spec files are plain-text files that are used to construct spec strings. They consist of a sequence of directives separated by blank lines. The type of directive is determined by the first non-whitespace character on the line, which can be one of the following: % command. Issues a command to the spec file processor.

How do I use Pyinstaller spec?

You create a spec file using this command: pyi-makespec options name.py [other scripts …] The options are the same options documented above for the pyinstaller command. This command creates the name….Each tuple has three elements:

  1. The option as a string, for example v or W ignore .
  2. None.
  3. The string OPTION.

How do you spec a file?

2.2. 1. Creating an Example Spec File for eject

  1. In a shell prompt, go into the buildroot and create a new spec file for your package.
  2. Open the spec file in a text editor.
  3. Edit the Release tag to set the release value of the package.
  4. Fill in the version and add a summary of the software:

What is a spec testing?

RSpec is a testing tool for Ruby, created for behavior-driven development (BDD). It is the most frequently used testing library for Ruby in production applications. Even though it has a very rich and powerful DSL (domain-specific language), at its core it is a simple tool which you can start using rather quickly.

What makes a good test specification?

Easy to understand A good specification is a specification that isn’t ambiguous. It is also including. Including also implies that the reader should not have to learn a special skill, such as programming, to be able to understand the specification. The language must be as natural as possible.

What is spec in Jasmine?

Specs. Specs are defined by calling the global Jasmine function it, which, like describe takes a string and a function. The string is the title of the spec and the function is the spec, or test. An expectation in Jasmine is an assertion that is either true or false. A spec with all true expectations is a passing spec.

What is a spec JS?

Use of spec. js is for writing you unit test cases for your angular application. We write test cases in angular using Jasmine & Karma. Jasmine is a Behavior Driven Development testing framework for JavaScript. It does not rely on browsers, DOM, or any JavaScript framework.

Понравилась статья? Поделить с друзьями:
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
  • Открыть диспетчер печати windows 10
  • Как подключиться к vds серверу на windows
  • Wxwidgets install on windows
  • Как на убунту записать образ windows на флешку
  • Как открыть виртуальную клавиатуру на windows 10 горячие клавиши