- 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)
394 lines
7.5 KiB
Markdown
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! 🚀
|