cmd/cue/cmd: update cmd documentation
Refer to --inject and remove redundant task section.
Change-Id: I13d993dce3eeb0213d94d53899d7aa01d9e589da
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/5540
Reviewed-by: Marcel van Lohuizen <mpvl@google.com>
diff --git a/cmd/cue/cmd/cmd.go b/cmd/cue/cmd/cmd.go
index 1d21973..fb31790 100644
--- a/cmd/cue/cmd/cmd.go
+++ b/cmd/cue/cmd/cmd.go
@@ -29,131 +29,36 @@
Short: "run a user-defined shell command",
Long: `cmd executes defined the named command for each of the named instances.
-Commands define actions on instances. For example, they may specify
-how to upload a configuration to Kubernetes. Commands are defined
-directly in tool files, which are regular CUE files within the same
-package with a filename ending in _tool.cue. These are typically
-defined at the top of the module root so that they apply to all
-instances.
+Commands define actions on instances. For example, they may
+specify how to upload a configuration to Kubernetes. Commands are
+defined directly in tool files, which are regular CUE files
+within the same package with a filename ending in _tool.cue.
+These are typically defined at the module root so that they apply
+to all instances.
-Each command consists of one or more tasks. A task may load or write
-a file, consult a user on the command line, fetch a web page, and
-so on. Each task has inputs and outputs. Outputs are typically are
-filled out by the task implementation as the task completes.
+Each command consists of one or more tasks. A task may, for
+example, load or write a file, consult a user on the command
+line, fetch a web page, and so on. Each task has inputs and
+outputs. Outputs are typically filled out by the task
+implementation as the task completes.
-Inputs of tasks my refer to outputs of other tasks. The cue tool does
-a static analysis of the configuration and only starts tasks that are
-fully specified. Upon completion of each task, cue rewrites the instance,
-filling in the completed task, and reevaluates which other tasks can
-now start, and so on until all tasks have completed.
-
-Commands are defined at the top-level of the configuration:
-
- command: [Name=string]: { // from tool.Command
- // usage gives a short usage pattern of the command.
- // Example:
- // fmt [-s] [inputs]
- usage?: Name | string
-
- // short gives a brief on-line description of the command.
- // Example:
- // reformat package sources
- short?: string
-
- // long gives a detailed description of the command, including a
- // description of flags usage and examples.
- long?: string
-
- // A task defines a single action to be run as part of this command.
- // Each task can have inputs and outputs, depending on the type
- // task. The outputs are initially unspecified, but are filled out
- // by the tooling
- task: [string]: { // from "tool".Task
- // supported fields depend on type
- }
-
- VarValue = string | bool | int | float | [...string|int|float]
-
- // var declares values that can be set by command line flags or
- // environment variables.
- //
- // Example:
- // // environment to run in
- // var env: "test" | "prod"
- // The tool would print documentation of this flag as:
- // Flags:
- // --env string environment to run in: test(default) or prod
- var: [string]: VarValue
-
- // flag defines a command line flag.
- //
- // Example:
- // var env: "test" | "prod"
- //
- // // augment the flag information for var
- // flag env: {
- // shortFlag: "e"
- // description: "environment to run in"
- // }
- //
- // The tool would print documentation of this flag as:
- // Flags:
- // -e, --env string environment to run in: test(default), staging, or prod
- //
- flag [Name=_]: { // from "tool".Flag
- // value defines the possible values for this flag.
- // The default is string. Users can define default values by
- // using disjunctions.
- value: *env[Name].value | VarValue
-
- // name, if set, allows var to be set with the command-line flag
- // of the given name. null disables the command line flag.
- name?: *Name | string
-
- // short defines an abbreviated version of the flag.
- // Disabled by default.
- short?: string
- }
-
- // populate flag with the default values for
- for k, v in var {
- flag: { "\(k)": { value: v } | null }
- }
-
- // env defines environment variables. It is populated with values
- // for var.
- //
- // To specify a var without an equivalent environment variable,
- // either specify it as a flag directly or disable the equally
- // named env entry explicitly:
- //
- // var foo: string
- // env foo: null // don't use environment variables for foo
- //
- env: [Name=_]: {
- // name defines the environment variable that sets this flag.
- name?: *"CUE_VAR_" + strings.Upper(Name) | string
-
- // The value retrieved from the environment variable or null
- // if not set.
- value?: string | bytes
- }
- env: {
- for k, v in var {
- "\(k)": { value: v } | null
- }
- }
- }
+Inputs of tasks my refer to outputs of other tasks. The cue tool
+does a static analysis of the configuration and only starts tasks
+that are fully specified. Upon completion of each task, cue
+rewrites the instance, filling in the completed task, and
+reevaluates which other tasks can now start, and so on until all
+tasks have completed.
Available tasks can be found in the package documentation at
- https://godoc.org/cuelang.org/go/pkg/tool
-
-More on tasks can be found in the tasks topic.
+ https://pkg.go.dev/cuelang.org/go/pkg/tool?tab=subdirectories
Examples:
-A simple file using command line execution:
+In this simple example, we define a command called "hello",
+which declares a single task called "print" which uses
+"tool/exec.Run" to execute a shell command that echos output to
+the terminal:
$ cat <<EOF > hello_tool.cue
package foo
@@ -161,60 +66,71 @@
import "tool/exec"
city: "Amsterdam"
+ who: *"World" | string @tag(who)
// Say hello!
command: hello: {
- // whom to say hello to
- var: who: *"World" | string
-
- task: print: exec.Run & {
- cmd: "echo Hello \(var.who)! Welcome to \(city)."
+ print: exec.Run & {
+ cmd: "echo Hello \(who)! Welcome to \(city)."
}
}
EOF
+We run the "hello" command like this:
+
$ cue cmd hello
Hello World! Welcome to Amsterdam.
- $ cue cmd hello -who you # Setting arguments is not supported yet by cue
- Hello you! Welcome to Amsterdam.
+ $ cue cmd --inject who=Jan hello
+ Hello Jan! Welcome to Amsterdam.
-An example using pipes:
+In this example we declare the "prompted" command which has four
+tasks. The first task prompts the user for a string input. The
+second task depends on the first, and echos the response back to
+the user with a friendly message. The third task pipes the output
+from the second to a file. The fourth task pipes the output from
+the second to standard output (i.e. it echos it again).
package foo
- import "tool/exec"
+ import (
+ "tool/cli"
+ "tool/exec"
+ "tool/file"
+ )
city: "Amsterdam"
// Say hello!
- command: hello: {
- var: file: "out.txt" | string // save transcript to this file
+ command: prompter: {
+ // save transcript to this file
+ var: file: *"out.txt" | string @tag(file)
- task: ask: cli.Ask & {
+ ask: cli.Ask & {
prompt: "What is your name?"
response: string
}
// starts after ask
- task: echo: exec.Run & {
- cmd: ["echo", "Hello", task.ask.response + "!"]
+ echo: exec.Run & {
+ cmd: ["echo", "Hello", ask.response + "!"]
stdout: string // capture stdout
}
// starts after echo
- task: write: file.Append & {
+ file.Append & {
filename: var.file
- contents: task.echo.stdout
+ contents: echo.stdout
}
// also starts after echo
- task: print: cli.Print & {
- contents: task.echo.stdout
+ print: cli.Print & {
+ contents: echo.stdout
}
}
+Run "cue help commands" for more details on tasks and commands.
`,
RunE: mkRunE(c, func(cmd *Command, args []string) error {
w := cmd.Stderr()
diff --git a/cmd/cue/cmd/help.go b/cmd/cue/cmd/help.go
index 68e4d21..5a8de6c 100644
--- a/cmd/cue/cmd/help.go
+++ b/cmd/cue/cmd/help.go
@@ -300,6 +300,165 @@
`,
}
+var commandsHelp = &cobra.Command{
+ Use: "commands",
+ Short: "user-defined commands",
+ Long: `Commands define actions on instances. For example, they may
+specify how to upload a configuration to Kubernetes. Commands are
+defined directly in tool files, which are regular CUE files
+within the same package with a filename ending in _tool.cue.
+These are typically defined at the module root so that they apply
+to all instances.
+
+Each command consists of one or more tasks. A task may, for
+example, load or write a file, consult a user on the command
+line, fetch a web page, and so on. Each task has inputs and
+outputs. Outputs are typically filled out by the task
+implementation as the task completes.
+
+Inputs of tasks my refer to outputs of other tasks. The cue tool
+does a static analysis of the configuration and only starts tasks
+that are fully specified. Upon completion of each task, cue
+rewrites the instance, filling in the completed task, and
+reevaluates which other tasks can now start, and so on until all
+tasks have completed.
+
+Available tasks can be found in the package documentation at
+
+ https://pkg.go.dev/cuelang.org/go/pkg/tool?tab=subdirectories
+
+More on tasks can be found in the commands help topic.
+
+Examples:
+
+In this simple example, we define a command called "hello",
+which declares a single task called "print" which uses
+"tool/exec.Run" to execute a shell command that echos output to
+the terminal:
+
+ $ cat <<EOF > hello_tool.cue
+ package foo
+
+ import "tool/exec"
+
+ city: "Amsterdam"
+ who: *"World" | string @tag(who)
+
+ // Say hello!
+ command: hello: {
+ print: exec.Run & {
+ cmd: "echo Hello \(who)! Welcome to \(city)."
+ }
+ }
+ EOF
+
+We run the "hello" command like this:
+
+ $ cue cmd hello
+ Hello World! Welcome to Amsterdam.
+
+ $ cue cmd --inject who=Jan hello
+ Hello Jan! Welcome to Amsterdam.
+
+
+In this example we declare the "prompted" command which has four
+tasks. The first task prompts the user for a string input. The
+second task depends on the first, and echos the response back to
+the user with a friendly message. The third task pipes the output
+from the second to a file. The fourth task pipes the output from
+the second to standard output (i.e. it echos it again).
+
+ package foo
+
+ import (
+ "tool/cli"
+ "tool/exec"
+ "tool/file"
+ )
+
+ city: "Amsterdam"
+
+ // Say hello!
+ command: prompter: {
+ // save transcript to this file
+ var: file: *"out.txt" | string @tag(file)
+
+ ask: cli.Ask & {
+ prompt: "What is your name?"
+ response: string
+ }
+
+ // starts after ask
+ echo: exec.Run & {
+ cmd: ["echo", "Hello", ask.response + "!"]
+ stdout: string // capture stdout
+ }
+
+ // starts after echo
+ file.Append & {
+ filename: var.file
+ contents: echo.stdout
+ }
+
+ // also starts after echo
+ print: cli.Print & {
+ contents: echo.stdout
+ }
+ }
+
+The types of the commands and tasks are defined in CUE itself at
+cuelang.org/go/pkg/tool/tool.cue.
+
+ command: [Name]: Command
+
+ Command :: {
+ // Tasks specifies the things to run to complete a command. Tasks are
+ // typically underspecified and completed by the particular internal
+ // handler that is running them. Tasks can be a single task, or a full
+ // hierarchy of tasks.
+ //
+ // Tasks that depend on the output of other tasks are run after such tasks.
+ // Use $after if a task needs to run after another task but does not
+ // otherwise depend on its output.
+ Tasks
+
+ //
+ // Example:
+ // mycmd [-n] names
+ $usage?: string
+
+ // short is short description of what the command does.
+ $short?: string
+
+ // long is a longer description that spans multiple lines and
+ // likely contain examples of usage of the command.
+ $long?: string
+ }
+
+ // Tasks defines a hierarchy of tasks. A command completes if all
+ // tasks have run to completion.
+ Tasks: Task | {
+ [name=Name]: Tasks
+ }
+
+ // Name defines a valid task or command name.
+ Name :: =~#"^\PL([-](\PL|\PN))*$"#
+
+ // A Task defines a step in the execution of a command.
+ Task: {
+ $type: "tool.Task" // legacy field 'kind' still supported for now.
+
+ // kind indicates the operation to run. It must be of the form
+ // packagePath.Operation.
+ $id: =~#"\."#
+
+ // $after can be used to specify a task is run after another one, when
+ // it does not otherwise refer to an output of that task.
+ $after?: Task | [...Task]
+ }
+`,
+}
+
// TODO: tags
// - doc/nodoc
// - attr/noattr
diff --git a/cmd/cue/cmd/testdata/script/help_cmd.txt b/cmd/cue/cmd/testdata/script/help_cmd.txt
index 3a2db1c..427164d 100644
--- a/cmd/cue/cmd/testdata/script/help_cmd.txt
+++ b/cmd/cue/cmd/testdata/script/help_cmd.txt
@@ -26,131 +26,36 @@
-- expect-stdout --
cmd executes defined the named command for each of the named instances.
-Commands define actions on instances. For example, they may specify
-how to upload a configuration to Kubernetes. Commands are defined
-directly in tool files, which are regular CUE files within the same
-package with a filename ending in _tool.cue. These are typically
-defined at the top of the module root so that they apply to all
-instances.
+Commands define actions on instances. For example, they may
+specify how to upload a configuration to Kubernetes. Commands are
+defined directly in tool files, which are regular CUE files
+within the same package with a filename ending in _tool.cue.
+These are typically defined at the module root so that they apply
+to all instances.
-Each command consists of one or more tasks. A task may load or write
-a file, consult a user on the command line, fetch a web page, and
-so on. Each task has inputs and outputs. Outputs are typically are
-filled out by the task implementation as the task completes.
+Each command consists of one or more tasks. A task may, for
+example, load or write a file, consult a user on the command
+line, fetch a web page, and so on. Each task has inputs and
+outputs. Outputs are typically filled out by the task
+implementation as the task completes.
-Inputs of tasks my refer to outputs of other tasks. The cue tool does
-a static analysis of the configuration and only starts tasks that are
-fully specified. Upon completion of each task, cue rewrites the instance,
-filling in the completed task, and reevaluates which other tasks can
-now start, and so on until all tasks have completed.
-
-Commands are defined at the top-level of the configuration:
-
- command: [Name=string]: { // from tool.Command
- // usage gives a short usage pattern of the command.
- // Example:
- // fmt [-s] [inputs]
- usage?: Name | string
-
- // short gives a brief on-line description of the command.
- // Example:
- // reformat package sources
- short?: string
-
- // long gives a detailed description of the command, including a
- // description of flags usage and examples.
- long?: string
-
- // A task defines a single action to be run as part of this command.
- // Each task can have inputs and outputs, depending on the type
- // task. The outputs are initially unspecified, but are filled out
- // by the tooling
- task: [string]: { // from "tool".Task
- // supported fields depend on type
- }
-
- VarValue = string | bool | int | float | [...string|int|float]
-
- // var declares values that can be set by command line flags or
- // environment variables.
- //
- // Example:
- // // environment to run in
- // var env: "test" | "prod"
- // The tool would print documentation of this flag as:
- // Flags:
- // --env string environment to run in: test(default) or prod
- var: [string]: VarValue
-
- // flag defines a command line flag.
- //
- // Example:
- // var env: "test" | "prod"
- //
- // // augment the flag information for var
- // flag env: {
- // shortFlag: "e"
- // description: "environment to run in"
- // }
- //
- // The tool would print documentation of this flag as:
- // Flags:
- // -e, --env string environment to run in: test(default), staging, or prod
- //
- flag [Name=_]: { // from "tool".Flag
- // value defines the possible values for this flag.
- // The default is string. Users can define default values by
- // using disjunctions.
- value: *env[Name].value | VarValue
-
- // name, if set, allows var to be set with the command-line flag
- // of the given name. null disables the command line flag.
- name?: *Name | string
-
- // short defines an abbreviated version of the flag.
- // Disabled by default.
- short?: string
- }
-
- // populate flag with the default values for
- for k, v in var {
- flag: { "\(k)": { value: v } | null }
- }
-
- // env defines environment variables. It is populated with values
- // for var.
- //
- // To specify a var without an equivalent environment variable,
- // either specify it as a flag directly or disable the equally
- // named env entry explicitly:
- //
- // var foo: string
- // env foo: null // don't use environment variables for foo
- //
- env: [Name=_]: {
- // name defines the environment variable that sets this flag.
- name?: *"CUE_VAR_" + strings.Upper(Name) | string
-
- // The value retrieved from the environment variable or null
- // if not set.
- value?: string | bytes
- }
- env: {
- for k, v in var {
- "\(k)": { value: v } | null
- }
- }
- }
+Inputs of tasks my refer to outputs of other tasks. The cue tool
+does a static analysis of the configuration and only starts tasks
+that are fully specified. Upon completion of each task, cue
+rewrites the instance, filling in the completed task, and
+reevaluates which other tasks can now start, and so on until all
+tasks have completed.
Available tasks can be found in the package documentation at
- https://godoc.org/cuelang.org/go/pkg/tool
-
-More on tasks can be found in the tasks topic.
+ https://pkg.go.dev/cuelang.org/go/pkg/tool?tab=subdirectories
Examples:
-A simple file using command line execution:
+In this simple example, we define a command called "hello",
+which declares a single task called "print" which uses
+"tool/exec.Run" to execute a shell command that echos output to
+the terminal:
$ cat <<EOF > hello_tool.cue
package foo
@@ -158,60 +63,72 @@
import "tool/exec"
city: "Amsterdam"
+ who: *"World" | string @tag(who)
// Say hello!
command: hello: {
- // whom to say hello to
- var: who: *"World" | string
-
- task: print: exec.Run & {
- cmd: "echo Hello \(var.who)! Welcome to \(city)."
+ print: exec.Run & {
+ cmd: "echo Hello \(who)! Welcome to \(city)."
}
}
EOF
+We run the "hello" command like this:
+
$ cue cmd hello
Hello World! Welcome to Amsterdam.
- $ cue cmd hello -who you # Setting arguments is not supported yet by cue
- Hello you! Welcome to Amsterdam.
+ $ cue cmd --inject who=Jan hello
+ Hello Jan! Welcome to Amsterdam.
-An example using pipes:
+In this example we declare the "prompted" command which has four
+tasks. The first task prompts the user for a string input. The
+second task depends on the first, and echos the response back to
+the user with a friendly message. The third task pipes the output
+from the second to a file. The fourth task pipes the output from
+the second to standard output (i.e. it echos it again).
package foo
- import "tool/exec"
+ import (
+ "tool/cli"
+ "tool/exec"
+ "tool/file"
+ )
city: "Amsterdam"
// Say hello!
- command: hello: {
- var: file: "out.txt" | string // save transcript to this file
+ command: prompter: {
+ // save transcript to this file
+ var: file: *"out.txt" | string @tag(file)
- task: ask: cli.Ask & {
+ ask: cli.Ask & {
prompt: "What is your name?"
response: string
}
// starts after ask
- task: echo: exec.Run & {
- cmd: ["echo", "Hello", task.ask.response + "!"]
+ echo: exec.Run & {
+ cmd: ["echo", "Hello", ask.response + "!"]
stdout: string // capture stdout
}
// starts after echo
- task: write: file.Append & {
+ file.Append & {
filename: var.file
- contents: task.echo.stdout
+ contents: echo.stdout
}
// also starts after echo
- task: print: cli.Print & {
- contents: task.echo.stdout
+ print: cli.Print & {
+ contents: echo.stdout
}
}
+Run "cue help commands" for more details on tasks and commands.
+
Usage:
cue cmd <name> [inputs] [flags]
cue cmd [command]
diff --git a/pkg/tool/tool.cue b/pkg/tool/tool.cue
index 87a1318..ed0bf2f 100644
--- a/pkg/tool/tool.cue
+++ b/pkg/tool/tool.cue
@@ -58,7 +58,7 @@
[name=Name]: Tasks
}
-// Name defines a valid task or command sname.
+// Name defines a valid task or command name.
Name :: =~#"^\PL([-](\PL|\PN))*$"#
// A Task defines a step in the execution of a command.