<commit_before>package models

import (
	"fmt"
	"os"
	"time"

	"github.com/coopernurse/gorp"
)

type BundlePlatformType int

const (
	BundlePlatformTypeAndroid BundlePlatformType = 1 + iota
	BundlePlatformTypeIOS
)

type BundleFileExtension string

const (
	BundleFileExtensionAndroid BundleFileExtension = ".apk"
	BundleFileExtensionIOS     BundleFileExtension = ".ipa"
)

func (ext BundleFileExtension) IsValid() (ok bool) {
	ok = false
	if ext == BundleFileExtensionAndroid {
		ok = true
	} else if ext == BundleFileExtensionIOS {
		ok = true
	}
	return
}

type Bundle struct {
	Id            int                `db:"id"`
	AppId         int                `db:"app_id"`
	FileId        string             `db:"file_id"`
	PlatformType  BundlePlatformType `db:"platform_type"`
	BundleVersion string             `db:"bundle_version"`
	Revision      int                `db:"revision"`
	Description   string             `db:"description"`
	CreatedAt     time.Time          `db:"created_at"`
	UpdatedAt     time.Time          `db:"updated_at"`

	Apk      *Apk     `db:"-"`
	File     *os.File `db:"-"`
	FileName string   `db:"-"`
}

type BundleJsonResponse struct {
	FileId     string `json:"file_id"`
	Version    string `json:"version"`
	Revision   int    `json:"revision"`
	InstallUrl string `json:"install_url"`
	QrCodeUrl  string `json:"qr_code_url"`
}

func (bundle *Bundle) JsonResponse(ub UriBuilder) (*BundleJsonResponse, error) {
	installUrl, err := ub.UriFor(fmt.Sprintf("bundle/%d/download", bundle.Id))
	if err != nil {
		return nil, err
	}
	qrCodeUrl, err := ub.UriFor(fmt.Sprintf("bundle/%d", bundle.Id))
	if err != nil {
		return nil, err
	}

	return &BundleJsonResponse{
		FileId:     bundle.FileId,
		Version:    bundle.BundleVersion,
		Revision:   bundle.Revision,
		InstallUrl: installUrl.String(),
		QrCodeUrl:  qrCodeUrl.String(),
	}, nil
}

func (bundle *Bundle) App(txn *gorp.Transaction) (*App, error) {
	app, err := txn.Get(App{}, bundle.AppId)
	if err != nil {
		return nil, err
	}
	return app.(*App), nil
}

func (bundle *Bundle) PreInsert(s gorp.SqlExecutor) error {
	bundle.BundleVersion = bundle.Apk.Version
	bundle.CreatedAt = time.Now()
	bundle.UpdatedAt = bundle.CreatedAt
	return nil
}

func (bundle *Bundle) PreUpdate(s gorp.SqlExecutor) error {
	bundle.UpdatedAt = time.Now()
	return nil
}

func (bundle *Bundle) Save(txn *gorp.Transaction) error {
	return txn.Insert(bundle)
}

func (bundle *Bundle) Update(txn *gorp.Transaction) error {
	current, err := GetBundle(txn, bundle.Id)
	if err != nil {
		return err
	}

	current.Description = bundle.Description

	_, err = txn.Update(current)
	return err
}

func (bundle *Bundle) DeleteFromDB(txn *gorp.Transaction) error {
	_, err := txn.Delete(bundle)
	return err
}

func (bundle *Bundle) DeleteFromGoogleDrive(s *GoogleService) error {
	return s.DeleteFile(bundle.FileId)
}

func (bundle *Bundle) Delete(txn *gorp.Transaction, s *GoogleService) error {
	if err := bundle.DeleteFromDB(txn); err != nil {
		return err
	}
	if err := bundle.DeleteFromGoogleDrive(s); err != nil {
		return err
	}
	return nil
}

func CreateBundle(txn *gorp.Transaction, bundle *Bundle) error {
	return txn.Insert(bundle)
}

func GetBundle(txn *gorp.Transaction, id int) (*Bundle, error) {
	bundle, err := txn.Get(Bundle{}, id)
	if err != nil {
		return nil, err
	}
	return bundle.(*Bundle), nil
}
<commit_msg>do not specify the name of return value<commit_after>package models

import (
	"fmt"
	"os"
	"time"

	"github.com/coopernurse/gorp"
)

type BundlePlatformType int

const (
	BundlePlatformTypeAndroid BundlePlatformType = 1 + iota
	BundlePlatformTypeIOS
)

type BundleFileExtension string

const (
	BundleFileExtensionAndroid BundleFileExtension = ".apk"
	BundleFileExtensionIOS     BundleFileExtension = ".ipa"
)

func (ext BundleFileExtension) IsValid() bool {
	var ok bool
	if ext == BundleFileExtensionAndroid {
		ok = true
	} else if ext == BundleFileExtensionIOS {
		ok = true
	}
	return ok
}

type Bundle struct {
	Id            int                `db:"id"`
	AppId         int                `db:"app_id"`
	FileId        string             `db:"file_id"`
	PlatformType  BundlePlatformType `db:"platform_type"`
	BundleVersion string             `db:"bundle_version"`
	Revision      int                `db:"revision"`
	Description   string             `db:"description"`
	CreatedAt     time.Time          `db:"created_at"`
	UpdatedAt     time.Time          `db:"updated_at"`

	Apk      *Apk     `db:"-"`
	File     *os.File `db:"-"`
	FileName string   `db:"-"`
}

type BundleJsonResponse struct {
	FileId     string `json:"file_id"`
	Version    string `json:"version"`
	Revision   int    `json:"revision"`
	InstallUrl string `json:"install_url"`
	QrCodeUrl  string `json:"qr_code_url"`
}

func (bundle *Bundle) JsonResponse(ub UriBuilder) (*BundleJsonResponse, error) {
	installUrl, err := ub.UriFor(fmt.Sprintf("bundle/%d/download", bundle.Id))
	if err != nil {
		return nil, err
	}
	qrCodeUrl, err := ub.UriFor(fmt.Sprintf("bundle/%d", bundle.Id))
	if err != nil {
		return nil, err
	}

	return &BundleJsonResponse{
		FileId:     bundle.FileId,
		Version:    bundle.BundleVersion,
		Revision:   bundle.Revision,
		InstallUrl: installUrl.String(),
		QrCodeUrl:  qrCodeUrl.String(),
	}, nil
}

func (bundle *Bundle) App(txn *gorp.Transaction) (*App, error) {
	app, err := txn.Get(App{}, bundle.AppId)
	if err != nil {
		return nil, err
	}
	return app.(*App), nil
}

func (bundle *Bundle) PreInsert(s gorp.SqlExecutor) error {
	bundle.BundleVersion = bundle.Apk.Version
	bundle.CreatedAt = time.Now()
	bundle.UpdatedAt = bundle.CreatedAt
	return nil
}

func (bundle *Bundle) PreUpdate(s gorp.SqlExecutor) error {
	bundle.UpdatedAt = time.Now()
	return nil
}

func (bundle *Bundle) Save(txn *gorp.Transaction) error {
	return txn.Insert(bundle)
}

func (bundle *Bundle) Update(txn *gorp.Transaction) error {
	current, err := GetBundle(txn, bundle.Id)
	if err != nil {
		return err
	}

	current.Description = bundle.Description

	_, err = txn.Update(current)
	return err
}

func (bundle *Bundle) DeleteFromDB(txn *gorp.Transaction) error {
	_, err := txn.Delete(bundle)
	return err
}

func (bundle *Bundle) DeleteFromGoogleDrive(s *GoogleService) error {
	return s.DeleteFile(bundle.FileId)
}

func (bundle *Bundle) Delete(txn *gorp.Transaction, s *GoogleService) error {
	if err := bundle.DeleteFromDB(txn); err != nil {
		return err
	}
	if err := bundle.DeleteFromGoogleDrive(s); err != nil {
		return err
	}
	return nil
}

func CreateBundle(txn *gorp.Transaction, bundle *Bundle) error {
	return txn.Insert(bundle)
}

func GetBundle(txn *gorp.Transaction, id int) (*Bundle, error) {
	bundle, err := txn.Get(Bundle{}, id)
	if err != nil {
		return nil, err
	}
	return bundle.(*Bundle), nil
}
<|endoftext|>


<commit_before>package models

import (
	"github.com/jinzhu/gorm"
	"time"
)

/**
 * 端末モデル
 */
type Device struct {
	Id            int64         `json:"id,omitempty"`
	Name          string        `json:"name,omitempty"`
	Manufacturer  string        `json:"manufacturer,omitempty"`
	Carrier       string        `json:"carrier,omitempty"`
	Os            string        `json:"os,omitempty"`
	Size          string        `json:"size,omitempty"`
	Resolution    string        `json:"resolution,omitempty"`
	Memory        string        `json:"memory,omitempty"`
	DateOfRelease int64         `json:"dataOfRelease,omitempty"`
	Other         string        `json:"other,omitempty"`
	CreatedAt     int64         `json:"createdAt,omitempty"`
	UpdatedAt     int64         `json:"updatedAt,omitempty"`
	DeletedAt     int64         `json:"deletedAt,omitempty"`
	User          User          `json:"user,omitempty"`         // One-To-One relationship (has one)
	UserId        int64         `json:"user_id,omitempty"`      // Foreign key of User
	DeviceStates  []DeviceState `json:"deviceStates,omitempty"` // One-To-Many relationship (has many)
}

func (d *Device) BeforeCreate() (err error) {
	d.CreatedAt = time.Now().Unix()
	d.UpdatedAt = time.Now().Unix()
	return
}

func (d *Device) BeforeUpdate() (err error) {
	d.UpdatedAt = time.Now().Unix()
	return
}

func (d *Device) BeforeDelete() (err error) {
	d.DeletedAt = time.Now().Unix()
	return
}

func findUser(Txn *gorm.DB, device Device) Device {
	var user m.User
	Txt.Model(&device).Related(&user)
	device.User = user
	return device
}

func findDeviceStates(Txn *gorm.DB, device Device) Device {
	var device_states []m.DeviceState
	Txn.Model(&device).Related(&device_states)
	for i := 0; i < len(device_states); i++ {
		device_state := device_states[i]
		var user m.User
		Txt.Model(&device_state).Related(&user)
		device_state.User = user
		device_states[i] = device_state
	}
	device.DeviceState = device_states
	return device
}
<commit_msg>Remove unused<commit_after>package models

import (
	"github.com/jinzhu/gorm"
	"time"
)

/**
 * 端末モデル
 */
type Device struct {
	Id            int64         `json:"id,omitempty"`
	Name          string        `json:"name,omitempty"`
	Manufacturer  string        `json:"manufacturer,omitempty"`
	Carrier       string        `json:"carrier,omitempty"`
	Os            string        `json:"os,omitempty"`
	Size          string        `json:"size,omitempty"`
	Resolution    string        `json:"resolution,omitempty"`
	Memory        string        `json:"memory,omitempty"`
	DateOfRelease int64         `json:"dataOfRelease,omitempty"`
	Other         string        `json:"other,omitempty"`
	CreatedAt     int64         `json:"createdAt,omitempty"`
	UpdatedAt     int64         `json:"updatedAt,omitempty"`
	DeletedAt     int64         `json:"deletedAt,omitempty"`
	User          User          `json:"user,omitempty"`         // One-To-One relationship (has one)
	UserId        int64         `json:"user_id,omitempty"`      // Foreign key of User
	DeviceStates  []DeviceState `json:"deviceStates,omitempty"` // One-To-Many relationship (has many)
}

func (d *Device) BeforeCreate() (err error) {
	d.CreatedAt = time.Now().Unix()
	d.UpdatedAt = time.Now().Unix()
	return
}

func (d *Device) BeforeUpdate() (err error) {
	d.UpdatedAt = time.Now().Unix()
	return
}

func (d *Device) BeforeDelete() (err error) {
	d.DeletedAt = time.Now().Unix()
	return
}

func findUser(Txn *gorm.DB, device Device) Device {
	var user User
	Txt.Model(&device).Related(&user)
	device.User = user
	return device
}

func findDeviceStates(Txn *gorm.DB, device Device) Device {
	var device_states []DeviceState
	Txn.Model(&device).Related(&device_states)
	for i := 0; i < len(device_states); i++ {
		device_state := device_states[i]
		var user User
		Txt.Model(&device_state).Related(&user)
		device_state.User = user
		device_states[i] = device_state
	}
	device.DeviceState = device_states
	return device
}
<|endoftext|>


<commit_before>// #############################################################################
// This file is part of the "clap" package of the "Eureka" project.
// It is distributed under the MIT License. Refer to the LICENSE file for more
// information.
//
// Website: http://www.github.com/sivachandra/eureka
// #############################################################################

// The clap package provides Command Line Argument Parsing facilities.
package clap

import (
	"fmt"
	"strconv"
	"strings"
)

type Arg string

type NamedArg struct {
	name string
	short string
	help string
	defValStr string
	dest interface{}
	required bool
	set bool
}

func (namedArg *NamedArg) Reset() error {
	namedArg.set = false
	if !namedArg.required {
		var valid bool
		var err error
		switch namedArg.dest.(type) {
		case *int:
			var ptr *int
			ptr, valid = namedArg.dest.(*int)
			if valid {
				var int64Val int64
				int64Val, err = strconv.ParseInt(namedArg.defValStr, 0, 0)
				if err == nil {
					*ptr = int(int64Val)
				}
			}
		case *uint:
			var ptr *uint
			ptr, valid = namedArg.dest.(*uint)
			if valid {
				var uint64Val uint64
				uint64Val, err = strconv.ParseUint(namedArg.defValStr, 0, 0)
				if err == nil {
					*ptr = uint(uint64Val)
				}
			}
		case *int64:
			var ptr *int64
			ptr, valid = namedArg.dest.(*int64)
			if valid {
				*ptr, err = strconv.ParseInt(namedArg.defValStr, 0, 64)
			}
		case *uint64:
			var ptr *uint64
			ptr, valid = namedArg.dest.(*uint64)
			if valid {
				*ptr, err = strconv.ParseUint(namedArg.defValStr, 0, 64)
			}
		case *float64:
			var ptr *float64
			ptr, valid = namedArg.dest.(*float64)
			if valid {
				*ptr, err = strconv.ParseFloat(namedArg.defValStr, 64)
			}
		case *bool:
			var ptr *bool
			ptr, valid = namedArg.dest.(*bool)
			if valid {
				*ptr, err = strconv.ParseBool(namedArg.defValStr)
			}
		case *string:
			var ptr *string
			ptr, valid = namedArg.dest.(*string)
			if valid {
				*ptr = namedArg.defValStr
			}
		default:
			err := fmt.Errorf(
				"Unexpected argument type while resetting named arg '%s'.",
				namedArg.name)
			return err
		}

		if !valid {
			err = fmt.Errorf(
				"Unable to cast to argument type for arg '%s'.", namedArg.name)
			return err
		}
		if err != nil {
			err = fmt.Errorf(
				"Error while resetting named arg '%s' to default value.\n%s",
				namedArg.name,
				err.Error())
			return err
		}
	}

	return nil
}

func newNamedArg(name, short, help, defValStr string, dest interface{}, required bool) *NamedArg {
	arg := new(NamedArg)
	arg.name = name
	arg.short = short
	arg.help = help
	arg.defValStr = defValStr
	arg.dest = dest
	arg.required = required
	arg.set = false

	return arg
}

type Cmd struct {
	// Command name
	name string

	// Sub-commands
	subCmds map[string]*Cmd

	// Command description
	description string

	// Mapping from arg names to args.
	// This is used during parsing.
	namedArgMap map[string]*NamedArg

	// List of all named args.
	namedArgList []*NamedArg

	// List of unnamed arguments to the command.
	// This is populated while parsing.
	argList []Arg

	// Indicates whether -h or --help was specified during parsing.
	shouldRenderHelp bool

	// Indicates whether the Parse method was called and that it was
	// successfull.
	parsed bool
}

// NewCmd creates a new command with name |name|.
// The description of the command (which is printed when the command is
// executed with '-h' or '--help' options) should be specified in
// |description|.
func NewCmd(name string, description string) *Cmd {
	cmd := new(Cmd)
	cmd.name = name
	cmd.description = description
	cmd.shouldRenderHelp = false
	cmd.parsed = false
	cmd.namedArgMap = make(map[string]*NamedArg)
	cmd.subCmds = make(map[string]*Cmd)

	cmd.AddBoolArg(
		"help", "h", &cmd.shouldRenderHelp, cmd.shouldRenderHelp,
		false, fmt.Sprintf("Print '%s' usage information.", name))

	return cmd
}

func (cmd *Cmd) Name() string {
	return cmd.name
}

func (cmd *Cmd) AddSubCmd(subCmd *Cmd) error {
	subCmdName := subCmd.Name()
	_, exists := cmd.subCmds[subCmdName]
	if exists {
		return fmt.Errorf(
			"Sub-command with name '%s' already registered with '%s'.",
			subCmdName, cmd.name)
	}

	cmd.subCmds[subCmdName] = subCmd
	return nil
}

func (cmd *Cmd) addNamedArg(
	name, short, help, defValStr string, dest interface{}, required bool) {
	arg := newNamedArg(name, short, help, defValStr, dest, required)
	cmd.namedArgList = append(cmd.namedArgList, arg)
	cmd.namedArgMap[name] = arg
	cmd.namedArgMap[short] = arg
}

func (cmd *Cmd) AddIntArg(
	name string, short string, dest *int, def int, required bool, help string) {
	cmd.addNamedArg(name, short, help, fmt.Sprintf("%d", def), dest, required)
	*dest = def
}

func (cmd *Cmd) AddInt64Arg(
	name string, short string, dest *int64, def int64, required bool, help string) {
	cmd.addNamedArg(name, short, help, fmt.Sprintf("%d", def), dest, required)
	*dest = def
}

func (cmd *Cmd) AddUIntArg(
	name string, short string, dest *uint, def uint, required bool, help string) {
	cmd.addNamedArg(name, short, help, fmt.Sprintf("%d", def), dest, required)
	*dest = def
}

func (cmd *Cmd) AddUInt64Arg(
	name string, short string, dest *uint64, def uint64, required bool, help string) {
	cmd.addNamedArg(name, short, help, fmt.Sprintf("%d", def), dest, required)
	*dest = def
}

func (cmd *Cmd) AddFloat64Arg(
	name string, short string, dest *float64, def float64, required bool, help string) {
	cmd.addNamedArg(name, short, help, fmt.Sprintf("%f", def), dest, required)
	*dest = def
}

func (cmd *Cmd) AddBoolArg(
	name string, short string, dest *bool, def bool, required bool, help string) {
	cmd.addNamedArg(name, short, help, fmt.Sprintf("%t", def), dest, required)
	*dest = def
}

func (cmd *Cmd) AddStringArg(
	name string, short string, dest *string, def string, required bool, help string) {
	cmd.addNamedArg(name, short, help, fmt.Sprintf("%s", def), dest, required)
	*dest = def
}

func (cmd *Cmd) Parse(arguments []string) ([]string, error) {
	processedCmds := []string{cmd.name}

	if len(arguments) > 0 {
		subCmd, exists := cmd.subCmds[arguments[0]]
		if exists {
			subCmdList, err := subCmd.Parse(arguments[1:])
			return append(processedCmds, subCmdList...), err
		}
	}

	for i := 0; i < len(arguments); i++ {
		argument := arguments[i]
		if strings.HasPrefix(argument, "-") {
			// A named argument can be specified in the following ways:
			//     -name value
			//     --name value
			//     -name=value
			//     --name=value
			// If it were a bool value argument, the value can be omitted to
			// imply a value of 'true':
			//     -name
			//     --name

			stripped := argument[1:]
			if strings.HasPrefix(stripped, "-") {
				stripped = stripped[1:]
			}

			var arg *NamedArg
			var valStr string

			indexOfEqual := strings.Index(stripped, "=")
			if indexOfEqual < 0 {
				// The stripped argument is the name if there is no "=".
				name := stripped
				var exists bool
				arg, exists = cmd.namedArgMap[name]
				if !exists {
					err := fmt.Errorf("Unknown argument '%s'.", name)
					return processedCmds, err
				}

				// If the argument is of bool type, then the next argument
				// can be a string which can be parsed error free by
				// strconv.ParseBool, or can be unspecified to mean 'true'.
				i += 1
				switch arg.dest.(type)  {
				default:
					valStr = arguments[i]
				case *bool:
					nextArgStr := arguments[i]
					_, err := strconv.ParseBool(nextArgStr)
					if err == nil {
						valStr = nextArgStr
					} else {
						i -= 1
						valStr = "true"
					}
				}
			} else if indexOfEqual == 0 {
				// This is an error
				err := fmt.Errorf(
					"Probably missing an argument name in '%s'.", argument)
				return processedCmds, err
			} else {
				name := stripped[0:indexOfEqual]
				valStr = stripped[indexOfEqual + 1:]
				var exists bool
				arg, exists = cmd.namedArgMap[name]
				if !exists {
					err := fmt.Errorf("Unknown argument '%s'.", name)
					return processedCmds, err
				}
			}

			var err error
			var valid bool
			switch arg.dest.(type) {
			case *int:
				var ptr *int
				ptr, valid = arg.dest.(*int)
				if valid {
					var int64Val int64
					int64Val, err = strconv.ParseInt(valStr, 0, 0)
					if err == nil {
						*ptr = int(int64Val)
					}
				}
			case *uint:
				var ptr *uint
				ptr, valid = arg.dest.(*uint)
				if valid {
					var uint64Val uint64
					uint64Val, err = strconv.ParseUint(valStr, 0, 0)
					if err == nil {
						*ptr = uint(uint64Val)
					}
				}
			case *int64:
				var ptr *int64
				ptr, valid = arg.dest.(*int64)
				if valid {
					*ptr, err = strconv.ParseInt(valStr, 0, 64)
				}
			case *uint64:
				var ptr *uint64
				ptr, valid = arg.dest.(*uint64)
				if valid {
					*ptr, err = strconv.ParseUint(valStr, 0, 64)
				}
			case *float64:
				var ptr *float64
				ptr, valid = arg.dest.(*float64)
				if valid {
					*ptr, err = strconv.ParseFloat(valStr, 64)
				}
			case *bool:
				var ptr *bool
				ptr, valid = arg.dest.(*bool)
				if valid {
					*ptr, err = strconv.ParseBool(valStr)
				}
			case *string:
				var ptr *string
				ptr, valid = arg.dest.(*string)
				if valid {
					*ptr = valStr
				}
			default:
				err := fmt.Errorf("Unexpected argument type while parsing.")
				return processedCmds, err
			}

			if !valid {
				err := fmt.Errorf("Unable to perform type assertion while parsing.")
				return processedCmds, err
			}
			if err != nil {
				err := fmt.Errorf(
					"Error parsing value of argument '%s'.\n%s", err.Error())
				return processedCmds, err
			}

			if arg.required {
				arg.set = true
			}
		} else {
			// This is not a named argument.
			cmd.argList = append(cmd.argList, Arg(argument))
		}
	}

	if !cmd.shouldRenderHelp {
		for _, arg := range cmd.namedArgList {
			if arg.required && !arg.set {
				err := fmt.Errorf("Required argument '%s' not specified.", arg.name)
				return processedCmds, err
			}
		}
	}

	return processedCmds, nil
}

func (cmd *Cmd) Args() []Arg {
	return cmd.argList
}

func (cmd *Cmd) Clear() error {
	cmd.argList = nil

	for _, namedArg := range cmd.namedArgList {
		err := namedArg.Reset()
		if err != nil {
			err = fmt.Errorf(
				"Unable to clear command '%s'.\n%s'", cmd.name, err.Error())
			return err
		}
	}

	for _, subCmd := range cmd.subCmds {
		err := subCmd.Clear()
		if err != nil {
			err = fmt.Errorf(
				"Unable to clear sub-command '%s' of command '%s'.\n%s",
				cmd.name, subCmd.name, err.Error())
			return err
		}
	}

	return nil
}

func (cmd *Cmd) ShouldRenderHelp() bool {
	return cmd.shouldRenderHelp
}

func (cmd *Cmd) RenderHelp() {
	fmt.Printf("%s\n\n", cmd.description)

	if len(cmd.subCmds) > 0 {
		fmt.Printf("Sub-commands:\n")
		for _, subCmd := range cmd.subCmds {
			fmt.Printf("     %s\n", subCmd.name)
		}
		fmt.Printf("\n")
	}

	fmt.Printf("Options:\n")
	for _, arg := range cmd.namedArgList {
		fmt.Printf("  -%s,  --%s\n", arg.short, arg.name)
		if arg.required {
			fmt.Printf("     Required argument.\n")
		} else {
			fmt.Printf("     Default value: %s\n", arg.defValStr)
		}
		usage := strings.Replace(arg.help, "\n", "\n     ", -1)
		fmt.Printf("     %s\n", usage)
	}
}
<commit_msg>[clap] Add method 'Description' to the 'Cmd' type.<commit_after>// #############################################################################
// This file is part of the "clap" package of the "Eureka" project.
// It is distributed under the MIT License. Refer to the LICENSE file for more
// information.
//
// Website: http://www.github.com/sivachandra/eureka
// #############################################################################

// The clap package provides Command Line Argument Parsing facilities.
package clap

import (
	"fmt"
	"strconv"
	"strings"
)

type Arg string

type NamedArg struct {
	name string
	short string
	help string
	defValStr string
	dest interface{}
	required bool
	set bool
}

func (namedArg *NamedArg) Reset() error {
	namedArg.set = false
	if !namedArg.required {
		var valid bool
		var err error
		switch namedArg.dest.(type) {
		case *int:
			var ptr *int
			ptr, valid = namedArg.dest.(*int)
			if valid {
				var int64Val int64
				int64Val, err = strconv.ParseInt(namedArg.defValStr, 0, 0)
				if err == nil {
					*ptr = int(int64Val)
				}
			}
		case *uint:
			var ptr *uint
			ptr, valid = namedArg.dest.(*uint)
			if valid {
				var uint64Val uint64
				uint64Val, err = strconv.ParseUint(namedArg.defValStr, 0, 0)
				if err == nil {
					*ptr = uint(uint64Val)
				}
			}
		case *int64:
			var ptr *int64
			ptr, valid = namedArg.dest.(*int64)
			if valid {
				*ptr, err = strconv.ParseInt(namedArg.defValStr, 0, 64)
			}
		case *uint64:
			var ptr *uint64
			ptr, valid = namedArg.dest.(*uint64)
			if valid {
				*ptr, err = strconv.ParseUint(namedArg.defValStr, 0, 64)
			}
		case *float64:
			var ptr *float64
			ptr, valid = namedArg.dest.(*float64)
			if valid {
				*ptr, err = strconv.ParseFloat(namedArg.defValStr, 64)
			}
		case *bool:
			var ptr *bool
			ptr, valid = namedArg.dest.(*bool)
			if valid {
				*ptr, err = strconv.ParseBool(namedArg.defValStr)
			}
		case *string:
			var ptr *string
			ptr, valid = namedArg.dest.(*string)
			if valid {
				*ptr = namedArg.defValStr
			}
		default:
			err := fmt.Errorf(
				"Unexpected argument type while resetting named arg '%s'.",
				namedArg.name)
			return err
		}

		if !valid {
			err = fmt.Errorf(
				"Unable to cast to argument type for arg '%s'.", namedArg.name)
			return err
		}
		if err != nil {
			err = fmt.Errorf(
				"Error while resetting named arg '%s' to default value.\n%s",
				namedArg.name,
				err.Error())
			return err
		}
	}

	return nil
}

func newNamedArg(name, short, help, defValStr string, dest interface{}, required bool) *NamedArg {
	arg := new(NamedArg)
	arg.name = name
	arg.short = short
	arg.help = help
	arg.defValStr = defValStr
	arg.dest = dest
	arg.required = required
	arg.set = false

	return arg
}

type Cmd struct {
	// Command name
	name string

	// Sub-commands
	subCmds map[string]*Cmd

	// Command description
	description string

	// Mapping from arg names to args.
	// This is used during parsing.
	namedArgMap map[string]*NamedArg

	// List of all named args.
	namedArgList []*NamedArg

	// List of unnamed arguments to the command.
	// This is populated while parsing.
	argList []Arg

	// Indicates whether -h or --help was specified during parsing.
	shouldRenderHelp bool

	// Indicates whether the Parse method was called and that it was
	// successfull.
	parsed bool
}

// NewCmd creates a new command with name |name|.
// The description of the command (which is printed when the command is
// executed with '-h' or '--help' options) should be specified in
// |description|.
func NewCmd(name string, description string) *Cmd {
	cmd := new(Cmd)
	cmd.name = name
	cmd.description = description
	cmd.shouldRenderHelp = false
	cmd.parsed = false
	cmd.namedArgMap = make(map[string]*NamedArg)
	cmd.subCmds = make(map[string]*Cmd)

	cmd.AddBoolArg(
		"help", "h", &cmd.shouldRenderHelp, cmd.shouldRenderHelp,
		false, fmt.Sprintf("Print '%s' usage information.", name))

	return cmd
}

func (cmd *Cmd) Name() string {
	return cmd.name
}

func (cmd *Cmd) Description() string {
	return cmd.description
}

func (cmd *Cmd) AddSubCmd(subCmd *Cmd) error {
	subCmdName := subCmd.Name()
	_, exists := cmd.subCmds[subCmdName]
	if exists {
		return fmt.Errorf(
			"Sub-command with name '%s' already registered with '%s'.",
			subCmdName, cmd.name)
	}

	cmd.subCmds[subCmdName] = subCmd
	return nil
}

func (cmd *Cmd) addNamedArg(
	name, short, help, defValStr string, dest interface{}, required bool) {
	arg := newNamedArg(name, short, help, defValStr, dest, required)
	cmd.namedArgList = append(cmd.namedArgList, arg)
	cmd.namedArgMap[name] = arg
	cmd.namedArgMap[short] = arg
}

func (cmd *Cmd) AddIntArg(
	name string, short string, dest *int, def int, required bool, help string) {
	cmd.addNamedArg(name, short, help, fmt.Sprintf("%d", def), dest, required)
	*dest = def
}

func (cmd *Cmd) AddInt64Arg(
	name string, short string, dest *int64, def int64, required bool, help string) {
	cmd.addNamedArg(name, short, help, fmt.Sprintf("%d", def), dest, required)
	*dest = def
}

func (cmd *Cmd) AddUIntArg(
	name string, short string, dest *uint, def uint, required bool, help string) {
	cmd.addNamedArg(name, short, help, fmt.Sprintf("%d", def), dest, required)
	*dest = def
}

func (cmd *Cmd) AddUInt64Arg(
	name string, short string, dest *uint64, def uint64, required bool, help string) {
	cmd.addNamedArg(name, short, help, fmt.Sprintf("%d", def), dest, required)
	*dest = def
}

func (cmd *Cmd) AddFloat64Arg(
	name string, short string, dest *float64, def float64, required bool, help string) {
	cmd.addNamedArg(name, short, help, fmt.Sprintf("%f", def), dest, required)
	*dest = def
}

func (cmd *Cmd) AddBoolArg(
	name string, short string, dest *bool, def bool, required bool, help string) {
	cmd.addNamedArg(name, short, help, fmt.Sprintf("%t", def), dest, required)
	*dest = def
}

func (cmd *Cmd) AddStringArg(
	name string, short string, dest *string, def string, required bool, help string) {
	cmd.addNamedArg(name, short, help, fmt.Sprintf("%s", def), dest, required)
	*dest = def
}

func (cmd *Cmd) Parse(arguments []string) ([]string, error) {
	processedCmds := []string{cmd.name}

	if len(arguments) > 0 {
		subCmd, exists := cmd.subCmds[arguments[0]]
		if exists {
			subCmdList, err := subCmd.Parse(arguments[1:])
			return append(processedCmds, subCmdList...), err
		}
	}

	for i := 0; i < len(arguments); i++ {
		argument := arguments[i]
		if strings.HasPrefix(argument, "-") {
			// A named argument can be specified in the following ways:
			//     -name value
			//     --name value
			//     -name=value
			//     --name=value
			// If it were a bool value argument, the value can be omitted to
			// imply a value of 'true':
			//     -name
			//     --name

			stripped := argument[1:]
			if strings.HasPrefix(stripped, "-") {
				stripped = stripped[1:]
			}

			var arg *NamedArg
			var valStr string

			indexOfEqual := strings.Index(stripped, "=")
			if indexOfEqual < 0 {
				// The stripped argument is the name if there is no "=".
				name := stripped
				var exists bool
				arg, exists = cmd.namedArgMap[name]
				if !exists {
					err := fmt.Errorf("Unknown argument '%s'.", name)
					return processedCmds, err
				}

				// If the argument is of bool type, then the next argument
				// can be a string which can be parsed error free by
				// strconv.ParseBool, or can be unspecified to mean 'true'.
				i += 1
				switch arg.dest.(type)  {
				default:
					valStr = arguments[i]
				case *bool:
					nextArgStr := arguments[i]
					_, err := strconv.ParseBool(nextArgStr)
					if err == nil {
						valStr = nextArgStr
					} else {
						i -= 1
						valStr = "true"
					}
				}
			} else if indexOfEqual == 0 {
				// This is an error
				err := fmt.Errorf(
					"Probably missing an argument name in '%s'.", argument)
				return processedCmds, err
			} else {
				name := stripped[0:indexOfEqual]
				valStr = stripped[indexOfEqual + 1:]
				var exists bool
				arg, exists = cmd.namedArgMap[name]
				if !exists {
					err := fmt.Errorf("Unknown argument '%s'.", name)
					return processedCmds, err
				}
			}

			var err error
			var valid bool
			switch arg.dest.(type) {
			case *int:
				var ptr *int
				ptr, valid = arg.dest.(*int)
				if valid {
					var int64Val int64
					int64Val, err = strconv.ParseInt(valStr, 0, 0)
					if err == nil {
						*ptr = int(int64Val)
					}
				}
			case *uint:
				var ptr *uint
				ptr, valid = arg.dest.(*uint)
				if valid {
					var uint64Val uint64
					uint64Val, err = strconv.ParseUint(valStr, 0, 0)
					if err == nil {
						*ptr = uint(uint64Val)
					}
				}
			case *int64:
				var ptr *int64
				ptr, valid = arg.dest.(*int64)
				if valid {
					*ptr, err = strconv.ParseInt(valStr, 0, 64)
				}
			case *uint64:
				var ptr *uint64
				ptr, valid = arg.dest.(*uint64)
				if valid {
					*ptr, err = strconv.ParseUint(valStr, 0, 64)
				}
			case *float64:
				var ptr *float64
				ptr, valid = arg.dest.(*float64)
				if valid {
					*ptr, err = strconv.ParseFloat(valStr, 64)
				}
			case *bool:
				var ptr *bool
				ptr, valid = arg.dest.(*bool)
				if valid {
					*ptr, err = strconv.ParseBool(valStr)
				}
			case *string:
				var ptr *string
				ptr, valid = arg.dest.(*string)
				if valid {
					*ptr = valStr
				}
			default:
				err := fmt.Errorf("Unexpected argument type while parsing.")
				return processedCmds, err
			}

			if !valid {
				err := fmt.Errorf("Unable to perform type assertion while parsing.")
				return processedCmds, err
			}
			if err != nil {
				err := fmt.Errorf(
					"Error parsing value of argument '%s'.\n%s", err.Error())
				return processedCmds, err
			}

			if arg.required {
				arg.set = true
			}
		} else {
			// This is not a named argument.
			cmd.argList = append(cmd.argList, Arg(argument))
		}
	}

	if !cmd.shouldRenderHelp {
		for _, arg := range cmd.namedArgList {
			if arg.required && !arg.set {
				err := fmt.Errorf("Required argument '%s' not specified.", arg.name)
				return processedCmds, err
			}
		}
	}

	return processedCmds, nil
}

func (cmd *Cmd) Args() []Arg {
	return cmd.argList
}

func (cmd *Cmd) Clear() error {
	cmd.argList = nil

	for _, namedArg := range cmd.namedArgList {
		err := namedArg.Reset()
		if err != nil {
			err = fmt.Errorf(
				"Unable to clear command '%s'.\n%s'", cmd.name, err.Error())
			return err
		}
	}

	for _, subCmd := range cmd.subCmds {
		err := subCmd.Clear()
		if err != nil {
			err = fmt.Errorf(
				"Unable to clear sub-command '%s' of command '%s'.\n%s",
				cmd.name, subCmd.name, err.Error())
			return err
		}
	}

	return nil
}

func (cmd *Cmd) ShouldRenderHelp() bool {
	return cmd.shouldRenderHelp
}

func (cmd *Cmd) RenderHelp() {
	fmt.Printf("%s\n\n", cmd.description)

	if len(cmd.subCmds) > 0 {
		fmt.Printf("Sub-commands:\n")
		for _, subCmd := range cmd.subCmds {
			fmt.Printf("     %s\n", subCmd.name)
		}
		fmt.Printf("\n")
	}

	fmt.Printf("Options:\n")
	for _, arg := range cmd.namedArgList {
		fmt.Printf("  -%s,  --%s\n", arg.short, arg.name)
		if arg.required {
			fmt.Printf("     Required argument.\n")
		} else {
			fmt.Printf("     Default value: %s\n", arg.defValStr)
		}
		usage := strings.Replace(arg.help, "\n", "\n     ", -1)
		fmt.Printf("     %s\n", usage)
	}
}
<|endoftext|>


<commit_before>package cli

import "fmt"

const (
	InfoColor    = "\033[1;34m%s\033[0m"
	NoticeColor  = "\033[1;36m%s\033[0m"
	WarningColor = "\033[1;33m%s\033[0m"
	ErrorColor   = "\033[1;31m%s\033[0m"
	DebugColor   = "\033[0;36m%s\033[0m"
)

func Info(s string) string {
	return fmt.Sprintf(InfoColor, s)
}

func Notice(s string) string {
	return fmt.Sprintf(NoticeColor, s)
}

func Warning(s string) string {
	return fmt.Sprintf(WarningColor, s)
}
func Error(s string) string {
	return fmt.Sprintf(ErrorColor, s)
}

func Debug(s string) string {
	return fmt.Sprintf(DebugColor, s)
}

func Errorf(msg string, args ...interface{}) {
	fmt.Printf(Error(msg), args)
}<commit_msg>optimize Color formatter<commit_after>package cli

import "fmt"

const (
	InfoColor    = "\033[1;34m"
	NoticeColor  = "\033[1;36m"
	WarningColor = "\033[1;33m"
	ErrorColor   = "\033[1;31m"
	DebugColor   = "\033[0;36m"
	ColorTail = "\033[0m"
)

func Info(s string) {
	fmt.Print(InfoColor + s + ColorTail)
}

func Notice(s string) {
	fmt.Print(NoticeColor + s + ColorTail)
}

func Warning(s string) {
	fmt.Print(WarningColor + s + ColorTail)
}

func Error(s string) {
	fmt.Print(ErrorColor + s + ColorTail)
}

func Debug(s string) {
	fmt.Print(DebugColor + s + ColorTail)
}

func Warningf(format string, args ...interface{}) {
	Warning(fmt.Sprintf(format, args))
}

func Errorf(format string, args ...interface{}) {
	Error(fmt.Sprintf(format, args))
}<|endoftext|>


<commit_before>package cli

import (
	"errors"
	"os"
	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/bitrise-io/bitrise-cli/bitrise"
	models "github.com/bitrise-io/bitrise-cli/models/models_1_0_0"
	"github.com/bitrise-io/go-pathutil/pathutil"
	"github.com/bitrise-io/goinp/goinp"
	"github.com/codegangsta/cli"
)

const (
	defaultBitriseConfigFileName = "bitrise.yml"
	defaultInventoryFileName     = ".bitrise.secrects.yml"
)

var (
	failedSteps   []string
	inventoryPath string
)

// StepIDData ...
type StepIDData struct {
	ID            string
	Version       string
	SteplibSource string
}

func isBuildFailed() bool {
	if len(failedSteps) > 0 {
		return true
	}
	return false
}

func createStepIDDataFromString(s string) (StepIDData, error) {
	libsourceStepSplits := strings.Split(s, "::")
	if len(libsourceStepSplits) != 2 {
		return StepIDData{}, errors.New("Steplib should be separated with a '::' separator from the step ID (" + s + ")")
	}
	stepidVersionSplits := strings.Split(libsourceStepSplits[1], "@")
	if len(stepidVersionSplits) != 2 {
		return StepIDData{}, errors.New("Step ID and version should be separated with a '@' separator (" + libsourceStepSplits[1] + ")")
	}

	return StepIDData{
		SteplibSource: libsourceStepSplits[0],
		ID:            stepidVersionSplits[0],
		Version:       stepidVersionSplits[1],
	}, nil
}

func exportEnvironmentsList(envsList []models.EnvironmentItemModel) error {
	log.Info("[BITRISE_CLI] - Exporting workflow environments")

	for _, env := range envsList {
		envKey, envValue, err := env.GetKeyValue()
		if err != nil {
			log.Errorln("[BITRISE_CLI] - Failed to get environment key-value pair from env:", env)
			return err
		}
		if envValue != "" {
			expand := true
			if env["is_expand"] != "" {
				boolValue, err := goinp.ParseBool(env["is_expand"])
				if err != nil {
					log.Error("Failed to parse bool:", err)
					return err
				}
				expand = boolValue
			}
			if err := bitrise.RunEnvmanAdd(envKey, envValue, expand); err != nil {
				log.Errorln("[BITRISE_CLI] - Failed to run envman add")
				return err
			}
		}
	}
	return nil
}

func activateAndRunSteps(workflow models.WorkflowModel) error {
	log.Info("[BITRISE_CLI] - Activating and running steps")

	for _, stepListItm := range workflow.Steps {
		// TODO: first arg should be 'stepCompositeID'
		//  which can contain the step-collection, step-id, version, etc.
		//  in one string!
		compositeStepIDStr, workflowStep, err := stepListItm.GetStepIDStepDataPair()
		if err != nil {
			return err
		}
		stepIDData, err := createStepIDDataFromString(compositeStepIDStr)
		if err != nil {
			return err
		}
		log.Infof("[BITRISE_CLI] - Running Step: %#v", workflowStep)
		stepDir := bitrise.BitriseWorkStepsDirPath + "/" + stepIDData.ID + "/" + stepIDData.Version + "/"

		if err := bitrise.RunStepmanSetup(stepIDData.SteplibSource); err != nil {
			log.Error("Failed to setup stepman:", err)
		}

		if err := bitrise.RunStepmanActivate(stepIDData.SteplibSource, stepIDData.ID, stepIDData.Version, stepDir); err != nil {
			log.Errorln("[BITRISE_CLI] - Failed to run stepman activate")
			failedSteps = append(failedSteps, compositeStepIDStr)
		} else {
			log.Infof("[BITRISE_CLI] - Step activated: %s (%s)", stepIDData.ID, stepIDData.Version)

			if err := runStep(workflowStep, stepIDData); err != nil {
				log.Errorln("[BITRISE_CLI] - Failed to run step:", err)
				failedSteps = append(failedSteps, compositeStepIDStr)
			}
		}
	}
	return nil
}

func runStep(step models.StepModel, stepIDData StepIDData) error {
	log.Infof("[BITRISE_CLI] - Try running step: %s (%s)", stepIDData.ID, stepIDData.Version)

	// Add step envs
	for _, input := range step.Inputs {
		envKey, envValue, err := input.GetKeyValue()
		if err != nil {
			return err
		}
		if envValue != "" {
			expand := true
			if input["is_expand"] != "" {
				boolValue, err := goinp.ParseBool(input["is_expand"])
				if err != nil {
					log.Error("Failed to parse bool:", err)
					return err
				}
				expand = boolValue
			}
			if err := bitrise.RunEnvmanAdd(envKey, envValue, expand); err != nil {
				log.Errorln("[BITRISE_CLI] - Failed to run envman add")
				return err
			}
		}
	}

	stepDir := bitrise.BitriseWorkStepsDirPath + "/" + stepIDData.ID + "/" + stepIDData.Version + "/"
	stepCmd := stepDir + "/" + "step.sh"
	cmd := []string{"bash", stepCmd}
	if err := bitrise.RunEnvmanRunInDir(bitrise.CurrentDir, cmd); err != nil {
		log.Errorln("[BITRISE_CLI] - Failed to run envman run")
		return err
	}

	log.Infof("[BITRISE_CLI] - Step executed: %s (%s)", stepIDData.ID, stepIDData.Version)
	return nil
}

func doRun(c *cli.Context) {
	log.Info("[BITRISE_CLI] - Run")

	// Cleanup
	if err := bitrise.CleanupBitriseWorkPath(); err != nil {
		log.Fatal("Failed to cleanup bitrise work dir:", err)
	}
	failedSteps = []string{}

	// Input validation
	bitriseConfigPath := c.String(PathKey)
	if bitriseConfigPath == "" {
		log.Infoln("[BITRISE_CLI] - Workflow path not defined, searching for " + defaultBitriseConfigFileName + " in current folder...")

		if exist, err := pathutil.IsPathExists("./" + defaultBitriseConfigFileName); err != nil {
			log.Fatalln("[BITRISE_CLI] - Failed to check path:", err)
		} else if !exist {
			log.Fatalln("[BITRISE_CLI] - No workflow yml found")
		}
		bitriseConfigPath = "./" + defaultBitriseConfigFileName
	}

	inventoryPath = c.String(InventoryKey)
	if inventoryPath == "" {
		log.Infoln("[BITRISE_CLI] - Inventory path not defined, searching for " + defaultInventoryFileName + " in current folder...")
		inventoryPath = bitrise.CurrentDir + "/" + defaultInventoryFileName

		if exist, err := pathutil.IsPathExists(inventoryPath); err != nil {
			log.Fatalln("[BITRISE_CLI] - Failed to check path:", err)
		} else if !exist {
			log.Error("[BITRISE_CLI] - No inventory yml found")
			inventoryPath = ""
		}
	} else {
		if exist, err := pathutil.IsPathExists(inventoryPath); err != nil {
			log.Fatalln("[BITRISE_CLI] - Failed to check path:", err)
		} else if !exist {
			log.Fatalln("[BITRISE_CLI] - No inventory yml found")
		}
	}
	if inventoryPath != "" {
		if err := bitrise.RunEnvmanEnvstoreTest(inventoryPath); err != nil {
			log.Fatal("Invalid invetory format:", err)
		}

		if err := bitrise.RunCopy(inventoryPath, bitrise.EnvstorePath); err != nil {
			log.Fatal("Failed to copy inventory:", err)
		}
	}

	// Workflow selection
	if len(c.Args()) < 1 {
		log.Fatalln("No workfow specified!")
	}
	workflowToRunName := c.Args()[0]

	// Envman setup
	if err := os.Setenv(bitrise.EnvstorePathEnvKey, bitrise.EnvstorePath); err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to add env:", err)
	}

	if err := os.Setenv(bitrise.FormattedOutputPathEnvKey, bitrise.FormattedOutputPath); err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to add env:", err)
	}

	if inventoryPath == "" {
		if err := bitrise.RunEnvmanInit(); err != nil {
			log.Fatalln("[BITRISE_CLI] - Failed to run envman init")
		}
	}

	// Run work flow
	bitriseConfig, err := bitrise.ReadBitriseConfigYML(bitriseConfigPath)
	if err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to read Workflow:", err)
	}
	workflowToRun, exist := bitriseConfig.Workflows[workflowToRunName]
	if !exist {
		log.Fatalln("[BITRISE_CLI] - Specified Workflow (" + workflowToRunName + ") does not exist!")
	}
	log.Infoln("[BITRISE_CLI] - Running Workflow:", workflowToRunName)

	// App level environment
	if err := exportEnvironmentsList(bitriseConfig.App.Environments); err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to export App environments:", err)
	}

	// Workflow level environments
	if err := exportEnvironmentsList(workflowToRun.Environments); err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to export Workflow environments:", err)
	}

	// Run the Workflow
	if err := activateAndRunSteps(workflowToRun); err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to activate steps:", err)
	}

	log.Info("Failed steps:", failedSteps)
}
<commit_msg>.bitrise.secrets.yml filename fix (typo)<commit_after>package cli

import (
	"errors"
	"os"
	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/bitrise-io/bitrise-cli/bitrise"
	models "github.com/bitrise-io/bitrise-cli/models/models_1_0_0"
	"github.com/bitrise-io/go-pathutil/pathutil"
	"github.com/bitrise-io/goinp/goinp"
	"github.com/codegangsta/cli"
)

const (
	defaultBitriseConfigFileName = "bitrise.yml"
	defaultInventoryFileName     = ".bitrise.secrets.yml"
)

var (
	failedSteps   []string
	inventoryPath string
)

// StepIDData ...
type StepIDData struct {
	ID            string
	Version       string
	SteplibSource string
}

func isBuildFailed() bool {
	if len(failedSteps) > 0 {
		return true
	}
	return false
}

func createStepIDDataFromString(s string) (StepIDData, error) {
	libsourceStepSplits := strings.Split(s, "::")
	if len(libsourceStepSplits) != 2 {
		return StepIDData{}, errors.New("Steplib should be separated with a '::' separator from the step ID (" + s + ")")
	}
	stepidVersionSplits := strings.Split(libsourceStepSplits[1], "@")
	if len(stepidVersionSplits) != 2 {
		return StepIDData{}, errors.New("Step ID and version should be separated with a '@' separator (" + libsourceStepSplits[1] + ")")
	}

	return StepIDData{
		SteplibSource: libsourceStepSplits[0],
		ID:            stepidVersionSplits[0],
		Version:       stepidVersionSplits[1],
	}, nil
}

func exportEnvironmentsList(envsList []models.EnvironmentItemModel) error {
	log.Info("[BITRISE_CLI] - Exporting workflow environments")

	for _, env := range envsList {
		envKey, envValue, err := env.GetKeyValue()
		if err != nil {
			log.Errorln("[BITRISE_CLI] - Failed to get environment key-value pair from env:", env)
			return err
		}
		if envValue != "" {
			expand := true
			if env["is_expand"] != "" {
				boolValue, err := goinp.ParseBool(env["is_expand"])
				if err != nil {
					log.Error("Failed to parse bool:", err)
					return err
				}
				expand = boolValue
			}
			if err := bitrise.RunEnvmanAdd(envKey, envValue, expand); err != nil {
				log.Errorln("[BITRISE_CLI] - Failed to run envman add")
				return err
			}
		}
	}
	return nil
}

func activateAndRunSteps(workflow models.WorkflowModel) error {
	log.Info("[BITRISE_CLI] - Activating and running steps")

	for _, stepListItm := range workflow.Steps {
		// TODO: first arg should be 'stepCompositeID'
		//  which can contain the step-collection, step-id, version, etc.
		//  in one string!
		compositeStepIDStr, workflowStep, err := stepListItm.GetStepIDStepDataPair()
		if err != nil {
			return err
		}
		stepIDData, err := createStepIDDataFromString(compositeStepIDStr)
		if err != nil {
			return err
		}
		log.Infof("[BITRISE_CLI] - Running Step: %#v", workflowStep)
		stepDir := bitrise.BitriseWorkStepsDirPath + "/" + stepIDData.ID + "/" + stepIDData.Version + "/"

		if err := bitrise.RunStepmanSetup(stepIDData.SteplibSource); err != nil {
			log.Error("Failed to setup stepman:", err)
		}

		if err := bitrise.RunStepmanActivate(stepIDData.SteplibSource, stepIDData.ID, stepIDData.Version, stepDir); err != nil {
			log.Errorln("[BITRISE_CLI] - Failed to run stepman activate")
			failedSteps = append(failedSteps, compositeStepIDStr)
		} else {
			log.Infof("[BITRISE_CLI] - Step activated: %s (%s)", stepIDData.ID, stepIDData.Version)

			if err := runStep(workflowStep, stepIDData); err != nil {
				log.Errorln("[BITRISE_CLI] - Failed to run step:", err)
				failedSteps = append(failedSteps, compositeStepIDStr)
			}
		}
	}
	return nil
}

func runStep(step models.StepModel, stepIDData StepIDData) error {
	log.Infof("[BITRISE_CLI] - Try running step: %s (%s)", stepIDData.ID, stepIDData.Version)

	// Add step envs
	for _, input := range step.Inputs {
		envKey, envValue, err := input.GetKeyValue()
		if err != nil {
			return err
		}
		if envValue != "" {
			expand := true
			if input["is_expand"] != "" {
				boolValue, err := goinp.ParseBool(input["is_expand"])
				if err != nil {
					log.Error("Failed to parse bool:", err)
					return err
				}
				expand = boolValue
			}
			if err := bitrise.RunEnvmanAdd(envKey, envValue, expand); err != nil {
				log.Errorln("[BITRISE_CLI] - Failed to run envman add")
				return err
			}
		}
	}

	stepDir := bitrise.BitriseWorkStepsDirPath + "/" + stepIDData.ID + "/" + stepIDData.Version + "/"
	stepCmd := stepDir + "/" + "step.sh"
	cmd := []string{"bash", stepCmd}
	if err := bitrise.RunEnvmanRunInDir(bitrise.CurrentDir, cmd); err != nil {
		log.Errorln("[BITRISE_CLI] - Failed to run envman run")
		return err
	}

	log.Infof("[BITRISE_CLI] - Step executed: %s (%s)", stepIDData.ID, stepIDData.Version)
	return nil
}

func doRun(c *cli.Context) {
	log.Info("[BITRISE_CLI] - Run")

	// Cleanup
	if err := bitrise.CleanupBitriseWorkPath(); err != nil {
		log.Fatal("Failed to cleanup bitrise work dir:", err)
	}
	failedSteps = []string{}

	// Input validation
	bitriseConfigPath := c.String(PathKey)
	if bitriseConfigPath == "" {
		log.Infoln("[BITRISE_CLI] - Workflow path not defined, searching for " + defaultBitriseConfigFileName + " in current folder...")

		if exist, err := pathutil.IsPathExists("./" + defaultBitriseConfigFileName); err != nil {
			log.Fatalln("[BITRISE_CLI] - Failed to check path:", err)
		} else if !exist {
			log.Fatalln("[BITRISE_CLI] - No workflow yml found")
		}
		bitriseConfigPath = "./" + defaultBitriseConfigFileName
	}

	inventoryPath = c.String(InventoryKey)
	if inventoryPath == "" {
		log.Infoln("[BITRISE_CLI] - Inventory path not defined, searching for " + defaultInventoryFileName + " in current folder...")
		inventoryPath = bitrise.CurrentDir + "/" + defaultInventoryFileName

		if exist, err := pathutil.IsPathExists(inventoryPath); err != nil {
			log.Fatalln("[BITRISE_CLI] - Failed to check path:", err)
		} else if !exist {
			log.Error("[BITRISE_CLI] - No inventory yml found")
			inventoryPath = ""
		}
	} else {
		if exist, err := pathutil.IsPathExists(inventoryPath); err != nil {
			log.Fatalln("[BITRISE_CLI] - Failed to check path:", err)
		} else if !exist {
			log.Fatalln("[BITRISE_CLI] - No inventory yml found")
		}
	}
	if inventoryPath != "" {
		if err := bitrise.RunEnvmanEnvstoreTest(inventoryPath); err != nil {
			log.Fatal("Invalid invetory format:", err)
		}

		if err := bitrise.RunCopy(inventoryPath, bitrise.EnvstorePath); err != nil {
			log.Fatal("Failed to copy inventory:", err)
		}
	}

	// Workflow selection
	if len(c.Args()) < 1 {
		log.Fatalln("No workfow specified!")
	}
	workflowToRunName := c.Args()[0]

	// Envman setup
	if err := os.Setenv(bitrise.EnvstorePathEnvKey, bitrise.EnvstorePath); err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to add env:", err)
	}

	if err := os.Setenv(bitrise.FormattedOutputPathEnvKey, bitrise.FormattedOutputPath); err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to add env:", err)
	}

	if inventoryPath == "" {
		if err := bitrise.RunEnvmanInit(); err != nil {
			log.Fatalln("[BITRISE_CLI] - Failed to run envman init")
		}
	}

	// Run work flow
	bitriseConfig, err := bitrise.ReadBitriseConfigYML(bitriseConfigPath)
	if err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to read Workflow:", err)
	}
	workflowToRun, exist := bitriseConfig.Workflows[workflowToRunName]
	if !exist {
		log.Fatalln("[BITRISE_CLI] - Specified Workflow (" + workflowToRunName + ") does not exist!")
	}
	log.Infoln("[BITRISE_CLI] - Running Workflow:", workflowToRunName)

	// App level environment
	if err := exportEnvironmentsList(bitriseConfig.App.Environments); err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to export App environments:", err)
	}

	// Workflow level environments
	if err := exportEnvironmentsList(workflowToRun.Environments); err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to export Workflow environments:", err)
	}

	// Run the Workflow
	if err := activateAndRunSteps(workflowToRun); err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to activate steps:", err)
	}

	log.Info("Failed steps:", failedSteps)
}
<|endoftext|>


<commit_before>package cli

import (
	"fmt"
	"github.com/brightbox/gobrightbox"
	"github.com/howeyc/gopass"
	"golang.org/x/oauth2"
	"gopkg.in/alecthomas/kingpin.v2"
	"strings"
)

type loginCommand struct {
	*CLIApp
	Email          string
	ApiUrl         string
	AuthUrl        string
	ClientId       string
	Secret         string
	DefaultAccount string
}

func (l *loginCommand) login(pc *kingpin.ParseContext) error {
	err := l.Configure()
	if err != nil {
		return err
	}

	var client *Client
	clientName := l.Email
	if l.ClientName == "" {
		client, _ = l.Config.Client(clientName)
	} else {
		client, err = l.Config.Client(clientName)
		if err != nil {
			l.Fatalf("Couldn't find client config %s: %s", clientName, err)
		}
	}

	if l.Email == "" && client != nil {
		l.Email = client.Username
	}

	if l.Email == "" {
		l.Fatalf("required argument 'email address' not provided")
	}

	if client == nil {
		client = new(Client)
	}

	email := l.Email
	if strings.Contains(email, "/") {
		toks := strings.SplitN(email, "/", 2)
		email = toks[0]
	}
	client.ClientName = clientName
	if l.ClientId != "" {
		client.ClientID = l.ClientId
	}
	if l.Secret != "" {
		client.Secret = l.Secret
	}
	if l.ApiUrl != "" {
		client.ApiUrl = l.ApiUrl
	}
	if client.ApiUrl == "" {
		client.ApiUrl = "https://api.gb1.brightbox.com"
	}
	if l.AuthUrl != "" {
		client.AuthUrl = l.AuthUrl
	}
	if client.AuthUrl == "" && l.ApiUrl != "" {
		client.ApiUrl = l.ApiUrl
	}
	if l.Email != "" {
		client.Username = email
	}
	if l.DefaultAccount != "" {
		client.DefaultAccount = l.DefaultAccount
	}

	oc := client.oauthConfig()
	var token *oauth2.Token
	switch oc := oc.(type) {
	case oauth2.Config:
		fmt.Printf("Password for %s: ", client.ClientName)
		password := gopass.GetPasswd()
		if string(password) == "" {
			l.Fatalf("Password not provided.")
		}
		token, err = oc.PasswordCredentialsToken(oauth2.NoContext, client.Username, string(password))
		if err != nil {
			l.Fatalf("%s", err)
		}
	default:
		l.Fatalf("Client config %s isn't for password authentication", client.ClientName)
	}
	client.TokenCache().Write(token)

	// Choose a default account
	if client.DefaultAccount == "" {
		client.Setup("")
		accounts, err := client.Accounts()
		if err != nil {
			l.Errorf("Couldn't choose a default account: %s", err)
		}
		if len(accounts) == 0 {
			l.Errorf("No accounts available to choose a default account")
		}
		var da brightbox.Account
		for _, a := range accounts {
			if a.Status == "active" {
				if da.Id == "" {
					da = a
					continue
				}
				if a.RamUsed > da.RamUsed {
					da = a
				}
			}
		}
		if da.Id != "" {
			fmt.Printf("Selected account \"%s\" (%s) as default account\n", da.Name, da.Id)
			client.DefaultAccount = da.Id
		}
	}
	err = l.Config.saveClientConfig(client)
	if err != nil {
		l.Fatalf("Couldn't save client config %s: %s", client.ClientName, err)
	}
	if l.Config.DefaultClient() == nil {
		l.Config.defaultClientName = client.ClientName
		l.Config.Write()
	}
	return nil
}

func configureLoginCommand(app *CLIApp) {
	cmd := loginCommand{CLIApp: app}
	login := app.Command("login", "Authenticate with user credentials").Action(cmd.login)
	login.Arg("email address", "Your user's email address").
		StringVar(&cmd.Email)
	login.Flag("api-url", "Custom Brightbox API URL. Defaults to https://api.gb1s.brightbox.com").
		StringVar(&cmd.ApiUrl)
	login.Flag("auth-url", "URL of Brightbox API authentication endpoint. Defaults to same as api-url.").
		StringVar(&cmd.AuthUrl)
	login.Flag("client-id", "OAuth client identifier to use").
		Default("app-12345").StringVar(&cmd.ClientId)
	login.Flag("secret", "OAuth client secret to use").
		Default("mocbuipbiaa6k6c").StringVar(&cmd.Secret)
	login.Flag("default-account", "Id of account to use by default with this client").
		StringVar(&cmd.DefaultAccount)

}
<commit_msg>Allow login with default client<commit_after>package cli

import (
	"fmt"
	"github.com/brightbox/gobrightbox"
	"github.com/howeyc/gopass"
	"golang.org/x/oauth2"
	"gopkg.in/alecthomas/kingpin.v2"
	"strings"
)

type loginCommand struct {
	*CLIApp
	Email          string
	ApiUrl         string
	AuthUrl        string
	ClientId       string
	Secret         string
	DefaultAccount string
}

func (l *loginCommand) login(pc *kingpin.ParseContext) error {
	err := l.Configure()
	if err != nil {
		return err
	}

	var client *Client
	username := ""
	clientname := ""

	if l.ClientName != "" {
		clientname = client.ClientName
		client, err = l.Config.Client(clientname)
		if err != nil {
			l.Fatalf("Couldn't find client config %s: %s", clientname, err)
		}
		username = client.Username
	}

	if l.Email != "" {
		username = l.Email
		if client == nil {
			clientname = username
			if strings.Contains(username, "/") {
				toks := strings.SplitN(username, "/", 2)
				username = toks[0]
			}
			client, _ = l.Config.Client(clientname)
			if client == nil {
				client = &Client{
					ClientName: clientname,
					Username: username,
				}
			}
		}
	}

	if client == nil {
		client = l.Config.DefaultClient()
		if client != nil	{
			username = client.Username
			clientname = client.ClientName
		}
	}

	if client == nil {
		client = &Client{
			Username: username,
			ClientName: clientname,
		}
	}

	if username == "" {
		l.Fatalf("required argument 'email address' not provided")
	}

	if l.ClientId != "" {
		client.ClientID = l.ClientId
	}
	if l.Secret != "" {
		client.Secret = l.Secret
	}
	if l.ApiUrl != "" {
		client.ApiUrl = l.ApiUrl
	}
	if client.ApiUrl == "" {
		client.ApiUrl = "https://api.gb1.brightbox.com"
	}
	if l.AuthUrl != "" {
		client.AuthUrl = l.AuthUrl
	}
	if client.AuthUrl == "" && l.ApiUrl != "" {
		client.ApiUrl = l.ApiUrl
	}
	if l.DefaultAccount != "" {
		client.DefaultAccount = l.DefaultAccount
	}

	oc := client.oauthConfig()
	var token *oauth2.Token
	switch oc := oc.(type) {
	case oauth2.Config:
		fmt.Printf("Password for %s: ", client.ClientName)
		password := gopass.GetPasswd()
		if string(password) == "" {
			l.Fatalf("Password not provided.")
		}
		token, err = oc.PasswordCredentialsToken(oauth2.NoContext, client.Username, string(password))
		if err != nil {
			l.Fatalf("%s", err)
		}
	default:
		l.Fatalf("Client config %s isn't for password authentication", client.ClientName)
	}
	client.TokenCache().Write(token)

	// Choose a default account
	if client.DefaultAccount == "" {
		client.Setup("")
		accounts, err := client.Accounts()
		if err != nil {
			l.Errorf("Couldn't choose a default account: %s", err)
		}
		if len(accounts) == 0 {
			l.Errorf("No accounts available to choose a default account")
		}
		var da brightbox.Account
		for _, a := range accounts {
			if a.Status == "active" {
				if da.Id == "" {
					da = a
					continue
				}
				if a.RamUsed > da.RamUsed {
					da = a
				}
			}
		}
		if da.Id != "" {
			fmt.Printf("Selected account \"%s\" (%s) as default account\n", da.Name, da.Id)
			client.DefaultAccount = da.Id
		}
	}
	err = l.Config.saveClientConfig(client)
	if err != nil {
		l.Fatalf("Couldn't save client config %s: %s", client.ClientName, err)
	}
	if l.Config.DefaultClient() == nil {
		l.Config.defaultClientName = client.ClientName
		l.Config.Write()
	}
	return nil
}

func configureLoginCommand(app *CLIApp) {
	cmd := loginCommand{CLIApp: app}
	login := app.Command("login", "Authenticate with user credentials").Action(cmd.login)
	login.Arg("email address", "Your user's email address").
		StringVar(&cmd.Email)
	login.Flag("api-url", "Custom Brightbox API URL. Defaults to https://api.gb1s.brightbox.com").
		StringVar(&cmd.ApiUrl)
	login.Flag("auth-url", "URL of Brightbox API authentication endpoint. Defaults to same as api-url.").
		StringVar(&cmd.AuthUrl)
	login.Flag("client-id", "OAuth client identifier to use").
		Default("app-12345").StringVar(&cmd.ClientId)
	login.Flag("secret", "OAuth client secret to use").
		Default("mocbuipbiaa6k6c").StringVar(&cmd.Secret)
	login.Flag("default-account", "Id of account to use by default with this client").
		StringVar(&cmd.DefaultAccount)

}
<|endoftext|>


<commit_before>// A memcached binary protocol client.
package memcached

import (
	"encoding/binary"
	"fmt"
	"io"
	"log"
	"net"
	"sync"

	"github.com/dustin/gomemcached"
)

const bufsize = 1024

// The Client itself.
type Client struct {
	conn io.ReadWriteCloser

	hdrBuf []byte
}

// Connect to a memcached server.
func Connect(prot, dest string) (rv *Client, err error) {
	conn, err := net.Dial(prot, dest)
	if err != nil {
		return nil, err
	}
	return &Client{
		conn:   conn,
		hdrBuf: make([]byte, gomemcached.HDR_LEN),
	}, nil
}

// Close the connection when you're done.
func (c *Client) Close() {
	c.conn.Close()
}

// Send a custom request and get the response.
func (client *Client) Send(req *gomemcached.MCRequest) (rv *gomemcached.MCResponse, err error) {
	err = transmitRequest(client.conn, req)
	if err != nil {
		return
	}
	return getResponse(client.conn, client.hdrBuf)
}

// Send a request, but do not wait for a response.
func (client *Client) Transmit(req *gomemcached.MCRequest) error {
	return transmitRequest(client.conn, req)
}

// Receive a response
func (client *Client) Receive() (*gomemcached.MCResponse, error) {
	return getResponse(client.conn, client.hdrBuf)
}

// Get the value for a key.
func (client *Client) Get(vb uint16, key string) (*gomemcached.MCResponse, error) {
	return client.Send(&gomemcached.MCRequest{
		Opcode:  gomemcached.GET,
		VBucket: vb,
		Key:     []byte(key),
		Cas:     0,
		Opaque:  0,
		Extras:  []byte{},
		Body:    []byte{}})
}

// Delete a key.
func (client *Client) Del(vb uint16, key string) (*gomemcached.MCResponse, error) {
	return client.Send(&gomemcached.MCRequest{
		Opcode:  gomemcached.DELETE,
		VBucket: vb,
		Key:     []byte(key),
		Cas:     0,
		Opaque:  0,
		Extras:  []byte{},
		Body:    []byte{}})
}

func (client *Client) store(opcode gomemcached.CommandCode, vb uint16,
	key string, flags int, exp int, body []byte) (*gomemcached.MCResponse, error) {

	req := &gomemcached.MCRequest{
		Opcode:  opcode,
		VBucket: vb,
		Key:     []byte(key),
		Cas:     0,
		Opaque:  0,
		Extras:  []byte{0, 0, 0, 0, 0, 0, 0, 0},
		Body:    body}

	binary.BigEndian.PutUint64(req.Extras, uint64(flags)<<32|uint64(exp))
	return client.Send(req)
}

// Increment a value.
func (client *Client) Incr(vb uint16, key string,
	amt, def uint64, exp int) (uint64, error) {

	req := &gomemcached.MCRequest{
		Opcode:  gomemcached.INCREMENT,
		VBucket: vb,
		Key:     []byte(key),
		Cas:     0,
		Opaque:  0,
		Extras:  make([]byte, 8+8+4),
		Body:    []byte{}}
	binary.BigEndian.PutUint64(req.Extras[:8], amt)
	binary.BigEndian.PutUint64(req.Extras[8:16], def)
	binary.BigEndian.PutUint32(req.Extras[16:20], uint32(exp))

	resp, err := client.Send(req)
	if err != nil {
		return 0, err
	}

	return binary.BigEndian.Uint64(resp.Body), nil
}

// Add a value for a key (store if not exists).
func (client *Client) Add(vb uint16, key string, flags int, exp int,
	body []byte) (*gomemcached.MCResponse, error) {
	return client.store(gomemcached.ADD, vb, key, flags, exp, body)
}

// Set the value for a key.
func (client *Client) Set(vb uint16, key string, flags int, exp int,
	body []byte) (*gomemcached.MCResponse, error) {
	return client.store(gomemcached.SET, vb, key, flags, exp, body)
}

// Get keys in bulk
func (client *Client) GetBulk(vb uint16, keys []string) (map[string]*gomemcached.MCResponse, error) {
	terminalOpaque := uint32(len(keys) + 5)
	rv := map[string]*gomemcached.MCResponse{}
	wg := sync.WaitGroup{}
	going := true

	defer func() {
		going = false
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		for going {
			res, err := client.Receive()
			if err != nil {
				return
			}
			if res.Opaque == terminalOpaque {
				return
			}
			if res.Opcode != gomemcached.GETQ {
				log.Panicf("Unexpected opcode in GETQ response: %+v",
					res)
			}
			rv[keys[res.Opaque]] = res
		}
	}()

	for i, k := range keys {
		err := client.Transmit(&gomemcached.MCRequest{
			Opcode:  gomemcached.GETQ,
			VBucket: vb,
			Key:     []byte(k),
			Cas:     0,
			Opaque:  uint32(i),
			Extras:  []byte{},
			Body:    []byte{}})
		if err != nil {
			return rv, err
		}
	}

	err := client.Transmit(&gomemcached.MCRequest{
		Opcode: gomemcached.NOOP,
		Key:    []byte{},
		Cas:    0,
		Extras: []byte{},
		Body:   []byte{},
		Opaque: terminalOpaque})
	if err != nil {
		return rv, err
	}

	wg.Wait()

	return rv, nil
}

// Stats returns a slice of these.
type StatValue struct {
	// The stat key
	Key string
	// The stat value
	Val string
}

// Get stats from the server
// use "" as the stat key for toplevel stats.
func (client *Client) Stats(key string) ([]StatValue, error) {
	rv := make([]StatValue, 0, 128)

	req := &gomemcached.MCRequest{
		Opcode:  gomemcached.STAT,
		VBucket: 0,
		Key:     []byte(key),
		Cas:     0,
		Opaque:  918494,
		Extras:  []byte{}}

	err := transmitRequest(client.conn, req)
	if err != nil {
		return rv, err
	}

	for {
		res, err := getResponse(client.conn, client.hdrBuf)
		if err != nil {
			return rv, err
		}
		k := string(res.Key)
		if k == "" {
			break
		}
		rv = append(rv, StatValue{
			Key: k,
			Val: string(res.Body),
		})
	}

	return rv, nil
}

// Get the stats from the server as a map
func (client *Client) StatsMap(key string) (map[string]string, error) {
	rv := make(map[string]string)
	st, err := client.Stats(key)
	if err != nil {
		return rv, err
	}
	for _, sv := range st {
		rv[sv.Key] = sv.Val
	}
	return rv, nil
}

func getResponse(s io.Reader, buf []byte) (rv *gomemcached.MCResponse, err error) {
	_, err = io.ReadFull(s, buf)
	if err != nil {
		return rv, err
	}
	rv, err = grokHeader(buf)
	if err != nil {
		return rv, err
	}
	err = readContents(s, rv)
	return rv, err
}

func readContents(s io.Reader, res *gomemcached.MCResponse) error {
	if len(res.Extras) > 0 {
		_, err := io.ReadFull(s, res.Extras)
		if err != nil {
			return err
		}
	}
	if len(res.Key) > 0 {
		_, err := io.ReadFull(s, res.Key)
		if err != nil {
			return err
		}
	}
	_, err := io.ReadFull(s, res.Body)
	return err
}

func grokHeader(hdrBytes []byte) (rv *gomemcached.MCResponse, err error) {
	if hdrBytes[0] != gomemcached.RES_MAGIC {
		return rv, fmt.Errorf("Bad magic: 0x%02x", hdrBytes[0])
	}
	rv = &gomemcached.MCResponse{
		Opcode: gomemcached.CommandCode(hdrBytes[1]),
		Key:    make([]byte, binary.BigEndian.Uint16(hdrBytes[2:4])),
		Extras: make([]byte, hdrBytes[4]),
		Status: gomemcached.Status(binary.BigEndian.Uint16(hdrBytes[6:8])),
		Opaque: binary.BigEndian.Uint32(hdrBytes[12:16]),
		Cas:    binary.BigEndian.Uint64(hdrBytes[16:24]),
	}
	bodyLen := binary.BigEndian.Uint32(hdrBytes[8:12]) -
		uint32(len(rv.Key)+len(rv.Extras))
	rv.Body = make([]byte, bodyLen)

	return
}

func transmitRequest(o io.Writer, req *gomemcached.MCRequest) (err error) {
	if len(req.Body) < 128 {
		_, err = o.Write(req.Bytes())
	} else {
		_, err = o.Write(req.HeaderBytes())
		if err == nil && len(req.Body) > 0 {
			_, err = o.Write(req.Body)
		}
	}
	return
}
<commit_msg>CAS support.<commit_after>// A memcached binary protocol client.
package memcached

import (
	"encoding/binary"
	"fmt"
	"io"
	"log"
	"net"
	"sync"

	"github.com/dustin/gomemcached"
)

const bufsize = 1024

// The Client itself.
type Client struct {
	conn io.ReadWriteCloser

	hdrBuf []byte
}

// Connect to a memcached server.
func Connect(prot, dest string) (rv *Client, err error) {
	conn, err := net.Dial(prot, dest)
	if err != nil {
		return nil, err
	}
	return &Client{
		conn:   conn,
		hdrBuf: make([]byte, gomemcached.HDR_LEN),
	}, nil
}

// Close the connection when you're done.
func (c *Client) Close() {
	c.conn.Close()
}

// Send a custom request and get the response.
func (client *Client) Send(req *gomemcached.MCRequest) (rv *gomemcached.MCResponse, err error) {
	err = transmitRequest(client.conn, req)
	if err != nil {
		return
	}
	return getResponse(client.conn, client.hdrBuf)
}

// Send a request, but do not wait for a response.
func (client *Client) Transmit(req *gomemcached.MCRequest) error {
	return transmitRequest(client.conn, req)
}

// Receive a response
func (client *Client) Receive() (*gomemcached.MCResponse, error) {
	return getResponse(client.conn, client.hdrBuf)
}

// Get the value for a key.
func (client *Client) Get(vb uint16, key string) (*gomemcached.MCResponse, error) {
	return client.Send(&gomemcached.MCRequest{
		Opcode:  gomemcached.GET,
		VBucket: vb,
		Key:     []byte(key),
		Cas:     0,
		Opaque:  0,
		Extras:  []byte{},
		Body:    []byte{}})
}

// Delete a key.
func (client *Client) Del(vb uint16, key string) (*gomemcached.MCResponse, error) {
	return client.Send(&gomemcached.MCRequest{
		Opcode:  gomemcached.DELETE,
		VBucket: vb,
		Key:     []byte(key),
		Cas:     0,
		Opaque:  0,
		Extras:  []byte{},
		Body:    []byte{}})
}

func (client *Client) store(opcode gomemcached.CommandCode, vb uint16,
	key string, flags int, exp int, body []byte) (*gomemcached.MCResponse, error) {

	req := &gomemcached.MCRequest{
		Opcode:  opcode,
		VBucket: vb,
		Key:     []byte(key),
		Cas:     0,
		Opaque:  0,
		Extras:  []byte{0, 0, 0, 0, 0, 0, 0, 0},
		Body:    body}

	binary.BigEndian.PutUint64(req.Extras, uint64(flags)<<32|uint64(exp))
	return client.Send(req)
}

// Increment a value.
func (client *Client) Incr(vb uint16, key string,
	amt, def uint64, exp int) (uint64, error) {

	req := &gomemcached.MCRequest{
		Opcode:  gomemcached.INCREMENT,
		VBucket: vb,
		Key:     []byte(key),
		Cas:     0,
		Opaque:  0,
		Extras:  make([]byte, 8+8+4),
		Body:    []byte{}}
	binary.BigEndian.PutUint64(req.Extras[:8], amt)
	binary.BigEndian.PutUint64(req.Extras[8:16], def)
	binary.BigEndian.PutUint32(req.Extras[16:20], uint32(exp))

	resp, err := client.Send(req)
	if err != nil {
		return 0, err
	}

	return binary.BigEndian.Uint64(resp.Body), nil
}

// Add a value for a key (store if not exists).
func (client *Client) Add(vb uint16, key string, flags int, exp int,
	body []byte) (*gomemcached.MCResponse, error) {
	return client.store(gomemcached.ADD, vb, key, flags, exp, body)
}

// Set the value for a key.
func (client *Client) Set(vb uint16, key string, flags int, exp int,
	body []byte) (*gomemcached.MCResponse, error) {
	return client.store(gomemcached.SET, vb, key, flags, exp, body)
}

// Get keys in bulk
func (client *Client) GetBulk(vb uint16, keys []string) (map[string]*gomemcached.MCResponse, error) {
	terminalOpaque := uint32(len(keys) + 5)
	rv := map[string]*gomemcached.MCResponse{}
	wg := sync.WaitGroup{}
	going := true

	defer func() {
		going = false
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		for going {
			res, err := client.Receive()
			if err != nil {
				return
			}
			if res.Opaque == terminalOpaque {
				return
			}
			if res.Opcode != gomemcached.GETQ {
				log.Panicf("Unexpected opcode in GETQ response: %+v",
					res)
			}
			rv[keys[res.Opaque]] = res
		}
	}()

	for i, k := range keys {
		err := client.Transmit(&gomemcached.MCRequest{
			Opcode:  gomemcached.GETQ,
			VBucket: vb,
			Key:     []byte(k),
			Cas:     0,
			Opaque:  uint32(i),
			Extras:  []byte{},
			Body:    []byte{}})
		if err != nil {
			return rv, err
		}
	}

	err := client.Transmit(&gomemcached.MCRequest{
		Opcode: gomemcached.NOOP,
		Key:    []byte{},
		Cas:    0,
		Extras: []byte{},
		Body:   []byte{},
		Opaque: terminalOpaque})
	if err != nil {
		return rv, err
	}

	wg.Wait()

	return rv, nil
}

// A function to perform a CAS transform
type CasFunc func(current []byte) []byte

// Perform a CAS transform with the given function.
//
// If the value does not exist, an empty byte string will be sent to f
func (client *Client) CAS(vb uint16, k string, f CasFunc,
	initexp int) (rv *gomemcached.MCResponse, err error) {

	flags := 0
	exp := 0

	for {
		orig, err := client.Get(vb, k)
		if err != nil && orig != nil && orig.Status != gomemcached.KEY_ENOENT {
			return rv, err
		}

		if orig.Status == gomemcached.KEY_ENOENT {
			init := f([]byte{})
			// If it doesn't exist, add it
			resp, err := client.Add(vb, k, 0, initexp, init)
			if err == nil && resp.Status != gomemcached.KEY_EEXISTS {
				return rv, err
			}
			// Copy the body into this response.
			resp.Body = init
			return resp, err
		} else {
			req := &gomemcached.MCRequest{
				Opcode:  gomemcached.SET,
				VBucket: vb,
				Key:     []byte(k),
				Cas:     orig.Cas,
				Opaque:  0,
				Extras:  []byte{0, 0, 0, 0, 0, 0, 0, 0},
				Body:    f(orig.Body)}

			binary.BigEndian.PutUint64(req.Extras, uint64(flags)<<32|uint64(exp))
			resp, err := client.Send(req)
			if err == nil {
				return resp, nil
			}
		}
	}
	panic("Unreachable")
}

// Stats returns a slice of these.
type StatValue struct {
	// The stat key
	Key string
	// The stat value
	Val string
}

// Get stats from the server
// use "" as the stat key for toplevel stats.
func (client *Client) Stats(key string) ([]StatValue, error) {
	rv := make([]StatValue, 0, 128)

	req := &gomemcached.MCRequest{
		Opcode:  gomemcached.STAT,
		VBucket: 0,
		Key:     []byte(key),
		Cas:     0,
		Opaque:  918494,
		Extras:  []byte{}}

	err := transmitRequest(client.conn, req)
	if err != nil {
		return rv, err
	}

	for {
		res, err := getResponse(client.conn, client.hdrBuf)
		if err != nil {
			return rv, err
		}
		k := string(res.Key)
		if k == "" {
			break
		}
		rv = append(rv, StatValue{
			Key: k,
			Val: string(res.Body),
		})
	}

	return rv, nil
}

// Get the stats from the server as a map
func (client *Client) StatsMap(key string) (map[string]string, error) {
	rv := make(map[string]string)
	st, err := client.Stats(key)
	if err != nil {
		return rv, err
	}
	for _, sv := range st {
		rv[sv.Key] = sv.Val
	}
	return rv, nil
}

func getResponse(s io.Reader, buf []byte) (rv *gomemcached.MCResponse, err error) {
	_, err = io.ReadFull(s, buf)
	if err != nil {
		return rv, err
	}
	rv, err = grokHeader(buf)
	if err != nil {
		return rv, err
	}
	err = readContents(s, rv)
	return rv, err
}

func readContents(s io.Reader, res *gomemcached.MCResponse) error {
	if len(res.Extras) > 0 {
		_, err := io.ReadFull(s, res.Extras)
		if err != nil {
			return err
		}
	}
	if len(res.Key) > 0 {
		_, err := io.ReadFull(s, res.Key)
		if err != nil {
			return err
		}
	}
	_, err := io.ReadFull(s, res.Body)
	return err
}

func grokHeader(hdrBytes []byte) (rv *gomemcached.MCResponse, err error) {
	if hdrBytes[0] != gomemcached.RES_MAGIC {
		return rv, fmt.Errorf("Bad magic: 0x%02x", hdrBytes[0])
	}
	rv = &gomemcached.MCResponse{
		Opcode: gomemcached.CommandCode(hdrBytes[1]),
		Key:    make([]byte, binary.BigEndian.Uint16(hdrBytes[2:4])),
		Extras: make([]byte, hdrBytes[4]),
		Status: gomemcached.Status(binary.BigEndian.Uint16(hdrBytes[6:8])),
		Opaque: binary.BigEndian.Uint32(hdrBytes[12:16]),
		Cas:    binary.BigEndian.Uint64(hdrBytes[16:24]),
	}
	bodyLen := binary.BigEndian.Uint32(hdrBytes[8:12]) -
		uint32(len(rv.Key)+len(rv.Extras))
	rv.Body = make([]byte, bodyLen)

	return
}

func transmitRequest(o io.Writer, req *gomemcached.MCRequest) (err error) {
	if len(req.Body) < 128 {
		_, err = o.Write(req.Bytes())
	} else {
		_, err = o.Write(req.HeaderBytes())
		if err == nil && len(req.Body) > 0 {
			_, err = o.Write(req.Body)
		}
	}
	return
}
<|endoftext|>


<commit_before>package plugin

import (
	"regexp"

	"code.cloudfoundry.org/cli/integration/helpers"
	"code.cloudfoundry.org/cli/util/configv3"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("plugin API", func() {
	BeforeEach(func() {
		installTestPlugin()
	})

	AfterEach(func() {
		uninstallTestPlugin()
	})

	Describe("AccessToken", func() {
		It("returns the access token", func() {
			confirmTestPluginOutput("AccessToken", `bearer [\w\d\.]+`)
		})
	})

	Describe("ApiEndpoint", func() {
		It("returns the API endpoint", func() {
			confirmTestPluginOutput("ApiEndpoint", apiURL)
		})
	})

	Describe("GetApp", func() {
		var appName string
		BeforeEach(func() {
			createTargetedOrgAndSpace()
			appName = helpers.PrefixedRandomName("APP")
			helpers.WithHelloWorldApp(func(appDir string) {
				Eventually(helpers.CF("push", appName, "--no-start", "-p", appDir, "-b", "staticfile_buildpack", "--no-route")).Should(Exit(0))
			})
		})

		It("gets application information", func() {
			confirmTestPluginOutputWithArg("GetApp", appName, appName)
		})
	})

	Describe("GetApps", func() {
		var appName [2]string
		BeforeEach(func() {
			createTargetedOrgAndSpace()
			// Verify apps come back in order of creation, not alphabetically
			appName[0] = "Z" + helpers.PrefixedRandomName("APP")
			appName[1] = "A" + helpers.PrefixedRandomName("APP")
			helpers.WithHelloWorldApp(func(appDir string) {
				Eventually(helpers.CF("push", appName[0], "--no-start", "-p", appDir, "-b", "staticfile_buildpack", "--no-route")).Should(Exit(0))
			})
			helpers.WithHelloWorldApp(func(appDir string) {
				Eventually(helpers.CF("push", appName[1], "--no-start", "-p", appDir, "-b", "staticfile_buildpack", "--no-route")).Should(Exit(0))
			})
		})

		It("gets application information", func() {
			confirmTestPluginOutputWithArg("GetApps", appName[0], appName[1])
		})
	})

	Describe("GetOrg", func() {
		var orgName string
		var orgGUID string
		var domainName string
		var domain helpers.Domain

		BeforeEach(func() {
			orgName = helpers.NewOrgName()
			helpers.CreateOrg(orgName)
			helpers.TargetOrg(orgName)
			orgGUID = helpers.GetOrgGUID(orgName)

			domainName = helpers.DomainName("get-org-test")
			domain = helpers.NewDomain(orgName, domainName)
			domain.Create()
		})

		AfterEach(func() {
			domain.Delete()
		})

		It("gets the organization information", func() {
			confirmTestPluginOutputWithArg("GetOrg", orgName, orgName, orgGUID, domainName)
		})

		When("the org has metadata", func() {
			BeforeEach(func() {
				Eventually(helpers.CF("set-label", "org", orgName, "orgType=production")).Should(Exit(0))
			})
			It("Displays the metadata correctly", func() {
				confirmTestPluginOutputWithArg("GetOrg", orgName, regexp.QuoteMeta("labels:map[orgType:{Value:production"))
			})
		})

		When("the org does not exist", func() {
			It("Displays a useful error message", func() {
				confirmTestPluginOutputWithArg("GetOrg", "blahblahblah", "Error GetOrg: Organization 'blahblahblah' not found")
			})
		})
	})

	Describe("GetSpace", func() {
		var orgName string
		var spaceName string
		var spaceGUID string

		BeforeEach(func() {
			orgName = helpers.NewOrgName()
			spaceName = helpers.NewSpaceName()
			helpers.CreateOrgAndSpace(orgName, spaceName)
			helpers.TargetOrg(orgName)
			spaceGUID = helpers.GetSpaceGUID(spaceName)
		})
		AfterEach(func() {
			helpers.QuickDeleteOrg(orgName)
		})

		It("gets the space information", func() {
			confirmTestPluginOutputWithArg("GetSpace", spaceName, spaceGUID)
		})

		When("the space has metadata", func() {
			BeforeEach(func() {
				Eventually(helpers.CF("set-label", "space", spaceName, "spaceType=production")).Should(Exit(0))
			})
			It("Displays the metadata correctly", func() {
				confirmTestPluginOutputWithArg("GetSpace", spaceName, "spaceType", "production")
			})
		})

		When("the space does not exist", func() {
			It("Displays a useful error message", func() {
				confirmTestPluginOutputWithArg("GetSpace", "blahblahblah", "Error GetSpace: Space 'blahblahblah' not found")
			})
		})
	})

	Describe("GetCurrentSpace", func() {
		It("gets the current targeted Space", func() {
			_, space := createTargetedOrgAndSpace()
			confirmTestPluginOutput("GetCurrentSpace", space)
		})
	})

	Describe("GetCurrentOrg", func() {
		It("gets the current targeted Org", func() {
			org, _ := createTargetedOrgAndSpace()
			confirmTestPluginOutput("GetCurrentOrg", org)
		})
	})

	Describe("IsLoggedIn", func() {
		When("logged in", func() {
			It("returns true", func() {
				confirmTestPluginOutput("IsLoggedIn", "true")
			})
		})
		When("logged out", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
			})
			It("returns false", func() {
				confirmTestPluginOutput("IsLoggedIn", "false")
			})
		})
	})

	Describe("Username", func() {
		It("gets the current user's name", func() {
			username := getUsername()
			confirmTestPluginOutput("Username", username)
		})

		When("not logged in", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
			})
			It("returns an error", func() {
				confirmTestPluginOutput("Username", "not logged in")
			})
		})

		When("the token is invalid", func() {
			var accessToken string

			BeforeEach(func() {
				helpers.SetConfig(func(config *configv3.Config) {
					accessToken = config.ConfigFile.AccessToken
					config.ConfigFile.AccessToken = accessToken + "***"
				})
			})
			AfterEach(func() {
				helpers.SetConfig(func(config *configv3.Config) {
					config.ConfigFile.AccessToken = accessToken
				})
			})

			When("running a v7 plugin command", func() {
				It("complains about the token", func() {
					session := helpers.CF("Username")
					Eventually(session).Should(Say("illegal base64 data at input byte 342"))
				})
			})
		})
	})

	Describe("IsSkipSSLValidation", func() {
		When("--skip-ssl-validation is not specified", func() {
			BeforeEach(func() {
				if helpers.SkipSSLValidation() {
					Skip("Test is being run with skip ssl validation")
				}
			})
			It("returns false", func() {
				confirmTestPluginOutput("IsSkipSSLValidation", "false")
			})
		})
		When("--skip-ssl-validation is specified", func() {
			BeforeEach(func() {
				Eventually(helpers.CF("api", apiURL, "--skip-ssl-validation")).Should(Exit(0))
			})
			It("returns true", func() {
				confirmTestPluginOutput("IsSkipSSLValidation", "true")
			})
		})
	})

})
<commit_msg>Rollback accidental change Labels vs labels<commit_after>package plugin

import (
	"regexp"

	"code.cloudfoundry.org/cli/integration/helpers"
	"code.cloudfoundry.org/cli/util/configv3"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("plugin API", func() {
	BeforeEach(func() {
		installTestPlugin()
	})

	AfterEach(func() {
		uninstallTestPlugin()
	})

	Describe("AccessToken", func() {
		It("returns the access token", func() {
			confirmTestPluginOutput("AccessToken", `bearer [\w\d\.]+`)
		})
	})

	Describe("ApiEndpoint", func() {
		It("returns the API endpoint", func() {
			confirmTestPluginOutput("ApiEndpoint", apiURL)
		})
	})

	Describe("GetApp", func() {
		var appName string
		BeforeEach(func() {
			createTargetedOrgAndSpace()
			appName = helpers.PrefixedRandomName("APP")
			helpers.WithHelloWorldApp(func(appDir string) {
				Eventually(helpers.CF("push", appName, "--no-start", "-p", appDir, "-b", "staticfile_buildpack", "--no-route")).Should(Exit(0))
			})
		})

		It("gets application information", func() {
			confirmTestPluginOutputWithArg("GetApp", appName, appName)
		})
	})

	Describe("GetApps", func() {
		var appName [2]string
		BeforeEach(func() {
			createTargetedOrgAndSpace()
			// Verify apps come back in order of creation, not alphabetically
			appName[0] = "Z" + helpers.PrefixedRandomName("APP")
			appName[1] = "A" + helpers.PrefixedRandomName("APP")
			helpers.WithHelloWorldApp(func(appDir string) {
				Eventually(helpers.CF("push", appName[0], "--no-start", "-p", appDir, "-b", "staticfile_buildpack", "--no-route")).Should(Exit(0))
			})
			helpers.WithHelloWorldApp(func(appDir string) {
				Eventually(helpers.CF("push", appName[1], "--no-start", "-p", appDir, "-b", "staticfile_buildpack", "--no-route")).Should(Exit(0))
			})
		})

		It("gets application information", func() {
			confirmTestPluginOutputWithArg("GetApps", appName[0], appName[1])
		})
	})

	Describe("GetOrg", func() {
		var orgName string
		var orgGUID string
		var domainName string
		var domain helpers.Domain

		BeforeEach(func() {
			orgName = helpers.NewOrgName()
			helpers.CreateOrg(orgName)
			helpers.TargetOrg(orgName)
			orgGUID = helpers.GetOrgGUID(orgName)

			domainName = helpers.DomainName("get-org-test")
			domain = helpers.NewDomain(orgName, domainName)
			domain.Create()
		})

		AfterEach(func() {
			domain.Delete()
		})

		It("gets the organization information", func() {
			confirmTestPluginOutputWithArg("GetOrg", orgName, orgName, orgGUID, domainName)
		})

		When("the org has metadata", func() {
			BeforeEach(func() {
				Eventually(helpers.CF("set-label", "org", orgName, "orgType=production")).Should(Exit(0))
			})
			It("Displays the metadata correctly", func() {
				confirmTestPluginOutputWithArg("GetOrg", orgName, regexp.QuoteMeta("Labels:map[orgType:{Value:production"))
			})
		})

		When("the org does not exist", func() {
			It("Displays a useful error message", func() {
				confirmTestPluginOutputWithArg("GetOrg", "blahblahblah", "Error GetOrg: Organization 'blahblahblah' not found")
			})
		})
	})

	Describe("GetSpace", func() {
		var orgName string
		var spaceName string
		var spaceGUID string

		BeforeEach(func() {
			orgName = helpers.NewOrgName()
			spaceName = helpers.NewSpaceName()
			helpers.CreateOrgAndSpace(orgName, spaceName)
			helpers.TargetOrg(orgName)
			spaceGUID = helpers.GetSpaceGUID(spaceName)
		})
		AfterEach(func() {
			helpers.QuickDeleteOrg(orgName)
		})

		It("gets the space information", func() {
			confirmTestPluginOutputWithArg("GetSpace", spaceName, spaceGUID)
		})

		When("the space has metadata", func() {
			BeforeEach(func() {
				Eventually(helpers.CF("set-label", "space", spaceName, "spaceType=production")).Should(Exit(0))
			})
			It("Displays the metadata correctly", func() {
				confirmTestPluginOutputWithArg("GetSpace", spaceName, "spaceType", "production")
			})
		})

		When("the space does not exist", func() {
			It("Displays a useful error message", func() {
				confirmTestPluginOutputWithArg("GetSpace", "blahblahblah", "Error GetSpace: Space 'blahblahblah' not found")
			})
		})
	})

	Describe("GetCurrentSpace", func() {
		It("gets the current targeted Space", func() {
			_, space := createTargetedOrgAndSpace()
			confirmTestPluginOutput("GetCurrentSpace", space)
		})
	})

	Describe("GetCurrentOrg", func() {
		It("gets the current targeted Org", func() {
			org, _ := createTargetedOrgAndSpace()
			confirmTestPluginOutput("GetCurrentOrg", org)
		})
	})

	Describe("IsLoggedIn", func() {
		When("logged in", func() {
			It("returns true", func() {
				confirmTestPluginOutput("IsLoggedIn", "true")
			})
		})
		When("logged out", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
			})
			It("returns false", func() {
				confirmTestPluginOutput("IsLoggedIn", "false")
			})
		})
	})

	Describe("Username", func() {
		It("gets the current user's name", func() {
			username := getUsername()
			confirmTestPluginOutput("Username", username)
		})

		When("not logged in", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
			})
			It("returns an error", func() {
				confirmTestPluginOutput("Username", "not logged in")
			})
		})

		When("the token is invalid", func() {
			var accessToken string

			BeforeEach(func() {
				helpers.SetConfig(func(config *configv3.Config) {
					accessToken = config.ConfigFile.AccessToken
					config.ConfigFile.AccessToken = accessToken + "***"
				})
			})
			AfterEach(func() {
				helpers.SetConfig(func(config *configv3.Config) {
					config.ConfigFile.AccessToken = accessToken
				})
			})

			When("running a v7 plugin command", func() {
				It("complains about the token", func() {
					session := helpers.CF("Username")
					Eventually(session).Should(Say("illegal base64 data at input byte 342"))
				})
			})
		})
	})

	Describe("IsSkipSSLValidation", func() {
		When("--skip-ssl-validation is not specified", func() {
			BeforeEach(func() {
				if helpers.SkipSSLValidation() {
					Skip("Test is being run with skip ssl validation")
				}
			})
			It("returns false", func() {
				confirmTestPluginOutput("IsSkipSSLValidation", "false")
			})
		})
		When("--skip-ssl-validation is specified", func() {
			BeforeEach(func() {
				Eventually(helpers.CF("api", apiURL, "--skip-ssl-validation")).Should(Exit(0))
			})
			It("returns true", func() {
				confirmTestPluginOutput("IsSkipSSLValidation", "true")
			})
		})
	})

})
<|endoftext|>


<commit_before>/*
Copyright 2020 The Ceph-CSI Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller

import (
	"fmt"

	"github.com/ceph/ceph-csi/internal/util/log"

	clientConfig "sigs.k8s.io/controller-runtime/pkg/client/config"
	"sigs.k8s.io/controller-runtime/pkg/manager"
	"sigs.k8s.io/controller-runtime/pkg/manager/signals"
)

// Manager is the interface that will wrap Add function.
// The New controllers which gets added, as to implement Add function to get
// started by the manager.
type Manager interface {
	Add(manager.Manager, Config) error
}

// Config holds the drivername and namespace name.
type Config struct {
	DriverName string
	Namespace  string
}

// ControllerList holds the list of managers need to be started.
var ControllerList []Manager

// addToManager calls the registered managers Add method.
func addToManager(mgr manager.Manager, config Config) error {
	for _, c := range ControllerList {
		err := c.Add(mgr, config)
		if err != nil {
			return fmt.Errorf("failed to add: %w", err)
		}
	}

	return nil
}

// Start will start all the registered managers.
func Start(config Config) error {
	electionID := config.DriverName + "-" + config.Namespace
	opts := manager.Options{
		LeaderElection: true,
		// disable metrics
		MetricsBindAddress:      "0",
		LeaderElectionNamespace: config.Namespace,
		LeaderElectionID:        electionID,
	}
	mgr, err := manager.New(clientConfig.GetConfigOrDie(), opts)
	if err != nil {
		log.ErrorLogMsg("failed to create manager %s", err)

		return err
	}
	err = addToManager(mgr, config)
	if err != nil {
		log.ErrorLogMsg("failed to add manager %s", err)

		return err
	}
	err = mgr.Start(signals.SetupSignalHandler())
	if err != nil {
		log.ErrorLogMsg("failed to start manager %s", err)
	}

	return err
}
<commit_msg>rbd: use leases for leader election<commit_after>/*
Copyright 2020 The Ceph-CSI Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller

import (
	"fmt"

	"github.com/ceph/ceph-csi/internal/util/log"

	"k8s.io/client-go/tools/leaderelection/resourcelock"
	clientConfig "sigs.k8s.io/controller-runtime/pkg/client/config"
	"sigs.k8s.io/controller-runtime/pkg/manager"
	"sigs.k8s.io/controller-runtime/pkg/manager/signals"
)

// Manager is the interface that will wrap Add function.
// The New controllers which gets added, as to implement Add function to get
// started by the manager.
type Manager interface {
	Add(manager.Manager, Config) error
}

// Config holds the drivername and namespace name.
type Config struct {
	DriverName string
	Namespace  string
}

// ControllerList holds the list of managers need to be started.
var ControllerList []Manager

// addToManager calls the registered managers Add method.
func addToManager(mgr manager.Manager, config Config) error {
	for _, c := range ControllerList {
		err := c.Add(mgr, config)
		if err != nil {
			return fmt.Errorf("failed to add: %w", err)
		}
	}

	return nil
}

// Start will start all the registered managers.
func Start(config Config) error {
	electionID := config.DriverName + "-" + config.Namespace
	opts := manager.Options{
		LeaderElection: true,
		// disable metrics
		MetricsBindAddress:         "0",
		LeaderElectionNamespace:    config.Namespace,
		LeaderElectionResourceLock: resourcelock.LeasesResourceLock,
		LeaderElectionID:           electionID,
	}
	mgr, err := manager.New(clientConfig.GetConfigOrDie(), opts)
	if err != nil {
		log.ErrorLogMsg("failed to create manager %s", err)

		return err
	}
	err = addToManager(mgr, config)
	if err != nil {
		log.ErrorLogMsg("failed to add manager %s", err)

		return err
	}
	err = mgr.Start(signals.SetupSignalHandler())
	if err != nil {
		log.ErrorLogMsg("failed to start manager %s", err)
	}

	return err
}
<|endoftext|>


<commit_before>package transport

import (
	"fmt"
	"syscall"
	"time"

	"github.com/linuxkit/virtsock/pkg/vsock"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

//nolint:deadcode,varcheck
const (
	vmaddrCidHost = 2
	vmaddrCidAny  = 0xffffffff
)

// VsockTransport is an implementation of Transport which uses vsock
// sockets.
type VsockTransport struct{}

var _ Transport = &VsockTransport{}

// Dial accepts a vsock socket port number as configuration, and
// returns an unconnected VsockConnection struct.
func (t *VsockTransport) Dial(port uint32) (Connection, error) {
	logrus.WithFields(logrus.Fields{
		"port": port,
	}).Info("opengcs::VsockTransport::Dial - vsock dial port")

	// HACK: Remove loop when vsock bugs are fixed!
	// Retry 10 times because vsock.Dial can return connection time out
	// due to some underlying kernel bug.
	for i := 0; i < 10; i++ {
		conn, err := vsock.Dial(vmaddrCidHost, port)
		if err == nil {
			return conn, nil
		}
		// If the error was ETIMEDOUT retry, otherwise fail.
		cause := errors.Cause(err)
		if errno, ok := cause.(syscall.Errno); ok && errno == syscall.ETIMEDOUT {
			time.Sleep(100 * time.Millisecond)
			continue
		} else {
			return nil, errors.Wrapf(err, "vsock Dial port (%d) failed", port)
		}
	}
	return nil, fmt.Errorf("failed connecting the VsockConnection: can't connect after 10 attempts")
}
<commit_msg>Put Linux build tag on /internal/guest/transport/vsock.go (#1301)<commit_after>//go:build linux
// +build linux

package transport

import (
	"fmt"
	"syscall"
	"time"

	"github.com/linuxkit/virtsock/pkg/vsock"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

//nolint:deadcode,varcheck
const (
	vmaddrCidHost = 2
	vmaddrCidAny  = 0xffffffff
)

// VsockTransport is an implementation of Transport which uses vsock
// sockets.
type VsockTransport struct{}

var _ Transport = &VsockTransport{}

// Dial accepts a vsock socket port number as configuration, and
// returns an unconnected VsockConnection struct.
func (t *VsockTransport) Dial(port uint32) (Connection, error) {
	logrus.WithFields(logrus.Fields{
		"port": port,
	}).Info("opengcs::VsockTransport::Dial - vsock dial port")

	// HACK: Remove loop when vsock bugs are fixed!
	// Retry 10 times because vsock.Dial can return connection time out
	// due to some underlying kernel bug.
	for i := 0; i < 10; i++ {
		conn, err := vsock.Dial(vmaddrCidHost, port)
		if err == nil {
			return conn, nil
		}
		// If the error was ETIMEDOUT retry, otherwise fail.
		cause := errors.Cause(err)
		if errno, ok := cause.(syscall.Errno); ok && errno == syscall.ETIMEDOUT {
			time.Sleep(100 * time.Millisecond)
			continue
		} else {
			return nil, errors.Wrapf(err, "vsock Dial port (%d) failed", port)
		}
	}
	return nil, fmt.Errorf("failed connecting the VsockConnection: can't connect after 10 attempts")
}
<|endoftext|>