diff --git a/pkg/compiler/artifact.go b/pkg/compiler/artifact.go index f9f0781e..e3c7f30d 100644 --- a/pkg/compiler/artifact.go +++ b/pkg/compiler/artifact.go @@ -15,11 +15,6 @@ package compiler -type Artifact interface { - GetPath() string - SetPath(string) -} - type PackageArtifact struct { Path string } diff --git a/pkg/compiler/backend/simpledocker.go b/pkg/compiler/backend/simpledocker.go index 793fd0d1..a06386c9 100644 --- a/pkg/compiler/backend/simpledocker.go +++ b/pkg/compiler/backend/simpledocker.go @@ -16,6 +16,7 @@ package backend import ( + "encoding/json" "os/exec" "github.com/mudler/luet/pkg/compiler" @@ -37,6 +38,8 @@ func (*SimpleDocker) BuildImage(opts compiler.CompilerBackendOptions) error { dockerfileName := opts.DockerFileName buildarg := []string{"build", "-f", dockerfileName, "-t", name, "."} Spinner(22) + defer SpinnerStop() + Debug("Building image "+name+" - running docker with: ", buildarg) cmd := exec.Command("docker", buildarg...) cmd.Dir = path @@ -44,7 +47,6 @@ func (*SimpleDocker) BuildImage(opts compiler.CompilerBackendOptions) error { if err != nil { return errors.Wrap(err, "Failed building image: "+string(out)) } - SpinnerStop() Info(string(out)) return nil } @@ -53,11 +55,11 @@ func (*SimpleDocker) RemoveImage(opts compiler.CompilerBackendOptions) error { name := opts.ImageName buildarg := []string{"rmi", name} Spinner(22) + defer SpinnerStop() out, err := exec.Command("docker", buildarg...).CombinedOutput() if err != nil { return errors.Wrap(err, "Failed removing image: "+string(out)) } - SpinnerStop() Info(string(out)) return nil } @@ -81,14 +83,59 @@ func (*SimpleDocker) ExportImage(opts compiler.CompilerBackendOptions) error { buildarg := []string{"save", name, "-o", path} Spinner(22) + defer SpinnerStop() Debug("Saving image "+name+" - running docker with: ", buildarg) out, err := exec.Command("docker", buildarg...).CombinedOutput() if err != nil { return errors.Wrap(err, "Failed exporting image: "+string(out)) } - SpinnerStop() + Info(string(out)) return nil } -// TODO: Use container-diff (https://github.com/GoogleContainerTools/container-diff) for checking out layer diffs +// container-diff diff daemon://luet/base alpine --type=file -j +// [ +// { +// "Image1": "luet/base", +// "Image2": "alpine", +// "DiffType": "File", +// "Diff": { +// "Adds": null, +// "Dels": [ +// { +// "Name": "/luetbuild", +// "Size": 5830706 +// }, +// { +// "Name": "/luetbuild/Dockerfile", +// "Size": 50 +// }, +// { +// "Name": "/luetbuild/output1", +// "Size": 5830656 +// } +// ], +// "Mods": null +// } +// } +// ] +// Changes uses container-diff (https://github.com/GoogleContainerTools/container-diff) for retrieving out layer diffs +func (*SimpleDocker) Changes(fromImage, toImage string) ([]compiler.ArtifactLayer, error) { + diffargs := []string{"diff", fromImage, toImage, "--type=file", "-j"} + Spinner(22) + defer SpinnerStop() + + out, err := exec.Command("container-diff", diffargs...).CombinedOutput() + if err != nil { + return []compiler.ArtifactLayer{}, errors.Wrap(err, "Failed Resolving layer diffs: "+string(out)) + } + + var diffs []compiler.ArtifactLayer + + err = json.Unmarshal(out, &diffs) + if err != nil { + return []compiler.ArtifactLayer{}, errors.Wrap(err, "Failed unmarshalling json response: "+string(out)) + } + return diffs, nil +} diff --git a/pkg/compiler/backend/simpledocker_test.go b/pkg/compiler/backend/simpledocker_test.go index 0a89070d..74b0da41 100644 --- a/pkg/compiler/backend/simpledocker_test.go +++ b/pkg/compiler/backend/simpledocker_test.go @@ -55,6 +55,10 @@ var _ = Describe("Docker backend", func() { Expect(err).ToNot(HaveOccurred()) defer os.RemoveAll(tmpdir) // clean up + tmpdir2, err := ioutil.TempDir(os.TempDir(), "tree2") + Expect(err).ToNot(HaveOccurred()) + defer os.RemoveAll(tmpdir2) // clean up + err = lspec.WriteBuildImageDefinition(filepath.Join(tmpdir, "Dockerfile")) Expect(err).ToNot(HaveOccurred()) dockerfile, err := helpers.Read(filepath.Join(tmpdir, "Dockerfile")) @@ -69,10 +73,10 @@ WORKDIR /luetbuild ImageName: "luet/base", SourcePath: tmpdir, DockerFileName: "Dockerfile", - Destination: filepath.Join(tmpdir, "output1"), + Destination: filepath.Join(tmpdir2, "output1.tar"), } Expect(b.ImageDefinitionToTar(opts)).ToNot(HaveOccurred()) - Expect(helpers.Exists(filepath.Join(tmpdir, "output1"))).To(BeTrue()) + Expect(helpers.Exists(filepath.Join(tmpdir2, "output1.tar"))).To(BeTrue()) Expect(b.BuildImage(opts)).ToNot(HaveOccurred()) err = lspec.WriteStepImageDefinition(lspec.Image, filepath.Join(tmpdir, "LuetDockerfile")) @@ -87,10 +91,22 @@ RUN echo bar > /test2`)) ImageName: "test", SourcePath: tmpdir, DockerFileName: "LuetDockerfile", - Destination: filepath.Join(tmpdir, "output2"), + Destination: filepath.Join(tmpdir, "output2.tar"), } Expect(b.ImageDefinitionToTar(opts)).ToNot(HaveOccurred()) - Expect(helpers.Exists(filepath.Join(tmpdir, "output2"))).To(BeTrue()) + Expect(helpers.Exists(filepath.Join(tmpdir, "output2.tar"))).To(BeTrue()) + + Expect(b.Changes(filepath.Join(tmpdir2, "output1.tar"), filepath.Join(tmpdir, "output2.tar"))).To(Equal( + []ArtifactLayer{{ + FromImage: filepath.Join(tmpdir2, "output1.tar"), + ToImage: filepath.Join(tmpdir, "output2.tar"), + Diffs: ArtifactDiffs{ + Additions: []ArtifactNode{ + {Name: "/test", Size: 4}, + {Name: "/test2", Size: 4}, + }, + }, + }})) }) diff --git a/pkg/compiler/backend/simpleimg.go b/pkg/compiler/backend/simpleimg.go index 22a0f676..d45d9cef 100644 --- a/pkg/compiler/backend/simpleimg.go +++ b/pkg/compiler/backend/simpleimg.go @@ -16,6 +16,7 @@ package backend import ( + "encoding/json" "os/exec" "github.com/mudler/luet/pkg/compiler" @@ -89,4 +90,25 @@ func (*SimpleImg) ExportImage(opts compiler.CompilerBackendOptions) error { return nil } +// TODO: Dup in docker, refactor common code in helpers for shared parts + // TODO: Use container-diff (https://github.com/GoogleContainerTools/container-diff) for checking out layer diffs +// Changes uses container-diff (https://github.com/GoogleContainerTools/container-diff) for retrieving out layer diffs +func (*SimpleImg) Changes(fromImage, toImage string) ([]compiler.ArtifactLayer, error) { + diffargs := []string{"diff", fromImage, toImage, "--type=file", "-j"} + Spinner(22) + defer SpinnerStop() + + out, err := exec.Command("container-diff", diffargs...).CombinedOutput() + if err != nil { + return []compiler.ArtifactLayer{}, errors.Wrap(err, "Failed Resolving layer diffs: "+string(out)) + } + + var diffs []compiler.ArtifactLayer + + err = json.Unmarshal(out, &diffs) + if err != nil { + return []compiler.ArtifactLayer{}, errors.Wrap(err, "Failed unmarshalling json response: "+string(out)) + } + return diffs, nil +} diff --git a/pkg/compiler/interface.go b/pkg/compiler/interface.go index 76c1c45b..2d4aeda2 100644 --- a/pkg/compiler/interface.go +++ b/pkg/compiler/interface.go @@ -15,7 +15,9 @@ package compiler -import pkg "github.com/mudler/luet/pkg/package" +import ( + pkg "github.com/mudler/luet/pkg/package" +) type Compiler interface { Compile(CompilationSpec) (Artifact, error) @@ -36,9 +38,30 @@ type CompilerBackend interface { BuildImage(CompilerBackendOptions) error ExportImage(CompilerBackendOptions) error RemoveImage(CompilerBackendOptions) error + Changes(fromImage, toImage string) ([]ArtifactLayer, error) ImageDefinitionToTar(CompilerBackendOptions) error } +type Artifact interface { + GetPath() string + SetPath(string) +} + +type ArtifactNode struct { + Name string `json:"Name"` + Size int `json:"Size"` +} +type ArtifactDiffs struct { + Additions []ArtifactNode `json:"Adds"` + Deletions []ArtifactNode `json:"Dels"` + Changes []ArtifactNode `json:"Mods"` +} +type ArtifactLayer struct { + FromImage string `json:"Image1"` + ToImage string `json:"Image2"` + Diffs ArtifactDiffs `json:"Diff"` +} + // CompilationSpec represent a compilation specification derived from a package type CompilationSpec interface { RenderBuildImage() (string, error)