From f96d6c89c761b9c38ca79d30858f599d4bf22d4a Mon Sep 17 00:00:00 2001 From: Vincent Demeester Date: Wed, 22 Aug 2018 11:45:15 +0200 Subject: [PATCH] Fix `docker-app save` on single-file application Signed-off-by: Vincent Demeester --- e2e/commands_test.go | 21 +++++++++++++++++ internal/packager/registry.go | 44 ++++++++++++++++++++++++----------- types/types.go | 14 +++++++++++ 3 files changed, 65 insertions(+), 14 deletions(-) diff --git a/e2e/commands_test.go b/e2e/commands_test.go index ed3bb69fe..6c8426007 100644 --- a/e2e/commands_test.go +++ b/e2e/commands_test.go @@ -17,6 +17,20 @@ import ( "gotest.tools/icmd" ) +const ( + singleFileApp = `version: 0.1.0 +name: helloworld +description: "hello world app" +namespace: "foo" +--- +version: '3.5' +services: + hello-world: + image: hello-world +--- +# This section contains the default values for your application settings.` +) + // just run a command discarding everything func runCommand(exe string, args ...string) { cmd := exec.Command(exe, args...) @@ -303,6 +317,13 @@ func TestImageBinary(t *testing.T) { assertCommand(t, dockerApp, "inspect", "alice/envvariables.dockerapp:0.1.0") } +func TestSaveBinary(t *testing.T) { + dir := fs.NewDir(t, "save-prepare-build", fs.WithFile("my.dockerapp", singleFileApp)) + defer dir.Remove() + dockerApp, _ := getDockerAppBinary(t) + assertCommand(t, dockerApp, "save", dir.Join("my.dockerapp")) +} + func TestForkBinary(t *testing.T) { dockerApp, _ := getDockerAppBinary(t) r := startRegistry(t) diff --git a/internal/packager/registry.go b/internal/packager/registry.go index 12412a77b..b88faf3d0 100644 --- a/internal/packager/registry.go +++ b/internal/packager/registry.go @@ -35,29 +35,45 @@ func Save(app *types.App, namespace, tag string) (string, error) { if namespace != "" && !strings.HasSuffix(namespace, "/") { namespace += "/" } + dir, err := prepareDockerBuildDirectory(app, meta, namespace, tag) + if err != nil { + return "", err + } + defer os.RemoveAll(dir) + imageName := namespace + internal.AppNameFromDir(app.Name) + internal.AppExtension + ":" + tag + args := []string{"build", "-t", imageName, dir} + cmd := exec.Command("docker", args...) + cmd.Stdout = ioutil.Discard + cmd.Stderr = os.Stderr + err = cmd.Run() + return imageName, err +} + +func prepareDockerBuildDirectory(app *types.App, meta metadata.AppMetadata) (string, error) { dockerfile := fmt.Sprintf(` FROM scratch LABEL %s=%s LABEL maintainers="%v" COPY / / `, internal.ImageLabel, meta.Name, meta.Maintainers) - df := filepath.Join(app.Path, "__Dockerfile-docker-app__") + dir, err := ioutil.TempDir("", "app-save") + if err != nil { + return "", errors.Wrap(err, "cannot create temporary directory") + } + // Write dockerfile + df := filepath.Join(dir, "Dockerfile") if err := ioutil.WriteFile(df, []byte(dockerfile), 0644); err != nil { - return "", errors.Wrapf(err, "cannot create file %s", df) + return dir, errors.Wrapf(err, "cannot create file %s", df) } - defer os.Remove(df) - di := filepath.Join(app.Path, ".dockerignore") - if err := ioutil.WriteFile(di, []byte("__Dockerfile-docker-app__\n.dockerignore"), 0644); err != nil { - return "", errors.Wrapf(err, "cannot create file %s", di) + di := filepath.Join(dir, ".dockerignore") + if err := ioutil.WriteFile(di, []byte("Dockerfile\n.dockerignore"), 0644); err != nil { + return dir, errors.Wrapf(err, "cannot create file %s", di) } - defer os.Remove(di) - imageName := namespace + internal.AppNameFromDir(app.Name) + internal.AppExtension + ":" + tag - args := []string{"build", "-t", imageName, "-f", df, app.Path} - cmd := exec.Command("docker", args...) - cmd.Stdout = ioutil.Discard - cmd.Stderr = os.Stderr - err = cmd.Run() - return imageName, err + // Write app content + if err := app.Extract(dir); err != nil { + return dir, errors.Wrap(err, "cannot extract app") + } + return dir, nil } // Load loads an app from docker diff --git a/types/types.go b/types/types.go index ac406df8c..75847e630 100644 --- a/types/types.go +++ b/types/types.go @@ -39,6 +39,20 @@ func (a *App) Metadata() []byte { return a.metadataContent } +// Extract writes the app in the specified folder +func (a *App) Extract(path string) error { + if err := ioutil.WriteFile(filepath.Join(path, internal.MetadataFileName), a.Metadata(), 0644); err != nil { + return err + } + if err := ioutil.WriteFile(filepath.Join(path, internal.ComposeFileName), a.Composes()[0], 0644); err != nil { + return err + } + if err := ioutil.WriteFile(filepath.Join(path, internal.SettingsFileName), a.Settings()[0], 0644); err != nil { + return err + } + return nil +} + func noop() {} // NewApp creates a new docker app with the specified path and struct modifiers