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