github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+incompatible/command/v6/update_buildpack_command.go (about)

     1  package v6
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"time"
     7  
     8  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
     9  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccversion"
    10  
    11  	"code.cloudfoundry.org/cli/actor/sharedaction"
    12  	"code.cloudfoundry.org/cli/actor/v2action"
    13  	"code.cloudfoundry.org/cli/command"
    14  	"code.cloudfoundry.org/cli/command/flag"
    15  	"code.cloudfoundry.org/cli/command/translatableerror"
    16  	"code.cloudfoundry.org/cli/command/v6/shared"
    17  	"code.cloudfoundry.org/cli/types"
    18  	"code.cloudfoundry.org/cli/util/download"
    19  )
    20  
    21  //go:generate counterfeiter . UpdateBuildpackActor
    22  
    23  type UpdateBuildpackActor interface {
    24  	CloudControllerAPIVersion() string
    25  	UpdateBuildpackByNameAndStack(name, currentStack string, position types.NullInt, locked types.NullBool, enabled types.NullBool, newStack string) (string, v2action.Warnings, error)
    26  	PrepareBuildpackBits(inputPath string, tmpDirPath string, downloader v2action.Downloader) (string, error)
    27  	UploadBuildpack(GUID string, path string, progBar v2action.SimpleProgressBar) (v2action.Warnings, error)
    28  }
    29  
    30  type UpdateBuildpackCommand struct {
    31  	RequiredArgs flag.BuildpackName               `positional-args:"yes"`
    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  	Order        types.NullInt                    `short:"i" description:"The order in which the buildpacks are checked during buildpack auto-detection"`
    36  	Lock         bool                             `long:"lock" description:"Lock the buildpack to prevent updates"`
    37  	Path         flag.PathWithExistenceCheckOrURL `short:"p" description:"Path to directory or zip file"`
    38  	Unlock       bool                             `long:"unlock" description:"Unlock the buildpack to enable updates"`
    39  	CurrentStack string                           `short:"s" description:"Specify stack to disambiguate buildpacks with the same name"`
    40  	usage        interface{}                      `usage:"CF_NAME update-buildpack BUILDPACK [-p PATH | -s STACK | --assign-stack NEW_STACK] [-i POSITION] [--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"`
    41  
    42  	relatedCommands interface{} `related_commands:"buildpacks, rename-buildpack, create-buildpack, delete-buildpack"`
    43  
    44  	UI          command.UI
    45  	SharedActor command.SharedActor
    46  	Actor       UpdateBuildpackActor
    47  	Config      command.Config
    48  	ProgressBar v2action.SimpleProgressBar
    49  }
    50  
    51  func (cmd *UpdateBuildpackCommand) Setup(config command.Config, ui command.UI) error {
    52  	cmd.UI = ui
    53  	cmd.Config = config
    54  
    55  	cmd.SharedActor = sharedaction.NewActor(config)
    56  	ccClient, uaaClient, err := shared.GetNewClientsAndConnectToCF(config, ui)
    57  	if err != nil {
    58  		return err
    59  	}
    60  	cmd.Actor = v2action.NewActor(ccClient, uaaClient, config)
    61  	cmd.ProgressBar = v2action.NewProgressBar()
    62  
    63  	return nil
    64  }
    65  
    66  func (cmd UpdateBuildpackCommand) Execute(args []string) error {
    67  	err := cmd.validateFlagCombinations()
    68  	if err != nil {
    69  		return err
    70  	}
    71  
    72  	err = cmd.SharedActor.CheckTarget(false, false)
    73  	if err != nil {
    74  		return err
    75  	}
    76  
    77  	err = cmd.minAPIVersionCheck()
    78  	if err != nil {
    79  		return err
    80  	}
    81  
    82  	user, err := cmd.Config.CurrentUser()
    83  	if err != nil {
    84  		return err
    85  	}
    86  
    87  	cmd.printInitialText(user.Name)
    88  
    89  	var buildpackBitsPath string
    90  
    91  	if cmd.Path != "" {
    92  		var (
    93  			tmpDirPath string
    94  		)
    95  		downloader := download.NewDownloader(time.Second * 30)
    96  		tmpDirPath, err = ioutil.TempDir("", "buildpack-dir-")
    97  		if err != nil {
    98  			return err
    99  		}
   100  		defer os.RemoveAll(tmpDirPath)
   101  
   102  		buildpackBitsPath, err = cmd.Actor.PrepareBuildpackBits(string(cmd.Path), tmpDirPath, downloader)
   103  		if err != nil {
   104  			return err
   105  		}
   106  	}
   107  
   108  	enabled := types.NullBool{
   109  		IsSet: cmd.Enable || cmd.Disable,
   110  		Value: cmd.Enable,
   111  	}
   112  
   113  	locked := types.NullBool{
   114  		IsSet: cmd.Lock || cmd.Unlock,
   115  		Value: cmd.Lock,
   116  	}
   117  
   118  	buildpackGUID, warnings, err := cmd.Actor.UpdateBuildpackByNameAndStack(cmd.RequiredArgs.Buildpack, cmd.CurrentStack, cmd.Order, locked, enabled, cmd.NewStack)
   119  
   120  	cmd.UI.DisplayWarnings(warnings)
   121  	if err != nil {
   122  		return err
   123  	}
   124  
   125  	cmd.UI.DisplayOK()
   126  
   127  	if buildpackBitsPath != "" {
   128  		cmd.UI.DisplayTextWithFlavor("Uploading buildpack {{.Buildpack}} as {{.Username}}...", map[string]interface{}{
   129  			"Buildpack": cmd.RequiredArgs.Buildpack,
   130  			"Username":  user.Name,
   131  		})
   132  
   133  		warnings, err = cmd.Actor.UploadBuildpack(buildpackGUID, buildpackBitsPath, cmd.ProgressBar)
   134  		if _, ok := err.(ccerror.InvalidAuthTokenError); ok {
   135  			cmd.UI.DisplayWarnings([]string{"Failed to upload buildpack due to auth token expiration, retrying..."})
   136  			warnings, err = cmd.Actor.UploadBuildpack(buildpackGUID, buildpackBitsPath, cmd.ProgressBar)
   137  		}
   138  		cmd.UI.DisplayWarnings(warnings)
   139  		if err != nil {
   140  			return err
   141  		}
   142  
   143  		cmd.UI.DisplayOK()
   144  
   145  	}
   146  	return err
   147  }
   148  
   149  func (cmd UpdateBuildpackCommand) minAPIVersionCheck() error {
   150  	if cmd.CurrentStack != "" {
   151  		return command.MinimumCCAPIVersionCheck(
   152  			cmd.Actor.CloudControllerAPIVersion(),
   153  			ccversion.MinVersionBuildpackStackAssociationV2,
   154  			"Option '-s'",
   155  		)
   156  	}
   157  
   158  	if cmd.NewStack != "" {
   159  		return command.MinimumCCAPIVersionCheck(
   160  			cmd.Actor.CloudControllerAPIVersion(),
   161  			ccversion.MinVersionBuildpackStackAssociationV2,
   162  			"Option '--assign-stack'",
   163  		)
   164  	}
   165  	return nil
   166  }
   167  
   168  func (cmd UpdateBuildpackCommand) printInitialText(userName string) {
   169  	if cmd.NewStack != "" {
   170  		cmd.UI.DisplayTextWithFlavor("Assigning stack {{.Stack}} to {{.Buildpack}} as {{.CurrentUser}}...", map[string]interface{}{
   171  			"Buildpack":   cmd.RequiredArgs.Buildpack,
   172  			"CurrentUser": userName,
   173  			"Stack":       cmd.NewStack,
   174  		})
   175  		if cmd.Order.IsSet || cmd.Lock || cmd.Unlock || cmd.Enable || cmd.Disable {
   176  			cmd.UI.DisplayTextWithFlavor("Updating buildpack {{.Buildpack}} with stack {{.Stack}} as {{.CurrentUser}}...", map[string]interface{}{
   177  				"Buildpack":   cmd.RequiredArgs.Buildpack,
   178  				"CurrentUser": userName,
   179  				"Stack":       cmd.NewStack,
   180  			})
   181  		}
   182  	} else if cmd.CurrentStack == "" {
   183  		cmd.UI.DisplayTextWithFlavor("Updating buildpack {{.Buildpack}} as {{.CurrentUser}}...", map[string]interface{}{
   184  			"Buildpack":   cmd.RequiredArgs.Buildpack,
   185  			"CurrentUser": userName,
   186  		})
   187  	} else {
   188  		cmd.UI.DisplayTextWithFlavor("Updating buildpack {{.Buildpack}} with stack {{.Stack}} as {{.CurrentUser}}...", map[string]interface{}{
   189  			"Buildpack":   cmd.RequiredArgs.Buildpack,
   190  			"CurrentUser": userName,
   191  			"Stack":       cmd.CurrentStack,
   192  		})
   193  	}
   194  }
   195  
   196  func (cmd UpdateBuildpackCommand) validateFlagCombinations() error {
   197  	if cmd.Lock && cmd.Unlock {
   198  		return translatableerror.ArgumentCombinationError{
   199  			Args: []string{"--lock", "--unlock"},
   200  		}
   201  	}
   202  
   203  	if cmd.Lock && len(cmd.Path) > 0 {
   204  		return translatableerror.ArgumentCombinationError{
   205  			Args: []string{"-p", "--lock"},
   206  		}
   207  	}
   208  
   209  	if len(cmd.Path) > 0 && cmd.Unlock {
   210  		return translatableerror.ArgumentCombinationError{
   211  			Args: []string{"-p", "--unlock"},
   212  		}
   213  	}
   214  
   215  	if len(cmd.Path) > 0 && len(cmd.NewStack) > 0 {
   216  		return translatableerror.ArgumentCombinationError{
   217  			Args: []string{"-p", "--assign-stack"},
   218  		}
   219  	}
   220  
   221  	if len(cmd.CurrentStack) > 0 && len(cmd.NewStack) > 0 {
   222  		return translatableerror.ArgumentCombinationError{
   223  			Args: []string{"-s", "--assign-stack"},
   224  		}
   225  	}
   226  
   227  	if cmd.Enable && cmd.Disable {
   228  		return translatableerror.ArgumentCombinationError{
   229  			Args: []string{"--enable", "--disable"},
   230  		}
   231  	}
   232  
   233  	return nil
   234  }