<commit_before>package alp

import (
	"fmt"
	"io"
	"os"

	"github.com/tkuchiki/alp/flag"
	"github.com/tkuchiki/gohttpstats"
	"github.com/tkuchiki/gohttpstats/options"
	"gopkg.in/alecthomas/kingpin.v2"
)

const version = "0.4.0"

type Profiler struct {
	outWriter    io.Writer
	errWriter    io.Writer
	inReader     *os.File
	optionParser *kingpin.Application
	flags        *flag.Flags
}

func NewProfiler(outw, errw io.Writer) *Profiler {
	p := &Profiler{
		outWriter:    outw,
		errWriter:    errw,
		inReader:     os.Stdin,
		optionParser: kingpin.New("alp", "Access Log Profiler for LTSV (read from file or stdin)."),
	}
	p.flags = flag.NewFlags()

	 p.flags.InitFlags(p.optionParser)

	return p
}

func (p *Profiler) SetFlags(flags *flag.Flags) {
	p.flags = flags
}

func (p *Profiler) SetInReader(f *os.File) {
	p.inReader = f
}

func (p *Profiler) Open(filename string) (*os.File, error) {
	var f *os.File
	var err error

	if filename != "" {
		f, err = os.Open(filename)
	} else {
		f = p.inReader
	}

	return f, err
}

func (p *Profiler) Run() error {
	p.optionParser.Version(version)
	p.optionParser.Parse(os.Args[1:])

	var sort string
	if p.flags.Max {
		sort = httpstats.SortMaxResponseTime
	} else if p.flags.Min {
		sort = httpstats.SortMinResponseTime
	} else if p.flags.Avg {
		sort = httpstats.SortAvgResponseTime
	} else if p.flags.Sum {
		sort = httpstats.SortSumResponseTime
	} else if p.flags.Cnt {
		sort = httpstats.SortCount
	} else if p.flags.P1 {
		sort = httpstats.SortP1ResponseTime
	} else if p.flags.P50 {
		sort = httpstats.SortP50ResponseTime
	} else if p.flags.P99 {
		sort = httpstats.SortP99ResponseTime
	} else if p.flags.Stddev {
		sort = httpstats.SortStddevResponseTime
	} else if p.flags.SortUri {
		sort = httpstats.SortUri
	} else if p.flags.Method {
		sort = httpstats.SortMethod
	} else if p.flags.MaxBody {
		sort = httpstats.SortMaxResponseBodySize
	} else if p.flags.MinBody {
		sort = httpstats.SortMinResponseBodySize
	} else if p.flags.AvgBody {
		sort = httpstats.SortAvgResponseBodySize
	} else if p.flags.SumBody {
		sort = httpstats.SortSumResponseBodySize
	} else {
		sort = httpstats.SortMaxResponseTime
	}

	var err error
	var options *stats_options.Options
	if p.flags.Config != "" {
		cf, err := os.Open(p.flags.Config)
		if err != nil {
			return err
		}
		defer cf.Close()

		options, err = stats_options.LoadOptionsFromReader(cf)
		if err != nil {
			return err
		}
	} else {
		options = stats_options.NewOptions()
	}

	options = stats_options.SetOptions(options,
		stats_options.File(p.flags.File),
		stats_options.Sort(sort),
		stats_options.Reverse(p.flags.Reverse),
		stats_options.QueryString(p.flags.QueryString),
		stats_options.Tsv(p.flags.Tsv),
		stats_options.ApptimeLabel(p.flags.ApptimeLabel),
		stats_options.ReqtimeLabel(p.flags.ReqtimeLabel),
		stats_options.StatusLabel(p.flags.StatusLabel),
		stats_options.SizeLabel(p.flags.SizeLabel),
		stats_options.MethodLabel(p.flags.MethodLabel),
		stats_options.UriLabel(p.flags.UriLabel),
		stats_options.TimeLabel(p.flags.TimeLabel),
		stats_options.Limit(p.flags.Limit),
		stats_options.NoHeaders(p.flags.NoHeaders),
		stats_options.StartTime(p.flags.StartTime),
		stats_options.EndTime(p.flags.EndTime),
		stats_options.StartTimeDuration(p.flags.StartTimeDuration),
		stats_options.EndTimeDuration(p.flags.EndTimeDuration),
		stats_options.CSVIncludes(p.flags.Includes),
		stats_options.CSVExcludes(p.flags.Excludes),
		stats_options.CSVIncludeStatuses(p.flags.IncludeStatuses),
		stats_options.CSVExcludeStatuses(p.flags.ExcludeStatuses),
		stats_options.CSVAggregates(p.flags.Aggregates),
	)

	po := httpstats.NewPrintOptions()
	po.SetWriter(p.outWriter)
	stats := httpstats.NewHTTPStats(true, false, false, po)

	err = stats.InitFilter(options)
	if err != nil {
		return err
	}

	stats.SetOptions(options)

	if p.flags.Load != "" {
		lf, err := os.Open(p.flags.Load)
		if err != nil {
			return err
		}
		err = stats.LoadStats(lf)
		if err != nil {
			return err
		}
		defer lf.Close()

		stats.SortWithOptions()
		stats.Print()
		return nil
	}

	f, err := p.Open(options.File)
	if err != nil {
		return err
	}
	defer f.Close()

	if len(options.Aggregates) > 0 {
		err = stats.SetURICapturingGroups(options.Aggregates)
		if err != nil {
			return err
		}
	}

	err = stats.InitParser("ltsv", f)
	if err != nil {
		return err
	}

Loop:
	for {
		uri, method, timestr, resTime, bodySize, status, err := stats.Parse()
		if err != nil {
			if err == io.EOF {
				break
			} else if err == httpstats.SkipReadLineErr {
				continue Loop
			}

			return err
		}

		if !stats.DoFilter(uri, method, timestr) {
			continue Loop
		}

		stats.Set(uri, method, status, resTime, bodySize, 0)

		if stats.CountUris() > options.Limit {
			return fmt.Errorf("Too many URI's (%d or less)", options.Limit)
		}
	}

	if p.flags.Dump != "" {
		df, err := os.OpenFile(p.flags.Dump, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
		err = stats.DumpStats(df)
		if err != nil {
			return err
		}
		defer df.Close()
	}

	stats.SortWithOptions()
	stats.Print()

	return nil
}
<commit_msg>[bugfix] Enable --tsv option<commit_after>package alp

import (
	"fmt"
	"io"
	"os"

	"github.com/tkuchiki/alp/flag"
	"github.com/tkuchiki/gohttpstats"
	"github.com/tkuchiki/gohttpstats/options"
	"gopkg.in/alecthomas/kingpin.v2"
)

const version = "0.4.0"

type Profiler struct {
	outWriter    io.Writer
	errWriter    io.Writer
	inReader     *os.File
	optionParser *kingpin.Application
	flags        *flag.Flags
}

func NewProfiler(outw, errw io.Writer) *Profiler {
	p := &Profiler{
		outWriter:    outw,
		errWriter:    errw,
		inReader:     os.Stdin,
		optionParser: kingpin.New("alp", "Access Log Profiler for LTSV (read from file or stdin)."),
	}
	p.flags = flag.NewFlags()

	p.flags.InitFlags(p.optionParser)

	return p
}

func (p *Profiler) SetFlags(flags *flag.Flags) {
	p.flags = flags
}

func (p *Profiler) SetInReader(f *os.File) {
	p.inReader = f
}

func (p *Profiler) Open(filename string) (*os.File, error) {
	var f *os.File
	var err error

	if filename != "" {
		f, err = os.Open(filename)
	} else {
		f = p.inReader
	}

	return f, err
}

func (p *Profiler) Run() error {
	p.optionParser.Version(version)
	p.optionParser.Parse(os.Args[1:])

	var sort string
	if p.flags.Max {
		sort = httpstats.SortMaxResponseTime
	} else if p.flags.Min {
		sort = httpstats.SortMinResponseTime
	} else if p.flags.Avg {
		sort = httpstats.SortAvgResponseTime
	} else if p.flags.Sum {
		sort = httpstats.SortSumResponseTime
	} else if p.flags.Cnt {
		sort = httpstats.SortCount
	} else if p.flags.P1 {
		sort = httpstats.SortP1ResponseTime
	} else if p.flags.P50 {
		sort = httpstats.SortP50ResponseTime
	} else if p.flags.P99 {
		sort = httpstats.SortP99ResponseTime
	} else if p.flags.Stddev {
		sort = httpstats.SortStddevResponseTime
	} else if p.flags.SortUri {
		sort = httpstats.SortUri
	} else if p.flags.Method {
		sort = httpstats.SortMethod
	} else if p.flags.MaxBody {
		sort = httpstats.SortMaxResponseBodySize
	} else if p.flags.MinBody {
		sort = httpstats.SortMinResponseBodySize
	} else if p.flags.AvgBody {
		sort = httpstats.SortAvgResponseBodySize
	} else if p.flags.SumBody {
		sort = httpstats.SortSumResponseBodySize
	} else {
		sort = httpstats.SortMaxResponseTime
	}

	var err error
	var options *stats_options.Options
	if p.flags.Config != "" {
		cf, err := os.Open(p.flags.Config)
		if err != nil {
			return err
		}
		defer cf.Close()

		options, err = stats_options.LoadOptionsFromReader(cf)
		if err != nil {
			return err
		}
	} else {
		options = stats_options.NewOptions()
	}

	options = stats_options.SetOptions(options,
		stats_options.File(p.flags.File),
		stats_options.Sort(sort),
		stats_options.Reverse(p.flags.Reverse),
		stats_options.QueryString(p.flags.QueryString),
		stats_options.Tsv(p.flags.Tsv),
		stats_options.ApptimeLabel(p.flags.ApptimeLabel),
		stats_options.ReqtimeLabel(p.flags.ReqtimeLabel),
		stats_options.StatusLabel(p.flags.StatusLabel),
		stats_options.SizeLabel(p.flags.SizeLabel),
		stats_options.MethodLabel(p.flags.MethodLabel),
		stats_options.UriLabel(p.flags.UriLabel),
		stats_options.TimeLabel(p.flags.TimeLabel),
		stats_options.Limit(p.flags.Limit),
		stats_options.NoHeaders(p.flags.NoHeaders),
		stats_options.StartTime(p.flags.StartTime),
		stats_options.EndTime(p.flags.EndTime),
		stats_options.StartTimeDuration(p.flags.StartTimeDuration),
		stats_options.EndTimeDuration(p.flags.EndTimeDuration),
		stats_options.CSVIncludes(p.flags.Includes),
		stats_options.CSVExcludes(p.flags.Excludes),
		stats_options.CSVIncludeStatuses(p.flags.IncludeStatuses),
		stats_options.CSVExcludeStatuses(p.flags.ExcludeStatuses),
		stats_options.CSVAggregates(p.flags.Aggregates),
	)

	po := httpstats.NewPrintOptions()
	po.SetWriter(p.outWriter)
	if options.Tsv {
		po.SetFormat("tsv")
	}
	stats := httpstats.NewHTTPStats(true, false, false, po)

	err = stats.InitFilter(options)
	if err != nil {
		return err
	}

	stats.SetOptions(options)

	if p.flags.Load != "" {
		lf, err := os.Open(p.flags.Load)
		if err != nil {
			return err
		}
		err = stats.LoadStats(lf)
		if err != nil {
			return err
		}
		defer lf.Close()

		stats.SortWithOptions()
		stats.Print()
		return nil
	}

	f, err := p.Open(options.File)
	if err != nil {
		return err
	}
	defer f.Close()

	if len(options.Aggregates) > 0 {
		err = stats.SetURICapturingGroups(options.Aggregates)
		if err != nil {
			return err
		}
	}

	err = stats.InitParser("ltsv", f)
	if err != nil {
		return err
	}

Loop:
	for {
		uri, method, timestr, resTime, bodySize, status, err := stats.Parse()
		if err != nil {
			if err == io.EOF {
				break
			} else if err == httpstats.SkipReadLineErr {
				continue Loop
			}

			return err
		}

		if !stats.DoFilter(uri, method, timestr) {
			continue Loop
		}

		stats.Set(uri, method, status, resTime, bodySize, 0)

		if stats.CountUris() > options.Limit {
			return fmt.Errorf("Too many URI's (%d or less)", options.Limit)
		}
	}

	if p.flags.Dump != "" {
		df, err := os.OpenFile(p.flags.Dump, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
		err = stats.DumpStats(df)
		if err != nil {
			return err
		}
		defer df.Close()
	}

	stats.SortWithOptions()
	stats.Print()

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package models

import (
	"fmt"
	"os"

	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/timeutil"
	"code.gitea.io/gitea/modules/util"
)

// RepoTransfer is used to manage repository transfers
type RepoTransfer struct {
	ID          int64 `xorm:"pk autoincr"`
	DoerID      int64
	Doer        *User `xorm:"-"`
	RecipientID int64
	Recipient   *User `xorm:"-"`
	RepoID      int64
	TeamIDs     []int64
	Teams       []*Team `xorm:"-"`

	CreatedUnix timeutil.TimeStamp `xorm:"INDEX NOT NULL created"`
	UpdatedUnix timeutil.TimeStamp `xorm:"INDEX NOT NULL updated"`
}

// LoadAttributes fetches the transfer recipient from the database
func (r *RepoTransfer) LoadAttributes() error {
	if r.Recipient == nil {
		u, err := GetUserByID(r.RecipientID)
		if err != nil {
			return err
		}

		r.Recipient = u
	}

	if r.Recipient.IsOrganization() && len(r.TeamIDs) != len(r.Teams) {

		for _, v := range r.TeamIDs {
			team, err := GetTeamByID(v)
			if err != nil {
				return err
			}

			if team.OrgID != r.Recipient.ID {
				return fmt.Errorf("team %d belongs not to org %d", v, r.Recipient.ID)
			}

			r.Teams = append(r.Teams, team)
		}
	}

	if r.Doer == nil {
		u, err := GetUserByID(r.DoerID)
		if err != nil {
			return err
		}

		r.Doer = u
	}

	return nil
}

// CanUserAcceptTransfer checks if the user has the rights to accept/decline a repo transfer.
// For user, it checks if it's himself
// For organizations, it checks if the user is able to create repos
func (r *RepoTransfer) CanUserAcceptTransfer(u *User) bool {
	if err := r.LoadAttributes(); err != nil {
		log.Error("LoadAttributes: %v", err)
		return false
	}

	if !r.Recipient.IsOrganization() {
		return r.RecipientID == u.ID
	}

	allowed, err := CanCreateOrgRepo(r.RecipientID, u.ID)
	if err != nil {
		log.Error("CanCreateOrgRepo: %v", err)
		return false
	}

	return allowed
}

// GetPendingRepositoryTransfer fetches the most recent and ongoing transfer
// process for the repository
func GetPendingRepositoryTransfer(repo *Repository) (*RepoTransfer, error) {
	var transfer = new(RepoTransfer)

	has, err := x.Where("repo_id = ? ", repo.ID).Get(transfer)
	if err != nil {
		return nil, err
	}

	if !has {
		return nil, ErrNoPendingRepoTransfer{RepoID: repo.ID}
	}

	return transfer, nil
}

func deleteRepositoryTransfer(e Engine, repoID int64) error {
	_, err := e.Where("repo_id = ?", repoID).Delete(&RepoTransfer{})
	return err
}

// CancelRepositoryTransfer marks the repository as ready and remove pending transfer entry,
// thus cancel the transfer process.
func CancelRepositoryTransfer(repo *Repository) error {
	sess := x.NewSession()
	defer sess.Close()
	if err := sess.Begin(); err != nil {
		return err
	}

	repo.Status = RepositoryReady
	if err := updateRepositoryCols(sess, repo, "status"); err != nil {
		return err
	}

	if err := deleteRepositoryTransfer(sess, repo.ID); err != nil {
		return err
	}

	return sess.Commit()
}

// TestRepositoryReadyForTransfer make sure repo is ready to transfer
func TestRepositoryReadyForTransfer(status RepositoryStatus) error {
	switch status {
	case RepositoryBeingMigrated:
		return fmt.Errorf("repo is not ready, currently migrating")
	case RepositoryPendingTransfer:
		return ErrRepoTransferInProgress{}
	}
	return nil
}

// CreatePendingRepositoryTransfer transfer a repo from one owner to a new one.
// it marks the repository transfer as "pending"
func CreatePendingRepositoryTransfer(doer, newOwner *User, repoID int64, teams []*Team) error {
	sess := x.NewSession()
	defer sess.Close()
	if err := sess.Begin(); err != nil {
		return err
	}

	repo, err := getRepositoryByID(sess, repoID)
	if err != nil {
		return err
	}

	// Make sure repo is ready to transfer
	if err := TestRepositoryReadyForTransfer(repo.Status); err != nil {
		return err
	}

	repo.Status = RepositoryPendingTransfer
	if err := updateRepositoryCols(sess, repo, "status"); err != nil {
		return err
	}

	// Check if new owner has repository with same name.
	if has, err := isRepositoryExist(sess, newOwner, repo.Name); err != nil {
		return fmt.Errorf("IsRepositoryExist: %v", err)
	} else if has {
		return ErrRepoAlreadyExist{newOwner.LowerName, repo.Name}
	}

	transfer := &RepoTransfer{
		RepoID:      repo.ID,
		RecipientID: newOwner.ID,
		CreatedUnix: timeutil.TimeStampNow(),
		UpdatedUnix: timeutil.TimeStampNow(),
		DoerID:      doer.ID,
		TeamIDs:     make([]int64, 0, len(teams)),
	}

	for k := range teams {
		transfer.TeamIDs = append(transfer.TeamIDs, teams[k].ID)
	}

	if _, err := sess.Insert(transfer); err != nil {
		return err
	}

	return sess.Commit()
}

// TransferOwnership transfers all corresponding repository items from old user to new one.
func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error {
	sess := x.NewSession()
	defer sess.Close()
	if err := sess.Begin(); err != nil {
		return fmt.Errorf("sess.Begin: %v", err)
	}

	newOwner, err := getUserByName(sess, newOwnerName)
	if err != nil {
		return fmt.Errorf("get new owner '%s': %v", newOwnerName, err)
	}

	// Check if new owner has repository with same name.
	if has, err := isRepositoryExist(sess, newOwner, repo.Name); err != nil {
		return fmt.Errorf("IsRepositoryExist: %v", err)
	} else if has {
		return ErrRepoAlreadyExist{newOwnerName, repo.Name}
	}

	oldOwner := repo.Owner

	// Note: we have to set value here to make sure recalculate accesses is based on
	// new owner.
	repo.OwnerID = newOwner.ID
	repo.Owner = newOwner
	repo.OwnerName = newOwner.Name

	// Update repository.
	if _, err := sess.ID(repo.ID).Update(repo); err != nil {
		return fmt.Errorf("update owner: %v", err)
	}

	// Remove redundant collaborators.
	collaborators, err := repo.getCollaborators(sess, ListOptions{})
	if err != nil {
		return fmt.Errorf("getCollaborators: %v", err)
	}

	// Dummy object.
	collaboration := &Collaboration{RepoID: repo.ID}
	for _, c := range collaborators {
		if c.ID != newOwner.ID {
			isMember, err := isOrganizationMember(sess, newOwner.ID, c.ID)
			if err != nil {
				return fmt.Errorf("IsOrgMember: %v", err)
			} else if !isMember {
				continue
			}
		}
		collaboration.UserID = c.ID
		if _, err := sess.Delete(collaboration); err != nil {
			return fmt.Errorf("remove collaborator '%d': %v", c.ID, err)
		}
	}

	// Remove old team-repository relations.
	if oldOwner.IsOrganization() {
		if err := oldOwner.removeOrgRepo(sess, repo.ID); err != nil {
			return fmt.Errorf("removeOrgRepo: %v", err)
		}
	}

	if newOwner.IsOrganization() {
		if err := newOwner.getTeams(sess); err != nil {
			return fmt.Errorf("GetTeams: %v", err)
		}
		for _, t := range newOwner.Teams {
			if t.IncludesAllRepositories {
				if err := t.addRepository(sess, repo); err != nil {
					return fmt.Errorf("addRepository: %v", err)
				}
			}
		}
	} else if err := repo.recalculateAccesses(sess); err != nil {
		// Organization called this in addRepository method.
		return fmt.Errorf("recalculateAccesses: %v", err)
	}

	// Update repository count.
	if _, err := sess.Exec("UPDATE `user` SET num_repos=num_repos+1 WHERE id=?", newOwner.ID); err != nil {
		return fmt.Errorf("increase new owner repository count: %v", err)
	} else if _, err := sess.Exec("UPDATE `user` SET num_repos=num_repos-1 WHERE id=?", oldOwner.ID); err != nil {
		return fmt.Errorf("decrease old owner repository count: %v", err)
	}

	if err := watchRepo(sess, doer.ID, repo.ID, true); err != nil {
		return fmt.Errorf("watchRepo: %v", err)
	}

	// Remove watch for organization.
	if oldOwner.IsOrganization() {
		if err := watchRepo(sess, oldOwner.ID, repo.ID, false); err != nil {
			return fmt.Errorf("watchRepo [false]: %v", err)
		}
	}

	// Rename remote repository to new path and delete local copy.
	dir := UserPath(newOwner.Name)

	if err := os.MkdirAll(dir, os.ModePerm); err != nil {
		return fmt.Errorf("Failed to create dir %s: %v", dir, err)
	}

	if err := os.Rename(RepoPath(oldOwner.Name, repo.Name), RepoPath(newOwner.Name, repo.Name)); err != nil {
		return fmt.Errorf("rename repository directory: %v", err)
	}

	// Rename remote wiki repository to new path and delete local copy.
	wikiPath := WikiPath(oldOwner.Name, repo.Name)

	if isExist, err := util.IsExist(wikiPath); err != nil {
		log.Error("Unable to check if %s exists. Error: %v", wikiPath, err)
		return err
	} else if isExist {
		if err := os.Rename(wikiPath, WikiPath(newOwner.Name, repo.Name)); err != nil {
			return fmt.Errorf("rename repository wiki: %v", err)
		}
	}

	if err := deleteRepositoryTransfer(sess, repo.ID); err != nil {
		return fmt.Errorf("deleteRepositoryTransfer: %v", err)
	}
	repo.Status = RepositoryReady
	if err := updateRepositoryCols(sess, repo, "status"); err != nil {
		return err
	}

	// If there was previously a redirect at this location, remove it.
	if err := deleteRepoRedirect(sess, newOwner.ID, repo.Name); err != nil {
		return fmt.Errorf("delete repo redirect: %v", err)
	}

	if err := newRepoRedirect(sess, oldOwner.ID, repo.ID, repo.Name, repo.Name); err != nil {
		return fmt.Errorf("newRepoRedirect: %v", err)
	}

	return sess.Commit()
}
<commit_msg>When transfering repository and database transaction failed, rollback the renames (#14864)<commit_after>// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package models

import (
	"fmt"
	"os"

	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/timeutil"
	"code.gitea.io/gitea/modules/util"
)

// RepoTransfer is used to manage repository transfers
type RepoTransfer struct {
	ID          int64 `xorm:"pk autoincr"`
	DoerID      int64
	Doer        *User `xorm:"-"`
	RecipientID int64
	Recipient   *User `xorm:"-"`
	RepoID      int64
	TeamIDs     []int64
	Teams       []*Team `xorm:"-"`

	CreatedUnix timeutil.TimeStamp `xorm:"INDEX NOT NULL created"`
	UpdatedUnix timeutil.TimeStamp `xorm:"INDEX NOT NULL updated"`
}

// LoadAttributes fetches the transfer recipient from the database
func (r *RepoTransfer) LoadAttributes() error {
	if r.Recipient == nil {
		u, err := GetUserByID(r.RecipientID)
		if err != nil {
			return err
		}

		r.Recipient = u
	}

	if r.Recipient.IsOrganization() && len(r.TeamIDs) != len(r.Teams) {

		for _, v := range r.TeamIDs {
			team, err := GetTeamByID(v)
			if err != nil {
				return err
			}

			if team.OrgID != r.Recipient.ID {
				return fmt.Errorf("team %d belongs not to org %d", v, r.Recipient.ID)
			}

			r.Teams = append(r.Teams, team)
		}
	}

	if r.Doer == nil {
		u, err := GetUserByID(r.DoerID)
		if err != nil {
			return err
		}

		r.Doer = u
	}

	return nil
}

// CanUserAcceptTransfer checks if the user has the rights to accept/decline a repo transfer.
// For user, it checks if it's himself
// For organizations, it checks if the user is able to create repos
func (r *RepoTransfer) CanUserAcceptTransfer(u *User) bool {
	if err := r.LoadAttributes(); err != nil {
		log.Error("LoadAttributes: %v", err)
		return false
	}

	if !r.Recipient.IsOrganization() {
		return r.RecipientID == u.ID
	}

	allowed, err := CanCreateOrgRepo(r.RecipientID, u.ID)
	if err != nil {
		log.Error("CanCreateOrgRepo: %v", err)
		return false
	}

	return allowed
}

// GetPendingRepositoryTransfer fetches the most recent and ongoing transfer
// process for the repository
func GetPendingRepositoryTransfer(repo *Repository) (*RepoTransfer, error) {
	var transfer = new(RepoTransfer)

	has, err := x.Where("repo_id = ? ", repo.ID).Get(transfer)
	if err != nil {
		return nil, err
	}

	if !has {
		return nil, ErrNoPendingRepoTransfer{RepoID: repo.ID}
	}

	return transfer, nil
}

func deleteRepositoryTransfer(e Engine, repoID int64) error {
	_, err := e.Where("repo_id = ?", repoID).Delete(&RepoTransfer{})
	return err
}

// CancelRepositoryTransfer marks the repository as ready and remove pending transfer entry,
// thus cancel the transfer process.
func CancelRepositoryTransfer(repo *Repository) error {
	sess := x.NewSession()
	defer sess.Close()
	if err := sess.Begin(); err != nil {
		return err
	}

	repo.Status = RepositoryReady
	if err := updateRepositoryCols(sess, repo, "status"); err != nil {
		return err
	}

	if err := deleteRepositoryTransfer(sess, repo.ID); err != nil {
		return err
	}

	return sess.Commit()
}

// TestRepositoryReadyForTransfer make sure repo is ready to transfer
func TestRepositoryReadyForTransfer(status RepositoryStatus) error {
	switch status {
	case RepositoryBeingMigrated:
		return fmt.Errorf("repo is not ready, currently migrating")
	case RepositoryPendingTransfer:
		return ErrRepoTransferInProgress{}
	}
	return nil
}

// CreatePendingRepositoryTransfer transfer a repo from one owner to a new one.
// it marks the repository transfer as "pending"
func CreatePendingRepositoryTransfer(doer, newOwner *User, repoID int64, teams []*Team) error {
	sess := x.NewSession()
	defer sess.Close()
	if err := sess.Begin(); err != nil {
		return err
	}

	repo, err := getRepositoryByID(sess, repoID)
	if err != nil {
		return err
	}

	// Make sure repo is ready to transfer
	if err := TestRepositoryReadyForTransfer(repo.Status); err != nil {
		return err
	}

	repo.Status = RepositoryPendingTransfer
	if err := updateRepositoryCols(sess, repo, "status"); err != nil {
		return err
	}

	// Check if new owner has repository with same name.
	if has, err := isRepositoryExist(sess, newOwner, repo.Name); err != nil {
		return fmt.Errorf("IsRepositoryExist: %v", err)
	} else if has {
		return ErrRepoAlreadyExist{newOwner.LowerName, repo.Name}
	}

	transfer := &RepoTransfer{
		RepoID:      repo.ID,
		RecipientID: newOwner.ID,
		CreatedUnix: timeutil.TimeStampNow(),
		UpdatedUnix: timeutil.TimeStampNow(),
		DoerID:      doer.ID,
		TeamIDs:     make([]int64, 0, len(teams)),
	}

	for k := range teams {
		transfer.TeamIDs = append(transfer.TeamIDs, teams[k].ID)
	}

	if _, err := sess.Insert(transfer); err != nil {
		return err
	}

	return sess.Commit()
}

// TransferOwnership transfers all corresponding repository items from old user to new one.
func TransferOwnership(doer *User, newOwnerName string, repo *Repository) (err error) {
	repoRenamed := false
	wikiRenamed := false
	oldOwnerName := doer.Name

	defer func() {
		if !repoRenamed && !wikiRenamed {
			return
		}

		recoverErr := recover()
		if err == nil && recoverErr == nil {
			return
		}

		if repoRenamed {
			if err := os.Rename(RepoPath(newOwnerName, repo.Name), RepoPath(oldOwnerName, repo.Name)); err != nil {
				log.Critical("Unable to move repository %s/%s directory from %s back to correct place %s: %v", oldOwnerName, repo.Name, RepoPath(newOwnerName, repo.Name), RepoPath(oldOwnerName, repo.Name), err)
			}
		}

		if wikiRenamed {
			if err := os.Rename(WikiPath(newOwnerName, repo.Name), WikiPath(oldOwnerName, repo.Name)); err != nil {
				log.Critical("Unable to move wiki for repository %s/%s directory from %s back to correct place %s: %v", oldOwnerName, repo.Name, WikiPath(newOwnerName, repo.Name), WikiPath(oldOwnerName, repo.Name), err)
			}
		}

		if recoverErr != nil {
			log.Error("Panic within TransferOwnership: %v\n%s", recoverErr, log.Stack(2))
			panic(recoverErr)
		}
	}()

	sess := x.NewSession()
	defer sess.Close()
	if err := sess.Begin(); err != nil {
		return fmt.Errorf("sess.Begin: %v", err)
	}

	newOwner, err := getUserByName(sess, newOwnerName)
	if err != nil {
		return fmt.Errorf("get new owner '%s': %v", newOwnerName, err)
	}
	newOwnerName = newOwner.Name // ensure capitalisation matches

	// Check if new owner has repository with same name.
	if has, err := isRepositoryExist(sess, newOwner, repo.Name); err != nil {
		return fmt.Errorf("IsRepositoryExist: %v", err)
	} else if has {
		return ErrRepoAlreadyExist{newOwnerName, repo.Name}
	}

	oldOwner := repo.Owner
	oldOwnerName = oldOwner.Name

	// Note: we have to set value here to make sure recalculate accesses is based on
	// new owner.
	repo.OwnerID = newOwner.ID
	repo.Owner = newOwner
	repo.OwnerName = newOwner.Name

	// Update repository.
	if _, err := sess.ID(repo.ID).Update(repo); err != nil {
		return fmt.Errorf("update owner: %v", err)
	}

	// Remove redundant collaborators.
	collaborators, err := repo.getCollaborators(sess, ListOptions{})
	if err != nil {
		return fmt.Errorf("getCollaborators: %v", err)
	}

	// Dummy object.
	collaboration := &Collaboration{RepoID: repo.ID}
	for _, c := range collaborators {
		if c.ID != newOwner.ID {
			isMember, err := isOrganizationMember(sess, newOwner.ID, c.ID)
			if err != nil {
				return fmt.Errorf("IsOrgMember: %v", err)
			} else if !isMember {
				continue
			}
		}
		collaboration.UserID = c.ID
		if _, err := sess.Delete(collaboration); err != nil {
			return fmt.Errorf("remove collaborator '%d': %v", c.ID, err)
		}
	}

	// Remove old team-repository relations.
	if oldOwner.IsOrganization() {
		if err := oldOwner.removeOrgRepo(sess, repo.ID); err != nil {
			return fmt.Errorf("removeOrgRepo: %v", err)
		}
	}

	if newOwner.IsOrganization() {
		if err := newOwner.getTeams(sess); err != nil {
			return fmt.Errorf("GetTeams: %v", err)
		}
		for _, t := range newOwner.Teams {
			if t.IncludesAllRepositories {
				if err := t.addRepository(sess, repo); err != nil {
					return fmt.Errorf("addRepository: %v", err)
				}
			}
		}
	} else if err := repo.recalculateAccesses(sess); err != nil {
		// Organization called this in addRepository method.
		return fmt.Errorf("recalculateAccesses: %v", err)
	}

	// Update repository count.
	if _, err := sess.Exec("UPDATE `user` SET num_repos=num_repos+1 WHERE id=?", newOwner.ID); err != nil {
		return fmt.Errorf("increase new owner repository count: %v", err)
	} else if _, err := sess.Exec("UPDATE `user` SET num_repos=num_repos-1 WHERE id=?", oldOwner.ID); err != nil {
		return fmt.Errorf("decrease old owner repository count: %v", err)
	}

	if err := watchRepo(sess, doer.ID, repo.ID, true); err != nil {
		return fmt.Errorf("watchRepo: %v", err)
	}

	// Remove watch for organization.
	if oldOwner.IsOrganization() {
		if err := watchRepo(sess, oldOwner.ID, repo.ID, false); err != nil {
			return fmt.Errorf("watchRepo [false]: %v", err)
		}
	}

	// Rename remote repository to new path and delete local copy.
	dir := UserPath(newOwner.Name)

	if err := os.MkdirAll(dir, os.ModePerm); err != nil {
		return fmt.Errorf("Failed to create dir %s: %v", dir, err)
	}

	if err := os.Rename(RepoPath(oldOwner.Name, repo.Name), RepoPath(newOwner.Name, repo.Name)); err != nil {
		return fmt.Errorf("rename repository directory: %v", err)
	}
	repoRenamed = true

	// Rename remote wiki repository to new path and delete local copy.
	wikiPath := WikiPath(oldOwner.Name, repo.Name)

	if isExist, err := util.IsExist(wikiPath); err != nil {
		log.Error("Unable to check if %s exists. Error: %v", wikiPath, err)
		return err
	} else if isExist {
		if err := os.Rename(wikiPath, WikiPath(newOwner.Name, repo.Name)); err != nil {
			return fmt.Errorf("rename repository wiki: %v", err)
		}
		wikiRenamed = true
	}

	if err := deleteRepositoryTransfer(sess, repo.ID); err != nil {
		return fmt.Errorf("deleteRepositoryTransfer: %v", err)
	}
	repo.Status = RepositoryReady
	if err := updateRepositoryCols(sess, repo, "status"); err != nil {
		return err
	}

	// If there was previously a redirect at this location, remove it.
	if err := deleteRepoRedirect(sess, newOwner.ID, repo.Name); err != nil {
		return fmt.Errorf("delete repo redirect: %v", err)
	}

	if err := newRepoRedirect(sess, oldOwner.ID, repo.ID, repo.Name, repo.Name); err != nil {
		return fmt.Errorf("newRepoRedirect: %v", err)
	}

	return sess.Commit()
}
<|endoftext|>


<commit_before>package goprismic

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
)

type Api struct {
	URL         string
	AccessToken string
	Data        ApiData
}

type ApiData struct {
	Forms         map[string]Form   `json:"forms"`
	Refs          []Ref             `json:"refs"`
	Bookmarks     map[string]string `json:"bookmarks"`
	Tags          []string          `json:"tags"`
	Types         map[string]string `json:"types"`
	OAuthInitiate string            `json:"oauth_initiate"`
	OAuthToken    string            `json:"oauth_token"`
}

// Api entry point
func Get(u, accessToken string) (*Api, error) {
	api := &Api{AccessToken: accessToken, URL: u}
	api.Data.Refs = make([]Ref, 0, 128)
	err := api.call(api.URL, map[string]string{}, &api.Data)
	return api, err
}

// Fetches the master ref
func (a *Api) Master() *SearchForm {
	for _, r := range a.Data.Refs {
		if r.IsMasterRef {
			return a.createSearchForm(r)
		}
	}
	return &SearchForm{err: fmt.Errorf("Master ref not found !?!")}
}

// Fetch another ref
func (a *Api) Ref(label string) *SearchForm {
	for _, r := range a.Data.Refs {
		if r.Label == label {
			return a.createSearchForm(r)
		}
	}
	return &SearchForm{err: fmt.Errorf("No ref found with label '%s'", label)}
}

func (a *Api) createSearchForm(r Ref) *SearchForm {
	f := &SearchForm{api: a, ref: r}
	f.data = make(map[string]string)
	return f
}

func (a *Api) call(u string, data map[string]string, res interface{}) error {
	callurl, errparse := url.Parse(u)
	if errparse != nil {
		return errparse
	}

	values := callurl.Query()
	for k, v := range data {
		values.Set(k, v)
	}
	if a.AccessToken != "" {
		values.Set("access_token", a.AccessToken)
	}
	callurl.RawQuery = values.Encode()

	req, errreq := http.NewRequest("GET", callurl.String(), nil)
	if errreq != nil {
		return errreq
	}
	req.Header.Add("Accept", "application/json")
	resp, errdo := http.DefaultClient.Do(req)
	defer resp.Body.Close()
	if errdo != nil {
		return errdo
	}
	encoded, errread := ioutil.ReadAll(resp.Body)
	if errread != nil {
		return errread
	}
	if resp.StatusCode != 200 {
		err := new(PrismicError)
		errjson := json.Unmarshal(encoded, err)
		if errjson != nil {
			return errjson
		} else {
			return err
		}
	}
	errjson := json.Unmarshal(encoded, res)
	return errjson
}
<commit_msg>Add Api.Refresh() to refresh Api data<commit_after>package goprismic

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
)

type Api struct {
	URL         string
	AccessToken string
	Data        ApiData
}

type ApiData struct {
	Forms         map[string]Form   `json:"forms"`
	Refs          []Ref             `json:"refs"`
	Bookmarks     map[string]string `json:"bookmarks"`
	Tags          []string          `json:"tags"`
	Types         map[string]string `json:"types"`
	OAuthInitiate string            `json:"oauth_initiate"`
	OAuthToken    string            `json:"oauth_token"`
}

// Api entry point
func Get(u, accessToken string) (*Api, error) {
	api := &Api{AccessToken: accessToken, URL: u}
	api.Data.Refs = make([]Ref, 0, 128)
	err := api.call(api.URL, map[string]string{}, &api.Data)
	return api, err
}

// Refreshes the Api data
func (a *Api) Refresh() error{
	return a.call(a.URL, map[string]string{}, &a.Data)
}

// Fetches the master ref
func (a *Api) Master() *SearchForm {
	for _, r := range a.Data.Refs {
		if r.IsMasterRef {
			return a.createSearchForm(r)
		}
	}
	return &SearchForm{err: fmt.Errorf("Master ref not found !?!")}
}

// Fetch another ref
func (a *Api) Ref(label string) *SearchForm {
	for _, r := range a.Data.Refs {
		if r.Label == label {
			return a.createSearchForm(r)
		}
	}
	return &SearchForm{err: fmt.Errorf("No ref found with label '%s'", label)}
}

func (a *Api) createSearchForm(r Ref) *SearchForm {
	f := &SearchForm{api: a, ref: r}
	f.data = make(map[string]string)
	return f
}

func (a *Api) call(u string, data map[string]string, res interface{}) error {
	callurl, errparse := url.Parse(u)
	if errparse != nil {
		return errparse
	}

	values := callurl.Query()
	for k, v := range data {
		values.Set(k, v)
	}
	if a.AccessToken != "" {
		values.Set("access_token", a.AccessToken)
	}
	callurl.RawQuery = values.Encode()

	req, errreq := http.NewRequest("GET", callurl.String(), nil)
	if errreq != nil {
		return errreq
	}
	req.Header.Add("Accept", "application/json")
	resp, errdo := http.DefaultClient.Do(req)
	defer resp.Body.Close()
	if errdo != nil {
		return errdo
	}
	encoded, errread := ioutil.ReadAll(resp.Body)
	if errread != nil {
		return errread
	}
	if resp.StatusCode != 200 {
		err := new(PrismicError)
		errjson := json.Unmarshal(encoded, err)
		if errjson != nil {
			return errjson
		} else {
			return err
		}
	}
	errjson := json.Unmarshal(encoded, res)
	return errjson
}
<|endoftext|>


<commit_before>package main

import (
	"./helpers"
	"crypto/md5"
	"encoding/json"
	"github.com/garyburd/redigo/redis"
	"github.com/googollee/go-socket.io"
	"strings"
)

type Space struct {
	subnet []Player
}

type Player struct {
	localIP  string
	userName string
}

func Adduser(msg string) {
	helpers.TRACE.Println("socket.io: adduser", msg)

}

func Logon(msg string) {

	var space Space

	ipNumbers := strings.Split(msg, " ")
	helpers.TRACE.Println("socket.io->Logon: IP", ipNumbers)

	spaceID := md5.Sum([]byte(ipNumbers[1]))
	helpers.TRACE.Println("socket.io->Logon: SpaceID", spaceID)

	redisDB := RedisPool.Get()
	defer redisDB.Close()

	jsonSpace, err := redis.Bytes(redisDB.Do("GET", spaceID))
	if err != nil {

		TRACE.Println("socket.io->Logon: newSpace", err)
		space = Space{
			subnet: []Player{
				{
					localIP:  ipNumbers[0],
					userName: "JonDoe",
				},
			},
		}
		jsonSpace, err := json.Marshal(space)
		if err != nil {
			ERROR.Println("socket.io->Logon JsonMarshal error: ", err)
		}
		_, err = redisDB.Do("SET", "spaceID", jsonSpace)
		if err != nil {
			ERROR.Println("socket.io->Logon Redis Set error: ", err)
		}

	} else {
		err = json.Unmarshal(jsonSpace, &space)
		if err != nil {
			ERROR.Println("socket.io->Logon error: ", err)
		}
	}
	TRACE.Println("socket.io: ", space)
}

func JoinGame(so socketio.Socket, msg string) {

	helpers.TRACE.Println("socket.io: Join", msg)

	so.Emit("channel", "abcde")
}
<commit_msg>Logon test<commit_after>package main

import (
	"./helpers"
	"encoding/json"
	"github.com/garyburd/redigo/redis"
	"github.com/googollee/go-socket.io"
	"strings"
)

type Space struct {
	subnet []Player
}

type Player struct {
	localIP  string
	userName string
}

func Adduser(msg string) {
	helpers.TRACE.Println("socket.io: adduser", msg)

}

func Logon(msg string) {

	var space Space

	ipNumbers := strings.Split(msg, " ")
	helpers.TRACE.Println("socket.io->Logon: IP", ipNumbers)

	spaceID := ipNumbers[1]
	helpers.TRACE.Println("socket.io->Logon: SpaceID", spaceID)

	redisDB := RedisPool.Get()
	defer redisDB.Close()

	jsonSpace, err := redis.Bytes(redisDB.Do("GET", spaceID))
	if err != nil {

		TRACE.Println("socket.io->Logon: newSpace", err)
		space = Space{
			subnet: []Player{
				{
					localIP:  ipNumbers[0],
					userName: "JonDoe",
				},
			},
		}
		jsonSpace, err := json.Marshal(space)
		if err != nil {
			ERROR.Println("socket.io->Logon json.Marshal error: ", err)
		}
		_, err = redisDB.Do("SET", "spaceID", jsonSpace)
		if err != nil {
			ERROR.Println("socket.io->Logon RedisDB SET error: ", err)
		}

	} else {
		err = json.Unmarshal(jsonSpace, &space)
		if err != nil {
			ERROR.Println("socket.io->Logon json.Unmarshal error: ", err)
		}
	}
	TRACE.Println("socket.io: ", space)
}

func JoinGame(so socketio.Socket, msg string) {

	helpers.TRACE.Println("socket.io: Join", msg)

	so.Emit("channel", "abcde")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"strings"
)

func renderAvailableServices(c *gin.Context) {
	names := []string{}

	for _, svc := range services {
		names = append(names, svc.Name)
	}

	c.String(200, strings.Join(names, "\n")+"\n")
}

func renderServiceEnvironments(c *gin.Context) {
	serviceName := c.Params.ByName("service")

	service, err := getService(serviceName)
	if err != nil {
		c.String(400, err.Error()+"\n")
		return
	}

	names := strings.Join(service.EnvironmentNames(), "\n") + "\n"
	c.String(200, names)
}

func renderServiceEnvironment(c *gin.Context) {
	serviceName := c.Params.ByName("service")
	envName := c.Params.ByName("env")

	environment, err := getEnvironment(serviceName, envName)

	if err != nil {
		c.String(400, err.Error()+"\n")
		return
	}

	c.String(200, environment.ToString()+"\n")
}

func renderReloadServices(c *gin.Context) {
	new_services, err := readServices()

	if err != nil {
		c.String(400, err.Error()+"\n")
		return
	}

	// Replace current configuration
	services = new_services

	c.String(200, "OK\n")
}

func startServer() {
	api := gin.Default()

	api.Use(gin.Logger())
	api.Use(gin.Recovery())

	api.GET("/", renderAvailableServices)
	api.GET("/:service", renderServiceEnvironments)
	api.GET("/:service/:env", renderServiceEnvironment)
	api.POST("/reload", renderReloadServices)

	api.Run(fmt.Sprintf(":%d", options.Port))
}
<commit_msg>Revert "Add logger and recovery middleware"<commit_after>package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"strings"
)

func renderAvailableServices(c *gin.Context) {
	names := []string{}

	for _, svc := range services {
		names = append(names, svc.Name)
	}

	c.String(200, strings.Join(names, "\n")+"\n")
}

func renderServiceEnvironments(c *gin.Context) {
	serviceName := c.Params.ByName("service")

	service, err := getService(serviceName)
	if err != nil {
		c.String(400, err.Error()+"\n")
		return
	}

	names := strings.Join(service.EnvironmentNames(), "\n") + "\n"
	c.String(200, names)
}

func renderServiceEnvironment(c *gin.Context) {
	serviceName := c.Params.ByName("service")
	envName := c.Params.ByName("env")

	environment, err := getEnvironment(serviceName, envName)

	if err != nil {
		c.String(400, err.Error()+"\n")
		return
	}

	c.String(200, environment.ToString()+"\n")
}

func renderReloadServices(c *gin.Context) {
	new_services, err := readServices()

	if err != nil {
		c.String(400, err.Error()+"\n")
		return
	}

	// Replace current configuration
	services = new_services

	c.String(200, "OK\n")
}

func startServer() {
	api := gin.Default()

	api.GET("/", renderAvailableServices)
	api.GET("/:service", renderServiceEnvironments)
	api.GET("/:service/:env", renderServiceEnvironment)
	api.POST("/reload", renderReloadServices)

	api.Run(fmt.Sprintf(":%d", options.Port))
}
<|endoftext|>


<commit_before>package brokerapi

import (
	"encoding/json"
	"net/http"

	"github.com/pivotal-cf/brokerapi/auth"
	"github.com/pivotal-golang/lager"
)

const provisionLogKey = "provision"
const deprovisionLogKey = "deprovision"
const bindLogKey = "bind"
const unbindLogKey = "unbind"

const instanceIDLogKey = "instance-id"
const instanceDetailsLogKey = "instance-details"
const bindingIDLogKey = "binding-id"

const invalidServiceDetailsErrorKey = "invalid-service-details"
const instanceLimitReachedErrorKey = "instance-limit-reached"
const instanceAlreadyExistsErrorKey = "instance-already-exists"
const bindingAlreadyExistsErrorKey = "binding-already-exists"
const instanceMissingErrorKey = "instance-missing"
const bindingMissingErrorKey = "binding-missing"
const unknownErrorKey = "unknown-error"

const statusUnprocessableEntity = 422

type BrokerCredentials struct {
	Username string
	Password string
}

func New(serviceBroker ServiceBroker, logger lager.Logger, brokerCredentials BrokerCredentials) http.Handler {
	router := newHttpRouter()

	router.Get("/v2/catalog", catalog(serviceBroker, router, logger))

	router.Put("/v2/service_instances/{instance_id}", provision(serviceBroker, router, logger))
	router.Delete("/v2/service_instances/{instance_id}", deprovision(serviceBroker, router, logger))

	router.Put("/v2/service_instances/{instance_id}/service_bindings/{binding_id}", bind(serviceBroker, router, logger))
	router.Delete("/v2/service_instances/{instance_id}/service_bindings/{binding_id}", unbind(serviceBroker, router, logger))

	return wrapAuth(router, brokerCredentials)
}

func wrapAuth(router httpRouter, credentials BrokerCredentials) http.Handler {
	return auth.NewWrapper(credentials.Username, credentials.Password).Wrap(router)
}

func catalog(serviceBroker ServiceBroker, router httpRouter, logger lager.Logger) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		catalog := CatalogResponse{
			Services: serviceBroker.Services(),
		}

		respond(w, http.StatusOK, catalog)
	}
}

func provision(serviceBroker ServiceBroker, router httpRouter, logger lager.Logger) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		var serviceDetails ServiceDetails

		vars := router.Vars(req)
		instanceID := vars["instance_id"]

		logger := logger.Session(provisionLogKey, lager.Data{
			instanceIDLogKey: instanceID,
		})

		err := json.NewDecoder(req.Body).Decode(&serviceDetails)
		if err != nil {
			logger.Error(invalidServiceDetailsErrorKey, err)

			respond(w, statusUnprocessableEntity, ErrorResponse{
				Description: err.Error(),
			})
			return
		}

		logger = logger.WithData(lager.Data{
			instanceDetailsLogKey: serviceDetails,
		})

		err = serviceBroker.Provision(instanceID, serviceDetails)
		if err != nil {
			switch err {
			case ErrInstanceAlreadyExists:
				logger.Error(instanceAlreadyExistsErrorKey, err)
				respond(w, http.StatusConflict, EmptyResponse{})
			case ErrInstanceLimitMet:
				logger.Error(instanceLimitReachedErrorKey, err)
				respond(w, http.StatusInternalServerError, ErrorResponse{
					Description: err.Error(),
				})
			default:
				logger.Error(unknownErrorKey, err)
				respond(w, http.StatusInternalServerError, ErrorResponse{
					Description: err.Error(),
				})
			}

			return
		}

		respond(w, http.StatusCreated, ProvisioningResponse{})
	}
}

func deprovision(serviceBroker ServiceBroker, router httpRouter, logger lager.Logger) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		vars := router.Vars(req)
		instanceID := vars["instance_id"]
		logger := logger.Session(deprovisionLogKey, lager.Data{
			instanceIDLogKey: instanceID,
		})

		err := serviceBroker.Deprovision(instanceID)
		if err != nil {
			switch err {
			case ErrInstanceDoesNotExist:
				logger.Error(instanceMissingErrorKey, err)
				respond(w, http.StatusGone, EmptyResponse{})
			default:
				logger.Error(unknownErrorKey, err)
				respond(w, http.StatusInternalServerError, ErrorResponse{
					Description: err.Error(),
				})
			}

			return
		}

		respond(w, http.StatusOK, EmptyResponse{})
	}
}

func bind(serviceBroker ServiceBroker, router httpRouter, logger lager.Logger) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		vars := router.Vars(req)
		instanceID := vars["instance_id"]
		bindingID := vars["binding_id"]

		logger := logger.Session(bindLogKey, lager.Data{
			instanceIDLogKey: instanceID,
			bindingIDLogKey:  bindingID,
		})
		credentials, err := serviceBroker.Bind(instanceID, bindingID)

		if err != nil {
			switch err {
			case ErrInstanceDoesNotExist:
				logger.Error(instanceMissingErrorKey, err)
				respond(w, http.StatusNotFound, ErrorResponse{
					Description: err.Error(),
				})
			case ErrBindingAlreadyExists:
				logger.Error(bindingAlreadyExistsErrorKey, err)
				respond(w, http.StatusConflict, ErrorResponse{
					Description: err.Error(),
				})
			default:
				logger.Error(unknownErrorKey, err)
				respond(w, http.StatusInternalServerError, ErrorResponse{
					Description: err.Error(),
				})
			}
			return
		}

		bindingResponse := BindingResponse{
			Credentials: credentials,
		}

		respond(w, http.StatusCreated, bindingResponse)
	}
}

func unbind(serviceBroker ServiceBroker, router httpRouter, logger lager.Logger) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		vars := router.Vars(req)
		instanceID := vars["instance_id"]
		bindingID := vars["binding_id"]

		logger := logger.Session(unbindLogKey, lager.Data{
			instanceIDLogKey: instanceID,
			bindingIDLogKey:  bindingID,
		})

		err := serviceBroker.Unbind(instanceID, bindingID)
		if err != nil {
			switch err {
			case ErrInstanceDoesNotExist:
				logger.Error(instanceMissingErrorKey, err)
				respond(w, http.StatusNotFound, EmptyResponse{})
			case ErrBindingDoesNotExist:
				logger.Error(bindingMissingErrorKey, err)
				respond(w, http.StatusGone, EmptyResponse{})
			default:
				logger.Error(unknownErrorKey, err)
				respond(w, http.StatusInternalServerError, ErrorResponse{
					Description: err.Error(),
				})
			}

			return
		}

		respond(w, http.StatusOK, EmptyResponse{})
	}
}

func respond(w http.ResponseWriter, status int, response interface{}) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)

	encoder := json.NewEncoder(w)
	encoder.Encode(response)
}
<commit_msg>minor tidyup in api.go<commit_after>package brokerapi

import (
	"encoding/json"
	"net/http"

	"github.com/pivotal-cf/brokerapi/auth"
	"github.com/pivotal-golang/lager"
)

const provisionLogKey = "provision"
const deprovisionLogKey = "deprovision"
const bindLogKey = "bind"
const unbindLogKey = "unbind"

const instanceIDLogKey = "instance-id"
const instanceDetailsLogKey = "instance-details"
const bindingIDLogKey = "binding-id"

const invalidServiceDetailsErrorKey = "invalid-service-details"
const instanceLimitReachedErrorKey = "instance-limit-reached"
const instanceAlreadyExistsErrorKey = "instance-already-exists"
const bindingAlreadyExistsErrorKey = "binding-already-exists"
const instanceMissingErrorKey = "instance-missing"
const bindingMissingErrorKey = "binding-missing"
const unknownErrorKey = "unknown-error"

const statusUnprocessableEntity = 422

type BrokerCredentials struct {
	Username string
	Password string
}

func New(serviceBroker ServiceBroker, logger lager.Logger, brokerCredentials BrokerCredentials) http.Handler {
	router := newHttpRouter()

	router.Get("/v2/catalog", catalog(serviceBroker, router, logger))

	router.Put("/v2/service_instances/{instance_id}", provision(serviceBroker, router, logger))
	router.Delete("/v2/service_instances/{instance_id}", deprovision(serviceBroker, router, logger))

	router.Put("/v2/service_instances/{instance_id}/service_bindings/{binding_id}", bind(serviceBroker, router, logger))
	router.Delete("/v2/service_instances/{instance_id}/service_bindings/{binding_id}", unbind(serviceBroker, router, logger))

	return wrapAuth(router, brokerCredentials)
}

func wrapAuth(router httpRouter, credentials BrokerCredentials) http.Handler {
	return auth.NewWrapper(credentials.Username, credentials.Password).Wrap(router)
}

func catalog(serviceBroker ServiceBroker, router httpRouter, logger lager.Logger) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		catalog := CatalogResponse{
			Services: serviceBroker.Services(),
		}

		respond(w, http.StatusOK, catalog)
	}
}

func provision(serviceBroker ServiceBroker, router httpRouter, logger lager.Logger) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		vars := router.Vars(req)
		instanceID := vars["instance_id"]

		logger := logger.Session(provisionLogKey, lager.Data{
			instanceIDLogKey: instanceID,
		})

		var serviceDetails ServiceDetails
		if err := json.NewDecoder(req.Body).Decode(&serviceDetails); err != nil {
			logger.Error(invalidServiceDetailsErrorKey, err)
			respond(w, statusUnprocessableEntity, ErrorResponse{
				Description: err.Error(),
			})
			return
		}

		logger = logger.WithData(lager.Data{
			instanceDetailsLogKey: serviceDetails,
		})

		if err := serviceBroker.Provision(instanceID, serviceDetails); err != nil {
			switch err {
			case ErrInstanceAlreadyExists:
				logger.Error(instanceAlreadyExistsErrorKey, err)
				respond(w, http.StatusConflict, EmptyResponse{})
			case ErrInstanceLimitMet:
				logger.Error(instanceLimitReachedErrorKey, err)
				respond(w, http.StatusInternalServerError, ErrorResponse{
					Description: err.Error(),
				})
			default:
				logger.Error(unknownErrorKey, err)
				respond(w, http.StatusInternalServerError, ErrorResponse{
					Description: err.Error(),
				})
			}
			return
		}

		respond(w, http.StatusCreated, ProvisioningResponse{})
	}
}

func deprovision(serviceBroker ServiceBroker, router httpRouter, logger lager.Logger) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		vars := router.Vars(req)
		instanceID := vars["instance_id"]
		logger := logger.Session(deprovisionLogKey, lager.Data{
			instanceIDLogKey: instanceID,
		})

		if err := serviceBroker.Deprovision(instanceID); err != nil {
			switch err {
			case ErrInstanceDoesNotExist:
				logger.Error(instanceMissingErrorKey, err)
				respond(w, http.StatusGone, EmptyResponse{})
			default:
				logger.Error(unknownErrorKey, err)
				respond(w, http.StatusInternalServerError, ErrorResponse{
					Description: err.Error(),
				})
			}
			return
		}

		respond(w, http.StatusOK, EmptyResponse{})
	}
}

func bind(serviceBroker ServiceBroker, router httpRouter, logger lager.Logger) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		vars := router.Vars(req)
		instanceID := vars["instance_id"]
		bindingID := vars["binding_id"]

		logger := logger.Session(bindLogKey, lager.Data{
			instanceIDLogKey: instanceID,
			bindingIDLogKey:  bindingID,
		})

		credentials, err := serviceBroker.Bind(instanceID, bindingID)
		if err != nil {
			switch err {
			case ErrInstanceDoesNotExist:
				logger.Error(instanceMissingErrorKey, err)
				respond(w, http.StatusNotFound, ErrorResponse{
					Description: err.Error(),
				})
			case ErrBindingAlreadyExists:
				logger.Error(bindingAlreadyExistsErrorKey, err)
				respond(w, http.StatusConflict, ErrorResponse{
					Description: err.Error(),
				})
			default:
				logger.Error(unknownErrorKey, err)
				respond(w, http.StatusInternalServerError, ErrorResponse{
					Description: err.Error(),
				})
			}
			return
		}

		bindingResponse := BindingResponse{
			Credentials: credentials,
		}

		respond(w, http.StatusCreated, bindingResponse)
	}
}

func unbind(serviceBroker ServiceBroker, router httpRouter, logger lager.Logger) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		vars := router.Vars(req)
		instanceID := vars["instance_id"]
		bindingID := vars["binding_id"]

		logger := logger.Session(unbindLogKey, lager.Data{
			instanceIDLogKey: instanceID,
			bindingIDLogKey:  bindingID,
		})

		if err := serviceBroker.Unbind(instanceID, bindingID); err != nil {
			switch err {
			case ErrInstanceDoesNotExist:
				logger.Error(instanceMissingErrorKey, err)
				respond(w, http.StatusNotFound, EmptyResponse{})
			case ErrBindingDoesNotExist:
				logger.Error(bindingMissingErrorKey, err)
				respond(w, http.StatusGone, EmptyResponse{})
			default:
				logger.Error(unknownErrorKey, err)
				respond(w, http.StatusInternalServerError, ErrorResponse{
					Description: err.Error(),
				})
			}
			return
		}

		respond(w, http.StatusOK, EmptyResponse{})
	}
}

func respond(w http.ResponseWriter, status int, response interface{}) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)

	encoder := json.NewEncoder(w)
	encoder.Encode(response)
}
<|endoftext|>


<commit_before>package vmx

type Vhardware struct {
	Version int    `vmx:"version,omitempty"`
	Compat  string `vmx:"productcompatibility,omitempty"`
}

type Ethernet struct {
	VMXID                string
	StartConnected       bool   `vmx:"startconnected,omitempty"`
	Present              bool   `vmx:"present,omitempty"`
	ConnectionType       string `vmx:"connectiontype,omitempty"`
	VirtualDev           string `vmx:"virtualdev,omitempty"`
	WakeOnPcktRcv        bool   `vmx:"wakeonpcktrcv,omitempty"`
	AddressType          string `vmx:"addresstype,omitempty"`
	LinkStatePropagation bool   `vmx:"linkstatepropagation.enable,omitempty"`
	VNetwork             string `vmx:"vnet,omitempty"`
}

type Device struct {
	VMXID          string
	Present        bool   `vmx:"present,omitempty"`
	Autodetect     bool   `vmx:"autodetect,omitempty"`
	StartConnected bool   `vmx:"startconnected,omitempty"`
	Type           string `vmx:"devicetype,omitempty"`
	Filename       string `vmxl:"filename,omitempty"`
}

type SATADevice struct {
	Device
}

type SCSIDevice struct {
	Device
	PCISlot    int    `vmx:"pcislotnumber,omitempty"`
	VirtualDev string `vmx:"virtualdev,omitempty"`
}

type IDEDevice struct {
	Device
}

type USBDevice struct {
	VMXID   string
	Present bool   `vmx:"present,omitempty"`
	Speed   uint   `vmx:"speed,omitempty"`
	Type    string `vmx:"devicetype,omitempty"`
	Port    uint   `vmx:"port,omitempty"`
	Parent  string `vmx:"parent,omitmepty"`
}

type PowerType struct {
	PowerOff string `vmx:"poweroff,omitempty"`
	PowerOn  string `vmx:"poweron,omitempty"`
	Reset    string `vmx:"reset,omitempty"`
	Suspend  string `vmx:"suspend,omitempty"`
}

type Sound struct {
	VMXID      string
	Present    bool   `vmx:"present,omitempty"`
	Filename   string `vmx:"filename,omitempty"`
	Autodetect bool   `vmx:"autodetect,omitempty"`
}

type SerialPort struct {
	VMXID              string
	StartConnected     bool   `vmx:"startconnected,omitempty"`
	Present            bool   `vmx:"present,omitempty"`
	Filetype           string `vmx:"filetype,omitempty"`
	Filename           string `vmx:"filename,omitempty"`
	Autodetect         bool   `vmx:"autodetect,omitempty"`
	TryNoRxLoss        bool   `vmx:"trynorxloss,omitempty"`
	PipeEndpoint       string `vmx:"pipe.endpoint,omitempty"`
	AllowGuestConnCtrl bool   `vmx:"allowguestconnectioncontrol,omitempty"`
	HardwareFlowCtrl   bool   `vmx:"hardwareFlowControl,omitempty"`
}

type PCIBridge struct {
	VMXID      string
	Present    bool   `vmx:"present,omitempty"`
	VirtualDev string `vmx:"virtualdev,omitempty"`
	SlotNumber int    `vmx:"pcislotnumber,omitempty"`
	Functions  uint   `vmx:"functions,omitempty"`
}

type Tools struct {
	SyncTime      bool   `vmx:"synctime,omitempty"`
	UpgradePolicy string `vmx:"upgrade.policy,omitempty"`
	RemindInstall bool   `vmx:"remindinstall,omitempty"`
}

type UUID struct {
	Action string `vmx:"action,omitempty"`
	// Autogenerated, do not change
	Bios string `vmx:"bios,omitempty"`
	// Autogenerated, do not change
	Location string `vmx:"location,omitempty"`
}

type RemoteDisplay struct {
	VNCEnabled     bool   `vmx:"vnc.enabled,omitempty"`
	VNCPort        uint   `vmx:"vnc.port,omitempty"`
	VNCPassword    string `vmx:"vnc.password,omitempty"`
	VNCIPAddress   string `vmx:"vnc.ip,omitempty"`
	VNCKey         string `vmx:"vnc.key,omitempty"`
	VNCKeyMap      string `vmx:"vnc.keymap,omitempty"`
	VNCKeyMapFile  string `vmx:"vnc.keymapfile,omitempty"`
	VNCZlibLevel   uint   `vmx:"vnc.zliblevel,omitempty"`
	VNCWheelStep   string `vmx:"vncWheelStep,omitempty"`
	Depth          uint   `vmx:"depth,omitempty"`
	MaxConnections uint   `vmx:"maxconnections,omitempty"`
	MaxHeight      uint   `vmx:"maxheight,omitempty"`
	MaxWidth       uint   `vmx:"maxwidth,omitempty"`
}

type SharedFolder struct {
	VMXID       string
	Present     bool   `vmx:"present,omitempty"`
	Enabled     bool   `vmx:"enabled,omitempty"`
	ReadAccess  bool   `vmx:"readaccess,omitempty"`
	WriteAccess bool   `vmx:"writeaccess,omitempty"`
	HostPath    string `vmx:"hostpath,omitempty"`
	GuestName   string `vmx:"guestname,omitempty"`
	Expiration  string `vmx:"expiration,omitempty"`
}

type GUI struct {
	ExitAtPowerOff      bool `vmx:"exitatpoweroff,omitempty"`
	FullScreenAtPowerOn bool `vmx:"fullscreenatpoweron,omitempty"`
	PowerOnAtStartup    bool `vmx:"poweronatstartup,omitempty"`
	ExitOnCLIHalt       bool `vmx:"exitonclihlt,omitempty"`
}

type Isolation struct {
	// Disable shared folders
	HgfsDisable      bool `vmx:"tools.hgfs.disable,omitempty"`
	CopyDisable      bool `vmx:"tools.copy.disable,omitempty"`
	PasteDisable     bool `vmx:"tools.paste.disable,omitempty"`
	DragNDropDisable bool `vmx:"tools.dnd.disable,omitempty"`
}

type FloppyDevice struct {
	VMXID          string
	Present        bool   `vmx:"present,omitempty"`
	StartConnected bool   `vmx:"startconnected,omitempty"`
	Autodetect     bool   `vmx:"autodetect,omitempty"`
	Filename       string `vmx:"filename,omitempty"`
	Filetype       string `vmx:"filetype,omitempty"`
	GuestControl   bool   `vmx:"allowGuestConnectionControl,omitempty"`
}

type VMCI struct {
	VMXID   string
	ID      string `vmx:"id,omitempty"`
	Present bool   `vmx:"present,omitempty"`
	PCISlot int    `vmx:"pcislotnumber,omitempty"`
}

type VMotion struct {
	CheckpointSize string `vmx:"checkpointFBSize"`
}

type VirtualMachine struct {
	Encoding        string    `vmx:".encoding,omitempty"`
	ExtendedCfgFile string    `vmx:"extendedconfigfile,omitempty"`
	PowerType       PowerType `vmx:"powertype,omitempty"`
	Annotation      string    `vmx:"annotation,omitempty"`
	Vhardware       Vhardware `vmx:"virtualhw,omitempty"`
	Memsize         uint      `vmx:"memsize,omitempty"`
	NumvCPUs        uint      `vmx:"numvcpus,omitempty"`
	MemHotAdd       bool      `vmx:"mem.hotadd,omitempty"`
	VCPUHotAdd      bool      `vmx:"vcpu.hotadd,omitempty"`
	DisplayName     string    `vmx:"displayname,omitempty"`
	GuestOS         string    `vmx:"guestos,omitempty"`
	Autoanswer      bool      `vmx:"msg.autoanswer,omitempty"`
	Sound           Sound     `vmx:"sound,omitempty"`
	Tools           Tools     `vmx:"tools,omitempty"`
	NVRam           string    `vmx:"nvmram,omitempty"`
	UUID            UUID      `vmx:"uuid,omitempty"`
	CleanShutdown   bool      `vmx:"cleanshutdown,omitempty"`
	SoftPowerOff    bool      `vmx:"softpoweroff,omitempty"`
	VMCI            VMCI      `vmx:"vmci0,omitempty"`
	VMotion         VMotion   `vmx:"vmotion"`
	// Enable or not nested virtualiation
	VHVEnable     bool           `vmx:"vhv.enable,omitempty"`
	RemoteDisplay RemoteDisplay  `vmx:"remotedisplay,omitempty"`
	Isolation     Isolation      `vmx:"isolation,omitempty"`
	SharedFolders []SharedFolder `vmx:"sharedfolder,omitempty"`
	PCIBridges    []PCIBridge    `vmx:"pcibridge,omitempty"`
	SerialPorts   []SerialPort   `vmx:"serial,omitempty"`
	Ethernet      []Ethernet     `vmx:"ethernet,omitempty"`
	IDEDevices    []IDEDevice    `vmx:"ide,omitempty"`
	SCSIDevices   []SCSIDevice   `vmx:"scsi,omitempty"`
	SATADevices   []SATADevice   `vmx:"sata,omitempty"`
	USBDevices    []USBDevice    `vmx:"usb,omitempty"`
	FloppyDevices []FloppyDevice `vmx:"floppy,omitempty"`
}
<commit_msg>Fixes tests<commit_after>package vmx

type Vhardware struct {
	Version int    `vmx:"version,omitempty"`
	Compat  string `vmx:"productcompatibility,omitempty"`
}

type Ethernet struct {
	VMXID                string
	StartConnected       bool   `vmx:"startconnected,omitempty"`
	Present              bool   `vmx:"present,omitempty"`
	ConnectionType       string `vmx:"connectiontype,omitempty"`
	VirtualDev           string `vmx:"virtualdev,omitempty"`
	WakeOnPcktRcv        bool   `vmx:"wakeonpcktrcv,omitempty"`
	AddressType          string `vmx:"addresstype,omitempty"`
	LinkStatePropagation bool   `vmx:"linkstatepropagation.enable,omitempty"`
	VNetwork             string `vmx:"vnet,omitempty"`
}

type Device struct {
	VMXID          string
	Present        bool   `vmx:"present,omitempty"`
	Autodetect     bool   `vmx:"autodetect,omitempty"`
	StartConnected bool   `vmx:"startconnected,omitempty"`
	Type           string `vmx:"devicetype,omitempty"`
	Filename       string `vmxl:"filename,omitempty"`
}

type SATADevice struct {
	Device
}

type SCSIDevice struct {
	Device
	PCISlot    int    `vmx:"pcislotnumber,omitempty"`
	VirtualDev string `vmx:"virtualdev,omitempty"`
}

type IDEDevice struct {
	Device
}

type USBDevice struct {
	VMXID   string
	Present bool   `vmx:"present,omitempty"`
	Speed   uint   `vmx:"speed,omitempty"`
	Type    string `vmx:"devicetype,omitempty"`
	Port    uint   `vmx:"port,omitempty"`
	Parent  string `vmx:"parent,omitmepty"`
}

type PowerType struct {
	PowerOff string `vmx:"poweroff,omitempty"`
	PowerOn  string `vmx:"poweron,omitempty"`
	Reset    string `vmx:"reset,omitempty"`
	Suspend  string `vmx:"suspend,omitempty"`
}

type Sound struct {
	VMXID      string
	Present    bool   `vmx:"present,omitempty"`
	Filename   string `vmx:"filename,omitempty"`
	Autodetect bool   `vmx:"autodetect,omitempty"`
}

type SerialPort struct {
	VMXID              string
	StartConnected     bool   `vmx:"startconnected,omitempty"`
	Present            bool   `vmx:"present,omitempty"`
	Filetype           string `vmx:"filetype,omitempty"`
	Filename           string `vmx:"filename,omitempty"`
	Autodetect         bool   `vmx:"autodetect,omitempty"`
	TryNoRxLoss        bool   `vmx:"trynorxloss,omitempty"`
	PipeEndpoint       string `vmx:"pipe.endpoint,omitempty"`
	AllowGuestConnCtrl bool   `vmx:"allowguestconnectioncontrol,omitempty"`
	HardwareFlowCtrl   bool   `vmx:"hardwareFlowControl,omitempty"`
}

type PCIBridge struct {
	VMXID      string
	Present    bool   `vmx:"present,omitempty"`
	VirtualDev string `vmx:"virtualdev,omitempty"`
	SlotNumber int    `vmx:"pcislotnumber,omitempty"`
	Functions  uint   `vmx:"functions,omitempty"`
}

type Tools struct {
	SyncTime      bool   `vmx:"synctime,omitempty"`
	UpgradePolicy string `vmx:"upgrade.policy,omitempty"`
	RemindInstall bool   `vmx:"remindinstall,omitempty"`
}

type UUID struct {
	Action string `vmx:"action,omitempty"`
	// Autogenerated, do not change
	Bios string `vmx:"bios,omitempty"`
	// Autogenerated, do not change
	Location string `vmx:"location,omitempty"`
}

type RemoteDisplay struct {
	VNCEnabled     bool   `vmx:"vnc.enabled,omitempty"`
	VNCPort        uint   `vmx:"vnc.port,omitempty"`
	VNCPassword    string `vmx:"vnc.password,omitempty"`
	VNCIPAddress   string `vmx:"vnc.ip,omitempty"`
	VNCKey         string `vmx:"vnc.key,omitempty"`
	VNCKeyMap      string `vmx:"vnc.keymap,omitempty"`
	VNCKeyMapFile  string `vmx:"vnc.keymapfile,omitempty"`
	VNCZlibLevel   uint   `vmx:"vnc.zliblevel,omitempty"`
	VNCWheelStep   string `vmx:"vncWheelStep,omitempty"`
	Depth          uint   `vmx:"depth,omitempty"`
	MaxConnections uint   `vmx:"maxconnections,omitempty"`
	MaxHeight      uint   `vmx:"maxheight,omitempty"`
	MaxWidth       uint   `vmx:"maxwidth,omitempty"`
}

type SharedFolder struct {
	VMXID       string
	Present     bool   `vmx:"present,omitempty"`
	Enabled     bool   `vmx:"enabled,omitempty"`
	ReadAccess  bool   `vmx:"readaccess,omitempty"`
	WriteAccess bool   `vmx:"writeaccess,omitempty"`
	HostPath    string `vmx:"hostpath,omitempty"`
	GuestName   string `vmx:"guestname,omitempty"`
	Expiration  string `vmx:"expiration,omitempty"`
}

type GUI struct {
	ExitAtPowerOff      bool `vmx:"exitatpoweroff,omitempty"`
	FullScreenAtPowerOn bool `vmx:"fullscreenatpoweron,omitempty"`
	PowerOnAtStartup    bool `vmx:"poweronatstartup,omitempty"`
	ExitOnCLIHalt       bool `vmx:"exitonclihlt,omitempty"`
}

type Isolation struct {
	// Disable shared folders
	HgfsDisable      bool `vmx:"tools.hgfs.disable,omitempty"`
	CopyDisable      bool `vmx:"tools.copy.disable,omitempty"`
	PasteDisable     bool `vmx:"tools.paste.disable,omitempty"`
	DragNDropDisable bool `vmx:"tools.dnd.disable,omitempty"`
}

type FloppyDevice struct {
	VMXID          string
	Present        bool   `vmx:"present,omitempty"`
	StartConnected bool   `vmx:"startconnected,omitempty"`
	Autodetect     bool   `vmx:"autodetect,omitempty"`
	Filename       string `vmx:"filename,omitempty"`
	Filetype       string `vmx:"filetype,omitempty"`
	GuestControl   bool   `vmx:"allowGuestConnectionControl,omitempty"`
}

type VMCI struct {
	VMXID   string
	ID      string `vmx:"id,omitempty"`
	Present bool   `vmx:"present,omitempty"`
	PCISlot int    `vmx:"pcislotnumber,omitempty"`
}

type VMotion struct {
	CheckpointSize string `vmx:"checkpointFBSize,omitempty"`
}

type VirtualMachine struct {
	Encoding        string    `vmx:".encoding,omitempty"`
	ExtendedCfgFile string    `vmx:"extendedconfigfile,omitempty"`
	PowerType       PowerType `vmx:"powertype,omitempty"`
	Annotation      string    `vmx:"annotation,omitempty"`
	Vhardware       Vhardware `vmx:"virtualhw,omitempty"`
	Memsize         uint      `vmx:"memsize,omitempty"`
	NumvCPUs        uint      `vmx:"numvcpus,omitempty"`
	MemHotAdd       bool      `vmx:"mem.hotadd,omitempty"`
	VCPUHotAdd      bool      `vmx:"vcpu.hotadd,omitempty"`
	DisplayName     string    `vmx:"displayname,omitempty"`
	GuestOS         string    `vmx:"guestos,omitempty"`
	Autoanswer      bool      `vmx:"msg.autoanswer,omitempty"`
	Sound           Sound     `vmx:"sound,omitempty"`
	Tools           Tools     `vmx:"tools,omitempty"`
	NVRam           string    `vmx:"nvmram,omitempty"`
	UUID            UUID      `vmx:"uuid,omitempty"`
	CleanShutdown   bool      `vmx:"cleanshutdown,omitempty"`
	SoftPowerOff    bool      `vmx:"softpoweroff,omitempty"`
	VMCI            VMCI      `vmx:"vmci0,omitempty"`
	VMotion         VMotion   `vmx:"vmotion"`
	// Enable or not nested virtualiation
	VHVEnable     bool           `vmx:"vhv.enable,omitempty"`
	RemoteDisplay RemoteDisplay  `vmx:"remotedisplay,omitempty"`
	Isolation     Isolation      `vmx:"isolation,omitempty"`
	SharedFolders []SharedFolder `vmx:"sharedfolder,omitempty"`
	PCIBridges    []PCIBridge    `vmx:"pcibridge,omitempty"`
	SerialPorts   []SerialPort   `vmx:"serial,omitempty"`
	Ethernet      []Ethernet     `vmx:"ethernet,omitempty"`
	IDEDevices    []IDEDevice    `vmx:"ide,omitempty"`
	SCSIDevices   []SCSIDevice   `vmx:"scsi,omitempty"`
	SATADevices   []SATADevice   `vmx:"sata,omitempty"`
	USBDevices    []USBDevice    `vmx:"usb,omitempty"`
	FloppyDevices []FloppyDevice `vmx:"floppy,omitempty"`
}
<|endoftext|>


<commit_before>package kwiscale

import (
	"log"
	"net/http"
	"reflect"

	"github.com/gorilla/mux"
)

// handlerManager is used to manage handler production and close
type handlerManager struct {

	// the handler type to produce
	handler reflect.Type

	// record closers
	closer chan int

	// record handlers (as interface)
	producer chan interface{}
}

type HandlerFactory func() IBaseHandler

// handlerFactory continuously generates new handlers in registry.
// It launches a goroutine to produce those handlers. The number of
// handlers to generate in cache is set by Config.NbHandlerCache.
// Return a chanel to write in to close handler production
func (manager handlerManager) produceHandlers() {
	// forever produce handlers until closer is called
	for {
		select {
		case manager.producer <- reflect.New(manager.handler).Interface():
			if debug {
				log.Println("Appended handler ", manager.handler.Name())
			}
		case <-manager.closer:
			// Someone closed the factory
			return
		}
	}
}

// the full registry
var handlerRegistry = make(map[string]handlerManager)

// Config structure that holds configuration
type Config struct {
	// Root directory where TemplateEngine will get files
	TemplateDir string
	// Port to listen
	Port string
	// Number of handler to prepare
	NbHandlerCache int
	// TemplateEngine to use (default, pango2...)
	TemplateEngine string
	// Template engine options (some addons need options)
	TemplateEngineOptions TplOptions
	// SessionEngine (default is a file storage)
	SessionsEngine string
	// SessionName is the name of session, eg. Cookie name, default is "kwiscale-session"
	SessionName string
	// A secret string to encrypt cookie
	SessionSecret []byte
	// Static directory (to put css, images, and so on...)
	StaticDir string
	// Activate static in memory cache
	StaticCacheEnabled bool

	// StrictSlash allows to match route that have trailing slashes
	StrictSlash bool

	// DBDriver should be the name of a
	// registered DB Driver (sqlite3, postgresql, mysql/mariadb...)
	//DBDriver string

	// DBURL is the connection path/url to the database
	//DBURL string
}

// App handles router and handlers.
type App struct {

	// configuration
	Config *Config

	// session store
	sessionstore ISessionStore

	// Template engine instance.
	templateEngine ITemplate

	// The router that will be used
	router *mux.Router

	// List of handler "names" mapped to route (will be create by a factory)
	handlers map[*mux.Route]string
}

// Initialize config default values if some are not defined
func initConfig(config *Config) *Config {
	if config == nil {
		config = new(Config)
	}

	if config.Port == "" {
		config.Port = ":8000"
	}

	if config.NbHandlerCache == 0 {
		config.NbHandlerCache = 5
	}

	if config.TemplateEngine == "" {
		config.TemplateEngine = "basic"
	}

	if config.SessionsEngine == "" {
		config.SessionsEngine = "default"
	}
	if config.SessionName == "" {
		config.SessionName = "kwiscale-session"
	}
	if config.SessionSecret == nil {
		config.SessionSecret = []byte("A very long secret string you should change")
	}

	return config
}

// NewApp Create new *App - App constructor.
func NewApp(config *Config) *App {

	// fill up config for non-set values
	config = initConfig(config)

	if debug {
		log.Printf("%+v\n", config)
	}

	// generate app, assign config, router and handlers map
	a := &App{
		Config:   config,
		router:   mux.NewRouter(),
		handlers: make(map[*mux.Route]string),

		// Get template engine from config
		templateEngine: templateEngine[config.TemplateEngine],
	}

	a.templateEngine.SetTemplateDir(config.TemplateDir)
	a.templateEngine.SetTemplateOptions(&config.TemplateEngineOptions)

	// set sessstion store
	a.sessionstore = sessionEngine[config.SessionsEngine]
	a.sessionstore.Name(config.SessionName)
	a.sessionstore.SetSecret(config.SessionSecret)
	a.sessionstore.Init()

	if config.StaticDir != "" {
		a.SetStatic(config.StaticDir)
	}

	a.router.StrictSlash(config.StrictSlash)

	// keep config
	a.Config = config

	return a
}

// ListenAndServe calls http.ListenAndServe method
func (a *App) ListenAndServe(port ...string) {
	p := a.Config.Port
	if len(port) > 0 {
		p = port[0]
	}
	log.Println("Listening", p)
	http.ListenAndServe(p, a)
}

// SetStatic set the route "prefix" to serve files configured in Config.StaticDir
func (a *App) SetStatic(prefix string) {
	a.AddRoute("/"+prefix+"/{file:.*}", staticHandler{})
}

// Implement http.Handler ServeHTTP method.
func (app *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {

	var req interface{}
	for route, handler := range app.handlers {
		var match mux.RouteMatch
		if route.Match(r, &match) {
			// construct handler from its name
			if debug {
				log.Printf("Route matches %#v\n", route)
				log.Println("Handler to fetch", handler)
			}

			// wait for a built handler from registry
			req = <-handlerRegistry[handler].producer

			if debug {
				log.Print("Handler found ", req)
			}

			//assign some vars
			req.(IBaseHandler).setVars(match.Vars, w, r)
			req.(IBaseHandler).setApp(app)
			req.(IBaseHandler).setSessionStore(app.sessionstore)
			break //that's ok, we can continue
		}
		// code hasn't breaked, so we didn't found handler
	}

	if req, ok := req.(IBaseHandler); ok {
		// Call Init before starting response
		if err, code := req.Init(); err != nil {
			// Init stops the request with error
			HandleError(code, req.getResponse(), req.getRequest(), err)
			return
		}
		// Prepare defered destroy
		defer req.Destroy()
	} else {
		HandleError(http.StatusNotFound, w, r, nil)
		return
	}

	// Websocket case
	if req, ok := req.(IWSHandler); ok {
		if err := req.upgrade(); err != nil {
			log.Println("Error upgrading Websocket protocol", err)
			return
		}
		req.Serve()
		return
	}

	// Standard Request
	if req, ok := req.(IRequestHandler); ok {
		// RequestHandler case
		w.Header().Add("Connection", "close")
		if debug {
			log.Println("Respond to IRequestHandler", r.Method, req)
		}
		if req == nil {
			HandleError(http.StatusNotFound, w, r, nil)
			return
		}

		switch r.Method {
		case "GET":
			req.Get()
		case "PUT":
			req.Put()
		case "POST":
			req.Post()
		case "DELETE":
			req.Delete()
		case "HEAD":
			req.Post()
		case "PATCH":
			req.Patch()
		case "OPTIONS":
			req.Options()
		case "TRACE":
			req.Trace()
		default:
			HandleError(http.StatusNotImplemented, w, r, nil)
		}
	} else {
		HandleError(http.StatusInternalServerError, w, r, nil)
		if debug {
			log.Printf("Registry: %+v\n", handlerRegistry)
			log.Printf("RequestWriter: %+v\n", w)
			log.Printf("Reponse: %+v", r)
			log.Printf("KwiscaleHandler: %+v\n", req)
		}
	}
}

// AddRoute appends route mapped to handler. Note that rh parameter should
// implement IRequestHandler (generally a struct composing RequestHandler).
func (app *App) AddRoute(route string, handler interface{}) {
	r := app.router.NewRoute()
	r.Path(route)
	r.Name(route)

	handlerType := reflect.TypeOf(handler)
	// keep in mind that "route" is an pointer
	app.handlers[r] = handlerType.String()
	if debug {
		log.Print("Register ", handlerType.String())
	}

	// register factory channel
	manager := handlerManager{
		handler:  handlerType,
		closer:   make(chan int, 0),
		producer: make(chan interface{}, app.Config.NbHandlerCache),
	}
	// produce handlers
	handlerRegistry[handlerType.String()] = manager
	go manager.produceHandlers()
}

// SoftStrop stops each handler manager goroutine (useful for testing).
func (app *App) SoftStop() {
	for name, closer := range handlerRegistry {
		if debug {
			log.Println("Closing ", name)
		}
		closer.closer <- 1
	}
}
<commit_msg>Changes route name - take handler name now<commit_after>package kwiscale

import (
	"log"
	"net/http"
	"reflect"

	"github.com/gorilla/mux"
)

// handlerManager is used to manage handler production and close
type handlerManager struct {

	// the handler type to produce
	handler reflect.Type

	// record closers
	closer chan int

	// record handlers (as interface)
	producer chan interface{}
}

type HandlerFactory func() IBaseHandler

// handlerFactory continuously generates new handlers in registry.
// It launches a goroutine to produce those handlers. The number of
// handlers to generate in cache is set by Config.NbHandlerCache.
// Return a chanel to write in to close handler production
func (manager handlerManager) produceHandlers() {
	// forever produce handlers until closer is called
	for {
		select {
		case manager.producer <- reflect.New(manager.handler).Interface():
			if debug {
				log.Println("Appended handler ", manager.handler.Name())
			}
		case <-manager.closer:
			// Someone closed the factory
			return
		}
	}
}

// the full registry
var handlerRegistry = make(map[string]handlerManager)

// Config structure that holds configuration
type Config struct {
	// Root directory where TemplateEngine will get files
	TemplateDir string
	// Port to listen
	Port string
	// Number of handler to prepare
	NbHandlerCache int
	// TemplateEngine to use (default, pango2...)
	TemplateEngine string
	// Template engine options (some addons need options)
	TemplateEngineOptions TplOptions
	// SessionEngine (default is a file storage)
	SessionsEngine string
	// SessionName is the name of session, eg. Cookie name, default is "kwiscale-session"
	SessionName string
	// A secret string to encrypt cookie
	SessionSecret []byte
	// Static directory (to put css, images, and so on...)
	StaticDir string
	// Activate static in memory cache
	StaticCacheEnabled bool

	// StrictSlash allows to match route that have trailing slashes
	StrictSlash bool

	// DBDriver should be the name of a
	// registered DB Driver (sqlite3, postgresql, mysql/mariadb...)
	//DBDriver string

	// DBURL is the connection path/url to the database
	//DBURL string
}

// App handles router and handlers.
type App struct {

	// configuration
	Config *Config

	// session store
	sessionstore ISessionStore

	// Template engine instance.
	templateEngine ITemplate

	// The router that will be used
	router *mux.Router

	// List of handler "names" mapped to route (will be create by a factory)
	handlers map[*mux.Route]string
}

// Initialize config default values if some are not defined
func initConfig(config *Config) *Config {
	if config == nil {
		config = new(Config)
	}

	if config.Port == "" {
		config.Port = ":8000"
	}

	if config.NbHandlerCache == 0 {
		config.NbHandlerCache = 5
	}

	if config.TemplateEngine == "" {
		config.TemplateEngine = "basic"
	}

	if config.SessionsEngine == "" {
		config.SessionsEngine = "default"
	}
	if config.SessionName == "" {
		config.SessionName = "kwiscale-session"
	}
	if config.SessionSecret == nil {
		config.SessionSecret = []byte("A very long secret string you should change")
	}

	return config
}

// NewApp Create new *App - App constructor.
func NewApp(config *Config) *App {

	// fill up config for non-set values
	config = initConfig(config)

	if debug {
		log.Printf("%+v\n", config)
	}

	// generate app, assign config, router and handlers map
	a := &App{
		Config:   config,
		router:   mux.NewRouter(),
		handlers: make(map[*mux.Route]string),

		// Get template engine from config
		templateEngine: templateEngine[config.TemplateEngine],
	}

	a.templateEngine.SetTemplateDir(config.TemplateDir)
	a.templateEngine.SetTemplateOptions(&config.TemplateEngineOptions)

	// set sessstion store
	a.sessionstore = sessionEngine[config.SessionsEngine]
	a.sessionstore.Name(config.SessionName)
	a.sessionstore.SetSecret(config.SessionSecret)
	a.sessionstore.Init()

	if config.StaticDir != "" {
		a.SetStatic(config.StaticDir)
	}

	a.router.StrictSlash(config.StrictSlash)

	// keep config
	a.Config = config

	return a
}

// ListenAndServe calls http.ListenAndServe method
func (a *App) ListenAndServe(port ...string) {
	p := a.Config.Port
	if len(port) > 0 {
		p = port[0]
	}
	log.Println("Listening", p)
	http.ListenAndServe(p, a)
}

// SetStatic set the route "prefix" to serve files configured in Config.StaticDir
func (a *App) SetStatic(prefix string) {
	a.AddRoute("/"+prefix+"/{file:.*}", staticHandler{})
}

// Implement http.Handler ServeHTTP method.
func (app *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {

	var req interface{}
	for route, handler := range app.handlers {
		var match mux.RouteMatch
		if route.Match(r, &match) {
			// construct handler from its name
			if debug {
				log.Printf("Route matches %#v\n", route)
				log.Println("Handler to fetch", handler)
			}

			// wait for a built handler from registry
			req = <-handlerRegistry[handler].producer

			if debug {
				log.Print("Handler found ", req)
			}

			//assign some vars
			req.(IBaseHandler).setVars(match.Vars, w, r)
			req.(IBaseHandler).setApp(app)
			req.(IBaseHandler).setSessionStore(app.sessionstore)
			break //that's ok, we can continue
		}
		// code hasn't breaked, so we didn't found handler
	}

	if req, ok := req.(IBaseHandler); ok {
		// Call Init before starting response
		if err, code := req.Init(); err != nil {
			// Init stops the request with error
			HandleError(code, req.getResponse(), req.getRequest(), err)
			return
		}
		// Prepare defered destroy
		defer req.Destroy()
	} else {
		HandleError(http.StatusNotFound, w, r, nil)
		return
	}

	// Websocket case
	if req, ok := req.(IWSHandler); ok {
		if err := req.upgrade(); err != nil {
			log.Println("Error upgrading Websocket protocol", err)
			return
		}
		req.Serve()
		return
	}

	// Standard Request
	if req, ok := req.(IRequestHandler); ok {
		// RequestHandler case
		w.Header().Add("Connection", "close")
		if debug {
			log.Println("Respond to IRequestHandler", r.Method, req)
		}
		if req == nil {
			HandleError(http.StatusNotFound, w, r, nil)
			return
		}

		switch r.Method {
		case "GET":
			req.Get()
		case "PUT":
			req.Put()
		case "POST":
			req.Post()
		case "DELETE":
			req.Delete()
		case "HEAD":
			req.Post()
		case "PATCH":
			req.Patch()
		case "OPTIONS":
			req.Options()
		case "TRACE":
			req.Trace()
		default:
			HandleError(http.StatusNotImplemented, w, r, nil)
		}
	} else {
		HandleError(http.StatusInternalServerError, w, r, nil)
		if debug {
			log.Printf("Registry: %+v\n", handlerRegistry)
			log.Printf("RequestWriter: %+v\n", w)
			log.Printf("Reponse: %+v", r)
			log.Printf("KwiscaleHandler: %+v\n", req)
		}
	}
}

// AddRoute appends route mapped to handler. Note that rh parameter should
// implement IRequestHandler (generally a struct composing RequestHandler).
func (app *App) AddRoute(route string, handler interface{}) {
	r := app.router.NewRoute()
	r.Path(route)

	handlerType := reflect.TypeOf(handler)
	name := handlerType.String()
	// keep in mind that "route" is an pointer
	app.handlers[r] = name
	r.Name(name)

	if debug {
		log.Print("Register ", name)
	}

	// register factory channel
	manager := handlerManager{
		handler:  handlerType,
		closer:   make(chan int, 0),
		producer: make(chan interface{}, app.Config.NbHandlerCache),
	}
	// produce handlers
	handlerRegistry[handlerType.String()] = manager
	go manager.produceHandlers()
}

// SoftStrop stops each handler manager goroutine (useful for testing).
func (app *App) SoftStop() {
	for name, closer := range handlerRegistry {
		if debug {
			log.Println("Closing ", name)
		}
		closer.closer <- 1
	}
}
<|endoftext|>


<commit_before>package app

import (
	"github.com/murlokswarm/log"
	"github.com/murlokswarm/markup"
)

var (
	// OnLaunch is a handler which (if set) is called when the app is
	// initialized and ready.
	// The main window should be created here.
	OnLaunch func()

	// OnFocus is a handler which (if set) is called when the app became
	// focused.
	OnFocus func()

	// OnBlur is a handler which (if set) is called when the app lost the
	// focus.
	OnBlur func()

	// OnReopen is a handler which (if set) is called when the app is reopened.
	// Eg. when the dock icon is clicked.
	OnReopen func(hasVisibleWindow bool)

	// OnFileOpen is a handler which (if set) is called when a file is targeted
	// to be opened with the app.
	OnFileOpen func(filename string)

	// OnTerminate is a handler which (if set) is called when the app is
	// requested to terminates. Return false cancels the termination request.
	OnTerminate func() bool

	// OnFinalize is a handler which (if set) is called when the app is about
	// to be terminated.
	// It should be used to perform any final cleanup before the application
	// terminates.
	OnFinalize func()
)

// Run runs the app.
func Run() {
	driver.Run()
}

// Render renders a component. Update the rendering of c.
// c must be mounted into a context.
func Render(c Componer) {
	syncs, err := markup.Synchronize(c)
	if err != nil {
		log.Error(err)
		return
	}

	ctx := Context(c)
	for _, s := range syncs {
		ctx.Render(s)
	}
}

// Storage returns the app storage directories.
func Storage() Storer {
	return driver.Storage()
}

// MenuBar returns the menu bar context (MacOS).
func MenuBar() Contexter {
	return driver.MenuBar()
}

// Dock returns the dock context.
func Dock() Docker {
	return driver.Dock()
}
<commit_msg>add OnFilesOpen event<commit_after>package app

import (
	"github.com/murlokswarm/log"
	"github.com/murlokswarm/markup"
)

var (
	// OnLaunch is a handler which (if set) is called when the app is
	// initialized and ready.
	// The main window should be created here.
	OnLaunch func()

	// OnFocus is a handler which (if set) is called when the app became
	// focused.
	OnFocus func()

	// OnBlur is a handler which (if set) is called when the app lost the
	// focus.
	OnBlur func()

	// OnReopen is a handler which (if set) is called when the app is reopened.
	// Eg. when the dock icon is clicked.
	OnReopen func(hasVisibleWindow bool)

	// OnFileOpen is a handler which (if set) is called when a file is targeted
	// to be opened with the app.
	OnFileOpen func(filename string)

	// OnFilesOpen is a handler which (if set) is called when files are targeted
	// to be opened with the app.
	OnFilesOpen func(filenames []string)

	// OnTerminate is a handler which (if set) is called when the app is
	// requested to terminates. Return false cancels the termination request.
	OnTerminate func() bool

	// OnFinalize is a handler which (if set) is called when the app is about
	// to be terminated.
	// It should be used to perform any final cleanup before the application
	// terminates.
	OnFinalize func()
)

// Run runs the app.
func Run() {
	driver.Run()
}

// Render renders a component. Update the rendering of c.
// c must be mounted into a context.
func Render(c Componer) {
	syncs, err := markup.Synchronize(c)
	if err != nil {
		log.Error(err)
		return
	}

	ctx := Context(c)
	for _, s := range syncs {
		ctx.Render(s)
	}
}

// Storage returns the app storage directories.
func Storage() Storer {
	return driver.Storage()
}

// MenuBar returns the menu bar context (MacOS).
func MenuBar() Contexter {
	return driver.MenuBar()
}

// Dock returns the dock context.
func Dock() Docker {
	return driver.Dock()
}
<|endoftext|>


<commit_before>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package utils

import (
	"os"
	"os/exec"
)

// Some helpful functions for running apt in a sane way

// TODO: When we have a unit-level lock to avoid multiple unit agents running
//       apt concurrently, we should use that same locking here

// osRunCommand calls cmd.Run, this is used as an overloading point so we can
// test what *would* be run without actually executing another program
func osRunCommand(cmd *exec.Cmd) error {
	return cmd.Run()
}

var runCommand = osRunCommand

// This is the default apt-get command used in cloud-init, the various settings
// mean that apt won't actually block waiting for a prompt from the user.
var aptGetCommand = []string{
	"apt-get", "--option=Dpkg::Options::=--force-confold",
	"--option=Dpkg::options::=--force-unsafe-io", "--assume-yes", "--quiet",
}

// aptEnvOptions are options we need to pass to apt-get to not have it prompt
// the user
var aptGetEnvOptions = []string{"DEBIAN_FRONTEND=noninteractive"}

// AptGetInstall runs 'apt-get install packages' for the packages listed here
func AptGetInstall(packages ...string) error {
	cmdArgs := append([]string(nil), aptGetCommand...)
	cmdArgs = append(cmdArgs, "install")
	cmdArgs = append(cmdArgs, packages...)
	cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
	cmd.Env = append(os.Environ(), aptGetEnvOptions...)
	return runCommand(cmd)
}
<commit_msg>Mark bug #1199915 as fixed. We don't need to long when it fails, because container/lxc logs it for us.<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package utils

import (
	"os"
	"os/exec"

        "launchpad.net/loggo"
)

var aptLogger = loggo.GetLogger("juju.utils.apt")

// Some helpful functions for running apt in a sane way

// TODO: When we have a unit-level lock to avoid multiple unit agents running
//       apt concurrently, we should use that same locking here

// osRunCommand calls cmd.Run, this is used as an overloading point so we can
// test what *would* be run without actually executing another program
func osRunCommand(cmd *exec.Cmd) error {
	return cmd.Run()
}

var runCommand = osRunCommand

// This is the default apt-get command used in cloud-init, the various settings
// mean that apt won't actually block waiting for a prompt from the user.
var aptGetCommand = []string{
	"apt-get", "--option=Dpkg::Options::=--force-confold",
	"--option=Dpkg::options::=--force-unsafe-io", "--assume-yes", "--quiet",
}

// aptEnvOptions are options we need to pass to apt-get to not have it prompt
// the user
var aptGetEnvOptions = []string{"DEBIAN_FRONTEND=noninteractive"}

// AptGetInstall runs 'apt-get install packages' for the packages listed here
func AptGetInstall(packages ...string) error {
	cmdArgs := append([]string(nil), aptGetCommand...)
	cmdArgs = append(cmdArgs, "install")
	cmdArgs = append(cmdArgs, packages...)
        aptLogger.Infof("Running: %s", cmdArgs)
	cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
	cmd.Env = append(os.Environ(), aptGetEnvOptions...)
	return runCommand(cmd)
}
<|endoftext|>