/* * Copyright 2026 Oleg Borodin * * This work is published and licensed under a Creative Commons * Attribution-NonCommercial-NoDerivatives 4.0 International License. * * Distribution of this work is permitted, but commercial use and * modifications are strictly prohibited. */ package main import ( "context" "net/url" "os" "path" "strings" "time" "mstore/pkg/client" "github.com/spf13/cobra" ) func packUserinfo(resurseuri, username, password string) (string, error) { var err error var res string if !strings.Contains(resurseuri, "://") { resurseuri = "https://" + resurseuri } uri, err := url.Parse(resurseuri) if err != nil { return res, err } uri.Path = path.Clean(uri.Path) if username != "" && password != "" { uri.User = url.UserPassword(username, password) } res = uri.String() return res, err } func (util *ImageUtil) CreateImageCmds() *cobra.Command { const defaultTimeout uint64 = 30 // Second var subCmd = &cobra.Command{ Use: "images", Short: "Image operations", Aliases: []string{"image"}, } subCmd.PersistentFlags().StringVarP(&util.commonImageParams.Username, "user", "u", "", "Username") subCmd.PersistentFlags().StringVarP(&util.commonImageParams.Password, "pass", "p", "", "Password") subCmd.PersistentFlags().Uint64VarP(&util.commonImageParams.Timeout, "timeout", "t", defaultTimeout, "Operation timeout") subCmd.MarkFlagsRequiredTogether("user", "pass") // PushImage var pushImageCmd = &cobra.Command{ Use: "push filename [user:pass@]hostname[:port]/path:tag", Short: "Push container image from local tar file into registry", Args: cobra.ExactArgs(2), Run: util.PushImage, } subCmd.AddCommand(pushImageCmd) // ImageInfo var imageInfoCmd = &cobra.Command{ Use: "info [user:pass@]hostname[:port]/path:tag", Short: "Show container image info", Args: cobra.ExactArgs(1), Run: util.ImageInfo, } subCmd.AddCommand(imageInfoCmd) // PullImage var pullImageCmd = &cobra.Command{ Use: "pull [user:pass@]hostname[:port]/path:tag filename", Short: "Pull container image from registry into local file", Args: cobra.ExactArgs(2), Run: util.PullImage, } subCmd.AddCommand(pullImageCmd) // DeleteImage var deleteImageCmd = &cobra.Command{ Use: "delete [user:pass@]hostname[:port]/path:tag", Short: "Delete container image from registry", Args: cobra.ExactArgs(1), Run: util.DeleteImage, } subCmd.AddCommand(deleteImageCmd) return subCmd } type ImageUtil struct { imageInfoParams ImageInfoParams pullImageParams PullImageParams pushImageParams PushImageParams deleteImageParams DeleteImageParams commonImageParams CommonImageParams } type CommonImageParams struct { Timeout uint64 Username string Password string } // PushImage type PushImageParams struct { Imagepath string Filepath string } type PushImageResult struct{} func (util *ImageUtil) PushImage(cmd *cobra.Command, args []string) { util.pushImageParams.Filepath = args[0] util.pushImageParams.Imagepath = args[1] res, err := util.pushImage(&util.commonImageParams, &util.pushImageParams) printResponse(res, err) } func (util *ImageUtil) pushImage(common *CommonImageParams, params *PushImageParams) (*PushImageResult, error) { var err error ctx := context.Background() res := &PushImageResult{} cli := client.NewClient() timeout := time.Duration(common.Timeout) * time.Second params.Imagepath, err = packUserinfo(params.Imagepath, common.Username, common.Password) if err != nil { return res, err } ctx, _ = context.WithTimeout(ctx, timeout) err = cli.PushImage(ctx, params.Filepath, params.Imagepath) if err != nil { return res, err } return res, err } // ImageInfo type ImageInfoParams struct { Imagepath string } type ImageInfoResult struct { ImageInfo *client.ImageDescr `yaml:"imageInfo"` } func (util *ImageUtil) ImageInfo(cmd *cobra.Command, args []string) { util.imageInfoParams.Imagepath = args[0] res, err := util.imageInfo(&util.commonImageParams, &util.imageInfoParams) printResponse(res, err) } func (util *ImageUtil) imageInfo(common *CommonImageParams, params *ImageInfoParams) (*ImageInfoResult, error) { var err error res := &ImageInfoResult{} ctx := context.Background() cli := client.NewClient() timeout := time.Duration(common.Timeout) * time.Second params.Imagepath, err = packUserinfo(params.Imagepath, common.Username, common.Password) if err != nil { return res, err } ctx, _ = context.WithTimeout(ctx, timeout) opres, err := cli.ImageInfo(ctx, params.Imagepath) if err != nil { return res, err } res.ImageInfo = opres return res, err } // PullImage type PullImageParams struct { Imagepath string Filepath string } type PullImageResult struct { Filepath string `yaml:"filepath"` Size int64 `yaml:"size"` } func (util *ImageUtil) PullImage(cmd *cobra.Command, args []string) { util.pullImageParams.Imagepath = args[0] util.pullImageParams.Filepath = args[1] res, err := util.pullImage(&util.commonImageParams, &util.pullImageParams) printResponse(res, err) } func (util *ImageUtil) pullImage(common *CommonImageParams, params *PullImageParams) (*PullImageResult, error) { var err error ctx := context.Background() res := &PullImageResult{} cli := client.NewClient() timeout := time.Duration(common.Timeout) * time.Second params.Imagepath, err = packUserinfo(params.Imagepath, common.Username, common.Password) if err != nil { return res, err } ctx, _ = context.WithTimeout(ctx, timeout) err = cli.PullImage(ctx, params.Imagepath, params.Filepath) if err != nil { return res, err } filestat, err := os.Stat(params.Filepath) if err != nil { return res, err } res.Size = filestat.Size() res.Filepath = params.Filepath return res, err } // DeleteImage type DeleteImageParams struct { Imagepath string } type DeleteImageResult struct { } func (util *ImageUtil) DeleteImage(cmd *cobra.Command, args []string) { util.deleteImageParams.Imagepath = args[0] res, err := util.deleteImage(&util.commonImageParams, &util.deleteImageParams) printResponse(res, err) } func (util *ImageUtil) deleteImage(common *CommonImageParams, params *DeleteImageParams) (*DeleteImageResult, error) { var err error res := &DeleteImageResult{} ctx := context.Background() cli := client.NewClient() timeout := time.Duration(common.Timeout) * time.Second params.Imagepath, err = packUserinfo(params.Imagepath, common.Username, common.Password) if err != nil { return res, err } ctx, _ = context.WithTimeout(ctx, timeout) err = cli.DeleteImage(ctx, params.Imagepath) if err != nil { return res, err } return res, err }