diff options
Diffstat (limited to 'scripts/prune_old_versions.go')
-rw-r--r-- | scripts/prune_old_versions.go | 128 |
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 +} |