Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions cli/assets/fig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,49 @@ const completionSpec: Fig.Spec = {
},
],
},
{
name: "go",
description: "Generate Go parse tables from a usage spec",
options: [
{
name: ["-f", "--file"],
description:
'A usage spec taken in as a file, use "-" to read from stdin',
isRepeatable: false,
args: {
name: "file",
template: "filepaths",
},
},
{
name: ["-o", "--out-file"],
description:
'File path where the generated Go source will be saved, or "-" for stdout',
isRepeatable: false,
args: {
name: "out_file",
template: "filepaths",
},
},
{
name: ["-p", "--package"],
description:
"Go package clause for the generated file (defaults to the spec's bin name)",
isRepeatable: false,
args: {
name: "package",
},
},
{
name: "--spec",
description: "Raw string spec input",
isRepeatable: false,
args: {
name: "spec",
},
},
],
},
{
name: "json",
description: "Outputs a usage spec in json format",
Expand Down
26 changes: 26 additions & 0 deletions cli/assets/usage.1
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ Generate a shell init script that auto\-completes any usage shebang script on $P
\fBgenerate fig\fR
Generate Fig completion spec for Amazon Q / Fig
.TP
\fBgenerate go\fR
Generate Go parse tables from a usage spec
.TP
\fBgenerate json\fR
Outputs a usage spec in json format
.TP
Expand Down Expand Up @@ -265,6 +268,29 @@ File path where the generated Fig spec will be saved, or "\-" for stdout
.TP
\fB\-\-spec\fR \fI<SPEC>\fR
Raw string spec input
.SH "USAGE GENERATE GO"
Generate Go parse tables from a usage spec

The tables are read by github.com/jdx/usage/go/argv. Go has no macros, so what a Rust CLI gets from a derive at compile time, a Go CLI gets from this at build time — typically from a `go:generate` line:

//go:generate usage generate go \-f mycli.usage.kdl \-o tables.go
.PP
\fBUsage:\fR usage generate go [OPTIONS]
.PP
\fBOptions:\fR
.PP
.TP
\fB\-f, \-\-file\fR \fI<FILE>\fR
A usage spec taken in as a file, use "\-" to read from stdin
.TP
\fB\-o, \-\-out\-file\fR \fI<OUT_FILE>\fR
File path where the generated Go source will be saved, or "\-" for stdout
.TP
\fB\-p, \-\-package\fR \fI<PACKAGE>\fR
Go package clause for the generated file (defaults to the spec's bin name)
.TP
\fB\-\-spec\fR \fI<SPEC>\fR
Raw string spec input
.SH "USAGE GENERATE JSON"
Outputs a usage spec in json format
.PP
Expand Down
62 changes: 62 additions & 0 deletions cli/src/cli/generate/go.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use std::path::PathBuf;

use clap::Args;
use miette::Result;
use usage::go::GoOptions;

use crate::cli::generate;

/// Generate Go parse tables from a usage spec
///
/// The tables are read by github.com/jdx/usage/go/argv. Go has no macros, so what
/// a Rust CLI gets from a derive at compile time, a Go CLI gets from this at build
/// time — typically from a `go:generate` line:
///
/// //go:generate usage generate go -f mycli.usage.kdl -o tables.go
#[derive(Args)]
#[clap()]
pub struct Go {
/// A usage spec taken in as a file, use "-" to read from stdin
#[clap(short, long)]
file: Option<PathBuf>,

/// File path where the generated Go source will be saved, or "-" for stdout
#[clap(short, long, value_hint = clap::ValueHint::FilePath)]
out_file: Option<PathBuf>,

/// Go package clause for the generated file (defaults to the spec's bin name)
#[clap(short, long)]
package: Option<String>,

/// Raw string spec input
#[clap(long, required_unless_present = "file", overrides_with = "file")]
spec: Option<String>,
}

impl Go {
pub fn run(&self) -> Result<()> {
// Checked here rather than sanitized, because this one came from a person:
// quietly turning `--package my-pkg` into `mypkg` is a surprise waiting in
// somebody's build script, and the file would not compile if it were not
// sanitized at all.
if let Some(package) = &self.package {
if !usage::go::is_valid_package(package) {
miette::bail!(
"`--package {package}` is not a Go package name. It must be \
letters, digits and underscores, not start with a digit, and \
not be one of Go's keywords."
);
}
}

let spec = generate::file_or_spec(&self.file, &self.spec)?;
let out = usage::go::generate(
&spec,
&GoOptions {
package: self.package.clone(),
},
);
generate::write_or_stdout(self.out_file.as_deref(), &out)?;
Ok(())
}
}
3 changes: 3 additions & 0 deletions cli/src/cli/generate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use usage::Spec;
mod completion;
mod completion_init;
mod fig;
mod go;
mod json;
mod json_schema;
mod manpage;
Expand All @@ -26,6 +27,7 @@ pub enum Command {
Completion(completion::Completion),
CompletionInit(completion_init::CompletionInit),
Fig(fig::Fig),
Go(go::Go),
Json(json::Json),
JsonSchema(json_schema::JsonSchema),
Manpage(manpage::Manpage),
Expand All @@ -39,6 +41,7 @@ impl Generate {
Command::Completion(cmd) => cmd.run(),
Command::CompletionInit(cmd) => cmd.run(),
Command::Fig(cmd) => cmd.run(),
Command::Go(cmd) => cmd.run(),
Command::Json(cmd) => cmd.run(),
Command::JsonSchema(cmd) => cmd.run(),
Command::Manpage(cmd) => cmd.run(),
Expand Down
2 changes: 2 additions & 0 deletions cli/src/command_effects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const EFFECTS: &[(&str, SpecCommandEffect)] = &[
("generate completion", Read),
("generate completion-init", Read),
("generate fig", Read),
("generate go", Read),
("generate json", Read),
("generate json-schema", Read),
("generate manpage", Read),
Expand All @@ -48,6 +49,7 @@ const EFFECTS: &[(&str, SpecCommandEffect)] = &[
/// All of these redirect output that would otherwise go to stdout.
const FLAG_EFFECTS: &[(&str, &str, SpecCommandEffect)] = &[
("generate fig", "out-file", Write),
("generate go", "out-file", Write),
("generate json-schema", "out-file", Write),
("generate manpage", "out-file", Write),
("generate markdown", "out-dir", Write),
Expand Down
21 changes: 21 additions & 0 deletions cli/usage.usage.kdl
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,27 @@ You may need to set this if you have a different bin named "usage"
arg <SPEC>
}
}
cmd go help="Generate Go parse tables from a usage spec" effect=read unknown_flags=error {
long_help #"""
Generate Go parse tables from a usage spec

The tables are read by github.com/jdx/usage/go/argv. Go has no macros, so what a Rust CLI gets from a derive at compile time, a Go CLI gets from this at build time — typically from a `go:generate` line:

//go:generate usage generate go -f mycli.usage.kdl -o tables.go
"""#
flag "-f --file" help="A usage spec taken in as a file, use \"-\" to read from stdin" {
arg <FILE>
}
flag "-o --out-file" help="File path where the generated Go source will be saved, or \"-\" for stdout" effect=write {
arg <OUT_FILE>
}
flag "-p --package" help="Go package clause for the generated file (defaults to the spec's bin name)" {
arg <PACKAGE>
}
flag --spec help="Raw string spec input" {
arg <SPEC>
}
}
cmd json help="Outputs a usage spec in json format" effect=read unknown_flags=error {
flag "-f --file" help="A usage spec taken in as a file, use \"-\" to read from stdin" {
arg <FILE>
Expand Down
87 changes: 87 additions & 0 deletions docs/cli/reference/commands.json
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,93 @@
"hidden_aliases": [],
"examples": []
},
"go": {
"full_cmd": ["generate", "go"],
"usage": "generate go [FLAGS]",
"subcommands": {},
"args": [],
"flags": [
{
"name": "file",
"usage": "-f --file <FILE>",
"help": "A usage spec taken in as a file, use \"-\" to read from stdin",
"help_first_line": "A usage spec taken in as a file, use \"-\" to read from stdin",
"short": ["f"],
"long": ["file"],
"hide": false,
"global": false,
"arg": {
"name": "FILE",
"usage": "<FILE>",
"required": true,
"double_dash": "Optional",
"hide": false
}
},
{
"name": "out-file",
"usage": "-o --out-file <OUT_FILE>",
"help": "File path where the generated Go source will be saved, or \"-\" for stdout",
"help_first_line": "File path where the generated Go source will be saved, or \"-\" for stdout",
"short": ["o"],
"long": ["out-file"],
"hide": false,
"global": false,
"arg": {
"name": "OUT_FILE",
"usage": "<OUT_FILE>",
"required": true,
"double_dash": "Optional",
"hide": false
},
"effect": "write"
},
{
"name": "package",
"usage": "-p --package <PACKAGE>",
"help": "Go package clause for the generated file (defaults to the spec's bin name)",
"help_first_line": "Go package clause for the generated file (defaults to the spec's bin name)",
"short": ["p"],
"long": ["package"],
"hide": false,
"global": false,
"arg": {
"name": "PACKAGE",
"usage": "<PACKAGE>",
"required": true,
"double_dash": "Optional",
"hide": false
}
},
{
"name": "spec",
"usage": "--spec <SPEC>",
"help": "Raw string spec input",
"help_first_line": "Raw string spec input",
"short": [],
"long": ["spec"],
"hide": false,
"global": false,
"arg": {
"name": "SPEC",
"usage": "<SPEC>",
"required": true,
"double_dash": "Optional",
"hide": false
}
}
],
"mounts": [],
"effect": "read",
"unknown_flags": "error",
"hide": false,
"help": "Generate Go parse tables from a usage spec",
"help_long": "Generate Go parse tables from a usage spec\n\nThe tables are read by github.com/jdx/usage/go/argv. Go has no macros, so what a Rust CLI gets from a derive at compile time, a Go CLI gets from this at build time — typically from a `go:generate` line:\n\n//go:generate usage generate go -f mycli.usage.kdl -o tables.go",
"name": "go",
"aliases": [],
"hidden_aliases": [],
"examples": []
},
"json": {
"full_cmd": ["generate", "json"],
"usage": "generate json [-f --file <FILE>] [--spec <SPEC>]",
Expand Down
1 change: 1 addition & 0 deletions docs/cli/reference/generate.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Generate completions, documentation, and other artifacts from usage specs
- [`usage generate completion [FLAGS] <SHELL> <BIN>`](/cli/reference/generate/completion.md)
- [`usage generate completion-init [--usage-bin <USAGE_BIN>] <SHELL>`](/cli/reference/generate/completion-init.md)
- [`usage generate fig [FLAGS]`](/cli/reference/generate/fig.md)
- [`usage generate go [FLAGS]`](/cli/reference/generate/go.md)
- [`usage generate json [-f --file <FILE>] [--spec <SPEC>]`](/cli/reference/generate/json.md)
- [`usage generate json-schema [FLAGS]`](/cli/reference/generate/json-schema.md)
- [`usage generate manpage <FLAGS>`](/cli/reference/generate/manpage.md)
Expand Down
33 changes: 33 additions & 0 deletions docs/cli/reference/generate/go.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<!-- @generated by usage-cli from usage spec -->

# `usage generate go`

- **Usage**: `usage generate go [FLAGS]`
- **Effect**: read-only
- **Source code**: [`cli/src/cli/generate/go.rs`](https://github.com/jdx/usage/blob/main/cli/src/cli/generate/go.rs)

Generate Go parse tables from a usage spec

The tables are read by github.com/jdx/usage/go/argv. Go has no macros, so what a Rust CLI gets from a derive at compile time, a Go CLI gets from this at build time — typically from a `go:generate` line:

//go:generate usage generate go -f mycli.usage.kdl -o tables.go

## Flags

### `-f --file <FILE>`

A usage spec taken in as a file, use "-" to read from stdin

### `-o --out-file <OUT_FILE>`

**Effect**: modifies state

File path where the generated Go source will be saved, or "-" for stdout

### `-p --package <PACKAGE>`

Go package clause for the generated file (defaults to the spec's bin name)

### `--spec <SPEC>`

Raw string spec input
1 change: 1 addition & 0 deletions docs/cli/reference/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Outputs a `usage.kdl` spec for this CLI itself
- [`usage generate completion [FLAGS] <SHELL> <BIN>`](/cli/reference/generate/completion.md)
- [`usage generate completion-init [--usage-bin <USAGE_BIN>] <SHELL>`](/cli/reference/generate/completion-init.md)
- [`usage generate fig [FLAGS]`](/cli/reference/generate/fig.md)
- [`usage generate go [FLAGS]`](/cli/reference/generate/go.md)
- [`usage generate json [-f --file <FILE>] [--spec <SPEC>]`](/cli/reference/generate/json.md)
- [`usage generate json-schema [FLAGS]`](/cli/reference/generate/json-schema.md)
- [`usage generate manpage <FLAGS>`](/cli/reference/generate/manpage.md)
Expand Down
Loading
Loading