github.com/arunkumar7540/cli@v6.45.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/sharedaction"
     9  	"code.cloudfoundry.org/cli/actor/v7action"
    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/command/v7/shared"
    15  	"code.cloudfoundry.org/cli/types"
    16  	"code.cloudfoundry.org/cli/util/configv3"
    17  	"code.cloudfoundry.org/cli/util/download"
    18  )
    19  
    20  //go:generate counterfeiter . UpdateBuildpackActor
    21  
    22  type UpdateBuildpackActor interface {
    23  	UpdateBuildpackByNameAndStack(buildpackName string, buildpackStack string, buildpack v7action.Buildpack) (v7action.Buildpack, v7action.Warnings, error)
    24  	UploadBuildpack(guid string, pathToBuildpackBits string, progressBar v7action.SimpleProgressBar) (ccv3.JobURL, v7action.Warnings, error)
    25  	PrepareBuildpackBits(inputPath string, tmpDirPath string, downloader v7action.Downloader) (string, error)
    26  	PollUploadBuildpackJob(jobURL ccv3.JobURL) (v7action.Warnings, error)
    27  }
    28  
    29  type UpdateBuildpackCommand struct {
    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] [--enable|--disable] [--lock|--unlock] [--rename]\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  	UI          command.UI
    44  	Config      command.Config
    45  	ProgressBar v7action.SimpleProgressBar
    46  	SharedActor command.SharedActor
    47  	Actor       UpdateBuildpackActor
    48  }
    49  
    50  func (cmd *UpdateBuildpackCommand) Setup(config command.Config, ui command.UI) error {
    51  	cmd.UI = ui
    52  	cmd.Config = config
    53  	sharedActor := sharedaction.NewActor(config)
    54  	cmd.SharedActor = sharedActor
    55  
    56  	ccClient, uaaClient, err := shared.NewClients(config, ui, true, "")
    57  	if err != nil {
    58  		return err
    59  	}
    60  	cmd.Actor = v7action.NewActor(ccClient, config, sharedActor, uaaClient)
    61  	cmd.ProgressBar = v7action.NewProgressBar()
    62  
    63  	return nil
    64  }
    65  
    66  func (cmd UpdateBuildpackCommand) Execute(args []string) error {
    67  	var buildpackBitsPath, tmpDirPath string
    68  
    69  	user, err := cmd.validateSetup()
    70  	if err != nil {
    71  		return err
    72  	}
    73  
    74  	cmd.printInitialText(user.Name)
    75  
    76  	if cmd.Path != "" {
    77  		buildpackBitsPath, tmpDirPath, err = cmd.prepareBuildpackBits()
    78  		if err != nil {
    79  			return err
    80  		}
    81  		defer os.RemoveAll(tmpDirPath)
    82  	}
    83  
    84  	updatedBuildpack, err := cmd.updateBuildpack()
    85  	if err != nil {
    86  		return err
    87  	}
    88  
    89  	if buildpackBitsPath != "" {
    90  		return cmd.uploadBits(user, updatedBuildpack, buildpackBitsPath)
    91  	}
    92  
    93  	return nil
    94  }
    95  
    96  func (cmd UpdateBuildpackCommand) validateSetup() (configv3.User, error) {
    97  	var user configv3.User
    98  
    99  	err := cmd.validateFlagCombinations()
   100  	if err != nil {
   101  		return user, err
   102  	}
   103  
   104  	err = cmd.SharedActor.CheckTarget(false, false)
   105  	if err != nil {
   106  		return user, err
   107  	}
   108  
   109  	return cmd.Config.CurrentUser()
   110  }
   111  
   112  func (cmd UpdateBuildpackCommand) prepareBuildpackBits() (string, string, error) {
   113  	downloader := download.NewDownloader(time.Second * 30)
   114  	tmpDirPath, err := ioutil.TempDir("", "buildpack-dir-")
   115  	if err != nil {
   116  		return "", "", err
   117  	}
   118  
   119  	buildpackBits, err := cmd.Actor.PrepareBuildpackBits(string(cmd.Path), tmpDirPath, downloader)
   120  	return buildpackBits, tmpDirPath, err
   121  }
   122  
   123  func (cmd UpdateBuildpackCommand) updateBuildpack() (v7action.Buildpack, error) {
   124  	var desiredBuildpack v7action.Buildpack
   125  
   126  	desiredBuildpack.Enabled = types.NullBool{IsSet: cmd.Enable || cmd.Disable, Value: cmd.Enable}
   127  	desiredBuildpack.Locked = types.NullBool{IsSet: cmd.Lock || cmd.Unlock, Value: cmd.Lock}
   128  	desiredBuildpack.Position = cmd.Position
   129  
   130  	if cmd.NewStack != "" {
   131  		desiredBuildpack.Stack = cmd.NewStack
   132  	}
   133  
   134  	if cmd.NewName != "" {
   135  		desiredBuildpack.Name = cmd.NewName
   136  	}
   137  
   138  	updatedBuildpack, warnings, err := cmd.Actor.UpdateBuildpackByNameAndStack(
   139  		cmd.RequiredArgs.Buildpack,
   140  		cmd.CurrentStack,
   141  		desiredBuildpack,
   142  	)
   143  	cmd.UI.DisplayWarnings(warnings)
   144  	if err != nil {
   145  		return updatedBuildpack, err
   146  	}
   147  	cmd.UI.DisplayOK()
   148  
   149  	return updatedBuildpack, nil
   150  }
   151  
   152  func (cmd UpdateBuildpackCommand) uploadBits(user configv3.User, updatedBuildpack v7action.Buildpack, buildpackBitsPath string) error {
   153  	cmd.UI.DisplayTextWithFlavor("Uploading buildpack {{.Buildpack}} as {{.Username}}...", map[string]interface{}{
   154  		"Buildpack": cmd.RequiredArgs.Buildpack,
   155  		"Username":  user.Name,
   156  	})
   157  
   158  	jobURL, warnings, err := cmd.Actor.UploadBuildpack(
   159  		updatedBuildpack.GUID,
   160  		buildpackBitsPath,
   161  		cmd.ProgressBar,
   162  	)
   163  	cmd.UI.DisplayWarnings(warnings)
   164  	if err != nil {
   165  		return err
   166  	}
   167  	cmd.UI.DisplayOK()
   168  
   169  	cmd.UI.DisplayTextWithFlavor("Processing uploaded buildpack {{.BuildpackName}}...", map[string]interface{}{
   170  		"BuildpackName": cmd.RequiredArgs.Buildpack,
   171  	})
   172  
   173  	warnings, err = cmd.Actor.PollUploadBuildpackJob(jobURL)
   174  	cmd.UI.DisplayWarnings(warnings)
   175  	if err != nil {
   176  		return err
   177  	}
   178  
   179  	cmd.UI.DisplayOK()
   180  	return nil
   181  }
   182  
   183  func (cmd UpdateBuildpackCommand) printInitialText(userName string) {
   184  	var originalBuildpackName = cmd.RequiredArgs.Buildpack
   185  	var buildpackName = originalBuildpackName
   186  
   187  	if cmd.NewName != "" {
   188  		buildpackName = cmd.NewName
   189  		cmd.UI.DisplayTextWithFlavor("Renaming buildpack {{.Buildpack}} to {{.DesiredBuildpackName}} as {{.CurrentUser}}...\n", map[string]interface{}{
   190  			"Buildpack":            originalBuildpackName,
   191  			"CurrentUser":          userName,
   192  			"DesiredBuildpackName": cmd.NewName,
   193  		})
   194  	}
   195  
   196  	switch {
   197  	case cmd.NewStack != "":
   198  		cmd.UI.DisplayTextWithFlavor("Assigning stack {{.Stack}} to {{.Buildpack}} as {{.CurrentUser}}...", map[string]interface{}{
   199  			"Buildpack":   buildpackName,
   200  			"CurrentUser": userName,
   201  			"Stack":       cmd.NewStack,
   202  		})
   203  		if cmd.Position.IsSet || cmd.Lock || cmd.Unlock || cmd.Enable || cmd.Disable {
   204  			cmd.UI.DisplayTextWithFlavor("\nUpdating buildpack {{.Buildpack}} with stack {{.Stack}} as {{.CurrentUser}}...", map[string]interface{}{
   205  				"Buildpack":   buildpackName,
   206  				"CurrentUser": userName,
   207  				"Stack":       cmd.NewStack,
   208  			})
   209  		}
   210  	case cmd.CurrentStack == "":
   211  		cmd.UI.DisplayTextWithFlavor("Updating buildpack {{.Buildpack}} as {{.CurrentUser}}...", map[string]interface{}{
   212  			"Buildpack":   buildpackName,
   213  			"CurrentUser": userName,
   214  		})
   215  	default:
   216  		cmd.UI.DisplayTextWithFlavor("Updating buildpack {{.Buildpack}} with stack {{.Stack}} as {{.CurrentUser}}...", map[string]interface{}{
   217  			"Buildpack":   buildpackName,
   218  			"CurrentUser": userName,
   219  			"Stack":       cmd.CurrentStack,
   220  		})
   221  	}
   222  }
   223  
   224  func (cmd UpdateBuildpackCommand) validateFlagCombinations() error {
   225  	if cmd.Lock && cmd.Unlock {
   226  		return translatableerror.ArgumentCombinationError{
   227  			Args: []string{"--lock", "--unlock"},
   228  		}
   229  	}
   230  
   231  	if cmd.Enable && cmd.Disable {
   232  		return translatableerror.ArgumentCombinationError{
   233  			Args: []string{"--enable", "--disable"},
   234  		}
   235  	}
   236  
   237  	if cmd.Path != "" && cmd.Lock {
   238  		return translatableerror.ArgumentCombinationError{
   239  			Args: []string{"--path", "--lock"},
   240  		}
   241  	}
   242  
   243  	if cmd.Path != "" && cmd.NewStack != "" {
   244  		return translatableerror.ArgumentCombinationError{
   245  			Args: []string{"--path", "--assign-stack"},
   246  		}
   247  	}
   248  
   249  	if cmd.CurrentStack != "" && cmd.NewStack != "" {
   250  		return translatableerror.ArgumentCombinationError{
   251  			Args: []string{"--stack", "--assign-stack"},
   252  		}
   253  	}
   254  	return nil
   255  }