Victor Vieux 12 éve
szülő
commit
66d9a73362
54 módosított fájl, 1039 hozzáadás és 1050 törlés
  1. 5 0
      CHANGELOG.md
  2. 4 1
      README.md
  3. 37 37
      api.go
  4. 29 30
      api_params.go
  5. 77 77
      api_test.go
  6. 4 4
      auth/auth.go
  7. 5 5
      builder.go
  8. 20 20
      builder_client.go
  9. 10 10
      buildfile.go
  10. 3 3
      buildfile_test.go
  11. 1 1
      changes.go
  12. 74 73
      commands.go
  13. 46 45
      container.go
  14. 64 33
      container_test.go
  15. 3 3
      contrib/crashTest.go
  16. 0 1
      contrib/docker-build/MAINTAINERS
  17. 0 68
      contrib/docker-build/README
  18. 0 142
      contrib/docker-build/docker-build
  19. 0 13
      contrib/docker-build/example.changefile
  20. 0 3
      contrib/docker-build/myscript
  21. 2 2
      docker/docker.go
  22. 1 1
      docs/Makefile
  23. 10 9
      docs/sources/api/docker_remote_api.rst
  24. 1 1
      docs/sources/contributing/contributing.rst
  25. 26 2
      docs/sources/contributing/devenvironment.rst
  26. 7 5
      docs/sources/faq.rst
  27. 10 0
      docs/sources/installation/ubuntulinux.rst
  28. 1 0
      docs/sources/installation/windows.rst
  29. 1 1
      docs/sources/use/builder.rst
  30. 21 9
      docs/theme/docker/layout.html
  31. 40 1
      docs/theme/docker/static/css/main.css
  32. 38 3
      docs/theme/docker/static/css/main.less
  33. 25 18
      docs/website/gettingstarted/index.html
  34. 29 29
      docs/website/index.html
  35. 21 21
      graph.go
  36. 11 11
      graph_test.go
  37. 15 0
      hack/PRINCIPLES.md
  38. 88 0
      hack/ROADMAP.md
  39. 1 0
      hack/dockerbuilder/MAITAINERS
  40. 17 18
      image.go
  41. 1 1
      lxc_template.go
  42. 7 8
      network.go
  43. 1 1
      network_test.go
  44. 7 0
      packaging/ubuntu/changelog
  45. 41 27
      registry/registry.go
  46. 31 31
      runtime.go
  47. 25 25
      runtime_test.go
  48. 100 88
      server.go
  49. 2 2
      server_test.go
  50. 14 14
      tags.go
  51. 7 105
      term/term.go
  52. 27 5
      term/termios_darwin.go
  53. 22 36
      term/termios_linux.go
  54. 7 7
      utils/utils.go

+ 5 - 0
CHANGELOG.md

@@ -1,5 +1,10 @@
 # Changelog
 
+## 0.4.0 (2013-06-03)
+ + Introducing Builder: 'docker build' builds a container, layer by layer, from a source repository containing a Dockerfile
+ + Introducing Remote API: control Docker programmatically using a simple HTTP/json API
+ * Runtime: various reliability and usability improvements
+
 ## 0.3.4 (2013-05-30)
  + Builder: 'docker build' builds a container, layer by layer, from a source repository containing a Dockerfile
  + Builder: 'docker build -t FOO' applies the tag FOO to the newly built container.

+ 4 - 1
README.md

@@ -251,7 +251,7 @@ Note
 ----
 
 We also keep the documentation in this repository. The website documentation is generated using sphinx using these sources.
-Please find it under docs/sources/ and read more about it https://github.com/dotcloud/docker/master/docs/README.md
+Please find it under docs/sources/ and read more about it https://github.com/dotcloud/docker/tree/master/docs/README.md
 
 Please feel free to fix / update the documentation and send us pull requests. More tutorials are also welcome.
 
@@ -371,4 +371,7 @@ Standard Container Specification
 
 #### Security
 
+### Legal
+
+Transfers Docker shall be in accordance with any applicable export control or other legal requirements.
 

+ 37 - 37
api.go

@@ -13,7 +13,7 @@ import (
 	"strings"
 )
 
-const API_VERSION = 1.1
+const APIVERSION = 1.1
 
 func hijackServer(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) {
 	conn, _, err := w.(http.Hijacker).Hijack()
@@ -54,7 +54,7 @@ func httpError(w http.ResponseWriter, err error) {
 	}
 }
 
-func writeJson(w http.ResponseWriter, b []byte) {
+func writeJSON(w http.ResponseWriter, b []byte) {
 	w.Header().Set("Content-Type", "application/json")
 	w.Write(b)
 }
@@ -84,7 +84,7 @@ func getAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Reques
 	if err != nil {
 		return err
 	}
-	writeJson(w, b)
+	writeJSON(w, b)
 	return nil
 }
 
@@ -113,11 +113,11 @@ func postAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Reque
 	}
 
 	if status != "" {
-		b, err := json.Marshal(&ApiAuth{Status: status})
+		b, err := json.Marshal(&APIAuth{Status: status})
 		if err != nil {
 			return err
 		}
-		writeJson(w, b)
+		writeJSON(w, b)
 		return nil
 	}
 	w.WriteHeader(http.StatusNoContent)
@@ -130,7 +130,7 @@ func getVersion(srv *Server, version float64, w http.ResponseWriter, r *http.Req
 	if err != nil {
 		return err
 	}
-	writeJson(w, b)
+	writeJSON(w, b)
 	return nil
 }
 
@@ -159,7 +159,7 @@ func getContainersExport(srv *Server, version float64, w http.ResponseWriter, r
 	return nil
 }
 
-func getImagesJson(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func getImagesJSON(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := parseForm(r); err != nil {
 		return err
 	}
@@ -178,7 +178,7 @@ func getImagesJson(srv *Server, version float64, w http.ResponseWriter, r *http.
 	if err != nil {
 		return err
 	}
-	writeJson(w, b)
+	writeJSON(w, b)
 	return nil
 }
 
@@ -195,7 +195,7 @@ func getInfo(srv *Server, version float64, w http.ResponseWriter, r *http.Reques
 	if err != nil {
 		return err
 	}
-	writeJson(w, b)
+	writeJSON(w, b)
 	return nil
 }
 
@@ -212,7 +212,7 @@ func getImagesHistory(srv *Server, version float64, w http.ResponseWriter, r *ht
 	if err != nil {
 		return err
 	}
-	writeJson(w, b)
+	writeJSON(w, b)
 	return nil
 }
 
@@ -229,11 +229,11 @@ func getContainersChanges(srv *Server, version float64, w http.ResponseWriter, r
 	if err != nil {
 		return err
 	}
-	writeJson(w, b)
+	writeJSON(w, b)
 	return nil
 }
 
-func getContainersJson(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func getContainersJSON(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := parseForm(r); err != nil {
 		return err
 	}
@@ -253,7 +253,7 @@ func getContainersJson(srv *Server, version float64, w http.ResponseWriter, r *h
 	if err != nil {
 		return err
 	}
-	writeJson(w, b)
+	writeJSON(w, b)
 	return nil
 }
 
@@ -296,12 +296,12 @@ func postCommit(srv *Server, version float64, w http.ResponseWriter, r *http.Req
 	if err != nil {
 		return err
 	}
-	b, err := json.Marshal(&ApiId{id})
+	b, err := json.Marshal(&APIID{id})
 	if err != nil {
 		return err
 	}
 	w.WriteHeader(http.StatusCreated)
-	writeJson(w, b)
+	writeJSON(w, b)
 	return nil
 }
 
@@ -355,7 +355,7 @@ func getImagesSearch(srv *Server, version float64, w http.ResponseWriter, r *htt
 	if err != nil {
 		return err
 	}
-	writeJson(w, b)
+	writeJSON(w, b)
 	return nil
 }
 
@@ -374,18 +374,18 @@ func postImagesInsert(srv *Server, version float64, w http.ResponseWriter, r *ht
 		w.Header().Set("Content-Type", "application/json")
 	}
 	sf := utils.NewStreamFormatter(version > 1.0)
-	imgId, err := srv.ImageInsert(name, url, path, w, sf)
+	imgID, err := srv.ImageInsert(name, url, path, w, sf)
 	if err != nil {
 		if sf.Used() {
 			w.Write(sf.FormatError(err))
 			return nil
 		}
 	}
-	b, err := json.Marshal(&ApiId{Id: imgId})
+	b, err := json.Marshal(&APIID{ID: imgID})
 	if err != nil {
 		return err
 	}
-	writeJson(w, b)
+	writeJSON(w, b)
 	return nil
 }
 
@@ -423,8 +423,8 @@ func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r
 		return err
 	}
 
-	out := &ApiRun{
-		Id: id,
+	out := &APIRun{
+		ID: id,
 	}
 	if config.Memory > 0 && !srv.runtime.capabilities.MemoryLimit {
 		log.Println("WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.")
@@ -439,7 +439,7 @@ func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r
 		return err
 	}
 	w.WriteHeader(http.StatusCreated)
-	writeJson(w, b)
+	writeJSON(w, b)
 	return nil
 }
 
@@ -500,7 +500,7 @@ func deleteImages(srv *Server, version float64, w http.ResponseWriter, r *http.R
 			if err != nil {
 				return err
 			}
-			writeJson(w, b)
+			writeJSON(w, b)
 		} else {
 			return fmt.Errorf("Conflict, %s wasn't deleted", name)
 		}
@@ -552,11 +552,11 @@ func postContainersWait(srv *Server, version float64, w http.ResponseWriter, r *
 	if err != nil {
 		return err
 	}
-	b, err := json.Marshal(&ApiWait{StatusCode: status})
+	b, err := json.Marshal(&APIWait{StatusCode: status})
 	if err != nil {
 		return err
 	}
-	writeJson(w, b)
+	writeJSON(w, b)
 	return nil
 }
 
@@ -643,7 +643,7 @@ func getContainersByName(srv *Server, version float64, w http.ResponseWriter, r
 	if err != nil {
 		return err
 	}
-	writeJson(w, b)
+	writeJSON(w, b)
 	return nil
 }
 
@@ -661,17 +661,17 @@ func getImagesByName(srv *Server, version float64, w http.ResponseWriter, r *htt
 	if err != nil {
 		return err
 	}
-	writeJson(w, b)
+	writeJSON(w, b)
 	return nil
 }
 
 func postImagesGetCache(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	apiConfig := &ApiImageConfig{}
+	apiConfig := &APIImageConfig{}
 	if err := json.NewDecoder(r.Body).Decode(apiConfig); err != nil {
 		return err
 	}
 
-	image, err := srv.ImageGetCached(apiConfig.Id, apiConfig.Config)
+	image, err := srv.ImageGetCached(apiConfig.ID, apiConfig.Config)
 	if err != nil {
 		return err
 	}
@@ -679,12 +679,12 @@ func postImagesGetCache(srv *Server, version float64, w http.ResponseWriter, r *
 		w.WriteHeader(http.StatusNotFound)
 		return nil
 	}
-	apiId := &ApiId{Id: image.Id}
-	b, err := json.Marshal(apiId)
+	apiID := &APIID{ID: image.ID}
+	b, err := json.Marshal(apiID)
 	if err != nil {
 		return err
 	}
-	writeJson(w, b)
+	writeJSON(w, b)
 	return nil
 }
 
@@ -730,13 +730,13 @@ func ListenAndServe(addr string, srv *Server, logging bool) error {
 			"/auth":                         getAuth,
 			"/version":                      getVersion,
 			"/info":                         getInfo,
-			"/images/json":                  getImagesJson,
+			"/images/json":                  getImagesJSON,
 			"/images/viz":                   getImagesViz,
 			"/images/search":                getImagesSearch,
 			"/images/{name:.*}/history":     getImagesHistory,
 			"/images/{name:.*}/json":        getImagesByName,
-			"/containers/ps":                getContainersJson,
-			"/containers/json":              getContainersJson,
+			"/containers/ps":                getContainersJSON,
+			"/containers/json":              getContainersJSON,
 			"/containers/{name:.*}/export":  getContainersExport,
 			"/containers/{name:.*}/changes": getContainersChanges,
 			"/containers/{name:.*}/json":    getContainersByName,
@@ -785,9 +785,9 @@ func ListenAndServe(addr string, srv *Server, logging bool) error {
 				}
 				version, err := strconv.ParseFloat(mux.Vars(r)["version"], 64)
 				if err != nil {
-					version = API_VERSION
+					version = APIVERSION
 				}
-				if version == 0 || version > API_VERSION {
+				if version == 0 || version > APIVERSION {
 					w.WriteHeader(http.StatusNotFound)
 					return
 				}

+ 29 - 30
api_params.go

@@ -1,35 +1,35 @@
 package docker
 
-type ApiHistory struct {
-	Id        string
+type APIHistory struct {
+	ID        string `json:"Id"`
 	Created   int64
-	CreatedBy string
+	CreatedBy string `json:",omitempty"`
 }
 
-type ApiImages struct {
+type APIImages struct {
 	Repository string `json:",omitempty"`
 	Tag        string `json:",omitempty"`
-	Id         string
+	ID         string `json:"Id"`
 	Created    int64
 }
 
-type ApiInfo struct {
+type APIInfo struct {
+	Debug       bool
 	Containers  int
-	Version     string
 	Images      int
-	Debug       bool
-	GoVersion   string
-	NFd         int `json:",omitempty"`
-	NGoroutines int `json:",omitempty"`
+	NFd         int  `json:",omitempty"`
+	NGoroutines int  `json:",omitempty"`
+	MemoryLimit bool `json:",omitempty"`
+	SwapLimit   bool `json:",omitempty"`
 }
 
-type ApiRmi struct {
+type APIRmi struct {
 	Deleted  string `json:",omitempty"`
 	Untagged string `json:",omitempty"`
 }
 
-type ApiContainers struct {
-	Id      string
+type APIContainers struct {
+	ID      string `json:"Id"`
 	Image   string
 	Command string
 	Created int64
@@ -37,40 +37,39 @@ type ApiContainers struct {
 	Ports   string
 }
 
-type ApiSearch struct {
+type APISearch struct {
 	Name        string
 	Description string
 }
 
-type ApiId struct {
-	Id string
+type APIID struct {
+	ID string `json:"Id"`
 }
 
-type ApiRun struct {
-	Id       string
-	Warnings []string
+type APIRun struct {
+	ID       string   `json:"Id"`
+	Warnings []string `json:",omitempty"`
 }
 
-type ApiPort struct {
+type APIPort struct {
 	Port string
 }
 
-type ApiVersion struct {
-	Version     string
-	GitCommit   string
-	MemoryLimit bool
-	SwapLimit   bool
+type APIVersion struct {
+	Version   string
+	GitCommit string `json:",omitempty"`
+	GoVersion string `json:",omitempty"`
 }
 
-type ApiWait struct {
+type APIWait struct {
 	StatusCode int
 }
 
-type ApiAuth struct {
+type APIAuth struct {
 	Status string
 }
 
-type ApiImageConfig struct {
-	Id string
+type APIImageConfig struct {
+	ID string `json:"Id"`
 	*Config
 }

+ 77 - 77
api_test.go

@@ -37,17 +37,17 @@ func TestGetAuth(t *testing.T) {
 		Email:    "utest@yopmail.com",
 	}
 
-	authConfigJson, err := json.Marshal(authConfig)
+	authConfigJSON, err := json.Marshal(authConfig)
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	req, err := http.NewRequest("POST", "/auth", bytes.NewReader(authConfigJson))
+	req, err := http.NewRequest("POST", "/auth", bytes.NewReader(authConfigJSON))
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	if err := postAuth(srv, API_VERSION, r, req, nil); err != nil {
+	if err := postAuth(srv, APIVERSION, r, req, nil); err != nil {
 		t.Fatal(err)
 	}
 
@@ -73,11 +73,11 @@ func TestGetVersion(t *testing.T) {
 
 	r := httptest.NewRecorder()
 
-	if err := getVersion(srv, API_VERSION, r, nil, nil); err != nil {
+	if err := getVersion(srv, APIVERSION, r, nil, nil); err != nil {
 		t.Fatal(err)
 	}
 
-	v := &ApiVersion{}
+	v := &APIVersion{}
 	if err = json.Unmarshal(r.Body.Bytes(), v); err != nil {
 		t.Fatal(err)
 	}
@@ -97,21 +97,21 @@ func TestGetInfo(t *testing.T) {
 
 	r := httptest.NewRecorder()
 
-	if err := getInfo(srv, API_VERSION, r, nil, nil); err != nil {
+	if err := getInfo(srv, APIVERSION, r, nil, nil); err != nil {
 		t.Fatal(err)
 	}
 
-	infos := &ApiInfo{}
+	infos := &APIInfo{}
 	err = json.Unmarshal(r.Body.Bytes(), infos)
 	if err != nil {
 		t.Fatal(err)
 	}
-	if infos.Version != VERSION {
-		t.Errorf("Excepted version %s, %s found", VERSION, infos.Version)
+	if infos.Images != 1 {
+		t.Errorf("Excepted images: %d, %d found", 1, infos.Images)
 	}
 }
 
-func TestGetImagesJson(t *testing.T) {
+func TestGetImagesJSON(t *testing.T) {
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)
@@ -128,11 +128,11 @@ func TestGetImagesJson(t *testing.T) {
 
 	r := httptest.NewRecorder()
 
-	if err := getImagesJson(srv, API_VERSION, r, req, nil); err != nil {
+	if err := getImagesJSON(srv, APIVERSION, r, req, nil); err != nil {
 		t.Fatal(err)
 	}
 
-	images := []ApiImages{}
+	images := []APIImages{}
 	if err := json.Unmarshal(r.Body.Bytes(), &images); err != nil {
 		t.Fatal(err)
 	}
@@ -153,11 +153,11 @@ func TestGetImagesJson(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	if err := getImagesJson(srv, API_VERSION, r2, req2, nil); err != nil {
+	if err := getImagesJSON(srv, APIVERSION, r2, req2, nil); err != nil {
 		t.Fatal(err)
 	}
 
-	images2 := []ApiImages{}
+	images2 := []APIImages{}
 	if err := json.Unmarshal(r2.Body.Bytes(), &images2); err != nil {
 		t.Fatal(err)
 	}
@@ -166,8 +166,8 @@ func TestGetImagesJson(t *testing.T) {
 		t.Errorf("Excepted 1 image, %d found", len(images2))
 	}
 
-	if images2[0].Id != GetTestImage(runtime).Id {
-		t.Errorf("Retrieved image Id differs, expected %s, received %s", GetTestImage(runtime).Id, images2[0].Id)
+	if images2[0].ID != GetTestImage(runtime).ID {
+		t.Errorf("Retrieved image Id differs, expected %s, received %s", GetTestImage(runtime).ID, images2[0].ID)
 	}
 
 	r3 := httptest.NewRecorder()
@@ -178,11 +178,11 @@ func TestGetImagesJson(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	if err := getImagesJson(srv, API_VERSION, r3, req3, nil); err != nil {
+	if err := getImagesJSON(srv, APIVERSION, r3, req3, nil); err != nil {
 		t.Fatal(err)
 	}
 
-	images3 := []ApiImages{}
+	images3 := []APIImages{}
 	if err := json.Unmarshal(r3.Body.Bytes(), &images3); err != nil {
 		t.Fatal(err)
 	}
@@ -199,7 +199,7 @@ func TestGetImagesJson(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	err = getImagesJson(srv, API_VERSION, r4, req4, nil)
+	err = getImagesJSON(srv, APIVERSION, r4, req4, nil)
 	if err == nil {
 		t.Fatalf("Error expected, received none")
 	}
@@ -220,7 +220,7 @@ func TestGetImagesViz(t *testing.T) {
 	srv := &Server{runtime: runtime}
 
 	r := httptest.NewRecorder()
-	if err := getImagesViz(srv, API_VERSION, r, nil, nil); err != nil {
+	if err := getImagesViz(srv, APIVERSION, r, nil, nil); err != nil {
 		t.Fatal(err)
 	}
 
@@ -256,11 +256,11 @@ func TestGetImagesSearch(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	if err := getImagesSearch(srv, API_VERSION, r, req, nil); err != nil {
+	if err := getImagesSearch(srv, APIVERSION, r, req, nil); err != nil {
 		t.Fatal(err)
 	}
 
-	results := []ApiSearch{}
+	results := []APISearch{}
 	if err := json.Unmarshal(r.Body.Bytes(), &results); err != nil {
 		t.Fatal(err)
 	}
@@ -280,11 +280,11 @@ func TestGetImagesHistory(t *testing.T) {
 
 	r := httptest.NewRecorder()
 
-	if err := getImagesHistory(srv, API_VERSION, r, nil, map[string]string{"name": unitTestImageName}); err != nil {
+	if err := getImagesHistory(srv, APIVERSION, r, nil, map[string]string{"name": unitTestImageName}); err != nil {
 		t.Fatal(err)
 	}
 
-	history := []ApiHistory{}
+	history := []APIHistory{}
 	if err := json.Unmarshal(r.Body.Bytes(), &history); err != nil {
 		t.Fatal(err)
 	}
@@ -303,7 +303,7 @@ func TestGetImagesByName(t *testing.T) {
 	srv := &Server{runtime: runtime}
 
 	r := httptest.NewRecorder()
-	if err := getImagesByName(srv, API_VERSION, r, nil, map[string]string{"name": unitTestImageName}); err != nil {
+	if err := getImagesByName(srv, APIVERSION, r, nil, map[string]string{"name": unitTestImageName}); err != nil {
 		t.Fatal(err)
 	}
 
@@ -311,12 +311,12 @@ func TestGetImagesByName(t *testing.T) {
 	if err := json.Unmarshal(r.Body.Bytes(), img); err != nil {
 		t.Fatal(err)
 	}
-	if img.Id != GetTestImage(runtime).Id || img.Comment != "Imported from http://get.docker.io/images/busybox" {
+	if img.ID != GetTestImage(runtime).ID || img.Comment != "Imported from http://get.docker.io/images/busybox" {
 		t.Errorf("Error inspecting image")
 	}
 }
 
-func TestGetContainersJson(t *testing.T) {
+func TestGetContainersJSON(t *testing.T) {
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)
@@ -326,7 +326,7 @@ func TestGetContainersJson(t *testing.T) {
 	srv := &Server{runtime: runtime}
 
 	container, err := NewBuilder(runtime).Create(&Config{
-		Image: GetTestImage(runtime).Id,
+		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"echo", "test"},
 	})
 	if err != nil {
@@ -340,18 +340,18 @@ func TestGetContainersJson(t *testing.T) {
 	}
 
 	r := httptest.NewRecorder()
-	if err := getContainersJson(srv, API_VERSION, r, req, nil); err != nil {
+	if err := getContainersJSON(srv, APIVERSION, r, req, nil); err != nil {
 		t.Fatal(err)
 	}
-	containers := []ApiContainers{}
+	containers := []APIContainers{}
 	if err := json.Unmarshal(r.Body.Bytes(), &containers); err != nil {
 		t.Fatal(err)
 	}
 	if len(containers) != 1 {
 		t.Fatalf("Excepted %d container, %d found", 1, len(containers))
 	}
-	if containers[0].Id != container.Id {
-		t.Fatalf("Container ID mismatch. Expected: %s, received: %s\n", container.Id, containers[0].Id)
+	if containers[0].ID != container.ID {
+		t.Fatalf("Container ID mismatch. Expected: %s, received: %s\n", container.ID, containers[0].ID)
 	}
 }
 
@@ -369,7 +369,7 @@ func TestGetContainersExport(t *testing.T) {
 	// Create a container and remove a file
 	container, err := builder.Create(
 		&Config{
-			Image: GetTestImage(runtime).Id,
+			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"touch", "/test"},
 		},
 	)
@@ -383,7 +383,7 @@ func TestGetContainersExport(t *testing.T) {
 	}
 
 	r := httptest.NewRecorder()
-	if err = getContainersExport(srv, API_VERSION, r, nil, map[string]string{"name": container.Id}); err != nil {
+	if err = getContainersExport(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err != nil {
 		t.Fatal(err)
 	}
 
@@ -424,7 +424,7 @@ func TestGetContainersChanges(t *testing.T) {
 	// Create a container and remove a file
 	container, err := builder.Create(
 		&Config{
-			Image: GetTestImage(runtime).Id,
+			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"/bin/rm", "/etc/passwd"},
 		},
 	)
@@ -438,7 +438,7 @@ func TestGetContainersChanges(t *testing.T) {
 	}
 
 	r := httptest.NewRecorder()
-	if err := getContainersChanges(srv, API_VERSION, r, nil, map[string]string{"name": container.Id}); err != nil {
+	if err := getContainersChanges(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err != nil {
 		t.Fatal(err)
 	}
 	changes := []Change{}
@@ -472,7 +472,7 @@ func TestGetContainersByName(t *testing.T) {
 	// Create a container and remove a file
 	container, err := builder.Create(
 		&Config{
-			Image: GetTestImage(runtime).Id,
+			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"echo", "test"},
 		},
 	)
@@ -482,15 +482,15 @@ func TestGetContainersByName(t *testing.T) {
 	defer runtime.Destroy(container)
 
 	r := httptest.NewRecorder()
-	if err := getContainersByName(srv, API_VERSION, r, nil, map[string]string{"name": container.Id}); err != nil {
+	if err := getContainersByName(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err != nil {
 		t.Fatal(err)
 	}
 	outContainer := &Container{}
 	if err := json.Unmarshal(r.Body.Bytes(), outContainer); err != nil {
 		t.Fatal(err)
 	}
-	if outContainer.Id != container.Id {
-		t.Fatalf("Wrong containers retrieved. Expected %s, recieved %s", container.Id, outContainer.Id)
+	if outContainer.ID != container.ID {
+		t.Fatalf("Wrong containers retrieved. Expected %s, recieved %s", container.ID, outContainer.ID)
 	}
 }
 
@@ -514,7 +514,7 @@ func TestPostAuth(t *testing.T) {
 	auth.SaveConfig(runtime.root, authStr, config.Email)
 
 	r := httptest.NewRecorder()
-	if err := getAuth(srv, API_VERSION, r, nil, nil); err != nil {
+	if err := getAuth(srv, APIVERSION, r, nil, nil); err != nil {
 		t.Fatal(err)
 	}
 
@@ -542,7 +542,7 @@ func TestPostCommit(t *testing.T) {
 	// Create a container and remove a file
 	container, err := builder.Create(
 		&Config{
-			Image: GetTestImage(runtime).Id,
+			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"touch", "/test"},
 		},
 	)
@@ -555,24 +555,24 @@ func TestPostCommit(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	req, err := http.NewRequest("POST", "/commit?repo=testrepo&testtag=tag&container="+container.Id, bytes.NewReader([]byte{}))
+	req, err := http.NewRequest("POST", "/commit?repo=testrepo&testtag=tag&container="+container.ID, bytes.NewReader([]byte{}))
 	if err != nil {
 		t.Fatal(err)
 	}
 
 	r := httptest.NewRecorder()
-	if err := postCommit(srv, API_VERSION, r, req, nil); err != nil {
+	if err := postCommit(srv, APIVERSION, r, req, nil); err != nil {
 		t.Fatal(err)
 	}
 	if r.Code != http.StatusCreated {
 		t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
 	}
 
-	apiId := &ApiId{}
-	if err := json.Unmarshal(r.Body.Bytes(), apiId); err != nil {
+	apiID := &APIID{}
+	if err := json.Unmarshal(r.Body.Bytes(), apiID); err != nil {
 		t.Fatal(err)
 	}
-	if _, err := runtime.graph.Get(apiId.Id); err != nil {
+	if _, err := runtime.graph.Get(apiID.ID); err != nil {
 		t.Fatalf("The image has not been commited")
 	}
 }
@@ -715,7 +715,7 @@ func TestPostImagesInsert(t *testing.T) {
 	// 	t.Fatalf("The test file has not been found")
 	// }
 
-	// if err := srv.runtime.graph.Delete(img.Id); err != nil {
+	// if err := srv.runtime.graph.Delete(img.ID); err != nil {
 	// 	t.Fatal(err)
 	// }
 }
@@ -824,8 +824,8 @@ func TestPostContainersCreate(t *testing.T) {
 
 	srv := &Server{runtime: runtime}
 
-	configJson, err := json.Marshal(&Config{
-		Image:  GetTestImage(runtime).Id,
+	configJSON, err := json.Marshal(&Config{
+		Image:  GetTestImage(runtime).ID,
 		Memory: 33554432,
 		Cmd:    []string{"touch", "/test"},
 	})
@@ -833,25 +833,25 @@ func TestPostContainersCreate(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	req, err := http.NewRequest("POST", "/containers/create", bytes.NewReader(configJson))
+	req, err := http.NewRequest("POST", "/containers/create", bytes.NewReader(configJSON))
 	if err != nil {
 		t.Fatal(err)
 	}
 
 	r := httptest.NewRecorder()
-	if err := postContainersCreate(srv, API_VERSION, r, req, nil); err != nil {
+	if err := postContainersCreate(srv, APIVERSION, r, req, nil); err != nil {
 		t.Fatal(err)
 	}
 	if r.Code != http.StatusCreated {
 		t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
 	}
 
-	apiRun := &ApiRun{}
+	apiRun := &APIRun{}
 	if err := json.Unmarshal(r.Body.Bytes(), apiRun); err != nil {
 		t.Fatal(err)
 	}
 
-	container := srv.runtime.Get(apiRun.Id)
+	container := srv.runtime.Get(apiRun.ID)
 	if container == nil {
 		t.Fatalf("Container not created")
 	}
@@ -880,7 +880,7 @@ func TestPostContainersKill(t *testing.T) {
 
 	container, err := NewBuilder(runtime).Create(
 		&Config{
-			Image:     GetTestImage(runtime).Id,
+			Image:     GetTestImage(runtime).ID,
 			Cmd:       []string{"/bin/cat"},
 			OpenStdin: true,
 		},
@@ -902,7 +902,7 @@ func TestPostContainersKill(t *testing.T) {
 	}
 
 	r := httptest.NewRecorder()
-	if err := postContainersKill(srv, API_VERSION, r, nil, map[string]string{"name": container.Id}); err != nil {
+	if err := postContainersKill(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err != nil {
 		t.Fatal(err)
 	}
 	if r.Code != http.StatusNoContent {
@@ -924,7 +924,7 @@ func TestPostContainersRestart(t *testing.T) {
 
 	container, err := NewBuilder(runtime).Create(
 		&Config{
-			Image:     GetTestImage(runtime).Id,
+			Image:     GetTestImage(runtime).ID,
 			Cmd:       []string{"/bin/cat"},
 			OpenStdin: true,
 		},
@@ -945,12 +945,12 @@ func TestPostContainersRestart(t *testing.T) {
 		t.Errorf("Container should be running")
 	}
 
-	req, err := http.NewRequest("POST", "/containers/"+container.Id+"/restart?t=1", bytes.NewReader([]byte{}))
+	req, err := http.NewRequest("POST", "/containers/"+container.ID+"/restart?t=1", bytes.NewReader([]byte{}))
 	if err != nil {
 		t.Fatal(err)
 	}
 	r := httptest.NewRecorder()
-	if err := postContainersRestart(srv, API_VERSION, r, req, map[string]string{"name": container.Id}); err != nil {
+	if err := postContainersRestart(srv, APIVERSION, r, req, map[string]string{"name": container.ID}); err != nil {
 		t.Fatal(err)
 	}
 	if r.Code != http.StatusNoContent {
@@ -980,7 +980,7 @@ func TestPostContainersStart(t *testing.T) {
 
 	container, err := NewBuilder(runtime).Create(
 		&Config{
-			Image:     GetTestImage(runtime).Id,
+			Image:     GetTestImage(runtime).ID,
 			Cmd:       []string{"/bin/cat"},
 			OpenStdin: true,
 		},
@@ -991,7 +991,7 @@ func TestPostContainersStart(t *testing.T) {
 	defer runtime.Destroy(container)
 
 	r := httptest.NewRecorder()
-	if err := postContainersStart(srv, API_VERSION, r, nil, map[string]string{"name": container.Id}); err != nil {
+	if err := postContainersStart(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err != nil {
 		t.Fatal(err)
 	}
 	if r.Code != http.StatusNoContent {
@@ -1006,7 +1006,7 @@ func TestPostContainersStart(t *testing.T) {
 	}
 
 	r = httptest.NewRecorder()
-	if err = postContainersStart(srv, API_VERSION, r, nil, map[string]string{"name": container.Id}); err == nil {
+	if err = postContainersStart(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err == nil {
 		t.Fatalf("A running containter should be able to be started")
 	}
 
@@ -1026,7 +1026,7 @@ func TestPostContainersStop(t *testing.T) {
 
 	container, err := NewBuilder(runtime).Create(
 		&Config{
-			Image:     GetTestImage(runtime).Id,
+			Image:     GetTestImage(runtime).ID,
 			Cmd:       []string{"/bin/cat"},
 			OpenStdin: true,
 		},
@@ -1048,12 +1048,12 @@ func TestPostContainersStop(t *testing.T) {
 	}
 
 	// Note: as it is a POST request, it requires a body.
-	req, err := http.NewRequest("POST", "/containers/"+container.Id+"/stop?t=1", bytes.NewReader([]byte{}))
+	req, err := http.NewRequest("POST", "/containers/"+container.ID+"/stop?t=1", bytes.NewReader([]byte{}))
 	if err != nil {
 		t.Fatal(err)
 	}
 	r := httptest.NewRecorder()
-	if err := postContainersStop(srv, API_VERSION, r, req, map[string]string{"name": container.Id}); err != nil {
+	if err := postContainersStop(srv, APIVERSION, r, req, map[string]string{"name": container.ID}); err != nil {
 		t.Fatal(err)
 	}
 	if r.Code != http.StatusNoContent {
@@ -1075,7 +1075,7 @@ func TestPostContainersWait(t *testing.T) {
 
 	container, err := NewBuilder(runtime).Create(
 		&Config{
-			Image:     GetTestImage(runtime).Id,
+			Image:     GetTestImage(runtime).ID,
 			Cmd:       []string{"/bin/sleep", "1"},
 			OpenStdin: true,
 		},
@@ -1091,10 +1091,10 @@ func TestPostContainersWait(t *testing.T) {
 
 	setTimeout(t, "Wait timed out", 3*time.Second, func() {
 		r := httptest.NewRecorder()
-		if err := postContainersWait(srv, API_VERSION, r, nil, map[string]string{"name": container.Id}); err != nil {
+		if err := postContainersWait(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err != nil {
 			t.Fatal(err)
 		}
-		apiWait := &ApiWait{}
+		apiWait := &APIWait{}
 		if err := json.Unmarshal(r.Body.Bytes(), apiWait); err != nil {
 			t.Fatal(err)
 		}
@@ -1119,7 +1119,7 @@ func TestPostContainersAttach(t *testing.T) {
 
 	container, err := NewBuilder(runtime).Create(
 		&Config{
-			Image:     GetTestImage(runtime).Id,
+			Image:     GetTestImage(runtime).ID,
 			Cmd:       []string{"/bin/cat"},
 			OpenStdin: true,
 		},
@@ -1148,12 +1148,12 @@ func TestPostContainersAttach(t *testing.T) {
 			out:              stdoutPipe,
 		}
 
-		req, err := http.NewRequest("POST", "/containers/"+container.Id+"/attach?stream=1&stdin=1&stdout=1&stderr=1", bytes.NewReader([]byte{}))
+		req, err := http.NewRequest("POST", "/containers/"+container.ID+"/attach?stream=1&stdin=1&stdout=1&stderr=1", bytes.NewReader([]byte{}))
 		if err != nil {
 			t.Fatal(err)
 		}
 
-		if err := postContainersAttach(srv, API_VERSION, r, req, map[string]string{"name": container.Id}); err != nil {
+		if err := postContainersAttach(srv, APIVERSION, r, req, map[string]string{"name": container.ID}); err != nil {
 			t.Fatal(err)
 		}
 	}()
@@ -1206,7 +1206,7 @@ func TestDeleteContainers(t *testing.T) {
 	srv := &Server{runtime: runtime}
 
 	container, err := NewBuilder(runtime).Create(&Config{
-		Image: GetTestImage(runtime).Id,
+		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"touch", "/test"},
 	})
 	if err != nil {
@@ -1218,19 +1218,19 @@ func TestDeleteContainers(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	req, err := http.NewRequest("DELETE", "/containers/"+container.Id, nil)
+	req, err := http.NewRequest("DELETE", "/containers/"+container.ID, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
 	r := httptest.NewRecorder()
-	if err := deleteContainers(srv, API_VERSION, r, req, map[string]string{"name": container.Id}); err != nil {
+	if err := deleteContainers(srv, APIVERSION, r, req, map[string]string{"name": container.ID}); err != nil {
 		t.Fatal(err)
 	}
 	if r.Code != http.StatusNoContent {
 		t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
 	}
 
-	if c := runtime.Get(container.Id); c != nil {
+	if c := runtime.Get(container.ID); c != nil {
 		t.Fatalf("The container as not been deleted")
 	}
 
@@ -1267,14 +1267,14 @@ func TestDeleteImages(t *testing.T) {
 	}
 
 	r := httptest.NewRecorder()
-	if err := deleteImages(srv, API_VERSION, r, req, map[string]string{"name": "test:test"}); err != nil {
+	if err := deleteImages(srv, APIVERSION, r, req, map[string]string{"name": "test:test"}); err != nil {
 		t.Fatal(err)
 	}
 	if r.Code != http.StatusOK {
 		t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
 	}
 
-	var outs []ApiRmi
+	var outs []APIRmi
 	if err := json.Unmarshal(r.Body.Bytes(), &outs); err != nil {
 		t.Fatal(err)
 	}

+ 4 - 4
auth/auth.go

@@ -16,12 +16,12 @@ import (
 const CONFIGFILE = ".dockercfg"
 
 // the registry server we want to login against
-const INDEX_SERVER = "https://index.docker.io/v1"
+const INDEXSERVER = "https://index.docker.io/v1"
 
-//const INDEX_SERVER = "http://indexstaging-docker.dotcloud.com/"
+//const INDEXSERVER = "http://indexstaging-docker.dotcloud.com/"
 
 var (
-	ErrConfigFileMissing error = errors.New("The Auth config file is missing")
+	ErrConfigFileMissing = errors.New("The Auth config file is missing")
 )
 
 type AuthConfig struct {
@@ -44,7 +44,7 @@ func IndexServerAddress() string {
 	if os.Getenv("DOCKER_INDEX_URL") != "" {
 		return os.Getenv("DOCKER_INDEX_URL") + "/v1"
 	}
-	return INDEX_SERVER
+	return INDEXSERVER
 }
 
 // create a base64 encoded auth string to store in config

+ 5 - 5
builder.go

@@ -40,7 +40,7 @@ func (builder *Builder) Create(config *Config) (*Container, error) {
 	}
 
 	// Generate id
-	id := GenerateId()
+	id := GenerateID()
 	// Generate default hostname
 	// FIXME: the lxc template no longer needs to set a default hostname
 	if config.Hostname == "" {
@@ -49,17 +49,17 @@ func (builder *Builder) Create(config *Config) (*Container, error) {
 
 	container := &Container{
 		// FIXME: we should generate the ID here instead of receiving it as an argument
-		Id:              id,
+		ID:              id,
 		Created:         time.Now(),
 		Path:            config.Cmd[0],
 		Args:            config.Cmd[1:], //FIXME: de-duplicate from config
 		Config:          config,
-		Image:           img.Id, // Always use the resolved image id
+		Image:           img.ID, // Always use the resolved image id
 		NetworkSettings: &NetworkSettings{},
 		// FIXME: do we need to store this in the container?
 		SysInitPath: sysInitPath,
 	}
-	container.root = builder.runtime.containerRoot(container.Id)
+	container.root = builder.runtime.containerRoot(container.ID)
 	// Step 1: create the container directory.
 	// This doubles as a barrier to avoid race conditions.
 	if err := os.Mkdir(container.root, 0700); err != nil {
@@ -110,7 +110,7 @@ func (builder *Builder) Commit(container *Container, repository, tag, comment, a
 	}
 	// Register the image if needed
 	if repository != "" {
-		if err := builder.repositories.Set(repository, tag, img.Id, true); err != nil {
+		if err := builder.repositories.Set(repository, tag, img.ID, true); err != nil {
 			return img, err
 		}
 	}

+ 20 - 20
builder_client.go

@@ -63,11 +63,11 @@ func (b *builderClient) CmdFrom(name string) error {
 		return err
 	}
 
-	img := &ApiId{}
+	img := &APIID{}
 	if err := json.Unmarshal(obj, img); err != nil {
 		return err
 	}
-	b.image = img.Id
+	b.image = img.ID
 	utils.Debugf("Using image %s", b.image)
 	return nil
 }
@@ -91,19 +91,19 @@ func (b *builderClient) CmdRun(args string) error {
 	b.config.Cmd = nil
 	MergeConfig(b.config, config)
 
-	body, statusCode, err := b.cli.call("POST", "/images/getCache", &ApiImageConfig{Id: b.image, Config: b.config})
+	body, statusCode, err := b.cli.call("POST", "/images/getCache", &APIImageConfig{ID: b.image, Config: b.config})
 	if err != nil {
 		if statusCode != 404 {
 			return err
 		}
 	}
 	if statusCode != 404 {
-		apiId := &ApiId{}
-		if err := json.Unmarshal(body, apiId); err != nil {
+		apiID := &APIID{}
+		if err := json.Unmarshal(body, apiID); err != nil {
 			return err
 		}
 		utils.Debugf("Use cached version")
-		b.image = apiId.Id
+		b.image = apiID.ID
 		return nil
 	}
 	cid, err := b.run()
@@ -163,7 +163,7 @@ func (b *builderClient) CmdInsert(args string) error {
 	// 	return err
 	// }
 
-	// apiId := &ApiId{}
+	// apiId := &APIId{}
 	// if err := json.Unmarshal(body, apiId); err != nil {
 	// 	return err
 	// }
@@ -182,7 +182,7 @@ func (b *builderClient) run() (string, error) {
 		return "", err
 	}
 
-	apiRun := &ApiRun{}
+	apiRun := &APIRun{}
 	if err := json.Unmarshal(body, apiRun); err != nil {
 		return "", err
 	}
@@ -191,18 +191,18 @@ func (b *builderClient) run() (string, error) {
 	}
 
 	//start the container
-	_, _, err = b.cli.call("POST", "/containers/"+apiRun.Id+"/start", nil)
+	_, _, err = b.cli.call("POST", "/containers/"+apiRun.ID+"/start", nil)
 	if err != nil {
 		return "", err
 	}
-	b.tmpContainers[apiRun.Id] = struct{}{}
+	b.tmpContainers[apiRun.ID] = struct{}{}
 
 	// Wait for it to finish
-	body, _, err = b.cli.call("POST", "/containers/"+apiRun.Id+"/wait", nil)
+	body, _, err = b.cli.call("POST", "/containers/"+apiRun.ID+"/wait", nil)
 	if err != nil {
 		return "", err
 	}
-	apiWait := &ApiWait{}
+	apiWait := &APIWait{}
 	if err := json.Unmarshal(body, apiWait); err != nil {
 		return "", err
 	}
@@ -210,7 +210,7 @@ func (b *builderClient) run() (string, error) {
 		return "", fmt.Errorf("The command %v returned a non-zero code: %d", b.config.Cmd, apiWait.StatusCode)
 	}
 
-	return apiRun.Id, nil
+	return apiRun.ID, nil
 }
 
 func (b *builderClient) commit(id string) error {
@@ -222,11 +222,11 @@ func (b *builderClient) commit(id string) error {
 	if id == "" {
 		cmd := b.config.Cmd
 		b.config.Cmd = []string{"true"}
-		if cid, err := b.run(); err != nil {
+		cid, err := b.run()
+		if err != nil {
 			return err
-		} else {
-			id = cid
 		}
+		id = cid
 		b.config.Cmd = cmd
 	}
 
@@ -239,12 +239,12 @@ func (b *builderClient) commit(id string) error {
 	if err != nil {
 		return err
 	}
-	apiId := &ApiId{}
-	if err := json.Unmarshal(body, apiId); err != nil {
+	apiID := &APIID{}
+	if err := json.Unmarshal(body, apiID); err != nil {
 		return err
 	}
-	b.tmpImages[apiId.Id] = struct{}{}
-	b.image = apiId.Id
+	b.tmpImages[apiID.ID] = struct{}{}
+	b.image = apiID.ID
 	b.needCommit = false
 	return nil
 }

+ 10 - 10
buildfile.go

@@ -73,7 +73,7 @@ func (b *buildFile) CmdFrom(name string) error {
 			return err
 		}
 	}
-	b.image = image.Id
+	b.image = image.ID
 	b.config = &Config{}
 	return nil
 }
@@ -102,7 +102,7 @@ func (b *buildFile) CmdRun(args string) error {
 		return err
 	} else if cache != nil {
 		utils.Debugf("[BUILDER] Use cached version")
-		b.image = cache.Id
+		b.image = cache.ID
 		return nil
 	} else {
 		utils.Debugf("[BUILDER] Cache miss")
@@ -238,7 +238,7 @@ func (b *buildFile) run() (string, error) {
 	if err != nil {
 		return "", err
 	}
-	b.tmpContainers[c.Id] = struct{}{}
+	b.tmpContainers[c.ID] = struct{}{}
 
 	//start the container
 	if err := c.Start(); err != nil {
@@ -250,7 +250,7 @@ func (b *buildFile) run() (string, error) {
 		return "", fmt.Errorf("The command %v returned a non-zero code: %d", b.config.Cmd, ret)
 	}
 
-	return c.Id, nil
+	return c.ID, nil
 }
 
 // Commit the container <id> with the autorun command <autoCmd>
@@ -266,17 +266,17 @@ func (b *buildFile) commit(id string, autoCmd []string, comment string) error {
 			return err
 		} else if cache != nil {
 			utils.Debugf("[BUILDER] Use cached version")
-			b.image = cache.Id
+			b.image = cache.ID
 			return nil
 		} else {
 			utils.Debugf("[BUILDER] Cache miss")
 		}
 
-		if cid, err := b.run(); err != nil {
+		cid, err := b.run()
+		if err != nil {
 			return err
-		} else {
-			id = cid
 		}
+		id = cid
 	}
 
 	container := b.runtime.Get(id)
@@ -292,8 +292,8 @@ func (b *buildFile) commit(id string, autoCmd []string, comment string) error {
 	if err != nil {
 		return err
 	}
-	b.tmpImages[image.Id] = struct{}{}
-	b.image = image.Id
+	b.tmpImages[image.ID] = struct{}{}
+	b.image = image.ID
 	return nil
 }
 

+ 3 - 3
buildfile_test.go

@@ -26,7 +26,7 @@ func TestBuild(t *testing.T) {
 
 	buildfile := NewBuildFile(srv, &utils.NopWriter{})
 
-	imgId, err := buildfile.Build(strings.NewReader(Dockerfile), nil)
+	imgID, err := buildfile.Build(strings.NewReader(Dockerfile), nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -34,7 +34,7 @@ func TestBuild(t *testing.T) {
 	builder := NewBuilder(runtime)
 	container, err := builder.Create(
 		&Config{
-			Image: imgId,
+			Image: imgID,
 			Cmd:   []string{"cat", "/tmp/passwd"},
 		},
 	)
@@ -53,7 +53,7 @@ func TestBuild(t *testing.T) {
 
 	container2, err := builder.Create(
 		&Config{
-			Image: imgId,
+			Image: imgID,
 			Cmd:   []string{"ls", "-d", "/var/run/sshd"},
 		},
 	)

+ 1 - 1
changes.go

@@ -65,7 +65,7 @@ func Changes(layers []string, rw string) ([]Change, error) {
 		file := filepath.Base(path)
 		// If there is a whiteout, then the file was removed
 		if strings.HasPrefix(file, ".wh.") {
-			originalFile := strings.TrimLeft(file, ".wh.")
+			originalFile := file[len(".wh."):]
 			change.Path = filepath.Join(filepath.Dir(path), originalFile)
 			change.Kind = ChangeDelete
 		} else {

+ 74 - 73
commands.go

@@ -28,10 +28,10 @@ import (
 	"unicode"
 )
 
-const VERSION = "0.3.4"
+const VERSION = "0.4.0"
 
 var (
-	GIT_COMMIT string
+	GITCOMMIT string
 )
 
 func (cli *DockerCli) getMethod(name string) (reflect.Method, bool) {
@@ -159,11 +159,11 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
 		file = os.Stdin
 	} else {
 		// Send Dockerfile from arg/Dockerfile (deprecate later)
-		if f, err := os.Open(path.Join(cmd.Arg(0), "Dockerfile")); err != nil {
+		f, err := os.Open(path.Join(cmd.Arg(0), "Dockerfile"))
+		if err != nil {
 			return err
-		} else {
-			file = f
 		}
+		file = f
 		// Send context from arg
 		// Create a FormFile multipart for the context if needed
 		// FIXME: Use NewTempArchive in order to have the size and avoid too much memory usage?
@@ -176,21 +176,21 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
 		if err != nil {
 			return err
 		}
-		if wField, err := w.CreateFormFile("Context", filepath.Base(absPath)+"."+compression.Extension()); err != nil {
+		wField, err := w.CreateFormFile("Context", filepath.Base(absPath)+"."+compression.Extension())
+		if err != nil {
 			return err
-		} else {
-			// FIXME: Find a way to have a progressbar for the upload too
-			sf := utils.NewStreamFormatter(false)
-			io.Copy(wField, utils.ProgressReader(ioutil.NopCloser(context), -1, os.Stdout, sf.FormatProgress("Caching Context", "%v/%v (%v)"), sf))
 		}
+		// FIXME: Find a way to have a progressbar for the upload too
+		sf := utils.NewStreamFormatter(false)
+		io.Copy(wField, utils.ProgressReader(ioutil.NopCloser(context), -1, os.Stdout, sf.FormatProgress("Caching Context", "%v/%v (%v)"), sf))
 		multipartBody = io.MultiReader(multipartBody, boundary)
 	}
 	// Create a FormFile multipart for the Dockerfile
-	if wField, err := w.CreateFormFile("Dockerfile", "Dockerfile"); err != nil {
+	wField, err := w.CreateFormFile("Dockerfile", "Dockerfile")
+	if err != nil {
 		return err
-	} else {
-		io.Copy(wField, file)
 	}
+	io.Copy(wField, file)
 	multipartBody = io.MultiReader(multipartBody, boundary)
 
 	v := &url.Values{}
@@ -276,9 +276,8 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
 	oldState, err := term.SetRawTerminal()
 	if err != nil {
 		return err
-	} else {
-		defer term.RestoreTerminal(oldState)
 	}
+	defer term.RestoreTerminal(oldState)
 
 	cmd := Subcmd("login", "", "Register or Login to the docker registry server")
 	if err := cmd.Parse(args); err != nil {
@@ -331,7 +330,7 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
 		return err
 	}
 
-	var out2 ApiAuth
+	var out2 APIAuth
 	err = json.Unmarshal(body, &out2)
 	if err != nil {
 		return err
@@ -358,7 +357,7 @@ func (cli *DockerCli) CmdWait(args ...string) error {
 		if err != nil {
 			fmt.Printf("%s", err)
 		} else {
-			var out ApiWait
+			var out APIWait
 			err = json.Unmarshal(body, &out)
 			if err != nil {
 				return err
@@ -386,21 +385,20 @@ func (cli *DockerCli) CmdVersion(args ...string) error {
 		return err
 	}
 
-	var out ApiVersion
+	var out APIVersion
 	err = json.Unmarshal(body, &out)
 	if err != nil {
 		utils.Debugf("Error unmarshal: body: %s, err: %s\n", body, err)
 		return err
 	}
-	fmt.Println("Version:", out.Version)
-	fmt.Println("Git Commit:", out.GitCommit)
-	if !out.MemoryLimit {
-		fmt.Println("WARNING: No memory limit support")
+	fmt.Println("Client version:", VERSION)
+	fmt.Println("Server version:", out.Version)
+	if out.GitCommit != "" {
+		fmt.Println("Git commit:", out.GitCommit)
 	}
-	if !out.SwapLimit {
-		fmt.Println("WARNING: No swap limit support")
+	if out.GoVersion != "" {
+		fmt.Println("Go version:", out.GoVersion)
 	}
-
 	return nil
 }
 
@@ -420,15 +418,24 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
 		return err
 	}
 
-	var out ApiInfo
-	err = json.Unmarshal(body, &out)
-	if err != nil {
+	var out APIInfo
+	if err := json.Unmarshal(body, &out); err != nil {
 		return err
 	}
-	fmt.Printf("containers: %d\nversion: %s\nimages: %d\nGo version: %s\n", out.Containers, out.Version, out.Images, out.GoVersion)
-	if out.Debug {
-		fmt.Println("debug mode enabled")
-		fmt.Printf("fds: %d\ngoroutines: %d\n", out.NFd, out.NGoroutines)
+
+	fmt.Printf("Containers: %d\n", out.Containers)
+	fmt.Printf("Images: %d\n", out.Images)
+	if out.Debug || os.Getenv("DEBUG") != "" {
+		fmt.Printf("Debug mode (server): %v\n", out.Debug)
+		fmt.Printf("Debug mode (client): %v\n", os.Getenv("DEBUG") != "")
+		fmt.Printf("Fds: %d\n", out.NFd)
+		fmt.Printf("Goroutines: %d\n", out.NGoroutines)
+	}
+	if !out.MemoryLimit {
+		fmt.Println("WARNING: No memory limit support")
+	}
+	if !out.SwapLimit {
+		fmt.Println("WARNING: No swap limit support")
 	}
 	return nil
 }
@@ -575,7 +582,7 @@ func (cli *DockerCli) CmdRmi(args ...string) error {
 		if err != nil {
 			fmt.Fprintf(os.Stderr, "%s", err)
 		} else {
-			var outs []ApiRmi
+			var outs []APIRmi
 			err = json.Unmarshal(body, &outs)
 			if err != nil {
 				return err
@@ -607,7 +614,7 @@ func (cli *DockerCli) CmdHistory(args ...string) error {
 		return err
 	}
 
-	var outs []ApiHistory
+	var outs []APIHistory
 	err = json.Unmarshal(body, &outs)
 	if err != nil {
 		return err
@@ -616,7 +623,7 @@ func (cli *DockerCli) CmdHistory(args ...string) error {
 	fmt.Fprintln(w, "ID\tCREATED\tCREATED BY")
 
 	for _, out := range outs {
-		fmt.Fprintf(w, "%s\t%s ago\t%s\n", out.Id, utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.CreatedBy)
+		fmt.Fprintf(w, "%s\t%s ago\t%s\n", out.ID, utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.CreatedBy)
 	}
 	w.Flush()
 	return nil
@@ -742,12 +749,6 @@ func (cli *DockerCli) CmdPull(args ...string) error {
 		remote = remoteParts[0]
 	}
 
-	if strings.Contains(remote, "/") {
-		if _, err := cli.checkIfLogged(true, "pull"); err != nil {
-			return err
-		}
-	}
-
 	v := url.Values{}
 	v.Set("fromImage", remote)
 	v.Set("tag", *tag)
@@ -795,7 +796,7 @@ func (cli *DockerCli) CmdImages(args ...string) error {
 			return err
 		}
 
-		var outs []ApiImages
+		var outs []APIImages
 		err = json.Unmarshal(body, &outs)
 		if err != nil {
 			return err
@@ -817,16 +818,16 @@ func (cli *DockerCli) CmdImages(args ...string) error {
 			if !*quiet {
 				fmt.Fprintf(w, "%s\t%s\t", out.Repository, out.Tag)
 				if *noTrunc {
-					fmt.Fprintf(w, "%s\t", out.Id)
+					fmt.Fprintf(w, "%s\t", out.ID)
 				} else {
-					fmt.Fprintf(w, "%s\t", utils.TruncateId(out.Id))
+					fmt.Fprintf(w, "%s\t", utils.TruncateID(out.ID))
 				}
 				fmt.Fprintf(w, "%s ago\n", utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))))
 			} else {
 				if *noTrunc {
-					fmt.Fprintln(w, out.Id)
+					fmt.Fprintln(w, out.ID)
 				} else {
-					fmt.Fprintln(w, utils.TruncateId(out.Id))
+					fmt.Fprintln(w, utils.TruncateID(out.ID))
 				}
 			}
 		}
@@ -873,7 +874,7 @@ func (cli *DockerCli) CmdPs(args ...string) error {
 		return err
 	}
 
-	var outs []ApiContainers
+	var outs []APIContainers
 	err = json.Unmarshal(body, &outs)
 	if err != nil {
 		return err
@@ -886,15 +887,15 @@ func (cli *DockerCli) CmdPs(args ...string) error {
 	for _, out := range outs {
 		if !*quiet {
 			if *noTrunc {
-				fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\n", out.Id, out.Image, out.Command, utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Status, out.Ports)
+				fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\n", out.ID, out.Image, out.Command, utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Status, out.Ports)
 			} else {
-				fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\n", 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)
+				fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\n", 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)
 			}
 		} else {
 			if *noTrunc {
-				fmt.Fprintln(w, out.Id)
+				fmt.Fprintln(w, out.ID)
 			} else {
-				fmt.Fprintln(w, utils.TruncateId(out.Id))
+				fmt.Fprintln(w, utils.TruncateID(out.ID))
 			}
 		}
 	}
@@ -937,13 +938,13 @@ func (cli *DockerCli) CmdCommit(args ...string) error {
 		return err
 	}
 
-	apiId := &ApiId{}
-	err = json.Unmarshal(body, apiId)
+	apiID := &APIID{}
+	err = json.Unmarshal(body, apiID)
 	if err != nil {
 		return err
 	}
 
-	fmt.Println(apiId.Id)
+	fmt.Println(apiID.ID)
 	return nil
 }
 
@@ -1080,7 +1081,7 @@ func (cli *DockerCli) CmdSearch(args ...string) error {
 		return err
 	}
 
-	outs := []ApiSearch{}
+	outs := []APISearch{}
 	err = json.Unmarshal(body, &outs)
 	if err != nil {
 		return err
@@ -1212,7 +1213,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
 		return err
 	}
 
-	out := &ApiRun{}
+	out := &APIRun{}
 	err = json.Unmarshal(body, out)
 	if err != nil {
 		return err
@@ -1233,18 +1234,21 @@ func (cli *DockerCli) CmdRun(args ...string) error {
 	}
 
 	//start the container
-	_, _, err = cli.call("POST", "/containers/"+out.Id+"/start", nil)
+	_, _, err = cli.call("POST", "/containers/"+out.ID+"/start", nil)
 	if err != nil {
 		return err
 	}
 
+	if !config.AttachStdout && !config.AttachStderr {
+		fmt.Println(out.ID)
+	}
 	if connections > 0 {
 		chErrors := make(chan error, connections)
-		cli.monitorTtySize(out.Id)
+		cli.monitorTtySize(out.ID)
 
 		if splitStderr && config.AttachStderr {
 			go func() {
-				chErrors <- cli.hijack("POST", "/containers/"+out.Id+"/attach?logs=1&stream=1&stderr=1", config.Tty, nil, os.Stderr)
+				chErrors <- cli.hijack("POST", "/containers/"+out.ID+"/attach?logs=1&stream=1&stderr=1", config.Tty, nil, os.Stderr)
 			}()
 		}
 
@@ -1262,7 +1266,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
 			v.Set("stderr", "1")
 		}
 		go func() {
-			chErrors <- cli.hijack("POST", "/containers/"+out.Id+"/attach?"+v.Encode(), config.Tty, os.Stdin, os.Stdout)
+			chErrors <- cli.hijack("POST", "/containers/"+out.ID+"/attach?"+v.Encode(), config.Tty, os.Stdin, os.Stdout)
 		}()
 		for connections > 0 {
 			err := <-chErrors
@@ -1272,9 +1276,6 @@ func (cli *DockerCli) CmdRun(args ...string) error {
 			connections -= 1
 		}
 	}
-	if !config.AttachStdout && !config.AttachStderr {
-		fmt.Println(out.Id)
-	}
 	return nil
 }
 
@@ -1322,7 +1323,7 @@ func (cli *DockerCli) call(method, path string, data interface{}) ([]byte, int,
 		params = bytes.NewBuffer(buf)
 	}
 
-	req, err := http.NewRequest(method, fmt.Sprintf("http://%s:%d/v%g%s", cli.host, cli.port, API_VERSION, path), params)
+	req, err := http.NewRequest(method, fmt.Sprintf("http://%s:%d/v%g%s", cli.host, cli.port, APIVERSION, path), params)
 	if err != nil {
 		return nil, -1, err
 	}
@@ -1354,7 +1355,7 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer) e
 	if (method == "POST" || method == "PUT") && in == nil {
 		in = bytes.NewReader([]byte{})
 	}
-	req, err := http.NewRequest(method, fmt.Sprintf("http://%s:%d/v%g%s", cli.host, cli.port, API_VERSION, path), in)
+	req, err := http.NewRequest(method, fmt.Sprintf("http://%s:%d/v%g%s", cli.host, cli.port, APIVERSION, path), in)
 	if err != nil {
 		return err
 	}
@@ -1381,14 +1382,14 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer) e
 	if resp.Header.Get("Content-Type") == "application/json" {
 		dec := json.NewDecoder(resp.Body)
 		for {
-			var m utils.JsonMessage
+			var m utils.JSONMessage
 			if err := dec.Decode(&m); err == io.EOF {
 				break
 			} else if err != nil {
 				return err
 			}
 			if m.Progress != "" {
-				fmt.Fprintf(out, "Downloading %s\r", m.Progress)
+				fmt.Fprintf(out, "%s %s\r", m.Status, m.Progress)
 			} else if m.Error != "" {
 				return fmt.Errorf(m.Error)
 			} else {
@@ -1404,7 +1405,7 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer) e
 }
 
 func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in *os.File, out io.Writer) error {
-	req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", API_VERSION, path), nil)
+	req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", APIVERSION, path), nil)
 	if err != nil {
 		return err
 	}
@@ -1425,12 +1426,12 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in *os.Fi
 		return err
 	})
 
-	if in != nil && setRawTerminal && term.IsTerminal(int(in.Fd())) && os.Getenv("NORAW") == "" {
-		if oldState, err := term.SetRawTerminal(); err != nil {
+	if in != nil && setRawTerminal && term.IsTerminal(in.Fd()) && os.Getenv("NORAW") == "" {
+		oldState, err := term.SetRawTerminal()
+		if err != nil {
 			return err
-		} else {
-			defer term.RestoreTerminal(oldState)
 		}
+		defer term.RestoreTerminal(oldState)
 	}
 	sendStdin := utils.Go(func() error {
 		_, err := io.Copy(rwc, in)
@@ -1444,7 +1445,7 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in *os.Fi
 		return err
 	}
 
-	if !term.IsTerminal(int(os.Stdin.Fd())) {
+	if !term.IsTerminal(os.Stdin.Fd()) {
 		if err := <-sendStdin; err != nil {
 			return err
 		}

+ 46 - 45
container.go

@@ -23,7 +23,7 @@ import (
 type Container struct {
 	root string
 
-	Id string
+	ID string
 
 	Created time.Time
 
@@ -167,8 +167,8 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *flag.FlagSet
 }
 
 type NetworkSettings struct {
-	IpAddress   string
-	IpPrefixLen int
+	IPAddress   string
+	IPPrefixLen int
 	Gateway     string
 	Bridge      string
 	PortMapping map[string]string
@@ -409,7 +409,7 @@ func (container *Container) Start() error {
 	defer container.State.unlock()
 
 	if container.State.Running {
-		return fmt.Errorf("The container %s is already running.", container.Id)
+		return fmt.Errorf("The container %s is already running.", container.ID)
 	}
 	if err := container.EnsureMounted(); err != nil {
 		return err
@@ -431,24 +431,24 @@ func (container *Container) Start() error {
 
 	// Create the requested volumes volumes
 	for volPath := range container.Config.Volumes {
-		if c, err := container.runtime.volumes.Create(nil, container, "", "", nil); err != nil {
+		c, err := container.runtime.volumes.Create(nil, container, "", "", nil)
+		if err != nil {
 			return err
-		} else {
-			if err := os.MkdirAll(path.Join(container.RootfsPath(), volPath), 0755); err != nil {
-				return nil
-			}
-			container.Volumes[volPath] = c.Id
 		}
+		if err := os.MkdirAll(path.Join(container.RootfsPath(), volPath), 0755); err != nil {
+			return nil
+		}
+		container.Volumes[volPath] = c.ID
 	}
 
 	if container.Config.VolumesFrom != "" {
 		c := container.runtime.Get(container.Config.VolumesFrom)
 		if c == nil {
-			return fmt.Errorf("Container %s not found. Impossible to mount its volumes", container.Id)
+			return fmt.Errorf("Container %s not found. Impossible to mount its volumes", container.ID)
 		}
 		for volPath, id := range c.Volumes {
 			if _, exists := container.Volumes[volPath]; exists {
-				return fmt.Errorf("The requested volume %s overlap one of the volume of the container %s", volPath, c.Id)
+				return fmt.Errorf("The requested volume %s overlap one of the volume of the container %s", volPath, c.ID)
 			}
 			if err := os.MkdirAll(path.Join(container.RootfsPath(), volPath), 0755); err != nil {
 				return nil
@@ -462,7 +462,7 @@ func (container *Container) Start() error {
 	}
 
 	params := []string{
-		"-n", container.Id,
+		"-n", container.ID,
 		"-f", container.lxcConfigPath(),
 		"--",
 		"/sbin/init",
@@ -573,17 +573,17 @@ func (container *Container) allocateNetwork() error {
 	}
 	container.NetworkSettings.PortMapping = make(map[string]string)
 	for _, spec := range container.Config.PortSpecs {
-		if nat, err := iface.AllocatePort(spec); err != nil {
+		nat, err := iface.AllocatePort(spec)
+		if err != nil {
 			iface.Release()
 			return err
-		} else {
-			container.NetworkSettings.PortMapping[strconv.Itoa(nat.Backend)] = strconv.Itoa(nat.Frontend)
 		}
+		container.NetworkSettings.PortMapping[strconv.Itoa(nat.Backend)] = strconv.Itoa(nat.Frontend)
 	}
 	container.network = iface
 	container.NetworkSettings.Bridge = container.runtime.networkManager.bridgeIface
-	container.NetworkSettings.IpAddress = iface.IPNet.IP.String()
-	container.NetworkSettings.IpPrefixLen, _ = iface.IPNet.Mask.Size()
+	container.NetworkSettings.IPAddress = iface.IPNet.IP.String()
+	container.NetworkSettings.IPPrefixLen, _ = iface.IPNet.Mask.Size()
 	container.NetworkSettings.Gateway = iface.Gateway.String()
 	return nil
 }
@@ -597,16 +597,16 @@ func (container *Container) releaseNetwork() {
 // FIXME: replace this with a control socket within docker-init
 func (container *Container) waitLxc() error {
 	for {
-		if output, err := exec.Command("lxc-info", "-n", container.Id).CombinedOutput(); err != nil {
+		output, err := exec.Command("lxc-info", "-n", container.ID).CombinedOutput()
+		if err != nil {
 			return err
-		} else {
-			if !strings.Contains(string(output), "RUNNING") {
-				return nil
-			}
+		}
+		if !strings.Contains(string(output), "RUNNING") {
+			return nil
 		}
 		time.Sleep(500 * time.Millisecond)
 	}
-	return nil
+	panic("Unreachable")
 }
 
 func (container *Container) monitor() {
@@ -616,17 +616,17 @@ func (container *Container) monitor() {
 	// If the command does not exists, try to wait via lxc
 	if container.cmd == nil {
 		if err := container.waitLxc(); err != nil {
-			utils.Debugf("%s: Process: %s", container.Id, err)
+			utils.Debugf("%s: Process: %s", container.ID, err)
 		}
 	} else {
 		if err := container.cmd.Wait(); err != nil {
 			// Discard the error as any signals or non 0 returns will generate an error
-			utils.Debugf("%s: Process: %s", container.Id, err)
+			utils.Debugf("%s: Process: %s", container.ID, err)
 		}
 	}
 	utils.Debugf("Process finished")
 
-	var exitCode int = -1
+	exitCode := -1
 	if container.cmd != nil {
 		exitCode = container.cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
 	}
@@ -635,24 +635,24 @@ func (container *Container) monitor() {
 	container.releaseNetwork()
 	if container.Config.OpenStdin {
 		if err := container.stdin.Close(); err != nil {
-			utils.Debugf("%s: Error close stdin: %s", container.Id, err)
+			utils.Debugf("%s: Error close stdin: %s", container.ID, err)
 		}
 	}
 	if err := container.stdout.CloseWriters(); err != nil {
-		utils.Debugf("%s: Error close stdout: %s", container.Id, err)
+		utils.Debugf("%s: Error close stdout: %s", container.ID, err)
 	}
 	if err := container.stderr.CloseWriters(); err != nil {
-		utils.Debugf("%s: Error close stderr: %s", container.Id, err)
+		utils.Debugf("%s: Error close stderr: %s", container.ID, err)
 	}
 
 	if container.ptyMaster != nil {
 		if err := container.ptyMaster.Close(); err != nil {
-			utils.Debugf("%s: Error closing Pty master: %s", container.Id, err)
+			utils.Debugf("%s: Error closing Pty master: %s", container.ID, err)
 		}
 	}
 
 	if err := container.Unmount(); err != nil {
-		log.Printf("%v: Failed to umount filesystem: %v", container.Id, err)
+		log.Printf("%v: Failed to umount filesystem: %v", container.ID, err)
 	}
 
 	// Re-create a brand new stdin pipe once the container exited
@@ -673,7 +673,7 @@ func (container *Container) monitor() {
 		// This is because State.setStopped() has already been called, and has caused Wait()
 		// to return.
 		// FIXME: why are we serializing running state to disk in the first place?
-		//log.Printf("%s: Failed to dump configuration to the disk: %s", container.Id, err)
+		//log.Printf("%s: Failed to dump configuration to the disk: %s", container.ID, err)
 	}
 }
 
@@ -683,17 +683,17 @@ func (container *Container) kill() error {
 	}
 
 	// Sending SIGKILL to the process via lxc
-	output, err := exec.Command("lxc-kill", "-n", container.Id, "9").CombinedOutput()
+	output, err := exec.Command("lxc-kill", "-n", container.ID, "9").CombinedOutput()
 	if err != nil {
-		log.Printf("error killing container %s (%s, %s)", container.Id, output, err)
+		log.Printf("error killing container %s (%s, %s)", container.ID, output, err)
 	}
 
 	// 2. Wait for the process to die, in last resort, try to kill the process directly
 	if err := container.WaitTimeout(10 * time.Second); err != nil {
 		if container.cmd == nil {
-			return fmt.Errorf("lxc-kill failed, impossible to kill the container %s", container.Id)
+			return fmt.Errorf("lxc-kill failed, impossible to kill the container %s", container.ID)
 		}
-		log.Printf("Container %s failed to exit within 10 seconds of lxc SIGKILL - trying direct SIGKILL", container.Id)
+		log.Printf("Container %s failed to exit within 10 seconds of lxc SIGKILL - trying direct SIGKILL", container.ID)
 		if err := container.cmd.Process.Kill(); err != nil {
 			return err
 		}
@@ -721,7 +721,7 @@ func (container *Container) Stop(seconds int) error {
 	}
 
 	// 1. Send a SIGTERM
-	if output, err := exec.Command("lxc-kill", "-n", container.Id, "15").CombinedOutput(); err != nil {
+	if output, err := exec.Command("lxc-kill", "-n", container.ID, "15").CombinedOutput(); err != nil {
 		log.Print(string(output))
 		log.Print("Failed to send SIGTERM to the process, force killing")
 		if err := container.kill(); err != nil {
@@ -731,7 +731,7 @@ func (container *Container) Stop(seconds int) error {
 
 	// 2. Wait for the process to exit on its own
 	if err := container.WaitTimeout(time.Duration(seconds) * time.Second); err != nil {
-		log.Printf("Container %v failed to exit within %d seconds of SIGTERM - using the force", container.Id, seconds)
+		log.Printf("Container %v failed to exit within %d seconds of SIGTERM - using the force", container.ID, seconds)
 		if err := container.kill(); err != nil {
 			return err
 		}
@@ -795,7 +795,8 @@ func (container *Container) WaitTimeout(timeout time.Duration) error {
 	case <-done:
 		return nil
 	}
-	panic("unreachable")
+
+	panic("Unreachable")
 }
 
 func (container *Container) EnsureMounted() error {
@@ -838,16 +839,16 @@ func (container *Container) Unmount() error {
 	return Unmount(container.RootfsPath())
 }
 
-// ShortId returns a shorthand version of the container's id for convenience.
+// ShortID returns a shorthand version of the container's id for convenience.
 // A collision with other container shorthands is very unlikely, but possible.
 // In case of a collision a lookup with Runtime.Get() will fail, and the caller
 // will need to use a langer prefix, or the full-length container Id.
-func (container *Container) ShortId() string {
-	return utils.TruncateId(container.Id)
+func (container *Container) ShortID() string {
+	return utils.TruncateID(container.ID)
 }
 
 func (container *Container) logPath(name string) string {
-	return path.Join(container.root, fmt.Sprintf("%s-%s.log", container.Id, name))
+	return path.Join(container.root, fmt.Sprintf("%s-%s.log", container.ID, name))
 }
 
 func (container *Container) ReadLog(name string) (io.Reader, error) {
@@ -887,7 +888,7 @@ func (container *Container) rwPath() string {
 	return path.Join(container.root, "rw")
 }
 
-func validateId(id string) error {
+func validateID(id string) error {
 	if id == "" {
 		return fmt.Errorf("Invalid empty id")
 	}

+ 64 - 33
container_test.go

@@ -14,7 +14,7 @@ import (
 	"time"
 )
 
-func TestIdFormat(t *testing.T) {
+func TestIDFormat(t *testing.T) {
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)
@@ -22,19 +22,19 @@ func TestIdFormat(t *testing.T) {
 	defer nuke(runtime)
 	container1, err := NewBuilder(runtime).Create(
 		&Config{
-			Image: GetTestImage(runtime).Id,
+			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"/bin/sh", "-c", "echo hello world"},
 		},
 	)
 	if err != nil {
 		t.Fatal(err)
 	}
-	match, err := regexp.Match("^[0-9a-f]{64}$", []byte(container1.Id))
+	match, err := regexp.Match("^[0-9a-f]{64}$", []byte(container1.ID))
 	if err != nil {
 		t.Fatal(err)
 	}
 	if !match {
-		t.Fatalf("Invalid container ID: %s", container1.Id)
+		t.Fatalf("Invalid container ID: %s", container1.ID)
 	}
 }
 
@@ -46,7 +46,7 @@ func TestMultipleAttachRestart(t *testing.T) {
 	defer nuke(runtime)
 	container, err := NewBuilder(runtime).Create(
 		&Config{
-			Image: GetTestImage(runtime).Id,
+			Image: GetTestImage(runtime).ID,
 			Cmd: []string{"/bin/sh", "-c",
 				"i=1; while [ $i -le 5 ]; do i=`expr $i + 1`;  echo hello; done"},
 		},
@@ -153,7 +153,7 @@ func TestDiff(t *testing.T) {
 	// Create a container and remove a file
 	container1, err := builder.Create(
 		&Config{
-			Image: GetTestImage(runtime).Id,
+			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"/bin/rm", "/etc/passwd"},
 		},
 	)
@@ -194,7 +194,7 @@ func TestDiff(t *testing.T) {
 	// Create a new container from the commited image
 	container2, err := builder.Create(
 		&Config{
-			Image: img.Id,
+			Image: img.ID,
 			Cmd:   []string{"cat", "/etc/passwd"},
 		},
 	)
@@ -217,6 +217,37 @@ func TestDiff(t *testing.T) {
 			t.Fatalf("/etc/passwd should not be present in the diff after commit.")
 		}
 	}
+
+	// Create a new containere
+	container3, err := builder.Create(
+		&Config{
+			Image: GetTestImage(runtime).ID,
+			Cmd:   []string{"rm", "/bin/httpd"},
+		},
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer runtime.Destroy(container3)
+
+	if err := container3.Run(); err != nil {
+		t.Fatal(err)
+	}
+
+	// Check the changelog
+	c, err = container3.Changes()
+	if err != nil {
+		t.Fatal(err)
+	}
+	success = false
+	for _, elem := range c {
+		if elem.Path == "/bin/httpd" && elem.Kind == 2 {
+			success = true
+		}
+	}
+	if !success {
+		t.Fatalf("/bin/httpd should be present in the diff after commit.")
+	}
 }
 
 func TestCommitAutoRun(t *testing.T) {
@@ -229,7 +260,7 @@ func TestCommitAutoRun(t *testing.T) {
 	builder := NewBuilder(runtime)
 	container1, err := builder.Create(
 		&Config{
-			Image: GetTestImage(runtime).Id,
+			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"/bin/sh", "-c", "echo hello > /world"},
 		},
 	)
@@ -260,7 +291,7 @@ func TestCommitAutoRun(t *testing.T) {
 	// FIXME: Make a TestCommit that stops here and check docker.root/layers/img.id/world
 	container2, err := builder.Create(
 		&Config{
-			Image: img.Id,
+			Image: img.ID,
 		},
 	)
 	if err != nil {
@@ -309,7 +340,7 @@ func TestCommitRun(t *testing.T) {
 
 	container1, err := builder.Create(
 		&Config{
-			Image: GetTestImage(runtime).Id,
+			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"/bin/sh", "-c", "echo hello > /world"},
 		},
 	)
@@ -341,7 +372,7 @@ func TestCommitRun(t *testing.T) {
 
 	container2, err := builder.Create(
 		&Config{
-			Image: img.Id,
+			Image: img.ID,
 			Cmd:   []string{"cat", "/world"},
 		},
 	)
@@ -388,7 +419,7 @@ func TestStart(t *testing.T) {
 	defer nuke(runtime)
 	container, err := NewBuilder(runtime).Create(
 		&Config{
-			Image:     GetTestImage(runtime).Id,
+			Image:     GetTestImage(runtime).ID,
 			Memory:    33554432,
 			CpuShares: 1000,
 			Cmd:       []string{"/bin/cat"},
@@ -432,7 +463,7 @@ func TestRun(t *testing.T) {
 	defer nuke(runtime)
 	container, err := NewBuilder(runtime).Create(
 		&Config{
-			Image: GetTestImage(runtime).Id,
+			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"ls", "-al"},
 		},
 	)
@@ -460,7 +491,7 @@ func TestOutput(t *testing.T) {
 	defer nuke(runtime)
 	container, err := NewBuilder(runtime).Create(
 		&Config{
-			Image: GetTestImage(runtime).Id,
+			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"echo", "-n", "foobar"},
 		},
 	)
@@ -484,7 +515,7 @@ func TestKillDifferentUser(t *testing.T) {
 	}
 	defer nuke(runtime)
 	container, err := NewBuilder(runtime).Create(&Config{
-		Image: GetTestImage(runtime).Id,
+		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"tail", "-f", "/etc/resolv.conf"},
 		User:  "daemon",
 	},
@@ -532,7 +563,7 @@ func TestKill(t *testing.T) {
 	}
 	defer nuke(runtime)
 	container, err := NewBuilder(runtime).Create(&Config{
-		Image: GetTestImage(runtime).Id,
+		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"cat", "/dev/zero"},
 	},
 	)
@@ -580,7 +611,7 @@ func TestExitCode(t *testing.T) {
 	builder := NewBuilder(runtime)
 
 	trueContainer, err := builder.Create(&Config{
-		Image: GetTestImage(runtime).Id,
+		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"/bin/true", ""},
 	})
 	if err != nil {
@@ -595,7 +626,7 @@ func TestExitCode(t *testing.T) {
 	}
 
 	falseContainer, err := builder.Create(&Config{
-		Image: GetTestImage(runtime).Id,
+		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"/bin/false", ""},
 	})
 	if err != nil {
@@ -617,7 +648,7 @@ func TestRestart(t *testing.T) {
 	}
 	defer nuke(runtime)
 	container, err := NewBuilder(runtime).Create(&Config{
-		Image: GetTestImage(runtime).Id,
+		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"echo", "-n", "foobar"},
 	},
 	)
@@ -650,7 +681,7 @@ func TestRestartStdin(t *testing.T) {
 	}
 	defer nuke(runtime)
 	container, err := NewBuilder(runtime).Create(&Config{
-		Image: GetTestImage(runtime).Id,
+		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"cat"},
 
 		OpenStdin: true,
@@ -732,7 +763,7 @@ func TestUser(t *testing.T) {
 
 	// Default user must be root
 	container, err := builder.Create(&Config{
-		Image: GetTestImage(runtime).Id,
+		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"id"},
 	},
 	)
@@ -750,7 +781,7 @@ func TestUser(t *testing.T) {
 
 	// Set a username
 	container, err = builder.Create(&Config{
-		Image: GetTestImage(runtime).Id,
+		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"id"},
 
 		User: "root",
@@ -770,7 +801,7 @@ func TestUser(t *testing.T) {
 
 	// Set a UID
 	container, err = builder.Create(&Config{
-		Image: GetTestImage(runtime).Id,
+		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"id"},
 
 		User: "0",
@@ -790,7 +821,7 @@ func TestUser(t *testing.T) {
 
 	// Set a different user by uid
 	container, err = builder.Create(&Config{
-		Image: GetTestImage(runtime).Id,
+		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"id"},
 
 		User: "1",
@@ -812,7 +843,7 @@ func TestUser(t *testing.T) {
 
 	// Set a different user by username
 	container, err = builder.Create(&Config{
-		Image: GetTestImage(runtime).Id,
+		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"id"},
 
 		User: "daemon",
@@ -841,7 +872,7 @@ func TestMultipleContainers(t *testing.T) {
 	builder := NewBuilder(runtime)
 
 	container1, err := builder.Create(&Config{
-		Image: GetTestImage(runtime).Id,
+		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"cat", "/dev/zero"},
 	},
 	)
@@ -851,7 +882,7 @@ func TestMultipleContainers(t *testing.T) {
 	defer runtime.Destroy(container1)
 
 	container2, err := builder.Create(&Config{
-		Image: GetTestImage(runtime).Id,
+		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"cat", "/dev/zero"},
 	},
 	)
@@ -897,7 +928,7 @@ func TestStdin(t *testing.T) {
 	}
 	defer nuke(runtime)
 	container, err := NewBuilder(runtime).Create(&Config{
-		Image: GetTestImage(runtime).Id,
+		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"cat"},
 
 		OpenStdin: true,
@@ -944,7 +975,7 @@ func TestTty(t *testing.T) {
 	}
 	defer nuke(runtime)
 	container, err := NewBuilder(runtime).Create(&Config{
-		Image: GetTestImage(runtime).Id,
+		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"cat"},
 
 		OpenStdin: true,
@@ -991,7 +1022,7 @@ func TestEnv(t *testing.T) {
 	}
 	defer nuke(runtime)
 	container, err := NewBuilder(runtime).Create(&Config{
-		Image: GetTestImage(runtime).Id,
+		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"/usr/bin/env"},
 	},
 	)
@@ -1069,7 +1100,7 @@ func TestLXCConfig(t *testing.T) {
 	cpuMax := 10000
 	cpu := cpuMin + rand.Intn(cpuMax-cpuMin)
 	container, err := NewBuilder(runtime).Create(&Config{
-		Image: GetTestImage(runtime).Id,
+		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"/bin/true"},
 
 		Hostname:  "foobar",
@@ -1097,7 +1128,7 @@ func BenchmarkRunSequencial(b *testing.B) {
 	defer nuke(runtime)
 	for i := 0; i < b.N; i++ {
 		container, err := NewBuilder(runtime).Create(&Config{
-			Image: GetTestImage(runtime).Id,
+			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"echo", "-n", "foo"},
 		},
 		)
@@ -1132,7 +1163,7 @@ func BenchmarkRunParallel(b *testing.B) {
 		tasks = append(tasks, complete)
 		go func(i int, complete chan error) {
 			container, err := NewBuilder(runtime).Create(&Config{
-				Image: GetTestImage(runtime).Id,
+				Image: GetTestImage(runtime).ID,
 				Cmd:   []string{"echo", "-n", "foo"},
 			},
 			)

+ 3 - 3
contrib/crashTest.go

@@ -11,13 +11,13 @@ import (
 	"time"
 )
 
-var DOCKER_PATH string = path.Join(os.Getenv("DOCKERPATH"), "docker")
+var DOCKERPATH = path.Join(os.Getenv("DOCKERPATH"), "docker")
 
 // WARNING: this crashTest will 1) crash your host, 2) remove all containers
 func runDaemon() (*exec.Cmd, error) {
 	os.Remove("/var/run/docker.pid")
 	exec.Command("rm", "-rf", "/var/lib/docker/containers").Run()
-	cmd := exec.Command(DOCKER_PATH, "-d")
+	cmd := exec.Command(DOCKERPATH, "-d")
 	outPipe, err := cmd.StdoutPipe()
 	if err != nil {
 		return nil, err
@@ -77,7 +77,7 @@ func crashTest() error {
 			stop = false
 			for i := 0; i < 100 && !stop; {
 				func() error {
-					cmd := exec.Command(DOCKER_PATH, "run", "base", "echo", fmt.Sprintf("%d", totalTestCount))
+					cmd := exec.Command(DOCKERPATH, "run", "base", "echo", fmt.Sprintf("%d", totalTestCount))
 					i++
 					totalTestCount++
 					outPipe, err := cmd.StdoutPipe()

+ 0 - 1
contrib/docker-build/MAINTAINERS

@@ -1 +0,0 @@
-Solomon Hykes <solomon@dotcloud.com>

+ 0 - 68
contrib/docker-build/README

@@ -1,68 +0,0 @@
-# docker-build: build your software with docker
-
-## Description
-
-docker-build is a script to build docker images from source. It will be deprecated once the 'build' feature is incorporated into docker itself (See https://github.com/dotcloud/docker/issues/278)
-
-Author: Solomon Hykes <solomon@dotcloud.com>
-
-
-## Install
-
-docker-builder requires:
-
-1) A reasonably recent Python setup (tested on 2.7.2).
-
-2) A running docker daemon at version 0.1.4 or more recent (http://www.docker.io/gettingstarted)
-
-
-## Usage
-
-First create a valid Changefile, which defines a sequence of changes to apply to a base image.
-
-    $ cat Changefile
-    # Start build from a know base image
-    from	base:ubuntu-12.10
-    # Update ubuntu sources
-    run	echo 'deb http://archive.ubuntu.com/ubuntu quantal main universe multiverse' > /etc/apt/sources.list
-    run	apt-get update
-    # Install system packages
-    run	DEBIAN_FRONTEND=noninteractive apt-get install -y -q git
-    run DEBIAN_FRONTEND=noninteractive apt-get install -y -q curl
-    run DEBIAN_FRONTEND=noninteractive apt-get install -y -q golang
-    # Insert files from the host (./myscript must be present in the current directory)
-    copy	myscript /usr/local/bin/myscript
-
-
-Run docker-build, and pass the contents of your Changefile as standard input.
-
-    $ IMG=$(./docker-build < Changefile)
-
-This will take a while: for each line of the changefile, docker-build will:
-
-1. Create a new container to execute the given command or insert the given file
-2. Wait for the container to complete execution
-3. Commit the resulting changes as a new image
-4. Use the resulting image as the input of the next step
-
-
-If all the steps succeed, the result will be an image containing the combined results of each build step.
-You can trace back those build steps by inspecting the image's history:
-
-    $ docker history $IMG
-    ID                  CREATED             CREATED BY
-    1e9e2045de86        A few seconds ago   /bin/sh -c cat > /usr/local/bin/myscript; chmod +x /usr/local/bin/git
-    77db140aa62a        A few seconds ago   /bin/sh -c DEBIAN_FRONTEND=noninteractive apt-get install -y -q golang
-    77db140aa62a        A few seconds ago   /bin/sh -c DEBIAN_FRONTEND=noninteractive apt-get install -y -q curl
-    77db140aa62a        A few seconds ago   /bin/sh -c DEBIAN_FRONTEND=noninteractive apt-get install -y -q git 
-    83e85d155451        A few seconds ago   /bin/sh -c apt-get update
-    bfd53b36d9d3        A few seconds ago   /bin/sh -c echo 'deb http://archive.ubuntu.com/ubuntu quantal main universe multiverse' > /etc/apt/sources.list
-    base		2 weeks ago         /bin/bash
-    27cf78414709        2 weeks ago
-
-
-Note that your build started from 'base', as instructed by your Changefile. But that base image itself seems to have been built in 2 steps - hence the extra step in the history.
-
-
-You can use this build technique to create any image you want: a database, a web application, or anything else that can be build by a sequence of unix commands - in other words, anything else.
-

+ 0 - 142
contrib/docker-build/docker-build

@@ -1,142 +0,0 @@
-#!/usr/bin/env python
-
-# docker-build is a script to build docker images from source.
-# It will be deprecated once the 'build' feature is incorporated into docker itself.
-# (See https://github.com/dotcloud/docker/issues/278)
-#
-# Author: Solomon Hykes <solomon@dotcloud.com>
-
-
-
-# First create a valid Changefile, which defines a sequence of changes to apply to a base image.
-# 
-#     $ cat Changefile
-#     # Start build from a know base image
-#     from	base:ubuntu-12.10
-#     # Update ubuntu sources
-#     run	echo 'deb http://archive.ubuntu.com/ubuntu quantal main universe multiverse' > /etc/apt/sources.list
-#     run	apt-get update
-#     # Install system packages
-#     run	DEBIAN_FRONTEND=noninteractive apt-get install -y -q git
-#     run DEBIAN_FRONTEND=noninteractive apt-get install -y -q curl
-#     run DEBIAN_FRONTEND=noninteractive apt-get install -y -q golang
-#     # Insert files from the host (./myscript must be present in the current directory)
-#     copy	myscript /usr/local/bin/myscript
-# 
-# 
-# Run docker-build, and pass the contents of your Changefile as standard input.
-# 
-#     $ IMG=$(./docker-build < Changefile)
-# 
-# This will take a while: for each line of the changefile, docker-build will:
-# 
-# 1. Create a new container to execute the given command or insert the given file
-# 2. Wait for the container to complete execution
-# 3. Commit the resulting changes as a new image
-# 4. Use the resulting image as the input of the next step
-
-
-import sys
-import subprocess
-import json
-import hashlib
-
-def docker(args, stdin=None):
-	print "# docker " + " ".join(args)
-	p = subprocess.Popen(["docker"] + list(args), stdin=stdin, stdout=subprocess.PIPE)
-	return p.stdout
-
-def image_exists(img):
-	return docker(["inspect", img]).read().strip() != ""
-
-def image_config(img):
-	return json.loads(docker(["inspect", img]).read()).get("config", {})
-
-def run_and_commit(img_in, cmd, stdin=None, author=None, run=None):
-	run_id = docker(["run"] + (["-i", "-a", "stdin"] if stdin else ["-d"]) + [img_in, "/bin/sh", "-c", cmd], stdin=stdin).read().rstrip()
-	print "---> Waiting for " + run_id
-	result=int(docker(["wait", run_id]).read().rstrip())
-	if result != 0:
-		print "!!! '{}' return non-zero exit code '{}'. Aborting.".format(cmd, result)
-		sys.exit(1)
-	return docker(["commit"] + (["-author", author] if author else []) + (["-run", json.dumps(run)] if run is not None else []) + [run_id]).read().rstrip()
-
-def insert(base, src, dst, author=None):
-	print "COPY {} to {} in {}".format(src, dst, base)
-	if dst == "":
-		raise Exception("Missing destination path")
-	stdin = file(src)
-	stdin.seek(0)
-	return run_and_commit(base, "cat > {0}; chmod +x {0}".format(dst), stdin=stdin, author=author)
-
-def add(base, src, dst, author=None):
-	print "PUSH to {} in {}".format(dst, base)
-	if src == ".":
-		tar = subprocess.Popen(["tar", "-c", "."], stdout=subprocess.PIPE).stdout
-	else:
-		tar = subprocess.Popen(["curl", src], stdout=subprocess.PIPE).stdout
-	if dst == "":
-		raise Exception("Missing argument to push")
-	return run_and_commit(base, "mkdir -p '{0}' && tar -C '{0}' -x".format(dst), stdin=tar, author=author)
-
-def main():
-	base=""
-	maintainer=""
-	steps = []
-	try:
-		for line in sys.stdin.readlines():
-			line = line.strip()
-			# Skip comments and empty lines
-			if line == "" or line[0] == "#":
-				continue
-			op, param = line.split(None, 1)
-			print op.upper() + " " + param
-			if op == "from":
-				base = param
-				steps.append(base)
-			elif op == "maintainer":
-				maintainer = param
-			elif op == "run":
-				result = run_and_commit(base, param, author=maintainer)
-				steps.append(result)
-				base = result
-				print "===> " + base
-			elif op == "copy":
-				src, dst = param.split("	", 1)
-				result = insert(base, src, dst, author=maintainer)
-				steps.append(result)
-				base = result
-				print "===> " + base
-			elif op == "add":
-				src, dst = param.split("	", 1)
-				result = add(base, src, dst, author=maintainer)
-				steps.append(result)
-				base=result
-				print "===> " + base
-			elif op == "expose":
-				config = image_config(base)
-				if config.get("PortSpecs") is None:
-					config["PortSpecs"] = []
-				portspec = param.strip()
-				config["PortSpecs"].append(portspec)
-				result = run_and_commit(base, "# (nop) expose port {}".format(portspec), author=maintainer, run=config)
-				steps.append(result)
-				base=result
-				print "===> " + base
-			elif op == "cmd":
-				config  = image_config(base)
-				cmd = list(json.loads(param))
-				config["Cmd"] = cmd
-				result = run_and_commit(base, "# (nop) set default command to '{}'".format(" ".join(cmd)), author=maintainer, run=config)
-				steps.append(result)
-				base=result
-				print "===> " + base
-			else:
-				print "Skipping uknown op " + op
-	except:
-		docker(["rmi"] + steps[1:])
-		raise
-	print base
-
-if __name__ == "__main__":
-	main()

+ 0 - 13
contrib/docker-build/example.changefile

@@ -1,13 +0,0 @@
-# Start build from a know base image
-maintainer	Solomon Hykes <solomon@dotcloud.com>
-from	base:ubuntu-12.10
-# Update ubuntu sources
-run	echo 'deb http://archive.ubuntu.com/ubuntu quantal main universe multiverse' > /etc/apt/sources.list
-run	apt-get update
-# Install system packages
-run	DEBIAN_FRONTEND=noninteractive apt-get install -y -q git
-run	DEBIAN_FRONTEND=noninteractive apt-get install -y -q curl
-run	DEBIAN_FRONTEND=noninteractive apt-get install -y -q golang
-# Insert files from the host (./myscript must be present in the current directory)
-copy	myscript	/usr/local/bin/myscript
-push	/src

+ 0 - 3
contrib/docker-build/myscript

@@ -1,3 +0,0 @@
-#!/bin/sh
-
-echo hello, world!

+ 2 - 2
docker/docker.go

@@ -15,7 +15,7 @@ import (
 )
 
 var (
-	GIT_COMMIT string
+	GITCOMMIT string
 )
 
 func main() {
@@ -59,7 +59,7 @@ func main() {
 	if *flDebug {
 		os.Setenv("DEBUG", "1")
 	}
-	docker.GIT_COMMIT = GIT_COMMIT
+	docker.GITCOMMIT = GITCOMMIT
 	if *flDaemon {
 		if flag.NArg() != 0 {
 			flag.Usage()

+ 1 - 1
docs/Makefile

@@ -63,7 +63,7 @@ site:
 connect:
 	@echo connecting dotcloud to www.docker.io website, make sure to use user 1
 	@cd _build/website/ ; \
-	dotcloud connect dockerwebsite ;
+	dotcloud connect dockerwebsite ; \
 	dotcloud list
 
 push:

+ 10 - 9
docs/sources/api/docker_remote_api.rst

@@ -564,7 +564,7 @@ Create an image
 	   Content-Type: application/json
 
 	   {"status":"Pulling..."}
-	   {"progress":"1/? (n/a)"}
+	   {"status":"Pulling", "progress":"1/? (n/a)"}
 	   {"error":"Invalid..."}
 	   ...
 
@@ -607,7 +607,7 @@ Insert a file in a image
 	   Content-Type: application/json
 
 	   {"status":"Inserting..."}
-	   {"progress":"1/? (n/a)"}
+	   {"status":"Inserting", "progress":"1/? (n/a)"}
 	   {"error":"Invalid..."}
 	   ...
 
@@ -734,7 +734,7 @@ Push an image on the registry
 	   Content-Type: application/json
 
 	   {"status":"Pushing..."}
-	   {"progress":"1/? (n/a)"}
+	   {"status":"Pushing", "progress":"1/? (n/a)"}
 	   {"error":"Invalid..."}
 	   ...
 
@@ -974,10 +974,12 @@ Display system-wide information
 
 	   {
 		"Containers":11,
-		"Version":"0.2.2",
 		"Images":16,
-		"GoVersion":"go1.0.3",
-		"Debug":false
+		"Debug":false,
+		"NFd": 11,
+		"NGoroutines":21,
+		"MemoryLimit":true,
+		"SwapLimit":false
 	   }
 
         :statuscode 200: no error
@@ -1003,12 +1005,11 @@ Show the docker version information
 
            HTTP/1.1 200 OK
 	   Content-Type: application/json
-	   
+
 	   {
 		"Version":"0.2.2",
 		"GitCommit":"5a2a5cc+CHANGES",
-		"MemoryLimit":true,
-		"SwapLimit":false
+		"GoVersion":"go1.0.3"
 	   }
 
         :statuscode 200: no error

+ 1 - 1
docs/sources/contributing/contributing.rst

@@ -5,5 +5,5 @@
 Contributing to Docker
 ======================
 
-Want to hack on Docker? Awesome! The repository includes `all the instructions you need to get started <https://github.com/dotcloud/docker/blob/master/CONTRIBUTING.md>`.
+Want to hack on Docker? Awesome! The repository includes `all the instructions you need to get started <https://github.com/dotcloud/docker/blob/master/CONTRIBUTING.md>`_.
 

+ 26 - 2
docs/sources/contributing/devenvironment.rst

@@ -5,11 +5,35 @@
 Setting Up a Dev Environment
 ============================
 
-Instructions that have been verified to work on Ubuntu 12.10,
+Instructions that have been verified to work on Ubuntu Precise 12.04 (LTS) (64-bit),
+
+
+Dependencies
+------------
+
+**Linux kernel 3.8**
+
+Due to a bug in LXC docker works best on the 3.8 kernel. Precise comes with a 3.2 kernel, so we need to upgrade it. The kernel we install comes with AUFS built in.
+
 
 .. code-block:: bash
 
-    sudo apt-get -y install lxc wget bsdtar curl golang git
+   # install the backported kernel
+   sudo apt-get update && sudo apt-get install linux-image-generic-lts-raring
+
+   # reboot
+   sudo reboot
+
+
+Installation
+------------
+
+.. code-block:: bash
+		
+    sudo apt-get install python-software-properties
+    sudo add-apt-repository ppa:gophers/go
+    sudo apt-get update
+    sudo apt-get -y install lxc wget bsdtar curl golang-stable git
 
     export GOPATH=~/go/
     export PATH=$GOPATH/bin:$PATH

+ 7 - 5
docs/sources/faq.rst

@@ -19,7 +19,8 @@ Most frequently asked questions.
 
 3. **Does Docker run on Mac OS X or Windows?**
 
-   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.
+   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 :ref:`install_using_vagrant` and :ref:`windows` installation guides.
 
 4. **How do containers compare to virtual machines?**
 
@@ -34,15 +35,16 @@ Most frequently asked questions.
 
     You can find more answers on:
 
-    * `IRC: docker on freenode`_
+    * `Docker club mailinglist`_
+    * `IRC, docker on freenode`_
     * `Github`_
     * `Ask questions on Stackoverflow`_
     * `Join the conversation on Twitter`_
 
-    .. _Windows: ../installation/windows/
-    .. _MacOSX: ../installation/vagrant/
+
+    .. _Docker club mailinglist: https://groups.google.com/d/forum/docker-club
     .. _the repo: http://www.github.com/dotcloud/docker
-    .. _IRC\: docker on freenode: irc://chat.freenode.net#docker
+    .. _IRC, docker on freenode: irc://chat.freenode.net#docker
     .. _Github: http://www.github.com/dotcloud/docker
     .. _Ask questions on Stackoverflow: http://stackoverflow.com/search?q=docker
     .. _Join the conversation on Twitter: http://twitter.com/getdocker

+ 10 - 0
docs/sources/installation/ubuntulinux.rst

@@ -92,6 +92,16 @@ have AUFS filesystem support enabled, so we need to install it.
    sudo apt-get update
    sudo apt-get install linux-image-extra-`uname -r`
 
+**add-apt-repository support**
+
+Some installations of Ubuntu 13.04 require ``software-properties-common`` to be
+installed before being able to use add-apt-repository.
+
+.. code-block:: bash
+
+  sudo apt-get install software-properties-common
+
+
 Installation
 ------------
 

+ 1 - 0
docs/sources/installation/windows.rst

@@ -2,6 +2,7 @@
 :description: Docker's tutorial to run docker on Windows
 :keywords: Docker, Docker documentation, Windows, requirements, virtualbox, vagrant, git, ssh, putty, cygwin
 
+.. _windows:
 
 Using Vagrant (Windows)
 =======================

+ 1 - 1
docs/sources/use/builder.rst

@@ -18,7 +18,7 @@ steps and commit them along the way, giving you a final image.
 To use Docker Builder, assemble the steps into a text file (commonly referred to
 as a Dockerfile) and supply this to `docker build` on STDIN, like so:
 
-    ``docker build < Dockerfile``
+    ``docker build - < Dockerfile``
 
 Docker will run your steps one-by-one, committing the result if necessary, 
 before finally outputting the ID of your new image.

+ 21 - 9
docs/theme/docker/layout.html

@@ -64,14 +64,15 @@
 
             <div style="float: right" class="pull-right">
                 <ul class="nav">
-                    <li><a href="http://www.docker.io/">Introduction</a></li>
-                    <li><a href="http://www.docker.io/gettingstarted/">Getting started</a></li>
-                    <li class="active"><a href="http://docs.docker.io/en/latest/">Documentation</a></li>
+                    <li id="nav-introduction"><a href="http://www.docker.io/">Introduction</a></li>
+                    <li id="nav-gettingstarted"><a href="http://www.docker.io/gettingstarted/">Getting started</a></li>
+                    <li id="nav-documentation" class="active"><a href="http://docs.docker.io/en/latest/">Documentation</a></li>
+                    <li id="nav-blog"><a href="http://blog.docker.io/">Blog</a></li>
                 </ul>
-                <div class="social links" style="float: right; margin-top: 14px; margin-left: 12px">
-                    <a class="twitter" href="http://twitter.com/getdocker">Twitter</a>
-                    <a class="github" href="https://github.com/dotcloud/docker/">GitHub</a>
-                </div>
+                <!--<div class="social links" style="float: right; margin-top: 14px; margin-left: 12px">-->
+                    <!--<a class="twitter" href="http://twitter.com/getdocker">Twitter</a>-->
+                    <!--<a class="github" href="https://github.com/dotcloud/docker/">GitHub</a>-->
+                <!--</div>-->
             </div>
 
             <div style="margin-left: -12px; float: left;">
@@ -86,8 +87,13 @@
 
 <div class="container">
     <div class="row">
-        <div class="span12 titlebar"><h1 class="pageheader">DOCUMENTATION</h1>
+        <div class="span12 titlebar">
             <!--<span class="pull-right" style="margin-left: 20px; font-size: 20px">{{version}}</span>-->
+            <div class="pull-right" id="fork-us" style="margin-top: 16px; margin-right: 16px;">
+                <a  href="http://github.com/dotcloud/docker/"><img src="{{ pathto('_static/img/fork-us.png', 1) }}"> Fork us on Github</a>
+            </div>
+            <h1 class="pageheader">DOCUMENTATION</h1>
+
         </div>
     </div>
 
@@ -123,8 +129,14 @@
     <div class="row">
 
         <div class="span12 footer">
+            <div class="tbox textright forceleftmargin social links pull-right">
+                <a class="twitter" href="http://twitter.com/getdocker">Twitter</a>
+                <a class="github" href="https://github.com/dotcloud/docker/">GitHub</a>
+            </div>
 
             Docker is a project by <a href="http://www.dotcloud.com">dotCloud</a>
+
+
 {#            {%- if show_source and has_source and sourcename %}#}
 {#            ·#}
 {#            <a href="{{ pathto('_sources/' + sourcename, true)|e }}"#}
@@ -157,7 +169,7 @@
   <!-- script which should be loaded after everything else -->
 <script type="text/javascript">
 
-
+    // Function to make the sticky header possible
     var shiftWindow = function() {
         scrollBy(0, -70);
         console.log("window shifted")

+ 40 - 1
docs/theme/docker/static/css/main.css

@@ -285,6 +285,40 @@ section.header {
 .social .github {
   background-position: -59px 2px;
 }
+#fork-us {
+  /*font-family: 'Maven Pro';*/
+
+  /*font-weight: bold;*/
+
+  font-size: 12px;
+  /*text-transform: uppercase;*/
+
+  display: block;
+  padding: 0px 1em;
+  height: 28px;
+  line-height: 28px;
+  background-color: #43484c;
+  filter: progid:dximagetransform.microsoft.gradient(gradientType=0, startColorstr='#FFFF6E56', endColorstr='#FFED4F35');
+  background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #747474), color-stop(100%, #43484c));
+  background-image: -webkit-linear-gradient(top, #747474 0%, #43484c 100%);
+  background-image: -moz-linear-gradient(top, #747474 0%, #43484c 100%);
+  background-image: -o-linear-gradient(top, #747474 0%, #43484c 100%);
+  background-image: linear-gradient(top, #747474 0%, #43484c 100%);
+  border: 1px solid #43484c;
+  -webkit-border-radius: 4px;
+  -moz-border-radius: 4px;
+  -ms-border-radius: 4px;
+  -o-border-radius: 4px;
+  border-radius: 4px;
+  -webkit-box-shadow: inset rgba(255, 255, 255, 0.17) 0 1px 1px;
+  -moz-box-shadow: inset rgba(255, 255, 255, 0.17) 0 1px 1px;
+  box-shadow: inset rgba(255, 255, 255, 0.17) 0 1px 1px;
+  margin: 8px;
+}
+#fork-us a {
+  color: #faf2ee;
+  text-shadow: rgba(0, 0, 0, 0.3) 0px 1px 0px;
+}
 /* =======================
    Media size overrides
 ======================= */
@@ -325,10 +359,15 @@ section.header {
   
     padding-top: 600px;
   }
+  #fork-us {
+    display: none;
+  }
 }
 /* Landscape phones and down */
 @media (max-width: 480px) {
-  
+  #nav-gettingstarted {
+    display: none;
+  }
 }
 /* Misc fixes */
 table th {

+ 38 - 3
docs/theme/docker/static/css/main.less

@@ -391,6 +391,38 @@ section.header {
 }
 
 
+#fork-us {
+  /*font-family: 'Maven Pro';*/
+  /*font-weight: bold;*/
+  font-size: 12px;
+  /*text-transform: uppercase;*/
+  display: block;
+  padding: 0px 1em;
+  height: 28px;
+  line-height: 28px;
+  background-color: #43484c;
+  filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#FFFF6E56', endColorstr='#FFED4F35');
+  background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #747474), color-stop(100%, #43484c));
+  background-image: -webkit-linear-gradient(top, #747474 0%, #43484c 100%);
+  background-image: -moz-linear-gradient(top, #747474 0%, #43484c 100%);
+  background-image: -o-linear-gradient(top, #747474 0%, #43484c 100%);
+  background-image: linear-gradient(top, #747474 0%, #43484c 100%);
+  border: 1px solid #43484c;
+  -webkit-border-radius: 4px;
+  -moz-border-radius: 4px;
+  -ms-border-radius: 4px;
+  -o-border-radius: 4px;
+  border-radius: 4px;
+  -webkit-box-shadow: inset rgba(255, 255, 255, 0.17) 0 1px 1px;
+  -moz-box-shadow: inset rgba(255, 255, 255, 0.17) 0 1px 1px;
+  box-shadow: inset rgba(255, 255, 255, 0.17) 0 1px 1px;
+  margin: 8px;
+
+  a {
+    color: #faf2ee;
+    text-shadow: rgba(0, 0, 0, 0.3) 0px 1px 0px;
+  }
+}
 /* =======================
    Media size overrides
 ======================= */
@@ -441,14 +473,17 @@ section.header {
   /* TODO: Fix this to be relative to the navigation size */
     padding-top: 600px;
   }
-
+  #fork-us {
+    display: none;
+  }
 }
 
 
 /* Landscape phones and down */
 @media (max-width: 480px) {
-
-
+  #nav-gettingstarted {
+    display: none;
+  }
 }
 
 /* Misc fixes */

+ 25 - 18
docs/website/gettingstarted/index.html

@@ -34,15 +34,11 @@
 
             <div style="float: right" class="pull-right">
                 <ul class="nav">
-                    <li><a href="../">Introduction</a></li>
-                    <li class="active"><a href="">Getting started</a></li>
-                    <li class=""><a href="http://docs.docker.io/en/latest/">Documentation</a></li>
+                    <li id="nav-introduction"><a href="../">Introduction</a></li>
+                    <li id="nav-gettingstarted" class="active"><a href="">Getting started</a></li>
+                    <li id="nav-documentation" class=""><a href="http://docs.docker.io/en/latest/">Documentation</a></li>
+                    <li id="nav-blog"><a href="http://blog.docker.io/">Blog</a></li>
                 </ul>
-
-                <div class="social links" style="float: right; margin-top: 14px; margin-left: 12px">
-                    <a class="twitter" href="http://twitter.com/getdocker">Twitter</a>
-                    <a class="github" href="https://github.com/dotcloud/docker/">GitHub</a>
-                </div>
             </div>
 
             <div style="margin-left: -12px; float: left;">
@@ -55,14 +51,22 @@
 
 <div class="container">
     <div class="row">
-        <div class="span12 titlebar"><h1 class="pageheader">GETTING STARTED</h1>
+
+        <div class="span12 titlebar">
+
+            <div class="pull-right" id="fork-us" style="margin-top: 16px; margin-right: 16px;">
+                <a  href="http://github.com/dotcloud/docker/"><img src="../static/img/fork-us.png"> Fork us on Github</a>
+            </div>
+
+            <h1 class="pageheader"> GETTING STARTED</h1>
         </div>
+
     </div>
 
 </div>
 
 <div class="container">
-    <div class="alert alert-info">
+    <div class="alert alert-info" style="margin-bottom: 0;">
         <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.
     </div>
     <div class="row">
@@ -133,13 +137,13 @@
             </section>
 
             <section class="contentblock">
-                <h2>More resources</h2>
-                <ul>
-                    <li><a href="irc://chat.freenode.net#docker">IRC: docker on freenode</a></li>
-                    <li><a href="http://www.github.com/dotcloud/docker">Github</a></li>
-                    <li><a href="http://stackoverflow.com/tags/docker/">Ask questions on Stackoverflow</a></li>
-                    <li><a href="http://twitter.com/getdocker/">Join the conversation on Twitter</a></li>
-                </ul>
+                <h2>Questions? Want to get in touch?</h2>
+                <p>There are several ways to get in touch:</p>
+                <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>
+                <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>
+                <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>
+                <p><strong>Get help on using Docker</strong> by asking on <a href="http://stackoverflow.com/tags/docker/">Stackoverflow</a></p>
+                <p>And of course, <strong>tweet</strong> your tweets to <a href="http://twitter.com/getdocker/">twitter.com/getdocker</a></p>
             </section>
 
 
@@ -172,7 +176,10 @@
     <footer id="footer" class="footer">
         <div class="row">
             <div class="span12 social">
-
+                <div class="tbox textright forceleftmargin social links pull-right">
+                    <a class="twitter" href="http://twitter.com/getdocker">Twitter</a>
+                    <a class="github" href="https://github.com/dotcloud/docker/">GitHub</a>
+                </div>
                 Docker is a project by <a href="http://www.dotcloud.com">dotCloud</a>
 
             </div>

+ 29 - 29
docs/website/index.html

@@ -44,9 +44,18 @@
         .debug {
             border: 1px red dotted;
         }
+        .twitterblock {
+            min-height: 75px;
+        }
+
+        .twitterblock img {
+            float: left;
+            margin-right: 10px;
+        }
 
     </style>
 
+
 </head>
 
 
@@ -56,17 +65,18 @@
     <div class="navbar-dotcloud">
         <div class="container" style="text-align: center;">
 
+
+            <div class="pull-left" id="fork-us" style="margin-top: 16px;">
+                <a  href="http://github.com/dotcloud/docker/"><img src="static/img/fork-us.png" alt="fork-icon"> Fork us on Github</a>
+            </div>
+
             <div class="pull-right" >
                 <ul class="nav">
-                    <li class="active"><a href="/">Introduction</a></li>
-                    <li ><a href="gettingstarted">Getting started</a></li>
-                    <li class=""><a href="http://docs.docker.io/en/latest/">Documentation</a></li>
+                    <li id="nav-introduction" class="active"><a href="/">Introduction</a></li>
+                    <li id="nav-gettingstarted"><a href="gettingstarted">Getting started</a></li>
+                    <li id="nav-documentation" class=""><a href="http://docs.docker.io/en/latest/">Documentation</a></li>
+                    <li id="nav-blog"><a href="http://blog.docker.io/">Blog</a></li>
                 </ul>
-
-                <div class="social links" style="float: right; margin-top: 14px; margin-left: 12px">
-                    <a class="twitter" href="http://twitter.com/getdocker">Twitter</a>
-                    <a class="github" href="https://github.com/dotcloud/docker/">GitHub</a>
-                </div>
             </div>
         </div>
     </div>
@@ -81,7 +91,7 @@
 
                 <div class="span5" style="margin-bottom: 15px;">
                     <div style="text-align: center;" >
-                        <img src="static/img/docker_letters_500px.png">
+                        <img src="static/img/docker_letters_500px.png" alt="docker letters">
 
                         <h2>The Linux container engine</h2>
                     </div>
@@ -130,7 +140,7 @@
             <section class="contentblock">
                 <div class="container">
                 <div class="span2" style="margin-left: 0" >
-                    <a href="http://dotcloud.theresumator.com/apply/mWjkD4/Software-Engineer.html" title="Job description"><img src="static/img/hiring_graphic.png" width="140px" style="margin-top: 25px"></a>
+                    <a href="http://dotcloud.theresumator.com/apply/mWjkD4/Software-Engineer.html" title="Job description"><img src="static/img/hiring_graphic.png" alt="we're hiring" width="140" style="margin-top: 25px"></a>
                 </div>
                 <div class="span4" style="margin-left: 0">
                     <h4>Do you think it is cool to hack on docker? Join us!</h4>
@@ -156,7 +166,7 @@
                     </div>
                 </a>
                 &nbsp;
-                <input type="button" class="searchbutton" type="submit" value="Search images"
+                <input type="button" class="searchbutton" value="Search images"
                        onClick="window.open('https://index.docker.io')" />
 
             </section>
@@ -184,32 +194,19 @@
 
 </div>
 
-<style>
-    .twitterblock {
-        min-height: 75px;
-    }
-
-    .twitterblock img {
-        float: left;
-        margin-right: 10px;
-    }
-
-</style>
-
-
 <div class="container">
 
     <div class="row">
         <div class="span6">
             <section class="contentblock twitterblock">
                 <img src="https://si0.twimg.com/profile_images/2707460527/252a64411a339184ff375a96fb68dcb0_bigger.png">
-                <em>Mitchell Hashimoto‏@mitchellh:</em> Docker launched today. It is incredible. They’re also working RIGHT NOW on a Vagrant provider. LXC is COMING!!
+                <em>Mitchell Hashimoto ‏@mitchellh:</em> Docker launched today. It is incredible. They’re also working RIGHT NOW on a Vagrant provider. LXC is COMING!!
             </section>
         </div>
         <div class="span6">
             <section class="contentblock twitterblock">
                 <img src="https://si0.twimg.com/profile_images/1108290260/Adam_Jacob-114x150_original_bigger.jpg">
-                <em>Adam Jacob‏@adamhjk:</em> Docker is clearly the right idea. @solomonstre absolutely killed it. Containerized app deployment is the future, I think.
+                <em>Adam Jacob ‏@adamhjk:</em> Docker is clearly the right idea. @solomonstre absolutely killed it. Containerized app deployment is the future, I think.
             </section>
         </div>
     </div>
@@ -217,13 +214,13 @@
         <div class="span6">
             <section class="contentblock twitterblock">
                 <img src="https://si0.twimg.com/profile_images/14872832/twitter_pic_bigger.jpg">
-                <em>Matt Townsend‏@mtownsend:</em> I have a serious code crush on docker.io - it's Lego for PaaS. Motherfucking awesome Lego.
+                <em>Matt Townsend ‏@mtownsend:</em> I have a serious code crush on docker.io - it's Lego for PaaS. Motherfucking awesome Lego.
             </section>
         </div>
         <div class="span6">
             <section class="contentblock twitterblock">
                 <img src="https://si0.twimg.com/profile_images/1312352395/rupert-259x300_bigger.jpg">
-                <em>Rob Harrop‏@robertharrop:</em> Impressed by @getdocker - it's all kinds of magic. Serious rethink of AWS architecture happening @skillsmatter.
+                <em>Rob Harrop ‏@robertharrop:</em> Impressed by @getdocker - it's all kinds of magic. Serious rethink of AWS architecture happening @skillsmatter.
             </section>
         </div>
     </div>
@@ -317,7 +314,10 @@
     <footer id="footer" class="footer">
         <div class="row">
             <div class="span12">
-
+                <div class="tbox textright forceleftmargin social links pull-right">
+                    <a class="twitter" href="http://twitter.com/getdocker">Twitter</a>
+                    <a class="github" href="https://github.com/dotcloud/docker/">GitHub</a>
+                </div>
                 Docker is a project by <a href="http://www.dotcloud.com">dotCloud</a>
 
             </div>

+ 21 - 21
graph.go

@@ -86,14 +86,14 @@ func (graph *Graph) Get(name string) (*Image, error) {
 	if err != nil {
 		return nil, err
 	}
-	if img.Id != id {
-		return nil, fmt.Errorf("Image stored at '%s' has wrong id '%s'", id, img.Id)
+	if img.ID != id {
+		return nil, fmt.Errorf("Image stored at '%s' has wrong id '%s'", id, img.ID)
 	}
 	img.graph = graph
 	graph.lockSumMap.Lock()
 	defer graph.lockSumMap.Unlock()
-	if _, exists := graph.checksumLock[img.Id]; !exists {
-		graph.checksumLock[img.Id] = &sync.Mutex{}
+	if _, exists := graph.checksumLock[img.ID]; !exists {
+		graph.checksumLock[img.ID] = &sync.Mutex{}
 	}
 	return img, nil
 }
@@ -101,7 +101,7 @@ func (graph *Graph) Get(name string) (*Image, error) {
 // Create creates a new image and registers it in the graph.
 func (graph *Graph) Create(layerData Archive, container *Container, comment, author string, config *Config) (*Image, error) {
 	img := &Image{
-		Id:            GenerateId(),
+		ID:            GenerateID(),
 		Comment:       comment,
 		Created:       time.Now(),
 		DockerVersion: VERSION,
@@ -111,7 +111,7 @@ func (graph *Graph) Create(layerData Archive, container *Container, comment, aut
 	}
 	if container != nil {
 		img.Parent = container.Image
-		img.Container = container.Id
+		img.Container = container.ID
 		img.ContainerConfig = *container.Config
 	}
 	if err := graph.Register(layerData, layerData != nil, img); err != nil {
@@ -124,12 +124,12 @@ func (graph *Graph) Create(layerData Archive, container *Container, comment, aut
 // Register imports a pre-existing image into the graph.
 // FIXME: pass img as first argument
 func (graph *Graph) Register(layerData Archive, store bool, img *Image) error {
-	if err := ValidateId(img.Id); err != nil {
+	if err := ValidateID(img.ID); err != nil {
 		return err
 	}
 	// (This is a convenience to save time. Race conditions are taken care of by os.Rename)
-	if graph.Exists(img.Id) {
-		return fmt.Errorf("Image %s already exists", img.Id)
+	if graph.Exists(img.ID) {
+		return fmt.Errorf("Image %s already exists", img.ID)
 	}
 	tmp, err := graph.Mktemp("")
 	defer os.RemoveAll(tmp)
@@ -140,12 +140,12 @@ func (graph *Graph) Register(layerData Archive, store bool, img *Image) error {
 		return err
 	}
 	// Commit
-	if err := os.Rename(tmp, graph.imageRoot(img.Id)); err != nil {
+	if err := os.Rename(tmp, graph.imageRoot(img.ID)); err != nil {
 		return err
 	}
 	img.graph = graph
-	graph.idIndex.Add(img.Id)
-	graph.checksumLock[img.Id] = &sync.Mutex{}
+	graph.idIndex.Add(img.ID)
+	graph.checksumLock[img.ID] = &sync.Mutex{}
 	return nil
 }
 
@@ -173,7 +173,7 @@ func (graph *Graph) TempLayerArchive(id string, compression Compression, output
 // Mktemp creates a temporary sub-directory inside the graph's filesystem.
 func (graph *Graph) Mktemp(id string) (string, error) {
 	if id == "" {
-		id = GenerateId()
+		id = GenerateID()
 	}
 	tmp, err := graph.tmp()
 	if err != nil {
@@ -230,7 +230,7 @@ func (graph *Graph) Map() (map[string]*Image, error) {
 	}
 	images := make(map[string]*Image, len(all))
 	for _, image := range all {
-		images[image.Id] = image
+		images[image.ID] = image
 	}
 	return images, nil
 }
@@ -273,10 +273,10 @@ func (graph *Graph) ByParent() (map[string][]*Image, error) {
 		if err != nil {
 			return
 		}
-		if children, exists := byParent[parent.Id]; exists {
-			byParent[parent.Id] = []*Image{image}
+		if children, exists := byParent[parent.ID]; exists {
+			byParent[parent.ID] = []*Image{image}
 		} else {
-			byParent[parent.Id] = append(children, image)
+			byParent[parent.ID] = append(children, image)
 		}
 	})
 	return byParent, err
@@ -293,8 +293,8 @@ func (graph *Graph) Heads() (map[string]*Image, error) {
 	err = graph.WalkAll(func(image *Image) {
 		// If it's not in the byParent lookup table, then
 		// it's not a parent -> so it's a head!
-		if _, exists := byParent[image.Id]; !exists {
-			heads[image.Id] = image
+		if _, exists := byParent[image.ID]; !exists {
+			heads[image.ID] = image
 		}
 	})
 	return heads, err
@@ -317,11 +317,11 @@ func (graph *Graph) getStoredChecksums() (map[string]string, error) {
 }
 
 func (graph *Graph) storeChecksums(checksums map[string]string) error {
-	checksumJson, err := json.Marshal(checksums)
+	checksumJSON, err := json.Marshal(checksums)
 	if err != nil {
 		return err
 	}
-	if err := ioutil.WriteFile(path.Join(graph.Root, "checksums"), checksumJson, 0600); err != nil {
+	if err := ioutil.WriteFile(path.Join(graph.Root, "checksums"), checksumJSON, 0600); err != nil {
 		return err
 	}
 	return nil

+ 11 - 11
graph_test.go

@@ -34,14 +34,14 @@ func TestInterruptedRegister(t *testing.T) {
 	defer os.RemoveAll(graph.Root)
 	badArchive, w := io.Pipe() // Use a pipe reader as a fake archive which never yields data
 	image := &Image{
-		Id:      GenerateId(),
+		ID:      GenerateID(),
 		Comment: "testing",
 		Created: time.Now(),
 	}
 	go graph.Register(badArchive, false, image)
 	time.Sleep(200 * time.Millisecond)
 	w.CloseWithError(errors.New("But I'm not a tarball!")) // (Nobody's perfect, darling)
-	if _, err := graph.Get(image.Id); err == nil {
+	if _, err := graph.Get(image.ID); err == nil {
 		t.Fatal("Image should not exist after Register is interrupted")
 	}
 	// Registering the same image again should succeed if the first register was interrupted
@@ -67,7 +67,7 @@ func TestGraphCreate(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	if err := ValidateId(image.Id); err != nil {
+	if err := ValidateID(image.ID); err != nil {
 		t.Fatal(err)
 	}
 	if image.Comment != "Testing" {
@@ -91,7 +91,7 @@ func TestRegister(t *testing.T) {
 		t.Fatal(err)
 	}
 	image := &Image{
-		Id:      GenerateId(),
+		ID:      GenerateID(),
 		Comment: "testing",
 		Created: time.Now(),
 	}
@@ -104,11 +104,11 @@ func TestRegister(t *testing.T) {
 	} else if l := len(images); l != 1 {
 		t.Fatalf("Wrong number of images. Should be %d, not %d", 1, l)
 	}
-	if resultImg, err := graph.Get(image.Id); err != nil {
+	if resultImg, err := graph.Get(image.ID); err != nil {
 		t.Fatal(err)
 	} else {
-		if resultImg.Id != image.Id {
-			t.Fatalf("Wrong image ID. Should be '%s', not '%s'", image.Id, resultImg.Id)
+		if resultImg.ID != image.ID {
+			t.Fatalf("Wrong image ID. Should be '%s', not '%s'", image.ID, resultImg.ID)
 		}
 		if resultImg.Comment != image.Comment {
 			t.Fatalf("Wrong image comment. Should be '%s', not '%s'", image.Comment, resultImg.Comment)
@@ -156,7 +156,7 @@ func TestDeletePrefix(t *testing.T) {
 	graph := tempGraph(t)
 	defer os.RemoveAll(graph.Root)
 	img := createTestImage(graph, t)
-	if err := graph.Delete(utils.TruncateId(img.Id)); err != nil {
+	if err := graph.Delete(utils.TruncateID(img.ID)); err != nil {
 		t.Fatal(err)
 	}
 	assertNImages(graph, t, 0)
@@ -187,7 +187,7 @@ func TestDelete(t *testing.T) {
 		t.Fatal(err)
 	}
 	assertNImages(graph, t, 1)
-	if err := graph.Delete(img.Id); err != nil {
+	if err := graph.Delete(img.ID); err != nil {
 		t.Fatal(err)
 	}
 	assertNImages(graph, t, 0)
@@ -201,7 +201,7 @@ func TestDelete(t *testing.T) {
 		t.Fatal(err)
 	}
 	assertNImages(graph, t, 2)
-	if err := graph.Delete(img1.Id); err != nil {
+	if err := graph.Delete(img1.ID); err != nil {
 		t.Fatal(err)
 	}
 	assertNImages(graph, t, 1)
@@ -216,7 +216,7 @@ func TestDelete(t *testing.T) {
 	if err := graph.Register(archive, false, img1); err != nil {
 		t.Fatal(err)
 	}
-	if err := graph.Delete(img1.Id); err != nil {
+	if err := graph.Delete(img1.ID); err != nil {
 		t.Fatal(err)
 	}
 	assertNImages(graph, t, 1)

+ 15 - 0
hack/PRINCIPLES.md

@@ -0,0 +1,15 @@
+# Docker principles
+
+In the design and development of Docker we try to follow these principles:
+
+(Work in progress)
+
+* Don't try to replace every tool. Instead, be an ingredient to improve them.
+* When hesitating between 2 options, choose the one that is easier to reverse.
+* No is temporary, Yes is forever. If you're not sure about a new feature, say no. You can change your mind later.
+* Containers must be portable to the greatest possible number of machines. Be suspicious of any change which makes machines less interchangeable.
+* The less moving parts in a container, the better.
+* Don't merge it unless you document it.
+* Don't document it unless you can keep it up-to-date.
+* Don't merge it unless you test it!
+* Everyone's problem is slightly different. Focus on the part that is the same for everyone, and solve that.

+ 88 - 0
hack/ROADMAP.md

@@ -0,0 +1,88 @@
+# Docker: what's next?
+
+This document is a high-level overview of where we want to take Docker next.
+It is a curated selection of planned improvements which are either important, difficult, or both.
+
+For a more complete view of planned and requested improvements, see [the Github issues](https://github.com/dotcloud/docker/issues).
+
+Tu suggest changes to the roadmap, including additions, please write the change as if it were already in effect, and make a pull request.
+
+Broader kernel support
+----------------------
+
+Our goal is to make Docker run everywhere, but currently Docker requires [Linux version 3.8 or higher with lxc and aufs support](http://docs.docker.io/en/latest/installation/kernel.html). If you're deploying new machines for the purpose of running Docker, this is a fairly easy requirement to meet.
+However, if you're adding Docker to an existing deployment, you may not have the flexibility to update and patch the kernel.
+
+Expanding Docker's kernel support is a priority. This includes running on older kernel versions,
+but also on kernels with no AUFS support, or with incomplete lxc capabilities.
+
+
+Cross-architecture support
+--------------------------
+
+Our goal is to make Docker run everywhere. However currently Docker only runs on x86_64 systems.
+We plan on expanding architecture support, so that Docker containers can be created and used on more architectures.
+
+
+Even more integrations
+----------------------
+
+We want Docker to be the secret ingredient that makes your existing tools more awesome.
+Thanks to this philosophy, Docker has already been integrated with
+[Puppet](http://forge.puppetlabs.com/garethr/docker),  [Chef](http://www.opscode.com/chef),
+[Openstack Nova](https://github.com/dotcloud/openstack-docker), [Jenkins](https://github.com/georgebashi/jenkins-docker-plugin),
+[DotCloud sandbox](http://github.com/dotcloud/sandbox), [Pallet](https://github.com/pallet/pallet-docker),
+[Strider CI](http://blog.frozenridge.co/next-generation-continuous-integration-deployment-with-dotclouds-docker-and-strider/)
+and even [Heroku buildpacks](https://github.com/progrium/buildstep).
+
+Expect Docker to integrate with even more of your favorite tools going forward, including:
+
+* Alternative storage backends such as ZFS, LVM or [BTRFS](github.com/dotcloud/docker/issues/443)
+* Alternative containerization backends such as [OpenVZ](http://openvz.org), Solaris Zones, BSD Jails and even plain Chroot.
+* Process managers like [Supervisord](http://supervisord.org/), [Runit](http://smarden.org/runit/), [Gaffer](https://gaffer.readthedocs.org/en/latest/#gaffer) and [Systemd](http://www.freedesktop.org/wiki/Software/systemd/)
+* Build and integration tools like Make, Maven, Scons, Jenkins, Buildbot and Cruise Control.
+* Configuration management tools like [Puppet](http://puppetlabs.com), [Chef](http://www.opscode.com/chef/) and [Salt](http://saltstack.org)
+* Personal development environments like [Vagrant](http://vagrantup.com), [Boxen](http://boxen.github.com/), [Koding](http://koding.com) and [Cloud9](http://c9.io).
+* Orchestration tools like [Zookeeper](http://zookeeper.apache.org/), [Mesos](http://incubator.apache.org/mesos/) and [Galaxy](https://github.com/ning/galaxy)
+* Infrastructure deployment tools like [Openstack](http://openstack.org), [Apache Cloudstack](http://apache.cloudstack.org), [Ganeti](https://code.google.com/p/ganeti/)
+
+
+Plugin API
+----------
+
+We want Docker to run everywhere, and to integrate with every devops tool.
+Those are ambitious goals, and the only way to reach them is with the Docker community.
+For the community to participate fully, we need an API which allows Docker to be deeply and easily customized.
+
+We are working on a plugin API which will make Docker very, very customization-friendly.
+We believe it will facilitate the integrations listed above - and many more we didn't even think about.
+
+Let us know if you want to start playing with the API before it's generally available.
+
+
+Externally mounted volumes
+--------------------------
+
+In 0.3 we [introduced data volumes](https://github.com/dotcloud/docker/wiki/Docker-0.3.0-release-note%2C-May-6-2013#data-volumes),
+a great mechanism for manipulating persistent data such as database files, log files, etc.
+
+Data volumes can be shared between containers, a powerful capability [which allows many advanced use cases](http://docs.docker.io/en/latest/examples/couchdb_data_volumes.html). In the future it will also be possible to share volumes between a container and the underlying host. This will make certain scenarios much easier, such as using a high-performance storage backend for your production database,
+making live development changes available to a container, etc.
+
+
+Better documentation
+--------------------
+
+We believe that great documentation is worth 10 features. We are often told that "Docker's documentation is great for a 2-month old project".
+Our goal is to make it great, period.
+
+If you have feedback on how to improve our documentation, please get in touch by replying to this email,
+or by [filing an issue](https://github.com/dotcloud/docker/issues). We always appreciate it!
+
+
+Production-ready
+----------------
+
+Docker is still alpha software, and not suited for production.
+We are working hard to get there, and we are confident that it will be possible within a few months.
+

+ 1 - 0
hack/dockerbuilder/MAITAINERS

@@ -0,0 +1 @@
+Daniel Mizyrycki <daniel@dotcloud.com>

+ 17 - 18
image.go

@@ -18,7 +18,7 @@ import (
 )
 
 type Image struct {
-	Id              string    `json:"id"`
+	ID              string    `json:"id"`
 	Parent          string    `json:"parent,omitempty"`
 	Comment         string    `json:"comment,omitempty"`
 	Created         time.Time `json:"created"`
@@ -42,18 +42,17 @@ func LoadImage(root string) (*Image, error) {
 	if err := json.Unmarshal(jsonData, img); err != nil {
 		return nil, err
 	}
-	if err := ValidateId(img.Id); err != nil {
+	if err := ValidateID(img.ID); err != nil {
 		return nil, err
 	}
 	// Check that the filesystem layer exists
 	if stat, err := os.Stat(layerPath(root)); err != nil {
 		if os.IsNotExist(err) {
-			return nil, fmt.Errorf("Couldn't load image %s: no filesystem layer", img.Id)
-		} else {
-			return nil, err
+			return nil, fmt.Errorf("Couldn't load image %s: no filesystem layer", img.ID)
 		}
+		return nil, err
 	} else if !stat.IsDir() {
-		return nil, fmt.Errorf("Couldn't load image %s: %s is not a directory", img.Id, layerPath(root))
+		return nil, fmt.Errorf("Couldn't load image %s: %s is not a directory", img.ID, layerPath(root))
 	}
 	return img, nil
 }
@@ -61,7 +60,7 @@ func LoadImage(root string) (*Image, error) {
 func StoreImage(img *Image, layerData Archive, root string, store bool) error {
 	// Check that root doesn't already exist
 	if _, err := os.Stat(root); err == nil {
-		return fmt.Errorf("Image %s already exists", img.Id)
+		return fmt.Errorf("Image %s already exists", img.ID)
 	} else if !os.IsNotExist(err) {
 		return err
 	}
@@ -181,11 +180,11 @@ func (image *Image) Changes(rw string) ([]Change, error) {
 	return Changes(layers, rw)
 }
 
-func (image *Image) ShortId() string {
-	return utils.TruncateId(image.Id)
+func (image *Image) ShortID() string {
+	return utils.TruncateID(image.ID)
 }
 
-func ValidateId(id string) error {
+func ValidateID(id string) error {
 	if id == "" {
 		return fmt.Errorf("Image id can't be empty")
 	}
@@ -195,7 +194,7 @@ func ValidateId(id string) error {
 	return nil
 }
 
-func GenerateId() string {
+func GenerateID() string {
 	id := make([]byte, 32)
 	_, err := io.ReadFull(rand.Reader, id)
 	if err != nil {
@@ -241,7 +240,7 @@ func (img *Image) layers() ([]string, error) {
 		return nil, e
 	}
 	if len(list) == 0 {
-		return nil, fmt.Errorf("No layer found for image %s\n", img.Id)
+		return nil, fmt.Errorf("No layer found for image %s\n", img.ID)
 	}
 	return list, nil
 }
@@ -276,7 +275,7 @@ func (img *Image) root() (string, error) {
 	if img.graph == nil {
 		return "", fmt.Errorf("Can't lookup root of unregistered image")
 	}
-	return img.graph.imageRoot(img.Id), nil
+	return img.graph.imageRoot(img.ID), nil
 }
 
 // Return the path of an image's layer
@@ -289,8 +288,8 @@ func (img *Image) layer() (string, error) {
 }
 
 func (img *Image) Checksum() (string, error) {
-	img.graph.checksumLock[img.Id].Lock()
-	defer img.graph.checksumLock[img.Id].Unlock()
+	img.graph.checksumLock[img.ID].Lock()
+	defer img.graph.checksumLock[img.ID].Unlock()
 
 	root, err := img.root()
 	if err != nil {
@@ -301,7 +300,7 @@ func (img *Image) Checksum() (string, error) {
 	if err != nil {
 		return "", err
 	}
-	if checksum, ok := checksums[img.Id]; ok {
+	if checksum, ok := checksums[img.ID]; ok {
 		return checksum, nil
 	}
 
@@ -352,7 +351,7 @@ func (img *Image) Checksum() (string, error) {
 		return "", err
 	}
 
-	checksums[img.Id] = hash
+	checksums[img.ID] = hash
 
 	// Dump the checksums to disc
 	if err := img.graph.storeChecksums(checksums); err != nil {
@@ -363,7 +362,7 @@ func (img *Image) Checksum() (string, error) {
 }
 
 // Build an Image object from raw json data
-func NewImgJson(src []byte) (*Image, error) {
+func NewImgJSON(src []byte) (*Image, error) {
 	ret := &Image{}
 
 	utils.Debugf("Json string: {%s}\n", src)

+ 1 - 1
lxc_template.go

@@ -19,7 +19,7 @@ lxc.network.flags = up
 lxc.network.link = {{.NetworkSettings.Bridge}}
 lxc.network.name = eth0
 lxc.network.mtu = 1500
-lxc.network.ipv4 = {{.NetworkSettings.IpAddress}}/{{.NetworkSettings.IpPrefixLen}}
+lxc.network.ipv4 = {{.NetworkSettings.IPAddress}}/{{.NetworkSettings.IPPrefixLen}}
 
 # root filesystem
 {{$ROOTFS := .RootfsPath}}

+ 7 - 8
network.go

@@ -52,7 +52,7 @@ func ipToInt(ip net.IP) int32 {
 }
 
 // Converts 32 bit integer into a 4 bytes IP address
-func intToIp(n int32) net.IP {
+func intToIP(n int32) net.IP {
 	b := make([]byte, 4)
 	binary.BigEndian.PutUint32(b, uint32(n))
 	return net.IP(b)
@@ -132,9 +132,8 @@ func CreateBridgeIface(ifaceName string) error {
 	}
 	if ifaceAddr == "" {
 		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)
-	} else {
-		utils.Debugf("Creating bridge %s with network %s", ifaceName, ifaceAddr)
 	}
+	utils.Debugf("Creating bridge %s with network %s", ifaceName, ifaceAddr)
 
 	if output, err := ip("link", "add", ifaceName, "type", "bridge"); err != nil {
 		return fmt.Errorf("Error creating bridge: %s (output: %s)", err, output)
@@ -258,7 +257,7 @@ func proxy(listener net.Listener, proto, address string) error {
 		utils.Debugf("Connected to backend, splicing")
 		splice(src, dst)
 	}
-	return nil
+	panic("Unreachable")
 }
 
 func halfSplice(dst, src net.Conn) error {
@@ -398,7 +397,7 @@ func (alloc *IPAllocator) run() {
 			}
 		}
 
-		ip := allocatedIP{ip: intToIp(newNum)}
+		ip := allocatedIP{ip: intToIP(newNum)}
 		if inUse {
 			ip.err = errors.New("No unallocated IP available")
 		}
@@ -465,11 +464,11 @@ func (iface *NetworkInterface) AllocatePort(spec string) (*Nat, error) {
 		return nil, err
 	}
 	// Allocate a random port if Frontend==0
-	if extPort, err := iface.manager.portAllocator.Acquire(nat.Frontend); err != nil {
+	extPort, err := iface.manager.portAllocator.Acquire(nat.Frontend)
+	if err != nil {
 		return nil, err
-	} else {
-		nat.Frontend = extPort
 	}
+	nat.Frontend = extPort
 	if err := iface.manager.portMapper.Map(nat.Frontend, net.TCPAddr{IP: iface.IPNet.IP, Port: nat.Backend}); err != nil {
 		iface.manager.portAllocator.Release(nat.Frontend)
 		return nil, err

+ 1 - 1
network_test.go

@@ -137,7 +137,7 @@ func TestConversion(t *testing.T) {
 	if i == 0 {
 		t.Fatal("converted to zero")
 	}
-	conv := intToIp(i)
+	conv := intToIP(i)
 	if !ip.Equal(conv) {
 		t.Error(conv.String())
 	}

+ 7 - 0
packaging/ubuntu/changelog

@@ -1,3 +1,10 @@
+lxc-docker (0.4.0-1) precise; urgency=low
+  - Introducing Builder: 'docker build' builds a container, layer by layer, from a source repository containing a Dockerfile
+  - Introducing Remote API: control Docker programmatically using a simple HTTP/json API
+  - Runtime: various reliability and usability improvements
+
+ -- dotCloud <ops@dotcloud.com>  Mon, 03 Jun 2013 00:00:00 -0700
+
 lxc-docker (0.3.4-1) precise; urgency=low
   - Builder: 'docker build' builds a container, layer by layer, from a source repository containing a Dockerfile
   - Builder: 'docker build -t FOO' applies the tag FOO to the newly built container.

+ 41 - 27
registry/registry.go

@@ -15,7 +15,7 @@ import (
 	"strings"
 )
 
-var ErrAlreadyExists error = errors.New("Image already exists")
+var ErrAlreadyExists = errors.New("Image already exists")
 
 func doWithCookies(c *http.Client, req *http.Request) (*http.Response, error) {
 	for _, cookie := range c.Jar.Cookies(req.URL) {
@@ -64,7 +64,11 @@ func (r *Registry) LookupRemoteImage(imgId, registry string, authConfig *auth.Au
 	}
 	req.SetBasicAuth(authConfig.Username, authConfig.Password)
 	res, err := rt.RoundTrip(req)
-	return err == nil && res.StatusCode == 307
+	if err != nil {
+		return false
+	}
+	res.Body.Close()
+	return res.StatusCode == 307
 }
 
 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
 
 // Retrieve an image from the Registry.
 // Returns the Image object as well as the layer as an Archive (io.Reader)
-func (r *Registry) GetRemoteImageJson(imgId, registry string, token []string) ([]byte, error) {
-	// Get the Json
+func (r *Registry) GetRemoteImageJSON(imgId, registry string, token []string) ([]byte, error) {
+	// Get the JSON
 	req, err := http.NewRequest("GET", registry+"/images/"+imgId+"/json", nil)
 	if err != nil {
 		return nil, fmt.Errorf("Failed to download json: %s", err)
@@ -152,21 +156,24 @@ func (r *Registry) GetRemoteTags(registries []string, repository string, token [
 		}
 		req.Header.Set("Authorization", "Token "+strings.Join(token, ", "))
 		res, err := r.client.Do(req)
-		defer res.Body.Close()
 		utils.Debugf("Got status code %d from %s", res.StatusCode, endpoint)
-		if err != nil || (res.StatusCode != 200 && res.StatusCode != 404) {
+		if err != nil {
+			return nil, err
+		}
+		defer res.Body.Close()
+
+		if res.StatusCode != 200 && res.StatusCode != 404 {
 			continue
 		} else if res.StatusCode == 404 {
 			return nil, fmt.Errorf("Repository not found")
 		}
 
 		result := make(map[string]string)
-
-		rawJson, err := ioutil.ReadAll(res.Body)
+		rawJSON, err := ioutil.ReadAll(res.Body)
 		if err != nil {
 			return nil, err
 		}
-		if err := json.Unmarshal(rawJson, &result); err != nil {
+		if err := json.Unmarshal(rawJSON, &result); err != nil {
 			return nil, err
 		}
 		return result, nil
@@ -212,19 +219,19 @@ func (r *Registry) GetRepositoryData(remote string) (*RepositoryData, error) {
 		return nil, fmt.Errorf("Index response didn't contain any endpoints")
 	}
 
-	checksumsJson, err := ioutil.ReadAll(res.Body)
+	checksumsJSON, err := ioutil.ReadAll(res.Body)
 	if err != nil {
 		return nil, err
 	}
 	remoteChecksums := []*ImgData{}
-	if err := json.Unmarshal(checksumsJson, &remoteChecksums); err != nil {
+	if err := json.Unmarshal(checksumsJSON, &remoteChecksums); err != nil {
 		return nil, err
 	}
 
 	// Forge a better object from the retrieved data
 	imgsData := make(map[string]*ImgData)
 	for _, elem := range remoteChecksums {
-		imgsData[elem.Id] = elem
+		imgsData[elem.ID] = elem
 	}
 
 	return &RepositoryData{
@@ -235,10 +242,10 @@ func (r *Registry) GetRepositoryData(remote string) (*RepositoryData, error) {
 }
 
 // Push a local image to the registry
-func (r *Registry) PushImageJsonRegistry(imgData *ImgData, jsonRaw []byte, registry string, token []string) error {
+func (r *Registry) PushImageJSONRegistry(imgData *ImgData, jsonRaw []byte, registry string, token []string) error {
 	registry = "https://" + registry + "/v1"
 	// FIXME: try json with UTF8
-	req, err := http.NewRequest("PUT", registry+"/images/"+imgData.Id+"/json", strings.NewReader(string(jsonRaw)))
+	req, err := http.NewRequest("PUT", registry+"/images/"+imgData.ID+"/json", strings.NewReader(string(jsonRaw)))
 	if err != nil {
 		return err
 	}
@@ -246,7 +253,7 @@ func (r *Registry) PushImageJsonRegistry(imgData *ImgData, jsonRaw []byte, regis
 	req.Header.Set("Authorization", "Token "+strings.Join(token, ","))
 	req.Header.Set("X-Docker-Checksum", imgData.Checksum)
 
-	utils.Debugf("Setting checksum for %s: %s", imgData.Id, imgData.Checksum)
+	utils.Debugf("Setting checksum for %s: %s", imgData.ID, imgData.Checksum)
 	res, err := doWithCookies(r.client, req)
 	if err != nil {
 		return fmt.Errorf("Failed to upload metadata: %s", err)
@@ -321,8 +328,8 @@ func (r *Registry) PushRegistryTag(remote, revision, tag, registry string, token
 	return nil
 }
 
-func (r *Registry) PushImageJsonIndex(remote string, imgList []*ImgData, validate bool) (*RepositoryData, error) {
-	imgListJson, err := json.Marshal(imgList)
+func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validate bool) (*RepositoryData, error) {
+	imgListJSON, err := json.Marshal(imgList)
 	if err != nil {
 		return nil, err
 	}
@@ -331,14 +338,14 @@ func (r *Registry) PushImageJsonIndex(remote string, imgList []*ImgData, validat
 		suffix = "images"
 	}
 
-	utils.Debugf("Image list pushed to index:\n%s\n", imgListJson)
+	utils.Debugf("Image list pushed to index:\n%s\n", imgListJSON)
 
-	req, err := http.NewRequest("PUT", auth.IndexServerAddress()+"/repositories/"+remote+"/"+suffix, bytes.NewReader(imgListJson))
+	req, err := http.NewRequest("PUT", auth.IndexServerAddress()+"/repositories/"+remote+"/"+suffix, bytes.NewReader(imgListJSON))
 	if err != nil {
 		return nil, err
 	}
 	req.SetBasicAuth(r.authConfig.Username, r.authConfig.Password)
-	req.ContentLength = int64(len(imgListJson))
+	req.ContentLength = int64(len(imgListJSON))
 	req.Header.Set("X-Docker-Token", "true")
 
 	res, err := r.client.Do(req)
@@ -350,12 +357,12 @@ func (r *Registry) PushImageJsonIndex(remote string, imgList []*ImgData, validat
 	// Redirect if necessary
 	for res.StatusCode >= 300 && res.StatusCode < 400 {
 		utils.Debugf("Redirected to %s\n", res.Header.Get("Location"))
-		req, err = http.NewRequest("PUT", res.Header.Get("Location"), bytes.NewReader(imgListJson))
+		req, err = http.NewRequest("PUT", res.Header.Get("Location"), bytes.NewReader(imgListJSON))
 		if err != nil {
 			return nil, err
 		}
 		req.SetBasicAuth(r.authConfig.Username, r.authConfig.Password)
-		req.ContentLength = int64(len(imgListJson))
+		req.ContentLength = int64(len(imgListJSON))
 		req.Header.Set("X-Docker-Token", "true")
 
 		res, err = r.client.Do(req)
@@ -389,11 +396,11 @@ func (r *Registry) PushImageJsonIndex(remote string, imgList []*ImgData, validat
 	}
 	if validate {
 		if res.StatusCode != 204 {
-			if errBody, err := ioutil.ReadAll(res.Body); err != nil {
+			errBody, err := ioutil.ReadAll(res.Body)
+			if err != nil {
 				return nil, err
-			} else {
-				return nil, fmt.Errorf("Error: Status %d trying to push checksums %s: %s", res.StatusCode, remote, errBody)
 			}
+			return nil, fmt.Errorf("Error: Status %d trying to push checksums %s: %s", res.StatusCode, remote, errBody)
 		}
 	}
 
@@ -456,7 +463,7 @@ type RepositoryData struct {
 }
 
 type ImgData struct {
-	Id       string `json:"id"`
+	ID       string `json:"id"`
 	Checksum string `json:"checksum,omitempty"`
 	Tag      string `json:",omitempty"`
 }
@@ -470,9 +477,16 @@ func NewRegistry(root string) *Registry {
 	// If the auth file does not exist, keep going
 	authConfig, _ := auth.LoadConfig(root)
 
+	httpTransport := &http.Transport{
+		DisableKeepAlives: true,
+		Proxy: http.ProxyFromEnvironment,
+	}
+
 	r := &Registry{
 		authConfig: authConfig,
-		client:     &http.Client{},
+		client: &http.Client{
+			Transport: httpTransport,
+		},
 	}
 	r.client.Jar = cookiejar.NewCookieJar()
 	return r

+ 31 - 31
runtime.go

@@ -51,7 +51,7 @@ func (runtime *Runtime) List() []*Container {
 func (runtime *Runtime) getContainerElement(id string) *list.Element {
 	for e := runtime.containers.Front(); e != nil; e = e.Next() {
 		container := e.Value.(*Container)
-		if container.Id == id {
+		if container.ID == id {
 			return e
 		}
 	}
@@ -83,8 +83,8 @@ func (runtime *Runtime) Load(id string) (*Container, error) {
 	if err := container.FromDisk(); err != nil {
 		return nil, err
 	}
-	if container.Id != id {
-		return container, fmt.Errorf("Container %s is stored at %s", container.Id, id)
+	if container.ID != id {
+		return container, fmt.Errorf("Container %s is stored at %s", container.ID, id)
 	}
 	if container.State.Running {
 		container.State.Ghost = true
@@ -95,12 +95,12 @@ func (runtime *Runtime) Load(id string) (*Container, error) {
 	return container, nil
 }
 
-// Register makes a container object usable by the runtime as <container.Id>
+// Register makes a container object usable by the runtime as <container.ID>
 func (runtime *Runtime) Register(container *Container) error {
-	if container.runtime != nil || runtime.Exists(container.Id) {
+	if container.runtime != nil || runtime.Exists(container.ID) {
 		return fmt.Errorf("Container is already loaded")
 	}
-	if err := validateId(container.Id); err != nil {
+	if err := validateID(container.ID); err != nil {
 		return err
 	}
 
@@ -123,7 +123,7 @@ func (runtime *Runtime) Register(container *Container) error {
 	}
 	// done
 	runtime.containers.PushBack(container)
-	runtime.idIndex.Add(container.Id)
+	runtime.idIndex.Add(container.ID)
 
 	// When we actually restart, Start() do the monitoring.
 	// However, when we simply 'reattach', we have to restart a monitor
@@ -133,25 +133,25 @@ func (runtime *Runtime) Register(container *Container) error {
 	//        if so, then we need to restart monitor and init a new lock
 	// If the container is supposed to be running, make sure of it
 	if container.State.Running {
-		if output, err := exec.Command("lxc-info", "-n", container.Id).CombinedOutput(); err != nil {
+		output, err := exec.Command("lxc-info", "-n", container.ID).CombinedOutput()
+		if err != nil {
 			return err
-		} else {
-			if !strings.Contains(string(output), "RUNNING") {
-				utils.Debugf("Container %s was supposed to be running be is not.", container.Id)
-				if runtime.autoRestart {
-					utils.Debugf("Restarting")
-					container.State.Ghost = false
-					container.State.setStopped(0)
-					if err := container.Start(); err != nil {
-						return err
-					}
-					nomonitor = true
-				} else {
-					utils.Debugf("Marking as stopped")
-					container.State.setStopped(-127)
-					if err := container.ToDisk(); err != nil {
-						return err
-					}
+		}
+		if !strings.Contains(string(output), "RUNNING") {
+			utils.Debugf("Container %s was supposed to be running be is not.", container.ID)
+			if runtime.autoRestart {
+				utils.Debugf("Restarting")
+				container.State.Ghost = false
+				container.State.setStopped(0)
+				if err := container.Start(); err != nil {
+					return err
+				}
+				nomonitor = true
+			} else {
+				utils.Debugf("Marking as stopped")
+				container.State.setStopped(-127)
+				if err := container.ToDisk(); err != nil {
+					return err
 				}
 			}
 		}
@@ -182,9 +182,9 @@ func (runtime *Runtime) Destroy(container *Container) error {
 		return fmt.Errorf("The given container is <nil>")
 	}
 
-	element := runtime.getContainerElement(container.Id)
+	element := runtime.getContainerElement(container.ID)
 	if element == nil {
-		return fmt.Errorf("Container %v not found - maybe it was already destroyed?", container.Id)
+		return fmt.Errorf("Container %v not found - maybe it was already destroyed?", container.ID)
 	}
 
 	if err := container.Stop(3); err != nil {
@@ -194,14 +194,14 @@ func (runtime *Runtime) Destroy(container *Container) error {
 		return err
 	} else if mounted {
 		if err := container.Unmount(); err != nil {
-			return fmt.Errorf("Unable to unmount container %v: %v", container.Id, err)
+			return fmt.Errorf("Unable to unmount container %v: %v", container.ID, err)
 		}
 	}
 	// Deregister the container before removing its directory, to avoid race conditions
-	runtime.idIndex.Delete(container.Id)
+	runtime.idIndex.Delete(container.ID)
 	runtime.containers.Remove(element)
 	if err := os.RemoveAll(container.root); err != nil {
-		return fmt.Errorf("Unable to remove filesystem for %v: %v", container.Id, err)
+		return fmt.Errorf("Unable to remove filesystem for %v: %v", container.ID, err)
 	}
 	return nil
 }
@@ -218,7 +218,7 @@ func (runtime *Runtime) restore() error {
 			utils.Debugf("Failed to load container %v: %v", id, err)
 			continue
 		}
-		utils.Debugf("Loaded container %v", container.Id)
+		utils.Debugf("Loaded container %v", container.ID)
 	}
 	return nil
 }

+ 25 - 25
runtime_test.go

@@ -120,7 +120,7 @@ func TestRuntimeCreate(t *testing.T) {
 	builder := NewBuilder(runtime)
 
 	container, err := builder.Create(&Config{
-		Image: GetTestImage(runtime).Id,
+		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"ls", "-al"},
 	},
 	)
@@ -140,29 +140,29 @@ func TestRuntimeCreate(t *testing.T) {
 	}
 
 	// Make sure the container List() returns is the right one
-	if runtime.List()[0].Id != container.Id {
+	if runtime.List()[0].ID != container.ID {
 		t.Errorf("Unexpected container %v returned by List", runtime.List()[0])
 	}
 
 	// Make sure we can get the container with Get()
-	if runtime.Get(container.Id) == nil {
+	if runtime.Get(container.ID) == nil {
 		t.Errorf("Unable to get newly created container")
 	}
 
 	// Make sure it is the right container
-	if runtime.Get(container.Id) != container {
+	if runtime.Get(container.ID) != container {
 		t.Errorf("Get() returned the wrong container")
 	}
 
 	// Make sure Exists returns it as existing
-	if !runtime.Exists(container.Id) {
+	if !runtime.Exists(container.ID) {
 		t.Errorf("Exists() returned false for a newly created container")
 	}
 
 	// Make sure crete with bad parameters returns an error
 	_, err = builder.Create(
 		&Config{
-			Image: GetTestImage(runtime).Id,
+			Image: GetTestImage(runtime).ID,
 		},
 	)
 	if err == nil {
@@ -171,7 +171,7 @@ func TestRuntimeCreate(t *testing.T) {
 
 	_, err = builder.Create(
 		&Config{
-			Image: GetTestImage(runtime).Id,
+			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{},
 		},
 	)
@@ -187,7 +187,7 @@ func TestDestroy(t *testing.T) {
 	}
 	defer nuke(runtime)
 	container, err := NewBuilder(runtime).Create(&Config{
-		Image: GetTestImage(runtime).Id,
+		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"ls", "-al"},
 	},
 	)
@@ -210,7 +210,7 @@ func TestDestroy(t *testing.T) {
 	}
 
 	// Make sure runtime.Get() refuses to return the unexisting container
-	if runtime.Get(container.Id) != nil {
+	if runtime.Get(container.ID) != nil {
 		t.Errorf("Unable to get newly created container")
 	}
 
@@ -237,7 +237,7 @@ func TestGet(t *testing.T) {
 	builder := NewBuilder(runtime)
 
 	container1, err := builder.Create(&Config{
-		Image: GetTestImage(runtime).Id,
+		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"ls", "-al"},
 	},
 	)
@@ -247,7 +247,7 @@ func TestGet(t *testing.T) {
 	defer runtime.Destroy(container1)
 
 	container2, err := builder.Create(&Config{
-		Image: GetTestImage(runtime).Id,
+		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"ls", "-al"},
 	},
 	)
@@ -257,7 +257,7 @@ func TestGet(t *testing.T) {
 	defer runtime.Destroy(container2)
 
 	container3, err := builder.Create(&Config{
-		Image: GetTestImage(runtime).Id,
+		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"ls", "-al"},
 	},
 	)
@@ -266,16 +266,16 @@ func TestGet(t *testing.T) {
 	}
 	defer runtime.Destroy(container3)
 
-	if runtime.Get(container1.Id) != container1 {
-		t.Errorf("Get(test1) returned %v while expecting %v", runtime.Get(container1.Id), container1)
+	if runtime.Get(container1.ID) != container1 {
+		t.Errorf("Get(test1) returned %v while expecting %v", runtime.Get(container1.ID), container1)
 	}
 
-	if runtime.Get(container2.Id) != container2 {
-		t.Errorf("Get(test2) returned %v while expecting %v", runtime.Get(container2.Id), container2)
+	if runtime.Get(container2.ID) != container2 {
+		t.Errorf("Get(test2) returned %v while expecting %v", runtime.Get(container2.ID), container2)
 	}
 
-	if runtime.Get(container3.Id) != container3 {
-		t.Errorf("Get(test3) returned %v while expecting %v", runtime.Get(container3.Id), container3)
+	if runtime.Get(container3.ID) != container3 {
+		t.Errorf("Get(test3) returned %v while expecting %v", runtime.Get(container3.ID), container3)
 	}
 
 }
@@ -283,7 +283,7 @@ func TestGet(t *testing.T) {
 func findAvailalblePort(runtime *Runtime, port int) (*Container, error) {
 	strPort := strconv.Itoa(port)
 	container, err := NewBuilder(runtime).Create(&Config{
-		Image:     GetTestImage(runtime).Id,
+		Image:     GetTestImage(runtime).ID,
 		Cmd:       []string{"sh", "-c", "echo well hello there | nc -l -p " + strPort},
 		PortSpecs: []string{strPort},
 	},
@@ -379,7 +379,7 @@ func TestRestore(t *testing.T) {
 
 	// Create a container with one instance of docker
 	container1, err := builder.Create(&Config{
-		Image: GetTestImage(runtime1).Id,
+		Image: GetTestImage(runtime1).ID,
 		Cmd:   []string{"ls", "-al"},
 	},
 	)
@@ -390,7 +390,7 @@ func TestRestore(t *testing.T) {
 
 	// Create a second container meant to be killed
 	container2, err := builder.Create(&Config{
-		Image:     GetTestImage(runtime1).Id,
+		Image:     GetTestImage(runtime1).ID,
 		Cmd:       []string{"/bin/cat"},
 		OpenStdin: true,
 	},
@@ -406,7 +406,7 @@ func TestRestore(t *testing.T) {
 	}
 
 	if !container2.State.Running {
-		t.Fatalf("Container %v should appear as running but isn't", container2.Id)
+		t.Fatalf("Container %v should appear as running but isn't", container2.ID)
 	}
 
 	// Simulate a crash/manual quit of dockerd: process dies, states stays 'Running'
@@ -426,7 +426,7 @@ func TestRestore(t *testing.T) {
 	}
 
 	if !container2.State.Running {
-		t.Fatalf("Container %v should appear as running but isn't", container2.Id)
+		t.Fatalf("Container %v should appear as running but isn't", container2.ID)
 	}
 
 	// Here are are simulating a docker restart - that is, reloading all containers
@@ -442,14 +442,14 @@ func TestRestore(t *testing.T) {
 	runningCount := 0
 	for _, c := range runtime2.List() {
 		if c.State.Running {
-			t.Errorf("Running container found: %v (%v)", c.Id, c.Path)
+			t.Errorf("Running container found: %v (%v)", c.ID, c.Path)
 			runningCount++
 		}
 	}
 	if runningCount != 0 {
 		t.Fatalf("Expected 0 container alive, %d found", runningCount)
 	}
-	container3 := runtime2.Get(container1.Id)
+	container3 := runtime2.Get(container1.ID)
 	if container3 == nil {
 		t.Fatal("Unable to Get container")
 	}

+ 100 - 88
server.go

@@ -17,8 +17,12 @@ import (
 	"strings"
 )
 
-func (srv *Server) DockerVersion() ApiVersion {
-	return ApiVersion{VERSION, GIT_COMMIT, srv.runtime.capabilities.MemoryLimit, srv.runtime.capabilities.SwapLimit}
+func (srv *Server) DockerVersion() APIVersion {
+	return APIVersion{
+		Version:   VERSION,
+		GitCommit: GITCOMMIT,
+		GoVersion: runtime.Version(),
+	}
 }
 
 func (srv *Server) ContainerKill(name string) error {
@@ -49,16 +53,16 @@ func (srv *Server) ContainerExport(name string, out io.Writer) error {
 	return fmt.Errorf("No such container: %s", name)
 }
 
-func (srv *Server) ImagesSearch(term string) ([]ApiSearch, error) {
+func (srv *Server) ImagesSearch(term string) ([]APISearch, error) {
 
 	results, err := registry.NewRegistry(srv.runtime.root).SearchRepositories(term)
 	if err != nil {
 		return nil, err
 	}
 
-	var outs []ApiSearch
+	var outs []APISearch
 	for _, repo := range results.Results {
-		var out ApiSearch
+		var out APISearch
 		out.Description = repo["description"]
 		if len(out.Description) > 45 {
 			out.Description = utils.Trunc(out.Description, 42) + "..."
@@ -82,7 +86,7 @@ func (srv *Server) ImageInsert(name, url, path string, out io.Writer, sf *utils.
 	}
 	defer file.Body.Close()
 
-	config, _, err := ParseRun([]string{img.Id, "echo", "insert", url, path}, srv.runtime.capabilities)
+	config, _, err := ParseRun([]string{img.ID, "echo", "insert", url, path}, srv.runtime.capabilities)
 	if err != nil {
 		return "", err
 	}
@@ -101,8 +105,8 @@ func (srv *Server) ImageInsert(name, url, path string, out io.Writer, sf *utils.
 	if err != nil {
 		return "", err
 	}
-	out.Write(sf.FormatStatus(img.Id))
-	return img.ShortId(), nil
+	out.Write(sf.FormatStatus(img.ID))
+	return img.ShortID(), nil
 }
 
 func (srv *Server) ImagesViz(out io.Writer) error {
@@ -122,9 +126,9 @@ func (srv *Server) ImagesViz(out io.Writer) error {
 			return fmt.Errorf("Error while getting parent image: %v", err)
 		}
 		if parentImage != nil {
-			out.Write([]byte(" \"" + parentImage.ShortId() + "\" -> \"" + image.ShortId() + "\"\n"))
+			out.Write([]byte(" \"" + parentImage.ShortID() + "\" -> \"" + image.ShortID() + "\"\n"))
 		} else {
-			out.Write([]byte(" base -> \"" + image.ShortId() + "\" [style=invis]\n"))
+			out.Write([]byte(" base -> \"" + image.ShortID() + "\" [style=invis]\n"))
 		}
 	}
 
@@ -132,7 +136,7 @@ func (srv *Server) ImagesViz(out io.Writer) error {
 
 	for name, repository := range srv.runtime.repositories.Repositories {
 		for tag, id := range repository {
-			reporefs[utils.TruncateId(id)] = append(reporefs[utils.TruncateId(id)], fmt.Sprintf("%s:%s", name, tag))
+			reporefs[utils.TruncateID(id)] = append(reporefs[utils.TruncateID(id)], fmt.Sprintf("%s:%s", name, tag))
 		}
 	}
 
@@ -143,7 +147,7 @@ func (srv *Server) ImagesViz(out io.Writer) error {
 	return nil
 }
 
-func (srv *Server) Images(all bool, filter string) ([]ApiImages, error) {
+func (srv *Server) Images(all bool, filter string) ([]APIImages, error) {
 	var (
 		allImages map[string]*Image
 		err       error
@@ -156,13 +160,13 @@ func (srv *Server) Images(all bool, filter string) ([]ApiImages, error) {
 	if err != nil {
 		return nil, err
 	}
-	outs := []ApiImages{} //produce [] when empty instead of 'null'
+	outs := []APIImages{} //produce [] when empty instead of 'null'
 	for name, repository := range srv.runtime.repositories.Repositories {
 		if filter != "" && name != filter {
 			continue
 		}
 		for tag, id := range repository {
-			var out ApiImages
+			var out APIImages
 			image, err := srv.runtime.graph.Get(id)
 			if err != nil {
 				log.Printf("Warning: couldn't load %s from %s/%s: %s", id, name, tag, err)
@@ -171,7 +175,7 @@ func (srv *Server) Images(all bool, filter string) ([]ApiImages, error) {
 			delete(allImages, id)
 			out.Repository = name
 			out.Tag = tag
-			out.Id = image.Id
+			out.ID = image.ID
 			out.Created = image.Created.Unix()
 			outs = append(outs, out)
 		}
@@ -179,8 +183,8 @@ func (srv *Server) Images(all bool, filter string) ([]ApiImages, error) {
 	// Display images which aren't part of a
 	if filter == "" {
 		for _, image := range allImages {
-			var out ApiImages
-			out.Id = image.Id
+			var out APIImages
+			out.ID = image.ID
 			out.Created = image.Created.Unix()
 			outs = append(outs, out)
 		}
@@ -188,7 +192,7 @@ func (srv *Server) Images(all bool, filter string) ([]ApiImages, error) {
 	return outs, nil
 }
 
-func (srv *Server) DockerInfo() ApiInfo {
+func (srv *Server) DockerInfo() *APIInfo {
 	images, _ := srv.runtime.graph.All()
 	var imgcount int
 	if images == nil {
@@ -196,29 +200,27 @@ func (srv *Server) DockerInfo() ApiInfo {
 	} else {
 		imgcount = len(images)
 	}
-	var out ApiInfo
-	out.Containers = len(srv.runtime.List())
-	out.Version = VERSION
-	out.Images = imgcount
-	out.GoVersion = runtime.Version()
-	if os.Getenv("DEBUG") != "" {
-		out.Debug = true
-		out.NFd = utils.GetTotalUsedFds()
-		out.NGoroutines = runtime.NumGoroutine()
+	return &APIInfo{
+		Containers:  len(srv.runtime.List()),
+		Images:      imgcount,
+		MemoryLimit: srv.runtime.capabilities.MemoryLimit,
+		SwapLimit:   srv.runtime.capabilities.SwapLimit,
+		Debug:       os.Getenv("DEBUG") != "",
+		NFd:         utils.GetTotalUsedFds(),
+		NGoroutines: runtime.NumGoroutine(),
 	}
-	return out
 }
 
-func (srv *Server) ImageHistory(name string) ([]ApiHistory, error) {
+func (srv *Server) ImageHistory(name string) ([]APIHistory, error) {
 	image, err := srv.runtime.repositories.LookupImage(name)
 	if err != nil {
 		return nil, err
 	}
 
-	var outs []ApiHistory = []ApiHistory{} //produce [] when empty instead of 'null'
+	outs := []APIHistory{} //produce [] when empty instead of 'null'
 	err = image.WalkHistory(func(img *Image) error {
-		var out ApiHistory
-		out.Id = srv.runtime.repositories.ImageName(img.ShortId())
+		var out APIHistory
+		out.ID = srv.runtime.repositories.ImageName(img.ShortID())
 		out.Created = img.Created.Unix()
 		out.CreatedBy = strings.Join(img.ContainerConfig.Cmd, " ")
 		outs = append(outs, out)
@@ -235,17 +237,17 @@ func (srv *Server) ContainerChanges(name string) ([]Change, error) {
 	return nil, fmt.Errorf("No such container: %s", name)
 }
 
-func (srv *Server) Containers(all bool, n int, since, before string) []ApiContainers {
+func (srv *Server) Containers(all bool, n int, since, before string) []APIContainers {
 	var foundBefore bool
 	var displayed int
-	retContainers := []ApiContainers{}
+	retContainers := []APIContainers{}
 
 	for _, container := range srv.runtime.List() {
 		if !container.State.Running && !all && n == -1 && since == "" && before == "" {
 			continue
 		}
 		if before != "" {
-			if container.ShortId() == before {
+			if container.ShortID() == before {
 				foundBefore = true
 				continue
 			}
@@ -256,13 +258,13 @@ func (srv *Server) Containers(all bool, n int, since, before string) []ApiContai
 		if displayed == n {
 			break
 		}
-		if container.ShortId() == since {
+		if container.ShortID() == since {
 			break
 		}
 		displayed++
 
-		c := ApiContainers{
-			Id: container.Id,
+		c := APIContainers{
+			ID: container.ID,
 		}
 		c.Image = srv.runtime.repositories.ImageName(container.Image)
 		c.Command = fmt.Sprintf("%s %s", container.Path, strings.Join(container.Args, " "))
@@ -283,7 +285,7 @@ func (srv *Server) ContainerCommit(name, repo, tag, author, comment string, conf
 	if err != nil {
 		return "", err
 	}
-	return img.ShortId(), err
+	return img.ShortID(), err
 }
 
 func (srv *Server) ContainerTag(name, repo, tag string, force bool) error {
@@ -304,22 +306,23 @@ func (srv *Server) pullImage(r *registry.Registry, out io.Writer, imgId, endpoin
 	for _, id := range history {
 		if !srv.runtime.graph.Exists(id) {
 			out.Write(sf.FormatStatus("Pulling %s metadata", id))
-			imgJson, err := r.GetRemoteImageJson(id, endpoint, token)
+			imgJSON, err := r.GetRemoteImageJSON(id, endpoint, token)
 			if err != nil {
 				// FIXME: Keep goging in case of error?
 				return err
 			}
-			img, err := NewImgJson(imgJson)
+			img, err := NewImgJSON(imgJSON)
 			if err != nil {
 				return fmt.Errorf("Failed to parse json: %s", err)
 			}
 
 			// Get the layer
 			out.Write(sf.FormatStatus("Pulling %s fs layer", id))
-			layer, contentLength, err := r.GetRemoteImageLayer(img.Id, endpoint, token)
+			layer, contentLength, err := r.GetRemoteImageLayer(img.ID, endpoint, token)
 			if err != nil {
 				return err
 			}
+			defer layer.Close()
 			if err := srv.runtime.graph.Register(utils.ProgressReader(layer, contentLength, out, sf.FormatProgress("Downloading", "%v/%v (%v)"), sf), false, img); err != nil {
 				return err
 			}
@@ -328,8 +331,8 @@ func (srv *Server) pullImage(r *registry.Registry, out io.Writer, imgId, endpoin
 	return nil
 }
 
-func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, remote, askedTag string, sf *utils.StreamFormatter) error {
-	out.Write(sf.FormatStatus("Pulling repository %s from %s", remote, auth.IndexServerAddress()))
+func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, local, remote, askedTag string, sf *utils.StreamFormatter) error {
+	out.Write(sf.FormatStatus("Pulling repository %s from %s", local, auth.IndexServerAddress()))
 	repoData, err := r.GetRepositoryData(remote)
 	if err != nil {
 		return err
@@ -354,22 +357,22 @@ func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, remote, a
 		}
 	} else {
 		// Otherwise, check that the tag exists and use only that one
-		if id, exists := tagsList[askedTag]; !exists {
-			return fmt.Errorf("Tag %s not found in repositoy %s", askedTag, remote)
-		} else {
-			repoData.ImgList[id].Tag = askedTag
+		id, exists := tagsList[askedTag]
+		if !exists {
+			return fmt.Errorf("Tag %s not found in repositoy %s", askedTag, local)
 		}
+		repoData.ImgList[id].Tag = askedTag
 	}
 
 	for _, img := range repoData.ImgList {
 		if askedTag != "" && img.Tag != askedTag {
-			utils.Debugf("(%s) does not match %s (id: %s), skipping", img.Tag, askedTag, img.Id)
+			utils.Debugf("(%s) does not match %s (id: %s), skipping", img.Tag, askedTag, img.ID)
 			continue
 		}
-		out.Write(sf.FormatStatus("Pulling image %s (%s) from %s", img.Id, img.Tag, remote))
+		out.Write(sf.FormatStatus("Pulling image %s (%s) from %s", img.ID, img.Tag, remote))
 		success := false
 		for _, ep := range repoData.Endpoints {
-			if err := srv.pullImage(r, out, img.Id, "https://"+ep+"/v1", repoData.Tokens, sf); err != nil {
+			if err := srv.pullImage(r, out, img.ID, "https://"+ep+"/v1", repoData.Tokens, sf); err != nil {
 				out.Write(sf.FormatStatus("Error while retrieving image for tag: %s (%s); checking next endpoint", askedTag, err))
 				continue
 			}
@@ -384,7 +387,7 @@ func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, remote, a
 		if askedTag != "" && tag != askedTag {
 			continue
 		}
-		if err := srv.runtime.repositories.Set(remote, tag, id, true); err != nil {
+		if err := srv.runtime.repositories.Set(local, tag, id, true); err != nil {
 			return err
 		}
 	}
@@ -404,8 +407,12 @@ func (srv *Server) ImagePull(name, tag, endpoint string, out io.Writer, sf *util
 		}
 		return nil
 	}
-
-	if err := srv.pullRepository(r, out, name, tag, sf); err != nil {
+	remote := name
+	parts := strings.Split(name, "/")
+	if len(parts) > 2 {
+		remote = fmt.Sprintf("src/%s", url.QueryEscape(strings.Join(parts, "/")))
+	}
+	if err := srv.pullRepository(r, out, name, remote, tag, sf); err != nil {
 		return err
 	}
 
@@ -459,16 +466,16 @@ func (srv *Server) getImageList(localRepo map[string]string) ([]*registry.ImgDat
 			return nil, err
 		}
 		img.WalkHistory(func(img *Image) error {
-			if _, exists := imageSet[img.Id]; exists {
+			if _, exists := imageSet[img.ID]; exists {
 				return nil
 			}
-			imageSet[img.Id] = struct{}{}
-			checksum, err := srv.getChecksum(img.Id)
+			imageSet[img.ID] = struct{}{}
+			checksum, err := srv.getChecksum(img.ID)
 			if err != nil {
 				return err
 			}
 			imgList = append([]*registry.ImgData{{
-				Id:       img.Id,
+				ID:       img.ID,
 				Checksum: checksum,
 				Tag:      tag,
 			}}, imgList...)
@@ -487,7 +494,13 @@ func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, name stri
 	}
 	out.Write(sf.FormatStatus("Sending image list"))
 
-	repoData, err := r.PushImageJsonIndex(name, imgList, false)
+	srvName := name
+	parts := strings.Split(name, "/")
+	if len(parts) > 2 {
+		srvName = fmt.Sprintf("src/%s", url.QueryEscape(strings.Join(parts, "/")))
+	}
+
+	repoData, err := r.PushImageJSONIndex(srvName, imgList, false)
 	if err != nil {
 		return err
 	}
@@ -496,22 +509,22 @@ func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, name stri
 		out.Write(sf.FormatStatus("Pushing repository %s to %s (%d tags)", name, ep, len(localRepo)))
 		// For each image within the repo, push them
 		for _, elem := range imgList {
-			if _, exists := repoData.ImgList[elem.Id]; exists {
+			if _, exists := repoData.ImgList[elem.ID]; exists {
 				out.Write(sf.FormatStatus("Image %s already on registry, skipping", name))
 				continue
 			}
-			if err := srv.pushImage(r, out, name, elem.Id, ep, repoData.Tokens, sf); err != nil {
+			if err := srv.pushImage(r, out, name, elem.ID, ep, repoData.Tokens, sf); err != nil {
 				// FIXME: Continue on error?
 				return err
 			}
-			out.Write(sf.FormatStatus("Pushing tags for rev [%s] on {%s}", elem.Id, ep+"/users/"+name+"/"+elem.Tag))
-			if err := r.PushRegistryTag(name, elem.Id, elem.Tag, ep, repoData.Tokens); err != nil {
+			out.Write(sf.FormatStatus("Pushing tags for rev [%s] on {%s}", elem.ID, ep+"/users/"+srvName+"/"+elem.Tag))
+			if err := r.PushRegistryTag(srvName, elem.ID, elem.Tag, ep, repoData.Tokens); err != nil {
 				return err
 			}
 		}
 	}
 
-	if _, err := r.PushImageJsonIndex(name, imgList, true); err != nil {
+	if _, err := r.PushImageJSONIndex(srvName, imgList, true); err != nil {
 		return err
 	}
 	return nil
@@ -531,14 +544,14 @@ func (srv *Server) pushImage(r *registry.Registry, out io.Writer, remote, imgId,
 		return err
 	}
 	imgData := &registry.ImgData{
-		Id:       imgId,
+		ID:       imgId,
 		Checksum: checksum,
 	}
 
 	// Send the json
-	if err := r.PushImageJsonRegistry(imgData, jsonRaw, ep, token); err != nil {
+	if err := r.PushImageJSONRegistry(imgData, jsonRaw, ep, token); err != nil {
 		if err == registry.ErrAlreadyExists {
-			out.Write(sf.FormatStatus("Image %s already uploaded ; skipping", imgData.Id))
+			out.Write(sf.FormatStatus("Image %s already uploaded ; skipping", imgData.ID))
 			return nil
 		}
 		return err
@@ -571,7 +584,7 @@ func (srv *Server) pushImage(r *registry.Registry, out io.Writer, remote, imgId,
 	}
 
 	// Send the layer
-	if err := r.PushImageLayerRegistry(imgData.Id, utils.ProgressReader(layerData, int(layerData.Size), out, sf.FormatProgress("", "%v/%v (%v)"), sf), ep, token); err != nil {
+	if err := r.PushImageLayerRegistry(imgData.ID, utils.ProgressReader(layerData, int(layerData.Size), out, sf.FormatProgress("Pushing", "%v/%v (%v)"), sf), ep, token); err != nil {
 		return err
 	}
 	return nil
@@ -595,7 +608,7 @@ func (srv *Server) ImagePush(name, endpoint string, out io.Writer, sf *utils.Str
 		return err
 	}
 	out.Write(sf.FormatStatus("The push refers to an image: [%s]", name))
-	if err := srv.pushImage(r, out, name, img.Id, endpoint, nil, sf); err != nil {
+	if err := srv.pushImage(r, out, name, img.ID, endpoint, nil, sf); err != nil {
 		return err
 	}
 	return nil
@@ -632,11 +645,11 @@ func (srv *Server) ImageImport(src, repo, tag string, in io.Reader, out io.Write
 	}
 	// Optionally register the image at REPO/TAG
 	if repo != "" {
-		if err := srv.runtime.repositories.Set(repo, tag, img.Id, true); err != nil {
+		if err := srv.runtime.repositories.Set(repo, tag, img.ID, true); err != nil {
 			return err
 		}
 	}
-	out.Write(sf.FormatStatus(img.ShortId()))
+	out.Write(sf.FormatStatus(img.ShortID()))
 	return nil
 }
 
@@ -657,7 +670,7 @@ func (srv *Server) ContainerCreate(config *Config) (string, error) {
 		}
 		return "", err
 	}
-	return container.ShortId(), nil
+	return container.ShortID(), nil
 }
 
 func (srv *Server) ContainerRestart(name string, t int) error {
@@ -694,7 +707,7 @@ func (srv *Server) ContainerDestroy(name string, removeVolume bool) error {
 			for volumeId := range volumes {
 				// If the requested volu
 				if c, exists := usedVolumes[volumeId]; exists {
-					log.Printf("The volume %s is used by the container %s. Impossible to remove it. Skipping.\n", volumeId, c.Id)
+					log.Printf("The volume %s is used by the container %s. Impossible to remove it. Skipping.\n", volumeId, c.ID)
 					continue
 				}
 				if err := srv.runtime.volumes.Delete(volumeId); err != nil {
@@ -710,9 +723,9 @@ func (srv *Server) ContainerDestroy(name string, removeVolume bool) error {
 
 var ErrImageReferenced = errors.New("Image referenced by a repository")
 
-func (srv *Server) deleteImageAndChildren(id string, imgs *[]ApiRmi) error {
+func (srv *Server) deleteImageAndChildren(id string, imgs *[]APIRmi) error {
 	// If the image is referenced by a repo, do not delete
-	if len(srv.runtime.repositories.ById()[id]) != 0 {
+	if len(srv.runtime.repositories.ByID()[id]) != 0 {
 		return ErrImageReferenced
 	}
 
@@ -723,12 +736,11 @@ func (srv *Server) deleteImageAndChildren(id string, imgs *[]ApiRmi) error {
 		return err
 	}
 	for _, img := range byParents[id] {
-		if err := srv.deleteImageAndChildren(img.Id, imgs); err != nil {
+		if err := srv.deleteImageAndChildren(img.ID, imgs); err != nil {
 			if err != ErrImageReferenced {
 				return err
-			} else {
-				referenced = true
 			}
+			referenced = true
 		}
 	}
 	if referenced {
@@ -748,13 +760,13 @@ func (srv *Server) deleteImageAndChildren(id string, imgs *[]ApiRmi) error {
 		if err != nil {
 			return err
 		}
-		*imgs = append(*imgs, ApiRmi{Deleted: utils.TruncateId(id)})
+		*imgs = append(*imgs, APIRmi{Deleted: utils.TruncateID(id)})
 		return nil
 	}
 	return nil
 }
 
-func (srv *Server) deleteImageParents(img *Image, imgs *[]ApiRmi) error {
+func (srv *Server) deleteImageParents(img *Image, imgs *[]APIRmi) error {
 	if img.Parent != "" {
 		parent, err := srv.runtime.graph.Get(img.Parent)
 		if err != nil {
@@ -769,18 +781,18 @@ func (srv *Server) deleteImageParents(img *Image, imgs *[]ApiRmi) error {
 	return nil
 }
 
-func (srv *Server) deleteImage(img *Image, repoName, tag string) (*[]ApiRmi, error) {
+func (srv *Server) deleteImage(img *Image, repoName, tag string) (*[]APIRmi, error) {
 	//Untag the current image
-	var imgs []ApiRmi
+	var imgs []APIRmi
 	tagDeleted, err := srv.runtime.repositories.Delete(repoName, tag)
 	if err != nil {
 		return nil, err
 	}
 	if tagDeleted {
-		imgs = append(imgs, ApiRmi{Untagged: img.ShortId()})
+		imgs = append(imgs, APIRmi{Untagged: img.ShortID()})
 	}
-	if len(srv.runtime.repositories.ById()[img.Id]) == 0 {
-		if err := srv.deleteImageAndChildren(img.Id, &imgs); err != nil {
+	if len(srv.runtime.repositories.ByID()[img.ID]) == 0 {
+		if err := srv.deleteImageAndChildren(img.ID, &imgs); err != nil {
 			if err != ErrImageReferenced {
 				return &imgs, err
 			}
@@ -793,13 +805,13 @@ func (srv *Server) deleteImage(img *Image, repoName, tag string) (*[]ApiRmi, err
 	return &imgs, nil
 }
 
-func (srv *Server) ImageDelete(name string, autoPrune bool) (*[]ApiRmi, error) {
+func (srv *Server) ImageDelete(name string, autoPrune bool) (*[]APIRmi, error) {
 	img, err := srv.runtime.repositories.LookupImage(name)
 	if err != nil {
 		return nil, fmt.Errorf("No such image: %s", name)
 	}
 	if !autoPrune {
-		if err := srv.runtime.graph.Delete(img.Id); err != nil {
+		if err := srv.runtime.graph.Delete(img.ID); err != nil {
 			return nil, fmt.Errorf("Error deleting image %s: %s", name, err.Error())
 		}
 		return nil, nil
@@ -829,7 +841,7 @@ func (srv *Server) ImageGetCached(imgId string, config *Config) (*Image, error)
 		if _, exists := imageMap[img.Parent]; !exists {
 			imageMap[img.Parent] = make(map[string]struct{})
 		}
-		imageMap[img.Parent][img.Id] = struct{}{}
+		imageMap[img.Parent][img.ID] = struct{}{}
 	}
 
 	// Loop on the children of the given image and check the config

+ 2 - 2
server_test.go

@@ -65,7 +65,7 @@ func TestCreateRm(t *testing.T) {
 
 	srv := &Server{runtime: runtime}
 
-	config, _, err := ParseRun([]string{GetTestImage(runtime).Id, "echo test"}, nil)
+	config, _, err := ParseRun([]string{GetTestImage(runtime).ID, "echo test"}, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -98,7 +98,7 @@ func TestCreateStartRestartStopStartKillRm(t *testing.T) {
 
 	srv := &Server{runtime: runtime}
 
-	config, _, err := ParseRun([]string{GetTestImage(runtime).Id, "/bin/cat"}, nil)
+	config, _, err := ParseRun([]string{GetTestImage(runtime).ID, "/bin/cat"}, nil)
 	if err != nil {
 		t.Fatal(err)
 	}

+ 14 - 14
tags.go

@@ -11,7 +11,7 @@ import (
 	"strings"
 )
 
-const DEFAULT_TAG = "latest"
+const DEFAULTTAG = "latest"
 
 type TagStore struct {
 	path         string
@@ -72,7 +72,7 @@ func (store *TagStore) LookupImage(name string) (*Image, error) {
 		// (so we can pass all errors here)
 		repoAndTag := strings.SplitN(name, ":", 2)
 		if len(repoAndTag) == 1 {
-			repoAndTag = append(repoAndTag, DEFAULT_TAG)
+			repoAndTag = append(repoAndTag, DEFAULTTAG)
 		}
 		if i, err := store.GetImage(repoAndTag[0], repoAndTag[1]); err != nil {
 			return nil, err
@@ -87,31 +87,31 @@ func (store *TagStore) LookupImage(name string) (*Image, error) {
 
 // Return a reverse-lookup table of all the names which refer to each image
 // Eg. {"43b5f19b10584": {"base:latest", "base:v1"}}
-func (store *TagStore) ById() map[string][]string {
-	byId := make(map[string][]string)
+func (store *TagStore) ByID() map[string][]string {
+	byID := make(map[string][]string)
 	for repoName, repository := range store.Repositories {
 		for tag, id := range repository {
 			name := repoName + ":" + tag
-			if _, exists := byId[id]; !exists {
-				byId[id] = []string{name}
+			if _, exists := byID[id]; !exists {
+				byID[id] = []string{name}
 			} else {
-				byId[id] = append(byId[id], name)
-				sort.Strings(byId[id])
+				byID[id] = append(byID[id], name)
+				sort.Strings(byID[id])
 			}
 		}
 	}
-	return byId
+	return byID
 }
 
 func (store *TagStore) ImageName(id string) string {
-	if names, exists := store.ById()[id]; exists && len(names) > 0 {
+	if names, exists := store.ByID()[id]; exists && len(names) > 0 {
 		return names[0]
 	}
-	return utils.TruncateId(id)
+	return utils.TruncateID(id)
 }
 
 func (store *TagStore) DeleteAll(id string) error {
-	names, exists := store.ById()[id]
+	names, exists := store.ByID()[id]
 	if !exists || len(names) == 0 {
 		return nil
 	}
@@ -162,7 +162,7 @@ func (store *TagStore) Set(repoName, tag, imageName string, force bool) error {
 		return err
 	}
 	if tag == "" {
-		tag = DEFAULT_TAG
+		tag = DEFAULTTAG
 	}
 	if err := validateRepoName(repoName); err != nil {
 		return err
@@ -183,7 +183,7 @@ func (store *TagStore) Set(repoName, tag, imageName string, force bool) error {
 		}
 		store.Repositories[repoName] = repo
 	}
-	repo[tag] = img.Id
+	repo[tag] = img.ID
 	return store.Save()
 }
 

+ 7 - 105
term/term.go

@@ -7,104 +7,6 @@ import (
 	"unsafe"
 )
 
-type Termios struct {
-	Iflag  uintptr
-	Oflag  uintptr
-	Cflag  uintptr
-	Lflag  uintptr
-	Cc     [20]byte
-	Ispeed uintptr
-	Ospeed uintptr
-}
-
-const (
-	// Input flags
-	inpck  = 0x010
-	istrip = 0x020
-	icrnl  = 0x100
-	ixon   = 0x200
-
-	// Output flags
-	opost = 0x1
-
-	// Control flags
-	cs8 = 0x300
-
-	// Local flags
-	icanon = 0x100
-	iexten = 0x400
-)
-
-const (
-	HUPCL   = 0x4000
-	ICANON  = 0x100
-	ICRNL   = 0x100
-	IEXTEN  = 0x400
-	BRKINT  = 0x2
-	CFLUSH  = 0xf
-	CLOCAL  = 0x8000
-	CREAD   = 0x800
-	CS5     = 0x0
-	CS6     = 0x100
-	CS7     = 0x200
-	CS8     = 0x300
-	CSIZE   = 0x300
-	CSTART  = 0x11
-	CSTATUS = 0x14
-	CSTOP   = 0x13
-	CSTOPB  = 0x400
-	CSUSP   = 0x1a
-	IGNBRK  = 0x1
-	IGNCR   = 0x80
-	IGNPAR  = 0x4
-	IMAXBEL = 0x2000
-	INLCR   = 0x40
-	INPCK   = 0x10
-	ISIG    = 0x80
-	ISTRIP  = 0x20
-	IUTF8   = 0x4000
-	IXANY   = 0x800
-	IXOFF   = 0x400
-	IXON    = 0x200
-	NOFLSH  = 0x80000000
-	OCRNL   = 0x10
-	OFDEL   = 0x20000
-	OFILL   = 0x80
-	ONLCR   = 0x2
-	ONLRET  = 0x40
-	ONOCR   = 0x20
-	ONOEOT  = 0x8
-	OPOST   = 0x1
-	RENB    = 0x1000
-	PARMRK  = 0x8
-	PARODD  = 0x2000
-
-	TOSTOP   = 0x400000
-	VDISCARD = 0xf
-	VDSUSP   = 0xb
-	VEOF     = 0x0
-	VEOL     = 0x1
-	VEOL2    = 0x2
-	VERASE   = 0x3
-	VINTR    = 0x8
-	VKILL    = 0x5
-	VLNEXT   = 0xe
-	VMIN     = 0x10
-	VQUIT    = 0x9
-	VREPRINT = 0x6
-	VSTART   = 0xc
-	VSTATUS  = 0x12
-	VSTOP    = 0xd
-	VSUSP    = 0xa
-	VT0      = 0x0
-	VT1      = 0x10000
-	VTDLY    = 0x10000
-	VTIME    = 0x11
-	ECHO     = 0x00000008
-
-	PENDIN = 0x20000000
-)
-
 type State struct {
 	termios Termios
 }
@@ -128,21 +30,21 @@ func SetWinsize(fd uintptr, ws *Winsize) error {
 }
 
 // IsTerminal returns true if the given file descriptor is a terminal.
-func IsTerminal(fd int) bool {
+func IsTerminal(fd uintptr) bool {
 	var termios Termios
-	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(getTermios), uintptr(unsafe.Pointer(&termios)))
+	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(getTermios), uintptr(unsafe.Pointer(&termios)))
 	return err == 0
 }
 
 // Restore restores the terminal connected to the given file descriptor to a
 // previous state.
-func Restore(fd int, state *State) error {
-	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(setTermios), uintptr(unsafe.Pointer(&state.termios)))
+func Restore(fd uintptr, state *State) error {
+	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(setTermios), uintptr(unsafe.Pointer(&state.termios)))
 	return err
 }
 
 func SetRawTerminal() (*State, error) {
-	oldState, err := MakeRaw(int(os.Stdin.Fd()))
+	oldState, err := MakeRaw(os.Stdin.Fd())
 	if err != nil {
 		return nil, err
 	}
@@ -150,12 +52,12 @@ func SetRawTerminal() (*State, error) {
 	signal.Notify(c, os.Interrupt)
 	go func() {
 		_ = <-c
-		Restore(int(os.Stdin.Fd()), oldState)
+		Restore(os.Stdin.Fd(), oldState)
 		os.Exit(0)
 	}()
 	return oldState, err
 }
 
 func RestoreTerminal(state *State) {
-	Restore(int(os.Stdin.Fd()), state)
+	Restore(os.Stdin.Fd(), state)
 }

+ 27 - 5
term/termios_darwin.go

@@ -8,23 +8,45 @@ import (
 const (
 	getTermios = syscall.TIOCGETA
 	setTermios = syscall.TIOCSETA
+
+	ECHO    = 0x00000008
+	ONLCR   = 0x2
+	ISTRIP  = 0x20
+	INLCR   = 0x40
+	ISIG    = 0x80
+	IGNCR   = 0x80
+	ICANON  = 0x100
+	ICRNL   = 0x100
+	IXOFF   = 0x400
+	IXON    = 0x200
 )
 
+type Termios struct {
+	Iflag  uint64
+	Oflag  uint64
+	Cflag  uint64
+	Lflag  uint64
+	Cc     [20]byte
+	Ispeed uint64
+	Ospeed uint64
+}
+
 // MakeRaw put the terminal connected to the given file descriptor into raw
 // mode and returns the previous state of the terminal so that it can be
 // restored.
-func MakeRaw(fd int) (*State, error) {
+func MakeRaw(fd uintptr) (*State, error) {
 	var oldState State
-	if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(getTermios), uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 {
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(getTermios), uintptr(unsafe.Pointer(&oldState.termios))); err != 0 {
 		return nil, err
 	}
 
 	newState := oldState.termios
-	newState.Iflag &^= ISTRIP | INLCR | IGNCR | IXON | IXOFF
+	newState.Iflag &^= (ISTRIP | INLCR | IGNCR | IXON | IXOFF)
 	newState.Iflag |= ICRNL
 	newState.Oflag |= ONLCR
-	newState.Lflag &^= ECHO | ICANON | ISIG
-	if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(setTermios), uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
+	newState.Lflag &^= (ECHO | ICANON | ISIG)
+
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(setTermios), uintptr(unsafe.Pointer(&newState))); err != 0 {
 		return nil, err
 	}
 

+ 22 - 36
term/termios_linux.go

@@ -5,54 +5,40 @@ import (
 	"unsafe"
 )
 
-// #include <termios.h>
-// #include <sys/ioctl.h>
-/*
-void MakeRaw(int fd) {
-  struct termios t;
-
-  // FIXME: Handle errors?
-  ioctl(fd, TCGETS, &t);
-
-  t.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
-  t.c_oflag &= ~OPOST;
-  t.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
-  t.c_cflag &= ~(CSIZE | PARENB);
-  t.c_cflag |= CS8;
-
-  ioctl(fd, TCSETS, &t);
-}
-*/
-import "C"
-
 const (
 	getTermios = syscall.TCGETS
 	setTermios = syscall.TCSETS
 )
 
+type Termios struct {
+	Iflag  uint32
+	Oflag  uint32
+	Cflag  uint32
+	Lflag  uint32
+	Cc     [20]byte
+	Ispeed uint32
+	Ospeed uint32
+}
+
 // MakeRaw put the terminal connected to the given file descriptor into raw
 // mode and returns the previous state of the terminal so that it can be
 // restored.
-func MakeRaw(fd int) (*State, error) {
+func MakeRaw(fd uintptr) (*State, error) {
 	var oldState State
-	if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), syscall.TCGETS, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 {
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, getTermios, uintptr(unsafe.Pointer(&oldState.termios))); err != 0 {
 		return nil, err
 	}
-	C.MakeRaw(C.int(fd))
-	return &oldState, nil
-
-	// FIXME: post on goland issues this: very same as the C function bug non-working
 
-	// newState := oldState.termios
+	newState := oldState.termios
 
-	// newState.Iflag &^= (IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON)
-	// newState.Oflag &^= OPOST
-	// newState.Lflag &^= (ECHO | syscall.ECHONL | ICANON | ISIG | IEXTEN)
-	// newState.Cflag &^= (CSIZE | syscall.PARENB)
-	// newState.Cflag |= CS8
+	newState.Iflag &^= (syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON)
+	newState.Oflag &^= syscall.OPOST
+	newState.Lflag &^= (syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN)
+	newState.Cflag &^= (syscall.CSIZE | syscall.PARENB)
+	newState.Cflag |= syscall.CS8
 
-	// if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.TCSETS, uintptr(unsafe.Pointer(&newState))); err != 0 {
-	// 	return nil, err
-	// }
-	// return &oldState, nil
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, setTermios, uintptr(unsafe.Pointer(&newState))); err != 0 {
+		return nil, err
+	}
+	return &oldState, nil
 }

+ 7 - 7
utils/utils.go

@@ -34,7 +34,7 @@ func Go(f func() error) chan error {
 // Request a given URL and return an io.Reader
 func Download(url string, stderr io.Writer) (*http.Response, error) {
 	var resp *http.Response
-	var err error = nil
+	var err error
 	if resp, err = http.Get(url); err != nil {
 		return nil, err
 	}
@@ -349,11 +349,11 @@ func (idx *TruncIndex) Get(s string) (string, error) {
 	return string(idx.bytes[before:after]), err
 }
 
-// TruncateId returns a shorthand version of a string identifier for convenience.
+// TruncateID returns a shorthand version of a string identifier for convenience.
 // A collision with other shorthands is very unlikely, but possible.
 // In case of a collision a lookup with TruncIndex.Get() will fail, and the caller
 // will need to use a langer prefix, or the full-length Id.
-func TruncateId(id string) string {
+func TruncateID(id string) string {
 	shortLen := 12
 	if len(id) < shortLen {
 		shortLen = len(id)
@@ -566,7 +566,7 @@ func NewWriteFlusher(w io.Writer) *WriteFlusher {
 	return &WriteFlusher{w: w, flusher: flusher}
 }
 
-type JsonMessage struct {
+type JSONMessage struct {
 	Status   string `json:"status,omitempty"`
 	Progress string `json:"progress,omitempty"`
 	Error    string `json:"error,omitempty"`
@@ -585,7 +585,7 @@ func (sf *StreamFormatter) FormatStatus(format string, a ...interface{}) []byte
 	sf.used = true
 	str := fmt.Sprintf(format, a...)
 	if sf.json {
-		b, err := json.Marshal(&JsonMessage{Status:str});
+		b, err := json.Marshal(&JSONMessage{Status:str});
 		if err != nil {
 			return sf.FormatError(err)
 		}
@@ -597,7 +597,7 @@ func (sf *StreamFormatter) FormatStatus(format string, a ...interface{}) []byte
 func (sf *StreamFormatter) FormatError(err error) []byte {
 	sf.used = true
 	if sf.json {
-		if b, err := json.Marshal(&JsonMessage{Error:err.Error()}); err == nil {
+		if b, err := json.Marshal(&JSONMessage{Error:err.Error()}); err == nil {
 			return b
 		}
 		return []byte("{\"error\":\"format error\"}")
@@ -608,7 +608,7 @@ func (sf *StreamFormatter) FormatError(err error) []byte {
 func (sf *StreamFormatter) FormatProgress(action, str string) []byte {
 	sf.used = true
 	if sf.json {
-		b, err := json.Marshal(&JsonMessage{Progress:str})
+		b, err := json.Marshal(&JSONMessage{Status: action, Progress:str})
 		if err != nil {
                         return nil
                 }