diff --git a/exec/doc.go b/exec/doc.go new file mode 100644 index 0000000..ddfb3f3 --- /dev/null +++ b/exec/doc.go @@ -0,0 +1,113 @@ +// Package exec provides simplified command execution utilities for running +// shell commands with enhanced error handling and output management. +// +// The package wraps Go's os/exec with convenience functions that handle +// common patterns like forwarding output to console, capturing combined +// output, and ignoring errors for optional operations. +// +// Key Features: +// - Execute commands with automatic stdout/stderr forwarding +// - Safe execution that never panics on errors +// - Environment variable support +// - Printf-style argument formatting +// - Combined output capture +// +// Basic Execution: +// +// // Execute a command and forward output to console +// err := exec.Exec("ls -la") +// +// // Execute with formatted arguments +// err := exec.Execf("echo 'Hello %s'", "World") +// +// // Execute with custom environment variables +// env := map[string]string{ +// "DEBUG": "true", +// "CONFIG_PATH": "/etc/app", +// } +// err := exec.ExecfWithEnv("./script.sh", env) +// +// Safe Execution: +// +// SafeExec executes commands and returns success status instead of errors, +// useful for optional operations or when you want to continue on failure: +// +// // Try to get git branch, continue if git isn't available +// branch, ok := exec.SafeExec("git rev-parse --abbrev-ref HEAD") +// if ok { +// fmt.Printf("Current branch: %s\n", branch) +// } +// +// // Check if a command exists +// _, exists := exec.SafeExec("which docker") +// if exists { +// // Docker is installed +// } +// +// Output Handling: +// +// // Exec forwards both stdout and stderr to console +// err := exec.Exec("make build") +// // User sees all output in real-time +// +// // SafeExec captures output and returns it +// output, ok := exec.SafeExec("cat /etc/hostname") +// if ok { +// fmt.Println("Hostname:", output) +// } +// +// Environment Variables: +// +// // Set environment for command execution +// env := map[string]string{ +// "PATH": "/usr/local/bin:/usr/bin", +// "DATABASE_URL": "postgres://localhost/mydb", +// } +// err := exec.ExecfWithEnv("migrate up", env) +// +// Error Handling: +// +// // Exec returns error with command output on failure +// if err := exec.Exec("./deploy.sh"); err != nil { +// // err contains both error and stderr output +// log.Fatal(err) +// } +// +// // SafeExec returns false on any error +// output, ok := exec.SafeExec("risky-command") +// if !ok { +// // Command failed, output is empty string +// log.Warn("Command failed, using default") +// } +// +// Formatted Commands: +// +// // Use printf-style formatting for dynamic commands +// filename := "data.json" +// err := exec.Execf("cat %s | jq .", filename) +// +// // Multiple arguments +// src := "/source" +// dst := "/dest" +// err := exec.Execf("rsync -av %s %s", src, dst) +// +// Common Use Cases: +// +// // Run build commands +// exec.Exec("go build -o app ./cmd/server") +// +// // Check tool availability +// if _, ok := exec.SafeExec("which kubectl"); !ok { +// log.Fatal("kubectl not found in PATH") +// } +// +// // Get version information +// version, ok := exec.SafeExec("app --version") +// +// // Run tests with environment +// env := map[string]string{"TEST_ENV": "integration"} +// exec.ExecfWithEnv("go test ./...", env) +// +// Note: All commands are executed through bash -c, providing full shell +// functionality including pipes, redirects, and variable expansion. +package exec diff --git a/files/doc.go b/files/doc.go new file mode 100644 index 0000000..d0586c1 --- /dev/null +++ b/files/doc.go @@ -0,0 +1,104 @@ +// Package files provides utilities for file operations, archive handling, +// and path manipulation. +// +// The package offers comprehensive support for working with various archive +// formats (tar, zip, gzip, xz), file path validation, glob pattern matching, +// and common file operations. +// +// Key Features: +// - Archive extraction with detailed results and statistics +// - Support for tar, tar.gz, tar.xz, and zip formats +// - Path traversal vulnerability protection +// - Glob pattern matching with doublestar support +// - File compression and decompression +// - Safe file operations with validation +// +// Archive Extraction: +// +// // Simple extraction +// err := files.UnarchiveSimple("package.tar.gz", "/dest") +// +// // Extraction with detailed results +// result, err := files.Unarchive("package.tar.gz", "/dest") +// fmt.Printf("Extracted %d files (%s)\n", len(result.Files), result.String()) +// +// // Extraction with options +// result, err := files.Unarchive("archive.zip", "/dest", +// files.WithOverwrite(true)) +// +// // Extract only executables +// err := files.UnarchiveExecutables("binaries.tar.gz", "/usr/local/bin") +// +// Compression: +// +// // Gzip a file +// data, err := files.GzipFile("document.txt") +// +// // Create a zip archive +// err := files.Zip("/source/dir", "archive.zip") +// +// // Decompress xz +// err := files.Unxz("file.xz", "file.txt") +// +// // Decompress gzip +// err := files.Ungzip("file.gz", "file.txt") +// +// Path Operations: +// +// // Validate path (check for traversal attacks) +// err := files.ValidatePath("../../etc/passwd") // Returns error +// +// // Check file type by extension +// if files.IsValidPathType("config.yaml", ".yaml", ".yml") { +// // Process YAML file +// } +// +// // Get base name without extension +// name := files.GetBaseName("config.yaml") // "config" +// +// Glob Matching: +// +// // Expand glob patterns +// matches, err := files.UnfoldGlobs("**/*.go", "**/*.yaml") +// +// // Match with doublestar patterns +// files, err := files.DoubleStarGlob("/project", []string{"**/*.go"}) +// +// File Operations: +// +// // Check if file exists +// if files.Exists("/path/to/file") { +// // File exists +// } +// +// // Safe read (returns empty string on error) +// content := files.SafeRead("/path/to/file") +// +// // Copy file +// err := files.Copy("/source/file", "/dest/file") +// +// // Copy from reader with permissions +// n, err := files.CopyFromReader(reader, "/dest/file", 0644) +// +// // Create temp file with custom name +// tmpFile := files.TempFileName("prefix-", ".txt") +// +// Archive Results: +// +// The Archive type provides detailed information about extraction operations: +// +// result, _ := files.Unarchive("package.tar.gz", "/dest") +// fmt.Printf("Files: %d\n", len(result.Files)) +// fmt.Printf("Directories: %d\n", len(result.Directories)) +// fmt.Printf("Symlinks: %d\n", len(result.Symlinks)) +// fmt.Printf("Size: %s -> %s (%.1f%% compression)\n", +// formatSize(result.CompressedSize), +// formatSize(result.ExtractedSize), +// result.CompressionRatio*100) +// +// Security: +// +// The package includes protection against path traversal vulnerabilities +// when extracting archives. All paths are validated to ensure they don't +// escape the destination directory. +package files diff --git a/is/doc.go b/is/doc.go new file mode 100644 index 0000000..954ab44 --- /dev/null +++ b/is/doc.go @@ -0,0 +1,92 @@ +// Package is provides simple type checking and environment detection utilities. +// +// The package offers concise boolean functions for common type checks and +// runtime environment detection. All functions follow the pattern is.X() +// for readable, natural-language code. +// +// Key Features: +// - Type checking with reflection +// - File and archive detection +// - Terminal/TTY detection +// - Simple, readable API +// +// Type Checking: +// +// // Check if value is a slice +// data := []string{"a", "b", "c"} +// if is.Slice(data) { +// // data is a slice +// } +// +// // Works with any type +// numbers := []int{1, 2, 3} +// is.Slice(numbers) // true +// +// str := "hello" +// is.Slice(str) // false +// +// File Detection: +// +// // Check if file exists +// if is.File("/etc/hosts") { +// // File exists +// } +// +// // Check if file is an archive +// if is.Archive("package.tar.gz") { +// // Extract the archive +// } +// +// // Supported archive formats +// is.Archive("file.zip") // true +// is.Archive("file.tar.gz") // true +// is.Archive("file.gz") // true +// is.Archive("file.xz") // true +// is.Archive("file.txz") // true +// is.Archive("file.txt") // false +// +// Terminal Detection: +// +// // Check if running in an interactive terminal +// if is.TTY() { +// // Enable colored output, progress bars, etc. +// fmt.Println("\033[32mGreen text\033[0m") +// } else { +// // Plain output for logs, pipes, redirects +// fmt.Println("Plain text") +// } +// +// Common Use Cases: +// +// // Conditional output formatting +// if is.TTY() { +// showProgressBar() +// } else { +// logToFile() +// } +// +// // File processing +// if is.File(configPath) { +// loadConfig(configPath) +// } +// +// // Archive handling +// if is.Archive(input) { +// extractArchive(input) +// } else { +// processFile(input) +// } +// +// // Generic type checking +// if is.Slice(value) { +// processSlice(value) +// } +// +// Limitations: +// +// The Slice function uses reflection and only checks if a value is a slice type. +// It doesn't validate slice element types or other slice properties. +// +// The Archive function only checks file extensions, not actual file content. +// For robust archive detection, consider inspecting file headers/magic numbers. +package is diff --git a/text/doc.go b/text/doc.go new file mode 100644 index 0000000..9c65c19 --- /dev/null +++ b/text/doc.go @@ -0,0 +1,84 @@ +// Package text provides utilities for text processing, formatting, and +// manipulation. +// +// The package includes functions for humanizing numbers and durations, +// indenting text, parsing extended duration formats, and safe I/O operations. +// +// Key Features: +// - Human-readable formatting for bytes, numbers, and durations +// - Text indentation for hierarchical output +// - Extended duration parsing (days, weeks, years) +// - Safe I/O operations that never panic +// +// Byte and Number Formatting: +// +// // Format bytes in human-readable form +// text.HumanizeBytes(1536) // "1.5 KB" +// text.HumanizeBytes(1048576) // "1.0 MB" +// text.HumanizeBytes(5368709120) // "5.0 GB" +// +// // Format large numbers with thousand separators +// text.HumanizeInt(1000000) // "1,000,000" +// text.HumanizeInt(42) // "42" +// +// Duration Formatting: +// +// // Format durations in human-readable form +// text.HumanizeDuration(90 * time.Minute) // "1h30m" +// text.HumanizeDuration(25 * time.Hour) // "1d1h" +// text.HumanizeDuration(8 * 24 * time.Hour) // "1w1d" +// +// // Calculate age since a time +// created := time.Now().Add(-48 * time.Hour) +// text.Age(created) // "2d" +// +// Duration Parsing: +// +// Parse durations with extended units beyond the standard Go time.Duration: +// +// d, err := text.ParseDuration("3d") // 72 hours +// d, err := text.ParseDuration("1w") // 168 hours +// d, err := text.ParseDuration("2y") // ~17520 hours +// d, err := text.ParseDuration("1d12h30m") // 36.5 hours +// +// Supported units: ns, us/µs, ms, s, m, h, d (days), w (weeks), y (years) +// +// Text Indentation: +// +// // Indent a string +// indented := text.String(" ", "line1\nline2\nline3") +// // " line1\n line2\n line3" +// +// // Indent bytes +// data := []byte("line1\nline2") +// indented := text.Bytes(" ", data) +// +// // Create an indenting writer +// writer := text.NewWriter(os.Stdout, " ") +// fmt.Fprintln(writer, "This will be indented") +// fmt.Fprintln(writer, "So will this") +// +// Safe I/O: +// +// // Read from reader without error handling +// resp, _ := http.Get("https://example.com") +// defer resp.Body.Close() +// content := text.SafeRead(resp.Body) // Empty string on error +// +// Formatting Examples: +// +// // Display file sizes +// fmt.Printf("Size: %s\n", text.HumanizeBytes(fileSize)) +// +// // Display request counts +// fmt.Printf("Requests: %s\n", text.HumanizeInt(requestCount)) +// +// // Display uptime +// fmt.Printf("Uptime: %s\n", text.HumanizeDuration(time.Since(startTime))) +// +// // Display last updated +// fmt.Printf("Updated: %s ago\n", text.Age(lastModified)) +// +// Related Packages: +// - duration: Extended duration parsing (used internally) +package text