1 个不稳定版本

0.1.0 2023 年 10 月 6 日

#37 in #symlink

24 每月下载量
用于 3 个 Crates (2 直接)

MIT 许可证

63KB
1.5K SLoC

此 crate 提供了从文本形式构建 [SchemaNode] 树的方法(见 [parse_schema])。

文本形式的语言使用重要空白(四个空格)进行缩进,通过存在 / 区分文件和目录,并通过存在 ->(后跟其目标路径表达式)来判断是否为符号链接。即目录树中的每个缩进节点具有以下形式之一

语法 描述
str 一个文件
str/ 一个目录
str -> expr 指向文件的符号链接
str/ -> expr 指向目录的符号链接

使用以下标签设置给定节点的属性

标签 类型 描述
:owner expr 所有 设置此文件/目录/符号链接目标的拥有者
:group expr 所有 设置此文件、目录或符号链接目标的组
:mode 八进制 所有 设置此文件/目录/符号链接目标的权限
:source expr 文件 expr 给定的路径内容复制到此文件中
:let ident = expr 目录 在此级别设置变量,供更深层使用
:def ident 目录 定义一个可由 :use 重复使用的子模式
:use ident 目录 重复使用由 :def 定义的子模式

简单模式

模式的第一层描述了一个目录,其[属性][Attributes]可以由:owner:group:mode标签设置。

use diskplan_schema::*;

let schema_root = parse_schema("
    :owner person
    :group user
    :mode 777
")?;

assert!(matches!(schema_root.schema, SchemaType::Directory(_)));
assert_eq!(schema_root.attributes.owner.unwrap(), "person");
assert_eq!(schema_root.attributes.group.unwrap(), "user");
assert_eq!(schema_root.attributes.mode.unwrap(), 0o777);

一个[DirectorySchema]可以包含子目录和文件。

#
// ...
"
    subdirectory/
        :owner admin
        :mode 700

    file_name
        :source content/example_file
"
// ...
assert_eq!(
    parse_schema(text)?
        .schema
        .as_directory()
        .expect("Not a directory")
        .entries()
        .len(),
    2
);

它还可以包含指向目录和文件的符号链接,其自身的模式将应用于目标。

#
// ...
"
    example_link/ -> /another/disk/example_target/
        :owner admin
        :mode 700

        file_to_create_at_target_end
            :source content/example_file
"
// ...
#
let (binding, node) = directory.entries().first().unwrap();
assert!(matches!(
    binding,
    Binding::Static(ref name) if name == &String::from("example_link")
));
assert_eq!(
    node.symlink.as_ref().unwrap().to_string(),
    String::from("/another/disk/example_target/")
);
assert!(matches!(node.schema, SchemaType::Directory(_)));
#
#

变量替换

变量可以用来驱动构建,例如

"
    :let asset_type = character
    :let asset_name = Monkey

    assets/
        $asset_type/
            $asset/
                reference/
"

变量也会拾取磁盘上已有的名称(即使一个:let提供了不同的值)。例如,如果我们已经在磁盘上有了assets/prop/Banana,那么$asset_type会与“prop”匹配(以及“character”),而$asset将获取“Banana”的值(以及“Monkey”),生成

assets
├── character
│   └── Monkey
│       └── reference
└── prop
    └── Banana
        └── reference

模式匹配

模式中的任何节点都可以有一个:match标签,它通过正则表达式控制变量可以取的可能值。

重要: 没有任何两个变量可以匹配相同的值。如果它们匹配,则在执行过程中将发生错误,因此请务必确保模式之间没有重叠。使用:avoid可以帮助限制模式匹配并确保适当的分区。

静态名称(不带变量)始终具有优先级,并且不需要与变量模式(反之亦然)唯一。

例如,这在模式中是合法的,但在实践中总是会出现错误

$first/
$second/

例如,当操作路径/test时,它会生成

Error: "test" matches multiple dynamic bindings "$first" and "$second" (Any)

一个工作示例可能是

$first/
    :match [A-Z].*
$second/
    :match [^A-Z].*

模式重用

模式的部分可以由可重用的定义构建。

定义是通过使用:def关键字形成的,后跟其名称和类似于任何其他模式节点的主体

:def reusable/
    anything_inside/

它通过在任意其他(相同或更深层)节点内添加:use标签来使用

reused_here/
    :use reusable

可以使用多个:use标签。属性按照以下顺序解析

example/
    ## Attributes set here win (before or after any :use lines)
    :owner root

    ## First :use is next in precedence
    :use one

    ## Subsequent :use lines take lower precedence
    :use two

依赖关系

~1.5MB
~27K SLoC