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