Parcourir la source

Merge pull request #4661 from vieux/add_no_prune

Add no prune
Guillaume J. Charmes il y a 11 ans
Parent
commit
68dc189680

+ 6 - 2
api/client.go

@@ -817,8 +817,9 @@ func (cli *DockerCli) CmdPort(args ...string) error {
 // 'docker rmi IMAGE' removes all images with the name IMAGE
 // 'docker rmi IMAGE' removes all images with the name IMAGE
 func (cli *DockerCli) CmdRmi(args ...string) error {
 func (cli *DockerCli) CmdRmi(args ...string) error {
 	var (
 	var (
-		cmd   = cli.Subcmd("rmi", "IMAGE [IMAGE...]", "Remove one or more images")
-		force = cmd.Bool([]string{"f", "-force"}, false, "Force")
+		cmd     = cli.Subcmd("rmi", "IMAGE [IMAGE...]", "Remove one or more images")
+		force   = cmd.Bool([]string{"f", "-force"}, false, "Force")
+		noprune = cmd.Bool([]string{"-no-prune"}, false, "Do not delete untagged parents")
 	)
 	)
 	if err := cmd.Parse(args); err != nil {
 	if err := cmd.Parse(args); err != nil {
 		return nil
 		return nil
@@ -832,6 +833,9 @@ func (cli *DockerCli) CmdRmi(args ...string) error {
 	if *force {
 	if *force {
 		v.Set("force", "1")
 		v.Set("force", "1")
 	}
 	}
+	if *noprune {
+		v.Set("noprune", "1")
+	}
 
 
 	var encounteredError error
 	var encounteredError error
 	for _, name := range cmd.Args() {
 	for _, name := range cmd.Args() {

+ 1 - 0
api/server.go

@@ -623,6 +623,7 @@ func deleteImages(eng *engine.Engine, version version.Version, w http.ResponseWr
 	var job = eng.Job("image_delete", vars["name"])
 	var job = eng.Job("image_delete", vars["name"])
 	streamJSON(job, w, false)
 	streamJSON(job, w, false)
 	job.Setenv("force", r.Form.Get("force"))
 	job.Setenv("force", r.Form.Get("force"))
+	job.Setenv("noprune", r.Form.Get("noprune"))
 
 
 	return job.Run()
 	return job.Run()
 }
 }

+ 1 - 0
docs/sources/reference/api/docker_remote_api.rst

@@ -50,6 +50,7 @@ What's new
 
 
    **New!** You can now use the force parameter to force delete of an image, even if it's
    **New!** You can now use the force parameter to force delete of an image, even if it's
    tagged in multiple repositories.
    tagged in multiple repositories.
+   **New!** You can now use the noprune parameter to prevent the deletion of parent images
 
 
 .. http:delete:: /containers/(id)
 .. http:delete:: /containers/(id)
 
 

+ 1 - 0
docs/sources/reference/api/docker_remote_api_v1.10.rst

@@ -931,6 +931,7 @@ Remove an image
            ]
            ]
 
 
         :query force: 1/True/true or 0/False/false, default false
         :query force: 1/True/true or 0/False/false, default false
+        :query noprune: 1/True/true or 0/False/false, default false
         :statuscode 200: no error
         :statuscode 200: no error
         :statuscode 404: no such image
         :statuscode 404: no such image
         :statuscode 409: conflict
         :statuscode 409: conflict

+ 1 - 0
docs/sources/reference/commandline/cli.rst

@@ -1092,6 +1092,7 @@ containers will not be deleted.
     Remove one or more images
     Remove one or more images
 
 
       -f, --force=false: Force
       -f, --force=false: Force
+      --no-prune=false: Do not delete untagged parents
 
 
 Removing tagged images
 Removing tagged images
 ~~~~~~~~~~~~~~~~~~~~~~
 ~~~~~~~~~~~~~~~~~~~~~~

+ 1 - 1
integration/commands_test.go

@@ -1062,7 +1062,7 @@ func TestContainerOrphaning(t *testing.T) {
 
 
 	// remove the second image by name
 	// remove the second image by name
 	resp := engine.NewTable("", 0)
 	resp := engine.NewTable("", 0)
-	if err := srv.DeleteImage(imageName, resp, true, false); err == nil {
+	if err := srv.DeleteImage(imageName, resp, true, false, false); err == nil {
 		t.Fatal("Expected error, got none")
 		t.Fatal("Expected error, got none")
 	}
 	}
 
 

+ 5 - 5
integration/server_test.go

@@ -36,7 +36,7 @@ func TestImageTagImageDelete(t *testing.T) {
 		t.Errorf("Expected %d images, %d found", nExpected, nActual)
 		t.Errorf("Expected %d images, %d found", nExpected, nActual)
 	}
 	}
 
 
-	if err := srv.DeleteImage("utest/docker:tag2", engine.NewTable("", 0), true, false); err != nil {
+	if err := srv.DeleteImage("utest/docker:tag2", engine.NewTable("", 0), true, false, false); err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
@@ -48,7 +48,7 @@ func TestImageTagImageDelete(t *testing.T) {
 		t.Errorf("Expected %d images, %d found", nExpected, nActual)
 		t.Errorf("Expected %d images, %d found", nExpected, nActual)
 	}
 	}
 
 
-	if err := srv.DeleteImage("utest:5000/docker:tag3", engine.NewTable("", 0), true, false); err != nil {
+	if err := srv.DeleteImage("utest:5000/docker:tag3", engine.NewTable("", 0), true, false, false); err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
@@ -57,7 +57,7 @@ func TestImageTagImageDelete(t *testing.T) {
 	nExpected = len(initialImages.Data[0].GetList("RepoTags")) + 1
 	nExpected = len(initialImages.Data[0].GetList("RepoTags")) + 1
 	nActual = len(images.Data[0].GetList("RepoTags"))
 	nActual = len(images.Data[0].GetList("RepoTags"))
 
 
-	if err := srv.DeleteImage("utest:tag1", engine.NewTable("", 0), true, false); err != nil {
+	if err := srv.DeleteImage("utest:tag1", engine.NewTable("", 0), true, false, false); err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
@@ -579,7 +579,7 @@ func TestRmi(t *testing.T) {
 		t.Fatalf("Expected 2 new images, found %d.", images.Len()-initialImages.Len())
 		t.Fatalf("Expected 2 new images, found %d.", images.Len()-initialImages.Len())
 	}
 	}
 
 
-	if err = srv.DeleteImage(imageID, engine.NewTable("", 0), true, false); err != nil {
+	if err = srv.DeleteImage(imageID, engine.NewTable("", 0), true, false, false); err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
@@ -815,7 +815,7 @@ func TestDeleteTagWithExistingContainers(t *testing.T) {
 
 
 	// Try to remove the tag
 	// Try to remove the tag
 	imgs := engine.NewTable("", 0)
 	imgs := engine.NewTable("", 0)
-	if err := srv.DeleteImage("utest:tag1", imgs, true, false); err != nil {
+	if err := srv.DeleteImage("utest:tag1", imgs, true, false, false); err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 

+ 4 - 4
server/server.go

@@ -1839,7 +1839,7 @@ func (srv *Server) ContainerDestroy(job *engine.Job) engine.Status {
 	return engine.StatusOK
 	return engine.StatusOK
 }
 }
 
 
-func (srv *Server) DeleteImage(name string, imgs *engine.Table, first, force bool) error {
+func (srv *Server) DeleteImage(name string, imgs *engine.Table, first, force, noprune bool) error {
 	var (
 	var (
 		repoName, tag string
 		repoName, tag string
 		tags          = []string{}
 		tags          = []string{}
@@ -1920,8 +1920,8 @@ func (srv *Server) DeleteImage(name string, imgs *engine.Table, first, force boo
 			out.Set("Deleted", img.ID)
 			out.Set("Deleted", img.ID)
 			imgs.Add(out)
 			imgs.Add(out)
 			srv.LogEvent("delete", img.ID, "")
 			srv.LogEvent("delete", img.ID, "")
-			if img.Parent != "" {
-				err := srv.DeleteImage(img.Parent, imgs, false, force)
+			if img.Parent != "" && !noprune {
+				err := srv.DeleteImage(img.Parent, imgs, false, force, noprune)
 				if first {
 				if first {
 					return err
 					return err
 				}
 				}
@@ -1938,7 +1938,7 @@ func (srv *Server) ImageDelete(job *engine.Job) engine.Status {
 		return job.Errorf("Usage: %s IMAGE", job.Name)
 		return job.Errorf("Usage: %s IMAGE", job.Name)
 	}
 	}
 	imgs := engine.NewTable("", 0)
 	imgs := engine.NewTable("", 0)
-	if err := srv.DeleteImage(job.Args[0], imgs, true, job.GetenvBool("force")); err != nil {
+	if err := srv.DeleteImage(job.Args[0], imgs, true, job.GetenvBool("force"), job.GetenvBool("noprune")); err != nil {
 		return job.Error(err)
 		return job.Error(err)
 	}
 	}
 	if len(imgs.Data) == 0 {
 	if len(imgs.Data) == 0 {