toml


二萌当初在写本章时,本来是打算给 edition 2022 准备的。
实际上,有部分内容已经下放给 edition 2021 了。

在之后的新版中,对于面向用户的配置,toml 会出现得更加频繁。


在天萌中,配置文件分为两种。
一种是只能看的,另一种则是可以写的。

只读可读可写
一般是软件包发行信息或数据索引信息真正意义上的程序配置文件

1. 只读配置

1.1. 概念解读

天萌的“容器属性信息”就是只读配置。
此处所指的只读配置并不是文件权限的 "read only",而是逻辑上的只读。
实际上,您可以直接修改该文件的内容,只是不应该手动去修改。
举个例子:
假如您看到了版本号为"1.57.0"。
心想:“这版本号也忒低了吧!咱把它改成 114514.999.9 吧!”
于是,您很开心地修改了它本身的属性。
从主观的角度来看:您收获了快乐。这很棒!因为快乐是一种积极的生活态度。
从客观的角度来看:您修复了版本号过低的问题。这也不错!
从原开发者的角度来看:啊这。。。
于是乎,只有原开发者受伤的世界达成了。(ó﹏ò。)

注:以上修改的内容不会生效。
对于只读配置,如果修改真的生效了,那么容器在安装或使用过程中可能会出现问题。
我相信您能在下一小节中找到原因。

1.2. 分析

本节将对“容器属性信息”进行分析。

天萌每周构建容器输出的只读配置如下:
(之后可能会发生变更)

[main]
name = "rust"
tag = ["nightly", "unstable"]
os = "debian"
release = "sid"
arch = "arm64"
syntax_version = "0.0.1"

[file]
name = "rust-nightly-arm64_2021-09-17_20-39.tar.zst"

# 这个值可以用来校验文件的完整性
# 举个例子:假设存在两个同名文件,它们都叫a.tar.zst,大小也相同,只是所在目录不同: A/a.tar.zst, B/a.tar.zst
# 您可能无法直接判断它们是否属于同一个文件
# 这时候可以通过对比两者的 sha256 校验值来检测它们是否为同一个文件,若 sha256 值相同,则文件相同,反之不同。
# 注:此处忽略了哈希碰撞等问题。
sha256 = "acc668db456e94053322f7049469995ba20e9fe6dcb297367226dca4553b633e"

[file.size]
# Installed size ≈ tar-size
# 安装大小 约等于 tar文件的大小
# tar大小就是容器镜像打包后的大小,解包后占用的空间可能会比tar本身略大一点
# 具体大小与文件簇有关,而文件簇又与 file system(文件系统)有关。
tar = "1.6G"
tar-bytes = 1717986919

# Space occupied ≈ tar-size + zstd-size
# You will need to prepare a large enough space before installation.
# Download size: zstd-size
# 在tar打包完成后,开发者还对镜像进行了压缩。
# 您需要下载的文件大小就是zstd的大小,准确来说是tar.zst文件的大小
# 在安装一个容器前,您需要考虑预留一定的空间:
# 1.压缩包文件的大小,2.压缩包解压后的大小, 3.容器的初始化过程也需要占用一点空间。
zstd = "216M"
zstd-bytes = 226492416

# 对于2022版,用户只需要看版本号就能知道镜像的先后顺序了,知道哪个比较新哪个比较旧。
# 开发者忽然想到了天萌存在一个自动判断时间先后顺序的功能,就算是旧版也有这个功能。
# 其实time(时间)是给开发者看的,普通用户不需要了解服务器在构建镜像过程中的某个流程究竟花了多少时间。
# 如果您感兴趣的话,那我可以说一下流程。
# 1. 服务器构建完成镜像后,需要对镜像进行打包和压缩。
# 2. start-zstd指的是开始进行zstd压缩的时间点
# 3. 在压缩完成后,需要将文件传输到另一个节点。
# 3-1. 对于天萌的每周构建,并不是所有节点都从零开始构建,而是其中一个节点完成构建后,就把相关文件同步到另一个节点。
[time]
begin = 2021-09-17T20:08:33.801113258Z
start-zstd = 20:14:20
start-sync_0 = 20:39:22
start-sync_1 = 20:41:33
end = 2021-09-17T20:44:32.392018144Z

[server]
name = "tmoe-us"
node = 2
available = [1, 2, 3, 4]

# Environment variables inside the container.
# 容器内部的环境变量会影响容器内的环境,~~听君一席话,如听一席话~~(●>ω<●)
[env]
PATH = "/usr/local/cargo/bin${PATH:+:${PATH}}"
RUSTUP_HOME= "/usr/local/rustup"
CARGO_HOME = "/usr/local/cargo"

[version]
rustup = 'rustup 1.24.3 (ce5817a94 2021-05-31)'
cargo = 'cargo 1.56.0-nightly (e515c3277 2021-09-08)'
rustc = 'rustc 1.57.0-nightly (e4828d5b7 2021-09-16)'

toml 是一种优秀的配置文件格式。
接下来,我们将会介绍 toml 的理念以及常见用法。
最后,我们将简单了解“可写配置”的概念与用法。

2. toml

2.1. 什么是 toml

Tom's Obvious, Minimal Language.
Tom 的(语义)明显、(配置)最小化的语言。
TOML 旨在成为一个语义明显且易于阅读的最小化配置文件格式。
TOML 被设计成可以无歧义地映射为哈希表。
TOML 应该能很容易地被解析成各种语言中的数据结构。

以上说明来自于 toml 的官网,您可以在里面找到一些详细的说明。

2.2. toml 与 json

谈到 toml,很多人都会提及到 json
为什么不用json呢? 它跟json 比有什么优势吗?

github 上 toml-lang/toml 的第 2 条 issue 就跟这个话题有关。

"No, JSON doesn't count. You know why."

But I don't know why too.

2.3. toml 的简单用法

本小节的内容将为(#4.3-可写配置) 打下基础。
在天萌容器的配置中,可能会涉及到以下知识点:

  • 字符串
  • 整数
  • 浮点数
  • 布尔值
  • rfc3339
  • 数组
  • 标准表
  • 内联表

其实这些也是 toml 本身的常见值类型。

很少涉及到的知识点是:

  • 表数组

2.3.1. 表数组

表数组的话,虽然很好用,但是天萌的开发者 (想要偷懒) 由于某种原因就不用这种类型了。

其实是表数组解析起来稍微要麻烦一点。
举个简单的例子:

[[bin]]
name = "tmm"

[[bin]]
name = "value"

[[bin]]
name = "tmoe"

全删[[bin]] 或者是追加写入一个新的[[bin]] 都很简单。
但是呢!要修改包含指定"value"的数据,还得要再处理一下。
不像标准表,直接键值对操作,多简单啊!

2.3.2. 字符串

字符串可能是天萌容器的配置文件里最常见的类型了。

比如说

str = "value"

toml 的字符串类型既可以用双引号,也可以用单引号。
这跟 rust 不一样,在 rust 中,如果您使用单引号,并且没有指明类型,那么编译器默认会推断该值为 char 类型(单个字符)。


#![allow(unused)]
fn main() {
let c = 'c';
}

回到 toml,你如果需要输入多个引号的话,那就这样子写吧!

str = """我有'''''5个单引号,还有两个""双引号"""

前面和后面都有三个引号。

2.3.3. 整数

整数的话,就不需要引号了!
举个字符串的例子:

int1 = "233"

在上面的式子中,int 的值将被识别为字符串, 而不是整数。
再举个整数的例子:

int2 = 233

举个负整数的例子:

int3 = -233

toml 可以接受的整数范围是 i64 (从 −2^63 到 2^63−1)。
跟 rust 一样,对于特别大的数字,您可以用 _ 来增强可读性。

int4 = 114_514_233

上面那条式子等于下面那条

int4 = 114514233

举个二进制、八进制和十六进制整数的例子:

# 二进制的0b11011111101010010等于十进制的114514
bin = 0b11011111101010010
# 0o开头的值是八进制的数字,猜猜看这是哪个数
oct1 = 0o337522
# 0x开头是十六进制喔
hex1 = 0x1BF52

2.3.4. 浮点数

浮点数也不能加引号哦!

用小数和指数形式举个几个例子吧!

f1 = 3.14159265
f2 = -3.14159265
f3 = 314e-2
f4 = 0.1145e+4

2.3.5. 布尔值

布尔值只有两个值: truefalse

true 为真,false 为假
true ✓
false X

bool1 = true
bool2 = false

2.3.6. rfc3339

rfc3339 是一种时间格式。

# 您可以只写时间
time1 = 01:25:57
time2 = 01:25:00.247810421
# 也可以只写日期
date1 = 2021-09-29
# 也可以都写
time3 = 2021-09-29T01:25:57Z
# 您可以把上面那个拆开来,并且无需加引号
time4 = 2021-09-29 01:25:57Z
# 末尾的Z代表的是UTC, 您可以换成+00:00
# 下面以纳秒级别来输出东八区的某一时间点。那么问题来了,您知道为什么是这个时间点吗?
time5 = 2021-09-29 01:29:13.598811802+08:00

因为开发者写文档写到很晚,都写到这个点啦!很辛苦的说。

2.3.7. 数组

简单来说,数组就是一个方括号,然后里面有 0 个或多个值。

# 您可以换行写
array1 = [233,
22,
33]
# 也可以不换行写
array2 = [ "你好", "世界" ]

2.3.8. 标准表

标准表也被称为哈希表。

举个 Cargo 里面的例子

[dependencies]
nom = "7.0.0"

您可以把上面的表写成下面的格式

[dependencies.nom]
version = "7.0.0"

2.3.9. 内联表

内联表可以把多行写成一行。

先举个标准表的例子

[dependencies.tokio]
version = "1.11.0"
features = ["macros", "tcp", "dns", "io-util"]

再举个内联表的例子

[dependencies]
tokio = { version = "1.11.0", features = ["macros", "tcp", "dns", "io-util"] }

怎么样?您喜欢标准表还是内联表呢?

3. 可写配置

3.1. 概念解读

咕咕咕,这个部分还没有开始写呢!