zutils/DEVELOPMENT.md
selamanapps aeae34365c feat: add zutils v0.2.0 with professional table formatting
- Add directory information with Unicode table borders
- Add network information with professional formatting
- Add version command
- Add comprehensive documentation (README.md, DEVELOPMENT.md)
- Improve table output with proper borders and alignment
- Add project structure (cmd/, pkg/ directories)
2026-05-02 00:05:44 +03:00

7.5 KiB

zutils Development Guide

Quick Start

  1. Build the project:

    go build -o zutils
    
  2. Test locally:

    ./zutils info main.go
    
  3. Install to system:

    ./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:

// 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:

// After existing registrations
registry.Register(&types.Command{
    Name:        "hello",
    Description: "Print a greeting",
    Handler:     cmd.HelloCommand,
})

Step 3: Test Your Command

go build -o zutils
./zutils hello

Best Practices

1. Use Shared Colors

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

import "github.com/zemenawi/zutils/pkg/formatter"

size := formatter.FormatSize(1234567)  // "1.18 MB"

3. Print Box Headers

cmd.PrintBoxHeader("MY HEADER", colors.Cyan)

4. Print Section Headers

cmd.PrintSectionHeader("MY SECTION")

5. Return Errors

Always return errors from command handlers:

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:

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:

// AutoDetectInfo in cmd/autodetect.go
func AutoDetectInfo(target string) error {
    // Checks if path is file or directory
    // Calls appropriate handler
}

This allows:

z main.go          # Detects as file
z .                # Detects as directory

Testing Commands

Unit Tests

Create test files alongside your commands:

// 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:

go build -o zutils
./zutils hello

Common Tasks

Adding a New Color

Edit pkg/colors/colors.go:

const (
    // Existing colors...
    MyColor = "\033[38;5;123m"  // RGB color
)

Adding a New Formatter

Edit pkg/formatter/utils.go:

func MyFormatter(value interface{}) string {
    // Your logic
    return formattedValue
}

Adding Command Aliases

Register multiple commands with the same handler:

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:

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:

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:

    // Good
    info, _ := os.Stat(path)
    size := info.Size()
    
    // Bad
    content, _ := os.ReadFile(path)
    size := int64(len(content))
    
  2. Use buffered I/O:

    scanner := bufio.NewScanner(file)
    for scanner.Scan() {
        // Process line
    }
    
  3. Limit directory scanning:

    if stats.FileCount > 1000 {
        return // Stop scanning
    }
    

Cross-Platform Considerations

Path Handling

Always use filepath package:

import "path/filepath"

path := filepath.Join("dir", "file.txt")
abs, _ := filepath.Abs(path)

OS-Specific Code

Use build tags or runtime checks:

import "runtime"

if runtime.GOOS == "windows" {
    // Windows-specific code
} else if runtime.GOOS == "linux" {
    // Linux-specific code
}

Resources

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! 🚀