Add OpenSpec change for pkg modularization refactor
This commit is contained in:
@@ -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
|
||||||
Reference in New Issue
Block a user