From 64b28a6888900bae0cd9814ee3b93994dae4cabc Mon Sep 17 00:00:00 2001 From: Mathieu Frenette Date: Sat, 29 May 2021 14:35:37 -0400 Subject: [PATCH 1/4] First draft of work-dir synchronisation --- .vscode/launch.json | 17 +++++++++++++++++ src/cmd/run/run.go | 31 ++++++++++++++++++++++++++++++- src/internal/context.go | 34 ++++++++++++++++++++++++++++++++++ src/internal/docker/cli.go | 32 ++++++++++++++++++++------------ 4 files changed, 101 insertions(+), 13 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..97cbcae --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + // Utilisez IntelliSense pour en savoir plus sur les attributs possibles. + // Pointez pour afficher la description des attributs existants. + // Pour plus d'informations, visitez : https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Debug yey run", + "type": "go", + "request": "launch", + "mode": "debug", + "program": "${workspaceFolder}/src", + "args": ["run"], + "cwd": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/src/cmd/run/run.go b/src/cmd/run/run.go index 51cdefc..189060b 100644 --- a/src/cmd/run/run.go +++ b/src/cmd/run/run.go @@ -3,6 +3,9 @@ package run import ( "context" "fmt" + "os" + "path/filepath" + "strings" yey "github.com/silphid/yey/src/internal" "github.com/silphid/yey/src/internal/docker" @@ -73,5 +76,31 @@ func run(ctx context.Context, name string, options Options) error { } } - return docker.Start(ctx, yeyContext, containerName) + workDir, err := getContainerWorkDir(yeyContext) + if err != nil { + return err + } + + return docker.Start(ctx, yeyContext, containerName, workDir) +} + +func getContainerWorkDir(yeyContext yey.Context) (string, error) { + workDir, err := os.Getwd() + if err != nil { + return "", err + } + + mounts, err := yeyContext.ResolveMounts() + if err != nil { + return "", err + } + + for key, value := range mounts { + if strings.HasPrefix(workDir, key) { + subDir := strings.TrimPrefix(workDir, key) + return filepath.Join(value, subDir), nil + } + } + + return "", nil } diff --git a/src/internal/context.go b/src/internal/context.go index df30cc2..104712f 100644 --- a/src/internal/context.go +++ b/src/internal/context.go @@ -1,6 +1,9 @@ package yey import ( + "path/filepath" + + "github.com/mitchellh/go-homedir" "gopkg.in/yaml.v2" ) @@ -60,3 +63,34 @@ func (c Context) String() string { } return string(buf) } + +func (c Context) ResolveMounts() (map[string]string, error) { + mounts := make(map[string]string, len(c.Mounts)) + for key, value := range c.Mounts { + dir, err := resolveLocalDir(key) + if err != nil { + return nil, err + } + mounts[dir] = value + } + return mounts, nil +} + +func resolveLocalDir(dir string) (string, error) { + var err error + if dir == "~" { + dir, err = homedir.Dir() + } else { + dir, err = homedir.Expand(dir) + } + if err != nil { + return "", err + } + + dir, err = filepath.Abs(dir) + if err != nil { + return "", err + } + + return dir, nil +} diff --git a/src/internal/docker/cli.go b/src/internal/docker/cli.go index b91ab07..b285f37 100644 --- a/src/internal/docker/cli.go +++ b/src/internal/docker/cli.go @@ -9,11 +9,10 @@ import ( "regexp" "strings" - "github.com/mitchellh/go-homedir" yey "github.com/silphid/yey/src/internal" ) -func Start(ctx context.Context, yeyCtx yey.Context, containerName string) error { +func Start(ctx context.Context, yeyCtx yey.Context, containerName, workDir string) error { // Determine whether we need to run or exec container status, err := getContainerStatus(ctx, containerName) if err != nil { @@ -22,11 +21,11 @@ func Start(ctx context.Context, yeyCtx yey.Context, containerName string) error switch status { case "": - return runContainer(ctx, yeyCtx, containerName) + return runContainer(ctx, yeyCtx, containerName, workDir) case "exited": return startContainer(ctx, containerName) case "running": - return execContainer(ctx, containerName, yeyCtx.Cmd) + return execContainer(ctx, containerName, workDir, yeyCtx.Cmd) default: return fmt.Errorf("container %q in unexpected state %q", containerName, status) } @@ -71,7 +70,7 @@ func getContainerStatus(ctx context.Context, name string) (string, error) { return strings.TrimSpace(string(output)), nil } -func runContainer(ctx context.Context, yeyCtx yey.Context, containerName string) error { +func runContainer(ctx context.Context, yeyCtx yey.Context, containerName, workDir string) error { cwd, err := os.Getwd() if err != nil { return err @@ -94,16 +93,16 @@ func runContainer(ctx context.Context, yeyCtx yey.Context, containerName string) args = append(args, "--env", fmt.Sprintf("%s=%s", name, value)) } - home, err := homedir.Dir() + // Mount binds + mounts, err := yeyCtx.ResolveMounts() if err != nil { - return fmt.Errorf("failed to detect user home directory: %w", err) + return err } - - for key, value := range yeyCtx.Mounts { + for key, value := range mounts { args = append( args, "--volume", - fmt.Sprintf("%s:%s", strings.ReplaceAll(key, "$HOME", home), value), + fmt.Sprintf("%s:%s", key, value), ) } @@ -111,6 +110,10 @@ func runContainer(ctx context.Context, yeyCtx yey.Context, containerName string) args = append(args, "--rm") } + if workDir != "" { + args = append(args, "--workdir", workDir) + } + args = append(args, yeyCtx.Image) args = append(args, yeyCtx.Cmd...) @@ -121,8 +124,13 @@ func startContainer(ctx context.Context, containerName string) error { return attachStdPipes(exec.CommandContext(ctx, "docker", "start", "-i", containerName)).Run() } -func execContainer(ctx context.Context, containerName string, cmd []string) error { - args := append([]string{"exec", "-ti", containerName}, cmd...) +func execContainer(ctx context.Context, containerName, workDir string, cmd []string) error { + args := []string{"exec", "-ti"} + if workDir != "" { + args = append(args, "--workdir", workDir) + } + args = append(args, containerName) + args = append(args, cmd...) return attachStdPipes(exec.CommandContext(ctx, "docker", args...)).Run() } From 1fd116a8efc7f1d1d35c10339ec12fa561932218 Mon Sep 17 00:00:00 2001 From: Mathieu Frenette Date: Sat, 29 May 2021 19:21:04 -0400 Subject: [PATCH 2/4] Combine home dir resolving into path resolving. Use filepath.Rel() instead of raw prefix checking. --- dev/build | 2 +- src/cmd/run/run.go | 15 ++++----- src/internal/context.go | 34 --------------------- src/internal/contextFile.go | 61 +++++++++++++++++++++++++++++-------- src/internal/docker/cli.go | 6 +--- 5 files changed, 59 insertions(+), 59 deletions(-) diff --git a/dev/build b/dev/build index 938e03f..ce29e1c 100755 --- a/dev/build +++ b/dev/build @@ -1,2 +1,2 @@ #!/bin/bash -go build -ldflags "-X main.version=dev-$(date +%F-%T)" -o /usr/local/bin/yeydev ./src \ No newline at end of file +go build -ldflags "-X main.version=dev-$(date +%F-%T)" -o /usr/local/bin/yey ./src \ No newline at end of file diff --git a/src/cmd/run/run.go b/src/cmd/run/run.go index 9541d1d..255e37c 100644 --- a/src/cmd/run/run.go +++ b/src/cmd/run/run.go @@ -100,14 +100,15 @@ func getContainerWorkDir(yeyContext yey.Context) (string, error) { return "", err } - mounts, err := yeyContext.ResolveMounts() - if err != nil { - return "", err - } + for key, value := range yeyContext.Mounts { + // Where is work dir relatively to mount dir? + subDir, err := filepath.Rel(key, workDir) + if err != nil { + return "", err + } - for key, value := range mounts { - if strings.HasPrefix(workDir, key) { - subDir := strings.TrimPrefix(workDir, key) + // Is work dir within mount dir? + if !strings.HasPrefix(subDir, fmt.Sprintf("..%c", filepath.Separator)) { return filepath.Join(value, subDir), nil } } diff --git a/src/internal/context.go b/src/internal/context.go index 7fce7c9..c8bc401 100644 --- a/src/internal/context.go +++ b/src/internal/context.go @@ -1,9 +1,6 @@ package yey import ( - "path/filepath" - - "github.com/mitchellh/go-homedir" "gopkg.in/yaml.v2" ) @@ -83,34 +80,3 @@ func (c Context) String() string { } return string(buf) } - -func (c Context) ResolveMounts() (map[string]string, error) { - mounts := make(map[string]string, len(c.Mounts)) - for key, value := range c.Mounts { - dir, err := resolveLocalDir(key) - if err != nil { - return nil, err - } - mounts[dir] = value - } - return mounts, nil -} - -func resolveLocalDir(dir string) (string, error) { - var err error - if dir == "~" { - dir, err = homedir.Dir() - } else { - dir, err = homedir.Expand(dir) - } - if err != nil { - return "", err - } - - dir, err = filepath.Abs(dir) - if err != nil { - return "", err - } - - return dir, nil -} diff --git a/src/internal/contextFile.go b/src/internal/contextFile.go index a400492..084e090 100644 --- a/src/internal/contextFile.go +++ b/src/internal/contextFile.go @@ -90,9 +90,16 @@ func parseContextFile(dir string, data []byte) (Contexts, error) { } if dir != "" { - contexts.Context = resolveContextPaths(dir, contexts.Context) + var err error + contexts.Context, err = resolveContextPaths(dir, contexts.Context) + if err != nil { + return Contexts{}, err + } for name, context := range contexts.Named { - contexts.Named[name] = resolveContextPaths(dir, context) + contexts.Named[name], err = resolveContextPaths(dir, context) + if err != nil { + return Contexts{}, err + } } } @@ -145,24 +152,54 @@ func LoadContexts() (Contexts, error) { return contexts, nil } -func resolveContextPaths(dir string, context Context) Context { +func resolveContextPaths(dir string, context Context) (Context, error) { clone := context.Clone() - clone.Build.Dockerfile = resolvePath(dir, context.Build.Dockerfile) - clone.Build.Context = resolvePath(dir, clone.Build.Context) - for key, value := range clone.Mounts { - clone.Mounts[resolvePath(dir, key)] = value + + // Resolve dockerfile path + var err error + clone.Build.Dockerfile, err = resolvePath(dir, context.Build.Dockerfile) + if err != nil { + return Context{}, err + } + + // Resolve build context dir + clone.Build.Context, err = resolvePath(dir, clone.Build.Context) + if err != nil { + return Context{}, err + } + + // Resolve mount dirs + clone.Mounts = make(map[string]string, len(context.Mounts)) + for key, value := range context.Mounts { + key, err = resolvePath(dir, key) + if err != nil { + return Context{}, err + } + clone.Mounts[key] = value } - return clone + + return clone, nil } -func resolvePath(dir, path string) string { +func resolvePath(dir, path string) (string, error) { if path == "" { - return "" + return "", nil + } + + // Resolve home dir + var err error + if path == "~" { + path, err = homedir.Dir() + } else { + path, err = homedir.Expand(path) + } + if err != nil { + return "", err } if filepath.IsAbs(path) { - return path + return path, nil } - return filepath.Join(dir, path) + return filepath.Join(dir, path), nil } diff --git a/src/internal/docker/cli.go b/src/internal/docker/cli.go index 34055c0..093e0e3 100644 --- a/src/internal/docker/cli.go +++ b/src/internal/docker/cli.go @@ -129,11 +129,7 @@ func runContainer(ctx context.Context, yeyCtx yey.Context, containerName, workDi } // Mount binds - mounts, err := yeyCtx.ResolveMounts() - if err != nil { - return err - } - for key, value := range mounts { + for key, value := range yeyCtx.Mounts { args = append( args, "--volume", From 3a4a83fc91e7fa39c0a5c3e32b15cbf83f28844d Mon Sep 17 00:00:00 2001 From: davidmdm Date: Sun, 30 May 2021 01:00:59 -0400 Subject: [PATCH 3/4] workdir suggestions --- src/cmd/run/run.go | 7 ++++++- src/internal/contextFile.go | 23 ++++++++++++++++------- src/internal/docker/cli.go | 35 ++++++++++++++++++++++++++--------- 3 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/cmd/run/run.go b/src/cmd/run/run.go index 255e37c..0c99536 100644 --- a/src/cmd/run/run.go +++ b/src/cmd/run/run.go @@ -91,7 +91,12 @@ func run(ctx context.Context, name string, options Options) error { return err } - return docker.Start(ctx, yeyContext, containerName, workDir) + var runOptions []docker.RunOption + if workDir != "" { + runOptions = append(runOptions, docker.WithWorkdir(workDir)) + } + + return docker.Start(ctx, yeyContext, containerName, runOptions...) } func getContainerWorkDir(yeyContext yey.Context) (string, error) { diff --git a/src/internal/contextFile.go b/src/internal/contextFile.go index 084e090..103fe46 100644 --- a/src/internal/contextFile.go +++ b/src/internal/contextFile.go @@ -91,16 +91,10 @@ func parseContextFile(dir string, data []byte) (Contexts, error) { if dir != "" { var err error - contexts.Context, err = resolveContextPaths(dir, contexts.Context) + contexts, err = resolveContextsPaths(dir, contexts) if err != nil { return Contexts{}, err } - for name, context := range contexts.Named { - contexts.Named[name], err = resolveContextPaths(dir, context) - if err != nil { - return Contexts{}, err - } - } } if ctxFile.Parent != "" { @@ -152,6 +146,21 @@ func LoadContexts() (Contexts, error) { return contexts, nil } +func resolveContextsPaths(dir string, contexts Contexts) (Contexts, error) { + var err error + contexts.Context, err = resolveContextPaths(dir, contexts.Context) + if err != nil { + return Contexts{}, err + } + for name, context := range contexts.Named { + contexts.Named[name], err = resolveContextPaths(dir, context) + if err != nil { + return Contexts{}, err + } + } + return contexts, nil +} + func resolveContextPaths(dir string, context Context) (Context, error) { clone := context.Clone() diff --git a/src/internal/docker/cli.go b/src/internal/docker/cli.go index 093e0e3..0471913 100644 --- a/src/internal/docker/cli.go +++ b/src/internal/docker/cli.go @@ -14,7 +14,24 @@ import ( "github.com/silphid/yey/src/internal/logging" ) -func Start(ctx context.Context, yeyCtx yey.Context, containerName, workDir string) error { +type runOptions struct { + workdir string +} + +type RunOption func(*runOptions) + +func WithWorkdir(wd string) RunOption { + return func(ro *runOptions) { + ro.workdir = wd + } +} + +func Start(ctx context.Context, yeyCtx yey.Context, containerName string, opts ...RunOption) error { + var options runOptions + for _, opt := range opts { + opt(&options) + } + // Determine whether we need to run or exec container status, err := getContainerStatus(ctx, containerName) if err != nil { @@ -23,11 +40,11 @@ func Start(ctx context.Context, yeyCtx yey.Context, containerName, workDir strin switch status { case "": - return runContainer(ctx, yeyCtx, containerName, workDir) + return runContainer(ctx, yeyCtx, containerName, options) case "exited": return startContainer(ctx, containerName) case "running": - return execContainer(ctx, containerName, workDir, yeyCtx.Cmd) + return execContainer(ctx, containerName, yeyCtx.Cmd, options) default: return fmt.Errorf("container %q in unexpected state %q", containerName, status) } @@ -105,7 +122,7 @@ func getContainerStatus(ctx context.Context, name string) (string, error) { return strings.TrimSpace(string(output)), nil } -func runContainer(ctx context.Context, yeyCtx yey.Context, containerName, workDir string) error { +func runContainer(ctx context.Context, yeyCtx yey.Context, containerName string, options runOptions) error { cwd, err := os.Getwd() if err != nil { return err @@ -141,8 +158,8 @@ func runContainer(ctx context.Context, yeyCtx yey.Context, containerName, workDi args = append(args, "--rm") } - if workDir != "" { - args = append(args, "--workdir", workDir) + if options.workdir != "" { + args = append(args, "--workdir", options.workdir) } args = append(args, yeyCtx.Image) @@ -155,10 +172,10 @@ func startContainer(ctx context.Context, containerName string) error { return attachStdPipes(exec.CommandContext(ctx, "docker", "start", "-i", containerName)).Run() } -func execContainer(ctx context.Context, containerName, workDir string, cmd []string) error { +func execContainer(ctx context.Context, containerName string, cmd []string, options runOptions) error { args := []string{"exec", "-ti"} - if workDir != "" { - args = append(args, "--workdir", workDir) + if options.workdir != "" { + args = append(args, "--workdir", options.workdir) } args = append(args, containerName) args = append(args, cmd...) From d28d867b9e0e25fc2b80305e014fb0b6651d30a7 Mon Sep 17 00:00:00 2001 From: Mathieu Frenette Date: Tue, 1 Jun 2021 08:41:05 -0400 Subject: [PATCH 4/4] Change workDir capitalization --- src/cmd/run/run.go | 2 +- src/internal/docker/cli.go | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/cmd/run/run.go b/src/cmd/run/run.go index 0c99536..01435d9 100644 --- a/src/cmd/run/run.go +++ b/src/cmd/run/run.go @@ -93,7 +93,7 @@ func run(ctx context.Context, name string, options Options) error { var runOptions []docker.RunOption if workDir != "" { - runOptions = append(runOptions, docker.WithWorkdir(workDir)) + runOptions = append(runOptions, docker.WithWorkDir(workDir)) } return docker.Start(ctx, yeyContext, containerName, runOptions...) diff --git a/src/internal/docker/cli.go b/src/internal/docker/cli.go index 0471913..90190e3 100644 --- a/src/internal/docker/cli.go +++ b/src/internal/docker/cli.go @@ -15,14 +15,14 @@ import ( ) type runOptions struct { - workdir string + workDir string } type RunOption func(*runOptions) -func WithWorkdir(wd string) RunOption { +func WithWorkDir(wd string) RunOption { return func(ro *runOptions) { - ro.workdir = wd + ro.workDir = wd } } @@ -158,8 +158,8 @@ func runContainer(ctx context.Context, yeyCtx yey.Context, containerName string, args = append(args, "--rm") } - if options.workdir != "" { - args = append(args, "--workdir", options.workdir) + if options.workDir != "" { + args = append(args, "--workdir", options.workDir) } args = append(args, yeyCtx.Image) @@ -174,8 +174,8 @@ func startContainer(ctx context.Context, containerName string) error { func execContainer(ctx context.Context, containerName string, cmd []string, options runOptions) error { args := []string{"exec", "-ti"} - if options.workdir != "" { - args = append(args, "--workdir", options.workdir) + if options.workDir != "" { + args = append(args, "--workdir", options.workDir) } args = append(args, containerName) args = append(args, cmd...)