Skip to content

arran4/go-subcommand

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

499 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Go Subcommand

Go Subcommand generates subcommand code for command-line interfaces (CLIs) in Go from source code comments. By leveraging specially formatted code comments, it automatically generates a dependency-less subcommand system, allowing you to focus on your application's core logic instead of boilerplate code.

Status: Pre-v1. The API and generated code structure may change.

Key Features

  • Convention over Configuration: Define your CLI structure with simple, intuitive code comments.
  • Zero Dependencies: The generated code is self-contained and doesn't require any external libraries.
  • Automatic Code Generation: gosubc parses your Go files and generates a complete, ready-to-use CLI.
  • Parameter Auto-Mapping: Automatically maps CLI flags, positional arguments, and variadic arguments to function parameters.
  • Rich Syntax Support: Supports custom flag names, default values, and description overrides via comments.
  • Man Page Generation: Automatically generate Unix man pages for your CLI.

Installation

To install gosubc, use go install:

go install github.com/arran4/go-subcommand/cmd/gosubc@latest

Getting Started

1. Define Your Commands

Create a Go file and define a function that will serve as your command. Add a comment above the function in the format // FunctionName is a subcommand 'root-command sub-command...'.

Example main.go:

package main

import "fmt"

// PrintHelloWorld is a subcommand `my-app hello`
// This command prints "Hello, World!" to the console.
func PrintHelloWorld() {
    fmt.Println("Hello, World!")
}

2. Add a generate.go File

Create a file named generate.go in the same directory (package main). This robust version checks if gosubc is installed; if not, it uses go run to fetch and run it. This ensures it works for everyone without manual installation steps.

package main

//go:generate sh -c "command -v gosubc >/dev/null 2>&1 && gosubc generate || go run github.com/arran4/go-subcommand/cmd/gosubc generate"

3. Generate the CLI

Run go generate in your terminal:

go generate

This will create a cmd/my-app directory containing the generated CLI code.

4. Run Your New CLI

You can now run your newly generated CLI:

go run ./cmd/my-app hello

Output:

Hello, World!

Comment Syntax Guide

go-subcommand uses a specific comment syntax to configure your CLI.

Subcommand Definition

The primary directive defines where the command lives in the CLI hierarchy:

// FuncName is a subcommand `root-cmd parent child`

Subcommand Aliases

You can define aliases for a subcommand using the Aliases: or Alias: directive.

// MyFunc is a subcommand `app cmd`
// Aliases: c, command
func MyFunc() { ... }

You can also use an inline syntax:

// MyFunc is a subcommand `app cmd` (aka: c)
func MyFunc() { ... }

Description & Extended Help

  • Short Description: The text immediately following the subcommand definition (or prefixed with that or -- ) becomes the short description used in usage lists.
  • Extended Help: Any subsequent lines that do not look like parameter definitions are treated as extended help text, displayed when the user requests help for that specific command.
// MyFunc is a subcommand `app cmd` -- Does something cool
//
// This is the extended help text. It can span multiple lines
// and provide detailed usage examples or explanations.

Parameter Configuration

Function parameters are automatically mapped to CLI flags. You can customize them using comments. go-subcommand looks for configuration in three places, in this priority order (highest to lowest):

  1. Flags: Block: A dedicated block in the main function documentation.
  2. Inline Comments: Comments on the same line as the parameter definition.
  3. Preceding Comments: Comments on the line immediately before the parameter.

The Flags: Block

This is the cleanest way to define multiple parameters. It must be an indented block following a line containing just Flags:.

// MyFunc is a subcommand `app cmd`
//
// Flags:
//
//   username: --username -u (default: "guest") The user to greet
//   count:    --count -c    (default: 1)       Number of times
func MyFunc(username string, count int) { ... }

Syntax Reference

Inside a Flags: block or inline/preceding comments, you can use the following syntax tokens to configure a parameter:

  • Flags: -f, --flag. One or more flag aliases.
  • Default Value: default: value or default: "value".
  • Positional Argument: @N (e.g., @1, @2). Maps the Nth positional argument (1-based) to this parameter.
  • Variadic Arguments: min...max (e.g., 1...3) or .... Maps remaining arguments to a slice.
  • Description: Any remaining text is treated as the parameter description.

Supported Types

The following Go types are supported for function parameters:

  • string: (Default)
  • int: Parsed as an integer.
  • bool: Parsed as a boolean flag (no value required, e.g., --verbose).
  • time.Duration: Parsed using time.ParseDuration (e.g., 10s, 1h).
  • error: (Return value only) Your function can return an error, which will be propagated to the CLI exit code.

Advanced Usage

Positional Arguments

To accept positional arguments instead of flags, use the @N syntax.

// Greet is a subcommand `app greet`
//
// Flags:
//
//   name: @1 The name to greet
func Greet(name string) {
    fmt.Printf("Hello, %s!\n", name)
}

Usage: app greet John

Variadic Arguments

To accept a variable number of arguments, use a slice parameter and mark it with ....

// ProcessFiles is a subcommand `app process`
//
// Flags:
//
//   files: ... List of files to process
func ProcessFiles(files ...string) {
    for _, file := range files {
        fmt.Println("Processing", file)
    }
}

Usage: app process file1.txt file2.txt file3.txt

Custom Flags

You can define custom short and long flags.

// Serve is a subcommand `app serve`
//
// Flags:
//
//   port: -p --port (default: 8080) Port to listen on
func Serve(port int) { ... }

Nesting Commands

Nesting is implicit based on the command path string.

// Root command: `app`
// Child: `app users`
// Grandchild: `app users create`

// CreateUser is a subcommand `app users create`
func CreateUser(...) { ... }

// ListUsers is a subcommand `app users list`
func ListUsers(...) { ... }

Parent Flags (Inheritance)

Subcommands can inherit flags from their parent command without redeclaring the variable. This allows the child command to update the parent's state (like global verbosity or configuration).

Use the parent-flag: <param_name> directive.

// Parent is a subcommand `app parent`
// Flags:
//
//   verbose: -v --verbose
func Parent(verbose bool) { ... }

// Child is a subcommand `app parent child`
// parent-flag: verbose
func Child(verbose bool) {
    // verbose parameter here maps to Parent's verbose variable
}

Man Page Generation

To generate man pages, pass the --man-dir flag to gosubc.

gosubc generate --man-dir ./man

This will generate standard Unix man pages in the specified directory, using the descriptions and extended help text from your comments.

CLI Reference

gosubc generate

Generates the Go code for your CLI.

  • --dir <path>: Root directory containing go.mod. Defaults to current directory.
  • --man-dir <path>: Directory to write man pages to.

gosubc list

Lists all detected subcommands.

  • --dir <path>: Root directory.

gosubc validate

Validates subcommand definitions for errors or conflicts.

  • --dir <path>: Root directory.

gosubc goreleaser

Generates release configuration.

  • --dir <path>: Root directory containing go.mod. Defaults to current directory.
  • --go-releaser-github-workflow: Generate GitHub Action workflow for GoReleaser.

Contributing

Contributions are welcome! If you find a bug or have a feature request, please open an issue on our GitHub repository.

License

This project is licensed under the BSD 3-Clause License. See the LICENSE file for details.

About

Generates dependencyless go command line argument subcommand system

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors