github.com/niteshexa/cloudfoundry_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  }