Browse Source

add version pkg

Docker-DCO-1.1-Signed-off-by: Victor Vieux <victor.vieux@docker.com> (github: vieux)
Victor Vieux 11 years ago
parent
commit
8dad771daa
6 changed files with 140 additions and 105 deletions
  1. 62 61
      api/server.go
  2. 1 0
      integration/server_test.go
  3. 52 0
      pkg/version/version.go
  4. 25 0
      pkg/version/version_test.go
  5. 0 24
      utils/utils.go
  6. 0 20
      utils/utils_test.go

+ 62 - 61
api/server.go

@@ -13,6 +13,7 @@ import (
 	"github.com/dotcloud/docker/pkg/listenbuffer"
 	"github.com/dotcloud/docker/pkg/systemd"
 	"github.com/dotcloud/docker/pkg/user"
+	"github.com/dotcloud/docker/pkg/version"
 	"github.com/dotcloud/docker/utils"
 	"github.com/gorilla/mux"
 	"io"
@@ -32,7 +33,7 @@ var (
 	activationLock chan struct{}
 )
 
-type HttpApiFunc func(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error
+type HttpApiFunc func(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error
 
 func hijackServer(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) {
 	conn, _, err := w.(http.Hijacker).Hijack()
@@ -113,7 +114,7 @@ func getBoolParam(value string) (bool, error) {
 	return ret, nil
 }
 
-func postAuth(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func postAuth(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	var (
 		authConfig, err = ioutil.ReadAll(r.Body)
 		job             = eng.Job("auth")
@@ -136,13 +137,13 @@ func postAuth(eng *engine.Engine, version string, w http.ResponseWriter, r *http
 	return nil
 }
 
-func getVersion(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func getVersion(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	w.Header().Set("Content-Type", "application/json")
 	eng.ServeHTTP(w, r)
 	return nil
 }
 
-func postContainersKill(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func postContainersKill(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 	}
@@ -160,7 +161,7 @@ func postContainersKill(eng *engine.Engine, version string, w http.ResponseWrite
 	return nil
 }
 
-func getContainersExport(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func getContainersExport(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 	}
@@ -172,7 +173,7 @@ func getContainersExport(eng *engine.Engine, version string, w http.ResponseWrit
 	return nil
 }
 
-func getImagesJSON(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func getImagesJSON(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := parseForm(r); err != nil {
 		return err
 	}
@@ -186,7 +187,7 @@ func getImagesJSON(eng *engine.Engine, version string, w http.ResponseWriter, r
 	job.Setenv("filter", r.Form.Get("filter"))
 	job.Setenv("all", r.Form.Get("all"))
 
-	if utils.CompareVersion(version, "1.7") >= 0 {
+	if version.GreaterThanOrEqualTo("1.7") {
 		streamJSON(job, w, false)
 	} else if outs, err = job.Stdout.AddListTable(); err != nil {
 		return err
@@ -196,7 +197,7 @@ func getImagesJSON(eng *engine.Engine, version string, w http.ResponseWriter, r
 		return err
 	}
 
-	if utils.CompareVersion(version, "1.7") < 0 && outs != nil { // Convert to legacy format
+	if version.LessThan("1.7") && outs != nil { // Convert to legacy format
 		outsLegacy := engine.NewTable("Created", 0)
 		for _, out := range outs.Data {
 			for _, repoTag := range out.GetList("RepoTags") {
@@ -219,8 +220,8 @@ func getImagesJSON(eng *engine.Engine, version string, w http.ResponseWriter, r
 	return nil
 }
 
-func getImagesViz(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if utils.CompareVersion(version, "1.6") > 0 {
+func getImagesViz(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if version.GreaterThan("1.6") {
 		w.WriteHeader(http.StatusNotFound)
 		return fmt.Errorf("This is now implemented in the client.")
 	}
@@ -228,13 +229,13 @@ func getImagesViz(eng *engine.Engine, version string, w http.ResponseWriter, r *
 	return nil
 }
 
-func getInfo(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func getInfo(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	w.Header().Set("Content-Type", "application/json")
 	eng.ServeHTTP(w, r)
 	return nil
 }
 
-func getEvents(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func getEvents(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := parseForm(r); err != nil {
 		return err
 	}
@@ -245,7 +246,7 @@ func getEvents(eng *engine.Engine, version string, w http.ResponseWriter, r *htt
 	return job.Run()
 }
 
-func getImagesHistory(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func getImagesHistory(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 	}
@@ -259,7 +260,7 @@ func getImagesHistory(eng *engine.Engine, version string, w http.ResponseWriter,
 	return nil
 }
 
-func getContainersChanges(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func getContainersChanges(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 	}
@@ -269,8 +270,8 @@ func getContainersChanges(eng *engine.Engine, version string, w http.ResponseWri
 	return job.Run()
 }
 
-func getContainersTop(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if utils.CompareVersion(version, "1.4") < 0 {
+func getContainersTop(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if version.LessThan("1.4") {
 		return fmt.Errorf("top was improved a lot since 1.3, Please upgrade your docker client.")
 	}
 	if vars == nil {
@@ -285,7 +286,7 @@ func getContainersTop(eng *engine.Engine, version string, w http.ResponseWriter,
 	return job.Run()
 }
 
-func getContainersJSON(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func getContainersJSON(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := parseForm(r); err != nil {
 		return err
 	}
@@ -301,7 +302,7 @@ func getContainersJSON(eng *engine.Engine, version string, w http.ResponseWriter
 	job.Setenv("before", r.Form.Get("before"))
 	job.Setenv("limit", r.Form.Get("limit"))
 
-	if utils.CompareVersion(version, "1.5") >= 0 {
+	if version.GreaterThanOrEqualTo("1.5") {
 		streamJSON(job, w, false)
 	} else if outs, err = job.Stdout.AddTable(); err != nil {
 		return err
@@ -309,7 +310,7 @@ func getContainersJSON(eng *engine.Engine, version string, w http.ResponseWriter
 	if err = job.Run(); err != nil {
 		return err
 	}
-	if utils.CompareVersion(version, "1.5") < 0 { // Convert to legacy format
+	if version.LessThan("1.5") { // Convert to legacy format
 		for _, out := range outs.Data {
 			ports := engine.NewTable("", 0)
 			ports.ReadListFrom([]byte(out.Get("Ports")))
@@ -323,7 +324,7 @@ func getContainersJSON(eng *engine.Engine, version string, w http.ResponseWriter
 	return nil
 }
 
-func postImagesTag(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func postImagesTag(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := parseForm(r); err != nil {
 		return err
 	}
@@ -340,7 +341,7 @@ func postImagesTag(eng *engine.Engine, version string, w http.ResponseWriter, r
 	return nil
 }
 
-func postCommit(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func postCommit(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := parseForm(r); err != nil {
 		return err
 	}
@@ -369,7 +370,7 @@ func postCommit(eng *engine.Engine, version string, w http.ResponseWriter, r *ht
 }
 
 // Creates an image from Pull or from Import
-func postImagesCreate(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func postImagesCreate(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := parseForm(r); err != nil {
 		return err
 	}
@@ -397,7 +398,7 @@ func postImagesCreate(eng *engine.Engine, version string, w http.ResponseWriter,
 			}
 		}
 		job = eng.Job("pull", r.Form.Get("fromImage"), tag)
-		job.SetenvBool("parallel", utils.CompareVersion(version, "1.3") > 0)
+		job.SetenvBool("parallel", version.GreaterThan("1.3"))
 		job.SetenvJson("metaHeaders", metaHeaders)
 		job.SetenvJson("authConfig", authConfig)
 	} else { //import
@@ -405,7 +406,7 @@ func postImagesCreate(eng *engine.Engine, version string, w http.ResponseWriter,
 		job.Stdin.Add(r.Body)
 	}
 
-	if utils.CompareVersion(version, "1.0") > 0 {
+	if version.GreaterThan("1.0") {
 		job.SetenvBool("json", true)
 		streamJSON(job, w, true)
 	} else {
@@ -415,14 +416,14 @@ func postImagesCreate(eng *engine.Engine, version string, w http.ResponseWriter,
 		if !job.Stdout.Used() {
 			return err
 		}
-		sf := utils.NewStreamFormatter(utils.CompareVersion(version, "1.0") > 0)
+		sf := utils.NewStreamFormatter(version.GreaterThan("1.0"))
 		w.Write(sf.FormatError(err))
 	}
 
 	return nil
 }
 
-func getImagesSearch(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func getImagesSearch(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := parseForm(r); err != nil {
 		return err
 	}
@@ -454,7 +455,7 @@ func getImagesSearch(eng *engine.Engine, version string, w http.ResponseWriter,
 	return job.Run()
 }
 
-func postImagesInsert(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func postImagesInsert(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := parseForm(r); err != nil {
 		return err
 	}
@@ -462,7 +463,7 @@ func postImagesInsert(eng *engine.Engine, version string, w http.ResponseWriter,
 		return fmt.Errorf("Missing parameter")
 	}
 	job := eng.Job("insert", vars["name"], r.Form.Get("url"), r.Form.Get("path"))
-	if utils.CompareVersion(version, "1.0") > 0 {
+	if version.GreaterThan("1.0") {
 		job.SetenvBool("json", true)
 		streamJSON(job, w, false)
 	} else {
@@ -472,14 +473,14 @@ func postImagesInsert(eng *engine.Engine, version string, w http.ResponseWriter,
 		if !job.Stdout.Used() {
 			return err
 		}
-		sf := utils.NewStreamFormatter(utils.CompareVersion(version, "1.0") > 0)
+		sf := utils.NewStreamFormatter(version.GreaterThan("1.0"))
 		w.Write(sf.FormatError(err))
 	}
 
 	return nil
 }
 
-func postImagesPush(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func postImagesPush(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 	}
@@ -513,7 +514,7 @@ func postImagesPush(eng *engine.Engine, version string, w http.ResponseWriter, r
 	job := eng.Job("push", vars["name"])
 	job.SetenvJson("metaHeaders", metaHeaders)
 	job.SetenvJson("authConfig", authConfig)
-	if utils.CompareVersion(version, "1.0") > 0 {
+	if version.GreaterThan("1.0") {
 		job.SetenvBool("json", true)
 		streamJSON(job, w, true)
 	} else {
@@ -524,17 +525,17 @@ func postImagesPush(eng *engine.Engine, version string, w http.ResponseWriter, r
 		if !job.Stdout.Used() {
 			return err
 		}
-		sf := utils.NewStreamFormatter(utils.CompareVersion(version, "1.0") > 0)
+		sf := utils.NewStreamFormatter(version.GreaterThan("1.0"))
 		w.Write(sf.FormatError(err))
 	}
 	return nil
 }
 
-func getImagesGet(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func getImagesGet(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 	}
-	if utils.CompareVersion(version, "1.0") > 0 {
+	if version.GreaterThan("1.0") {
 		w.Header().Set("Content-Type", "application/x-tar")
 	}
 	job := eng.Job("image_export", vars["name"])
@@ -542,13 +543,13 @@ func getImagesGet(eng *engine.Engine, version string, w http.ResponseWriter, r *
 	return job.Run()
 }
 
-func postImagesLoad(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func postImagesLoad(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	job := eng.Job("load")
 	job.Stdin.Add(r.Body)
 	return job.Run()
 }
 
-func postContainersCreate(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func postContainersCreate(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := parseForm(r); err != nil {
 		return nil
 	}
@@ -579,7 +580,7 @@ func postContainersCreate(eng *engine.Engine, version string, w http.ResponseWri
 	return writeJSON(w, http.StatusCreated, out)
 }
 
-func postContainersRestart(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func postContainersRestart(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := parseForm(r); err != nil {
 		return err
 	}
@@ -595,7 +596,7 @@ func postContainersRestart(eng *engine.Engine, version string, w http.ResponseWr
 	return nil
 }
 
-func deleteContainers(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func deleteContainers(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := parseForm(r); err != nil {
 		return err
 	}
@@ -612,7 +613,7 @@ func deleteContainers(eng *engine.Engine, version string, w http.ResponseWriter,
 	return nil
 }
 
-func deleteImages(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func deleteImages(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := parseForm(r); err != nil {
 		return err
 	}
@@ -626,7 +627,7 @@ func deleteImages(eng *engine.Engine, version string, w http.ResponseWriter, r *
 	return job.Run()
 }
 
-func postContainersStart(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func postContainersStart(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 	}
@@ -647,7 +648,7 @@ func postContainersStart(eng *engine.Engine, version string, w http.ResponseWrit
 	return nil
 }
 
-func postContainersStop(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func postContainersStop(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := parseForm(r); err != nil {
 		return err
 	}
@@ -663,7 +664,7 @@ func postContainersStop(eng *engine.Engine, version string, w http.ResponseWrite
 	return nil
 }
 
-func postContainersWait(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func postContainersWait(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 	}
@@ -685,7 +686,7 @@ func postContainersWait(eng *engine.Engine, version string, w http.ResponseWrite
 	return writeJSON(w, http.StatusOK, env)
 }
 
-func postContainersResize(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func postContainersResize(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := parseForm(r); err != nil {
 		return err
 	}
@@ -698,7 +699,7 @@ func postContainersResize(eng *engine.Engine, version string, w http.ResponseWri
 	return nil
 }
 
-func postContainersAttach(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func postContainersAttach(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := parseForm(r); err != nil {
 		return err
 	}
@@ -740,7 +741,7 @@ func postContainersAttach(eng *engine.Engine, version string, w http.ResponseWri
 
 	fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
 
-	if c.GetSubEnv("Config") != nil && !c.GetSubEnv("Config").GetBool("Tty") && utils.CompareVersion(version, "1.6") >= 0 {
+	if c.GetSubEnv("Config") != nil && !c.GetSubEnv("Config").GetBool("Tty") && version.GreaterThanOrEqualTo("1.6") {
 		errStream = utils.NewStdWriter(outStream, utils.Stderr)
 		outStream = utils.NewStdWriter(outStream, utils.Stdout)
 	} else {
@@ -763,7 +764,7 @@ func postContainersAttach(eng *engine.Engine, version string, w http.ResponseWri
 	return nil
 }
 
-func wsContainersAttach(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func wsContainersAttach(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := parseForm(r); err != nil {
 		return err
 	}
@@ -795,7 +796,7 @@ func wsContainersAttach(eng *engine.Engine, version string, w http.ResponseWrite
 	return nil
 }
 
-func getContainersByName(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func getContainersByName(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 	}
@@ -805,7 +806,7 @@ func getContainersByName(eng *engine.Engine, version string, w http.ResponseWrit
 	return job.Run()
 }
 
-func getImagesByName(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func getImagesByName(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 	}
@@ -815,8 +816,8 @@ func getImagesByName(eng *engine.Engine, version string, w http.ResponseWriter,
 	return job.Run()
 }
 
-func postBuild(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if utils.CompareVersion(version, "1.3") < 0 {
+func postBuild(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if version.LessThan("1.3") {
 		return fmt.Errorf("Multipart upload for build is no longer supported. Please upgrade your docker client.")
 	}
 	var (
@@ -831,7 +832,7 @@ func postBuild(eng *engine.Engine, version string, w http.ResponseWriter, r *htt
 	// Both headers will be parsed and sent along to the daemon, but if a non-empty
 	// ConfigFile is present, any value provided as an AuthConfig directly will
 	// be overridden. See BuildFile::CmdFrom for details.
-	if utils.CompareVersion(version, "1.9") < 0 && authEncoded != "" {
+	if version.LessThan("1.9") && authEncoded != "" {
 		authJson := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
 		if err := json.NewDecoder(authJson).Decode(authConfig); err != nil {
 			// for a pull it is not an error if no auth was given
@@ -849,7 +850,7 @@ func postBuild(eng *engine.Engine, version string, w http.ResponseWriter, r *htt
 		}
 	}
 
-	if utils.CompareVersion(version, "1.8") >= 0 {
+	if version.GreaterThanOrEqualTo("1.8") {
 		job.SetenvBool("json", true)
 		streamJSON(job, w, true)
 	} else {
@@ -868,13 +869,13 @@ func postBuild(eng *engine.Engine, version string, w http.ResponseWriter, r *htt
 		if !job.Stdout.Used() {
 			return err
 		}
-		sf := utils.NewStreamFormatter(utils.CompareVersion(version, "1.8") >= 0)
+		sf := utils.NewStreamFormatter(version.GreaterThanOrEqualTo("1.8"))
 		w.Write(sf.FormatError(err))
 	}
 	return nil
 }
 
-func postContainersCopy(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func postContainersCopy(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 	}
@@ -907,7 +908,7 @@ func postContainersCopy(eng *engine.Engine, version string, w http.ResponseWrite
 	return nil
 }
 
-func optionsHandler(eng *engine.Engine, version string, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func optionsHandler(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	w.WriteHeader(http.StatusOK)
 	return nil
 }
@@ -917,7 +918,7 @@ func writeCorsHeaders(w http.ResponseWriter, r *http.Request) {
 	w.Header().Add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS")
 }
 
-func makeHttpHandler(eng *engine.Engine, logging bool, localMethod string, localRoute string, handlerFunc HttpApiFunc, enableCors bool, dockerVersion string) http.HandlerFunc {
+func makeHttpHandler(eng *engine.Engine, logging bool, localMethod string, localRoute string, handlerFunc HttpApiFunc, enableCors bool, dockerVersion version.Version) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		// log the request
 		utils.Debugf("Calling %s %s", localMethod, localRoute)
@@ -928,11 +929,11 @@ func makeHttpHandler(eng *engine.Engine, logging bool, localMethod string, local
 
 		if strings.Contains(r.Header.Get("User-Agent"), "Docker-Client/") {
 			userAgent := strings.Split(r.Header.Get("User-Agent"), "/")
-			if len(userAgent) == 2 && userAgent[1] != dockerVersion {
+			if len(userAgent) == 2 && !dockerVersion.Equal(userAgent[1]) {
 				utils.Debugf("Warning: client and server don't have the same version (client: %s, server: %s)", userAgent[1], dockerVersion)
 			}
 		}
-		version := mux.Vars(r)["version"]
+		version := version.Version(mux.Vars(r)["version"])
 		if version == "" {
 			version = APIVERSION
 		}
@@ -940,7 +941,7 @@ func makeHttpHandler(eng *engine.Engine, logging bool, localMethod string, local
 			writeCorsHeaders(w, r)
 		}
 
-		if utils.CompareVersion(version, APIVERSION) == 1 {
+		if version.GreaterThan(APIVERSION) {
 			http.Error(w, fmt.Errorf("client and server don't have same version (client : %s, server: %s)", version, APIVERSION).Error(), http.StatusNotFound)
 			return
 		}
@@ -1039,7 +1040,7 @@ func createRouter(eng *engine.Engine, logging, enableCors bool, dockerVersion st
 			localMethod := method
 
 			// build the handler function
-			f := makeHttpHandler(eng, logging, localMethod, localRoute, localFct, enableCors, dockerVersion)
+			f := makeHttpHandler(eng, logging, localMethod, localRoute, localFct, enableCors, version.Version(dockerVersion))
 
 			// add the new route
 			if localRoute == "" {
@@ -1057,7 +1058,7 @@ func createRouter(eng *engine.Engine, logging, enableCors bool, dockerVersion st
 // ServeRequest processes a single http request to the docker remote api.
 // FIXME: refactor this to be part of Server and not require re-creating a new
 // router each time. This requires first moving ListenAndServe into Server.
-func ServeRequest(eng *engine.Engine, apiversion string, w http.ResponseWriter, req *http.Request) error {
+func ServeRequest(eng *engine.Engine, apiversion version.Version, w http.ResponseWriter, req *http.Request) error {
 	router, err := createRouter(eng, false, true, "")
 	if err != nil {
 		return err

+ 1 - 0
integration/server_test.go

@@ -2,6 +2,7 @@ package docker
 
 import (
 	"github.com/dotcloud/docker"
+	"github.com/dotcloud/docker/engine"
 	"github.com/dotcloud/docker/runconfig"
 	"strings"
 	"testing"

+ 52 - 0
pkg/version/version.go

@@ -0,0 +1,52 @@
+package version
+
+import (
+	"strconv"
+	"strings"
+)
+
+type Version string
+
+func (me Version) compareTo(other string) int {
+	var (
+		meTab    = strings.Split(string(me), ".")
+		otherTab = strings.Split(other, ".")
+	)
+	for i, s := range meTab {
+		var meInt, otherInt int
+		meInt, _ = strconv.Atoi(s)
+		if len(otherTab) > i {
+			otherInt, _ = strconv.Atoi(otherTab[i])
+		}
+		if meInt > otherInt {
+			return 1
+		}
+		if otherInt > meInt {
+			return -1
+		}
+	}
+	if len(otherTab) > len(meTab) {
+		return -1
+	}
+	return 0
+}
+
+func (me Version) LessThan(other string) bool {
+	return me.compareTo(other) == -1
+}
+
+func (me Version) LessThanOrEqualTo(other string) bool {
+	return me.compareTo(other) <= 0
+}
+
+func (me Version) GreaterThan(other string) bool {
+	return me.compareTo(other) == 1
+}
+
+func (me Version) GreaterThanOrEqualTo(other string) bool {
+	return me.compareTo(other) >= 0
+}
+
+func (me Version) Equal(other string) bool {
+	return me.compareTo(other) == 0
+}

+ 25 - 0
pkg/version/version_test.go

@@ -0,0 +1,25 @@
+package version
+
+import (
+	"testing"
+)
+
+func assertVersion(t *testing.T, a, b string, result int) {
+	if r := Version(a).compareTo(b); r != result {
+		t.Fatalf("Unexpected version comparison result. Found %d, expected %d", r, result)
+	}
+}
+
+func TestCompareVersion(t *testing.T) {
+	assertVersion(t, "1.12", "1.12", 0)
+	assertVersion(t, "1.05.00.0156", "1.0.221.9289", 1)
+	assertVersion(t, "1", "1.0.1", -1)
+	assertVersion(t, "1.0.1", "1", 1)
+	assertVersion(t, "1.0.1", "1.0.2", -1)
+	assertVersion(t, "1.0.2", "1.0.3", -1)
+	assertVersion(t, "1.0.3", "1.1", -1)
+	assertVersion(t, "1.1", "1.1.1", -1)
+	assertVersion(t, "1.1.1", "1.1.2", -1)
+	assertVersion(t, "1.1.2", "1.2", -1)
+
+}

+ 0 - 24
utils/utils.go

@@ -972,27 +972,3 @@ func NewReadCloserWrapper(r io.Reader, closer func() error) io.ReadCloser {
 		closer: closer,
 	}
 }
-
-func CompareVersion(a, b string) int {
-	var (
-		aa = strings.Split(a, ".")
-		bb = strings.Split(b, ".")
-	)
-	for i, s := range aa {
-		var ai, bi int
-		ai, _ = strconv.Atoi(s)
-		if len(bb) > i {
-			bi, _ = strconv.Atoi(bb[i])
-		}
-		if ai > bi {
-			return 1
-		}
-		if bi > ai {
-			return -1
-		}
-	}
-	if len(bb) > len(aa) {
-		return -1
-	}
-	return 0
-}

+ 0 - 20
utils/utils_test.go

@@ -479,23 +479,3 @@ func StrSlicesEqual(a, b []string) bool {
 
 	return true
 }
-
-func asserVersion(t *testing.T, a, b string, result int) {
-	if r := CompareVersion(a, b); r != result {
-		t.Fatalf("Unexpected version comparison result. Found %d, expected %d", r, result)
-	}
-}
-
-func TestCompareVersion(t *testing.T) {
-	asserVersion(t, "1.12", "1.12", 0)
-	asserVersion(t, "1.05.00.0156", "1.0.221.9289", 1)
-	asserVersion(t, "1", "1.0.1", -1)
-	asserVersion(t, "1.0.1", "1", 1)
-	asserVersion(t, "1.0.1", "1.0.2", -1)
-	asserVersion(t, "1.0.2", "1.0.3", -1)
-	asserVersion(t, "1.0.3", "1.1", -1)
-	asserVersion(t, "1.1", "1.1.1", -1)
-	asserVersion(t, "1.1.1", "1.1.2", -1)
-	asserVersion(t, "1.1.2", "1.2", -1)
-
-}