github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+incompatible/cf/commands/buildpack/create_buildpack.go (about)

     1  package buildpack
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  
     7  	"code.cloudfoundry.org/cli/cf/flags"
     8  	. "code.cloudfoundry.org/cli/cf/i18n"
     9  
    10  	"code.cloudfoundry.org/cli/cf"
    11  	"code.cloudfoundry.org/cli/cf/api"
    12  	"code.cloudfoundry.org/cli/cf/commandregistry"
    13  	"code.cloudfoundry.org/cli/cf/errors"
    14  	"code.cloudfoundry.org/cli/cf/models"
    15  	"code.cloudfoundry.org/cli/cf/requirements"
    16  	"code.cloudfoundry.org/cli/cf/terminal"
    17  )
    18  
    19  type CreateBuildpack struct {
    20  	ui                terminal.UI
    21  	buildpackRepo     api.BuildpackRepository
    22  	buildpackBitsRepo api.BuildpackBitsRepository
    23  }
    24  
    25  func init() {
    26  	commandregistry.Register(&CreateBuildpack{})
    27  }
    28  
    29  func (cmd *CreateBuildpack) MetaData() commandregistry.CommandMetadata {
    30  	fs := make(map[string]flags.FlagSet)
    31  	fs["enable"] = &flags.BoolFlag{Name: "enable", Usage: T("Enable the buildpack to be used for staging")}
    32  	fs["disable"] = &flags.BoolFlag{Name: "disable", Usage: T("Disable the buildpack from being used for staging")}
    33  
    34  	return commandregistry.CommandMetadata{
    35  		Name:        "create-buildpack",
    36  		Description: T("Create a buildpack"),
    37  		Usage: []string{
    38  			T("CF_NAME create-buildpack BUILDPACK PATH POSITION [--enable|--disable]"),
    39  			T("\n\nTIP:\n"),
    40  			T("   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."),
    41  		},
    42  		Flags:     fs,
    43  		TotalArgs: 3,
    44  	}
    45  }
    46  
    47  func (cmd *CreateBuildpack) Requirements(requirementsFactory requirements.Factory, fc flags.FlagContext) ([]requirements.Requirement, error) {
    48  	if len(fc.Args()) != 3 {
    49  		cmd.ui.Failed(T("Incorrect Usage. Requires buildpack_name, path and position as arguments\n\n") + commandregistry.Commands.CommandUsage("create-buildpack"))
    50  		return nil, fmt.Errorf("Incorrect usage: %d arguments of %d required", len(fc.Args()), 3)
    51  	}
    52  
    53  	reqs := []requirements.Requirement{
    54  		requirementsFactory.NewLoginRequirement(),
    55  	}
    56  
    57  	return reqs, nil
    58  }
    59  
    60  func (cmd *CreateBuildpack) SetDependency(deps commandregistry.Dependency, pluginCall bool) commandregistry.Command {
    61  	cmd.ui = deps.UI
    62  	cmd.buildpackRepo = deps.RepoLocator.GetBuildpackRepository()
    63  	cmd.buildpackBitsRepo = deps.RepoLocator.GetBuildpackBitsRepository()
    64  	return cmd
    65  }
    66  
    67  func (cmd *CreateBuildpack) Execute(c flags.FlagContext) error {
    68  	buildpackName := c.Args()[0]
    69  
    70  	buildpackFile, buildpackFileName, err := cmd.buildpackBitsRepo.CreateBuildpackZipFile(c.Args()[1])
    71  	if err != nil {
    72  		cmd.ui.Warn(T("Failed to create a local temporary zip file for the buildpack"))
    73  		return err
    74  	}
    75  
    76  	cmd.ui.Say(T("Creating buildpack {{.BuildpackName}}...", map[string]interface{}{"BuildpackName": terminal.EntityNameColor(buildpackName)}))
    77  
    78  	buildpack, err := cmd.createBuildpack(buildpackName, c)
    79  
    80  	if err != nil {
    81  		if httpErr, ok := err.(errors.HTTPError); ok && httpErr.ErrorCode() == errors.BuildpackNameTaken {
    82  			cmd.ui.Ok()
    83  			cmd.ui.Warn(T("Buildpack {{.BuildpackName}} already exists", map[string]interface{}{"BuildpackName": buildpackName}))
    84  			cmd.ui.Say(T("TIP: use '{{.CfUpdateBuildpackCommand}}' to update this buildpack", map[string]interface{}{"CfUpdateBuildpackCommand": terminal.CommandColor(cf.Name + " " + "update-buildpack")}))
    85  		} else if httpErr, ok := err.(errors.HTTPError); ok && httpErr.ErrorCode() == errors.StackUnique {
    86  			cmd.ui.Ok()
    87  			cmd.ui.Warn(T("Buildpack {{.BuildpackName}} already exists without a stack", map[string]interface{}{"BuildpackName": buildpackName}))
    88  			cmd.ui.Say(T("TIP: use '{{.CfDeleteBuildpackCommand}}' to delete buildpack {{.BuildpackName}} without a stack", map[string]interface{}{"CfDeleteBuildpackCommand": terminal.CommandColor(cf.Name + " " + "delete-buildpack"), "BuildpackName": buildpackName}))
    89  		} else {
    90  			return err
    91  		}
    92  		return nil
    93  	}
    94  	cmd.ui.Ok()
    95  	cmd.ui.Say("")
    96  
    97  	cmd.ui.Say(T("Uploading buildpack {{.BuildpackName}}...", map[string]interface{}{"BuildpackName": terminal.EntityNameColor(buildpackName)}))
    98  
    99  	err = cmd.buildpackBitsRepo.UploadBuildpack(buildpack, buildpackFile, buildpackFileName)
   100  	if err != nil {
   101  		if httpErr, ok := err.(errors.HTTPError); ok && httpErr.ErrorCode() == errors.BuildpackNameStackTaken {
   102  			cmd.ui.Ok()
   103  			cmd.ui.Warn(httpErr.Error())
   104  			cmd.ui.Say(T("TIP: use '{{.CfUpdateBuildpackCommand}}' to update this buildpack", map[string]interface{}{"CfUpdateBuildpackCommand": terminal.CommandColor(cf.Name + " " + "update-buildpack")}))
   105  		} else {
   106  			return err
   107  		}
   108  		return nil
   109  	}
   110  
   111  	cmd.ui.Ok()
   112  	return nil
   113  }
   114  
   115  func (cmd CreateBuildpack) createBuildpack(buildpackName string, c flags.FlagContext) (buildpack models.Buildpack, apiErr error) {
   116  	position, err := strconv.Atoi(c.Args()[2])
   117  	if err != nil {
   118  		apiErr = fmt.Errorf(T("Error {{.ErrorDescription}} is being passed in as the argument for 'Position' but 'Position' requires an integer.  For more syntax help, see `cf create-buildpack -h`.", map[string]interface{}{"ErrorDescription": c.Args()[2]}))
   119  		return
   120  	}
   121  
   122  	enabled := c.Bool("enable")
   123  	disabled := c.Bool("disable")
   124  	if enabled && disabled {
   125  		apiErr = errors.New(T("Cannot specify both {{.Enabled}} and {{.Disabled}}.", map[string]interface{}{
   126  			"Enabled":  "enabled",
   127  			"Disabled": "disabled",
   128  		}))
   129  		return
   130  	}
   131  
   132  	var enableOption *bool
   133  	if enabled {
   134  		enableOption = &enabled
   135  	}
   136  	if disabled {
   137  		disabled = false
   138  		enableOption = &disabled
   139  	}
   140  
   141  	buildpack, apiErr = cmd.buildpackRepo.Create(buildpackName, &position, enableOption, nil)
   142  
   143  	return
   144  }