From 49a78929c61cbab0d25b49fdee43beac62fc9f66 Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Thu, 21 Mar 2013 20:06:20 -0700 Subject: [PATCH 1/3] Repositories and tags can't have ':' in their name (to allow parsing the REPO:TAG notation) --- tags.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tags.go b/tags.go index 55a5135860..a26a2f196d 100644 --- a/tags.go +++ b/tags.go @@ -2,9 +2,11 @@ package docker import ( "encoding/json" + "fmt" "io/ioutil" "os" "path/filepath" + "strings" ) type TagStore struct { @@ -60,6 +62,12 @@ func (store *TagStore) Reload() error { } func (store *TagStore) Set(repoName, tag, revision string) error { + if strings.Contains(repoName, ":") { + return fmt.Errorf("Illegal repository name: %s", repoName) + } + if strings.Contains(repoName, ":") { + return fmt.Errorf("Illegal tag name: %s", tag) + } if err := store.Reload(); err != nil { return err } From 8396798ebae99791ce3f2f43c276af8e6b96d782 Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Thu, 21 Mar 2013 20:07:37 -0700 Subject: [PATCH 2/3] 'docker commit' can optionally tag the new image into a repository --- commands.go | 27 ++++++++------------------- runtime.go | 27 +++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/commands.go b/commands.go index 4b23204854..7a6e4b332c 100644 --- a/commands.go +++ b/commands.go @@ -531,33 +531,22 @@ func (srv *Server) CmdPs(stdin io.ReadCloser, stdout io.Writer, args ...string) func (srv *Server) CmdCommit(stdin io.ReadCloser, stdout io.Writer, args ...string) error { cmd := rcli.Subcmd(stdout, - "commit", "[OPTIONS] CONTAINER [DEST]", + "commit", "[OPTIONS] CONTAINER [REPOSITORY [TAG]]", "Create a new image from a container's changes") if err := cmd.Parse(args); err != nil { return nil } - containerName, imgName := cmd.Arg(0), cmd.Arg(1) - if containerName == "" || imgName == "" { + containerName, repository, tag := cmd.Arg(0), cmd.Arg(1), cmd.Arg(2) + if containerName == "" { cmd.Usage() return nil } - if container := srv.runtime.Get(containerName); container != nil { - // FIXME: freeze the container before copying it to avoid data corruption? - // FIXME: this shouldn't be in commands. - rwTar, err := container.ExportRw() - if err != nil { - return err - } - // Create a new image from the container's base layers + a new layer from container changes - img, err := srv.runtime.graph.Create(rwTar, container.Image, "") - if err != nil { - return err - } - - fmt.Fprintln(stdout, img.Id) - return nil + img, err := srv.runtime.Commit(containerName, repository, tag) + if err != nil { + return err } - return errors.New("No such container: " + containerName) + fmt.Fprintln(stdout, img.Id) + return nil } func (srv *Server) CmdExport(stdin io.ReadCloser, stdout io.Writer, args ...string) error { diff --git a/runtime.go b/runtime.go index 9aa213f7e2..5df3b7b5b8 100644 --- a/runtime.go +++ b/runtime.go @@ -200,6 +200,33 @@ func (runtime *Runtime) Destroy(container *Container) error { return nil } +// Commit creates a new filesystem image from the current state of a container. +// The image can optionally be tagged into a repository +func (runtime *Runtime) Commit(id, repository, tag string) (*Image, error) { + container := runtime.Get(id) + if container == nil { + return nil, fmt.Errorf("No such container: %s", id) + } + // FIXME: freeze the container before copying it to avoid data corruption? + // FIXME: this shouldn't be in commands. + rwTar, err := container.ExportRw() + if err != nil { + return nil, err + } + // Create a new image from the container's base layers + a new layer from container changes + img, err := runtime.graph.Create(rwTar, container.Image, "") + if err != nil { + return nil, err + } + // Register the image if needed + if repository != "" { + if err := runtime.repositories.Set(repository, tag, img.Id); err != nil { + return img, err + } + } + return img, nil +} + func (runtime *Runtime) restore() error { dir, err := ioutil.ReadDir(runtime.repository) if err != nil { From 05ae69a6eb72e012ed35422a6842038a01a24b61 Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Thu, 21 Mar 2013 21:13:27 -0700 Subject: [PATCH 3/3] 'docker commit' records parent container id and command, in addition to parent image --- commands.go | 2 +- container_test.go | 2 +- graph.go | 8 ++++++-- graph_test.go | 10 +++++----- image.go | 12 +++++++----- runtime.go | 2 +- 6 files changed, 21 insertions(+), 15 deletions(-) diff --git a/commands.go b/commands.go index 7a6e4b332c..4325201f20 100644 --- a/commands.go +++ b/commands.go @@ -384,7 +384,7 @@ func (srv *Server) CmdImport(stdin io.ReadCloser, stdout io.Writer, args ...stri } archive = ProgressReader(resp.Body, int(resp.ContentLength), stdout) } - img, err := srv.runtime.graph.Create(archive, "", "Imported from "+src) + img, err := srv.runtime.graph.Create(archive, nil, "Imported from "+src) if err != nil { return err } diff --git a/container_test.go b/container_test.go index 64558871ac..94db11408d 100644 --- a/container_test.go +++ b/container_test.go @@ -46,7 +46,7 @@ func TestCommitRun(t *testing.T) { if err != nil { t.Error(err) } - img, err := runtime.graph.Create(rwTar, container1.Image, "unit test commited image") + img, err := runtime.graph.Create(rwTar, container1, "unit test commited image") if err != nil { t.Error(err) } diff --git a/graph.go b/graph.go index b0440518ad..c6bb30353a 100644 --- a/graph.go +++ b/graph.go @@ -47,13 +47,17 @@ func (graph *Graph) Get(id string) (*Image, error) { return img, nil } -func (graph *Graph) Create(layerData Archive, parent, comment string) (*Image, error) { +func (graph *Graph) Create(layerData Archive, container *Container, comment string) (*Image, error) { img := &Image{ Id: GenerateId(), - Parent: parent, Comment: comment, Created: time.Now(), } + if container != nil { + img.Parent = container.Image + img.ParentContainer = container.Id + img.ParentCommand = append([]string{container.Path}, container.Args...) + } if err := graph.Register(layerData, img); err != nil { return nil, err } diff --git a/graph_test.go b/graph_test.go index 20e879e52c..b9bdc5140f 100644 --- a/graph_test.go +++ b/graph_test.go @@ -35,7 +35,7 @@ func TestGraphCreate(t *testing.T) { if err != nil { t.Fatal(err) } - image, err := graph.Create(archive, "", "Testing") + image, err := graph.Create(archive, nil, "Testing") if err != nil { t.Fatal(err) } @@ -92,7 +92,7 @@ func TestMount(t *testing.T) { if err != nil { t.Fatal(err) } - image, err := graph.Create(archive, "", "Testing") + image, err := graph.Create(archive, nil, "Testing") if err != nil { t.Fatal(err) } @@ -128,7 +128,7 @@ func TestDelete(t *testing.T) { t.Fatal(err) } assertNImages(graph, t, 0) - img, err := graph.Create(archive, "", "Bla bla") + img, err := graph.Create(archive, nil, "Bla bla") if err != nil { t.Fatal(err) } @@ -139,11 +139,11 @@ func TestDelete(t *testing.T) { assertNImages(graph, t, 0) // Test 2 create (same name) / 1 delete - img1, err := graph.Create(archive, "foo", "Testing") + img1, err := graph.Create(archive, nil, "Testing") if err != nil { t.Fatal(err) } - if _, err = graph.Create(archive, "foo", "Testing"); err != nil { + if _, err = graph.Create(archive, nil, "Testing"); err != nil { t.Fatal(err) } assertNImages(graph, t, 2) diff --git a/image.go b/image.go index e508a164ea..84935e3996 100644 --- a/image.go +++ b/image.go @@ -15,11 +15,13 @@ import ( ) type Image struct { - Id string - Parent string - Comment string - Created time.Time - graph *Graph + Id string + Parent string + Comment string + Created time.Time + ParentContainer string + ParentCommand []string + graph *Graph } func LoadImage(root string) (*Image, error) { diff --git a/runtime.go b/runtime.go index 5df3b7b5b8..dcaaec6366 100644 --- a/runtime.go +++ b/runtime.go @@ -214,7 +214,7 @@ func (runtime *Runtime) Commit(id, repository, tag string) (*Image, error) { return nil, err } // Create a new image from the container's base layers + a new layer from container changes - img, err := runtime.graph.Create(rwTar, container.Image, "") + img, err := runtime.graph.Create(rwTar, container, "") if err != nil { return nil, err }