go_subcommand

package module
v0.0.20 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 18, 2026 License: BSD-3-Clause Imports: 20 Imported by: 0

README

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`
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.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var TemplatesFS embed.FS

Functions

func Format added in v0.0.18

func Format(dir string, inplace bool, paths []string, recursive bool) error

Format is a subcommand `gosubc format` formats the subcommand definitions Format updates the documentation comments for subcommands in the codebase to match the defined parameters and standard formatting.

Flags:

dir:        --dir         (default: ".")         The project root directory
inplace:    --inplace                            Modify files in place
paths:      --path        (default: nil)         Paths to search for subcommands (relative to dir)
recursive:  --recursive   (default: true)        Search recursively

func FormatSourceComments added in v0.0.15

func FormatSourceComments(dir string, paths []string, recursive bool) error

FormatSourceComments is a subcommand `gosubc format-source-comments` formats source comments to match gofmt style

Flags:

dir:        --dir         (default: ".")         The project root directory containing go.mod
paths:      --path        (default: nil)         Paths to search for subcommands (relative to dir)
recursive:  --recursive   (default: true)        Search recursively

func Generate

func Generate(dir string, manDir string, parserName string, paths []string, recursive bool) error

Generate is a subcommand `gosubc generate` generates the subcommand code

Flags:

dir:        --dir         (default: ".")         Project root directory containing go.mod
manDir:     --man-dir                            Directory to generate man pages in optional
parserName: --parser-name (default: "commentv1") Name of the parser to use
paths:      --path        (default: nil)         Paths to search for subcommands (relative to dir)
recursive:  --recursive   (default: true)        Search recursively

func GenerateWithFS added in v0.0.11

func GenerateWithFS(inputFS fs.FS, writer FileWriter, dir string, manDir string, parserName string, options *parsers.ParseOptions) error

GenerateWithFS generates code using provided FS and Writer

func Goreleaser added in v0.0.14

func Goreleaser(dir string, githubWorkflow bool, verificationWorkflow bool) error

Goreleaser is a subcommand `gosubc goreleaser`

Flags:

dir:                  --dir                         (default: ".")
githubWorkflow:       --go-releaser-github-workflow (default: false) Generate GitHub Actions release workflow
verificationWorkflow: --verification-workflow       (default: false) Generate verification workflow

func GoreleaserWithWriter added in v0.0.14

func GoreleaserWithWriter(writer FileWriter, dir string, githubWorkflow bool, verificationWorkflow bool) error

func HelpSyntax added in v0.0.19

func HelpSyntax() error

HelpSyntax is a subcommand `gosubc syntax` that prints the available forms of function comments

func List

func List(dir string, parserName string, paths []string, recursive bool) error

List is a subcommand `gosubc list` lists the subcommands

Flags:

dir:        --dir         (default: ".")         The project root directory containing go.mod
parserName: --parser-name (default: "commentv1") Name of the parser to use
paths:      --path        (default: nil)         Paths to search for subcommands (relative to dir)
recursive:  --recursive   (default: true)        Search recursively

func ParseTemplates added in v0.0.15

func ParseTemplates(fsys fs.FS) (*template.Template, error)

func Scan added in v0.0.18

func Scan(dir string, parserName string, paths []string, recursive bool) error

Scan is a subcommand `gosubc scan` lists all available subcommands and their flags Scan lists all available subcommands and their flags from the parsed codebase. It is useful for verifying the command structure and configuration.

Flags:

dir:        --dir         (default: ".")         The project root directory
parserName: --parser-name (default: "commentv1") Name of the parser to use
paths:      --path        (default: nil)         Paths to search for subcommands (relative to dir)
recursive:  --recursive   (default: true)        Search recursively

func Validate

func Validate(dir string, parserName string, paths []string, recursive bool) error

Validate is a subcommand `gosubc validate` validates the subcommand code

Flags:

dir:        --dir         (default: ".")         The project root directory containing go.mod
parserName: --parser-name (default: "commentv1") Name of the parser to use
paths:      --path        (default: nil)         Paths to search for subcommands (relative to dir)
recursive:  --recursive   (default: true)        Search recursively

Types

type FileWriter added in v0.0.11

type FileWriter interface {
	WriteFile(path string, content []byte, perm os.FileMode) error
	MkdirAll(path string, perm os.FileMode) error
}

FileWriter interface allows mocking file system writes

type OSFileWriter added in v0.0.11

type OSFileWriter struct{}

OSFileWriter implements FileWriter using os package

func (*OSFileWriter) MkdirAll added in v0.0.11

func (w *OSFileWriter) MkdirAll(path string, perm os.FileMode) error

func (*OSFileWriter) WriteFile added in v0.0.11

func (w *OSFileWriter) WriteFile(path string, content []byte, perm os.FileMode) error

Directories

Path Synopsis
cmd
gosubc command
returns module
examples
basic1 module
complex module
returns module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL