github.com/jenspinney/cli@v6.42.1-0.20190207184520-7450c600020e+incompatible/command/v6/create_buildpack_command.go (about)

     1  package v6
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"time"
     7  
     8  	"code.cloudfoundry.org/cli/actor/actionerror"
     9  	"code.cloudfoundry.org/cli/actor/sharedaction"
    10  	"code.cloudfoundry.org/cli/actor/v2action"
    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/v6/shared"
    15  	"code.cloudfoundry.org/cli/util/download"
    16  )
    17  
    18  //go:generate counterfeiter . Downloader
    19  
    20  type Downloader interface {
    21  	Download(string) (string, error)
    22  }
    23  
    24  //go:generate counterfeiter . CreateBuildpackActor
    25  
    26  type CreateBuildpackActor interface {
    27  	CreateBuildpack(name string, position int, enabled bool) (v2action.Buildpack, v2action.Warnings, error)
    28  	UploadBuildpack(GUID string, path string, progBar v2action.SimpleProgressBar) (v2action.Warnings, error)
    29  	PrepareBuildpackBits(inputPath string, tmpDirPath string, downloader v2action.Downloader) (string, error)
    30  }
    31  
    32  type CreateBuildpackCommand struct {
    33  	RequiredArgs    flag.CreateBuildpackArgs `positional-args:"yes"`
    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  	usage           interface{}              `usage:"CF_NAME create-buildpack BUILDPACK PATH POSITION [--enable|--disable]\n\nTIP:\n   Path 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."`
    37  	relatedCommands interface{}              `related_commands:"buildpacks, push"`
    38  
    39  	UI          command.UI
    40  	Actor       CreateBuildpackActor
    41  	ProgressBar v2action.SimpleProgressBar
    42  	SharedActor command.SharedActor
    43  	Config      command.Config
    44  }
    45  
    46  func (cmd *CreateBuildpackCommand) Setup(config command.Config, ui command.UI) error {
    47  	cmd.UI = ui
    48  	cmd.Config = config
    49  	cmd.SharedActor = sharedaction.NewActor(config)
    50  
    51  	ccClient, uaaClient, err := shared.NewClients(config, ui, true)
    52  	if err != nil {
    53  		return err
    54  	}
    55  	cmd.Actor = v2action.NewActor(ccClient, uaaClient, config)
    56  	cmd.ProgressBar = v2action.NewProgressBar()
    57  
    58  	return nil
    59  }
    60  
    61  func (cmd *CreateBuildpackCommand) Execute(args []string) error {
    62  	if cmd.Enable && cmd.Disable {
    63  		return translatableerror.ArgumentCombinationError{
    64  			Args: []string{"--enable", "--disable"},
    65  		}
    66  	}
    67  
    68  	err := cmd.SharedActor.CheckTarget(false, false)
    69  	if err != nil {
    70  		return err
    71  	}
    72  
    73  	user, err := cmd.Config.CurrentUser()
    74  	if err != nil {
    75  		return err
    76  	}
    77  
    78  	cmd.UI.DisplayTextWithFlavor("Creating buildpack {{.Buildpack}} as {{.Username}}...", map[string]interface{}{
    79  		"Buildpack": cmd.RequiredArgs.Buildpack,
    80  		"Username":  user.Name,
    81  	})
    82  
    83  	downloader := download.NewDownloader(time.Second * 30)
    84  	tmpDirPath, err := ioutil.TempDir("", "buildpack-dir-")
    85  	if err != nil {
    86  		return err
    87  	}
    88  	defer os.RemoveAll(tmpDirPath)
    89  
    90  	pathToBuildpackBits, err := cmd.Actor.PrepareBuildpackBits(string(cmd.RequiredArgs.Path), tmpDirPath, downloader)
    91  	if err != nil {
    92  		return err
    93  	}
    94  
    95  	buildpack, warnings, err := cmd.Actor.CreateBuildpack(cmd.RequiredArgs.Buildpack, cmd.RequiredArgs.Position, !cmd.Disable)
    96  	cmd.UI.DisplayWarnings(warnings)
    97  
    98  	if err != nil {
    99  		return cmd.displayIfNameCollisionError(err)
   100  	}
   101  
   102  	cmd.UI.DisplayOK()
   103  
   104  	cmd.UI.DisplayTextWithFlavor("Uploading buildpack {{.Buildpack}} as {{.Username}}...", map[string]interface{}{
   105  		"Buildpack": cmd.RequiredArgs.Buildpack,
   106  		"Username":  user.Name,
   107  	})
   108  
   109  	uploadWarnings, err := cmd.Actor.UploadBuildpack(buildpack.GUID, pathToBuildpackBits, cmd.ProgressBar)
   110  	cmd.UI.DisplayWarnings(uploadWarnings)
   111  	if err != nil {
   112  		cmd.UI.DisplayNewline()
   113  		cmd.UI.DisplayNewline()
   114  		if _, ok := err.(actionerror.BuildpackAlreadyExistsForStackError); ok {
   115  			cmd.displayNameAndStackCollisionError(err)
   116  			return nil
   117  		} else if httpErr, ok := err.(download.RawHTTPStatusError); ok {
   118  			return translatableerror.HTTPStatusError{Status: httpErr.Status}
   119  		}
   120  		return err
   121  	}
   122  
   123  	cmd.UI.DisplayNewline()
   124  	cmd.UI.DisplayText("Done uploading")
   125  	cmd.UI.DisplayOK()
   126  
   127  	return nil
   128  }
   129  
   130  func (cmd CreateBuildpackCommand) displayNameAndStackCollisionError(err error) {
   131  	cmd.UI.DisplayWarning(err.Error())
   132  	cmd.UI.DisplayTextWithFlavor("TIP: use '{{.CfUpdateBuildpackCommand}}' to update this buildpack",
   133  		map[string]interface{}{
   134  			"CfUpdateBuildpackCommand": cmd.Config.BinaryName() + " update-buildpack",
   135  		})
   136  }
   137  
   138  func (cmd CreateBuildpackCommand) displayIfNameCollisionError(err error) error {
   139  	if _, ok := err.(actionerror.BuildpackAlreadyExistsWithoutStackError); ok {
   140  		cmd.displayAlreadyExistingBuildpackWithoutStack(err)
   141  		return nil
   142  	} else if _, ok := err.(actionerror.BuildpackNameTakenError); ok {
   143  		cmd.displayAlreadyExistingBuildpack(err)
   144  		return nil
   145  	}
   146  	return err
   147  }
   148  
   149  func (cmd CreateBuildpackCommand) displayAlreadyExistingBuildpackWithoutStack(err error) {
   150  	cmd.UI.DisplayNewline()
   151  	cmd.UI.DisplayWarning(err.Error())
   152  	cmd.UI.DisplayTextWithFlavor("TIP: use '{{.CfBuildpacksCommand}}' and '{{.CfDeleteBuildpackCommand}}' to delete buildpack {{.BuildpackName}} without a stack",
   153  		map[string]interface{}{
   154  			"CfBuildpacksCommand":      cmd.Config.BinaryName() + " buildpacks",
   155  			"CfDeleteBuildpackCommand": cmd.Config.BinaryName() + " delete-buildpack",
   156  			"BuildpackName":            cmd.RequiredArgs.Buildpack,
   157  		})
   158  }
   159  
   160  func (cmd CreateBuildpackCommand) displayAlreadyExistingBuildpack(err error) {
   161  	cmd.UI.DisplayNewline()
   162  	cmd.UI.DisplayWarning(err.Error())
   163  	cmd.UI.DisplayTextWithFlavor("TIP: use '{{.CfUpdateBuildpackCommand}}' to update this buildpack",
   164  		map[string]interface{}{
   165  			"CfUpdateBuildpackCommand": cmd.Config.BinaryName() + " update-buildpack",
   166  		})
   167  }