mirror of https://github.com/docker/docs.git
Show shorthand image IDs for convenience. Shorthand IDs (or any non-conflicting prefix) can be used to lookup images
This commit is contained in:
parent
a52a28b609
commit
1632566ecb
14
commands.go
14
commands.go
|
@ -372,7 +372,7 @@ func (srv *Server) CmdHistory(stdin io.ReadCloser, stdout io.Writer, args ...str
|
||||||
fmt.Fprintf(w, "ID\tCREATED\tCREATED BY\n")
|
fmt.Fprintf(w, "ID\tCREATED\tCREATED BY\n")
|
||||||
return image.WalkHistory(func(img *Image) error {
|
return image.WalkHistory(func(img *Image) error {
|
||||||
fmt.Fprintf(w, "%s\t%s\t%s\n",
|
fmt.Fprintf(w, "%s\t%s\t%s\n",
|
||||||
srv.runtime.repositories.ImageName(img.Id),
|
srv.runtime.repositories.ImageName(img.ShortId()),
|
||||||
HumanDuration(time.Now().Sub(img.Created))+" ago",
|
HumanDuration(time.Now().Sub(img.Created))+" ago",
|
||||||
strings.Join(img.ContainerConfig.Cmd, " "),
|
strings.Join(img.ContainerConfig.Cmd, " "),
|
||||||
)
|
)
|
||||||
|
@ -458,7 +458,7 @@ func (srv *Server) CmdImport(stdin io.ReadCloser, stdout io.Writer, args ...stri
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Fprintln(stdout, img.Id)
|
fmt.Fprintln(stdout, img.ShortId())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -591,7 +591,7 @@ func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...stri
|
||||||
for idx, field := range []string{
|
for idx, field := range []string{
|
||||||
/* REPOSITORY */ name,
|
/* REPOSITORY */ name,
|
||||||
/* TAG */ tag,
|
/* TAG */ tag,
|
||||||
/* ID */ id,
|
/* ID */ TruncateId(id),
|
||||||
/* CREATED */ HumanDuration(time.Now().Sub(image.Created)) + " ago",
|
/* CREATED */ HumanDuration(time.Now().Sub(image.Created)) + " ago",
|
||||||
/* PARENT */ srv.runtime.repositories.ImageName(image.Parent),
|
/* PARENT */ srv.runtime.repositories.ImageName(image.Parent),
|
||||||
} {
|
} {
|
||||||
|
@ -603,7 +603,7 @@ func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...stri
|
||||||
}
|
}
|
||||||
w.Write([]byte{'\n'})
|
w.Write([]byte{'\n'})
|
||||||
} else {
|
} else {
|
||||||
stdout.Write([]byte(image.Id + "\n"))
|
stdout.Write([]byte(image.ShortId() + "\n"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -614,7 +614,7 @@ func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...stri
|
||||||
for idx, field := range []string{
|
for idx, field := range []string{
|
||||||
/* REPOSITORY */ "<none>",
|
/* REPOSITORY */ "<none>",
|
||||||
/* TAG */ "<none>",
|
/* TAG */ "<none>",
|
||||||
/* ID */ id,
|
/* ID */ TruncateId(id),
|
||||||
/* CREATED */ HumanDuration(time.Now().Sub(image.Created)) + " ago",
|
/* CREATED */ HumanDuration(time.Now().Sub(image.Created)) + " ago",
|
||||||
/* PARENT */ srv.runtime.repositories.ImageName(image.Parent),
|
/* PARENT */ srv.runtime.repositories.ImageName(image.Parent),
|
||||||
} {
|
} {
|
||||||
|
@ -626,7 +626,7 @@ func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...stri
|
||||||
}
|
}
|
||||||
w.Write([]byte{'\n'})
|
w.Write([]byte{'\n'})
|
||||||
} else {
|
} else {
|
||||||
stdout.Write([]byte(image.Id + "\n"))
|
stdout.Write([]byte(image.ShortId() + "\n"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -700,7 +700,7 @@ func (srv *Server) CmdCommit(stdin io.ReadCloser, stdout io.Writer, args ...stri
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Fprintln(stdout, img.Id)
|
fmt.Fprintln(stdout, img.ShortId())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -566,11 +566,7 @@ func (container *Container) Unmount() error {
|
||||||
// In case of a collision a lookup with Runtime.Get() will fail, and the caller
|
// In case of a collision a lookup with Runtime.Get() will fail, and the caller
|
||||||
// will need to use a langer prefix, or the full-length container Id.
|
// will need to use a langer prefix, or the full-length container Id.
|
||||||
func (container *Container) ShortId() string {
|
func (container *Container) ShortId() string {
|
||||||
shortLen := 12
|
return TruncateId(container.Id)
|
||||||
if len(container.Id) < shortLen {
|
|
||||||
shortLen = len(container.Id)
|
|
||||||
}
|
|
||||||
return container.Id[:shortLen]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) logPath(name string) string {
|
func (container *Container) logPath(name string) string {
|
||||||
|
|
42
graph.go
42
graph.go
|
@ -12,7 +12,8 @@ import (
|
||||||
|
|
||||||
// A Graph is a store for versioned filesystem images, and the relationship between them.
|
// A Graph is a store for versioned filesystem images, and the relationship between them.
|
||||||
type Graph struct {
|
type Graph struct {
|
||||||
Root string
|
Root string
|
||||||
|
idIndex *TruncIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGraph instanciates a new graph at the given root path in the filesystem.
|
// NewGraph instanciates a new graph at the given root path in the filesystem.
|
||||||
|
@ -26,9 +27,26 @@ func NewGraph(root string) (*Graph, error) {
|
||||||
if err := os.Mkdir(root, 0700); err != nil && !os.IsExist(err) {
|
if err := os.Mkdir(root, 0700); err != nil && !os.IsExist(err) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &Graph{
|
graph := &Graph{
|
||||||
Root: abspath,
|
Root: abspath,
|
||||||
}, nil
|
idIndex: NewTruncIndex(),
|
||||||
|
}
|
||||||
|
if err := graph.restore(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return graph, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (graph *Graph) restore() error {
|
||||||
|
dir, err := ioutil.ReadDir(graph.Root)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, v := range dir {
|
||||||
|
id := v.Name()
|
||||||
|
graph.idIndex.Add(id)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Implement error subclass instead of looking at the error text
|
// FIXME: Implement error subclass instead of looking at the error text
|
||||||
|
@ -47,7 +65,11 @@ func (graph *Graph) Exists(id string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns the image with the given id, or an error if the image doesn't exist.
|
// Get returns the image with the given id, or an error if the image doesn't exist.
|
||||||
func (graph *Graph) Get(id string) (*Image, error) {
|
func (graph *Graph) Get(name string) (*Image, error) {
|
||||||
|
id, err := graph.idIndex.Get(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
// FIXME: return nil when the image doesn't exist, instead of an error
|
// FIXME: return nil when the image doesn't exist, instead of an error
|
||||||
img, err := LoadImage(graph.imageRoot(id))
|
img, err := LoadImage(graph.imageRoot(id))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -101,6 +123,7 @@ func (graph *Graph) Register(layerData Archive, img *Image) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
img.graph = graph
|
img.graph = graph
|
||||||
|
graph.idIndex.Add(img.Id)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,8 +166,11 @@ func (graph *Graph) Delete(id string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
graph.idIndex.Delete(id)
|
||||||
err = os.Rename(graph.imageRoot(id), garbage.imageRoot(id))
|
err = os.Rename(graph.imageRoot(id), garbage.imageRoot(id))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// FIXME: this introduces a race condition in Delete() if the image is already present
|
||||||
|
// in garbage. Let's store at random names in grabage instead.
|
||||||
if isNotEmpty(err) {
|
if isNotEmpty(err) {
|
||||||
Debugf("The image %s is already present in garbage. Removing it.", id)
|
Debugf("The image %s is already present in garbage. Removing it.", id)
|
||||||
if err = os.RemoveAll(garbage.imageRoot(id)); err != nil {
|
if err = os.RemoveAll(garbage.imageRoot(id)); err != nil {
|
||||||
|
@ -170,7 +196,11 @@ func (graph *Graph) Undelete(id string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return os.Rename(garbage.imageRoot(id), graph.imageRoot(id))
|
if err := os.Rename(garbage.imageRoot(id), graph.imageRoot(id)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
graph.idIndex.Add(id)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GarbageCollect definitely deletes all images moved to the garbage
|
// GarbageCollect definitely deletes all images moved to the garbage
|
||||||
|
|
4
image.go
4
image.go
|
@ -150,6 +150,10 @@ func (image *Image) Changes(rw string) ([]Change, error) {
|
||||||
return Changes(layers, rw)
|
return Changes(layers, rw)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (image *Image) ShortId() string {
|
||||||
|
return TruncateId(image.Id)
|
||||||
|
}
|
||||||
|
|
||||||
func ValidateId(id string) error {
|
func ValidateId(id string) error {
|
||||||
if id == "" {
|
if id == "" {
|
||||||
return fmt.Errorf("Image id can't be empty")
|
return fmt.Errorf("Image id can't be empty")
|
||||||
|
|
2
tags.go
2
tags.go
|
@ -106,7 +106,7 @@ func (store *TagStore) ImageName(id string) string {
|
||||||
if names, exists := store.ById()[id]; exists && len(names) > 0 {
|
if names, exists := store.ById()[id]; exists && len(names) > 0 {
|
||||||
return names[0]
|
return names[0]
|
||||||
}
|
}
|
||||||
return id
|
return TruncateId(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *TagStore) Set(repoName, tag, imageName string, force bool) error {
|
func (store *TagStore) Set(repoName, tag, imageName string, force bool) error {
|
||||||
|
|
12
utils.go
12
utils.go
|
@ -334,3 +334,15 @@ func (idx *TruncIndex) Get(s string) (string, error) {
|
||||||
}
|
}
|
||||||
return string(idx.bytes[before:after]), err
|
return string(idx.bytes[before:after]), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TruncateId returns a shorthand version of a string identifier for convenience.
|
||||||
|
// A collision with other shorthands is very unlikely, but possible.
|
||||||
|
// In case of a collision a lookup with TruncIndex.Get() will fail, and the caller
|
||||||
|
// will need to use a langer prefix, or the full-length Id.
|
||||||
|
func TruncateId(id string) string {
|
||||||
|
shortLen := 12
|
||||||
|
if len(id) < shortLen {
|
||||||
|
shortLen = len(id)
|
||||||
|
}
|
||||||
|
return id[:shortLen]
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue