Skip to content

Commit

Permalink
Merge pull request #168 from carolynvs/split-download-locations
Browse files Browse the repository at this point in the history
Support new release scheme
  • Loading branch information
carolynvs authored Aug 16, 2017
2 parents a663964 + 2bfa66c commit b8c0211
Show file tree
Hide file tree
Showing 34 changed files with 3,318 additions and 1,064 deletions.
6 changes: 3 additions & 3 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

[[constraint]]
name = "github.com/Masterminds/semver"
version = "1.2.2"
branch = "2.x"

[[constraint]]
name = "github.com/codegangsta/cli"
Expand Down
70 changes: 62 additions & 8 deletions dvm-helper/dockerversion/dockerversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,69 @@ func Parse(value string) Version {
v := Version{raw: value}
semver, err := semver.NewVersion(value)
if err == nil {
v.semver = semver
v.semver = &semver
} else {
v.alias = value
}
return v
}

func (version Version) BuildDownloadURL(mirrorURL string) (url string, archived bool) {
var releaseSlug, versionSlug, extSlug string

archivedReleaseCutoff, _ := semver.NewVersion("1.11.0-rc1")
dockerStoreCutoff, _ := semver.NewVersion("17.06.0-ce")

var edgeVersion Version
if version.IsExperimental() {
// TODO: Figure out the latest edge version
edgeVersion = Parse("17.06.0-ce")
}

// Docker Store Download
if version.IsExperimental() || !version.semver.LessThan(dockerStoreCutoff) {
archived = true
extSlug = archiveFileExt
if mirrorURL == "" {
mirrorURL = "download.docker.com"
}
if version.IsExperimental() {
releaseSlug = "edge"
versionSlug = edgeVersion.String()
} else if version.IsPrerelease() {
releaseSlug = "test"
versionSlug = version.String()
} else {
releaseSlug = "stable"
versionSlug = version.String()
}

url = fmt.Sprintf("https://%s/%s/static/%s/%s/docker-%s%s",
mirrorURL, mobyOS, releaseSlug, dockerArch, versionSlug, extSlug)
return
} else { // Original Download
archived = !version.semver.LessThan(archivedReleaseCutoff)
versionSlug = version.String()
if archived {
extSlug = archiveFileExt
} else {
extSlug = binaryFileExt
}
if mirrorURL == "" {
mirrorURL = "docker.com"
}
if version.IsPrerelease() {
releaseSlug = "test"
} else {
releaseSlug = "get"
}

url = fmt.Sprintf("https://%s.%s/builds/%s/%s/docker-%s%s",
releaseSlug, mirrorURL, dockerOS, dockerArch, versionSlug, extSlug)
return
}
}

func (version Version) IsPrerelease() bool {
if version.semver == nil {
return false
Expand Down Expand Up @@ -78,11 +134,6 @@ func (version *Version) SetAsExperimental() {
version.alias = ExperimentalAlias
}

func (version Version) ShouldUseArchivedRelease() bool {
cutoff, _ := semver.NewConstraint(">= 1.11.0-rc1")
return version.IsExperimental() || cutoff.Check(version.semver)
}

func (version Version) String() string {
if version.alias != "" && version.semver != nil {
return fmt.Sprintf("%s (%s)", version.alias, version.formatRaw())
Expand Down Expand Up @@ -129,7 +180,10 @@ func (version Version) InRange(r string) (bool, error) {
if err != nil {
return false, errors.Wrapf(err, "Unable to parse range constraint: %s", r)
}
return c.Check(version.semver), nil
if version.semver == nil {
return false, nil
}
return c.Matches(*version.semver) == nil, nil
}

// Compare compares Versions v to o:
Expand All @@ -138,7 +192,7 @@ func (version Version) InRange(r string) (bool, error) {
// 1 == v is greater than o
func (v Version) Compare(o Version) int {
if v.semver != nil && o.semver != nil {
return v.semver.Compare(o.semver)
return v.semver.Compare(*o.semver)
}

return strings.Compare(v.alias, o.alias)
Expand Down
6 changes: 6 additions & 0 deletions dvm-helper/dockerversion/dockerversion.nix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// +build !windows

package dockerversion

const archiveFileExt string = ".tgz"
const binaryFileExt string = ""
3 changes: 3 additions & 0 deletions dvm-helper/dockerversion/dockerversion_386.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package dockerversion

const dockerArch string = "i386"
3 changes: 3 additions & 0 deletions dvm-helper/dockerversion/dockerversion_amd64.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package dockerversion

const dockerArch string = "x86_64"
4 changes: 4 additions & 0 deletions dvm-helper/dockerversion/dockerversion_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package dockerversion

const dockerOS string = "Darwin"
const mobyOS string = "mac"
4 changes: 4 additions & 0 deletions dvm-helper/dockerversion/dockerversion_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package dockerversion

const dockerOS string = "Linux"
const mobyOS string = "linux"
104 changes: 76 additions & 28 deletions dvm-helper/dockerversion/dockerversion_test.go
Original file line number Diff line number Diff line change
@@ -1,76 +1,72 @@
package dockerversion_test
package dockerversion

import (
"fmt"
"net/http"
"testing"

"github.com/howtowhale/dvm/dvm-helper/dockerversion"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)

func TestStripLeadingV(t *testing.T) {
v := dockerversion.Parse("v1.0.0")
v := Parse("v1.0.0")
assert.Equal(t, "1.0.0", v.String(), "Leading v should be stripped from the string representation")
assert.Equal(t, "1.0.0", v.Name(), "Leading v should be stripped from the name")
assert.Equal(t, "1.0.0", v.Value(), "Leading v should be stripped from the version value")
}

func TestIsPrerelease(t *testing.T) {
var v dockerversion.Version
var v Version

v = dockerversion.Parse("17.3.0-ce-rc1")
v = Parse("17.3.0-ce-rc1")
assert.True(t, v.IsPrerelease(), "%s should be a prerelease", v)

v = dockerversion.Parse("1.12.4-rc1")
v = Parse("1.12.4-rc1")
assert.True(t, v.IsPrerelease(), "%s should be a prerelease", v)

v = dockerversion.Parse("1.12.4-beta.1")
v = Parse("1.12.4-beta.1")
assert.True(t, v.IsPrerelease(), "%s should be a prerelease", v)

v = dockerversion.Parse("1.12.4-alpha-2")
v = Parse("1.12.4-alpha-2")
assert.True(t, v.IsPrerelease(), "%s should be a prerelease", v)

v = dockerversion.Parse("17.3.0-ce")
v = Parse("17.3.0-ce")
assert.False(t, v.IsPrerelease(), "%s should NOT be a prerelease", v)
}

func TestPrereleaseUsesArchivedReleases(t *testing.T) {
v := dockerversion.Parse("v1.12.5-rc1")

assert.True(t, v.ShouldUseArchivedRelease())
}

func TestLeadingZeroInVersion(t *testing.T) {
v := dockerversion.Parse("v17.03.0-ce")
v := Parse("v17.03.0-ce")

assert.Equal(t, "17.03.0-ce", v.String(), "Leading zeroes in the version should be preserved")
}

func TestSystemAlias(t *testing.T) {
v := dockerversion.Parse(dockerversion.SystemAlias)
v := Parse(SystemAlias)
assert.Empty(t, v.Slug(),
"The system alias should not have a slug")
assert.Equal(t, dockerversion.SystemAlias, v.String(),
assert.Equal(t, SystemAlias, v.String(),
"An empty alias should only print the alias")
assert.Equal(t, dockerversion.SystemAlias, v.Name(),
assert.Equal(t, SystemAlias, v.Name(),
"The name for an aliased version should be its alias")
assert.Equal(t, "", v.Value(),
"The value for an empty aliased version should be empty")
}

func TestExperimentalAlias(t *testing.T) {
v := dockerversion.Parse(dockerversion.ExperimentalAlias)
assert.Equal(t, dockerversion.ExperimentalAlias, v.Slug(),
v := Parse(ExperimentalAlias)
assert.Equal(t, ExperimentalAlias, v.Slug(),
"The slug for the experimental version should be 'experimental'")
assert.Equal(t, dockerversion.ExperimentalAlias, v.String(),
assert.Equal(t, ExperimentalAlias, v.String(),
"An empty alias should only print the alias")
assert.Equal(t, dockerversion.ExperimentalAlias, v.Name(),
assert.Equal(t, ExperimentalAlias, v.Name(),
"The name for an aliased version should be its alias")
assert.Equal(t, "", v.Value(),
"The value for an empty aliased version should be empty")
}

func TestAlias(t *testing.T) {
v := dockerversion.NewAlias("prod", "1.2.3")
v := NewAlias("prod", "1.2.3")
assert.Equal(t, "1.2.3", v.Slug(),
"The slug for an aliased version should be its semver value")
assert.Equal(t, "prod (1.2.3)", v.String(),
Expand All @@ -82,7 +78,7 @@ func TestAlias(t *testing.T) {
}

func TestSemanticVersion(t *testing.T) {
v := dockerversion.Parse("1.2.3")
v := Parse("1.2.3")
assert.Equal(t, "1.2.3", v.Slug(),
"The slug for a a semantic version should be its semver value")
assert.Equal(t, "1.2.3", v.String(),
Expand All @@ -94,13 +90,65 @@ func TestSemanticVersion(t *testing.T) {
}

func TestSetAsExperimental(t *testing.T) {
v := dockerversion.Parse("1.2.3")
v := Parse("1.2.3")
v.SetAsExperimental()
assert.True(t, v.IsExperimental())
}

func TestSetAsSystem(t *testing.T) {
v := dockerversion.Parse("1.2.3")
v := Parse("1.2.3")
v.SetAsSystem()
assert.True(t, v.IsSystem())
}
}

func TestVersion_BuildDownloadURL(t *testing.T) {
testcases := map[Version]struct {
wantURL string
wantArchived bool
}{
// original download location, without compression
Parse("1.10.3"): {fmt.Sprintf("https://get.docker.com/builds/%s/%s/docker-1.10.3", dockerOS, dockerArch), false},

// original download location, without compression, prerelease
Parse("1.10.0-rc1"): {fmt.Sprintf("https://test.docker.com/builds/%s/%s/docker-1.10.0-rc1", dockerOS, dockerArch), false},

// compressed binaries
Parse("1.11.0-rc1"): {fmt.Sprintf("https://test.docker.com/builds/%s/%s/docker-1.11.0-rc1.tgz", dockerOS, dockerArch), true},

// original version scheme, prerelease binaries
Parse("1.13.0-rc1"): {fmt.Sprintf("https://test.docker.com/builds/%s/%s/docker-1.13.0-rc1.tgz", dockerOS, dockerArch), true},

// yearly notation, original download location, release location
Parse("17.03.0-ce"): {fmt.Sprintf("https://get.docker.com/builds/%s/%s/docker-17.03.0-ce%s", dockerOS, dockerArch, archiveFileExt), true},

// docker store download
Parse("17.06.0-ce"): {fmt.Sprintf("https://download.docker.com/%s/static/stable/%s/docker-17.06.0-ce.tgz", mobyOS, dockerArch), true},

// docker store download, prerelease
Parse("17.07.0-ce-rc1"): {fmt.Sprintf("https://download.docker.com/%s/static/test/%s/docker-17.07.0-ce-rc1.tgz", mobyOS, dockerArch), true},

// latest edge/experimental
Parse("experimental"): {fmt.Sprintf("https://download.docker.com/%s/static/edge/%s/docker-17.06.0-ce.tgz", mobyOS, dockerArch), true},
}

for version, testcase := range testcases {
t.Run(version.String(), func(t *testing.T) {
gotURL, gotArchived := version.BuildDownloadURL("")
if testcase.wantURL != gotURL {
t.Fatalf("Expected %s to be downloaded from '%s', but got '%s'", version, testcase.wantURL, gotURL)
}
if testcase.wantArchived != gotArchived {
t.Fatalf("Expected %s to use an archived download strategy", version)
}

response, err := http.DefaultClient.Head(gotURL)
if err != nil {
t.Fatalf("%#v", errors.Wrapf(err, "Unable to download release from %s", gotURL))
}

if response.StatusCode != 200 {
t.Fatalf("Unexpected status code (%d) when downloading %s", response.StatusCode, gotURL)
}
})
}
}
6 changes: 6 additions & 0 deletions dvm-helper/dockerversion/dockerversion_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package dockerversion

const dockerOS string = "Windows"
const mobyOS string = "win"
const archiveFileExt string = ".zip"
const binaryFileExt string = ".exe"
1 change: 0 additions & 1 deletion dvm-helper/dvm-helper.386.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@

package main

const dockerArch string = "i386"
const dvmArch string = "i386"
1 change: 0 additions & 1 deletion dvm-helper/dvm-helper.amd64.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@

package main

const dockerArch string = "x86_64"
const dvmArch string = "x86_64"
1 change: 0 additions & 1 deletion dvm-helper/dvm-helper.darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@

package main

const dockerOS string = "Darwin"
const dvmOS string = "Darwin"
30 changes: 2 additions & 28 deletions dvm-helper/dvm-helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -441,37 +441,11 @@ func install(version dockerversion.Version) {
}
}

func buildDownloadURL(version dockerversion.Version) string {
dockerVersion := version.Value()
if version.IsExperimental() {
dockerVersion = "latest"
}

if mirrorURL == "" {
mirrorURL = "https://get.docker.com/builds"
if version.IsExperimental() {
writeDebug("Downloading from experimental builds mirror")
mirrorURL = "https://experimental.docker.com/builds"
}
if version.IsPrerelease() {
writeDebug("Downloading from prerelease builds mirror")
mirrorURL = "https://test.docker.com/builds"
}
}

// New Docker versions are released in a zip file, vs. the old way of releasing the client binary only
if version.ShouldUseArchivedRelease() {
return fmt.Sprintf("%s/%s/%s/docker-%s%s", mirrorURL, dockerOS, dockerArch, dockerVersion, archiveFileExt)
}

return fmt.Sprintf("%s/%s/%s/docker-%s%s", mirrorURL, dockerOS, dockerArch, dockerVersion, binaryFileExt)
}

func downloadRelease(version dockerversion.Version) {
url := buildDownloadURL(version)
url, archived := version.BuildDownloadURL(mirrorURL)
binaryName := getBinaryName()
binaryPath := filepath.Join(getVersionDir(version), binaryName)
if version.ShouldUseArchivedRelease() {
if archived {
archivedFile := path.Join("docker", binaryName)
downloadArchivedFileWithChecksum(url, archivedFile, binaryPath)
} else {
Expand Down
Loading

0 comments on commit b8c0211

Please sign in to comment.