Skip to main content

Simple CLI building tool and script management tool.

Project description

Dryads

Simple CLI building tool and script management tool.

  • 对标:
    • Simple CLI building tools: argparse, click and typer
    • Script management tool: Just

发心

在图形化(GUI)软件出现之前,计算机操作员使用的是命令行(CLI)软件。两种软件本质是将人的指令交给计算机。

学术的说,在 CLI 中,有 argument 参数,不带前缀,是字符串;flag 标志,通常以-开头,通常是可选的,相当于 bool 值;options 选项,通常以-或者--开头,通常后接参数。注意git add中的add并不属于此三者的任何一个,而是命令本身。

形象的说,命令、参数、标志和选项是人和计算机交流的语言。而围绕某一个事物的一系列修饰词中,将归纳汇总并依次连接,可形成树形结构,很多命令行工具的选项都是。

举个 🌰,网易的分布式存储系统下有对集群的运维工具curve-tool


有子命令,分别是bs(管理块存储集群)、completion()、fs(管理文件存储集群)、upgrade(升级)。

使用一个子命令继续看

还有子命令,可以理解为针对块存储集群的各种操作,比如check(检测)、create(创建资源)、delete(删除资源)、list(罗列资源)等等。

继续使用一个子命令继续看
还有子命令,对于“检测”这个动作,还能继续“修饰”,到底检测什么“事物”

继续使用一个子命令继续看
至此确实没有了,开始添加 flag 了

可以想象,将这里所有的子命令取出来,并通过前后关系作为 Parent 结点和 Child 结点,可以形成树形结构。

再举个 🌰,在完成CMU 15445 Lab过程中,需要较多命令,比如测试、格式化、打包等等。而每个动作还能细分,比如 Lab 分成多个 Project,每个 Project 又分成多个 Task。于是就出现了“测试 Project1 Task1 相关代码”这样的命令。同理,格式化和打包操作也类似。所以可形成如下树形结构(以 Json 表示)

{
    "test": {
        "p1": {
            "t1": ...,
            "t2": ...,
            ...
        },
        "p2": ...,
        ...
    },
    "format": ...,
    "submit": ...,
}

故本项目的使用场景呼之欲出

  • Simple CLI building tools: 如果命令行工具可以描述为嵌套的子命令,则该框架可以很简单的构建。
  • Script management tool: 如果围绕某个项目或者在工作流中有一系列的命令,可以用该框架管理使之维护在一个文件中。同时大量的命令几乎无法记忆(比如在 15445 中使用的命令),通过子命令的方式使记忆它们称为可能(子命令对应一个脚本)。同时,文件主体是一个 Python 文件,命令作为字符串嵌入其中,同样是脚本语言,Python 有较于 Bash 或者 Powershell 强的多的表意能力和跨平台性。

该工具以嵌入我的工作流中并极大的提高我的效率。

Install

  • 通过 PyPI:PyPI

    pip install dryads
    

    同时会下载命令ds,它会在当前路径递归向上寻找dryadsfile文件并使用 Python 解释器运行它。我们也建议每个项目下都有一个dryadsfile用来管理维护该项目需要命令,原因在Just Further Ramblings

Use

  • 命令ds,如上,它会在当前路径递归向上寻找dryadsfile文件并使用 Python 解释器运行它。

    • 编译器通常通过文件后缀名识别文件类型,但是dryadsfile并没有文件后缀,在 VSCode 中,可以在.vscode/settings.json中添加下面内容解决。
      "files.associations": {
          "dryadsfile": "python"
      },
      
  • 如果是在 Linux 系统,通过在脚本前添加 shebang

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    

    则可以通过./script.py这种很接近命令的形式使用

使用字符串表达脚本内容,而 Python 中“万物皆对象”,可以将函数本身作为值传递。使用dict数据类型即可描述出树形结构,将该dict交给框架,子命令的解析和执行交给框架即可。

下面是一个经典的例子。

# test/classic_example.py
from dryads import Dryads, DryadsContainer, DryadsFlag, run_shell_cmd

def create_python():
    run_shell_cmd(f"poetry new {DryadsContainer.DryadsArg}")

def create_rust():
    run_shell_cmd(f"cargo new {DryadsContainer.DryadsArg}")

CMDS = {
    "echo": {
        "English": "echo Hello World",
        "Chinese": "echo 我可以吞下玻璃而不受到伤害",
        "Math": ["echo 42", "echo 3.14"],
    },
    "work": {
        DryadsFlag.PrefixCmd: ["cd Project"],
        "build": "cd build && make -j`nproc`",
        "run": "./build/bin/work",
    },
    "create": {
        "python": [
            DryadsFlag.Anchoring,
            DryadsFlag.AcceptArg,
            create_python,
        ],
        "rust": [
            DryadsFlag.Anchoring,
            DryadsFlag.AcceptArg,
            create_rust,
        ],
    },
    ("-d", "--dryads"): "echo Hello Dryads",
}

Dryads(CMDS)

直接执行上文件输出如下

相当于

其中子命令env-h/--help是默认生成的

对于各级子命令,也能使用-h(或者--help)选项

下面聊聊语法

  • 以嵌套的dict数据结构描述树形结构

  • dict的键只能是str或者tuple[str]或者DryadsFlag(这是什么后面再聊)来描述子命令

  • 叶子节点以str/Callable/list[str | Callable | DryadsFlag]类型表示具体的要执行的脚本内容。

    • 每个str类型字面量作为一个 Shell 脚本一起交给 Shell 执行,即一个字符串可以是多行的,它们是连续的。

      • 如果在list[str]中有cd命令,列表中的其他字符串中的命令不会被影响。
  • 执行:一个命令的所有子命令相当于从根到叶子的路径

    • 叶子节点:

    • 中间节点:执行该节点子树中的所有叶子节点

  • 标记DryadsFlag,当希望改变某些默认的行为时,以标记的方式实现。其本身是枚举量,作为键或者叶子执行修改某种行为。

    • DryadsFlag.Anchoring: 作为叶子的值, 表示该叶子中的命令都是以执行脚本的路径开始, 默认从脚本所在的路径开始, 例子在Anchoring
    • DryadsFlag.InVisible: 作为叶子的值, 表示执行的脚本是否打印, 默认打印, 使用该标志表示不打印, 例子在InVisible
    • DryadsFlag.IgnoreErr: 作为叶子的值, 表示命令执行出错后是否停止, 默认停止, 使用该标志表示不停止, 例子在IgnoreErr
    • DryadsFlag.PrefixCmd: 作为某个节点的键, 其值对应的脚本为其所有兄弟节点的子树中所有脚本的前置脚本, 例子在PrefixCmd
      • 该标记只能用于dict不能用于list,但往往是对叶子节点list中的一系列命令设置前置脚本,可通过再套一层 dict 解决。
  • 参数: 将所有的子命令匹配之后的命令行参数, 即视为 dryads 的参数, 可以通过dryads.argv获取, 例子在MultiLineCmd

用户

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dryads-2.0.2.tar.gz (14.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dryads-2.0.2-py3-none-any.whl (13.9 kB view details)

Uploaded Python 3

File details

Details for the file dryads-2.0.2.tar.gz.

File metadata

  • Download URL: dryads-2.0.2.tar.gz
  • Upload date:
  • Size: 14.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.4

File hashes

Hashes for dryads-2.0.2.tar.gz
Algorithm Hash digest
SHA256 a4a6571f626514b3b69b90509f0c5695f9fc2d1eb1eea79ee884eb7dfd558ac2
MD5 cb0e5301b6e2fd64ecf1be317169da55
BLAKE2b-256 172ff9d9073e6781e3f627839ec61b4393fdf79bfc0db9303b2d80dbcd171768

See more details on using hashes here.

File details

Details for the file dryads-2.0.2-py3-none-any.whl.

File metadata

  • Download URL: dryads-2.0.2-py3-none-any.whl
  • Upload date:
  • Size: 13.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.4

File hashes

Hashes for dryads-2.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 88893610f29ce65dc6b3f3ea0074f3dc72286aa021daa7d3e543e000dadff740
MD5 b47437abff547bf9fa095df5e6e97b9f
BLAKE2b-256 cf58e0035bf182f28d1486414f1da40b6230c6b2b78e708c288436c24eb0327a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page