5 changed files with 226 additions and 0 deletions
@ -0,0 +1,2 @@ |
|||||||
|
schema: spec-driven |
||||||
|
created: 2026-04-14 |
||||||
@ -0,0 +1,141 @@ |
|||||||
|
# Design: Refactor pkg Into Modular Packages |
||||||
|
|
||||||
|
## New Structure |
||||||
|
|
||||||
|
``` |
||||||
|
pkg/ |
||||||
|
├── pacman/ # write operations only |
||||||
|
│ └── pacman.go |
||||||
|
├── fetch/ # package resolution (NEW) |
||||||
|
│ └── fetch.go |
||||||
|
├── validation/ # DB freshness (existing, expand) |
||||||
|
│ └── validation.go |
||||||
|
├── output/ # (unchanged) |
||||||
|
│ └── output.go |
||||||
|
├── merge/ # (unchanged) |
||||||
|
│ └── merge.go |
||||||
|
└── input/ # (unchanged) |
||||||
|
└── input.go |
||||||
|
``` |
||||||
|
|
||||||
|
## Package Responsibilities |
||||||
|
|
||||||
|
### pkg/fetch (NEW) |
||||||
|
|
||||||
|
``` |
||||||
|
type Fetcher struct { |
||||||
|
handle dyalpm.Handle |
||||||
|
localDB dyalpm.Database |
||||||
|
syncDBs []dyalpm.Database |
||||||
|
aurCache map[string]AURPackage |
||||||
|
} |
||||||
|
|
||||||
|
func New() *Fetcher |
||||||
|
func (f *Fetcher) Close() error |
||||||
|
func (f *Fetcher) Resolve(packages []string) (map[string]*PackageInfo, error) |
||||||
|
func (f *Fetcher) ListOrphans() ([]string, error) |
||||||
|
``` |
||||||
|
|
||||||
|
Extracted from `pacman.go`: |
||||||
|
- `buildLocalPkgMap()` |
||||||
|
- `checkSyncDBs()` |
||||||
|
- `resolvePackages()` |
||||||
|
- AUR cache (`ensureAURCache()`, `fetchAURInfo()`) |
||||||
|
|
||||||
|
### pkg/pacman (REFACTORED) |
||||||
|
|
||||||
|
``` |
||||||
|
func Sync(packages []string) (*output.Result, error) |
||||||
|
func DryRun(packages []string) (*output.Result, error) |
||||||
|
func MarkAsExplicit(packages []string) error |
||||||
|
func MarkAllAsDeps() error |
||||||
|
func CleanupOrphans() (int, error) |
||||||
|
``` |
||||||
|
|
||||||
|
Write actions only: |
||||||
|
- `Sync()` - calls `Fetcher` for resolution, then pacman commands |
||||||
|
- `DryRun()` - calls `Fetcher.Resolve()` + `ListOrphans()` |
||||||
|
- `MarkAsExplicit()`, `MarkAllAsDeps()` |
||||||
|
- `CleanupOrphans()` - calls `ListOrphans()` then removes |
||||||
|
|
||||||
|
### pkg/validation (REFACTORED) |
||||||
|
|
||||||
|
``` |
||||||
|
func CheckDBFreshness() error |
||||||
|
``` |
||||||
|
|
||||||
|
Keep as-is: checks lock file age, auto-synces if stale. |
||||||
|
|
||||||
|
Remove from `pacman.go`: |
||||||
|
- `IsDBFresh()` - replaced by `CheckDBFreshness()` |
||||||
|
- `SyncDB()` - called by validation when stale |
||||||
|
|
||||||
|
### Orphan Deduplication |
||||||
|
|
||||||
|
```go |
||||||
|
// In fetch/fetch.go |
||||||
|
func (f *Fetcher) ListOrphans() ([]string, error) { |
||||||
|
cmd := exec.Command("pacman", "-Qdtq") |
||||||
|
// ... |
||||||
|
} |
||||||
|
|
||||||
|
// In pacman/pacman.go |
||||||
|
func CleanupOrphans() (int, error) { |
||||||
|
orphans, err := fetcher.ListOrphans() // reuse |
||||||
|
if err != nil || len(orphans) == 0 { |
||||||
|
return 0, nil |
||||||
|
} |
||||||
|
// ... remove |
||||||
|
} |
||||||
|
|
||||||
|
func DryRun(...) (*output.Result, error) { |
||||||
|
orphans, err := fetcher.ListOrphans() // reuse |
||||||
|
// ... |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
## Data Structures Move to fetch |
||||||
|
|
||||||
|
```go |
||||||
|
// In fetch/fetch.go |
||||||
|
type PackageInfo struct { |
||||||
|
Name string |
||||||
|
InAUR bool |
||||||
|
Exists bool |
||||||
|
Installed bool |
||||||
|
AURInfo *AURPackage |
||||||
|
syncPkg dyalpm.Package |
||||||
|
} |
||||||
|
|
||||||
|
type AURResponse struct { |
||||||
|
Results []AURPackage `json:"results"` |
||||||
|
} |
||||||
|
|
||||||
|
type AURPackage struct { |
||||||
|
Name string `json:"Name"` |
||||||
|
PackageBase string `json:"PackageBase"` |
||||||
|
Version string `json:"Version"` |
||||||
|
URL string `json:"URL"` |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
## Import Changes |
||||||
|
|
||||||
|
`pkg/pacman/fetch.go` will need: |
||||||
|
- `github.com/Jguer/dyalpm` |
||||||
|
- `github.com/Riyyi/declpac/pkg/output` |
||||||
|
|
||||||
|
`pkg/pacman/pacman.go` will need: |
||||||
|
- `github.com/Riyyi/declpac/pkg/fetch` |
||||||
|
- `github.com/Riyyi/declpac/pkg/output` |
||||||
|
|
||||||
|
## Dependencies to Add |
||||||
|
|
||||||
|
- New import: `pkg/fetch` in `pacman` package |
||||||
|
|
||||||
|
## No Changes To |
||||||
|
|
||||||
|
- CLI entry points |
||||||
|
- `output.Result` struct |
||||||
|
- `input.ReadPackages()` |
||||||
|
- `merge.Merge()` |
||||||
@ -0,0 +1,30 @@ |
|||||||
|
# Proposal: Refactor pkg Into Modular Packages |
||||||
|
|
||||||
|
## Summary |
||||||
|
|
||||||
|
Split monolithic `pkg/pacman/pacman.go` into focused packages: `fetch` (package resolution), `validation` (DB checks), and keep `pacman` for write actions only. Also deduplicate orphan detection logic. |
||||||
|
|
||||||
|
## Motivation |
||||||
|
|
||||||
|
`pacman.go` is 645 lines doing too much: |
||||||
|
- Package resolution (local + sync DBs + AUR) |
||||||
|
- DB freshness checks |
||||||
|
- Pacman write operations (sync, mark, clean) |
||||||
|
- Orphan listing/cleanup |
||||||
|
|
||||||
|
This violates single responsibility. Hard to test, reason about, or reuse. Also has duplication: |
||||||
|
- `validation.CheckDBFreshness()` and `pacman.IsDBFresh()` both check DB freshness |
||||||
|
- `listOrphans()` and `CleanupOrphans()` duplicate orphan detection |
||||||
|
|
||||||
|
## Scope |
||||||
|
|
||||||
|
- Extract package resolution to new `pkg/fetch/` |
||||||
|
- Move DB freshness to `pkg/validation/` (keep `CheckDBFreshness()`) |
||||||
|
- Keep only write actions in `pkg/pacman/` |
||||||
|
- Deduplicate orphan logic: one function for listing, reuse in cleanup and dry-run |
||||||
|
|
||||||
|
## Out of Scope |
||||||
|
|
||||||
|
- No new features |
||||||
|
- No API changes to CLI |
||||||
|
- No changes to `pkg/output/`, `pkg/merge/`, `pkg/input/` |
||||||
@ -0,0 +1,15 @@ |
|||||||
|
# Scope |
||||||
|
|
||||||
|
## In Scope |
||||||
|
|
||||||
|
- Extract package resolution from pacman.go to pkg/fetch |
||||||
|
- Deduplicate orphan listing |
||||||
|
- Keep pacman write operations in pacman package |
||||||
|
- Maintain existing CLI API |
||||||
|
|
||||||
|
## Out of Scope |
||||||
|
|
||||||
|
- New features |
||||||
|
- New package management backends (e.g., libalpm alternatives) |
||||||
|
- Config file changes |
||||||
|
- State file format changes |
||||||
@ -0,0 +1,38 @@ |
|||||||
|
# Tasks: Refactor pkg Into Modular Packages |
||||||
|
|
||||||
|
## Phase 1: Create pkg/fetch |
||||||
|
|
||||||
|
- [ ] 1.1 Create `pkg/fetch/fetch.go` |
||||||
|
- [ ] 1.2 Move `AURResponse`, `AURPackage`, `PackageInfo` structs to fetch |
||||||
|
- [ ] 1.3 Move `buildLocalPkgMap()` to fetch as `Fetcher.buildLocalPkgMap()` |
||||||
|
- [ ] 1.4 Move `checkSyncDBs()` to fetch as `Fetcher.checkSyncDBs()` |
||||||
|
- [ ] 1.5 Move `resolvePackages()` to fetch as `Fetcher.Resolve()` |
||||||
|
- [ ] 1.6 Move AUR cache methods (`ensureAURCache`, `fetchAURInfo`) to fetch |
||||||
|
- [ ] 1.7 Add `New()` and `Close()` to Fetcher |
||||||
|
- [ ] 1.8 Add `ListOrphans()` to Fetcher |
||||||
|
|
||||||
|
## Phase 2: Refactor pkg/pacman |
||||||
|
|
||||||
|
- [ ] 2.1 Remove from pacman.go (now in fetch): |
||||||
|
- `buildLocalPkgMap()` |
||||||
|
- `checkSyncDBs()` |
||||||
|
- `resolvePackages()` |
||||||
|
- `ensureAURCache()` |
||||||
|
- `fetchAURInfo()` |
||||||
|
- `AURResponse`, `AURPackage`, `PackageInfo` structs |
||||||
|
- [ ] 2.2 Remove `IsDBFresh()` and `SyncDB()` (use validation instead) |
||||||
|
- [ ] 2.3 Update imports in pacman.go to include fetch package |
||||||
|
- [ ] 2.4 Update `Sync()` to use `fetch.Fetcher` for resolution |
||||||
|
- [ ] 2.5 Update `DryRun()` to call `fetcher.ListOrphans()` instead of duplicate call |
||||||
|
- [ ] 2.6 Update `CleanupOrphans()` to call `fetcher.ListOrphans()` instead of duplicate call |
||||||
|
|
||||||
|
## Phase 3: Clean Up Validation |
||||||
|
|
||||||
|
- [ ] 3.1 Keep `validation.CheckDBFreshness()` as-is |
||||||
|
- [ ] 3.2 Remove any remaining DB freshness duplication |
||||||
|
|
||||||
|
## Phase 4: Verify |
||||||
|
|
||||||
|
- [ ] 4.1 Run tests (if any exist) |
||||||
|
- [ ] 4.2 Build: `go build ./...` |
||||||
|
- [ ] 4.3 Verify CLI still works: test dry-run, sync, orphan cleanup |
||||||
Loading…
Reference in new issue