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

394 lines
7.5 KiB
Markdown

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