mirror of
https://github.com/LCTT/TranslateProject.git
synced 2024-12-26 21:30:55 +08:00
commit
0e02bb7dd9
@ -1,38 +1,36 @@
|
||||
坚实的 React 基础:初学者指南
|
||||
============================================================
|
||||
============
|
||||
|
||||
![](https://cdn-images-1.medium.com/max/1000/1*wj5ujzj5wPQIKb0mIWLgNQ.png)
|
||||
React.js crash course
|
||||
|
||||
*React.js crash course*
|
||||
|
||||
在过去的几个月里,我一直在使用 React 和 React-Native。我已经发布了两个作为产品的应用, [Kiven Aa][1](React)和 [Pollen Chat][2](React Native)。当我开始学习 React 时,我找了一些不仅仅是教我如何用 React 写应用的东西(一个博客,一个视频,一个课程,等等),我也想让它帮我做好面试准备。
|
||||
|
||||
我发现的大部分资料都集中在某一单一方面上。所以,这篇文章针对的是那些希望理论与实践完美结合的观众。我会告诉你一些理论,以便你了解幕后发生的事情,然后我会向你展示如何编写一些 React.js 代码。
|
||||
|
||||
如果你更喜欢视频形式,我在YouTube上传了整个课程,请去看看。
|
||||
|
||||
如果你更喜欢视频形式,我在 [YouTube][https://youtu.be/WJ6PgzI16I4] 上传了整个课程,请去看看。
|
||||
|
||||
让我们开始......
|
||||
|
||||
> React.js 是一个用于构建用户界面的 JavaScript 库
|
||||
|
||||
你可以构建各种单页应用程序。例如,你希望在用户界面上实时显示更改的聊天软件和电子商务门户。
|
||||
你可以构建各种单页应用程序。例如,你希望在用户界面上实时显示变化的聊天软件和电子商务门户。
|
||||
|
||||
### 一切都是组件
|
||||
|
||||
React 应用由组件组成,数量多且互相嵌套。你或许会问:”可什么是组件呢?“
|
||||
React 应用由组件组成,数量繁多且互相嵌套。你或许会问:”可什么是组件呢?“
|
||||
|
||||
组件是可重用的代码段,它定义了某些功能在 UI 上的外观和行为。 比如,按钮就是一个组件。
|
||||
|
||||
让我们看看下面的计算器,当你尝试计算2 + 2 = 4 -1 = 3(简单的数学题)时,你会在Google上看到这个计算器。
|
||||
让我们看看下面的计算器,当你尝试计算 2 + 2 = 4 -1 = 3(简单的数学题)时,你会在 Google 上看到这个计算器。
|
||||
|
||||
![](https://cdn-images-1.medium.com/max/1000/1*NS9DykYDyYG7__UXJdysTA.png)
|
||||
红色标记表示组件
|
||||
|
||||
|
||||
*红色标记表示组件*
|
||||
|
||||
如上图所示,这个计算器有很多区域,比如展示窗口和数字键盘。所有这些都可以是许多单独的组件或一个巨大的组件。这取决于在 React 中分解和抽象出事物的程度。你为所有这些组件分别编写代码,然后合并这些组件到一个容器中,而这个容器又是一个 React 组件。这样你就可以创建可重用的组件,最终的应用将是一组协同工作的单独组件。
|
||||
|
||||
|
||||
|
||||
以下是一个你践行了以上原则并可以用 React 编写计算器的方法。
|
||||
|
||||
```
|
||||
@ -47,7 +45,6 @@ React 应用由组件组成,数量多且互相嵌套。你或许会问:”
|
||||
<Key number={9}/>
|
||||
</NumPad>
|
||||
</Calculator>
|
||||
|
||||
```
|
||||
|
||||
没错!它看起来像HTML代码,然而并不是。我们将在后面的部分中详细探讨它。
|
||||
@ -56,7 +53,7 @@ React 应用由组件组成,数量多且互相嵌套。你或许会问:”
|
||||
|
||||
这篇教程专注于 React 的基础部分。它没有偏向 Web 或 React Native(开发移动应用)。所以,我们会用一个在线编辑器,这样可以在学习 React 能做什么之前避免 web 或 native 的具体配置。
|
||||
|
||||
我已经为读者在 [codepen.io][4] 设置好了开发环境。只需点开这个链接并且阅读所有 HTML 和 JavaScript 注释。
|
||||
我已经为读者在 [codepen.io][4] 设置好了开发环境。只需点开[该链接][4]并且阅读 HTML 和 JavaScript 中的所有注释。
|
||||
|
||||
### 控制组件
|
||||
|
||||
@ -70,8 +67,6 @@ React 应用由组件组成,数量多且互相嵌套。你或许会问:”
|
||||
|
||||
在 React 中,一个函数式组件通过 `props` 对象使用你传递给它的任意数据。它返回一个对象,该对象描述了 React 应渲染的 UI。函数式组件也称为无状态组件。
|
||||
|
||||
|
||||
|
||||
让我们编写第一个函数式组件。
|
||||
|
||||
```
|
||||
@ -80,14 +75,12 @@ function Hello(props) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
就这么简单。我们只是将 `props` 作为参数传递给了一个普通的 JavaScript 函数并且有返回值。嗯?返回了什么?那个 `<div>{props.name}</div>`。它是 JSX(JavaScript Extended)。我们将在后面的部分中详细了解它。
|
||||
|
||||
上面这个函数将在浏览器中渲染出以下HTML。
|
||||
上面这个函数将在浏览器中渲染出以下 HTML。
|
||||
|
||||
```
|
||||
<!-- If the "props" object is: {name: 'rajat'} -->
|
||||
<!-- If the "props" object is: {name: 'rajat'} -->
|
||||
<div>
|
||||
rajat
|
||||
</div>
|
||||
@ -104,7 +97,7 @@ function Hello(props) {
|
||||
|
||||
属性 `name` 在上面的代码中变成了 `Hello` 组件里的 `props.name` ,属性 `age` 变成了 `props.age` 。
|
||||
|
||||
> 记住! 你可以将一个React组件嵌套在其他React组件中。
|
||||
> 记住! 你可以将一个 React 组件嵌套在其他 React 组件中。
|
||||
|
||||
让我们在 codepen playground 使用 `Hello` 组件。用我们的 `Hello` 组件替换 `ReactDOM.render()` 中的 `div`,并在底部窗口中查看更改。
|
||||
|
||||
@ -117,13 +110,15 @@ ReactDOM.render(<Hello name="rajat"/>, document.getElementById('root'));
|
||||
```
|
||||
|
||||
|
||||
> 但是如果你的组件有一些内部状态怎么办?例如,像下面的计数器组件一样,它有一个内部计数变量,它在 + 和 - 键按下时发生变化。
|
||||
> 但是如果你的组件有一些内部状态怎么办?例如,像下面的计数器组件一样,它有一个内部计数变量,它在 `+` 和 `-` 键按下时发生变化。
|
||||
|
||||
具有内部状态的 React 组件
|
||||
![](https://media.giphy.com/media/3ohs4xEtqjJIs4FJ9C/giphy.gif)
|
||||
|
||||
*具有内部状态的 React 组件*
|
||||
|
||||
#### b) 基于类的组件
|
||||
|
||||
基于类的组件有一个额外属性 `state` ,你可以用它存放组件的私有数据。我们可以用 class 表示法重写我们的 `Hello` 。由于这些组件具有状态,因此这些组件也称为有状态组件。
|
||||
基于类的组件有一个额外属性 `state` ,你可以用它存放组件的私有数据。我们可以用 `class` 表示法重写我们的 `Hello` 。由于这些组件具有状态,因此这些组件也称为有状态组件。
|
||||
|
||||
```
|
||||
class Counter extends React.Component {
|
||||
@ -138,9 +133,9 @@ class Counter extends React.Component {
|
||||
}
|
||||
```
|
||||
|
||||
我们继承了 React 库的 React.Component 类以在React中创建基于类的组件。在[这里][5]了解更多有关 JavaScript 类的东西。
|
||||
我们继承了 React 库的 `React.Component` 类以在 React 中创建基于类的组件。在[这里][5]了解更多有关 JavaScript 类的东西。
|
||||
|
||||
`render()` 方法必须存在于你的类中,因为React会查找此方法,用以了解它应在屏幕上渲染的 UI。为了使用这种内部状态,我们首先要在组件
|
||||
`render()` 方法必须存在于你的类中,因为 React 会查找此方法,用以了解它应在屏幕上渲染的 UI。为了使用这种内部状态,我们首先要在组件
|
||||
|
||||
要使用这种内部状态,我们首先必须按以下方式初始化组件类的构造函数中的状态对象。
|
||||
|
||||
@ -166,47 +161,47 @@ class Counter extends React.Component {
|
||||
// In your react app: <Counter />
|
||||
```
|
||||
|
||||
类似地,可以使用 this.props 对象在我们基于类的组件内访问 props。
|
||||
类似地,可以使用 `this.props` 对象在我们基于类的组件内访问 `props`。
|
||||
|
||||
要设置 state,请使用 `React.Component` 的 `setState()`。 在本教程的最后一部分中,我们将看到一个这样的例子。
|
||||
要设置 `state`,请使用 `React.Component` 的 `setState()`。 在本教程的最后一部分中,我们将看到一个这样的例子。
|
||||
|
||||
> 提示:永远不要在 `render()` 函数中调用 `setState()`,因为 `setState` 会导致组件重新渲染,这将导致无限循环。
|
||||
|
||||
![](https://cdn-images-1.medium.com/max/1000/1*rPUhERO1Bnr5XdyzEwNOwg.png)
|
||||
基于类的组件具有可选属性 “state”。
|
||||
|
||||
*基于类的组件具有可选属性 “state”。*
|
||||
|
||||
除了 `state` 以外,基于类的组件有一些声明周期方法比如 `componentWillMount()`。你可以利用这些去做初始化 `state`这样的事, 可是那将超出这篇文章的范畴。
|
||||
|
||||
### JSX
|
||||
|
||||
JSX 是 JavaScript Extended 的一种简短形式,它是一种编写 React components 的方法。使用 JSX,你可以在类 XML 标签中获得 JavaScript 的全部力量。
|
||||
JSX 是 JavaScript Extended 的缩写,它是一种编写 React 组件的方法。使用 JSX,你可以在类 XML 标签中获得 JavaScript 的全部力量。
|
||||
|
||||
你把 JavaScript 表达式放在`{}`里。下面是一些有效的 JSX 例子。
|
||||
你把 JavaScript 表达式放在 `{}` 里。下面是一些有效的 JSX 例子。
|
||||
|
||||
```
|
||||
<button disabled={true}>Press me!</button>
|
||||
|
||||
<button disabled={true}>Press me {3+1} times!</button>;
|
||||
|
||||
<div className='container'><Hello /></div>
|
||||
|
||||
```
|
||||
|
||||
它的工作方式是你编写 JSX 来描述你的 UI 应该是什么样子。像 Babel 这样的转码器将这些代码转换为一堆 `React.createElement()`调用。然后,React 库使用这些 `React.createElement()`调用来构造 DOM 元素的树状结构。对于 React 的网页视图或 React Native 的 Native 视图,它将保存在内存中。
|
||||
它的工作方式是你编写 JSX 来描述你的 UI 应该是什么样子。像 Babel 这样的转码器将这些代码转换为一堆 `React.createElement()` 调用。然后,React 库使用这些 `React.createElement()` 调用来构造 DOM 元素的树状结构。对于 React 的网页视图或 React Native 的 Native 视图,它将保存在内存中。
|
||||
|
||||
React 接着会计算它如何在存储展示给用户的 UI 的内存中有效地模仿这个树。此过程称为 [reconciliation][7]。完成计算后,React会对屏幕上的真正 UI 进行更改。
|
||||
React 接着会计算它如何在展示给用户的 UI 的内存中有效地模仿这个树。此过程称为 [reconciliation][7]。完成计算后,React 会对屏幕上的真正 UI 进行更改。
|
||||
|
||||
![](https://cdn-images-1.medium.com/max/1000/1*ighKXxBnnSdDlaOr5-ZOPg.png)
|
||||
React 如何将你的 JSX 转化为描述应用 UI 的树。
|
||||
|
||||
*React 如何将你的 JSX 转化为描述应用 UI 的树。*
|
||||
|
||||
你可以使用 [Babel 的在线 REPL][8] 查看当你写一些 JSX 的时候,React 的真正输出。
|
||||
|
||||
![](https://cdn-images-1.medium.com/max/1000/1*NRuBKgzNh1nHwXn0JKHafg.png)
|
||||
使用Babel REPL 转换 JSX 为普通 JavaScript
|
||||
|
||||
*使用Babel REPL 转换 JSX 为普通 JavaScript*
|
||||
|
||||
> 由于 JSX 只是 `React.createElement()` 调用的语法糖,因此可以在没有 JSX 的情况下使用 React。
|
||||
|
||||
现在我们了解了所有的概念,所以我们已经准备好编写我们之前看到的作为GIF图的计数器组件。
|
||||
现在我们了解了所有的概念,所以我们已经准备好编写我们之前看到之前的 GIF 图中的计数器组件。
|
||||
|
||||
代码如下,我希望你已经知道了如何在我们的 playground 上渲染它。
|
||||
|
||||
@ -249,20 +244,19 @@ class Counter extends React.Component {
|
||||
以下是关于上述代码的一些重点。
|
||||
|
||||
1. JSX 使用 `驼峰命名` ,所以 `button` 的 属性是 `onClick`,不是我们在HTML中用的 `onclick`。
|
||||
|
||||
2. 绑定 `this` 是必要的,以便在回调时工作。 请参阅上面代码中的第8行和第9行。
|
||||
|
||||
最终的交互式代码位于[此处][9]。
|
||||
|
||||
有了这个,我们已经到了 React 速成课程的结束。我希望我已经阐明了 React 如何工作以及如何使用 React 来构建更大的应用程序,使用更小和可重用的组件。
|
||||
有了这个,我们已经到了 React 速成课程的结束。我希望我已经阐明了 React 如何工作,以及如何使用 React 来构建更大的应用程序,使用更小和可重用的组件。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://medium.freecodecamp.org/rock-solid-react-js-foundations-a-beginners-guide-c45c93f5a923
|
||||
|
||||
作者:[Rajat Saxena ][a]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
作者:[Rajat Saxena][a]
|
||||
译者:[GraveAccent](https://github.com/GraveAccent)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,38 +1,39 @@
|
||||
写给系统管理员的容器手册
|
||||
面向系统管理员的容器手册
|
||||
======
|
||||
> 你所需了解的容器如何工作的知识。
|
||||
|
||||
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/toolbox-learn-draw-container-yearbook.png?itok=xDbwz1pP)
|
||||
|
||||
现在人们严重地过度使用“容器”这个术语。另外,对不同的人来说,它可能会有不同的含义,这取决于上下文。
|
||||
现在人们严重过度使用了“容器”这个术语。另外,对不同的人来说,它可能会有不同的含义,这取决于上下文。
|
||||
|
||||
传统的 Linux 容器只是系统上普通的进程组成的进程组。进程组之间是相互隔离的,实现方法包括:资源限制(控制组 [cgoups])、Linux 安全限制(文件权限,基于 Capability 的安全模块,SELinux,AppArmor,seccomp 等)还有名字空间(进程 ID,网络,挂载等)。
|
||||
传统的 Linux 容器只是系统上普通的进程。一组进程与另外一组进程是相互隔离的,实现方法包括:资源限制(控制组 [cgoups])、Linux 安全限制(文件权限,基于 Capability 的安全模块、SELinux、AppArmor、seccomp 等)还有名字空间(进程 ID、网络、挂载等)。
|
||||
|
||||
如果你启动一台现代 Linux 操作系统,使用 `cat /proc/PID/cgroup` 命令就可以看到该进程是属于一个控制组的。还可以从 `/proc/PID/status` 文件中查看进程的 Capability 信息,从 `/proc/self/attr/current` 文件中查看进程的 SELinux 标签信息,从 `/proc/PID/ns` 目录下的文件查看进程所属的名字空间。因此,如果把容器定义为带有资源限制、Linux 安全限制和名字空间的进程,那么按照这个定义,Linux 操作系统上的每一个进程都在容器里。因此我们常说 [Linux 就是容器,容器就是 Linux][1]。而**容器运行时**是这样一种工具,它调整上述资源限制、安全限制和名字空间,并启动容器。
|
||||
如果你启动一台现代 Linux 操作系统,使用 `cat /proc/PID/cgroup` 命令就可以看到该进程是属于一个控制组的。还可以从 `/proc/PID/status` 文件中查看进程的 Capability 信息,从 `/proc/self/attr/current` 文件中查看进程的 SELinux 标签信息,从 `/proc/PID/ns` 目录下的文件查看进程所属的名字空间。因此,如果把容器定义为带有资源限制、Linux 安全限制和名字空间的进程,那么按照这个定义,Linux 操作系统上的每一个进程都在一个容器里。因此我们常说 [Linux 就是容器,容器就是 Linux][1]。而**容器运行时**是这样一种工具,它调整上述资源限制、安全限制和名字空间,并启动容器。
|
||||
|
||||
Docker 引入了**容器镜像**的概念,镜像是一个普通的 TAR 包文件,包含了:
|
||||
|
||||
* **Rootfs(容器的根文件系统):**一个目录,看起来像是操作系统的普通根目录(/),例如,一个包含 `/usr`, `/var`, `/home` 等的目录。
|
||||
* **JSON 文件(容器的配置):**定义了如何运行 rootfs;例如,当容器启动的时候要在 rootfs 里运行什么 **command** 或者 **entrypoint**,给容器定义什么样的**环境变量**,容器的**工作目录**是哪个,以及其他一些设置。
|
||||
* **rootfs(容器的根文件系统)**:一个目录,看起来像是操作系统的普通根目录(`/`),例如,一个包含 `/usr`, `/var`, `/home` 等的目录。
|
||||
* **JSON 文件(容器的配置)**:定义了如何运行 rootfs;例如,当容器启动的时候要在 rootfs 里运行什么命令(`CMD`)或者入口(`ENTRYPOINT `),给容器定义什么样的环境变量(`ENV`),容器的工作目录(`WORKDIR `)是哪个,以及其他一些设置。
|
||||
|
||||
Docker 把 rootfs 和 JSON 配置文件打包成**基础镜像**。你可以在这个基础之上,给 rootfs 安装更多东西,创建新的 JSON 配置文件,然后把相对于原始镜像的不同内容打包到新的镜像。这种方法创建出来的是**分层的镜像**。
|
||||
|
||||
[Open Container Initiative(开放容器计划 OCI)][2] 标准组织最终把容器镜像的格式标准化了,也就是 [OCI Image Specification(OCI 镜像规范)][3]。
|
||||
<ruby>[开放容器计划][2]<rt>Open Container Initiative</rt></ruby>(OCI)标准组织最终把容器镜像的格式标准化了,也就是 <ruby>[镜像规范][3]<rt>OCI Image Specification</rt></ruby>(OCI)。
|
||||
|
||||
用来创建容器镜像的工具被称为**容器镜像构建器**。有时候容器引擎做这件事情,不过可以用一些独立的工具来构建容器镜像。
|
||||
|
||||
Docker 把这些容器镜像(**tar 包**)托管到 web 服务中,并开发了一种协议来支持从 web 拉取镜像,这个 web 服务就叫**容器仓库**。
|
||||
Docker 把这些容器镜像(**tar 包**)托管到 web 服务中,并开发了一种协议来支持从 web 拉取镜像,这个 web 服务就叫<ruby>容器仓库<rt>container registry</rt></ruby>。
|
||||
|
||||
**容器引擎**是能从镜像仓库拉取镜像并装载到**容器存储**上的程序。容器引擎还能启动**容器运行时**(见下图)。
|
||||
|
||||
![](https://opensource.com/sites/default/files/linux_container_internals_2.0_-_hosts.png)
|
||||
|
||||
容器存储一般是**写入时复制**(COW)的分层文件系统。从容器仓库拉取一个镜像时,其中的 rootfs 首先被解压到磁盘。如果这个镜像是多层的,那么每一层都会被下载到 COW 文件系统的不同分层。 COW 文件系统保证了镜像的每一层独立存储,这最大化了多个分层镜像之间的文件共享程度。容器引擎通常支持多种容器存储类型,包括 `overlay`、`devicemapper`、`btrfs`、`aufs` 和 `zfs`。
|
||||
容器存储一般是<ruby>写入时复制<rt>copy-on-write</rt></ruby>(COW)的分层文件系统。从容器仓库拉取一个镜像时,其中的 rootfs 首先被解压到磁盘。如果这个镜像是多层的,那么每一层都会被下载到 COW 文件系统的不同分层。 COW 文件系统保证了镜像的每一层独立存储,这最大化了多个分层镜像之间的文件共享程度。容器引擎通常支持多种容器存储类型,包括 `overlay`、`devicemapper`、`btrfs`、`aufs` 和 `zfs`。
|
||||
|
||||
容器引擎将容器镜像下载到容器存储中之后,需要创建一份**容器运行时配置**,这份配置是用户/调用者的输入和镜像配置的合并。例如,容器的调用者可能会调整安全设置,添加额外的环境变量或者挂载一些卷到容器中。
|
||||
|
||||
容器运行时配置的格式,和解压出来的 rootfs 也都被开放容器计划 OCI 标准组织做了标准化,称为 [OCI 运行时规范][4]。
|
||||
|
||||
最终,容器引擎启动了一个**容器运行时**来读取运行时配置,修改 Linux 控制组、安全限制和名字空间,并执行容器命令来创建容器的 **PID 1**。至此,容器引擎已经可以把容器的标准输入/标准输出转给调用方,并控制容器了(例如,stop,start,attach)。
|
||||
最终,容器引擎启动了一个**容器运行时**来读取运行时配置,修改 Linux 控制组、安全限制和名字空间,并执行容器命令来创建容器的 **PID 1** 进程。至此,容器引擎已经可以把容器的标准输入/标准输出转给调用方,并控制容器了(例如,`stop`、`start`、`attach`)。
|
||||
|
||||
值得一提的是,现在出现了很多新的容器运行时,它们使用 Linux 的不同特性来隔离容器。可以使用 KVM 技术来隔离容器(想想迷你虚拟机),或者使用其他虚拟机监视器策略(例如拦截所有从容器内的进程发起的系统调用)。既然我们有了标准的运行时规范,这些工具都能被相同的容器引擎来启动。即使在 Windows 系统下,也可以使用 OCI 运行时规范来启动 Windows 容器。
|
||||
|
||||
@ -45,7 +46,7 @@ via: https://opensource.com/article/18/8/sysadmins-guide-containers
|
||||
作者:[Daniel J Walsh][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[belitex](https://github.com/belitex)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,19 +1,19 @@
|
||||
如何构建rpm包
|
||||
如何构建 RPM 包
|
||||
======
|
||||
|
||||
节省跨多个主机安装文件和脚本的时间和精力。
|
||||
> 节省跨多个主机安装文件和脚本的时间和精力。
|
||||
|
||||
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/OSDC_gift_giveaway_box_520x292.png?itok=w1YQhNH1)
|
||||
|
||||
自20多年前我开始使用 Linux 以来,我已经使用过基于 rpm 的软件包管理器在 Red Hat 和 Fedora Linux系统上安装软件。我使用过 **rpm** 程序本身,还有 **yum** 和 **DNF** ,用于在我的 Linux 主机上安装和更新软件包,DNF 是 yum 的一个紧密后代。 yum 和 DNF 工具是 rpm 实用程序的包装器,它提供了其他功能,例如查找和安装包依赖项的功能。
|
||||
自20多年前我开始使用 Linux 以来,我已经使用过基于 rpm 的软件包管理器在 Red Hat 和 Fedora Linux 系统上安装软件。我使用过 `rpm` 程序本身,还有 `yum` 和 `dnf` ,用于在我的 Linux 主机上安装和更新软件包,`dnf` 是 `yum` 的一个近亲。 `yum` 和 `dnf` 工具是 `rpm` 实用程序的包装器,它提供了其他功能,例如查找和安装包依赖项的功能。
|
||||
|
||||
多年来,我创建了许多 Bash 脚本,其中一些脚本具有单独的配置文件,我希望在大多数新计算机和虚拟机上安装这些脚本。这也能解决安装所有这些软件包需要花费大量时间的难题,因此我决定通过创建一个 rpm 软件包来自动执行该过程,我可以将其复制到目标主机并将所有这些文件安装在适当的位置。虽然 **rpm** 工具以前用于构建 rpm 包,但该功能已被删除,并且创建了一个新工具来构建新的 rpm。
|
||||
多年来,我创建了许多 Bash 脚本,其中一些脚本具有单独的配置文件,我希望在大多数新计算机和虚拟机上安装这些脚本。这也能解决安装所有这些软件包需要花费大量时间的难题,因此我决定通过创建一个 rpm 软件包来自动执行该过程,我可以将其复制到目标主机并将所有这些文件安装在适当的位置。虽然 `rpm` 工具以前用于构建 rpm 包,但该功能已被删除,并且创建了一个新工具来构建新的 rpm。
|
||||
|
||||
当我开始这个项目时,我发现很少有关于创建 rpm 包的信息,但我找到了一本书,名为《Maximum RPM》,这本书才帮我弄明白了。这本书现在已经过时了,我发现的绝大多数信息都是如此。它也已经绝版,使用复印件需要花费数百美元。[Maximum RPM][1] 的在线版本是免费提供的,并保持最新。 [RPM 网站][2]还有其他网站的链接,这些网站上有很多关于 rpm 的文档。其他的信息往往是简短的,显然都是假设你已经对该过程有了很多了解。
|
||||
当我开始这个项目时,我发现很少有关于创建 rpm 包的信息,但我找到了一本书,名为《Maximum RPM》,这本书才帮我弄明白了。这本书现在已经过时了,我发现的绝大多数信息都是如此。它也已经绝版,用过的副本也需要花费数百美元。[Maximum RPM][1] 的在线版本是免费提供的,并保持最新。该 [RPM 网站][2]还有其他网站的链接,这些网站上有很多关于 rpm 的文档。其他的信息往往是简短的,显然都是假设你已经对该过程有了很多了解。
|
||||
|
||||
此外,我发现的每个文档都假定代码需要在开发环境中从源代码编译。我不是开发人员。我是一个系统管理员,我们系统管理员有不同的需求,因为我们不需要或者我们不应该为了管理任务而去编译代码;我们应该使用 shell 脚本。所以我们没有源代码,因为它需要被编译成二进制可执行文件。我们拥有的是一个也是可执行的源代码。
|
||||
此外,我发现的每个文档都假定代码需要在开发环境中从源代码编译。我不是开发人员。我是一个系统管理员,我们系统管理员有不同的需求,因为我们不需要或者我们不应该为了管理任务而去编译代码;我们应该使用 shell 脚本。所以我们没有源代码,因为它需要被编译成二进制可执行文件。我们拥有的源代码也应该是可执行的。
|
||||
|
||||
在大多数情况下,此项目应作为非 root 用户执行。 Rpm 包永远不应该由 root 用户构建,而只能由非特权普通用户构建。我将指出哪些部分应该以 root 身份执行,哪些部分应由非 root,非特权用户执行。
|
||||
在大多数情况下,此项目应作为非 root 用户执行。 rpm 包永远不应该由 root 用户构建,而只能由非特权普通用户构建。我将指出哪些部分应该以 root 身份执行,哪些部分应由非 root,非特权用户执行。
|
||||
|
||||
### 准备
|
||||
|
||||
@ -37,7 +37,7 @@ passwd: all authentication tokens updated successfully.
|
||||
[root@testvm1 ~]#
|
||||
```
|
||||
|
||||
构建 rpm 包需要 `rpm-build` 包,该包可能尚未安装。 现在以 root 身份安装它。 请注意,此命令还将安装多个依赖项。 数量可能会有所不同,具体取决于主机上已安装的软件包; 它在我的测试虚拟机上总共安装了17个软件包,这是非常小的。
|
||||
构建 rpm 包需要 `rpm-build` 包,该包可能尚未安装。 现在以 root 身份安装它。 请注意,此命令还将安装多个依赖项。 数量可能会有所不同,具体取决于主机上已安装的软件包; 它在我的测试虚拟机上总共安装了 17 个软件包,这是非常小的。
|
||||
|
||||
```
|
||||
dnf install -y rpm-build
|
||||
@ -49,15 +49,15 @@ dnf install -y rpm-build
|
||||
wget https://github.com/opensourceway/how-to-rpm/raw/master/utils.tar
|
||||
```
|
||||
|
||||
此 tar 包包含将由最终 rpm 程序安装的所有文件和 Bash 脚本。 还有一个完整的 spec 文件,你可以使用它来构建 rpm。 我们将详细介绍 spec 文件的每个部分。
|
||||
此 tar 包包含将由最终 `rpm` 程序安装的所有文件和 Bash 脚本。 还有一个完整的 spec 文件,你可以使用它来构建 rpm。 我们将详细介绍 spec 文件的每个部分。
|
||||
|
||||
作为普通学生 student,使用你的家目录作为当前工作目录(pwd),解压缩 tar 包。
|
||||
作为普通学生 student,使用你的家目录作为当前工作目录(`pwd`),解压缩 tar 包。
|
||||
|
||||
```
|
||||
[student@testvm1 ~]$ cd ; tar -xvf utils.tar
|
||||
```
|
||||
|
||||
使用 `tree` 命令验证~/development 的目录结构和包含的文件,如下所示:
|
||||
使用 `tree` 命令验证 `~/development` 的目录结构和包含的文件,如下所示:
|
||||
|
||||
```
|
||||
[student@testvm1 ~]$ tree development/
|
||||
@ -77,13 +77,13 @@ development/
|
||||
[student@testvm1 ~]$
|
||||
```
|
||||
|
||||
`mymotd` 脚本创建一个发送到标准输出的“当日消息”数据流。 `create_motd` 脚本运行 `mymotd` 脚本并将输出重定向到 /etc/motd 文件。 此文件用于向使用SSH远程登录的用户显示每日消息。
|
||||
`mymotd` 脚本创建一个发送到标准输出的“当日消息”数据流。 `create_motd` 脚本运行 `mymotd` 脚本并将输出重定向到 `/etc/motd` 文件。 此文件用于向使用 SSH 远程登录的用户显示每日消息。
|
||||
|
||||
`die` 脚本是我自己的脚本,它将 `kill` 命令包装在一些代码中,这些代码可以找到与指定字符串匹配的运行程序并将其终止。 它使用 `kill -9` 来确保kill命令一定会执行。
|
||||
`die` 脚本是我自己的脚本,它将 `kill` 命令包装在一些代码中,这些代码可以找到与指定字符串匹配的运行程序并将其终止。 它使用 `kill -9` 来确保 `kill` 命令一定会执行。
|
||||
|
||||
`sysdata` 脚本可以显示有关计算机硬件,还有已安装的 Linux 版本,所有已安装的软件包以及硬盘驱动器元数据的数万行数据。 我用它来记录某个时间点的主机状态。 我以后可以用它作为参考。 我曾经这样做是为了维护我为客户安装的主机记录。
|
||||
`sysdata` 脚本可以显示有关计算机硬件,还有已安装的 Linux 版本,所有已安装的软件包以及硬盘驱动器元数据等数万行数据。 我用它来记录某个时间点的主机状态。 我以后可以用它作为参考。 我曾经这样做是为了维护我为客户安装的主机记录。
|
||||
|
||||
你可能需要将这些文件和目录的所有权更改为 student:student 。 如有必要,使用以下命令执行此操作:
|
||||
你可能需要将这些文件和目录的所有权更改为 `student:student` 。 如有必要,使用以下命令执行此操作:
|
||||
|
||||
```
|
||||
chown -R student:student development
|
||||
@ -104,11 +104,11 @@ chown -R student:student development
|
||||
└── SRPMS
|
||||
```
|
||||
|
||||
我们不会创建 rpmbuild/RPMS/X86_64 目录,因为对于64位编译的二进制文件这是特定于体系结构的。 我们有 shell 脚本,不是特定于体系结构的。 实际上,我们也不会使用 SRPMS 目录,它将包含编译器的源文件。
|
||||
我们不会创建 `rpmbuild/RPMS/X86_64` 目录,因为它是特定于体系结构编译的 64 位二进制文件。 我们有 shell 脚本,不是特定于体系结构的。 实际上,我们也不会使用 `SRPMS` 目录,它将包含编译器的源文件。
|
||||
|
||||
### 检查 spec 文件
|
||||
|
||||
每个 spec 文件都有许多部分,其中一些部分可能会被忽视或省略,取决于 rpm 构建的具体情况。 这个特定的 spec 文件不是工作所需的最小文件的示例,但它是一个很好的包含不需要编译的文件的中等复杂 spec 文件的例子。 如果需要编译,它将在`构建`部分中执行,该部分在此 spec 文件中省略掉了,因为它不是必需的。
|
||||
每个 spec 文件都有许多部分,其中一些部分可能会被忽视或省略,取决于 rpm 构建的具体情况。 这个特定的 spec 文件不是工作所需的最小文件的示例,但它是一个包含不需要编译的文件的中等复杂 spec 文件的很好例子。 如果需要编译,它将在 `%build` 部分中执行,该部分在此 spec 文件中省略掉了,因为它不是必需的。
|
||||
|
||||
#### 前言
|
||||
|
||||
@ -139,40 +139,46 @@ BuildRoot: ~/rpmbuild/
|
||||
# rpmbuild --target noarch -bb utils.spec
|
||||
```
|
||||
|
||||
`rpmbuild` 程序会忽略注释行。我总是喜欢在本节中添加注释,其中包含创建包所需的 `rpmbuild` 命令的确切语法。摘要标签是包的简短描述。 Name,Version 和 Release 标签用于创建 rpm 文件的名称,如utils-1.00-1.rpm 中所示。通过增加发行版号码和版本号,你可以创建 rpm 包去更新旧版本的。
|
||||
`rpmbuild` 程序会忽略注释行。我总是喜欢在本节中添加注释,其中包含创建包所需的 `rpmbuild` 命令的确切语法。
|
||||
|
||||
许可证标签定义了发布包的许可证。我总是使用 GPL 的一个变体。指定许可证对于澄清包中包含的软件是开源的这一事实非常重要。这也是我将许可证和 GPL 语句包含在将要安装的文件中的原因。
|
||||
`Summary` 标签是包的简短描述。
|
||||
|
||||
URL 通常是项目或项目所有者的网页。在这种情况下,它是我的个人网页。
|
||||
`Name`、`Version` 和 `Release` 标签用于创建 rpm 文件的名称,如 `utils-1.00-1.rpm`。通过增加发行版号码和版本号,你可以创建 rpm 包去更新旧版本的。
|
||||
|
||||
Group 标签很有趣,通常用于 GUI 应用程序。 Group 标签的值决定了应用程序菜单中的哪一组图标将包含此包中可执行文件的图标。与 Icon 标签(我们此处未使用)一起使用时,Group 标签允许添加图标和所需信息用于将程序启动到应用程序菜单结构中。
|
||||
`License` 标签定义了发布包的许可证。我总是使用 GPL 的一个变体。指定许可证对于澄清包中包含的软件是开源的这一事实非常重要。这也是我将 `License` 和 `GPL` 语句包含在将要安装的文件中的原因。
|
||||
|
||||
Packager 标签用于指定负责维护和创建包的人员或组织。
|
||||
`URL` 通常是项目或项目所有者的网页。在这种情况下,它是我的个人网页。
|
||||
|
||||
Requires 语句定义此 rpm 包的依赖项。每个都是包名。如果其中一个指定的软件包不存在,DNF 安装实用程序将尝试在 /etc/yum.repos.d 中定义的某个已定义的存储库中找到它,如果存在则安装它。如果 DNF 找不到一个或多个所需的包,它将抛出一个错误,指出哪些包丢失并终止。
|
||||
`Group` 标签很有趣,通常用于 GUI 应用程序。 `Group` 标签的值决定了应用程序菜单中的哪一组图标将包含此包中可执行文件的图标。与 `Icon` 标签(我们此处未使用)一起使用时,`Group` 标签允许在应用程序菜单结构中添加用于启动程序的图标和所需信息。
|
||||
|
||||
BuildRoot 行指定顶级目录,`rpmbuild` 工具将在其中找到 spec 文件,并在构建包时在其中创建临时目录。完成的包将存储在我们之前指定的noarch子目录中。注释显示了构建此程序包的命令语法,包括定义了目标体系结构的 `–target noarch` 选项。因为这些是Bash脚本,所以它们与特定的CPU架构无关。如果省略此选项,则构建将选用正在执行构建的CPU的体系结构。
|
||||
`Packager` 标签用于指定负责维护和创建包的人员或组织。
|
||||
|
||||
`Requires` 语句定义此 rpm 包的依赖项。每个都是包名。如果其中一个指定的软件包不存在,DNF 安装实用程序将尝试在 `/etc/yum.repos.d` 中定义的某个已定义的存储库中找到它,如果存在则安装它。如果 DNF 找不到一个或多个所需的包,它将抛出一个错误,指出哪些包丢失并终止。
|
||||
|
||||
`BuildRoot` 行指定顶级目录,`rpmbuild` 工具将在其中找到 spec 文件,并在构建包时在其中创建临时目录。完成的包将存储在我们之前指定的 `noarch` 子目录中。
|
||||
|
||||
注释显示了构建此程序包的命令语法,包括定义了目标体系结构的 `–target noarch` 选项。因为这些是 Bash 脚本,所以它们与特定的 CPU 架构无关。如果省略此选项,则构建将选用正在执行构建的 CPU 的体系结构。
|
||||
|
||||
`rpmbuild` 程序可以针对许多不同的体系结构,并且使用 `--target` 选项允许我们在不同的体系结构主机上构建特定体系结构的包,其具有与执行构建的体系结构不同的体系结构。所以我可以在 x86_64 主机上构建一个用于 i686 架构的软件包,反之亦然。
|
||||
|
||||
如果你有自己的网站,请将打包者的名称更改为你自己的网站。
|
||||
|
||||
#### 描述
|
||||
#### 描述部分(`%description`)
|
||||
|
||||
spec 文件的 `描述` 部分包含 rpm 包的描述。 它可以很短,也可以包含许多信息。 我们的 `描述` 部分相当简洁。
|
||||
spec 文件的 `%description` 部分包含 rpm 包的描述。 它可以很短,也可以包含许多信息。 我们的 `%description` 部分相当简洁。
|
||||
|
||||
```
|
||||
%description
|
||||
A collection of utility scripts for testing RPM creation.
|
||||
```
|
||||
|
||||
#### 准备
|
||||
#### 准备部分(`%prep`)
|
||||
|
||||
`准备` 部分是在构建过程中执行的第一个脚本。 在安装程序包期间不会执行此脚本。
|
||||
`%prep` 部分是在构建过程中执行的第一个脚本。 在安装程序包期间不会执行此脚本。
|
||||
|
||||
这个脚本只是一个 Bash shell 脚本。 它准备构建目录,根据需要创建用于构建的目录,并将相应的文件复制到各自的目录中。 这将包括完整编译作为构建的一部分所需的源。
|
||||
这个脚本只是一个 Bash shell 脚本。 它准备构建目录,根据需要创建用于构建的目录,并将相应的文件复制到各自的目录中。 这将包括作为构建的一部分的完整编译所需的源代码。
|
||||
|
||||
$RPM_BUILD_ROOT 目录表示已安装系统的根目录。 在 $RPM_BUILD_ROOT 目录中创建的目录是实时文件系统中的绝对路径,例如 /user/local/share/utils,/usr/local/bin 等。
|
||||
`$RPM_BUILD_ROOT` 目录表示已安装系统的根目录。 在 `$RPM_BUILD_ROOT` 目录中创建的目录是真实文件系统中的绝对路径,例如 `/user/local/share/utils`、`/usr/local/bin` 等。
|
||||
|
||||
对于我们的包,我们没有预编译源,因为我们的所有程序都是 Bash 脚本。 因此,我们只需将这些脚本和其他文件复制到已安装系统的目录中。
|
||||
|
||||
@ -193,11 +199,11 @@ cp /home/student/development/utils/spec/* $RPM_BUILD_ROOT/usr/local/share/utils
|
||||
exit
|
||||
```
|
||||
|
||||
请注意,本节末尾的 exit 语句是必需的。
|
||||
请注意,本节末尾的 `exit` 语句是必需的。
|
||||
|
||||
#### 文件
|
||||
#### 文件部分(`%files`)
|
||||
|
||||
spec 文件的这一部分定义了要安装的文件及其在目录树中的位置。 它还指定了要安装的每个文件的文件属性以及所有者和组所有者。 文件权限和所有权是可选的,但我建议明确设置它们以消除这些属性在安装时不正确或不明确的任何可能性。 如果目录尚不存在,则会在安装期间根据需要创建目录。
|
||||
spec 文件的 `%files` 这一部分定义了要安装的文件及其在目录树中的位置。 它还指定了要安装的每个文件的文件属性(`%attr`)以及所有者和组所有者。 文件权限和所有权是可选的,但我建议明确设置它们以消除这些属性在安装时不正确或不明确的任何可能性。 如果目录尚不存在,则会在安装期间根据需要创建目录。
|
||||
|
||||
```
|
||||
%files
|
||||
@ -205,13 +211,13 @@ spec 文件的这一部分定义了要安装的文件及其在目录树中的位
|
||||
%attr(0644, root, root) /usr/local/share/utils/*
|
||||
```
|
||||
|
||||
#### 安装前
|
||||
#### 安装前(`%pre`)
|
||||
|
||||
在我们的实验室项目的 spec 文件中,此部分为空。 这将放置那些需要 rpm 安装前执行的脚本。
|
||||
在我们的实验室项目的 spec 文件中,此部分为空。 这应该放置那些需要 rpm 中的文件安装前执行的脚本。
|
||||
|
||||
#### 安装后
|
||||
#### 安装后(`%post`)
|
||||
|
||||
spec 文件的这一部分是另一个 Bash 脚本。 这个在安装文件后运行。 此部分几乎可以是你需要或想要的任何内容,包括创建文件,运行系统命令以及重新启动服务以在进行配置更改后重新初始化它们。 我们的 rpm 包的 `安装后` 脚本执行其中一些任务。
|
||||
spec 文件的这一部分是另一个 Bash 脚本。 这个在文件安装后运行。 此部分几乎可以是你需要或想要的任何内容,包括创建文件、运行系统命令以及重新启动服务以在进行配置更改后重新初始化它们。 我们的 rpm 包的 `%post` 脚本执行其中一些任务。
|
||||
|
||||
```
|
||||
%post
|
||||
@ -236,11 +242,11 @@ fi
|
||||
|
||||
此脚本中包含的注释应明确其用途。
|
||||
|
||||
#### 卸载后
|
||||
#### 卸载后(`%postun`)
|
||||
|
||||
此部分包含将在卸载 rpm 软件包后运行的脚本。 使用 rpm 或 DNF 删除包会删除文件部分中列出的所有文件,但它不会删除安装后部分创建的文件或链接,因此我们需要在本节中处理。
|
||||
此部分包含将在卸载 rpm 软件包后运行的脚本。 使用 `rpm` 或 `dnf` 删除包会删除文件部分中列出的所有文件,但它不会删除安装后部分创建的文件或链接,因此我们需要在本节中处理。
|
||||
|
||||
此脚本通常由清理任务组成,只是清除以前由rpm安装的文件,但rpm本身无法完成清除。 对于我们的包,它包括删除 `安装后` 脚本创建的链接并恢复 motd 文件的已保存原件。
|
||||
此脚本通常由清理任务组成,只是清除以前由 `rpm` 安装的文件,但 rpm 本身无法完成清除。 对于我们的包,它包括删除 `%post` 脚本创建的链接并恢复 motd 文件的已保存原件。
|
||||
|
||||
```
|
||||
%postun
|
||||
@ -254,9 +260,9 @@ then
|
||||
fi
|
||||
```
|
||||
|
||||
#### 清理
|
||||
#### 清理(`%clean`)
|
||||
|
||||
这个 Bash 脚本在 rpm 构建过程之后开始清理。 下面 `清理` 部分中的两行删除了 `rpm-build` 命令创建的构建目录。 在许多情况下,可能还需要额外的清理。
|
||||
这个 Bash 脚本在 rpm 构建过程之后开始清理。 下面 `%clean` 部分中的两行删除了 `rpm-build` 命令创建的构建目录。 在许多情况下,可能还需要额外的清理。
|
||||
|
||||
```
|
||||
%clean
|
||||
@ -264,9 +270,9 @@ rm -rf $RPM_BUILD_ROOT/usr/local/bin
|
||||
rm -rf $RPM_BUILD_ROOT/usr/local/share/utils
|
||||
```
|
||||
|
||||
#### 更新日志
|
||||
#### 变更日志(`%changelog`)
|
||||
|
||||
此可选的文本部分包含 rpm 及其包含的文件的更改列表。 最新的更改记录在本部分顶部。
|
||||
此可选的文本部分包含 rpm 及其包含的文件的变更列表。最新的变更记录在本部分顶部。
|
||||
|
||||
```
|
||||
%changelog
|
||||
@ -280,20 +286,20 @@ rm -rf $RPM_BUILD_ROOT/usr/local/share/utils
|
||||
|
||||
### 构建 rpm
|
||||
|
||||
spec 文件必须位于 rpmbuild 目录树的 SPECS 目录中。 我发现最简单的方法是创建一个指向该目录中实际 spec 文件的链接,以便可以在开发目录中对其进行编辑,而无需将其复制到 SPECS 目录。 将 SPECS 目录设为当前工作目录,然后创建链接。
|
||||
spec 文件必须位于 `rpmbuild` 目录树的 `SPECS` 目录中。 我发现最简单的方法是创建一个指向该目录中实际 spec 文件的链接,以便可以在开发目录中对其进行编辑,而无需将其复制到 `SPECS` 目录。 将 `SPECS` 目录设为当前工作目录,然后创建链接。
|
||||
|
||||
```
|
||||
cd ~/rpmbuild/SPECS/
|
||||
ln -s ~/development/spec/utils.spec
|
||||
```
|
||||
|
||||
运行以下命令以构建 rpm 。 如果没有错误发生,只需要花一点时间来创建 rpm 。
|
||||
运行以下命令以构建 rpm。 如果没有错误发生,只需要花一点时间来创建 rpm。
|
||||
|
||||
```
|
||||
rpmbuild --target noarch -bb utils.spec
|
||||
```
|
||||
|
||||
检查 ~/rpmbuild/RPMS/noarch 目录以验证新的 rpm 是否存在。
|
||||
检查 `~/rpmbuild/RPMS/noarch` 目录以验证新的 rpm 是否存在。
|
||||
|
||||
```
|
||||
[student@testvm1 ~]$ cd rpmbuild/RPMS/noarch/
|
||||
@ -305,7 +311,7 @@ total 24
|
||||
|
||||
### 测试 rpm
|
||||
|
||||
以 root 用户身份安装 rpm 以验证它是否正确安装并且文件是否安装在正确的目录中。 rpm 的确切名称将取决于你在 Preamble 部分中标签的值,但如果你使用了示例中的值,则 rpm 名称将如下面的示例命令所示:
|
||||
以 root 用户身份安装 rpm 以验证它是否正确安装并且文件是否安装在正确的目录中。 rpm 的确切名称将取决于你在前言部分中标签的值,但如果你使用了示例中的值,则 rpm 名称将如下面的示例命令所示:
|
||||
|
||||
```
|
||||
[root@testvm1 ~]# cd /home/student/rpmbuild/RPMS/noarch/
|
||||
@ -318,9 +324,9 @@ Updating / installing...
|
||||
1:utils-1.0.0-1 ################################# [100%]
|
||||
```
|
||||
|
||||
检查 /usr/local/bin 以确保新文件存在。 你还应验证是否已创建 /etc/cron.daily 中的 create_motd 链接。
|
||||
检查 `/usr/local/bin` 以确保新文件存在。 你还应验证是否已创建 `/etc/cron.daily` 中的 `create_motd` 链接。
|
||||
|
||||
使用 `rpm -q --changelog utils` 命令查看更改日志。 使用 `rpm -ql utils` 命令(在 `ql`中为小写 L )查看程序包安装的文件。
|
||||
使用 `rpm -q --changelog utils` 命令查看更改日志。 使用 `rpm -ql utils` 命令(在 `ql` 中为小写 `L` )查看程序包安装的文件。
|
||||
|
||||
```
|
||||
[root@testvm1 noarch]# rpm -q --changelog utils
|
||||
@ -356,11 +362,11 @@ Requires: badrequire
|
||||
|
||||
构建包并尝试安装它。 显示什么消息?
|
||||
|
||||
我们使用 `rpm` 命令来安装和删除 `utils` 包。 尝试使用 yum 或 DNF 安装软件包。 你必须与程序包位于同一目录中,或指定程序包的完整路径才能使其正常工作。
|
||||
我们使用 `rpm` 命令来安装和删除 `utils` 包。 尝试使用 `yum` 或 `dnf` 安装软件包。 你必须与程序包位于同一目录中,或指定程序包的完整路径才能使其正常工作。
|
||||
|
||||
### 总结
|
||||
|
||||
在这里看一下创建 rpm 包的基础知识,我们没有涉及很多标签和很多部分。 下面列出的资源可以提供更多信息。 构建 rpm 包并不困难;你只需要正确的信息。 我希望这对你有所帮助——我花了几个月的时间来自己解决问题。
|
||||
在这篇对创建 rpm 包的基础知识的概览中,我们没有涉及很多标签和很多部分。 下面列出的资源可以提供更多信息。 构建 rpm 包并不困难;你只需要正确的信息。 我希望这对你有所帮助——我花了几个月的时间来自己解决问题。
|
||||
|
||||
我们没有涵盖源代码构建,但如果你是开发人员,那么从这一点开始应该是一个简单的步骤。
|
||||
|
||||
@ -368,9 +374,9 @@ Requires: badrequire
|
||||
|
||||
### 资料
|
||||
|
||||
- Edward C. Baily,Maximum RPM,Sams著,于2000年,ISBN 0-672-31105-4
|
||||
- Edward C. Baily,[Maximum RPM][1],更新在线版本
|
||||
- [RPM文档][4]:此网页列出了 rpm 的大多数可用在线文档。 它包括许多其他网站的链接和有关 rpm 的信息。
|
||||
- Edward C. Baily,《Maximum RPM》,Sams 出版于 2000 年,ISBN 0-672-31105-4
|
||||
- Edward C. Baily,《[Maximum RPM][1]》,更新在线版本
|
||||
- [RPM 文档][4]:此网页列出了 rpm 的大多数可用在线文档。 它包括许多其他网站的链接和有关 rpm 的信息。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -379,7 +385,7 @@ via: https://opensource.com/article/18/9/how-build-rpm-packages
|
||||
作者:[David Both][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[Flowsnow](https://github.com/Flowsnow)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
@ -387,4 +393,4 @@ via: https://opensource.com/article/18/9/how-build-rpm-packages
|
||||
[1]: http://ftp.rpm.org/max-rpm/
|
||||
[2]: http://rpm.org/index.html
|
||||
[3]: http://www.both.org/?p=960
|
||||
[4]: http://rpm.org/documentation.html
|
||||
[4]: http://rpm.org/documentation.html
|
@ -1,3 +1,5 @@
|
||||
fuowang 翻译中
|
||||
|
||||
Using Your Own Private Registry with Docker Enterprise Edition
|
||||
======
|
||||
|
||||
|
@ -1,162 +0,0 @@
|
||||
FSSlc translating
|
||||
|
||||
A Cross-platform High-quality GIF Encoder
|
||||
======
|
||||
|
||||
![](https://www.ostechnix.com/wp-content/uploads/2018/09/gifski-720x340.png)
|
||||
|
||||
As a content writer, I needed to add images in my articles. Sometimes, it is better to add videos or gif images to explain the concept a bit easier. The readers can easily understand the guide much better by watching the output in video or gif format than the text. The day before, I have written about [**Flameshot**][1], a feature-rich and powerful screenshot tool for Linux. Today, I will show you how to make high quality gif images either from a video or set of images. Meet **Gifski** , a cross-platform, open source, command line High-quality GIF encoder based on **Pngquant**.
|
||||
|
||||
For those wondering, pngquant is a command line lossy PNG image compressor. Trust me, pngquant is one of the best loss-less PNG compressor that I ever use. It compresses PNG images **upto 70%** without losing the original quality and and preserves full alpha transparency. The compressed images are compatible with all web browsers and operating systems. Since Gifski is based on Pngquant, it uses pngquant’s features for creating efficient GIF animations. Gifski is capable of creating animated GIFs that use thousands of colors per frame. Gifski is also requires **ffmpeg** to convert video into PNG images.
|
||||
|
||||
### **Installing Gifski**
|
||||
|
||||
Make sure you have installed FFMpeg and Pngquant.
|
||||
|
||||
FFmpeg is available in the default repositories of most Linux distributions, so you can install it using the default package manager. For installation instructions, refer the following guide.
|
||||
|
||||
Pngquant is available in [**AUR**][2]. To install it in Arch-based systems, use any AUR helper programs like [**Yay**][3].
|
||||
```
|
||||
$ yay -S pngquant
|
||||
|
||||
```
|
||||
|
||||
On Debian-based systems, run:
|
||||
```
|
||||
$ sudo apt install pngquant
|
||||
|
||||
```
|
||||
|
||||
If pngquant is not available for your distro, compile and install it from source. You will need **`libpng-dev`** package installed with development headers.
|
||||
```
|
||||
$ git clone --recursive https://github.com/kornelski/pngquant.git
|
||||
|
||||
$ make
|
||||
|
||||
$ sudo make install
|
||||
|
||||
```
|
||||
|
||||
After installing the prerequisites, install Gifski. You can install it using **cargo** if you have installed [**Rust**][4] programming language.
|
||||
```
|
||||
$ cargo install gifski
|
||||
|
||||
```
|
||||
|
||||
You can also get it with [**Linuxbrew**][5] package manager.
|
||||
```
|
||||
$ brew install gifski
|
||||
|
||||
```
|
||||
|
||||
If you don’t want to install cargo or Linuxbrew, download the latest binary executables from [**releases page**][6] and compile and install gifski manually.
|
||||
|
||||
### Create high-quality GIF animations using Gifski high-quality GIF encoder
|
||||
|
||||
Go to the location where you have kept the PNG images and run the following command to create GIF animation from the set of images:
|
||||
```
|
||||
$ gifski -o file.gif *.png
|
||||
|
||||
```
|
||||
|
||||
Here file.gif is the final output gif animation.
|
||||
|
||||
Gifski has also some other additional features, like;
|
||||
|
||||
* Create GIF animation with specific dimension
|
||||
* Show specific number of animations per second
|
||||
* Encode with a specific quality
|
||||
* Encode faster
|
||||
* Encode images exactly in the order given, rather than sorted
|
||||
|
||||
|
||||
|
||||
To create GIF animation with specific dimension, for example width=800 and height=400, use the following command:
|
||||
```
|
||||
$ gifski -o file.gif -W 800 -H 400 *.png
|
||||
|
||||
```
|
||||
|
||||
You can set how many number of animation frames per second you want in the gif animation. The default value is **20**. To do so, run:
|
||||
```
|
||||
$ gifski -o file.gif --fps 1 *.png
|
||||
|
||||
```
|
||||
|
||||
In the above example, I have used one animation frame per second.
|
||||
|
||||
We can encode with specific quality on the scale of 1-100. Obviously, the lower quality may give smaller file and higher quality give bigger seize gif animation.
|
||||
```
|
||||
$ gifski -o file.gif --quality 50 *.png
|
||||
|
||||
```
|
||||
|
||||
Gifski will take more time when you encode large number of images. To make the encoding process 3 times faster than usual speed, run:
|
||||
```
|
||||
$ gifski -o file.gif --fast *.png
|
||||
|
||||
```
|
||||
|
||||
Please note that it will reduce quality to 10% and create bigger animation file.
|
||||
|
||||
To encode images exactly in the order given (rather than sorted), use **`--nosort`** option.
|
||||
```
|
||||
$ gifski -o file.gif --nosort *.png
|
||||
|
||||
```
|
||||
|
||||
If you do not to loop the GIF, simple use **`--once`** option.
|
||||
```
|
||||
$ gifski -o file.gif --once *.png
|
||||
|
||||
```
|
||||
|
||||
**Create GIF animation from Video file**
|
||||
|
||||
Some times you might want to an animated file from a video. It is also possible. This is where FFmpeg comes in help. First convert the video into PNG frames first like below.
|
||||
```
|
||||
$ ffmpeg -i video.mp4 frame%04d.png
|
||||
|
||||
```
|
||||
|
||||
The above command makes image files namely “frame0001.png”, “frame0002.png”, “frame0003.png”…, etc. from video.mp4 (%04d makes the frame number) and save them in the current working directory.
|
||||
|
||||
After converting the image files, simply run the following command to make the animated GIF file.
|
||||
```
|
||||
$ gifski -o file.gif *.png
|
||||
|
||||
```
|
||||
|
||||
For more details, refer the help section.
|
||||
```
|
||||
$ gifski -h
|
||||
|
||||
```
|
||||
|
||||
Here is the sample animated file created using Gifski.
|
||||
|
||||
As you can see, the quality of the GIF file is really great.
|
||||
|
||||
And, that’s all for now. Hope this was useful. More good stuffs to come. Stay tuned!
|
||||
|
||||
Cheers!
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/gifski-a-cross-platform-high-quality-gif-encoder/
|
||||
|
||||
作者:[SK][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.ostechnix.com/author/sk/
|
||||
[1]: https://www.ostechnix.com/flameshot-a-simple-yet-powerful-feature-rich-screenshot-tool/
|
||||
[2]: https://aur.archlinux.org/packages/pngquant/
|
||||
[3]: https://www.ostechnix.com/yay-found-yet-another-reliable-aur-helper/
|
||||
[4]: https://www.ostechnix.com/install-rust-programming-language-in-linux/
|
||||
[5]: https://www.ostechnix.com/linuxbrew-common-package-manager-linux-mac-os-x/
|
||||
[6]: https://github.com/ImageOptim/gifski/releases
|
@ -0,0 +1,147 @@
|
||||
Gifski – 一个跨平台的高质量 GIF 编码器
|
||||
======
|
||||
|
||||
![](https://www.ostechnix.com/wp-content/uploads/2018/09/gifski-720x340.png)
|
||||
|
||||
作为一名文字工作者,我需要在我的文章中添加图片。有时为了更容易讲清楚某个概念,我还会添加视频或者 gif 动图,相比于文字,通过视频或者 gif 格式的输出,读者可以更容易地理解我的指导。前些天,我已经写了篇文章来介绍针对 Linux 的功能丰富的强大截屏工具 [**Flameshot**][1]。今天,我将向你展示如何从一段视频或者一些图片来制作高质量的 gif 动图。这个工具就是 **Gifski**,一个跨平台、开源、基于 **Pngquant** 的高质量命令行 GIF 编码器。
|
||||
|
||||
对于那些好奇 pngquant 是什么的读者,简单来说 pngquant 是一个针对 PNG 图片的无损压缩命令行工具。相信我,pngquant 是我使用过的最好的 PNG 无损压缩工具。它可以将 PNG 图片最高压缩 **70%** 而不会损失图片的原有质量并保存了所有的阿尔法透明度。经过压缩的图片可以在所有的网络浏览器和系统中使用。而 Gifski 是基于 Pngquant 的,它使用 pngquant 的功能来创建高质量的 GIF 动图。Gifski 能够创建每帧包含上千种颜色的 GIF 动图。Gifski 也需要 **ffmpeg** 来将视频转换为 PNG 图片。
|
||||
|
||||
### **安装 Gifski**
|
||||
|
||||
首先需要确保你安装了 FFMpeg 和 Pngquant。
|
||||
|
||||
FFmpeg 在大多数的 Linux 发行版的默认软件仓库中都可以获取到,所以你可以使用默认的包管理器来安装它。具体的安装过程,请参考下面链接中的指导。
|
||||
|
||||
- [在 Linux 中如何安装 FFmpeg](https://www.ostechnix.com/install-ffmpeg-linux/)
|
||||
|
||||
Pngquant 可以从 [**AUR**][2] 中获取到。要在基于 Arch 的系统安装它,使用任意一个 AUR 帮助程序即可,例如下面示例中的 [**Yay**][3]:
|
||||
```
|
||||
$ yay -S pngquant
|
||||
```
|
||||
|
||||
在基于 Debian 的系统中,运行:
|
||||
```
|
||||
$ sudo apt install pngquant
|
||||
```
|
||||
|
||||
假如在你使用的发行版中没有 pngquant,你可以从源码编译并安装它。为此你还需要安装 **`libpng-dev`** 包。
|
||||
```
|
||||
$ git clone --recursive https://github.com/kornelski/pngquant.git
|
||||
|
||||
$ make
|
||||
|
||||
$ sudo make install
|
||||
```
|
||||
|
||||
安装完上述依赖后,再安装 Gifski。假如你已经安装了 [**Rust**][4] 编程语言,你可以使用 **cargo** 来安装它:
|
||||
```
|
||||
$ cargo install gifski
|
||||
```
|
||||
|
||||
另外,你还可以使用 [**Linuxbrew**][5] 包管理器来安装它:
|
||||
```
|
||||
$ brew install gifski
|
||||
```
|
||||
|
||||
假如你不想安装 cargo 或 Linuxbrew,可以从它的 [发布页面][6] 下载最新的二进制程序,或者手动从源码编译并安装 gifski 。
|
||||
|
||||
### 使用 Gifski 来创建高质量的 GIF 动图
|
||||
|
||||
进入你保存 PNG 图片的目录,然后运行下面的命令来从这些图片创建 GIF 动图:
|
||||
```
|
||||
$ gifski -o file.gif *.png
|
||||
```
|
||||
|
||||
上面的 `file.gif` 为最后输出的 gif 动图。
|
||||
|
||||
Gifski 还有其他的特性,例如:
|
||||
|
||||
* 创建特定大小的 GIF 动图
|
||||
* 在每秒钟展示特定数目的动图
|
||||
* 以特定的质量编码
|
||||
* 更快速度的编码
|
||||
* 以给定顺序来编码图片,而不是以排序的结果来编码
|
||||
|
||||
为了创建特定大小的 GIF 动图,例如宽为 800,高为 400,可以使用下面的命令:
|
||||
```
|
||||
$ gifski -o file.gif -W 800 -H 400 *.png
|
||||
|
||||
```
|
||||
|
||||
你可以设定 GIF 动图在每秒钟展示多少帧,默认值是 **20**。为此,可以运行下面的命令:
|
||||
```
|
||||
$ gifski -o file.gif --fps 1 *.png
|
||||
```
|
||||
|
||||
在上面的例子中,我指定每秒钟展示 1 帧。
|
||||
|
||||
我们还能够以特定质量(1-100 范围内)来编码。显然,更低的质量将生成更小的文件,更高的质量将生成更大的 GIF 动图文件。
|
||||
```
|
||||
$ gifski -o file.gif --quality 50 *.png
|
||||
```
|
||||
|
||||
当需要编码大量图片时,Gifski 将会花费更多时间。如果想要编码过程加快到通常速度的 3 倍左右,可以运行:
|
||||
```
|
||||
$ gifski -o file.gif --fast *.png
|
||||
```
|
||||
|
||||
请注意上面的命令产生的 GIF 动图文件将减少 10% 的质量并且文件大小也会更大。
|
||||
|
||||
如果想让图片以某个给定的顺序(而不是通过排序)精确地被编码,可以使用 **`--nosort`** 选项。
|
||||
```
|
||||
$ gifski -o file.gif --nosort *.png
|
||||
```
|
||||
|
||||
假如你不想让 GIF 循环播放,只需要使用 **`--once`** 选项即可:
|
||||
```
|
||||
$ gifski -o file.gif --once *.png
|
||||
```
|
||||
|
||||
**从视频创建 GIF 动图**
|
||||
|
||||
有时或许你想从一个视频创建 GIF 动图。这也是可以做到的,这时候 FFmpeg 便能提供帮助。首先像下面这样,将视频转换成一系列的 PNG 图片:
|
||||
```
|
||||
$ ffmpeg -i video.mp4 frame%04d.png
|
||||
```
|
||||
|
||||
上面的命令将会从 `video.mp4` 这个视频文件创建名为“frame0001.png”、“frame0002.png”、“frame0003.png”等等形式的图片(其中的 `%04d` 代表帧数),然后将这些图片保存在当前的工作目录。
|
||||
|
||||
转换好图片后,只需要运行下面的命令便可以制作 GIF 动图了:
|
||||
```
|
||||
$ gifski -o file.gif *.png
|
||||
```
|
||||
|
||||
想知晓更多的细节,请参考它的帮助部分:
|
||||
```
|
||||
$ gifski -h
|
||||
```
|
||||
|
||||
下面是使用 Gifski 创建的示例 GIF 动图文件。
|
||||
|
||||
![](https://gif.ski/jazz-chromecast-ultra.gif)
|
||||
|
||||
正如你看到的那样,GIF 动图的质量看起来是非常好的。
|
||||
|
||||
好了,这就是全部内容了。希望这篇指南对你有所帮助。更多精彩内容即将呈现,请保持关注!
|
||||
|
||||
干杯吧!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/gifski-a-cross-platform-high-quality-gif-encoder/
|
||||
|
||||
作者:[SK][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[FSSlc](https://github.com/FSSlc)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.ostechnix.com/author/sk/
|
||||
[1]: https://www.ostechnix.com/flameshot-a-simple-yet-powerful-feature-rich-screenshot-tool/
|
||||
[2]: https://aur.archlinux.org/packages/pngquant/
|
||||
[3]: https://www.ostechnix.com/yay-found-yet-another-reliable-aur-helper/
|
||||
[4]: https://www.ostechnix.com/install-rust-programming-language-in-linux/
|
||||
[5]: https://www.ostechnix.com/linuxbrew-common-package-manager-linux-mac-os-x/
|
||||
[6]: https://github.com/ImageOptim/gifski/releases
|
Loading…
Reference in New Issue
Block a user