simple_cli

Cookbook

Recipes

  1. Simple Command-Line Tool
  2. Git-Style Subcommands
  3. File Processor
  4. Build Tool
  5. Server Application
  6. Data Converter
  7. Test Runner
  8. Deployment Tool

1. Simple Command-Line Tool

A basic tool with flags and one required option.

class GREP_TOOL

create
    make

feature

    make
        local
            cli: SIMPLE_CLI
        do
            create cli.make
            cli.set_app_info ("mygrep", "Search for patterns in files", "1.0.0")

            -- Flags
            cli.add_flag ("i|ignore-case", "Case-insensitive matching")
            cli.add_flag ("n|line-number", "Print line numbers")
            cli.add_flag ("c|count", "Only print match count")
            cli.add_flag ("r|recursive", "Search directories recursively")

            cli.parse

            if cli.help_requested then
                cli.print_help
            elseif cli.has_errors then
                cli.print_errors
            elseif cli.arguments.count < 2 then
                print ("Usage: mygrep [OPTIONS] PATTERN FILE...%N")
            else
                search (cli)
            end
        end

    search (cli: SIMPLE_CLI)
        local
            pattern: STRING
            ignore_case: BOOLEAN
            show_line_nums: BOOLEAN
        do
            if attached cli.command as p then
                pattern := p
            end

            ignore_case := cli.has_flag ("ignore-case")
            show_line_nums := cli.has_flag ("line-number")

            -- Search each file argument
            across cli.arguments_after_command as file_path loop
                search_file (pattern, file_path, ignore_case, show_line_nums)
            end
        end

    search_file (pattern, file_path: STRING; ignore_case, show_line_nums: BOOLEAN)
        do
            -- Implementation...
        end

end

Usage

# Basic search
mygrep "error" log.txt

# Case-insensitive with line numbers
mygrep -in "warning" src/*.e

# Recursive search
mygrep -r "TODO" src/

2. Git-Style Subcommands

Tool with multiple subcommands like git (init, add, commit).

class PACKAGE_MANAGER

create
    make

feature

    make
        local
            cli: SIMPLE_CLI
        do
            create cli.make
            cli.set_app_info ("pkg", "Simple package manager", "1.0.0")

            -- Global options
            cli.add_flag ("v|verbose", "Verbose output")
            cli.add_flag ("q|quiet", "Suppress output")

            cli.parse

            if cli.help_requested then
                print_main_help
            elseif attached cli.command as cmd then
                dispatch_command (cmd, cli)
            else
                print_main_help
            end
        end

feature {NONE} -- Commands

    dispatch_command (cmd: STRING; cli: SIMPLE_CLI)
        do
            if cmd.same_string ("install") then
                cmd_install (cli)
            elseif cmd.same_string ("remove") then
                cmd_remove (cli)
            elseif cmd.same_string ("update") then
                cmd_update (cli)
            elseif cmd.same_string ("list") then
                cmd_list (cli)
            else
                print ("Unknown command: " + cmd + "%N")
            end
        end

    cmd_install (cli: SIMPLE_CLI)
        do
            across cli.arguments_after_command as pkg loop
                if cli.has_flag ("verbose") then
                    print ("Installing " + pkg + "...%N")
                end
                -- Install package...
            end
        end

    cmd_remove (cli: SIMPLE_CLI)
        do
            -- Remove packages...
        end

    cmd_update (cli: SIMPLE_CLI)
        do
            print ("Updating package index...%N")
        end

    cmd_list (cli: SIMPLE_CLI)
        do
            print ("Installed packages:%N")
            -- List packages...
        end

    print_main_help
        do
            print ("pkg - Simple package manager%N")
            print ("%NCommands:%N")
            print ("  install PKG...   Install packages%N")
            print ("  remove PKG...    Remove packages%N")
            print ("  update           Update package index%N")
            print ("  list             List installed packages%N")
            print ("%NOptions:%N")
            print ("  -v, --verbose    Verbose output%N")
            print ("  -q, --quiet      Suppress output%N")
            print ("  -h, --help       Show help%N")
        end

end

Usage

pkg install simple_json simple_file
pkg -v remove old_package
pkg update
pkg list

3. File Processor

Process files with input/output options.

class FILE_PROCESSOR

create
    make

feature

    make
        local
            cli: SIMPLE_CLI
        do
            create cli.make
            cli.set_app_info ("process", "Transform files", "1.0.0")

            -- Required input
            cli.add_required_option ("i|input", "Input file", "FILE")

            -- Optional output (defaults to stdout)
            cli.add_option ("o|output", "Output file (default: stdout)", "FILE")

            -- Format options
            cli.add_option_with_default ("f|format", "Output format", "FMT", "json")

            -- Processing flags
            cli.add_flag ("p|pretty", "Pretty print output")
            cli.add_flag ("m|minify", "Minify output")

            cli.parse

            if cli.help_requested then
                cli.print_help
            elseif cli.has_errors then
                cli.print_errors
            else
                process (cli)
            end
        end

    process (cli: SIMPLE_CLI)
        local
            input_path, output_path: STRING
            format: STRING
            pretty: BOOLEAN
        do
            -- Required option always has value
            if attached cli.option_value ("input") as i then
                input_path := i
            end

            -- Optional with inline default
            output_path := cli.option_value_or_default ("output", "")

            -- Format has configured default
            if attached cli.option_value ("format") as f then
                format := f
            end

            pretty := cli.has_flag ("pretty")

            -- Process file...
            print ("Processing " + input_path + " as " + format + "%N")
        end

end

Usage

# Convert to JSON (default format)
process -i data.xml -o data.json

# Convert to YAML, pretty printed
process -i data.json -f yaml -p

# Output to stdout
process -i data.xml

4. Build Tool

Compile/build tool with targets and options.

class BUILD_TOOL

create
    make

feature

    make
        local
            cli: SIMPLE_CLI
        do
            create cli.make
            cli.set_app_info ("build", "Build Eiffel projects", "2.0.0")

            -- Build options
            cli.add_option ("c|config", "ECF configuration file", "FILE")
            cli.add_option ("t|target", "Build target", "TARGET")
            cli.add_option_with_default ("j|jobs", "Parallel jobs", "NUM", "4")

            -- Build modes
            cli.add_flag ("r|release", "Release build (optimized)")
            cli.add_flag ("d|debug", "Debug build (assertions)")
            cli.add_flag ("clean", "Clean before build")
            cli.add_flag ("finalize", "Finalized build")

            cli.parse

            if cli.help_requested then
                cli.print_help
            elseif cli.has_errors then
                cli.print_errors
            else
                run_build (cli)
            end
        end

    run_build (cli: SIMPLE_CLI)
        local
            config_file: STRING
            jobs: INTEGER
        do
            config_file := cli.option_value_or_default ("config", "project.ecf")
            jobs := cli.integer_option_or_default ("jobs", 4)

            if cli.has_flag ("clean") then
                print ("Cleaning...%N")
            end

            print ("Building " + config_file + " with " + jobs.out + " jobs%N")

            if cli.has_flag ("release") then
                print ("Mode: Release%N")
            elseif cli.has_flag ("debug") then
                print ("Mode: Debug%N")
            end
        end

end

5. Server Application

Web server with host/port configuration.

class WEB_SERVER

create
    make

feature

    make
        local
            cli: SIMPLE_CLI
        do
            create cli.make
            cli.set_app_info ("server", "Simple web server", "1.0.0")

            -- Network options
            cli.add_option_with_default ("H|host", "Bind address", "ADDR", "127.0.0.1")
            cli.add_option_with_default ("p|port", "Port number", "PORT", "8080")

            -- Path options
            cli.add_option_with_default ("d|docroot", "Document root", "DIR", "./public")

            -- Runtime options
            cli.add_flag ("daemon", "Run as daemon")
            cli.add_flag ("a|access-log", "Enable access logging")
            cli.add_option ("l|log-file", "Log file path", "FILE")

            cli.parse

            if cli.help_requested then
                cli.print_help
            elseif cli.has_errors then
                cli.print_errors
            else
                start_server (cli)
            end
        end

    start_server (cli: SIMPLE_CLI)
        local
            host: STRING
            port: INTEGER
            docroot: STRING
        do
            host := cli.option_value_or_default ("host", "127.0.0.1")
            port := cli.integer_option_or_default ("port", 8080)
            docroot := cli.option_value_or_default ("docroot", "./public")

            print ("Starting server on " + host + ":" + port.out + "%N")
            print ("Document root: " + docroot + "%N")

            if cli.has_flag ("access-log") then
                print ("Access logging enabled%N")
            end

            -- Start server...
        end

end

Usage

# Start on default port
server

# Custom port and document root
server -p 3000 -d ./dist

# Production settings
server --host=0.0.0.0 --port=80 --daemon --access-log

6. Data Converter

Convert between data formats.

class DATA_CONVERTER

create
    make

feature

    make
        local
            cli: SIMPLE_CLI
        do
            create cli.make
            cli.set_app_info ("convert", "Convert between data formats", "1.0.0")

            -- Format options
            cli.add_required_option ("f|from", "Input format", "FORMAT")
            cli.add_required_option ("t|to", "Output format", "FORMAT")

            -- I/O
            cli.add_option ("i|input", "Input file (stdin if omitted)", "FILE")
            cli.add_option ("o|output", "Output file (stdout if omitted)", "FILE")

            -- Options
            cli.add_flag ("p|pretty", "Pretty print")
            cli.add_option ("indent", "Indentation spaces", "NUM")

            cli.parse

            if cli.help_requested then
                print_help
            elseif cli.has_errors then
                cli.print_errors
            else
                convert (cli)
            end
        end

    print_help
        do
            print ("convert - Data format converter%N")
            print ("%NSupported formats: json, yaml, xml, csv, toml%N")
            print ("%NExamples:%N")
            print ("  convert -f json -t yaml -i data.json -o data.yaml%N")
            print ("  convert --from=csv --to=json < data.csv%N")
        end

    convert (cli: SIMPLE_CLI)
        local
            from_fmt, to_fmt: STRING
            indent: INTEGER
        do
            if attached cli.option_value ("from") as f then
                from_fmt := f
            end
            if attached cli.option_value ("to") as t then
                to_fmt := t
            end

            indent := cli.integer_option_or_default ("indent", 2)

            print ("Converting from " + from_fmt + " to " + to_fmt + "%N")
            -- Conversion logic...
        end

end

7. Test Runner

Run tests with filtering and output options.

class TEST_RUNNER

create
    make

feature

    make
        local
            cli: SIMPLE_CLI
        do
            create cli.make
            cli.set_app_info ("test", "Eiffel test runner", "1.0.0")

            -- Test selection
            cli.add_option ("f|filter", "Run tests matching pattern", "PATTERN")
            cli.add_option ("t|tag", "Run tests with tag", "TAG")

            -- Output
            cli.add_flag ("v|verbose", "Verbose output")
            cli.add_flag ("q|quiet", "Only show failures")
            cli.add_option_with_default ("format", "Output format", "FMT", "text")

            -- Execution
            cli.add_flag ("fail-fast", "Stop on first failure")
            cli.add_option_with_default ("timeout", "Test timeout (seconds)", "SEC", "30")

            cli.parse

            if cli.help_requested then
                cli.print_help
            elseif cli.has_errors then
                cli.print_errors
            else
                run_tests (cli)
            end
        end

    run_tests (cli: SIMPLE_CLI)
        local
            timeout: INTEGER
            filter: detachable STRING
        do
            timeout := cli.integer_option_or_default ("timeout", 30)
            filter := cli.option_value ("filter")

            if attached filter then
                print ("Running tests matching: " + filter + "%N")
            else
                print ("Running all tests%N")
            end

            print ("Timeout: " + timeout.out + "s%N")

            if cli.has_flag ("fail-fast") then
                print ("Stopping on first failure%N")
            end
        end

end

Usage

# Run all tests
test

# Run specific tests
test --filter="*json*"
test --tag=unit

# CI mode
test --format=junit --quiet --fail-fast

8. Deployment Tool

Deploy applications with environment selection.

class DEPLOY_TOOL

create
    make

feature

    make
        local
            cli: SIMPLE_CLI
        do
            create cli.make
            cli.set_app_info ("deploy", "Deployment tool", "1.0.0")

            -- Environment
            cli.add_required_option ("e|env", "Target environment", "ENV")

            -- Options
            cli.add_option ("b|branch", "Git branch", "BRANCH")
            cli.add_option ("tag", "Deploy specific tag", "TAG")

            -- Flags
            cli.add_flag ("n|dry-run", "Show what would be done")
            cli.add_flag ("f|force", "Force deployment")
            cli.add_flag ("skip-tests", "Skip test suite")
            cli.add_flag ("y|yes", "Skip confirmation")

            cli.parse

            if cli.help_requested then
                print_help
            elseif cli.has_errors then
                cli.print_errors
            else
                deploy (cli)
            end
        end

    print_help
        do
            print ("deploy - Deployment tool%N")
            print ("%NEnvironments: staging, production%N")
            print ("%NExamples:%N")
            print ("  deploy -e staging           Deploy to staging%N")
            print ("  deploy -e production -y     Deploy to production (no prompt)%N")
            print ("  deploy -e staging -n        Dry run%N")
        end

    deploy (cli: SIMPLE_CLI)
        local
            env, branch: STRING
        do
            if attached cli.option_value ("env") as e then
                env := e
            end
            branch := cli.option_value_or_default ("branch", "main")

            if cli.has_flag ("dry-run") then
                print ("[DRY RUN] ")
            end

            print ("Deploying " + branch + " to " + env + "%N")

            if env.same_string ("production") and not cli.has_flag ("yes") then
                print ("Are you sure? Use -y to skip confirmation%N")
                return
            end

            -- Deployment logic...
        end

end