<commit_before>package moves

import (
	"errors"
	"github.com/jkomoros/boardgame"
	"github.com/jkomoros/boardgame/moves/moveinterfaces"
	"strconv"
	"sync"
)

//go:generate autoreader

//game.Name() to set of move types that are always legal
var alwaysLegalMoveTypesByGame map[string]map[string]bool
var alwaysLegalMoveTypesMutex sync.RWMutex

func init() {
	alwaysLegalMoveTypesMutex.Lock()
	alwaysLegalMoveTypesByGame = make(map[string]map[string]bool)
	alwaysLegalMoveTypesMutex.Unlock()
}

/*
Base is an optional, convenience struct designed to be embedded
anonymously in your own Moves. It implements no-op methods for many of the
required methods on Moves. Apply is not covered, because every Move
should implement their own, and if this implemented them it would obscure
errors where for example your Apply() was incorrectly named and thus not used.
In general your MoveConstructor can always be exactly the same, modulo the
name of your underlying move type:

	MoveConstructor: func() boardgame.Move {
 		return new(myMoveStruct)
	}

Base's Legal() method does basic checking for whehter the move is legal in
this phase, so your own Legal() method should always call Base.Legal() at the
top of its own method.

It is extremely rare to not use moves.Base either directly, or implicitly
within another sub-class in your move.

Base cannot help your move implement PropertyReadSetter; use autoreader to
generate that code for you.

*/
type Base struct {
	info           *boardgame.MoveInfo
	topLevelStruct boardgame.Move
}

func (d *Base) SetInfo(m *boardgame.MoveInfo) {
	d.info = m
}

//Type simply returns BaseMove.MoveInfo
func (d *Base) Info() *boardgame.MoveInfo {
	return d.info
}

func (d *Base) SetTopLevelStruct(m boardgame.Move) {
	d.topLevelStruct = m
}

//TopLevelStruct returns the object that was set via SetTopLevelStruct.
func (d *Base) TopLevelStruct() boardgame.Move {
	return d.topLevelStruct
}

//DefaultsForState doesn't do anything
func (d *Base) DefaultsForState(state boardgame.State) {
	return
}

//Description defaults to returning the Type's HelpText()
func (d *Base) Description() string {
	return d.Info().Type().HelpText()
}

//ValidConfiguration always returns nil because there is no required
//configuration for moves.Base.
func (d *Base) ValidConfiguration(exampleState boardgame.MutableState) error {
	return nil
}

//Legal checks whether the game's CurrentPhase (as determined by the delegate)
//is one of the LegalPhases for this moveType. A zero-length LegalPhases is
//interpreted as the move being legal in all phases. The string for the
//current phase will be based on the enum value of the PhaseEnum named by
//delegate.PhaseEnumName(), if it exists. Next, it checks to see if the give
//move is at a legal point in the move progression for this phase, if it
//exists. Each move in the move progression must show up 1 or more times. The
//method checks to see if we were to make this move, would the moves since the
//last phase change match the pattern? If your move can be made legally
//multiple times in a row in a given move progression, implement
//moveinterfaces.AllowMultipleInProgression() and return true.
func (d *Base) Legal(state boardgame.State, proposer boardgame.PlayerIndex) error {

	if err := d.legalInPhase(state); err != nil {
		return err
	}

	return d.legalMoveInProgression(state, proposer)

}

//legalInPhase will return a descriptive error if this move is not legal in
//the current phase of hte game.
func (d *Base) legalInPhase(state boardgame.State) error {

	legalPhases := d.Info().Type().LegalPhases()

	if len(legalPhases) == 0 {
		return nil
	}

	currentPhase := state.Game().Manager().Delegate().CurrentPhase(state)

	for _, phase := range legalPhases {
		if phase == currentPhase {
			return nil
		}
	}

	phaseName := strconv.Itoa(currentPhase)

	if phaseEnum := state.Game().Manager().Delegate().PhaseEnum(); phaseEnum != nil {
		phaseName = phaseEnum.String(currentPhase)
	}

	return errors.New("Move is not legal in phase " + phaseName)
}

func (d *Base) historicalMovesSincePhaseTransition(game *boardgame.Game, upToVersion int) []*boardgame.MoveStorageRecord {

	moves := game.MoveRecords(upToVersion)

	//TODO: ideally we'd memoize this so all base moves for this game for this
	//version could use the result. If we do that, we'll want to make sure the
	//lifetime of the cache does not extend beyond the lifetime of the game,
	//or is purged every so often.

	if len(moves) == 0 {
		return nil
	}

	alwaysLegalMoveTypesMutex.RLock()
	alwaysLegalMoveTypes, ok := alwaysLegalMoveTypesByGame[game.Name()]
	alwaysLegalMoveTypesMutex.RUnlock()

	if !ok {

		alwaysLegalMoveTypes = make(map[string]bool)

		//Create the list!
		for _, fixUpMove := range game.Manager().FixUpMoveTypes() {
			if len(fixUpMove.LegalPhases()) == 0 {
				alwaysLegalMoveTypes[fixUpMove.Name()] = true
			}
		}

		alwaysLegalMoveTypesMutex.Lock()
		alwaysLegalMoveTypesByGame[game.Name()] = alwaysLegalMoveTypes
		alwaysLegalMoveTypesMutex.Unlock()
	}

	var keptMoves []*boardgame.MoveStorageRecord

	targetPhase := moves[len(moves)-1].Phase

	for i := len(moves) - 1; i >= 0; i-- {
		move := moves[i]

		if alwaysLegalMoveTypes[move.Name] {
			//We skip move types that are always legal for the purposes of
			//matching.
			continue
		}

		if move.Phase != targetPhase {
			//Must have fallen off the end of the current phase's most recent run
			break
		}

		keptMoves = append(keptMoves, move)
	}

	//keptMoves is backwards, reverse it.

	moves = nil

	for i := len(keptMoves) - 1; i >= 0; i-- {
		moves = append(moves, keptMoves[i])
	}

	return moves

}

func (d *Base) legalMoveInProgression(state boardgame.State, proposer boardgame.PlayerIndex) error {
	currentPhase := state.Game().Manager().Delegate().CurrentPhase(state)

	pattern := state.Game().Manager().Delegate().PhaseMoveProgression(currentPhase)

	//If there is no legal move progression then moves are legal in the phase at any time
	if pattern == nil {
		return nil
	}

	historicalMoves := d.historicalMovesSincePhaseTransition(state.Game(), state.Version())

	progression := make([]string, len(historicalMoves))

	for i, move := range historicalMoves {
		progression[i] = move.Name
	}

	//If we were to add our target move to the historical progression, would it match the pattern?
	if !progressionMatches(append(progression, d.Info().Type().Name()), pattern) {
		return errors.New("This move is not legal at this point in the current phase.")
	}

	//Are we a new type of move in the progression? if so, is the move before
	//us still legal?

	if len(historicalMoves) == 0 {
		//We're the first move, it's fine.
		return nil
	}

	lastMoveRecord := historicalMoves[len(historicalMoves)-1]

	if lastMoveRecord.Name == d.Info().Type().Name() {

		//We're applying multiple in a row. Is that legal?

		//We can't check ourselves because we're embedded in the real move type.
		testMove := d.TopLevelStruct()

		allowMultiple, ok := testMove.(moveinterfaces.AllowMultipleInProgression)

		if !ok || !allowMultiple.AllowMultipleInProgression() {
			return errors.New("This move was just applied and is not configured to allow multiple in a row in this phase.")
		}

		return nil
	}

	lastMoveType := state.Game().Manager().FixUpMoveTypeByName(lastMoveRecord.Name)

	if lastMoveType == nil {
		lastMoveType = state.Game().Manager().PlayerMoveTypeByName(lastMoveRecord.Name)
	}

	if lastMoveType == nil {
		return errors.New("Unexpected error: couldn't find a historical move type")
	}

	//LastMove will have all of the defaults set.
	lastMove := lastMoveType.NewMove(state)

	if lastMove.Legal(state, proposer) == nil {
		return errors.New("A move that needs to happen earlier in the phase is still legal to apply.")
	}

	return nil

}

//progressionMatches returns true if the given history matches the pattern.
func progressionMatches(input []string, pattern []string) bool {

	inputPosition := 0
	patternPosition := 0

	for inputPosition < len(input) {

		inputItem := input[inputPosition]
		patternItem := pattern[patternPosition]

		if inputItem != patternItem {
			//Perhaps we just passed to the next part of the pattern?

			//that's not legal at the very front of input
			if inputPosition == 0 {
				return false
			}

			patternPosition++

			if patternPosition >= len(pattern) {
				//No more pattern, I guess we didn't match.
				return false
			}

			patternItem = pattern[patternPosition]

			if inputItem != patternItem {
				//Nope, we didn't match the next part of the pattern, we just don't match
				return false
			}

		}

		inputPosition++

	}

	//If we got to the end of the input without invalidating then it passes.
	return true

}
<commit_msg>Actually as of last commit, we needed to change how legaMoveInPhaseProgression worked. This is that commit. Part of #516.<commit_after>package moves

import (
	"errors"
	"github.com/jkomoros/boardgame"
	"github.com/jkomoros/boardgame/moves/moveinterfaces"
	"strconv"
	"sync"
)

//go:generate autoreader

//game.Name() to set of move types that are always legal
var alwaysLegalMoveTypesByGame map[string]map[string]bool
var alwaysLegalMoveTypesMutex sync.RWMutex

func init() {
	alwaysLegalMoveTypesMutex.Lock()
	alwaysLegalMoveTypesByGame = make(map[string]map[string]bool)
	alwaysLegalMoveTypesMutex.Unlock()
}

/*
Base is an optional, convenience struct designed to be embedded
anonymously in your own Moves. It implements no-op methods for many of the
required methods on Moves. Apply is not covered, because every Move
should implement their own, and if this implemented them it would obscure
errors where for example your Apply() was incorrectly named and thus not used.
In general your MoveConstructor can always be exactly the same, modulo the
name of your underlying move type:

	MoveConstructor: func() boardgame.Move {
 		return new(myMoveStruct)
	}

Base's Legal() method does basic checking for whehter the move is legal in
this phase, so your own Legal() method should always call Base.Legal() at the
top of its own method.

It is extremely rare to not use moves.Base either directly, or implicitly
within another sub-class in your move.

Base cannot help your move implement PropertyReadSetter; use autoreader to
generate that code for you.

*/
type Base struct {
	info           *boardgame.MoveInfo
	topLevelStruct boardgame.Move
}

func (d *Base) SetInfo(m *boardgame.MoveInfo) {
	d.info = m
}

//Type simply returns BaseMove.MoveInfo
func (d *Base) Info() *boardgame.MoveInfo {
	return d.info
}

func (d *Base) SetTopLevelStruct(m boardgame.Move) {
	d.topLevelStruct = m
}

//TopLevelStruct returns the object that was set via SetTopLevelStruct.
func (d *Base) TopLevelStruct() boardgame.Move {
	return d.topLevelStruct
}

//DefaultsForState doesn't do anything
func (d *Base) DefaultsForState(state boardgame.State) {
	return
}

//Description defaults to returning the Type's HelpText()
func (d *Base) Description() string {
	return d.Info().Type().HelpText()
}

//ValidConfiguration always returns nil because there is no required
//configuration for moves.Base.
func (d *Base) ValidConfiguration(exampleState boardgame.MutableState) error {
	return nil
}

//Legal checks whether the game's CurrentPhase (as determined by the delegate)
//is one of the LegalPhases for this moveType. A zero-length LegalPhases is
//interpreted as the move being legal in all phases. The string for the
//current phase will be based on the enum value of the PhaseEnum named by
//delegate.PhaseEnumName(), if it exists. Next, it checks to see if the give
//move is at a legal point in the move progression for this phase, if it
//exists. Each move in the move progression must show up 1 or more times. The
//method checks to see if we were to make this move, would the moves since the
//last phase change match the pattern? If your move can be made legally
//multiple times in a row in a given move progression, implement
//moveinterfaces.AllowMultipleInProgression() and return true.
func (d *Base) Legal(state boardgame.State, proposer boardgame.PlayerIndex) error {

	if err := d.legalInPhase(state); err != nil {
		return err
	}

	return d.legalMoveInProgression(state, proposer)

}

//legalInPhase will return a descriptive error if this move is not legal in
//the current phase of hte game.
func (d *Base) legalInPhase(state boardgame.State) error {

	legalPhases := d.Info().Type().LegalPhases()

	if len(legalPhases) == 0 {
		return nil
	}

	currentPhase := state.Game().Manager().Delegate().CurrentPhase(state)

	for _, phase := range legalPhases {
		if phase == currentPhase {
			return nil
		}
	}

	phaseName := strconv.Itoa(currentPhase)

	if phaseEnum := state.Game().Manager().Delegate().PhaseEnum(); phaseEnum != nil {
		phaseName = phaseEnum.String(currentPhase)
	}

	return errors.New("Move is not legal in phase " + phaseName)
}

func (d *Base) historicalMovesSincePhaseTransition(game *boardgame.Game, upToVersion int, targetPhase int) []*boardgame.MoveStorageRecord {

	moves := game.MoveRecords(upToVersion)

	//TODO: ideally we'd memoize this so all base moves for this game for this
	//version could use the result. If we do that, we'll want to make sure the
	//lifetime of the cache does not extend beyond the lifetime of the game,
	//or is purged every so often.

	if len(moves) == 0 {
		return nil
	}

	alwaysLegalMoveTypesMutex.RLock()
	alwaysLegalMoveTypes, ok := alwaysLegalMoveTypesByGame[game.Name()]
	alwaysLegalMoveTypesMutex.RUnlock()

	if !ok {

		alwaysLegalMoveTypes = make(map[string]bool)

		//Create the list!
		for _, fixUpMove := range game.Manager().FixUpMoveTypes() {
			if len(fixUpMove.LegalPhases()) == 0 {
				alwaysLegalMoveTypes[fixUpMove.Name()] = true
			}
		}

		alwaysLegalMoveTypesMutex.Lock()
		alwaysLegalMoveTypesByGame[game.Name()] = alwaysLegalMoveTypes
		alwaysLegalMoveTypesMutex.Unlock()
	}

	var keptMoves []*boardgame.MoveStorageRecord

	for i := len(moves) - 1; i >= 0; i-- {
		move := moves[i]

		if alwaysLegalMoveTypes[move.Name] {
			//We skip move types that are always legal for the purposes of
			//matching.
			continue
		}

		if move.Phase != targetPhase {
			//Must have fallen off the end of the current phase's most recent run
			break
		}

		keptMoves = append(keptMoves, move)
	}

	//keptMoves is backwards, reverse it.

	moves = nil

	for i := len(keptMoves) - 1; i >= 0; i-- {
		moves = append(moves, keptMoves[i])
	}

	return moves

}

func (d *Base) legalMoveInProgression(state boardgame.State, proposer boardgame.PlayerIndex) error {
	currentPhase := state.Game().Manager().Delegate().CurrentPhase(state)

	pattern := state.Game().Manager().Delegate().PhaseMoveProgression(currentPhase)

	//If there is no legal move progression then moves are legal in the phase at any time
	if pattern == nil {
		return nil
	}

	historicalMoves := d.historicalMovesSincePhaseTransition(state.Game(), state.Version(), currentPhase)

	progression := make([]string, len(historicalMoves))

	for i, move := range historicalMoves {
		progression[i] = move.Name
	}

	//If we were to add our target move to the historical progression, would it match the pattern?
	if !progressionMatches(append(progression, d.Info().Type().Name()), pattern) {
		return errors.New("This move is not legal at this point in the current phase.")
	}

	//Are we a new type of move in the progression? if so, is the move before
	//us still legal?

	if len(historicalMoves) == 0 {
		//We're the first move, it's fine.
		return nil
	}

	lastMoveRecord := historicalMoves[len(historicalMoves)-1]

	if lastMoveRecord.Name == d.Info().Type().Name() {

		//We're applying multiple in a row. Is that legal?

		//We can't check ourselves because we're embedded in the real move type.
		testMove := d.TopLevelStruct()

		allowMultiple, ok := testMove.(moveinterfaces.AllowMultipleInProgression)

		if !ok || !allowMultiple.AllowMultipleInProgression() {
			return errors.New("This move was just applied and is not configured to allow multiple in a row in this phase.")
		}

		return nil
	}

	lastMoveType := state.Game().Manager().FixUpMoveTypeByName(lastMoveRecord.Name)

	if lastMoveType == nil {
		lastMoveType = state.Game().Manager().PlayerMoveTypeByName(lastMoveRecord.Name)
	}

	if lastMoveType == nil {
		return errors.New("Unexpected error: couldn't find a historical move type")
	}

	//LastMove will have all of the defaults set.
	lastMove := lastMoveType.NewMove(state)

	if lastMove.Legal(state, proposer) == nil {
		return errors.New("A move that needs to happen earlier in the phase is still legal to apply.")
	}

	return nil

}

//progressionMatches returns true if the given history matches the pattern.
func progressionMatches(input []string, pattern []string) bool {

	inputPosition := 0
	patternPosition := 0

	for inputPosition < len(input) {

		inputItem := input[inputPosition]
		patternItem := pattern[patternPosition]

		if inputItem != patternItem {
			//Perhaps we just passed to the next part of the pattern?

			//that's not legal at the very front of input
			if inputPosition == 0 {
				return false
			}

			patternPosition++

			if patternPosition >= len(pattern) {
				//No more pattern, I guess we didn't match.
				return false
			}

			patternItem = pattern[patternPosition]

			if inputItem != patternItem {
				//Nope, we didn't match the next part of the pattern, we just don't match
				return false
			}

		}

		inputPosition++

	}

	//If we got to the end of the input without invalidating then it passes.
	return true

}
<|endoftext|>


<commit_before>// Copyright 2017 The LUCI 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 buildstore

import (
	"fmt"
	"net/http"
	"strconv"
	"strings"

	"golang.org/x/net/context"

	"go.chromium.org/luci/buildbucket"
	bbapi "go.chromium.org/luci/common/api/buildbucket/buildbucket/v1"
	"go.chromium.org/luci/common/data/strpair"
	"go.chromium.org/luci/common/errors"
	"go.chromium.org/luci/common/logging"
	"go.chromium.org/luci/logdog/common/types"
	"go.chromium.org/luci/milo/api/buildbot"
	"go.chromium.org/luci/milo/common"
	"go.chromium.org/luci/server/auth"
)

// This file implements conversion of buildbucket builds to buildbot builds.

// buildFromBuildbucket converts a buildbucket build to a buildbot build.
// If details is false, steps, text and properties are not guaranteed to be
// loaded.
//
// Does not populate OSFamily, OSVersion, Blame or SourceStamp.Changes
// fields.
func buildFromBuildbucket(c context.Context, master string, msg *bbapi.ApiCommonBuildMessage, fetchAnnotations bool) (*buildbot.Build, error) {
	var b buildbucket.Build
	if err := b.ParseMessage(msg); err != nil {
		return nil, err
	}
	num, err := buildNumber(&b)
	if err != nil {
		return nil, errors.Annotate(err, "parsing buildnumber").Err()
	}

	res := &buildbot.Build{
		Emulated:    true,
		Master:      master,
		Buildername: b.Builder,
		Number:      num,
		Results:     statusResult(b.Status),
		TimeStamp:   buildbot.Time{b.UpdateTime},
		Times: buildbot.TimeRange{
			Start:  buildbot.Time{b.StartTime},
			Finish: buildbot.Time{b.CompletionTime},
		},
		// TODO(nodir): use buildbucket access API when it is ready,
		// or, perhaps, just delete this code.
		// Note that this function should not be called on builds
		// that the requester does not have access to, in the first place.
		Internal:    b.Bucket != "luci.chromium.try",
		Finished:    b.Status.Completed(),
		Sourcestamp: &buildbot.SourceStamp{},
	}

	for _, bs := range b.BuildSets {
		if commit, ok := bs.(*buildbucket.GitilesCommit); ok {
			res.Sourcestamp.Repository = commit.RepoURL()
			res.Sourcestamp.Revision = commit.Revision
			break
		}
	}

	if fetchAnnotations && b.Status != buildbucket.StatusScheduled {
		addr, err := logLocation(&b)
		if err != nil {
			return nil, err
		}

		ann, err := fetchAnnotationProto(c, addr)
		switch {
		case err == errAnnotationNotFound:
		case err != nil:
			return nil, errors.Annotate(err, "could not load annotation proto").Err()
		default:
			res.Properties = extractProperties(ann)

			prefix, _ := addr.Path.Split()
			conv := annotationConverter{
				logdogServer:       addr.Host,
				logdogPrefix:       fmt.Sprintf("%s/%s", addr.Project, prefix),
				buildCompletedTime: b.CompletionTime,
			}
			convCtx := logging.SetField(c, "build_id", b.ID)
			conv.addSteps(convCtx, &res.Steps, ann.Substep, "")
			for i := range res.Steps {
				s := &res.Steps[i]
				s.StepNumber = i + 1
				res.Logs = append(res.Logs, s.Logs...)
				if !s.IsFinished {
					res.Currentstep = s.Name
				}
				if s.Results.Result != buildbot.Success {
					res.Text = append(res.Text, fmt.Sprintf("%s %s", s.Results.Result, s.Name))
				}
			}
		}
	}

	if len(res.Text) == 0 && b.Status == buildbucket.StatusSuccess {
		res.Text = []string{"Build successful"}
	}

	return res, nil
}

func buildbucketClient(c context.Context) (*bbapi.Service, error) {
	t, err := auth.GetRPCTransport(c, auth.AsUser)
	if err != nil {
		return nil, err
	}
	client, err := bbapi.New(&http.Client{Transport: t})
	if err != nil {
		return nil, err
	}

	settings := common.GetSettings(c)
	if settings.GetBuildbucket().GetHost() == "" {
		return nil, errors.New("missing buildbucket host in settings")
	}

	client.BasePath = fmt.Sprintf("https://%s/api/buildbucket/v1/", settings.Buildbucket.Host)
	return client, nil
}

func buildNumber(b *buildbucket.Build) (int, error) {
	address := b.Tags.Get("build_address")
	if address == "" {
		return 0, errors.Reason("no build_address", b.ID).Err()
	}

	// address format is "<bucket>/<builder>/<buildnumber>"
	parts := strings.Split(address, "/")
	if len(parts) != 3 {
		return 0, errors.Reason("unexpected build_address format, %q", address).Err()
	}

	return strconv.Atoi(parts[2])
}

func statusResult(status buildbucket.Status) buildbot.Result {
	switch status {
	case buildbucket.StatusScheduled, buildbucket.StatusStarted:
		return buildbot.NoResult
	case buildbucket.StatusSuccess:
		return buildbot.Success
	case buildbucket.StatusFailure:
		return buildbot.Failure
	case buildbucket.StatusError, buildbucket.StatusTimeout, buildbucket.StatusCancelled:
		return buildbot.Exception
	default:
		panic(errors.Reason("unexpected buildbucket status %q", status).Err())
	}
}

func logLocation(b *buildbucket.Build) (*types.StreamAddr, error) {
	swarmingTags := strpair.ParseMap(b.Tags["swarming_tag"])
	logLocation := swarmingTags.Get("log_location")
	if logLocation == "" {
		return nil, errors.New("log_location not found")
	}

	// Parse LogDog URL
	addr, err := types.ParseURL(logLocation)
	if err != nil {
		return nil, errors.Annotate(err, "could not parse LogDog stream from location").Err()
	}
	return addr, nil
}
<commit_msg>[milo] initialize step to empty slice<commit_after>// Copyright 2017 The LUCI 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 buildstore

import (
	"fmt"
	"net/http"
	"strconv"
	"strings"

	"golang.org/x/net/context"

	"go.chromium.org/luci/buildbucket"
	bbapi "go.chromium.org/luci/common/api/buildbucket/buildbucket/v1"
	"go.chromium.org/luci/common/data/strpair"
	"go.chromium.org/luci/common/errors"
	"go.chromium.org/luci/common/logging"
	"go.chromium.org/luci/logdog/common/types"
	"go.chromium.org/luci/milo/api/buildbot"
	"go.chromium.org/luci/milo/common"
	"go.chromium.org/luci/server/auth"
)

// This file implements conversion of buildbucket builds to buildbot builds.

// buildFromBuildbucket converts a buildbucket build to a buildbot build.
// If details is false, steps, text and properties are not guaranteed to be
// loaded.
//
// Does not populate OSFamily, OSVersion, Blame or SourceStamp.Changes
// fields.
func buildFromBuildbucket(c context.Context, master string, msg *bbapi.ApiCommonBuildMessage, fetchAnnotations bool) (*buildbot.Build, error) {
	var b buildbucket.Build
	if err := b.ParseMessage(msg); err != nil {
		return nil, err
	}
	num, err := buildNumber(&b)
	if err != nil {
		return nil, errors.Annotate(err, "parsing buildnumber").Err()
	}

	res := &buildbot.Build{
		Emulated:    true,
		Master:      master,
		Buildername: b.Builder,
		Number:      num,
		Results:     statusResult(b.Status),
		TimeStamp:   buildbot.Time{b.UpdateTime},
		Times: buildbot.TimeRange{
			Start:  buildbot.Time{b.StartTime},
			Finish: buildbot.Time{b.CompletionTime},
		},
		// TODO(nodir): use buildbucket access API when it is ready,
		// or, perhaps, just delete this code.
		// Note that this function should not be called on builds
		// that the requester does not have access to, in the first place.
		Internal:    b.Bucket != "luci.chromium.try",
		Finished:    b.Status.Completed(),
		Sourcestamp: &buildbot.SourceStamp{},

		// non-nil slice because we want an array, not null,
		// when converted to JSON
		Steps: []buildbot.Step{},
	}

	for _, bs := range b.BuildSets {
		if commit, ok := bs.(*buildbucket.GitilesCommit); ok {
			res.Sourcestamp.Repository = commit.RepoURL()
			res.Sourcestamp.Revision = commit.Revision
			break
		}
	}

	if fetchAnnotations && b.Status != buildbucket.StatusScheduled {
		addr, err := logLocation(&b)
		if err != nil {
			return nil, err
		}

		ann, err := fetchAnnotationProto(c, addr)
		switch {
		case err == errAnnotationNotFound:
		case err != nil:
			return nil, errors.Annotate(err, "could not load annotation proto").Err()
		default:
			res.Properties = extractProperties(ann)

			prefix, _ := addr.Path.Split()
			conv := annotationConverter{
				logdogServer:       addr.Host,
				logdogPrefix:       fmt.Sprintf("%s/%s", addr.Project, prefix),
				buildCompletedTime: b.CompletionTime,
			}
			convCtx := logging.SetField(c, "build_id", b.ID)
			conv.addSteps(convCtx, &res.Steps, ann.Substep, "")
			for i := range res.Steps {
				s := &res.Steps[i]
				s.StepNumber = i + 1
				res.Logs = append(res.Logs, s.Logs...)
				if !s.IsFinished {
					res.Currentstep = s.Name
				}
				if s.Results.Result != buildbot.Success {
					res.Text = append(res.Text, fmt.Sprintf("%s %s", s.Results.Result, s.Name))
				}
			}
		}
	}

	if len(res.Text) == 0 && b.Status == buildbucket.StatusSuccess {
		res.Text = []string{"Build successful"}
	}

	return res, nil
}

func buildbucketClient(c context.Context) (*bbapi.Service, error) {
	t, err := auth.GetRPCTransport(c, auth.AsUser)
	if err != nil {
		return nil, err
	}
	client, err := bbapi.New(&http.Client{Transport: t})
	if err != nil {
		return nil, err
	}

	settings := common.GetSettings(c)
	if settings.GetBuildbucket().GetHost() == "" {
		return nil, errors.New("missing buildbucket host in settings")
	}

	client.BasePath = fmt.Sprintf("https://%s/api/buildbucket/v1/", settings.Buildbucket.Host)
	return client, nil
}

func buildNumber(b *buildbucket.Build) (int, error) {
	address := b.Tags.Get("build_address")
	if address == "" {
		return 0, errors.Reason("no build_address", b.ID).Err()
	}

	// address format is "<bucket>/<builder>/<buildnumber>"
	parts := strings.Split(address, "/")
	if len(parts) != 3 {
		return 0, errors.Reason("unexpected build_address format, %q", address).Err()
	}

	return strconv.Atoi(parts[2])
}

func statusResult(status buildbucket.Status) buildbot.Result {
	switch status {
	case buildbucket.StatusScheduled, buildbucket.StatusStarted:
		return buildbot.NoResult
	case buildbucket.StatusSuccess:
		return buildbot.Success
	case buildbucket.StatusFailure:
		return buildbot.Failure
	case buildbucket.StatusError, buildbucket.StatusTimeout, buildbucket.StatusCancelled:
		return buildbot.Exception
	default:
		panic(errors.Reason("unexpected buildbucket status %q", status).Err())
	}
}

func logLocation(b *buildbucket.Build) (*types.StreamAddr, error) {
	swarmingTags := strpair.ParseMap(b.Tags["swarming_tag"])
	logLocation := swarmingTags.Get("log_location")
	if logLocation == "" {
		return nil, errors.New("log_location not found")
	}

	// Parse LogDog URL
	addr, err := types.ParseURL(logLocation)
	if err != nil {
		return nil, errors.Annotate(err, "could not parse LogDog stream from location").Err()
	}
	return addr, nil
}
<|endoftext|>


<commit_before>package shell

import (
	"fmt"
	"github.com/bfontaine/go-readline"
	"os"
	"os/exec"
	"strings"
)

type Repl struct {
	Prompt string

	lastError error
}

func (r *Repl) complete(input, line string, start, end int) []string {
	return []string{}
}

func (r *Repl) fail(err error) {
	r.lastError = err
	fmt.Printf("%v\n", err)
}

func (r *Repl) execute(line string) (exit, history bool) {
	words := strings.Fields(strings.TrimSpace(line))
	wordsCount := len(words)

	if wordsCount == 0 {
		return
	}

	history = true

	// try builtin commands
	switch words[0] {
	case "cd":
		directory := strings.Join(words[1:], " ")
		if err := os.Chdir(directory); err != nil {
			r.fail(err)
			history = false
			return
		}
	case "quit":
		fallthrough
	case "exit":
		exit = true
		return
	}

	cmd := exec.Command(words[0], words[1:]...)

	out, err := cmd.CombinedOutput()

	if err != nil {
		r.fail(err)
		history = false
		return
	}

	fmt.Print(string(out))

	return
}

func (r *Repl) Loop() (err error) {

	// tab-completion
	readline.SetCompletionFunction(r.complete)
	readline.ParseAndBind("TAB: menu-complete")

	for {
		line := readline.Readline(&r.Prompt)
		// ^D
		if line == nil {
			break
		}

		if exit, history := r.execute(*line); exit {
			break
		} else if history {
			readline.AddHistory(*line)
		}
	}

	return err
}
<commit_msg>builtins autocomplete<commit_after>package shell

import (
	"fmt"
	"github.com/bfontaine/go-readline"
	"os"
	"os/exec"
	"strings"
)

type Repl struct {
	Prompt string

	lastError error
}

var builtins = []string{"cd", "exit", "quit"}

func (r *Repl) complete(input, line string, start, end int) (cmp []string) {
	for _, builtin := range builtins {
		if strings.HasPrefix(builtin, input) {
			cmp = append(cmp, builtin)
		}
	}
	return
}

func (r *Repl) fail(err error) {
	r.lastError = err
	fmt.Printf("%v\n", err)
}

func (r *Repl) execute(line string) (exit, history bool) {
	words := strings.Fields(strings.TrimSpace(line))
	wordsCount := len(words)

	if wordsCount == 0 {
		return
	}

	history = true

	// try builtin commands
	switch words[0] {
	case "cd":
		directory := strings.Join(words[1:], " ")
		if err := os.Chdir(directory); err != nil {
			r.fail(err)
			history = false
			return
		}
	case "quit":
		fallthrough
	case "exit":
		exit = true
		return
	}

	cmd := exec.Command(words[0], words[1:]...)

	out, err := cmd.CombinedOutput()

	if err != nil {
		r.fail(err)
		history = false
		return
	}

	fmt.Print(string(out))

	return
}

func (r *Repl) Loop() (err error) {

	// tab-completion
	readline.SetCompletionFunction(r.complete)
	readline.ParseAndBind("TAB: menu-complete")

	for {
		line := readline.Readline(&r.Prompt)
		// ^D
		if line == nil {
			break
		}

		if exit, history := r.execute(*line); exit {
			break
		} else if history {
			readline.AddHistory(*line)
		}
	}

	return err
}
<|endoftext|>


<commit_before>// Copyright 2017 Google Inc. All Rights Reserved.
//
// 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 integration provides test-only code for performing integrated
// tests of Trillian functionality.
package integration

import (
	"context"
	"crypto"
	"database/sql"
	"net"
	"sync"
	"time"

	"github.com/golang/protobuf/proto"
	"github.com/golang/protobuf/ptypes"
	"github.com/google/trillian"
	"github.com/google/trillian/crypto/keys/der"
	"github.com/google/trillian/crypto/keys/pem"
	"github.com/google/trillian/crypto/keyspb"
	"github.com/google/trillian/extension"
	"github.com/google/trillian/quota"
	"github.com/google/trillian/server"
	"github.com/google/trillian/server/interceptor"
	"github.com/google/trillian/storage/mysql"
	"github.com/google/trillian/storage/testdb"
	"github.com/google/trillian/testonly"
	"github.com/google/trillian/util"
	"google.golang.org/grpc"

	ktestonly "github.com/google/trillian/crypto/keys/testonly"
	stestonly "github.com/google/trillian/storage/testonly"

	_ "github.com/go-sql-driver/mysql"                   // Load MySQL driver
	_ "github.com/google/trillian/crypto/keys/der/proto" // Register PrivateKey ProtoHandler
)

var (
	sequencerWindow = time.Duration(0)
	batchSize       = 50
	// SequencerInterval is the time between runs of the sequencer.
	SequencerInterval = 100 * time.Millisecond
	timeSource        = util.SystemTimeSource{}
	publicKey         = testonly.DemoPublicKey
	privateKeyInfo    = &keyspb.PrivateKey{
		Der: ktestonly.MustMarshalPrivatePEMToDER(testonly.DemoPrivateKey, testonly.DemoPrivateKeyPass),
	}
)

// LogEnv is a test environment that contains both a log server and a connection to it.
type LogEnv struct {
	registry        extension.Registry
	pendingTasks    *sync.WaitGroup
	grpcServer      *grpc.Server
	logServer       *server.TrillianLogRPCServer
	LogOperation    server.LogOperation
	Sequencer       *server.LogOperationManager
	sequencerCancel context.CancelFunc
	ClientConn      *grpc.ClientConn
	DB              *sql.DB
	// PublicKey is the public key that verifies responses from this server.
	PublicKey crypto.PublicKey
}

// NewLogEnv creates a fresh DB, log server, and client. The numSequencers parameter
// indicates how many sequencers to run in parallel; if numSequencers is zero a
// manually-controlled test sequencer is used.
// TODO(codingllama): Remove 3rd parameter (need to coordinate with
// github.com/google/certificate-transparency-go)
func NewLogEnv(ctx context.Context, numSequencers int, _ string) (*LogEnv, error) {
	db, err := testdb.NewTrillianDB(ctx)
	if err != nil {
		return nil, err
	}

	registry := extension.Registry{
		AdminStorage: mysql.NewAdminStorage(db),
		LogStorage:   mysql.NewLogStorage(db, nil),
		QuotaManager: quota.Noop(),
		NewKeyProto: func(ctx context.Context, spec *keyspb.Specification) (proto.Message, error) {
			return der.NewProtoFromSpec(spec)
		},
	}

	ret, err := NewLogEnvWithRegistry(ctx, numSequencers, registry)
	if err != nil {
		db.Close()
		return nil, err
	}
	ret.DB = db
	return ret, nil
}

// NewLogEnvWithRegistry uses the passed in Registry to create a log server,
// and client. The numSequencers parameter indicates how many sequencers to
// run in parallel; if numSequencers is zero a manually-controlled test
// sequencer is used.
func NewLogEnvWithRegistry(ctx context.Context, numSequencers int, registry extension.Registry) (*LogEnv, error) {
	// Create Log Server.
	grpcServer := grpc.NewServer(grpc.UnaryInterceptor(interceptor.ErrorWrapper))
	logServer := server.NewTrillianLogRPCServer(registry, timeSource)
	trillian.RegisterTrillianLogServer(grpcServer, logServer)

	// Create Sequencer.
	sequencerManager := server.NewSequencerManager(registry, sequencerWindow)
	var wg sync.WaitGroup
	var sequencerTask *server.LogOperationManager
	ctx, cancel := context.WithCancel(ctx)
	info := server.LogOperationInfo{
		Registry:    registry,
		BatchSize:   batchSize,
		NumWorkers:  numSequencers,
		RunInterval: SequencerInterval,
		TimeSource:  timeSource,
	}
	// Start a live sequencer in a goroutine.
	sequencerTask = server.NewLogOperationManager(info, sequencerManager)
	wg.Add(1)
	go func(wg *sync.WaitGroup, om *server.LogOperationManager) {
		defer wg.Done()
		om.OperationLoop(ctx)
	}(&wg, sequencerTask)

	// Listen and start server.
	addr, lis, err := listen()
	if err != nil {
		cancel()
		return nil, err
	}
	wg.Add(1)
	go func(wg *sync.WaitGroup, grpcServer *grpc.Server, lis net.Listener) {
		defer wg.Done()
		grpcServer.Serve(lis)
	}(&wg, grpcServer, lis)

	// Connect to the server.
	cc, err := grpc.Dial(addr, grpc.WithInsecure())
	if err != nil {
		cancel()
		return nil, err
	}

	publicKey, err := pem.UnmarshalPublicKey(publicKey)
	if err != nil {
		cancel()
		return nil, err
	}

	return &LogEnv{
		registry:        registry,
		pendingTasks:    &wg,
		grpcServer:      grpcServer,
		logServer:       logServer,
		ClientConn:      cc,
		PublicKey:       publicKey,
		LogOperation:    sequencerManager,
		Sequencer:       sequencerTask,
		sequencerCancel: cancel,
	}, nil
}

// Close shuts down the server.
func (env *LogEnv) Close() {
	if env.sequencerCancel != nil {
		env.sequencerCancel()
	}
	env.ClientConn.Close()
	env.grpcServer.GracefulStop()
	env.pendingTasks.Wait()
	if env.DB != nil {
		env.DB.Close()
	}
}

// CreateLog creates a log and signs the first empty tree head.
func (env *LogEnv) CreateLog() (int64, error) {
	ctx := context.Background()
	tx, err := env.registry.AdminStorage.Begin(ctx)
	if err != nil {
		return 0, err
	}

	tree := stestonly.LogTree
	tree.PrivateKey, err = ptypes.MarshalAny(privateKeyInfo)
	if err != nil {
		return 0, err
	}
	tree.PublicKey = &keyspb.PublicKey{
		Der: ktestonly.MustMarshalPublicPEMToDER(publicKey),
	}

	tree, err = tx.CreateTree(ctx, tree)
	if err != nil {
		return 0, err
	}
	if err := tx.Commit(); err != nil {
		return 0, err
	}
	// Sign the first empty tree head.
	env.Sequencer.OperationSingle(ctx)
	return tree.TreeId, nil
}
<commit_msg>Add an `Address` field to `LogEnv`. (#924)<commit_after>// Copyright 2017 Google Inc. All Rights Reserved.
//
// 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 integration provides test-only code for performing integrated
// tests of Trillian functionality.
package integration

import (
	"context"
	"crypto"
	"database/sql"
	"net"
	"sync"
	"time"

	"github.com/golang/protobuf/proto"
	"github.com/golang/protobuf/ptypes"
	"github.com/google/trillian"
	"github.com/google/trillian/crypto/keys/der"
	"github.com/google/trillian/crypto/keys/pem"
	"github.com/google/trillian/crypto/keyspb"
	"github.com/google/trillian/extension"
	"github.com/google/trillian/quota"
	"github.com/google/trillian/server"
	"github.com/google/trillian/server/interceptor"
	"github.com/google/trillian/storage/mysql"
	"github.com/google/trillian/storage/testdb"
	"github.com/google/trillian/testonly"
	"github.com/google/trillian/util"
	"google.golang.org/grpc"

	ktestonly "github.com/google/trillian/crypto/keys/testonly"
	stestonly "github.com/google/trillian/storage/testonly"

	_ "github.com/go-sql-driver/mysql"                   // Load MySQL driver
	_ "github.com/google/trillian/crypto/keys/der/proto" // Register PrivateKey ProtoHandler
)

var (
	sequencerWindow = time.Duration(0)
	batchSize       = 50
	// SequencerInterval is the time between runs of the sequencer.
	SequencerInterval = 100 * time.Millisecond
	timeSource        = util.SystemTimeSource{}
	publicKey         = testonly.DemoPublicKey
	privateKeyInfo    = &keyspb.PrivateKey{
		Der: ktestonly.MustMarshalPrivatePEMToDER(testonly.DemoPrivateKey, testonly.DemoPrivateKeyPass),
	}
)

// LogEnv is a test environment that contains both a log server and a connection to it.
type LogEnv struct {
	registry        extension.Registry
	pendingTasks    *sync.WaitGroup
	grpcServer      *grpc.Server
	logServer       *server.TrillianLogRPCServer
	LogOperation    server.LogOperation
	Sequencer       *server.LogOperationManager
	sequencerCancel context.CancelFunc
	Address         string
	ClientConn      *grpc.ClientConn
	DB              *sql.DB
	// PublicKey is the public key that verifies responses from this server.
	PublicKey crypto.PublicKey
}

// NewLogEnv creates a fresh DB, log server, and client. The numSequencers parameter
// indicates how many sequencers to run in parallel; if numSequencers is zero a
// manually-controlled test sequencer is used.
// TODO(codingllama): Remove 3rd parameter (need to coordinate with
// github.com/google/certificate-transparency-go)
func NewLogEnv(ctx context.Context, numSequencers int, _ string) (*LogEnv, error) {
	db, err := testdb.NewTrillianDB(ctx)
	if err != nil {
		return nil, err
	}

	registry := extension.Registry{
		AdminStorage: mysql.NewAdminStorage(db),
		LogStorage:   mysql.NewLogStorage(db, nil),
		QuotaManager: quota.Noop(),
		NewKeyProto: func(ctx context.Context, spec *keyspb.Specification) (proto.Message, error) {
			return der.NewProtoFromSpec(spec)
		},
	}

	ret, err := NewLogEnvWithRegistry(ctx, numSequencers, registry)
	if err != nil {
		db.Close()
		return nil, err
	}
	ret.DB = db
	return ret, nil
}

// NewLogEnvWithRegistry uses the passed in Registry to create a log server,
// and client. The numSequencers parameter indicates how many sequencers to
// run in parallel; if numSequencers is zero a manually-controlled test
// sequencer is used.
func NewLogEnvWithRegistry(ctx context.Context, numSequencers int, registry extension.Registry) (*LogEnv, error) {
	// Create Log Server.
	grpcServer := grpc.NewServer(grpc.UnaryInterceptor(interceptor.ErrorWrapper))
	logServer := server.NewTrillianLogRPCServer(registry, timeSource)
	trillian.RegisterTrillianLogServer(grpcServer, logServer)

	// Create Sequencer.
	sequencerManager := server.NewSequencerManager(registry, sequencerWindow)
	var wg sync.WaitGroup
	var sequencerTask *server.LogOperationManager
	ctx, cancel := context.WithCancel(ctx)
	info := server.LogOperationInfo{
		Registry:    registry,
		BatchSize:   batchSize,
		NumWorkers:  numSequencers,
		RunInterval: SequencerInterval,
		TimeSource:  timeSource,
	}
	// Start a live sequencer in a goroutine.
	sequencerTask = server.NewLogOperationManager(info, sequencerManager)
	wg.Add(1)
	go func(wg *sync.WaitGroup, om *server.LogOperationManager) {
		defer wg.Done()
		om.OperationLoop(ctx)
	}(&wg, sequencerTask)

	// Listen and start server.
	addr, lis, err := listen()
	if err != nil {
		cancel()
		return nil, err
	}
	wg.Add(1)
	go func(wg *sync.WaitGroup, grpcServer *grpc.Server, lis net.Listener) {
		defer wg.Done()
		grpcServer.Serve(lis)
	}(&wg, grpcServer, lis)

	// Connect to the server.
	cc, err := grpc.Dial(addr, grpc.WithInsecure())
	if err != nil {
		cancel()
		return nil, err
	}

	publicKey, err := pem.UnmarshalPublicKey(publicKey)
	if err != nil {
		cancel()
		return nil, err
	}

	return &LogEnv{
		registry:        registry,
		pendingTasks:    &wg,
		grpcServer:      grpcServer,
		logServer:       logServer,
		Address:         addr,
		ClientConn:      cc,
		PublicKey:       publicKey,
		LogOperation:    sequencerManager,
		Sequencer:       sequencerTask,
		sequencerCancel: cancel,
	}, nil
}

// Close shuts down the server.
func (env *LogEnv) Close() {
	if env.sequencerCancel != nil {
		env.sequencerCancel()
	}
	env.ClientConn.Close()
	env.grpcServer.GracefulStop()
	env.pendingTasks.Wait()
	if env.DB != nil {
		env.DB.Close()
	}
}

// CreateLog creates a log and signs the first empty tree head.
func (env *LogEnv) CreateLog() (int64, error) {
	ctx := context.Background()
	tx, err := env.registry.AdminStorage.Begin(ctx)
	if err != nil {
		return 0, err
	}

	tree := stestonly.LogTree
	tree.PrivateKey, err = ptypes.MarshalAny(privateKeyInfo)
	if err != nil {
		return 0, err
	}
	tree.PublicKey = &keyspb.PublicKey{
		Der: ktestonly.MustMarshalPublicPEMToDER(publicKey),
	}

	tree, err = tx.CreateTree(ctx, tree)
	if err != nil {
		return 0, err
	}
	if err := tx.Commit(); err != nil {
		return 0, err
	}
	// Sign the first empty tree head.
	env.Sequencer.OperationSingle(ctx)
	return tree.TreeId, nil
}
<|endoftext|>


<commit_before>package scenarios

import (
	"fmt"
	"io"
	"io/ioutil"
	"os/exec"
	"path/filepath"
	"runtime"
	"sync"
	"syscall"
	"time"

	"github.com/golang/protobuf/proto"
	"v2ray.com/core"
	"v2ray.com/core/app/dispatcher"
	"v2ray.com/core/app/proxyman"
	"v2ray.com/core/common"
	"v2ray.com/core/common/log"
	"v2ray.com/core/common/net"
	"v2ray.com/core/common/retry"
	"v2ray.com/core/common/serial"
)

func xor(b []byte) []byte {
	r := make([]byte, len(b))
	for i, v := range b {
		r[i] = v ^ 'c'
	}
	return r
}

func readFrom(conn net.Conn, timeout time.Duration, length int) []byte {
	b := make([]byte, length)
	deadline := time.Now().Add(timeout)
	conn.SetReadDeadline(deadline)
	n, err := io.ReadFull(conn, b[:length])
	if err != nil {
		fmt.Println("Unexpected error from readFrom:", err)
	}
	return b[:n]
}

func InitializeServerConfigs(configs ...*core.Config) ([]*exec.Cmd, error) {
	servers := make([]*exec.Cmd, 0, 10)

	for _, config := range configs {
		server, err := InitializeServerConfig(config)
		if err != nil {
			CloseAllServers(servers)
			return nil, err
		}
		servers = append(servers, server)
	}

	time.Sleep(time.Second * 2)

	return servers, nil
}

func InitializeServerConfig(config *core.Config) (*exec.Cmd, error) {
	err := BuildV2Ray()
	if err != nil {
		return nil, err
	}

	config = withDefaultApps(config)
	configBytes, err := proto.Marshal(config)
	if err != nil {
		return nil, err
	}
	proc := RunV2RayProtobuf(configBytes)

	if err := proc.Start(); err != nil {
		return nil, err
	}

	return proc, nil
}

var (
	testBinaryPath    string
	testBinaryPathGen sync.Once
)

func genTestBinaryPath() {
	testBinaryPathGen.Do(func() {
		var tempDir string
		common.Must(retry.Timed(5, 100).On(func() error {
			dir, err := ioutil.TempDir("", "v2ray")
			if err != nil {
				return err
			}
			tempDir = dir
			return nil
		}))
		file := filepath.Join(tempDir, "v2ray.test")
		if runtime.GOOS == "windows" {
			file += ".exe"
		}
		testBinaryPath = file
		fmt.Printf("Generated binary path: %s\n", file)
	})
}

func GetSourcePath() string {
	return filepath.Join("v2ray.com", "core", "main")
}

func CloseAllServers(servers []*exec.Cmd) {
	log.Record(&log.GeneralMessage{
		Severity: log.Severity_Info,
		Content:  "Closing all servers.",
	})
	for _, server := range servers {
		server.Process.Signal(syscall.SIGTERM)
	}
	for _, server := range servers {
		server.Process.Wait()
	}
	log.Record(&log.GeneralMessage{
		Severity: log.Severity_Info,
		Content:  "All server closed.",
	})
}

func withDefaultApps(config *core.Config) *core.Config {
	config.App = append(config.App, serial.ToTypedMessage(&dispatcher.Config{}))
	config.App = append(config.App, serial.ToTypedMessage(&proxyman.InboundConfig{}))
	config.App = append(config.App, serial.ToTypedMessage(&proxyman.OutboundConfig{}))
	return config
}
<commit_msg>try another way to kill process on windows<commit_after>package scenarios

import (
	"fmt"
	"io"
	"io/ioutil"
	"os/exec"
	"path/filepath"
	"runtime"
	"sync"
	"syscall"
	"time"

	"github.com/golang/protobuf/proto"
	"v2ray.com/core"
	"v2ray.com/core/app/dispatcher"
	"v2ray.com/core/app/proxyman"
	"v2ray.com/core/common"
	"v2ray.com/core/common/log"
	"v2ray.com/core/common/net"
	"v2ray.com/core/common/retry"
	"v2ray.com/core/common/serial"
)

func xor(b []byte) []byte {
	r := make([]byte, len(b))
	for i, v := range b {
		r[i] = v ^ 'c'
	}
	return r
}

func readFrom(conn net.Conn, timeout time.Duration, length int) []byte {
	b := make([]byte, length)
	deadline := time.Now().Add(timeout)
	conn.SetReadDeadline(deadline)
	n, err := io.ReadFull(conn, b[:length])
	if err != nil {
		fmt.Println("Unexpected error from readFrom:", err)
	}
	return b[:n]
}

func InitializeServerConfigs(configs ...*core.Config) ([]*exec.Cmd, error) {
	servers := make([]*exec.Cmd, 0, 10)

	for _, config := range configs {
		server, err := InitializeServerConfig(config)
		if err != nil {
			CloseAllServers(servers)
			return nil, err
		}
		servers = append(servers, server)
	}

	time.Sleep(time.Second * 2)

	return servers, nil
}

func InitializeServerConfig(config *core.Config) (*exec.Cmd, error) {
	err := BuildV2Ray()
	if err != nil {
		return nil, err
	}

	config = withDefaultApps(config)
	configBytes, err := proto.Marshal(config)
	if err != nil {
		return nil, err
	}
	proc := RunV2RayProtobuf(configBytes)

	if err := proc.Start(); err != nil {
		return nil, err
	}

	return proc, nil
}

var (
	testBinaryPath    string
	testBinaryPathGen sync.Once
)

func genTestBinaryPath() {
	testBinaryPathGen.Do(func() {
		var tempDir string
		common.Must(retry.Timed(5, 100).On(func() error {
			dir, err := ioutil.TempDir("", "v2ray")
			if err != nil {
				return err
			}
			tempDir = dir
			return nil
		}))
		file := filepath.Join(tempDir, "v2ray.test")
		if runtime.GOOS == "windows" {
			file += ".exe"
		}
		testBinaryPath = file
		fmt.Printf("Generated binary path: %s\n", file)
	})
}

func GetSourcePath() string {
	return filepath.Join("v2ray.com", "core", "main")
}

func CloseAllServers(servers []*exec.Cmd) {
	log.Record(&log.GeneralMessage{
		Severity: log.Severity_Info,
		Content:  "Closing all servers.",
	})
	for _, server := range servers {
		if runtime.GOOS == "windows" {
			server.Process.Kill()
		} else {
			server.Process.Signal(syscall.SIGTERM)
		}
	}
	for _, server := range servers {
		server.Process.Wait()
	}
	log.Record(&log.GeneralMessage{
		Severity: log.Severity_Info,
		Content:  "All server closed.",
	})
}

func withDefaultApps(config *core.Config) *core.Config {
	config.App = append(config.App, serial.ToTypedMessage(&dispatcher.Config{}))
	config.App = append(config.App, serial.ToTypedMessage(&proxyman.InboundConfig{}))
	config.App = append(config.App, serial.ToTypedMessage(&proxyman.OutboundConfig{}))
	return config
}
<|endoftext|>


<commit_before>// The chroot package is able to create an Amazon AMI without requiring
// the launch of a new instance for every build. It does this by attaching
// and mounting the root volume of another AMI and chrooting into that
// directory. It then creates an AMI from that attached drive.
package chroot

import (
	"github.com/mitchellh/goamz/ec2"
	"github.com/mitchellh/multistep"
	awscommon "github.com/mitchellh/packer/builder/amazon/common"
	"github.com/mitchellh/packer/builder/common"
	"github.com/mitchellh/packer/packer"
	"log"
)

// The unique ID for this builder
const BuilderId = "mitchellh.amazon.chroot"

// Config is the configuration that is chained through the steps and
// settable from the template.
type Config struct {
	common.PackerConfig    `mapstructure:",squash"`
	awscommon.AccessConfig `mapstructure:",squash"`

	SourceAmi string `mapstructure:"source_ami"`
}

type Builder struct {
	config Config
	runner multistep.Runner
}

func (b *Builder) Prepare(raws ...interface{}) error {
	md, err := common.DecodeConfig(&b.config, raws...)
	if err != nil {
		return err
	}

	// Defaults

	// Accumulate any errors
	errs := common.CheckUnusedConfig(md)
	errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare()...)

	if errs != nil && len(errs.Errors) > 0 {
		return errs
	}

	log.Printf("Config: %+v", b.config)
	return nil
}

func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
	region, err := b.config.Region()
	if err != nil {
		return nil, err
	}

	auth, err := b.config.AccessConfig.Auth()
	if err != nil {
		return nil, err
	}

	ec2conn := ec2.New(auth, region)

	// Setup the state bag and initial state for the steps
	state := make(map[string]interface{})
	state["config"] = &b.config
	state["ec2"] = ec2conn
	state["hook"] = hook
	state["ui"] = ui

	// Build the steps
	steps := []multistep.Step{
		&StepInstanceInfo{},
		&StepSourceAMIInfo{},
		&StepCreateVolume{},
		&StepAttachVolume{},
	}

	// Run!
	if b.config.PackerDebug {
		b.runner = &multistep.DebugRunner{
			Steps:   steps,
			PauseFn: common.MultistepDebugFn(ui),
		}
	} else {
		b.runner = &multistep.BasicRunner{Steps: steps}
	}

	b.runner.Run(state)

	// If there was an error, return that
	if rawErr, ok := state["error"]; ok {
		return nil, rawErr.(error)
	}

	// If there are no AMIs, then just return
	if _, ok := state["amis"]; !ok {
		return nil, nil
	}

	// Build the artifact and return it
	artifact := &awscommon.Artifact{
		Amis:           state["amis"].(map[string]string),
		BuilderIdValue: BuilderId,
		Conn:           ec2conn,
	}

	return artifact, nil
}

func (b *Builder) Cancel() {
	if b.runner != nil {
		log.Println("Cancelling the step runner...")
		b.runner.Cancel()
	}
}
<commit_msg>builder/amazon/chroot: only let it run on Linux<commit_after>// The chroot package is able to create an Amazon AMI without requiring
// the launch of a new instance for every build. It does this by attaching
// and mounting the root volume of another AMI and chrooting into that
// directory. It then creates an AMI from that attached drive.
package chroot

import (
	"errors"
	"github.com/mitchellh/goamz/ec2"
	"github.com/mitchellh/multistep"
	awscommon "github.com/mitchellh/packer/builder/amazon/common"
	"github.com/mitchellh/packer/builder/common"
	"github.com/mitchellh/packer/packer"
	"log"
	"runtime"
)

// The unique ID for this builder
const BuilderId = "mitchellh.amazon.chroot"

// Config is the configuration that is chained through the steps and
// settable from the template.
type Config struct {
	common.PackerConfig    `mapstructure:",squash"`
	awscommon.AccessConfig `mapstructure:",squash"`

	SourceAmi string `mapstructure:"source_ami"`
}

type Builder struct {
	config Config
	runner multistep.Runner
}

func (b *Builder) Prepare(raws ...interface{}) error {
	md, err := common.DecodeConfig(&b.config, raws...)
	if err != nil {
		return err
	}

	// Defaults

	// Accumulate any errors
	errs := common.CheckUnusedConfig(md)
	errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare()...)

	if errs != nil && len(errs.Errors) > 0 {
		return errs
	}

	log.Printf("Config: %+v", b.config)
	return nil
}

func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
	if runtime.GOOS != "linux" {
		return nil, errors.New("The amazon-chroot builder only works on Linux environments.")
	}

	region, err := b.config.Region()
	if err != nil {
		return nil, err
	}

	auth, err := b.config.AccessConfig.Auth()
	if err != nil {
		return nil, err
	}

	ec2conn := ec2.New(auth, region)

	// Setup the state bag and initial state for the steps
	state := make(map[string]interface{})
	state["config"] = &b.config
	state["ec2"] = ec2conn
	state["hook"] = hook
	state["ui"] = ui

	// Build the steps
	steps := []multistep.Step{
		&StepInstanceInfo{},
		&StepSourceAMIInfo{},
		&StepCreateVolume{},
		&StepAttachVolume{},
	}

	// Run!
	if b.config.PackerDebug {
		b.runner = &multistep.DebugRunner{
			Steps:   steps,
			PauseFn: common.MultistepDebugFn(ui),
		}
	} else {
		b.runner = &multistep.BasicRunner{Steps: steps}
	}

	b.runner.Run(state)

	// If there was an error, return that
	if rawErr, ok := state["error"]; ok {
		return nil, rawErr.(error)
	}

	// If there are no AMIs, then just return
	if _, ok := state["amis"]; !ok {
		return nil, nil
	}

	// Build the artifact and return it
	artifact := &awscommon.Artifact{
		Amis:           state["amis"].(map[string]string),
		BuilderIdValue: BuilderId,
		Conn:           ec2conn,
	}

	return artifact, nil
}

func (b *Builder) Cancel() {
	if b.runner != nil {
		log.Println("Cancelling the step runner...")
		b.runner.Cancel()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
)

var (
	ModulePaths []string
)

func init() {
	ModulePaths = make([]string, 0)
	ModulePaths = append(ModulePaths, "/usr/local/etc/govern/modules")
	ModulePaths = append(ModulePaths, "/etc/govern/modules")

	userModsPath := filepath.Join(os.Getenv("HOME"), ".govern", "modules")
	ModulePaths = append(ModulePaths, userModsPath)
}

type Module struct {
	Name           string
	OSFamily       string
	OSVersionMajor string
	OSVersionMinor string
	Path           string
}

func GatherModules() ([]Module, error) {
	mods := make([]Module, 0)
	for _, pth := range ModulePaths {
		if fi, err := os.Stat(pth); err != nil && os.IsNotExist(err) {
			// The error is just because the path does not exist.
			// Carry on.
			continue
		} else if err != nil {
			return nil, err
		} else if !fi.IsDir() {
			return nil, fmt.Errorf("%s is not a directory")
		}

		m, err := gatherModulesInDir(pth)
		if err != nil {
			return nil, err
		}

		mods = append(mods, m...)
	}

	return mods, nil
}

func gatherModulesInDir(pth string) ([]Module, error) {
	matches, err := filepath.Glob(filepath.Join(pth, "*.sh"))
	if err != nil {
		return nil, err
	}

	mods := make([]Module, 0)
	for _, match := range matches {
		parts := strings.SplitN(filepath.Base(match), "_", 4)

		var name, osf, osvmj, osvmn string

		switch nparts := len(parts); nparts {
		case 0:
			return nil, fmt.Errorf("poorly named module %q", match)

		case 1:
			name = strings.TrimRight(parts[0], ".sh")

		case 2:
			name = parts[0]
			osf = strings.TrimRight(parts[1], ".sh")

		case 3:
			name = parts[0]
			osf = parts[1]
			osvmj = strings.TrimRight(parts[2], ".sh")

		case 4:
			name = parts[0]
			osf = parts[1]
			osvmj = parts[2]
			osvmn = strings.TrimRight(parts[3], ".sh")
		}

		m := Module{
			Name:           name,
			OSFamily:       osf,
			OSVersionMajor: osvmj,
			OSVersionMinor: osvmn,
			Path:           match}

		mods = append(mods, m)
	}

	return mods, nil
}
<commit_msg>modules: Added support for modules in the current directory.<commit_after>package main

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
)

var (
	ModulePaths []string
)

func init() {
	ModulePaths = make([]string, 0)
	ModulePaths = append(ModulePaths, "/usr/local/etc/govern/modules")
	ModulePaths = append(ModulePaths, "/etc/govern/modules")

	userModsPath := filepath.Join(os.Getenv("HOME"), ".govern", "modules")
	ModulePaths = append(ModulePaths, userModsPath)

	if pwd, err := os.Getwd(); err == nil {
		lmd := filepath.Join(pwd, "modules")
		if info, err := os.Stat(lmd); err != nil && os.IsNotExist(err) {
			fmt.Println("No \"modules\" directory in the current working path")
		} else if err != nil {
			fmt.Println("ERROR:", err.Error())
		} else if !info.IsDir() {
			fmt.Println("WARNING: Found modules in current directory, but is not a directory")
		} else if info.IsDir() {
			ModulePaths = append(ModulePaths, lmd)
		}
	} else {
		fmt.Println("ERROR:", err.Error())
	}
}

type Module struct {
	Name           string
	OSFamily       string
	OSVersionMajor string
	OSVersionMinor string
	Path           string
}

func GatherModules() ([]Module, error) {
	mods := make([]Module, 0)
	for _, pth := range ModulePaths {
		if fi, err := os.Stat(pth); err != nil && os.IsNotExist(err) {
			// The error is just because the path does not exist.
			// Carry on.
			continue
		} else if err != nil {
			return nil, err
		} else if !fi.IsDir() {
			return nil, fmt.Errorf("%s is not a directory")
		}

		m, err := gatherModulesInDir(pth)
		if err != nil {
			return nil, err
		}

		mods = append(mods, m...)
	}

	return mods, nil
}

func gatherModulesInDir(pth string) ([]Module, error) {
	matches, err := filepath.Glob(filepath.Join(pth, "*.sh"))
	if err != nil {
		return nil, err
	}

	mods := make([]Module, 0)
	for _, match := range matches {
		// Skip files with an underscore as the first letter of the name.
		// The underscore as the first letter in the filename is used to
		// denote includes.
		if strings.HasPrefix(filepath.Base(match), "_") {
			continue
		}

		parts := strings.SplitN(filepath.Base(match), "_", 4)

		var name, osf, osvmj, osvmn string

		switch nparts := len(parts); nparts {
		case 0:
			return nil, fmt.Errorf("poorly named module %q", match)

		case 1:
			name = strings.TrimRight(parts[0], ".sh")

		case 2:
			name = parts[0]
			osf = strings.TrimRight(parts[1], ".sh")

		case 3:
			name = parts[0]
			osf = parts[1]
			osvmj = strings.TrimRight(parts[2], ".sh")

		case 4:
			name = parts[0]
			osf = parts[1]
			osvmj = parts[2]
			osvmn = strings.TrimRight(parts[3], ".sh")
		}

		m := Module{
			Name:           name,
			OSFamily:       osf,
			OSVersionMajor: osvmj,
			OSVersionMinor: osvmn,
			Path:           match}

		mods = append(mods, m)
	}

	return mods, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/codegangsta/cli"
	"os"
)

var api *Api
var controller Controller

func main() {
	loginController := new(LoginController)

	app := cli.NewApp()
	app.Name = "mongohq"
	app.Usage = "Allow MongoHQ interaction from the commandline (enables awesomeness)"
	app.Before = func(c *cli.Context) error {
		loginController.RequireAuth(c) // Exits process if auth fails
		loginController.Api.Config = getConfig()

		controller = Controller{Api: loginController.Api}
		return nil
	}
	app.CommandNotFound = findClosestCommand
	app.Version = Version()
	app.Commands = []cli.Command{
		{
			Name:  "accounts",
			Usage: "list accounts",
			Flags: []cli.Flag{
				cli.StringFlag{"account,a", "<string>", "optional account slug; if included, will run accounts:info"},
			},
			Description: `
   List the slugs for all accounts which you have permission
   To change the default account, see the "config:account" command.
      `,
			Action: func(c *cli.Context) {
				if c.String("account") == "<string>" {
					controller.ListAccounts()
				} else {
					controller.ShowAccount(c.String("account"))
				}
			},
		},
		{
			Name:  "accounts:info",
			Usage: "account information",
			Flags: []cli.Flag{
				cli.StringFlag{"account,a", "<string>", "account slug"},
			},
			Description: `
   More detail about a particular account, including name, slug, owner, and users.
      `,
			Action: func(c *cli.Context) {
				controller.ShowAccount(c.String("account"))
			},
		},
		{
			Name:  "backups",
			Usage: "list backups with optional filters",
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "optional deployment filter for backups"},
				cli.StringFlag{"backup,b", "<string>", "optional backup name; if included, will run backups:info"},
			},
			Description: `
   Lists the backups associated with your account or deployment.

   To see a list of all backups on your account, including those from deleted
   deployments, omit the deployment argument.

   To see a list of all backups on a single deployment, include the name or
   id of the intended deployment using the deployment argument.
      `,
			Action: func(c *cli.Context) {
				if c.String("backup") == "<string>" {
					controller.ListBackups(c.String("deployment"))
				} else {
					controller.ShowBackup(c.String("backup"))
				}
			},
		},
		{
			Name:  "backups:create",
			Usage: "create an on-demand backup for a deployment",
			Description: `
   Queues an on-demand backup for a deployment.  To read more about this feature,
   see http://docs.mongohq.com/backups/elastic-deployments.html#on-demand-backups.
      `,
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "deployment name"},
			},
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"deployment"}, []string{})
				controller.CreateBackup(c.String("deployment"))
			},
		},
		{
			Name:  "backups:info",
			Usage: "information on backup",
			Flags: []cli.Flag{
				cli.StringFlag{"backup,b", "<string>", "file name of backup"},
			},
			Description: `
   More detail about a particular backup, including deployment, databases, creation time, type, size, and download link.
      `,
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"backup"}, []string{})
				controller.ShowBackup(c.String("backup"))
			},
		},
		{
			Name:  "backups:restore",
			Usage: "restore backup to a new database",
			Description: `
   Restores a backup of a database to a new, fresh deployment. The new
   deployment will be created in the same datacenter with the same version
   as the source database.
      `,
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "new deployment name"},
				cli.StringFlag{"backup,b", "<string>", "file name of backup"},
				cli.StringFlag{"source-database,source", "<string>", "original database name"},
				cli.StringFlag{"destination-database,destination", "<string>", "new database name"},
			},
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"deployment", "backup", "source-database", "destination-database"}, []string{})
				controller.RestoreBackup(c.String("backup"), c.String("deployment"), c.String("source-database"), c.String("destination-database"))
			},
		},
		{
			Name:  "config:account",
			Usage: "set a default account context",
			Flags: []cli.Flag{
				cli.StringFlag{"account,a", "<string>", "slug for default account"},
			},
			Description: `
   Set a default account so the account flag is not required for each command.
      `,
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"account"}, []string{})
				controller.SetConfigAccount(c.String("account"))
			},
		},
		{
			Name:  "databases:create",
			Usage: "create database on an existing deployment",
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "deployment to create database on"},
				cli.StringFlag{"database,db", "<string>", "new database to create"},
			},
			Description: `
   Create a new database on an existing deployment.  If you are looking to create a
   new database on a new deployment, see the deployments:create command.
      `,
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"deployment", "database"}, []string{})
				controller.CreateDatabase(c.String("deployment"), c.String("database"))
			},
		},
		{
			Name:  "databases:info",
			Usage: "information on database",
			Flags: []cli.Flag{
				cli.StringFlag{"database,db", "<string>", " database for more information"},
				cli.StringFlag{"deployment,dep", "<string>", " deployment containing database"},
			},
			Description: `
   More detail on a particular database, including name, status, and stats.
      `,
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"database", "deployment"}, []string{})
				controller.ShowDatabase(c.String("deployment"), c.String("database"))
			},
		},
		{
			Name:  "databases:remove",
			Usage: "remove database",
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "deployment"},
				cli.StringFlag{"database,db", "<string>", "database to remove"},
				cli.BoolFlag{"force,f", "delete without confirmation"},
			},
			Description: `
   Deletes a database from a deployment.  If this is the last database on the
   deployment, the deployment will also be deleted.

   You will be asked to verify the database name on delete, unless including
   the force argument.
      `,
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"database", "deployment"}, []string{})
				controller.DeleteDatabase(c.String("deployment"), c.String("database"), c.Bool("force"))
			},
		},
		{
			Name:  "deployments",
			Usage: "list deployments",
			Description: `
   List the slugs for all deployments.
      `,
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "optional deployment name; if included runs deployments:info"},
			},
			Action: func(c *cli.Context) {
				if c.String("deployment") == "<string>" {
					controller.ListDeployments()
				} else {
					controller.ShowDeployment(c.String("deployment"))
				}
			},
		},
		{
			Name:  "deployments:create",
			Usage: "create a new Elastic Deployment",
			Flags: []cli.Flag{
				cli.StringFlag{"database,db", "<string>", "new database name"},
				cli.StringFlag{"deployment,dep", "<string>", "new deployment name"},
				cli.StringFlag{"location,l", "<string>", "location of deployment (for list of locations, run 'mongohq locations')"},
			},
			Description: `
   Creates an elastic deployment on the MongoHQ platform. Stick with me here: it will create a new database on a new
   deployment at location you specify.  The deployment is a Replica Set and the database is the logical MongoDB database.
   You can find a list of locations by running "mongohq locations".
      `,
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"deployment", "database", "location"}, []string{})
				controller.CreateDeployment(c.String("deployment"), c.String("database"), c.String("location"))
			},
		},
		{
			Name:  "deployments:info",
			Usage: "information on deployment",
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "deployment for more information"},
			},
			Description: `
   More detail about a particular deployment, including plan, status, location,
   current primary, members, version, and a list of databases.
      `,
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"deployment"}, []string{})
				controller.ShowDeployment(c.String("deployment"))
			},
		},
		{
			Name:  "deployments:rename",
			Usage: "rename a deployment",
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "deployment for more information"},
				cli.StringFlag{"name,n", "<string>", "new name for deployment"},
			},
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"deployment", "name"}, []string{})
				controller.RenameDeployment(c.String("deployment"), c.String("name"))
			},
		},
		{
			Name:  "deployments:remove",
			Usage: "remove a deployment",
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "deployment for more information"},
				cli.BoolFlag{"force,f", "delete without confirmation"},
			},
			Description: `
   Deletes a deployment.  Requires confirmation because this is a very destructive action,
   particularly for data.
      `,
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"deployment"}, []string{})
				controller.DeleteDeployment(c.String("deployment"), c.Bool("force"))
			},
		},
		{
			Name:  "logs",
			Usage: "query historical logs",
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "deployment for querying logs"},
			},
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"deployment"}, []string{})
				controller.HistoricalLogs(c.String("deployment"))
			},
		},
		{
			Name:  "locations",
			Usage: "list available locations",
			Description: `
   List the current locations available for MongoHQ deployments.  Used with both new
   deployments and restoring databases from backups.
      `,
			Action: func(c *cli.Context) {
				controller.ListLocations()
			},
		},
		{
			Name:  "mongostat",
			Usage: "realtime mongostat",
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "deployment for watching mongostats"},
			},
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"deployment"}, []string{})
				controller.DeploymentMongoStat(c.String("deployment"))
			},
		},
		{
			Name:  "users",
			Usage: "list users on a database",
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "deployment id the database is on"},
				cli.StringFlag{"database,db", "<string>", "database to list users"},
			},
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"deployment", "database"}, []string{})
				controller.ListDatabaseUsers(c.String("deployment"), c.String("database"))
			},
		},
		{
			Name:  "users:create",
			Usage: "add user to a database",
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "deployment id the database is on"},
				cli.StringFlag{"database,db", "<string>", "atabase name to create the user on"},
				cli.StringFlag{"username,u", "<string>", "user to create"},
			},
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"deployment", "database", "username"}, []string{})
				controller.CreateDatabaseUser(c.String("deployment"), c.String("database"), c.String("username"))
			},
		},
		{
			Name:  "users:remove",
			Usage: "remove user from database",
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "deployment id the database is on"},
				cli.StringFlag{"database,db", "<string>", "database name to remove the user from"},
				cli.StringFlag{"username,u", "<string>", "user to remove from the deployment"},
			},
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"deployment", "database", "username"}, []string{})
				controller.DeleteDatabaseUser(c.String("deployment"), c.String("database"), c.String("username"))
			},
		},
		{
			Name:  "whoami",
			Usage: "display effective user",
			Action: func(c *cli.Context) {
				controller.CurrentUser()
			},
		},
		{
			Name:  "logout",
			Usage: "remove stored auth",
			Action: func(c *cli.Context) {
				loginController.Logout()
			},
		},
		{
			Name:  "update",
			Usage: "script to update the MongoHQ CLI binary",
			Action: func(c *cli.Context) {
				fmt.Println("To update, run: `curl https://mongohq-cli.s3.amazonaws.com/install.sh | sh`")
			},
		},
	}

	app.Run(os.Args)
}
<commit_msg>Add documentation for deployments:rename<commit_after>package main

import (
	"fmt"
	"github.com/codegangsta/cli"
	"os"
)

var api *Api
var controller Controller

func main() {
	loginController := new(LoginController)

	app := cli.NewApp()
	app.Name = "mongohq"
	app.Usage = "Allow MongoHQ interaction from the commandline (enables awesomeness)"
	app.Before = func(c *cli.Context) error {
		loginController.RequireAuth(c) // Exits process if auth fails
		loginController.Api.Config = getConfig()

		controller = Controller{Api: loginController.Api}
		return nil
	}
	app.CommandNotFound = findClosestCommand
	app.Version = Version()
	app.Commands = []cli.Command{
		{
			Name:  "accounts",
			Usage: "list accounts",
			Flags: []cli.Flag{
				cli.StringFlag{"account,a", "<string>", "optional account slug; if included, will run accounts:info"},
			},
			Description: `
   List the slugs for all accounts which you have permission
   To change the default account, see the "config:account" command.
      `,
			Action: func(c *cli.Context) {
				if c.String("account") == "<string>" {
					controller.ListAccounts()
				} else {
					controller.ShowAccount(c.String("account"))
				}
			},
		},
		{
			Name:  "accounts:info",
			Usage: "account information",
			Flags: []cli.Flag{
				cli.StringFlag{"account,a", "<string>", "account slug"},
			},
			Description: `
   More detail about a particular account, including name, slug, owner, and users.
      `,
			Action: func(c *cli.Context) {
				controller.ShowAccount(c.String("account"))
			},
		},
		{
			Name:  "backups",
			Usage: "list backups with optional filters",
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "optional deployment filter for backups"},
				cli.StringFlag{"backup,b", "<string>", "optional backup name; if included, will run backups:info"},
			},
			Description: `
   Lists the backups associated with your account or deployment.

   To see a list of all backups on your account, including those from deleted
   deployments, omit the deployment argument.

   To see a list of all backups on a single deployment, include the name or
   id of the intended deployment using the deployment argument.
      `,
			Action: func(c *cli.Context) {
				if c.String("backup") == "<string>" {
					controller.ListBackups(c.String("deployment"))
				} else {
					controller.ShowBackup(c.String("backup"))
				}
			},
		},
		{
			Name:  "backups:create",
			Usage: "create an on-demand backup for a deployment",
			Description: `
   Queues an on-demand backup for a deployment.  To read more about this feature,
   see http://docs.mongohq.com/backups/elastic-deployments.html#on-demand-backups.
      `,
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "deployment name"},
			},
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"deployment"}, []string{})
				controller.CreateBackup(c.String("deployment"))
			},
		},
		{
			Name:  "backups:info",
			Usage: "information on backup",
			Flags: []cli.Flag{
				cli.StringFlag{"backup,b", "<string>", "file name of backup"},
			},
			Description: `
   More detail about a particular backup, including deployment, databases, creation time, type, size, and download link.
      `,
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"backup"}, []string{})
				controller.ShowBackup(c.String("backup"))
			},
		},
		{
			Name:  "backups:restore",
			Usage: "restore backup to a new database",
			Description: `
   Restores a backup of a database to a new, fresh deployment. The new
   deployment will be created in the same datacenter with the same version
   as the source database.
      `,
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "new deployment name"},
				cli.StringFlag{"backup,b", "<string>", "file name of backup"},
				cli.StringFlag{"source-database,source", "<string>", "original database name"},
				cli.StringFlag{"destination-database,destination", "<string>", "new database name"},
			},
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"deployment", "backup", "source-database", "destination-database"}, []string{})
				controller.RestoreBackup(c.String("backup"), c.String("deployment"), c.String("source-database"), c.String("destination-database"))
			},
		},
		{
			Name:  "config:account",
			Usage: "set a default account context",
			Flags: []cli.Flag{
				cli.StringFlag{"account,a", "<string>", "slug for default account"},
			},
			Description: `
   Set a default account so the account flag is not required for each command.
      `,
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"account"}, []string{})
				controller.SetConfigAccount(c.String("account"))
			},
		},
		{
			Name:  "databases:create",
			Usage: "create database on an existing deployment",
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "deployment to create database on"},
				cli.StringFlag{"database,db", "<string>", "new database to create"},
			},
			Description: `
   Create a new database on an existing deployment.  If you are looking to create a
   new database on a new deployment, see the deployments:create command.
      `,
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"deployment", "database"}, []string{})
				controller.CreateDatabase(c.String("deployment"), c.String("database"))
			},
		},
		{
			Name:  "databases:info",
			Usage: "information on database",
			Flags: []cli.Flag{
				cli.StringFlag{"database,db", "<string>", " database for more information"},
				cli.StringFlag{"deployment,dep", "<string>", " deployment containing database"},
			},
			Description: `
   More detail on a particular database, including name, status, and stats.
      `,
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"database", "deployment"}, []string{})
				controller.ShowDatabase(c.String("deployment"), c.String("database"))
			},
		},
		{
			Name:  "databases:remove",
			Usage: "remove database",
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "deployment"},
				cli.StringFlag{"database,db", "<string>", "database to remove"},
				cli.BoolFlag{"force,f", "delete without confirmation"},
			},
			Description: `
   Deletes a database from a deployment.  If this is the last database on the
   deployment, the deployment will also be deleted.

   You will be asked to verify the database name on delete, unless including
   the force argument.
      `,
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"database", "deployment"}, []string{})
				controller.DeleteDatabase(c.String("deployment"), c.String("database"), c.Bool("force"))
			},
		},
		{
			Name:  "deployments",
			Usage: "list deployments",
			Description: `
   List the slugs for all deployments.
      `,
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "optional deployment name; if included runs deployments:info"},
			},
			Action: func(c *cli.Context) {
				if c.String("deployment") == "<string>" {
					controller.ListDeployments()
				} else {
					controller.ShowDeployment(c.String("deployment"))
				}
			},
		},
		{
			Name:  "deployments:create",
			Usage: "create a new Elastic Deployment",
			Flags: []cli.Flag{
				cli.StringFlag{"database,db", "<string>", "new database name"},
				cli.StringFlag{"deployment,dep", "<string>", "new deployment name"},
				cli.StringFlag{"location,l", "<string>", "location of deployment (for list of locations, run 'mongohq locations')"},
			},
			Description: `
   Creates an elastic deployment on the MongoHQ platform. Stick with me here: it will create a new database on a new
   deployment at location you specify.  The deployment is a Replica Set and the database is the logical MongoDB database.
   You can find a list of locations by running "mongohq locations".
      `,
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"deployment", "database", "location"}, []string{})
				controller.CreateDeployment(c.String("deployment"), c.String("database"), c.String("location"))
			},
		},
		{
			Name:  "deployments:info",
			Usage: "information on deployment",
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "deployment for more information"},
			},
			Description: `
   More detail about a particular deployment, including plan, status, location,
   current primary, members, version, and a list of databases.
      `,
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"deployment"}, []string{})
				controller.ShowDeployment(c.String("deployment"))
			},
		},
		{
			Name:  "deployments:rename",
			Usage: "rename a deployment",
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "deployment for more information"},
				cli.StringFlag{"name,n", "<string>", "new name for deployment"},
			},
			Description: `
   Sometime, you want a little more description about a deployment than an hex id.  Use this
   to create a deployment name (only allows alphanumeric characters and hyphens).

   Immediately after making this change, you will need to reference the deployment by the new
   name.
      `,
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"deployment", "name"}, []string{})
				controller.RenameDeployment(c.String("deployment"), c.String("name"))
			},
		},
		{
			Name:  "deployments:remove",
			Usage: "remove a deployment",
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "deployment for more information"},
				cli.BoolFlag{"force,f", "delete without confirmation"},
			},
			Description: `
   Deletes a deployment.  Requires confirmation because this is a very destructive action,
   particularly for data.
      `,
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"deployment"}, []string{})
				controller.DeleteDeployment(c.String("deployment"), c.Bool("force"))
			},
		},
		{
			Name:  "logs",
			Usage: "query historical logs",
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "deployment for querying logs"},
			},
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"deployment"}, []string{})
				controller.HistoricalLogs(c.String("deployment"))
			},
		},
		{
			Name:  "locations",
			Usage: "list available locations",
			Description: `
   List the current locations available for MongoHQ deployments.  Used with both new
   deployments and restoring databases from backups.
      `,
			Action: func(c *cli.Context) {
				controller.ListLocations()
			},
		},
		{
			Name:  "mongostat",
			Usage: "realtime mongostat",
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "deployment for watching mongostats"},
			},
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"deployment"}, []string{})
				controller.DeploymentMongoStat(c.String("deployment"))
			},
		},
		{
			Name:  "users",
			Usage: "list users on a database",
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "deployment id the database is on"},
				cli.StringFlag{"database,db", "<string>", "database to list users"},
			},
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"deployment", "database"}, []string{})
				controller.ListDatabaseUsers(c.String("deployment"), c.String("database"))
			},
		},
		{
			Name:  "users:create",
			Usage: "add user to a database",
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "deployment id the database is on"},
				cli.StringFlag{"database,db", "<string>", "atabase name to create the user on"},
				cli.StringFlag{"username,u", "<string>", "user to create"},
			},
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"deployment", "database", "username"}, []string{})
				controller.CreateDatabaseUser(c.String("deployment"), c.String("database"), c.String("username"))
			},
		},
		{
			Name:  "users:remove",
			Usage: "remove user from database",
			Flags: []cli.Flag{
				cli.StringFlag{"deployment,dep", "<string>", "deployment id the database is on"},
				cli.StringFlag{"database,db", "<string>", "database name to remove the user from"},
				cli.StringFlag{"username,u", "<string>", "user to remove from the deployment"},
			},
			Action: func(c *cli.Context) {
				requireArguments(c, []string{"deployment", "database", "username"}, []string{})
				controller.DeleteDatabaseUser(c.String("deployment"), c.String("database"), c.String("username"))
			},
		},
		{
			Name:  "whoami",
			Usage: "display effective user",
			Action: func(c *cli.Context) {
				controller.CurrentUser()
			},
		},
		{
			Name:  "logout",
			Usage: "remove stored auth",
			Action: func(c *cli.Context) {
				loginController.Logout()
			},
		},
		{
			Name:  "update",
			Usage: "script to update the MongoHQ CLI binary",
			Action: func(c *cli.Context) {
				fmt.Println("To update, run: `curl https://mongohq-cli.s3.amazonaws.com/install.sh | sh`")
			},
		},
	}

	app.Run(os.Args)
}
<|endoftext|>