diff --git a/cmd/cli/image_test.go b/cmd/cli/image_test.go index 7c7d4d2027663e80a4007f8edfffd4f0703e9c75..d7a4f319d226e9512584a1d5ff8fb403c5760482 100644 --- a/cmd/cli/image_test.go +++ b/cmd/cli/image_test.go @@ -27,9 +27,16 @@ func TestImageCommand(t *testing.T) { assert.ErrorContains(t, err, "isula_build.sock") } +func TestImageCommandMultipleArgs(t *testing.T) { + imageCmd := NewImagesCmd() + args := []string{"aaa", "bbb"} + err := imagesCommand(imageCmd, args) + assert.ErrorContains(t, err, "requires at most one argument") +} + func TestRunList(t *testing.T) { ctx := context.Background() cli := newMockClient(&mockGrpcClient{}) - err := runList(ctx, &cli) + err := runList(ctx, &cli, "") assert.NilError(t, err) } diff --git a/cmd/cli/images.go b/cmd/cli/images.go index 6b3f1db4e11fdb8b8561835a36e3b23cb442e245..bded3617564a7f90a24b09daee8092cb5dbd4bf0 100644 --- a/cmd/cli/images.go +++ b/cmd/cli/images.go @@ -18,11 +18,11 @@ import ( "fmt" "github.com/bndr/gotabulate" + "github.com/pkg/errors" "github.com/spf13/cobra" constant "isula.org/isula-build" pb "isula.org/isula-build/api/services" - "isula.org/isula-build/util" ) const ( @@ -33,17 +33,17 @@ REPOSITORY TAG IMAGE ID CREATED ) const ( - imagesExample = `isula-build ctr-img images` + imagesExample = `isula-build ctr-img images +isula-build ctr-img images ` ) // NewImagesCmd returns images command func NewImagesCmd() *cobra.Command { // imagesCmd represents the "images" command imagesCmd := &cobra.Command{ - Use: "images", + Use: "images [REPOSITORY[:TAG]]", Short: "List locally stored images", Example: imagesExample, - Args: util.NoArgs, RunE: imagesCommand, } @@ -51,18 +51,29 @@ func NewImagesCmd() *cobra.Command { } func imagesCommand(c *cobra.Command, args []string) error { + if len(args) > 1 { + return errors.New("isula-build images requires at most one argument") + } + + var image string + if len(args) == 0 { + image = "" + } else { + image = args[0] + } + ctx := context.TODO() cli, err := NewClient(ctx) if err != nil { return err } - return runList(ctx, cli) + return runList(ctx, cli, image) } -func runList(ctx context.Context, cli Cli) error { +func runList(ctx context.Context, cli Cli, image string) error { resp, err := cli.Client().List(ctx, &pb.ListRequest{ - ImageName: "", + ImageName: image, }) if err != nil { return err diff --git a/daemon/images.go b/daemon/images.go index e5b5cdf495da582aa3d3014ccb261c0f3e32d9bc..f572f5e6b9025185276a5755fa03e7a5bae01da4 100644 --- a/daemon/images.go +++ b/daemon/images.go @@ -23,6 +23,7 @@ import ( constant "isula.org/isula-build" pb "isula.org/isula-build/api/services" + "isula.org/isula-build/image" "isula.org/isula-build/store" "isula.org/isula-build/util" ) @@ -37,12 +38,29 @@ func (b *Backend) List(ctx context.Context, req *pb.ListRequest) (*pb.ListRespon "ImageName": req.GetImageName(), }).Info("ListRequest received") - imageName := req.ImageName - reqRepository, reqTag := imageName, "" + var reqRepository, reqTag string const minImageFieldLenWithTag = 2 - parts := strings.Split(imageName, ":") - if len(parts) >= minImageFieldLenWithTag { - reqRepository, reqTag = strings.Join(parts[0:len(parts)-1], ":"), parts[len(parts)-1] + if req.ImageName != "" { + imageName := req.ImageName + _, img, err := image.FindImage(b.daemon.localStore, imageName) + if err != nil { + return nil, errors.Wrapf(err, "find local image %v error", imageName) + } + + parts := strings.Split(imageName, ":") + if len(parts) >= minImageFieldLenWithTag { + reqRepository, reqTag = strings.Join(parts[0:len(parts)-1], ":"), parts[len(parts)-1] + } + + imageInfo := &pb.ListResponse_ImageInfo{ + Repository: reqRepository, + Tag: reqTag, + Id: img.ID, + Created: img.Created.Format(constant.LayoutTime), + Size_: getImageSize(&b.daemon.localStore, img.ID), + } + + return &pb.ListResponse{Images: []*pb.ListResponse_ImageInfo{imageInfo}}, nil } images, err := b.daemon.localStore.Images()