github.com/kubri/kubri@v0.5.1-0.20240317001612-bda2aaef967e/integrations/apk/repo.go (about) 1 package apk 2 3 import ( 4 "bytes" 5 "context" 6 "errors" 7 "fmt" 8 "io" 9 "io/fs" 10 "os" 11 "path/filepath" 12 13 "gitlab.alpinelinux.org/alpine/go/repository" 14 15 "github.com/kubri/kubri/pkg/crypto/rsa" 16 "github.com/kubri/kubri/target" 17 ) 18 19 type repo struct { 20 repos map[string]*repository.ApkIndex 21 dir string 22 } 23 24 func openRepo(ctx context.Context, t target.Target) (*repo, error) { 25 dir, err := os.MkdirTemp("", "") 26 if err != nil { 27 return nil, err 28 } 29 30 res := &repo{ 31 repos: make(map[string]*repository.ApkIndex), 32 dir: dir, 33 } 34 35 // See https://wiki.alpinelinux.org/wiki/Architecture 36 archs := []string{"x86", "x86_64", "armhf", "armv7", "aarch64", "ppc64le", "s390x"} 37 38 for _, arch := range archs { 39 r, err := t.NewReader(ctx, arch+"/APKINDEX.tar.gz") 40 if err != nil { 41 if errors.Is(err, fs.ErrNotExist) { 42 continue 43 } 44 return nil, err 45 } 46 index, err := repository.IndexFromArchive(r) 47 if err != nil { 48 return nil, err 49 } 50 res.repos[arch] = index 51 } 52 53 return res, nil 54 } 55 56 func (r *repo) Add(b []byte) error { 57 p, err := repository.ParsePackage(bytes.NewReader(b)) 58 if err != nil { 59 return err 60 } 61 62 index, ok := r.repos[p.Arch] 63 if !ok { 64 index = &repository.ApkIndex{} 65 r.repos[p.Arch] = index 66 } 67 index.Packages = append(index.Packages, p) 68 69 dirname := filepath.Join(r.dir, p.Arch) 70 if err = os.MkdirAll(dirname, fs.ModePerm); err != nil { 71 return err 72 } 73 74 filename := fmt.Sprintf("%s-%s.apk", p.Name, p.Version) 75 return os.WriteFile(filepath.Join(dirname, filename), b, 0o600) 76 } 77 78 func (r *repo) Write(rsaKey *rsa.PrivateKey, publicKeyName string) error { 79 for arch, index := range r.repos { 80 rd, err := repository.ArchiveFromIndex(index) 81 if err != nil { 82 return err 83 } 84 85 if rsaKey != nil { 86 rd, err = repository.SignArchive(rd, rsaKey, publicKeyName) 87 if err != nil { 88 return err 89 } 90 } 91 92 path := filepath.Join(r.dir, arch, "APKINDEX.tar.gz") 93 f, err := os.Create(path) 94 if err != nil { 95 return err 96 } 97 if _, err = io.Copy(f, rd); err != nil { 98 return err 99 } 100 if err = f.Close(); err != nil { 101 return err 102 } 103 } 104 105 if rsaKey != nil { 106 pub, err := rsa.MarshalPublicKey(rsa.Public(rsaKey)) 107 if err != nil { 108 return err 109 } 110 return os.WriteFile(filepath.Join(r.dir, publicKeyName), pub, 0o600) 111 } 112 113 return nil 114 }