标签 不可变 下的文章

本文介绍如何使用 rpm-ostree 查找要添加到基于 ostree 的系统(例如 Silverblue 和 Kinoite)的应用。

基于 Fedora ostree 的系统的主要优点之一是系统的不可变性。该镜像不仅是只读的,而且是预先构建在 Fedora 服务器上的。因此,更新正在运行的系统会下载更新增量(即仅差异)并修补系统。这使得许多安装在默认情况下都是相同的。

对于大多数人来说,预构建的镜像就足够了,因为通常鼓励用户同时使用 Flatpak 安装应用,使用工具箱进行开发任务。但是,如果特定应用不符合此要求并且用户需要在主机系统上安装应用怎么办?

在这种情况下,可以选择在系统上覆盖软件包,在本地创建一个新的镜像,在标准镜像上添加软件包。

但是,我如何知道我要安装哪个包?搜索功能怎么样?

老方法(toolbox + dnf search)

虽然始终可以通过支持 PackageKit 的软件中心(例如 GNOME “ 软件 Software ” 应用 或 KDE “ 发现 Discover ” 应用)搜索软件包,但通过 CLI 来搜索软件包有点困难。

由于 rpm-ostree 不曾提供搜索命令,因此常见的搜索方式是使用 toolbox enter 进入工具箱并使用 dnf search <搜索词> 进行搜索。这样做的缺点是需要在工具箱中启用相同的仓库才能获得正确的搜索结果。

搜索 neofetch 的示例:

$ toolbox enter
<Note that at this point the toolbox command might request creating a toolbox, which might involve downloading a container image>
⬢[fedora@toolbox ~]$ dnf search neofetch
<snip> 
=== Name Exactly Matched: neofetch ===
neofetch.noarch : CLI system information tool written in Bash
=== Summary Matched: neofetch ===
fastfetch.x86_64 : Like neofetch, but much faster because written in c

新方法(rpm-ostree search)

version 2023.6 开始,rpm-ostree 支持 search 命令,允许用户使用 rpm-ostree 搜索可用的软件包。一个示例命令是:

rpm-ostree search *kernel

要使用搜索命令,请首先确保你使用的是 rpm-ostree 2023.6 或更高版本:

$ rpm-ostree --version
rpm-ostree:
    Version: '2023.8'
    Git: 9a99d0af32640b234318815a256a2d11e35fa64c
    Features:
    - rust
    - compose
    - container
    - fedora-integration

如果满足版本要求,你应该能够运行 rpm-ostree search <搜索词>

这是一个使用 rpm-ostree search 搜索 neofetch 的示例:

$ rpm-ostree search neofetch

===== Name Matched =====
neofetch : CLI system information tool written in Bash

===== Summary Matched =====
fastfetch : Like neofetch, but much faster because written in c

(题图:DA/5d27838e-6068-46a6-9bca-4ec486d65c46)


via: https://fedoramagazine.org/searching-for-packages-with-rpm-ostree-search/

作者:Mateus Rodrigues Costa 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

不可变性是一种时下流行的概念。看看有哪些适合你的不可变 Linux 发行版。

每个发行版都是根据一系列目的而定制的。一些配置适用于 旧计算机,一些旨在提供 优质的用户体验,而一些则专注于安全性。

几年前,不可变发行版不是用户想要的。但是,最近越来越多的项目正在将不可变性作为 Linux 发行版的核心特征。

为什么会这样?有哪些可供选择?在你查看此列表之前,让我简要地向你介绍不可变性的更多内容:

什么是不可变 Linux 发行版?

不可变发行版确保操作系统的核心保持不变。对于不可变发行版来说,根文件系统保持为只读状态使得它可以在多个实例中保持相同。当然,如果你希望更改某些内容,则仍可以进行更改。但默认情况下该能力会被禁用。

它有什么用处?

传统上,不可变发行版存在的目的是为了方便测试和基于容器的软件开发。此外,不可变性为你的操作系统提供了更好的安全性和可靠的更新。

早期,这种特性的关注点主要集中在针对专业人士和开发人员的发行版上。现在,它开始应用于日常桌面用户。

? 以下列表并没有按照任何特定的排名顺序列出,并且某些发行版仍处于早期开发阶段。

1、carbonOS

carbon os screenshot with gnome menu

在写这篇文章时,carbonOS 是一款仍未推出的独立 Linux 发行版。它专注于提供强大的技术和流畅的用户体验。

它采用 Flatpak 优先和容器优先的方法。carbonOS 还旨在提供安全的系统更新,并提供一些不是所有原子发行版都具备的功能,如经过验证的启动。

除了其独特的特点外,它还希望专注于为用户提供出色的 GNOME 桌面体验。

2、Fedora Silverblue

fedora workstation screenshot

Silverblue 是具有不可变性的 Fedora Workstation 的变种,是最受欢迎的不可变发行版之一。

用户界面和体验与普通的 Fedora Workstation 发行版保持一致。每当有新的 Fedora 版本发布时,也会有一个新的 Silverblue 版本。

Fedora Silverblue 旨在提供稳定的体验,适用于测试和基于容器的软件开发。如果更新后出现问题,你总是可以回滚到该操作系统的先前版本。

3、Flatcar Container Linux

flatcar linux

正如名字所示,这是一个专门针对容器工作负载而定制的社区构建版 Linux 发行版。

你将获得一个最小化的操作系统镜像,其中仅包括运行容器所需的工具,没有包管理器,也无需配置。

如果你想为你的容器提供可靠的底层,那么 Flatcar 可能是一个不错的选择,因为它同时具有可伸缩性、安全性和简单性。请在其 GitHub 页面 上了解更多信息。

4、openSUSE MicroOS

opensuse microos

openSUSE MicroOS 是为需要部署容器或处理自动化工作流程的服务器而构建的。

它依赖于事务性更新(使用 Btrfs 进行快照),这有助于保存文件系统的历史记录而不占用太多存储空间。

总的来说,MicroOS 是服务器用户的一个可扩展、可靠和安全的选项。

5、Vanilla OS

vanilla os

Vanilla OS 是不可变性领域中的一个相对较新的参与者。但是,它在发布后成功引起了轰动,并在第一个稳定版发布后切换到了以 Debian 为基础,放弃了 Ubuntu。

它旨在提供易于使用的桌面体验,同时具备可靠性和不可变性特征。

6、Bottlerocket

Bottlerocket 是由 AWS 构建的基于 Linux 的开源操作系统,旨在在其平台上运行容器。

与其他选项不同,它的使用仅限于 AWS。

它确保使用 AWS 服务的客户具有最少的维护开销,并且可以无缝地自动化其工作流程。创建 EC2( 亚马逊弹性计算云 Amazon Elastic Compute Cloud )时,你只能将其用作 AMI( 亚马逊机器镜像 Amazon Machine Image ) 使用。

7、blendOS

blendOS

blendOS 是一个正在开发中的有趣发行版,旨在提供其他发行版的各种优点。

换句话说,你可以在发行版上安装任何类型的软件包(RPM、DEB 等),同时获得所期望的不可变性和更新可靠性。

8、Talos Linux

talos linux

另一个独特的 Linux 发行版,专为 Kubernetes 设计。Talos Linux 对于云用户/开发人员来说是一个有趣的选择。

它是安全、不可变的,是支持云平台、裸机和虚拟化平台的最小化选择之一。你还可以在 Docker 中轻松启动 Talos 集群。

该操作系统从 SquashFS 中运行在内存中,这样整个主磁盘都可以留给 Kubernetes。

9、NixOS

NixOS 是当前 最先进的 Linux 发行版 之一。如果你想要不可变性以及易于恢复、强大的软件包管理器等诸多好处,那么 NixOS 将是一个很好的选择。

如果你还不了解 NixOS,也不用担心,可以浏览我们的 NixOS 系列文章 来学习并进行设置。

10、GUIX

GUIX 类似于 NixOS(某种程度上),并且专为希望获得可靠升级和良好系统控制的高级用户而设计。

如果你是一名新的 Linux 用户,不应将其视为你的日常操作系统。因此,你可能需要查阅 文档 以便浏览并开始使用。

11、Endless OS

Endless OS 是一个基于 Debian 的 Linux 发行版。

与其它基于 Debian 的发行版(例如 Ubuntu)不同,Endless OS 采用了健壮的设计,在其核心实现了不可变性,以确保更新一个软件包不会破坏系统。

? 你对不可变的 Linux 发行版有何看法?你需要它们吗?你是否想在未来将你系统上的流行选项替换为其中任何一个?

(题图:MJ/6c0169a0-9820-4bf7-b9fb-f0cd2c45d7bf)


via: https://itsfoss.com/immutable-linux-distros/

作者:Ankush Das 选题:lkxed 译者:ChatGPT 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

不可变性可以帮助我们更好地理解我们的代码。下面我将讲述如何在不牺牲性能的条件下来实现它。

在这个由两篇文章构成的系列中,我将讨论如何将函数式编程方法论中的思想引入至 Python 中,来充分发挥这两个领域的优势。

本文(也就是第一篇文章)中,我们将探讨不可变数据结构的优势。第二部分会探讨如何在 toolz 库的帮助下,用 Python 实现高层次的函数式编程理念。

为什么要用函数式编程?因为变化的东西更难推理。如果你已经确信变化会带来麻烦,那很棒。如果你还没有被说服,在文章结束时,你会明白这一点的。

我们从思考正方形和矩形开始。如果我们抛开实现细节,单从接口的角度考虑,正方形是矩形的子类吗?

子类的定义基于里氏替换原则。一个子类必须能够完成超类所做的一切。

如何为矩形定义接口?

from zope.interface import Interface

class IRectangle(Interface):
    def get_length(self):
        """正方形能做到"""
    def get_width(self):
        """正方形能做到"""
    def set_dimensions(self, length, width):
        """啊哦"""

如果我们这么定义,那正方形就不能成为矩形的子类:如果长度和宽度不等,它就无法对 set_dimensions 方法做出响应。

另一种方法,是选择将矩形做成不可变对象。

class IRectangle(Interface):
    def get_length(self):
        """正方形能做到"""
    def get_width(self):
        """正方形能做到"""
    def with_dimensions(self, length, width):
        """返回一个新矩形"""

现在,我们可以将正方形视为矩形了。在调用 with_dimensions 时,它可以返回一个新的矩形(它不一定是个正方形),但它本身并没有变,依然是一个正方形。

这似乎像是个学术问题 —— 直到我们认为正方形和矩形可以在某种意义上看做一个容器的侧面。在理解了这个例子以后,我们会处理更传统的容器,以解决更现实的案例。比如,考虑一下随机存取数组。

我们现在有 ISquareIRectangle,而且 ISequereIRectangle 的子类。

我们希望把矩形放进随机存取数组中:

class IArrayOfRectangles(Interface):
    def get_element(self, i):
        """返回一个矩形"""
    def set_element(self, i, rectangle):
        """'rectangle' 可以是任意 IRectangle 对象"""

我们同样希望把正方形放进随机存取数组:

class IArrayOfSquare(Interface):
    def get_element(self, i):
        """返回一个正方形"""
    def set_element(self, i, square):
        """'square' 可以是任意 ISquare 对象"""

尽管 ISquareIRectangle 的子集,但没有任何一个数组可以同时实现 IArrayOfSquareIArrayOfRectangle.

为什么不能呢?假设 bucket 实现了这两个类的功能。

>>> rectangle = make_rectangle(3, 4)
>>> bucket.set_element(0, rectangle) # 这是 IArrayOfRectangle 中的合法操作
>>> thing = bucket.get_element(0) # IArrayOfSquare 要求 thing 必须是一个正方形
>>> assert thing.height == thing.width
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

无法同时实现这两类功能,意味着这两个类无法构成继承关系,即使 ISquareIRectangle 的子类。问题来自 set_element 方法:如果我们实现一个只读的数组,那 IArrayOfSquare 就可以是 IArrayOfRectangle 的子类了。

在可变的 IRectangle 和可变的 IArrayOf* 接口中,可变性都会使得对类型和子类的思考变得更加困难 —— 放弃变换的能力,意味着我们的直觉所希望的类型间关系能够成立了。

可变性还会带来作用域方面的影响。当一个共享对象被两个地方的代码改变时,这种问题就会发生。一个经典的例子是两个线程同时改变一个共享变量。不过在单线程程序中,即使在两个相距很远的地方共享一个变量,也是一件简单的事情。从 Python 语言的角度来思考,大多数对象都可以从很多位置来访问:比如在模块全局变量,或在一个堆栈跟踪中,或者以类属性来访问。

如果我们无法对共享做出约束,那我们可能要考虑对可变性来进行约束了。

这是一个不可变的矩形,它利用了 attr 库:

@attr.s(frozen=True)
class Rectange(object):
    length = attr.ib()
    width = attr.ib()
    @classmethod
    def with_dimensions(cls, length, width):
        return cls(length, width)

这是一个正方形:

@attr.s(frozen=True)
class Square(object):
    side = attr.ib()
    @classmethod
    def with_dimensions(cls, length, width):
        return Rectangle(length, width)

使用 frozen 参数,我们可以轻易地使 attrs 创建的类成为不可变类型。正确实现 __setitem__ 方法的工作都交给别人完成了,对我们是不可见的。

修改对象仍然很容易;但是我们不可能改变它的本质。

too_long = Rectangle(100, 4)
reasonable = attr.evolve(too_long, length=10)

Pyrsistent 能让我们拥有不可变的容器。

# 由整数构成的向量
a = pyrsistent.v(1, 2, 3)
# 并非由整数构成的向量
b = a.set(1, "hello")

尽管 b 不是一个由整数构成的向量,但没有什么能够改变 a 只由整数构成的性质。

如果 a 有一百万个元素呢?b 会将其中的 999999 个元素复制一遍吗?Pyrsistent 具有“大 O”性能保证:所有操作的时间复杂度都是 O(log n). 它还带有一个可选的 C 语言扩展,以在“大 O”性能之上进行提升。

修改嵌套对象时,会涉及到“变换器”的概念:

blog = pyrsistent.m(
    title="My blog",
    links=pyrsistent.v("github", "twitter"),
    posts=pyrsistent.v(
        pyrsistent.m(title="no updates",
                     content="I'm busy"),
        pyrsistent.m(title="still no updates",
                     content="still busy")))
new_blog = blog.transform(["posts", 1, "content"],
                          "pretty busy")

new_blog 现在将是如下对象的不可变等价物:

{'links': ['github', 'twitter'],
 'posts': [{'content': "I'm busy",
            'title': 'no updates'},
           {'content': 'pretty busy',
            'title': 'still no updates'}],
 'title': 'My blog'}

不过 blog 依然不变。这意味着任何拥有旧对象引用的人都没有受到影响:转换只会有局部效果。

当共享行为猖獗时,这会很有用。例如,函数的默认参数:

def silly_sum(a, b, extra=v(1, 2)):
    extra = extra.extend([a, b])
    return sum(extra)

在本文中,我们了解了为什么不可变性有助于我们来思考我们的代码,以及如何在不带来过大性能负担的条件下实现它。下一篇,我们将学习如何借助不可变对象来实现强大的程序结构。


via: https://opensource.com/article/18/10/functional-programming-python-immutable-data-structures

作者:Moshe Zadka 选题:lujun9972 译者:StdioA 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出