My App

Building from source

Build, test, and lint go-udap locally

Building from source

Prerequisites

  • Go 1.26 or later (see go.mod)
  • Task (optional, for build automation)
  • prek (optional, for pre-commit hooks)

Build

# Build optimized binary for current platform
task build

# Run tests
task test

# Run tests with verbose output
task test:verbose

# Format code
task fmt

# Run linter
task lint

# Clean build artifacts
task clean

Using Go Directly

# Development build
go build -o go-udap .

# Optimized build (smaller binary)
go build -ldflags="-s -w" -trimpath -o go-udap .

# Run tests (with race detector)
go test -race ./...

Testing

Running Tests

# All tests
task test

# Verbose output
task test:verbose

# With coverage report
task test:coverage

Manual Testing

With a physical Squeezebox device:

  1. Put the device in setup mode by holding the front button for ~3 seconds until the LED blinks slow red (or factory-reset by holding ~6 seconds until it blinks fast red — see the wiki).
  2. Run go-udap discover --info to confirm the device appears.
  3. Configure with set (use --reboot/-r to apply changes that take effect on reboot).
  4. Read back with read to verify (output is filtered to non-default values — pass --all to see everything).

Code Style

  • Follow standard Go formatting (go fmt)
  • Use go vet for static analysis
  • Structured logging with key-value pairs
  • Context-aware functions for cancellation support

Project Structure

go-udap/
├── main.go                       # 16-line entry point; calls cli.Run
├── cli/                          # CLI surface (one file per subcommand)
│   ├── cli.go                    # dispatcher, global flag hoisting
│   ├── discover.go info.go read.go get.go set.go reboot.go
│   ├── find.go                   # discover-and-find-by-MAC helper
│   ├── params.go                 # CLI flag table derived from udap.Parameters
│   ├── source.go                 # layered set sources (file/stdin/flags)
│   ├── config.go                 # INI parser
│   ├── output.go                 # formatParamMap, formatDeviceInfo
│   ├── progress.go stderr.go     # TTY progress bar + log/bar mutex
│   └── *_test.go                 # unit tests
├── udap/                         # protocol + transport
│   ├── client.go                 # UDP socket, packet builders, capture
│   ├── discovery.go              # broadcast + listener, RWMutex-protected device map
│   ├── config.go                 # GetData / SetData / Reset (WithContext)
│   ├── protocol.go               # Packet struct, ParsePacket, constants
│   ├── parameters.go             # ★ single source of truth for 26 NVRAM params
│   ├── getdata_response.go       # offset/length/value response decoder
│   ├── loopback.go               # isUDAPRequestPacket — kernel-loopback filter
│   ├── validation.go             # parameter / packet validation
│   ├── logger.go                 # structured logger (takes io.Writer)
│   ├── socket_unix.go            # SO_BROADCAST via SyscallConn().Control
│   ├── socket_windows.go
│   ├── testdata/captures/*.bin   # captured Net::UDAP wire payloads
│   └── *_test.go
├── docs/superpowers/             # planning specs/plans (history)
├── Taskfile.yml                  # Task automation
├── go.mod / go.sum               # module definition (Go 1.26.3, only pflag dep)
└── README.md / CLAUDE.md

On this page