Browse code

bump to master again

Victor Vieux authored on 2013/06/06 01:01:36
Showing 67 changed files
... ...
@@ -15,6 +15,7 @@ Brian McCallister <brianm@skife.org>
15 15
 Bruno Bigras <bigras.bruno@gmail.com>
16 16
 Caleb Spare <cespare@gmail.com>
17 17
 Charles Hooper <charles.hooper@dotcloud.com>
18
+Daniel Gasienica <daniel@gasienica.ch>
18 19
 Daniel Mizyrycki <daniel.mizyrycki@dotcloud.com>
19 20
 Daniel Robinson <gottagetmac@gmail.com>
20 21
 Daniel Von Fange <daniel@leancoder.com>
... ...
@@ -1,5 +1,19 @@
1 1
 # Changelog
2 2
 
3
+## 0.4.0 (2013-06-03)
4
+ + Introducing Builder: 'docker build' builds a container, layer by layer, from a source repository containing a Dockerfile
5
+ + Introducing Remote API: control Docker programmatically using a simple HTTP/json API
6
+ * Runtime: various reliability and usability improvements
7
+
8
+## 0.3.4 (2013-05-30)
9
+ + Builder: 'docker build' builds a container, layer by layer, from a source repository containing a Dockerfile
10
+ + Builder: 'docker build -t FOO' applies the tag FOO to the newly built container.
11
+ + Runtime: interactive TTYs correctly handle window resize
12
+ * Runtime: fix how configuration is merged between layers
13
+ + Remote API: split stdout and stderr on 'docker run'
14
+ + Remote API: optionally listen on a different IP and port (use at your own risk)
15
+ * Documentation: improved install instructions.
16
+
3 17
 ## 0.3.3 (2013-05-23)
4 18
  - Registry: Fix push regression
5 19
  - Various bugfixes
... ...
@@ -13,7 +13,7 @@ import (
13 13
 	"strings"
14 14
 )
15 15
 
16
-const API_VERSION = 1.1
16
+const APIVERSION = 1.1
17 17
 
18 18
 func hijackServer(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) {
19 19
 	conn, _, err := w.(http.Hijacker).Hijack()
... ...
@@ -45,12 +45,14 @@ func httpError(w http.ResponseWriter, err error) {
45 45
 		http.Error(w, err.Error(), http.StatusNotFound)
46 46
 	} else if strings.HasPrefix(err.Error(), "Bad parameter") {
47 47
 		http.Error(w, err.Error(), http.StatusBadRequest)
48
+	} else if strings.HasPrefix(err.Error(), "Impossible") {
49
+		http.Error(w, err.Error(), http.StatusNotAcceptable)
48 50
 	} else {
49 51
 		http.Error(w, err.Error(), http.StatusInternalServerError)
50 52
 	}
51 53
 }
52 54
 
53
-func writeJson(w http.ResponseWriter, b []byte) {
55
+func writeJSON(w http.ResponseWriter, b []byte) {
54 56
 	w.Header().Set("Content-Type", "application/json")
55 57
 	w.Write(b)
56 58
 }
... ...
@@ -80,7 +82,7 @@ func getAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Reques
80 80
 	if err != nil {
81 81
 		return err
82 82
 	}
83
-	writeJson(w, b)
83
+	writeJSON(w, b)
84 84
 	return nil
85 85
 }
86 86
 
... ...
@@ -109,11 +111,11 @@ func postAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Reque
109 109
 	}
110 110
 
111 111
 	if status != "" {
112
-		b, err := json.Marshal(&ApiAuth{Status: status})
112
+		b, err := json.Marshal(&APIAuth{Status: status})
113 113
 		if err != nil {
114 114
 			return err
115 115
 		}
116
-		writeJson(w, b)
116
+		writeJSON(w, b)
117 117
 		return nil
118 118
 	}
119 119
 	w.WriteHeader(http.StatusNoContent)
... ...
@@ -126,7 +128,7 @@ func getVersion(srv *Server, version float64, w http.ResponseWriter, r *http.Req
126 126
 	if err != nil {
127 127
 		return err
128 128
 	}
129
-	writeJson(w, b)
129
+	writeJSON(w, b)
130 130
 	return nil
131 131
 }
132 132
 
... ...
@@ -155,7 +157,7 @@ func getContainersExport(srv *Server, version float64, w http.ResponseWriter, r
155 155
 	return nil
156 156
 }
157 157
 
158
-func getImagesJson(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
158
+func getImagesJSON(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
159 159
 	if err := parseForm(r); err != nil {
160 160
 		return err
161 161
 	}
... ...
@@ -174,7 +176,7 @@ func getImagesJson(srv *Server, version float64, w http.ResponseWriter, r *http.
174 174
 	if err != nil {
175 175
 		return err
176 176
 	}
177
-	writeJson(w, b)
177
+	writeJSON(w, b)
178 178
 	return nil
179 179
 }
180 180
 
... ...
@@ -191,7 +193,7 @@ func getInfo(srv *Server, version float64, w http.ResponseWriter, r *http.Reques
191 191
 	if err != nil {
192 192
 		return err
193 193
 	}
194
-	writeJson(w, b)
194
+	writeJSON(w, b)
195 195
 	return nil
196 196
 }
197 197
 
... ...
@@ -208,7 +210,7 @@ func getImagesHistory(srv *Server, version float64, w http.ResponseWriter, r *ht
208 208
 	if err != nil {
209 209
 		return err
210 210
 	}
211
-	writeJson(w, b)
211
+	writeJSON(w, b)
212 212
 	return nil
213 213
 }
214 214
 
... ...
@@ -225,11 +227,11 @@ func getContainersChanges(srv *Server, version float64, w http.ResponseWriter, r
225 225
 	if err != nil {
226 226
 		return err
227 227
 	}
228
-	writeJson(w, b)
228
+	writeJSON(w, b)
229 229
 	return nil
230 230
 }
231 231
 
232
-func getContainersJson(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
232
+func getContainersJSON(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
233 233
 	if err := parseForm(r); err != nil {
234 234
 		return err
235 235
 	}
... ...
@@ -249,7 +251,7 @@ func getContainersJson(srv *Server, version float64, w http.ResponseWriter, r *h
249 249
 	if err != nil {
250 250
 		return err
251 251
 	}
252
-	writeJson(w, b)
252
+	writeJSON(w, b)
253 253
 	return nil
254 254
 }
255 255
 
... ...
@@ -292,12 +294,12 @@ func postCommit(srv *Server, version float64, w http.ResponseWriter, r *http.Req
292 292
 	if err != nil {
293 293
 		return err
294 294
 	}
295
-	b, err := json.Marshal(&ApiId{id})
295
+	b, err := json.Marshal(&APIID{id})
296 296
 	if err != nil {
297 297
 		return err
298 298
 	}
299 299
 	w.WriteHeader(http.StatusCreated)
300
-	writeJson(w, b)
300
+	writeJSON(w, b)
301 301
 	return nil
302 302
 }
303 303
 
... ...
@@ -312,16 +314,25 @@ func postImagesCreate(srv *Server, version float64, w http.ResponseWriter, r *ht
312 312
 	tag := r.Form.Get("tag")
313 313
 	repo := r.Form.Get("repo")
314 314
 
315
+	if version > 1.0 {
316
+		w.Header().Set("Content-Type", "application/json")
317
+	}
318
+	sf := utils.NewStreamFormatter(version > 1.0)
315 319
 	if image != "" { //pull
316 320
 		registry := r.Form.Get("registry")
317
-		if version > 1.0 {
318
-			w.Header().Set("Content-Type", "application/json")
319
-		}
320
-		if err := srv.ImagePull(image, tag, registry, w, version > 1.0); err != nil {
321
+		if err := srv.ImagePull(image, tag, registry, w, sf); err != nil {
322
+			if sf.Used() {
323
+				w.Write(sf.FormatError(err))
324
+				return nil
325
+			}
321 326
 			return err
322 327
 		}
323 328
 	} else { //import
324
-		if err := srv.ImageImport(src, repo, tag, r.Body, w); err != nil {
329
+		if err := srv.ImageImport(src, repo, tag, r.Body, w, sf); err != nil {
330
+			if sf.Used() {
331
+				w.Write(sf.FormatError(err))
332
+				return nil
333
+			}
325 334
 			return err
326 335
 		}
327 336
 	}
... ...
@@ -342,7 +353,7 @@ func getImagesSearch(srv *Server, version float64, w http.ResponseWriter, r *htt
342 342
 	if err != nil {
343 343
 		return err
344 344
 	}
345
-	writeJson(w, b)
345
+	writeJSON(w, b)
346 346
 	return nil
347 347
 }
348 348
 
... ...
@@ -357,16 +368,22 @@ func postImagesInsert(srv *Server, version float64, w http.ResponseWriter, r *ht
357 357
 		return fmt.Errorf("Missing parameter")
358 358
 	}
359 359
 	name := vars["name"]
360
-
361
-	imgId, err := srv.ImageInsert(name, url, path, w)
360
+	if version > 1.0 {
361
+		w.Header().Set("Content-Type", "application/json")
362
+	}
363
+	sf := utils.NewStreamFormatter(version > 1.0)
364
+	imgID, err := srv.ImageInsert(name, url, path, w, sf)
362 365
 	if err != nil {
363
-		return err
366
+		if sf.Used() {
367
+			w.Write(sf.FormatError(err))
368
+			return nil
369
+		}
364 370
 	}
365
-	b, err := json.Marshal(&ApiId{Id: imgId})
371
+	b, err := json.Marshal(&APIID{ID: imgID})
366 372
 	if err != nil {
367 373
 		return err
368 374
 	}
369
-	writeJson(w, b)
375
+	writeJSON(w, b)
370 376
 	return nil
371 377
 }
372 378
 
... ...
@@ -380,8 +397,15 @@ func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http
380 380
 		return fmt.Errorf("Missing parameter")
381 381
 	}
382 382
 	name := vars["name"]
383
-
384
-	if err := srv.ImagePush(name, registry, w); err != nil {
383
+	if version > 1.0 {
384
+		w.Header().Set("Content-Type", "application/json")
385
+	}
386
+	sf := utils.NewStreamFormatter(version > 1.0)
387
+	if err := srv.ImagePush(name, registry, w, sf); err != nil {
388
+		if sf.Used() {
389
+			w.Write(sf.FormatError(err))
390
+			return nil
391
+		}
385 392
 		return err
386 393
 	}
387 394
 	return nil
... ...
@@ -397,8 +421,8 @@ func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r
397 397
 		return err
398 398
 	}
399 399
 
400
-	out := &ApiRun{
401
-		Id: id,
400
+	out := &APIRun{
401
+		ID: id,
402 402
 	}
403 403
 	if config.Memory > 0 && !srv.runtime.capabilities.MemoryLimit {
404 404
 		log.Println("WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.")
... ...
@@ -413,7 +437,7 @@ func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r
413 413
 		return err
414 414
 	}
415 415
 	w.WriteHeader(http.StatusCreated)
416
-	writeJson(w, b)
416
+	writeJSON(w, b)
417 417
 	return nil
418 418
 }
419 419
 
... ...
@@ -510,11 +534,11 @@ func postContainersWait(srv *Server, version float64, w http.ResponseWriter, r *
510 510
 	if err != nil {
511 511
 		return err
512 512
 	}
513
-	b, err := json.Marshal(&ApiWait{StatusCode: status})
513
+	b, err := json.Marshal(&APIWait{StatusCode: status})
514 514
 	if err != nil {
515 515
 		return err
516 516
 	}
517
-	writeJson(w, b)
517
+	writeJSON(w, b)
518 518
 	return nil
519 519
 }
520 520
 
... ...
@@ -601,7 +625,7 @@ func getContainersByName(srv *Server, version float64, w http.ResponseWriter, r
601 601
 	if err != nil {
602 602
 		return err
603 603
 	}
604
-	writeJson(w, b)
604
+	writeJSON(w, b)
605 605
 	return nil
606 606
 }
607 607
 
... ...
@@ -619,17 +643,17 @@ func getImagesByName(srv *Server, version float64, w http.ResponseWriter, r *htt
619 619
 	if err != nil {
620 620
 		return err
621 621
 	}
622
-	writeJson(w, b)
622
+	writeJSON(w, b)
623 623
 	return nil
624 624
 }
625 625
 
626 626
 func postImagesGetCache(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
627
-	apiConfig := &ApiImageConfig{}
627
+	apiConfig := &APIImageConfig{}
628 628
 	if err := json.NewDecoder(r.Body).Decode(apiConfig); err != nil {
629 629
 		return err
630 630
 	}
631 631
 
632
-	image, err := srv.ImageGetCached(apiConfig.Id, apiConfig.Config)
632
+	image, err := srv.ImageGetCached(apiConfig.ID, apiConfig.Config)
633 633
 	if err != nil {
634 634
 		return err
635 635
 	}
... ...
@@ -637,12 +661,12 @@ func postImagesGetCache(srv *Server, version float64, w http.ResponseWriter, r *
637 637
 		w.WriteHeader(http.StatusNotFound)
638 638
 		return nil
639 639
 	}
640
-	apiId := &ApiId{Id: image.Id}
641
-	b, err := json.Marshal(apiId)
640
+	apiID := &APIID{ID: image.ID}
641
+	b, err := json.Marshal(apiID)
642 642
 	if err != nil {
643 643
 		return err
644 644
 	}
645
-	writeJson(w, b)
645
+	writeJSON(w, b)
646 646
 	return nil
647 647
 }
648 648
 
... ...
@@ -650,6 +674,13 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ
650 650
 	if err := r.ParseMultipartForm(4096); err != nil {
651 651
 		return err
652 652
 	}
653
+	remote := r.FormValue("t")
654
+	tag := ""
655
+	if strings.Contains(remote, ":") {
656
+		remoteParts := strings.Split(remote, ":")
657
+		tag = remoteParts[1]
658
+		remote = remoteParts[0]
659
+	}
653 660
 
654 661
 	dockerfile, _, err := r.FormFile("Dockerfile")
655 662
 	if err != nil {
... ...
@@ -664,8 +695,10 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ
664 664
 	}
665 665
 
666 666
 	b := NewBuildFile(srv, utils.NewWriteFlusher(w))
667
-	if _, err := b.Build(dockerfile, context); err != nil {
667
+	if id, err := b.Build(dockerfile, context); err != nil {
668 668
 		fmt.Fprintf(w, "Error build: %s\n", err)
669
+	} else if remote != "" {
670
+		srv.runtime.repositories.Set(remote, tag, id, false)
669 671
 	}
670 672
 	return nil
671 673
 }
... ...
@@ -679,13 +712,13 @@ func ListenAndServe(addr string, srv *Server, logging bool) error {
679 679
 			"/auth":                         getAuth,
680 680
 			"/version":                      getVersion,
681 681
 			"/info":                         getInfo,
682
-			"/images/json":                  getImagesJson,
682
+			"/images/json":                  getImagesJSON,
683 683
 			"/images/viz":                   getImagesViz,
684 684
 			"/images/search":                getImagesSearch,
685 685
 			"/images/{name:.*}/history":     getImagesHistory,
686 686
 			"/images/{name:.*}/json":        getImagesByName,
687
-			"/containers/ps":                getContainersJson,
688
-			"/containers/json":              getContainersJson,
687
+			"/containers/ps":                getContainersJSON,
688
+			"/containers/json":              getContainersJSON,
689 689
 			"/containers/{name:.*}/export":  getContainersExport,
690 690
 			"/containers/{name:.*}/changes": getContainersChanges,
691 691
 			"/containers/{name:.*}/json":    getContainersByName,
... ...
@@ -734,9 +767,9 @@ func ListenAndServe(addr string, srv *Server, logging bool) error {
734 734
 				}
735 735
 				version, err := strconv.ParseFloat(mux.Vars(r)["version"], 64)
736 736
 				if err != nil {
737
-					version = API_VERSION
737
+					version = APIVERSION
738 738
 				}
739
-				if version == 0 || version > API_VERSION {
739
+				if version == 0 || version > APIVERSION {
740 740
 					w.WriteHeader(http.StatusNotFound)
741 741
 					return
742 742
 				}
... ...
@@ -1,75 +1,75 @@
1 1
 package docker
2 2
 
3
-type ApiHistory struct {
4
-	Id        string
3
+type APIHistory struct {
4
+	ID        string `json:"Id"`
5 5
 	Created   int64
6
-	CreatedBy string
6
+	CreatedBy string `json:",omitempty"`
7 7
 }
8 8
 
9
-type ApiImages struct {
9
+type APIImages struct {
10 10
 	Repository string `json:",omitempty"`
11 11
 	Tag        string `json:",omitempty"`
12
-	Id         string
13
-	Created    int64 `json:",omitempty"`
12
+	ID         string `json:"Id"`
13
+	Created    int64
14 14
 	Size       int64
15 15
 	ParentSize int64
16
+
16 17
 }
17 18
 
18
-type ApiInfo struct {
19
+type APIInfo struct {
20
+	Debug       bool
19 21
 	Containers  int
20
-	Version     string
21 22
 	Images      int
22
-	Debug       bool
23
-	GoVersion   string
24
-	NFd         int `json:",omitempty"`
25
-	NGoroutines int `json:",omitempty"`
23
+	NFd         int  `json:",omitempty"`
24
+	NGoroutines int  `json:",omitempty"`
25
+	MemoryLimit bool `json:",omitempty"`
26
+	SwapLimit   bool `json:",omitempty"`
26 27
 }
27 28
 
28
-type ApiContainers struct {
29
-	Id         string
30
-	Image      string `json:",omitempty"`
31
-	Command    string `json:",omitempty"`
32
-	Created    int64  `json:",omitempty"`
33
-	Status     string `json:",omitempty"`
34
-	Ports      string `json:",omitempty"`
29
+type APIContainers struct {
30
+	ID         string `json:"Id"`
31
+	Image      string 
32
+	Command    string 
33
+	Created    int64  
34
+	Status     string 
35
+	Ports      string 
35 36
 	SizeRw     int64
36 37
 	SizeRootFs int64
37 38
 }
38 39
 
39
-type ApiSearch struct {
40
+type APISearch struct {
40 41
 	Name        string
41 42
 	Description string
42 43
 }
43 44
 
44
-type ApiId struct {
45
-	Id string
45
+type APIID struct {
46
+	ID string `json:"Id"`
46 47
 }
47 48
 
48
-type ApiRun struct {
49
-	Id       string
50
-	Warnings []string
49
+type APIRun struct {
50
+	ID       string   `json:"Id"`
51
+	Warnings []string `json:",omitempty"`
51 52
 }
52 53
 
53
-type ApiPort struct {
54
+type APIPort struct {
54 55
 	Port string
55 56
 }
56 57
 
57
-type ApiVersion struct {
58
-	Version     string
59
-	GitCommit   string
60
-	MemoryLimit bool
61
-	SwapLimit   bool
58
+type APIVersion struct {
59
+	Version   string
60
+	GitCommit string `json:",omitempty"`
61
+	GoVersion string `json:",omitempty"`
62 62
 }
63 63
 
64
-type ApiWait struct {
64
+type APIWait struct {
65 65
 	StatusCode int
66 66
 }
67 67
 
68
-type ApiAuth struct {
68
+type APIAuth struct {
69 69
 	Status string
70 70
 }
71 71
 
72
-type ApiImageConfig struct {
73
-	Id string
72
+type APIImageConfig struct {
73
+	ID string `json:"Id"`
74 74
 	*Config
75 75
 }
... ...
@@ -37,17 +37,17 @@ func TestGetAuth(t *testing.T) {
37 37
 		Email:    "utest@yopmail.com",
38 38
 	}
39 39
 
40
-	authConfigJson, err := json.Marshal(authConfig)
40
+	authConfigJSON, err := json.Marshal(authConfig)
41 41
 	if err != nil {
42 42
 		t.Fatal(err)
43 43
 	}
44 44
 
45
-	req, err := http.NewRequest("POST", "/auth", bytes.NewReader(authConfigJson))
45
+	req, err := http.NewRequest("POST", "/auth", bytes.NewReader(authConfigJSON))
46 46
 	if err != nil {
47 47
 		t.Fatal(err)
48 48
 	}
49 49
 
50
-	if err := postAuth(srv, API_VERSION, r, req, nil); err != nil {
50
+	if err := postAuth(srv, APIVERSION, r, req, nil); err != nil {
51 51
 		t.Fatal(err)
52 52
 	}
53 53
 
... ...
@@ -73,11 +73,11 @@ func TestGetVersion(t *testing.T) {
73 73
 
74 74
 	r := httptest.NewRecorder()
75 75
 
76
-	if err := getVersion(srv, API_VERSION, r, nil, nil); err != nil {
76
+	if err := getVersion(srv, APIVERSION, r, nil, nil); err != nil {
77 77
 		t.Fatal(err)
78 78
 	}
79 79
 
80
-	v := &ApiVersion{}
80
+	v := &APIVersion{}
81 81
 	if err = json.Unmarshal(r.Body.Bytes(), v); err != nil {
82 82
 		t.Fatal(err)
83 83
 	}
... ...
@@ -97,21 +97,21 @@ func TestGetInfo(t *testing.T) {
97 97
 
98 98
 	r := httptest.NewRecorder()
99 99
 
100
-	if err := getInfo(srv, API_VERSION, r, nil, nil); err != nil {
100
+	if err := getInfo(srv, APIVERSION, r, nil, nil); err != nil {
101 101
 		t.Fatal(err)
102 102
 	}
103 103
 
104
-	infos := &ApiInfo{}
104
+	infos := &APIInfo{}
105 105
 	err = json.Unmarshal(r.Body.Bytes(), infos)
106 106
 	if err != nil {
107 107
 		t.Fatal(err)
108 108
 	}
109
-	if infos.Version != VERSION {
110
-		t.Errorf("Excepted version %s, %s found", VERSION, infos.Version)
109
+	if infos.Images != 1 {
110
+		t.Errorf("Excepted images: %d, %d found", 1, infos.Images)
111 111
 	}
112 112
 }
113 113
 
114
-func TestGetImagesJson(t *testing.T) {
114
+func TestGetImagesJSON(t *testing.T) {
115 115
 	runtime, err := newTestRuntime()
116 116
 	if err != nil {
117 117
 		t.Fatal(err)
... ...
@@ -128,11 +128,11 @@ func TestGetImagesJson(t *testing.T) {
128 128
 
129 129
 	r := httptest.NewRecorder()
130 130
 
131
-	if err := getImagesJson(srv, API_VERSION, r, req, nil); err != nil {
131
+	if err := getImagesJSON(srv, APIVERSION, r, req, nil); err != nil {
132 132
 		t.Fatal(err)
133 133
 	}
134 134
 
135
-	images := []ApiImages{}
135
+	images := []APIImages{}
136 136
 	if err := json.Unmarshal(r.Body.Bytes(), &images); err != nil {
137 137
 		t.Fatal(err)
138 138
 	}
... ...
@@ -153,11 +153,11 @@ func TestGetImagesJson(t *testing.T) {
153 153
 		t.Fatal(err)
154 154
 	}
155 155
 
156
-	if err := getImagesJson(srv, API_VERSION, r2, req2, nil); err != nil {
156
+	if err := getImagesJSON(srv, APIVERSION, r2, req2, nil); err != nil {
157 157
 		t.Fatal(err)
158 158
 	}
159 159
 
160
-	images2 := []ApiImages{}
160
+	images2 := []APIImages{}
161 161
 	if err := json.Unmarshal(r2.Body.Bytes(), &images2); err != nil {
162 162
 		t.Fatal(err)
163 163
 	}
... ...
@@ -166,8 +166,8 @@ func TestGetImagesJson(t *testing.T) {
166 166
 		t.Errorf("Excepted 1 image, %d found", len(images2))
167 167
 	}
168 168
 
169
-	if images2[0].Id != GetTestImage(runtime).Id {
170
-		t.Errorf("Retrieved image Id differs, expected %s, received %s", GetTestImage(runtime).Id, images2[0].Id)
169
+	if images2[0].ID != GetTestImage(runtime).ID {
170
+		t.Errorf("Retrieved image Id differs, expected %s, received %s", GetTestImage(runtime).ID, images2[0].ID)
171 171
 	}
172 172
 
173 173
 	r3 := httptest.NewRecorder()
... ...
@@ -178,11 +178,11 @@ func TestGetImagesJson(t *testing.T) {
178 178
 		t.Fatal(err)
179 179
 	}
180 180
 
181
-	if err := getImagesJson(srv, API_VERSION, r3, req3, nil); err != nil {
181
+	if err := getImagesJSON(srv, APIVERSION, r3, req3, nil); err != nil {
182 182
 		t.Fatal(err)
183 183
 	}
184 184
 
185
-	images3 := []ApiImages{}
185
+	images3 := []APIImages{}
186 186
 	if err := json.Unmarshal(r3.Body.Bytes(), &images3); err != nil {
187 187
 		t.Fatal(err)
188 188
 	}
... ...
@@ -199,7 +199,7 @@ func TestGetImagesJson(t *testing.T) {
199 199
 		t.Fatal(err)
200 200
 	}
201 201
 
202
-	err = getImagesJson(srv, API_VERSION, r4, req4, nil)
202
+	err = getImagesJSON(srv, APIVERSION, r4, req4, nil)
203 203
 	if err == nil {
204 204
 		t.Fatalf("Error expected, received none")
205 205
 	}
... ...
@@ -220,7 +220,7 @@ func TestGetImagesViz(t *testing.T) {
220 220
 	srv := &Server{runtime: runtime}
221 221
 
222 222
 	r := httptest.NewRecorder()
223
-	if err := getImagesViz(srv, API_VERSION, r, nil, nil); err != nil {
223
+	if err := getImagesViz(srv, APIVERSION, r, nil, nil); err != nil {
224 224
 		t.Fatal(err)
225 225
 	}
226 226
 
... ...
@@ -256,11 +256,11 @@ func TestGetImagesSearch(t *testing.T) {
256 256
 		t.Fatal(err)
257 257
 	}
258 258
 
259
-	if err := getImagesSearch(srv, API_VERSION, r, req, nil); err != nil {
259
+	if err := getImagesSearch(srv, APIVERSION, r, req, nil); err != nil {
260 260
 		t.Fatal(err)
261 261
 	}
262 262
 
263
-	results := []ApiSearch{}
263
+	results := []APISearch{}
264 264
 	if err := json.Unmarshal(r.Body.Bytes(), &results); err != nil {
265 265
 		t.Fatal(err)
266 266
 	}
... ...
@@ -280,11 +280,11 @@ func TestGetImagesHistory(t *testing.T) {
280 280
 
281 281
 	r := httptest.NewRecorder()
282 282
 
283
-	if err := getImagesHistory(srv, API_VERSION, r, nil, map[string]string{"name": unitTestImageName}); err != nil {
283
+	if err := getImagesHistory(srv, APIVERSION, r, nil, map[string]string{"name": unitTestImageName}); err != nil {
284 284
 		t.Fatal(err)
285 285
 	}
286 286
 
287
-	history := []ApiHistory{}
287
+	history := []APIHistory{}
288 288
 	if err := json.Unmarshal(r.Body.Bytes(), &history); err != nil {
289 289
 		t.Fatal(err)
290 290
 	}
... ...
@@ -303,7 +303,7 @@ func TestGetImagesByName(t *testing.T) {
303 303
 	srv := &Server{runtime: runtime}
304 304
 
305 305
 	r := httptest.NewRecorder()
306
-	if err := getImagesByName(srv, API_VERSION, r, nil, map[string]string{"name": unitTestImageName}); err != nil {
306
+	if err := getImagesByName(srv, APIVERSION, r, nil, map[string]string{"name": unitTestImageName}); err != nil {
307 307
 		t.Fatal(err)
308 308
 	}
309 309
 
... ...
@@ -311,12 +311,12 @@ func TestGetImagesByName(t *testing.T) {
311 311
 	if err := json.Unmarshal(r.Body.Bytes(), img); err != nil {
312 312
 		t.Fatal(err)
313 313
 	}
314
-	if img.Id != GetTestImage(runtime).Id || img.Comment != "Imported from http://get.docker.io/images/busybox" {
314
+	if img.ID != GetTestImage(runtime).ID || img.Comment != "Imported from http://get.docker.io/images/busybox" {
315 315
 		t.Errorf("Error inspecting image")
316 316
 	}
317 317
 }
318 318
 
319
-func TestGetContainersJson(t *testing.T) {
319
+func TestGetContainersJSON(t *testing.T) {
320 320
 	runtime, err := newTestRuntime()
321 321
 	if err != nil {
322 322
 		t.Fatal(err)
... ...
@@ -326,7 +326,7 @@ func TestGetContainersJson(t *testing.T) {
326 326
 	srv := &Server{runtime: runtime}
327 327
 
328 328
 	container, err := NewBuilder(runtime).Create(&Config{
329
-		Image: GetTestImage(runtime).Id,
329
+		Image: GetTestImage(runtime).ID,
330 330
 		Cmd:   []string{"echo", "test"},
331 331
 	})
332 332
 	if err != nil {
... ...
@@ -340,18 +340,18 @@ func TestGetContainersJson(t *testing.T) {
340 340
 	}
341 341
 
342 342
 	r := httptest.NewRecorder()
343
-	if err := getContainersJson(srv, API_VERSION, r, req, nil); err != nil {
343
+	if err := getContainersJSON(srv, APIVERSION, r, req, nil); err != nil {
344 344
 		t.Fatal(err)
345 345
 	}
346
-	containers := []ApiContainers{}
346
+	containers := []APIContainers{}
347 347
 	if err := json.Unmarshal(r.Body.Bytes(), &containers); err != nil {
348 348
 		t.Fatal(err)
349 349
 	}
350 350
 	if len(containers) != 1 {
351 351
 		t.Fatalf("Excepted %d container, %d found", 1, len(containers))
352 352
 	}
353
-	if containers[0].Id != container.Id {
354
-		t.Fatalf("Container ID mismatch. Expected: %s, received: %s\n", container.Id, containers[0].Id)
353
+	if containers[0].ID != container.ID {
354
+		t.Fatalf("Container ID mismatch. Expected: %s, received: %s\n", container.ID, containers[0].ID)
355 355
 	}
356 356
 }
357 357
 
... ...
@@ -369,7 +369,7 @@ func TestGetContainersExport(t *testing.T) {
369 369
 	// Create a container and remove a file
370 370
 	container, err := builder.Create(
371 371
 		&Config{
372
-			Image: GetTestImage(runtime).Id,
372
+			Image: GetTestImage(runtime).ID,
373 373
 			Cmd:   []string{"touch", "/test"},
374 374
 		},
375 375
 	)
... ...
@@ -383,7 +383,7 @@ func TestGetContainersExport(t *testing.T) {
383 383
 	}
384 384
 
385 385
 	r := httptest.NewRecorder()
386
-	if err = getContainersExport(srv, API_VERSION, r, nil, map[string]string{"name": container.Id}); err != nil {
386
+	if err = getContainersExport(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err != nil {
387 387
 		t.Fatal(err)
388 388
 	}
389 389
 
... ...
@@ -424,7 +424,7 @@ func TestGetContainersChanges(t *testing.T) {
424 424
 	// Create a container and remove a file
425 425
 	container, err := builder.Create(
426 426
 		&Config{
427
-			Image: GetTestImage(runtime).Id,
427
+			Image: GetTestImage(runtime).ID,
428 428
 			Cmd:   []string{"/bin/rm", "/etc/passwd"},
429 429
 		},
430 430
 	)
... ...
@@ -438,7 +438,7 @@ func TestGetContainersChanges(t *testing.T) {
438 438
 	}
439 439
 
440 440
 	r := httptest.NewRecorder()
441
-	if err := getContainersChanges(srv, API_VERSION, r, nil, map[string]string{"name": container.Id}); err != nil {
441
+	if err := getContainersChanges(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err != nil {
442 442
 		t.Fatal(err)
443 443
 	}
444 444
 	changes := []Change{}
... ...
@@ -472,7 +472,7 @@ func TestGetContainersByName(t *testing.T) {
472 472
 	// Create a container and remove a file
473 473
 	container, err := builder.Create(
474 474
 		&Config{
475
-			Image: GetTestImage(runtime).Id,
475
+			Image: GetTestImage(runtime).ID,
476 476
 			Cmd:   []string{"echo", "test"},
477 477
 		},
478 478
 	)
... ...
@@ -482,15 +482,15 @@ func TestGetContainersByName(t *testing.T) {
482 482
 	defer runtime.Destroy(container)
483 483
 
484 484
 	r := httptest.NewRecorder()
485
-	if err := getContainersByName(srv, API_VERSION, r, nil, map[string]string{"name": container.Id}); err != nil {
485
+	if err := getContainersByName(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err != nil {
486 486
 		t.Fatal(err)
487 487
 	}
488 488
 	outContainer := &Container{}
489 489
 	if err := json.Unmarshal(r.Body.Bytes(), outContainer); err != nil {
490 490
 		t.Fatal(err)
491 491
 	}
492
-	if outContainer.Id != container.Id {
493
-		t.Fatalf("Wrong containers retrieved. Expected %s, recieved %s", container.Id, outContainer.Id)
492
+	if outContainer.ID != container.ID {
493
+		t.Fatalf("Wrong containers retrieved. Expected %s, recieved %s", container.ID, outContainer.ID)
494 494
 	}
495 495
 }
496 496
 
... ...
@@ -514,7 +514,7 @@ func TestPostAuth(t *testing.T) {
514 514
 	auth.SaveConfig(runtime.root, authStr, config.Email)
515 515
 
516 516
 	r := httptest.NewRecorder()
517
-	if err := getAuth(srv, API_VERSION, r, nil, nil); err != nil {
517
+	if err := getAuth(srv, APIVERSION, r, nil, nil); err != nil {
518 518
 		t.Fatal(err)
519 519
 	}
520 520
 
... ...
@@ -542,7 +542,7 @@ func TestPostCommit(t *testing.T) {
542 542
 	// Create a container and remove a file
543 543
 	container, err := builder.Create(
544 544
 		&Config{
545
-			Image: GetTestImage(runtime).Id,
545
+			Image: GetTestImage(runtime).ID,
546 546
 			Cmd:   []string{"touch", "/test"},
547 547
 		},
548 548
 	)
... ...
@@ -555,24 +555,24 @@ func TestPostCommit(t *testing.T) {
555 555
 		t.Fatal(err)
556 556
 	}
557 557
 
558
-	req, err := http.NewRequest("POST", "/commit?repo=testrepo&testtag=tag&container="+container.Id, bytes.NewReader([]byte{}))
558
+	req, err := http.NewRequest("POST", "/commit?repo=testrepo&testtag=tag&container="+container.ID, bytes.NewReader([]byte{}))
559 559
 	if err != nil {
560 560
 		t.Fatal(err)
561 561
 	}
562 562
 
563 563
 	r := httptest.NewRecorder()
564
-	if err := postCommit(srv, API_VERSION, r, req, nil); err != nil {
564
+	if err := postCommit(srv, APIVERSION, r, req, nil); err != nil {
565 565
 		t.Fatal(err)
566 566
 	}
567 567
 	if r.Code != http.StatusCreated {
568 568
 		t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
569 569
 	}
570 570
 
571
-	apiId := &ApiId{}
572
-	if err := json.Unmarshal(r.Body.Bytes(), apiId); err != nil {
571
+	apiID := &APIID{}
572
+	if err := json.Unmarshal(r.Body.Bytes(), apiID); err != nil {
573 573
 		t.Fatal(err)
574 574
 	}
575
-	if _, err := runtime.graph.Get(apiId.Id); err != nil {
575
+	if _, err := runtime.graph.Get(apiID.ID); err != nil {
576 576
 		t.Fatalf("The image has not been commited")
577 577
 	}
578 578
 }
... ...
@@ -715,7 +715,7 @@ func TestPostImagesInsert(t *testing.T) {
715 715
 	// 	t.Fatalf("The test file has not been found")
716 716
 	// }
717 717
 
718
-	// if err := srv.runtime.graph.Delete(img.Id); err != nil {
718
+	// if err := srv.runtime.graph.Delete(img.ID); err != nil {
719 719
 	// 	t.Fatal(err)
720 720
 	// }
721 721
 }
... ...
@@ -824,8 +824,8 @@ func TestPostContainersCreate(t *testing.T) {
824 824
 
825 825
 	srv := &Server{runtime: runtime}
826 826
 
827
-	configJson, err := json.Marshal(&Config{
828
-		Image:  GetTestImage(runtime).Id,
827
+	configJSON, err := json.Marshal(&Config{
828
+		Image:  GetTestImage(runtime).ID,
829 829
 		Memory: 33554432,
830 830
 		Cmd:    []string{"touch", "/test"},
831 831
 	})
... ...
@@ -833,25 +833,25 @@ func TestPostContainersCreate(t *testing.T) {
833 833
 		t.Fatal(err)
834 834
 	}
835 835
 
836
-	req, err := http.NewRequest("POST", "/containers/create", bytes.NewReader(configJson))
836
+	req, err := http.NewRequest("POST", "/containers/create", bytes.NewReader(configJSON))
837 837
 	if err != nil {
838 838
 		t.Fatal(err)
839 839
 	}
840 840
 
841 841
 	r := httptest.NewRecorder()
842
-	if err := postContainersCreate(srv, API_VERSION, r, req, nil); err != nil {
842
+	if err := postContainersCreate(srv, APIVERSION, r, req, nil); err != nil {
843 843
 		t.Fatal(err)
844 844
 	}
845 845
 	if r.Code != http.StatusCreated {
846 846
 		t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
847 847
 	}
848 848
 
849
-	apiRun := &ApiRun{}
849
+	apiRun := &APIRun{}
850 850
 	if err := json.Unmarshal(r.Body.Bytes(), apiRun); err != nil {
851 851
 		t.Fatal(err)
852 852
 	}
853 853
 
854
-	container := srv.runtime.Get(apiRun.Id)
854
+	container := srv.runtime.Get(apiRun.ID)
855 855
 	if container == nil {
856 856
 		t.Fatalf("Container not created")
857 857
 	}
... ...
@@ -880,7 +880,7 @@ func TestPostContainersKill(t *testing.T) {
880 880
 
881 881
 	container, err := NewBuilder(runtime).Create(
882 882
 		&Config{
883
-			Image:     GetTestImage(runtime).Id,
883
+			Image:     GetTestImage(runtime).ID,
884 884
 			Cmd:       []string{"/bin/cat"},
885 885
 			OpenStdin: true,
886 886
 		},
... ...
@@ -902,7 +902,7 @@ func TestPostContainersKill(t *testing.T) {
902 902
 	}
903 903
 
904 904
 	r := httptest.NewRecorder()
905
-	if err := postContainersKill(srv, API_VERSION, r, nil, map[string]string{"name": container.Id}); err != nil {
905
+	if err := postContainersKill(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err != nil {
906 906
 		t.Fatal(err)
907 907
 	}
908 908
 	if r.Code != http.StatusNoContent {
... ...
@@ -924,7 +924,7 @@ func TestPostContainersRestart(t *testing.T) {
924 924
 
925 925
 	container, err := NewBuilder(runtime).Create(
926 926
 		&Config{
927
-			Image:     GetTestImage(runtime).Id,
927
+			Image:     GetTestImage(runtime).ID,
928 928
 			Cmd:       []string{"/bin/cat"},
929 929
 			OpenStdin: true,
930 930
 		},
... ...
@@ -945,12 +945,12 @@ func TestPostContainersRestart(t *testing.T) {
945 945
 		t.Errorf("Container should be running")
946 946
 	}
947 947
 
948
-	req, err := http.NewRequest("POST", "/containers/"+container.Id+"/restart?t=1", bytes.NewReader([]byte{}))
948
+	req, err := http.NewRequest("POST", "/containers/"+container.ID+"/restart?t=1", bytes.NewReader([]byte{}))
949 949
 	if err != nil {
950 950
 		t.Fatal(err)
951 951
 	}
952 952
 	r := httptest.NewRecorder()
953
-	if err := postContainersRestart(srv, API_VERSION, r, req, map[string]string{"name": container.Id}); err != nil {
953
+	if err := postContainersRestart(srv, APIVERSION, r, req, map[string]string{"name": container.ID}); err != nil {
954 954
 		t.Fatal(err)
955 955
 	}
956 956
 	if r.Code != http.StatusNoContent {
... ...
@@ -980,7 +980,7 @@ func TestPostContainersStart(t *testing.T) {
980 980
 
981 981
 	container, err := NewBuilder(runtime).Create(
982 982
 		&Config{
983
-			Image:     GetTestImage(runtime).Id,
983
+			Image:     GetTestImage(runtime).ID,
984 984
 			Cmd:       []string{"/bin/cat"},
985 985
 			OpenStdin: true,
986 986
 		},
... ...
@@ -991,7 +991,7 @@ func TestPostContainersStart(t *testing.T) {
991 991
 	defer runtime.Destroy(container)
992 992
 
993 993
 	r := httptest.NewRecorder()
994
-	if err := postContainersStart(srv, API_VERSION, r, nil, map[string]string{"name": container.Id}); err != nil {
994
+	if err := postContainersStart(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err != nil {
995 995
 		t.Fatal(err)
996 996
 	}
997 997
 	if r.Code != http.StatusNoContent {
... ...
@@ -1006,7 +1006,7 @@ func TestPostContainersStart(t *testing.T) {
1006 1006
 	}
1007 1007
 
1008 1008
 	r = httptest.NewRecorder()
1009
-	if err = postContainersStart(srv, API_VERSION, r, nil, map[string]string{"name": container.Id}); err == nil {
1009
+	if err = postContainersStart(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err == nil {
1010 1010
 		t.Fatalf("A running containter should be able to be started")
1011 1011
 	}
1012 1012
 
... ...
@@ -1026,7 +1026,7 @@ func TestPostContainersStop(t *testing.T) {
1026 1026
 
1027 1027
 	container, err := NewBuilder(runtime).Create(
1028 1028
 		&Config{
1029
-			Image:     GetTestImage(runtime).Id,
1029
+			Image:     GetTestImage(runtime).ID,
1030 1030
 			Cmd:       []string{"/bin/cat"},
1031 1031
 			OpenStdin: true,
1032 1032
 		},
... ...
@@ -1048,12 +1048,12 @@ func TestPostContainersStop(t *testing.T) {
1048 1048
 	}
1049 1049
 
1050 1050
 	// Note: as it is a POST request, it requires a body.
1051
-	req, err := http.NewRequest("POST", "/containers/"+container.Id+"/stop?t=1", bytes.NewReader([]byte{}))
1051
+	req, err := http.NewRequest("POST", "/containers/"+container.ID+"/stop?t=1", bytes.NewReader([]byte{}))
1052 1052
 	if err != nil {
1053 1053
 		t.Fatal(err)
1054 1054
 	}
1055 1055
 	r := httptest.NewRecorder()
1056
-	if err := postContainersStop(srv, API_VERSION, r, req, map[string]string{"name": container.Id}); err != nil {
1056
+	if err := postContainersStop(srv, APIVERSION, r, req, map[string]string{"name": container.ID}); err != nil {
1057 1057
 		t.Fatal(err)
1058 1058
 	}
1059 1059
 	if r.Code != http.StatusNoContent {
... ...
@@ -1075,7 +1075,7 @@ func TestPostContainersWait(t *testing.T) {
1075 1075
 
1076 1076
 	container, err := NewBuilder(runtime).Create(
1077 1077
 		&Config{
1078
-			Image:     GetTestImage(runtime).Id,
1078
+			Image:     GetTestImage(runtime).ID,
1079 1079
 			Cmd:       []string{"/bin/sleep", "1"},
1080 1080
 			OpenStdin: true,
1081 1081
 		},
... ...
@@ -1091,10 +1091,10 @@ func TestPostContainersWait(t *testing.T) {
1091 1091
 
1092 1092
 	setTimeout(t, "Wait timed out", 3*time.Second, func() {
1093 1093
 		r := httptest.NewRecorder()
1094
-		if err := postContainersWait(srv, API_VERSION, r, nil, map[string]string{"name": container.Id}); err != nil {
1094
+		if err := postContainersWait(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err != nil {
1095 1095
 			t.Fatal(err)
1096 1096
 		}
1097
-		apiWait := &ApiWait{}
1097
+		apiWait := &APIWait{}
1098 1098
 		if err := json.Unmarshal(r.Body.Bytes(), apiWait); err != nil {
1099 1099
 			t.Fatal(err)
1100 1100
 		}
... ...
@@ -1119,7 +1119,7 @@ func TestPostContainersAttach(t *testing.T) {
1119 1119
 
1120 1120
 	container, err := NewBuilder(runtime).Create(
1121 1121
 		&Config{
1122
-			Image:     GetTestImage(runtime).Id,
1122
+			Image:     GetTestImage(runtime).ID,
1123 1123
 			Cmd:       []string{"/bin/cat"},
1124 1124
 			OpenStdin: true,
1125 1125
 		},
... ...
@@ -1148,12 +1148,12 @@ func TestPostContainersAttach(t *testing.T) {
1148 1148
 			out:              stdoutPipe,
1149 1149
 		}
1150 1150
 
1151
-		req, err := http.NewRequest("POST", "/containers/"+container.Id+"/attach?stream=1&stdin=1&stdout=1&stderr=1", bytes.NewReader([]byte{}))
1151
+		req, err := http.NewRequest("POST", "/containers/"+container.ID+"/attach?stream=1&stdin=1&stdout=1&stderr=1", bytes.NewReader([]byte{}))
1152 1152
 		if err != nil {
1153 1153
 			t.Fatal(err)
1154 1154
 		}
1155 1155
 
1156
-		if err := postContainersAttach(srv, API_VERSION, r, req, map[string]string{"name": container.Id}); err != nil {
1156
+		if err := postContainersAttach(srv, APIVERSION, r, req, map[string]string{"name": container.ID}); err != nil {
1157 1157
 			t.Fatal(err)
1158 1158
 		}
1159 1159
 	}()
... ...
@@ -1206,7 +1206,7 @@ func TestDeleteContainers(t *testing.T) {
1206 1206
 	srv := &Server{runtime: runtime}
1207 1207
 
1208 1208
 	container, err := NewBuilder(runtime).Create(&Config{
1209
-		Image: GetTestImage(runtime).Id,
1209
+		Image: GetTestImage(runtime).ID,
1210 1210
 		Cmd:   []string{"touch", "/test"},
1211 1211
 	})
1212 1212
 	if err != nil {
... ...
@@ -1218,19 +1218,19 @@ func TestDeleteContainers(t *testing.T) {
1218 1218
 		t.Fatal(err)
1219 1219
 	}
1220 1220
 
1221
-	req, err := http.NewRequest("DELETE", "/containers/"+container.Id, nil)
1221
+	req, err := http.NewRequest("DELETE", "/containers/"+container.ID, nil)
1222 1222
 	if err != nil {
1223 1223
 		t.Fatal(err)
1224 1224
 	}
1225 1225
 	r := httptest.NewRecorder()
1226
-	if err := deleteContainers(srv, API_VERSION, r, req, map[string]string{"name": container.Id}); err != nil {
1226
+	if err := deleteContainers(srv, APIVERSION, r, req, map[string]string{"name": container.ID}); err != nil {
1227 1227
 		t.Fatal(err)
1228 1228
 	}
1229 1229
 	if r.Code != http.StatusNoContent {
1230 1230
 		t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
1231 1231
 	}
1232 1232
 
1233
-	if c := runtime.Get(container.Id); c != nil {
1233
+	if c := runtime.Get(container.ID); c != nil {
1234 1234
 		t.Fatalf("The container as not been deleted")
1235 1235
 	}
1236 1236
 
... ...
@@ -54,6 +54,9 @@ func Tar(path string, compression Compression) (io.Reader, error) {
54 54
 func Untar(archive io.Reader, path string) error {
55 55
 	cmd := exec.Command("bsdtar", "-f", "-", "-C", path, "-x")
56 56
 	cmd.Stdin = archive
57
+	// Hardcode locale environment for predictable outcome regardless of host configuration.
58
+	//   (see https://github.com/dotcloud/docker/issues/355)
59
+	cmd.Env = []string{"LANG=en_US.utf-8", "LC_ALL=en_US.utf-8"}
57 60
 	output, err := cmd.CombinedOutput()
58 61
 	if err != nil {
59 62
 		return fmt.Errorf("%s: %s", err, output)
... ...
@@ -16,12 +16,12 @@ import (
16 16
 const CONFIGFILE = ".dockercfg"
17 17
 
18 18
 // the registry server we want to login against
19
-const INDEX_SERVER = "https://index.docker.io/v1"
19
+const INDEXSERVER = "https://index.docker.io/v1"
20 20
 
21
-//const INDEX_SERVER = "http://indexstaging-docker.dotcloud.com/"
21
+//const INDEXSERVER = "http://indexstaging-docker.dotcloud.com/"
22 22
 
23 23
 var (
24
-	ErrConfigFileMissing error = errors.New("The Auth config file is missing")
24
+	ErrConfigFileMissing = errors.New("The Auth config file is missing")
25 25
 )
26 26
 
27 27
 type AuthConfig struct {
... ...
@@ -44,7 +44,7 @@ func IndexServerAddress() string {
44 44
 	if os.Getenv("DOCKER_INDEX_URL") != "" {
45 45
 		return os.Getenv("DOCKER_INDEX_URL") + "/v1"
46 46
 	}
47
-	return INDEX_SERVER
47
+	return INDEXSERVER
48 48
 }
49 49
 
50 50
 // create a base64 encoded auth string to store in config
... ...
@@ -40,7 +40,7 @@ func (builder *Builder) Create(config *Config) (*Container, error) {
40 40
 	}
41 41
 
42 42
 	// Generate id
43
-	id := GenerateId()
43
+	id := GenerateID()
44 44
 	// Generate default hostname
45 45
 	// FIXME: the lxc template no longer needs to set a default hostname
46 46
 	if config.Hostname == "" {
... ...
@@ -49,17 +49,17 @@ func (builder *Builder) Create(config *Config) (*Container, error) {
49 49
 
50 50
 	container := &Container{
51 51
 		// FIXME: we should generate the ID here instead of receiving it as an argument
52
-		Id:              id,
52
+		ID:              id,
53 53
 		Created:         time.Now(),
54 54
 		Path:            config.Cmd[0],
55 55
 		Args:            config.Cmd[1:], //FIXME: de-duplicate from config
56 56
 		Config:          config,
57
-		Image:           img.Id, // Always use the resolved image id
57
+		Image:           img.ID, // Always use the resolved image id
58 58
 		NetworkSettings: &NetworkSettings{},
59 59
 		// FIXME: do we need to store this in the container?
60 60
 		SysInitPath: sysInitPath,
61 61
 	}
62
-	container.root = builder.runtime.containerRoot(container.Id)
62
+	container.root = builder.runtime.containerRoot(container.ID)
63 63
 	// Step 1: create the container directory.
64 64
 	// This doubles as a barrier to avoid race conditions.
65 65
 	if err := os.Mkdir(container.root, 0700); err != nil {
... ...
@@ -110,7 +110,7 @@ func (builder *Builder) Commit(container *Container, repository, tag, comment, a
110 110
 	}
111 111
 	// Register the image if needed
112 112
 	if repository != "" {
113
-		if err := builder.repositories.Set(repository, tag, img.Id, true); err != nil {
113
+		if err := builder.repositories.Set(repository, tag, img.ID, true); err != nil {
114 114
 			return img, err
115 115
 		}
116 116
 	}
... ...
@@ -63,11 +63,11 @@ func (b *builderClient) CmdFrom(name string) error {
63 63
 		return err
64 64
 	}
65 65
 
66
-	img := &ApiId{}
66
+	img := &APIID{}
67 67
 	if err := json.Unmarshal(obj, img); err != nil {
68 68
 		return err
69 69
 	}
70
-	b.image = img.Id
70
+	b.image = img.ID
71 71
 	utils.Debugf("Using image %s", b.image)
72 72
 	return nil
73 73
 }
... ...
@@ -91,19 +91,19 @@ func (b *builderClient) CmdRun(args string) error {
91 91
 	b.config.Cmd = nil
92 92
 	MergeConfig(b.config, config)
93 93
 
94
-	body, statusCode, err := b.cli.call("POST", "/images/getCache", &ApiImageConfig{Id: b.image, Config: b.config})
94
+	body, statusCode, err := b.cli.call("POST", "/images/getCache", &APIImageConfig{ID: b.image, Config: b.config})
95 95
 	if err != nil {
96 96
 		if statusCode != 404 {
97 97
 			return err
98 98
 		}
99 99
 	}
100 100
 	if statusCode != 404 {
101
-		apiId := &ApiId{}
102
-		if err := json.Unmarshal(body, apiId); err != nil {
101
+		apiID := &APIID{}
102
+		if err := json.Unmarshal(body, apiID); err != nil {
103 103
 			return err
104 104
 		}
105 105
 		utils.Debugf("Use cached version")
106
-		b.image = apiId.Id
106
+		b.image = apiID.ID
107 107
 		return nil
108 108
 	}
109 109
 	cid, err := b.run()
... ...
@@ -163,7 +163,7 @@ func (b *builderClient) CmdInsert(args string) error {
163 163
 	// 	return err
164 164
 	// }
165 165
 
166
-	// apiId := &ApiId{}
166
+	// apiId := &APIId{}
167 167
 	// if err := json.Unmarshal(body, apiId); err != nil {
168 168
 	// 	return err
169 169
 	// }
... ...
@@ -182,7 +182,7 @@ func (b *builderClient) run() (string, error) {
182 182
 		return "", err
183 183
 	}
184 184
 
185
-	apiRun := &ApiRun{}
185
+	apiRun := &APIRun{}
186 186
 	if err := json.Unmarshal(body, apiRun); err != nil {
187 187
 		return "", err
188 188
 	}
... ...
@@ -191,18 +191,18 @@ func (b *builderClient) run() (string, error) {
191 191
 	}
192 192
 
193 193
 	//start the container
194
-	_, _, err = b.cli.call("POST", "/containers/"+apiRun.Id+"/start", nil)
194
+	_, _, err = b.cli.call("POST", "/containers/"+apiRun.ID+"/start", nil)
195 195
 	if err != nil {
196 196
 		return "", err
197 197
 	}
198
-	b.tmpContainers[apiRun.Id] = struct{}{}
198
+	b.tmpContainers[apiRun.ID] = struct{}{}
199 199
 
200 200
 	// Wait for it to finish
201
-	body, _, err = b.cli.call("POST", "/containers/"+apiRun.Id+"/wait", nil)
201
+	body, _, err = b.cli.call("POST", "/containers/"+apiRun.ID+"/wait", nil)
202 202
 	if err != nil {
203 203
 		return "", err
204 204
 	}
205
-	apiWait := &ApiWait{}
205
+	apiWait := &APIWait{}
206 206
 	if err := json.Unmarshal(body, apiWait); err != nil {
207 207
 		return "", err
208 208
 	}
... ...
@@ -210,7 +210,7 @@ func (b *builderClient) run() (string, error) {
210 210
 		return "", fmt.Errorf("The command %v returned a non-zero code: %d", b.config.Cmd, apiWait.StatusCode)
211 211
 	}
212 212
 
213
-	return apiRun.Id, nil
213
+	return apiRun.ID, nil
214 214
 }
215 215
 
216 216
 func (b *builderClient) commit(id string) error {
... ...
@@ -222,11 +222,11 @@ func (b *builderClient) commit(id string) error {
222 222
 	if id == "" {
223 223
 		cmd := b.config.Cmd
224 224
 		b.config.Cmd = []string{"true"}
225
-		if cid, err := b.run(); err != nil {
225
+		cid, err := b.run()
226
+		if err != nil {
226 227
 			return err
227
-		} else {
228
-			id = cid
229 228
 		}
229
+		id = cid
230 230
 		b.config.Cmd = cmd
231 231
 	}
232 232
 
... ...
@@ -239,12 +239,12 @@ func (b *builderClient) commit(id string) error {
239 239
 	if err != nil {
240 240
 		return err
241 241
 	}
242
-	apiId := &ApiId{}
243
-	if err := json.Unmarshal(body, apiId); err != nil {
242
+	apiID := &APIID{}
243
+	if err := json.Unmarshal(body, apiID); err != nil {
244 244
 		return err
245 245
 	}
246
-	b.tmpImages[apiId.Id] = struct{}{}
247
-	b.image = apiId.Id
246
+	b.tmpImages[apiID.ID] = struct{}{}
247
+	b.image = apiID.ID
248 248
 	b.needCommit = false
249 249
 	return nil
250 250
 }
... ...
@@ -32,8 +32,6 @@ type buildFile struct {
32 32
 	tmpContainers map[string]struct{}
33 33
 	tmpImages     map[string]struct{}
34 34
 
35
-	needCommit bool
36
-
37 35
 	out io.Writer
38 36
 }
39 37
 
... ...
@@ -63,7 +61,7 @@ func (b *buildFile) CmdFrom(name string) error {
63 63
 				remote = name
64 64
 			}
65 65
 
66
-			if err := b.srv.ImagePull(remote, tag, "", b.out, false); err != nil {
66
+			if err := b.srv.ImagePull(remote, tag, "", b.out, utils.NewStreamFormatter(false)); err != nil {
67 67
 				return err
68 68
 			}
69 69
 
... ...
@@ -75,15 +73,14 @@ func (b *buildFile) CmdFrom(name string) error {
75 75
 			return err
76 76
 		}
77 77
 	}
78
-	b.image = image.Id
78
+	b.image = image.ID
79 79
 	b.config = &Config{}
80 80
 	return nil
81 81
 }
82 82
 
83 83
 func (b *buildFile) CmdMaintainer(name string) error {
84
-	b.needCommit = true
85 84
 	b.maintainer = name
86
-	return nil
85
+	return b.commit("", b.config.Cmd, fmt.Sprintf("MAINTAINER %s", name))
87 86
 }
88 87
 
89 88
 func (b *buildFile) CmdRun(args string) error {
... ...
@@ -95,28 +92,34 @@ func (b *buildFile) CmdRun(args string) error {
95 95
 		return err
96 96
 	}
97 97
 
98
-	cmd, env := b.config.Cmd, b.config.Env
98
+	cmd := b.config.Cmd
99 99
 	b.config.Cmd = nil
100 100
 	MergeConfig(b.config, config)
101 101
 
102
-	if cache, err := b.srv.ImageGetCached(b.image, config); err != nil {
102
+	utils.Debugf("Command to be executed: %v", b.config.Cmd)
103
+
104
+	if cache, err := b.srv.ImageGetCached(b.image, b.config); err != nil {
103 105
 		return err
104 106
 	} else if cache != nil {
105
-		utils.Debugf("Use cached version")
106
-		b.image = cache.Id
107
+		utils.Debugf("[BUILDER] Use cached version")
108
+		b.image = cache.ID
107 109
 		return nil
110
+	} else {
111
+		utils.Debugf("[BUILDER] Cache miss")
108 112
 	}
109 113
 
110 114
 	cid, err := b.run()
111 115
 	if err != nil {
112 116
 		return err
113 117
 	}
114
-	b.config.Cmd, b.config.Env = cmd, env
115
-	return b.commit(cid)
118
+	if err := b.commit(cid, cmd, "run"); err != nil {
119
+		return err
120
+	}
121
+	b.config.Cmd = cmd
122
+	return nil
116 123
 }
117 124
 
118 125
 func (b *buildFile) CmdEnv(args string) error {
119
-	b.needCommit = true
120 126
 	tmp := strings.SplitN(args, " ", 2)
121 127
 	if len(tmp) != 2 {
122 128
 		return fmt.Errorf("Invalid ENV format")
... ...
@@ -131,60 +134,34 @@ func (b *buildFile) CmdEnv(args string) error {
131 131
 		}
132 132
 	}
133 133
 	b.config.Env = append(b.config.Env, key+"="+value)
134
-	return nil
134
+	return b.commit("", b.config.Cmd, fmt.Sprintf("ENV %s=%s", key, value))
135 135
 }
136 136
 
137 137
 func (b *buildFile) CmdCmd(args string) error {
138
-	b.needCommit = true
139 138
 	var cmd []string
140 139
 	if err := json.Unmarshal([]byte(args), &cmd); err != nil {
141 140
 		utils.Debugf("Error unmarshalling: %s, using /bin/sh -c", err)
142
-		b.config.Cmd = []string{"/bin/sh", "-c", args}
143
-	} else {
144
-		b.config.Cmd = cmd
141
+		cmd = []string{"/bin/sh", "-c", args}
142
+	}
143
+	if err := b.commit("", cmd, fmt.Sprintf("CMD %v", cmd)); err != nil {
144
+		return err
145 145
 	}
146
+	b.config.Cmd = cmd
146 147
 	return nil
147 148
 }
148 149
 
149 150
 func (b *buildFile) CmdExpose(args string) error {
150 151
 	ports := strings.Split(args, " ")
151 152
 	b.config.PortSpecs = append(ports, b.config.PortSpecs...)
152
-	return nil
153
+	return b.commit("", b.config.Cmd, fmt.Sprintf("EXPOSE %v", ports))
153 154
 }
154 155
 
155 156
 func (b *buildFile) CmdInsert(args string) error {
156
-	if b.image == "" {
157
-		return fmt.Errorf("Please provide a source image with `from` prior to insert")
158
-	}
159
-	tmp := strings.SplitN(args, " ", 2)
160
-	if len(tmp) != 2 {
161
-		return fmt.Errorf("Invalid INSERT format")
162
-	}
163
-	sourceUrl := strings.Trim(tmp[0], " ")
164
-	destPath := strings.Trim(tmp[1], " ")
165
-
166
-	file, err := utils.Download(sourceUrl, b.out)
167
-	if err != nil {
168
-		return err
169
-	}
170
-	defer file.Body.Close()
171
-
172
-	b.config.Cmd = []string{"echo", "INSERT", sourceUrl, "in", destPath}
173
-	cid, err := b.run()
174
-	if err != nil {
175
-		return err
176
-	}
177
-
178
-	container := b.runtime.Get(cid)
179
-	if container == nil {
180
-		return fmt.Errorf("An error occured while creating the container")
181
-	}
182
-
183
-	if err := container.Inject(file.Body, destPath); err != nil {
184
-		return err
185
-	}
157
+	return fmt.Errorf("INSERT has been deprecated. Please use ADD instead")
158
+}
186 159
 
187
-	return b.commit(cid)
160
+func (b *buildFile) CmdCopy(args string) error {
161
+	return fmt.Errorf("COPY has been deprecated. Please use ADD instead")
188 162
 }
189 163
 
190 164
 func (b *buildFile) CmdAdd(args string) error {
... ...
@@ -193,12 +170,13 @@ func (b *buildFile) CmdAdd(args string) error {
193 193
 	}
194 194
 	tmp := strings.SplitN(args, " ", 2)
195 195
 	if len(tmp) != 2 {
196
-		return fmt.Errorf("Invalid INSERT format")
196
+		return fmt.Errorf("Invalid ADD format")
197 197
 	}
198 198
 	orig := strings.Trim(tmp[0], " ")
199 199
 	dest := strings.Trim(tmp[1], " ")
200 200
 
201
-	b.config.Cmd = []string{"echo", "PUSH", orig, "in", dest}
201
+	cmd := b.config.Cmd
202
+	b.config.Cmd = []string{"/bin/sh", "-c", fmt.Sprintf("#(nop) ADD %s in %s", orig, dest)}
202 203
 	cid, err := b.run()
203 204
 	if err != nil {
204 205
 		return err
... ...
@@ -208,19 +186,23 @@ func (b *buildFile) CmdAdd(args string) error {
208 208
 	if container == nil {
209 209
 		return fmt.Errorf("Error while creating the container (CmdAdd)")
210 210
 	}
211
-
212
-	if err := os.MkdirAll(path.Join(container.rwPath(), dest), 0700); err != nil {
211
+	if err := container.EnsureMounted(); err != nil {
213 212
 		return err
214 213
 	}
214
+	defer container.Unmount()
215 215
 
216 216
 	origPath := path.Join(b.context, orig)
217
-	destPath := path.Join(container.rwPath(), dest)
217
+	destPath := path.Join(container.RootfsPath(), dest)
218 218
 
219 219
 	fi, err := os.Stat(origPath)
220 220
 	if err != nil {
221 221
 		return err
222 222
 	}
223 223
 	if fi.IsDir() {
224
+		if err := os.MkdirAll(destPath, 0700); err != nil {
225
+			return err
226
+		}
227
+
224 228
 		files, err := ioutil.ReadDir(path.Join(b.context, orig))
225 229
 		if err != nil {
226 230
 			return err
... ...
@@ -231,12 +213,18 @@ func (b *buildFile) CmdAdd(args string) error {
231 231
 			}
232 232
 		}
233 233
 	} else {
234
+		if err := os.MkdirAll(path.Dir(destPath), 0700); err != nil {
235
+			return err
236
+		}
234 237
 		if err := utils.CopyDirectory(origPath, destPath); err != nil {
235 238
 			return err
236 239
 		}
237 240
 	}
238
-
239
-	return b.commit(cid)
241
+	if err := b.commit(cid, cmd, fmt.Sprintf("ADD %s in %s", orig, dest)); err != nil {
242
+		return err
243
+	}
244
+	b.config.Cmd = cmd
245
+	return nil
240 246
 }
241 247
 
242 248
 func (b *buildFile) run() (string, error) {
... ...
@@ -250,7 +238,7 @@ func (b *buildFile) run() (string, error) {
250 250
 	if err != nil {
251 251
 		return "", err
252 252
 	}
253
-	b.tmpContainers[c.Id] = struct{}{}
253
+	b.tmpContainers[c.ID] = struct{}{}
254 254
 
255 255
 	//start the container
256 256
 	if err := c.Start(); err != nil {
... ...
@@ -262,23 +250,33 @@ func (b *buildFile) run() (string, error) {
262 262
 		return "", fmt.Errorf("The command %v returned a non-zero code: %d", b.config.Cmd, ret)
263 263
 	}
264 264
 
265
-	return c.Id, nil
265
+	return c.ID, nil
266 266
 }
267 267
 
268
-func (b *buildFile) commit(id string) error {
268
+// Commit the container <id> with the autorun command <autoCmd>
269
+func (b *buildFile) commit(id string, autoCmd []string, comment string) error {
269 270
 	if b.image == "" {
270 271
 		return fmt.Errorf("Please provide a source image with `from` prior to commit")
271 272
 	}
272 273
 	b.config.Image = b.image
273 274
 	if id == "" {
274
-		cmd := b.config.Cmd
275
-		b.config.Cmd = []string{"true"}
276
-		if cid, err := b.run(); err != nil {
275
+		b.config.Cmd = []string{"/bin/sh", "-c", "#(nop) " + comment}
276
+
277
+		if cache, err := b.srv.ImageGetCached(b.image, b.config); err != nil {
277 278
 			return err
279
+		} else if cache != nil {
280
+			utils.Debugf("[BUILDER] Use cached version")
281
+			b.image = cache.ID
282
+			return nil
278 283
 		} else {
279
-			id = cid
284
+			utils.Debugf("[BUILDER] Cache miss")
285
+		}
286
+
287
+		cid, err := b.run()
288
+		if err != nil {
289
+			return err
280 290
 		}
281
-		b.config.Cmd = cmd
291
+		id = cid
282 292
 	}
283 293
 
284 294
 	container := b.runtime.Get(id)
... ...
@@ -286,20 +284,20 @@ func (b *buildFile) commit(id string) error {
286 286
 		return fmt.Errorf("An error occured while creating the container")
287 287
 	}
288 288
 
289
+	// Note: Actually copy the struct
290
+	autoConfig := *b.config
291
+	autoConfig.Cmd = autoCmd
289 292
 	// Commit the container
290
-	image, err := b.builder.Commit(container, "", "", "", b.maintainer, nil)
293
+	image, err := b.builder.Commit(container, "", "", "", b.maintainer, &autoConfig)
291 294
 	if err != nil {
292 295
 		return err
293 296
 	}
294
-	b.tmpImages[image.Id] = struct{}{}
295
-	b.image = image.Id
296
-	b.needCommit = false
297
+	b.tmpImages[image.ID] = struct{}{}
298
+	b.image = image.ID
297 299
 	return nil
298 300
 }
299 301
 
300 302
 func (b *buildFile) Build(dockerfile, context io.Reader) (string, error) {
301
-	defer b.clearTmp(b.tmpContainers, b.tmpImages)
302
-
303 303
 	if context != nil {
304 304
 		name, err := ioutil.TempDir("/tmp", "docker-build")
305 305
 		if err != nil {
... ...
@@ -337,6 +335,7 @@ func (b *buildFile) Build(dockerfile, context io.Reader) (string, error) {
337 337
 		method, exists := reflect.TypeOf(b).MethodByName("Cmd" + strings.ToUpper(instruction[:1]) + strings.ToLower(instruction[1:]))
338 338
 		if !exists {
339 339
 			fmt.Fprintf(b.out, "Skipping unknown instruction %s\n", strings.ToUpper(instruction))
340
+			continue
340 341
 		}
341 342
 		ret := method.Func.Call([]reflect.Value{reflect.ValueOf(b), reflect.ValueOf(arguments)})[0].Interface()
342 343
 		if ret != nil {
... ...
@@ -345,22 +344,10 @@ func (b *buildFile) Build(dockerfile, context io.Reader) (string, error) {
345 345
 
346 346
 		fmt.Fprintf(b.out, "===> %v\n", b.image)
347 347
 	}
348
-	if b.needCommit {
349
-		if err := b.commit(""); err != nil {
350
-			return "", err
351
-		}
352
-	}
353 348
 	if b.image != "" {
354
-		// The build is successful, keep the temporary containers and images
355
-		for i := range b.tmpImages {
356
-			delete(b.tmpImages, i)
357
-		}
358
-		fmt.Fprintf(b.out, "Build success.\n Image id:\n%s\n", b.image)
349
+		fmt.Fprintf(b.out, "Build successful.\n===> %s\n", b.image)
359 350
 		return b.image, nil
360 351
 	}
361
-	for i := range b.tmpContainers {
362
-		delete(b.tmpContainers, i)
363
-	}
364 352
 	return "", fmt.Errorf("An error occured during the build\n")
365 353
 }
366 354
 
... ...
@@ -26,7 +26,7 @@ func TestBuild(t *testing.T) {
26 26
 
27 27
 	buildfile := NewBuildFile(srv, &utils.NopWriter{})
28 28
 
29
-	imgId, err := buildfile.Build(strings.NewReader(Dockerfile), nil)
29
+	imgID, err := buildfile.Build(strings.NewReader(Dockerfile), nil)
30 30
 	if err != nil {
31 31
 		t.Fatal(err)
32 32
 	}
... ...
@@ -34,7 +34,7 @@ func TestBuild(t *testing.T) {
34 34
 	builder := NewBuilder(runtime)
35 35
 	container, err := builder.Create(
36 36
 		&Config{
37
-			Image: imgId,
37
+			Image: imgID,
38 38
 			Cmd:   []string{"cat", "/tmp/passwd"},
39 39
 		},
40 40
 	)
... ...
@@ -53,7 +53,7 @@ func TestBuild(t *testing.T) {
53 53
 
54 54
 	container2, err := builder.Create(
55 55
 		&Config{
56
-			Image: imgId,
56
+			Image: imgID,
57 57
 			Cmd:   []string{"ls", "-d", "/var/run/sshd"},
58 58
 		},
59 59
 	)
... ...
@@ -65,7 +65,7 @@ func Changes(layers []string, rw string) ([]Change, error) {
65 65
 		file := filepath.Base(path)
66 66
 		// If there is a whiteout, then the file was removed
67 67
 		if strings.HasPrefix(file, ".wh.") {
68
-			originalFile := strings.TrimLeft(file, ".wh.")
68
+			originalFile := file[len(".wh."):]
69 69
 			change.Path = filepath.Join(filepath.Dir(path), originalFile)
70 70
 			change.Kind = ChangeDelete
71 71
 		} else {
... ...
@@ -17,6 +17,7 @@ import (
17 17
 	"net/url"
18 18
 	"os"
19 19
 	"os/signal"
20
+	"path"
20 21
 	"path/filepath"
21 22
 	"reflect"
22 23
 	"strconv"
... ...
@@ -27,10 +28,10 @@ import (
27 27
 	"unicode"
28 28
 )
29 29
 
30
-const VERSION = "0.3.3"
30
+const VERSION = "0.4.0"
31 31
 
32 32
 var (
33
-	GIT_COMMIT string
33
+	GITCOMMIT string
34 34
 )
35 35
 
36 36
 func (cli *DockerCli) getMethod(name string) (reflect.Method, bool) {
... ...
@@ -101,7 +102,7 @@ func (cli *DockerCli) CmdHelp(args ...string) error {
101 101
 		{"stop", "Stop a running container"},
102 102
 		{"tag", "Tag an image into a repository"},
103 103
 		{"version", "Show the docker version information"},
104
-		{"wait", "Block until a container stops}, then print its exit code"},
104
+		{"wait", "Block until a container stops, then print its exit code"},
105 105
 	} {
106 106
 		help += fmt.Sprintf("    %-10.10s%s\n", command[0], command[1])
107 107
 	}
... ...
@@ -130,16 +131,20 @@ func (cli *DockerCli) CmdInsert(args ...string) error {
130 130
 }
131 131
 
132 132
 func (cli *DockerCli) CmdBuild(args ...string) error {
133
-	cmd := Subcmd("build", "[OPTIONS] [CONTEXT]", "Build an image from a Dockerfile")
134
-	fileName := cmd.String("f", "Dockerfile", "Use `file` as Dockerfile. Can be '-' for stdin")
133
+	cmd := Subcmd("build", "[OPTIONS] PATH | -", "Build a new container image from the source code at PATH")
134
+	tag := cmd.String("t", "", "Tag to be applied to the resulting image in case of success")
135 135
 	if err := cmd.Parse(args); err != nil {
136 136
 		return nil
137 137
 	}
138
+	if cmd.NArg() != 1 {
139
+		cmd.Usage()
140
+		return nil
141
+	}
138 142
 
139 143
 	var (
140
-		file          io.ReadCloser
141 144
 		multipartBody io.Reader
142
-		err           error
145
+		file          io.ReadCloser
146
+		contextPath   string
143 147
 	)
144 148
 
145 149
 	// Init the needed component for the Multipart
... ...
@@ -148,27 +153,19 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
148 148
 	w := multipart.NewWriter(buff)
149 149
 	boundary := strings.NewReader("\r\n--" + w.Boundary() + "--\r\n")
150 150
 
151
-	// Create a FormFile multipart for the Dockerfile
152
-	if *fileName == "-" {
151
+	compression := Bzip2
152
+
153
+	if cmd.Arg(0) == "-" {
153 154
 		file = os.Stdin
154 155
 	} else {
155
-		file, err = os.Open(*fileName)
156
+		// Send Dockerfile from arg/Dockerfile (deprecate later)
157
+		f, err := os.Open(path.Join(cmd.Arg(0), "Dockerfile"))
156 158
 		if err != nil {
157 159
 			return err
158 160
 		}
159
-		defer file.Close()
160
-	}
161
-	if wField, err := w.CreateFormFile("Dockerfile", *fileName); err != nil {
162
-		return err
163
-	} else {
164
-		io.Copy(wField, file)
165
-	}
166
-	multipartBody = io.MultiReader(multipartBody, boundary)
167
-
168
-	compression := Bzip2
169
-
170
-	// Create a FormFile multipart for the context if needed
171
-	if cmd.Arg(0) != "" {
161
+		file = f
162
+		// Send context from arg
163
+		// Create a FormFile multipart for the context if needed
172 164
 		// FIXME: Use NewTempArchive in order to have the size and avoid too much memory usage?
173 165
 		context, err := Tar(cmd.Arg(0), compression)
174 166
 		if err != nil {
... ...
@@ -179,23 +176,32 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
179 179
 		if err != nil {
180 180
 			return err
181 181
 		}
182
-		if wField, err := w.CreateFormFile("Context", filepath.Base(absPath)+"."+compression.Extension()); err != nil {
182
+		wField, err := w.CreateFormFile("Context", filepath.Base(absPath)+"."+compression.Extension())
183
+		if err != nil {
183 184
 			return err
184
-		} else {
185
-			// FIXME: Find a way to have a progressbar for the upload too
186
-			io.Copy(wField, utils.ProgressReader(ioutil.NopCloser(context), -1, os.Stdout, "Caching Context %v/%v (%v)\r", false))
187 185
 		}
188
-
186
+		// FIXME: Find a way to have a progressbar for the upload too
187
+		sf := utils.NewStreamFormatter(false)
188
+		io.Copy(wField, utils.ProgressReader(ioutil.NopCloser(context), -1, os.Stdout, sf.FormatProgress("Caching Context", "%v/%v (%v)"), sf))
189 189
 		multipartBody = io.MultiReader(multipartBody, boundary)
190 190
 	}
191
+	// Create a FormFile multipart for the Dockerfile
192
+	wField, err := w.CreateFormFile("Dockerfile", "Dockerfile")
193
+	if err != nil {
194
+		return err
195
+	}
196
+	io.Copy(wField, file)
197
+	multipartBody = io.MultiReader(multipartBody, boundary)
191 198
 
199
+	v := &url.Values{}
200
+	v.Set("t", *tag)
192 201
 	// Send the multipart request with correct content-type
193
-	req, err := http.NewRequest("POST", fmt.Sprintf("http://%s:%d%s", cli.host, cli.port, "/build"), multipartBody)
202
+	req, err := http.NewRequest("POST", fmt.Sprintf("http://%s:%d%s?%s", cli.host, cli.port, "/build", v.Encode()), multipartBody)
194 203
 	if err != nil {
195 204
 		return err
196 205
 	}
197 206
 	req.Header.Set("Content-Type", w.FormDataContentType())
198
-	if cmd.Arg(0) != "" {
207
+	if contextPath != "" {
199 208
 		req.Header.Set("X-Docker-Context-Compression", compression.Flag())
200 209
 		fmt.Println("Uploading Context...")
201 210
 	}
... ...
@@ -270,9 +276,8 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
270 270
 	oldState, err := term.SetRawTerminal()
271 271
 	if err != nil {
272 272
 		return err
273
-	} else {
274
-		defer term.RestoreTerminal(oldState)
275 273
 	}
274
+	defer term.RestoreTerminal(oldState)
276 275
 
277 276
 	cmd := Subcmd("login", "", "Register or Login to the docker registry server")
278 277
 	if err := cmd.Parse(args); err != nil {
... ...
@@ -325,7 +330,7 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
325 325
 		return err
326 326
 	}
327 327
 
328
-	var out2 ApiAuth
328
+	var out2 APIAuth
329 329
 	err = json.Unmarshal(body, &out2)
330 330
 	if err != nil {
331 331
 		return err
... ...
@@ -352,7 +357,7 @@ func (cli *DockerCli) CmdWait(args ...string) error {
352 352
 		if err != nil {
353 353
 			fmt.Printf("%s", err)
354 354
 		} else {
355
-			var out ApiWait
355
+			var out APIWait
356 356
 			err = json.Unmarshal(body, &out)
357 357
 			if err != nil {
358 358
 				return err
... ...
@@ -380,21 +385,20 @@ func (cli *DockerCli) CmdVersion(args ...string) error {
380 380
 		return err
381 381
 	}
382 382
 
383
-	var out ApiVersion
383
+	var out APIVersion
384 384
 	err = json.Unmarshal(body, &out)
385 385
 	if err != nil {
386 386
 		utils.Debugf("Error unmarshal: body: %s, err: %s\n", body, err)
387 387
 		return err
388 388
 	}
389
-	fmt.Println("Version:", out.Version)
390
-	fmt.Println("Git Commit:", out.GitCommit)
391
-	if !out.MemoryLimit {
392
-		fmt.Println("WARNING: No memory limit support")
389
+	fmt.Println("Client version:", VERSION)
390
+	fmt.Println("Server version:", out.Version)
391
+	if out.GitCommit != "" {
392
+		fmt.Println("Git commit:", out.GitCommit)
393 393
 	}
394
-	if !out.SwapLimit {
395
-		fmt.Println("WARNING: No swap limit support")
394
+	if out.GoVersion != "" {
395
+		fmt.Println("Go version:", out.GoVersion)
396 396
 	}
397
-
398 397
 	return nil
399 398
 }
400 399
 
... ...
@@ -414,15 +418,24 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
414 414
 		return err
415 415
 	}
416 416
 
417
-	var out ApiInfo
418
-	err = json.Unmarshal(body, &out)
419
-	if err != nil {
417
+	var out APIInfo
418
+	if err := json.Unmarshal(body, &out); err != nil {
420 419
 		return err
421 420
 	}
422
-	fmt.Printf("containers: %d\nversion: %s\nimages: %d\nGo version: %s\n", out.Containers, out.Version, out.Images, out.GoVersion)
423
-	if out.Debug {
424
-		fmt.Println("debug mode enabled")
425
-		fmt.Printf("fds: %d\ngoroutines: %d\n", out.NFd, out.NGoroutines)
421
+
422
+	fmt.Printf("Containers: %d\n", out.Containers)
423
+	fmt.Printf("Images: %d\n", out.Images)
424
+	if out.Debug || os.Getenv("DEBUG") != "" {
425
+		fmt.Printf("Debug mode (server): %v\n", out.Debug)
426
+		fmt.Printf("Debug mode (client): %v\n", os.Getenv("DEBUG") != "")
427
+		fmt.Printf("Fds: %d\n", out.NFd)
428
+		fmt.Printf("Goroutines: %d\n", out.NGoroutines)
429
+	}
430
+	if !out.MemoryLimit {
431
+		fmt.Println("WARNING: No memory limit support")
432
+	}
433
+	if !out.SwapLimit {
434
+		fmt.Println("WARNING: No swap limit support")
426 435
 	}
427 436
 	return nil
428 437
 }
... ...
@@ -590,7 +603,7 @@ func (cli *DockerCli) CmdHistory(args ...string) error {
590 590
 		return err
591 591
 	}
592 592
 
593
-	var outs []ApiHistory
593
+	var outs []APIHistory
594 594
 	err = json.Unmarshal(body, &outs)
595 595
 	if err != nil {
596 596
 		return err
... ...
@@ -599,7 +612,7 @@ func (cli *DockerCli) CmdHistory(args ...string) error {
599 599
 	fmt.Fprintln(w, "ID\tCREATED\tCREATED BY")
600 600
 
601 601
 	for _, out := range outs {
602
-		fmt.Fprintf(w, "%s\t%s ago\t%s\n", out.Id, utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.CreatedBy)
602
+		fmt.Fprintf(w, "%s\t%s ago\t%s\n", out.ID, utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.CreatedBy)
603 603
 	}
604 604
 	w.Flush()
605 605
 	return nil
... ...
@@ -725,12 +738,6 @@ func (cli *DockerCli) CmdPull(args ...string) error {
725 725
 		remote = remoteParts[0]
726 726
 	}
727 727
 
728
-	if strings.Contains(remote, "/") {
729
-		if _, err := cli.checkIfLogged(true, "pull"); err != nil {
730
-			return err
731
-		}
732
-	}
733
-
734 728
 	v := url.Values{}
735 729
 	v.Set("fromImage", remote)
736 730
 	v.Set("tag", *tag)
... ...
@@ -778,7 +785,7 @@ func (cli *DockerCli) CmdImages(args ...string) error {
778 778
 			return err
779 779
 		}
780 780
 
781
-		var outs []ApiImages
781
+		var outs []APIImages
782 782
 		err = json.Unmarshal(body, &outs)
783 783
 		if err != nil {
784 784
 			return err
... ...
@@ -800,9 +807,9 @@ func (cli *DockerCli) CmdImages(args ...string) error {
800 800
 			if !*quiet {
801 801
 				fmt.Fprintf(w, "%s\t%s\t", out.Repository, out.Tag)
802 802
 				if *noTrunc {
803
-					fmt.Fprintf(w, "%s\t", out.Id)
803
+					fmt.Fprintf(w, "%s\t", out.ID)
804 804
 				} else {
805
-					fmt.Fprintf(w, "%s\t", utils.TruncateId(out.Id))
805
+					fmt.Fprintf(w, "%s\t", utils.TruncateID(out.ID))
806 806
 				}
807 807
 				fmt.Fprintf(w, "%s ago\t", utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))))
808 808
 				if out.ParentSize > 0 {
... ...
@@ -812,9 +819,9 @@ func (cli *DockerCli) CmdImages(args ...string) error {
812 812
 				}
813 813
 			} else {
814 814
 				if *noTrunc {
815
-					fmt.Fprintln(w, out.Id)
815
+					fmt.Fprintln(w, out.ID)
816 816
 				} else {
817
-					fmt.Fprintln(w, utils.TruncateId(out.Id))
817
+					fmt.Fprintln(w, utils.TruncateID(out.ID))
818 818
 				}
819 819
 			}
820 820
 		}
... ...
@@ -861,7 +868,7 @@ func (cli *DockerCli) CmdPs(args ...string) error {
861 861
 		return err
862 862
 	}
863 863
 
864
-	var outs []ApiContainers
864
+	var outs []APIContainers
865 865
 	err = json.Unmarshal(body, &outs)
866 866
 	if err != nil {
867 867
 		return err
... ...
@@ -874,9 +881,9 @@ func (cli *DockerCli) CmdPs(args ...string) error {
874 874
 	for _, out := range outs {
875 875
 		if !*quiet {
876 876
 			if *noTrunc {
877
-				fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t", out.Id, out.Image, out.Command, out.Status, utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Ports)
877
+				fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t", out.ID, out.Image, out.Command, utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Status, out.Ports)
878 878
 			} else {
879
-				fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t", utils.TruncateId(out.Id), out.Image, utils.Trunc(out.Command, 20), out.Status, utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Ports)
879
+				fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t", utils.TruncateID(out.ID), out.Image, utils.Trunc(out.Command, 20), utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Status, out.Ports)
880 880
 			}
881 881
 			if out.SizeRootFs > 0 {
882 882
 				fmt.Fprintf(w, "%s (virtual %s)\n", utils.HumanSize(out.SizeRw), utils.HumanSize(out.SizeRootFs))
... ...
@@ -885,9 +892,9 @@ func (cli *DockerCli) CmdPs(args ...string) error {
885 885
 			}
886 886
 		} else {
887 887
 			if *noTrunc {
888
-				fmt.Fprintln(w, out.Id)
888
+				fmt.Fprintln(w, out.ID)
889 889
 			} else {
890
-				fmt.Fprintln(w, utils.TruncateId(out.Id))
890
+				fmt.Fprintln(w, utils.TruncateID(out.ID))
891 891
 			}
892 892
 		}
893 893
 	}
... ...
@@ -930,13 +937,13 @@ func (cli *DockerCli) CmdCommit(args ...string) error {
930 930
 		return err
931 931
 	}
932 932
 
933
-	apiId := &ApiId{}
934
-	err = json.Unmarshal(body, apiId)
933
+	apiID := &APIID{}
934
+	err = json.Unmarshal(body, apiID)
935 935
 	if err != nil {
936 936
 		return err
937 937
 	}
938 938
 
939
-	fmt.Println(apiId.Id)
939
+	fmt.Println(apiID.ID)
940 940
 	return nil
941 941
 }
942 942
 
... ...
@@ -993,12 +1000,10 @@ func (cli *DockerCli) CmdLogs(args ...string) error {
993 993
 		return nil
994 994
 	}
995 995
 
996
-	v := url.Values{}
997
-	v.Set("logs", "1")
998
-	v.Set("stdout", "1")
999
-	v.Set("stderr", "1")
1000
-
1001
-	if err := cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), false, nil, os.Stdout); err != nil {
996
+	if err := cli.stream("POST", "/containers/"+cmd.Arg(0)+"/attach?logs=1&stdout=1", nil, os.Stdout); err != nil {
997
+		return err
998
+	}
999
+	if err := cli.stream("POST", "/containers/"+cmd.Arg(0)+"/attach?logs=1&stderr=1", nil, os.Stderr); err != nil {
1002 1000
 		return err
1003 1001
 	}
1004 1002
 	return nil
... ...
@@ -1075,7 +1080,7 @@ func (cli *DockerCli) CmdSearch(args ...string) error {
1075 1075
 		return err
1076 1076
 	}
1077 1077
 
1078
-	outs := []ApiSearch{}
1078
+	outs := []APISearch{}
1079 1079
 	err = json.Unmarshal(body, &outs)
1080 1080
 	if err != nil {
1081 1081
 		return err
... ...
@@ -1207,7 +1212,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
1207 1207
 		return err
1208 1208
 	}
1209 1209
 
1210
-	out := &ApiRun{}
1210
+	out := &APIRun{}
1211 1211
 	err = json.Unmarshal(body, out)
1212 1212
 	if err != nil {
1213 1213
 		return err
... ...
@@ -1228,18 +1233,21 @@ func (cli *DockerCli) CmdRun(args ...string) error {
1228 1228
 	}
1229 1229
 
1230 1230
 	//start the container
1231
-	_, _, err = cli.call("POST", "/containers/"+out.Id+"/start", nil)
1231
+	_, _, err = cli.call("POST", "/containers/"+out.ID+"/start", nil)
1232 1232
 	if err != nil {
1233 1233
 		return err
1234 1234
 	}
1235 1235
 
1236
+	if !config.AttachStdout && !config.AttachStderr {
1237
+		fmt.Println(out.ID)
1238
+	}
1236 1239
 	if connections > 0 {
1237 1240
 		chErrors := make(chan error, connections)
1238
-		cli.monitorTtySize(out.Id)
1241
+		cli.monitorTtySize(out.ID)
1239 1242
 
1240 1243
 		if splitStderr && config.AttachStderr {
1241 1244
 			go func() {
1242
-				chErrors <- cli.hijack("POST", "/containers/"+out.Id+"/attach?logs=1&stream=1&stderr=1", config.Tty, nil, os.Stderr)
1245
+				chErrors <- cli.hijack("POST", "/containers/"+out.ID+"/attach?logs=1&stream=1&stderr=1", config.Tty, nil, os.Stderr)
1243 1246
 			}()
1244 1247
 		}
1245 1248
 
... ...
@@ -1257,7 +1265,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
1257 1257
 			v.Set("stderr", "1")
1258 1258
 		}
1259 1259
 		go func() {
1260
-			chErrors <- cli.hijack("POST", "/containers/"+out.Id+"/attach?"+v.Encode(), config.Tty, os.Stdin, os.Stdout)
1260
+			chErrors <- cli.hijack("POST", "/containers/"+out.ID+"/attach?"+v.Encode(), config.Tty, os.Stdin, os.Stdout)
1261 1261
 		}()
1262 1262
 		for connections > 0 {
1263 1263
 			err := <-chErrors
... ...
@@ -1267,9 +1275,6 @@ func (cli *DockerCli) CmdRun(args ...string) error {
1267 1267
 			connections -= 1
1268 1268
 		}
1269 1269
 	}
1270
-	if !config.AttachStdout && !config.AttachStderr {
1271
-		fmt.Println(out.Id)
1272
-	}
1273 1270
 	return nil
1274 1271
 }
1275 1272
 
... ...
@@ -1317,7 +1322,7 @@ func (cli *DockerCli) call(method, path string, data interface{}) ([]byte, int,
1317 1317
 		params = bytes.NewBuffer(buf)
1318 1318
 	}
1319 1319
 
1320
-	req, err := http.NewRequest(method, fmt.Sprintf("http://%s:%d/v%g%s", cli.host, cli.port, API_VERSION, path), params)
1320
+	req, err := http.NewRequest(method, fmt.Sprintf("http://%s:%d/v%g%s", cli.host, cli.port, APIVERSION, path), params)
1321 1321
 	if err != nil {
1322 1322
 		return nil, -1, err
1323 1323
 	}
... ...
@@ -1349,7 +1354,7 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer) e
1349 1349
 	if (method == "POST" || method == "PUT") && in == nil {
1350 1350
 		in = bytes.NewReader([]byte{})
1351 1351
 	}
1352
-	req, err := http.NewRequest(method, fmt.Sprintf("http://%s:%d/v%g%s", cli.host, cli.port, API_VERSION, path), in)
1352
+	req, err := http.NewRequest(method, fmt.Sprintf("http://%s:%d/v%g%s", cli.host, cli.port, APIVERSION, path), in)
1353 1353
 	if err != nil {
1354 1354
 		return err
1355 1355
 	}
... ...
@@ -1374,20 +1379,18 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer) e
1374 1374
 	}
1375 1375
 
1376 1376
 	if resp.Header.Get("Content-Type") == "application/json" {
1377
-		type Message struct {
1378
-			Status   string `json:"status,omitempty"`
1379
-			Progress string `json:"progress,omitempty"`
1380
-		}
1381 1377
 		dec := json.NewDecoder(resp.Body)
1382 1378
 		for {
1383
-			var m Message
1379
+			var m utils.JSONMessage
1384 1380
 			if err := dec.Decode(&m); err == io.EOF {
1385 1381
 				break
1386 1382
 			} else if err != nil {
1387 1383
 				return err
1388 1384
 			}
1389 1385
 			if m.Progress != "" {
1390
-				fmt.Fprintf(out, "Downloading %s\r", m.Progress)
1386
+				fmt.Fprintf(out, "%s %s\r", m.Status, m.Progress)
1387
+			} else if m.Error != "" {
1388
+				return fmt.Errorf(m.Error)
1391 1389
 			} else {
1392 1390
 				fmt.Fprintf(out, "%s\n", m.Status)
1393 1391
 			}
... ...
@@ -1401,7 +1404,7 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer) e
1401 1401
 }
1402 1402
 
1403 1403
 func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in *os.File, out io.Writer) error {
1404
-	req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", API_VERSION, path), nil)
1404
+	req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", APIVERSION, path), nil)
1405 1405
 	if err != nil {
1406 1406
 		return err
1407 1407
 	}
... ...
@@ -1422,12 +1425,12 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in *os.Fi
1422 1422
 		return err
1423 1423
 	})
1424 1424
 
1425
-	if in != nil && setRawTerminal && term.IsTerminal(int(in.Fd())) && os.Getenv("NORAW") == "" {
1426
-		if oldState, err := term.SetRawTerminal(); err != nil {
1425
+	if in != nil && setRawTerminal && term.IsTerminal(in.Fd()) && os.Getenv("NORAW") == "" {
1426
+		oldState, err := term.SetRawTerminal()
1427
+		if err != nil {
1427 1428
 			return err
1428
-		} else {
1429
-			defer term.RestoreTerminal(oldState)
1430 1429
 		}
1430
+		defer term.RestoreTerminal(oldState)
1431 1431
 	}
1432 1432
 	sendStdin := utils.Go(func() error {
1433 1433
 		_, err := io.Copy(rwc, in)
... ...
@@ -1441,7 +1444,7 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in *os.Fi
1441 1441
 		return err
1442 1442
 	}
1443 1443
 
1444
-	if !term.IsTerminal(int(os.Stdin.Fd())) {
1444
+	if !term.IsTerminal(os.Stdin.Fd()) {
1445 1445
 		if err := <-sendStdin; err != nil {
1446 1446
 			return err
1447 1447
 		}
... ...
@@ -24,7 +24,7 @@ import (
24 24
 type Container struct {
25 25
 	root string
26 26
 
27
-	Id string
27
+	ID string
28 28
 
29 29
 	Created time.Time
30 30
 
... ...
@@ -168,8 +168,8 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *flag.FlagSet
168 168
 }
169 169
 
170 170
 type NetworkSettings struct {
171
-	IpAddress   string
172
-	IpPrefixLen int
171
+	IPAddress   string
172
+	IPPrefixLen int
173 173
 	Gateway     string
174 174
 	Bridge      string
175 175
 	PortMapping map[string]string
... ...
@@ -410,7 +410,7 @@ func (container *Container) Start() error {
410 410
 	defer container.State.unlock()
411 411
 
412 412
 	if container.State.Running {
413
-		return fmt.Errorf("The container %s is already running.", container.Id)
413
+		return fmt.Errorf("The container %s is already running.", container.ID)
414 414
 	}
415 415
 	if err := container.EnsureMounted(); err != nil {
416 416
 		return err
... ...
@@ -432,24 +432,24 @@ func (container *Container) Start() error {
432 432
 
433 433
 	// Create the requested volumes volumes
434 434
 	for volPath := range container.Config.Volumes {
435
-		if c, err := container.runtime.volumes.Create(nil, container, "", "", nil); err != nil {
435
+		c, err := container.runtime.volumes.Create(nil, container, "", "", nil)
436
+		if err != nil {
436 437
 			return err
437
-		} else {
438
-			if err := os.MkdirAll(path.Join(container.RootfsPath(), volPath), 0755); err != nil {
439
-				return nil
440
-			}
441
-			container.Volumes[volPath] = c.Id
442 438
 		}
439
+		if err := os.MkdirAll(path.Join(container.RootfsPath(), volPath), 0755); err != nil {
440
+			return nil
441
+		}
442
+		container.Volumes[volPath] = c.ID
443 443
 	}
444 444
 
445 445
 	if container.Config.VolumesFrom != "" {
446 446
 		c := container.runtime.Get(container.Config.VolumesFrom)
447 447
 		if c == nil {
448
-			return fmt.Errorf("Container %s not found. Impossible to mount its volumes", container.Id)
448
+			return fmt.Errorf("Container %s not found. Impossible to mount its volumes", container.ID)
449 449
 		}
450 450
 		for volPath, id := range c.Volumes {
451 451
 			if _, exists := container.Volumes[volPath]; exists {
452
-				return fmt.Errorf("The requested volume %s overlap one of the volume of the container %s", volPath, c.Id)
452
+				return fmt.Errorf("The requested volume %s overlap one of the volume of the container %s", volPath, c.ID)
453 453
 			}
454 454
 			if err := os.MkdirAll(path.Join(container.RootfsPath(), volPath), 0755); err != nil {
455 455
 				return nil
... ...
@@ -463,7 +463,7 @@ func (container *Container) Start() error {
463 463
 	}
464 464
 
465 465
 	params := []string{
466
-		"-n", container.Id,
466
+		"-n", container.ID,
467 467
 		"-f", container.lxcConfigPath(),
468 468
 		"--",
469 469
 		"/sbin/init",
... ...
@@ -574,17 +574,17 @@ func (container *Container) allocateNetwork() error {
574 574
 	}
575 575
 	container.NetworkSettings.PortMapping = make(map[string]string)
576 576
 	for _, spec := range container.Config.PortSpecs {
577
-		if nat, err := iface.AllocatePort(spec); err != nil {
577
+		nat, err := iface.AllocatePort(spec)
578
+		if err != nil {
578 579
 			iface.Release()
579 580
 			return err
580
-		} else {
581
-			container.NetworkSettings.PortMapping[strconv.Itoa(nat.Backend)] = strconv.Itoa(nat.Frontend)
582 581
 		}
582
+		container.NetworkSettings.PortMapping[strconv.Itoa(nat.Backend)] = strconv.Itoa(nat.Frontend)
583 583
 	}
584 584
 	container.network = iface
585 585
 	container.NetworkSettings.Bridge = container.runtime.networkManager.bridgeIface
586
-	container.NetworkSettings.IpAddress = iface.IPNet.IP.String()
587
-	container.NetworkSettings.IpPrefixLen, _ = iface.IPNet.Mask.Size()
586
+	container.NetworkSettings.IPAddress = iface.IPNet.IP.String()
587
+	container.NetworkSettings.IPPrefixLen, _ = iface.IPNet.Mask.Size()
588 588
 	container.NetworkSettings.Gateway = iface.Gateway.String()
589 589
 	return nil
590 590
 }
... ...
@@ -598,16 +598,16 @@ func (container *Container) releaseNetwork() {
598 598
 // FIXME: replace this with a control socket within docker-init
599 599
 func (container *Container) waitLxc() error {
600 600
 	for {
601
-		if output, err := exec.Command("lxc-info", "-n", container.Id).CombinedOutput(); err != nil {
601
+		output, err := exec.Command("lxc-info", "-n", container.ID).CombinedOutput()
602
+		if err != nil {
602 603
 			return err
603
-		} else {
604
-			if !strings.Contains(string(output), "RUNNING") {
605
-				return nil
606
-			}
604
+		}
605
+		if !strings.Contains(string(output), "RUNNING") {
606
+			return nil
607 607
 		}
608 608
 		time.Sleep(500 * time.Millisecond)
609 609
 	}
610
-	return nil
610
+	panic("Unreachable")
611 611
 }
612 612
 
613 613
 func (container *Container) monitor() {
... ...
@@ -617,17 +617,17 @@ func (container *Container) monitor() {
617 617
 	// If the command does not exists, try to wait via lxc
618 618
 	if container.cmd == nil {
619 619
 		if err := container.waitLxc(); err != nil {
620
-			utils.Debugf("%s: Process: %s", container.Id, err)
620
+			utils.Debugf("%s: Process: %s", container.ID, err)
621 621
 		}
622 622
 	} else {
623 623
 		if err := container.cmd.Wait(); err != nil {
624 624
 			// Discard the error as any signals or non 0 returns will generate an error
625
-			utils.Debugf("%s: Process: %s", container.Id, err)
625
+			utils.Debugf("%s: Process: %s", container.ID, err)
626 626
 		}
627 627
 	}
628 628
 	utils.Debugf("Process finished")
629 629
 
630
-	var exitCode int = -1
630
+	exitCode := -1
631 631
 	if container.cmd != nil {
632 632
 		exitCode = container.cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
633 633
 	}
... ...
@@ -636,24 +636,24 @@ func (container *Container) monitor() {
636 636
 	container.releaseNetwork()
637 637
 	if container.Config.OpenStdin {
638 638
 		if err := container.stdin.Close(); err != nil {
639
-			utils.Debugf("%s: Error close stdin: %s", container.Id, err)
639
+			utils.Debugf("%s: Error close stdin: %s", container.ID, err)
640 640
 		}
641 641
 	}
642 642
 	if err := container.stdout.CloseWriters(); err != nil {
643
-		utils.Debugf("%s: Error close stdout: %s", container.Id, err)
643
+		utils.Debugf("%s: Error close stdout: %s", container.ID, err)
644 644
 	}
645 645
 	if err := container.stderr.CloseWriters(); err != nil {
646
-		utils.Debugf("%s: Error close stderr: %s", container.Id, err)
646
+		utils.Debugf("%s: Error close stderr: %s", container.ID, err)
647 647
 	}
648 648
 
649 649
 	if container.ptyMaster != nil {
650 650
 		if err := container.ptyMaster.Close(); err != nil {
651
-			utils.Debugf("%s: Error closing Pty master: %s", container.Id, err)
651
+			utils.Debugf("%s: Error closing Pty master: %s", container.ID, err)
652 652
 		}
653 653
 	}
654 654
 
655 655
 	if err := container.Unmount(); err != nil {
656
-		log.Printf("%v: Failed to umount filesystem: %v", container.Id, err)
656
+		log.Printf("%v: Failed to umount filesystem: %v", container.ID, err)
657 657
 	}
658 658
 
659 659
 	// Re-create a brand new stdin pipe once the container exited
... ...
@@ -674,7 +674,7 @@ func (container *Container) monitor() {
674 674
 		// This is because State.setStopped() has already been called, and has caused Wait()
675 675
 		// to return.
676 676
 		// FIXME: why are we serializing running state to disk in the first place?
677
-		//log.Printf("%s: Failed to dump configuration to the disk: %s", container.Id, err)
677
+		//log.Printf("%s: Failed to dump configuration to the disk: %s", container.ID, err)
678 678
 	}
679 679
 }
680 680
 
... ...
@@ -684,17 +684,17 @@ func (container *Container) kill() error {
684 684
 	}
685 685
 
686 686
 	// Sending SIGKILL to the process via lxc
687
-	output, err := exec.Command("lxc-kill", "-n", container.Id, "9").CombinedOutput()
687
+	output, err := exec.Command("lxc-kill", "-n", container.ID, "9").CombinedOutput()
688 688
 	if err != nil {
689
-		log.Printf("error killing container %s (%s, %s)", container.Id, output, err)
689
+		log.Printf("error killing container %s (%s, %s)", container.ID, output, err)
690 690
 	}
691 691
 
692 692
 	// 2. Wait for the process to die, in last resort, try to kill the process directly
693 693
 	if err := container.WaitTimeout(10 * time.Second); err != nil {
694 694
 		if container.cmd == nil {
695
-			return fmt.Errorf("lxc-kill failed, impossible to kill the container %s", container.Id)
695
+			return fmt.Errorf("lxc-kill failed, impossible to kill the container %s", container.ID)
696 696
 		}
697
-		log.Printf("Container %s failed to exit within 10 seconds of lxc SIGKILL - trying direct SIGKILL", container.Id)
697
+		log.Printf("Container %s failed to exit within 10 seconds of lxc SIGKILL - trying direct SIGKILL", container.ID)
698 698
 		if err := container.cmd.Process.Kill(); err != nil {
699 699
 			return err
700 700
 		}
... ...
@@ -722,7 +722,7 @@ func (container *Container) Stop(seconds int) error {
722 722
 	}
723 723
 
724 724
 	// 1. Send a SIGTERM
725
-	if output, err := exec.Command("lxc-kill", "-n", container.Id, "15").CombinedOutput(); err != nil {
725
+	if output, err := exec.Command("lxc-kill", "-n", container.ID, "15").CombinedOutput(); err != nil {
726 726
 		log.Print(string(output))
727 727
 		log.Print("Failed to send SIGTERM to the process, force killing")
728 728
 		if err := container.kill(); err != nil {
... ...
@@ -732,7 +732,7 @@ func (container *Container) Stop(seconds int) error {
732 732
 
733 733
 	// 2. Wait for the process to exit on its own
734 734
 	if err := container.WaitTimeout(time.Duration(seconds) * time.Second); err != nil {
735
-		log.Printf("Container %v failed to exit within %d seconds of SIGTERM - using the force", container.Id, seconds)
735
+		log.Printf("Container %v failed to exit within %d seconds of SIGTERM - using the force", container.ID, seconds)
736 736
 		if err := container.kill(); err != nil {
737 737
 			return err
738 738
 		}
... ...
@@ -796,7 +796,8 @@ func (container *Container) WaitTimeout(timeout time.Duration) error {
796 796
 	case <-done:
797 797
 		return nil
798 798
 	}
799
-	panic("unreachable")
799
+
800
+	panic("Unreachable")
800 801
 }
801 802
 
802 803
 func (container *Container) EnsureMounted() error {
... ...
@@ -839,16 +840,16 @@ func (container *Container) Unmount() error {
839 839
 	return Unmount(container.RootfsPath())
840 840
 }
841 841
 
842
-// ShortId returns a shorthand version of the container's id for convenience.
842
+// ShortID returns a shorthand version of the container's id for convenience.
843 843
 // A collision with other container shorthands is very unlikely, but possible.
844 844
 // In case of a collision a lookup with Runtime.Get() will fail, and the caller
845 845
 // will need to use a langer prefix, or the full-length container Id.
846
-func (container *Container) ShortId() string {
847
-	return utils.TruncateId(container.Id)
846
+func (container *Container) ShortID() string {
847
+	return utils.TruncateID(container.ID)
848 848
 }
849 849
 
850 850
 func (container *Container) logPath(name string) string {
851
-	return path.Join(container.root, fmt.Sprintf("%s-%s.log", container.Id, name))
851
+	return path.Join(container.root, fmt.Sprintf("%s-%s.log", container.ID, name))
852 852
 }
853 853
 
854 854
 func (container *Container) ReadLog(name string) (io.Reader, error) {
... ...
@@ -888,7 +889,7 @@ func (container *Container) rwPath() string {
888 888
 	return path.Join(container.root, "rw")
889 889
 }
890 890
 
891
-func validateId(id string) error {
891
+func validateID(id string) error {
892 892
 	if id == "" {
893 893
 		return fmt.Errorf("Invalid empty id")
894 894
 	}
... ...
@@ -14,7 +14,7 @@ import (
14 14
 	"time"
15 15
 )
16 16
 
17
-func TestIdFormat(t *testing.T) {
17
+func TestIDFormat(t *testing.T) {
18 18
 	runtime, err := newTestRuntime()
19 19
 	if err != nil {
20 20
 		t.Fatal(err)
... ...
@@ -22,19 +22,19 @@ func TestIdFormat(t *testing.T) {
22 22
 	defer nuke(runtime)
23 23
 	container1, err := NewBuilder(runtime).Create(
24 24
 		&Config{
25
-			Image: GetTestImage(runtime).Id,
25
+			Image: GetTestImage(runtime).ID,
26 26
 			Cmd:   []string{"/bin/sh", "-c", "echo hello world"},
27 27
 		},
28 28
 	)
29 29
 	if err != nil {
30 30
 		t.Fatal(err)
31 31
 	}
32
-	match, err := regexp.Match("^[0-9a-f]{64}$", []byte(container1.Id))
32
+	match, err := regexp.Match("^[0-9a-f]{64}$", []byte(container1.ID))
33 33
 	if err != nil {
34 34
 		t.Fatal(err)
35 35
 	}
36 36
 	if !match {
37
-		t.Fatalf("Invalid container ID: %s", container1.Id)
37
+		t.Fatalf("Invalid container ID: %s", container1.ID)
38 38
 	}
39 39
 }
40 40
 
... ...
@@ -46,7 +46,7 @@ func TestMultipleAttachRestart(t *testing.T) {
46 46
 	defer nuke(runtime)
47 47
 	container, err := NewBuilder(runtime).Create(
48 48
 		&Config{
49
-			Image: GetTestImage(runtime).Id,
49
+			Image: GetTestImage(runtime).ID,
50 50
 			Cmd: []string{"/bin/sh", "-c",
51 51
 				"i=1; while [ $i -le 5 ]; do i=`expr $i + 1`;  echo hello; done"},
52 52
 		},
... ...
@@ -153,7 +153,7 @@ func TestDiff(t *testing.T) {
153 153
 	// Create a container and remove a file
154 154
 	container1, err := builder.Create(
155 155
 		&Config{
156
-			Image: GetTestImage(runtime).Id,
156
+			Image: GetTestImage(runtime).ID,
157 157
 			Cmd:   []string{"/bin/rm", "/etc/passwd"},
158 158
 		},
159 159
 	)
... ...
@@ -194,7 +194,7 @@ func TestDiff(t *testing.T) {
194 194
 	// Create a new container from the commited image
195 195
 	container2, err := builder.Create(
196 196
 		&Config{
197
-			Image: img.Id,
197
+			Image: img.ID,
198 198
 			Cmd:   []string{"cat", "/etc/passwd"},
199 199
 		},
200 200
 	)
... ...
@@ -217,6 +217,37 @@ func TestDiff(t *testing.T) {
217 217
 			t.Fatalf("/etc/passwd should not be present in the diff after commit.")
218 218
 		}
219 219
 	}
220
+
221
+	// Create a new containere
222
+	container3, err := builder.Create(
223
+		&Config{
224
+			Image: GetTestImage(runtime).ID,
225
+			Cmd:   []string{"rm", "/bin/httpd"},
226
+		},
227
+	)
228
+	if err != nil {
229
+		t.Fatal(err)
230
+	}
231
+	defer runtime.Destroy(container3)
232
+
233
+	if err := container3.Run(); err != nil {
234
+		t.Fatal(err)
235
+	}
236
+
237
+	// Check the changelog
238
+	c, err = container3.Changes()
239
+	if err != nil {
240
+		t.Fatal(err)
241
+	}
242
+	success = false
243
+	for _, elem := range c {
244
+		if elem.Path == "/bin/httpd" && elem.Kind == 2 {
245
+			success = true
246
+		}
247
+	}
248
+	if !success {
249
+		t.Fatalf("/bin/httpd should be present in the diff after commit.")
250
+	}
220 251
 }
221 252
 
222 253
 func TestCommitAutoRun(t *testing.T) {
... ...
@@ -229,7 +260,7 @@ func TestCommitAutoRun(t *testing.T) {
229 229
 	builder := NewBuilder(runtime)
230 230
 	container1, err := builder.Create(
231 231
 		&Config{
232
-			Image: GetTestImage(runtime).Id,
232
+			Image: GetTestImage(runtime).ID,
233 233
 			Cmd:   []string{"/bin/sh", "-c", "echo hello > /world"},
234 234
 		},
235 235
 	)
... ...
@@ -260,7 +291,7 @@ func TestCommitAutoRun(t *testing.T) {
260 260
 	// FIXME: Make a TestCommit that stops here and check docker.root/layers/img.id/world
261 261
 	container2, err := builder.Create(
262 262
 		&Config{
263
-			Image: img.Id,
263
+			Image: img.ID,
264 264
 		},
265 265
 	)
266 266
 	if err != nil {
... ...
@@ -309,7 +340,7 @@ func TestCommitRun(t *testing.T) {
309 309
 
310 310
 	container1, err := builder.Create(
311 311
 		&Config{
312
-			Image: GetTestImage(runtime).Id,
312
+			Image: GetTestImage(runtime).ID,
313 313
 			Cmd:   []string{"/bin/sh", "-c", "echo hello > /world"},
314 314
 		},
315 315
 	)
... ...
@@ -341,7 +372,7 @@ func TestCommitRun(t *testing.T) {
341 341
 
342 342
 	container2, err := builder.Create(
343 343
 		&Config{
344
-			Image: img.Id,
344
+			Image: img.ID,
345 345
 			Cmd:   []string{"cat", "/world"},
346 346
 		},
347 347
 	)
... ...
@@ -388,7 +419,7 @@ func TestStart(t *testing.T) {
388 388
 	defer nuke(runtime)
389 389
 	container, err := NewBuilder(runtime).Create(
390 390
 		&Config{
391
-			Image:     GetTestImage(runtime).Id,
391
+			Image:     GetTestImage(runtime).ID,
392 392
 			Memory:    33554432,
393 393
 			CpuShares: 1000,
394 394
 			Cmd:       []string{"/bin/cat"},
... ...
@@ -432,7 +463,7 @@ func TestRun(t *testing.T) {
432 432
 	defer nuke(runtime)
433 433
 	container, err := NewBuilder(runtime).Create(
434 434
 		&Config{
435
-			Image: GetTestImage(runtime).Id,
435
+			Image: GetTestImage(runtime).ID,
436 436
 			Cmd:   []string{"ls", "-al"},
437 437
 		},
438 438
 	)
... ...
@@ -460,7 +491,7 @@ func TestOutput(t *testing.T) {
460 460
 	defer nuke(runtime)
461 461
 	container, err := NewBuilder(runtime).Create(
462 462
 		&Config{
463
-			Image: GetTestImage(runtime).Id,
463
+			Image: GetTestImage(runtime).ID,
464 464
 			Cmd:   []string{"echo", "-n", "foobar"},
465 465
 		},
466 466
 	)
... ...
@@ -484,7 +515,7 @@ func TestKillDifferentUser(t *testing.T) {
484 484
 	}
485 485
 	defer nuke(runtime)
486 486
 	container, err := NewBuilder(runtime).Create(&Config{
487
-		Image: GetTestImage(runtime).Id,
487
+		Image: GetTestImage(runtime).ID,
488 488
 		Cmd:   []string{"tail", "-f", "/etc/resolv.conf"},
489 489
 		User:  "daemon",
490 490
 	},
... ...
@@ -532,7 +563,7 @@ func TestKill(t *testing.T) {
532 532
 	}
533 533
 	defer nuke(runtime)
534 534
 	container, err := NewBuilder(runtime).Create(&Config{
535
-		Image: GetTestImage(runtime).Id,
535
+		Image: GetTestImage(runtime).ID,
536 536
 		Cmd:   []string{"cat", "/dev/zero"},
537 537
 	},
538 538
 	)
... ...
@@ -580,7 +611,7 @@ func TestExitCode(t *testing.T) {
580 580
 	builder := NewBuilder(runtime)
581 581
 
582 582
 	trueContainer, err := builder.Create(&Config{
583
-		Image: GetTestImage(runtime).Id,
583
+		Image: GetTestImage(runtime).ID,
584 584
 		Cmd:   []string{"/bin/true", ""},
585 585
 	})
586 586
 	if err != nil {
... ...
@@ -595,7 +626,7 @@ func TestExitCode(t *testing.T) {
595 595
 	}
596 596
 
597 597
 	falseContainer, err := builder.Create(&Config{
598
-		Image: GetTestImage(runtime).Id,
598
+		Image: GetTestImage(runtime).ID,
599 599
 		Cmd:   []string{"/bin/false", ""},
600 600
 	})
601 601
 	if err != nil {
... ...
@@ -617,7 +648,7 @@ func TestRestart(t *testing.T) {
617 617
 	}
618 618
 	defer nuke(runtime)
619 619
 	container, err := NewBuilder(runtime).Create(&Config{
620
-		Image: GetTestImage(runtime).Id,
620
+		Image: GetTestImage(runtime).ID,
621 621
 		Cmd:   []string{"echo", "-n", "foobar"},
622 622
 	},
623 623
 	)
... ...
@@ -650,7 +681,7 @@ func TestRestartStdin(t *testing.T) {
650 650
 	}
651 651
 	defer nuke(runtime)
652 652
 	container, err := NewBuilder(runtime).Create(&Config{
653
-		Image: GetTestImage(runtime).Id,
653
+		Image: GetTestImage(runtime).ID,
654 654
 		Cmd:   []string{"cat"},
655 655
 
656 656
 		OpenStdin: true,
... ...
@@ -732,7 +763,7 @@ func TestUser(t *testing.T) {
732 732
 
733 733
 	// Default user must be root
734 734
 	container, err := builder.Create(&Config{
735
-		Image: GetTestImage(runtime).Id,
735
+		Image: GetTestImage(runtime).ID,
736 736
 		Cmd:   []string{"id"},
737 737
 	},
738 738
 	)
... ...
@@ -750,7 +781,7 @@ func TestUser(t *testing.T) {
750 750
 
751 751
 	// Set a username
752 752
 	container, err = builder.Create(&Config{
753
-		Image: GetTestImage(runtime).Id,
753
+		Image: GetTestImage(runtime).ID,
754 754
 		Cmd:   []string{"id"},
755 755
 
756 756
 		User: "root",
... ...
@@ -770,7 +801,7 @@ func TestUser(t *testing.T) {
770 770
 
771 771
 	// Set a UID
772 772
 	container, err = builder.Create(&Config{
773
-		Image: GetTestImage(runtime).Id,
773
+		Image: GetTestImage(runtime).ID,
774 774
 		Cmd:   []string{"id"},
775 775
 
776 776
 		User: "0",
... ...
@@ -790,7 +821,7 @@ func TestUser(t *testing.T) {
790 790
 
791 791
 	// Set a different user by uid
792 792
 	container, err = builder.Create(&Config{
793
-		Image: GetTestImage(runtime).Id,
793
+		Image: GetTestImage(runtime).ID,
794 794
 		Cmd:   []string{"id"},
795 795
 
796 796
 		User: "1",
... ...
@@ -812,7 +843,7 @@ func TestUser(t *testing.T) {
812 812
 
813 813
 	// Set a different user by username
814 814
 	container, err = builder.Create(&Config{
815
-		Image: GetTestImage(runtime).Id,
815
+		Image: GetTestImage(runtime).ID,
816 816
 		Cmd:   []string{"id"},
817 817
 
818 818
 		User: "daemon",
... ...
@@ -841,7 +872,7 @@ func TestMultipleContainers(t *testing.T) {
841 841
 	builder := NewBuilder(runtime)
842 842
 
843 843
 	container1, err := builder.Create(&Config{
844
-		Image: GetTestImage(runtime).Id,
844
+		Image: GetTestImage(runtime).ID,
845 845
 		Cmd:   []string{"cat", "/dev/zero"},
846 846
 	},
847 847
 	)
... ...
@@ -851,7 +882,7 @@ func TestMultipleContainers(t *testing.T) {
851 851
 	defer runtime.Destroy(container1)
852 852
 
853 853
 	container2, err := builder.Create(&Config{
854
-		Image: GetTestImage(runtime).Id,
854
+		Image: GetTestImage(runtime).ID,
855 855
 		Cmd:   []string{"cat", "/dev/zero"},
856 856
 	},
857 857
 	)
... ...
@@ -897,7 +928,7 @@ func TestStdin(t *testing.T) {
897 897
 	}
898 898
 	defer nuke(runtime)
899 899
 	container, err := NewBuilder(runtime).Create(&Config{
900
-		Image: GetTestImage(runtime).Id,
900
+		Image: GetTestImage(runtime).ID,
901 901
 		Cmd:   []string{"cat"},
902 902
 
903 903
 		OpenStdin: true,
... ...
@@ -944,7 +975,7 @@ func TestTty(t *testing.T) {
944 944
 	}
945 945
 	defer nuke(runtime)
946 946
 	container, err := NewBuilder(runtime).Create(&Config{
947
-		Image: GetTestImage(runtime).Id,
947
+		Image: GetTestImage(runtime).ID,
948 948
 		Cmd:   []string{"cat"},
949 949
 
950 950
 		OpenStdin: true,
... ...
@@ -991,7 +1022,7 @@ func TestEnv(t *testing.T) {
991 991
 	}
992 992
 	defer nuke(runtime)
993 993
 	container, err := NewBuilder(runtime).Create(&Config{
994
-		Image: GetTestImage(runtime).Id,
994
+		Image: GetTestImage(runtime).ID,
995 995
 		Cmd:   []string{"/usr/bin/env"},
996 996
 	},
997 997
 	)
... ...
@@ -1069,7 +1100,7 @@ func TestLXCConfig(t *testing.T) {
1069 1069
 	cpuMax := 10000
1070 1070
 	cpu := cpuMin + rand.Intn(cpuMax-cpuMin)
1071 1071
 	container, err := NewBuilder(runtime).Create(&Config{
1072
-		Image: GetTestImage(runtime).Id,
1072
+		Image: GetTestImage(runtime).ID,
1073 1073
 		Cmd:   []string{"/bin/true"},
1074 1074
 
1075 1075
 		Hostname:  "foobar",
... ...
@@ -1097,7 +1128,7 @@ func BenchmarkRunSequencial(b *testing.B) {
1097 1097
 	defer nuke(runtime)
1098 1098
 	for i := 0; i < b.N; i++ {
1099 1099
 		container, err := NewBuilder(runtime).Create(&Config{
1100
-			Image: GetTestImage(runtime).Id,
1100
+			Image: GetTestImage(runtime).ID,
1101 1101
 			Cmd:   []string{"echo", "-n", "foo"},
1102 1102
 		},
1103 1103
 		)
... ...
@@ -1132,7 +1163,7 @@ func BenchmarkRunParallel(b *testing.B) {
1132 1132
 		tasks = append(tasks, complete)
1133 1133
 		go func(i int, complete chan error) {
1134 1134
 			container, err := NewBuilder(runtime).Create(&Config{
1135
-				Image: GetTestImage(runtime).Id,
1135
+				Image: GetTestImage(runtime).ID,
1136 1136
 				Cmd:   []string{"echo", "-n", "foo"},
1137 1137
 			},
1138 1138
 			)
... ...
@@ -11,13 +11,13 @@ import (
11 11
 	"time"
12 12
 )
13 13
 
14
-var DOCKER_PATH string = path.Join(os.Getenv("DOCKERPATH"), "docker")
14
+var DOCKERPATH = path.Join(os.Getenv("DOCKERPATH"), "docker")
15 15
 
16 16
 // WARNING: this crashTest will 1) crash your host, 2) remove all containers
17 17
 func runDaemon() (*exec.Cmd, error) {
18 18
 	os.Remove("/var/run/docker.pid")
19 19
 	exec.Command("rm", "-rf", "/var/lib/docker/containers").Run()
20
-	cmd := exec.Command(DOCKER_PATH, "-d")
20
+	cmd := exec.Command(DOCKERPATH, "-d")
21 21
 	outPipe, err := cmd.StdoutPipe()
22 22
 	if err != nil {
23 23
 		return nil, err
... ...
@@ -77,7 +77,7 @@ func crashTest() error {
77 77
 			stop = false
78 78
 			for i := 0; i < 100 && !stop; {
79 79
 				func() error {
80
-					cmd := exec.Command(DOCKER_PATH, "run", "base", "echo", fmt.Sprintf("%d", totalTestCount))
80
+					cmd := exec.Command(DOCKERPATH, "run", "base", "echo", fmt.Sprintf("%d", totalTestCount))
81 81
 					i++
82 82
 					totalTestCount++
83 83
 					outPipe, err := cmd.StdoutPipe()
... ...
@@ -2,18 +2,15 @@
2 2
 set -e
3 3
 
4 4
 # these should match the names found at http://www.debian.org/releases/
5
-stableSuite='squeeze'
6
-testingSuite='wheezy'
5
+stableSuite='wheezy'
6
+testingSuite='jessie'
7 7
 unstableSuite='sid'
8 8
 
9
-# if suite is equal to this, it gets the "latest" tag
10
-latestSuite="$testingSuite"
11
-
12 9
 variant='minbase'
13 10
 include='iproute,iputils-ping'
14 11
 
15 12
 repo="$1"
16
-suite="${2:-$latestSuite}"
13
+suite="${2:-$stableSuite}"
17 14
 mirror="${3:-}" # stick to the default debootstrap mirror if one is not provided
18 15
 
19 16
 if [ ! "$repo" ]; then
... ...
@@ -41,17 +38,14 @@ img=$(sudo tar -c . | docker import -)
41 41
 # tag suite
42 42
 docker tag $img $repo $suite
43 43
 
44
-if [ "$suite" = "$latestSuite" ]; then
45
-	# tag latest
46
-	docker tag $img $repo latest
47
-fi
48
-
49 44
 # test the image
50 45
 docker run -i -t $repo:$suite echo success
51 46
 
52
-# unstable's version numbers match testing (since it's mostly just a sandbox for testing), so it doesn't get a version number tag
53
-if [ "$suite" != "$unstableSuite" -a "$suite" != 'unstable' ]; then
54
-	# tag the specific version
47
+if [ "$suite" = "$stableSuite" -o "$suite" = 'stable' ]; then
48
+	# tag latest
49
+	docker tag $img $repo latest
50
+	
51
+	# tag the specific debian release version
55 52
 	ver=$(docker run $repo:$suite cat /etc/debian_version)
56 53
 	docker tag $img $repo $ver
57 54
 fi
... ...
@@ -15,7 +15,7 @@ import (
15 15
 )
16 16
 
17 17
 var (
18
-	GIT_COMMIT string
18
+	GITCOMMIT string
19 19
 )
20 20
 
21 21
 func main() {
... ...
@@ -59,7 +59,7 @@ func main() {
59 59
 	if *flDebug {
60 60
 		os.Setenv("DEBUG", "1")
61 61
 	}
62
-	docker.GIT_COMMIT = GIT_COMMIT
62
+	docker.GITCOMMIT = GITCOMMIT
63 63
 	if *flDaemon {
64 64
 		if flag.NArg() != 0 {
65 65
 			flag.Usage()
... ...
@@ -6,6 +6,7 @@ SPHINXOPTS    =
6 6
 SPHINXBUILD   = sphinx-build
7 7
 PAPER         =
8 8
 BUILDDIR      = _build
9
+PYTHON        = python
9 10
 
10 11
 # Internal variables.
11 12
 PAPEROPT_a4     = -D latex_paper_size=a4
... ...
@@ -38,6 +39,7 @@ help:
38 38
 #	@echo "  linkcheck  to check all external links for integrity"
39 39
 #	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
40 40
 	@echo "  docs       to build the docs and copy the static files to the outputdir"
41
+	@echo "  server     to serve the docs in your browser under \`http://localhost:8000\`"
41 42
 	@echo "  publish    to publish the app to dotcloud"
42 43
 
43 44
 clean:
... ...
@@ -49,6 +51,8 @@ docs:
49 49
 	@echo
50 50
 	@echo "Build finished. The documentation pages are now in $(BUILDDIR)/html."
51 51
 
52
+server:
53
+	@cd $(BUILDDIR)/html; $(PYTHON) -m SimpleHTTPServer 8000
52 54
 
53 55
 site:
54 56
 	cp -r website $(BUILDDIR)/
... ...
@@ -59,7 +63,7 @@ site:
59 59
 connect:
60 60
 	@echo connecting dotcloud to www.docker.io website, make sure to use user 1
61 61
 	@cd _build/website/ ; \
62
-	dotcloud connect dockerwebsite ;
62
+	dotcloud connect dockerwebsite ; \
63 63
 	dotcloud list
64 64
 
65 65
 push:
... ...
@@ -14,20 +14,22 @@ Installation
14 14
 ------------
15 15
 
16 16
 * Work in your own fork of the code, we accept pull requests.
17
-* Install sphinx: ``pip install sphinx``
18
-* Install sphinx httpdomain contrib package ``sphinxcontrib-httpdomain``
17
+* Install sphinx: `pip install sphinx`
18
+    * Mac OS X: `[sudo] pip-2.7 install sphinx`)
19
+* Install sphinx httpdomain contrib package: `pip install sphinxcontrib-httpdomain`
20
+    * Mac OS X: `[sudo] pip-2.7 install sphinxcontrib-httpdomain`
19 21
 * If pip is not available you can probably install it using your favorite package manager as **python-pip**
20 22
 
21 23
 Usage
22 24
 -----
23
-* change the .rst files with your favorite editor to your liking
24
-* run *make docs* to clean up old files and generate new ones
25
-* your static website can now be found in the _build dir
26
-* to preview what you have generated, cd into _build/html and then run 'python -m SimpleHTTPServer 8000'
25
+* Change the `.rst` files with your favorite editor to your liking.
26
+* Run `make docs` to clean up old files and generate new ones.
27
+* Your static website can now be found in the `_build` directory.
28
+* To preview what you have generated run `make server` and open <http://localhost:8000/> in your favorite browser.
27 29
 
28
-Working using github's file editor
30
+Working using GitHub's file editor
29 31
 ----------------------------------
30
-Alternatively, for small changes and typo's you might want to use github's built in file editor. It allows
32
+Alternatively, for small changes and typo's you might want to use GitHub's built in file editor. It allows
31 33
 you to preview your changes right online. Just be carefull not to create many commits.
32 34
 
33 35
 Images
... ...
@@ -72,4 +74,4 @@ Guides on using sphinx
72 72
 
73 73
 * Code examples
74 74
 
75
-  Start without $, so it's easy to copy and paste.
76 75
\ No newline at end of file
76
+  Start without $, so it's easy to copy and paste.
... ...
@@ -15,10 +15,17 @@ Docker Remote API
15 15
 - Default port in the docker deamon is 4243 
16 16
 - The API tends to be REST, but for some complex commands, like attach or pull, the HTTP connection is hijacked to transport stdout stdin and stderr
17 17
 
18
-2. Endpoints
18
+2. Version
19
+==========
20
+
21
+The current verson of the API is 1.1
22
+Calling /images/<name>/insert is the same as calling /v1.1/images/<name>/insert
23
+You can still call an old version of the api using /v1.0/images/<name>/insert
24
+
25
+3. Endpoints
19 26
 ============
20 27
 
21
-2.1 Containers
28
+3.1 Containers
22 29
 --------------
23 30
 
24 31
 List containers
... ...
@@ -132,6 +139,7 @@ Create a container
132 132
 	:jsonparam config: the container's configuration
133 133
 	:statuscode 201: no error
134 134
 	:statuscode 404: no such container
135
+	:statuscode 406: impossible to attach (container not running)
135 136
 	:statuscode 500: server error
136 137
 
137 138
 
... ...
@@ -459,7 +467,7 @@ Remove a container
459 459
         :statuscode 500: server error
460 460
 
461 461
 
462
-2.2 Images
462
+3.2 Images
463 463
 ----------
464 464
 
465 465
 List Images
... ...
@@ -548,7 +556,19 @@ Create an image
548 548
 
549 549
            POST /images/create?fromImage=base HTTP/1.1
550 550
 
551
-        **Example response**:
551
+        **Example response v1.1**:
552
+
553
+        .. sourcecode:: http
554
+
555
+           HTTP/1.1 200 OK
556
+	   Content-Type: application/json
557
+
558
+	   {"status":"Pulling..."}
559
+	   {"status":"Pulling", "progress":"1/? (n/a)"}
560
+	   {"error":"Invalid..."}
561
+	   ...
562
+
563
+        **Example response v1.0**:
552 564
 
553 565
         .. sourcecode:: http
554 566
 
... ...
@@ -579,7 +599,19 @@ Insert a file in a image
579 579
 
580 580
            POST /images/test/insert?path=/usr&url=myurl HTTP/1.1
581 581
 
582
-	**Example response**:
582
+	**Example response v1.1**:
583
+
584
+        .. sourcecode:: http
585
+
586
+           HTTP/1.1 200 OK
587
+	   Content-Type: application/json
588
+
589
+	   {"status":"Inserting..."}
590
+	   {"status":"Inserting", "progress":"1/? (n/a)"}
591
+	   {"error":"Invalid..."}
592
+	   ...
593
+
594
+	**Example response v1.0**:
583 595
 
584 596
         .. sourcecode:: http
585 597
 
... ...
@@ -694,7 +726,19 @@ Push an image on the registry
694 694
 
695 695
 	    POST /images/test/push HTTP/1.1
696 696
 
697
-	 **Example response**:
697
+	 **Example response v1.1**:
698
+
699
+        .. sourcecode:: http
700
+
701
+           HTTP/1.1 200 OK
702
+	   Content-Type: application/json
703
+
704
+	   {"status":"Pushing..."}
705
+	   {"status":"Pushing", "progress":"1/? (n/a)"}
706
+	   {"error":"Invalid..."}
707
+	   ...
708
+
709
+	 **Example response v1.0**:
698 710
 
699 711
         .. sourcecode:: http
700 712
 
... ...
@@ -800,7 +844,7 @@ Search images
800 800
 	   :statuscode 500: server error
801 801
 
802 802
 
803
-2.3 Misc
803
+3.3 Misc
804 804
 --------
805 805
 
806 806
 Build an image from Dockerfile via stdin
... ...
@@ -826,6 +870,7 @@ Build an image from Dockerfile via stdin
826 826
 	   
827 827
 	   {{ STREAM }}
828 828
 
829
+	:query t: tag to be applied to the resulting image in case of success
829 830
 	:statuscode 200: no error
830 831
         :statuscode 500: server error
831 832
 
... ...
@@ -912,10 +957,12 @@ Display system-wide information
912 912
 
913 913
 	   {
914 914
 		"Containers":11,
915
-		"Version":"0.2.2",
916 915
 		"Images":16,
917
-		"GoVersion":"go1.0.3",
918
-		"Debug":false
916
+		"Debug":false,
917
+		"NFd": 11,
918
+		"NGoroutines":21,
919
+		"MemoryLimit":true,
920
+		"SwapLimit":false
919 921
 	   }
920 922
 
921 923
         :statuscode 200: no error
... ...
@@ -941,12 +988,11 @@ Show the docker version information
941 941
 
942 942
            HTTP/1.1 200 OK
943 943
 	   Content-Type: application/json
944
-	   
944
+
945 945
 	   {
946 946
 		"Version":"0.2.2",
947 947
 		"GitCommit":"5a2a5cc+CHANGES",
948
-		"MemoryLimit":true,
949
-		"SwapLimit":false
948
+		"GoVersion":"go1.0.3"
950 949
 	   }
951 950
 
952 951
         :statuscode 200: no error
... ...
@@ -2,8 +2,8 @@
2 2
 :description: docker documentation
3 3
 :keywords: docker, ipa, documentation
4 4
 
5
-API's
6
-=============
5
+APIs
6
+====
7 7
 
8 8
 This following :
9 9
 
... ...
@@ -246,7 +246,6 @@ The Index has two main purposes (along with its fancy social features):
246 246
 
247 247
 - Resolve short names (to avoid passing absolute URLs all the time)
248 248
    - username/projectname -> \https://registry.docker.io/users/<username>/repositories/<projectname>/
249
-   - team/projectname -> \https://registry.docker.io/team/<team>/repositories/<projectname>/
250 249
 - Authenticate a user as a repos owner (for a central referenced repository)
251 250
 
252 251
 3.1 Without an Index
... ...
@@ -2,12 +2,27 @@
2 2
 :description: Build a new image from the Dockerfile passed via stdin
3 3
 :keywords: build, docker, container, documentation
4 4
 
5
-========================================================
6
-``build`` -- Build a container from Dockerfile via stdin
7
-========================================================
5
+================================================
6
+``build`` -- Build a container from a Dockerfile
7
+================================================
8 8
 
9 9
 ::
10 10
 
11
-    Usage: docker build -
12
-    Example: cat Dockerfile | docker build -
13
-    Build a new image from the Dockerfile passed via stdin
11
+    Usage: docker build [OPTIONS] PATH | -
12
+    Build a new container image from the source code at PATH
13
+      -t="": Tag to be applied to the resulting image in case of success.
14
+
15
+Examples
16
+--------
17
+
18
+.. code-block:: bash
19
+
20
+    docker build .
21
+
22
+This will take the local Dockerfile
23
+
24
+.. code-block:: bash
25
+
26
+    docker build -
27
+
28
+This will read a Dockerfile form Stdin without context
... ...
@@ -5,8 +5,8 @@
5 5
 Introduction
6 6
 ============
7 7
 
8
-Docker - The Linux container runtime
8
+Docker -- The Linux container runtime
9
+-------------------------------------
9 10
 
10 11
 Docker complements LXC with a high-level API which operates at the process level. It runs unix processes with strong guarantees of isolation and repeatability across servers.
11 12
 
... ...
@@ -1,8 +1,8 @@
1
-:title: Setting up a dev environment
1
+:title: Setting Up a Dev Environment
2 2
 :description: Guides on how to contribute to docker
3 3
 :keywords: Docker, documentation, developers, contributing, dev environment
4 4
 
5
-Setting up a dev environment
5
+Setting Up a Dev Environment
6 6
 ============================
7 7
 
8 8
 Instructions that have been verified to work on Ubuntu 12.10,
... ...
@@ -4,8 +4,8 @@
4 4
 
5 5
 .. _running_couchdb_service:
6 6
 
7
-Create a CouchDB service
8
-========================
7
+CouchDB Service
8
+===============
9 9
 
10 10
 .. include:: example_header.inc
11 11
 
... ...
@@ -1,6 +1,6 @@
1 1
 :title: Docker Examples
2 2
 :description: Examples on how to use Docker
3
-:keywords: docker, hello world, examples
3
+:keywords: docker, hello world, node, nodejs, python, couch, couchdb, redis, ssh, sshd, examples
4 4
 
5 5
 
6 6
 
... ...
@@ -16,6 +16,7 @@ Contents:
16 16
    hello_world
17 17
    hello_world_daemon
18 18
    python_web_app
19
+   nodejs_web_app
19 20
    running_redis_service
20 21
    running_ssh_service
21 22
    couchdb_data_volumes
22 23
new file mode 100644
... ...
@@ -0,0 +1,236 @@
0
+:title: Running a Node.js app on CentOS
1
+:description: Installing and running a Node.js app on CentOS
2
+:keywords: docker, example, package installation, node, centos
3
+
4
+.. _nodejs_web_app:
5
+
6
+Node.js Web App
7
+===============
8
+
9
+.. include:: example_header.inc
10
+
11
+The goal of this example is to show you how you can build your own docker images
12
+from a parent image using a ``Dockerfile`` . We will do that by making a simple
13
+Node.js hello world web application running on CentOS. You can get the full
14
+source code at https://github.com/gasi/docker-node-hello.
15
+
16
+Create Node.js app
17
+
18
+First, create a ``package.json`` file that describes your app and its
19
+dependencies:
20
+
21
+.. code-block:: json
22
+
23
+    {
24
+      "name": "docker-centos-hello",
25
+      "private": true,
26
+      "version": "0.0.1",
27
+      "description": "Node.js Hello World app on CentOS using docker",
28
+      "author": "Daniel Gasienica <daniel@gasienica.ch>",
29
+      "dependencies": {
30
+        "express": "3.2.4"
31
+      }
32
+    }
33
+
34
+Then, create an ``index.js`` file that defines a web app using the
35
+`Express.js <http://expressjs.com/>`_ framework:
36
+
37
+.. code-block:: javascript
38
+
39
+    var express = require('express');
40
+
41
+    // Constants
42
+    var PORT = 8080;
43
+
44
+    // App
45
+    var app = express();
46
+    app.get('/', function (req, res) {
47
+      res.send('Hello World\n');
48
+    });
49
+
50
+    app.listen(PORT)
51
+    console.log('Running on http://localhost:' + PORT);
52
+
53
+
54
+In the next steps, we’ll look at how you can run this app inside a CentOS
55
+container using docker. First, you’ll need to build a docker image of your app.
56
+
57
+Creating a ``Dockerfile``
58
+
59
+Create an empty file called ``Dockerfile``:
60
+
61
+.. code-block:: bash
62
+
63
+    touch Dockerfile
64
+
65
+Open the ``Dockerfile`` in your favorite text editor and add the following line
66
+that defines the version of docker the image requires to build
67
+(this example uses docker 0.3.4):
68
+
69
+.. code-block:: bash
70
+
71
+    # DOCKER-VERSION 0.3.4
72
+
73
+Next, define the parent image you want to use to build your own image on top of.
74
+Here, we’ll use `CentOS <https://index.docker.io/_/centos/>`_ (tag: ``6.4``)
75
+available on the `docker index`_:
76
+
77
+.. code-block:: bash
78
+
79
+    FROM    centos:6.4
80
+
81
+Since we’re building a Node.js app, you’ll have to install Node.js as well as
82
+npm on your CentOS image. Node.js is required to run your app and npm to install
83
+your app’s dependencies defined in ``package.json``.
84
+To install the right package for CentOS, we’ll use the instructions from the
85
+`Node.js wiki`_:
86
+
87
+.. code-block:: bash
88
+
89
+    # Enable EPEL for Node.js
90
+    RUN     rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
91
+    # Install Node.js and npm
92
+    RUN     yum install -y npm-1.2.17-5.el6
93
+
94
+To bundle your app’s source code inside the docker image, use the ``ADD``
95
+command:
96
+
97
+.. code-block:: bash
98
+
99
+    # Bundle app source
100
+    ADD . /src
101
+
102
+Install your app dependencies using npm:
103
+
104
+.. code-block:: bash
105
+
106
+    # Install app dependencies
107
+    RUN cd /src; npm install
108
+
109
+Your app binds to port ``8080`` so you’ll use the ``EXPOSE`` command to have it
110
+mapped by the docker daemon:
111
+
112
+.. code-block:: bash
113
+
114
+    EXPOSE  8080
115
+
116
+Last but not least, define the command to run your app using ``CMD`` which
117
+defines your runtime, i.e. ``node``, and the path to our app, i.e.
118
+``src/index.js`` (see the step where we added the source to the container):
119
+
120
+.. code-block:: bash
121
+
122
+    CMD ["node", "/src/index.js"]
123
+
124
+Your ``Dockerfile`` should now look like this:
125
+
126
+.. code-block:: bash
127
+
128
+
129
+    # DOCKER-VERSION 0.3.4
130
+    FROM    centos:6.4
131
+
132
+    # Enable EPEL for Node.js
133
+    RUN     rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
134
+    # Install Node.js and npm
135
+    RUN     yum install -y npm-1.2.17-5.el6
136
+
137
+    # Bundle app source
138
+    ADD . /src
139
+    # Install app dependencies
140
+    RUN cd /src; npm install
141
+
142
+    EXPOSE  8080
143
+    CMD ["node", "/src/index.js"]
144
+
145
+
146
+Building your image
147
+
148
+Go to the directory that has your ``Dockerfile`` and run the following command
149
+to build a docker image. The ``-t`` flag let’s you tag your image so it’s easier
150
+to find later using the ``docker images`` command:
151
+
152
+.. code-block:: bash
153
+
154
+    docker build -t <your username>/centos-node-hello .
155
+
156
+Your image will now be listed by docker:
157
+
158
+.. code-block:: bash
159
+
160
+    docker images
161
+
162
+    > # Example
163
+    > REPOSITORY                 TAG       ID              CREATED
164
+    > centos                     6.4       539c0211cd76    8 weeks ago
165
+    > gasi/centos-node-hello     latest    d64d3505b0d2    2 hours ago
166
+
167
+
168
+Run the image
169
+
170
+Running your image with ``-d`` runs the container in detached mode, leaving the
171
+container running in the background. Run the image you previously built:
172
+
173
+.. code-block:: bash
174
+
175
+    docker run -d <your username>/centos-node-hello
176
+
177
+Print the output of your app:
178
+
179
+.. code-block:: bash
180
+
181
+    # Get container ID
182
+    docker ps
183
+
184
+    # Print app output
185
+    docker logs <container id>
186
+
187
+    > # Example
188
+    > Running on http://localhost:8080
189
+
190
+
191
+Test
192
+
193
+To test your app, get the the port of your app that docker mapped:
194
+
195
+.. code-block:: bash
196
+
197
+    docker ps
198
+
199
+    > # Example
200
+    > ID            IMAGE                          COMMAND              ...   PORTS
201
+    > ecce33b30ebf  gasi/centos-node-hello:latest  node /src/index.js         49160->8080
202
+
203
+In the example above, docker mapped the ``8080`` port of the container to
204
+``49160``.
205
+
206
+Now you can call your app using ``curl`` (install if needed via:
207
+``sudo apt-get install curl``):
208
+
209
+.. code-block:: bash
210
+
211
+    curl -i localhost:49160
212
+
213
+    > HTTP/1.1 200 OK
214
+    > X-Powered-By: Express
215
+    > Content-Type: text/html; charset=utf-8
216
+    > Content-Length: 12
217
+    > Date: Sun, 02 Jun 2013 03:53:22 GMT
218
+    > Connection: keep-alive
219
+    >
220
+    > Hello World
221
+
222
+We hope this tutorial helped you get up and running with Node.js and CentOS on
223
+docker. You can get the full source code at
224
+https://github.com/gasi/docker-node-hello.
225
+
226
+Continue to :ref:`running_redis_service`.
227
+
228
+
229
+.. _Node.js wiki: https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#rhelcentosscientific-linux-6
230
+.. _docker index: https://index.docker.io/
... ...
@@ -4,8 +4,8 @@
4 4
 
5 5
 .. _python_web_app:
6 6
 
7
-Building a python web app
8
-=========================
7
+Python Web App
8
+==============
9 9
 
10 10
 .. include:: example_header.inc
11 11
 
... ...
@@ -4,7 +4,7 @@
4 4
 
5 5
 .. _running_examples:
6 6
 
7
-Running The Examples
7
+Running the Examples
8 8
 --------------------
9 9
 
10 10
 All the examples assume your machine is running the docker daemon. To run the docker daemon in the background, simply type:
... ...
@@ -4,8 +4,8 @@
4 4
 
5 5
 .. _running_redis_service:
6 6
 
7
-Create a redis service
8
-======================
7
+Redis Service
8
+=============
9 9
 
10 10
 .. include:: example_header.inc
11 11
 
... ...
@@ -34,7 +34,7 @@ Snapshot the installation
34 34
 
35 35
 .. code-block:: bash
36 36
 
37
-    docker ps -a  # grab the container id (this will be the last one in the list)
37
+    docker ps -a  # grab the container id (this will be the first one in the list)
38 38
     docker commit <container_id> <your username>/redis
39 39
 
40 40
 Run the service
... ...
@@ -4,8 +4,8 @@
4 4
 
5 5
 .. _running_ssh_service:
6 6
 
7
-Create an ssh daemon service
8
-============================
7
+SSH Daemon Service
8
+==================
9 9
 
10 10
 .. include:: example_header.inc
11 11
 
... ...
@@ -20,8 +20,7 @@ minutes and not entirely smooth, but gives you a good idea.
20 20
     <div style="margin-top:10px;">
21 21
       <iframe width="800" height="400" src="http://ascii.io/a/2637/raw" frameborder="0"></iframe>
22 22
     </div>
23
-
24
-
23
+	
25 24
 You can also get this sshd container by using
26 25
 ::
27 26
 
... ...
@@ -30,3 +29,49 @@ You can also get this sshd container by using
30 30
 
31 31
 The password is 'screencast'
32 32
 
33
+**Video's Transcription:**
34
+
35
+.. code-block:: bash
36
+
37
+	 # Hello! We are going to try and install openssh on a container and run it as a servic 
38
+	 # let's pull base to get a base ubuntu image. 
39
+	 $ docker pull base
40
+	 # I had it so it was quick
41
+	 # now let's connect using -i for interactive and with -t for terminal 
42
+	 # we execute /bin/bash to get a prompt.
43
+	 $ docker run -i -t base /bin/bash
44
+	 # now let's commit it 
45
+	 # which container was it?
46
+	 $ docker ps -a |more
47
+	 $ docker commit a30a3a2f2b130749995f5902f079dc6ad31ea0621fac595128ec59c6da07feea dhrp/sshd 
48
+	 # I gave the name dhrp/sshd for the container
49
+	 # now we can run it again 
50
+	 $ docker run -d dhrp/sshd /usr/sbin/sshd -D # D for daemon mode 
51
+	 # is it running?
52
+	 $ docker ps
53
+	 # yes!
54
+	 # let's stop it 
55
+	 $ docker stop 0ebf7cec294755399d063f4b1627980d4cbff7d999f0bc82b59c300f8536a562
56
+	 $ docker ps
57
+	 # and reconnect, but now open a port to it
58
+	 $ docker run -d -p 22 dhrp/sshd /usr/sbin/sshd -D 
59
+	 $ docker port b2b407cf22cf8e7fa3736fa8852713571074536b1d31def3fdfcd9fa4fd8c8c5 22
60
+	 # it has now given us a port to connect to
61
+	 # we have to connect using a public ip of our host
62
+	 $ hostname
63
+	 $ ifconfig
64
+	 $ ssh root@192.168.33.10 -p 49153
65
+	 # Ah! forgot to set root passwd
66
+	 $ docker commit b2b407cf22cf8e7fa3736fa8852713571074536b1d31def3fdfcd9fa4fd8c8c5 dhrp/sshd 
67
+	 $ docker ps -a
68
+	 $ docker run -i -t dhrp/sshd /bin/bash
69
+	 $ passwd
70
+	 $ exit
71
+	 $ docker commit 9e863f0ca0af31c8b951048ba87641d67c382d08d655c2e4879c51410e0fedc1 dhrp/sshd
72
+	 $ docker run -d -p 22 dhrp/sshd /usr/sbin/sshd -D
73
+	 $ docker port a0aaa9558c90cf5c7782648df904a82365ebacce523e4acc085ac1213bfe2206 22
74
+	 $ ifconfig
75
+	 $ ssh root@192.168.33.10 -p 49154
76
+	 # Thanks for watching, Thatcher thatcher@dotcloud.com
77
+
78
+
... ...
@@ -19,7 +19,8 @@ Most frequently asked questions.
19 19
 
20 20
 3. **Does Docker run on Mac OS X or Windows?**
21 21
 
22
-   Not at this time, Docker currently only runs on Linux, but you can use VirtualBox to run Docker in a virtual machine on your box, and get the best of both worlds. Check out the MacOSX_ and Windows_ installation guides.
22
+   Not at this time, Docker currently only runs on Linux, but you can use VirtualBox to run Docker in a
23
+   virtual machine on your box, and get the best of both worlds. Check out the :ref:`install_using_vagrant` and :ref:`windows` installation guides.
23 24
 
24 25
 4. **How do containers compare to virtual machines?**
25 26
 
... ...
@@ -39,10 +40,8 @@ Most frequently asked questions.
39 39
     * `Ask questions on Stackoverflow`_
40 40
     * `Join the conversation on Twitter`_
41 41
 
42
-    .. _Windows: ../installation/windows/
43
-    .. _MacOSX: ../installation/vagrant/
44 42
     .. _the repo: http://www.github.com/dotcloud/docker
45
-    .. _IRC\: docker on freenode: irc://chat.freenode.net#docker
43
+    .. _IRC: docker on freenode: docker on freenode: irc://chat.freenode.net#docker
46 44
     .. _Github: http://www.github.com/dotcloud/docker
47 45
     .. _Ask questions on Stackoverflow: http://stackoverflow.com/search?q=docker
48 46
     .. _Join the conversation on Twitter: http://twitter.com/getdocker
... ...
@@ -7,8 +7,8 @@
7 7
 Introduction
8 8
 ============
9 9
 
10
-Docker - The Linux container runtime
10
+Docker -- The Linux container runtime
11
+-------------------------------------
11 12
 
12 13
 Docker complements LXC with a high-level API which operates at the process level. It runs unix processes with strong guarantees of isolation and repeatability across servers.
13 14
 
... ...
@@ -92,6 +92,16 @@ have AUFS filesystem support enabled, so we need to install it.
92 92
    sudo apt-get update
93 93
    sudo apt-get install linux-image-extra-`uname -r`
94 94
 
95
+**add-apt-repository support**
96
+
97
+Some installations of Ubuntu 13.04 require ``software-properties-common`` to be
98
+installed before being able to use add-apt-repository.
99
+
100
+.. code-block:: bash
101
+
102
+  sudo apt-get install software-properties-common
103
+
104
+
95 105
 Installation
96 106
 ------------
97 107
 
... ...
@@ -2,6 +2,7 @@
2 2
 :description: Docker's tutorial to run docker on Windows
3 3
 :keywords: Docker, Docker documentation, Windows, requirements, virtualbox, vagrant, git, ssh, putty, cygwin
4 4
 
5
+.. _windows:
5 6
 
6 7
 Using Vagrant (Windows)
7 8
 =======================
... ...
@@ -3,8 +3,8 @@
3 3
 :keywords: Examples, Usage, basic commands, docker, documentation, examples
4 4
 
5 5
 
6
-The basics
7
-=============
6
+The Basics
7
+==========
8 8
 
9 9
 Starting Docker
10 10
 ---------------
... ...
@@ -125,8 +125,14 @@ curl was installed within the image.
125 125
 .. note::
126 126
     The path must include the file name.
127 127
 
128
-.. note::
129
-    This instruction has temporarily disabled
128
+2.8 ADD
129
+-------
130
+
131
+    ``ADD <src> <dest>``
132
+
133
+The `ADD` instruction will insert the files from the `<src>` path of the context into `<dest>` path 
134
+of the container.
135
+The context must be set in order to use this instruction. (see examples)
130 136
 
131 137
 3. Dockerfile Examples
132 138
 ======================
... ...
@@ -4,8 +4,8 @@
4 4
 
5 5
 .. _working_with_the_repository:
6 6
 
7
-Working with the repository
8
-============================
7
+Working with the Repository
8
+===========================
9 9
 
10 10
 
11 11
 Top-level repositories and user repositories
... ...
@@ -14,9 +14,9 @@ Top-level repositories and user repositories
14 14
 Generally, there are two types of repositories: Top-level repositories which are controlled by the people behind
15 15
 Docker, and user repositories.
16 16
 
17
-* Top-level repositories can easily be recognized by not having a / (slash) in their name. These repositories can
17
+* Top-level repositories can easily be recognized by not having a ``/`` (slash) in their name. These repositories can
18 18
   generally be trusted.
19
-* User repositories always come in the form of <username>/<repo_name>. This is what your published images will look like.
19
+* User repositories always come in the form of ``<username>/<repo_name>``. This is what your published images will look like.
20 20
 * User images are not checked, it is therefore up to you whether or not you trust the creator of this image.
21 21
 
22 22
 
... ...
@@ -62,7 +62,7 @@
62 62
 </div>
63 63
 
64 64
 <div class="container">
65
-    <div class="alert alert-info">
65
+    <div class="alert alert-info" style="margin-bottom: 0;">
66 66
         <strong>Docker is still under heavy development.</strong> It should not yet be used in production. Check <a href="http://github.com/dotcloud/docker">the repo</a> for recent progress.
67 67
     </div>
68 68
     <div class="row">
... ...
@@ -133,13 +133,13 @@
133 133
             </section>
134 134
 
135 135
             <section class="contentblock">
136
-                <h2>More resources</h2>
137
-                <ul>
138
-                    <li><a href="irc://chat.freenode.net#docker">IRC: docker on freenode</a></li>
139
-                    <li><a href="http://www.github.com/dotcloud/docker">Github</a></li>
140
-                    <li><a href="http://stackoverflow.com/tags/docker/">Ask questions on Stackoverflow</a></li>
141
-                    <li><a href="http://twitter.com/getdocker/">Join the conversation on Twitter</a></li>
142
-                </ul>
136
+                <h2>Questions? Want to get in touch?</h2>
137
+                <p>There are several ways to get in touch:</p>
138
+                <p><strong>Join the discussion on IRC.</strong> We can be found in the <a href="irc://chat.freenode.net#docker">#docker</a> channel on chat.freenode.net</p>
139
+                <p><strong>Discussions</strong> happen on our google group: <a href="https://groups.google.com/d/forum/docker-club">docker-club at googlegroups.com</a></p>
140
+                <p>All our <strong>development and decisions</strong> are made out in the open on Github <a href="http://www.github.com/dotcloud/docker">github.com/dotcloud/docker</a></p>
141
+                <p><strong>Get help on using Docker</strong> by asking on <a href="http://stackoverflow.com/tags/docker/">Stackoverflow</a></p>
142
+                <p>And of course, <strong>tweet</strong> your tweets to <a href="http://twitter.com/getdocker/">twitter.com/getdocker</a></p>
143 143
             </section>
144 144
 
145 145
 
... ...
@@ -270,7 +270,7 @@
270 270
                     <li>Filesystem isolation: each process container runs in a completely separate root filesystem.</li>
271 271
                     <li>Resource isolation: system resources like cpu and memory can be allocated differently to each process container, using cgroups.</li>
272 272
                     <li>Network isolation: each process container runs in its own network namespace, with a virtual interface and IP address of its own.</li>
273
-                    <li>Copy-on-write: root filesystems are created using copy-on-write, which makes deployment extremeley fast, memory-cheap and disk-cheap.</li>
273
+                    <li>Copy-on-write: root filesystems are created using copy-on-write, which makes deployment extremely fast, memory-cheap and disk-cheap.</li>
274 274
                     <li>Logging: the standard streams (stdout/stderr/stdin) of each process container is collected and logged for real-time or batch retrieval.</li>
275 275
                     <li>Change management: changes to a container's filesystem can be committed into a new image and re-used to create more containers. No templating or manual configuration required.</li>
276 276
                     <li>Interactive shell: docker can allocate a pseudo-tty and attach to the standard input of any container, for example to run a throwaway interactive shell.</li>
... ...
@@ -86,8 +86,8 @@ func (graph *Graph) Get(name string) (*Image, error) {
86 86
 	if err != nil {
87 87
 		return nil, err
88 88
 	}
89
-	if img.Id != id {
90
-		return nil, fmt.Errorf("Image stored at '%s' has wrong id '%s'", id, img.Id)
89
+	if img.ID != id {
90
+		return nil, fmt.Errorf("Image stored at '%s' has wrong id '%s'", id, img.ID)
91 91
 	}
92 92
 	img.graph = graph
93 93
 	if img.Size == 0 {
... ...
@@ -101,8 +101,8 @@ func (graph *Graph) Get(name string) (*Image, error) {
101 101
 	}
102 102
 	graph.lockSumMap.Lock()
103 103
 	defer graph.lockSumMap.Unlock()
104
-	if _, exists := graph.checksumLock[img.Id]; !exists {
105
-		graph.checksumLock[img.Id] = &sync.Mutex{}
104
+	if _, exists := graph.checksumLock[img.ID]; !exists {
105
+		graph.checksumLock[img.ID] = &sync.Mutex{}
106 106
 	}
107 107
 	return img, nil
108 108
 }
... ...
@@ -110,16 +110,17 @@ func (graph *Graph) Get(name string) (*Image, error) {
110 110
 // Create creates a new image and registers it in the graph.
111 111
 func (graph *Graph) Create(layerData Archive, container *Container, comment, author string, config *Config) (*Image, error) {
112 112
 	img := &Image{
113
-		Id:            GenerateId(),
113
+		ID:            GenerateID(),
114 114
 		Comment:       comment,
115 115
 		Created:       time.Now(),
116 116
 		DockerVersion: VERSION,
117 117
 		Author:        author,
118 118
 		Config:        config,
119
+		Architecture:  "x86_64",
119 120
 	}
120 121
 	if container != nil {
121 122
 		img.Parent = container.Image
122
-		img.Container = container.Id
123
+		img.Container = container.ID
123 124
 		img.ContainerConfig = *container.Config
124 125
 	}
125 126
 	if err := graph.Register(layerData, layerData != nil, img); err != nil {
... ...
@@ -132,12 +133,12 @@ func (graph *Graph) Create(layerData Archive, container *Container, comment, aut
132 132
 // Register imports a pre-existing image into the graph.
133 133
 // FIXME: pass img as first argument
134 134
 func (graph *Graph) Register(layerData Archive, store bool, img *Image) error {
135
-	if err := ValidateId(img.Id); err != nil {
135
+	if err := ValidateID(img.ID); err != nil {
136 136
 		return err
137 137
 	}
138 138
 	// (This is a convenience to save time. Race conditions are taken care of by os.Rename)
139
-	if graph.Exists(img.Id) {
140
-		return fmt.Errorf("Image %s already exists", img.Id)
139
+	if graph.Exists(img.ID) {
140
+		return fmt.Errorf("Image %s already exists", img.ID)
141 141
 	}
142 142
 	tmp, err := graph.Mktemp("")
143 143
 	defer os.RemoveAll(tmp)
... ...
@@ -148,12 +149,12 @@ func (graph *Graph) Register(layerData Archive, store bool, img *Image) error {
148 148
 		return err
149 149
 	}
150 150
 	// Commit
151
-	if err := os.Rename(tmp, graph.imageRoot(img.Id)); err != nil {
151
+	if err := os.Rename(tmp, graph.imageRoot(img.ID)); err != nil {
152 152
 		return err
153 153
 	}
154 154
 	img.graph = graph
155
-	graph.idIndex.Add(img.Id)
156
-	graph.checksumLock[img.Id] = &sync.Mutex{}
155
+	graph.idIndex.Add(img.ID)
156
+	graph.checksumLock[img.ID] = &sync.Mutex{}
157 157
 	return nil
158 158
 }
159 159
 
... ...
@@ -174,13 +175,14 @@ func (graph *Graph) TempLayerArchive(id string, compression Compression, output
174 174
 	if err != nil {
175 175
 		return nil, err
176 176
 	}
177
-	return NewTempArchive(utils.ProgressReader(ioutil.NopCloser(archive), 0, output, "Buffering to disk %v/%v (%v)", false), tmp.Root)
177
+	sf := utils.NewStreamFormatter(false)
178
+	return NewTempArchive(utils.ProgressReader(ioutil.NopCloser(archive), 0, output, sf.FormatProgress("Buffering to disk", "%v/%v (%v)"), sf), tmp.Root)
178 179
 }
179 180
 
180 181
 // Mktemp creates a temporary sub-directory inside the graph's filesystem.
181 182
 func (graph *Graph) Mktemp(id string) (string, error) {
182 183
 	if id == "" {
183
-		id = GenerateId()
184
+		id = GenerateID()
184 185
 	}
185 186
 	tmp, err := graph.tmp()
186 187
 	if err != nil {
... ...
@@ -237,7 +239,7 @@ func (graph *Graph) Map() (map[string]*Image, error) {
237 237
 	}
238 238
 	images := make(map[string]*Image, len(all))
239 239
 	for _, image := range all {
240
-		images[image.Id] = image
240
+		images[image.ID] = image
241 241
 	}
242 242
 	return images, nil
243 243
 }
... ...
@@ -280,10 +282,10 @@ func (graph *Graph) ByParent() (map[string][]*Image, error) {
280 280
 		if err != nil {
281 281
 			return
282 282
 		}
283
-		if children, exists := byParent[parent.Id]; exists {
284
-			byParent[parent.Id] = []*Image{image}
283
+		if children, exists := byParent[parent.ID]; exists {
284
+			byParent[parent.ID] = []*Image{image}
285 285
 		} else {
286
-			byParent[parent.Id] = append(children, image)
286
+			byParent[parent.ID] = append(children, image)
287 287
 		}
288 288
 	})
289 289
 	return byParent, err
... ...
@@ -300,8 +302,8 @@ func (graph *Graph) Heads() (map[string]*Image, error) {
300 300
 	err = graph.WalkAll(func(image *Image) {
301 301
 		// If it's not in the byParent lookup table, then
302 302
 		// it's not a parent -> so it's a head!
303
-		if _, exists := byParent[image.Id]; !exists {
304
-			heads[image.Id] = image
303
+		if _, exists := byParent[image.ID]; !exists {
304
+			heads[image.ID] = image
305 305
 		}
306 306
 	})
307 307
 	return heads, err
... ...
@@ -324,11 +326,11 @@ func (graph *Graph) getStoredChecksums() (map[string]string, error) {
324 324
 }
325 325
 
326 326
 func (graph *Graph) storeChecksums(checksums map[string]string) error {
327
-	checksumJson, err := json.Marshal(checksums)
327
+	checksumJSON, err := json.Marshal(checksums)
328 328
 	if err != nil {
329 329
 		return err
330 330
 	}
331
-	if err := ioutil.WriteFile(path.Join(graph.Root, "checksums"), checksumJson, 0600); err != nil {
331
+	if err := ioutil.WriteFile(path.Join(graph.Root, "checksums"), checksumJSON, 0600); err != nil {
332 332
 		return err
333 333
 	}
334 334
 	return nil
... ...
@@ -34,14 +34,14 @@ func TestInterruptedRegister(t *testing.T) {
34 34
 	defer os.RemoveAll(graph.Root)
35 35
 	badArchive, w := io.Pipe() // Use a pipe reader as a fake archive which never yields data
36 36
 	image := &Image{
37
-		Id:      GenerateId(),
37
+		ID:      GenerateID(),
38 38
 		Comment: "testing",
39 39
 		Created: time.Now(),
40 40
 	}
41 41
 	go graph.Register(badArchive, false, image)
42 42
 	time.Sleep(200 * time.Millisecond)
43 43
 	w.CloseWithError(errors.New("But I'm not a tarball!")) // (Nobody's perfect, darling)
44
-	if _, err := graph.Get(image.Id); err == nil {
44
+	if _, err := graph.Get(image.ID); err == nil {
45 45
 		t.Fatal("Image should not exist after Register is interrupted")
46 46
 	}
47 47
 	// Registering the same image again should succeed if the first register was interrupted
... ...
@@ -67,7 +67,7 @@ func TestGraphCreate(t *testing.T) {
67 67
 	if err != nil {
68 68
 		t.Fatal(err)
69 69
 	}
70
-	if err := ValidateId(image.Id); err != nil {
70
+	if err := ValidateID(image.ID); err != nil {
71 71
 		t.Fatal(err)
72 72
 	}
73 73
 	if image.Comment != "Testing" {
... ...
@@ -91,7 +91,7 @@ func TestRegister(t *testing.T) {
91 91
 		t.Fatal(err)
92 92
 	}
93 93
 	image := &Image{
94
-		Id:      GenerateId(),
94
+		ID:      GenerateID(),
95 95
 		Comment: "testing",
96 96
 		Created: time.Now(),
97 97
 	}
... ...
@@ -104,11 +104,11 @@ func TestRegister(t *testing.T) {
104 104
 	} else if l := len(images); l != 1 {
105 105
 		t.Fatalf("Wrong number of images. Should be %d, not %d", 1, l)
106 106
 	}
107
-	if resultImg, err := graph.Get(image.Id); err != nil {
107
+	if resultImg, err := graph.Get(image.ID); err != nil {
108 108
 		t.Fatal(err)
109 109
 	} else {
110
-		if resultImg.Id != image.Id {
111
-			t.Fatalf("Wrong image ID. Should be '%s', not '%s'", image.Id, resultImg.Id)
110
+		if resultImg.ID != image.ID {
111
+			t.Fatalf("Wrong image ID. Should be '%s', not '%s'", image.ID, resultImg.ID)
112 112
 		}
113 113
 		if resultImg.Comment != image.Comment {
114 114
 			t.Fatalf("Wrong image comment. Should be '%s', not '%s'", image.Comment, resultImg.Comment)
... ...
@@ -156,7 +156,7 @@ func TestDeletePrefix(t *testing.T) {
156 156
 	graph := tempGraph(t)
157 157
 	defer os.RemoveAll(graph.Root)
158 158
 	img := createTestImage(graph, t)
159
-	if err := graph.Delete(utils.TruncateId(img.Id)); err != nil {
159
+	if err := graph.Delete(utils.TruncateID(img.ID)); err != nil {
160 160
 		t.Fatal(err)
161 161
 	}
162 162
 	assertNImages(graph, t, 0)
... ...
@@ -187,7 +187,7 @@ func TestDelete(t *testing.T) {
187 187
 		t.Fatal(err)
188 188
 	}
189 189
 	assertNImages(graph, t, 1)
190
-	if err := graph.Delete(img.Id); err != nil {
190
+	if err := graph.Delete(img.ID); err != nil {
191 191
 		t.Fatal(err)
192 192
 	}
193 193
 	assertNImages(graph, t, 0)
... ...
@@ -201,7 +201,7 @@ func TestDelete(t *testing.T) {
201 201
 		t.Fatal(err)
202 202
 	}
203 203
 	assertNImages(graph, t, 2)
204
-	if err := graph.Delete(img1.Id); err != nil {
204
+	if err := graph.Delete(img1.ID); err != nil {
205 205
 		t.Fatal(err)
206 206
 	}
207 207
 	assertNImages(graph, t, 1)
... ...
@@ -216,7 +216,7 @@ func TestDelete(t *testing.T) {
216 216
 	if err := graph.Register(archive, false, img1); err != nil {
217 217
 		t.Fatal(err)
218 218
 	}
219
-	if err := graph.Delete(img1.Id); err != nil {
219
+	if err := graph.Delete(img1.ID); err != nil {
220 220
 		t.Fatal(err)
221 221
 	}
222 222
 	assertNImages(graph, t, 1)
... ...
@@ -1,23 +1,31 @@
1 1
 # This will build a container capable of producing an official binary build of docker and
2 2
 # uploading it to S3
3
+from	ubuntu:12.04
3 4
 maintainer	Solomon Hykes <solomon@dotcloud.com>
4
-from	ubuntu:12.10
5
+# Workaround the upstart issue
6
+run dpkg-divert --local --rename --add /sbin/initctl
7
+run ln -s /bin/true /sbin/initctl
8
+# Enable universe and gophers PPA
9
+run	DEBIAN_FRONTEND=noninteractive apt-get install -y -q python-software-properties
10
+run	add-apt-repository "deb http://archive.ubuntu.com/ubuntu $(lsb_release -sc) universe"
11
+run	add-apt-repository -y ppa:gophers/go/ubuntu
5 12
 run	apt-get update
13
+# Packages required to checkout, build and upload docker
6 14
 run	DEBIAN_FRONTEND=noninteractive apt-get install -y -q s3cmd
7 15
 run	DEBIAN_FRONTEND=noninteractive apt-get install -y -q curl
8
-# Packages required to checkout and build docker
9 16
 run	curl -s -o /go.tar.gz https://go.googlecode.com/files/go1.1.linux-amd64.tar.gz
10 17
 run	tar -C /usr/local -xzf /go.tar.gz
11
-run	echo "export PATH=$PATH:/usr/local/go/bin" > /.bashrc
12
-run	echo "export PATH=$PATH:/usr/local/go/bin" > /.bash_profile
18
+run	echo "export PATH=/usr/local/go/bin:$PATH" > /.bashrc
19
+run	echo "export PATH=/usr/local/go/bin:$PATH" > /.bash_profile
13 20
 run	DEBIAN_FRONTEND=noninteractive apt-get install -y -q git
14 21
 run	DEBIAN_FRONTEND=noninteractive apt-get install -y -q build-essential
15 22
 # Packages required to build an ubuntu package
23
+run	DEBIAN_FRONTEND=noninteractive apt-get install -y -q golang-stable
16 24
 run	DEBIAN_FRONTEND=noninteractive apt-get install -y -q debhelper
17 25
 run	DEBIAN_FRONTEND=noninteractive apt-get install -y -q autotools-dev
18
-copy	fake_initctl	/usr/local/bin/initctl
19 26
 run	apt-get install -y -q devscripts
20
-add	.	/src
27
+# Copy dockerbuilder files into the container
28
+add	.       /src
21 29
 run	cp /src/dockerbuilder /usr/local/bin/ && chmod +x /usr/local/bin/dockerbuilder
22 30
 run	cp /src/s3cfg /.s3cfg
23 31
 cmd	["dockerbuilder"]
... ...
@@ -2,7 +2,7 @@
2 2
 set -x
3 3
 set -e
4 4
 
5
-export PATH=$PATH:/usr/local/go/bin
5
+export PATH=/usr/local/go/bin:$PATH
6 6
 
7 7
 PACKAGE=github.com/dotcloud/docker
8 8
 
... ...
@@ -36,5 +36,6 @@ else
36 36
 fi
37 37
 
38 38
 if [ -z "$NO_UBUNTU" ]; then
39
+	export PATH=`echo $PATH | sed 's#/usr/local/go/bin:##g'`
39 40
 	(cd packaging/ubuntu && make ubuntu)
40 41
 fi
41 42
deleted file mode 100755
... ...
@@ -1,3 +0,0 @@
1
-#!/bin/sh
2
-
3
-echo Whatever you say, man
4 1
new file mode 100644
... ...
@@ -0,0 +1,2 @@
0
+Ken Cochrane <ken@dotcloud.com>
1
+Jerome Petazzoni <jerome@dotcloud.com>
0 2
new file mode 100644
... ...
@@ -0,0 +1,5 @@
0
+# Docker project infrastructure
1
+
2
+This directory holds all information about the technical infrastructure of the docker project; servers, dns, email, and all the corresponding tools and configuration.
3
+
4
+Obviously credentials should not be stored in this repo, but how to obtain and use them should be documented here.
... ...
@@ -19,7 +19,7 @@ import (
19 19
 )
20 20
 
21 21
 type Image struct {
22
-	Id              string    `json:"id"`
22
+	ID              string    `json:"id"`
23 23
 	Parent          string    `json:"parent,omitempty"`
24 24
 	Comment         string    `json:"comment,omitempty"`
25 25
 	Created         time.Time `json:"created"`
... ...
@@ -28,6 +28,7 @@ type Image struct {
28 28
 	DockerVersion   string    `json:"docker_version,omitempty"`
29 29
 	Author          string    `json:"author,omitempty"`
30 30
 	Config          *Config   `json:"config,omitempty"`
31
+	Architecture    string    `json:"architecture,omitempty"`
31 32
 	graph           *Graph
32 33
 	Size            int64
33 34
 	ParentSize      int64
... ...
@@ -44,18 +45,17 @@ func LoadImage(root string) (*Image, error) {
44 44
 	if err := json.Unmarshal(jsonData, img); err != nil {
45 45
 		return nil, err
46 46
 	}
47
-	if err := ValidateId(img.Id); err != nil {
47
+	if err := ValidateID(img.ID); err != nil {
48 48
 		return nil, err
49 49
 	}
50 50
 	// Check that the filesystem layer exists
51 51
 	if stat, err := os.Stat(layerPath(root)); err != nil {
52 52
 		if os.IsNotExist(err) {
53
-			return nil, fmt.Errorf("Couldn't load image %s: no filesystem layer", img.Id)
54
-		} else {
55
-			return nil, err
53
+			return nil, fmt.Errorf("Couldn't load image %s: no filesystem layer", img.ID)
56 54
 		}
55
+		return nil, err
57 56
 	} else if !stat.IsDir() {
58
-		return nil, fmt.Errorf("Couldn't load image %s: %s is not a directory", img.Id, layerPath(root))
57
+		return nil, fmt.Errorf("Couldn't load image %s: %s is not a directory", img.ID, layerPath(root))
59 58
 	}
60 59
 	return img, nil
61 60
 }
... ...
@@ -63,7 +63,7 @@ func LoadImage(root string) (*Image, error) {
63 63
 func StoreImage(img *Image, layerData Archive, root string, store bool) error {
64 64
 	// Check that root doesn't already exist
65 65
 	if _, err := os.Stat(root); err == nil {
66
-		return fmt.Errorf("Image %s already exists", img.Id)
66
+		return fmt.Errorf("Image %s already exists", img.ID)
67 67
 	} else if !os.IsNotExist(err) {
68 68
 		return err
69 69
 	}
... ...
@@ -195,11 +195,11 @@ func (image *Image) Changes(rw string) ([]Change, error) {
195 195
 	return Changes(layers, rw)
196 196
 }
197 197
 
198
-func (image *Image) ShortId() string {
199
-	return utils.TruncateId(image.Id)
198
+func (image *Image) ShortID() string {
199
+	return utils.TruncateID(image.ID)
200 200
 }
201 201
 
202
-func ValidateId(id string) error {
202
+func ValidateID(id string) error {
203 203
 	if id == "" {
204 204
 		return fmt.Errorf("Image id can't be empty")
205 205
 	}
... ...
@@ -209,7 +209,7 @@ func ValidateId(id string) error {
209 209
 	return nil
210 210
 }
211 211
 
212
-func GenerateId() string {
212
+func GenerateID() string {
213 213
 	id := make([]byte, 32)
214 214
 	_, err := io.ReadFull(rand.Reader, id)
215 215
 	if err != nil {
... ...
@@ -255,7 +255,7 @@ func (img *Image) layers() ([]string, error) {
255 255
 		return nil, e
256 256
 	}
257 257
 	if len(list) == 0 {
258
-		return nil, fmt.Errorf("No layer found for image %s\n", img.Id)
258
+		return nil, fmt.Errorf("No layer found for image %s\n", img.ID)
259 259
 	}
260 260
 	return list, nil
261 261
 }
... ...
@@ -290,7 +290,7 @@ func (img *Image) root() (string, error) {
290 290
 	if img.graph == nil {
291 291
 		return "", fmt.Errorf("Can't lookup root of unregistered image")
292 292
 	}
293
-	return img.graph.imageRoot(img.Id), nil
293
+	return img.graph.imageRoot(img.ID), nil
294 294
 }
295 295
 
296 296
 // Return the path of an image's layer
... ...
@@ -303,8 +303,8 @@ func (img *Image) layer() (string, error) {
303 303
 }
304 304
 
305 305
 func (img *Image) Checksum() (string, error) {
306
-	img.graph.checksumLock[img.Id].Lock()
307
-	defer img.graph.checksumLock[img.Id].Unlock()
306
+	img.graph.checksumLock[img.ID].Lock()
307
+	defer img.graph.checksumLock[img.ID].Unlock()
308 308
 
309 309
 	root, err := img.root()
310 310
 	if err != nil {
... ...
@@ -315,7 +315,7 @@ func (img *Image) Checksum() (string, error) {
315 315
 	if err != nil {
316 316
 		return "", err
317 317
 	}
318
-	if checksum, ok := checksums[img.Id]; ok {
318
+	if checksum, ok := checksums[img.ID]; ok {
319 319
 		return checksum, nil
320 320
 	}
321 321
 
... ...
@@ -366,7 +366,7 @@ func (img *Image) Checksum() (string, error) {
366 366
 		return "", err
367 367
 	}
368 368
 
369
-	checksums[img.Id] = hash
369
+	checksums[img.ID] = hash
370 370
 
371 371
 	// Dump the checksums to disc
372 372
 	if err := img.graph.storeChecksums(checksums); err != nil {
... ...
@@ -386,7 +386,7 @@ func (img *Image) getVirtualSize(size int64) int64 {
386 386
 }
387 387
 
388 388
 // Build an Image object from raw json data
389
-func NewImgJson(src []byte) (*Image, error) {
389
+func NewImgJSON(src []byte) (*Image, error) {
390 390
 	ret := &Image{}
391 391
 
392 392
 	utils.Debugf("Json string: {%s}\n", src)
... ...
@@ -19,7 +19,7 @@ lxc.network.flags = up
19 19
 lxc.network.link = {{.NetworkSettings.Bridge}}
20 20
 lxc.network.name = eth0
21 21
 lxc.network.mtu = 1500
22
-lxc.network.ipv4 = {{.NetworkSettings.IpAddress}}/{{.NetworkSettings.IpPrefixLen}}
22
+lxc.network.ipv4 = {{.NetworkSettings.IPAddress}}/{{.NetworkSettings.IPPrefixLen}}
23 23
 
24 24
 # root filesystem
25 25
 {{$ROOTFS := .RootfsPath}}
... ...
@@ -52,7 +52,7 @@ func ipToInt(ip net.IP) int32 {
52 52
 }
53 53
 
54 54
 // Converts 32 bit integer into a 4 bytes IP address
55
-func intToIp(n int32) net.IP {
55
+func intToIP(n int32) net.IP {
56 56
 	b := make([]byte, 4)
57 57
 	binary.BigEndian.PutUint32(b, uint32(n))
58 58
 	return net.IP(b)
... ...
@@ -132,9 +132,8 @@ func CreateBridgeIface(ifaceName string) error {
132 132
 	}
133 133
 	if ifaceAddr == "" {
134 134
 		return fmt.Errorf("Could not find a free IP address range for interface '%s'. Please configure its address manually and run 'docker -b %s'", ifaceName, ifaceName)
135
-	} else {
136
-		utils.Debugf("Creating bridge %s with network %s", ifaceName, ifaceAddr)
137 135
 	}
136
+	utils.Debugf("Creating bridge %s with network %s", ifaceName, ifaceAddr)
138 137
 
139 138
 	if output, err := ip("link", "add", ifaceName, "type", "bridge"); err != nil {
140 139
 		return fmt.Errorf("Error creating bridge: %s (output: %s)", err, output)
... ...
@@ -258,7 +257,7 @@ func proxy(listener net.Listener, proto, address string) error {
258 258
 		utils.Debugf("Connected to backend, splicing")
259 259
 		splice(src, dst)
260 260
 	}
261
-	return nil
261
+	panic("Unreachable")
262 262
 }
263 263
 
264 264
 func halfSplice(dst, src net.Conn) error {
... ...
@@ -398,7 +397,7 @@ func (alloc *IPAllocator) run() {
398 398
 			}
399 399
 		}
400 400
 
401
-		ip := allocatedIP{ip: intToIp(newNum)}
401
+		ip := allocatedIP{ip: intToIP(newNum)}
402 402
 		if inUse {
403 403
 			ip.err = errors.New("No unallocated IP available")
404 404
 		}
... ...
@@ -465,11 +464,11 @@ func (iface *NetworkInterface) AllocatePort(spec string) (*Nat, error) {
465 465
 		return nil, err
466 466
 	}
467 467
 	// Allocate a random port if Frontend==0
468
-	if extPort, err := iface.manager.portAllocator.Acquire(nat.Frontend); err != nil {
468
+	extPort, err := iface.manager.portAllocator.Acquire(nat.Frontend)
469
+	if err != nil {
469 470
 		return nil, err
470
-	} else {
471
-		nat.Frontend = extPort
472 471
 	}
472
+	nat.Frontend = extPort
473 473
 	if err := iface.manager.portMapper.Map(nat.Frontend, net.TCPAddr{IP: iface.IPNet.IP, Port: nat.Backend}); err != nil {
474 474
 		iface.manager.portAllocator.Release(nat.Frontend)
475 475
 		return nil, err
... ...
@@ -137,7 +137,7 @@ func TestConversion(t *testing.T) {
137 137
 	if i == 0 {
138 138
 		t.Fatal("converted to zero")
139 139
 	}
140
-	conv := intToIp(i)
140
+	conv := intToIP(i)
141 141
 	if !ip.Equal(conv) {
142 142
 		t.Error(conv.String())
143 143
 	}
... ...
@@ -1,3 +1,14 @@
1
+lxc-docker (0.3.4-1) UNRELEASED; urgency=low
2
+  - Builder: 'docker build' builds a container, layer by layer, from a source repository containing a Dockerfile
3
+  - Builder: 'docker build -t FOO' applies the tag FOO to the newly built container.
4
+  - Runtime: interactive TTYs correctly handle window resize
5
+  - Runtime: fix how configuration is merged between layers
6
+  - Remote API: split stdout and stderr on 'docker run'
7
+  - Remote API: optionally listen on a different IP and port (use at your own risk)
8
+  - Documentation: improved install instructions.
9
+
10
+ -- dotCloud <ops@dotcloud.com>  Thu, 30 May 2013 00:00:00 -0700
11
+
1 12
 lxc-docker (0.3.2-1) UNRELEASED; urgency=low
2 13
   - Runtime: Store the actual archive on commit
3 14
   - Registry: Improve the checksum process
... ...
@@ -1,3 +1,22 @@
1
+lxc-docker (0.4.0-1) precise; urgency=low
2
+  - Introducing Builder: 'docker build' builds a container, layer by layer, from a source repository containing a Dockerfile
3
+  - Introducing Remote API: control Docker programmatically using a simple HTTP/json API
4
+  - Runtime: various reliability and usability improvements
5
+
6
+ -- dotCloud <ops@dotcloud.com>  Mon, 03 Jun 2013 00:00:00 -0700
7
+
8
+lxc-docker (0.3.4-1) precise; urgency=low
9
+  - Builder: 'docker build' builds a container, layer by layer, from a source repository containing a Dockerfile
10
+  - Builder: 'docker build -t FOO' applies the tag FOO to the newly built container.
11
+  - Runtime: interactive TTYs correctly handle window resize
12
+  - Runtime: fix how configuration is merged between layers
13
+  - Remote API: split stdout and stderr on 'docker run'
14
+  - Remote API: optionally listen on a different IP and port (use at your own risk)
15
+  - Documentation: improved install instructions.
16
+
17
+ -- dotCloud <ops@dotcloud.com>  Thu, 30 May 2013 00:00:00 -0700
18
+
19
+
1 20
 lxc-docker (0.3.3-1) precise; urgency=low
2 21
   - Registry: Fix push regression
3 22
   - Various bugfixes
... ...
@@ -5,6 +5,5 @@ stop on starting rc RUNLEVEL=[016]
5 5
 respawn
6 6
 
7 7
 script
8
-    # FIXME: docker should not depend on the system having en_US.UTF-8
9
-    LC_ALL='en_US.UTF-8' /usr/bin/docker -d
8
+    /usr/bin/docker -d
10 9
 end script
... ...
@@ -15,7 +15,7 @@ import (
15 15
 	"strings"
16 16
 )
17 17
 
18
-var ErrAlreadyExists error = errors.New("Image already exists")
18
+var ErrAlreadyExists = errors.New("Image already exists")
19 19
 
20 20
 func doWithCookies(c *http.Client, req *http.Request) (*http.Response, error) {
21 21
 	for _, cookie := range c.Jar.Cookies(req.URL) {
... ...
@@ -64,7 +64,11 @@ func (r *Registry) LookupRemoteImage(imgId, registry string, authConfig *auth.Au
64 64
 	}
65 65
 	req.SetBasicAuth(authConfig.Username, authConfig.Password)
66 66
 	res, err := rt.RoundTrip(req)
67
-	return err == nil && res.StatusCode == 307
67
+	if err != nil {
68
+		return false
69
+	}
70
+	res.Body.Close()
71
+	return res.StatusCode == 307
68 72
 }
69 73
 
70 74
 func (r *Registry) getImagesInRepository(repository string, authConfig *auth.AuthConfig) ([]map[string]string, error) {
... ...
@@ -103,8 +107,8 @@ func (r *Registry) getImagesInRepository(repository string, authConfig *auth.Aut
103 103
 
104 104
 // Retrieve an image from the Registry.
105 105
 // Returns the Image object as well as the layer as an Archive (io.Reader)
106
-func (r *Registry) GetRemoteImageJson(imgId, registry string, token []string) ([]byte, error) {
107
-	// Get the Json
106
+func (r *Registry) GetRemoteImageJSON(imgId, registry string, token []string) ([]byte, error) {
107
+	// Get the JSON
108 108
 	req, err := http.NewRequest("GET", registry+"/images/"+imgId+"/json", nil)
109 109
 	if err != nil {
110 110
 		return nil, fmt.Errorf("Failed to download json: %s", err)
... ...
@@ -152,21 +156,24 @@ func (r *Registry) GetRemoteTags(registries []string, repository string, token [
152 152
 		}
153 153
 		req.Header.Set("Authorization", "Token "+strings.Join(token, ", "))
154 154
 		res, err := r.client.Do(req)
155
-		defer res.Body.Close()
156 155
 		utils.Debugf("Got status code %d from %s", res.StatusCode, endpoint)
157
-		if err != nil || (res.StatusCode != 200 && res.StatusCode != 404) {
156
+		if err != nil {
157
+			return nil, err
158
+		}
159
+		defer res.Body.Close()
160
+
161
+		if res.StatusCode != 200 && res.StatusCode != 404 {
158 162
 			continue
159 163
 		} else if res.StatusCode == 404 {
160 164
 			return nil, fmt.Errorf("Repository not found")
161 165
 		}
162 166
 
163 167
 		result := make(map[string]string)
164
-
165
-		rawJson, err := ioutil.ReadAll(res.Body)
168
+		rawJSON, err := ioutil.ReadAll(res.Body)
166 169
 		if err != nil {
167 170
 			return nil, err
168 171
 		}
169
-		if err := json.Unmarshal(rawJson, &result); err != nil {
172
+		if err := json.Unmarshal(rawJSON, &result); err != nil {
170 173
 			return nil, err
171 174
 		}
172 175
 		return result, nil
... ...
@@ -212,19 +219,19 @@ func (r *Registry) GetRepositoryData(remote string) (*RepositoryData, error) {
212 212
 		return nil, fmt.Errorf("Index response didn't contain any endpoints")
213 213
 	}
214 214
 
215
-	checksumsJson, err := ioutil.ReadAll(res.Body)
215
+	checksumsJSON, err := ioutil.ReadAll(res.Body)
216 216
 	if err != nil {
217 217
 		return nil, err
218 218
 	}
219 219
 	remoteChecksums := []*ImgData{}
220
-	if err := json.Unmarshal(checksumsJson, &remoteChecksums); err != nil {
220
+	if err := json.Unmarshal(checksumsJSON, &remoteChecksums); err != nil {
221 221
 		return nil, err
222 222
 	}
223 223
 
224 224
 	// Forge a better object from the retrieved data
225 225
 	imgsData := make(map[string]*ImgData)
226 226
 	for _, elem := range remoteChecksums {
227
-		imgsData[elem.Id] = elem
227
+		imgsData[elem.ID] = elem
228 228
 	}
229 229
 
230 230
 	return &RepositoryData{
... ...
@@ -235,10 +242,10 @@ func (r *Registry) GetRepositoryData(remote string) (*RepositoryData, error) {
235 235
 }
236 236
 
237 237
 // Push a local image to the registry
238
-func (r *Registry) PushImageJsonRegistry(imgData *ImgData, jsonRaw []byte, registry string, token []string) error {
238
+func (r *Registry) PushImageJSONRegistry(imgData *ImgData, jsonRaw []byte, registry string, token []string) error {
239 239
 	registry = "https://" + registry + "/v1"
240 240
 	// FIXME: try json with UTF8
241
-	req, err := http.NewRequest("PUT", registry+"/images/"+imgData.Id+"/json", strings.NewReader(string(jsonRaw)))
241
+	req, err := http.NewRequest("PUT", registry+"/images/"+imgData.ID+"/json", strings.NewReader(string(jsonRaw)))
242 242
 	if err != nil {
243 243
 		return err
244 244
 	}
... ...
@@ -246,7 +253,7 @@ func (r *Registry) PushImageJsonRegistry(imgData *ImgData, jsonRaw []byte, regis
246 246
 	req.Header.Set("Authorization", "Token "+strings.Join(token, ","))
247 247
 	req.Header.Set("X-Docker-Checksum", imgData.Checksum)
248 248
 
249
-	utils.Debugf("Setting checksum for %s: %s", imgData.Id, imgData.Checksum)
249
+	utils.Debugf("Setting checksum for %s: %s", imgData.ID, imgData.Checksum)
250 250
 	res, err := doWithCookies(r.client, req)
251 251
 	if err != nil {
252 252
 		return fmt.Errorf("Failed to upload metadata: %s", err)
... ...
@@ -321,8 +328,8 @@ func (r *Registry) PushRegistryTag(remote, revision, tag, registry string, token
321 321
 	return nil
322 322
 }
323 323
 
324
-func (r *Registry) PushImageJsonIndex(remote string, imgList []*ImgData, validate bool) (*RepositoryData, error) {
325
-	imgListJson, err := json.Marshal(imgList)
324
+func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validate bool) (*RepositoryData, error) {
325
+	imgListJSON, err := json.Marshal(imgList)
326 326
 	if err != nil {
327 327
 		return nil, err
328 328
 	}
... ...
@@ -331,14 +338,14 @@ func (r *Registry) PushImageJsonIndex(remote string, imgList []*ImgData, validat
331 331
 		suffix = "images"
332 332
 	}
333 333
 
334
-	utils.Debugf("Image list pushed to index:\n%s\n", imgListJson)
334
+	utils.Debugf("Image list pushed to index:\n%s\n", imgListJSON)
335 335
 
336
-	req, err := http.NewRequest("PUT", auth.IndexServerAddress()+"/repositories/"+remote+"/"+suffix, bytes.NewReader(imgListJson))
336
+	req, err := http.NewRequest("PUT", auth.IndexServerAddress()+"/repositories/"+remote+"/"+suffix, bytes.NewReader(imgListJSON))
337 337
 	if err != nil {
338 338
 		return nil, err
339 339
 	}
340 340
 	req.SetBasicAuth(r.authConfig.Username, r.authConfig.Password)
341
-	req.ContentLength = int64(len(imgListJson))
341
+	req.ContentLength = int64(len(imgListJSON))
342 342
 	req.Header.Set("X-Docker-Token", "true")
343 343
 
344 344
 	res, err := r.client.Do(req)
... ...
@@ -350,12 +357,12 @@ func (r *Registry) PushImageJsonIndex(remote string, imgList []*ImgData, validat
350 350
 	// Redirect if necessary
351 351
 	for res.StatusCode >= 300 && res.StatusCode < 400 {
352 352
 		utils.Debugf("Redirected to %s\n", res.Header.Get("Location"))
353
-		req, err = http.NewRequest("PUT", res.Header.Get("Location"), bytes.NewReader(imgListJson))
353
+		req, err = http.NewRequest("PUT", res.Header.Get("Location"), bytes.NewReader(imgListJSON))
354 354
 		if err != nil {
355 355
 			return nil, err
356 356
 		}
357 357
 		req.SetBasicAuth(r.authConfig.Username, r.authConfig.Password)
358
-		req.ContentLength = int64(len(imgListJson))
358
+		req.ContentLength = int64(len(imgListJSON))
359 359
 		req.Header.Set("X-Docker-Token", "true")
360 360
 
361 361
 		res, err = r.client.Do(req)
... ...
@@ -389,11 +396,11 @@ func (r *Registry) PushImageJsonIndex(remote string, imgList []*ImgData, validat
389 389
 	}
390 390
 	if validate {
391 391
 		if res.StatusCode != 204 {
392
-			if errBody, err := ioutil.ReadAll(res.Body); err != nil {
392
+			errBody, err := ioutil.ReadAll(res.Body)
393
+			if err != nil {
393 394
 				return nil, err
394
-			} else {
395
-				return nil, fmt.Errorf("Error: Status %d trying to push checksums %s: %s", res.StatusCode, remote, errBody)
396 395
 			}
396
+			return nil, fmt.Errorf("Error: Status %d trying to push checksums %s: %s", res.StatusCode, remote, errBody)
397 397
 		}
398 398
 	}
399 399
 
... ...
@@ -456,7 +463,7 @@ type RepositoryData struct {
456 456
 }
457 457
 
458 458
 type ImgData struct {
459
-	Id       string `json:"id"`
459
+	ID       string `json:"id"`
460 460
 	Checksum string `json:"checksum,omitempty"`
461 461
 	Tag      string `json:",omitempty"`
462 462
 }
... ...
@@ -470,9 +477,16 @@ func NewRegistry(root string) *Registry {
470 470
 	// If the auth file does not exist, keep going
471 471
 	authConfig, _ := auth.LoadConfig(root)
472 472
 
473
+	httpTransport := &http.Transport{
474
+		DisableKeepAlives: true,
475
+		Proxy: http.ProxyFromEnvironment,
476
+	}
477
+
473 478
 	r := &Registry{
474 479
 		authConfig: authConfig,
475
-		client:     &http.Client{},
480
+		client: &http.Client{
481
+			Transport: httpTransport,
482
+		},
476 483
 	}
477 484
 	r.client.Jar = cookiejar.NewCookieJar()
478 485
 	return r
... ...
@@ -51,7 +51,7 @@ func (runtime *Runtime) List() []*Container {
51 51
 func (runtime *Runtime) getContainerElement(id string) *list.Element {
52 52
 	for e := runtime.containers.Front(); e != nil; e = e.Next() {
53 53
 		container := e.Value.(*Container)
54
-		if container.Id == id {
54
+		if container.ID == id {
55 55
 			return e
56 56
 		}
57 57
 	}
... ...
@@ -83,8 +83,8 @@ func (runtime *Runtime) Load(id string) (*Container, error) {
83 83
 	if err := container.FromDisk(); err != nil {
84 84
 		return nil, err
85 85
 	}
86
-	if container.Id != id {
87
-		return container, fmt.Errorf("Container %s is stored at %s", container.Id, id)
86
+	if container.ID != id {
87
+		return container, fmt.Errorf("Container %s is stored at %s", container.ID, id)
88 88
 	}
89 89
 	if container.State.Running {
90 90
 		container.State.Ghost = true
... ...
@@ -95,12 +95,12 @@ func (runtime *Runtime) Load(id string) (*Container, error) {
95 95
 	return container, nil
96 96
 }
97 97
 
98
-// Register makes a container object usable by the runtime as <container.Id>
98
+// Register makes a container object usable by the runtime as <container.ID>
99 99
 func (runtime *Runtime) Register(container *Container) error {
100
-	if container.runtime != nil || runtime.Exists(container.Id) {
100
+	if container.runtime != nil || runtime.Exists(container.ID) {
101 101
 		return fmt.Errorf("Container is already loaded")
102 102
 	}
103
-	if err := validateId(container.Id); err != nil {
103
+	if err := validateID(container.ID); err != nil {
104 104
 		return err
105 105
 	}
106 106
 
... ...
@@ -123,7 +123,7 @@ func (runtime *Runtime) Register(container *Container) error {
123 123
 	}
124 124
 	// done
125 125
 	runtime.containers.PushBack(container)
126
-	runtime.idIndex.Add(container.Id)
126
+	runtime.idIndex.Add(container.ID)
127 127
 
128 128
 	// When we actually restart, Start() do the monitoring.
129 129
 	// However, when we simply 'reattach', we have to restart a monitor
... ...
@@ -133,25 +133,25 @@ func (runtime *Runtime) Register(container *Container) error {
133 133
 	//        if so, then we need to restart monitor and init a new lock
134 134
 	// If the container is supposed to be running, make sure of it
135 135
 	if container.State.Running {
136
-		if output, err := exec.Command("lxc-info", "-n", container.Id).CombinedOutput(); err != nil {
136
+		output, err := exec.Command("lxc-info", "-n", container.ID).CombinedOutput()
137
+		if err != nil {
137 138
 			return err
138
-		} else {
139
-			if !strings.Contains(string(output), "RUNNING") {
140
-				utils.Debugf("Container %s was supposed to be running be is not.", container.Id)
141
-				if runtime.autoRestart {
142
-					utils.Debugf("Restarting")
143
-					container.State.Ghost = false
144
-					container.State.setStopped(0)
145
-					if err := container.Start(); err != nil {
146
-						return err
147
-					}
148
-					nomonitor = true
149
-				} else {
150
-					utils.Debugf("Marking as stopped")
151
-					container.State.setStopped(-127)
152
-					if err := container.ToDisk(); err != nil {
153
-						return err
154
-					}
139
+		}
140
+		if !strings.Contains(string(output), "RUNNING") {
141
+			utils.Debugf("Container %s was supposed to be running be is not.", container.ID)
142
+			if runtime.autoRestart {
143
+				utils.Debugf("Restarting")
144
+				container.State.Ghost = false
145
+				container.State.setStopped(0)
146
+				if err := container.Start(); err != nil {
147
+					return err
148
+				}
149
+				nomonitor = true
150
+			} else {
151
+				utils.Debugf("Marking as stopped")
152
+				container.State.setStopped(-127)
153
+				if err := container.ToDisk(); err != nil {
154
+					return err
155 155
 				}
156 156
 			}
157 157
 		}
... ...
@@ -182,9 +182,9 @@ func (runtime *Runtime) Destroy(container *Container) error {
182 182
 		return fmt.Errorf("The given container is <nil>")
183 183
 	}
184 184
 
185
-	element := runtime.getContainerElement(container.Id)
185
+	element := runtime.getContainerElement(container.ID)
186 186
 	if element == nil {
187
-		return fmt.Errorf("Container %v not found - maybe it was already destroyed?", container.Id)
187
+		return fmt.Errorf("Container %v not found - maybe it was already destroyed?", container.ID)
188 188
 	}
189 189
 
190 190
 	if err := container.Stop(3); err != nil {
... ...
@@ -194,14 +194,14 @@ func (runtime *Runtime) Destroy(container *Container) error {
194 194
 		return err
195 195
 	} else if mounted {
196 196
 		if err := container.Unmount(); err != nil {
197
-			return fmt.Errorf("Unable to unmount container %v: %v", container.Id, err)
197
+			return fmt.Errorf("Unable to unmount container %v: %v", container.ID, err)
198 198
 		}
199 199
 	}
200 200
 	// Deregister the container before removing its directory, to avoid race conditions
201
-	runtime.idIndex.Delete(container.Id)
201
+	runtime.idIndex.Delete(container.ID)
202 202
 	runtime.containers.Remove(element)
203 203
 	if err := os.RemoveAll(container.root); err != nil {
204
-		return fmt.Errorf("Unable to remove filesystem for %v: %v", container.Id, err)
204
+		return fmt.Errorf("Unable to remove filesystem for %v: %v", container.ID, err)
205 205
 	}
206 206
 	return nil
207 207
 }
... ...
@@ -218,7 +218,7 @@ func (runtime *Runtime) restore() error {
218 218
 			utils.Debugf("Failed to load container %v: %v", id, err)
219 219
 			continue
220 220
 		}
221
-		utils.Debugf("Loaded container %v", container.Id)
221
+		utils.Debugf("Loaded container %v", container.ID)
222 222
 	}
223 223
 	return nil
224 224
 }
... ...
@@ -68,7 +68,7 @@ func init() {
68 68
 		runtime: runtime,
69 69
 	}
70 70
 	// Retrieve the Image
71
-	if err := srv.ImagePull(unitTestImageName, "", "", os.Stdout, false); err != nil {
71
+	if err := srv.ImagePull(unitTestImageName, "", "", os.Stdout, utils.NewStreamFormatter(false)); err != nil {
72 72
 		panic(err)
73 73
 	}
74 74
 }
... ...
@@ -120,7 +120,7 @@ func TestRuntimeCreate(t *testing.T) {
120 120
 	builder := NewBuilder(runtime)
121 121
 
122 122
 	container, err := builder.Create(&Config{
123
-		Image: GetTestImage(runtime).Id,
123
+		Image: GetTestImage(runtime).ID,
124 124
 		Cmd:   []string{"ls", "-al"},
125 125
 	},
126 126
 	)
... ...
@@ -140,29 +140,29 @@ func TestRuntimeCreate(t *testing.T) {
140 140
 	}
141 141
 
142 142
 	// Make sure the container List() returns is the right one
143
-	if runtime.List()[0].Id != container.Id {
143
+	if runtime.List()[0].ID != container.ID {
144 144
 		t.Errorf("Unexpected container %v returned by List", runtime.List()[0])
145 145
 	}
146 146
 
147 147
 	// Make sure we can get the container with Get()
148
-	if runtime.Get(container.Id) == nil {
148
+	if runtime.Get(container.ID) == nil {
149 149
 		t.Errorf("Unable to get newly created container")
150 150
 	}
151 151
 
152 152
 	// Make sure it is the right container
153
-	if runtime.Get(container.Id) != container {
153
+	if runtime.Get(container.ID) != container {
154 154
 		t.Errorf("Get() returned the wrong container")
155 155
 	}
156 156
 
157 157
 	// Make sure Exists returns it as existing
158
-	if !runtime.Exists(container.Id) {
158
+	if !runtime.Exists(container.ID) {
159 159
 		t.Errorf("Exists() returned false for a newly created container")
160 160
 	}
161 161
 
162 162
 	// Make sure crete with bad parameters returns an error
163 163
 	_, err = builder.Create(
164 164
 		&Config{
165
-			Image: GetTestImage(runtime).Id,
165
+			Image: GetTestImage(runtime).ID,
166 166
 		},
167 167
 	)
168 168
 	if err == nil {
... ...
@@ -171,7 +171,7 @@ func TestRuntimeCreate(t *testing.T) {
171 171
 
172 172
 	_, err = builder.Create(
173 173
 		&Config{
174
-			Image: GetTestImage(runtime).Id,
174
+			Image: GetTestImage(runtime).ID,
175 175
 			Cmd:   []string{},
176 176
 		},
177 177
 	)
... ...
@@ -187,7 +187,7 @@ func TestDestroy(t *testing.T) {
187 187
 	}
188 188
 	defer nuke(runtime)
189 189
 	container, err := NewBuilder(runtime).Create(&Config{
190
-		Image: GetTestImage(runtime).Id,
190
+		Image: GetTestImage(runtime).ID,
191 191
 		Cmd:   []string{"ls", "-al"},
192 192
 	},
193 193
 	)
... ...
@@ -210,7 +210,7 @@ func TestDestroy(t *testing.T) {
210 210
 	}
211 211
 
212 212
 	// Make sure runtime.Get() refuses to return the unexisting container
213
-	if runtime.Get(container.Id) != nil {
213
+	if runtime.Get(container.ID) != nil {
214 214
 		t.Errorf("Unable to get newly created container")
215 215
 	}
216 216
 
... ...
@@ -237,7 +237,7 @@ func TestGet(t *testing.T) {
237 237
 	builder := NewBuilder(runtime)
238 238
 
239 239
 	container1, err := builder.Create(&Config{
240
-		Image: GetTestImage(runtime).Id,
240
+		Image: GetTestImage(runtime).ID,
241 241
 		Cmd:   []string{"ls", "-al"},
242 242
 	},
243 243
 	)
... ...
@@ -247,7 +247,7 @@ func TestGet(t *testing.T) {
247 247
 	defer runtime.Destroy(container1)
248 248
 
249 249
 	container2, err := builder.Create(&Config{
250
-		Image: GetTestImage(runtime).Id,
250
+		Image: GetTestImage(runtime).ID,
251 251
 		Cmd:   []string{"ls", "-al"},
252 252
 	},
253 253
 	)
... ...
@@ -257,7 +257,7 @@ func TestGet(t *testing.T) {
257 257
 	defer runtime.Destroy(container2)
258 258
 
259 259
 	container3, err := builder.Create(&Config{
260
-		Image: GetTestImage(runtime).Id,
260
+		Image: GetTestImage(runtime).ID,
261 261
 		Cmd:   []string{"ls", "-al"},
262 262
 	},
263 263
 	)
... ...
@@ -266,16 +266,16 @@ func TestGet(t *testing.T) {
266 266
 	}
267 267
 	defer runtime.Destroy(container3)
268 268
 
269
-	if runtime.Get(container1.Id) != container1 {
270
-		t.Errorf("Get(test1) returned %v while expecting %v", runtime.Get(container1.Id), container1)
269
+	if runtime.Get(container1.ID) != container1 {
270
+		t.Errorf("Get(test1) returned %v while expecting %v", runtime.Get(container1.ID), container1)
271 271
 	}
272 272
 
273
-	if runtime.Get(container2.Id) != container2 {
274
-		t.Errorf("Get(test2) returned %v while expecting %v", runtime.Get(container2.Id), container2)
273
+	if runtime.Get(container2.ID) != container2 {
274
+		t.Errorf("Get(test2) returned %v while expecting %v", runtime.Get(container2.ID), container2)
275 275
 	}
276 276
 
277
-	if runtime.Get(container3.Id) != container3 {
278
-		t.Errorf("Get(test3) returned %v while expecting %v", runtime.Get(container3.Id), container3)
277
+	if runtime.Get(container3.ID) != container3 {
278
+		t.Errorf("Get(test3) returned %v while expecting %v", runtime.Get(container3.ID), container3)
279 279
 	}
280 280
 
281 281
 }
... ...
@@ -283,7 +283,7 @@ func TestGet(t *testing.T) {
283 283
 func findAvailalblePort(runtime *Runtime, port int) (*Container, error) {
284 284
 	strPort := strconv.Itoa(port)
285 285
 	container, err := NewBuilder(runtime).Create(&Config{
286
-		Image:     GetTestImage(runtime).Id,
286
+		Image:     GetTestImage(runtime).ID,
287 287
 		Cmd:       []string{"sh", "-c", "echo well hello there | nc -l -p " + strPort},
288 288
 		PortSpecs: []string{strPort},
289 289
 	},
... ...
@@ -379,7 +379,7 @@ func TestRestore(t *testing.T) {
379 379
 
380 380
 	// Create a container with one instance of docker
381 381
 	container1, err := builder.Create(&Config{
382
-		Image: GetTestImage(runtime1).Id,
382
+		Image: GetTestImage(runtime1).ID,
383 383
 		Cmd:   []string{"ls", "-al"},
384 384
 	},
385 385
 	)
... ...
@@ -390,7 +390,7 @@ func TestRestore(t *testing.T) {
390 390
 
391 391
 	// Create a second container meant to be killed
392 392
 	container2, err := builder.Create(&Config{
393
-		Image:     GetTestImage(runtime1).Id,
393
+		Image:     GetTestImage(runtime1).ID,
394 394
 		Cmd:       []string{"/bin/cat"},
395 395
 		OpenStdin: true,
396 396
 	},
... ...
@@ -406,7 +406,7 @@ func TestRestore(t *testing.T) {
406 406
 	}
407 407
 
408 408
 	if !container2.State.Running {
409
-		t.Fatalf("Container %v should appear as running but isn't", container2.Id)
409
+		t.Fatalf("Container %v should appear as running but isn't", container2.ID)
410 410
 	}
411 411
 
412 412
 	// Simulate a crash/manual quit of dockerd: process dies, states stays 'Running'
... ...
@@ -426,7 +426,7 @@ func TestRestore(t *testing.T) {
426 426
 	}
427 427
 
428 428
 	if !container2.State.Running {
429
-		t.Fatalf("Container %v should appear as running but isn't", container2.Id)
429
+		t.Fatalf("Container %v should appear as running but isn't", container2.ID)
430 430
 	}
431 431
 
432 432
 	// Here are are simulating a docker restart - that is, reloading all containers
... ...
@@ -442,14 +442,14 @@ func TestRestore(t *testing.T) {
442 442
 	runningCount := 0
443 443
 	for _, c := range runtime2.List() {
444 444
 		if c.State.Running {
445
-			t.Errorf("Running container found: %v (%v)", c.Id, c.Path)
445
+			t.Errorf("Running container found: %v (%v)", c.ID, c.Path)
446 446
 			runningCount++
447 447
 		}
448 448
 	}
449 449
 	if runningCount != 0 {
450 450
 		t.Fatalf("Expected 0 container alive, %d found", runningCount)
451 451
 	}
452
-	container3 := runtime2.Get(container1.Id)
452
+	container3 := runtime2.Get(container1.ID)
453 453
 	if container3 == nil {
454 454
 		t.Fatal("Unable to Get container")
455 455
 	}
... ...
@@ -16,8 +16,12 @@ import (
16 16
 	"strings"
17 17
 )
18 18
 
19
-func (srv *Server) DockerVersion() ApiVersion {
20
-	return ApiVersion{VERSION, GIT_COMMIT, srv.runtime.capabilities.MemoryLimit, srv.runtime.capabilities.SwapLimit}
19
+func (srv *Server) DockerVersion() APIVersion {
20
+	return APIVersion{
21
+		Version:   VERSION,
22
+		GitCommit: GITCOMMIT,
23
+		GoVersion: runtime.Version(),
24
+	}
21 25
 }
22 26
 
23 27
 func (srv *Server) ContainerKill(name string) error {
... ...
@@ -48,16 +52,16 @@ func (srv *Server) ContainerExport(name string, out io.Writer) error {
48 48
 	return fmt.Errorf("No such container: %s", name)
49 49
 }
50 50
 
51
-func (srv *Server) ImagesSearch(term string) ([]ApiSearch, error) {
51
+func (srv *Server) ImagesSearch(term string) ([]APISearch, error) {
52 52
 
53 53
 	results, err := registry.NewRegistry(srv.runtime.root).SearchRepositories(term)
54 54
 	if err != nil {
55 55
 		return nil, err
56 56
 	}
57 57
 
58
-	var outs []ApiSearch
58
+	var outs []APISearch
59 59
 	for _, repo := range results.Results {
60
-		var out ApiSearch
60
+		var out APISearch
61 61
 		out.Description = repo["description"]
62 62
 		if len(out.Description) > 45 {
63 63
 			out.Description = utils.Trunc(out.Description, 42) + "..."
... ...
@@ -68,7 +72,7 @@ func (srv *Server) ImagesSearch(term string) ([]ApiSearch, error) {
68 68
 	return outs, nil
69 69
 }
70 70
 
71
-func (srv *Server) ImageInsert(name, url, path string, out io.Writer) (string, error) {
71
+func (srv *Server) ImageInsert(name, url, path string, out io.Writer, sf *utils.StreamFormatter) (string, error) {
72 72
 	out = utils.NewWriteFlusher(out)
73 73
 	img, err := srv.runtime.repositories.LookupImage(name)
74 74
 	if err != nil {
... ...
@@ -81,7 +85,7 @@ func (srv *Server) ImageInsert(name, url, path string, out io.Writer) (string, e
81 81
 	}
82 82
 	defer file.Body.Close()
83 83
 
84
-	config, _, err := ParseRun([]string{img.Id, "echo", "insert", url, path}, srv.runtime.capabilities)
84
+	config, _, err := ParseRun([]string{img.ID, "echo", "insert", url, path}, srv.runtime.capabilities)
85 85
 	if err != nil {
86 86
 		return "", err
87 87
 	}
... ...
@@ -92,7 +96,7 @@ func (srv *Server) ImageInsert(name, url, path string, out io.Writer) (string, e
92 92
 		return "", err
93 93
 	}
94 94
 
95
-	if err := c.Inject(utils.ProgressReader(file.Body, int(file.ContentLength), out, "Downloading %v/%v (%v)\r", false), path); err != nil {
95
+	if err := c.Inject(utils.ProgressReader(file.Body, int(file.ContentLength), out, sf.FormatProgress("Downloading", "%v/%v (%v)"), sf), path); err != nil {
96 96
 		return "", err
97 97
 	}
98 98
 	// FIXME: Handle custom repo, tag comment, author
... ...
@@ -100,8 +104,8 @@ func (srv *Server) ImageInsert(name, url, path string, out io.Writer) (string, e
100 100
 	if err != nil {
101 101
 		return "", err
102 102
 	}
103
-	fmt.Fprintf(out, "%s\n", img.Id)
104
-	return img.ShortId(), nil
103
+	out.Write(sf.FormatStatus(img.ID))
104
+	return img.ShortID(), nil
105 105
 }
106 106
 
107 107
 func (srv *Server) ImagesViz(out io.Writer) error {
... ...
@@ -121,9 +125,9 @@ func (srv *Server) ImagesViz(out io.Writer) error {
121 121
 			return fmt.Errorf("Error while getting parent image: %v", err)
122 122
 		}
123 123
 		if parentImage != nil {
124
-			out.Write([]byte(" \"" + parentImage.ShortId() + "\" -> \"" + image.ShortId() + "\"\n"))
124
+			out.Write([]byte(" \"" + parentImage.ShortID() + "\" -> \"" + image.ShortID() + "\"\n"))
125 125
 		} else {
126
-			out.Write([]byte(" base -> \"" + image.ShortId() + "\" [style=invis]\n"))
126
+			out.Write([]byte(" base -> \"" + image.ShortID() + "\" [style=invis]\n"))
127 127
 		}
128 128
 	}
129 129
 
... ...
@@ -131,7 +135,7 @@ func (srv *Server) ImagesViz(out io.Writer) error {
131 131
 
132 132
 	for name, repository := range srv.runtime.repositories.Repositories {
133 133
 		for tag, id := range repository {
134
-			reporefs[utils.TruncateId(id)] = append(reporefs[utils.TruncateId(id)], fmt.Sprintf("%s:%s", name, tag))
134
+			reporefs[utils.TruncateID(id)] = append(reporefs[utils.TruncateID(id)], fmt.Sprintf("%s:%s", name, tag))
135 135
 		}
136 136
 	}
137 137
 
... ...
@@ -142,7 +146,7 @@ func (srv *Server) ImagesViz(out io.Writer) error {
142 142
 	return nil
143 143
 }
144 144
 
145
-func (srv *Server) Images(all bool, filter string) ([]ApiImages, error) {
145
+func (srv *Server) Images(all bool, filter string) ([]APIImages, error) {
146 146
 	var (
147 147
 		allImages map[string]*Image
148 148
 		err       error
... ...
@@ -155,13 +159,13 @@ func (srv *Server) Images(all bool, filter string) ([]ApiImages, error) {
155 155
 	if err != nil {
156 156
 		return nil, err
157 157
 	}
158
-	outs := []ApiImages{} //produce [] when empty instead of 'null'
158
+	outs := []APIImages{} //produce [] when empty instead of 'null'
159 159
 	for name, repository := range srv.runtime.repositories.Repositories {
160 160
 		if filter != "" && name != filter {
161 161
 			continue
162 162
 		}
163 163
 		for tag, id := range repository {
164
-			var out ApiImages
164
+			var out APIImages
165 165
 			image, err := srv.runtime.graph.Get(id)
166 166
 			if err != nil {
167 167
 				log.Printf("Warning: couldn't load %s from %s/%s: %s", id, name, tag, err)
... ...
@@ -170,7 +174,7 @@ func (srv *Server) Images(all bool, filter string) ([]ApiImages, error) {
170 170
 			delete(allImages, id)
171 171
 			out.Repository = name
172 172
 			out.Tag = tag
173
-			out.Id = image.Id
173
+			out.ID = image.ID
174 174
 			out.Created = image.Created.Unix()
175 175
 			out.Size = image.Size
176 176
 			out.ParentSize = image.getVirtualSize(0)
... ...
@@ -180,8 +184,8 @@ func (srv *Server) Images(all bool, filter string) ([]ApiImages, error) {
180 180
 	// Display images which aren't part of a
181 181
 	if filter == "" {
182 182
 		for _, image := range allImages {
183
-			var out ApiImages
184
-			out.Id = image.Id
183
+			var out APIImages
184
+			out.ID = image.ID
185 185
 			out.Created = image.Created.Unix()
186 186
 			out.Size = image.Size
187 187
 			out.ParentSize = image.getVirtualSize(0)
... ...
@@ -191,7 +195,7 @@ func (srv *Server) Images(all bool, filter string) ([]ApiImages, error) {
191 191
 	return outs, nil
192 192
 }
193 193
 
194
-func (srv *Server) DockerInfo() ApiInfo {
194
+func (srv *Server) DockerInfo() *APIInfo {
195 195
 	images, _ := srv.runtime.graph.All()
196 196
 	var imgcount int
197 197
 	if images == nil {
... ...
@@ -199,29 +203,27 @@ func (srv *Server) DockerInfo() ApiInfo {
199 199
 	} else {
200 200
 		imgcount = len(images)
201 201
 	}
202
-	var out ApiInfo
203
-	out.Containers = len(srv.runtime.List())
204
-	out.Version = VERSION
205
-	out.Images = imgcount
206
-	out.GoVersion = runtime.Version()
207
-	if os.Getenv("DEBUG") != "" {
208
-		out.Debug = true
209
-		out.NFd = utils.GetTotalUsedFds()
210
-		out.NGoroutines = runtime.NumGoroutine()
202
+	return &APIInfo{
203
+		Containers:  len(srv.runtime.List()),
204
+		Images:      imgcount,
205
+		MemoryLimit: srv.runtime.capabilities.MemoryLimit,
206
+		SwapLimit:   srv.runtime.capabilities.SwapLimit,
207
+		Debug:       os.Getenv("DEBUG") != "",
208
+		NFd:         utils.GetTotalUsedFds(),
209
+		NGoroutines: runtime.NumGoroutine(),
211 210
 	}
212
-	return out
213 211
 }
214 212
 
215
-func (srv *Server) ImageHistory(name string) ([]ApiHistory, error) {
213
+func (srv *Server) ImageHistory(name string) ([]APIHistory, error) {
216 214
 	image, err := srv.runtime.repositories.LookupImage(name)
217 215
 	if err != nil {
218 216
 		return nil, err
219 217
 	}
220 218
 
221
-	var outs []ApiHistory = []ApiHistory{} //produce [] when empty instead of 'null'
219
+	outs := []APIHistory{} //produce [] when empty instead of 'null'
222 220
 	err = image.WalkHistory(func(img *Image) error {
223
-		var out ApiHistory
224
-		out.Id = srv.runtime.repositories.ImageName(img.ShortId())
221
+		var out APIHistory
222
+		out.ID = srv.runtime.repositories.ImageName(img.ShortID())
225 223
 		out.Created = img.Created.Unix()
226 224
 		out.CreatedBy = strings.Join(img.ContainerConfig.Cmd, " ")
227 225
 		outs = append(outs, out)
... ...
@@ -238,17 +240,17 @@ func (srv *Server) ContainerChanges(name string) ([]Change, error) {
238 238
 	return nil, fmt.Errorf("No such container: %s", name)
239 239
 }
240 240
 
241
-func (srv *Server) Containers(all bool, n int, since, before string) []ApiContainers {
241
+func (srv *Server) Containers(all bool, n int, since, before string) []APIContainers {
242 242
 	var foundBefore bool
243 243
 	var displayed int
244
-	retContainers := []ApiContainers{}
244
+	retContainers := []APIContainers{}
245 245
 
246 246
 	for _, container := range srv.runtime.List() {
247 247
 		if !container.State.Running && !all && n == -1 && since == "" && before == "" {
248 248
 			continue
249 249
 		}
250 250
 		if before != "" {
251
-			if container.ShortId() == before {
251
+			if container.ShortID() == before {
252 252
 				foundBefore = true
253 253
 				continue
254 254
 			}
... ...
@@ -259,13 +261,13 @@ func (srv *Server) Containers(all bool, n int, since, before string) []ApiContai
259 259
 		if displayed == n {
260 260
 			break
261 261
 		}
262
-		if container.ShortId() == since {
262
+		if container.ShortID() == since {
263 263
 			break
264 264
 		}
265 265
 		displayed++
266 266
 
267
-		c := ApiContainers{
268
-			Id: container.Id,
267
+		c := APIContainers{
268
+			ID: container.ID,
269 269
 		}
270 270
 		c.Image = srv.runtime.repositories.ImageName(container.Image)
271 271
 		c.Command = fmt.Sprintf("%s %s", container.Path, strings.Join(container.Args, " "))
... ...
@@ -288,7 +290,7 @@ func (srv *Server) ContainerCommit(name, repo, tag, author, comment string, conf
288 288
 	if err != nil {
289 289
 		return "", err
290 290
 	}
291
-	return img.ShortId(), err
291
+	return img.ShortID(), err
292 292
 }
293 293
 
294 294
 func (srv *Server) ContainerTag(name, repo, tag string, force bool) error {
... ...
@@ -298,7 +300,7 @@ func (srv *Server) ContainerTag(name, repo, tag string, force bool) error {
298 298
 	return nil
299 299
 }
300 300
 
301
-func (srv *Server) pullImage(r *registry.Registry, out io.Writer, imgId, endpoint string, token []string, json bool) error {
301
+func (srv *Server) pullImage(r *registry.Registry, out io.Writer, imgId, endpoint string, token []string, sf *utils.StreamFormatter) error {
302 302
 	history, err := r.GetRemoteHistory(imgId, endpoint, token)
303 303
 	if err != nil {
304 304
 		return err
... ...
@@ -308,24 +310,25 @@ func (srv *Server) pullImage(r *registry.Registry, out io.Writer, imgId, endpoin
308 308
 	// FIXME: Launch the getRemoteImage() in goroutines
309 309
 	for _, id := range history {
310 310
 		if !srv.runtime.graph.Exists(id) {
311
-			fmt.Fprintf(out, utils.FormatStatus("Pulling %s metadata", json), id)
312
-			imgJson, err := r.GetRemoteImageJson(id, endpoint, token)
311
+			out.Write(sf.FormatStatus("Pulling %s metadata", id))
312
+			imgJSON, err := r.GetRemoteImageJSON(id, endpoint, token)
313 313
 			if err != nil {
314 314
 				// FIXME: Keep goging in case of error?
315 315
 				return err
316 316
 			}
317
-			img, err := NewImgJson(imgJson)
317
+			img, err := NewImgJSON(imgJSON)
318 318
 			if err != nil {
319 319
 				return fmt.Errorf("Failed to parse json: %s", err)
320 320
 			}
321 321
 
322 322
 			// Get the layer
323
-			fmt.Fprintf(out, utils.FormatStatus("Pulling %s fs layer", json), id)
324
-			layer, contentLength, err := r.GetRemoteImageLayer(img.Id, endpoint, token)
323
+			out.Write(sf.FormatStatus("Pulling %s fs layer", id))
324
+			layer, contentLength, err := r.GetRemoteImageLayer(img.ID, endpoint, token)
325 325
 			if err != nil {
326 326
 				return err
327 327
 			}
328
-			if err := srv.runtime.graph.Register(utils.ProgressReader(layer, contentLength, out, utils.FormatProgress("%v/%v (%v)", json), json), false, img); err != nil {
328
+			defer layer.Close()
329
+			if err := srv.runtime.graph.Register(utils.ProgressReader(layer, contentLength, out, sf.FormatProgress("Downloading", "%v/%v (%v)"), sf), false, img); err != nil {
329 330
 				return err
330 331
 			}
331 332
 		}
... ...
@@ -333,8 +336,8 @@ func (srv *Server) pullImage(r *registry.Registry, out io.Writer, imgId, endpoin
333 333
 	return nil
334 334
 }
335 335
 
336
-func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, remote, askedTag string, json bool) error {
337
-	fmt.Fprintf(out, utils.FormatStatus("Pulling repository %s from %s", json), remote, auth.IndexServerAddress())
336
+func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, remote, askedTag string, sf *utils.StreamFormatter) error {
337
+	out.Write(sf.FormatStatus("Pulling repository %s from %s", remote, auth.IndexServerAddress()))
338 338
 	repoData, err := r.GetRepositoryData(remote)
339 339
 	if err != nil {
340 340
 		return err
... ...
@@ -359,23 +362,23 @@ func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, remote, a
359 359
 		}
360 360
 	} else {
361 361
 		// Otherwise, check that the tag exists and use only that one
362
-		if id, exists := tagsList[askedTag]; !exists {
362
+		id, exists := tagsList[askedTag]
363
+		if !exists {
363 364
 			return fmt.Errorf("Tag %s not found in repositoy %s", askedTag, remote)
364
-		} else {
365
-			repoData.ImgList[id].Tag = askedTag
366 365
 		}
366
+		repoData.ImgList[id].Tag = askedTag
367 367
 	}
368 368
 
369 369
 	for _, img := range repoData.ImgList {
370 370
 		if askedTag != "" && img.Tag != askedTag {
371
-			utils.Debugf("(%s) does not match %s (id: %s), skipping", img.Tag, askedTag, img.Id)
371
+			utils.Debugf("(%s) does not match %s (id: %s), skipping", img.Tag, askedTag, img.ID)
372 372
 			continue
373 373
 		}
374
-		fmt.Fprintf(out, utils.FormatStatus("Pulling image %s (%s) from %s", json), img.Id, img.Tag, remote)
374
+		out.Write(sf.FormatStatus("Pulling image %s (%s) from %s", img.ID, img.Tag, remote))
375 375
 		success := false
376 376
 		for _, ep := range repoData.Endpoints {
377
-			if err := srv.pullImage(r, out, img.Id, "https://"+ep+"/v1", repoData.Tokens, json); err != nil {
378
-				fmt.Fprintf(out, utils.FormatStatus("Error while retrieving image for tag: %s (%s); checking next endpoint\n", json), askedTag, err)
377
+			if err := srv.pullImage(r, out, img.ID, "https://"+ep+"/v1", repoData.Tokens, sf); err != nil {
378
+				out.Write(sf.FormatStatus("Error while retrieving image for tag: %s (%s); checking next endpoint", askedTag, err))
379 379
 				continue
380 380
 			}
381 381
 			success = true
... ...
@@ -400,17 +403,17 @@ func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, remote, a
400 400
 	return nil
401 401
 }
402 402
 
403
-func (srv *Server) ImagePull(name, tag, endpoint string, out io.Writer, json bool) error {
403
+func (srv *Server) ImagePull(name, tag, endpoint string, out io.Writer, sf *utils.StreamFormatter) error {
404 404
 	r := registry.NewRegistry(srv.runtime.root)
405 405
 	out = utils.NewWriteFlusher(out)
406 406
 	if endpoint != "" {
407
-		if err := srv.pullImage(r, out, name, endpoint, nil, json); err != nil {
407
+		if err := srv.pullImage(r, out, name, endpoint, nil, sf); err != nil {
408 408
 			return err
409 409
 		}
410 410
 		return nil
411 411
 	}
412 412
 
413
-	if err := srv.pullRepository(r, out, name, tag, json); err != nil {
413
+	if err := srv.pullRepository(r, out, name, tag, sf); err != nil {
414 414
 		return err
415 415
 	}
416 416
 
... ...
@@ -464,16 +467,16 @@ func (srv *Server) getImageList(localRepo map[string]string) ([]*registry.ImgDat
464 464
 			return nil, err
465 465
 		}
466 466
 		img.WalkHistory(func(img *Image) error {
467
-			if _, exists := imageSet[img.Id]; exists {
467
+			if _, exists := imageSet[img.ID]; exists {
468 468
 				return nil
469 469
 			}
470
-			imageSet[img.Id] = struct{}{}
471
-			checksum, err := srv.getChecksum(img.Id)
470
+			imageSet[img.ID] = struct{}{}
471
+			checksum, err := srv.getChecksum(img.ID)
472 472
 			if err != nil {
473 473
 				return err
474 474
 			}
475 475
 			imgList = append([]*registry.ImgData{{
476
-				Id:       img.Id,
476
+				ID:       img.ID,
477 477
 				Checksum: checksum,
478 478
 				Tag:      tag,
479 479
 			}}, imgList...)
... ...
@@ -483,52 +486,52 @@ func (srv *Server) getImageList(localRepo map[string]string) ([]*registry.ImgDat
483 483
 	return imgList, nil
484 484
 }
485 485
 
486
-func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, name string, localRepo map[string]string) error {
486
+func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, name string, localRepo map[string]string, sf *utils.StreamFormatter) error {
487 487
 	out = utils.NewWriteFlusher(out)
488
-	fmt.Fprintf(out, "Processing checksums\n")
488
+	out.Write(sf.FormatStatus("Processing checksums"))
489 489
 	imgList, err := srv.getImageList(localRepo)
490 490
 	if err != nil {
491 491
 		return err
492 492
 	}
493
-	fmt.Fprintf(out, "Sending images list\n")
493
+	out.Write(sf.FormatStatus("Sending image list"))
494 494
 
495
-	repoData, err := r.PushImageJsonIndex(name, imgList, false)
495
+	repoData, err := r.PushImageJSONIndex(name, imgList, false)
496 496
 	if err != nil {
497 497
 		return err
498 498
 	}
499 499
 
500 500
 	for _, ep := range repoData.Endpoints {
501
-		fmt.Fprintf(out, "Pushing repository %s to %s (%d tags)\r\n", name, ep, len(localRepo))
501
+		out.Write(sf.FormatStatus("Pushing repository %s to %s (%d tags)", name, ep, len(localRepo)))
502 502
 		// For each image within the repo, push them
503 503
 		for _, elem := range imgList {
504
-			if _, exists := repoData.ImgList[elem.Id]; exists {
505
-				fmt.Fprintf(out, "Image %s already on registry, skipping\n", name)
504
+			if _, exists := repoData.ImgList[elem.ID]; exists {
505
+				out.Write(sf.FormatStatus("Image %s already on registry, skipping", name))
506 506
 				continue
507 507
 			}
508
-			if err := srv.pushImage(r, out, name, elem.Id, ep, repoData.Tokens); err != nil {
508
+			if err := srv.pushImage(r, out, name, elem.ID, ep, repoData.Tokens, sf); err != nil {
509 509
 				// FIXME: Continue on error?
510 510
 				return err
511 511
 			}
512
-			fmt.Fprintf(out, "Pushing tags for rev [%s] on {%s}\n", elem.Id, ep+"/users/"+name+"/"+elem.Tag)
513
-			if err := r.PushRegistryTag(name, elem.Id, elem.Tag, ep, repoData.Tokens); err != nil {
512
+			out.Write(sf.FormatStatus("Pushing tags for rev [%s] on {%s}", elem.ID, ep+"/users/"+name+"/"+elem.Tag))
513
+			if err := r.PushRegistryTag(name, elem.ID, elem.Tag, ep, repoData.Tokens); err != nil {
514 514
 				return err
515 515
 			}
516 516
 		}
517 517
 	}
518 518
 
519
-	if _, err := r.PushImageJsonIndex(name, imgList, true); err != nil {
519
+	if _, err := r.PushImageJSONIndex(name, imgList, true); err != nil {
520 520
 		return err
521 521
 	}
522 522
 	return nil
523 523
 }
524 524
 
525
-func (srv *Server) pushImage(r *registry.Registry, out io.Writer, remote, imgId, ep string, token []string) error {
525
+func (srv *Server) pushImage(r *registry.Registry, out io.Writer, remote, imgId, ep string, token []string, sf *utils.StreamFormatter) error {
526 526
 	out = utils.NewWriteFlusher(out)
527 527
 	jsonRaw, err := ioutil.ReadFile(path.Join(srv.runtime.graph.Root, imgId, "json"))
528 528
 	if err != nil {
529 529
 		return fmt.Errorf("Error while retreiving the path for {%s}: %s", imgId, err)
530 530
 	}
531
-	fmt.Fprintf(out, "Pushing %s\r\n", imgId)
531
+	out.Write(sf.FormatStatus("Pushing %s", imgId))
532 532
 
533 533
 	// Make sure we have the image's checksum
534 534
 	checksum, err := srv.getChecksum(imgId)
... ...
@@ -536,14 +539,14 @@ func (srv *Server) pushImage(r *registry.Registry, out io.Writer, remote, imgId,
536 536
 		return err
537 537
 	}
538 538
 	imgData := &registry.ImgData{
539
-		Id:       imgId,
539
+		ID:       imgId,
540 540
 		Checksum: checksum,
541 541
 	}
542 542
 
543 543
 	// Send the json
544
-	if err := r.PushImageJsonRegistry(imgData, jsonRaw, ep, token); err != nil {
544
+	if err := r.PushImageJSONRegistry(imgData, jsonRaw, ep, token); err != nil {
545 545
 		if err == registry.ErrAlreadyExists {
546
-			fmt.Fprintf(out, "Image %s already uploaded ; skipping\n", imgData.Id)
546
+			out.Write(sf.FormatStatus("Image %s already uploaded ; skipping", imgData.ID))
547 547
 			return nil
548 548
 		}
549 549
 		return err
... ...
@@ -576,22 +579,22 @@ func (srv *Server) pushImage(r *registry.Registry, out io.Writer, remote, imgId,
576 576
 	}
577 577
 
578 578
 	// Send the layer
579
-	if err := r.PushImageLayerRegistry(imgData.Id, utils.ProgressReader(layerData, int(layerData.Size), out, "", false), ep, token); err != nil {
579
+	if err := r.PushImageLayerRegistry(imgData.ID, utils.ProgressReader(layerData, int(layerData.Size), out, sf.FormatProgress("Pushing", "%v/%v (%v)"), sf), ep, token); err != nil {
580 580
 		return err
581 581
 	}
582 582
 	return nil
583 583
 }
584 584
 
585
-func (srv *Server) ImagePush(name, endpoint string, out io.Writer) error {
585
+func (srv *Server) ImagePush(name, endpoint string, out io.Writer, sf *utils.StreamFormatter) error {
586 586
 	out = utils.NewWriteFlusher(out)
587 587
 	img, err := srv.runtime.graph.Get(name)
588 588
 	r := registry.NewRegistry(srv.runtime.root)
589 589
 
590 590
 	if err != nil {
591
-		fmt.Fprintf(out, "The push refers to a repository [%s] (len: %d)\n", name, len(srv.runtime.repositories.Repositories[name]))
591
+		out.Write(sf.FormatStatus("The push refers to a repository [%s] (len: %d)", name, len(srv.runtime.repositories.Repositories[name])))
592 592
 		// If it fails, try to get the repository
593 593
 		if localRepo, exists := srv.runtime.repositories.Repositories[name]; exists {
594
-			if err := srv.pushRepository(r, out, name, localRepo); err != nil {
594
+			if err := srv.pushRepository(r, out, name, localRepo, sf); err != nil {
595 595
 				return err
596 596
 			}
597 597
 			return nil
... ...
@@ -599,14 +602,14 @@ func (srv *Server) ImagePush(name, endpoint string, out io.Writer) error {
599 599
 
600 600
 		return err
601 601
 	}
602
-	fmt.Fprintf(out, "The push refers to an image: [%s]\n", name)
603
-	if err := srv.pushImage(r, out, name, img.Id, endpoint, nil); err != nil {
602
+	out.Write(sf.FormatStatus("The push refers to an image: [%s]", name))
603
+	if err := srv.pushImage(r, out, name, img.ID, endpoint, nil, sf); err != nil {
604 604
 		return err
605 605
 	}
606 606
 	return nil
607 607
 }
608 608
 
609
-func (srv *Server) ImageImport(src, repo, tag string, in io.Reader, out io.Writer) error {
609
+func (srv *Server) ImageImport(src, repo, tag string, in io.Reader, out io.Writer, sf *utils.StreamFormatter) error {
610 610
 	var archive io.Reader
611 611
 	var resp *http.Response
612 612
 
... ...
@@ -615,21 +618,21 @@ func (srv *Server) ImageImport(src, repo, tag string, in io.Reader, out io.Write
615 615
 	} else {
616 616
 		u, err := url.Parse(src)
617 617
 		if err != nil {
618
-			fmt.Fprintf(out, "Error: %s\n", err)
618
+			return err
619 619
 		}
620 620
 		if u.Scheme == "" {
621 621
 			u.Scheme = "http"
622 622
 			u.Host = src
623 623
 			u.Path = ""
624 624
 		}
625
-		fmt.Fprintf(out, "Downloading from %s\n", u)
625
+		out.Write(sf.FormatStatus("Downloading from %s", u))
626 626
 		// Download with curl (pretty progress bar)
627 627
 		// If curl is not available, fallback to http.Get()
628 628
 		resp, err = utils.Download(u.String(), out)
629 629
 		if err != nil {
630 630
 			return err
631 631
 		}
632
-		archive = utils.ProgressReader(resp.Body, int(resp.ContentLength), out, "Importing %v/%v (%v)\r", false)
632
+		archive = utils.ProgressReader(resp.Body, int(resp.ContentLength), out, sf.FormatProgress("Importing", "%v/%v (%v)"), sf)
633 633
 	}
634 634
 	img, err := srv.runtime.graph.Create(archive, nil, "Imported from "+src, "", nil)
635 635
 	if err != nil {
... ...
@@ -637,11 +640,11 @@ func (srv *Server) ImageImport(src, repo, tag string, in io.Reader, out io.Write
637 637
 	}
638 638
 	// Optionally register the image at REPO/TAG
639 639
 	if repo != "" {
640
-		if err := srv.runtime.repositories.Set(repo, tag, img.Id, true); err != nil {
640
+		if err := srv.runtime.repositories.Set(repo, tag, img.ID, true); err != nil {
641 641
 			return err
642 642
 		}
643 643
 	}
644
-	fmt.Fprintf(out, "%s\n", img.ShortId())
644
+	out.Write(sf.FormatStatus(img.ShortID()))
645 645
 	return nil
646 646
 }
647 647
 
... ...
@@ -662,7 +665,7 @@ func (srv *Server) ContainerCreate(config *Config) (string, error) {
662 662
 		}
663 663
 		return "", err
664 664
 	}
665
-	return container.ShortId(), nil
665
+	return container.ShortID(), nil
666 666
 }
667 667
 
668 668
 func (srv *Server) ContainerRestart(name string, t int) error {
... ...
@@ -699,7 +702,7 @@ func (srv *Server) ContainerDestroy(name string, removeVolume bool) error {
699 699
 			for volumeId := range volumes {
700 700
 				// If the requested volu
701 701
 				if c, exists := usedVolumes[volumeId]; exists {
702
-					log.Printf("The volume %s is used by the container %s. Impossible to remove it. Skipping.\n", volumeId, c.Id)
702
+					log.Printf("The volume %s is used by the container %s. Impossible to remove it. Skipping.\n", volumeId, c.ID)
703 703
 					continue
704 704
 				}
705 705
 				if err := srv.runtime.volumes.Delete(volumeId); err != nil {
... ...
@@ -717,10 +720,9 @@ func (srv *Server) ImageDelete(name string) error {
717 717
 	img, err := srv.runtime.repositories.LookupImage(name)
718 718
 	if err != nil {
719 719
 		return fmt.Errorf("No such image: %s", name)
720
-	} else {
721
-		if err := srv.runtime.graph.Delete(img.Id); err != nil {
722
-			return fmt.Errorf("Error deleting image %s: %s", name, err.Error())
723
-		}
720
+	}
721
+	if err := srv.runtime.graph.Delete(img.ID); err != nil {
722
+		return fmt.Errorf("Error deleting image %s: %s", name, err.Error())
724 723
 	}
725 724
 	return nil
726 725
 }
... ...
@@ -739,7 +741,7 @@ func (srv *Server) ImageGetCached(imgId string, config *Config) (*Image, error)
739 739
 		if _, exists := imageMap[img.Parent]; !exists {
740 740
 			imageMap[img.Parent] = make(map[string]struct{})
741 741
 		}
742
-		imageMap[img.Parent][img.Id] = struct{}{}
742
+		imageMap[img.Parent][img.ID] = struct{}{}
743 743
 	}
744 744
 
745 745
 	// Loop on the children of the given image and check the config
... ...
@@ -796,7 +798,6 @@ func (srv *Server) ContainerAttach(name string, logs, stream, stdin, stdout, std
796 796
 	if container == nil {
797 797
 		return fmt.Errorf("No such container: %s", name)
798 798
 	}
799
-
800 799
 	//logs
801 800
 	if logs {
802 801
 		if stdout {
... ...
@@ -822,6 +823,9 @@ func (srv *Server) ContainerAttach(name string, logs, stream, stdin, stdout, std
822 822
 		if container.State.Ghost {
823 823
 			return fmt.Errorf("Impossible to attach to a ghost container")
824 824
 		}
825
+		if !container.State.Running {
826
+			return fmt.Errorf("Impossible to attach to a stopped container, start it first")
827
+		}
825 828
 
826 829
 		var (
827 830
 			cStdin           io.ReadCloser
... ...
@@ -13,7 +13,7 @@ func TestCreateRm(t *testing.T) {
13 13
 
14 14
 	srv := &Server{runtime: runtime}
15 15
 
16
-	config, _, err := ParseRun([]string{GetTestImage(runtime).Id, "echo test"}, nil)
16
+	config, _, err := ParseRun([]string{GetTestImage(runtime).ID, "echo test"}, nil)
17 17
 	if err != nil {
18 18
 		t.Fatal(err)
19 19
 	}
... ...
@@ -46,7 +46,7 @@ func TestCreateStartRestartStopStartKillRm(t *testing.T) {
46 46
 
47 47
 	srv := &Server{runtime: runtime}
48 48
 
49
-	config, _, err := ParseRun([]string{GetTestImage(runtime).Id, "/bin/cat"}, nil)
49
+	config, _, err := ParseRun([]string{GetTestImage(runtime).ID, "/bin/cat"}, nil)
50 50
 	if err != nil {
51 51
 		t.Fatal(err)
52 52
 	}
... ...
@@ -11,7 +11,7 @@ import (
11 11
 	"strings"
12 12
 )
13 13
 
14
-const DEFAULT_TAG = "latest"
14
+const DEFAULTTAG = "latest"
15 15
 
16 16
 type TagStore struct {
17 17
 	path         string
... ...
@@ -72,7 +72,7 @@ func (store *TagStore) LookupImage(name string) (*Image, error) {
72 72
 		// (so we can pass all errors here)
73 73
 		repoAndTag := strings.SplitN(name, ":", 2)
74 74
 		if len(repoAndTag) == 1 {
75
-			repoAndTag = append(repoAndTag, DEFAULT_TAG)
75
+			repoAndTag = append(repoAndTag, DEFAULTTAG)
76 76
 		}
77 77
 		if i, err := store.GetImage(repoAndTag[0], repoAndTag[1]); err != nil {
78 78
 			return nil, err
... ...
@@ -87,27 +87,27 @@ func (store *TagStore) LookupImage(name string) (*Image, error) {
87 87
 
88 88
 // Return a reverse-lookup table of all the names which refer to each image
89 89
 // Eg. {"43b5f19b10584": {"base:latest", "base:v1"}}
90
-func (store *TagStore) ById() map[string][]string {
91
-	byId := make(map[string][]string)
90
+func (store *TagStore) ByID() map[string][]string {
91
+	byID := make(map[string][]string)
92 92
 	for repoName, repository := range store.Repositories {
93 93
 		for tag, id := range repository {
94 94
 			name := repoName + ":" + tag
95
-			if _, exists := byId[id]; !exists {
96
-				byId[id] = []string{name}
95
+			if _, exists := byID[id]; !exists {
96
+				byID[id] = []string{name}
97 97
 			} else {
98
-				byId[id] = append(byId[id], name)
99
-				sort.Strings(byId[id])
98
+				byID[id] = append(byID[id], name)
99
+				sort.Strings(byID[id])
100 100
 			}
101 101
 		}
102 102
 	}
103
-	return byId
103
+	return byID
104 104
 }
105 105
 
106 106
 func (store *TagStore) ImageName(id string) string {
107
-	if names, exists := store.ById()[id]; exists && len(names) > 0 {
107
+	if names, exists := store.ByID()[id]; exists && len(names) > 0 {
108 108
 		return names[0]
109 109
 	}
110
-	return utils.TruncateId(id)
110
+	return utils.TruncateID(id)
111 111
 }
112 112
 
113 113
 func (store *TagStore) Set(repoName, tag, imageName string, force bool) error {
... ...
@@ -116,7 +116,7 @@ func (store *TagStore) Set(repoName, tag, imageName string, force bool) error {
116 116
 		return err
117 117
 	}
118 118
 	if tag == "" {
119
-		tag = DEFAULT_TAG
119
+		tag = DEFAULTTAG
120 120
 	}
121 121
 	if err := validateRepoName(repoName); err != nil {
122 122
 		return err
... ...
@@ -137,7 +137,7 @@ func (store *TagStore) Set(repoName, tag, imageName string, force bool) error {
137 137
 		}
138 138
 		store.Repositories[repoName] = repo
139 139
 	}
140
-	repo[tag] = img.Id
140
+	repo[tag] = img.ID
141 141
 	return store.Save()
142 142
 }
143 143
 
144 144
new file mode 100644
... ...
@@ -0,0 +1,2 @@
0
+Guillaume Charmes <guillaume@dotcloud.com>
1
+Solomon Hykes <solomon@dotcloud.com>
... ...
@@ -7,104 +7,6 @@ import (
7 7
 	"unsafe"
8 8
 )
9 9
 
10
-type Termios struct {
11
-	Iflag  uintptr
12
-	Oflag  uintptr
13
-	Cflag  uintptr
14
-	Lflag  uintptr
15
-	Cc     [20]byte
16
-	Ispeed uintptr
17
-	Ospeed uintptr
18
-}
19
-
20
-const (
21
-	// Input flags
22
-	inpck  = 0x010
23
-	istrip = 0x020
24
-	icrnl  = 0x100
25
-	ixon   = 0x200
26
-
27
-	// Output flags
28
-	opost = 0x1
29
-
30
-	// Control flags
31
-	cs8 = 0x300
32
-
33
-	// Local flags
34
-	icanon = 0x100
35
-	iexten = 0x400
36
-)
37
-
38
-const (
39
-	HUPCL   = 0x4000
40
-	ICANON  = 0x100
41
-	ICRNL   = 0x100
42
-	IEXTEN  = 0x400
43
-	BRKINT  = 0x2
44
-	CFLUSH  = 0xf
45
-	CLOCAL  = 0x8000
46
-	CREAD   = 0x800
47
-	CS5     = 0x0
48
-	CS6     = 0x100
49
-	CS7     = 0x200
50
-	CS8     = 0x300
51
-	CSIZE   = 0x300
52
-	CSTART  = 0x11
53
-	CSTATUS = 0x14
54
-	CSTOP   = 0x13
55
-	CSTOPB  = 0x400
56
-	CSUSP   = 0x1a
57
-	IGNBRK  = 0x1
58
-	IGNCR   = 0x80
59
-	IGNPAR  = 0x4
60
-	IMAXBEL = 0x2000
61
-	INLCR   = 0x40
62
-	INPCK   = 0x10
63
-	ISIG    = 0x80
64
-	ISTRIP  = 0x20
65
-	IUTF8   = 0x4000
66
-	IXANY   = 0x800
67
-	IXOFF   = 0x400
68
-	IXON    = 0x200
69
-	NOFLSH  = 0x80000000
70
-	OCRNL   = 0x10
71
-	OFDEL   = 0x20000
72
-	OFILL   = 0x80
73
-	ONLCR   = 0x2
74
-	ONLRET  = 0x40
75
-	ONOCR   = 0x20
76
-	ONOEOT  = 0x8
77
-	OPOST   = 0x1
78
-	RENB    = 0x1000
79
-	PARMRK  = 0x8
80
-	PARODD  = 0x2000
81
-
82
-	TOSTOP   = 0x400000
83
-	VDISCARD = 0xf
84
-	VDSUSP   = 0xb
85
-	VEOF     = 0x0
86
-	VEOL     = 0x1
87
-	VEOL2    = 0x2
88
-	VERASE   = 0x3
89
-	VINTR    = 0x8
90
-	VKILL    = 0x5
91
-	VLNEXT   = 0xe
92
-	VMIN     = 0x10
93
-	VQUIT    = 0x9
94
-	VREPRINT = 0x6
95
-	VSTART   = 0xc
96
-	VSTATUS  = 0x12
97
-	VSTOP    = 0xd
98
-	VSUSP    = 0xa
99
-	VT0      = 0x0
100
-	VT1      = 0x10000
101
-	VTDLY    = 0x10000
102
-	VTIME    = 0x11
103
-	ECHO     = 0x00000008
104
-
105
-	PENDIN = 0x20000000
106
-)
107
-
108 10
 type State struct {
109 11
 	termios Termios
110 12
 }
... ...
@@ -128,21 +30,21 @@ func SetWinsize(fd uintptr, ws *Winsize) error {
128 128
 }
129 129
 
130 130
 // IsTerminal returns true if the given file descriptor is a terminal.
131
-func IsTerminal(fd int) bool {
131
+func IsTerminal(fd uintptr) bool {
132 132
 	var termios Termios
133
-	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(getTermios), uintptr(unsafe.Pointer(&termios)))
133
+	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(getTermios), uintptr(unsafe.Pointer(&termios)))
134 134
 	return err == 0
135 135
 }
136 136
 
137 137
 // Restore restores the terminal connected to the given file descriptor to a
138 138
 // previous state.
139
-func Restore(fd int, state *State) error {
140
-	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(setTermios), uintptr(unsafe.Pointer(&state.termios)))
139
+func Restore(fd uintptr, state *State) error {
140
+	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(setTermios), uintptr(unsafe.Pointer(&state.termios)))
141 141
 	return err
142 142
 }
143 143
 
144 144
 func SetRawTerminal() (*State, error) {
145
-	oldState, err := MakeRaw(int(os.Stdin.Fd()))
145
+	oldState, err := MakeRaw(os.Stdin.Fd())
146 146
 	if err != nil {
147 147
 		return nil, err
148 148
 	}
... ...
@@ -150,12 +52,12 @@ func SetRawTerminal() (*State, error) {
150 150
 	signal.Notify(c, os.Interrupt)
151 151
 	go func() {
152 152
 		_ = <-c
153
-		Restore(int(os.Stdin.Fd()), oldState)
153
+		Restore(os.Stdin.Fd(), oldState)
154 154
 		os.Exit(0)
155 155
 	}()
156 156
 	return oldState, err
157 157
 }
158 158
 
159 159
 func RestoreTerminal(state *State) {
160
-	Restore(int(os.Stdin.Fd()), state)
160
+	Restore(os.Stdin.Fd(), state)
161 161
 }
... ...
@@ -8,23 +8,45 @@ import (
8 8
 const (
9 9
 	getTermios = syscall.TIOCGETA
10 10
 	setTermios = syscall.TIOCSETA
11
+
12
+	ECHO    = 0x00000008
13
+	ONLCR   = 0x2
14
+	ISTRIP  = 0x20
15
+	INLCR   = 0x40
16
+	ISIG    = 0x80
17
+	IGNCR   = 0x80
18
+	ICANON  = 0x100
19
+	ICRNL   = 0x100
20
+	IXOFF   = 0x400
21
+	IXON    = 0x200
11 22
 )
12 23
 
24
+type Termios struct {
25
+	Iflag  uint64
26
+	Oflag  uint64
27
+	Cflag  uint64
28
+	Lflag  uint64
29
+	Cc     [20]byte
30
+	Ispeed uint64
31
+	Ospeed uint64
32
+}
33
+
13 34
 // MakeRaw put the terminal connected to the given file descriptor into raw
14 35
 // mode and returns the previous state of the terminal so that it can be
15 36
 // restored.
16
-func MakeRaw(fd int) (*State, error) {
37
+func MakeRaw(fd uintptr) (*State, error) {
17 38
 	var oldState State
18
-	if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(getTermios), uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 {
39
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(getTermios), uintptr(unsafe.Pointer(&oldState.termios))); err != 0 {
19 40
 		return nil, err
20 41
 	}
21 42
 
22 43
 	newState := oldState.termios
23
-	newState.Iflag &^= ISTRIP | INLCR | IGNCR | IXON | IXOFF
44
+	newState.Iflag &^= (ISTRIP | INLCR | IGNCR | IXON | IXOFF)
24 45
 	newState.Iflag |= ICRNL
25 46
 	newState.Oflag |= ONLCR
26
-	newState.Lflag &^= ECHO | ICANON | ISIG
27
-	if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(setTermios), uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
47
+	newState.Lflag &^= (ECHO | ICANON | ISIG)
48
+
49
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(setTermios), uintptr(unsafe.Pointer(&newState))); err != 0 {
28 50
 		return nil, err
29 51
 	}
30 52
 
... ...
@@ -5,54 +5,40 @@ import (
5 5
 	"unsafe"
6 6
 )
7 7
 
8
-// #include <termios.h>
9
-// #include <sys/ioctl.h>
10
-/*
11
-void MakeRaw(int fd) {
12
-  struct termios t;
13
-
14
-  // FIXME: Handle errors?
15
-  ioctl(fd, TCGETS, &t);
16
-
17
-  t.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
18
-  t.c_oflag &= ~OPOST;
19
-  t.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
20
-  t.c_cflag &= ~(CSIZE | PARENB);
21
-  t.c_cflag |= CS8;
22
-
23
-  ioctl(fd, TCSETS, &t);
24
-}
25
-*/
26
-import "C"
27
-
28 8
 const (
29 9
 	getTermios = syscall.TCGETS
30 10
 	setTermios = syscall.TCSETS
31 11
 )
32 12
 
13
+type Termios struct {
14
+	Iflag  uint32
15
+	Oflag  uint32
16
+	Cflag  uint32
17
+	Lflag  uint32
18
+	Cc     [20]byte
19
+	Ispeed uint32
20
+	Ospeed uint32
21
+}
22
+
33 23
 // MakeRaw put the terminal connected to the given file descriptor into raw
34 24
 // mode and returns the previous state of the terminal so that it can be
35 25
 // restored.
36
-func MakeRaw(fd int) (*State, error) {
26
+func MakeRaw(fd uintptr) (*State, error) {
37 27
 	var oldState State
38
-	if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), syscall.TCGETS, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 {
28
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, getTermios, uintptr(unsafe.Pointer(&oldState.termios))); err != 0 {
39 29
 		return nil, err
40 30
 	}
41
-	C.MakeRaw(C.int(fd))
42
-	return &oldState, nil
43
-
44
-	// FIXME: post on goland issues this: very same as the C function bug non-working
45 31
 
46
-	// newState := oldState.termios
32
+	newState := oldState.termios
47 33
 
48
-	// newState.Iflag &^= (IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON)
49
-	// newState.Oflag &^= OPOST
50
-	// newState.Lflag &^= (ECHO | syscall.ECHONL | ICANON | ISIG | IEXTEN)
51
-	// newState.Cflag &^= (CSIZE | syscall.PARENB)
52
-	// newState.Cflag |= CS8
34
+	newState.Iflag &^= (syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON)
35
+	newState.Oflag &^= syscall.OPOST
36
+	newState.Lflag &^= (syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN)
37
+	newState.Cflag &^= (syscall.CSIZE | syscall.PARENB)
38
+	newState.Cflag |= syscall.CS8
53 39
 
54
-	// if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.TCSETS, uintptr(unsafe.Pointer(&newState))); err != 0 {
55
-	// 	return nil, err
56
-	// }
57
-	// return &oldState, nil
40
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, setTermios, uintptr(unsafe.Pointer(&newState))); err != 0 {
41
+		return nil, err
42
+	}
43
+	return &oldState, nil
58 44
 }
... ...
@@ -4,6 +4,7 @@ import (
4 4
 	"bytes"
5 5
 	"crypto/sha256"
6 6
 	"encoding/hex"
7
+	"encoding/json"
7 8
 	"errors"
8 9
 	"fmt"
9 10
 	"index/suffixarray"
... ...
@@ -33,7 +34,7 @@ func Go(f func() error) chan error {
33 33
 // Request a given URL and return an io.Reader
34 34
 func Download(url string, stderr io.Writer) (*http.Response, error) {
35 35
 	var resp *http.Response
36
-	var err error = nil
36
+	var err error
37 37
 	if resp, err = http.Get(url); err != nil {
38 38
 		return nil, err
39 39
 	}
... ...
@@ -69,7 +70,7 @@ type progressReader struct {
69 69
 	readProgress int           // How much has been read so far (bytes)
70 70
 	lastUpdate   int           // How many bytes read at least update
71 71
 	template     string        // Template to print. Default "%v/%v (%v)"
72
-	json         bool
72
+	sf *StreamFormatter
73 73
 }
74 74
 
75 75
 func (r *progressReader) Read(p []byte) (n int, err error) {
... ...
@@ -93,7 +94,7 @@ func (r *progressReader) Read(p []byte) (n int, err error) {
93 93
 	}
94 94
 	// Send newline when complete
95 95
 	if err != nil {
96
-		fmt.Fprintf(r.output, FormatStatus("", r.json))
96
+		r.output.Write(r.sf.FormatStatus(""))
97 97
 	}
98 98
 
99 99
 	return read, err
... ...
@@ -101,11 +102,12 @@ func (r *progressReader) Read(p []byte) (n int, err error) {
101 101
 func (r *progressReader) Close() error {
102 102
 	return io.ReadCloser(r.reader).Close()
103 103
 }
104
-func ProgressReader(r io.ReadCloser, size int, output io.Writer, template string, json bool) *progressReader {
105
-	if template == "" {
106
-		template = "%v/%v (%v)\r"
104
+func ProgressReader(r io.ReadCloser, size int, output io.Writer, template []byte, sf *StreamFormatter) *progressReader {
105
+      	tpl := string(template)
106
+	if tpl == "" {
107
+		tpl = string(sf.FormatProgress("", "%v/%v (%v)"))
107 108
 	}
108
-	return &progressReader{r, NewWriteFlusher(output), size, 0, 0, template, json}
109
+	return &progressReader{r, NewWriteFlusher(output), size, 0, 0, tpl, sf}
109 110
 }
110 111
 
111 112
 // HumanDuration returns a human-readable approximation of a duration
... ...
@@ -361,11 +363,11 @@ func (idx *TruncIndex) Get(s string) (string, error) {
361 361
 	return string(idx.bytes[before:after]), err
362 362
 }
363 363
 
364
-// TruncateId returns a shorthand version of a string identifier for convenience.
364
+// TruncateID returns a shorthand version of a string identifier for convenience.
365 365
 // A collision with other shorthands is very unlikely, but possible.
366 366
 // In case of a collision a lookup with TruncIndex.Get() will fail, and the caller
367 367
 // will need to use a langer prefix, or the full-length Id.
368
-func TruncateId(id string) string {
368
+func TruncateID(id string) string {
369 369
 	shortLen := 12
370 370
 	if len(id) < shortLen {
371 371
 		shortLen = len(id)
... ...
@@ -578,16 +580,57 @@ func NewWriteFlusher(w io.Writer) *WriteFlusher {
578 578
 	return &WriteFlusher{w: w, flusher: flusher}
579 579
 }
580 580
 
581
-func FormatStatus(str string, json bool) string {
582
-	if json {
583
-		return "{\"status\" : \"" + str + "\"}"
581
+type JSONMessage struct {
582
+	Status   string `json:"status,omitempty"`
583
+	Progress string `json:"progress,omitempty"`
584
+	Error    string `json:"error,omitempty"`
585
+}
586
+
587
+type StreamFormatter struct {
588
+	json bool
589
+	used bool
590
+}
591
+
592
+func NewStreamFormatter(json bool) *StreamFormatter {
593
+	return &StreamFormatter{json, false}
594
+}
595
+
596
+func (sf *StreamFormatter) FormatStatus(format string, a ...interface{}) []byte {
597
+	sf.used = true
598
+	str := fmt.Sprintf(format, a...)
599
+	if sf.json {
600
+		b, err := json.Marshal(&JSONMessage{Status:str});
601
+		if err != nil {
602
+			return sf.FormatError(err)
603
+		}
604
+		return b
584 605
 	}
585
-	return str + "\r\n"
606
+	return []byte(str + "\r\n")
586 607
 }
587 608
 
588
-func FormatProgress(str string, json bool) string {
589
-	if json {
590
-		return "{\"progress\" : \"" + str + "\"}"
609
+func (sf *StreamFormatter) FormatError(err error) []byte {
610
+	sf.used = true
611
+	if sf.json {
612
+		if b, err := json.Marshal(&JSONMessage{Error:err.Error()}); err == nil {
613
+			return b
614
+		}
615
+		return []byte("{\"error\":\"format error\"}")
591 616
 	}
592
-	return "Downloading " + str + "\r"
617
+	return []byte("Error: " + err.Error() + "\r\n")
618
+}
619
+
620
+func (sf *StreamFormatter) FormatProgress(action, str string) []byte {
621
+	sf.used = true
622
+	if sf.json {
623
+		b, err := json.Marshal(&JSONMessage{Status: action, Progress:str})
624
+		if err != nil {
625
+                        return nil
626
+                }
627
+		return b
628
+	}
629
+	return []byte(action + " " + str + "\r")
630
+}
631
+
632
+func (sf *StreamFormatter) Used() bool {
633
+	return sf.used
593 634
 }