From ab35e3fac33410a4d241e6ee140646b5776f5d48 Mon Sep 17 00:00:00 2001 From: Djordje Lukic Date: Thu, 10 Mar 2022 16:40:49 +0100 Subject: [PATCH] Handle relative source mounts With this change it is now possible to give a relative path to the --volume and --mount flags. $ docker run --mount type=bind,source=./,target=/test ... $ docker run -v .:/test ... Fixes #1203 Signed-off-by: Djordje Lukic --- cli/command/container/opts.go | 19 ++++++++++++++++++- opts/mount.go | 6 ++++++ opts/mount_test.go | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/cli/command/container/opts.go b/cli/command/container/opts.go index eacdf11deb..c449955717 100644 --- a/cli/command/container/opts.go +++ b/cli/command/container/opts.go @@ -6,6 +6,7 @@ import ( "fmt" "os" "path" + "path/filepath" "reflect" "regexp" "strconv" @@ -15,6 +16,7 @@ import ( "github.com/docker/cli/cli/compose/loader" "github.com/docker/cli/opts" "github.com/docker/docker/api/types/container" + mounttypes "github.com/docker/docker/api/types/mount" networktypes "github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/strslice" "github.com/docker/docker/api/types/versions" @@ -348,10 +350,25 @@ func parse(flags *pflag.FlagSet, copts *containerOptions, serverOS string) (*con // add any bind targets to the list of container volumes for bind := range copts.volumes.GetMap() { parsed, _ := loader.ParseVolume(bind) + if parsed.Source != "" { + toBind := bind + + if parsed.Type == string(mounttypes.TypeBind) { + if arr := strings.SplitN(bind, ":", 2); len(arr) == 2 { + hostPart := arr[0] + if strings.HasPrefix(hostPart, "."+string(filepath.Separator)) || hostPart == "." { + if absHostPart, err := filepath.Abs(hostPart); err == nil { + hostPart = absHostPart + } + } + toBind = hostPart + ":" + arr[1] + } + } + // after creating the bind mount we want to delete it from the copts.volumes values because // we do not want bind mounts being committed to image configs - binds = append(binds, bind) + binds = append(binds, toBind) // We should delete from the map (`volumes`) here, as deleting from copts.volumes will not work if // there are duplicates entries. delete(volumes, bind) diff --git a/opts/mount.go b/opts/mount.go index ef661dd51b..fd010d66a4 100644 --- a/opts/mount.go +++ b/opts/mount.go @@ -4,6 +4,7 @@ import ( "encoding/csv" "fmt" "os" + "path/filepath" "strconv" "strings" @@ -92,6 +93,11 @@ func (m *MountOpt) Set(value string) error { mount.Type = mounttypes.Type(strings.ToLower(value)) case "source", "src": mount.Source = value + if strings.HasPrefix(value, "."+string(filepath.Separator)) || value == "." { + if abs, err := filepath.Abs(value); err == nil { + mount.Source = abs + } + } case "target", "dst", "destination": mount.Target = value case "readonly", "ro": diff --git a/opts/mount_test.go b/opts/mount_test.go index 1da6319070..fd771290a1 100644 --- a/opts/mount_test.go +++ b/opts/mount_test.go @@ -2,6 +2,7 @@ package opts import ( "os" + "path/filepath" "testing" mounttypes "github.com/docker/docker/api/types/mount" @@ -28,6 +29,40 @@ func TestMountOptString(t *testing.T) { assert.Check(t, is.Equal(expected, mount.String())) } +func TestMountRelative(t *testing.T) { + + for _, testcase := range []struct { + name string + path string + bind string + }{ + { + name: "Current path", + path: ".", + bind: "type=bind,source=.,target=/target", + }, { + name: "Current path with slash", + path: "./", + bind: "type=bind,source=./,target=/target", + }, + } { + t.Run(testcase.name, func(t *testing.T) { + var mount MountOpt + assert.NilError(t, mount.Set(testcase.bind)) + + mounts := mount.Value() + assert.Assert(t, is.Len(mounts, 1)) + abs, err := filepath.Abs(testcase.path) + assert.NilError(t, err) + assert.Check(t, is.DeepEqual(mounttypes.Mount{ + Type: mounttypes.TypeBind, + Source: abs, + Target: "/target", + }, mounts[0])) + }) + } +} + func TestMountOptSetBindNoErrorBind(t *testing.T) { for _, testcase := range []string{ // tests several aliases that should have same result.