cli-distribution
Distribution and packaging patterns including shell completions, man pages, cross-compilation, and release automation. Use when preparing CLI tools for distribution.
What this skill does
# CLI Distribution Skill
Patterns and best practices for distributing Rust CLI applications to users.
## Shell Completion Generation
### Using clap_complete
```rust
use clap::{CommandFactory, Parser};
use clap_complete::{generate, Generator, Shell};
use std::io;
#[derive(Parser)]
struct Cli {
/// Generate shell completions
#[arg(long = "generate", value_enum)]
generator: Option<Shell>,
// ... other fields
}
fn print_completions<G: Generator>(gen: G, cmd: &mut clap::Command) {
generate(gen, cmd, cmd.get_name().to_string(), &mut io::stdout());
}
fn main() {
let cli = Cli::parse();
if let Some(generator) = cli.generator {
let mut cmd = Cli::command();
print_completions(generator, &mut cmd);
return;
}
// ... rest of application
}
```
### Installation Instructions by Shell
**Bash:**
```bash
# Generate and save
myapp --generate bash > /etc/bash_completion.d/myapp
# Or add to ~/.bashrc
eval "$(myapp --generate bash)"
```
**Zsh:**
```bash
# Generate and save
myapp --generate zsh > ~/.zfunc/_myapp
# Add to ~/.zshrc
fpath=(~/.zfunc $fpath)
autoload -Uz compinit && compinit
```
**Fish:**
```bash
# Generate and save
myapp --generate fish > ~/.config/fish/completions/myapp.fish
# Or load directly
myapp --generate fish | source
```
**PowerShell:**
```powershell
# Add to $PROFILE
Invoke-Expression (& myapp --generate powershell)
```
### Dynamic Completions
For commands with dynamic values (like listing resources):
```rust
use clap::CommandFactory;
use clap_complete::{generate, Generator};
pub fn generate_with_values<G: Generator>(
gen: G,
resources: &[String],
) -> String {
let mut cmd = Cli::command();
// Add dynamic values to completion
if let Some(subcommand) = cmd.find_subcommand_mut("get") {
for resource in resources {
subcommand = subcommand.arg(
clap::Arg::new("resource")
.value_parser(clap::builder::PossibleValuesParser::new(resource))
);
}
}
let mut buf = Vec::new();
generate(gen, &mut cmd, "myapp", &mut buf);
String::from_utf8(buf).unwrap()
}
```
## Man Page Generation
### Using clap_mangen
```toml
[dependencies]
clap_mangen = "0.2"
```
```rust
use clap::CommandFactory;
use clap_mangen::Man;
use std::io;
fn generate_man_page() {
let cmd = Cli::command();
let man = Man::new(cmd);
man.render(&mut io::stdout()).unwrap();
}
```
### Build Script for Man Pages
```rust
// build.rs
use clap::CommandFactory;
use clap_mangen::Man;
use std::fs;
use std::path::PathBuf;
include!("src/cli.rs");
fn main() {
let out_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("target/man");
fs::create_dir_all(&out_dir).unwrap();
let cmd = Cli::command();
let man = Man::new(cmd);
let mut buffer = Vec::new();
man.render(&mut buffer).unwrap();
fs::write(out_dir.join("myapp.1"), buffer).unwrap();
}
```
### Install Man Page
```bash
# System-wide
sudo cp target/man/myapp.1 /usr/local/share/man/man1/
# User-local
mkdir -p ~/.local/share/man/man1
cp target/man/myapp.1 ~/.local/share/man/man1/
```
## Cross-Compilation
### Target Triples
Common targets for CLI distribution:
```bash
# Linux
x86_64-unknown-linux-gnu # GNU Linux
x86_64-unknown-linux-musl # MUSL Linux (static)
aarch64-unknown-linux-gnu # ARM64 Linux
# macOS
x86_64-apple-darwin # Intel Mac
aarch64-apple-darwin # Apple Silicon
# Windows
x86_64-pc-windows-msvc # Windows MSVC
x86_64-pc-windows-gnu # Windows GNU
```
### Cross-Compilation with cross
```bash
# Install cross
cargo install cross
# Build for Linux from any platform
cross build --release --target x86_64-unknown-linux-gnu
# Build static binary with MUSL
cross build --release --target x86_64-unknown-linux-musl
```
### GitHub Actions for Cross-Compilation
```yaml
# .github/workflows/release.yml
name: Release
on:
push:
tags:
- 'v*'
jobs:
build:
strategy:
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
artifact_name: myapp
asset_name: myapp-linux-amd64
- os: ubuntu-latest
target: x86_64-unknown-linux-musl
artifact_name: myapp
asset_name: myapp-linux-musl-amd64
- os: macos-latest
target: x86_64-apple-darwin
artifact_name: myapp
asset_name: myapp-macos-amd64
- os: macos-latest
target: aarch64-apple-darwin
artifact_name: myapp
asset_name: myapp-macos-arm64
- os: windows-latest
target: x86_64-pc-windows-msvc
artifact_name: myapp.exe
asset_name: myapp-windows-amd64.exe
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Build
run: cargo build --release --target ${{ matrix.target }}
- name: Upload binaries
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.asset_name }}
path: target/${{ matrix.target }}/release/${{ matrix.artifact_name }}
```
## Binary Size Optimization
### Cargo.toml optimizations
```toml
[profile.release]
opt-level = "z" # Optimize for size
lto = true # Link-time optimization
codegen-units = 1 # Better optimization
strip = true # Strip symbols
panic = "abort" # Smaller panic handler
```
### Additional size reduction
```bash
# Install upx
brew install upx # macOS
apt install upx # Linux
# Compress binary
upx --best --lzma target/release/myapp
```
**Before/After example:**
```
Original: 2.5 MB
Optimized: 1.2 MB (strip = true)
UPX: 400 KB (upx --best --lzma)
```
## Package Distribution
### Homebrew (macOS/Linux)
Create a formula:
```ruby
# Formula/myapp.rb
class Myapp < Formula
desc "Description of your CLI tool"
homepage "https://github.com/username/myapp"
url "https://github.com/username/myapp/archive/v1.0.0.tar.gz"
sha256 "abc123..."
license "MIT"
depends_on "rust" => :build
def install
system "cargo", "install", "--locked", "--root", prefix, "--path", "."
# Install shell completions
generate_completions_from_executable(bin/"myapp", "--generate")
# Install man page
man1.install "target/man/myapp.1"
end
test do
assert_match "myapp 1.0.0", shell_output("#{bin}/myapp --version")
end
end
```
### Debian Package (.deb)
Using `cargo-deb`:
```bash
cargo install cargo-deb
# Create debian package
cargo deb
# Package will be in target/debian/myapp_1.0.0_amd64.deb
```
**Cargo.toml metadata:**
```toml
[package.metadata.deb]
maintainer = "Your Name <[email protected]>"
copyright = "2024, Your Name"
license-file = ["LICENSE", "4"]
extended-description = """
A longer description of your CLI tool
that spans multiple lines."""
depends = "$auto"
section = "utility"
priority = "optional"
assets = [
["target/release/myapp", "usr/bin/", "755"],
["README.md", "usr/share/doc/myapp/", "644"],
["target/completions/myapp.bash", "usr/share/bash-completion/completions/", "644"],
["target/man/myapp.1", "usr/share/man/man1/", "644"],
]
```
### Docker Distribution
```dockerfile
# Dockerfile
FROM rust:1.75 as builder
WORKDIR /app
COPY . .
RUN cargo build --release
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/myapp /usr/local/bin/myapp
ENTRYPOINT ["myapp"]
```
**Multi-stage with MUSL (smaller image):**
```dockerfile
FROM rust:1.75-alpine as builder
RUN apk add --no-cache musl-dev
WORKDIR /app
COPY . .
RUN cargo build --release --target x86_64-unknown-linux-musl
FROM scratch
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/myapp /myapp
ENTRYPOINT ["/myapp"]
```
### CargRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.