-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5093 from openSUSE/image-tree
Refactor image tree for API usage
- Loading branch information
Showing
12 changed files
with
254 additions
and
171 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
package image | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/docker/go-units" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
const ( | ||
middleItem = "├── " | ||
continueItem = "│ " | ||
lastItem = "└── " | ||
) | ||
|
||
type tree struct { | ||
img *Image | ||
imageInfo *InfoImage | ||
layerInfo map[string]*LayerInfo | ||
sb *strings.Builder | ||
} | ||
|
||
// GenerateTree creates an image tree string representation for displaying it | ||
// to the user. | ||
func (i *Image) GenerateTree(whatRequires bool) (string, error) { | ||
// Fetch map of image-layers, which is used for printing output. | ||
layerInfo, err := GetLayersMapWithImageInfo(i.imageruntime) | ||
if err != nil { | ||
return "", errors.Wrapf(err, "error while retrieving layers of image %q", i.InputName) | ||
} | ||
|
||
// Create an imageInfo and fill the image and layer info | ||
imageInfo := &InfoImage{ | ||
ID: i.ID(), | ||
Tags: i.Names(), | ||
} | ||
|
||
if err := BuildImageHierarchyMap(imageInfo, layerInfo, i.TopLayer()); err != nil { | ||
return "", err | ||
} | ||
sb := &strings.Builder{} | ||
tree := &tree{i, imageInfo, layerInfo, sb} | ||
if err := tree.print(whatRequires); err != nil { | ||
return "", err | ||
} | ||
return tree.string(), nil | ||
} | ||
|
||
func (t *tree) string() string { | ||
return t.sb.String() | ||
} | ||
|
||
func (t *tree) print(whatRequires bool) error { | ||
size, err := t.img.Size(context.Background()) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
fmt.Fprintf(t.sb, "Image ID: %s\n", t.imageInfo.ID[:12]) | ||
fmt.Fprintf(t.sb, "Tags: %s\n", t.imageInfo.Tags) | ||
fmt.Fprintf(t.sb, "Size: %v\n", units.HumanSizeWithPrecision(float64(*size), 4)) | ||
if t.img.TopLayer() != "" { | ||
fmt.Fprintf(t.sb, "Image Layers\n") | ||
} else { | ||
fmt.Fprintf(t.sb, "No Image Layers\n") | ||
} | ||
|
||
if !whatRequires { | ||
// fill imageInfo with layers associated with image. | ||
// the layers will be filled such that | ||
// (Start)RootLayer->...intermediate Parent Layer(s)-> TopLayer(End) | ||
// Build output from imageInfo into buffer | ||
t.printImageHierarchy(t.imageInfo) | ||
} else { | ||
// fill imageInfo with layers associated with image. | ||
// the layers will be filled such that | ||
// (Start)TopLayer->...intermediate Child Layer(s)-> Child TopLayer(End) | ||
// (Forks)... intermediate Child Layer(s) -> Child Top Layer(End) | ||
return t.printImageChildren(t.layerInfo, t.img.TopLayer(), "", true) | ||
} | ||
return nil | ||
} | ||
|
||
// Stores all children layers which are created using given Image. | ||
// Layers are stored as follows | ||
// (Start)TopLayer->...intermediate Child Layer(s)-> Child TopLayer(End) | ||
// (Forks)... intermediate Child Layer(s) -> Child Top Layer(End) | ||
func (t *tree) printImageChildren(layerMap map[string]*LayerInfo, layerID string, prefix string, last bool) error { | ||
if layerID == "" { | ||
return nil | ||
} | ||
ll, ok := layerMap[layerID] | ||
if !ok { | ||
return fmt.Errorf("lookup error: layerid %s, not found", layerID) | ||
} | ||
fmt.Fprint(t.sb, prefix) | ||
|
||
//initialize intend with middleItem to reduce middleItem checks. | ||
intend := middleItem | ||
if !last { | ||
// add continueItem i.e. '|' for next iteration prefix | ||
prefix += continueItem | ||
} else if len(ll.ChildID) > 1 || len(ll.ChildID) == 0 { | ||
// The above condition ensure, alignment happens for node, which has more then 1 children. | ||
// If node is last in printing hierarchy, it should not be printed as middleItem i.e. ├── | ||
intend = lastItem | ||
prefix += " " | ||
} | ||
|
||
var tags string | ||
if len(ll.RepoTags) > 0 { | ||
tags = fmt.Sprintf(" Top Layer of: %s", ll.RepoTags) | ||
} | ||
fmt.Fprintf(t.sb, "%sID: %s Size: %7v%s\n", intend, ll.ID[:12], units.HumanSizeWithPrecision(float64(ll.Size), 4), tags) | ||
for count, childID := range ll.ChildID { | ||
if err := t.printImageChildren(layerMap, childID, prefix, count == len(ll.ChildID)-1); err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
// prints the layers info of image | ||
func (t *tree) printImageHierarchy(imageInfo *InfoImage) { | ||
for count, l := range imageInfo.Layers { | ||
var tags string | ||
intend := middleItem | ||
if len(l.RepoTags) > 0 { | ||
tags = fmt.Sprintf(" Top Layer of: %s", l.RepoTags) | ||
} | ||
if count == len(imageInfo.Layers)-1 { | ||
intend = lastItem | ||
} | ||
fmt.Fprintf(t.sb, "%s ID: %s Size: %7v%s\n", intend, l.ID[:12], units.HumanSizeWithPrecision(float64(l.Size), 4), tags) | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.