From 48afbca6920e745dbaa57bd46c4a4ff215c7f019 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Feb 2026 04:17:41 +0000 Subject: [PATCH 1/5] Initial plan From 3c48fe152aa2ecf4cd9078cfc40ae7ae7a74fbf3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Feb 2026 04:20:12 +0000 Subject: [PATCH 2/5] Add clear-caches directive to clear apt caches Co-authored-by: ericsuh <382805+ericsuh@users.noreply.github.com> --- aptfile/main.go | 16 ++++++++++++++++ aptfile/main_test.go | 5 +++++ main.go | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/aptfile/main.go b/aptfile/main.go index 73efd6e..46afb3f 100644 --- a/aptfile/main.go +++ b/aptfile/main.go @@ -57,6 +57,9 @@ type HoldDirective struct { PackageName string } +type ClearCachesDirective struct { +} + var ( ErrNoDirective = errors.New("no directive found") ErrParsing = errors.New("error parsing aptfile") @@ -158,6 +161,8 @@ func ParseLine(lineNum int, line string) (any, error) { return parsePinDirective(cmd, args, opts) case "hold": return parseHoldDirective(cmd, args, opts) + case "clear-caches": + return parseClearCachesDirective(cmd, args, opts) default: return nil, fmt.Errorf(`unexpected directive "%s"`, cmd) } @@ -296,3 +301,14 @@ func parseHoldDirective(_ string, args []string, opts map[string]string) (HoldDi PackageName: args[0], }, nil } + +// clear-caches directive is formatted like, `clear-caches` +func parseClearCachesDirective(_ string, args []string, opts map[string]string) (ClearCachesDirective, error) { + if len(args) > 0 { + return ClearCachesDirective{}, fmt.Errorf("expected no arguments, got %v", args) + } + if len(opts) > 0 { + return ClearCachesDirective{}, fmt.Errorf("unexpected options %v", opts) + } + return ClearCachesDirective{}, nil +} diff --git a/aptfile/main_test.go b/aptfile/main_test.go index ec70c30..346b108 100644 --- a/aptfile/main_test.go +++ b/aptfile/main_test.go @@ -84,6 +84,11 @@ func TestParseLine(t *testing.T) { line: "hold curl", expected: HoldDirective{PackageName: "curl"}, }, + { + name: "clear-caches directive", + line: "clear-caches", + expected: ClearCachesDirective{}, + }, { name: "invalid syntax", line: "package foo: bar", diff --git a/main.go b/main.go index fa840df..d4a1b37 100644 --- a/main.go +++ b/main.go @@ -117,6 +117,10 @@ func processAptfile(path string, dryRun bool) { if err := addHold(dir, dryRun); err != nil { log.Fatalf("Failed to add hold: %v", err) } + case aptfile.ClearCachesDirective: + if err := clearCaches(dryRun); err != nil { + log.Fatalf("Failed to clear caches: %v", err) + } default: log.Fatalf("Unknown directive: %v", d) } @@ -401,3 +405,34 @@ func addHold(hold aptfile.HoldDirective, dryRun bool) error { return fixCmd.Run() } } + +func clearCaches(dryRun bool) error { + if dryRun { + fmt.Println("[dry-run] Would run `apt-get clean`") + fmt.Println("[dry-run] Would remove /var/lib/apt/lists/*") + return nil + } + + fmt.Println("Clearing apt caches...") + + // Run apt-get clean to clear package cache + cleanCmd := exec.Command("apt-get", "clean") + cleanCmd.Env = append(os.Environ(), "DEBIAN_FRONTEND=noninteractive") + cleanCmd.Stdout = os.Stdout + cleanCmd.Stderr = os.Stderr + if err := cleanCmd.Run(); err != nil { + return fmt.Errorf("error running apt-get clean: %w", err) + } + + // Remove apt lists to reduce size further + fmt.Println("Removing apt package lists...") + rmCmd := exec.Command("rm", "-rf", "/var/lib/apt/lists/*") + rmCmd.Stdout = os.Stdout + rmCmd.Stderr = os.Stderr + if err := rmCmd.Run(); err != nil { + return fmt.Errorf("error removing apt lists: %w", err) + } + + fmt.Println("Cache clearing completed") + return nil +} From 4f8e7f82d5de2704a06064712fe07150d3b2ab9e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Feb 2026 04:21:17 +0000 Subject: [PATCH 3/5] Execute clear-caches after packages are installed and update README Co-authored-by: ericsuh <382805+ericsuh@users.noreply.github.com> --- README.md | 3 +++ main.go | 13 ++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3327081..7f4b7aa 100644 --- a/README.md +++ b/README.md @@ -36,5 +36,8 @@ hold "ffmpeg" # Use pins to control package source selection pin "*" 600, release: "l=NVIDIA CUDA" + +# Clear apt caches to reduce disk usage (useful for Docker images) +clear-caches ``` diff --git a/main.go b/main.go index d4a1b37..718a402 100644 --- a/main.go +++ b/main.go @@ -84,6 +84,7 @@ func processAptfile(path string, dryRun bool) { } pkgs := make([]aptfile.PackageDirective, 0) + clearCachesDirectives := make([]aptfile.ClearCachesDirective, 0) // First pass, skip package installation (except for .deb files, // which can be necessary for setting up repos or keyrings, etc.) @@ -118,9 +119,8 @@ func processAptfile(path string, dryRun bool) { log.Fatalf("Failed to add hold: %v", err) } case aptfile.ClearCachesDirective: - if err := clearCaches(dryRun); err != nil { - log.Fatalf("Failed to clear caches: %v", err) - } + // Defer clear-caches to run after packages are installed + clearCachesDirectives = append(clearCachesDirectives, dir) default: log.Fatalf("Unknown directive: %v", d) } @@ -130,6 +130,13 @@ func processAptfile(path string, dryRun bool) { if err != nil { log.Fatalf("Failed to install packages: %v", err) } + + // Execute clear-caches directives after packages are installed + for range clearCachesDirectives { + if err := clearCaches(dryRun); err != nil { + log.Fatalf("Failed to clear caches: %v", err) + } + } } func installPackages(pkgs []aptfile.PackageDirective, dryRun bool) error { From b93bd3eb4bdf995a4c737101f945e60433eada5b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Feb 2026 04:22:19 +0000 Subject: [PATCH 4/5] Fix clear-caches to run only once and fix glob expansion in rm command Co-authored-by: ericsuh <382805+ericsuh@users.noreply.github.com> --- main.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/main.go b/main.go index 718a402..394781c 100644 --- a/main.go +++ b/main.go @@ -131,8 +131,8 @@ func processAptfile(path string, dryRun bool) { log.Fatalf("Failed to install packages: %v", err) } - // Execute clear-caches directives after packages are installed - for range clearCachesDirectives { + // Execute clear-caches once if any directives exist + if len(clearCachesDirectives) > 0 { if err := clearCaches(dryRun); err != nil { log.Fatalf("Failed to clear caches: %v", err) } @@ -432,8 +432,9 @@ func clearCaches(dryRun bool) error { } // Remove apt lists to reduce size further + // Use sh -c to ensure glob expansion works fmt.Println("Removing apt package lists...") - rmCmd := exec.Command("rm", "-rf", "/var/lib/apt/lists/*") + rmCmd := exec.Command("sh", "-c", "rm -rf /var/lib/apt/lists/*") rmCmd.Stdout = os.Stdout rmCmd.Stderr = os.Stderr if err := rmCmd.Run(); err != nil { From 13cf2e87f39383bb813f2c334488138c5172ea12 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Feb 2026 04:43:14 +0000 Subject: [PATCH 5/5] Fix GoReleaser build in CI by adding snapshot flag Co-authored-by: ericsuh <382805+ericsuh@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0d3b238..1a52a9d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,4 +38,4 @@ jobs: - name: Run GoReleaser build uses: goreleaser/goreleaser-action@v6 with: - args: build + args: build --snapshot --clean