rpm本地打包之spec文件(linux)

rpm本地打包之spec文件(linux)

rpm本地打包的回顧

  • Linux之rpm本地打包中分析了rpm的常用指令、rpmbuild的常用命令以及參數的配置說明,詳細情況請進入鏈接詳細查看。接下來重點是分析spec文件。

spec文件

  • 能夠熟悉在以上鍊接中的操作命令以及配置參數的含義,管理日常的rpm軟件包也就不成問題了。
  • 然而,隨着linux操作系統越來越流行於世界各地,越來越多的開發者更喜歡採用RPM格式來發布自己的軟件包。那麼RPM軟件包是怎麼樣製作的了?對於大多數的開發者來說還是比較陌生的。
  • 其實,製作RPM軟件包並不是一件複雜的工作,其中最爲關鍵在於編寫SPEC軟件包描述文件。要想製作一個rpm軟件包就必須寫一個軟件包描述文件(SPEC)。這個文件中包含了軟件包的諸多信息,如軟件包的名字、版本、類別、說明摘要、創建時要執行什麼指令、安裝時要執行什麼操作、以及軟件包所要包含的文件列表等等。

  • 描述文件如下:

文件頭:

  • 一般的spec文件頭包含以下幾個域:

Name:

  • 軟件包的名字,最終RPM軟件包是用該名字與版本號,釋出號及體系號來命名軟件包的。

Name(example):

Name:   python-django-horizon

Epoch:

  • 軟件包的系列,也就是軟件包的體系號,表示軟件包的系列

Epoch(example):

Epoch:  1

Version:

  • 軟件包的版本號。僅當軟件包比以前有較大改變時才增加版本號。

Version(example):

Version:    4.0.2

Release:

  • 軟件包釋出號。一般我們對該軟件包做一些小的補丁的時候就應該釋出號出1。

Relase(example):

Release:    4.0.2

注意: 其中Epoch:Version:Release表示了rpm包的新舊,優先級依次降低,打出的rpm包也是以${package}-${Version}-${Release}命名

Summary:

  • 一句話概括該軟件包儘量多的信息。

Summary(example):

Summary:    Django application for talking to Openstack

Group:

  • 軟件包所屬類別,具體類別有:
    • Amusements/Games (娛樂/遊戲)
    • Amusements/Graphics(娛樂/圖形)
    • Applications/Archiving (應用/文檔)
    • Applications/Communications(應用/通訊)
    • Applications/Databases (應用/數據庫)
    • Applications/Editors (應用/編輯器)
    • Applications/Emulators (應用/仿真器)
    • Applications/Engineering (應用/工程)
    • Applications/File (應用/文件)
    • Applications/Internet (應用/因特網)
    • Applications/Multimedia(應用/多媒體)
    • Applications/Productivity (應用/產品)
    • Applications/Publishing(應用/印刷)
    • Applications/System(應用/系統)
    • Applications/Text (應用/文本)
    • Development/Debuggers (開發/調試器)
    • Development/Languages (開發/語言)
    • Development/Libraries (開發/函數庫)
    • Development/System (開發/系統)
    • Development/Tools (開發/工具)
    • Documentation (文檔)
    • System Environment/Base(系統環境/基礎)
    • System Environment/Daemons (系統環境/守護)
    • System Environment/Kernel (系統環境/內核)
    • System Environment/Libraries (系統環境/函數庫)
    • System Environment/Shells (系統環境/接口)
    • User Interface/Desktops(用戶界面/桌面)
    • User Interface/X (用戶界面/X窗口)
    • User Interface/X Hardware Support (用戶界面/X硬件支持)

Group(example):

Group:      Development/Libraries

License:

  • 軟件包的發行許可證,也就是軟件的授權方式,通常是GPL。

License(example)

# Code in horizon/horizon/utils taken from django which is BSD
License:    ASL 2.0 and BSD

URL:

  • rpm軟件包的主頁鏈接地址。

URL(example):

URL:        http://horizon.openstack.org/

Source:

  • 源程序軟件包的名稱。例如:horizon-9.0.1.tar.gz
    注意: Source[0-n]是rpm軟件包打包時的源代碼

Source(example):

Source0:    https://tarballs.openstack.org/horizon/horizon-%{upstream_version}.tar.gz
Source2:    openstack-dashboard-httpd-2.4.conf
Source3:    python-django-horizon-systemd.conf

# demo config for separate logging
Source4:    openstack-dashboard-httpd-logging.conf

# logrotate config
Source5:    python-django-horizon-logrotate.conf

BuildArch:

  • 指編譯的目標處理器架構,noarch標識不指定,但通常都是以/usr/lib/rpm/marcros中的內容爲默認值。

BuildArch(example):

BuildArch:  noarch

BuildRequires:

  • rpm軟件包構建過程中所依賴的軟件包名稱,可以使用>=或者<=表示大於或者小於某一特定版本。

BuildRequires(example):

BuildRequires: python-setuptools
BuildRequires: python-pbr >= 2.0.0
BuildRequires: git
BuildRequires: python-six >= 1.10.0
BuildRequires: gettext

Requires:

  • rpm軟件包所依賴的軟件包名稱,可以使用>=或者<=表示大於或者小於某一特定版本。

Requires(example):

Requires:   python-django
Requires:   pytz
Requires:   python-six >= 1.10.0
Requires:   python-pbr

Provides:

  • 指明rpm軟件包提供一些特定的功能,以便其他rpm識別。

Provides(example):

# additional provides to be consistent with other django packages
Provides: django-horizon = %{epoch}:%{version}-%{release}

Obsoletes:

  • 過時的,廢棄的軟件包

Obsoletes(example):

Obsoletes: python-django-openstack-auth < 4.0.0-1
Obsoletes: python2-django-openstack-auth < 4.0.0-1

%description:

  • rpm軟件包的詳細說明。

%description(example):

%description
Horizon is a Django application for providing Openstack UI components.
It allows performing site administrator (viewing account resource usage,
configuring users, accounts, quotas, flavors, etc.) and end user
operations (start/stop/delete instances, create/restore snapshots, view
instance VNC console, etc.)

%package:

  • 定義一個子包

%package(example):

%package -n openstack-dashboard
Summary:    Openstack web user interface reference implementation
Group:      Applications/System

Requires:   httpd

%description doc
Documentation for the Django Horizon application for talking with Openstack

%files段:

  • 本段是文件段,用於定義軟件包所包含的文件,分爲三類–說明文檔(doc),配置文件(config)及執行程序,還可定義文件存取權限,擁有者及組別。

%files段(example):

%files -n openstack-dashboard -f dashboard.lang
...

注意: 當需要去定義一個子包時,必須至少包含Summary;Group;%description選項,任何沒有指定的選項將使用父包的選項,如版本等。
%package -n openstack-dashboard表示定義一個子包,子包的名稱是openstack-dashboard
如果在%package中使用了-n選項,那麼在使用%description時也要加上,如: %package -n openstack-dashboard以及它的%description -n openstack-dashboard
如果在%package中使用了-n選項,那麼在使用%files時也要加上,如:%package -n openstack-dashboard以及它的%files -n openstack-dashboard -f dashboard.lang

%prep段:

  • 這個段是預處理段,通常用來執行一些解開源程序包的命令,爲下一步的編譯安裝作準備。%prep和下面的%build,%install段一樣,除了可以執行RPM所定義的宏命令(以%開頭)以外,還可以執行SHELL命令,命令可以有很多行,如我們常寫的tar解包命令。

%prep段(example):

%prep
%autosetup -n horizon-%{upstream_version} -S git
# drop config snippet
cp -p %{SOURCE4} .

# customize default settings
# WAS [PATCH] disable debug, move web root
sed -i "/^DEBUG =.*/c\DEBUG = False" openstack_dashboard/local/local_settings.py.example
sed -i "/^WEBROOT =.*/c\WEBROOT = '/dashboard/'" openstack_dashboard/local/local_settings.py.example
sed -i "/^.*ALLOWED_HOSTS =.*/c\ALLOWED_HOSTS = ['horizon.example.com', 'localhost']" openstack_dashboard/local/local_settings.py.example
sed -i "/^.*LOCAL_PATH =.*/c\LOCAL_PATH = '/tmp'" openstack_dashboard/local/local_settings.py.example
sed -i "/^.*POLICY_FILES_PATH =.*/c\POLICY_FILES_PATH = '/etc/openstack-dashboard'" openstack_dashboard/local/local_settings.py.example

sed -i "/^BIN_DIR = .*/c\BIN_DIR = '/usr/bin'" openstack_dashboard/settings.py
sed -i "/^COMPRESS_PARSER = .*/a COMPRESS_OFFLINE = True" openstack_dashboard/settings.py

# set COMPRESS_OFFLINE=True
sed -i 's:COMPRESS_OFFLINE.=.False:COMPRESS_OFFLINE = True:' openstack_dashboard/settings.py

%build段:

  • 本段是建立段,所要執行的命令爲生成軟件包服務,如make 命令。

%build段(example):

%build
# compile message strings
cd horizon && django-admin compilemessages && cd ..
cd openstack_dashboard && django-admin compilemessages && cd ..
# Dist tarball is missing .mo files so they're not listed in distributed egg metadata.
# Removing egg-info and letting PBR regenerate it was working around that issue
# but PBR cannot regenerate complete SOURCES.txt so some other files wont't get installed.
# Further reading why not remove upstream egg metadata:
# https://github.com/emonty/python-oslo-messaging/commit/f632684eb2d582253601e8da7ffdb8e55396e924
# https://fedorahosted.org/fpc/ticket/488
echo >> horizon.egg-info/SOURCES.txt
ls */locale/*/LC_MESSAGES/django*mo >> horizon.egg-info/SOURCES.txt
%{__python} setup.py build

# compress css, js etc.
cp openstack_dashboard/local/local_settings.py.example openstack_dashboard/local/local_settings.py
# get it ready for compressing later in puppet-horizon
%{__python} manage.py collectstatic --noinput --clear
%{__python} manage.py compress --force


# build docs
export PYTHONPATH=.
sphinx-build -b html doc/source html

# undo hack
cp openstack_dashboard/local/local_settings.py.example openstack_dashboard/local/local_settings.py

# Fix hidden-file-or-dir warnings
rm -fr html/.doctrees html/.buildinfo

%install段:

  • 本段是安裝段,其中的命令在安裝軟件包時將執行,如make install命令。

%install段(example):

%install
%{__python} setup.py install -O1 --skip-build --root %{buildroot}

# drop httpd-conf snippet
install -m 0644 -D -p %{SOURCE2} %{buildroot}%{_sysconfdir}/httpd/conf.d/openstack-dashboard.conf
install -d -m 755 %{buildroot}%{_datadir}/openstack-dashboard
install -d -m 755 %{buildroot}%{_sharedstatedir}/openstack-dashboard
install -d -m 755 %{buildroot}%{_sysconfdir}/openstack-dashboard

# create directory for systemd snippet
mkdir -p %{buildroot}%{_unitdir}/httpd.service.d/
cp %{SOURCE3} %{buildroot}%{_unitdir}/httpd.service.d/openstack-dashboard.conf


# Copy everything to /usr/share
mv %{buildroot}%{python_sitelib}/openstack_dashboard \
   %{buildroot}%{_datadir}/openstack-dashboard
cp manage.py %{buildroot}%{_datadir}/openstack-dashboard
rm -rf %{buildroot}%{python_sitelib}/openstack_dashboard

# remove unnecessary .po files
find %{buildroot} -name django.po -exec rm '{}' \;
find %{buildroot} -name djangojs.po -exec rm '{}' \;

# Move config to /etc, symlink it back to /usr/share
mv %{buildroot}%{_datadir}/openstack-dashboard/openstack_dashboard/local/local_settings.py.example %{buildroot}%{_sysconfdir}/openstack-dashboard/local_settings
ln -s ../../../../..%{_sysconfdir}/openstack-dashboard/local_settings %{buildroot}%{_datadir}/openstack-dashboard/openstack_dashboard/local/local_settings.py

mv %{buildroot}%{_datadir}/openstack-dashboard/openstack_dashboard/conf/*.json %{buildroot}%{_sysconfdir}/openstack-dashboard
mv %{buildroot}%{_datadir}/openstack-dashboard/openstack_dashboard/conf/cinder_policy.d %{buildroot}%{_sysconfdir}/openstack-dashboard
mv %{buildroot}%{_datadir}/openstack-dashboard/openstack_dashboard/conf/nova_policy.d %{buildroot}%{_sysconfdir}/openstack-dashboard

%find_lang django --all-name

grep "\/usr\/share\/openstack-dashboard" django.lang > dashboard.lang
grep "\/site-packages\/horizon" django.lang > horizon.lang

# copy static files to %{_datadir}/openstack-dashboard/static
mkdir -p %{buildroot}%{_datadir}/openstack-dashboard/static
cp -a openstack_dashboard/static/* %{buildroot}%{_datadir}/openstack-dashboard/static
cp -a horizon/static/* %{buildroot}%{_datadir}/openstack-dashboard/static
cp -a static/* %{buildroot}%{_datadir}/openstack-dashboard/static

# create /var/run/openstack-dashboard/ and own it
mkdir -p %{buildroot}%{_sharedstatedir}/openstack-dashboard

# create /var/log/horizon and own it
mkdir -p %{buildroot}%{_var}/log/horizon

# place logrotate config:
mkdir -p %{buildroot}%{_sysconfdir}/logrotate.d
cp -a %{SOURCE5} %{buildroot}%{_sysconfdir}/logrotate.d/openstack-dashboard

需要特別注意的是:%install部分使用的是絕對路徑,而%files使用的則是相對路徑,雖然描述的是同一個地方,但是路徑的書寫格式千萬不要出錯
%files -n openstack-dashboard -f dashboard.lang中的-f dashboard.lang分析: 生成一個名爲dashboard.lang的文件,內容是所有的dashboard.mo-f參數是將其後邊接的文件合併到%files的文件列表。
開始把軟件安裝到虛擬的根目錄中,本段是安裝段,其中的命令在安裝軟件包時將執行,如: make install命令、cp、mv、install、ln。

%check段:

  • rpm軟件包的測試。

%check段(example):

%check
%{__python2} manage.py test horizon --settings=horizon.test.settings

%post段:

  • rpm軟件包安裝之後執行的腳本。

%post段(example):

%post -n openstack-dashboard
# ugly hack to set a unique SECRET_KEY
sed -i "/^from horizon.utils import secret_key$/d" /etc/openstack-dashboard/local_settings
sed -i "/^SECRET_KEY.*$/{N;s/^.*$/SECRET_KEY='`openssl rand -hex 10`'/}" /etc/openstack-dashboard/local_settings
# reload systemd unit files
systemctl daemon-reload >/dev/null 2>&1 || :

%postun段:

  • rpm軟件包卸載之後執行的腳本。

%postun段(example):

%postun
# update systemd unit files
%{systemd_postun}

課外知識: rpm還提供了一種信號機制:不同的操作會返回不同的信息,並放到默認變量$1中。
引用
0代表卸載,1代表安裝,2代表升級

%doc段:

  • 表示這是文檔文件,因此如果安裝時使用--excludedocs將不會安裝此類文件。

%doc段(example):

%doc README.rst openstack-dashboard-httpd-logging.conf

%dir段:

  • 表示將dir目錄路徑下的內容打進rpm軟件包裏。

%dir段(example):

%dir %{_datadir}/openstack-dashboard/

%config(noreplace):

  • 該配置文件不會覆蓋已經存在文件(RPM包中文件會以.rpmnew存在於系統,卸載時系統中的該配置文件會以.rpmsave保存下來,如果沒有這個選項,安裝時RPM包中文件會以.rpmorig存在於系統)覆蓋已經存在文件(沒被修改),創建新的文件加上擴展後綴.rpmnew(被修改)。

%config(noreplace):

%config(noreplace) %{_sysconfdir}/httpd/conf.d/openstack-dashboard.conf
...

%attr(mode, user, group) filename

  • 控制文件權限

%attr(mode, user, group) filename(example):

%dir %attr(0750, root, apache) %{_sysconfdir}/openstack-dashboard
%dir %attr(0750, root, apache) %{_sysconfdir}/openstack-dashboard/cinder_policy.d/
%dir %attr(0750, apache, apache) %{_sharedstatedir}/openstack-dashboard
%dir %attr(0750, apache, apache) %{_var}/log/horizon

%changelog段:

  • 本段是修改日誌段。你可以將軟件的每次修改記錄到這裏,保存到發佈的軟件包中,以便查詢之用。每一個修改日誌都有這樣一種格式:第一行是:* 星期 月 日 年 修改人 電子信箱。其中:星期、月份均用英文形式的前3個字母,用中文會報錯。接下來的行寫的是修改了什麼地方,可寫多行。一般以減號開始,便於後續的查閱。

%changelog段(example):

%changelog

宏定義字段

%{_sysconfdir} /etc
%{_prefix} /usr
...
  • 所有的宏定義都可以在/usr/lib/rpm/macros中進行查看。

JackDan Thinking

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章