#flags #gflags #struct-fields #cli #arg #argument

gflags-derive

从结构体字段派生 gflags 调用

1 个不稳定版本

0.1.0 2020 年 5 月 2 日

#848命令行界面

Download history 266/week @ 2024-03-11 243/week @ 2024-03-18 180/week @ 2024-03-25 178/week @ 2024-04-01 278/week @ 2024-04-08 225/week @ 2024-04-15 550/week @ 2024-04-22 332/week @ 2024-04-29 142/week @ 2024-05-06 18/week @ 2024-05-13 112/week @ 2024-05-20 23/week @ 2024-05-27 19/week @ 2024-06-03 50/week @ 2024-06-10 35/week @ 2024-06-17 34/week @ 2024-06-24

每月 141 次下载

MIT/Apache

36KB
370

gflags-derive

使用 gflagsstruct 字段派生命令行参数。

这是 gflags 手册中“定义标志”部分的替代方案。

定义标志

创建一个结构体来包含您库或二进制的配置数据。

例如,这个假设的日志库定义了两个配置选项。

struct Config {
    /// True if log messages should also be sent to STDERR
    to_stderr: bool,

    /// The directory to write log files to
    dir: String,
}

通过在结构体上派生 gflags_derive::Gflags 将标志添加到注册表中。

use gflags_derive::GFlags;

#[derive(GFlags)]
struct Config {
    /// True if log messages should also be sent to STDERR
    to_stderr: bool,

    /// The directory to write log files to
    dir: String,
}

现在您有两个新的标志,就像您已经写了一样

gflags::define! {
    /// True if log messages should also be sent to STDERR
    --to_stderr: bool
}

gflags::define! {
    /// The directory to write log files to
    --dir: &str
}

注意:

  • 每个结构体字段的注释也是标志的文档注释,它成为其帮助文本。
  • --dir 标志的类型已从 String 转换为 &str

定义标志前缀

您可能希望所有标志名称都有相同的前缀,而无需在字段名称中使用该前缀。例如,日志模块可能希望所有标志都从 log-log_ 开始。

为此,请使用结构体上的 #[gflags(prefix = "...")] 属性。

use gflags_derive::GFlags;

#[derive(GFlags)]
#[gflags(prefix = "log_")]
struct Config {
    /// True if log messages should also be sent to STDERR
    to_stderr: bool,

    /// The directory to write log files to
    dir: String,
}

现在标志定义包含前缀,就像您已经写了一样

gflags::define! {
    /// True if log messages should also be sent to STDERR
    --log_to_stderr: bool
}

gflags::define! {
    /// The directory to write log files to
    --log_dir: &str
}

如果标志前缀以 - 结尾,则宏将标志名称转换为 kebab-case 而不是 snake_case。因此,编写

use gflags_derive::GFlags;

#[derive(GFlags)]
#[gflags(prefix = "log-")]
struct Config {
    /// True if log messages should also be sent to STDERR
    to_stderr: bool,

    /// The directory to write log files to
    dir: String,
}

生成以下标志

gflags::define! {
    /// True if log messages should also be sent to STDERR
    --log-to-stderr: bool
}

gflags::define! {
    /// The directory to write log files to
    --log-dir: &str
}

处理 Option<T>

您的配置 struct 可能包含具有 Option<T> 类型的字段。对于这些字段,gflags_derive 会创建一个内部类型 T 的标志。

自定义默认值

要为标志指定默认值,请向字段添加一个 #[gflags(default = ...)] 属性。

该属性的值是字面值,而不是引用值。只有当字段的类型是字符串或可以从字符串创建时才引用值。

例如,要将 --log-to-stderr 标志的默认值设置为 true

use gflags_derive::GFlags;

#[derive(GFlags)]
#[gflags(prefix = "log-")]
struct Config {
    /// True if log messages should also be sent to STDERR
    #[gflags(default = true)]
    to_stderr: bool,

    /// The directory to write log files to
    dir: String,
}

使用引号指定,#[gflags(default = "true")] 将导致编译时错误

expected `bool`, found `&str`

重要:这不会改变创建 Config 结构体实例时的默认值。它只改变 LOG_TO_STDERR.flag 变量的默认值。

自定义类型

要使用不同类型的字段和命令行标志,请向字段添加一个 #[gflags(type = "...")] 属性。例如,要将日志目录存储为 PathBuf,但在命令行上接受字符串

use gflags_derive::GFlags;
use std::path::PathBuf;

#[derive(GFlags)]
#[gflags(prefix = "log-")]
struct Config {
    /// True if log messages should also be sent to STDERR
    to_stderr: bool,

    /// The directory to write log files to
    #[gflags(type = "&str")]
    dir: PathBuf,
}

自定义可见性

要为标志使用不同的可见性,请向字段添加一个 #[gflags(visibility = "...")] 属性,并给出 Rust 可见性指定符。

在此示例中,LOG_DIR 标志变量将在父模块中可见。

use gflags_derive::GFlags;
use std::path::PathBuf;

#[derive(GFlags)]
#[gflags(prefix = "log-")]
struct Config {
    /// True if log messages should also be sent to STDERR
    to_stderr: bool,

    /// The directory to write log files to
    #[gflags(visibility = "pub(super)")]
    #[gflags(type = "&str")]
    dir: PathBuf,
}

指定占位符

为了在标志的 help 输出中显示占位符,请将该字段添加一个 #[gflags(placeholder = "...")] 属性。这将用 <...> 包裹以供显示。

use gflags_derive::GFlags;
use std::path::PathBuf;

#[derive(GFlags)]
#[gflags(prefix = "log-")]
struct Config {
    /// True if log messages should also be sent to STDERR
    to_stderr: bool,

    /// The directory to write log files to
    #[gflags(placeholder = "DIR")]
    #[gflags(type = "&str")]
    dir: PathBuf,
}

在帮助输出中,--log-dir 标志将显示为

--log-dir <DIR>
        The directory to write log files to

跳过标志

要跳过一个字段的标志生成,请将该字段添加一个 #[gflags(skip)] 属性。

use gflags_derive::GFlags;
use std::path::PathBuf;

#[derive(GFlags)]
#[gflags(prefix = "log-")]
struct Config {
    /// True if log messages should also be sent to STDERR
    to_stderr: bool,

    /// The directory to write log files to
    #[gflags(skip)]
    dir: PathBuf,
}

不会生成 --log-dir 标志。

提供多个属性

如果您想在一个字段上提供多个属性,则可以在单个 #[gflags(...)] 属性中指定多个选项,或者指定多个 #[gflags(...)] 属性。以下示例是相同的。

...
    /// The directory to write log files to
    #[gflags(type = "&str", visibility = "pub(super)")]
    dir: PathBuf,
...
...
    /// The directory to write log files to
    #[gflags(type = "&str")]
    #[gflags(visibility = "pub(super)")]
    dir: PathBuf,
...

反序列化和合并标志

这支持了一种强大的模式,用于配置由多个crate组成的应用程序,其中每个crate导出一个配置并支持多个标志,而应用程序crate定义了一个配置,该配置导入了组件crate中的配置结构体。

此主配置可以从例如JSON文件中反序列化,然后每个组件crate都有机会使用特定于该crate的命令行标志中的信息覆盖加载的配置。

有关实现此功能的完整应用程序,请参阅 examples/json 目录。

prost 一起使用

此宏可用于从使用 prostprost-build 生成的Protobuffer模式生成的 structs 提取标志。

给定此 .proto 文件

syntax = "proto3"

package log.config.v1;

message Config {
    // True if log messages should also be sent to STDERR
    bool to_stderr = 1;

    // The directory to write log files to
    string dir = 2;
}

build.rs 文件将添加相关属性,添加 log- 前缀并跳过 dir 字段。

fn main() {
    let mut config = prost_build::Config::new();

    config.type_attribute(".log.config.v1.Config", "#[derive(gflags_derive::GFlags)]");
    config.type_attribute(".log.config.v1.Config", "#[gflags(prefix=\"log-\")]");

    config.field_attribute(".log.config.v1.Config.dir", "#[gflags(skip)]");

    config
        .compile_protos(&["proto/log/config/v1/config.proto"], &["proto"])
        .unwrap();
}

有关实现此功能的完整应用程序,请参阅 examples/protobuf 目录。

许可:MIT OR Apache-2.0

依赖项

~1.5MB
~37K SLoC