mirror of
https://github.com/LCTT/TranslateProject.git
synced 2024-12-26 21:30:55 +08:00
commit
71fb789516
@ -1,33 +1,29 @@
|
||||
Cgo 与 Python
|
||||
============================================================
|
||||
如何在 Go 中嵌入 Python
|
||||
==================
|
||||
|
||||
![](https://datadog-prod.imgix.net/img/blog/engineering/cgo-and-python/cgo_python_hero.png?auto=format&w=1900&dpr=1)
|
||||
|
||||
|
||||
|
||||
如果你查看 [new Datadog Agent][8],你可能会注意到大部分代码库是用 Go 编写的,但我们用来收集指标的检查仍然是用 Python 编写的。这大概是因为 Datadog Agent 是基于一个[嵌入][9] CPython 解释器的 GO,可以在任何时候按需执行 Python 代码。这个过程通过抽象层来透明化,使得你可以编写惯用的 Go 代码来运行后台的 Python。
|
||||
如果你看一下 [新的 Datadog Agent][8],你可能会注意到大部分代码库是用 Go 编写的,尽管我们用来收集指标的检查仍然是用 Python 编写的。这大概是因为 Datadog Agent 是一个 [嵌入了][9] CPython 解释器的普通 Go 二进制文件,可以在任何时候按需执行 Python 代码。这个过程通过抽象层来透明化,使得你可以编写惯用的 Go 代码而底层运行的是 Python。
|
||||
|
||||
[视频](https://youtu.be/yrEi5ezq2-c)
|
||||
|
||||
在 Go 应用程序中嵌入 Python 的原因有很多:
|
||||
|
||||
* 它在过渡期间很有用;逐步将现有 Python 项目的部分迁移到新语言,而不会在此过程中丢失任何功能。
|
||||
|
||||
* 它在过渡期间很有用;可以逐步将现有 Python 项目的部分迁移到新语言,而不会在此过程中丢失任何功能。
|
||||
* 你可以复用现有的 Python 软件或库,而无需用新语言重新实现。
|
||||
|
||||
* 你可以通过加载去执行常规 Python 脚本来动态扩展你软件,甚至在运行时也可以。
|
||||
|
||||
理由还可以列很多,但对于 Datadog Agent 来说,最后一点至关重要:我们希望做到无需重新编译 Agent,或者说编译任何内容就能够执行自定义检查或更改现有检查。
|
||||
|
||||
嵌入 CPython 非常简单,而且文档齐全。解释器本身是用 C 编写的,并且提供了一个 C API 以编程方式来执行底层操作,例如创建对象、导入模块和调用函数。
|
||||
|
||||
在本文中,我们将展示一些代码示例,我们将会在与 Python 交互的同时继续保持 Go 代码的惯用语,但在我们继续之前,我们需要解决一个间隙:嵌入 API 是 C 但我们的主要应用程序是 Go,这怎么可能工作?
|
||||
在本文中,我们将展示一些代码示例,我们将会在与 Python 交互的同时继续保持 Go 代码的惯用语,但在我们继续之前,我们需要解决一个间隙:嵌入 API 是 C 语言,但我们的主要应用程序是 Go,这怎么可能工作?
|
||||
|
||||
![](https://datadog-prod.imgix.net/img/blog/engineering/cgo-and-python/cgo_python_divider_1.png?auto=format&fit=max&w=847)
|
||||
|
||||
### 介绍 cgo
|
||||
|
||||
有[很多好的理由][10] 说服你为什么不要在堆栈中引入 cgo,但嵌入 CPython 是你必须这样做的原因。[Cgo][11] 不是语言,也不是编译器。它是 [Foreign Function Interface][12] (FFI),一种让我们可以在 Go 中使用来调用不同语言(特别是 C)编写的函数和服务的机制。
|
||||
有 [很多好的理由][10] 说服你为什么不要在堆栈中引入 cgo,但嵌入 CPython 是你必须这样做的原因。[cgo][11] 不是语言,也不是编译器。它是 <ruby>[外部函数接口][12]<rt>Foreign Function Interface</rt></ruby>(FFI),一种让我们可以在 Go 中使用来调用不同语言(特别是 C)编写的函数和服务的机制。
|
||||
|
||||
当我们提起 “cgo” 时,我们实际上指的是 Go 工具链在底层使用的一组工具、库、函数和类型,因此我们可以通过执行 `go build` 来获取我们的 Go 二进制文件。下面是使用 cgo 的示例程序:
|
||||
|
||||
@ -44,16 +40,17 @@ func main() {
|
||||
|
||||
```
|
||||
|
||||
在这种包含标头情况下,`import "C"` 指令上方的注释块称为“前导码”,可以包含实际的 C 代码。导入后,我们可以通过“C”伪包来“跳转”到外部代码,访问常量`FLT_MAX`。你可以通过调用 `go build` 来构建,它就像普通的 Go 一样。
|
||||
在这种包含头文件情况下,`import "C"` 指令上方的注释块称为“<ruby>序言<rt>preamble</rt></ruby>”,可以包含实际的 C 代码。导入后,我们可以通过“C”伪包来“跳转”到外部代码,访问常量 `FLT_MAX`。你可以通过调用 `go build` 来构建,它就像普通的 Go 一样。
|
||||
|
||||
如果你想查看 cgo 在这背后到底做了什么,可以运行 `go build -x`。你将看到 “cgo” 工具将被调用以生成一些 C 和 Go 模块,然后将调用 C 和 Go 编译器来构建目标模块,最后链接器将所有内容放在一起。
|
||||
|
||||
你可以在 [Go Blog][13] 上阅读更多有关 cgo 的信息,文章包含更多的例子以及一些有用的链接来做进一步了解细节。
|
||||
你可以在 [Go 博客][13] 上阅读更多有关 cgo 的信息,该文章包含更多的例子以及一些有用的链接来做进一步了解细节。
|
||||
|
||||
现在我们已经了解了 cgo 可以为我们做什么,让我们看看如何使用这种机制运行一些 Python 代码。
|
||||
|
||||
![](https://datadog-prod.imgix.net/img/blog/engineering/cgo-and-python/cgo_python_divider_2.png?auto=format&fit=max&w=847)
|
||||
|
||||
### 嵌入 CPython: a primer
|
||||
### 嵌入 CPython:一个入门指南
|
||||
|
||||
从技术上讲,嵌入 CPython 的 Go 程序并没有你想象的那么复杂。事实上,我们只需在运行 Python 代码之前初始化解释器,并在完成后关闭它。请注意,我们在所有示例中使用 Python 2.x,但我们只需做很少的调整就可以应用于 Python 3.x。让我们看一个例子:
|
||||
|
||||
@ -73,19 +70,19 @@ func main() {
|
||||
|
||||
```
|
||||
|
||||
上面的示例与以下 Python 代码完全相同:
|
||||
上面的例子做的正是下面 Python 代码要做的事:
|
||||
|
||||
```
|
||||
import sys
|
||||
print(sys.version)
|
||||
|
||||
```
|
||||
|
||||
你可以看到我们在开头加入了一个 `#cgo` 指令;这些指令被会被传递到工具链,你就改变了构建工作流程。在这种情况下,我们告诉 cgo 调用`pkg-config`来收集构建并链接名为“python-2.7”的库所需的标志,并将这些标志传递给 C 编译器。如果你的系统中安装了 CPython 开发库和 pkg-config,你只需要运行 `go build` 来编译上面的示例。
|
||||
你可以看到我们在序言加入了一个 `#cgo` 指令;这些指令被会被传递到工具链,让你改变构建工作流程。在这种情况下,我们告诉 cgo 调用 `pkg-config` 来收集构建和链接名为 `python-2.7` 的库所需的标志,并将这些标志传递给 C 编译器。如果你的系统中安装了 CPython 开发库和 pkg-config,你只需要运行 `go build` 来编译上面的示例。
|
||||
|
||||
回到代码,我们使用 `Py_Initialize()` 和 `Py_Finalize()` 来初始化和关闭解释器,并使用 `Py_GetVersion` C 函数来获取嵌入式解释器版本信息的字符串。
|
||||
|
||||
如果你更近一步,我们可以把所有调用 C Python API 的 cgo 代码一起,这就是 Datadog Agent 进行所有嵌入式操作所有依赖的 [go-python][14] 做的事情;该库为 C API 提供了一个 Go 友好的轻量级包,并隐藏了 cgo 细节。这是另一个基本的嵌入式示例,这次使用 go-python:
|
||||
如果你想知道,所有我们需要放在一起调用 C 语言 Python API的 cgo 代码都是模板代码。这就是为什么 Datadog Agent 依赖 [go-python][14] 来完成所有的嵌入操作;该库为 C API 提供了一个 Go 友好的轻量级包,并隐藏了 cgo 细节。这是另一个基本的嵌入式示例,这次使用 go-python:
|
||||
|
||||
```
|
||||
package main
|
||||
|
||||
@ -112,7 +109,6 @@ def hello():
|
||||
Print hello world for fun and profit.
|
||||
"""
|
||||
print "hello, world!"
|
||||
|
||||
```
|
||||
|
||||
Go 代码稍微复杂一些,但仍然可读:
|
||||
@ -144,26 +140,26 @@ func main() {
|
||||
|
||||
```
|
||||
|
||||
首次构建,我们需要将 `PYTHONPATH` 环境变量设置为当前工作目录,以便导入语句能够找到 `foo.py` 模块。在 shell 中,该命令如下所示:
|
||||
构建时,我们需要将 `PYTHONPATH` 环境变量设置为当前工作目录,以便导入语句能够找到 `foo.py` 模块。在 shell 中,该命令如下所示:
|
||||
|
||||
```
|
||||
$ go build main.go && PYTHONPATH=. ./main
|
||||
hello, world!
|
||||
|
||||
```
|
||||
|
||||
![](https://datadog-prod.imgix.net/img/blog/engineering/cgo-and-python/cgo_python_divider_3.png?auto=format&fit=max&w=847)
|
||||
|
||||
### 可怕的全局解释器锁
|
||||
|
||||
为了嵌入 Python 必须引入 cgo 需要权衡:构建速度会变慢,垃圾收集器不会帮助我们管理外部系统使用的内存,交叉编译也很难。这些是否是针对特定项目的问题可以讨论,但我认为有一些不容商量的问题:Go 并发模型。如果我们不能从 goroutine 运行 Python,那么使用 Go 就没有意义了。
|
||||
为了嵌入 Python 必须引入 cgo ,这是一种权衡:构建速度会变慢,垃圾收集器不会帮助我们管理外部系统使用的内存,交叉编译也很难。对于一个特定的项目来说,这些问题是否是可以争论的,但我认为有一些不容商量的问题:Go 并发模型。如果我们不能从 goroutine 中运行 Python,那么使用 Go 就没有意义了。
|
||||
|
||||
在处理并发、Python 和 cgo 之前,我们还需要知道一些事情:它就是全局解释器锁,也称为 GIL。GIL 是语言解释器(CPython 就是其中之一)中广泛采用的一种机制,可防止多个线程同时运行。这意味着 CPython 执行的任何 Python 程序都无法在同一进程中并行运行。并发仍然是可能的,锁是速度、安全性和实现之间的一个很好的权衡,那么,当涉及到嵌入时,为什么这会造成问题呢?
|
||||
在处理并发、Python 和 cgo 之前,我们还需要知道一些事情:它就是<ruby>全局解释器锁<rt>Global Interpreter Lock</rt></ruby>,即 GIL。GIL 是语言解释器(CPython 就是其中之一)中广泛采用的一种机制,可防止多个线程同时运行。这意味着 CPython 执行的任何 Python 程序都无法在同一进程中并行运行。并发仍然是可能的,锁是速度、安全性和实现简易性之间的一个很好的权衡,那么,当涉及到嵌入时,为什么这会造成问题呢?
|
||||
|
||||
当一个常规的、非嵌入式的 Python 程序启动时,不涉及 GIL 以避免锁定操作中的无用开销;在某些 Python 代码请求生成线程时 GIL 首次启动。对于每个线程,解释器创建一个数据结构来存储当前的相关状态信息并锁定 GIL。当线程完成时,状态被恢复,GIL 被解锁,准备被其他线程使用。
|
||||
当一个常规的、非嵌入式的 Python 程序启动时,不涉及 GIL 以避免锁定操作中的无用开销;在某些 Python 代码首次请求生成线程时 GIL 就启动了。对于每个线程,解释器创建一个数据结构来存储当前的相关状态信息并锁定 GIL。当线程完成时,状态被恢复,GIL 被解锁,准备被其他线程使用。
|
||||
|
||||
当我们从 Go 程序运行 Python 时,上述情况都不会自动发生。如果没有 GIL,我们的 Go 程序可以创建多个 Python 线程,这可能会导致竞争条件,从而导致致命的运行时错误,并且很可能是分段错误导致整个 Go 应用程序瘫痪。
|
||||
当我们从 Go 程序运行 Python 时,上述情况都不会自动发生。如果没有 GIL,我们的 Go 程序可以创建多个 Python 线程,这可能会导致竞争条件,从而导致致命的运行时错误,并且很可能出现分段错误导致整个 Go 应用程序崩溃。
|
||||
|
||||
解决方案是在我们从 Go 运行多线程代码时显式调用 GIL;代码并不复杂,因为 C API 提供了我们需要的所有工具。为了更好地暴露这个问题,我们需要写一些受 CPU 限制的 Python 代码。让我们将这些函数添加到前面示例中的 foo.py 模块中:
|
||||
解决方案是在我们从 Go 运行多线程代码时显式调用 GIL;代码并不复杂,因为 C API 提供了我们需要的所有工具。为了更好地暴露这个问题,我们需要写一些受 CPU 限制的 Python 代码。让我们将这些函数添加到前面示例中的 `foo.py` 模块中:
|
||||
|
||||
```
|
||||
# foo.py
|
||||
@ -187,7 +183,7 @@ def print_even(limit=10):
|
||||
|
||||
```
|
||||
|
||||
我们将尝试从 Go 并发打印奇数和偶数,使用两个不同的 goroutines(因此涉及线程):
|
||||
我们将尝试从 Go 并发打印奇数和偶数,使用两个不同的 goroutine(因此涉及线程):
|
||||
|
||||
```
|
||||
package main
|
||||
@ -243,46 +239,39 @@ func main() {
|
||||
|
||||
```
|
||||
|
||||
在阅读示例时,您可能会注意到一个模式,该模式将成为我们运行嵌入式 Python 代码的习惯写法:
|
||||
在阅读示例时,你可能会注意到一个模式,该模式将成为我们运行嵌入式 Python 代码的习惯写法:
|
||||
|
||||
1. 保存状态并锁定 GIL。
|
||||
|
||||
2. 执行 Python.
|
||||
|
||||
2. 执行 Python。
|
||||
3. 恢复状态并解锁 GIL。
|
||||
|
||||
代码应该很简单,但我们想指出一个微妙的细节:请注意,尽管借用了 GIL 执行,有时我们通过调用 `PyEval_SaveThread()` 和 `PyEval_RestoreThread()` 来操作 GIL,有时(查看 goroutines)我们对 `PyGILState_Ensure()` 和 `PyGILState_Release()` 来做同样的事情。
|
||||
代码应该很简单,但我们想指出一个微妙的细节:请注意,尽管借用了 GIL 执行,有时我们通过调用 `PyEval_SaveThread()` 和 `PyEval_RestoreThread()` 来操作 GIL,有时(查看 goroutines 里面)我们对 `PyGILState_Ensure()` 和 `PyGILState_Release()` 来做同样的事情。
|
||||
|
||||
我们说过当从 Python 操作多线程时,解释器负责创建存储当前状态所需的数据结构,但是当同样的事情发生在 C API 时,我们来负责处理。
|
||||
|
||||
当我们用 go-python 初始化解释器时,我们是在 Python 上下文中操作的。因此,当调用 `PyEval_InitThreads()` 时,它会初始化数据结构并锁定 GIL。我们可以使用 `PyEval_SaveThread()` 和 `PyEval_RestoreThread()` 对已经存在的状态进行操作。
|
||||
|
||||
在 goroutines 中,我们从 Go 上下文操作,我们需要显式创建状态并在完成后将其删除,这就是 `PyGILState_Ensure()` 和 `PyGILState_Release()` 为我们所做的。
|
||||
|
||||
![](https://datadog-prod.imgix.net/img/blog/engineering/cgo-and-python/cgo_python_divider_4.png?auto=format&fit=max&w=847)
|
||||
|
||||
### 释放 Gopher
|
||||
|
||||
在这一点上,我们知道如何处理在嵌入式解释器中执行 Python 的多线程 Go 代码,但在 GIL 之后,另一个挑战即将来临:Go 调度程序。
|
||||
|
||||
当一个 goroutine 启动时,它被安排在可用的 `GOMAXPROCS` 线程之一上执行[参见此处][15] 了解有关该主题的更多详细信息。如果一个 goroutine 碰巧执行了系统调用或调用 C 代码,当前线程会将移交给另一个队列中等待运行的其他 goroutine ,以便它们有更好的机会运行; 当前 goroutine 被暂停,等待系统调用或 C 函数返回。当 C 函数返回时,线程会尝试恢复暂停的 goroutine,但如果这不可能,它会要求 Go runtime 找到另一个线程来完成 goroutine 并进入睡眠状态。
|
||||
当一个 goroutine 启动时,它被安排在可用的 `GOMAXPROCS` 线程之一上执行,[参见此处][15] 可了解有关该主题的更多详细信息。如果一个 goroutine 碰巧执行了系统调用或调用 C 代码,当前线程会将线程队列中等待运行的其他 goroutine 移交给另一个线程,以便它们有更好的机会运行; 当前 goroutine 被暂停,等待系统调用或 C 函数返回。当这种情况发生时,线程会尝试恢复暂停的 goroutine,但如果这不可能,它会要求 Go 运行时找到另一个线程来完成 goroutine 并进入睡眠状态。 goroutine 最后被安排给另一个线程,它就完成了。
|
||||
|
||||
考虑到这一点,让我们看看当一个 goroutine 被移动到一个新线程时,运行一些 Python 代码的 goroutine 会发生什么:
|
||||
|
||||
1. 我们的 goroutine 启动,执行 C 调用,暂停,GIL 被锁定。
|
||||
|
||||
2. 当 C 调用返回时,当前线程尝试恢复 goroutine,但失败。
|
||||
|
||||
1. 我们的 goroutine 启动,执行 C 调用并暂停。GIL 被锁定。
|
||||
2. 当 C 调用返回时,当前线程尝试恢复 goroutine,但失败了。
|
||||
3. 当前线程告诉 Go 运行时寻找另一个线程来恢复我们的 goroutine。
|
||||
4. Go 调度器找到一个可用线程并恢复 goroutine。
|
||||
5. goroutine 快完成了,并在返回之前尝试解锁 GIL。
|
||||
6. 当前状态中存储的线程 ID 来自原线程,与当前线程的 ID 不同。
|
||||
7. 崩溃!
|
||||
|
||||
4. Go scheduler 找到可用线程并恢复 goroutine。
|
||||
|
||||
5. goroutine 快完成了,并在返回之前尝试解锁 GIL。The goroutine is almost done and tries to unlock the GIL before returning.
|
||||
|
||||
6. 当前状态中存储的线程ID来自原始线程,与当前线程的ID不同。
|
||||
|
||||
7. Panic!
|
||||
|
||||
所幸,我们可以通过从 goroutine 中调用运行时包中的 LockOSThread 函数来强制 Go runtime 始终保持我们的 goroutine 在同一线程上运行:
|
||||
所幸,我们可以通过从 goroutine 中调用运行时包中的 `LockOSThread` 函数来强制 Go runtime 始终保持我们的 goroutine 在同一线程上运行:
|
||||
|
||||
```
|
||||
go func() {
|
||||
@ -293,31 +282,27 @@ go func() {
|
||||
python.PyGILState_Release(_gstate)
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
```
|
||||
|
||||
这会干扰 scheduler 并可能引入一些开销,但这是我们也愿意付出代价。
|
||||
这会干扰调度器并可能引入一些开销,但这是我们愿意付出的代价。
|
||||
|
||||
### 结论
|
||||
|
||||
为了嵌入 Python,Datadog Agent 必须接受一些权衡:
|
||||
|
||||
* cgo 引入的开销。
|
||||
|
||||
* 手动处理 GIL 的任务。
|
||||
|
||||
* 在执行期间将 goroutine 绑定到同一线程的限制。
|
||||
|
||||
为了能方便在 Go 中运行 Python 检查代码,我们乐此不疲。意识到权衡,我们能够最大限度地减少它们的影响,除了为支持 Python 而引入的其他限制,我们没有对策来控制潜在问题:
|
||||
为了能方便在 Go 中运行 Python 检查,我们很乐意接受其中的每一项。但通过意识到这些权衡,我们能够最大限度地减少它们的影响,除了为支持 Python 而引入的其他限制,我们没有对策来控制潜在问题:
|
||||
|
||||
* 构建是自动化和可配置的,因此开发人员仍然需要拥有与 `go build` 非常相似的东西。
|
||||
* Agent 的轻量级版本,可以使用 Go 构建标签,完全剥离 Python 支持。
|
||||
* 这样的版本仅依赖于在 Agent 本身硬编码的核心检查(主要是系统和网络检查),但没有 cgo 并且可以交叉编译。
|
||||
|
||||
* agent 的轻量级版本,可以完全剥离 Python 支持,只需使用 Go 构建标签。A lightweight version of the agent can be built stripping out Python support entirely simply using Go build tags.
|
||||
我们将在未来重新评估我们的选择,并决定是否仍然值得保留 cgo;我们甚至可以重新考虑整个 Python 是否仍然值得,等待 [Go 插件包][16] 成熟到足以支持我们的用例。但就目前而言,嵌入式 Python 运行良好,从旧代理过渡到新代理再简单不过了。
|
||||
|
||||
* 这样的版本仅依赖于在代理本身中硬编码的核心检查(主要是系统和网络检查),但没有 cgo 并且可以交叉编译。Such a version only relies on core checks hardcoded in the agent itself (system and network checks mostly) but is cgo free and can be cross compiled.
|
||||
|
||||
我们将在未来重新评估我们的选择,并决定是否仍然值得保留 cgo; 我们甚至可以重新考虑 Python 作为一个整体是否仍然值得,等待 [Go plugin package][16] 成熟到足以支持我们的用例。但就目前而言,嵌入式 Python 运行良好,从旧代理过渡到新代理再简单不过了。
|
||||
|
||||
你是一个喜欢混合不同编程语言的多语言者吗?您喜欢了解语言的内部工作原理以提高您的代码性能吗? [Join us at Datadog!][17]
|
||||
你是一个喜欢混合不同编程语言的多语言者吗?你喜欢了解语言的内部工作原理以提高你的代码性能吗?
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -325,7 +310,7 @@ via: https://www.datadoghq.com/blog/engineering/cgo-and-python/
|
||||
|
||||
作者:[Massimiliano Pippi][a]
|
||||
译者:[Zioyi](https://github.com/Zioyi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -0,0 +1,98 @@
|
||||
[#]: subject: (Linux Mint 20.2 is Now Available With New Features and Tools)
|
||||
[#]: via: (https://news.itsfoss.com/linux-mint-20-2-release/)
|
||||
[#]: author: (Ankush Das https://news.itsfoss.com/author/ankush/)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
Linux Mint 20.2 is Now Available With New Features and Tools
|
||||
======
|
||||
|
||||
Linux Mint 20.2 beta [arrived][1] a few weeks ago. And now, the final stable release for Linux Mint 20.2 is here.
|
||||
|
||||
This release is an LTS upgrade based on Ubuntu 20.04 that is supported until 2025.
|
||||
|
||||
Let us take a quick look at what’s new with this release and how do you get it.
|
||||
|
||||
### Linux Mint 20.2: What’s New?
|
||||
|
||||
The key highlight of this release is the addition of update notification, which should encourage more users to keep their systems up-to-date to ensure best security.
|
||||
|
||||
It will [not force updates like Windows][2], but it will keep an eye out for how long you don’t apply updates, check system’s uptime, and then prompt you with an update reminder notification.
|
||||
|
||||
![][3]
|
||||
|
||||
You also get to configure the update notifications, which is great.
|
||||
|
||||
Other major upgrades include **Cinnamon 5** desktop environment, a new bulk **file renaming tool** (Bulky), and **Sticky Notes replacing GNote** as the default note application.
|
||||
|
||||
![][4]
|
||||
|
||||
The file renaming tool is available for all the desktop editions, excluding Xfce, because its default file manager (Thunar) already supports the feature.
|
||||
|
||||
Cinnamon 5 is not exactly exciting, but there are some under-the-hood improvements to its performance and nice little option to limit its RAM usage.
|
||||
|
||||
![][5]
|
||||
|
||||
And Sticky Notes is developed in GTK 3, supports HiDPI and offers more features, along with better integration with the system tray.
|
||||
|
||||
![][6]
|
||||
|
||||
### Other Improvements
|
||||
|
||||
[Warpinator app][7] to share files across a network has received some upgrades making it more useful.
|
||||
|
||||
Other desktop environment upgrades include Xfce 4.16 and MATE 1.24. In addition to that, you will find certain subtle UI improvements and several bug fixes.
|
||||
|
||||
Especially addressing issues with NVIDIA graphics, along with the **support for hybrid graphics**, great news for Laptop users!
|
||||
|
||||
To know more about some of the detailed changes, you can refer to the [official announcement][8] for one of the desktop editions.
|
||||
|
||||
### Download or Upgrade to Linux Mint 20.2
|
||||
|
||||
You can find the stable releases directly from the official website’s [download page][9].
|
||||
|
||||
[Download Linux Mint 20.2][9]
|
||||
|
||||
If you have Linux Mint 20 or 20.1 installed, you can choose to first apply all the available updates and then an update to your Update Manager.
|
||||
|
||||
Next, make sure that you have a backup (use timeshift if you want) and then head to the Update Manager’s System Upgrade option from the **Edit** menu as shown below.
|
||||
|
||||
![][10]
|
||||
|
||||
When you click on it, you will be greeted with the on-screen instructions to go ahead with the upgrade. You may also refer to the [official upgrade instructions][11] for further help.
|
||||
|
||||
_Have you upgraded yet? What do you think about the latest release? Feel free to share your thoughts in the comments down below._
|
||||
|
||||
#### Big Tech Websites Get Millions in Revenue, It's FOSS Got You!
|
||||
|
||||
If you like what we do here at It's FOSS, please consider making a donation to support our independent publication. Your support will help us keep publishing content focusing on desktop Linux and open source software.
|
||||
|
||||
I'm not interested
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://news.itsfoss.com/linux-mint-20-2-release/
|
||||
|
||||
作者:[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://news.itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://news.itsfoss.com/linux-mint-20-2-beta-release/
|
||||
[2]: https://news.itsfoss.com/linux-mint-updates-notice/
|
||||
[3]: data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjE2MCIgd2lkdGg9IjQ5NCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiLz4=
|
||||
[4]: data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjQ2OCIgd2lkdGg9IjU3MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiLz4=
|
||||
[5]: data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjYwOCIgd2lkdGg9Ijc4MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiLz4=
|
||||
[6]: data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjQ2NiIgd2lkdGg9Ijc4MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiLz4=
|
||||
[7]: https://news.itsfoss.com/warpinator-android-app/
|
||||
[8]: https://blog.linuxmint.com/?p=4102
|
||||
[9]: https://linuxmint.com/download.php
|
||||
[10]: data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjI2MCIgd2lkdGg9IjUzMyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiLz4=
|
||||
[11]: https://blog.linuxmint.com/?p=4111
|
@ -1,158 +0,0 @@
|
||||
[#]: subject: (Enter invisible passwords using this Python module)
|
||||
[#]: via: (https://opensource.com/article/21/7/invisible-passwords-python)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
Enter invisible passwords using this Python module
|
||||
======
|
||||
Give your password an extra layer of security with GPG and the Python
|
||||
getpass module.
|
||||
![Password lock][1]
|
||||
|
||||
Passwords are particularly problematic for programmers. You're not supposed to store them without encrypting them, and you're not supposed to reveal what's been typed when your user enters one. This became particularly important to me when I decided I wanted to boost security on my laptop. I encrypt my home directory—but once I log in, any password stored as plain text in a configuration file is potentially exposed to prying eyes.
|
||||
|
||||
Specifically, I use an application called [Mutt][2] as my email client. It lets me read and compose emails in my Linux terminal, but normally it expects a password in its configuration file. I restricted permissions on my Mutt config file so that only I can see it, but I'm the only user of my laptop, so I'm not really concerned about authenticated users inadvertently looking at my configs. Instead, I wanted to protect myself from absent-mindedly posting my config online, either for bragging rights or version control, with my password exposed. In addition, although I have no expectations of unwelcome guests on my system, I did want to ensure that an intruder couldn't obtain my password just by running `cat` on my config.
|
||||
|
||||
### Python GnuPG
|
||||
|
||||
The Python module `python-gnupg` is a Python wrapper for the `gpg` application. The module's name is `python-gnupg`, which you must not confuse with a module called `gnupg`.
|
||||
|
||||
[GnuPG][3] (GPG) is the default encryption system for Linux, and I've been using it since 2009 or so. I feel comfortable with it and have a high level of trust in its security.
|
||||
|
||||
I decided that the best way to get my password into Mutt was to store my password inside an encrypted GPG file, create a prompt for my GPG password to unlock the encrypted file, and hand the password over to Mutt (actually to the `offlineimap` command, which I use to synchronize my laptop with the email server).
|
||||
|
||||
[Getting user input with Python][4] is pretty easy. You make a call to `input`, and whatever the user types is stored as a variable:
|
||||
|
||||
|
||||
```
|
||||
print("Enter password: ")
|
||||
myinput = input()
|
||||
|
||||
print("You entered: ", myinput)
|
||||
```
|
||||
|
||||
My problem was when I typed a password into the terminal in response to my password prompt, everything I typed was visible to anyone looking over my shoulder or scrolling through my terminal history:
|
||||
|
||||
|
||||
```
|
||||
$ ./test.py
|
||||
Enter password: my-Complex-Passphrase
|
||||
```
|
||||
|
||||
### Invisible password entry with getpass
|
||||
|
||||
As is often the case, there's a Python module that's already solved my problem. The module is `getpass4`, and from the user's perspective, it behaves exactly like `input` except without displaying what the user is typing.
|
||||
|
||||
You can install both modules with [pip][5]:
|
||||
|
||||
|
||||
```
|
||||
$ python -m pip install --user \
|
||||
python-gnupg getpass4
|
||||
```
|
||||
|
||||
Here's my Python script to create a password prompt:
|
||||
|
||||
|
||||
```
|
||||
#!/usr/bin/env python
|
||||
# by Seth Kenlon
|
||||
# GPLv3
|
||||
|
||||
# install deps:
|
||||
# python3 -m pip install --user python-gnupg getpass4
|
||||
|
||||
import gnupg
|
||||
import getpass
|
||||
from pathlib import Path
|
||||
|
||||
def get_api_pass():
|
||||
homedir = str(Path.home())
|
||||
gpg = gnupg.GPG(gnupghome=os.path.join(homedir,".gnupg"), use_agent=True)
|
||||
passwd = getpass.getpass(prompt="Enter your GnuPG password: ", stream=None)
|
||||
|
||||
with open(os.path.join(homedir,'.mutt','pass.gpg'), 'rb') as f:
|
||||
apipass = (gpg.decrypt_file(f, passphrase=passwd))
|
||||
|
||||
f.close()
|
||||
|
||||
return str(apipass)
|
||||
|
||||
if __name__ == "__main__":
|
||||
apipass = get_api_pass()
|
||||
print(apipass)
|
||||
```
|
||||
|
||||
Save the file as `password_prompt.py` if you want to try it out. If you're using `offlineimap` and want to use this solution for your own password entry, then save it to some location you can point `offlineimap` to in your `.offlineimaprc` file (I use `~/.mutt/password_prompt.py`).
|
||||
|
||||
### Testing the password prompt
|
||||
|
||||
To see the script in action, you first must create an encrypted file (I'll assume that you already have GPG set up):
|
||||
|
||||
|
||||
```
|
||||
$ echo "hello world" > pass
|
||||
$ gpg --encrypt pass
|
||||
$ mv pass.gpg ~/.mutt/pass.gpg
|
||||
$ rm pass
|
||||
```
|
||||
|
||||
Now run the Python script:
|
||||
|
||||
|
||||
```
|
||||
$ python ~/.mutt/password_prompt.py
|
||||
Enter your GPG password:
|
||||
hello world
|
||||
```
|
||||
|
||||
Nothing displays as you type, but as long as you enter your GPG passphrase correctly, you will see the test message.
|
||||
|
||||
### Integrating the password prompt with offlineimap
|
||||
|
||||
I needed to integrate my new prompt with the `offlineimap` command. I chose Python for this script because I knew that `offlineimap` can make calls to Python applications. If you're an `offlineimap` user, you'll appreciate that the only "integration" required is changing two lines in your `.offlineimaprc` file.
|
||||
|
||||
First, add a line referencing the Python file:
|
||||
|
||||
|
||||
```
|
||||
`pythonfile = ~/.mutt/password_prompt.py`
|
||||
```
|
||||
|
||||
And then replace the `remotepasseval` line in `.offlineimaprc` with a call to the `get_api_pass()` function in `password_prompt.py`:
|
||||
|
||||
|
||||
```
|
||||
`remotepasseval = get_api_pass()`
|
||||
```
|
||||
|
||||
No more passwords in your config file!
|
||||
|
||||
### Security matters
|
||||
|
||||
It sometimes feels almost paranoid to think about security minutiae on your personal computer. Does your SSH config really need to be restricted to 600? Does it really matter that your email password is in an inconsequential config file buried within a hidden folder called, of all things, `.mutt`? Probably not.
|
||||
|
||||
And yet knowing that I don't have sensitive data quietly hidden away in my config files makes it a lot easier for me to commit files to public Git repositories, to copy and paste snippets into support forums, and to share my knowledge in the form of actual, known-good configuration files. For that alone, improved security has made my life easier. And with so many great Python modules available to help, it's easy to implement.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/7/invisible-passwords-python
|
||||
|
||||
作者:[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/password.jpg?itok=ec6z6YgZ (Password lock)
|
||||
[2]: http://www.mutt.org/
|
||||
[3]: https://gnupg.org/
|
||||
[4]: https://opensource.com/article/20/12/learn-python
|
||||
[5]: https://opensource.com/article/19/11/python-pip-cheat-sheet
|
@ -2,7 +2,7 @@
|
||||
[#]: via: (https://opensource.com/article/21/7/generate-passwords-pwgen)
|
||||
[#]: author: (Sumantro Mukherjee https://opensource.com/users/sumantro)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
@ -2,7 +2,7 @@
|
||||
[#]: via: (https://opensource.com/article/21/7/parsing-config-files-java)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (Starryi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
@ -0,0 +1,126 @@
|
||||
[#]: subject: (3 reasons Quarkus 2.0 improves developer productivity on Linux)
|
||||
[#]: via: (https://opensource.com/article/21/7/developer-productivity-linux)
|
||||
[#]: author: (Daniel Oh https://opensource.com/users/daniel-oh)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
3 reasons Quarkus 2.0 improves developer productivity on Linux
|
||||
======
|
||||
New features in Quarkus 2.0 make it easier to test code in the developer
|
||||
console.
|
||||
![Person using a laptop][1]
|
||||
|
||||
No matter how long you work as an application developer and no matter what programming language you use, you probably still struggle to increase your development productivity. Additionally, new paradigms, including cloud computing, DevOps, and test-driven development, have significantly accelerated the development lifecycle for individual developers and multifunctional teams.
|
||||
|
||||
You might think open source tools could help fix this problem, but I'd say many open source development frameworks and tools for coding, building, and testing make these challenges worse. Also, it's not easy to find appropriate [Kubernetes][2] development tools to install on Linux distributions due to system dependencies and support restrictions.
|
||||
|
||||
Fortunately, you can increase development productivity on Linux with [Quarkus][3], a Kubernetes-native Java stack. Quarkus 2.0 was released recently with useful new features for testing in the developer console.
|
||||
|
||||
### Interactive developer UX/UI
|
||||
|
||||
If you need to add more than 10 dependencies (e.g., database connections, object-relational mapping, JSON formatting, REST API specifications) to your Java Maven project, you must define more than 60 configurations with keys and values in one or more `application.properties` files. More configurations decrease readability for individual developers and are harder for developer teams to manage.
|
||||
|
||||
Quarkus has an interactive interface to display all dependencies that have been added. It is available at the `localhost:8080/q/dev` endpoint after you start Quarkus dev mode with the `mvn quarkus:dev` command. You can also update configurations in the DEV user interface (UI), as Figure 1 shows, and the changes will automatically sync with the `application.properties` file.
|
||||
|
||||
(Note: You can find the entire Quarkus application code for this article in my [GitHub repository][4].)
|
||||
|
||||
![Quarkus DEV UI][5]
|
||||
|
||||
Figure 1. Quarkus DEV UI (Daniel Oh, [CC BY-SA 4.0][6])
|
||||
|
||||
### Better continuous testing
|
||||
|
||||
When developing an application, anything from a monolith to microservices, you have to test your code. Often, a dedicated quality assurance (QA) team using external continuous integration (CI) tools is responsible for verifying unit tests. That's worked for years, and it still does, but Quarkus allows programmers to run tests in the runtime environment where their code is running as it's being developed. Quarkus 2.0 provides this continuous testing feature through the command-line interface (CLI) and the DEV UI, as shown in Figure 2.
|
||||
|
||||
![Quarkus Testing in DEV UI][7]
|
||||
|
||||
Figure 2. Quarkus testing in DEV UI (Daniel Oh, [CC BY-SA 4.0][6])
|
||||
|
||||
Continuous testing is not running when a Quarkus application starts. To start it, click "Tests not running" on the bottom-right of the DEV UI. You can also open a web terminal by clicking "Open" on the left-hand side of the DEV UI. Both of those options are highlighted in Figure 2, and an example test result is shown in Figure 3.
|
||||
|
||||
![Quarkus console in DEV UI][8]
|
||||
|
||||
Figure 3. Quarkus console in DEV UI (Daniel Oh, [CC BY-SA 4.0][6])
|
||||
|
||||
If you change the code (e.g., "Hello" to "Hi" in the `hello()` method) but not the test code (regardless of whether the feature works), the test will fail, as shown in Figure 4. To fix it, update the test code along with the logic code.
|
||||
|
||||
![Test failures in Quarkus DEV UI][9]
|
||||
|
||||
Figure 4. Test failures in Quarkus DEV UI (Daniel Oh, [CC BY-SA 4.0][6])
|
||||
|
||||
You can rerun the test cases implemented in the `src/test/java/` directory. This feature alleviates the need to integrate with an external CI tool and ensures functionality while developing business logic continuously.
|
||||
|
||||
### Zero configuration with dev services
|
||||
|
||||
When you're developing for a specific target, it's important that your development environment is an accurate reflection of the environment where it is meant to run. That can make installing a database in a place like a local environment a little difficult. If you're developing on Linux, you could run the requisite database in a container, but they tend to run differently based on what resources are available, and your local environment probably doesn't have the same resources as the target production environment.
|
||||
|
||||
Quarkus 2.0 helps solve this problem by providing dev services built on [Testcontainers][10]. For example, you can test applications if they work in the production database, PostgreSQL, rather than an H2 in-memory datastore with the following [configurations][11]:
|
||||
|
||||
|
||||
```
|
||||
quarkus.datasource.db-kind = postgresql (1)
|
||||
quarkus.hibernate-orm.log.sql = true
|
||||
|
||||
quarkus.datasource.username=person (2)
|
||||
quarkus.datasource.password=password (3)
|
||||
quarkus.hibernate-orm.database.generation=drop-and-create
|
||||
|
||||
%prod.quarkus.datasource.db-kind = postgresql (4)
|
||||
%prod.quarkus.datasource.jdbc.url = jdbc:postgresql://db:5432/person (5)
|
||||
%prod.quarkus.datasource.jdbc.driver=postgresql
|
||||
|
||||
quarkus.datasource.devservices.image-name=postgres:latest (6)
|
||||
```
|
||||
|
||||
In the code above:
|
||||
|
||||
(1) The kind of database you will connect for development and test
|
||||
(2) Datasource username
|
||||
(3) Datasource password
|
||||
(4) The kind of database you will connect for production
|
||||
(5) Datasource URL
|
||||
(6) The container image name to use for DevServices providers; if the provider is not container-based (e.g., H2 database), then this has no effect
|
||||
|
||||
When Quarkus restarts with the new configuration, the Postgres container image will be created and start running automatically, as in Figure 5.
|
||||
|
||||
![Quarkus DevServices][12]
|
||||
|
||||
Figure 5. Quarkus DevServices (Daniel Oh, [CC BY-SA 4.0][6])
|
||||
|
||||
This feature enables you to remove the production datastore integration test. It also increases your development productivity due to avoiding environmental disparities in the development loop.
|
||||
|
||||
### Conclusion
|
||||
|
||||
Quarkus 2.0 increases developer productivity with built-in continuous testing, an interactive DEV UI, and dev services. In addition, it offers additional features for improving developer experiences such as [live coding][13], [remote development mode on Kubernetes][14], and unified configurations that accelerate the development loop. Quarkus 2.0 is certainly no exception! Try it out for yourself [here][15]!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/7/developer-productivity-linux
|
||||
|
||||
作者:[Daniel Oh][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/daniel-oh
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/laptop_screen_desk_work_chat_text.png?itok=UXqIDRDD (Person using a laptop)
|
||||
[2]: https://opensource.com/resources/what-is-kubernetes
|
||||
[3]: https://quarkus.io/
|
||||
[4]: https://github.com/danieloh30/quarkus-testing
|
||||
[5]: https://opensource.com/sites/default/files/uploads/quarkus-devui.png (Quarkus DEV UI)
|
||||
[6]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[7]: https://opensource.com/sites/default/files/uploads/quarkustesting.png (Quarkus Testing in DEV UI)
|
||||
[8]: https://opensource.com/sites/default/files/uploads/quarkusconsole.png (Quarkus console in DEV UI)
|
||||
[9]: https://opensource.com/sites/default/files/uploads/failedtest.png (Test failures in Quarkus DEV UI)
|
||||
[10]: https://www.testcontainers.org/
|
||||
[11]: https://github.com/danieloh30/quarkus-testing/blob/main/src/main/resources/application.properties
|
||||
[12]: https://opensource.com/sites/default/files/uploads/quarkusdevservices.png (Quarkus DevServices)
|
||||
[13]: https://quarkus.io/guides/getting-started#development-mode
|
||||
[14]: https://developers.redhat.com/blog/2021/02/11/enhancing-the-development-loop-with-quarkus-remote-development
|
||||
[15]: https://quarkus.io/quarkus2/
|
@ -0,0 +1,119 @@
|
||||
[#]: subject: (Encrypt and decrypt files with a passphrase on Linux)
|
||||
[#]: via: (https://opensource.com/article/21/7/linux-age)
|
||||
[#]: author: (Sumantro Mukherjee https://opensource.com/users/sumantro)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
Encrypt and decrypt files with a passphrase on Linux
|
||||
======
|
||||
Age is a simple, easy-to-use tool that allows you to encrypt and decrypt
|
||||
files with a single passphrase.
|
||||
![Scissors cutting open access to files][1]
|
||||
|
||||
Encryption and security for protecting files and sensitive documents have long been a concern for users. Even as more and more of our data is housed on websites and cloud services, protected by user accounts with ever-more secure and challenging passwords, there's still great value in being able to store sensitive data on our own filesystems, especially when we can encrypt that data quickly and easily.
|
||||
|
||||
[Age][2] allows you to do this. It is a small, easy-to-use tool that allows you to encrypt a file with a single passphrase and decrypt it as required.
|
||||
|
||||
### Install age
|
||||
|
||||
Age is available to [install][3] from most Linux repositories.
|
||||
|
||||
To install it on Fedora:
|
||||
|
||||
|
||||
```
|
||||
`$ sudo dnf install age -y`
|
||||
```
|
||||
|
||||
On macOS, use [MacPorts][4] or [Homebrew][5]. On Windows, use [Chocolatey][6].
|
||||
|
||||
### Encrypting and decrypting files with age
|
||||
|
||||
Age can encrypt and decrypt files with either a public key or a passphrase set by the user.
|
||||
|
||||
#### Using age with a public key
|
||||
|
||||
First, generate a public key and write the output to a `key.txt` file:
|
||||
|
||||
|
||||
```
|
||||
$ age-keygen -o key.txt
|
||||
Public key: age16frc22wz6z206hslrjzuv2tnsuw32rk80pnrku07fh7hrmxhudawase896m9
|
||||
```
|
||||
|
||||
### Encrypt with a public key
|
||||
|
||||
To encrypt a file with your public key:
|
||||
|
||||
|
||||
```
|
||||
`$ touch mypasswds.txt | age -r ageage16frc22wz6z206hslrjzuv2tnsuw32rk80pnrku07fh7hrmxhudawase896m9 > mypass.tar.gz.age`
|
||||
```
|
||||
|
||||
In this example, the file `mypasswds.txt` is encrypted with the public key I generated and put inside an encrypted file called `mypass.tar.gz.age`.
|
||||
|
||||
### Decrypt with a public key
|
||||
|
||||
To decrypt the information you've protected, use the `age` command and the `--decrypt` option:
|
||||
|
||||
|
||||
```
|
||||
`$ age --decrypt -i key.txt -o mypass.tar.gz mypass.tar.gz.age`
|
||||
```
|
||||
|
||||
In this example, age uses the key stored in `key.text` and decrypts the file I created in the previous step.
|
||||
|
||||
### Encrypt with a passphrase
|
||||
|
||||
Encrypting a file without a public key is known as symmetrical encryption. It allows a user to set the passphrase to encrypt and decrypt a file. To do so:
|
||||
|
||||
|
||||
```
|
||||
$ age --passphrase --output mypasswd-encrypted.txt mypasswd.txt
|
||||
Enter passphrase (leave empty to autogenerate a secure one):
|
||||
Confirm passphrase:
|
||||
```
|
||||
|
||||
In this example, age prompts you for a passphrase, which it uses to encrypt the input file `mypasswd.txt` and render the file `mypasswd-encrypted.txt` in return.
|
||||
|
||||
### Decrypt with a passphrase
|
||||
|
||||
To decrypt a file encrypted with a passphrase, use the `age` command with the `--decrypt` option:
|
||||
|
||||
|
||||
```
|
||||
`$ age --decrypt --output passwd-decrypt.txt mypasswd-encrypted.txt`
|
||||
```
|
||||
|
||||
In this example, age prompts you for the passphrase, then decrypts the contents of the `mypasswd-encrypted.txt` file into `passwd-decrypt.txt`, as long as you provide the passphrase that matches the one set during encryption.
|
||||
|
||||
### Don't lose your keys
|
||||
|
||||
Whether you're using passphrase encryption or public-key encryption, you _must not_ lose the credentials for your encrypted data. By design, a file encrypted with age cannot be decrypted without the key used to encrypt it. So back up your public key, and remember those passphrases!
|
||||
|
||||
### Easy encryption at last
|
||||
|
||||
Age is a really robust tool. I like to encrypt my sensitive files, especially tax records and other archival data, into a `.tz` file for later access. Age is user-friendly and makes it very easy to get started with encryption on the go.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/7/linux-age
|
||||
|
||||
作者:[Sumantro Mukherjee][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/sumantro
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/document_free_access_cut_security.png?itok=ocvCv8G2 (Scissors cutting open access to files)
|
||||
[2]: https://github.com/FiloSottile/age
|
||||
[3]: https://github.com/FiloSottile/age#installation
|
||||
[4]: https://opensource.com/article/20/11/macports
|
||||
[5]: https://opensource.com/article/20/6/homebrew-mac
|
||||
[6]: https://opensource.com/article/20/3/chocolatey
|
@ -0,0 +1,97 @@
|
||||
[#]: subject: (Write good examples by starting with real code)
|
||||
[#]: via: (https://jvns.ca/blog/2021/07/08/writing-great-examples/)
|
||||
[#]: author: (Julia Evans https://jvns.ca/)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
Write good examples by starting with real code
|
||||
======
|
||||
|
||||
When I write about programming, I spend a lot of time trying to come up with good examples. I haven’t seen a lot written about how to make examples, so here’s a little bit about my approach to writing examples!
|
||||
|
||||
The basic idea here is to start with real code that you wrote and then remove irrelevant details to make it into a self-contained example instead of coming up with examples out of thin air.
|
||||
|
||||
I’ll talk about two kinds of examples: realistic examples and suprising examples.
|
||||
|
||||
### good examples are realistic
|
||||
|
||||
To see why examples should be realistic, let’s first talk about an unrealistic example! Let’s say we’re trying to explain Python lambdas (which is just the first concept I thought of). You could give this example, of using `map` and a lambda to double a set of numbers.
|
||||
|
||||
```
|
||||
numbers = [1, 2, 3, 4]
|
||||
squares = map(lambda x: x * x, numbers)
|
||||
```
|
||||
|
||||
I think this example is unrealistic for a couple of reasons:
|
||||
|
||||
* squaring a set of numbers isn’t something you’re super likely to do in a real program unless it’s for Project Euler or something (there are LOTS of operations on lists that are a lot more likely)
|
||||
* This usage of `map` is not idiomatic Python, even if you were doing this I would write `[x*x for x in numbers]` instead
|
||||
|
||||
|
||||
|
||||
A more realistic example of Python lambdas is using them with `sort`, like this;
|
||||
|
||||
```
|
||||
children = [{"name": "ashwin", "age": 12}, {"name": "radhika", "age": 3}]
|
||||
sorted_children = sorted(children, key=lambda x: x['age'])
|
||||
```
|
||||
|
||||
But this example is still pretty contrived (why exactly do we need to sort these children by age?). So how do we actually make realistic examples?
|
||||
|
||||
### how to make your examples realistic: look at actual code you wrote
|
||||
|
||||
I think the easiest way to make realistic examples is, instead of pulling an example out of thin air (like I did with that `children` example), instead just start by looking at real code!
|
||||
|
||||
For example, if I grep a bunch of Python code I wrote for `sort.+key`, I find LOTS of real examples of me sorting a list by some criterion, like:
|
||||
|
||||
* `tasks.sort(key=lambda task: task['completed_time'])`
|
||||
* `emails = reversed(sorted(emails, key=lambda x:x['receivedAt']))`
|
||||
* `sorted_keysizes = sorted(scores.keys(), key=scores.get)`
|
||||
* `shows = sorted(dates[date], key=lambda x: x['time']['performanceTime'])`
|
||||
|
||||
|
||||
|
||||
It’s pretty easy to see a pattern here – a lot of these are sorting by time! So you can see how you could easily put together a simple realistic example of sorting some objects (emails, events, etc) by time.
|
||||
|
||||
### realistic examples help “sell” the concept you’re trying to explain
|
||||
|
||||
When I’m trying to explain an idea (like Python lambdas), I’m usually also trying to convince the reader that it’s worth learning! Python lambdas are super useful! And to convince someone that lambdas are useful, it really helps to show someone how lambdas could help them do a task that they could actually imagine themselves doing, and ideally a task that they’ve done before.
|
||||
|
||||
### distilling down examples from real code can take a long time
|
||||
|
||||
The example I just gave of explaining how to use `sort` with `lambda` is pretty simple and it didn’t take me a long time to come up with, but turning real code into a standalone example can take a really long time!
|
||||
|
||||
For example, I was thinking of including an example of some weird CSS behaviour in this post to illustrate how it’s fun to create examples with weird or surprising behaviour. I spent 2 hours taking a real problem I had this week, making sure I understood what was actually happening with the CSS, and making it into a minimal example.
|
||||
|
||||
In the end it “just” took [5 lines of HTML and a tiny bit of CSS][1] to demonstrate the problem and it doesn’t really look like it took hours to write. But originally it was hundreds of lines of JS/CSS/JavaScript, and it takes time to untangle all that and come up with something small that gets at the heart of the issue!
|
||||
|
||||
But I think it’s worth it to take the time to make examples really clear and minimal – if hundreds of people are reading your example, you’re saving them all so much time!
|
||||
|
||||
### that’s all for now!
|
||||
|
||||
I think there’s a lot more to say about examples – for instance I think there are a few different types of useful examples, like:
|
||||
|
||||
* examples that are surprising to the reader, which are more about changing someone’s mental model than providing code to use directly
|
||||
* examples that are easy to copy and paste to use as a starting point
|
||||
|
||||
|
||||
|
||||
but maybe I’ll write about that another day :)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://jvns.ca/blog/2021/07/08/writing-great-examples/
|
||||
|
||||
作者:[Julia Evans][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://jvns.ca/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://codepen.io/wizardzines/pen/0eda7725a46c919dcfdd3fa80aff3d41
|
68
sources/tech/20210709 How to Install Zlib on Ubuntu Linux.md
Normal file
68
sources/tech/20210709 How to Install Zlib on Ubuntu Linux.md
Normal file
@ -0,0 +1,68 @@
|
||||
[#]: subject: (How to Install Zlib on Ubuntu Linux)
|
||||
[#]: via: (https://itsfoss.com/install-zlib-ubuntu/)
|
||||
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
How to Install Zlib on Ubuntu Linux
|
||||
======
|
||||
|
||||
[Zlib][1] is an open source library for used for data compression.
|
||||
|
||||
As an end user, you are likely to encounter the need of installing Zlib (or zlib devel package) as a dependency of another application.
|
||||
|
||||
But here comes the problem. If you try installing Zlib on Ubuntu, it will throw “unable to locate package zlib” error.
|
||||
|
||||
```
|
||||
sudo apt install zlib
|
||||
Reading package lists... Done
|
||||
Building dependency tree
|
||||
Reading state information... Done
|
||||
E: Unable to locate package zlib
|
||||
```
|
||||
|
||||
Why do you see this [unable to locate package error][2]? Because there is no package named zlib.
|
||||
|
||||
If you [use the apt search command][3], you’ll find that the there are a couple of packages that let you install zlib: **zlib1g and zlib1g-dev**. When you have that information, installing them is just one apt command away.
|
||||
|
||||
### Install Zlib on Ubuntu-based Linux distributions
|
||||
|
||||
Open a terminal and use the following command:
|
||||
|
||||
```
|
||||
sudo apt install zlib1g
|
||||
```
|
||||
|
||||
_**Please keep in mind that the the letter before g is 1 (one), not lowercase L. Many people make this mistake while typing the command.**_
|
||||
|
||||
The other package, zlib1g-dev is development package. Only install it if you require it otherwise you should be good with the main runtime zlib1g package.
|
||||
|
||||
```
|
||||
sudo apt install zlib1g-dev
|
||||
```
|
||||
|
||||
You may also download the source code of Zlib [from its website][1] and install it. However, I won’t recommend going the source code way just for installing zlib unless you have a good reason to do so. For example, if you need the latest or a specific version of zlib which is not available in the distribution’s repository.
|
||||
|
||||
It is interesting how a seemingly small stuff like installing zlib could become a pain for two reasons: a different package name and the package name containing a “hidden” numeral one (1) which is confused with lowercase L.
|
||||
|
||||
I hope this quick tip helps you. Feel free to drop your questions, suggestions or a simple “thank you” in the comment section.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/install-zlib-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://zlib.net/
|
||||
[2]: https://itsfoss.com/unable-to-locate-package-error-ubuntu/
|
||||
[3]: https://itsfoss.com/apt-search-command/
|
@ -0,0 +1,156 @@
|
||||
[#]: subject: (Enter invisible passwords using this Python module)
|
||||
[#]: via: (https://opensource.com/article/21/7/invisible-passwords-python)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
使用这个 Python 模块输入不可见的密码
|
||||
======
|
||||
用 GPG 和 Python 的 getpass 模块给你的密码多一层安全保障。
|
||||
![Password lock][1]
|
||||
|
||||
密码对程序员来说尤其成问题。你不应该在不加密的情况下存储它们,而且你也不应该在用户输入密码的时候透露出输入的内容。当我决定要提高我的笔记本电脑的安全性时,这对我来说变得特别重要。我对我的家目录进行了加密,但当我登录后,任何以纯文本形式存储在配置文件中的密码都有可能暴露在偷窥者面前。
|
||||
|
||||
具体来说,我使用一个名为 [Mutt][2] 的应用作为我的电子邮件客户端。它可以让我在我的 Linux 终端中阅读和撰写电子邮件,但通常它希望在其配置文件中有一个密码。我限制了我的 Mutt 配置文件的权限,以便只有我可以看到它,但我是我的笔记本电脑的唯一用户,所以我并不真的担心经过认证的用户会无意中看到我的配置文件。相反,我想保护自己不至于心不在焉地把我的配置发布到网上,无论是为了吹嘘还是为了版本控制,我的密码都暴露了。此外,虽然我不希望我的系统上有不受欢迎的客人,但我确实想确保入侵者不能通过对我的配置上运行 `cat` 就获得我的密码。
|
||||
|
||||
### Python GnuPG
|
||||
|
||||
Python 模块 `python-gnupg` 是 `gpg` 应用的一个 Python 封装。该模块的名字是 `python-gnupg`,你不要把它和一个叫做 `gnupg` 的模块混淆。
|
||||
|
||||
[GnuPG][3](GPG) 是 Linux 的默认加密系统,我从 2009 年左右开始使用它。我对它感到很舒服,对它的安全性有很高的信任。
|
||||
|
||||
我决定将我的密码输入 Mutt 的最好方法是将我的密码存储在一个加密的 GPG 文件中,创建一个提示我的 GPG 密码来解锁这个加密文件,然后将密码交给 Mutt(实际上是交给 `offlineimap` 命令,我用它来同步我的笔记本和电子邮件服务器)。
|
||||
|
||||
[用 Python 获取用户输入][4]是非常容易的。对 `input` 进行调用,无论用户输入什么,都会被存储为一个变量:
|
||||
|
||||
|
||||
```
|
||||
print("Enter password: ")
|
||||
myinput = input()
|
||||
|
||||
print("You entered: ", myinput)
|
||||
```
|
||||
|
||||
我的问题是,当我根据密码提示在终端上输入密码时,我所输入的所有内容对任何从我肩膀上看过去或滚动我的终端历史的人来说都是可见的:
|
||||
|
||||
|
||||
```
|
||||
$ ./test.py
|
||||
Enter password: my-Complex-Passphrase
|
||||
```
|
||||
|
||||
### 用 getpass 输入不可见密码
|
||||
|
||||
正如通常的情况一样,有一个 Python 模块已经解决了我的问题。这个模块是 `getpass4`,从用户的角度来看,它的行为和 `input` 完全一样,只是不显示用户输入的内容。
|
||||
|
||||
你可以用 [pip][5] 安装这两个模块:
|
||||
|
||||
|
||||
```
|
||||
$ python -m pip install --user \
|
||||
python-gnupg getpass4
|
||||
```
|
||||
|
||||
下面是我的 Python 脚本,用于创建密码提示:
|
||||
|
||||
|
||||
```
|
||||
#!/usr/bin/env python
|
||||
# by Seth Kenlon
|
||||
# GPLv3
|
||||
|
||||
# install deps:
|
||||
# python3 -m pip install --user python-gnupg getpass4
|
||||
|
||||
import gnupg
|
||||
import getpass
|
||||
from pathlib import Path
|
||||
|
||||
def get_api_pass():
|
||||
homedir = str(Path.home())
|
||||
gpg = gnupg.GPG(gnupghome=os.path.join(homedir,".gnupg"), use_agent=True)
|
||||
passwd = getpass.getpass(prompt="Enter your GnuPG password: ", stream=None)
|
||||
|
||||
with open(os.path.join(homedir,'.mutt','pass.gpg'), 'rb') as f:
|
||||
apipass = (gpg.decrypt_file(f, passphrase=passwd))
|
||||
|
||||
f.close()
|
||||
|
||||
return str(apipass)
|
||||
|
||||
if __name__ == "__main__":
|
||||
apipass = get_api_pass()
|
||||
print(apipass)
|
||||
```
|
||||
|
||||
如果你想试试,把文件保存为 `password_prompt.py`。如果你使用 `offlineimap` 并想在你自己的密码输入中使用这个方案,那么把它保存到某个你可以在 `.offlineimaprc` 文件中指向 `offlineimap` 的位置(我使用 `~/.mutt/password_prompt.py`)。
|
||||
|
||||
### 测试密码提示
|
||||
|
||||
要查看脚本的运行情况,你首先必须创建一个加密文件(我假设你已经设置了 GPG):
|
||||
|
||||
|
||||
```
|
||||
$ echo "hello world" > pass
|
||||
$ gpg --encrypt pass
|
||||
$ mv pass.gpg ~/.mutt/pass.gpg
|
||||
$ rm pass
|
||||
```
|
||||
|
||||
现在运行 Python 脚本:
|
||||
|
||||
|
||||
```
|
||||
$ python ~/.mutt/password_prompt.py
|
||||
Enter your GPG password:
|
||||
hello world
|
||||
```
|
||||
|
||||
当你输入时没有任何显示,但只要你正确输入 GPG 口令,你就会看到测试信息。
|
||||
|
||||
### 将密码提示符与 offlineimap 整合起来
|
||||
|
||||
我需要将我的新提示与 `offlineimap` 命令结合起来。我为这个脚本选择了 Python,因为我知道 `offlineimap` 可以对 Python 程序进行调用。如果你是一个 `offlineimap` 用户,你会明白唯一需要的“整合”是在你的 `.offlineimaprc` 文件中改变两行。
|
||||
|
||||
首先,添加一行引用 Python 文件的内容:
|
||||
|
||||
|
||||
```
|
||||
`pythonfile = ~/.mutt/password_prompt.py`
|
||||
```
|
||||
|
||||
然后将 `.offlineimaprc`中的 `remotepasseval` 行改为调用 `password_prompt.py`中的 `get_api_pass()` 函数:
|
||||
|
||||
```
|
||||
`remotepasseval = get_api_pass()`
|
||||
```
|
||||
|
||||
配置文件中不再有密码!
|
||||
|
||||
### 安全问题
|
||||
|
||||
在你的个人电脑上考虑安全问题有时会让人觉得很偏执。你的 SSH 配置是否真的需要限制为 600?隐藏在名为 `.mutt` 的无关紧要的电子邮件密码真的重要吗?也许不重要。
|
||||
|
||||
然而,知道我没有把敏感数据悄悄地藏在我的配置文件里,使我更容易把文件提交到公共 Git 仓库,把片段复制和粘贴到支持论坛,并以实际的、已知的好的配置文件的形式分享我的知识。仅就这一点而言,安全性的提高使我的生活更加轻松。而且有这么多好的 Python 模块可以提供帮助,这很容易实现。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/7/invisible-passwords-python
|
||||
|
||||
作者:[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/password.jpg?itok=ec6z6YgZ (Password lock)
|
||||
[2]: http://www.mutt.org/
|
||||
[3]: https://gnupg.org/
|
||||
[4]: https://opensource.com/article/20/12/learn-python
|
||||
[5]: https://opensource.com/article/19/11/python-pip-cheat-sheet
|
Loading…
Reference in New Issue
Block a user