Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

initial commit

  • Loading branch information...
commit 5d76d7aaabddd64d70f188a02dbf61a0b734fc9d 0 parents
@falconindy authored
Showing with 200 additions and 0 deletions.
  1. +11 −0 Makefile
  2. +9 −0 README
  3. +180 −0 gobble.go
11 Makefile
@@ -0,0 +1,11 @@
+include $(GOROOT)/src/Make.inc
+
+TARG=gobble
+GOFILES=\
+ gobble.go
+
+include $(GOROOT)/src/Make.cmd
+
+format: fmt
+fmt:
+ gofmt -w -tabindent=false -tabwidth=2 *.go
9 README
@@ -0,0 +1,9 @@
+Gobble
+------------------------------
+A package cleaner for Pacman.
+
+usage: gobble [flags]
+ -k=3: number of packages to keep
+ -c="/var/cache/pacman/pkg": path to package cache
+ -h=false: display this help message
+ -d=false: delete packages over keep limit
180 gobble.go
@@ -0,0 +1,180 @@
+package main
+
+import (
+ "exec"
+ "flag"
+ "os"
+ "fmt"
+ "strings"
+ "container/list"
+)
+
+const (
+ PKGCACHE = "/var/cache/pacman/pkg"
+)
+
+var (
+ help = flag.Bool("h", false, "display this help message")
+ cachePath = flag.String("c", PKGCACHE, "path to package cache")
+ keep = flag.Int("k", 3, "number of packages to keep")
+ delete = flag.Bool("d", false, "delete packages over keep limit")
+ quiet = flag.Bool("q", false, "don't print deletion candidates")
+)
+
+type archpkg struct {
+ Name string
+ Version string
+ Ext string
+}
+
+var pkgList = map[string]*list.List{}
+
+func addPkgSorted(l *list.List, eAdd *archpkg) {
+ p := l.Front()
+ ele := (p.Value).(*archpkg)
+
+ for {
+ if vercmp(eAdd.Version, ele.Version) == -1 {
+ l.InsertBefore(eAdd, p)
+ return
+ }
+ if next := p.Next(); next == nil {
+ l.PushBack(eAdd)
+ return
+ } else {
+ p = p.Next()
+ }
+ }
+}
+
+func parsePkg(file string) *archpkg {
+ parts := strings.Split(file, "-", -1)
+ n := len(parts)
+ if n < 3 {
+ return nil
+ }
+
+ pkgname := strings.Join(parts[0:n-3], "-")
+ if pkgname == "" {
+ return nil
+ }
+
+ pkgver := strings.Join(parts[n-3:n-1], "-")
+
+ return &archpkg{pkgname, pkgver, parts[n-1]}
+}
+
+func addPkgToMap(pkg *archpkg) {
+ if _, ok := pkgList[pkg.Name]; !ok {
+ pkgList[pkg.Name] = list.New()
+ pkgList[pkg.Name].PushFront(pkg)
+ } else {
+ addPkgSorted(pkgList[pkg.Name], pkg)
+ }
+}
+
+func prune() int {
+ count := 0
+
+ for _, group := range pkgList {
+ groupSz := group.Len()
+ if groupSz <= *keep {
+ continue
+ }
+ for i := 0; i < groupSz-*keep; i++ {
+ p := (group.Front().Value).(*archpkg)
+ filename := strings.Join([]string{p.Name, p.Version, p.Ext}, "-")
+
+ fullpath := fmt.Sprint(*cachePath + "/" + filename)
+ if *delete {
+ if !*quiet {
+ fmt.Println("Deleting " + fullpath)
+ }
+ err := os.Remove(fullpath)
+ if err != nil {
+ fmt.Fprintln(os.Stderr, "error deleting %s: %s\n", fullpath, err.String())
+ os.Exit(2)
+ }
+ } else {
+ if !*quiet {
+ fmt.Println("Would delete: " + fullpath)
+ }
+ }
+ count++
+
+ group.Remove(group.Front())
+ }
+
+ if !*quiet {
+ fmt.Println()
+ }
+ }
+
+ return count
+}
+
+/* TODO: Reimplement alpm_pkg_vermp() */
+func vercmp(a, b string) int {
+ p, _ := exec.Run("vercmp", []string{"vercmp", a, b}, os.Environ(), "/usr/bin", 0, exec.DevNull, exec.DevNull)
+ w, _ := p.Wait(0)
+
+ return w.ExitStatus()
+}
+
+func main() {
+ flag.Parse()
+ flag.Usage = func() {
+ fmt.Println("usage: gobble [flags]")
+ flag.PrintDefaults()
+ os.Exit(0)
+ }
+
+ if *help {
+ flag.Usage()
+ }
+
+ if *delete && os.Getuid() != 0 {
+ fmt.Fprintln(os.Stderr, "error: cannot delete as non-root user.")
+ os.Exit(1)
+ }
+
+ d, err := os.Open(*cachePath, os.O_RDONLY, 0666)
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err.String())
+ os.Exit(1)
+ }
+ defer d.Close()
+
+ fi, err := d.Readdir(-1)
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err.String())
+ os.Exit(1)
+ }
+
+ if !*delete {
+ fmt.Println("Performing dry-run...")
+ }
+
+ found := 0
+ for _, pkg := range fi {
+ if p := parsePkg(pkg.Name); p != nil {
+ addPkgToMap(p)
+ found++
+ }
+ }
+
+ switch found {
+ case 0:
+ fmt.Fprintln(os.Stderr, "error: No candidate package groups found. Are you sure this is a valid pacman cache?")
+ os.Exit(0)
+ default:
+ fmt.Printf("%d candidate package groups found.\n", found)
+ }
+
+ if *delete {
+ fmt.Printf("%d packages pruned.\n", prune())
+ } else {
+ fmt.Printf("%d packages would be pruned.\n", prune())
+ }
+
+}
Please sign in to comment.
Something went wrong with that request. Please try again.