Skip to content

Commit

Permalink
Merge pull request #821 from jonjohnsonjr/apk
Browse files Browse the repository at this point in the history
  • Loading branch information
imjasonh authored Jul 19, 2023
2 parents ada7280 + 2014a34 commit 703467d
Show file tree
Hide file tree
Showing 12 changed files with 175 additions and 302 deletions.
6 changes: 1 addition & 5 deletions internal/cli/build-minirootfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,11 @@ func BuildMinirootFSCmd(ctx context.Context, opts ...build.Option) error {
}
defer os.RemoveAll(wd)

bc, err := build.New(wd, opts...)
bc, err := build.New(ctx, wd, opts...)
if err != nil {
return err
}

if err := bc.Refresh(); err != nil {
return err
}

ic := bc.ImageConfiguration()

if len(ic.Archs) != 0 {
Expand Down
44 changes: 18 additions & 26 deletions internal/cli/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,17 +181,11 @@ func buildImageComponents(ctx context.Context, wd string, archs []types.Architec
ctx, span := otel.Tracer("apko").Start(ctx, "buildImageComponents")
defer span.End()

bc, err := build.New(wd, opts...)
o, ic, err := build.NewOptions(wd, opts...)
if err != nil {
return nil, nil, err
}

if err := bc.Refresh(); err != nil {
return nil, nil, err
}

ic := bc.ImageConfiguration()

// cases:
// - archs set: use those archs
// - archs not set, bc.ImageConfiguration.Archs set: use Config archs
Expand All @@ -206,7 +200,7 @@ func buildImageComponents(ctx context.Context, wd string, archs []types.Architec
}
// save the final set we will build
archs = ic.Archs
bc.Logger().Infof("Building images for %d architectures: %+v", len(ic.Archs), ic.Archs)
o.Logger().Infof("Building images for %d architectures: %+v", len(ic.Archs), ic.Archs)

// The build context options is sometimes copied in the next functions. Ensure
// we have the directory defined and created by invoking the function early.
Expand All @@ -217,7 +211,7 @@ func buildImageComponents(ctx context.Context, wd string, archs []types.Architec
// image/ - the summary layer files and sboms for each architecture
// imageDir, created here, is where the final artifacts will be: layer tars, indexes, etc.

bc.Logger().Printf("building tags %v", bc.Tags())
o.Logger().Printf("building tags %v", o.Tags)

var errg errgroup.Group
workDir := wd
Expand All @@ -236,7 +230,7 @@ func buildImageComponents(ctx context.Context, wd string, archs []types.Architec
// maximum "build date epoch" of the per-arch images. If the user has
// explicitly set SOURCE_DATE_EPOCH, that will always trump this
// computation.
multiArchBDE := bc.SourceDateEpoch()
multiArchBDE := o.SourceDateEpoch

for _, arch := range archs {
arch := arch
Expand All @@ -245,10 +239,9 @@ func buildImageComponents(ctx context.Context, wd string, archs []types.Architec
bopts := slices.Clone(opts)
bopts = append(bopts,
build.WithArch(arch),
build.WithTarball(filepath.Join(imageDir, bc.TarballFilename())),
build.WithSBOM(imageDir),
)
bc, err := build.New(wd, bopts...)
bc, err := build.New(ctx, wd, bopts...)
if err != nil {
return nil, nil, err
}
Expand All @@ -257,10 +250,6 @@ func buildImageComponents(ctx context.Context, wd string, archs []types.Architec
contexts[arch] = bc

errg.Go(func() error {
if err := bc.Refresh(); err != nil {
return fmt.Errorf("failed to update build context for %q: %w", arch, err)
}

layerTarGZ, layer, err := bc.BuildLayer(ctx)
if err != nil {
return fmt.Errorf("failed to build layer image for %q: %w", arch, err)
Expand Down Expand Up @@ -301,10 +290,22 @@ func buildImageComponents(ctx context.Context, wd string, archs []types.Architec
}

// generate the index
finalDigest, idx, err := oci.GenerateIndex(ctx, ic, imgs)
finalDigest, idx, err := oci.GenerateIndex(ctx, *ic, imgs)
if err != nil {
return nil, nil, fmt.Errorf("failed to generate OCI index: %w", err)
}

opts = append(opts,
build.WithImageConfiguration(*ic), // We mutate Archs above.
build.WithSourceDateEpoch(multiArchBDE), // Maximum child's time.
build.WithSBOM(imageDir),
)

bc, err := build.New(ctx, wd, opts...)
if err != nil {
return nil, nil, err
}

if _, _, err := bc.WriteIndex(idx); err != nil {
return nil, nil, fmt.Errorf("failed to write OCI index: %w", err)
}
Expand Down Expand Up @@ -337,15 +338,6 @@ func buildImageComponents(ctx context.Context, wd string, archs []types.Architec
return nil, nil, err
}

opts = append(opts,
build.WithImageConfiguration(ic), // We mutate Archs above.
build.WithSourceDateEpoch(multiArchBDE), // Maximum child's time.
build.WithSBOM(imageDir),
)
bc, err := build.New(wd, opts...)
if err != nil {
return nil, nil, err
}
files, err := bc.GenerateIndexSBOM(ctx, finalDigest, imgs)
if err != nil {
return nil, nil, fmt.Errorf("generating index SBOM: %w", err)
Expand Down
6 changes: 1 addition & 5 deletions internal/cli/show-config.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,11 @@ func ShowConfigCmd(ctx context.Context, opts ...build.Option) error {
}
defer os.RemoveAll(wd)

bc, err := build.New(wd, opts...)
bc, err := build.New(ctx, wd, opts...)
if err != nil {
return err
}

if err := bc.Refresh(); err != nil {
return err
}

var buf bytes.Buffer
enc := yaml.NewEncoder(&buf)

Expand Down
12 changes: 2 additions & 10 deletions internal/cli/show-packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,11 @@ func ShowPackagesCmd(ctx context.Context, format string, archs []types.Architect
}
defer os.RemoveAll(wd)

bc, err := build.New(wd, opts...)
bc, err := build.New(ctx, wd, opts...)
if err != nil {
return err
}

if err := bc.Refresh(); err != nil {
return err
}

ic := bc.ImageConfiguration()

// cases:
Expand Down Expand Up @@ -165,15 +161,11 @@ func ShowPackagesCmd(ctx context.Context, format string, archs []types.Architect
wd := filepath.Join(wd, arch.ToAPK())
bopts := slices.Clone(opts)
bopts = append(bopts, build.WithArch(arch))
bc, err := build.New(wd, bopts...)
bc, err := build.New(ctx, wd, bopts...)
if err != nil {
return err
}

if err := bc.Refresh(); err != nil {
return fmt.Errorf("failed to update build context for %q: %w", arch, err)
}

pkgs, _, err := bc.BuildPackageList(ctx)
if err != nil {
return fmt.Errorf("failed to get package list for image: %w", err)
Expand Down
140 changes: 0 additions & 140 deletions pkg/apk/apk.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,140 +17,18 @@ package apk
//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -generate

import (
"archive/tar"
"context"
"fmt"
"io/fs"
"os"
"regexp"
"sort"
"strings"

apkimpl "github.com/chainguard-dev/go-apk/pkg/apk"
apkfs "github.com/chainguard-dev/go-apk/pkg/fs"
"github.com/google/go-containerregistry/pkg/name"
"gitlab.alpinelinux.org/alpine/go/repository"
"golang.org/x/sync/errgroup"
"k8s.io/apimachinery/pkg/util/sets"

"chainguard.dev/apko/pkg/build/types"
"chainguard.dev/apko/pkg/options"
"chainguard.dev/apko/pkg/sbom"
)

type APK struct {
impl *apkimpl.APK
fs apkfs.FullFS
Options options.Options
}

func New() (*APK, error) {
return NewWithOptions(apkfs.DirFS("/"), options.Default)
}

func NewWithOptions(fsys apkfs.FullFS, o options.Options) (*APK, error) {
opts := options.Default
if o.Log == nil {
o.Log = opts.Log
}

// apko does not execute the scripts, so they do not matter. This buys us flexibility
// to run without root privileges, or even on non-Linux.
apkOpts := []apkimpl.Option{
apkimpl.WithFS(fsys),
apkimpl.WithLogger(o.Logger()),
apkimpl.WithArch(o.Arch.ToAPK()),
apkimpl.WithIgnoreMknodErrors(true),
}
// only try to pass the cache dir if one of the following is true:
// - the user has explicitly set a cache dir
// - the user's system-determined cachedir, as set by os.UserCacheDir(), can be found
// if neither of these are true, then we don't want to pass a cache dir, because
// go-apk will try to set it to os.UserCacheDir() which returns an error if $HOME
// is not set.

// note that this is not easy to do in a switch statement, because of the second
// condition, if err := ...; err == nil {}
if o.CacheDir != "" {
apkOpts = append(apkOpts, apkimpl.WithCache(o.CacheDir))
} else if _, err := os.UserCacheDir(); err == nil {
apkOpts = append(apkOpts, apkimpl.WithCache(o.CacheDir))
} else {
o.Logger().Warnf("cache disabled because cache dir was not set, and cannot determine system default: %v", err)
}

apkImpl, err := apkimpl.New(apkOpts...)
if err != nil {
return nil, err
}
a := &APK{
Options: o,
impl: apkImpl,
fs: fsys,
}
return a, nil
}

type Option func(*APK) error

// Initialize sets the image in Context.WorkDir according to the image configuration,
// and does everything short of installing the packages.
func (a *APK) Initialize(ctx context.Context, ic types.ImageConfiguration) error {
// initialize apk
alpineVersions := parseOptionsFromRepositories(ic.Contents.Repositories)
if err := a.impl.InitDB(ctx, alpineVersions...); err != nil {
return fmt.Errorf("failed to initialize apk database: %w", err)
}

var eg errgroup.Group

eg.Go(func() error {
keyring := sets.List(sets.New(ic.Contents.Keyring...).Insert(a.Options.ExtraKeyFiles...))
if err := a.impl.InitKeyring(ctx, keyring, nil); err != nil {
return fmt.Errorf("failed to initialize apk keyring: %w", err)
}
return nil
})

eg.Go(func() error {
repos := sets.List(sets.New(ic.Contents.Repositories...).Insert(a.Options.ExtraRepos...))
if err := a.impl.SetRepositories(repos); err != nil {
return fmt.Errorf("failed to initialize apk repositories: %w", err)
}
return nil
})

eg.Go(func() error {
packages := sets.List(sets.New(ic.Contents.Packages...).Insert(a.Options.ExtraPackages...))
if err := a.impl.SetWorld(packages); err != nil {
return fmt.Errorf("failed to initialize apk world: %w", err)
}
return nil
})

if err := eg.Wait(); err != nil {
return err
}

return nil
}

// Install install packages. Only works if already initialized.
func (a *APK) Install(ctx context.Context) error {
// sync reality with desired apk world
return a.impl.FixateWorld(ctx, &a.Options.SourceDateEpoch)
}

// ResolvePackages gets list of packages that should be installed
func (a *APK) ResolvePackages(ctx context.Context) (toInstall []*repository.RepositoryPackage, conflicts []string, err error) {
// sync reality with desired apk world
return a.impl.ResolveWorld(ctx)
}

func (a *APK) GetInstalled() ([]*apkimpl.InstalledPackage, error) {
return a.impl.GetInstalled()
}

// AdditionalTags is a helper function used in conjunction with the --package-version-tag flag
// If --package-version-tag is set to a package name (e.g. go), then this function
// returns a list of all images that should be published with the associated version of that package tagged (e.g. 1.18)
Expand Down Expand Up @@ -242,21 +120,3 @@ func getStemmedVersionTags(opts options.Options, origRef string, version string)
})
return tags, nil
}

func (a *APK) ListInitFiles() []tar.Header {
return a.impl.ListInitFiles()
}

var repoRE = regexp.MustCompile(`^http[s]?://.+\/alpine\/([^\/]+)\/[^\/]+$`)

func parseOptionsFromRepositories(repos []string) []string {
var versions = make([]string, 0)
for _, r := range repos {
parts := repoRE.FindStringSubmatch(r)
if len(parts) < 2 {
continue
}
versions = append(versions, parts[1])
}
return versions
}
15 changes: 0 additions & 15 deletions pkg/apk/apk_implementation.go

This file was deleted.

19 changes: 0 additions & 19 deletions pkg/apk/const.go

This file was deleted.

Loading

0 comments on commit 703467d

Please sign in to comment.