mirror of
https://github.com/LCTT/TranslateProject.git
synced 2025-01-07 22:11:09 +08:00
commit
f4ed048c92
296
published/20160921 lawyer The MIT License, Line by Line.md
Normal file
296
published/20160921 lawyer The MIT License, Line by Line.md
Normal file
@ -0,0 +1,296 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (bestony)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13180-1.html)
|
||||
[#]: subject: (lawyer The MIT License, Line by Line)
|
||||
[#]: via: (https://writing.kemitchell.com/2016/09/21/MIT-License-Line-by-Line.html)
|
||||
[#]: author: (Kyle E. Mitchell https://kemitchell.com/)
|
||||
|
||||
逐行解读 MIT 许可证
|
||||
======
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202103/06/224509d0zt70ctxtt7iibo.png)
|
||||
|
||||
> 每个程序员都应该明白的 171 个字。
|
||||
|
||||
[MIT 许可证][1] 是世界上最流行的开源软件许可证。以下是它的逐行解读。
|
||||
|
||||
### 阅读许可证
|
||||
|
||||
如果你参与了开源软件,但还没有花时间从头到尾的阅读过这个许可证(它只有 171 个单词),你需要现在就去读一下。尤其是如果许可证不是你日常每天都会接触的,把任何看起来不对劲或不清楚的地方记下来,然后继续阅读。我会分段、按顺序、加入上下文和注释,把每一个词再重复一遍。但最重要的还是要有个整体概念。
|
||||
|
||||
> The MIT License (MIT)
|
||||
>
|
||||
> Copyright (c) \<year> \<copyright holders>
|
||||
>
|
||||
> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
>
|
||||
> The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
>
|
||||
> *The Software is provided “as is”, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the Software.*
|
||||
|
||||
(LCTT 译注:MIT 许可证并无官方的中文文本,我们也没找到任何可靠的、精确的非官方中文文本。在本文中,我们仅作为参考目的提供一份逐字逐行而没有经过润色的中文翻译文本,但该文本及对其的理解**不能**作为 MIT 许可证使用,我们也不为此中文翻译文本的使用承担任何责任,这份中文文本,我们贡献给公共领域。)
|
||||
|
||||
> MIT 许可证(MIT)
|
||||
>
|
||||
> 版权 (c) <年份> <版权人>
|
||||
>
|
||||
> 特此免费授予任何获得本软件副本和相关文档文件(下称“软件”)的人不受限制地处置该软件的权利,包括不受限制地使用、复制、修改、合并、发布、分发、转授许可和/或出售该软件副本,以及再授权被配发了本软件的人如上的权利,须在下列条件下:
|
||||
>
|
||||
> 上述版权声明和本许可声明应包含在该软件的所有副本或实质成分中。
|
||||
>
|
||||
> 本软件是“如此”提供的,没有任何形式的明示或暗示的保证,包括但不限于对适销性、特定用途的适用性和不侵权的保证。在任何情况下,作者或版权持有人都不对任何索赔、损害或其他责任负责,无论这些追责来自合同、侵权或其它行为中,还是产生于、源于或有关于本软件以及本软件的使用或其它处置。
|
||||
|
||||
该许可证分为五段,按照逻辑划分如下:
|
||||
|
||||
* **头部**
|
||||
* **许可证名称**:“MIT 许可证”
|
||||
* **版权说明**:“版权 (c) …”
|
||||
* **许可证授予**:“特此授予 …”
|
||||
* **授予范围**:“… 处置软件 …”
|
||||
* **条件**:“… 须在 …”
|
||||
* **归因和声明**:“上述 … 应包含在 …”
|
||||
* **免责声明**:“本软件是‘如此’提供的 …”
|
||||
* **责任限制**:“在任何情况下 …”
|
||||
|
||||
接下来详细看看。
|
||||
|
||||
### 头部
|
||||
|
||||
#### 许可证名称
|
||||
|
||||
> The MIT License (MIT)
|
||||
|
||||
> MIT 许可证(MIT)
|
||||
|
||||
“MIT 许可证”不是一个单一的许可证,而是根据<ruby>麻省理工学院<rt>Massachusetts Institute of Technology</rt></ruby>(MIT)为发行版本准备的语言衍生出来一系列许可证形式。多年来,无论是对于使用它的原始项目,还是作为其他项目的范本,它经历了许多变化。Fedora 项目一直保持着 [收藏 MIT 许可证的好奇心][2],以纯文本的方式记录了那些平淡的变化,如同泡在甲醛中的解剖标本一般,追溯了它的各种演变。
|
||||
|
||||
幸运的是,<ruby>[开放源码倡议组织][3]<rt>Open Source Initiative</rt></ruby>(OSI) 和 <ruby>[软件数据包交换][4]<rt>Software Package Data eXchange</rt></ruby>组织(SPDX)已经将一种通用的 MIT 式的许可证形式标准化为“<ruby>MIT 许可证<rt>The MIT License</rt></ruby>”。OSI 反过来又采用了 SPDX 通用开源许可证的标准化 [字符串标志符][5],并将其中的 “MIT” 明确指向了标准化形式的“MIT 许可证”。如果你想为一个新项目使用 MIT 式的条款,请使用其 [标准化的形式][1]。
|
||||
|
||||
即使你在 `LICENSE` 文件中包含 “The MIT License” 或 “SPDX:MIT”,任何负责的审查者仍会将文本与标准格式进行比较,以确保安全。尽管自称为“MIT 许可证”的各种许可证形式只在细微的细节上有所不同,但所谓的“MIT 许可证”的松散性已经诱使了一些作者加入麻烦的“自定义”。典型的糟糕、不好的、非常坏的例子是 [JSON 许可证][6],一个 MIT 家族的许可证被加上了“本软件应用于善,而非恶”。这件事情可能是“非常克罗克福特”的(LCTT 译者注,Crockford 是 JSON 格式和 JSON.org 的作者)。这绝对是一件麻烦事,也许这个玩笑本来是开在律师身上的,但他们却笑得前仰后合。
|
||||
|
||||
这个故事的寓意是:“MIT 许可证”本身就是模棱两可的。大家可能很清楚你的意思,但你只需要把标准的 MIT 许可证文本复制到你的项目中,就可以节省每个人的时间。如果使用元数据(如包管理器中的元数据文件)来指定 “MIT 许可证”,请确保 `LICENSE` 文件和任何头部的注释都使用标准的许可证文本。所有的这些都可以 [自动化完成][7]。
|
||||
|
||||
#### 版权声明
|
||||
|
||||
> Copyright (c) <year> <copyright holders>
|
||||
|
||||
> 版权 (c) <年份> <版权持有人>
|
||||
|
||||
在 1976 年(美国)《版权法》颁布之前,美国的版权法规要求采取具体的行动,即所谓的“手续”来确保创意作品的版权。如果你不遵守这些手续,你起诉他人未经授权使用你的作品的权力就会受到限制,往往会完全丧失权力,其中一项手续就是“<ruby>声明<rt>notice</rt></ruby>”。在你的作品上打上记号,以其他方式让市场知道你拥有版权。“©” 是一个标准符号,用于标记受版权保护的作品,以发出版权声明。ASCII 字符集没有 © 符号,但 `Copyright (c)` 可以表达同样的意思。
|
||||
|
||||
1976 年的《版权法》“落实”了国际《<ruby>伯尔尼公约<rt>Berne Convention</rt></ruby>》的许多要求,取消了确保版权的手续。至少在美国,著作权人在起诉侵权之前,仍然需要对自己的版权作品进行登记,如果在侵权行为开始之前进行登记,可能会获得更高的赔偿。但在实践中,很多人在对某个人提起诉讼之前,都会先注册版权。你并不会因为没有在上面贴上声明、注册它、向国会图书馆寄送副本等而失去版权。
|
||||
|
||||
即使版权声明不像过去那样绝对必要,但它们仍然有很多用处。说明作品的创作年份和版权属于谁,可以让人知道作品的版权何时到期,从而使作品纳入公共领域。作者或作者们的身份也很有用。美国法律对个人作者和“公司”作者的版权条款的计算方式不同。特别是在商业用途中,公司在使用已知竞争对手的软件时,可能也要三思而行,即使许可条款给予了非常慷慨的许可。如果你希望别人看到你的作品并想从你这里获得许可,版权声明可以很好地起到归属作用。
|
||||
|
||||
至于“<ruby>版权持有人<rt>copyright holder</rt></ruby>”。并非所有标准形式的许可证都有写明这一点的空间。最新的许可证形式,如 [Apache 2.0][8] 和 [GPL 3.0][9],发布的许可证文本是要逐字复制的,并在其他地方加上标题注释和单独文件,以表明谁拥有版权并提供许可证。这些办法巧妙地阻止了对“标准”文本的意外或故意的修改。这还使自动许可证识别更加可靠。
|
||||
|
||||
MIT 许可证是从为机构发布的代码而写的语言演变而来。对于机构发布的代码,只有一个明确的“版权持有人”,即发布代码的机构。其他机构抄袭了这些许可证,用他们自己的名字代替了 “MIT”,最终形成了我们现在拥有的通用形式。这一过程同样适用于该时代的其他简短的机构许可证,特别是加州大学伯克利分校的最初的 <ruby>[四条款 BSD 许可证][10]<rt>four-clause BSD License</rt></ruby> 成为了现在使用的 [三条款][11] 和 [两条款][12] 变体,以及 MIT 许可证的变体<ruby>互联网系统联盟<rt>Internet Systems Consortium</rt></ruby>的 [ISC 许可证][13]。
|
||||
|
||||
在每一种情况下,该机构都根据版权所有权规则将自己列为版权持有人,这些规则称为“[雇佣作品][14]”规则,这些规则赋予雇主和客户在其雇员和承包商代表其从事的某些工作中的版权所有权。这些规则通常不适用于自愿提交代码的分布式协作者。这给项目监管型基金会(如 Apache 基金会和 Eclipse 基金会)带来了一个问题,因为它们接受来自更多不同的贡献者的贡献。到目前为止,通常的基础方法是使用一个单一的许可证,它规定了一个版权持有者,如 [Apache 2.0][8] 和 [EPL 1.0][15],并由<ruby>贡献者许可协议<rt>contributor license agreements</rt></ruby> [Apache CLA][16] 以及 [Eclipse CLA][17] 为后盾,以从贡献者中收集权利。在像 GPL 这样的<ruby>左版<rt>copyleft</rt></ruby>许可证下,将版权所有权收集在一个地方就更加重要了,因为 GPL 依靠版权所有者来执行许可证条件,以促进软件自由的价值。
|
||||
|
||||
如今,大量没有机构或商业管理人的项目都在使用 MIT 风格的许可条款。SPDX 和 OSI 通过标准化不涉及特定实体或机构版权持有人的 MIT 和 ISC 之类的许可证形式,为这些用例提供了帮助。有了这些许可证形式,项目作者的普遍做法是在许可证的版权声明中尽早填上自己的名字...也许还会在这里或那里填上年份。至少根据美国的版权法,由此产生的版权声明并不能说明全部情况。
|
||||
|
||||
软件的原始所有者保留其工作的所有权。但是,尽管 MIT 风格的许可条款赋予了他人开发和更改软件的权利,创造了法律上所谓的“衍生作品”,但它们并没有赋予原始作者对他人的贡献的所有权。相反,每个贡献者在以现有代码为起点所做的任何作品都拥有版权,[即使是稍做了一点创意][18]。
|
||||
|
||||
这些项目大多数也对接受<ruby>贡献者许可协议<rt>contributor license agreements</rt></ruby>(CLA)的想法嗤之以鼻,更不用说签署版权转让协议了。这既幼稚又可以理解。尽管一些较新的开源开发人员认为,在 GitHub 上发送<ruby>拉取请求<rt>Pull Request</rt></ruby>,就会“自动”根据项目现有的许可证条款授权分发贡献,但美国法律不承认任何此类规则。强有力的版权保护是默认的,而不是宽松许可。
|
||||
|
||||
> 更新:GitHub 后来修改了全站的服务条款,包括试图至少在 GitHub.com 上改变这一默认值。我在 [另一篇文章][19] 中写了一些对这一发展的想法,并非所有想法都是积极的。
|
||||
|
||||
为了填补法律上有效的、有据可查的贡献权利授予与完全没有纸质痕迹之间的差距,一些项目采用了 <ruby>[开发者原创证书][20]<rt>Developer Certificate of Origin</rt></ruby>,这是贡献者在 Git 提交中使用 `Signed-Off-By` 元数据标签暗示的标准声明。开发者原创证书是在臭名昭著的 SCO 诉讼之后为 Linux 内核开发而开发的,该诉讼称 Linux 的大部分代码源自 SCO 拥有的 Unix 源代码。作为创建显示 Linux 的每一行都来自贡献者的书面记录的一种方法,开发者原创证书的功能良好。尽管开发者原创证书不是许可证,但它确实提供了大量证据,证明提交代码的人希望项目分发其代码,并让其他人根据内核现有的许可证条款使用该代码。内核还维护着一个机器可读的 `CREDITS` 文件,其中列出了贡献者的名字、所属机构、贡献领域和其他元数据。我做了 [一些][21] [实验][22],把这种方法改编成适用于不使用内核开发流程的项目。
|
||||
|
||||
### 许可证授权
|
||||
|
||||
> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”),
|
||||
|
||||
> 特此免费授予任何获得本软件副本和相关文档文件(下称“软件”)的人
|
||||
|
||||
MIT 许可证的实质是许可证(你猜对了)。一般来说,许可证是一个人或法律实体(“<ruby>许可人<rt>licensor</rt></ruby>”)给予另一个人(“<ruby>被许可人<rt>licensee</rt></ruby>”)做一些法律允许他们起诉的事情的许可。MIT 许可证是一种不起诉的承诺。
|
||||
|
||||
法律有时将许可证与给予许可证的承诺区分开来。如果有人违背了提供许可证的承诺,你可以起诉他们违背了承诺,但你最终可能得不到许可证。“<ruby>特此<rt>Hereby</rt></ruby>”是律师们永远摆脱不了的一个矫揉造作、老生常谈的词。这里使用它来表明,许可证文本本身提供了许可证,而不仅仅是许可证的承诺。这是一个合法的 [即调函数表达式(IIFE)][23]。
|
||||
|
||||
尽管许多许可证都是授予特定的、指定的被许可人的,但 MIT 许可证是一个“<ruby>公共许可证<rt>public license</rt></ruby>”。公共许可证授予所有人(整个公众)许可。这是开源许可中的三大理念之一。MIT 许可证通过“向任何获得……软件副本的人”授予许可证来体现这一思想。稍后我们将看到,获得此许可证还有一个条件,以确保其他人也可以了解他们的许可。
|
||||
|
||||
在美国式法律文件中,括号中带引号的首字母大写词汇是赋予术语特定含义的标准方式(“定义”)。当法庭看到文件中其他地方使用了一个已定义的大写术语时,法庭会可靠地回顾定义中的术语。
|
||||
|
||||
#### 授权范围
|
||||
|
||||
> to deal in the Software without restriction,
|
||||
|
||||
> 不受限制地处置该软件的权利,
|
||||
|
||||
从被许可人的角度来看,这是 MIT 许可证中最重要的七个字。主要的法律问题就是因侵犯版权而被起诉,和因侵犯专利而被起诉。无论是版权法还是专利法都没有将 “<ruby>处置<rt>to deal in</rt></ruby>” 作为一个术语,它在法庭上没有特定的含义。因此,任何法庭在裁决许可人和被许可人之间的纠纷时,都会询问当事人对这一措辞的含义和理解。法庭将看到的是,该措辞有意宽泛和开放。它为被许可人提供了一个强有力的论据,反对许可人提出的任何主张 —— 即他们不允许被许可人使用该软件做那件特定的事情,即使在授予许可证时双方都没有明显想到。
|
||||
|
||||
> including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
|
||||
> 包括不受限制地使用、复制、修改、合并、发布、分发、转授许可和/或出售该软件副本,以及再授权被配发了本软件的人如上的权利,
|
||||
|
||||
没有一篇法律是完美的、“意义上完全确定”、或明确无误的。小心那些假装不然的人。这是 MIT 许可证中最不完美的部分。主要有三个问题:
|
||||
|
||||
首先,“<ruby>包括不受限制地<rt>including without limitation</rt></ruby>”是一种法律反模式。它有多种衍生:
|
||||
|
||||
* <ruby>包括,但不受限制<rt>including, without limitation</rt></ruby>
|
||||
* <ruby>包括,但不限于前述的一般性<rt>including, without limiting the generality of the foregoing</rt></ruby>
|
||||
* <ruby>包括,但不限于<rt>including, but not limited to</rt></ruby>
|
||||
* 很多、很多毫无意义的变化
|
||||
|
||||
所有这些都有一个共同的目标,但都未能可靠地实现。从根本上说,使用它们的起草者也会尽量试探着去做。在 MIT 许可证中,这意味着引入“<ruby>处置软件<rt>dealing in the Software</rt></ruby>”的具体例子 — “使用、复制、修改”等等,但不意味着被许可方的行为必须与给出的例子类似,才能算作“处置”。问题是,如果你最终需要法庭来审查和解释许可证的条款,法庭将把它的工作看作是找出这些语言的含义。如果法庭需要决定“<ruby>处置<rt>deal in</rt></ruby>”的含义,它不能“无视”这些例子,即使你告诉它。我认为,“不受限制地处置本软件”本身对被许可人更好,也更短。
|
||||
|
||||
其次,作为“<ruby>处置<rt>deal in</rt></ruby>”的例子的那些动词是一个大杂烩。有些在版权法或专利法下有特定的含义,有些稍微有或根本没有含义:
|
||||
|
||||
* “<ruby>使用<rt>use</rt></ruby>”出现在 [《美国法典》第 35 篇,第 271(a)节][24],这是专利法中专利权人可以起诉他人未经许可的行为的清单。
|
||||
* “<ruby>复制<rt>copy</rt></ruby>”出现在 [《美国法典》第 17 篇,第 106 节][25],即版权法列出的版权所有人可以起诉他人未经许可的行为。
|
||||
* “<ruby>修改<rt>modify</rt></ruby>”既不出现在版权法中,也不出现在专利法中。它可能最接近版权法下的“<ruby>准备衍生作品<rt>prepare derivative works</rt></ruby>”,但也可能涉及改进或其他衍生发明。
|
||||
* 无论是在版权法还是专利法中,“<ruby>合并<rt>merge</rt></ruby>”都没有出现。“<ruby>合并<rt>merger</rt></ruby>”在版权方面有特定的含义,但这显然不是这里的意图。相反,法庭可能会根据其在行业中的含义来解读“合并”,如“合并代码”。
|
||||
* 无论是在版权法还是专利法中,都没有“<ruby>发布<rt>publish</rt></ruby>”。由于“软件”是被发布的内容,根据《[版权法][25]》,它可能最接近于“<ruby>分发<rt>distribute</rt></ruby>”。该法令还包括“公开”表演和展示作品的权利,但这些权利只适用于特定类型的受版权保护的作品,如戏剧、录音和电影。
|
||||
* “<ruby>分发<rt>distribute</rt></ruby>”出现在《[版权法][25]》中。
|
||||
* “<ruby>转授许可<rt>sublicense</rt></ruby>”是知识产权法中的一个总称。转授许可的权利是指把自己的许可证授予他人,有权进行你所许可的部分或全部活动。实际上,MIT 许可证的转授许可的权利在开源代码许可证中并不常见。通常的做法是 Heather Meeker 所说的“<ruby>直接许可<rt>direct licensing</rt></ruby>”方式,在这种方法中,每个获得该软件及其许可证条款副本的人都直接从所有者那里获得授权。任何可能根据 MIT 许可证获得转授许可的人都可能会得到一份许可证副本,告诉他们其也有直接许可证。
|
||||
* “<ruby>出售副本<rt>sell copies</rt></ruby>”是个混杂品。它接近于《[专利法][24]》中的“<ruby>要约出售<rt>offer to sell</rt></ruby>”和“<ruby>出售<rt>sell</rt></ruby>”,但指的是“<ruby>副本<rt>coyies</rt></ruby>”,这是一种版权概念。在版权方面,它似乎接近于“<ruby>分发<rt>distribute</rt></ruby>”,但《[版权法][25]》没有提到销售。
|
||||
* “<ruby>允许被配发了本软件的人这样做<rt>permit persons to whom the Software is furnished to do so</rt></ruby>”似乎是多余的“转授许可”。这也是不必要的,因为获得副本的人也可以直接获得许可证。
|
||||
|
||||
最后,由于这种法律、行业、一般知识产权和一般使用条款的混杂,并不清楚 MIT 许可证是否包括专利许可。一般性语言“<ruby>处置<rt>deal in</rt></ruby>”和一些例子动词,尤其是“使用”,指向了一个专利许可,尽管是一个非常不明确的许可。许可证来自于版权持有人,而版权持有人可能对软件中的发明拥有或不拥有专利权,以及大多数的例子动词和“<ruby>软件<rt>the Software</rt></ruby>”本身的定义,都强烈地指向版权许可证。诸如 [Apache 2.0][8] 之类的较新的宽容开源许可分别具体地处理了版权、专利甚至商标问题。
|
||||
|
||||
#### 三个许可条件
|
||||
|
||||
> subject to the following conditions:
|
||||
|
||||
> 须在下列条件下:
|
||||
|
||||
总有一个陷阱!MIT 许可证有三个!
|
||||
|
||||
如果你不遵守 MIT 许可证的条件,你就得不到许可证提供的许可。因此,如果不能履行条件,至少从理论上说,会让你面临一场诉讼,很可能是一场版权诉讼。
|
||||
|
||||
开源软件的第二个伟大思想是,利用软件对被许可人的价值来激励被许可人遵守条件,即使被许可人没有支付任何许可费用。最后一个伟大思想,在 MIT 许可证中没有,它构建了许可证条件:像 [GNU 通用公共许可证][9](GPL)这样的左版许可证,使用许可证条件来控制如何对修改后的版本进行许可和发布。
|
||||
|
||||
#### 声明条件
|
||||
|
||||
> The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
> 上述版权声明和本许可声明应包含在该软件的所有副本或实质成分中。
|
||||
|
||||
如果你给别人一份软件的副本,你需要包括许可证文本和任何版权声明。这有几个关键目的:
|
||||
|
||||
1. 给别人一个声明,说明他们有权使用该公共许可证下的软件。这是直接授权模式的一个关键部分,在这种模式下,每个用户直接从版权持有人那里获得许可证。
|
||||
2. 让人们知道谁是软件的幕后人物,这样他们就可以得到赞美、荣耀和冷冰冰的现金捐赠。
|
||||
3. 确保保修免责声明和责任限制(在后面)伴随该软件。每个得到该副本的人也应该得到一份这些许可人保护的副本。
|
||||
|
||||
没有什么可以阻止你对提供一个副本、甚至是一个没有源代码的编译形式的副本而收费。但是当你这么做的时候,你不能假装 MIT 代码是你自己的专有代码,也不能在其他许可证下提供。接受的人要知道自己在“公共许可证”下的权利。
|
||||
|
||||
坦率地说,遵守这个条件正在崩溃。几乎所有的开源许可证都有这样的“<ruby>归因<rt>attribution</rt></ruby>”条件。系统和装机软件的制作者往往明白,他们需要为自己的每一个发行版本编制一个声明文件或“许可证信息”屏,并附上库和组件的许可证文本副本。项目监管型基金会在教授这些做法方面起到了重要作用。但是整个 Web 开发者群体还没有取得这种经验。这不能用缺乏工具来解释,工具有很多,也不能用 npm 和其他资源库中的包的高度模块化来解释,它们统一了许可证信息的元数据格式。所有好的 JavaScript 压缩器都有保存许可证标题注释的命令行标志。其他工具可以从包树中串联 `LICENSE` 文件。这实在是没有借口。
|
||||
|
||||
#### 免责声明
|
||||
|
||||
> The Software is provided “as is”, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement.
|
||||
|
||||
> 本软件是“如此”提供的,没有任何形式的明示或暗示的保证,包括但不限于对适销性、特定用途的适用性和不侵权的保证。
|
||||
|
||||
美国几乎每个州都颁布了一个版本的《<ruby>统一商业法典<rt>Uniform Commercial Code</rt></ruby>》(UCC),这是一部规范商业交易的示范性法律。UCC 的第 2 条(加利福尼亚州的“第 2 部分”)规定了商品销售合同,包括了从二手汽车的购买到向制造厂运送大量工业化学品。
|
||||
|
||||
UCC 关于销售合同的某些规则是强制性的。这些规则始终适用,无论买卖双方是否喜欢。其他只是“默认”。除非买卖双方以书面形式选择不适用这些默认,否则 UCC 潜在视作他们希望在 UCC 文本中找到交易的基准规则。默认规则中包括隐含的“<ruby>免责<rt>warranties</rt></ruby>”,或卖方对买方关于所售商品的质量和可用性的承诺。
|
||||
|
||||
关于诸如 MIT 许可证之类的公共许可证是合同(许可方和被许可方之间的可执行协议)还是仅仅是许可证(单向的,但可能有附加条件),这在理论上存在很大争议。关于软件是否被视为“商品”,从而触发 UCC 规则的争论较少。许可人之间没有就赔偿责任进行辩论:如果他们免费提供的软件出现故障、导致问题、无法正常工作或以其他方式引起麻烦,他们不想被起诉和被要求巨额赔偿。这与“<ruby>默示保证<rt>implied warranty</rt></ruby>”的三个默认规则完全相反:
|
||||
|
||||
1. 据 [UCC 第 2-314 节][26],“<ruby>适销性<rt>merchantability</rt></ruby>”的默示保证是一种承诺:“商品”(即软件)的质量至少为平均水平,并经过适当包装和标记,并适用于其常规用途。仅当提供该软件的人是该软件的“商人”时,此保证才适用,这意味着他们从事软件交易,并表现出对软件的熟练程度。
|
||||
2. 据 [UCC 第 2-315 节][27],当卖方知道买方依靠他们提供用于特定目的的货物时,“<ruby>适用于某一特定目的<rt>fitness for a particular purpose</rt></ruby>”的默示保证就会生效。商品实际上需要“适用”这一目的。
|
||||
3. “<ruby>非侵权<rt>noninfringement</rt></ruby>”的默示保证不是 UCC 的一部分,而是一般合同法的共同特征。如果事实证明买方收到的商品侵犯了他人的知识产权,则这种默示的承诺将保护买方。如果根据 MIT 许可证获得的软件实际上并不属于尝试许可该软件的许可人,或者属于他人拥有的专利,那就属于这种情况。
|
||||
|
||||
UCC 的 [第2-316(3)节][28] 要求,选择不适用或“排除”适销性和适用于某一特定目的的默示保证措辞必须醒目。“醒目”意味着书面化或格式化,以引起人们的注意,这与旨在从不小心的消费者身边溜走的细小字体相反。各州法律可以对不侵权的免责声明提出类似的引人注目的要求。
|
||||
|
||||
长期以来,律师们都有一种错觉,认为用“全大写”写任何东西都符合明显的要求。这是不正确的。法庭曾批评律师协会自以为是,而且大多数人都认为,全大写更多的是阻止阅读,而不是强制阅读。同样的,大多数开源许可证的形式都将其免责声明设置为全大写,部分原因是这是在纯文本的 `LICENSE` 文件中唯一明显的方式。我更喜欢使用星号或其他 ASCII 艺术,但那是很久很久以前的事了。
|
||||
|
||||
#### 责任限制
|
||||
|
||||
> In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the Software or the use or other dealings in the Software.
|
||||
|
||||
> 在任何情况下,作者或版权持有人都不对任何索赔、损害或其他责任负责,无论这些追责来自合同、侵权或其它行为中,还是产生于、源于或有关于本软件以及本软件的使用或其它处置。
|
||||
|
||||
MIT 许可证授予软件“免费”许可,但法律并不认为接受免费许可证的人在出错时放弃了起诉的权利,而许可人应该受到责备。“责任限制”,通常与“损害赔偿排除”条款搭配使用,其作用与许可证很像,是不起诉的承诺。但这些都是保护许可人免受被许可人起诉的保护措施。
|
||||
|
||||
一般来说,法庭对责任限制和损害赔偿排除条款的解读非常谨慎,因为这些条款可以将大量的风险从一方转移到另一方。为了保护社会的切身利益,让民众有办法纠正在法庭上所犯的错误,他们“严格地”用措辞限制责任,尽可能地对受其保护的一方进行解读。责任限制必须具体才能成立。特别是在“消费者”合同和其他放弃起诉权的人缺乏成熟度或讨价还价能力的情况下,法庭有时会拒绝尊重那些似乎被埋没在视线之外的措辞。部分是出于这个原因,部分是出于习惯,律师们往往也会给责任限制以全大写处理。
|
||||
|
||||
再往下看,“责任限制”部分是对被许可人可以起诉的金额上限。在开源许可证中,这个上限总是没有钱,0 元,“不承担责任”。相比之下,在商业许可证中,它通常是过去 12 个月内支付的许可证费用的倍数,尽管它通常是经过谈判的。
|
||||
|
||||
“排除”部分具体列出了各种法律主张,即请求赔偿的理由,许可人不能使用。像许多其他法律形式一样,MIT 许可证 提到了“<ruby>违约<rt>of contract</rt></ruby>”行为(即违反合同)和“<ruby>侵权<rt>of tort</rt></ruby>”行为。侵权规则是防止粗心或恶意伤害他人的一般规则。如果你在发短信时在路上撞倒了人,你就犯了侵权行为。如果你的公司销售的有问题的耳机会烧伤人们的耳朵,则说明贵公司已经侵权。如果合同没有明确排除侵权索赔,那么法庭有时会在合同中使用排除措辞以防止合同索赔。出于很好的考虑,MIT 许可证抛出“或其它”字样,只是为了截住奇怪的海事法或其它异国情调的法律主张。
|
||||
|
||||
“<ruby>产生于、源于或有关于<rt>arising from, out of or in connection with</rt></ruby>”这句话是法律起草人固有的、焦虑的不安全感反复出现的症状。关键是,任何与软件有关的诉讼都被这些限制和排除范围所覆盖。万一某些事情可以“<ruby>产生于<rt>arising from</rt></ruby>”,但不能“<ruby>源于<rt>out of</rt></ruby>”或“<ruby>有关于<rt>in connection with</rt></ruby>”,那就最好把这三者都写在里面,所以要把它们打包在一起。更不用说,任何被迫在这部分内容中斤斤计较的法庭将不得不为每个词提出不同的含义,前提是专业的起草者不会在一行中使用不同的词来表示同一件事。更不用说,在实践中,如果法庭对一开始就不利的限制感觉不好,那么他们会更愿意狭隘地解读范围触发器。但我离题了,同样的语言出现在数以百万计的合同中。
|
||||
|
||||
### 总结
|
||||
|
||||
所有这些诡辩都有点像在进教堂的路上吐口香糖。MIT 许可证是一个法律经典,且有效。它绝不是解决所有软件知识产权弊病的灵丹妙药,尤其是它比已经出现的软件专利灾难还要早几十年。但 MIT 风格的许可证发挥了令人钦佩的作用,实现了一个狭隘的目的,用最少的、谨慎的法律工具组合扭转了版权、销售和合同法等棘手的默认规则。在计算机技术的大背景下,它的寿命是惊人的。MIT 许可证已经超过、并将要超过绝大多数软件许可证。我们只能猜测,当它最终失去青睐时,它能提供多少年的忠实法律服务。对于那些无法提供自己的律师的人来说,这尤其慷慨。
|
||||
|
||||
我们已经看到,我们今天所知道的 MIT 许可证是如何成为一套具体的、标准化的条款,使机构特有的、杂乱无章的变化终于有了秩序。
|
||||
|
||||
我们已经看到了它对归因和版权声明的处理方法如何为学术、标准、商业和基金会机构的知识产权管理实践提供信息。
|
||||
|
||||
我们已经看到了 MIT 许可证是如何运行所有人免费试用软件的,但前提是要保护许可人不受担保和责任的影响。
|
||||
|
||||
我们已经看到,尽管有一些生硬的措辞和律师的矫揉造作,但一百七十一个小词可以完成大量的法律工作,为开源软件在知识产权和合同的密集丛林中开辟一条道路。
|
||||
|
||||
我非常感谢所有花时间阅读这篇相当长的文章的人,让我知道他们发现它很有用,并帮助改进它。一如既往,我欢迎你通过 [e-mail][29]、[Twitter][30] 和 [GitHub][31] 发表评论。
|
||||
|
||||
---
|
||||
|
||||
有很多人问,他们在哪里可以读到更多的东西,或者找到其他许可证,比如 GNU 通用公共许可证或 Apache 2.0 许可证。无论你的兴趣是什么,我都会向你推荐以下书籍:
|
||||
|
||||
* Andrew M. St. Laurent 的 [Understanding Open Source & Free Software Licensing][32],来自 O’Reilly。
|
||||
> 我先说这本,因为虽然它有些过时,但它的方法也最接近上面使用的逐行方法。O'Reilly 已经把它[放在网上][33]。
|
||||
* Heather Meeker 的 [Open (Source) for Business][34]
|
||||
> 在我看来,这是迄今为止关于 GNU 通用公共许可证和更广泛的左版的最佳著作。这本书涵盖了历史、许可证、它们的发展,以及兼容性和合规性。这本书是我给那些考虑或处理 GPL 的客户的书。
|
||||
* Larry Rosen 的 [Open Source Licensing][35],来自 Prentice Hall。
|
||||
> 一本很棒的入门书,也可以免费 [在线阅读][36]。对于从零开始的程序员来说,这是开源许可和相关法律的最好介绍。这本在一些具体细节上也有点过时了,但 Larry 的许可证分类法和对开源商业模式的简洁总结经得起时间的考验。
|
||||
|
||||
所有这些都对我作为一个开源许可律师的教育至关重要。它们的作者都是我的职业英雄。请读一读吧 — K.E.M
|
||||
|
||||
我将此文章基于 [Creative Commons Attribution-ShareAlike 4.0 license][37] 授权
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://writing.kemitchell.com/2016/09/21/MIT-License-Line-by-Line.html
|
||||
|
||||
作者:[Kyle E. Mitchell][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[bestony](https://github.com/bestony)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://kemitchell.com/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: http://spdx.org/licenses/MIT
|
||||
[2]: https://fedoraproject.org/wiki/Licensing:MIT?rd=Licensing/MIT
|
||||
[3]: https://opensource.org
|
||||
[4]: https://spdx.org
|
||||
[5]: http://spdx.org/licenses/
|
||||
[6]: https://spdx.org/licenses/JSON
|
||||
[7]: https://www.npmjs.com/package/licensor
|
||||
[8]: https://www.apache.org/licenses/LICENSE-2.0
|
||||
[9]: https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||
[10]: http://spdx.org/licenses/BSD-4-Clause
|
||||
[11]: https://spdx.org/licenses/BSD-3-Clause
|
||||
[12]: https://spdx.org/licenses/BSD-2-Clause
|
||||
[13]: http://www.isc.org/downloads/software-support-policy/isc-license/
|
||||
[14]: http://worksmadeforhire.com/
|
||||
[15]: https://www.eclipse.org/legal/epl-v10.html
|
||||
[16]: https://www.apache.org/licenses/#clas
|
||||
[17]: https://wiki.eclipse.org/ECA
|
||||
[18]: https://en.wikipedia.org/wiki/Feist_Publications,_Inc.,_v._Rural_Telephone_Service_Co.
|
||||
[19]: https://writing.kemitchell.com/2017/02/16/Against-Legislating-the-Nonobvious.html
|
||||
[20]: http://developercertificate.org/
|
||||
[21]: https://github.com/berneout/berneout-pledge
|
||||
[22]: https://github.com/berneout/authors-certificate
|
||||
[23]: https://en.wikipedia.org/wiki/Immediately-invoked_function_expression
|
||||
[24]: https://www.govinfo.gov/app/details/USCODE-2017-title35/USCODE-2017-title35-partIII-chap28-sec271
|
||||
[25]: https://www.govinfo.gov/app/details/USCODE-2017-title17/USCODE-2017-title17-chap1-sec106
|
||||
[26]: https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?sectionNum=2314.&lawCode=COM
|
||||
[27]: https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?sectionNum=2315.&lawCode=COM
|
||||
[28]: https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?sectionNum=2316.&lawCode=COM
|
||||
[29]: mailto:kyle@kemitchell.com
|
||||
[30]: https://twitter.com/kemitchell
|
||||
[31]: https://github.com/kemitchell/writing/tree/master/_posts/2016-09-21-MIT-License-Line-by-Line.md
|
||||
[32]: https://lccn.loc.gov/2006281092
|
||||
[33]: http://www.oreilly.com/openbook/osfreesoft/book/
|
||||
[34]: https://www.amazon.com/dp/1511617772
|
||||
[35]: https://lccn.loc.gov/2004050558
|
||||
[36]: http://www.rosenlaw.com/oslbook.htm
|
||||
[37]: https://creativecommons.org/licenses/by-sa/4.0/legalcode
|
@ -1,8 +1,8 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13172-1.html)
|
||||
[#]: subject: (KDE Customization Guide: Here are 11 Ways You Can Change the Look and Feel of Your KDE-Powered Linux Desktop)
|
||||
[#]: via: (https://itsfoss.com/kde-customization/)
|
||||
[#]: author: (Dimitrios Savvopoulos https://itsfoss.com/author/dimitrios/)
|
||||
@ -10,6 +10,8 @@
|
||||
KDE 桌面环境定制指南
|
||||
======
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202103/03/234801udzaled8erltd78u.jpg)
|
||||
|
||||
[KDE Plasma 桌面][1] 无疑是定制化的巅峰,因为你几乎可以改变任何你想要的东西。你甚至可以让它充当 [平铺窗口管理器][2]。
|
||||
|
||||
KDE Plasma 提供的定制化程度会让初学者感到困惑。用户会迷失在层层深入的选项之中。
|
@ -1,8 +1,8 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13181-1.html)
|
||||
[#]: subject: (5 Tweaks to Customize the Look of Your Linux Terminal)
|
||||
[#]: via: (https://itsfoss.com/customize-linux-terminal/)
|
||||
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
|
||||
@ -10,6 +10,8 @@
|
||||
定制你的 Linux 终端外观的 5 项调整
|
||||
======
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202103/06/232911eg4g65gp4g2ww24u.jpg)
|
||||
|
||||
终端仿真器(或简称终端)是任何 Linux 发行版中不可或缺的一部分。
|
||||
|
||||
当你改变发行版的主题时,往往终端也会自动得到改造。但这并不意味着你不能进一步定制终端。
|
@ -1,8 +1,8 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (Chao-zhi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13178-1.html)
|
||||
[#]: subject: (4 tech jobs for people who don't code)
|
||||
[#]: via: (https://opensource.com/article/21/2/non-engineering-jobs-tech)
|
||||
[#]: author: (Dawn Parzych https://opensource.com/users/dawnparzych)
|
||||
@ -10,13 +10,13 @@
|
||||
不懂代码的人也可以干的 4 种技术工作
|
||||
======
|
||||
|
||||
对于不是工程师的人来说也有很多技术工作可以做。本文作为本系列的第二篇,就具体阐述这些工作。
|
||||
> 对于不是工程师的人来说也有很多技术工作可以做。本文作为本系列的第二篇,就具体阐述这些工作。
|
||||
|
||||
![Looking at a map][1]
|
||||
![](https://img.linux.net.cn/data/attachment/album/202103/06/094041jnrriww0g6ggjn0p.jpg)
|
||||
|
||||
在[本系列的第一篇文章 ][2] 中,我解释了技术行业如何将人员和角色划分为“技术”或“非技术”类别,以及与此相关的问题。科技行业使得那些对科技感兴趣但不懂编程的人很难找到适合自己的角色。
|
||||
在 [本系列的第一篇文章][2] 中,我解释了技术行业如何将人员和角色划分为“技术”或“非技术”类别,以及与此相关的问题。科技行业使得那些对科技感兴趣但不懂编程的人很难找到适合自己的角色。
|
||||
|
||||
如果您对技术或开源感兴趣,但对编程不感兴趣,这也有一些工作适合你。科技公司的任何一个职位都可能需要一个精通科技但不一定会写代码的人。但是,您确实需要了解术语并理解产品。
|
||||
如果你对技术或开源感兴趣,但对编程不感兴趣,这也有一些工作适合你。科技公司的任何一个职位都可能需要一个精通科技但不一定会写代码的人。但是,你确实需要了解术语并理解产品。
|
||||
|
||||
我最近注意到,在诸如技术客户经理、技术产品经理、技术社区经理等职位头衔上增加了“技术”一词。这反映了几年前的趋势,即在头衔上加上“工程师”一词,以表示该职位的技术需要。过了一段时间,每个人的头衔中都有“工程师”这个词,这样的分类就失去了一些吸引力。
|
||||
|
||||
@ -26,13 +26,13 @@
|
||||
>
|
||||
> —— Tim Banks is a buttery biscuit (@elchefe) [December 15,2020][3]
|
||||
|
||||
这遵循了我第一篇文章中的建议:Tim 并不是简单地询问“非技术角色”;他提供了更重要的详细描述。在 Twitter 这样的媒体上,每一个字符都很重要,这些额外的字符会产生不同的效果。这些是技术角色。如果为了节约笔墨,而简单的称呼他们为非技术人员,会改变你的原意,产生不好的影响。
|
||||
这遵循了我第一篇文章中的建议:Tim 并不是简单地询问“非技术角色”;他提供了更重要的详细描述。在 Twitter 这样的媒体上,每一个字符都很重要,这些额外的字符会产生不同的效果。这些是技术角色。如果为了节约笔墨,而简单的称呼他们为“非技术人员”,会改变你的原意,产生不好的影响。
|
||||
|
||||
以下是需要技术知识的非工程类角色的示例。
|
||||
|
||||
### 技术作家
|
||||
### 技术作者
|
||||
|
||||
[技术作家的工作 ][4] 是在两方或多方之间传递事实信息。传统上,技术作家提供有关如何使用技术产品的说明或文档。最近,我看到术语“技术作家”指的是写其他形式内容的人。科技公司希望一个人为他们的开发者读者写博客文章,而这种技巧不同于文案或内容营销。
|
||||
[技术作者的工作][4] 是在两方或多方之间传递事实信息。传统上,技术作者提供有关如何使用技术产品的说明或文档。最近,我看到术语“技术作者”指的是写其他形式内容的人。科技公司希望一个人为他们的开发者读者写博客文章,而这种技巧不同于文案或内容营销。
|
||||
|
||||
**需要的技术技能:**
|
||||
|
||||
@ -41,7 +41,6 @@
|
||||
* 快速跟上新产品或新特性的速度的能力
|
||||
* 在各种环境中创作的技能
|
||||
|
||||
|
||||
**适合人群:**
|
||||
|
||||
* 可以清楚地提供分步说明
|
||||
@ -49,10 +48,9 @@
|
||||
* 对活跃的声音和音乐有热情
|
||||
* 喜欢描述事物和解释原理
|
||||
|
||||
|
||||
### 产品经理
|
||||
|
||||
[产品经理 ][5] 负责领导产品战略。职责可能包括收集客户需求并确定其优先级,撰写业务案例,以及培训销售人员。产品经理跨职能工作,利用创造性和技术技能的结合,成功地推出产品。产品经理需要深厚的产品专业知识。
|
||||
[产品经理][5] 负责领导产品战略。职责可能包括收集客户需求并确定其优先级,撰写业务案例,以及培训销售人员。产品经理跨职能工作,利用创造性和技术技能的结合,成功地推出产品。产品经理需要深厚的产品专业知识。
|
||||
|
||||
**所需技术技能:**
|
||||
|
||||
@ -69,7 +67,7 @@
|
||||
|
||||
### 数据分析师
|
||||
|
||||
数据分析师负责收集和解释数据,以帮助推动业务决策,如是否进入新市场、瞄准哪些客户或在何处投资。这个角色需要知道如何使用所有可用的潜在数据来做出决策。我们常常希望把事情简单化,而数据分析往往过于简单化。获取正确的信息并不像编写查询 “select all limit 10” 来获取前 10 行那么简单。您需要知道要加入哪些表。你需要知道如何分类。您需要知道是否需要在运行查询之前或之后以某种方式清理数据。
|
||||
数据分析师负责收集和解释数据,以帮助推动业务决策,如是否进入新市场、瞄准哪些客户或在何处投资。这个角色需要知道如何使用所有可用的潜在数据来做出决策。我们常常希望把事情简单化,而数据分析往往过于简单化。获取正确的信息并不像编写查询 `select all limit 10` 来获取前 10 行那么简单。你需要知道要加入哪些表。你需要知道如何分类。你需要知道是否需要在运行查询之前或之后以某种方式清理数据。
|
||||
|
||||
**所需技术技能:**
|
||||
|
||||
@ -84,11 +82,9 @@
|
||||
* 享受解决问题的乐趣
|
||||
* 渴望学习和提出问题
|
||||
|
||||
|
||||
|
||||
### 开发者关系
|
||||
|
||||
[Developer relations][6] 是一门相对较新的技术学科。它包括[开发人员代言人 ][7]、 开发人员传道者和开发人员营销等角色。这些角色要求您与开发人员沟通,与他们建立关系,并帮助他们提高工作效率。你向公司倡导开发者的需求,并向开发者代表公司。开发人员关系可以包括撰写文章、创建教程、录制播客、在会议上发言以及创建集成和演示。有人说你需要做过开发人员才能进入开发人员关系。我没有走那条路,我知道很多人没有。
|
||||
[开发者关系][6] 是一门相对较新的技术学科。它包括 <ruby>[开发者代言人][7]<rt> developer advocate</rt></ruby>、<ruby>开发者传道者<rt>developer evangelist</rt></ruby>和<ruby>开发者营销<rt>developer marketing</rt></ruby>等角色。这些角色要求你与开发人员沟通,与他们建立关系,并帮助他们提高工作效率。你向公司倡导开发者的需求,并向开发者代表公司。开发者关系可以包括撰写文章、创建教程、录制播客、在会议上发言以及创建集成和演示。有人说你需要做过开发才能进入开发者关系。我没有走那条路,我知道很多人没有。
|
||||
|
||||
**所需技术技能:**
|
||||
|
||||
@ -105,11 +101,9 @@
|
||||
* 可以为他人辩护
|
||||
* 你很有创意
|
||||
|
||||
|
||||
### 无限的可能性
|
||||
|
||||
这并不是一个完整的清单,并没有列出技术领域中所有的非工程类角色,而是一些不喜欢每天编写代码的人可以尝试的工作。如果你对科技职业感兴趣,看看你的技能和什么角色最适合。可能性是无穷的。为了帮助您完成旅程,在本系列的最后一篇文章中,我将与这些角色的人分享一些建议。
|
||||
有很多非代码方式可以为开源做出贡献:这里有三种选择。
|
||||
这并不是一个完整的清单,并没有列出技术领域中所有的非工程类角色,而是一些不喜欢每天编写代码的人可以尝试的工作。如果你对科技职业感兴趣,看看你的技能和什么角色最适合。可能性是无穷的。为了帮助你完成旅程,在本系列的最后一篇文章中,我将与这些角色的人分享一些建议。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -118,14 +112,14 @@ via: https://opensource.com/article/21/2/non-engineering-jobs-tech
|
||||
作者:[Dawn Parzych][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[Chao-zhi](https://github.com/Chao-zhi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/dawnparzych
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/tips_map_guide_ebook_help_troubleshooting_lightbulb_520.png?itok=L0BQHgjr (Looking at a map)
|
||||
[2]: https://opensource.com/article/21/2/what-does-it-mean-be-technical
|
||||
[2]: https://linux.cn/article-13168-1.html
|
||||
[3]: https://twitter.com/elchefe/status/1338933320147750915?ref_src=twsrc%5Etfw
|
||||
[4]: https://opensource.com/article/17/5/technical-writing-job-interview-tips
|
||||
[5]: https://opensource.com/article/20/2/product-management-open-source-company
|
@ -1,63 +1,57 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13174-1.html)
|
||||
[#]: subject: (A guide to Python virtual environments with virtualenvwrapper)
|
||||
[#]: via: (https://opensource.com/article/21/2/python-virtualenvwrapper)
|
||||
[#]: author: (Ben Nuttall https://opensource.com/users/bennuttall)
|
||||
|
||||
使用 virtualenvwrapper 构建 Python 虚拟环境指南
|
||||
使用 virtualenvwrapper 构建 Python 虚拟环境
|
||||
======
|
||||
虚拟环境是安全地使用不同版本的 Python 和软件包组合的关键。
|
||||
![Python in a coffee cup.][1]
|
||||
|
||||
一段时间以来,Python 已经包含了对管理虚拟环境的支持。Python 3.3 甚至增加了内置的 **venv** 模块,用于创建没有第三方库的环境。Python 程序员使用几种不同的工具来管理他们的环境,我使用的工具叫做 [**virtualenvwrapper**][2]。
|
||||
> 虚拟环境是安全地使用不同版本的 Python 和软件包组合的关键。
|
||||
|
||||
虚拟环境是将你的 Python 项目和它的依赖关系与你的系统安装的 Python 分离的一种方式。如果你使用的是基于 macOS 或 Linux 的操作系统,它很可能在安装中附带了一个 Python 版本,事实上,它很可能依赖于那个特定版本的 Python 才能正常运行。但这是你的计算机,你可能想用它来达到自己的目的。你可能需要安装另一个版本的 Python,而不是操作系统提供的版本。你可能还需要安装一些额外的库。尽管你可以升级你的系统 Python,但不推荐这样做。也可以安装其他库,但你必须注意不要干扰系统所依赖的任何东西。
|
||||
![](https://img.linux.net.cn/data/attachment/album/202103/04/072251y8wkis7c40i8crkw.jpg)
|
||||
|
||||
Python 对管理虚拟环境的支持,已经提供了一段时间了。Python 3.3 甚至增加了内置的 `venv` 模块,用于创建没有第三方库的环境。Python 程序员可以使用几种不同的工具来管理他们的环境,我使用的工具叫做 [virtualenvwrapper][2]。
|
||||
|
||||
虚拟环境是将你的 Python 项目及其依赖关系与你的系统安装的 Python 分离的一种方式。如果你使用的是基于 macOS 或 Linux 的操作系统,它很可能在安装中附带了一个 Python 版本,事实上,它很可能依赖于那个特定版本的 Python 才能正常运行。但这是你的计算机,你可能想用它来达到自己的目的。你可能需要安装另一个版本的 Python,而不是操作系统提供的版本。你可能还需要安装一些额外的库。尽管你可以升级你的系统 Python,但不推荐这样做。你也可以安装其他库,但你必须注意不要干扰系统所依赖的任何东西。
|
||||
|
||||
虚拟环境是创建隔离的关键,你需要安全地修改不同版本的 Python 和不同组合的包。它们还允许你为不同的项目安装同一库的不同版本,这解决了在相同环境满足所有项目需求这个不可能的问题。
|
||||
|
||||
为什么选择 virtualenvwrapper 而不是其他工具?简而言之:
|
||||
|
||||
* 与 `venv` 需要在项目目录内或旁边有一个 `venv` 目录不同,virtualenvwrapper 将所有环境保存在一个地方:默认在 `~/.virtualenvs` 中。
|
||||
* 它提供了用于创建和激活环境的命令,而且激活环境不依赖于找到正确的 `activate` 脚本。它只需要 `workon projectname`(从任何地方)而不需要 `source ~/Projects/flashylights-env/bin/activate`。
|
||||
|
||||
为什么选择 `virtualenvwrapper` 而不是其他工具?简而言之:
|
||||
|
||||
* 与 `venv` 需要在项目目录内或旁边有一个 `venv` 目录不同,`virtualenvwrapper` 将所有环境保存在一个地方:默认在 `~/.virtualenvs` 中。
|
||||
* 它提供了用于创建和激活环境的命令,而且激活环境不依赖于找到正确的 `activate` 脚本。它只需要(从任何地方)`workon projectname`而不需要 `source ~/Projects/flashylights-env/bin/activate`。
|
||||
|
||||
### 开始使用
|
||||
|
||||
首先,花点时间了解一下你的系统 Python 是如何配置的,以及 **pip** 工具是如何工作的。
|
||||
首先,花点时间了解一下你的系统 Python 是如何配置的,以及 `pip` 工具是如何工作的。
|
||||
|
||||
|
||||
以树莓派系统为例,该系统同时安装了 Python 2.7 和 3.7。它还提供了单独的 **pip** 实例,每个版本一个:
|
||||
以树莓派系统为例,该系统同时安装了 Python 2.7 和 3.7。它还提供了单独的 `pip` 实例,每个版本一个:
|
||||
|
||||
* 命令 `python` 运行 Python 2.7,位于 `/usr/bin/python`。
|
||||
* 命令 `python3` 运行 Python 3.7,位于 `/usr/bin/python3`。
|
||||
* 命令 `pip` 安装 Python 2.7 的软件包,位于 `/usr/bin/pip`。
|
||||
* 命令 `pip3` 安装 Python 3.7 的包,位于 `/usr/bin/pip3`。
|
||||
|
||||
|
||||
|
||||
![Python commands on Raspberry Pi][3]
|
||||
|
||||
(Ben Nuttall, [CC BY-SA 4.0][4])
|
||||
|
||||
在开始使用虚拟环境之前,验证一下使用 `python` 和 `pip` 命令的状态是很有用的。关于你的 `pip` 实例的更多信息可以通过运行 `pip debug` 或 `pip3 debug` 命令找到。
|
||||
|
||||
在我运行 Ubuntu Linux 的电脑上几乎是相同的信息(除了它是 Python 3.8)。在我的 Macbook 上也很相似,除了唯一的系统 Python 是 2.6,而我用 `brew` 安装 Python 3.8,所以它位于 `/usr/local/bin/python3` (和 `pip3` 一起)。
|
||||
在我运行 Ubuntu Linux 的电脑上几乎是相同的信息(除了它是 Python 3.8)。在我的 Macbook 上也很相似,除了唯一的系统 Python 是 2.6,而我用 `brew` 安装 Python 3.8,所以它位于 `/usr/local/bin/python3`(和 `pip3` 一起)。
|
||||
|
||||
### 安装 virtualenvwrapper
|
||||
|
||||
你需要使用系统 Python 3 的 `pip` 安装 virtualenvwrapper:
|
||||
你需要使用系统 Python 3 的 `pip` 安装 `virtualenvwrapper`:
|
||||
|
||||
|
||||
```
|
||||
`sudo pip3 install virtualenvwrapper`
|
||||
sudo pip3 install virtualenvwrapper
|
||||
```
|
||||
|
||||
下一步是配置你的 shell 来加载 virtualenvwrapper 命令。你可以通过编辑 shell 的 RC 文件(例如 `.bashrc`、`.bash_profile` 或 `.zshrc`)并添加以下几行:
|
||||
|
||||
下一步是配置你的 shell 来加载 `virtualenvwrapper` 命令。你可以通过编辑 shell 的 RC 文件(例如 `.bashrc`、`.bash_profile` 或 `.zshrc`)并添加以下几行:
|
||||
|
||||
```
|
||||
export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
|
||||
@ -67,56 +61,44 @@ source /usr/local/bin/virtualenvwrapper.sh
|
||||
|
||||
![bashrc][5]
|
||||
|
||||
(Ben Nuttall, [CC BY-SA 4.0][4])
|
||||
|
||||
如果你的 Python 3 位于其他地方,请根据你的设置修改第一行。
|
||||
|
||||
关闭你的终端,然后重新打开它,这样才能生效。第一次打开终端时,你应该看到 virtualenvwrapper 的一些输出。这只会发生一次,因为一些目录是作为设置的一部分被创建的。
|
||||
关闭你的终端,然后重新打开它,这样才能生效。第一次打开终端时,你应该看到 `virtualenvwrapper` 的一些输出。这只会发生一次,因为一些目录是作为设置的一部分被创建的。
|
||||
|
||||
现在你应该可以输入 `mkvirtualenv --version` 命令来验证 virtualenvwrapper 是否已经安装。
|
||||
现在你应该可以输入 `mkvirtualenv --version` 命令来验证 `virtualenvwrapper` 是否已经安装。
|
||||
|
||||
### 创建一个新的虚拟环境
|
||||
|
||||
假设你正在进行一个名为 **flashylights** 的项目。要用这个名字创建一个虚拟环境,请运行该命令:
|
||||
|
||||
假设你正在进行一个名为 `flashylights` 的项目。要用这个名字创建一个虚拟环境,请运行该命令:
|
||||
|
||||
```
|
||||
`mkvirtualenv flashylights`
|
||||
mkvirtualenv flashylights
|
||||
```
|
||||
|
||||
环境已经创建并激活,所以你会看到 `(flashlylights)` 出现在你的提示前:
|
||||
|
||||
![Flashylights prompt][6]
|
||||
|
||||
(Ben Nuttall, [CC BY-SA 4.0][4])
|
||||
|
||||
现在环境被激活了,事情发生了变化。`python` 现在指向一个与你之前在系统中识别的 Python 实例完全不同的 Python 实例。它为你的环境创建了一个目录,并在其中放置了 Python 3 二进制文件、pip 命令等的副本。输入 `which python` 和 `which pip` 来查看它们的位置。
|
||||
|
||||
![Flashylights command][7]
|
||||
|
||||
(Ben Nuttall, [CC BY-SA 4.0][4])
|
||||
|
||||
如果你现在运行一个 Python 程序,你可以用 `python` 代替 `python3` 来运行,你可以用 `pip` 代替 `pip3`。你使用 `pip`安装的任何包都将只安装在这个环境中,它们不会干扰你的其他项目、其他环境或系统安装。
|
||||
|
||||
要停用这个环境,运行 `deactivate` 命令。要重新启用它,运行 `workon flashylights`。
|
||||
|
||||
你可以用 `workon` 或使用 `lsvirtualenv` 列出所有可用的环境。你可以用 `rmvirtualenv flashylights` 删除一个环境。
|
||||
|
||||
|
||||
在你的开发流程中添加虚拟环境是一件明智的事情。根据我的经验,它可以防止我在系统范围内安装我正在试验的库,这可能会导致问题。我发现 virtualenvwrapper 是最简单的可以让我进入流程的方法,并无忧无虑地管理我的项目环境,而不需要考虑太多,也不需要记住太多命令。
|
||||
在你的开发流程中添加虚拟环境是一件明智的事情。根据我的经验,它可以防止我在系统范围内安装我正在试验的库,这可能会导致问题。我发现 `virtualenvwrapper` 是最简单的可以让我进入流程的方法,并无忧无虑地管理我的项目环境,而不需要考虑太多,也不需要记住太多命令。
|
||||
|
||||
### 高级特性
|
||||
|
||||
* 你可以在你的系统上安装多个 Python 版本(例如,在 Ubuntu 上使用 [deadsnakes PPA][8]),并使用该版本创建一个虚拟环境,例如,`mkvirtualenv -p /usr/bin/python3.9 myproject`。
|
||||
* 可以在进入/离开目录时自动激活/停用。
|
||||
* 可以在进入和离开目录时自动激活、停用。
|
||||
* 你可以使用 `postmkvirtualenv` 钩子在每次创建新环境时安装常用工具。
|
||||
|
||||
|
||||
|
||||
更多提示请参见[文档][9]。
|
||||
|
||||
* * *
|
||||
|
||||
_本文基于 Ben Nuttall 在 [Tooling Tuesday 上关于 virtualenvwrapper 的帖子][10],经许可后重用。_
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
@ -126,7 +108,7 @@ via: https://opensource.com/article/21/2/python-virtualenvwrapper
|
||||
作者:[Ben Nuttall][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,265 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (stevenzdg988)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Testing Bash with BATS)
|
||||
[#]: via: (https://opensource.com/article/19/2/testing-bash-bats)
|
||||
[#]: author: (Darin London https://opensource.com/users/dmlond)
|
||||
|
||||
Testing Bash with BATS
|
||||
======
|
||||
The Bash Automated Testing System puts Bash code through the same types of testing processes used by Java, Ruby, and Python developers.
|
||||
|
||||
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/todo_checklist_team_metrics_report.png?itok=oB5uQbzf)
|
||||
|
||||
Software developers writing applications in languages such as Java, Ruby, and Python have sophisticated libraries to help them maintain their software's integrity over time. They create tests that run applications through a series of executions in structured environments to ensure all of their software's aspects work as expected.
|
||||
|
||||
These tests are even more powerful when they're automated in a continuous integration (CI) system, where every push to the source repository causes the tests to run, and developers are immediately notified when tests fail. This fast feedback increases developers' confidence in the functional integrity of their applications.
|
||||
|
||||
The Bash Automated Testing System ([BATS][1]) enables developers writing Bash scripts and libraries to apply the same practices used by Java, Ruby, Python, and other developers to their Bash code.
|
||||
|
||||
### Installing BATS
|
||||
|
||||
The BATS GitHub page includes installation instructions. There are two BATS helper libraries that provide more powerful assertions or allow overrides to the Test Anything Protocol ([TAP][2]) output format used by BATS. These can be installed in a standard location and sourced by all scripts. It may be more convenient to include a complete version of BATS and its helper libraries in the Git repository for each set of scripts or libraries being tested. This can be accomplished using the **[git submodule][3]** system.
|
||||
|
||||
The following commands will install BATS and its helper libraries into the **test** directory in a Git repository.
|
||||
|
||||
```
|
||||
git submodule init
|
||||
git submodule add https://github.com/sstephenson/bats test/libs/bats
|
||||
git submodule add https://github.com/ztombol/bats-assert test/libs/bats-assert
|
||||
git submodule add https://github.com/ztombol/bats-support test/libs/bats-support
|
||||
git add .
|
||||
git commit -m 'installed bats'
|
||||
```
|
||||
|
||||
To clone a Git repository and install its submodules at the same time, use the
|
||||
**\--recurse-submodules** flag to **git clone**.
|
||||
|
||||
Each BATS test script must be executed by the **bats** executable. If you installed BATS into your source code repo's **test/libs** directory, you can invoke the test with:
|
||||
|
||||
```
|
||||
./test/libs/bats/bin/bats <path to test script>
|
||||
```
|
||||
|
||||
Alternatively, add the following to the beginning of each of your BATS test scripts:
|
||||
|
||||
```
|
||||
#!/usr/bin/env ./test/libs/bats/bin/bats
|
||||
load 'libs/bats-support/load'
|
||||
load 'libs/bats-assert/load'
|
||||
```
|
||||
|
||||
and **chmod +x <path to test script>**. This will a) make them executable with the BATS installed in **./test/libs/bats** and b) include these helper libraries. BATS test scripts are typically stored in the **test** directory and named for the script being tested, but with the **.bats** extension. For example, a BATS script that tests **bin/build** should be called **test/build.bats**.
|
||||
|
||||
You can also run an entire set of BATS test files by passing a regular expression to BATS, e.g., **./test/lib/bats/bin/bats test/*.bats**.
|
||||
|
||||
### Organizing libraries and scripts for BATS coverage
|
||||
|
||||
Bash scripts and libraries must be organized in a way that efficiently exposes their inner workings to BATS. In general, library functions and shell scripts that run many commands when they are called or executed are not amenable to efficient BATS testing.
|
||||
|
||||
For example, [build.sh][4] is a typical script that many people write. It is essentially a big pile of code. Some might even put this pile of code in a function in a library. But it's impossible to run a big pile of code in a BATS test and cover all possible types of failures it can encounter in separate test cases. The only way to test this pile of code with sufficient coverage is to break it into many small, reusable, and, most importantly, independently testable functions.
|
||||
|
||||
It's straightforward to add more functions to a library. An added benefit is that some of these functions can become surprisingly useful in their own right. Once you have broken your library function into lots of smaller functions, you can **source** the library in your BATS test and run the functions as you would any other command to test them.
|
||||
|
||||
Bash scripts must also be broken down into multiple functions, which the main part of the script should call when the script is executed. In addition, there is a very useful trick to make it much easier to test Bash scripts with BATS: Take all the code that is executed in the main part of the script and move it into a function, called something like **run_main**. Then, add the following to the end of the script:
|
||||
|
||||
```
|
||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]
|
||||
then
|
||||
run_main
|
||||
fi
|
||||
```
|
||||
|
||||
This bit of extra code does something special. It makes the script behave differently when it is executed as a script than when it is brought into the environment with **source**. This trick enables the script to be tested the same way a library is tested, by sourcing it and testing the individual functions. For example, here is [build.sh refactored for better BATS testability][5].
|
||||
|
||||
### Writing and running tests
|
||||
|
||||
As mentioned above, BATS is a TAP-compliant testing framework with a syntax and output that will be familiar to those who have used other TAP-compliant testing suites, such as JUnit, RSpec, or Jest. Its tests are organized into individual test scripts. Test scripts are organized into one or more descriptive **@test** blocks that describe the unit of the application being tested. Each **@test** block will run a series of commands that prepares the test environment, runs the command to be tested, and makes assertions about the exit and output of the tested command. Many assertion functions are imported with the **bats** , **bats-assert** , and **bats-support** libraries, which are loaded into the environment at the beginning of the BATS test script. Here is a typical BATS test block:
|
||||
|
||||
```
|
||||
@test "requires CI_COMMIT_REF_SLUG environment variable" {
|
||||
unset CI_COMMIT_REF_SLUG
|
||||
assert_empty "${CI_COMMIT_REF_SLUG}"
|
||||
run some_command
|
||||
assert_failure
|
||||
assert_output --partial "CI_COMMIT_REF_SLUG"
|
||||
}
|
||||
```
|
||||
|
||||
If a BATS script includes **setup** and/or **teardown** functions, they are automatically executed by BATS before and after each test block runs. This makes it possible to create environment variables, test files, and do other things needed by one or all tests, then tear them down after each test runs. [**Build.bats**][6] is a full BATS test of our newly formatted **build.sh** script. (The **mock_docker** command in this test will be explained below, in the section on mocking/stubbing.)
|
||||
|
||||
When the test script runs, BATS uses **exec** to run each **@test** block as a separate subprocess. This makes it possible to export environment variables and even functions in one **@test** without affecting other **@test** s or polluting your current shell session. The output of a test run is a standard format that can be understood by humans and parsed or manipulated programmatically by TAP consumers. Here is an example of the output for the **CI_COMMIT_REF_SLUG** test block when it fails:
|
||||
|
||||
```
|
||||
✗ requires CI_COMMIT_REF_SLUG environment variable
|
||||
(from function `assert_output' in file test/libs/bats-assert/src/assert.bash, line 231,
|
||||
in test file test/ci_deploy.bats, line 26)
|
||||
`assert_output --partial "CI_COMMIT_REF_SLUG"' failed
|
||||
|
||||
-- output does not contain substring --
|
||||
substring (1 lines):
|
||||
CI_COMMIT_REF_SLUG
|
||||
output (3 lines):
|
||||
./bin/deploy.sh: join_string_by: command not found
|
||||
oc error
|
||||
Could not login
|
||||
--
|
||||
|
||||
** Did not delete , as test failed **
|
||||
|
||||
1 test, 1 failure
|
||||
```
|
||||
|
||||
Here is the output of a successful test:
|
||||
|
||||
```
|
||||
✓ requires CI_COMMIT_REF_SLUG environment variable
|
||||
```
|
||||
|
||||
### Helpers
|
||||
|
||||
Like any shell script or library, BATS test scripts can include helper libraries to share common code across tests or enhance their capabilities. These helper libraries, such as **bats-assert** and **bats-support** , can even be tested with BATS.
|
||||
|
||||
Libraries can be placed in the same test directory as the BATS scripts or in the **test/libs** directory if the number of files in the test directory gets unwieldy. BATS provides the **load** function that takes a path to a Bash file relative to the script being tested (e.g., **test** , in our case) and sources that file. Files must end with the prefix **.bash** , but the path to the file passed to the **load** function can't include the prefix. **build.bats** loads the **bats-assert** and **bats-support** libraries, a small **[helpers.bash][7]** library, and a **docker_mock.bash** library (described below) with the following code placed at the beginning of the test script below the interpreter magic line:
|
||||
|
||||
```
|
||||
load 'libs/bats-support/load'
|
||||
load 'libs/bats-assert/load'
|
||||
load 'helpers'
|
||||
load 'docker_mock'
|
||||
```
|
||||
|
||||
### Stubbing test input and mocking external calls
|
||||
|
||||
The majority of Bash scripts and libraries execute functions and/or executables when they run. Often they are programmed to behave in specific ways based on the exit status or output ( **stdout** , **stderr** ) of these functions or executables. To properly test these scripts, it is often necessary to make fake versions of these commands that are designed to behave in a specific way during a specific test, a process called "stubbing." It may also be necessary to spy on the program being tested to ensure it calls a specific command, or it calls a specific command with specific arguments, a process called "mocking." For more on this, check out this great [discussion of mocking and stubbing][8] in Ruby RSpec, which applies to any testing system.
|
||||
|
||||
The Bash shell provides tricks that can be used in your BATS test scripts to do mocking and stubbing. All require the use of the Bash **export** command with the **-f** flag to export a function that overrides the original function or executable. This must be done before the tested program is executed. Here is a simple example that overrides the **cat** executable:
|
||||
|
||||
```
|
||||
function cat() { echo "THIS WOULD CAT ${*}" }
|
||||
export -f cat
|
||||
```
|
||||
|
||||
This method overrides a function in the same manner. If a test needs to override a function within the script or library being tested, it is important to source the tested script or library before the function is stubbed or mocked. Otherwise, the stub/mock will be replaced with the actual function when the script is sourced. Also, make sure to stub/mock before you run the command you're testing. Here is an example from **build.bats** that mocks the **raise** function described in **build.sh** to ensure a specific error message is raised by the login fuction:
|
||||
|
||||
```
|
||||
@test ".login raises on oc error" {
|
||||
source ${profile_script}
|
||||
function raise() { echo "${1} raised"; }
|
||||
export -f raise
|
||||
run login
|
||||
assert_failure
|
||||
assert_output -p "Could not login raised"
|
||||
}
|
||||
```
|
||||
|
||||
Normally, it is not necessary to unset a stub/mock function after the test, since **export** only affects the current subprocess during the **exec** of the current **@test** block. However, it is possible to mock/stub commands (e.g. **cat** , **sed** , etc.) that the BATS **assert** * functions use internally. These mock/stub functions must be **unset** before these assert commands are run, or they will not work properly. Here is an example from **build.bats** that mocks **sed** , runs the **build_deployable** function, and unsets **sed** before running any assertions:
|
||||
|
||||
```
|
||||
@test ".build_deployable prints information, runs docker build on a modified Dockerfile.production and publish_image when its not a dry_run" {
|
||||
local expected_dockerfile='Dockerfile.production'
|
||||
local application='application'
|
||||
local environment='environment'
|
||||
local expected_original_base_image="${application}"
|
||||
local expected_candidate_image="${application}-candidate:${environment}"
|
||||
local expected_deployable_image="${application}:${environment}"
|
||||
source ${profile_script}
|
||||
mock_docker build --build-arg OAUTH_CLIENT_ID --build-arg OAUTH_REDIRECT --build-arg DDS_API_BASE_URL -t "${expected_deployable_image}" -
|
||||
function publish_image() { echo "publish_image ${*}"; }
|
||||
export -f publish_image
|
||||
function sed() {
|
||||
echo "sed ${*}" >&2;
|
||||
echo "FROM application-candidate:environment";
|
||||
}
|
||||
export -f sed
|
||||
run build_deployable "${application}" "${environment}"
|
||||
assert_success
|
||||
unset sed
|
||||
assert_output --regexp "sed.*${expected_dockerfile}"
|
||||
assert_output -p "Building ${expected_original_base_image} deployable ${expected_deployable_image} FROM ${expected_candidate_image}"
|
||||
assert_output -p "FROM ${expected_candidate_image} piped"
|
||||
assert_output -p "build --build-arg OAUTH_CLIENT_ID --build-arg OAUTH_REDIRECT --build-arg DDS_API_BASE_URL -t ${expected_deployable_image} -"
|
||||
assert_output -p "publish_image ${expected_deployable_image}"
|
||||
}
|
||||
```
|
||||
|
||||
Sometimes the same command, e.g. foo, will be invoked multiple times, with different arguments, in the same function being tested. These situations require the creation of a set of functions:
|
||||
|
||||
* mock_foo: takes expected arguments as input, and persists these to a TMP file
|
||||
* foo: the mocked version of the command, which processes each call with the persisted list of expected arguments. This must be exported with export -f.
|
||||
* cleanup_foo: removes the TMP file, for use in teardown functions. This can test to ensure that a @test block was successful before removing.
|
||||
|
||||
|
||||
|
||||
Since this functionality is often reused in different tests, it makes sense to create a helper library that can be loaded like other libraries.
|
||||
|
||||
A good example is **[docker_mock.bash][9]**. It is loaded into **build.bats** and used in any test block that tests a function that calls the Docker executable. A typical test block using **docker_mock** looks like:
|
||||
|
||||
```
|
||||
@test ".publish_image fails if docker push fails" {
|
||||
setup_publish
|
||||
local expected_image="image"
|
||||
local expected_publishable_image="${CI_REGISTRY_IMAGE}/${expected_image}"
|
||||
source ${profile_script}
|
||||
mock_docker tag "${expected_image}" "${expected_publishable_image}"
|
||||
mock_docker push "${expected_publishable_image}" and_fail
|
||||
run publish_image "${expected_image}"
|
||||
assert_failure
|
||||
assert_output -p "tagging ${expected_image} as ${expected_publishable_image}"
|
||||
assert_output -p "tag ${expected_image} ${expected_publishable_image}"
|
||||
assert_output -p "pushing image to gitlab registry"
|
||||
assert_output -p "push ${expected_publishable_image}"
|
||||
}
|
||||
```
|
||||
|
||||
This test sets up an expectation that Docker will be called twice with different arguments. With the second call to Docker failing, it runs the tested command, then tests the exit status and expected calls to Docker.
|
||||
|
||||
One aspect of BATS introduced by **mock_docker.bash** is the **${BATS_TMPDIR}** environment variable, which BATS sets at the beginning to allow tests and helpers to create and destroy TMP files in a standard location. The **mock_docker.bash** library will not delete its persisted mocks file if a test fails, but it will print where it is located so it can be viewed and deleted. You may need to periodically clean old mock files out of this directory.
|
||||
|
||||
One note of caution regarding mocking/stubbing: The **build.bats** test consciously violates a dictum of testing that states: [Don't mock what you don't own!][10] This dictum demands that calls to commands that the test's developer didn't write, like **docker** , **cat** , **sed** , etc., should be wrapped in their own libraries, which should be mocked in tests of scripts that use them. The wrapper libraries should then be tested without mocking the external commands.
|
||||
|
||||
This is good advice and ignoring it comes with a cost. If the Docker CLI API changes, the test scripts will not detect this change, resulting in a false positive that won't manifest until the tested **build.sh** script runs in a production setting with the new version of Docker. Test developers must decide how stringently they want to adhere to this standard, but they should understand the tradeoffs involved with their decision.
|
||||
|
||||
### Conclusion
|
||||
|
||||
Introducing a testing regime to any software development project creates a tradeoff between a) the increase in time and organization required to develop and maintain code and tests and b) the increased confidence developers have in the integrity of the application over its lifetime. Testing regimes may not be appropriate for all scripts and libraries.
|
||||
|
||||
In general, scripts and libraries that meet one or more of the following should be tested with BATS:
|
||||
|
||||
* They are worthy of being stored in source control
|
||||
* They are used in critical processes and relied upon to run consistently for a long period of time
|
||||
* They need to be modified periodically to add/remove/modify their function
|
||||
* They are used by others
|
||||
|
||||
|
||||
|
||||
Once the decision is made to apply a testing discipline to one or more Bash scripts or libraries, BATS provides the comprehensive testing features that are available in other software development environments.
|
||||
|
||||
Acknowledgment: I am indebted to [Darrin Mann][11] for introducing me to BATS testing.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/2/testing-bash-bats
|
||||
|
||||
作者:[Darin London][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[stevenzdg988](https://github.com/stevenzdg988)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/dmlond
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://github.com/sstephenson/bats
|
||||
[2]: http://testanything.org/
|
||||
[3]: https://git-scm.com/book/en/v2/Git-Tools-Submodules
|
||||
[4]: https://github.com/dmlond/how_to_bats/blob/preBats/build.sh
|
||||
[5]: https://github.com/dmlond/how_to_bats/blob/master/bin/build.sh
|
||||
[6]: https://github.com/dmlond/how_to_bats/blob/master/test/build.bats
|
||||
[7]: https://github.com/dmlond/how_to_bats/blob/master/test/helpers.bash
|
||||
[8]: https://www.codewithjason.com/rspec-mocks-stubs-plain-english/
|
||||
[9]: https://github.com/dmlond/how_to_bats/blob/master/test/docker_mock.bash
|
||||
[10]: https://github.com/testdouble/contributing-tests/wiki/Don't-mock-what-you-don't-own
|
||||
[11]: https://github.com/dmann
|
@ -1,99 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (robsean)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Run your favorite Windows applications on Linux)
|
||||
[#]: via: (https://opensource.com/article/21/2/linux-wine)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
Run your favorite Windows applications on Linux
|
||||
======
|
||||
WINE is an open source project that helps many Windows applications run
|
||||
on Linux as if they were native programs.
|
||||
![Computer screen with files or windows open][1]
|
||||
|
||||
In 2021, there are more reasons why people love Linux than ever before. In this series, I'll share 21 different reasons to use Linux. Here's how switching from Windows to Linux can be made seamless with WINE.
|
||||
|
||||
Do you have an application that only runs on Windows? Is that one application the one and only thing holding you back from switching to Linux? If so, you'll be happy to know about WINE, an open source project that has all but reinvented key Windows libraries so that applications compiled for Windows can run on Linux.
|
||||
|
||||
WINE stands for "Wine Is Not an Emulator," which references the code driving this technology. Open source developers have worked since 1993 to translate any incoming Windows API calls an application makes to [POSIX][2] calls.
|
||||
|
||||
This is an astonishing feat of programming, especially given that the project operated independently, with no help from Microsoft (to say the least), but there are limits. The farther an application strays from the "core" of the Windows API, the less likely it is that WINE could have anticipated its requests. There are vendors that may make up for this, notably [Codeweavers][3] and [Valve Software][4]. There's no coordination between the producers of the applications requiring translation and the people and companies doing the translation, so there can be some lag time between, for instance, an updated software title and when it earns a "gold" status from [WINE headquarters][5].
|
||||
|
||||
However, if you're looking to run a well-known Windows application on Linux, the chances are good that WINE is ready for it.
|
||||
|
||||
### Installing WINE
|
||||
|
||||
You can install WINE from your Linux distribution's software repository. On Fedora, CentOS Stream, or RHEL:
|
||||
|
||||
|
||||
```
|
||||
`$ sudo dnf install wine`
|
||||
```
|
||||
|
||||
On Debian, Linux Mint, Elementary, and similar:
|
||||
|
||||
|
||||
```
|
||||
`$ sudo apt install wine`
|
||||
```
|
||||
|
||||
WINE isn't an application that you launch on its own. It's a backend that gets invoked when a Windows application is launched. Your first interaction with WINE will most likely occur when you launch the installer of a Windows application.
|
||||
|
||||
### Installing an application
|
||||
|
||||
[TinyCAD][6] is a nice open source application for designing circuits, but it's only available for Windows. While it is a small application, it does incorporate some .NET components, so that ought to stress test WINE a little.
|
||||
|
||||
First, download the installer for TinyCAD. As is often the case for Windows installers, it's a `.exe` file. Once downloaded, double-click the file to launch it.
|
||||
|
||||
![WINE TinyCAD installation wizard][7]
|
||||
|
||||
WINE installation wizard for TinyCAD
|
||||
|
||||
Step through the installer as you would on Windows. It's usually best to accept the defaults, especially where WINE is concerned. The WINE environment is largely self-contained, hidden away on your hard drive in a **drive_c** directory that gets used by a Windows application as the fake root directory of the file system.
|
||||
|
||||
![WINE TinyCAD installation and destination drive][8]
|
||||
|
||||
WINE TinyCAD destination drive
|
||||
|
||||
Once it's installed, the application usually offers to launch for you. If you're ready to test it out, launch the application.
|
||||
|
||||
### Launching a Windows application
|
||||
|
||||
Aside from the first launch immediately after installation, you normally launch a WINE application the same way as you launch a native Linux application. Whether you use an applications menu or an Activities screen or just type the application's name into a runner, desktop Windows applications running in WINE are treated essentially as native applications on Linux.
|
||||
|
||||
![TinyCAD running with WINE][9]
|
||||
|
||||
TinyCAD running with WINE support
|
||||
|
||||
### When WINE fails
|
||||
|
||||
Most applications I run in WINE, TinyCAD included, run as expected. There are exceptions, however. In those cases, you can either wait a few months to see whether WINE developers (or, if it's a game, Valve Software) manage to catch up, or you can contact a vendor like Codeweavers to find out whether they sell support for the application you require.
|
||||
|
||||
### WINE is cheating, but in a good way
|
||||
|
||||
Some Linux users feel that if you use WINE, you're "cheating" on Linux. It might feel that way, but WINE is an open source project that's enabling users to switch to Linux and still run required applications for their work or hobbies. If WINE solves your problem and lets you use Linux, then use it, and embrace the flexibility of Linux.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/2/linux-wine
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/browser_screen_windows_files.png?itok=kLTeQUbY (Computer screen with files or windows open)
|
||||
[2]: https://opensource.com/article/19/7/what-posix-richard-stallman-explains
|
||||
[3]: https://www.codeweavers.com/crossover
|
||||
[4]: https://github.com/ValveSoftware/Proton
|
||||
[5]: http://winehq.org
|
||||
[6]: https://sourceforge.net/projects/tinycad/
|
||||
[7]: https://opensource.com/sites/default/files/wine-tinycad-install.jpg
|
||||
[8]: https://opensource.com/sites/default/files/wine-tinycad-drive_0.jpg
|
||||
[9]: https://opensource.com/sites/default/files/wine-tinycad-running.jpg
|
@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (MjSeven)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
@ -2,7 +2,7 @@
|
||||
[#]: via: (https://opensource.com/article/21/2/path-freedos)
|
||||
[#]: author: (Kevin O'Brien https://opensource.com/users/ahuka)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (robsean)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
@ -1,86 +0,0 @@
|
||||
[#]: subject: (3 Linux terminals you need to try)
|
||||
[#]: via: (https://opensource.com/article/21/2/linux-terminals)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
3 Linux terminals you need to try
|
||||
======
|
||||
Linux gives you the ability to choose the terminal interface you
|
||||
like—not one it imposes.
|
||||
![4 different color terminal windows with code][1]
|
||||
|
||||
In 2021, there are more reasons why people love Linux than ever before. In this series, I'll share 21 different reasons to use Linux. The ability to choose your own terminal is a big reason to use Linux.
|
||||
|
||||
Many people think once you've used one terminal interface, you've used them all. But users who love the terminal know there are minor but important differences between them. This article looks at three of my favorites.
|
||||
|
||||
Before diving into them, though, it's important to understand the difference between a shell and a terminal. A terminal (technically a _terminal emulator_, because terminals used to be physical hardware devices) is an application that runs in a window on your desktop. A shell is the engine that's visible to you in a terminal window. Popular shells are [Bash][2], [tcsh][3], and [zsh][4], and they all run in a terminal.
|
||||
|
||||
It almost goes without saying on modern Linux, but all the terminals in this article have tabbed interfaces.
|
||||
|
||||
### Xfce terminal
|
||||
|
||||
![Xfce ][5]
|
||||
|
||||
(Seth Kenlon, [CC BY-SA 4.0][6])
|
||||
|
||||
The [lightweight Xfce desktop][7] provides a lightweight terminal that nicely balances features with simplicity. It provides access to the shell (as expected), and it has easy access to several important configuration options. You can set which characters break a string when you double-click on text, choose your default character encoding, and disable Alt shortcuts to the terminal's window so that your favorite Bash shortcuts are passed through to the shell. You can also set a font and a new color theme or load a color theme from a list of common presets. It's even got an optional toolbar across the top for easy access to your favorite functions.
|
||||
|
||||
For me, Xfce's star feature is how easy it is to vary the background color for each tab you open. This is a priceless option when running a remote shell on a server—it has prevented me from making stupid mistakes by constantly keeping me aware of which tab I'm in.
|
||||
|
||||
### rxvt-unicode
|
||||
|
||||
![rxvt][8]
|
||||
|
||||
(Seth Kenlon, [CC BY-SA 4.0][6])
|
||||
|
||||
The [rxvt terminal][9] is my favorite lightweight console. It's got many of the features you'd find in the old-school [xterm][10] terminal emulator but is more extensible. Its configuration is defined in `~/.Xdefaults`, so there's no preferences panel or settings menu—but this makes it very easy to manage and back up your setup. Using some Perl libraries, rxvt has tabs, and through xrdb, it has access to fonts and any color theme you can think of. You can set attributes like `URxvt.urlLancher: firefox` to set what web browser launches when you open URLs, change the look of the scrollbar, modify keyboard shortcuts, and do much more.
|
||||
|
||||
The original rxvt didn't support Unicode (because at the time, Unicode didn't exist) but the `rxvt-unicode` (sometimes also called `urxvt`) package provides a patched version with full Unicode support.
|
||||
|
||||
I keep rxvt on every computer because it's the best all-purpose terminal for me. It's not necessarily the best terminal for all users (it has no drag-and-drop interface, for instance). Still, for intermediate to advanced users looking for a fast and flexible terminal, rxvt is an easy choice.
|
||||
|
||||
### Konsole
|
||||
|
||||
![Konsole][11]
|
||||
|
||||
(Seth Kenlon, [CC BY-SA 4.0][6])
|
||||
|
||||
Konsole, the KDE Plasma desktop's terminal, was the first terminal I used after switching to Linux, so it's the standard to which I hold all others. It does set a high bar. Konsole has all the usual nice features (and then some), such as easy color themes plus profile support, font selection, encoding, detachable tabs, renamable tabs, and so on. But that's to be expected on a modern desktop (at least, it is if your desktop is running Plasma).
|
||||
|
||||
Konsole is light-years (or maybe a few months) ahead of other terminals. It can split its window vertically or horizontally. You can copy input to all tabs (as with [tmux][12]). You can set it to monitor itself for either silence or activity and configure notifications. If you use KDE Connect on your Android phone, that means you can get notifications on your mobile when a job finishes! You can save Konsole's output to a text or HTML file, bookmark open tabs, clone tabs, adjust your search settings, and more.
|
||||
|
||||
Konsole is a true power user's terminal, yet it's also great for new users. You can drag and drop files into Konsole to change the directory to a specific location on your hard drive or paste in the path or even copy a file to Konsole's current working directory. It makes using the terminal easy, and that's something that translates across all users.
|
||||
|
||||
### Try a terminal
|
||||
|
||||
Is your aesthetic a dark office and the warm glow of green text against a black background? Or do you prefer a bright sunlit lounge and a soothing ink-black font on a paper-crisp screen? No matter your vision of a perfect computer setup, if you love the efficiency and clarity of communicating with your operating system by typing commands, then Linux has an interface for you.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/2/linux-terminals
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/freedos.png?itok=aOBLy7Ky (4 different color terminal windows with code)
|
||||
[2]: https://opensource.com/resources/what-bash
|
||||
[3]: https://opensource.com/article/20/8/tcsh
|
||||
[4]: https://opensource.com/article/19/9/getting-started-zsh
|
||||
[5]: https://opensource.com/sites/default/files/uploads/terminal-xfce.jpg (Xfce )
|
||||
[6]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[7]: https://opensource.com/article/19/12/xfce-linux-desktop
|
||||
[8]: https://opensource.com/sites/default/files/uploads/terminal-rxvt.jpg (rxvt)
|
||||
[9]: https://opensource.com/article/19/10/why-use-rxvt-terminal
|
||||
[10]: https://opensource.com/article/20/7/xterm
|
||||
[11]: https://opensource.com/sites/default/files/uploads/terminal-konsole.jpg (Konsole)
|
||||
[12]: https://opensource.com/article/20/1/tmux-console
|
@ -2,7 +2,7 @@
|
||||
[#]: via: (https://opensource.com/article/21/3/linux-server)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
@ -0,0 +1,71 @@
|
||||
[#]: subject: (5 signs you might be a Rust programmer)
|
||||
[#]: via: (https://opensource.com/article/21/3/rust-programmer)
|
||||
[#]: author: (Mike Bursell https://opensource.com/users/mikecamel)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
5 signs you might be a Rust programmer
|
||||
======
|
||||
During my journey to learning Rust, I've noticed a few common behaviors
|
||||
of fellow Rustaceans.
|
||||
![name tag that says hello my name is open source][1]
|
||||
|
||||
I'm a fairly recent [convert to Rust][2], which I started to learn around the end of April 2020. But, like many converts, I'm an enthusiastic evangelist. I'm also not a very good Rustacean, truth be told, in that my coding style isn't great, and I don't write particularly idiomatic Rust. I suspect this is partly because I never really finished learning Rust before diving in and writing quite a lot of code (some of which is coming back to haunt me) and partly because I'm just not that good a programmer.
|
||||
|
||||
But I love Rust, and so should you. It's friendly—well, more friendly than C or C++; it's ready for low-level systems tasks—more so than Python, it's well-structured—more than Perl; and, best of all, it's completely open source from the design level up—much more than Java, for instance.
|
||||
|
||||
Despite my lack of expertise, I noticed a few things that I suspect are common to many Rust enthusiasts and programmers. If you say "yes" to the following five signs (the first of which was sparked by some exciting recent news), you, too, might be a Rust programmer.
|
||||
|
||||
### 1\. The word "foundation" excites you
|
||||
|
||||
For Rust programmers, the word "foundation" will no longer be associated first and foremost with Isaac Asimov but with the newly formed [Rust Foundation][3]. Microsoft, Huawei, Google, AWS, and Mozilla are providing the directors (and presumably most of the initial funding) for the Foundation, which will look after all aspects of the language, "heralding Rust's arrival as an enterprise production-ready technology," [according to interim executive director][4] Ashley Williams. (On a side note, it's great to see a woman heading up such a major industry initiative.)
|
||||
|
||||
The Foundation seems committed to safeguarding the philosophy of Rust and ensuring that everybody has the opportunity to get involved. Rust is, in many ways, a poster-child example of an open source project. Not that it's perfect (neither the language nor the community), but in that there seem to be sufficient enthusiasts who are dedicated to preserving the high-involvement, low-bar approach to community, which I think of as core to much of open source. I strongly welcome the move, which I think can only help promote Rust's adoption and maturity over the coming years and months.
|
||||
|
||||
### 2\. You get frustrated by newsfeed references to Rust (the game)
|
||||
|
||||
There's another computer-related thing out there that goes by the name "Rust," and it's a "multi-player only survival video game." It's newer than Rust the language (having been announced in 2013 and released in 2018), but I was once searching for Rust-related swag and made the mistake of searching for the game by that name. The interwebs being what they are, this meant that my news feed is now infected with this alternative Rust beast, and I now get random updates from their fandom and PR folks. This is low-key annoying, but I'm pretty sure I'm not alone in the Rust (language) community. I strongly suggest that if you _do_ want to find out more about this upstart in the computing world, you use a privacy-improving (I refuse to say "privacy-preserving") [open source browser][5] to do your research.
|
||||
|
||||
### 3\. The word "unsafe" makes you recoil in horror
|
||||
|
||||
Rust (the language, again) does a _really_ good job of helping you do the Right Thing™, certainly in terms of memory safety, which is a major concern within C and C++ (not because it's impossible but because it's really hard to get right consistently). Dave Herman wrote a post in 2016 on why safety is such a positive attribute of the Rust language: [_Safety is Rust's fireflower_][6]. Safety (memory, type safety) may not be glamourous, but it's something you become used to—and grateful for—as you write more Rust, particularly if you're involved in any systems programming, which is where Rust often excels.
|
||||
|
||||
Now, Rust doesn't _stop_ you from doing the Wrong Thing™, but it does make you make a conscious decision when you wish to go outside the bounds of safety by making you use the `unsafe` keyword. This is good not only for you, as it will (hopefully) make you think really, really carefully about what you're putting in any code block that uses it; it is also good for anyone reading your code. It's a trigger-word that makes any half-sane Rustacean shiver at least slightly, sit upright in their chair, and think, "hmm, what's going on here? I need to pay special attention." If you're lucky, the person reading your code may be able to think of ways of rewriting it such that it _does_ make use of Rust's safety features or at least reduces the amount of unsafe code that gets committed and released.
|
||||
|
||||
### 4\. You wonder why there's no emoji for `?;` or `{:?}` or `::<>`
|
||||
|
||||
Everybody loves (to hate) the turbofish (`::<>`) but there are other semantic constructs that you see regularly in Rust code. In particular, `{:?}` (for string formatting) and `?;` (`?` is a way of propagating errors up the calling stack, and `;` ends the line/block, so you often see them together). They're so common in Rust code that you just learn to parse them as you go, and they're also so useful that I sometimes wonder why they've not made it into normal conversation, at least as emojis. There are probably others, too. What would be your suggestions?
|
||||
|
||||
### 5\. Clippy is your friend (and not an animated paperclip)
|
||||
|
||||
Clippy, the Microsoft animated paperclip, was a "feature" that Office users learned very quickly to hate and has become the starting point for many [memes][7]. On the other hand, `cargo clippy` is one of those [amazing Cargo commands][8] that should become part of every Rust programmer's toolkit. Clippy is a language linter and helps improve your code to make it cleaner, tidier, more legible, more idiomatic, and generally less embarrassing when you share it with your colleagues or the rest of the world. Cargo has arguably rehabilitated the name "Clippy," and although it's not something I'd choose to name one of my kids, I don't feel a sense of unease whenever I come across the term on the web anymore.
|
||||
|
||||
* * *
|
||||
|
||||
_This article was originally published on [Alice, Eve, and Bob][9] and is reprinted with the author's permission._
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/3/rust-programmer
|
||||
|
||||
作者:[Mike Bursell][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/mikecamel
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/EDU_OSDC_IntroOS_520x292_FINAL.png?itok=woiZamgj (name tag that says hello my name is open source)
|
||||
[2]: https://opensource.com/article/20/6/why-rust
|
||||
[3]: https://foundation.rust-lang.org/
|
||||
[4]: https://foundation.rust-lang.org/posts/2021-02-08-hello-world/
|
||||
[5]: https://opensource.com/article/19/7/open-source-browsers
|
||||
[6]: https://www.thefeedbackloop.xyz/safety-is-rusts-fireflower/
|
||||
[7]: https://knowyourmeme.com/memes/clippy
|
||||
[8]: https://opensource.com/article/20/11/commands-rusts-cargo
|
||||
[9]: https://aliceevebob.com/2021/02/09/5-signs-that-you-may-be-a-rust-programmer/
|
@ -1,104 +0,0 @@
|
||||
[#]: subject: (Guake Terminal: A Customizable Linux Terminal for Power Users [Inspired by an FPS Game])
|
||||
[#]: via: (https://itsfoss.com/guake-terminal/)
|
||||
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
Guake Terminal: A Customizable Linux Terminal for Power Users [Inspired by an FPS Game]
|
||||
======
|
||||
|
||||
_**Brief: Quickly access your terminal that is customizable and powerful for a variety of users with Guake Terminal emulator.**_
|
||||
|
||||
### Guake Terminal: Top-Down Terminal for GNOME Desktop
|
||||
|
||||
![][1]
|
||||
|
||||
[Guake][2] is a terminal emulator that’s tailored for GNOME desktop with a top-down design.
|
||||
|
||||
It was originally inspired from the terminal seen in an FPS game ([Quake][3]). Even though it was initially built as a quick and accessible terminal, it is much more than that.
|
||||
|
||||
Guake terminal offers a ton of features, and customizable options. Here, I’ll highlight the key features of the terminal along with the process of getting it installed on any of your Linux distribution.
|
||||
|
||||
### Features of Guake Terminal
|
||||
|
||||
![][4]
|
||||
|
||||
* Keyboard Shortcut (**F12**) to launch the terminal anywhere as an overlay
|
||||
* Guake terminal runs in the background for persistent access
|
||||
* Ability to split tabs horizontally and vertically
|
||||
* Change the default shell from available options (if any)
|
||||
* Re-alignment option
|
||||
* Change appearance of the terminal from a wide selection of color palettes
|
||||
* Ability to save the content of the terminal to a file using GUI option
|
||||
* Toggle Full screen option when needed
|
||||
* You can easily save the tabs or open new tabs when needed
|
||||
* Ability to restore tabs
|
||||
* Option to configure and learn new keyboard shortcuts to quickly access the terminal and perform tasks
|
||||
* Change colors of specific tabs
|
||||
* Easily rename the tabs to quickly access what you already need
|
||||
* Quick open feature to open text files directly from your terminal on your favorite editor with a click
|
||||
* Ability to add your own command or scripts when starting up or showing up the Guake terminal
|
||||
* Multi-monitor support
|
||||
|
||||
|
||||
|
||||
![][5]
|
||||
|
||||
Just to have fun, you can do a great deal of things. But, I also believe that power users can make use of the features to make their terminal experience easier and more productive.
|
||||
|
||||
For the time I used it to test out a few things and write this article, I felt like I was summoning the terminal to be honest. So, I definitely find it cool!
|
||||
|
||||
### Installing Guake Terminal on Linux
|
||||
|
||||
![][6]
|
||||
|
||||
**Guake Terminal is available through the default repositories on Ubuntu, Fedora, and Arch**.
|
||||
|
||||
You can follow its official instructions to know the commands you can use or if you’re using an Ubuntu-based distro, simply type in:
|
||||
|
||||
```
|
||||
sudo apt install guake
|
||||
```
|
||||
|
||||
Do note that you may not get the latest version using this method. So, if you want to have the latest version, you can opt to use the PPA by [Linux Uprising][7] to get the latest version:
|
||||
|
||||
```
|
||||
sudo add-apt-repository ppa:linuxuprising/guake
|
||||
sudo apt update
|
||||
sudo apt install guake
|
||||
```
|
||||
|
||||
In either case, you can also get it using [Pypi][8] or from source by referring to the [official documentation][9] or the [GitHub page][10].
|
||||
|
||||
[Guake Terminal][10]
|
||||
|
||||
What do you think about Guake Terminal? Do you think of it as a useful terminal emulator? Anything similar that you know of?
|
||||
|
||||
Feel free to let me know what you think in the comments down below.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/guake-terminal/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/02/guake-terminal-1.png?resize=800%2C363&ssl=1
|
||||
[2]: http://guake-project.org/
|
||||
[3]: https://quake.bethesda.net/en
|
||||
[4]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/02/guake-terminal.jpg?resize=800%2C245&ssl=1
|
||||
[5]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/02/guake-preferences.jpg?resize=800%2C559&ssl=1
|
||||
[6]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2021/02/guake-terminal-2.png?resize=800%2C432&ssl=1
|
||||
[7]: https://www.linuxuprising.com/
|
||||
[8]: https://pypi.org/
|
||||
[9]: https://guake.readthedocs.io/en/latest/user/installing.html
|
||||
[10]: https://github.com/Guake/guake
|
@ -0,0 +1,509 @@
|
||||
[#]: subject: (Host your website with dynamic content and a database on a Raspberry Pi)
|
||||
[#]: via: (https://opensource.com/article/21/3/web-hosting-raspberry-pi)
|
||||
[#]: author: (Marty Kalin https://opensource.com/users/mkalindepauledu)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
Host your website with dynamic content and a database on a Raspberry Pi
|
||||
======
|
||||
You can use free software to support a web application on a very
|
||||
lightweight computer.
|
||||
![Digital creative of a browser on the internet][1]
|
||||
|
||||
Raspberry Pi's single-board machines have set the mark for cheap, real-world computing. With its model 4, the Raspberry Pi can host web applications with a production-grade web server, a transactional database system, and dynamic content through scripting. This article explains the installation and configuration details with a full code example. Welcome to web applications hosted on a very lightweight computer.
|
||||
|
||||
### The snowfall application
|
||||
|
||||
Imagine a downhill ski area large enough to have microclimates, which can mean dramatically different snowfalls across the area. The area is divided into regions, each of which has devices that record snowfall in centimeters; the recorded information then guides decisions on snowmaking, grooming, and other maintenance operations. The devices communicate, say, every 20 minutes with a server that updates a database that supports reports. Nowadays, the server-side software for such an application can be free _and_ production-grade.
|
||||
|
||||
This snowfall application uses the following technologies:
|
||||
|
||||
* A [Raspberry Pi 4][2] running Debian
|
||||
* Nginx web server: The free version hosts over 400 million websites. This web server is easy to install, configure, and use.
|
||||
* [SQLite relational database system][3], which is file-based: A database, which can hold many tables, is a file on the local system. SQLite is lightweight but also [ACID-compliant][4]; it is suited for low to moderate volume. SQLite is likely the most widely used database system in the world, and the source code for SQLite is in the public domain. The current version is 3. A more powerful (but still free) option is PostgreSQL.
|
||||
* Python: The Python programming language can interact with databases such as SQLite and web servers such as Nginx. Python (version 3) comes with Linux and macOS systems.
|
||||
|
||||
|
||||
|
||||
Python includes a software driver for communicating with SQLite. There are options for connecting Python scripts with Nginx and other web servers. One option is [uWSGI][5] (Web Server Gateway Interface), which updates the ancient CGI (Common Gateway Interface) from the 1990s.
|
||||
|
||||
Several factors speak for uWSGI:
|
||||
|
||||
* uWSGI is flexible. It can be used as either a lightweight concurrent web server or the backend application server connected to a web server such as Nginx.
|
||||
* Its setup is minimal.
|
||||
* The snowfall application involves a low to moderate volume of hits on the web server and database system. In general, CGI technologies are not fast by modern standards, but CGI performs well enough for department-level web applications such as this one.
|
||||
|
||||
|
||||
|
||||
Various acronyms describe the uWSGI option. Here's a sketch of the three principal ones:
|
||||
|
||||
* **WSGI** is a Python specification for an interface between a web server on one side, and an application or an application framework (e.g., Django) on the other side. This specification defines an API whose implementation is left open.
|
||||
* **uWSGI** implements the WSGI interface by providing an application server, which connects applications to a web server. A uWSGI application server's main job is to translate HTTP requests into a format that a web application can consume and, afterward, to format the application's response into an HTTP message.
|
||||
* **uwsgi** is a binary protocol implemented by a uWSGI application server to communicate with a full-featured web server such as Nginx; it also includes utilities such as a lightweight web server. The Nginx web server "speaks" uwsgi out of the box.
|
||||
|
||||
|
||||
|
||||
For convenience, I will use "uwsgi" as shorthand for the binary protocol, the application server, and the very lightweight web server.
|
||||
|
||||
### Setting up the database
|
||||
|
||||
On a Debian-based system, you can install SQLite the usual way (with `%` representing the command-line prompt):
|
||||
|
||||
|
||||
```
|
||||
`% sudo apt-get install sqlite3`
|
||||
```
|
||||
|
||||
This database system is a collection of C libraries and utilities, all of which come to about 500KB in size. There is no database server to start, stop, or otherwise maintain.
|
||||
|
||||
Once SQLite is installed, create a database at the command-line prompt:
|
||||
|
||||
|
||||
```
|
||||
`% sqlite3 snowfall.db`
|
||||
```
|
||||
|
||||
If this succeeds, the command creates the file `snowfall.db` in the current working directory. The database name is arbitrary (e.g., no extension is required), and the command opens the SQLite client utility with `>sqlite` as the prompt:
|
||||
|
||||
|
||||
```
|
||||
Enter ".help" for usage hints.
|
||||
sqlite>
|
||||
```
|
||||
|
||||
Create the snowfall table in the snowfall database with the following command. The table name, like the database name, is arbitrary:
|
||||
|
||||
|
||||
```
|
||||
sqlite> CREATE TABLE snowfall (id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
region TEXT NOT NULL,
|
||||
device TEXT NOT NULL,
|
||||
amount DECIMAL NOT NULL,
|
||||
tstamp DECIMAL NOT NULL);
|
||||
```
|
||||
|
||||
SQLite commands are case-insensitive, but it is traditional to use uppercase for SQL terms and lowercase for user terms. Check that the table was created:
|
||||
|
||||
|
||||
```
|
||||
`sqlite> .schema`
|
||||
```
|
||||
|
||||
The command echoes the `CREATE TABLE` statement.
|
||||
|
||||
The database is now ready for business, although the single-table snowfall is empty. You can add rows interactively to the table, but an empty table is fine for now.
|
||||
|
||||
### A first look at the overall architecture
|
||||
|
||||
Recall that uwsgi can be used in two ways: either as a lightweight web server or as an application server connected to a production-grade web server such as Nginx. The second use is the goal, but the first is suited for developing and testing the programmer's request-handling code. Here's the architecture with Nginx in play as the web server:
|
||||
|
||||
|
||||
```
|
||||
HTTP uwsgi
|
||||
client<\---->Nginx<\----->appServer<\--->request-handling code<\--->SQLite
|
||||
```
|
||||
|
||||
The client could be a browser, a utility such as [curl][6], or a hand-crafted program fluent in HTTP. Communications between the client and Nginx occur through HTTP, but then uwsgi takes over as a binary-transport protocol between Nginx and the application server, which interacts with request-handling code such as `requestHandler.py` (described below). This architecture delivers a clean division of labor. Nginx alone manages the client, and only the request-handling code interacts with the database. In turn, the application server separates the web server from the programmer-written code, which has a high-level API to read and write HTTP messages delivered over uwsgi.
|
||||
|
||||
I'll examine these architectural pieces and cover the steps for installing, configuring, and using uwsgi and Nginx in the next sections.
|
||||
|
||||
### The snowfall application code
|
||||
|
||||
Below is the source code file `requestHandler.py` for the snowfall application. (It's also available on my [website][7].) Different functions within this code help clarify the software architecture that connects SQLite, Nginx, and uwsgi.
|
||||
|
||||
#### The request-handling program
|
||||
|
||||
|
||||
```
|
||||
import sqlite3
|
||||
import cgi
|
||||
|
||||
PATH_2_DB = '/home/marty/wsgi/snowfall.db'
|
||||
|
||||
## Dispatches HTTP requests to the appropriate handler.
|
||||
def application(env, start_line):
|
||||
if env['REQUEST_METHOD'] == 'POST': ## add new DB record
|
||||
return handle_post(env, start_line)
|
||||
elif env['REQUEST_METHOD'] == 'GET': ## create HTML-fragment report
|
||||
return handle_get(start_line)
|
||||
else: ## no other option for now
|
||||
start_line('405 METHOD NOT ALLOWED', [('Content-Type', 'text/plain')])
|
||||
response_body = 'Only POST and GET verbs supported.'
|
||||
return [response_body.encode()]
|
||||
|
||||
def handle_post(env, start_line):
|
||||
form = get_field_storage(env) ## body of an HTTP POST request
|
||||
|
||||
## Extract fields from POST form.
|
||||
region = form.getvalue('region')
|
||||
device = form.getvalue('device')
|
||||
amount = form.getvalue('amount')
|
||||
tstamp = form.getvalue('tstamp')
|
||||
|
||||
## Missing info?
|
||||
if (region is not None and
|
||||
device is not None and
|
||||
amount is not None and
|
||||
tstamp is not None):
|
||||
add_record(region, device, amount, tstamp)
|
||||
response_body = "POST request handled.\n"
|
||||
start_line('201 OK', [('Content-Type', 'text/plain')])
|
||||
else:
|
||||
response_body = "Missing info in POST request.\n"
|
||||
start_line('400 Bad Request', [('Content-Type', 'text/plain')])
|
||||
|
||||
return [response_body.encode()]
|
||||
|
||||
def handle_get(start_line):
|
||||
conn = sqlite3.connect(PATH_2_DB) ## connect to DB
|
||||
cursor = conn.cursor() ## get a cursor
|
||||
cursor.execute("select * from snowfall")
|
||||
|
||||
response_body = "<h3>Snowfall report</h3><ul>"
|
||||
rows = cursor.fetchall()
|
||||
for row in rows:
|
||||
response_body += "<li>" + str(row[0]) + '|' ## primary key
|
||||
response_body += row[1] + '|' ## region
|
||||
response_body += row[2] + '|' ## device
|
||||
response_body += str(row[3]) + '|' ## amount
|
||||
response_body += str(row[4]) + "</li>" ## timestamp
|
||||
response_body += "</ul>"
|
||||
|
||||
conn.commit() ## commit
|
||||
conn.close() ## cleanup
|
||||
|
||||
start_line('200 OK', [('Content-Type', 'text/html')])
|
||||
return [response_body.encode()]
|
||||
|
||||
## Add a record from a device to the DB.
|
||||
def add_record(reg, dev, amt, tstamp):
|
||||
conn = sqlite3.connect(PATH_2_DB) ## connect to DB
|
||||
cursor = conn.cursor() ## get a cursor
|
||||
|
||||
sql = "INSERT INTO snowfall(region,device,amount,tstamp) values (?,?,?,?)"
|
||||
cursor.execute(sql, (reg, dev, amt, tstamp)) ## execute INSERT
|
||||
|
||||
conn.commit() ## commit
|
||||
conn.close() ## cleanup
|
||||
|
||||
def get_field_storage(env):
|
||||
input = env['wsgi.input']
|
||||
form = env.get('wsgi.post_form')
|
||||
if (form is not None and form[0] is input):
|
||||
return form[2]
|
||||
|
||||
fs = cgi.FieldStorage(fp = input,
|
||||
environ = env,
|
||||
keep_blank_values = 1)
|
||||
return fs
|
||||
```
|
||||
|
||||
A constant at the start of the source file defines the path to the database file:
|
||||
|
||||
|
||||
```
|
||||
`PATH_2_DB = '/home/marty/wsgi/snowfall.db'`
|
||||
```
|
||||
|
||||
Make sure to update the path for your Raspberry Pi.
|
||||
|
||||
As noted earlier, uwsgi includes a lightweight web server that can host this request-handling application. To begin, install uwsgi with these two commands (`##` introduces my comments):
|
||||
|
||||
|
||||
```
|
||||
% sudo apt-get install build-essential python-dev ## C header files, etc.
|
||||
% pip install uwsgi ## pip = Python package manager
|
||||
```
|
||||
|
||||
Next, launch a bare-bones snowfall application using uwsgi as the web server:
|
||||
|
||||
|
||||
```
|
||||
`% uwsgi --http 127.0.0.1:9999 --wsgi-file requestHandler.py `
|
||||
```
|
||||
|
||||
The flag `--http` runs uwsgi in web-server mode, with 9999 as the web server's listening port on localhost (127.0.0.1). By default, uwsgi dispatches HTTP requests to a programmer-defined function named `application`. For review, here's the full function from the top of the `requestHandler.py` code:
|
||||
|
||||
|
||||
```
|
||||
def application(env, start_line):
|
||||
if env['REQUEST_METHOD'] == 'POST': ## add new DB record
|
||||
return handle_post(env, start_line)
|
||||
elif env['REQUEST_METHOD'] == 'GET': ## create HTML-fragment report
|
||||
return handle_get(start_line)
|
||||
else: ## no other option for now
|
||||
start_line('405 METHOD NOT ALLOWED', [('Content-Type', 'text/plain')])
|
||||
response_body = 'Only POST and GET verbs supported.'
|
||||
return [response_body.encode()]
|
||||
```
|
||||
|
||||
The snowfall application accepts only two request types:
|
||||
|
||||
* A POST request, if up to snuff, creates a new entry in the snowfall table. The request should include the ski area region, the device in the region, the snowfall amount in centimeters, and a Unix-style timestamp. A POST request is dispatched to the `handle_post` function (which I'll clarify shortly).
|
||||
* A GET request returns an HTML fragment (an unordered list) with the records currently in the snowfall table.
|
||||
|
||||
|
||||
|
||||
Requests with an HTTP verb other than POST and GET will generate an error message.
|
||||
|
||||
You can use a utility such as curl to generate HTTP requests for testing. Here are three sample POST requests to start populating the database:
|
||||
|
||||
|
||||
```
|
||||
% curl -X POST -d "region=R1&device=D9&amount=1.42&tstamp=1604722088.0158753" localhost:9999/
|
||||
% curl -X POST -d "region=R7&device=D4&amount=2.11&tstamp=1604722296.8862638" localhost:9999/
|
||||
% curl -X POST -d "region=R5&device=D1&amount=1.12&tstamp=1604942236.1013834" localhost:9999/
|
||||
```
|
||||
|
||||
These commands add three records to the snowfall table. A subsequent GET request from curl or a browser displays an HTML fragment that lists the rows in the snowfall table. Here's the equivalent as non-HTML text:
|
||||
|
||||
|
||||
```
|
||||
Snowfall report
|
||||
|
||||
1|R1|D9|1.42|1604722088.0158753
|
||||
2|R7|D4|2.11|1604722296.8862638
|
||||
3|R5|D1|1.12|1604942236.1013834
|
||||
```
|
||||
|
||||
A professional report would convert the numeric timestamps into human-readable ones. But the emphasis, for now, is on the architectural components in the snowfall application, not on the user interface.
|
||||
|
||||
The uwsgi utility accepts various flags, which can be given either through a configuration file or in the launch command. For example, here's a richer launch of uwsgi as a web server:
|
||||
|
||||
|
||||
```
|
||||
`% uwsgi --master --processes 2 --http 127.0.0.1:9999 --wsgi-file requestHandler.py`
|
||||
```
|
||||
|
||||
This version creates a master (supervisory) process and two worker processes, which can handle the HTTP requests concurrently.
|
||||
|
||||
In the snowfall application, the functions `handle_post` and `handle_get` process POST and GET requests, respectively. Here's the `handle_post` function in full:
|
||||
|
||||
|
||||
```
|
||||
def handle_post(env, start_line):
|
||||
form = get_field_storage(env) ## body of an HTTP POST request
|
||||
|
||||
## Extract fields from POST form.
|
||||
region = form.getvalue('region')
|
||||
device = form.getvalue('device')
|
||||
amount = form.getvalue('amount')
|
||||
tstamp = form.getvalue('tstamp')
|
||||
|
||||
## Missing info?
|
||||
if (region is not None and
|
||||
device is not None and
|
||||
amount is not None and
|
||||
tstamp is not None):
|
||||
add_record(region, device, amount, tstamp)
|
||||
response_body = "POST request handled.\n"
|
||||
start_line('201 OK', [('Content-Type', 'text/plain')])
|
||||
else:
|
||||
response_body = "Missing info in POST request.\n"
|
||||
start_line('400 Bad Request', [('Content-Type', 'text/plain')])
|
||||
|
||||
return [response_body.encode()]
|
||||
```
|
||||
|
||||
The two arguments to the `handle_post` function (`env` and `start_line`) represent the system environment and a communications channel, respectively. The `start_line` channel sends the HTTP start line (in this case, either `400 Bad Request` or `201 OK`) and any HTTP headers (in this case, just `Content-Type: text/plain`) of an HTTP response.
|
||||
|
||||
The `handle_post` function tries to extract the relevant data from the HTTP POST request and, if it's successful, calls the function `add_record` to add another row to the snowfall table:
|
||||
|
||||
|
||||
```
|
||||
def add_record(reg, dev, amt, tstamp):
|
||||
conn = sqlite3.connect(PATH_2_DB) ## connect to DB
|
||||
cursor = conn.cursor() ## get a cursor
|
||||
|
||||
sql = "INSERT INTO snowfall(region,device,amount,tstamp) VALUES (?,?,?,?)"
|
||||
cursor.execute(sql, (reg, dev, amt, tstamp)) ## execute INSERT
|
||||
|
||||
conn.commit() ## commit
|
||||
conn.close() ## cleanup
|
||||
```
|
||||
|
||||
SQLite automatically wraps single SQL statements (such as `INSERT` above) in a transaction, which accounts for the call to `conn.commit()` in the code. SQLite also supports multi-statement transactions. After calling `add_record`, the `handle_post` function winds up its work by sending an HTTP response confirmation message to the requester.
|
||||
|
||||
The `handle_get` function also touches the database, but only to read the records in the snowfall table:
|
||||
|
||||
|
||||
```
|
||||
def handle_get(start_line):
|
||||
conn = sqlite3.connect(PATH_2_DB) ## connect to DB
|
||||
cursor = conn.cursor() ## get a cursor
|
||||
cursor.execute("SELECT * FROM snowfall")
|
||||
|
||||
response_body = "<h3>Snowfall report</h3><ul>"
|
||||
rows = cursor.fetchall()
|
||||
for row in rows:
|
||||
response_body += "<li>" + str(row[0]) + '|' ## primary key
|
||||
response_body += row[1] + '|' ## region
|
||||
response_body += row[2] + '|' ## device
|
||||
response_body += str(row[3]) + '|' ## amount
|
||||
response_body += str(row[4]) + "</li>" ## timestamp
|
||||
response_body += "</ul>"
|
||||
|
||||
conn.commit() ## commit
|
||||
conn.close() ## cleanup
|
||||
|
||||
start_line('200 OK', [('Content-Type', 'text/html')])
|
||||
return [response_body.encode()]
|
||||
```
|
||||
|
||||
A user-friendly version of the snowfall application would support additional (and fancier) reports, but even this version of `handle_get` underscores the clean interface between Python and SQLite. By the way, uwsgi expects a response body to be a list of bytes. In the `return` statement, the call to `response_body.encode()` inside the square brackets generates the byte list from the `response_body` string.
|
||||
|
||||
### Moving up to Nginx
|
||||
|
||||
The Nginx web server can be installed on a Debian-based system with one command:
|
||||
|
||||
|
||||
```
|
||||
`% sudo apt-get install nginx`
|
||||
```
|
||||
|
||||
As a web server, Nginx provides the expected services, such as wire-level security, HTTPS, user authentication, load balancing, media streaming, response compression, file uploading, etc. The Nginx engine is high-performance and stable, and this server can support dynamic content through a variety of programming languages. Using uwsgi as a very lightweight web server is an attractive option but switching to Nginx is a move up to industrial-strength web hosting with high-volume capability. Nginx and uwsgi are both implemented in C.
|
||||
|
||||
With Nginx in play, uwsgi takes on a communication protocol's restricted roles and an application server; it no longer acts as an HTTP web server. Here's the revised architecture:
|
||||
|
||||
|
||||
```
|
||||
HTTP uwsgi
|
||||
requester<\---->Nginx<\----->app server<\--->requestHandler.py
|
||||
```
|
||||
|
||||
As noted earlier, Nginx includes uwsgi support and now acts as a reverse-proxy server that forwards designated HTTP requests to the uwsgi application server, which in turn interacts with the Python script `requestHandler.py`. Responses from the Python script move in the reverse direction so that Nginx sends the HTTP response back to the requesting client.
|
||||
|
||||
Two changes bring this new architecture to life. The first launches uwsgi as an application server:
|
||||
|
||||
|
||||
```
|
||||
`% uwsgi --socket 127.0.0.1:8001 --wsgi-file requestHandler.py`
|
||||
```
|
||||
|
||||
Socket 8001 is the Nginx default for uwsgi communications. For robustness, you could use the full path to the Python script so that the command above does not have to be executed in the directory that houses the Python script. In a production environment, uwsgi would start and stop automatically; for now, however, the emphasis remains on how the architectural pieces fit together.
|
||||
|
||||
The second change involves Nginx configuration, which can be tricky on Debian-based systems. The main configuration file for Nginx is `/etc/nginx/nginx.conf`, but this file may have `include` directives for other files, in particular, files in one of three `/etc/nginx` subdirectories: `nginx.d`, `sites-available`, and `sites-enabled`. The `include` directives can be eliminated to simplify matters; in this case, the configuration occurs only in `nginx.conf`. I recommend the simple approach.
|
||||
|
||||
However the configuration is distributed, the key section for having Nginx talk to the uwsgi application server begins with `http` and has one or more `server` subsections, which in turn have `location` subsections. Here's an example from the Nginx documentation:
|
||||
|
||||
|
||||
```
|
||||
...
|
||||
http {
|
||||
# Configuration specific to HTTP and affecting all virtual servers
|
||||
...
|
||||
server { # simple reverse-proxy
|
||||
listen 80;
|
||||
server_name domain2.com [www.domain2.com][8];
|
||||
access_log logs/domain2.access.log main;
|
||||
|
||||
# serve static files
|
||||
location ~ ^/(images|javascript|js|css|flash|media|static)/ {
|
||||
root /var/www/virtual/big.server.com/htdocs;
|
||||
expires 30d;
|
||||
}
|
||||
|
||||
# pass requests for dynamic content to rails/turbogears/zope, et al
|
||||
location / {
|
||||
proxy_pass <http://127.0.0.1:8080>;
|
||||
}
|
||||
}
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
The `location` subsections are the ones of interest. For the snowfall application, here's the added `location` entry with its two configuration lines:
|
||||
|
||||
|
||||
```
|
||||
...
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
|
||||
root /var/www/html;
|
||||
index index.html index.htm index.nginx-debian.html;
|
||||
|
||||
server_name _;
|
||||
|
||||
### key addition for uwsgi communication
|
||||
location /snowfall {
|
||||
include uwsgi_params; ## comes with Nginx
|
||||
uwsgi_pass 127.0.0.1:8001; ## 8001 is the default for uwsgi
|
||||
}
|
||||
...
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
To keep things simple for now, make `/snowfall` the only `location` in the configuration. With this configuration in place, Nginx listens on port 80 and dispatches HTTP requests ending with the `/snowfall` path to the uwsgi application server:
|
||||
|
||||
|
||||
```
|
||||
% curl -X POST -d "..." localhost/snowfall ## new POST
|
||||
% curl -X GET localhost/snowfall ## new GET
|
||||
```
|
||||
|
||||
The port number 80 can be dropped from the request because 80 is the default server port for HTTP requests.
|
||||
|
||||
If the configured location were simply `/` instead of `/snowfall`, then any HTTP request with `/` at the start of the path would be dispatched to the uwsgi application server. Accordingly, the `/snowfall` path leaves room for other locations and, therefore, for further actions in response to HTTP requests.
|
||||
|
||||
Once you've changed the Nginx configuration with the added `location` subsection, you can start the web server:
|
||||
|
||||
|
||||
```
|
||||
`% sudo systemctl start nginx`
|
||||
```
|
||||
|
||||
There are other commands similar to `stop` and `restart` Nginx. In a production environment, you could automate these actions so that Nginx starts on a system boot and stops on a system shutdown.
|
||||
|
||||
With uwsgi and Nginx both running, you can use a browser to test whether the architectural components cooperate as expected. For example, if you enter the URL `localhost/` in the browser's input window, then the Nginx welcome page should appear with (HTML) content similar to this:
|
||||
|
||||
|
||||
```
|
||||
Welcome to nginx!
|
||||
...
|
||||
Thank you for using nginx.
|
||||
```
|
||||
|
||||
By contrast, the URL `localhost/snowfall` should display the rows currently in the snowfall table:
|
||||
|
||||
|
||||
```
|
||||
Snowfall report
|
||||
|
||||
1|R1|D9|1.42|1604722088.0158753
|
||||
2|R7|D4|2.11|1604722296.8862638
|
||||
3|R5|D1|1.12|1604942236.1013834
|
||||
```
|
||||
|
||||
### Wrapping up
|
||||
|
||||
The snowfall application shows how free software components—a high-powered web server, an ACID-compliant database system, and scripting for dynamic content—can support a realistic web application on a Raspberry Pi 4 platform. This lightweight machine lifts above its weight class, and Debian eases the lifting.
|
||||
|
||||
The software components in the web application work well together and require very little configuration. For higher volume hits against a relational database, recall that a free and feature-rich alternative to SQLite is PostgreSQL. If you're eager to play on the Raspberry Pi 4—in particular, to explore server-side web programming on this platform—then Nginx, SQLite or PostgreSQL, uwsgi, and Python are worth considering.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/3/web-hosting-raspberry-pi
|
||||
|
||||
作者:[Marty Kalin][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/mkalindepauledu
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/browser_web_internet_website.png?itok=g5B_Bw62 (Digital creative of a browser on the internet)
|
||||
[2]: https://www.raspberrypi.org/products/raspberry-pi-4-model-b/
|
||||
[3]: https://opensource.com/article/21/2/sqlite3-cheat-sheet
|
||||
[4]: https://en.wikipedia.org/wiki/ACID
|
||||
[5]: https://uwsgi-docs.readthedocs.io/en/latest/
|
||||
[6]: https://opensource.com/article/20/5/curl-cheat-sheet
|
||||
[7]: https://condor.depaul.edu/mkalin
|
||||
[8]: http://www.domain2.com
|
86
sources/tech/20210304 An Introduction to WebAssembly.md
Normal file
86
sources/tech/20210304 An Introduction to WebAssembly.md
Normal file
@ -0,0 +1,86 @@
|
||||
[#]: subject: (An Introduction to WebAssembly)
|
||||
[#]: via: (https://www.linux.com/news/an-introduction-to-webassembly/)
|
||||
[#]: author: (Dan Brown https://training.linuxfoundation.org/announcements/an-introduction-to-webassembly/)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
An Introduction to WebAssembly
|
||||
======
|
||||
|
||||
_By Marco Fioretti_
|
||||
|
||||
## **What on Earth is WebAssembly?**
|
||||
|
||||
[WebAssembly, also called Wasm][1], is a Web-optimized code format and API (Application Programming Interface) that can greatly improve the performances and capabilities of websites. Version 1.0 of WebAssembly, was released in 2017, and became an official W3C standard in 2019.
|
||||
|
||||
The standard is actively supported by all major browser suppliers, for obvious reasons: the official list of [“inside the browser” use cases][2] mentions, among other things, video editing, 3D games, virtual and augmented reality, p2p services, and scientific simulations. Besides making browsers much more powerful than JavaScript could, this standard may even extend the lifespan of websites: for example, it is WebAssembly that powers the continued support of [Flash animations and games at the Internet Archive][3].
|
||||
|
||||
WebAssembly isn’t just for browsers though; it is currently being used in mobile and edge based environments with such products as Cloudflare Workers.
|
||||
|
||||
## **How WebAssembly works**
|
||||
|
||||
Files in .wasm format contain low level binary instructions (bytecode), executable at “near CPU-native speed” by a virtual machine that uses a common stack. The code is packaged in modules – that is objects that are directly executable by a browser – and each module can be instantiated multiple times by a web page. The functions defined inside modules are listed in one dedicated array, or Table, and the corresponding data are contained in another structure, called arraybuffer. Developers can explicitly allocate memory for .wasm code with the Javascript WebAssembly.memory() call.
|
||||
|
||||
A pure text version of the .wasm format – that can greatly simplify learning and debugging – is also available. WebAssembly, however, is not really intended for direct human use. Technically speaking, .wasm is just a browser-compatible **compilation target**: a format in which software compilers can automatically translate code written in high-level programming languages.
|
||||
|
||||
This choice is exactly what allows developers to program directly for the preferred user interface of billions of people, in languages they already know (C/C++, Python, Go, Rust and others) but could not be efficiently used by browsers before. Even better, programmers would get this – at least in theory – without ever looking directly at WebAssembly code or worrying (since the target is a **virtual** machine) about which physical CPUs will actually run their code.
|
||||
|
||||
## **But we already have JavaScript. Do we really need WebAssembly?**
|
||||
|
||||
Yes, for several reasons. To begin with, being binary instructions, .wasm files can be much smaller – that is much faster to download – than JavaScript files of equivalent functionality. Above all, Javascript files must be fully parsed and verified before a browser can convert them to bytecode usable by its internal virtual machine.
|
||||
|
||||
.wasm files, instead, can be verified and compiled in a single pass, thus making “Streaming Compilation” possible: a browser can start to compile and execute them the moment it starts **downloading them**, just like happens with streaming movies.
|
||||
|
||||
This said, not all conceivable WebAssembly applications would surely be faster – or smaller – than equivalent JavaScript ones that are manually optimized by expert programmers. This may happen, for example, if some .wasm needed to include libraries that are not needed with JavaScript.
|
||||
|
||||
## **Does WebAssembly make JavaScript obsolete?**
|
||||
|
||||
In a word: no. Certainly not for a while, at least inside browsers. WebAssembly modules still need JavaScript because by design they cannot access the Document Object Model (DOM), that is the [main API made to modify web pages][4]. Besides, .wasm code cannot make system calls or read the browser’s memory. WebAssembly only runs in a sandbox and, in general, can interact with the outside world even less than JavaScript can, and only through JavaScript interfaces.
|
||||
|
||||
Therefore – at least in the near future – .wasm modules will just provide, through JavaScript, the parts that would consume much more bandwidth, memory or CPU time if they were written in that language.
|
||||
|
||||
## **How web browsers run WebAssembly**
|
||||
|
||||
In general, a browser needs at least two pieces to handle dynamic applications: a virtual machine (VM) that runs the app code and standard APIs that that code can use to modify both the behaviour of the browser, and the content of the web page that it displays.
|
||||
|
||||
The VMs inside modern browsers support both JavaScript and WebAssembly in the following way:
|
||||
|
||||
1. The browser downloads a web page written in the HTML markup language, and renders it
|
||||
2. if that HTML calls JavaScript code, the browser’s VM executes it. But…
|
||||
3. if that JavaScript code contains an instance of a WebAssembly module, that one is fetched as explained above, and then used as needed by JavaScript, via the WebAssembly APIs
|
||||
4. and when the WebAssembly code produces something that would alter the DOM – that is the structure of the “host” web page – the JavaScript code receives it and proceeds to the actual alteration.
|
||||
|
||||
|
||||
|
||||
## **How can I create usable WebAssembly code?**
|
||||
|
||||
There are more and more programming language communities that are supporting compiling to Wasm directly, we recommend looking at the [introductory guides][5] from webassembly.org as a starting point depending what language you work with. Note that not all programming languages have the same level of Wasm support, so your mileage may vary.
|
||||
|
||||
We plan to release a series of articles in the coming months providing more information about WebAssembly. To get started using it yourself, you can enroll in The Linux Foundation’s free [Introduction to WebAssembly][6] online training course.
|
||||
|
||||
The post [An Introduction to WebAssembly][7] appeared first on [Linux Foundation – Training][8].
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linux.com/news/an-introduction-to-webassembly/
|
||||
|
||||
作者:[Dan Brown][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://training.linuxfoundation.org/announcements/an-introduction-to-webassembly/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://webassembly.org/
|
||||
[2]: https://webassembly.org/docs/use-cases/
|
||||
[3]: https://blog.archive.org/2020/11/19/flash-animations-live-forever-at-the-internet-archive/
|
||||
[4]: https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction
|
||||
[5]: https://webassembly.org/getting-started/developers-guide/
|
||||
[6]: https://training.linuxfoundation.org/training/introduction-to-webassembly-lfd133/
|
||||
[7]: https://training.linuxfoundation.org/announcements/an-introduction-to-webassembly/
|
||||
[8]: https://training.linuxfoundation.org/
|
@ -0,0 +1,318 @@
|
||||
[#]: subject: (Learn to debug code with the GNU Debugger)
|
||||
[#]: via: (https://opensource.com/article/21/3/debug-code-gdb)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
Learn to debug code with the GNU Debugger
|
||||
======
|
||||
Troubleshoot your code with the GNU Debugger. Download our new cheat
|
||||
sheet.
|
||||
![magnifying glass on computer screen, finding a bug in the code][1]
|
||||
|
||||
The GNU Debugger, more commonly known by its command, `gdb`, is an interactive console to help you step through source code, analyze what gets executed, and essentially reverse-engineer what's going wrong in a buggy application.
|
||||
|
||||
The trouble with troubleshooting is that it's complex. [GNU Debugger][2] isn't exactly a complex application, but it can be overwhelming if you don't know where to start or even when and why you might need to turn to GDB to do your troubleshooting. If you've been using print, echo, or [printf statements][3] to debug your code, but you're beginning to suspect there may be something more powerful, then this tutorial is for you.
|
||||
|
||||
### Code is buggy
|
||||
|
||||
To get started with GDB, you need some code. Here's a sample application written in C++ (it's OK if you don't typically write in C++, the principles are the same across all languages), derived from one of the examples in the [guessing game series][4] here on Opensource.com:
|
||||
|
||||
|
||||
```
|
||||
#include <iostream>
|
||||
#include <stdlib.h> //srand
|
||||
#include <stdio.h> //printf
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main () {
|
||||
|
||||
srand (time(NULL));
|
||||
int alpha = rand() % 8;
|
||||
cout << "Hello world." << endl;
|
||||
int beta = 2;
|
||||
|
||||
printf("alpha is set to is %s\n", alpha);
|
||||
printf("kiwi is set to is %s\n", beta);
|
||||
|
||||
return 0;
|
||||
} // main
|
||||
```
|
||||
|
||||
There's a bug in this code sample, but it does compile (at least as of GCC 5). If you're familiar with C++, you may already see it, but it's a simple problem that can help new GDB users understand the debugging process. Compile it and run it to see the error:
|
||||
|
||||
|
||||
```
|
||||
$ g++ -o buggy example.cpp
|
||||
$ ./buggy
|
||||
Hello world.
|
||||
Segmentation fault
|
||||
```
|
||||
|
||||
### Troubleshooting a segmentation fault
|
||||
|
||||
From this output, you can surmise that the variable `alpha` was set correctly because otherwise, you wouldn't expect the line of code that came _after_ it. That's not always true, of course, but it's a good working theory, and it's essentially the same conclusion you'd likely come to if you were using `printf` as a log and debugger. From here, you can assume that the bug lies in _some line_ after the one that printed successfully. However, it's not clear whether the bug is in the very next line or several lines later.
|
||||
|
||||
GNU Debugger is an interactive troubleshooter, so you can use the `gdb` command to run buggy code. For best results, you should recompile your buggy application from source code with _debug symbols_ included. First, take a look at what information GDB can provide without recompiling:
|
||||
|
||||
|
||||
```
|
||||
$ gdb ./buggy
|
||||
Reading symbols from ./buggy...done.
|
||||
(gdb) start
|
||||
Temporary breakpoint 1 at 0x400a44
|
||||
Starting program: /home/seth/demo/buggy
|
||||
|
||||
Temporary breakpoint 1, 0x0000000000400a44 in main ()
|
||||
(gdb)
|
||||
```
|
||||
|
||||
When you start GDB with a binary executable as the argument, GDB loads the application and then waits for your instructions. Because this is the first time you're running GDB on this executable, it makes sense to try to repeat the error in hopes that GDB can provide further insight. GDB's command to launch the application it has loaded is, intuitively enough, `start`. By default, there's a _breakpoint_ built into GDB so that when it encounters the `main` function of your application, it pauses execution. To allow GDB to proceed, use the command `continue`:
|
||||
|
||||
|
||||
```
|
||||
(gdb) continue
|
||||
Continuing.
|
||||
Hello world.
|
||||
|
||||
Program received signal SIGSEGV, Segmentation fault.
|
||||
0x00007ffff71c0c0b in vfprintf () from /lib64/libc.so.6
|
||||
(gdb)
|
||||
```
|
||||
|
||||
No surprises here: the application crashed shortly after printing "Hello world," but GDB can provide the function call that was happening when the crash occurred. This could potentially be all you need to find the bug that's causing the crash, but to get a better idea of GDB's features and the general debugging process, imagine that the problem hasn't become clear yet, and you want to dig even deeper into what's happening with this code.
|
||||
|
||||
### Compiling code with debug symbols
|
||||
|
||||
To get the most out of GDB, you need debug symbols compiled into your executable. You can generate this with the `-g` option in GCC:
|
||||
|
||||
|
||||
```
|
||||
$ g++ -o debuggy example.cpp
|
||||
$ ./debuggy
|
||||
Hello world.
|
||||
Segmentation fault
|
||||
```
|
||||
|
||||
Compiling debug symbols into an executable results in a much larger file, so they're usually not distributed with the added convenience. However, if you're debugging open source code, it makes sense to recompile with debug symbols for testing:
|
||||
|
||||
|
||||
```
|
||||
$ ls -l *buggy* *cpp
|
||||
-rw-r--r-- 310 Feb 19 08:30 debug.cpp
|
||||
-rwxr-xr-x 11624 Feb 19 10:27 buggy*
|
||||
-rwxr-xr-x 22952 Feb 19 10:53 debuggy*
|
||||
```
|
||||
|
||||
### Debugging with GDB
|
||||
|
||||
Launch GDB with your new executable (`debuggy`, in this example) loaded:
|
||||
|
||||
|
||||
```
|
||||
$ gdb ./debuggy
|
||||
Reading symbols from ./debuggy...done.
|
||||
(gdb) start
|
||||
Temporary breakpoint 1 at 0x400a44
|
||||
Starting program: /home/seth/demo/debuggy
|
||||
|
||||
Temporary breakpoint 1, 0x0000000000400a44 in main ()
|
||||
(gdb)
|
||||
```
|
||||
|
||||
As before, use the `start` command to proceed:
|
||||
|
||||
|
||||
```
|
||||
(gdb) start
|
||||
Temporary breakpoint 1 at 0x400a48: file debug.cpp, line 9.
|
||||
Starting program: /home/sek/demo/debuggy
|
||||
|
||||
Temporary breakpoint 1, main () at debug.cpp:9
|
||||
9 srand (time(NULL));
|
||||
(gdb)
|
||||
```
|
||||
|
||||
This time, the automatic `main` breakpoint can specify what line number GDB paused on and what code the line contains. You could resume normal operation with `continue` but you already know that the application crashes before completion, so instead, you can step through your code line-by-line using the `next` keyword:
|
||||
|
||||
|
||||
```
|
||||
(gdb) next
|
||||
10 int alpha = rand() % 8;
|
||||
(gdb) next
|
||||
11 cout << "Hello world." << endl;
|
||||
(gdb) next
|
||||
Hello world.
|
||||
12 int beta = 2;
|
||||
(gdb) next
|
||||
14 printf("alpha is set to is %s\n", alpha);
|
||||
(gdb) next
|
||||
|
||||
Program received signal SIGSEGV, Segmentation fault.
|
||||
0x00007ffff71c0c0b in vfprintf () from /lib64/libc.so.6
|
||||
(gdb)
|
||||
```
|
||||
|
||||
From this process, you can confirm that the crash didn't happen when the `beta` variable was being set but when the `printf` line was executed. The bug has been exposed several times in this article (spoiler: the wrong data type is being provided to `printf`), but assume for a moment that the solution remains unclear and that further investigation is required.
|
||||
|
||||
### Setting breakpoints
|
||||
|
||||
Once your code is loaded into GDB, you can ask GDB about the data that the code has produced so far. To try some data introspection, restart your application by issuing the `start` command again and then proceed to line 11. An easy way to get to 11 quickly is to set a breakpoint that looks for a specific line number:
|
||||
|
||||
|
||||
```
|
||||
(gdb) start
|
||||
The program being debugged has been started already.
|
||||
Start it from the beginning? (y or n) y
|
||||
Temporary breakpoint 2 at 0x400a48: file debug.cpp, line 9.
|
||||
Starting program: /home/sek/demo/debuggy
|
||||
|
||||
Temporary breakpoint 2, main () at debug.cpp:9
|
||||
9 srand (time(NULL));
|
||||
(gdb) break 11
|
||||
Breakpoint 3 at 0x400a74: file debug.cpp, line 11.
|
||||
```
|
||||
|
||||
With the breakpoint established, continue the execution with `continue`:
|
||||
|
||||
|
||||
```
|
||||
(gdb) continue
|
||||
Continuing.
|
||||
|
||||
Breakpoint 3, main () at debug.cpp:11
|
||||
11 cout << "Hello world." << endl;
|
||||
(gdb)
|
||||
```
|
||||
|
||||
You're now paused at line 11, just after the `alpha` variable has been set, and just before `beta` gets set.
|
||||
|
||||
### Doing variable introspection with GDB
|
||||
|
||||
To see the value of a variable, use the `print` command. The value of `alpha` is random in this example code, so your actual results may vary from mine:
|
||||
|
||||
|
||||
```
|
||||
(gdb) print alpha
|
||||
$1 = 3
|
||||
(gdb)
|
||||
```
|
||||
|
||||
Of course, you can't see the value of a variable that has not yet been established:
|
||||
|
||||
|
||||
```
|
||||
(gdb) print beta
|
||||
$2 = 0
|
||||
```
|
||||
|
||||
### Using flow control
|
||||
|
||||
To proceed, you could step through the lines of code to get to the point where `beta` is set to a value:
|
||||
|
||||
|
||||
```
|
||||
(gdb) next
|
||||
Hello world.
|
||||
12 int beta = 2;
|
||||
(gdb) next
|
||||
14 printf("alpha is set to is %s\n", alpha);
|
||||
(gdb) print beta
|
||||
$3 = 2
|
||||
```
|
||||
|
||||
Alternatively, you could set a watchpoint. A watchpoint, like a breakpoint, is a way to control the flow of how GDB executes the code. In this case, you know that the `beta` variable should be set to `2`, so you could set a watchpoint to alert you when the value of `beta` changes:
|
||||
|
||||
|
||||
```
|
||||
(gdb) watch beta > 0
|
||||
Hardware watchpoint 5: beta > 0
|
||||
(gdb) continue
|
||||
Continuing.
|
||||
|
||||
Breakpoint 3, main () at debug.cpp:11
|
||||
11 cout << "Hello world." << endl;
|
||||
(gdb) continue
|
||||
Continuing.
|
||||
Hello world.
|
||||
|
||||
Hardware watchpoint 5: beta > 0
|
||||
|
||||
Old value = false
|
||||
New value = true
|
||||
main () at debug.cpp:14
|
||||
14 printf("alpha is set to is %s\n", alpha);
|
||||
(gdb)
|
||||
```
|
||||
|
||||
You can step through the code execution manually with `next`, or you can control how the code executes with breakpoints, watchpoints, and catchpoints.
|
||||
|
||||
### Analyzing data with GDB
|
||||
|
||||
You can see data in different formats. For instance, to see the value of `beta` as an octal value:
|
||||
|
||||
|
||||
```
|
||||
(gdb) print /o beta
|
||||
$4 = 02
|
||||
```
|
||||
|
||||
To see its address in memory:
|
||||
|
||||
|
||||
```
|
||||
(gdb) print /o beta
|
||||
$5 = 0x2
|
||||
```
|
||||
|
||||
You can also see the data type of a variable:
|
||||
|
||||
|
||||
```
|
||||
(gdb) whatis beta
|
||||
type = int
|
||||
```
|
||||
|
||||
### Solving bugs with GDB
|
||||
|
||||
This kind of introspection better informs you about not only what code is getting executed but how it's getting executed. In this example, the `whatis` command on a variable gives you a clue that your `alpha` and `beta` variables are integers, which might jog your memory about `printf` syntax, making you realize that instead of `%s` in your `printf` statements, you must use the `%d` designator. Making that change causes the application to run as expected, with no more obvious bugs present.
|
||||
|
||||
It's especially frustrating when code compiles but then reveals that there are bugs present, but that's how the trickiest of bugs work. If they were easy to catch, they wouldn't be bugs. Using GDB is one way to hunt them down and eliminate them.
|
||||
|
||||
### Download our cheatsheet
|
||||
|
||||
It's a fact of life, in even the most basic forms of programming, that code has bugs. Not all bugs are so crippling that they stop an application from running (or even from compiling), and not all bugs are caused by incorrect code. Sometimes bugs happen intermittently based on an unexpected combination of choices made by a particularly creative user. Sometimes programmers inherit bugs from the libraries they use in their own code. Whatever the cause, bugs are basically everywhere, and it's part of the programmer's job to find and neutralize them.
|
||||
|
||||
GNU Debugger is a useful tool in finding bugs. There's a lot more you can do with it than I demonstrated in this article. You can read about its many functions with the GNU Info reader:
|
||||
|
||||
|
||||
```
|
||||
`$ info gdb`
|
||||
```
|
||||
|
||||
Whether you're just learning GDB or you're a pro at it, it never hurts to have a reminder of what commands are available to you and what the syntax for those commands are.
|
||||
|
||||
### [Download our cheatsheet for GDB today.][5]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/3/debug-code-gdb
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/mistake_bug_fix_find_error.png?itok=PZaz3dga (magnifying glass on computer screen, finding a bug in the code)
|
||||
[2]: https://www.gnu.org/software/gdb/
|
||||
[3]: https://opensource.com/article/20/8/printf
|
||||
[4]: https://opensource.com/article/20/12/learn-c-game
|
||||
[5]: https://opensource.com/downloads/gnu-debugger-cheat-sheet
|
@ -0,0 +1,351 @@
|
||||
[#]: subject: (Measure your Internet of Things with Raspberry Pi and open source tools)
|
||||
[#]: via: (https://opensource.com/article/21/3/iot-measure-raspberry-pi)
|
||||
[#]: author: (Darin London https://opensource.com/users/dmlond)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
Measure your Internet of Things with Raspberry Pi and open source tools
|
||||
======
|
||||
Setting up an environment-monitoring system demonstrates how to use open
|
||||
source tools to keep tabs on temperature, humidity, and more.
|
||||
![Metrics and a graph illustration][1]
|
||||
|
||||
If you are interested in measuring and interacting with the world around you through the Internet of Things (IoT), there are a variety of inexpensive microcontrollers and microcomputers you can use. There are also many sensors available that connect to these devices to measure many aspects of the physical world.
|
||||
|
||||
These sensors interface with the microcontroller boards using the [I2C][2] message bus, which programs that run on the boards can access using open source libraries in [MicroPython][3], Java, C#, and other popular programming languages. These devices and libraries make it very easy to create sophisticated data-collection systems.
|
||||
|
||||
To demonstrate how easy and powerful this is, I built a greenhouse monitoring system using the following components that I purchased from [SparkFun][4]:
|
||||
|
||||
* [Raspberry Pi Zero W with headers][5]
|
||||
* [Power supply][6]
|
||||
* [Qwiic pHAT][7]
|
||||
* [Qwiic cables][8]
|
||||
* [Qwiic Environmental Combo breakout][9]
|
||||
* [Qwiic ambient light detector][10]
|
||||
* [32GB microSD card][11]
|
||||
* [Metal standoffs][12], [screws][13], and [nuts][14]
|
||||
|
||||
|
||||
|
||||
Adafruit has very similar offerings and connection systems.
|
||||
|
||||
### Getting to know Prometheus
|
||||
|
||||
One of the first things you can do to start interacting with your world is to collect and analyze data acquired by sensors. Open source software makes it easy to collect, analyze, display, and even take action on your data.
|
||||
|
||||
The [Prometheus][15] family of applications makes it easy to collect, store, and analyze data as a time series of individual events. I will briefly introduce the relevant parts of the Prometheus architecture; if you would like to learn more, there are many great articles about Prometheus on Opensource.com, including [_An introduction to monitoring with Prometheus_][16] and [_Achieve high-scale application monitoring with Prometheus_][17].
|
||||
|
||||
The Prometheus suite includes the following applications, which can be plugged together in various ways.
|
||||
|
||||
#### [Prometheus][18]
|
||||
|
||||
The main Prometheus service is a powerful time-series database that runs on a general-purpose computer, such as a Linux machine, cloud service, or Raspberry Pi (the Raspberry Pi 4 is recommended). A Prometheus instance can be configured to regularly "scrape" various file- and network-connected exporter services (e.g., HTTP, TCP, etc.) in the [Prometheus exposition format][19]. A single Prometheus service can be configured to scrape multiple targets, each with a unique job name. A scrape target publishes data in the form of events with a user-defined name, timestamp, value, and optional set of key-value annotations. If a data source publishes data without a timestamp, the scrape's exact time is automatically added to the event when it is stored. It can also be configured to communicate with one or more Alertmanager instances running on the same host or another host on the same network.
|
||||
|
||||
Once events are published in a Prometheus service, they can be queried using the [Prometheus Query Language][20]. PromQL queries can be used to create tables and graphs of events. They can also be used to configure alerts, whereby a PromQL query condition's truth causes the Prometheus service to set the configured alert's firing state as `true`; this alert will remain in the firing state as long as the condition is true. Once the condition becomes false, the alert firing state is set to `false`.
|
||||
|
||||
Multiple instances of an exporting service can publish the same metrics but differentiated by annotations to identify the sensor. For example, if you have three greenhouse monitors, each can publish its temperature, humidity, and other metrics, annotated with something like `greenhouse=1`, `greenhouse=2`, or `greenhouse=3`. Graphs, tables, and alerts can be configured to show all instances for a particular metric or just the metrics with specific annotations.
|
||||
|
||||
All metrics stored in Prometheus are annotated with the job defined for the scrape target in the configuration. Every scrape target configured in a Prometheus service has a Boolean metric called `up`, which is set to `true` each time the service successfully scrapes the target and `false` when it cannot. This is a useful metric to use in PromQL queries to define alerts when a service goes down.
|
||||
|
||||
#### [Alertmanager][21]
|
||||
|
||||
The main Prometheus service does not act on alerts—it just holds the alerts' state as firing or not firing at any particular moment. The Alertmanager service works with a Prometheus service to set up notifications when alerts defined in Prometheus are firing. One or more Alertmanager services can be configured to run on general-purpose computers on the same network as the Prometheus service.
|
||||
|
||||
Alertmanager notifications can be configured to communicate with various external systems, including email gateways, web service endpoints, chat services, and popular ticketing systems. Each notification can be templated to use various attributes about the event, including all of its annotations, to produce the notification message.
|
||||
|
||||
#### [Node Exporter][22]
|
||||
|
||||
Node Exporter is a very simple daemon that runs on a general-purpose computer host as a web service and exports data about that host via HTTP in the Prometheus exposition format. It is programmed to produce many different metrics about its host, such as CPU and memory utilization, using logic defined for each specific host architecture (e.g., proc filesystem, Windows Registry, etc.).
|
||||
|
||||
A Node Exporter instance can also be configured to present one or more Prometheus exposition format compliant files on the host filesystem. This makes it useful for publishing metrics produced by another application running on the same host. The example greenhouse monitoring system uses a Python program to collect data from the sensors and produce a Prometheus-formatted export file, and Node Exporter publishes these metrics.
|
||||
|
||||
#### [Pushgateway][23]
|
||||
|
||||
A Raspberry Pi Zero, 3, or 4 can host a Node Exporter, but other microcontrollers (such as an Arduino or Raspberry Pi Pico) cannot. Pushgateway enables these devices to publish their metrics. It is a microservice that can run on another general-purpose computer host (such as a desktop, a cloud, or even a Rasberry Pi Zero, 3, or 4) and present a prometheus exposition formatted feed for a Prometheus service to scrape, and a REST API that other processes connected to its network can use to report custom metrics.
|
||||
|
||||
A Pushgateway instance can run on the same host as the Prometheus service or a different host on the same network. If the microprocessor can communicate with the network using the Pushgateway and Prometheus services (e.g., an Ethernet cable, WiFi, or [LoRaWAN][24]), the process running on the microcontroller can use a standard HTTP library to report metrics using the Pushgateway REST API as part of its process loop.
|
||||
|
||||
#### [Grafana][25]
|
||||
|
||||
Grafana is not part of the Prometheus suite. It is an open source observability system designed to pull in data from multiple external data sources and integrate the data into customizable visualization dashboards. Grafana can pull data in from a variety of external system types, including Prometheus. It's another powerful, open source application that you can use to create sophisticated dashboards with the data produced by your devices. Grafana can also be installed onto a general-purpose computer, such as a desktop or a Raspberry Pi Zero, 3, or 4. (I installed it on the Raspberry Pi 4 that hosts the Prometheus and Alertmanager services.)
|
||||
|
||||
There are plenty of tutorials available to help you get up and running with Grafana, including several on Opensource.com, such as _[The perfect combo with Prometheus and Grafana, and more industry trends][26]_ and _[Monitoring Linux performance with Grafana][27]_.
|
||||
|
||||
Once Grafana is installed, use your browser to navigate to the Grafana host's hostname or internet protocol address (IP) at port 3000, and log in with the default credentials (**blank** / **admin**). Make sure to change the admin password. You can then add a data source and use the menu to choose the Prometheus main server's IP or host and port. Once you add the data source, you can start to graph data from Prometheus or create dashboards.
|
||||
|
||||
If you are installing any of the above on a Raspberry Pi, ensure you download the [Prometheus][28] and [Grafana][29] binary distributions for your CPU's architecture. On a running Raspberry Pi, you can use either of these commands:
|
||||
|
||||
* `uname -m`
|
||||
* `cat /proc/cpuinfo`
|
||||
|
||||
|
||||
|
||||
to get cpu architecture. It will say something like armv7.
|
||||
|
||||
### Connect the Raspberry Pi Zero's sensors
|
||||
|
||||
Once you have somewhere to store the data, you can assemble and configure the greenhouse monitoring device. I flashed the MicroSD card with the [Raspberry Pi OS Lite][30] image and configured it for [headless connection over WiFi][31]. I plugged the Qwiiic pHAT onto the Pi Zero headers and connected the Qwiic cables from the Qwiic pHAT to each of the light and environmental combo sensors. (Be sure to plug the yellow cable into the Qwiic pHAT on the side with the Pi header connection and into the sensors on the side with the I2C solder connection holes.) It is also possible to daisy-chain the sensors if you have only one Qwiic connection to your Raspberry Pi.
|
||||
|
||||
![Wiring architecture][32]
|
||||
|
||||
(Darin London, [CC BY-SA 4.0][33])
|
||||
|
||||
Once the Raspberry Pi is connected to the sensors, plug the SD card into its slot, connect the power supply, and power it up. It will boot up, and then you should be able to connect to the Raspberry Pi using:
|
||||
|
||||
|
||||
```
|
||||
`ssh pi@raspbberrypi.local`
|
||||
```
|
||||
|
||||
The default password is **raspberry**, but change it to something more secure using the `passwd` command. You can also use ping on your desktop to get the host's IP address and use it instead of the `raspberrypi.local` address. (This is useful if you have multiple Pis on your network.)
|
||||
|
||||
### Install Node Exporter
|
||||
|
||||
Install the Node Exporter application on your Raspberry Pi Zero by [downloading][34] the binary distribution for your architecture from the Prometheus website. Once it is installed, [configure it as a systemd service][35] so that it automatically starts and stops with the Raspberry Pi.
|
||||
|
||||
### Install Python sensor libraries
|
||||
|
||||
Raspberry Pi OS comes with Python 3, but it does not include the libraries required to interact with the sensors. Fortunately, there are Python libraries available.
|
||||
|
||||
Install SparkFun's official [Qwiic_Py library][36] to access the sensors on the Environmental Combo breakout. If you are using Raspberry Pi OS Lite, you have to install [pip][37] (the Python package installer) for Python 3:
|
||||
|
||||
|
||||
```
|
||||
`sudo apt install python3-pip`
|
||||
```
|
||||
|
||||
The light sensor does not yet have an official SparkFun or Adafruit Python package, but you can get an open source [vml6030.py package][38] from its GitHub repo and copy it to `/home/pi` to use it in your monitoring application. It is based on the official SparkFun Arduino library.
|
||||
|
||||
### Install the greenhouse monitor code
|
||||
|
||||
The `greenhouse_monitor.py` script in this project's [GitHub repo][39] uses the Python sensor libraries to append metrics for `ambient_temperature`, `ambient_humidity`, and `ambient_light` every 11 seconds to a file named `/home/pi/metrics.prom` in the format Prometheus expects:
|
||||
|
||||
|
||||
```
|
||||
#!/usr/bin/python3
|
||||
|
||||
from veml6030 import VEML6030
|
||||
import smbus2
|
||||
import qwiic_bme280
|
||||
import time
|
||||
import sys
|
||||
|
||||
def instrument_metrics(light,temp,humidity):
|
||||
metrics_out = open('/home/pi/metrics.prom', 'w+')
|
||||
print('# HELP ambient_temperature temperature in fahrenheit', flush=True, file=metrics_out)
|
||||
print('# TYPE ambient_temperature gauge', flush=True, file=metrics_out)
|
||||
print(f'ambient_temperature {temp}', flush=True, file=metrics_out)
|
||||
print('# HELP ambient_light light in lux', flush=True, file=metrics_out)
|
||||
print('# TYPE ambient_light gauge', flush=True, file=metrics_out)
|
||||
print(f'ambient_light {light}', flush=True, file=metrics_out)
|
||||
print('# HELP ambient_humidity humidity in %RH', flush=True, file=metrics_out)
|
||||
print('# TYPE ambient_humidity gauge', flush=True, file=metrics_out)
|
||||
print(f'ambient_humidity {humidity}', flush=True, file=metrics_out)
|
||||
metrics_out.close()
|
||||
|
||||
print("Starting Greenhouse Monitor")
|
||||
bus = smbus2.SMBus(1) # For Raspberry Pi
|
||||
light_sensor = VEML6030(bus)
|
||||
environment_sensor = qwiic_bme280.QwiicBme280()
|
||||
|
||||
if environment_sensor.is_connected() == False:
|
||||
print("The Environment Sensor isn't connected to the system. Please check your connection", file=sys.stderr)
|
||||
exit(1)
|
||||
environment_sensor.begin()
|
||||
while True:
|
||||
light = light_sensor.read_light()
|
||||
temp = environment_sensor.temperature_fahrenheit
|
||||
humidity = environment_sensor.humidity
|
||||
instrument_metrics(light, temp, humidity)
|
||||
time.sleep(11)
|
||||
```
|
||||
|
||||
This can be set up as a systemd service, `/etc/systemd/system/greenhouse_montor.service`:
|
||||
|
||||
|
||||
```
|
||||
[Unit]
|
||||
Description=Greenhouse Monitor
|
||||
Documentation=<https://github.com/prometheus/node\_exporter>
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
User=pi
|
||||
Restart=on-failure
|
||||
|
||||
ExecStart=/home/pi/greenhouse_monitor.py
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
A Node Exporter can also be configured as a systemd service to publish the metrics file produced by the `greenhouse_montitor.py` script at `/etc/systemd/system/node_exporter.service`:
|
||||
|
||||
|
||||
```
|
||||
[Unit]
|
||||
Description=Node Exporter
|
||||
Documentation=<https://github.com/prometheus/node\_exporter>
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
User=pi
|
||||
Restart=on-failure
|
||||
|
||||
ExecStart=/usr/local/bin/node_exporter \
|
||||
--no-collector.arp \
|
||||
--no-collector.bcache \
|
||||
--no-collector.bonding \
|
||||
--no-collector.btrfs \
|
||||
--no-collector.cpu --no-collector.cpufreq --no-collector.edac --no-collector.entropy --no-collector.filefd --no-collector.hwmon --no-collector.ipvs \
|
||||
--no-collector.loadavg \
|
||||
--no-collector.mdadm \
|
||||
--no-collector.meminfo \
|
||||
--no-collector.netdev \
|
||||
--no-collector.netstat \
|
||||
--no-collector.nfs \
|
||||
--no-collector.nfsd \
|
||||
--no-collector.rapl \
|
||||
--no-collector.softnet \
|
||||
--no-collector.stat \
|
||||
--no-collector.time \
|
||||
--no-collector.timex \
|
||||
--no-collector.uname \
|
||||
--no-collector.vmstat \
|
||||
--no-collector.xfs \
|
||||
--no-collector.zfs \
|
||||
--no-collector.netclass \
|
||||
--no-collector.powersupplyclass \
|
||||
--no-collector.pressure \
|
||||
--no-collector.diskstats \
|
||||
--no-collector.filesystem \
|
||||
--no-collector.conntrack \
|
||||
--no-collector.infiniband \
|
||||
--no-collector.schedstat \
|
||||
--no-collector.sockstat \
|
||||
--no-collector.thermal_zone \
|
||||
--no-collector.udp_queues \
|
||||
--collector.textfile.directory=/home/pi
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
Note that you can leave off all the `--nocollector.*` arguments, and `node_exporter` will export lots of metrics about the Raspberry Pi host and the `greenhouse_monitor` data.
|
||||
|
||||
Once the systemd service definitions are in place, you can add and enable them using systemctl, and they will start as soon as your Raspberry Pi boots up and has a network:
|
||||
|
||||
|
||||
```
|
||||
sudo systemctl enable greenhouse_monitor.py
|
||||
sudo systemctl enable node_exporter
|
||||
```
|
||||
|
||||
You can troubleshoot these services using:
|
||||
|
||||
|
||||
```
|
||||
`sudo systemctl status $servicename`
|
||||
```
|
||||
|
||||
The Python script and systemd service definition files are available in the [project's GitHub repo][39].
|
||||
|
||||
### Restart the Raspberry Pi Zero and start monitoring
|
||||
|
||||
When the Raspberry Pi starts, it will start `greenhouse_monitor.py` and the `node_exporter` service. You can visit the `node_exporter` service using the IP or hostname of the Raspberry Pi running the greenhouse monitor at port 9100 (e.g., `http://$ip:9100`). Refresh every 11 seconds to see new entries.
|
||||
|
||||
### Configure the Prometheus server scrape endpoint
|
||||
|
||||
Once your greenhouse monitor's Node Exporter is exporting metrics, you can configure the Prometheus service to scrape it. Add the following lines to the `prometheus.yml` configuration file within the `scrape_configs` section (replace the IP in the targets with the IP of the device running the greenhouse_monitoring service on your network):
|
||||
|
||||
|
||||
```
|
||||
- job_name: 'greenhouse_monitor'
|
||||
|
||||
# metrics_path defaults to '/metrics'
|
||||
# scheme defaults to 'http'.
|
||||
|
||||
static_configs:
|
||||
- targets: ['192.168.1.12:9100']
|
||||
```
|
||||
|
||||
Prometheus will automatically load the configuration file every few seconds and start scraping your greenhouse monitor. You can verify that it has started scraping (and get its up/down status) by visiting the Prometheus web user interface (UI) targets page at `http://$prometheus_host:9090/targets`.
|
||||
|
||||
If it is up (and green), you can query metrics in the Prometheus web UI graphs page `http://$prometheus_host:9090/graph`.
|
||||
|
||||
![Prometheus web UI graphs page][40]
|
||||
|
||||
(Darin London, [CC BY-SA 4.0][33])
|
||||
|
||||
Once you are getting data in Prometheus, you can visit the Grafana service at `http://$graphana_host:3000`. I created a dashboard called Greenhouse with the panels for the three metrics exported by the greenhouse monitor. You can set Grafana to show data in the panels using the time controls. I was able to get the values for a 24-hour period from midnight to 11:59:59pm on the same day using the format `from: YYYY-MM-DD 00:00:00` and `To: YYYY-MM-DD 23:59:59`.
|
||||
|
||||
![24-hour metrics][41]
|
||||
|
||||
(Darin London, [CC BY-SA 4.0][33])
|
||||
|
||||
Notice the time of day when the sun was shining through a window onto the device?
|
||||
|
||||
### What should you measure next?
|
||||
|
||||
You have a treasure-trove of data at your fingertips to examine the physical world. Next, you could [configure Alertmanager][42] to send notifications through various communication technologies (e.g., webhooks, Slack, Gmail, PagerDuty, etc.) when alerts configured in Prometheus are firing.
|
||||
|
||||
Now that you know how to measure your world, the question becomes: What do you want to measure?
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/3/iot-measure-raspberry-pi
|
||||
|
||||
作者:[Darin London][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/dmlond
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/metrics_graph_stats_blue.png?itok=OKCc_60D (Metrics and a graph illustration)
|
||||
[2]: https://en.wikipedia.org/wiki/I%C2%B2C
|
||||
[3]: https://micropython.org/
|
||||
[4]: https://www.sparkfun.com/
|
||||
[5]: https://www.sparkfun.com/products/15470
|
||||
[6]: https://www.sparkfun.com/products/13831
|
||||
[7]: https://www.sparkfun.com/products/15945
|
||||
[8]: https://www.sparkfun.com/products/15081
|
||||
[9]: https://www.sparkfun.com/products/14348
|
||||
[10]: https://www.sparkfun.com/products/15436
|
||||
[11]: https://www.sparkfun.com/products/14832
|
||||
[12]: https://www.sparkfun.com/products/10463
|
||||
[13]: https://www.sparkfun.com/products/10453
|
||||
[14]: https://www.sparkfun.com/products/10454
|
||||
[15]: https://prometheus.io/
|
||||
[16]: https://opensource.com/article/19/11/introduction-monitoring-prometheus
|
||||
[17]: https://opensource.com/article/19/10/application-monitoring-prometheus
|
||||
[18]: https://prometheus.io/docs/introduction/overview/
|
||||
[19]: https://github.com/prometheus/docs/blob/master/content/docs/instrumenting/exposition_formats.md
|
||||
[20]: https://prometheus.io/docs/prometheus/latest/querying/basics/
|
||||
[21]: https://prometheus.io/docs/alerting/latest/alertmanager/
|
||||
[22]: https://prometheus.io/docs/guides/node-exporter/
|
||||
[23]: https://prometheus.io/docs/practices/pushing
|
||||
[24]: https://en.wikipedia.org/wiki/LoRa#LoRaWAN
|
||||
[25]: https://grafana.com/
|
||||
[26]: https://opensource.com/article/20/5/Prometheus-Grafana-and-more-industry-trends
|
||||
[27]: https://opensource.com/article/17/8/linux-grafana
|
||||
[28]: https://prometheus.io/download/
|
||||
[29]: https://grafana.com/grafana/download
|
||||
[30]: https://www.raspberrypi.org/software/operating-systems/
|
||||
[31]: https://www.raspberrypi.org/documentation/configuration/wireless/headless.md
|
||||
[32]: https://opensource.com/sites/default/files/uploads/raspberrypi-qwiic-wiring.jpg (Wiring architecture)
|
||||
[33]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[34]: https://prometheus.io/docs/guides/node-exporter/#installing-and-running-the-node-exporter
|
||||
[35]: https://pimylifeup.com/raspberry-pi-prometheus
|
||||
[36]: https://github.com/sparkfun/Qwiic_Py
|
||||
[37]: https://pypi.org/project/pip/
|
||||
[38]: https://github.com/n8many/VEML6030py
|
||||
[39]: https://github.com/dmlond/greenhouse
|
||||
[40]: https://opensource.com/sites/default/files/pictures/prometheus-web-ui-graphs-page.png (Prometheus web UI graphs page)
|
||||
[41]: https://opensource.com/sites/default/files/uploads/24-hour-metrics.png (24-hour metrics)
|
||||
[42]: https://prometheus.io/docs/alerting/latest/configuration/
|
@ -0,0 +1,104 @@
|
||||
[#]: subject: (You Can Now Install Official Evernote Client on Ubuntu and Debian-based Linux Distributions)
|
||||
[#]: via: (https://itsfoss.com/install-evernote-ubuntu/)
|
||||
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
You Can Now Install Official Evernote Client on Ubuntu and Debian-based Linux Distributions
|
||||
======
|
||||
|
||||
[Evernote][1] is a popular note-taking application. It was a revolutionary product at the time of its launch. Since then, there have been several such application that allow you to save web clippings, notes etc into notebook formats.
|
||||
|
||||
For years, the desktop client of Evernote was not available for Linux. Evernote promised a Linux application some time ago and its beta version is finally available for Ubuntu-based distributions.
|
||||
|
||||
Non-FOSS alert!
|
||||
|
||||
Evernote Linux client is not open source. It’s been covered here because the application is made available on Linux and we cover popular non-foss applications for Linux users from time to time. This helps with regular desktop Linux users.
|
||||
|
||||
### Installing Evernote on Ubuntu and Debian-based Linux distributions
|
||||
|
||||
Go to the following page on Evernote’s website:
|
||||
|
||||
[Evernote Linux Beta Program][2]
|
||||
|
||||
Scroll down a bit to accept the terms and conditions of ‘early testing program’. You’ll see a ‘Install Now’ button appearing on the screen. Click on it to download the DEB file.
|
||||
|
||||
![][3]
|
||||
|
||||
To [install the application from the DEB file][4], double-click on it. It should open the Software Center app and give you the option to install it.
|
||||
|
||||
![][5]
|
||||
|
||||
Once the installation completes, search for Evernote in the system menu and launch it.
|
||||
|
||||
![][6]
|
||||
|
||||
When you start the application for the first time, you’ll need to log in to your Evernote account.
|
||||
|
||||
![][7]
|
||||
|
||||
The first run brings you to the ‘Home screen’ where you can organize your notebooks for even quicker access.
|
||||
|
||||
![][8]
|
||||
|
||||
You may enjoy using Evernote on Linux now.
|
||||
|
||||
### Experiencing the beta version of Evernote Linux client
|
||||
|
||||
There are a few annoyances here and there with the software being in beta.
|
||||
|
||||
As you can notice in the image above, Evernote Linux client detected the [dark mode in Ubuntu][9] and switched to dark theme automatically. However, when I changed the system theme to light or standard, it didn’t change theme application theme immediately. The changes took into effect only after I restarted Evernote app.
|
||||
|
||||
Another issue is about closing the application. If you click on the X button to close the Evernote application, the program goes in background instead of exiting.
|
||||
|
||||
There is an app indicator that seems like a way to launch a minimized Evernote application, like [Skype on Linux][10]. Unfortunately, that’s not the case. It opens the Scratch Pad for you to type a quick note.
|
||||
|
||||
This gives you another [note taking application on Linux][11] but it also presents a problem. There is no option to quit Evernote here. It is only for opening the quick note taking app.
|
||||
|
||||
![][12]
|
||||
|
||||
So, how do you quit the Evernote application? For that, open the Evernote application again. If it is running in the background, search for it in the menu and launch it as if you are opening it afresh.
|
||||
|
||||
When Evernote application is running in the foreground, go to File->Quit Evernote.
|
||||
|
||||
![][13]
|
||||
|
||||
This is something the developers should look to improve in the future versions.
|
||||
|
||||
I also cannot say how will the beta version of the program be updated in the future. It doesn’t add any repository. I just hope that the application itself notifies about the availability of a newer version so that users could download the new DEB file.
|
||||
|
||||
I do NOT have a premium Evernote subscription but still, I could access the saved web articles and notes without internet connection. Strange, right?
|
||||
|
||||
Overall, I am happy to see that Evernote finally made the effort to bring the application to Linux. Now you don’t have to try third-party applications to use Evernote on Linux, at least on Ubuntu and Debian-based distributions. You may, of course, use an [Evernote alternative][14] like [Joplin][15] that are actually open source.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/install-evernote-ubuntu/
|
||||
|
||||
作者:[Abhishek Prakash][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/abhishek/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://evernote.com/
|
||||
[2]: https://evernote.com/intl/en/b1433t1422
|
||||
[3]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/03/evernote-early-access-linux.png?resize=799%2C495&ssl=1
|
||||
[4]: https://itsfoss.com/install-deb-files-ubuntu/
|
||||
[5]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/03/install-evernote-linux.png?resize=800%2C539&ssl=1
|
||||
[6]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/03/evernote-ubuntu.jpg?resize=800%2C230&ssl=1
|
||||
[7]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/03/evernote-running-ubuntu.png?resize=800%2C505&ssl=1
|
||||
[8]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/03/evernote-on-ubuntu.png?resize=800%2C537&ssl=1
|
||||
[9]: https://itsfoss.com/dark-mode-ubuntu/
|
||||
[10]: https://itsfoss.com/install-skype-ubuntu-1404/
|
||||
[11]: https://itsfoss.com/note-taking-apps-linux/
|
||||
[12]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/03/evernote-app-indicator.png?resize=800%2C480&ssl=1
|
||||
[13]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/03/quit-evernote-linux.png?resize=799%2C448&ssl=1
|
||||
[14]: https://itsfoss.com/5-evernote-alternatives-linux/
|
||||
[15]: https://itsfoss.com/joplin/
|
@ -1,290 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (bestony)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (lawyer The MIT License, Line by Line)
|
||||
[#]: via: (https://writing.kemitchell.com/2016/09/21/MIT-License-Line-by-Line.html)
|
||||
[#]: author: (Kyle E. Mitchell https://kemitchell.com/)
|
||||
|
||||
逐行解读 MIT 许可证
|
||||
======
|
||||
|
||||
[MIT 许可证][1] 是世界上最流行的开源软件许可证。以下是它的逐行解读。
|
||||
|
||||
#### 阅读协议
|
||||
|
||||
如果你涉及到开源软件,并且没有花时间从头到尾的阅读整个许可证(它只有 171 个单词),你现在就需要这样去做。尤其是当许可证不是你日常的工作内容时。把任何看起来不对劲或不清楚的地方记下来,然后继续阅读。我会把每一个单词再重复一遍,并按顺序分块,加入上下文和注释。但最重要的还是要牢记整体。
|
||||
|
||||
> The MIT License (MIT)
|
||||
>
|
||||
> Copyright (c) <year> <copyright holders>
|
||||
>
|
||||
> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
>
|
||||
> The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
>
|
||||
> The Software is provided “as is”, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the Software.
|
||||
|
||||
许可证可以分为五段,按照逻辑划分如下:
|
||||
|
||||
* **头部**
|
||||
* **许可证标题** : “MIT 许可证”
|
||||
* **版权说明** : “Copyright (c) …”
|
||||
* **许可证授权** : “特此批准 …”
|
||||
* **授权范围** : “… 处理软件 …”
|
||||
* **条件** : “… 服从了 …”
|
||||
* **归属和通知** : “上述 … 应当被包含在内 …”
|
||||
* **免责声明** : “软件按照“原状”提供 …”
|
||||
* **责任限制** : “在任何情况下 …”
|
||||
|
||||
|
||||
接下来详细看看
|
||||
|
||||
#### 头部
|
||||
|
||||
##### 许可证头部
|
||||
|
||||
> The MIT License (MIT)
|
||||
|
||||
“MIT 许可证“不是单一的许可证,而是一系列从麻省理工学院为将要发布的语言准备的许可证衍生的许可证。多年来,无论是对于使用它的原始项目,还是作为其他项目的模型,他都经历了许多变化。Fedora 项目维护了一个纯文本的[麻省理工学院许可证其他版本]的页面,如同泡在甲醛中的解剖标本一般,平淡的追溯了无序的演变。
|
||||
|
||||
幸运的是,[OSI(开放源码倡议)][3] 和 [Software Package Data eXchange(软件数据包交换)]团体已经将一种通用的 MIT 式的许可证形式标准化为”MIT 许可证“。而 OSI 则采用了 SPDX 标准化的[字符串标志符][5],并将其中的 ”MIT“ 明确的指向标准化形式的”MIT 许可证“
|
||||
|
||||
即使你在 “LICENSE” 文件中包含 “MIT 许可证”或 “SPDX:MIT“ ,任何负责的审查员仍会将文本与标准格式进行比较,以确保安全。尽管自称为“MIT 许可证”的各种许可证形式只在细微的细节上有所不同,但“MIT 许可证”的松散性吸引了一些作者加入麻烦的“定制”。典型的糟糕、不好的例子是[JSON 许可证][6],一个 MIT 家族的许可证被加上了“这个软件应该被应用于好的,而不是恶的”。这件事情可能是“非常克罗克福特”的(译者注,JSON 格式和 JSON.org 的作者)。这绝对是一件麻烦事,也许这个笑话应该只是在律师身上,但它一直延伸到银行业。
|
||||
|
||||
这个故事的寓意是:“MIT 许可证”本身就是模棱两可的。大家可能很清楚你的意思,但你只需要把标准的 MIT 许可证文本复制到你的项目中,就可以节省每个人的时间。如果使用元数据(如包管理器中的元数据文件)来制定 “MIT 许可证”,请确保 “LICENSE” 文件和任何头部的注释都适用标准的许可证文本。所有的这些都可以[自动化完成][7]。
|
||||
|
||||
|
||||
##### 版权说明
|
||||
|
||||
> Copyright (c) <year> <copyright holders>
|
||||
|
||||
|
||||
在 1976 年《版权法》颁布之前,美国的版权法要求采取具体的行动,即所谓的“手续”来确保创意作品的版权。如果你不遵守这些手续,你起诉他人未经授权使用你的作品的权力就会受到限制,往往完全丧失权力,其中一项手续就是 "通知"。在你的作品上打上记号,以其他方式让市场知道你拥有版权 ©是一个标准符号,用于标记受版权保护的作品,以发出版权通知。ASCII 字符集没有©符号,但`Copyright (c)`可以表达同样的意思。
|
||||
|
||||
1976 年的版权法“执行”了国际《伯尔尼公约》的许多要求, 取消了确保版权的手续。至少在美国,著作权人在起诉侵权之前,仍然需要对自己的版权作品进行登记,如果在侵权行为开始之前进行登记,可能会获得更高的赔偿。但在实践中,很多人在对某个人提起诉讼之前,都会先注册版权。你并不会因为没有在上面贴上告示、注册、向国会图书馆寄送副本等而失去版权。
|
||||
|
||||
即使版权声明不像过去那样绝对必要,但它们仍然有很多用处。说明作品的创作年份和版权属于谁,可以让人知道作品的版权何时到期,从而使作品进入公共领域。作者或作者们的身份也很有用。美国法律对个人作者和"公司"作者的版权条款的计算方式不同。特别是在商业用途中,公司在使用已知竞争对手的软件时,可能也要三思而行,即使许可条款给予了非常慷慨的许可。如果你希望别人看到你的作品并想从你这里获得许可,版权声明可以很好地起到归属作用。
|
||||
|
||||
至于"版权持有人"。并非所有标准形式的许可证都有写明这一点的空间。最新的许可证形式,如[Apache 2.0][8]和[GPL 3.0][9],公布了 "LICENSE" 文本,这些文本是要逐字复制的,并在其他地方加上标题注释和单独的文件,以表明谁拥有版权和给予许可证。这些办法巧妙地阻止了对 "标准"文本的意外或故意的修改。这还使自动许可证识别更加可靠。
|
||||
|
||||
麻省理工学院的许可证是从为机构发布代码而写的语言演变而来。对于机构发布的代码,只有一个明确的 "版权持有人",即发布代码的机构。其他机构则抄袭了这些许可证,用他们自己的名字代替 "MIT",最终形成了我们现在的通用形式。这一过程同样适用于该时代的其他简短机构许可证,特别是加州大学伯克利分校的[最初的四条款 BSD 许可证][10],现在用于[三条款][11]和[两条款][12]变体,以及麻省理工学院的变体 — 互联网系统联盟的[ISC 许可证][13]。
|
||||
|
||||
在每一种情况下,该机构都根据版权所有权规则将自己列为版权持有人,这些规则称为“[雇佣作品][14]”规则,这些规则赋予雇主和客户对其雇员和承包商代表其从事的某些工作的版权所有权。这些规则通常不适用于自愿提交代码的分布式协作者。这给项目统筹型基金会(如 Apache 基金会和 Eclipse 基金会)带来了一个问题,它们接受来自更多不同贡献者的贡献。到目前为止,通常的基础方法是使用一个房产型许可证,它规定了一个版权持有者,如[Apache 2.0][8] 和 [EPL 1.0][15] — 并由贡献者许可协议 [Apache CLAs][16] 以及 [Eclipse CLAs][17] 支持,以从贡献者中收集权利。在像 GPL 这样的 "copyleft" 许可证下,将版权所有权收集在一个地方就更加重要了,因为 GPL 依靠版权所有者来执行许可证条件,以促进软件自由的价值。
|
||||
|
||||
如今,没有任何机构或业务统筹的大量项目都使用 MIT 风格的许可条款。 SPDX 和 OSI 通过标准化不涉及特定实体或机构版权持有人的 MIT 和 ISC 之类的许可证形式,为这些用例提供了帮助。有了这些许可证,项目作者的普遍做法是在许可证的版权声明中很早就填上自己的名字...也许还会在这里和那里填上年份。至少根据美国的版权法,由此产生的版权通知并不能说明全部情况。
|
||||
|
||||
某个软件的原始所有者保留其工作的所有权。但是,尽管 MIT 风格的许可条款赋予了他人开发和更改软件的权利,创造了法律所谓的“衍生作品”,但它们并没有赋予原始作者他人的贡献的所有权。相反,每个贡献者都以他们使用现有代码为起点进行的任何[甚至是少量创造][18]的作品来拥有版权。
|
||||
|
||||
这些项目中的大多数也对获得贡献者许可协议的想法犹豫不决,更不用说签署的版权转让了。这既幼稚又可以理解。尽管一些较新的开源开发人员假设在 GitHub 上发送 Pull Request “自动”根据项目现有许可证的条款授权分发贡献,但美国法律不承认任何此类规则。默认而强大的版本保护是不允许许可的。
|
||||
|
||||
更新:GitHub 后来修改了全站的服务条款,包括试图改变这一默认值,至少在 GitHub.com 上是这样。我在[另一篇][19]中写了一些对这一发展的并非都是正面的看法。
|
||||
|
||||
为了填补法律上有效的、有据可查的贡献权利授予与完全没有文件线索之间的差距,一些项目采用了[开发者原创证书][20],这是贡献者在 Git 提交中使用 "Signed-Off-By" 元数据标签暗示的标准声明。 开发人员原创证书是在臭名昭著的 SCO 诉讼之后,为 Linux 内核开发而开发的,该诉讼称 Linux 的大部分代码源自 SCO 拥有的 Unix 作为来源。作为创建显示 Linux 的每一行都来自贡献者的书面记录的一种方法,开发人员原创证书功能很好。尽管开发人员原产地证书不是许可证,但它确实提供了许多充分的证据,表明提交代码的人希望项目分发其代码,并让其他人根据内核现有的许可证条款使用该代码。内核还维护着一个机器可读的 “CREDITS” 文件,列出了具有名称,隶属关系,贡献区域和其他元数据的贡献者。我已经做了[一些][21][实验][22]针对不使用内核开发流程的项目进行了调整。
|
||||
|
||||
#### 许可证授权
|
||||
|
||||
> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”),
|
||||
|
||||
MIT 许可证的实质是许可证(你猜对了)。一般来说,许可证是一个人或法律实体"许可人"给予另一个人"被许可人"做一些法律允许他们起诉的事情的许可。MIT 许可证是一种不起诉的承诺。
|
||||
|
||||
法律有时将许可证与给予许可证的承诺区分开来。如果有人违背了提供许可证的承诺,你可以起诉他们违背了承诺,但你最终可能得不到许可证。“特此”是律师们永远摆脱不了的一个老生常谈的词。这里使用它来显示许可证文本本身提供了许可证,而不仅仅是许可证的承诺。这是合法的[IIFE][23]。
|
||||
|
||||
尽管许多许可证都授予特定的命名许可证持有人许可,但 MIT 许可证是“公共许可证”。 公共许可证授予所有人(包括整个公众)许可。 这是开源许可中的三大创意之一。 MIT 许可证通过“向任何获得……软件副本的人”授予许可证来体现这一思想。 稍后我们将看到,获得此许可证还有一个条件,即确保其他人也可以了解他们的许可。
|
||||
|
||||
在美国式法律文件中,带引号大写的附加语(定义)是赋予术语特定含义的标准方式。当法院看到文件中其他地方使用了一个已定义的大写术语时,法院将可靠地回顾定义中的术语。
|
||||
|
||||
##### 授权范围
|
||||
|
||||
> to deal in the Software without restriction,
|
||||
|
||||
从被许可人的角度来看,这是 MIT 许可证中最重要的七个字。关键的法律问题是被起诉侵犯版权和被起诉侵犯专利。无论是版权法还是专利法都没有将 "to deal in" 作为一个术语,它在法庭上没有特定的含义。因此,任何法院在裁决许可人和被许可人之间的纠纷时,都会问双方对这种语言的含义和理解。法院将看到的是,该措辞有意宽泛和开放。它使被许可人强烈反对许可人的任何主张,即他们没有许可被许可人使用该软件做特定的事情,即使在授予许可时双方都没有明显想到。
|
||||
|
||||
> including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
|
||||
任何一篇法律文章都不是完美的,“意义上完全确定”或明确无误的。小心那些装作不一样的人。这是 MIT 许可证中最不完美的部分。主要有三个问题:
|
||||
|
||||
首先,“包括但不限于”是一种法律反模式。它有多种衍生:
|
||||
|
||||
* 包括但不限于
|
||||
|
||||
* 包括但不限于前述条文的一般性
|
||||
|
||||
* 包括但不限于
|
||||
|
||||
* 很多,很多毫无意义的变化
|
||||
|
||||
所有这些都有一个共同的目标,但都未能可靠地实现。从根本上说,使用它们的起草者也会尽量试探着去做。在MIT许可证中,这意味着引入“软件交易”的具体例子 — “使用、复制、修改”等等,但不意味着被许可方的行为必须与给出的例子类似,才能算作“交易”。问题是,如果你最终需要法庭来审查和解释许可证的条款,法庭将把它的工作看作是找出这些语言的含义。如果法院需要决定“交易”的含义,它不能“看不到”这些例子,即使你告诉它。我认为“不受限制的软件交易”本身对被许可方更好,也更短。
|
||||
|
||||
其次,作为 “deal in” 例子的动词是一个大杂烩。有些在版权法或专利法下有特定的含义,有些几乎有或根本没有:
|
||||
|
||||
|
||||
* 使用出现在 [美国法典第 35 篇, 第 271(a)节][24], 专利法列出了专利权人可以在未经许可的情况下起诉他人的行为。
|
||||
|
||||
* 拷贝出现在 [美国法典第 17 篇, 第 106 节][25], 版权法列出了版权所有人可以在未经许可的情况下起诉他人的行为。
|
||||
|
||||
* 修改既不出现在版权法中,也不出现在专利法中。它可能最接近版权法下的“准备衍生作品”,但也可能涉及改进或其他衍生发明。
|
||||
|
||||
* 无论是在版权法还是专利法中,合并都没有出现。“合并”在版权方面有特定的含义,但这显然不是本文的意图。相反,法院可能会根据其在行业中的含义来解读“合并”,如“合并法典”。
|
||||
|
||||
* 无论是在版权法还是专利法中,都没有公布。由于“软件”是正在出版的东西,根据[版权法][25],它可能最接近于“发行”。该法令还包括“公开”表演和展示作品的权利,但这些权利只适用于特定类型的受版权保护的作品,如戏剧、录音和电影。
|
||||
|
||||
* 分发出现在[版权法][25]中。
|
||||
|
||||
* 分许可是知识产权法的总称。再许可权是指授予他人自己的许可,进行您所许可的部分或全部活动的权利。实际上,MIT 许可证的分许可证权利实际上在开放源代码许可证中并不常见。希瑟·米克(Heather Meeker)所说的规范是“直接许可”方法,在这种方法中,每个获得该软件及其许可条款副本的人都直接从所有者那里获得许可。任何可能根据 MIT 许可证获得分许可证的人都可能会得到一份许可证副本,告诉他们他们也有直接许可证。
|
||||
|
||||
|
||||
* 卖书是个混血儿。它接近于[专利法][24]中的“要约出售”和“出售”,但指的是“复制品”,一种版权概念。在版权方面,它似乎接近于“分发”,但[版权法][25]没有提到销售。
|
||||
|
||||
* 允许向其提供软件的人员这样做似乎是多余的“分许可”。这也是不必要的,因为获得拷贝的人也可以直接获得许可证。
|
||||
|
||||
最后,由于这种法律、行业、一般知识产权和一般使用条款的混杂,并不清楚《麻省理工学院许可证》是否包括专利许可。一般性语言 "交易 "和一些例子动词,尤其是 "使用",都指向了尽管是一个非常不明确的许可的专利许可。许可证来自于版权人,而版权人可能对软件中的发明拥有或不拥有专利权,以及大多数的例子动词和 "软件" 本身的定义,都强烈地指向版权许可证。诸如[Apache 2.0][8]之类的较新的开放源代码许可分别特别地处理了版权,专利甚至商标。
|
||||
|
||||
##### 三个许可条件
|
||||
|
||||
> subject to the following conditions:
|
||||
|
||||
总有一个陷阱!麻省理工有三个!
|
||||
|
||||
如果你不遵守麻省理工学院许可证的条件,你就得不到许可证提供的许可。因此,如果不按照条件所说的去做,至少在理论上会让你面临一场诉讼,很可能是一场版权诉讼。
|
||||
|
||||
开源软件的第二个好主意是,利用软件对被许可人的价值来激发对条件的遵守,即使被许可人不为许可支付任何费用。 最后一个想法,在《麻省理工学院许可证》中没有,它建立在许可证条件之上。像[GNU 通用公共许可证][9]这样的 "Copyleft "许可证,使用许可证条件来控制那些进行修改的人如何对其修改后的版本进行许可和发布。
|
||||
|
||||
##### 通知条件
|
||||
|
||||
> The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
如果你给别人一份软件的副本,你需要包括许可证文本和任何版权声明。这有几个关键目的。
|
||||
|
||||
1. 给别人一个通知,说明他们在公共许可证下对软件有许可。这是直接授权模式的一个关键部分,在这种模式下,每个用户都能直接从版权持有人那里获得授权。
|
||||
|
||||
2. 让人们知道谁是软件的幕后推手,这样他们就可以得到赞美、荣耀和冷冰冰的现金捐赠。
|
||||
|
||||
3. 确保保修免责声明和责任限制(下一步)跟在软件后面。每一个得到副本的人也应该得到一份这些许可人保护的副本。
|
||||
|
||||
|
||||
没有任何东西可以阻止你为提供一个没有源代码的副本,甚至是编译形式的副本而收费。但是当你这么做的时候,你不能假装 MIT 代码是你自己的专有代码,或者是在其他许可下提供的。获得“公共许可证”的人可以了解他们在“公共许可证”下的权利。
|
||||
|
||||
坦率地说,遵守这个条件是崩溃的。几乎所有的开源许可证都有这样的"归属"条件。系统和装机软件的制作者往往明白,他们需要为自己的每一个发行版本编制一个通知文件或 "许可证信息 "屏幕,并附上库和组件的许可证文本副本。项目统筹基金会在教授这些做法方面起到了重要作用。但是网络开发者作为一个整体,还没有得到备忘录。这不能用缺乏工具来解释,工具有很多,也不能用 npm 和其他资源库中的包的高度模块化来解释,它们统一了许可证信息的元数据格式。所有好的 JavaScript minifiers 都有命令行标志来保存许可证头注释。其他工具会从包树中连接`LICENSE`文件。这实在是无可厚非。
|
||||
|
||||
##### 免责声明
|
||||
|
||||
> The Software is provided “as is”, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement.
|
||||
|
||||
美国几乎每个州都颁布了统一商业法典的版本,该法典是规范商业交易的法律范本。 UCC 的第2条(加利福尼亚州的“第2分部”)规定了商品销售合同,从批量购买的二手车到大批工业化学品再到制造厂。
|
||||
|
||||
UCC 关于销售合同的某些规则是强制性的。 这些规则始终适用,无论买卖双方是否喜欢。 其他只是“默认值”。 除非买卖双方以书面形式选择退出,否则 UCC 表示他们希望在 UCC 文本中找到交易的基准规则。 默认规则中包括隐含的“保证”,或卖方对买方关于所售商品的质量和可用性的承诺。
|
||||
|
||||
关于诸如 MIT 许可证之类的公共许可证是合同(许可方和被许可方之间的可执行协议)还是仅仅是许可,这在理论上存在很大争议,这是一种方式,但可能附带条件。 关于软件是否被视为“商品”,从而触发了 UCC 的规则,争论较少。 许可人之间没有就赔偿责任进行辩论:如果他们免费提供的软件可以免费休息,造成问题,无法正常工作或以其他方式引起麻烦,那么他们就不会被起诉要求巨额赔偿。 这与“默示保证”的三个默认规则完全相反:
|
||||
|
||||
1. [UCC 第2-314节][26]所隐含的“可商购性”保证是对“商品”(即软件)的质量至少为平均水平,并经过适当包装和标记,并符合其常规用途, 意在服务。 仅当提供该软件的人是该软件的“商人”时,此保证才适用,这意味着他们从事软件交易并表现出对软件的熟练程度。
|
||||
|
||||
2. 当卖方知道买方依靠他们提供用于特定目的的货物时,[UCC第 2-315节][27]中的“针对特定目的的适用性”的隐含担保即刻生效。 为此,商品实际上需要“适合”。
|
||||
|
||||
3. 隐含的“非侵权”保证不是 UCC 的一部分,而是一般合同法的共同特征。 如果事实证明买方收到的商品侵犯了他人的知识产权,则该隐含的承诺将保护买方。 如果根据MIT许可获得的软件实际上并不属于尝试许可该软件的软件,或者属于他人拥有的专利,那就属于这种情况。
|
||||
|
||||
|
||||
UCC 的[第2-316(3)节][28]要求,出于明显的目的,选择退出或“排除”隐含的适销性和适用性的默示保证。 反过来,“显眼”是指书写或格式化以引起人们的注意,这与微观精细印刷的反义词相反,意在溜过粗心的消费者。 州法律可能会对不侵权免责声明施加类似的引人注目的要求。
|
||||
|
||||
长期以来,律师们都有一种错觉,认为用 "全大写 "写任何东西都符合明显的要求。这是不正确的。法院曾批评律师协会自以为是,而且大多数人都认为,全大写更多的是阻止阅读,而不是强制阅读。同样的,大多数开源许可表格都将其担保免责声明设置为全大写,部分原因是这是在纯文本的 `LICENSE` 文件中唯一明显的方式。我更喜欢使用星号或其他 ASCII 艺术,但那是很久很久以前的事了。
|
||||
|
||||
##### 责任限制
|
||||
|
||||
> In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the Software or the use or other dealings in the Software.
|
||||
|
||||
麻省理工学院许可证允许 "免费 "使用软件,但法律并不认为接受免费许可证的人在出错时放弃了起诉的权利,而要责怪许可人。"责任限制",通常与 "损害赔偿排除条款 "搭配使用,其作用与许可证很像,是不起诉的承诺。但这些都是保护许可人免受被许可人起诉的保护措施。
|
||||
|
||||
一般来说,法院对责任限制和损害赔偿排除条款的解读非常谨慎,因为这些条款可以将大量的风险从一方转移到另一方。为了保护社会的重大利益,让人们有办法在法庭上纠正错误,他们 "严格解释 "限制责任的语言,在可能的情况下对受其保护的一方进行解读。责任限制必须具体才能成立。特别是在 "消费者 "合同和其他放弃起诉权的人缺乏复杂性或讨价还价能力的情况下,法院有时会拒绝尊重那些似乎被埋没在视线之外的语言。部分是出于这个原因,部分是出于习惯,律师们往往也会给责任限制以全称处理。
|
||||
|
||||
再往下看,"责任限制 "部分是对被许可人可以起诉的金额的上限。在开源许可证中,这个上限总是没有钱,0元,"不负责任"。相比之下,在商业许可证中,它通常是过去 12 个月内支付的许可证费用的倍数,尽管它通常是经过谈判的。
|
||||
|
||||
“排除”部分具体列出了各种法律主张,即请求赔偿的理由,许可人无法使用。 像许多其他法律形式一样,MIT 许可证 提到了“违反合同”的行为(即违反合同)和“侵权”的行为。 侵权规则是防止粗心或恶意伤害他人的一般规则。 如果您在发短信时在路上撞人,则表示您犯了侵权行为。 如果您的公司销售的有问题的耳机会烧伤人们的耳朵,则说明您的公司已经侵权。 如果合同没有明确排除侵权索赔,那么法院有时会在合同中使用排除语言,以仅阻止合同索赔。 出于很好的考虑, MIT 许可证抛出“或其他”字样,只是为了抓住奇怪的海事法或其他奇特的法律主张。
|
||||
|
||||
“产生于、来自或与之相关”这句话是法律起草人固有的、焦虑的不安全感的反复出现的症状。关键是,任何与软件有关的诉讼都包含在限制和排除范围内。在偶然的情况下,有些东西可以“产生”,但不能“产生”,或者“与之相关”,把这三者都放在形式上感觉更好,所以把它们打包。更不用说,任何法院被迫在表格的这一部分分头讨论的问题,都必须对每一个问题给出不同的含义,前提是专业的起草者不会在一行中使用不同的词来表示同一件事。更不用说,在实践中,如果法院对一开始不受欢迎的限制感觉不好,那么他们将更愿意狭隘地解读范围触发器。但我离题了。同样的语言出现在数以百万计的合同中。
|
||||
|
||||
#### 总结
|
||||
|
||||
所有这些诡辩都有点像在进教堂的路上吐口香糖。MIT 许可证是一个法律经典且有效。 它绝不是所有软件 IP 弊病的灵丹妙药,尤其是它早在几十年前就已经出现的软件专利灾难。但麻省理工学院风格的许可证发挥了令人钦佩的作用,实现了一个狭隘的目的,用最少的谨慎的法律工具组合扭转了版权、销售和合同法等棘手的默认规则。在计算的大背景下,它的寿命是惊人的。麻省理工学院的许可证已经和将要超过绝大多数的软件许可证。我们只能猜测,当它最终失宠时,它将提供多少年忠实的法律服务。对于那些付不起自己律师的人来说,这是特别慷慨的。
|
||||
|
||||
我们已经看到,我们今天所知道的麻省理工学院的许可证是一套具体的、标准化的条款,最终将秩序带入了一个混乱的机构特定的、随意的变化。
|
||||
|
||||
我们已经看到了它的方法,归因和版权通知通知知识产权管理的做法,学术,标准,商业和基础机构。
|
||||
|
||||
我们已经看到了麻省理工学院的许可证是如何免费授予所有人软件许可的,但前提是要保护许可人不受担保和责任的影响。
|
||||
|
||||
我们已经看到,尽管有一些刻薄的措辞和律师的矫揉造作,但一百七十一个小词可以完成大量的法律工作,通过密集的知识产权和合同丛林为开源软件扫清了一条道路。
|
||||
我非常感谢所有花时间阅读这篇相当长的文章的人,让我知道他们发现它很有用,并帮助改进它。一如既往,我欢迎您通过[e-mail][29]、[Twitter][30]和[GitHub][31]发表评论。
|
||||
|
||||
|
||||
有很多人问,他们在哪里可以读到更多的东西,或者找到其他许可证,比如 GNU 通用公共许可证或 Apache 2.0 许可证。无论你的兴趣是什么,我都会向你推荐以下书籍:
|
||||
|
||||
* Andrew M. St. Laurent 的 [Understanding Open Source & Free Software Licensing][32], 来自 O’Reilly.
|
||||
|
||||
我先说这本,因为虽然它有些过时,但它的方法也最接近上面使用的逐行方法。O'Reilly 已经把它[放在网上][33]。
|
||||
|
||||
* Heather Meeker’s [Open (Source) for Business][34]
|
||||
|
||||
在我看来,这是迄今为止关于 GN U通用公共许可证和更广泛的 copyleft 的最佳著作。这本书涵盖了历史、许可证、它们的发展,以及兼容性和合规性。这本书是我给那些考虑或处理 GPL 的客户的书。
|
||||
|
||||
* Larry Rosen’s [Open Source Licensing][35], from Prentice Hall.
|
||||
|
||||
一本很棒的第一本书,也可以免费[在线阅读][36]。对于从零开始的程序员来说,这是开源许可和相关法律的最好介绍。这本在一些具体细节上也有点过时了,但 Larry 的许可证分类法和对开源商业模式的简洁总结经得起时间的考验。
|
||||
|
||||
|
||||
|
||||
所有这些都对我作为一个开源许可律师的教育至关重要。它们的作者都是我的职业英雄。请读一读吧 — K.E.M
|
||||
|
||||
我将此文章基于 [Creative Commons Attribution-ShareAlike 4.0 license][37] 授权
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://writing.kemitchell.com/2016/09/21/MIT-License-Line-by-Line.html
|
||||
|
||||
作者:[Kyle E. Mitchell][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[bestony](https://github.com/bestony)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://kemitchell.com/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: http://spdx.org/licenses/MIT
|
||||
[2]: https://fedoraproject.org/wiki/Licensing:MIT?rd=Licensing/MIT
|
||||
[3]: https://opensource.org
|
||||
[4]: https://spdx.org
|
||||
[5]: http://spdx.org/licenses/
|
||||
[6]: https://spdx.org/licenses/JSON
|
||||
[7]: https://www.npmjs.com/package/licensor
|
||||
[8]: https://www.apache.org/licenses/LICENSE-2.0
|
||||
[9]: https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||
[10]: http://spdx.org/licenses/BSD-4-Clause
|
||||
[11]: https://spdx.org/licenses/BSD-3-Clause
|
||||
[12]: https://spdx.org/licenses/BSD-2-Clause
|
||||
[13]: http://www.isc.org/downloads/software-support-policy/isc-license/
|
||||
[14]: http://worksmadeforhire.com/
|
||||
[15]: https://www.eclipse.org/legal/epl-v10.html
|
||||
[16]: https://www.apache.org/licenses/#clas
|
||||
[17]: https://wiki.eclipse.org/ECA
|
||||
[18]: https://en.wikipedia.org/wiki/Feist_Publications,_Inc.,_v._Rural_Telephone_Service_Co.
|
||||
[19]: https://writing.kemitchell.com/2017/02/16/Against-Legislating-the-Nonobvious.html
|
||||
[20]: http://developercertificate.org/
|
||||
[21]: https://github.com/berneout/berneout-pledge
|
||||
[22]: https://github.com/berneout/authors-certificate
|
||||
[23]: https://en.wikipedia.org/wiki/Immediately-invoked_function_expression
|
||||
[24]: https://www.govinfo.gov/app/details/USCODE-2017-title35/USCODE-2017-title35-partIII-chap28-sec271
|
||||
[25]: https://www.govinfo.gov/app/details/USCODE-2017-title17/USCODE-2017-title17-chap1-sec106
|
||||
[26]: https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?sectionNum=2314.&lawCode=COM
|
||||
[27]: https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?sectionNum=2315.&lawCode=COM
|
||||
[28]: https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?sectionNum=2316.&lawCode=COM
|
||||
[29]: mailto:kyle@kemitchell.com
|
||||
[30]: https://twitter.com/kemitchell
|
||||
[31]: https://github.com/kemitchell/writing/tree/master/_posts/2016-09-21-MIT-License-Line-by-Line.md
|
||||
[32]: https://lccn.loc.gov/2006281092
|
||||
[33]: http://www.oreilly.com/openbook/osfreesoft/book/
|
||||
[34]: https://www.amazon.com/dp/1511617772
|
||||
[35]: https://lccn.loc.gov/2004050558
|
||||
[36]: http://www.rosenlaw.com/oslbook.htm
|
||||
[37]: https://creativecommons.org/licenses/by-sa/4.0/legalcode
|
262
translated/tech/20190221 Testing Bash with BATS.md
Normal file
262
translated/tech/20190221 Testing Bash with BATS.md
Normal file
@ -0,0 +1,262 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (stevenzdg988)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Testing Bash with BATS)
|
||||
[#]: via: (https://opensource.com/article/19/2/testing-bash-bats)
|
||||
[#]: author: (Darin London https://opensource.com/users/dmlond)
|
||||
|
||||
利用 BATS 测试 Bash
|
||||
======
|
||||
Bash 自动测试系统通过 Java,Ruby 和 Python 开发人员所使用的相同类型的测试进程来提交 Bash 代码。
|
||||
|
||||
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/todo_checklist_team_metrics_report.png?itok=oB5uQbzf)
|
||||
|
||||
用Java,Ruby和Python等语言编写应用程序的软件开发人员拥有完善的库,可以帮助他们随着时间的推移保持软件的完整性。他们创建测试,以在结构化环境中通过一系列执行来运行应用程序,以确保其所有软件方面均按预期工作。
|
||||
|
||||
当这些测试在持续集成(CI)系统中自动化时甚至会更加健壮,在这种情况下,每次推送到源知识库都会使测试运行,并且在测试失败时会立即通知开发人员。这种快速反馈提高了开发人员对其应用程序功能完整性的信心。
|
||||
|
||||
Bash 自动测试系统([BATS][1])使开发人员能够编写 Bash 脚本和库,以将Java,Ruby,Python 和其他开发人员所使用的相同惯例应用于其 Bash 代码。
|
||||
|
||||
### 安装 BATS
|
||||
|
||||
BATS GitHub 页面包含安装指令。有两个 BATS 帮助程序函数库,它们提供更强大的断言或允许使用 BATS 重写 Test Anything Protocol(测试协议)([TAP][2])输出格式。可以将它们安装在标准位置,并由所有脚本提供。在 Git 知识库中包含完整版本的 BATS 及其帮助函数库对于要测试的每组脚本或函数库可能会更实用。这可以使用 **[git submodule][3]** (git 子模块)系统来完成。
|
||||
|
||||
以下命令会将 BATS 及其帮助函数库安装到 Git 知识库中的 **test** 目录中。
|
||||
|
||||
```
|
||||
git submodule init
|
||||
git submodule add https://github.com/sstephenson/bats test/libs/bats
|
||||
git submodule add https://github.com/ztombol/bats-assert test/libs/bats-assert
|
||||
git submodule add https://github.com/ztombol/bats-support test/libs/bats-support
|
||||
git add .
|
||||
git commit -m 'installed bats'
|
||||
```
|
||||
|
||||
要克隆 Git 知识库并同时安装其子模块,请使用
|
||||
**\-recurse-submodules** 为 **git clone** 标记。
|
||||
|
||||
每个 BATS 测试脚本必须由 **bats** 可执行文件执行。如果您将 BATS 安装到源代码知识库的 **test/libs** 目录中,则可以使用以下命令调用测试:
|
||||
|
||||
```
|
||||
./test/libs/bats/bin/bats <path to test script>
|
||||
```
|
||||
|
||||
或者,将以下内容添加到每个 BATS 测试脚本的开头:
|
||||
|
||||
```
|
||||
#!/usr/bin/env ./test/libs/bats/bin/bats
|
||||
load 'libs/bats-support/load'
|
||||
load 'libs/bats-assert/load'
|
||||
```
|
||||
|
||||
并且执行命令 **chmod +x <测试脚本的路径>**。 这将 a) 使它们与安装在 **./test/libs/bats** 中的 BATS 可执行,并且 b) 包括这些帮助函数库。BATS 测试脚本通常存储在 **test** 目录中,并为要测试的脚本命名,扩展名为 **.bats**。例如,测试 **bin/build** 的 BATS 脚本应称为 **test/build.bats**。
|
||||
|
||||
您还可以通过正则表达式传递给 BATS 来运行整套 BATS 测试文件,例如 **./test/lib/bats/bin/bats test/*.bats**。
|
||||
|
||||
### 为 BATS 组织函数库和脚本的重写范围
|
||||
|
||||
Bash 脚本和库必须以一种有效地将其内部工作暴露给 BATS 的方式进行组织。通常,在调用或执行时库函数和运行诸多命令的 Shell 脚本不适合进行有效的 BATS 测试。
|
||||
|
||||
例如,[build.sh][4] 是许多人编写的典型脚本。本质上是一大堆代码。有些人甚至可能将这堆代码放入库中的函数中。但是,不可能在 BATS 测试中运行大量代码并涵盖在单独的测试用例中可能遇到的所有类型的故障。测试具有足够重写范围的这堆代码的唯一方法是将其分解为许多小的,可重用的,最重要的是可独立测试的功能。
|
||||
|
||||
向库添加更多功能(函数)很简单。额外的好处是其中一些功能本身可以变得出奇的有用。将库函数分解为许多较小的函数后,您可以在 BATS 测试中 **source** 库,并像测试任何其他命令一样运行这些函数。
|
||||
|
||||
Bash 脚本还必须分解为多个函数,执行脚本时,脚本的主要部分应调用这些函数。此外,还有一个非常有用的技巧,可以使使用 BATS 测试 Bash 脚本变得更加容易:将脚本主要部分中执行的所有代码都移到一个函数中,称为 **run_main**。然后,将以下内容添加到脚本的末尾:
|
||||
|
||||
```
|
||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]
|
||||
then
|
||||
run_main
|
||||
fi
|
||||
```
|
||||
|
||||
这段额外的代码做了一些特殊的事情。它使脚本当作为脚本执行时与使用 **source** 进入环境时的行为有所不同。此技巧使通过与测试库相同的方式测试脚本和测试各个函数功能成为可能。例如,利用脚本 [build.sh 重构以获得更好的 BATS 可测试性][5]。
|
||||
|
||||
### 编写和运行测试
|
||||
|
||||
如上所述,BATS 是一个 TAP 兼容测试框架,其语法和输出对于使用过其他 TAP 兼容测试套件(例如 JUnit,RSpec 或 Jest)的用户来说将是熟悉的。它的测试被组织进各个测试脚本。测试脚本被组织进一个或多个描述性 **@test** 块中,它们描述了被测试应用程序的单元。每个 **@test** 块都将运行一系列准备测试环境命令,运行要测试的命令,并对退出和被测试命令的输出进行断言。许多断言函数是通过 **bats** , **bats-assert** , 和 **bats-support** 库导入的,这些库在 BATS 测试脚本的开头加载到环境中。下面是一个典型的 BATS 测试块:
|
||||
|
||||
```
|
||||
@test "requires CI_COMMIT_REF_SLUG environment variable" {
|
||||
unset CI_COMMIT_REF_SLUG
|
||||
assert_empty "${CI_COMMIT_REF_SLUG}"
|
||||
run some_command
|
||||
assert_failure
|
||||
assert_output --partial "CI_COMMIT_REF_SLUG"
|
||||
}
|
||||
```
|
||||
|
||||
如果 BATS 脚本包含 **setup(安装)** 和/或 **teardown(拆卸)** 功能,则 BATS 将在每个测试块运行之前和之后自动执行它们。这样就可以创建环境变量,测试文件以及执行一个或所有测试所需的其他操作,然后在每次测试运行后将其拆卸。[**Build.bats**][6] 是对我们新格式化的 **build.sh** 脚本的完整 BATS 测试。(此测试中的 **mock_docker** 命令将在以下关于模拟/桩的部分中进行说明。)
|
||||
|
||||
当测试脚本运行时,BATS 使用 **exec** 来将每个 **@test** 块作为单独的子进程运行。这样就可以在一个 **@test** 中导出环境变量甚至函数,而不会影响其他 **@test** 或污染您当前的 Shell 会话。测试运行的输出是一种标准格式,可以被人理解,并且可以由 TAP 用户以编程方式进行解析或操作。下面是 **CI_COMMIT_REF_SLUG** 测试块失败时的输出示例:
|
||||
|
||||
```
|
||||
✗ requires CI_COMMIT_REF_SLUG environment variable
|
||||
(from function `assert_output' in file test/libs/bats-assert/src/assert.bash, line 231,
|
||||
in test file test/ci_deploy.bats, line 26)
|
||||
`assert_output --partial "CI_COMMIT_REF_SLUG"' failed
|
||||
|
||||
-- output does not contain substring --
|
||||
substring (1 lines):
|
||||
CI_COMMIT_REF_SLUG
|
||||
output (3 lines):
|
||||
./bin/deploy.sh: join_string_by: command not found
|
||||
oc error
|
||||
Could not login
|
||||
--
|
||||
|
||||
** Did not delete , as test failed **
|
||||
|
||||
1 test, 1 failure
|
||||
```
|
||||
|
||||
下面是成功测试的输出:
|
||||
|
||||
```
|
||||
✓ requires CI_COMMIT_REF_SLUG environment variable
|
||||
```
|
||||
|
||||
### 助手
|
||||
|
||||
像任何 Shell 脚本或库一样,BATS 测试脚本可以包括帮助程序库,以在测试之间共享通用代码或增强其性能。这些帮助程序库,例如 **bats-assert** 和 **bats-support** 甚至可以使用 BATS 进行测试。
|
||||
|
||||
如果测试目录中的文件数量庞大,则可以将库放置在同一测试目录中作为 BATS 脚本,也可以将它们放置在 **test/libs** 目录中。BATS 提供了 **load** 函数,该函数采用相对于要测试的脚本的 Bash 文件的路径(例如,在我们的示例中的 **test**),并声明该文件。文件必须以前缀 **.bash** 结尾,但是传递给 **load** 函数的文件路径不能包含前缀。**build.bats** 加载 **bats-assert** 和 **bats-support** 库,一个小型 **[helpers.bash][7]** 库以及 **docker_mock.bash** 库(如下所述),以下代码位于解释器调谐线下方的测试脚本的开头:
|
||||
|
||||
```
|
||||
load 'libs/bats-support/load'
|
||||
load 'libs/bats-assert/load'
|
||||
load 'helpers'
|
||||
load 'docker_mock'
|
||||
```
|
||||
|
||||
### 测试输入桩和模拟外部调用
|
||||
|
||||
大多数 Bash 脚本和库运行时执行函数和(或)可执行文件。通常,它们被程序化为基于特定方式运行退出状态或这些函数或可执行文件的输出(**stdout**,**stderr**)。为了正确地测试这些脚本,通常需要制作这些命令的伪版本,这些被设计用来在特定测试过程中以特定方式运行,称为“桩(桩?)”。可能还需要监视正在测试的程序,以确保其调用了特定命令,或者使用特定参数调用了特定命令,此过程称为“模拟”。有关更多信息,请查看在 Ruby RSpec 中适用于任何测试系统的伟大的 [有关模拟和桩的讨论][8]。
|
||||
|
||||
Bash shell 提供了的技巧,可以在您的 BATS 测试脚本中使用进行模拟和桩。所有这些都需要使用带有 **-f** 标志的 Bash **export** 命令来导出重写原始函数或可执行文件的函数。必须在测试程序执行之前完成此操作。下面是重写可执行命令 **cat** 的简单示例:
|
||||
|
||||
```
|
||||
function cat() { echo "THIS WOULD CAT ${*}" }
|
||||
export -f cat
|
||||
```
|
||||
|
||||
此方法以相同的方式重写函数。如果测试需要重写要测试的脚本或库中的函数,则在对函数进行桩或模拟之前,必须先声明已测试脚本或库,这一点很重要。否则,在声明脚本时,桩/模拟将被原函数替代。另外,在运行即将进行的测试命令之前确认桩/模拟。下面是**build.bats**的示例,该示例模拟**build.sh**中描述的**raise**函数,以确保利用登录函数引发特定的错误消息:
|
||||
|
||||
```
|
||||
@test ".login raises on oc error" {
|
||||
source ${profile_script}
|
||||
function raise() { echo "${1} raised"; }
|
||||
export -f raise
|
||||
run login
|
||||
assert_failure
|
||||
assert_output -p "Could not login raised"
|
||||
}
|
||||
```
|
||||
|
||||
一般情况下,没有必要在测试后复原桩/模拟功能,因为 **export**(输出)仅在当前 **@test** 块的 **exec**(执行)期间影响当前子进程。但是,可以模拟/桩 BATS **assert** 函数在内部使用的命令(例如**cat**,**sed**等)是可能的。在运行这些断言命令之前,必须对这些模拟/桩函数进行 **unset**(复原) ,否则它们将无法正常工作。下面是 **build.bats** 中的一个示例,该示例模拟 **sed**,运行 **build_deployable** 函数并在运行任何断言之前复原 **sed**:
|
||||
|
||||
```
|
||||
@test ".build_deployable prints information, runs docker build on a modified Dockerfile.production and publish_image when its not a dry_run" {
|
||||
local expected_dockerfile='Dockerfile.production'
|
||||
local application='application'
|
||||
local environment='environment'
|
||||
local expected_original_base_image="${application}"
|
||||
local expected_candidate_image="${application}-candidate:${environment}"
|
||||
local expected_deployable_image="${application}:${environment}"
|
||||
source ${profile_script}
|
||||
mock_docker build --build-arg OAUTH_CLIENT_ID --build-arg OAUTH_REDIRECT --build-arg DDS_API_BASE_URL -t "${expected_deployable_image}" -
|
||||
function publish_image() { echo "publish_image ${*}"; }
|
||||
export -f publish_image
|
||||
function sed() {
|
||||
echo "sed ${*}" >&2;
|
||||
echo "FROM application-candidate:environment";
|
||||
}
|
||||
export -f sed
|
||||
run build_deployable "${application}" "${environment}"
|
||||
assert_success
|
||||
unset sed
|
||||
assert_output --regexp "sed.*${expected_dockerfile}"
|
||||
assert_output -p "Building ${expected_original_base_image} deployable ${expected_deployable_image} FROM ${expected_candidate_image}"
|
||||
assert_output -p "FROM ${expected_candidate_image} piped"
|
||||
assert_output -p "build --build-arg OAUTH_CLIENT_ID --build-arg OAUTH_REDIRECT --build-arg DDS_API_BASE_URL -t ${expected_deployable_image} -"
|
||||
assert_output -p "publish_image ${expected_deployable_image}"
|
||||
}
|
||||
```
|
||||
|
||||
有的时候相同的命令,例如 `foo`,将在被测试的同一函数中使用不同的参数多次调用。 这些情况需要创建一组函数:
|
||||
|
||||
* mock_foo:将期望的参数作为输入,并将其持久化到 TMP 文件中
|
||||
* foo:命令的模拟版本,该命令使用持久化的预期参数列表处理每个调用。必须使用 `export -f` 将其导出。
|
||||
* cleanup_foo:删除 TMP 文件,用于拆卸函数。这可以进行测试以确保在删除之前成功完成 `@test` 块。
|
||||
|
||||
由于此功能通常在不同的测试中重复使用,因此创建可以像其他库一样加载的帮助程序库会变得有意义。
|
||||
|
||||
**[docker_mock.bash][9]**是一个很棒的例子。它被加载到 **build.bats** 中,并在任何测试调用 Docker 可执行文件的函数的测试块中使用。使用 **docker_mock** 典型的测试块如下所示:
|
||||
|
||||
```
|
||||
@test ".publish_image fails if docker push fails" {
|
||||
setup_publish
|
||||
local expected_image="image"
|
||||
local expected_publishable_image="${CI_REGISTRY_IMAGE}/${expected_image}"
|
||||
source ${profile_script}
|
||||
mock_docker tag "${expected_image}" "${expected_publishable_image}"
|
||||
mock_docker push "${expected_publishable_image}" and_fail
|
||||
run publish_image "${expected_image}"
|
||||
assert_failure
|
||||
assert_output -p "tagging ${expected_image} as ${expected_publishable_image}"
|
||||
assert_output -p "tag ${expected_image} ${expected_publishable_image}"
|
||||
assert_output -p "pushing image to gitlab registry"
|
||||
assert_output -p "push ${expected_publishable_image}"
|
||||
}
|
||||
```
|
||||
|
||||
该测试建立了一个使用不同的参数两次调用 Docker 的预期。在对Docker 的第二次调用失败时,将运行测试命令,然后测试退出状态和对 Docker 调用的预期。
|
||||
|
||||
一方面 BATS 利用 **mock_docker.bash** 引入 **${BATS_TMPDIR}** 环境变量,BATS 在测试开始的位置对其进行了设置,以允许测试和助手程序在标准位置创建和销毁 TMP 文件。如果测试失败,**mock_docker.bash** 库将不会删除其持久化的模拟文件,但会在其所在位置进行打印,以便可以查看和删除它。您可能需要定期从该目录中清除旧的模拟文件。
|
||||
|
||||
请注意关于模拟/桩的警告:**build.bats** 测试有意识地违反了关于测试声明的规定:[不要模拟没有拥有的!][10]该规定要求调用开发人员没有编写代码的测试命令,例如 **docker**,**cat**,**sed**等,应封装在自己的库中,应在使用它们脚本的测试中对其进行模拟。然后应该在不模拟外部命令的情况下测试封装库。
|
||||
|
||||
这是一个很好的建议,而忽略它是有代价的。如果 Docker CLI API 发生变化,则测试脚本将不会检测到此变化,从而导致一个错误内容直到经过测试的 **build.sh** 脚本在使用新版本 Docker 的生产环境中运行后才显示出来。测试开发人员必须确定要严格遵守此标准的程度,但是他们应该了解其所涉及的权衡。
|
||||
|
||||
### 总结
|
||||
|
||||
在任何软件开发项目中引入测试方案都会在 a)增加开发和维护代码及测试所需的时间和组织与 b)增加开发人员在对应用程序整个生命周期中完整性的信心之间进行权衡。测试方案可能不适用于所有脚本和库。
|
||||
|
||||
通常,满足以下一个或多个条件的脚本和库才可以使用 BATS 测试:
|
||||
|
||||
* They are used by others
|
||||
* 值得存储在源代码管理中
|
||||
* 用于关键进程中,并可以长期稳定运行
|
||||
* 需要定期对其进行修改以添加/删除/修改其函数
|
||||
* 可以被其他人使用
|
||||
|
||||
一旦决定将测试规则应用于一个或多个 Bash 脚本或库,BATS 将提供其他软件开发环境中可用的全面测试功能。
|
||||
|
||||
致谢:感激[Darrin Mann][11]向我引荐了 BATS 测试。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/2/testing-bash-bats
|
||||
|
||||
作者:[Darin London][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[stevenzdg988](https://github.com/stevenzdg988)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/dmlond
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://github.com/sstephenson/bats
|
||||
[2]: http://testanything.org/
|
||||
[3]: https://git-scm.com/book/en/v2/Git-Tools-Submodules
|
||||
[4]: https://github.com/dmlond/how_to_bats/blob/preBats/build.sh
|
||||
[5]: https://github.com/dmlond/how_to_bats/blob/master/bin/build.sh
|
||||
[6]: https://github.com/dmlond/how_to_bats/blob/master/test/build.bats
|
||||
[7]: https://github.com/dmlond/how_to_bats/blob/master/test/helpers.bash
|
||||
[8]: https://www.codewithjason.com/rspec-mocks-stubs-plain-english/
|
||||
[9]: https://github.com/dmlond/how_to_bats/blob/master/test/docker_mock.bash
|
||||
[10]: https://github.com/testdouble/contributing-tests/wiki/Don't-mock-what-you-don't-own
|
||||
[11]: https://github.com/dmann
|
@ -0,0 +1,98 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (robsean)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Run your favorite Windows applications on Linux)
|
||||
[#]: via: (https://opensource.com/article/21/2/linux-wine)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
在 Linux 上运行你最喜欢的 Windows 应用程序
|
||||
======
|
||||
WINE 是一个开放源文件的项目,它协助很多 Windows 应用程序在 Linux 上运行,就好像它们是本地程序一样。
|
||||
![打开文件或窗口的计算机屏幕][1]
|
||||
|
||||
在 2021 年,有很多人们比为什么以往更喜欢 Linux 的原因。在这系列中,我将分享使用 Linux 的 21 种的不同原因。这里是如何使用 WINE 来实现从 Windows 到 Linux 的无缝切换。
|
||||
|
||||
你有仅在 Windows 上运行的应用程序吗?是这个应用程序的事情阻碍你切换到 Linux 吗?如果是这样的话,你将会很高兴知道 WINE, 一个开放源文件工程,几乎彻底改造了关键的 Windows 库,以便为 Windows 编译的应用程序可以在 Linux 上运行。
|
||||
|
||||
WINE 代表着 "Wine Is Not an Emulator" ,它引用驱动这项技术的代码。开放源文件开发者从 1993 年开始致力将应用程序任何传入的 Windows API调用翻译为 [POSIX][2] 调用。
|
||||
|
||||
这是一个令人十分惊讶的编程壮举,尤其是考虑到这个项目是独立运行的,没有来自 Microsoft (客观的说)的帮助,但是这里有局限性。一个应用程序偏离 Windows API 的 “内核” 越远,WINE 就越不能预期应用程序的请求。这里有一些供应商可以弥补这一点,尤其是 [Codeweavers][3] 和 [Valve Software][4]。在需要翻译应用程序的制作者和制作翻译的人们和公司之间没有协调配合,因此,在两者之间可能会有一些时间上的滞后,例如,一个更新的软件标题和当它从 [WINE 总部][5] 获得“黄金”身份时。
|
||||
|
||||
然而,如果你想在 Linux 上运行一个著名的 Windows 应用程序,WINE 可能已经为它准备好了可能性。
|
||||
|
||||
### 安装 WINE
|
||||
|
||||
你可以从你的 Linux 发行版的软件包存储库中安装 WINE 。在 Fedora ,CentOS Stream ,或 RHEL 系统上:
|
||||
|
||||
|
||||
```
|
||||
`$ sudo dnf install wine`
|
||||
```
|
||||
|
||||
在 Debian ,Linux Mint ,Elementary 及相似的系统上:
|
||||
|
||||
|
||||
```
|
||||
`$ sudo apt install wine`
|
||||
```
|
||||
|
||||
WINE 不是一个你启动它本身的应用程序。当启动一个 Windows 应用程序时,它是一个被调用的后端。你与 WINE 的第一次交互很可能就发生在你启动一个 Windows 应用程序的安装程序。
|
||||
|
||||
### 安装一个应用程序
|
||||
|
||||
[TinyCAD][6] 是一个极好的用于设计电路的开放源文件的应用程序,但是它仅在 Windows 上可用。虽然它是一个小型的应用程序,但是它确实包含一些 .NET 组件,因此应该能对 WINE 进行一些压力测试。
|
||||
|
||||
首先,下载 TinyCAD 的安装程序。Windows 安装程序通常都是这样,它是一个 `.exe` 文件。在下载后,双击文件来启动它。
|
||||
|
||||
![WINE TinyCAD 安装向导][7]
|
||||
|
||||
针对 TinyCAD 的 WINE 安装向导
|
||||
|
||||
像你在 Windows 上一样逐步a完成安装程序。通常最好接受默认选项,尤其是与 WINE 有关的地方。WINE 环境基本上是独立的,隐藏在你的硬盘驱动器上的一个 **drive_c** 目录中,作为Windows 应用程序使用的一个文件系统的仿真根目录。
|
||||
|
||||
![WINE TinyCAD 安装和明白驱动器][8]
|
||||
|
||||
WINE TinyCAD 目标驱动器
|
||||
|
||||
在它安装后,应用程序通常会为你提供启动器。如果你正准备测试一下它的话,启动应用程序。
|
||||
|
||||
### 启动一个 Windows 应用程序
|
||||
|
||||
除了在安装后的第一次启动外,在正常情况下,你启动一个 WINE 应用程序的方式与你启动一个本地 Linux 应用程序相同。不管你使用一个应用程序菜单或一个 Activities 屏幕或者只是在一个运行器中输入应用程序的名称,在 WINE 中运行的桌面 Windows 应用程序都会被视为在 Linux 上的本地应用程序。
|
||||
|
||||
![TinyCAD 使用 WINE 运行][9]
|
||||
|
||||
通过 WINE 的支持来运行 TinyCAD
|
||||
|
||||
### 当 WINE 失败时
|
||||
|
||||
我在 WINE 中的大多数应用程序,包括 TinyCAD ,都能如期运行。不过,也会有意外。在这些情况下,你可以静候几个月来查看 WINE 开发者 (或者,如果它是一款游戏,等候 Valve Software) 是否进行追加修补,或者你可以联系一个像or you can contact a vendor like Codeweavers 这样的供应商来查看他们是否出售对你所需要的应用程序的服务支持。
|
||||
|
||||
### WINE 是作弊的,但是它使用了一种很好的方法。
|
||||
|
||||
一些 Linux 用户觉得:如果你使用 WINE 的话,你就是在 Linux 上“作弊”。它可能会让人有这种感觉,但是 WINE 是一个开放源文件的项目,它能够使用户切换到 Linux ,并且仍然能为他们运行工作或爱好所必要的应用程序。如果 WINE 能解决你的问题,并且让你使用 Linux 的话,那么就使用它,并拥抱 Linux 的灵活性。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/2/linux-wine
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[robsean](https://github.com/robsean)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/browser_screen_windows_files.png?itok=kLTeQUbY (Computer screen with files or windows open)
|
||||
[2]: https://opensource.com/article/19/7/what-posix-richard-stallman-explains
|
||||
[3]: https://www.codeweavers.com/crossover
|
||||
[4]: https://github.com/ValveSoftware/Proton
|
||||
[5]: http://winehq.org
|
||||
[6]: https://sourceforge.net/projects/tinycad/
|
||||
[7]: https://opensource.com/sites/default/files/wine-tinycad-install.jpg
|
||||
[8]: https://opensource.com/sites/default/files/wine-tinycad-drive_0.jpg
|
||||
[9]: https://opensource.com/sites/default/files/wine-tinycad-running.jpg
|
@ -0,0 +1,85 @@
|
||||
[#]: subject: (3 Linux terminals you need to try)
|
||||
[#]: via: (https://opensource.com/article/21/2/linux-terminals)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
你需要尝试的 3 种 Linux 终端
|
||||
======
|
||||
Linux 让你能够选择你喜欢的终端界面,而不是它强加的界面。
|
||||
![4 different color terminal windows with code][1]
|
||||
|
||||
在 2021 年,人们喜欢 Linux 的理由比以往任何时候都多。在这个系列中,我将分享 21 个使用 Linux 的不同理由。能够选择自己的终端是使用 Linux 的一个重要原因。
|
||||
|
||||
很多人认为一旦你用过一个终端界面,你就已经用过所有的终端了。但喜欢终端的用户都知道,它们之间有一些细微但重要的区别。本文将介绍我最喜欢的三种。
|
||||
|
||||
不过在深入研究它们之前,先要了解 shell 和终端之间的区别。终端(技术上说是_终端模拟器_,因为终端曾经是物理硬件设备)是一个在桌面上的窗口中运行的应用。shell 是在终端窗口中对你可见的引擎。流行的 shell 有 [Bash][2]、[tcsh][3] 和 [zsh][4],它们都在终端中运行。
|
||||
|
||||
在现代 Linux 上几乎不用说,但本文中所有的终端都有标签界面。
|
||||
|
||||
### Xfce 终端
|
||||
|
||||
![Xfce ][5]
|
||||
|
||||
(Seth Kenlon, [CC BY-SA 4.0][6])
|
||||
|
||||
[轻量级 Xfce 桌面][7]提供了一个轻量级的终端,很好地平衡了功能和简单性。它提供了对 shell 的访问(如预期的那样),并且它可以轻松访问几个重要的配置选项。你可以设置当你双击文本时哪些字符会断字,选择你的默认字符编码,并禁用终端窗口的 Alt 快捷方式,这样你最喜欢的 Bash 快捷方式就会传递到 shell。你还可以设置字体和新的颜色主题,或者从常用预设列表中加载颜色主题。它甚至在顶部有一个可选的工具栏,方便你访问你最喜欢的功能。
|
||||
|
||||
对我来说,Xfce 的亮点功能是非常容易地为你打开的每一个标签页改变背景颜色。当在服务器上运行远程 shell 时,这是非常有价值的。它让我知道自己在哪个标签页中,从而避免了我犯愚蠢的错误。
|
||||
|
||||
### rxvt-unicode
|
||||
|
||||
![rxvt][8]
|
||||
|
||||
(Seth Kenlon, [CC BY-SA 4.0][6])
|
||||
|
||||
[rxvt 终端][9]是我最喜欢的轻量级控制台。它有许多老式 [xterm][10] 终端仿真器的功能,但它的扩展性更强。它的配置是在 `~/.Xdefaults` 中定义的,所以没有偏好面板或设置菜单,但这使得它很容易管理和备份你的设置。使用一些 Perl 库,rxvt 有标签,并且通过 xrdb,它可以访问字体和任何你能想到的颜色主题。你可以设置像 `URxvt.urlLancher: firefox` 这样的属性来设置当你打开 URL 时启动的网页浏览器,改变滚动条的外观,修改键盘快捷键等等。
|
||||
|
||||
最初的 rxvt 不支持 Unicode(因为当时 Unicode 还不存在),但 `rxvt-unicode`(有时也叫 `urxvt`)包提供了一个完全支持 Unicode 的补丁版本。
|
||||
|
||||
我在每台电脑上都有 rxvt,因为对我来说它是最好的通用终端。它不一定是所有用户的最佳终端(例如,它没有拖放界面)。不过,对于寻找快速和灵活终端的中高级用户来说,rxvt 是一个简单的选择。
|
||||
|
||||
### Konsole
|
||||
|
||||
![Konsole][11]
|
||||
|
||||
(Seth Kenlon, [CC BY-SA 4.0][6])
|
||||
|
||||
Konsole,KDE Plasma 桌面的终端,是我转到 Linux 后使用的第一个终端,所以它是我对所有其他终端的标准。它确实设定了一个很高的标准。Konsole 有所有通常的不错的功能(还有些其他的),比如简单的颜色主题加上配置文件支持、字体选择、编码、可分离标签、可重命名标签等等。但这在现代桌面上是可以预期的(至少,如果你的桌面运行的是 Plasma 的话)。
|
||||
|
||||
Konsole 比其他终端领先许多年(或者几个月)。它可以垂直或水平地分割窗口。你可以把输入复制到所有的标签页上(就像 [tmux][12] 一样)。你可以将其设置为监视自身是否静音或活动并配置通知。如果你在 Android 手机上使用 KDE Connect,这意味着当一个任务完成时,你可以在手机上收到通知。你可以将 Konsole 的输出保存到文本或 HTML 文件中,为打开的标签页添加书签,克隆标签页,调整搜索设置等等。
|
||||
|
||||
Konsole 是一个真正的高级用户终端,但它也非常适合新用户。你可以将文件拖放到 Konsole 中,将目录改为硬盘上的特定位置,也可以将路径粘贴进去,甚至可以将文件复制到 Konsole 的当前工作目录中。这让使用终端变得很简单,这也是所有用户都能理解的。
|
||||
|
||||
### 尝试一个终端
|
||||
|
||||
你的审美观念是黑暗的办公室和黑色背景下绿色文字的温暖光芒吗?还是喜欢阳光明媚的休息室和屏幕上舒缓的墨黑色字体?无论你对完美电脑设置的愿景是什么,如果你喜欢通过输入命令高效地与操作系统交流,那么 Linux 已经为你提供了一个接口。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/2/linux-terminals
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/freedos.png?itok=aOBLy7Ky (4 different color terminal windows with code)
|
||||
[2]: https://opensource.com/resources/what-bash
|
||||
[3]: https://opensource.com/article/20/8/tcsh
|
||||
[4]: https://opensource.com/article/19/9/getting-started-zsh
|
||||
[5]: https://opensource.com/sites/default/files/uploads/terminal-xfce.jpg (Xfce )
|
||||
[6]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[7]: https://opensource.com/article/19/12/xfce-linux-desktop
|
||||
[8]: https://opensource.com/sites/default/files/uploads/terminal-rxvt.jpg (rxvt)
|
||||
[9]: https://opensource.com/article/19/10/why-use-rxvt-terminal
|
||||
[10]: https://opensource.com/article/20/7/xterm
|
||||
[11]: https://opensource.com/sites/default/files/uploads/terminal-konsole.jpg (Konsole)
|
||||
[12]: https://opensource.com/article/20/1/tmux-console
|
@ -0,0 +1,103 @@
|
||||
[#]: subject: (Guake Terminal: A Customizable Linux Terminal for Power Users [Inspired by an FPS Game])
|
||||
[#]: via: (https://itsfoss.com/guake-terminal/)
|
||||
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
Guake 终端:一个为专业用户定制的 Linux 终端(灵感来自于一个 FPS 游戏)
|
||||
======
|
||||
|
||||
_**简介:使用 Guake 终端这个可自定义且强大的适合各种用户的工具快速访问你的终端**_
|
||||
|
||||
### Guake 终端:GNOME 桌面中自上而下终端
|
||||
|
||||
![][1]
|
||||
|
||||
[Guake][2] 是一款为 GNOME 桌面量身定做的终端模拟器,采用自上而下的设计。
|
||||
|
||||
它最初的灵感来自于一款 FPS 游戏([Quake][3])中的终端。尽管它最初是作为一个快速和易于使用的终端而设计的,但它的功能远不止于此。
|
||||
|
||||
Guake 终端提供了大量的功能,以及可定制的选项。在这里,我将重点介绍终端的主要功能,以及如何将它安装到你的任何 Linux 发行版上。
|
||||
|
||||
### Guake 终端的特点
|
||||
|
||||
![][4]
|
||||
|
||||
* 键盘快捷键(**F12**)以覆盖方式在任何地方启动终端
|
||||
* Guake 终端在后台运行,以便持久访问
|
||||
* 能够横向和纵向分割标签页
|
||||
* 从可用选项中更改默认的 shell(如果有的话)
|
||||
* 重新对齐选项
|
||||
* 从多种调色板中选择改变终端的外观
|
||||
* 能够使用 GUI 选项将终端内容保存到文件中
|
||||
* 需要时切换全屏选项
|
||||
* 你可以轻松地保存标签或在需要时打开新的标签
|
||||
* 恢复标签的能力
|
||||
* 可选择配置和学习新的键盘快捷键,以快速访问终端和执行任务
|
||||
* 改变特定选项卡的颜色
|
||||
* 轻松重命名标签,快速访问你需要的内容
|
||||
* 快速打开功能,只需点击一下,就可直接在终端中用你最喜欢的编辑器打开文件
|
||||
* 能够在启动或显示 Guake 终端时添加自己的命令或脚本。
|
||||
* 支持多显示器
|
||||
|
||||
|
||||
![][5]
|
||||
|
||||
只是为了乐趣,你可以做很多事情。 但是,我也相信,高级用户可以利用这些功能使他们的终端体验更轻松,更高效。
|
||||
|
||||
就我用它来测试一些东西和写这篇文章的时候,说实话,我觉得我是在召唤终端。所以,我绝对觉得它很酷!
|
||||
|
||||
### 在 Linux 上安装 Guake
|
||||
|
||||
![][6]
|
||||
|
||||
**在 Ubuntu、Fedora 和 Arch 的默认仓库中都有 Guake 终端。**
|
||||
|
||||
你可以按照它的官方说明来了解你可以使用的命令,如果你使用的是基于 Ubuntu 的发行版,只需输入:
|
||||
|
||||
```
|
||||
sudo apt install guake
|
||||
```
|
||||
|
||||
请注意,使用这种方法可能无法获得最新版本。所以,如果你想获得最新的版本,你可以选择使用 [Linux Uprising][7] 的 PPA 来获得最新版本:
|
||||
|
||||
```
|
||||
sudo add-apt-repository ppa:linuxuprising/guake
|
||||
sudo apt update
|
||||
sudo apt install guake
|
||||
```
|
||||
|
||||
无论是哪种情况,你也可以使用 [Pypi][8] 或者参考[官方文档][9]或从 [GitHub 页面][10]获取源码。
|
||||
|
||||
[Guake Terminal][10]
|
||||
|
||||
你觉得 Guake 终端怎么样?你认为它是一个有用的终端仿真器吗?你知道有什么类似的软件吗?
|
||||
|
||||
欢迎在下面的评论中告诉我你的想法。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/guake-terminal/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/02/guake-terminal-1.png?resize=800%2C363&ssl=1
|
||||
[2]: http://guake-project.org/
|
||||
[3]: https://quake.bethesda.net/en
|
||||
[4]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/02/guake-terminal.jpg?resize=800%2C245&ssl=1
|
||||
[5]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/02/guake-preferences.jpg?resize=800%2C559&ssl=1
|
||||
[6]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2021/02/guake-terminal-2.png?resize=800%2C432&ssl=1
|
||||
[7]: https://www.linuxuprising.com/
|
||||
[8]: https://pypi.org/
|
||||
[9]: https://guake.readthedocs.io/en/latest/user/installing.html
|
||||
[10]: https://github.com/Guake/guake
|
Loading…
Reference in New Issue
Block a user