mirror of
https://github.com/mudler/luet.git
synced 2025-09-06 09:41:05 +00:00
⚙️ Add support for subpackages during buildtime
This commit is contained in:
committed by
mudler
parent
c363c916d6
commit
2fa1defd87
@@ -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`.
|
||||
|
@@ -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.
|
||||
|
@@ -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
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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 {
|
||||
|
||||
|
@@ -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())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@@ -149,5 +149,4 @@ var _ = Describe("ImageHashTree", func() {
|
||||
Expect(hashB).To(Equal("9ece11c782e862e366ab4b42fdaaea9d89abe41ff4d9ed1bd24c81f6041bc9da"), hashB)
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
||||
|
21
tests/fixtures/subpackage/alpine/build.yaml
vendored
Normal file
21
tests/fixtures/subpackage/alpine/build.yaml
vendored
Normal 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}}
|
4
tests/fixtures/subpackage/alpine/definition.yaml
vendored
Normal file
4
tests/fixtures/subpackage/alpine/definition.yaml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
category: "test"
|
||||
name: "alpine"
|
||||
version: "1.0"
|
||||
test: "yup"
|
21
tests/fixtures/subpackage_collection/alpine/build.yaml
vendored
Normal file
21
tests/fixtures/subpackage_collection/alpine/build.yaml
vendored
Normal 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}}
|
9
tests/fixtures/subpackage_collection/alpine/collection.yaml
vendored
Normal file
9
tests/fixtures/subpackage_collection/alpine/collection.yaml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
packages:
|
||||
- category: "test"
|
||||
name: "alpine"
|
||||
version: "1.0"
|
||||
test: "yup"
|
||||
- category: "test"
|
||||
name: "debian"
|
||||
version: "1.0"
|
||||
test: "yup"
|
72
tests/integration/37_subpackages.sh
Executable file
72
tests/integration/37_subpackages.sh
Executable 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
|
||||
|
Reference in New Issue
Block a user