131 lines
3.1 KiB
Go
131 lines
3.1 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"slices"
|
|
"strings"
|
|
|
|
"code.gitea.io/sdk/gitea"
|
|
"github.com/carlmjohnson/requests"
|
|
)
|
|
|
|
func main() {
|
|
giteaUrl := os.Getenv("GITEA_URL")
|
|
giteaToken := os.Getenv("GITEA_TOKEN")
|
|
|
|
if err := run(giteaUrl, giteaUrl, giteaToken); err != nil {
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
fmt.Println("OK")
|
|
}
|
|
|
|
func run(giteaUrl string, registryUrl string, giteaToken string) error {
|
|
ctx := context.TODO()
|
|
|
|
var catalog RegistryCatalog
|
|
if err := requests.URL(registryUrl).Path("/v2/_catalog").BasicAuth("<token>", giteaToken).ToJSON(&catalog).Fetch(ctx); err != nil {
|
|
return err
|
|
}
|
|
|
|
var images []string
|
|
var orgs []string
|
|
for _, repo := range catalog.Repositories {
|
|
srepo := strings.Split(repo, "/")
|
|
if len(srepo) == 2 {
|
|
if !slices.Contains(orgs, srepo[0]) {
|
|
orgs = append(orgs, srepo[0])
|
|
}
|
|
|
|
var regRepo RegistryRepository
|
|
if err := requests.URL(registryUrl).Pathf("/v2/%s/tags/list", repo).BasicAuth("<token>", giteaToken).ToJSON(®Repo).Fetch(ctx); err != nil {
|
|
return err
|
|
}
|
|
for _, tag := range regRepo.Tags {
|
|
var regMan RegistryRepositoryManifest
|
|
if err := requests.URL(registryUrl).Pathf("/v2/%s/manifests/%s", repo, tag).BasicAuth("<token>", giteaToken).ToJSON(®Man).Fetch(ctx); err != nil {
|
|
return err
|
|
}
|
|
for _, man := range regMan.Manifests {
|
|
images = append(images, repo+"/"+man.Digest)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var toPurge, toKeep []string
|
|
|
|
client, err := gitea.NewClient(giteaUrl, gitea.SetToken(giteaToken))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, org := range orgs {
|
|
page := 1
|
|
pageSize := -1
|
|
|
|
for {
|
|
list, _, err := client.ListPackages(org, gitea.ListPackagesOptions{ListOptions: gitea.ListOptions{Page: page}})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if pageSize < 0 {
|
|
pageSize = len(list)
|
|
}
|
|
if len(list) < pageSize || len(list) == 0 {
|
|
break
|
|
}
|
|
page++
|
|
|
|
for _, pkg := range list {
|
|
if pkg.Type == "container" && strings.HasPrefix(pkg.Version, "sha") {
|
|
if slices.Contains(images, org+"/"+pkg.Name+"/"+pkg.Version) {
|
|
toKeep = append(toKeep, org+"/"+pkg.Name+"/"+pkg.Version)
|
|
} else {
|
|
toPurge = append(toPurge, org+"/"+pkg.Name+"/"+pkg.Version)
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
slices.Sort(images)
|
|
slices.Sort(toKeep)
|
|
|
|
if !slices.Equal(images, toKeep) {
|
|
return fmt.Errorf("images from registry don't match with those to keep")
|
|
}
|
|
|
|
for _, p := range toPurge {
|
|
px := strings.Split(p, "/")
|
|
if len(px) == 3 {
|
|
if _, err := client.DeletePackage(px[0], "container", px[1], px[2]); err != nil {
|
|
return err
|
|
}
|
|
fmt.Printf("removing.. \"%s/%s\" %s\n", px[0], px[1], px[2])
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type RegistryCatalog struct {
|
|
Repositories []string `json:"repositories"`
|
|
}
|
|
|
|
type RegistryRepository struct {
|
|
Name string `json:"name"`
|
|
Tags []string `json:"tags"`
|
|
}
|
|
|
|
type RegistryRepositoryManifest struct {
|
|
SchemaVersion int `json:"schemaVersion"`
|
|
MediaType string `json:"mediaType"`
|
|
Digest string `json:"digest"`
|
|
Size int `json:"size"`
|
|
Manifests []RegistryRepositoryManifest `json:"manifests"`
|
|
}
|