summaryrefslogtreecommitdiff
path: root/scripts/prune_old_versions.go
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/prune_old_versions.go')
-rw-r--r--scripts/prune_old_versions.go128
1 files changed, 128 insertions, 0 deletions
diff --git a/scripts/prune_old_versions.go b/scripts/prune_old_versions.go
new file mode 100644
index 0000000..43d9997
--- /dev/null
+++ b/scripts/prune_old_versions.go
@@ -0,0 +1,128 @@
+package main
+
+import (
+ "encoding/json"
+ "flag"
+ "fmt"
+ "net/http"
+ "os"
+ "sort"
+ "strings"
+ "time"
+)
+
+var (
+ user = flag.String("user", "", "username")
+ repo = flag.String("repo", "", "repository name")
+ pkgType = flag.String("pkg-type", "deb", "Package type, e.g. 'deb'")
+ distro = flag.String("distro", "", "distro name, e.g. 'debian'")
+ distroVersion = flag.String("version", "", "distro version, e.g. 'stretch'")
+ pkg = flag.String("package", "", "package name")
+ arch = flag.String("arch", "", "package architecture")
+ limit = flag.Int("limit", 2, "package versions to keep")
+)
+
+func fatalf(msg string, args ...interface{}) {
+ fmt.Printf(msg+"\n", args...)
+ os.Exit(1)
+}
+
+func main() {
+ flag.Parse()
+ if *user == "" {
+ fatalf("missing -user")
+ }
+ if *repo == "" {
+ fatalf("missing -repo")
+ }
+ if *pkgType == "" {
+ fatalf("missing -pkg-type")
+ }
+ if *distro == "" {
+ fatalf("missing -distro")
+ }
+ if *distroVersion == "" {
+ fatalf("missing -version")
+ }
+ if *pkg == "" {
+ fatalf("missing -package")
+ }
+ if *arch == "" {
+ fatalf("missing -arch")
+ }
+ if *limit < 1 {
+ fatalf("limit must be >= 1")
+ }
+
+ files, err := packageVersions(*user, *repo, *pkgType, *distro, *distroVersion, *pkg, *arch)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ if len(files) <= *limit {
+ fmt.Println("Below limit, no packages deleted")
+ return
+ }
+ delete := files[:len(files)-*limit]
+ keep := files[len(files)-*limit:]
+ if err = deletePackages(delete); err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+
+ fmt.Printf("Deleted:\n\n%s\n\nKept:\n\n%s\n", strings.Join(delete, "\n"), strings.Join(keep, "\n"))
+}
+
+type packageMeta struct {
+ Created time.Time `json:"created_at"`
+ Filename string `json:"filename"`
+}
+
+type metaSort []packageMeta
+
+func (m metaSort) Len() int { return len(m) }
+func (m metaSort) Less(i, j int) bool { return m[i].Created.Before(m[j].Created) }
+func (m metaSort) Swap(i, j int) { m[i], m[j] = m[j], m[i] }
+
+func packageVersions(user, repo, typ, distro, version, pkgname, arch string) ([]string, error) {
+ url := fmt.Sprintf("https://%s:@packagecloud.io/api/v1/repos/%s/%s/package/%s/%s/%s/%s/%s/versions.json", os.Getenv("PACKAGECLOUD_API_KEY"), user, repo, typ, distro, version, pkgname, arch)
+ resp, err := http.Get(url)
+ if err != nil {
+ return nil, fmt.Errorf("get versions.json: %s", err)
+ }
+ defer resp.Body.Close()
+
+ var files []packageMeta
+ if err := json.NewDecoder(resp.Body).Decode(&files); err != nil {
+ return nil, fmt.Errorf("decode versions.json: %s", err)
+ }
+
+ // Newest first
+ sort.Sort(metaSort(files))
+
+ var ret []string
+ for _, meta := range files {
+ ret = append(ret, fmt.Sprintf("/api/v1/repos/%s/%s/%s/%s/%s", user, repo, distro, version, meta.Filename))
+ }
+
+ return ret, nil
+}
+
+func deletePackages(urls []string) error {
+ for _, url := range urls {
+ fullURL := fmt.Sprintf("https://%s:@packagecloud.io%s", os.Getenv("PACKAGECLOUD_API_KEY"), url)
+ req, err := http.NewRequest("DELETE", fullURL, nil)
+ if err != nil {
+ return fmt.Errorf("build delete request for %s: %s", url, err)
+ }
+ resp, err := http.DefaultClient.Do(req)
+ if err != nil {
+ return fmt.Errorf("delete %s: %s", url, err)
+ }
+ defer resp.Body.Close()
+ if resp.StatusCode != 200 {
+ return fmt.Errorf("delete %s: %s", url, resp.Status)
+ }
+ }
+ return nil
+}