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