github.com/abemedia/appcast@v0.4.0/integrations/apk/build.go (about) 1 package apk 2 3 import ( 4 "context" 5 "io/fs" 6 "os" 7 "path" 8 "strings" 9 "unsafe" 10 11 "github.com/abemedia/appcast/pkg/crypto/rsa" 12 "github.com/abemedia/appcast/source" 13 "github.com/abemedia/appcast/target" 14 "gitlab.alpinelinux.org/alpine/go/repository" 15 ) 16 17 type Config struct { 18 Source *source.Source 19 Version string 20 Prerelease bool 21 Target target.Target 22 RSAKey *rsa.PrivateKey 23 KeyName string 24 } 25 26 //nolint:funlen 27 func Build(ctx context.Context, c *Config) error { 28 repo, err := openRepo(ctx, c.Target) 29 if err != nil { 30 return err 31 } 32 defer os.RemoveAll(repo.dir) 33 34 version := c.Version 35 if v := getVersionConstraint(repo.repos); v != "" { 36 version += "," + v 37 } 38 39 releases, err := c.Source.ListReleases(ctx, &source.ListOptions{ 40 Version: version, 41 Prerelease: c.Prerelease, 42 }) 43 if err == source.ErrNoReleaseFound { 44 return nil 45 } 46 if err != nil { 47 return err 48 } 49 50 var hasReleases bool 51 for _, release := range releases { 52 for _, asset := range release.Assets { 53 if path.Ext(asset.Name) != ".apk" { 54 continue 55 } 56 b, err := c.Source.DownloadAsset(ctx, release.Version, asset.Name) 57 if err != nil { 58 return err 59 } 60 if err = repo.Add(b); err != nil { 61 return err 62 } 63 hasReleases = true 64 } 65 } 66 if !hasReleases { 67 return nil 68 } 69 70 if err = repo.Write(c.RSAKey, c.KeyName); err != nil { 71 return err 72 } 73 74 files := os.DirFS(repo.dir) 75 err = fs.WalkDir(files, ".", func(path string, d fs.DirEntry, err error) error { 76 if err != nil || d.IsDir() { 77 return err 78 } 79 b, err := fs.ReadFile(files, path) 80 if err != nil { 81 return err 82 } 83 w, err := c.Target.NewWriter(ctx, path) 84 if err != nil { 85 return err 86 } 87 if _, err = w.Write(b); err != nil { 88 return err 89 } 90 return w.Close() 91 }) 92 if err != nil { 93 return err 94 } 95 96 return nil 97 } 98 99 func getVersionConstraint(repo map[string]*repository.ApkIndex) string { 100 if len(repo) == 0 { 101 return "" 102 } 103 104 replace := strings.NewReplacer("_p", "+", "_", "-") 105 v := make([]byte, 0) 106 for _, r := range repo { 107 for _, p := range r.Packages { 108 v = append(v, '!', '=') 109 v = append(v, replace.Replace(p.Version)...) 110 v = append(v, ',') 111 } 112 } 113 114 return unsafe.String(unsafe.SliceData(v), len(v)-1) 115 }