github.com/buildpacks/pack@v0.33.3-0.20240516162812-884dd1837311/internal/commands/config_run_image_mirrors.go (about) 1 package commands 2 3 import ( 4 "fmt" 5 "sort" 6 "strings" 7 8 "github.com/pkg/errors" 9 "github.com/spf13/cobra" 10 11 "github.com/buildpacks/pack/internal/config" 12 "github.com/buildpacks/pack/internal/stringset" 13 "github.com/buildpacks/pack/internal/style" 14 "github.com/buildpacks/pack/pkg/logging" 15 ) 16 17 var mirrors []string 18 19 func ConfigRunImagesMirrors(logger logging.Logger, cfg config.Config, cfgPath string) *cobra.Command { 20 cmd := &cobra.Command{ 21 Use: "run-image-mirrors", 22 Short: "List, add and remove run image mirrors", 23 Args: cobra.MaximumNArgs(3), 24 RunE: logError(logger, func(cmd *cobra.Command, args []string) error { 25 listRunImageMirror(args, logger, cfg) 26 return nil 27 }), 28 } 29 30 listCmd := generateListCmd(cmd.Use, logger, cfg, listRunImageMirror) 31 listCmd.Long = "List all run image mirrors. If a run image is provided, it will return " 32 listCmd.Use = "list [<run-image>]" 33 listCmd.Example = "pack config run-image-mirrors list" 34 cmd.AddCommand(listCmd) 35 36 addCmd := generateAdd("mirror for a run image", logger, cfg, cfgPath, addRunImageMirror) 37 addCmd.Use = "add <image> [-m <mirror...]" 38 addCmd.Long = "Set mirrors to other repositories for a given run image" 39 addCmd.Example = "pack config run-image-mirrors add cnbs/sample-stack-run:bionic --mirror index.docker.io/cnbs/sample-stack-run:bionic --mirror gcr.io/cnbs/sample-stack-run:bionic" 40 addCmd.Flags().StringSliceVarP(&mirrors, "mirror", "m", nil, "Run image mirror"+stringSliceHelp("mirror")) 41 cmd.AddCommand(addCmd) 42 43 rmCmd := generateRemove("mirror for a run image", logger, cfg, cfgPath, removeRunImageMirror) 44 rmCmd.Use = "remove <image> [-m <mirror...]" 45 rmCmd.Long = "Remove mirrors for a given run image. If specific mirrors are passed, they will be removed. " + 46 "If no mirrors are provided, all mirrors for the given run image will be removed from the config." 47 rmCmd.Example = "pack config run-image-mirrors remove cnbs/sample-stack-run:bionic" 48 rmCmd.Flags().StringSliceVarP(&mirrors, "mirror", "m", nil, "Run image mirror"+stringSliceHelp("mirror")) 49 cmd.AddCommand(rmCmd) 50 51 AddHelpFlag(cmd, "run-image-mirrors") 52 return cmd 53 } 54 55 func addRunImageMirror(args []string, logger logging.Logger, cfg config.Config, cfgPath string) error { 56 runImage := args[0] 57 if len(mirrors) == 0 { 58 logger.Infof("No run image mirrors were provided.") 59 return nil 60 } 61 62 newMirrors := mirrors 63 for _, image := range cfg.RunImages { 64 if image.Image == runImage { 65 newMirrors = append(newMirrors, image.Mirrors...) 66 break 67 } 68 } 69 70 cfg = config.SetRunImageMirrors(cfg, runImage, dedupAndSortSlice(newMirrors)) 71 if err := config.Write(cfg, cfgPath); err != nil { 72 return errors.Wrapf(err, "failed to write to %s", cfgPath) 73 } 74 75 for _, mirror := range mirrors { 76 logger.Infof("Run Image %s configured with mirror %s", style.Symbol(runImage), style.Symbol(mirror)) 77 } 78 return nil 79 } 80 81 func removeRunImageMirror(args []string, logger logging.Logger, cfg config.Config, cfgPath string) error { 82 image := args[0] 83 84 idx := -1 85 for i, runImage := range cfg.RunImages { 86 if runImage.Image == image { 87 idx = i 88 } 89 } 90 91 if idx == -1 || len(cfg.RunImages) == 0 { 92 // Run Image wasn't found 93 logger.Infof("No run image mirrors have been set for %s", style.Symbol(image)) 94 return nil 95 } 96 97 mirrorsMap := stringset.FromSlice(mirrors) 98 var newMirrors []string 99 for _, currMirror := range cfg.RunImages[idx].Mirrors { 100 if _, ok := mirrorsMap[currMirror]; !ok { 101 newMirrors = append(newMirrors, currMirror) 102 } 103 } 104 105 if len(newMirrors) == 0 || len(mirrors) == 0 { 106 lastImageIdx := len(cfg.RunImages) - 1 107 cfg.RunImages[idx] = cfg.RunImages[lastImageIdx] 108 cfg.RunImages = cfg.RunImages[:lastImageIdx] 109 } else { 110 cfg = config.SetRunImageMirrors(cfg, image, newMirrors) 111 } 112 113 if err := config.Write(cfg, cfgPath); err != nil { 114 return errors.Wrapf(err, "failed to write to %s", cfgPath) 115 } 116 if len(mirrors) == 0 { 117 logger.Infof("Removed all run image mirrors for %s", style.Symbol(image)) 118 } else { 119 logger.Infof("Removed mirrors %s for %s", strings.Join(mirrors, ", "), style.Symbol(image)) 120 } 121 122 return nil 123 } 124 125 func listRunImageMirror(args []string, logger logging.Logger, cfg config.Config) { 126 var ( 127 reqImage string 128 found = false 129 ) 130 131 if len(args) > 0 { 132 reqImage = args[0] 133 } 134 135 buf := strings.Builder{} 136 buf.WriteString("Run Image Mirrors:\n") 137 for _, runImage := range cfg.RunImages { 138 if (reqImage != "" && runImage.Image == reqImage) || reqImage == "" { 139 found = true 140 buf.WriteString(fmt.Sprintf(" %s:\n", style.Symbol(runImage.Image))) 141 for _, mirror := range runImage.Mirrors { 142 buf.WriteString(fmt.Sprintf(" %s\n", mirror)) 143 } 144 } 145 } 146 147 if !found { 148 suffix := "" 149 if reqImage != "" { 150 suffix = fmt.Sprintf("for %s", style.Symbol(reqImage)) 151 } 152 logger.Infof("No run image mirrors have been set %s", suffix) 153 } else { 154 logger.Info(buf.String()) 155 } 156 } 157 158 func dedupAndSortSlice(slice []string) []string { 159 set := stringset.FromSlice(slice) 160 var newSlice []string 161 for s := range set { 162 newSlice = append(newSlice, s) 163 } 164 sort.Strings(newSlice) 165 return newSlice 166 }