163 lines
3.9 KiB
Markdown
163 lines
3.9 KiB
Markdown
# Quickstart: Safety, Reliability & Idiomatic Refactor
|
|
|
|
**Feature Branch**: `001-safety-reliability-refactor`
|
|
**Date**: 2026-03-03
|
|
|
|
## Prerequisites
|
|
|
|
- **Go 1.20** toolchain installed (must be exactly 1.20.x, not newer)
|
|
- Administrator/root privileges (required to write the hosts file)
|
|
- Git
|
|
|
|
## Setup
|
|
|
|
```bash
|
|
# Clone and switch to feature branch
|
|
git checkout 001-safety-reliability-refactor
|
|
|
|
# Verify Go version
|
|
go version
|
|
# Expected: go version go1.20.x ...
|
|
|
|
# Download dependencies
|
|
go mod download
|
|
|
|
# Run all tests
|
|
go test ./...
|
|
|
|
# Build
|
|
go build -o dns-helper .
|
|
```
|
|
|
|
## Project Structure After Refactor
|
|
|
|
```
|
|
dns-helper/
|
|
├── main.go # Entry point, CLI parsing, os.Exit
|
|
├── resolver/
|
|
│ ├── resolver.go # DNS resolution via golang.org/x/net/dns/dnsmessage
|
|
│ └── resolver_test.go
|
|
├── hostfile/
|
|
│ ├── hostfile.go # Hosts file read/write (atomic pattern)
|
|
│ ├── hostfile_test.go
|
|
│ ├── managed.go # Managed block parsing, add, remove
|
|
│ └── managed_test.go
|
|
├── platform/
|
|
│ ├── platform.go # Interface definition
|
|
│ ├── platform_windows.go # Windows hosts file path
|
|
│ ├── platform_linux.go # Linux hosts file path
|
|
│ ├── platform_darwin.go # macOS hosts file path
|
|
│ └── platform_test.go
|
|
├── lockfile/
|
|
│ ├── lockfile.go # Lock file acquisition/release
|
|
│ └── lockfile_test.go
|
|
├── go.mod # go 1.20, golang.org/x/net v0.35.0
|
|
└── go.sum
|
|
```
|
|
|
|
## Key Implementation Patterns
|
|
|
|
### TDD Workflow (Constitution Principle VI)
|
|
|
|
Every change follows Red-Green-Refactor:
|
|
|
|
1. **Red**: Write a failing test that specifies the desired behavior.
|
|
2. **Green**: Write the minimum code to make the test pass.
|
|
3. **Refactor**: Clean up while keeping tests green.
|
|
|
|
```bash
|
|
# Run tests for a specific package
|
|
go test ./resolver/
|
|
go test ./hostfile/
|
|
go test ./lockfile/
|
|
|
|
# Run all tests
|
|
go test ./...
|
|
```
|
|
|
|
### Error Handling (Constitution Principle IV)
|
|
|
|
All functions return errors. Only `main()` calls `os.Exit()`:
|
|
|
|
```go
|
|
// WRONG — do not do this in any package
|
|
func doSomething() {
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
os.Exit(1) // PROHIBITED outside main()
|
|
}
|
|
}
|
|
|
|
// CORRECT — return errors to caller
|
|
func doSomething() error {
|
|
if err != nil {
|
|
return fmt.Errorf("doing something: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
```
|
|
|
|
### Testable Interfaces (Constitution Principle VI)
|
|
|
|
Functions that interact with filesystem or DNS accept interfaces:
|
|
|
|
```go
|
|
// Production: uses real OS calls
|
|
manager := hostfile.NewManager(hostfile.NewOSFileSystem())
|
|
|
|
// Test: uses in-memory fake
|
|
manager := hostfile.NewManager(fakeFS)
|
|
```
|
|
|
|
### Atomic Write Sequence
|
|
|
|
```
|
|
1. Backup: copy hosts → <exe-dir>/hosts.bak.<date>-<rand>
|
|
2. Write: assemble content → temp file (same dir as hosts)
|
|
3. Sync: temp.Sync()
|
|
4. Chmod: match original permissions
|
|
5. Close: temp.Close()
|
|
6. Rename: os.Rename(temp, hosts) [retry on Windows]
|
|
7. Clean: delete backup on success
|
|
```
|
|
|
|
## Usage Examples
|
|
|
|
```bash
|
|
# Add DNS entries
|
|
dns-helper add -host myapp.example.com -server 10.0.0.53
|
|
|
|
# Add multiple hosts
|
|
dns-helper add -host host1.example.com,host2.example.com -server dns.internal
|
|
|
|
# Delete specific host entries
|
|
dns-helper delete -host myapp.example.com
|
|
|
|
# Delete all managed entries
|
|
dns-helper delete all
|
|
```
|
|
|
|
## Build for All Platforms
|
|
|
|
```bash
|
|
# Windows
|
|
GOOS=windows GOARCH=amd64 go build -o bin/windows/dns-helper.exe .
|
|
|
|
# Linux
|
|
GOOS=linux GOARCH=amd64 go build -o bin/linux/dns-helper .
|
|
|
|
# macOS
|
|
GOOS=darwin GOARCH=amd64 go build -o bin/macos/dns-helper .
|
|
```
|
|
|
|
## Dependency Management
|
|
|
|
```bash
|
|
# After removing miekg/dns and adding dnsmessage usage:
|
|
go mod tidy
|
|
|
|
# Verify no unapproved dependencies
|
|
go list -m all
|
|
# Should only show: golang.org/x/net, golang.org/x/sys (transitive)
|
|
```
|