mirror of
https://github.com/LCTT/TranslateProject.git
synced 2025-03-09 01:30:10 +08:00
commit
7c945d5a8e
13
.travis.yml
13
.travis.yml
@ -1,18 +1,27 @@
|
||||
language: c
|
||||
language: minimal
|
||||
install:
|
||||
- sudo apt-get install jq
|
||||
- git clone --depth=1 -b gh-pages https://github.com/LCTT/TranslateProject/ build && rm -rf build/.git
|
||||
script:
|
||||
- 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then sh ./scripts/check.sh; fi'
|
||||
- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then sh ./scripts/badge.sh; fi'
|
||||
- 'if [ "$TRAVIS_EVENT_TYPE" = "cron" ]; then sh ./scripts/status.sh; fi'
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
# - status
|
||||
except:
|
||||
- gh-pages
|
||||
git:
|
||||
submodules: false
|
||||
depth: false
|
||||
deploy:
|
||||
provider: pages
|
||||
skip_cleanup: true
|
||||
github_token: $GITHUB_TOKEN
|
||||
local_dir: build
|
||||
on:
|
||||
branch: master
|
||||
branch:
|
||||
- master
|
||||
# - status
|
||||
|
@ -1,4 +0,0 @@
|
||||
# Linux中国翻译规范
|
||||
1. 翻译中出现的专有名词,可参见Dict.md中的翻译。
|
||||
2. 英文人名,如无中文对应译名,一般不译。
|
||||
2. 缩写词,一般不须翻译,可考虑旁注中文全名。
|
112
README.md
112
README.md
@ -1,44 +1,40 @@
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
[](https://lctt.github.io/new)
|
||||
[](https://lctt.github.io/translating)
|
||||
[](https://github.com/LCTT/TranslateProject/tree/master/translated)
|
||||
[](https://github.com/LCTT/TranslateProject/tree/master/published)
|
||||
|
||||
[](https://travis-ci.org/LCTT/TranslateProject)
|
||||
[](https://travis-ci.com/LCTT/TranslateProject)
|
||||
[](https://github.com/LCTT/TranslateProject/graphs/contributors)
|
||||
[](https://github.com/LCTT/TranslateProject/pulls?q=is%3Apr+is%3Aclosed)
|
||||
|
||||
简介
|
||||
-------------------------------
|
||||
|
||||
[LCTT](https://linux.cn/lctt/) 是“Linux中国”([https://linux.cn/](https://linux.cn/))的翻译组,负责从国外优秀媒体翻译 Linux 相关的技术、资讯、杂文等内容。
|
||||
[LCTT](https://linux.cn/lctt/) 是“Linux 中国”([https://linux.cn/](https://linux.cn/))的翻译组,负责从国外优秀媒体翻译 Linux 相关的技术、资讯、杂文等内容。
|
||||
|
||||
LCTT 已经拥有几百名活跃成员,并欢迎更多的 Linux 志愿者加入我们的团队。
|
||||
|
||||

|
||||

|
||||
|
||||
LCTT 的组成
|
||||
-------------------------------
|
||||
|
||||
**选题**,负责选择合适的内容,并将原文转换为 markdown 格式,提交到 LCTT 的 [TranslateProject](https://github.com/LCTT/TranslateProject) 库中。
|
||||
|
||||
**译者**,负责从选题中选择内容进行翻译。
|
||||
|
||||
**校对**,负责将初译的文章进行文字润色、技术校对等工作。
|
||||
|
||||
**发布**,负责将校对后的文章,排版进行发布。
|
||||
- LCTT 官网: [https://linux.cn/lctt/](https://linux.cn/lctt/)
|
||||
- LCTT 状态: [https://lctt.github.io/](https://lctt.github.io/)
|
||||
|
||||
加入我们
|
||||
-------------------------------
|
||||
|
||||
请首先加入翻译组的 QQ 群,群号是:198889102,加群时请说明是“志愿者”。加入后记得修改您的群名片为您的 GitHub 的 ID。
|
||||
请首先加入翻译组的 QQ 群,群号是:**198889102**,加群时请说明是“*志愿者*”。
|
||||
|
||||
加入的成员,请先阅读 [WIKI 如何开始](https://github.com/LCTT/TranslateProject/wiki/01-如何开始)。
|
||||
加入的成员,请:
|
||||
|
||||
1. 修改你的 QQ 群名片为“译者-您的_GitHub_ID”。
|
||||
2. 阅读 [WIKI](http://lctt.github.io/wiki) 了解如何开始。
|
||||
3. 遇到不解之处,请在群内发问。
|
||||
|
||||
如何开始
|
||||
-------------------------------
|
||||
|
||||
请阅读 [WIKI](https://github.com/LCTT/TranslateProject/wiki)。
|
||||
请阅读 [WIKI](http://lctt.github.io/wiki)。如需要协助,请在群内发问。
|
||||
|
||||
历史
|
||||
-------------------------------
|
||||
@ -79,44 +75,52 @@ LCTT 的组成
|
||||
* 2018/08/17 提升 pityonline 为核心成员,担任校对,并接受他的建议采用 PR 审核模式。
|
||||
* 2018/09/10 [LCTT 五周年](https://linux.cn/article-9999-1.html)。
|
||||
* 2018/10/25 重构了 CI,感谢 vizv、lujun9972、bestony。
|
||||
* 2018/11/13 [成立了项目管理委员会(PMC)](https://linux.cn/article-10279-1.html),初始成员为:@wxy (主席)、@oska874、@lujun9972、@bestony、@pityonline、@geekpi、@qhwdw。
|
||||
|
||||
核心成员
|
||||
|
||||
项目管理委员及核心成员
|
||||
-------------------------------
|
||||
|
||||
目前 LCTT 核心成员有:
|
||||
LCTT 现由项目管理委员会(PMC)进行管理,成员如下:
|
||||
|
||||
- 组长 @wxy,
|
||||
- 选题 @oska874,
|
||||
- 选题 @lujun9972,
|
||||
- 技术 @bestony,
|
||||
- 校对 @jasminepeng,
|
||||
- 校对 @pityonline,
|
||||
- 钻石译者 @geekpi,
|
||||
- 钻石译者 @qhwdw,
|
||||
- 钻石译者 @GOLinux,
|
||||
- 核心成员 @GHLandy,
|
||||
- 核心成员 @martin2011qi,
|
||||
- 核心成员 @ictlyh,
|
||||
- 核心成员 @strugglingyouth,
|
||||
- 核心成员 @FSSlc,
|
||||
- 核心成员 @zpl1025,
|
||||
- 核心成员 @runningwater,
|
||||
- 核心成员 @bazz2,
|
||||
- 核心成员 @Vic020,
|
||||
- 核心成员 @alim0x,
|
||||
- 核心成员 @tinyeyeser,
|
||||
- 核心成员 @Locez,
|
||||
- 核心成员 @ucasFL,
|
||||
- 核心成员 @rusking,
|
||||
- 核心成员 @MjSeven
|
||||
- 前任选题 @DeadFire,
|
||||
- 前任校对 @reinoir222,
|
||||
- 前任校对 @PurlingNayuki,
|
||||
- 前任校对 @carolinewuyan,
|
||||
- 功勋成员 @vito-L,
|
||||
- 功勋成员 @willqian,
|
||||
- 功勋成员 @vizv,
|
||||
- 功勋成员 @dongfengweixiao,
|
||||
- 🎩 主席 @wxy
|
||||
- 🎩 选题 @oska874
|
||||
- 🎩 选题 @lujun9972
|
||||
- 🎩 技术 @bestony
|
||||
- 🎩 校对 @pityonline
|
||||
- 🎩 译者 @geekpi
|
||||
- 🎩 译者 @qhwdw
|
||||
|
||||
目前 LCTT 核心成员有:
|
||||
|
||||
- ❤️ 核心成员 @vizv
|
||||
- ❤️ 核心成员 @zpl1025
|
||||
- ❤️ 核心成员 @runningwater
|
||||
- ❤️ 核心成员 @FSSlc
|
||||
- ❤️ 核心成员 @Vic020
|
||||
- ❤️ 核心成员 @alim0x
|
||||
- ❤️ 核心成员 @martin2011qi
|
||||
- ❤️ 核心成员 @Locez
|
||||
- ❤️ 核心成员 @ucasFL
|
||||
- ❤️ 核心成员 @MjSeven
|
||||
|
||||
曾经做出了巨大贡献的核心成员,被列入荣誉榜:
|
||||
|
||||
- 🏆 前任选题 @DeadFire
|
||||
- 🏆 前任校对 @reinoir222
|
||||
- 🏆 前任校对 @PurlingNayuki
|
||||
- 🏆 前任校对 @carolinewuyan
|
||||
- 🏆 前任校对 @jasminepeng
|
||||
- 🏆 功勋成员 @tinyeyeser
|
||||
- 🏆 功勋成员 @vito-L
|
||||
- 🏆 功勋成员 @willqian
|
||||
- 🏆 功勋成员 @GOLinux
|
||||
- 🏆 功勋成员 @bazz2
|
||||
- 🏆 功勋成员 @ictlyh
|
||||
- 🏆 功勋成员 @dongfengweixiao
|
||||
- 🏆 功勋成员 @strugglingyouth
|
||||
- 🏆 功勋成员 @GHLandy
|
||||
- 🏆 功勋成员 @rusking
|
||||
|
||||
全部成员列表请参见: https://linux.cn/lctt-list/ 。
|
||||
|
||||
|
@ -0,0 +1,54 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (qhwdw)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10429-1.html)
|
||||
[#]: subject: (Computer Laboratory – Raspberry Pi: Lesson 0 Introduction)
|
||||
[#]: via: (https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/introduction.html)
|
||||
[#]: author: (Robert Mullins http://www.cl.cam.ac.uk/~rdm34)
|
||||
|
||||
计算机实验室之树莓派:课程 0 简介
|
||||
======
|
||||
|
||||
这个课程简介不包含实践内容,但它解释了一个操作系统的基本概念、汇编代码、和其它很重要的一些基本原理。如果你想直接进入实践环节,跳过本课程并不会有什么问题。
|
||||
|
||||
### 1、操作系统
|
||||
|
||||
操作系统就是一个非常复杂的程序。它的任务就是组织安排计算机上的其它程序,包括共享计算机的时间、内存、硬件和其它资源。你可能听说过的一些比较大的桌面操作系统家族有 GNU/Linux、Mac OS X 和 Microsoft Windows。其它的设备比如电话,也需要操作系统,它可能使用的操作系统是 Android、iOS 和 Windows Phone。 [^1]
|
||||
|
||||
由于操作系统是用来与计算机系统上的硬件进行交互的,所以它必须了解系统上硬件专有的信息。为了能让操作系统适用于各种类型的计算机,发明了 **驱动程序** 的概念。驱动程序是为了能够让操作系统与特定的硬件进行交互而添加(并可删除)到操作系统上的一小部分代码。在本课程中,我们并不涉及如何创建可删除的驱动程序,而是专注于特定的一个硬件:树莓派。
|
||||
|
||||
操作系统有各种不同的设计方式,在本课程中,我们只触及操作系统设计的皮毛。本课程中,我们主要专注于操作系统与各种硬件的交互部分,因为这经常是比较棘手的部分,并且也是在网络上文档和帮助最少的部分。
|
||||
|
||||
### 2、汇编代码
|
||||
|
||||
> 处理器每秒可以执行上百万的指令,但是这些指令必须要简单。
|
||||
|
||||
本课程几乎要完全靠汇编代码来写。汇编代码非常接近计算机的底层。计算机其实是靠一个叫处理器的设备来工作的,处理器能够执行像加法这样的简单任务,还有一组叫做 RAM 的芯片,它能够用来保存数字。当计算机通电后,处理器执行程序员给定的一系列指令,这将导致内存中的数字发生变化,以及与连接的硬件进行交互。汇编代码只是将这些机器命令转换为人类可读的文本。
|
||||
|
||||
常规的编程就是,程序员使用编程语言,比如 C++、Java、C#、Basic 等等来写代码,然后一个叫编译器的程序将程序员写的代码转换成汇编代码,然后进一步转换为二进制代码。[^2] 二进制代码才是计算机真正能够理解的东西,但它是人类无法读取的东西。汇编代码比二进制代码好一点,至少它的命令是人类可读的,但它仍然让人很沮丧。请记住,你用汇编代码写的每个命令都是处理器可以直接认识的,因此这些命令设计的很简单,因为物理电路必须能够处理每个命令。
|
||||
|
||||
![Compiler process][1]
|
||||
|
||||
和普通编程一样,也有很多不同的汇编代码编程语言,但与普通编程不一样的是,每个汇编编程语言是面对不同的处理器的,每种处理器设计为去理解不同的语言。因此,用一个针对某种机器设计的汇编语言所写的汇编代码,是不能在其它种类的机器上运行的。很多情况下,这都是一个大灾难,因此每个程序都必须在使用它的不同种类的机器上重写一遍,但对于操作系统,这不是个问题,因为在不同的硬件上它必须得重写。尽管如此,大多数操作系统都是用 C++ 或 C 来写的,这样它们就可以很容易地在不同种类的硬件上使用,只需要重写那些必须用汇编代码来实现的部分即可。
|
||||
|
||||
现在,你已经准备好进入第一节课了,它是 [课程 1 OK01][2]
|
||||
|
||||
[^1]: 要查看更完整的操作系统列表,请参照:[操作系统列表 - Wikipedia](http://en.wikipedia.org/wiki/List_of_operating_systems)
|
||||
[^2]: 当然,我简化了普通编程的这种解释,实际上它在很大程度上取决于语言和机器。感兴趣的话,参见 [编译器 - Wikipedia](http://en.wikipedia.org/wiki/Compiler)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/introduction.html
|
||||
|
||||
作者:[Robert Mullins][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://www.cl.cam.ac.uk/~rdm34
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/compiling.png
|
||||
[2]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok01.html
|
@ -0,0 +1,233 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (qhwdw)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10458-1.html)
|
||||
[#]: subject: (Computer Laboratory – Raspberry Pi: Lesson 1 OK01)
|
||||
[#]: via: (https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok01.html)
|
||||
[#]: author: (Robert Mullins http://www.cl.cam.ac.uk/~rdm34)
|
||||
|
||||
计算机实验室之树莓派:课程 1 OK01
|
||||
======
|
||||
|
||||
OK01 课程讲解了树莓派如何入门,以及在树莓派上如何启用靠近 RCA 和 USB 端口的 OK 或 ACT 的 LED 指示灯。这个指示灯最初是为了指示 OK 状态的,但它在第二版的树莓派上被改名为 ACT。
|
||||
|
||||
### 1、入门
|
||||
|
||||
我们假设你已经访问了[下载][1]页面,并且已经获得了必需的 GNU 工具链。也下载了一个称为操作系统模板的文件。请下载这个文件并在一个新目录中解开它。
|
||||
|
||||
### 2、开始
|
||||
|
||||
现在,你已经展开了这个模板文件,在 `source` 目录中创建一个名为 `main.s` 的文件。这个文件包含了这个操作系统的代码。具体来看,这个文件夹的结构应该像下面这样:
|
||||
|
||||
```
|
||||
build/
|
||||
(empty)
|
||||
source/
|
||||
main.s
|
||||
kernel.ld
|
||||
LICENSE
|
||||
Makefile
|
||||
```
|
||||
|
||||
用文本编辑器打开 `main.s` 文件,这样我们就可以输入汇编代码了。树莓派使用了称为 ARMv6 的汇编代码变体,这就是我们即将要写的汇编代码类型。
|
||||
|
||||
> 扩展名为 `.s` 的文件一般是汇编代码,需要记住的是,在这里它是 ARMv6 的汇编代码。
|
||||
|
||||
首先,我们复制下面的这些命令。
|
||||
|
||||
```
|
||||
.section .init
|
||||
.globl _start
|
||||
_start:
|
||||
```
|
||||
|
||||
实际上,上面这些指令并没有在树莓派上做任何事情,它们是提供给汇编器的指令。汇编器是一个转换程序,它将我们能够理解的汇编代码转换成树莓派能够理解的机器代码。在汇编代码中,每个行都是一个新的命令。上面的第一行告诉汇编器 [^1] 在哪里放我们的代码。我们提供的模板中将它放到一个名为 `.init` 的节中的原因是,它是输出的起始点。这很重要,因为我们希望确保我们能够控制哪个代码首先运行。如果不这样做,首先运行的代码将是按字母顺序排在前面的代码!`.section` 命令简单地告诉汇编器,哪个节中放置代码,从这个点开始,直到下一个 `.section` 或文件结束为止。
|
||||
|
||||
```
|
||||
在汇编代码中,你可以跳行、在命令前或后放置空格去提升可读性。
|
||||
```
|
||||
|
||||
接下来两行是停止一个警告消息,它们并不重要。[^2]
|
||||
|
||||
### 3、第一行代码
|
||||
|
||||
现在,我们正式开始写代码。计算机执行汇编代码时,是简单地一行一行按顺序执行每个指令,除非明确告诉它不这样做。每个指令都是开始于一个新行。
|
||||
|
||||
复制下列指令。
|
||||
|
||||
```
|
||||
ldr r0,=0x20200000
|
||||
```
|
||||
|
||||
> `ldr reg,=val` 将数字 `val` 加载到名为 `reg` 的寄存器中。
|
||||
|
||||
那是我们的第一个命令。它告诉处理器将数字 `0x20200000` 保存到寄存器 `r0` 中。在这里我需要去回答两个问题,<ruby>寄存器<rt>register</rt></ruby>是什么?`0x20200000` 是一个什么样的数字?
|
||||
|
||||
寄存器在处理器中就是一个极小的内存块,它是处理器保存正在处理的数字的地方。处理器中有很多寄存器,很多都有专门的用途,我们在后面会一一接触到它们。最重要的有十三个(命名为 `r0`、`r1`、`r2`、…、`r9`、`r10`、`r11`、`r12`),它们被称为通用寄存器,你可以使用它们做任何计算。由于是写我们的第一行代码,我们在示例中使用了 `r0`,当然你可以使用它们中的任何一个。只要后面始终如一就没有问题。
|
||||
|
||||
> 树莓派上的一个单独的寄存器能够保存任何介于 `0` 到 `4,294,967,295`(含)之间的任意整数,它可能看起来像一个很大的内存,实际上它仅有 32 个二进制比特。
|
||||
|
||||
`0x20200000` 确实是一个数字。只不过它是以十六进制表示的。下面的内容详细解释了十六进制的相关信息:
|
||||
|
||||
> 延伸阅读:十六进制解释
|
||||
|
||||
> 十六进制是另一种表示数字的方式。你或许只知道十进制的数字表示方法,十进制共有十个数字:`0`、`1`、`2`、`3`、`4`、`5`、`6`、`7`、`8` 和 `9`。十六进制共有十六个数字:`0`、`1`、`2`、`3`、`4`、`5`、`6`、`7`、`8`、`9`、`a`、`b`、`c`、`d`、`e` 和 `f`。
|
||||
|
||||
> 你可能还记得十进制是如何用位制来表示的。即最右侧的数字是个位,紧接着的左边一位是十位,再接着的左边一位是百位,依此类推。也就是说,它的值是 100 × 百位的数字,再加上 10 × 十位的数字,再加上 1 × 个位的数字。
|
||||
|
||||
> ![567 is 5 hundreds, 6 tens and 7 units.][2]
|
||||
|
||||
> 从数学的角度来看,我们可以发现规律,最右侧的数字是 10<sup>0</sup> = 1s,紧接着的左边一位是 10<sup>1</sup> = 10s,再接着是 10<sup>2</sup> = 100s,依此类推。我们设定在系统中,0 是最低位,紧接着是 1,依此类推。但如果我们使用一个不同于 10 的数字为幂底会是什么样呢?我们在系统中使用的十六进制就是这样的一个数字。
|
||||
|
||||
> ![567 is 5x10^2+6x10^1+7x10^0][3]
|
||||
|
||||
> ![567 = 5x10^2+6x10^1+7x10^0 = 2x16^2+3x16^1+7x16^0][4]
|
||||
|
||||
> 上面的数学等式表明,十进制的数字 567 等于十六进制的数字 237。通常我们需要在系统中明确它们,我们使用下标 <sub>10</sub> 表示它是十进制数字,用下标 <sub>16</sub> 表示它是十六进制数字。由于在汇编代码中写上下标的小数字很困难,因此我们使用 0x 来表示它是一个十六进制的数字,因此 0x237 的意思就是 237<sub>16</sub> 。
|
||||
|
||||
> 那么,后面的 `a`、`b`、`c`、`d`、`e` 和 `f` 又是什么呢?好问题!在十六进制中为了能够写每个数字,我们就需要额外的东西。例如 9<sub>16</sub> = 9×16<sup>0</sup> = 9<sub>10</sub> ,但是 10<sub>16</sub> = 1×16<sup>1</sup> + 1×16<sup>0</sup> = 16<sub>10</sub> 。因此,如果我们只使用 0、1、2、3、4、5、6、7、8 和 9,我们就无法写出 10<sub>10</sub> 、11<sub>10</sub> 、12<sub>10</sub> 、13<sub>10</sub> 、14<sub>10</sub> 、15<sub>10</sub> 。因此我们引入了 6 个新的数字,这样 a<sub>16</sub> = 10<sub>10</sub> 、b<sub>16</sub> = 11<sub>10</sub> 、c<sub>16</sub> = 12<sub>10</sub> 、d<sub>16</sub> = 13<sub>10</sub> 、e<sub>16</sub> = 14<sub>10</sub> 、f<sub>16</sub> = 15<sub>10</sub> 。
|
||||
|
||||
> 所以,我们就有了另一种写数字的方式。但是我们为什么要这么麻烦呢?好问题!由于计算机总是工作在二进制中,事实证明,十六进制是非常有用的,因为每个十六进制数字正好是四个二进制数字的长度。这种方法还有另外一个好处,那就是许多计算机的数字都是十六进制的整数倍,而不是十进制的整数倍。比如,我在上面的汇编代码中使用的一个数字 20200000<sub>16</sub> 。如果我们用十进制来写,它就是一个不太好记住的数字 538968064<sub>10</sub> 。
|
||||
|
||||
> 我们可以用下面的简单方法将十进制转换成十六进制:
|
||||
|
||||
> ![Conversion example][5]
|
||||
|
||||
> 1. 我们以十进制数字 567 为例来说明。
|
||||
> 2. 将十进制数字 567 除以 16 并计算其余数。例如 567 ÷ 16 = 35 余数为 7。
|
||||
> 3. 在十六进制中余数就是答案中的最后一位数字,在我们的例子中它是 7。
|
||||
> 4. 重复第 2 步和第 3 步,直到除法结果的整数部分为 0。例如 35 ÷ 16 = 2 余数为 3,因此 3 就是答案中的下一位。2 ÷ 16 = 0 余数为 2,因此 2 就是答案的接下来一位。
|
||||
> 5. 一旦除法结果的整数部分为 0 就结束了。答案就是反序的余数,因此 567<sub>10</sub> = 237<sub>16</sub>。
|
||||
|
||||
> 转换十六进制数字为十进制,也很容易,将数字展开即可,因此 237<sub>16</sub> = 2×16<sup>2</sup> + 3×16<sup>1</sup> +7 ×16<sup>0</sup> = 2×256 + 3×16 + 7×1 = 512 + 48 + 7 = 567。
|
||||
|
||||
因此,我们所写的第一个汇编命令是将数字 20200000<sub>16</sub> 加载到寄存器 `r0` 中。那个命令看起来似乎没有什么用,但事实并非如此。在计算机中,有大量的内存块和设备。为了能够访问它们,我们给每个内存块和设备指定了一个地址。就像邮政地址或网站地址一样,它用于标识我们想去访问的内存块或设备的位置。计算机中的地址就是一串数字,因此上面的数字 20200000<sub>16</sub> 就是 GPIO 控制器的地址。这个地址是由制造商的设计所决定的,他们也可以使用其它地址(只要不与其它的冲突即可)。我之所以知道这个地址是 GPIO 控制器的地址是因为我看了它的手册,[^3] 地址的使用没有专门的规范(除了它们都是以十六进制表示的大数以外)。
|
||||
|
||||
### 4、启用输出
|
||||
|
||||
![A diagram showing key parts of the GPIO controller.][6]
|
||||
|
||||
阅读了手册可以得知,我们需要给 GPIO 控制器发送两个消息。我们必须用它的语言告诉它,如果我们这样做了,它将非常乐意实现我们的意图,去打开 OK 的 LED 指示灯。幸运的是,它是一个非常简单的芯片,为了让它能够理解我们要做什么,只需要给它设定几个数字即可。
|
||||
|
||||
```
|
||||
mov r1,#1
|
||||
lsl r1,#18
|
||||
str r1,[r0,#4]
|
||||
```
|
||||
|
||||
> `mov reg,#val` 将数字 `val` 放到名为 `reg` 的寄存器中。
|
||||
|
||||
> `lsl reg,#val` 将寄存器 `reg` 中的二进制操作数左移 `val` 位。
|
||||
|
||||
> `str reg,[dest,#val]` 将寄存器 `reg` 中的数字保存到地址 `dest + val` 上。
|
||||
|
||||
这些命令的作用是在 GPIO 的第 16 号插针上启用输出。首先我们在寄存器 `r1` 中获取一个必需的值,接着将这个值发送到 GPIO 控制器。因此,前两个命令是尝试取值到寄存器 `r1` 中,我们可以像前面一样使用另一个命令 `ldr` 来实现,但 `lsl` 命令对我们后面能够设置任何给定的 GPIO 针比较有用,因此从一个公式中推导出值要比直接写入来好一些。表示 OK 的 LED 灯是直接连线到 GPIO 的第 16 号针脚上的,因此我们需要发送一个命令去启用第 16 号针脚。
|
||||
|
||||
寄存器 `r1` 中的值是启用 LED 针所需要的。第一行命令将数字 1<sub>10</sub> 放到 `r1` 中。在这个操作中 `mov` 命令要比 `ldr` 命令快很多,因为它不需要与内存交互,而 `ldr` 命令是将需要的值从内存中加载到寄存器中。尽管如此,`mov` 命令仅能用于加载某些值。[^4] 在 ARM 汇编代码中,基本上每个指令都使用一个三字母代码表示。它们被称为助记词,用于表示操作的用途。`mov` 是 “move” 的简写,而 `ldr` 是 “load register” 的简写。`mov` 是将第二个参数 `#1` 移动到前面的 `r1` 寄存器中。一般情况下,`#` 肯定是表示一个数字,但我们已经看到了不符合这种情况的一个反例。
|
||||
|
||||
第二个指令是 `lsl`(逻辑左移)。它的意思是将第一个参数的二进制操作数向左移第二个参数所表示的位数。在这个案例中,将 1<sub>10</sub> (即 1<sub>2</sub> )向左移 18 位(将它变成 1000000000000000000<sub>2</sub>=262144<sub>10</sub> )。
|
||||
|
||||
如果你不熟悉二进制表示法,可以看下面的内容:
|
||||
|
||||
> 延伸阅读: 二进制解释
|
||||
|
||||
> 与十六进制一样,二进制是写数字的另一种方法。在二进制中只有两个数字,即 `0` 和 `1`。它在计算机中非常有用,因为我们可以用电路来实现它,即电流能够通过电路表示为 `1`,而电流不能通过电路表示为 `0`。这就是计算机能够完成真实工作和做数学运算的原理。尽管二进制只有两个数字,但它却能够表示任何一个数字,只是写起来有点长而已。
|
||||
|
||||
> ![567 in decimal = 1000110111 in binary][7]
|
||||
|
||||
> 这个图片展示了 567<sub>10</sub> 的二进制表示是 1000110111<sub>2</sub> 。我们使用下标 2 来表示这个数字是用二进制写的。
|
||||
|
||||
> 我们在汇编代码中大量使用二进制的其中一个巧合之处是,数字可以很容易地被 `2` 的幂(即 `1`、`2`、`4`、`8`、`16`)乘或除。通常乘法和除法都是非常难的,而在某些特殊情况下却变得非常容易,所以二进制非常重要。
|
||||
|
||||
> ![13*4 = 52, 1101*100=110100][8]
|
||||
|
||||
> 将一个二进制数字左移 `n` 位就相当于将这个数字乘以 2<sup>n</sup>。因此,如果我们想将一个数乘以 4,我们只需要将这个数字左移 2 位。如果我们想将它乘以 256,我们只需要将它左移 8 位。如果我们想将一个数乘以 12 这样的数字,我们可以有一个替代做法,就是先将这个数乘以 8,然后再将那个数乘以 4,最后将两次相乘的结果相加即可得到最终结果(N × 12 = N × (8 + 4) = N × 8 + N × 4)。
|
||||
|
||||
> ![53/16 = 3, 110100/10000=11][9]
|
||||
|
||||
> 右移一个二进制数 `n` 位就相当于这个数除以 2<sup>n</sup> 。在右移操作中,除法的余数位将被丢弃。不幸的是,如果对一个不能被 2 的幂次方除尽的二进制数字做除法是非常难的,这将在 [课程 9 Screen04][10] 中讲到。
|
||||
|
||||
> ![Binary Terminology][11]
|
||||
|
||||
> 这个图展示了二进制常用的术语。一个<ruby>比特<rt>bit</rt></ruby>就是一个单独的二进制位。一个“<ruby>半字节<rt>nibble</rt></ruby>“ 是 4 个二进制位。一个<ruby>字节<rt>byte</rt></ruby>是 2 个半字节,也就是 8 个比特。<ruby>半字<rt>half</rt></ruby>是指一个字长度的一半,这里是 2 个字节。<ruby>字<rt>word</rt></ruby>是指处理器上寄存器的大小,因此,树莓派的字长是 4 字节。按惯例,将一个字最高有效位标识为 31,而将最低有效位标识为 0。顶部或最高位表示最高有效位,而底部或最低位表示最低有效位。一个 kilobyte(KB)就是 1000 字节,一个 megabyte 就是 1000 KB。这样表示会导致一些困惑,到底应该是 1000 还是 1024(二进制中的整数)。鉴于这种情况,新的国际标准规定,一个 KB 等于 1000 字节,而一个 Kibibyte(KiB)是 1024 字节。一个 Kb 是 1000 比特,而一个 Kib 是 1024 比特。
|
||||
|
||||
> 树莓派默认采用小端法,也就是说,从你刚才写的地址上加载一个字节时,是从一个字的低位字节开始加载的。
|
||||
|
||||
再强调一次,我们只有去阅读手册才能知道我们所需要的值。手册上说,GPIO 控制器中有一个 24 字节的集合,由它来决定 GPIO 针脚的设置。第一个 4 字节与前 10 个 GPIO 针脚有关,第二个 4 字节与接下来的 10 个针脚有关,依此类推。总共有 54 个 GPIO 针脚,因此,我们需要 6 个 4 字节的一个集合,总共是 24 个字节。在每个 4 字节中,每 3 个比特与一个特定的 GPIO 针脚有关。我们想去启用的是第 16 号 GPIO 针脚,因此我们需要去设置第二组 4 字节,因为第二组的 4 字节用于处理 GPIO 针脚的第 10-19 号,而我们需要第 6 组 3 比特,它在上面的代码中的编号是 18(6×3)。
|
||||
|
||||
最后的 `str`(“store register”)命令去保存第一个参数中的值,将寄存器 `r1` 中的值保存到后面的表达式计算出来的地址上。这个表达式可以是一个寄存器,在上面的例子中是 `r0`,我们知道 `r0` 中保存了 GPIO 控制器的地址,而另一个值是加到它上面的,在这个例子中是 `#4`。它的意思是将 GPIO 控制器地址加上 `4` 得到一个新的地址,并将寄存器 `r1` 中的值写到那个地址上。那个地址就是我们前面提到的第二组 4 字节的位置,因此,我们发送我们的第一个消息到 GPIO 控制器上,告诉它准备启用 GPIO 第 16 号针脚的输出。
|
||||
|
||||
### 5、生命的信号
|
||||
|
||||
现在,LED 已经做好了打开准备,我们还需要实际去打开它。意味着需要给 GPIO 控制器发送一个消息去关闭 16 号针脚。是的,你没有看错,就是要发送一个关闭的消息。芯片制造商认为,在 GPIO 针脚关闭时打开 LED 更有意义。[^5] 硬件工程师经常做这种反常理的决策,似乎是为了让操作系统开发者保持警觉。可以认为是给自己的一个警告。
|
||||
|
||||
```
|
||||
mov r1,#1
|
||||
lsl r1,#16
|
||||
str r1,[r0,#40]
|
||||
```
|
||||
|
||||
希望你能够认识上面全部的命令,先不要管它的值。第一个命令和前面一样,是将值 `1` 推入到寄存器 `r1` 中。第二个命令是将二进制的 `1` 左移 16 位。由于我们是希望关闭 GPIO 的 16 号针脚,我们需要在下一个消息中将第 16 比特设置为 1(想设置其它针脚只需要改变相应的比特位即可)。最后,我们写这个值到 GPIO 控制器地址加上 40<sub>10</sub> 的地址上,这将使那个针脚关闭(加上 28 将打开针脚)。
|
||||
|
||||
### 6、永远幸福快乐
|
||||
|
||||
似乎我们现在就可以结束了,但不幸的是,处理器并不知道我们做了什么。事实上,处理器只要通电,它就永不停止地运转。因此,我们需要给它一个任务,让它一直运转下去,否则,树莓派将进入休眠(本示例中不会,LED 灯会一直亮着)。
|
||||
|
||||
```
|
||||
loop$:
|
||||
b loop$
|
||||
|
||||
```
|
||||
|
||||
> `name:` 下一行的名字。
|
||||
|
||||
> `b label` 下一行将去标签 `label` 处运行。
|
||||
|
||||
第一行不是一个命令,而是一个标签。它给下一行命名为 `loop$`,这意味着我们能够通过名字来指向到该行。这就称为一个标签。当代码被转换成二进制后,标签将被丢弃,但这对我们通过名字而不是数字(地址)找到行比较有用。按惯例,我们使用一个 `$` 表示这个标签只对这个代码块中的代码起作用,让其它人知道,它不对整个程序起作用。`b`(“branch”)命令将去运行指定的标签中的命令,而不是去运行它后面的下一个命令。因此,下一行将再次去运行这个 `b` 命令,这将导致永远循环下去。因此处理器将进入一个无限循环中,直到它安全关闭为止。
|
||||
|
||||
代码块结尾的一个空行是有意这样写的。GNU 工具链要求所有的汇编代码文件都是以空行结束的,因此,这就可以你确实是要结束了,并且文件没有被截断。如果你不这样处理,在汇编器运行时,你将收到烦人的警告。
|
||||
|
||||
### 7、树莓派上场
|
||||
|
||||
由于我们已经写完了代码,现在,我们可以将它上传到树莓派中了。在你的计算机上打开一个终端,改变当前工作目录为 `source` 文件夹的父级目录。输入 `make` 然后回车。如果报错,请参考排错章节。如果没有报错,你将生成三个文件。 `kernel.img` 是你的编译后的操作系统镜像。`kernel.list` 是你写的汇编代码的一个清单,它实际上是生成的。这在将来检查程序是否正确时非常有用。`kernel.map` 文件包含所有标签结束位置的一个映射,这对于跟踪值非常有用。
|
||||
|
||||
为安装你的操作系统,需要先有一个已经安装了树莓派操作系统的 SD 卡。如果你浏览 SD 卡中的文件,你应该能看到一个名为 `kernel.img` 的文件。将这个文件重命名为其它名字,比如 `kernel_linux.img`。然后,复制你编译的 `kernel.img` 文件到 SD 卡中原来的位置,这将用你的操作系统镜像文件替换现在的树莓派操作系统镜像。想切换回来时,只需要简单地删除你自己的 `kernel.img` 文件,然后将前面重命名的文件改回 `kernel.img` 即可。我发现,保留一个原始的树莓派操作系统的备份是非常有用的,万一你要用到它呢。
|
||||
|
||||
将这个 SD 卡插入到树莓派,并打开它的电源。这个 OK 的 LED 灯将亮起来。如果不是这样,请查看故障排除页面。如果一切如愿,恭喜你,你已经写出了你的第一个操作系统。[课程 2 OK02][12] 将指导你让 LED 灯闪烁和关闭闪烁。
|
||||
|
||||
[^1]: 是的,我说错了,它告诉的是链接器,它是另一个程序,用于将汇编器转换过的几个代码文件链接到一起。直接说是汇编器也没有大问题。
|
||||
[^2]: 其实它们对你很重要。由于 GNU 工具链主要用于开发操作系统,它要求入口点必须是名为 `_start` 的地方。由于我们是开发一个操作系统,无论什么时候,它总是从 `_start` 开时的,而我们可以使用 `.section .init` 命令去设置它。因此,如果我们没有告诉它入口点在哪里,就会使工具链困惑而产生警告消息。所以,我们先定义一个名为 `_start` 的符号,它是所有人可见的(全局的),紧接着在下一行生成符号 `_start` 的地址。我们很快就讲到这个地址了。
|
||||
[^3]: 本教程的设计减少了你阅读树莓派开发手册的难度,但是,如果你必须要阅读它,你可以在这里 [SoC-Peripherals.pdf](https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/downloads/SoC-Peripherals.pdf) 找到它。由于添加了混淆,手册中 GPIO 使用了不同的地址系统。我们的操作系统中的地址 0x20200000 对应到手册中是 0x7E200000。
|
||||
[^4]: `mov` 能够加载的值只有前 8 位是 `1` 的二进制表示的值。换句话说就是一个 0 后面紧跟着 8 个 `1` 或 `0`。
|
||||
[^5]: 一个很友好的硬件工程师是这样向我解释这个问题的:
|
||||
|
||||
原因是现在的芯片都是用一种称为 CMOS 的技术来制成的,它是互补金属氧化物半导体的简称。互补的意思是每个信号都连接到两个晶体管上,一个是使用 N 型半导体的材料制成,它用于将电压拉低,而另一个使用 P 型半导体材料制成,它用于将电压升高。在任何时刻,仅有一个半导体是打开的,否则将会短路。P 型材料的导电性能不如 N 型材料。这意味着三倍大的 P 型半导体材料才能提供与 N 型半导体材料相同的电流。这就是为什么 LED 总是通过降低为低电压来打开它,因为 N 型半导体拉低电压比 P 型半导体拉高电压的性能更强。
|
||||
|
||||
还有一个原因。早在上世纪七十年代,芯片完全是由 N 型材料制成的(NMOS),P 型材料部分使用了一个电阻来代替。这意味着当信号为低电压时,即便它什么事都没有做,芯片仍然在消耗能量(并发热)。你的电话装在口袋里什么事都不做,它仍然会发热并消耗你的电池电量,这不是好的设计。因此,信号设计成 “活动时低”,而不活动时为高电压,这样就不会消耗能源了。虽然我们现在已经不使用 NMOS 了,但由于 N 型材料的低电压信号比 P 型材料的高电压信号要快,所以仍然使用了这种设计。通常在一个 “活动时低” 信号名字上方会有一个条型标记,或者写作 `SIGNAL_n` 或 `/SIGNAL`。但是即便这样,仍然很让人困惑,那怕是硬件工程师,也不可避免这种困惑!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok01.html
|
||||
|
||||
作者:[Robert Mullins][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://www.cl.cam.ac.uk/~rdm34
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/downloads.html
|
||||
[2]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/hexadecimal1.png
|
||||
[3]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/hexadecimal2.png
|
||||
[4]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/hexadecimal3.png
|
||||
[5]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/hexadecimal4.png
|
||||
[6]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/gpioController.png
|
||||
[7]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/binary1.png
|
||||
[8]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/binary2.png
|
||||
[9]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/binary3.png
|
||||
[10]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/screen04.html
|
||||
[11]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/binary4.png
|
||||
[12]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok02.html
|
@ -0,0 +1,68 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (qhwdw)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10478-1.html)
|
||||
[#]: subject: (Computer Laboratory – Raspberry Pi: Lesson 2 OK02)
|
||||
[#]: via: (https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok02.html)
|
||||
[#]: author: (Robert Mullins http://www.cl.cam.ac.uk/~rdm34)
|
||||
|
||||
计算机实验室之树莓派:课程 2 OK02
|
||||
======
|
||||
|
||||
OK02 课程构建于 OK01 课程的基础上,通过不停地打开和关闭 OK 或 ACT LED 指示灯来实现闪烁。假设你已经有了 [课程 1:OK01][1] 操作系统的代码,它将是这一节课的基础。
|
||||
|
||||
### 1、等待
|
||||
|
||||
等待是操作系统开发中非常有用的部分。操作系统经常发现自己无事可做,以及必须要延迟。在这个例子中,我们希望通过等待,让 LED 灯打开、关闭的闪烁可以看到。如果你只是打开和关闭它,你将看到这个视觉效果,因为计算机每秒种可以打开和关闭它好几千次(LCTT 译注:视觉暂留效应会使你难以发觉它的闪烁)。在后面的课程中,我们将看到精确的等待,但是现在,我们只要简单地去消耗时间就足够了。
|
||||
|
||||
```
|
||||
mov r2,#0x3F0000
|
||||
wait1$:
|
||||
sub r2,#1
|
||||
cmp r2,#0
|
||||
bne wait1$
|
||||
```
|
||||
|
||||
> `sub reg,#val` 从寄存器 `reg` 中的值上减去数字 `val`
|
||||
>
|
||||
> `cmp reg,#val` 将寄存器中的值与数字 `val` 进行比较。
|
||||
>
|
||||
> 如果最后的比较结果是不相等,那么执行后缀了 `ne` 的 `b` 命令。
|
||||
|
||||
上面是一个很常见的产生延迟的代码片段,由于每个树莓派基本上是相同的,所以产生的延迟大致也是相同的。它的工作原理是,使用一个 `mov` 命令将值 3F0000<sub>16</sub> 推入到寄存器 `r2` 中,然后将这个值减 1,直到这个值减到 0 为止。在这里使用了三个新命令 `sub`、 `cmp` 和 `bne`。
|
||||
|
||||
`sub` 是减法命令,它只是简单地从第一个参数中的值减去第二个参数中的值。
|
||||
|
||||
`cmp` 是个很有趣的命令。它将第一个参数与第二个参数进行比较,然后将比较结果记录到一个称为当前处理器状态寄存器的专用寄存器中。你其实不用担心它,它记住的只是两个数谁大或谁小,或是相等而已。[^1]
|
||||
|
||||
`bne` 其实是一个伪装的分支命令。在 ARM 汇编语言家族中,任何指令都可以有条件地运行。这意味着如果上一个比较结果是某个确定的结果,那个指令才会运行。这是个非常有意思的技巧,我们在后面将大量使用到它,但在本案例中,我们在 `b` 命令后面的 `ne` 后缀意思是 “只有在上一个比较的结果是值不相等,才去运行该分支”。`ne` 后缀可以使用在任何命令上,其它几个(总共 16 个)条件也是如此,比如 `eq` 表示等于,而 `lt` 表示小于。
|
||||
|
||||
### 2、组合到一起
|
||||
|
||||
上一节讲我提到过,通过将 GPIO 地址偏移量设置为 28(即:`str r1,[r0,#28]`)而不是 40 即可实现 LED 的关闭。因此,你需要去修改课程 OK01 的代码,在打开 LED 后,运行等待代码,然后再关闭 LED,再次运行等待代码,并包含一个回到开始位置的分支。注意,不需要重新启用 GPIO 的 16 号针脚的输出功能,这个操作只需要做一次就可以了。如果你想更高效,我建议你复用 `r1` 寄存器的值。所有课程都一样,你可以在 [下载页面][2] 找到所有的解决方案。需要注意的是,必须保证你的所有标签都是唯一的。当你写了 `wait1$:` 你其它行上的标签就不能再使用 `wait1$` 了。
|
||||
|
||||
在我的树莓派上,它大约是每秒闪两次。通过改变我们所设置的 `r2` 寄存器中的值,可以很轻松地修改它。但是,不幸的是,我不能够精确地预测它的运行速度。如果你的树莓派未按预期正常工作,请查看我们的故障排除页面,如果它正常工作,恭喜你。
|
||||
|
||||
在这个课程中,我们学习了另外两个汇编命令:`sub` 和 `cmp`,同时学习了 ARM 中如何实现有条件运行。
|
||||
|
||||
在下一个课程,[课程 3:OK03][3] 中我们将学习如何编写代码,以及建立一些代码复用的标准,并且如果需要的话,可能会使用 C 或 C++ 来写代码。
|
||||
|
||||
[^1]: 如果你点了这个链接,说明你一定想知道它的具体内容。CPSR 是一个由许多独立的比特位组成的 32 比特寄存器。它有一个位用于表示正数、零和负数。当一个 `cmp` 指令运行后,它从第一个参数上减去第二个参数,然后用这个位记下它的结果是正数、零还是负数。如果是零意味着它们相等(`a-b=0` 暗示着 `a=b`)如果为正数意味着 a 大于 b(`a-b>0` 暗示着 `a>b`),如果为负数意味着小于。还有其它比较指令,但 `cmp` 指令最直观。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok02.html
|
||||
|
||||
作者:[Robert Mullins][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://www.cl.cam.ac.uk/~rdm34
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://linux.cn/article-10458-1.html
|
||||
[2]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/downloads.html
|
||||
[3]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok03.html
|
144
published/20150717 The History of Hello World.md
Normal file
144
published/20150717 The History of Hello World.md
Normal file
@ -0,0 +1,144 @@
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: "zzzzzzmj"
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-10485-1.html"
|
||||
[#]: subject: "The History of Hello World"
|
||||
[#]: via: "https://www.thesoftwareguild.com/blog/the-history-of-hello-world/"
|
||||
[#]: author: "thussong https://www.thesoftwareguild.com/blog/author/thussong/"
|
||||
|
||||
Hello World 的由来
|
||||
=========
|
||||
|
||||
资深软件开发人员都知道 [Hello World][2] 程序,这是一个能在设备显示器上输出某种变体的 “Hello, World!” 的程序,是学习编程的第一步。在这个编程中只涉及到一些最基本语法的程序,可以用大多数编程语言了来编写。事实上,路易斯安纳理工学院计算机协会(ACM)在最近统计[发现][3]这个程序至少有 204 个版本。
|
||||
|
||||
传统意义上,Hello World 程序是用于说明编码过程是如何工作的,以及确保编程语言或系统能正常运行。它们经常是新手程序员学习的第一个程序,因为即使是经验很少或者没有经验的人也能轻松正确的执行 Hello World。
|
||||
|
||||
首先,Hello World 简单,这就是为什么它经常被用做程序执行成功的晴雨表。如果 Hello World 在该框架中无法有效执行,那么其它更复杂的程序中也可能会失败。正如 [Win-Vector][4] 的一位专家所说,Hello World 实际上是一个对抗性程序。“该作者还说道,‘你的计算机系统能不能工作并不是一目了然,除非我能看到它至少能打印一行文字,否则我不会在上面浪费太多时间。’” Win-Vector 博主 John Mount 说。
|
||||
|
||||
但是这个两词短语在计算机科学领域有着重大的影响。以 Hello World 为基础,新手程序员可以轻松的理解计算机科学原理或元素,而拥有多年编码经验的程序员可以用它来学习编程语言的工作原理,特别是在结构与语法方面。这样的一个小程序,在任何难度的应用程序和几乎所有语言中都有着悠久的历史。
|
||||
|
||||
### 用途
|
||||
|
||||
以上概括了 Hello World 程序的主要用途:这是新手程序员熟悉新语言的一种方式。然而,这些程序不仅仅是对编码世界的介绍。例如,Hello World 可以作为测试,以确保语言的组件(编译器、开发和运行环境)安装正确。因为配置完整的编程工具链的过程复杂而漫长,所以像 Hello World 这样简单的程序通常用作新工具链的首次运行测试。
|
||||
|
||||
根据 Cunningham & Cunningham(C2)的编程顾问所说,在系统设计人员并不预期可以执行代码的地方,黑客经常使用 Hello World 程序作为一个可以通过漏洞执行任意代码的概念验证(POC)。事实上,它是在设备上使用自制内容或者“自酿”的第一步,当[有经验的编码人员][5]正在配置环境或在学习新事物时,他们会通过 Hello World 来验证其行为是否正确。
|
||||
|
||||
它也作为调试过程的一部分,允许程序员检查他们是否正确地编辑了可在运行时修改的程序并重新加载。
|
||||
|
||||
Hello World 的一个更常用的用途是作为基础比较。根据 C2 的 wiki 所讲,程序员可以“比较语言生成的可执行文件的大小,以及程序背后必须存在多少支持的基础设施才能执行。”
|
||||
|
||||
### 开端
|
||||
|
||||
虽然 Hello World 的起源还有些不太明了,不过人们普遍认为它作为测试用语,最早出现在 Brian Kernigham 在 1972 年发布的《<ruby>B 语言简介教程<rt>A Tutorial Introduction to the Language B</rt></ruby>》中。在此文中,该程序的第一个已知版本用于说明外部变量。因为该教程中的前一个例子在终端上打印了 “hi!”,而需要更多的字符常量来表达相对复杂的 “hello,world!”,这是学习过程的下一步。
|
||||
|
||||
在那以后,它还被用于 1974 年的贝尔实验室备忘录,以及 1987 年的《<ruby>C 语言程序设计<rt>The C Programming Language</rt></ruby>》。这两篇著名的文字是让 Hello World 闻名于世的主要原因。在书中的一个例子(第一个,也是最著名的例子)打印了没有大写字母和感叹号的 “hello,world”。此时的 Hello World 几乎只是用于说明语言的一些功能,而不是测试系统是否正常运行。
|
||||
|
||||
在 Kernigham 的关于 B 语言和 C 语言的开创性文章之前,没有真正意义上的第一个程序,甚至直到 1974 年,它也没被广泛使用。著名的 BASIC 教程 “<ruby>我的电脑喜欢我用 BASIC 跟它讲话<rt>My Computer Likes Me,When I Speak BASIC</rt></ruby>”,从一个写一行文本的简单程序开始,不过那句话是 “MY HUMAN UNDERSTANDS ME”,跟如今程序员侃侃而谈的这个双词问候语差的有点远。不过,当 Hello World 被发明后,它就迅速传播,并在 20 世纪 70 年代后变成了众所周知。直到今天它也依然受欢迎。
|
||||
|
||||
### 一个声明,多种语言
|
||||
|
||||
以下是目前正在被使用的一些流行的编程语言中的 Hello World 代码。
|
||||
|
||||
#### Java
|
||||
|
||||
```
|
||||
class HelloWorld {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Hello, world!");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### C#
|
||||
|
||||
```
|
||||
using System;
|
||||
class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Hello, world!");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Python
|
||||
|
||||
```
|
||||
print("Hello, world!")
|
||||
```
|
||||
|
||||
#### Ruby
|
||||
|
||||
```
|
||||
puts "Hello, world!"
|
||||
```
|
||||
|
||||
#### Scala
|
||||
|
||||
```
|
||||
object HelloWorld extends App {
|
||||
println("Hello, world!")
|
||||
}
|
||||
```
|
||||
|
||||
#### ASP.NET
|
||||
|
||||
```
|
||||
Response.Write("Hello World!");
|
||||
```
|
||||
|
||||
#### Lisp
|
||||
|
||||
```
|
||||
(princ "Hello, world!")
|
||||
```
|
||||
|
||||
#### Haskell
|
||||
|
||||
```
|
||||
main = putStrLn "Hello, world!"
|
||||
```
|
||||
|
||||
#### Malbolge
|
||||
|
||||
```
|
||||
('&%:9]!~}|z2Vxwv-,POqponl$Hjig%eB@@>}=<M:9wv6WsU2T|nm-,jcL(I&%$#"
|
||||
`CB]V?Tx<uVtT`Rpo3NlF.Jh++FdbCBA@?]!~|4XzyTT43Qsqq(Lnmkj"Fhg${z@>
|
||||
```
|
||||
|
||||
#### Go
|
||||
|
||||
```
|
||||
package main
|
||||
import "fmt"
|
||||
func main() {
|
||||
fmt.Println("Hello, world!")
|
||||
}
|
||||
```
|
||||
|
||||
### 如今的 Hello world:各种形式下的标准实践
|
||||
|
||||
在现在的编程语言中,Hello World 有着不同的复杂程度。例如,Go 语言中引入一个多语言版的 Hello World 程序,XL 则会提供一个具有图形、可旋转的 3D 版本。一些编程语言,像 Ruby、Python,仅仅需要一个语句去打印“Hello World”,但是低级汇编语言则需要几个命令才能做到这样。现在的编程语言还引入对标点符号和大小写的变化,包括是否有逗号或者感叹号,以及两个词的大写形式。举个例子,当系统只支持大写字母,会呈现像“HELLO WORLD”的短语。值得纪念的第一个 Malbolge 程序打印出了“HEllO WORld”(LCTT 译注:Malbolge 是最难的编程语言之一。事实上,在它诞生后,花了 2 年时间才完成第一个 Malbolge 程序)。它的变体跨越了原本的字面意思。像 Lisp、Haskell 这样函数语言,用阶乘程序替代了 Hello World,从而注重递归技术。这与原来的示例不同,后者更强调 I/O 以及产生的副作用。
|
||||
|
||||
随着现在的编程语言越来越复杂,Hello World 比以往显得更加重要。作为测试和教学工具,它已经成为程序员测试配置的编程环境的标准方法。没有人能确切说出为什么 Hello World 能在快速创新著称的行业中经受住时间的考验,但是它又确实留下来了。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.thesoftwareguild.com/blog/the-history-of-hello-world/
|
||||
|
||||
作者:[thussong][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[zzzzzzmj](https://github.com/zzzzzzmj)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.thesoftwareguild.com/blog/author/thussong/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Fwww.thesoftwareguild.com%2Fblog%2Fthe-history-of-hello-world%2F&title=The%20History%20of%20Hello%20World
|
||||
[2]: http://en.wikipedia.org/wiki/%22Hello,_World!%22_program
|
||||
[3]: http://whatis.techtarget.com/definition/Hello-World
|
||||
[4]: http://www.win-vector.com/blog/2008/02/hello-world-an-instance-rhetoric-in-computer-science/
|
||||
[5]: http://c2.com/cgi/wiki?HelloWorld
|
136
published/20170523 Best Websites to Download Linux Games.md
Normal file
136
published/20170523 Best Websites to Download Linux Games.md
Normal file
@ -0,0 +1,136 @@
|
||||
下载 Linux 游戏的最佳网站
|
||||
======
|
||||
|
||||
> 新接触 Linux 游戏并想知道从哪里来 **下载 Linux 游戏**?我们列出了最好的资源,在这里你既能 **下载免费的 Linux 游戏** ,也能购买优质的 Linux 游戏。
|
||||
|
||||
Linux 和游戏?从前,很难想象这两者走到一起。然而随着时间流逝,很多事情都在变化。到如今,有成千上万在 Linux 上可以玩的游戏,而大公司和独立开发者们正在开发更多的游戏。
|
||||
|
||||
[在 Linux 上玩游戏][1] 现在已经是现实。今天我们将去看看,你在哪里可以找到 Linux 平台游戏、搜索到你喜欢的游戏。
|
||||
|
||||
### 在哪里来下载 Linux 游戏?
|
||||
|
||||
![下载 Linux 游戏的网站][2]
|
||||
|
||||
首先,看看你的 Linux 发行版的软件中心(如果有的话)。在这里你也能找到大量的游戏。
|
||||
|
||||
但是,这不意味着你应该将自己的视野局限于软件中心上。让我们来为你列出一些可以下载 Linux 游戏网站。
|
||||
|
||||
#### 1. Steam
|
||||
|
||||
如果你是老练的玩家,你应该听过 Steam。如果你还不知道的话,没错,Steam 在 Linux 上也是可用的。Steam 推荐运行在 Ubuntu 上,但是它也能运行在其它主要的发行版上。如果你真的对 Steam 很狂热,这里甚至还有一个玩 Steam 游戏的专用操作系统:[SteamOS][3]。我们在上一年 [最佳的 Linux 游戏发行版][4] 文章中提及了它。
|
||||
|
||||
![Steam 商店][5]
|
||||
|
||||
Steam 有最大的 Linux 游戏商店。当写这篇文章的时候,在 Linux 平台上,确切地说有 3487 款游戏,这真的是很多了。你可以从宽广的类型中寻找游戏。至于 [数字版权管理(DRM)][6],大多数的 Steam 游戏都有某种 DRM 。
|
||||
|
||||
对于使用 Steam ,要么你必须在你的 Linux 系统上安装 [Steam 客户端][7],要么使用 SteamOS。Steam 的一个优势是,在初始化安装后,对于大多数的游戏,你不需要担心依赖关系和复杂的安装过程。 Steam 客户端将为你做这些繁重的任务。
|
||||
|
||||
- [Steam 商店][8]
|
||||
|
||||
#### 2. GOG
|
||||
|
||||
如果你只对免 DRM 的游戏感兴趣,GOG 收集了相当多的这种游戏。此刻,GOG 在它们的库中有 1978 种免 DRM 游戏。GOG 因它大量收集了免 DRM 游戏而闻名。
|
||||
|
||||
![GOG 商店][9]
|
||||
|
||||
GOG 游戏官方支持 Ubuntu LTS 版本和 Linux Mint。所以,Ubuntu 和它的衍生版在安装它们时将没有问题。在其他发行版上安装它们时可能需要一些额外的工作,例如,你需要安装正确的依赖关系。
|
||||
|
||||
从 GOG 中下载游戏,你不需要额外的客户端。所有购买的游戏都可在你的账户区内找到。你可以使用你最爱的下载管理器直接下载它们。
|
||||
|
||||
- [GOG 商店][10]
|
||||
|
||||
#### 3. Humble 商店
|
||||
|
||||
Humble 商店是另一个你可以查找各种各样 Linux 游戏的地方。在 Humble 商店中有免 DRM 和非免 DRM 的游戏。非免 DRM 游戏通常来自 Steam。在 Humble 商店中,当前有超过 1826 款 Linux 游戏。
|
||||
|
||||
![Humble 商店][11]
|
||||
|
||||
Humble 商店因另一个原因而著名。它们有一个被称为 [Humble 独立包][12]的活动,其中打包提供了一批游戏,带有令人不可抗拒的限时优惠。关于 Humble 的另一件事是,当你购买时,你的购买金额的 10% 将捐给慈善机构。
|
||||
|
||||
Humble 不需要额外的客户端来下载它们的游戏。
|
||||
|
||||
- [Humble 商店][13]
|
||||
|
||||
#### 4. itch.io 商店
|
||||
|
||||
itch.io 是给独立数字创作者的一个开放市场,其致力于独立视频游戏。itch.io 有一些你能找到的最有趣、最独特的游戏。在 itch.io 的大多数游戏是免 DRM 的。
|
||||
|
||||
![itch.io 商店][14]
|
||||
|
||||
现今,itch.io 在它的商店中有 9514 款 Linux 平台的游戏。
|
||||
|
||||
itch.io 有它自己的 [客户端][15],可以轻松地下载、安装、更新和玩它们的游戏。
|
||||
|
||||
- [itch.io 商店][16]
|
||||
|
||||
#### 5. LGDB
|
||||
|
||||
LGDB 是 <ruby>Linux 游戏数据库<rt>Linux Game DataBase</rt></ruby>的缩写。虽然从技术上说它不是一个游戏商店,它收集有大量的 Linux 游戏,以及关于它们的各种各样的信息。每一款游戏都有你可以在哪里找到它们的链接。
|
||||
|
||||
![Linux 游戏数据库][17]
|
||||
|
||||
如今,在该数据库中有 2046 款游戏。它们也有很长的关于 [模拟器][18]、[工具][19] 和 [游戏引擎][20] 的列表。
|
||||
|
||||
- [LGDB][21]
|
||||
|
||||
#### 6. Game Jolt 商店
|
||||
|
||||
Game Jolt 有一个非常可观的集合,在它的库藏中大约有 5000 个 Linux 独立游戏。
|
||||
|
||||
![Game Jolt 商店][22]
|
||||
|
||||
Game Jolt 有一个(预览版)[客户端][23],可用于轻松地下载、安装、更新和玩游戏。
|
||||
|
||||
- [Game Jolt 商店][24]
|
||||
|
||||
### 其他
|
||||
|
||||
有很多其他的销售 Linux 游戏的商店。也有很多你能找到免费游戏的地方。这是它们中的两个:
|
||||
|
||||
* [Bundle Stars][25]:当前有 814 个 Linux 游戏和 31 个游戏包。
|
||||
* [GamersGate][26]:现在有 595 个 Linux 游戏。既有免 DRM 的,也有非免 DRM 的。
|
||||
|
||||
#### 应用商店、软件中心 & 软件库
|
||||
|
||||
Linux 发行版有它们自己的应用商店或软件库。尽管不是很多,但是在这里你也能找到各种各样的游戏。
|
||||
|
||||
今天到此为止。你知道这里有这么多 Linux 上可玩的游戏吗?你使用一些其他的网站来下载 Linux 游戏吗?与我们分享你的收藏。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/download-linux-games/
|
||||
|
||||
作者:[Munif Tanjim][a]
|
||||
译者:[robsean](https://github.com/robsean)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/munif/
|
||||
[1]:https://linux.cn/article-7316-1.html
|
||||
[2]:https://itsfoss.com/wp-content/uploads/2017/05/download-linux-games-800x450.jpg
|
||||
[3]:http://store.steampowered.com/steamos/
|
||||
[4]:https://itsfoss.com/linux-gaming-distributions/
|
||||
[5]:https://itsfoss.com/wp-content/uploads/2017/05/Steam-Store-800x382.jpg
|
||||
[6]:https://www.wikiwand.com/en/Digital_rights_management
|
||||
[7]:http://store.steampowered.com/about/
|
||||
[8]:http://store.steampowered.com/linux
|
||||
[9]:https://itsfoss.com/wp-content/uploads/2017/05/GOG-Store-800x366.jpg
|
||||
[10]:https://www.gog.com/games?system=lin_mint,lin_ubuntu
|
||||
[11]:https://itsfoss.com/wp-content/uploads/2017/05/The-Humble-Store-800x393.jpg
|
||||
[12]:https://www.humblebundle.com/?partner=itsfoss
|
||||
[13]:https://www.humblebundle.com/store?partner=itsfoss
|
||||
[14]:https://itsfoss.com/wp-content/uploads/2017/05/itch.io-Store-800x485.jpg
|
||||
[15]:https://itch.io/app
|
||||
[16]:https://itch.io/games/platform-linux
|
||||
[17]:https://itsfoss.com/wp-content/uploads/2017/05/LGDB-800x304.jpg
|
||||
[18]:https://lgdb.org/emulators
|
||||
[19]:https://lgdb.org/tools
|
||||
[20]:https://lgdb.org/engines
|
||||
[21]:https://lgdb.org/games
|
||||
[22]:https://itsfoss.com/wp-content/uploads/2017/05/GameJolt-Store-800x357.jpg
|
||||
[23]:http://gamejolt.com/client
|
||||
[24]:http://gamejolt.com/games/best?os=linux
|
||||
[25]:https://www.bundlestars.com/en/games?page=1&platforms=Linux
|
||||
[26]:https://www.gamersgate.com/games?state=available
|
||||
[27]:https://itsfoss.com/linux-gaming-problems/
|
115
published/20170921 The Rise and Rise of JSON.md
Normal file
115
published/20170921 The Rise and Rise of JSON.md
Normal file
@ -0,0 +1,115 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (runningwater)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: subject: (The Rise and Rise of JSON)
|
||||
[#]: via: (https://twobithistory.org/2017/09/21/the-rise-and-rise-of-json.html)
|
||||
[#]: author: (https://twobithistory.org)
|
||||
[#]: url: (https://linux.cn/article-10440-1.html)
|
||||
|
||||
JSON 的兴起与崛起
|
||||
======
|
||||
|
||||
JSON 已经占领了全世界。当今,任何两个应用程序彼此通过互联网通信时,可以打赌它们在使用 JSON。它已被所有大型企业所采用:十大最受欢迎的 web API 接口列表中(主要由 Google、Facebook 和 Twitter 提供),仅仅只有一个 API 接口是以 XML 的格式开放数据的。[^1] 这个列表中的 Twitter API 为此做了一个鲜活的注脚:其对 XML 格式的支持到 2013 年结束,其时发布的新版本的 API 取消 XML 格式,转而仅使用 JSON。JSON 也在程序编码级别和文件存储上被广泛采用:在 Stack Overflow(LCTT 译注:一个面向程序员的问答网站)上,现在更多的是关于 JSON 的问题,而不是其他的数据交换格式。[^2]
|
||||
|
||||
![][1]
|
||||
|
||||
XML 仍然在很多地方存在。网络上它被用于 SVG 和 RSS / Atom 信息流。Android 开发者想要获得用户权限许可时,需要在其 APP 的 `manifest` 文件中声明 —— 此文件是 XML 格式的。XML 的替代品也不仅仅只有 JSON,现在有很多人在使用 YAML 或 Google 的 Protocol Buffers 等技术,但这些技术的受欢迎程度远不如 JSON。目前来看,JSON 是应用程序在网络之间通信的首选协议格式。
|
||||
考虑到自 2005 年来 Web 编程世界就垂涎于 “异步 JavaScript 和 XML” 而非 “异步 JavaScript 和 JSON” 的技术潜力,你可以发现 JSON 的主导地位是如此的让人惊讶。当然了,这可能与这两种通信格式的受欢迎程度无关,而仅反映出缩写 “AJAX” 似乎比 “AJAJ” 更具吸引力。但是,即使在 2005 年有些人(实际上没有太多人)已经用 JSON 来取代 XML 了,我们不禁要问为什么 XML 的噩运来的如此之快,以至于短短十来年,“异步 JavaScript 和 XML” 这个名称就成为一个很讽刺的误称。那这十来年发生了什么?JSON 怎么会在那么多应用程序中取代了 XML?现在被全世界工程师和系统所使用、依赖的这种数据格式是谁提出的?
|
||||
|
||||
### JSON 之诞生
|
||||
|
||||
2001 年 4 月,首个 JSON 格式的消息被发送出来。此消息是从旧金山湾区某车库的一台计算机发出的,这是计算机历史上重要的的时刻。Douglas Crockford 和 Chip Morningstar 是一家名为 State Software 的技术咨询公司的联合创始人,他们当时聚集在 Morningstar 的车库里测试某个想法,发出了此消息。
|
||||
|
||||
在 “AJAX” 这个术语被创造之前,Crockford 和 Morningstar 就已经在尝试构建好用的 AJAX 应用程序了,可是浏览器对其兼容性不好。他们想要在初始页面加载后就将数据传递给应用程序,但其目标要针对所有的浏览器,这就实现不了。
|
||||
|
||||
这在今天看来不太可信,但是要记得 2001 年的时候 Internet Explorer(IE)代表了网页浏览器的最前沿技术产品。早在 1999 年的时候,Internet Explorer 5 就支持了原始形式的 `XMLHttpRequest`,开发者可以使用名为 ActiveX 的框架来访问此对象。Crockford 和 Morningstar 能够使用此技术(在 IE 中)来获取数据,但是在 Netscape 4 中(这是他们想要支持的另一种浏览器)就无法使用这种解决方案。为此 Crockford 和 Morningstar 只得使用一套不同的系统以兼容不同的浏览器。
|
||||
|
||||
第一条 JSON 消息如下所示:
|
||||
|
||||
```
|
||||
<html><head><script>
|
||||
document.domain = 'fudco';
|
||||
parent.session.receive(
|
||||
{ to: "session", do: "test",
|
||||
text: "Hello world" }
|
||||
)
|
||||
</script></head></html>
|
||||
```
|
||||
|
||||
消息中只有一小部分类似于今天我们所知的 JSON,本身其实是一个包含有一些 JavaScript 的 HTML 文档。类似于 JSON 的部分只是传递给名为 `receive()` 的函数的 JavaScript 对象字面量。
|
||||
|
||||
Crockford 和 Morningstar 决定滥用 HTML 的帧(`<frame>`)以发送数据。他们可以让一个帧指向一个返回的上述 HTML 文档的 URL。当接收到 HTML 时,JavaScript 代码段就会运行,就可以把数据对象字面量如实地传递回应用程序。只要小心的回避浏览器保护策略(即子窗口不允许访问父窗口),这种技术就可以正常运行无误。可以看到 Crockford 和 Mornginstar 通过明确地设置文档域这种方法来达到其目的。(这种基于帧的技术,有时称为隐藏帧技术,通常在 90 年代后期,即在广泛使用 XMLHttpRequest 技术之前使用。[^3] )
|
||||
|
||||
第一个 JSON 消息的惊人之处在于,它显然不是一种新的数据格式的首次使用。它就是 JavaScript!实际上,以此方式使用 JavaScript 的想法如此简单,Crockford 自己也说过他不是第一个这样做的人。他说 Netscape 公司的某人早在 1996 年就使用 JavaScript 数组字面量来交换信息。[^4] 因为消息就是 JavaScript,其不需要任何特殊解析工作,JavaScript 解释器就可搞定一切。
|
||||
|
||||
最初的 JSON 信息实际上与 JavaScript 解释器发生了冲突。JavaScript 保留了大量的关键字(ECMAScript 6 版本就有 64 个保留字),Crockford 和 Morningstar 无意中在其 JSON 中使用了一个保留字。他们使用了 `do` 作为了键名,但 `do` 是解释器中的保留字。因为 JavaScript 使用的保留字太多了,Crockford 做了决定:既然不可避免的要使用到这些保留字,那就要求所有的 JSON 键名都加上引号。被引起来的键名会被 JavaScript 解释器识别成字符串,其意味着那些保留字也可以放心安全的使用。这就为什么今天 JSON 键名都要用引号引起来的原因。
|
||||
|
||||
Crockford 和 Morningstar 意识到这技术可以应用于各类应用系统。想给其命名为 “JSML”,即 <ruby>JavaScript 标记语言<rt>JavaScript Markup Language</rt></ruby>的意思,但发现这个缩写已经被一个名为 Java Speech 标记语言的东西所使用了。因此他们决定采用 “JavaScript Object Notation”,缩写为 JSON。他们开始向客户推销,但很快发现客户不愿意冒险使用缺乏官方规范的未知技术。所以 Crockford 决定写一个规范。
|
||||
|
||||
2002 年,Crockford 买下了 [JSON.org][2] 域名,放上了 JSON 语法及一个解释器的实例例子。该网站仍然在运行,现在已经包含有 2013 年正式批准的 JSON ECMA 标准的显著链接。在该网站建立后,Crockford 并没有过多的推广,但很快发现很多人都在提交各种不同编程语言的 JSON 解析器实现。JSON 的血统显然与 JavaScript 相关联,但很明显 JSON 非常适合于不同语言之间的数据交换。
|
||||
|
||||
### AJAX 导致的误会
|
||||
|
||||
2005 年,JSON 有了一次大爆发。那一年,一位名叫 Jesse James Garrett 的网页设计师和开发者在博客文章中创造了 “AJAX” 一词。他很谨慎地强调:AJAX 并不是新技术,而是 “好几种蓬勃发展的技术以某种强大的新方式汇集在一起。[^5] ” AJAX 是 Garrett 给这种正受到青睐的 Web 应用程序的新开发方法的命名。他的博客文章接着描述了开发人员如何利用 JavaScript 和 XMLHttpRequest 构建新型应用程序,这些应用程序比传统的网页更具响应性和状态性。他还以 Gmail 和 Flickr 网站已经使用 AJAX 技术作为了例子。
|
||||
|
||||
当然了,“AJAX” 中的 “X” 代表 XML。但在随后的问答帖子中,Garrett 指出,JSON 可以完全替代 XML。他写道:“虽然 XML 是 AJAX 客户端进行数据输入、输出的最完善的技术,但要实现同样的效果,也可以使用像 JavaScript Object Notation(JSON)或任何类似的结构数据方法等技术。 ”[^6]
|
||||
|
||||
开发者确实发现在构建 AJAX 应用程序时可以很容易的使用 JSON,许多人更喜欢它而不是 XML。具有讽刺意味的是,对 AJAX 的兴趣逐渐的导致了 JSON 的普及。大约在这个时候,JSON 引起了博客圈的注意。
|
||||
|
||||
2006 年,Dave Winer,一位高产的博主,他也是许多基于 XML 的技术(如 RSS 和 XML-RPC)背后的开发工程师,他抱怨到 JSON 毫无疑问的正在重新发明 XML。尽管人们认为数据交换格式之间的竞争不会导致某一技术的消亡。其写到:
|
||||
|
||||
> 毫无疑问,我可以编写一个例程来解析 JSON,但来看看他们要重新发明一个东西有多大的意义,出于某种原因 XML 本身对他们来说还不够好(我很想听听原因)。谁想干这荒谬之事?查找一棵树然后把节点串起来。可以立马试试。[^7]
|
||||
|
||||
我很理解 Winer 的挫败感。事实上并没有太多人喜欢 XML。甚至 Winer 也说过他不喜欢 XML。[^8] 但 XML 已被设计成一个可供任何人使用,并且可以用于几乎能想象到的所有事情。归根到底,XML 实际上是一门元语言,允许你为特定应用程序自定义该领域特定的语言。如 Web 信息流技术 RSS 和 SOAP(简单对象访问协议)就是例子。Winer 认为由于通用交换格式所带来的好处,努力达成共识非常重要。XML 的灵活性应该能满足任何人的需求,然而 JSON 格式呢,其并没有比 XML 提供更多东西,除了它抛弃了使 XML 更灵活的那些繁琐的东西。
|
||||
|
||||
Crockford 阅读了 Winer 的这篇文章并留下了评论。为了回应 JSON 重新发明 XML 的指责,Crockford 写到:“重造轮子的好处是可以得到一个更好的轮子。”[^9]
|
||||
|
||||
### JSON 与 XML 对比
|
||||
|
||||
到 2014 年,JSON 已经由 ECMA 标准和 RFC 官方正式认可。它有了自己的 MIME 类型。JSON 已经进入了大联盟时代。
|
||||
|
||||
为什么 JSON 比 XML 更受欢迎?
|
||||
|
||||
在 [JSON.org][2] 网站上,Crockford 总结了一些 JSON 的优势。他写到,JSON 的语法极少,其结构可预测,因此 JSON 更容易被人类和机器理解。[^10] 其他博主一直关注 XML 的冗长啰嗦及“尖括号负担”。[^11] XML 中每个开始标记都必须与结束标记匹配,这意味着 XML 文档包含大量的冗余信息。在未压缩时,XML 文档的体积比同等信息量 JSON 文档的体积大很多,但是,更重要的,这也使 XML 文档更难以阅读。
|
||||
|
||||
Crockford 还声称 JSON 的另一个巨大优势是其被设计为数据交换格式。[^12] 从一开始,它的目的就是在应用程序间传递结构化信息的。而 XML 呢,虽然也可以使用来传递数据,但其最初被设计为文档标记语言。它演变自 SGML(通用标准标记语言),而它又是从被称为 Scribe 的标记语言演变而来,其旨在发展成类似于 LaTeX 一样的文字处理系统。XML 中,一个标签可以包含有所谓的“混合内容”,即带有围绕单词、短语的内嵌标签的文本。这会让人浮现出一副用红蓝笔记录的手稿画面,这是标记语言核心思想的形象比喻。另一方面,JSON 不支持对混合内容模型的清晰构建,但这也意味着它的结构足够简单。一份文档最好的建模就是一棵树,但 JSON 抛弃了这种文档的思想,Crockford 将 JSON 抽象限制为字典和数组,这是所有程序员构建程序时都会使用的最基本的、也最熟悉的元素。
|
||||
|
||||
最后,我认为人们不喜欢 XML 是因为它让人困惑。它让人迷惑的地方就是有很多不同的风格。乍一看,XML 本身及其子语言(如 RSS、ATOM、SOAP 或 SVG)之间的界限并不明显。典型的 XML 文档的第一行标识了该 XML 的版本,然后该 XML 文档应该符合特定的子语言。这就有变化需要考虑了,特别是跟 JSON 做比较,JSON 是如此简单,以至于永远不需要编写新版本的 JSON 规范。XML 的设计者试图将 XML 做为唯一的数据交换格式以支配所有格式,就会掉入那个经典的程序员陷阱:过度工程化。XML 非常笼统及概念化,所以很难于简单的使用。
|
||||
|
||||
在 2000 年的时候,发起了一场使 HTML 符合 XML 标准的活动,发布了一份符合 XML 标准的 HTML 开发规范,这就此后很出名的 XHTML。虽然一些浏览器厂商立即开始支持这个新标准,但也很明显,大部分基于 HTML 技术的开发者不愿意改变他们的习惯。新标准要求对 XHTML 文档进行严格的验证,而不是基于 HTML 的基准。但大多的网站都是依赖于 HTML 的宽容规则的。到 2009 年的时候,试图编写第二版本的 XHTML 标准的努力已经流产,因为未来已清晰可见,HTML 将会发展为 HTML5(一种不强制要求接受 XML 规则的标准)。
|
||||
|
||||
如果 XHTML 的努力取得了成功,那么 XML 可能会成为其设计者所希望的通用数据格式。想象一下,一个 HTML 文档和 API 响应具有完全相同结构的世界。在这样的世界中,JSON 可能不会像现在一样普遍存在。但我把 HTML 的失败看做是 XML 阵营的一种道义上的失败。如果 XML 不是 HTML 的最佳工具,那么对于其他应用程序,也许会有更好的工具出现。在这个世界,我们的世界,很容易看到像 JSON 格式这样的足够简单、量体裁衣的才能获得更大的成功。
|
||||
|
||||
如果你喜欢这博文,每两周会更新一次! 请在 Twitter 上关注 [@TwoBitHistory][3] 或订阅 [RSS feed][4],以确保得到更新的通知。
|
||||
|
||||
[^1]: http://www.cs.tufts.edu/comp/150IDS/final_papers/tstras01.1/FinalReport/FinalReport.html#software
|
||||
[^2]: https://insights.stackoverflow.com/trends?tags=json%2Cxml%2Cprotocol-buffers%2Cyaml%2Ccsv
|
||||
[^3]: Zakas, Nicholas C., et al. “What Is Ajax?” Professional Ajax, 2nd ed., Wiley, 2007.
|
||||
[^4]: https://youtu.be/-C-JoyNuQJs?t=32s
|
||||
[^5]: http://adaptivepath.org/ideas/ajax-new-approach-web-applications/
|
||||
[^6]: 同上
|
||||
[^7]: http://scripting.com/2006/12/20.html
|
||||
[^8]: http://blogoscoped.com/archive/2009-03-05-n15.html
|
||||
[^9]: https://scripting.wordpress.com/2006/12/20/scripting-news-for-12202006/#comment-26383
|
||||
[^10]: http://www.json.org/xml.html
|
||||
[^11]: https://blog.codinghorror.com/xml-the-angle-bracket-tax
|
||||
[^12]: https://youtu.be/-C-JoyNuQJs?t=33m50sgg
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://twobithistory.org/2017/09/21/the-rise-and-rise-of-json.html
|
||||
|
||||
作者:[Two-Bit History][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[runningwater](https://github.com/runningwater)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://twobithistory.org
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://twobithistory.org/images/json.svg
|
||||
[2]: http://JSON.org
|
||||
[3]: https://twitter.com/TwoBitHistory
|
||||
[4]: https://twobithistory.org/feed.xml
|
@ -0,0 +1,112 @@
|
||||
如何用 Gonimo 创建一个免费的婴儿监视系统
|
||||
======
|
||||
> 当你可以用两个设备、浏览器和网络连接就能免费搭建一个婴儿监视器时,谁还会花钱去买呢?
|
||||
|
||||

|
||||
|
||||
新父母和准父母很快就会知道将会有一个既长且昂贵的新生儿所需设备的清单,清单中的首位是一个婴儿监视器,借此他们可以在做其他事情时照看自己的婴儿,但这儿有一件不必消耗你的婴儿经费的设备,Gonimo 是一个可以将现有的设备转换成婴儿监控系统的自由开源解决方案,附近大型婴儿用品商店的过道中有数以千计的其他必备或时尚物品,就可以为其中某一个腾出一些婴儿的预算。
|
||||
|
||||
Gonimo 诞生时,它的开发者,一个有双胞胎的开源粉丝,发现现有选择存在问题:
|
||||
|
||||
* 现有硬件婴儿监视器价格昂贵,使用范围有限,需要您带着额外的设备。
|
||||
* 虽然有移动监控应用程序,但大多数现有的 iOS / Android 婴儿监控应用程序都不可靠且不安全,不太容易找到开源产品。
|
||||
* 如果您有两个小孩(例如双胞胎),您将需要两台监视器,使您的成本翻倍。
|
||||
|
||||
Gonimo 是作为一个解决典型的监视器的缺点的开源解决方案而创建的:
|
||||
|
||||
* 昂贵?不,它是免费的!
|
||||
* 使用范围有限?不,它适用于互联网 / WiFi,无论您身在何处。
|
||||
* 下载并安装应用程序?噢不,它适用于您现有的网络浏览器。
|
||||
* 购买新设备?不用,你可以使用任何笔记本电脑、手机或平板电脑与网络浏览器和麦克风和/或相机。
|
||||
|
||||
(注意:遗憾的是,Apple iOS 设备尚不支持,但预计很快就会发生变化 —— 请继续阅读,了解如何帮实现这一目标。)
|
||||
|
||||
### 开始
|
||||
|
||||
将您的设备转换为婴儿监视器很容易。从您设备的浏览器(理想情况下为 Chrome),访问 [gonimo.com][1] 并单击 “Start baby monitor” 以访问该 Web 应用程序。
|
||||
|
||||
1、创建家庭:在首次启动的屏幕上,你会看到一只可爱的兔子在地球上奔跑。这是您创建新家庭的地方。单击 “+” 按钮并接受随机生成的姓氏或键入您自己的选择。
|
||||
|
||||
![Start screen][3]
|
||||
|
||||
*从开始屏幕创建一个新家庭*
|
||||
|
||||
2、邀请设备:建立完家庭以后,下个屏幕将指示您邀请其他设备加入你的 Gonimo 家庭。您可以通过电子邮件直接发送一次性邀请链接,也可以将其复制并粘贴到消息中。对其他设备,只需打开该链接并接受邀请。对您要邀请的任何其他设备重复此过程。您的设备现在属于同一家庭,可以作为一个完全正常工作的婴儿监视器系统进行配合。
|
||||
|
||||
![Invite screen][5]
|
||||
|
||||
*邀请家庭成员*
|
||||
|
||||
3、启动婴儿站流:接下来,通过转到 [Gonimo 主屏][6],点击带有奶嘴的按钮,并允许网络浏览器访问设备的麦克风和摄像头,选择将婴儿的音频和视频流式传输到父母的设备。调整相机以指向宝宝的床,或关闭它以节省设备电池(音频仍将流式传输)。点击“Start”。该流现在处于活动状态。
|
||||
|
||||
![Select baby station][8]
|
||||
|
||||
*选择婴儿站*
|
||||
|
||||
![Press Start][10]
|
||||
|
||||
*按“Start”开始以流式传输视频*
|
||||
|
||||
4、连接到父母站流:要查看婴儿站流,请转到 Gonimo 家族中的另外的设备 —— 即父母站。点击 Gonimo 主屏幕上的 “Parent” 按钮。您将看到该系列中所有设备的列表;旁边有一个闪动的“Connect”按钮的是活跃的婴儿站。选择“Connect”,您可以通过点对点音频/视频流看到和听到您的宝宝。音量条为传输的音频流提供可视化。
|
||||
|
||||
![Select parent station][12]
|
||||
|
||||
*选择父母站*
|
||||
|
||||
![Press Connect][14]
|
||||
|
||||
*按下“Connect”开始观看婴儿流。*
|
||||
|
||||
5、恭喜!您已成功将设备直接通过网络浏览器转换为婴儿监视器,无需下载或安装任何应用程序!
|
||||
|
||||
有关重命名设备,从系列中删除设备或删除系列的详细信息和详细说明,请查看 gonimo.com 的[视频教程][15]。
|
||||
|
||||
### 家庭系统的灵活性
|
||||
|
||||
Gonimo 的优势之一是其基于家庭的系统,它为即使在商业 Android 或 iOS 应用中也无法提供的各种情况提供了极大的灵活性。要深入了解这些功能,我们假设您创建了一个由三个设备组成的家庭系统。
|
||||
|
||||
* 多婴儿:如果你想留意你在两个不同房间睡觉的两个小孩怎么办?在每个孩子的房间放一个设备,并将其设置为婴儿站。第三个设备将充当父母站,您可以在其上连接到两个流并通过分屏查看您的幼儿。您甚至可以通过向该家庭系统提供更多设备,并将其设置为婴儿站来将此用例扩展到两个以上的婴儿站。只要您的父母站连接到第一个婴儿站,请单击左上角的后退箭头返回“设备概述”屏幕。现在您可以连接到第二个(以及依次为第三个、第四个、第五个和第五个等)设备,并自动建立分屏。酷!
|
||||
* 多父母:如果爸爸想在他上班的时候看孩子怎么办?只需邀请第四个设备(例如,他的办公室 PC )到家庭并将其设置为父母站。父母双方都可以通过他们自己的设备同时检查他们的孩子,甚至可以独立地选择他们希望连接的孩子。
|
||||
* 多家庭:单个设备也可以是几个家庭系统的一部分。当您的婴儿站与您一起时,如平板电脑,您经常访问亲戚或朋友时,这非常有用。为“奶奶的房子”或“约翰叔叔的房子”创建另一个家庭,其中包括您的婴儿站设备与奶奶或约翰叔叔的设备配对。您可以随时通过婴儿站设备的 Gonimo 主屏幕在这些家庭中切换婴儿站设备。
|
||||
|
||||
### 想要参加吗?
|
||||
|
||||
Gonimo 团队喜欢开源。代码来自社区,代码用于社区。Gonimo 的用户对我们非常重要,但它们只是 Gonimo 故事的一部分。幕后有创意的大脑是创造出色婴儿监视器体验的关键。
|
||||
|
||||
目前我们特别需要那些愿意成为 iOS 11 测试者的人的帮助,因为 Apple 在 iOS 11 中对 WebRTC 的支持意味着我们最终将能够支持 iOS 设备。如果可以,请帮助我们实现这个令人赞叹的里程碑。
|
||||
|
||||
如果您了解 Haskell 或想要了解它,您可以查看 [GitHub 上我们的代码][16]。欢迎发起拉取请求、审查代码以及提出问题。
|
||||
|
||||
最后,请通过向新父母和开源世界宣传 Gonimo 婴儿监视器是易于使用并且便携的。
|
||||
|
||||
### 关于作者
|
||||
|
||||
Robert Klotzner:我是双胞胎的父亲,一个程序员。当我听到普通人可以给计算机编程时,我买了一本 1200 页的关于 C++ 的书开始学习,我当时才十五岁。我坚持用 C++ 相当长的一段时间,学习了 Java 又回归到 C++,学习了 D、Python 等等,最终学习了 Haskell。我喜欢 Haskell 是因为它丰富的类型系统,这几乎可以避免我书写错误的代码。强壮的静态类型和性能让我爱上了 C++……
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/17/9/gonimo
|
||||
|
||||
作者:[Robert Klotzner][a]
|
||||
译者:[lintaov587](https://github.com/lintaov587)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/robert-klotzner
|
||||
[1]:https://gonimo.com/
|
||||
[2]:/file/371256
|
||||
[3]:https://opensource.com/sites/default/files/u128651/start-screen.png (Start screen)
|
||||
[4]:/file/371236
|
||||
[5]:https://opensource.com/sites/default/files/u128651/invite-screen.png (Invite screen)
|
||||
[6]:https://app.gonimo.com/
|
||||
[7]:/file/371231
|
||||
[8]:https://opensource.com/sites/default/files/u128651/baby-select.png (Select baby station)
|
||||
[9]:/file/371226
|
||||
[10]:https://opensource.com/sites/default/files/u128651/baby-screen.png (Press Start)
|
||||
[11]:/file/371251
|
||||
[12]:https://opensource.com/sites/default/files/u128651/parent-select.png (Select parent station)
|
||||
[13]:/file/371241
|
||||
[14]:https://opensource.com/sites/default/files/u128651/parent-screen.png (Press Connect)
|
||||
[15]:https://gonimo.com/index.php#intro
|
||||
[16]:https://github.com/gonimo/gonimo
|
89
published/20171119 The Ruby Story.md
Normal file
89
published/20171119 The Ruby Story.md
Normal file
@ -0,0 +1,89 @@
|
||||
红宝石(Ruby)史话
|
||||
======
|
||||
|
||||
尽管我很难说清楚为什么,但 Ruby 一直是我最喜爱的一门编程语言。如果用音乐来类比的话,Python 给我的感觉像是<ruby>朋克摇滚<rt>punk rock</rt></ruby>,简单、直接,但略显单调,而 Ruby 则像是爵士乐,从根本上赋予了程序员表达自我的自由,虽然这可能会让代码变复杂,编写出来的程序对其他人来说不直观。
|
||||
|
||||
Ruby 社区一直将<ruby>灵活表达<rt>freedom of expression</rt></ruby>视为其核心价值。可我不认同这对于 Ruby 的开发和普及是最重要的。创建一门编程语言也许是为了更高的性能,也许是为了在抽象上节省更多的时间,可 Ruby 就有趣在它并不关心这些,从它诞生之初,它的目标就是让程序员更快乐。
|
||||
|
||||
### 松本·行弘
|
||||
|
||||
<ruby>松本·行弘<rt>Yukihiro Matsumoto</rt></ruby>,亦称为 “Matz”,于 1990 年毕业于筑波大学。筑波是东京东北方向上的一个小城市,是科学研究与技术开发的中心之一。筑波大学以其 STEM 计划广为流传。松本·行弘在筑波大学的信息科学专业学习过,且专攻编程语言。他也在 Ikuo Nakata 的编程语言实验室工作过。(LCTT 译注:STEM 是<ruby>科学<rt>Science</rt></ruby>、<ruby>技术<rt>Technology</rt></ruby>、<ruby>工程<rt>Engineering</rt></ruby>、<ruby>数学<rt>Mathematics</rt></ruby>四门学科英文首字母的缩写。)
|
||||
|
||||
松本从 1993 年开始制作 Ruby,那时他才刚毕业几年。他制作 Ruby 的起因是觉得那时的脚本语言缺乏一些特性。他在使用 Perl 的时候觉得这门语言过于“玩具”,此外 Python 也有点弱,用他自己的话说:
|
||||
|
||||
> 我那时就知道 Python 了,但我不喜欢它,因为我认为它不是一门真正的面向对象的语言。面向对象就像是 Python 的一个附件。作为一个编程语言狂热者,我在 15 年里一直是面向对象的忠实粉丝。我真的想要一门生来就面向对象而且易用的脚本语言。我为此特地寻找过,可事实并不如愿。[^1]
|
||||
|
||||
所以一种解释松本创造 Ruby 的动机就是他想要创造一门更好,且面向对象的 Perl。
|
||||
|
||||
但在其他场合,松本说他创造 Ruby 主要是为了让他自己和别人更快乐。2008 年,松本在谷歌技术讲座结束时放映了这张幻灯片:
|
||||
|
||||
![][1]
|
||||
|
||||
他对听众说到,
|
||||
|
||||
> 我希望 Ruby 能帮助世界上的每一个程序员更有效率地工作,享受编程并感到快乐。这也是制作 Ruby 语言的主要意图。[^2]
|
||||
|
||||
松本开玩笑的说他制作 Ruby 的原因很自私,因为他觉得其它的语言乏味,所以需要创造一点让自己开心的东西。
|
||||
|
||||
这张幻灯片展现了松本谦虚的一面。其实,松本是一位摩门教践行者,因此我很好奇他传奇般的友善有多少归功于他的宗教信仰。无论如何,他的友善在 Ruby 社区广为流传,甚至有一条称为 MINASWAN 的原则,即“<ruby>松本人很好,我们也一样<rt>Matz Is Nice And So We Are Nice</rt></ruby>”。我想那张幻灯片一定震惊了来自 Google 的观众。我想谷歌技术讲座上的每张幻灯片都充满着代码和运行效率的指标,来说明一个方案比另一个更快更有效,可仅仅放映崇高的目标的幻灯片却寥寥无几。
|
||||
|
||||
Ruby 主要受到 Perl 的影响。Perl 则是由 Larry Wall 于 20 世纪 80 年代晚期创造的语言,主要用于处理和转换基于文本的数据。Perl 因其文本处理和正则表达式而闻名于世。对于 Ruby 程序员,Perl 程序中的很多语法元素都不陌生,例如符号 `$`、符号 `@`、`elsif` 等等。虽然我觉得,这些不是 Ruby 应该具有的特征。除了这些符号外,Ruby 还借鉴了 Perl 中的正则表达式的处理和标准库。
|
||||
|
||||
但影响了 Ruby 的不仅仅只有 Perl 。在 Ruby 之前,松本制作过一个仅用 Emacs Lisp 编写的邮件客户端。这一经历让他对 Emacs 和 Lisp 语言运行的内部原理有了更多的认识。松本说 Ruby 底层的对象模型也受其启发。在那之上,松本添加了一个 Smalltalk 风格的信息传递系统,这一系统随后成为了 Ruby 中任何依赖 `#method_missing` 的操作的基石。松本也表示过 Ada 和 Eiffel 也影响了 Ruby 的设计。
|
||||
|
||||
当时间来到了给这门新语言命名的时候,松本和他的同事 Keiju Ishitsuka 挑选了很多个名字。他们希望名字能够体现新语言和 Perl、shell 脚本间的联系。在[这一段非常值得一读的即时消息记录][2]中,Ishitsuka 和 松本也许花了太多的时间来思考 <ruby>shell<rt>贝壳</rt></ruby>、<ruby>clam<rt>蛤蛎</rt></ruby>、<ruby>oyster<rt>牡蛎</rt></ruby>和<ruby>pearl<rt>珍珠</rt></ruby>之间的关系了,以至于差点把 Ruby 命名为“<ruby>Coral<rt>珊瑚虫</rt></ruby>”或“<ruby>Bisque<rt>贝类浓汤</rt></ruby>”。幸好,他们决定使用 Ruby,因为它就像 pearl 一样,是一种珍贵的宝石。此外,<ruby>Ruby<rt>红宝石</rt></ruby> 还是 7 月的生辰石,而 <ruby>Pearl<rt>珍珠</rt></ruby> 则是 6 月的生辰石,采用了类似 C++ 和 C# 的隐喻,暗示着她们是改进自前辈的编程语言。(LCTT 译注:Perl 和 Pearl 发音相同,所以也常以“珍珠”来借喻 Perl;shell 是操作系统提供的用户界面,这里指的是命令行界面;更多有关生辰石的[信息](https://zh.wikipedia.org/zh-hans/%E8%AA%95%E7%94%9F%E7%9F%B3)。)
|
||||
|
||||
### Ruby 西渐
|
||||
|
||||
Ruby 在日本的普及很快。1995 年 Ruby 刚刚发布后不久后,松本就被一家名为 Netlab 的日本软件咨询财团(全名 Network Applied Communication Laboratory)雇用,并全职为 Ruby 工作。到 2000 年时,在 Ruby 发布仅仅 5 年后,Ruby 在日本的流行度就超过了 Python。可这时的 Ruby 才刚刚进入英语国家。虽然从 Ruby 的诞生之初就存在讨论它的日语邮件列表,但是英语的邮件列表直到 1998 年才建立起来。起初,在英语的邮件列表中交流的大多是日本的 Ruby 狂热者,可随着 Ruby 在西方的逐渐普及而得以改变。
|
||||
|
||||
在 2000 年,Dave Thomas 出版了第一本涵盖 Ruby 的英文书籍《Programming Ruby》。因为它的封面上画着一把锄头,所以这本书也被称为锄头书。这是第一次向身处西方的程序员们介绍了 Ruby。就像在日本那样,Ruby 的普及很快,到 2002 年时,英语的 Ruby 邮件列表的通信量就超过了日语邮件列表。
|
||||
|
||||
时间来到了 2005 年,Ruby 更流行了,但它仍然不是主流的编程语言。然而,Ruby on Rails 的发布让一切都不一样了。Ruby on Rails 是 Ruby 的“杀手级应用”,没有别的什么项目能比它更推动 Ruby 的普及了。在 Ruby on Rails 发布后,人们对 Ruby 的兴趣爆发式的增长,看看 TIOBE 监测的语言排行:
|
||||
|
||||
![][3]
|
||||
|
||||
有时人们开玩笑的说,Ruby 程序全是基于 Ruby-on-Rails 的网站。虽然这听起来就像是 Ruby on Rails 占领了整个 Ruby 社区,但在一定程度上,这是事实。因为编写 Rails 应用时使用的语言正是 Ruby。Rails 欠 Ruby 的和 Ruby 欠 Rails 的一样多。
|
||||
|
||||
Ruby 的设计哲学也深深地影响了 Rails 的设计与开发。Rails 之父 David Heinemeier Hansson 常常提起他第一次与 Ruby 的接触的情形,那简直就是一次传教。他说,那种经历简直太有感召力了,让他感受到要为松本的杰作(指 Ruby)“传教”的使命。[^3] 对于 Hansson 来说,Ruby 的灵活性简直就是对 Python 或 Java 语言中自上而下的设计哲学的反抗。他很欣赏 Ruby 这门能够信任自己的语言,Ruby 赋予了他自由选择<ruby>程序表达方式<rt>express his programs</rt></ruby>的权力。
|
||||
|
||||
就像松本那样,Hansson 声称他创造 Rails 时因为对现状的不满并想让自己能更开心。他也认同让程序员更快乐高于一切的观点,所以检验 Rails 是否需要添加一项新特性的标准是“<ruby>更灿烂的笑容标准<rt>The Principle of The Bigger Smile</rt></ruby>”。什么功能能让 Hansson 更开心就给 Rails 添加什么。因此,Rails 中包括了很多非正统的功能,例如 “Inflector” 类和 `Time` 扩展(“Inflector”类试图将单个类的名字映射到多个数据库表的名字;`Time` 扩展允许程序员使用 `2.days.ago` 这样的表达式)。可能会有人觉得这些功能太奇怪了,但 Rails 的成功表明它的确能让很多人的生活得更快乐。
|
||||
|
||||
因此,虽然 Rails 的火热带动了 Ruby 的普及看起来是一个偶然,但事实上 Rails 体现了 Ruby 的很多核心准则。此外,很难看到使用其他语言开发的 Rails,正是因为 Rails 的实现依赖于 Ruby 中<ruby>类似于宏的类方法调用<rt>macro-like class method calls</rt></ruby>来实现模型关联这样的功能。一些人认为这么多的 Ruby 开发需要基于 Ruby on Rails 是 Ruby 生态不健康的表现,但 Ruby 和 Ruby on Rails 结合的如此紧密并不是没有道理的。
|
||||
|
||||
### Ruby 之未来
|
||||
|
||||
人们似乎对 Ruby(及 Ruby on Rails)是否正在消亡有着异常的兴趣。早在 2011 年,Stack Overflow 和 Quora 上就充斥着程序员在咨询“如果几年后不再使用 Ruby 那么现在是否有必要学它”的话题。这些担忧对 Ruby 并非没有道理,根据 TIOBE 指数和 Stack Overflow 趋势,Ruby 和 Ruby on Rails 的人气一直在萎缩,虽然它也曾是热门新事物,但在更新更热的框架面前它已经黯然失色。
|
||||
|
||||
一种解释这种趋势的理论是程序员们正在舍弃动态类型的语言转而选择静态类型的。TIOBE 指数的趋势中可以看出对软件质量的需求在上升,这意味着出现在运行时的异常变得难以接受。他们引用 TypeScript 来说明这一趋势,TypeScript 是 JavaScript 的全新版本,而创造它的目的正是为了保证客户端运行的代码能受益于编译所提供的安全保障。
|
||||
|
||||
我认为另一个更可能的原因是比起 Ruby on Rails 推出的时候,现在存在着更多有竞争力的框架。2005 年它刚刚发布的时候,还没有那么多用于创建 Web 程序的框架,其主要的替代者还是 Java。可在今天,你可以使用为 Go、Javascript 或者 Python 开发的各种优秀的框架,而这还仅仅是主流的选择。Web 的世界似乎正走向更加分布式的结构,与其使用一块代码来完成从数据库读取到页面渲染所有事务,不如将事务拆分到多个组件,其中每个组件专注于一项事务并将其做到最好。在这种趋势下,Rails 相较于那些专攻于 JavaScript 前端通信的 JSON API 就显得过于宽泛和臃肿。
|
||||
|
||||
总而言之,我们有理由对 Ruby 的未来持乐观态度。因为不管是 Ruby 还是 Rails 的开发都还很活跃。松本和其他的贡献者们都在努力开发 Ruby 的第三个主要版本。新的版本将比现在的版本快上 3 倍,以减轻制约着 Ruby 发展的性能问题。虽然从 2005 年起,越来越多的 Web 框架被开发出来,但这并不意味着 Ruby on Rails 就失去了其生存空间。Rails 是一个富有大量功能的成熟的工具,对于一些特定类型的应用开发一直是非常好的选择。
|
||||
|
||||
但就算 Ruby 和 Rails 走上了消亡的道路,Ruby 让程序员更快乐的信条一定会存活下来。Ruby 已经深远的影响了许多新的编程语言的设计,这些语言的设计中能够看到来自 Ruby 的很多理念。而其他的新生语言则试着变成 Ruby 更现代的实现,例如 Elixir 是一个强调函数式编程范例的语言,仍在开发中的 Crystal 目标是成为使用静态类型的 Ruby 。世界上许多程序员都喜欢上了 Ruby 及其语法,因此它的影响必将会在未来持续很长一段时间。
|
||||
|
||||
喜欢这篇文章吗?这里每两周都会发表一篇这样的文章。请在推特上关注我们 [@TwoBitHistory][4] 或者订阅我们的 [RSS][5],这样新文章发布的第一时间你就能得到通知。
|
||||
|
||||
[^1]: http://ruby-doc.org/docs/ruby-doc-bundle/FAQ/FAQ.html
|
||||
[^2]: https://www.youtube.com/watch?v=oEkJvvGEtB4?t=30m55s
|
||||
[^3]: http://rubyonrails.org/doctrine/
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://twobithistory.org/2017/11/19/the-ruby-story.html
|
||||
|
||||
作者:[Two-Bit History][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wwhio](https://github.com/wwhio)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://twobithistory.org
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://twobithistory.org/images/matz.png
|
||||
[2]: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/88819
|
||||
[3]: https://twobithistory.org/images/tiobe_ruby.png
|
||||
[4]: https://twitter.com/TwoBitHistory
|
||||
[5]: https://twobithistory.org/feed.xml
|
@ -0,0 +1,84 @@
|
||||
Turtl:Evernote 的开源替代品
|
||||
======
|
||||
> 如果你正在寻找一个 Evernote 和 Google Keep 的替代品,那么 Turtl 是一个可靠的记笔记工具。
|
||||
|
||||

|
||||
|
||||
我认识的每个人都会记笔记,许多人使用在线笔记应用,如 Evernote、Simplenote 或 Google Keep。这些都是很好的工具,但你不得不担忧信息的安全性和隐私性 —— 特别是考虑到 [Evernote 2016 年的隐私策略变更][1]。如果你想要更好地控制笔记和数据,你需要转向开源工具。
|
||||
|
||||
无论你离开 Evernote 的原因是什么,都有开源替代品。让我们来看看其中一个选择:Turtl。
|
||||
|
||||
### 入门
|
||||
|
||||
[Turtl][2] 背后的开发人员希望你将其视为“具有绝对隐私的 Evernote”。说实话,我不能保证 Turtl 提供的隐私级别,但它是一个非常好的笔记工具。
|
||||
|
||||
要开始使用 Turtl,[下载][3]适用于 Linux、Mac OS 或 Windows 的桌面客户端,或者获取它的 [Android 应用][4]。安装它,然后启动客户端或应用。系统会要求你输入用户名和密码。Turtl 使用密码来生成加密密钥,根据开发人员的说法,加密密钥会在将笔记存储在设备或服务器上之前对其进行加密。
|
||||
|
||||
### 使用 Turtl
|
||||
|
||||
你可以使用 Turtl 创建以下类型的笔记:
|
||||
|
||||
* 密码
|
||||
* 档案
|
||||
* 图片
|
||||
* 书签
|
||||
* 文字笔记
|
||||
|
||||
无论你选择何种类型的笔记,你都可以在类似的窗口中创建:
|
||||
|
||||

|
||||
|
||||
*在 Turtl 中创建新笔记*
|
||||
|
||||
添加笔记标题、文字并(如果你正在创建文件或图像笔记)附加文件或图像等信息。然后单击“保存”。
|
||||
|
||||
你可以通过 [Markdown][6] 为你的笔记添加格式。因为没有工具栏快捷方式,所以你需要手动添加格式。
|
||||
|
||||
如果你需要整理笔记,可以将它们添加到“白板”中。白板就像 Evernote 中的笔记本。要创建新的白板,请单击 “Board” 选项卡,然后单击“创建”按钮。输入白板的标题,然后单击“创建”。
|
||||
|
||||

|
||||
|
||||
*在 Turtl 中创建新的白板*
|
||||
|
||||
要向白板中添加笔记,请创建或编辑笔记,然后单击笔记底部的“此笔记不在任何白板”的链接。选择一个或多个白板,然后单击“完成”。
|
||||
|
||||
要为笔记添加标记,请单击记事本底部的“标记”图标,输入一个或多个以逗号分隔的关键字,然后单击“完成”。
|
||||
|
||||
### 跨设备同步你的笔记
|
||||
|
||||
例如,如果你在多台计算机和 Android 设备上使用 Turtl,Turtl 会在你上线时同步你的笔记。但是,我在同步时遇到了一个小问题:我手机上创建的笔记经常不会同步到我的笔记本电脑上。我尝试通过单击窗口左上角的图标手动同步,然后单击立即同步,但这并不总是有效。我发现偶尔需要单击“设置”图标,然后单击“清除本地数据”。然后我需要重新登录 Turtl,但所有数据都能正确同步了。
|
||||
|
||||
### 一个疑问和一些问题
|
||||
|
||||
当我开始使用 Turtl 时,我被一个疑问所困扰:我的笔记保存在哪里?事实证明,Turtl 背后的开发人员位于美国,这也是他们服务器的所在地。虽然 Turtl 使用的加密[非常强大][8]并且你的笔记在服务器上加密,但我偏执地认为你不应该在 Turtl 中保存任何敏感内容(或在任何类似的在线笔记中)。
|
||||
|
||||
Turtl 以平铺视图显示笔记,让人想起 Google Keep:
|
||||
|
||||

|
||||
|
||||
*Turtl 中的一系列笔记*
|
||||
|
||||
无法在桌面或 Android 应用上将其更改为列表视图。这对我来说不是问题,但我听说有些人因为它没有列表视图而不喜欢 Turtl。
|
||||
|
||||
说到 Android 应用,它并不差。但是,它没有与 Android 共享菜单集成。如果你想把在其他应用中看到或阅读的内容添加到 Turtl 笔记中,则需要手动复制并粘贴。
|
||||
|
||||
我已经在我的 Linux 笔记本,[运行 GalliumOS 的 Chromebook][10],还有一台 Android 手机上使用 Turtl 几个月了。对所有这些设备来说这都是一种非常无缝的体验。虽然它不是我最喜欢的开源笔记工具,但 Turtl 做得非常好。试试看它,它可能是你正在寻找的简单的笔记工具。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/17/12/using-turtl-open-source-alternative-evernote
|
||||
|
||||
作者:[Scott Nesbitt][a]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/scottnesbitt
|
||||
[1]:https://blog.evernote.com/blog/2016/12/15/evernote-revisits-privacy-policy/
|
||||
[2]:https://turtlapp.com/
|
||||
[3]:https://turtlapp.com/download/
|
||||
[4]:https://turtlapp.com/download/
|
||||
[6]:https://en.wikipedia.org/wiki/Markdown
|
||||
[8]:https://turtlapp.com/docs/security/encryption-specifics/
|
||||
[10]:https://opensource.com/article/17/4/linux-chromebook-gallium-os
|
316
published/20171227 YAML- probably not so great after all.md
Normal file
316
published/20171227 YAML- probably not so great after all.md
Normal file
@ -0,0 +1,316 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (MjSeven)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10423-1.html)
|
||||
[#]: subject: (YAML: probably not so great after all)
|
||||
[#]: via: (https://arp242.net/weblog/yaml_probably_not_so_great_after_all.html)
|
||||
[#]: author: (Martin Tournoij https://arp242.net/)
|
||||
|
||||
YAML:可能并不是那么完美
|
||||
======
|
||||
|
||||
我之前写过[为什么将 JSON 用于人类可编辑的配置文件是一个坏主意][1],今天我们将讨论 YAML 格式的一些常见问题。
|
||||
|
||||
### 默认情况下不安全
|
||||
|
||||
YAML 默认是不安全的。加载用户提供的(不可信的)YAML 字符串需要仔细考虑。
|
||||
|
||||
```
|
||||
!!python/object/apply:os.system
|
||||
args: ['ls /']
|
||||
```
|
||||
|
||||
用 `print(yaml.load(open('a.yaml')))` 运行它,应该给你这样的东西:
|
||||
|
||||
```
|
||||
bin etc lib lost+found opt root sbin tmp var sys
|
||||
boot dev efi home lib64 mnt proc run srv usr
|
||||
0
|
||||
```
|
||||
|
||||
许多其他语言(包括 Ruby 和 PHP [^1] )默认情况下也不安全(LCTT 译注:这里应该说的是解析 yaml)。[在 GitHub 上搜索 yaml.load][2] 会得到惊人的 280 万个结果,而 [yaml.safe_load][3] 只能得到 26000 个结果。
|
||||
|
||||
提个醒,很多这样的 `yaml.load()` 都工作的很好,在配置文件中加载 `yaml.load()` 通常没问题,因为它通常(虽然并不总是!)来自“可靠源”,而且很多都来自静态的 YAML 测试文件。但是,人们还是不禁怀疑在这 280 万个结果中隐藏了多少漏洞。
|
||||
|
||||
这不是一个理论问题。在 2013 年,[正是由于这个问题,所有的 Ruby on Rails 应用程序都被发现易受][4]远程代码执行攻击。
|
||||
|
||||
有人可能会反驳说这不是 YAML 格式的错误,而是那些库实现错误的的问题,但似乎大多数库默认不是安全的(特别是动态语言),所以事实上这是 YAML 的一个问题。
|
||||
|
||||
有些人可能会反驳认为修复它就像用 `safe_load()` 替换 `load()` 一样容易,但是很多人都没有意识到这个问题,即使你知道它,它也是很容易忘记的事情之一。这是非常糟糕的 API 设计。
|
||||
|
||||
### 可能很难编辑,特别是对于大文件
|
||||
|
||||
YAML 文件可能很难编辑,随着文件变大,这个难度会快速增大。
|
||||
|
||||
一个很好的例子是 Ruby on Rails 的本地化翻译文件。例如:
|
||||
|
||||
```
|
||||
en:
|
||||
formtastic:
|
||||
labels:
|
||||
title: "Title" # Default global value
|
||||
article:
|
||||
body: "Article content"
|
||||
post:
|
||||
new:
|
||||
title: "Choose a title..."
|
||||
body: "Write something..."
|
||||
edit:
|
||||
title: "Edit title"
|
||||
body: "Edit body"
|
||||
```
|
||||
|
||||
看起来不错,对吧?但是如果这个文件有 100 行怎么办?或者 1,000 行?在文件中很难看到 “where”,因为它可能在屏幕外。你需要向上滚动,但是你需要跟踪缩进,即使遵循缩进指南也很难,特别是因为 2 个空格缩进是常态而且 [制表符缩进被禁止][5] [^2] 。
|
||||
|
||||
不小心缩进出错通常不算错误,它通常只是反序列化为你不想要的东西。这样只能祝你调试快乐!
|
||||
|
||||
我已经愉快地编写 Python 长达十多年,所以我已经习惯了显眼的空白,但有时候我仍在和 YAML 抗争。在 Python 中,虽然没有那种长达几页的函数,但数据或配置文件的长度没有这种自然限制,这就带来了缺点和损失了清晰度。
|
||||
|
||||
对于小文件,这不是问题,但它确实无法很好地扩展到较大的文件,特别是如果你以后想编辑它们的话。
|
||||
|
||||
### 这非常复杂
|
||||
|
||||
在浏览一个基本的例子时,YAML 看似“简单”和“显而易见”,但事实证明并非如此。[YAML 规范][6]有 23449 个单词,为了比较,[TOML][7] 有 3339 个单词,[Json][8] 有 1969 个单词,[XML][9] 有 20603 个单词。
|
||||
|
||||
我们中有谁读过全部规范吗?有谁读过并理解了全部?谁阅读过,理解进而**记住**所有这些?
|
||||
|
||||
例如,你知道[在 YAML 中编写多行字符串有 9 种方法][10]吗?并且它们具有细微的不同行为。
|
||||
|
||||
是的 :-/
|
||||
|
||||
如果你看一下[那篇文章的修订历史][11],它就会变得更加有趣,因为文章的作者发现了越来越多的方法可以实现这一点,以及更多的细微之处。
|
||||
|
||||
它从预览开始告诉我们 YAML 规范,它表明(强调我的):
|
||||
|
||||
> 本节简要介绍了 YAML 的表达能力。**预计初次阅读的人不可能理解所有的例子**。相反,这些选择用作该规范其余部分的动机。
|
||||
|
||||
#### 令人惊讶的行为
|
||||
|
||||
以下会解析成什么([Colm O’Connor][12] 提供的例子):
|
||||
|
||||
```
|
||||
- Don Corleone: Do you have faith in my judgment?
|
||||
- Clemenza: Yes
|
||||
- Don Corleone: Do I have your loyalty?
|
||||
```
|
||||
|
||||
结果为:
|
||||
|
||||
```
|
||||
[
|
||||
{'Don Corleone': 'Do you have faith in my judgment?'},
|
||||
{'Clemenza': True},
|
||||
{'Don Corleone': 'Do I have your loyalty?'}
|
||||
]
|
||||
```
|
||||
|
||||
那么这个呢:
|
||||
|
||||
```
|
||||
python: 3.5.3
|
||||
postgres: 9.3
|
||||
```
|
||||
|
||||
`3.5.3` 被识别为字符串,但 `9.3` 被识别为数字而不是字符串:
|
||||
|
||||
```
|
||||
{'python': '3.5.3', 'postgres': 9.3}
|
||||
```
|
||||
|
||||
这个呢:
|
||||
|
||||
```
|
||||
Effenaar: Eindhoven
|
||||
013: Tilburg
|
||||
```
|
||||
|
||||
`013` 是<ruby>蒂尔堡<rt>Tilburg<rt></ruby>的一个流行音乐场地,但 YAML 会告诉你错误答案,因为它被解析为八进制数字:
|
||||
|
||||
```
|
||||
{11: 'Tilburg', 'Effenaar': 'Eindhoven'}
|
||||
```
|
||||
|
||||
所有这一切,以及更多,就是为什么许多经验丰富的 YAMLer 经常会将所有字符串用引号引起来的原因,即使它不是严格要求。许多人不使用引号,而且很容易忘记,特别是如果文件的其余部分(可能由其他人编写)不使用引号。
|
||||
|
||||
### 它不方便
|
||||
|
||||
因为它太复杂了,它所声称的可移植性被夸大了。例如,考虑以下这个从 YAML 规范中获取的示例:
|
||||
|
||||
```
|
||||
? - Detroit Tigers
|
||||
- Chicago cubs
|
||||
:
|
||||
- 2001-07-23
|
||||
|
||||
? [ New York Yankees,
|
||||
Atlanta Braves ]
|
||||
: [ 2001-07-02, 2001-08-12,
|
||||
2001-08-14 ]
|
||||
```
|
||||
|
||||
抛开大多数读者可能甚至不知道这是在做什么之外,请尝试使用 PyYAML 在 Python 中解析它:
|
||||
|
||||
```
|
||||
yaml.constructor.ConstructorError: while constructing a mapping
|
||||
in "a.yaml", line 1, column 1
|
||||
found unhashable key
|
||||
in "a.yaml", line 1, column 3
|
||||
```
|
||||
|
||||
在 Ruby 中,它可以工作:
|
||||
|
||||
```
|
||||
{
|
||||
["Detroit Tigers", "Chicago cubs"] => [
|
||||
#<Date: 2001-07-23 ((2452114j,0s,0n),+0s,2299161j)>
|
||||
],
|
||||
["New York Yankees", "Atlanta Braves"] => [
|
||||
#<Date: 2001-07-02 ((2452093j,0s,0n),+0s,2299161j)>,
|
||||
#<Date: 2001-08-12 ((2452134j,0s,0n),+0s,2299161j)>,
|
||||
#<Date: 2001-08-14 ((2452136j,0s,0n),+0s,2299161j)>
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
这个原因是你不能在 Python 中使用列表作为一个字典的键:
|
||||
|
||||
```
|
||||
>>> {['a']: 'zxc'}
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
TypeError: unhashable type: 'list'
|
||||
```
|
||||
|
||||
而这种限制并不是 Python 特有的,PHP、JavaScript 和 Go 等常用语言都有此限制。
|
||||
|
||||
因此,在 YAML 文件中使用这种语法,你将无法在大多数语言中解析它。
|
||||
|
||||
这是另一个从 YAML 规范的示例部分中获取的:
|
||||
|
||||
```
|
||||
# Ranking of 1998 home runs
|
||||
---
|
||||
- Mark McGwire
|
||||
- Sammy Sosa
|
||||
- Ken Griffey
|
||||
|
||||
# Team ranking
|
||||
---
|
||||
- Chicago Cubs
|
||||
- St Louis Cardinals
|
||||
```
|
||||
|
||||
Python 会输出:
|
||||
|
||||
```
|
||||
yaml.composer.ComposerError: expected a single document in the stream
|
||||
in "a.yaml", line 3, column 1
|
||||
but found another document
|
||||
in "a.yaml", line 8, column 1
|
||||
```
|
||||
|
||||
然而 Ruby 输出:
|
||||
|
||||
```
|
||||
["Mark McGwire", "Sammy Sosa", "Ken Griffey"]
|
||||
```
|
||||
|
||||
原因是单个文件中有多个 YAML 文档(`---` 意味开始一个新文档)。在 Python 中,有一个 `load_all` 函数来解析所有文档,而 Ruby 的 `load()` 只是加载第一个文档,据我所知,它没有办法加载多个文档。
|
||||
|
||||
[在实现之间存在很多不兼容][13]。
|
||||
|
||||
### 目标实现了吗?
|
||||
|
||||
规范说明:
|
||||
|
||||
> YAML 的设计目标是降低优先级:
|
||||
>
|
||||
> 1. YAML 很容易被人类阅读。
|
||||
> 2. YAML 数据在编程语言之间是可移植的。
|
||||
> 3. YAML 匹配敏捷语言的原生数据结构。
|
||||
> 4. YAML 有一个一致的模型来支持通用工具。
|
||||
> 5. YAML 支持一次性处理。
|
||||
> 6. YAML 具有表现力和可扩展性。
|
||||
> 7. YAML 易于实现和使用。
|
||||
|
||||
那么它做的如何呢?
|
||||
|
||||
> YAML 很容易被人类阅读。
|
||||
|
||||
只有坚持一小部分子集时才有效。完整的规则集很复杂 —— 远远超过 XML 或 JSON。
|
||||
|
||||
> YAML 数据在编程语言之间是可移植的。
|
||||
|
||||
事实并非如此,因为创建常见语言不支持的结构太容易了。
|
||||
|
||||
> YAML 匹配敏捷语言的原生数据结构。
|
||||
|
||||
参见上面。另外,为什么只支持敏捷(或动态)语言?其他语言呢?
|
||||
|
||||
> YAML 有一个一致的模型来支持通用工具。
|
||||
|
||||
我甚至不确定这意味着什么,我找不到任何详细说明。
|
||||
|
||||
> YAML 支持一次性处理。
|
||||
|
||||
这点我接受。
|
||||
|
||||
> YAML 具有表现力和可扩展性。
|
||||
|
||||
嗯,是的,但它太富有表现力(例如太复杂)。
|
||||
|
||||
> YAML 易于实现和使用。
|
||||
|
||||
```
|
||||
$ cat `ls -1 ~/gocode/src/github.com/go-yaml/yaml/*.go | grep -v _test` | wc -l
|
||||
9247
|
||||
|
||||
$ cat /usr/lib/python3.5/site-packages/yaml/*.py | wc -l
|
||||
5713
|
||||
```
|
||||
|
||||
### 结论
|
||||
|
||||
不要误解我的意思,并不是说 YAML 很糟糕 —— 它肯定不像[使用 JSON 那么多的问题][1] —— 但它也不是非常好。有一些一开始并不明显的缺点和惊喜,还有许多更好的替代品,如 [TOML][7] 和其他更专业的格式。
|
||||
|
||||
就个人而言,当我有选择时,我不太可能再次使用它。
|
||||
|
||||
如果你必须使用 YAML,那么我建议你使用 [StrictYAML][14],它会删除一些(虽然不是全部)比较麻烦的部分。
|
||||
|
||||
### 反馈
|
||||
|
||||
你可以发送电子邮件至 [martin@arp242.net][15] 或[创建 GitHub issue][16] 以获取反馈、问题等。
|
||||
|
||||
[^1]: 在 PHP 中你需要修改一个 INI 设置来获得安全的行为,不能只是调用像 `yaml_safe()` 这样的东西。PHP 想尽办法让愚蠢的东西越发愚蠢。干得漂亮!
|
||||
[^2]: 不要在这里做空格与制表符之争,如果这里可以用制表符的话,我可以(临时)增加制表符宽度来使它更易读——这是制表符的一种用途。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://arp242.net/weblog/yaml_probably_not_so_great_after_all.html
|
||||
|
||||
作者:[Martin Tournoij][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[MjSeven](https://github.com/MjSeven)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://arp242.net/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: http://arp242.net/weblog/JSON_as_configuration_files-_please_dont.html
|
||||
[2]: https://github.com/search?q=yaml.load&type=Code&utf8=%E2%9C%93
|
||||
[3]: https://github.com/search?q=yaml.safe_load&type=Code&utf8=%E2%9C%93
|
||||
[4]: https://www.sitepoint.com/anatomy-of-an-exploit-an-in-depth-look-at-the-rails-yaml-vulnerability/
|
||||
[5]: http://www.yaml.org/faq.html
|
||||
[6]: http://yaml.org/spec/1.2/spec.pdf
|
||||
[7]: https://github.com/toml-lang/toml
|
||||
[8]: http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
|
||||
[9]: https://www.w3.org/TR/REC-xml/
|
||||
[10]: http://stackoverflow.com/a/21699210/660921
|
||||
[11]: http://stackoverflow.com/posts/21699210/revisions
|
||||
[12]: https://github.com/crdoconnor/strictyaml/blob/master/FAQ.rst#what-is-wrong-with-implicit-typing
|
||||
[13]: https://github.com/cblp/yaml-sucks
|
||||
[14]: https://github.com/crdoconnor/strictyaml
|
||||
[15]: mailto:martin@arp242.net
|
||||
[16]: https://github.com/Carpetsmoker/arp242.net/issues/new
|
@ -0,0 +1,90 @@
|
||||
5 款 Linux 街机游戏
|
||||
================
|
||||
|
||||

|
||||
|
||||
长久以来,游戏都是 Linux 的软肋。近些年,Steam、GOG 等游戏发布平台上不少商业游戏都开始支持 Linux,这对于 Linux 的游戏生态来说是件好事,但是我们能在这些平台上玩到的游戏通常是不开源的商业作品。当然,这些游戏在一个开源的操作系统上运行,但对于一个开源提倡者来说这似乎还不够纯粹。
|
||||
|
||||
那么,我们能找到既自由开源又能给玩家带来完整游戏体验的优质游戏吗?当然!虽然绝大多数的开源游戏很难和 3A 商业游戏大作竞争,但仍然有不少各种类型的开源游戏,不仅内容有趣而且直接可以通过几大 Linux 发行版本库中直接安装。
|
||||
|
||||
本文首先介绍 Linux 开源游戏中的街机类型游戏,在之后的文章中,我将介绍桌面和卡牌游戏,解谜游戏,竞速游戏,以及策略模拟游戏。
|
||||
|
||||
### <ruby>太空危机<rt>AstroMenace</rt></ruby>
|
||||
|
||||

|
||||
|
||||
[太空危机][3] 是一个近现代太空背景下的滚动页面射击游戏。开发初期它是一个闭源游戏,但它的代码和素材而后以开源许可证发布了。游戏玩法和大多数此类游戏大同小异,但它有质量极高的 3D 画面。飞船和武器升级可以通过击杀敌人所获得的点数购买。游戏的难度可以选择,因此适合新手以及想要追求挑战的硬核玩家。
|
||||
|
||||
安装太空危机,你只需要在终端下运行以下指令:
|
||||
|
||||
- Fedora 用户: `dnf install astromenace`
|
||||
- Debian/Ubuntu 用户: `apt install astromenace`
|
||||
|
||||
### <ruby>坦克战役<rt>Battle Tanks</rt></ruby>
|
||||
|
||||

|
||||
|
||||
[坦克战役][4] 是一个俯瞰式视角的快节奏坦克战斗游戏。玩家可以选择三种不同的陆地坦克,操纵其在地图上前行,收集道具并且尝试炸飞敌军。它有四种游戏模式,死亡竞赛(又称“死斗”)、团队死斗、夺旗模式和合作模式。死斗和夺旗模式下,分别有 9 张地图可供玩家选择,合作模式则有 4 张。该游戏支持分屏本地双人游戏,以及在线多人竞技。游戏节奏很快,默认一次战役仅 5 分钟,因此,坦克战役十分适合想要利用零碎时间快速来一局的玩家。
|
||||
|
||||
安装坦克战役,你只需要在终端下运行以下指令:
|
||||
|
||||
- Fedora 用户: `dnf install btanks`
|
||||
- Debian/Ubuntu 用户: `apt install btanks`
|
||||
|
||||
### <ruby>火星<rt>M.A.R.S.</rt></ruby>
|
||||
|
||||

|
||||
|
||||
[火星][5] 是一个自上而下的太空射击游戏,游戏机制类似传统街机游戏 “<ruby>爆破彗星<rt>Asteroids</rt></ruby>”。玩家在操控一个太空船的同时向敌方射击并躲避敌军的弹幕射击。游戏有标准的死斗和团体死斗模式,除此之外也有更新鲜的比赛形式 —— 例如在一个模式下,玩家需要控制一个球使其进入敌方母星。该游戏支持本地多人游戏,但遗憾的是不支持多人联机。该游戏的开发更新似乎已经停止,所以该游戏之后增加联机模式的几率很小,但就算没有联机支持,这个游戏仍然值得一试。
|
||||
|
||||
安装火星,你只需要在终端下运行以下指令:
|
||||
|
||||
- Fedora 用户: `dnf install marsshooter`
|
||||
- Debian/Ubuntu 用户: `apt install marsshooter`
|
||||
|
||||
### <ruby>不存在之球<rt>Neverball</rt></ruby>
|
||||
|
||||

|
||||
|
||||
[不存在之球][6] 的游戏灵感来源自世嘉的 “<ruby>超级猴子球<rt>Super Monkey Ball</rt></ruby>” ,玩家需要将一个球在 3D 球场上运动起来,但是玩家控制的不是球,而是球场。游戏任务是在规定的时限内,收集足够多的金币从而打开该关卡的出口并且将小球落进该洞中。游戏可以调整难度,从休闲到难以超乎想象,可以适应不同的玩家需求。该游戏支持键盘/鼠标以及控制杆操作。
|
||||
|
||||
安装不存在之球,你只需要在终端下运行以下指令:
|
||||
|
||||
- Fedora 用户:`dnf install neverball`
|
||||
- Debian/Ubuntu 用户:`apt install neverball`
|
||||
|
||||
### <ruby>超级 Tux<rt>SuperTux</rt></ruby>
|
||||
|
||||

|
||||
|
||||
[超级 Tux][7] 是继任天堂超级马里奥后的一款 2D 的平台跳跃游戏。Linux 的吉祥物企鹅 Tux 代替了马里奥,而鸡蛋对应着马里奥系列中的蘑菇能力提升。当 Tux 获得了鸡蛋得到了能力提升,它便可以收集花朵,而花朵可以带来新的附加特殊能力。火焰花在关卡中最为常见,收集了火焰花的 Tux 可以掷出火球。除此之外,冰冻花/空气花/土地花也在游戏的程序中。收集星星的能力提升能使 Tux 暂时变得隐形,就如同马里奥系列游戏。该游戏最基础的一组关卡,冰之岛也有 30 关之多,因此游戏的内容和流程和超级马里奥系列一般长。SuperTux 还有一些附加关卡,例如三个额外奖励小岛、一个森林之岛、一个万圣节岛、一个孵化处,以及很多测试关卡。SuperTux 有一个自带的关卡编辑器,所以玩家可以创建他们的原创关卡。
|
||||
|
||||
安装超级 Tux,你只需要在终端下运行以下指令:
|
||||
|
||||
- Fedora 用户:`dnf install supertux`
|
||||
- Debian/Ubuntu 用户: `apt install supertux`
|
||||
|
||||
如果我没有在上文中提及你最喜欢的开源街机游戏,欢迎在评论中分享。
|
||||
|
||||
### 有关作者
|
||||
|
||||
Joshua Allen Holm - 是 Opensource.com 的社区协调者之一。他的主要兴趣有数字人文、学术开放以及公开教育资源。你可以在 GitHub、GitLab、LinkedIn 和 Zotero 上找到他。可以通过 holmja@opensource.com 联系到他。
|
||||
|
||||
------
|
||||
|
||||
via: https://opensource.com/article/18/1/arcade-games-linux
|
||||
|
||||
作者:[Joshua Allen Holm][a]
|
||||
译者:[Scoutydren](https://github.com/Scoutydren)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/holmja
|
||||
[1]: http://store.steampowered.com/
|
||||
[2]: https://www.gog.com/
|
||||
[3]: http://www.viewizard.com/
|
||||
[4]: http://btanks.sourceforge.net/blog/about-game
|
||||
[5]: http://mars-game.sourceforge.net/?page_id=10
|
||||
[6]: https://neverball.org/index.php
|
||||
[7]: http://supertux.org/
|
@ -0,0 +1,261 @@
|
||||
tmux:适用于重度命令行 Linux 用户的终端复用器
|
||||
======
|
||||
|
||||
tmux 是<ruby>终端复用器<rt>terminal multiplexer</rt></ruby>的缩写,它允许用户在单个窗口中创建或启用多个终端(垂直或水平),当你处理不同的问题时,可以在单个窗口中轻松访问和控制它们。
|
||||
|
||||
它使用客户端-服务器模型,允许在用户之间共享会话,也可以将终端连接到 tmux 会话。我们可以根据需要轻松移动或重新排列虚拟控制台。终端会话可以从一个虚拟控制台自由切换到另一个。
|
||||
|
||||
tmux 依赖于 `libevent` 和 `ncurses` 库。tmux 在屏幕底部提供了一个状态行,它显示当前 tmux 会话的有关信息,例如当前窗口编号、窗口名称、用户名、主机名、当前时间和日期。
|
||||
|
||||
启动 tmux 时,它会在一个单独窗口上创建一个新的会话,并将其显示在屏幕上。它允许用户在同一个会话中创建任意数量的窗口。
|
||||
|
||||
许多人说它类似于 `screen`,但我不这么认为,因为它提供了许多配置选项。
|
||||
|
||||
**注意:** `Ctrl+b` 是 tmux 中的默认命令前缀,因此,要在 tmux 中执行任何操作,你必须先输入该前缀然后输入所需的选项。
|
||||
|
||||
### tmux 特性
|
||||
|
||||
* 创建任意数量的窗口
|
||||
* 在一个窗口中创建任意数量的窗格
|
||||
* 它允许垂直和水平分割
|
||||
* 分离并重新连接窗口
|
||||
* 客户端-服务器架构,这允许用户之间共享会话
|
||||
* tmux 提供许多配置技巧
|
||||
|
||||
**建议阅读:**
|
||||
|
||||
- [tmate - 马上与其他人分享你的终端会话][2]
|
||||
- [Teleconsole - 一个与其他人分享终端会话的工具][3]
|
||||
|
||||
### 如何安装 tmux 命令
|
||||
|
||||
大多数 Linux 系统默认预安装 tmux 命令。如果没有,按照以下步骤安装。
|
||||
|
||||
对于 Debian/Ubuntu,使用 [APT-GET 命令][4]或 [APT 命令][5]来安装:
|
||||
|
||||
```
|
||||
$ sudo apt install tmux
|
||||
```
|
||||
|
||||
对于 RHEL/CentOS,使用 [YUM 命令][6]来安装:
|
||||
|
||||
```
|
||||
$ sudo yum install tmux
|
||||
```
|
||||
|
||||
对于 Fedora,使用 [DNF 命令][7]来安装:
|
||||
|
||||
```
|
||||
$ sudo dnf install tmux
|
||||
```
|
||||
|
||||
对于 Arch Linux,使用 [Pacman 命令][8]来安装:
|
||||
|
||||
```
|
||||
$ sudo pacman -S tmux
|
||||
```
|
||||
|
||||
对于 openSUSE,使用 [Zypper 命令][9]来安装:
|
||||
|
||||
```
|
||||
$ sudo zypper in tmux
|
||||
```
|
||||
|
||||
### 如何使用 tmux
|
||||
|
||||
在终端上运行以下命令来启动 tmux 会话。启动 tmux 后,它会在一个新窗口中创建新会话,并将使用你的用户账户自动登录到你的默认 shell。
|
||||
|
||||
```
|
||||
$ tmux
|
||||
```
|
||||
|
||||
![][11]
|
||||
|
||||
你会得到类似于我们上面的截图。tmux 附带状态栏,显示有关当前会话详细信息、日期、时间等。
|
||||
|
||||
状态栏信息如下:
|
||||
|
||||
* `[0]`:它表示由 tmux 服务器创建的会话号。默认情况下,它从 0 开始。
|
||||
* `0:bash`:表示会话号、命令行提示符(这里的 `bash` 表示 shell 名称)。
|
||||
* `*`:这表示该窗口现在处于活动状态。
|
||||
* 主机名:显示服务器的完全主机名。
|
||||
* 日期与时间:显示当前日期和时间。
|
||||
|
||||
(LCTT 译注:tmux 的状态可以根据需要定制,也会因环境、版本的不同而不同。)
|
||||
|
||||
### 如何拆分窗口
|
||||
|
||||
tmux 允许用户垂直或水平分割窗口,称为窗格。每个窗格都包含自己独立运行的终端实例。我们来看看如何做到这一点。
|
||||
|
||||
按下 `Ctrl+b, %` 来垂直分割窗格。
|
||||
|
||||
![][13]
|
||||
|
||||
按下 `Ctrl+b, "` 来水平分割窗格。
|
||||
|
||||
![][14]
|
||||
|
||||
### 如何在窗格之间移动
|
||||
|
||||
假设,我们创建了一些窗格,希望在它们之间移动,这该怎么做?如果你不知道怎么做,那么使用 tmux 就没有意义了。使用以下控制键执行操作。在窗格之间移动有许多方法。
|
||||
|
||||
- 按 `Ctrl+b, ←` - 选择左边的窗格
|
||||
- 按 `Ctrl+b, →` - 选择右边的窗格
|
||||
- 按 `Ctrl+b, ↑` - 选择上边的窗格
|
||||
- 按 `Ctrl+b, ↓` - 选择下边的窗格
|
||||
- 按 `Ctrl+b, {` - 来向左交换窗格
|
||||
- 按 `Ctrl+b, }` - 来向右交换窗格
|
||||
- 按 `Ctrl+b, o` - 切换到下一个窗格(从左到右,从上到下)
|
||||
- 按 `Ctrl+b, ;` - 移动到先前活动的窗格
|
||||
|
||||
出于测试目的,我们将在窗格之间移动。现在我们在 `pane2` 中,它展示了 `lsb_release -a` 命令的输出。
|
||||
|
||||
![][15]
|
||||
|
||||
我们将移动到 `pane0`,它显示 `uname -a` 命令的输出。
|
||||
|
||||
![][16]
|
||||
|
||||
### 如何打开/创建新窗口
|
||||
|
||||
你可以在一个终端内打开任意数量的窗口。
|
||||
|
||||
- 按 `Ctrl+b, c` 来创建一个新窗口。
|
||||
- 按 `Ctrl+b, n` 移动到下一个窗口。
|
||||
- 按 `Ctrl+b, p` 移动到上一个窗口。
|
||||
- 按 `Ctrl+b, 0` ~ `Ctrl+b, 9` 立即移动到特定窗口。
|
||||
- 按 `Ctrl+b, l` 移动到先前选择的窗口。
|
||||
|
||||
我有两个窗口,第一个窗口有三个窗格,其中包含操作系统版本信息,`top` 命令输出和内核信息。
|
||||
|
||||
![][17]
|
||||
|
||||
第二个窗口有两个窗格,其中包含 Linux 发行版 logo 信息。使用以下命令执行操作:
|
||||
|
||||
![][18]
|
||||
|
||||
按 `Ctrl+b, w` 以交互方式选择当前窗口。
|
||||
|
||||
![][19]
|
||||
|
||||
### 如何缩放窗格
|
||||
|
||||
你正在一些非常小的窗格中工作,并且你希望将其缩小以进行进一步的工作。要做到这一点,使用以下键绑定。
|
||||
|
||||
目前我们有三个窗格,我在 `pane1` 工作,它使用 `top` 命令显示系统活动信息,我将缩放它。
|
||||
|
||||
![][17]
|
||||
|
||||
缩放窗格时,它将隐藏所有其它窗格,并只显示窗口中的缩放窗格。
|
||||
|
||||
![][20]
|
||||
|
||||
按 `Ctrl+b, z` 缩放窗格,并再次按下它使缩放窗格恢复原状。
|
||||
|
||||
### 显示窗格信息
|
||||
|
||||
要了解窗格编号及其大小,运行以下命令。
|
||||
|
||||
按 `Ctrl+b, q` 可简单显示窗格索引。
|
||||
|
||||
![][21]
|
||||
|
||||
### 显示窗口信息
|
||||
|
||||
要知道窗口编号、布局大小,与窗口关联的窗格数量及其大小等,运行以下命令。
|
||||
|
||||
只需运行 `tmux list-windows` 即可查看窗口信息。
|
||||
|
||||
![][22]
|
||||
|
||||
### 如何调整窗格大小
|
||||
|
||||
你可能需要调整窗格大小来满足你的要求。你必须按下 `Ctrl+b, :`,然后在页面底部的黄色颜色条上输入以下详细信息。
|
||||
|
||||
![][23]
|
||||
|
||||
在上一部分中,我们打印了窗格索引,它同时也显示了窗格大小。为了测试,我们要向增加 `10` 个单元。参考以下输出,该窗格将 pane1 和 pane2 的大小从 `55x21` 增加到 `55x31`。
|
||||
|
||||
![][24]
|
||||
|
||||
**语法:** `Ctrl+b, :` 然后输入 `resize-pane [options] [cells size]`
|
||||
|
||||
- `Ctrl+b, :` 然后输入 `resize-pane -D 10` 将当前窗格大小向下调整 10 个单元。
|
||||
- `Ctrl+b, :` 然后输入 `resize-pane -U 10` 将当前窗格大小向上调整 10 个单元。
|
||||
- `Ctrl+b, :` 然后输入 `resize-pane -L 10` 将当前窗格大小向左调整 10 个单元。
|
||||
- `Ctrl+b, :` 然后输入 `resize-pane -R 10` 将当前窗格大小向右调整 10 个单元。
|
||||
|
||||
### 分离并重新连接 tmux 会话
|
||||
|
||||
tmux 最强大的功能之一是能够在需要时分离和重新连接会话。
|
||||
|
||||
运行一个长时间运行的进程,然后按下 `Ctrl+b`,接着按 `d`,通过离开正在运行的进程安全地分离你的 tmux 会话。
|
||||
|
||||
**建议阅读:** [如何在断开 SSH 会话后保持进程/命令继续运行][25]
|
||||
|
||||
现在,运行一个长时间运行的进程。出于演示目的,我们将把此服务器备份移动到另一个远程服务器以进行灾难恢复(DR)。
|
||||
|
||||
```
|
||||
$ rsync -avzhe ssh /backup root@192.168.0.161:/backups/week-1/
|
||||
```
|
||||
|
||||
在分离 tmux 会话之后,你将获得类似下面的输出。
|
||||
|
||||
```
|
||||
[detached (from session 0)]
|
||||
```
|
||||
|
||||
运行以下命令以列出可用的 tmux 会话。
|
||||
|
||||
```
|
||||
$ tmux ls
|
||||
0: 3 windows (created Tue Jan 30 06:17:47 2018) [109x45]
|
||||
```
|
||||
|
||||
现在,使用适当的会话 ID 重新连接 tmux 会话,如下所示:
|
||||
|
||||
```
|
||||
$ tmux attach -t 0
|
||||
```
|
||||
|
||||
### 如何关闭窗格和窗口
|
||||
|
||||
只需在相应的窗格中输入 `exit` 或按下 `Ctrl-d` 即可关闭它,和终端关闭类似。要关闭窗口,按下 `Ctrl+b, &`。
|
||||
|
||||
好了,就到这里了,希望你喜欢上它。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.2daygeek.com/tmux-a-powerful-terminal-multiplexer-emulator-for-linux/
|
||||
|
||||
作者:[Magesh Maruthamuthu][a]
|
||||
译者:[MjSeven](https://github.com/MjSeven)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.2daygeek.com/author/magesh/
|
||||
[1]:https://www.2daygeek.com/category/terminal-emulator/
|
||||
[2]:https://www.2daygeek.com/tmate-instantly-share-your-terminal-session-to-anyone-in-seconds/
|
||||
[3]:https://www.2daygeek.com/teleconsole-share-terminal-session-instantly-to-anyone-in-seconds/
|
||||
[4]:https://www.2daygeek.com/apt-get-apt-cache-command-examples-manage-packages-debian-ubuntu-systems/
|
||||
[5]:https://www.2daygeek.com/apt-command-examples-manage-packages-debian-ubuntu-systems/
|
||||
[6]:https://www.2daygeek.com/yum-command-examples-manage-packages-rhel-centos-systems/
|
||||
[7]:https://www.2daygeek.com/dnf-command-examples-manage-packages-fedora-system/
|
||||
[8]:https://www.2daygeek.com/pacman-command-examples-manage-packages-arch-linux-system/
|
||||
[9]:https://www.2daygeek.com/zypper-command-examples-manage-packages-opensuse-system/
|
||||
[10]:data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[11]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-1.png
|
||||
[13]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-2.png
|
||||
[14]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-3.png
|
||||
[15]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-4.png
|
||||
[16]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-5.png
|
||||
[17]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-8.png
|
||||
[18]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-6.png
|
||||
[19]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-7.png
|
||||
[20]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-9.png
|
||||
[21]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-10.png
|
||||
[22]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-14.png
|
||||
[23]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-11.png
|
||||
[24]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-13.png
|
||||
[25]:https://www.2daygeek.com/how-to-keep-a-process-command-running-after-disconnecting-ssh-session/
|
@ -0,0 +1,144 @@
|
||||
如何使用 Ansible 管理你的工作站配置
|
||||
======
|
||||
|
||||
> 在这个系列的第一篇中,学习一下管理笔记本电脑和台式机配置的基础内容。
|
||||
|
||||

|
||||
|
||||
配置管理是服务器管理和 DevOps 的一个非常重要的方面。“<ruby>基础架构即代码<rt>infrastructure as code</rt></ruby>”方法可以轻松地以各种配置部署服务器,并动态扩展组织的资源以满足用户需求。但是,对于希望自动设置自己的笔记本电脑和台式机(工作站)的个人管理员的关注较少。
|
||||
|
||||
在本系列中,我将向你展示如何通过 [Ansible][1] 自动化你的工作站设置,如果你想要或需要重新安装你的机器,这可以让你轻松恢复整个配置。此外,如果你有多个工作站,则可以使用相同的方法在每个工作站上进行相同的配置。在第一篇文章中,我们将为个人或工作计算机设置基本的配置管理,并为本系列的其余部分奠定基础。到本文结束时,你将会因此得到一个可以工作的环境。本系列之后的每篇文章都会自动化更多内容并增加复杂性。
|
||||
|
||||
### 为什么用 Ansible?
|
||||
|
||||
有许多配置管理解决方案,包括 Salt Stack、Chef 和 Puppet。我更喜欢 Ansible,因为它在资源利用方面更轻量级,语法更容易阅读,并且如果正确使用它可以彻底改变你的配置管理。Ansible 的轻量级特性与这个主题特别相关,因为我们可能不希望运行一整台服务器而只是为了自动化我们的笔记本电脑和台式机的设置。一般我们总是想要快一些;我们可以使用某些东西来快速启动和运行,以在我们需要恢复的工作站或在多台机器之间同步我们的配置。我使用 Ansible 的具体方法(我将在本文中演示)非常适用于此,而不需要维护服务器。你只需下载配置并运行它。
|
||||
|
||||
### 我的方法
|
||||
|
||||
通常,Ansible 运行于中央服务器。它使用一个<ruby>库存清单<rt>inventory</rt></ruby>文件,该文件是一个文本文件,其中包含我们希望 Ansible 管理的所有主机及其 IP 地址或域名的列表。这对于静态环境非常有用,但对于工作站来说并不理想。原因是我们真的不知道我们的工作站在某一时刻的状态。也许我关闭了台式电脑,或者笔记本电脑可能会被挂起并放在我的包里。在任何一种情况下,Ansible 服务器都会抱怨,因为如果它们处于脱机状态,Ansible 就无法联系到我的机器。我们更需要的是按需方式,我们通过利用 `ansible-pull` 来实现这一目标。`ansible-pull` 命令是 Ansible 的一个命令,允许你从 Git 仓库下载配置并立即应用它。你不需要维护服务器或库存清单;你只需运行 `ansible-pull` 命令,给它一个 Git 仓库 URL,它将为你完成剩下的工作。
|
||||
|
||||
### 起步
|
||||
|
||||
首先,在要管理的计算机上安装 Ansible。有一个问题是许多发行版都附带了旧版本的 Ansible。根据经验,你肯定希望获得最新版本。Ansible 中经常引入新功能,如果你运行的是旧版本,则你在网上找到的示例语法可能无法正常运行,因为它使用的功能未在你安装的版本中实现。甚至发布的小版本都有很多新功能。其中一个例子是 `dconf` 模块,它是从 Ansible 2.4 开始的新功能。如果你尝试使用使用此模块的语法,除非你使用 2.4 或更新版本,否则会失败。在 Ubuntu 及其衍生产品中,我们可以使用官方个人包存档([PPA][2])轻松安装最新版本的 Ansible。以下命令可以解决这个问题:
|
||||
|
||||
```
|
||||
sudo apt-get install software-properties-common
|
||||
sudo apt-add-repository ppa:ansible/ansible
|
||||
sudo apt-get update
|
||||
sudo apt-get install ansible
|
||||
```
|
||||
|
||||
如果你没有使用 Ubuntu,请参阅 [Ansible 的文档][3] 了解如何为你的平台获取它。
|
||||
|
||||
接下来,我们需要一个 Git 仓库来保存我们的配置。满足此要求的最简单方法是在 GitHub 上创建一个空的仓库,或者如果有的话,也可以使用自己的 Git 服务器。为了简单起见,我假设你正在使用 GitHub,因此如果你正在使用其他仓库,请相应调整命令。在 GitHub 中创建一个仓库;你最终会得到一个与此类似的仓库 URL:
|
||||
|
||||
```
|
||||
git@github.com:<your_user_name>/ansible.git
|
||||
```
|
||||
|
||||
将该仓库克隆到你的本地工作目录(忽略任何抱怨仓库为空的消息):
|
||||
|
||||
```
|
||||
git clone git@github.com:<your_user_name>/ansible.git
|
||||
```
|
||||
|
||||
现在我们有了一个可以使用的空仓库。将你的工作目录切换到仓库(例如 `cd ./ansible`),并在你喜欢的文本编辑器中创建名为 `local.yml` 的文件。将以下配置放在该文件中:
|
||||
|
||||
```
|
||||
- hosts: localhost
|
||||
become: true
|
||||
tasks:
|
||||
- name: Install htop
|
||||
apt: name=htop
|
||||
```
|
||||
|
||||
你刚刚创建的文件被称为<ruby>剧本<rt>playbook</rt></ruby>,安装 `htop` 的指令(我任意选择的一个包作为例子)被称为<ruby>动作<rt>play</rt></ruby>。剧本本身是一个 YAML 格式的文件,它是一种易于阅读的标记语言。对 YAML 的完整讲述超出了本文的范围,但你无需专业理解即可熟练使用 Ansible。该配置易于阅读;只需查看此文件,你就可以轻松理解我们正在安装的 `htop` 软件包。要注意一下最后一行的 `apt` 模块,它只适用于基于 Debian 的系统。如果你使用的是 Red Hat 平台,你可以将其更改为 `yum` 而不是 `apt`,或者如果你正在使用 Fedora,则将其更改为 `dnf`。`name` 行只是提供有关我们任务的信息,并将显示在输出中。因此,你需要确保名称具有描述性,以便在需要对多个动作进行故障排除时很容易找到。
|
||||
|
||||
接下来,让我们将新文件提交到我们的仓库:
|
||||
|
||||
```
|
||||
git add local.yml
|
||||
git commit -m "initial commit"
|
||||
git push origin master
|
||||
```
|
||||
|
||||
现在我们的新剧本应该出现在我们的 GitHub 上的仓库中。我们可以使用以下命令应用我们创建的剧本:
|
||||
|
||||
```
|
||||
sudo ansible-pull -U https://github.com/<your_user_name>/ansible.git
|
||||
```
|
||||
|
||||
如果执行正确,`htop`包应该会安装在你的系统上。你可能会在开头附近看到一些警告,抱怨缺少库存清单文件。这很好,因为我们没有使用库存清单文件(我们也不需要这样做)。在输出结束时,它将概述它做的内容。如果 `htop` 安装正确,你应该在输出的最后一行看到 `changed = 1`。
|
||||
|
||||
它是如何工作的呢?`ansible-pull` 命令使用了 `-U` 选项,它需要一个仓库 URL。出于安全考虑,我给它提供了仓库 URL 的 https 版本,因为我不希望任何主机对仓库具有写访问权限(默认情况下 https 是只读的)。`local.yml` 是预设的剧本名称,因此我们不需要为剧本提供文件名:如果它在仓库的根目录中找到名为 `local.yml` 的剧本,它将自动运行它。接下来,我们在命令前面使用了 `sudo`,因为我们正在修改系统。
|
||||
|
||||
让我们继续为我们的剧本添加更多的包。我将添加两个包,使它看起来像这样:
|
||||
|
||||
```
|
||||
- hosts: localhost
|
||||
become: true
|
||||
tasks:
|
||||
- name: Install htop
|
||||
apt: name=htop
|
||||
|
||||
- name: Install mc
|
||||
apt: name=mc
|
||||
|
||||
- name: Install tmux
|
||||
apt: name=tmux
|
||||
```
|
||||
|
||||
我添加了更多的动作(任务)来安装另外两个包,`mc` 和 `tmux`。在此剧本中选择安装的哪些软件包并不重要;我只是随意挑选这些。你应该安装你希望所有的系统都具有的软件包。唯一需要注意的是,在你分发前,你必须知道那个包存在于软件仓库中。
|
||||
|
||||
在我们提交并应用这个更新的剧本之前,我们应该整理一下它。它可以很好地工作,但(说实话)它看起来有点混乱。让我们尝试在一个动作中安装所有三个包。用下面这个替换你的 `local.yml` 的内容:
|
||||
|
||||
```
|
||||
- hosts: localhost
|
||||
become: true
|
||||
tasks:
|
||||
- name: Install packages
|
||||
apt: name={{item}}
|
||||
with_items:
|
||||
- htop
|
||||
- mc
|
||||
- tmux
|
||||
```
|
||||
|
||||
现在看起来更干净、更有效率了。我们使用 `with_items` 将我们的包列表合并为一个动作。如果我们想要添加其他包,我们只需添加另一个带有连字符和包名称的行。可以把 `with_items` 看做类似于 `for` 循环。我们列出的每个包都将安装。
|
||||
|
||||
将我们的新更改提交回仓库:
|
||||
|
||||
```
|
||||
git add local.yml
|
||||
git commit -m "added additional packages, cleaned up formatting"
|
||||
git push origin master
|
||||
```
|
||||
|
||||
现在我们可以运行我们的剧本以接受新的新配置:
|
||||
|
||||
```
|
||||
sudo ansible-pull -U https://github.com/<your_user_name>/ansible.git
|
||||
```
|
||||
|
||||
不可否认,这个例子还没有做多少事情;它所做的就是安装一些软件包。你可以使用包管理器更快地安装这些包。然而,随着这个系列的继续,这些例子将变得更加复杂,我们将自动化更多的东西。最后,你创建的 Ansible 配置将自动执行越来越多的任务。例如,我自己使用的那个配置可以自动安装数百个软件包、设置cron 作业、处理桌面配置等等。
|
||||
|
||||
从我们迄今为止所取得的成就来看,你可能已经有了大概了解。我们所要做的就是创建一个仓库,在该仓库中放置一个剧本,然后利用 `ansible-pull` 命令拉取该仓库并将其应用到我们的机器上。我们不需要设置服务器。将来,如果我们想要更改配置,我们可以拉取该仓库、更新它,然后将其推回到我们的仓库并应用它。如果我们要设置新机器,我们只需要安装 Ansible 并应用配置。
|
||||
|
||||
在下一篇文章中,我们将通过 cron 和一些其他项目进一步自动化。与此同时,我已将本文的代码复制到
|
||||
[我的 GitHub 仓库][4] 中,以便你可以用你的语法对比一下我的。随着我们的进展,我会不断更新代码。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/3/manage-workstation-ansible
|
||||
|
||||
作者:[Jay LaCroix][a]
|
||||
译者:[wxy](https://github.com/)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/jlacroix
|
||||
[1]:https://www.ansible.com/
|
||||
[2]:https://launchpad.net/ubuntu/+ppas
|
||||
[3]:http://docs.ansible.com/ansible/latest/intro_installation.html
|
||||
[4]:https://github.com/jlacroix82/ansible_article
|
@ -0,0 +1,154 @@
|
||||
用 PGP 保护代码完整性(四):将主密钥移到离线存储中
|
||||
======
|
||||
> 如果开发者的 PGP 密钥被偷了,危害非常大。了解一下如何更安全。
|
||||
|
||||

|
||||
|
||||
在本系列教程中,我们为使用 PGP 提供了一个实用指南。你可以从下面的链接中查看前面的文章:
|
||||
|
||||
- [第一部分:基本概念和工具][1]
|
||||
- [第二部分:生成你的主密钥][2]
|
||||
- [第三部分:生成 PGP 子密钥][3]
|
||||
|
||||
这是本系列教程的第四部分,我们继续本教程,我们将谈一谈如何及为什么要将主密钥从你的家目录移到离线存储中。现在开始我们的教程。
|
||||
|
||||
#### 清单
|
||||
|
||||
* 准备一个加密的可移除的存储(必要)
|
||||
* 备份你的 GnuPG 目录(必要)
|
||||
* 从你的家目录中删除主密钥(推荐)
|
||||
* 从你的家目录中删除吊销证书(推荐)
|
||||
|
||||
#### 考虑事项
|
||||
|
||||
为什么要从你的家目录中删除你的主 [C] 密钥 ?这样做的主要原因是防止你的主密钥失窃或意外泄露。对于心怀不轨的人来说,私钥对他们具有很大的诱惑力 —— 我们知道有几个恶意软件成功地实现了扫描用户的家目录并将发现的私钥内容上传。
|
||||
|
||||
对于开发者来说,私钥失窃是非常危险的事情 —— 在自由软件的世界中,这无疑是身份证明失窃。从你的家目录中删除私钥将帮你防范这类事件的发生。
|
||||
|
||||
#### 备份你的 GnuPG 目录
|
||||
|
||||
**!!!绝对不要跳过这一步!!!**
|
||||
|
||||
备份你的 PGP 密钥将让你在需要的时候很容易地恢复它们,这很重要!(这与我们做的使用 paperkey 的灾难级备份是不一样的)。
|
||||
|
||||
#### 准备可移除的加密存储
|
||||
|
||||
我们从取得一个(最好是两个)小型的 USB “拇指“ 驱动器(可加密 U 盘)开始,我们将用它来做备份。你首先需要去加密它们:
|
||||
|
||||
加密密码可以使用与主密钥相同的密码。
|
||||
|
||||
#### 备份你的 GnuPG 目录
|
||||
|
||||
加密过程结束之后,重新插入 USB 驱动器并确保它能够正常挂载。你可以通过运行 `mount` 命令去找到设备挂载点的完全路径。(在 Linux 下,外置介质一般挂载在 `/media/disk` 下,Mac 一般在它的 `/Volumes` 下)
|
||||
|
||||
你知道了挂载点的全路径后,将你的整个 GnuPG 的目录复制进去:
|
||||
|
||||
```
|
||||
$ cp -rp ~/.gnupg [/media/disk/name]/gnupg-backup
|
||||
```
|
||||
|
||||
(注意:如果出现任何套接字不支持的错误,没有关系,直接忽略它们。)
|
||||
|
||||
现在,用如下的命令去测试一下,确保它们能够正常地工作:
|
||||
|
||||
```
|
||||
$ gpg --homedir=[/media/disk/name]/gnupg-backup --list-key [fpr]
|
||||
```
|
||||
|
||||
如果没有出现任何错误,说明一切正常。弹出这个 USB 驱动器并给它粘上一个明确的标签,以便于你下次需要它时能够很快找到它。接着,将它放到一个安全的 —— 但不要太远 —— 的地方,因为从现在起,你需要偶尔使用它来做一些像编辑身份信息、添加或吊销子证书、或签署其它人的密钥这样的事情。
|
||||
|
||||
#### 删除主密钥
|
||||
|
||||
我们家目录中的文件并没有像我们所想像的那样受到保护。它们可能会通过许多不同的方式被泄露或失窃:
|
||||
|
||||
* 通过快速复制来配置一个新工作站时的偶尔事故
|
||||
* 通过系统管理员的疏忽或恶意操作
|
||||
* 通过安全性欠佳的备份
|
||||
* 通过桌面应用中的恶意软件(浏览器、pdf 查看器等等)
|
||||
* 通过跨境胁迫
|
||||
|
||||
使用一个很好的密码来保护你的密钥是降低上述风险的一个很好方法,但是密码能够通过键盘记录器、背后窥视、或其它方式被发现。基于以上原因,我们建议去配置一个从你的家目录上可移除的主密钥,将它保存在一个离线存储中。
|
||||
|
||||
##### 删除你的主密钥
|
||||
|
||||
**请查看前面的节,确保你有完整的你的 GnuPG 目录的一个备份。如果你没有一个可用的备份,下面所做的操作将会使你的主密钥失效!!!**
|
||||
|
||||
首先,识别你的主密钥的 keygrip:
|
||||
|
||||
```
|
||||
$ gpg --with-keygrip --list-key [fpr]
|
||||
```
|
||||
|
||||
它的输出应该像下面这样:
|
||||
|
||||
```
|
||||
pub rsa4096 2017-12-06 [C] [expires: 2019-12-06]
|
||||
111122223333444455556666AAAABBBBCCCCDDDD
|
||||
Keygrip = AAAA999988887777666655554444333322221111
|
||||
uid [ultimate] Alice Engineer <alice@example.org>
|
||||
uid [ultimate] Alice Engineer <allie@example.net>
|
||||
sub rsa2048 2017-12-06 [E]
|
||||
Keygrip = BBBB999988887777666655554444333322221111
|
||||
sub rsa2048 2017-12-06 [S]
|
||||
Keygrip = CCCC999988887777666655554444333322221111
|
||||
```
|
||||
|
||||
找到 `pub` 行下方的 `Keygrip` 条目(就在主密钥指纹的下方)。它与你的家目录下 `.gnupg` 目录下的一个文件是一致的:
|
||||
|
||||
```
|
||||
$ cd ~/.gnupg/private-keys-v1.d
|
||||
$ ls
|
||||
AAAA999988887777666655554444333322221111.key
|
||||
BBBB999988887777666655554444333322221111.key
|
||||
CCCC999988887777666655554444333322221111.key
|
||||
```
|
||||
|
||||
现在你做的全部操作就是简单地删除与主密钥 keygrip 一致的 `.key` 文件:
|
||||
|
||||
```
|
||||
$ cd ~/.gnupg/private-keys-v1.d
|
||||
$ rm AAAA999988887777666655554444333322221111.key
|
||||
```
|
||||
|
||||
现在,如果运行 `--list-secret-keys` 命令将出现问题,它将显示主密钥丢失(`#` 表示不可用):
|
||||
|
||||
```
|
||||
$ gpg --list-secret-keys
|
||||
sec# rsa4096 2017-12-06 [C] [expires: 2019-12-06]
|
||||
111122223333444455556666AAAABBBBCCCCDDDD
|
||||
uid [ultimate] Alice Engineer <alice@example.org>
|
||||
uid [ultimate] Alice Engineer <allie@example.net>
|
||||
ssb rsa2048 2017-12-06 [E]
|
||||
ssb rsa2048 2017-12-06 [S]
|
||||
```
|
||||
|
||||
#### 删除吊销证书
|
||||
|
||||
你应该去删除的另一个文件是吊销证书(**删除之前,确保你的备份中有它**),它是使用你的主密钥自动创建的。吊销证书允许一些人去永久标记你的证书为吊销状态,这意味着它无论在任何用途中将不再被使用或信任。一般是使用它来吊销由于某些原因不再受控的一个密钥 —— 比如,你丢失了密钥密码。
|
||||
|
||||
与使用主密钥一样,如果一个吊销证书泄露到恶意者手中,他们能够使用它去破坏你的开发者数字身份,因此,最好是从你的家目录中删除它。
|
||||
|
||||
```
|
||||
cd ~/.gnupg/openpgp-revocs.d
|
||||
rm [fpr].rev
|
||||
```
|
||||
|
||||
在下一篇文章中,你将学习如何保护你的子密钥。敬请期待。
|
||||
|
||||
从来自 Linux 基金会和 edX 的免费课程 [“Linux 入门”][4] 中学习更多 Linux 知识。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linux.com/blog/learn/pgp/2018/3/protecting-code-integrity-pgp-part-4-moving-your-master-key-offline-storage
|
||||
|
||||
作者:[Konstantin Ryabitsev][a]
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.linux.com/users/mricon
|
||||
[1]:https://linux.cn/article-9524-1.html
|
||||
[2]:https://linux.cn/article-9529-1.html
|
||||
[3]:https://linux.cn/article-9607-1.html
|
||||
[4]:https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux
|
@ -0,0 +1,285 @@
|
||||
用 PGP 保护代码完整性(五):将子密钥移到一个硬件设备中
|
||||
======
|
||||
|
||||
> 在这个系列教材中,将为你提供使用 PGP 和保护你的私钥的最佳体验。
|
||||
|
||||

|
||||
|
||||
在本系列教程中,我们将提供一个使用 PGP 的实用指南。如果你没有看过前面的文章,你可以通过下面的链接去查看。在这篇文章中,我们将继续讨论如何保护你的密钥,谈一谈将你的子密钥移到一个专门的硬件设备中的一些技巧。
|
||||
|
||||
- [第一部分:基本概念和工具][1]
|
||||
- [第二部分:生成你的主密钥][2]
|
||||
- [第三部分:生成 PGP 子密钥][3]
|
||||
- [第四部分:将主密钥移到离线存储中][4]
|
||||
|
||||
#### 清单
|
||||
|
||||
* 取得一个 GnuPG 兼容的硬件设备(必要)
|
||||
* 配置 GnuPG 在设备上工作(必要)
|
||||
* 设置用户和管理员的 PIN(必要)
|
||||
* 移动子密钥到设备中(必要)
|
||||
|
||||
#### 考虑事项
|
||||
|
||||
虽然现在主密钥已经不用担心泄露或失窃了,但子密钥仍然在你的家目录中。任何得到它的人都能够解密你的通讯或假冒你的签名(如果他们知道密钥的密码)。并且,每次执行一个 GnuPG 操作都要将密钥加载到操作系统内存中,这将使一些更高级的恶意软件有机会得到你的密钥(想想 Meltdown 和 Spectre)。
|
||||
|
||||
完全保护密钥的最好方式就是,将它移到一个专门的硬件设备中,这种硬件设备是一个可操作的智能卡。
|
||||
|
||||
##### 智能卡的好处
|
||||
|
||||
一个智能卡包含一个加密芯片,它能够存储私钥,并且直接在智能卡内部执行秘密操作。因为密钥内容从来没有离开过智能卡,计算机操作系统并不能检索你插入的智能卡上的私钥。这与前面用于备份目的的加密 USB 存储是不同的 —— 虽然 USB 设备也是插入并解密的,但操作系统是能够去访问私钥内容的。使用外置的加密 USB 介质并不能代替智能卡设备的功能。
|
||||
|
||||
智能卡的一些其它好处:
|
||||
|
||||
* 它们很便宜且易于获得
|
||||
* 它们小巧且易于携带
|
||||
* 它们可以用于多种设备上
|
||||
* 它们中的很多都具有防篡改功能(取决于制造商)
|
||||
|
||||
#### 可用的智能卡设备
|
||||
|
||||
智能卡最初是嵌入到真实钱包大小的卡中,故而得名智能卡。你肯定可以买到并使用 GnuPG 功能的智能卡,并且它们是你能得到的最便宜的可用设备之一。但是,事实上智能卡有一个很重要的缺点:它们需要一个智能卡读卡器,只有极小数的笔记本电脑上有这种读卡器。
|
||||
|
||||
由于这个原因,制造商开始推出小型 USB 设备,它的大小和 U 盘类似,内置有微型智能卡,并且在芯片上简单地实现了智能卡协议特性。下面推荐几个这样的设备:
|
||||
|
||||
* [Nitrokey Start][5]:开源硬件和自由软件,可用于 GnuPG 的最便宜的选择之一,但是额外的安全特性很少。
|
||||
* [Nitrokey Pro][6]:类似于 Nitrokey Start,它提供防篡改及更多的安全特性(但没有 U2F,具体查看指南的 U2F 节)。
|
||||
* [Yubikey 4][7]:专利硬件和软件,但比 Nitrokey Pro 便宜,并且可以用在最新的笔记本电脑上的 USB-C 接口;也提供像 U2F 这样的额外的安全特性。
|
||||
|
||||
我们推荐选一个同时具备智能卡功能和 U2F 的设备,在写这篇文章时,只能选择 Yubikey 4。
|
||||
|
||||
#### 配置智能卡设备
|
||||
|
||||
你的智能卡设备插入任何一台现代的 Linux 或 Mac 工作站上都应该能正常工作。你可以通过运行如下的命令去验证它:
|
||||
|
||||
```
|
||||
$ gpg --card-status
|
||||
```
|
||||
|
||||
如果你没有收到错误,有一个完整的卡列表,就表示一切正常。不幸的是,排除为什么设备不能正常工作的所有可能原因,已经超出了本指南的范围。如果你的智能卡使用 GnuPG 时有问题,请通过你的操作系统的常见支持通道寻求支持。
|
||||
|
||||
##### PIN 不一定是数字
|
||||
|
||||
注意,尽管名为 “PIN”(暗示你它必须是一个“数字”),不论是用户 PIN 还是管理员 PIN 都不必非要是数字。
|
||||
|
||||
当你收到一个新设备时,它可能设置有一个默认的用户和管理员 PIN,对于 Yubikey,它分别是 `123456` 和 `12345678`。如果它们的 PIN 不是默认的,请查看设备附带的说明书。
|
||||
|
||||
##### 快速设置
|
||||
|
||||
为配置你的智能卡,你需要使用 GnuPG 菜单系统,因此这里并没有更方便的命令行开关:
|
||||
|
||||
```
|
||||
$ gpg --card-edit
|
||||
[...omitted...]
|
||||
gpg/card> admin
|
||||
Admin commands are allowed
|
||||
gpg/card> passwd
|
||||
```
|
||||
|
||||
你应该去设置用户 PIN (1)、管理员 PIN (3)、和重置码 (4)。请确保把它们记录并保存到一个安全的地方 —— 尤其是管理员 PIN 和重置码(它允许你去擦除整个智能卡内容)。你很少使用到管理员 PIN,因此如果你不记录下来,很可能会忘掉它。
|
||||
|
||||
返回到智能卡主菜单,你也可以设置其它值(比如名字、性别、登入日期、等等),但是这些都不是必需的,一旦你的智能卡丢失了,将导致额外的信息泄露。
|
||||
|
||||
#### 将子密钥移到你的智能卡中
|
||||
|
||||
退出卡菜单(使用 `q` 命令)保存所有更改。接下来,我们将你的子密钥移到智能卡中。将需要用到你的 PGP 密钥的密码,在大多数的智能卡操作中都将用到管理员 PIN。记住,那个 `[fpr]` 表示你的密钥的完整的 40 个字符的指纹。
|
||||
|
||||
```
|
||||
$ gpg --edit-key [fpr]
|
||||
|
||||
Secret subkeys are available.
|
||||
|
||||
pub rsa4096/AAAABBBBCCCCDDDD
|
||||
created: 2017-12-07 expires: 2019-12-07 usage: C
|
||||
trust: ultimate validity: ultimate
|
||||
ssb rsa2048/1111222233334444
|
||||
created: 2017-12-07 expires: never usage: E
|
||||
ssb rsa2048/5555666677778888
|
||||
created: 2017-12-07 expires: never usage: S
|
||||
[ultimate] (1). Alice Engineer <alice@example.org>
|
||||
[ultimate] (2) Alice Engineer <allie@example.net>
|
||||
|
||||
gpg>
|
||||
```
|
||||
|
||||
使用 `--edit-key` 再次进入到菜单模式,你将注意到那个密钥清单有一点小差别。从现在开始,所有的命令都是在这个菜单模式下运行,它用 `gpg>` 提示符来表示。
|
||||
|
||||
首先,我们来选择移到智能卡中的密钥 —— 你可以通过键入 `key 1`(它表示选择清单中的第一个密钥)来实现:
|
||||
|
||||
```
|
||||
gpg> key 1
|
||||
```
|
||||
|
||||
这个输出会有一点细微的差别:
|
||||
|
||||
```
|
||||
pub rsa4096/AAAABBBBCCCCDDDD
|
||||
created: 2017-12-07 expires: 2019-12-07 usage: C
|
||||
trust: ultimate validity: ultimate
|
||||
ssb* rsa2048/1111222233334444
|
||||
created: 2017-12-07 expires: never usage: E
|
||||
ssb rsa2048/5555666677778888
|
||||
created: 2017-12-07 expires: never usage: S
|
||||
[ultimate] (1). Alice Engineer <alice@example.org>
|
||||
[ultimate] (2) Alice Engineer <allie@example.net>
|
||||
```
|
||||
|
||||
注意与密钥对应的 `ssb` 行旁边的 `*` —— 它表示这是当前选定的密钥。它是可切换的,意味着如果你再次输入 `key 1`,这个 `*` 将消失,这个密钥将不再被选中。
|
||||
|
||||
现在,我们来将密钥移到智能卡中:
|
||||
|
||||
```
|
||||
gpg> keytocard
|
||||
Please select where to store the key:
|
||||
(2) Encryption key
|
||||
Your selection? 2
|
||||
```
|
||||
|
||||
由于它是我们的 [E] 密钥,把它移到加密区中是有很有意义的。当你提交了你的选择之后,将会被提示输入你的 PGP 密钥的保护密码,接下来输入智能卡的管理员 PIN。如果命令没有返回错误,表示你的密钥已经被移到智能卡中了。
|
||||
|
||||
**重要:** 现在再次输入 `key 1` 去取消选中第一个密钥,并输入 `key 2` 去选择 [S] 密钥:
|
||||
|
||||
```
|
||||
gpg> key 1
|
||||
gpg> key 2
|
||||
gpg> keytocard
|
||||
Please select where to store the key:
|
||||
(1) Signature key
|
||||
(3) Authentication key
|
||||
Your selection? 1
|
||||
```
|
||||
|
||||
你可以使用 [S] 密钥同时做签名和验证,但是我们希望确保它在签名区,因此,我们选择 (`1`)。完成后,如果你的命令没有返回错误,表示操作已成功。
|
||||
|
||||
最后,如果你创建了一个 [A] 密钥,你也可以将它移到智能卡中,但是你需要先取消选中 `key 2`。完成后,选择 `q`:
|
||||
|
||||
```
|
||||
gpg> q
|
||||
Save changes? (y/N) y
|
||||
```
|
||||
|
||||
保存变更将把你的子密钥移到智能卡后,把你的家目录中的相应子密钥删除(没有关系,因为我们的备份中还有,如果更换了智能卡,你需要再做一遍)。
|
||||
|
||||
##### 验证移动后的密钥
|
||||
|
||||
现在,如果你执行一个` --list-secret-keys` 操作,你将看到一个稍有不同的输出:
|
||||
|
||||
```
|
||||
$ gpg --list-secret-keys
|
||||
sec# rsa4096 2017-12-06 [C] [expires: 2019-12-06]
|
||||
111122223333444455556666AAAABBBBCCCCDDDD
|
||||
uid [ultimate] Alice Engineer <alice@example.org>
|
||||
uid [ultimate] Alice Engineer <allie@example.net>
|
||||
ssb> rsa2048 2017-12-06 [E]
|
||||
ssb> rsa2048 2017-12-06 [S]
|
||||
```
|
||||
|
||||
在 `ssb>` 的输出中的 `>` 表示子密钥仅在智能卡上有效。如果你进入到你的密钥目录中,查看目录的内容,你将会看到那个 `.key` 文件已经被存根替换:
|
||||
|
||||
```
|
||||
$ cd ~/.gnupg/private-keys-v1.d
|
||||
$ strings *.key
|
||||
```
|
||||
|
||||
这个输出将包含一个影子私钥,它表示那个文件仅是个存根,真正的内容在智能卡中。
|
||||
|
||||
#### 验证智能卡的功能
|
||||
|
||||
验证智能卡能否如期正常运行,你可以通过创建一个签名来验证:
|
||||
|
||||
```
|
||||
$ echo "Hello world" | gpg --clearsign > /tmp/test.asc
|
||||
$ gpg --verify /tmp/test.asc
|
||||
```
|
||||
|
||||
首次运行这个命令时将询问你智能卡的 PIN,在你运行 `gpg —verify` 之后,它将显示 “Good signature”。
|
||||
|
||||
祝贺你,你已经成功将窃取你的开发者数字身份变得更加困难了!
|
||||
|
||||
#### 其它常见 GnuPG 操作
|
||||
|
||||
下面是使用你的 PGP 密钥需要做的一些常见操作的快速指南。
|
||||
|
||||
在下面的所有命令中,`[fpr]` 表示你的密钥指纹。
|
||||
|
||||
##### 挂载主密钥离线存储
|
||||
|
||||
下面的一些操作将需要你的主密钥,因此首先需要去挂载你的主密钥离线存储,并告诉 GnuPG 去使用它。首先,找出介质挂载路径,可以通过查看 `mount` 命令的输出找到它。接着,设置你的 GnuPG 目录为你的介质上备份的目录,并告诉 GnuPG 将那个目录做为它的家目录:
|
||||
|
||||
```
|
||||
$ export GNUPGHOME=/media/disk/name/gnupg-backup
|
||||
$ gpg --list-secret-keys
|
||||
```
|
||||
|
||||
确保你在输出中看到的是 `sec` 而不是 `sec#`(这个 `#` 表示密钥不可用,仍然使用的是惯常的那个 Home 目录)。
|
||||
|
||||
##### 更新你惯常使用的那个 GnuPG 工作目录
|
||||
|
||||
在你的离线存储上做了任何更改之后,你应该将这些更改同步应用到你惯常使用的工作目录中:
|
||||
|
||||
```
|
||||
$ gpg --export | gpg --homedir ~/.gnupg --import
|
||||
$ unset GNUPGHOME
|
||||
```
|
||||
|
||||
##### 延长密钥过期日期
|
||||
|
||||
我们创建的主密钥的默认过期日期是自创建之日起两年后。这样做都是为安全考虑,这样将使淘汰密钥最终从密钥服务器上消失。
|
||||
|
||||
延长你的密钥过期日期,从当前日期延长一年,只需要运行如下命令:
|
||||
|
||||
```
|
||||
$ gpg --quick-set-expire [fpr] 1y
|
||||
```
|
||||
|
||||
如果为了好记住,你也可以使用一个特定日期(比如,你的生日、1 月 1 日、或加拿大国庆日):
|
||||
|
||||
```
|
||||
$ gpg --quick-set-expire [fpr] 2020-07-01
|
||||
```
|
||||
|
||||
记得将更新后的密钥发送到密钥服务器:
|
||||
|
||||
```
|
||||
$ gpg --send-key [fpr]
|
||||
```
|
||||
|
||||
##### 吊销身份
|
||||
|
||||
如果你需要吊销一个身份(比如,你换了雇主并且旧的邮件地址不再有效了),你可以使用一行命令搞定:
|
||||
|
||||
```
|
||||
$ gpg --quick-revoke-uid [fpr] 'Alice Engineer <aengineer@example.net>'
|
||||
```
|
||||
|
||||
你也可以通过使用 `gpg --edit-key [fpr]` 在菜单模式下完成同样的事情。
|
||||
|
||||
完成后,记得将更新后的密钥发送到密钥服务器上:
|
||||
|
||||
```
|
||||
$ gpg --send-key [fpr]
|
||||
```
|
||||
|
||||
下一篇文章中,我们将谈谈 Git 如何支持 PGP 的多级别集成。
|
||||
|
||||
通过来自 Linux 基金会和 edX 的免费课程 [“Linux 入门”][8]学习更多 Linux 知识。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linux.com/blog/learn/pgp/2018/3/protecting-code-integrity-pgp-part-5-moving-subkeys-hardware-device
|
||||
|
||||
作者:[KONSTANTIN RYABITSEV][a]
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.linux.com/users/mricon
|
||||
[1]:https://linux.cn/article-9524-1.html
|
||||
[2]:https://linux.cn/article-9529-1.html
|
||||
[3]:https://linux.cn/article-9607-1.html
|
||||
[4]:https://linux.cn/article-10402-1.html
|
||||
[5]:https://shop.nitrokey.com/shop/product/nitrokey-start-6
|
||||
[6]:https://shop.nitrokey.com/shop/product/nitrokey-pro-3
|
||||
[7]:https://www.yubico.com/product/yubikey-4-series/
|
||||
[8]:https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux
|
@ -0,0 +1,62 @@
|
||||
关于团队敏捷开发实践的 6 个常见问题
|
||||
======
|
||||
|
||||
> 专家回答了敏捷实践如何帮助团队更有效的 6 个常见问题。
|
||||
|
||||

|
||||
|
||||
”有问题么?“
|
||||
|
||||
你可能听过演讲者在演讲结束的时候提出这个问题。这是演讲中最重要的部分 —— 毕竟,你不仅仅是听讲座, 而是参加讨论和社群交流。
|
||||
|
||||
最近,我有机会听到我的同伴 Red Hatters 给当地一所大学的一群技术型学生做一个名为 “[敏捷实践][1]” 的讲座。讲座中有软件工程师 Tomas Tomecek 和敏捷开发的从业者 Fernando Colleone 、Pavel Najman 合作解释了敏捷开发方法的基础,并展示最佳实践在日常活动中的应用。
|
||||
|
||||
知道了学生们参加这个课程是为了了解什么是敏捷实践以及如何将其应用于项目,我想知道学生们的问题会与我作为敏捷从业者在 Red Hat 每天听到的问题相比有什么不同。结果学生的疑问和我的同事们如出一辙。这些问题都直指敏捷实践的核心。
|
||||
|
||||
### 1、完美的团队规模是多大?
|
||||
|
||||
学生们想知道一个小团队和一个大团队的规模是多少。这个问题与任何曾经合作过做项目的人都是相关的。根据 Tomas 作为技术领导的经验,12 个人从事的项目被认为是一个大型团队。现实中,团队规模通常与生产力没有直接关系。在有些时候,在一个地方或同一个时区的小团队也许会比一个成员分布在满世界的大团队更具有生产力。最终,该讲座建议理想的团队大小大概是 5 个人(正如 scrum 开发方法的 7,+-2)。
|
||||
|
||||
### 2、团队会面临哪些实际挑战?
|
||||
|
||||
演讲者比较了由本地团队组成的项目(团队成员都是一个办公室的,或者相邻近的人)与分散型的团队(位于不同时区)。当项目需要团队成员之间密切合作时,工程师更喜欢本地的团队,因为时间差异造成的延迟可能会破坏软件开发的“流”。同时,分散型团队可以将可能不适用与当地项目但适用于某些开发用例的技能集合在一起。此外,还有各种最佳方法可用于改进分散型团队中的合作方式。
|
||||
|
||||
### 3、整理堆积的工作需要多少时间?
|
||||
|
||||
因为这是一个对于新学习敏捷的学生的介绍性质的演讲,演讲者着重把 [Scrum][2] 和 [Kanban][3] 作为介绍敏捷开发的方法。他们使用 Scrum 框架来作为说明软件编写的方法,并且用 Kanban 作为工作规划和沟通的系统。关于需要多少时间来整理项目堆积的工作,演讲者解释说并没有固定的准则,相对的,实践出真知:在开发的早期阶段,当一个崭新的项目 —— 特别如果团队里有新人 —— 每周可能会花费数个小时在整理工作上。随着时间推移和不断地练习,会越来越高效。
|
||||
|
||||
### 4、产品负责人是否是必要的? 他们扮演什么样的角色?
|
||||
|
||||
产品负责人会帮助团队更方便的拓展,然而,职位名称并不重要,重要的是你的团队中有人能够传递用户的意愿。在许多团队中,特别是在大型团队中从事单个任务的团队,首席工程师就可以担任产品负责人。
|
||||
|
||||
### 5、建议使用哪些敏捷开发的工具?使用 Scrum 或 Kanban 做敏捷开发的时候必须用特定的软件么?
|
||||
|
||||
尽管使用一些专业软件例如 Jira 或 Trello 会很有帮助,特别是在与大量从事大型企业项目的工作者合作时,但它们不是必需的。Scrum 和 Kanban 可以使用像纸卡这样简单的工具完成。关键是在团队中要有一个清晰的信息来源和紧密的交流。推荐两个优秀的 kanban 开源工具 [Taiga][4] 和 [Wekan][5]。更多信息请查看 [Trello 的 5 个开源替代品][6] 和 [敏捷团队的最好的 7 个开源项目管理工具][7] 。
|
||||
|
||||
### 6、学生如何在学校项目中使用敏捷开发技术?
|
||||
|
||||
演讲者鼓励学生使用 kanban 在项目结束前使用可视化和概述要完成的任务。关键是要创建一个公共板块,这样整个团队就可以看到项目的状态。通过使用 kanban 或者类似的高度可视化的策略,学生不会在项目后期才发现个别成员没有跟上进度。
|
||||
|
||||
Scrum 实践比如 sprints 和 daily standups 也是确认每个人都在进步以及项目的各个部分最终会一起发挥作用的绝佳方法。定期检查和信息共享也至关重要。更多关于 Scrum 的信息,访问 [什么是 scrum?][8] 。
|
||||
|
||||
牢记 Kanban 和 Scrum 只是敏捷开发中众多框架和工具中的两个而已。它们可能不是应对每一种情况的最佳方法。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/3/agile-mindset
|
||||
|
||||
作者:[Dominika Bula][a]
|
||||
译者:[lixinyuxx](https://github.com/lixinxyuxx)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/dominika
|
||||
[1]:http://zijemeit.cz/sessions/agile-in-practice/
|
||||
[2]:https://www.scrum.org/resources/what-is-scrum
|
||||
[3]:https://en.wikipedia.org/wiki/Kanban
|
||||
[4]:https://taiga.io/
|
||||
[5]:https://wekan.github.io/
|
||||
[6]:https://opensource.com/alternatives/trello
|
||||
[7]:https://opensource.com/article/18/2/agile-project-management-tools
|
||||
[8]:https://opensource.com/resources/scrum
|
@ -0,0 +1,283 @@
|
||||
用 PGP 保护代码完整性(六):在 Git 上使用 PGP
|
||||
======
|
||||
|
||||
> 我们继续我们的 PGP 实践系列,来看看签名标签的标签和提交,这可以帮你确保你的仓库没有被篡改。
|
||||
|
||||

|
||||
|
||||
在本系列教程中,我们提供了一个使用 PGP 的实用指南,包括基本概念和工具、生成和保护你的密钥。如果你错过了前面的文章,你可以查看下面的链接。在这篇文章中,我们谈一谈在 Git 中如何集成 PGP、使用签名的标签,然后介绍签名提交,最后添加签名推送的支持。
|
||||
|
||||
- [第一部分:基本概念和工具][1]
|
||||
- [第二部分:生成你的主密钥][2]
|
||||
- [第三部分:生成 PGP 子密钥][3]
|
||||
- [第四部分:将主密钥移到离线存储中][4]
|
||||
- [第五部分:将子密钥移到硬件设备中][5]
|
||||
|
||||
Git 的核心特性之一就是它的去中心化本质 —— 一旦仓库克隆到你的本地系统,你就拥有了项目的完整历史,包括所有的标签、提交和分支。然而由于存在着成百上千的克隆仓库,如何才能验证你下载的仓库没有被恶意的第三方做过篡改?你可以从 GitHub 或一些貌似官方的位置来克隆它们,但是如果有些人故意欺骗了你怎么办?
|
||||
|
||||
或者在你参与的一些项目上发现了后门,而 “Author” 行显示是你干的,然而你很确定 [不是你干的][6],会发生什么情况?
|
||||
|
||||
为解决上述问题,Git 添加了 PGP 集成。签名的标签通过确认它的内容与创建这个标签的开发者的工作站上的内容完全一致来证明仓库的完整性,而签名的提交几乎是不可能在不访问你的 PGP 密钥的情况下能够假冒你。
|
||||
|
||||
#### 清单
|
||||
|
||||
* 了解签名的标签、提交和推送(必要)
|
||||
* 配置 git 使用你的密钥(必要)
|
||||
* 学习标签如何签名和验证(必要)
|
||||
* 配置 git 总是签名带注释标签(推荐)
|
||||
* 学习提交如何签名和验证工作(必要)
|
||||
* 配置 git 总是签名提交(推荐)
|
||||
* 配置 gpg-agent 选项(必要)
|
||||
|
||||
#### 考虑事项
|
||||
|
||||
git 实现了 PGP 的多级集成,首先从签名标签开始,接着介绍签名提交,最后添加签名推送的支持。
|
||||
|
||||
##### 了解 Git 哈希
|
||||
|
||||
git 是一个复杂的东西,为了你能够更好地掌握它如何集成 PGP,你需要了解什么是”哈希“。我们将它归纳为两种类型的哈希:树哈希和提交哈希。
|
||||
|
||||
###### 树哈希
|
||||
|
||||
每次你向仓库提交一个变更,对于仓库中的每个子目录,git 都会记录它里面所有对象的校验和哈希 —— 内容(blobs)、目录(trees)、文件名和许可等等。它只对每次提交中发生变更的树和内容做此操作,这样在只变更树的一小部分时就不必去重新计算整个树的校验和。
|
||||
|
||||
然后再计算和存储处于顶级的树的校验和,这样如果仓库的任何一部分发生变化,校验和将不可避免地发生变化。
|
||||
|
||||
###### 提交哈希
|
||||
|
||||
一旦创建了树哈希,git 将计算提交哈希,它将包含有关仓库和变更的下列信息:
|
||||
|
||||
* 树哈希的校验和
|
||||
* 变更前树哈希的校验和(父级)
|
||||
* 有关作者的信息(名字、email、创作时间)
|
||||
* 有关提交者的信息(名字、email、提交时间)
|
||||
* 提交信息
|
||||
|
||||
###### 哈希函数
|
||||
|
||||
在写这篇文章时,虽然研究一种更强大的、抗碰撞的算法的工作正在进行,但 git 仍然使用的是 SHA1 哈希机制去计算校验和。注意,git 已经包含了碰撞防范程序,因此认为对 git 成功进行碰撞攻击仍然是不可行的。
|
||||
|
||||
#### 带注释标签和标签签名
|
||||
|
||||
在每个 Git 仓库中,标签允许开发者标记特定的提交。标签可以是 “轻量级的” —— 几乎只是一个特定提交上的指针,或者它们可以是 “带注释的”,它自己将成为 git 树中的项目。一个带注释标签对象包含所有下列的信息:
|
||||
|
||||
* 成为标签的提交的哈希的校验和
|
||||
* 标签名字
|
||||
* 关于打标签的人的信息(名字、email、打标签时间)
|
||||
* 标签信息
|
||||
|
||||
一个 PGP 签名的标签是一个带有将所有这些条目封装进一个 PGP 签名的带注释标签。当开发者签名他们的 git 标签时,他们实际上是向你保证了如下的信息:
|
||||
|
||||
* 他们是谁(以及他们为什么应该被信任)
|
||||
* 他们在签名时的仓库状态是什么样:
|
||||
* 标签包含的提交的哈希
|
||||
* 提交的哈希包含了顶级树的哈希
|
||||
* 顶级树哈希包含了所有文件、内容和子树的哈希
|
||||
* 它也包含有关作者的所有信息
|
||||
* 包含变更发生时的精确时间
|
||||
|
||||
当你克隆一个仓库并验证一个签名的标签时,就是向你以密码方式保证:仓库中的所有内容、包括所有它的历史,与开发者签名时在它的计算机上的仓库完全一致。
|
||||
|
||||
#### 签名的提交
|
||||
|
||||
签名的提交与签名的标签非常类似 —— PGP 签名的是提交对象的内容,而不是标签对象的内容。一个提交签名也给你提供了开发者签名时开发者树上的全部可验证信息。标签签名和提交的 PGP 签名提供了有关仓库和它的完整历史的完全一致的安全保证。
|
||||
|
||||
#### 签名的推送
|
||||
|
||||
为了完整起见,在这里包含了签名的推送这一功能,因为在你使用这个功能之前,需要在接收推送的服务器上先启用它。正如我们在上面所说过的,PGP 签名一个 git 对象就是提供了开发者的 git 树当时的可验证信息,但不提供开发者对那个树意图相关的信息。
|
||||
|
||||
比如,你可以在你自己复刻的 git 仓库的一个实验分支上尝试一个很酷的特性,为了评估它,你提交了你的工作,但是有人在你的代码中发现了一个恶意的 bug。由于你的提交是经过正确签名的,因此有人可能将包含有恶意 bug 的分支推入到 master 分支中,从而在生产系统中引入一个漏洞。由于提交是经过你的密钥正确签名的,所以一切看起来都是合理合法的,而当 bug 被发现时,你的声誉就会因此而受到影响。
|
||||
|
||||
在 `git push` 时,为了验证提交的意图而不仅仅是验证它的内容,添加了要求 PGP 推送签名的功能。
|
||||
|
||||
#### 配置 git 使用你的 PGP 密钥
|
||||
|
||||
如果在你的钥匙环上只有一个密钥,那么你就不需要再做额外的事了,因为它是你的默认密钥。
|
||||
|
||||
然而,如果你有多个密钥,那么你必须要告诉 git 去使用哪一个密钥。(`[fpr]` 是你的密钥的指纹):
|
||||
|
||||
```
|
||||
$ git config --global user.signingKey [fpr]
|
||||
```
|
||||
|
||||
注意:如果你有一个不同的 `gpg2` 命令,那么你应该告诉 git 总是去使用它,而不是传统的版本 1 的 `gpg`:
|
||||
|
||||
```
|
||||
$ git config --global gpg.program gpg2
|
||||
```
|
||||
|
||||
#### 如何使用签名标签
|
||||
|
||||
创建一个签名的标签,只要传递一个简单地 `-s` 开关给 `tag` 命令即可:
|
||||
|
||||
```
|
||||
$ git tag -s [tagname]
|
||||
```
|
||||
|
||||
我们建议始终对 git 标签签名,这样让其它的开发者确信他们使用的 git 仓库没有被恶意地修改过(比如,引入后门):
|
||||
|
||||
##### 如何验证签名的标签
|
||||
|
||||
验证一个签名的标签,只需要简单地使用 `verify-tag` 命令即可:
|
||||
|
||||
```
|
||||
$ git verify-tag [tagname]
|
||||
```
|
||||
|
||||
如果你要验证其他人的 git 标签,那么就需要你导入他的 PGP 公钥。请参考 “可信任的团队沟通” 一文中关于此主题的指导。
|
||||
|
||||
##### 在拉取时验证
|
||||
|
||||
如果你从项目仓库的其它复刻中拉取一个标签,git 将自动验证签名,并在合并操作时显示结果:
|
||||
|
||||
```
|
||||
$ git pull [url] tags/sometag
|
||||
```
|
||||
|
||||
合并信息将包含类似下面的内容:
|
||||
|
||||
```
|
||||
Merge tag 'sometag' of [url]
|
||||
|
||||
[Tag message]
|
||||
|
||||
# gpg: Signature made [...]
|
||||
# gpg: Good signature from [...]
|
||||
```
|
||||
|
||||
#### 配置 git 始终签名带注释标签
|
||||
|
||||
很可能的是,你正在创建一个带注释标签,你应该去签名它。强制 git 始终签名带注释的标签,你可以设置一个全局配置选项:
|
||||
|
||||
```
|
||||
$ git config --global tag.forceSignAnnotated true
|
||||
```
|
||||
|
||||
或者,你始终记得每次都传递一个 `-s` 开关:
|
||||
|
||||
```
|
||||
$ git tag -asm "Tag message" tagname
|
||||
```
|
||||
|
||||
#### 如何使用签名的提交
|
||||
|
||||
创建一个签名的提交很容易,但是将它纳入到你的工作流中却很困难。许多项目使用签名的提交作为一种 “Committed-by:” 的等价行,它记录了代码来源 —— 除了跟踪项目历史外,签名很少有人去验证。在某种意义上,签名的提交用于 “篡改证据”,而不是 git 工作流的 “篡改证明”。
|
||||
|
||||
为创建一个签名的提交,你只需要 `git commit` 命令传递一个 `-S` 标志即可(由于它与另一个标志冲突,所以改为大写的 `-S`):
|
||||
|
||||
```
|
||||
$ git commit -S
|
||||
```
|
||||
|
||||
我们建议始终使用签名提交,并要求项目所有成员都这样做,这样其它人就可以验证它们(下面就讲到如何验证)。
|
||||
|
||||
##### 如何去验证签名的提交
|
||||
|
||||
验证签名的提交需要使用 `verify-commit` 命令:
|
||||
|
||||
```
|
||||
$ git verify-commit [hash]
|
||||
```
|
||||
|
||||
你也可以查看仓库日志,要求所有提交签名是被验证和显示的:
|
||||
|
||||
```
|
||||
$ git log --pretty=short --show-signature
|
||||
```
|
||||
|
||||
##### 在 git 合并时验证提交
|
||||
|
||||
如果项目的所有成员都签名了他们的提交,你可以在合并时强制进行签名检查(然后使用 `-S` 标志对合并操作本身进行签名):
|
||||
|
||||
```
|
||||
$ git merge --verify-signatures -S merged-branch
|
||||
```
|
||||
|
||||
注意,如果有一个提交没有签名或验证失败,将导致合并操作失败。通常情况下,技术是最容易的部分 —— 而人的因素使得项目中很难采用严格的提交验证。
|
||||
|
||||
##### 如果你的项目在补丁管理上采用邮件列表
|
||||
|
||||
如果你的项目在提交和处理补丁时使用一个邮件列表,那么一般很少使用签名提交,因为通过那种方式发送时,签名信息将会丢失。对提交进行签名仍然是非常有用的,这样其他人就能引用你托管在公开 git 树作为参考,但是上游项目接收你的补丁时,仍然不能直接使用 git 去验证它们。
|
||||
|
||||
尽管,你仍然可以签名包含补丁的电子邮件。
|
||||
|
||||
#### 配置 git 始终签名提交
|
||||
|
||||
你可以告诉 git 总是签名提交:
|
||||
|
||||
```
|
||||
git config --global commit.gpgSign true
|
||||
```
|
||||
|
||||
或者你每次都记得给 `git commit` 操作传递一个 `-S` 标志(包括 `—amend`)。
|
||||
|
||||
#### 配置 gpg-agent 选项
|
||||
|
||||
GnuPG agent 是一个守护工具,它能在你使用 gpg 命令时随时自动启动,并运行在后台来缓存私钥的密码。这种方式让你只需要解锁一次密钥就可以重复地使用它(如果你需要在一个自动脚本中签署一组 git 操作,而不想重复输入密钥,这种方式就很方便)。
|
||||
|
||||
为了调整缓存中的密钥过期时间,你应该知道这两个选项:
|
||||
|
||||
* `default-cache-ttl`(秒):如果在 TTL 过期之前再次使用同一个密钥,这个倒计时将重置成另一个倒计时周期。缺省值是 600(10 分钟)。
|
||||
* `max-cache-ttl`(秒):自首次密钥输入以后,不论最近一次使用密钥是什么时间,只要最大值的 TTL 倒计时过期,你将被要求再次输入密码。它的缺省值是 30 分钟。
|
||||
|
||||
如果你认为这些缺省值过短(或过长),你可以编辑 `~/.gnupg/gpg-agent.conf` 文件去设置你自己的值:
|
||||
|
||||
```
|
||||
# set to 30 minutes for regular ttl, and 2 hours for max ttl
|
||||
default-cache-ttl 1800
|
||||
max-cache-ttl 7200
|
||||
```
|
||||
|
||||
##### 补充:与 ssh 一起使用 gpg-agent
|
||||
|
||||
如果你创建了一个 [A](验证)密钥,并将它移到了智能卡,你可以将它用到 ssh 上,为你的 ssh 会话添加一个双因子验证。为了与 agent 沟通你只需要告诉你的环境去使用正确的套接字文件即可。
|
||||
|
||||
首先,添加下列行到你的 `~/.gnupg/gpg-agent.conf` 文件中:
|
||||
|
||||
```
|
||||
enable-ssh-support
|
||||
```
|
||||
|
||||
接着,添加下列行到你的 `.bashrc` 文件中:
|
||||
|
||||
```
|
||||
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
|
||||
```
|
||||
|
||||
为了让改变生效,你需要杀掉正在运行的 gpg-agent 进程,并重新启动一个新的登入会话:
|
||||
|
||||
```
|
||||
$ killall gpg-agent
|
||||
$ bash
|
||||
$ ssh-add -L
|
||||
```
|
||||
|
||||
最后的命令将列出代表你的 PGP Auth 密钥的 SSH(注释应该会在结束的位置显示: cardno:XXXXXXXX,表示它来自智能卡)。
|
||||
|
||||
为了启用 ssh 的基于密钥的登入,只需要在你要登入的远程系统上添加 `ssh-add -L` 的输出到 `~/.ssh/authorized_keys` 中。祝贺你,这将使你的 SSH 登入凭据更难以窃取。
|
||||
|
||||
此外,你可以从公共密钥服务器上下载其它人的基于 PGP 的 ssh 公钥,这样就可以赋予他登入 ssh 的权利:
|
||||
|
||||
```
|
||||
$ gpg --export-ssh-key [keyid]
|
||||
```
|
||||
|
||||
如果你有让开发人员通过 ssh 来访问 git 仓库的需要,这将让你非常方便。下一篇文章,我们将提供像保护你的密钥那样保护电子邮件帐户的小技巧。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linux.com/blog/learn/pgp/2018/3/protecting-code-integrity-pgp-part-6-using-pgp-git
|
||||
|
||||
作者:[KONSTANTIN RYABITSEV][a]
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.linux.com/users/mricon
|
||||
[1]:https://linux.cn/article-9524-1.html
|
||||
[2]:https://linux.cn/article-9529-1.html
|
||||
[3]:https://linux.cn/article-9607-1.html
|
||||
[4]:https://linux.cn/article-10402-1.html
|
||||
[5]:https://linux.cn/article-10415-1.html
|
||||
[6]:https://github.com/jayphelps/git-blame-someone-else
|
@ -0,0 +1,205 @@
|
||||
使用 Ansible 来管理你的工作站:配置自动化
|
||||
======
|
||||
> 学习如何使 Ansible 自动对一系列台式机和笔记本应用配置。
|
||||
|
||||

|
||||
|
||||
Ansible 是一个令人惊讶的自动化的配置管理工具。其主要应用在服务器和云部署上,但在工作站上的应用(无论是台式机还是笔记本)却鲜少得到关注,这就是本系列所要关注的。
|
||||
|
||||
在这个系列的[第一部分][1],我向你展示了 `ansible-pull` 命令的基本用法,我们创建了一个安装了少量包的剧本。它本身是没有多大的用处的,但是为后续的自动化做了准备。
|
||||
|
||||
在这篇文章中,将会达成闭环,而且在最后部分,我们将会有一个针对工作站自动配置的完整的工作解决方案。现在,我们将要设置 Ansible 的配置,这样未来将要做的改变将会自动的部署应用到我们的工作站上。现阶段,假设你已经完成了[第一部分][1]的工作。如果没有的话,当你完成的时候回到本文。你应该已经有一个包含第一篇文章中代码的 GitHub 库。我们将直接在之前创建的部分之上继续。
|
||||
|
||||
首先,因为我们要做的不仅仅是安装包文件,所以我们要做一些重新的组织工作。现在,我们已经有一个名为 `local.yml` 并包含以下内容的剧本:
|
||||
|
||||
```
|
||||
- hosts: localhost
|
||||
become: true
|
||||
tasks:
|
||||
- name: Install packages
|
||||
apt: name={{item}}
|
||||
with_items:
|
||||
- htop
|
||||
- mc
|
||||
- tmux
|
||||
```
|
||||
|
||||
如果我们仅仅想实现一个任务那么上面的配置就足够了。随着向我们的配置中不断的添加内容,这个文件将会变的相当的庞大和杂乱。最好能够根据不同类型的配置将我们的<ruby>动作<rt>play</rt></ruby>分为独立的文件。为了达到这个要求,创建一个名为<ruby>任务手册<rt>taskbook</rt></ruby>的东西,它和<ruby>剧本<rt>playbook</rt></ruby>很像但内容更加的流线型。让我们在 Git 库中为任务手册创建一个目录。
|
||||
|
||||
```
|
||||
mkdir tasks
|
||||
```
|
||||
|
||||
`local.yml ` 剧本中的代码可以很好地过渡为安装包文件的任务手册。让我们把这个文件移动到刚刚创建好的 `task` 目录中,并重新命名。
|
||||
|
||||
```
|
||||
mv local.yml tasks/packages.yml
|
||||
```
|
||||
|
||||
现在,我们编辑 `packages.yml` 文件将它进行大幅的瘦身,事实上,我们可以精简除了独立任务本身之外的所有内容。让我们把 `packages.yml` 编辑成如下的形式:
|
||||
|
||||
```
|
||||
- name: Install packages
|
||||
apt: name={{item}}
|
||||
with_items:
|
||||
- htop
|
||||
- mc
|
||||
- tmux
|
||||
```
|
||||
|
||||
正如你所看到的,它使用同样的语法,但我们去掉了对这个任务无用没有必要的所有内容。现在我们有了一个专门安装包文件的任务手册。然而我们仍然需要一个名为 `local.yml` 的文件,因为执行 `ansible-pull` 命令时仍然会去找这个文件。所以我们将在我们库的根目录下(不是在 `task` 目录下)创建一个包含这些内容的全新文件:
|
||||
|
||||
```
|
||||
- hosts: localhost
|
||||
become: true
|
||||
pre_tasks:
|
||||
- name: update repositories
|
||||
apt: update_cache=yes
|
||||
changed_when: False
|
||||
|
||||
tasks:
|
||||
- include: tasks/packages.yml
|
||||
```
|
||||
|
||||
这个新的 `local.yml` 扮演的是导入我们的任务手册的索引的角色。我已经在这个文件中添加了一些你在这个系列中还没见到的内容。首先,在这个文件的开头处,我添加了 `pre_tasks`,这个任务的作用是在其他所有任务运行之前先运行某个任务。在这种情况下,我们给 Ansible 的命令是让它去更新我们的发行版的软件库的索引,下面的配置将执行这个任务要求:
|
||||
|
||||
```
|
||||
apt: update_cache=yes
|
||||
```
|
||||
|
||||
通常 `apt` 模块是用来安装包文件的,但我们也能够让它来更新软件库索引。这样做的目的是让我们的每个动作在 Ansible 运行的时候能够以最新的索引工作。这将确保我们在使用一个老旧的索引安装一个包的时候不会出现问题。因为 `apt` 模块仅仅在 Debian、Ubuntu 及它们的衍生发行版下工作。如果你运行的一个不同的发行版,你要使用特定于你的发行版的模块而不是 `apt`。如果你需要使用一个不同的模块请查看 Ansible 的相关文档。
|
||||
|
||||
下面这行也需要进一步解释:
|
||||
|
||||
```
|
||||
changed_when: False
|
||||
```
|
||||
|
||||
在某个任务中的这行阻止了 Ansible 去报告动作改变的结果,即使是它本身在系统中导致的一个改变。在这里,我们不会去在意库索引是否包含新的数据;它几乎总是会的,因为库总是在改变的。我们不会去在意 `apt` 库的改变,因为索引的改变是正常的过程。如果我们删除这行,我们将在过程报告的后面看到所有的变动,即使仅仅库的更新而已。最好忽略这类的改变。
|
||||
|
||||
接下来是常规任务的阶段,我们将创建好的任务手册导入。我们每次添加另一个任务手册的时候,要添加下面这一行:
|
||||
|
||||
```
|
||||
tasks:
|
||||
- include: tasks/packages.yml
|
||||
```
|
||||
|
||||
如果你现在运行 `ansible-pull` 命令,它应该基本上像上一篇文章中做的一样。不同的是我们已经改进了我们的组织方式,并且能够更有效的扩展它。为了节省你到上一篇文章中去寻找,`ansible-pull` 命令的语法参考如下:
|
||||
|
||||
```
|
||||
sudo ansible-pull -U https://github.com/<github_user>/ansible.git
|
||||
```
|
||||
|
||||
如果你还记得话,`ansible-pull` 的命令拉取一个 Git 仓库并且应用它所包含的配置。
|
||||
|
||||
既然我们的基础已经搭建好,我们现在可以扩展我们的 Ansible 并且添加功能。更特别的是,我们将添加配置来自动化的部署对工作站要做的改变。为了支撑这个要求,首先我们要创建一个特殊的账户来应用我们的 Ansible 配置。这个不是必要的,我们仍然能够在我们自己的用户下运行 Ansible 配置。但是使用一个隔离的用户能够将其隔离到不需要我们参与的在后台运行的一个系统进程中,
|
||||
|
||||
我们可以使用常规的方式来创建这个用户,但是既然我们正在使用 Ansible,我们应该尽量避开使用手动的改变。替代的是,我们将会创建一个任务手册来处理用户创建任务。这个任务手册目前将会仅仅创建一个用户,但你可以在这个任务手册中添加额外的动作来创建更多的用户。我将这个用户命名为 `ansible`,你可以按照自己的想法来命名(如果你做了这个改变要确保更新所有出现地方)。让我们来创建一个名为 `user.yml` 的任务手册并且将以下代码写进去:
|
||||
|
||||
```
|
||||
- name: create ansible user
|
||||
user: name=ansible uid=900
|
||||
```
|
||||
|
||||
下一步,我们需要编辑 `local.yml` 文件,将这个新的任务手册添加进去,像如下这样写:
|
||||
|
||||
```
|
||||
- hosts: localhost
|
||||
become: true
|
||||
pre_tasks:
|
||||
- name: update repositories
|
||||
apt: update_cache=yes
|
||||
changed_when: False
|
||||
|
||||
tasks:
|
||||
- include: tasks/users.yml
|
||||
- include: tasks/packages.yml
|
||||
```
|
||||
|
||||
现在当我们运行 `ansible-pull` 命令的时候,一个名为 `ansible` 的用户将会在系统中被创建。注意我特地通过参数 `uid` 为这个用户声明了用户 ID 为 900。这个不是必须的,但建议直接创建好 UID。因为在 1000 以下的 UID 在登录界面是不会显示的,这样是很棒的,因为我们根本没有需要去使用 `ansibe` 账户来登录我们的桌面。UID 900 是随便定的;它应该是在 1000 以下没有被使用的任何一个数值。你可以使用以下命令在系统中去验证 UID 900 是否已经被使用了:
|
||||
|
||||
```
|
||||
cat /etc/passwd |grep 900
|
||||
```
|
||||
|
||||
不过,你使用这个 UID 应该不会遇到什么问题,因为迄今为止在我使用的任何发行版中我还没遇到过它是被默认使用的。
|
||||
|
||||
现在,我们已经拥有了一个名为 `ansible` 的账户,它将会在之后的自动化配置中使用。接下来,我们可以创建实际的定时作业来自动操作。我们应该将其分开放到它自己的文件中,而不是将其放置到我们刚刚创建的 `users.yml` 文件中。在任务目录中创建一个名为 `cron.yml` 的任务手册并且将以下的代码写进去:
|
||||
|
||||
```
|
||||
- name: install cron job (ansible-pull)
|
||||
cron: user="ansible" name="ansible provision" minute="*/10" job="/usr/bin/ansible-pull -o -U https://github.com/<github_user>/ansible.git > /dev/null"
|
||||
```
|
||||
|
||||
`cron` 模块的语法几乎不需加以说明。通过这个动作,我们创建了一个通过用户 `ansible` 运行的定时作业。这个作业将每隔 10 分钟执行一次,下面是它将要执行的命令:
|
||||
|
||||
```
|
||||
/usr/bin/ansible-pull -o -U https://github.com/<github_user>/ansible.git > /dev/null
|
||||
```
|
||||
|
||||
同样,我们也可以添加想要我们的所有工作站部署的额外的定时作业到这个文件中。我们只需要在新的定时作业中添加额外的动作即可。然而,仅仅是添加一个定时的任务手册是不够的,我们还需要将它添加到 `local.yml` 文件中以便它能够被调用。将下面的一行添加到末尾:
|
||||
|
||||
```
|
||||
- include: tasks/cron.yml
|
||||
```
|
||||
|
||||
现在当 `ansible-pull` 命令执行的时候,它将会以用户 `ansible` 每隔十分钟设置一个新的定时作业。但是,每个十分钟运行一个 Ansible 作业并不是一个好的方式,因为这个将消耗很多的 CPU 资源。每隔十分钟来运行对于 Ansible 来说是毫无意义的,除非我们已经在 Git 仓库中改变一些东西。
|
||||
|
||||
然而,我们已经解决了这个问题。注意我在定时作业中的命令 `ansible-pill` 添加的我们之前从未用到过的参数 `-o`。这个参数告诉 Ansible 只有在从上次 `ansible-pull` 被调用以后库有了变化后才会运行。如果库没有任何变化,它将不会做任何事情。通过这个方法,你将不会无端的浪费 CPU 资源。当然在拉取存储库的时候会使用一些 CPU 资源,但不会像再一次应用整个配置的时候使用的那么多。当 `ansible-pull` 执行的时候,它将会遍历剧本和任务手册中的所有任务,但至少它不会毫无目的的运行。
|
||||
|
||||
尽管我们已经添加了所有必须的配置要素来自动化 `ansible-pull`,它仍然还不能正常的工作。`ansible-pull` 命令需要 `sudo` 的权限来运行,这将允许它执行系统级的命令。然而我们创建的用户 `ansible` 并没有被设置为以 `sudo` 的权限来执行命令,因此当定时作业触发的时候,执行将会失败。通常我们可以使用命令 `visudo` 来手动的去设置用户 `ansible` 去拥有这个权限。然而我们现在应该以 Ansible 的方式来操作,而且这将会是一个向你展示 `copy` 模块是如何工作的机会。`copy` 模块允许你从库复制一个文件到文件系统的任何位置。在这个案列中,我们将会复制 `sudo` 的一个配置文件到 `/etc/sudoers.d/` 以便用户 `ansible` 能够以管理员的权限执行任务。
|
||||
|
||||
打开 `users.yml`,将下面的的动作添加到文件末尾。
|
||||
|
||||
```
|
||||
- name: copy sudoers_ansible
|
||||
copy: src=files/sudoers_ansible dest=/etc/sudoers.d/ansible owner=root group=root mode=0440
|
||||
```
|
||||
|
||||
正如我们看到的,`copy`模块从我们的仓库中复制一个文件到其他任何位置。在这个过程中,我们正在抓取一个名为 `sudoers_ansible`(我们将在后续创建)的文件并将它复制为 `/etc/sudoers/ansible`,并且拥有者为 `root`。
|
||||
|
||||
接下来,我们需要创建我们将要复制的文件。在你的仓库的根目录下,创建一个名为 `files` 的目录:
|
||||
|
||||
```
|
||||
mkdir files
|
||||
```
|
||||
|
||||
然后,在我们刚刚创建的 `files` 目录里,创建名为 `sudoers_ansible` 的文件,包含以下内容:
|
||||
|
||||
```
|
||||
ansible ALL=(ALL) NOPASSWD: ALL
|
||||
```
|
||||
|
||||
就像我们正在这样做的,在 `/etc/sudoer.d` 目录里创建一个文件允许我们为一个特殊的用户配置 `sudo` 权限。现在我们正在通过 `sudo` 允许用户 `ansible` 不需要密码提示就拥有完全控制权限。这将允许 `ansible-pull` 以后台任务的形式运行而不需要手动去运行。
|
||||
|
||||
现在,你可以通过再次运行 `ansible-pull` 来拉取最新的变动:
|
||||
|
||||
```
|
||||
sudo ansible-pull -U https://github.com/<github_user>/ansible.git
|
||||
```
|
||||
|
||||
从这里开始,`ansible-pull` 的定时作业将会在后台每隔十分钟运行一次来检查你的仓库是否有变化,如果它发现有变化,将会运行你的剧本并且应用你的任务手册。
|
||||
|
||||
所以现在我们有了一个完整的可工作方案。当你第一次设置一台新的笔记本或者台式机的时候,你要去手动的运行 `ansible-pull` 命令,但仅仅是在第一次的时候。从第一次之后,用户 `ansible` 将会在后台接手后续的运行任务。当你想对你的机器做变动的时候,你只需要简单的去拉取你的 Git 仓库来做变动,然后将这些变化回传到库中。接着,当定时作业下次在每台机器上运行的时候,它将会拉取变动的部分并应用它们。你现在只需要做一次变动,你的所有工作站将会跟着一起变动。这方法尽管有一点不同寻常,通常,你会有一个包含你的机器列表和不同机器所属规则的清单文件。然而,`ansible-pull` 的方法,就像在文章中描述的,是管理工作站配置的非常有效的方法。
|
||||
|
||||
我已经在我的 [Github 仓库][2]中更新了这篇文章中的代码,所以你可以随时去浏览来对比检查你的语法。同时我将前一篇文章中的代码移到了它自己的目录中。
|
||||
|
||||
在[第三部分][3],我们将通过介绍使用 Ansible 来配置 GNOME 桌面设置来结束这个系列。我将会告诉你如何设置你的墙纸和锁屏壁纸、应用一个桌面主题以及更多的东西。
|
||||
|
||||
同时,到了布置一些作业的时候了,大多数人都有我们所使用的各种应用的配置文件。可能是 Bash、Vim 或者其他你使用的工具的配置文件。现在你可以尝试通过我们在使用的 Ansible 库来自动复制这些配置到你的机器中。在这篇文章中,我已将向你展示了如何去复制文件,所以去尝试以下看看你是都已经能应用这些知识。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/3/manage-your-workstation-configuration-ansible-part-2
|
||||
|
||||
作者:[Jay LaCroix][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[FelixYFZ](https://github.com/FelixYFZ)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/jlacroix
|
||||
[1]:https://linux.cn/article-10434-1.html
|
||||
[2]:https://github.com/jlacroix82/ansible_article.git
|
||||
[3]:https://opensource.com/article/18/5/manage-your-workstation-ansible-part-3
|
@ -0,0 +1,110 @@
|
||||
用 PGP 保护代码完整性(七):保护在线帐户
|
||||
======
|
||||
|
||||
> 在这个系列的最后一篇当中,我们将为你展示如何用双因子认证保护你的在线账户。
|
||||
|
||||

|
||||
|
||||
到目前为止,本系列教程已经提供了 PGP 的实用指南,包括基本概念和工具、生成和保护你的密钥的步骤。如果你错过了前面的文章,可以通过下面的链接查看。在本系列的最后一篇文章中,我们将为你保护在线帐户提供一个额外的指南,保护在线帐户是当今非常重要的一件事情。
|
||||
|
||||
- [第一部分:基本概念和工具][1]
|
||||
- [第二部分:生成你的主密钥][2]
|
||||
- [第三部分:生成 PGP 子密钥][3]
|
||||
- [第四部分:将主密钥移到离线存储中][4]
|
||||
- [第五部分:将子密钥移到硬件设备中][5]
|
||||
- [第六部分:在 Git 中使用 PGP][6]
|
||||
|
||||
#### 清单
|
||||
|
||||
* 取得一个具备 U2F 功能的设备(必要)
|
||||
* 为你的在线帐户启用双因子认证(必要)
|
||||
* GitHub/GitLab
|
||||
* Google
|
||||
* 社交媒体
|
||||
* 使用 U2F 作为主验证机制,使用 TOTP 作为备选(必要)
|
||||
|
||||
#### 考虑事项
|
||||
|
||||
你可能注意到,很多在线开发者身份是捆绑了 email 地址的。如果有人能够访问你的邮箱,他们就能够去做一些对你会产生危害的事情,进而会损害你作为自由软件开发者的声誉。应该像保护你的 PGP 密钥那样保护你的 email 地址。
|
||||
|
||||
##### 使用 Fido U2F 的双因子认证
|
||||
|
||||
[双因子认证][7] 是一种提升帐户安全性的机制,它除了要求用户名和密码之外,还要求一个物理令牌。它的目标是即便在有人窃取了你的密码(通过按键记录器、肩窥攻击或其它方式)的情况下,仍然能确保你的帐户安全,他们在没有得到你的一个专用的物理设备(“必备”的那个因子)的情况下,始终不能获取你的帐户。
|
||||
|
||||
广为人知的双因子认证机制有:
|
||||
|
||||
* 基于 SMS 的验证
|
||||
* 借助智能手机应用程序的基于时间的一次性令牌(TOTP),比如 Google Authenticator 或类似解决方案
|
||||
* 支持 Fido U2F 的硬件令牌
|
||||
|
||||
基于 SMS 的验证很容易配置,但是它有如下的缺点:它在没有手机信号的地方无法使用(比如,建筑物的地下室),并且如果攻击者能够阻断或转向 SMS 信息,这种方式可能就会失败,比如通过克隆你的 SIM 卡。
|
||||
|
||||
基于 TOTP 的多因子认证提供了比 SMS 更好的安全保护,但它也有一些重要的缺点(你要在智能手机中添加的那么多令牌中找到正确的那个)。此外,还不能避免一个事实,那就是你的密钥最终还是保存在你的智能手机中 —— 它是一个复杂的、全球连接的设备,它有可能还没有及时从制造商那儿收到安全补丁。
|
||||
|
||||
更重要的是,不论是使用 TOTP 还是 SMS 的方法来保护你免受诱骗攻击 —— 如果诱骗攻击者能够窃取你的帐户密码和双因子令牌,他们就可以在合法的站点上使用它们,访问你的帐户。
|
||||
|
||||
[Fido U2F][8] 是一个按标准开发的专用设备,它能够提供双因子认证机制来对付诱骗攻击。U2F 协议在 USB 令牌中保存每个站点的的唯一密钥,如果你在任何合法站点以外的地方尝试使用它,它将阻止你,以防范偶然让攻击者获得你的密码和一次性令牌。
|
||||
|
||||
Chrome 和 Firefox 都支持 U2F 双因子认证,希望其它浏览器也能够提供对 U2F 的支持。
|
||||
|
||||
#### 获得一个支持 Fido U2F 功能的令牌
|
||||
|
||||
支持 U2F 的硬件令牌的 [可选目标很多][9],但如果你已经订购了一个支持智能卡的物理设备,那么你最好的选择就是 Yubikey 4,它两者都支持。
|
||||
|
||||
#### 启用你的在线帐户的双因子认证
|
||||
|
||||
你要确定想启用双因子认证的在线账户,你的 email 提供商已经使用了(特别是 Google,它对 U2F 的支持非常好)。其它的站点这个功能应该是启用了:
|
||||
|
||||
* GitHub:当你上传你的 PGP 公钥时,你应该要想到,如果其他人能够获得访问你的帐户,他们可以用他们自己的 PGP 公钥替换掉你的 PGP 公钥。如果在 GitHub 上发布代码,你应该使用 U2F 认证来保护你的帐户安全。
|
||||
* GitLab:理由同上
|
||||
* Google:如果你有 google 帐户,你就惊奇地发现,许多帐户都允许以 Google 帐户来代替站点专用的认证来登入它们。
|
||||
* Facebook:理由同上,许多在线站点都提供一个选择让你以 Facebook 的帐户来认证。即便你不使用 Facebook 也应该使用双因子认证来保护你的 Facebook 帐户。
|
||||
* 你认为必要的其它站点。查看 [dongleauth.info][10] 去找找灵感。
|
||||
|
||||
#### 如有可能,配置 TOTP 作为备选
|
||||
|
||||
许多站点都允许你配置多个双因子认证机制,推荐的设置是:
|
||||
|
||||
* U2F 令牌作为主认证机制
|
||||
* TOTP 手机应用作为辅助认证机制
|
||||
|
||||
通过这种方式,即便你丢失了你的 U2F 令牌,你仍然能够重新获取对你的帐户的访问。或者,你可以注册多个 U2F 令牌(即:你可以用一个便宜的令牌仅用它做 U2F,并且将它用作备份)。
|
||||
|
||||
### 延伸阅读
|
||||
|
||||
到目前为止,你已经完成了下列的重要任务:
|
||||
|
||||
1. 创建你的开发者身份并使用 PGP 加密来保护它。
|
||||
2. 通过将你的主密钥移到一个离线存储中并将子密钥移到一个外置硬件设备中的方式来配置你的环境,让窃取你的身份变得极为困难。
|
||||
3. 配置你的 Git 环境去确保任何使用你项目的人都能够验证仓库的完整性和它的整个历史。
|
||||
4. 使用双因子认证强化你的在线帐户。
|
||||
|
||||
在安全保护方面,你已经做的很好了,但是你还应该去阅读以下的主题:
|
||||
|
||||
* 如何去强化你的团队沟通。你的项目开发和治理决策的要求应该和保护提交代码那样去保护,如果不这样做,应该确保你的团队沟通是可信任的,并且所有决策的完整性是可验证的。
|
||||
* 如何去强化你的工作站的安全。你的目标是尽可能减少导致项目代码被污染的危险或你的开发者身份被窃的行为。
|
||||
* 如何写出安全的代码(查看相关编程语言和你项目所使用的库的各种文档)。即便引入它的提交代码上有一个 PGP 签名,糟糕的、不安全的代码仍然是糟糕的、不安全的代码!
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linux.com/blog/learn/pgp/2018/3/protecting-code-integrity-pgp-part-7-protecting-online-accounts
|
||||
|
||||
作者:[Konstantin Ryabitsev][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.linux.com/users/mricon
|
||||
[1]:https://linux.cn/article-9524-1.html
|
||||
[2]:https://linux.cn/article-9529-1.html
|
||||
[3]:https://linux.cn/article-9607-1.html
|
||||
[4]:https://linux.cn/article-10402-1.html
|
||||
[5]:https://linux.cn/article-10415-1.html
|
||||
[6]:https://linux.cn/article-10421-1.html
|
||||
[7]:https://en.wikipedia.org/wiki/Multi-factor_authentication
|
||||
[8]:https://en.wikipedia.org/wiki/Universal_2nd_Factor
|
||||
[9]:http://www.dongleauth.info/dongles/
|
||||
[10]:http://www.dongleauth.info/
|
176
published/20180411 How To Setup Static File Server Instantly.md
Normal file
176
published/20180411 How To Setup Static File Server Instantly.md
Normal file
@ -0,0 +1,176 @@
|
||||
如何即时设置一个静态文件服务器
|
||||
======
|
||||
|
||||

|
||||
|
||||
曾经想通过网络共享你的文件或项目,但不知道怎么做?别担心!这里有一个名为 **serve** 的简单实用程序,可以通过网络即时共享你的文件。这个简单的实用程序会立即将你的系统变成一个静态文件服务器,允许你通过网络提供文件。你可以从任何设备访问这些文件,而不用担心它们的操作系统是什么。你所需的只是一个 Web 浏览器。这个实用程序还可以用来服务静态网站。它以前称为 “list” 或 “micri-list”,但现在名称已改为 “serve”(提供),这更适合这个实用程序的目的。
|
||||
|
||||
### 使用 Serve 来设置一个静态文件服务器
|
||||
|
||||
要安装 serve,首先你需要安装 NodeJS 和 NPM。参考以下链接在 Linux 中安装 NodeJS 和 NPM。
|
||||
|
||||
* [如何在 Linux 上安装 NodeJS](https://www.ostechnix.com/install-node-js-linux/)
|
||||
|
||||
NodeJS 和 NPM 安装完成后,运行以下命令来安装 serve:
|
||||
|
||||
```
|
||||
$ npm install -g serve
|
||||
```
|
||||
|
||||
完成!现在是时候 serve 文件或文件夹了。
|
||||
|
||||
使用 serve 的典型语法是:
|
||||
|
||||
```
|
||||
$ serve [options] <path-to-files-or-folders>
|
||||
```
|
||||
|
||||
### 提供特定文件或文件夹
|
||||
|
||||
例如,让我们共享 `Documents` 目录里的内容。为此,运行:
|
||||
|
||||
```
|
||||
$ serve Documents/
|
||||
```
|
||||
|
||||
示例输出:
|
||||
|
||||
![][2]
|
||||
|
||||
正如你在上图中看到的,给定目录的内容已通过两个 URL 提供网络支持。
|
||||
|
||||
要从本地系统访问内容,你只需打开 Web 浏览器,输入 URL `http://localhost:5000/`:
|
||||
|
||||
![][3]
|
||||
|
||||
serve 实用程序以简单的布局显示给定目录的内容。你可以下载(右键单击文件并选择“将链接另存为...”)或只在浏览器中查看它们。
|
||||
|
||||
如果想要在浏览器中自动打开本地地址,使用 `-o` 选项。
|
||||
|
||||
```
|
||||
$ serve -o Documents/
|
||||
```
|
||||
|
||||
运行上述命令后,serve 实用程序将自动打开 Web 浏览器并显示共享项的内容。
|
||||
|
||||
同样,要通过网络从远程系统访问共享目录,可以在浏览器地址栏中输入 `http://192.168.43.192:5000`。用你系统的 IP 替换 192.168.43.192。
|
||||
|
||||
### 通过不同的端口提供内容
|
||||
|
||||
你可能已经注意到,默认情况下,serve 实用程序使用端口 5000。因此,确保防火墙或路由器中允许使用端口 5000。如果由于某种原因被阻止,你可以使用 `-p` 选项使用不同端口来提供内容。
|
||||
|
||||
```
|
||||
$ serve -p 1234 Documents/
|
||||
```
|
||||
|
||||
上面的命令将通过端口 1234 提供 `Documents` 目录的内容。
|
||||
|
||||
![][4]
|
||||
|
||||
要提供文件而不是文件夹,只需给它完整的路径,如下所示。
|
||||
|
||||
```
|
||||
$ serve Documents/Papers/notes.txt
|
||||
```
|
||||
|
||||
只要知道路径,网络上的任何用户都可以访问共享目录的内容。
|
||||
|
||||
### 提供整个 `$HOME` 目录
|
||||
|
||||
打开终端输入
|
||||
|
||||
```
|
||||
$ serve
|
||||
```
|
||||
|
||||
这将通过网络共享整个 `$HOME` 目录的内容。
|
||||
|
||||
要停止共享,按下 `CTRL+C`。
|
||||
|
||||
### 提供选定的文件或文件夹
|
||||
|
||||
你可能不想共享所有文件或目录,只想共享其中的一些。你可以使用 `-i` 选项排除文件或目录。
|
||||
|
||||
```
|
||||
$ serve -i Downloads/
|
||||
```
|
||||
|
||||
以上命令将提供整个文件系统,除了 `Downloads` 目录。
|
||||
|
||||
### 仅在本地主机上提供内容
|
||||
|
||||
有时,你只想在本地系统而不是整个网络上提供内容。为此,使用 `-l` 标志,如下所示:
|
||||
|
||||
```
|
||||
$ serve -l Documents/
|
||||
```
|
||||
|
||||
此命令会仅在本地提供 `Documents` 目录。
|
||||
|
||||
![][5]
|
||||
|
||||
当你在共享服务器上工作时,这可能会很有用。系统中的所有用户都可以访问共享,但远程用户不能。
|
||||
|
||||
### 使用 SSL 提供内容
|
||||
|
||||
由于我们通过本地网络提供内容,因此我们不需要使用 SSL。但是,serve 实用程序可以使用 `-ssl` 选项来使用 SSL 共享内容。
|
||||
|
||||
```
|
||||
$ serve --ssl Documents/
|
||||
```
|
||||
|
||||
![][6]
|
||||
|
||||
要通过 Web 浏览器访问共享,输入 `https://localhost:5000` 或 `https://ip:5000`。
|
||||
|
||||
![][7]
|
||||
|
||||
### 通过身份验证提供内容
|
||||
|
||||
在上面的所有示例中,我们在没有任何身份验证的情况下提供内容,所以网络上的任何人都可以在没有任何身份验证的情况下访问共享内容。你可能会觉得应该使用用户名和密码访问某些内容。
|
||||
|
||||
为此,使用:
|
||||
|
||||
```
|
||||
$ SERVE_USER=ostechnix SERVE_PASSWORD=123456 serve --auth
|
||||
```
|
||||
|
||||
现在用户需要输入用户名(即 `ostechnix`)和密码(`123456`)来访问共享。(LCTT 译注:123456 是非常不好的密码,仅在实验情况下使用)
|
||||
|
||||
![][8]
|
||||
|
||||
serve 实用程序还有一些其它功能,例如禁用 [Gzip 压缩][9],设置 CORS 头以允许来自任河源的请求,防止自动复制地址到剪贴板等。通过以下命令,你可以阅读完整的帮助部分。
|
||||
|
||||
```
|
||||
$ serve help
|
||||
```
|
||||
|
||||
好了,这就是全部了。希望这可以帮助到你。更多好东西要来了,敬请关注!
|
||||
|
||||
共勉!
|
||||
|
||||
资源:
|
||||
|
||||
* [Serve GitHub 仓库](https://github.com/zeit/serve)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/how-to-setup-static-file-server-instantly/
|
||||
|
||||
作者:[SK][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[MjSeven](https://github.com/MjSeven)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.ostechnix.com/author/sk/
|
||||
[1]:data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[2]:http://www.ostechnix.com/wp-content/uploads/2018/04/serve-1.png
|
||||
[3]:http://www.ostechnix.com/wp-content/uploads/2018/04/serve-2.png
|
||||
[4]:http://www.ostechnix.com/wp-content/uploads/2018/04/serve-4.png
|
||||
[5]:http://www.ostechnix.com/wp-content/uploads/2018/04/serve-3.png
|
||||
[6]:http://www.ostechnix.com/wp-content/uploads/2018/04/serve-6.png
|
||||
[7]:http://www.ostechnix.com/wp-content/uploads/2018/04/serve-5-1.png
|
||||
[8]:http://www.ostechnix.com/wp-content/uploads/2018/04/serve-7-1.png
|
||||
[9]:https://www.ostechnix.com/how-to-compress-and-decompress-files-in-linux/
|
@ -0,0 +1,157 @@
|
||||
设计微服务架构前应该了解的 5 项指导原则
|
||||
======
|
||||
> 顶级 CTO 基于五个简单的原则为精心设计的微服务提供建议。
|
||||
|
||||

|
||||
|
||||
对于从微服务开始的团队来说,最大的挑战之一就是坚持<ruby>金发女孩原则<rt>The Goldilocks principle</rt></ruby>(该典故来自于童话《金发姑娘和三只熊》):不要太大,不要太小,不能太紧密耦合。之所以是挑战的部分原因是会对究竟什么是设计良好的微服务感到疑惑。
|
||||
|
||||
数十位 CTO 通过采访分享了他们的经验,这些对话说明了设计良好的微服务的五个特点。本文将帮助指导团队设计微服务。(有关详细信息,请查看即将出版的书籍 [Microservices for Startups][1],LCTT 译注:已可免费下载完整的电子版)。本文将简要介绍微服务的边界和主观的 “规则”,以避免在深入了解五个特征之前就开始指导您的微服务设计。
|
||||
|
||||
### 微服务边界
|
||||
|
||||
[使用微服务开发新系统的核心优势][2]之一是该体系结构允许开发人员独立构建和修改各个组件,但在最大限度地减少每个 API 之间的回调数量方面可能会出现问题。根据 [SparkPost][3] 工程副总裁 Chris McFadden 所说,解决方案是应用适当的服务边界。
|
||||
|
||||
关于边界,与有时难以理解和抽象的领域驱动设计(DDD,一种微服务框架)形成鲜明对比,本文重点介绍了和我们行业的一些顶级 CTO 一同建立的明确定义的微服务边界的实用原则。
|
||||
|
||||
### 避免主观的 “规则”
|
||||
|
||||
如果您阅读了足够多的关于设计和创建微服务的建议,您一定会遇到下面的一些 “规则”。 尽管将它们用作创建微服务的指南很有吸引力,但加入这些主观规则并不是思考确定微服务的边界的原则性方式。
|
||||
|
||||
#### “微服务应该有 X 行代码”
|
||||
|
||||
让我们直说:微服务中有多少行代码没有限制。微服务不会因为您写了几行额外的代码而突然变成一个独石应用。关键是要确保服务中的代码具有很高的内聚性(稍后将对此进行更多介绍)。
|
||||
|
||||
#### “将每个功能转换为微服务”
|
||||
|
||||
如果函数基于三个输入值计算某些内容并返回结果,它是否是微服务的理想候选项?它是否应该是单独可部署应用程序?这确实取决于该函数是什么以及它是如何服务于整个系统。将每个函数转换为微服务在您的情景中可能根本没有意义。
|
||||
|
||||
其他主观规则包括不考虑整个情景的规则,例如团队的经验、DevOps 能力、服务正在执行的操作以及数据的可用性需求。
|
||||
|
||||
### 精心设计的服务的 5 个特点
|
||||
|
||||
如果您读过关于微服务的文章,您无疑会遇到有关设计良好的服务的建议。简单地说,高内聚和低耦合。如果您不熟悉这些概念,有[许多][4][文章][4]关于这些概念的文章。虽然它们提供了合理的建议,但这些概念是相当抽象的。基于与经验丰富的 CTO 们的对话,下面是在创建设计良好的微服务时需要牢记的关键特征。
|
||||
|
||||
#### #1:不与其他服务共享数据库表
|
||||
|
||||
在 SparkPost 的早期,Chris McFadden 和他的团队必须解决每个 SaaS 业务需要面对的问题:它们需要提供基本服务,如身份验证、帐户管理和计费。
|
||||
|
||||
为了解决这个问题,他们创建了两个微服务:用户 API 和帐户 API。用户 API 将处理用户帐户、API 密钥和身份验证,而帐户 API 将处理所有与计费相关的逻辑。这是一个非常合乎逻辑的分离 —— 但没过多久,他们发现了一个问题。
|
||||
|
||||
McFadden 解释说,“我们有一个名为‘用户 API’的服务,还有一个名为‘帐户 API’的服务。问题是,他们之间实际上有几个来回的调用。因此,您会在帐户服务中执行一些操作,然后调用并终止于用户服务,反之亦然”
|
||||
|
||||
这两个服务的耦合太紧密了。
|
||||
|
||||
在设计微服务时,如果您有多个服务引用同一个表,则它是一个危险的信号,因为这可能意味着您的数据库是耦合的源头。
|
||||
|
||||
这确实是关于服务与数据的关系,这正是 [Swiftype SRE,Elastic][6] 的负责人 Oleksiy Kovrin 告诉我。他说,“我们在开发新服务时使用的主要基本原则之一是,它们不应跨越数据库边界。每个服务都应依赖于自己的一组底层数据存储。这使我们能够集中访问控制、审计日志记录、缓存逻辑等。”
|
||||
|
||||
Kovrin 接着解释说,如果数据库表的某个子集“与数据集的其余部分没有或很少连接,则这是一个强烈的信号,表明该组件可以被隔离到单独的 API 或单独的服务中”。
|
||||
|
||||
[Lead Honestly][7] 的联合创始人 Darby Frey 与此的观点相呼应:“每个服务都应该有自己的表并且永远不应该共享数据库表。”
|
||||
|
||||
#### #2:数据库表数量最小化
|
||||
|
||||
微服务的理想尺寸应该足够小,但不能太小。每个服务的数据库表的数量也是如此。
|
||||
|
||||
[Scaylr][8] 的工程主管 Steven Czerwinski 在接受采访时解释说 Scaylr 的最佳选择是“一个或两个服务的数据库表。”
|
||||
|
||||
SparkPost 的 Chris McFadden 表示同意:“我们有一个 suppression 微服务,它处理、跟踪数以百万计和数十亿围绕 suppression 的条目,但它们都非常专注于围绕 suppression,所以实际上只有一个或两个表。其他服务也是如此,比如 webhooks。
|
||||
|
||||
#### #3:考虑有状态和无状态
|
||||
|
||||
在设计微服务时,您需要问问自己它是否需要访问数据库,或者它是否是处理 TB 级数据 (如电子邮件或日志) 的无状态服务。
|
||||
|
||||
[Algolia][9] 的 CTO Julien Lemoine 解释说:“我们通过定义服务的输入和输出来定义服务的边界。有时服务是网络 API,但它也可能是使用文件并在数据库中生成记录的进程 (这就是我们的日志处理服务)。”
|
||||
|
||||
事先要明确是否有状态,这将引导一个更好的服务设计。
|
||||
|
||||
#### #4:考虑数据可用性需求
|
||||
|
||||
在设计微服务时,请记住哪些服务将依赖于此新服务,以及在该数据不可用时的整个系统的影响。考虑到这一点,您可以正确地设计此服务的数据备份和恢复系统。
|
||||
|
||||
Steven Czerwinski 提到,在 Scaylr 由于关键客户行空间映射数据的重要性,它将以不同的方式复制和分离。
|
||||
|
||||
相比之下,他补充说,“每个分片信息,都在自己的小分区里。如果部分客户群体因为没有可用日志而停止服务那很糟糕,但它只影响 5% 的客户,而不是100% 的客户。”
|
||||
|
||||
#### #5:单一的真实来源
|
||||
|
||||
设计服务,使其成为系统中某些内容的唯一真实来源。
|
||||
|
||||
例如,当您从电子商务网站订购内容时,则会生成订单 ID,其他服务可以使用此订单 ID 来查询订单服务,以获取有关订单的完整信息。使用 [发布/订阅模式][10],在服务之间传递的数据应该是订单 ID ,而不是订单本身的属性信息。只有订单服务具有订单的完整信息,并且是给定订单信息的唯一真实来源。
|
||||
|
||||
### 大型团队的注意事项
|
||||
|
||||
考虑到上面列出的五个注意事项,较大的团队应了解其组织结构对微服务边界的影响。
|
||||
|
||||
对于较大的组织,整个团队可以专门拥有服务,在确定服务边界时,组织性就会发挥作用。还有两个需要考虑的因素:**独立的发布计划**和**不同的正常运行时间**的重要性。
|
||||
|
||||
[Cloud66.][11] 的 CEO Khash Sajadi 说:“我们所看到的微服务最成功的实现要么基于类似领域驱动设计这样的软件设计原则 (如面向服务的体系结构),要么基于反映组织方法的设计原则。”
|
||||
|
||||
“所以 (对于) 支付团队” Sajadi 说,“他们有支付服务或信用卡验证服务,这就是他们向外界提供的服务。所以这不一定是关于软件的。这主要是关于为外界提供更多服务的业务单位。”
|
||||
|
||||
### 双披萨原理
|
||||
|
||||
Amazon 是一个拥有多个团队的大型组织的完美示例。正如在一篇发表于 [API Evangelist][12] 的文章中所提到的,Jeff Bezos 向所有员工发布一项要求,告知他们公司内的每个团队都必须通过 API 进行沟通。任何不这样做的人都会被解雇。
|
||||
|
||||
这样,所有数据和功能都通过该接口公开。Bezos 还设法让每个团队解耦,定义他们的资源,并通过 API 提供。Amazon 正在从头建立一个系统。这使得公司内的每一支团队都能成为彼此的合作伙伴。
|
||||
|
||||
我与 [Iron.io][13] 的 CTO Travis Reeder 谈到了 Bezos 的内部倡议。
|
||||
|
||||
“Jeff Bezos 规定所有团队都必须构建 API 才能与其他团队进行沟通,” Reeder 说。“他也是提出‘双披萨’规则的人:一支团队不应该比两个比萨饼能养活的大。”
|
||||
|
||||
“我认为这里也可以适用同样的方法:无论一个小型团队是否能够开发、管理和富有成效。如果它开始变得笨重或开始变慢,它可能变得太大了。” Reeder 告诉我。
|
||||
|
||||
### 最后注意事项: 您的服务是否具有合适的大小和正确的定义?
|
||||
|
||||
在微服务系统的测试和实施阶段,有一些指标需要记住。
|
||||
|
||||
#### 指标 #1: 服务之间是否存在过度依赖?
|
||||
|
||||
如果两个服务不断地相互回调,那么这就是强烈的耦合信号,也是它们可能更好地合并为一个服务的信号。
|
||||
|
||||
回到 Chris McFadden 的例子, 他有两个 API 服务,帐户服务和用户服务不断地相互通信, McFadden 提出了一个合并服务的想法,并决定将其称为 “账户用户 API”。事实证明,这是一项富有成效的战略。
|
||||
|
||||
“我们开始做的是消除这些内部 API 之间调用的链接,” McFadden 告诉我。“这有助于简化代码。”
|
||||
|
||||
#### 指标 #2: 设置服务的开销是否超过了服务独立的好处?
|
||||
|
||||
Darby Frey 解释说,“每个应用都需要将其日志聚合到某个位置,并需要进行监视。你需要设置它的警报。你需要有标准的操作程序,和在出现问题时的操作手册。您必须管理 SSH 对它的访问。只是为了让一个应用运行起来,就有大量的基础性工作必须存在。”
|
||||
|
||||
### 关键要点
|
||||
|
||||
设计微服务往往会让人感觉更像是一门艺术,而不是一门科学。对工程师来说,这可能并不顺利。有很多一般性的建议,但有时可能有点太抽象了。让我们回顾一下在设计下一组微服务时要注意的五个具体特征:
|
||||
|
||||
1. 不与其他服务共享数据库表
|
||||
2. 数据库表数量最小化
|
||||
3. 考虑有状态和无状态
|
||||
4. 考虑数据可用性需求
|
||||
5. 单一的真实来源
|
||||
|
||||
下次设计一组微服务并确定服务边界时,回顾这些原则应该会使任务变得更容易。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/4/guide-design-microservices
|
||||
|
||||
作者:[Jake Lumetta][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[lixinyuxx](https://github.com/lixinyuxx)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/jakelumetta
|
||||
[1]:https://buttercms.com/books/microservices-for-startups/
|
||||
[2]:https://buttercms.com/books/microservices-for-startups/should-you-always-start-with-a-monolith
|
||||
[3]:https://www.sparkpost.com/
|
||||
[4]:https://thebojan.ninja/2015/04/08/high-cohesion-loose-coupling/
|
||||
[5]:https://en.wikipedia.org/wiki/Single_responsibility_principle
|
||||
[6]:https://www.elastic.co/solutions/site-search
|
||||
[7]:https://leadhonestly.com/
|
||||
[8]:https://www.scalyr.com/
|
||||
[9]:https://www.algolia.com/
|
||||
[10]:https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern
|
||||
[11]:https://www.cloud66.com/
|
||||
[12]:https://apievangelist.com/2012/01/12/the-secret-to-amazons-success-internal-apis/
|
||||
[13]:https://www.iron.io/
|
304
published/20180428 A Beginners Guide To Flatpak.md
Normal file
304
published/20180428 A Beginners Guide To Flatpak.md
Normal file
@ -0,0 +1,304 @@
|
||||
Flatpak 新手指南
|
||||
======
|
||||
|
||||

|
||||
|
||||
以前,我们介绍 Ubuntu 推出的 [Snaps][1]。Snaps 是由 Canonical 公司为 Ubuntu 开发的,并随后移植到其他的 Linux 发行版,如 Arch、Gentoo、Fedora 等等。由于一个 snap 包中含有软件的二进制文件和其所需的所有依赖和库,所以可以在无视软件版本、在任意 Linux 发行版上安装软件。和 Snaps 类似,还有一个名为 Flatpak 的工具。也许你已经知道,为不同的 Linux 发行版打包并分发应用是一件多么费时又复杂的工作,因为不同的 Linux 发行版的库不同,库的版本也不同。现在,Flatpak 作为分发桌面应用的新框架可以让开发者完全摆脱这些负担。开发者只需构建一个 Flatpak app 就可以在多种发行版上安装使用。这真是又酷又棒!
|
||||
|
||||
用户也完全不用担心库和依赖的问题了,所有的东西都和 app 打包在了一起。更重要的是 Flatpak app 们都自带沙箱,而且与宿主操作系统的其他部分隔离。对了,Flatpak 还有一个很棒的特性,它允许用户在同一个系统中安装同一应用的多个版本,例如 VLC 播放器的 2.1 版、2.2 版、2.3 版。这使开发者测试同一个软件的多个版本变得更加方便。
|
||||
|
||||
在本文中,我们将指导你如何在 GNU/Linux 中安装 Flatpak。
|
||||
|
||||
### 安装 Flatpak
|
||||
|
||||
Flatpak 可以在大多数的主流 Linux 发行版上安装使用,如 Arch Linux、Debian、Fedora、Gentoo、Red Hat、Linux Mint、openSUSE、Solus、Mageia 还有 Ubuntu。
|
||||
|
||||
在 Arch Linux 上,使用这一条命令来安装 Flatpak:
|
||||
|
||||
```
|
||||
$ sudo pacman -S flatpak
|
||||
```
|
||||
|
||||
对于 Debian 用户,Flatpak 被收录进 Stretch 或之后版本的默认软件源中。要安装 Flatpak,直接执行:
|
||||
|
||||
```
|
||||
$ sudo apt install flatpak
|
||||
```
|
||||
|
||||
对于 Fedora 用户,Flatpak 是发行版默认安装的软件。你可以直接跳过这一步。
|
||||
|
||||
如果因为某种原因没有安装的话,可以执行:
|
||||
|
||||
```
|
||||
$ sudo dnf install flatpak
|
||||
```
|
||||
|
||||
对于 RHEL 7 用户,安装 Flatpak 的命令为:
|
||||
|
||||
```
|
||||
$ sudo yum install flatpak
|
||||
```
|
||||
|
||||
如果你在使用 Linux Mint 18.3,那么 Flatpat 也随系统默认安装,所以跳过这一步。
|
||||
|
||||
在 openSUSE Tumbleweed 中,使用 Zypper 包管理来安装 Flatpak:
|
||||
|
||||
```
|
||||
$ sudo zypper install flatpak
|
||||
```
|
||||
|
||||
而 Ubuntu 需要添加下面的软件源再安装 Flatpak,命令如下:
|
||||
|
||||
```
|
||||
$ sudo add-apt-repository ppa:alexlarsson/flatpak
|
||||
$ sudo apt update
|
||||
$ sudo apt install flatpak
|
||||
```
|
||||
|
||||
Gnome 提供了一个 Flatpak 插件,安装它就可以使用图形界面来安装 Flatpak app 了。插件的安装命令为:
|
||||
|
||||
```
|
||||
$ sudo apt install gnome-software-plugin-flatpak
|
||||
```
|
||||
|
||||
如果你是用发行版没有在上述的说明里,请你参考官方[安装指南][2]。
|
||||
|
||||
### 开始使用 Flatpak
|
||||
|
||||
有不少流行应用都支持 Flatpak 安装,如 Gimp、Kdenlive、Steam、Spotify、Visual Sudio Code 等。
|
||||
|
||||
下面让我来一起学习 flatpak 的基本操作命令。
|
||||
|
||||
首先,我们需要添加远程仓库。
|
||||
|
||||
#### 添加软件仓库
|
||||
|
||||
**添加 Flathub 仓库:**
|
||||
|
||||
Flathub 是一个包含了几乎所有 flatpak 应用的仓库。运行这条命令来启用它:
|
||||
|
||||
```
|
||||
$ sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
```
|
||||
|
||||
对于流行应用来说,Flathub 已经可以满足需求。如果你想试试 GNOME 应用的话,可以添加 GNOME 的仓库。
|
||||
|
||||
**添加 GNOME 仓库:**
|
||||
|
||||
GNOME 仓库包括了所有的 GNOME 核心应用,它提供了两种版本:<ruby>稳定版<rt>stable</rt></ruby>和<strong><ruby>每日构建版<rt>nightly</rt></ruby></strong>。
|
||||
|
||||
使用下面的命令来添加 GNOME 稳定版仓库:
|
||||
|
||||
```
|
||||
$ wget https://sdk.gnome.org/keys/gnome-sdk.gpg
|
||||
$ sudo flatpak remote-add --gpg-import=gnome-sdk.gpg --if-not-exists gnome-apps https://sdk.gnome.org/repo-apps/
|
||||
```
|
||||
|
||||
需要注意的是,GNOME 稳定版仓库中的应用需要 **3.20 版本的 org.gnome.Platform 运行时环境**。
|
||||
|
||||
安装稳定版运行时环境,请执行:
|
||||
|
||||
```
|
||||
$ sudo flatpak remote-add --gpg-import=gnome-sdk.gpg gnome https://sdk.gnome.org/repo/
|
||||
```
|
||||
|
||||
如果想使用每日构建版的 GNOME 仓库,使用如下的命令:
|
||||
|
||||
```
|
||||
$ wget https://sdk.gnome.org/nightly/keys/nightly.gpg
|
||||
$ sudo flatpak remote-add --gpg-import=nightly.gpg --if-not-exists gnome-nightly-apps https://sdk.gnome.org/nightly/repo-apps/
|
||||
```
|
||||
|
||||
同样,每日构建版的 GNOME 仓库也需要 **org.gnome.Platform 运行时环境的每日构建版本**。
|
||||
|
||||
执行下面的命令安装每日构建版的运行时环境:
|
||||
|
||||
```
|
||||
$ sudo flatpak remote-add --gpg-import=nightly.gpg gnome-nightly https://sdk.gnome.org/nightly/repo/
|
||||
```
|
||||
|
||||
#### 查看软件仓库
|
||||
|
||||
要查看已经添加的软件仓库,执行下面的命令:
|
||||
|
||||
```
|
||||
$ flatpak remotes
|
||||
Name Options
|
||||
flathub system
|
||||
gnome system
|
||||
gnome-apps system
|
||||
gnome-nightly system
|
||||
gnome-nightly-apps system
|
||||
```
|
||||
|
||||
如你所见,上述命令会列出你添加到系统中的软件仓库。此外,执行结果还表明了软件仓库的配置是<ruby>用户级<rt>per-user</rt></ruby>还是<ruby>系统级<rt>system-wide</rt></ruby>。
|
||||
|
||||
#### 删除软件仓库
|
||||
|
||||
要删除软件仓库,例如 flathub,用这条命令:
|
||||
|
||||
```
|
||||
$ sudo flatpak remote-delete flathub
|
||||
```
|
||||
|
||||
这里的 flathub 是软件仓库的名字。
|
||||
|
||||
#### 安装 Flatpak 应用
|
||||
|
||||
这一节,我们将学习如何安装 flatpak 应用。
|
||||
|
||||
要安装一个应用,只要一条命令就能完成:
|
||||
|
||||
```
|
||||
$ sudo flatpak install flathub com.spotify.Client
|
||||
```
|
||||
|
||||
所有的稳定版 GNOME 软件仓库中的应用,都使用“stable”作为版本名。
|
||||
|
||||
例如,想从稳定版 GNOME 软件仓库中安装稳定版 Evince,就执行:
|
||||
|
||||
```
|
||||
$ sudo flatpak install gnome-apps org.gnome.Evince stable
|
||||
```
|
||||
|
||||
所有的每日构建版 GNOME 仓库中的应用,都使用“master”作为版本名。
|
||||
|
||||
例如,要从每日构建版 GNOME 软件仓库中安装 gedit 的每次构建版本,就执行:
|
||||
|
||||
```
|
||||
$ sudo flatpak install gnome-nightly-apps org.gnome.gedit master
|
||||
```
|
||||
|
||||
如果不希望应用安装在<ruby>系统级<rt>system-wide</rt></ruby>,而只安装在<ruby>用户级<rt>per-user</rt></ruby>,那么你可以这样安装软件:
|
||||
|
||||
```
|
||||
$ flatpak install --user <name-of-app>
|
||||
```
|
||||
|
||||
所有的应用都会被存储在 `$HOME/.var/app/` 目录下.
|
||||
|
||||
```
|
||||
$ ls $HOME/.var/app/
|
||||
com.spotify.Client
|
||||
```
|
||||
|
||||
#### 执行 Flatpak 应用
|
||||
|
||||
你可以直接使用<ruby>应用启动器<rt>application launcher</rt></ruby>来运行已安装的 Flatpak 应用。如果你想从命令行启动的话,以 Spotify 为例,执行下面的命令:
|
||||
|
||||
```
|
||||
$ flatpak run com.spotify.Client
|
||||
```
|
||||
|
||||
#### 列出已安装的 Flatpak 应用
|
||||
|
||||
要查看已安装的应用程序和运行时环境,执行:
|
||||
|
||||
```
|
||||
$ flatpak list
|
||||
```
|
||||
|
||||
想只查看已安装的应用,那就用这条命令:
|
||||
|
||||
```
|
||||
$ flatpak list --app
|
||||
```
|
||||
|
||||
如果想查询已添加的软件仓库中的可安装程序和可安装的运行时环境,使用命令:
|
||||
|
||||
```
|
||||
$ flatpak remote-ls
|
||||
```
|
||||
|
||||
只列出可安装的应用程序的命令是:
|
||||
|
||||
```
|
||||
$ flatpak remote-ls --app
|
||||
```
|
||||
|
||||
查询指定远程仓库中的所有可安装的应用程序和运行时环境,这里以 gnome-apps 为例,执行命令:
|
||||
|
||||
```
|
||||
$ flatpak remote-ls gnome-apps
|
||||
```
|
||||
|
||||
只列出可安装的应用程序,这里以 flathub 为例:
|
||||
|
||||
```
|
||||
$ flatpak remote-ls flathub --app
|
||||
```
|
||||
|
||||
#### 更新应用程序
|
||||
|
||||
更新所有的 Flatpak 应用程序,执行:
|
||||
|
||||
```
|
||||
$ flatpak update
|
||||
```
|
||||
|
||||
更新指定的 Flatpak 应用程序,执行:
|
||||
|
||||
```
|
||||
$ flatpak update com.spotify.Client
|
||||
```
|
||||
|
||||
#### 获取应用详情
|
||||
|
||||
执行下面的命令来查看已安装应用程序的详细信息:
|
||||
|
||||
```
|
||||
$ flatpak info io.github.mmstick.FontFinder
|
||||
```
|
||||
|
||||
输出样例:
|
||||
|
||||
```
|
||||
Ref: app/io.github.mmstick.FontFinder/x86_64/stable
|
||||
ID: io.github.mmstick.FontFinder
|
||||
Arch: x86_64
|
||||
Branch: stable
|
||||
Origin: flathub
|
||||
Date: 2018-04-11 15:10:31 +0000
|
||||
Subject: Workaround appstream issues (391ef7f5)
|
||||
Commit: 07164e84148c9fc8b0a2a263c8a468a5355b89061b43e32d95008fc5dc4988f4
|
||||
Parent: dbff9150fce9fdfbc53d27e82965010805f16491ec7aa1aa76bf24ec1882d683
|
||||
Location: /var/lib/flatpak/app/io.github.mmstick.FontFinder/x86_64/stable/07164e84148c9fc8b0a2a263c8a468a5355b89061b43e32d95008fc5dc4988f4
|
||||
Installed size: 2.5 MB
|
||||
Runtime: org.gnome.Platform/x86_64/3.28
|
||||
```
|
||||
|
||||
#### 删除应用程序
|
||||
|
||||
要删除一个 Flatpak 应用程序,这里以 spotify 为例,执行:
|
||||
|
||||
```
|
||||
$ sudo flatpak uninstall com.spotify.Client
|
||||
```
|
||||
|
||||
如果你需要更多信息,可以参考 Flatpak 的帮助。
|
||||
|
||||
```
|
||||
$ flatpak --help
|
||||
```
|
||||
|
||||
到此,希望你对 Flatpak 有了一些基础了解。
|
||||
|
||||
如果你觉得这篇指南有些帮助,请在你的社交媒体上分享它来支持我们。
|
||||
|
||||
稍后还有更多精彩内容,敬请期待~
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/flatpak-new-framework-desktop-applications-linux/
|
||||
|
||||
作者:[SK][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[wwhio](https://github.com/wwhio)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.ostechnix.com/author/sk/
|
||||
[1]:http://www.ostechnix.com/introduction-ubuntus-snap-packages/
|
||||
[2]:https://flatpak.org/setup/
|
@ -0,0 +1,188 @@
|
||||
Linux 上查看系统/服务器运行时间的 11 种方法
|
||||
======
|
||||
|
||||
你是否想知道自己的 Linux 系统正常运行了多长时间而没有宕机?系统是什么时候启动的?
|
||||
|
||||
Linux 上有多个查看服务器/系统运行时间的命令,大多数用户喜欢使用标准并且很有名的 `uptime` 命令获取这些具体的信息。
|
||||
|
||||
服务器的运行时间对一些用户来说不那么重要,但是当服务器运行诸如在线商城<ruby>门户<rt>portal</rt></ruby>、网上银行门户等<ruby>关键任务应用<rt>mission-critical applications</rt></ruby>时,它对于<ruby>服务器管理员<rt>server adminstrators</rt></ruby>来说就至关重要。
|
||||
|
||||
它必须做到零宕机,因为一旦停机就会影响到数百万用户。
|
||||
|
||||
正如我所说,许多命令都可以让用户看到 Linux 服务器的运行时间。在这篇教程里我会教你如何使用下面 11 种方式来查看。
|
||||
|
||||
<ruby>正常运行时间<rt>uptime</rt></ruby>指的是服务器自从上次关闭或重启以来经过的时间。
|
||||
|
||||
`uptime` 命令获取 `/proc` 文件中的详细信息并输出正常运行时间,而 `/proc` 文件并不适合人直接看。
|
||||
|
||||
以下这些命令会输出系统运行和启动的时间。也会显示一些额外的信息。
|
||||
|
||||
### 方法 1:使用 uptime 命令
|
||||
|
||||
`uptime` 命令会告诉你系统运行了多长时间。它会用一行显示以下信息。
|
||||
|
||||
当前时间、系统运行时间、当前登录用户的数量、过去 1 分钟/5 分钟/15 分钟系统负载的均值。
|
||||
|
||||
```
|
||||
# uptime
|
||||
|
||||
08:34:29 up 21 days, 5:46, 1 user, load average: 0.06, 0.04, 0.00
|
||||
```
|
||||
|
||||
### 方法 2:使用 w 命令
|
||||
|
||||
`w` 命令为每个登录进系统的用户,每个用户当前所做的事情,所有活动的负载对计算机的影响提供了一个快速的概要。这个单一命令结合了多个 Unix 程序:`who`、`uptime`,和 `ps -a` 的结果。
|
||||
|
||||
```
|
||||
# w
|
||||
|
||||
08:35:14 up 21 days, 5:47, 1 user, load average: 0.26, 0.09, 0.02
|
||||
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
|
||||
root pts/1 103.5.134.167 08:34 0.00s 0.01s 0.00s w
|
||||
```
|
||||
|
||||
### 方法 3:使用 top 命令
|
||||
|
||||
`top` 命令是 Linux 上监视实时系统进程的基础命令之一。它显示系统信息和运行进程的信息,例如正常运行时间、平均负载、运行的任务、登录用户数量、CPU 数量 & CPU 利用率、内存 & 交换空间信息。
|
||||
|
||||
**推荐阅读:**[TOP 命令监视服务器性能的例子][1]
|
||||
|
||||
```
|
||||
# top -c
|
||||
|
||||
top - 08:36:01 up 21 days, 5:48, 1 user, load average: 0.12, 0.08, 0.02
|
||||
Tasks: 98 total, 1 running, 97 sleeping, 0 stopped, 0 zombie
|
||||
Cpu(s): 0.0%us, 0.3%sy, 0.0%ni, 99.7%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
|
||||
Mem: 1872888k total, 1454644k used, 418244k free, 175804k buffers
|
||||
Swap: 2097148k total, 0k used, 2097148k free, 1098140k cached
|
||||
|
||||
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
|
||||
1 root 20 0 19340 1492 1172 S 0.0 0.1 0:01.04 /sbin/init
|
||||
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 [kthreadd]
|
||||
3 root RT 0 0 0 0 S 0.0 0.0 0:00.00 [migration/0]
|
||||
4 root 20 0 0 0 0 S 0.0 0.0 0:34.32 [ksoftirqd/0]
|
||||
5 root RT 0 0 0 0 S 0.0 0.0 0:00.00 [stopper/0]
|
||||
```
|
||||
|
||||
### 方法 4:使用 who 命令
|
||||
|
||||
`who` 命令列出当前登录进计算机的用户。`who` 命令与 `w` 命令类似,但后者还包含额外的数据和统计信息。
|
||||
|
||||
```
|
||||
# who -b
|
||||
system boot 2018-04-12 02:48
|
||||
```
|
||||
|
||||
### 方法 5:使用 last 命令
|
||||
|
||||
`last` 命令列出最近登录过的用户。`last` 回溯 `/var/log/wtmp` 文件并显示自从文件创建后登录进(出)的用户。
|
||||
|
||||
```
|
||||
# last reboot -F | head -1 | awk '{print $5,$6,$7,$8,$9}'
|
||||
Thu Apr 12 02:48:04 2018
|
||||
```
|
||||
|
||||
### 方法 6:使用 /proc/uptime 文件
|
||||
|
||||
这个文件中包含系统上次启动后运行时间的详细信息。`/proc/uptime` 的输出相当精简。
|
||||
|
||||
第一个数字是系统自从启动的总秒数。第二个数字是总时间中系统空闲所花费的时间,以秒为单位。
|
||||
|
||||
```
|
||||
# cat /proc/uptime
|
||||
1835457.68 1809207.16
|
||||
```
|
||||
|
||||
### 方法 7:使用 tuptime 命令
|
||||
|
||||
`tuptime` 是一个汇报系统运行时间的工具,输出历史信息并作以统计,保留重启之间的数据。和 `uptime` 命令很像,但输出更有意思一些。
|
||||
|
||||
```
|
||||
$ tuptime
|
||||
```
|
||||
|
||||
### 方法 8:使用 htop 命令
|
||||
|
||||
`htop` 是运行在 Linux 上的一个交互式进程查看器,是 Hisham 使用 ncurses 库开发的。`htop` 比起 `top` 有很多的特性和选项。
|
||||
|
||||
**推荐阅读:** [使用 Htop 命令监控系统资源][2]
|
||||
|
||||
```
|
||||
# htop
|
||||
|
||||
CPU[| 0.5%] Tasks: 48, 5 thr; 1 running
|
||||
Mem[||||||||||||||||||||||||||||||||||||||||||||||||||| 165/1828MB] Load average: 0.10 0.05 0.01
|
||||
Swp[ 0/2047MB] Uptime: 21 days, 05:52:35
|
||||
|
||||
PID USER PRI NI VIRT RES SHR S CPU% MEM% TIME+ Command
|
||||
29166 root 20 0 110M 2484 1240 R 0.0 0.1 0:00.03 htop
|
||||
29580 root 20 0 11464 3500 1032 S 0.0 0.2 55:15.97 /bin/sh ./OSWatcher.sh 10 1
|
||||
1 root 20 0 19340 1492 1172 S 0.0 0.1 0:01.04 /sbin/init
|
||||
486 root 16 -4 10780 900 348 S 0.0 0.0 0:00.07 /sbin/udevd -d
|
||||
748 root 18 -2 10780 932 360 S 0.0 0.0 0:00.00 /sbin/udevd -d
|
||||
```
|
||||
|
||||
### 方法 9:使用 glances 命令
|
||||
|
||||
`glances` 是一个跨平台的基于 curses 库的监控工具,它是使用 python 编写的。可以说它非常强大,仅用一点空间就能获得很多信息。它使用 psutil 库从系统中获取信息。
|
||||
|
||||
`glances` 可以监控 CPU、内存、负载、进程、网络接口、磁盘 I/O、<ruby>磁盘阵列<rt>RAID</rt></ruby>、传感器、文件系统(与文件夹)、容器、监视器、Alert 日志、系统信息、运行时间、<ruby>快速查看<rt>Quicklook</rt></ruby>(CPU,内存、负载)等。
|
||||
|
||||
**推荐阅读:** [Glances (集大成)– Linux 上高级的实时系统运行监控工具][3]
|
||||
|
||||
```
|
||||
glances
|
||||
|
||||
ubuntu (Ubuntu 17.10 64bit / Linux 4.13.0-37-generic) - IP 192.168.1.6/24 Uptime: 21 days, 05:55:15
|
||||
|
||||
CPU [|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 90.6%] CPU - 90.6% nice: 0.0% ctx_sw: 4K MEM \ 78.4% active: 942M SWAP - 5.9% LOAD 2-core
|
||||
MEM [||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 78.0%] user: 55.1% irq: 0.0% inter: 1797 total: 1.95G inactive: 562M total: 12.4G 1 min: 4.35
|
||||
SWAP [|||| 5.9%] system: 32.4% iowait: 1.8% sw_int: 897 used: 1.53G buffers: 14.8M used: 749M 5 min: 4.38
|
||||
idle: 7.6% steal: 0.0% free: 431M cached: 273M free: 11.7G 15 min: 3.38
|
||||
|
||||
NETWORK Rx/s Tx/s TASKS 211 (735 thr), 4 run, 207 slp, 0 oth sorted automatically by memory_percent, flat view
|
||||
docker0 0b 232b
|
||||
enp0s3 12Kb 4Kb Systemd 7 Services loaded: 197 active: 196 failed: 1
|
||||
lo 616b 616b
|
||||
_h478e48e 0b 232b CPU% MEM% VIRT RES PID USER NI S TIME+ R/s W/s Command
|
||||
63.8 18.9 2.33G 377M 2536 daygeek 0 R 5:57.78 0 0 /usr/lib/firefox/firefox -contentproc -childID 1 -isForBrowser -intPrefs 6:50|7:-1|19:0|34:1000|42:20|43:5|44:10|51
|
||||
DefaultGateway 83ms 78.5 10.9 3.46G 217M 2039 daygeek 0 S 21:07.46 0 0 /usr/bin/gnome-shell
|
||||
8.5 10.1 2.32G 201M 2464 daygeek 0 S 8:45.69 0 0 /usr/lib/firefox/firefox -new-window
|
||||
DISK I/O R/s W/s 1.1 8.5 2.19G 170M 2653 daygeek 0 S 2:56.29 0 0 /usr/lib/firefox/firefox -contentproc -childID 4 -isForBrowser -intPrefs 6:50|7:-1|19:0|34:1000|42:20|43:5|44:10|51
|
||||
dm-0 0 0 1.7 7.2 2.15G 143M 2880 daygeek 0 S 7:10.46 0 0 /usr/lib/firefox/firefox -contentproc -childID 6 -isForBrowser -intPrefs 6:50|7:-1|19:0|34:1000|42:20|43:5|44:10|51
|
||||
sda1 9.46M 12K 0.0 4.9 1.78G 97.2M 6125 daygeek 0 S 1:36.57 0 0 /usr/lib/firefox/firefox -contentproc -childID 7 -isForBrowser -intPrefs 6:50|7:-1|19:0|34:1000|42:20|43:5|44:10|51
|
||||
```
|
||||
|
||||
### 方法 10:使用 stat 命令
|
||||
|
||||
`stat` 命令显示指定文件或文件系统的详细状态。
|
||||
|
||||
```
|
||||
# stat /var/log/dmesg | grep Modify
|
||||
Modify: 2018-04-12 02:48:04.027999943 -0400
|
||||
```
|
||||
|
||||
### 方法 11:使用 procinfo 命令
|
||||
|
||||
`procinfo` 从 `/proc` 文件夹下收集一些系统数据并将其很好的格式化输出在标准输出设备上。
|
||||
|
||||
```
|
||||
# procinfo | grep Bootup
|
||||
Bootup: Fri Apr 20 19:40:14 2018 Load average: 0.16 0.05 0.06 1/138 16615
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.2daygeek.com/11-methods-to-find-check-system-server-uptime-in-linux/
|
||||
|
||||
作者:[Magesh Maruthamuthu][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[LuuMing](https://github.com/LuuMing)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.2daygeek.com/author/magesh/
|
||||
[1]:https://www.2daygeek.com/top-command-examples-to-monitor-server-performance/
|
||||
[2]:https://www.2daygeek.com/htop-command-examples-to-monitor-system-resources/
|
||||
[3]:https://www.2daygeek.com/install-glances-advanced-real-time-linux-system-performance-monitoring-tool-on-centos-fedora-ubuntu-debian-opensuse-arch-linux/
|
67
published/20180507 Modularity in Fedora 28 Server Edition.md
Normal file
67
published/20180507 Modularity in Fedora 28 Server Edition.md
Normal file
@ -0,0 +1,67 @@
|
||||
Fedora 28 服务器版的模块化
|
||||
========
|
||||
|
||||

|
||||
|
||||
### 什么是模块化
|
||||
|
||||
所有开源发行版都面临的一个经典难题是“太快/太慢”的问题。用户安装操作系统是为了能够使用其应用程序。像 Fedora 这样的全面的发行版在大量可用软件方面有其优势和劣势。虽然有用户想要的软件包,但可能无法使用其所需的版本。以下是<ruby>模块化<rt>Modularity</rt></ruby>如何帮助解决该问题。
|
||||
|
||||
对于某些用户,Fedora 有时升级得太快。其快速发布周期以及尽可能提供最新稳定软件的愿望可能导致与应用程序的兼容性下降。如果因为 Fedora 将 Web 框架升级为不兼容的版本而导致用户无法运行 Web 应用程序,则会非常令人沮丧。对“太快”问题的经典回答是“Fedora 应该有一个 LTS 版本。”然而,这种方法只能解决问题的一半,并使这个难题的另一面变得更糟。
|
||||
|
||||
有时候 Fedora 对某些用户而言又升级速度太慢。例如,Fedora 的发布可能与其它想要的软件的发布时间不匹配。一旦 Fedora 版本宣布稳定,打包者必须遵守 [稳定更新政策][1] 并且不能在系统中引入不兼容的更改。
|
||||
|
||||
Fedora 的模块化从两个方面解决了这个问题。Fedora 仍将根据其传统政策发布标准版本。但是,它还将提供一组模块给出流行软件的限定替代版本。那些处于“太快”阵营的人仍然可以享受 Fedora 的新内核和其它通用平台增强功能。此外,他们仍然可以访问支持其应用程序的旧框架或工具链。
|
||||
|
||||
此外,那些喜欢更新潮一些的用户可以访问比发布时更新的软件。
|
||||
|
||||
### 模块化不是什么?
|
||||
|
||||
模块化不是 <ruby>[软件集合][2]<rt>Software Collections</rt></ruby> 的直接替代品。这两种技术试图解决许多相同的问题,但有明显的差异。
|
||||
|
||||
软件集合可以在系统上并行安装不同版本的软件包。但是,它们的缺点是每份安装包都存在于文件系统上的它们自己的命名空间里面。此外,需要告诉每个依赖它们的应用程序在哪里找到它们。
|
||||
|
||||
使用模块化,系统上只存在一个版本的软件包,但用户可以选择哪个版本。优点是该版本位于系统的标准位置。该程序包不需要对依赖它的应用程序进行特殊更改。来自用户研究的反馈表明,大多数用户实际上并不依赖于并行安装。容器化和虚拟化解决了这个问题。
|
||||
|
||||
### 为什么不干脆使用容器化?
|
||||
|
||||
这是另一个常见问题。为什么用户在可以使用容器时还需要模块?答案是,人们仍然需要维护容器中的软件。 模块为那些用户不需要自己维护、更新和修补的容器提供预打包的内容。这就是 Fedora 如何利用发行版的传统价值并将其转移到新的容器化的世界。
|
||||
|
||||
以下是模块化如何为 Node.js 和 Review Board 的用户解决问题的示例。
|
||||
|
||||
### Node.js
|
||||
|
||||
许多读者可能熟悉 Node.js,这是一个流行的服务器端 JavaScript 运行时环境。Node.js 采用偶数/奇数版本策略。它的社区支持偶数版本(6.x、8.x、10.x 等)约 30 个月。同时,他们也支持奇数版本,基本上是 9 个月的开发者预览版。
|
||||
|
||||
由于这个周期的原因,Fedora 在其稳定的仓库中只携带最新的偶数版本的 Node.js。它完全避免了奇数版本,因为它们的生命周期比 Fedora 短,并且通常与 Fedora 发布周期不一致。对于一些希望获得最新和最大增强功能的 Fedora 用户来说,这并不合适。
|
||||
|
||||
由于模块化,Fedora 28 不是提供了一个版本,而是提供了三个版本的 Node.js,以满足开发人员和稳定部署的需求。Fedora 28 的传统仓库带有 Node.js 8.x。此版本是发布时最新的长期稳定版本。模块仓库(默认情况下在 Fedora 28 Server 版本上可用)也使得更旧的 Node.js 6.x 版本和更新的 Node.js 9.x 开发版本可用。
|
||||
|
||||
另外,Node.js 在 Fedora 28 之后几天发布了 10.x 上游版本。过去,想要部署该版本的用户必须等到 Fedora 29,或者使用来自 Fedora 之外的源代码。但是,再次感谢模块化,Node.js 10.x 已经在 Fedora 28 的 Modular Updates-Testing 仓库中 [可用][3] 了。
|
||||
|
||||
### Review Board
|
||||
|
||||
Review Board 是一个流行的 Django 应用程序,用于执行代码审查。Fedora 从 Fedora 13 到 Fedora 21 都包括了 Review Board。此时,Fedora 转移到了 Django 1.7。由于 Django 数据库支持的向后兼容性在不断变化,而 Review Board 无法跟上。它在 RHEL / CentOS 7 的 EPEL 仓库中仍然存在,而仅仅是因为这些发行版的版本幸运地被冻结在 Django 1.6上。尽管如此,它在 Fedora 的时代显然已经过去了。
|
||||
|
||||
然而,随着模块化的出现,Fedora 能够再次将旧的 Django 作为非默认模块流发布。因此,Review Board 已作为一个模块在 Fedora 上恢复了。Fedora 承载了来自上游的两个受支持的版本:2.5.x 和 3.0.x。
|
||||
|
||||
### 组合在一起
|
||||
|
||||
Fedora 一直为用户提供非常广泛的软件使用。Fedora 模块化现在为他们所需的软件版本提供了更深入的选择。接下来的几年对于 Fedora 来说将是非常令人兴奋的,因为开发人员和用户可以以新的和令人兴奋的(或旧的和令人兴奋的)方式组合他们的软件。
|
||||
|
||||
------
|
||||
|
||||
via: https://fedoramagazine.org/working-modules-fedora-28/
|
||||
|
||||
作者:[Stephen Gallagher][a]
|
||||
选题:[wxy](https://github.com/wxy)
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://fedoramagazine.org/author/sgallagh/
|
||||
[1]: https://fedoraproject.org/wiki/Updates_Policy#Stable_Releases
|
||||
[2]: https://www.softwarecollections.org/
|
||||
[3]: https://bodhi.fedoraproject.org/updates/FEDORA-MODULAR-2018-2b0846cb86
|
||||
|
111
published/20180604 4 Firefox extensions worth checking out.md
Normal file
111
published/20180604 4 Firefox extensions worth checking out.md
Normal file
@ -0,0 +1,111 @@
|
||||
4 个值得一提的 Firefox 扩展插件
|
||||
======
|
||||
|
||||
> 这些扩展可以使火狐更具生产力和使用乐趣。
|
||||
|
||||

|
||||
|
||||
自从大约 12 年前 Firefox(火狐浏览器)v2.0 推出以来, 我一直是它的用户。它不是那时最好的网络浏览器,但是总会有一个理由让我回到它:我最喜爱的浏览器扩展插件不能工作在其它浏览器上。
|
||||
|
||||
如今,我喜欢现下的 Firefox,因为它快速、可定制和开源,我也很欣赏那些体现了原开发人员从未想到过的想法的扩展插件:如果你想在没有鼠标的情况下浏览网页呢?如果你不喜欢盯着晚上从显示器里发出来的强光呢?如何在 YouTube 和其他视频托管网站上使用一个更专业的播放器来获得更好的性能和更多播放控制呢?如果你需要更复杂的方法来禁用跟踪器和加快加载页面,该怎么办?
|
||||
|
||||
幸运的是,这些问题都有答案,我将展现给你我最喜爱的扩展 —— 所有这些都是免费软件或开源的 (即,在 [GNU GPL][1]、[MPL][2] 或 [Apache][3] 许可帧下) ,它们可以使一个优秀的浏览器更优秀。
|
||||
|
||||
尽管术语<ruby>加载项<rt>add-on</rt></ruby>和<ruby>扩展<rt>extension</rt></ruby>的含义稍微不同,但我在本文中的使用不会区分它们。
|
||||
|
||||
### Tridactyl
|
||||
|
||||
![Tridactyl screenshot][5]
|
||||
|
||||
*Tridactyl 的新选项卡页面,展示了链接的指引。*
|
||||
|
||||
[Tridactyl][6] 使你能够在大多数浏览活动中使用键盘。它的灵感来自于现已不复存在的 [Vimperator][7] 和 [Pentadactyl][8],而它们受到了 [Vim][9] 的默认键绑定的启发。由于我已经习惯了 Vim 和其他命令行应用程序,我发现了它的功能类似于使用键值 `h/j/k/l` 进行导航,用 `f/F` 可以与超链接进行交互,而且创建自定义的键绑定和命令非常方便。
|
||||
|
||||
Tridactyl 最近刚刚实现了一个可选的本地信使(目前,仅适用于 GNU/Linux 和 Mac OSX),提供了更酷的功能。例如,有了它,你可以隐藏 Firefox 用户界面上的一些元素(以 Vimperator 和 Pentadactyl 的方式)、在外部程序中打开链接或当前页(我经常用 [mpv][10] 和 [youtube-dl][11] 播放视频)、通过按 `Ctrl-I`(或者任意你选择的组合键)用你喜爱的编辑器来编辑文本框的内容。
|
||||
|
||||
话虽如此,但要记住,这是一个相对早期的项目,细节可能还是很粗糙。另一方面,它的开发非常活跃,当你回顾它早期的缺陷时,未尝不是一种乐趣。
|
||||
|
||||
### Open With
|
||||
|
||||
![Open With Screenshot][13]
|
||||
|
||||
*Open With 提供的菜单。我可以用这里列出的一个外部程序打开当前页面。*
|
||||
|
||||
说到与外部程序的互动,有时能够用鼠标来做到这一点还是让人很高兴的。这是 [Open With][14] 的用武之地。
|
||||
|
||||
除了添加的上下文菜单(如屏幕截图所示)之外,你还可以通过单击加载项栏上的扩展图标来找到自己定义的命令。如[它在 Mozilla Add-ons 页面上][14] 的图标和描述所示,它主要是为了切换到其它的 web 浏览器,但我也可以轻松地将它与 mpv 和 youtube-dl 相配合。
|
||||
|
||||
它也提供了键盘快捷方式,但它们受到了严重限制。可以在扩展设置的下拉列表中选择的组合不超过三种。相反,Tridactyl 允许我将命令分配给几乎任何没有被 Firefox 所阻止的东西。没错,Open With 目前为鼠标而准备的。
|
||||
|
||||
### Stylus
|
||||
|
||||
![Stylus Screenshot][16]
|
||||
|
||||
*在这个屏幕截图中,我刚刚搜索并为当前正在浏览的 Stylus 的网站安装了一个黑暗主题。即使是弹出窗口也可以定制风格(称为 Deepdark Stylus)!*
|
||||
|
||||
[Stylus][17] 是一个用户样式管理器,这意味着可以通过编写自定义 CSS 规则并将其加载到 Stylus 中来更改任何网页的外观。如果你不懂 CSS,在如 [userstyles.org][18] 这样网站上有大量的其他人制作的样式。
|
||||
|
||||
现在,你可能会问,“这不就是 [Stylish][19] 么?” 你是对的!Stylus 是基于 Stylish 的,并提供了更多的改进:它不包含任何远程记录、尊重你的隐私,所有开发都是公开的(尽管 Stylish 仍在积极开发,我一直未能找到最新版本的源代码),而且它还支持 [UserCSS][20]。
|
||||
|
||||
UserCSS 是一种有趣的格式,尤其是对于开发人员来说。我已经为不同的网站写了几种用户样式(主要是黑暗主题,和为了提高可读性的调整),虽然 Stylus 的内部编辑器很好,我还是喜欢用 Neovim 编辑代码。为了做到这样我所需要做的就是用 “.user.css” 作为本地加载文件的后缀名,在 Stylus 里启动 “Live Reload” 选项,只要我在 Neovim 中保存文件就会应用所有的更改。它也支持远程 UserCSS 文件,因此,每当我将更改推送到 GitHub 或任何基于 git 的开发平台时,它们将自动对用户可用。(我提供了指向该文件的原始版本的链接,以便他们可以轻松地访问它。)
|
||||
|
||||
### uMatrix
|
||||
|
||||
![uMatrix Screenshot][22]
|
||||
|
||||
*uMatrix 的用户界面,显示当前访问过的网页的当前规则。*
|
||||
|
||||
Jeremy Garcia 在他发表在 Opensource.com 的[文章][23]中提到了一个优秀的拦截器 uBlock Origin。我想提请大家关注另一个由 [gorhill][24] 开发的扩展插件: uMatrix 。
|
||||
|
||||
[uMatrix][25] 允许你为网页上的某些请求设置拦截规则,可以通过点击该加载项的弹出窗口来切换(在上面的屏幕截图中可以看到)。这些请求的区别在于脚本的类别、脚本发起的请求、cookies、CSS 规则、图像、媒体、帧,和被 uMatrix 标记为“other” 的其它内容。例如,你可以设置全局规则,以便在默认情况下允许所有请求,并将特定的请求添加到黑名单中(更方便的方法),或在默认情况下阻止所有内容,并手动将某些请求列入白名单(更安全的方法)。如果你一直在使用 NoScript 或 RequestPolicy,你可以从它们 [导入][26] 你的白名单规则。
|
||||
|
||||
另外 uMatrix 支持 [hosts 文件][27],可用于阻止来自某些域的请求。不要与 uBlock Origin 所使用的筛选列表混淆,它使用的语法同 Adblock Plus 一样。默认情况下,uMatrix 会通过几个 hosts 文件阻止已知的分发广告、跟踪器和恶意软件的服务器,如果需要,你可以添加更多外部数据源。
|
||||
|
||||
那么你将选择哪一个:uBlock Origin 或 uMatrix ?就个人而言,我在电脑上两个都用,而只在安卓手机上用 uMatrix 。[据 gorhill 所说][28],两者之间存在某种重叠,但它们有不同的目标用户和目地。如果你想要的只是阻止跟踪器和广告的简单方法,uBlock Origine 是更好的选择;另一方面,如果你希望对网页在浏览器中可以执行或不能执行的操作进行精细的控制,即使需要一些时间来进行配置,并且可能会阻止某些网站如预期的工作,uMatrix 也是更好的选择。
|
||||
|
||||
### 结论
|
||||
|
||||
目前,这些是 Firefox 里我最喜欢的扩展。Tridactyl 通过依靠键盘和与外部程序交互,加快了浏览导航速度;Open With 能让我用鼠标在另外一个程序中打开页面;Stylus 是全面的用户样式管理器,对用户和开发人员都很有吸引力;uMatrix 本质上是 Firefox 的防火墙,可以用于过滤未知的请求。
|
||||
|
||||
尽管我基本上只是讨论了这些加载项的好处,但没有一个软件是完美的。如果你喜欢它们中的任何一个,并认为它们的某些方面可以改进,我建议你去它们的 Github 页面,并查看它们的贡献指南。通常情况下,自由开源软件的开发人员是欢迎错误报告和提交请求的。告诉你的朋友或道谢也是帮助开发者的好方法,特别是如果这些开发者是在业余时间从事他们的项目的话。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/6/firefox-open-source-extensions
|
||||
|
||||
作者:[Zsolt Szakács][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[lixinyuxx](https://github.com/lixinyuxx)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/zsolt
|
||||
[1]:https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||
[2]:https://www.mozilla.org/en-US/MPL/
|
||||
[3]:https://www.apache.org/licenses/LICENSE-2.0
|
||||
[4]:/file/398411
|
||||
[5]:https://opensource.com/sites/default/files/uploads/tridactyl.png "Tridactyl's new tab page, showcasing link hinting"
|
||||
[6]:https://addons.mozilla.org/en-US/firefox/addon/tridactyl-vim/
|
||||
[7]:https://github.com/vimperator/vimperator-labs
|
||||
[8]:https://addons.mozilla.org/en-US/firefox/addon/pentadactyl/
|
||||
[9]:https://www.vim.org/
|
||||
[10]:https://mpv.io/
|
||||
[11]:https://rg3.github.io/youtube-dl/index.html
|
||||
[12]:/file/398416
|
||||
[13]:https://opensource.com/sites/default/files/uploads/openwith.png "A context menu provided by Open With. I can open the current page with one of the external programs listed here."
|
||||
[14]:https://addons.mozilla.org/en-US/firefox/addon/open-with/
|
||||
[15]:/file/398421
|
||||
[16]:https://opensource.com/sites/default/files/uploads/stylus.png "In this screenshot, I've just searched for and installed a dark theme for the site I'm currently on with Stylus. Even the popup has custom style (called Deepdark Stylus)!"
|
||||
[17]:https://addons.mozilla.org/en-US/firefox/addon/styl-us/
|
||||
[18]:https://userstyles.org/
|
||||
[19]:https://addons.mozilla.org/en-US/firefox/addon/stylish/
|
||||
[20]:https://github.com/openstyles/stylus/wiki/Usercss
|
||||
[21]:/file/398426
|
||||
[22]:https://opensource.com/sites/default/files/uploads/umatrix.png "The user interface of uMatrix, showing the current rules for the currently visited webpage."
|
||||
[23]:https://opensource.com/article/18/5/firefox-extensions
|
||||
[24]:https://addons.mozilla.org/en-US/firefox/user/gorhill/
|
||||
[25]:https://addons.mozilla.org/en-US/firefox/addon/umatrix
|
||||
[26]:https://github.com/gorhill/uMatrix/wiki/FAQ
|
||||
[27]:https://en.wikipedia.org/wiki/Hosts_(file)
|
||||
[28]:https://github.com/gorhill/uMatrix/issues/32#issuecomment-61372436
|
140
published/20180606 Working with modules in Fedora 28.md
Normal file
140
published/20180606 Working with modules in Fedora 28.md
Normal file
@ -0,0 +1,140 @@
|
||||
使用 Fedora 28 中的模块
|
||||
======
|
||||
|
||||

|
||||
|
||||
最近 Fedora Magazine 中题为 [Fedora 28 服务器版的模块化][1]在解释 Fedora 28 中的模块化方面做得很好。它还给出了一些示例模块并解释了它们解决的问题。本文将其中一个模块用于实际应用,包括使用模块安装设置 Review Board 3.0。
|
||||
|
||||
### 入门
|
||||
|
||||
想要继续并使用模块,你需要一个 [Fedora 28 服务器版][2]并拥有 [sudo 管理权限][3]。另外,运行此命令以确保系统上的所有软件包都是最新的:
|
||||
|
||||
```
|
||||
sudo dnf -y update
|
||||
```
|
||||
|
||||
虽然你可以在 Fedora 28 非服务器版本上使用模块,但请注意[上一篇文章评论中提到的警告][4]。
|
||||
|
||||
### 检查模块
|
||||
|
||||
首先,看看 Fedora 28 可用的模块。运行以下命令:
|
||||
|
||||
```
|
||||
dnf module list
|
||||
```
|
||||
|
||||
输出列出了一组模块,这些模块显示了每个模块的关联的流、版本和可用安装配置文件。模块流旁边的 `[d]` 表示安装命名模块时使用的默认流。
|
||||
|
||||
输出还显示大多数模块都有名为 `default` 的配置文件。这不是巧合,因为 `default` 是默认配置文件使用的名称。
|
||||
|
||||
要查看所有这些模块的来源,请运行:
|
||||
|
||||
```
|
||||
dnf repolist
|
||||
```
|
||||
|
||||
与通常的 [fedora 和更新包仓库][5]一起,输出还显示了 fedora-modular 和 updates-modular 仓库。
|
||||
|
||||
介绍声明你将设置 Review Board 3.0。也许名为 reviewboard 的模块在之前的输出中引起了你的注意。接下来,要获取有关该模块的一些详细信息,请运行以下命令:
|
||||
|
||||
```
|
||||
dnf module info reviewboard
|
||||
```
|
||||
|
||||
根据描述确认它是 Review Board 模块,但也说明是 2.5 的流。然而你想要 3.0 的。查看可用的 reviewboard 模块:
|
||||
|
||||
```
|
||||
dnf module list reviewboard
|
||||
```
|
||||
|
||||
2.5 旁边的 `[d]` 表示它被配置为 reviewboard 的默认流。因此,请明确你想要的流:
|
||||
|
||||
```
|
||||
dnf module info reviewboard:3.0
|
||||
```
|
||||
|
||||
有关 reviewboard:3.0 模块的更多详细信息,请添加详细选项:
|
||||
|
||||
```
|
||||
dnf module info reviewboard:3.0 -v
|
||||
```
|
||||
|
||||
### 安装 Review Board 3.0 模块
|
||||
|
||||
现在你已经跟踪了所需的模块,请使用以下命令安装它:
|
||||
|
||||
```
|
||||
sudo dnf -y module install reviewboard:3.0
|
||||
```
|
||||
|
||||
输出显示已安装 ReviewBoard 以及其他几个依赖软件包,其中包括 django:1.6 模块中的几个软件包。安装还启用了 reviewboard:3.0 模块和相关的 django:1.6 模块。
|
||||
|
||||
接下来,要查看已启用的模块,请使用以下命令:
|
||||
|
||||
```
|
||||
dnf module list --enabled
|
||||
```
|
||||
|
||||
输出中,`[e]` 表示已启用的流,`[i]` 表示已安装的配置。对于 reviewboard:3.0 模块,已安装默认配置。你可以在安装模块时指定其他配置。实际上,你仍然可以安装它,而且这次你不需要指定 3.0,因为它已经启用:
|
||||
|
||||
```
|
||||
sudo dnf -y module install reviewboard/server
|
||||
```
|
||||
|
||||
但是,安装 reviewboard:3.0/server 配置非常平常。reviewboard:3.0 模块的服务器配置与默认配置文件相同 —— 因此无需安装。
|
||||
|
||||
### 启动 Review Board 网站
|
||||
|
||||
现在已经安装了 Review Board 3.0 模块及其相关软件包,[创建一个本地运行的 Review Board 网站][6]。无需解释,请复制并粘贴以下命令:
|
||||
|
||||
```
|
||||
sudo rb-site install --noinput \
|
||||
--domain-name=localhost --db-type=sqlite3 \
|
||||
--db-name=/var/www/rev.local/data/reviewboard.db \
|
||||
--admin-user=rbadmin --admin-password=secret \
|
||||
/var/www/rev.local
|
||||
sudo chown -R apache /var/www/rev.local/htdocs/media/uploaded \
|
||||
/var/www/rev.local/data
|
||||
sudo ln -s /var/www/rev.local/conf/apache-wsgi.conf \
|
||||
/etc/httpd/conf.d/reviewboard-localhost.conf
|
||||
sudo setsebool -P httpd_can_sendmail=1 httpd_can_network_connect=1 \
|
||||
httpd_can_network_memcache=1 httpd_unified=1
|
||||
sudo systemctl enable --now httpd
|
||||
```
|
||||
|
||||
现在启动系统中的 Web 浏览器,打开 <http://localhost>,然后享受全新的 Review Board 网站!要以 Review Board 管理员身份登录,请使用上面 `rb-site` 命令中的用户 ID 和密码。
|
||||
|
||||
### 模块清理
|
||||
|
||||
完成后清理是个好习惯。为此,删除 Review Board 模块和站点目录:
|
||||
|
||||
```
|
||||
sudo dnf -y module remove reviewboard:3.0
|
||||
sudo rm -rf /var/www/rev.local
|
||||
```
|
||||
|
||||
### 总结
|
||||
|
||||
现在你已经探索了如何检测和管理 Review Board 模块,那么去体验 Fedora 28 中提供的其他模块吧。
|
||||
|
||||
在 [Fedora 模块化][7]网站上了解有关在 Fedora 28 中使用模块的更多信息。dnf 手册页中的 module 命令部分也包含了有用的信息。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/working-modules-fedora-28/
|
||||
|
||||
作者:[Merlin Mathesius][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://fedoramagazine.org/author/merlinm/
|
||||
[1]:https://linux.cn/article-10479-1.html
|
||||
[2]:https://getfedora.org/server/
|
||||
[3]:https://fedoramagazine.org/howto-use-sudo/
|
||||
[4]:https://fedoramagazine.org/modularity-fedora-28-server-edition/#comment-476696
|
||||
[5]:https://fedoraproject.org/wiki/Repositories
|
||||
[6]:https://www.reviewboard.org/docs/manual/dev/admin/installation/creating-sites/
|
||||
[7]:https://docs.pagure.org/modularity/
|
@ -0,0 +1,86 @@
|
||||
使用 Xfce Linux 桌面环境的 8 个理由
|
||||
============================
|
||||
> 整体上很优雅的 Xfce 桌面所具备的足够轻巧和快速的特性能够让它很容易地知道如何做好一件事。
|
||||
|
||||

|
||||
|
||||
由于某些原因(也包括好奇),几周前我开始使用 [Xfce][1] 作为我的 Linux 桌面。促使我更换 Linux 桌面环境的原因之一是桌面相关的守护进程占据了我的性能非常强大的主工作站的绝大部分 CPU 资源和 I/O 带宽。当然,有些不稳定性可能是因为我删除了提供这些守护进程的 RPM 包。然而,事实是在我删除这些 RPM 包之前,KDE 就已经很不稳定了而且还导致了一系列其他方面的性能和稳定性问题。所以我需要换一个桌面来避免这些问题。
|
||||
|
||||
在回顾了我为 Linux 桌面所写的一系列文章后我才意识到我忽略了 Xfce。这篇文章也是力图能够纠正弥补这个疏忽。我非常喜欢 Xfce 也很享受它所带给我超乎预期的快速、轻量的体验。
|
||||
|
||||
作为研究的一部分,我有尝试过在 Google 上查询 Xfce 对应什么意思。有个历史参考是它对应着 “XForms Common Environment”,但 Xfce 早已不在使用 XForms 工具。几年前,我找到另一个参考是 “Xtra fine computing environment” 而且我也很喜欢这个解释。我将会用它作为 Xfce 的全称(尽管再也找不到这个参考页面)。
|
||||
|
||||
### 推荐 Xfce 的 8 个理由
|
||||
|
||||
#### 1、轻量级架构
|
||||
|
||||
Xfce 相对于其他的桌面如 KDE 和 GNOME,不管是内存还是 CPU 的占用率都非常小。在我的系统中,组成 Xfce 桌面的程序仅占用了少量内存就构成一个如此强大的桌面。超低的 CPU 占用率也是 Xfce 桌面的一个特点。了解到 Xfce 内存占用特别低后,我对它的 CPU 占用率也非常低这个特性自然而言也就不感到奇怪了。
|
||||
|
||||
#### 2、简洁
|
||||
|
||||
Xfce 桌面很简单,就像绒毛整洁的动物让人一目了然、赏心悦目。基础的桌面有两个面板和一条在左边垂直的图标行。面板 0 在底部,并由一些基础的应用启动程序和能访问到系统里对应程序的图标组成。面板 1 在顶部,由一个应用程序启动器和一个能够允许用户在多个工作区之间来回切换的工作区切换器组成。面板可以通过补充项自定义修改,比如增加个新的应用启动器或者更改它们的宽高。
|
||||
|
||||
桌面左侧的图标对应是家目录和垃圾桶。它也可以显示其他的图标,如完整的文件系统目录树和已连接上系统的可插拔的任意 USB 存储设备。这些图标可以用来挂载和卸载设备,也可以用来打开默认的文件管理器。如果你愿意,它们都可以被隐藏,同时文件系统、垃圾箱、家目录对应的图标都可以逐个控制管理。所有的可移动设备也可以被隐藏或作为一个组显示。
|
||||
|
||||
#### 3、文件管理
|
||||
|
||||
作为 Xfce 的默认文件管理器 Thunar,它很简单,既易于使用和配置也非常容易学习。尽管它并不像其他的文件管理器比如 Konqueror 或者 Dolphin 那样效果华丽,但它很强大也很快。Thunar 并不能在一个窗口里面打开多个面板,但它提供了选项卡来支持多个目录的同时打开。Thunar 也有一个非常漂亮的侧边栏,其上同样的图标就像桌面那样能够显示完整的文件系统目录树和所有已连接的 USB 存储设备。设备能够被挂载和卸载,可移动媒介如 CD 也能够被弹出。Thunar 也可以使用类似 Ark 这种帮助软件来在你点击归档文件的时候打开它们。比如 ZIP、TAR、RPM 这种归档文件都可以被浏览也可以从中复制单个文件。
|
||||
|
||||
![Xfce desktop][3]
|
||||
|
||||
*Xfce 桌面及 Thunar 和 Xfce 下的终端模拟器。*
|
||||
|
||||
在我的[文件管理器系列][4]文章中,我已经使用体验过很多不同的文件管理器软件,我不得不说 Thunar 的简单易用让你无法不喜欢上它。它可以让你通过使用侧边栏来很容易地浏览文件系统。
|
||||
|
||||
#### 4、稳定
|
||||
|
||||
Xfce 桌面非常稳定。新版本的发布周期似乎是三年,但也会根据需要发布相关更新。最新的版本是于 2015 年 2 月发布的 4.12。在使用 KDE 遇到一系列问题后,稳如磐石的 Xfce 桌面环境显得让人格外放心。在我使用 Xfce 的过程中,它从来没有崩溃过,也不会产生额外的守护进程占据过多的系统资源。这正是我想要的:它安安静静地工作,不会给你带来额外的困扰。
|
||||
|
||||
#### 5、优雅
|
||||
|
||||
Xfce 简单优雅。在我的今年秋天将面世的新书《系统管理员的 Linux 哲学》中我谈到了关于简单的一系列好处,包括简单事实上也是优雅的诸多标志之一。很明确能够确定的就是 Xfce 及相关组件程序的开发者和维护者也是极力推崇简单至上。这种简单特性很可能也是 Xfce 如此稳定的主要原因,但它也给用户带来了一个整洁的桌面外观,一个反应灵敏的操作界面,一个会让人感觉很自然也很易用的导航结构,而且 Xfce 整体上的优雅特性也会让用户的使用过程中充满愉悦感。
|
||||
|
||||
#### 6、终端仿真程序
|
||||
|
||||
Xfce4 的终端仿真程序非常强大,而且和其他很多终端仿真程序一样可以允许你使用多个选项卡来让多个终端在一个单独窗口里共存。尽管它与 Tilix、Terminator、Konsole 这种终端仿真程序比起来相对简陋,但它也能很好的完成工作。选项卡的名字可以更改,而且选项卡也可以通过拖放或者工具栏的箭头图标或者菜单栏的选项重新排列。我特别喜欢 Xfce 的终端仿真程序的一点就是不管你连接了多少主机,相对应的选项卡都会显示对应的主机名,比如,从 host1=>host2=>host3=>host4,会准确地在选项卡显示了 “host4”。但其他的终端仿真程序最多也就显示 “host2”。
|
||||
|
||||
至于这个终端仿真程序功能和外观的其他方面都可以根据你的需要很容易配置成你想要的。当然同 Xfce 的其他组件一样,这款终端仿真程序占用了系统资源的很少一部分。
|
||||
|
||||
#### 7、可配置性
|
||||
|
||||
Xfce 能够配置的范围极大。虽然 Xfce 桌面的可配置性比不上 KDE,但依旧远超 GNOME,而且比它更容易配置。比如,我发现设置管理器是 Xfce 配置一切的入口。虽然每个配置程序都可以单独使用,但是设置管理器把他们都放在一个窗口里以便快速访问。关于 Xfce 桌面很多重要的部分都可以通过配置来满足我的需求。
|
||||
|
||||
#### 8、模块化
|
||||
|
||||
Xfce 是由一系列单个的项目组成的整体,而且在你的 Linux 桌面发行版中也未必安装了 Xfce 的所有组件。[Xfce 项目][5] 的主页列出了主要的项目,所以你可以根据需要安装你想安装的附加组件。比如在我的 Fedora 28 workstation 版本上我安装的 Xfce 组时就没有 [Xfce 项目][5] 主页最下面的说明的一些程序。
|
||||
|
||||
这里还有个关于 Xfce 的 [文档页面][6] 和 一个被称为 [Xfce 超值项目][7] 的 wiki 列举了其他的 Xfce 相关的项目,它们为 Xfce 的面板及 Thunar 提供了很多不错的应用程序、精美的插图、好用的插件。
|
||||
|
||||
### 总结
|
||||
|
||||
整体上很优雅的 Xfce 桌面所具备的足够轻巧和快速的特性能够让它很容易地知道如何做好一件事。它的轻量级的结构也节省了大量的 CPU 和内存资源。这也使得 Xfce 非常适合那种由于硬件有限而无法分配给桌面太多资源的旧主机。然而,Xfce 又是足够的灵活和强大的,能够满足高级用户的需要。
|
||||
|
||||
我知道,更换到一个新的 Linux 桌面环境需要你自己按照你想要的做些对应的自定义设置:比如面板上显示你最爱用的程序对应的启动器,设置下你最喜欢的桌面背景壁纸等一系列工作。这些年来我已经在切换到新桌面环境或更新旧桌面环境折腾很多次了。这需要时间也需要耐心。
|
||||
|
||||
我觉得切换 Linux 的桌面环境就像我在工作中换个办公工位或者办公室一样。别人把我的东西装箱从旧办公室搬到新办公室,然后我在我的新办公室里组装连接好我的电脑,打开箱子再把里面的东西放在合适的位置。而切换到 Xfce 桌面大概就是我做过的最简单省事容易的桌面环境更换了。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/6/xfce-desktop
|
||||
|
||||
作者:[David Both][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[WangYueScream](https://github.com/WangYueScream)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/dboth
|
||||
[1]:https://xfce.org/
|
||||
[2]:/file/401856
|
||||
[3]:https://opensource.com/sites/default/files/uploads/xfce-desktop-01.png (Xfce desktop)
|
||||
[4]:https://opensource.com/sitewide-search?search_api_views_fulltext=David%20Both%20File%20managers
|
||||
[5]:https://xfce.org/projects
|
||||
[6]:https://docs.xfce.org/
|
||||
[7]:https://goodies.xfce.org/
|
69
published/20180625 The life cycle of a software bug.md
Normal file
69
published/20180625 The life cycle of a software bug.md
Normal file
@ -0,0 +1,69 @@
|
||||
软件 bug 的生命周期
|
||||
======
|
||||
|
||||
> 从发现软件故障到解决它们,这里讲述是开发团队如何压制软件 bug。
|
||||
|
||||

|
||||
|
||||
1947 年,发现了第一个计算机 bug —— 被困在计算机继电器中的飞蛾。
|
||||
|
||||
要是所有的 bug 都能如此简单地发现就好了。随着软件变得越来越复杂,测试和调试的过程也变得更加复杂。如今,软件 bug 的生命周期可能会很长,尽管正确的技术和业务流程可能会有所帮助。对于开源软件,开发人员使用严格的工单服务和协作来查找和解决 bug。
|
||||
|
||||
### 确认计算机 bug
|
||||
|
||||
在测试过程中,发现的 bug 会报告给开发团队。质量保证测试人员尽可能详细地描述 bug ,报告他们的系统状态、他们正在进行的过程以及 bug 是如何表现出来的。
|
||||
|
||||
尽管如此,一些 bug 从未得到确认;它们可能会在测试中报告,但永远无法在可控环境中重现。在这种情况下,它们可能得不到解决,而是被关闭。
|
||||
|
||||
有些计算机 bug 可能很难确认,因为使用的平台种类繁多,用户行为也非常多。有些 bug 只是间歇性地或在非常特殊的情况下发生的,而另一些 bug 可能会出现在随机的情况下。
|
||||
|
||||
许多人使用开源软件并与之交互,许多 bug 和问题可能是不可重复的,或者可能没有得到充分的描述。不过,由于每个用户和开发人员也都扮演质量保证测试人员的角色,至少在一定程度上,bug 还是很有可能会发现的。
|
||||
|
||||
确认 bug 后,修复工作就开始了。
|
||||
|
||||
### 分配要修复的 bug
|
||||
|
||||
已确认的 bug 被分配给负责解决的开发人员或开发团队。在此阶段,需要重现 bug,发现问题,并修复相关代码。如果 bug 的优先级较低,开发人员可以将此 bug 分类为稍后要修复的问题,也可以在该 bug 具有高优先级的情况下直接指派某人修复。无论哪种方式,都会在开发过程中打开一个工单,并且 bug 将成为已知的问题。
|
||||
|
||||
在开源解决方案中,开发人员可以进行选择他们想要解决的 bug,要么选择他们最熟悉的程序区域,要么从优先级最高的的开始。综合解决方案,如 [GitHub][1] 使得多个开发人员能够轻松地着手解决,而不会干扰彼此的工作。
|
||||
|
||||
当将 bug 设置为需要修复时,bug 报告者还可以为该 bug 选择优先级。主要的 bug 可能具有较高的优先级,而仅与外观相关的 bug 可能具有较低的级别。优先级确定开发团队解决这些问题的方式和时间。无论哪种方式,所有的 bug 都需要先解决,然后才能认为产品已完成。在这方面,适当的回溯到优先级高的需求也会很有帮助。
|
||||
|
||||
### 解决 bug
|
||||
|
||||
一旦修复了 bug ,通常会将其作为已解决的 bug 发送回质量保证测试人员。然后,质量保证测试人员再次将产品置于其工作中,以重现 bug。如果无法重现 bug ,质量保证测验人员将假定它已得到适当解决。
|
||||
|
||||
在开源情况下,任何更改都会被分发,通常是作为正在测试的暂定版本。此测试版本分发给用户,用户再次履行质量保证测试人员的职责并测试产品。
|
||||
|
||||
如果 bug 再次出现,问题将被发送回开发团队。在此阶段,该 bug 将重新触发,开发团队有责任重复解决该 bug 的循环。这种情况可能会发生多次,尤其是在 bug 不可预知或间歇性发生的情况下。众所周知,间歇性的 bug 很难解决。
|
||||
|
||||
如果该 bug 不再出现,则该问题将被标记为已解决。在某些情况下,最初的 bug 得到了解决,但由于所做的更改,会出现其他 bug。发生这种情况时,可能需要新的 bug 报告,然后重新开始该过程。
|
||||
|
||||
### 关闭 bug
|
||||
|
||||
在处理、识别和解决 bug 后,该 bug 将被关闭,开发人员可以转到软件开发和测试的其他阶段。如果始终找不到 bug ,或者开发人员无法重现 bug ,则该 bug 也将被关闭 —— 无论哪种方式,都将开始开发和测试的下一阶段。
|
||||
|
||||
在测试版本中对解决方案所做的任何更改都将滚动到产品的下一个版本中。如果 bug 是严重的,则在下一个版本发布之前,可能会为当前用户提供修补程序或修补程序。这在安全问题中很常见。
|
||||
|
||||
软件 bug 可能很难找到,但通过遵循过程,开发人员可以使开发更快、更容易、更一致。质量保证是这一过程的重要组成部分,因为质量保证测试人员必须发现和识别 bug ,并帮助开发人员重现这些 bug 。在 bug 不再发生之前,无法关闭和解决 bug。
|
||||
|
||||
开源的解决方案分散了质量保证测试、开发和缓解的负担,这往往导致 bug 被更快、更全面地发现和缓解。但是,由于开源技术的性质,此过程的速度和准确性通常取决于解决方案的受欢迎程度及其维护和开发团队的敬业精神。
|
||||
|
||||
Rich Butkevic 是一个 PMP 项目经理认证,,敏捷开发框架认证(certified scrum master) 并且 维护 [Project Zendo][2],这是供项目管理专业人员去发现、简化和改进其项目成果策略的网站。可以在 [Richbutkevic.com][3] 或者使用 [LinkedIn][4] 与 Rich 联系。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/6/life-cycle-software-bug
|
||||
|
||||
作者:[Rich Butkevic][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[lixinyuxx](https://github.com/lixinyuxx)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/rich-butkevic
|
||||
[1]:https://github.com/
|
||||
[2]:https://projectzendo.com
|
||||
[3]:https://richbutkevic.com
|
||||
[4]:https://www.linkedin.com/in/richbutkevic
|
@ -0,0 +1,99 @@
|
||||
10 个供管理员救急的杀手级工具
|
||||
======
|
||||
|
||||
> 可以让你赶快离开办公室的网络管理技巧和工具。
|
||||
|
||||

|
||||
|
||||
当工作任务堆积成山时,管理网络和系统就变得十分有压力了。没有人能真正意识到需要花费多长时间,每个人都希望在昨天就完成他们的工作。
|
||||
|
||||
所以难怪我们这么多人都被致力于找出有效的方法并与大家分享的开源精神所吸引。因为,当截止日期来临,并且当天没有足够多的时间时,如果你可以找到立刻施行的免费答案,那会非常有帮助。
|
||||
|
||||
因此,闲话少叙,下述是我的瑞士军刀,可以保证你在晚饭前离开办公室。
|
||||
|
||||
### 服务器配置和脚本
|
||||
|
||||
让我们看一看!
|
||||
|
||||
- [NixCraft][1]
|
||||
|
||||
使用该网站的搜索功能。经过十多年的定期更新,这里遍地是黄金!有用的脚本和方便的技巧可以立刻解决你的问题。这是我一般使用 Google 后的第二个选项。
|
||||
|
||||
- [Webmin][2]
|
||||
|
||||
它提供给你了一个很好的 Web 界面来帮助你远程编辑配置文件。它减少了在处理目录路径和 `sudo nano` 上花费的大量时间,在你处理多个客户时,非常方便。
|
||||
|
||||
- [Windows 下的 Linux 子系统][3]
|
||||
|
||||
现代工作场所的现实是大多数员工都运行着 Windows,而服务器机房中不断增长的设备则运行着 Linux 。因此,有些时候你会发现尝试在 Windows 桌面上执行管理任务。
|
||||
|
||||
你怎么做?装一个虚拟机?如果安装目前 Windows 10 中免费提供的 Linux 子系统的兼容层,实际上要快得多,配置要少的多。
|
||||
|
||||
这为你提供了一个 Bash 终端窗口,你可以在这个窗口中执行本地计算机上的 Bash 脚本和 Linux 二进制文件,可以完全访问 Windows 和 Linux 文件系统,以及安装网络驱动器。它包含 Ubuntu 、OpenSUSE、SLES、Debian 和 Kali 发行版。
|
||||
|
||||
- [mRemoteNG][4]
|
||||
|
||||
当你有 100 多个服务器需要去管理时,这会是一个出色的 SSH 和远程桌面客户端。
|
||||
|
||||
### 设置网络,这样你就无需再这样做了。
|
||||
|
||||
一个设计不周的网络是厌恶加班的管理员的死敌。
|
||||
|
||||
- [可拓展的 IP 寻址方案][5]
|
||||
|
||||
IP 地址耗尽的可怕之处在于,当 IP 地址耗尽时,网络已经变的足够大,而新的寻址方案是众所周知的昂贵、令人痛苦的耗时。
|
||||
|
||||
没有人有时间做这件事!
|
||||
|
||||
到了某个时候,IPv6 终将到来,来拯救这世界。但在那之前,无论世界向我们扔了多少可穿戴设备、平板电脑、智能锁、灯、安全摄像头、VoIP 耳机和浓缩咖啡机,这些以不变应万变的 IP 寻址方案都应该让我们继续前行。
|
||||
|
||||
- [Linux Chmod 权限备忘录][6]
|
||||
|
||||
一个简短但是有用的 Bash 命令备忘录可以帮助你通过网络设置权限。所以,客户服务部的账单落入到勒索软件骗局时,你可以只恢复他们的文件,而不是整个公司的文件。
|
||||
|
||||
- [VLSM 子网计算器][7]
|
||||
|
||||
只需要输入你想要从地址空间中创建的网络的数量,以及每个网络所需要的主机数量,它就可以计算出所有的子网掩码应该是什么。
|
||||
|
||||
### 单一用途的 Linux 发行版
|
||||
|
||||
需要一个只做一件事的 Linux 容器?如果其他人已经在一个操作系统上搞好了一个小东西,你就可以快速安装它并马上投入使用。
|
||||
|
||||
下面这些每一个都使得我的工作变得轻松了许多。
|
||||
|
||||
- [Porteus Kiosk][8]
|
||||
|
||||
这个工具用来帮你把一台电脑上锁定到一个浏览器上。通过稍稍一些调整,你甚至可以把浏览器锁定在一个特定的网站上。它对于公共访问机器来说非常方便。它可以与触摸屏或键盘鼠标配合使用。
|
||||
|
||||
- [Parted Magic][9]
|
||||
|
||||
这是一个你可以从 USB 驱动器启动的,可以用来划分磁盘驱动器、恢复数据并运行基准测试工具的操作系统。
|
||||
|
||||
- [IPFire][10]
|
||||
|
||||
啊哈~我还是不敢相信有人把路由器/防火墙/代理组合成为“我尿火”(LCTT 译注:IPFire 和 “I pee Fire“ 同音)。这是我在这个 Linux 发行版中第二喜欢的东西。我最喜欢的是它是一个非常可靠的软件套件,设置和配置十分容易,而且有一系列的插件可以拓展它。
|
||||
|
||||
那么,你呢?你发现了哪些工具、资源和备忘录可以让我们的工作日更加的轻松?我很高兴知道,请在评论中分享您的工具。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/7/tools-admin
|
||||
|
||||
作者:[Grant Hamono][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[bestony](https://github.com/bestony)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/grantdxm
|
||||
[1]:https://www.cyberciti.biz/
|
||||
[2]:http://www.webmin.com/
|
||||
[3]:http://wsl-guide.org/en/latest/
|
||||
[4]:https://mremoteng.org/
|
||||
[5]:https://blog.dxmtechsupport.com.au/ip-addressing-for-a-small-business-that-might-grow/
|
||||
[6]:https://isabelcastillo.com/linux-chmod-permissions-cheat-sheet
|
||||
[7]:http://www.vlsm-calc.net/
|
||||
[8]:http://porteus-kiosk.org/
|
||||
[9]:https://partedmagic.com/
|
||||
[10]:https://www.ipfire.org/
|
140
published/20180722 Dawn of the Microcomputer- The Altair 8800.md
Normal file
140
published/20180722 Dawn of the Microcomputer- The Altair 8800.md
Normal file
@ -0,0 +1,140 @@
|
||||
微型计算机的始祖:Altair 8800
|
||||
======
|
||||
|
||||
《<ruby>大众电子<rt>Popular Electronics</rt></ruby>》的订阅者们是个复杂的群体,该杂志的编辑 Arthur Salsberg 不得不在 [1974 年 12 月刊][1] 中的前言部分指出这点。此前,杂志编辑组曾收到了对《如何搭建家庭媒体中心》文章的抱怨,称这篇文章激励了许多业余电视爱好者走出去,削弱了专业修理人员存在的必要性,这对许多人的电视造成了极大伤害。Salsberg 认为,这个担忧的产生可能是因为大家不清楚《大众电子》读者们的真实水平。他解释道,据杂志内部调查的数据显示,52% 的订阅者都是某方面的电子专家,并且其中的 150,000 人在最近 60 天之内都修过电视。此外,订阅者们平均在电子产品上花费了 470 美金(2018 年则是 3578 美金),并且他们拥有万用表、真空管伏特计、电子管测试仪、晶体管测试仪、射频讯号产生器和示波器等必要设备。“《大众电子》的读者们并不全都是新手。”Salsberg 总结道。
|
||||
|
||||
熟悉《大众电子》的人居然会质疑它的订阅者,这令我十分吃惊。不过最近 60 天我的确没修过电视。我的电脑对我来说就是一块铝,我甚至没把它拆开看过。1974 年 12 月的《大众电子》刊登的像《驻波比是什么以及如何处理它》和《对万用表的测试》之类的特色文章,甚至连广告都令人生畏。它们中有个看起来像某种立体声系统的东西大胆地写道“除了‘四通道单元(即内建的 SQ、RM 和 CD-4 解码接收器)’,没有任何音频设备是值得期待的”。这也表明了《大众电子》的订阅者一定对电子有很多深入的了解。
|
||||
|
||||
不过在 [1975 年 1 月刊][2] 中,该杂志为读者们带来了一些他们从没见过的东西。在标题“突破性项目”下面,杂志的封面是一个大大的黑灰色盒子,其前面板上有一组复杂开关和灯。这便是 Altair 8800,“世界上首个有商业竞争力的小型机”,它的售价低于 400 美元。尽管 Altair 被宣传作“<ruby>小型机<rt>minicomputer</rt></ruby>”,但它实际上是首个商业上成功的新型计算机成员,它首先被称为“<ruby>微型计算机<rt>microcomputers</rt></ruby>”,最终被称为 PC(<ruby>个人计算机<rt>Personal Computer</rt></ruby>)。Altair 十分小巧而且很便宜,以至于它成为了当时家家户户都能用起的电脑。正如 Salsberg 所写道,它在《大众电子》上的出现意味着:“家用电脑的时代终于到来了。”
|
||||
|
||||
![《大众电子》1975 年 1 月刊的封面][3]
|
||||
|
||||
此前,我曾写过 [关于 Altair 的文章][4],但我觉得 Altair 值得重新审视。与当时其它的计算机相比,它并不是一台性能强劲的计算机(尽管它的成本要低得多),它也不是首个采用微处理器的通用计算机(在它之前已经至少有三个基于微处理器的计算机)。但是 Altair 是一种可供我们所有人使用的计算机。它是历史上我们所拥有的设备中首台流行的计算机,而早于 Altair 计算机都是完全不同的机器,那些大型机和笨重的迷你计算机由穿孔卡编程并且很少与之直接交互。不过 Altair 也是台极其简单的计算机,它没有附带任何操作系统甚至是引导程序。除非你为它购买外围设备,否则 Altair 就是一台装配了 RAM、前面板只有一组开关和灯泡的机器。由于 Altair 操作简单,使得重新理解基本的计算概念都成了十分简单的事情,正如模拟信号时代的人们第一次接触到数字设备一样。
|
||||
|
||||
### Roberts 和他的公司
|
||||
|
||||
Altair 是由一家名为<ruby>微型仪器和遥测系统<rt>Micro Instrumentation and Telemetry Systems</rt></ruby>(MITS)的公司所设计制造,这家公司位于美国新墨西哥州的阿尔布开克。MITS 由一个叫 H. Edward Roberts 的人经营。在进入计算器市场之前,该公司已经开始制造模型火箭的遥测系统,该市场在 20 世纪 70 年代初期蓬勃发展。集成电路大大降低了计算器的成本,突然之间它就成了美国每个在职的专业人士的必需品。不幸的是,由于计算器市场竞争过于激烈,到了 1974 年初,MITS 便负债累累。
|
||||
|
||||
1974 年在计算机界是<ruby>奇迹迭出的一年<rt>annus mirabilis</rt></ruby>。[^1] 一月的时候,惠普公司推出了世界首个可编程的手持计算器 HP-65。四月的时候,Intel 发布了 Intel 8080,这是他们的第二款 8 位微处理器,它也是首款广受欢迎的微处理器。接着,六月的时候,《<ruby>无线电电子<rt>Radio Electronics</rt></ruby>》杂志宣传了一台名为 Mark-8 的自制小型计算机,它使用了 Intel 在 1972 年推出的 Intel 8008 微处理器。Mark-8 是有史以来使用微处理器搭建的第三台电脑,它的首次登场是在杂志的封面上。[^2] Mark-8 在《无线电电子》上的出现促使了《大众电子》寻找他们要自己宣传的小型机项目。
|
||||
|
||||
《大众电子》的订阅者们其实早在 1974 年 12 月就通过邮件获得了 1975 年 1 月刊的刊物。[^3] 所以 Altair 的宣布为这个<ruby>奇迹迭出的一年<rt>annus mirabilis</rt></ruby>画上了圆满的句号。Altair 的出现是十分重要的,因为此前从未有过向公众提供的价格公道而又功能齐全的电脑。当时,作为最受欢迎的小型计算机之一的 PDP-8 要几千美金才能买到。然而作为 Altair 核心的 Intel 8080 芯片几乎能与 PDP-8 匹敌,甚至更强;8080 支持更广泛的指令集,而且 Altair 可以扩展到 64 kb 内存,显然强于仅有 4 kb 内存的 PDP-8。并且,Mark-8 也不是它的对手,因为它搭载的是只能处理 16 kb 内存的 Intel 8008。在 Mark-8 必须由用户按照说明书在印刷电路板上手动拼装的情况下,Altair 在购买时就已经被组装好了(不过由于后来 MITS 被大量订单淹没,最后真正能获得 Altair 的方式也只有买套件拼装了)。
|
||||
|
||||
对许多《大众电子》的读者来说,Altair 是他们了解数字计算的起点。1975 年 1 月刊上那篇介绍 Altair 的文章由 Roberts 和 Altair 的共同设计师 William Yates 所写。Roberts 和 Yates 煞费苦心地用电工和无线电狂热者们所熟悉的词汇来介绍了数字硬件和计算机编程的基本概念。他们写道:“一台计算机其实由一块可变的硬件。仅需修改储存于内存之中的位组合形式,便可改变硬件设备的种类。”同时,Roberts 和 Yates 认为编程的基本概念是“足够简单并能在较短时间内掌握,但是想要成为一个高效的程序员必须经验丰富且富有创造力。”对此我十分认同。尽管该部分已经完全组装好了,文章仍包含了用来讲解 Intel 8080 的组成电路的详细图表。文章解释了 CPU 和计算机内存单元的区别,堆栈指针的用法,和汇编语言以及更高级的语言(例如 FORTRAN 和 BASIC)比起手动输入机器码所带来的巨大优势。
|
||||
|
||||
其实,《大众电子》在 1975 年 1 月刊之前就出版过 Roberts 撰写的系列文章。这一系列作为短期课程被收录在“数字逻辑”专栏中。在 1974 年 12 月刊中,Roberts 为读者们带来了关于构建“超低成本计算机终端”的文章,文章中介绍了可以用于 8 位电脑中输入值的八进制键盘。在介绍这个键盘时,Roberts 解释了晶体管到晶体管的逻辑工作原理,以及关于构建一种可以“记住”数字值的触发器的方法。Roberts 承诺说,这个键盘可以在下个月即将公布的 Altair 电脑中使用。
|
||||
|
||||
有多少《大众电子》的读者制作了这个键盘我们无从得知,但是那个键盘的确是个很有用的东西。如果没有键盘和其它输入设备,我们只能通过拨动 Altair 面板上的开关来输入值。Altair 的前面板上有一行 16 个开关被用来设置地址,而下方的 8 个则是用来操作计算机的。一行 16 个开关中最右边的 8 个开关也能用来指定要储存在内存中的值。这么做不无道理,因为 Intel 8080 使用 16 位的值来寻址 8 位的字。而前面板的这 16 个开关每一个都代表了一个位,当开关向上时代表 1,向下则代表 0。用这样的方式与计算机交互是个启示(一会儿我们就会讲到),因为 Altair 的面板是真正的二进制界面。这使得你可以尽可能地接触到计算机实体。
|
||||
|
||||
尽管在当下 Altair 的界面对我们来说完全不像是人用的,不过在那个时代却并不罕见。比如 PDP-8 的面板上有个类似的但更漂亮的二进制输入装置,而且它被涂上了吸引人的黄色和橙色,不过讲真,它真的应该卷土重来。然而 PDP-8 经常与纸带阅读器或电传打字机配合使用,这使得程序输入更加容易。这些 I/O 设备价格高昂,这意味着 Altair 的用户们大都会被那个前面板拦住。正如你可能想象的那样,通过这一堆开关输入一个大型程序是个苦差事。不过幸运的是,Altair 可以与盒式记录器连接,这样一来载入程序就不是什么难事了。Bill Gates 和 Paul Allen 在 MITS 的授权下为 Altair 编写了一个 BASIC 语言版本,并在 1975 年中期发行,这成为了微软有史以来的首次商业尝试。此后,那些买得起电传打字机的用户就能 [通过纸带来将 BASIC 载入 Altair][5] 了,并能使得用户能够通过文字与 Altair 交互。之后,BASIC 便成为了学生们最爱的入门编程语言,并成了早期小型机时代的标准接口。
|
||||
|
||||
### z80pack
|
||||
|
||||
多亏了网络上一些人,特别是 Udo Munk 的努力,你可以在你的计算机上运行 Altair 的模拟器。这个模拟器是在 Zilog Z80 CPU 的虚拟套件上构建的,这个 CPU 可以运行 Intel 8080 的软件。Altair 模拟器允许你像 Altair 的早期用户们一样拨动前面板上的开关。尽管点击这些开关的感觉不如拨动真实开关的触觉,但是使用 Altair 模拟器仍是一个能让你感受二进制人机交互效率有多低的途径,至少在我看来这非常简明直观。
|
||||
|
||||
z80pack 是 Udo Munk 开发的 Z80 模拟器套件,你可以在 z80pack 的官网上找到它的下载链接。我在 [上一篇介绍 Altair 的文章中][4] 写到过在 macOS 上使用它的详细过程。如果你能编译 FrontPanel 库和 `altairsim` 可执行程序,你应该能直接运行 `altairsim` 并看到这个窗口:
|
||||
|
||||
![模拟器中的 Altair 面板][6]
|
||||
|
||||
在新版的 z80pack 中(比如我正在使用的 1.36 版本),你可以使用一个叫 Tarbell boot ROM 的功能,我觉得这是用来加载磁盘镜像的。经我测试,这意味着你不能写入到 RAM 中的前几个字。在编辑 `/altairsim/conf/system.conf` 之后,你可以构建带有一个 16 页 RAM 且没有 ROM 或引导加载器的 Altair。除此之外,你还可以用这个配置文件来扩大运行模拟器的窗口大小,不得不说这还是挺方便的。
|
||||
|
||||
Altair 的面板看起来令人生畏,不过事实上并没有我们想象中的这么可怕。[Altair 说明书][7] 对解释开关和指示灯起到了很大的作用,这个 [YouTube 视频][8] 也是如此。若想输入和运行一个简易的程序,你只需要了解一点点东西。Altair 右上方标签为 D0 到 D7 的指示灯代表当前寻址的字的内容。标签为 A0 到 A15 的指示灯表示当前的地址。地址指示灯下的 16 个开关可以用来设置新地址;当 “EXAMINE” 开关被向上推动时,数据指示灯才会更新以显示新地址上的内容。用这个功能,你便能“观察”到内存中所有的信息了。你也可以将 “EXAMINE” 推下来“EXAMINE NEXT”位置,以自动检查下一个位置上的信息,这使得查看连续的信息更容易了。
|
||||
|
||||
要将位组合方式保存到内存信息中,请使用最右边的 8 个标签为 0 到 7 的开关。然后,请向上推动 “DEPOSIT” 按钮。
|
||||
|
||||
在《大众电子》 的 [1975 年 2 月刊][9] 中,Roberts 和 Yates 引导用户输入一小段程序来确保他们的 Altair 正常工作。这个程序从内存中读取两个整型数据并相加之后将和存回内存中。这个小程序仅由 6 条指令组成,但是这 6 条指令涉及了 14 个字的内存,所以要正确地输入它们需要一点时间。这个示例程序也被写入了 Altair 的说明书,原文如下:
|
||||
|
||||
| Address | Mnemonic | Bit Pattern | Octal Equivalent |
|
||||
| :------: | :------: | :------: | :------: |
|
||||
| 0 | LDA | 00 111 010 | 0 7 2 |
|
||||
| 1 | (address) | 10 000 000 | 2 0 0 |
|
||||
| 2 | (address) | 00 000 000 | 0 0 0 |
|
||||
| 3 | MOV B, A | 01 000 111 | 1 0 7 |
|
||||
| 4 | LDA | 00 111 010 | 0 7 2 |
|
||||
| 5 | (address) | 10 000 001 | 2 0 1 |
|
||||
| 6 | (address) | 00 000 000 | 0 0 0 |
|
||||
| 7 | ADD B | 10 000 000 | 2 0 0 |
|
||||
| 8 | STA | 00 110 010 | 0 6 2 |
|
||||
| 9 | (address) | 10 000 010 | 2 0 2 |
|
||||
| 10 | (address) | 00 000 000 | 0 0 0 |
|
||||
| 11 | JMP | 11 000 011 | 3 0 3 |
|
||||
| 12 | (address) | 00 000 000 | 0 0 0 |
|
||||
| 13 | (address) | 00 000 000 | 0 0 0 |
|
||||
|
||||
如果你通过开关来将上表的这些值输入到 Altair,最终会得到一个程序,它会读取内存 128 中的值,并将其与 129 中的值相加,最终将其保存至 130 中。伴随每条取一个地址的指令的地址,它们最开始会给出最低有效位,这便是第二个字节总会被清零的原因了(没有高于 255 的地址)。在输入这个程序并在 128 和 129 中输入了一些值之后,你可以向下短暂推动 “RUN” ,之后再将它推到 “STOP” 位置。因为程序循环执行,以一秒内执行上千次的速度反复地添加并保存那些值。并且最后得到的值总是相同的,如果你停止该程序并查看 130 的内容,你应该能找到正确答案。
|
||||
|
||||
我不知道普通的 Altair 用户是否使用过汇编程序,不过 z80pack 包括了一个:`z80asm`,意思是<ruby>适用于 Z80 的汇编程序<rt>Z80 assembly</rt></ruby>,所以它使用了一组不同的助记符。不过因为 Z80 是被设计来兼容为 Intel 8080 写的软件的,所以即使助记符不一样,它们的操作码也是相同的。你可以直接将 `z80asm` 汇编码装载进 Altair:
|
||||
|
||||
```
|
||||
ORG 0000H
|
||||
START: LD A,(80H) ;Load from address 128.
|
||||
LD B,A ;Move loaded value from accumulator (A) to reg B.
|
||||
LD A,(81H) ;Load from address 129.
|
||||
ADD A,B ;Add A and B.
|
||||
LD (82H),A ;Store A at address 130.
|
||||
JP START ;Jump to start.
|
||||
```
|
||||
|
||||
编译之后,你可以调用汇编程序来将其转换为 Intel HEX 文件:
|
||||
|
||||
```shell
|
||||
$ ./z80asm -fh -oadd.hex add.asm
|
||||
```
|
||||
|
||||
我们用带有 `h` 参数的 `-f` 标识来定义输出的 HEX 文件。你可以用 `-x` 标识来传递 HEX 文件,从而使得 Altair 能够加载该程序:
|
||||
|
||||
```shell
|
||||
$ ./altairsim -x add.hex
|
||||
```
|
||||
|
||||
这会在内存中自动设置前 14 个字,就和你通过开关手动输入这些值一样。你可以直接使用 “RUN” 按钮来替代以前那些繁琐的步骤,这是如此的简单!
|
||||
|
||||
我不觉得有很多 Altair 用户以这种方式来编写软件。Altair BASIC 发布后,使得 BASIC 成为了 Altair 编程最简单的方法。z80pack 同时也包括了一些不同版本 Altair BASIC 的 HEX 文件;在模拟器中,你可以用这个方式加载 4.0 版本的 4K BASIC:
|
||||
|
||||
```shell
|
||||
$ ./altairsim -x basic4k40.hex
|
||||
```
|
||||
|
||||
当你开启模拟器并按下 “RUN” 按钮之后,你就会看到 BASIC 开始执行了,同时它会在终端中与你交互。它首先会提示你输入你的内存可用量,我们输入 4000 字节。随后,在显示 “OK” 提示符之前,它会问你几个问题,Gates 和 Allen 用这个“OK”来代替标准的 “READY” 并以此节省内存。在这之后,你便可以使用 BASIC 了:
|
||||
|
||||
```
|
||||
OK
|
||||
PRINT 3 + 4
|
||||
7
|
||||
```
|
||||
|
||||
虽然运行 BASIC 只有 4kb 的内存并没有给你足够的空间,但你可以看到它是如何从使用前面板迈出了重要的一步。
|
||||
|
||||
很显然,Altair 远不及如今的家用电脑和笔记本电脑,并且比它晚十多年发布的 Mac 电脑看上去也是对 这个简朴的 Altair 电脑的巨大飞跃。但是对第一批购买并亲手组装了 Altair 的《大众电子》的读者们来说,Altair 才是他们拥有的第一个真正的全功能电脑,而这一切只用了 400 美金低价和一半的书柜空间。对那时只能用 [一叠卡片][10] 或一卷磁带来与计算机交互的人们来说,Altair 是个令人眼前一亮的玩意。这之后的微型计算机基本都是在对 Altair 改进,使得它更易用。从某种意义上来说,它们只是更复杂的 Altair。Altair,一个野兽派的极简作品,却为之后的许多微型计算机打下了铺垫。
|
||||
|
||||
如果你觉得这篇文章写的不错,你可以在推特上关注 [@TwoBitHistory][11] 或订阅 [RSS feed][12] 来获得我们文章的更新提醒。文章每两周就会更新一次!
|
||||
|
||||
[^1]: Paul E. Ceruzzi, A History of Modern Computing (Cambridge, Mass: MIT Press, 2003), 226.
|
||||
[^2]: “Mark-8 Minicomputer,” Byran’s Old Computers, accessed July 21, 2018, http://bytecollector.com/mark_8.htm.
|
||||
[^3]: Paul E. Ceruzzi, A History of Modern Computing (Cambridge, Mass: MIT Press, 2003), 226.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://twobithistory.org/2018/07/22/dawn-of-the-microcomputer.html
|
||||
|
||||
作者:[Sinclair Target][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[zhs852](https://github.com/zhs852)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://twobithistory.org
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.americanradiohistory.com/Archive-Poptronics/70s/1974/Poptronics-1974-12.pdf
|
||||
[2]: https://www.americanradiohistory.com/Archive-Poptronics/70s/1975/Poptronics-1975-01.pdf
|
||||
[3]: https://twobithistory.org/images/jan1975-altair.jpg
|
||||
[4]: https://linux.cn/article-10181-1.html
|
||||
[5]: https://www.youtube.com/watch?v=qv5b1Xowxdk
|
||||
[6]: https://www.autometer.de/unix4fun/z80pack/altair.png
|
||||
[7]: http://www.classiccmp.org/dunfield/altair/d/88opman.pdf
|
||||
[8]: https://www.youtube.com/watch?v=suyiMfzmZKs
|
||||
[9]: https://www.americanradiohistory.com/Archive-Poptronics/70s/1975/Poptronics-1975-02.pdf
|
||||
[10]: https://linux.cn/article-10382-1.html
|
||||
[11]: https://twitter.com/TwoBitHistory
|
||||
[12]: https://twobithistory.org/feed.xml
|
||||
[13]: https://twitter.com/TwoBitHistory/status/1015647820353867776?ref_src=twsrc%5Etfw
|
335
published/20180725 Build an interactive CLI with Node.js.md
Normal file
335
published/20180725 Build an interactive CLI with Node.js.md
Normal file
@ -0,0 +1,335 @@
|
||||
使用 Node.js 构建交互式命令行工具
|
||||
======
|
||||
|
||||
> 使用 Node.js 构建一个根据询问创建文件的命令行工具。
|
||||
|
||||

|
||||
|
||||
当用于构建命令行界面(CLI)时,Node.js 十分有用。在这篇文章中,我将会教你如何使用 [Node.js][1] 来构建一个问一些问题并基于回答创建一个文件的命令行工具。
|
||||
|
||||
### 开始
|
||||
|
||||
首先,创建一个新的 [npm][2] 包(NPM 是 JavaScript 包管理器)。
|
||||
|
||||
```
|
||||
mkdir my-script
|
||||
cd my-script
|
||||
npm init
|
||||
```
|
||||
|
||||
NPM 将会问一些问题。随后,我们需要安装一些包。
|
||||
|
||||
```
|
||||
npm install --save chalk figlet inquirer shelljs
|
||||
```
|
||||
|
||||
这是我们需要的包:
|
||||
|
||||
* Chalk:正确设定终端的字符样式
|
||||
* Figlet:使用普通字符制作大字母的程序(LCTT 译注:使用标准字符,拼凑出图片)
|
||||
* Inquirer:通用交互式命令行用户界面的集合
|
||||
* ShellJS:Node.js 版本的可移植 Unix Shell 命令行工具
|
||||
|
||||
### 创建一个 index.js 文件
|
||||
|
||||
现在我们要使用下述内容创建一个 `index.js` 文件。
|
||||
|
||||
```
|
||||
#!/usr/bin/env node
|
||||
|
||||
const inquirer = require("inquirer");
|
||||
const chalk = require("chalk");
|
||||
const figlet = require("figlet");
|
||||
const shell = require("shelljs");
|
||||
```
|
||||
|
||||
### 规划命令行工具
|
||||
|
||||
在我们写命令行工具所需的任何代码之前,做计划总是很棒的。这个命令行工具只做一件事:**创建一个文件**。
|
||||
|
||||
它将会问两个问题:文件名是什么以及文件后缀名是什么?然后创建文件,并展示一个包含了所创建文件路径的成功信息。
|
||||
|
||||
```
|
||||
// index.js
|
||||
|
||||
const run = async () => {
|
||||
// show script introduction
|
||||
// ask questions
|
||||
// create the file
|
||||
// show success message
|
||||
};
|
||||
|
||||
run();
|
||||
```
|
||||
|
||||
第一个函数只是该脚本的介绍。让我们使用 `chalk` 和 `figlet` 来把它完成。
|
||||
|
||||
```
|
||||
const init = () => {
|
||||
console.log(
|
||||
chalk.green(
|
||||
figlet.textSync("Node JS CLI", {
|
||||
font: "Ghost",
|
||||
horizontalLayout: "default",
|
||||
verticalLayout: "default"
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const run = async () => {
|
||||
// show script introduction
|
||||
init();
|
||||
|
||||
// ask questions
|
||||
// create the file
|
||||
// show success message
|
||||
};
|
||||
|
||||
run();
|
||||
```
|
||||
|
||||
然后,我们来写一个函数来问问题。
|
||||
|
||||
```
|
||||
const askQuestions = () => {
|
||||
const questions = [
|
||||
{
|
||||
name: "FILENAME",
|
||||
type: "input",
|
||||
message: "What is the name of the file without extension?"
|
||||
},
|
||||
{
|
||||
type: "list",
|
||||
name: "EXTENSION",
|
||||
message: "What is the file extension?",
|
||||
choices: [".rb", ".js", ".php", ".css"],
|
||||
filter: function(val) {
|
||||
return val.split(".")[1];
|
||||
}
|
||||
}
|
||||
];
|
||||
return inquirer.prompt(questions);
|
||||
};
|
||||
|
||||
// ...
|
||||
|
||||
const run = async () => {
|
||||
// show script introduction
|
||||
init();
|
||||
|
||||
// ask questions
|
||||
const answers = await askQuestions();
|
||||
const { FILENAME, EXTENSION } = answers;
|
||||
|
||||
// create the file
|
||||
// show success message
|
||||
};
|
||||
```
|
||||
|
||||
注意,常量 `FILENAME` 和 `EXTENSIONS` 来自 `inquirer` 包。
|
||||
|
||||
下一步将会创建文件。
|
||||
|
||||
```
|
||||
const createFile = (filename, extension) => {
|
||||
const filePath = `${process.cwd()}/${filename}.${extension}`
|
||||
shell.touch(filePath);
|
||||
return filePath;
|
||||
};
|
||||
|
||||
// ...
|
||||
|
||||
const run = async () => {
|
||||
// show script introduction
|
||||
init();
|
||||
|
||||
// ask questions
|
||||
const answers = await askQuestions();
|
||||
const { FILENAME, EXTENSION } = answers;
|
||||
|
||||
// create the file
|
||||
const filePath = createFile(FILENAME, EXTENSION);
|
||||
|
||||
// show success message
|
||||
};
|
||||
```
|
||||
|
||||
最后,重要的是,我们将展示成功信息以及文件路径。
|
||||
|
||||
```
|
||||
const success = (filepath) => {
|
||||
console.log(
|
||||
chalk.white.bgGreen.bold(`Done! File created at ${filepath}`)
|
||||
);
|
||||
};
|
||||
|
||||
// ...
|
||||
|
||||
const run = async () => {
|
||||
// show script introduction
|
||||
init();
|
||||
|
||||
// ask questions
|
||||
const answers = await askQuestions();
|
||||
const { FILENAME, EXTENSION } = answers;
|
||||
|
||||
// create the file
|
||||
const filePath = createFile(FILENAME, EXTENSION);
|
||||
|
||||
// show success message
|
||||
success(filePath);
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
来让我们通过运行 `node index.js` 来测试这个脚本,这是我们得到的:
|
||||
|
||||

|
||||
|
||||
### 完整代码
|
||||
|
||||
下述代码为完整代码:
|
||||
|
||||
```
|
||||
#!/usr/bin/env node
|
||||
|
||||
const inquirer = require("inquirer");
|
||||
const chalk = require("chalk");
|
||||
const figlet = require("figlet");
|
||||
const shell = require("shelljs");
|
||||
|
||||
const init = () => {
|
||||
console.log(
|
||||
chalk.green(
|
||||
figlet.textSync("Node JS CLI", {
|
||||
font: "Ghost",
|
||||
horizontalLayout: "default",
|
||||
verticalLayout: "default"
|
||||
})
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
const askQuestions = () => {
|
||||
const questions = [
|
||||
{
|
||||
name: "FILENAME",
|
||||
type: "input",
|
||||
message: "What is the name of the file without extension?"
|
||||
},
|
||||
{
|
||||
type: "list",
|
||||
name: "EXTENSION",
|
||||
message: "What is the file extension?",
|
||||
choices: [".rb", ".js", ".php", ".css"],
|
||||
filter: function(val) {
|
||||
return val.split(".")[1];
|
||||
}
|
||||
}
|
||||
];
|
||||
return inquirer.prompt(questions);
|
||||
};
|
||||
|
||||
const createFile = (filename, extension) => {
|
||||
const filePath = `${process.cwd()}/${filename}.${extension}`
|
||||
shell.touch(filePath);
|
||||
return filePath;
|
||||
};
|
||||
|
||||
const success = filepath => {
|
||||
console.log(
|
||||
chalk.white.bgGreen.bold(`Done! File created at ${filepath}`)
|
||||
);
|
||||
};
|
||||
|
||||
const run = async () => {
|
||||
// show script introduction
|
||||
init();
|
||||
|
||||
// ask questions
|
||||
const answers = await askQuestions();
|
||||
const { FILENAME, EXTENSION } = answers;
|
||||
|
||||
// create the file
|
||||
const filePath = createFile(FILENAME, EXTENSION);
|
||||
|
||||
// show success message
|
||||
success(filePath);
|
||||
};
|
||||
|
||||
run();
|
||||
```
|
||||
|
||||
### 使用这个脚本
|
||||
|
||||
想要在其它地方执行这个脚本,在你的 `package.json` 文件中添加一个 `bin` 部分,并执行 `npm link`:
|
||||
|
||||
```
|
||||
{
|
||||
"name": "creator",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "node index.js"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"chalk": "^2.4.1",
|
||||
"figlet": "^1.2.0",
|
||||
"inquirer": "^6.0.0",
|
||||
"shelljs": "^0.8.2"
|
||||
},
|
||||
"bin": {
|
||||
"creator": "./index.js"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
执行 `npm link` 使得这个脚本可以在任何地方调用。
|
||||
|
||||
这就是是当你运行这个命令时的结果。
|
||||
|
||||
```
|
||||
/usr/bin/creator -> /usr/lib/node_modules/creator/index.js
|
||||
/usr/lib/node_modules/creator -> /home/hugo/code/creator
|
||||
```
|
||||
|
||||
这会连接 `index.js` 作为一个可执行文件。这是完全可能的,因为这个 CLI 脚本的第一行是 `#!/usr/bin/env node`。
|
||||
|
||||
现在我们可以通过执行如下命令来调用。
|
||||
|
||||
```
|
||||
$ creator
|
||||
```
|
||||
|
||||
### 总结
|
||||
|
||||
正如你所看到的,Node.js 使得构建一个好的命令行工具变得非常简单。如果你希望了解更多内容,查看下列包。
|
||||
|
||||
* [meow][3]:一个简单的命令行助手工具
|
||||
* [yargs][4]:一个命令行参数解析工具
|
||||
* [pkg][5]:将你的 Node.js 程序包装在一个可执行文件中。
|
||||
|
||||
在评论中留下你关于构建命令行工具的经验吧!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/7/node-js-interactive-cli
|
||||
|
||||
作者:[Hugo Dias][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[bestony](https://github.com/bestony)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/hugodias
|
||||
[1]:https://nodejs.org/en/
|
||||
[2]:https://www.npmjs.com/
|
||||
[3]:https://github.com/sindresorhus/meow
|
||||
[4]:https://github.com/yargs/yargs
|
||||
[5]:https://github.com/zeit/pkg
|
118
published/20180731 How to be the lazy sysadmin.md
Normal file
118
published/20180731 How to be the lazy sysadmin.md
Normal file
@ -0,0 +1,118 @@
|
||||
如何成为一名懒惰的系统管理员
|
||||
======
|
||||
> 我们是聪明地工作,而不是刻苦工作,但仍能把工作做好。
|
||||
|
||||

|
||||
|
||||
Linux 的系统管理员的工作总是复杂的,并且总是伴随着各种陷阱和障碍。做每件事都没有足够时间,当你想完成那个半秃头老板(PHB)给的任务时,他(只会)不停在你的后面盯着,而最核心的服务器总是在最不合时宜的时间点崩溃,问题和挑战比比皆是。而我发现,成为一名<ruby>懒惰的系统管理员<rt>Lazy SysAdmin</rt></ruby>可以解决这一困境。
|
||||
|
||||
(LCTT 译注:<ruby>[半秃头老板](https://en.wikipedia.org/wiki/Pointy-haired_Boss)<rt>Pointy-Haired Boss</rt></ruby>(PHB),那是[呆伯特漫画](https://zh.wikipedia.org/wiki/%E5%91%86%E4%BC%AF%E7%89%B9)中的角色,缺乏一般知识常识及其职位所应具有的管理能力,爱说大话且富有向物理显示挑战的精神,大概长成下图这样。)
|
||||
|
||||

|
||||
|
||||
我在即将在 Apress 出版的新书 《The Linux Philosophy for SysAdmins》(LCTT 译注:暂译《系统管理员的 Linux 哲学》)中更详细地讨论如何成为一个懒惰的系统管理员,那书预计会在 9 月出版(LCTT 译注:已于 2018 年 8 月出版)。这本的部分内容摘录自该书,特别是第九章,“成为一名懒惰的系统管理员”。在我们讨论如何做到这点前,让我们简单了解一下成为一个名懒惰的系统管理员意味着什么。
|
||||
|
||||

|
||||
|
||||
### 真实生产力 vs. 虚假生产力
|
||||
|
||||
#### 虚假生产力
|
||||
|
||||
在我工作的地方,半秃头老板相信的管理风格叫“<ruby>走动式管理<rt>management by walking around</rt></ruby>”。通过判断某人在不在他的键盘上输入东西,或者至少要看看他们显示器上显示的东西,来判断他们的工作是否有效率。这是一个糟糕的工作场所。各部门间有道很高的行政墙,这会造就了许多的、微小的沟通壁垒,大量无用的文书工作,以及获得任何事情的许可都要等待漫长的时间。因为这样、那样的原因,不可能高效地做任何事情,如果真的是这样,那是非常低效。为了看起来很忙,我们都有自己的一套<ruby>“看起来很忙”的工具包<rt>Look Busy Kits</rt></ruby>(LBK),可能是一些短小的、用来显示一些行为活动的 Bash 脚本,或者是 `top`、`htop`、`iotop` 之类的程序,或者是一些持续显示某些行为活动的监控工具。这种工作场所的风气让人不可能真正高效,我讨厌这种地方,也讨厌那个几乎不可能完成任何有价值的事情的事实。
|
||||
|
||||
这种糟糕场所对真实的系统管理员来讲是场噩梦。没有人会感到快乐。在那里花费四五个月才能完成的事,在其他地方只需的一个早晨。我们没有什么实际工作要做,却要花大量的时间干活来让自己看起来很忙。我们在默默地竞赛,看谁能创造最好的“看起来很忙”的工具包,这就是我们花费最多时间的地方了。那份工作我只做了几个月,但好像已经耗费了一生。如果你看到的这个监狱的表面,你可能会说我们是很懒,因为我们只完成了几乎为 0 的实际工作。
|
||||
|
||||
这是个极端的例子,它完全与我所说的“我是一个懒惰的系统管理员”的意思相反,而做一个懒惰的系统管理是件好事。
|
||||
|
||||
#### 真实生产力
|
||||
|
||||
我很幸运,曾为一些真正的管理者工作过 —— 他们明白,系统管理员的生产力并不是以每天花多少小时敲键盘来衡量。毕竟,即使一只猴子能敲击他们的键盘,但也不能说明结果的价值。
|
||||
|
||||
正如我书中所言:
|
||||
|
||||
> “我是一个懒惰的系统管理员,同时我也是一个高效的系统管理员。这两者看似矛盾的说法不是相互排斥的,而是会以一种非常积极的方式相辅相成……
|
||||
>
|
||||
> “系统管理员在思考的时候是最高效的 —— 思考关于如何解决现有问题和避免未来的问题;思考怎样监控 Linux 计算机,以便找到预测和预示这些未来的问题的线索;思考如何让他们的工作更有效率;思考如何自动化所有这些要执行的任务,无论是每天还是每年一次的任务。
|
||||
>
|
||||
> “系统管理员冥思苦想的那一面是不会被非系统管理员所熟知的,那些人包括很多管理着系统管理员的人,比如那个半秃头老板。系统管理员都会以不同的方式解决他们工作中苦思的部分。一些我认识的系统管理员会在沙滩、骑自行车、参加马拉松或者攀岩时找到最好的想法。另一些人会认为静坐或听音乐的时候思考得最好。还有一些会在阅读小说、学习不相关的学科、甚至在学习 Linux 系统的时候可以最佳思考。关键是我们都有不同的方式激发我们的创造力,而这些创造力的推进器中很多并不涉及键盘上的任何一个按键。我们真正的生产力对于系统管理员周围的人来说可能是完全看不见的。”
|
||||
|
||||
成为懒惰的系统管理员有一些简单的秘诀 —— 系统管理员要完成一切需要完成的事,而且更多的是,当所有人都处于恐慌的状态时要保持冷静和镇定。秘诀的一部分是高效工作,另一部分是把预防问题放在首位。
|
||||
|
||||
### 成为懒惰系统管理员的方法
|
||||
|
||||
#### 多思考
|
||||
|
||||
我相信关于懒惰系统管理员最重要的秘诀在于思考。正如上面的摘录所言,优秀的系统管理员会花大量的时候思考这些事情,如何更有效率地工作,在异常成为问题前如何定位,更聪明地工作,做其它事情的同时会考虑如何完成这些事情等等。
|
||||
|
||||
例如,除了撰写本文之外,我现在正在想一个项目,我打算在从亚马逊和本地计算机商店采购的新部件到达时才开始。我有一台不太关键的计算机上的主板坏了,最近它的崩溃更频率。但我的一台非常老的小服务器并没有出现故障,它负责处理我的电子邮件和外部网站,以及为我的网络的其余部分提供 DHCP 和 DNS 服务,但需要解决由于各种外部攻击而导致的间歇性过载。
|
||||
|
||||
我一开始想,我只要替换故障设备的主板及其直接部件:内存、CPU,可能还有电源。但是在考虑了一段时间之后,我决定将新部件放到服务器中,并将旧的(但仍然可用的)部件从服务器移到故障设备中。可以这样做的,只需一、两个小时就可以从服务器上移除旧部件并安装新的。然后我就可以花时间更换出故障的电脑里的部件了。太好了,所以我开始在脑海中列出要完成的任务。
|
||||
|
||||
然而,当我查看这个任务列表时,我意识到服务器中唯一不能替换的部件是机箱和硬盘驱动器,这两台计算机的机箱几乎完全相同。在有了这个小小的发现之后,我开始考虑用新的部件替换出了故障的计算机的部件,并将之作为我的服务器。经过一些测试之后,我只需从当前的服务器移除硬盘,并将它安装到用了新组件的机箱中,改下网络配置项,再更改 KVM 交换机端口上的主机名,并更改机箱上的主机名标签,就可以了。这将大大减少服务器停机时间,大大减少我的压力。此外,如果出现故障,我可以简单地将硬盘移回原来的服务器,直到我可以用新服务器解决问题为止。
|
||||
|
||||
所以,现在我在脑海中已经创建了一个完成这项工作我所需要做的任务清单。而且,我希望你能仔细观察,当我脑子里想着这一切的时候,我的手指从来没有碰过键盘。我新的心理行动计划风险很低,与我最初的计划相比,涉及的服务器停机时间要少得多。
|
||||
|
||||
当我在 IBM 工作的时候,我经常看到很多语言中都有写着“**思考**”的标语。思考可以节省时间和压力,是懒散的系统管理员的主要标志。
|
||||
|
||||
#### 做预防性维护
|
||||
|
||||
在 1970 年代中期,我被 IBM 聘为客户工程师,我的领地由相当多的[穿孔卡片设备][2]组成。这也就是说,它们是处理打孔卡的重型机械设备,其中一些可以追溯到 20 世纪 30 年代。因为这些机器主要是机械的,所以它们的部件经常磨损或失调。我的部分工作是在它们损坏时修复它们。我工作的主要部分,也是最重要的部分,是首先要防止它们损坏。预防性维护的目的是在磨损部件损坏之前进行更换,并对还在运行的部件进行润滑和调整,以确保它们工作正常。
|
||||
|
||||
正如我在《系统管理员的 Linux 哲学》中所言:
|
||||
|
||||
>“我在 IBM 的经理们明白这只是冰山一角;他们和我都知道,我的工作是让顾客满意。虽然这通常意味着修复损坏的硬件,但也意味着减少硬件损坏的次数。这对客户来说是好事,因为他们的机器在工作时工作效率更高。这对我有好处,因为我从那些快乐的客户那里接到的电话要少得多。我也睡了更多的觉,因为这样做的结果是更少的非工作时间的紧急电话。我是个懒惰的(客户工程师)。通过提前做额外的工作,从长远来看,我需要做的工作要少得多。
|
||||
>
|
||||
>“这一原则已成为系统管理员的 Linux 哲学的功能原则之一。作为系统管理员,我们的时间最好用在最大限度地减少未来工作量的任务上。”
|
||||
|
||||
在 Linux 计算机中查找要解决的问题相当于项目管理。我检查系统日志,寻找以后可能会变得非常危险的问题的迹象。如果出现了一些小问题,或者我注意到我的工作站、服务器没有做出该有的响应,或者如果日志显示了一些不寻常的东西,所有这些都可以暗示出潜在的问题,而对于用户或半秃头老板来说,这些问题并没有产生明显的症状。
|
||||
|
||||
我经常检查 `/var/log/` 中的文件,特别是 `messages` 和 `security` 文件。我最常见的问题之一是许多脚本小子在我的防火墙系统上尝试各种类型的攻击。而且,不,我不依赖 ISP 提供的调制解调器/路由器中的所谓的防火墙。这些日志包含了大量关于企图攻击来源的信息,非常有价值。但是要扫描不同主机上的日志并将解决方案部署到位,需要做大量的工作,所以我转向自动化。
|
||||
|
||||
#### 自动化
|
||||
|
||||
我发现我的工作有很大一部分可以通过某种形式的自动化来完成。系统管理员的 Linux 哲学的原则之一是 “自动化一切”,这包括每天扫描日志文件等枯燥乏味的任务。
|
||||
|
||||
像是 [Logwatch][3] 这类的程序能够监控你的日志文件中的异常条目,并在异常条目发生时通知您。Logwatch 通常作为 cron 任务每天运行一次,并向本地主机上的 root 用户发送电子邮件。你可以从命令行运行 Logwatch,并立即在显示器上查看结果。现在我只需要每天查看 Logwatch 的电子邮件通知。
|
||||
|
||||
但现实是,仅仅收到通知是不够的,因为我们不能坐以待毙。有时需要立即作出反应。我喜欢的另一个程序是——它能为我做所有事(看,这就是懒惰的管理员)——它就是 [Fail2ban][4]。Fail2Ban 会扫描指定的日志文件,查找各种类型的黑客攻击和入侵尝试,如果它发现某个 IP 地址在持续做特定类型的活动,它会向防火墙添加一个条目,在指定的时间内阻止来自该 IP 地址的任何进一步的黑客尝试。默认值通常在 10 分钟左右,但我喜欢为大多数类型的攻击指定为 12 或 24 小时。每种类型的黑客攻击都是单独配置的,例如尝试通过 SSH 登录和那些 Web 服务器的攻击。
|
||||
|
||||
#### 写脚本
|
||||
|
||||
自动化是这种哲学的关键组成部分之一。一切可以自动化的东西都应该自动化的,其余的尽可能地自动化。所以,我也写了很多脚本来解决问题,也就是说我编写了脚本来完成我的大部分工作。
|
||||
|
||||
我的脚本帮我节省了大量时间,因为它们包含执行特定任务的命令,这大大减少了我需要输入的数量。例如,我经常重新启动我的电子邮件服务器和垃圾邮件过滤软件(当修改 SpamAssassin 的 `local.cf` 配置文件时,就需要重启)。必须按特定顺序停止并重新启动这些服务。因此,我用几个命令编写了一个简短的脚本,并将其存储在可访问的 `/usr/local/bin` 中。现在,不用键入几个命令并等待每个命令都完成,然后再键入下一个命令,更不用记住正确的命令顺序和每个命令的正确语法,我输入一个三个字符的命令,其余的留给我的脚本来完成。
|
||||
|
||||
#### 简化键入
|
||||
|
||||
另一种成为懒惰的系统管理员的方法是减少我们需要键入的数量。而且,我的打字技巧真的很糟糕(也就是说,我一点也没有,顶多是几个笨拙的手指)。导致错误的一个可能原因是我糟糕的打字技巧,所以我会尽量少打字。
|
||||
|
||||
绝大多数 GNU 和 Linux 核心实用程序都有非常短的名称。然而,它们都是有意义的名字。诸如用于更改目录的 `cd` 、用于列出目录内容的 `ls` 和用于磁盘转储的 `dd` 等工具都一目了然。短名字意味着更少的打字和更少的产生错误机会。我认为短的名字通常更容易记住。
|
||||
|
||||
当我编写 shell 脚本时,我喜欢保持名称简短而意义(至少对我来说是),比如用于 rsync 备份的 `rsbu`(LCTT 译注,Rsync Backup 的简写)。但在某些情况下,我喜欢使用更长的名称,比如 `doUpdates` 来执行系统更新。在后一种情况下,更长一点的名字让脚本的目的更明显。这可以节省时间,因为很容易记住脚本的名称。
|
||||
|
||||
其他减少键入的方法包括命令行别名、历史命令调回和编辑。别名只是你在 Bash shell 键入命令时才做的替换。键入 `alias` 命令会看到默认配置的别名列表。例如,当你输入命令 `ls` 时,会被条目 `alias ls='ls –color=auto'` 替成较长的命令,因此你只需键入 2 个字符而不是 14 个字符即可获得带有颜色的文件列表。还可以使用 `alias` 命令添加你自己定义的别名。
|
||||
|
||||
历史命令调回允许你使用键盘的向上和向下箭头键滚动浏览命令历史记录。如果需要再次使用相同的命令,只需在找到所需的命令时按回车键即可。如果在找到命令后需要更改该命令,则可以使用标准命令行编辑功能进行更改。
|
||||
|
||||
### 结束语
|
||||
|
||||
一名懒惰的系统管理员实际上也有很多的工作。但我们是聪明地工作,而不是刻苦工作。早在一堆小问题汇聚成大问题之前,我们就花时间探索我们负责的主机,并处理好所有的小问题。我们花了很多时间思考解决问题的最佳方法,我们也花了很多时间来发现新的方法,让自己更聪明地工作,成为懒惰的系统管理员。
|
||||
|
||||
除了这里描述的少数方法外,还有许多其他的方式可以成为懒惰的系统管理员。我相信你也有一些自己的方式;请在评论中和我们分享。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/7/how-be-lazy-sysadmin
|
||||
|
||||
作者:[David Both][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[zgj1024](https://github.com/zgj1024)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/dboth
|
||||
[1]:https://www.apress.com/us/book/9781484237298
|
||||
[2]:https://en.wikipedia.org/wiki/Unit_record_equipment
|
||||
[3]:https://www.techrepublic.com/article/how-to-install-and-use-logwatch-on-linux/
|
||||
[4]:https://www.fail2ban.org/wiki/index.php/Main_Page
|
137
published/20180809 Perform robust unit tests with PyHamcrest.md
Normal file
137
published/20180809 Perform robust unit tests with PyHamcrest.md
Normal file
@ -0,0 +1,137 @@
|
||||
使用 PyHamcrest 执行健壮的单元测试
|
||||
======
|
||||
> 使用此框架编写断言,提高开发测试的准确性。
|
||||
|
||||

|
||||
|
||||
在[测试金字塔][1]的底部是单元测试。单元测试每次只测试一个代码单元,通常是一个函数或方法。
|
||||
|
||||
通常,设计单个单元测试是为了测试通过一个函数或特定分支的特定执行流程,这使得将失败的单元测试和导致失败的 bug 对应起来变得容易。
|
||||
|
||||
理想情况下,单元测试很少使用或不使用外部资源,从而隔离它们并使它们更快。
|
||||
|
||||
单元测试套件通过在开发过程的早期发现问题来帮助维护高质量的产品。有效的单元测试可以在代码离开开发人员机器之前捕获 bug,或者至少可以在特定分支上的持续集成环境中捕获 bug。这标志着好的和坏的单元测试之间的区别:*好的*测试通过尽早捕获 bug 并使测试更快来提高开发人员的生产力。*坏的*测试降低了开发人员的工作效率。
|
||||
|
||||
当测试*附带的特性*时,生产率通常会降低。当代码更改时测试会失败,即使它仍然是正确的。发生这种情况是因为输出的不同,但在某种程度上是因为它不是<ruby>函数契约<rt>function's contract</rt></ruby>的一部分。
|
||||
|
||||
因此,一个好的单元测试可以帮助执行函数所提交的契约。
|
||||
|
||||
如果单元测试中断,那意味着该契约被违反了,应该(通过更改文档和测试)明确修改,或者(通过修复代码并保持测试不变)来修复。
|
||||
|
||||
虽然将测试限制为只执行公共契约是一项需要学习的复杂技能,但有一些工具可以提供帮助。
|
||||
|
||||
其中一个工具是 [Hamcrest][2],这是一个用于编写断言的框架。最初是为基于 Java 的单元测试而发明的,但它现在支持多种语言,包括 [Python][3]。
|
||||
|
||||
Hamcrest 旨在使测试断言更容易编写和更精确。
|
||||
|
||||
```
|
||||
def add(a, b):
|
||||
return a + b
|
||||
|
||||
from hamcrest import assert_that, equal_to
|
||||
|
||||
def test_add():
|
||||
assert_that(add(2, 2), equal_to(4))
|
||||
```
|
||||
|
||||
这是一个用于简单函数的断言。如果我们想要断言更复杂的函数怎么办?
|
||||
|
||||
```
|
||||
def test_set_removal():
|
||||
my_set = {1, 2, 3, 4}
|
||||
my_set.remove(3)
|
||||
assert_that(my_set, contains_inanyorder([1, 2, 4]))
|
||||
assert_that(my_set, is_not(has_item(3)))
|
||||
```
|
||||
|
||||
注意,我们可以简单地断言其结果是任何顺序的 `1`、`2` 和 `4`,因为集合不保证顺序。
|
||||
|
||||
我们也可以很容易用 `is_not` 来否定断言。这有助于我们编写*精确的断言*,使我们能够把自己限制在执行函数的公共契约方面。
|
||||
|
||||
然而,有时候,内置的功能都不是我们*真正*需要的。在这些情况下,Hamcrest 允许我们编写自己的<ruby>匹配器<rt>matchers</rt></ruby>。
|
||||
|
||||
想象一下以下功能:
|
||||
|
||||
```
|
||||
def scale_one(a, b):
|
||||
scale = random.randint(0, 5)
|
||||
pick = random.choice([a,b])
|
||||
return scale * pick
|
||||
```
|
||||
|
||||
我们可以自信地断言其结果均匀地分配到至少一个输入。
|
||||
|
||||
匹配器继承自 `hamcrest.core.base_matcher.BaseMatcher`,重写两个方法:
|
||||
|
||||
```
|
||||
class DivisibleBy(hamcrest.core.base_matcher.BaseMatcher):
|
||||
def __init__(self, factor):
|
||||
self.factor = factor
|
||||
|
||||
def _matches(self, item):
|
||||
return (item % self.factor) == 0
|
||||
|
||||
def describe_to(self, description):
|
||||
description.append_text('number divisible by')
|
||||
description.append_text(repr(self.factor))
|
||||
```
|
||||
|
||||
编写高质量的 `describe_to` 方法很重要,因为这是测试失败时显示的消息的一部分。
|
||||
|
||||
```
|
||||
def divisible_by(num):
|
||||
return DivisibleBy(num)
|
||||
```
|
||||
|
||||
按照惯例,我们将匹配器包装在一个函数中。有时这给了我们进一步处理输入的机会,但在这种情况下,我们不需要进一步处理。
|
||||
|
||||
```
|
||||
def test_scale():
|
||||
result = scale_one(3, 7)
|
||||
assert_that(result,
|
||||
any_of(divisible_by(3),
|
||||
divisible_by(7)))
|
||||
```
|
||||
|
||||
请注意,我们将 `divisible_by` 匹配器与内置的 `any_of` 匹配器结合起来,以确保我们只测试函数提交的内容。
|
||||
|
||||
在编辑这篇文章时,我听到一个传言,取 “Hamcrest” 这个名字是因为它是 “matches” 字母组成的字谜。嗯...
|
||||
|
||||
```
|
||||
>>> assert_that("matches", contains_inanyorder(*"hamcrest")
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
File "/home/moshez/src/devops-python/build/devops/lib/python3.6/site-packages/hamcrest/core/assert_that.py", line 43, in assert_that
|
||||
_assert_match(actual=arg1, matcher=arg2, reason=arg3)
|
||||
File "/home/moshez/src/devops-python/build/devops/lib/python3.6/site-packages/hamcrest/core/assert_that.py", line 57, in _assert_match
|
||||
raise AssertionError(description)
|
||||
AssertionError:
|
||||
Expected: a sequence over ['h', 'a', 'm', 'c', 'r', 'e', 's', 't'] in any order
|
||||
but: no item matches: 'r' in ['m', 'a', 't', 'c', 'h', 'e', 's']
|
||||
```
|
||||
|
||||
经过进一步的研究,我找到了传言的来源:它是 “matchers” 字母组成的字谜。
|
||||
|
||||
```
|
||||
>>> assert_that("matchers", contains_inanyorder(*"hamcrest"))
|
||||
>>>
|
||||
```
|
||||
|
||||
如果你还没有为你的 Python 代码编写单元测试,那么现在是开始的好时机。如果你正在为你的 Python 代码编写单元测试,那么使用 Hamcrest 将允许你使你的断言更加*精确*,既不会比你想要测试的多也不会少。这将在修改代码时减少误报,并减少修改工作代码的测试所花费的时间。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/8/robust-unit-tests-hamcrest
|
||||
|
||||
作者:[Moshe Zadka][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[MjSeven](https://github.com/MjSeven)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/moshez
|
||||
[1]:https://martinfowler.com/bliki/TestPyramid.html
|
||||
[2]:http://hamcrest.org/
|
||||
[3]:https://www.python.org/
|
@ -0,0 +1,103 @@
|
||||
5 款开源的 Linux 策略模拟游戏
|
||||
======
|
||||
|
||||
> 用这些开源游戏来挑战你的战略技能,探索新世界。
|
||||
|
||||

|
||||
|
||||
长久以来,游戏都是 Linux 的软肋。近些年,Steam、GOG 等游戏发布平台上不少商业游戏都开始支持 Linux,这对于 Linux 的游戏生态来说是件好事,但是我们能在这些平台上玩到的游戏通常是不开源的商业作品。当然,这些游戏在一个开源的操作系统上运行,但对于一个开源提倡者来说这似乎还不够纯粹。
|
||||
|
||||
那么,我们能找到既自由开源又能给玩家带来完整游戏体验的优质游戏吗?当然!虽然绝大多数的开源游戏很难和 3A 商业游戏大作竞争,但仍然有不少各种类型的开源游戏,不仅内容有趣而且直接可以通过几大 Linux 发行版本库中直接安装。就算某个游戏在不在某个发行版本的库中,我们也可以在这个游戏项目的网站上找到直接的安装方法。
|
||||
|
||||
本篇文章将会介绍策略和模拟类游戏。我已经写了[街机游戏][1]、[桌面卡牌游戏][2]、[解谜游戏][3]、[竞速飞行游戏][4]以及[角色扮演游戏][5]。
|
||||
|
||||
### 开源版“文明”(Freeciv)
|
||||
|
||||

|
||||
|
||||
[Freeciv][6] 可以被视为是[文明系列][7]游戏的开源版本。游戏玩法和文明系列最早期的游戏十分类似,Freeciv 可以让玩家选择选用文明 1 或者文明 2 中的游戏规则设置。Freeciv 中包含了很多元素,例如建造城市、探索世界地图、发展科技以及和其他扩张中的文明竞争。胜利条件包括打败所有其他的文明或建立一个外星殖民地,如果在前两者都没有达成的话,在游戏时间期限前存活下来也可以算作胜利。这个游戏可以和其他玩家联机也可以和 AI 对战,不同的地图集可以改变游戏的外观。
|
||||
|
||||
安装 Freeciv,你只需要在终端下运行以下指令。
|
||||
|
||||
* Fedora 用户: `dnf install freeciv`
|
||||
* Debian/Ubuntu 用户:`apt install freeciv`
|
||||
|
||||
### MegaGlest
|
||||
|
||||

|
||||
|
||||
[MegaGlest][8] 是一个开源的实时战略游戏,类似暴雪公司制作的游戏[魔兽世界][9]和[星际争霸][10]。玩家控制不同派别的人员、建造新建筑、招募士兵、拓展领土并与敌人作战。在游戏比赛的最开始,玩家仅能建造最基础的建筑和招募最基础的士兵。为了建造更高级的建筑并招募级别更高的人员,玩家必须通过增加建筑和人员从而一路提高科技树、解锁更加高级的选项。当敌人进入国土领域之中,战斗单元将会迎战。但是最好的应对策略是,通过控制战斗单元直接操控每一场战斗。在管理新建筑的建立,新人员的招募的同时控制战斗局势听上去十分困难,但是这就是 RTS(实时战略游戏)游戏的精华所在。MegaGlest 这个游戏提供了大量的人员派别,玩家可以不断尝试这些不同的技巧。
|
||||
|
||||
安装 MegaGlest,你只需要在终端下运行以下指令:
|
||||
|
||||
* Fedora 用户: `dnf install megaglest`
|
||||
* Debian/Ubuntu 用户:`apt install megaglest`
|
||||
|
||||
### 开源版“运输大亨”(OpenTTD)
|
||||
|
||||

|
||||
|
||||
[OpenTTD][11](见我们的 [评测][12] )是一个开源实现的 [运输大亨][13] 。该游戏的目的在于创建一个交通运输网络并获得金钱,从而建立更加复杂的运输网络。这个运输网络包括了船只、巴士、火车、货车和飞机。默认的游戏时间在 1950 和 2050 之间,玩家的目标就是在规定时间内拿到最高的游戏分数。游戏的最终分数基于很多因素,例如货物运输的数量、玩家所拥有的汽车数量以及他们赚到的钱。
|
||||
|
||||
安装 OpenTTD,你只需要在终端运行以下指令:
|
||||
|
||||
* Fedora 用户: `dnf install openttd`
|
||||
* Debian/Ubuntu 用户 `apt install openttd`
|
||||
|
||||
### <ruby>韦诺之战<rt>The Battle for Wesnoth</rt></ruby>
|
||||
|
||||

|
||||
|
||||
[韦诺之战][14] 是目前最完善的开源游戏之一。这个回合制游戏在一个奇幻的故事设定下。游戏在一个六角形网格中进行,各个单元可以互相操作进行战斗。每个类型的单元都有它独特的能力和弱点,因此玩家需要根据这些特点来设计不同的行动。韦诺之战中有很多不同的行动分支,每个行动分支都有它特别的故事线和目标。韦诺之战同时也有一个地图编辑器,感兴趣的玩家可以创作自己的地图以及行动分支。
|
||||
|
||||
安装韦诺之战,你只需要在终端运行以下指令:
|
||||
|
||||
* Fedora 用户: `dnf install wesnoth`
|
||||
* Debian/Ubuntu 用户: `apt install wesnoth`
|
||||
|
||||
### <ruby>UFO:外星入侵<rt>UFO: Alien Invasion</rt></ruby>
|
||||
|
||||

|
||||
|
||||
[UFO: Alien Invasion][15] 是一个开源策略游戏,基于 <ruby>[幽浮系列][20]<rt>X-COM</rt></ruby>。 有两个不同的游戏模式: geoscape 和 tactical。在 geoscape 模式下,玩家控制大局、管理基地、开发新技术以及掌控整体策略。 在 tactical 游戏模式下,玩家控制一群士兵并且以回合制的形式直接迎战外星侵略者。两个游戏模式提供了不同的游戏玩法,两者都需要相当复杂的策略和战术。
|
||||
|
||||
安装这个游戏,你只需要在终端下运行以下指令:
|
||||
|
||||
* Debian/Ubuntu 用户: `apt install ufoai`
|
||||
|
||||
遗憾的是,UFO: 外星入寝不支持 Fedora 发行版。
|
||||
|
||||
如果你知道除了这些以外的开源策略模拟游戏的话,欢迎在评论中分享。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/8/strategy-simulation-games-linux
|
||||
|
||||
作者:[Joshua Allen Holm][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[Scoutydren](https://github.com/Scoutydren)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/holmja
|
||||
[1]:https://linux.cn/article-10433-1.html
|
||||
[2]:https://opensource.com/article/18/3/card-board-games-linux
|
||||
[3]:https://opensource.com/article/18/6/puzzle-games-linux
|
||||
[4]:https://opensource.com/article/18/7/racing-flying-games-linux
|
||||
[5]:https://opensource.com/article/18/8/role-playing-games-linux
|
||||
[6]:http://www.freeciv.org/
|
||||
[7]:https://en.wikipedia.org/wiki/Civilization_(series)
|
||||
[8]:https://megaglest.org/
|
||||
[9]:https://en.wikipedia.org/wiki/Warcraft
|
||||
[10]:https://en.wikipedia.org/wiki/StarCraft
|
||||
[11]:https://www.openttd.org/
|
||||
[12]:https://opensource.com/life/15/7/linux-game-review-openttd
|
||||
[13]:https://en.wikipedia.org/wiki/Transport_Tycoon#Transport_Tycoon_Deluxe
|
||||
[14]:https://www.wesnoth.org/
|
||||
[15]:https://ufoai.org/
|
||||
[16]:https://opensource.com/downloads/cheat-sheets?intcmp=7016000000127cYAAQ
|
||||
[17]:https://opensource.com/alternatives?intcmp=7016000000127cYAAQ
|
||||
[18]:https://opensource.com/tags/linux?intcmp=7016000000127cYAAQ
|
||||
[19]:https://developers.redhat.com/cheat-sheets/advanced-linux-commands/?intcmp=7016000000127cYAAQ
|
||||
[20]:https://en.wikipedia.org/wiki/X-COM
|
79
published/20180919 5 ways DevSecOps changes security.md
Normal file
79
published/20180919 5 ways DevSecOps changes security.md
Normal file
@ -0,0 +1,79 @@
|
||||
|
||||
DevSecOps 提升安全性的五种方式
|
||||
======
|
||||
|
||||
> 安全必须进化以跟上当今的应用开发和部署方式。
|
||||
|
||||

|
||||
|
||||
对于我们是否需要扩展 DevOps 以确实提升安全性,我们一直都有争议。毕竟,我们认为,DevOps 一直是一系列的新实践的简写,使用新工具(通常是开源的)并且在这之上构建更多的协作文化。为什么 [DevBizOps][3] 不能更好地满足商业的需求?或者说 DevChatOps 强调的是更快更好的沟通?
|
||||
|
||||
然而,如 [John Willis][4] 在今年(LCTT 译注:此处是 2018 年)的早些时候写的关于他对 [DevSecOps][5] 术语的理解,“我希望,有一天我们能在任何地方都不再使用 DevSecOps 这个词,安全会是所有关于服务交付的讨论中理所应当的部分。在那一天到来前,在这一点上,我的一般性结论是,这个词只是三个新的特性而已。更重要的是,我们作为一个产业,在信息安全方面并没有做的很好,而这个名称切实地区分出了问题的状况。”
|
||||
|
||||
所以,为什么我们在[信息安全][6]方面做的不好,在 DevSecOps 的语境下安全做的好又是什么意思呢?
|
||||
|
||||
尽管(也可能是因为)庞大的复杂行业的单点产品解决了特定方面的问题,但我们可以说是从未做好过信息安全。我们仍然可以在这个时代把工作做得足够好,以此来防范威胁,这些威胁主要集中在一个范围内,网络的连接是受限的,而且大多数的用户都是公司的员工,使用的是公司提供的设备。
|
||||
|
||||
这些年来,这些情况并没有能准确地描述出大多数组织的真实现状。但在现在这个时代,不止引入了 DevSecOps,也同时引入了新的应用架构模型、开发实践,和越来越多的安全威胁,这些一起定义了一个需要更快迭代的新常态。与其说 DevSecOps 孤立地改变了安全,不如说信息安全公司在 2018 年需要新的方法。
|
||||
|
||||
请仔细思考下面这五个领域。
|
||||
|
||||
### 自动化
|
||||
|
||||
大量的自动化通常是 DevOps 的标志,这部分是关于速度的,如果你要快速变化(并且不会造成破坏),你需要有可重复的过程,而且这个过程不需要太多的人工干预。实际上,自动化是 DevOps 最好的切入点之一,甚至是在仍然主要使用老式的<ruby>独石应用<rt>monolithic app</rt></ruby>的组织里也是如此。使用像 Ansible 这样易于使用的工具来自动化地处理相关的配置或者是测试,这是快速开始 DevOps 之路的常用方法。
|
||||
|
||||
DevSecOps 也不例外,在今天,安全已经变成了一个持续性的过程,而不是在应用的生命周期里进行不定期的检查,甚至是每周、每月的检查。当漏洞被厂商发现并修复的时候,这些修复能被快速地应用是很重要的,这样对这些漏洞的利用程序很快就会被淘汰。
|
||||
|
||||
### “左移”
|
||||
|
||||
在开发流程结束时,传统的安全通常被视作一个守门人。检查所有的部分确保没有问题,然后这个应用程序就可以投入生产了。否则,就要再来一次。安全小组以说“不”而闻名。
|
||||
|
||||
因此,我们想的是,为什么不把安全这个部分提到前面呢(在一个典型的从左到右的开发流程图的“左边”)?安全团队仍然可以说“不”,但在开发的早期进行重构的影响要远远小于开发已经完成并且准备上线时进行重构的影响。
|
||||
|
||||
不过,我不喜欢“左移”这个词,这意味着安全仍然是一个只不过提前进行的一次性工作。在应用程序的整个生命周期里,从供应链到开发,再到测试,直到上线部署,安全都需要进行大量的自动化处理。
|
||||
|
||||
### 管理依赖
|
||||
|
||||
我们在现代应用程序开发过程中看到的一个最大的改变,就是你通常不需要去编写这个程序的大部分代码。使用开源的函数库和框架就是一个明显的例子。而且你也可以从公共的云服务商或其他来源那里获得额外的服务。在许多情况下,这些额外的代码和服务比你给自己写的要好得多。
|
||||
|
||||
因此,DevSecOps 需要你把重点放在你的[软件供应链][8]上,你是从可信的来源那里获取你的软件的吗?这些软件是最新的吗?它们已经集成到了你为自己的代码所使用的安全流程中了吗?对于这些你能使用的代码和 API 你有哪些策略?你为自己的产品代码使用的组件是否有可用的商业支持?
|
||||
|
||||
没有一套标准答案可以应对所有的情况。对于概念验证和大规模的生产,它们可能会有所不同。但是,正如制造业长期存在的情况(DevSecOps 和制造业的发展方面有许多相似之处),供应链的可信是至关重要的。
|
||||
|
||||
### 可见性
|
||||
|
||||
关于贯穿应用程序整个生命周期里所有阶段的自动化的需求,我已经谈过很多了。这里假设我们能看见每个阶段里发生的情况。
|
||||
|
||||
有效的 DevSecOps 需要有效的检测,以便于自动化程序知道要做什么。这个检测分了很多类别。一些长期的和高级别的指标能帮助我们了解整个 DevSecOps 流程是否工作良好。严重威胁级别的警报需要立刻有人进行处理(安全扫描系统已经关闭!)。有一些警报,比如扫描失败,需要进行修复。我们记录了许多参数的志以便事后进行分析(随着时间的推移,哪些发生了改变?导致失败的原因是什么?)。
|
||||
|
||||
### 分散服务 vs 一体化解决方案
|
||||
|
||||
虽然 DevSecOps 实践可以应用于多种类型的应用架构,但它们对小型且松散耦合的组件最有效,这些组件可以进行更新和复用,而且不会在应用程序的其他地方进行强制更改。在纯净版的形式里,这些组件可以是微服务或者函数,但是这个一般性原则适用于通过网络进行通信的松散耦合服务的任何地方。
|
||||
|
||||
这种方法确实带来了一些新的安全挑战,组件之间的交互可能会很复杂,总的攻击面会更大,因为现在应用程序通过网络有了更多的切入点。
|
||||
|
||||
另一方面,这种类型的架构还意味着自动化的安全和监视可以更加精细地查看应用程序的组件,因为它们不再深埋在一个独石应用程序之中。
|
||||
|
||||
不要过多地关注 DevSecOps 这个术语,但要提醒一下,安全正在不断地演变,因为我们编写和部署程序的方式也在不断地演变。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/9/devsecops-changes-security
|
||||
|
||||
作者:[Gordon Haff][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[hopefully2333](https://github.com/hopefully2333)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ghaff
|
||||
[1]: https://opensource.com/resources/devops
|
||||
[2]: https://opensource.com/tags/devops
|
||||
[3]: https://opensource.com/article/18/5/steps-apply-devops-culture-beyond-it
|
||||
[4]: https://www.devsecopsdays.com/articles/its-just-a-name
|
||||
[5]: https://opensource.com/article/18/4/devsecops
|
||||
[6]: https://opensource.com/article/18/6/where-cycle-security-devops
|
||||
[7]: https://opensource.com/tags/ansible
|
||||
[8]: https://opensource.com/article/17/1/be-open-source-supply-chain
|
||||
[9]: https://opensource.com/tags/microservices
|
@ -0,0 +1,128 @@
|
||||
dbxfs:在 Linux 中本地挂载 Dropbox 文件夹
|
||||
======
|
||||
|
||||

|
||||
|
||||
不久前,我们总结了所有 [在本地挂载 Google Drive][1] 作为虚拟文件系统,并从 Linux 系统访问存储在 Google Drive 中的文件的方法。今天,我们将学习使用 `dbxfs` 将 Dropbox 文件夹挂载到本地文件系统中。`dbxfs` 用于在类 Unix 操作系统中本地挂载 Dropbox 文件夹作为虚拟文件系统。虽然在 Linux 中很容易[安装 Dropbox 客户端][2],但这种方法与官方方法略有不同。它是一个命令行 dropbox 客户端,且无需磁盘空间即可访问。`dbxfs` 是自由开源的,并且是用 Python 3.5+ 编写的。
|
||||
|
||||
### 安装 dbxfs
|
||||
|
||||
`dbxfs` 官方支持 Linux 和 Mac OS。但是,它应该适用于任何提供 **FUSE 兼容库**或能够挂载 SMB 共享的 POSIX 系统。由于它是用 Python 3.5 编写的,因此可以使用 pip3 包管理器进行安装。如果尚未安装 pip,请参阅以下指南。
|
||||
|
||||
- [如何使用 pip 管理 Python 包][13]
|
||||
|
||||
并且也要安装 FUSE 库。
|
||||
|
||||
在基于 Debian 的系统上,运行以下命令以安装 FUSE:
|
||||
|
||||
```
|
||||
$ sudo apt install libfuse2
|
||||
```
|
||||
|
||||
在 Fedora 上:
|
||||
|
||||
```
|
||||
$ sudo dnf install fuse
|
||||
```
|
||||
|
||||
安装完所有必需的依赖项后,运行以下命令以安装 `dbxfs`:
|
||||
|
||||
```
|
||||
$ pip3 install dbxfs
|
||||
```
|
||||
|
||||
### 在本地挂载 Dropbox 文件夹
|
||||
|
||||
创建一个挂载点以将 Dropbox 文件夹挂载到本地文件系统中。
|
||||
|
||||
```
|
||||
$ mkdir ~/mydropbox
|
||||
```
|
||||
|
||||
然后,使用 `dbxfs` 在本地挂载 dropbox 文件夹,如下所示:
|
||||
|
||||
```
|
||||
$ dbxfs ~/mydropbox
|
||||
```
|
||||
|
||||
你将被要求生成一个访问令牌:
|
||||
|
||||

|
||||
|
||||
要生成访问令牌,只需在 Web 浏览器中输入上面输出的 URL,然后单击 **允许** 以授权 Dropbox 访问。你需要登录 Dropbox 帐户才能完成授权过程。
|
||||
|
||||
下一个页面将生成新的授权码。复制代码并返回终端将其粘贴到 cli-dbxfs 提示符中以完成该过程。
|
||||
|
||||
然后,系统会要求你保存凭据以供将来访问。根据你是要保存还是拒绝,输入 `Y` 或 `N`。然后,你需要为新的访问令牌输入两次密码。
|
||||
|
||||
最后,输入 `Y` 接受 `/home/username/mydropbox` 作为默认挂载点。如果你要设置不同的路径,输入 `N` 并输入你选择的位置。
|
||||
|
||||
![Generate access token 2][4]
|
||||
|
||||
完成了!从现在开始,你可以看到你的 Dropbox 文件夹已挂载到本地文件系统中。
|
||||
|
||||

|
||||
|
||||
### 更改访问令牌存储路径
|
||||
|
||||
默认情况下,`dbxfs` 会将 Dropbox 访问令牌存储在系统密钥环或加密文件中。但是,你可能希望将其存储在 gpg 加密文件或其他地方。如果是这样,请在 [Dropbox 开发者应用控制台][5]上创建个人应用来获取访问令牌。
|
||||
|
||||

|
||||
|
||||
创建应用后,单击下一步中的**生成**按钮。此令牌可用于通过 API 访问你的 Dropbox 帐户。不要与任何人共享你的访问令牌。
|
||||
|
||||

|
||||
|
||||
创建访问令牌后,使用任何你选择的加密工具对其进行加密,例如 [Cryptomater][6]、[Cryptkeeper][7]、[CryptGo][8]、[Cryptr][9]、[Tomb][10]、[Toplip][11] 和 [**GnuPG][12] 等,并在你喜欢的位置保存。
|
||||
|
||||
接下来编辑 dbxfs 配置文件并添加以下行:
|
||||
|
||||
```
|
||||
"access_token_command": ["gpg", "--decrypt", "/path/to/access/token/file.gpg"]
|
||||
```
|
||||
|
||||
你可以通过运行以下命令找到 dbxfs 配置文件:
|
||||
|
||||
```
|
||||
$ dbxfs --print-default-config-file
|
||||
```
|
||||
|
||||
有关更多详细信息,请参阅 dbxfs 帮助:
|
||||
|
||||
```
|
||||
$ dbxfs -h
|
||||
```
|
||||
|
||||
如你所见,使用 `dbxfs` 在你的文件系统中本地挂载 Dropfox 文件夹并不复杂。经过测试,`dbxfs` 如常工作。如果你有兴趣了解它是如何工作的,请尝试一下,并在下面的评论栏告诉我们你的体验。
|
||||
|
||||
就是这些了。希望这篇文章有用。还有更多好东西。敬请期待!
|
||||
|
||||
干杯!
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/dbxfs-mount-dropbox-folder-locally-as-virtual-file-system-in-linux/
|
||||
|
||||
作者:[SK][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.ostechnix.com/author/sk/
|
||||
[1]: https://www.ostechnix.com/how-to-mount-google-drive-locally-as-virtual-file-system-in-linux/
|
||||
[2]: https://www.ostechnix.com/install-dropbox-in-ubuntu-18-04-lts-desktop/
|
||||
[3]: data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[4]: http://www.ostechnix.com/wp-content/uploads/2018/10/Generate-access-token-2.png
|
||||
[5]: https://dropbox.com/developers/apps
|
||||
[6]: https://www.ostechnix.com/cryptomator-open-source-client-side-encryption-tool-cloud/
|
||||
[7]: https://www.ostechnix.com/how-to-encrypt-your-personal-foldersdirectories-in-linux-mint-ubuntu-distros/
|
||||
[8]: https://www.ostechnix.com/cryptogo-easy-way-encrypt-password-protect-files/
|
||||
[9]: https://www.ostechnix.com/cryptr-simple-cli-utility-encrypt-decrypt-files/
|
||||
[10]: https://www.ostechnix.com/tomb-file-encryption-tool-protect-secret-files-linux/
|
||||
[11]: https://www.ostechnix.com/toplip-strong-file-encryption-decryption-cli-utility/
|
||||
[12]: https://www.ostechnix.com/an-easy-way-to-encrypt-and-decrypt-files-from-commandline-in-linux/
|
||||
[13]:https://www.ostechnix.com/manage-python-packages-using-pip/
|
@ -1,12 +1,12 @@
|
||||
最终的 JOS 项目
|
||||
Caffeinated 6.828:实验 7:最终的 JOS 项目
|
||||
======
|
||||
|
||||
### 简介
|
||||
|
||||
对于最后的项目,你有两个选择:
|
||||
|
||||
* 继续使用你自己的 JOS 内核并做 [实验 6][1],包括实验 6 中的一个挑战问题。(你可以随意地、以任何有趣的方式去扩展实验 6 或者 JOS 的任何部分,当然了,这不是课程规定的。)
|
||||
|
||||
* 在一个、二个或三个人组成的团队中,你选择去做一个涉及了你的 JOS 的项目。这个项目必须是涉及到与实验 6 相同或更大的(如果你是团队中的一员)领域。
|
||||
* 在一个、二个或三个人组成的团队中,你选择去做一个涉及了你的 JOS 的项目。这个项目必须是涉及到与实验 6 相同或更大的领域(如果你是团队中的一员)。
|
||||
|
||||
目标是为了获得乐趣或探索更高级的 O/S 的话题;你不需要做最新的研究。
|
||||
|
||||
@ -16,70 +16,48 @@
|
||||
|
||||
### 交付期限
|
||||
|
||||
```
|
||||
11 月 3 日:Piazza 讨论和 1、2、或 3 年级组选择(根据你的最终选择来定)。使用在 Piazza 上的 lab7 标记/目录。在 Piazza 上的文章评论区与其它人计论想法。使用这些文章帮你去找到有类似想法的其它学生一起组建一个小组。课程的教学人员将在 Piazza 上为你的项目想法给出反馈;如果你想得到更详细的反馈,可以与我们单独讨论。
|
||||
```
|
||||
> 11 月 3 日:Piazza 讨论和 1、2、或 3 年级组选择(根据你的最终选择来定)。使用在 Piazza 上的 lab7 标记/目录。在 Piazza 上的文章评论区与其它人计论想法。使用这些文章帮你去找到有类似想法的其它学生一起组建一个小组。课程的教学人员将在 Piazza 上为你的项目想法给出反馈;如果你想得到更详细的反馈,可以与我们单独讨论。
|
||||
|
||||
```markdown
|
||||
11 月 9 日:在 [提交网站][19] 上提交一个提议,只需要一到两个段落就可以。提议要包括你的小组成员列表、你的计划、以及明确的设计和实现打算。(如果你做实验 6,就不用做这个了)
|
||||
```
|
||||
.
|
||||
|
||||
```markdown
|
||||
12 月 7 日:和你的简短报告一起提交源代码。将你的报告放在与名为 "README.pdf" 的文件相同的目录下。由于你只是这个实验任务小组中的一员,你可能需要去使用 git 在小组成员之间共享你的项目代码。因此你需要去决定哪些源代码将作为你的小组项目的共享起始点。一定要为你的最终项目去创建一个分支,并且命名为 `lab7`。(如果你做了实验 6,就按实验 6 的提交要求做即可。)
|
||||
```
|
||||
> 11 月 9 日:在 [提交网站][19] 上提交一个提议,只需要一到两个段落就可以。提议要包括你的小组成员列表、你的计划、以及明确的设计和实现打算。(如果你做实验 6,就不用做这个了)
|
||||
|
||||
```
|
||||
12 月 11 日这一周:简短的课堂演示。为你的 JOS 项目准备一个简短的课堂演示。为了你的项目演示,我们将提供一个投影仪。根据小组数量和每个小组选择的项目类型,我们可能会限制总的演讲数,并且有些小组可能最终没有机会上台演示。
|
||||
```
|
||||
.
|
||||
|
||||
```
|
||||
12 月 11 日这一周:助教们验收。向助教演示你的项目,因此我们可能会提问一些问题,去了解你所做的一些细节。
|
||||
```
|
||||
> 12 月 7 日:和你的简短报告一起提交源代码。将你的报告放在与名为 “README.pdf” 的文件相同的目录下。由于你只是这个实验任务小组中的一员,你可能需要去使用 git 在小组成员之间共享你的项目代码。因此你需要去决定哪些源代码将作为你的小组项目的共享起始点。一定要为你的最终项目去创建一个分支,并且命名为 `lab7`。(如果你做了实验 6,就按实验 6 的提交要求做即可。)
|
||||
|
||||
.
|
||||
|
||||
> 12 月 11 日这一周:简短的课堂演示。为你的 JOS 项目准备一个简短的课堂演示。为了你的项目演示,我们将提供一个投影仪。根据小组数量和每个小组选择的项目类型,我们可能会限制总的演讲数,并且有些小组可能最终没有机会上台演示。
|
||||
|
||||
.
|
||||
|
||||
> 12 月 11 日这一周:助教们验收。向助教演示你的项目,因此我们可能会提问一些问题,去了解你所做的一些细节。
|
||||
|
||||
### 项目想法
|
||||
|
||||
如果你不做实验 6,下面是一个启迪你的想法列表。但是,你应该大胆地去实现你自己的想法。其中一些想法只是一个开端,并且本身不在实验 6 的领域内,并且其它的可能是在更大的领域中。
|
||||
|
||||
* 使用 [x86 虚拟机支持][2] 去构建一个能够运行多个访客系统(比如,多个 JOS 实例)的虚拟机监视器。
|
||||
|
||||
* 使用 Intel SGX 硬件保护机制做一些有用的事情。[这是使用 Intel SGX 的最新的论文][3]。
|
||||
|
||||
* 让 JOS 文件系统支持写入、文件创建、为持久性使用日志、等等。或许你可以从 Linux EXT3 上找到一些启示。
|
||||
|
||||
* 从 [软更新][4]、[WAFL][5]、ZFS、或其它较高级的文件系统上找到一些使用文件系统的想法。
|
||||
|
||||
* 给一个文件系统添加快照功能,以便于用户能够查看过去的多个时间点上的文件系统。为了降低空间使用量,你或许要使用一些写时复制技术。
|
||||
|
||||
* 使用分页去提供实时共享的内存,来构建一个 [分布式的共享内存][6](DSM)系统,以便于你在一个机器集群上运行多线程的共享内存的并行程序。当一个线程尝试去访问位于另外一个机器上的页时,页故障将给 DSM 系统提供一个机会,让它基于网络去从当前存储这个页的任意一台机器上获取这个页。
|
||||
|
||||
* 允许进程在机器之间基于网络进行迁移。你将需要做一些关于一个进程状态的多个片段方面的事情,但是由于在 JOS 中许多状态是在用户空间中,它或许从 Linux 上的进程迁移要容易一些。
|
||||
|
||||
* 在 JOS 中实现 [分页][7] 到磁盘,这样那个进程使用的内存就可以大于真实的内存。使用交换空间去扩展你的内存。
|
||||
|
||||
* 为 JOS 实现文件的 [mmap()][8]。
|
||||
|
||||
* 使用 [xfi][9] 将一个进程的代码沙箱化。
|
||||
|
||||
* 支持 x86 的 [2MB 或 4MB 的页大小][10]。
|
||||
|
||||
* 修改 JOS 让内核支持进程内的线程。从查看 [课堂上的 uthread 任务][11] 去开始。实现调度器触发将是实现这个项目的一种方式。
|
||||
|
||||
* 在 JOS 的内核中或文件系统中(实现多线程之后),使用细粒度锁或无锁并发。Linux 内核使用 [读复制更新][12] 去执行无需上锁的读取操作。通过在 JOS 中实现它来探索 RCU,并使用它去支持无锁读取的名称缓存。
|
||||
|
||||
* 实现 [外内核论文][13] 中的想法。例如包过滤器。
|
||||
|
||||
* 使 JOS 拥有软实时行为。用它来辨识一些应用程序时非常有用。
|
||||
|
||||
* 使 JOS 运行在 64 位 CPU 上。这包括重设计虚拟内存让它使用 4 级页表。有关这方面的文档,请查看 [参考页][14]。
|
||||
|
||||
* 移植 JOS 到一个不同的微处理器。这个 [osdev wiki][15] 或许对你有帮助。
|
||||
|
||||
* 为 JOS 系统增加一个“窗口”系统,包括图形驱动和鼠标。有关这方面的文档,请查看 [参考页][16]。[sqrt(x)][17] 就是一个 JOS “窗口” 系统的示例。
|
||||
|
||||
* 在 JOS 中实现 [dune][18],以提供特权硬件指令给用户空间应用程序。
|
||||
|
||||
* 写一个用户级调试器,添加类似跟踪的功能;硬件寄存器概要(即:Oprofile);调用跟踪等等。
|
||||
|
||||
* 为(静态的)Linux 可运行程序做一个二进制仿真。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
@ -89,7 +67,7 @@ via: https://pdos.csail.mit.edu/6.828/2018/labs/lab7/
|
||||
作者:[csail.mit][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,67 +1,66 @@
|
||||
实验 6:网络驱动程序
|
||||
Caffeinated 6.828:实验 6:网络驱动程序
|
||||
======
|
||||
### 实验 6:网络驱动程序(缺省的最终设计)
|
||||
|
||||
### 简介
|
||||
|
||||
这个实验是缺省的最终项目中你自己能够做的最后的实验。
|
||||
这个实验是默认你能够自己完成的最终项目。
|
||||
|
||||
现在你有了一个文件系统,一个典型的操作系统都应该有一个网络栈。在本实验中,你将继续为一个网卡去写一个驱动程序。这个网卡基于 Intel 82540EM 芯片,也就是众所周知的 E1000 芯片。
|
||||
现在你已经有了一个文件系统,一个典型的操作系统都应该有一个网络栈。在本实验中,你将继续为一个网卡去写一个驱动程序。这个网卡基于 Intel 82540EM 芯片,也就是众所周知的 E1000 芯片。
|
||||
|
||||
##### 预备知识
|
||||
#### 预备知识
|
||||
|
||||
使用 Git 去提交你的实验 5 的源代码(如果还没有提交的话),获取课程仓库的最新版本,然后创建一个名为 `lab6` 的本地分支,它跟踪我们的远程分支 `origin/lab6`:
|
||||
|
||||
```c
|
||||
athena% cd ~/6.828/lab
|
||||
athena% add git
|
||||
athena% git commit -am 'my solution to lab5'
|
||||
nothing to commit (working directory clean)
|
||||
athena% git pull
|
||||
Already up-to-date.
|
||||
athena% git checkout -b lab6 origin/lab6
|
||||
Branch lab6 set up to track remote branch refs/remotes/origin/lab6.
|
||||
Switched to a new branch "lab6"
|
||||
athena% git merge lab5
|
||||
Merge made by recursive.
|
||||
fs/fs.c | 42 +++++++++++++++++++
|
||||
1 files changed, 42 insertions(+), 0 deletions(-)
|
||||
athena%
|
||||
athena% cd ~/6.828/lab
|
||||
athena% add git
|
||||
athena% git commit -am 'my solution to lab5'
|
||||
nothing to commit (working directory clean)
|
||||
athena% git pull
|
||||
Already up-to-date.
|
||||
athena% git checkout -b lab6 origin/lab6
|
||||
Branch lab6 set up to track remote branch refs/remotes/origin/lab6.
|
||||
Switched to a new branch "lab6"
|
||||
athena% git merge lab5
|
||||
Merge made by recursive.
|
||||
fs/fs.c | 42 +++++++++++++++++++
|
||||
1 files changed, 42 insertions(+), 0 deletions(-)
|
||||
athena%
|
||||
```
|
||||
|
||||
然后,仅有网卡驱动程序并不能够让你的操作系统接入因特网。在新的实验 6 的代码中,我们为你提供了网络栈和一个网络服务器。与以前的实验一样,使用 git 去拉取这个实验的代码,合并到你自己的代码中,并去浏览新的 `net/` 目录中的内容,以及在 `kern/` 中的新文件。
|
||||
然后,仅有网卡驱动程序并不能够让你的操作系统接入互联网。在新的实验 6 的代码中,我们为你提供了网络栈和一个网络服务器。与以前的实验一样,使用 git 去拉取这个实验的代码,合并到你自己的代码中,并去浏览新的 `net/` 目录中的内容,以及在 `kern/` 中的新文件。
|
||||
|
||||
除了写这个驱动程序以外,你还需要去创建一个访问你的驱动程序的系统调用。你将要去实现那些在网络服务器中缺失的代码,以便于在网络栈和你的驱动程序之间传输包。你还需要通过完成一个 web 服务器来将所有的东西连接到一起。你的新 web 服务器还需要你的文件系统来提供所需要的文件。
|
||||
|
||||
大部分的内核设备驱动程序代码都需要你自己去从头开始编写。本实验提供的指导比起前面的实验要少一些:没有框架文件、没有现成的系统调用接口、并且很多设计都由你自己决定。因此,我们建议你在开始任何单独练习之前,阅读全部的编写任务。许多学生都反应这个实验比前面的实验都难,因此请根据你的实际情况计划你的时间。
|
||||
|
||||
##### 实验要求
|
||||
#### 实验要求
|
||||
|
||||
与以前一样,你需要做实验中全部的常规练习和至少一个挑战问题。在实验中写出你的详细答案,并将挑战问题的方案描述写入到 `answers-lab6.txt` 文件中。
|
||||
|
||||
#### QEMU 的虚拟网络
|
||||
### QEMU 的虚拟网络
|
||||
|
||||
我们将使用 QEMU 的用户模式网络栈,因为它不需要以管理员权限运行。QEMU 的文档的[这里][1]有更多关于用户网络的内容。我们更新后的 makefile 启用了 QEMU 的用户模式网络栈和虚拟的 E1000 网卡。
|
||||
|
||||
缺省情况下,QEMU 提供一个运行在 IP 地址 10.2.2.2 上的虚拟路由器,它给 JOS 分配的 IP 地址是 10.0.2.15。为了简单起见,我们在 `net/ns.h` 中将这些缺省值硬编码到网络服务器上。
|
||||
|
||||
虽然 QEMU 的虚拟网络允许 JOS 随意连接因特网,但 JOS 的 10.0.2.15 的地址并不能在 QEMU 中的虚拟网络之外使用(也就是说,QEMU 还得做一个 NAT),因此我们并不能直接连接到 JOS 上运行的服务器,即便是从运行 QEMU 的主机上连接也不行。为解决这个问题,我们配置 QEMU 在主机的某些端口上运行一个服务器,这个服务器简单地连接到 JOS 中的一些端口上,并在你的真实主机和虚拟网络之间传递数据。
|
||||
虽然 QEMU 的虚拟网络允许 JOS 随意连接互联网,但 JOS 的 10.0.2.15 的地址并不能在 QEMU 中的虚拟网络之外使用(也就是说,QEMU 还得做一个 NAT),因此我们并不能直接连接到 JOS 上运行的服务器,即便是从运行 QEMU 的主机上连接也不行。为解决这个问题,我们配置 QEMU 在主机的某些端口上运行一个服务器,这个服务器简单地连接到 JOS 中的一些端口上,并在你的真实主机和虚拟网络之间传递数据。
|
||||
|
||||
你将在端口 7(echo)和端口 80(http)上运行 JOS,为避免在共享的 Athena 机器上发生冲突,makefile 将为这些端口基于你的用户 ID 来生成转发端口。你可以运行 `make which-ports` 去找出是哪个 QEMU 端口转发到你的开发主机上。为方便起见,makefile 也提供 `make nc-7` 和 `make nc-80`,它允许你在终端上直接与运行这些端口的服务器去交互。(这些目标仅能连接到一个运行中的 QEMU 实例上;你必须分别去启动它自己的 QEMU)
|
||||
|
||||
##### 包检查
|
||||
#### 包检查
|
||||
|
||||
makefile 也可以配置 QEMU 的网络栈去记录所有的入站和出站数据包,并将它保存到你的实验目录中的 `qemu.pcap` 文件中。
|
||||
|
||||
使用 `tcpdump` 命令去获取一个捕获的 hex/ASCII 包转储:
|
||||
|
||||
```
|
||||
tcpdump -XXnr qemu.pcap
|
||||
tcpdump -XXnr qemu.pcap
|
||||
```
|
||||
|
||||
或者,你可以使用 [Wireshark][2] 以图形化界面去检查 pcap 文件。Wireshark 也知道如何去解码和检查成百上千的网络协议。如果你在 Athena 上,你可以使用 Wireshark 的前辈:ethereal,它运行在加锁的保密互联网协议网络中。
|
||||
|
||||
##### 调试 E1000
|
||||
#### 调试 E1000
|
||||
|
||||
我们非常幸运能够去使用仿真硬件。由于 E1000 是在软件中运行的,仿真的 E1000 能够给我们提供一个人类可读格式的报告、它的内部状态以及它遇到的任何问题。通常情况下,对祼机上做驱动程序开发的人来说,这是非常难能可贵的。
|
||||
|
||||
@ -78,15 +77,15 @@ E1000 能够产生一些调试输出,因此你可以去打开一个专门的
|
||||
| eeprom | 读取 EEPROM 的日志 |
|
||||
| interrupt | 中断和中断寄存器变更日志 |
|
||||
|
||||
例如,你可以使用 `make E1000_DEBUG=tx,txerr` 去打开 "tx" 和 "txerr" 日志功能。
|
||||
例如,你可以使用 `make E1000_DEBUG=tx,txerr` 去打开 “tx” 和 “txerr” 日志功能。
|
||||
|
||||
注意:`E1000_DEBUG` 标志仅能在打了 6.828 补丁的 QEMU 版本上工作。
|
||||
|
||||
你可以使用软件去仿真硬件,来做进一步的调试工作。如果你使用它时卡壳了,不明白为什么 E1000 没有如你预期那样响应你,你可以查看在 `hw/e1000.c` 中的 QEMU 的 E1000 实现。
|
||||
|
||||
#### 网络服务器
|
||||
### 网络服务器
|
||||
|
||||
从头开始写一个网络栈是很困难的。因此我们将使用 lwIP,它是一个开源的、轻量级 TCP/IP 协议套件,它能做包括一个网络栈在内的很多事情。你能在 [这里][3] 找到很多关于 IwIP 的信息。在这个任务中,对我们而言,lwIP 就是一个实现了一个 BSD 套接字接口和拥有一个包输入端口和包输出端口的黑盒子。
|
||||
从头开始写一个网络栈是很困难的。因此我们将使用 lwIP,它是一个开源的、轻量级 TCP/IP 协议套件,它能做包括一个网络栈在内的很多事情。你能在 [这里][3] 找到很多关于 lwIP 的信息。在这个任务中,对我们而言,lwIP 就是一个实现了一个 BSD 套接字接口和拥有一个包输入端口和包输出端口的黑盒子。
|
||||
|
||||
一个网络服务器其实就是一个有以下四个环境的混合体:
|
||||
|
||||
@ -95,59 +94,53 @@ E1000 能够产生一些调试输出,因此你可以去打开一个专门的
|
||||
* 输出环境
|
||||
* 定时器环境
|
||||
|
||||
|
||||
|
||||
下图展示了各个环境和它们之间的关系。下图展示了包括设备驱动的整个系统,我们将在后面详细讲到它。在本实验中,你将去实现图中绿色高亮的部分。
|
||||
|
||||
![Network server architecture][4]
|
||||
|
||||
##### 核心网络服务器环境
|
||||
#### 核心网络服务器环境
|
||||
|
||||
核心网络服务器环境由套接字调用派发器和 IwIP 自身组成的。套接字调用派发器就像一个文件服务器一样。用户环境使用 stubs(可以在 `lib/nsipc.c` 中找到它)去发送 IPC 消息到核心网络服务器环境。如果你看了 `lib/nsipc.c`,你就会发现核心网络服务器与我们创建的文件服务器 `i386_init` 的工作方式是一样的,`i386_init` 是使用 NS_TYPE_NS 创建的 NS 环境,因此我们检查 `envs`,去查找这个特殊的环境类型。对于每个用户环境的 IPC,网络服务器中的派发器将调用相应的、由 IwIP 提供的、代表用户的 BSD 套接字接口函数。
|
||||
核心网络服务器环境由套接字调用派发器和 lwIP 自身组成的。套接字调用派发器就像一个文件服务器一样。用户环境使用 stubs(可以在 `lib/nsipc.c` 中找到它)去发送 IPC 消息到核心网络服务器环境。如果你看了 `lib/nsipc.c`,你就会发现核心网络服务器与我们创建的文件服务器 `i386_init` 的工作方式是一样的,`i386_init` 是使用 NS_TYPE_NS 创建的 NS 环境,因此我们检查 `envs`,去查找这个特殊的环境类型。对于每个用户环境的 IPC,网络服务器中的派发器将调用相应的、由 lwIP 提供的、代表用户的 BSD 套接字接口函数。
|
||||
|
||||
普通用户环境不能直接使用 `nsipc_*` 调用。而是通过在 `lib/sockets.c` 中的函数来使用它们,这些函数提供了基于文件描述符的套接字 API。以这种方式,用户环境通过文件描述符来引用套接字,就像它们引用磁盘上的文件一样。一些操作(`connect`、`accept`、等等)是特定于套接字的,但 `read`、`write`、和 `close` 是通过 `lib/fd.c` 中一般的文件描述符设备派发代码的。就像文件服务器对所有的打开的文件维护唯一的内部 ID 一样,lwIP 也为所有的打开的套接字生成唯一的 ID。不论是文件服务器还是网络服务器,我们都使用存储在 `struct Fd` 中的信息去映射每个环境的文件描述符到这些唯一的 ID 空间上。
|
||||
普通用户环境不能直接使用 `nsipc_*` 调用。而是通过在 `lib/sockets.c` 中的函数来使用它们,这些函数提供了基于文件描述符的套接字 API。以这种方式,用户环境通过文件描述符来引用套接字,就像它们引用磁盘上的文件一样。一些操作(`connect`、`accept` 等等)是特定于套接字的,但 `read`、`write` 和 `close` 是通过 `lib/fd.c` 中一般的文件描述符设备派发代码的。就像文件服务器对所有的打开的文件维护唯一的内部 ID 一样,lwIP 也为所有的打开的套接字生成唯一的 ID。不论是文件服务器还是网络服务器,我们都使用存储在 `struct Fd` 中的信息去映射每个环境的文件描述符到这些唯一的 ID 空间上。
|
||||
|
||||
尽管看起来文件服务器的网络服务器的 IPC 派发器行为是一样的,但它们之间还有很重要的差别。BSD 套接字调用(像 `accept` 和 `recv`)能够无限期阻塞。如果派发器让 lwIP 去执行其中一个调用阻塞,派发器也将被阻塞,并且在整个系统中,同一时间只能有一个未完成的网络调用。由于这种情况是无法接受的,所以网络服务器使用用户级线程以避免阻塞整个服务器环境。对于每个入站 IPC 消息,派发器将创建一个线程,然后在新创建的线程上来处理请求。如果线程被阻塞,那么只有那个线程被置入休眠状态,而其它线程仍然处于运行中。
|
||||
|
||||
除了核心网络环境外,还有三个辅助环境。核心网络服务器环境除了接收来自用户应用程序的消息之外,它的派发器也接收来自输入环境和定时器环境的消息。
|
||||
|
||||
##### 输出环境
|
||||
#### 输出环境
|
||||
|
||||
在为用户环境套接字调用提供服务时,lwIP 将为网卡生成用于发送的包。IwIP 将使用 `NSREQ_OUTPUT` 去发送在 IPC 消息页参数中附加了包的 IPC 消息。输出环境负责接收这些消息,并通过你稍后创建的系统调用接口来转发这些包到设备驱动程序上。
|
||||
在为用户环境套接字调用提供服务时,lwIP 将为网卡生成用于发送的包。lwIP 将使用 `NSREQ_OUTPUT` 去发送在 IPC 消息页参数中附加了包的 IPC 消息。输出环境负责接收这些消息,并通过你稍后创建的系统调用接口来转发这些包到设备驱动程序上。
|
||||
|
||||
##### 输入环境
|
||||
#### 输入环境
|
||||
|
||||
网卡接收到的包需要传递到 lwIP 中。输入环境将每个由设备驱动程序接收到的包拉进内核空间(使用你将要实现的内核系统调用),并使用 `NSREQ_INPUT` IPC 消息将这些包发送到核心网络服务器环境。
|
||||
网卡接收到的包需要传递到 lwIP 中。输入环境将每个由设备驱动程序接收到的包拉进内核空间(使用你将要实现的内核系统调用),并使用 `NSREQ_INPUT` IPC 消息将这些包发送到核心网络服务器环境。
|
||||
|
||||
包输入功能是独立于核心网络环境的,因为在 JOS 上同时实现接收 IPC 消息并从设备驱动程序中查询或等待包有点困难。我们在 JOS 中没有实现 `select` 系统调用,这是一个允许环境去监视多个输入源以识别准备处理哪个输入的系统调用。
|
||||
|
||||
如果你查看了 `net/input.c` 和 `net/output.c`,你将会看到在它们中都需要去实现那个系统调用。这主要是因为实现它要依赖你的系统调用接口。在你实现了驱动程序和系统调用接口之后,你将要为这两个辅助环境写这个代码。
|
||||
|
||||
##### 定时器环境
|
||||
#### 定时器环境
|
||||
|
||||
定时器环境周期性发送 `NSREQ_TIMER` 类型的消息到核心服务器,以提醒它那个定时器已过期。IwIP 使用来自线程的定时器消息来实现各种网络超时。
|
||||
定时器环境周期性发送 `NSREQ_TIMER` 类型的消息到核心服务器,以提醒它那个定时器已过期。lwIP 使用来自线程的定时器消息来实现各种网络超时。
|
||||
|
||||
### Part A:初始化和发送包
|
||||
|
||||
你的内核还没有一个时间概念,因此我们需要去添加它。这里有一个由硬件产生的每 10 ms 一次的时钟中断。每收到一个时钟中断,我们将增加一个变量值,以表示时间已过去 10 ms。它在 `kern/time.c` 中已实现,但还没有完全集成到你的内核中。
|
||||
|
||||
```markdown
|
||||
练习 1、为 `kern/trap.c` 中的每个时钟中断增加一个到 `time_tick` 的调用。实现 `sys_time_msec` 并增加到 `kern/syscall.c` 中的 `syscall`,以便于用户空间能够访问时间。
|
||||
```
|
||||
> **练习 1**、为 `kern/trap.c` 中的每个时钟中断增加一个到 `time_tick` 的调用。实现 `sys_time_msec` 并增加到 `kern/syscall.c` 中的 `syscall`,以便于用户空间能够访问时间。
|
||||
|
||||
使用 `make INIT_CFLAGS=-DTEST_NO_NS run-testtime` 去测试你的代码。你应该会看到环境计数从 5 开始以 1 秒为间隔减少。"-DTEST_NO_NS” 参数禁止在网络服务器环境上启动,因为在当前它将导致 JOS 崩溃。
|
||||
使用 `make INIT_CFLAGS=-DTEST_NO_NS run-testtime` 去测试你的代码。你应该会看到环境计数从 5 开始以 1 秒为间隔减少。`-DTEST_NO_NS` 参数禁止在网络服务器环境上启动,因为在当前它将导致 JOS 崩溃。
|
||||
|
||||
#### 网卡
|
||||
|
||||
写驱动程序要求你必须深入了解硬件和软件中的接口。本实验将给你提供一个如何使用 E1000 接口的高度概括的文档,但是你在写驱动程序时还需要大量去查询 Intel 的手册。
|
||||
|
||||
```markdown
|
||||
练习 2、为开发 E1000 驱动,去浏览 Intel 的 [软件开发者手册][5]。这个手册涵盖了几个与以太网控制器紧密相关的东西。QEMU 仿真了 82540EM。
|
||||
> **练习 2**、为开发 E1000 驱动,去浏览 Intel 的 [软件开发者手册][5]。这个手册涵盖了几个与以太网控制器紧密相关的东西。QEMU 仿真了 82540EM。
|
||||
|
||||
现在,你应该去浏览第 2 章,以对设备获得一个整体概念。写驱动程序时,你需要熟悉第 3 到 14 章,以及 4.1(不包括 4.1 的子节)。你也应该去参考第 13 章。其它章涵盖了 E1000 的组件,你的驱动程序并不与这些组件去交互。现在你不用担心过多细节的东西;只需要了解文档的整体结构,以便于你后面需要时容易查找。
|
||||
> 现在,你应该去浏览第 2 章,以对设备获得一个整体概念。写驱动程序时,你需要熟悉第 3 到 14 章,以及 4.1(不包括 4.1 的子节)。你也应该去参考第 13 章。其它章涵盖了 E1000 的组件,你的驱动程序并不与这些组件去交互。现在你不用担心过多细节的东西;只需要了解文档的整体结构,以便于你后面需要时容易查找。
|
||||
|
||||
在阅读手册时,记住,E1000 是一个拥有很多高级特性的很复杂的设备,一个能让 E1000 工作的驱动程序仅需要它一小部分的特性和 NIC 提供的接口即可。仔细考虑一下,如何使用最简单的方式去使用网卡的接口。我们强烈推荐你在使用高级特性之前,只去写一个基本的、能够让网卡工作的驱动程序即可。
|
||||
```
|
||||
> 在阅读手册时,记住,E1000 是一个拥有很多高级特性的很复杂的设备,一个能让 E1000 工作的驱动程序仅需要它一小部分的特性和 NIC 提供的接口即可。仔细考虑一下,如何使用最简单的方式去使用网卡的接口。我们强烈推荐你在使用高级特性之前,只去写一个基本的、能够让网卡工作的驱动程序即可。
|
||||
|
||||
##### PCI 接口
|
||||
|
||||
@ -156,10 +149,10 @@ E1000 是一个 PCI 设备,也就是说它是插到主板的 PCI 总线插槽
|
||||
我们在 `kern/pci.c` 中已经为你提供了使用 PCI 的代码。PCI 初始化是在引导期间执行的,PCI 代码遍历PCI 总线来查找设备。当它找到一个设备时,它读取它的供应商 ID 和设备 ID,然后使用这两个值作为关键字去搜索 `pci_attach_vendor` 数组。这个数组是由像下面这样的 `struct pci_driver` 条目组成:
|
||||
|
||||
```c
|
||||
struct pci_driver {
|
||||
uint32_t key1, key2;
|
||||
int (*attachfn) (struct pci_func *pcif);
|
||||
};
|
||||
struct pci_driver {
|
||||
uint32_t key1, key2;
|
||||
int (*attachfn) (struct pci_func *pcif);
|
||||
};
|
||||
```
|
||||
|
||||
如果发现的设备的供应商 ID 和设备 ID 与数组中条目匹配,那么 PCI 代码将调用那个条目的 `attachfn` 去执行设备初始化。(设备也可以按类别识别,那是通过 `kern/pci.c` 中其它的驱动程序表来实现的。)
|
||||
@ -167,50 +160,46 @@ E1000 是一个 PCI 设备,也就是说它是插到主板的 PCI 总线插槽
|
||||
绑定函数是传递一个 _PCI 函数_ 去初始化。一个 PCI 卡能够发布多个函数,虽然这个 E1000 仅发布了一个。下面是在 JOS 中如何去表示一个 PCI 函数:
|
||||
|
||||
```c
|
||||
struct pci_func {
|
||||
struct pci_bus *bus;
|
||||
struct pci_func {
|
||||
struct pci_bus *bus;
|
||||
|
||||
uint32_t dev;
|
||||
uint32_t func;
|
||||
uint32_t dev;
|
||||
uint32_t func;
|
||||
|
||||
uint32_t dev_id;
|
||||
uint32_t dev_class;
|
||||
uint32_t dev_id;
|
||||
uint32_t dev_class;
|
||||
|
||||
uint32_t reg_base[6];
|
||||
uint32_t reg_size[6];
|
||||
uint8_t irq_line;
|
||||
};
|
||||
uint32_t reg_base[6];
|
||||
uint32_t reg_size[6];
|
||||
uint8_t irq_line;
|
||||
};
|
||||
```
|
||||
|
||||
上面的结构反映了在 Intel 开发者手册里第 4.1 节的表 4-1 中找到的一些条目。`struct pci_func` 的最后三个条目我们特别感兴趣的,因为它们将记录这个设备协商的内存、I/O、以及中断资源。`reg_base` 和 `reg_size` 数组包含最多六个基址寄存器或 BAR。`reg_base` 为映射到内存中的 I/O 区域(对于 I/O 端口而言是基 I/O 端口)保存了内存的基地址,`reg_size` 包含了以字节表示的大小或来自 `reg_base` 的相关基值的 I/O 端口号,而 `irq_line` 包含了为中断分配给设备的 IRQ 线。在表 4-2 的后半部分给出了 E1000 BAR 的具体涵义。
|
||||
|
||||
当设备调用了绑定函数后,设备已经被发现,但没有被启用。这意味着 PCI 代码还没有确定分配给设备的资源,比如地址空间和 IRQ 线,也就是说,`struct pci_func` 结构的最后三个元素还没有被填入。绑定函数将调用 `pci_func_enable`,它将去启用设备、协商这些资源、并在结构 `struct pci_func` 中填入它。
|
||||
|
||||
```markdown
|
||||
练习 3、实现一个绑定函数去初始化 E1000。添加一个条目到 `kern/pci.c` 中的数组 `pci_attach_vendor` 上,如果找到一个匹配的 PCI 设备就去触发你的函数(确保一定要把它放在表末尾的 `{0, 0, 0}` 条目之前)。你在 5.2 节中能找到 QEMU 仿真的 82540EM 的供应商 ID 和设备 ID。在引导期间,当 JOS 扫描 PCI 总线时,你也可以看到列出来的这些信息。
|
||||
> **练习 3**、实现一个绑定函数去初始化 E1000。添加一个条目到 `kern/pci.c` 中的数组 `pci_attach_vendor` 上,如果找到一个匹配的 PCI 设备就去触发你的函数(确保一定要把它放在表末尾的 `{0, 0, 0}` 条目之前)。你在 5.2 节中能找到 QEMU 仿真的 82540EM 的供应商 ID 和设备 ID。在引导期间,当 JOS 扫描 PCI 总线时,你也可以看到列出来的这些信息。
|
||||
|
||||
到目前为止,我们通过 `pci_func_enable` 启用了 E1000 设备。通过本实验我们将添加更多的初始化。
|
||||
> 到目前为止,我们通过 `pci_func_enable` 启用了 E1000 设备。通过本实验我们将添加更多的初始化。
|
||||
|
||||
我们已经为你提供了 `kern/e1000.c` 和 `kern/e1000.h` 文件,这样你就不会把构建系统搞糊涂了。不过它们现在都是空的;你需要在本练习中去填充它们。你还可能在内核的其它地方包含这个 `e1000.h` 文件。
|
||||
> 我们已经为你提供了 `kern/e1000.c` 和 `kern/e1000.h` 文件,这样你就不会把构建系统搞糊涂了。不过它们现在都是空的;你需要在本练习中去填充它们。你还可能在内核的其它地方包含这个 `e1000.h` 文件。
|
||||
|
||||
当你引导你的内核时,你应该会看到它输出的信息显示 E1000 的 PCI 函数已经启用。这时你的代码已经能够通过 `make grade` 的 `pci attach` 测试了。
|
||||
```
|
||||
> 当你引导你的内核时,你应该会看到它输出的信息显示 E1000 的 PCI 函数已经启用。这时你的代码已经能够通过 `make grade` 的 `pci attach` 测试了。
|
||||
|
||||
##### 内存映射的 I/O
|
||||
|
||||
软件与 E1000 通过内存映射的 I/O(MMIO) 来沟通。你在 JOS 的前面部分可能看到过 MMIO 两次:CGA 控制台和 LAPIC 都是通过写入和读取“内存”来控制和查询设备的。但这些读取和写入不是去往内存芯片的,而是直接到这些设备的。
|
||||
软件与 E1000 通过内存映射的 I/O(MMIO)来沟通。你在 JOS 的前面部分可能看到过 MMIO 两次:CGA 控制台和 LAPIC 都是通过写入和读取“内存”来控制和查询设备的。但这些读取和写入不是去往内存芯片的,而是直接到这些设备的。
|
||||
|
||||
`pci_func_enable` 为 E1000 协调一个 MMIO 区域,来存储它在 BAR 0 的基址和大小(也就是 `reg_base[0]` 和 `reg_size[0]`),这是一个分配给设备的一段物理内存地址,也就是说你可以通过虚拟地址访问它来做一些事情。由于 MMIO 区域一般分配高位物理地址(一般是 3GB 以上的位置),因此你不能使用 `KADDR` 去访问它们,因为 JOS 被限制为最大使用 256MB。因此,你可以去创建一个新的内存映射。我们将使用 `MMIOBASE`(从实验 4 开始,你的 `mmio_map_region` 区域应该确保不能被 LAPIC 使用的映射所覆盖)以上的部分。由于在 JOS 创建用户环境之前,PCI 设备就已经初始化了,因此你可以在 `kern_pgdir` 处创建映射,并且让它始终可用。
|
||||
|
||||
```markdown
|
||||
练习 4、在你的绑定函数中,通过调用 `mmio_map_region`(它就是你在实验 4 中写的,是为了支持 LAPIC 内存映射)为 E1000 的 BAR 0 创建一个虚拟地址映射。
|
||||
> **练习 4**、在你的绑定函数中,通过调用 `mmio_map_region`(它就是你在实验 4 中写的,是为了支持 LAPIC 内存映射)为 E1000 的 BAR 0 创建一个虚拟地址映射。
|
||||
|
||||
你将希望在一个变量中记录这个映射的位置,以便于后面访问你映射的寄存器。去看一下 `kern/lapic.c` 中的 `lapic` 变量,它就是一个这样的例子。如果你使用一个指针指向设备寄存器映射,一定要声明它为 `volatile`;否则,编译器将允许缓存它的值,并可以在内存中再次访问它。
|
||||
> 你将希望在一个变量中记录这个映射的位置,以便于后面访问你映射的寄存器。去看一下 `kern/lapic.c` 中的 `lapic` 变量,它就是一个这样的例子。如果你使用一个指针指向设备寄存器映射,一定要声明它为 `volatile`;否则,编译器将允许缓存它的值,并可以在内存中再次访问它。
|
||||
|
||||
为测试你的映射,尝试去输出设备状态寄存器(第 12.4.2 节)。这是一个在寄存器空间中以字节 8 开头的 4 字节寄存器。你应该会得到 `0x80080783`,它表示以 1000 MB/s 的速度启用一个全双工的链路,以及其它信息。
|
||||
```
|
||||
> 为测试你的映射,尝试去输出设备状态寄存器(第 12.4.2 节)。这是一个在寄存器空间中以字节 8 开头的 4 字节寄存器。你应该会得到 `0x80080783`,它表示以 1000 MB/s 的速度启用一个全双工的链路,以及其它信息。
|
||||
|
||||
提示:你将需要一些常数,像寄存器位置和掩码位数。如果从开发者手册中复制这些东西很容易出错,并且导致调试过程很痛苦。我们建议你使用 QEMU 的 [`e1000_hw.h`][6] 头文件做为基准。我们不建议完全照抄它,因为它定义的值远超过你所需要,并且定义的东西也不见得就是你所需要的,但它仍是一个很好的参考。
|
||||
提示:你将需要一些常数,像寄存器位置和掩码位数。如果从开发者手册中复制这些东西很容易出错,并且导致调试过程很痛苦。我们建议你使用 QEMU 的 [e1000_hw.h][6] 头文件做为基准。我们不建议完全照抄它,因为它定义的值远超过你所需要,并且定义的东西也不见得就是你所需要的,但它仍是一个很好的参考。
|
||||
|
||||
##### DMA
|
||||
|
||||
@ -224,13 +213,13 @@ E1000 是一个 PCI 设备,也就是说它是插到主板的 PCI 总线插槽
|
||||
|
||||
#### 发送包
|
||||
|
||||
E1000 中的发送和接收功能本质上是独立的,因此我们可以同时进行发送接收。我们首先去攻克简单的数据包发送,因为我们在没有先去发送一个 “I'm here!" 包之前是无法测试接收包功能的。
|
||||
E1000 中的发送和接收功能本质上是独立的,因此我们可以同时进行发送接收。我们首先去攻克简单的数据包发送,因为我们在没有先去发送一个 “I'm here!” 包之前是无法测试接收包功能的。
|
||||
|
||||
首先,你需要初始化网卡以准备发送,详细步骤查看 14.5 节(不必着急看子节)。发送初始化的第一步是设置发送队列。队列的详细结构在 3.4 节中,描述符的结构在 3.3.3 节中。我们先不要使用 E1000 的 TCP offload 特性,因此你只需专注于 “传统的发送描述符格式” 即可。你应该现在就去阅读这些章节,并要熟悉这些结构。
|
||||
|
||||
##### C 结构
|
||||
|
||||
你可以用 C `struct` 很方便地描述 E1000 的结构。正如你在 `struct Trapframe` 中所看到的结构那样,C `struct` 可以让你很方便地在内存中描述准确的数据布局。C 可以在字段中插入数据,但是 E1000 的结构就是这样布局的,这样就不会是个问题。如果你遇到字段对齐问题,进入 GCC 查看它的 "packed” 属性。
|
||||
你可以用 C `struct` 很方便地描述 E1000 的结构。正如你在 `struct Trapframe` 中所看到的结构那样,C `struct` 可以让你很方便地在内存中描述准确的数据布局。C 可以在字段中插入数据,但是 E1000 的结构就是这样布局的,这样就不会是个问题。如果你遇到字段对齐问题,进入 GCC 查看它的 "packed” 属性。
|
||||
|
||||
查看手册中表 3-8 所给出的一个传统的发送描述符,将它复制到这里作为一个示例:
|
||||
|
||||
@ -246,31 +235,29 @@ E1000 中的发送和接收功能本质上是独立的,因此我们可以同
|
||||
从结构右上角第一个字节开始,我们将它转变成一个 C 结构,从上到下,从右到左读取。如果你从右往左看,你将看到所有的字段,都非常适合一个标准大小的类型:
|
||||
|
||||
```c
|
||||
struct tx_desc
|
||||
{
|
||||
uint64_t addr;
|
||||
uint16_t length;
|
||||
uint8_t cso;
|
||||
uint8_t cmd;
|
||||
uint8_t status;
|
||||
uint8_t css;
|
||||
uint16_t special;
|
||||
};
|
||||
struct tx_desc
|
||||
{
|
||||
uint64_t addr;
|
||||
uint16_t length;
|
||||
uint8_t cso;
|
||||
uint8_t cmd;
|
||||
uint8_t status;
|
||||
uint8_t css;
|
||||
uint16_t special;
|
||||
};
|
||||
```
|
||||
|
||||
你的驱动程序将为发送描述符数组去保留内存,并由发送描述符指向到包缓冲区。有几种方式可以做到,从动态分配页到在全局变量中简单地声明它们。无论你如何选择,记住,E1000 是直接访问物理内存的,意味着它能访问的任何缓存区在物理内存中必须是连续的。
|
||||
|
||||
处理包缓存也有几种方式。我们推荐从最简单的开始,那就是在驱动程序初始化期间,为每个描述符保留包缓存空间,并简单地将包数据复制进预留的缓冲区中或从其中复制出来。一个以太网包最大的尺寸是 1518 字节,这就限制了这些缓存区的大小。主流的成熟驱动程序都能够动态分配包缓存区(即:当网络使用率很低时,减少内存使用量),或甚至跳过缓存区,直接由用户空间提供(就是“零复制”技术),但我们还是从简单开始为好。
|
||||
|
||||
```markdown
|
||||
练习 5、执行一个 14.5 节中的初始化步骤(它的子节除外)。对于寄存器的初始化过程使用 13 节作为参考,对发送描述符和发送描述符数组参考 3.3.3 节和 3.4 节。
|
||||
> **练习 5**、执行一个 14.5 节中的初始化步骤(它的子节除外)。对于寄存器的初始化过程使用 13 节作为参考,对发送描述符和发送描述符数组参考 3.3.3 节和 3.4 节。
|
||||
|
||||
要记住,在发送描述符数组中要求对齐,并且数组长度上有限制。因为 TDLEN 必须是 128 字节对齐的,而每个发送描述符是 16 字节,你的发送描述符数组必须是 8 个发送描述符的倍数。并且不能使用超过 64 个描述符,以及不能在我们的发送环形缓存测试中溢出。
|
||||
> 要记住,在发送描述符数组中要求对齐,并且数组长度上有限制。因为 TDLEN 必须是 128 字节对齐的,而每个发送描述符是 16 字节,你的发送描述符数组必须是 8 个发送描述符的倍数。并且不能使用超过 64 个描述符,以及不能在我们的发送环形缓存测试中溢出。
|
||||
|
||||
对于 TCTL.COLD,你可以假设为全双工操作。对于 TIPG、IEEE 802.3 标准的 IPG(不要使用 14.5 节中表上的值),参考在 13.4.34 节中表 13-77 中描述的缺省值。
|
||||
```
|
||||
> 对于 TCTL.COLD,你可以假设为全双工操作。对于 TIPG、IEEE 802.3 标准的 IPG(不要使用 14.5 节中表上的值),参考在 13.4.34 节中表 13-77 中描述的缺省值。
|
||||
|
||||
尝试运行 `make E1000_DEBUG=TXERR,TX qemu`。如果你使用的是打了 6.828 补丁的 QEMU,当你设置 TDT(发送描述符尾部)寄存器时你应该会看到一个 “e1000: tx disabled" 的信息,并且不会有更多 "e1000” 信息了。
|
||||
尝试运行 `make E1000_DEBUG=TXERR,TX qemu`。如果你使用的是打了 6.828 补丁的 QEMU,当你设置 TDT(发送描述符尾部)寄存器时你应该会看到一个 “e1000: tx disabled” 的信息,并且不会有更多 “e1000” 信息了。
|
||||
|
||||
现在,发送初始化已经完成,你可以写一些代码去发送一个数据包,并且通过一个系统调用使它可以访问用户空间。你可以将要发送的数据包添加到发送队列的尾部,也就是说复制数据包到下一个包缓冲区中,然后更新 TDT 寄存器去通知网卡在发送队列中有另外的数据包。(注意,TDT 是一个进入发送描述符数组的索引,不是一个字节偏移量;关于这一点文档中说明的不是很清楚。)
|
||||
|
||||
@ -278,76 +265,64 @@ E1000 中的发送和接收功能本质上是独立的,因此我们可以同
|
||||
|
||||
如果用户调用你的发送系统调用,但是下一个描述符的 DD 位没有设置,表示那个发送队列已满,该怎么办?在这种情况下,你该去决定怎么办了。你可以简单地丢弃数据包。网络协议对这种情况的处理很灵活,但如果你丢弃大量的突发数据包,协议可能不会去重新获得它们。可能需要你替代网络协议告诉用户环境让它重传,就像你在 `sys_ipc_try_send` 中做的那样。在环境上回推产生的数据是有好处的。
|
||||
|
||||
```
|
||||
练习 6、写一个函数去发送一个数据包,它需要检查下一个描述符是否空闲、复制包数据到下一个描述符并更新 TDT。确保你处理的发送队列是满的。
|
||||
```
|
||||
> **练习 6**、写一个函数去发送一个数据包,它需要检查下一个描述符是否空闲、复制包数据到下一个描述符并更新 TDT。确保你处理的发送队列是满的。
|
||||
|
||||
现在,应该去测试你的包发送代码了。通过从内核中直接调用你的发送函数来尝试发送几个包。在测试时,你不需要去创建符合任何特定网络协议的数据包。运行 `make E1000_DEBUG=TXERR,TX qemu` 去测试你的代码。你应该看到类似下面的信息:
|
||||
|
||||
```c
|
||||
e1000: index 0: 0x271f00 : 9000002a 0
|
||||
...
|
||||
e1000: index 0: 0x271f00 : 9000002a 0
|
||||
...
|
||||
```
|
||||
|
||||
在你发送包时,每行都给出了在发送数组中的序号、那个发送的描述符的缓存地址、`cmd/CSO/length` 字段、以及 `special/CSS/status` 字段。如果 QEMU 没有从你的发送描述符中输出你预期的值,检查你的描述符中是否有合适的值和你配置的正确的 TDBAL 和 TDBAH。如果你收到的是 "e1000: TDH wraparound @0, TDT x, TDLEN y" 的信息,意味着 E1000 的发送队列持续不断地运行(如果 QEMU 不去检查它,它将是一个无限循环),这意味着你没有正确地维护 TDT。如果你收到了许多 "e1000: tx disabled" 的信息,那么意味着你没有正确设置发送控制寄存器。
|
||||
在你发送包时,每行都给出了在发送数组中的序号、那个发送的描述符的缓存地址、`cmd/CSO/length` 字段、以及 `special/CSS/status` 字段。如果 QEMU 没有从你的发送描述符中输出你预期的值,检查你的描述符中是否有合适的值和你配置的正确的 TDBAL 和 TDBAH。如果你收到的是 “e1000: TDH wraparound @0, TDT x, TDLEN y” 的信息,意味着 E1000 的发送队列持续不断地运行(如果 QEMU 不去检查它,它将是一个无限循环),这意味着你没有正确地维护 TDT。如果你收到了许多 “e1000: tx disabled” 的信息,那么意味着你没有正确设置发送控制寄存器。
|
||||
|
||||
一旦 QEMU 运行,你就可以运行 `tcpdump -XXnr qemu.pcap` 去查看你发送的包数据。如果从 QEMU 中看到预期的 "e1000: index” 信息,但你捕获的包是空的,再次检查你发送的描述符,是否填充了每个必需的字段和位。(E1000 或许已经遍历了你的发送描述符,但它认为不需要去发送)
|
||||
一旦 QEMU 运行,你就可以运行 `tcpdump -XXnr qemu.pcap` 去查看你发送的包数据。如果从 QEMU 中看到预期的 “e1000: index” 信息,但你捕获的包是空的,再次检查你发送的描述符,是否填充了每个必需的字段和位。(E1000 或许已经遍历了你的发送描述符,但它认为不需要去发送)
|
||||
|
||||
```
|
||||
练习 7、添加一个系统调用,让你从用户空间中发送数据包。详细的接口由你来决定。但是不要忘了检查从用户空间传递给内核的所有指针。
|
||||
```
|
||||
> **练习 7**、添加一个系统调用,让你从用户空间中发送数据包。详细的接口由你来决定。但是不要忘了检查从用户空间传递给内核的所有指针。
|
||||
|
||||
#### 发送包:网络服务器
|
||||
|
||||
现在,你已经有一个系统调用接口可以发送包到你的设备驱动程序端了。输出辅助环境的目标是在一个循环中做下面的事情:从核心网络服务器中接收 `NSREQ_OUTPUT` IPC 消息,并使用你在上面增加的系统调用去发送伴随这些 IPC 消息的数据包。这个 `NSREQ_OUTPUT` IPC 是通过 `net/lwip/jos/jif/jif.c` 中的 `low_level_output` 函数来发送的。它集成 lwIP 栈到 JOS 的网络系统。每个 IPC 将包含一个页,这个页由一个 `union Nsipc` 和在 `struct jif_pkt pkt` 字段中的一个包组成(查看 `inc/ns.h`)。`struct jif_pkt` 看起来像下面这样:
|
||||
|
||||
```c
|
||||
struct jif_pkt {
|
||||
int jp_len;
|
||||
char jp_data[0];
|
||||
};
|
||||
struct jif_pkt {
|
||||
int jp_len;
|
||||
char jp_data[0];
|
||||
};
|
||||
```
|
||||
|
||||
`jp_len` 表示包的长度。在 IPC 页上的所有后续字节都是为了包内容。在结构的结尾处使用一个长度为 0 的数组来表示缓存没有一个预先确定的长度(像 `jp_data` 一样),这是一个常见的 C 技巧(也有人说这是一个令人讨厌的做法)。因为 C 并不做数组边界的检查,只要你确保结构后面有足够的未使用内存即可,你可以把 `jp_data` 作为一个任意大小的数组来使用。
|
||||
|
||||
当设备驱动程序的发送队列中没有足够的空间时,一定要注意在设备驱动程序、输出环境和核心网络服务器之间的交互。核心网络服务器使用 IPC 发送包到输出环境。如果输出环境在由于一个发送包的系统调用而挂起,导致驱动程序没有足够的缓存去容纳新数据包,这时核心网络服务器将阻塞以等待输出服务器去接收 IPC 调用。
|
||||
|
||||
```markdown
|
||||
练习 8、实现 `net/output.c`。
|
||||
```
|
||||
> **练习 8**、实现 `net/output.c`。
|
||||
|
||||
你可以使用 `net/testoutput.c` 去测试你的输出代码而无需整个网络服务器参与。尝试运行 `make E1000_DEBUG=TXERR,TX run-net_testoutput`。你将看到如下的输出:
|
||||
|
||||
```c
|
||||
Transmitting packet 0
|
||||
e1000: index 0: 0x271f00 : 9000009 0
|
||||
Transmitting packet 1
|
||||
e1000: index 1: 0x2724ee : 9000009 0
|
||||
...
|
||||
Transmitting packet 0
|
||||
e1000: index 0: 0x271f00 : 9000009 0
|
||||
Transmitting packet 1
|
||||
e1000: index 1: 0x2724ee : 9000009 0
|
||||
...
|
||||
```
|
||||
|
||||
运行 `tcpdump -XXnr qemu.pcap` 将输出:
|
||||
|
||||
|
||||
```c
|
||||
reading from file qemu.pcap, link-type EN10MB (Ethernet)
|
||||
-5:00:00.600186 [|ether]
|
||||
0x0000: 5061 636b 6574 2030 30 Packet.00
|
||||
-5:00:00.610080 [|ether]
|
||||
0x0000: 5061 636b 6574 2030 31 Packet.01
|
||||
...
|
||||
reading from file qemu.pcap, link-type EN10MB (Ethernet)
|
||||
-5:00:00.600186 [|ether]
|
||||
0x0000: 5061 636b 6574 2030 30 Packet.00
|
||||
-5:00:00.610080 [|ether]
|
||||
0x0000: 5061 636b 6574 2030 31 Packet.01
|
||||
...
|
||||
```
|
||||
|
||||
使用更多的数据包去测试,可以运行 `make E1000_DEBUG=TXERR,TX NET_CFLAGS=-DTESTOUTPUT_COUNT=100 run-net_testoutput`。如果它导致你的发送队列溢出,再次检查你的 DD 状态位是否正确,以及是否告诉硬件去设置 DD 状态位(使用 RS 命令位)。
|
||||
|
||||
你的代码应该会通过 `make grade` 的 `testoutput` 测试。
|
||||
|
||||
```
|
||||
问题
|
||||
|
||||
1、你是如何构造你的发送实现的?在实践中,如果发送缓存区满了,你该如何处理?
|
||||
```
|
||||
|
||||
> **问题 1**、你是如何构造你的发送实现的?在实践中,如果发送缓存区满了,你该如何处理?
|
||||
|
||||
### Part B:接收包和 web 服务器
|
||||
|
||||
@ -355,9 +330,7 @@ E1000 中的发送和接收功能本质上是独立的,因此我们可以同
|
||||
|
||||
就像你在发送包中做的那样,你将去配置 E1000 去接收数据包,并提供一个接收描述符队列和接收描述符。在 3.2 节中描述了接收包的操作,包括接收队列结构和接收描述符、以及在 14.4 节中描述的详细的初始化过程。
|
||||
|
||||
```
|
||||
练习 9、阅读 3.2 节。你可以忽略关于中断和 offload 校验和方面的内容(如果在后面你想去使用这些特性,可以再返回去阅读),你现在不需要去考虑阈值的细节和网卡内部缓存是如何工作的。
|
||||
```
|
||||
> **练习 9**、阅读 3.2 节。你可以忽略关于中断和 offload 校验和方面的内容(如果在后面你想去使用这些特性,可以再返回去阅读),你现在不需要去考虑阈值的细节和网卡内部缓存是如何工作的。
|
||||
|
||||
除了接收队列是由一系列的等待入站数据包去填充的空缓存包以外,接收队列的其它部分与发送队列非常相似。所以,当网络空闲时,发送队列是空的(因为所有的包已经被发送出去了),而接收队列是满的(全部都是空缓存包)。
|
||||
|
||||
@ -365,123 +338,108 @@ E1000 中的发送和接收功能本质上是独立的,因此我们可以同
|
||||
|
||||
如果 E1000 在一个接收描述符中接收到了一个比包缓存还要大的数据包,它将按需从接收队列中检索尽可能多的描述符以保存数据包的全部内容。为表示发生了这种情况,它将在所有的这些描述符上设置 DD 状态位,但仅在这些描述符的最后一个上设置 EOP 状态位。在你的驱动程序上,你可以去处理这种情况,也可以简单地配置网卡拒绝接收这种”长包“(这种包也被称为”巨帧“),你要确保接收缓存有足够的空间尽可能地去存储最大的标准以太网数据包(1518 字节)。
|
||||
|
||||
```markdown
|
||||
练习 10、设置接收队列并按 14.4 节中的流程去配置 E1000。你可以不用支持 ”长包“ 或多播。到目前为止,我们不用去配置网卡使用中断;如果你在后面决定去使用接收中断时可以再去改。另外,配置 E1000 去除以太网的 CRC 校验,因为我们的评级脚本要求必须去掉校验。
|
||||
> **练习 10**、设置接收队列并按 14.4 节中的流程去配置 E1000。你可以不用支持 ”长包“ 或多播。到目前为止,我们不用去配置网卡使用中断;如果你在后面决定去使用接收中断时可以再去改。另外,配置 E1000 去除以太网的 CRC 校验,因为我们的评级脚本要求必须去掉校验。
|
||||
|
||||
默认情况下,网卡将过滤掉所有的数据包。你必须使用网卡的 MAC 地址去配置接收地址寄存器(RAL 和 RAH)以接收发送到这个网卡的数据包。你可以简单地硬编码 QEMU 的默认 MAC 地址 52:54:00:12:34:56(我们已经在 lwIP 中硬编码了这个地址,因此这样做不会有问题)。使用字节顺序时要注意;MAC 地址是从低位字节到高位字节的方式来写的,因此 52:54:00:12 是 MAC 地址的低 32 位,而 34:56 是它的高 16 位。
|
||||
> 默认情况下,网卡将过滤掉所有的数据包。你必须使用网卡的 MAC 地址去配置接收地址寄存器(RAL 和 RAH)以接收发送到这个网卡的数据包。你可以简单地硬编码 QEMU 的默认 MAC 地址 52:54:00:12:34:56(我们已经在 lwIP 中硬编码了这个地址,因此这样做不会有问题)。使用字节顺序时要注意;MAC 地址是从低位字节到高位字节的方式来写的,因此 52:54:00:12 是 MAC 地址的低 32 位,而 34:56 是它的高 16 位。
|
||||
|
||||
E1000 的接收缓存区大小仅支持几个指定的设置值(在 13.4.22 节中描述的 RCTL.BSIZE 值)。如果你的接收包缓存够大,并且拒绝长包,那你就不用担心跨越多个缓存区的包。另外,要记住的是,和发送一样,接收队列和包缓存必须是连接的物理内存。
|
||||
> E1000 的接收缓存区大小仅支持几个指定的设置值(在 13.4.22 节中描述的 RCTL.BSIZE 值)。如果你的接收包缓存够大,并且拒绝长包,那你就不用担心跨越多个缓存区的包。另外,要记住的是,和发送一样,接收队列和包缓存必须是连接的物理内存。
|
||||
|
||||
你应该使用至少 128 个接收描述符。
|
||||
```
|
||||
> 你应该使用至少 128 个接收描述符。
|
||||
|
||||
现在,你可以做接收功能的基本测试了,甚至都无需写代码去接收包了。运行 `make E1000_DEBUG=TX,TXERR,RX,RXERR,RXFILTER run-net_testinput`。`testinput` 将发送一个 ARP(地址解析协议)通告包(使用你的包发送的系统调用),而 QEMU 将自动回复它,即便是你的驱动尚不能接收这个回复,你也应该会看到一个 "e1000: unicast match[0]: 52:54:00:12:34:56" 的消息,表示 E1000 接收到一个包,并且匹配了配置的接收过滤器。如果你看到的是一个 "e1000: unicast mismatch: 52:54:00:12:34:56” 消息,表示 E1000 过滤掉了这个包,意味着你的 RAL 和 RAH 的配置不正确。确保你按正确的顺序收到了字节,并不要忘记设置 RAH 中的 "Address Valid” 位。如果你没有收到任何 "e1000” 消息,或许是你没有正确地启用接收功能。
|
||||
现在,你可以做接收功能的基本测试了,甚至都无需写代码去接收包了。运行 `make E1000_DEBUG=TX,TXERR,RX,RXERR,RXFILTER run-net_testinput`。`testinput` 将发送一个 ARP(地址解析协议)通告包(使用你的包发送的系统调用),而 QEMU 将自动回复它,即便是你的驱动尚不能接收这个回复,你也应该会看到一个 “e1000: unicast match[0]: 52:54:00:12:34:56” 的消息,表示 E1000 接收到一个包,并且匹配了配置的接收过滤器。如果你看到的是一个 “e1000: unicast mismatch: 52:54:00:12:34:56” 消息,表示 E1000 过滤掉了这个包,意味着你的 RAL 和 RAH 的配置不正确。确保你按正确的顺序收到了字节,并不要忘记设置 RAH 中的 “Address Valid” 位。如果你没有收到任何 “e1000” 消息,或许是你没有正确地启用接收功能。
|
||||
|
||||
现在,你准备去实现接收数据包。为了接收数据包,你的驱动程序必须持续跟踪希望去保存下一下接收到的包的描述符(提示:按你的设计,这个功能或许已经在 E1000 中的一个寄存器来实现了)。与发送类似,官方文档上表示,RDH 寄存器状态并不能从软件中可靠地读取,因为确定一个包是否被发送到描述符的包缓存中,你需要去读取描述符中的 DD 状态位。如果 DD 位被设置,你就可以从那个描述符的缓存中复制出这个数据包,然后通过更新队列的尾索引 RDT 来告诉网卡那个描述符是空闲的。
|
||||
|
||||
如果 DD 位没有被设置,表明没有接收到包。这就与发送队列满的情况一样,这时你可以有几种做法。你可以简单地返回一个 ”重传“ 错误来要求对端重发一次。对于满的发送队列,由于那是个临时状况,这种做法还是很好的,但对于空的接收队列来说就不太合理了,因为接收队列可能会保持好长一段时间的空的状态。第二个方法是挂起调用环境,直到在接收队列中处理了这个包为止。这个策略非常类似于 `sys_ipc_recv`。就像在 IPC 的案例中,因为我们每个 CPU 仅有一个内核栈,一旦我们离开内核,栈上的状态就会被丢弃。我们需要设置一个标志去表示那个环境由于接收队列下溢被挂起并记录系统调用参数。这种方法的缺点是过于复杂:E1000 必须被指示去产生接收中断,并且驱动程序为了恢复被阻塞等待一个包的环境,必须处理这个中断。
|
||||
|
||||
```
|
||||
练习 11、写一个函数从 E1000 中接收一个包,然后通过一个系统调用将它发布到用户空间。确保你将接收队列处理成空的。
|
||||
```
|
||||
> **练习 11**、写一个函数从 E1000 中接收一个包,然后通过一个系统调用将它发布到用户空间。确保你将接收队列处理成空的。
|
||||
|
||||
```markdown
|
||||
小挑战!如果发送队列是满的或接收队列是空的,环境和你的驱动程序可能会花费大量的 CPU 周期是轮询、等待一个描述符。一旦完成发送或接收描述符,E1000 能够产生一个中断,以避免轮询。修改你的驱动程序,处理发送和接收队列是以中断而不是轮询的方式进行。
|
||||
.
|
||||
|
||||
注意,一旦确定为中断,它将一直处于中断状态,直到你的驱动程序明确处理完中断为止。在你的中断服务程序中,一旦处理完成要确保清除掉中断状态。如果你不那样做,从你的中断服务程序中返回后,CPU 将再次跳转到你的中断服务程序中。除了在 E1000 网卡上清除中断外,也需要使用 `lapic_eoi` 在 LAPIC 上清除中断。
|
||||
```
|
||||
> 小挑战!如果发送队列是满的或接收队列是空的,环境和你的驱动程序可能会花费大量的 CPU 周期是轮询、等待一个描述符。一旦完成发送或接收描述符,E1000 能够产生一个中断,以避免轮询。修改你的驱动程序,处理发送和接收队列是以中断而不是轮询的方式进行。
|
||||
|
||||
> 注意,一旦确定为中断,它将一直处于中断状态,直到你的驱动程序明确处理完中断为止。在你的中断服务程序中,一旦处理完成要确保清除掉中断状态。如果你不那样做,从你的中断服务程序中返回后,CPU 将再次跳转到你的中断服务程序中。除了在 E1000 网卡上清除中断外,也需要使用 `lapic_eoi` 在 LAPIC 上清除中断。
|
||||
|
||||
#### 接收包:网络服务器
|
||||
|
||||
在网络服务器输入环境中,你需要去使用你的新的接收系统调用以接收数据包,并使用 `NSREQ_INPUT` IPC 消息将它传递到核心网络服务器环境。这些 IPC 输入消息应该会有一个页,这个页上绑定了一个 `union Nsipc`,它的 `struct jif_pkt pkt` 字段中有从网络上接收到的包。
|
||||
|
||||
```markdown
|
||||
练习 12、实现 `net/input.c`。
|
||||
```
|
||||
> **练习 12**、实现 `net/input.c`。
|
||||
|
||||
使用 `make E1000_DEBUG=TX,TXERR,RX,RXERR,RXFILTER run-net_testinput` 再次运行 `testinput`,你应该会看到:
|
||||
|
||||
```c
|
||||
Sending ARP announcement...
|
||||
Waiting for packets...
|
||||
e1000: index 0: 0x26dea0 : 900002a 0
|
||||
e1000: unicast match[0]: 52:54:00:12:34:56
|
||||
input: 0000 5254 0012 3456 5255 0a00 0202 0806 0001
|
||||
input: 0010 0800 0604 0002 5255 0a00 0202 0a00 0202
|
||||
input: 0020 5254 0012 3456 0a00 020f 0000 0000 0000
|
||||
input: 0030 0000 0000 0000 0000 0000 0000 0000 0000
|
||||
Sending ARP announcement...
|
||||
Waiting for packets...
|
||||
e1000: index 0: 0x26dea0 : 900002a 0
|
||||
e1000: unicast match[0]: 52:54:00:12:34:56
|
||||
input: 0000 5254 0012 3456 5255 0a00 0202 0806 0001
|
||||
input: 0010 0800 0604 0002 5255 0a00 0202 0a00 0202
|
||||
input: 0020 5254 0012 3456 0a00 020f 0000 0000 0000
|
||||
input: 0030 0000 0000 0000 0000 0000 0000 0000 0000
|
||||
```
|
||||
|
||||
"input:” 打头的行是一个 QEMU 的 ARP 回复的十六进制转储。
|
||||
“input:” 打头的行是一个 QEMU 的 ARP 回复的十六进制转储。
|
||||
|
||||
你的代码应该会通过 `make grade` 的 `testinput` 测试。注意,在没有发送至少一个包去通知 QEMU 中的 JOS 的 IP 地址上时,是没法去测试包接收的,因此在你的发送代码中的 bug 可能会导致测试失败。
|
||||
|
||||
为彻底地测试你的网络代码,我们提供了一个称为 `echosrv` 的守护程序,它在端口 7 上设置运行 `echo` 的服务器,它将回显通过 TCP 连接发送给它的任何内容。使用 `make E1000_DEBUG=TX,TXERR,RX,RXERR,RXFILTER run-echosrv` 在一个终端中启动 `echo` 服务器,然后在另一个终端中通过 `make nc-7` 去连接它。你输入的每一行都被这个服务器回显出来。每次在仿真的 E1000 上接收到一个包,QEMU 将在控制台上输出像下面这样的内容:
|
||||
|
||||
```c
|
||||
e1000: unicast match[0]: 52:54:00:12:34:56
|
||||
e1000: index 2: 0x26ea7c : 9000036 0
|
||||
e1000: index 3: 0x26f06a : 9000039 0
|
||||
e1000: unicast match[0]: 52:54:00:12:34:56
|
||||
e1000: unicast match[0]: 52:54:00:12:34:56
|
||||
e1000: index 2: 0x26ea7c : 9000036 0
|
||||
e1000: index 3: 0x26f06a : 9000039 0
|
||||
e1000: unicast match[0]: 52:54:00:12:34:56
|
||||
```
|
||||
|
||||
做到这一点后,你应该也就能通过 `echosrv` 的测试了。
|
||||
|
||||
```
|
||||
问题
|
||||
> **问题 2**、你如何构造你的接收实现?在实践中,如果接收队列是空的并且一个用户环境要求下一个入站包,你怎么办?
|
||||
|
||||
2、你如何构造你的接收实现?在实践中,如果接收队列是空的并且一个用户环境要求下一个入站包,你怎么办?
|
||||
```
|
||||
.
|
||||
|
||||
> 小挑战!在开发者手册中阅读关于 EEPROM 的内容,并写出从 EEPROM 中加载 E1000 的 MAC 地址的代码。目前,QEMU 的默认 MAC 地址是硬编码到你的接收初始化代码和 lwIP 中的。修复你的初始化代码,让它能够从 EEPROM 中读取 MAC 地址,和增加一个系统调用去传递 MAC 地址到 lwIP 中,并修改 lwIP 去从网卡上读取 MAC 地址。通过配置 QEMU 使用一个不同的 MAC 地址去测试你的变更。
|
||||
|
||||
```
|
||||
小挑战!在开发者手册中阅读关于 EEPROM 的内容,并写出从 EEPROM 中加载 E1000 的 MAC 地址的代码。目前,QEMU 的默认 MAC 地址是硬编码到你的接收初始化代码和 lwIP 中的。修复你的初始化代码,让它能够从 EEPROM 中读取 MAC 地址,和增加一个系统调用去传递 MAC 地址到 lwIP 中,并修改 lwIP 去从网卡上读取 MAC 地址。通过配置 QEMU 使用一个不同的 MAC 地址去测试你的变更。
|
||||
```
|
||||
.
|
||||
|
||||
```
|
||||
小挑战!修改你的 E1000 驱动程序去使用 "零复制" 技术。目前,数据包是从用户空间缓存中复制到发送包缓存中,和从接收包缓存中复制回到用户空间缓存中。一个使用 ”零复制“ 技术的驱动程序可以通过直接让用户空间和 E1000 共享包缓存内存来实现。还有许多不同的方法去实现 ”零复制“,包括映射内容分配的结构到用户空间或直接传递用户提供的缓存到 E1000。不论你选择哪种方法,都要注意你如何利用缓存的问题,因为你不能在用户空间代码和 E1000 之间产生争用。
|
||||
```
|
||||
> 小挑战!修改你的 E1000 驱动程序去使用 "零复制" 技术。目前,数据包是从用户空间缓存中复制到发送包缓存中,和从接收包缓存中复制回到用户空间缓存中。一个使用 ”零复制“ 技术的驱动程序可以通过直接让用户空间和 E1000 共享包缓存内存来实现。还有许多不同的方法去实现 ”零复制“,包括映射内容分配的结构到用户空间或直接传递用户提供的缓存到 E1000。不论你选择哪种方法,都要注意你如何利用缓存的问题,因为你不能在用户空间代码和 E1000 之间产生争用。
|
||||
|
||||
```
|
||||
小挑战!把 ”零复制“ 的概念用到 lwIP 中。
|
||||
.
|
||||
|
||||
一个典型的包是由许多头构成的。用户发送的数据被发送到 lwIP 中的一个缓存中。TCP 层要添加一个 TCP 包头,IP 层要添加一个 IP 包头,而 MAC 层有一个以太网头。甚至还有更多的部分增加到包上,这些部分要正确地连接到一起,以便于设备驱动程序能够发送最终的包。
|
||||
> 小挑战!把 “零复制” 的概念用到 lwIP 中。
|
||||
|
||||
E1000 的发送描述符设计是非常适合收集分散在内存中的包片段的,像在 IwIP 中创建的包的帧。如果你排队多个发送描述符,但仅设置最后一个描述符的 EOP 命令位,那么 E1000 将在内部把这些描述符串成包缓存,并在它们标记完 EOP 后仅发送串起来的缓存。因此,独立的包片段不需要在内存中把它们连接到一起。
|
||||
> 一个典型的包是由许多头构成的。用户发送的数据被发送到 lwIP 中的一个缓存中。TCP 层要添加一个 TCP 包头,IP 层要添加一个 IP 包头,而 MAC 层有一个以太网头。甚至还有更多的部分增加到包上,这些部分要正确地连接到一起,以便于设备驱动程序能够发送最终的包。
|
||||
|
||||
修改你的驱动程序,以使它能够发送由多个缓存且无需复制的片段组成的包,并且修改 lwIP 去避免它合并包片段,因为它现在能够正确处理了。
|
||||
```
|
||||
> E1000 的发送描述符设计是非常适合收集分散在内存中的包片段的,像在 lwIP 中创建的包的帧。如果你排队多个发送描述符,但仅设置最后一个描述符的 EOP 命令位,那么 E1000 将在内部把这些描述符串成包缓存,并在它们标记完 EOP 后仅发送串起来的缓存。因此,独立的包片段不需要在内存中把它们连接到一起。
|
||||
|
||||
```markdown
|
||||
小挑战!增加你的系统调用接口,以便于它能够为多于一个的用户环境提供服务。如果有多个网络栈(和多个网络服务器)并且它们各自都有自己的 IP 地址运行在用户模式中,这将是非常有用的。接收系统调用将决定它需要哪个环境来转发每个入站的包。
|
||||
> 修改你的驱动程序,以使它能够发送由多个缓存且无需复制的片段组成的包,并且修改 lwIP 去避免它合并包片段,因为它现在能够正确处理了。
|
||||
|
||||
注意,当前的接口并不知道两个包之间有何不同,并且如果多个环境去调用包接收的系统调用,各个环境将得到一个入站包的子集,而那个子集可能并不包含调用环境指定的那个包。
|
||||
.
|
||||
|
||||
在 [这篇][7] 外内核论文的 2.2 节和 3 节中对这个问题做了深度解释,并解释了在内核中(如 JOS)处理它的一个方法。用这个论文中的方法去解决这个问题,你不需要一个像论文中那么复杂的方案。
|
||||
```
|
||||
> 小挑战!增加你的系统调用接口,以便于它能够为多于一个的用户环境提供服务。如果有多个网络栈(和多个网络服务器)并且它们各自都有自己的 IP 地址运行在用户模式中,这将是非常有用的。接收系统调用将决定它需要哪个环境来转发每个入站的包。
|
||||
|
||||
> 注意,当前的接口并不知道两个包之间有何不同,并且如果多个环境去调用包接收的系统调用,各个环境将得到一个入站包的子集,而那个子集可能并不包含调用环境指定的那个包。
|
||||
|
||||
> 在 [这篇][7] 外内核论文的 2.2 节和 3 节中对这个问题做了深度解释,并解释了在内核中(如 JOS)处理它的一个方法。用这个论文中的方法去解决这个问题,你不需要一个像论文中那么复杂的方案。
|
||||
|
||||
#### Web 服务器
|
||||
|
||||
一个最简单的 web 服务器类型是发送一个文件的内容到请求的客户端。我们在 `user/httpd.c` 中提供了一个非常简单的 web 服务器的框架代码。这个框架内码处理入站连接并解析请求头。
|
||||
|
||||
```markdown
|
||||
练习 13、这个 web 服务器中缺失了发送一个文件的内容到客户端的处理代码。通过实现 `send_file` 和 `send_data` 完成这个 web 服务器。
|
||||
```
|
||||
> **练习 13**、这个 web 服务器中缺失了发送一个文件的内容到客户端的处理代码。通过实现 `send_file` 和 `send_data` 完成这个 web 服务器。
|
||||
|
||||
在你完成了这个 web 服务器后,启动这个 web 服务器(`make run-httpd-nox`),使用你喜欢的浏览器去浏览 http:// _host_ : _port_ /index.html 地址。其中 _host_ 是运行 QEMU 的计算机的名字(如果你在 athena 上运行 QEMU,使用 `hostname.mit.edu`(其中 hostname 是在 athena 上运行 `hostname` 命令的输出,或者如果你在运行 QEMU 的机器上运行 web 浏览器的话,直接使用 `localhost`),而 _port_ 是 web 服务器运行 `make which-ports` 命令报告的端口号。你应该会看到一个由运行在 JOS 中的 HTTP 服务器提供的一个 web 页面。
|
||||
在你完成了这个 web 服务器后,启动这个 web 服务器(`make run-httpd-nox`),使用你喜欢的浏览器去浏览 `http://host:port/index.html` 地址。其中 _host_ 是运行 QEMU 的计算机的名字(如果你在 athena 上运行 QEMU,使用 `hostname.mit.edu`(其中 hostname 是在 athena 上运行 `hostname` 命令的输出,或者如果你在运行 QEMU 的机器上运行 web 浏览器的话,直接使用 `localhost`),而 _port_ 是 web 服务器运行 `make which-ports` 命令报告的端口号。你应该会看到一个由运行在 JOS 中的 HTTP 服务器提供的一个 web 页面。
|
||||
|
||||
到目前为止,你的评级测试得分应该是 105 分(满分为105)。
|
||||
到目前为止,你的评级测试得分应该是 105 分(满分为 105)。
|
||||
|
||||
```markdown
|
||||
小挑战!在 JOS 中添加一个简单的聊天服务器,多个人可以连接到这个服务器上,并且任何用户输入的内容都被发送到其它用户。为实现它,你需要找到一个一次与多个套接字通讯的方法,并且在同一时间能够在同一个套接字上同时实现发送和接收。有多个方法可以达到这个目的。lwIP 为 `recv`(查看 `net/lwip/api/sockets.c` 中的 `lwip_recvfrom`)提供了一个 MSG_DONTWAIT 标志,以便于你不断地轮询所有打开的套接字。注意,虽然网络服务器的 IPC 支持 `recv` 标志,但是通过普通的 `read` 函数并不能访问它们,因此你需要一个方法来传递这个标志。一个更高效的方法是为每个连接去启动一个或多个环境,并且使用 IPC 去协调它们。而且碰巧的是,对于一个套接字,在结构 Fd 中找到的 lwIP 套接字 ID 是全局的(不是每个环境私有的),因此,比如一个 `fork` 的子环境继承了它的父环境的套接字。或者,一个环境通过构建一个包含了正确套接字 ID 的 Fd 就能够发送到另一个环境的套接字上。
|
||||
```
|
||||
> 小挑战!在 JOS 中添加一个简单的聊天服务器,多个人可以连接到这个服务器上,并且任何用户输入的内容都被发送到其它用户。为实现它,你需要找到一个一次与多个套接字通讯的方法,并且在同一时间能够在同一个套接字上同时实现发送和接收。有多个方法可以达到这个目的。lwIP 为 `recv`(查看 `net/lwip/api/sockets.c` 中的 `lwip_recvfrom`)提供了一个 MSG_DONTWAIT 标志,以便于你不断地轮询所有打开的套接字。注意,虽然网络服务器的 IPC 支持 `recv` 标志,但是通过普通的 `read` 函数并不能访问它们,因此你需要一个方法来传递这个标志。一个更高效的方法是为每个连接去启动一个或多个环境,并且使用 IPC 去协调它们。而且碰巧的是,对于一个套接字,在结构 Fd 中找到的 lwIP 套接字 ID 是全局的(不是每个环境私有的),因此,比如一个 `fork` 的子环境继承了它的父环境的套接字。或者,一个环境通过构建一个包含了正确套接字 ID 的 Fd 就能够发送到另一个环境的套接字上。
|
||||
|
||||
```
|
||||
问题
|
||||
> **问题 3**、由 JOS 的 web 服务器提供的 web 页面显示了什么?
|
||||
|
||||
.
|
||||
|
||||
> **问题 4**、你做这个实验大约花了多长的时间?
|
||||
|
||||
3、由 JOS 的 web 服务器提供的 web 页面显示了什么?
|
||||
4. 你做这个实验大约花了多长的时间?
|
||||
```
|
||||
|
||||
**本实验到此结束了。**一如既往,不要忘了运行 `make grade` 并去写下你的答案和挑战问题的解决方案的描述。在你动手之前,使用 `git status` 和 `git diff` 去检查你的变更,并不要忘了去 `git add answers-lab6.txt`。当你完成之后,使用 `git commit -am 'my solutions to lab 6’` 去提交你的变更,然后 `make handin` 并关注它的动向。
|
||||
|
||||
@ -492,7 +450,7 @@ via: https://pdos.csail.mit.edu/6.828/2018/labs/lab6/
|
||||
作者:[csail.mit][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -0,0 +1,111 @@
|
||||
怎样如软件工程师一样组织知识
|
||||
==========
|
||||
|
||||
总体上说,软件开发和技术是以非常快的速度发展的领域,所以持续学习是必不可少的。在互联网上花几分钟找一下,在 Twitter、媒体、RSS 订阅、Hacker News 和其它专业网站和社区等地方,就可以从文章、案例研究、教程、代码片段、新应用程序和信息中找到大量有用的信息。
|
||||
|
||||
保存和组织所有这些信息可能是一项艰巨的任务。在这篇文章中,我将介绍一些我用来组织信息的工具。
|
||||
|
||||
我认为在知识管理方面非常重要的一点就是避免锁定在特定平台。我使用的所有工具都允许以标准格式(如 Markdown 和 HTML)导出数据。
|
||||
|
||||
请注意,我的流程并不完美,我一直在寻找新工具和方法来优化它。每个人都不同,所以对我有用的东西可能不适合你。
|
||||
|
||||
|
||||
### 用 NotionHQ 做知识库
|
||||
|
||||
对我来说,知识管理的基本部分是拥有某种个人知识库或维基。这是一个你可以以有组织的方式保存链接、书签、备注等的地方。
|
||||
|
||||
我使用 [NotionHQ][7] 做这件事。我使用它来记录各种主题,包括资源列表,如通过编程语言分组的优秀的库或教程,为有趣的博客文章和教程添加书签等等,不仅与软件开发有关,而且与我的个人生活有关。
|
||||
|
||||
我真正喜欢 NotionHQ 的是,创建新内容是如此简单。你可以使用 Markdown 编写它并将其组织为树状。
|
||||
|
||||
这是我的“开发”工作区的顶级页面:
|
||||
|
||||
[][8]
|
||||
|
||||
NotionHQ 有一些很棒的其他功能,如集成了电子表格/数据库和任务板。
|
||||
|
||||
如果您想认真使用 NotionHQ,您将需要订阅付费个人计划,因为免费计划有所限制。我觉得它物有所值。NotionHQ 允许将整个工作区导出为 Markdown 文件。导出功能存在一些重要问题,例如丢失页面层次结构,希望 Notion 团队可以改进这一点。
|
||||
|
||||
作为一个免费的替代方案,我可能会使用 [VuePress][9] 或 [GitBook][10] 来托管我自己的知识库。
|
||||
|
||||
### 用 Pocket 保存感兴趣的文章
|
||||
|
||||
[Pocket][11] 是我最喜欢的应用之一!使用 Pocket,您可以创建一个来自互联网上的文章的阅读列表。每当我看到一篇看起来很有趣的文章时,我都会使用 Chrome 扩展程序将其保存到 Pocket。稍后,我会阅读它,如果我发现它足够有用,我将使用 Pocket 的“存档”功能永久保存该文章并清理我的 Pocket 收件箱。
|
||||
|
||||
我尽量保持这个阅读清单足够小,并存档我已经处理过的信息。Pocket 允许您标记文章,以便以后更轻松地搜索特定主题的文章。
|
||||
|
||||
如果原始网站消失,您还可以在 Pocket 服务器中保存文章的副本,但是您需要 Pocket Premium 订阅计划。
|
||||
|
||||
Pocket 还具有“发现”功能,根据您保存的文章推荐类似的文章。这是找到可以阅读的新内容的好方法。
|
||||
|
||||
### 用 SnippetStore 做代码片段管理
|
||||
|
||||
从 GitHub 到 Stack Overflow 的答案,到博客文章,经常能找到一些你想要保存备用的好代码片段。它可能是一些不错的算法实现、一个有用的脚本或如何在某种语言中执行某种操作的示例。
|
||||
|
||||
我尝试了很多应用程序,从简单的 GitHub Gists 到 [Boostnote][12],直到我发现 [SnippetStore][13]。
|
||||
|
||||
SnippetStore 是一个开源的代码片段管理应用。SnippetStore 与其他产品的区别在于其简单性。您可以按语言或标签整理片段,并且可以拥有多个文件片段。它不完美,但是可以用。例如,Boostnote 具有更多功能,但我更喜欢 SnippetStore 组织内容的简单方法。
|
||||
|
||||
对于我每天使用的缩写和片段,我更喜欢使用我的编辑器 / IDE 的代码片段功能,因为它更便于使用。我使用 SnippetStore 更像是作为编码示例的参考。
|
||||
|
||||
[Cacher][14] 也是一个有趣的选择,因为它与许多编辑器进行了集成,他有一个命令行工具,并使用 GitHub Gists 作为后端,但其专业计划为 6 美元/月,我觉这有点太贵。
|
||||
|
||||
### 用 DevHints 管理速查表
|
||||
|
||||
[Devhints][15] 是由 Rico Sta. Cruz 创建的一个速查表集合。它是开源的,是用 Jekyll 生成的,Jekyll 是最受欢迎的静态站点生成器之一。
|
||||
|
||||
这些速查表是用 Markdown 编写的,带有一些额外的格式化支持,例如支持列。
|
||||
|
||||
我非常喜欢其界面的外观,并且不像可以在 [Cheatography][16] 等网站上找到 PDF 或图像格式的速查表, Markdown 非常容易添加新内容并保持更新和进行版本控制。
|
||||
|
||||
因为它是开源,我创建了自己的分叉版本,删除了一些我不需要的速查表,并添加了更多。
|
||||
|
||||
我使用速查表作为如何使用某些库或编程语言或记住一些命令的参考。速查表的单个页面非常方便,例如,可以列出特定编程语言的所有基本语法。
|
||||
|
||||
我仍在尝试这个工具,但到目前为止它的工作很好。
|
||||
|
||||
### Diigo
|
||||
|
||||
[Diigo][17] 允许您注释和突出显示部分网站。我在研究新东西时使用它来注释重要信息,或者从文章、Stack Overflow 答案或来自 Twitter 的鼓舞人心的引语中保存特定段落!;)
|
||||
|
||||
* * *
|
||||
|
||||
就这些了。某些工具的功能方面可能存在一些重叠,但正如我在开始时所说的那样,这是一个不断演进的工作流程,因为我一直在尝试和寻找改进和提高工作效率的方法。
|
||||
|
||||
你呢?是如何组织你的知识的?请随时在下面发表评论。
|
||||
|
||||
谢谢你的阅读。
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
作者简介:Bruno Paz,Web 工程师,专精 #PHP 和 @Symfony 框架。热心于新技术。喜欢运动,@FCPorto 的粉丝!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://dev.to/brpaz/how-do-i-organize-my-knowledge-as-a-software-engineer-4387
|
||||
|
||||
作者:[Bruno Paz][a]
|
||||
选题:[oska874](https://github.com/oska874)
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:http://brunopaz.net/
|
||||
[1]:https://dev.to/brpaz
|
||||
[2]:http://twitter.com/brunopaz88
|
||||
[3]:http://github.com/brpaz
|
||||
[4]:https://dev.to/t/knowledge
|
||||
[5]:https://dev.to/t/learning
|
||||
[6]:https://dev.to/t/development
|
||||
[7]:https://www.notion.so/
|
||||
[8]:https://res.cloudinary.com/practicaldev/image/fetch/s--uMbaRUtu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://i.imgur.com/kRnuvMV.png
|
||||
[9]:https://vuepress.vuejs.org/
|
||||
[10]:https://www.gitbook.com/?t=1
|
||||
[11]:https://getpocket.com/
|
||||
[12]:https://boostnote.io/
|
||||
[13]:https://github.com/ZeroX-DG/SnippetStore
|
||||
[14]:https://www.cacher.io/
|
||||
[15]:https://devhints.io/
|
||||
[16]:https://cheatography.com/
|
||||
[17]:https://www.diigo.com/index
|
@ -1,37 +1,35 @@
|
||||
使用企业版 Docker 搭建自己的私有注册服务器
|
||||
使用 Docker 企业版搭建自己的私有注册服务器
|
||||
======
|
||||
|
||||
![docker trusted registry][1]
|
||||
|
||||
Docker 真的很酷,特别是和使用虚拟机相比,转移 Docker 镜像十分容易。如果你已准备好使用 Docker,那你肯定已从 [Docker Hub][2] 上拉取完整的镜像。Docker Hub 是 Docker 的云端注册服务器服务,包含成千上万个供选择的 Docker 镜像。如果你开发了自己的软件包并创建了自己的 Docker 镜像,那么你会想有自己的私有注册服务器。如果你有搭配着专有许可的镜像,或想为你的构建系统提供复杂的持续集成(CI)过程,则更应该拥有自己的私有注册服务器。
|
||||
Docker 真的很酷,特别是和使用虚拟机相比,转移 Docker 镜像十分容易。如果你已准备好使用 Docker,那你肯定已从 [Docker Hub][2] 上拉取过完整的镜像。Docker Hub 是 Docker 的云端注册服务器服务,它包含成千上万个供选择的 Docker 镜像。如果你开发了自己的软件包并创建了自己的 Docker 镜像,那么你会想有自己私有的注册服务器。如果你有搭配着专有许可的镜像,或想为你的构建系统提供复杂的持续集成(CI)过程,则更应该拥有自己的私有注册服务器。
|
||||
|
||||
Docker 企业版包括 Docker Trusted Registry(译者注:DTR,Docker 可信注册服务器)。这是一个具有安全镜像管理功能的高可用的注册服务器,为了在你自己的数据中心或基于云端的架构上运行而构建。在接下来的几周,我们将了解 DTR 是提供安全、可重用且连续的[软件供应链][3]的一个关键组件。你可以通过我们的[免费托管小样][4]立即开始使用,或者通过下载安装进行 30 天的免费试用。下面是开始自己安装的步骤。
|
||||
Docker 企业版包括 <ruby>Docker 可信注册服务器<rt>Docker Trusted Registry</rt></ruby>(DTR)。这是一个具有安全镜像管理功能的高可用的注册服务器,为在你自己的数据中心或基于云端的架构上运行而构建。在接下来,我们将了解到 DTR 是提供安全、可重用且连续的[软件供应链][3]的一个关键组件。你可以通过我们的[免费托管小样][4]立即开始使用,或者通过下载安装进行 30 天的免费试用。下面是开始自己安装的步骤。
|
||||
|
||||
## 配置 Docker 企业版
|
||||
### 配置 Docker 企业版
|
||||
|
||||
Docker Trusted Registry 在通用控制面板(UCP)上运行,所以开始前要安装一个单节点集群。如果你已经有了自己的 UCP 集群,可以跳过这一步。在你的 docker 托管主机上,运行以下命令:
|
||||
DTR 运行于通用控制面板(UCP)之上,所以开始前要安装一个单节点集群。如果你已经有了自己的 UCP 集群,可以跳过这一步。在你的 docker 托管主机上,运行以下命令:
|
||||
|
||||
```
|
||||
# 拉取并安装 UCP
|
||||
|
||||
docker run -it -rm -v /var/run/docker.sock:/var/run/docker.sock -name ucp docker/ucp:latest install
|
||||
```
|
||||
|
||||
当 UCP 启动并运行后,在安装 DTR 之前你还有几件事要做。针对刚刚安装的 UCP 实例,打开浏览器。在日志输出的末尾应该有一个链接。如果你已经有了 Docker 企业版的许可证,那就在这个界面上输入它吧。如果你还没有,可以访问 [Docker 商店][5]获取30天的免费试用版。
|
||||
当 UCP 启动并运行后,在安装 DTR 之前你还有几件事要做。针对刚刚安装的 UCP 实例,打开浏览器。在日志输出的末尾应该有一个链接。如果你已经有了 Docker 企业版的许可证,那就在这个界面上输入它吧。如果你还没有,可以访问 [Docker 商店][5]获取 30 天的免费试用版。
|
||||
|
||||
准备好许可证后,你可能会需要改变一下 UCP 运行的端口。因为这是一个单节点集群,DTR 和 UCP 可能会以相同的端口运行他们的 web 服务。如果你拥有不只一个节点的 UCP 集群,这就不是问题,因为 DTR 会寻找有所需空闲端口的节点。在 UCP 中,点击管理员设置 -> 集群配置并修改控制器端口,比如 5443。
|
||||
准备好许可证后,你可能会需要改变一下 UCP 运行的端口。因为这是一个单节点集群,DTR 和 UCP 可能会以相同的端口运行它们的 web 服务。如果你拥有不只一个节点的 UCP 集群,这就不是问题,因为 DTR 会寻找有所需空闲端口的节点。在 UCP 中,点击“管理员设置 -> 集群配置”并修改控制器端口,比如 5443。
|
||||
|
||||
## 安装 DTR
|
||||
### 安装 DTR
|
||||
|
||||
我们要安装一个简单的、单节点的 Docker Trusted Registry 实例。如果你要安装实际生产用途的 DTR,那么你会将其设置为高可用(HA)模式,即需要另一种存储介质,比如基于云端的对象存储或者 NFS(译者注:Network File System,网络文件系统)。因为目前安装的是一个单节点实例,我们依然使用默认的本地存储。
|
||||
我们要安装一个简单的、单节点的 DTR 实例。如果你要安装实际生产用途的 DTR,那么你会将其设置为高可用(HA)模式,即需要另一种存储介质,比如基于云端的对象存储或者 NFS(LCTT 译注:Network File System,网络文件系统)。因为目前安装的是一个单节点实例,我们依然使用默认的本地存储。
|
||||
|
||||
首先我们需要拉取 DTR 的 bootstrap 镜像。Boostrap 镜像是一个微小的独立安装程序,包括连接到 UCP 以及设置和启动 DTR 所需的所有容器、卷和逻辑网络。
|
||||
首先我们需要拉取 DTR 的 bootstrap 镜像。boostrap 镜像是一个微小的独立安装程序,包括了连接到 UCP 以及设置和启动 DTR 所需的所有容器、卷和逻辑网络。
|
||||
|
||||
使用命令:
|
||||
|
||||
```
|
||||
# 拉取并运行 DTR 引导程序
|
||||
|
||||
docker run -it -rm docker/dtr:latest install -ucp-insecure-tls
|
||||
```
|
||||
|
||||
@ -39,55 +37,42 @@ docker run -it -rm docker/dtr:latest install -ucp-insecure-tls
|
||||
|
||||
然后 DTR bootstrap 镜像会让你确定几项设置,比如 UCP 安装的 URL 地址以及管理员的用户名和密码。从拉取所有的 DTR 镜像到设置全部完成,只需要一到两分钟的时间。
|
||||
|
||||
## 保证一切安全
|
||||
### 保证一切安全
|
||||
|
||||
一切都准备好后,就可以向注册服务器推送或者从中拉取镜像了。在做这一步之前,让我们设置 TLS 证书,以便安全的与 DTR 通信。
|
||||
一切都准备好后,就可以向注册服务器推送或者从中拉取镜像了。在做这一步之前,让我们设置 TLS 证书,以便与 DTR 安全地通信。
|
||||
|
||||
在 Linux 上,我们可以使用以下命令(只需确保更改了 DTR_HOSTNAME 变量,来正确映射我们刚刚设置的 DTR):
|
||||
在 Linux 上,我们可以使用以下命令(只需确保更改了 `DTR_HOSTNAME` 变量,来正确映射我们刚刚设置的 DTR):
|
||||
|
||||
```
|
||||
# 从 DTR 拉取 CA 证书(如果 curl 不可用,你可以使用 wget)
|
||||
|
||||
DTR_HOSTNAME=< DTR 主机名>
|
||||
|
||||
curl -k https://$(DTR_HOSTNAME)/ca > $(DTR_HOSTNAME).crt
|
||||
|
||||
sudo mkdir /etc/docker/certs.d/$(DTR_HOSTNAME)
|
||||
|
||||
sudo cp $(DTR_HOSTNAME) /etc/docker/certs.d/$(DTR_HOSTNAME)
|
||||
|
||||
# 重启 docker 守护进程(在 Ubuntu 14.04 上,使用 `sudo service docker restart` 命令)
|
||||
|
||||
sudo systemctl restart docker
|
||||
```
|
||||
|
||||
对于 Mac 和 Windows 版的 Docker,我们会以不同的方式安装客户端。转入设置 -> 守护进程,在 Insecure Registries(译者注:不安全的注册服务器)部分,输入你的 DTR 主机名。点击应用,docker 守护进程应在重启后可以良好使用。
|
||||
对于 Mac 和 Windows 版的 Docker,我们会以不同的方式安装客户端。转入“设置 -> 守护进程”,在“不安全的注册服务器”部分,输入你的 DTR 主机名。点击“应用”,docker 守护进程应在重启后可以良好使用。
|
||||
|
||||
## 推送和拉取镜像
|
||||
### 推送和拉取镜像
|
||||
|
||||
现在我们需要设置一个仓库来存放镜像。这和 Docker Hub 有一点不同,如果你做的 docker 推送仓库中不存在,它会自动创建一个。要创建一个仓库,在浏览器中打开 https://<Your DTR hostname> 并在出现登录提示时使用你的管理员凭据登录。如果你向 UCP 添加了许可证,则 DTR 会自动获取该许可证。如果没有,请现在确认上传你的许可证。
|
||||
现在我们需要设置一个仓库来存放镜像。这和 Docker Hub 有一点不同,如果你做的 docker 推送仓库中不存在,它会自动创建一个。要创建一个仓库,在浏览器中打开 `https://<Your DTR hostname>` 并在出现登录提示时使用你的管理员凭据登录。如果你向 UCP 添加了许可证,则 DTR 会自动获取该许可证。如果没有,请现在确认上传你的许可证。
|
||||
|
||||
进入刚才的网页之后,点击`新建仓库`按钮来创建新的仓库。
|
||||
进入刚才的网页之后,点击“新建仓库”按钮来创建新的仓库。
|
||||
|
||||
我们会创建一个用于存储 Alpine linux 的仓库,所以在名字输入处键入 `alpine`,点击`保存`(在 DTR 2.5 及更高版本中叫`创建`)。
|
||||
我们会创建一个用于存储 Alpine linux 的仓库,所以在名字输入处键入 “alpine”,点击“保存”(在 DTR 2.5 及更高版本中叫“创建”)。
|
||||
|
||||
现在我们回到 shell 界面输入以下命令:
|
||||
|
||||
```
|
||||
# 拉取 Alpine Linux 的最新版
|
||||
|
||||
docker pull alpine:latest
|
||||
|
||||
# 登入新的 DTR 实例
|
||||
|
||||
docker login <Your DTR hostname>
|
||||
|
||||
# 标记上 Alpine 使能推送其至你的 DTR
|
||||
|
||||
docker tag alpine:latest <Your DTR hostname>/admin/alpine:latest
|
||||
|
||||
# 向 DTR 推送镜像
|
||||
|
||||
docker push <Your DTR hostname>/admin/alpine:latest
|
||||
```
|
||||
|
||||
@ -95,22 +80,19 @@ docker push <Your DTR hostname>/admin/alpine:latest
|
||||
|
||||
```
|
||||
# 从 DTR 中拉取镜像
|
||||
|
||||
docker pull <Your DTR hostname>/admin/alpine:latest
|
||||
```
|
||||
|
||||
DTR 具有许多优秀的镜像管理功能,例如图像缓存,镜像,扫描,签名甚至自动化供应链策略。这些功能我们在后期的博客文章中更详细的探讨。
|
||||
|
||||
|
||||
DTR 具有许多优秀的镜像管理功能,例如镜像的缓存、映像、扫描、签名甚至自动化供应链策略。这些功能我们在后期的博客文章中更详细的探讨。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://blog.docker.com/2018/01/dtr/
|
||||
|
||||
作者:[Patrick Devine;Rolf Neugebauer;Docker Core Engineering;Matt Bentley][a]
|
||||
作者:[Patrick Devine][a]
|
||||
译者:[fuowang](https://github.com/fuowang)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
53
published/201811/20180127 Write Dumb Code.md
Normal file
53
published/201811/20180127 Write Dumb Code.md
Normal file
@ -0,0 +1,53 @@
|
||||
写直白的代码
|
||||
====
|
||||
|
||||
为开源项目作贡献最好的方式是为它减少代码,我们应致力于写出让新手程序员无需注释就容易理解的代码,让维护者也无需花费太多精力就能着手维护。
|
||||
|
||||
在学生时代,我们会更多地用复杂巧妙的技术去挑战新的难题。首先我们会学习循环,然后是函数啊,类啊,等等。当我们到达一定高的程度,能用更高级的技术写更长的程序,我们会因此受到称赞。此刻我们发现老司机们用 monads 而新手们用 loop 作循环。
|
||||
|
||||
之后我们毕业找了工作,或者和他人合作开源项目。我们用在学校里学到的各种炫技寻求并骄傲地给出解决方案的代码实现。
|
||||
|
||||
*哈哈,我能扩展这个项目,并实现某牛 X 功能啦,我这里能用继承啦,我太聪明啦!*
|
||||
|
||||
我们实现了某个小的功能,并以充分的理由觉得自己做到了。现实项目中的编程却不是针对某某部分的功能而言。以我个人的经验而言,以前我很开心的去写代码,并骄傲地向世界展示我所知道的事情。有例为证,作为对某种编程技术的偏爱,这是用另一种元编程语言构建的一个 [线性代数语言][1],注意,这么多年以来一直没人愿意碰它。
|
||||
|
||||
在维护了更多的代码后,我的观点发生了变化。
|
||||
|
||||
1. 我们不应去刻意探求如何构建软件。软件是我们为解决问题所付出的代价,那才是我们真实的目的。我们应努力为了解决问题而构建较小的软件。
|
||||
2. 我们应使用尽可能简单的技术,那么更多的人就越可能会使用,并且无需理解我们所知的高级技术就能扩展软件的功能。当然,在我们不知道如何使用简单技术去实现时,我们也可以使用高级技术。
|
||||
|
||||
所有的这些例子都不是听来的故事。我遇到的大部分人会认同某些部分,但不知为什么,当我们向一个新项目贡献代码时又会忘掉这个初衷。直觉里用复杂技术去构建的念头往往会占据上风。
|
||||
|
||||
### 软件是种投入
|
||||
|
||||
你写的每行代码都要花费人力。写代码当然是需要时间的,也许你会认为只是你个人在奉献,然而这些代码在被审阅的时候也需要花时间理解,对于未来维护和开发人员来说,他们在维护和修改代码时同样要花费时间。否则他们完全可以用这时间出去晒晒太阳,或者陪伴家人。
|
||||
|
||||
所以,当你向某个项目贡献代码时,请心怀谦恭。就像是,你正和你的家人进餐时,餐桌上却没有足够的食物,你只索取你所需的部分,别人对你的自我约束将肃然起敬。以更少的代码去解决问题是很难的,你肩负重任的同时自然减轻了别人的重负。
|
||||
|
||||
### 技术越复杂越难维护
|
||||
|
||||
作为学生,逐渐使用高端技术证明了自己的价值。这体现在,首先我们有能力在开源项目中使用函数,接着是类,然后是高阶函数,monads 等等。我们向同行显示自己的解决方案时,常因自己所用技术高低而感到自豪或卑微。
|
||||
|
||||
而在现实中,和团队去解决问题时,情况发生了逆转。现在,我们致力于尽可能使用简单的代码去解决问题。简单方式解决问题使新手程序员能够以此扩展并解决其他问题。简单的代码让别人容易上手,效果立竿见影。我们藉以只用简单的技术去解决难题,从而展示自己的价值。
|
||||
|
||||
*看,我用循环替代了递归函数并且一样达到了我们的需求。当然我明白这是不够聪明的做法,不过我注意到新手同事在这里会遇上麻烦,我觉得这种改变将有所帮助吧。*
|
||||
|
||||
如果你是个好的程序员,你不需要证明你知道很多炫技。相应的,你可以通过用一个简单的方法解决一个问题来显示你的价值,并激发你的团队在未来的时间里去完善它。
|
||||
|
||||
### 当然,也请保持节制
|
||||
|
||||
话虽如此,过于遵循 “用简单的工具去构建” 的教条也会降低生产力。通常用递归会比用循环解决问题更简单,用类或 monad 才是正确的途径。还有两种情况另当别论,一是只是只为满足自我而创建的系统,或者是别人毫无构建经验的系统。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://matthewrocklin.com/blog/work/2018/01/27/write-dumb-code
|
||||
|
||||
作者:[Matthew Rocklin][a]
|
||||
译者:[plutoid](https://github.com/plutoid)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:http://matthewrocklin.com
|
||||
[1]:https://github.com/mrocklin/matrix-algebra
|
@ -0,0 +1,78 @@
|
||||
Emacs 系列(一):抛掉一切,投入 Emacs 和 Org 模式的怀抱
|
||||
======
|
||||
|
||||
我必须承认,在使用了几十年的 vim 后, 我被 [Emacs][1] 吸引了。
|
||||
|
||||
长期以来,我一直对如何组织安排事情感到沮丧。我也有用过 [GTD][2] 和 [ZTD][3] 之类的方法,但是像邮件或是大型文件这样的事务真的很难来组织安排。
|
||||
|
||||
我一直在用 Asana 处理任务,用 Evernote 做笔记,用 Thunderbird 处理邮件,把 ikiwiki 和其他的一些项目组合作为个人知识库,而且还在电脑的归档了各种文件。当我的新工作需要将 Slack 也加入进来时,我终于忍无可忍了。
|
||||
|
||||
许多 TODO 管理工具与电子邮件集成的很差。当你想做“提醒我在一周内回复这个邮件”之类的事时,很多时候是不可能的,因为这个工具不能以一种能够轻松回复的方式存储邮件。而这个问题在 Slack 上更为严重。
|
||||
|
||||
就在那时,我偶然发现了 [Carsten Dominik 在 Google Talk 上关于 Org 模式的讲话][4]。Carsten 是 Org 模式的作者,即便是这个讲话已经有 10 年了,但它仍然很具有参考价值。
|
||||
|
||||
我之前有用过 [Org 模式][5],但是每次我都没有真正的深入研究它,
|
||||
因为我当时的反应是“一个大纲编辑器?但我需要的是待办事项列表”。我就这么错过了它。但实际上 Org 模式就是我所需要的。
|
||||
|
||||
### 什么是 Emacs?什么是 Org 模式?
|
||||
|
||||
Emacs 最初是一个文本编辑器,现在依然是一个文本编辑器,而且这种传统无疑贯穿始终。但是说 Emacs 是个编辑器是很不公平的。
|
||||
|
||||
Emacs 更像一个平台或是工具包。你不仅可以用它来编辑源代码,而且配置 Emacs 本身也是编程,里面有很多模式。就像编写一个 Firefox 插件一样简单,只要几行代码,然后,模式里的操作就改变了。
|
||||
|
||||
Org 模式也一样。确实,它是一个大纲编辑器,但它真正所包含的不止如此。它是一个信息组织平台。它的网站上写着,“你可以用纯文本来记录你的生活:你可以用 Org 模式来记笔记,处理待办事项,规划项目和使用快速有效的纯文本系统编写文档。”
|
||||
|
||||
### 捕获
|
||||
|
||||
如果你读过基于 GTD 的生产力指南,那么他们强调的一件事就是毫不费力地获取项目。这个想法是,当某件事突然出现在你的脑海里时,把它迅速输入一个受信任的系统,这样你就可以继续做你正在做的事情。Org 模式有一个专门的捕获系统。我可以在 Emacs 的任何地方按下 `C-c c` 键,它就会空出一个位置来记录我的笔记。最关键的是,自动嵌入到笔记中的链接可以链接到我按下 `C-c c` 键时正在编辑的那一行。如果我正在编辑文件,它会链回到那个文件和我所在的行。如果我正在浏览邮件,它就会链回到那封邮件(通过邮件的 Message-Id,这样它就可以在任何一个文件夹中找到邮件)。聊天时也一样,甚至是当你在另一个 Org 模式中也可也这样。
|
||||
|
||||
这样我就可以做一个笔记,它会提醒我在一周内回复某封邮件,当我点击这个笔记中的链接时,它会在我的邮件阅读器中弹出这封邮件 —— 即使我随后将它从收件箱中存档。
|
||||
|
||||
没错,这正是我要找的!
|
||||
|
||||
### 工具套件
|
||||
|
||||
一旦你开始使用 Org 模式,很快你就会想将所有的事情都集成到里面。有可以从网络上捕获内容的浏览器插件,也有多个 Emacs 邮件或新闻阅读器与之集成,ERC(IRC 客户端)也不错。所以我将自己从 Thunderbird 和 mairix + mutt (用于邮件归档)换到了 mu4e,从 xchat + slack 换到了 ERC。
|
||||
|
||||
你可能不明白,我喜欢这些基于 Emacs 的工具,而不是具有相同功能的单独的工具。
|
||||
|
||||
一个小花絮:我又在使用离线 IMAP 了!我甚至在很久以前就用过 GNUS。
|
||||
|
||||
### 用一个 Emacs 进程来管理
|
||||
|
||||
我以前也经常使用 Emacs,那时,Emacs 是一个“大”的程序(现在显示电源状态的小程序占用的内存要比 Emacs 多)。当时存在在启动时间过长的问题,但是现在已经有连接到一个正在运行的 Emacs 进程的解决方法。
|
||||
|
||||
我喜欢用 Mod-p(一个 [xmonad][6] 中 [dzen][7] 菜单栏的快捷方式,但是在大多数传统的桌面环境中该功能的快捷键是 `Alt-F2`)来启动程序(LCTT 译注:xmonad 是一种平铺桌面;dzen 是 X11 窗口下管理消息、提醒和菜单的程序)。这个设置在不运行多个<ruby>[emacs 们](https://www.emacswiki.org/emacs/Emacsen)<rt>emacsen</rt></ruby>时很方便,因为这样就不会在试图捕获另一个打开的文件时出问题。这中方法很简单:创建一个叫 `em` 的脚本并将它放到我自己的环境变量中。就像这样:
|
||||
|
||||
```
|
||||
#!/bin/bash exec emacsclient -c -a "" "$@"
|
||||
```
|
||||
|
||||
如果没有 emacs 进程存在的话,就会创建一个新的 emacs 进程,否则的话就直接使用已存在的进程。这样做还有一个好处:`-nw` 之类的参数工作的很好,它实际上就像在 shell 提示符下输入 `emacs` 一样。它很适合用于设置 `EDITOR` 环境变量。
|
||||
|
||||
### 下一篇
|
||||
|
||||
接下来我将讨论我的使用情况,并展示以下的配置:
|
||||
|
||||
* Org 模式,包括计算机之间的同步、捕获、日程和待办事项、文件、链接、关键字和标记、各种导出(幻灯片)等。
|
||||
* mu4e,用于电子邮件,包括多个账户,bbdb 集成
|
||||
* ERC,用于 IRC 和即时通讯
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://changelog.complete.org/archives/9861-emacs-1-ditching-a-bunch-of-stuff-and-moving-to-emacs-and-org-mode
|
||||
|
||||
作者:[John Goerzen][a]
|
||||
译者:[oneforalone](https://github.com/oneforalone)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:http://changelog.complete.org/archives/author/jgoerzen
|
||||
[1]:https://www.gnu.org/software/emacs/
|
||||
[2]:https://gettingthingsdone.com/
|
||||
[3]:https://zenhabits.net/zen-to-done-the-simple-productivity-e-book/
|
||||
[4]:https://www.youtube.com/watch?v=oJTwQvgfgMM
|
||||
[5]:https://orgmode.org/
|
||||
[6]:https://wiki.archlinux.org/index.php/Xmonad_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)
|
||||
[7]:http://robm.github.io/dzen/
|
@ -1,26 +1,34 @@
|
||||
DevOps应聘者应该准备回答的20个问题
|
||||
DevOps 应聘者应该准备回答的 20 个问题
|
||||
======
|
||||
|
||||
> 想要建立一个积极,富有成效的工作环境? 在招聘过程中要专注于寻找契合点。
|
||||
|
||||

|
||||
聘请一个不合适的人代价是很高的。根据Link人力资源的首席执行官Jörgen Sundberg的统计,招聘,雇佣一名新员工将会花费公司$240,000之多,当你进行了一次不合适的招聘:
|
||||
* 你失去了他们所知道的。
|
||||
* 你失去了他们认识的人
|
||||
|
||||
聘请一个不合适的人[代价是很高的][1]。根据 Link 人力资源的首席执行官 Jörgen Sundberg 的统计,招聘、雇佣一名新员工将会花费公司$240,000 之多,当你进行了一次不合适的招聘:
|
||||
|
||||
* 你失去了他们的知识技能。
|
||||
* 你失去了他们的人脉。
|
||||
* 你的团队将可能进入到一个组织发展的震荡阶段
|
||||
* 你的公司将会面临组织破裂的风险
|
||||
|
||||
当你失去一名员工的时候,你就像丢失了公司图谱中的一块。同样值得一提的是另一端的疼痛。应聘到一个错误工作岗位的员工会感受到很大的压力以及整个身心的不满意,甚至是健康问题。
|
||||
当你失去一名员工的时候,你就像丢失了公司版图中的一块。同样值得一提的是另一端的痛苦。应聘到一个错误工作岗位的员工会感受到很大的压力以及整个身心的不满意,甚至是健康问题。
|
||||
|
||||
另外一方面,当你招聘到合适的人时,新的员工将会:
|
||||
* 丰富公司现有的文化,使你的组织成为一个更好的工作场所。研究表明一个积极的工作文化能够帮助驱动一个更长久的财务业绩,而且如果你在一个欢快的环境中工 作,你更有可能在生活中做的更好。
|
||||
|
||||
* 丰富公司现有的文化,使你的组织成为一个更好的工作场所。研究表明一个积极的工作文化能够帮助更长久推动财务业绩增长,而且如果你在一个欢快的环境中工作,你更有可能在生活中做的更好。
|
||||
* 热爱和你的组织在一起工作。当人们热爱他们所在做的,他们会趋向于做的更好。
|
||||
|
||||
招聘适合的或者加强现有的文化在DevOps和敏捷团多中是必不可少的。也就是说雇佣到一个能够鼓励积极合作的人,以便来自不同背景,有着不同目标和工作方式的团队能够在一起有效的工作。你新雇佣的员工因应该能够帮助团队合作来充分发挥放大他们的价值同时也能够增加员工的满意度以及平衡组织目标的冲突。他或者她应该能够通过明智的选择工具和工作流来促进你的组织,文化就是一切。
|
||||
招聘以适合或加强现有的文化在 DevOps 和敏捷团多中是必不可少的。也就是说雇佣到一个能够鼓励积极合作的人,以便来自不同背景,有着不同目标和工作方式的团队能够在一起有效的工作。你新雇佣的员工应该能够帮助团队合作来充分发挥放大他们的价值,同时也能够增加员工的满意度以及平衡组织目标的冲突。他或者她应该能够通过明智的选择工具和工作流来促进你的组织,文化就是一切。
|
||||
|
||||
作为我们 2017 年 11 月发布的一篇文章 [DevOps 的招聘经理应该准备回答的 20 个问题][4] 的回应,这篇文章将会重点关注在如何招聘最适合的人。
|
||||
|
||||
作为我们2017年11月发布的一篇文章,[DevOps的招聘经理应该准备回答的20个问题][4],这篇文章将会重点关注在如何招聘最适合的人。
|
||||
### 为什么招聘走错了方向
|
||||
很多公司现在在用的典型的雇佣策略是基于人才过剩的基础上:
|
||||
|
||||
* 职位公告栏。
|
||||
* 关注和所需才能符合的应聘者。
|
||||
很多公司现在用的典型的雇佣策略是基于人才过剩的基础上:
|
||||
|
||||
* 在职位公告栏发布招聘。
|
||||
* 关注具有所需才能的应聘者。
|
||||
* 尽可能找多的候选者。
|
||||
* 通过面试淘汰弱者。
|
||||
* 通过正式的面试淘汰更多的弱者。
|
||||
@ -30,37 +38,48 @@ DevOps应聘者应该准备回答的20个问题
|
||||

|
||||
|
||||
职位公告栏是有成千上万失业者人才过剩的经济大萧条时期发明的。在今天的求职市场上已经没有人才过剩了,然而我们仍然在使用基于此的招聘策略。
|
||||
|
||||

|
||||
|
||||
### 雇佣最合适的人员:运用文化和情感
|
||||
在人才过剩雇佣策略背后的思想是去设计工作岗位然后将人员安排进去。
|
||||
相反,做相反的事情:寻找将会积极融入你的商业文化的人才,然后为他们寻找他们热爱的最合适的岗位。要想如此实现,你必须能够围绕他们热情为他们创造工作岗位。
|
||||
**谁正在寻找一份工作?** 根据一份2016年对美国50,000名开发者的调查显示,[85.7%的受访对象][5]要么对新的机会不感兴趣,要么对于寻找新工作没有积极性。在寻找工作的那部分中,有将近[28.3%的求职者][5]来自于朋友的推荐。如果你只是在那些在找工作的人中寻找人才,你将会错过高端的人才。
|
||||
**运用团队力量去发现和寻找潜力的雇员**。列如,戴安娜是你的团队中的一名开发者,她所提供的机会即使她已经从事编程很多年而且在期间已经结识了很多从事热爱他们所从事的工作的人。难道你不认为她所推荐的潜在员工在技能,知识和智慧上要比HR所寻找的要优秀吗?在要求戴安娜分享她同伴之前,通知她即将到来的使命任务,向她阐明你要雇佣潜在有探索精神的团队,描述在将来会需要的知识领域。
|
||||
**雇员想要什么?**一份来自千禧年,婴儿潮实时期出生的人的对比综合性研究显示,20% 的人所想要的是相同的:
|
||||
|
||||
在人才过剩雇佣策略背后的思想是设计工作岗位然后将人员安排进去。
|
||||
|
||||
反而应该反过来:寻找将会积极融入你的商业文化的人才,然后为他们寻找他们热爱的最合适的岗位。要想实现这样的目标,你必须能够围绕他们热情为他们创造工作岗位。
|
||||
|
||||
**谁正在寻找一份工作?** 根据一份 2016 年对美国 50000 名开发者的调查显示,[85.7% 的受访对象][5]要么对新的机会不感兴趣,要么对于寻找新工作没有积极性。在寻找工作的那部分中,有将近 [28.3% 的求职者][5]来自于朋友的推荐。如果你只是在那些在找工作的人中寻找人才,你将会错过高端的人才。
|
||||
|
||||
**运用团队力量去发现和寻找潜力的雇员**。例如,戴安娜是你的团队中的一名开发者,她所能提供的机会是,她已经[从事编程很多年][6]而且在期间已经结识了很多从事热爱他们所从事的工作的人。难道你不认为她所推荐的潜在员工在技能、知识和智慧上要比 HR 所寻找的要优秀吗?在要求戴安娜分享她同伴之前,通知她即将到来的使命任务,向她阐明你要雇佣潜在有探索精神的团队,描述在将来会需要的知识领域。
|
||||
|
||||
**雇员想要什么?**一份来自千禧年婴儿潮时期出生的人的对比综合性研究显示,20% 的人所想要的是相同的:
|
||||
|
||||
1. 对组织产生积极的影响
|
||||
2. 帮助解决社交或者环境上的挑战
|
||||
3. 和一群有动力的人一起工作
|
||||
|
||||
### 面试的挑战
|
||||
面试应该是招聘者和应聘者双方为了寻找最合适的人才进行的一次双方之间的对话。将面试聚焦在企业文化和情感对话两个问题上:这个应聘者将会丰富你的企业文化并且会热爱和你在一起工作吗?你能够在工作中帮他们取得成功吗?
|
||||
**对于招聘经理来说:** 每一次的面试都是你学习如何将自己的组织变得对未来的团队成员更有吸引力,并且每次积极的面试多都可能是你发现人才(即使你不会雇佣)的机会。每个人都将会记得积极有效的面试的经历。即使他们不会被雇佣,他们将会和他们的朋友谈论这次经历,你竟会得到一个被推荐的机会。这又很大的好处:如果你无法吸引到这个人才,你也将会从中学习吸取经验并且改善。
|
||||
**对面试者来说**:每次的面试都是你释放激情的机会
|
||||
|
||||
### 助你释放潜在雇员激情的20个问题
|
||||
面试应该是招聘者和应聘者双方为了寻找最合适的人才进行的一次双方之间的对话。将面试聚焦在企业文化和情感对话两个问题上:这个应聘者将会丰富你的企业文化并且会热爱和你在一起工作吗?你能够在工作中帮他们取得成功吗?
|
||||
|
||||
**对于招聘经理来说:** 每一次的面试都是你学习如何将自己的组织变得对未来的团队成员更有吸引力,并且每次积极的面试都可能是你发现人才(即使你不会雇佣)的机会。每个人都将会记得积极有效的面试的经历。即使他们不会被雇佣,他们将会和他们的朋友谈论这次经历,你会得到一个被推荐的机会。这有很大的好处:如果你无法吸引到这个人才,你也将会从中学习吸取经验并且改善。
|
||||
|
||||
**对面试者来说**:每次的面试都是你释放激情的机会。
|
||||
|
||||
### 助你释放潜在雇员激情的 20 个问题
|
||||
|
||||
1. 你热爱什么?
|
||||
2. “今天早晨我已经迫不及待的要去工作”你怎么看待这句话?
|
||||
2. “今天早晨我已经迫不及待的要去工作”,你怎么看待这句话?
|
||||
3. 你曾经最快乐的是什么?
|
||||
4. 你曾经解决问题的最典型的例子是什么,你是如何解决的?
|
||||
5. 你如何看待配对学习?
|
||||
6. 你到达办公室和离开办公室心里最先想到的是什么?
|
||||
7. 你如果你有一次改变你之前或者现在的共工作的一件事的机会,将会是什么事?
|
||||
8. 当你在这工作的时候,你最兴奋去学习什么?
|
||||
7. 你如果你有一次改变你之前或者现在的工作中的一件事的机会,将会是什么事?
|
||||
8. 当你在工作的时候,你最乐于去学习什么?
|
||||
9. 你的梦想是什么,你如何去实现?
|
||||
10. 你在学会如何去实现你的追求的时候想要或者需要什么?
|
||||
11. 你的价值观是什么?
|
||||
12. 你是如何坚守自己的价值观的?
|
||||
13. 平衡在你的生活中意味着什么?
|
||||
13. 在你的生活中平衡意味着什么?
|
||||
14. 你最引以为傲的工作交流能力是什么?为什么?
|
||||
15. 你最喜欢营造什么样的环境?
|
||||
16. 你喜欢别人怎样对待你?
|
||||
@ -70,14 +89,13 @@ DevOps应聘者应该准备回答的20个问题
|
||||
20. 如果你正在雇佣我,你将会问我什么问题?
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/3/questions-devops-employees-should-answer
|
||||
|
||||
作者:[Catherine Louis][a]
|
||||
译者:[FelixYFZ](https://github.com/FelixYFZ)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -0,0 +1,447 @@
|
||||
17 种查看 Linux 物理内存的方法
|
||||
=======
|
||||
|
||||
大多数系统管理员在遇到性能问题时会检查 CPU 和内存利用率。Linux 中有许多实用程序可以用于检查物理内存。这些命令有助于我们检查系统中存在的物理内存,还允许用户检查各种方面的内存利用率。
|
||||
|
||||
我们大多数人只知道很少的命令,在本文中我们试图包含所有可能的命令。
|
||||
|
||||
你可能会想,为什么我想知道所有这些命令,而不是知道一些特定的和例行的命令呢。
|
||||
|
||||
不要觉得没用或对此有负面的看法,因为每个人都有不同的需求和看法,所以,对于那些在寻找其它目的的人,这对于他们非常有帮助。
|
||||
|
||||
### 什么是 RAM
|
||||
|
||||
计算机内存是能够临时或永久存储信息的物理设备。RAM 代表随机存取存储器,它是一种易失性存储器,用于存储操作系统,软件和硬件使用的信息。
|
||||
|
||||
有两种类型的内存可供选择:
|
||||
|
||||
* 主存
|
||||
* 辅助内存
|
||||
|
||||
主存是计算机的主存储器。CPU 可以直接读取或写入此内存。它固定在电脑的主板上。
|
||||
|
||||
* **RAM**:随机存取存储器是临时存储。关闭计算机后,此信息将消失。
|
||||
* **ROM**: 只读存储器是永久存储,即使系统关闭也能保存数据。
|
||||
|
||||
### 方法-1:使用 free 命令
|
||||
|
||||
`free` 显示系统中空闲和已用的物理内存和交换内存的总量,以及内核使用的缓冲区和缓存。它通过解析 `/proc/meminfo` 来收集信息。
|
||||
|
||||
**建议阅读:** [free – 在 Linux 系统中检查内存使用情况统计(空闲和已用)的标准命令][1]
|
||||
|
||||
```
|
||||
$ free -m
|
||||
total used free shared buff/cache available
|
||||
Mem: 1993 1681 82 81 228 153
|
||||
Swap: 12689 1213 11475
|
||||
|
||||
$ free -g
|
||||
total used free shared buff/cache available
|
||||
Mem: 1 1 0 0 0 0
|
||||
Swap: 12 1 11
|
||||
```
|
||||
|
||||
### 方法-2:使用 /proc/meminfo 文件
|
||||
|
||||
`/proc/meminfo` 是一个虚拟文本文件,它包含有关系统 RAM 使用情况的大量有价值的信息。
|
||||
|
||||
它报告系统上的空闲和已用内存(物理和交换)的数量。
|
||||
|
||||
```
|
||||
$ grep MemTotal /proc/meminfo
|
||||
MemTotal: 2041396 kB
|
||||
|
||||
$ grep MemTotal /proc/meminfo | awk '{print $2 / 1024}'
|
||||
1993.55
|
||||
|
||||
$ grep MemTotal /proc/meminfo | awk '{print $2 / 1024 / 1024}'
|
||||
1.94683
|
||||
```
|
||||
|
||||
### 方法-3:使用 top 命令
|
||||
|
||||
`top` 命令是 Linux 中监视实时系统进程的基本命令之一。它显示系统信息和运行的进程信息,如正常运行时间、平均负载、正在运行的任务、登录的用户数、CPU 数量和 CPU 利用率,以及内存和交换信息。运行 `top` 命令,然后按下 `E` 来使内存利用率以 MB 为单位显示。
|
||||
|
||||
**建议阅读:** [TOP 命令示例监视服务器性能][2]
|
||||
|
||||
```
|
||||
$ top
|
||||
|
||||
top - 14:38:36 up 1:59, 1 user, load average: 1.83, 1.60, 1.52
|
||||
Tasks: 223 total, 2 running, 221 sleeping, 0 stopped, 0 zombie
|
||||
%Cpu(s): 48.6 us, 11.2 sy, 0.0 ni, 39.3 id, 0.3 wa, 0.0 hi, 0.5 si, 0.0 st
|
||||
MiB Mem : 1993.551 total, 94.184 free, 1647.367 used, 252.000 buff/cache
|
||||
MiB Swap: 12689.58+total, 11196.83+free, 1492.750 used. 306.465 avail Mem
|
||||
|
||||
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
|
||||
9908 daygeek 20 0 2971440 649324 39700 S 55.8 31.8 11:45.74 Web Content
|
||||
21942 daygeek 20 0 2013760 308700 69272 S 35.0 15.1 4:13.75 Web Content
|
||||
4782 daygeek 20 0 3687116 227336 39156 R 14.5 11.1 16:47.45 gnome-shell
|
||||
```
|
||||
|
||||
### 方法-4:使用 vmstat 命令
|
||||
|
||||
`vmstat` 是一个漂亮的标准工具,它报告 Linux 系统的虚拟内存统计信息。`vmstat` 报告有关进程、内存、分页、块 IO、陷阱和 CPU 活动的信息。它有助于 Linux 管理员在故障检修时识别系统瓶颈。
|
||||
|
||||
**建议阅读:** [vmstat – 一个报告虚拟内存统计信息的标准且漂亮的工具][3]
|
||||
|
||||
```
|
||||
$ vmstat -s | grep "total memory"
|
||||
2041396 K total memory
|
||||
|
||||
$ vmstat -s -S M | egrep -ie 'total memory'
|
||||
1993 M total memory
|
||||
|
||||
$ vmstat -s | awk '{print $1 / 1024 / 1024}' | head -1
|
||||
1.94683
|
||||
|
||||
```
|
||||
|
||||
### 方法-5:使用 nmon 命令
|
||||
|
||||
`nmon` 是另一个很棒的工具,用于在 Linux 终端上监视各种系统资源,如 CPU、内存、网络、磁盘、文件系统、NFS、top 进程、Power 的微分区和资源(Linux 版本和处理器)。
|
||||
|
||||
只需按下 `m` 键,即可查看内存利用率统计数据(缓存、活动、非活动、缓冲、空闲,以 MB 和百分比为单位)。
|
||||
|
||||
**建议阅读:** [nmon – Linux 中一个监视系统资源的漂亮的工具][4]
|
||||
|
||||
```
|
||||
┌nmon─14g──────[H for help]───Hostname=2daygeek──Refresh= 2secs ───07:24.44─────────────────┐
|
||||
│ Memory Stats ─────────────────────────────────────────────────────────────────────────────│
|
||||
│ RAM High Low Swap Page Size=4 KB │
|
||||
│ Total MB 32079.5 -0.0 -0.0 20479.0 │
|
||||
│ Free MB 11205.0 -0.0 -0.0 20479.0 │
|
||||
│ Free Percent 34.9% 100.0% 100.0% 100.0% │
|
||||
│ MB MB MB │
|
||||
│ Cached= 19763.4 Active= 9617.7 │
|
||||
│ Buffers= 172.5 Swapcached= 0.0 Inactive = 10339.6 │
|
||||
│ Dirty = 0.0 Writeback = 0.0 Mapped = 11.0 │
|
||||
│ Slab = 636.6 Commit_AS = 118.2 PageTables= 3.5 │
|
||||
│───────────────────────────────────────────────────────────────────────────────────────────│
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
└───────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 方法-6:使用 dmidecode 命令
|
||||
|
||||
`dmidecode` 是一个读取计算机 DMI 表内容的工具,它以人类可读的格式显示系统硬件信息。(DMI 意即桌面管理接口,也有人说是读取的是 SMBIOS —— 系统管理 BIOS)
|
||||
|
||||
此表包含系统硬件组件的描述,以及其它有用信息,如序列号、制造商信息、发布日期和 BIOS 修改等。
|
||||
|
||||
**建议阅读:** [Dmidecode – 获取 Linux 系统硬件信息的简便方法][5]
|
||||
|
||||
```
|
||||
# dmidecode -t memory | grep Size:
|
||||
Size: 8192 MB
|
||||
Size: No Module Installed
|
||||
Size: No Module Installed
|
||||
Size: 8192 MB
|
||||
Size: No Module Installed
|
||||
Size: No Module Installed
|
||||
Size: No Module Installed
|
||||
Size: No Module Installed
|
||||
Size: No Module Installed
|
||||
Size: No Module Installed
|
||||
Size: No Module Installed
|
||||
Size: No Module Installed
|
||||
Size: 8192 MB
|
||||
Size: No Module Installed
|
||||
Size: No Module Installed
|
||||
Size: 8192 MB
|
||||
Size: No Module Installed
|
||||
Size: No Module Installed
|
||||
Size: No Module Installed
|
||||
Size: No Module Installed
|
||||
Size: No Module Installed
|
||||
Size: No Module Installed
|
||||
Size: No Module Installed
|
||||
Size: No Module Installed
|
||||
```
|
||||
|
||||
只打印已安装的 RAM 模块。
|
||||
|
||||
```
|
||||
# dmidecode -t memory | grep Size: | grep -v "No Module Installed"
|
||||
Size: 8192 MB
|
||||
Size: 8192 MB
|
||||
Size: 8192 MB
|
||||
Size: 8192 MB
|
||||
```
|
||||
|
||||
汇总所有已安装的 RAM 模块。
|
||||
|
||||
```
|
||||
# dmidecode -t memory | grep Size: | grep -v "No Module Installed" | awk '{sum+=$2}END{print sum}'
|
||||
32768
|
||||
```
|
||||
|
||||
### 方法-7:使用 hwinfo 命令
|
||||
|
||||
`hwinfo` 意即硬件信息,它是另一个很棒的实用工具,用于探测系统中存在的硬件,并以人类可读的格式显示有关各种硬件组件的详细信息。
|
||||
|
||||
它报告有关 CPU、RAM、键盘、鼠标、图形卡、声音、存储、网络接口、磁盘、分区、BIOS 和网桥等的信息。
|
||||
|
||||
**建议阅读:** [hwinfo(硬件信息)– 一个在 Linux 系统上检测系统硬件信息的好工具][6]
|
||||
|
||||
```
|
||||
$ hwinfo --memory
|
||||
01: None 00.0: 10102 Main Memory
|
||||
[Created at memory.74]
|
||||
Unique ID: rdCR.CxwsZFjVASF
|
||||
Hardware Class: memory
|
||||
Model: "Main Memory"
|
||||
Memory Range: 0x00000000-0x7a4abfff (rw)
|
||||
Memory Size: 1 GB + 896 MB
|
||||
Config Status: cfg=new, avail=yes, need=no, active=unknown
|
||||
```
|
||||
|
||||
### 方法-8:使用 lshw 命令
|
||||
|
||||
`lshw`(代表 Hardware Lister)是一个小巧的工具,可以生成机器上各种硬件组件的详细报告,如内存配置、固件版本、主板配置、CPU 版本和速度、缓存配置、USB、网卡、显卡、多媒体、打印机、总线速度等。
|
||||
|
||||
它通过读取 `/proc` 目录和 DMI 表中的各种文件来生成硬件信息。
|
||||
|
||||
**建议阅读:** [LSHW (Hardware Lister) – 一个在 Linux 上获取硬件信息的好工具][7]
|
||||
|
||||
```
|
||||
$ sudo lshw -short -class memory
|
||||
[sudo] password for daygeek:
|
||||
H/W path Device Class Description
|
||||
==================================================
|
||||
/0/0 memory 128KiB BIOS
|
||||
/0/1 memory 1993MiB System memory
|
||||
```
|
||||
|
||||
### 方法-9:使用 inxi 命令
|
||||
|
||||
`inxi` 是一个很棒的工具,它可以检查 Linux 上的硬件信息,并提供了大量的选项来获取 Linux 系统上的所有硬件信息,这些特性是我在 Linux 上的其它工具中从未发现的。它是从 locsmif 编写的古老的但至今看来都异常灵活的 infobash 演化而来的。
|
||||
|
||||
`inxi` 是一个脚本,它可以快速显示系统硬件、CPU、驱动程序、Xorg、桌面、内核、GCC 版本、进程、RAM 使用情况以及各种其它有用的信息,还可以用于论坛技术支持和调试工具。
|
||||
|
||||
**建议阅读:** [inxi – 一个检查 Linux 上硬件信息的好工具][8]
|
||||
|
||||
```
|
||||
$ inxi -F | grep "Memory"
|
||||
Info: Processes: 234 Uptime: 3:10 Memory: 1497.3/1993.6MB Client: Shell (bash) inxi: 2.3.37
|
||||
```
|
||||
|
||||
### 方法-10:使用 screenfetch 命令
|
||||
|
||||
`screenfetch` 是一个 bash 脚本。它将自动检测你的发行版,并在右侧显示该发行版标识的 ASCII 艺术版本和一些有价值的信息。
|
||||
|
||||
**建议阅读:** [ScreenFetch – 以 ASCII 艺术标志在终端显示 Linux 系统信息][9]
|
||||
|
||||
```
|
||||
$ screenfetch
|
||||
./+o+- daygeek@ubuntu
|
||||
yyyyy- -yyyyyy+ OS: Ubuntu 17.10 artful
|
||||
://+//////-yyyyyyo Kernel: x86_64 Linux 4.13.0-37-generic
|
||||
.++ .:/++++++/-.+sss/` Uptime: 44m
|
||||
.:++o: /++++++++/:--:/- Packages: 1831
|
||||
o:+o+:++.`..`` `.-/oo+++++/ Shell: bash 4.4.12
|
||||
.:+o:+o/. `+sssoo+/ Resolution: 1920x955
|
||||
.++/+:+oo+o:` /sssooo. DE: GNOME
|
||||
/+++//+:`oo+o /::--:. WM: GNOME Shell
|
||||
\+/+o+++`o++o ++////. WM Theme: Adwaita
|
||||
.++.o+++oo+:` /dddhhh. GTK Theme: Azure [GTK2/3]
|
||||
.+.o+oo:. `oddhhhh+ Icon Theme: Papirus-Dark
|
||||
\+.++o+o``-````.:ohdhhhhh+ Font: Ubuntu 11
|
||||
`:o+++ `ohhhhhhhhyo++os: CPU: Intel Core i7-6700HQ @ 2x 2.592GHz
|
||||
.o:`.syhhhhhhh/.oo++o` GPU: llvmpipe (LLVM 5.0, 256 bits)
|
||||
/osyyyyyyo++ooo+++/ RAM: 1521MiB / 1993MiB
|
||||
````` +oo+++o\:
|
||||
`oo++.
|
||||
```
|
||||
|
||||
### 方法-11:使用 neofetch 命令
|
||||
|
||||
`neofetch` 是一个跨平台且易于使用的命令行(CLI)脚本,它收集你的 Linux 系统信息,并将其作为一张图片显示在终端上,也可以是你的发行版徽标,或者是你选择的任何 ascii 艺术。
|
||||
|
||||
**建议阅读:** [Neofetch – 以 ASCII 分发标志来显示 Linux 系统信息][10]
|
||||
|
||||
```
|
||||
$ neofetch
|
||||
.-/+oossssoo+/-. daygeek@ubuntu
|
||||
`:+ssssssssssssssssss+:` --------------
|
||||
-+ssssssssssssssssssyyssss+- OS: Ubuntu 17.10 x86_64
|
||||
.ossssssssssssssssssdMMMNysssso. Host: VirtualBox 1.2
|
||||
/ssssssssssshdmmNNmmyNMMMMhssssss/ Kernel: 4.13.0-37-generic
|
||||
+ssssssssshmydMMMMMMMNddddyssssssss+ Uptime: 47 mins
|
||||
/sssssssshNMMMyhhyyyyhmNMMMNhssssssss/ Packages: 1832
|
||||
.ssssssssdMMMNhsssssssssshNMMMdssssssss. Shell: bash 4.4.12
|
||||
+sssshhhyNMMNyssssssssssssyNMMMysssssss+ Resolution: 1920x955
|
||||
ossyNMMMNyMMhsssssssssssssshmmmhssssssso DE: ubuntu:GNOME
|
||||
ossyNMMMNyMMhsssssssssssssshmmmhssssssso WM: GNOME Shell
|
||||
+sssshhhyNMMNyssssssssssssyNMMMysssssss+ WM Theme: Adwaita
|
||||
.ssssssssdMMMNhsssssssssshNMMMdssssssss. Theme: Azure [GTK3]
|
||||
/sssssssshNMMMyhhyyyyhdNMMMNhssssssss/ Icons: Papirus-Dark [GTK3]
|
||||
+sssssssssdmydMMMMMMMMddddyssssssss+ Terminal: gnome-terminal
|
||||
/ssssssssssshdmNNNNmyNMMMMhssssss/ CPU: Intel i7-6700HQ (2) @ 2.591GHz
|
||||
.ossssssssssssssssssdMMMNysssso. GPU: VirtualBox Graphics Adapter
|
||||
-+sssssssssssssssssyyyssss+- Memory: 1620MiB / 1993MiB
|
||||
`:+ssssssssssssssssss+:`
|
||||
.-/+oossssoo+/-.
|
||||
```
|
||||
|
||||
### 方法-12:使用 dmesg 命令
|
||||
|
||||
`dmesg`(代表显示消息或驱动消息)是大多数类 Unix 操作系统上的命令,用于打印内核的消息缓冲区。
|
||||
|
||||
```
|
||||
$ dmesg | grep "Memory"
|
||||
[ 0.000000] Memory: 1985916K/2096696K available (12300K kernel code, 2482K rwdata, 4000K rodata, 2372K init, 2368K bss, 110780K reserved, 0K cma-reserved)
|
||||
[ 0.012044] x86/mm: Memory block size: 128MB
|
||||
```
|
||||
|
||||
### 方法-13:使用 atop 命令
|
||||
|
||||
`atop` 是一个用于 Linux 的 ASCII 全屏系统性能监视工具,它能报告所有服务器进程的活动(即使进程在间隔期间已经完成)。
|
||||
|
||||
它记录系统和进程活动以进行长期分析(默认情况下,日志文件保存 28 天),通过使用颜色等来突出显示过载的系统资源。它结合可选的内核模块 netatop 显示每个进程或线程的网络活动。
|
||||
|
||||
**建议阅读:** [Atop – 实时监控系统性能,资源,进程和检查资源利用历史][11]
|
||||
|
||||
```
|
||||
$ atop -m
|
||||
|
||||
ATOP - ubuntu 2018/03/31 19:34:08 ------------- 10s elapsed
|
||||
PRC | sys 0.47s | user 2.75s | | | #proc 219 | #trun 1 | #tslpi 802 | #tslpu 0 | #zombie 0 | clones 7 | | | #exit 4 |
|
||||
CPU | sys 7% | user 22% | irq 0% | | | idle 170% | wait 0% | | steal 0% | guest 0% | | curf 2.59GHz | curscal ?% |
|
||||
cpu | sys 3% | user 11% | irq 0% | | | idle 85% | cpu001 w 0% | | steal 0% | guest 0% | | curf 2.59GHz | curscal ?% |
|
||||
cpu | sys 4% | user 11% | irq 0% | | | idle 85% | cpu000 w 0% | | steal 0% | guest 0% | | curf 2.59GHz | curscal ?% |
|
||||
CPL | avg1 1.98 | | avg5 3.56 | avg15 3.20 | | | csw 14894 | | intr 6610 | | | numcpu 2 | |
|
||||
MEM | tot 1.9G | free 101.7M | cache 244.2M | dirty 0.2M | buff 6.9M | slab 92.9M | slrec 35.6M | shmem 97.8M | shrss 21.0M | shswp 3.2M | vmbal 0.0M | hptot 0.0M | hpuse 0.0M |
|
||||
SWP | tot 12.4G | free 11.6G | | | | | | | | | vmcom 7.9G | | vmlim 13.4G |
|
||||
PAG | scan 0 | steal 0 | | stall 0 | | | | | | | swin 3 | | swout 0 |
|
||||
DSK | sda | busy 0% | | read 114 | write 37 | KiB/r 21 | KiB/w 6 | | MBr/s 0.2 | MBw/s 0.0 | avq 6.50 | | avio 0.26 ms |
|
||||
NET | transport | tcpi 11 | tcpo 17 | udpi 4 | udpo 8 | tcpao 3 | tcppo 0 | | tcprs 3 | tcpie 0 | tcpor 0 | udpnp 0 | udpie 0 |
|
||||
NET | network | ipi 20 | | ipo 33 | ipfrw 0 | deliv 20 | | | | | icmpi 5 | | icmpo 0 |
|
||||
NET | enp0s3 0% | pcki 11 | pcko 28 | sp 1000 Mbps | si 1 Kbps | so 1 Kbps | | coll 0 | mlti 0 | erri 0 | erro 0 | drpi 0 | drpo 0 |
|
||||
NET | lo ---- | pcki 9 | pcko 9 | sp 0 Mbps | si 0 Kbps | so 0 Kbps | | coll 0 | mlti 0 | erri 0 | erro 0 | drpi 0 | drpo 0 |
|
||||
|
||||
PID TID MINFLT MAJFLT VSTEXT VSLIBS VDATA VSTACK VSIZE RSIZE PSIZE VGROW RGROW SWAPSZ RUID EUID MEM CMD 1/1
|
||||
2536 - 941 0 188K 127.3M 551.2M 144K 2.3G 281.2M 0K 0K 344K 6556K daygeek daygeek 14% Web Content
|
||||
2464 - 75 0 188K 187.7M 680.6M 132K 2.3G 226.6M 0K 0K 212K 42088K daygeek daygeek 11% firefox
|
||||
2039 - 4199 6 16K 163.6M 423.0M 132K 3.5G 220.2M 0K 0K 2936K 109.6M daygeek daygeek 11% gnome-shell
|
||||
10822 - 1 0 4K 16680K 377.0M 132K 3.4G 193.4M 0K 0K 0K 0K root root 10% java
|
||||
```
|
||||
|
||||
### 方法-14:使用 htop 命令
|
||||
|
||||
`htop` 是由 Hisham 用 ncurses 库开发的用于 Linux 的交互式进程查看器。与 `top` 命令相比,`htop` 有许多特性和选项。
|
||||
|
||||
**建议阅读:** [使用 Htop 命令监视系统资源][12]
|
||||
|
||||
```
|
||||
$ htop
|
||||
|
||||
1 [||||||||||||| 13.0%] Tasks: 152, 587 thr; 1 running
|
||||
2 [||||||||||||||||||||||||| 25.0%] Load average: 0.91 2.03 2.66
|
||||
Mem[||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||1.66G/1.95G] Uptime: 01:14:53
|
||||
Swp[|||||| 782M/12.4G]
|
||||
|
||||
PID USER PRI NI VIRT RES SHR S CPU% MEM% TIME+ Command
|
||||
2039 daygeek 20 0 3541M 214M 46728 S 36.6 10.8 22:36.77 /usr/bin/gnome-shell
|
||||
2045 daygeek 20 0 3541M 214M 46728 S 10.3 10.8 3:02.92 /usr/bin/gnome-shell
|
||||
2046 daygeek 20 0 3541M 214M 46728 S 8.3 10.8 3:04.96 /usr/bin/gnome-shell
|
||||
6080 daygeek 20 0 807M 37228 24352 S 2.1 1.8 0:11.99 /usr/lib/gnome-terminal/gnome-terminal-server
|
||||
2880 daygeek 20 0 2205M 164M 17048 S 2.1 8.3 7:16.50 /usr/lib/firefox/firefox -contentproc -childID 6 -isForBrowser -intPrefs 6:50|7:-1|19:0|34:1000|42:20|43:5|44:10|51:0|57:128|58:10000|63:0|65:400|66
|
||||
6125 daygeek 20 0 1916M 159M 92352 S 2.1 8.0 2:09.14 /usr/lib/firefox/firefox -contentproc -childID 7 -isForBrowser -intPrefs 6:50|7:-1|19:0|34:1000|42:20|43:5|44:10|51:0|57:128|58:10000|63:0|65:400|66
|
||||
2536 daygeek 20 0 2335M 243M 26792 S 2.1 12.2 6:25.77 /usr/lib/firefox/firefox -contentproc -childID 1 -isForBrowser -intPrefs 6:50|7:-1|19:0|34:1000|42:20|43:5|44:10|51:0|57:128|58:10000|63:0|65:400|66
|
||||
2653 daygeek 20 0 2237M 185M 20788 S 1.4 9.3 3:01.76 /usr/lib/firefox/firefox -contentproc -childID 4 -isForBrowser -intPrefs 6:50|7:-1|19:0|34:1000|42:20|43:5|44:10|51:0|57:128|58:10000|63:0|65:400|66
|
||||
```
|
||||
|
||||
### 方法-15:使用 corefreq 实用程序
|
||||
|
||||
CoreFreq 是为 Intel 64 位处理器设计的 CPU 监控软件,支持的架构有 Atom、Core2、Nehalem、SandyBridge 和 superior,AMD 家族 0F。
|
||||
|
||||
CoreFreq 提供了一个框架来以高精确度检索 CPU 数据。
|
||||
|
||||
**建议阅读:** [CoreFreq – 一个用于 Linux 系统的强大的 CPU 监控工具][13]
|
||||
|
||||
```
|
||||
$ ./corefreq-cli -k
|
||||
Linux:
|
||||
|- Release [4.13.0-37-generic]
|
||||
|- Version [#42-Ubuntu SMP Wed Mar 7 14:13:23 UTC 2018]
|
||||
|- Machine [x86_64]
|
||||
Memory:
|
||||
|- Total RAM 2041396 KB
|
||||
|- Shared RAM 99620 KB
|
||||
|- Free RAM 108428 KB
|
||||
|- Buffer RAM 8108 KB
|
||||
|- Total High 0 KB
|
||||
|- Free High 0 KB
|
||||
```
|
||||
|
||||
### 方法-16:使用 glances 命令
|
||||
|
||||
Glances 是用 Python 编写的跨平台基于 curses(LCTT 译注:curses 是一个 Linux/Unix 下的图形函数库)的系统监控工具。我们可以说它一应俱全,就像在最小的空间含有最大的信息。它使用 psutil 库从系统中获取信息。
|
||||
|
||||
Glances 可以监视 CPU、内存、负载、进程列表、网络接口、磁盘 I/O、Raid、传感器、文件系统(和文件夹)、Docker、监视器、警报、系统信息、正常运行时间、快速预览(CPU、内存、负载)等。
|
||||
|
||||
**建议阅读:** [Glances (一应俱全)– 一个 Linux 的高级的实时系
|
||||
统性能监控工具][14]
|
||||
|
||||
```
|
||||
$ glances
|
||||
|
||||
ubuntu (Ubuntu 17.10 64bit / Linux 4.13.0-37-generic) - IP 192.168.1.6/24 Uptime: 1:08:40
|
||||
|
||||
CPU [|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 90.6%] CPU - 90.6% nice: 0.0% ctx_sw: 4K MEM \ 78.4% active: 942M SWAP - 5.9% LOAD 2-core
|
||||
MEM [||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 78.0%] user: 55.1% irq: 0.0% inter: 1797 total: 1.95G inactive: 562M total: 12.4G 1 min: 4.35
|
||||
SWAP [|||| 5.9%] system: 32.4% iowait: 1.8% sw_int: 897 used: 1.53G buffers: 14.8M used: 749M 5 min: 4.38
|
||||
idle: 7.6% steal: 0.0% free: 431M cached: 273M free: 11.7G 15 min: 3.38
|
||||
|
||||
NETWORK Rx/s Tx/s TASKS 211 (735 thr), 4 run, 207 slp, 0 oth sorted automatically by memory_percent, flat view
|
||||
docker0 0b 232b
|
||||
enp0s3 12Kb 4Kb Systemd 7 Services loaded: 197 active: 196 failed: 1
|
||||
lo 616b 616b
|
||||
_h478e48e 0b 232b CPU% MEM% VIRT RES PID USER NI S TIME+ R/s W/s Command
|
||||
63.8 18.9 2.33G 377M 2536 daygeek 0 R 5:57.78 0 0 /usr/lib/firefox/firefox -contentproc -childID 1 -isForBrowser -intPrefs 6:50|7:-1|19:0|34:1000|42:20|43:5|44:10|51
|
||||
DefaultGateway 83ms 78.5 10.9 3.46G 217M 2039 daygeek 0 S 21:07.46 0 0 /usr/bin/gnome-shell
|
||||
8.5 10.1 2.32G 201M 2464 daygeek 0 S 8:45.69 0 0 /usr/lib/firefox/firefox -new-window
|
||||
DISK I/O R/s W/s 1.1 8.5 2.19G 170M 2653 daygeek 0 S 2:56.29 0 0 /usr/lib/firefox/firefox -contentproc -childID 4 -isForBrowser -intPrefs 6:50|7:-1|19:0|34:1000|42:20|43:5|44:10|51
|
||||
dm-0 0 0 1.7 7.2 2.15G 143M 2880 daygeek 0 S 7:10.46 0 0 /usr/lib/firefox/firefox -contentproc -childID 6 -isForBrowser -intPrefs 6:50|7:-1|19:0|34:1000|42:20|43:5|44:10|51
|
||||
sda1 9.46M 12K 0.0 4.9 1.78G 97.2M 6125 daygeek 0 S 1:36.57 0 0 /usr/lib/firefox/firefox -contentproc -childID 7 -isForBrowser -intPrefs 6:50|7:-1|19:0|34:1000|42:20|43:5|44:10|51
|
||||
```
|
||||
|
||||
### 方法-17 : 使用 Gnome 系统监视器
|
||||
|
||||
Gnome 系统监视器是一个管理正在运行的进程和监视系统资源的工具。它向你显示正在运行的程序以及耗费的处理器时间,内存和磁盘空间。
|
||||
|
||||
![][16]
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.2daygeek.com/easy-ways-to-check-size-of-physical-memory-ram-in-linux/
|
||||
|
||||
作者:[Ramya Nuvvula][a]
|
||||
译者:[MjSeven](https://github.com/MjSeven)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.2daygeek.com/author/ramya/
|
||||
[1]:https://www.2daygeek.com/free-command-to-check-memory-usage-statistics-in-linux/
|
||||
[2]:https://www.2daygeek.com/top-command-examples-to-monitor-server-performance/
|
||||
[3]:https://www.2daygeek.com/linux-vmstat-command-examples-tool-report-virtual-memory-statistics/
|
||||
[4]:https://www.2daygeek.com/nmon-system-performance-monitor-system-resources-on-linux/
|
||||
[5]:https://www.2daygeek.com/dmidecode-get-print-display-check-linux-system-hardware-information/
|
||||
[6]:https://www.2daygeek.com/hwinfo-check-display-detect-system-hardware-information-linux/
|
||||
[7]:https://www.2daygeek.com/lshw-find-check-system-hardware-information-details-linux/
|
||||
[8]:https://www.2daygeek.com/inxi-system-hardware-information-on-linux/
|
||||
[9]:https://www.2daygeek.com/screenfetch-display-linux-systems-information-ascii-distribution-logo-terminal/
|
||||
[10]:https://www.2daygeek.com/neofetch-display-linux-systems-information-ascii-distribution-logo-terminal/
|
||||
[11]:https://www.2daygeek.com/atop-system-process-performance-monitoring-tool/
|
||||
[12]:https://www.2daygeek.com/htop-command-examples-to-monitor-system-resources/
|
||||
[13]:https://www.2daygeek.com/corefreq-linux-cpu-monitoring-tool/
|
||||
[14]:https://www.2daygeek.com/install-glances-advanced-real-time-linux-system-performance-monitoring-tool-on-centos-fedora-ubuntu-debian-opensuse-arch-linux/
|
||||
[15]:data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[16]:https://www.2daygeek.com/wp-content/uploads/2018/03/check-memory-information-using-gnome-system-monitor.png
|
@ -0,0 +1,101 @@
|
||||
构建满足用户需求的云环境的五个步骤
|
||||
======
|
||||
> 在投入时间和资金开发你的云环境之前,确认什么是你的用户所需要的。
|
||||
|
||||

|
||||
|
||||
无论你如何定义,云就是你的用户展现其在组织中的价值的另一个工具。当谈论新的范例或者技术(云是两者兼有)的时候很容易被它的新特性所分心。由一系列无止境的问题引发的对话能够很快的被发展为功能愿景清单,所有下面的这些都是你可能已经考虑到的:
|
||||
|
||||
* 是公有云、私有云还是混合云?
|
||||
* 会使用虚拟机还是容器,或者是两者?
|
||||
* 会提供自助服务吗?
|
||||
* 从开发到生产是完全自动的,还是它将需要手动操作?
|
||||
* 我们能以多块的速度做到?
|
||||
* 关于某某工具?
|
||||
|
||||
这样的清单还可以列举很多。
|
||||
|
||||
当开始 IT 现代化,或者数字转型,无论你是如何称呼的,通常方法是开始回答更高管理层的一些高层次问题,这种方法的结果是可以预想到的:失败。经过大范围的调研并且花费了数月的时间(如果不是几年的话)部署了这个最炫的新技术,而这个新的云技术却从未被使用过,而且陷入了荒废,直到它最终被丢弃或者遗忘在数据中心的一角和预算之中。
|
||||
|
||||
这是因为无论你交付的是什么工具,都不是用户所想要或者需要的。更加糟糕的是,它可能是一个单一的工具,而用户真正需要的是一系列工具 —— 能够随着时间推移,更换升级为更新的、更漂亮的工具,以更好地满足其需求。
|
||||
|
||||
### 专注于重要的事情
|
||||
|
||||
问题在于关注,传统上一直是关注于工具。但工具并不是要增加到组织价值中的东西;终端用户利用它做什么才是目的。你需要将你的注意力从创建云(例如技术和工具)转移到你的人员和用户身上。
|
||||
|
||||
事实上,除了使用工具的用户(而不是工具本身)是驱动价值的因素之外,聚焦注意力在用户身上也是有其它原因的。工具是给用户使用去解决他们的问题并允许他们创造价值的,所以这就导致了如果那些工具不能满足那些用户的需求,那么那些工具将不会被使用。如果你交付给你的用户的工具并不是他们喜欢的,他们将不会使用,这就是人类的人性行为。
|
||||
|
||||
数十年来,IT 产业只为用户提供一种解决方案,因为仅有一个或两个选择,用户是没有权力去改变的。现在情况已经不同了。我们现在生活在一个技术选择的世界中。不给用户一个选择的机会的情况将不会被接受的;他们在个人的科技生活中有选择,同时希望在工作中也有选择。现在的用户都是受过教育的并且知道将会有比你所提供的更好选择。
|
||||
|
||||
因此,在物理上的最安全的地点之外,没有能够阻止他们只做他们自己想要的东西的方法,我们称之为“影子 IT”。如果你的组织有如此严格的安全策略和承诺策略而不允许影子 IT,许多员工将会感到灰心丧气并且会离职去其他能提供更好机会的公司。
|
||||
|
||||
基于以上所有的原因,你必须牢记要首先和你的最终用户设计你的昂贵又费时的云项目。
|
||||
|
||||
### 创建满足用户需求的云五个步骤的过程
|
||||
|
||||
既然我们已经知道了为什么,接下来我们来讨论一下怎么做。你如何去为终端用户创建一个云?你怎样重新将你的注意力从技术转移到使用技术的用户身上?
|
||||
|
||||
根据以往的经验,我们知道最好的方法中包含两件重要的事情:从你的用户中得到及时的反馈,在创建中和用户进行更多的互动。
|
||||
|
||||
你的云环境将继续随着你的组织不断发展。下面的五个步骤将会帮助你创建满足用户需求的云环境。
|
||||
|
||||
#### 1、识别谁将是你的用户
|
||||
|
||||
在你开始询问用户问题之前,你首先必须识别谁将是你的新的云环境的用户。他们可能包括将在云上创建开发应用的开发者;也可能是运营、维护或者或者创建该云的运维团队;还可能是保护你的组织的安全团队。在第一次迭代时,将你的用户数量缩小至人数较少的小组防止你被大量的反馈所淹没,让你识别的每个小组指派两个代表(一个主要的一个辅助的)。这将使你的第一次交付在规模和时间上都很小。
|
||||
|
||||
#### 2、和你的用户面对面的交谈来收获有价值的输入。
|
||||
|
||||
获得反馈的最佳途径是和用户直接交谈。群发的邮件会自行挑选出受访者——如果你能收到回复的话。小组讨论会很有帮助的,但是当人们有个私密的、专注的对话者时,他们会比较的坦诚。
|
||||
|
||||
和你的第一批用户安排个面对面的个人的会谈,并且向他们询问以下的问题:
|
||||
|
||||
* 为了完成你的任务,你需要什么?
|
||||
* 为了完成你的任务,你想要什么?
|
||||
* 你现在最头疼的技术痛点是什么?
|
||||
* 你现在最头疼的政策或者流程痛点是哪个?
|
||||
* 关于解决你的需求、希望或痛点,你有什么建议?
|
||||
|
||||
这些问题只是指导性的,并不一定适合每个组织。你不应该只询问这些问题,他们应该导向更深层次的讨论。确保告诉用户他们任何所说的和被问的都被视作反馈,所有的反馈都是有帮助的,无论是消极的还是积极的。这些对话将会帮助你设置你的开发优先级。
|
||||
|
||||
收集这种个性化的反馈是保持初始用户群较小的另一个原因:这将会花费你大量的时间来和每个用户交流,但是我们已经发现这是相当值得付出的投入。
|
||||
|
||||
#### 3、设计并交付你的解决方案的第一个版本
|
||||
|
||||
一旦你收到初始用户的反馈,就是时候开始去设计并交付一部分的功能了。我们不推荐尝试一次性交付整个解决方案。设计和交付的时期要短;这可以避免你花费一年的时间去构建一个你*认为*正确的解决方案,而只会让你的用户拒绝它,因为对他们来说毫无用处。创建你的云所需要的工具取决于你的组织和它的特殊需求。只需确保你的解决方案是建立在用户的反馈的基础上的,你将功能小块化的交付并且要经常的去征求用户的反馈。
|
||||
|
||||
#### 4、询问用户对第一个版本的反馈
|
||||
|
||||
太棒了,现在你已经设计并向你的用户交付了你的炫酷的新的云环境的第一个版本!你并不是花费一整年去完成它而是将它处理成小的模块。为什么将其分为小的模块如此重要呢?因为你要回到你的用户组并且向他们收集关于你的设计和交付的功能。他们喜欢什么?不喜欢什么?你正确的处理了他们所关注的吗?是技术功能上很厉害,但系统进程或者策略方面仍然欠缺吗?
|
||||
|
||||
再重申一次,你要问的问题取决于你的组织;这里的关键是继续前一个阶段的讨论。毕竟你正在为用户创建云环境,所以确保它对用户来说是有用的并且能够有效利用每个人的时间。
|
||||
|
||||
#### 5、回到第一步。
|
||||
|
||||
这是一个迭代的过程。你的首次交付应该是快速而小规模的,而且以后的迭代也应该是这样的。不要期待仅仅按照这个流程完成了一次、两次甚至是三次就能完成。一旦你持续的迭代,你将会吸引更多的用户从而能够在这个过程中得到更好的回报。你将会从用户那里得到更多的支持。你能够迭代的更迅速并且更可靠。到最后,你将会通过改变你的流程来满足用户的需求。
|
||||
|
||||
用户是这个过程中最重要的一部分,但迭代是第二重要的因为它让你能够回到用户中进行持续沟通从而得到更多有用的信息。在每个阶段,记录哪些是有效的哪些没有起到应有的效果。要自省,要对自己诚实。我们所花费的时间提供了最有价值的了吗?如果不是,在下一个阶段尝试些不同的。在每次循环中不要花费太多时间的最重要的部分是,如果某部分在这次不起作用,你能够很容易的在下一次中调整它,直到你找到能够在你组织中起作用的方法。
|
||||
|
||||
### 这仅仅是开始
|
||||
|
||||
通过许多客户约见,从他们那里收集反馈,以及在这个领域的同行的经验,我们一次次的发现在创建云的时候最重要事就是和你的用户交谈。这似乎是很明显的,但很让人惊讶的是很多组织却偏离了这个方向去花费数月或者数年的时间去创建,然后最终发现它对终端用户甚至一点用处都没有。
|
||||
|
||||
现在你已经知道为什么你需要将你的注意力集中到终端用户身上并且在中心节点和用户一起的互动创建云。剩下的是我们所喜欢的部分,你自己去做的部分。
|
||||
|
||||
这篇文章是基于一篇作者在 [Red Hat Summit 2018][3] 上发表的文章“[为终端用户设计混合云,要么失败]”。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/4/5-steps-building-your-cloud-correctly
|
||||
|
||||
作者:[Cameron Wyatt][a], [Ian Teksbury][1]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[FelixYFZ](https://github.com/FelixYFZ)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/cameronmwyatt
|
||||
[1]:https://opensource.com/users/itewk
|
||||
[2]:https://agenda.summit.redhat.com/SessionDetail.aspx?id=154225
|
||||
[3]:https://www.redhat.com/en/summit/2018
|
@ -0,0 +1,214 @@
|
||||
如何使用 Emacs 创建 LaTeX 文档
|
||||
======
|
||||
> 这篇教程将带你遍历在 Emacs 使用强大的开源排版系统 LaTex 来创建文档的全过程。
|
||||
|
||||

|
||||
|
||||
一篇由 Aaron Cocker 写的很棒的文章 “[在 LaTeX 中创建文件的介绍][1]” 中,介绍了 [LaTeX 排版系统][3] 并描述了如何使用 [TeXstudio][4] 来创建 LaTeX 文档。同时,他也列举了一些很多用户觉得创建 LaTeX 文档很方便的编辑器。
|
||||
|
||||
[Greg Pittman][5] 对这篇文章的评论吸引了我:“当你第一次开始使用 LaTeX 时,他似乎是个很差劲的排版……” 事实也确实如此。LaTeX 包含了多种排版字体和调试,如果你漏了一个特殊的字符比如说感叹号,这会让很多用户感到沮丧,尤其是新手。在本文中,我将介绍如何使用 [GNU Emacs][6] 来创建 LaTeX 文档。
|
||||
|
||||
### 创建你的第一个文档
|
||||
|
||||
启动 Emacs:
|
||||
|
||||
```
|
||||
emacs -q --no-splash helloworld.org
|
||||
```
|
||||
|
||||
参数 `-q` 确保 Emacs 不会加载其他的初始化配置。参数 `--no-splash-screen` 防止 Emacs 打开多个窗口,确保只打开一个窗口,最后的参数 `helloworld.org` 表示你要创建的文件名为 `helloworld.org` 。
|
||||
|
||||
![Emacs startup screen][8]
|
||||
|
||||
*GNU Emacs 打开文件名为 helloworld.org 的窗口时的样子。*
|
||||
|
||||
现在让我们用 Emacs 添加一些 LaTeX 的标题吧:在菜单栏找到 “Org” 选项并选择 “Export/Publish”。
|
||||
|
||||
![template_flow.png][10]
|
||||
|
||||
*导入一个默认的模板*
|
||||
|
||||
在下一个窗口中,Emacs 同时提供了导入和导出一个模板。输入 `#`(“[#] Insert template”)来导入一个模板。这将会使光标跳转到一个带有 “Options category:” 提示的 mini-buffer 中。第一次你可能不知道这个类型的名字,但是你可以使用 `Tab` 键来查看所有的补全。输入 “default” 然后按回车,之后你就能看到如下的内容被插入了:
|
||||
|
||||
```
|
||||
#+TITLE: helloworld
|
||||
#+DATE: <2018-03-12 Mon>
|
||||
#+AUTHOR:
|
||||
#+EMAIL: makerpm@nubia
|
||||
#+OPTIONS: ':nil *:t -:t ::t <:t H:3 \n:nil ^:t arch:headline
|
||||
#+OPTIONS: author:t c:nil creator:comment d:(not "LOGBOOK") date:t
|
||||
#+OPTIONS: e:t email:nil f:t inline:t num:t p:nil pri:nil stat:t
|
||||
#+OPTIONS: tags:t tasks:t tex:t timestamp:t toc:t todo:t |:t
|
||||
#+CREATOR: Emacs 25.3.1 (Org mode 8.2.10)
|
||||
#+DESCRIPTION:
|
||||
#+EXCLUDE_TAGS: noexport
|
||||
#+KEYWORDS:
|
||||
#+LANGUAGE: en
|
||||
#+SELECT_TAGS: export
|
||||
```
|
||||
|
||||
根据自己的需求修改标题、日期、作者和 email。我自己的话是下面这样的:
|
||||
|
||||
```
|
||||
#+TITLE: Hello World! My first LaTeX document
|
||||
#+DATE: \today
|
||||
#+AUTHOR: Sachin Patil
|
||||
#+EMAIL: psachin@redhat.com
|
||||
```
|
||||
|
||||
我们目前还不想创建一个目录,所以要将 `toc` 的值由 `t` 改为 `nil`,具体如下:
|
||||
|
||||
```
|
||||
#+OPTIONS: tags:t tasks:t tex:t timestamp:t toc:nil todo:t |:t
|
||||
```
|
||||
|
||||
现在让我们添加一个章节和段落吧。章节是由一个星号(`*`)开头。我们从 Aaron 的贴子(来自 [Lipsum Lorem Ipsum 生成器][11])复制一些文本过来:
|
||||
|
||||
```
|
||||
* Introduction
|
||||
|
||||
\paragraph{}
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras lorem
|
||||
nisi, tincidunt tempus sem nec, elementum feugiat ipsum. Nulla in
|
||||
diam libero. Nunc tristique ex a nibh egestas sollicitudin.
|
||||
|
||||
\paragraph{}
|
||||
Mauris efficitur vitae ex id egestas. Vestibulum ligula felis,
|
||||
pulvinar a posuere id, luctus vitae leo. Sed ac imperdiet orci, non
|
||||
elementum leo. Nullam molestie congue placerat. Phasellus tempor et
|
||||
libero maximus commodo.
|
||||
```
|
||||
|
||||
|
||||
![helloworld_file.png][13]
|
||||
|
||||
*helloworld.org 文件*
|
||||
|
||||
|
||||
将内容修改好后,我们要把它导出为 PDF 格式。再次在 “Org” 的菜单选项中选择 “Export/Publish”,但是这次,要输入 `l`(“export to LaTeX”),紧跟着输入 `o`(“as PDF file and open”)。这次操作不止会打开 PDF 文件让你浏览,同时也会将文件保存为 `helloworld.pdf`,并保存在与 `helloworld.org` 的同一个目录下。
|
||||
|
||||
![org_to_pdf.png][15]
|
||||
|
||||
*将 helloworld.org 导出为 helloworld.pdf*
|
||||
|
||||
![org_and_pdf_file.png][17]
|
||||
|
||||
*打开 helloworld.pdf 文件*
|
||||
|
||||
你也可以按下 `Alt + x` 键,然后输入 `org-latex-export-to-pdf` 来将 org 文件导出为 PDF 文件。可以使用 `Tab` 键来自动补全命令。
|
||||
|
||||
Emacs 也会创建 `helloworld.tex` 文件来让你控制具体的内容。
|
||||
|
||||
![org_tex_pdf.png][19]
|
||||
|
||||
*Emacs 在三个不同的窗口中分别打开 LaTeX,org 和 PDF 文档。*
|
||||
|
||||
你可以使用命令来将 `.tex` 文件转换为 `.pdf` 文件:
|
||||
|
||||
```
|
||||
pdflatex helloworld.tex
|
||||
```
|
||||
|
||||
你也可以将 `.org` 文件输出为 HTML 或是一个简单的文本格式的文件。我最喜欢 `.org` 文件的原因是他们可以被推送到 [GitHub][20] 上,然后同 markdown 一样被渲染。
|
||||
|
||||
### 创建一个 LaTeX 的 Beamer 简报
|
||||
|
||||
现在让我们更进一步,通过少量的修改上面的文档来创建一个 LaTeX [Beamer][21] 简报,如下所示:
|
||||
|
||||
```
|
||||
#+TITLE: LaTeX Beamer presentation
|
||||
#+DATE: \today
|
||||
#+AUTHOR: Sachin Patil
|
||||
#+EMAIL: psachin@redhat.com
|
||||
#+OPTIONS: ':nil *:t -:t ::t <:t H:3 \n:nil ^:t arch:headline
|
||||
#+OPTIONS: author:t c:nil creator:comment d:(not "LOGBOOK") date:t
|
||||
#+OPTIONS: e:t email:nil f:t inline:t num:t p:nil pri:nil stat:t
|
||||
#+OPTIONS: tags:t tasks:t tex:t timestamp:t toc:nil todo:t |:t
|
||||
#+CREATOR: Emacs 25.3.1 (Org mode 8.2.10)
|
||||
#+DESCRIPTION:
|
||||
#+EXCLUDE_TAGS: noexport
|
||||
#+KEYWORDS:
|
||||
#+LANGUAGE: en
|
||||
#+SELECT_TAGS: export
|
||||
#+LATEX_CLASS: beamer
|
||||
#+BEAMER_THEME: Frankfurt
|
||||
#+BEAMER_INNER_THEME: rounded
|
||||
|
||||
|
||||
* Introduction
|
||||
*** Programming
|
||||
- Python
|
||||
- Ruby
|
||||
|
||||
*** Paragraph one
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing
|
||||
elit. Cras lorem nisi, tincidunt tempus sem nec, elementum feugiat
|
||||
ipsum. Nulla in diam libero. Nunc tristique ex a nibh egestas
|
||||
sollicitudin.
|
||||
|
||||
*** Paragraph two
|
||||
|
||||
Mauris efficitur vitae ex id egestas. Vestibulum
|
||||
ligula felis, pulvinar a posuere id, luctus vitae leo. Sed ac
|
||||
imperdiet orci, non elementum leo. Nullam molestie congue
|
||||
placerat. Phasellus tempor et libero maximus commodo.
|
||||
|
||||
* Thanks
|
||||
*** Links
|
||||
- Link one
|
||||
- Link two
|
||||
```
|
||||
|
||||
我们给标题增加了三行:
|
||||
|
||||
```
|
||||
#+LATEX_CLASS: beamer
|
||||
#+BEAMER_THEME: Frankfurt
|
||||
#+BEAMER_INNER_THEME: rounded
|
||||
```
|
||||
|
||||
导出为 PDF,按下 `Alt + x` 键后输入 `org-beamer-export-to-pdf`。
|
||||
|
||||
![latex_beamer_presentation.png][23]
|
||||
|
||||
*用 Emacs 和 Org 模式创建的 Latex Beamer 简报*
|
||||
|
||||
希望你会爱上使用 Emacs 来创建 LaTex 和 Beamer 文档(注意:使用快捷键比用鼠标更快些)。Emacs 的 Org 模式提供了比我在这篇文章中说的更多的功能,你可以在 [orgmode.org][24] 获取更多的信息.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/4/how-create-latex-documents-emacs
|
||||
|
||||
作者:[Sachin Patil][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[oneforalone](https://github.com/oneforalone)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/psachin
|
||||
[1]:https://opensource.com/article/17/6/introduction-latex
|
||||
[2]:https://opensource.com/users/aaroncocker
|
||||
[3]:https://www.latex-project.org
|
||||
[4]:http://www.texstudio.org/
|
||||
[5]:https://opensource.com/users/greg-p
|
||||
[6]:https://www.gnu.org/software/emacs/
|
||||
[7]:/file/392261
|
||||
[8]:https://opensource.com/sites/default/files/styles/panopoly_image_original/public/images/life-uploads/emacs_startup.png?itok=UnT4PgK5 (Emacs startup screen)
|
||||
[9]:/file/392266
|
||||
[10]:https://opensource.com/sites/default/files/styles/panopoly_image_original/public/images/life-uploads/insert_template_flow.png?itok=V_c2KipO (template_flow.png)
|
||||
[11]:https://www.lipsum.com/feed/html
|
||||
[12]:/file/392271
|
||||
[13]:https://opensource.com/sites/default/files/styles/panopoly_image_original/public/images/life-uploads/helloworld_file.png?itok=o8IX0TsJ (helloworld_file.png)
|
||||
[14]:/file/392276
|
||||
[15]:https://opensource.com/sites/default/files/styles/panopoly_image_original/public/images/life-uploads/org_to_pdf.png?itok=fNnC1Y-L (org_to_pdf.png)
|
||||
[16]:/file/392281
|
||||
[17]:https://opensource.com/sites/default/files/styles/panopoly_image_original/public/images/life-uploads/org_and_pdf_file.png?itok=HEhtw-cu (org_and_pdf_file.png)
|
||||
[18]:/file/392286
|
||||
[19]:https://opensource.com/sites/default/files/styles/panopoly_image_original/public/images/life-uploads/org_tex_pdf.png?itok=poZZV_tj (org_tex_pdf.png)
|
||||
[20]:https://github.com
|
||||
[21]:https://www.sharelatex.com/learn/Beamer
|
||||
[22]:/file/392291
|
||||
[23]:https://opensource.com/sites/default/files/styles/panopoly_image_original/public/images/life-uploads/latex_beamer_presentation.png?itok=rsPSeIuM (latex_beamer_presentation.png)
|
||||
[24]:https://orgmode.org/worg/org-tutorials/org-latex-export.html
|
@ -0,0 +1,139 @@
|
||||
如何在终端中浏览 Stack Overflow
|
||||
======
|
||||
|
||||

|
||||
|
||||
前段时间,我们写了一篇关于 [SoCLI][1] 的文章,它是一个从命令行搜索和浏览 Stack Overflow 网站的 python 脚本。今天,我们将讨论一个名为 “how2” 的类似工具。它是一个命令行程序,可以从终端浏览 Stack Overflow。你可以如你在 [Google 搜索][2]中那样直接用英语查询,然后它会使用 Google 和 Stackoverflow API 来搜索给定的查询。它是使用 NodeJS 编写的自由开源程序。
|
||||
|
||||
### 使用 how2 从终端浏览 Stack Overflow
|
||||
|
||||
由于 `how2` 是一个 NodeJS 包,我们可以使用 Npm 包管理器安装它。如果你尚未安装 Npm 和 NodeJS,请参考以下指南。
|
||||
|
||||
在安装 Npm 和 NodeJS 后,运行以下命令安装 how2。
|
||||
|
||||
```
|
||||
$ npm install -g how2
|
||||
```
|
||||
|
||||
现在让我们看下如何使用这个程序浏览 Stack Overflow。使用 `how2` 搜索 Stack Overflow 站点的典型用法是:
|
||||
|
||||
```
|
||||
$ how2 <search-query>
|
||||
```
|
||||
|
||||
例如,我将搜索如何创建 tgz 存档。
|
||||
|
||||
```
|
||||
$ how2 create archive tgz
|
||||
```
|
||||
|
||||
哎呀!我收到以下错误。
|
||||
|
||||
```
|
||||
/home/sk/.nvm/versions/node/v9.11.1/lib/node_modules/how2/node_modules/devnull/transports/transport.js:59
|
||||
Transport.prototype.__proto__ = EventEmitter.prototype;
|
||||
^
|
||||
|
||||
TypeError: Cannot read property 'prototype' of undefined
|
||||
at Object.<anonymous> (/home/sk/.nvm/versions/node/v9.11.1/lib/node_modules/how2/node_modules/devnull/transports/transport.js:59:46)
|
||||
at Module._compile (internal/modules/cjs/loader.js:654:30)
|
||||
at Object.Module._extensions..js (internal/modules/cjs/loader.js:665:10)
|
||||
at Module.load (internal/modules/cjs/loader.js:566:32)
|
||||
at tryModuleLoad (internal/modules/cjs/loader.js:506:12)
|
||||
at Function.Module._load (internal/modules/cjs/loader.js:498:3)
|
||||
at Module.require (internal/modules/cjs/loader.js:598:17)
|
||||
at require (internal/modules/cjs/helpers.js:11:18)
|
||||
at Object.<anonymous> (/home/sk/.nvm/versions/node/v9.11.1/lib/node_modules/how2/node_modules/devnull/transports/stream.js:8:17)
|
||||
at Module._compile (internal/modules/cjs/loader.js:654:30)
|
||||
|
||||
```
|
||||
|
||||
我可能遇到了一个 bug。我希望它在未来版本中得到修复。但是,我在[这里][3]找到了一个临时方法。
|
||||
|
||||
|
||||
要临时修复此错误,你需要使用以下命令编辑 `transport.js`:
|
||||
|
||||
```
|
||||
$ vi /home/sk/.nvm/versions/node/v9.11.1/lib/node_modules/how2/node_modules/devnull/transports/transport.js
|
||||
```
|
||||
|
||||
此文件的实际路径将显示在错误输出中。用你自己的文件路径替换上述文件路径。然后找到以下行:
|
||||
|
||||
```
|
||||
var EventEmitter = process.EventEmitter;
|
||||
```
|
||||
|
||||
并用以下行替换它:
|
||||
|
||||
```
|
||||
var EventEmitter = require('events');
|
||||
```
|
||||
|
||||
按 `ESC` 并输入 `:wq` 以保存并退出文件。
|
||||
|
||||
现在再次搜索查询。
|
||||
|
||||
```
|
||||
$ how2 create archive tgz
|
||||
```
|
||||
|
||||
这是我的 Ubuntu 系统的示例输出。
|
||||
|
||||
![][5]
|
||||
|
||||
如果你要查找的答案未显示在上面的输出中,请按**空格键**键开始交互式搜索,你可以通过它查看 Stack Overflow 站点中的所有建议问题和答案。
|
||||
|
||||
![][6]
|
||||
|
||||
使用向上/向下箭头在结果之间移动。得到正确的答案/问题后,点击空格键或回车键在终端中打开它。
|
||||
|
||||
![][7]
|
||||
|
||||
要返回并退出,请按 `ESC`。
|
||||
|
||||
**搜索特定语言的答案**
|
||||
|
||||
如果你没有指定语言,它**默认为 Bash** unix 命令行,并立即为你提供最可能的答案。你还可以将结果缩小到特定语言,例如 perl、python、c、Java 等。
|
||||
|
||||
例如,使用 `-l` 标志仅搜索与 “Python” 语言相关的查询,如下所示。
|
||||
|
||||
```
|
||||
$ how2 -l python linked list
|
||||
```
|
||||
|
||||
![][8]
|
||||
|
||||
要获得快速帮助,请输入:
|
||||
|
||||
```
|
||||
$ how2 -h
|
||||
```
|
||||
|
||||
### 总结
|
||||
|
||||
`how2` 是一个基本的命令行程序,它可以快速搜索 Stack Overflow 中的问题和答案,而无需离开终端,并且它可以很好地完成这项工作。但是,它只是 Stack overflow 的 CLI 浏览器。对于一些高级功能,例如搜索投票最多的问题,使用多个标签搜索查询,彩色界面,提交新问题和查看问题统计信息等,**SoCLI** 做得更好。
|
||||
|
||||
就是这些了。希望这篇文章有用。我将很快写一篇新的指南。在此之前,请继续关注!
|
||||
|
||||
干杯!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/how-to-browse-stack-overflow-from-terminal/
|
||||
|
||||
作者:[SK][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[geekpi](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.ostechnix.com/author/sk/
|
||||
[1]:https://www.ostechnix.com/search-browse-stack-overflow-website-commandline/
|
||||
[2]:https://www.ostechnix.com/google-search-navigator-enhance-keyboard-navigation-in-google-search/
|
||||
[3]:https://github.com/santinic/how2/issues/79
|
||||
[4]:data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[5]:http://www.ostechnix.com/wp-content/uploads/2018/04/stack-overflow-1.png
|
||||
[6]:http://www.ostechnix.com/wp-content/uploads/2018/04/stack-overflow-2.png
|
||||
[7]:http://www.ostechnix.com/wp-content/uploads/2018/04/stack-overflow-3.png
|
||||
[8]:http://www.ostechnix.com/wp-content/uploads/2018/04/stack-overflow-4.png
|
@ -1,43 +1,41 @@
|
||||
关于安全,开发人员需要知道的
|
||||
======
|
||||
(to 校正:有些长句子理解得不好,望见谅)
|
||||
> 开发人员不需要成为安全专家, 但他们确实需要摆脱将安全视为一些不幸障碍的心态。
|
||||
|
||||

|
||||
|
||||
DevOps 并不意味着每个人都需要成为开发和运维方面的专家。尤其在大型组织中,其中角色往往更加专业化。相反,DevOps 思想在某种程度上更多地是关注问题的分离。在某种程度上,运维团队可以为开发人员(无论是在本地云还是在公共云中)部署平台,并且不受影响,这对两个团队来说都是好消息。开发人员可以获得高效的开发环境和自助服务,运维人员可以专注于保持基础管道运行和维护平台。
|
||||
|
||||
这是一种约定。开发者期望从运维人员那里得到一个稳定和实用的平台,运维人员希望开发者能够自己处理与开发应用相关的大部分任务。
|
||||
|
||||
也就是说,DevOps 还涉及更好的沟通、合作和透明度。如果它不仅仅是一种介于开发和运维之间的新型壁垒,它的效果会更好。运维人员需要对开发者想要和需要的工具类型以及他们通过监视和日志记录来编写更好应用程序所需的可见性保持敏感。相反,开发人员需要了解如何才能使底层基础设施更有效地使用,以及什么能够在夜间(字面上)保持操作。(to 校正:这里意思是不是在无人时候操作)
|
||||
也就是说,DevOps 还涉及更好的沟通、合作和透明度。如果它不仅仅是一种介于开发和运维之间的新型壁垒,它的效果会更好。运维人员需要对开发者想要和需要的工具类型以及他们通过监视和日志记录来编写更好应用程序所需的可见性保持敏感。另一方面,开发人员需要了解如何才能更有效地使用底层基础设施,以及什么能够使运维在夜间(字面上)保持运行。
|
||||
|
||||
同样的原则也适用于更广泛的 DevSecOps,这个术语明确地提醒我们,安全需要嵌入到整个 DevOps 管道中,从获取内容到编写应用程序、构建应用程序、测试应用程序以及在生产环境中运行它们。开发人员(和运维人员)不需要突然成为安全专家,除了他们的其它角色。但是,他们通常可以从对安全最佳实践(这可能不同于他们已经习惯的)的更高认识中获益,并从将安全视为一些不幸障碍的心态中转变出来。
|
||||
同样的原则也适用于更广泛的 DevSecOps,这个术语明确地提醒我们,安全需要嵌入到整个 DevOps 管道中,从获取内容到编写应用程序、构建应用程序、测试应用程序以及在生产环境中运行它们。开发人员(和运维人员)除了他们已有的角色不需要突然成为安全专家。但是,他们通常可以从对安全最佳实践(这可能不同于他们已经习惯的)的更高认识中获益,并从将安全视为一些不幸障碍的心态中转变出来。
|
||||
|
||||
以下是一些观察结果。
|
||||
|
||||
开放式 Web 应用程序安全项目(Open Web Application Security Project)([OWASP][1])[Top 10 列表]提供了一个窗口,可以了解 Web 应用程序中的主要漏洞。列表中的许多条目对 Web 程序员来说都很熟悉。跨站脚本(XSS)和注入漏洞是最常见的。但令人震惊的是,2007 年列表中的许多漏洞仍在 2017 年的列表中([PDF][3])。无论是培训还是工具,都有问题,许多相同的编码漏洞在不断出现。(to 校正:这句话不清楚)
|
||||
<ruby>开放式 Web 应用程序安全项目<rt>Open Web Application Security Project</rt></ruby>([OWASP][1])[Top 10 列表]提供了一个窗口,可以了解 Web 应用程序中的主要漏洞。列表中的许多条目对 Web 程序员来说都很熟悉。跨站脚本(XSS)和注入漏洞是最常见的。但令人震惊的是,2007 年列表中的许多漏洞仍在 2017 年的列表中([PDF][3])。无论是培训还是工具,都有问题,许多同样的编码漏洞一再出现。
|
||||
|
||||
新平台技术加剧了这种情况。例如,虽然容器不一定要求应用程序以不同的方式编写,但是它们与新模式(例如[微服务][4])相吻合,并且可以放大某些对于安全实践的影响。例如,我的同事 [Dan Walsh][5]([@rhatdan][6])写道:“计算机领域最大的误解是需要 root 权限来运行应用程序,问题是并不是所有开发者都认为他们需要 root,而是他们将这种假设构建到他们建设的服务中,即服务无法在非 root 情况下运行,而这降低了安全性。”
|
||||
新的平台技术加剧了这种情况。例如,虽然容器不一定要求应用程序以不同的方式编写,但是它们与新模式(例如[微服务][4])相吻合,并且可以放大某些对于安全实践的影响。例如,我的同事 [Dan Walsh][5]([@rhatdan][6])写道:“计算机领域最大的误解是需要 root 权限来运行应用程序,问题是并不是所有开发者都认为他们需要 root,而是他们将这种假设构建到他们建设的服务中,即服务无法在非 root 情况下运行,而这降低了安全性。”
|
||||
|
||||
默认使用 root 访问是一个好的实践吗?并不是。但它可能(也许)是一个可以防御的应用程序和系统,否则就会被其它方法完全隔离。但是,由于所有东西都连接在一起,没有真正的边界,多用户工作负载,拥有许多不同级别访问权限的用户,更不用说更加危险的环境了,那么快捷方式的回旋余地就更小了。
|
||||
|
||||
[自动化][7]应该是 DevOps 不可分割的一部分。自动化需要覆盖整个过程中,包括安全和合规性测试。代码是从哪里来的?是否涉及第三方技术、产品或容器映像?是否有已知的安全勘误表?是否有已知的常见代码缺陷?秘密和个人身份信息是否被隔离?如何进行身份认证?谁被授权部署服务和应用程序?
|
||||
[自动化][7]应该是 DevOps 不可分割的一部分。自动化需要覆盖整个过程中,包括安全和合规性测试。代码是从哪里来的?是否涉及第三方技术、产品或容器镜像?是否有已知的安全勘误表?是否有已知的常见代码缺陷?机密信息和个人身份信息是否被隔离?如何进行身份认证?谁被授权部署服务和应用程序?
|
||||
|
||||
你不是在写你自己的加密代码吧?
|
||||
你不是自己在写你的加密代码吧?
|
||||
|
||||
尽可能地自动化渗透测试。我提到过自动化没?它是使安全性持续的一个重要部分,而不是偶尔做一次的检查清单。
|
||||
|
||||
这听起来很难吗?可能有点。至少它是不同的。但是,作一名 [DevOpsDays OpenSpaces][8] 伦敦论坛的一名参与者对我说:“这只是技术测试。它既不神奇也不神秘。”他接着说,将安全作为一种更广泛地了解整个软件生命周期(这是一种不错的技能)的方法来参与进来并不难。他还建议参加事件响应练习或[捕获国旗练习][9]。你会发现它们很有趣。
|
||||
|
||||
本文基于作者将于 5 月 8 日至 10 日在旧金山举行的 [Red Hat Summit 2018][11] 上发表的演讲。_[5 月 7 日前注册][11]以节省 500 美元的注册。使用折扣代码**OPEN18**在支付页面应用折扣_
|
||||
|
||||
这听起来很难吗?可能有点。至少它是不同的。但是,一名 [DevOpsDays OpenSpaces][8] 伦敦论坛的参与者对我说:“这只是技术测试。它既不神奇也不神秘。”他接着说,将安全作为一种更广泛地了解整个软件生命周期的方法(这是一种不错的技能)来参与进来并不难。他还建议参加事件响应练习或[夺旗练习][9]。你会发现它们很有趣。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/4/what-developers-need-know-about-security
|
||||
|
||||
作者:[Gordon Haff][a]
|
||||
译者:[MjSeven](https://github.com/MjSeven)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[MjSeven](https://github.com/MjSeven)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
77
published/201811/20180626 8 great pytest plugins.md
Normal file
77
published/201811/20180626 8 great pytest plugins.md
Normal file
@ -0,0 +1,77 @@
|
||||
8 个很棒的 pytest 插件
|
||||
======
|
||||
|
||||
> Python 测试工具最好的一方面是其强大的生态系统。这里列出了八个最好的插件。
|
||||
|
||||

|
||||
|
||||
我们是 [pytest][1] 的忠实粉丝,并将其作为工作和开源项目的默认 Python 测试工具。在本月的 Python 专栏中,我们分享了为什么我们喜欢 `pytest` 以及一些让 `pytest` 测试工作更有趣的插件。
|
||||
|
||||
### 什么是 pytest?
|
||||
|
||||
正如该工具的网站所说,“pytest 框架可以轻松地编写小型测试,也能进行扩展以支持应用和库的复杂功能测试。”
|
||||
|
||||
`pytest` 允许你在任何名为 `test_*.py` 的文件中定义测试,并将其定义为以 `test_*` 开头的函数。然后,pytest 将在整个项目中查找所有测试,并在控制台中运行 `pytest` 时自动运行这些测试。pytest 接受[标志和参数][2],它们可以在测试运行器停止时更改,这些包含如何输出结果,运行哪些测试以及输出中包含哪些信息。它还包括一个 `set_trace()` 函数,它可以进入到你的测试中。它会暂停您的测试, 并允许你与变量进行交互,不然你只能在终端中“四处翻弄”来调试你的项目。
|
||||
|
||||
`pytest` 最好的一方面是其强大的插件生态系统。因为 `pytest` 是一个非常流行的测试库,所以多年来创建了许多插件来扩展、定制和增强其功能。这八个插件是我们的最爱。
|
||||
|
||||
### 8 个很棒的插件
|
||||
|
||||
#### 1、pytest-sugar
|
||||
|
||||
[pytest-sugar][3] 改变了 `pytest` 的默认外观,添加了一个进度条,并立即显示失败的测试。它不需要配置,只需 `pip install pytest-sugar`,用 `pytest` 运行测试,来享受更漂亮、更有用的输出。
|
||||
|
||||
#### 2、pytest-cov
|
||||
|
||||
[pytest-cov][4] 在 `pytest` 中增加了覆盖率支持,来显示哪些代码行已经测试过,哪些还没有。它还将包括项目的测试覆盖率。
|
||||
|
||||
#### 3、pytest-picked
|
||||
|
||||
[pytest-picked][5] 对你已经修改但尚未提交 `git` 的代码运行测试。安装库并运行 `pytest --picked` 来仅测试自上次提交后已更改的文件。
|
||||
|
||||
#### 4、pytest-instafail
|
||||
|
||||
[pytest-instafail][6] 修改 `pytest` 的默认行为来立即显示失败和错误,而不是等到 `pytest` 完成所有测试。
|
||||
|
||||
#### 5、pytest-tldr
|
||||
|
||||
一个全新的 `pytest` 插件,可以将输出限制为你需要的东西。`pytest-tldr`(`tldr` 代表 “too long, didn't read” —— 太长,不想读),就像 pytest-sugar 一样,除基本安装外不需要配置。不像 pytest 的默认输出那么详细,[pytest-tldr][7] 将默认输出限制为失败测试的回溯信息,并忽略了一些令人讨厌的颜色编码。添加 `-v` 标志会为喜欢它的人返回更详细的输出。
|
||||
|
||||
#### 6、pytest-xdist
|
||||
|
||||
[pytest-xdist][8] 允许你通过 `-n` 标志并行运行多个测试:例如,`pytest -n 2` 将在两个 CPU 上运行你的测试。这可以显著加快你的测试速度。它还包括 `--looponfail` 标志,它将自动重新运行你的失败测试。
|
||||
|
||||
#### 7、pytest-django
|
||||
|
||||
[pytest-django][9] 为 Django 应用和项目添加了 `pytest` 支持。具体来说,`pytest-django` 引入了使用 pytest fixture 测试 Django 项目的能力,而省略了导入 `unittest` 和复制/粘贴其他样板测试代码的需要,并且比标准的 Django 测试套件运行得更快。
|
||||
|
||||
#### 8、django-test-plus
|
||||
|
||||
[django-test-plus][10] 并不是专门为 `pytest` 开发,但它现在支持 `pytest`。它包含自己的 `TestCase` 类,你的测试可以继承该类,并使你能够使用较少的按键来输出频繁的测试案例,例如检查特定的 HTTP 错误代码。
|
||||
|
||||
我们上面提到的库绝不是你扩展 `pytest` 的唯一选择。有用的 pytest 插件的前景是广阔的。查看 [pytest 插件兼容性][11]页面来自行探索。你最喜欢哪些插件?
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/6/pytest-plugins
|
||||
|
||||
作者:[Jeff Triplett][a1], [Lacery Williams Henschel][a2]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a1]:https://opensource.com/users/jefftriplett
|
||||
[a2]:https://opensource.com/users/laceynwilliams
|
||||
[1]:https://docs.pytest.org/en/latest/
|
||||
[2]:https://docs.pytest.org/en/latest/usage.html
|
||||
[3]:https://github.com/Frozenball/pytest-sugar
|
||||
[4]:https://github.com/pytest-dev/pytest-cov
|
||||
[5]:https://github.com/anapaulagomes/pytest-picked
|
||||
[6]:https://github.com/pytest-dev/pytest-instafail
|
||||
[7]:https://github.com/freakboy3742/pytest-tldr
|
||||
[8]:https://github.com/pytest-dev/pytest-xdist
|
||||
[9]:https://pytest-django.readthedocs.io/en/latest/
|
||||
[10]:https://django-test-plus.readthedocs.io/en/latest/
|
||||
[11]:https://plugincompat.herokuapp.com/
|
@ -0,0 +1,103 @@
|
||||
如何在 Anbox 上安装 Google Play 商店及启用 ARM 支持
|
||||
======
|
||||
|
||||

|
||||
|
||||
[Anbox][1] (Anroid in a Box)是一个自由开源工具,它允许你在 Linux 上运行 Android 应用程序。它的工作原理是在 LXC 容器中运行 Android 运行时环境,重新创建 Android 的目录结构作为可挂载的 loop 镜像,同时使用本机 Linux 内核来执行应用。
|
||||
|
||||
据其网站所述,它的主要特性是安全性、性能、集成和趋同(不同外形尺寸缩放)。
|
||||
|
||||
使用 Anbox,每个 Android 应用或游戏就像系统应用一样都在一个单独的窗口中启动,它们的行为或多或少类似于常规窗口,显示在启动器中,可以平铺等等。
|
||||
|
||||
默认情况下,Anbox 没有 Google Play 商店或 ARM 应用支持。要安装应用,你必须下载每个应用的 APK 并使用 `adb` 手动安装。此外,默认情况下不能使用 Anbox 安装 ARM 应用或游戏 —— 尝试安装 ARM 应用会显示以下错误:
|
||||
|
||||
```
|
||||
Failed to install PACKAGE.NAME.apk: Failure [INSTALL_FAILED_NO_MATCHING_ABIS: Failed to extract native libraries, res=-113]
|
||||
|
||||
```
|
||||
|
||||
你可以在 Anbox 中手动设置 Google Play 商店和 ARM 应用支持(通过 libhoudini),但这是一个非常复杂的过程。为了更容易地在 Anbox 上安装 Google Play 商店和 Google Play 服务,并让它支持 ARM 应用程序和游戏(使用 libhoudini),[geeks-r-us.de][2](文章是德语)上的人创建了一个自动执行这些任务的脚本。
|
||||
|
||||
在使用之前,我想明确指出,即使在集成 libhoudini 来支持 ARM 后,也并非所有 Android 应用和游戏都能在 Anbox 中运行。某些 Android 应用和游戏可能根本不会出现在 Google Play 商店中,而一些应用和游戏可能可以安装但无法使用。此外,某些应用可能无法使用某些功能。
|
||||
|
||||
### 安装 Google Play 商店并在 Anbox 上启用 ARM 应用/游戏支持
|
||||
|
||||
如果你的 Linux 桌面上尚未安装 Anbox,这些说明显然不起作用。如果你还没有,请按照[此处][7]的安装说明安装 Anbox。此外,请确保在安装 Anbox 之后,使用此脚本之前至少运行一次 `anbox.appmgr`,以避免遇到问题。另外,确保在执行下面的脚本时 Anbox 没有运行(我怀疑这是导致评论中提到的这个[问题][8]的原因)。
|
||||
|
||||
1、 安装所需的依赖项(wget、lzip、unzip 和 squashfs-tools)。
|
||||
|
||||
在 Debian、Ubuntu 或 Linux Mint 中,使用此命令安装所需的依赖项:
|
||||
|
||||
```
|
||||
sudo apt install wget lzip unzip squashfs-tools
|
||||
```
|
||||
|
||||
2、 下载并运行脚本,在 Anbox 上自动下载并安装 Google Play 商店(和 Google Play 服务)和 libhoudini(用于 ARM 应用/游戏支持)。
|
||||
|
||||
**警告:永远不要在不知道它做什么的情况下运行不是你写的脚本。在运行此脚本之前,请查看其[代码][4]。**
|
||||
|
||||
要下载脚本,使其可执行并在 Linux 桌面上运行,请在终端中使用以下命令:
|
||||
|
||||
```
|
||||
wget https://raw.githubusercontent.com/geeks-r-us/anbox-playstore-installer/master/install-playstore.sh
|
||||
chmod +x install-playstore.sh
|
||||
sudo ./install-playstore.sh
|
||||
```
|
||||
|
||||
3、要让 Google Play 商店在 Anbox 中运行,你需要启用 Google Play 商店和 Google Play 服务的所有权限
|
||||
|
||||
为此,请运行Anbox:
|
||||
|
||||
```
|
||||
anbox.appmgr
|
||||
```
|
||||
|
||||
然后进入“设置 > 应用 > Google Play 服务 > 权限”并启用所有可用权限。对 Google Play 商店也一样!
|
||||
|
||||

|
||||
|
||||
你现在应该可以使用 Google 帐户登录 Google Play 商店了。
|
||||
|
||||
如果未启用 Google Play 商店和 Google Play 服务的所有权限,你可能会在尝试登录 Google 帐户时可能会遇到问题,并显示以下错误消息:“Couldn't sign in. There was a problem communicating with Google servers. Try again later“,如你在下面的截图中看到的那样:
|
||||
|
||||

|
||||
|
||||
登录后,你可以停用部分 Google Play 商店/Google Play 服务权限。
|
||||
|
||||
**如果你在 Anbox 上登录 Google 帐户时遇到一些连接问题**,请确保 `anbox-bride.sh` 正在运行:
|
||||
|
||||
启动它:
|
||||
|
||||
```
|
||||
sudo /snap/anbox/current/bin/anbox-bridge.sh start
|
||||
```
|
||||
重启它:
|
||||
|
||||
```
|
||||
sudo /snap/anbox/current/bin/anbox-bridge.sh restart
|
||||
```
|
||||
|
||||
根据[此用户][9]的说法,如果 Anbox 仍然存在连接问题,你可能还需要安装 dnsmasq 包。但是在我的 Ubuntu 18.04 桌面上不需要这样做。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linuxuprising.com/2018/07/anbox-how-to-install-google-play-store.html
|
||||
|
||||
作者:[Logix][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://plus.google.com/118280394805678839070
|
||||
[1]:https://anbox.io/
|
||||
[2]:https://geeks-r-us.de/2017/08/26/android-apps-auf-dem-linux-desktop/
|
||||
[3]:https://github.com/geeks-r-us/anbox-playstore-installer/
|
||||
[4]:https://github.com/geeks-r-us/anbox-playstore-installer/blob/master/install-playstore.sh
|
||||
[5]:https://docs.anbox.io/userguide/install.html
|
||||
[6]:https://github.com/anbox/anbox/issues/118#issuecomment-295270113
|
||||
[7]:https://github.com/anbox/anbox/blob/master/docs/install.md
|
||||
[8]:https://www.linuxuprising.com/2018/07/anbox-how-to-install-google-play-store.html?showComment=1533506821283#c4415289781078860898
|
||||
[9]:https://github.com/anbox/anbox/issues/118#issuecomment-295270113
|
@ -0,0 +1,67 @@
|
||||
一个用于家庭项目的单用户、轻量级操作系统
|
||||
======
|
||||
> 业余爱好者应该了解一下 RISC OS 的五个原因。
|
||||
|
||||

|
||||
|
||||
究竟什么是 RISC OS?嗯,它不是一种新的 Linux。它也不是有些人认为的 Windows。事实上,它发布于 1987 年,它比它们任何一个都要古老。但你看到它时不一定会意识到这一点。
|
||||
|
||||
其点击式图形用户界面在底部为活动的程序提供一个固定面板和一个图标栏。因此,它看起来像 Windows 95,并且比它早了 8 年。
|
||||
|
||||
这个操作系统最初是为 [Acorn Archimedes][1] 编写的。这台机器中的 Acorn RISC Machines CPU 是全新的硬件,因此需要在其上运行全新的软件。这是最早的 ARM 芯片上的系统,早于任何人想到的 Android 或 [Armbian][2] 之前。
|
||||
|
||||
虽然 Acorn 桌面最终消失了,但 ARM 芯片继续征服世界。在这里,RISC OS 一直有一个优点 —— 通常在嵌入式设备中,你从来没有真正地意识到它。RISC OS 过去长期以来一直是一个完全专有的操作系统。但近年来,该抄系统的所有者已经开始将源代码发布到一个名为 [RISC OS Open][3] 的项目中。
|
||||
|
||||
### 1、你可以将它安装在树莓派上
|
||||
|
||||
树莓派的官方操作系统 [Raspbian][4] 实际上非常棒(如果你对摆弄不同技术上新奇的东西不感兴趣,那么你可能最初也不会选择树莓派)。由于 RISC OS 是专门为 ARM 编写的,因此它可以在各种小型计算机上运行,包括树莓派的各个型号。
|
||||
|
||||
### 2、它超轻量级
|
||||
|
||||
我的树莓派上安装的 RISC 系统占用了几百兆 —— 这是在我加载了数十个程序和游戏之后。它们大多数时候不超过 1 兆。
|
||||
|
||||
如果你真的节俭,RISC OS Pico 可用在 16MB SD 卡上。如果你要在嵌入式系统或物联网项目中鼓捣某些东西,这是很完美的。当然,16MB 实际上比压缩到 512KB 的老 Archimedes 的 ROM 要多得多。但我想 30 年间内存技术的发展,我们可以稍微放宽一下了。
|
||||
|
||||
### 3、它非常适合复古游戏
|
||||
|
||||
当 Archimedes 处于鼎盛时期时,ARM CPU 的速度比 Apple Macintosh 和 Commodore Amiga 中的 Motorola 68000 要快几倍,它也完全吸了新的 386 技术。这使得它成为对游戏开发者有吸引力的一个平台,他们希望用这个星球上最强大的桌面计算机来支撑他们的东西。
|
||||
|
||||
那些游戏的许多拥有者都非常慷慨,允许业余爱好者免费下载他们的老作品。虽然 RISC OS 和硬件已经发展了,但只需要进行少量的调整就可以让它们运行起来。
|
||||
|
||||
如果你有兴趣探索这个,[这里有一个指南][5]让这些游戏在你的树莓派上运行。
|
||||
|
||||
### 4、它有 BBC BASIC
|
||||
|
||||
就像过去一样,按下 `F12` 进入命令行,输入 `*BASIC`,就可以看到一个完整的 BBC BASIC 解释器。
|
||||
|
||||
对于那些在 80 年代没有接触过它的人,请让我解释一下:BBC BASIC 是当时我们很多人的第一个编程语言,因为它专门教孩子如何编码。当时有大量的书籍和杂志文章教我们编写自己的简单但高度可玩的游戏。
|
||||
|
||||
几十年后,对于一个想要在学校假期做点什么的有技术头脑的孩子而言,在 BBC BASIC 上编写自己的游戏仍然是一个很棒的项目。但很少有孩子在家里有 BBC micro。那么他们应该怎么做呢?
|
||||
|
||||
当然,你可以在每台家用电脑上运行解释器,但是当别人需要使用它时就不能用了。那么为什么不使用装有 RISC OS 的树莓派呢?
|
||||
|
||||
### 5、它是一个简单的单用户操作系统
|
||||
|
||||
RISC OS 不像 Linux 一样有自己的用户和超级用户访问权限。它有一个用户并可以完全访问整个机器。因此,它可能不是跨企业部署的最佳日常驱动,甚至不适合给老人家做银行业务。但是,如果你正在寻找可以用来修改和鼓捣的东西,那绝对是太棒了。你和机器之间没有那么多障碍,所以你可以直接闯进去。
|
||||
|
||||
### 扩展阅读
|
||||
|
||||
如果你想了解有关此操作系统的更多信息,请查看 [RISC OS Open][3],或者将镜像烧到闪存到卡上并开始使用它。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/7/gentle-intro-risc-os
|
||||
|
||||
作者:[James Mawson][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/dxmjames
|
||||
[1]:https://en.wikipedia.org/wiki/Acorn_Archimedes
|
||||
[2]:https://www.armbian.com/
|
||||
[3]:https://www.riscosopen.org/content/
|
||||
[4]:https://www.raspbian.org/
|
||||
[5]:https://www.riscosopen.org/wiki/documentation/show/Introduction%20to%20RISC%20OS
|
@ -1,67 +1,64 @@
|
||||
**全文共三处“译注”,麻烦校对大大**
|
||||
|
||||
2018 年 5 款最好的 Linux 游戏
|
||||
======
|
||||
|
||||

|
||||
|
||||
Linux 可能不会很快成为游戏玩家选择的平台——Valve Steam Machines 的失败似乎是对这一点的深刻提醒——但这并不意味着该平台没有稳定增长,并且拥有相当多的优秀游戏。
|
||||
Linux 可能不会很快成为游戏玩家选择的平台 —— Valve Steam Machines 的失败似乎是对这一点的深刻提醒 —— 但这并不意味着该平台没有稳定增长,并且拥有相当多的优秀游戏。
|
||||
|
||||
从独立打击到辉煌的 RPG(角色扮演),2018 年已经可以称得上是 Linux 游戏的丰收年,在这里,我们将列出迄今为止最喜欢的五款。
|
||||
从独立单机到辉煌的 RPG(角色扮演),2018 年已经可以称得上是 Linux 游戏的丰收年,在这里,我们将列出迄今为止最喜欢的五款。
|
||||
|
||||
你是否在寻找优秀的 Linux 游戏却又不想挥霍金钱?来看看我们的最佳 [免费 Linux 游戏][1] 名单吧!
|
||||
|
||||
### 1. 永恒之柱2:死亡之火(Pillars of Eternity II: Deadfire)
|
||||
### 1、<ruby>永恒之柱 2:死亡之火<rt>Pillars of Eternity II: Deadfire</rt></ruby>
|
||||
|
||||
![best-linux-games-2018-pillars-of-eternity-2-deadfire][2]
|
||||
|
||||
其中一款最能代表近年来 cRPG 的复兴,它让传统的 Bethesda RPG 看起来更像是轻松的动作冒险游戏。在《永恒之柱》系列的最新作品中,当你和船员在充满冒险和危机的岛屿周围航行时,你会发现自己更像是一个海盗。
|
||||
其中一款最能代表近年来 cRPG 的复兴,它让传统的 Bethesda RPG 看起来更像是轻松的动作冒险游戏。在磅礴的《<ruby>永恒之柱<rt>Pillars of Eternity</rt></ruby>》系列的最新作品中,当你和船员在充满冒险和危机的岛屿周围航行时,你会发现自己更像是一个海盗。
|
||||
|
||||
在混合了海战元素的基础上,《死亡之火》延续了前作丰富的游戏剧情和出色的写作,同时在美丽的画面和手绘背景的基础上更进一步。
|
||||
在混合了海战元素的基础上,《死亡之火》延续了前作丰富的游戏剧情和出色的文笔,同时在美丽的画面和手绘背景的基础上更进一步。
|
||||
|
||||
这是一款毫无疑问的深度的硬核 RPG ,可能会让一些人对它产生抵触情绪,不过那些接受它的人会投入几个月的时间沉迷其中。
|
||||
这是一款毫无疑问的令人印象深刻的硬核 RPG ,可能会让一些人对它产生抵触情绪,不过那些接受它的人会投入几个月的时间沉迷其中。
|
||||
|
||||
|
||||
### 2. 杀戮尖塔(Slay the Spire)
|
||||
### 2、<ruby>杀戮尖塔<rt>Slay the Spire</rt></ruby>
|
||||
|
||||
![best-linux-games-2018-slay-the-spire][3]
|
||||
|
||||
《杀戮尖塔》仍处于早期阶段,却已经成为年度最佳游戏之一,它是一款采用 deck-building 玩法的卡牌游戏,由充满活力的视觉风格和流氓般的机制加以点缀,在每次令人愤怒的(但可能是应受的)死亡之后,你还会回来尝试更多次。(译注:翻译出来有点生硬)
|
||||
《杀戮尖塔》仍处于早期阶段,却已经成为年度最佳游戏之一,它是一款采用 deck-building 玩法的卡牌游戏,由充满活力的视觉风格和 rogue-like 机制加以点缀,即便在一次次令人愤怒的(但可能是应受的)死亡之后,你还会再次投入其中。
|
||||
|
||||
每次游戏都有无尽的卡牌组合和不同的布局,《杀戮尖塔》就像是近年来所有震撼独立场景的最佳实现——卡牌游戏和永久死亡冒险合二为一。
|
||||
每次游戏都有无尽的卡牌组合和不同的布局,《杀戮尖塔》就像是近年来所有令人震撼的独立游戏的最佳具现 —— 卡牌游戏和永久死亡冒险模式合二为一。
|
||||
|
||||
再强调一次,它仍处于早期阶段,所以它只会变得越来越好!
|
||||
|
||||
### 3. 战斗机甲(Battletech)
|
||||
### 3、<ruby>战斗机甲<rt>Battletech</rt></ruby>
|
||||
|
||||
![best-linux-games-2018-battletech][4]
|
||||
|
||||
正如我们在这个名单上看到的“重磅”游戏一样(译注:这句翻译出来前后逻辑感觉有问题),《战斗机甲》是一款星际战争游戏(基于桌面游戏),你将装载一个机甲战队并引导它们进行丰富的回合制战斗。
|
||||
这是我们榜单上像“大片”一样的游戏,《战斗机甲》是一款星际战争游戏(基于桌面游戏),你将装载一个机甲战队并引导它们进行丰富的回合制战斗。
|
||||
|
||||
战斗发生在一系列的地形上——从寒冷的荒地到阳光普照的地带——你将用巨大的热武器装备你的四人小队,与对手小队作战。如果你觉得这听起来有点“机械战士”的味道,那么你正是在正确的思考路线上,只不过这次更注重战术安排而不是直接行动。
|
||||
战斗发生在一系列的地形上,从寒冷的荒地到阳光普照的地带,你将用巨大的热武器装备你的四人小队,与对手小队作战。如果你觉得这听起来有点“机械战士”的味道,那么你想的没错,只不过这次更注重战术安排而不是直接行动。
|
||||
|
||||
除了让你在宇宙冲突中指挥的战役外,多人模式也可能会耗费你数不清的时间。
|
||||
|
||||
### 4. 死亡细胞(Dead Cells)
|
||||
### 4、<ruby>死亡细胞<rt>Dead Cells</rt></ruby>
|
||||
|
||||
![best-linux-games-2018-dead-cells][5]
|
||||
|
||||
这款游戏称得上是年度最佳平台动作游戏。"Roguelite" 类游戏《死亡细胞》将你带入一个黑暗(却色彩绚丽)的世界,在那里进行攻击和躲避以通过程序生成的关卡。它有点像 2D 的《黑暗之魂(Dark Souls)》,如果黑暗之魂被五彩缤纷的颜色浸透的话。
|
||||
这款游戏称得上是年度最佳平台动作游戏。Roguelike 游戏《死亡细胞》将你带入一个黑暗(却色彩绚丽)的世界,在那里进行攻击和躲避以通过程序生成的关卡。它有点像 2D 的《<ruby>黑暗之魂<rt>Dark Souls</rt></ruby>》,如果《黑暗之魂》也充满五彩缤纷的颜色的话。
|
||||
|
||||
死亡细胞很残忍,不过精确而灵敏的控制系统一定会让你为死亡付出代价,而在两次运行期间的升级系统又会确保你总是有一些进步的成就感。
|
||||
《死亡细胞》是无情的,只有精确而灵敏的控制才会让你避开死亡,而在两次运行期间的升级系统又会确保你总是有一些进步的成就感。
|
||||
|
||||
《死亡细胞》的像素风、动画效果和游戏机制都达到了巅峰,它及时地提醒我们,在没有 3D 图形的过度使用下游戏可以制作成什么样子。
|
||||
|
||||
|
||||
### 5. 叛逆机械师(Iconoclasts)
|
||||
### 5、<ruby>叛逆机械师<rt>Iconoclasts</rt></ruby>
|
||||
|
||||
![best-linux-games-2018-iconoclasts][6]
|
||||
|
||||
这款游戏不像上面提到的几款那样为人所知,它是一款可爱风格的游戏,可以看作是《死亡细胞》不那么惊悚、更可爱的替代品(译注:形容词生硬)。玩家将扮演成罗宾,发现自己处于政治扭曲的外星世界后开始了逃亡。
|
||||
这款游戏不像上面提到的几款那样为人所知,它是一款可爱风格的游戏,可以看作是《死亡细胞》不那么惊悚、更可爱的替代品。玩家将扮演成罗宾,一个发现自己处于政治扭曲的外星世界后开始了逃亡的女孩。
|
||||
|
||||
尽管你的角色将在非线性的关卡中行动,游戏却有着扣人心弦的游戏剧情,罗宾会获得各种各样充满想象力的提升,其中最重要的是她的扳手,从发射炮弹到解决巧妙的环境问题,你几乎可以用它来做任何事。
|
||||
|
||||
《叛逆机械师》是一个充满快乐与活力的平台游戏,融合了《洛克人(Megaman)》的战斗和《银河战士(Metroid)》的探索。如果你借鉴了那两部伟大的作品,可能不会比它做得更好。
|
||||
《叛逆机械师》是一个充满快乐与活力的平台游戏,融合了《<ruby>洛克人<rt>Megaman</rt></ruby>》的战斗和《<ruby>银河战士<rt>Metroid</rt></ruby>》的探索。如果你借鉴了那两部伟大的作品,可能不会比它做得更好。
|
||||
|
||||
### 总结
|
||||
|
||||
@ -74,7 +71,7 @@ via: https://www.maketecheasier.com/best-linux-games/
|
||||
作者:[Robert Zak][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[seriouszyx](https://github.com/seriouszyx)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -0,0 +1,109 @@
|
||||
i3 窗口管理器使 Linux 更美好
|
||||
======
|
||||
|
||||
> 通过键盘操作的 i3 平铺窗口管理器使用 Linux 桌面。
|
||||
|
||||

|
||||
|
||||
Linux(和一般的开源软件)最美好的一点是自由 —— 可以在不同的替代方案中进行选择以满足我们的需求。
|
||||
|
||||
我使用 Linux 已经很长时间了,但我从来没有对可选用的桌面环境完全满意过。直到去年,[Xfce][1] 还是我认为在功能和性能之间的平和最接近满意的一个桌面环境。然后我发现了 [i3][2],这是一个改变了我的生活的惊人的软件。
|
||||
|
||||
i3 是一个平铺窗口管理器。窗口管理器的目标是控制窗口系统中窗口的外观和位置。窗口管理器通常用作功能齐全的桌面环境 (如 GONME 或 Xfce ) 的一部分,但也有一些可以用作独立的应用程序。
|
||||
|
||||
平铺式窗口管理器会自动排列窗口,以不重叠的方式占据整个屏幕。其他流行的平铺式窗口管理器还有 [wmii][3] 和 [xmonad][4] 。
|
||||
|
||||
![i3 tiled window manager screenshot][6]
|
||||
|
||||
*带有三个的 i3 屏幕截图*
|
||||
|
||||
为了获得更好的 Linux 桌面体验,以下是我使用和推荐 i3 窗口管理器的五个首要原因。
|
||||
|
||||
### 1、极简艺术
|
||||
|
||||
i3 速度很快。它既不冗杂、也不花哨。它的设计简单而高效。作为开发人员,我重视这些功能,因为我可以使用更多的功能以丰富我最喜欢的开发工具,或者使用容器或虚拟机在本地测试内容。
|
||||
|
||||
此外, i3 是一个窗口管理器,与功能齐全的桌面环境不同,它并不规定您应该使用的应用程序。您是否想使用 Xfce 的 Thunar 作为文件管理器?GNOME 的 gedit 去编辑文本? i3 并不在乎。选择对您的工作流最有意义的工具,i3 将以相同的方式管理它们。
|
||||
|
||||
### 2、屏幕实际使用面积
|
||||
|
||||
作为平铺式窗口管理器,i3 将自动 “平铺”,以不重叠的方式定位窗口,类似于在墙上放置瓷砖。因为您不需要担心窗口定位,i3 一般会更好地利用您的屏幕空间。它还可以让您更快地找到您需要的东西。
|
||||
|
||||
对于这种情况有很多有用的例子。例如,系统管理员可以打开多个终端来同时监视或在不同的远程系统上工作;开发人员可以使用他们最喜欢的 IDE 或编辑器和几个终端来测试他们的程序。
|
||||
|
||||
此外,i3 具有灵活性。如果您需要为特定窗口提供更多空间,请启用全屏模式或切换到其他布局,如堆叠或选项卡式(标签式)。
|
||||
|
||||
### 3、键盘式工作流程
|
||||
|
||||
i3 广泛使用键盘快捷键来控制环境的不同方面。其中包括打开终端和其他程序、调整大小和定位窗口、更改布局,甚至退出 i3。当您开始使用 i3 时,您需要记住其中的一些快捷方式才能使用,随着时间的推移,您会使用更多的快捷方式。
|
||||
|
||||
主要好处是,您不需要经常在键盘和鼠标之间切换。通过练习,您将提高工作流程的速度和效率。
|
||||
|
||||
例如, 要打开新的终端,请按 `<SUPER>+<ENTER>`。由于窗口是自动定位的,您可以立即开始键入命令。结合一个很好的终端文本编辑器(如 Vim)和一个以面向键盘的浏览器,形成一个完全由键盘驱动的工作流程。
|
||||
|
||||
在 i3 中,您可以为所有内容定义快捷方式。下面是一些示例:
|
||||
|
||||
* 打开终端
|
||||
* 打开浏览器
|
||||
* 更改布局
|
||||
* 调整窗口大小
|
||||
* 控制音乐播放器
|
||||
* 切换工作区
|
||||
|
||||
现在我已经习惯了这个工作形式,我已无法回到了常规的桌面环境。
|
||||
|
||||
### 4、灵活
|
||||
|
||||
i3 力求极简,使用很少的系统资源,但这并不意味着它不能变漂亮。i3 是灵活且可通过多种方式进行自定义以改善视觉体验。因为 i3 是一个窗口管理器,所以它没有提供启用自定义的工具,你需要外部工具来实现这一点。一些例子:
|
||||
|
||||
* 用 `feh` 定义桌面的背景图片。
|
||||
* 使用合成器管理器,如 `compton` 以启用窗口淡入淡出和透明度等效果。
|
||||
* 用 `dmenu` 或 `rofi` 以启用可从键盘快捷方式启动的可自定义菜单。
|
||||
* 用 `dunst` 用于桌面通知。
|
||||
|
||||
i3 是可完全配置的,您可以通过更新默认配置文件来控制它的各个方面。从更改所有键盘快捷键,到重新定义工作区的名称,再到修改状态栏,您都可以使 i3 以任何最适合您需要的方式运行。
|
||||
|
||||
![i3 with rofi menu and dunst desktop notifications][8]
|
||||
|
||||
*i3 与 `rofi` 菜单和 `dunst` 桌面通知。*
|
||||
|
||||
最后,对于更高级的用户,i3 提供了完整的进程间通信([IPC][9])接口,允许您使用偏好的语言来开发脚本或程序,以实现更多的自定义选项。
|
||||
|
||||
### 5、工作空间
|
||||
|
||||
在 i3 中,工作区是对窗口进行分组的一种简单方法。您可以根据您的工作流以不同的方式对它们进行分组。例如,您可以将浏览器放在一个工作区上,终端放在另一个工作区上,将电子邮件客户端放在第三个工作区上等等。您甚至可以更改 i3 的配置,以便始终将特定应用程序分配给它们自己的工作区。
|
||||
|
||||
切换工作区既快速又简单。像 i3 中的惯例,使用键盘快捷方式执行此操作。按 `<SUPER>+num` 切换到工作区 `num` 。如果您养成了始终将应用程序组的窗口分配到同一个工作区的习惯,则可以在它们之间快速切换,这使得工作区成为非常有用的功能。
|
||||
|
||||
此外,还可以使用工作区来控制多监视器环境,其中每个监视器都有个初始工作区。如果切换到该工作区,则切换到该监视器,而无需让手离开键盘。
|
||||
|
||||
最后,i3 中还有另一种特殊类型的工作空间:the scratchpad(便笺簿)。它是一个不可见的工作区,通过按快捷方式显示在其他工作区的中间。这是一种访问您经常使用的窗口或程序的方便方式,如电子邮件客户端或音乐播放器。
|
||||
|
||||
### 尝试一下吧
|
||||
|
||||
如果您重视简洁和效率,并且不惮于使用键盘,i3 就是您的窗口管理器。有人说是为高级用户准备的,但情况不一定如此。你需要学习一些基本的快捷方式来度过开始的阶段,不久就会越来越自然并且不假思索地使用它们。
|
||||
|
||||
这篇文章只是浅浅谈及了 i3 能做的事情。欲了解更多详情,请参阅 [i3 的文档][10]。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/8/i3-tiling-window-manager
|
||||
|
||||
作者:[Ricardo Gerardi][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[lixinyuxx](https://github.com/lixinyuxx)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/rgerardi
|
||||
[1]:https://xfce.org/
|
||||
[2]:https://i3wm.org/
|
||||
[3]:https://code.google.com/archive/p/wmii/
|
||||
[4]:https://xmonad.org/
|
||||
[5]:/file/406476
|
||||
[6]:https://opensource.com/sites/default/files/uploads/i3_screenshot.png "i3 tiled window manager screenshot"
|
||||
[7]:/file/405161
|
||||
[8]:https://opensource.com/sites/default/files/uploads/rofi_dunst.png "i3 with rofi menu and dunst desktop notifications"
|
||||
[9]:https://i3wm.org/docs/ipc.html
|
||||
[10]:https://i3wm.org/docs/userguide.html
|
@ -1,24 +1,26 @@
|
||||
Dropbox 将在 Linux 上终止除了 Ext4 之外所有文件系统的同步支持
|
||||
Dropbox 在 Linux 上终止除了 Ext4 之外所有文件系统的同步支持
|
||||
======
|
||||
Dropbox 正考虑将同步支持限制为少数几种文件系统类型:Windows 的 NTFS、macOS 的 HFS+/APFS 和 Linux 的 Ext4。
|
||||
|
||||
> Dropbox 正考虑将同步支持限制为少数几种文件系统类型:Windows 的 NTFS、macOS 的 HFS+/APFS 和 Linux 的 Ext4。
|
||||
|
||||
![Dropbox ends support for various file system types][1]
|
||||
|
||||
[Dropbox][2] 是最受欢迎的[ Linux 中的云服务][3]之一。很多人正好使用的是 Linux 下的 Dropbox 同步客户端。但是,最近,一些用户在他们的 Dropbox Linux 桌面客户端上收到一条警告说:
|
||||
[Dropbox][2] 是最受欢迎的 [Linux 中的云服务][3]之一。很多人都在使用 Linux 下的 Dropbox 同步客户端。但是,最近,一些用户在他们的 Dropbox Linux 桌面客户端上收到一条警告说:
|
||||
|
||||
> “移动 Dropbox 文件夹位置,
|
||||
> Dropbox 将在 11 月停止同步“
|
||||
|
||||
### Dropbox 将仅支持少量文件系统
|
||||
|
||||
一个[ Reddit 主题][4]高亮了一位用户在[ Dropbox 论坛][5]上查询了该消息后的公告,该消息是社区管理员带来的意外消息。这是[回复][6]中的内容:
|
||||
一个 [Reddit 主题][4]强调了一位用户在 [Dropbox 论坛][5]上查询了该消息后的公告,该消息被社区管理员标记为意外新闻。这是[回复][6]中的内容:
|
||||
|
||||
> **“大家好,在 2018 年 11 月 7 日,我们会结束 Dropbox 在某些不常见文件系统的同步支持。支持的文件系统是 Windows 的 NTFS、macOS 的 HFS+ 或 APFS,以及Linux 的 Ext4。**
|
||||
> “大家好,在 2018 年 11 月 7 日,我们会结束 Dropbox 在某些不常见文件系统的同步支持。支持的文件系统是 Windows 的 NTFS、macOS 的 HFS+ 或 APFS,以及Linux 的 Ext4。
|
||||
>
|
||||
> [Dropbox 官方论坛][6]
|
||||
|
||||
![Dropbox official confirmation over limitation on supported file systems][7]
|
||||
Dropbox 官方确认支持文件系统的限制
|
||||
|
||||
*Dropbox 官方确认支持文件系统的限制*
|
||||
|
||||
此举旨在提供稳定和一致的体验。Dropbox 还更新了其[桌面要求][8]。
|
||||
|
||||
@ -31,11 +33,12 @@ Linux 仅支持 Ext4 文件系统。但这并不是一个令人担忧的新闻
|
||||
在 Ubuntu 或其他基于 Ubuntu 的发行版上,打开磁盘应用并查看 Linux 系统所在分区的文件系统。
|
||||
|
||||
![Check file system type on Ubuntu][9]
|
||||
检查 Ubuntu 上的文件系统类型
|
||||
|
||||
*检查 Ubuntu 上的文件系统类型*
|
||||
|
||||
如果你的系统上没有安装磁盘应用,那么可以[使用命令行了解文件系统类型][10]。
|
||||
|
||||
如果你使用的是 Ext4 文件系统并仍然收到来自 Dropbox 的警告,请检查你是否有可能收到通知的非活动计算机/设备。如果是,[将该系统与你的 Dropbox 帐户取消链接][11]。
|
||||
如果你使用的是 Ext4 文件系统并仍然收到来自 Dropbox 的警告,请检查你是否有可能收到通知的非活动计算机/设备。如果是,[将该系统与你的 Dropbox 帐户取消连接][11]。
|
||||
|
||||
### Dropbox 也不支持加密的 Ext4 吗?
|
||||
|
||||
@ -51,21 +54,21 @@ via: https://itsfoss.com/dropbox-linux-ext4-only/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/ankush/
|
||||
[1]: https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2018/08/dropbox-filesystem-support-featured.png
|
||||
[1]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2018/08/dropbox-filesystem-support-featured.png?w=800&ssl=1
|
||||
[2]: https://www.dropbox.com/
|
||||
[3]: https://itsfoss.com/cloud-services-linux/
|
||||
[4]: https://www.reddit.com/r/linux/comments/966xt0/linux_dropbox_client_will_stop_syncing_on_any/
|
||||
[5]: https://www.dropboxforum.com/t5/Syncing-and-uploads/
|
||||
[6]: https://www.dropboxforum.com/t5/Syncing-and-uploads/Linux-Dropbox-client-warn-me-that-it-ll-stop-syncing-in-Nov-why/m-p/290065/highlight/true#M42255
|
||||
[7]: https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2018/08/dropbox-stopping-file-system-supports.jpeg
|
||||
[7]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/08/dropbox-stopping-file-system-supports.jpeg?w=800&ssl=1
|
||||
[8]: https://www.dropbox.com/help/desktop-web/system-requirements#desktop
|
||||
[9]: https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2018/08/check-file-system-type-ubuntu.jpg
|
||||
[9]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/08/check-file-system-type-ubuntu.jpg?w=800&ssl=1
|
||||
[10]: https://www.thegeekstuff.com/2011/04/identify-file-system-type/
|
||||
[11]: https://www.dropbox.com/help/mobile/unlink-relink-computer-mobile
|
||||
[12]: https://www.dropbox.com/help/desktop-web/cant-establish-secure-connection#location
|
@ -0,0 +1,100 @@
|
||||
顶级 Linux 开发者推荐的编程书籍
|
||||
======
|
||||
|
||||

|
||||
|
||||
> 毫无疑问,Linux 是由那些拥有深厚计算机知识背景而且才华横溢的程序员发明的。让那些大名鼎鼎的 Linux 程序员向如今的开发者分享一些曾经带领他们登堂入室的好书和技术参考资料吧,你会不会也读过其中几本呢?
|
||||
|
||||
Linux,毫无争议的属于 21 世纪的操作系统。虽然 Linus Torvalds 在建立开源社区这件事上做了很多工作和社区决策,不过那些网络专家和开发者愿意接受 Linux 的原因还是因为它卓越的代码质量和高可用性。Torvalds 是个编程天才,同时必须承认他还是得到了很多其他同样极具才华的开发者的无私帮助。
|
||||
|
||||
就此我咨询了 Torvalds 和其他一些顶级 Linux 开发者,有哪些书籍帮助他们走上了成为顶级开发者的道路,下面请听我一一道来。
|
||||
|
||||
### 熠熠生辉的 C 语言
|
||||
|
||||
Linux 是在大约上世纪 90 年代开发出来的,与它一起问世的还有其他一些完成基础功能的开源软件。与此相应,那时的开发者使用的工具和语言反映了那个时代的印记,也就是说 C 语言。可能 [C 语言不再流行了][1],可对于很多已经建功立业的开发者来说,C 语言是他们的第一个在实际开发中使用的语言,这一点也在他们推选的对他们有着深远影响的书单中反映出来。
|
||||
|
||||
Torvalds 说,“你不应该再选用我那个时代使用的语言或者开发方式”,他的开发道路始于 BASIC,然后转向机器码(“甚至都不是汇编语言,而是真真正正的‘二进制’机器码”,他解释道),再然后转向汇编语言和 C 语言。
|
||||
|
||||
“任何人都不应该再从这些语言开始进入开发这条路了”,他补充道。“这些语言中的一些今天已经没有什么意义(如 BASIC 和机器语言)。尽管 C 还是一个主流语言,我也不推荐你从它开始。”
|
||||
|
||||
并不是他不喜欢 C。不管怎样,Linux 是用 [GNU C 语言][2]写就的。“我始终认为 C 是一个伟大的语言,它有着非常简单的语法,对于很多方向的开发都很合适,但是我怀疑你会遇到重重挫折,从你的第一个‘Hello World’程序开始到你真正能开发出能用的东西当中有很大一步要走”。他认为,用现在的标准,如果作为入门语言的话,从 C 语言开始的代价太大。
|
||||
|
||||
在他那个时代,Torvalds 的唯一选择的书就只能是 Brian W. Kernighan 和 Dennis M. Ritchie 合著的《<ruby>[C 编程语言,第二版][3]<rt>C Programming Language, 2nd Edition</rt></ruby>》,它在编程圈内也被尊称为 K&R。“这本书简单精炼,但是你要先有编程的背景才能欣赏它”,Torvalds 说到。
|
||||
|
||||
Torvalds 并不是唯一一个推荐 K&R 的开源开发者。以下几位也同样引用了这本他们认为值得推荐的书籍,他们有:Linux 和 Oracle 虚拟化开发副总裁 Wim Coekaerts;Linux 开发者 Alan Cox;Google 云 CTO Brian Stevens;Canonical 技术运营部副总裁 Pete Graner。
|
||||
|
||||
如果你今日还想同 C 语言较量一番的话,Samba 的共同创始人 Jeremy Allison 推荐《<ruby>[C 程序设计新思维][4]<rt>21st Century C: C Tips from the New School</rt></ruby>》。他还建议,同时也去阅读一本比较旧但是写的更详细的《<ruby>[C 专家编程][5]<rt>Expert C Programming: Deep C Secrets</rt></ruby>》和有着 20 年历史的《<ruby>[POSIX 多线程编程][6]<rt>Programming with POSIX Threads</rt></ruby>》。
|
||||
|
||||
### 如果不选 C 语言, 那选什么?
|
||||
|
||||
Linux 开发者推荐的书籍自然都是他们认为适合今时今日的开发项目的语言工具。这也折射了开发者自身的个人偏好。例如,Allison 认为年轻的开发者应该在《<ruby>[Go 编程语言][7]<rt>The Go Programming Language</rt></ruby>》和《<ruby>[Rust 编程][8]<rt>Rust with Programming Rust</rt></ruby>》的帮助下去学习 Go 语言和 Rust 语言。
|
||||
|
||||
但是超越编程语言来考虑问题也不无道理(尽管这些书传授了你编程技巧)。今日要做些有意义的开发工作的话,"要从那些已经完成了 99% 显而易见工作的框架开始,然后你就能围绕着它开始写脚本了", Torvalds 推荐了这种做法。
|
||||
|
||||
“坦率来说,语言本身远远没有围绕着它的基础架构重要”,他继续道,“可能你会从 Java 或者 Kotlin 开始,但那是因为你想为自己的手机开发一个应用,因此安卓 SDK 成为了最佳的选择,又或者,你对游戏开发感兴趣,你选择了一个游戏开发引擎来开始,而通常它们有着自己的脚本语言”。
|
||||
|
||||
这里提及的基础架构包括那些和操作系统本身相关的编程书籍。
|
||||
Garner 在读完了大名鼎鼎的 K&R 后又拜读了 W. Richard Steven 的《<ruby>[Unix 网络编程][10]<rt>Unix Network Programming</rt></ruby>》。特别是,Steven 的《<ruby>[TCP/IP 详解,卷1:协议][11]<rt>TCP/IP Illustrated, Volume 1: The Protocols</rt></ruby>》在出版了 30 年之后仍然被认为是必读之书。因为 Linux 开发很大程度上和[和网络基础架构有关][12],Garner 也推荐了很多 O'Reilly 在 [Sendmail][13]、[Bash][14]、[DNS][15] 以及 [IMAP/POP][16] 等方面的书。
|
||||
|
||||
Coekaerts 也是 Maurice Bach 的《<ruby>[UNIX 操作系统设计][17]<rt>The Design of the Unix Operation System</rt></ruby>》的书迷之一。James Bottomley 也是这本书的推崇者,作为一个 Linux 内核开发者,当 Linux 刚刚问世时 James 就用 Bach 的这本书所传授的知识将它研究了个底朝天。
|
||||
|
||||
### 软件设计知识永不过时
|
||||
|
||||
尽管这样说有点太局限在技术领域。Stevens 还是说到,“所有的开发者都应该在开始钻研语法前先研究如何设计,《<ruby>[设计心理学][18]<rt>The Design of Everyday Things</rt></ruby>》是我的最爱”。
|
||||
|
||||
Coekaerts 喜欢 Kernighan 和 Rob Pike 合著的《<ruby>[程序设计实践][19]<rt>The Practic of Programming</rt></ruby>》。这本关于设计实践的书当 Coekaerts 还在学校念书的时候还未出版,他说道,“但是我把它推荐给每一个人”。
|
||||
|
||||
不管何时,当你问一个长期从事于开发工作的开发者他最喜欢的计算机书籍时,你迟早会听到一个名字和一本书:Donald Knuth 和他所著的《<ruby>[计算机程序设计艺术(1-4A)][20]<rt>The Art of Computer Programming, Volumes 1-4A</rt></ruby>》。VMware 首席开源官 Dirk Hohndel,认为这本书尽管有永恒的价值,但他也承认,“今时今日并非极其有用”。(LCTT 译注:不代表译者观点)
|
||||
|
||||
### 读代码。大量的读。
|
||||
|
||||
编程书籍能教会你很多,也请别错过另外一个在开源社区特有的学习机会:《<ruby>[代码阅读方法与实践][21]<rt>Code Reading: The Open Source Perspective</rt></ruby>》。那里有不可计数的代码例子阐述如何解决编程问题(以及如何让你陷入麻烦……)。Stevens 说,谈到磨炼编程技巧,在他的书单里排名第一的“书”是 Unix 的源代码。
|
||||
|
||||
“也请不要忽略从他人身上学习的各种机会。” Cox 道,“我是在一个计算机俱乐部里和其他人一起学的 BASIC,在我看来,这仍然是一个学习的最好办法”,他从《<ruby>[精通 ZX81 机器码][22]<rt>Mastering machine code on your ZX81</rt></ruby>》这本书和 Honeywell L66 B 编译器手册里学习到了如何编写机器码,但是学习技术这点来说,单纯阅读和与其他开发者在工作中共同学习仍然有着很大的不同。
|
||||
|
||||
Cox 说,“我始终认为最好的学习方法是和一群人一起试图去解决你们共同关心的一些问题并从中找到快乐,这和你是 5 岁还是 55 岁无关”。
|
||||
|
||||
最让我吃惊的是这些顶级 Linux 开发者都是在非常底层级别开始他们的开发之旅的,甚至不是从汇编语言或 C 语言,而是从机器码开始开发。毫无疑问,这对帮助开发者理解计算机在非常微观的底层级别是怎么工作的起了非常大的作用。
|
||||
|
||||
那么现在你准备好尝试一下硬核 Linux 开发了吗?Greg Kroah-Hartman,这位 Linux 内核稳定分支的维护者,推荐了 Steve Oualline 的《<ruby>[实用 C 语言编程][23]<rt>Practical C Programming</rt></ruby>》和 Samuel harbison 与 Guy Steels 合著的《<ruby>[C 语言参考手册][24]<rt>C: A Reference Manual</rt></ruby>》。接下来请阅读<ruby>[如何进行 Linux 内核开发][25]<rt>HOWTO do Linux kernel development</rt></ruby>,到这时,就像 Kroah-Hartman 所说,你已经准备好启程了。
|
||||
|
||||
于此同时,还请你刻苦学习并大量编码,最后祝你在跟随顶级 Linux 开发者脚步的道路上好运相随。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.hpe.com/us/en/insights/articles/top-linux-developers-recommended-programming-books-1808.html
|
||||
|
||||
作者:[Steven Vaughan-Nichols][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[DavidChenLiang](https://github.com/DavidChenLiang)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.hpe.com/us/en/insights/contributors/steven-j-vaughan-nichols.html
|
||||
[1]:https://www.codingdojo.com/blog/7-most-in-demand-programming-languages-of-2018/
|
||||
[2]:https://www.gnu.org/software/gnu-c-manual/
|
||||
[3]:https://amzn.to/2nhyjEO
|
||||
[4]:https://amzn.to/2vsL8k9
|
||||
[5]:https://amzn.to/2KBbWn9
|
||||
[6]:https://amzn.to/2M0rfeR
|
||||
[7]:https://amzn.to/2nhyrnMe
|
||||
[8]:http://shop.oreilly.com/product/0636920040385.do
|
||||
[9]:https://www.hpe.com/us/en/resources/storage/containers-for-dummies.html?jumpid=in_510384402_linuxbooks_containerebook0818
|
||||
[10]:https://amzn.to/2MfpbyC
|
||||
[11]:https://amzn.to/2MpgrTn
|
||||
[12]:https://www.hpe.com/us/en/insights/articles/how-to-see-whats-going-on-with-your-linux-system-right-now-1807.html
|
||||
[13]:http://shop.oreilly.com/product/9780596510299.do
|
||||
[14]:http://shop.oreilly.com/product/9780596009656.do
|
||||
[15]:http://shop.oreilly.com/product/9780596100575.do
|
||||
[16]:http://shop.oreilly.com/product/9780596000127.do
|
||||
[17]:https://amzn.to/2vsCJgF
|
||||
[18]:https://amzn.to/2APzt3Z
|
||||
[19]:https://www.amazon.com/Practice-Programming-Addison-Wesley-Professional-Computing/dp/020161586X/ref=as_li_ss_tl?ie=UTF8&linkCode=sl1&tag=thegroovycorpora&linkId=e6bbdb1ca2182487069bf9089fc8107e&language=en_US
|
||||
[20]:https://amzn.to/2OknFsJ
|
||||
[21]:https://amzn.to/2M4VVL3
|
||||
[22]:https://amzn.to/2OjccJA
|
||||
[23]:http://shop.oreilly.com/product/9781565923065.do
|
||||
[24]:https://amzn.to/2OjzgrT
|
||||
[25]:https://www.kernel.org/doc/html/v4.16/process/howto.html
|
File diff suppressed because it is too large
Load Diff
@ -3,11 +3,12 @@
|
||||
|
||||

|
||||
|
||||
越来越多的开发人员使用容器开发和部署他们的应用。这意味着可以轻松地测试容器也变得很重要。[Conu][1] (container utilities 的简写) 是一个Python库,让你编写容器测试变得简单。本文向你介绍如何使用它测试容器。
|
||||
越来越多的开发人员使用容器开发和部署他们的应用。这意味着可以轻松地测试容器也变得很重要。[Conu][1] (container utilities 的简写) 是一个 Python 库,让你编写容器测试变得简单。本文向你介绍如何使用它测试容器。
|
||||
|
||||
### 开始吧
|
||||
|
||||
首先,你需要一个容器程序来测试。为此,以下命令创建一个包含一个容器 Dockerfile 和一个被容器伺服的 Flask 应用程序的文件夹。
|
||||
首先,你需要一个容器程序来测试。为此,以下命令创建一个包含一个容器的 Dockerfile 和一个被容器伺服的 Flask 应用程序的文件夹。
|
||||
|
||||
```bash
|
||||
$ mkdir container_test
|
||||
$ cd container_test
|
||||
@ -15,22 +16,24 @@ $ touch Dockerfile
|
||||
$ touch app.py
|
||||
```
|
||||
|
||||
将以下代码复制到 app.py 文件中。这是惯常的基本 Flask 应用,它返回字符串“Hello Container World!”。
|
||||
将以下代码复制到 `app.py` 文件中。这是惯常的基本 Flask 应用,它返回字符串 “Hello Container World!”。
|
||||
|
||||
```python
|
||||
from flask import Flask
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route('/')
|
||||
def hello_world():
|
||||
return 'Hello Container World!'
|
||||
return 'Hello Container World!'
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True,host='0.0.0.0')
|
||||
app.run(debug=True,host='0.0.0.0')
|
||||
```
|
||||
|
||||
### 创建和构建测试容器
|
||||
|
||||
为了构建测试容器,将以下指令添加到 Dockerfile。
|
||||
|
||||
```dockerfile
|
||||
FROM registry.fedoraproject.org/fedora-minimal:latest
|
||||
RUN microdnf -y install python3-flask && microdnf clean all
|
||||
@ -39,6 +42,7 @@ CMD ["python3", "/srv/app.py"]
|
||||
```
|
||||
|
||||
然后使用 Docker CLI 工具构建容器。
|
||||
|
||||
```bash
|
||||
$ sudo dnf -y install docker
|
||||
$ sudo systemctl start docker
|
||||
@ -48,6 +52,7 @@ $ sudo docker build . -t flaskapp_container
|
||||
提示:只有在系统上未安装 Docker 时才需要前两个命令。
|
||||
|
||||
构建之后使用以下命令运行容器。
|
||||
|
||||
```bash
|
||||
$ sudo docker run -p 5000:5000 --rm flaskapp_container
|
||||
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
|
||||
@ -56,17 +61,19 @@ $ sudo docker run -p 5000:5000 --rm flaskapp_container
|
||||
* Debugger PIN: 473-505-51
|
||||
```
|
||||
|
||||
最后,使用 curl 检查 Flask 应用程序是否在容器内正确运行:
|
||||
最后,使用 `curl` 检查 Flask 应用程序是否在容器内正确运行:
|
||||
|
||||
```bash
|
||||
$ curl http://127.0.0.1:5000
|
||||
Hello Container World!
|
||||
```
|
||||
|
||||
现在,flaskapp_container 正在运行并准备好进行测试,你可以使用 Ctrl+C 将其停止。
|
||||
现在,flaskapp_container 正在运行并准备好进行测试,你可以使用 `Ctrl+C` 将其停止。
|
||||
|
||||
### 创建测试脚本
|
||||
|
||||
在编写测试脚本之前,必须安装 conu。在先前创建的 container_test 目录中,运行以下命令。
|
||||
在编写测试脚本之前,必须安装 `conu`。在先前创建的 `container_test` 目录中,运行以下命令。
|
||||
|
||||
```bash
|
||||
$ python3 -m venv .venv
|
||||
$ source .venv/bin/activate
|
||||
@ -75,48 +82,48 @@ $ source .venv/bin/activate
|
||||
$ touch test_container.py
|
||||
```
|
||||
|
||||
然后将以下脚本复制并保存在 test_container.py 文件中。
|
||||
然后将以下脚本复制并保存在 `test_container.py` 文件中。
|
||||
|
||||
```python
|
||||
import conu
|
||||
|
||||
PORT = 5000
|
||||
|
||||
with conu.DockerBackend() as backend:
|
||||
image = backend.ImageClass("flaskapp_container")
|
||||
options = ["-p", "5000:5000"]
|
||||
container = image.run_via_binary(additional_opts=options)
|
||||
image = backend.ImageClass("flaskapp_container")
|
||||
options = ["-p", "5000:5000"]
|
||||
container = image.run_via_binary(additional_opts=options)
|
||||
|
||||
try:
|
||||
# Check that the container is running and wait for the flask application to start.
|
||||
assert container.is_running()
|
||||
container.wait_for_port(PORT)
|
||||
|
||||
# Run a GET request on / port 5000.
|
||||
http_response = container.http_request(path="/", port=PORT)
|
||||
|
||||
# Check the response status code is 200
|
||||
assert http_response.ok
|
||||
|
||||
# Get the response content
|
||||
response_content = http_response.content.decode("utf-8")
|
||||
|
||||
try:
|
||||
# Check that the container is running and wait for the flask application to start.
|
||||
assert container.is_running()
|
||||
container.wait_for_port(PORT)
|
||||
# Check that the "Hello Container World!" string is served.
|
||||
assert "Hello Container World!" in response_content
|
||||
|
||||
# Run a GET request on / port 5000.
|
||||
http_response = container.http_request(path="/", port=PORT)
|
||||
|
||||
# Check the response status code is 200
|
||||
assert http_response.ok
|
||||
|
||||
# Get the response content
|
||||
response_content = http_response.content.decode("utf-8")
|
||||
|
||||
# Check that the "Hello Container World!" string is served.
|
||||
assert "Hello Container World!" in response_content
|
||||
|
||||
# Get the logs from the container
|
||||
logs = [line for line in container.logs()]
|
||||
# Check the the Flask application saw the GET request.
|
||||
assert b'"GET / HTTP/1.1" 200 -' in logs[-1]
|
||||
|
||||
finally:
|
||||
container.stop()
|
||||
container.delete()
|
||||
# Get the logs from the container
|
||||
logs = [line for line in container.logs()]
|
||||
# Check the the Flask application saw the GET request.
|
||||
assert b'"GET / HTTP/1.1" 200 -' in logs[-1]
|
||||
|
||||
finally:
|
||||
container.stop()
|
||||
container.delete()
|
||||
```
|
||||
|
||||
#### 测试设置
|
||||
|
||||
这个脚本首先设置 conu 使用 Docker 作为后端来运行容器。然后它设置容器镜像以使用你在本教程第一部分中构建的 flaskapp_container。
|
||||
这个脚本首先设置 `conu` 使用 Docker 作为后端来运行容器。然后它设置容器镜像以使用你在本教程第一部分中构建的 flaskapp_container。
|
||||
|
||||
下一步是配置运行容器所需的选项。在此示例中,Flask 应用在端口5000上提供内容。于是你需要暴露此端口并将其映射到主机上的同一端口。
|
||||
|
||||
@ -124,13 +131,13 @@ with conu.DockerBackend() as backend:
|
||||
|
||||
#### 测试方法
|
||||
|
||||
在测试容器之前,检查容器是否正在运行并准备就绪。示范脚本使用 container.is_running 和 container.wait_for_port。这些方法可确保容器正在运行,并且服务在预设端口上可用。
|
||||
在测试容器之前,检查容器是否正在运行并准备就绪。示范脚本使用 `container.is_running` 和 `container.wait_for_port`。这些方法可确保容器正在运行,并且服务在预设端口上可用。
|
||||
|
||||
container.http_request 是 [request][2] 库的包装器,可以方便地在测试期间发送 HTTP 请求。这个方法返回[requests.Responseobject][3],因此可以轻松地访问响应的内容以进行测试。
|
||||
`container.http_request` 是 [request][2] 库的包装器,可以方便地在测试期间发送 HTTP 请求。这个方法返回[requests.Responseobject][3],因此可以轻松地访问响应的内容以进行测试。
|
||||
|
||||
Conu 还可以访问容器日志。又一次,这在测试期间非常有用。在上面的示例中,container.logs 方法返回容器日志。你可以使用它们断言打印了特定日志,或者,例如在测试期间没有异常被引发。
|
||||
`conu` 还可以访问容器日志。又一次,这在测试期间非常有用。在上面的示例中,`container.logs` 方法返回容器日志。你可以使用它们断言打印了特定日志,或者,例如在测试期间没有异常被引发。
|
||||
|
||||
Conu 提供了许多与容器接合的有用方法。[文档][4]中提供了完整的 API 列表。你还可以参考 [GitHub][5] 上提供的示例。
|
||||
`conu` 提供了许多与容器接合的有用方法。[文档][4]中提供了完整的 API 列表。你还可以参考 [GitHub][5] 上提供的示例。
|
||||
|
||||
运行本教程所需的所有代码和文件也可以在 [GitHub][6] 上获得。 对于想要进一步采用这个例子的读者,你可以看看使用 [pytest][7] 来运行测试并构建一个容器测试套件。
|
||||
|
||||
@ -141,7 +148,7 @@ via: https://fedoramagazine.org/test-containers-python-conu/
|
||||
作者:[Clément Verna][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[GraveAccent](https://github.com/GraveAccent)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
222
published/201811/20180907 6.828 lab tools guide.md
Normal file
222
published/201811/20180907 6.828 lab tools guide.md
Normal file
@ -0,0 +1,222 @@
|
||||
Caffeinated 6.828:实验工具指南
|
||||
======
|
||||
|
||||
熟悉你的环境对高效率的开发和调试来说是至关重要的。本文将为你简单概述一下 JOS 环境和非常有用的 GDB 和 QEMU 命令。话虽如此,但你仍然应该去阅读 GDB 和 QEMU 手册,来理解这些强大的工具如何使用。
|
||||
|
||||
### 调试小贴士
|
||||
|
||||
#### 内核
|
||||
|
||||
GDB 是你的朋友。使用 `qemu-gdb target`(或它的变体 `qemu-gdb-nox`)使 QEMU 等待 GDB 去绑定。下面在调试内核时用到的一些命令,可以去查看 GDB 的资料。
|
||||
|
||||
如果你遭遇意外的中断、异常、或三重故障,你可以使用 `-d` 参数要求 QEMU 去产生一个详细的中断日志。
|
||||
|
||||
调试虚拟内存问题时,尝试 QEMU 的监视命令 `info mem`(提供内存高级概述)或 `info pg`(提供更多细节内容)。注意,这些命令仅显示**当前**页表。
|
||||
|
||||
(在实验 4 以后)去调试多个 CPU 时,使用 GDB 的线程相关命令,比如 `thread` 和 `info threads`。
|
||||
|
||||
#### 用户环境(在实验 3 以后)
|
||||
|
||||
GDB 也可以去调试用户环境,但是有些事情需要注意,因为 GDB 无法区分开多个用户环境或区分开用户环境与内核环境。
|
||||
|
||||
你可以使用 `make run-name`(或编辑 `kern/init.c` 目录)来指定 JOS 启动的用户环境,为使 QEMU 等待 GDB 去绑定,使用 `run-name-gdb` 的变体。
|
||||
|
||||
你可以符号化调试用户代码,就像调试内核代码一样,但是你要告诉 GDB,哪个符号表用到符号文件命令上,因为它一次仅能够使用一个符号表。提供的 `.gdbinit` 用于加载内核符号表 `obj/kern/kernel`。对于一个用户环境,这个符号表在它的 ELF 二进制文件中,因此你可以使用 `symbol-file obj/user/name` 去加载它。不要从任何 `.o` 文件中加载符号,因为它们不会被链接器迁移进去(库是静态链接进 JOS 用户二进制文件中的,因此这些符号已经包含在每个用户二进制文件中了)。确保你得到了正确的用户二进制文件;在不同的二进制文件中,库函数被链接为不同的 EIP,而 GDB 并不知道更多的内容!
|
||||
|
||||
(在实验 4 以后)因为 GDB 绑定了整个虚拟机,所以它可以将时钟中断看作为一种控制转移。这使得从底层上不可能实现步进用户代码,因为一个时钟中断无形中保证了片刻之后虚拟机可以再次运行。因此可以使用 `stepi` 命令,因为它阻止了中断,但它仅可以步进一个汇编指令。断点一般来说可以正常工作,但要注意,因为你可能在不同的环境(完全不同的一个二进制文件)上遇到同一个 EIP。
|
||||
|
||||
### 参考
|
||||
|
||||
#### JOS makefile
|
||||
|
||||
JOS 的 GNUmakefile 包含了在各种方式中运行的 JOS 的许多假目标。所有这些目标都配置 QEMU 去监听 GDB 连接(`*-gdb` 目标也等待这个连接)。要在运行中的 QEMU 上启动它,只需要在你的实验目录中简单地运行 `gdb ` 即可。我们提供了一个 `.gdbinit` 文件,它可以在 QEMU 中自动指向到 GDB、加载内核符号文件、以及在 16 位和 32 位模式之间切换。退出 GDB 将关闭 QEMU。
|
||||
|
||||
* `make qemu`
|
||||
|
||||
在一个新窗口中构建所有的东西并使用 VGA 控制台和你的终端中的串行控制台启动 QEMU。想退出时,既可以关闭 VGA 窗口,也可以在你的终端中按 `Ctrl-c` 或 `Ctrl-a x`。
|
||||
* `make qemu-nox`
|
||||
|
||||
和 `make qemu` 一样,但仅使用串行控制台来运行。想退出时,按下 `Ctrl-a x`。这种方式在通过 SSH 拨号连接到 Athena 上时非常有用,因为 VGA 窗口会占用许多带宽。
|
||||
* `make qemu-gdb`
|
||||
|
||||
和 `make qemu` 一样,但它与任意时间被动接受 GDB 不同,而是暂停第一个机器指令并等待一个 GDB 连接。
|
||||
* `make qemu-nox-gdb`
|
||||
|
||||
它是 `qemu-nox` 和 `qemu-gdb` 目标的组合。
|
||||
* `make run-nam`
|
||||
|
||||
(在实验 3 以后)运行用户程序 _name_。例如,`make run-hello` 运行 `user/hello.c`。
|
||||
* `make run-name-nox`,`run-name-gdb`, `run-name-gdb-nox`
|
||||
|
||||
(在实验 3 以后)与 `qemu` 目标变量对应的 `run-name` 的变体。
|
||||
|
||||
makefile 也接受几个非常有用的变量:
|
||||
|
||||
* `make V=1 …`
|
||||
|
||||
详细模式。输出正在运行的每个命令,包括参数。
|
||||
* `make V=1 grade`
|
||||
|
||||
在评级测试失败后停止,并将 QEMU 的输出放入 `jos.out` 文件中以备检查。
|
||||
* `make QEMUEXTRA=' _args_ ' …`
|
||||
|
||||
指定传递给 QEMU 的额外参数。
|
||||
|
||||
#### JOS obj/
|
||||
|
||||
在构建 JOS 时,makefile 也产生一些额外的输出文件,这些文件在调试时非常有用:
|
||||
|
||||
* `obj/boot/boot.asm`、`obj/kern/kernel.asm`、`obj/user/hello.asm`、等等。
|
||||
|
||||
引导加载器、内核、和用户程序的汇编代码列表。
|
||||
* `obj/kern/kernel.sym`、`obj/user/hello.sym`、等等。
|
||||
|
||||
内核和用户程序的符号表。
|
||||
* `obj/boot/boot.out`、`obj/kern/kernel`、`obj/user/hello`、等等。
|
||||
|
||||
内核和用户程序链接的 ELF 镜像。它们包含了 GDB 用到的符号信息。
|
||||
|
||||
#### GDB
|
||||
|
||||
完整的 GDB 命令指南请查看 [GDB 手册][1]。下面是一些在 6.828 课程中非常有用的命令,它们中的一些在操作系统开发之外的领域几乎用不到。
|
||||
|
||||
* `Ctrl-c`
|
||||
|
||||
在当前指令处停止机器并打断进入到 GDB。如果 QEMU 有多个虚拟的 CPU,所有的 CPU 都会停止。
|
||||
* `c`(或 `continue`)
|
||||
|
||||
继续运行,直到下一个断点或 `Ctrl-c`。
|
||||
* `si`(或 `stepi`)
|
||||
|
||||
运行一个机器指令。
|
||||
* `b function` 或 `b file:line`(或 `breakpoint`)
|
||||
|
||||
在给定的函数或行上设置一个断点。
|
||||
* `b * addr`(或 `breakpoint`)
|
||||
|
||||
在 EIP 的 addr 处设置一个断点。
|
||||
* `set print pretty`
|
||||
|
||||
启用数组和结构的美化输出。
|
||||
* `info registers`
|
||||
|
||||
输出通用寄存器 `eip`、`eflags`、和段选择器。更多更全的机器寄存器状态转储,查看 QEMU 自己的 `info registers` 命令。
|
||||
* `x/ N x addr`
|
||||
|
||||
以十六进制显示虚拟地址 addr 处开始的 N 个词的转储。如果 N 省略,默认为 1。addr 可以是任何表达式。
|
||||
* `x/ N i addr`
|
||||
|
||||
显示从 addr 处开始的 N 个汇编指令。使用 `$eip` 作为 addr 将显示当前指令指针寄存器中的指令。
|
||||
* `symbol-file file`
|
||||
|
||||
(在实验 3 以后)切换到符号文件 file 上。当 GDB 绑定到 QEMU 后,它并不是虚拟机中进程边界内的一部分,因此我们要去告诉它去使用哪个符号。默认情况下,我们配置 GDB 去使用内核符号文件 `obj/kern/kernel`。如果机器正在运行用户代码,比如是 `hello.c`,你就需要使用 `symbol-file obj/user/hello` 去切换到 hello 的符号文件。
|
||||
|
||||
QEMU 将每个虚拟 CPU 表示为 GDB 中的一个线程,因此你可以使用 GDB 中所有的线程相关的命令去查看或维护 QEMU 的虚拟 CPU。
|
||||
|
||||
* `thread n`
|
||||
|
||||
GDB 在一个时刻只关注于一个线程(即:CPU)。这个命令将关注的线程切换到 n,n 是从 0 开始编号的。
|
||||
* `info threads`
|
||||
|
||||
列出所有的线程(即:CPU),包括它们的状态(活动还是停止)和它们在什么函数中。
|
||||
|
||||
|
||||
#### QEMU
|
||||
|
||||
QEMU 包含一个内置的监视器,它能够有效地检查和修改机器状态。想进入到监视器中,在运行 QEMU 的终端中按入 `Ctrl-a c` 即可。再次按下 `Ctrl-a c` 将切换回串行控制台。
|
||||
|
||||
监视器命令的完整参考资料,请查看 [QEMU 手册][2]。下面是 6.828 课程中用到的一些有用的命令:
|
||||
|
||||
* `xp/ N x paddr`
|
||||
|
||||
显示从物理地址 paddr 处开始的 N 个词的十六进制转储。如果 N 省略,默认为 1。这是 GDB 的 `x` 命令模拟的物理内存。
|
||||
* `info registers`
|
||||
|
||||
显示机器内部寄存器状态的一个完整转储。实践中,对于段选择器,这将包含机器的 _隐藏_ 段状态和局部、全局、和中断描述符表加任务状态寄存器。隐藏状态是在加载段选择器后,虚拟的 CPU 从 GDT/LDT 中读取的信息。下面是实验 1 中 JOS 内核处于运行中时的 CS 信息和每个字段的含义:
|
||||
|
||||
```c
|
||||
CS =0008 10000000 ffffffff 10cf9a00 DPL=0 CS32 [-R-]
|
||||
```
|
||||
|
||||
* `CS =0008`
|
||||
|
||||
代码选择器可见部分。我们使用段 0x8。这也告诉我们参考全局描述符表(0x8&4=0),并且我们的 CPL(当前权限级别)是 0x8&3=0。
|
||||
* `10000000`
|
||||
|
||||
这是段基址。线性地址 = 逻辑地址 + 0x10000000。
|
||||
* `ffffffff`
|
||||
|
||||
这是段限制。访问线性地址 0xffffffff 以上将返回段违规异常。
|
||||
* `10cf9a00`
|
||||
|
||||
段的原始标志,QEMU 将在接下来的几个字段中解码这些对我们有用的标志。
|
||||
* `DPL=0`
|
||||
|
||||
段的权限级别。一旦代码以权限 0 运行,它将就能够加载这个段。
|
||||
* `CS32`
|
||||
|
||||
这是一个 32 位代码段。对于数据段(不要与 DS 寄存器混淆了),另外的值还包括 `DS`,而对于本地描述符表是 `LDT`。
|
||||
* `[-R-]`
|
||||
|
||||
这个段是只读的。
|
||||
|
||||
* `info mem`
|
||||
|
||||
(在实验 2 以后)显示映射的虚拟内存和权限。比如:
|
||||
|
||||
```
|
||||
ef7c0000-ef800000 00040000 urw
|
||||
efbf8000-efc00000 00008000 -rw
|
||||
```
|
||||
|
||||
这告诉我们从 0xef7c0000 到 0xef800000 的 0x00040000 字节的内存被映射为读取/写入/用户可访问,而映射在 0xefbf8000 到 0xefc00000 之间的内存权限是读取/写入,但是仅限于内核可访问。
|
||||
|
||||
* `info pg`
|
||||
|
||||
(在实验 2 以后)显示当前页表结构。它的输出类似于 `info mem`,但与页目录条目和页表条目是有区别的,并且为每个条目给了单独的权限。重复的 PTE 和整个页表被折叠为一个单行。例如:
|
||||
|
||||
```
|
||||
VPN range Entry Flags Physical page
|
||||
[00000-003ff] PDE[000] -------UWP
|
||||
[00200-00233] PTE[200-233] -------U-P 00380 0037e 0037d 0037c 0037b 0037a ..
|
||||
[00800-00bff] PDE[002] ----A--UWP
|
||||
[00800-00801] PTE[000-001] ----A--U-P 0034b 00349
|
||||
[00802-00802] PTE[002] -------U-P 00348
|
||||
```
|
||||
|
||||
这里各自显示了两个页目录条目、虚拟地址范围 0x00000000 到 0x003fffff 以及 0x00800000 到 0x00bfffff。 所有的 PDE 都存在于内存中、可写入、并且用户可访问,而第二个 PDE 也是可访问的。这些页表中的第二个映射了三个页、虚拟地址范围 0x00800000 到 0x00802fff,其中前两个页是存在于内存中的、可写入、并且用户可访问的,而第三个仅存在于内存中,并且用户可访问。这些 PTE 的第一个条目映射在物理页 0x34b 处。
|
||||
|
||||
QEMU 也有一些非常有用的命令行参数,使用 `QEMUEXTRA` 变量可以将参数传递给 JOS 的 makefile。
|
||||
|
||||
* `make QEMUEXTRA='-d int' ...`
|
||||
|
||||
记录所有的中断和一个完整的寄存器转储到 `qemu.log` 文件中。你可以忽略前两个日志条目、“SMM: enter” 和 “SMM: after RMS”,因为这些是在进入引导加载器之前生成的。在这之后的日志条目看起来像下面这样:
|
||||
|
||||
```
|
||||
4: v=30 e=0000 i=1 cpl=3 IP=001b:00800e2e pc=00800e2e SP=0023:eebfdf28 EAX=00000005
|
||||
EAX=00000005 EBX=00001002 ECX=00200000 EDX=00000000
|
||||
ESI=00000805 EDI=00200000 EBP=eebfdf60 ESP=eebfdf28
|
||||
...
|
||||
```
|
||||
|
||||
第一行描述了中断。`4:` 只是一个日志记录计数器。`v` 提供了十六进程的向量号。`e` 提供了错误代码。`i=1` 表示它是由一个 `int` 指令(相对一个硬件产生的中断而言)产生的。剩下的行的意思很明显。对于一个寄存器转储而言,接下来看到的就是寄存器信息。
|
||||
|
||||
注意:如果你运行的是一个 0.15 版本之前的 QEMU,日志将写入到 `/tmp` 目录,而不是当前目录下。
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://pdos.csail.mit.edu/6.828/2018/labguide.html
|
||||
|
||||
作者:[csail.mit][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://pdos.csail.mit.edu
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: http://sourceware.org/gdb/current/onlinedocs/gdb/
|
||||
[2]: http://wiki.qemu.org/download/qemu-doc.html#pcsys_005fmonitor
|
@ -1,86 +1,76 @@
|
||||
6.828 中使用的工具
|
||||
Caffeinated 6.828:使用的工具
|
||||
======
|
||||
### 6.828 中使用的工具
|
||||
|
||||
在这个课程中你将使用两套工具:一个是 x86 模拟器 QEMU,它用来运行你的内核;另一个是编译器工具链,包括汇编器、链接器、C 编译器、以及调试器,它们用来编译和测试你的内核。本文有你需要去下载和安装你自己的副本相关信息。本课程假定你熟悉所有出现的 Unix 命令的用法。
|
||||
在这个课程中你将使用两套工具:一个是 x86 模拟器 QEMU,它用来运行你的内核;另一个是编译器工具链,包括汇编器、链接器、C 编译器,以及调试器,它们用来编译和测试你的内核。本文有你需要去下载和安装你自己的副本相关信息。本课程假定你熟悉所有出现的 Unix 命令的用法。
|
||||
|
||||
我们强烈推荐你使用一个 Debathena 机器,比如 athena.dialup.mit.edu,去做你的实验。如果你使用 MIT 的运行在 Linux 上的 Athena 机器,那么本课程所需要的所有软件工具都在 6.828 的存储中:只需要输入 'add -f 6.828' 就可以访问它们。
|
||||
我们强烈推荐你使用一个 Debathena 机器去做你的实验,比如 athena.dialup.mit.edu。如果你使用运行在 Linux 上的 MIT Athena 机器,那么本课程所需要的所有软件工具都在 6.828 的存储中:只需要输入 `add -f 6.828` 就可以访问它们。
|
||||
|
||||
如果你不使用一个 Debathena 机器,我们建议你使用一台 Linux 虚拟机。如果是这样,你可以在你的 Linux 虚拟机上构建和安装工具。我们将在下面介绍如何在 Linux 和 MacOS 计算上来构建和安装工具。
|
||||
如果你不使用 Debathena 机器,我们建议你使用一台 Linux 虚拟机。如果是这样,你可以在你的 Linux 虚拟机上构建和安装工具。我们将在下面介绍如何在 Linux 和 MacOS 计算上来构建和安装工具。
|
||||
|
||||
在 [Cygwin][1] 的帮助下,在窗口中运行这个开发环境也是可行的。安装 cygwin,并确保安装了 flex 和 bison 包(它们在开发头下面)。
|
||||
在 [Cygwin][1] 的帮助下,在 Windows 中运行这个开发环境也是可行的。安装 cygwin,并确保安装了 flex 和 bison 包(它们在开发 header 软件包分类下面)。
|
||||
|
||||
对于 6.828 中使用的工具中的有用的命令,请参考[实验工具指南][2]。
|
||||
|
||||
#### 编译器工具链
|
||||
### 编译器工具链
|
||||
|
||||
一个 “编译器工具链“ 是一套程序,包括一个 C 编译器、汇编器、和链接器,使用它们来将代码转换成可运行的二进制文件。你需要一个能够生成在 32 位 Intel 架构(x86 架构)上运行的 ELF 二进制格式程序的编译器工具链。
|
||||
“编译器工具链“ 是一套程序,包括一个 C 编译器、汇编器和链接器,使用它们来将代码转换成可运行的二进制文件。你需要一个能够生成在 32 位 Intel 架构(x86 架构)上运行的 ELF 二进制格式程序的编译器工具链。
|
||||
|
||||
##### 测试你的编译器工具链
|
||||
#### 测试你的编译器工具链
|
||||
|
||||
现代的 Linux 和 BSD UNIX 发行版已经为 6.828 提供了一个合适的工具链。去测试你的发行版,可以输入如下的命令:
|
||||
|
||||
```
|
||||
% objdump -i
|
||||
|
||||
```
|
||||
|
||||
第二行应该是 `elf32-i386`。
|
||||
|
||||
```
|
||||
% gcc -m32 -print-libgcc-file-name
|
||||
|
||||
```
|
||||
|
||||
这个命令应该会输出如 `/usr/lib/gcc/i486-linux-gnu/version/libgcc.a` 或 `/usr/lib/gcc/x86_64-linux-gnu/version/32/libgcc.a` 这样的东西。
|
||||
|
||||
如果这些命令都运行成功,说明你的工具链都已安装,你不需要去编译你自己的工具链。
|
||||
|
||||
如果 gcc 命令失败,你可能需要去安装一个开发环境。在 Ubuntu Linux 上,输入如下的命令:
|
||||
如果 `gcc` 命令失败,你可能需要去安装一个开发环境。在 Ubuntu Linux 上,输入如下的命令:
|
||||
|
||||
```
|
||||
% sudo apt-get install -y build-essential gdb
|
||||
|
||||
```
|
||||
|
||||
在 64 位的机器上,你可能需要去安装一个 32 位的支持库。链接失败的表现是有一个类似于 "`__udivdi3` not found" 和 "`__muldi3` not found” 的错误信息。在 Ubuntu Linux 上,输入如下的命令去尝试修复这个问题:
|
||||
在 64 位的机器上,你可能需要去安装一个 32 位的支持库。链接失败的表现是有一个类似于 “`__udivdi3` not found” 和 “`__muldi3` not found” 的错误信息。在 Ubuntu Linux 上,输入如下的命令去尝试修复这个问题:
|
||||
|
||||
```
|
||||
% sudo apt-get install gcc-multilib
|
||||
|
||||
```
|
||||
|
||||
##### 使用一个虚拟机
|
||||
#### 使用一个虚拟机
|
||||
|
||||
获得一个兼容的工具链的最容易的另外的方法是,在你的计算机上安装一个现代的 Linux 发行版。使用虚拟化平台,Linux 可以与你正常的计算环境和平共处。安装一个 Linux 虚拟机共有两步。首先,去下载一个虚拟化平台。
|
||||
|
||||
* [**VirtualBox**][3](对 Mac、Linux、Windows 免费)— [下载地址][3]
|
||||
* [VirtualBox][3](对 Mac、Linux、Windows 免费)— [下载地址][3]
|
||||
* [VMware Player][4](对 Linux 和 Windows 免费,但要求注册)
|
||||
* [VMware Fusion][5](可以从 IS&T 免费下载)。
|
||||
|
||||
|
||||
|
||||
VirtualBox 有点慢并且灵活性欠佳,但它免费!
|
||||
|
||||
虚拟化平台安装完成后,下载一个你选择的 Linux 发行版的引导磁盘镜像。
|
||||
|
||||
* 我们使用的是 [Ubuntu 桌面版][6]。
|
||||
|
||||
|
||||
|
||||
这将下载一个命名类似于 `ubuntu-10.04.1-desktop-i386.iso` 的文件。启动你的虚拟化平台并创建一个新(32 位)的虚拟机。使用下载的 Ubuntu 镜像作为一个引导磁盘;安装过程在不同的虚拟机上有所不同,但都很简单。就像上面一样输入 `objdump -i`,去验证你的工具是否已安装。你将在虚拟机中完成你的工作。
|
||||
|
||||
##### 构建你自己的编译器工具链
|
||||
#### 构建你自己的编译器工具链
|
||||
|
||||
在设置上你将花一些时间,但是比起一个虚拟机来说,它的性能要稍好一些,并且让你工作在你熟悉的环境中(Unix/MacOS)。对于 MacOS 命令,你可以快进到文章的末尾部分去看。
|
||||
你需要花一些时间来设置,但是比起一个虚拟机来说,它的性能要稍好一些,并且让你工作在你熟悉的环境中(Unix/MacOS)。对于 MacOS 命令,你可以快进到文章的末尾部分去看。
|
||||
|
||||
###### Linux
|
||||
##### Linux
|
||||
|
||||
通过将下列行添加到 `conf/env.mk` 中去使用你自己的工具链:
|
||||
|
||||
```
|
||||
GCCPREFIX=
|
||||
|
||||
```
|
||||
|
||||
我们假设你将工具链安装到了 `/usr/local` 中。你将需要大量的空间(大约 1 GB)去编译工具。如果你空间不足,在它的 `make install` 步骤之后删除它们的目录。
|
||||
@ -94,7 +84,7 @@ GCCPREFIX=
|
||||
+ http://ftpmirror.gnu.org/gcc/gcc-4.6.4/gcc-core-4.6.4.tar.bz2
|
||||
+ http://ftpmirror.gnu.org/gdb/gdb-7.3.1.tar.bz2
|
||||
|
||||
(你可能也在使用这些包的最新版本。)解包并构建。绿色粗体文本显示如何安装到 `/usr/local` 中,它是我们建议的。要安装到不同的目录,$PFX,注意高亮输入处的不同。如果有问题,可以看下面。
|
||||
(你可能也在使用这些包的最新版本。)解包并构建。安装到 `/usr/local` 中,它是我们建议的。要安装到不同的目录,如 `$PFX`,注意相应修改。如果有问题,可以看下面。
|
||||
|
||||
```c
|
||||
export PATH=$PFX/bin:$PATH
|
||||
@ -166,39 +156,40 @@ cd gdb-7.3.1
|
||||
make all
|
||||
make install # This step may require privilege (sudo make install)
|
||||
cd ..
|
||||
|
||||
```
|
||||
|
||||
###### Linux 排错
|
||||
**Linux 排错:**
|
||||
|
||||
Q:我不能运行 `make install`,因为我在这台机器上没有 root 权限。
|
||||
|
||||
A:我们的指令假定你是安装到了 `/usr/local` 目录中。但是,在你的环境中可能并不是这样做的。如果你仅能够在你的家目录中安装代码。那么在上面的命令中,使用 `--prefix=$HOME` 去替换 `--prefix=/usr/local`。你也需要修改你的 `PATH` 和 `LD_LIBRARY_PATH` 环境变量,以通知你的 shell 这个工具的位置。例如:
|
||||
|
||||
* Q:我不能运行 `make install`,因为我在这台机器上没有 root 权限。
|
||||
A:我们的指令假定你是安装到了 `/usr/local` 目录中。但是,在你的环境中可能并不是这样做的。如果你仅能够在你的 home 目录中安装代码。那么在上面的命令中,使用 `--prefix=$HOME`(并[点击这里][7] 去更新后面的命令)去替换 `--prefix=/usr/local`。你也需要修改你的 `PATH` 和 `LD_LIBRARY_PATH` 环境变量,以通知你的 shell 这个工具的位置。例如:
|
||||
```
|
||||
export PATH=$HOME/bin:$PATH
|
||||
export LD_LIBRARY_PATH=$HOME/lib:$LD_LIBRARY_PATH
|
||||
export PATH=$HOME/bin:$PATH
|
||||
export LD_LIBRARY_PATH=$HOME/lib:$LD_LIBRARY_PATH
|
||||
```
|
||||
|
||||
在你的 `~/.bashrc` 文件中输入这些行,以便于你登入后不需要每次都输入它们。
|
||||
|
||||
Q:我构建失败了,错误信息是 “library not found”。
|
||||
|
||||
|
||||
* Q:我构建失败了,错误信息是 "library not found”。
|
||||
A:你需要去设置你的 `LD_LIBRARY_PATH`。环境变量必须包含 `PREFIX/lib` 目录(例如 `/usr/local/lib`)。
|
||||
|
||||
##### MacOS
|
||||
|
||||
|
||||
#### MacOS
|
||||
|
||||
首先从 Mac OSX 上安装开发工具开始:
|
||||
`xcode-select --install`
|
||||
首先从 Mac OSX 上安装开发工具开始:`xcode-select --install` 。
|
||||
|
||||
你可以从 homebrew 上安装 qemu 的依赖,但是不能去安装 qemu,因为我们需要安装打了 6.828 补丁的 qemu。
|
||||
|
||||
`brew install $(brew deps qemu)`
|
||||
```
|
||||
brew install $(brew deps qemu)
|
||||
```
|
||||
|
||||
gettext 工具并不能把已安装的二进制文件添加到路径中,因此你需要去运行:
|
||||
gettext 工具并不能把它已安装的二进制文件添加到路径中,因此你需要去运行:
|
||||
|
||||
`PATH=${PATH}:/usr/local/opt/gettext/bin make install`
|
||||
```
|
||||
PATH=${PATH}:/usr/local/opt/gettext/bin make install
|
||||
```
|
||||
|
||||
完成后,开始安装 qemu。
|
||||
|
||||
@ -208,13 +199,12 @@ gettext 工具并不能把已安装的二进制文件添加到路径中,因此
|
||||
|
||||
不幸的是,QEMU 的调试功能虽然很强大,但是有点不成熟,因此我们强烈建议你使用我们打过 6.828 补丁的版本,而不是发行版自带的版本。这个安装在 Athena 上的 QEMU 版本已经打过补丁了。构建你自己的、打 6.828 补丁的 QEMU 版本的过程如下:
|
||||
|
||||
1. 克隆 IAP 6.828 QEMU 的 git 仓库:`git clone https://github.com/mit-pdos/6.828-qemu.git qemu`。
|
||||
2. 在 Linux 上,你或许需要安装几个库。我们成功地在 Debian/Ubuntu 16.04 上构建 6.828 版的 QEMU 需要安装下列的库:libsdl1.2-dev、libtool-bin、libglib2.0-dev、libz-dev、和 libpixman-1-dev。
|
||||
3. 配置源代码(方括号中是可选参考;用你自己的真实路径替换 PFX)
|
||||
1. 克隆 IAP 6.828 QEMU 的 git 仓库:`git clone https://github.com/mit-pdos/6.828-qemu.git qemu`。
|
||||
2. 在 Linux 上,你或许需要安装几个库。我们成功地在 Debian/Ubuntu 16.04 上构建 6.828 版的 QEMU 需要安装下列的库:libsdl1.2-dev、libtool-bin、libglib2.0-dev、libz-dev 和 libpixman-1-dev。
|
||||
3. 配置源代码(方括号中是可选参数;用你自己的真实路径替换 `PFX`)
|
||||
1. Linux:`./configure --disable-kvm --disable-werror [--prefix=PFX] [--target-list="i386-softmmu x86_64-softmmu"]`。
|
||||
2. OS X:`./configure --disable-kvm --disable-werror --disable-sdl [--prefix=PFX] [--target-list="i386-softmmu x86_64-softmmu"]`。`prefix` 参数指定安装 QEMU 的位置;如果不指定,将缺省安装 QEMU 到 `/usr/local` 目录中。`target-list` 参数将简单地简化 QEMU 所支持的架构。
|
||||
4. 运行 `make && make install`。
|
||||
|
||||
4. 运行 `make && make install`。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
@ -224,7 +214,7 @@ via: https://pdos.csail.mit.edu/6.828/2018/tools.html
|
||||
作者:[csail.mit][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -0,0 +1,67 @@
|
||||
IssueHunt:一个新的开源软件打赏平台
|
||||
======
|
||||
|
||||
![IssueHunt][4]
|
||||
|
||||
许多开源开发者和公司都在努力解决的问题之一就是资金问题。社区中有一种假想,甚至是期望,必须免费提供自由开源软件(FOSS)。但即使是 FOSS 也需要资金来继续开发。如果我们不建立让软件持续开发的系统,我们怎能期待更高质量的软件?
|
||||
|
||||
我们已经写了一篇关于[开源资金平台][1]的文章来试图解决这个缺点,截至今年 7 月,市场上出现了一个新的竞争者,旨在帮助填补这个空白:[IssueHunt][2]。
|
||||
|
||||
### IssueHunt: 开源软件打赏平台
|
||||
|
||||
![IssueHunt website][3]
|
||||
|
||||
IssueHunt 提供了一种服务,对自由开发者的开源代码贡献进行支付。它通过所谓的赏金来实现:给予解决特定问题的任何人财务奖励。这些奖励的资金来自任何愿意捐赠以修复任何特定 bug 或添加功能的人。
|
||||
|
||||
如果你想修复的某个开源软件存在问题,你可以根据自己选择的方式提供奖励金额。
|
||||
|
||||
想要自己的产品被争抢解决么?在 IssueHunt 上向任何解决问题的人提供奖金就好了。就这么简单。
|
||||
|
||||
如果你是程序员,则可以浏览未解决的问题。解决这个问题(如果你可以的话),在 GitHub 存储库上提交拉取请求,如果你的拉取请求被合并,那么你就会得到了钱。
|
||||
|
||||
#### IssueHunt 最初是 Boostnote 的内部项目
|
||||
|
||||
当笔记应用 [Boostnote][5] 背后的开发人员联系社区为他们的产品做出贡献时,该产品出现了。
|
||||
|
||||
在使用 IssueHunt 的前两年,Boostnote 通过数百名贡献者和压倒性的捐款收到了超过 8,400 个 Github star。
|
||||
|
||||
该产品非常成功,团队决定将其开放给社区的其他成员。
|
||||
|
||||
如今,[列表中在使用这个服务的项目][6]提供了数千美元的赏金。
|
||||
|
||||
Boostnote 号称有 [$2,800 的总赏金][7],而 Settings Sync,以前称为 Visual Studio Code Settings Sync,提供了[超过 $1,600 的赏金][8]。
|
||||
|
||||
还有其他服务提供类似于 IssueHunt 在此提供的内容。也许最引人注目的是 [Bountysource][9],它提供与 IssueHunt 类似的赏金服务,同时还提供类似于 [Librepay][10] 的订阅支付处理。
|
||||
|
||||
#### 你怎么看待 IssueHunt?
|
||||
|
||||
在撰写本文时,IssueHunt 还处于起步阶段,但我非常高兴看到这个项目在这些年里的成果。
|
||||
|
||||
我不知道你会怎么看,但我非常乐意为 FOSS 付款。如果产品质量高,并为我的生活增添价值,那么我很乐意向开发者支付产品费用。特别是 FOSS 的开发者正在创造尊重我自由的产品。
|
||||
|
||||
话虽如此,我一定会关注 IssueHunt 的继续前进,我可以用自己的钱或者在需要贡献的地方传播这个它来支持社区。
|
||||
|
||||
但你怎么看?你是否同意我的看法,或者你认为软件应该免费提供,并且应该在志愿者的基础上做出贡献?请在下面的评论中告诉我们你的想法。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/issuehunt/
|
||||
|
||||
作者:[Phillip Prado][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/phillip/
|
||||
[1]: https://itsfoss.com/open-source-funding-platforms/
|
||||
[2]: https://issuehunt.io
|
||||
[3]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/09/issuehunt-website.png?w=799&ssl=1
|
||||
[4]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2018/09/issuehunt.jpg?w=800&ssl=1
|
||||
[5]: https://itsfoss.com/boostnote-linux-review/
|
||||
[6]: https://issuehunt.io/repos
|
||||
[7]: https://issuehunt.io/repos/53266139
|
||||
[8]: https://issuehunt.io/repos/47984369
|
||||
[9]: https://www.bountysource.com/
|
||||
[10]: https://liberapay.com/
|
@ -1,17 +1,17 @@
|
||||
将 Grails 与 jQuery 和 DataTables 一起使用
|
||||
在 Grails 中使用 jQuery 和 DataTables
|
||||
======
|
||||
|
||||
本文介绍如何构建一个基于 Grails 的数据浏览器来可视化复杂的表格数据。
|
||||
> 本文介绍如何构建一个基于 Grails 的数据浏览器来可视化复杂的表格数据。
|
||||
|
||||

|
||||
|
||||
我是 [Grails][1] 的忠实粉丝。当然,我主要是热衷于利用命令行工具来探索和分析数据的数据人。数据人经常需要_查看_数据,这也意味着他们通常拥有优秀的数据浏览器。利用 Grails,[jQuery][2],以及 [DataTables jQuery 插件][3],我们可以制作出非常友好的表格数据浏览器。
|
||||
我是 [Grails][1] 的忠实粉丝。当然,我主要是热衷于利用命令行工具来探索和分析数据的数据从业人员。数据从业人员经常需要*查看*数据,这也意味着他们通常拥有优秀的数据浏览器。利用 Grails、[jQuery][2],以及 [DataTables jQuery 插件][3],我们可以制作出非常友好的表格数据浏览器。
|
||||
|
||||
[DataTables 网站][3]提供了许多“食谱风格”的教程文档,展示了如何组合一些优秀的示例应用程序,这些程序包含了完成一些非常漂亮的东西所必要的 JavaScript,HTML,以及偶尔出现的 [PHP][4]。但对于那些宁愿使用 Grails 作为后端的人来说,有必要进行一些说明示教。此外,样本程序中使用的数据是虚构公司的员工的单个平面表数据,因此处理这些复杂的表关系可以作为读者的一个练习项目。
|
||||
[DataTables 网站][3]提供了许多“食谱式”的教程文档,展示了如何组合一些优秀的示例应用程序,这些程序包含了完成一些非常漂亮的东西所必要的 JavaScript、HTML,以及偶尔出现的 [PHP][4]。但对于那些宁愿使用 Grails 作为后端的人来说,有必要进行一些说明示教。此外,样本程序中使用的数据是一个虚构公司的员工的单个平面表格数据,因此处理这些复杂的表关系可以作为读者的一个练习项目。
|
||||
|
||||
本文中,我们将创建具有略微复杂的数据结构和 DataTables 浏览器的 Grails 应用程序。我们将介绍 Grails 标准 [Groovy][5]-fied Java Hibernate 标准。我已将代码托管在 [GitHub][6] 上方便大家访问,因此本文主要是对代码细节的解读。
|
||||
本文中,我们将创建具有略微复杂的数据结构和 DataTables 浏览器的 Grails 应用程序。我们将介绍 Grails 标准,它是 [Groovy][5] 式的 Java Hibernate 标准。我已将代码托管在 [GitHub][6] 上方便大家访问,因此本文主要是对代码细节的解读。
|
||||
|
||||
首先,你需要配置 Java,Groovy,Grails 的使用环境。对于 Grails,我倾向于使用终端窗口和 [Vim][7],本文也使用它们。为获得现代 Java,建议下载并安装 Linux 发行版提供的 [Open Java Development Kit][8] (OpenJDK)(应该是 Java 8,9,10或11,撰写本文时,我正在使用 Java 8)。从我的角度来看,获取最新的 Groovy 和 Grails 的最佳方法是使用 [SKDMAN!][9]。
|
||||
首先,你需要配置 Java、Groovy、Grails 的使用环境。对于 Grails,我倾向于使用终端窗口和 [Vim][7],本文也使用它们。为获得现代的 Java 环境,建议下载并安装 Linux 发行版提供的 [Open Java Development Kit][8] (OpenJDK)(应该是 Java 8、9、10 或 11 之一,撰写本文时,我正在使用 Java 8)。从我的角度来看,获取最新的 Groovy 和 Grails 的最佳方法是使用 [SDKMAN!][9]。
|
||||
|
||||
从未尝试过 Grails 的读者可能需要做一些背景资料阅读。作为初学者,推荐文章 [创建你的第一个 Grails 应用程序][10]。
|
||||
|
||||
@ -34,7 +34,7 @@ grails create-domain-class com.nuevaconsulting.embrow.Employeecd embrowgrails cr
|
||||
|
||||
这种方式构建的域类没有属性,因此必须按如下方式编辑它们:
|
||||
|
||||
Position 域类:
|
||||
`Position` 域类:
|
||||
|
||||
```
|
||||
package com.nuevaconsulting.embrow
|
||||
@ -51,7 +51,7 @@ class Position {
|
||||
}com.Stringint startingstatic constraintsnullableblankstarting nullable
|
||||
```
|
||||
|
||||
Office 域类:
|
||||
`Office` 域类:
|
||||
|
||||
```
|
||||
package com.nuevaconsulting.embrow
|
||||
@ -72,7 +72,7 @@ class Office {
|
||||
}
|
||||
```
|
||||
|
||||
Enployee 域类:
|
||||
`Enployee` 域类:
|
||||
|
||||
```
|
||||
package com.nuevaconsulting.embrow
|
||||
@ -98,7 +98,7 @@ class Employee {
|
||||
}
|
||||
```
|
||||
|
||||
请注意,虽然 Position 和 Office 域类使用了预定义的 Groovy 类型 String 以及 int,但 Employee 域类定义了 Position 和 Office 字段(以及预定义的 Date)。这会导致创建数据库表,其中存储的 Employee 实例中包含了指向存储 Position 和 Office 实例表的引用或者外键。
|
||||
请注意,虽然 `Position` 和 `Office` 域类使用了预定义的 Groovy 类型 `String` 以及 `int`,但 `Employee` 域类定义了 `Position` 和 `Office` 字段(以及预定义的 `Date`)。这会导致创建数据库表,其中存储的 `Employee` 实例中包含了指向存储 `Position` 和 `Office` 实例表的引用或者外键。
|
||||
|
||||
现在你可以生成控制器,视图,以及其他各种测试组件:
|
||||
|
||||
@ -108,7 +108,7 @@ grails generate-all com.nuevaconsulting.embrow.Office
|
||||
grails generate-all com.nuevaconsulting.embrow.Employeegrails generateall com.grails generateall com.grails generateall com.
|
||||
```
|
||||
|
||||
此时,你已经准备好基本的 create-read-update-delete(CRUD)应用程序。我在**grails-app/init/com/nuevaconsulting/BootStrap.groovy**中包含了一些基础数据来填充表格。
|
||||
此时,你已经准备好了一个基本的增删改查(CRUD)应用程序。我在 `grails-app/init/com/nuevaconsulting/BootStrap.groovy` 中包含了一些基础数据来填充表格。
|
||||
|
||||
如果你用如下命令来启动应用程序:
|
||||
|
||||
@ -116,43 +116,44 @@ grails generate-all com.nuevaconsulting.embrow.Employeegrails generateall com.gr
|
||||
grails run-app
|
||||
```
|
||||
|
||||
在浏览器输入**<http://localhost:8080/:>**,你将会看到如下界面:
|
||||
在浏览器输入 `http://localhost:8080/`,你将会看到如下界面:
|
||||
|
||||
![Embrow home screen][12]
|
||||
|
||||
Embrow 应用程序主界面。
|
||||
*Embrow 应用程序主界面。*
|
||||
|
||||
单击 OfficeController,会跳转到如下界面:
|
||||
单击 “OfficeController” 链接,会跳转到如下界面:
|
||||
|
||||
![Office list][14]
|
||||
|
||||
Office 列表
|
||||
*Office 列表*
|
||||
|
||||
注意,此表由 **OfficeController index** 生成,并由视图 `office/index.gsp` 显示。
|
||||
注意,此表由 `OfficeController` 的 `index` 方式生成,并由视图 `office/index.gsp` 显示。
|
||||
|
||||
同样,单击 **EmployeeController** 跳转到如下界面:
|
||||
同样,单击 “EmployeeController” 链接 跳转到如下界面:
|
||||
|
||||
![Employee controller][16]
|
||||
|
||||
employee controller
|
||||
*employee 控制器*
|
||||
|
||||
好吧,这很丑陋: Position 和 Office 链接是什么?
|
||||
|
||||
上面的命令 `generate-all` 生成的视图创建了一个叫 **index.gsp** 的文件,它使用 Grails <f:table/> 标签,该标签默认会显示类名(**com.nuevaconsulting.embrow.Position**)和持久化示例标识符(**30**)。这个操作可以自定义用来产生更好看的东西,并且自动生成链接,自动生成分页以及自动生成可拍序列的一些非常简洁直观的东西。
|
||||
上面的命令 `generate-all` 生成的视图创建了一个叫 `index.gsp` 的文件,它使用 Grails `<f:table/>` 标签,该标签默认会显示类名(`com.nuevaconsulting.embrow.Position`)和持久化示例标识符(`30`)。这个操作可以自定义用来产生更好看的东西,并且自动生成链接,自动生成分页以及自动生成可排序列的一些非常简洁直观的东西。
|
||||
|
||||
但该员工信息浏览器功能也是有限的。例如,如果想查找 position 信息中包含 “dev” 的员工该怎么办?如果要组合排序,以姓氏为主排序关键字,office 为辅助排序关键字,该怎么办?或者,你需要将已排序的数据导出到电子表格或 PDF 文档以便通过电子邮件发送给无法访问浏览器的人,该怎么办?
|
||||
但该员工信息浏览器功能也是有限的。例如,如果想查找 “position” 信息中包含 “dev” 的员工该怎么办?如果要组合排序,以姓氏为主排序关键字,“office” 为辅助排序关键字,该怎么办?或者,你需要将已排序的数据导出到电子表格或 PDF 文档以便通过电子邮件发送给无法访问浏览器的人,该怎么办?
|
||||
|
||||
jQuery DataTables 插件提供了这些所需的功能。允许你创建一个完成的表格数据浏览器。
|
||||
|
||||
### 创建员工信息浏览器视图和控制器的方法
|
||||
|
||||
要基于 jQuery DataTables 创建员工信息浏览器,你必须先完成以下两个任务:
|
||||
1. 创建 Grails 视图,其中包含启用 DataTable 所需的 HTML 和 JavaScript
|
||||
|
||||
1. 创建 Grails 视图,其中包含启用 DataTable 所需的 HTML 和 JavaScript
|
||||
2. 给 Grails 控制器增加一个方法来控制新视图。
|
||||
|
||||
#### 员工信息浏览器视图
|
||||
|
||||
在目录 **embrow/grails-app/views/employee** 中,首先复制 **index.gsp** 文件,重命名为 **browser.gsp**:
|
||||
在目录 `embrow/grails-app/views/employee` 中,首先复制 `index.gsp` 文件,重命名为 `browser.gsp`:
|
||||
|
||||
```
|
||||
cd Projects
|
||||
@ -160,7 +161,7 @@ cd embrow/grails-app/views/employee
|
||||
cp gsp browser.gsp
|
||||
```
|
||||
|
||||
此刻,你自定义新的 **browser.gsp** 文件来添加相关的 jQuery DataTables 代码。
|
||||
此刻,你自定义新的 `browser.gsp` 文件来添加相关的 jQuery DataTables 代码。
|
||||
|
||||
通常,在可能的时候,我喜欢从内容提供商处获得 JavaScript 和 CSS;在下面这行后面:
|
||||
|
||||
@ -185,7 +186,7 @@ cp gsp browser.gsp
|
||||
<script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/buttons/1.5.1/js/buttons.print.min.js "></script>
|
||||
```
|
||||
|
||||
然后删除 **index.gsp** 中提供数据分页的代码:
|
||||
然后删除 `index.gsp` 中提供数据分页的代码:
|
||||
|
||||
```
|
||||
<div id="list-employee" class="content scaffold-list" role="main">
|
||||
@ -253,7 +254,7 @@ $(this).html('<input type="text" size="15" placeholder="' + title + '?" />');
|
||||
});titletitletitletitletitle
|
||||
```
|
||||
|
||||
接下来,定义表模型。 这是提供所有表选项的地方,包括界面的滚动,而不是分页,根据 dom 字符串提供的装饰,将数据导出为 CSV 和其他格式的能力,以及建立与服务器的 Ajax 连接。 请注意,使用 Groovy GString 调用 Grails **createLink()** 的方法创建 URL,在 **EmployeeController** 中指向 **browserLister** 操作。同样有趣的是表格列的定义。此信息将发送到后端,后端查询数据库并返回相应的记录。
|
||||
接下来,定义表模型。这是提供所有表选项的地方,包括界面的滚动,而不是分页,根据 DOM 字符串提供的装饰,将数据导出为 CSV 和其他格式的能力,以及建立与服务器的 AJAX 连接。 请注意,使用 Groovy GString 调用 Grails `createLink()` 的方法创建 URL,在 `EmployeeController` 中指向 `browserLister` 操作。同样有趣的是表格列的定义。此信息将发送到后端,后端查询数据库并返回相应的记录。
|
||||
|
||||
```
|
||||
var table = $('#employee_dt').DataTable( {
|
||||
@ -302,7 +303,7 @@ that.search(this.value).draw();
|
||||
|
||||

|
||||
|
||||
这是另一个屏幕截图,显示了过滤和多列排序(寻找 position 包括字符 “dev” 的员工,先按 office 排序,然后按姓氏排序):
|
||||
这是另一个屏幕截图,显示了过滤和多列排序(寻找 “position” 包括字符 “dev” 的员工,先按 “office” 排序,然后按姓氏排序):
|
||||
|
||||

|
||||
|
||||
@ -314,37 +315,37 @@ that.search(this.value).draw();
|
||||
|
||||

|
||||
|
||||
好的,视图部分看起来非常简单; 因此,控制器必须做所有繁重的工作,对吧? 让我们来看看…
|
||||
好的,视图部分看起来非常简单;因此,控制器必须做所有繁重的工作,对吧? 让我们来看看……
|
||||
|
||||
#### 控制器 browserLister 操作
|
||||
|
||||
回想一下,我们看到过这个字符串
|
||||
回想一下,我们看到过这个字符串:
|
||||
|
||||
```
|
||||
"${createLink(controller: 'employee', action: 'browserLister')}"
|
||||
```
|
||||
|
||||
对于从 DataTables 模型中调用 Ajax 的 URL,是在 Grails 服务器上动态创建 HTML 链接,其 Grails 标记背后通过调用 [createLink()][17] 的方法实现的。这会最终产生一个指向 **EmployeeController** 的链接,位于:
|
||||
对于从 DataTables 模型中调用 AJAX 的 URL,是在 Grails 服务器上动态创建 HTML 链接,其 Grails 标记背后通过调用 [createLink()][17] 的方法实现的。这会最终产生一个指向 `EmployeeController` 的链接,位于:
|
||||
|
||||
```
|
||||
embrow/grails-app/controllers/com/nuevaconsulting/embrow/EmployeeController.groovy
|
||||
```
|
||||
|
||||
特别是控制器方法 **browserLister()**。我在代码中留了一些 print 语句,以便在运行时能够在终端看到中间结果。
|
||||
特别是控制器方法 `browserLister()`。我在代码中留了一些 `print` 语句,以便在运行时能够在终端看到中间结果。
|
||||
|
||||
```
|
||||
def browserLister() {
|
||||
// Applies filters and sorting to return a list of desired employees
|
||||
```
|
||||
|
||||
首先,打印出传递给 **browserLister()** 的参数。我通常使用此代码开始构建控制器方法,以便我完全清楚我的控制器正在接收什么。
|
||||
首先,打印出传递给 `browserLister()` 的参数。我通常使用此代码开始构建控制器方法,以便我完全清楚我的控制器正在接收什么。
|
||||
|
||||
```
|
||||
println "employee browserLister params $params"
|
||||
println()
|
||||
```
|
||||
|
||||
接下来,处理这些参数以使它们更加有用。首先,jQuery DataTables 参数,一个名为 **jqdtParams**的 Groovy 映射:
|
||||
接下来,处理这些参数以使它们更加有用。首先,jQuery DataTables 参数,一个名为 `jqdtParams` 的 Groovy 映射:
|
||||
|
||||
```
|
||||
def jqdtParams = [:]
|
||||
@ -363,7 +364,7 @@ println "employee dataTableParams $jqdtParams"
|
||||
println()
|
||||
```
|
||||
|
||||
接下来,列数据,一个名为 **columnMap**的 Groovy 映射:
|
||||
接下来,列数据,一个名为 `columnMap` 的 Groovy 映射:
|
||||
|
||||
```
|
||||
def columnMap = jqdtParams.columns.collectEntries { k, v ->
|
||||
@ -386,7 +387,7 @@ println "employee columnMap $columnMap"
|
||||
println()
|
||||
```
|
||||
|
||||
接下来,从 **columnMap** 中检索的所有列表,以及在视图中应如何排序这些列表,Groovy 列表分别称为 **allColumnList**和 **orderList**:
|
||||
接下来,从 `columnMap` 中检索的所有列表,以及在视图中应如何排序这些列表,Groovy 列表分别称为 `allColumnList` 和 `orderList` :
|
||||
|
||||
```
|
||||
def allColumnList = columnMap.keySet() as List
|
||||
@ -395,7 +396,7 @@ def orderList = jqdtParams.order.collect { k, v -> [allColumnList[v.column as In
|
||||
println "employee orderList $orderList"
|
||||
```
|
||||
|
||||
我们将使用 Grails 的 Hibernate 标准实现来实际选择要显示的元素以及它们的排序和分页。标准要求过滤器关闭; 在大多数示例中,这是作为标准实例本身的创建的一部分给出的,但是在这里我们预先定义过滤器闭包。请注意,在这种情况下,“date hired” 过滤器的相对复杂的解释被视为一年并应用于建立日期范围,并使用 **createAlias** 以允许我们进入相关类别 Position 和 Office:
|
||||
我们将使用 Grails 的 Hibernate 标准实现来实际选择要显示的元素以及它们的排序和分页。标准要求过滤器关闭;在大多数示例中,这是作为标准实例本身的创建的一部分给出的,但是在这里我们预先定义过滤器闭包。请注意,在这种情况下,“date hired” 过滤器的相对复杂的解释被视为一年并应用于建立日期范围,并使用 `createAlias` 以允许我们进入相关类别 `Position` 和 `Office`:
|
||||
|
||||
```
|
||||
def filterer = {
|
||||
@ -424,14 +425,14 @@ def filterer = {
|
||||
}
|
||||
```
|
||||
|
||||
是时候应用上述内容了。第一步是获取分页代码所需的所有 Employee 实例的总数:
|
||||
是时候应用上述内容了。第一步是获取分页代码所需的所有 `Employee` 实例的总数:
|
||||
|
||||
```
|
||||
def recordsTotal = Employee.count()
|
||||
println "employee recordsTotal $recordsTotal"
|
||||
```
|
||||
|
||||
接下来,将过滤器应用于 Employee 实例以获取过滤结果的计数,该结果将始终小于或等于总数(同样,这是针对分页代码):
|
||||
接下来,将过滤器应用于 `Employee` 实例以获取过滤结果的计数,该结果将始终小于或等于总数(同样,这是针对分页代码):
|
||||
|
||||
```
|
||||
def c = Employee.createCriteria()
|
||||
@ -467,7 +468,7 @@ def filterer = {
|
||||
|
||||
要完全清楚,JTable 中的分页代码管理三个计数:数据集中的记录总数,应用过滤器后得到的数字,以及要在页面上显示的数字(显示是滚动还是分页)。 排序应用于所有过滤的记录,并且分页应用于那些过滤的记录的块以用于显示目的。
|
||||
|
||||
接下来,处理命令返回的结果,在每行中创建指向 Employee,Position 和 Office 实例的链接,以便用户可以单击这些链接以获取相关实例的所有详细信息:
|
||||
接下来,处理命令返回的结果,在每行中创建指向 `Employee`、`Position` 和 `Office` 实例的链接,以便用户可以单击这些链接以获取相关实例的所有详细信息:
|
||||
|
||||
```
|
||||
def dollarFormatter = new DecimalFormat('$##,###.##')
|
||||
@ -490,14 +491,15 @@ def filterer = {
|
||||
}
|
||||
```
|
||||
|
||||
大功告成
|
||||
大功告成。
|
||||
|
||||
如果你熟悉 Grails,这可能看起来比你原先想象的要多,但这里没有火箭式的一步到位方法,只是很多分散的操作步骤。但是,如果你没有太多接触 Grails(或 Groovy),那么需要了解很多新东西 - 闭包,代理和构建器等等。
|
||||
|
||||
在那种情况下,从哪里开始? 最好的地方是了解 Groovy 本身,尤其是 [Groovy closures][18] 和 [Groovy delegates and builders][19]。然后再去阅读上面关于 Grails 和 Hibernate 条件查询的建议阅读文章。
|
||||
|
||||
### 结语
|
||||
|
||||
jQuery DataTables 为 Grails 制作了很棒的表格数据浏览器。对视图进行编码并不是太棘手,但DataTables 文档中提供的 PHP 示例提供的功能仅到此位置。特别是,它们不是用 Grails 程序员编写的,也不包含探索使用引用其他类(实质上是查找表)的元素的更精细的细节。
|
||||
jQuery DataTables 为 Grails 制作了很棒的表格数据浏览器。对视图进行编码并不是太棘手,但 DataTables 文档中提供的 PHP 示例提供的功能仅到此位置。特别是,它们不是用 Grails 程序员编写的,也不包含探索使用引用其他类(实质上是查找表)的元素的更精细的细节。
|
||||
|
||||
我使用这种方法制作了几个数据浏览器,允许用户选择要查看和累积记录计数的列,或者只是浏览数据。即使在相对适度的 VPS 上的百万行表中,性能也很好。
|
||||
|
||||
@ -512,7 +514,7 @@ via: https://opensource.com/article/18/9/using-grails-jquery-and-datatables
|
||||
作者:[Chris Hermansen][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[jrg](https://github.com/jrglinux)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
@ -528,11 +530,11 @@ via: https://opensource.com/article/18/9/using-grails-jquery-and-datatables
|
||||
[9]: http://sdkman.io/
|
||||
[10]: http://guides.grails.org/creating-your-first-grails-app/guide/index.html
|
||||
[11]: https://opensource.com/file/410061
|
||||
[12]: https://opensource.com/sites/default/files/uploads/screen_1.png "Embrow home screen"
|
||||
[12]: https://opensource.com/sites/default/files/uploads/screen_1.png
|
||||
[13]: https://opensource.com/file/410066
|
||||
[14]: https://opensource.com/sites/default/files/uploads/screen_2.png "Office list screenshot"
|
||||
[14]: https://opensource.com/sites/default/files/uploads/screen_2.png
|
||||
[15]: https://opensource.com/file/410071
|
||||
[16]: https://opensource.com/sites/default/files/uploads/screen3.png "Employee controller screenshot"
|
||||
[16]: https://opensource.com/sites/default/files/uploads/screen3.png
|
||||
[17]: https://gsp.grails.org/latest/ref/Tags/createLink.html
|
||||
[18]: http://groovy-lang.org/closures.html
|
||||
[19]: http://groovy-lang.org/dsls.html
|
@ -0,0 +1,98 @@
|
||||
容器技术对 DevOps 的一些启发
|
||||
======
|
||||
|
||||
> 容器技术的使用支撑了目前 DevOps 三大主要实践:工作流、及时反馈、持续学习。
|
||||
|
||||

|
||||
|
||||
有人说容器技术与 DevOps 二者在发展的过程中是互相促进的关系。得益于 DevOps 设计理念的流行,容器生态系统在设计上与组件选择上也有相应发展。同时,由于容器技术在生产环境中的使用,反过来也促进了 DevOps 三大主要实践:[支撑 DevOps 的三个实践][1]。
|
||||
|
||||
### 工作流
|
||||
|
||||
#### 容器中的工作流
|
||||
|
||||
每个容器都可以看成一个独立的运行环境,对于容器内部,不需要考虑外部的宿主环境、集群环境,以及其它基础设施。在容器内部,每个功能看起来都是以传统的方式运行。从外部来看,容器内运行的应用一般作为整个应用系统架构的一部分:比如 web API、web app 用户界面、数据库、任务执行、缓存系统、垃圾回收等。运维团队一般会限制容器的资源使用,并在此基础上建立完善的容器性能监控服务,从而降低其对基础设施或者下游其他用户的影响。
|
||||
|
||||
#### 现实中的工作流
|
||||
|
||||
那些跟“容器”一样业务功能独立的团队,也可以借鉴这种容器思维。因为无论是在现实生活中的工作流(代码发布、构建基础设施,甚至制造 [《杰森一家》中的斯贝斯利太空飞轮][2] 等),还是技术中的工作流(开发、测试、运维、发布)都使用了这样的线性工作流,一旦某个独立的环节或者工作团队出现了问题,那么整个下游都会受到影响,虽然使用这种线性的工作流有效降低了工作耦合性。
|
||||
|
||||
#### DevOps 中的工作流
|
||||
|
||||
DevOps 中的第一条原则,就是掌控整个执行链路的情况,努力理解系统如何协同工作,并理解其中出现的问题如何对整个过程产生影响。为了提高流程的效率,团队需要持续不断的找到系统中可能存在的性能浪费以及问题,并最终修复它们。
|
||||
|
||||
> 践行这样的工作流后,可以避免将一个已知缺陷带到工作流的下游,避免局部优化导致可能的全局性能下降,要不断探索如何优化工作流,持续加深对于系统的理解。
|
||||
|
||||
> —— Gene Kim,《[支撑 DevOps 的三个实践][3]》,IT 革命,2017.4.25
|
||||
|
||||
### 反馈
|
||||
|
||||
#### 容器中的反馈
|
||||
|
||||
除了限制容器的资源,很多产品还提供了监控和通知容器性能指标的功能,从而了解当容器工作不正常时,容器内部处于什么样的状态。比如目前[流行的][5] [Prometheus][4],可以用来收集容器和容器集群中相应的性能指标数据。容器本身特别适用于分隔应用系统,以及打包代码和其运行环境,但同时也带来了不透明的特性,这时,从中快速收集信息来解决其内部出现的问题就显得尤为重要了。
|
||||
|
||||
#### 现实中的反馈
|
||||
|
||||
在现实中,从始至终同样也需要反馈。一个高效的处理流程中,及时的反馈能够快速地定位事情发生的时间。反馈的关键词是“快速”和“相关”。当一个团队被淹没在大量不相关的事件时,那些真正需要快速反馈的重要信息很容易被忽视掉,并向下游传递形成更严重的问题。想象下[如果露西和埃塞尔][6]能够很快地意识到:传送带太快了,那么制作出的巧克力可能就没什么问题了(尽管这样就不那么搞笑了)。(LCTT 译注:露西和埃塞尔是上世纪 50 年代的著名黑白情景喜剧《我爱露西》中的主角)
|
||||
|
||||
#### DevOps 中的反馈
|
||||
|
||||
DevOps 中的第二条原则,就是快速收集所有相关的有用信息,这样在问题影响到其它开发流程之前就可以被识别出。DevOps 团队应该努力去“优化下游”,以及快速解决那些可能会影响到之后团队的问题。同工作流一样,反馈也是一个持续的过程,目标是快速的获得重要的信息以及当问题出现后能够及时地响应。
|
||||
|
||||
> 快速的反馈对于提高技术的质量、可用性、安全性至关重要。
|
||||
|
||||
> —— Gene Kim 等人,《DevOps 手册:如何在技术组织中创造世界级的敏捷性,可靠性和安全性》,IT 革命,2016
|
||||
|
||||
### 持续学习
|
||||
|
||||
#### 容器中的持续学习
|
||||
|
||||
践行第三条原则“持续学习”是一个不小的挑战。在不需要掌握太多边缘的或难以理解的东西的情况下,容器技术让我们的开发工程师和运营团队依然可以安全地进行本地和生产环境的测试,这在之前是难以做到的。即便是一些激进的实验,容器技术仍然让我们轻松地进行版本控制、记录和分享。
|
||||
|
||||
#### 现实中的持续学习
|
||||
|
||||
举个我自己的例子:多年前,作为一个年轻、初出茅庐的系统管理员(仅仅工作三周),我被安排对一个运行着某个大学核心 IT 部门网站的 Apache 虚拟主机配置进行更改。由于没有方便的测试环境,我直接在生产站点上修改配置,当时觉得配置没问题就发布了,几分钟后,我无意中听到了隔壁同事说:
|
||||
|
||||
“等会,网站挂了?”
|
||||
|
||||
“没错,怎么回事?”
|
||||
|
||||
很多人蒙圈了……
|
||||
|
||||
在被嘲讽之后(真实的嘲讽),我一头扎在工作台上,赶紧撤销我之前的更改。当天下午晚些时候,部门主管 —— 我老板的老板的老板 —— 来到我的工位询问发生了什么事。“别担心,”她告诉我。“我们不会责怪你,这是一个错误,现在你已经学会了。”
|
||||
|
||||
而在容器中,这种情形在我的笔记本上就很容易测试了,并且也很容易在部署生产环境之前,被那些经验老道的团队成员发现。
|
||||
|
||||
#### DevOps 中的持续学习
|
||||
|
||||
持续学习文化的一部分是我们每个人都希望通过一些改变从而能够提高一些东西,并勇敢地通过实验来验证我们的想法。对于 DevOps 团队来说,失败无论对团队还是个人来说都是成长而不是惩罚,所以不要畏惧失败。团队中的每个成员不断学习、共享,也会不断提升其所在团队与组织的水平。
|
||||
|
||||
随着系统越来越被细分,我们更需要将注意力集中在具体的点上:上面提到的两条原则主要关注整体流程,而持续学习关注的则是整个项目、人员、团队、组织的未来。它不仅对流程产生了影响,还对流程中的每个人产生影响。
|
||||
|
||||
> 实验和冒险让我们能够不懈地改进我们的工作,但也要求我们尝试之前未用过的工作方式。
|
||||
|
||||
> —— Gene Kim 等人,《[凤凰计划:让你了解 IT、DevOps 以及如何取得商业成功][7]》,IT 革命,2013
|
||||
|
||||
### 容器技术带给 DevOps 的启迪
|
||||
|
||||
有效地应用容器技术可以学习 DevOps 的三条原则:工作流,反馈以及持续学习。从整体上看应用程序和基础设施,而不是对容器外的东西置若罔闻,教会我们考虑到系统的所有部分,了解其上游和下游影响,打破隔阂,并作为一个团队工作,以提升整体表现和深度了解整个系统。通过努力提供及时准确的反馈,我们可以在组织内部创建有效的反馈机制,以便在问题发生影响之前发现问题。最后,提供一个安全的环境来尝试新的想法并从中学习,教会我们创造一种文化,在这种文化中,失败一方面促进了我们知识的增长,另一方面通过有根据的猜测,可以为复杂的问题带来新的、优雅的解决方案。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/9/containers-can-teach-us-devops
|
||||
|
||||
作者:[Chris Hermansen][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[littleji](https://github.com/littleji)
|
||||
校对:[pityonline](https://github.com/pityonline), [wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/clhermansen
|
||||
[1]: https://itrevolution.com/the-three-ways-principles-underpinning-devops/
|
||||
[2]: https://en.wikipedia.org/wiki/The_Jetsons
|
||||
[3]: http://itrevolution.com/the-three-ways-principles-underpinning-devops
|
||||
[4]: https://prometheus.io/
|
||||
[5]: https://opensource.com/article/18/9/prometheus-operational-advantage
|
||||
[6]: https://www.youtube.com/watch?v=8NPzLBSBzPI
|
||||
[7]: https://itrevolution.com/book/the-phoenix-project/
|
@ -0,0 +1,259 @@
|
||||
使用 Pandoc 将你的书转换成网页和电子书
|
||||
======
|
||||
|
||||
> 通过 Markdown 和 Pandoc,可以做到编写一次,发布两次。
|
||||
|
||||

|
||||
|
||||
Pandoc 是一个命令行工具,用于将文件从一种标记语言转换为另一种标记语言。在我 [对 Pandoc 的简介][1] 一文中,我演示了如何把 Markdown 编写的文本转换为网页、幻灯片和 PDF。
|
||||
|
||||
在这篇后续文章中,我将深入探讨 [Pandoc][2],展示如何从同一个 Markdown 源文件生成网页和 ePub 格式的电子书。我将使用我即将发布的电子书《[面向对象思想的 GRASP 原则][3]》为例进行讲解,这本电子书正是通过以下过程创建的。
|
||||
|
||||
首先,我将解释这本书使用的文件结构,然后介绍如何使用 Pandoc 生成网页并将其部署在 GitHub 上;最后,我演示了如何生成对应的 ePub 格式电子书。
|
||||
|
||||
你可以在我的 GitHub 仓库 [Programming Fight Club][4] 中找到相应代码。
|
||||
|
||||
### 设置图书结构
|
||||
|
||||
我用 Markdown 语法完成了所有的写作,你也可以使用 HTML 标记,但是当 Pandoc 将 Markdown 转换为 ePub 文档时,引入的 HTML 标记越多,出现问题的风险就越高。我的书按照每章一个文件的形式进行组织,用 Markdown 的 `H1` 标记(`#`)声明每章的标题。你也可以在每个文件中放置多个章节,但将它们放在单独的文件中可以更轻松地查找内容并在以后进行更新。
|
||||
|
||||
元信息遵循类似的模式,每种输出格式都有自己的元信息文件。元信息文件定义有关文档的信息,例如要添加到 HTML 中的文本或 ePub 的许可证。我将所有 Markdown 文档存储在名为 `parts` 的文件夹中(这对于用来生成网页和 ePub 的 Makefile 非常重要)。下面以一个例子进行说明,让我们看一下目录,前言和关于本书(分为 `toc.md`、`preface.md` 和 `about.md` 三个文件)这三部分,为清楚起见,我们将省略其余的章节。
|
||||
|
||||
关于本书这部分内容的开头部分类似:
|
||||
|
||||
```
|
||||
# About this book {-}
|
||||
|
||||
## Who should read this book {-}
|
||||
|
||||
Before creating a complex software system one needs to create a solid foundation.
|
||||
General Responsibility Assignment Software Principles (GRASP) are guidelines to assign
|
||||
responsibilities to software classes in object-oriented programming.
|
||||
```
|
||||
|
||||
每一章完成后,下一步就是添加元信息来设置网页和 ePub 的格式。
|
||||
|
||||
### 生成网页
|
||||
|
||||
#### 创建 HTML 元信息文件
|
||||
|
||||
我创建的网页的元信息文件(`web-metadata.yaml`)是一个简单的 YAML 文件,其中包含 `<head> ` 标签中的作者、标题、和版权等信息,以及 HTML 文件中开头和结尾的内容。
|
||||
|
||||
我建议(至少)包括 `web-metadata.yaml` 文件中的以下字段:
|
||||
|
||||
```
|
||||
---
|
||||
title: <a href="/grasp-principles/toc/">GRASP principles for the Object-oriented mind</a>
|
||||
author: Kiko Fernandez-Reyes
|
||||
rights: 2017 Kiko Fernandez-Reyes, CC-BY-NC-SA 4.0 International
|
||||
header-includes:
|
||||
- |
|
||||
```{=html}
|
||||
<link href="https://fonts.googleapis.com/css?family=Inconsolata" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Gentium+Basic|Inconsolata" rel="stylesheet">
|
||||
```
|
||||
include-before:
|
||||
- |
|
||||
```{=html}
|
||||
<p>If you like this book, please consider
|
||||
spreading the word or
|
||||
<a href="https://www.buymeacoffee.com/programming">
|
||||
buying me a coffee
|
||||
</a>
|
||||
</p>
|
||||
```
|
||||
include-after:
|
||||
- |
|
||||
```{=html}
|
||||
<div class="footnotes">
|
||||
<hr>
|
||||
<div class="container">
|
||||
<nav class="pagination" role="pagination">
|
||||
<ul>
|
||||
<p>
|
||||
<span class="page-number">Designed with</span> ❤️ <span class="page-number"> from Uppsala, Sweden</span>
|
||||
</p>
|
||||
<p>
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a>
|
||||
</p>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
---
|
||||
```
|
||||
|
||||
下面几个变量需要注意一下:
|
||||
|
||||
- `header-includes` 变量包含将要嵌入 `<head>` 标签的 HTML 文本。
|
||||
- 调用变量后的下一行必须是 `- |`。再往下一行必须以与 `|` 对齐的三个反引号开始,否则 Pandoc 将无法识别。`{= html}` 告诉 Pandoc 其中的内容是原始文本,不应该作为 Markdown 处理。(为此,需要检查 Pandoc 中的 `raw_attribute` 扩展是否已启用。要进行此检查,键入 `pandoc --list-extensions | grep raw` 并确保返回的列表包含名为 `+ raw_html` 的项目,加号表示已启用。)
|
||||
- 变量 `include-before` 在网页开头添加一些 HTML 文本,此处我请求读者帮忙宣传我的书或给我打赏。
|
||||
- `include-after` 变量在网页末尾添加原始 HTML 文本,同时显示我的图书许可证。
|
||||
|
||||
这些只是其中一部分可用的变量,查看 HTML 中的模板变量(我的文章 [Pandoc简介][1] 中介绍了如何查看 LaTeX 的模版变量,查看 HTML 模版变量的过程是相同的)对其余变量进行了解。
|
||||
|
||||
#### 将网页分成多章
|
||||
|
||||
网页可以作为一个整体生成,这会产生一个包含所有内容的长页面;也可以分成多章,我认为这样会更容易阅读。我将解释如何将网页划分为多章,以便读者不会被长网页吓到。
|
||||
|
||||
为了使网页易于在 GitHub Pages 上部署,需要创建一个名为 `docs` 的根文件夹(这是 GitHub Pages 默认用于渲染网页的根文件夹)。然后我们需要为 `docs` 下的每一章创建文件夹,将 HTML 内容放在各自的文件夹中,将文件内容放在名为 `index.html` 的文件中。
|
||||
|
||||
例如,`about.md` 文件将转换成名为 `index.html` 的文件,该文件位于名为 `about`(`about/index.html`)的文件夹中。这样,当用户键入 `http://<your-website.com>/about/` 时,文件夹中的 `index.html` 文件将显示在其浏览器中。
|
||||
|
||||
下面的 `Makefile` 将执行上述所有操作:
|
||||
|
||||
```
|
||||
# Your book files
|
||||
DEPENDENCIES= toc preface about
|
||||
|
||||
# Placement of your HTML files
|
||||
DOCS=docs
|
||||
|
||||
all: web
|
||||
|
||||
web: setup $(DEPENDENCIES)
|
||||
@cp $(DOCS)/toc/index.html $(DOCS)
|
||||
|
||||
|
||||
# Creation and copy of stylesheet and images into
|
||||
# the assets folder. This is important to deploy the
|
||||
# website to Github Pages.
|
||||
setup:
|
||||
@mkdir -p $(DOCS)
|
||||
@cp -r assets $(DOCS)
|
||||
|
||||
|
||||
# Creation of folder and index.html file on a
|
||||
# per-chapter basis
|
||||
|
||||
$(DEPENDENCIES):
|
||||
@mkdir -p $(DOCS)/$@
|
||||
@pandoc -s --toc web-metadata.yaml parts/$@.md \
|
||||
-c /assets/pandoc.css -o $(DOCS)/$@/index.html
|
||||
|
||||
clean:
|
||||
@rm -rf $(DOCS)
|
||||
|
||||
.PHONY: all clean web setup
|
||||
```
|
||||
|
||||
选项 `- c /assets/pandoc.css` 声明要使用的 CSS 样式表,它将从 `/assets/pandoc.cs` 中获取。也就是说,在 `<head>` 标签内,Pandoc 会添加这样一行:
|
||||
|
||||
```
|
||||
<link rel="stylesheet" href="/assets/pandoc.css">
|
||||
```
|
||||
|
||||
使用下面的命令生成网页:
|
||||
|
||||
```
|
||||
make
|
||||
```
|
||||
|
||||
根文件夹现在应该包含如下所示的文件结构:
|
||||
|
||||
```
|
||||
.---parts
|
||||
| |--- toc.md
|
||||
| |--- preface.md
|
||||
| |--- about.md
|
||||
|
|
||||
|---docs
|
||||
|--- assets/
|
||||
|--- index.html
|
||||
|--- toc
|
||||
| |--- index.html
|
||||
|
|
||||
|--- preface
|
||||
| |--- index.html
|
||||
|
|
||||
|--- about
|
||||
|--- index.html
|
||||
|
||||
```
|
||||
|
||||
#### 部署网页
|
||||
|
||||
通过以下步骤将网页部署到 GitHub 上:
|
||||
|
||||
1. 创建一个新的 GitHub 仓库
|
||||
2. 将内容推送到新创建的仓库
|
||||
3. 找到仓库设置中的 GitHub Pages 部分,选择 `Source` 选项让 GitHub 使用主分支的内容
|
||||
|
||||
你可以在 [GitHub Pages][5] 的网站上获得更多详细信息。
|
||||
|
||||
[我的书的网页][6] 便是通过上述过程生成的,可以在网页上查看结果。
|
||||
|
||||
### 生成电子书
|
||||
|
||||
#### 创建 ePub 格式的元信息文件
|
||||
|
||||
ePub 格式的元信息文件 `epub-meta.yaml` 和 HTML 元信息文件是类似的。主要区别在于 ePub 提供了其他模板变量,例如 `publisher` 和 `cover-image` 。ePub 格式图书的样式表可能与网页所用的不同,在这里我使用一个名为 `epub.css` 的样式表。
|
||||
|
||||
```
|
||||
---
|
||||
title: 'GRASP principles for the Object-oriented Mind'
|
||||
publisher: 'Programming Language Fight Club'
|
||||
author: Kiko Fernandez-Reyes
|
||||
rights: 2017 Kiko Fernandez-Reyes, CC-BY-NC-SA 4.0 International
|
||||
cover-image: assets/cover.png
|
||||
stylesheet: assets/epub.css
|
||||
...
|
||||
```
|
||||
|
||||
将以下内容添加到之前的 `Makefile` 中:
|
||||
|
||||
```
|
||||
epub:
|
||||
@pandoc -s --toc epub-meta.yaml \
|
||||
$(addprefix parts/, $(DEPENDENCIES:=.md)) -o $(DOCS)/assets/book.epub
|
||||
```
|
||||
|
||||
用于产生 ePub 格式图书的命令从 HTML 版本获取所有依赖项(每章的名称),向它们添加 Markdown 扩展,并在它们前面加上每一章的文件夹路径,以便让 Pandoc 知道如何进行处理。例如,如果 `$(DEPENDENCIES` 变量只包含 “前言” 和 “关于本书” 两章,那么 `Makefile` 将会这样调用:
|
||||
|
||||
```
|
||||
@pandoc -s --toc epub-meta.yaml \
|
||||
parts/preface.md parts/about.md -o $(DOCS)/assets/book.epub
|
||||
```
|
||||
|
||||
Pandoc 将提取这两章的内容,然后进行组合,最后生成 ePub 格式的电子书,并放在 `Assets` 文件夹中。
|
||||
|
||||
这是使用此过程创建 ePub 格式电子书的一个 [示例][7]。
|
||||
|
||||
### 过程总结
|
||||
|
||||
从 Markdown 文件创建网页和 ePub 格式电子书的过程并不困难,但有很多细节需要注意。遵循以下大纲可能使你更容易使用 Pandoc。
|
||||
|
||||
- HTML 图书:
|
||||
- 使用 Markdown 语法创建每章内容
|
||||
- 添加元信息
|
||||
- 创建一个 `Makefile` 将各个部分组合在一起
|
||||
- 设置 GitHub Pages
|
||||
- 部署
|
||||
- ePub 电子书:
|
||||
- 使用之前创建的每一章内容
|
||||
- 添加新的元信息文件
|
||||
- 创建一个 `Makefile` 以将各个部分组合在一起
|
||||
- 设置 GitHub Pages
|
||||
- 部署
|
||||
|
||||
|
||||
------
|
||||
|
||||
via: https://opensource.com/article/18/10/book-to-website-epub-using-pandoc
|
||||
|
||||
作者:[Kiko Fernandez-Reyes][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[jlztan](https://github.com/jlztan)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/kikofernandez
|
||||
[1]: https://linux.cn/article-10228-1.html
|
||||
[2]: https://pandoc.org/
|
||||
[3]: https://www.programmingfightclub.com/
|
||||
[4]: https://github.com/kikofernandez/programmingfightclub
|
||||
[5]: https://pages.github.com/
|
||||
[6]: https://www.programmingfightclub.com/grasp-principles/
|
||||
[7]: https://github.com/kikofernandez/programmingfightclub/raw/master/docs/web_assets/demo.epub
|
@ -0,0 +1,70 @@
|
||||
|
||||
Greg Kroah-Hartman 解释内核社区是如何使 Linux 安全的
|
||||
============
|
||||
|
||||

|
||||
|
||||
> 内核维护者 Greg Kroah-Hartman 谈论内核社区如何保护 Linux 不遭受损害。
|
||||
|
||||
由于 Linux 使用量持续扩大,内核社区去提高这个世界上使用最广泛的技术 —— Linux 内核的安全性的重要性越来越高。安全不仅对企业客户很重要,它对消费者也很重要,因为 80% 的移动设备都使用了 Linux。在本文中,Linux 内核维护者 Greg Kroah-Hartman 带我们了解内核社区如何应对威胁。
|
||||
|
||||
### bug 不可避免
|
||||
|
||||

|
||||
|
||||
*Greg Kroah-Hartman [Linux 基金会][1]*
|
||||
|
||||
正如 Linus Torvalds 曾经说过的,大多数安全问题都是 bug 造成的,而 bug 又是软件开发过程的一部分。是软件就有 bug。
|
||||
|
||||
Kroah-Hartman 说:“就算是 bug,我们也不知道它是安全的 bug 还是不安全的 bug。我修复的一个著名 bug,在三年后才被 Red Hat 认定为安全漏洞“。
|
||||
|
||||
在消除 bug 方面,内核社区没有太多的办法,只能做更多的测试来寻找 bug。内核社区现在已经有了自己的安全团队,它们是由熟悉内核核心的内核开发者组成。
|
||||
|
||||
Kroah-Hartman 说:”当我们收到一个报告时,我们就让参与这个领域的核心开发者去修复它。在一些情况下,他们可能是同一个人,让他们进入安全团队可以更快地解决问题“。但他也强调,内核所有部分的开发者都必须清楚地了解这些问题,因为内核是一个可信环境,它必须被保护起来。
|
||||
|
||||
Kroah-Hartman 说:”一旦我们修复了它,我们就将它放到我们的栈分析规则中,以便于以后不再重新出现这个 bug。“
|
||||
|
||||
除修复 bug 之外,内核社区也不断加固内核。Kroah-Hartman 说:“我们意识到,我们需要一些主动的缓减措施,因此我们需要加固内核。”
|
||||
|
||||
Kees Cook 和其他一些人付出了巨大的努力,带来了一直在内核之外的加固特性,并将它们合并或适配到内核中。在每个内核发行后,Cook 都对所有新的加固特性做一个总结。但是只加固内核是不够的,供应商们必须要启用这些新特性来让它们充分发挥作用,但他们并没有这么做。
|
||||
|
||||
Kroah-Hartman [每周发布一个稳定版内核][5],而为了长期的支持,公司们只从中挑选一个,以便于设备制造商能够利用它。但是,Kroah-Hartman 注意到,除了 Google Pixel 之外,大多数 Android 手机并不包含这些额外的安全加固特性,这就意味着,所有的这些手机都是有漏洞的。他说:“人们应该去启用这些加固特性”。
|
||||
|
||||
Kroah-Hartman 说:“我购买了基于 Linux 内核 4.4 的所有旗舰级手机,去查看它们中哪些确实升级了新特性。结果我发现只有一家公司升级了它们的内核。……我在整个供应链中努力去解决这个问题,因为这是一个很棘手的问题。它涉及许多不同的组织 —— SoC 制造商、运营商等等。关键点是,需要他们把我们辛辛苦苦设计的内核去推送给大家。”
|
||||
|
||||
好消息是,与消费电子产品不一样,像 Red Hat 和 SUSE 这样的大供应商,在企业环境中持续对内核进行更新。使用容器、pod 和虚拟化的现代系统做到这一点更容易了。无需停机就可以毫不费力地更新和重启。事实上,现在来保证系统安全相比过去容易多了。
|
||||
|
||||
### Meltdown 和 Spectre
|
||||
|
||||
没有任何一个关于安全的讨论能够避免提及 Meltdown 和 Spectre 缺陷。内核社区一直致力于修改新发现的和已查明的安全漏洞。不管怎样,Intel 已经因为这些事情改变了它们的策略。
|
||||
|
||||
Kroah-Hartman 说:“他们已经重新研究如何处理安全 bug,以及如何与社区合作,因为他们知道他们做错了。内核已经修复了几乎所有大的 Spectre 问题,但是还有一些小问题仍在处理中”。
|
||||
|
||||
好消息是,这些 Intel 漏洞使得内核社区正在变得更好。Kroah-Hartman 说:“我们需要做更多的测试。对于最新一轮的安全补丁,在它们被发布之前,我们自己花了四个月时间来测试它们,因为我们要防止这个安全问题在全世界扩散。而一旦这些漏洞在真实的世界中被利用,将让我们认识到我们所依赖的基础设施是多么的脆弱,我们多年来一直在做这种测试,这确保了其它人不会遭到这些 bug 的伤害。所以说,Intel 的这些漏洞在某种程度上让内核社区变得更好了”。
|
||||
|
||||
对安全的日渐关注也为那些有才华的人创造了更多的工作机会。由于安全是个极具吸引力的领域,那些希望在内核空间中有所建树的人,安全将是他们一个很好的起点。
|
||||
|
||||
Kroah-Hartman 说:“如果有人想从事这方面的工作,我们有大量的公司愿意雇佣他们。我知道一些开始去修复 bug 的人已经被他们雇佣了。”
|
||||
|
||||
你可以在下面链接的视频上查看更多的内容:
|
||||
|
||||
[视频](https://youtu.be/jkGVabyMh1I)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linux.com/blog/2018/10/greg-kroah-hartman-explains-how-kernel-community-securing-linux-0
|
||||
|
||||
作者:[SWAPNIL BHARTIYA][a]
|
||||
选题:[oska874][b]
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.linux.com/users/arnieswap
|
||||
[b]:https://github.com/oska874
|
||||
[1]:https://www.linux.com/licenses/category/linux-foundation
|
||||
[2]:https://www.linux.com/licenses/category/creative-commons-zero
|
||||
[3]:https://www.linux.com/files/images/greg-k-hpng
|
||||
[4]:https://www.linux.com/files/images/kernel-securityjpg-0
|
||||
[5]:https://www.kernel.org/category/releases.html
|
@ -0,0 +1,159 @@
|
||||
Terminalizer:一个记录您终端活动并且生成 Gif 图像的工具
|
||||
====
|
||||
|
||||
今天我们要讨论一个广为人知的主题,我们也围绕这个主题写过许多的文章,因此我不会针对这个如何记录终端会话流程给出太多具体的资料。
|
||||
|
||||
我们可以使用脚本命令来记录 Linux 的终端会话,这也是大家公认的一种办法。不过今天我们将来介绍一个能起到相同作用的工具 —— Terminalizer。
|
||||
|
||||
这个工具可以帮助我们记录用户的终端活动,以帮助我们从输出的文件中找到有用的信息。
|
||||
|
||||
### 什么是 Terminlizer
|
||||
|
||||
用户可以用 Terminlizer 记录他们的终端活动并且生成一个 Gif 图像。它是一个允许高度定制的 CLI 工具。用户可以在网络播放器、在线播放器上用链接分享他们记录下的文件。
|
||||
|
||||
**推荐阅读:**
|
||||
|
||||
- [Script – 一个记录您终端对话的简单工具][1]
|
||||
- [在 Linux 上自动记录/捕捉所有用户的终端对话][2]
|
||||
- [Teleconsole – 一个能立即与任何人分享您终端对话的工具][3]
|
||||
- [tmate – 立即与任何人分享您的终端对话][4]
|
||||
- [Peek – 在 Linux 里制造一个 Gif 记录器][5]
|
||||
- [Kgif – 一个能生成 Gif 图片,以记录窗口活动的简单 Shell 脚本][6]
|
||||
- [Gifine – 在 Ubuntu/Debian 里快速制造一个 Gif 视频][7]
|
||||
|
||||
目前没有发行版拥有官方软件包来安装此实用程序,不过我们可以用 Node.js 来安装它。
|
||||
|
||||
### 如何在 Linux 上安装 Node.js
|
||||
|
||||
安装 Node.js 有许多种方法。我们在这里将会教您一个常用的方法。
|
||||
|
||||
在 Ubuntu/LinuxMint 上可以使用 [APT-GET 命令][8] 或者 [APT 命令][9] 来安装 Node.js。
|
||||
|
||||
```
|
||||
$ curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
|
||||
$ sudo apt-get install -y nodejs
|
||||
```
|
||||
|
||||
在 Debian 上使用 [APT-GET 命令][8] 或者 [APT 命令][9] 来安装 Node.js。
|
||||
|
||||
```
|
||||
# curl -sL https://deb.nodesource.com/setup_8.x | bash -
|
||||
# apt-get install -y nodejs
|
||||
```
|
||||
|
||||
在 RHEL/CentOS 上,使用 [YUM 命令][10] 来安装。
|
||||
|
||||
```
|
||||
$ sudo curl --silent --location https://rpm.nodesource.com/setup_8.x | sudo bash -
|
||||
$ sudo yum install epel-release
|
||||
$ sudo yum -y install nodejs
|
||||
```
|
||||
|
||||
在 Fedora 上,用 [DNF 命令][11] 来安装 tmux。
|
||||
|
||||
```
|
||||
$ sudo dnf install nodejs
|
||||
```
|
||||
|
||||
在 Arch Linux 上,用 [Pacman 命令][12] 来安装 tmux。
|
||||
|
||||
```
|
||||
$ sudo pacman -S nodejs npm
|
||||
```
|
||||
|
||||
在 openSUSE 上,用 [Zypper Command][13] 来安装 tmux。
|
||||
|
||||
```
|
||||
$ sudo zypper in nodejs6
|
||||
```
|
||||
|
||||
### 如何安装 Terminalizer
|
||||
|
||||
您已经安装了 Node.js 这个先决软件包,现在是时候在您的系统上安装 Terminalizer 了。简单执行如下的 `npm` 命令即可安装。
|
||||
|
||||
```
|
||||
$ sudo npm install -g terminalizer
|
||||
```
|
||||
|
||||
### 如何使用 Terminalizer
|
||||
|
||||
您只需要执行如下的命令,即可使用 Terminalizer 记录您的终端会话活动。您可以敲击 `CTRL+D` 来结束并且保存记录。
|
||||
|
||||
```
|
||||
# terminalizer record 2g-session
|
||||
|
||||
defaultConfigPath
|
||||
The recording session is started
|
||||
Press CTRL+D to exit and save the recording
|
||||
```
|
||||
|
||||
这将会将您记录的会话保存成一个 YAML 文件,在这个例子里,我的文件名将会是 2g-session-activity.yml。
|
||||
|
||||
![][15]
|
||||
|
||||
```
|
||||
# logout
|
||||
Successfully Recorded
|
||||
The recording data is saved into the file:
|
||||
/home/daygeek/2g-session.yml
|
||||
You can edit the file and even change the configurations.
|
||||
```
|
||||
|
||||
![][16]
|
||||
|
||||
### 如何播放记录下来的文件
|
||||
|
||||
使用以下命令来播放您记录的 YAML 文件。在以下操作中,请确保您已经用了您的文件名来替换 “2g-session”。
|
||||
|
||||
```
|
||||
# terminalizer play 2g-session
|
||||
```
|
||||
|
||||
将记录的文件渲染成 Gif 图像。
|
||||
|
||||
```
|
||||
# terminalizer render 2g-session
|
||||
```
|
||||
|
||||
注意: 以下的两个命令在此版本尚且不可用,或许在下一版本这两个命令将会付诸使用。
|
||||
|
||||
如果您想要将记录的文件分享给其他人,您可以将您的文件上传到在线播放器,并且将链接分享给对方。
|
||||
|
||||
```
|
||||
terminalizer share 2g-session
|
||||
```
|
||||
|
||||
为记录的文件生成一个网络播放器。
|
||||
|
||||
```
|
||||
# terminalizer generate 2g-session
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.2daygeek.com/terminalizer-a-tool-to-record-your-terminal-and-generate-animated-gif-images/
|
||||
|
||||
作者:[Prakash Subramanian][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[thecyanbird](https://github.com/thecyanbird)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.2daygeek.com/author/prakash/
|
||||
[1]: https://www.2daygeek.com/script-command-record-save-your-terminal-session-activity-linux/
|
||||
[2]: https://www.2daygeek.com/automatically-record-all-users-terminal-sessions-activity-linux-script-command/
|
||||
[3]: https://www.2daygeek.com/teleconsole-share-terminal-session-instantly-to-anyone-in-seconds/
|
||||
[4]: https://www.2daygeek.com/tmate-instantly-share-your-terminal-session-to-anyone-in-seconds/
|
||||
[5]: https://www.2daygeek.com/peek-create-animated-gif-screen-recorder-capture-arch-linux-mint-fedora-ubuntu/
|
||||
[6]: https://www.2daygeek.com/kgif-create-animated-gif-file-active-window-screen-recorder-capture-arch-linux-mint-fedora-ubuntu-debian-opensuse-centos/
|
||||
[7]: https://www.2daygeek.com/gifine-create-animated-gif-vedio-recorder-linux-mint-debian-ubuntu/
|
||||
[8]: https://www.2daygeek.com/apt-get-apt-cache-command-examples-manage-packages-debian-ubuntu-systems/
|
||||
[9]: https://www.2daygeek.com/apt-command-examples-manage-packages-debian-ubuntu-systems/
|
||||
[10]: https://www.2daygeek.com/yum-command-examples-manage-packages-rhel-centos-systems/
|
||||
[11]: https://www.2daygeek.com/dnf-command-examples-manage-packages-fedora-system/
|
||||
[12]: https://www.2daygeek.com/pacman-command-examples-manage-packages-arch-linux-system/
|
||||
[13]: https://www.2daygeek.com/zypper-command-examples-manage-packages-opensuse-system/
|
||||
[14]: data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[15]: https://www.2daygeek.com/wp-content/uploads/2018/10/terminalizer-record-2g-session-1.gif
|
||||
[16]: https://www.2daygeek.com/wp-content/uploads/2018/10/terminalizer-play-2g-session.gif
|
@ -0,0 +1,118 @@
|
||||
服务器的 LinuxBoot:告别 UEFI、拥抱开源
|
||||
============
|
||||
|
||||
[LinuxBoot][13] 是私有的 [UEFI][15] 固件的开源 [替代品][14]。它发布于去年,并且现在已经得到主流的硬件生产商的认可成为他们产品的默认固件。去年,LinuxBoot 已经被 Linux 基金会接受并[纳入][16]开源家族。
|
||||
|
||||
这个项目最初是由 Ron Minnich 在 2017 年 1 月提出,它是 LinuxBIOS 的创造人,并且在 Google 领导 [coreboot][17] 的工作。
|
||||
|
||||
Google、Facebook、[Horizon Computing Solutions][18]、和 [Two Sigma][19] 共同合作,在运行 Linux 的服务器上开发 [LinuxBoot 项目][20](以前叫 [NERF][21])。
|
||||
|
||||
它的开放性允许服务器用户去很容易地定制他们自己的引导脚本、修复问题、构建他们自己的 [运行时环境][22] 和用他们自己的密钥去 [刷入固件][23],而不需要等待供应商的更新。
|
||||
|
||||
下面是第一次使用 NERF BIOS 去引导 [Ubuntu Xenial][24] 的视频:
|
||||
|
||||
[点击看视频](https://youtu.be/HBkZAN3xkJg)
|
||||
|
||||
我们来讨论一下它与 UEFI 相比在服务器硬件方面的其它优势。
|
||||
|
||||
### LinuxBoot 超越 UEFI 的优势
|
||||
|
||||

|
||||
|
||||
下面是一些 LinuxBoot 超越 UEFI 的主要优势:
|
||||
|
||||
#### 启动速度显著加快
|
||||
|
||||
它能在 20 秒钟以内完成服务器启动,而 UEFI 需要几分钟的时间。
|
||||
|
||||
#### 显著的灵活性
|
||||
|
||||
LinuxBoot 可以用在 Linux 支持的各种设备、文件系统和协议上。
|
||||
|
||||
#### 更加安全
|
||||
|
||||
相比 UEFI 而言,LinuxBoot 在设备驱动程序和文件系统方面进行更加严格的检查。
|
||||
|
||||
我们可能争辩说 UEFI 是使用 [EDK II][25] 而部分开源的,而 LinuxBoot 是部分闭源的。但有人[提出][26],即便有像 EDK II 这样的代码,但也没有做适当的审查级别和像 [Linux 内核][27] 那样的正确性检查,并且在 UEFI 的开发中还大量使用闭源组件。
|
||||
|
||||
另一方面,LinuxBoot 有非常小的二进制文件,它仅用了大约几百 KB,相比而言,而 UEFI 的二进制文件有 32 MB。
|
||||
|
||||
严格来说,LinuxBoot 与 UEFI 不一样,更适合于[可信计算基础][28]。
|
||||
|
||||
LinuxBoot 有一个基于 [kexec][30] 的引导加载器,它不支持启动 Windows/非 Linux 内核,但这影响并不大,因为主流的云都是基于 Linux 的服务器。
|
||||
|
||||
### LinuxBoot 的采用者
|
||||
|
||||
自 2011 年, [Facebook][32] 发起了[开源计算项目(OCP)][31],它的一些服务器是基于[开源][33]设计的,目的是构建的数据中心更加高效。LinuxBoot 已经在下面列出的几个开源计算硬件上做了测试:
|
||||
|
||||
* Winterfell
|
||||
* Leopard
|
||||
* Tioga Pass
|
||||
|
||||
更多 [OCP][34] 硬件在[这里][35]有一个简短的描述。OCP 基金会通过[开源系统固件][36]运行一个专门的固件项目。
|
||||
|
||||
支持 LinuxBoot 的其它一些设备有:
|
||||
|
||||
* [QEMU][9] 仿真的 [Q35][10] 系统
|
||||
* [Intel S2600wf][11]
|
||||
* [Dell R630][12]
|
||||
|
||||
上个月底(2018 年 9 月 24 日),[Equus 计算解决方案][37] [宣布][38] 发行它的 [白盒开放式™][39] M2660 和 M2760 服务器,作为它们的定制的、成本优化的、开放硬件服务器和存储平台的一部分。它们都支持 LinuxBoot 灵活定制服务器的 BIOS,以提升安全性和设计一个非常快的纯净的引导体验。
|
||||
|
||||
### 你认为 LinuxBoot 怎么样?
|
||||
|
||||
LinuxBoot 在 [GitHub][40] 上有很丰富的文档。你喜欢它与 UEFI 不同的特性吗?由于 LinuxBoot 的开放式开发和未来,你愿意使用 LinuxBoot 而不是 UEFI 去启动你的服务器吗?请在下面的评论区告诉我们吧。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/linuxboot-uefi/
|
||||
|
||||
作者:[Avimanyu Bandyopadhyay][a]
|
||||
选题:[oska874][b]
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://itsfoss.com/author/avimanyu/
|
||||
[b]:https://github.com/oska874
|
||||
[1]:https://itsfoss.com/linuxboot-uefi/#
|
||||
[2]:https://itsfoss.com/linuxboot-uefi/#
|
||||
[3]:https://itsfoss.com/linuxboot-uefi/#
|
||||
[4]:https://itsfoss.com/linuxboot-uefi/#
|
||||
[5]:https://itsfoss.com/linuxboot-uefi/#
|
||||
[6]:https://itsfoss.com/linuxboot-uefi/#
|
||||
[7]:https://itsfoss.com/author/avimanyu/
|
||||
[8]:https://itsfoss.com/linuxboot-uefi/#comments
|
||||
[9]:https://en.wikipedia.org/wiki/QEMU
|
||||
[10]:https://wiki.qemu.org/Features/Q35
|
||||
[11]:https://trmm.net/S2600
|
||||
[12]:https://trmm.net/NERF#Installing_on_a_Dell_R630
|
||||
[13]:https://www.linuxboot.org/
|
||||
[14]:https://www.phoronix.com/scan.php?page=news_item&px=LinuxBoot-OSFC-2018-State
|
||||
[15]:https://itsfoss.com/check-uefi-or-bios/
|
||||
[16]:https://www.linuxfoundation.org/blog/2018/01/system-startup-gets-a-boost-with-new-linuxboot-project/
|
||||
[17]:https://en.wikipedia.org/wiki/Coreboot
|
||||
[18]:http://www.horizon-computing.com/
|
||||
[19]:https://www.twosigma.com/
|
||||
[20]:https://trmm.net/LinuxBoot_34c3
|
||||
[21]:https://trmm.net/NERF
|
||||
[22]:https://trmm.net/LinuxBoot_34c3#Runtimes
|
||||
[23]:http://www.tech-faq.com/flashing-firmware.html
|
||||
[24]:https://itsfoss.com/features-ubuntu-1604/
|
||||
[25]:https://www.tianocore.org/
|
||||
[26]:https://media.ccc.de/v/34c3-9056-bringing_linux_back_to_server_boot_roms_with_nerf_and_heads
|
||||
[27]:https://medium.com/@bhumikagoyal/linux-kernel-development-cycle-52b4c55be06e
|
||||
[28]:https://en.wikipedia.org/wiki/Trusted_computing_base
|
||||
[29]:https://itsfoss.com/adobe-alternatives-linux/
|
||||
[30]:https://en.wikipedia.org/wiki/Kexec
|
||||
[31]:https://en.wikipedia.org/wiki/Open_Compute_Project
|
||||
[32]:https://github.com/facebook
|
||||
[33]:https://github.com/opencomputeproject
|
||||
[34]:https://www.networkworld.com/article/3266293/lan-wan/what-is-the-open-compute-project.html
|
||||
[35]:http://hyperscaleit.com/ocp-server-hardware/
|
||||
[36]:https://www.opencompute.org/projects/open-system-firmware
|
||||
[37]:https://www.equuscs.com/
|
||||
[38]:http://www.dcvelocity.com/products/Software_-_Systems/20180924-equus-compute-solutions-introduces-whitebox-open-m2660-and-m2760-servers/
|
||||
[39]:https://www.equuscs.com/servers/whitebox-open/
|
||||
[40]:https://github.com/linuxboot/linuxboot
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user