⚙️ Add support for subpackages during buildtime

This commit is contained in:
Ettore Di Giacinto
2022-04-27 19:01:24 +02:00
committed by mudler
parent c363c916d6
commit 2fa1defd87
14 changed files with 483 additions and 25 deletions

View File

@@ -64,6 +64,26 @@ See the `--help` of `create-repo` and `build` to learn all the available options
## Example
Luet can seamlessly build packages also from Dockerfiles (_since luet>=0.32.0_), consider the following example, that will generate a `curl` package from an `alpine` image:
```bash
$> # put yourself in some workdir
$~/workdir> mkdir curl
$~/workdir> cat <<EOF > curl/Dockerfile
FROM alpine
apk add curl
EOF
$~/workdir> luet build --all
```
However, `luet` supports an extended syntax that allows to define packages with a more fine-grained control, templating support, and several other features that makes creation batch images much faster.
### The extended syntax
A [package definition](/docs/docs/concepts/packages/specfile) is composed of a `build.yaml` and a sibiling `definition.yaml`.
In the following example, we are creating a dummy package (`bar/foo`). Which ships one file only, `/foo`
@@ -106,25 +126,6 @@ $> luet build --all
Luet "trees" are just a group of specfiles, in the above example, our tree was the current directory. You can also specify a directory with the `--tree` option. Luet doesn't enforce any tree layout, so they can be nested at any level. The only rule of thumb is that a `build.yaml` file needs to have either a `definition.yaml` or a `collection.yaml` file next to it.
## Dockerfile example
Luet can seamlessly build packages also from Dockerfiles, consider the following example, that will generate a `curl` package from an `alpine` image:
```bash
$> # put yourself in some workdir
$~/workdir> mkdir curl
$~/workdir> cat <<EOF > curl/Dockerfile
FROM alpine
apk add curl
EOF
$~/workdir> luet build --all
```
## Nesting dependencies
In the example above we have created a package from a `delta`. Luet by default creates packages by analyzing the differences between the generated containers, and extracts the differences as archive, the resulting files then are compressed and can be consumed later on by `luet install`.

View File

@@ -402,6 +402,34 @@ unpack: true
It indicates that the package content **is** the whole container content.
### `subpackages`
_since luet>=0.32.0_
(optional) A list of packages to create with the result of the current package definition.
```yaml
subpackages:
- name: "foo"
category: "bar"
version: "1.0"
includes:
- ...
excludes:
- ...
- name: "baz"
category: "bar"
version: "1.0"
```
After generating the main package, `luet` will create split packages from the resulting one from the list.
Every subpackage stanza supports `excludes` and `includes` to selectively exclude and include files in every resulting package.
Note, subpackages support is available for collection, standard packages and templated packages.
See [Package concepts](/docs/docs/concepts/packages) for more information on how to represent a package in a Luet tree.
## Rutime specs
Runtime specification are denoted in a `definition.yaml` or a `collection.yaml` sibiling file. It identifies the package and the runtime contraints attached to it.

View File

@@ -113,7 +113,23 @@ func (a *PackageArtifact) Verify() error {
return nil
}
func (a *PackageArtifact) WriteYAML(dst string) error {
type opts struct {
runtimePackage *types.Package
}
func WithRuntimePackage(p *types.Package) func(o *opts) {
return func(o *opts) {
o.runtimePackage = p
}
}
func (a *PackageArtifact) WriteYAML(dst string, o ...func(o *opts)) error {
opts := &opts{}
for _, oo := range o {
oo(opts)
}
// First compute checksum of artifact. When we write the yaml we want to write up-to-date informations.
err := a.Hash()
if err != nil {
@@ -121,12 +137,14 @@ func (a *PackageArtifact) WriteYAML(dst string) error {
}
// Update runtime package information
if a.CompileSpec != nil && a.CompileSpec.Package != nil {
if a.CompileSpec != nil && a.CompileSpec.Package != nil && opts.runtimePackage == nil {
runtime, err := a.CompileSpec.Package.GetRuntimePackage()
if err != nil {
return errors.Wrapf(err, "getting runtime package for '%s'", a.CompileSpec.Package.HumanReadableString())
}
a.Runtime = runtime
} else if opts.runtimePackage != nil {
a.Runtime = opts.runtimePackage
}
data, err := yaml.Marshal(a)
@@ -507,12 +525,26 @@ func (a *PackageArtifact) GetProtectFiles(ctx types.Context) (res []string) {
}
// Unpack Untar and decompress (TODO) to the given path
func (a *PackageArtifact) Unpack(ctx types.Context, dst string, keepPerms bool) error {
func (a *PackageArtifact) Unpack(ctx types.Context, dst string, keepPerms bool, filters ...func(h *tar.Header) (bool, error)) error {
if !strings.HasPrefix(dst, string(os.PathSeparator)) {
return errors.New("destination must be an absolute path")
}
var filter func(h *tar.Header) (bool, error)
if len(filters) > 0 {
filter = func(h *tar.Header) (bool, error) {
for _, f := range filters {
b, err := f(h)
if !b || err != nil {
return b, err
}
}
return true, nil
}
}
// Create
protectedFiles := a.GetProtectFiles(ctx)
@@ -546,7 +578,7 @@ func (a *PackageArtifact) Unpack(ctx types.Context, dst string, keepPerms bool)
// // tarModifier.Modifier()
// return true, nil
// },
_, _, err = image.ExtractReader(ctx, replacerArchive, dst, nil)
_, _, err = image.ExtractReader(ctx, replacerArchive, dst, filter)
return err
}

View File

@@ -100,8 +100,14 @@ const (
Zstandard CompressionImplementation = "zstd"
)
type SubPackage struct {
*Package
Includes []string `json:"includes,omitempty" yaml:"includes,omitempty"`
Excludes []string `json:"excludes,omitempty" yaml:"excludes,omitempty"`
}
type LuetCompilationSpec struct {
Steps []string `json:"steps"` // Are run inside a container and the result layer diff is saved
Steps []string `json:"steps" yaml:"steps,omitempty"` // Are run inside a container and the result layer diff is saved
Env []string `json:"env"`
Prelude []string `json:"prelude"` // Are run inside the image which will be our builder
Image string `json:"image"`
@@ -110,6 +116,8 @@ type LuetCompilationSpec struct {
SourceAssertion PackagesAssertions `json:"-"`
PackageDir string `json:"package_dir" yaml:"package_dir"`
SubPackages []*SubPackage `json:"subpackages,omitempty" yaml:"subpackages,omitempty"`
Retrieve []string `json:"retrieve"`
OutputPath string `json:"-"` // Where the build processfiles go

View File

@@ -521,9 +521,61 @@ func (cs *LuetCompiler) genArtifact(p *types.LuetCompilationSpec, builderOpts, r
return nil, err
}
// Write sub packages
if len(a.CompileSpec.SubPackages) > 0 {
cs.Options.Context.Success(pkgTag, " :gear: Creating sub packages")
for _, sub := range a.CompileSpec.SubPackages {
if err := cs.buildSubPackage(a, sub, p, keepPermissions, concurrency); err != nil {
return nil, err
}
}
}
return a, nil
}
func (cs *LuetCompiler) buildSubPackage(a *artifact.PackageArtifact, sub *types.SubPackage, spec *types.LuetCompilationSpec, keepPermissions bool, concurrency int) error {
sub.SetPath(spec.Package.Path)
cs.Options.Context.Info(":arrow_right: Creating sub package", sub.HumanReadableString())
subArtifactDir, err := cs.Options.Context.TempDir("subpackage")
if err != nil {
return errors.Wrap(err, "could not create tempdir for final artifact")
}
defer os.RemoveAll(subArtifactDir)
err = a.Unpack(cs.Options.Context, subArtifactDir, keepPermissions, image.ExtractFiles(cs.Options.Context, "", sub.Includes, sub.Excludes))
if err != nil {
return errors.Wrap(err, "while unpack sub package")
}
subP := spec.Rel(sub.GetFingerPrint() + ".package.tar")
subArtifact := artifact.NewPackageArtifact(subP)
subArtifact.CompressionType = cs.Options.CompressionType
if err := subArtifact.Compress(subArtifactDir, concurrency); err != nil {
return errors.Wrap(err, "Error met while creating package archive")
}
subArtifact.CompileSpec = spec
subArtifact.CompileSpec.Package = sub.Package
subArtifact.Runtime = sub.Package
subArtifact.CompileSpec.GetPackage().SetBuildTimestamp(time.Now().String())
err = subArtifact.WriteYAML(spec.GetOutputPath(), artifact.WithRuntimePackage(sub.Package))
if err != nil {
return errors.Wrap(err, "Failed while writing metadata file")
}
cs.Options.Context.Success(" :white_check_mark: done (subpackage)", sub.HumanReadableString())
if err := cs.finalizeImages(subArtifact, spec, keepPermissions); err != nil {
return errors.Wrap(err, "Failed while writing finalizing images")
}
return nil
}
// finalizeImages finalizes images and generates final artifacts (push them as well if necessary).
func (cs *LuetCompiler) finalizeImages(a *artifact.PackageArtifact, p *types.LuetCompilationSpec, keepPermissions bool) error {

View File

@@ -1213,4 +1213,152 @@ var _ = Describe("Compiler", func() {
))
})
})
Context("Sub packages", func() {
It("Compiles from a single package", func() {
generalRecipe := tree.NewCompilerRecipe(pkg.NewInMemoryDatabase(false))
err := generalRecipe.Load("../../tests/fixtures/subpackage")
Expect(err).ToNot(HaveOccurred())
Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(1))
installerRecipe := tree.NewInstallerRecipe(pkg.NewInMemoryDatabase(false))
err = installerRecipe.Load("../../tests/fixtures/subpackage")
Expect(err).ToNot(HaveOccurred())
Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(1))
Expect(len(installerRecipe.GetDatabase().GetPackages())).To(Equal(4))
compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase())
spec, err := compiler.FromPackage(&types.Package{Name: "alpine", Category: "test", Version: "1.0"})
Expect(err).ToNot(HaveOccurred())
Expect(spec.GetPackage().GetPath()).ToNot(Equal(""))
tmpdir, err := ioutil.TempDir("", "tree")
Expect(err).ToNot(HaveOccurred())
defer os.RemoveAll(tmpdir) // clean up
spec.SetOutputPath(tmpdir)
artifacts, errs := compiler.CompileParallel(false, types.NewLuetCompilationspecs(spec))
Expect(errs).To(BeNil())
Expect(len(artifacts)).To(Equal(1))
Expect(len(artifacts[0].Dependencies)).To(Equal(0))
tmpdir2, err := ioutil.TempDir("", "tree")
Expect(err).ToNot(HaveOccurred())
defer os.RemoveAll(tmpdir2) // clean up
Expect(artifact.NewPackageArtifact(filepath.Join(tmpdir, "alpine-test-1.0.package.tar")).Unpack(ctx, tmpdir2, false)).ToNot(HaveOccurred())
Expect(fileHelper.Exists(filepath.Join(tmpdir2, "bin/busybox"))).To(BeTrue())
Expect(fileHelper.Exists(filepath.Join(tmpdir2, "var"))).To(BeTrue())
Expect(fileHelper.Exists(filepath.Join(tmpdir2, "usr"))).To(BeTrue())
Expect(fileHelper.Exists(filepath.Join(tmpdir2, "root"))).To(BeTrue())
tmpdir3, err := ioutil.TempDir("", "tree")
Expect(err).ToNot(HaveOccurred())
defer os.RemoveAll(tmpdir3) // clean up
Expect(artifact.NewPackageArtifact(filepath.Join(tmpdir, "foo-test-1.1.package.tar")).Unpack(ctx, tmpdir3, false)).ToNot(HaveOccurred())
Expect(fileHelper.Exists(filepath.Join(tmpdir3, "bin/busybox"))).To(BeTrue())
Expect(fileHelper.Exists(filepath.Join(tmpdir3, "var"))).To(BeFalse())
tmpdir4, err := ioutil.TempDir("", "tree")
Expect(err).ToNot(HaveOccurred())
defer os.RemoveAll(tmpdir4) // clean up
Expect(artifact.NewPackageArtifact(filepath.Join(tmpdir, "bar-test-1.1.package.tar")).Unpack(ctx, tmpdir4, false)).ToNot(HaveOccurred())
Expect(fileHelper.Exists(filepath.Join(tmpdir4, "bin/busybox"))).To(BeTrue())
Expect(fileHelper.Exists(filepath.Join(tmpdir4, "usr/bin/cksum"))).ToNot(BeTrue())
Expect(fileHelper.Exists(filepath.Join(tmpdir4, "usr"))).To(BeFalse())
tmpdir5, err := ioutil.TempDir("", "tree")
Expect(err).ToNot(HaveOccurred())
defer os.RemoveAll(tmpdir5) // clean up
Expect(artifact.NewPackageArtifact(filepath.Join(tmpdir, "baz-test-1.1.package.tar")).Unpack(ctx, tmpdir5, false)).ToNot(HaveOccurred())
Expect(fileHelper.Exists(filepath.Join(tmpdir5, "usr/bin/cksum"))).To(BeTrue())
Expect(fileHelper.Exists(filepath.Join(tmpdir5, "bin/busybox"))).ToNot(BeTrue())
Expect(fileHelper.Exists(filepath.Join(tmpdir5, "var"))).ToNot(BeTrue())
Expect(fileHelper.Exists(filepath.Join(tmpdir5, "root"))).ToNot(BeTrue())
Expect(fileHelper.Exists(filepath.Join(tmpdir5, "etc"))).ToNot(BeTrue())
})
It("Compiles in collections", func() {
generalRecipe := tree.NewCompilerRecipe(pkg.NewInMemoryDatabase(false))
err := generalRecipe.Load("../../tests/fixtures/subpackage_collection")
Expect(err).ToNot(HaveOccurred())
Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(2))
installerRecipe := tree.NewInstallerRecipe(pkg.NewInMemoryDatabase(false))
err = installerRecipe.Load("../../tests/fixtures/subpackage_collection")
Expect(err).ToNot(HaveOccurred())
Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(2))
Expect(len(installerRecipe.GetDatabase().GetPackages())).To(Equal(8))
compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase())
spec, err := compiler.FromPackage(&types.Package{Name: "debian", Category: "test", Version: "1.0"})
Expect(err).ToNot(HaveOccurred())
Expect(spec.GetPackage().GetPath()).ToNot(Equal(""))
tmpdir, err := ioutil.TempDir("", "tree")
Expect(err).ToNot(HaveOccurred())
defer os.RemoveAll(tmpdir) // clean up
spec.SetOutputPath(tmpdir)
artifacts, errs := compiler.CompileParallel(false, types.NewLuetCompilationspecs(spec))
Expect(errs).To(BeNil())
Expect(len(artifacts)).To(Equal(1))
Expect(len(artifacts[0].Dependencies)).To(Equal(0))
tmpdir2, err := ioutil.TempDir("", "tree")
Expect(err).ToNot(HaveOccurred())
defer os.RemoveAll(tmpdir2) // clean up
Expect(artifact.NewPackageArtifact(filepath.Join(tmpdir, "debian-test-1.0.package.tar")).Unpack(ctx, tmpdir2, false)).ToNot(HaveOccurred())
Expect(fileHelper.Exists(filepath.Join(tmpdir2, "bin/busybox"))).To(BeTrue())
Expect(fileHelper.Exists(filepath.Join(tmpdir2, "var"))).To(BeTrue())
Expect(fileHelper.Exists(filepath.Join(tmpdir2, "usr"))).To(BeTrue())
Expect(fileHelper.Exists(filepath.Join(tmpdir2, "root"))).To(BeTrue())
tmpdir3, err := ioutil.TempDir("", "tree")
Expect(err).ToNot(HaveOccurred())
defer os.RemoveAll(tmpdir3) // clean up
Expect(artifact.NewPackageArtifact(filepath.Join(tmpdir, "foo-debian-test-1.1.package.tar")).Unpack(ctx, tmpdir3, false)).ToNot(HaveOccurred())
Expect(fileHelper.Exists(filepath.Join(tmpdir3, "bin/busybox"))).To(BeTrue())
Expect(fileHelper.Exists(filepath.Join(tmpdir3, "var"))).To(BeFalse())
tmpdir4, err := ioutil.TempDir("", "tree")
Expect(err).ToNot(HaveOccurred())
defer os.RemoveAll(tmpdir4) // clean up
Expect(artifact.NewPackageArtifact(filepath.Join(tmpdir, "bar-debian-test-1.1.package.tar")).Unpack(ctx, tmpdir4, false)).ToNot(HaveOccurred())
Expect(fileHelper.Exists(filepath.Join(tmpdir4, "bin/busybox"))).To(BeTrue())
Expect(fileHelper.Exists(filepath.Join(tmpdir4, "usr/bin/cksum"))).ToNot(BeTrue())
Expect(fileHelper.Exists(filepath.Join(tmpdir4, "usr"))).To(BeFalse())
tmpdir5, err := ioutil.TempDir("", "tree")
Expect(err).ToNot(HaveOccurred())
defer os.RemoveAll(tmpdir5) // clean up
Expect(artifact.NewPackageArtifact(filepath.Join(tmpdir, "baz-debian-test-1.1.package.tar")).Unpack(ctx, tmpdir5, false)).ToNot(HaveOccurred())
Expect(fileHelper.Exists(filepath.Join(tmpdir5, "usr/bin/cksum"))).To(BeTrue())
Expect(fileHelper.Exists(filepath.Join(tmpdir5, "bin/busybox"))).ToNot(BeTrue())
Expect(fileHelper.Exists(filepath.Join(tmpdir5, "var"))).ToNot(BeTrue())
Expect(fileHelper.Exists(filepath.Join(tmpdir5, "root"))).ToNot(BeTrue())
Expect(fileHelper.Exists(filepath.Join(tmpdir5, "etc"))).ToNot(BeTrue())
})
})
})

View File

@@ -149,5 +149,4 @@ var _ = Describe("ImageHashTree", func() {
Expect(hashB).To(Equal("9ece11c782e862e366ab4b42fdaaea9d89abe41ff4d9ed1bd24c81f6041bc9da"), hashB)
})
})
})

View File

@@ -19,6 +19,7 @@ import (
"io/ioutil"
"path/filepath"
"github.com/ghodss/yaml"
"github.com/mudler/luet/pkg/api/core/template"
"github.com/mudler/luet/pkg/api/core/types"
fileHelper "github.com/mudler/luet/pkg/helpers/file"
@@ -97,6 +98,11 @@ func RuntimeCollectionParser(srcDir, currentpath, name string, templates []strin
if err != nil {
return errors.Wrap(err, "Error reading yaml "+currentpath)
}
packsRaw, err := types.GetRawPackages(dat)
if err != nil {
return errors.Wrap(err, "Error reading raw packages from "+currentpath)
}
for _, p := range packs {
// Path is set only internally when tree is loaded from disk
p.SetPath(filepath.Dir(currentpath))
@@ -104,6 +110,34 @@ func RuntimeCollectionParser(srcDir, currentpath, name string, templates []strin
if err != nil {
return errors.Wrap(err, "Error creating package "+p.GetName())
}
compileDefPath := p.Rel(CompilerDefinitionFile)
if fileHelper.Exists(compileDefPath) {
raw := packsRaw.Find(p.GetName(), p.GetCategory(), p.GetVersion())
buildyaml, err := ioutil.ReadFile(compileDefPath)
if err != nil {
return errors.Wrap(err, "Error reading file "+currentpath)
}
dat, err := template.Render(append(template.ReadFiles(templates...), string(buildyaml)), raw, map[string]interface{}{})
if err != nil {
return errors.Wrap(err,
"Error templating file "+CompilerDefinitionFile+" from "+
filepath.Dir(currentpath))
}
spec := &types.LuetCompilationSpec{}
if err := yaml.Unmarshal([]byte(dat), spec); err != nil {
return err
}
for _, s := range spec.SubPackages {
_, err = db.CreatePackage(s.Package)
if err != nil {
return errors.Wrap(err, "Error creating package "+p.GetName())
}
}
}
}
return nil
}

View File

@@ -23,6 +23,8 @@ import (
"github.com/mudler/luet/pkg/api/core/types"
fileHelper "github.com/mudler/luet/pkg/helpers/file"
"github.com/pkg/errors"
"github.com/ghodss/yaml"
)
func RuntimeDefinitionParser(srcDir, currentpath, name string, templates []string, db types.PackageDatabase) error {
@@ -45,6 +47,33 @@ func RuntimeDefinitionParser(srcDir, currentpath, name string, templates []strin
if err != nil {
return errors.Wrap(err, "Error creating package "+pack.GetName())
}
// slurp subpackages here
compileDefPath := pack.Rel(CompilerDefinitionFile)
if fileHelper.Exists(compileDefPath) {
dat, err := template.RenderWithValues(append(templates, compileDefPath), currentpath)
if err != nil {
return errors.Wrap(err,
"Error templating file "+CompilerDefinitionFile+" from "+
filepath.Dir(currentpath))
}
spec := &types.LuetCompilationSpec{}
if err := yaml.Unmarshal([]byte(dat), spec); err != nil {
return err
}
for i, _ := range spec.SubPackages {
d := spec.SubPackages[i]
d.SetPath(filepath.Dir(currentpath))
_, err = db.CreatePackage(d.Package)
if err != nil {
return errors.Wrap(err, "Error creating package "+pack.GetName())
}
}
}
return nil
}

View File

@@ -0,0 +1,21 @@
image: "alpine"
unpack: true
subpackages:
- name: "baz"
category: "test"
version: "1.1"
includes:
- usr/bin/cksum
- name: "bar"
category: "test"
version: "1.1"
excludes:
- ^/usr
{{ if eq .Values.test "yup" }}
- name: "foo"
category: "test"
version: "1.1"
excludes:
- ^/var
{{end}}

View File

@@ -0,0 +1,4 @@
category: "test"
name: "alpine"
version: "1.0"
test: "yup"

View File

@@ -0,0 +1,21 @@
image: "alpine"
unpack: true
subpackages:
- name: "baz-{{.Values.name}}"
category: "test"
version: "1.1"
includes:
- usr/bin/cksum
- name: "bar-{{.Values.name}}"
category: "test"
version: "1.1"
excludes:
- ^/usr
{{ if eq .Values.test "yup" }}
- name: "foo-{{.Values.name}}"
category: "test"
version: "1.1"
excludes:
- ^/var
{{end}}

View File

@@ -0,0 +1,9 @@
packages:
- category: "test"
name: "alpine"
version: "1.0"
test: "yup"
- category: "test"
name: "debian"
version: "1.0"
test: "yup"

View File

@@ -0,0 +1,72 @@
#!/bin/bash
export LUET_NOLOCK=true
oneTimeSetUp() {
export tmpdir="$(mktemp -d)"
}
oneTimeTearDown() {
rm -rf "$tmpdir"
}
testBuild() {
mkdir $tmpdir/testbuild
luet build --tree "$ROOT_DIR/tests/fixtures/subpackage" --destination $tmpdir/testbuild --compression gzip test/alpine
buildst=$?
assertEquals 'builds successfully' "$buildst" "0"
assertTrue 'create package baz' "[ -e '$tmpdir/testbuild/baz-test-1.1.package.tar.gz' ]"
assertTrue 'create package bar' "[ -e '$tmpdir/testbuild/bar-test-1.1.package.tar.gz' ]"
assertTrue 'create package foo' "[ -e '$tmpdir/testbuild/foo-test-1.1.package.tar.gz' ]"
assertTrue 'create package alpine' "[ -e '$tmpdir/testbuild/alpine-test-1.0.package.tar.gz' ]"
}
testRepo() {
assertTrue 'no repository' "[ ! -e '$tmpdir/testbuild/repository.yaml' ]"
luet create-repo --tree "$ROOT_DIR/tests/fixtures/subpackage" \
--output $tmpdir/testbuild \
--packages $tmpdir/testbuild \
--name "test" \
--descr "Test Repo" \
--urls $tmpdir/testrootfs \
--type disk
createst=$?
assertEquals 'create repo successfully' "$createst" "0"
assertTrue 'create repository' "[ -e '$tmpdir/testbuild/repository.yaml' ]"
}
testConfig() {
mkdir $tmpdir/testrootfs
cat <<EOF > $tmpdir/luet.yaml
general:
debug: true
system:
rootfs: $tmpdir/testrootfs
database_path: "/"
database_engine: "boltdb"
config_from_host: true
repositories:
- name: "main"
type: "disk"
enable: true
urls:
- "$tmpdir/testbuild"
EOF
luet config --config $tmpdir/luet.yaml
res=$?
assertEquals 'config test successfully' "$res" "0"
}
testInstall() {
luet install -y --config $tmpdir/luet.yaml test/foo
#luet install -y --config $tmpdir/luet.yaml test/c@1.0 > /dev/null
installst=$?
assertEquals 'install test successfully' "$installst" "0"
assertTrue 'package not installed' "[ ! -d '$tmpdir/testrootfs/var' ]"
assertTrue 'package installed' "[ -e '$tmpdir/testrootfs/bin/busybox' ]"
}
# Load shUnit2.
. "$ROOT_DIR/tests/integration/shunit2"/shunit2