diff --git a/CHANGELOG.md b/CHANGELOG.md index c882f97..c8c84be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Change Log +## [0.1.5](https://github.com/grammarly/rocker-compose/tree/0.1.5) (2016-02-12) + +[Full Changelog](https://github.com/grammarly/rocker-compose/compare/0.1.4...0.1.5) + +**Implemented enhancements:** + +- New S3 naming schema support [\#42](https://github.com/grammarly/rocker-compose/pull/42) + ## [0.1.4](https://github.com/grammarly/rocker-compose/tree/HEAD) (2016-02-08) [Full Changelog](https://github.com/grammarly/rocker-compose/compare/0.1.3...0.1.4) diff --git a/VERSION b/VERSION index 845639e..9faa1b7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.4 +0.1.5 diff --git a/main.go b/main.go index d330d32..1630f1e 100644 --- a/main.go +++ b/main.go @@ -36,10 +36,10 @@ import ( "github.com/codegangsta/cli" "github.com/fsouza/go-dockerclient" "github.com/go-yaml/yaml" + "github.com/grammarly/rocker/src/dockerclient" "github.com/grammarly/rocker/src/rocker/debugtrap" - "github.com/grammarly/rocker/src/rocker/dockerclient" - "github.com/grammarly/rocker/src/rocker/template" "github.com/grammarly/rocker/src/rocker/textformatter" + "github.com/grammarly/rocker/src/template" ) var ( diff --git a/src/compose/client.go b/src/compose/client.go index 620ac21..3f9a6c8 100644 --- a/src/compose/client.go +++ b/src/compose/client.go @@ -23,10 +23,10 @@ import ( "os" "time" - "github.com/grammarly/rocker/src/rocker/dockerclient" - "github.com/grammarly/rocker/src/rocker/imagename" - "github.com/grammarly/rocker/src/rocker/storage/s3" - "github.com/grammarly/rocker/src/rocker/template" + "github.com/grammarly/rocker/src/dockerclient" + "github.com/grammarly/rocker/src/imagename" + "github.com/grammarly/rocker/src/storage/s3" + "github.com/grammarly/rocker/src/template" "github.com/kr/pretty" log "github.com/Sirupsen/logrus" @@ -715,7 +715,7 @@ func (client *DockerClient) resolveVersions(local, hub bool, vars template.Vars, } // looking locally first - candidate := container.Image.ResolveVersion(images) + candidate := container.Image.ResolveVersion(images, true) // in case we want to include external images as well, pulling list of available // images from repository or central docker hub @@ -739,13 +739,14 @@ func (client *DockerClient) resolveVersions(local, hub bool, vars template.Vars, log.Debugf("remote: %v", remote) // Re-Resolve having hub tags - candidate = container.Image.ResolveVersion(append(images, remote...)) + candidate = container.Image.ResolveVersion(append(images, remote...), false) } if candidate == nil { err = fmt.Errorf("Image not found: %s", container.Image) return } + candidate.IsOldS3Name = container.Image.IsOldS3Name log.Infof("Resolve %s --> %s", container.Image, candidate.GetTag()) diff --git a/src/compose/client_test.go b/src/compose/client_test.go index c9d5253..40e470a 100644 --- a/src/compose/client_test.go +++ b/src/compose/client_test.go @@ -25,10 +25,10 @@ import ( log "github.com/Sirupsen/logrus" "github.com/fsouza/go-dockerclient" - "github.com/grammarly/rocker/src/rocker/dockerclient" - "github.com/grammarly/rocker/src/rocker/imagename" - "github.com/grammarly/rocker/src/rocker/template" + "github.com/grammarly/rocker/src/dockerclient" + "github.com/grammarly/rocker/src/imagename" "github.com/grammarly/rocker/src/rocker/test" + "github.com/grammarly/rocker/src/template" "github.com/kr/pretty" "github.com/stretchr/testify/assert" ) diff --git a/src/compose/compose.go b/src/compose/compose.go index 08b5fcc..5d8a53c 100644 --- a/src/compose/compose.go +++ b/src/compose/compose.go @@ -29,7 +29,7 @@ import ( log "github.com/Sirupsen/logrus" "github.com/fsouza/go-dockerclient" - "github.com/grammarly/rocker/src/rocker/template" + "github.com/grammarly/rocker/src/template" "github.com/kr/pretty" ) diff --git a/src/compose/config/config.go b/src/compose/config/config.go index ff3be44..f2a4d3b 100644 --- a/src/compose/config/config.go +++ b/src/compose/config/config.go @@ -33,8 +33,8 @@ import ( "regexp" "strings" - "github.com/grammarly/rocker/src/rocker/imagename" - "github.com/grammarly/rocker/src/rocker/template" + "github.com/grammarly/rocker/src/imagename" + "github.com/grammarly/rocker/src/template" "github.com/mitchellh/go-homedir" "github.com/fsouza/go-dockerclient" diff --git a/src/compose/config/config_test.go b/src/compose/config/config_test.go index 0fd7f83..33d04a9 100644 --- a/src/compose/config/config_test.go +++ b/src/compose/config/config_test.go @@ -20,7 +20,7 @@ import ( "strings" "testing" - "github.com/grammarly/rocker/src/rocker/template" + "github.com/grammarly/rocker/src/template" "github.com/stretchr/testify/assert" ) diff --git a/src/compose/container.go b/src/compose/container.go index da35d96..160d25b 100644 --- a/src/compose/container.go +++ b/src/compose/container.go @@ -23,7 +23,7 @@ import ( "time" "github.com/go-yaml/yaml" - "github.com/grammarly/rocker/src/rocker/imagename" + "github.com/grammarly/rocker/src/imagename" log "github.com/Sirupsen/logrus" "github.com/fsouza/go-dockerclient" diff --git a/src/compose/diff_test.go b/src/compose/diff_test.go index 31655da..8e19bf7 100644 --- a/src/compose/diff_test.go +++ b/src/compose/diff_test.go @@ -21,8 +21,8 @@ import ( "github.com/grammarly/rocker-compose/src/compose/config" "testing" - "github.com/grammarly/rocker/src/rocker/imagename" - "github.com/grammarly/rocker/src/rocker/template" + "github.com/grammarly/rocker/src/imagename" + "github.com/grammarly/rocker/src/template" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) @@ -38,9 +38,9 @@ func TestComparatorSameValue(t *testing.T) { func TestDiffCreateAll(t *testing.T) { cmp := NewDiff("test") containers := []*Container{} - c1 := newContainer("test", "1", config.ContainerName{"test", "2"}, config.ContainerName{"test", "3"}) - c2 := newContainer("test", "2", config.ContainerName{"test", "4"}) - c3 := newContainer("test", "3", config.ContainerName{"test", "4"}) + c1 := newContainer("test", "1", config.ContainerName{Namespace: "test", Name: "2"}, config.ContainerName{Namespace: "test", Name: "3"}) + c2 := newContainer("test", "2", config.ContainerName{Namespace: "test", Name: "4"}) + c3 := newContainer("test", "3", config.ContainerName{Namespace: "test", Name: "4"}) c4 := newContainer("test", "4") containers = append(containers, c1, c2, c3, c4) actions, _ := cmp.Diff(containers, []*Container{}) @@ -157,8 +157,8 @@ func TestDiffEnsureFewExternalDependencies(t *testing.T) { c1 := newContainer("metrics", "1") c2 := newContainer("metrics", "2") c3 := newContainer("metrics", "3") - c4 := newContainer("test", "1", config.ContainerName{"metrics", "1"}, - config.ContainerName{"metrics", "2"}, config.ContainerName{"metrics", "3"}) + c4 := newContainer("test", "1", config.ContainerName{Namespace: "metrics", Name: "1"}, + config.ContainerName{Namespace: "metrics", Name: "2"}, config.ContainerName{Namespace: "metrics", Name: "3"}) actions, _ := cmp.Diff([]*Container{c4}, []*Container{c1, c2, c3}) mock := clientMock{} mock.On("EnsureContainerExist", c1).Return(nil) @@ -188,9 +188,9 @@ func TestDiffFailInMiddle(t *testing.T) { func TestDiffFailInDependent(t *testing.T) { cmp := NewDiff("test") - c1 := newContainer("test", "1", config.ContainerName{"test", "2"}) + c1 := newContainer("test", "1", config.ContainerName{Namespace: "test", Name: "2"}) c2 := newContainer("test", "2") - c3 := newContainer("test", "3", config.ContainerName{"test", "2"}) + c3 := newContainer("test", "3", config.ContainerName{Namespace: "test", Name: "2"}) actions, _ := cmp.Diff([]*Container{c1, c2, c3}, []*Container{}) mock := clientMock{} mock.On("RunContainer", c2).Return(fmt.Errorf("fail")) @@ -201,7 +201,7 @@ func TestDiffFailInDependent(t *testing.T) { func TestDiffInDependent(t *testing.T) { cmp := NewDiff("test") - c1 := newContainer("test", "1", config.ContainerName{"test", "2"}) + c1 := newContainer("test", "1", config.ContainerName{Namespace: "test", Name: "2"}) c2 := newContainer("test", "2") c2x := newContainer("test", "2") c2x.Config.Labels = map[string]string{"test": "test2"} @@ -224,17 +224,17 @@ func TestDiffInDependentNet(t *testing.T) { } c1 := &Container{ State: &ContainerState{Running: true}, - Name: &config.ContainerName{"test", "1"}, + Name: &config.ContainerName{Namespace: "test", Name: "1"}, Config: &config.Container{Net: c2NetName}, } c2 := &Container{ State: &ContainerState{Running: true}, - Name: &config.ContainerName{"test", "2"}, + Name: &config.ContainerName{Namespace: "test", Name: "2"}, Config: &config.Container{}, } c2x := &Container{ State: &ContainerState{Running: true}, - Name: &config.ContainerName{"test", "2"}, + Name: &config.ContainerName{Namespace: "test", Name: "2"}, Config: &config.Container{Labels: map[string]string{"test": "test2"}}, } actions, _ := cmp.Diff([]*Container{c1, c2x}, []*Container{c1, c2}) @@ -256,7 +256,7 @@ func TestDiffInDependentExternalNet(t *testing.T) { } c1 := &Container{ State: &ContainerState{Running: true}, - Name: &config.ContainerName{"test", "1"}, + Name: &config.ContainerName{Namespace: "test", Name: "1"}, Config: &config.Container{Net: c2NetName}, } c2 := newContainer("external", "2") @@ -271,9 +271,9 @@ func TestDiffInDependentExternalNet(t *testing.T) { func TestDiffForCycles(t *testing.T) { cmp := NewDiff("test") containers := []*Container{} - c1 := newContainer("test", "1", config.ContainerName{"test", "2"}) - c2 := newContainer("test", "2", config.ContainerName{"test", "3"}) - c3 := newContainer("test", "3", config.ContainerName{"test", "1"}) + c1 := newContainer("test", "1", config.ContainerName{Namespace: "test", Name: "2"}) + c2 := newContainer("test", "2", config.ContainerName{Namespace: "test", Name: "3"}) + c3 := newContainer("test", "3", config.ContainerName{Namespace: "test", Name: "1"}) containers = append(containers, c1, c2, c3) _, err := cmp.Diff(containers, []*Container{c1, c3}) assert.Error(t, err) @@ -286,12 +286,12 @@ func TestDiffDifferentConfig(t *testing.T) { cpusetCpus2 := "0-4" c1x := &Container{ State: &ContainerState{Running: true}, - Name: &config.ContainerName{"test", "1"}, + Name: &config.ContainerName{Namespace: "test", Name: "1"}, Config: &config.Container{CpusetCpus: &cpusetCpus1}, } c1y := &Container{ State: &ContainerState{Running: true}, - Name: &config.ContainerName{"test", "1"}, + Name: &config.ContainerName{Namespace: "test", Name: "1"}, Config: &config.Container{CpusetCpus: &cpusetCpus2}, } containers = append(containers, c1x) @@ -308,7 +308,7 @@ func TestDiffForExternalDependencies(t *testing.T) { cmp := NewDiff("test") containers := []*Container{} c1 := newContainer("test", "1") - c2 := newContainer("test", "2", config.ContainerName{"metrics", "1"}) + c2 := newContainer("test", "2", config.ContainerName{Namespace: "metrics", Name: "1"}) m1 := newContainer("metrics", "1") containers = append(containers, c1, c2) actions, _ := cmp.Diff(containers, []*Container{m1}) @@ -324,9 +324,9 @@ func TestDiffForExternalDependencies(t *testing.T) { func TestDiffCreateRemoving(t *testing.T) { cmp := NewDiff("test") containers := []*Container{} - c1 := newContainer("test", "1", config.ContainerName{"test", "2"}, config.ContainerName{"test", "3"}) - c2 := newContainer("test", "2", config.ContainerName{"test", "4"}) - c3 := newContainer("test", "3", config.ContainerName{"test", "4"}) + c1 := newContainer("test", "1", config.ContainerName{Namespace: "test", Name: "2"}, config.ContainerName{Namespace: "test", Name: "3"}) + c2 := newContainer("test", "2", config.ContainerName{Namespace: "test", Name: "4"}) + c3 := newContainer("test", "3", config.ContainerName{Namespace: "test", Name: "4"}) c4 := newContainer("test", "4") c5 := newContainer("test", "5") containers = append(containers, c1, c2, c3, c4) @@ -345,9 +345,9 @@ func TestDiffCreateRemoving(t *testing.T) { func TestDiffCreateSome(t *testing.T) { cmp := NewDiff("test") containers := []*Container{} - c1 := newContainer("test", "1", config.ContainerName{"test", "2"}, config.ContainerName{"test", "3"}) - c2 := newContainer("test", "2", config.ContainerName{"test", "4"}) - c3 := newContainer("test", "3", config.ContainerName{"test", "4"}) + c1 := newContainer("test", "1", config.ContainerName{Namespace: "test", Name: "2"}, config.ContainerName{Namespace: "test", Name: "3"}) + c2 := newContainer("test", "2", config.ContainerName{Namespace: "test", Name: "4"}) + c3 := newContainer("test", "3", config.ContainerName{Namespace: "test", Name: "4"}) c4 := newContainer("test", "4") containers = append(containers, c1, c2, c3, c4) actions, _ := cmp.Diff(containers, []*Container{c1}) @@ -362,7 +362,7 @@ func TestDiffCreateSome(t *testing.T) { func TestWaitForStart(t *testing.T) { cmp := NewDiff("test") - c1 := newContainerWaitFor("test", "1", config.ContainerName{"test", "2"}) + c1 := newContainerWaitFor("test", "1", config.ContainerName{Namespace: "test", Name: "2"}) c2 := newContainer("test", "2") actions, _ := cmp.Diff([]*Container{c1, c2}, []*Container{}) mock := clientMock{} @@ -376,7 +376,7 @@ func TestWaitForStart(t *testing.T) { func TestWaitForNotRestart(t *testing.T) { cmp := NewDiff("test") - c1 := newContainerWaitFor("test", "1", config.ContainerName{"test", "2"}) + c1 := newContainerWaitFor("test", "1", config.ContainerName{Namespace: "test", Name: "2"}) c2 := newContainer("test", "2") c2x := newContainer("test", "2") c2x.Config.Labels = map[string]string{"test": "test2"} @@ -394,12 +394,12 @@ func TestDiffRecovery(t *testing.T) { cmp := NewDiff("") c1x := &Container{ State: &ContainerState{Running: true}, - Name: &config.ContainerName{"test", "1"}, + Name: &config.ContainerName{Namespace: "test", Name: "1"}, Config: &config.Container{}, } c1y := &Container{ State: &ContainerState{Running: false}, - Name: &config.ContainerName{"test", "1"}, + Name: &config.ContainerName{Namespace: "test", Name: "1"}, Config: &config.Container{}, } actions, _ := cmp.Diff([]*Container{c1x}, []*Container{c1y}) @@ -415,7 +415,7 @@ func newContainer(namespace string, name string, dependencies ...config.Containe State: &ContainerState{ Running: true, }, - Name: &config.ContainerName{namespace, name}, + Name: &config.ContainerName{Namespace: namespace, Name: name}, Config: &config.Container{ VolumesFrom: dependencies, }} @@ -426,7 +426,7 @@ func newContainerWaitFor(namespace string, name string, dependencies ...config.C State: &ContainerState{ Running: true, }, - Name: &config.ContainerName{namespace, name}, + Name: &config.ContainerName{Namespace: namespace, Name: name}, Config: &config.Container{ WaitFor: dependencies, }} diff --git a/src/compose/docker.go b/src/compose/docker.go index e151c41..a63fdba 100644 --- a/src/compose/docker.go +++ b/src/compose/docker.go @@ -25,9 +25,9 @@ import ( "github.com/docker/docker/pkg/jsonmessage" "github.com/docker/docker/pkg/term" "github.com/fsouza/go-dockerclient" - "github.com/grammarly/rocker/src/rocker/dockerclient" - "github.com/grammarly/rocker/src/rocker/imagename" - "github.com/grammarly/rocker/src/rocker/storage/s3" + "github.com/grammarly/rocker/src/dockerclient" + "github.com/grammarly/rocker/src/imagename" + "github.com/grammarly/rocker/src/storage/s3" ) const emptyImageName = "gliderlabs/alpine:3.2" diff --git a/src/compose/docker_test.go b/src/compose/docker_test.go index f8e37cc..fe49325 100644 --- a/src/compose/docker_test.go +++ b/src/compose/docker_test.go @@ -22,7 +22,7 @@ import ( "testing" "github.com/fsouza/go-dockerclient" - "github.com/grammarly/rocker/src/rocker/dockerclient" + "github.com/grammarly/rocker/src/dockerclient" ) func TestEntrypointOverride(t *testing.T) { diff --git a/vendor/github.com/grammarly/rocker/src/rocker/dockerclient/auth.go b/vendor/github.com/grammarly/rocker/src/dockerclient/auth.go similarity index 98% rename from vendor/github.com/grammarly/rocker/src/rocker/dockerclient/auth.go rename to vendor/github.com/grammarly/rocker/src/dockerclient/auth.go index c9c9f8a..d94b23f 100644 --- a/vendor/github.com/grammarly/rocker/src/rocker/dockerclient/auth.go +++ b/vendor/github.com/grammarly/rocker/src/dockerclient/auth.go @@ -19,11 +19,10 @@ package dockerclient import ( "encoding/base64" "fmt" + "github.com/grammarly/rocker/src/imagename" "strings" "sync" - "github.com/grammarly/rocker/src/rocker/imagename" - log "github.com/Sirupsen/logrus" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/credentials" diff --git a/vendor/github.com/grammarly/rocker/src/rocker/dockerclient/dockerclient.go b/vendor/github.com/grammarly/rocker/src/dockerclient/dockerclient.go similarity index 100% rename from vendor/github.com/grammarly/rocker/src/rocker/dockerclient/dockerclient.go rename to vendor/github.com/grammarly/rocker/src/dockerclient/dockerclient.go diff --git a/vendor/github.com/grammarly/rocker/src/rocker/dockerclient/dockerclient_test.go b/vendor/github.com/grammarly/rocker/src/dockerclient/dockerclient_test.go similarity index 100% rename from vendor/github.com/grammarly/rocker/src/rocker/dockerclient/dockerclient_test.go rename to vendor/github.com/grammarly/rocker/src/dockerclient/dockerclient_test.go diff --git a/vendor/github.com/grammarly/rocker/src/rocker/dockerclient/matrix.go b/vendor/github.com/grammarly/rocker/src/dockerclient/matrix.go similarity index 98% rename from vendor/github.com/grammarly/rocker/src/rocker/dockerclient/matrix.go rename to vendor/github.com/grammarly/rocker/src/dockerclient/matrix.go index 2f49fb4..9c557f6 100644 --- a/vendor/github.com/grammarly/rocker/src/rocker/dockerclient/matrix.go +++ b/vendor/github.com/grammarly/rocker/src/dockerclient/matrix.go @@ -18,13 +18,12 @@ package dockerclient import ( "fmt" + "github.com/grammarly/rocker/src/util" "os" "path" "path/filepath" "strings" - "github.com/grammarly/rocker/src/rocker/util" - "github.com/fsouza/go-dockerclient" ) diff --git a/vendor/github.com/grammarly/rocker/src/rocker/dockerclient/matrix_test.go b/vendor/github.com/grammarly/rocker/src/dockerclient/matrix_test.go similarity index 100% rename from vendor/github.com/grammarly/rocker/src/rocker/dockerclient/matrix_test.go rename to vendor/github.com/grammarly/rocker/src/dockerclient/matrix_test.go diff --git a/vendor/github.com/grammarly/rocker/src/rocker/dockerclient/registry.go b/vendor/github.com/grammarly/rocker/src/dockerclient/registry.go similarity index 99% rename from vendor/github.com/grammarly/rocker/src/rocker/dockerclient/registry.go rename to vendor/github.com/grammarly/rocker/src/dockerclient/registry.go index 1e7cc2b..01b9491 100644 --- a/vendor/github.com/grammarly/rocker/src/rocker/dockerclient/registry.go +++ b/vendor/github.com/grammarly/rocker/src/dockerclient/registry.go @@ -19,13 +19,12 @@ package dockerclient import ( "encoding/json" "fmt" + "github.com/grammarly/rocker/src/imagename" "io/ioutil" "net/http" "net/url" "strings" - "github.com/grammarly/rocker/src/rocker/imagename" - "github.com/fsouza/go-dockerclient" log "github.com/Sirupsen/logrus" diff --git a/vendor/github.com/grammarly/rocker/src/rocker/imagename/artifact.go b/vendor/github.com/grammarly/rocker/src/imagename/artifact.go similarity index 100% rename from vendor/github.com/grammarly/rocker/src/rocker/imagename/artifact.go rename to vendor/github.com/grammarly/rocker/src/imagename/artifact.go diff --git a/vendor/github.com/grammarly/rocker/src/rocker/imagename/imagename.go b/vendor/github.com/grammarly/rocker/src/imagename/imagename.go similarity index 87% rename from vendor/github.com/grammarly/rocker/src/rocker/imagename/imagename.go rename to vendor/github.com/grammarly/rocker/src/imagename/imagename.go index 92ba5bf..6d5e312 100644 --- a/vendor/github.com/grammarly/rocker/src/rocker/imagename/imagename.go +++ b/vendor/github.com/grammarly/rocker/src/imagename/imagename.go @@ -21,6 +21,7 @@ package imagename import ( "encoding/json" + "fmt" "regexp" "sort" "strings" @@ -44,6 +45,11 @@ const ( StorageS3 = "s3" ) +const ( + s3Prefix = "s3.amazonaws.com/" + s3OldPrefix = "s3:" +) + var ( ecrRe = regexp.MustCompile("^\\d+\\.dkr\\.ecr\\.[^\\.]+\\.amazonaws\\.com$") ) @@ -55,6 +61,8 @@ type ImageName struct { Tag string Storage string Version *semver.Range + + IsOldS3Name bool } // NewFromString parses a given string and returns ImageName @@ -63,6 +71,19 @@ func NewFromString(image string) *ImageName { return New(name, tag) } +// WarnIfOldS3ImageName Check whether old image format is used. Also return warning message if yes +func WarnIfOldS3ImageName(imageName string) (bool, string) { + if !strings.HasPrefix(imageName, s3OldPrefix) { + return false, "" + } + + warning := fmt.Sprintf("Your image '%s' is using old name style (s3:/) for s3 images."+ + " This style isn't supported by docker 1.10 and would be removed from rocker in the future as well."+ + " Please consider changing to the new schema (s3.amazonaws.com//).", imageName) + + return true, warning +} + // New parses a given 'image' and 'tag' strings and returns ImageName func New(image string, tag string) *ImageName { dockerImage := &ImageName{} @@ -74,19 +95,22 @@ func New(image string, tag string) *ImageName { // default storage driver dockerImage.Storage = StorageRegistry - // In case storage is specified, e.g. s3://bucket-name/image-name - storages := []string{StorageRegistry, StorageS3} firstIsHost := false + prefix := "" - for _, storage := range storages { - prefix := storage + ":" + if strings.HasPrefix(image, s3Prefix) { + dockerImage.IsOldS3Name = false + prefix = s3Prefix - if strings.HasPrefix(image, prefix) { - image = strings.TrimPrefix(image, prefix) - dockerImage.Storage = storage - firstIsHost = true - break - } + } else if strings.HasPrefix(image, s3OldPrefix) { + dockerImage.IsOldS3Name = true + prefix = s3OldPrefix + } + + if strings.HasPrefix(image, s3Prefix) || strings.HasPrefix(image, s3OldPrefix) { + image = strings.TrimPrefix(image, prefix) + dockerImage.Storage = StorageS3 + firstIsHost = true } nameParts := strings.SplitN(image, "/", 2) @@ -243,8 +267,12 @@ func (img ImageName) NameWithRegistry() string { if img.Registry != "" { registryPrefix = img.Registry + "/" } - if img.Storage != StorageRegistry { - registryPrefix = img.Storage + ":" + registryPrefix + if img.Storage == StorageS3 { + if img.IsOldS3Name { + registryPrefix = s3OldPrefix + registryPrefix + } else { + registryPrefix = s3Prefix + registryPrefix + } } return registryPrefix + img.Name } @@ -277,13 +305,17 @@ func (img ImageName) Contains(b *ImageName) bool { } // ResolveVersion finds an applicable tag for current image among the list of available tags -func (img *ImageName) ResolveVersion(list []*ImageName) (result *ImageName) { +func (img *ImageName) ResolveVersion(list []*ImageName, strictS3Match bool) (result *ImageName) { for _, candidate := range list { // If these are different images (different names/repos) if !img.IsSameKind(*candidate) { continue } + if strictS3Match && img.IsOldS3Name != candidate.IsOldS3Name { + continue + } + // If we have a strict equality if img.HasTag() && candidate.HasTag() && img.Tag == candidate.Tag { return candidate diff --git a/vendor/github.com/grammarly/rocker/src/rocker/imagename/imagename_test.go b/vendor/github.com/grammarly/rocker/src/imagename/imagename_test.go similarity index 85% rename from vendor/github.com/grammarly/rocker/src/rocker/imagename/imagename_test.go rename to vendor/github.com/grammarly/rocker/src/imagename/imagename_test.go index a42699a..0371e63 100644 --- a/vendor/github.com/grammarly/rocker/src/rocker/imagename/imagename_test.go +++ b/vendor/github.com/grammarly/rocker/src/imagename/imagename_test.go @@ -270,7 +270,7 @@ func TestImageResolveVersion_Strict(t *testing.T) { NewFromString("golang:1.5.3"), NewFromString("golang:latest"), } - assert.Equal(t, "golang:1.5.2", img.ResolveVersion(list).String()) + assert.Equal(t, "golang:1.5.2", img.ResolveVersion(list, false).String()) } func TestImageResolveVersion_Wildcard(t *testing.T) { @@ -281,7 +281,7 @@ func TestImageResolveVersion_Wildcard(t *testing.T) { NewFromString("golang:1.5.3"), NewFromString("golang:latest"), } - assert.Equal(t, "golang:1.5.3", img.ResolveVersion(list).String()) + assert.Equal(t, "golang:1.5.3", img.ResolveVersion(list, false).String()) } func TestImageResolveVersion_WildcardMulti(t *testing.T) { @@ -293,7 +293,7 @@ func TestImageResolveVersion_WildcardMulti(t *testing.T) { NewFromString("golang:1.5.2"), NewFromString("golang:latest"), } - assert.Equal(t, "golang:1.4.2", img.ResolveVersion(list).String()) + assert.Equal(t, "golang:1.4.2", img.ResolveVersion(list, false).String()) } func TestImageResolveVersion_WildcardMatchX(t *testing.T) { @@ -306,7 +306,7 @@ func TestImageResolveVersion_WildcardMatchX(t *testing.T) { NewFromString("golang:1.5.2"), NewFromString("golang:latest"), } - assert.Equal(t, "golang:1.4.x", img.ResolveVersion(list).String()) + assert.Equal(t, "golang:1.4.x", img.ResolveVersion(list, false).String()) } func TestImageResolveVersion_WildcardMatchX2(t *testing.T) { @@ -319,7 +319,7 @@ func TestImageResolveVersion_WildcardMatchX2(t *testing.T) { NewFromString("golang:1.5.2"), NewFromString("golang:latest"), } - assert.Equal(t, "golang:1.5.2", img.ResolveVersion(list).String()) + assert.Equal(t, "golang:1.5.2", img.ResolveVersion(list, false).String()) } func TestImageResolveVersion_WildcardMatchX3(t *testing.T) { @@ -333,7 +333,7 @@ func TestImageResolveVersion_WildcardMatchX3(t *testing.T) { NewFromString("golang:1.5.2"), NewFromString("golang:latest"), } - assert.Equal(t, "golang:1.x", img.ResolveVersion(list).String()) + assert.Equal(t, "golang:1.x", img.ResolveVersion(list, false).String()) } func TestImageResolveVersion_All(t *testing.T) { @@ -343,7 +343,7 @@ func TestImageResolveVersion_All(t *testing.T) { NewFromString("golang:1.5.1"), NewFromString("golang:latest"), } - assert.Equal(t, "golang:1.5.1", img.ResolveVersion(list).String()) + assert.Equal(t, "golang:1.5.1", img.ResolveVersion(list, false).String()) } func TestImageResolveVersion_Latest(t *testing.T) { @@ -353,7 +353,7 @@ func TestImageResolveVersion_Latest(t *testing.T) { NewFromString("golang:1.5.1"), NewFromString("golang:latest"), } - assert.Equal(t, "golang:latest", img.ResolveVersion(list).String()) + assert.Equal(t, "golang:latest", img.ResolveVersion(list, false).String()) } func TestImageResolveVersion_OtherTag(t *testing.T) { @@ -364,7 +364,7 @@ func TestImageResolveVersion_OtherTag(t *testing.T) { NewFromString("golang:stable"), NewFromString("golang:latest"), } - assert.Equal(t, "golang:stable", img.ResolveVersion(list).String()) + assert.Equal(t, "golang:stable", img.ResolveVersion(list, false).String()) } func TestImageResolveVersion_NoTag(t *testing.T) { @@ -375,7 +375,7 @@ func TestImageResolveVersion_NoTag(t *testing.T) { NewFromString("golang:stable"), NewFromString("golang:latest"), } - assert.Equal(t, "golang:latest", img.ResolveVersion(list).String()) + assert.Equal(t, "golang:latest", img.ResolveVersion(list, false).String()) } func TestImageResolveVersion_NoTagOnlyLatest(t *testing.T) { @@ -384,7 +384,7 @@ func TestImageResolveVersion_NoTagOnlyLatest(t *testing.T) { NewFromString("golang:stable"), NewFromString("golang:latest"), } - assert.Equal(t, "golang:latest", img.ResolveVersion(list).String()) + assert.Equal(t, "golang:latest", img.ResolveVersion(list, false).String()) } func TestImageResolveVersion_PatchExact(t *testing.T) { @@ -397,7 +397,7 @@ func TestImageResolveVersion_PatchExact(t *testing.T) { NewFromString("golang:1.5.2"), NewFromString("golang:latest"), } - assert.Equal(t, "golang:1.4.1", img.ResolveVersion(list).String()) + assert.Equal(t, "golang:1.4.1", img.ResolveVersion(list, false).String()) } func TestImageResolveVersion_PatchMatch(t *testing.T) { @@ -409,7 +409,7 @@ func TestImageResolveVersion_PatchMatch(t *testing.T) { NewFromString("golang:1.5.2"), NewFromString("golang:latest"), } - assert.Equal(t, "golang:1.4.1-p2", img.ResolveVersion(list).String()) + assert.Equal(t, "golang:1.4.1-p2", img.ResolveVersion(list, false).String()) } func TestImageResolveVersion_PatchStrict(t *testing.T) { @@ -422,7 +422,7 @@ func TestImageResolveVersion_PatchStrict(t *testing.T) { NewFromString("golang:1.5.2"), NewFromString("golang:latest"), } - assert.Equal(t, "golang:1.4.1-p1", img.ResolveVersion(list).String()) + assert.Equal(t, "golang:1.4.1-p1", img.ResolveVersion(list, false).String()) } func TestImageResolveVersion_NotFound(t *testing.T) { @@ -432,7 +432,7 @@ func TestImageResolveVersion_NotFound(t *testing.T) { NewFromString("golang:stable"), NewFromString("golang:latest"), } - assert.Nil(t, img.ResolveVersion(list)) + assert.Nil(t, img.ResolveVersion(list, false)) } func TestImageIsSameKind(t *testing.T) { @@ -493,7 +493,7 @@ func TestImagename_ToYaml(t *testing.T) { assert.Equal(t, "name: hub/ns/name:1\n", string(data)) } -func TestImagename_S3_Basic(t *testing.T) { +func TestImagename_S3_Basic_Old(t *testing.T) { img := NewFromString("s3:bucket-name/image-name:1.2.3") assert.Equal(t, "bucket-name", img.Registry) assert.Equal(t, "image-name", img.Name) @@ -503,7 +503,7 @@ func TestImagename_S3_Basic(t *testing.T) { assert.Equal(t, "s3:bucket-name/image-name:1.2.3", img.String()) } -func TestImagename_S3_Digest(t *testing.T) { +func TestImagename_S3_Digest_Old(t *testing.T) { img := NewFromString("s3:bucket-name/image-name@sha256:ead434cd278824865d6e3b67e5d4579ded02eb2e8367fc165efa21138b225f11") assert.Equal(t, "bucket-name", img.Registry) assert.Equal(t, "image-name", img.Name) @@ -514,7 +514,7 @@ func TestImagename_S3_Digest(t *testing.T) { assert.Equal(t, "s3:bucket-name/image-name@sha256:ead434cd278824865d6e3b67e5d4579ded02eb2e8367fc165efa21138b225f11", img.String()) } -func TestImagename_S3_Sha(t *testing.T) { +func TestImagename_S3_Sha_Old(t *testing.T) { img := NewFromString("s3:bucket-name/image-name:sha256-ead434cd278824865d6e3b67e5d4579ded02eb2e8367fc165efa21138b225f11") assert.Equal(t, "bucket-name", img.Registry) assert.Equal(t, "image-name", img.Name) @@ -524,3 +524,35 @@ func TestImagename_S3_Sha(t *testing.T) { assert.Equal(t, "sha256-ead434cd278824865d6e3b67e5d4579ded02eb2e8367fc165efa21138b225f11", img.GetTag()) assert.Equal(t, "s3:bucket-name/image-name:sha256-ead434cd278824865d6e3b67e5d4579ded02eb2e8367fc165efa21138b225f11", img.String()) } + +func TestImagename_S3_Basic(t *testing.T) { + img := NewFromString("s3.amazonaws.com/bucket-name/image-name:1.2.3") + assert.Equal(t, "bucket-name", img.Registry) + assert.Equal(t, "image-name", img.Name) + assert.Equal(t, false, img.TagIsSha()) + assert.Equal(t, "1.2.3", img.GetTag()) + assert.Equal(t, "s3.amazonaws.com/bucket-name/image-name", img.NameWithRegistry()) + assert.Equal(t, "s3.amazonaws.com/bucket-name/image-name:1.2.3", img.String()) +} + +func TestImagename_S3_Digest(t *testing.T) { + img := NewFromString("s3.amazonaws.com/bucket-name/image-name@sha256:ead434cd278824865d6e3b67e5d4579ded02eb2e8367fc165efa21138b225f11") + assert.Equal(t, "bucket-name", img.Registry) + assert.Equal(t, "image-name", img.Name) + assert.Equal(t, true, img.TagIsSha()) + assert.Equal(t, true, img.TagIsDigest()) + assert.Equal(t, "s3.amazonaws.com/bucket-name/image-name", img.NameWithRegistry()) + assert.Equal(t, "sha256:ead434cd278824865d6e3b67e5d4579ded02eb2e8367fc165efa21138b225f11", img.GetTag()) + assert.Equal(t, "s3.amazonaws.com/bucket-name/image-name@sha256:ead434cd278824865d6e3b67e5d4579ded02eb2e8367fc165efa21138b225f11", img.String()) +} + +func TestImagename_S3_Sha(t *testing.T) { + img := NewFromString("s3.amazonaws.com/bucket-name/image-name:sha256-ead434cd278824865d6e3b67e5d4579ded02eb2e8367fc165efa21138b225f11") + assert.Equal(t, "bucket-name", img.Registry) + assert.Equal(t, "image-name", img.Name) + assert.Equal(t, true, img.TagIsSha()) + assert.Equal(t, false, img.TagIsDigest()) + assert.Equal(t, "s3.amazonaws.com/bucket-name/image-name", img.NameWithRegistry()) + assert.Equal(t, "sha256-ead434cd278824865d6e3b67e5d4579ded02eb2e8367fc165efa21138b225f11", img.GetTag()) + assert.Equal(t, "s3.amazonaws.com/bucket-name/image-name:sha256-ead434cd278824865d6e3b67e5d4579ded02eb2e8367fc165efa21138b225f11", img.String()) +} diff --git a/vendor/github.com/grammarly/rocker/src/rocker/storage/s3/logger.go b/vendor/github.com/grammarly/rocker/src/storage/s3/logger.go similarity index 100% rename from vendor/github.com/grammarly/rocker/src/rocker/storage/s3/logger.go rename to vendor/github.com/grammarly/rocker/src/storage/s3/logger.go diff --git a/vendor/github.com/grammarly/rocker/src/rocker/storage/s3/retryer.go b/vendor/github.com/grammarly/rocker/src/storage/s3/retryer.go similarity index 100% rename from vendor/github.com/grammarly/rocker/src/rocker/storage/s3/retryer.go rename to vendor/github.com/grammarly/rocker/src/storage/s3/retryer.go diff --git a/vendor/github.com/grammarly/rocker/src/rocker/storage/s3/s3.go b/vendor/github.com/grammarly/rocker/src/storage/s3/s3.go similarity index 97% rename from vendor/github.com/grammarly/rocker/src/rocker/storage/s3/s3.go rename to vendor/github.com/grammarly/rocker/src/storage/s3/s3.go index bb954a2..83c334a 100644 --- a/vendor/github.com/grammarly/rocker/src/rocker/storage/s3/s3.go +++ b/vendor/github.com/grammarly/rocker/src/storage/s3/s3.go @@ -21,14 +21,13 @@ import ( "crypto/sha256" "encoding/json" "fmt" + "github.com/grammarly/rocker/src/imagename" "io" "io/ioutil" "os" "path/filepath" "strings" - "github.com/grammarly/rocker/src/rocker/imagename" - log "github.com/Sirupsen/logrus" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" @@ -156,7 +155,7 @@ func (s *StorageS3) Push(imageName string) (digest string, err error) { } defer fd.Close() - log.Infof("| Uploading image to s3://%s/%s", img.Registry, imgPathDigest) + log.Infof("| Uploading image to s3.amazonaws.com/%s/%s", img.Registry, imgPathDigest) uploadParams := &s3manager.UploadInput{ Bucket: aws.String(img.Registry), @@ -185,7 +184,7 @@ func (s *StorageS3) Push(imageName string) (digest string, err error) { Key: aws.String(imgPathTag), } - log.Infof("| Make alias s3://%s/%s", img.Registry, imgPathTag) + log.Infof("| Make alias s3.amazonaws.com/%s/%s", img.Registry, imgPathTag) if _, err = s.s3.CopyObject(copyParams); err != nil { return "", fmt.Errorf("Failed to PUT object to S3, error: %s", err) @@ -227,7 +226,7 @@ func (s *StorageS3) Pull(name string) error { } ) - log.Infof("| Import s3://%s/%s to %s", img.Registry, imgPath, tmpf.Name()) + log.Infof("| Import %s/%s.tar to %s", img.NameWithRegistry(), img.Tag, tmpf.Name()) if err := s.retryer.Outer(func() error { _, err := downloader.Download(tmpf, downloadParams) @@ -484,7 +483,7 @@ func (s *StorageS3) ListTags(imageName string) (images []*imagename.ImageName, e } imgName := strings.Join(split[:len(split)-1], "/") - imgName = fmt.Sprintf("s3:%s/%s", image.Registry, imgName) + imgName = fmt.Sprintf("s3.amazonaws.com/%s/%s", image.Registry, imgName) tag := strings.TrimSuffix(split[len(split)-1], ".tar") candidate := imagename.New(imgName, tag) diff --git a/vendor/github.com/grammarly/rocker/src/rocker/storage/storage.go b/vendor/github.com/grammarly/rocker/src/storage/storage.go similarity index 95% rename from vendor/github.com/grammarly/rocker/src/rocker/storage/storage.go rename to vendor/github.com/grammarly/rocker/src/storage/storage.go index 1945917..6b16b81 100644 --- a/vendor/github.com/grammarly/rocker/src/rocker/storage/storage.go +++ b/vendor/github.com/grammarly/rocker/src/storage/storage.go @@ -17,7 +17,7 @@ package storage import ( - "rocker/imagename" + "github.com/grammarly/rocker/src/imagename" "github.com/fsouza/go-dockerclient" ) diff --git a/vendor/github.com/grammarly/rocker/src/rocker/template/LICENSE b/vendor/github.com/grammarly/rocker/src/template/LICENSE similarity index 100% rename from vendor/github.com/grammarly/rocker/src/rocker/template/LICENSE rename to vendor/github.com/grammarly/rocker/src/template/LICENSE diff --git a/vendor/github.com/grammarly/rocker/src/rocker/template/Makefile b/vendor/github.com/grammarly/rocker/src/template/Makefile similarity index 100% rename from vendor/github.com/grammarly/rocker/src/rocker/template/Makefile rename to vendor/github.com/grammarly/rocker/src/template/Makefile diff --git a/vendor/github.com/grammarly/rocker/src/rocker/template/README.md b/vendor/github.com/grammarly/rocker/src/template/README.md similarity index 100% rename from vendor/github.com/grammarly/rocker/src/rocker/template/README.md rename to vendor/github.com/grammarly/rocker/src/template/README.md diff --git a/vendor/github.com/grammarly/rocker/src/rocker/template/shellarg.go b/vendor/github.com/grammarly/rocker/src/template/shellarg.go similarity index 100% rename from vendor/github.com/grammarly/rocker/src/rocker/template/shellarg.go rename to vendor/github.com/grammarly/rocker/src/template/shellarg.go diff --git a/vendor/github.com/grammarly/rocker/src/rocker/template/shellarg_test.go b/vendor/github.com/grammarly/rocker/src/template/shellarg_test.go similarity index 100% rename from vendor/github.com/grammarly/rocker/src/rocker/template/shellarg_test.go rename to vendor/github.com/grammarly/rocker/src/template/shellarg_test.go diff --git a/vendor/github.com/grammarly/rocker/src/rocker/template/template.go b/vendor/github.com/grammarly/rocker/src/template/template.go similarity index 99% rename from vendor/github.com/grammarly/rocker/src/rocker/template/template.go rename to vendor/github.com/grammarly/rocker/src/template/template.go index 6e51654..e47d76a 100644 --- a/vendor/github.com/grammarly/rocker/src/rocker/template/template.go +++ b/vendor/github.com/grammarly/rocker/src/template/template.go @@ -20,6 +20,7 @@ import ( "bytes" "encoding/json" "fmt" + "github.com/grammarly/rocker/src/imagename" "io" "io/ioutil" "os" @@ -29,8 +30,6 @@ import ( "strings" "text/template" - "github.com/grammarly/rocker/src/rocker/imagename" - "github.com/go-yaml/yaml" "github.com/kr/pretty" diff --git a/vendor/github.com/grammarly/rocker/src/rocker/template/template_test.go b/vendor/github.com/grammarly/rocker/src/template/template_test.go similarity index 99% rename from vendor/github.com/grammarly/rocker/src/rocker/template/template_test.go rename to vendor/github.com/grammarly/rocker/src/template/template_test.go index 654b4ff..c2af074 100644 --- a/vendor/github.com/grammarly/rocker/src/rocker/template/template_test.go +++ b/vendor/github.com/grammarly/rocker/src/template/template_test.go @@ -18,12 +18,11 @@ package template import ( "fmt" + "github.com/grammarly/rocker/src/imagename" "os" "strings" "testing" - "github.com/grammarly/rocker/src/rocker/imagename" - "github.com/stretchr/testify/assert" ) diff --git a/vendor/github.com/grammarly/rocker/src/rocker/template/testdata/content.txt b/vendor/github.com/grammarly/rocker/src/template/testdata/content.txt similarity index 100% rename from vendor/github.com/grammarly/rocker/src/rocker/template/testdata/content.txt rename to vendor/github.com/grammarly/rocker/src/template/testdata/content.txt diff --git a/vendor/github.com/grammarly/rocker/src/rocker/template/vars.go b/vendor/github.com/grammarly/rocker/src/template/vars.go similarity index 99% rename from vendor/github.com/grammarly/rocker/src/rocker/template/vars.go rename to vendor/github.com/grammarly/rocker/src/template/vars.go index 52323ce..a14b248 100644 --- a/vendor/github.com/grammarly/rocker/src/rocker/template/vars.go +++ b/vendor/github.com/grammarly/rocker/src/template/vars.go @@ -19,6 +19,7 @@ package template import ( "encoding/json" "fmt" + "github.com/grammarly/rocker/src/imagename" "io/ioutil" "os" "path" @@ -28,8 +29,6 @@ import ( "sort" "strings" - "github.com/grammarly/rocker/src/rocker/imagename" - "github.com/go-yaml/yaml" log "github.com/Sirupsen/logrus" diff --git a/vendor/github.com/grammarly/rocker/src/rocker/template/vars_test.go b/vendor/github.com/grammarly/rocker/src/template/vars_test.go similarity index 98% rename from vendor/github.com/grammarly/rocker/src/rocker/template/vars_test.go rename to vendor/github.com/grammarly/rocker/src/template/vars_test.go index a942a99..cc71893 100644 --- a/vendor/github.com/grammarly/rocker/src/rocker/template/vars_test.go +++ b/vendor/github.com/grammarly/rocker/src/template/vars_test.go @@ -19,14 +19,13 @@ package template import ( "encoding/json" "fmt" + "github.com/grammarly/rocker/src/imagename" + "github.com/grammarly/rocker/src/test" "io/ioutil" "os" "path" "testing" - "github.com/grammarly/rocker/src/rocker/imagename" - "github.com/grammarly/rocker/src/rocker/test" - "github.com/stretchr/testify/assert" ) diff --git a/vendor/github.com/grammarly/rocker/src/util/cmd.go b/vendor/github.com/grammarly/rocker/src/util/cmd.go new file mode 100644 index 0000000..25124ce --- /dev/null +++ b/vendor/github.com/grammarly/rocker/src/util/cmd.go @@ -0,0 +1,125 @@ +/*- + * Copyright 2015 Grammarly, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package util + +// TODO: this stuff is smelling and should be refactored + +import ( + "bufio" + "bytes" + "fmt" + "io" + "os/exec" + "strings" + "syscall" +) + +// Cmd is a wrapper over os/exec and provides extra convenience stuff +type Cmd struct { + Args []string + Env []string + Dir string + Stream io.Writer + Reader *io.PipeReader + Writer *io.PipeWriter + ExitStatus int + Error error +} + +// Pipe pipes cmd stdout/stderr to a given io.Writer +func (cmd *Cmd) Pipe(writer io.Writer) error { + scanner := bufio.NewScanner(cmd.Reader) + for scanner.Scan() { + writer.Write(scanner.Bytes()) + writer.Write([]byte("\n")) + } + return scanner.Err() +} + +// String returns debug representation of the Cmd +func (cmd *Cmd) String() string { + if len(cmd.Env) > 0 { + return fmt.Sprintf("%s [Env %s] [Dir %s]", strings.Join(cmd.Args, " "), strings.Join(cmd.Env, " "), cmd.Dir) + } + return fmt.Sprintf("%s [Dir %s]", strings.Join(cmd.Args, " "), cmd.Dir) +} + +// ExecPipe executes the command and returns its output, exit code and error +func ExecPipe(cmd *Cmd) (string, int, error) { + var output bytes.Buffer + cmd, err := Exec(cmd) + if err != nil { + return "", 0, err + } + err = cmd.Pipe(&output) + if err != nil { + return "", 0, err + } + return output.String(), cmd.ExitStatus, cmd.Error +} + +// Exec runs the command and grabs exit code at the end +// If Stream property is present, then it also pipes stdout/stderr to it +func Exec(cmd *Cmd) (*Cmd, error) { + reader, writer := io.Pipe() + + cmd.Reader = reader + cmd.Writer = writer + + execCmd := &exec.Cmd{ + Path: cmd.Args[0], + Args: cmd.Args, + Env: cmd.Env, + Dir: cmd.Dir, + } + + execCmd.Stdout = cmd.Writer + execCmd.Stderr = cmd.Writer + + go func() { + defer cmd.Writer.Close() + err := execCmd.Start() + if err != nil { + cmd.Error = err + return + } + if err = execCmd.Wait(); err != nil { + if exiterr, ok := err.(*exec.ExitError); ok { + // The program has exited with an exit code != 0 + + // This works on both Unix and Windows. Although package + // syscall is generally platform dependent, WaitStatus is + // defined for both Unix and Windows and in both cases has + // an ExitStatus() method with the same signature. + if status, ok := exiterr.Sys().(syscall.WaitStatus); ok { + cmd.ExitStatus = status.ExitStatus() + } + } else { + cmd.Error = err + } + } + }() + + if cmd.Stream != nil { + err := cmd.Pipe(cmd.Stream) + if err != nil { + return cmd, err + } + } + + return cmd, nil +} diff --git a/vendor/github.com/grammarly/rocker/src/util/cmd_test.go b/vendor/github.com/grammarly/rocker/src/util/cmd_test.go new file mode 100644 index 0000000..1a15a4c --- /dev/null +++ b/vendor/github.com/grammarly/rocker/src/util/cmd_test.go @@ -0,0 +1,91 @@ +/*- + * Copyright 2015 Grammarly, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package util + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestExecBase(t *testing.T) { + cmd, err := Exec(&Cmd{ + Args: []string{"testdata/prog"}, + }) + if err != nil { + t.Fatal(err) + } + + var buf bytes.Buffer + err = cmd.Pipe(&buf) + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, "1 stdout\n1 stderr\n2 stdout\n2 stderr\n3 stdout\n3 stderr\n4 stdout\n4 stderr\n5 stdout\n5 stderr\n", buf.String()) + assert.Equal(t, 0, cmd.ExitStatus) +} + +func TestExecStream(t *testing.T) { + var buf bytes.Buffer + + cmd, err := Exec(&Cmd{ + Args: []string{"testdata/prog"}, + Stream: &buf, + }) + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, "1 stdout\n1 stderr\n2 stdout\n2 stderr\n3 stdout\n3 stderr\n4 stdout\n4 stderr\n5 stdout\n5 stderr\n", buf.String()) + assert.Equal(t, 0, cmd.ExitStatus) +} + +func TestExecPipe(t *testing.T) { + output, exitStatus, err := ExecPipe(&Cmd{ + Args: []string{"testdata/prog"}, + }) + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, "1 stdout\n1 stderr\n2 stdout\n2 stderr\n3 stdout\n3 stderr\n4 stdout\n4 stderr\n5 stdout\n5 stderr\n", output) + assert.Equal(t, 0, exitStatus) +} + +func TestExecPipeError(t *testing.T) { + output, exitStatus, err := ExecPipe(&Cmd{ + Args: []string{"klwemlwkemw"}, + }) + + assert.Equal(t, "", output, "expected error to be") + assert.Equal(t, "fork/exec klwemlwkemw: no such file or directory", err.Error(), "expected error to be") + assert.Equal(t, 0, exitStatus) +} + +func TestExecPipeExitStatus(t *testing.T) { + output, exitStatus, err := ExecPipe(&Cmd{ + Args: []string{"testdata/prog", "1"}, + }) + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, "1 stdout\n1 stderr\n2 stdout\n2 stderr\n3 stdout\n3 stderr\n4 stdout\n4 stderr\n5 stdout\n5 stderr\n", output) + assert.Equal(t, 1, exitStatus) +} diff --git a/vendor/github.com/grammarly/rocker/src/rocker/storage/s3/s3_test.go b/vendor/github.com/grammarly/rocker/src/util/doc.go similarity index 55% rename from vendor/github.com/grammarly/rocker/src/rocker/storage/s3/s3_test.go rename to vendor/github.com/grammarly/rocker/src/util/doc.go index 85b6b2c..b577df0 100644 --- a/vendor/github.com/grammarly/rocker/src/rocker/storage/s3/s3_test.go +++ b/vendor/github.com/grammarly/rocker/src/util/doc.go @@ -1,5 +1,3 @@ -// +build integration - /*- * Copyright 2015 Grammarly, Inc. * @@ -16,32 +14,6 @@ * limitations under the License. */ -// Run the test like this: -// GOPATH=`pwd`:`pwd`/vendor go test -v rocker/storage/s3 -tags="integration" - -package s3 - -import ( - "os" - "rocker/dockerclient" - "testing" - - "github.com/kr/pretty" -) - -func TestStorageS3_Basic(t *testing.T) { - client, err := dockerclient.New() - if err != nil { - t.Fatal(err) - } - - s := New(client) - - tmpf, digest, err := s.MakeTar("alpine-s3:0.2") - if err != nil { - t.Fatal(err) - } - defer os.Remove(tmpf) - - pretty.Println(digest, tmpf) -} +// Package util provide different utilities that are used by rocker +// TODO: this should be refactored to a different packages +package util diff --git a/vendor/github.com/grammarly/rocker/src/util/filepath.go b/vendor/github.com/grammarly/rocker/src/util/filepath.go new file mode 100644 index 0000000..2e02d92 --- /dev/null +++ b/vendor/github.com/grammarly/rocker/src/util/filepath.go @@ -0,0 +1,78 @@ +/*- + * Copyright 2015 Grammarly, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package util + +import ( + "fmt" + "os" + "os/user" + "path" + "path/filepath" + "strings" +) + +// ResolvePath resolves the subPath from baseDir such that the resultig path cannot +// go outside the baseDir +func ResolvePath(baseDir, subPath string) (resultPath string, err error) { + resultPath = path.Join(baseDir, subPath) + + // path.Join cleans the path and removes trailing slash if it's not the root path + // but we want to preserve trailing slash instead + if subPath[len(subPath)-1:] == "/" && resultPath[len(resultPath)-1:] != "/" { + resultPath = resultPath + "/" + } + + if resultPath == baseDir { + return resultPath, nil + } + + if !strings.HasPrefix(resultPath, baseDir+"/") { + return resultPath, fmt.Errorf("Invalid path: %s", subPath) + } + + return resultPath, nil +} + +// MakeAbsolute makes any path absolute, either according to a HOME or from a working directory +func MakeAbsolute(path string) (result string, err error) { + result = filepath.Clean(path) + if filepath.IsAbs(result) { + return result, nil + } + + if strings.HasPrefix(result, "~/") || result == "~" { + home := os.Getenv("HOME") + + // fallback to system user info + if home == "" { + usr, err := user.Current() + if err != nil { + return "", err + } + home = usr.HomeDir + } + + return home + result[1:], nil + } + + wd, err := os.Getwd() + if err != nil { + return "", err + } + + return filepath.Join(wd, path), nil +} diff --git a/vendor/github.com/grammarly/rocker/src/util/io.go b/vendor/github.com/grammarly/rocker/src/util/io.go new file mode 100644 index 0000000..9876542 --- /dev/null +++ b/vendor/github.com/grammarly/rocker/src/util/io.go @@ -0,0 +1,40 @@ +/*- + * Copyright 2015 Grammarly, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package util + +import ( + "bufio" + "fmt" + "io" +) + +// PrefixPipe creates an io wrapper that will add [prefix] to every line written +func PrefixPipe(prefix string, writer io.Writer) io.Writer { + reader, proxy := io.Pipe() + + go func(prefix string, reader io.Reader, writer io.Writer) { + scanner := bufio.NewScanner(reader) + for scanner.Scan() { + writer.Write([]byte(prefix + scanner.Text() + "\n")) + } + if scannererr := scanner.Err(); scannererr != nil { + fmt.Fprint(writer, scannererr) + } + }(prefix, reader, writer) + + return proxy +} diff --git a/vendor/github.com/grammarly/rocker/src/util/testdata/prog b/vendor/github.com/grammarly/rocker/src/util/testdata/prog new file mode 100644 index 0000000..d809216 --- /dev/null +++ b/vendor/github.com/grammarly/rocker/src/util/testdata/prog @@ -0,0 +1,8 @@ +#!/bin/bash +for i in {1..5}; do + echo "$i stdout" + >&2 echo "$i stderr" + sleep .05 +done + +exit $1 diff --git a/vendor/manifest b/vendor/manifest index 38a3940..d2c0a4c 100644 --- a/vendor/manifest +++ b/vendor/manifest @@ -1,42 +1,18 @@ { "version": 0, "dependencies": [ - { - "importpath": "github.com/go-yaml/yaml", - "repository": "https://github.com/go-yaml/yaml", - "revision": "7ad95dd0798a40da1ccdff6dff35fd177b5edf40", - "branch": "v2" - }, - { - "importpath": "github.com/stretchr/testify", - "repository": "https://github.com/stretchr/testify", - "revision": "089c7181b8c728499929ff09b62d3fdd8df8adff", - "branch": "master" - }, - { - "importpath": "github.com/kr/pretty", - "repository": "https://github.com/kr/pretty", - "revision": "e6ac2fc51e89a3249e82157fa0bb7a18ef9dd5bb", - "branch": "master" - }, - { - "importpath": "github.com/kr/text", - "repository": "https://github.com/kr/text", - "revision": "e373e137fafd8abd480af49182dea0513914adb4", - "branch": "master" - }, - { - "importpath": "github.com/stretchr/objx", - "repository": "https://github.com/stretchr/objx", - "revision": "cbeaeb16a013161a98496fad62933b1d21786672", - "branch": "master" - }, { "importpath": "github.com/Sirupsen/logrus", "repository": "https://github.com/Sirupsen/logrus", "revision": "93a1736895ca25a01a739e0394bf7f672299a27d", "branch": "master" }, + { + "importpath": "github.com/aws/aws-sdk-go", + "repository": "https://github.com/aws/aws-sdk-go", + "revision": "c924893c38ecc04b18d7aab8a7aa561cb8b4c4cc", + "branch": "master" + }, { "importpath": "github.com/codegangsta/cli", "repository": "https://github.com/codegangsta/cli", @@ -50,6 +26,13 @@ "branch": "master", "path": "/pkg/jsonmessage" }, + { + "importpath": "github.com/docker/docker/pkg/signal", + "repository": "https://github.com/docker/docker", + "revision": "92487d7fb4963c0333c409d053ff694e619c538d", + "branch": "master", + "path": "/pkg/signal" + }, { "importpath": "github.com/docker/docker/pkg/term", "repository": "https://github.com/docker/docker", @@ -72,30 +55,50 @@ "path": "/pkg/units" }, { - "importpath": "github.com/grammarly/rocker/src/rocker/test", + "importpath": "github.com/fsouza/go-dockerclient", + "repository": "https://github.com/fsouza/go-dockerclient", + "revision": "c9ad0ce23f68428421adfc6ced9e6123f54788a5", + "branch": "HEAD" + }, + { + "importpath": "github.com/go-ini/ini", + "repository": "https://github.com/go-ini/ini", + "revision": "9f4d2712cf687b68fad24366f81eaee163079090", + "branch": "v1" + }, + { + "importpath": "github.com/go-yaml/yaml", + "repository": "https://github.com/go-yaml/yaml", + "revision": "7ad95dd0798a40da1ccdff6dff35fd177b5edf40", + "branch": "v2" + }, + { + "importpath": "github.com/grammarly/rocker/src/dockerclient", "repository": "https://github.com/grammarly/rocker", - "revision": "79bcadfcce121a8d9fa0f84e231314c6374bf8f3", + "revision": "ec7c40b0d139303db89add1fbdde15d321142e53", "branch": "master", - "path": "/src/rocker/test" + "path": "/src/dockerclient" }, { - "importpath": "github.com/grammarly/rocker/src/rocker/util", + "importpath": "github.com/grammarly/rocker/src/imagename", "repository": "https://github.com/grammarly/rocker", - "revision": "79bcadfcce121a8d9fa0f84e231314c6374bf8f3", + "revision": "ec7c40b0d139303db89add1fbdde15d321142e53", "branch": "master", - "path": "/src/rocker/util" + "path": "/src/imagename" }, { - "importpath": "github.com/fsouza/go-dockerclient", - "repository": "https://github.com/fsouza/go-dockerclient", - "revision": "c9ad0ce23f68428421adfc6ced9e6123f54788a5", - "branch": "HEAD" + "importpath": "github.com/grammarly/rocker/src/rocker/debugtrap", + "repository": "https://github.com/grammarly/rocker", + "revision": "d6a4bbfc503169324de3462a2ae2bb5a5dc2f041", + "branch": "v1", + "path": "/src/rocker/debugtrap" }, { - "importpath": "github.com/wmark/semver", - "repository": "https://github.com/wmark/semver", - "revision": "461c06b538be53cc0339815001a398e29ace025b", - "branch": "master" + "importpath": "github.com/grammarly/rocker/src/rocker/test", + "repository": "https://github.com/grammarly/rocker", + "revision": "79bcadfcce121a8d9fa0f84e231314c6374bf8f3", + "branch": "master", + "path": "/src/rocker/test" }, { "importpath": "github.com/grammarly/rocker/src/rocker/textformatter", @@ -105,37 +108,32 @@ "path": "/src/rocker/textformatter" }, { - "importpath": "github.com/grammarly/rocker/src/rocker/template", + "importpath": "github.com/grammarly/rocker/src/rocker/util", "repository": "https://github.com/grammarly/rocker", - "revision": "3b5905678b83b1b5cc4f22557bed523ff4d2438e", - "branch": "v1", - "path": "/src/rocker/template" - }, - { - "importpath": "github.com/mitchellh/go-homedir", - "repository": "https://github.com/mitchellh/go-homedir", - "revision": "d682a8f0cf139663a984ff12528da460ca963de9", - "branch": "master" + "revision": "79bcadfcce121a8d9fa0f84e231314c6374bf8f3", + "branch": "master", + "path": "/src/rocker/util" }, { - "importpath": "github.com/docker/docker/pkg/signal", - "repository": "https://github.com/docker/docker", - "revision": "92487d7fb4963c0333c409d053ff694e619c538d", + "importpath": "github.com/grammarly/rocker/src/storage", + "repository": "https://github.com/grammarly/rocker", + "revision": "ec7c40b0d139303db89add1fbdde15d321142e53", "branch": "master", - "path": "/pkg/signal" + "path": "/src/storage" }, { - "importpath": "github.com/grammarly/rocker/src/rocker/debugtrap", + "importpath": "github.com/grammarly/rocker/src/template", "repository": "https://github.com/grammarly/rocker", - "revision": "d6a4bbfc503169324de3462a2ae2bb5a5dc2f041", - "branch": "v1", - "path": "/src/rocker/debugtrap" + "revision": "ec7c40b0d139303db89add1fbdde15d321142e53", + "branch": "master", + "path": "/src/template" }, { - "importpath": "github.com/go-ini/ini", - "repository": "https://github.com/go-ini/ini", - "revision": "9f4d2712cf687b68fad24366f81eaee163079090", - "branch": "v1" + "importpath": "github.com/grammarly/rocker/src/util", + "repository": "https://github.com/grammarly/rocker", + "revision": "ec7c40b0d139303db89add1fbdde15d321142e53", + "branch": "master", + "path": "/src/util" }, { "importpath": "github.com/jmespath/go-jmespath", @@ -144,31 +142,40 @@ "branch": "master" }, { - "importpath": "github.com/grammarly/rocker/src/rocker/storage", - "repository": "https://github.com/grammarly/rocker", - "revision": "d0220cddfa1bcd107db138498c0f4de5d9f0ecc2", - "branch": "f-s3", - "path": "/src/rocker/storage" + "importpath": "github.com/kr/pretty", + "repository": "https://github.com/kr/pretty", + "revision": "e6ac2fc51e89a3249e82157fa0bb7a18ef9dd5bb", + "branch": "master" }, { - "importpath": "github.com/grammarly/rocker/src/rocker/imagename", - "repository": "https://github.com/grammarly/rocker", - "revision": "fb14fe236b5675a3491e9c948ba01c43432252db", - "branch": "dev", - "path": "/src/rocker/imagename" + "importpath": "github.com/kr/text", + "repository": "https://github.com/kr/text", + "revision": "e373e137fafd8abd480af49182dea0513914adb4", + "branch": "master" }, { - "importpath": "github.com/grammarly/rocker/src/rocker/dockerclient", - "repository": "https://github.com/grammarly/rocker", - "revision": "fb14fe236b5675a3491e9c948ba01c43432252db", - "branch": "dev", - "path": "/src/rocker/dockerclient" + "importpath": "github.com/mitchellh/go-homedir", + "repository": "https://github.com/mitchellh/go-homedir", + "revision": "d682a8f0cf139663a984ff12528da460ca963de9", + "branch": "master" }, { - "importpath": "github.com/aws/aws-sdk-go", - "repository": "https://github.com/aws/aws-sdk-go", - "revision": "c924893c38ecc04b18d7aab8a7aa561cb8b4c4cc", + "importpath": "github.com/stretchr/objx", + "repository": "https://github.com/stretchr/objx", + "revision": "cbeaeb16a013161a98496fad62933b1d21786672", + "branch": "master" + }, + { + "importpath": "github.com/stretchr/testify", + "repository": "https://github.com/stretchr/testify", + "revision": "089c7181b8c728499929ff09b62d3fdd8df8adff", + "branch": "master" + }, + { + "importpath": "github.com/wmark/semver", + "repository": "https://github.com/wmark/semver", + "revision": "461c06b538be53cc0339815001a398e29ace025b", "branch": "master" } ] -} +} \ No newline at end of file