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