`
netcome
  • 浏览: 482441 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

用 RPM 打包软件,第 3 部分

rpm 
阅读更多

安装和卸载脚本的工作原理

安装和卸载脚本看起来很简单,但它们工作原理中的一些意外可能会引起大问题。

这里是一些基本信息。可以将下列四节中的任意一个添加到 .spec 文件, 它列出了在您的包安装期间各个点上运行的 shell 脚本:

%pre
在安装包之前运行
%post
在安装包之后运行
%preun
在卸载包之前运行
%postun
在卸载包之后运行

尤其要注意 %install 与这些节之间的差异。构建 RPM 时, %install 在开发机器上运行; 它应该将产品安装在开发机器上或安装到一个构建根目录中。 另一方面,这些节指定当用户正在安装或卸载您的 RPM 包时将在 用户的机器上运行什么。

这里有一个示例,是在前文基础上建立的。我们要使用 install-info 将 GNU indent 的 info 文件添加到目录中。


清单 1. indent-4.spec
# Simplistic example of install scripts - do not use
Summary: GNU indent
Name: indent
Version: 2.2.6
        
          Release: 4
        
Source0: %{name}-%{version}.tar.gz
License: GPL
Group: Development/Tools
BuildRoot: %{_builddir}/%{name}-root
%description
The GNU indent program reformats C code to any of a variety of
formatting standards, or you can define your own.
%prep
%setup -q
%build
./configure
make
%install
rm -rf $RPM_BUILD_ROOT
make DESTDIR=$RPM_BUILD_ROOT install
        
          %post
        
if [ -x /sbin/install-info ]; then
  /sbin/install-info /usr/local/info/indent.info /usr/local/info/dir
fi
%preun
if [ -x /sbin/install-info ]; then
  /sbin/install-info --delete /usr/local/info/indent.info /usr/local/info/dir
fi
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
/usr/local/bin/indent
%doc /usr/local/info/indent.info
%doc %attr(0444,root,root) /usr/local/man/man1/indent.1
%doc COPYING AUTHORS README NEWS
      

请注意,在尝试使用 install-info 工具之前,首先对它进行检查。我们不希望只是因为我们不能提供至产品文档的链接而使安装失败。

但也有可能在某种情况下您希望安装过程失败。一种好的技术是使用 %pre 脚本来检查安装前提条件,它们比 RPM 可以直接支持的更复杂。 如果不符合前提条件,那么脚本以非零状态退出,而且 RPM 不会继续安装。

另外请注意,我们必须小心地使用卸载脚本来撤销安装脚本。

没有那么简单:升级使每件事情都变得复杂

现在,让我们着手升级。如果用户只安装和删除您自己的包,那么前面节中的指令将正常工作;但在升级期间,它们会完全失效。

以下是 RPM 如何执行升级:

  • 运行新包的 %pre
  • 安装新文件
  • 运行新包的 %post
  • 运行旧包的 %preun
  • 删除新文件未覆盖的所有旧文件
  • 运行旧包的 %postun

如果我们使用前面的示例来升级,那么 RPM 最后将运行 %postun 脚本, 它将除去我们在安装脚本中所做的所有工作!使用 RPM 的一般开发人员可能不会想到这一点。 我不会尝试解释其原因,只是解释您必须为此做点什么。

相当幸运的是,在一定程度上,脚本有一种方法可以告之是否正在安装、删除或升级包。每个脚本都被传递单一命令行参数 ― 一个数字。 这应该告诉脚本 在当前包完成安装或卸载之后将安装多少个包的副本

只查看在各种情况下传递的值或许更容易,而不是尝试计算它。

这里是在安装期间传递的实际值:

  • 运行新包的 %pre (1)
  • 安装新文件
  • 运行新包的 %post (1)

这里是在升级期间传递的值:

  • 运行新包的 %pre (2)
  • 安装新文件
  • 运行新包的 %post (2)
  • 运行旧包的 %preun (1)
  • 删除新文件未覆盖的任何旧文件
  • 运行旧包的 %postun (1)

这里是在删除期间传递的值:

  • 运行旧包的 %preun (0)
  • 删除文件
  • 运行旧包的 %postun (0)

可以通过将类似下例的一些东西添加到您的包中来自己测试它。 然后创建一个带稍高发行版号的新包,安装第一个,然后升级到第二个,最后卸载它,以查看所有可能性。 当然,在信任的公共社区上发布任何 RPM 之前,您总是要对它进行几次这样的尝试。


清单 2. 脚本执行的测试顺序和参数
%pre
echo This is pre for %{version}-%{release}: arg=$1
%post
echo This is post for %{version}-%{release}: arg=$1
%preun
echo This is preun for %{version}-%{release}: arg=$1
%postun
echo This is postun for %{version}-%{release}: arg=$1

这里是另一个示例,这次正确地处理升级过程:


清单 3. indent-5.spec
Summary: GNU indent
Name: indent
Version: 2.2.6
        
          Release: 5
        
Source0: %{name}-%{version}.tar.gz
License: GPL
Group: Development/Tools
BuildRoot: %{_builddir}/%{name}-root
%description
The GNU indent program reformats C code to any of a variety of
formatting standards, or you can define your own.
%prep
%setup -q
%build
./configure
make
%install
rm -rf $RPM_BUILD_ROOT
make DESTDIR=$RPM_BUILD_ROOT install
%post
        
          if [ "$1" = "1" ] ; then  # first install
        
 if [ -x /sbin/install-info ]; then
   /sbin/install-info /usr/local/info/indent.info /usr/local/info/dir
 fi
        
          fi
        
%preun
        
          if [ "$1" = "0" ] ; then # last uninstall
        
 if [ -x /sbin/install-info ]; then
   /sbin/install-info --delete /usr/local/info/indent.info /usr/local/info/dir
 fi
        
          fi
        
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
/usr/local/bin/indent
%doc /usr/local/info/indent.info
%doc %attr(0444,root,root) /usr/local/man/man1/indent.1
%doc COPYING AUTHORS README NEWS
      

现在,仅当完全删除这个包时才会除去 info 链接。

触发器 — 在安装或卸载其它包时运行脚本

假设在安装或卸载 其它包时要运行您包中的一些代码。 可以用 触发器(trigger)脚本来完成这一任务。

您为什么要这样做?通常是因为您的包使用一个或多个其它包的服务,或者提供服务给一个或多个其它包。

这里有一个示例。假设您正在为 Emacs 和 Xemacs 编辑器打包一个极好的附加工具。它可以与其中任何一个或两个编辑器一起工作, 但根据所安装的编辑器,需要做一些少量的配置。

安装时,可以对 Emacs 和 Xemacs 进行测试,并配置您的工具以使可用编辑器可以访问它。 但是,如果用户稍后安装 Xemacs,那么会发生什么情况呢?您的工具在 Xemacs 中不可用,除非用户卸载并重新安装您的工具。 如果您的包可以告诉 RPM,“让我知道是否安装了 Xemacs”,这是否会更好呢?

这是触发器脚本的思想。可以将它添加到 .spec 文件中:


清单 4. 触发器示例
%triggerin -- emacs
# Insert code here to run if your package is already installed,
# then emacs is installed,
# OR if emacs is already installed, then your package is installed
%triggerin -- xemacs
# Insert code here to run if your package is already installed,
# then xemacs is installed,
# OR if xemacs is already installed, then your package is installed
%triggerun -- emacs
# insert code here to run if your package is already installed,
# then emacs is uninstalled
%triggerun -- xemacs
# insert code here to run if your package is already installed,
# then xemacs is uninstalled
%postun
# Insert code here to run if your package is uninstalled

触发器脚本被传递了 两个参数。第一个参数是当触发器脚本完成运行时将安装的 您的包的实例数。第二个参数是当触发器脚本完成运行时将安装的 要触发的包的实例数。

这里是 RPM 升级期间脚本执行和文件安装及卸载的完整顺序,它来自 RPM 分发版中的 triggers 文件:


清单 5. 脚本顺序
 new-%pre  for new version of package being installed
  ...       (all new files are installed)
  new-%post for new version of package being installed
  any-%triggerin (%triggerin from other packages set off by new install)
  new-%triggerin
  old-%triggerun
  any-%triggerun (%triggerun from other packages set off by old uninstall)
  old-%preun    for old version of package being removed
  ...       (all old files are removed)
  old-%postun   for old version of package being removed
  old-%triggerpostun
  any-%triggerpostun (%triggerpostun from other packages set off by old un
        install)

高级脚本编制

备用解释器

通常,所有安装时脚本和触发器脚本都是使用 /bin/sh shell 程序运行的。如果您更喜欢另一个脚本语言,比方说 Perl,那么可以通过将 -p interpreter 添加到脚本行来告诉 RPM 应该使用另一种解释器运行您的脚本。例如:


清单 6. 备用解释器示例
%post -p /usr/bin/perl
# Perl script here
%triggerun -p /usr/bin/perl -- xemacs
# Another Perl script here

请注意,这 适用于 RPM 的构建时脚本,如 %install 。

RPM 变量

RPM 在将 RPM 变量存储到 RPM 包文件之前先在您的脚本中扩充它们,有时候这是有用的。 例如,可以在 .spec 文件顶部附近定义您自己的参数,然后在整个 .spec 文件 ― 甚至在您的脚本中使用 %{variable_name} 引用它们:


清单 7. RPM 变量示例
...
%define foo_dir /usr/lib/foo
...
%install
cp install.time.message $RPM_BUILD_ROOT/%{foo_dir}
%files
%{foo_dir}/install.time.message
%post
/bin/cat %{foo_dir}/install.time.message

要避免的事情

您可能会在安装时试图做一些事情,但结果会证明这是一个坏主意。 例如,与用户交互的任何尝试或许不能很好地工作。RPM 被设计成在无需用户出现的情况下允许进行批处理安装。 如果在安装期间 RPM 包停下来并提出问题,而没有人看到这个问题,那么安装将一直挂起。

您可能要避免的另一件事情是启动任何服务。 在完整安装期间,您不能确定程序所需的每样东西是否已经在那里(例如,可能还没有任何网络); 另外,如果在完整操作系统安装期间每个 RPM 服务都尝试启动,那么整个安装过程大概会花很长时间。 这种情况下您可以做的就是打印消息,告诉用户有关任何所需配置或需要启动的服务的信息。 如果用户正在手工安装您的 RPM 包, 那么他或她将看到这些消息;如果它是较大批处理安装的一部分,那么它不会损害任何东西, 机器几乎肯定在结束时重新引导,启动您的服务。

要记住的事情

如果您的包安装了 init 脚本,则可以使用 chkconfig 来安排将在适当运行级别上启动和停止的服务。 虽然可以通过将必需的符号链接直接安装为包的一部分来实现同一件事情, 但要使它们恢复正常会有很多麻烦,您可能宁愿使用 chkconfig 。

为了安全起见,许多服务在一个特定的用户标识下运行; 如果您的服务是这样的话,当系统上不存在该用户时,您需要在系统上创建它。

如果您的包安装了任何 GNU info 文件,那么在 Info 目录中将看不到它们,除非在安装时使用 install-info 工具添加它们。

当然,在卸载之前,必须试图停止您的包可能正在运行的任何服务(但如果服务不在运行,请确保卸载不会失败)。

当然,在卸载时,应该将您在安装时可能对系统做的大多数更改恢复成原来状态。 但稍微考虑一下您的操作;例如,卸载 RPM 包时不应该意外地删除任何用户创建的文件。 所以,请不要尝试除去用户标识或删除整个目录树,这样可能会好一些。

分享到:
评论

相关推荐

    RPM打包全过程SPEC详解

    SPEC文件是RPM打包的核心,它包含关于软件包的所有信息,如版本、作者、依赖关系以及如何构建和安装软件的指令。 **2. 创建SPEC文件** 创建SPEC文件通常以`.spec`为扩展名,用文本编辑器打开并按照RPM的规范编写。...

    java 打包rpm打包文档.zip

    将SpringBoot应用打包成RPM,首先需要编写一个spec文件,这是RPM打包的核心配置文件,它定义了软件包的元数据、依赖关系、安装和卸载时执行的脚本等。 3. **创建spec文件** 在spec文件中,你需要指定版本信息、源...

    RPM打包和典型SPEC文件分析

    RPM打包过程主要分为两个部分:第一部分是编写SPEC文件,第二部分是通过rpmbuild命令根据SPEC文件构建出最终的RPM包。SPEC文件通常包含以下几个主要部分: 1. 宏定义区域:这通常在SPEC文件的开头部分,用于定义...

    rhl rpm打包原理详解

    RPM打包原理详解主要涉及如何创建自己的RPM软件包,以便在这些系统中方便地安装、升级和管理软件。本篇文章将深入探讨RPM打包的各个方面。 1. RPM基础知识: - **RPM结构**:RPM软件包由元数据和软件内容两部分...

    Hadoop生态圈常用软件打包rpm spec描述文件

    在Hadoop生态圈中,为了在Linux环境中方便管理和部署组件,如Hadoop、Spark、Alluxio、Ranger等,都会使用RPM打包技术。 `spec`文件是RPM打包的核心,它由一系列的指令和宏组成,用于指导编译、安装和配置过程。...

    Rpm打包原理详解.doc

    RPM打包是一种在Linux系统中广泛使用的软件管理方式,它允许用户方便地安装、升级和卸载软件。RPM打包不仅仅是简单的将软件压缩,而是包含了完整的安装流程,包括菜单创建、依赖处理、预配置、打补丁等功能。这种...

    RPM和DEB软件包打包教程.doc

    3. **RPM打包** 打包完成后,spec文件会指导RPM构建过程。使用`rpmbuild`命令进行打包,例如:`rpmbuild -bb SPECS/demo-1.0.0.spec`。 4. **RPM软件的安装、升级、卸载** - 安装:`rpm -ivh <包全名>.rpm` - ...

    RPM打包技术与典型SPEC文件分析

    RPM打包技术是Linux系统中广泛使用的一种软件包管理方式,它使得软件的安装、升级和卸载变得简便易行。RPM(Red Hat Package Manager)最初由Red Hat公司开发,但现在已被许多其他Linux发行版采纳。在RPM打包过程中...

    CentOS系统rpm打包简易教程

    在Linux环境中,尤其是Red Hat系列的系统,如CentOS,RPM(Red Hat Package Manager)是一种广泛使用的软件包管理器,它使得安装、升级和卸载软件变得非常便捷。`rpm`命令是RPM系统的核心,它能处理预编译的RPM...

    rpm package guide

    文档的第一部分是关于RPM打包者指南的介绍,这部分内容适用于那些对RPM打包有兴趣的初学者,或者由于工作原因需要了解如何打包RPM包的人。在这部分中,如果读者已经熟悉源代码以及如何将源代码编译或构建为软件,...

    6.6: 版本控制 、 Git基础 、 Git进阶 、 RPM打包 、 总结和答疑.docx

    总结和答疑部分可能会涵盖上述操作中遇到的问题及解决方案,包括但不限于权限问题、冲突解决、RPM打包过程中的错误等。对于初学者,理解并熟练掌握这些基本操作是成为Git高手的第一步,而深入理解和运用Git的高级...

    用rpmbuilder打rpm包

    在Linux系统中,RPM(Red Hat Package Manager)是一种广泛使用的软件包管理器,用于安装、升级、查询和卸载软件。RPM包是遵循RPM格式的软件包,它们通常用于Fedora、CentOS、RHEL等基于RPM的Linux发行版。`rpmbuild...

    gcc、openssl rpm文件包

    RPM文件是为这些系统打包的软件,包含了软件本身以及元数据,如软件描述、依赖关系、权限设置等。通过RPM,用户可以方便地安装、升级、查询和卸载软件,同时RPM会处理软件的依赖性问题,确保安装的软件能正常运行。 ...

    rpm-hello_0.1.zip

    在这个场景中,我们讨论的是如何使用RPM来创建一个"Hello World"包,这通常作为学习RPM打包过程的入门实践。 标题"rpm-hello_0.1.zip"暗示了这是一个名为"hello"的软件包,版本为0.1,以ZIP格式压缩。ZIP是一种常见...

    jdk8安装包rpm,jdk8安装包rpm

    RPM包将所有依赖关系、元数据和软件文件打包在一起,简化了软件的管理和维护。 **三、JDK 8 RPM安装步骤** 1. **下载JDK RPM包**:在描述中提到的文件名为`jdk-8u131-linux-x64.rpm`,这表示是适用于64位Linux系统...

    hello程序的rpm包

    标题中的“hello程序的rpm包”指的是一个用RPM格式打包的“hello”程序,这通常是一个简单的示例程序,用于向用户介绍如何创建和管理RPM包。 【描述】:...

    ant rpm

    通过分析这个文件,你可以了解博主是如何使用Ant进行RPM打包的具体实现。 总结来说,"ant rpm"涉及的知识点有: - Apache Ant工具的使用 - RPM包管理格式和Linux软件分发 - Ant构建文件(build.xml)的编写 - Ant的...

    ARM架构和X86_64架构rpmbuild制作openssh和openssl的rpm包

    `rpmbuild`是RPM打包系统的一部分,用于创建符合RPM规范的软件包。RPM(Red Hat Package Manager)是一种广泛应用于Linux发行版的软件包管理器,它能方便地安装、升级和卸载软件。`rpmbuild`提供了命令行接口,使得...

    openssh7.8p1RPM包

    OpenSSH 7.8p1 RPM包则是将OpenSSH软件打包成RPM格式,便于在支持RPM的系统,如CentOS 7上快速安装和管理。 三、如何在CentOS7上安装OpenSSH 7.8p1 RPM包 1. 下载RPM包:首先,你需要从可靠源下载这个自制的...

    gcc离线RPM安装包

    RPM是一种流行的Linux软件打包格式,它包含了软件的所有组件、元数据和依赖关系。在离线环境中安装RPM包,通常需要先下载所有必要的RPM文件,然后在目标系统上运行上述命令进行安装。这种方式适用于那些无法连接到...

Global site tag (gtag.js) - Google Analytics