Add virtual packages support

This commit is contained in:
Ettore Di Giacinto
2021-01-03 20:08:04 +01:00
parent f2ba9e02d7
commit 457acd0d8a
10 changed files with 114 additions and 20 deletions

View File

@@ -16,7 +16,6 @@
package compiler
import (
"archive/tar"
"fmt"
"io/ioutil"
"os"
@@ -427,29 +426,33 @@ func (cs *LuetCompiler) genArtifact(p CompilationSpec, builderOpts, runnerOpts C
var artifact Artifact
var rootfs string
var err error
unpack := p.ImageUnpack()
pkgTag := ":package: " + p.GetPackage().HumanReadableString()
// If package_dir was specified in the spec, we want to treat the content of the directory
// as the root of our archive. ImageUnpack is implied to be true. override it
if p.GetPackageDir() != "" {
unpack = true
}
if len(p.BuildSteps()) == 0 && len(p.GetPreBuildSteps()) == 0 && !unpack {
fakePackage := p.Rel(p.GetPackage().GetFingerPrint() + ".package.tar")
// We can't generate delta in this case. It implies the package is a virtual, and nothing has to be done really
if p.EmptyPackage() {
fakePackage := p.Rel(p.GetPackage().GetFingerPrint() + ".package.tar")
file, err := os.Create(fakePackage)
rootfs, err = ioutil.TempDir(p.GetOutputPath(), "rootfs")
if err != nil {
return nil, errors.Wrap(err, "Failed creating virtual package")
return nil, errors.Wrap(err, "Could not create tempdir")
}
defer file.Close()
tw := tar.NewWriter(file)
defer tw.Close()
defer os.RemoveAll(rootfs) // clean up
artifact := NewPackageArtifact(fakePackage)
artifact.SetCompressionType(cs.CompressionType)
if err := artifact.Compress(rootfs, concurrency); err != nil {
return nil, errors.Wrap(err, "Error met while creating package archive")
}
artifact.SetCompileSpec(p)
artifact.GetCompileSpec().GetPackage().SetBuildTimestamp(time.Now().String())
err = artifact.WriteYaml(p.GetOutputPath())
if err != nil {
return artifact, errors.Wrap(err, "Failed while writing metadata file")
}
Info(pkgTag, " :white_check_mark: done (empty virtual package)")
return artifact, nil
}
@@ -476,7 +479,7 @@ func (cs *LuetCompiler) genArtifact(p CompilationSpec, builderOpts, runnerOpts C
return nil, errors.Wrap(err, "Could not extract rootfs")
}
if unpack {
if p.UnpackedPackage() {
// Take content of container as a base for our package files
artifact, err = cs.unpackFs(rootfs, concurrency, p)
if err != nil {
@@ -524,6 +527,13 @@ func (cs *LuetCompiler) compileWithImage(image, buildertaggedImage, packageImage
keepPermissions, keepImg bool,
p CompilationSpec, generateArtifact bool) (Artifact, error) {
// If it is a virtual, check if we have to generate an empty artifact or not.
if generateArtifact && p.EmptyPackage() {
return cs.genArtifact(p, CompilerBackendOptions{}, CompilerBackendOptions{}, concurrency, keepPermissions)
} else if p.EmptyPackage() {
return &PackageArtifact{}, nil
}
if !generateArtifact {
exists := cs.Backend.ImageExists(packageImage)
if art, err := LoadArtifactFromYaml(p); err == nil && exists { // If YAML is correctly loaded, and both images exists, no reason to rebuild.
@@ -649,10 +659,13 @@ func (cs *LuetCompiler) Compile(keepPermissions bool, p CompilationSpec) (Artifa
func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, p CompilationSpec) (Artifact, error) {
Info(":package: Compiling", p.GetPackage().HumanReadableString(), ".... :coffee:")
if len(p.GetPackage().GetRequires()) == 0 && p.GetImage() == "" {
Error("Package with no deps and no seed image supplied, bailing out")
return nil, errors.New("Package " + p.GetPackage().GetFingerPrint() +
" with no deps and no seed image supplied, bailing out")
Debug(fmt.Sprintf("%s: has images %t, empty package: %t", p.GetPackage().HumanReadableString(), p.HasImageSource(), p.EmptyPackage()))
if !p.HasImageSource() && !p.EmptyPackage() {
return nil,
fmt.Errorf(
"%s is invalid: package has no dependencies and no seed image supplied while it has steps defined",
p.GetPackage().GetFingerPrint(),
)
}
targetAssertion := p.GetSourceAssertion().Search(p.GetPackage().GetFingerPrint())

View File

@@ -178,6 +178,10 @@ type CompilationSpec interface {
SetPackageDir(string)
GetPackageDir() string
EmptyPackage() bool
UnpackedPackage() bool
HasImageSource() bool
}
type CompilationSpecs interface {

View File

@@ -185,6 +185,24 @@ func (cs *LuetCompilationSpec) SetSeedImage(s string) {
cs.Seed = s
}
func (cs *LuetCompilationSpec) EmptyPackage() bool {
return len(cs.BuildSteps()) == 0 && len(cs.GetPreBuildSteps()) == 0 && !cs.UnpackedPackage()
}
func (cs *LuetCompilationSpec) UnpackedPackage() bool {
// If package_dir was specified in the spec, we want to treat the content of the directory
// as the root of our archive. ImageUnpack is implied to be true. override it
unpack := cs.ImageUnpack()
if cs.GetPackageDir() != "" {
unpack = true
}
return unpack
}
func (cs *LuetCompilationSpec) HasImageSource() bool {
return len(cs.GetPackage().GetRequires()) != 0 || cs.GetImage() != ""
}
func (cs *LuetCompilationSpec) CopyRetrieves(dest string) error {
var err error
if len(cs.Retrieve) > 0 {

0
tests/fixtures/virtuals/a/build.yaml vendored Normal file
View File

View File

@@ -0,0 +1,3 @@
category: test
name: "a"
version: "1.0"

4
tests/fixtures/virtuals/b/build.yaml vendored Normal file
View File

@@ -0,0 +1,4 @@
requires:
- category: "test"
name: "a"
version: ">=0"

View File

@@ -0,0 +1,3 @@
category: test
name: "b"
version: "1.0"

4
tests/fixtures/virtuals/c/build.yaml vendored Normal file
View File

@@ -0,0 +1,4 @@
# Invalid, no source image or requires defined, but we define steps
steps:
- echo "fail!"

View File

@@ -0,0 +1,3 @@
category: test
name: "c"
version: "1.0"

View File

@@ -0,0 +1,42 @@
#!/bin/bash
export LUET_NOLOCK=true
oneTimeSetUp() {
export tmpdir="$(mktemp -d)"
}
oneTimeTearDown() {
rm -rf "$tmpdir"
}
testBuildA() {
mkdir $tmpdir/testbuild1
luet build --tree "$ROOT_DIR/tests/fixtures/virtuals" --debug --compression "gzip" --destination $tmpdir/testbuild1 test/a
buildst=$?
assertEquals 'builds successfully' "$buildst" "0"
assertTrue 'create package A 1.0' "[ -e '$tmpdir/testbuild1/a-test-1.0.package.tar.gz' ]"
assertTrue 'create package A 1.0' "[ -e '$tmpdir/testbuild1/a-test-1.0.metadata.yaml' ]"
}
testBuildB() {
mkdir $tmpdir/testbuild2
luet build --tree "$ROOT_DIR/tests/fixtures/virtuals" --debug --compression "gzip" --destination $tmpdir/testbuild2 test/b
buildst=$?
assertEquals 'builds successfully' "$buildst" "0"
assertTrue 'create package A 1.0' "[ -e '$tmpdir/testbuild2/a-test-1.0.package.tar.gz' ]"
assertTrue 'create package A 1.0' "[ -e '$tmpdir/testbuild2/a-test-1.0.metadata.yaml' ]"
assertTrue 'create package B 1.0' "[ -e '$tmpdir/testbuild2/b-test-1.0.package.tar.gz' ]"
assertTrue 'create package B 1.0' "[ -e '$tmpdir/testbuild2/b-test-1.0.metadata.yaml' ]"
}
testBuildC() {
mkdir $tmpdir/testbuild3
luet build --tree "$ROOT_DIR/tests/fixtures/virtuals" --debug --destination $tmpdir/testbuild3 test/c
buildst=$?
assertEquals 'builds of C expected to fail' "$buildst" "1"
}
# Load shUnit2.
. "$ROOT_DIR/tests/integration/shunit2"/shunit2