4 changed files with 139 additions and 0 deletions
@ -0,0 +1,2 @@
|
||||
schema: spec-driven |
||||
created: 2026-04-15 |
||||
@ -0,0 +1,66 @@
|
||||
## Implementation |
||||
|
||||
### Log File Location |
||||
- Path: `/var/log/declpac.log` |
||||
- Single merged log file (stdout + stderr intermingled in order of arrival) |
||||
|
||||
### State-Modifying Functions (need logging) |
||||
1. `SyncPackages()` - `pacman -S --needed <packages>` |
||||
2. `InstallAUR()` - `git clone` + `makepkg -si --noconfirm` |
||||
3. `MarkAllAsDeps()` - `pacman -D --asdeps` |
||||
4. `MarkAsExplicit()` - `pacman -D --asexplicit <packages>` |
||||
5. `CleanupOrphans()` - `pacman -Rns` |
||||
|
||||
### Functions to Skip (read-only) |
||||
- `DryRun()` - queries only |
||||
- `getInstalledCount()` - pacman -Qq |
||||
|
||||
### Execution Patterns |
||||
|
||||
| Pattern | Functions | How | |
||||
|---------|------------|-----| |
||||
| Streaming | MarkAllAsDeps, MarkAsExplicit, InstallAUR | `io.MultiWriter` to tee to both terminal and log | |
||||
| Captured | SyncPackages, CleanupOrphans | capture with `CombinedOutput()`, write to log, write to terminal | |
||||
|
||||
### Error Handling |
||||
- Write error to log BEFORE returning from function |
||||
- Print error to stderr so user sees it |
||||
|
||||
### Dependencies |
||||
- Add to imports: `io`, `os`, `path/filepath` |
||||
|
||||
### Structure |
||||
|
||||
```go |
||||
// pkg/state/state.go |
||||
var logFile *os.File |
||||
|
||||
func OpenLog() error { |
||||
logPath := filepath.Join("/var/log", "declpac.log") |
||||
f, err := os.OpenFile(logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
logFile = f |
||||
return nil |
||||
} |
||||
|
||||
func GetLogWriter() io.Writer { |
||||
return logFile |
||||
} |
||||
|
||||
func Close() error { |
||||
if logFile == nil { |
||||
return nil |
||||
} |
||||
return logFile.Close() |
||||
} |
||||
``` |
||||
|
||||
### Flow in Sync() or main entrypoint |
||||
1. Call `OpenLog()` at program start, defer close |
||||
2. Each state-modifying function uses `state.GetLogWriter()` via MultiWriter |
||||
|
||||
### Wire into main.go |
||||
- Open log at start of `run()` |
||||
- Pass log writer to pacman package (via exported function or global) |
||||
@ -0,0 +1,26 @@
|
||||
## Why |
||||
|
||||
The tool exits without saving the full pacman output, making debugging difficult |
||||
when operations fail. Users need a persistent log of all pacman operations for |
||||
debugging and audit. |
||||
|
||||
## What Changes |
||||
|
||||
- Add state directory initialization creating `~/.local/state/declpac` if not exists |
||||
- Open/manage a single log file at `$XDG_STATE_HOME/declpac` (e.g., `~/.local/state/declpac/declpac`) |
||||
- Instrument all state-modifying exec calls in `pkg/pacman/pacman.go` to tee or append output to this file |
||||
- Skip debug messages (internal timing logs) |
||||
- Capture and write errors before returning |
||||
|
||||
## Capabilities |
||||
|
||||
### New Capabilities |
||||
- Operation logging: Persist stdout/stderr from all pacman operations |
||||
|
||||
### Modified Capabilities |
||||
- None |
||||
|
||||
## Impact |
||||
|
||||
- `pkg/pacman/pacman.go`: Instrument all state-modifying functions to write to log file |
||||
- New module: May create `pkg/state/state.go` or similar for log file management |
||||
@ -0,0 +1,45 @@
|
||||
## Tasks |
||||
|
||||
- [x] 1. Create state module |
||||
|
||||
Create `pkg/state/state.go`: |
||||
- `OpenLog()` - opens `/var/log/declpac.log` in append mode |
||||
- `GetLogWriter()` - returns the raw log file writer (for MultiWriter) |
||||
- `Write(msg []byte)` - writes message with timestamp + dashes separator |
||||
- `Close()` - closes the file |
||||
|
||||
- [x] 2. Wire into main.go |
||||
|
||||
In `cmd/declpac/main.go` `run()`: |
||||
- Call `OpenLog()` at start |
||||
- `defer Close()` log |
||||
|
||||
- [x] 3. Instrument pkg/pacman |
||||
|
||||
Modify `pkg/pacman/pacman.go`: |
||||
|
||||
All state-modifying functions use `state.Write()` instead of `state.GetLogWriter().Write()`: |
||||
|
||||
``` |
||||
// OLD |
||||
state.GetLogWriter().Write(output) |
||||
|
||||
// NEW |
||||
state.Write(output) // auto-prepends timestamp |
||||
``` |
||||
|
||||
**Functions updated:** |
||||
- `SyncPackages()` - write output with timestamp |
||||
- `CleanupOrphans()` - write output with timestamp |
||||
- `MarkAllAsDeps()` - write operation name with timestamp before running |
||||
- `MarkAsExplicit()` - write operation name with timestamp before running |
||||
- `InstallAUR()` - write "Cloning ..." and "Building package..." with timestamps |
||||
- Error handling - `state.Write([]byte("error: ..."))` for all error paths |
||||
|
||||
- [x] 4. Add io import |
||||
|
||||
Add `io` to imports in pacman.go |
||||
|
||||
- [x] 5. Test |
||||
|
||||
Run a sync operation and verify log file created at `/var/log/declpac.log` |
||||
Loading…
Reference in new issue