WIP: Man pages generation with clap_mangen
This commit is contained in:
@@ -0,0 +1,320 @@
|
||||
# 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:
|
||||
```bash
|
||||
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
|
||||
|
||||
### Option 1: Use the Installation Script (Recommended)
|
||||
|
||||
The `scripts/install-with-man.sh` script builds the binaries, extracts the generated man pages, and installs everything:
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
# 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:
|
||||
|
||||
```bash
|
||||
# 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:
|
||||
|
||||
```bash
|
||||
man socktop
|
||||
man socktop_agent
|
||||
```
|
||||
|
||||
If `man socktop` doesn't work after user installation, add to your shell rc:
|
||||
|
||||
```bash
|
||||
# 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`:
|
||||
```rust
|
||||
/// Your new option description
|
||||
#[arg(short = 'x', long = "example")]
|
||||
pub example: bool,
|
||||
```
|
||||
|
||||
2. **Rebuild** to regenerate man pages:
|
||||
```bash
|
||||
cargo build --release
|
||||
```
|
||||
|
||||
3. **Reinstall** man pages:
|
||||
```bash
|
||||
./scripts/install-with-man.sh --man-only
|
||||
```
|
||||
|
||||
The man pages will automatically reflect your changes!
|
||||
|
||||
## CLI Definition Format
|
||||
|
||||
### Basic Structure
|
||||
|
||||
```rust
|
||||
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
|
||||
|
||||
```rust
|
||||
/// 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
|
||||
|
||||
```rust
|
||||
/// 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
|
||||
|
||||
```bash
|
||||
# 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:
|
||||
```bash
|
||||
cargo clean
|
||||
cargo build -vv 2>&1 | grep build.rs
|
||||
```
|
||||
|
||||
### Can't find generated man page
|
||||
|
||||
**Solution:** Look in the correct build output:
|
||||
```bash
|
||||
find target -name "socktop.1" -type f
|
||||
```
|
||||
|
||||
### Man page content is outdated
|
||||
|
||||
**Solution:** Clean and rebuild:
|
||||
```bash
|
||||
cargo clean
|
||||
cargo build --release
|
||||
```
|
||||
|
||||
### MANPATH not working
|
||||
|
||||
**Solution:** Verify the path is correct:
|
||||
```bash
|
||||
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
|
||||
|
||||
- [clap documentation](https://docs.rs/clap/)
|
||||
- [clap_mangen documentation](https://docs.rs/clap_mangen/)
|
||||
- [Manual man pages](man/README.md) - The original manually written versions
|
||||
- [Quick Reference](QUICK_REFERENCE.md) - Command cheat sheet
|
||||
@@ -0,0 +1,380 @@
|
||||
# Migration to Clap for Auto-Generated Man Pages
|
||||
|
||||
## Summary
|
||||
|
||||
Socktop has been migrated from manual argument parsing to **clap** (Command Line Argument Parser) with automatic man page generation via **clap_mangen**. This provides several benefits:
|
||||
|
||||
✅ **Auto-generated man pages** - Always in sync with CLI
|
||||
✅ **Better help output** - Rich, formatted `--help` text
|
||||
✅ **Type safety** - Compile-time checking of arguments
|
||||
✅ **Environment variable support** - Built-in env var integration
|
||||
✅ **Shell completions** - Easy to add bash/zsh/fish completions
|
||||
✅ **Single source of truth** - CLI definitions generate everything
|
||||
|
||||
## What Changed
|
||||
|
||||
### Before (Manual Parsing)
|
||||
|
||||
```rust
|
||||
// Old approach: Manual argument parsing
|
||||
fn parse_args<I: IntoIterator<Item = String>>(args: I) -> Result<ParsedArgs, String> {
|
||||
let mut it = args.into_iter();
|
||||
let prog = it.next().unwrap_or_else(|| "socktop".into());
|
||||
let mut url: Option<String> = None;
|
||||
let mut tls_ca: Option<String> = None;
|
||||
// ... lots of manual parsing code ...
|
||||
while let Some(arg) = it.next() {
|
||||
match arg.as_str() {
|
||||
"-h" | "--help" => {
|
||||
return Err(format!("Usage: {prog} ..."));
|
||||
}
|
||||
"--tls-ca" | "-t" => {
|
||||
tls_ca = it.next();
|
||||
}
|
||||
// ... more matches ...
|
||||
}
|
||||
}
|
||||
Ok(ParsedArgs { url, tls_ca, ... })
|
||||
}
|
||||
```
|
||||
|
||||
**Problems:**
|
||||
- Manual parsing is error-prone
|
||||
- Help text gets out of sync
|
||||
- No automatic man page generation
|
||||
- Duplicated logic for `--flag` and `--flag=value`
|
||||
- No environment variable support
|
||||
- Hard to test
|
||||
|
||||
### After (Clap Derive)
|
||||
|
||||
```rust
|
||||
// New approach: Clap derive macros
|
||||
use clap::Parser;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(
|
||||
name = "socktop",
|
||||
version,
|
||||
author,
|
||||
about = "Remote system monitor with a rich TUI over WebSocket",
|
||||
long_about = "socktop is a remote system monitor..."
|
||||
)]
|
||||
pub struct Cli {
|
||||
/// WebSocket URL to connect to
|
||||
#[arg(value_name = "URL")]
|
||||
pub url: Option<String>,
|
||||
|
||||
/// Path to TLS certificate PEM file for WSS connections
|
||||
#[arg(short = 't', long = "tls-ca", value_name = "CERT_PEM")]
|
||||
pub tls_ca: Option<String>,
|
||||
|
||||
// ... more fields ...
|
||||
}
|
||||
|
||||
// Usage:
|
||||
let cli = Cli::parse();
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Declarative and concise
|
||||
- Auto-generated help and man pages
|
||||
- Type-safe argument parsing
|
||||
- Automatic support for `--flag` and `--flag=value`
|
||||
- Built-in env var support with `env` attribute
|
||||
- Easy to test
|
||||
|
||||
## Files Modified
|
||||
|
||||
### Core Changes
|
||||
|
||||
1. **`socktop/Cargo.toml`** - Added clap dependencies
|
||||
2. **`socktop/src/cli.rs`** - NEW: CLI definition using clap derive
|
||||
3. **`socktop/src/main.rs`** - Updated to use `Cli::parse_args()`
|
||||
4. **`socktop/build.rs`** - NEW: Auto-generates man pages at build time
|
||||
|
||||
5. **`socktop_agent/Cargo.toml`** - Added clap dependencies
|
||||
6. **`socktop_agent/src/cli.rs`** - NEW: CLI definition using clap derive
|
||||
7. **`socktop_agent/src/main.rs`** - Updated to use `Cli::parse_args()`
|
||||
8. **`socktop_agent/build.rs`** - Updated to auto-generate man pages
|
||||
|
||||
### Documentation
|
||||
|
||||
9. **`docs/AUTO_MAN_PAGES.md`** - Comprehensive guide to auto-generated man pages
|
||||
10. **`docs/CLAP_MIGRATION.md`** - This file
|
||||
11. **`README.md`** - Updated Man Pages section
|
||||
12. **`scripts/install-with-man.sh`** - NEW: Installation script that includes man pages
|
||||
|
||||
## Man Page Generation
|
||||
|
||||
### How It Works
|
||||
|
||||
1. **Build Time** - When you run `cargo build`, the `build.rs` script:
|
||||
- Includes the CLI definition from `src/cli.rs`
|
||||
- Creates a clap `Command` instance
|
||||
- Uses `clap_mangen` to generate a man page
|
||||
- Saves it to `$OUT_DIR/man/*.1`
|
||||
|
||||
2. **Location** - Generated man pages are at:
|
||||
```
|
||||
target/release/build/socktop-*/out/man/socktop.1
|
||||
target/release/build/socktop_agent-*/out/man/socktop_agent.1
|
||||
```
|
||||
|
||||
3. **Installation** - Use the installation script:
|
||||
```bash
|
||||
./scripts/install-with-man.sh # User install
|
||||
sudo ./scripts/install-with-man.sh --system # System install
|
||||
```
|
||||
|
||||
4. **Viewing** - After installation:
|
||||
```bash
|
||||
man socktop
|
||||
man socktop_agent
|
||||
```
|
||||
|
||||
### Man Page Content
|
||||
|
||||
The man pages include:
|
||||
- **NAME** - From `about` attribute
|
||||
- **SYNOPSIS** - Auto-generated from arguments
|
||||
- **DESCRIPTION** - From `long_about` attribute
|
||||
- **OPTIONS** - From field doc comments and `#[arg(...)]` attributes
|
||||
- **VERSION** - From Cargo.toml
|
||||
- **AUTHORS** - From Cargo.toml
|
||||
|
||||
## CLI Definition Format
|
||||
|
||||
### Structure
|
||||
|
||||
```rust
|
||||
use clap::Parser;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(
|
||||
name = "myapp",
|
||||
version, // Uses Cargo.toml version
|
||||
author, // Uses Cargo.toml authors
|
||||
about = "Short description",
|
||||
long_about = "Longer description for man page and --help"
|
||||
)]
|
||||
pub struct Cli {
|
||||
/// Short description
|
||||
///
|
||||
/// Longer description that appears in the man page.
|
||||
/// Multiple paragraphs supported.
|
||||
#[arg(short = 't', long = "thing", value_name = "VALUE")]
|
||||
pub thing: Option<String>,
|
||||
}
|
||||
```
|
||||
|
||||
### Common Attributes
|
||||
|
||||
| Attribute | Purpose | Example |
|
||||
|-----------|---------|---------|
|
||||
| `short = 'x'` | Short flag | `-x` |
|
||||
| `long = "example"` | Long flag | `--example` |
|
||||
| `value_name = "FOO"` | Display name | `--thing <FOO>` |
|
||||
| `env = "VAR"` | Environment variable | `env = "MY_VAR"` |
|
||||
| `default_value = "x"` | Default value | Default: "x" |
|
||||
| `hide = true` | Hide from help/man | For internal options |
|
||||
| `value_parser = func` | Custom parser | Validation |
|
||||
|
||||
### Environment Variables
|
||||
|
||||
```rust
|
||||
/// Port to listen on
|
||||
///
|
||||
/// Can be set via SOCKTOP_PORT environment variable.
|
||||
#[arg(short = 'p', long = "port", env = "SOCKTOP_PORT")]
|
||||
pub port: Option<u16>,
|
||||
```
|
||||
|
||||
This automatically:
|
||||
- Checks the environment variable
|
||||
- Shows `[env: SOCKTOP_PORT=]` in help
|
||||
- Documents it in the man page
|
||||
|
||||
## Testing
|
||||
|
||||
### Unit Tests
|
||||
|
||||
Both CLI modules include comprehensive unit tests:
|
||||
|
||||
```rust
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_basic_parsing() {
|
||||
let cli = Cli::try_parse_from(&["socktop", "ws://localhost:8080/ws"]).unwrap();
|
||||
assert_eq!(cli.url, Some("ws://localhost:8080/ws".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tls_options() {
|
||||
let cli = Cli::try_parse_from(&[
|
||||
"socktop",
|
||||
"-t", "/path/to/cert.pem",
|
||||
"--verify-hostname",
|
||||
"wss://example.com:8443/ws",
|
||||
]).unwrap();
|
||||
assert_eq!(cli.tls_ca, Some("/path/to/cert.pem".to_string()));
|
||||
assert!(cli.verify_hostname);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Run tests with:
|
||||
```bash
|
||||
cargo test --package socktop cli::
|
||||
cargo test --package socktop_agent cli::
|
||||
```
|
||||
|
||||
### Manual Testing
|
||||
|
||||
Test the help output:
|
||||
```bash
|
||||
cargo run --package socktop -- --help
|
||||
cargo run --package socktop_agent -- --help
|
||||
```
|
||||
|
||||
Test argument parsing:
|
||||
```bash
|
||||
cargo run --package socktop -- ws://localhost:8080/ws
|
||||
cargo run --package socktop -- -t cert.pem wss://localhost:8443/ws
|
||||
cargo run --package socktop_agent -- --port 8080
|
||||
cargo run --package socktop_agent -- --enableSSL
|
||||
```
|
||||
|
||||
Test environment variables:
|
||||
```bash
|
||||
SOCKTOP_PORT=9000 cargo run --package socktop_agent
|
||||
SOCKTOP_ENABLE_SSL=1 cargo run --package socktop_agent
|
||||
```
|
||||
|
||||
## Backwards Compatibility
|
||||
|
||||
### Command-Line Interface
|
||||
|
||||
✅ **Fully compatible** - All existing command-line arguments work exactly the same:
|
||||
|
||||
```bash
|
||||
# Still works
|
||||
socktop -t cert.pem wss://host:8443/ws
|
||||
socktop --profile myprofile
|
||||
socktop --demo
|
||||
|
||||
socktop_agent --port 8080
|
||||
socktop_agent --enableSSL
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
✅ **Fully compatible** - All environment variables still work:
|
||||
|
||||
```bash
|
||||
SOCKTOP_PORT=8080 socktop_agent
|
||||
SOCKTOP_ENABLE_SSL=1 socktop_agent
|
||||
```
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
❌ **None** - This is a drop-in replacement for the old parser.
|
||||
|
||||
## Comparison: Manual vs Clap
|
||||
|
||||
| Feature | Manual Parsing | Clap |
|
||||
|---------|---------------|------|
|
||||
| Code lines | ~120 lines | ~50 lines |
|
||||
| Man pages | Separate files | Auto-generated |
|
||||
| Help text | Hardcoded strings | Auto-generated |
|
||||
| Type safety | Runtime errors | Compile-time |
|
||||
| Env vars | Manual `std::env::var` | Built-in `env` attribute |
|
||||
| Testing | Hard to test | Easy with `try_parse_from` |
|
||||
| Maintenance | High | Low |
|
||||
| Consistency | Can drift | Always in sync |
|
||||
| Completions | Manual | Auto-generate |
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Now that we're using clap, we can easily add:
|
||||
|
||||
### Shell Completions
|
||||
|
||||
```rust
|
||||
// In build.rs
|
||||
use clap_complete::{generate_to, shells::*};
|
||||
|
||||
let cmd = Cli::command();
|
||||
generate_to(Bash, &mut cmd, "socktop", &out_dir)?;
|
||||
generate_to(Zsh, &mut cmd, "socktop", &out_dir)?;
|
||||
generate_to(Fish, &mut cmd, "socktop", &out_dir)?;
|
||||
```
|
||||
|
||||
### Subcommands
|
||||
|
||||
```rust
|
||||
#[derive(Parser)]
|
||||
enum Commands {
|
||||
/// Connect to an agent
|
||||
Connect {
|
||||
#[arg(value_name = "URL")]
|
||||
url: String,
|
||||
},
|
||||
/// List saved profiles
|
||||
Profiles,
|
||||
/// Run demo mode
|
||||
Demo,
|
||||
}
|
||||
```
|
||||
|
||||
### Better Validation
|
||||
|
||||
```rust
|
||||
#[arg(value_parser = clap::value_parser!(u16).range(1..=65535))]
|
||||
pub port: Option<u16>,
|
||||
```
|
||||
|
||||
### Custom Help Sections
|
||||
|
||||
```rust
|
||||
#[command(
|
||||
after_help = "EXAMPLES:\n socktop ws://localhost:8080/ws\n socktop --demo"
|
||||
)]
|
||||
```
|
||||
|
||||
## Migration Checklist
|
||||
|
||||
If migrating other Rust projects to clap:
|
||||
|
||||
- [ ] Add clap and clap_mangen dependencies
|
||||
- [ ] Create `src/cli.rs` with derive macros
|
||||
- [ ] Update `main.rs` to use `Cli::parse()`
|
||||
- [ ] Create/update `build.rs` for man page generation
|
||||
- [ ] Write unit tests for CLI parsing
|
||||
- [ ] Test all existing command-line arguments
|
||||
- [ ] Test environment variables
|
||||
- [ ] Update documentation
|
||||
- [ ] Create installation scripts for man pages
|
||||
- [ ] Consider adding shell completions
|
||||
|
||||
## Resources
|
||||
|
||||
- [Clap Documentation](https://docs.rs/clap/)
|
||||
- [Clap Derive Tutorial](https://docs.rs/clap/latest/clap/_derive/index.html)
|
||||
- [Clap Mangen](https://docs.rs/clap_mangen/)
|
||||
- [Auto-Generated Man Pages Guide](AUTO_MAN_PAGES.md)
|
||||
- [Manual Man Pages](man/README.md)
|
||||
|
||||
## Conclusion
|
||||
|
||||
The migration to clap provides:
|
||||
- Better developer experience
|
||||
- Auto-generated, always-in-sync documentation
|
||||
- Reduced maintenance burden
|
||||
- Professional-quality help output and man pages
|
||||
- Foundation for future enhancements (completions, subcommands)
|
||||
|
||||
All with **zero breaking changes** to the existing CLI.
|
||||
Reference in New Issue
Block a user