# zutils Development Guide ## Quick Start 1. **Build the project:** ```bash go build -o zutils ``` 2. **Test locally:** ```bash ./zutils info main.go ``` 3. **Install to system:** ```bash ./install.sh ``` ## Project Architecture ### Directory Structure ``` zutils/ ├── cmd/ # Command implementations │ ├── info.go # Main info command router │ ├── file.go # File info handler │ ├── dir.go # Directory info handler │ ├── network.go # Network info handler │ └── autodetect.go # Auto-detection logic ├── pkg/ # Shared packages │ ├── colors/ # ANSI color constants │ ├── formatter/ # Output formatting utilities │ └── types/ # Command registry and types ├── examples/ # Example files for testing ├── main.go # Application entry point └── go.mod # Go module definition ``` ### How It Works 1. **Entry Point (`main.go`):** - Creates a command registry - Registers all available commands - Parses command-line arguments - Routes to appropriate command handler 2. **Command Registry (`pkg/types/registry.go`):** - Manages all available commands - Provides registration and lookup functionality - Makes it easy to add new commands 3. **Command Handlers (`cmd/`):** - Each command has its own file - Implements the handler function - Uses shared utilities for output formatting 4. **Shared Utilities (`pkg/`):** - `colors/`: ANSI color codes for terminal output - `formatter/`: Utility functions for formatting output - `types/`: Command registry and type definitions ## Adding a New Command ### Step 1: Create the Command File Create a new file in `cmd/` directory: ```go // cmd/hello.go package cmd import ( "fmt" "github.com/zemenawi/zutils/pkg/colors" ) func HelloCommand(args []string) error { fmt.Printf("%s%sHello, World!%s\n", colors.Green, colors.Bold, colors.Reset) return nil } ``` ### Step 2: Register the Command Add registration in `main.go`: ```go // After existing registrations registry.Register(&types.Command{ Name: "hello", Description: "Print a greeting", Handler: cmd.HelloCommand, }) ``` ### Step 3: Test Your Command ```bash go build -o zutils ./zutils hello ``` ## Best Practices ### 1. Use Shared Colors ```go import "github.com/zemenawi/zutils/pkg/colors" fmt.Printf("%sSuccess message%s\n", colors.Green, colors.Reset) fmt.Printf("%sWarning message%s\n", colors.Yellow, colors.Reset) fmt.Printf("%sError message%s\n", colors.Red, colors.Reset) ``` ### 2. Use Formatter Utilities ```go import "github.com/zemenawi/zutils/pkg/formatter" size := formatter.FormatSize(1234567) // "1.18 MB" ``` ### 3. Print Box Headers ```go cmd.PrintBoxHeader("MY HEADER", colors.Cyan) ``` ### 4. Print Section Headers ```go cmd.PrintSectionHeader("MY SECTION") ``` ### 5. Return Errors Always return errors from command handlers: ```go func MyCommand(args []string) error { if len(args) < 1 { return fmt.Errorf("missing argument") } // Your logic here return nil } ``` ## Color Palette | Color | Usage | Constant | |-------|-------|----------| | Red | Errors | `colors.Red` | | Green | Success, positive info | `colors.Green` | | Yellow | Warnings, secondary info | `colors.Yellow` | | Blue | Primary labels | `colors.Blue` | | Purple | Directory info | `colors.Purple` | | Cyan | Network info, values | `colors.Cyan` | | Gray | Separators | `colors.Gray` | ## Command Pattern All commands follow this pattern: ```go package cmd import ( "fmt" "github.com/zemenawi/zutils/pkg/colors" "github.com/zemenawi/zutils/pkg/formatter" ) func MyCommand(args []string) error { // Validate arguments if len(args) < 1 { return fmt.Errorf("please specify an argument") } // Print header PrintBoxHeader("MY COMMAND", colors.Cyan) // Your logic here fmt.Printf("%s%sProcessing: %s%s\n", colors.Blue, colors.Bold, args[0], colors.Reset) // Print sections PrintSectionHeader("DETAILS") fmt.Printf("Size: %s\n", formatter.FormatSize(1234)) fmt.Println() return nil } ``` ## Auto-Detection The info command supports auto-detection of files vs directories: ```go // AutoDetectInfo in cmd/autodetect.go func AutoDetectInfo(target string) error { // Checks if path is file or directory // Calls appropriate handler } ``` This allows: ```bash z main.go # Detects as file z . # Detects as directory ``` ## Testing Commands ### Unit Tests Create test files alongside your commands: ```go // cmd/hello_test.go package cmd import "testing" func TestHelloCommand(t *testing.T) { err := HelloCommand([]string{}) if err != nil { t.Errorf("HelloCommand failed: %v", err) } } ``` ### Integration Tests Test the full command line: ```bash go build -o zutils ./zutils hello ``` ## Common Tasks ### Adding a New Color Edit `pkg/colors/colors.go`: ```go const ( // Existing colors... MyColor = "\033[38;5;123m" // RGB color ) ``` ### Adding a New Formatter Edit `pkg/formatter/utils.go`: ```go func MyFormatter(value interface{}) string { // Your logic return formattedValue } ``` ### Adding Command Aliases Register multiple commands with the same handler: ```go registry.Register(&types.Command{ Name: "info", Description: "Get information", Handler: cmd.InfoCommand, }) registry.Register(&types.Command{ Name: "i", Description: "Info (alias)", Handler: cmd.InfoCommand, }) ``` ## Debugging ### Enable Debug Output Add a debug flag to your command: ```go import "flag" func MyCommand(args []string) error { debug := flag.Bool("debug", false, "Enable debug output") flag.Parse() if *debug { fmt.Println("Debug mode enabled") } // ... } ``` ### Print Structured Data Use JSON for debugging complex data: ```go import "encoding/json" func MyCommand(args []string) error { data := map[string]interface{}{ "args": args, "path": "/some/path", } jsonBytes, _ := json.MarshalIndent(data, "", " ") fmt.Println(string(jsonBytes)) return nil } ``` ## Performance Tips 1. **Avoid unnecessary file operations:** ```go // Good info, _ := os.Stat(path) size := info.Size() // Bad content, _ := os.ReadFile(path) size := int64(len(content)) ``` 2. **Use buffered I/O:** ```go scanner := bufio.NewScanner(file) for scanner.Scan() { // Process line } ``` 3. **Limit directory scanning:** ```go if stats.FileCount > 1000 { return // Stop scanning } ``` ## Cross-Platform Considerations ### Path Handling Always use `filepath` package: ```go import "path/filepath" path := filepath.Join("dir", "file.txt") abs, _ := filepath.Abs(path) ``` ### OS-Specific Code Use build tags or runtime checks: ```go import "runtime" if runtime.GOOS == "windows" { // Windows-specific code } else if runtime.GOOS == "linux" { // Linux-specific code } ``` ## Resources - [Go Documentation](https://golang.org/doc/) - [Go Standard Library](https://golang.org/pkg/) - [Effective Go](https://golang.org/doc/effective_go.html) ## Getting Help If you're stuck: 1. Check existing commands for examples 2. Read the command registry implementation 3. Look at shared utilities in `pkg/` 4. Test incrementally with small changes Happy coding! 🚀