Browse code

Refactor utils/utils, fixes #11923

Signed-off-by: Antonio Murdaca <me@runcom.ninja>

Antonio Murdaca authored on 2015/03/30 06:17:23
Showing 46 changed files
... ...
@@ -9,7 +9,6 @@ import (
9 9
 	"github.com/docker/docker/engine"
10 10
 	flag "github.com/docker/docker/pkg/mflag"
11 11
 	"github.com/docker/docker/pkg/signal"
12
-	"github.com/docker/docker/utils"
13 12
 )
14 13
 
15 14
 // CmdAttach attaches to a running container.
... ...
@@ -81,7 +80,7 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
81 81
 		return err
82 82
 	}
83 83
 	if status != 0 {
84
-		return &utils.StatusError{StatusCode: status}
84
+		return &StatusError{StatusCode: status}
85 85
 	}
86 86
 
87 87
 	return nil
... ...
@@ -302,7 +302,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
302 302
 		if jerr.Code == 0 {
303 303
 			jerr.Code = 1
304 304
 		}
305
-		return &utils.StatusError{Status: jerr.Message, StatusCode: jerr.Code}
305
+		return &StatusError{Status: jerr.Message, StatusCode: jerr.Code}
306 306
 	}
307 307
 	return err
308 308
 }
... ...
@@ -3,3 +3,15 @@
3 3
 // Run "docker help SUBCOMMAND" or "docker SUBCOMMAND --help" to see more information on any Docker subcommand, including the full list of options supported for the subcommand.
4 4
 // See https://docs.docker.com/installation/ for instructions on installing Docker.
5 5
 package client
6
+
7
+import "fmt"
8
+
9
+// An StatusError reports an unsuccessful exit by a command.
10
+type StatusError struct {
11
+	Status     string
12
+	StatusCode int
13
+}
14
+
15
+func (e *StatusError) Error() string {
16
+	return fmt.Sprintf("Status: %s, Code: %d", e.Status, e.StatusCode)
17
+}
... ...
@@ -9,7 +9,6 @@ import (
9 9
 	"github.com/docker/docker/api/types"
10 10
 	"github.com/docker/docker/pkg/promise"
11 11
 	"github.com/docker/docker/runconfig"
12
-	"github.com/docker/docker/utils"
13 12
 )
14 13
 
15 14
 // CmdExec runs a command in a running container.
... ...
@@ -21,7 +20,7 @@ func (cli *DockerCli) CmdExec(args ...string) error {
21 21
 	execConfig, err := runconfig.ParseExec(cmd, args)
22 22
 	// just in case the ParseExec does not exit
23 23
 	if execConfig.Container == "" || err != nil {
24
-		return &utils.StatusError{StatusCode: 1}
24
+		return &StatusError{StatusCode: 1}
25 25
 	}
26 26
 
27 27
 	stream, _, err := cli.call("POST", "/containers/"+execConfig.Container+"/exec", execConfig, nil)
... ...
@@ -122,7 +121,7 @@ func (cli *DockerCli) CmdExec(args ...string) error {
122 122
 	}
123 123
 
124 124
 	if status != 0 {
125
-		return &utils.StatusError{StatusCode: status}
125
+		return &StatusError{StatusCode: status}
126 126
 	}
127 127
 
128 128
 	return nil
... ...
@@ -9,8 +9,8 @@ import (
9 9
 	"github.com/docker/docker/api/types"
10 10
 	flag "github.com/docker/docker/pkg/mflag"
11 11
 	"github.com/docker/docker/pkg/stringid"
12
+	"github.com/docker/docker/pkg/stringutils"
12 13
 	"github.com/docker/docker/pkg/units"
13
-	"github.com/docker/docker/utils"
14 14
 )
15 15
 
16 16
 // CmdHistory shows the history of an image.
... ...
@@ -51,7 +51,7 @@ func (cli *DockerCli) CmdHistory(args ...string) error {
51 51
 			if *noTrunc {
52 52
 				fmt.Fprintf(w, "%s\t", entry.CreatedBy)
53 53
 			} else {
54
-				fmt.Fprintf(w, "%s\t", utils.Trunc(entry.CreatedBy, 45))
54
+				fmt.Fprintf(w, "%s\t", stringutils.Truncate(entry.CreatedBy, 45))
55 55
 			}
56 56
 			fmt.Fprintf(w, "%s\t", units.HumanSize(float64(entry.Size)))
57 57
 			fmt.Fprintf(w, "%s", entry.Comment)
... ...
@@ -9,7 +9,6 @@ import (
9 9
 	"text/template"
10 10
 
11 11
 	flag "github.com/docker/docker/pkg/mflag"
12
-	"github.com/docker/docker/utils"
13 12
 )
14 13
 
15 14
 // CmdInspect displays low-level information on one or more containers or images.
... ...
@@ -27,7 +26,7 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
27 27
 		var err error
28 28
 		if tmpl, err = template.New("").Funcs(funcMap).Parse(*tmplStr); err != nil {
29 29
 			fmt.Fprintf(cli.err, "Template parsing error: %v\n", err)
30
-			return &utils.StatusError{StatusCode: 64,
30
+			return &StatusError{StatusCode: 64,
31 31
 				Status: "Template parsing error: " + err.Error()}
32 32
 		}
33 33
 	}
... ...
@@ -86,7 +85,7 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
86 86
 	}
87 87
 
88 88
 	if status != 0 {
89
-		return &utils.StatusError{StatusCode: status}
89
+		return &StatusError{StatusCode: status}
90 90
 	}
91 91
 	return nil
92 92
 }
... ...
@@ -15,8 +15,8 @@ import (
15 15
 	flag "github.com/docker/docker/pkg/mflag"
16 16
 	"github.com/docker/docker/pkg/parsers/filters"
17 17
 	"github.com/docker/docker/pkg/stringid"
18
+	"github.com/docker/docker/pkg/stringutils"
18 19
 	"github.com/docker/docker/pkg/units"
19
-	"github.com/docker/docker/utils"
20 20
 )
21 21
 
22 22
 // CmdPs outputs a list of Docker containers.
... ...
@@ -135,7 +135,7 @@ func (cli *DockerCli) CmdPs(args ...string) error {
135 135
 		)
136 136
 
137 137
 		if !*noTrunc {
138
-			command = utils.Trunc(command, 20)
138
+			command = stringutils.Truncate(command, 20)
139 139
 
140 140
 			// only display the default name for the container with notrunc is passed
141 141
 			for _, name := range names {
... ...
@@ -12,7 +12,6 @@ import (
12 12
 	"github.com/docker/docker/pkg/resolvconf"
13 13
 	"github.com/docker/docker/pkg/signal"
14 14
 	"github.com/docker/docker/runconfig"
15
-	"github.com/docker/docker/utils"
16 15
 )
17 16
 
18 17
 func (cid *cidFile) Close() error {
... ...
@@ -242,7 +241,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
242 242
 		}
243 243
 	}
244 244
 	if status != 0 {
245
-		return &utils.StatusError{StatusCode: status}
245
+		return &StatusError{StatusCode: status}
246 246
 	}
247 247
 	return nil
248 248
 }
... ...
@@ -10,8 +10,8 @@ import (
10 10
 
11 11
 	flag "github.com/docker/docker/pkg/mflag"
12 12
 	"github.com/docker/docker/pkg/parsers"
13
+	"github.com/docker/docker/pkg/stringutils"
13 14
 	"github.com/docker/docker/registry"
14
-	"github.com/docker/docker/utils"
15 15
 )
16 16
 
17 17
 type ByStars []registry.SearchResult
... ...
@@ -68,7 +68,7 @@ func (cli *DockerCli) CmdSearch(args ...string) error {
68 68
 		desc := strings.Replace(res.Description, "\n", " ", -1)
69 69
 		desc = strings.Replace(desc, "\r", " ", -1)
70 70
 		if !*noTrunc && len(desc) > 45 {
71
-			desc = utils.Trunc(desc, 42) + "..."
71
+			desc = stringutils.Truncate(desc, 42) + "..."
72 72
 		}
73 73
 		fmt.Fprintf(w, "%s\t%s\t%d\t", res.Name, desc, res.StarCount)
74 74
 		if res.IsOfficial {
... ...
@@ -11,7 +11,6 @@ import (
11 11
 	flag "github.com/docker/docker/pkg/mflag"
12 12
 	"github.com/docker/docker/pkg/promise"
13 13
 	"github.com/docker/docker/pkg/signal"
14
-	"github.com/docker/docker/utils"
15 14
 )
16 15
 
17 16
 func (cli *DockerCli) forwardAllSignals(cid string) chan os.Signal {
... ...
@@ -156,7 +155,7 @@ func (cli *DockerCli) CmdStart(args ...string) error {
156 156
 			return err
157 157
 		}
158 158
 		if status != 0 {
159
-			return &utils.StatusError{StatusCode: status}
159
+			return &StatusError{StatusCode: status}
160 160
 		}
161 161
 	}
162 162
 	return nil
... ...
@@ -25,6 +25,7 @@ import (
25 25
 	imagepkg "github.com/docker/docker/image"
26 26
 	"github.com/docker/docker/pkg/archive"
27 27
 	"github.com/docker/docker/pkg/chrootarchive"
28
+	"github.com/docker/docker/pkg/httputils"
28 29
 	"github.com/docker/docker/pkg/ioutils"
29 30
 	"github.com/docker/docker/pkg/jsonmessage"
30 31
 	"github.com/docker/docker/pkg/parsers"
... ...
@@ -35,7 +36,6 @@ import (
35 35
 	"github.com/docker/docker/pkg/tarsum"
36 36
 	"github.com/docker/docker/pkg/urlutil"
37 37
 	"github.com/docker/docker/runconfig"
38
-	"github.com/docker/docker/utils"
39 38
 )
40 39
 
41 40
 func (b *Builder) readContext(context io.Reader) error {
... ...
@@ -250,7 +250,7 @@ func calcCopyInfo(b *Builder, cmdName string, cInfos *[]*copyInfo, origPath stri
250 250
 		*cInfos = append(*cInfos, &ci)
251 251
 
252 252
 		// Initiate the download
253
-		resp, err := utils.Download(ci.origPath)
253
+		resp, err := httputils.Download(ci.origPath)
254 254
 		if err != nil {
255 255
 			return err
256 256
 		}
... ...
@@ -16,12 +16,12 @@ import (
16 16
 	"github.com/docker/docker/engine"
17 17
 	"github.com/docker/docker/graph"
18 18
 	"github.com/docker/docker/pkg/archive"
19
+	"github.com/docker/docker/pkg/httputils"
19 20
 	"github.com/docker/docker/pkg/parsers"
20 21
 	"github.com/docker/docker/pkg/streamformatter"
21 22
 	"github.com/docker/docker/pkg/urlutil"
22 23
 	"github.com/docker/docker/registry"
23 24
 	"github.com/docker/docker/runconfig"
24
-	"github.com/docker/docker/utils"
25 25
 )
26 26
 
27 27
 // whitelist of commands allowed for a commit/import
... ...
@@ -106,7 +106,7 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) error {
106 106
 		}
107 107
 		context = c
108 108
 	} else if urlutil.IsURL(remoteURL) {
109
-		f, err := utils.Download(remoteURL)
109
+		f, err := httputils.Download(remoteURL)
110 110
 		if err != nil {
111 111
 			return err
112 112
 		}
... ...
@@ -10,7 +10,6 @@ import (
10 10
 	"github.com/Sirupsen/logrus"
11 11
 	"github.com/docker/docker/pkg/jsonlog"
12 12
 	"github.com/docker/docker/pkg/promise"
13
-	"github.com/docker/docker/utils"
14 13
 )
15 14
 
16 15
 func (c *Container) AttachWithLogs(stdin io.ReadCloser, stdout, stderr io.Writer, logs, stream bool) error {
... ...
@@ -131,7 +130,7 @@ func attach(streamConfig *StreamConfig, openStdin, stdinOnce, tty bool, stdin io
131 131
 
132 132
 		var err error
133 133
 		if tty {
134
-			_, err = utils.CopyEscapable(cStdin, stdin)
134
+			_, err = copyEscapable(cStdin, stdin)
135 135
 		} else {
136 136
 			_, err = io.Copy(cStdin, stdin)
137 137
 
... ...
@@ -185,3 +184,46 @@ func attach(streamConfig *StreamConfig, openStdin, stdinOnce, tty bool, stdin io
185 185
 		return nil
186 186
 	})
187 187
 }
188
+
189
+// Code c/c from io.Copy() modified to handle escape sequence
190
+func copyEscapable(dst io.Writer, src io.ReadCloser) (written int64, err error) {
191
+	buf := make([]byte, 32*1024)
192
+	for {
193
+		nr, er := src.Read(buf)
194
+		if nr > 0 {
195
+			// ---- Docker addition
196
+			// char 16 is C-p
197
+			if nr == 1 && buf[0] == 16 {
198
+				nr, er = src.Read(buf)
199
+				// char 17 is C-q
200
+				if nr == 1 && buf[0] == 17 {
201
+					if err := src.Close(); err != nil {
202
+						return 0, err
203
+					}
204
+					return 0, nil
205
+				}
206
+			}
207
+			// ---- End of docker
208
+			nw, ew := dst.Write(buf[0:nr])
209
+			if nw > 0 {
210
+				written += int64(nw)
211
+			}
212
+			if ew != nil {
213
+				err = ew
214
+				break
215
+			}
216
+			if nr != nw {
217
+				err = io.ErrShortWrite
218
+				break
219
+			}
220
+		}
221
+		if er == io.EOF {
222
+			break
223
+		}
224
+		if er != nil {
225
+			err = er
226
+			break
227
+		}
228
+	}
229
+	return written, err
230
+}
... ...
@@ -1063,7 +1063,7 @@ func (container *Container) setupContainerDns() error {
1063 1063
 			updatedResolvConf, modified := resolvconf.FilterResolvDns(latestResolvConf, container.daemon.config.Bridge.EnableIPv6)
1064 1064
 			if modified {
1065 1065
 				// changes have occurred during resolv.conf localhost cleanup: generate an updated hash
1066
-				newHash, err := utils.HashData(bytes.NewReader(updatedResolvConf))
1066
+				newHash, err := ioutils.HashData(bytes.NewReader(updatedResolvConf))
1067 1067
 				if err != nil {
1068 1068
 					return err
1069 1069
 				}
... ...
@@ -1118,7 +1118,7 @@ func (container *Container) setupContainerDns() error {
1118 1118
 	}
1119 1119
 	//get a sha256 hash of the resolv conf at this point so we can check
1120 1120
 	//for changes when the host resolv.conf changes (e.g. network update)
1121
-	resolvHash, err := utils.HashData(bytes.NewReader(resolvConf))
1121
+	resolvHash, err := ioutils.HashData(bytes.NewReader(resolvConf))
1122 1122
 	if err != nil {
1123 1123
 		return err
1124 1124
 	}
... ...
@@ -1150,7 +1150,7 @@ func (container *Container) updateResolvConf(updatedResolvConf []byte, newResolv
1150 1150
 	if err != nil {
1151 1151
 		return err
1152 1152
 	}
1153
-	curHash, err := utils.HashData(bytes.NewReader(resolvBytes))
1153
+	curHash, err := ioutils.HashData(bytes.NewReader(resolvBytes))
1154 1154
 	if err != nil {
1155 1155
 		return err
1156 1156
 	}
... ...
@@ -32,6 +32,7 @@ import (
32 32
 	"github.com/docker/docker/image"
33 33
 	"github.com/docker/docker/pkg/archive"
34 34
 	"github.com/docker/docker/pkg/broadcastwriter"
35
+	"github.com/docker/docker/pkg/fileutils"
35 36
 	"github.com/docker/docker/pkg/graphdb"
36 37
 	"github.com/docker/docker/pkg/ioutils"
37 38
 	"github.com/docker/docker/pkg/namesgenerator"
... ...
@@ -431,7 +432,7 @@ func (daemon *Daemon) setupResolvconfWatcher() error {
431 431
 						updatedResolvConf, modified := resolvconf.FilterResolvDns(updatedResolvConf, daemon.config.Bridge.EnableIPv6)
432 432
 						if modified {
433 433
 							// changes have occurred during localhost cleanup: generate an updated hash
434
-							newHash, err := utils.HashData(bytes.NewReader(updatedResolvConf))
434
+							newHash, err := ioutils.HashData(bytes.NewReader(updatedResolvConf))
435 435
 							if err != nil {
436 436
 								logrus.Debugf("Error generating hash of new resolv.conf: %v", err)
437 437
 							} else {
... ...
@@ -830,7 +831,7 @@ func NewDaemonFromDirectory(config *Config, eng *engine.Engine, registryService
830 830
 	if err != nil {
831 831
 		return nil, fmt.Errorf("Unable to get the TempDir under %s: %s", config.Root, err)
832 832
 	}
833
-	realTmp, err := utils.ReadSymlinkedDirectory(tmp)
833
+	realTmp, err := fileutils.ReadSymlinkedDirectory(tmp)
834 834
 	if err != nil {
835 835
 		return nil, fmt.Errorf("Unable to get the full path to the TempDir (%s): %s", tmp, err)
836 836
 	}
... ...
@@ -841,7 +842,7 @@ func NewDaemonFromDirectory(config *Config, eng *engine.Engine, registryService
841 841
 	if _, err := os.Stat(config.Root); err != nil && os.IsNotExist(err) {
842 842
 		realRoot = config.Root
843 843
 	} else {
844
-		realRoot, err = utils.ReadSymlinkedDirectory(config.Root)
844
+		realRoot, err = fileutils.ReadSymlinkedDirectory(config.Root)
845 845
 		if err != nil {
846 846
 			return nil, fmt.Errorf("Unable to get the full path to root (%s): %s", config.Root, err)
847 847
 		}
... ...
@@ -959,7 +960,7 @@ func NewDaemonFromDirectory(config *Config, eng *engine.Engine, registryService
959 959
 		if err := os.Mkdir(path.Dir(localCopy), 0700); err != nil && !os.IsExist(err) {
960 960
 			return nil, err
961 961
 		}
962
-		if _, err := utils.CopyFile(sysInitPath, localCopy); err != nil {
962
+		if _, err := fileutils.CopyFile(sysInitPath, localCopy); err != nil {
963 963
 			return nil, err
964 964
 		}
965 965
 		if err := os.Chmod(localCopy, 0700); err != nil {
... ...
@@ -18,10 +18,10 @@ import (
18 18
 
19 19
 	"github.com/Sirupsen/logrus"
20 20
 	"github.com/docker/docker/daemon/execdriver"
21
+	"github.com/docker/docker/pkg/stringutils"
21 22
 	sysinfo "github.com/docker/docker/pkg/system"
22 23
 	"github.com/docker/docker/pkg/term"
23 24
 	"github.com/docker/docker/pkg/version"
24
-	"github.com/docker/docker/utils"
25 25
 	"github.com/docker/libcontainer"
26 26
 	"github.com/docker/libcontainer/cgroups"
27 27
 	"github.com/docker/libcontainer/configs"
... ...
@@ -187,7 +187,7 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
187 187
 		// without exec in go we have to do this horrible shell hack...
188 188
 		shellString :=
189 189
 			"mount --make-rslave /; exec " +
190
-				utils.ShellQuoteArguments(params)
190
+				stringutils.ShellQuoteArguments(params)
191 191
 
192 192
 		params = []string{
193 193
 			"unshare", "-m", "--", "/bin/sh", "-c", shellString,
... ...
@@ -9,7 +9,7 @@ import (
9 9
 	"github.com/Sirupsen/logrus"
10 10
 	"github.com/docker/docker/daemon/execdriver"
11 11
 	nativeTemplate "github.com/docker/docker/daemon/execdriver/native/template"
12
-	"github.com/docker/docker/utils"
12
+	"github.com/docker/docker/pkg/stringutils"
13 13
 	"github.com/docker/libcontainer/label"
14 14
 )
15 15
 
... ...
@@ -177,7 +177,7 @@ func keepCapabilities(adds []string, drops []string) ([]string, error) {
177 177
 }
178 178
 
179 179
 func dropList(drops []string) ([]string, error) {
180
-	if utils.StringsContainsNoCase(drops, "all") {
180
+	if stringutils.InSlice(drops, "all") {
181 181
 		var newCaps []string
182 182
 		for _, capName := range execdriver.GetAllCapabilities() {
183 183
 			cap := execdriver.GetCapability(capName)
... ...
@@ -4,7 +4,7 @@ import (
4 4
 	"fmt"
5 5
 	"strings"
6 6
 
7
-	"github.com/docker/docker/utils"
7
+	"github.com/docker/docker/pkg/stringutils"
8 8
 	"github.com/syndtr/gocapability/capability"
9 9
 )
10 10
 
... ...
@@ -89,17 +89,17 @@ func TweakCapabilities(basics, adds, drops []string) ([]string, error) {
89 89
 		if strings.ToLower(cap) == "all" {
90 90
 			continue
91 91
 		}
92
-		if !utils.StringsContainsNoCase(allCaps, cap) {
92
+		if !stringutils.InSlice(allCaps, cap) {
93 93
 			return nil, fmt.Errorf("Unknown capability drop: %q", cap)
94 94
 		}
95 95
 	}
96 96
 
97 97
 	// handle --cap-add=all
98
-	if utils.StringsContainsNoCase(adds, "all") {
98
+	if stringutils.InSlice(adds, "all") {
99 99
 		basics = allCaps
100 100
 	}
101 101
 
102
-	if !utils.StringsContainsNoCase(drops, "all") {
102
+	if !stringutils.InSlice(drops, "all") {
103 103
 		for _, cap := range basics {
104 104
 			// skip `all` aready handled above
105 105
 			if strings.ToLower(cap) == "all" {
... ...
@@ -107,7 +107,7 @@ func TweakCapabilities(basics, adds, drops []string) ([]string, error) {
107 107
 			}
108 108
 
109 109
 			// if we don't drop `all`, add back all the non-dropped caps
110
-			if !utils.StringsContainsNoCase(drops, cap) {
110
+			if !stringutils.InSlice(drops, cap) {
111 111
 				newCaps = append(newCaps, strings.ToUpper(cap))
112 112
 			}
113 113
 		}
... ...
@@ -119,12 +119,12 @@ func TweakCapabilities(basics, adds, drops []string) ([]string, error) {
119 119
 			continue
120 120
 		}
121 121
 
122
-		if !utils.StringsContainsNoCase(allCaps, cap) {
122
+		if !stringutils.InSlice(allCaps, cap) {
123 123
 			return nil, fmt.Errorf("Unknown capability to add: %q", cap)
124 124
 		}
125 125
 
126 126
 		// add cap if not already in the list
127
-		if !utils.StringsContainsNoCase(newCaps, cap) {
127
+		if !stringutils.InSlice(newCaps, cap) {
128 128
 			newCaps = append(newCaps, strings.ToUpper(cap))
129 129
 		}
130 130
 	}
... ...
@@ -8,6 +8,7 @@ import (
8 8
 	"github.com/Sirupsen/logrus"
9 9
 	"github.com/docker/docker/autogen/dockerversion"
10 10
 	"github.com/docker/docker/engine"
11
+	"github.com/docker/docker/pkg/fileutils"
11 12
 	"github.com/docker/docker/pkg/parsers/kernel"
12 13
 	"github.com/docker/docker/pkg/parsers/operatingsystem"
13 14
 	"github.com/docker/docker/pkg/system"
... ...
@@ -61,7 +62,7 @@ func (daemon *Daemon) CmdInfo(job *engine.Job) error {
61 61
 	v.SetBool("SwapLimit", daemon.SystemConfig().SwapLimit)
62 62
 	v.SetBool("IPv4Forwarding", !daemon.SystemConfig().IPv4ForwardingDisabled)
63 63
 	v.SetBool("Debug", os.Getenv("DEBUG") != "")
64
-	v.SetInt("NFd", utils.GetTotalUsedFds())
64
+	v.SetInt("NFd", fileutils.GetTotalUsedFds())
65 65
 	v.SetInt("NGoroutines", runtime.NumGoroutine())
66 66
 	v.Set("SystemTime", time.Now().Format(time.RFC3339Nano))
67 67
 	v.Set("ExecutionDriver", daemon.ExecutionDriver().Name())
... ...
@@ -4,12 +4,11 @@ import (
4 4
 	"testing"
5 5
 
6 6
 	"github.com/docker/docker/runconfig"
7
-	"github.com/docker/docker/utils"
8 7
 )
9 8
 
10 9
 func TestMergeLxcConfig(t *testing.T) {
11 10
 	hostConfig := &runconfig.HostConfig{
12
-		LxcConf: []utils.KeyValuePair{
11
+		LxcConf: []runconfig.KeyValuePair{
13 12
 			{Key: "lxc.cgroups.cpuset", Value: "1,2"},
14 13
 		},
15 14
 	}
... ...
@@ -15,7 +15,6 @@ import (
15 15
 	flag "github.com/docker/docker/pkg/mflag"
16 16
 	"github.com/docker/docker/pkg/reexec"
17 17
 	"github.com/docker/docker/pkg/term"
18
-	"github.com/docker/docker/utils"
19 18
 )
20 19
 
21 20
 const (
... ...
@@ -136,7 +135,7 @@ func main() {
136 136
 	}
137 137
 
138 138
 	if err := cli.Cmd(flag.Args()...); err != nil {
139
-		if sterr, ok := err.(*utils.StatusError); ok {
139
+		if sterr, ok := err.(*client.StatusError); ok {
140 140
 			if sterr.Status != "" {
141 141
 				logrus.Println(sterr.Status)
142 142
 			}
... ...
@@ -9,7 +9,7 @@ import (
9 9
 	"strings"
10 10
 	"time"
11 11
 
12
-	"github.com/docker/docker/utils"
12
+	"github.com/docker/docker/pkg/ioutils"
13 13
 )
14 14
 
15 15
 type Env []string
... ...
@@ -258,7 +258,7 @@ func (env *Env) Encode(dst io.Writer) error {
258 258
 }
259 259
 
260 260
 func (env *Env) WriteTo(dst io.Writer) (int64, error) {
261
-	wc := utils.NewWriteCounter(dst)
261
+	wc := ioutils.NewWriteCounter(dst)
262 262
 	err := env.Encode(wc)
263 263
 	return wc.Count, err
264 264
 }
... ...
@@ -25,7 +25,6 @@ import (
25 25
 	"github.com/docker/docker/pkg/stringid"
26 26
 	"github.com/docker/docker/pkg/truncindex"
27 27
 	"github.com/docker/docker/runconfig"
28
-	"github.com/docker/docker/utils"
29 28
 )
30 29
 
31 30
 // A Graph is a store for versioned filesystem images and the relationship between them.
... ...
@@ -154,7 +153,7 @@ func (graph *Graph) Register(img *image.Image, layerData archive.ArchiveReader)
154 154
 			graph.driver.Remove(img.ID)
155 155
 		}
156 156
 	}()
157
-	if err := utils.ValidateID(img.ID); err != nil {
157
+	if err := image.ValidateID(img.ID); err != nil {
158 158
 		return err
159 159
 	}
160 160
 	// (This is a convenience to save time. Race conditions are taken care of by os.Rename)
... ...
@@ -9,6 +9,7 @@ import (
9 9
 
10 10
 	"github.com/docker/docker/engine"
11 11
 	"github.com/docker/docker/pkg/archive"
12
+	"github.com/docker/docker/pkg/httputils"
12 13
 	"github.com/docker/docker/pkg/progressreader"
13 14
 	"github.com/docker/docker/pkg/streamformatter"
14 15
 	"github.com/docker/docker/runconfig"
... ...
@@ -46,7 +47,7 @@ func (s *TagStore) CmdImport(job *engine.Job) error {
46 46
 			u.Path = ""
47 47
 		}
48 48
 		job.Stdout.Write(sf.FormatStatus("", "Downloading from %s", u))
49
-		resp, err = utils.Download(u.String())
49
+		resp, err = httputils.Download(u.String())
50 50
 		if err != nil {
51 51
 			return err
52 52
 		}
... ...
@@ -13,7 +13,6 @@ import (
13 13
 	"github.com/docker/docker/image"
14 14
 	"github.com/docker/docker/pkg/archive"
15 15
 	"github.com/docker/docker/pkg/chrootarchive"
16
-	"github.com/docker/docker/utils"
17 16
 )
18 17
 
19 18
 // Loads a set of images into the repository. This is the complementary of ImageExport.
... ...
@@ -100,7 +99,7 @@ func (s *TagStore) recursiveLoad(eng *engine.Engine, address, tmpImageDir string
100 100
 			logrus.Debugf("Error unmarshalling json", err)
101 101
 			return err
102 102
 		}
103
-		if err := utils.ValidateID(img.ID); err != nil {
103
+		if err := image.ValidateID(img.ID); err != nil {
104 104
 			logrus.Debugf("Error validating ID: %s", err)
105 105
 			return err
106 106
 		}
... ...
@@ -6,12 +6,12 @@ import (
6 6
 	"io/ioutil"
7 7
 	"os"
8 8
 	"path"
9
+	"regexp"
9 10
 	"strconv"
10 11
 	"time"
11 12
 
12 13
 	"github.com/docker/docker/pkg/archive"
13 14
 	"github.com/docker/docker/runconfig"
14
-	"github.com/docker/docker/utils"
15 15
 )
16 16
 
17 17
 // Set the max depth to the aufs default that most
... ...
@@ -51,7 +51,7 @@ func LoadImage(root string) (*Image, error) {
51 51
 	if err := dec.Decode(img); err != nil {
52 52
 		return nil, err
53 53
 	}
54
-	if err := utils.ValidateID(img.ID); err != nil {
54
+	if err := ValidateID(img.ID); err != nil {
55 55
 		return nil, err
56 56
 	}
57 57
 
... ...
@@ -263,3 +263,13 @@ func NewImgJSON(src []byte) (*Image, error) {
263 263
 	}
264 264
 	return ret, nil
265 265
 }
266
+
267
+// Check wheather id is a valid image ID or not
268
+func ValidateID(id string) error {
269
+	validHex := regexp.MustCompile(`^([a-f0-9]{64})$`)
270
+	if ok := validHex.MatchString(id); !ok {
271
+		err := fmt.Errorf("image ID '%s' is invalid", id)
272
+		return err
273
+	}
274
+	return nil
275
+}
... ...
@@ -15,7 +15,6 @@ import (
15 15
 	"github.com/docker/docker/image"
16 16
 	"github.com/docker/docker/pkg/archive"
17 17
 	"github.com/docker/docker/pkg/stringid"
18
-	"github.com/docker/docker/utils"
19 18
 )
20 19
 
21 20
 func TestMount(t *testing.T) {
... ...
@@ -103,7 +102,7 @@ func TestGraphCreate(t *testing.T) {
103 103
 	if err != nil {
104 104
 		t.Fatal(err)
105 105
 	}
106
-	if err := utils.ValidateID(img.ID); err != nil {
106
+	if err := image.ValidateID(img.ID); err != nil {
107 107
 		t.Fatal(err)
108 108
 	}
109 109
 	if img.Comment != "Testing" {
... ...
@@ -23,6 +23,7 @@ import (
23 23
 	"github.com/docker/docker/graph"
24 24
 	"github.com/docker/docker/image"
25 25
 	"github.com/docker/docker/nat"
26
+	"github.com/docker/docker/pkg/fileutils"
26 27
 	"github.com/docker/docker/pkg/ioutils"
27 28
 	"github.com/docker/docker/pkg/reexec"
28 29
 	"github.com/docker/docker/pkg/stringid"
... ...
@@ -121,7 +122,7 @@ func init() {
121 121
 	spawnGlobalDaemon()
122 122
 	spawnLegitHttpsDaemon()
123 123
 	spawnRogueHttpsDaemon()
124
-	startFds, startGoroutines = utils.GetTotalUsedFds(), runtime.NumGoroutine()
124
+	startFds, startGoroutines = fileutils.GetTotalUsedFds(), runtime.NumGoroutine()
125 125
 }
126 126
 
127 127
 func setupBaseImage() {
... ...
@@ -1,13 +1,14 @@
1 1
 package docker
2 2
 
3 3
 import (
4
-	"github.com/docker/docker/utils"
5 4
 	"runtime"
6 5
 	"testing"
6
+
7
+	"github.com/docker/docker/pkg/fileutils"
7 8
 )
8 9
 
9 10
 func displayFdGoroutines(t *testing.T) {
10
-	t.Logf("File Descriptors: %d, Goroutines: %d", utils.GetTotalUsedFds(), runtime.NumGoroutine())
11
+	t.Logf("File Descriptors: %d, Goroutines: %d", fileutils.GetTotalUsedFds(), runtime.NumGoroutine())
11 12
 }
12 13
 
13 14
 func TestFinal(t *testing.T) {
... ...
@@ -1,6 +1,10 @@
1 1
 package fileutils
2 2
 
3 3
 import (
4
+	"fmt"
5
+	"io"
6
+	"io/ioutil"
7
+	"os"
4 8
 	"path/filepath"
5 9
 
6 10
 	"github.com/Sirupsen/logrus"
... ...
@@ -25,3 +29,53 @@ func Matches(relFilePath string, patterns []string) (bool, error) {
25 25
 	}
26 26
 	return false, nil
27 27
 }
28
+
29
+func CopyFile(src, dst string) (int64, error) {
30
+	if src == dst {
31
+		return 0, nil
32
+	}
33
+	sf, err := os.Open(src)
34
+	if err != nil {
35
+		return 0, err
36
+	}
37
+	defer sf.Close()
38
+	if err := os.Remove(dst); err != nil && !os.IsNotExist(err) {
39
+		return 0, err
40
+	}
41
+	df, err := os.Create(dst)
42
+	if err != nil {
43
+		return 0, err
44
+	}
45
+	defer df.Close()
46
+	return io.Copy(df, sf)
47
+}
48
+
49
+func GetTotalUsedFds() int {
50
+	if fds, err := ioutil.ReadDir(fmt.Sprintf("/proc/%d/fd", os.Getpid())); err != nil {
51
+		logrus.Errorf("Error opening /proc/%d/fd: %s", os.Getpid(), err)
52
+	} else {
53
+		return len(fds)
54
+	}
55
+	return -1
56
+}
57
+
58
+// ReadSymlinkedDirectory returns the target directory of a symlink.
59
+// The target of the symbolic link may not be a file.
60
+func ReadSymlinkedDirectory(path string) (string, error) {
61
+	var realPath string
62
+	var err error
63
+	if realPath, err = filepath.Abs(path); err != nil {
64
+		return "", fmt.Errorf("unable to get absolute path for %s: %s", path, err)
65
+	}
66
+	if realPath, err = filepath.EvalSymlinks(realPath); err != nil {
67
+		return "", fmt.Errorf("failed to canonicalise path for %s: %s", path, err)
68
+	}
69
+	realPathInfo, err := os.Stat(realPath)
70
+	if err != nil {
71
+		return "", fmt.Errorf("failed to stat target '%s' of '%s': %s", realPath, path, err)
72
+	}
73
+	if !realPathInfo.Mode().IsDir() {
74
+		return "", fmt.Errorf("canonical path points to a file '%s'", realPath)
75
+	}
76
+	return realPath, nil
77
+}
28 78
new file mode 100644
... ...
@@ -0,0 +1,81 @@
0
+package fileutils
1
+
2
+import (
3
+	"os"
4
+	"testing"
5
+)
6
+
7
+// Reading a symlink to a directory must return the directory
8
+func TestReadSymlinkedDirectoryExistingDirectory(t *testing.T) {
9
+	var err error
10
+	if err = os.Mkdir("/tmp/testReadSymlinkToExistingDirectory", 0777); err != nil {
11
+		t.Errorf("failed to create directory: %s", err)
12
+	}
13
+
14
+	if err = os.Symlink("/tmp/testReadSymlinkToExistingDirectory", "/tmp/dirLinkTest"); err != nil {
15
+		t.Errorf("failed to create symlink: %s", err)
16
+	}
17
+
18
+	var path string
19
+	if path, err = ReadSymlinkedDirectory("/tmp/dirLinkTest"); err != nil {
20
+		t.Fatalf("failed to read symlink to directory: %s", err)
21
+	}
22
+
23
+	if path != "/tmp/testReadSymlinkToExistingDirectory" {
24
+		t.Fatalf("symlink returned unexpected directory: %s", path)
25
+	}
26
+
27
+	if err = os.Remove("/tmp/testReadSymlinkToExistingDirectory"); err != nil {
28
+		t.Errorf("failed to remove temporary directory: %s", err)
29
+	}
30
+
31
+	if err = os.Remove("/tmp/dirLinkTest"); err != nil {
32
+		t.Errorf("failed to remove symlink: %s", err)
33
+	}
34
+}
35
+
36
+// Reading a non-existing symlink must fail
37
+func TestReadSymlinkedDirectoryNonExistingSymlink(t *testing.T) {
38
+	var path string
39
+	var err error
40
+	if path, err = ReadSymlinkedDirectory("/tmp/test/foo/Non/ExistingPath"); err == nil {
41
+		t.Fatalf("error expected for non-existing symlink")
42
+	}
43
+
44
+	if path != "" {
45
+		t.Fatalf("expected empty path, but '%s' was returned", path)
46
+	}
47
+}
48
+
49
+// Reading a symlink to a file must fail
50
+func TestReadSymlinkedDirectoryToFile(t *testing.T) {
51
+	var err error
52
+	var file *os.File
53
+
54
+	if file, err = os.Create("/tmp/testReadSymlinkToFile"); err != nil {
55
+		t.Fatalf("failed to create file: %s", err)
56
+	}
57
+
58
+	file.Close()
59
+
60
+	if err = os.Symlink("/tmp/testReadSymlinkToFile", "/tmp/fileLinkTest"); err != nil {
61
+		t.Errorf("failed to create symlink: %s", err)
62
+	}
63
+
64
+	var path string
65
+	if path, err = ReadSymlinkedDirectory("/tmp/fileLinkTest"); err == nil {
66
+		t.Fatalf("ReadSymlinkedDirectory on a symlink to a file should've failed")
67
+	}
68
+
69
+	if path != "" {
70
+		t.Fatalf("path should've been empty: %s", path)
71
+	}
72
+
73
+	if err = os.Remove("/tmp/testReadSymlinkToFile"); err != nil {
74
+		t.Errorf("failed to remove file: %s", err)
75
+	}
76
+
77
+	if err = os.Remove("/tmp/fileLinkTest"); err != nil {
78
+		t.Errorf("failed to remove symlink: %s", err)
79
+	}
80
+}
0 81
new file mode 100644
... ...
@@ -0,0 +1,26 @@
0
+package httputils
1
+
2
+import (
3
+	"fmt"
4
+	"net/http"
5
+
6
+	"github.com/docker/docker/pkg/jsonmessage"
7
+)
8
+
9
+// Request a given URL and return an io.Reader
10
+func Download(url string) (resp *http.Response, err error) {
11
+	if resp, err = http.Get(url); err != nil {
12
+		return nil, err
13
+	}
14
+	if resp.StatusCode >= 400 {
15
+		return nil, fmt.Errorf("Got HTTP status code >= 400: %s", resp.Status)
16
+	}
17
+	return resp, nil
18
+}
19
+
20
+func NewHTTPRequestError(msg string, res *http.Response) error {
21
+	return &jsonmessage.JSONError{
22
+		Message: msg,
23
+		Code:    res.StatusCode,
24
+	}
25
+}
... ...
@@ -3,6 +3,8 @@ package ioutils
3 3
 import (
4 4
 	"bytes"
5 5
 	"crypto/rand"
6
+	"crypto/sha256"
7
+	"encoding/hex"
6 8
 	"io"
7 9
 	"math/big"
8 10
 	"sync"
... ...
@@ -215,3 +217,11 @@ func (r *bufReader) Close() error {
215 215
 	}
216 216
 	return closer.Close()
217 217
 }
218
+
219
+func HashData(src io.Reader) (string, error) {
220
+	h := sha256.New()
221
+	if _, err := io.Copy(h, src); err != nil {
222
+		return "", err
223
+	}
224
+	return "sha256:" + hex.EncodeToString(h.Sum(nil)), nil
225
+}
... ...
@@ -37,3 +37,24 @@ func NewWriteCloserWrapper(r io.Writer, closer func() error) io.WriteCloser {
37 37
 		closer: closer,
38 38
 	}
39 39
 }
40
+
41
+// Wrap a concrete io.Writer and hold a count of the number
42
+// of bytes written to the writer during a "session".
43
+// This can be convenient when write return is masked
44
+// (e.g., json.Encoder.Encode())
45
+type WriteCounter struct {
46
+	Count  int64
47
+	Writer io.Writer
48
+}
49
+
50
+func NewWriteCounter(w io.Writer) *WriteCounter {
51
+	return &WriteCounter{
52
+		Writer: w,
53
+	}
54
+}
55
+
56
+func (wc *WriteCounter) Write(p []byte) (count int, err error) {
57
+	count, err = wc.Writer.Write(p)
58
+	wc.Count += int64(count)
59
+	return
60
+}
40 61
new file mode 100644
... ...
@@ -0,0 +1,41 @@
0
+package ioutils
1
+
2
+import (
3
+	"bytes"
4
+	"strings"
5
+	"testing"
6
+)
7
+
8
+func TestNopWriter(t *testing.T) {
9
+	nw := &NopWriter{}
10
+	l, err := nw.Write([]byte{'c'})
11
+	if err != nil {
12
+		t.Fatal(err)
13
+	}
14
+	if l != 1 {
15
+		t.Fatalf("Expected 1 got %d", l)
16
+	}
17
+}
18
+
19
+func TestWriteCounter(t *testing.T) {
20
+	dummy1 := "This is a dummy string."
21
+	dummy2 := "This is another dummy string."
22
+	totalLength := int64(len(dummy1) + len(dummy2))
23
+
24
+	reader1 := strings.NewReader(dummy1)
25
+	reader2 := strings.NewReader(dummy2)
26
+
27
+	var buffer bytes.Buffer
28
+	wc := NewWriteCounter(&buffer)
29
+
30
+	reader1.WriteTo(wc)
31
+	reader2.WriteTo(wc)
32
+
33
+	if wc.Count != totalLength {
34
+		t.Errorf("Wrong count: %d vs. %d", wc.Count, totalLength)
35
+	}
36
+
37
+	if buffer.String() != dummy1+dummy2 {
38
+		t.Error("Wrong message written")
39
+	}
40
+}
... ...
@@ -180,8 +180,8 @@ func TestRequestFactory(t *testing.T) {
180 180
 
181 181
 	requestFactory := NewRequestFactory(ad, uad)
182 182
 
183
-	if dlen := len(requestFactory.GetDecorators()); dlen != 2 {
184
-		t.Fatalf("Expected to have two decorators, got %d", dlen)
183
+	if l := len(requestFactory.GetDecorators()); l != 2 {
184
+		t.Fatalf("Expected to have two decorators, got %d", l)
185 185
 	}
186 186
 
187 187
 	req, err := requestFactory.NewRequest("GET", "/test", strings.NewReader("test"))
... ...
@@ -209,8 +209,8 @@ func TestRequestFactoryNewRequestWithDecorators(t *testing.T) {
209 209
 
210 210
 	requestFactory := NewRequestFactory(ad)
211 211
 
212
-	if dlen := len(requestFactory.GetDecorators()); dlen != 1 {
213
-		t.Fatalf("Expected to have one decorators, got %d", dlen)
212
+	if l := len(requestFactory.GetDecorators()); l != 1 {
213
+		t.Fatalf("Expected to have one decorators, got %d", l)
214 214
 	}
215 215
 
216 216
 	ad2 := NewAuthDecorator("test2", "password2")
... ...
@@ -235,15 +235,15 @@ func TestRequestFactoryNewRequestWithDecorators(t *testing.T) {
235 235
 func TestRequestFactoryAddDecorator(t *testing.T) {
236 236
 	requestFactory := NewRequestFactory()
237 237
 
238
-	if dlen := len(requestFactory.GetDecorators()); dlen != 0 {
239
-		t.Fatalf("Expected to have zero decorators, got %d", dlen)
238
+	if l := len(requestFactory.GetDecorators()); l != 0 {
239
+		t.Fatalf("Expected to have zero decorators, got %d", l)
240 240
 	}
241 241
 
242 242
 	ad := NewAuthDecorator("test", "password")
243 243
 	requestFactory.AddDecorator(ad)
244 244
 
245
-	if dlen := len(requestFactory.GetDecorators()); dlen != 1 {
246
-		t.Fatalf("Expected to have one decorators, got %d", dlen)
245
+	if l := len(requestFactory.GetDecorators()); l != 1 {
246
+		t.Fatalf("Expected to have one decorators, got %d", l)
247 247
 	}
248 248
 }
249 249
 
... ...
@@ -9,7 +9,7 @@ import (
9 9
 	"sync"
10 10
 
11 11
 	"github.com/Sirupsen/logrus"
12
-	"github.com/docker/docker/utils"
12
+	"github.com/docker/docker/pkg/ioutils"
13 13
 )
14 14
 
15 15
 var (
... ...
@@ -59,7 +59,7 @@ func GetIfChanged() ([]byte, string, error) {
59 59
 	if err != nil {
60 60
 		return nil, "", err
61 61
 	}
62
-	newHash, err := utils.HashData(bytes.NewReader(resolv))
62
+	newHash, err := ioutils.HashData(bytes.NewReader(resolv))
63 63
 	if err != nil {
64 64
 		return nil, "", err
65 65
 	}
... ...
@@ -1,7 +1,9 @@
1 1
 package stringutils
2 2
 
3 3
 import (
4
+	"bytes"
4 5
 	mathrand "math/rand"
6
+	"strings"
5 7
 	"time"
6 8
 )
7 9
 
... ...
@@ -28,3 +30,57 @@ func GenerateRandomAsciiString(n int) string {
28 28
 	}
29 29
 	return string(res)
30 30
 }
31
+
32
+// Truncate a string to maxlen
33
+func Truncate(s string, maxlen int) string {
34
+	if len(s) <= maxlen {
35
+		return s
36
+	}
37
+	return s[:maxlen]
38
+}
39
+
40
+// Test wheather a string is contained in a slice of strings or not.
41
+// Comparison is case insensitive
42
+func InSlice(slice []string, s string) bool {
43
+	for _, ss := range slice {
44
+		if strings.ToLower(s) == strings.ToLower(ss) {
45
+			return true
46
+		}
47
+	}
48
+	return false
49
+}
50
+
51
+func quote(word string, buf *bytes.Buffer) {
52
+	// Bail out early for "simple" strings
53
+	if word != "" && !strings.ContainsAny(word, "\\'\"`${[|&;<>()~*?! \t\n") {
54
+		buf.WriteString(word)
55
+		return
56
+	}
57
+
58
+	buf.WriteString("'")
59
+
60
+	for i := 0; i < len(word); i++ {
61
+		b := word[i]
62
+		if b == '\'' {
63
+			// Replace literal ' with a close ', a \', and a open '
64
+			buf.WriteString("'\\''")
65
+		} else {
66
+			buf.WriteByte(b)
67
+		}
68
+	}
69
+
70
+	buf.WriteString("'")
71
+}
72
+
73
+// Take a list of strings and escape them so they will be handled right
74
+// when passed as arguments to an program via a shell
75
+func ShellQuoteArguments(args []string) string {
76
+	var buf bytes.Buffer
77
+	for i, arg := range args {
78
+		if i != 0 {
79
+			buf.WriteByte(' ')
80
+		}
81
+		quote(arg, &buf)
82
+	}
83
+	return buf.String()
84
+}
... ...
@@ -56,3 +56,32 @@ func TestGenerateRandomAsciiStringIsAscii(t *testing.T) {
56 56
 		t.Fatalf("%s contained non-ascii characters", str)
57 57
 	}
58 58
 }
59
+
60
+func TestTruncate(t *testing.T) {
61
+	str := "teststring"
62
+	newstr := Truncate(str, 4)
63
+	if newstr != "test" {
64
+		t.Fatalf("Expected test, got %s", newstr)
65
+	}
66
+	newstr = Truncate(str, 20)
67
+	if newstr != "teststring" {
68
+		t.Fatalf("Expected teststring, got %s", newstr)
69
+	}
70
+}
71
+
72
+func TestInSlice(t *testing.T) {
73
+	slice := []string{"test", "in", "slice"}
74
+
75
+	test := InSlice(slice, "test")
76
+	if !test {
77
+		t.Fatalf("Expected string test to be in slice")
78
+	}
79
+	test = InSlice(slice, "SLICE")
80
+	if !test {
81
+		t.Fatalf("Expected string SLICE to be in slice")
82
+	}
83
+	test = InSlice(slice, "notinslice")
84
+	if test {
85
+		t.Fatalf("Expected string notinslice not to be in slice")
86
+	}
87
+}
... ...
@@ -9,9 +9,9 @@ import (
9 9
 	"regexp"
10 10
 	"strings"
11 11
 
12
+	"github.com/docker/docker/image"
12 13
 	"github.com/docker/docker/opts"
13 14
 	flag "github.com/docker/docker/pkg/mflag"
14
-	"github.com/docker/docker/utils"
15 15
 )
16 16
 
17 17
 // Options holds command line options.
... ...
@@ -213,7 +213,7 @@ func validateRemoteName(remoteName string) error {
213 213
 		name = nameParts[0]
214 214
 
215 215
 		// the repository name must not be a valid image ID
216
-		if err := utils.ValidateID(name); err == nil {
216
+		if err := image.ValidateID(name); err == nil {
217 217
 			return fmt.Errorf("Invalid repository name (%s), cannot specify 64-byte hexadecimal strings", name)
218 218
 		}
219 219
 	} else {
... ...
@@ -21,7 +21,6 @@ import (
21 21
 	"github.com/docker/docker/pkg/httputils"
22 22
 	"github.com/docker/docker/pkg/requestdecorator"
23 23
 	"github.com/docker/docker/pkg/tarsum"
24
-	"github.com/docker/docker/utils"
25 24
 )
26 25
 
27 26
 type Session struct {
... ...
@@ -86,7 +85,7 @@ func (r *Session) GetRemoteHistory(imgID, registry string, token []string) ([]st
86 86
 		if res.StatusCode == 401 {
87 87
 			return nil, errLoginRequired
88 88
 		}
89
-		return nil, utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to fetch remote history for %s", res.StatusCode, imgID), res)
89
+		return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to fetch remote history for %s", res.StatusCode, imgID), res)
90 90
 	}
91 91
 
92 92
 	jsonString, err := ioutil.ReadAll(res.Body)
... ...
@@ -115,7 +114,7 @@ func (r *Session) LookupRemoteImage(imgID, registry string, token []string) erro
115 115
 	}
116 116
 	res.Body.Close()
117 117
 	if res.StatusCode != 200 {
118
-		return utils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d", res.StatusCode), res)
118
+		return httputils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d", res.StatusCode), res)
119 119
 	}
120 120
 	return nil
121 121
 }
... ...
@@ -134,7 +133,7 @@ func (r *Session) GetRemoteImageJSON(imgID, registry string, token []string) ([]
134 134
 	}
135 135
 	defer res.Body.Close()
136 136
 	if res.StatusCode != 200 {
137
-		return nil, -1, utils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d", res.StatusCode), res)
137
+		return nil, -1, httputils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d", res.StatusCode), res)
138 138
 	}
139 139
 	// if the size header is not present, then set it to '-1'
140 140
 	imageSize := -1
... ...
@@ -282,13 +281,13 @@ func (r *Session) GetRepositoryData(remote string) (*RepositoryData, error) {
282 282
 	// TODO: Right now we're ignoring checksums in the response body.
283 283
 	// In the future, we need to use them to check image validity.
284 284
 	if res.StatusCode == 404 {
285
-		return nil, utils.NewHTTPRequestError(fmt.Sprintf("HTTP code: %d", res.StatusCode), res)
285
+		return nil, httputils.NewHTTPRequestError(fmt.Sprintf("HTTP code: %d", res.StatusCode), res)
286 286
 	} else if res.StatusCode != 200 {
287 287
 		errBody, err := ioutil.ReadAll(res.Body)
288 288
 		if err != nil {
289 289
 			logrus.Debugf("Error reading response body: %s", err)
290 290
 		}
291
-		return nil, utils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to pull repository %s: %q", res.StatusCode, remote, errBody), res)
291
+		return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to pull repository %s: %q", res.StatusCode, remote, errBody), res)
292 292
 	}
293 293
 
294 294
 	var tokens []string
... ...
@@ -379,12 +378,12 @@ func (r *Session) PushImageJSONRegistry(imgData *ImgData, jsonRaw []byte, regist
379 379
 	}
380 380
 	defer res.Body.Close()
381 381
 	if res.StatusCode == 401 && strings.HasPrefix(registry, "http://") {
382
-		return utils.NewHTTPRequestError("HTTP code 401, Docker will not send auth headers over HTTP.", res)
382
+		return httputils.NewHTTPRequestError("HTTP code 401, Docker will not send auth headers over HTTP.", res)
383 383
 	}
384 384
 	if res.StatusCode != 200 {
385 385
 		errBody, err := ioutil.ReadAll(res.Body)
386 386
 		if err != nil {
387
-			return utils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d while uploading metadata and error when trying to parse response body: %s", res.StatusCode, err), res)
387
+			return httputils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d while uploading metadata and error when trying to parse response body: %s", res.StatusCode, err), res)
388 388
 		}
389 389
 		var jsonBody map[string]string
390 390
 		if err := json.Unmarshal(errBody, &jsonBody); err != nil {
... ...
@@ -392,7 +391,7 @@ func (r *Session) PushImageJSONRegistry(imgData *ImgData, jsonRaw []byte, regist
392 392
 		} else if jsonBody["error"] == "Image already exists" {
393 393
 			return ErrAlreadyExists
394 394
 		}
395
-		return utils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d while uploading metadata: %q", res.StatusCode, errBody), res)
395
+		return httputils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d while uploading metadata: %q", res.StatusCode, errBody), res)
396 396
 	}
397 397
 	return nil
398 398
 }
... ...
@@ -432,9 +431,9 @@ func (r *Session) PushImageLayerRegistry(imgID string, layer io.Reader, registry
432 432
 	if res.StatusCode != 200 {
433 433
 		errBody, err := ioutil.ReadAll(res.Body)
434 434
 		if err != nil {
435
-			return "", "", utils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d while uploading metadata and error when trying to parse response body: %s", res.StatusCode, err), res)
435
+			return "", "", httputils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d while uploading metadata and error when trying to parse response body: %s", res.StatusCode, err), res)
436 436
 		}
437
-		return "", "", utils.NewHTTPRequestError(fmt.Sprintf("Received HTTP code %d while uploading layer: %q", res.StatusCode, errBody), res)
437
+		return "", "", httputils.NewHTTPRequestError(fmt.Sprintf("Received HTTP code %d while uploading layer: %q", res.StatusCode, errBody), res)
438 438
 	}
439 439
 
440 440
 	checksumPayload = "sha256:" + hex.EncodeToString(h.Sum(nil))
... ...
@@ -461,7 +460,7 @@ func (r *Session) PushRegistryTag(remote, revision, tag, registry string, token
461 461
 	}
462 462
 	res.Body.Close()
463 463
 	if res.StatusCode != 200 && res.StatusCode != 201 {
464
-		return utils.NewHTTPRequestError(fmt.Sprintf("Internal server error: %d trying to push tag %s on %s", res.StatusCode, tag, remote), res)
464
+		return httputils.NewHTTPRequestError(fmt.Sprintf("Internal server error: %d trying to push tag %s on %s", res.StatusCode, tag, remote), res)
465 465
 	}
466 466
 	return nil
467 467
 }
... ...
@@ -523,7 +522,7 @@ func (r *Session) PushImageJSONIndex(remote string, imgList []*ImgData, validate
523 523
 			if err != nil {
524 524
 				logrus.Debugf("Error reading response body: %s", err)
525 525
 			}
526
-			return nil, utils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to push repository %s: %q", res.StatusCode, remote, errBody), res)
526
+			return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to push repository %s: %q", res.StatusCode, remote, errBody), res)
527 527
 		}
528 528
 		if res.Header.Get("X-Docker-Token") != "" {
529 529
 			tokens = res.Header["X-Docker-Token"]
... ...
@@ -547,7 +546,7 @@ func (r *Session) PushImageJSONIndex(remote string, imgList []*ImgData, validate
547 547
 			if err != nil {
548 548
 				logrus.Debugf("Error reading response body: %s", err)
549 549
 			}
550
-			return nil, utils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to push checksums %s: %q", res.StatusCode, remote, errBody), res)
550
+			return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to push checksums %s: %q", res.StatusCode, remote, errBody), res)
551 551
 		}
552 552
 	}
553 553
 
... ...
@@ -595,7 +594,7 @@ func (r *Session) SearchRepositories(term string) (*SearchResults, error) {
595 595
 	}
596 596
 	defer res.Body.Close()
597 597
 	if res.StatusCode != 200 {
598
-		return nil, utils.NewHTTPRequestError(fmt.Sprintf("Unexpected status code %d", res.StatusCode), res)
598
+		return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Unexpected status code %d", res.StatusCode), res)
599 599
 	}
600 600
 	result := new(SearchResults)
601 601
 	err = json.NewDecoder(res.Body).Decode(result)
... ...
@@ -12,7 +12,7 @@ import (
12 12
 	"github.com/Sirupsen/logrus"
13 13
 	"github.com/docker/distribution/digest"
14 14
 	"github.com/docker/distribution/registry/api/v2"
15
-	"github.com/docker/docker/utils"
15
+	"github.com/docker/docker/pkg/httputils"
16 16
 )
17 17
 
18 18
 const DockerDigestHeader = "Docker-Content-Digest"
... ...
@@ -95,7 +95,7 @@ func (r *Session) GetV2ImageManifest(ep *Endpoint, imageName, tagName string, au
95 95
 		} else if res.StatusCode == 404 {
96 96
 			return nil, "", ErrDoesNotExist
97 97
 		}
98
-		return nil, "", utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to fetch for %s:%s", res.StatusCode, imageName, tagName), res)
98
+		return nil, "", httputils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to fetch for %s:%s", res.StatusCode, imageName, tagName), res)
99 99
 	}
100 100
 
101 101
 	manifestBytes, err := ioutil.ReadAll(res.Body)
... ...
@@ -141,7 +141,7 @@ func (r *Session) HeadV2ImageBlob(ep *Endpoint, imageName string, dgst digest.Di
141 141
 		return false, nil
142 142
 	}
143 143
 
144
-	return false, utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying head request for %s - %s", res.StatusCode, imageName, dgst), res)
144
+	return false, httputils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying head request for %s - %s", res.StatusCode, imageName, dgst), res)
145 145
 }
146 146
 
147 147
 func (r *Session) GetV2ImageBlob(ep *Endpoint, imageName string, dgst digest.Digest, blobWrtr io.Writer, auth *RequestAuthorization) error {
... ...
@@ -168,7 +168,7 @@ func (r *Session) GetV2ImageBlob(ep *Endpoint, imageName string, dgst digest.Dig
168 168
 		if res.StatusCode == 401 {
169 169
 			return errLoginRequired
170 170
 		}
171
-		return utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to pull %s blob", res.StatusCode, imageName), res)
171
+		return httputils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to pull %s blob", res.StatusCode, imageName), res)
172 172
 	}
173 173
 
174 174
 	_, err = io.Copy(blobWrtr, res.Body)
... ...
@@ -198,7 +198,7 @@ func (r *Session) GetV2ImageBlobReader(ep *Endpoint, imageName string, dgst dige
198 198
 		if res.StatusCode == 401 {
199 199
 			return nil, 0, errLoginRequired
200 200
 		}
201
-		return nil, 0, utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to pull %s blob - %s", res.StatusCode, imageName, dgst), res)
201
+		return nil, 0, httputils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to pull %s blob - %s", res.StatusCode, imageName, dgst), res)
202 202
 	}
203 203
 	lenStr := res.Header.Get("Content-Length")
204 204
 	l, err := strconv.ParseInt(lenStr, 10, 64)
... ...
@@ -245,7 +245,7 @@ func (r *Session) PutV2ImageBlob(ep *Endpoint, imageName string, dgst digest.Dig
245 245
 			return err
246 246
 		}
247 247
 		logrus.Debugf("Unexpected response from server: %q %#v", errBody, res.Header)
248
-		return utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to push %s blob - %s", res.StatusCode, imageName, dgst), res)
248
+		return httputils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to push %s blob - %s", res.StatusCode, imageName, dgst), res)
249 249
 	}
250 250
 
251 251
 	return nil
... ...
@@ -286,7 +286,7 @@ func (r *Session) initiateBlobUpload(ep *Endpoint, imageName string, auth *Reque
286 286
 		}
287 287
 
288 288
 		logrus.Debugf("Unexpected response from server: %q %#v", errBody, res.Header)
289
-		return "", utils.NewHTTPRequestError(fmt.Sprintf("Server error: unexpected %d response status trying to initiate upload of %s", res.StatusCode, imageName), res)
289
+		return "", httputils.NewHTTPRequestError(fmt.Sprintf("Server error: unexpected %d response status trying to initiate upload of %s", res.StatusCode, imageName), res)
290 290
 	}
291 291
 
292 292
 	if location = res.Header.Get("Location"); location == "" {
... ...
@@ -328,7 +328,7 @@ func (r *Session) PutV2ImageManifest(ep *Endpoint, imageName, tagName string, si
328 328
 			return "", err
329 329
 		}
330 330
 		logrus.Debugf("Unexpected response from server: %q %#v", errBody, res.Header)
331
-		return "", utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to push %s:%s manifest", res.StatusCode, imageName, tagName), res)
331
+		return "", httputils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to push %s:%s manifest", res.StatusCode, imageName, tagName), res)
332 332
 	}
333 333
 
334 334
 	hdrDigest, err := digest.ParseDigest(res.Header.Get(DockerDigestHeader))
... ...
@@ -384,7 +384,7 @@ func (r *Session) GetV2RemoteTags(ep *Endpoint, imageName string, auth *RequestA
384 384
 		} else if res.StatusCode == 404 {
385 385
 			return nil, ErrDoesNotExist
386 386
 		}
387
-		return nil, utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to fetch for %s", res.StatusCode, imageName), res)
387
+		return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to fetch for %s", res.StatusCode, imageName), res)
388 388
 	}
389 389
 
390 390
 	decoder := json.NewDecoder(res.Body)
... ...
@@ -6,9 +6,13 @@ import (
6 6
 	"github.com/docker/docker/engine"
7 7
 	"github.com/docker/docker/nat"
8 8
 	"github.com/docker/docker/pkg/ulimit"
9
-	"github.com/docker/docker/utils"
10 9
 )
11 10
 
11
+type KeyValuePair struct {
12
+	Key   string
13
+	Value string
14
+}
15
+
12 16
 type NetworkMode string
13 17
 
14 18
 // IsPrivate indicates whether container use it's private network stack
... ...
@@ -107,7 +111,7 @@ type LogConfig struct {
107 107
 type HostConfig struct {
108 108
 	Binds           []string
109 109
 	ContainerIDFile string
110
-	LxcConf         []utils.KeyValuePair
110
+	LxcConf         []KeyValuePair
111 111
 	Memory          int64  // Memory limit (in bytes)
112 112
 	MemorySwap      int64  // Total memory usage (memory + swap); set `-1` to disable swap
113 113
 	CpuShares       int64  // CPU shares (relative weight vs. other containers)
... ...
@@ -12,7 +12,6 @@ import (
12 12
 	"github.com/docker/docker/pkg/parsers"
13 13
 	"github.com/docker/docker/pkg/ulimit"
14 14
 	"github.com/docker/docker/pkg/units"
15
-	"github.com/docker/docker/utils"
16 15
 )
17 16
 
18 17
 var (
... ...
@@ -430,14 +429,14 @@ func parseDriverOpts(opts opts.ListOpts) (map[string][]string, error) {
430 430
 	return out, nil
431 431
 }
432 432
 
433
-func parseKeyValueOpts(opts opts.ListOpts) ([]utils.KeyValuePair, error) {
434
-	out := make([]utils.KeyValuePair, opts.Len())
433
+func parseKeyValueOpts(opts opts.ListOpts) ([]KeyValuePair, error) {
434
+	out := make([]KeyValuePair, opts.Len())
435 435
 	for i, o := range opts.GetAll() {
436 436
 		k, v, err := parsers.ParseKeyValueOpt(o)
437 437
 		if err != nil {
438 438
 			return nil, err
439 439
 		}
440
-		out[i] = utils.KeyValuePair{Key: k, Value: v}
440
+		out[i] = KeyValuePair{Key: k, Value: v}
441 441
 	}
442 442
 	return out, nil
443 443
 }
... ...
@@ -2,9 +2,7 @@ package utils
2 2
 
3 3
 import (
4 4
 	"bufio"
5
-	"bytes"
6 5
 	"crypto/sha1"
7
-	"crypto/sha256"
8 6
 	"encoding/hex"
9 7
 	"fmt"
10 8
 	"io"
... ...
@@ -13,47 +11,17 @@ import (
13 13
 	"os"
14 14
 	"os/exec"
15 15
 	"path/filepath"
16
-	"regexp"
17 16
 	"runtime"
18 17
 	"strings"
19 18
 	"sync"
20 19
 
21
-	"github.com/Sirupsen/logrus"
22 20
 	"github.com/docker/docker/autogen/dockerversion"
23 21
 	"github.com/docker/docker/pkg/archive"
24 22
 	"github.com/docker/docker/pkg/fileutils"
25 23
 	"github.com/docker/docker/pkg/ioutils"
26
-	"github.com/docker/docker/pkg/jsonmessage"
27 24
 	"github.com/docker/docker/pkg/stringid"
28 25
 )
29 26
 
30
-type KeyValuePair struct {
31
-	Key   string
32
-	Value string
33
-}
34
-
35
-var (
36
-	validHex = regexp.MustCompile(`^([a-f0-9]{64})$`)
37
-)
38
-
39
-// Request a given URL and return an io.Reader
40
-func Download(url string) (resp *http.Response, err error) {
41
-	if resp, err = http.Get(url); err != nil {
42
-		return nil, err
43
-	}
44
-	if resp.StatusCode >= 400 {
45
-		return nil, fmt.Errorf("Got HTTP status code >= 400: %s", resp.Status)
46
-	}
47
-	return resp, nil
48
-}
49
-
50
-func Trunc(s string, maxlen int) string {
51
-	if len(s) <= maxlen {
52
-		return s
53
-	}
54
-	return s[:maxlen]
55
-}
56
-
57 27
 // Figure out the absolute path of our own binary (if it's still around).
58 28
 func SelfPath() string {
59 29
 	path, err := exec.LookPath(os.Args[0])
... ...
@@ -155,74 +123,7 @@ func DockerInitPath(localCopy string) string {
155 155
 	return ""
156 156
 }
157 157
 
158
-func GetTotalUsedFds() int {
159
-	if fds, err := ioutil.ReadDir(fmt.Sprintf("/proc/%d/fd", os.Getpid())); err != nil {
160
-		logrus.Errorf("Error opening /proc/%d/fd: %s", os.Getpid(), err)
161
-	} else {
162
-		return len(fds)
163
-	}
164
-	return -1
165
-}
166
-
167
-func ValidateID(id string) error {
168
-	if ok := validHex.MatchString(id); !ok {
169
-		err := fmt.Errorf("image ID '%s' is invalid", id)
170
-		return err
171
-	}
172
-	return nil
173
-}
174
-
175
-// Code c/c from io.Copy() modified to handle escape sequence
176
-func CopyEscapable(dst io.Writer, src io.ReadCloser) (written int64, err error) {
177
-	buf := make([]byte, 32*1024)
178
-	for {
179
-		nr, er := src.Read(buf)
180
-		if nr > 0 {
181
-			// ---- Docker addition
182
-			// char 16 is C-p
183
-			if nr == 1 && buf[0] == 16 {
184
-				nr, er = src.Read(buf)
185
-				// char 17 is C-q
186
-				if nr == 1 && buf[0] == 17 {
187
-					if err := src.Close(); err != nil {
188
-						return 0, err
189
-					}
190
-					return 0, nil
191
-				}
192
-			}
193
-			// ---- End of docker
194
-			nw, ew := dst.Write(buf[0:nr])
195
-			if nw > 0 {
196
-				written += int64(nw)
197
-			}
198
-			if ew != nil {
199
-				err = ew
200
-				break
201
-			}
202
-			if nr != nw {
203
-				err = io.ErrShortWrite
204
-				break
205
-			}
206
-		}
207
-		if er == io.EOF {
208
-			break
209
-		}
210
-		if er != nil {
211
-			err = er
212
-			break
213
-		}
214
-	}
215
-	return written, err
216
-}
217
-
218
-func HashData(src io.Reader) (string, error) {
219
-	h := sha256.New()
220
-	if _, err := io.Copy(h, src); err != nil {
221
-		return "", err
222
-	}
223
-	return "sha256:" + hex.EncodeToString(h.Sum(nil)), nil
224
-}
225
-
158
+// FIXME: move to httputils? ioutils?
226 159
 type WriteFlusher struct {
227 160
 	sync.Mutex
228 161
 	w       io.Writer
... ...
@@ -254,58 +155,6 @@ func NewWriteFlusher(w io.Writer) *WriteFlusher {
254 254
 	return &WriteFlusher{w: w, flusher: flusher}
255 255
 }
256 256
 
257
-func NewHTTPRequestError(msg string, res *http.Response) error {
258
-	return &jsonmessage.JSONError{
259
-		Message: msg,
260
-		Code:    res.StatusCode,
261
-	}
262
-}
263
-
264
-// An StatusError reports an unsuccessful exit by a command.
265
-type StatusError struct {
266
-	Status     string
267
-	StatusCode int
268
-}
269
-
270
-func (e *StatusError) Error() string {
271
-	return fmt.Sprintf("Status: %s, Code: %d", e.Status, e.StatusCode)
272
-}
273
-
274
-func quote(word string, buf *bytes.Buffer) {
275
-	// Bail out early for "simple" strings
276
-	if word != "" && !strings.ContainsAny(word, "\\'\"`${[|&;<>()~*?! \t\n") {
277
-		buf.WriteString(word)
278
-		return
279
-	}
280
-
281
-	buf.WriteString("'")
282
-
283
-	for i := 0; i < len(word); i++ {
284
-		b := word[i]
285
-		if b == '\'' {
286
-			// Replace literal ' with a close ', a \', and a open '
287
-			buf.WriteString("'\\''")
288
-		} else {
289
-			buf.WriteByte(b)
290
-		}
291
-	}
292
-
293
-	buf.WriteString("'")
294
-}
295
-
296
-// Take a list of strings and escape them so they will be handled right
297
-// when passed as arguments to an program via a shell
298
-func ShellQuoteArguments(args []string) string {
299
-	var buf bytes.Buffer
300
-	for i, arg := range args {
301
-		if i != 0 {
302
-			buf.WriteByte(' ')
303
-		}
304
-		quote(arg, &buf)
305
-	}
306
-	return buf.String()
307
-}
308
-
309 257
 var globalTestID string
310 258
 
311 259
 // TestDirectory creates a new temporary directory and returns its path.
... ...
@@ -343,26 +192,6 @@ func GetCallerName(depth int) string {
343 343
 	return callerShortName
344 344
 }
345 345
 
346
-func CopyFile(src, dst string) (int64, error) {
347
-	if src == dst {
348
-		return 0, nil
349
-	}
350
-	sf, err := os.Open(src)
351
-	if err != nil {
352
-		return 0, err
353
-	}
354
-	defer sf.Close()
355
-	if err := os.Remove(dst); err != nil && !os.IsNotExist(err) {
356
-		return 0, err
357
-	}
358
-	df, err := os.Create(dst)
359
-	if err != nil {
360
-		return 0, err
361
-	}
362
-	defer df.Close()
363
-	return io.Copy(df, sf)
364
-}
365
-
366 346
 // ReplaceOrAppendValues returns the defaults with the overrides either
367 347
 // replaced by env key or appended to the list
368 348
 func ReplaceOrAppendEnvValues(defaults, overrides []string) []string {
... ...
@@ -411,27 +240,6 @@ func DoesEnvExist(name string) bool {
411 411
 	return false
412 412
 }
413 413
 
414
-// ReadSymlinkedDirectory returns the target directory of a symlink.
415
-// The target of the symbolic link may not be a file.
416
-func ReadSymlinkedDirectory(path string) (string, error) {
417
-	var realPath string
418
-	var err error
419
-	if realPath, err = filepath.Abs(path); err != nil {
420
-		return "", fmt.Errorf("unable to get absolute path for %s: %s", path, err)
421
-	}
422
-	if realPath, err = filepath.EvalSymlinks(realPath); err != nil {
423
-		return "", fmt.Errorf("failed to canonicalise path for %s: %s", path, err)
424
-	}
425
-	realPathInfo, err := os.Stat(realPath)
426
-	if err != nil {
427
-		return "", fmt.Errorf("failed to stat target '%s' of '%s': %s", realPath, path, err)
428
-	}
429
-	if !realPathInfo.Mode().IsDir() {
430
-		return "", fmt.Errorf("canonical path points to a file '%s'", realPath)
431
-	}
432
-	return realPath, nil
433
-}
434
-
435 414
 // ValidateContextDirectory checks if all the contents of the directory
436 415
 // can be read and returns an error if some files can't be read
437 416
 // symlinks which point to non-existing files don't trigger an error
... ...
@@ -476,15 +284,6 @@ func ValidateContextDirectory(srcPath string, excludes []string) error {
476 476
 	})
477 477
 }
478 478
 
479
-func StringsContainsNoCase(slice []string, s string) bool {
480
-	for _, ss := range slice {
481
-		if strings.ToLower(s) == strings.ToLower(ss) {
482
-			return true
483
-		}
484
-	}
485
-	return false
486
-}
487
-
488 479
 // Reads a .dockerignore file and returns the list of file patterns
489 480
 // to ignore. Note this will trim whitespace from each line as well
490 481
 // as use GO's "clean" func to get the shortest/cleanest path for each.
... ...
@@ -516,27 +315,6 @@ func ReadDockerIgnore(path string) ([]string, error) {
516 516
 	return excludes, nil
517 517
 }
518 518
 
519
-// Wrap a concrete io.Writer and hold a count of the number
520
-// of bytes written to the writer during a "session".
521
-// This can be convenient when write return is masked
522
-// (e.g., json.Encoder.Encode())
523
-type WriteCounter struct {
524
-	Count  int64
525
-	Writer io.Writer
526
-}
527
-
528
-func NewWriteCounter(w io.Writer) *WriteCounter {
529
-	return &WriteCounter{
530
-		Writer: w,
531
-	}
532
-}
533
-
534
-func (wc *WriteCounter) Write(p []byte) (count int, err error) {
535
-	count, err = wc.Writer.Write(p)
536
-	wc.Count += int64(count)
537
-	return
538
-}
539
-
540 519
 // ImageReference combines `repo` and `ref` and returns a string representing
541 520
 // the combination. If `ref` is a digest (meaning it's of the form
542 521
 // <algorithm>:<digest>, the returned string is <repo>@<ref>. Otherwise,
... ...
@@ -1,9 +1,10 @@
1 1
 package utils
2 2
 
3 3
 import (
4
-	"bytes"
4
+	"fmt"
5
+	"io/ioutil"
5 6
 	"os"
6
-	"strings"
7
+	"path/filepath"
7 8
 	"testing"
8 9
 )
9 10
 
... ...
@@ -25,104 +26,6 @@ func TestReplaceAndAppendEnvVars(t *testing.T) {
25 25
 	}
26 26
 }
27 27
 
28
-// Reading a symlink to a directory must return the directory
29
-func TestReadSymlinkedDirectoryExistingDirectory(t *testing.T) {
30
-	var err error
31
-	if err = os.Mkdir("/tmp/testReadSymlinkToExistingDirectory", 0777); err != nil {
32
-		t.Errorf("failed to create directory: %s", err)
33
-	}
34
-
35
-	if err = os.Symlink("/tmp/testReadSymlinkToExistingDirectory", "/tmp/dirLinkTest"); err != nil {
36
-		t.Errorf("failed to create symlink: %s", err)
37
-	}
38
-
39
-	var path string
40
-	if path, err = ReadSymlinkedDirectory("/tmp/dirLinkTest"); err != nil {
41
-		t.Fatalf("failed to read symlink to directory: %s", err)
42
-	}
43
-
44
-	if path != "/tmp/testReadSymlinkToExistingDirectory" {
45
-		t.Fatalf("symlink returned unexpected directory: %s", path)
46
-	}
47
-
48
-	if err = os.Remove("/tmp/testReadSymlinkToExistingDirectory"); err != nil {
49
-		t.Errorf("failed to remove temporary directory: %s", err)
50
-	}
51
-
52
-	if err = os.Remove("/tmp/dirLinkTest"); err != nil {
53
-		t.Errorf("failed to remove symlink: %s", err)
54
-	}
55
-}
56
-
57
-// Reading a non-existing symlink must fail
58
-func TestReadSymlinkedDirectoryNonExistingSymlink(t *testing.T) {
59
-	var path string
60
-	var err error
61
-	if path, err = ReadSymlinkedDirectory("/tmp/test/foo/Non/ExistingPath"); err == nil {
62
-		t.Fatalf("error expected for non-existing symlink")
63
-	}
64
-
65
-	if path != "" {
66
-		t.Fatalf("expected empty path, but '%s' was returned", path)
67
-	}
68
-}
69
-
70
-// Reading a symlink to a file must fail
71
-func TestReadSymlinkedDirectoryToFile(t *testing.T) {
72
-	var err error
73
-	var file *os.File
74
-
75
-	if file, err = os.Create("/tmp/testReadSymlinkToFile"); err != nil {
76
-		t.Fatalf("failed to create file: %s", err)
77
-	}
78
-
79
-	file.Close()
80
-
81
-	if err = os.Symlink("/tmp/testReadSymlinkToFile", "/tmp/fileLinkTest"); err != nil {
82
-		t.Errorf("failed to create symlink: %s", err)
83
-	}
84
-
85
-	var path string
86
-	if path, err = ReadSymlinkedDirectory("/tmp/fileLinkTest"); err == nil {
87
-		t.Fatalf("ReadSymlinkedDirectory on a symlink to a file should've failed")
88
-	}
89
-
90
-	if path != "" {
91
-		t.Fatalf("path should've been empty: %s", path)
92
-	}
93
-
94
-	if err = os.Remove("/tmp/testReadSymlinkToFile"); err != nil {
95
-		t.Errorf("failed to remove file: %s", err)
96
-	}
97
-
98
-	if err = os.Remove("/tmp/fileLinkTest"); err != nil {
99
-		t.Errorf("failed to remove symlink: %s", err)
100
-	}
101
-}
102
-
103
-func TestWriteCounter(t *testing.T) {
104
-	dummy1 := "This is a dummy string."
105
-	dummy2 := "This is another dummy string."
106
-	totalLength := int64(len(dummy1) + len(dummy2))
107
-
108
-	reader1 := strings.NewReader(dummy1)
109
-	reader2 := strings.NewReader(dummy2)
110
-
111
-	var buffer bytes.Buffer
112
-	wc := NewWriteCounter(&buffer)
113
-
114
-	reader1.WriteTo(wc)
115
-	reader2.WriteTo(wc)
116
-
117
-	if wc.Count != totalLength {
118
-		t.Errorf("Wrong count: %d vs. %d", wc.Count, totalLength)
119
-	}
120
-
121
-	if buffer.String() != dummy1+dummy2 {
122
-		t.Error("Wrong message written")
123
-	}
124
-}
125
-
126 28
 func TestImageReference(t *testing.T) {
127 29
 	tests := []struct {
128 30
 		repo     string
... ...
@@ -152,3 +55,46 @@ func TestDigestReference(t *testing.T) {
152 152
 		t.Errorf("Unexpected DigestReference=true for input %q", input)
153 153
 	}
154 154
 }
155
+
156
+func TestReadDockerIgnore(t *testing.T) {
157
+	tmpDir, err := ioutil.TempDir("", "dockerignore-test")
158
+	if err != nil {
159
+		t.Fatal(err)
160
+	}
161
+	defer os.RemoveAll(tmpDir)
162
+
163
+	diName := filepath.Join(tmpDir, ".dockerignore")
164
+
165
+	di, err := ReadDockerIgnore(diName)
166
+	if err != nil {
167
+		t.Fatalf("Expected not to have error, got %s", err)
168
+	}
169
+
170
+	if diLen := len(di); diLen != 0 {
171
+		t.Fatalf("Expected to have zero dockerignore entry, got %d", diLen)
172
+	}
173
+
174
+	content := fmt.Sprintf("test1\n/test2\n/a/file/here\n\nlastfile")
175
+	err = ioutil.WriteFile(diName, []byte(content), 0777)
176
+	if err != nil {
177
+		t.Fatal(err)
178
+	}
179
+
180
+	di, err = ReadDockerIgnore(diName)
181
+	if err != nil {
182
+		t.Fatal(err)
183
+	}
184
+
185
+	if di[0] != "test1" {
186
+		t.Fatalf("First element is not test1")
187
+	}
188
+	if di[1] != "/test2" {
189
+		t.Fatalf("Second element is not /test2")
190
+	}
191
+	if di[2] != "/a/file/here" {
192
+		t.Fatalf("Third element is not /a/file/here")
193
+	}
194
+	if di[3] != "lastfile" {
195
+		t.Fatalf("Fourth element is not lastfile")
196
+	}
197
+}