socktop/docs/AUTO_MAN_PAGES.md
jasonwitty f82a5903b8
Some checks failed
CI / build (ubuntu-latest) (push) Has been cancelled
CI / build (windows-latest) (push) Has been cancelled
WIP: Man pages generation with clap_mangen
2025-11-20 23:35:29 -08:00

8.1 KiB

Auto-Generated Man Pages

This document explains how man pages are automatically generated from the CLI definitions using clap and clap_mangen.

Overview

Starting from version 1.50.0+, socktop uses clap for CLI parsing and clap_mangen to automatically generate man pages at build time. This approach has several advantages:

Man pages are always in sync with the actual CLI
Single source of truth (CLI definitions)
No manual maintenance of separate man page files
Generated during cargo build automatically
Can be installed alongside binaries

How It Works

1. CLI Definitions

Both socktop and socktop_agent use clap's derive macros to define their CLI:

  • socktop/src/cli.rs - Client CLI definition
  • socktop_agent/src/cli.rs - Agent CLI definition

These files use clap's attributes to specify:

  • Arguments and options
  • Help text and descriptions
  • Value names and types
  • Environment variable support
  • Hidden options (for testing)

2. Build-Time Generation

Each crate has a build.rs script that:

  1. Includes the CLI definition file
  2. Uses clap_mangen to generate the man page
  3. Saves it to $OUT_DIR/man/*.1

The generation happens automatically during:

cargo build
cargo build --release
cargo install

3. Generated Man Pages Location

After building, man pages are located at:

target/debug/build/socktop-*/out/man/socktop.1
target/debug/build/socktop_agent-*/out/man/socktop_agent.1

# Or for release builds:
target/release/build/socktop-*/out/man/socktop.1
target/release/build/socktop_agent-*/out/man/socktop_agent.1

Installation Options

The scripts/install-with-man.sh script builds the binaries, extracts the generated man pages, and installs everything:

# User installation (no sudo)
./scripts/install-with-man.sh

# System-wide installation (requires sudo)
sudo ./scripts/install-with-man.sh --system

# Only install man pages (after building)
./scripts/install-with-man.sh --man-only

This script:

  • Builds the project in release mode
  • Extracts generated man pages from OUT_DIR
  • Installs binaries to ~/.cargo/bin or /usr/local/bin
  • Installs man pages to ~/.local/share/man/man1 or /usr/local/share/man/man1

Option 2: Manual Installation After Build

# Build the project
cargo build --release

# Find generated man pages
SOCKTOP_MAN=$(find target/release/build/socktop-*/out/man/socktop.1 | head -1)
AGENT_MAN=$(find target/release/build/socktop_agent-*/out/man/socktop_agent.1 | head -1)

# Install to user directory
mkdir -p ~/.local/share/man/man1
cp "$SOCKTOP_MAN" ~/.local/share/man/man1/
cp "$AGENT_MAN" ~/.local/share/man/man1/

# Or install system-wide
sudo mkdir -p /usr/local/share/man/man1
sudo cp "$SOCKTOP_MAN" /usr/local/share/man/man1/
sudo cp "$AGENT_MAN" /usr/local/share/man/man1/
sudo mandb  # Update man database

Option 3: View Without Installing

You can view the generated man pages directly:

# After building
man -l $(find target/release/build/socktop-*/out/man/socktop.1 | head -1)
man -l $(find target/release/build/socktop_agent-*/out/man/socktop_agent.1 | head -1)

Viewing Installed Man Pages

After installation:

man socktop
man socktop_agent

If man socktop doesn't work after user installation, add to your shell rc:

# For bash
echo 'export MANPATH="$HOME/.local/share/man:$MANPATH"' >> ~/.bashrc
source ~/.bashrc

# For zsh
echo 'export MANPATH="$HOME/.local/share/man:$MANPATH"' >> ~/.zshrc
source ~/.zshrc

Updating CLI and Man Pages

When you need to update the CLI or man pages:

  1. Edit the CLI definition in src/cli.rs:

    /// Your new option description
    #[arg(short = 'x', long = "example")]
    pub example: bool,
    
  2. Rebuild to regenerate man pages:

    cargo build --release
    
  3. Reinstall man pages:

    ./scripts/install-with-man.sh --man-only
    

The man pages will automatically reflect your changes!

CLI Definition Format

Basic Structure

use clap::Parser;

#[derive(Parser, Debug)]
#[command(
    name = "myapp",
    version,
    author,
    about = "Short description",
    long_about = "Longer description that appears in man page and --help"
)]
pub struct Cli {
    /// Short description of this option
    ///
    /// Longer description that appears in the man page.
    /// Can span multiple lines.
    #[arg(short = 't', long = "thing", value_name = "VALUE")]
    pub thing: Option<String>,
    
    /// Boolean flag
    #[arg(long)]
    pub flag: bool,
    
    /// Hidden option (won't appear in man page or --help)
    #[arg(long, hide = true)]
    pub secret: bool,
}

Environment Variable Support

/// Port to listen on
///
/// Can also be set via MYAPP_PORT environment variable.
#[arg(short = 'p', long = "port", env = "MYAPP_PORT")]
pub port: Option<u16>,

Value Parsing

/// Custom parser
#[arg(long, value_parser = parse_custom)]
pub custom: Option<String>,

fn parse_custom(s: &str) -> Result<String, String> {
    // Custom validation logic
    Ok(s.to_string())
}

Advantages Over Manual Man Pages

Feature Auto-Generated Manual
Always in sync with CLI Yes Manual updates required
Single source of truth Yes Duplicated info
Maintenance effort Low High
Consistency Guaranteed Can drift
Generated at build time Yes Separate process
Works with --help Same source Separate
Rich formatting ⚠️ Good Full control

Comparison with Manual Man Pages

The project also includes manually written man pages in docs/man/ for comparison and as templates. These are more detailed and include additional sections like:

  • EXAMPLES with complex scenarios
  • SECURITY CONSIDERATIONS
  • PLATFORM NOTES
  • Systemd integration guides
  • Troubleshooting tips

The auto-generated man pages from clap are excellent for:

  • Options and arguments
  • Basic descriptions
  • Version and author info
  • Environment variables

But may be limited for:

  • Complex examples
  • Extensive narrative documentation
  • Custom formatting
  • Additional reference sections

Best Practices

  1. Write good doc comments in cli.rs - they become man page content
  2. Use long_about for detailed descriptions
  3. Specify value_name for clarity (e.g., <PORT>, <URL>)
  4. Document environment variables in the option description
  5. Use hide = true for internal/test options
  6. Keep descriptions concise but informative
  7. Rebuild after CLI changes to update man pages

Testing Man Page Generation

# Clean build to ensure regeneration
cargo clean

# Build and check for man page warning
cargo build --release 2>&1 | grep "Man page generated"

# View the generated man page
man -l $(find target/release/build/socktop-*/out/man/socktop.1 | head -1)

# Check for errors
lexgrog $(find target/release/build/socktop-*/out/man/socktop.1 | head -1)

Troubleshooting

Man page not generated

Solution: Check that build.rs ran successfully:

cargo clean
cargo build -vv 2>&1 | grep build.rs

Can't find generated man page

Solution: Look in the correct build output:

find target -name "socktop.1" -type f

Man page content is outdated

Solution: Clean and rebuild:

cargo clean
cargo build --release

MANPATH not working

Solution: Verify the path is correct:

echo $MANPATH
man -w  # Show current man paths

Future Enhancements

Potential improvements:

  • Add more detailed examples section using clap's after_help
  • Generate shell completions alongside man pages
  • Create a custom man page template with additional sections
  • Package man pages in release artifacts
  • Auto-install man pages during cargo install

See Also