Add Separate tree for build dependency

Reuse the Recipe and extend it to read a separate tree for build
dependencies.

Also add accessors to compilespec to produce dockerfile image format.
This commit is contained in:
Ettore Di Giacinto
2019-11-05 17:36:22 +01:00
parent f570f74a9e
commit ff88ff67c2
7 changed files with 254 additions and 12 deletions

View File

@@ -27,15 +27,37 @@ import (
const BuildFile = "build.yaml"
type LuetCompiler struct {
*tree.Recipe
*tree.CompilerRecipe
Backend CompilerBackend
}
func NewLuetCompiler(backend CompilerBackend, t pkg.Tree) Compiler {
return &LuetCompiler{Backend: backend, Recipe: &tree.Recipe{PackageTree: t}}
// The CompilerRecipe will gives us a tree with only build deps listed.
return &LuetCompiler{
Backend: backend,
CompilerRecipe: &tree.CompilerRecipe{
tree.Recipe{PackageTree: t},
},
}
}
func (cs *LuetCompiler) Compile(p CompilationSpec) (*Artifact, error) {
// - If image is not set, we read a base_image. Then we will build one image from it to kick-off our build based
// on how we compute the resolvable tree.
// This means to recursively build all the build-images needed to reach that tree part.
// - We later on compute an hash used to identify the image, so each similar deptree keeps the same build image.
// - 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
if p.GetImage() != "" {
p.SetSeedImage(p.GetImage())
//p.WriteBuildImageDefinition(path)
//backend.BuildImage(path)
//backend.RunSteps(CompilationSpec)
}
return nil, errors.New("Not implemented yet")
}
@@ -54,7 +76,7 @@ func (cs *LuetCompiler) FromPackage(p pkg.Package) (CompilationSpec, error) {
if err != nil {
return nil, err
}
return NewLuetCompilationSpec(dat)
return NewLuetCompilationSpec(dat, p)
}
func (cs *LuetCompiler) GetBackend() CompilerBackend {

View File

@@ -26,11 +26,23 @@ type Compiler interface {
}
type CompilerBackend interface {
Tree() pkg.Tree
WithTree(pkg.Tree)
BuildImage(name, path,dockerfileName string) error
}
// CompilationSpec represent a compilation specification derived from a package
type CompilationSpec interface {
ToDocker() (string, error)
RenderBuildImage() (string, error)
WriteBuildImageDefinition(string) error
RenderStepImage(image string) (string, error)
WriteStepImageDefinition(fromimage, path string) error
GetPackage() pkg.Package
BuildSteps() []string
GetSeedImage() string
SetSeedImage(string)
GetImage() string
SetImage(string)
}

View File

@@ -16,23 +16,86 @@
package compiler
import (
pkg "github.com/mudler/luet/pkg/package"
yaml "gopkg.in/yaml.v2"
"io/ioutil"
)
type LuetCompilationSpec struct {
Steps []string `json:"steps"`
Image string `json:"image"`
Steps []string `json:"steps"` // Are run inside a container and the result layer diff is saved
Image string `json:"image"`
Seed string `json:"seed"`
Package pkg.Package `json:"-"`
}
func NewLuetCompilationSpec(b []byte) (CompilationSpec, error) {
func NewLuetCompilationSpec(b []byte, p pkg.Package) (CompilationSpec, error) {
var spec LuetCompilationSpec
err := yaml.Unmarshal(b, &spec)
if err != nil {
return &spec, err
}
spec.Package = p
return &spec, nil
}
func (cs *LuetCompilationSpec) ToDocker() (string, error) {
return "", nil
func (cs *LuetCompilationSpec) GetPackage() pkg.Package {
return cs.Package
}
func (cs *LuetCompilationSpec) BuildSteps() []string {
return cs.Steps
}
func (cs *LuetCompilationSpec) GetSeedImage() string {
return cs.Seed
}
func (cs *LuetCompilationSpec) GetImage() string {
return cs.Image
}
func (cs *LuetCompilationSpec) SetImage(s string) {
cs.Image = s
}
func (cs *LuetCompilationSpec) SetSeedImage(s string) {
cs.Seed = s
}
// TODO: docker build image first. Then a backend can be used to actually spin up a container with it and run the steps within
func (cs *LuetCompilationSpec) RenderBuildImage() (string, error) {
spec := `
FROM ` + cs.GetSeedImage() + `
COPY . /luetbuild
WORKDIR /luetbuild
`
return spec, nil
}
// TODO: docker build image first. Then a backend can be used to actually spin up a container with it and run the steps within
func (cs *LuetCompilationSpec) RenderStepImage(image string) (string, error) {
spec := `
FROM ` + image
for _, s := range cs.BuildSteps() {
spec = spec + `
RUN ` + s
}
return spec, nil
}
func (cs *LuetCompilationSpec) WriteBuildImageDefinition(path string) error {
data, err := cs.RenderBuildImage()
if err != nil {
return err
}
return ioutil.WriteFile(path, []byte(data), 0644)
}
func (cs *LuetCompilationSpec) WriteStepImageDefinition(fromimage, path string) error {
data, err := cs.RenderStepImage(fromimage)
if err != nil {
return err
}
return ioutil.WriteFile(path, []byte(data), 0644)
}

View File

@@ -17,10 +17,14 @@ package compiler_test
import (
. "github.com/mudler/luet/pkg/compiler"
helpers "github.com/mudler/luet/pkg/helpers"
pkg "github.com/mudler/luet/pkg/package"
"github.com/mudler/luet/pkg/tree"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"io/ioutil"
"os"
"path/filepath"
)
var _ = Describe("Spec", func() {
@@ -43,6 +47,30 @@ var _ = Describe("Spec", func() {
Expect(lspec.Steps).To(Equal([]string{"echo foo", "bar"}))
Expect(lspec.Image).To(Equal("luet/base"))
Expect(lspec.Seed).To(Equal("luet/baseimage"))
tmpdir, err := ioutil.TempDir("", "tree")
Expect(err).ToNot(HaveOccurred())
defer os.RemoveAll(tmpdir) // clean up
err = lspec.WriteBuildImageDefinition(filepath.Join(tmpdir, "Dockerfile"))
Expect(err).ToNot(HaveOccurred())
dockerfile, err := helpers.Read(filepath.Join(tmpdir, "Dockerfile"))
Expect(err).ToNot(HaveOccurred())
Expect(dockerfile).To(Equal(`
FROM luet/baseimage
COPY . /luetbuild
WORKDIR /luetbuild
`))
err = lspec.WriteStepImageDefinition(lspec.Image, filepath.Join(tmpdir, "Dockerfile"))
Expect(err).ToNot(HaveOccurred())
dockerfile, err = helpers.Read(filepath.Join(tmpdir, "Dockerfile"))
Expect(err).ToNot(HaveOccurred())
Expect(dockerfile).To(Equal(`
FROM luet/base
RUN echo foo
RUN bar`))
})
})