Allow to pull from multiple repositories

Adds a new cli flag to luet build `--pull-repository` which allows to
pass-by a list of docker image references which are used to pull the
cache from

Fixes #185
Fixes #184
Closes #161
This commit is contained in:
Ettore Di Giacinto 2021-04-07 15:54:38 +02:00
parent 88307b1912
commit ec19b34ca8
4 changed files with 169 additions and 85 deletions

View File

@ -154,6 +154,7 @@ Build packages specifying multiple definition trees:
discount := LuetCfg.Viper.GetFloat64("solver.discount") discount := LuetCfg.Viper.GetFloat64("solver.discount")
rate := LuetCfg.Viper.GetFloat64("solver.rate") rate := LuetCfg.Viper.GetFloat64("solver.rate")
attempts := LuetCfg.Viper.GetInt("solver.max_attempts") attempts := LuetCfg.Viper.GetInt("solver.max_attempts")
pullRepo, _ := cmd.Flags().GetStringArray("pull-repository")
LuetCfg.GetSolverOptions().Type = stype LuetCfg.GetSolverOptions().Type = stype
LuetCfg.GetSolverOptions().LearnRate = float32(rate) LuetCfg.GetSolverOptions().LearnRate = float32(rate)
@ -166,7 +167,8 @@ Build packages specifying multiple definition trees:
opts := compiler.NewDefaultCompilerOptions() opts := compiler.NewDefaultCompilerOptions()
opts.SolverOptions = *LuetCfg.GetSolverOptions() opts.SolverOptions = *LuetCfg.GetSolverOptions()
opts.ImageRepository = imageRepository opts.PushImageRepository = imageRepository
opts.PullImageRepository = pullRepo
opts.PullFirst = pull opts.PullFirst = pull
opts.KeepImg = keepImages opts.KeepImg = keepImages
opts.Push = push opts.Push = push
@ -330,6 +332,7 @@ func init() {
buildCmd.Flags().Bool("live-output", LuetCfg.GetGeneral().ShowBuildOutput, "Enable live output of the build phase.") buildCmd.Flags().Bool("live-output", LuetCfg.GetGeneral().ShowBuildOutput, "Enable live output of the build phase.")
buildCmd.Flags().Bool("pretend", false, "Just print what packages will be compiled") buildCmd.Flags().Bool("pretend", false, "Just print what packages will be compiled")
buildCmd.Flags().StringArrayP("pull-repository", "p", []string{}, "A list of repositories to pull the cache from")
buildCmd.Flags().StringP("output", "o", "terminal", "Output format ( Defaults: terminal, available: json,yaml )") buildCmd.Flags().StringP("output", "o", "terminal", "Output format ( Defaults: terminal, available: json,yaml )")

View File

@ -57,6 +57,7 @@ func NewTreeImageCommand() *cobra.Command {
treePath, _ := cmd.Flags().GetStringArray("tree") treePath, _ := cmd.Flags().GetStringArray("tree")
imageRepository := viper.GetString("image-repository") imageRepository := viper.GetString("image-repository")
pullRepo, _ := cmd.Flags().GetStringArray("pull-repository")
out, _ := cmd.Flags().GetString("output") out, _ := cmd.Flags().GetString("output")
if out != "terminal" { if out != "terminal" {
@ -75,7 +76,8 @@ func NewTreeImageCommand() *cobra.Command {
opts := compiler.NewDefaultCompilerOptions() opts := compiler.NewDefaultCompilerOptions()
opts.SolverOptions = *LuetCfg.GetSolverOptions() opts.SolverOptions = *LuetCfg.GetSolverOptions()
opts.ImageRepository = imageRepository opts.PushImageRepository = imageRepository
opts.PullImageRepository = pullRepo
solverOpts := solver.Options{Type: solver.SingleCoreSimple, Concurrency: 1} solverOpts := solver.Options{Type: solver.SingleCoreSimple, Concurrency: 1}
luetCompiler := compiler.NewLuetCompiler(compilerBackend, reciper.GetDatabase(), opts, solverOpts) luetCompiler := compiler.NewLuetCompiler(compilerBackend, reciper.GetDatabase(), opts, solverOpts)
@ -135,6 +137,7 @@ func NewTreeImageCommand() *cobra.Command {
ans.Flags().StringP("output", "o", "terminal", "Output format ( Defaults: terminal, available: json,yaml )") ans.Flags().StringP("output", "o", "terminal", "Output format ( Defaults: terminal, available: json,yaml )")
ans.Flags().StringArrayP("tree", "t", []string{path}, "Path of the tree to use.") ans.Flags().StringArrayP("tree", "t", []string{path}, "Path of the tree to use.")
ans.Flags().String("image-repository", "luet/cache", "Default base image string for generated image") ans.Flags().String("image-repository", "luet/cache", "Default base image string for generated image")
ans.Flags().StringArrayP("pull-repository", "p", []string{}, "A list of repositories to pull the cache from")
return ans return ans
} }

View File

@ -1,4 +1,4 @@
// Copyright © 2019 Ettore Di Giacinto <mudler@gentoo.org> // Copyright © 2019-2021 Ettore Di Giacinto <mudler@sabayon.org>
// //
// This program is free software; you can redistribute it and/or modify // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by // it under the terms of the GNU General Public License as published by
@ -43,9 +43,11 @@ const CollectionFile = "collection.yaml"
type LuetCompiler struct { type LuetCompiler struct {
*tree.CompilerRecipe *tree.CompilerRecipe
Backend CompilerBackend Backend CompilerBackend
Database pkg.PackageDatabase Database pkg.PackageDatabase
ImageRepository string PushImageRepository string
PullImageRepository []string
PullFirst, KeepImg, Clean bool PullFirst, KeepImg, Clean bool
Concurrency int Concurrency int
CompressionType CompressionImplementation CompressionType CompressionImplementation
@ -56,28 +58,41 @@ type LuetCompiler struct {
func NewLuetCompiler(backend CompilerBackend, db pkg.PackageDatabase, opt *CompilerOptions, solvopts solver.Options) Compiler { func NewLuetCompiler(backend CompilerBackend, db pkg.PackageDatabase, opt *CompilerOptions, solvopts solver.Options) Compiler {
// The CompilerRecipe will gives us a tree with only build deps listed. // The CompilerRecipe will gives us a tree with only build deps listed.
if len(opt.PullImageRepository) == 0 {
opt.PullImageRepository = []string{opt.PushImageRepository}
}
return &LuetCompiler{ return &LuetCompiler{
Backend: backend, Backend: backend,
CompilerRecipe: &tree.CompilerRecipe{ CompilerRecipe: &tree.CompilerRecipe{
tree.Recipe{Database: db}, Recipe: tree.Recipe{Database: db},
}, },
Database: db, Database: db,
ImageRepository: opt.ImageRepository, PushImageRepository: opt.PushImageRepository,
PullFirst: opt.PullFirst, PullImageRepository: opt.PullImageRepository,
CompressionType: opt.CompressionType, PullFirst: opt.PullFirst,
KeepImg: opt.KeepImg, CompressionType: opt.CompressionType,
Concurrency: opt.Concurrency, KeepImg: opt.KeepImg,
Options: *opt, Concurrency: opt.Concurrency,
SolverOptions: solvopts, Options: *opt,
SolverOptions: solvopts,
} }
} }
// SetBackendArgs sets arbitrary backend arguments.
// Those for example can be commands passed to the docker daemon during build phase,
// as build-args, etc.
func (cs *LuetCompiler) SetBackendArgs(args []string) { func (cs *LuetCompiler) SetBackendArgs(args []string) {
cs.BackedArgs = args cs.BackedArgs = args
} }
// SetConcurrency sets the compiler concurrency
func (cs *LuetCompiler) SetConcurrency(i int) { func (cs *LuetCompiler) SetConcurrency(i int) {
cs.Concurrency = i cs.Concurrency = i
} }
// SetCompressionType sets the compiler compression type for resulting artifacts
func (cs *LuetCompiler) SetCompressionType(t CompressionImplementation) { func (cs *LuetCompiler) SetCompressionType(t CompressionImplementation) {
cs.CompressionType = t cs.CompressionType = t
} }
@ -97,6 +112,7 @@ func (cs *LuetCompiler) compilerWorker(i int, wg *sync.WaitGroup, cspecs chan Co
} }
} }
// CompileWithReverseDeps compiles the supplied compilationspecs and their reverse dependencies
func (cs *LuetCompiler) CompileWithReverseDeps(keepPermissions bool, ps CompilationSpecs) ([]Artifact, []error) { func (cs *LuetCompiler) CompileWithReverseDeps(keepPermissions bool, ps CompilationSpecs) ([]Artifact, []error) {
artifacts, err := cs.CompileParallel(keepPermissions, ps) artifacts, err := cs.CompileParallel(keepPermissions, ps)
if len(err) != 0 { if len(err) != 0 {
@ -117,28 +133,6 @@ func (cs *LuetCompiler) CompileWithReverseDeps(keepPermissions bool, ps Compilat
toCompile.Add(spec) toCompile.Add(spec)
} }
// for _, assertion := range a.GetSourceAssertion() {
// if assertion.Value && assertion.Package.Flagged() {
// spec, asserterr := cs.FromPackage(assertion.Package)
// if err != nil {
// return nil, append(err, asserterr)
// }
// w, asserterr := cs.Tree().World()
// if err != nil {
// return nil, append(err, asserterr)
// }
// revdeps := spec.GetPackage().Revdeps(&w)
// for _, r := range revdeps {
// spec, asserterr := cs.FromPackage(r)
// if asserterr != nil {
// return nil, append(err, asserterr)
// }
// spec.SetOutputPath(ps.All()[0].GetOutputPath())
// toCompile.Add(spec)
// }
// }
// }
} }
uniques := toCompile.Unique().Remove(ps) uniques := toCompile.Unique().Remove(ps)
@ -150,6 +144,8 @@ func (cs *LuetCompiler) CompileWithReverseDeps(keepPermissions bool, ps Compilat
return append(artifacts, artifacts2...), err return append(artifacts, artifacts2...), err
} }
// CompileParallel compiles the supplied compilationspecs in parallel
// to note, no specific heuristic is implemented, and the specs are run in parallel as they are.
func (cs *LuetCompiler) CompileParallel(keepPermissions bool, ps CompilationSpecs) ([]Artifact, []error) { func (cs *LuetCompiler) CompileParallel(keepPermissions bool, ps CompilationSpecs) ([]Artifact, []error) {
all := make(chan CompilationSpec) all := make(chan CompilationSpec)
artifacts := []Artifact{} artifacts := []Artifact{}
@ -329,13 +325,13 @@ func (cs *LuetCompiler) buildPackageImage(image, buildertaggedImage, packageImag
fp := p.GetPackage().HashFingerprint(helpers.StripRegistryFromImage(packageImage)) fp := p.GetPackage().HashFingerprint(helpers.StripRegistryFromImage(packageImage))
if buildertaggedImage == "" { if buildertaggedImage == "" {
buildertaggedImage = cs.ImageRepository + ":builder-" + fp buildertaggedImage = cs.PushImageRepository + ":builder-" + fp
Debug(pkgTag, "Creating intermediary image", buildertaggedImage, "from", image) Debug(pkgTag, "Creating intermediary image", buildertaggedImage, "from", image)
} }
// TODO: Cleanup, not actually hit // TODO: Cleanup, not actually hit
if packageImage == "" { if packageImage == "" {
packageImage = cs.ImageRepository + ":builder-invalid" + fp return runnerOpts, builderOpts, errors.New("no package image given")
} }
p.SetSeedImage(image) // In this case, we ignore the build deps as we suppose that the image has them - otherwise we recompose the tree with a solver, p.SetSeedImage(image) // In this case, we ignore the build deps as we suppose that the image has them - otherwise we recompose the tree with a solver,
@ -407,11 +403,11 @@ func (cs *LuetCompiler) buildPackageImage(image, buildertaggedImage, packageImag
} }
if buildImage { if buildImage {
if err := cs.Backend.BuildImage(opts); err != nil { if err := cs.Backend.BuildImage(opts); err != nil {
return errors.Wrap(err, "Could not build image: "+image+" "+opts.DockerFileName) return errors.Wrapf(err, "Could not build image: %s %s", image, opts.DockerFileName)
} }
if cs.Options.Push { if cs.Options.Push {
if err = cs.Backend.Push(opts); err != nil { if err = cs.Backend.Push(opts); err != nil {
return errors.Wrap(err, "Could not push image: "+image+" "+opts.DockerFileName) return errors.Wrapf(err, "Could not push image: %s %s", image, opts.DockerFileName)
} }
} }
} }
@ -420,7 +416,7 @@ func (cs *LuetCompiler) buildPackageImage(image, buildertaggedImage, packageImag
if len(p.GetPreBuildSteps()) != 0 { if len(p.GetPreBuildSteps()) != 0 {
Info(pkgTag, ":whale: Generating 'builder' image from", image, "as", buildertaggedImage, "with prelude steps") Info(pkgTag, ":whale: Generating 'builder' image from", image, "as", buildertaggedImage, "with prelude steps")
if err := buildAndPush(builderOpts); err != nil { if err := buildAndPush(builderOpts); err != nil {
return builderOpts, runnerOpts, errors.Wrap(err, "Could not push image: "+image+" "+builderOpts.DockerFileName) return builderOpts, runnerOpts, errors.Wrapf(err, "Could not push image: %s %s", image, builderOpts.DockerFileName)
} }
} }
@ -428,7 +424,7 @@ func (cs *LuetCompiler) buildPackageImage(image, buildertaggedImage, packageImag
// acting as a docker tag. // acting as a docker tag.
Info(pkgTag, ":whale: Generating 'package' image from", buildertaggedImage, "as", packageImage, "with build steps") Info(pkgTag, ":whale: Generating 'package' image from", buildertaggedImage, "as", packageImage, "with build steps")
if err := buildAndPush(runnerOpts); err != nil { if err := buildAndPush(runnerOpts); err != nil {
return builderOpts, runnerOpts, errors.Wrap(err, "Could not push image: "+image+" "+builderOpts.DockerFileName) return builderOpts, runnerOpts, errors.Wrapf(err, "Could not push image: %s %s", image, runnerOpts.DockerFileName)
} }
return builderOpts, runnerOpts, nil return builderOpts, runnerOpts, nil
@ -501,19 +497,85 @@ func (cs *LuetCompiler) genArtifact(p CompilationSpec, builderOpts, runnerOpts C
return artifact, nil return artifact, nil
} }
func (cs *LuetCompiler) waitForImage(image string) { func (cs *LuetCompiler) waitForImages(images []string) {
if cs.Options.PullFirst && cs.Options.Wait && !cs.Backend.ImageAvailable(image) { if cs.Options.PullFirst && cs.Options.Wait {
Info(fmt.Sprintf("Waiting for image %s to be available... :zzz:", image)) available, _ := oneOfImagesAvailable(images, cs.Backend)
Spinner(22) if !available {
defer SpinnerStop() Info(fmt.Sprintf("Waiting for image %s to be available... :zzz:", images))
for !cs.Backend.ImageAvailable(image) { Spinner(22)
Info(fmt.Sprintf("Image %s not available yet, sleeping", image)) defer SpinnerStop()
time.Sleep(5 * time.Second) for !available {
available, _ = oneOfImagesAvailable(images, cs.Backend)
Info(fmt.Sprintf("Image %s not available yet, sleeping", images))
time.Sleep(5 * time.Second)
}
} }
} }
} }
func (cs *LuetCompiler) compileWithImage(image, buildertaggedImage, packageImage string, func oneOfImagesExists(images []string, b CompilerBackend) (bool, string) {
for _, i := range images {
if exists := b.ImageExists(i); exists {
return true, i
}
}
return false, ""
}
func oneOfImagesAvailable(images []string, b CompilerBackend) (bool, string) {
for _, i := range images {
if exists := b.ImageAvailable(i); exists {
return true, i
}
}
return false, ""
}
func (cs *LuetCompiler) resolveExistingImageHash(imageHash string) string {
var resolvedImage string
toChecklist := append([]string{fmt.Sprintf("%s:%s", cs.PushImageRepository, imageHash)},
genImageList(cs.PullImageRepository, imageHash)...)
if exists, which := oneOfImagesExists(toChecklist, cs.Backend); exists {
resolvedImage = which
}
if cs.Options.PullFirst {
if exists, which := oneOfImagesAvailable(toChecklist, cs.Backend); exists {
resolvedImage = which
}
}
if resolvedImage == "" {
resolvedImage = fmt.Sprintf("%s:%s", cs.PushImageRepository, imageHash)
}
return resolvedImage
}
func (cs *LuetCompiler) getImageArtifact(hash string, p CompilationSpec) (Artifact, error) {
// we check if there is an available image with the given hash and
// we return a full artifact if can be loaded locally.
toChecklist := append([]string{fmt.Sprintf("%s:%s", cs.PushImageRepository, hash)},
genImageList(cs.PullImageRepository, hash)...)
exists, _ := oneOfImagesExists(toChecklist, cs.Backend)
if art, err := LoadArtifactFromYaml(p); err == nil && exists { // If YAML is correctly loaded, and both images exists, no reason to rebuild.
Debug("Artifact reloaded from YAML. Skipping build")
return art, nil
}
cs.waitForImages(toChecklist)
available, _ := oneOfImagesAvailable(toChecklist, cs.Backend)
if exists || (cs.Options.PullFirst && available) {
Debug("Image available, returning empty artifact")
return &PackageArtifact{}, nil
}
return nil, errors.New("artifact not found")
}
// compileWithImage compiles a PackageTagHash image using the image source, and tagging an indermediate
// image buildertaggedImage.
// Images that can be resolved from repositories are prefered over the local ones if PullFirst is set to true
// avoiding to rebuild images as much as possible
func (cs *LuetCompiler) compileWithImage(image, buildertaggedImage string, packageTagHash string,
concurrency int, concurrency int,
keepPermissions, keepImg bool, keepPermissions, keepImg bool,
p CompilationSpec, generateArtifact bool) (Artifact, error) { p CompilationSpec, generateArtifact bool) (Artifact, error) {
@ -526,17 +588,16 @@ func (cs *LuetCompiler) compileWithImage(image, buildertaggedImage, packageImage
} }
if !generateArtifact { if !generateArtifact {
exists := cs.Backend.ImageExists(packageImage) // try to avoid regenerating the image if possible by checking the hash in the
if art, err := LoadArtifactFromYaml(p); err == nil && exists { // If YAML is correctly loaded, and both images exists, no reason to rebuild. // given repositories
Debug("Artifact reloaded from YAML. Skipping build") // It is best effort. If we fail resolving, we will generate the images and keep going
return art, err if art, err := cs.getImageArtifact(packageTagHash, p); err == nil {
} return art, nil
cs.waitForImage(packageImage)
if cs.Options.PullFirst && cs.Backend.ImageAvailable(packageImage) {
return &PackageArtifact{}, nil
} }
} }
// always going to point at the destination from the repo defined
packageImage := fmt.Sprintf("%s:%s", cs.PushImageRepository, packageTagHash)
builderOpts, runnerOpts, err := cs.buildPackageImage(image, buildertaggedImage, packageImage, concurrency, keepPermissions, p) builderOpts, runnerOpts, err := cs.buildPackageImage(image, buildertaggedImage, packageImage, concurrency, keepPermissions, p)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed building package image") return nil, errors.Wrap(err, "failed building package image")
@ -561,6 +622,8 @@ func (cs *LuetCompiler) compileWithImage(image, buildertaggedImage, packageImage
return cs.genArtifact(p, builderOpts, runnerOpts, concurrency, keepPermissions) return cs.genArtifact(p, builderOpts, runnerOpts, concurrency, keepPermissions)
} }
// FromDatabase returns all the available compilation specs from a database. If the minimum flag is returned
// it will be computed a minimal subset that will guarantees that all packages are built ( if not targeting a single package explictly )
func (cs *LuetCompiler) FromDatabase(db pkg.PackageDatabase, minimum bool, dst string) ([]CompilationSpec, error) { func (cs *LuetCompiler) FromDatabase(db pkg.PackageDatabase, minimum bool, dst string) ([]CompilationSpec, error) {
compilerSpecs := NewLuetCompilationspecs() compilerSpecs := NewLuetCompilationspecs()
@ -608,6 +671,8 @@ func (cs *LuetCompiler) ComputeMinimumCompilableSet(p ...CompilationSpec) ([]Com
return result, nil return result, nil
} }
// ComputeDepTree computes the dependency tree of a compilation spec and returns solver assertions
// in order to be able to compile the spec.
func (cs *LuetCompiler) ComputeDepTree(p CompilationSpec) (solver.PackagesAssertions, error) { func (cs *LuetCompiler) ComputeDepTree(p CompilationSpec) (solver.PackagesAssertions, error) {
s := solver.NewResolver(cs.SolverOptions, pkg.NewInMemoryDatabase(false), cs.Database, pkg.NewInMemoryDatabase(false), cs.Options.SolverOptions.Resolver()) s := solver.NewResolver(cs.SolverOptions, pkg.NewInMemoryDatabase(false), cs.Database, pkg.NewInMemoryDatabase(false), cs.Options.SolverOptions.Resolver())
@ -637,7 +702,8 @@ func (cs *LuetCompiler) ComputeDepTree(p CompilationSpec) (solver.PackagesAssert
return assertions, nil return assertions, nil
} }
// Compile is non-parallel // Compile is a non-parallel version of CompileParallel. It builds the compilation specs and generates
// an artifact
func (cs *LuetCompiler) Compile(keepPermissions bool, p CompilationSpec) (Artifact, error) { func (cs *LuetCompiler) Compile(keepPermissions bool, p CompilationSpec) (Artifact, error) {
asserts, err := cs.ComputeDepTree(p) asserts, err := cs.ComputeDepTree(p)
if err != nil { if err != nil {
@ -647,6 +713,14 @@ func (cs *LuetCompiler) Compile(keepPermissions bool, p CompilationSpec) (Artifa
return cs.compile(cs.Concurrency, keepPermissions, p) return cs.compile(cs.Concurrency, keepPermissions, p)
} }
func genImageList(refs []string, hash string) []string {
var res []string
for _, r := range refs {
res = append(res, fmt.Sprintf("%s:%s", r, hash))
}
return res
}
func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, p CompilationSpec) (Artifact, error) { func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, p CompilationSpec) (Artifact, error) {
Info(":package: Compiling", p.GetPackage().HumanReadableString(), ".... :coffee:") Info(":package: Compiling", p.GetPackage().HumanReadableString(), ".... :coffee:")
@ -660,7 +734,6 @@ func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, p Compila
} }
targetAssertion := p.GetSourceAssertion().Search(p.GetPackage().GetFingerPrint()) targetAssertion := p.GetSourceAssertion().Search(p.GetPackage().GetFingerPrint())
targetPackageHash := cs.ImageRepository + ":" + targetAssertion.Hash.PackageHash
bus.Manager.Publish(bus.EventPackagePreBuild, struct { bus.Manager.Publish(bus.EventPackagePreBuild, struct {
CompileSpec CompilationSpec CompileSpec CompilationSpec
@ -673,7 +746,7 @@ func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, p Compila
// - If image is set we just generate a plain dockerfile // - If image is set we just generate a plain dockerfile
// Treat last case (easier) first. The image is provided and we just compute a plain dockerfile with the images listed as above // Treat last case (easier) first. The image is provided and we just compute a plain dockerfile with the images listed as above
if p.GetImage() != "" { if p.GetImage() != "" {
return cs.compileWithImage(p.GetImage(), "", targetPackageHash, concurrency, keepPermissions, cs.KeepImg, p, true) return cs.compileWithImage(p.GetImage(), "", targetAssertion.Hash.PackageHash, concurrency, keepPermissions, cs.KeepImg, p, true)
} }
// - If image is not set, we read a base_image. Then we will build one image from it to kick-off our build based // - If image is not set, we read a base_image. Then we will build one image from it to kick-off our build based
@ -704,11 +777,8 @@ func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, p Compila
return nil, errors.Wrap(err, "Error while generating compilespec for "+assertion.Package.GetName()) return nil, errors.Wrap(err, "Error while generating compilespec for "+assertion.Package.GetName())
} }
compileSpec.SetOutputPath(p.GetOutputPath()) compileSpec.SetOutputPath(p.GetOutputPath())
Debug(pkgTag, " :arrow_right_hook: :whale: Builder image from hash", assertion.Hash.BuildHash)
buildImageHash := cs.ImageRepository + ":" + assertion.Hash.BuildHash Debug(pkgTag, " :arrow_right_hook: :whale: Package image from hash", assertion.Hash.PackageHash)
currentPackageImageHash := cs.ImageRepository + ":" + assertion.Hash.PackageHash
Debug(pkgTag, " :arrow_right_hook: :whale: Builder image from", buildImageHash)
Debug(pkgTag, " :arrow_right_hook: :whale: Package image name", currentPackageImageHash)
bus.Manager.Publish(bus.EventPackagePreBuild, struct { bus.Manager.Publish(bus.EventPackagePreBuild, struct {
CompileSpec CompilationSpec CompileSpec CompilationSpec
@ -718,10 +788,15 @@ func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, p Compila
Assert: assertion, Assert: assertion,
}) })
lastHash = currentPackageImageHash lastHash = assertion.Hash.PackageHash
// for the source instead, pick an image and a buildertaggedImage from hashes if they exists.
// otherways fallback to the pushed repo
// Resolve images from the hashtree
resolvedBuildImage := cs.resolveExistingImageHash(assertion.Hash.BuildHash)
if compileSpec.GetImage() != "" { if compileSpec.GetImage() != "" {
Debug(pkgTag, " :wrench: Compiling "+compileSpec.GetPackage().HumanReadableString()+" from image") Debug(pkgTag, " :wrench: Compiling "+compileSpec.GetPackage().HumanReadableString()+" from image")
artifact, err := cs.compileWithImage(compileSpec.GetImage(), buildImageHash, currentPackageImageHash, concurrency, keepPermissions, cs.KeepImg, compileSpec, packageDeps)
artifact, err := cs.compileWithImage(compileSpec.GetImage(), resolvedBuildImage, assertion.Hash.PackageHash, concurrency, keepPermissions, cs.KeepImg, compileSpec, packageDeps)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "Failed compiling "+compileSpec.GetPackage().HumanReadableString()) return nil, errors.Wrap(err, "Failed compiling "+compileSpec.GetPackage().HumanReadableString())
} }
@ -731,11 +806,9 @@ func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, p Compila
} }
Debug(pkgTag, " :wrench: Compiling "+compileSpec.GetPackage().HumanReadableString()+" from tree") Debug(pkgTag, " :wrench: Compiling "+compileSpec.GetPackage().HumanReadableString()+" from tree")
artifact, err := cs.compileWithImage(buildImageHash, "", currentPackageImageHash, concurrency, keepPermissions, cs.KeepImg, compileSpec, packageDeps) artifact, err := cs.compileWithImage(resolvedBuildImage, "", assertion.Hash.PackageHash, concurrency, keepPermissions, cs.KeepImg, compileSpec, packageDeps)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "Failed compiling "+compileSpec.GetPackage().HumanReadableString()) return nil, errors.Wrap(err, "Failed compiling "+compileSpec.GetPackage().HumanReadableString())
// deperrs = append(deperrs, err)
// break // stop at first error
} }
bus.Manager.Publish(bus.EventPackagePostBuild, struct { bus.Manager.Publish(bus.EventPackagePostBuild, struct {
@ -751,13 +824,14 @@ func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, p Compila
} }
} else if len(dependencies) > 0 { } else if len(dependencies) > 0 {
lastHash = cs.ImageRepository + ":" + dependencies[len(dependencies)-1].Hash.PackageHash lastHash = dependencies[len(dependencies)-1].Hash.PackageHash
} }
if !cs.Options.OnlyDeps { if !cs.Options.OnlyDeps {
resolvedBuildImage := cs.resolveExistingImageHash(lastHash)
Info(":rocket: All dependencies are satisfied, building package requested by the user", p.GetPackage().HumanReadableString()) Info(":rocket: All dependencies are satisfied, building package requested by the user", p.GetPackage().HumanReadableString())
Info(":package:", p.GetPackage().HumanReadableString(), " Using image: ", lastHash) Info(":package:", p.GetPackage().HumanReadableString(), " Using image: ", resolvedBuildImage)
artifact, err := cs.compileWithImage(lastHash, "", targetPackageHash, concurrency, keepPermissions, cs.KeepImg, p, true) artifact, err := cs.compileWithImage(resolvedBuildImage, "", targetAssertion.Hash.PackageHash, concurrency, keepPermissions, cs.KeepImg, p, true)
if err != nil { if err != nil {
return artifact, err return artifact, err
} }
@ -780,6 +854,7 @@ func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, p Compila
type templatedata map[string]interface{} type templatedata map[string]interface{}
// FromPackage returns a compilation spec from a package definition
func (cs *LuetCompiler) FromPackage(p pkg.Package) (CompilationSpec, error) { func (cs *LuetCompiler) FromPackage(p pkg.Package) (CompilationSpec, error) {
pack, err := cs.Database.FindPackageCandidate(p) pack, err := cs.Database.FindPackageCandidate(p)
@ -834,10 +909,12 @@ func (cs *LuetCompiler) FromPackage(p pkg.Package) (CompilationSpec, error) {
return NewLuetCompilationSpec(dataresult, pack) return NewLuetCompilationSpec(dataresult, pack)
} }
// GetBackend returns the current compilation backend
func (cs *LuetCompiler) GetBackend() CompilerBackend { func (cs *LuetCompiler) GetBackend() CompilerBackend {
return cs.Backend return cs.Backend
} }
// SetBackend sets the compilation backend
func (cs *LuetCompiler) SetBackend(b CompilerBackend) { func (cs *LuetCompiler) SetBackend(b CompilerBackend) {
cs.Backend = b cs.Backend = b
} }

View File

@ -49,7 +49,8 @@ type CompilerBackendOptions struct {
} }
type CompilerOptions struct { type CompilerOptions struct {
ImageRepository string PushImageRepository string
PullImageRepository []string
PullFirst, KeepImg, Push bool PullFirst, KeepImg, Push bool
Concurrency int Concurrency int
CompressionType CompressionImplementation CompressionType CompressionImplementation
@ -65,14 +66,14 @@ type CompilerOptions struct {
func NewDefaultCompilerOptions() *CompilerOptions { func NewDefaultCompilerOptions() *CompilerOptions {
return &CompilerOptions{ return &CompilerOptions{
ImageRepository: "luet/cache", PushImageRepository: "luet/cache",
PullFirst: false, PullFirst: false,
Push: false, Push: false,
CompressionType: None, CompressionType: None,
KeepImg: true, KeepImg: true,
Concurrency: runtime.NumCPU(), Concurrency: runtime.NumCPU(),
OnlyDeps: false, OnlyDeps: false,
NoDeps: false, NoDeps: false,
} }
} }