20 个版本 (10 个重大更新)
0.11.4 | 2023 年 10 月 15 日 |
---|---|
0.11.3 | 2023 年 1 月 8 日 |
0.11.2 | 2022 年 5 月 26 日 |
0.11.1 | 2022 年 2 月 15 日 |
0.5.0 | 2019 年 7 月 29 日 |
#34 in 构建工具
每月下载量 193
49KB
738 行
mask
是一个 CLI 任务运行器,它由一个简单的 Markdown 文件定义。它在当前目录中搜索 maskfile.md
,然后解析其中的命令和参数。
maskfile.md
既是 可读文档,也是 命令定义!专注于文档使其他人可以简单地通过阅读您的 maskfile.md
来轻松开始您的项目开发设置。使用 Markdown 的一个优点是,许多编辑器和渲染器(如 GitHub 本身)内置了代码块的高亮显示。
这是 maskfile.md,它是 mask
自身使用的示例!
要开始,请按照以下指南操作或查看 mask
的更多 高级功能,例如 位置参数、可选标志、子命令、其他 脚本运行时 等。
安装
预编译的二进制文件
前往 发布页面,查找最新发布的版本。在 资产 下,您将看到可用于下载的 Linux、macOS 和 Windows 的压缩文件。下载完成后,您可以将它们解压缩,然后将 mask
二进制文件移动到您的 $PATH
中可访问的位置,例如 mv mask /usr/local/bin
。
Homebrew
mask
在 Homebrew 中可用,您可以通过以下命令安装它:brew install mask
。
Cargo
mask
已发布到 crates.io,您可以通过以下命令安装它:cargo install mask
。
从源码构建
如果您更喜欢从源码构建,请克隆此仓库,然后运行以下命令:cargo build --release
入门指南
首先,在您的项目中定义一个简单的 maskfile.md
文件。
# Tasks For My Project
<!-- A heading defines the command's name -->
## build
<!-- A blockquote defines the command's description -->
> Builds my project
<!-- A code block defines the script to be executed -->
~~~sh
echo "building project..."
~~~
## test
> Tests my project
You can also write documentation anywhere you want. Only certain types of markdown patterns
are parsed to determine the command structure.
This code block below is defined as js which means it will be ran with node. Mask also
supports other scripting runtimes including python, ruby and php!
~~~js
console.log("running tests...")
~~~
然后,尝试运行您的某个命令!
mask build
mask test
功能
位置参数
这些在命令名称旁边定义在 (round_brackets)
中。它们是必须提供的参数,以便命令可以运行。即将推出 可选参数。参数名称被注入到脚本的范围内作为环境变量。
示例
## test (file) (test_case)
> Run tests
~~~bash
echo "Testing $test_case in $file"
~~~
命名标志
您可以为您的命令定义一组命名标志。标志名称被注入到脚本的范围内作为环境变量。
示例
## serve
> Serve this directory
<!-- You must define OPTIONS right before your list of flags -->
**OPTIONS**
* port
* flags: -p --port
* type: string
* desc: Which port to serve on
~~~sh
PORT=${port:-8080} # Set a fallback port if not supplied
if [[ "$verbose" == "true" ]]; then
echo "Starting an http server on PORT: $PORT"
fi
python -m SimpleHTTPServer $PORT
~~~
您还可以通过将标志的 type
设置为 number
来使标志期望一个数值。这意味着 mask
将自动为您验证它。如果验证失败,mask
将退出并显示有用的错误信息。
示例
## purchase (price)
> Calculate the total price of something.
**OPTIONS**
* tax
* flags: -t --tax
* type: number
* desc: What's the tax?
~~~sh
TAX=${tax:-1} # Fallback to 1 if not supplied
echo "Total: $(($price * $TAX))"
~~~
如果您省略了 type
字段,mask
将将其视为一个 boolean
标志。如果传递了标志,其环境变量将为 "true"
,否则它将未设置/不存在。
值得注意的是,mask
自动注入一个非常常见的 boolean
标志,名为 verbose
,到每个命令中,即使它未被使用,这也为您节省了一些打字时间。这意味着每个命令都隐式具有一个 -v
和 --verbose
标志。
示例
## test
> Run the test suite
**OPTIONS**
* watch
* flags: -w --watch
* desc: Run tests on file change
~~~bash
[[ "$watch" == "true" ]] && echo "Starting in watch mode..."
[[ "$verbose" == "true" ]] && echo "Running with extra logs..."
~~~
默认情况下,标志是可选的。如果您在标志定义中添加 required
,如果用户没有提供标志,mask
将会报错。
示例
## ping
**OPTIONS**
* domain
* flags: -d --domain
* type: string
* desc: Which domain to ping
* required
~~~sh
ping $domain
~~~
子命令
可以通过简单的Markdown标题级别定义嵌套命令结构。H2 (##
) 是您定义顶级命令的地方。之后的每个级别都是一个子命令。
示例
## services
> Commands related to starting and stopping services
### services start (service_name)
> Start a service.
~~~bash
echo "Starting service $service_name"
~~~
### services stop (service_name)
> Stop a service.
~~~bash
echo "Stopping service $service_name"
~~~
您可能已经注意到,start
和 stop
命令前面都带有它们的父命令 services
的前缀。在某些情况下,用父命令前缀子命令可能有助于可读性,但这完全是可选的。下面的例子与上面的例子相同,但没有使用前缀。
示例
## services
> Commands related to starting and stopping services
### start (service_name)
> Start a service.
~~~bash
echo "Starting service $service_name"
~~~
### stop (service_name)
> Stop a service.
~~~bash
echo "Stopping service $service_name"
~~~
支持其他脚本运行时
除了shell/bash脚本之外,mask
还支持使用node、python、ruby和php作为脚本运行环境。这为您提供了选择合适工具来完成特定任务的能力。例如,假设您有一个serve
命令和一个snapshot
命令。您可以选择python来serve
一个简单的目录,也许使用node来运行一个puppeteer脚本,生成每个页面的pngsnapshot
。
示例
## shell (name)
> An example shell script
Valid lang codes: sh, bash, zsh, fish... any shell that supports -c
~~~zsh
echo "Hello, $name!"
~~~
## node (name)
> An example node script
Valid lang codes: js, javascript
~~~js
const { name } = process.env;
console.log(`Hello, ${name}!`);
~~~
## python (name)
> An example python script
Valid lang codes: py, python
~~~python
import os
name = os.getenv("name", "WORLD")
print("Hello, " + name + "!")
~~~
## ruby (name)
> An example ruby script
Valid lang codes: rb, ruby
~~~ruby
name = ENV["name"] || "WORLD"
puts "Hello, #{name}!"
~~~
## php (name)
> An example php script
~~~php
$name = getenv("name") ?: "WORLD";
echo "Hello, " . $name . "!\n";
~~~
Windows支持
您甚至可以在Linux/macOS代码块旁边添加powershell或批处理代码块。根据运行的平台,将执行正确的代码块。
示例
## link
> Build and link the binary globally
~~~bash
cargo install --force --path .
~~~
~~~powershell
[Diagnostics.Process]::Start("cargo", "install --force --path .").WaitForExit()
~~~
自动帮助和用法输出
您不必花费时间手动编写帮助信息。mask
使用您的命令描述和选项自动生成帮助输出。对于每个命令,它都会添加-h, --help
标志和一个备选的help <name>
命令。
示例
mask services start -h
mask services start --help
mask services help start
mask help services start
所有输出相同帮助信息
mask-services-start
Start or restart a service.
USAGE:
mask services start [FLAGS] <service_name>
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
-v, --verbose Sets the level of verbosity
-r, --restart Restart this service if it's already running
-w, --watch Restart a service on file change
ARGS:
<service_name>
在脚本中运行mask
如果您需要将命令连接起来,可以轻松地在脚本中调用mask
。但是,如果您打算使用不同的maskfile运行mask,应考虑使用$MASK
实用程序,这允许您的脚本不受位置限制。
示例
## bootstrap
> Installs deps, builds, links, migrates the db and then starts the app
~~~sh
mask install
mask build
mask link
# $MASK also works. It's an alias variable for `mask --maskfile <path_to_maskfile>`
# which guarantees your scripts will still work even if they are called from
# another directory.
$MASK db migrate
$MASK start
~~~
继承脚本的退出代码
如果您的命令以错误退出,mask
将以其状态码退出。这允许您连接命令,这些命令将在第一个错误时退出。
示例
## ci
> Runs tests and checks for lint and formatting errors
~~~sh
mask test \
&& mask lint \
&& mask format --check
~~~
使用不同的maskfile运行mask
如果您在一个没有maskfile.md
的目录中,但您想参考其他地方的文件,可以使用--maskfile <path_to_maskfile>
选项。
示例
mask --maskfile ~/maskfile.md <subcommand>
提示: 创建一个bash别名,以便您可以在任何地方轻松调用它
# Call it something fun
alias wask="mask --maskfile ~/maskfile.md"
# You can run this from anywhere
wask <subcommand>
环境变量实用工具
在每个脚本的执行环境中,mask
会注入一些有用的环境变量助手。
$MASK
当在脚本中运行mask时,这很有用。该变量允许我们通过在脚本中调用$MASK command
来代替mask --maskfile <path> command
,从而使它们不受位置限制(不关心它们是从哪里被调用的)。这对于您可能从任何地方调用的全局maskfile特别有用。
$MASKFILE_DIR
该变量是maskfile父目录的绝对路径。拥有父目录允许我们相对于maskfile本身加载文件,这在您有依赖于其他外部文件的命令时可能很有用。
文档部分
如果标题没有代码块,它将被视为文档并完全忽略。
示例
## This is a heading with no script
It's useful as a place to document things like a setup guide or required dependencies
or tools that your commands may rely on.
用例
以下是一些mask
可能很有用的示例场景。
项目特定任务
您有一个包含大量随机构建和开发脚本或难以管理的Makefile
的项目。您希望通过一个单一、易于阅读的文件简化流程,以便团队成员添加和修改现有任务。
全局系统实用工具
您需要一个适用于各种系统任务的全局实用CLI,例如备份目录或重命名文件。通过为 mask --maskfile ~/my-global-maskfile.md
创建bash别名,这很容易实现。
常见问题解答
mask
作为库可用吗?
存在一个名为 mask-parser 的crate,但它尚未文档化,也不算稳定。
灵感来自哪里?
我肯定不是第一个想到使用markdown作为CLI结构定义的人。
我对 make
语法的不满驱使我寻找其他选项。我一度转向了 just,这是一个相当不错的改进。我最喜欢的 just
功能是其对其他语言运行时的支持,这也是为什么 mask
也具备这种能力!然而,它仍然缺少一些我想拥有的功能,比如嵌套子命令和多个可选标志。
在搜索的过程中,我遇到了 maid,这是 mask
大部分灵感的来源。我认为将markdown用作命令定义格式同时又非常易读是一个绝妙的想法。
那么,为什么我选择重新造轮子而不是使用 maid
呢?一方面,我更喜欢安装一个单独的二进制文件,就像 just
一样,而不是安装一个包含数百个依赖项的npm包。我还有一些建议可以改进 maid
,这就是为什么 mask
支持多级嵌套子命令以及可选标志和位置参数。此外...我真的很想用Rust再建一个东西 :)
我还要提到 clap 和 pulldown-cmark,它们实际上是 mask
的核心部分,使得它如此容易创建。
贡献
在创建问题或提交PR之前,请查看我们的 贡献指南 🙌
此外,请审查并遵守我们 行为准则 😊
作者
Jacob Deichert 及其贡献者。
依赖
~2–12MB
~98K SLoC