diff --git a/acceptance/acceptance_test.go b/acceptance/acceptance_test.go index 99f1e7101e..092474aa32 100644 --- a/acceptance/acceptance_test.go +++ b/acceptance/acceptance_test.go @@ -113,7 +113,7 @@ func testPack(t *testing.T, when spec.G, it spec.S) { when("'--publish' flag is not specified'", func() { it("builds and exports an image", func() { - cmd := exec.Command(pack, "build", repoName, "-p", sourceCodePath, "--detect-image", "packsdev/v3:detect") + cmd := exec.Command(pack, "build", repoName, "-p", sourceCodePath) cmd.Env = append(os.Environ(), "HOME="+homeDir) run(t, cmd) @@ -135,7 +135,7 @@ func testPack(t *testing.T, when spec.G, it spec.S) { it("builds and exports an image", func() { runPackBuild := func() string { t.Helper() - cmd := exec.Command(pack, "build", repoName, "-p", sourceCodePath, "--detect-image", "packsdev/v3:detect", "--publish") + cmd := exec.Command(pack, "build", repoName, "-p", sourceCodePath, "--publish") cmd.Env = append(os.Environ(), "HOME="+homeDir) return run(t, cmd) } @@ -269,7 +269,7 @@ func testPack(t *testing.T, when spec.G, it spec.S) { }) }, spec.Parallel(), spec.Report(report.Terminal{})) - when("create, build, run", func() { + when.Pend("create, build, run", func() { var tmpDir, detectImageName, buildImageName, repoName, containerName, registryContainerName, registry string it.Before(func() { diff --git a/analyzer.go b/analyzer.go index 33ca600b4d..b10ad58021 100644 --- a/analyzer.go +++ b/analyzer.go @@ -1,34 +1,56 @@ package pack import ( + "context" + "encoding/json" "os" "github.com/buildpack/lifecycle" "github.com/buildpack/packs" + dockercli "github.com/docker/docker/client" ) -func analyzer(group lifecycle.BuildpackGroup, launchDir, repoName string, useDaemon bool) error { - origImage, err := readImage(repoName, useDaemon) - if err != nil { - return err - } - - if origImage == nil { - // no previous image to analyze - return nil - } - +func analyzer(group lifecycle.BuildpackGroup, workspaceDir, repoName string, useDaemon bool) error { analyzer := &lifecycle.Analyzer{ Buildpacks: group.Buildpacks, Out: os.Stdout, Err: os.Stderr, } - err = analyzer.Analyze( - launchDir, - origImage, - ) - if err != nil { - return packs.FailErrCode(err, packs.CodeFailedBuild) + + if useDaemon { + cli, err := dockercli.NewEnvClient() + if err != nil { + return packs.FailErrCode(err, packs.CodeFailedBuild) + } + i, _, err := cli.ImageInspectWithRaw(context.Background(), repoName) + if err != nil { + if dockercli.IsErrNotFound(err) { + // images does not already exist, skip analyze + return nil + } + return packs.FailErrCode(err, packs.CodeFailedBuild) + } + var config lifecycle.AppImageMetadata + if err := json.Unmarshal([]byte(i.Config.Labels["sh.packs.build"]), &config); err != nil { + return packs.FailErrCode(err, packs.CodeFailedBuild) + } + if err := analyzer.AnalyzeConfig(workspaceDir, config); err != nil { + return packs.FailErrCode(err, packs.CodeFailedBuild) + } + } else { + origImage, err := readImage(repoName, useDaemon) + if err != nil { + return err + } + + if origImage == nil { + // no previous image to analyze + return nil + } + + if err := analyzer.Analyze(workspaceDir, origImage); err != nil { + return packs.FailErrCode(err, packs.CodeFailedBuild) + } } return nil diff --git a/build.go b/build.go index a06ef89910..8a75bebb1a 100644 --- a/build.go +++ b/build.go @@ -14,20 +14,22 @@ import ( "github.com/google/uuid" ) -func Build(appDir, detectImage, repoName string, publish bool) error { +func Build(appDir, buildImage, runImage, repoName string, publish bool) error { return (&BuildFlags{ - AppDir: appDir, - DetectImage: detectImage, - RepoName: repoName, - Publish: publish, + AppDir: appDir, + BuildImage: buildImage, + RunImage: runImage, + RepoName: repoName, + Publish: publish, }).Run() } type BuildFlags struct { - AppDir string - DetectImage string - RepoName string - Publish bool + AppDir string + BuildImage string + RunImage string + RepoName string + Publish bool } func (b *BuildFlags) Run() error { @@ -38,26 +40,24 @@ func (b *BuildFlags) Run() error { } uid := uuid.New().String() - launchVolume := fmt.Sprintf("pack-launch-%x", uid) workspaceVolume := fmt.Sprintf("pack-workspace-%x", uid) cacheVolume := fmt.Sprintf("pack-cache-%x", md5.Sum([]byte(b.AppDir))) - defer exec.Command("docker", "volume", "rm", "-f", launchVolume).Run() defer exec.Command("docker", "volume", "rm", "-f", workspaceVolume).Run() - // fmt.Println("*** COPY APP TO VOLUME:") - if err := copyToVolume(b.DetectImage, launchVolume, b.AppDir, "app"); err != nil { + fmt.Println("*** COPY APP TO VOLUME:") + if err := copyToVolume(b.BuildImage, workspaceVolume, b.AppDir, "app"); err != nil { return err } fmt.Println("*** DETECTING:") - cmd := exec.Command("docker", "run", "--rm", "-v", launchVolume+":/launch", "-v", workspaceVolume+":/workspace", b.DetectImage) + cmd := exec.Command("docker", "run", "--rm", "-v", workspaceVolume+":/workspace", b.BuildImage, "/lifecycle/detector") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { return err } - group, err := groupToml(workspaceVolume, b.DetectImage) + group, err := groupToml(workspaceVolume, b.BuildImage) if err != nil { return err } @@ -71,17 +71,17 @@ func (b *BuildFlags) Run() error { if err := analyzer(group, analyzeTmpDir, b.RepoName, !b.Publish); err != nil { return err } - if err := copyToVolume(b.DetectImage, launchVolume, analyzeTmpDir, ""); err != nil { + if err := copyToVolume(b.BuildImage, workspaceVolume, analyzeTmpDir, ""); err != nil { return err } fmt.Println("*** BUILDING:") cmd = exec.Command("docker", "run", "--rm", - "-v", launchVolume+":/launch", "-v", workspaceVolume+":/workspace", "-v", cacheVolume+":/cache", - group.BuildImage, + b.BuildImage, + "/lifecycle/builder", ) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -91,26 +91,34 @@ func (b *BuildFlags) Run() error { if !b.Publish { fmt.Println("*** PULLING RUN IMAGE LOCALLY:") - if out, err := exec.Command("docker", "pull", group.RunImage).CombinedOutput(); err != nil { + if out, err := exec.Command("docker", "pull", b.RunImage).CombinedOutput(); err != nil { fmt.Println(string(out)) return err } } fmt.Println("*** EXPORTING:") - localLaunchDir, cleanup, err := exportVolume(b.DetectImage, launchVolume) - if err != nil { - return err - } - defer cleanup() - - imgSHA, err := export(group, localLaunchDir, b.RepoName, group.RunImage, !b.Publish, !b.Publish) - if err != nil { - return err - } - if b.Publish { + localWorkspaceDir, cleanup, err := exportVolume(b.BuildImage, workspaceVolume) + if err != nil { + return err + } + defer cleanup() + + imgSHA, err := exportRegistry(&group, localWorkspaceDir, b.RepoName, b.RunImage) + if err != nil { + return err + } fmt.Printf("\n*** Image: %s@%s\n", b.RepoName, imgSHA) + } else { + var buildpacks []string + for _, b := range group.Buildpacks { + buildpacks = append(buildpacks, b.ID) + } + + if err := exportDaemon(buildpacks, workspaceVolume, b.RepoName, b.RunImage); err != nil { + return err + } } return nil @@ -124,13 +132,13 @@ func exportVolume(image, volName string) (string, func(), error) { cleanup := func() { os.RemoveAll(tmpDir) } containerName := uuid.New().String() - if output, err := exec.Command("docker", "container", "create", "--name", containerName, "-v", volName+":/launch:ro", image).CombinedOutput(); err != nil { + if output, err := exec.Command("docker", "container", "create", "--name", containerName, "-v", volName+":/workspace:ro", image).CombinedOutput(); err != nil { cleanup() fmt.Println(string(output)) return "", func() {}, err } defer exec.Command("docker", "rm", containerName).Run() - if output, err := exec.Command("docker", "cp", containerName+":/launch/.", tmpDir).CombinedOutput(); err != nil { + if output, err := exec.Command("docker", "cp", containerName+":/workspace/.", tmpDir).CombinedOutput(); err != nil { cleanup() fmt.Println(string(output)) return "", func() {}, err @@ -141,12 +149,12 @@ func exportVolume(image, volName string) (string, func(), error) { func copyToVolume(image, volName, srcDir, destDir string) error { containerName := uuid.New().String() - if output, err := exec.Command("docker", "container", "create", "--user", "0", "--name", containerName, "--entrypoint", "", "-v", volName+":/launch", image, "chown", "-R", "packs:packs", "/launch").CombinedOutput(); err != nil { + if output, err := exec.Command("docker", "container", "create", "--user", "0", "--name", containerName, "--entrypoint", "", "-v", volName+":/workspace", image, "chown", "-R", "pack:pack", "/workspace").CombinedOutput(); err != nil { fmt.Println(string(output)) return err } defer exec.Command("docker", "rm", containerName).Run() - if output, err := exec.Command("docker", "cp", srcDir+"/.", containerName+":"+filepath.Join("/launch", destDir)).CombinedOutput(); err != nil { + if output, err := exec.Command("docker", "cp", srcDir+"/.", containerName+":"+filepath.Join("/workspace", destDir)).CombinedOutput(); err != nil { fmt.Println(string(output)) return err } @@ -158,9 +166,9 @@ func copyToVolume(image, volName, srcDir, destDir string) error { return nil } -func groupToml(workspaceVolume, detectImage string) (lifecycle.BuildpackGroup, error) { +func groupToml(workspaceVolume, buildImage string) (lifecycle.BuildpackGroup, error) { var buf bytes.Buffer - cmd := exec.Command("docker", "run", "--rm", "-v", workspaceVolume+":/workspace:ro", "--entrypoint", "", detectImage, "bash", "-c", "cat $PACK_BP_GROUP_PATH") + cmd := exec.Command("docker", "run", "--rm", "-v", workspaceVolume+":/workspace:ro", "--entrypoint", "", buildImage, "bash", "-c", "cat $PACK_GROUP_PATH") cmd.Stdout = &buf cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { diff --git a/cmd/pack/main.go b/cmd/pack/main.go index c80af6d9d4..03647dad7b 100644 --- a/cmd/pack/main.go +++ b/cmd/pack/main.go @@ -20,7 +20,8 @@ func main() { }, } buildCommand.Flags().StringVarP(&buildFlags.AppDir, "path", "p", wd, "path to app dir") - buildCommand.Flags().StringVar(&buildFlags.DetectImage, "detect-image", "packs/v3:detect", "detect image") + buildCommand.Flags().StringVar(&buildFlags.BuildImage, "build-image", "packs/build:0.0.1-rc.170", "build image") + buildCommand.Flags().StringVar(&buildFlags.RunImage, "run-image", "packs/run:0.0.1-rc.170", "run image") buildCommand.Flags().BoolVar(&buildFlags.Publish, "publish", false, "publish to registry") var createFlags pack.Create diff --git a/exporter.go b/exporter.go index b29abcf910..0e921d8e88 100644 --- a/exporter.go +++ b/exporter.go @@ -1,31 +1,39 @@ package pack import ( + "archive/tar" + "bytes" + "context" + "encoding/json" + "fmt" + "io" "io/ioutil" "os" + "sort" + "strings" + "github.com/BurntSushi/toml" "github.com/buildpack/lifecycle" "github.com/buildpack/packs" "github.com/buildpack/packs/img" + dockertypes "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" + dockercli "github.com/docker/docker/client" + "github.com/pkg/errors" ) -func export(group lifecycle.BuildpackGroup, launchDir, repoName, stackName string, useDaemon, useDaemonStack bool) (string, error) { - origImage, err := readImage(repoName, useDaemon) +func exportRegistry(group *lifecycle.BuildpackGroup, workspaceDir, repoName, stackName string) (string, error) { + origImage, err := readImage(repoName, false) if err != nil { return "", err } - stackImage, err := readImage(stackName, useDaemonStack) + stackImage, err := readImage(stackName, false) if err != nil || stackImage == nil { return "", packs.FailErr(err, "get image for", stackName) } - var repoStore img.Store - if useDaemon { - repoStore, err = img.NewDaemon(repoName) - } else { - repoStore, err = img.NewRegistry(repoName) - } + repoStore, err := img.NewRegistry(repoName) if err != nil { return "", packs.FailErr(err, "access", repoName) } @@ -43,7 +51,7 @@ func export(group lifecycle.BuildpackGroup, launchDir, repoName, stackName strin Err: os.Stderr, } newImage, err := exporter.Export( - launchDir, + workspaceDir, stackImage, origImage, ) @@ -62,3 +70,277 @@ func export(group lifecycle.BuildpackGroup, launchDir, repoName, stackName strin return sha.String(), nil } + +func exportDaemon(buildpacks []string, workspaceVolume, repoName, runImage string) error { + cli, err := dockercli.NewEnvClient() + if err != nil { + return errors.Wrap(err, "new docker client") + } + ctx := context.Background() + ctr, err := cli.ContainerCreate(ctx, &container.Config{ + Image: runImage, + User: "root", + Entrypoint: []string{}, + Cmd: []string{"echo", "hi"}, + }, &container.HostConfig{ + Binds: []string{ + workspaceVolume + ":/workspace", + }, + }, nil, "") + if err != nil { + return errors.Wrap(err, "container create") + } + + r, _, err := cli.CopyFromContainer(ctx, ctr.ID, "/workspace") + if err != nil { + return errors.Wrap(err, "copy from container") + } + + r2, layerChan, errChan := addDockerfileToTar(runImage, repoName, buildpacks, r) + + res, err := cli.ImageBuild(ctx, r2, dockertypes.ImageBuildOptions{Tags: []string{repoName}}) + if err != nil { + return errors.Wrap(err, "image build") + } + defer res.Body.Close() + if _, err := parseImageBuildBody(res.Body, os.Stdout); err != nil { + return errors.Wrap(err, "image build") + } + res.Body.Close() + + if err := <-errChan; err != nil { + return errors.Wrap(err, "modify tar to add dockerfile") + } + layerNames := <-layerChan + + // Calculate metadata + i, _, err := cli.ImageInspectWithRaw(ctx, repoName) + if err != nil { + return errors.Wrap(err, "inspect image to find layers") + } + layerIDX := len(i.RootFS.Layers) - len(layerNames) + metadata := packs.BuildMetadata{ + RunImage: packs.RunImageMetadata{ + Name: runImage, + SHA: i.RootFS.Layers[layerIDX-3], + }, + App: packs.AppMetadata{ + SHA: i.RootFS.Layers[layerIDX-2], + }, + Config: packs.ConfigMetadata{ + SHA: i.RootFS.Layers[layerIDX-1], + }, + Buildpacks: []packs.BuildpackMetadata{}, + } + for _, buildpack := range buildpacks { + data := packs.BuildpackMetadata{Key: buildpack, Layers: make(map[string]packs.LayerMetadata)} + for _, layer := range layerNames { + if layer.buildpack == buildpack { + data.Layers[layer.layer] = packs.LayerMetadata{ + SHA: i.RootFS.Layers[layerIDX], + Data: layer.data, + } + layerIDX++ + } + } + metadata.Buildpacks = append(metadata.Buildpacks, data) + } + metadataJSON, err := json.Marshal(metadata) + if err != nil { + return errors.Wrap(err, "marshal metadata to json") + } + if err := addLabelToImage(cli, repoName, map[string]string{"sh.packs.build": string(metadataJSON)}); err != nil { + return errors.Wrap(err, "add sh.packs.build label to image") + } + + return nil +} + +func addLabelToImage(cli *dockercli.Client, repoName string, labels map[string]string) error { + dockerfile := "FROM " + repoName + "\n" + for k, v := range labels { + dockerfile += fmt.Sprintf("LABEL %s='%s'\n", k, v) + } + var buf bytes.Buffer + tw := tar.NewWriter(&buf) + tw.WriteHeader(&tar.Header{Name: "Dockerfile", Size: int64(len(dockerfile)), Mode: 0666}) + tw.Write([]byte(dockerfile)) + tw.Close() + + res, err := cli.ImageBuild(context.Background(), bytes.NewReader(buf.Bytes()), dockertypes.ImageBuildOptions{ + Tags: []string{repoName}, + }) + if err != nil { + return err + } + defer res.Body.Close() + if _, err := parseImageBuildBody(res.Body, os.Stdout); err != nil { + return errors.Wrap(err, "image build") + } + return err +} + +type dockerfileLayer struct { + buildpack string + layer string + data interface{} +} + +func addDockerfileToTar(runImage, repoName string, buildpacks []string, r io.Reader) (io.Reader, chan []dockerfileLayer, chan error) { + dockerFile := "FROM " + runImage + "\n" + dockerFile += "ADD --chown=pack:pack /workspace/app /workspace/app\n" + dockerFile += "ADD --chown=pack:pack /workspace/config /workspace/config\n" + layerChan := make(chan []dockerfileLayer, 1) + var layerNames []dockerfileLayer + errChan := make(chan error, 1) + + pr, pw := io.Pipe() + tw := tar.NewWriter(pw) + + isBuildpack := make(map[string]bool) + for _, b := range buildpacks { + isBuildpack[b] = true + } + // fmt.Println(isBuildpack) + + go func() { + defer pw.Close() + tr := tar.NewReader(r) + tomlFiles := make(map[string]map[string]interface{}) + dirs := make(map[string]map[string]bool) + for { + hdr, err := tr.Next() + if err == io.EOF { + break // End of archive + } + if err != nil { + layerChan <- nil + errChan <- errors.Wrap(err, "tr.Next") + return + } + // fmt.Printf("File: %s\n", hdr.Name) + + tw.WriteHeader(hdr) + + arr := strings.Split(strings.TrimPrefix(strings.TrimSuffix(hdr.Name, "/"), "/"), "/") + if len(arr) == 3 && isBuildpack[arr[1]] && strings.HasSuffix(arr[2], ".toml") && arr[2] != "launch.toml" { + if tomlFiles[arr[1]] == nil { + tomlFiles[arr[1]] = make(map[string]interface{}) + } + + buf, err := ioutil.ReadAll(tr) + if err != nil { + layerChan <- nil + errChan <- errors.Wrap(err, "read toml file") + return + } + if _, err := tw.Write(buf); err != nil { + layerChan <- nil + errChan <- errors.Wrap(err, "write toml file") + return + } + + var data interface{} + if _, err := toml.Decode(string(buf), &data); err != nil { + layerChan <- nil + errChan <- errors.Wrap(err, "parsing toml file: "+hdr.Name) + return + } + tomlFiles[arr[1]][strings.TrimSuffix(arr[2], ".toml")] = data + } else if len(arr) == 3 && isBuildpack[arr[1]] && hdr.Typeflag == tar.TypeDir { + if dirs[arr[1]] == nil { + dirs[arr[1]] = make(map[string]bool) + } + dirs[arr[1]][arr[2]] = true + } + + // TODO is it OK to do this if we have already read it above? eg. toml file + if _, err := io.Copy(tw, tr); err != nil { + layerChan <- nil + errChan <- errors.Wrap(err, "io copy") + return + } + } + + copyFromPrev := false + for _, buildpack := range buildpacks { + layers := sortedKeys(tomlFiles[buildpack]) + for _, layer := range layers { + layerNames = append(layerNames, dockerfileLayer{buildpack, layer, tomlFiles[buildpack][layer]}) + // fmt.Println("Buildpack:", buildpack, "Layer:", layer, "DIRS:", dirs) + if dirs[buildpack][layer] { + dockerFile += fmt.Sprintf("ADD --chown=pack:pack /workspace/%s/%s /workspace/%s/%s\n", buildpack, layer, buildpack, layer) + } else { + dockerFile += fmt.Sprintf("COPY --from=prev --chown=pack:pack /workspace/%s/%s /workspace/%s/%s\n", buildpack, layer, buildpack, layer) + copyFromPrev = true + } + } + } + if copyFromPrev { + dockerFile = "FROM " + repoName + " AS prev\n\n" + dockerFile + } + + fmt.Println(tomlFiles) + fmt.Println(dirs) + // fmt.Println(dockerFile) + + if err := tw.WriteHeader(&tar.Header{Name: "Dockerfile", Size: int64(len(dockerFile)), Mode: 0666}); err != nil { + layerChan <- nil + errChan <- errors.Wrap(err, "write tar header for Dockerfile") + return + } + if _, err := tw.Write([]byte(dockerFile)); err != nil { + layerChan <- nil + errChan <- errors.Wrap(err, "write Dockerfile to tar") + return + } + + tw.Close() + pw.Close() + layerChan <- layerNames + errChan <- nil + }() + + return pr, layerChan, errChan +} + +func sortedKeys(m map[string]interface{}) []string { + keys := make([]string, 0, len(m)) + for key, _ := range m { + keys = append(keys, key) + } + sort.Strings(keys) + return keys +} + +func parseImageBuildBody(r io.Reader, out io.Writer) (string, error) { + jr := json.NewDecoder(r) + var id string + var streamError error + var obj struct { + Stream string `json:"stream"` + Error string `json:"error"` + Aux struct { + ID string `json:"ID"` + } `json:"aux"` + } + for { + err := jr.Decode(&obj) + if err != nil { + if err == io.EOF { + break + } + return "", err + } + if obj.Aux.ID != "" { + id = obj.Aux.ID + } + if txt := strings.TrimSpace(obj.Stream); txt != "" { + fmt.Fprintln(out, txt) + } + if txt := strings.TrimSpace(obj.Error); txt != "" { + streamError = errors.New(txt) + } + } + return id, streamError +} diff --git a/go.mod b/go.mod index ea556b75ee..0d98aba096 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/buildpack/pack require ( github.com/BurntSushi/toml v0.3.0 github.com/Microsoft/go-winio v0.4.9 - github.com/buildpack/lifecycle v0.0.0-20180824000627-2f640c42a336dbb896d0935c8adffdb72b1c558d + github.com/buildpack/lifecycle v0.0.0-20180824000627-5afbc99a71b820aaffc43b148d3fa47b1587e3e3 github.com/buildpack/packs v0.0.0-20180824001031-aa30a412923763df37e83f14a6e4e0fe07e11f25 github.com/docker/distribution v2.6.2+incompatible github.com/docker/docker v1.13.1 diff --git a/go.sum b/go.sum index a5b3c4ece5..a26f9d176e 100644 --- a/go.sum +++ b/go.sum @@ -7,6 +7,8 @@ github.com/buildpack/lifecycle v0.0.0-20180824000627-2f640c42a336dbb896d0935c8ad github.com/buildpack/lifecycle v0.0.0-20180824000627-2f640c42a336dbb896d0935c8adffdb72b1c558d/go.mod h1:tKBHRckd8Oq05rG6PDrZnOAINA0NkZxlMmUAOxzweAQ= github.com/buildpack/lifecycle v0.0.0-20180824000627-4afeeba810a3 h1:+8bhC03vXrHIdhu82ECs+0YKXtl8DkFhTYVF/OnUd2Q= github.com/buildpack/lifecycle v0.0.0-20180824000627-4afeeba810a3/go.mod h1:tKBHRckd8Oq05rG6PDrZnOAINA0NkZxlMmUAOxzweAQ= +github.com/buildpack/lifecycle v0.0.0-20180824000627-5afbc99a71b820aaffc43b148d3fa47b1587e3e3 h1:kTdUz/Ry8kRGF0uJ31GPhpeJB5Il7W8Wojy/MpHyWQM= +github.com/buildpack/lifecycle v0.0.0-20180824000627-5afbc99a71b820aaffc43b148d3fa47b1587e3e3/go.mod h1:vz2ERQFz2MtQIsTD/+rU692KFDeJdeFRKUjsMRt1bFk= github.com/buildpack/packs v0.0.0-20180808181744-27a22e86e2e7 h1:nTd2oUeTXp0sHXrWHuFc0T+bBABCrtnHRttoIi3zbUc= github.com/buildpack/packs v0.0.0-20180808181744-27a22e86e2e7/go.mod h1:jcquCT5a2gbyJw8WMkfgq36g7yc5VDSABVnCctIUKs8= github.com/buildpack/packs v0.0.0-20180820154346-0aa8a49ec4b4 h1:UKCftJJ3LYjRq8Gudd5HjCXrTCw5w8k1qyBCj0MXj/o= @@ -15,14 +17,18 @@ github.com/buildpack/packs v0.0.0-20180824001031-44341001317e h1:6u0yBr+dVuuXUQJ github.com/buildpack/packs v0.0.0-20180824001031-44341001317e/go.mod h1:jcquCT5a2gbyJw8WMkfgq36g7yc5VDSABVnCctIUKs8= github.com/buildpack/packs v0.0.0-20180824001031-aa30a412923763df37e83f14a6e4e0fe07e11f25 h1:gaFgBRK9mKLhfH26GLqMYmriWawmcUvYYgta73tHVJ4= github.com/buildpack/packs v0.0.0-20180824001031-aa30a412923763df37e83f14a6e4e0fe07e11f25/go.mod h1:jcquCT5a2gbyJw8WMkfgq36g7yc5VDSABVnCctIUKs8= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/docker/distribution v0.0.0-20180327202408-83389a148052/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.6.2+incompatible h1:4FI6af79dfCS/CYb+RRtkSHw3q1L/bnDjG1PcPZtQhM= github.com/docker/distribution v2.6.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20180531152204-71cd53e4a197/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v1.13.1 h1:5VBhsO6ckUxB0A8CE5LlUJdXzik9cbEbBTQ/ggeml7M= github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -32,9 +38,13 @@ github.com/google/go-containerregistry v0.0.0-20180815195620-3165313d6d3f h1:r0k github.com/google/go-containerregistry v0.0.0-20180815195620-3165313d6d3f/go.mod h1:yZAFP63pRshzrEYLXLGPmUt0Ay+2zdjmMN1loCnRLUk= github.com/google/uuid v0.0.0-20171129191014-dec09d789f3d h1:rXQlD9GXkjA/PQZhmEaF/8Pj/sJfdZJK7GJG0gkS8I0= github.com/google/uuid v0.0.0-20171129191014-dec09d789f3d/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gotestyourself/gotestyourself v2.1.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sclevine/spec v0.0.0-20180404042546-a925ac4bfbc9 h1:xh7f/httJstXLcqjPfzpsgLoLuB1wFNRPaOE8KYxdoM= github.com/sclevine/spec v0.0.0-20180404042546-a925ac4bfbc9/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= github.com/sclevine/spec v1.0.0 h1:ILQ08A/CHCz8GGqivOvI54Hy1U40wwcpkf7WtB1MQfY= @@ -45,8 +55,10 @@ github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.2 h1:Fy0orTDgHdbnzHcsOgfCN4LtHf0ec3wwtiwJqwvf3Gc= github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= golang.org/x/net v0.0.0-20180611182652-db08ff08e862 h1:JZi6BqOZ+iSgmLWe6llhGrNnEnK+YB/MRkStwnEfbqM= golang.org/x/net v0.0.0-20180611182652-db08ff08e862/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180816102801-aaf60122140d h1:211XH5RPVP5tOBkz6xm3/b7KxtjqVf6PYG+evqJpE08= golang.org/x/net v0.0.0-20180816102801-aaf60122140d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/sys v0.0.0-20180724212812-e072cadbbdc8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +gotest.tools v2.1.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=