mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #8827 from jlhawn/build_implied_from_scratch
Make `FROM scratch` a special cased 'no-base' spec
This commit is contained in:
commit
610842f906
17 changed files with 70 additions and 42 deletions
|
@ -1696,7 +1696,12 @@ func (cli *DockerCli) CmdPs(args ...string) error {
|
||||||
|
|
||||||
ports.ReadListFrom([]byte(out.Get("Ports")))
|
ports.ReadListFrom([]byte(out.Get("Ports")))
|
||||||
|
|
||||||
fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t%s\t", outID, out.Get("Image"), outCommand,
|
image := out.Get("Image")
|
||||||
|
if image == "" {
|
||||||
|
image = "<no image>"
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t%s\t", outID, image, outCommand,
|
||||||
units.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))),
|
units.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))),
|
||||||
out.Get("Status"), api.DisplayablePorts(ports), strings.Join(outNames, ","))
|
out.Get("Status"), api.DisplayablePorts(ports), strings.Join(outNames, ","))
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,12 @@ import (
|
||||||
"github.com/docker/docker/runconfig"
|
"github.com/docker/docker/runconfig"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// NoBaseImageSpecifier is the symbol used by the FROM
|
||||||
|
// command to specify that no base image is to be used.
|
||||||
|
NoBaseImageSpecifier string = "scratch"
|
||||||
|
)
|
||||||
|
|
||||||
// dispatch with no layer / parsing. This is effectively not a command.
|
// dispatch with no layer / parsing. This is effectively not a command.
|
||||||
func nullDispatch(b *Builder, args []string, attributes map[string]bool, original string) error {
|
func nullDispatch(b *Builder, args []string, attributes map[string]bool, original string) error {
|
||||||
return nil
|
return nil
|
||||||
|
@ -115,6 +121,12 @@ func from(b *Builder, args []string, attributes map[string]bool, original string
|
||||||
|
|
||||||
name := args[0]
|
name := args[0]
|
||||||
|
|
||||||
|
if name == NoBaseImageSpecifier {
|
||||||
|
b.image = ""
|
||||||
|
b.noBaseImage = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
image, err := b.Daemon.Repositories().LookupImage(name)
|
image, err := b.Daemon.Repositories().LookupImage(name)
|
||||||
if b.Pull {
|
if b.Pull {
|
||||||
image, err = b.pullImage(name)
|
image, err = b.pullImage(name)
|
||||||
|
@ -191,7 +203,7 @@ func workdir(b *Builder, args []string, attributes map[string]bool, original str
|
||||||
// RUN [ "echo", "hi" ] # echo hi
|
// RUN [ "echo", "hi" ] # echo hi
|
||||||
//
|
//
|
||||||
func run(b *Builder, args []string, attributes map[string]bool, original string) error {
|
func run(b *Builder, args []string, attributes map[string]bool, original string) error {
|
||||||
if b.image == "" {
|
if b.image == "" && !b.noBaseImage {
|
||||||
return fmt.Errorf("Please provide a source image with `from` prior to run")
|
return fmt.Errorf("Please provide a source image with `from` prior to run")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,7 +110,7 @@ type Builder struct {
|
||||||
cmdSet bool // indicates is CMD was set in current Dockerfile
|
cmdSet bool // indicates is CMD was set in current Dockerfile
|
||||||
context tarsum.TarSum // the context is a tarball that is uploaded by the client
|
context tarsum.TarSum // the context is a tarball that is uploaded by the client
|
||||||
contextPath string // the path of the temporary directory the local context is unpacked to (server side)
|
contextPath string // the path of the temporary directory the local context is unpacked to (server side)
|
||||||
|
noBaseImage bool // indicates that this build does not start from any base image, but is being built from an empty file system.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the builder with the context. This is the lynchpin of this package. This
|
// Run the builder with the context. This is the lynchpin of this package. This
|
||||||
|
|
|
@ -58,7 +58,7 @@ func (b *Builder) readContext(context io.Reader) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Builder) commit(id string, autoCmd []string, comment string) error {
|
func (b *Builder) commit(id string, autoCmd []string, comment string) error {
|
||||||
if b.image == "" {
|
if b.image == "" && !b.noBaseImage {
|
||||||
return fmt.Errorf("Please provide a source image with `from` prior to commit")
|
return fmt.Errorf("Please provide a source image with `from` prior to commit")
|
||||||
}
|
}
|
||||||
b.Config.Image = b.image
|
b.Config.Image = b.image
|
||||||
|
@ -513,7 +513,7 @@ func (b *Builder) probeCache() (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Builder) create() (*daemon.Container, error) {
|
func (b *Builder) create() (*daemon.Container, error) {
|
||||||
if b.image == "" {
|
if b.image == "" && !b.noBaseImage {
|
||||||
return nil, fmt.Errorf("Please provide a source image with `from` prior to run")
|
return nil, fmt.Errorf("Please provide a source image with `from` prior to run")
|
||||||
}
|
}
|
||||||
b.Config.Image = b.image
|
b.Config.Image = b.image
|
||||||
|
|
|
@ -59,17 +59,17 @@ func (daemon *Daemon) Commit(container *Container, repository, tag, comment, aut
|
||||||
|
|
||||||
// Create a new image from the container's base layers + a new layer from container changes
|
// Create a new image from the container's base layers + a new layer from container changes
|
||||||
var (
|
var (
|
||||||
containerID, containerImage string
|
containerID, parentImageID string
|
||||||
containerConfig *runconfig.Config
|
containerConfig *runconfig.Config
|
||||||
)
|
)
|
||||||
|
|
||||||
if container != nil {
|
if container != nil {
|
||||||
containerID = container.ID
|
containerID = container.ID
|
||||||
containerImage = container.Image
|
parentImageID = container.ImageID
|
||||||
containerConfig = container.Config
|
containerConfig = container.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
img, err := daemon.graph.Create(rwTar, containerID, containerImage, comment, author, containerConfig, config)
|
img, err := daemon.graph.Create(rwTar, containerID, parentImageID, comment, author, containerConfig, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ type Container struct {
|
||||||
Args []string
|
Args []string
|
||||||
|
|
||||||
Config *runconfig.Config
|
Config *runconfig.Config
|
||||||
Image string
|
ImageID string `json:"Image"`
|
||||||
|
|
||||||
NetworkSettings *NetworkSettings
|
NetworkSettings *NetworkSettings
|
||||||
|
|
||||||
|
@ -186,7 +186,7 @@ func (container *Container) WriteHostConfig() error {
|
||||||
|
|
||||||
func (container *Container) LogEvent(action string) {
|
func (container *Container) LogEvent(action string) {
|
||||||
d := container.daemon
|
d := container.daemon
|
||||||
if err := d.eng.Job("log", action, container.ID, d.Repositories().ImageName(container.Image)).Run(); err != nil {
|
if err := d.eng.Job("log", action, container.ID, d.Repositories().ImageName(container.ImageID)).Run(); err != nil {
|
||||||
log.Errorf("Error logging event %s for %s: %s", action, container.ID, err)
|
log.Errorf("Error logging event %s for %s: %s", action, container.ID, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -786,7 +786,7 @@ func (container *Container) GetImage() (*image.Image, error) {
|
||||||
if container.daemon == nil {
|
if container.daemon == nil {
|
||||||
return nil, fmt.Errorf("Can't get image of unregistered container")
|
return nil, fmt.Errorf("Can't get image of unregistered container")
|
||||||
}
|
}
|
||||||
return container.daemon.graph.Get(container.Image)
|
return container.daemon.graph.Get(container.ImageID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) Unmount() error {
|
func (container *Container) Unmount() error {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
|
|
||||||
"github.com/docker/docker/engine"
|
"github.com/docker/docker/engine"
|
||||||
"github.com/docker/docker/graph"
|
"github.com/docker/docker/graph"
|
||||||
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/pkg/parsers"
|
"github.com/docker/docker/pkg/parsers"
|
||||||
"github.com/docker/docker/runconfig"
|
"github.com/docker/docker/runconfig"
|
||||||
"github.com/docker/libcontainer/label"
|
"github.com/docker/libcontainer/label"
|
||||||
|
@ -68,15 +69,22 @@ func (daemon *Daemon) Create(config *runconfig.Config, hostConfig *runconfig.Hos
|
||||||
var (
|
var (
|
||||||
container *Container
|
container *Container
|
||||||
warnings []string
|
warnings []string
|
||||||
|
img *image.Image
|
||||||
|
imgID string
|
||||||
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
img, err := daemon.repositories.LookupImage(config.Image)
|
if config.Image != "" {
|
||||||
|
img, err = daemon.repositories.LookupImage(config.Image)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if err := img.CheckDepth(); err != nil {
|
if err = img.CheckDepth(); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
imgID = img.ID
|
||||||
|
}
|
||||||
|
|
||||||
if warnings, err = daemon.mergeAndVerifyConfig(config, img); err != nil {
|
if warnings, err = daemon.mergeAndVerifyConfig(config, img); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -86,13 +94,13 @@ func (daemon *Daemon) Create(config *runconfig.Config, hostConfig *runconfig.Hos
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if container, err = daemon.newContainer(name, config, img); err != nil {
|
if container, err = daemon.newContainer(name, config, imgID); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if err := daemon.Register(container); err != nil {
|
if err := daemon.Register(container); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if err := daemon.createRootfs(container, img); err != nil {
|
if err := daemon.createRootfs(container); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if hostConfig != nil {
|
if hostConfig != nil {
|
||||||
|
|
|
@ -417,10 +417,10 @@ func (daemon *Daemon) checkDeprecatedExpose(config *runconfig.Config) bool {
|
||||||
|
|
||||||
func (daemon *Daemon) mergeAndVerifyConfig(config *runconfig.Config, img *image.Image) ([]string, error) {
|
func (daemon *Daemon) mergeAndVerifyConfig(config *runconfig.Config, img *image.Image) ([]string, error) {
|
||||||
warnings := []string{}
|
warnings := []string{}
|
||||||
if daemon.checkDeprecatedExpose(img.Config) || daemon.checkDeprecatedExpose(config) {
|
if (img != nil && daemon.checkDeprecatedExpose(img.Config)) || daemon.checkDeprecatedExpose(config) {
|
||||||
warnings = append(warnings, "The mapping to public ports on your host via Dockerfile EXPOSE (host:port:port) has been deprecated. Use -p to publish the ports.")
|
warnings = append(warnings, "The mapping to public ports on your host via Dockerfile EXPOSE (host:port:port) has been deprecated. Use -p to publish the ports.")
|
||||||
}
|
}
|
||||||
if img.Config != nil {
|
if img != nil && img.Config != nil {
|
||||||
if err := runconfig.Merge(config, img.Config); err != nil {
|
if err := runconfig.Merge(config, img.Config); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -557,7 +557,7 @@ func parseSecurityOpt(container *Container, config *runconfig.HostConfig) error
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) newContainer(name string, config *runconfig.Config, img *image.Image) (*Container, error) {
|
func (daemon *Daemon) newContainer(name string, config *runconfig.Config, imgID string) (*Container, error) {
|
||||||
var (
|
var (
|
||||||
id string
|
id string
|
||||||
err error
|
err error
|
||||||
|
@ -578,7 +578,7 @@ func (daemon *Daemon) newContainer(name string, config *runconfig.Config, img *i
|
||||||
Args: args, //FIXME: de-duplicate from config
|
Args: args, //FIXME: de-duplicate from config
|
||||||
Config: config,
|
Config: config,
|
||||||
hostConfig: &runconfig.HostConfig{},
|
hostConfig: &runconfig.HostConfig{},
|
||||||
Image: img.ID, // Always use the resolved image id
|
ImageID: imgID,
|
||||||
NetworkSettings: &NetworkSettings{},
|
NetworkSettings: &NetworkSettings{},
|
||||||
Name: name,
|
Name: name,
|
||||||
Driver: daemon.driver.String(),
|
Driver: daemon.driver.String(),
|
||||||
|
@ -590,14 +590,14 @@ func (daemon *Daemon) newContainer(name string, config *runconfig.Config, img *i
|
||||||
return container, err
|
return container, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) createRootfs(container *Container, img *image.Image) error {
|
func (daemon *Daemon) createRootfs(container *Container) error {
|
||||||
// Step 1: create the container directory.
|
// Step 1: create the container directory.
|
||||||
// This doubles as a barrier to avoid race conditions.
|
// This doubles as a barrier to avoid race conditions.
|
||||||
if err := os.Mkdir(container.root, 0700); err != nil {
|
if err := os.Mkdir(container.root, 0700); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
initID := fmt.Sprintf("%s-init", container.ID)
|
initID := fmt.Sprintf("%s-init", container.ID)
|
||||||
if err := daemon.driver.Create(initID, img.ID); err != nil {
|
if err := daemon.driver.Create(initID, container.ImageID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
initPath, err := daemon.driver.Get(initID, "")
|
initPath, err := daemon.driver.Get(initID, "")
|
||||||
|
|
|
@ -131,7 +131,7 @@ func (daemon *Daemon) DeleteImage(eng *engine.Engine, name string, imgs *engine.
|
||||||
|
|
||||||
func (daemon *Daemon) canDeleteImage(imgID string, force bool) error {
|
func (daemon *Daemon) canDeleteImage(imgID string, force bool) error {
|
||||||
for _, container := range daemon.List() {
|
for _, container := range daemon.List() {
|
||||||
parent, err := daemon.Repositories().LookupImage(container.Image)
|
parent, err := daemon.Repositories().LookupImage(container.ImageID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if daemon.Graph().IsNotExist(err) {
|
if daemon.Graph().IsNotExist(err) {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -35,7 +35,7 @@ func (daemon *Daemon) ContainerInspect(job *engine.Job) engine.Status {
|
||||||
out.SetList("Args", container.Args)
|
out.SetList("Args", container.Args)
|
||||||
out.SetJson("Config", container.Config)
|
out.SetJson("Config", container.Config)
|
||||||
out.SetJson("State", container.State)
|
out.SetJson("State", container.State)
|
||||||
out.SetJson("Image", container.Image)
|
out.Set("Image", container.ImageID)
|
||||||
out.SetJson("NetworkSettings", container.NetworkSettings)
|
out.SetJson("NetworkSettings", container.NetworkSettings)
|
||||||
out.Set("ResolvConfPath", container.ResolvConfPath)
|
out.Set("ResolvConfPath", container.ResolvConfPath)
|
||||||
out.Set("HostnamePath", container.HostnamePath)
|
out.Set("HostnamePath", container.HostnamePath)
|
||||||
|
|
|
@ -116,7 +116,7 @@ func (daemon *Daemon) Containers(job *engine.Job) engine.Status {
|
||||||
out := &engine.Env{}
|
out := &engine.Env{}
|
||||||
out.SetJson("Id", container.ID)
|
out.SetJson("Id", container.ID)
|
||||||
out.SetList("Names", names[container.ID])
|
out.SetList("Names", names[container.ID])
|
||||||
out.SetJson("Image", daemon.Repositories().ImageName(container.Image))
|
out.SetJson("Image", daemon.Repositories().ImageName(container.ImageID))
|
||||||
if len(container.Args) > 0 {
|
if len(container.Args) > 0 {
|
||||||
args := []string{}
|
args := []string{}
|
||||||
for _, arg := range container.Args {
|
for _, arg := range container.Args {
|
||||||
|
|
|
@ -298,6 +298,9 @@ func validateRepoName(name string) error {
|
||||||
if name == "" {
|
if name == "" {
|
||||||
return fmt.Errorf("Repository name can't be empty")
|
return fmt.Errorf("Repository name can't be empty")
|
||||||
}
|
}
|
||||||
|
if name == "scratch" {
|
||||||
|
return fmt.Errorf("'scratch' is a reserved name")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -230,9 +230,9 @@ func TestEventsRedirectStdout(t *testing.T) {
|
||||||
|
|
||||||
func TestEventsImagePull(t *testing.T) {
|
func TestEventsImagePull(t *testing.T) {
|
||||||
since := time.Now().Unix()
|
since := time.Now().Unix()
|
||||||
pullCmd := exec.Command(dockerBinary, "pull", "scratch")
|
pullCmd := exec.Command(dockerBinary, "pull", "hello-world")
|
||||||
if out, _, err := runCommandWithOutput(pullCmd); err != nil {
|
if out, _, err := runCommandWithOutput(pullCmd); err != nil {
|
||||||
t.Fatalf("pulling the scratch image from has failed: %s, %v", out, err)
|
t.Fatalf("pulling the hello-world image from has failed: %s, %v", out, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
eventsCmd := exec.Command(dockerBinary, "events",
|
eventsCmd := exec.Command(dockerBinary, "events",
|
||||||
|
@ -243,7 +243,7 @@ func TestEventsImagePull(t *testing.T) {
|
||||||
events := strings.Split(strings.TrimSpace(out), "\n")
|
events := strings.Split(strings.TrimSpace(out), "\n")
|
||||||
event := strings.TrimSpace(events[len(events)-1])
|
event := strings.TrimSpace(events[len(events)-1])
|
||||||
|
|
||||||
if !strings.HasSuffix(event, "scratch:latest: pull") {
|
if !strings.HasSuffix(event, "hello-world:latest: pull") {
|
||||||
t.Fatalf("Missing pull event - got:%q", event)
|
t.Fatalf("Missing pull event - got:%q", event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestInspectImage(t *testing.T) {
|
func TestInspectImage(t *testing.T) {
|
||||||
imageTest := "scratch"
|
imageTest := "emptyfs"
|
||||||
imageTestID := "511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158"
|
imageTestID := "511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158"
|
||||||
imagesCmd := exec.Command(dockerBinary, "inspect", "--format='{{.Id}}'", imageTest)
|
imagesCmd := exec.Command(dockerBinary, "inspect", "--format='{{.Id}}'", imageTest)
|
||||||
out, exitCode, err := runCommandWithOutput(imagesCmd)
|
out, exitCode, err := runCommandWithOutput(imagesCmd)
|
||||||
|
|
|
@ -9,11 +9,11 @@ import (
|
||||||
|
|
||||||
// pulling an image from the central registry should work
|
// pulling an image from the central registry should work
|
||||||
func TestPullImageFromCentralRegistry(t *testing.T) {
|
func TestPullImageFromCentralRegistry(t *testing.T) {
|
||||||
pullCmd := exec.Command(dockerBinary, "pull", "scratch")
|
pullCmd := exec.Command(dockerBinary, "pull", "hello-world")
|
||||||
if out, _, err := runCommandWithOutput(pullCmd); err != nil {
|
if out, _, err := runCommandWithOutput(pullCmd); err != nil {
|
||||||
t.Fatalf("pulling the scratch image from the registry has failed: %s, %v", out, err)
|
t.Fatalf("pulling the hello-world image from the registry has failed: %s, %v", out, err)
|
||||||
}
|
}
|
||||||
logDone("pull - pull scratch")
|
logDone("pull - pull hello-world")
|
||||||
}
|
}
|
||||||
|
|
||||||
// pulling a non-existing image from the central registry should return a non-zero exit code
|
// pulling a non-existing image from the central registry should return a non-zero exit code
|
||||||
|
|
|
@ -270,7 +270,7 @@ func TestSaveSingleTag(t *testing.T) {
|
||||||
func TestSaveImageId(t *testing.T) {
|
func TestSaveImageId(t *testing.T) {
|
||||||
repoName := "foobar-save-image-id-test"
|
repoName := "foobar-save-image-id-test"
|
||||||
|
|
||||||
tagCmdFinal := fmt.Sprintf("%v tag scratch:latest %v:latest", dockerBinary, repoName)
|
tagCmdFinal := fmt.Sprintf("%v tag emptyfs:latest %v:latest", dockerBinary, repoName)
|
||||||
tagCmd := exec.Command("bash", "-c", tagCmdFinal)
|
tagCmd := exec.Command("bash", "-c", tagCmdFinal)
|
||||||
if out, _, err := runCommandWithOutput(tagCmd); err != nil {
|
if out, _, err := runCommandWithOutput(tagCmd); err != nil {
|
||||||
t.Fatalf("failed to tag repo: %s, %v", out, err)
|
t.Fatalf("failed to tag repo: %s, %v", out, err)
|
||||||
|
@ -370,7 +370,7 @@ func TestSaveMultipleNames(t *testing.T) {
|
||||||
repoName := "foobar-save-multi-name-test"
|
repoName := "foobar-save-multi-name-test"
|
||||||
|
|
||||||
// Make one image
|
// Make one image
|
||||||
tagCmdFinal := fmt.Sprintf("%v tag scratch:latest %v-one:latest", dockerBinary, repoName)
|
tagCmdFinal := fmt.Sprintf("%v tag emptyfs:latest %v-one:latest", dockerBinary, repoName)
|
||||||
tagCmd := exec.Command("bash", "-c", tagCmdFinal)
|
tagCmd := exec.Command("bash", "-c", tagCmdFinal)
|
||||||
if out, _, err := runCommandWithOutput(tagCmd); err != nil {
|
if out, _, err := runCommandWithOutput(tagCmd); err != nil {
|
||||||
t.Fatalf("failed to tag repo: %s, %v", out, err)
|
t.Fatalf("failed to tag repo: %s, %v", out, err)
|
||||||
|
@ -378,7 +378,7 @@ func TestSaveMultipleNames(t *testing.T) {
|
||||||
defer deleteImages(repoName + "-one")
|
defer deleteImages(repoName + "-one")
|
||||||
|
|
||||||
// Make two images
|
// Make two images
|
||||||
tagCmdFinal = fmt.Sprintf("%v tag scratch:latest %v-two:latest", dockerBinary, repoName)
|
tagCmdFinal = fmt.Sprintf("%v tag emptyfs:latest %v-two:latest", dockerBinary, repoName)
|
||||||
tagCmd = exec.Command("bash", "-c", tagCmdFinal)
|
tagCmd = exec.Command("bash", "-c", tagCmdFinal)
|
||||||
if out, _, err := runCommandWithOutput(tagCmd); err != nil {
|
if out, _, err := runCommandWithOutput(tagCmd); err != nil {
|
||||||
t.Fatalf("failed to tag repo: %s, %v", out, err)
|
t.Fatalf("failed to tag repo: %s, %v", out, err)
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
if ! docker inspect scratch &> /dev/null; then
|
if ! docker inspect scratch &> /dev/null; then
|
||||||
# let's build a "docker save" tarball for "scratch"
|
# let's build a "docker save" tarball for "emptyfs"
|
||||||
# see https://github.com/docker/docker/pull/5262
|
# see https://github.com/docker/docker/pull/5262
|
||||||
# and also https://github.com/docker/docker/issues/4242
|
# and also https://github.com/docker/docker/issues/4242
|
||||||
mkdir -p /docker-scratch
|
mkdir -p /docker-scratch
|
||||||
(
|
(
|
||||||
cd /docker-scratch
|
cd /docker-scratch
|
||||||
echo '{"scratch":{"latest":"511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158"}}' > repositories
|
echo '{"emptyfs":{"latest":"511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158"}}' > repositories
|
||||||
mkdir -p 511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158
|
mkdir -p 511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158
|
||||||
(
|
(
|
||||||
cd 511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158
|
cd 511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158
|
||||||
|
|
Loading…
Add table
Reference in a new issue