<commit_before>package models

import (
	"errors"
	"fmt"
	"log"
	"sort"
	"time"

	"github.com/UniversityRadioYork/2016-site/utils"
)

// weekFromVars extracts the year, and week strings from vars.
func weekFromVars(vars map[string]string) (string, string, error) {
	y, ok := vars["year"]
	if !ok {
		return "", "", errors.New("no year provided")
	}
	w, ok := vars["week"]
	if !ok {
		return "", "", errors.New("no week provided")
	}

	return y, w, nil
}

//
// Week schedule algorithm
// TODO(CaptainHayashi): move?
//

// WeekScheduleCell represents one cell in the week schedule.
type WeekScheduleCell struct {
	// Number of rows this cell spans.
	// If 0, this is a continuation from a cell further up.
	RowSpan uint

	// Pointer to the timeslot in this cell, if any.
	// Will be nil if 'RowSpan' is 0.
	Item *ScheduleItem

	// Hour stores which hour (row) the cell is in
	Hour int

	// Minute stores the minute for this row
	Minute int
}

// WeekScheduleRow represents one row in the week schedule.
type WeekScheduleRow struct {
	// The hour of the row (0..23).
	Hour int
	// The minute of the show (0..59).
	Minute int
	// The cells inside this row.
	Cells []WeekScheduleCell
}

// addCell adds a cell with rowspan s and item i to the row r.
func (r *WeekScheduleRow) addCell(s uint, i *ScheduleItem) {
	r.Cells = append(r.Cells, WeekScheduleCell{RowSpan: s, Item: i})
}

// straddlesDay checks whether a show's start and finish cross over the boundary of a URY day.
func straddlesDay(s *ScheduleItem) bool {
	dayBoundary := utils.StartHour
	adjustedStartDay := s.Start.Add(time.Hour * time.Duration(-dayBoundary))
	adjustedEndDay := s.Finish.Add(time.Hour * time.Duration(-dayBoundary))
	straddle := adjustedEndDay.Day() != adjustedStartDay.Day() && s.Finish.Sub(s.Start) > time.Hour
	return straddle
}

// calcScheduleBoundaries gets the offsets of the earliest and latest visible schedule hours.
// It returns these as top and bot respectively.
func calcScheduleBoundaries(items []*ScheduleItem, scheduleStart time.Time) (top, bot utils.StartOffset, err error) {
	if len(items) == 0 {
		err = errors.New("calculateScheduleBoundaries: no schedule")
		return
	}

	// These are the boundaries for culling, and are expanded upwards when we find shows that start earlier or finish later than the last-set boundary.
	// Initially they are set to one past their worst case to make the updating logic easier.
	// Since we assert we have a schedule, these values _will_ change.
	top = utils.StartOffset(23)
	bot = utils.StartOffset(-1)

	for _, s := range items {
		// Any show that isn't a sustainer affects the culling boundaries.
		if s.IsSustainer() {
			continue
		}

		if straddlesDay(s) {
			if scheduleStart.After(s.Start) {
				//This is the first item on the schedule and straddles the week, so we only set the top of the schedule
				//top = utils.StartOffset(0)
				//Temporarily disabled as this slot doesn't show up on the schedule
				continue
			} else if s.Finish.After(scheduleStart.AddDate(0, 0, 7)) {
				//This is the last item on the schedule and straddles the week, so we only set the bottom of the schedule
				bot = utils.StartOffset(23)
				continue
			} else {
				// An item that straddles the day crosses over from the end of a day to the start of the day.
				// This means that we saturate the culling boundaries.
				// As an optimisation we don't need to consider any other show.
				return utils.StartOffset(0), utils.StartOffset(23), nil
			}
		}

		// Otherwise, if its start/finish as offsets from start time are outside the current boundaries, update them.
		var ctop utils.StartOffset
		if ctop, err = utils.HourToStartOffset(s.Start.Hour()); err != nil {
			return
		}
		if ctop < top {
			top = ctop
		}

		var cbot utils.StartOffset
		if cbot, err = utils.HourToStartOffset(s.Finish.Hour()); err != nil {
			return
		}
		// cbot is the offset of the hour in which the item finishes.
		// This is _one past_ the last row the item occupies if the item ends cleanly at :00:00.
		if s.Finish.Minute() == 0 && s.Finish.Second() == 0 && s.Finish.Nanosecond() == 0 {
			cbot--
		}

		if bot < cbot {
			bot = cbot
		}
	}

	return
}

// rowDecision is an internal type recording information about which rows to display in the week schedule.
// It records, for one hour, the minute rows (00, 30, etc) that are switched 'on' for that row.
type rowDecision map[int]struct{}

// visible checks if the hour represented by row decision r is to be shown on the schedule.
func (r rowDecision) visible() bool {
	// Each visible row has its on-the-hour row set.
	_, visible := r[0]
	return visible
}

// mark adds a mark for the given minute to row decision r.
func (r rowDecision) mark(minute int) {
	r[minute] = struct{}{}
}

// toRow converts row decision r to a slice of schedule rows for the given hour.
func (r rowDecision) toRows(hour int) []WeekScheduleRow {
	minutes := make([]int, len(r))
	j := 0
	for k := range r {
		minutes[j] = k
		j++
	}
	sort.Ints(minutes)

	rows := make([]WeekScheduleRow, len(minutes))
	for j, m := range minutes {
		rows[j] = WeekScheduleRow{Hour: hour, Minute: m, Cells: []WeekScheduleCell{}}
	}
	return rows
}

// initRowDecisions creates 24 rowDecisions, from schedule start to schedule end.
// Each is marked as visble or invisible depending on the offsets top and bot.
func initRowDecisions(top, bot utils.StartOffset) ([]rowDecision, error) {
	// Make sure the offsets are valid.
	if !top.Valid() || !bot.Valid() {
		return nil, fmt.Errorf("initRowDecisions: row boundaries %d to %d are invalid", int(top), int(bot))
	}

	rows := make([]rowDecision, 24)

	// Go through each hour, culling ones before the boundaries, and adding on-the-hour minute marks to the others.
	// Boundaries are inclusive, so cull only things outside of them.
	for i := utils.StartOffset(0); i < utils.StartOffset(24); i++ {
		h, err := i.ToHour()
		if err != nil {
			return nil, err
		}

		rows[h] = rowDecision{}
		if top <= i && i <= bot {
			// This has the effect of making the row visible.
			rows[h].mark(0)
		}
	}

	return rows, nil
}

// addItemsToRowDecisions populates the row decision list rows with minute marks from schedule items not starting on the hour.
func addItemsToRowDecisions(rows []rowDecision, items []*ScheduleItem) {
	for _, item := range items {
		h := item.Start.Hour()
		if rows[h].visible() {
			rows[h].mark(item.Start.Minute())
		}
	}
}

// rowDecisionsToRows generates rows based on the per-hourly row decisions in rdecs.
func rowDecisionsToRows(rdecs []rowDecision) ([]WeekScheduleRow, error) {
	rows := []WeekScheduleRow{}

	for i := utils.StartOffset(0); i < utils.StartOffset(24); i++ {
		h, err := i.ToHour()
		if err != nil {
			return nil, err
		}

		if rdecs[h].visible() {
			rows = append(rows, rdecs[h].toRows(h)...)
		}
	}

	return rows, nil
}

// initScheduleRows takes a schedule and determines which rows should be displayed.
func initScheduleRows(items []*ScheduleItem, startTime time.Time) ([]WeekScheduleRow, error) {
	top, bot, err := calcScheduleBoundaries(items, startTime)
	if err != nil {
		return nil, err
	}

	rdecs, err := initRowDecisions(top, bot)
	if err != nil {
		return nil, err
	}
	addItemsToRowDecisions(rdecs, items)

	return rowDecisionsToRows(rdecs)
}

// populateRows fills schedule rows with timeslots.
// It takes the list of schedule start times on the days the schedule spans,
// the slice of rows to populate, and the schedule items to add.
func populateRows(days []time.Time, rows []WeekScheduleRow, items []*ScheduleItem) {
	currentItem := 0

	for d, day := range days {
		// We use this to find out when we've gone over midnight
		lastHour := -1
		// And this to find out where the current show started
		thisShowIndex := -1

		// Now, go through all the rows for this day.
		// We have to be careful to make sure we tick over day if we go past midnight.
		for i := range rows {
			if rows[i].Hour < lastHour {
				day = day.AddDate(0, 0, 1)
			}
			lastHour = rows[i].Hour

			rowTime := time.Date(day.Year(), day.Month(), day.Day(), rows[i].Hour, rows[i].Minute, 0, 0, time.Local)

			// Seek forwards if the current show has finished.
			for !items[currentItem].Finish.After(rowTime) {
				currentItem++
				thisShowIndex = -1
			}

			// If this is not the first time we've seen this slot,
			// update the rowspan in the first instance's cell and
			// put in a placeholder.
			if thisShowIndex != -1 {
				rows[thisShowIndex].Cells[d].RowSpan++
				rows[i].addCell(0, nil)
			} else {
				thisShowIndex = i
				rows[i].addCell(1, items[currentItem])
			}
		}
	}
}

// WeekSchedule is the type of week schedules.
type WeekSchedule struct {
	// Dates enumerates the dates this week schedule covers.
	Dates []time.Time
	// Table is the actual week table.
	// If there is no schedule for the given week, this will be nil.
	Table []WeekScheduleCol
}

// hasShows asks whether a schedule slice contains any non-sustainer shows.
// It assumes the slice has been filled with sustainer.
func hasShows(schedule []*ScheduleItem) bool {
	// This shouldn't happen, but if it does, this is the right thing to do.
	if len(schedule) == 0 {
		return false
	}

	// We know that, if a slice is filled but has no non-sustainer, then
	// the slice will contain only one sustainer item.  So, eliminate the
	// other cases.
	if 1 < len(schedule) || !schedule[0].IsSustainer() {
		return true
	}

	return false
}

// Flippin that table

// WeekScheduleCol represents one day in the week schedule.
type WeekScheduleCol struct {
	// The day of the show.
	Day time.Time
	// The cells inside this row.
	Cells []WeekScheduleCell
}

// addCell adds a cell with rowspan s and item i to the column c.
func (c *WeekScheduleCol) addCell(s uint, i *ScheduleItem, h int, m int) {
	c.Cells = append(c.Cells, WeekScheduleCell{RowSpan: s, Item: i, Hour: h, Minute: m})
}

// tableFilp flips the schedule table such that it becomes a list of days which have a list
// of shows on that day.
func tableFilp(rows []WeekScheduleRow, dates []time.Time) []WeekScheduleCol {
	days := make([]WeekScheduleCol, 7)
	for i := range days {
		days[i].Day = dates[i]
	}
	for _, row := range rows {
		for i, cell := range row.Cells {
			days[i].addCell(cell.RowSpan, cell.Item, row.Hour, row.Minute)
		}
	}
	return days
}

// tabulateWeekSchedule creates a schedule table from the given schedule slice.
func tabulateWeekSchedule(start, finish time.Time, schedule []*ScheduleItem) (*WeekSchedule, error) {
	days := []time.Time{}
	for d := start; d.Before(finish); d = d.AddDate(0, 0, 1) {
		days = append(days, d)
	}

	if !hasShows(schedule) {
		return &WeekSchedule{
			Dates: days,
			Table: nil,
		}, nil
	}

	rows, err := initScheduleRows(schedule, start)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	populateRows(days, rows, schedule)

	table := tableFilp(rows, days)

	sch := WeekSchedule{
		Dates: days,
		Table: table,
	}

	return &sch, nil
}
<commit_msg>Make sure weeks with only post-midnight shows work properly ... by forcing the schedule boundary to be before midnight, so the populator sees the change in day<commit_after>package models

import (
	"errors"
	"fmt"
	"log"
	"sort"
	"time"

	"github.com/UniversityRadioYork/2016-site/utils"
)

// weekFromVars extracts the year, and week strings from vars.
func weekFromVars(vars map[string]string) (string, string, error) {
	y, ok := vars["year"]
	if !ok {
		return "", "", errors.New("no year provided")
	}
	w, ok := vars["week"]
	if !ok {
		return "", "", errors.New("no week provided")
	}

	return y, w, nil
}

//
// Week schedule algorithm
// TODO(CaptainHayashi): move?
//

// WeekScheduleCell represents one cell in the week schedule.
type WeekScheduleCell struct {
	// Number of rows this cell spans.
	// If 0, this is a continuation from a cell further up.
	RowSpan uint

	// Pointer to the timeslot in this cell, if any.
	// Will be nil if 'RowSpan' is 0.
	Item *ScheduleItem

	// Hour stores which hour (row) the cell is in
	Hour int

	// Minute stores the minute for this row
	Minute int
}

// WeekScheduleRow represents one row in the week schedule.
type WeekScheduleRow struct {
	// The hour of the row (0..23).
	Hour int
	// The minute of the show (0..59).
	Minute int
	// The cells inside this row.
	Cells []WeekScheduleCell
}

// addCell adds a cell with rowspan s and item i to the row r.
func (r *WeekScheduleRow) addCell(s uint, i *ScheduleItem) {
	r.Cells = append(r.Cells, WeekScheduleCell{RowSpan: s, Item: i})
}

// straddlesDay checks whether a show's start and finish cross over the boundary of a URY day.
func straddlesDay(s *ScheduleItem) bool {
	dayBoundary := utils.StartHour
	adjustedStart := s.Start.Add(time.Hour * time.Duration(-dayBoundary))
	adjustedEnd := s.Finish.Add(time.Hour * time.Duration(-dayBoundary))
	straddle := adjustedEnd.Day() != adjustedStart.Day() && s.Finish.Sub(s.Start) > time.Hour
	return straddle
}

// calcScheduleBoundaries gets the offsets of the earliest and latest visible schedule hours.
// It returns these as top and bot respectively.
func calcScheduleBoundaries(items []*ScheduleItem, scheduleStart time.Time) (top, bot utils.StartOffset, err error) {
	if len(items) == 0 {
		err = errors.New("calculateScheduleBoundaries: no schedule")
		return
	}

	// These are the boundaries for culling, and are expanded upwards when we find shows that start earlier or finish later than the last-set boundary.
	// Initially they are set to one past their worst case to make the updating logic easier.
	// Since we assert we have a schedule, these values _will_ change.
	// (Top must be before 00:00 or the populator gets screwed up)
	top = utils.StartOffset(23 - utils.StartHour)
	bot = utils.StartOffset(-1)

	for _, s := range items {
		// Any show that isn't a sustainer affects the culling boundaries.
		if s.IsSustainer() {
			continue
		}

		if straddlesDay(s) {
			if scheduleStart.After(s.Start) {
				//This is the first item on the schedule and straddles the week, so we only set the top of the schedule
				//top = utils.StartOffset(0)
				//Temporarily disabled as this slot doesn't show up on the schedule
				continue
			} else if s.Finish.After(scheduleStart.AddDate(0, 0, 7)) {
				//This is the last item on the schedule and straddles the week, so we only set the bottom of the schedule
				bot = utils.StartOffset(23)
				continue
			} else {
				// An item that straddles the day crosses over from the end of a day to the start of the day.
				// This means that we saturate the culling boundaries.
				// As an optimisation we don't need to consider any other show.
				return utils.StartOffset(0), utils.StartOffset(23), nil
			}
		}

		// Otherwise, if its start/finish as offsets from start time are outside the current boundaries, update them.
		var ctop utils.StartOffset
		if ctop, err = utils.HourToStartOffset(s.Start.Hour()); err != nil {
			return
		}
		if ctop < top {
			top = ctop
		}

		var cbot utils.StartOffset
		if cbot, err = utils.HourToStartOffset(s.Finish.Hour()); err != nil {
			return
		}
		// cbot is the offset of the hour in which the item finishes.
		// This is _one past_ the last row the item occupies if the item ends cleanly at :00:00.
		if s.Finish.Minute() == 0 && s.Finish.Second() == 0 && s.Finish.Nanosecond() == 0 {
			cbot--
		}

		if bot < cbot {
			bot = cbot
		}
	}

	return
}

// rowDecision is an internal type recording information about which rows to display in the week schedule.
// It records, for one hour, the minute rows (00, 30, etc) that are switched 'on' for that row.
type rowDecision map[int]struct{}

// visible checks if the hour represented by row decision r is to be shown on the schedule.
func (r rowDecision) visible() bool {
	// Each visible row has its on-the-hour row set.
	_, visible := r[0]
	return visible
}

// mark adds a mark for the given minute to row decision r.
func (r rowDecision) mark(minute int) {
	r[minute] = struct{}{}
}

// toRow converts row decision r to a slice of schedule rows for the given hour.
func (r rowDecision) toRows(hour int) []WeekScheduleRow {
	minutes := make([]int, len(r))
	j := 0
	for k := range r {
		minutes[j] = k
		j++
	}
	sort.Ints(minutes)

	rows := make([]WeekScheduleRow, len(minutes))
	for j, m := range minutes {
		rows[j] = WeekScheduleRow{Hour: hour, Minute: m, Cells: []WeekScheduleCell{}}
	}
	return rows
}

// initRowDecisions creates 24 rowDecisions, from schedule start to schedule end.
// Each is marked as visble or invisible depending on the offsets top and bot.
func initRowDecisions(top, bot utils.StartOffset) ([]rowDecision, error) {
	// Make sure the offsets are valid.
	if !top.Valid() || !bot.Valid() {
		return nil, fmt.Errorf("initRowDecisions: row boundaries %d to %d are invalid", int(top), int(bot))
	}

	rows := make([]rowDecision, 24)

	// Go through each hour, culling ones before the boundaries, and adding on-the-hour minute marks to the others.
	// Boundaries are inclusive, so cull only things outside of them.
	for i := utils.StartOffset(0); i < utils.StartOffset(24); i++ {
		h, err := i.ToHour()
		if err != nil {
			return nil, err
		}

		rows[h] = rowDecision{}
		if top <= i && i <= bot {
			// This has the effect of making the row visible.
			rows[h].mark(0)
		}
	}

	return rows, nil
}

// addItemsToRowDecisions populates the row decision list rows with minute marks from schedule items not starting on the hour.
func addItemsToRowDecisions(rows []rowDecision, items []*ScheduleItem) {
	for _, item := range items {
		h := item.Start.Hour()
		if rows[h].visible() {
			rows[h].mark(item.Start.Minute())
		}
	}
}

// rowDecisionsToRows generates rows based on the per-hourly row decisions in rdecs.
func rowDecisionsToRows(rdecs []rowDecision) ([]WeekScheduleRow, error) {
	rows := []WeekScheduleRow{}

	for i := utils.StartOffset(0); i < utils.StartOffset(24); i++ {
		h, err := i.ToHour()
		if err != nil {
			return nil, err
		}

		if rdecs[h].visible() {
			rows = append(rows, rdecs[h].toRows(h)...)
		}
	}

	return rows, nil
}

// initScheduleRows takes a schedule and determines which rows should be displayed.
func initScheduleRows(items []*ScheduleItem, startTime time.Time) ([]WeekScheduleRow, error) {
	top, bot, err := calcScheduleBoundaries(items, startTime)
	if err != nil {
		return nil, err
	}

	rdecs, err := initRowDecisions(top, bot)
	if err != nil {
		return nil, err
	}
	addItemsToRowDecisions(rdecs, items)

	return rowDecisionsToRows(rdecs)
}

// populateRows fills schedule rows with timeslots.
// It takes the list of schedule start times on the days the schedule spans,
// the slice of rows to populate, and the schedule items to add.
func populateRows(days []time.Time, rows []WeekScheduleRow, items []*ScheduleItem) {
	currentItem := 0

	for d, day := range days {
		// We use this to find out when we've gone over midnight
		lastHour := -1
		// And this to find out where the current show started
		thisShowIndex := -1

		// Now, go through all the rows for this day.
		// We have to be careful to make sure we tick over day if we go past midnight.
		for i := range rows {
			if rows[i].Hour < lastHour {
				day = day.AddDate(0, 0, 1)
			}
			lastHour = rows[i].Hour

			rowTime := time.Date(day.Year(), day.Month(), day.Day(), rows[i].Hour, rows[i].Minute, 0, 0, time.Local)

			// Seek forwards if the current show has finished.
			for !items[currentItem].Finish.After(rowTime) {
				currentItem++
				thisShowIndex = -1
			}

			// If this is not the first time we've seen this slot,
			// update the rowspan in the first instance's cell and
			// put in a placeholder.
			if thisShowIndex != -1 {
				rows[thisShowIndex].Cells[d].RowSpan++
				rows[i].addCell(0, nil)
			} else {
				thisShowIndex = i
				rows[i].addCell(1, items[currentItem])
			}
		}
	}
}

// WeekSchedule is the type of week schedules.
type WeekSchedule struct {
	// Dates enumerates the dates this week schedule covers.
	Dates []time.Time
	// Table is the actual week table.
	// If there is no schedule for the given week, this will be nil.
	Table []WeekScheduleCol
}

// hasShows asks whether a schedule slice contains any non-sustainer shows.
// It assumes the slice has been filled with sustainer.
func hasShows(schedule []*ScheduleItem) bool {
	// This shouldn't happen, but if it does, this is the right thing to do.
	if len(schedule) == 0 {
		return false
	}

	// We know that, if a slice is filled but has no non-sustainer, then
	// the slice will contain only one sustainer item.  So, eliminate the
	// other cases.
	if 1 < len(schedule) || !schedule[0].IsSustainer() {
		return true
	}

	return false
}

// Flippin that table

// WeekScheduleCol represents one day in the week schedule.
type WeekScheduleCol struct {
	// The day of the show.
	Day time.Time
	// The cells inside this row.
	Cells []WeekScheduleCell
}

// addCell adds a cell with rowspan s and item i to the column c.
func (c *WeekScheduleCol) addCell(s uint, i *ScheduleItem, h int, m int) {
	c.Cells = append(c.Cells, WeekScheduleCell{RowSpan: s, Item: i, Hour: h, Minute: m})
}

// tableFilp flips the schedule table such that it becomes a list of days which have a list
// of shows on that day.
func tableFilp(rows []WeekScheduleRow, dates []time.Time) []WeekScheduleCol {
	days := make([]WeekScheduleCol, 7)
	for i := range days {
		days[i].Day = dates[i]
	}
	for _, row := range rows {
		for i, cell := range row.Cells {
			days[i].addCell(cell.RowSpan, cell.Item, row.Hour, row.Minute)
		}
	}
	return days
}

// tabulateWeekSchedule creates a schedule table from the given schedule slice.
func tabulateWeekSchedule(start, finish time.Time, schedule []*ScheduleItem) (*WeekSchedule, error) {
	days := []time.Time{}
	for d := start; d.Before(finish); d = d.AddDate(0, 0, 1) {
		days = append(days, d)
	}

	if !hasShows(schedule) {
		return &WeekSchedule{
			Dates: days,
			Table: nil,
		}, nil
	}

	rows, err := initScheduleRows(schedule, start)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	populateRows(days, rows, schedule)

	table := tableFilp(rows, days)

	sch := WeekSchedule{
		Dates: days,
		Table: table,
	}

	return &sch, nil
}
<|endoftext|>


<commit_before>package ssh

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"

	"github.com/docker/docker/pkg/term"
	"github.com/docker/machine/log"
	"github.com/docker/machine/utils"
	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/terminal"
)

type Client interface {
	Output(command string) (string, error)
	Shell() error
}

type ExternalClient struct {
	BaseArgs   []string
	BinaryPath string
}

type NativeClient struct {
	Config   ssh.ClientConfig
	Hostname string
	Port     int
}

type Auth struct {
	Passwords []string
	Keys      []string
}

type SSHClientType string

const (
	maxDialAttempts = 10
)

const (
	External SSHClientType = "external"
	Native   SSHClientType = "native"
)

var (
	baseSSHArgs = []string{
		"-o", "IdentitiesOnly=yes",
		"-o", "StrictHostKeyChecking=no",
		"-o", "UserKnownHostsFile=/dev/null",
		"-o", "LogLevel=quiet", // suppress "Warning: Permanently added '[localhost]:2022' (ECDSA) to the list of known hosts."
		"-o", "ConnectionAttempts=3", // retry 3 times if SSH connection fails
		"-o", "ConnectTimeout=10", // timeout after 10 seconds
	}
	defaultClientType SSHClientType = External
)

func SetDefaultClient(clientType SSHClientType) {
	// Allow over-riding of default client type, so that even if ssh binary
	// is found in PATH we can still use the Go native implementation if
	// desired.
	switch clientType {
	case External:
		defaultClientType = External
	case Native:
		defaultClientType = Native
	}
}

func NewClient(user string, host string, port int, auth *Auth) (Client, error) {
	sshBinaryPath, err := exec.LookPath("ssh")
	if err != nil {
		if defaultClientType == External {
			log.Fatal("Requested shellout SSH client type but no ssh binary available")
		}
		log.Debug("ssh binary not found, using native Go implementation")
		return NewNativeClient(user, host, port, auth)
	}

	if defaultClientType == Native {
		log.Debug("Using SSH client type: native")
		return NewNativeClient(user, host, port, auth)
	}

	log.Debug("Using SSH client type: external")
	return NewExternalClient(sshBinaryPath, user, host, port, auth)
}

func NewNativeClient(user, host string, port int, auth *Auth) (Client, error) {
	config, err := NewNativeConfig(user, auth)
	if err != nil {
		return nil, fmt.Errorf("Error getting config for native Go SSH: %s", err)
	}

	return NativeClient{
		Config:   config,
		Hostname: host,
		Port:     port,
	}, nil
}

func NewNativeConfig(user string, auth *Auth) (ssh.ClientConfig, error) {
	var (
		authMethods []ssh.AuthMethod
	)

	for _, k := range auth.Keys {
		key, err := ioutil.ReadFile(k)
		if err != nil {
			return ssh.ClientConfig{}, err
		}

		privateKey, err := ssh.ParsePrivateKey(key)
		if err != nil {
			return ssh.ClientConfig{}, err
		}

		authMethods = append(authMethods, ssh.PublicKeys(privateKey))
	}

	for _, p := range auth.Passwords {
		authMethods = append(authMethods, ssh.Password(p))
	}

	return ssh.ClientConfig{
		User: user,
		Auth: authMethods,
	}, nil
}

func (client NativeClient) dialSuccess() bool {
	if _, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", client.Hostname, client.Port), &client.Config); err != nil {
		log.Debugf("Error dialing TCP: %s", err)
		return false
	}
	return true
}

func (client NativeClient) Output(command string) (string, error) {
	if err := utils.WaitFor(client.dialSuccess); err != nil {
		return "", fmt.Errorf("Error attempting SSH client dial: %s", err)
	}

	conn, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", client.Hostname, client.Port), &client.Config)
	if err != nil {
		return "", fmt.Errorf("Mysterious error dialing TCP for SSH (we already succeeded at least once) : %s", err)
	}

	session, err := conn.NewSession()
	if err != nil {
		return "", fmt.Errorf("Error getting new session: %s", err)
	}

	defer session.Close()

	output, err := session.CombinedOutput(command)

	fd := int(os.Stdin.Fd())
	if err != nil {
		return string(output), err
	}

	termWidth, termHeight, err := terminal.GetSize(fd)
	if err != nil {
		return string(output), err
	}

	modes := ssh.TerminalModes{
		ssh.ECHO:          1,
		ssh.TTY_OP_ISPEED: 14400,
		ssh.TTY_OP_OSPEED: 14400,
	}

	// request tty -- fixes error with hosts that use
	// "Defaults requiretty" in /etc/sudoers - I'm looking at you RedHat
	if err := session.RequestPty("xterm-256color", termHeight, termWidth, modes); err != nil {
		return string(output), err
	}

	return string(output), session.Run(command)
}

func (client NativeClient) Shell() error {
	var (
		termWidth, termHeight int
	)
	conn, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", client.Hostname, client.Port), &client.Config)
	if err != nil {
		return err
	}

	session, err := conn.NewSession()
	if err != nil {
		return err
	}

	defer session.Close()

	session.Stdout = os.Stdout
	session.Stderr = os.Stderr
	session.Stdin = os.Stdin

	modes := ssh.TerminalModes{
		ssh.ECHO: 1,
	}

	fd := os.Stdin.Fd()

	if term.IsTerminal(fd) {
		oldState, err := term.MakeRaw(fd)
		if err != nil {
			return err
		}

		defer term.RestoreTerminal(fd, oldState)

		winsize, err := term.GetWinsize(fd)
		if err != nil {
			termWidth = 80
			termHeight = 24
		} else {
			termWidth = int(winsize.Width)
			termHeight = int(winsize.Height)
		}
	}

	if err := session.RequestPty("xterm", termHeight, termWidth, modes); err != nil {
		return err
	}

	if err := session.Shell(); err != nil {
		return err
	}

	session.Wait()

	return nil
}

func NewExternalClient(sshBinaryPath, user, host string, port int, auth *Auth) (ExternalClient, error) {
	client := ExternalClient{
		BinaryPath: sshBinaryPath,
	}

	// Base args take care of settings some options for us, e.g. don't use
	// the authorized hosts file.
	args := baseSSHArgs

	// Specify which private keys to use to authorize the SSH request.
	for _, privateKeyPath := range auth.Keys {
		args = append(args, "-i", privateKeyPath)
	}

	// Set which port to use for SSH.
	args = append(args, "-p", fmt.Sprintf("%d", port))

	// Set the user and hostname, e.g. ubuntu@12.34.56.78
	args = append(args, fmt.Sprintf("%s@%s", user, host))

	client.BaseArgs = args

	return client, nil
}

func (client ExternalClient) Output(command string) (string, error) {
	args := append(client.BaseArgs, command)

	cmd := exec.Command(client.BinaryPath, args...)
	log.Debug(cmd)

	// Allow piping of local things to remote commands.
	cmd.Stdin = os.Stdin

	output, err := cmd.CombinedOutput()
	return string(output), err
}

func (client ExternalClient) Shell() error {
	cmd := exec.Command(client.BinaryPath, client.BaseArgs...)
	log.Debug(cmd)

	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	return cmd.Run()
}
<commit_msg>ssh: add -t to force tty allocation<commit_after>package ssh

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"

	"github.com/docker/docker/pkg/term"
	"github.com/docker/machine/log"
	"github.com/docker/machine/utils"
	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/terminal"
)

type Client interface {
	Output(command string) (string, error)
	Shell() error
}

type ExternalClient struct {
	BaseArgs   []string
	BinaryPath string
}

type NativeClient struct {
	Config   ssh.ClientConfig
	Hostname string
	Port     int
}

type Auth struct {
	Passwords []string
	Keys      []string
}

type SSHClientType string

const (
	maxDialAttempts = 10
)

const (
	External SSHClientType = "external"
	Native   SSHClientType = "native"
)

var (
	baseSSHArgs = []string{
		"-o", "IdentitiesOnly=yes",
		"-o", "StrictHostKeyChecking=no",
		"-o", "UserKnownHostsFile=/dev/null",
		"-o", "LogLevel=quiet", // suppress "Warning: Permanently added '[localhost]:2022' (ECDSA) to the list of known hosts."
		"-o", "ConnectionAttempts=3", // retry 3 times if SSH connection fails
		"-o", "ConnectTimeout=10", // timeout after 10 seconds
		"-t", // force tty allocation
	}
	defaultClientType SSHClientType = External
)

func SetDefaultClient(clientType SSHClientType) {
	// Allow over-riding of default client type, so that even if ssh binary
	// is found in PATH we can still use the Go native implementation if
	// desired.
	switch clientType {
	case External:
		defaultClientType = External
	case Native:
		defaultClientType = Native
	}
}

func NewClient(user string, host string, port int, auth *Auth) (Client, error) {
	sshBinaryPath, err := exec.LookPath("ssh")
	if err != nil {
		if defaultClientType == External {
			log.Fatal("Requested shellout SSH client type but no ssh binary available")
		}
		log.Debug("ssh binary not found, using native Go implementation")
		return NewNativeClient(user, host, port, auth)
	}

	if defaultClientType == Native {
		log.Debug("Using SSH client type: native")
		return NewNativeClient(user, host, port, auth)
	}

	log.Debug("Using SSH client type: external")
	return NewExternalClient(sshBinaryPath, user, host, port, auth)
}

func NewNativeClient(user, host string, port int, auth *Auth) (Client, error) {
	config, err := NewNativeConfig(user, auth)
	if err != nil {
		return nil, fmt.Errorf("Error getting config for native Go SSH: %s", err)
	}

	return NativeClient{
		Config:   config,
		Hostname: host,
		Port:     port,
	}, nil
}

func NewNativeConfig(user string, auth *Auth) (ssh.ClientConfig, error) {
	var (
		authMethods []ssh.AuthMethod
	)

	for _, k := range auth.Keys {
		key, err := ioutil.ReadFile(k)
		if err != nil {
			return ssh.ClientConfig{}, err
		}

		privateKey, err := ssh.ParsePrivateKey(key)
		if err != nil {
			return ssh.ClientConfig{}, err
		}

		authMethods = append(authMethods, ssh.PublicKeys(privateKey))
	}

	for _, p := range auth.Passwords {
		authMethods = append(authMethods, ssh.Password(p))
	}

	return ssh.ClientConfig{
		User: user,
		Auth: authMethods,
	}, nil
}

func (client NativeClient) dialSuccess() bool {
	if _, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", client.Hostname, client.Port), &client.Config); err != nil {
		log.Debugf("Error dialing TCP: %s", err)
		return false
	}
	return true
}

func (client NativeClient) Output(command string) (string, error) {
	if err := utils.WaitFor(client.dialSuccess); err != nil {
		return "", fmt.Errorf("Error attempting SSH client dial: %s", err)
	}

	conn, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", client.Hostname, client.Port), &client.Config)
	if err != nil {
		return "", fmt.Errorf("Mysterious error dialing TCP for SSH (we already succeeded at least once) : %s", err)
	}

	session, err := conn.NewSession()
	if err != nil {
		return "", fmt.Errorf("Error getting new session: %s", err)
	}

	defer session.Close()

	output, err := session.CombinedOutput(command)

	fd := int(os.Stdin.Fd())
	if err != nil {
		return string(output), err
	}

	termWidth, termHeight, err := terminal.GetSize(fd)
	if err != nil {
		return string(output), err
	}

	modes := ssh.TerminalModes{
		ssh.ECHO:          1,
		ssh.TTY_OP_ISPEED: 14400,
		ssh.TTY_OP_OSPEED: 14400,
	}

	// request tty -- fixes error with hosts that use
	// "Defaults requiretty" in /etc/sudoers - I'm looking at you RedHat
	if err := session.RequestPty("xterm-256color", termHeight, termWidth, modes); err != nil {
		return string(output), err
	}

	return string(output), session.Run(command)
}

func (client NativeClient) Shell() error {
	var (
		termWidth, termHeight int
	)
	conn, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", client.Hostname, client.Port), &client.Config)
	if err != nil {
		return err
	}

	session, err := conn.NewSession()
	if err != nil {
		return err
	}

	defer session.Close()

	session.Stdout = os.Stdout
	session.Stderr = os.Stderr
	session.Stdin = os.Stdin

	modes := ssh.TerminalModes{
		ssh.ECHO: 1,
	}

	fd := os.Stdin.Fd()

	if term.IsTerminal(fd) {
		oldState, err := term.MakeRaw(fd)
		if err != nil {
			return err
		}

		defer term.RestoreTerminal(fd, oldState)

		winsize, err := term.GetWinsize(fd)
		if err != nil {
			termWidth = 80
			termHeight = 24
		} else {
			termWidth = int(winsize.Width)
			termHeight = int(winsize.Height)
		}
	}

	if err := session.RequestPty("xterm", termHeight, termWidth, modes); err != nil {
		return err
	}

	if err := session.Shell(); err != nil {
		return err
	}

	session.Wait()

	return nil
}

func NewExternalClient(sshBinaryPath, user, host string, port int, auth *Auth) (ExternalClient, error) {
	client := ExternalClient{
		BinaryPath: sshBinaryPath,
	}

	// Base args take care of settings some options for us, e.g. don't use
	// the authorized hosts file.
	args := baseSSHArgs

	// Specify which private keys to use to authorize the SSH request.
	for _, privateKeyPath := range auth.Keys {
		args = append(args, "-i", privateKeyPath)
	}

	// Set which port to use for SSH.
	args = append(args, "-p", fmt.Sprintf("%d", port))

	// Set the user and hostname, e.g. ubuntu@12.34.56.78
	args = append(args, fmt.Sprintf("%s@%s", user, host))

	client.BaseArgs = args

	return client, nil
}

func (client ExternalClient) Output(command string) (string, error) {
	args := append(client.BaseArgs, command)

	cmd := exec.Command(client.BinaryPath, args...)
	log.Debug(cmd)

	// Allow piping of local things to remote commands.
	cmd.Stdin = os.Stdin

	output, err := cmd.CombinedOutput()
	return string(output), err
}

func (client ExternalClient) Shell() error {
	cmd := exec.Command(client.BinaryPath, client.BaseArgs...)
	log.Debug(cmd)

	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	return cmd.Run()
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"os"
	"os/signal"
	"syscall"

	"github.com/micro/cli"
	"github.com/micro/go-micro/config/cmd"
	gorun "github.com/micro/go-micro/runtime"
	"github.com/micro/go-micro/util/log"

	// include usage

	"github.com/micro/micro/internal/update"
	_ "github.com/micro/micro/internal/usage"
)

type initNotifier struct {
	gorun.Notifier
	services []string
}

func (i *initNotifier) Notify() (<-chan gorun.Event, error) {
	ch, err := i.Notifier.Notify()
	if err != nil {
		return nil, err
	}

	// create new event channel
	evChan := make(chan gorun.Event, 32)

	go func() {
		for ev := range ch {
			// fire an event per service
			for _, service := range i.services {
				evChan <- gorun.Event{
					Service:   service,
					Version:   ev.Version,
					Timestamp: ev.Timestamp,
					Type:      ev.Type,
				}
			}
		}

		// we've reached the end
		close(evChan)
	}()

	return evChan, nil
}

func initNotify(n gorun.Notifier, services []string) gorun.Notifier {
	return &initNotifier{n, services}
}

func initCommand(context *cli.Context) {
	log.Name("init")

	if len(context.Args()) > 0 {
		cli.ShowSubcommandHelp(context)
		os.Exit(1)
	}

	// services to manage
	services := []string{
		// network services
		"network.api",
		"network.dns",
		"network.web",
		// runtime services
		"network",  // :8085
		"runtime",  // :8088
		"registry", // :8000
		"broker",   // :8001
		"store",    // :8002
		"tunnel",   // :8083
		"router",   // :8084
		"monitor",  // :????
		"debug",    // :????
		"proxy",    // :8081
		"api",      // :8080
		"web",      // :8082
		"bot",      // :????
		"init",     // no port, manage self
	}

	// get the service prefix
	if namespace := context.GlobalString("namespace"); len(namespace) > 0 {
		for i, service := range services {
			services[i] = fmt.Sprintf("%s.%s", namespace, service)
		}
	}

	// create new micro runtime
	muRuntime := cmd.DefaultCmd.Options().Runtime

	// Use default update notifier
	notifier := update.NewNotifier(BuildDate)
	wrapped := initNotify(notifier, services)

	// specify with a notifier that fires
	// individual events for each service
	options := []gorun.Option{
		gorun.WithNotifier(wrapped),
		gorun.WithType("runtime"),
	}
	(*muRuntime).Init(options...)

	// used to signal when to shutdown
	shutdown := make(chan os.Signal, 1)
	signal.Notify(shutdown, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT)

	log.Info("Starting service runtime")

	// start the runtime
	if err := (*muRuntime).Start(); err != nil {
		log.Fatal(err)
	}

	log.Info("Service runtime started")

	select {
	case <-shutdown:
		log.Info("Shutdown signal received")
		log.Info("Stopping service runtime")
	}

	// stop all the things
	if err := (*muRuntime).Stop(); err != nil {
		log.Fatal(err)
	}

	log.Info("Service runtime shutdown")

	// exit success
	os.Exit(0)
}
<commit_msg>add debug web to init updates<commit_after>package cmd

import (
	"fmt"
	"os"
	"os/signal"
	"syscall"

	"github.com/micro/cli"
	"github.com/micro/go-micro/config/cmd"
	gorun "github.com/micro/go-micro/runtime"
	"github.com/micro/go-micro/util/log"

	// include usage

	"github.com/micro/micro/internal/update"
	_ "github.com/micro/micro/internal/usage"
)

type initNotifier struct {
	gorun.Notifier
	services []string
}

func (i *initNotifier) Notify() (<-chan gorun.Event, error) {
	ch, err := i.Notifier.Notify()
	if err != nil {
		return nil, err
	}

	// create new event channel
	evChan := make(chan gorun.Event, 32)

	go func() {
		for ev := range ch {
			// fire an event per service
			for _, service := range i.services {
				evChan <- gorun.Event{
					Service:   service,
					Version:   ev.Version,
					Timestamp: ev.Timestamp,
					Type:      ev.Type,
				}
			}
		}

		// we've reached the end
		close(evChan)
	}()

	return evChan, nil
}

func initNotify(n gorun.Notifier, services []string) gorun.Notifier {
	return &initNotifier{n, services}
}

func initCommand(context *cli.Context) {
	log.Name("init")

	if len(context.Args()) > 0 {
		cli.ShowSubcommandHelp(context)
		os.Exit(1)
	}

	// services to manage
	services := []string{
		// network services
		"network.api",
		"network.dns",
		"network.web",
		"debug.web",
		// runtime services
		"network",  // :8085
		"runtime",  // :8088
		"registry", // :8000
		"broker",   // :8001
		"store",    // :8002
		"tunnel",   // :8083
		"router",   // :8084
		"monitor",  // :????
		"debug",    // :????
		"proxy",    // :8081
		"api",      // :8080
		"web",      // :8082
		"bot",      // :????
		"init",     // no port, manage self
	}

	// get the service prefix
	if namespace := context.GlobalString("namespace"); len(namespace) > 0 {
		for i, service := range services {
			services[i] = fmt.Sprintf("%s.%s", namespace, service)
		}
	}

	// create new micro runtime
	muRuntime := cmd.DefaultCmd.Options().Runtime

	// Use default update notifier
	notifier := update.NewNotifier(BuildDate)
	wrapped := initNotify(notifier, services)

	// specify with a notifier that fires
	// individual events for each service
	options := []gorun.Option{
		gorun.WithNotifier(wrapped),
		gorun.WithType("runtime"),
	}
	(*muRuntime).Init(options...)

	// used to signal when to shutdown
	shutdown := make(chan os.Signal, 1)
	signal.Notify(shutdown, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT)

	log.Info("Starting service runtime")

	// start the runtime
	if err := (*muRuntime).Start(); err != nil {
		log.Fatal(err)
	}

	log.Info("Service runtime started")

	select {
	case <-shutdown:
		log.Info("Shutdown signal received")
		log.Info("Stopping service runtime")
	}

	// stop all the things
	if err := (*muRuntime).Stop(); err != nil {
		log.Fatal(err)
	}

	log.Info("Service runtime shutdown")

	// exit success
	os.Exit(0)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"github.com/dooman87/transformimgs/health"
	"github.com/dooman87/transformimgs/img"
	"log"
	"net/http"
)

func main() {
	flag.Parse()

	http.HandleFunc("/health", health.Health)

	img.CheckImagemagick()
	img := img.Service{
		Processor: &img.ImageMagickProcessor{},
		Reader:    &img.ImgUrlReader{},
	}
	http.HandleFunc("/img/resize", http.HandlerFunc(img.ResizeUrl))

	log.Fatal(http.ListenAndServe(":8080", nil))
}
<commit_msg>Added logging to signal that the application was started.<commit_after>package main

import (
	"flag"
	"github.com/dooman87/transformimgs/health"
	"github.com/dooman87/transformimgs/img"
	"github.com/golang/glog"
	"log"
	"net/http"
)

func main() {
	flag.Parse()

	http.HandleFunc("/health", health.Health)

	img.CheckImagemagick()
	img := img.Service{
		Processor: &img.ImageMagickProcessor{},
		Reader:    &img.ImgUrlReader{},
	}
	http.HandleFunc("/img/resize", http.HandlerFunc(img.ResizeUrl))

	glog.Info("Running the applicaiton on port 8080...")
	log.Fatal(http.ListenAndServe(":8080", nil))
}
<|endoftext|>


<commit_before>// Images transformations API
//
// The purpose of this API is to provide a set of
// endpoints that will transform and optimise images.
// Then it becomes easy to use the API with <img> and <picture> tags in web development.
//
// Version: 2
// Schemes: https
// Host: pixboost.com
// BasePath: /api/2/
// Security:
// - api_key:
// SecurityDefinitions:
//   api_key:
//     type: apiKey
//     name: auth
//     in: query
// swagger:meta
package main

import (
	"flag"
	"github.com/Pixboost/transformimgs/img"
	"github.com/Pixboost/transformimgs/img/processors"
	"github.com/Pixboost/transformimgs/img/reader"
	"github.com/dooman87/kolibri/health"
	"net/http"
	"os"
	"runtime"
)

func main() {
	var (
		im      string
		imIdent string
		cache   int
		procNum int
	)
	flag.StringVar(&im, "imConvert", "", "Imagemagick convert command")
	flag.StringVar(&imIdent, "imIdentify", "", "Imagemagick identify command")
	flag.IntVar(&cache, "cache", 86400,
		"Number of seconds to cache image after transformation (0 to disable cache). Default value is 86400 (one day)")
	flag.IntVar(&procNum, "proc", runtime.NumCPU(), "Number of images processors to run. Defaults to number of CPUs")
	flag.Parse()

	p, err := processors.NewImageMagick(im, imIdent, []string{
		"-limit", "memory", "64MiB",
		"-limit", "memory", "128MiB",
	})
	if err != nil {
		img.Log.Errorf("Can't create image magic processor: %+v", err)
		os.Exit(1)
	}

	img.CacheTTL = cache
	srv, err := img.NewService(&reader.Http{}, p, procNum)
	if err != nil {
		img.Log.Errorf("Can't create image service: %+v", err)
		os.Exit(2)
	}

	router := srv.GetRouter()
	router.HandleFunc("/health", health.Health)

	img.Log.Printf("Running the applicaiton on port 8080...\n")
	err = http.ListenAndServe(":8080", router)

	if err != nil {
		img.Log.Errorf("Error while stopping application: %+v", err)
		os.Exit(3)
	}
	os.Exit(0)
}
<commit_msg>FIX: Setting fmap memory limit<commit_after>// Images transformations API
//
// The purpose of this API is to provide a set of
// endpoints that will transform and optimise images.
// Then it becomes easy to use the API with <img> and <picture> tags in web development.
//
// Version: 2
// Schemes: https
// Host: pixboost.com
// BasePath: /api/2/
// Security:
// - api_key:
// SecurityDefinitions:
//   api_key:
//     type: apiKey
//     name: auth
//     in: query
// swagger:meta
package main

import (
	"flag"
	"github.com/Pixboost/transformimgs/img"
	"github.com/Pixboost/transformimgs/img/processors"
	"github.com/Pixboost/transformimgs/img/reader"
	"github.com/dooman87/kolibri/health"
	"net/http"
	"os"
	"runtime"
)

func main() {
	var (
		im      string
		imIdent string
		cache   int
		procNum int
	)
	flag.StringVar(&im, "imConvert", "", "Imagemagick convert command")
	flag.StringVar(&imIdent, "imIdentify", "", "Imagemagick identify command")
	flag.IntVar(&cache, "cache", 86400,
		"Number of seconds to cache image after transformation (0 to disable cache). Default value is 86400 (one day)")
	flag.IntVar(&procNum, "proc", runtime.NumCPU(), "Number of images processors to run. Defaults to number of CPUs")
	flag.Parse()

	p, err := processors.NewImageMagick(im, imIdent, []string{
		"-limit", "memory", "64MiB",
		"-limit", "map", "128MiB",
	})
	if err != nil {
		img.Log.Errorf("Can't create image magic processor: %+v", err)
		os.Exit(1)
	}

	img.CacheTTL = cache
	srv, err := img.NewService(&reader.Http{}, p, procNum)
	if err != nil {
		img.Log.Errorf("Can't create image service: %+v", err)
		os.Exit(2)
	}

	router := srv.GetRouter()
	router.HandleFunc("/health", health.Health)

	img.Log.Printf("Running the applicaiton on port 8080...\n")
	err = http.ListenAndServe(":8080", router)

	if err != nil {
		img.Log.Errorf("Error while stopping application: %+v", err)
		os.Exit(3)
	}
	os.Exit(0)
}
<|endoftext|>


<commit_before>// Copyright © 2017 Michael Lihs
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package cmd

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"os"

	"reflect"

	"github.com/hashicorp/go-cleanhttp"
	"github.com/hashicorp/go-rootcerts"
	"github.com/michaellihs/golab/cmd/mapper"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"github.com/xanzy/go-gitlab"
)

var cfgFile, caFile, caPath string

var gitlabClient *gitlab.Client

type golabCommand struct {
	Parent *cobra.Command
	Flags  interface{}
	Opts   interface{}
	Paged  bool
	Run    func(cmd golabCommand) error
	Mapper mapper.FlagMapper
	Cmd    *cobra.Command
}

func (c golabCommand) Execute() error {
	_, _, err := c.Mapper.AutoMap()
	if err != nil {
		return err
	}
	c.Flags = c.Mapper.MappedFlags()
	c.Opts = c.Mapper.MappedOpts()
	if err = applyPagination(c); err != nil {
		return err
	}
	return c.Run(c)
}

func applyPagination(c golabCommand) error {
	if c.Paged {
		optsReflected := reflect.ValueOf(c.Opts).Elem()
		page, err := c.Cmd.Flags().GetInt("page")
		if err != nil {
			return err
		}
		optsReflected.FieldByName("ListOptions").FieldByName("Page").Set(reflect.ValueOf(page))
		perPage, err := c.Cmd.Flags().GetInt("per_page")
		if err != nil {
			return err
		}
		optsReflected.FieldByName("ListOptions").FieldByName("PerPage").Set(reflect.ValueOf(perPage))
	}
	return nil
}

func (c golabCommand) Init() error {
	c.Cmd.RunE = func(cmd *cobra.Command, args []string) error {
		return c.Execute()
	}
	c.Mapper = mapper.InitializedMapper(c.Cmd, c.Flags, c.Opts)
	setPaginationFlags(c)
	c.Parent.AddCommand(c.Cmd)
	return nil // TODO do something useful with the error return
}

func setPaginationFlags(c golabCommand) {
	if c.Paged {
		c.Cmd.PersistentFlags().Int("page", 0, "(optional) Page of results to retrieve")
		c.Cmd.PersistentFlags().Int("per_page", 0, "(optional) The number of results to include per page (max 100)")
	}
}

var RootCmd = &cobra.Command{
	Use:               "golab",
	Short:             "Gitlab CLI written in Go",
	Long:              `This application provides a Command Line Interface for Gitlab.`,
	DisableAutoGenTag: true, // disables footer in markdown files generated by cobra.gendoc
}

func Execute() {
	initRootCommand()
	if err := RootCmd.Execute(); err != nil {
		os.Exit(-1)
	}
}

func OutputJson(object interface{}) error {
	result, err := json.MarshalIndent(object, "", "  ")
	if err != nil {
		return err
	}
	fmt.Println(string(result))
	return nil
}

func initRootCommand() {
	RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "(optional) CURRENTLY NOT SUPPORTED config file (default is ./.golab.yml and $HOME/.golab.yml)")
	RootCmd.PersistentFlags().StringVar(&caFile, "ca-file", "", "(optional) provides a .pem file to be used in certificates pool for SSL connection")
	RootCmd.PersistentFlags().StringVar(&caPath, "ca-path", "", "(optional) provides a directory with .pem certificates to be used for SSL connection")

	// TODO this is an ugly hack to prevent re-initialization when mocked in testing
	if gitlabClient == nil {
		cobra.OnInitialize(initConfig)
		cobra.OnInitialize(initGitlabClient)
	}
}

func initConfig() {
	if cfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(cfgFile)
	}

	// TODO read config from --config flag
	viper.SetConfigName(".golab") // name of config file (without extension)
	viper.AddConfigPath(".")      // adding current directory as first search path
	viper.AddConfigPath("$HOME")  // adding home directory as first search path
	viper.AutomaticEnv()          // read in environment variables that match

	if err := viper.ReadInConfig(); err != nil {
		fmt.Println(err)
	}
}

func initGitlabClient() {
	baseUrl, err := url.Parse(viper.GetString("url"))
	if err != nil {
		fmt.Printf("Could not parse given URL '%s': %s", baseUrl, err)
	}

	httpClient, err := initHttpClient()
	if err != nil {
		panic("Error in initializing http client " + err.Error())
	}

	gitlabClient = gitlab.NewClient(httpClient, viper.GetString("token"))
	gitlabClient.SetBaseURL(baseUrl.String() + "/api/v4")
}

func initHttpClient() (*http.Client, error) {
	// see https://github.com/hashicorp/go-rootcerts
	tlsConfig := &tls.Config{}
	err := rootcerts.ConfigureTLS(tlsConfig, &rootcerts.Config{
		//CAFile: os.Getenv("GOLAB_CAFILE"),
		//CAPath: os.Getenv("GOLAB_CAPATH"),
		CAFile: caFile,
		CAPath: caPath,
	})
	if err != nil {
		return nil, err
	}
	c := cleanhttp.DefaultClient()
	t := cleanhttp.DefaultTransport()

	// use this line for debugging certificates
	//fmt.Println(tlsConfig.RootCAs)

	t.TLSClientConfig = tlsConfig
	c.Transport = t
	return c, nil

	// TODO this is an ugly hack to prevent SSL verification... see https://github.com/andygrunwald/go-jira/issues/52
	//tr := &http.Transport{
	//	TLSClientConfig: &tls.Config{InsecureSkipVerify : true},
	//}
	//return &http.Client{Transport: tr}, nil
}

func isoTime2String(time *gitlab.ISOTime) (string, error) {
	bytes, err := time.MarshalJSON()
	return string(bytes), err
}
<commit_msg>add support for `--config`<commit_after>// Copyright © 2017 Michael Lihs
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package cmd

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"os"

	"reflect"

	"github.com/hashicorp/go-cleanhttp"
	"github.com/hashicorp/go-rootcerts"
	"github.com/michaellihs/golab/cmd/mapper"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"github.com/xanzy/go-gitlab"
)

var cfgFile, caFile, caPath string

var gitlabClient *gitlab.Client

type golabCommand struct {
	Parent *cobra.Command
	Flags  interface{}
	Opts   interface{}
	Paged  bool
	Run    func(cmd golabCommand) error
	Mapper mapper.FlagMapper
	Cmd    *cobra.Command
}

func (c golabCommand) Execute() error {
	_, _, err := c.Mapper.AutoMap()
	if err != nil {
		return err
	}
	c.Flags = c.Mapper.MappedFlags()
	c.Opts = c.Mapper.MappedOpts()
	if err = applyPagination(c); err != nil {
		return err
	}
	return c.Run(c)
}

func applyPagination(c golabCommand) error {
	if c.Paged {
		optsReflected := reflect.ValueOf(c.Opts).Elem()
		page, err := c.Cmd.Flags().GetInt("page")
		if err != nil {
			return err
		}
		optsReflected.FieldByName("ListOptions").FieldByName("Page").Set(reflect.ValueOf(page))
		perPage, err := c.Cmd.Flags().GetInt("per_page")
		if err != nil {
			return err
		}
		optsReflected.FieldByName("ListOptions").FieldByName("PerPage").Set(reflect.ValueOf(perPage))
	}
	return nil
}

func (c golabCommand) Init() error {
	c.Cmd.RunE = func(cmd *cobra.Command, args []string) error {
		return c.Execute()
	}
	c.Mapper = mapper.InitializedMapper(c.Cmd, c.Flags, c.Opts)
	setPaginationFlags(c)
	c.Parent.AddCommand(c.Cmd)
	return nil // TODO do something useful with the error return
}

func setPaginationFlags(c golabCommand) {
	if c.Paged {
		c.Cmd.PersistentFlags().Int("page", 0, "(optional) Page of results to retrieve")
		c.Cmd.PersistentFlags().Int("per_page", 0, "(optional) The number of results to include per page (max 100)")
	}
}

var RootCmd = &cobra.Command{
	Use:               "golab",
	Short:             "Gitlab CLI written in Go",
	Long:              `This application provides a Command Line Interface for Gitlab.`,
	DisableAutoGenTag: true, // disables footer in markdown files generated by cobra.gendoc
}

func Execute() {
	initRootCommand()
	if err := RootCmd.Execute(); err != nil {
		os.Exit(-1)
	}
}

func OutputJson(object interface{}) error {
	result, err := json.MarshalIndent(object, "", "  ")
	if err != nil {
		return err
	}
	fmt.Println(string(result))
	return nil
}

func initRootCommand() {
	RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "(optional) golab config file (default is ./.golab.yml and $HOME/.golab.yml)")
	RootCmd.PersistentFlags().StringVar(&caFile, "ca-file", "", "(optional) provides a .pem file to be used in certificates pool for SSL connection")
	RootCmd.PersistentFlags().StringVar(&caPath, "ca-path", "", "(optional) provides a directory with .pem certificates to be used for SSL connection")

	// TODO this is an ugly hack to prevent re-initialization when mocked in testing
	if gitlabClient == nil {
		cobra.OnInitialize(initConfig)
		cobra.OnInitialize(initGitlabClient)
	}
}

func initConfig() {
	if cfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(cfgFile)
	}

	if config, err := RootCmd.PersistentFlags().GetString("config"); err == nil && config != "" {
		viper.SetConfigFile(config)
	} else {
		viper.SetConfigName(".golab") // name of config file (without extension)
		viper.AddConfigPath(".")      // adding current directory as first search path
		viper.AddConfigPath("$HOME")  // adding home directory as second search path
	}
	viper.AutomaticEnv() // read in environment variables that match

	if err := viper.ReadInConfig(); err != nil {
		fmt.Println(err)
	}
}

func initGitlabClient() {
	baseUrl, err := url.Parse(viper.GetString("url"))
	if err != nil {
		fmt.Printf("Could not parse given URL '%s': %s", baseUrl, err)
	}

	httpClient, err := initHttpClient()
	if err != nil {
		panic("Error in initializing http client " + err.Error())
	}

	gitlabClient = gitlab.NewClient(httpClient, viper.GetString("token"))
	gitlabClient.SetBaseURL(baseUrl.String() + "/api/v4")
}

func initHttpClient() (*http.Client, error) {
	// see https://github.com/hashicorp/go-rootcerts
	tlsConfig := &tls.Config{}
	err := rootcerts.ConfigureTLS(tlsConfig, &rootcerts.Config{
		//CAFile: os.Getenv("GOLAB_CAFILE"),
		//CAPath: os.Getenv("GOLAB_CAPATH"),
		CAFile: caFile,
		CAPath: caPath,
	})
	if err != nil {
		return nil, err
	}
	c := cleanhttp.DefaultClient()
	t := cleanhttp.DefaultTransport()

	// use this line for debugging certificates
	//fmt.Println(tlsConfig.RootCAs)

	t.TLSClientConfig = tlsConfig
	c.Transport = t
	return c, nil

	// TODO this is an ugly hack to prevent SSL verification... see https://github.com/andygrunwald/go-jira/issues/52
	//tr := &http.Transport{
	//	TLSClientConfig: &tls.Config{InsecureSkipVerify : true},
	//}
	//return &http.Client{Transport: tr}, nil
}

func isoTime2String(time *gitlab.ISOTime) (string, error) {
	bytes, err := time.MarshalJSON()
	return string(bytes), err
}
<|endoftext|>


<commit_before>// Copyright © 2016 Tobias Wellnitz, DH1TW <Tobias.Wellnitz@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package cmd

import (
	"fmt"
	"os"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var cfgFile string

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "mqttaudio",
	Short: "A brief description of your application",
	Long: `A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
// Uncomment the following line if your bare application
// has an action associated with it:
//	Run: func(cmd *cobra.Command, args []string) { },
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)

	// Here you will define your flags and configuration settings.
	// Cobra supports Persistent Flags, which, if defined here,
	// will be global for your application.

	RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.mqttaudio.yaml)")
	// Cobra also supports local flags, which will only run
	// when this action is called directly.
	RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if cfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(cfgFile)
	}

	viper.SetConfigName(".mqttaudio") // name of config file (without extension)
	viper.AddConfigPath("$HOME")  // adding home directory as first search path
	viper.AutomaticEnv()          // read in environment variables that match

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}
}
<commit_msg>corrected name<commit_after>// Copyright © 2016 Tobias Wellnitz, DH1TW <Tobias.Wellnitz@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package cmd

import (
	"fmt"
	"os"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var cfgFile string

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "remoteAudio",
	Short: "A brief description of your application",
	Long: `A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
	// Uncomment the following line if your bare application
	// has an action associated with it:
	//	Run: func(cmd *cobra.Command, args []string) { },
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)

	// Here you will define your flags and configuration settings.
	// Cobra supports Persistent Flags, which, if defined here,
	// will be global for your application.

	RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.remoteAudio.yaml)")
	// Cobra also supports local flags, which will only run
	// when this action is called directly.
	RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if cfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(cfgFile)
	}

	viper.SetConfigName(".remoteAudio") // name of config file (without extension)
	viper.AddConfigPath("$HOME")        // adding home directory as first search path
	viper.AutomaticEnv()                // read in environment variables that match

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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 cmd

import (
	"fmt"
	"os"
	"strconv"

	"github.com/spf13/cobra"
	"github.com/srinandan/apigeecli/apiclient"
	"github.com/srinandan/apigeecli/cmd/apis"
	"github.com/srinandan/apigeecli/cmd/apps"
	cache "github.com/srinandan/apigeecli/cmd/cache"
	"github.com/srinandan/apigeecli/cmd/developers"
	"github.com/srinandan/apigeecli/cmd/env"
	flowhooks "github.com/srinandan/apigeecli/cmd/flowhooks"
	"github.com/srinandan/apigeecli/cmd/iam"
	"github.com/srinandan/apigeecli/cmd/istio"
	"github.com/srinandan/apigeecli/cmd/keyaliases"
	"github.com/srinandan/apigeecli/cmd/keystores"
	"github.com/srinandan/apigeecli/cmd/kvm"
	"github.com/srinandan/apigeecli/cmd/org"
	"github.com/srinandan/apigeecli/cmd/products"
	"github.com/srinandan/apigeecli/cmd/projects"
	"github.com/srinandan/apigeecli/cmd/references"
	res "github.com/srinandan/apigeecli/cmd/res"
	"github.com/srinandan/apigeecli/cmd/sharedflows"
	"github.com/srinandan/apigeecli/cmd/sync"
	targetservers "github.com/srinandan/apigeecli/cmd/targetservers"
	"github.com/srinandan/apigeecli/cmd/token"
)

//RootCmd to manage apigeecli
var RootCmd = &cobra.Command{
	Use:   "apigeecli",
	Short: "Utility to work with Apigee APIs.",
	Long:  "This command lets you interact with Apigee APIs.",
	PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
		apiclient.SetServiceAccount(serviceAccount)
		apiclient.SetApigeeToken(accessToken)

		err := apiclient.SetAccessToken()
		if err != nil {
			return err
		}
		return nil
	},
}

func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

var accessToken, serviceAccount string

func init() {
	cobra.OnInitialize(initConfig)

	RootCmd.PersistentFlags().StringVarP(&accessToken, "token", "t",
		"", "Google OAuth Token")

	RootCmd.PersistentFlags().StringVarP(&serviceAccount, "account", "a",
		"", "Path Service Account private key in JSON")

	RootCmd.AddCommand(apis.Cmd)
	RootCmd.AddCommand(org.Cmd)
	RootCmd.AddCommand(sync.Cmd)
	RootCmd.AddCommand(env.Cmd)
	RootCmd.AddCommand(products.Cmd)
	RootCmd.AddCommand(developers.Cmd)
	RootCmd.AddCommand(apps.Cmd)
	RootCmd.AddCommand(sharedflows.Cmd)
	RootCmd.AddCommand(kvm.Cmd)
	RootCmd.AddCommand(flowhooks.Cmd)
	RootCmd.AddCommand(targetservers.Cmd)
	RootCmd.AddCommand(token.Cmd)
	RootCmd.AddCommand(keystores.Cmd)
	RootCmd.AddCommand(keyaliases.Cmd)
	RootCmd.AddCommand(cache.Cmd)
	RootCmd.AddCommand(references.Cmd)
	RootCmd.AddCommand(res.Cmd)
	RootCmd.AddCommand(projects.Cmd)
	RootCmd.AddCommand(iam.Cmd)
	RootCmd.AddCommand(istio.Cmd)
}

func initConfig() {
	var skipLogInfo = true
	var skipCache bool

	if os.Getenv("APIGEECLI_SKIPLOG") == "false" {
		skipLogInfo = false
	}

	skipCache, _ = strconv.ParseBool(os.Getenv("APIGEECLI_SKIPCACHE"))

	apiclient.NewApigeeClient(apiclient.ApigeeClientOptions{
		SkipCheck:   true,
		PrintOutput: true,
		SkipLogInfo: skipLogInfo,
		SkipCache:   skipCache,
	})
}

// GetRootCmd returns the root of the cobra command-tree.
func GetRootCmd() *cobra.Command {
	return RootCmd
}
<commit_msg>rename istio to envoy<commit_after>// Copyright 2020 Google LLC
//
// 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 cmd

import (
	"fmt"
	"os"
	"strconv"

	"github.com/spf13/cobra"
	"github.com/srinandan/apigeecli/apiclient"
	"github.com/srinandan/apigeecli/cmd/apis"
	"github.com/srinandan/apigeecli/cmd/apps"
	cache "github.com/srinandan/apigeecli/cmd/cache"
	"github.com/srinandan/apigeecli/cmd/developers"
	"github.com/srinandan/apigeecli/cmd/env"
	"github.com/srinandan/apigeecli/cmd/envoy"
	flowhooks "github.com/srinandan/apigeecli/cmd/flowhooks"
	"github.com/srinandan/apigeecli/cmd/iam"
	"github.com/srinandan/apigeecli/cmd/keyaliases"
	"github.com/srinandan/apigeecli/cmd/keystores"
	"github.com/srinandan/apigeecli/cmd/kvm"
	"github.com/srinandan/apigeecli/cmd/org"
	"github.com/srinandan/apigeecli/cmd/products"
	"github.com/srinandan/apigeecli/cmd/projects"
	"github.com/srinandan/apigeecli/cmd/references"
	res "github.com/srinandan/apigeecli/cmd/res"
	"github.com/srinandan/apigeecli/cmd/sharedflows"
	"github.com/srinandan/apigeecli/cmd/sync"
	targetservers "github.com/srinandan/apigeecli/cmd/targetservers"
	"github.com/srinandan/apigeecli/cmd/token"
)

//RootCmd to manage apigeecli
var RootCmd = &cobra.Command{
	Use:   "apigeecli",
	Short: "Utility to work with Apigee APIs.",
	Long:  "This command lets you interact with Apigee APIs.",
	PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
		apiclient.SetServiceAccount(serviceAccount)
		apiclient.SetApigeeToken(accessToken)

		err := apiclient.SetAccessToken()
		if err != nil {
			return err
		}
		return nil
	},
}

func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

var accessToken, serviceAccount string

func init() {
	cobra.OnInitialize(initConfig)

	RootCmd.PersistentFlags().StringVarP(&accessToken, "token", "t",
		"", "Google OAuth Token")

	RootCmd.PersistentFlags().StringVarP(&serviceAccount, "account", "a",
		"", "Path Service Account private key in JSON")

	RootCmd.AddCommand(apis.Cmd)
	RootCmd.AddCommand(org.Cmd)
	RootCmd.AddCommand(sync.Cmd)
	RootCmd.AddCommand(env.Cmd)
	RootCmd.AddCommand(products.Cmd)
	RootCmd.AddCommand(developers.Cmd)
	RootCmd.AddCommand(apps.Cmd)
	RootCmd.AddCommand(sharedflows.Cmd)
	RootCmd.AddCommand(kvm.Cmd)
	RootCmd.AddCommand(flowhooks.Cmd)
	RootCmd.AddCommand(targetservers.Cmd)
	RootCmd.AddCommand(token.Cmd)
	RootCmd.AddCommand(keystores.Cmd)
	RootCmd.AddCommand(keyaliases.Cmd)
	RootCmd.AddCommand(cache.Cmd)
	RootCmd.AddCommand(references.Cmd)
	RootCmd.AddCommand(res.Cmd)
	RootCmd.AddCommand(projects.Cmd)
	RootCmd.AddCommand(iam.Cmd)
	RootCmd.AddCommand(envoy.Cmd)
}

func initConfig() {
	var skipLogInfo = true
	var skipCache bool

	if os.Getenv("APIGEECLI_SKIPLOG") == "false" {
		skipLogInfo = false
	}

	skipCache, _ = strconv.ParseBool(os.Getenv("APIGEECLI_SKIPCACHE"))

	apiclient.NewApigeeClient(apiclient.ApigeeClientOptions{
		SkipCheck:   true,
		PrintOutput: true,
		SkipLogInfo: skipLogInfo,
		SkipCache:   skipCache,
	})
}

// GetRootCmd returns the root of the cobra command-tree.
func GetRootCmd() *cobra.Command {
	return RootCmd
}
<|endoftext|>


<commit_before>package cmd

import (
	"github.com/bpicode/fritzctl/flags"
	"github.com/spf13/cobra"
)

// RootCmd represents the base command when called without any sub-commands.
var RootCmd = &cobra.Command{
	Use: "fritzctl [subcommand]",
}

func init() {
	cobra.OnInitialize()
	RootCmd.PersistentFlags().Var(&flags.Loglevel{}, "loglevel", "logging verbosity")
}
<commit_msg>Issue #37: add long/short description to root command<commit_after>package cmd

import (
	"github.com/bpicode/fritzctl/flags"
	"github.com/spf13/cobra"
)

// RootCmd represents the base command when called without any sub-commands.
var RootCmd = &cobra.Command{
	Use: "fritzctl [subcommand]",
	Short: "A lightweight, easy to use console client for the AVM FRITZ!Box Home Automation",
	Long: `fritzctl is a command line client for the AVM FRITZ!Box primarily focused on the AVM Home Automation HTTP Interface. See also https://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/AHA-HTTP-Interface.pdf.`,
}

func init() {
	cobra.OnInitialize()
	RootCmd.PersistentFlags().Var(&flags.Loglevel{}, "loglevel", "logging verbosity")
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gogs 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 cmd

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/Unknwon/com"
	"github.com/urfave/cli"
	log "gopkg.in/clog.v1"

	"github.com/gogits/gogs/models"
	"github.com/gogits/gogs/models/errors"
	"github.com/gogits/gogs/pkg/setting"
	http "github.com/gogits/gogs/routers/repo"
	"syscall"
)

const (
	_ACCESS_DENIED_MESSAGE = "Repository does not exist or you do not have access"
)

var Serv = cli.Command{
	Name:        "serv",
	Usage:       "This command should only be called by SSH shell",
	Description: `Serv provide access auth for repositories`,
	Action:      runServ,
	Flags: []cli.Flag{
		stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"),
	},
}

func fail(userMessage, logMessage string, args ...interface{}) {
	fmt.Fprintln(os.Stderr, "Gin:", userMessage)

	if len(logMessage) > 0 {
		if !setting.ProdMode {
			fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
		}
		log.Fatal(3, logMessage, args...)
	}

	os.Exit(1)
}

func setup(c *cli.Context, logPath string, connectDB bool) {
	if c.IsSet("config") {
		setting.CustomConf = c.String("config")
	} else if c.GlobalIsSet("config") {
		setting.CustomConf = c.GlobalString("config")
	}

	setting.NewContext()

	level := log.TRACE
	if setting.ProdMode {
		level = log.ERROR
	}
	log.New(log.FILE, log.FileConfig{
		Level:    level,
		Filename: filepath.Join(setting.LogRootPath, logPath),
		FileRotationConfig: log.FileRotationConfig{
			Rotate:  true,
			Daily:   true,
			MaxDays: 3,
		},
	})
	log.Delete(log.CONSOLE) // Remove primary logger

	if !connectDB {
		return
	}

	models.LoadConfigs()

	if setting.UseSQLite3 {
		workDir, _ := setting.WorkDir()
		os.Chdir(workDir)
	}

	if err := models.SetEngine(); err != nil {
		fail("Internal error", "SetEngine: %v", err)
	}
}

func isAnnexShell(cmd string) bool {
	return cmd == "git-annex-shell"
}

func parseSSHCmd(cmd string) (string, string, []string) {
	ss := strings.Split(cmd, " ")
	if len(ss) < 2 {
		return "", "", nil
	}
	if isAnnexShell(ss[0]) {
		return ss[0], strings.Replace(ss[2], "/", "'", 1), ss
	} else {
		return ss[0], strings.Replace(ss[1], "/", "'", 1), ss
	}
}

func checkDeployKey(key *models.PublicKey, repo *models.Repository) {
	// Check if this deploy key belongs to current repository.
	if !models.HasDeployKey(key.ID, repo.ID) {
		fail("Key access denied", "Deploy key access denied: [key_id: %d, repo_id: %d]", key.ID, repo.ID)
	}

	// Update deploy key activity.
	deployKey, err := models.GetDeployKeyByRepo(key.ID, repo.ID)
	if err != nil {
		fail("Internal error", "GetDeployKey: %v", err)
	}

	deployKey.Updated = time.Now()
	if err = models.UpdateDeployKey(deployKey); err != nil {
		fail("Internal error", "UpdateDeployKey: %v", err)
	}
}

var (
	allowedCommands = map[string]models.AccessMode{
		"git-upload-pack":    models.ACCESS_MODE_READ,
		"git-upload-archive": models.ACCESS_MODE_READ,
		"git-receive-pack":   models.ACCESS_MODE_WRITE,
		"git-annex-shell":    models.ACCESS_MODE_WRITE,
	}
)

func runServ(c *cli.Context) error {
	setup(c, "serv.log", true)

	if setting.SSH.Disabled {
		println("Gins: SSH has been disabled")
		return nil
	}

	if len(c.Args()) < 1 {
		fail("Not enough arguments", "Not enough arguments")
	}

	sshCmd := strings.Replace(os.Getenv("SSH_ORIGINAL_COMMAND"), "'", "", -1)
	log.Info("SSH commadn:%s", sshCmd)
	if len(sshCmd) == 0 {
		println("Hi there, You've successfully authenticated, but Gin does not provide shell access.")
		return nil
	}

	verb, path, args := parseSSHCmd(sshCmd)
	repoFullName := strings.ToLower(strings.Trim(path, "'"))
	repoFields := strings.SplitN(repoFullName, "/", 2)
	if len(repoFields) != 2 {
		fail("Invalid repository path", "Invalid repository path: %v", path)
	}
	ownerName := strings.ToLower(repoFields[0])
	repoName := strings.TrimSuffix(strings.ToLower(repoFields[1]), ".git")
	repoName = strings.TrimSuffix(repoName, ".wiki")

	owner, err := models.GetUserByName(ownerName)
	if err != nil {
		if errors.IsUserNotExist(err) {
			fail("Repository owner does not exist", "Unregistered owner: %s", ownerName)
		}
		fail("Internal error", "Fail to get repository owner '%s': %v", ownerName, err)
	}

	repo, err := models.GetRepositoryByName(owner.ID, repoName)
	if err != nil {
		if errors.IsRepoNotExist(err) {
			fail(_ACCESS_DENIED_MESSAGE, "Repository does not exist: %s/%s", owner.Name, repoName)
		}
		fail("Internal error", "Fail to get repository: %v", err)
	}
	repo.Owner = owner

	requestMode, ok := allowedCommands[verb]
	if !ok {
		fail("Unknown git command", "Unknown git command '%s'", verb)
	}

	// Prohibit push to mirror repositories.
	if requestMode > models.ACCESS_MODE_READ && repo.IsMirror {
		fail("Mirror repository is read-only", "")
	}

	// Allow anonymous (user is nil) clone for public repositories.
	var user *models.User

	key, err := models.GetPublicKeyByID(com.StrTo(strings.TrimPrefix(c.Args()[0], "key-")).MustInt64())
	if err != nil {
		fail("Invalid key ID", "Invalid key ID '%s': %v", c.Args()[0], err)
	}

	if requestMode == models.ACCESS_MODE_WRITE || repo.IsPrivate {
		// Check deploy key or user key.
		if key.IsDeployKey() {
			if key.Mode < requestMode {
				fail("Key permission denied", "Cannot push with deployment key: %d", key.ID)
			}
			checkDeployKey(key, repo)
		} else {
			user, err = models.GetUserByKeyID(key.ID)
			if err != nil {
				fail("Internal error", "Fail to get user by key ID '%d': %v", key.ID, err)
			}

			mode, err := models.AccessLevel(user.ID, repo)
			if err != nil {
				fail("Internal error", "Fail to check access: %v", err)
			}

			if mode < requestMode {
				clientMessage := _ACCESS_DENIED_MESSAGE
				if mode >= models.ACCESS_MODE_READ {
					clientMessage = "You do not have sufficient authorization for this action"
				}
				fail(clientMessage,
					"User '%s' does not have level '%v' access to repository '%s'",
					user.Name, requestMode, repoFullName)
			}
		}
	} else {
		setting.NewService()
		// Check if the key can access to the repository in case of it is a deploy key (a deploy keys != user key).
		// A deploy key doesn't represent a signed in user, so in a site with Service.RequireSignInView activated
		// we should give read access only in repositories where this deploy key is in use. In other case, a server
		// or system using an active deploy key can get read access to all the repositories in a Gogs service.
		if key.IsDeployKey() && setting.Service.RequireSignInView {
			checkDeployKey(key, repo)
		}
	}

	// Update user key activity.
	if key.ID > 0 {
		key, err := models.GetPublicKeyByID(key.ID)
		if err != nil {
			fail("Internal error", "GetPublicKeyByID: %v", err)
		}

		key.Updated = time.Now()
		if err = models.UpdatePublicKey(key); err != nil {
			fail("Internal error", "UpdatePublicKey: %v", err)
		}
	}

	// Special handle for Windows.
	// Todo will break with annex
	if setting.IsWindows {
		verb = strings.Replace(verb, "-", " ", 1)
	}
	verbs := strings.Split(verb, " ")
	var cmd []string
	if len(verbs) == 2 {
		cmd = []string{verbs[0], verbs[1], repoFullName}
	} else if isAnnexShell(verb) {
		repoAbsPath := setting.RepoRootPath + "/" + repoFullName
		if err := secureGitAnnex(repoAbsPath, requestMode); err != nil {
			fail("Git annex failed", "Git annex failed: %s", err)
		}
		cmd = args
		// Setting full path to repo as git-annex-shell requires it
		cmd[2] = repoAbsPath
	} else {
		cmd = []string{verb, repoFullName}
	}
	runGit(cmd, requestMode, user, owner, repo)
	return nil

}

func runGit(cmd [] string, requestMode models.AccessMode, user *models.User, owner *models.User,
	repo *models.Repository) error {
	log.Info("will exectute:%s", cmd)
	gitCmd := exec.Command(cmd[0], cmd[1:]...)
	if requestMode == models.ACCESS_MODE_WRITE {
		gitCmd.Env = append(os.Environ(), http.ComposeHookEnvs(http.ComposeHookEnvsOptions{
			AuthUser:  user,
			OwnerName: owner.Name,
			OwnerSalt: owner.Salt,
			RepoID:    repo.ID,
			RepoName:  repo.Name,
			RepoPath:  repo.RepoPath(),
		})...)
	}
	gitCmd.Dir = setting.RepoRootPath
	gitCmd.Stdout = os.Stdout
	gitCmd.Stdin = os.Stdin
	gitCmd.Stderr = os.Stderr
	log.Info("args:%s", gitCmd.Args)
	err := gitCmd.Run()
	log.Info("err:%s", err)
	if t, ok := err.(*exec.ExitError); ok {
		log.Info("t:%s", t)
		os.Exit(t.Sys().(syscall.WaitStatus).ExitStatus())
	}

	return nil
}

// Make sure git-annex-shell does not make "bad" changes (refectored from repo)
func secureGitAnnex(path string, requestMode models.AccessMode) error {
	// "If set, disallows running git-shell to handle unknown commands."
	err := os.Setenv("GIT_ANNEX_SHELL_LIMITED", "True")
	if err != nil {
		return fmt.Errorf("ERROR: Could set annex shell to be limited.")
	}
	// "If set, git-annex-shell will refuse to run commands
	//  that do not operate on the specified directory."
	err = os.Setenv("GIT_ANNEX_SHELL_DIRECTORY", path)
	if err != nil {
		return fmt.Errorf("ERROR: Could set annex shell directory.")
	}
	if ! (requestMode > models.ACCESS_MODE_READ) {
		err = os.Setenv("GIT_ANNEX_SHELL_READONLY", "True")
		if err != nil {
			return fmt.Errorf("ERROR: Could set annex shell to read only.")
		}
	}
	return nil
}
<commit_msg>[annex] allow git-annex read only<commit_after>// Copyright 2014 The Gogs 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 cmd

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/Unknwon/com"
	"github.com/urfave/cli"
	log "gopkg.in/clog.v1"

	"github.com/gogits/gogs/models"
	"github.com/gogits/gogs/models/errors"
	"github.com/gogits/gogs/pkg/setting"
	http "github.com/gogits/gogs/routers/repo"
	"syscall"
)

const (
	_ACCESS_DENIED_MESSAGE = "Repository does not exist or you do not have access"
)

var Serv = cli.Command{
	Name:        "serv",
	Usage:       "This command should only be called by SSH shell",
	Description: `Serv provide access auth for repositories`,
	Action:      runServ,
	Flags: []cli.Flag{
		stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"),
	},
}

func fail(userMessage, logMessage string, args ...interface{}) {
	fmt.Fprintln(os.Stderr, "Gin:", userMessage)

	if len(logMessage) > 0 {
		if !setting.ProdMode {
			fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
		}
		log.Fatal(3, logMessage, args...)
	}

	os.Exit(1)
}

func setup(c *cli.Context, logPath string, connectDB bool) {
	if c.IsSet("config") {
		setting.CustomConf = c.String("config")
	} else if c.GlobalIsSet("config") {
		setting.CustomConf = c.GlobalString("config")
	}

	setting.NewContext()

	level := log.TRACE
	if setting.ProdMode {
		level = log.ERROR
	}
	log.New(log.FILE, log.FileConfig{
		Level:    level,
		Filename: filepath.Join(setting.LogRootPath, logPath),
		FileRotationConfig: log.FileRotationConfig{
			Rotate:  true,
			Daily:   true,
			MaxDays: 3,
		},
	})
	log.Delete(log.CONSOLE) // Remove primary logger

	if !connectDB {
		return
	}

	models.LoadConfigs()

	if setting.UseSQLite3 {
		workDir, _ := setting.WorkDir()
		os.Chdir(workDir)
	}

	if err := models.SetEngine(); err != nil {
		fail("Internal error", "SetEngine: %v", err)
	}
}

func isAnnexShell(cmd string) bool {
	return cmd == "git-annex-shell"
}

func parseSSHCmd(cmd string) (string, string, []string) {
	ss := strings.Split(cmd, " ")
	if len(ss) < 2 {
		return "", "", nil
	}
	if isAnnexShell(ss[0]) {
		return ss[0], strings.Replace(ss[2], "/", "'", 1), ss
	} else {
		return ss[0], strings.Replace(ss[1], "/", "'", 1), ss
	}
}

func checkDeployKey(key *models.PublicKey, repo *models.Repository) {
	// Check if this deploy key belongs to current repository.
	if !models.HasDeployKey(key.ID, repo.ID) {
		fail("Key access denied", "Deploy key access denied: [key_id: %d, repo_id: %d]", key.ID, repo.ID)
	}

	// Update deploy key activity.
	deployKey, err := models.GetDeployKeyByRepo(key.ID, repo.ID)
	if err != nil {
		fail("Internal error", "GetDeployKey: %v", err)
	}

	deployKey.Updated = time.Now()
	if err = models.UpdateDeployKey(deployKey); err != nil {
		fail("Internal error", "UpdateDeployKey: %v", err)
	}
}

var (
	allowedCommands = map[string]models.AccessMode{
		"git-upload-pack":    models.ACCESS_MODE_READ,
		"git-upload-archive": models.ACCESS_MODE_READ,
		"git-receive-pack":   models.ACCESS_MODE_WRITE,
		"git-annex-shell":    models.ACCESS_MODE_READ,
	}
)

func runServ(c *cli.Context) error {
	setup(c, "serv.log", true)

	if setting.SSH.Disabled {
		println("Gins: SSH has been disabled")
		return nil
	}

	if len(c.Args()) < 1 {
		fail("Not enough arguments", "Not enough arguments")
	}

	sshCmd := strings.Replace(os.Getenv("SSH_ORIGINAL_COMMAND"), "'", "", -1)
	log.Info("SSH commadn:%s", sshCmd)
	if len(sshCmd) == 0 {
		println("Hi there, You've successfully authenticated, but Gin does not provide shell access.")
		return nil
	}

	verb, path, args := parseSSHCmd(sshCmd)
	repoFullName := strings.ToLower(strings.Trim(path, "'"))
	repoFields := strings.SplitN(repoFullName, "/", 2)
	if len(repoFields) != 2 {
		fail("Invalid repository path", "Invalid repository path: %v", path)
	}
	ownerName := strings.ToLower(repoFields[0])
	repoName := strings.TrimSuffix(strings.ToLower(repoFields[1]), ".git")
	repoName = strings.TrimSuffix(repoName, ".wiki")

	owner, err := models.GetUserByName(ownerName)
	if err != nil {
		if errors.IsUserNotExist(err) {
			fail("Repository owner does not exist", "Unregistered owner: %s", ownerName)
		}
		fail("Internal error", "Fail to get repository owner '%s': %v", ownerName, err)
	}

	repo, err := models.GetRepositoryByName(owner.ID, repoName)
	if err != nil {
		if errors.IsRepoNotExist(err) {
			fail(_ACCESS_DENIED_MESSAGE, "Repository does not exist: %s/%s", owner.Name, repoName)
		}
		fail("Internal error", "Fail to get repository: %v", err)
	}
	repo.Owner = owner

	requestMode, ok := allowedCommands[verb]
	if !ok {
		fail("Unknown git command", "Unknown git command '%s'", verb)
	}

	// Prohibit push to mirror repositories.
	if requestMode > models.ACCESS_MODE_READ && repo.IsMirror {
		fail("Mirror repository is read-only", "")
	}

	// Allow anonymous (user is nil) clone for public repositories.
	var user *models.User

	key, err := models.GetPublicKeyByID(com.StrTo(strings.TrimPrefix(c.Args()[0], "key-")).MustInt64())
	if err != nil {
		fail("Invalid key ID", "Invalid key ID '%s': %v", c.Args()[0], err)
	}

	if requestMode == models.ACCESS_MODE_WRITE || repo.IsPrivate {
		// Check deploy key or user key.
		if key.IsDeployKey() {
			if key.Mode < requestMode {
				fail("Key permission denied", "Cannot push with deployment key: %d", key.ID)
			}
			checkDeployKey(key, repo)
		} else {
			user, err = models.GetUserByKeyID(key.ID)
			if err != nil {
				fail("Internal error", "Fail to get user by key ID '%d': %v", key.ID, err)
			}

			mode, err := models.AccessLevel(user.ID, repo)
			if err != nil {
				fail("Internal error", "Fail to check access: %v", err)
			}

			if mode < requestMode {
				clientMessage := _ACCESS_DENIED_MESSAGE
				if mode >= models.ACCESS_MODE_READ {
					clientMessage = "You do not have sufficient authorization for this action"
				}
				fail(clientMessage,
					"User '%s' does not have level '%v' access to repository '%s'",
					user.Name, requestMode, repoFullName)
			}
		}
	} else {
		setting.NewService()
		// Check if the key can access to the repository in case of it is a deploy key (a deploy keys != user key).
		// A deploy key doesn't represent a signed in user, so in a site with Service.RequireSignInView activated
		// we should give read access only in repositories where this deploy key is in use. In other case, a server
		// or system using an active deploy key can get read access to all the repositories in a Gogs service.
		if key.IsDeployKey() && setting.Service.RequireSignInView {
			checkDeployKey(key, repo)
		}
	}

	// Update user key activity.
	if key.ID > 0 {
		key, err := models.GetPublicKeyByID(key.ID)
		if err != nil {
			fail("Internal error", "GetPublicKeyByID: %v", err)
		}

		key.Updated = time.Now()
		if err = models.UpdatePublicKey(key); err != nil {
			fail("Internal error", "UpdatePublicKey: %v", err)
		}
	}

	// Special handle for Windows.
	// Todo will break with annex
	if setting.IsWindows {
		verb = strings.Replace(verb, "-", " ", 1)
	}
	verbs := strings.Split(verb, " ")
	var cmd []string
	if len(verbs) == 2 {
		cmd = []string{verbs[0], verbs[1], repoFullName}
	} else if isAnnexShell(verb) {
		repoAbsPath := setting.RepoRootPath + "/" + repoFullName
		if err := secureGitAnnex(repoAbsPath, requestMode); err != nil {
			fail("Git annex failed", "Git annex failed: %s", err)
		}
		cmd = args
		// Setting full path to repo as git-annex-shell requires it
		cmd[2] = repoAbsPath
	} else {
		cmd = []string{verb, repoFullName}
	}
	runGit(cmd, requestMode, user, owner, repo)
	return nil

}

func runGit(cmd [] string, requestMode models.AccessMode, user *models.User, owner *models.User,
	repo *models.Repository) error {
	log.Info("will exectute:%s", cmd)
	gitCmd := exec.Command(cmd[0], cmd[1:]...)
	if requestMode == models.ACCESS_MODE_WRITE {
		gitCmd.Env = append(os.Environ(), http.ComposeHookEnvs(http.ComposeHookEnvsOptions{
			AuthUser:  user,
			OwnerName: owner.Name,
			OwnerSalt: owner.Salt,
			RepoID:    repo.ID,
			RepoName:  repo.Name,
			RepoPath:  repo.RepoPath(),
		})...)
	}
	gitCmd.Dir = setting.RepoRootPath
	gitCmd.Stdout = os.Stdout
	gitCmd.Stdin = os.Stdin
	gitCmd.Stderr = os.Stderr
	log.Info("args:%s", gitCmd.Args)
	err := gitCmd.Run()
	log.Info("err:%s", err)
	if t, ok := err.(*exec.ExitError); ok {
		log.Info("t:%s", t)
		os.Exit(t.Sys().(syscall.WaitStatus).ExitStatus())
	}

	return nil
}

// Make sure git-annex-shell does not make "bad" changes (refectored from repo)
func secureGitAnnex(path string, requestMode models.AccessMode) error {
	// "If set, disallows running git-shell to handle unknown commands."
	err := os.Setenv("GIT_ANNEX_SHELL_LIMITED", "True")
	if err != nil {
		return fmt.Errorf("ERROR: Could set annex shell to be limited.")
	}
	// "If set, git-annex-shell will refuse to run commands
	//  that do not operate on the specified directory."
	err = os.Setenv("GIT_ANNEX_SHELL_DIRECTORY", path)
	if err != nil {
		return fmt.Errorf("ERROR: Could set annex shell directory.")
	}
	if ! (requestMode > models.ACCESS_MODE_READ) {
		err = os.Setenv("GIT_ANNEX_SHELL_READONLY", "True")
		if err != nil {
			return fmt.Errorf("ERROR: Could set annex shell to read only.")
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"encoding/json"
	"os"
	"path"

	"github.com/containerum/chkit/pkg/chkitErrors"

	kubeClientModels "git.containerum.net/ch/kube-client/pkg/model"
	"github.com/BurntSushi/toml"
	"github.com/containerum/chkit/pkg/client"
	"github.com/containerum/chkit/pkg/model"
	"github.com/sirupsen/logrus"
	"gopkg.in/urfave/cli.v2"
)

func getLog(ctx *cli.Context) *logrus.Logger {
	return ctx.App.Metadata["log"].(*logrus.Logger)
}
func getConfig(ctx *cli.Context) model.Config {
	return ctx.App.Metadata["config"].(model.Config)
}

func setConfig(ctx *cli.Context, config model.Config) {
	ctx.App.Metadata["config"] = config
}

func saveConfig(ctx *cli.Context) error {
	err := writeConfig(ctx)
	if err != nil {
		return chkitErrors.ErrUnableToSaveConfig().
			AddDetailsErr(err)
	}
	return nil
}

func getClient(ctx *cli.Context) chClient.Client {
	return ctx.App.Metadata["client"].(chClient.Client)
}

func setClient(ctx *cli.Context, client chClient.Client) {
	ctx.App.Metadata["client"] = client
}

func getConfigPath(ctx *cli.Context) string {
	return ctx.App.Metadata["configPath"].(string)
}
func exitOnErr(log *logrus.Logger, err error) {
	if err != nil {
		log.WithError(err).Fatal(err)
		os.Exit(1)
	}
}

func loadConfig(configFilePath string, config *model.Config) error {
	_, err := toml.DecodeFile(configFilePath, &config.UserInfo)
	if err != nil {
		return err
	}
	return nil
}

func writeConfig(ctx *cli.Context) error {
	configPath := getConfigPath(ctx)
	err := os.MkdirAll(configPath, os.ModePerm)
	if err != nil && !os.IsExist(err) {
		return err
	}
	file, err := os.Create(path.Join(configPath, "config.toml"))
	if err != nil {
		return err
	}
	config := getConfig(ctx)
	return toml.NewEncoder(file).Encode(config.UserInfo)
}

func getTokens(ctx *cli.Context) kubeClientModels.Tokens {
	return ctx.App.Metadata["tokens"].(kubeClientModels.Tokens)
}

func setTokens(ctx *cli.Context, tokens kubeClientModels.Tokens) {
	ctx.App.Metadata["tokens"] = tokens
}
func saveTokens(ctx *cli.Context, tokens kubeClientModels.Tokens) error {
	file, err := os.Create(path.Join(getConfigPath(ctx), "tokens"))
	if err != nil {
		return err
	}
	return json.NewEncoder(file).Encode(tokens)
}

func loadTokens(ctx *cli.Context) (kubeClientModels.Tokens, error) {
	tokens := kubeClientModels.Tokens{}
	file, err := os.Open(path.Join(getConfigPath(ctx), "tokens"))
	if err != nil {
		return tokens, err
	}
	return tokens, json.NewDecoder(file).Decode(&tokens)
}
<commit_msg>rm cherry errors<commit_after>package cmd

import (
	"encoding/json"
	"os"
	"path"

	"github.com/containerum/chkit/pkg/chkitErrors"

	kubeClientModels "git.containerum.net/ch/kube-client/pkg/model"
	"github.com/BurntSushi/toml"
	"github.com/containerum/chkit/pkg/client"
	"github.com/containerum/chkit/pkg/model"
	"github.com/sirupsen/logrus"
	"gopkg.in/urfave/cli.v2"
)

const (
	ErrUnableToSaveConfig chkitErrors.Err = "unable to save config"
)

func getLog(ctx *cli.Context) *logrus.Logger {
	return ctx.App.Metadata["log"].(*logrus.Logger)
}
func getConfig(ctx *cli.Context) model.Config {
	return ctx.App.Metadata["config"].(model.Config)
}

func setConfig(ctx *cli.Context, config model.Config) {
	ctx.App.Metadata["config"] = config
}

func saveConfig(ctx *cli.Context) error {
	err := writeConfig(ctx)
	if err != nil {
		return ErrUnableToSaveConfig.Wrap(err)
	}
	return nil
}

func getClient(ctx *cli.Context) chClient.Client {
	return ctx.App.Metadata["client"].(chClient.Client)
}

func setClient(ctx *cli.Context, client chClient.Client) {
	ctx.App.Metadata["client"] = client
}

func getConfigPath(ctx *cli.Context) string {
	return ctx.App.Metadata["configPath"].(string)
}
func exitOnErr(log *logrus.Logger, err error) {
	if err != nil {
		log.WithError(err).Fatal(err)
		os.Exit(1)
	}
}

func loadConfig(configFilePath string, config *model.Config) error {
	_, err := toml.DecodeFile(configFilePath, &config.UserInfo)
	if err != nil {
		return err
	}
	return nil
}

func writeConfig(ctx *cli.Context) error {
	configPath := getConfigPath(ctx)
	err := os.MkdirAll(configPath, os.ModePerm)
	if err != nil && !os.IsExist(err) {
		return err
	}
	file, err := os.Create(path.Join(configPath, "config.toml"))
	if err != nil {
		return err
	}
	config := getConfig(ctx)
	return toml.NewEncoder(file).Encode(config.UserInfo)
}

func getTokens(ctx *cli.Context) kubeClientModels.Tokens {
	return ctx.App.Metadata["tokens"].(kubeClientModels.Tokens)
}

func setTokens(ctx *cli.Context, tokens kubeClientModels.Tokens) {
	ctx.App.Metadata["tokens"] = tokens
}
func saveTokens(ctx *cli.Context, tokens kubeClientModels.Tokens) error {
	file, err := os.Create(path.Join(getConfigPath(ctx), "tokens"))
	if err != nil {
		return err
	}
	return json.NewEncoder(file).Encode(tokens)
}

func loadTokens(ctx *cli.Context) (kubeClientModels.Tokens, error) {
	tokens := kubeClientModels.Tokens{}
	file, err := os.Open(path.Join(getConfigPath(ctx), "tokens"))
	if err != nil {
		return tokens, err
	}
	return tokens, json.NewDecoder(file).Decode(&tokens)
}
<|endoftext|>