github.com/loafoe/cli@v7.1.0+incompatible/command/v7/update_buildpack_command.go (about) 1 package v7 2 3 import ( 4 "io/ioutil" 5 "os" 6 "time" 7 8 "code.cloudfoundry.org/cli/actor/v7action" 9 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 10 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" 11 "code.cloudfoundry.org/cli/command" 12 "code.cloudfoundry.org/cli/command/flag" 13 "code.cloudfoundry.org/cli/command/translatableerror" 14 "code.cloudfoundry.org/cli/types" 15 "code.cloudfoundry.org/cli/util/configv3" 16 "code.cloudfoundry.org/cli/util/download" 17 ) 18 19 type UpdateBuildpackActor interface { 20 UpdateBuildpackByNameAndStack(buildpackName string, buildpackStack string, buildpack v7action.Buildpack) (v7action.Buildpack, v7action.Warnings, error) 21 UploadBuildpack(guid string, pathToBuildpackBits string, progressBar v7action.SimpleProgressBar) (ccv3.JobURL, v7action.Warnings, error) 22 PrepareBuildpackBits(inputPath string, tmpDirPath string, downloader v7action.Downloader) (string, error) 23 PollUploadBuildpackJob(jobURL ccv3.JobURL) (v7action.Warnings, error) 24 } 25 26 type UpdateBuildpackCommand struct { 27 BaseCommand 28 29 RequiredArgs flag.BuildpackName `positional-args:"Yes"` 30 usage interface{} `usage:"CF_NAME update-buildpack BUILDPACK [-p PATH | -s STACK | --assign-stack NEW_STACK] [-i POSITION] [--rename NEW_NAME] [--enable|--disable] [--lock|--unlock]\n\nTIP:\nPath should be a zip file, a url to a zip file, or a local directory. Position is a positive integer, sets priority, and is sorted from lowest to highest.\n\nUse '--assign-stack' with caution. Associating a buildpack with a stack that it does not support may result in undefined behavior. Additionally, changing this association once made may require a local copy of the buildpack.\n\n"` 31 relatedCommands interface{} `related_commands:"buildpacks, create-buildpack, delete-buildpack"` 32 NewStack string `long:"assign-stack" description:"Assign a stack to a buildpack that does not have a stack association"` 33 Disable bool `long:"disable" description:"Disable the buildpack from being used for staging"` 34 Enable bool `long:"enable" description:"Enable the buildpack to be used for staging"` 35 Lock bool `long:"lock" description:"Lock the buildpack to prevent updates"` 36 Path flag.PathWithExistenceCheckOrURL `long:"path" short:"p" description:"Path to directory or zip file"` 37 Position types.NullInt `long:"position" short:"i" description:"The order in which the buildpacks are checked during buildpack auto-detection"` 38 NewName string `long:"rename" description:"Rename an existing buildpack"` 39 CurrentStack string `long:"stack" short:"s" description:"Specify stack to disambiguate buildpacks with the same name"` 40 Unlock bool `long:"unlock" description:"Unlock the buildpack to enable updates"` 41 42 ProgressBar v7action.SimpleProgressBar 43 } 44 45 func (cmd *UpdateBuildpackCommand) Setup(config command.Config, ui command.UI) error { 46 cmd.ProgressBar = v7action.NewProgressBar() 47 return cmd.BaseCommand.Setup(config, ui) 48 } 49 50 func (cmd UpdateBuildpackCommand) Execute(args []string) error { 51 var buildpackBitsPath, tmpDirPath string 52 53 user, err := cmd.validateSetup() 54 if err != nil { 55 return err 56 } 57 58 cmd.printInitialText(user.Name) 59 60 if cmd.Path != "" { 61 buildpackBitsPath, tmpDirPath, err = cmd.prepareBuildpackBits() 62 if err != nil { 63 return err 64 } 65 defer os.RemoveAll(tmpDirPath) 66 } 67 68 updatedBuildpack, err := cmd.updateBuildpack() 69 if err != nil { 70 return err 71 } 72 73 if buildpackBitsPath != "" { 74 return cmd.uploadBits(user, updatedBuildpack, buildpackBitsPath) 75 } 76 77 return nil 78 } 79 80 func (cmd UpdateBuildpackCommand) validateSetup() (configv3.User, error) { 81 var user configv3.User 82 83 err := cmd.validateFlagCombinations() 84 if err != nil { 85 return user, err 86 } 87 88 err = cmd.SharedActor.CheckTarget(false, false) 89 if err != nil { 90 return user, err 91 } 92 93 return cmd.Config.CurrentUser() 94 } 95 96 func (cmd UpdateBuildpackCommand) prepareBuildpackBits() (string, string, error) { 97 downloader := download.NewDownloader(time.Second * 30) 98 tmpDirPath, err := ioutil.TempDir("", "buildpack-dir-") 99 if err != nil { 100 return "", "", err 101 } 102 103 buildpackBits, err := cmd.Actor.PrepareBuildpackBits(string(cmd.Path), tmpDirPath, downloader) 104 return buildpackBits, tmpDirPath, err 105 } 106 107 func (cmd UpdateBuildpackCommand) updateBuildpack() (v7action.Buildpack, error) { 108 var desiredBuildpack v7action.Buildpack 109 110 desiredBuildpack.Enabled = types.NullBool{IsSet: cmd.Enable || cmd.Disable, Value: cmd.Enable} 111 desiredBuildpack.Locked = types.NullBool{IsSet: cmd.Lock || cmd.Unlock, Value: cmd.Lock} 112 desiredBuildpack.Position = cmd.Position 113 114 if cmd.NewStack != "" { 115 desiredBuildpack.Stack = cmd.NewStack 116 } 117 118 if cmd.NewName != "" { 119 desiredBuildpack.Name = cmd.NewName 120 } 121 122 updatedBuildpack, warnings, err := cmd.Actor.UpdateBuildpackByNameAndStack( 123 cmd.RequiredArgs.Buildpack, 124 cmd.CurrentStack, 125 desiredBuildpack, 126 ) 127 cmd.UI.DisplayWarnings(warnings) 128 if err != nil { 129 return updatedBuildpack, err 130 } 131 cmd.UI.DisplayOK() 132 133 return updatedBuildpack, nil 134 } 135 136 func (cmd UpdateBuildpackCommand) uploadBits(user configv3.User, updatedBuildpack v7action.Buildpack, buildpackBitsPath string) error { 137 cmd.UI.DisplayTextWithFlavor("Uploading buildpack {{.Buildpack}} as {{.Username}}...", map[string]interface{}{ 138 "Buildpack": cmd.RequiredArgs.Buildpack, 139 "Username": user.Name, 140 }) 141 142 jobURL, warnings, err := cmd.Actor.UploadBuildpack( 143 updatedBuildpack.GUID, 144 buildpackBitsPath, 145 cmd.ProgressBar, 146 ) 147 if _, ok := err.(ccerror.InvalidAuthTokenError); ok { 148 cmd.UI.DisplayWarnings([]string{"Failed to upload buildpack due to auth token expiration, retrying..."}) 149 jobURL, warnings, err = cmd.Actor.UploadBuildpack(updatedBuildpack.GUID, buildpackBitsPath, cmd.ProgressBar) 150 } 151 cmd.UI.DisplayWarnings(warnings) 152 if err != nil { 153 return err 154 } 155 cmd.UI.DisplayOK() 156 157 cmd.UI.DisplayTextWithFlavor("Processing uploaded buildpack {{.BuildpackName}}...", map[string]interface{}{ 158 "BuildpackName": cmd.RequiredArgs.Buildpack, 159 }) 160 161 warnings, err = cmd.Actor.PollUploadBuildpackJob(jobURL) 162 cmd.UI.DisplayWarnings(warnings) 163 if err != nil { 164 return err 165 } 166 167 cmd.UI.DisplayOK() 168 return nil 169 } 170 171 func (cmd UpdateBuildpackCommand) printInitialText(userName string) { 172 var originalBuildpackName = cmd.RequiredArgs.Buildpack 173 var buildpackName = originalBuildpackName 174 175 if cmd.NewName != "" { 176 buildpackName = cmd.NewName 177 cmd.UI.DisplayTextWithFlavor("Renaming buildpack {{.Buildpack}} to {{.DesiredBuildpackName}} as {{.CurrentUser}}...\n", map[string]interface{}{ 178 "Buildpack": originalBuildpackName, 179 "CurrentUser": userName, 180 "DesiredBuildpackName": cmd.NewName, 181 }) 182 } 183 184 switch { 185 case cmd.NewStack != "": 186 cmd.UI.DisplayTextWithFlavor("Assigning stack {{.Stack}} to {{.Buildpack}} as {{.CurrentUser}}...", map[string]interface{}{ 187 "Buildpack": buildpackName, 188 "CurrentUser": userName, 189 "Stack": cmd.NewStack, 190 }) 191 if cmd.Position.IsSet || cmd.Lock || cmd.Unlock || cmd.Enable || cmd.Disable { 192 cmd.UI.DisplayTextWithFlavor("\nUpdating buildpack {{.Buildpack}} with stack {{.Stack}} as {{.CurrentUser}}...", map[string]interface{}{ 193 "Buildpack": buildpackName, 194 "CurrentUser": userName, 195 "Stack": cmd.NewStack, 196 }) 197 } 198 case cmd.CurrentStack == "": 199 cmd.UI.DisplayTextWithFlavor("Updating buildpack {{.Buildpack}} as {{.CurrentUser}}...", map[string]interface{}{ 200 "Buildpack": buildpackName, 201 "CurrentUser": userName, 202 }) 203 default: 204 cmd.UI.DisplayTextWithFlavor("Updating buildpack {{.Buildpack}} with stack {{.Stack}} as {{.CurrentUser}}...", map[string]interface{}{ 205 "Buildpack": buildpackName, 206 "CurrentUser": userName, 207 "Stack": cmd.CurrentStack, 208 }) 209 } 210 } 211 212 func (cmd UpdateBuildpackCommand) validateFlagCombinations() error { 213 if cmd.Lock && cmd.Unlock { 214 return translatableerror.ArgumentCombinationError{ 215 Args: []string{"--lock", "--unlock"}, 216 } 217 } 218 219 if cmd.Enable && cmd.Disable { 220 return translatableerror.ArgumentCombinationError{ 221 Args: []string{"--enable", "--disable"}, 222 } 223 } 224 225 if cmd.Path != "" && cmd.Lock { 226 return translatableerror.ArgumentCombinationError{ 227 Args: []string{"--path", "--lock"}, 228 } 229 } 230 231 if cmd.Path != "" && cmd.NewStack != "" { 232 return translatableerror.ArgumentCombinationError{ 233 Args: []string{"--path", "--assign-stack"}, 234 } 235 } 236 237 if cmd.CurrentStack != "" && cmd.NewStack != "" { 238 return translatableerror.ArgumentCombinationError{ 239 Args: []string{"--stack", "--assign-stack"}, 240 } 241 } 242 return nil 243 }