Signed-off-by: Antonio Murdaca <me@runcom.ninja>
| ... | ... |
@@ -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 |
+} |