mirror of https://github.com/docker/docs.git
Move volume.SplitN() to the one place it is used in runconfig.
Signed-off-by: Daniel Nephin <dnephin@docker.com>
This commit is contained in:
parent
2b7ad47bd2
commit
c5a2fdb697
|
@ -12,7 +12,6 @@ import (
|
||||||
flag "github.com/docker/docker/pkg/mflag"
|
flag "github.com/docker/docker/pkg/mflag"
|
||||||
"github.com/docker/docker/pkg/mount"
|
"github.com/docker/docker/pkg/mount"
|
||||||
"github.com/docker/docker/pkg/signal"
|
"github.com/docker/docker/pkg/signal"
|
||||||
"github.com/docker/docker/volume"
|
|
||||||
"github.com/docker/go-connections/nat"
|
"github.com/docker/go-connections/nat"
|
||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
)
|
)
|
||||||
|
@ -199,7 +198,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*container.Config, *container.Host
|
||||||
var binds []string
|
var binds []string
|
||||||
// add any bind targets to the list of container volumes
|
// add any bind targets to the list of container volumes
|
||||||
for bind := range flVolumes.GetMap() {
|
for bind := range flVolumes.GetMap() {
|
||||||
if arr := volume.SplitN(bind, 2); len(arr) > 1 {
|
if arr := volumeSplitN(bind, 2); len(arr) > 1 {
|
||||||
// after creating the bind mount we want to delete it from the flVolumes values because
|
// after creating the bind mount we want to delete it from the flVolumes values because
|
||||||
// we do not want bind mounts being committed to image configs
|
// we do not want bind mounts being committed to image configs
|
||||||
binds = append(binds, bind)
|
binds = append(binds, bind)
|
||||||
|
@ -621,3 +620,59 @@ func validatePath(val string, validator func(string) bool) (string, error) {
|
||||||
}
|
}
|
||||||
return val, nil
|
return val, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SplitN splits raw into a maximum of n parts, separated by a separator colon.
|
||||||
|
// A separator colon is the last `:` character in the regex `[/:\\]?[a-zA-Z]:` (note `\\` is `\` escaped).
|
||||||
|
// This allows to correctly split strings such as `C:\foo:D:\:rw`.
|
||||||
|
func volumeSplitN(raw string, n int) []string {
|
||||||
|
var array []string
|
||||||
|
if len(raw) == 0 || raw[0] == ':' {
|
||||||
|
// invalid
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// numberOfParts counts the number of parts separated by a separator colon
|
||||||
|
numberOfParts := 0
|
||||||
|
// left represents the left-most cursor in raw, updated at every `:` character considered as a separator.
|
||||||
|
left := 0
|
||||||
|
// right represents the right-most cursor in raw incremented with the loop. Note this
|
||||||
|
// starts at index 1 as index 0 is already handle above as a special case.
|
||||||
|
for right := 1; right < len(raw); right++ {
|
||||||
|
// stop parsing if reached maximum number of parts
|
||||||
|
if n >= 0 && numberOfParts >= n {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if raw[right] != ':' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
potentialDriveLetter := raw[right-1]
|
||||||
|
if (potentialDriveLetter >= 'A' && potentialDriveLetter <= 'Z') || (potentialDriveLetter >= 'a' && potentialDriveLetter <= 'z') {
|
||||||
|
if right > 1 {
|
||||||
|
beforePotentialDriveLetter := raw[right-2]
|
||||||
|
if beforePotentialDriveLetter != ':' && beforePotentialDriveLetter != '/' && beforePotentialDriveLetter != '\\' {
|
||||||
|
// e.g. `C:` is not preceded by any delimiter, therefore it was not a drive letter but a path ending with `C:`.
|
||||||
|
array = append(array, raw[left:right])
|
||||||
|
left = right + 1
|
||||||
|
numberOfParts++
|
||||||
|
}
|
||||||
|
// else, `C:` is considered as a drive letter and not as a delimiter, so we continue parsing.
|
||||||
|
}
|
||||||
|
// if right == 1, then `C:` is the beginning of the raw string, therefore `:` is again not considered a delimiter and we continue parsing.
|
||||||
|
} else {
|
||||||
|
// if `:` is not preceded by a potential drive letter, then consider it as a delimiter.
|
||||||
|
array = append(array, raw[left:right])
|
||||||
|
left = right + 1
|
||||||
|
numberOfParts++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// need to take care of the last part
|
||||||
|
if left < len(raw) {
|
||||||
|
if n >= 0 && numberOfParts >= n {
|
||||||
|
// if the maximum number of parts is reached, just append the rest to the last part
|
||||||
|
// left-1 is at the last `:` that needs to be included since not considered a separator.
|
||||||
|
array[n-1] += raw[left-1:]
|
||||||
|
} else {
|
||||||
|
array = append(array, raw[left:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return array
|
||||||
|
}
|
||||||
|
|
|
@ -763,3 +763,52 @@ func TestValidateDevice(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVolumeSplitN(t *testing.T) {
|
||||||
|
for _, x := range []struct {
|
||||||
|
input string
|
||||||
|
n int
|
||||||
|
expected []string
|
||||||
|
}{
|
||||||
|
{`C:\foo:d:`, -1, []string{`C:\foo`, `d:`}},
|
||||||
|
{`:C:\foo:d:`, -1, nil},
|
||||||
|
{`/foo:/bar:ro`, 3, []string{`/foo`, `/bar`, `ro`}},
|
||||||
|
{`/foo:/bar:ro`, 2, []string{`/foo`, `/bar:ro`}},
|
||||||
|
{`C:\foo\:/foo`, -1, []string{`C:\foo\`, `/foo`}},
|
||||||
|
|
||||||
|
{`d:\`, -1, []string{`d:\`}},
|
||||||
|
{`d:`, -1, []string{`d:`}},
|
||||||
|
{`d:\path`, -1, []string{`d:\path`}},
|
||||||
|
{`d:\path with space`, -1, []string{`d:\path with space`}},
|
||||||
|
{`d:\pathandmode:rw`, -1, []string{`d:\pathandmode`, `rw`}},
|
||||||
|
{`c:\:d:\`, -1, []string{`c:\`, `d:\`}},
|
||||||
|
{`c:\windows\:d:`, -1, []string{`c:\windows\`, `d:`}},
|
||||||
|
{`c:\windows:d:\s p a c e`, -1, []string{`c:\windows`, `d:\s p a c e`}},
|
||||||
|
{`c:\windows:d:\s p a c e:RW`, -1, []string{`c:\windows`, `d:\s p a c e`, `RW`}},
|
||||||
|
{`c:\program files:d:\s p a c e i n h o s t d i r`, -1, []string{`c:\program files`, `d:\s p a c e i n h o s t d i r`}},
|
||||||
|
{`0123456789name:d:`, -1, []string{`0123456789name`, `d:`}},
|
||||||
|
{`MiXeDcAsEnAmE:d:`, -1, []string{`MiXeDcAsEnAmE`, `d:`}},
|
||||||
|
{`name:D:`, -1, []string{`name`, `D:`}},
|
||||||
|
{`name:D::rW`, -1, []string{`name`, `D:`, `rW`}},
|
||||||
|
{`name:D::RW`, -1, []string{`name`, `D:`, `RW`}},
|
||||||
|
{`c:/:d:/forward/slashes/are/good/too`, -1, []string{`c:/`, `d:/forward/slashes/are/good/too`}},
|
||||||
|
{`c:\Windows`, -1, []string{`c:\Windows`}},
|
||||||
|
{`c:\Program Files (x86)`, -1, []string{`c:\Program Files (x86)`}},
|
||||||
|
|
||||||
|
{``, -1, nil},
|
||||||
|
{`.`, -1, []string{`.`}},
|
||||||
|
{`..\`, -1, []string{`..\`}},
|
||||||
|
{`c:\:..\`, -1, []string{`c:\`, `..\`}},
|
||||||
|
{`c:\:d:\:xyzzy`, -1, []string{`c:\`, `d:\`, `xyzzy`}},
|
||||||
|
} {
|
||||||
|
res := volumeSplitN(x.input, x.n)
|
||||||
|
if len(res) < len(x.expected) {
|
||||||
|
t.Fatalf("input: %v, expected: %v, got: %v", x.input, x.expected, res)
|
||||||
|
}
|
||||||
|
for i, e := range res {
|
||||||
|
if e != x.expected[i] {
|
||||||
|
t.Fatalf("input: %v, expected: %v, got: %v", x.input, x.expected, res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -113,59 +113,3 @@ func ParseVolumesFrom(spec string) (string, string, error) {
|
||||||
}
|
}
|
||||||
return id, mode, nil
|
return id, mode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SplitN splits raw into a maximum of n parts, separated by a separator colon.
|
|
||||||
// A separator colon is the last `:` character in the regex `[/:\\]?[a-zA-Z]:` (note `\\` is `\` escaped).
|
|
||||||
// This allows to correctly split strings such as `C:\foo:D:\:rw`.
|
|
||||||
func SplitN(raw string, n int) []string {
|
|
||||||
var array []string
|
|
||||||
if len(raw) == 0 || raw[0] == ':' {
|
|
||||||
// invalid
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// numberOfParts counts the number of parts separated by a separator colon
|
|
||||||
numberOfParts := 0
|
|
||||||
// left represents the left-most cursor in raw, updated at every `:` character considered as a separator.
|
|
||||||
left := 0
|
|
||||||
// right represents the right-most cursor in raw incremented with the loop. Note this
|
|
||||||
// starts at index 1 as index 0 is already handle above as a special case.
|
|
||||||
for right := 1; right < len(raw); right++ {
|
|
||||||
// stop parsing if reached maximum number of parts
|
|
||||||
if n >= 0 && numberOfParts >= n {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if raw[right] != ':' {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
potentialDriveLetter := raw[right-1]
|
|
||||||
if (potentialDriveLetter >= 'A' && potentialDriveLetter <= 'Z') || (potentialDriveLetter >= 'a' && potentialDriveLetter <= 'z') {
|
|
||||||
if right > 1 {
|
|
||||||
beforePotentialDriveLetter := raw[right-2]
|
|
||||||
if beforePotentialDriveLetter != ':' && beforePotentialDriveLetter != '/' && beforePotentialDriveLetter != '\\' {
|
|
||||||
// e.g. `C:` is not preceded by any delimiter, therefore it was not a drive letter but a path ending with `C:`.
|
|
||||||
array = append(array, raw[left:right])
|
|
||||||
left = right + 1
|
|
||||||
numberOfParts++
|
|
||||||
}
|
|
||||||
// else, `C:` is considered as a drive letter and not as a delimiter, so we continue parsing.
|
|
||||||
}
|
|
||||||
// if right == 1, then `C:` is the beginning of the raw string, therefore `:` is again not considered a delimiter and we continue parsing.
|
|
||||||
} else {
|
|
||||||
// if `:` is not preceded by a potential drive letter, then consider it as a delimiter.
|
|
||||||
array = append(array, raw[left:right])
|
|
||||||
left = right + 1
|
|
||||||
numberOfParts++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// need to take care of the last part
|
|
||||||
if left < len(raw) {
|
|
||||||
if n >= 0 && numberOfParts >= n {
|
|
||||||
// if the maximum number of parts is reached, just append the rest to the last part
|
|
||||||
// left-1 is at the last `:` that needs to be included since not considered a separator.
|
|
||||||
array[n-1] += raw[left-1:]
|
|
||||||
} else {
|
|
||||||
array = append(array, raw[left:])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return array
|
|
||||||
}
|
|
||||||
|
|
|
@ -133,55 +133,6 @@ func TestParseMountSpec(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSplitN(t *testing.T) {
|
|
||||||
for _, x := range []struct {
|
|
||||||
input string
|
|
||||||
n int
|
|
||||||
expected []string
|
|
||||||
}{
|
|
||||||
{`C:\foo:d:`, -1, []string{`C:\foo`, `d:`}},
|
|
||||||
{`:C:\foo:d:`, -1, nil},
|
|
||||||
{`/foo:/bar:ro`, 3, []string{`/foo`, `/bar`, `ro`}},
|
|
||||||
{`/foo:/bar:ro`, 2, []string{`/foo`, `/bar:ro`}},
|
|
||||||
{`C:\foo\:/foo`, -1, []string{`C:\foo\`, `/foo`}},
|
|
||||||
|
|
||||||
{`d:\`, -1, []string{`d:\`}},
|
|
||||||
{`d:`, -1, []string{`d:`}},
|
|
||||||
{`d:\path`, -1, []string{`d:\path`}},
|
|
||||||
{`d:\path with space`, -1, []string{`d:\path with space`}},
|
|
||||||
{`d:\pathandmode:rw`, -1, []string{`d:\pathandmode`, `rw`}},
|
|
||||||
{`c:\:d:\`, -1, []string{`c:\`, `d:\`}},
|
|
||||||
{`c:\windows\:d:`, -1, []string{`c:\windows\`, `d:`}},
|
|
||||||
{`c:\windows:d:\s p a c e`, -1, []string{`c:\windows`, `d:\s p a c e`}},
|
|
||||||
{`c:\windows:d:\s p a c e:RW`, -1, []string{`c:\windows`, `d:\s p a c e`, `RW`}},
|
|
||||||
{`c:\program files:d:\s p a c e i n h o s t d i r`, -1, []string{`c:\program files`, `d:\s p a c e i n h o s t d i r`}},
|
|
||||||
{`0123456789name:d:`, -1, []string{`0123456789name`, `d:`}},
|
|
||||||
{`MiXeDcAsEnAmE:d:`, -1, []string{`MiXeDcAsEnAmE`, `d:`}},
|
|
||||||
{`name:D:`, -1, []string{`name`, `D:`}},
|
|
||||||
{`name:D::rW`, -1, []string{`name`, `D:`, `rW`}},
|
|
||||||
{`name:D::RW`, -1, []string{`name`, `D:`, `RW`}},
|
|
||||||
{`c:/:d:/forward/slashes/are/good/too`, -1, []string{`c:/`, `d:/forward/slashes/are/good/too`}},
|
|
||||||
{`c:\Windows`, -1, []string{`c:\Windows`}},
|
|
||||||
{`c:\Program Files (x86)`, -1, []string{`c:\Program Files (x86)`}},
|
|
||||||
|
|
||||||
{``, -1, nil},
|
|
||||||
{`.`, -1, []string{`.`}},
|
|
||||||
{`..\`, -1, []string{`..\`}},
|
|
||||||
{`c:\:..\`, -1, []string{`c:\`, `..\`}},
|
|
||||||
{`c:\:d:\:xyzzy`, -1, []string{`c:\`, `d:\`, `xyzzy`}},
|
|
||||||
} {
|
|
||||||
res := SplitN(x.input, x.n)
|
|
||||||
if len(res) < len(x.expected) {
|
|
||||||
t.Fatalf("input: %v, expected: %v, got: %v", x.input, x.expected, res)
|
|
||||||
}
|
|
||||||
for i, e := range res {
|
|
||||||
if e != x.expected[i] {
|
|
||||||
t.Fatalf("input: %v, expected: %v, got: %v", x.input, x.expected, res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// testParseMountSpec is a structure used by TestParseMountSpecSplit for
|
// testParseMountSpec is a structure used by TestParseMountSpecSplit for
|
||||||
// specifying test cases for the ParseMountSpec() function.
|
// specifying test cases for the ParseMountSpec() function.
|
||||||
type testParseMountSpec struct {
|
type testParseMountSpec struct {
|
||||||
|
|
Loading…
Reference in New Issue