diff --git a/pkg/compiler/artifact.go b/pkg/compiler/artifact.go index 3c2d1feb..55e99627 100644 --- a/pkg/compiler/artifact.go +++ b/pkg/compiler/artifact.go @@ -241,6 +241,46 @@ func (a *PackageArtifact) SetPath(p string) { a.Path = p } +func (a *PackageArtifact) genDockerfile() string { + return ` +FROM scratch +COPY * /` +} + +// GenerateFinalImage takes an artifact and builds a Docker image with its content +func (a *PackageArtifact) GenerateFinalImage(imageprefix string, b CompilerBackend, keepPerms bool) (CompilerBackendOptions, error) { + builderOpts := CompilerBackendOptions{} + archive, err := LuetCfg.GetSystem().TempDir("archive") + if err != nil { + return builderOpts, errors.Wrap(err, "error met while creating tempdir for "+a.Path) + } + defer os.RemoveAll(archive) // clean up + + uncompressedFiles := filepath.Join(archive, "files") + dockerFile := filepath.Join(archive, "Dockerfile") + + if err := os.MkdirAll(uncompressedFiles, os.ModePerm); err != nil { + return builderOpts, errors.Wrap(err, "error met while creating tempdir for "+a.Path) + } + + data := a.genDockerfile() + if err := ioutil.WriteFile(dockerFile, []byte(data), 0644); err != nil { + return builderOpts, errors.Wrap(err, "error met while rendering artifact dockerfile "+a.Path) + } + + if err := a.Unpack(uncompressedFiles, keepPerms); err != nil { + return builderOpts, errors.Wrap(err, "error met while uncompressing artifact "+a.Path) + } + + builderOpts = CompilerBackendOptions{ + ImageName: imageprefix + a.CompileSpec.Package.GetFingerPrint(), + SourcePath: archive, + DockerFileName: dockerFile, + Context: uncompressedFiles, + } + return builderOpts, b.BuildImage(builderOpts) +} + // Compress Archives and compress (TODO) to the artifact path func (a *PackageArtifact) Compress(src string, concurrency int) error { switch a.CompressionType { diff --git a/pkg/compiler/artifact_test.go b/pkg/compiler/artifact_test.go index 8335b2c6..239f1c85 100644 --- a/pkg/compiler/artifact_test.go +++ b/pkg/compiler/artifact_test.go @@ -159,5 +159,46 @@ RUN echo bar > /test2`)) Expect(err).To(HaveOccurred()) }) + It("Generates packages images", func() { + b := NewSimpleDockerBackend() + imageprefix := "foo/" + testString := []byte(`funky test data`) + + tmpdir, err := ioutil.TempDir(os.TempDir(), "artifact") + Expect(err).ToNot(HaveOccurred()) + defer os.RemoveAll(tmpdir) // clean up + + tmpWork, err := ioutil.TempDir(os.TempDir(), "artifact2") + Expect(err).ToNot(HaveOccurred()) + defer os.RemoveAll(tmpWork) // clean up + + err = ioutil.WriteFile(filepath.Join(tmpdir, "test"), testString, 0644) + Expect(err).ToNot(HaveOccurred()) + + artifact := NewPackageArtifact(filepath.Join(tmpWork, "fake.tar")) + artifact.SetCompileSpec(&LuetCompilationSpec{Package: &pkg.DefaultPackage{Name: "foo", Version: "1.0"}}) + + err = artifact.Compress(tmpdir, 1) + Expect(err).ToNot(HaveOccurred()) + resultingImage := imageprefix + "foo--1.0" + opts, err := artifact.GenerateFinalImage(imageprefix, b, false) + Expect(err).ToNot(HaveOccurred()) + Expect(opts.ImageName).To(Equal(resultingImage)) + + Expect(b.ImageExists(resultingImage)).To(BeTrue()) + + result, err := ioutil.TempDir(os.TempDir(), "result") + Expect(err).ToNot(HaveOccurred()) + defer os.RemoveAll(result) // clean up + + err = b.ExtractRootfs(CompilerBackendOptions{ImageName: resultingImage, Destination: result}, false) + Expect(err).ToNot(HaveOccurred()) + + content, err := ioutil.ReadFile(filepath.Join(result, "test")) + Expect(err).ToNot(HaveOccurred()) + + Expect(content).To(Equal(testString)) + }) + }) }) diff --git a/pkg/compiler/backend/simpledocker.go b/pkg/compiler/backend/simpledocker.go index 9948bc8f..0767ad69 100644 --- a/pkg/compiler/backend/simpledocker.go +++ b/pkg/compiler/backend/simpledocker.go @@ -183,10 +183,23 @@ type ManifestEntry struct { Layers []string `json:"Layers"` } -func (*SimpleDocker) ExtractRootfs(opts compiler.CompilerBackendOptions, keepPerms bool) error { +func (b *SimpleDocker) ExtractRootfs(opts compiler.CompilerBackendOptions, keepPerms bool) error { src := opts.SourcePath dst := opts.Destination + if src == "" && opts.ImageName != "" { + tempUnpack, err := ioutil.TempDir(dst, "tempUnpack") + if err != nil { + return errors.Wrap(err, "Error met while creating tempdir for rootfs") + } + defer os.RemoveAll(tempUnpack) // clean up + imageExport := filepath.Join(tempUnpack, "image.tar") + if err := b.ExportImage(compiler.CompilerBackendOptions{ImageName: opts.ImageName, Destination: imageExport}); err != nil { + return errors.Wrap(err, "while exporting image before extraction") + } + src = imageExport + } + rootfs, err := ioutil.TempDir(dst, "tmprootfs") if err != nil { return errors.Wrap(err, "Error met while creating tempdir for rootfs") diff --git a/pkg/compiler/backend/simpleimg.go b/pkg/compiler/backend/simpleimg.go index fbccf8c0..6ba7da75 100644 --- a/pkg/compiler/backend/simpleimg.go +++ b/pkg/compiler/backend/simpleimg.go @@ -139,7 +139,7 @@ func (*SimpleImg) ExportImage(opts compiler.CompilerBackendOptions) error { return nil } -// TODO: Dup in docker, refactor common code in helpers for shared parts +// ExtractRootfs extracts the docker image content inside the destination func (*SimpleImg) ExtractRootfs(opts compiler.CompilerBackendOptions, keepPerms bool) error { name := opts.ImageName path := opts.Destination @@ -153,7 +153,6 @@ func (*SimpleImg) ExtractRootfs(opts compiler.CompilerBackendOptions, keepPerms } Info(":tea: Image " + name + " extracted") return nil - //return NewSimpleDockerBackend().ExtractRootfs(opts, keepPerms) } // TODO: Use container-diff (https://github.com/GoogleContainerTools/container-diff) for checking out layer diffs diff --git a/pkg/compiler/interface.go b/pkg/compiler/interface.go index 2f932648..97cc0f3c 100644 --- a/pkg/compiler/interface.go +++ b/pkg/compiler/interface.go @@ -114,6 +114,8 @@ type Artifact interface { GetChecksums() Checksums SetChecksums(c Checksums) + + GenerateFinalImage(string, CompilerBackend, bool) (CompilerBackendOptions, error) } type ArtifactNode struct {