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