Browse code

Move volume.SplitN() to the one place it is used in runconfig.

Signed-off-by: Daniel Nephin <dnephin@docker.com>

Daniel Nephin authored on 2015/12/23 09:52:27
Showing 4 changed files
... ...
@@ -12,7 +12,6 @@ import (
12 12
 	flag "github.com/docker/docker/pkg/mflag"
13 13
 	"github.com/docker/docker/pkg/mount"
14 14
 	"github.com/docker/docker/pkg/signal"
15
-	"github.com/docker/docker/volume"
16 15
 	"github.com/docker/go-connections/nat"
17 16
 	"github.com/docker/go-units"
18 17
 )
... ...
@@ -199,7 +198,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*container.Config, *container.Host
199 199
 	var binds []string
200 200
 	// add any bind targets to the list of container volumes
201 201
 	for bind := range flVolumes.GetMap() {
202
-		if arr := volume.SplitN(bind, 2); len(arr) > 1 {
202
+		if arr := volumeSplitN(bind, 2); len(arr) > 1 {
203 203
 			// after creating the bind mount we want to delete it from the flVolumes values because
204 204
 			// we do not want bind mounts being committed to image configs
205 205
 			binds = append(binds, bind)
... ...
@@ -621,3 +620,59 @@ func validatePath(val string, validator func(string) bool) (string, error) {
621 621
 	}
622 622
 	return val, nil
623 623
 }
624
+
625
+// SplitN splits raw into a maximum of n parts, separated by a separator colon.
626
+// A separator colon is the last `:` character in the regex `[/:\\]?[a-zA-Z]:` (note `\\` is `\` escaped).
627
+// This allows to correctly split strings such as `C:\foo:D:\:rw`.
628
+func volumeSplitN(raw string, n int) []string {
629
+	var array []string
630
+	if len(raw) == 0 || raw[0] == ':' {
631
+		// invalid
632
+		return nil
633
+	}
634
+	// numberOfParts counts the number of parts separated by a separator colon
635
+	numberOfParts := 0
636
+	// left represents the left-most cursor in raw, updated at every `:` character considered as a separator.
637
+	left := 0
638
+	// right represents the right-most cursor in raw incremented with the loop. Note this
639
+	// starts at index 1 as index 0 is already handle above as a special case.
640
+	for right := 1; right < len(raw); right++ {
641
+		// stop parsing if reached maximum number of parts
642
+		if n >= 0 && numberOfParts >= n {
643
+			break
644
+		}
645
+		if raw[right] != ':' {
646
+			continue
647
+		}
648
+		potentialDriveLetter := raw[right-1]
649
+		if (potentialDriveLetter >= 'A' && potentialDriveLetter <= 'Z') || (potentialDriveLetter >= 'a' && potentialDriveLetter <= 'z') {
650
+			if right > 1 {
651
+				beforePotentialDriveLetter := raw[right-2]
652
+				if beforePotentialDriveLetter != ':' && beforePotentialDriveLetter != '/' && beforePotentialDriveLetter != '\\' {
653
+					// e.g. `C:` is not preceded by any delimiter, therefore it was not a drive letter but a path ending with `C:`.
654
+					array = append(array, raw[left:right])
655
+					left = right + 1
656
+					numberOfParts++
657
+				}
658
+				// else, `C:` is considered as a drive letter and not as a delimiter, so we continue parsing.
659
+			}
660
+			// if right == 1, then `C:` is the beginning of the raw string, therefore `:` is again not considered a delimiter and we continue parsing.
661
+		} else {
662
+			// if `:` is not preceded by a potential drive letter, then consider it as a delimiter.
663
+			array = append(array, raw[left:right])
664
+			left = right + 1
665
+			numberOfParts++
666
+		}
667
+	}
668
+	// need to take care of the last part
669
+	if left < len(raw) {
670
+		if n >= 0 && numberOfParts >= n {
671
+			// if the maximum number of parts is reached, just append the rest to the last part
672
+			// left-1 is at the last `:` that needs to be included since not considered a separator.
673
+			array[n-1] += raw[left-1:]
674
+		} else {
675
+			array = append(array, raw[left:])
676
+		}
677
+	}
678
+	return array
679
+}
... ...
@@ -763,3 +763,52 @@ func TestValidateDevice(t *testing.T) {
763 763
 		}
764 764
 	}
765 765
 }
766
+
767
+func TestVolumeSplitN(t *testing.T) {
768
+	for _, x := range []struct {
769
+		input    string
770
+		n        int
771
+		expected []string
772
+	}{
773
+		{`C:\foo:d:`, -1, []string{`C:\foo`, `d:`}},
774
+		{`:C:\foo:d:`, -1, nil},
775
+		{`/foo:/bar:ro`, 3, []string{`/foo`, `/bar`, `ro`}},
776
+		{`/foo:/bar:ro`, 2, []string{`/foo`, `/bar:ro`}},
777
+		{`C:\foo\:/foo`, -1, []string{`C:\foo\`, `/foo`}},
778
+
779
+		{`d:\`, -1, []string{`d:\`}},
780
+		{`d:`, -1, []string{`d:`}},
781
+		{`d:\path`, -1, []string{`d:\path`}},
782
+		{`d:\path with space`, -1, []string{`d:\path with space`}},
783
+		{`d:\pathandmode:rw`, -1, []string{`d:\pathandmode`, `rw`}},
784
+		{`c:\:d:\`, -1, []string{`c:\`, `d:\`}},
785
+		{`c:\windows\:d:`, -1, []string{`c:\windows\`, `d:`}},
786
+		{`c:\windows:d:\s p a c e`, -1, []string{`c:\windows`, `d:\s p a c e`}},
787
+		{`c:\windows:d:\s p a c e:RW`, -1, []string{`c:\windows`, `d:\s p a c e`, `RW`}},
788
+		{`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`}},
789
+		{`0123456789name:d:`, -1, []string{`0123456789name`, `d:`}},
790
+		{`MiXeDcAsEnAmE:d:`, -1, []string{`MiXeDcAsEnAmE`, `d:`}},
791
+		{`name:D:`, -1, []string{`name`, `D:`}},
792
+		{`name:D::rW`, -1, []string{`name`, `D:`, `rW`}},
793
+		{`name:D::RW`, -1, []string{`name`, `D:`, `RW`}},
794
+		{`c:/:d:/forward/slashes/are/good/too`, -1, []string{`c:/`, `d:/forward/slashes/are/good/too`}},
795
+		{`c:\Windows`, -1, []string{`c:\Windows`}},
796
+		{`c:\Program Files (x86)`, -1, []string{`c:\Program Files (x86)`}},
797
+
798
+		{``, -1, nil},
799
+		{`.`, -1, []string{`.`}},
800
+		{`..\`, -1, []string{`..\`}},
801
+		{`c:\:..\`, -1, []string{`c:\`, `..\`}},
802
+		{`c:\:d:\:xyzzy`, -1, []string{`c:\`, `d:\`, `xyzzy`}},
803
+	} {
804
+		res := volumeSplitN(x.input, x.n)
805
+		if len(res) < len(x.expected) {
806
+			t.Fatalf("input: %v, expected: %v, got: %v", x.input, x.expected, res)
807
+		}
808
+		for i, e := range res {
809
+			if e != x.expected[i] {
810
+				t.Fatalf("input: %v, expected: %v, got: %v", x.input, x.expected, res)
811
+			}
812
+		}
813
+	}
814
+}
... ...
@@ -113,59 +113,3 @@ func ParseVolumesFrom(spec string) (string, string, error) {
113 113
 	}
114 114
 	return id, mode, nil
115 115
 }
116
-
117
-// SplitN splits raw into a maximum of n parts, separated by a separator colon.
118
-// A separator colon is the last `:` character in the regex `[/:\\]?[a-zA-Z]:` (note `\\` is `\` escaped).
119
-// This allows to correctly split strings such as `C:\foo:D:\:rw`.
120
-func SplitN(raw string, n int) []string {
121
-	var array []string
122
-	if len(raw) == 0 || raw[0] == ':' {
123
-		// invalid
124
-		return nil
125
-	}
126
-	// numberOfParts counts the number of parts separated by a separator colon
127
-	numberOfParts := 0
128
-	// left represents the left-most cursor in raw, updated at every `:` character considered as a separator.
129
-	left := 0
130
-	// right represents the right-most cursor in raw incremented with the loop. Note this
131
-	// starts at index 1 as index 0 is already handle above as a special case.
132
-	for right := 1; right < len(raw); right++ {
133
-		// stop parsing if reached maximum number of parts
134
-		if n >= 0 && numberOfParts >= n {
135
-			break
136
-		}
137
-		if raw[right] != ':' {
138
-			continue
139
-		}
140
-		potentialDriveLetter := raw[right-1]
141
-		if (potentialDriveLetter >= 'A' && potentialDriveLetter <= 'Z') || (potentialDriveLetter >= 'a' && potentialDriveLetter <= 'z') {
142
-			if right > 1 {
143
-				beforePotentialDriveLetter := raw[right-2]
144
-				if beforePotentialDriveLetter != ':' && beforePotentialDriveLetter != '/' && beforePotentialDriveLetter != '\\' {
145
-					// e.g. `C:` is not preceded by any delimiter, therefore it was not a drive letter but a path ending with `C:`.
146
-					array = append(array, raw[left:right])
147
-					left = right + 1
148
-					numberOfParts++
149
-				}
150
-				// else, `C:` is considered as a drive letter and not as a delimiter, so we continue parsing.
151
-			}
152
-			// if right == 1, then `C:` is the beginning of the raw string, therefore `:` is again not considered a delimiter and we continue parsing.
153
-		} else {
154
-			// if `:` is not preceded by a potential drive letter, then consider it as a delimiter.
155
-			array = append(array, raw[left:right])
156
-			left = right + 1
157
-			numberOfParts++
158
-		}
159
-	}
160
-	// need to take care of the last part
161
-	if left < len(raw) {
162
-		if n >= 0 && numberOfParts >= n {
163
-			// if the maximum number of parts is reached, just append the rest to the last part
164
-			// left-1 is at the last `:` that needs to be included since not considered a separator.
165
-			array[n-1] += raw[left-1:]
166
-		} else {
167
-			array = append(array, raw[left:])
168
-		}
169
-	}
170
-	return array
171
-}
... ...
@@ -133,55 +133,6 @@ func TestParseMountSpec(t *testing.T) {
133 133
 	}
134 134
 }
135 135
 
136
-func TestSplitN(t *testing.T) {
137
-	for _, x := range []struct {
138
-		input    string
139
-		n        int
140
-		expected []string
141
-	}{
142
-		{`C:\foo:d:`, -1, []string{`C:\foo`, `d:`}},
143
-		{`:C:\foo:d:`, -1, nil},
144
-		{`/foo:/bar:ro`, 3, []string{`/foo`, `/bar`, `ro`}},
145
-		{`/foo:/bar:ro`, 2, []string{`/foo`, `/bar:ro`}},
146
-		{`C:\foo\:/foo`, -1, []string{`C:\foo\`, `/foo`}},
147
-
148
-		{`d:\`, -1, []string{`d:\`}},
149
-		{`d:`, -1, []string{`d:`}},
150
-		{`d:\path`, -1, []string{`d:\path`}},
151
-		{`d:\path with space`, -1, []string{`d:\path with space`}},
152
-		{`d:\pathandmode:rw`, -1, []string{`d:\pathandmode`, `rw`}},
153
-		{`c:\:d:\`, -1, []string{`c:\`, `d:\`}},
154
-		{`c:\windows\:d:`, -1, []string{`c:\windows\`, `d:`}},
155
-		{`c:\windows:d:\s p a c e`, -1, []string{`c:\windows`, `d:\s p a c e`}},
156
-		{`c:\windows:d:\s p a c e:RW`, -1, []string{`c:\windows`, `d:\s p a c e`, `RW`}},
157
-		{`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`}},
158
-		{`0123456789name:d:`, -1, []string{`0123456789name`, `d:`}},
159
-		{`MiXeDcAsEnAmE:d:`, -1, []string{`MiXeDcAsEnAmE`, `d:`}},
160
-		{`name:D:`, -1, []string{`name`, `D:`}},
161
-		{`name:D::rW`, -1, []string{`name`, `D:`, `rW`}},
162
-		{`name:D::RW`, -1, []string{`name`, `D:`, `RW`}},
163
-		{`c:/:d:/forward/slashes/are/good/too`, -1, []string{`c:/`, `d:/forward/slashes/are/good/too`}},
164
-		{`c:\Windows`, -1, []string{`c:\Windows`}},
165
-		{`c:\Program Files (x86)`, -1, []string{`c:\Program Files (x86)`}},
166
-
167
-		{``, -1, nil},
168
-		{`.`, -1, []string{`.`}},
169
-		{`..\`, -1, []string{`..\`}},
170
-		{`c:\:..\`, -1, []string{`c:\`, `..\`}},
171
-		{`c:\:d:\:xyzzy`, -1, []string{`c:\`, `d:\`, `xyzzy`}},
172
-	} {
173
-		res := SplitN(x.input, x.n)
174
-		if len(res) < len(x.expected) {
175
-			t.Fatalf("input: %v, expected: %v, got: %v", x.input, x.expected, res)
176
-		}
177
-		for i, e := range res {
178
-			if e != x.expected[i] {
179
-				t.Fatalf("input: %v, expected: %v, got: %v", x.input, x.expected, res)
180
-			}
181
-		}
182
-	}
183
-}
184
-
185 136
 // testParseMountSpec is a structure used by TestParseMountSpecSplit for
186 137
 // specifying test cases for the ParseMountSpec() function.
187 138
 type testParseMountSpec struct {