<commit_before>// Package brb (Basic Big.Rat) make using golang's big.Rats less of a pain in
// the butt.
// It provides a natural language interface to big.Rats instead of having to
// deal with assembly like mnemonics.
package brb

import (
	"bufio"
	"errors"
	"fmt"
	"math/big"
	"strings"
	"sync"
)

var (
	// ErrVariableNotFound is returned if the requested variable does not
	// exist.
	ErrVariableNotFound = errors.New("variable not found")

	// ErrNoResult is returned if the script has not return value but was.
	// successful.
	// Variables may or may not have been set.
	ErrNoResult = errors.New("no result")
)

// Interpreter is the context that is required to run expressions.
type Interpreter struct {
	lexer *yylexer
	mtx   sync.Mutex
}

// New returns an Interpreter context.
func New() *Interpreter {
	i := Interpreter{}
	return &i
}

// Run executes script and returns a *big.Rat if there is a result.
// If there is no result Run returns ErrNoResult.
// The following example returns ErrNoResult:
//	br, err := new(Interpreter).Run("a=12.5")
func (i *Interpreter) Run(script string, args ...interface{}) (*big.Rat, error) {
	r := bufio.NewReader(strings.NewReader(script))

	// make sure args are *big.Rat
	for k, v := range args {
		switch v.(type) {
		case *big.Rat:
		default:
			return nil, fmt.Errorf("invalid arg %v type %T", k+1, v)
		}
	}

	// for now don't allow reentrant calls
	i.mtx.Lock()
	defer i.mtx.Unlock()

	i.lexer = newLexer(r, args...)
	result := yyParse(i.lexer)
	if result == 0 {
		if i.lexer.result != nil {
			v := *i.lexer.result
			return &v, nil
		}
		return nil, ErrNoResult
	}
	return nil, i.lexer.lastError
}

// GetVar returns a variable if it exists.
// If the requested variable does not exist it returns ErrVariableNotFound.
// The following example returns a *big.Rat that is set to 12/1
//	i := New()
//	_, err := i.Run("a=12.0")
//	myvar, err := i.GetVar("a")
func (i *Interpreter) GetVar(name string) (*big.Rat, error) {
	i.mtx.Lock()
	defer i.mtx.Unlock()

	val := i.lexer.getVar(name)
	if val == nil {
		return nil, ErrVariableNotFound
	}
	v := *val
	return &v, nil
}

// GetResult returns the result if it exists.
func (i *Interpreter) GetResult(name string) (*big.Rat, error) {
	i.mtx.Lock()
	defer i.mtx.Unlock()

	val := i.lexer.result
	if val == nil {
		return nil, ErrNoResult
	}
	v := *val
	return &v, nil
}
<commit_msg>one . too many<commit_after>// Package brb (Basic Big.Rat) make using golang's big.Rats less of a pain in
// the butt.
// It provides a natural language interface to big.Rats instead of having to
// deal with assembly like mnemonics.
package brb

import (
	"bufio"
	"errors"
	"fmt"
	"math/big"
	"strings"
	"sync"
)

var (
	// ErrVariableNotFound is returned if the requested variable does not
	// exist.
	ErrVariableNotFound = errors.New("variable not found")

	// ErrNoResult is returned if the script has not return value but was
	// successful.
	// Variables may or may not have been set.
	ErrNoResult = errors.New("no result")
)

// Interpreter is the context that is required to run expressions.
type Interpreter struct {
	lexer *yylexer
	mtx   sync.Mutex
}

// New returns an Interpreter context.
func New() *Interpreter {
	i := Interpreter{}
	return &i
}

// Run executes script and returns a *big.Rat if there is a result.
// If there is no result Run returns ErrNoResult.
// The following example returns ErrNoResult:
//	br, err := new(Interpreter).Run("a=12.5")
func (i *Interpreter) Run(script string, args ...interface{}) (*big.Rat, error) {
	r := bufio.NewReader(strings.NewReader(script))

	// make sure args are *big.Rat
	for k, v := range args {
		switch v.(type) {
		case *big.Rat:
		default:
			return nil, fmt.Errorf("invalid arg %v type %T", k+1, v)
		}
	}

	// for now don't allow reentrant calls
	i.mtx.Lock()
	defer i.mtx.Unlock()

	i.lexer = newLexer(r, args...)
	result := yyParse(i.lexer)
	if result == 0 {
		if i.lexer.result != nil {
			v := *i.lexer.result
			return &v, nil
		}
		return nil, ErrNoResult
	}
	return nil, i.lexer.lastError
}

// GetVar returns a variable if it exists.
// If the requested variable does not exist it returns ErrVariableNotFound.
// The following example returns a *big.Rat that is set to 12/1
//	i := New()
//	_, err := i.Run("a=12.0")
//	myvar, err := i.GetVar("a")
func (i *Interpreter) GetVar(name string) (*big.Rat, error) {
	i.mtx.Lock()
	defer i.mtx.Unlock()

	val := i.lexer.getVar(name)
	if val == nil {
		return nil, ErrVariableNotFound
	}
	v := *val
	return &v, nil
}

// GetResult returns the result if it exists.
func (i *Interpreter) GetResult(name string) (*big.Rat, error) {
	i.mtx.Lock()
	defer i.mtx.Unlock()

	val := i.lexer.result
	if val == nil {
		return nil, ErrNoResult
	}
	v := *val
	return &v, nil
}
<|endoftext|>


<commit_before>package riakpb

import (
	"sync"
)

var bufPool *sync.Pool

func init() {
	bufPool = new(sync.Pool)
	bufPool.New = func() interface{} {
		return new(buf)
	}
}

type buf struct {
	Body []byte
}

// proto message w/ Size and MarshalTo
type protom interface {
	MarshalTo([]byte) (n int, err error)
	Size() int
}

func (b *buf) Set(p protom) error {
	sz := p.Size()
	var err error
	if cap(b.Body) >= sz {
		b.Body = b.Body[0:sz]
		_, err = p.MarshalTo(b.Body)
	} else {
		b.Body = make([]byte, sz)
		_, err = p.MarshalTo(b.Body)
	}
	return err
}

func getBuf() *buf {
	b, ok := bufPool.Get().(*buf)
	if !ok {
		return new(buf)
	}
	return b
}

func putBuf(b *buf) { bufPool.Put(b) }
<commit_msg>so we're 1 alloc better<commit_after>package riakpb

import (
	"sync"
)

var bufPool *sync.Pool

func init() {
	bufPool = new(sync.Pool)
	bufPool.New = func() interface{} {
		return new(buf)
	}
}

type buf struct {
	Body []byte
}

// proto message w/ Size and MarshalTo
type protom interface {
	MarshalTo([]byte) (n int, err error)
	Size() int
}

func (b *buf) Set(p protom) error {
	sz := p.Size()
	var err error
	if cap(b.Body) >= sz {
		b.Body = b.Body[0:sz]
		_, err = p.MarshalTo(b.Body)
	} else {
		b.Body = make([]byte, sz)
		_, err = p.MarshalTo(b.Body)
	}
	return err
}

func getBuf() *buf {
	return bufPool.Get().(*buf)
}

func putBuf(b *buf) { bufPool.Put(b) }
<|endoftext|>


<commit_before>package bus

import (
	"fmt"
	"reflect"
	"sync"
)

type Bus struct {
	subscriber map[string][]*subscriber
	lock       sync.Mutex
	wg         sync.WaitGroup
}

type subscriber struct {
	cb          reflect.Value
	once        bool
	async       bool
	transaction bool
	sync.Mutex
}

func New() *Bus {
	return &Bus{
		make(map[string][]*subscriber),
		sync.Mutex{},
		sync.WaitGroup{},
	}
}

func (b *Bus) prepare(n string, fn interface{}, once, async, transaction bool) (h *subscriber, err error) {
	if reflect.TypeOf(fn).Kind() != reflect.Func {
		return nil, fmt.Errorf("%T is not a function", fn)
	}
	if b.subscriber[n] == nil {
		b.subscriber[n] = make([]*subscriber, 0)
	}
	v := reflect.ValueOf(fn)
	return &subscriber{v, once, async, transaction, sync.Mutex{}}, nil
}

// Has check if a topic is present and has active subscribers.
func (b *Bus) Has(n string) bool {
	return b.subscriber[n] != nil && len(b.subscriber[n]) > 0
}

// Subscribe adds a callback to the subscribers.
func (b *Bus) Subscribe(n string, fn interface{}) (err error) {
	b.lock.Lock()
	defer b.lock.Unlock()

	var s *subscriber
	s, err = b.prepare(n, fn, false, false, false)
	if err == nil {
		b.subscriber[n] = append(b.subscriber[n], s)
	}
	return
}

// SubscribeAsync adds a callback to the subscribers. Transaction determines if the subsequent calls for a topic are done in concurrently (true) or serial (false).
func (b *Bus) SubscribeAsync(n string, fn interface{}, transaction bool) (err error) {
	b.lock.Lock()
	defer b.lock.Unlock()

	var s *subscriber
	s, err = b.prepare(n, fn, false, true, transaction)
	if err == nil {
		b.subscriber[n] = append(b.subscriber[n], s)
	}
	return
}

// OnceAsync removes the event after the callback has been fired synchronously.
func (b *Bus) Once(n string, fn interface{}) (err error) {
	b.lock.Lock()
	defer b.lock.Unlock()

	var s *subscriber
	s, err = b.prepare(n, fn, true, false, false)
	if err == nil {
		b.subscriber[n] = append(b.subscriber[n], s)
	}
	return
}

// OnceAsync removes the event after the callback has been fired asynchronously.
func (b *Bus) OnceAsync(n string, fn interface{}) (err error) {
	b.lock.Lock()
	defer b.lock.Unlock()

	var s *subscriber
	s, err = b.prepare(n, fn, true, true, false)
	if err == nil {
		b.subscriber[n] = append(b.subscriber[n], s)
	}
	return
}

// Unsubscribe removes a topic from the bus
func (b *Bus) Unsubscribe(n string) error {
	b.lock.Lock()
	defer b.lock.Unlock()
	if _, ok := b.subscriber[n]; ok {
		delete(b.subscriber, n)
		return nil
	}
	return fmt.Errorf("Topic %q does not exist", n)
}

func (b *Bus) Publish(n string, a ...interface{}) {
	b.lock.Lock()
	if h, ok := b.subscriber[n]; ok {
		for _, s := range h {
			if s.async {
				b.wg.Add(1)
				go b.publishAsync(s, n, a...)
			} else {
				b.publish(s, n, a...)
			}
		}
	} else {
		b.lock.Unlock()
	}
}

func (b *Bus) publish(h *subscriber, n string, a ...interface{}) {
	args := b.setup(h.once, n, a...)
	h.cb.Call(args)
}

func (b *Bus) publishAsync(h *subscriber, n string, a ...interface{}) {
	defer b.wg.Done()
	if h.transaction {
		h.Lock()
		defer h.Unlock()
	}
	b.publish(h, n, a...)
}

func (b *Bus) setup(r bool, n string, a ...interface{}) []reflect.Value {
	defer b.lock.Unlock()
	args := make([]reflect.Value, 0)
	for _, arg := range a {
		args = append(args, reflect.ValueOf(arg))
	}
	if r {
		delete(b.subscriber, n)
	}
	return args
}

// Wait waits for all the async callbacks to finish
func (b *Bus) Wait() {
	b.wg.Wait()
}
<commit_msg>Added shared bus<commit_after>package bus

import (
	"fmt"
	"log"
	"reflect"
	"runtime"
	"sync"
)

var shared = New()

type Bus struct {
	Debug      bool
	subscriber map[string][]*subscriber
	lock       sync.Mutex
	wg         sync.WaitGroup
}

type subscriber struct {
	cb          reflect.Value
	once        bool
	async       bool
	transaction bool
	sync.Mutex
}

func New() *Bus {
	return &Bus{
		false,
		make(map[string][]*subscriber),
		sync.Mutex{},
		sync.WaitGroup{},
	}
}

func (b *Bus) prepare(n string, fn interface{}, once, async, transaction bool) (h *subscriber, err error) {
	if reflect.TypeOf(fn).Kind() != reflect.Func {
		return nil, fmt.Errorf("%T is not a function", fn)
	}
	if b.subscriber[n] == nil {
		b.subscriber[n] = make([]*subscriber, 0)
	}
	v := reflect.ValueOf(fn)
	return &subscriber{v, once, async, transaction, sync.Mutex{}}, nil
}

// Has check if a topic is present and has active subscribers.
func (b *Bus) Has(n string) bool {
	return b.subscriber[n] != nil && len(b.subscriber[n]) > 0
}

// Subscribe adds a callback to the subscribers.
func (b *Bus) Subscribe(n string, fn interface{}) (err error) {
	b.lock.Lock()
	defer b.lock.Unlock()

	var s *subscriber
	s, err = b.prepare(n, fn, false, false, false)
	if err == nil {
		b.subscriber[n] = append(b.subscriber[n], s)
		if b.Debug {
			log.Printf("bus [%p]: subsribed to %q\n", b, n)
		}
	}
	return
}

// SubscribeAsync adds a callback to the subscribers. Transaction determines if the subsequent calls for a topic are done in concurrently (true) or serial (false).
func (b *Bus) SubscribeAsync(n string, fn interface{}, transaction bool) (err error) {
	b.lock.Lock()
	defer b.lock.Unlock()

	var s *subscriber
	s, err = b.prepare(n, fn, false, true, transaction)
	if err == nil {
		b.subscriber[n] = append(b.subscriber[n], s)
	}
	return
}

// Once removes the event after the callback has been fired synchronously.
func (b *Bus) Once(n string, fn interface{}) (err error) {
	b.lock.Lock()
	defer b.lock.Unlock()

	var s *subscriber
	s, err = b.prepare(n, fn, true, false, false)
	if err == nil {
		b.subscriber[n] = append(b.subscriber[n], s)
	}
	return
}

// OnceAsync removes the event after the callback has been fired asynchronously.
func (b *Bus) OnceAsync(n string, fn interface{}) (err error) {
	b.lock.Lock()
	defer b.lock.Unlock()

	var s *subscriber
	s, err = b.prepare(n, fn, true, true, false)
	if err == nil {
		b.subscriber[n] = append(b.subscriber[n], s)
	}
	return
}

// Unsubscribe removes a topic from the bus
func (b *Bus) Unsubscribe(n string, fn interface{}) error {
	if reflect.TypeOf(fn).Kind() != reflect.Func {
		return fmt.Errorf("%T is not a function", fn)
	}
	b.lock.Lock()
	defer b.lock.Unlock()
	if h, ok := b.subscriber[n]; ok {
		for i, s := range h {
			if s == fn {
				b.subscriber[n] = append(b.subscriber[n][i:], b.subscriber[n][i+1:]...)
				return nil
			}
		}
		return nil
	}
	return fmt.Errorf("Topic %q does not exist", n)
}

func (b *Bus) Publish(n string, a ...interface{}) {
	b.lock.Lock()
	if b.Debug && len(b.subscriber[n]) > 0 {
		log.Printf("bus [%p]: publish %q to %d subscribers\n", b, n, len(b.subscriber[n]))
	}
	if h, ok := b.subscriber[n]; ok {
		for _, s := range h {
			if s.async {
				b.wg.Add(1)
				go b.publishAsync(s, n, a...)
			} else {
				b.publish(s, n, a...)
			}
		}
	}
	b.lock.Unlock()
}

func (b *Bus) publish(h *subscriber, n string, a ...interface{}) {
	args := b.setup(h.once, n, a...)
	defer func() {
		if err := recover(); err != nil {
			trace := make([]byte, 1024)
			runtime.Stack(trace, false)
			log.Printf("bus: recover in %T: %v", h.cb.Type().Name(), err)
			log.Println(string(trace))
			//fmt.Println(errors.Wrap(err, 2).ErrorStack())
		}
	}()
	h.cb.Call(args)
}

func (b *Bus) publishAsync(h *subscriber, n string, a ...interface{}) {
	defer b.wg.Done()
	if h.transaction {
		h.Lock()
		defer h.Unlock()
	}
	b.publish(h, n, a...)
}

func (b *Bus) setup(r bool, n string, a ...interface{}) []reflect.Value {
	args := make([]reflect.Value, 0)
	for _, arg := range a {
		args = append(args, reflect.ValueOf(arg))
	}
	if r {
		delete(b.subscriber, n)
	}
	return args
}

// Wait waits for all the async callbacks to finish
func (b *Bus) Wait() {
	b.wg.Wait()
}

// Global functions for the shared bus

func Debug(debug bool) {
	shared.Debug = debug
}

func Publish(n string, a ...interface{}) {
	shared.Publish(n, a...)
}

// Subscribe adds a callback to the subscribers.
func Subscribe(n string, fn interface{}) error {
	return shared.Subscribe(n, fn)
}

// SubscribeAsync adds a callback to the subscribers. Transaction determines if the subsequent calls for a topic are done in concurrently (true) or serial (false).
func SubscribeAsync(n string, fn interface{}, transaction bool) (err error) {
	return shared.SubscribeAsync(n, fn, transaction)
}

// Once removes the event after the callback has been fired synchronously.
func Once(n string, fn interface{}) (err error) {
	return shared.Once(n, fn)
}

// OnceAsync removes the event after the callback has been fired asynchronously.
func OnceAsync(n string, fn interface{}) (err error) {
	return shared.OnceAsync(n, fn)
}

// Unsubscribe removes a topic from the bus
func Unsubscribe(n string, fn interface{}) error {
	return shared.Unsubscribe(n, fn)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"regexp"
	"strconv"

	"github.com/jbreitbart/coBench/bit"
)

func generateCatConfigs(minBits uint64, numBits uint64) [][]uint64 {
	pairs := make([][]uint64, 0)

	if *cat {
		for bits := minBits; bits <= numBits-minBits; bits += *catBitChunk {
			pairs = append(pairs, []uint64{bit.SetFirstN(0, bits), bit.SetLastN(0, bits, numBits)})
		}
	}

	// Added as a last entry, so that after programm execution cat is disabled
	pairs = append(pairs, []uint64{bit.SetFirstN(0, numBits), bit.SetFirstN(0, numBits)})

	return pairs
}

func createDirsCAT() error {
	for _, dir := range catDirs {
		err := os.Mkdir(dir, 0777)
		if os.IsExist(err) {
			continue
		}
		if err != nil {
			return fmt.Errorf("CAT: %v", err)
		}
	}

	return nil
}

func removeDirsCAT() error {
	for _, dir := range catDirs {
		err := os.Remove(dir)
		if err != nil {
			return fmt.Errorf("Cannot remove dir %v: %v", dir, err)
		}
	}

	return nil
}

func resetCAT() error {
	return removeDirsCAT()
}

func readCATInfo() (minBits uint64, numBits uint64, err error) {
	// TODO read from resctrlPath
	minBits = 2
	numBits = 20
	err = nil
	return
}

func setupCAT() (minBits uint64, numBits uint64, err error) {

	if minBits, numBits, err = readCATInfo(); err != nil {
		return
	}

	if err = createDirsCAT(); err != nil {
		return
	}

	numbers := regexp.MustCompile("[0-9]+")

	for i, cpu := range cpus {
		cpuIDs := numbers.FindAllString(cpu, -1)
		if len(cpuIDs)%2 != 0 {
			err = fmt.Errorf("Unsupported CPU list: %v", cpu)
			return
		}

		var bitset uint64

		// loop over every pair
		for i := 0; i < len(cpuIDs); i += 2 {
			var start, end uint64
			start, err = strconv.ParseUint(cpuIDs[i], 10, 64)
			if err != nil {
				err = fmt.Errorf("Parse number: %v", start)
				return
			}
			end, err = strconv.ParseUint(cpuIDs[i+1], 10, 64)
			if err != nil {
				err = fmt.Errorf("Parse number: %v", end)
				return
			}
			if end < start {
				start, end = end, start
			}
			for c := start; c <= end; c++ {
				// TODO validate by max cpu size
				bitset = bit.Set(bitset, c)
			}
		}

		var file *os.File

		file, err = os.OpenFile(catDirs[i]+"/cpus", os.O_WRONLY|os.O_TRUNC, 0777)
		if err != nil {
			err = fmt.Errorf("CAT could not open cpus file: %v", err)
			return
		}
		defer file.Close()

		_, err = file.WriteString(fmt.Sprintf("%x", bitset))
		if err != nil {
			err = fmt.Errorf("CAT could write to cpus file: %v", err)
			return
		}
	}

	return
}

func writeCATConfig(configs []uint64) error {

	if len(catDirs) != len(configs) {
		return fmt.Errorf("Internal error")
	}

	for i, dir := range catDirs {
		file, err := os.OpenFile(dir+"/schemata", os.O_WRONLY|os.O_TRUNC, 0777)
		if err != nil {
			return fmt.Errorf("CAT could not open cpus file: %v", err)
		}
		defer file.Close()

		// TODO hardcoded string
		_, err = file.WriteString(fmt.Sprintf("L3:0=%x;1=%x\n", configs[i], configs[i]))
		if err != nil {
			return fmt.Errorf("CAT could not write to schemata file: %v", err)
		}
	}
	return nil
}
<commit_msg>Read min/num CAT bits from resctrl.<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"regexp"
	"strconv"
	"strings"

	"github.com/jbreitbart/coBench/bit"
)

func generateCatConfigs(minBits uint64, numBits uint64) [][]uint64 {
	pairs := make([][]uint64, 0)

	if *cat {
		for bits := minBits; bits <= numBits-minBits; bits += *catBitChunk {
			pairs = append(pairs, []uint64{bit.SetFirstN(0, bits), bit.SetLastN(0, bits, numBits)})
		}
	}

	// Added as a last entry, so that after programm execution cat is disabled
	pairs = append(pairs, []uint64{bit.SetFirstN(0, numBits), bit.SetFirstN(0, numBits)})

	return pairs
}

func createDirsCAT() error {
	for _, dir := range catDirs {
		err := os.Mkdir(dir, 0777)
		if os.IsExist(err) {
			continue
		}
		if err != nil {
			return fmt.Errorf("CAT: %v", err)
		}
	}

	return nil
}

func removeDirsCAT() error {
	for _, dir := range catDirs {
		err := os.Remove(dir)
		if err != nil {
			return fmt.Errorf("Cannot remove dir %v: %v", dir, err)
		}
	}

	return nil
}

func resetCAT() error {
	return removeDirsCAT()
}

func readCATInfo() (minBits uint64, numBits uint64, err error) {
	minBitsFilename := *resctrlPath + "/info/L3/min_cbm_bits"
	minBitsByteTxt, err := ioutil.ReadFile(minBitsFilename)
	if err != nil {
		return
	}
	minBitsTxt := strings.TrimSpace(string(minBitsByteTxt))
	minBits, err = strconv.ParseUint(minBitsTxt, 10, 64)
	if err != nil {
		return
	}

	numBitsFilename := *resctrlPath + "/info/L3/cbm_mask"
	numBitsByteTxt, err := ioutil.ReadFile(numBitsFilename)
	if err != nil {
		return
	}
	numBitsTxt := strings.TrimSpace(string(numBitsByteTxt))
	numBitsTemp, err := strconv.ParseUint(numBitsTxt, 16, 64)
	if err != nil {
		return
	}

	numBits = 0
	for i := (uint64)(0); i < 64; i++ {
		if bit.Has(numBitsTemp, i) {
			numBits++
		}
	}

	fmt.Printf("%v - %v\n", minBits, numBits)

	err = nil
	return
}

func setupCAT() (minBits uint64, numBits uint64, err error) {

	if minBits, numBits, err = readCATInfo(); err != nil {
		return
	}

	if err = createDirsCAT(); err != nil {
		return
	}

	numbers := regexp.MustCompile("[0-9]+")

	for i, cpu := range cpus {
		cpuIDs := numbers.FindAllString(cpu, -1)
		if len(cpuIDs)%2 != 0 {
			err = fmt.Errorf("Unsupported CPU list: %v", cpu)
			return
		}

		var bitset uint64

		// loop over every pair
		for i := 0; i < len(cpuIDs); i += 2 {
			var start, end uint64
			start, err = strconv.ParseUint(cpuIDs[i], 10, 64)
			if err != nil {
				err = fmt.Errorf("Parse number: %v", start)
				return
			}
			end, err = strconv.ParseUint(cpuIDs[i+1], 10, 64)
			if err != nil {
				err = fmt.Errorf("Parse number: %v", end)
				return
			}
			if end < start {
				start, end = end, start
			}
			for c := start; c <= end; c++ {
				// TODO validate by max cpu size
				bitset = bit.Set(bitset, c)
			}
		}

		var file *os.File

		file, err = os.OpenFile(catDirs[i]+"/cpus", os.O_WRONLY|os.O_TRUNC, 0777)
		if err != nil {
			err = fmt.Errorf("CAT could not open cpus file: %v", err)
			return
		}
		defer file.Close()

		_, err = file.WriteString(fmt.Sprintf("%x", bitset))
		if err != nil {
			err = fmt.Errorf("CAT could write to cpus file: %v", err)
			return
		}
	}

	return
}

func writeCATConfig(configs []uint64) error {

	if len(catDirs) != len(configs) {
		return fmt.Errorf("Internal error")
	}

	for i, dir := range catDirs {
		file, err := os.OpenFile(dir+"/schemata", os.O_WRONLY|os.O_TRUNC, 0777)
		if err != nil {
			return fmt.Errorf("CAT could not open cpus file: %v", err)
		}
		defer file.Close()

		// TODO hardcoded string
		_, err = file.WriteString(fmt.Sprintf("L3:0=%x;1=%x\n", configs[i], configs[i]))
		if err != nil {
			return fmt.Errorf("CAT could not write to schemata file: %v", err)
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package ghch

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"strings"
	"text/template"
	"time"

	"github.com/jessevdk/go-flags"
	"github.com/octokit/go-octokit/octokit"
)

type ghOpts struct {
	RepoPath    string `short:"r" long:"repo" default:"." description:"git repository path"`
	GitPath     string `short:"g" long:"git" default:"git" description:"git path"`
	From        string `short:"f" long:"from" description:"git commit revision range start from"`
	To          string `short:"t" long:"to" description:"git commit revision range end to"`
	Token       string `          long:"token" description:"github token"`
	Verbose     bool   `short:"v" long:"verbose"`
	Remote      string `          long:"remote" default:"origin" description:"default remote name"`
	Format      string `short:"F" long:"format" default:"json" description:"json or markdown"`
	All         bool   `short:"A" long:"all" description:"output all changes"`
	NextVersion string `short:"N" long:"next-version"`
	// Tmpl string
}

const (
	exitCodeOK = iota
	exitCodeParseFlagError
	exitCodeErr
)

type CLI struct {
	OutStream, ErrStream io.Writer
}

func (cli *CLI) Run(argv []string) int {
	log.SetOutput(cli.ErrStream)
	p, opts, err := parseArgs(argv)
	if err != nil {
		if ferr, ok := err.(*flags.Error); !ok || ferr.Type != flags.ErrHelp {
			p.WriteHelp(cli.ErrStream)
		}
		return exitCodeParseFlagError
	}

	gh := (&ghch{
		remote:   opts.Remote,
		repoPath: opts.RepoPath,
		gitPath:  opts.GitPath,
		verbose:  opts.Verbose,
		token:    opts.Token,
	}).initialize()

	if opts.All {
		chlog := changelog{}
		vers := append(gh.versions(), "")
		prevRev := ""
		for _, rev := range vers {
			r := gh.getSection(rev, prevRev)
			if prevRev == "" && opts.NextVersion != "" {
				r.ToRevision = opts.NextVersion
			}
			chlog.Sections = append(chlog.Sections, r)
			prevRev = rev
		}

		if opts.Format == "markdown" {
			results := make([]string, len(chlog.Sections))
			for i, v := range chlog.Sections {
				results[i], _ = v.toMkdn()
			}
			fmt.Fprintln(cli.OutStream, strings.Join(results, "\n\n"))
		} else {
			jsn, _ := json.MarshalIndent(chlog, "", "  ")
			fmt.Fprintln(cli.OutStream, string(jsn))
		}
	} else {
		if opts.From == "" && opts.To == "" {
			opts.From = gh.getLatestSemverTag()
		}
		r := gh.getSection(opts.From, opts.To)
		if r.ToRevision == "" && opts.NextVersion != "" {
			r.ToRevision = opts.NextVersion
		}
		if opts.Format == "markdown" {
			str, err := r.toMkdn()
			if err != nil {
				log.Print(err)
			} else {
				fmt.Fprintln(cli.OutStream, str)
			}
		} else {
			jsn, _ := json.MarshalIndent(r, "", "  ")
			fmt.Fprintln(cli.OutStream, string(jsn))
		}
	}
	return exitCodeOK
}

func parseArgs(args []string) (*flags.Parser, *ghOpts, error) {
	opts := &ghOpts{}
	p := flags.NewParser(opts, flags.Default)
	p.Usage = "[OPTIONS]\n\nVersion: " + version
	_, err := p.ParseArgs(args)
	return p, opts, err
}

func (gh *ghch) getSection(from, to string) section {
	r := gh.mergedPRs(from, to)
	t, err := gh.getChangedAt(to)
	if err != nil {
		log.Print(err)
	}
	owner, repo := gh.ownerAndRepo()
	return section{
		PullRequests: r,
		FromRevision: from,
		ToRevision:   to,
		ChangedAt:    t,
		Owner:        owner,
		Repo:         repo,
	}
}

type changelog struct {
	Sections []section `json:"sections"`
}

type section struct {
	PullRequests []*octokit.PullRequest `json:"pull_requests"`
	FromRevision string                 `json:"from_revision"`
	ToRevision   string                 `json:"to_revision"`
	ChangedAt    time.Time              `json:"changed_at"`
	Owner        string                 `json:"owner"`
	Repo         string                 `json:"repo"`
}

var tmplStr = `{{$ret := . -}}
## [{{.ToRevision}}](https://github.com/{{.Owner}}/{{.Repo}}/releases/tag/{{.ToRevision}}) ({{.ChangedAt.Format "2006-01-02"}})
{{range .PullRequests}}
* {{.Title}} [#{{.Number}}](https://github.com/{{$ret.Owner}}/{{$ret.Repo}}/pull/{{.Number}}) ([{{.User.Login}}](https://github.com/{{.User.Login}}))
{{- end}}`

var mdTmpl *template.Template

func init() {
	var err error
	mdTmpl, err = template.New("md-changelog").Parse(tmplStr)
	if err != nil {
		log.Fatal(err)
	}
}

func (rs section) toMkdn() (string, error) {
	var b bytes.Buffer
	err := mdTmpl.Execute(&b, rs)
	if err != nil {
		return "", err
	}
	return b.String(), nil
}
<commit_msg>add comment<commit_after>package ghch

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"strings"
	"text/template"
	"time"

	"github.com/jessevdk/go-flags"
	"github.com/octokit/go-octokit/octokit"
)

type ghOpts struct {
	RepoPath    string `short:"r" long:"repo" default:"." description:"git repository path"`
	GitPath     string `short:"g" long:"git" default:"git" description:"git path"`
	From        string `short:"f" long:"from" description:"git commit revision range start from"`
	To          string `short:"t" long:"to" description:"git commit revision range end to"`
	Token       string `          long:"token" description:"github token"`
	Verbose     bool   `short:"v" long:"verbose"`
	Remote      string `          long:"remote" default:"origin" description:"default remote name"`
	Format      string `short:"F" long:"format" default:"json" description:"json or markdown"`
	All         bool   `short:"A" long:"all" description:"output all changes"`
	NextVersion string `short:"N" long:"next-version"`
	// Tmpl string
}

const (
	exitCodeOK = iota
	exitCodeParseFlagError
	exitCodeErr
)

// CLI is struct for command line tool
type CLI struct {
	OutStream, ErrStream io.Writer
}

// Run the ghch
func (cli *CLI) Run(argv []string) int {
	log.SetOutput(cli.ErrStream)
	p, opts, err := parseArgs(argv)
	if err != nil {
		if ferr, ok := err.(*flags.Error); !ok || ferr.Type != flags.ErrHelp {
			p.WriteHelp(cli.ErrStream)
		}
		return exitCodeParseFlagError
	}

	gh := (&ghch{
		remote:   opts.Remote,
		repoPath: opts.RepoPath,
		gitPath:  opts.GitPath,
		verbose:  opts.Verbose,
		token:    opts.Token,
	}).initialize()

	if opts.All {
		chlog := changelog{}
		vers := append(gh.versions(), "")
		prevRev := ""
		for _, rev := range vers {
			r := gh.getSection(rev, prevRev)
			if prevRev == "" && opts.NextVersion != "" {
				r.ToRevision = opts.NextVersion
			}
			chlog.Sections = append(chlog.Sections, r)
			prevRev = rev
		}

		if opts.Format == "markdown" {
			results := make([]string, len(chlog.Sections))
			for i, v := range chlog.Sections {
				results[i], _ = v.toMkdn()
			}
			fmt.Fprintln(cli.OutStream, strings.Join(results, "\n\n"))
		} else {
			jsn, _ := json.MarshalIndent(chlog, "", "  ")
			fmt.Fprintln(cli.OutStream, string(jsn))
		}
	} else {
		if opts.From == "" && opts.To == "" {
			opts.From = gh.getLatestSemverTag()
		}
		r := gh.getSection(opts.From, opts.To)
		if r.ToRevision == "" && opts.NextVersion != "" {
			r.ToRevision = opts.NextVersion
		}
		if opts.Format == "markdown" {
			str, err := r.toMkdn()
			if err != nil {
				log.Print(err)
			} else {
				fmt.Fprintln(cli.OutStream, str)
			}
		} else {
			jsn, _ := json.MarshalIndent(r, "", "  ")
			fmt.Fprintln(cli.OutStream, string(jsn))
		}
	}
	return exitCodeOK
}

func parseArgs(args []string) (*flags.Parser, *ghOpts, error) {
	opts := &ghOpts{}
	p := flags.NewParser(opts, flags.Default)
	p.Usage = "[OPTIONS]\n\nVersion: " + version
	_, err := p.ParseArgs(args)
	return p, opts, err
}

func (gh *ghch) getSection(from, to string) section {
	r := gh.mergedPRs(from, to)
	t, err := gh.getChangedAt(to)
	if err != nil {
		log.Print(err)
	}
	owner, repo := gh.ownerAndRepo()
	return section{
		PullRequests: r,
		FromRevision: from,
		ToRevision:   to,
		ChangedAt:    t,
		Owner:        owner,
		Repo:         repo,
	}
}

type changelog struct {
	Sections []section `json:"sections"`
}

type section struct {
	PullRequests []*octokit.PullRequest `json:"pull_requests"`
	FromRevision string                 `json:"from_revision"`
	ToRevision   string                 `json:"to_revision"`
	ChangedAt    time.Time              `json:"changed_at"`
	Owner        string                 `json:"owner"`
	Repo         string                 `json:"repo"`
}

var tmplStr = `{{$ret := . -}}
## [{{.ToRevision}}](https://github.com/{{.Owner}}/{{.Repo}}/releases/tag/{{.ToRevision}}) ({{.ChangedAt.Format "2006-01-02"}})
{{range .PullRequests}}
* {{.Title}} [#{{.Number}}](https://github.com/{{$ret.Owner}}/{{$ret.Repo}}/pull/{{.Number}}) ([{{.User.Login}}](https://github.com/{{.User.Login}}))
{{- end}}`

var mdTmpl *template.Template

func init() {
	var err error
	mdTmpl, err = template.New("md-changelog").Parse(tmplStr)
	if err != nil {
		log.Fatal(err)
	}
}

func (rs section) toMkdn() (string, error) {
	var b bytes.Buffer
	err := mdTmpl.Execute(&b, rs)
	if err != nil {
		return "", err
	}
	return b.String(), nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"os"

	"github.com/ggiamarchi/pxe-pilot/api"
	"github.com/ggiamarchi/pxe-pilot/common/http"
	"github.com/ggiamarchi/pxe-pilot/logger"
	"github.com/ggiamarchi/pxe-pilot/model"

	cli "github.com/jawher/mow.cli"
	"github.com/olekukonko/tablewriter"
)

func setupCLI() {

	app := cli.App("pxe-pilot", "PXE Pilot")

	serverURL := app.StringOpt("s server", "http://localhost:3478", "Server URL for PXE Pilot client")
	debug := app.BoolOpt("d debug", false, "Show client logs on stdout")

	app.Command("server", "Run PXE Pilot server", func(cmd *cli.Cmd) {

		var configFile = cmd.StringOpt("c config", "/etc/pxe-pilot/pxe-pilot.yml", "PXE Pilot YAML configuration file")

		cmd.Action = func() {
			logger.Init(false)
			api.Run(*configFile)
		}
	})

	app.Command("config", "PXE configuration commands", func(cmd *cli.Cmd) {
		cmd.Command("show", "Show PXE configurations", func(cmd *cli.Cmd) {

			cmd.Spec = "NAME"

			var (
				name = cmd.StringArg("NAME", "", "Configuration to show")
			)

			cmd.Action = func() {
				logger.Init(!*debug)

				var configuration = &model.ConfigurationDetails{}
				statusCode, err := http.Request("GET", *serverURL, fmt.Sprintf("/v1/configurations/%s", *name), nil, configuration)
				if err != nil || statusCode != 200 {
					panic(err)
				}

				fmt.Println(configuration.Content)
				// Print data table
				// table := tablewriter.NewWriter(os.Stdout)
				// table.SetAutoWrapText(false)
				// table.SetHeader([]string{"Name", "Content"})
				// table.Append([]string{configuration.Name, configuration.Content})
				// table.Render()
			}
		})
		cmd.Command("list", "List available PXE configurations", func(cmd *cli.Cmd) {
			cmd.Action = func() {
				logger.Init(!*debug)
				var configurations = &[]*model.Configuration{}
				statusCode, err := http.Request("GET", *serverURL, "/v1/configurations", nil, configurations)
				if err != nil || statusCode != 200 {
					panic(err)
				}

				// Print data table
				table := tablewriter.NewWriter(os.Stdout)
				table.SetHeader([]string{"Name"})
				for _, c := range *configurations {
					table.Append([]string{c.Name})
				}
				table.Render()
			}
		})
		cmd.Command("deploy", "Deploy a configuration for a host", func(cmd *cli.Cmd) {

			cmd.Spec = "CONFIG HOSTNAMES..."

			var (
				config    = cmd.StringArg("CONFIG", "", "Configuration to deploy")
				hostnames = cmd.StringsArg("HOSTNAMES", []string{}, "Hosts for whom to deploy a configuration")
			)

			cmd.Action = func() {

				logger.Init(!*debug)

				hosts := make([]*model.HostQuery, len(*hostnames))

				for i, h := range *hostnames {
					hosts[i] = &model.HostQuery{
						Name: h,
					}
				}

				hostsQuery := &model.HostsQuery{
					Hosts: hosts,
				}

				resp := &struct {
					Message string
				}{}

				statusCode, err := http.Request("PUT", *serverURL, "/v1/configurations/"+*config+"/deploy", hostsQuery, resp)

				if err != nil || statusCode != 200 {
					os.Stdout.WriteString(resp.Message + "\n")
					cli.Exit(1)
				}

				// Print data table
				table := tablewriter.NewWriter(os.Stdout)
				table.SetAutoWrapText(false)
				table.SetHeader([]string{"Name", "Configuration"})

				for _, h := range *hostnames {
					table.Append([]string{h, *config})
				}

				table.Render()
			}
		})
	})

	app.Command("host", "Host commands", func(cmd *cli.Cmd) {
		cmd.Command("list", "List hosts", func(cmd *cli.Cmd) {
			cmd.Action = func() {
				logger.Init(!*debug)
				var hosts = &[]*model.Host{}
				statusCode, err := http.Request("GET", *serverURL, "/v1/hosts", nil, hosts)

				if err != nil {
					os.Stdout.WriteString("Error : " + err.Error())
				}

				if err != nil || statusCode != 200 {
					os.Stdout.WriteString("Error...")
					cli.Exit(1)
				}

				// Print data table
				table := tablewriter.NewWriter(os.Stdout)
				table.SetHeader([]string{"Name", "Configuration", "MAC", "IPMI MAC", "IPMI HOST", "Power State"})
				table.SetAutoWrapText(false)

				for _, h := range *hosts {
					var configuration string
					if h.Configuration != nil {
						configuration = h.Configuration.Name
					}

					var ipmi *model.IPMI
					if h.IPMI != nil {
						ipmi = h.IPMI
					} else {
						ipmi = &model.IPMI{}
					}

					var macAddresses bytes.Buffer

					for i := 0; i < len(h.MACAddresses); i++ {
						if i != 0 {
							macAddresses.WriteString(" | ")
						}
						macAddresses.WriteString(h.MACAddresses[i])
					}

					table.Append([]string{h.Name, configuration, macAddresses.String(), ipmi.MACAddress, ipmi.Hostname, ipmi.Status})
				}
				table.Render()
			}
		})
		cmd.Command("reboot", "(re)boot a host", func(cmd *cli.Cmd) {
			cmd.Spec = "HOSTNAME"

			var (
				hostname = cmd.StringArg("HOSTNAME", "", "Host to reboot or reboot if powered off")
			)

			cmd.Action = func() {

				logger.Init(!*debug)

				statusCode, err := http.Request("PATCH", *serverURL, "/v1/hosts/"+*hostname+"/reboot", nil, nil)

				// Print data table
				table := tablewriter.NewWriter(os.Stdout)
				table.SetAutoWrapText(false)
				table.SetHeader([]string{"Name", "Reboot"})

				if err != nil || statusCode != 204 {
					table.Append([]string{*hostname, "ERROR"})
					table.Render()
					cli.Exit(1)
				} else {
					table.Append([]string{*hostname, "OK"})
					table.Render()
				}
			}
		})
		cmd.Command("refresh", "Refresh hosts information", func(cmd *cli.Cmd) {
			cmd.Action = func() {
				logger.Init(!*debug)
				statusCode, err := http.Request("PATCH", *serverURL, "/v1/refresh", nil, nil)

				// Print data table
				table := tablewriter.NewWriter(os.Stdout)
				table.SetHeader([]string{"Refresh"})
				table.SetAutoWrapText(false)
				if err != nil {
					table.Append([]string{"ERROR : " + err.Error()})
				}
				if err != nil || statusCode != 204 {
					table.Append([]string{"ERROR"})
					cli.Exit(1)
				}
				table.Append([]string{"OK"})
				table.Render()
			}
		})
	})

	err := app.Run(os.Args)
	if err != nil {
		logger.Error("%s", err)
	}
}
<commit_msg>Clean code<commit_after>package main

import (
	"bytes"
	"fmt"
	"os"

	"github.com/ggiamarchi/pxe-pilot/api"
	"github.com/ggiamarchi/pxe-pilot/common/http"
	"github.com/ggiamarchi/pxe-pilot/logger"
	"github.com/ggiamarchi/pxe-pilot/model"

	cli "github.com/jawher/mow.cli"
	"github.com/olekukonko/tablewriter"
)

func setupCLI() {

	app := cli.App("pxe-pilot", "PXE Pilot")

	serverURL := app.StringOpt("s server", "http://localhost:3478", "Server URL for PXE Pilot client")
	debug := app.BoolOpt("d debug", false, "Show client logs on stdout")

	app.Command("server", "Run PXE Pilot server", func(cmd *cli.Cmd) {

		var configFile = cmd.StringOpt("c config", "/etc/pxe-pilot/pxe-pilot.yml", "PXE Pilot YAML configuration file")

		cmd.Action = func() {
			logger.Init(false)
			api.Run(*configFile)
		}
	})

	app.Command("config", "PXE configuration commands", func(cmd *cli.Cmd) {
		cmd.Command("show", "Show PXE configurations", func(cmd *cli.Cmd) {

			cmd.Spec = "NAME"

			var (
				name = cmd.StringArg("NAME", "", "Configuration to show")
			)

			cmd.Action = func() {
				logger.Init(!*debug)

				var configuration = &model.ConfigurationDetails{}
				statusCode, err := http.Request("GET", *serverURL, fmt.Sprintf("/v1/configurations/%s", *name), nil, configuration)
				if err != nil || statusCode != 200 {
					panic(err)
				}

				fmt.Println(configuration.Content)
			}
		})
		cmd.Command("list", "List available PXE configurations", func(cmd *cli.Cmd) {
			cmd.Action = func() {
				logger.Init(!*debug)
				var configurations = &[]*model.Configuration{}
				statusCode, err := http.Request("GET", *serverURL, "/v1/configurations", nil, configurations)
				if err != nil || statusCode != 200 {
					panic(err)
				}

				// Print data table
				table := tablewriter.NewWriter(os.Stdout)
				table.SetHeader([]string{"Name"})
				for _, c := range *configurations {
					table.Append([]string{c.Name})
				}
				table.Render()
			}
		})
		cmd.Command("deploy", "Deploy a configuration for a host", func(cmd *cli.Cmd) {

			cmd.Spec = "CONFIG HOSTNAMES..."

			var (
				config    = cmd.StringArg("CONFIG", "", "Configuration to deploy")
				hostnames = cmd.StringsArg("HOSTNAMES", []string{}, "Hosts for whom to deploy a configuration")
			)

			cmd.Action = func() {

				logger.Init(!*debug)

				hosts := make([]*model.HostQuery, len(*hostnames))

				for i, h := range *hostnames {
					hosts[i] = &model.HostQuery{
						Name: h,
					}
				}

				hostsQuery := &model.HostsQuery{
					Hosts: hosts,
				}

				resp := &struct {
					Message string
				}{}

				statusCode, err := http.Request("PUT", *serverURL, "/v1/configurations/"+*config+"/deploy", hostsQuery, resp)

				if err != nil || statusCode != 200 {
					os.Stdout.WriteString(resp.Message + "\n")
					cli.Exit(1)
				}

				// Print data table
				table := tablewriter.NewWriter(os.Stdout)
				table.SetAutoWrapText(false)
				table.SetHeader([]string{"Name", "Configuration"})

				for _, h := range *hostnames {
					table.Append([]string{h, *config})
				}

				table.Render()
			}
		})
	})

	app.Command("host", "Host commands", func(cmd *cli.Cmd) {
		cmd.Command("list", "List hosts", func(cmd *cli.Cmd) {
			cmd.Action = func() {
				logger.Init(!*debug)
				var hosts = &[]*model.Host{}
				statusCode, err := http.Request("GET", *serverURL, "/v1/hosts", nil, hosts)

				if err != nil {
					os.Stdout.WriteString("Error : " + err.Error())
				}

				if err != nil || statusCode != 200 {
					os.Stdout.WriteString("Error...")
					cli.Exit(1)
				}

				// Print data table
				table := tablewriter.NewWriter(os.Stdout)
				table.SetHeader([]string{"Name", "Configuration", "MAC", "IPMI MAC", "IPMI HOST", "Power State"})
				table.SetAutoWrapText(false)

				for _, h := range *hosts {
					var configuration string
					if h.Configuration != nil {
						configuration = h.Configuration.Name
					}

					var ipmi *model.IPMI
					if h.IPMI != nil {
						ipmi = h.IPMI
					} else {
						ipmi = &model.IPMI{}
					}

					var macAddresses bytes.Buffer

					for i := 0; i < len(h.MACAddresses); i++ {
						if i != 0 {
							macAddresses.WriteString(" | ")
						}
						macAddresses.WriteString(h.MACAddresses[i])
					}

					table.Append([]string{h.Name, configuration, macAddresses.String(), ipmi.MACAddress, ipmi.Hostname, ipmi.Status})
				}
				table.Render()
			}
		})
		cmd.Command("reboot", "(re)boot a host", func(cmd *cli.Cmd) {
			cmd.Spec = "HOSTNAME"

			var (
				hostname = cmd.StringArg("HOSTNAME", "", "Host to reboot or reboot if powered off")
			)

			cmd.Action = func() {

				logger.Init(!*debug)

				statusCode, err := http.Request("PATCH", *serverURL, "/v1/hosts/"+*hostname+"/reboot", nil, nil)

				// Print data table
				table := tablewriter.NewWriter(os.Stdout)
				table.SetAutoWrapText(false)
				table.SetHeader([]string{"Name", "Reboot"})

				if err != nil || statusCode != 204 {
					table.Append([]string{*hostname, "ERROR"})
					table.Render()
					cli.Exit(1)
				} else {
					table.Append([]string{*hostname, "OK"})
					table.Render()
				}
			}
		})
		cmd.Command("refresh", "Refresh hosts information", func(cmd *cli.Cmd) {
			cmd.Action = func() {
				logger.Init(!*debug)
				statusCode, err := http.Request("PATCH", *serverURL, "/v1/refresh", nil, nil)

				// Print data table
				table := tablewriter.NewWriter(os.Stdout)
				table.SetHeader([]string{"Refresh"})
				table.SetAutoWrapText(false)
				if err != nil {
					table.Append([]string{"ERROR : " + err.Error()})
				}
				if err != nil || statusCode != 204 {
					table.Append([]string{"ERROR"})
					cli.Exit(1)
				}
				table.Append([]string{"OK"})
				table.Render()
			}
		})
	})

	err := app.Run(os.Args)
	if err != nil {
		logger.Error("%s", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/Toorop/tmail/api"
	//"github.com/Toorop/tmail/scope"
	"github.com/codegangsta/cli"
	"os"
	"strconv"
)

var cliCommands = []cli.Command{
	{
		// SMTPD
		Name:  "smtpd",
		Usage: "commands to interact with smtpd process",
		Subcommands: []cli.Command{
			// users
			{
				Name:        "addUser",
				Usage:       "Add a smtpd user",
				Description: "tmail smtpd addUser USER CLEAR_PASSWD [RELAY_ALLOWED]",
				Action: func(c *cli.Context) {
					var err error
					if len(c.Args()) < 2 {
						cliDieBadArgs(c)
					}
					relayAllowed := false
					if len(c.Args()) > 2 {
						relayAllowed, err = strconv.ParseBool(c.Args()[2])
						cliHandleErr(err)
					}

					err = api.SmtpdAddUser(c.Args()[0], c.Args()[1], relayAllowed)
					cliHandleErr(err)
					cliDieOk()
				},
			},
			{
				Name:        "delUser",
				Usage:       "Delete a smtpd user",
				Description: "tmail smtpd delUser USER",
				Action: func(c *cli.Context) {
					var err error
					if len(c.Args()) != 1 {
						cliDieBadArgs(c)
					}
					err = api.SmtpdDelUser(c.Args()[0])
					cliHandleErr(err)
					cliDieOk()
				},
			},
			{
				Name:        "listAutorizedUsers",
				Usage:       "Return a list of authorized users (users who can send mail after authentification)",
				Description: "",
				Action: func(c *cli.Context) {
					users, err := api.SmtpdGetAllowedUsers()
					cliHandleErr(err)
					if len(users) == 0 {
						println("There is no smtpd users yet.")
						return
					}
					println("Relay access granted to: ", c.Args().First())
					for _, user := range users {
						println(user.Login)
					}
				},
			},
			{
				Name:        "addRcpthost",
				Usage:       "Add a 'rcpthost' which is a hostname that tmail have to handle mails for",
				Description: "tmail smtpd addRcpthost HOSTNAME",
				Action: func(c *cli.Context) {
					var err error
					if len(c.Args()) != 1 {
						cliDieBadArgs(c)
					}
					err = api.SmtpdAddRcptHost(c.Args()[0])
					cliHandleErr(err)
					cliDieOk()
				},
			},
			{
				Name:        "delRcpthost",
				Usage:       "Delete a rcpthost",
				Description: "tmail smtpd delRcpthost HOSTNAME",
				Action: func(c *cli.Context) {
					var err error
					if len(c.Args()) != 1 {
						cliDieBadArgs(c)
					}
					err = api.SmtpdDelRcptHost(c.Args()[0])
					cliHandleErr(err)
					cliDieOk()
				},
			},
			{
				Name:        "getRcpthosts",
				Usage:       "Returns all the rcpthosts ",
				Description: "tmail smtpd getRcpthost",
				Action: func(c *cli.Context) {
					var err error
					if len(c.Args()) != 0 {
						cliDieBadArgs(c)
					}
					rcptHosts, err := api.SmtpdGetRcptHosts()
					cliHandleErr(err)
					for _, h := range rcptHosts {
						println(h.Hostname)
					}
				},
			},
		},
	}, {
		// QUEUE
		Name:  "queue",
		Usage: "commands to interact with tmail queue",
		Subcommands: []cli.Command{
			// list queue
			{
				Name:        "list",
				Usage:       "List messages in queue",
				Description: "tmail queue list",
				Action: func(c *cli.Context) {
					var status string
					messages, err := api.QueueGetMessages()
					cliHandleErr(err)
					if len(messages) == 0 {
						println("There is no message in queue.")
					} else {
						fmt.Printf("%d messages in queue.\r\n", len(messages))
						for _, m := range messages {
							switch m.Status {
							case 0:
								status = "Delivery in progress"
							case 1:
								status = "Will be discarded"
							case 2:
								status = "Scheduled"
							case 3:
								status = "Will be bounced"
							}

							msg := fmt.Sprintf("%d - From: %s - To: %s - Status: %s - Added: %v ", m.Id, m.MailFrom, m.RcptTo, status, m.AddedAt)
							if m.Status != 0 {
								msg += fmt.Sprintf("- Next delivery process scheduled at: %v", m.NextDeliveryScheduledAt)
							}
							println(msg)
						}
					}
					os.Exit(0)
				},
			},
			{
				Name:        "discard",
				Usage:       "Discard (delete without bouncing) a message in queue",
				Description: "tmail queue discard MESSAGE_ID",
				Action: func(c *cli.Context) {
					if len(c.Args()) != 1 {
						cliDieBadArgs(c)
					}
					id, err := strconv.ParseInt(c.Args()[0], 10, 64)
					cliHandleErr(err)
					cliHandleErr(api.QueueDiscardMsg(id))
					cliDieOk()
				},
			},
			{
				Name:        "bounce",
				Usage:       "Bounce a message in queue",
				Description: "tmail queue bounce MESSAGE_ID",
				Action: func(c *cli.Context) {
					if len(c.Args()) != 1 {
						cliDieBadArgs(c)
					}
					id, err := strconv.ParseInt(c.Args()[0], 10, 64)
					cliHandleErr(err)
					cliHandleErr(api.QueueBounceMsg(id))
					cliDieOk()
				},
			},
		},
	}, {
		// ROUTES
		Name:  "routes",
		Usage: "commands to manage outgoing SMTP routes",
		Subcommands: []cli.Command{
			{
				Name:        "list",
				Usage:       "List routes",
				Description: "tmail routes list",
				Action: func(c *cli.Context) {
					routes, err := api.RoutesGet()
					cliHandleErr(err)
					//scope.Log.Debug(routes)
					if len(routes) == 0 {
						println("There is no routes configurated, all mails are routed following MX records")
					} else {
						for _, route := range routes {
							//scope.Log.Debug(route)

							// ID
							line := fmt.Sprintf("%d", route.Id)

							// Host
							line += " - Destination host: " + route.Host

							// If mail from
							if route.MailFrom.Valid && route.MailFrom.String != "" {
								line += " - if mail from: " + route.MailFrom.String
							}

							// Priority
							line += " - Prority: "
							if route.Priority.Valid && route.Priority.Int64 != 0 {
								line += fmt.Sprintf("%d", route.Priority.Int64)
							} else {
								line += "1"
							}

							// Local IPs
							line += " - Local IPs: "
							if route.LocalIp.Valid && route.LocalIp.String != "" {
								line += route.LocalIp.String
							} else {
								line += "default"
							}

							// Remote Host
							line += " - Remote host: "
							if route.SmtpAuthLogin.Valid && route.SmtpAuthLogin.String != "" {
								line += route.SmtpAuthLogin.String
								if route.SmtpAuthPasswd.Valid && route.SmtpAuthPasswd.String != "" {
									line += ":" + route.SmtpAuthPasswd.String
								}
								line += "@"
							}

							line += route.RemoteHost
							if route.RemotePort.Valid && route.RemotePort.Int64 != 0 {
								line += fmt.Sprintf(":%d", route.RemotePort.Int64)
							} else {
								line += ":25"
							}

							//

							println(line)
						}
					}
					os.Exit(0)
				},
			},
		},
	},
}

// gotError handle error from cli
func cliHandleErr(err error) {
	if err != nil {
		println("Error: ", err.Error())
		os.Exit(1)
	}
}

// cliDieBadArgs die on bad arg
func cliDieBadArgs(c *cli.Context) {
	println("Error: bad args")
	cli.ShowAppHelp(c)
	os.Exit(1)
}

func cliDieOk() {
	//println("Success")
	os.Exit(0)
}
<commit_msg>package cli<commit_after>package main

import (
	"github.com/Toorop/tmail/cli"
	cgCli "github.com/codegangsta/cli"
)

var cliCommands = []cgCli.Command{
	cli.Queue,
	cli.Routes,
	cli.Smtpd,
}
<|endoftext|>


<commit_before>package cli

import (
	"bytes"
	"fmt"
	"os"
	"reflect"
	"strings"

	"github.com/labstack/gommon/color"
)

// Run runs a single command app
func Run(argv interface{}, fn CommandFunc, descs ...string) {
	RunWithArgs(argv, os.Args, fn, descs...)
}

// RunWithArgs runs a single command app with args
func RunWithArgs(argv interface{}, args []string, fn CommandFunc, descs ...string) {
	desc := ""
	if len(descs) > 0 {
		desc = strings.Join(descs, "\n")
	}
	err := (&Command{
		Name:        args[0],
		Desc:        desc,
		Argv:        func() interface{} { return argv },
		CanSubRoute: true,
		Fn:          fn,
	}).Run(args[1:])
	if err != nil {
		fmt.Println(err)
	}
}

// Root registers forest for root and return root
func Root(root *Command, forest ...*CommandTree) *Command {
	root.RegisterTree(forest...)
	return root
}

// Tree creates a CommandTree
func Tree(cmd *Command, forest ...*CommandTree) *CommandTree {
	return &CommandTree{
		command: cmd,
		forest:  forest,
	}
}

// Parse parses args to object argv
func Parse(args []string, argv interface{}) error {
	clr := color.Color{}
	fset := parseArgv(args, argv, clr)
	return fset.err
}

//------------------
// Implements parse
//------------------

func parseArgv(args []string, argv interface{}, clr color.Color) *flagSet {
	var (
		typ     = reflect.TypeOf(argv)
		val     = reflect.ValueOf(argv)
		flagSet = newFlagSet()
	)
	switch typ.Kind() {
	case reflect.Ptr:
		if reflect.Indirect(val).Type().Kind() != reflect.Struct {
			flagSet.err = errNotPointToStruct
			return flagSet
		}
		parseWithTypeValue(args, typ, val, flagSet, clr)
		return flagSet
	default:
		flagSet.err = errNotAPointer
		return flagSet
	}
}

func usage(v interface{}, clr color.Color, style UsageStyle) string {
	var (
		typ     = reflect.TypeOf(v)
		val     = reflect.ValueOf(v)
		flagSet = newFlagSet()
	)
	if typ.Kind() == reflect.Ptr &&
		reflect.Indirect(val).Type().Kind() == reflect.Struct {
		// initialize flagSet
		initFlagSet(typ, val, flagSet, clr, true)
		if flagSet.err != nil {
			return ""
		}
		return flagSlice(flagSet.flags).StringWithStyle(clr, style)
	}
	return ""
}

func initFlagSet(typ reflect.Type, val reflect.Value, flagSet *flagSet, clr color.Color, dontSetValue bool) {
	var (
		typElem  = typ.Elem()
		valElem  = val.Elem()
		numField = valElem.NumField()
	)
	for i := 0; i < numField; i++ {
		var (
			typField     = typElem.Field(i)
			valField     = valElem.Field(i)
			tag, isEmpty = parseTag(typField.Name, typField.Tag)
		)
		if tag == nil {
			continue
		}
		// if `cli` tag is empty and the field is a struct
		if isEmpty && valField.Kind() == reflect.Struct {
			var (
				subObj   = valField.Addr().Interface()
				subType  = reflect.TypeOf(subObj)
				subValue = reflect.ValueOf(subObj)
			)
			initFlagSet(subType, subValue, flagSet, clr, dontSetValue)
			if flagSet.err != nil {
				return
			}
			continue
		}
		fl, err := newFlag(typField, valField, tag, clr, dontSetValue)
		if flagSet.err = err; err != nil {
			return
		}
		// ignored flag
		if fl == nil {
			continue
		}
		flagSet.flags = append(flagSet.flags, fl)

		// encode flag value
		value := ""
		if fl.isAssigned {
			if !valField.CanInterface() {
				flagSet.err = fmt.Errorf("field %s cannot interface", typField.Name)
				return
			}
			intf := valField.Interface()
			if encoder, ok := intf.(Encoder); ok {
				value = encoder.Encode()
			} else {
				value = fmt.Sprintf("%v", intf)
			}
		}

		names := append(fl.tag.shortNames, fl.tag.longNames...)
		for i, name := range names {
			if _, ok := flagSet.flagMap[name]; ok {
				flagSet.err = fmt.Errorf("flag %s repeat", clr.Bold(name))
				return
			}
			flagSet.flagMap[name] = fl
			if dontSetValue {
				continue
			}
			if fl.isAssigned && i == 0 {
				flagSet.values[name] = []string{value}
			}
		}
	}
}

func parseWithTypeValue(args []string, typ reflect.Type, val reflect.Value, flagSet *flagSet, clr color.Color) {
	initFlagSet(typ, val, flagSet, clr, false)
	if flagSet.err != nil {
		return
	}

	size := len(args)
	for i := 0; i < size; i++ {
		arg := args[i]
		if !strings.HasPrefix(arg, dashOne) {
			// append a free argument
			flagSet.args = append(flagSet.args, arg)
			continue
		}

		var (
			next   = ""
			offset = 0
		)
		if i+1 < size {
			if !strings.HasPrefix(args[i+1], dashOne) {
				next = args[i+1]
				offset = 1
			}
		}

		if arg == dashOne {
			flagSet.err = fmt.Errorf("unexpected single dash")
			return
		}

		// terminate the flag parse while occur `--`
		if arg == dashTwo {
			flagSet.args = append(flagSet.args, args[i+1:]...)
			break
		}

		// split arg by "="(key=value)
		strs := []string{arg}
		index := strings.Index(arg, "=")
		if index >= 0 {
			strs = []string{arg[:index], arg[index+1:]}
		}

		arg = strs[0]
		fl, ok := flagSet.flagMap[arg]

		// found in flagMap
		if ok {
			retOffset := parseToFoundFlag(flagSet, fl, strs, arg, next, offset, clr)
			if flagSet.err != nil {
				return
			}
			i += retOffset
			continue
		}

		// not found in flagMap
		// it's an invalid flag if arg has prefix `--`
		if strings.HasPrefix(arg, dashTwo) {
			flagSet.err = fmt.Errorf("undefined flag %s", clr.Bold(arg))
			return
		}

		// try parse `-F<value>`
		if parseSiameseFlag(flagSet, arg[0:2], args[i][2:], clr) {
			continue
		} else if flagSet.err != nil {
			return
		}

		// other cases, find flag char by char
		arg = strings.TrimPrefix(arg, dashOne)
		parseFlagCharByChar(flagSet, arg, clr)
		if flagSet.err != nil {
			return
		}
		continue
	}

	// read delay flags
	for _, fl := range flagSet.flags {
		if fl.isNeedDelaySet && fl.isAssigned {
			err := setWithProperType(fl, fl.field.Type, fl.value, fl.lastValue, clr, false)
			if flagSet.err == nil && err != nil {
				flagSet.err = err
			}
		}
		if fl.tag.isForce && fl.getBool() {
			flagSet.hasForce = true
		}
	}

	// read prompt flags
	if !flagSet.hasForce {
		if flagSet.err != nil {
			return
		}
		flagSet.readPrompt(os.Stdout, clr)
		if flagSet.err != nil {
			return
		}
	} else {
		flagSet.err = nil
	}

	buff := bytes.NewBufferString("")
	for _, fl := range flagSet.flags {
		if !fl.isAssigned && fl.tag.required {
			if buff.Len() > 0 {
				buff.WriteByte('\n')
			}
			fmt.Fprintf(buff, "required argument %s missing", clr.Bold(fl.name()))
		}
	}
	if buff.Len() > 0 && !flagSet.hasForce {
		flagSet.err = fmt.Errorf(buff.String())
	}
}

func parseToFoundFlag(flagSet *flagSet, fl *flag, strs []string, arg, next string, offset int, clr color.Color) int {
	retOffset := 0
	l := len(strs)
	if l == 1 {
		flagSet.err = fl.set(arg, next, clr)
		if !fl.isBoolean() {
			retOffset = offset
		}
	} else if l == 2 {
		flagSet.err = fl.set(arg, strs[1], clr)
	} else {
		flagSet.err = fmt.Errorf("too many(%d) value", l)
	}
	if flagSet.err != nil {
		name := clr.Bold(fl.name())
		flagSet.err = fmt.Errorf("argument %s invalid: %v", name, flagSet.err)
		return retOffset
	}
	flagSet.values[arg] = []string{fmt.Sprintf("%v", fl.value.Interface())}
	return retOffset
}

func parseFlagCharByChar(flagSet *flagSet, arg string, clr color.Color) {
	// NOTE: each fold flag should be boolean
	chars := []byte(arg)
	for _, c := range chars {
		tmp := dashOne + string([]byte{c})
		fl, ok := flagSet.flagMap[tmp]
		if !ok {
			flagSet.err = fmt.Errorf("undefined flag %s", clr.Bold(tmp))
			return
		}

		if !fl.isBoolean() {
			flagSet.err = fmt.Errorf("each fold flag should be boolean, but %s not", clr.Bold(tmp))
			return
		}

		fl.set(tmp, "true", clr)
		flagSet.values[tmp] = []string{"true"}
	}
}

func parseSiameseFlag(flagSet *flagSet, firstHalf, latterHalf string, clr color.Color) bool {
	// NOTE: fl must be not a boolean
	key, val := firstHalf, latterHalf
	if fl, ok := flagSet.flagMap[key]; ok && !fl.isBoolean() {
		if flagSet.err = fl.set(key, val, clr); flagSet.err != nil {
			return false
		}
		return true
	}
	return false
}
<commit_msg>fix parsing bool<commit_after>package cli

import (
	"bytes"
	"fmt"
	"os"
	"reflect"
	"strings"

	"github.com/labstack/gommon/color"
)

// Run runs a single command app
func Run(argv interface{}, fn CommandFunc, descs ...string) {
	RunWithArgs(argv, os.Args, fn, descs...)
}

// RunWithArgs runs a single command app with args
func RunWithArgs(argv interface{}, args []string, fn CommandFunc, descs ...string) {
	desc := ""
	if len(descs) > 0 {
		desc = strings.Join(descs, "\n")
	}
	err := (&Command{
		Name:        args[0],
		Desc:        desc,
		Argv:        func() interface{} { return argv },
		CanSubRoute: true,
		Fn:          fn,
	}).Run(args[1:])
	if err != nil {
		fmt.Println(err)
	}
}

// Root registers forest for root and return root
func Root(root *Command, forest ...*CommandTree) *Command {
	root.RegisterTree(forest...)
	return root
}

// Tree creates a CommandTree
func Tree(cmd *Command, forest ...*CommandTree) *CommandTree {
	return &CommandTree{
		command: cmd,
		forest:  forest,
	}
}

// Parse parses args to object argv
func Parse(args []string, argv interface{}) error {
	clr := color.Color{}
	fset := parseArgv(args, argv, clr)
	return fset.err
}

//------------------
// Implements parse
//------------------

func parseArgv(args []string, argv interface{}, clr color.Color) *flagSet {
	var (
		typ     = reflect.TypeOf(argv)
		val     = reflect.ValueOf(argv)
		flagSet = newFlagSet()
	)
	switch typ.Kind() {
	case reflect.Ptr:
		if reflect.Indirect(val).Type().Kind() != reflect.Struct {
			flagSet.err = errNotPointToStruct
			return flagSet
		}
		parseWithTypeValue(args, typ, val, flagSet, clr)
		return flagSet
	default:
		flagSet.err = errNotAPointer
		return flagSet
	}
}

func usage(v interface{}, clr color.Color, style UsageStyle) string {
	var (
		typ     = reflect.TypeOf(v)
		val     = reflect.ValueOf(v)
		flagSet = newFlagSet()
	)
	if typ.Kind() == reflect.Ptr &&
		reflect.Indirect(val).Type().Kind() == reflect.Struct {
		// initialize flagSet
		initFlagSet(typ, val, flagSet, clr, true)
		if flagSet.err != nil {
			return ""
		}
		return flagSlice(flagSet.flags).StringWithStyle(clr, style)
	}
	return ""
}

func initFlagSet(typ reflect.Type, val reflect.Value, flagSet *flagSet, clr color.Color, dontSetValue bool) {
	var (
		typElem  = typ.Elem()
		valElem  = val.Elem()
		numField = valElem.NumField()
	)
	for i := 0; i < numField; i++ {
		var (
			typField     = typElem.Field(i)
			valField     = valElem.Field(i)
			tag, isEmpty = parseTag(typField.Name, typField.Tag)
		)
		if tag == nil {
			continue
		}
		// if `cli` tag is empty and the field is a struct
		if isEmpty && valField.Kind() == reflect.Struct {
			var (
				subObj   = valField.Addr().Interface()
				subType  = reflect.TypeOf(subObj)
				subValue = reflect.ValueOf(subObj)
			)
			initFlagSet(subType, subValue, flagSet, clr, dontSetValue)
			if flagSet.err != nil {
				return
			}
			continue
		}
		fl, err := newFlag(typField, valField, tag, clr, dontSetValue)
		if flagSet.err = err; err != nil {
			return
		}
		// ignored flag
		if fl == nil {
			continue
		}
		flagSet.flags = append(flagSet.flags, fl)

		// encode flag value
		value := ""
		if fl.isAssigned {
			if !valField.CanInterface() {
				flagSet.err = fmt.Errorf("field %s cannot interface", typField.Name)
				return
			}
			intf := valField.Interface()
			if encoder, ok := intf.(Encoder); ok {
				value = encoder.Encode()
			} else {
				value = fmt.Sprintf("%v", intf)
			}
		}

		names := append(fl.tag.shortNames, fl.tag.longNames...)
		for i, name := range names {
			if _, ok := flagSet.flagMap[name]; ok {
				flagSet.err = fmt.Errorf("flag %s repeat", clr.Bold(name))
				return
			}
			flagSet.flagMap[name] = fl
			if dontSetValue {
				continue
			}
			if fl.isAssigned && i == 0 {
				flagSet.values[name] = []string{value}
			}
		}
	}
}

func parseWithTypeValue(args []string, typ reflect.Type, val reflect.Value, flagSet *flagSet, clr color.Color) {
	initFlagSet(typ, val, flagSet, clr, false)
	if flagSet.err != nil {
		return
	}

	size := len(args)
	for i := 0; i < size; i++ {
		arg := args[i]
		if !strings.HasPrefix(arg, dashOne) {
			// append a free argument
			flagSet.args = append(flagSet.args, arg)
			continue
		}

		var (
			next   = ""
			offset = 0
		)
		if i+1 < size {
			if !strings.HasPrefix(args[i+1], dashOne) {
				next = args[i+1]
				offset = 1
			}
		}

		if arg == dashOne {
			flagSet.err = fmt.Errorf("unexpected single dash")
			return
		}

		// terminate the flag parse while occur `--`
		if arg == dashTwo {
			flagSet.args = append(flagSet.args, args[i+1:]...)
			break
		}

		// split arg by "="(key=value)
		strs := []string{arg}
		index := strings.Index(arg, "=")
		if index >= 0 {
			strs = []string{arg[:index], arg[index+1:]}
		}

		arg = strs[0]
		fl, ok := flagSet.flagMap[arg]

		// found in flagMap
		if ok {
			retOffset := parseToFoundFlag(flagSet, fl, strs, arg, next, offset, clr)
			if flagSet.err != nil {
				return
			}
			i += retOffset
			continue
		}

		// not found in flagMap
		// it's an invalid flag if arg has prefix `--`
		if strings.HasPrefix(arg, dashTwo) {
			flagSet.err = fmt.Errorf("undefined flag %s", clr.Bold(arg))
			return
		}

		// try parse `-F<value>`
		if parseSiameseFlag(flagSet, arg[0:2], args[i][2:], clr) {
			continue
		} else if flagSet.err != nil {
			return
		}

		// other cases, find flag char by char
		arg = strings.TrimPrefix(arg, dashOne)
		parseFlagCharByChar(flagSet, arg, clr)
		if flagSet.err != nil {
			return
		}
		continue
	}

	// read delay flags
	for _, fl := range flagSet.flags {
		if fl.isNeedDelaySet && fl.isAssigned {
			err := setWithProperType(fl, fl.field.Type, fl.value, fl.lastValue, clr, false)
			if flagSet.err == nil && err != nil {
				flagSet.err = err
			}
		}
		if fl.tag.isForce && fl.getBool() {
			flagSet.hasForce = true
		}
	}

	// read prompt flags
	if !flagSet.hasForce {
		if flagSet.err != nil {
			return
		}
		flagSet.readPrompt(os.Stdout, clr)
		if flagSet.err != nil {
			return
		}
	} else {
		flagSet.err = nil
	}

	buff := bytes.NewBufferString("")
	for _, fl := range flagSet.flags {
		if !fl.isAssigned && fl.tag.required {
			if buff.Len() > 0 {
				buff.WriteByte('\n')
			}
			fmt.Fprintf(buff, "required argument %s missing", clr.Bold(fl.name()))
		}
	}
	if buff.Len() > 0 && !flagSet.hasForce {
		flagSet.err = fmt.Errorf(buff.String())
	}
}

func parseToFoundFlag(flagSet *flagSet, fl *flag, strs []string, arg, next string, offset int, clr color.Color) int {
	retOffset := 0
	l := len(strs)
	if l == 1 {
		if fl.isBoolean() {
			flagSet.err = fl.set(arg, "true", clr)
		} else {
			flagSet.err = fl.set(arg, next, clr)
			retOffset = offset
		}
	} else if l == 2 {
		flagSet.err = fl.set(arg, strs[1], clr)
	} else {
		flagSet.err = fmt.Errorf("too many(%d) value", l)
	}
	if flagSet.err != nil {
		name := clr.Bold(fl.name())
		flagSet.err = fmt.Errorf("argument %s invalid: %v", name, flagSet.err)
		return retOffset
	}
	flagSet.values[arg] = []string{fmt.Sprintf("%v", fl.value.Interface())}
	return retOffset
}

func parseFlagCharByChar(flagSet *flagSet, arg string, clr color.Color) {
	// NOTE: each fold flag should be boolean
	chars := []byte(arg)
	for _, c := range chars {
		tmp := dashOne + string([]byte{c})
		fl, ok := flagSet.flagMap[tmp]
		if !ok {
			flagSet.err = fmt.Errorf("undefined flag %s", clr.Bold(tmp))
			return
		}

		if !fl.isBoolean() {
			flagSet.err = fmt.Errorf("each fold flag should be boolean, but %s not", clr.Bold(tmp))
			return
		}

		fl.set(tmp, "true", clr)
		flagSet.values[tmp] = []string{"true"}
	}
}

func parseSiameseFlag(flagSet *flagSet, firstHalf, latterHalf string, clr color.Color) bool {
	// NOTE: fl must be not a boolean
	key, val := firstHalf, latterHalf
	if fl, ok := flagSet.flagMap[key]; ok && !fl.isBoolean() {
		if flagSet.err = fl.set(key, val, clr); flagSet.err != nil {
			return false
		}
		return true
	}
	return false
}
<|endoftext|>


<commit_before>package fuelcell

import (
	"bytes"
	"context"
	"io"
	"os"

	flag "github.com/spf13/pflag"
)

// FParseErrWhitelist configures Flag parse errors to be ignored
type FParseErrWhitelist flag.ParseErrorsWhitelist

// ControlUsageFn is the function signature for the usage closure.
type ControlUsageFn func(*Cmd) error

// ControlFlagErrorFn is a function signature to allow user to control when
// the parsing of a flag returns an error
type ControlFlagErrorFn func(*Cmd, error) error

// ControlHelpFn is a function signature to allow users to control help
type ControlHelpFn func(*Cmd, []string)

// Cmd represents a command on the command line. This command is heavily
// influenced by Cobra cli. The goal of this project is to implement what
// cobra did but with a few difference and of course remove unneeded legacy
// baggage.
type Cmd struct {
	// Use is the one-line usage message.
	// Recommended syntax is as follows:
	//   [ ] identifies an optional argument. Arguments that are not enclosed in brackets are required.
	//   ... indicates that you can specify multiple values for the previous argument.
	//   |   indicates mutually exclusive information. You can use the argument to the left of the separator or the
	//       argument to the right of the separator. You cannot use both arguments in a single use of the command.
	//   { } delimits a set of mutually exclusive arguments when one of the arguments is required. If the arguments are
	//       optional, they are enclosed in brackets ([ ]).
	// Example: add [-F file | -D dir]... [-f format] profile
	Use string

	// Aliases is an array of aliases that can be used instead of the first word in Use.
	Aliases []string

	// SuggestFor is an array of command names for which this command will be suggested -
	// similar to aliases but only suggests.
	SuggestFor []string

	// Short is the short description shown in the 'help' output.
	Short string

	// Long is the long message shown in the 'help <this-command>' output.
	Long string

	// Example is examples of how to use the command.
	Example string

	// ValidArgs is list of all valid non-flag arguments that are accepted in shell completions
	ValidArgs []string

	// ValidArgsFunction is an optional function that provides valid non-flag arguments for shell completion.
	// It is a dynamic version of using ValidArgs.
	// Only one of ValidArgs and ValidArgsFunction can be used for a command.
	ValidArgsFunction func(cmd *Cmd, args []string, toComplete string) ([]string, ShellCompDirective)

	// Expected arguments
	Args PositionalArgs

	// ArgAliases is List of aliases for ValidArgs.
	// These are not suggested to the user in the shell completion,
	// but accepted if entered manually.
	ArgAliases []string

	// Deprecated defines, if this command is deprecated and should print this string when used.
	Deprecated string

	// Version defines the version for this command. If this value is non-empty and the command does not
	// define a "version" flag, a "version" boolean flag will be added to the command and, if specified,
	// will print content of the "Version" variable. A shorthand "v" flag will also be added if the
	// command does not define one.
	Version string

	// The *Run functions are executed in the following order:
	//   * PersistentPreRun()
	//   * PreRun()
	//   * Run()
	//   * PostRun()
	//   * PersistentPostRun()
	// All functions get the same args, the arguments after the command name.
	//
	// PersistentPreRun: children of this command will inherit and execute.
	PersistentPreRun func(cmd *Cmd, args []string)
	// PersistentPreRunE: PersistentPreRun but returns an error.
	PersistentPreRunE func(cmd *Cmd, args []string) error
	// PreRun: children of this command will not inherit.
	PreRun func(cmd *Cmd, args []string)
	// PreRunE: PreRun but returns an error.
	PreRunE func(cmd *Cmd, args []string) error
	// Run: Typically the actual work function. Most commands will only implement this.
	Run func(cmd *Cmd, args []string)
	// RunE: Run but returns an error.
	RunE func(cmd *Cmd, args []string) error
	// PostRun: run after the Run command.
	PostRun func(cmd *Cmd, args []string)
	// PostRunE: PostRun but returns an error.
	PostRunE func(cmd *Cmd, args []string) error
	// PersistentPostRun: children of this command will inherit and execute after PostRun.
	PersistentPostRun func(cmd *Cmd, args []string)
	// PersistentPostRunE: PersistentPostRun but returns an error.
	PersistentPostRunE func(cmd *Cmd, args []string) error

	// args is actual args parsed from flags.
	args []string
	// flagErrorBuf contains all error messages from pflag.
	flagErrorBuf *bytes.Buffer
	// flags is full set of flags.
	flags *flag.FlagSet
	// pflags contains persistent flags.
	pflags *flag.FlagSet
	// lflags contains local flags.
	lflags *flag.FlagSet
	// iflags contains inherited flags.
	iflags *flag.FlagSet
	// parentsPflags is all persistent flags of cmd parents.
	parentsPflags *flag.FlagSet
	// globNormFunc is the global normalization function
	// that we can use on every pflag set and children commands
	globNormFunc func(f *flag.FlagSet, name string) flag.NormalizedName

	// Controls the usage string
	usage Usage

	// flagErrorFn is func defined by user, and it's called when the parsing of
	// flags returns an error.
	flagErrorFn ControlFlagErrorFn

	// help allows for the configuration of the help message by the user
	help Help

	// versionTemplate is the version template defined by user.
	versionTemplate string

	// input, output and error streams
	streams DataStreams

	// CompletionOptions is a set of options to control the handling of shell completion
	CompletionOptions CompletionOptions

	// commandsAreSorted defines, if command slice are sorted or not.
	commandsAreSorted bool
	// commandCalledAs is the name or alias value used to call this command.
	commandCalledAs struct {
		name   string
		called bool
	}

	ctx context.Context

	// commands is the list of commands supported by this program.
	commands []*Cmd
	// parent is a parent command for this command.
	parent *Cmd

	// Max lengths of commands' string lengths for use in padding.
	commandsMaxUseLen         int
	commandsMaxCommandPathLen int
	commandsMaxNameLen        int

	// TraverseChildren parses flags on all parents before executing child command.
	TraverseChildren bool

	// Hidden defines, if this command is hidden and should NOT show up in the list of available commands.
	Hidden bool

	// SilenceErrors is an option to quiet errors down stream.
	SilenceErrors bool

	// SilenceUsage is an option to silence usage when an error occurs.
	SilenceUsage bool

	// DisableFlagParsing disables the flag parsing.
	// If this is true all flags will be passed to the command as arguments.
	DisableFlagParsing bool

	// DisableAutoGenTag defines, if gen tag ("Auto generated by spf13/cobra...")
	// will be printed by generating docs for this command.
	DisableAutoGenTag bool

	// DisableFlagsInUseLine will disable the addition of [flags] to the usage
	// line of a command when printing help or generating docs
	DisableFlagsInUseLine bool

	// DisableSuggestions disables the suggestions based on Levenshtein distance
	// that go along with 'unknown command' messages.
	DisableSuggestions bool

	// SuggestionsMinimumDistance defines minimum levenshtein distance to display suggestions.
	// Must be > 0.
	SuggestionsMinimumDistance int
}

// Context returns underlying command context. If command was executed
// with ExecuteContext or the context was set with SetContext, the
// previously set context will be returned. Otherwise, nil is returned.
//
// Notice that a call to Execute and ExecuteC will replace a nil context of
// a command with a context.Background, so a background context will be
// returned by Context after one of these functions has been called.
func (c *Cmd) Context() context.Context {
	return c.ctx
}

// SetContext sets context for the command. It is set to context.Background
// by default and will be overwritten by Command.ExecuteContext or
// Command.ExecuteContextC
func (c *Cmd) SetContext(ctx context.Context) {
	c.ctx = ctx
}

// SetArgs sets arguments for the command. It is set to os.Args[1:] by default,
// if desired, can be overridden particularly useful when testing.
func (c *Cmd) SetArgs(a []string) {
	c.args = a
}

// SetInputStream allows the input stream to be assigned to the command.
func (c *Cmd) SetInputStream(in io.Reader) {
	c.streams.In = in
}

// SetOutputStream allows the output stream to be assigned to the command.
func (c *Cmd) SetOutputStream(out io.Writer) {
	c.streams.Out = out
}

// SetErrorStream allows the error stream to be assigned to the command.
func (c *Cmd) SetErrorStream(e io.Writer) {
	c.streams.Err = e
}

// SetUsageClosure assign user defined closure for usage
func (c *Cmd) SetUsageClosure(fn ControlUsageFn) {
	c.usage.Control = fn
}

// SetUsageTemplate allows the user to control the usage template.
func (c *Cmd) SetUsageTemplate(s string) {
	c.usage.Template = s
}

// DataStreams represents the 3 modes by which data travels via the cli.
// In: 	the standard input os.Stdin of the app.
// Out:	the standard output os.Stdout of the app.
// Err: the standard error os.Stderr of the app.
//
// These can all be controlled by the user, but left on touched the defaults
// are listed as above
type DataStreams struct {
	In  io.Reader
	Out io.Writer
	Err io.Writer
}

// NewDefaultDataStreams represents the system defaults for all streams
func NewDefaultDataStreams() DataStreams {
	return NewDataStreams(os.Stdin, os.Stdout, os.Stderr)
}

// NewDataStreams constructor used to create in/out and err streams
func NewDataStreams(in io.Reader, out, err io.Writer) DataStreams {
	return DataStreams{
		In:  in,
		Out: out,
		Err: err,
	}
}

// Usage allows the user to control the usage string in the cli
type Usage struct {
	Control  ControlUsageFn
	Template string
}

// Help allow for the configuration of the cli help screen
// Control: 	help function defined by the user
// Template: 	help template defined by the user
// Default: 	default help cmd
type Help struct {
	Control  ControlHelpFn
	Template string
	Default  *Cmd
}
<commit_msg>moving lifecycle events into separate struct<commit_after>package fuelcell

import (
	"bytes"
	"context"
	"io"
	"os"

	flag "github.com/spf13/pflag"
)

// FParseErrWhitelist configures Flag parse errors to be ignored
type FParseErrWhitelist flag.ParseErrorsWhitelist

// ControlUsageFn is the function signature for the usage closure.
type ControlUsageFn func(*Cmd) error

// ControlFlagErrorFn is a function signature to allow user to control when
// the parsing of a flag returns an error
type ControlFlagErrorFn func(*Cmd, error) error

// ControlHelpFn is a function signature to allow users to control help
type ControlHelpFn func(*Cmd, []string)

// CLIRun defines how a Cmd should be executed when error handle is governed
// by the returned error.
type CLIRun func(*Cmd, []string) error

// Cmd represents a command on the command line. This command is heavily
// influenced by Cobra cli. The goal of this project is to implement what
// cobra did but with a few difference and of course remove unneeded legacy
// baggage.
type Cmd struct {
	// Use is the one-line usage message.
	// Recommended syntax is as follows:
	//   [ ] identifies an optional argument. Arguments that are not enclosed in brackets are required.
	//   ... indicates that you can specify multiple values for the previous argument.
	//   |   indicates mutually exclusive information. You can use the argument to the left of the separator or the
	//       argument to the right of the separator. You cannot use both arguments in a single use of the command.
	//   { } delimits a set of mutually exclusive arguments when one of the arguments is required. If the arguments are
	//       optional, they are enclosed in brackets ([ ]).
	// Example: add [-F file | -D dir]... [-f format] profile
	Use string

	// Aliases is an array of aliases that can be used instead of the first word in Use.
	Aliases []string

	// SuggestFor is an array of command names for which this command will be suggested -
	// similar to aliases but only suggests.
	SuggestFor []string

	// Short is the short description shown in the 'help' output.
	Short string

	// Long is the long message shown in the 'help <this-command>' output.
	Long string

	// Example is examples of how to use the command.
	Example string

	// ValidArgs is list of all valid non-flag arguments that are accepted in shell completions
	ValidArgs []string

	// ValidArgsFunction is an optional function that provides valid non-flag arguments for shell completion.
	// It is a dynamic version of using ValidArgs.
	// Only one of ValidArgs and ValidArgsFunction can be used for a command.
	ValidArgsFunction func(cmd *Cmd, args []string, toComplete string) ([]string, ShellCompDirective)

	// Expected arguments
	Args PositionalArgs

	// ArgAliases is List of aliases for ValidArgs.
	// These are not suggested to the user in the shell completion,
	// but accepted if entered manually.
	ArgAliases []string

	// Deprecated defines, if this command is deprecated and should print this string when used.
	Deprecated string

	// Version defines the version for this command. If this value is non-empty and the command does not
	// define a "version" flag, a "version" boolean flag will be added to the command and, if specified,
	// will print content of the "Version" variable. A shorthand "v" flag will also be added if the
	// command does not define one.
	Version string

	// The *Run functions are executed in the following order:
	//   * PersistentPreRun()
	//   * PreRun()
	//   * Run()
	//   * PostRun()
	//   * PersistentPostRun()
	// All functions get the same args, the arguments after the command name.
	//

	// The run event function are executed in the following order:
	// * GlobalPreRun
	// * PreRun
	// * Run
	// * PostRun
	// * GlobalPostRun
	// All function have the same run signature CLIRun
	lifecycle Lifecycle

	// args is actual args parsed from flags.
	args []string
	// flagErrorBuf contains all error messages from pflag.
	flagErrorBuf *bytes.Buffer
	// flags is full set of flags.
	flags *flag.FlagSet
	// pflags contains persistent flags.
	pflags *flag.FlagSet
	// lflags contains local flags.
	lflags *flag.FlagSet
	// iflags contains inherited flags.
	iflags *flag.FlagSet
	// parentsPflags is all persistent flags of cmd parents.
	parentsPflags *flag.FlagSet
	// globNormFunc is the global normalization function
	// that we can use on every pflag set and children commands
	globNormFunc func(f *flag.FlagSet, name string) flag.NormalizedName

	// Controls the usage string
	usage Usage

	// flagErrorFn is func defined by user, and it's called when the parsing of
	// flags returns an error.
	flagErrorFn ControlFlagErrorFn

	// help allows for the configuration of the help message by the user
	help Help

	// versionTemplate is the version template defined by user.
	versionTemplate string

	// input, output and error streams
	streams DataStreams

	// CompletionOptions is a set of options to control the handling of shell completion
	CompletionOptions CompletionOptions

	// commandsAreSorted defines, if command slice are sorted or not.
	commandsAreSorted bool
	// commandCalledAs is the name or alias value used to call this command.
	commandCalledAs struct {
		name   string
		called bool
	}

	ctx context.Context

	// commands is the list of commands supported by this program.
	commands []*Cmd
	// parent is a parent command for this command.
	parent *Cmd

	// Max lengths of commands' string lengths for use in padding.
	commandsMaxUseLen         int
	commandsMaxCommandPathLen int
	commandsMaxNameLen        int

	// TraverseChildren parses flags on all parents before executing child command.
	TraverseChildren bool

	// Hidden defines, if this command is hidden and should NOT show up in the list of available commands.
	Hidden bool

	// SilenceErrors is an option to quiet errors down stream.
	SilenceErrors bool

	// SilenceUsage is an option to silence usage when an error occurs.
	SilenceUsage bool

	// DisableFlagParsing disables the flag parsing.
	// If this is true all flags will be passed to the command as arguments.
	DisableFlagParsing bool

	// DisableAutoGenTag defines, if gen tag ("Auto generated by spf13/cobra...")
	// will be printed by generating docs for this command.
	DisableAutoGenTag bool

	// DisableFlagsInUseLine will disable the addition of [flags] to the usage
	// line of a command when printing help or generating docs
	DisableFlagsInUseLine bool

	// DisableSuggestions disables the suggestions based on Levenshtein distance
	// that go along with 'unknown command' messages.
	DisableSuggestions bool

	// SuggestionsMinimumDistance defines minimum levenshtein distance to display suggestions.
	// Must be > 0.
	SuggestionsMinimumDistance int
}

// Context returns underlying command context. If command was executed
// with ExecuteContext or the context was set with SetContext, the
// previously set context will be returned. Otherwise, nil is returned.
//
// Notice that a call to Execute and ExecuteC will replace a nil context of
// a command with a context.Background, so a background context will be
// returned by Context after one of these functions has been called.
func (c *Cmd) Context() context.Context {
	return c.ctx
}

// SetContext sets context for the command. It is set to context.Background
// by default and will be overwritten by Command.ExecuteContext or
// Command.ExecuteContextC
func (c *Cmd) SetContext(ctx context.Context) {
	c.ctx = ctx
}

// SetArgs sets arguments for the command. It is set to os.Args[1:] by default,
// if desired, can be overridden particularly useful when testing.
func (c *Cmd) SetArgs(a []string) {
	c.args = a
}

// SetInputStream allows the input stream to be assigned to the command.
func (c *Cmd) SetInputStream(in io.Reader) {
	c.streams.In = in
}

// SetOutputStream allows the output stream to be assigned to the command.
func (c *Cmd) SetOutputStream(out io.Writer) {
	c.streams.Out = out
}

// SetErrorStream allows the error stream to be assigned to the command.
func (c *Cmd) SetErrorStream(e io.Writer) {
	c.streams.Err = e
}

// SetUsageClosure assign user defined closure for usage
func (c *Cmd) SetUsageClosure(fn ControlUsageFn) {
	c.usage.Control = fn
}

// SetUsageTemplate allows the user to control the usage template.
func (c *Cmd) SetUsageTemplate(s string) {
	c.usage.Template = s
}

// DataStreams represents the 3 modes by which data travels via the cli.
// In: 	the standard input os.Stdin of the app.
// Out:	the standard output os.Stdout of the app.
// Err: the standard error os.Stderr of the app.
//
// These can all be controlled by the user, but left on touched the defaults
// are listed as above
type DataStreams struct {
	In  io.Reader
	Out io.Writer
	Err io.Writer
}

// NewDefaultDataStreams represents the system defaults for all streams
func NewDefaultDataStreams() DataStreams {
	return NewDataStreams(os.Stdin, os.Stdout, os.Stderr)
}

// NewDataStreams constructor used to create in/out and err streams
func NewDataStreams(in io.Reader, out, err io.Writer) DataStreams {
	return DataStreams{
		In:  in,
		Out: out,
		Err: err,
	}
}

// Usage allows the user to control the usage string in the cli
type Usage struct {
	Control  ControlUsageFn
	Template string
}

// Help allow for the configuration of the cli help screen
// Control: 	help function defined by the user
// Template: 	help template defined by the user
// Default: 	default help cmd
type Help struct {
	Control  ControlHelpFn
	Template string
	Default  *Cmd
}

// Lifecycle holds all the different events which are fired during the
// lifetime of the command.
// Events are run in the following order:
// * GlobalPreRun
// * PreRun
// * Run
// * PostRun
// * GlobalPostRun
// All events follow the same function signature.
type Lifecycle struct {
	GlobalPreRun  CLIRun
	PreRun        CLIRun
	Run           CLIRun
	PostRun       CLIRun
	GlobalPostRun CLIRun
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/spf13/cobra"
)

type Options struct {
	verbose  bool
	force    bool
	kill     bool
	config   string
	manifest string
	group    string
}

var options = Options{
	false,
	false,
	false,
	"",
	"",
	"",
}
var defaultManifests = []string{"crane.json", "crane.yaml", "crane.yml", "Cranefile"}

func manifestFiles() []string {
	var result = []string(nil)
	if len(options.manifest) > 0 {
		result = []string{options.manifest}
	} else {
		result = defaultManifests
	}
	return result
}

func isVerbose() bool {
	return options.verbose
}

func handleCmd() {
	var cmdLift = &cobra.Command{
		Use:   "lift",
		Short: "Build or pull images, then run or start the containers",
		Long: `
lift will use specified Dockerfiles to build the images.
If no Dockerfile is given, it will pull the image(s) from the given registry.`,
		Run: func(cmd *cobra.Command, args []string) {
			containers := getContainers(options)
			containers.lift(options.force, options.kill)
		},
	}

	var cmdProvision = &cobra.Command{
		Use:   "provision",
		Short: "Build or pull images",
		Long: `
provision will use specified Dockerfiles to build the images.
If no Dockerfile is given, it will pull the image(s) from the given registry.`,
		Run: func(cmd *cobra.Command, args []string) {
			containers := getContainers(options)
			containers.provision(options.force)
		},
	}

	var cmdRun = &cobra.Command{
		Use:   "run",
		Short: "Run the containers",
		Long:  `run will call docker run on all containers.`,
		Run: func(cmd *cobra.Command, args []string) {
			containers := getContainers(options)
			containers.run(options.force, options.kill)
		},
	}

	var cmdRm = &cobra.Command{
		Use:   "rm",
		Short: "Remove the containers",
		Long:  `rm will call docker rm on all containers.`,
		Run: func(cmd *cobra.Command, args []string) {
			containers := getContainers(options)
			containers.rm(options.force, options.kill)
		},
	}

	var cmdKill = &cobra.Command{
		Use:   "kill",
		Short: "Kill the containers",
		Long:  `kill will call docker kill on all containers.`,
		Run: func(cmd *cobra.Command, args []string) {
			containers := getContainers(options)
			containers.kill()
		},
	}

	var cmdStart = &cobra.Command{
		Use:   "start",
		Short: "Start the containers",
		Long:  `start will call docker start on all containers.`,
		Run: func(cmd *cobra.Command, args []string) {
			containers := getContainers(options)
			containers.start()
		},
	}

	var cmdStop = &cobra.Command{
		Use:   "stop",
		Short: "Stop the containers",
		Long:  `stop will call docker stop on all containers.`,
		Run: func(cmd *cobra.Command, args []string) {
			containers := getContainers(options)
			containers.stop()
		},
	}

	var cmdStatus = &cobra.Command{
		Use:   "status",
		Short: "Displays status of containers",
		Long:  `Displays the current status of the containers.`,
		Run: func(cmd *cobra.Command, args []string) {
			containers := getContainers(options)
			containers.status()
		},
	}

	var cmdVersion = &cobra.Command{
		Use:   "version",
		Short: "Display version",
		Long:  `Displays the version of Crane.`,
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("v0.7.0")
		},
	}

	var craneCmd = &cobra.Command{
		Use:   "crane",
		Short: "crane - Lift containers with ease",
		Long: `
Crane is a little tool to orchestrate Docker containers.
It works by reading in JSON or YAML (either from crane.json, crane.yaml, the string specified in --config, or a json or yml file specified by --manifest) which describes how to obtain container images and how to run them.
See the corresponding docker commands for more information.`,
	}

	craneCmd.PersistentFlags().BoolVarP(&options.verbose, "verbose", "v", false, "verbose output")
	craneCmd.PersistentFlags().StringVarP(&options.config, "config", "c", "", "config to read from")
	craneCmd.PersistentFlags().StringVarP(&options.manifest, "manifest", "m", "", "config file to read from")
	craneCmd.PersistentFlags().StringVarP(&options.group, "group", "g", "", "group or container to restrict the command to")
	cmdLift.Flags().BoolVarP(&options.force, "force", "f", false, "rebuild all images")
	cmdLift.Flags().BoolVarP(&options.kill, "kill", "k", false, "kill containers")
	cmdProvision.Flags().BoolVarP(&options.force, "force", "f", false, "rebuild all images")
	cmdRun.Flags().BoolVarP(&options.force, "force", "f", false, "stop and remove running containers first")
	cmdRun.Flags().BoolVarP(&options.kill, "kill", "k", false, "when using --force, kill containers instead of stopping them")
	cmdRm.Flags().BoolVarP(&options.force, "force", "f", false, "stop running containers first")
	cmdRm.Flags().BoolVarP(&options.kill, "kill", "k", false, "when using --force, kill containers instead of stopping them")
	craneCmd.AddCommand(cmdLift, cmdProvision, cmdRun, cmdRm, cmdKill, cmdStart, cmdStop, cmdStatus, cmdVersion)
	craneCmd.Execute()
}
<commit_msg>reflect possibility of restricting the affected containers via -g<commit_after>package main

import (
	"fmt"
	"github.com/spf13/cobra"
)

type Options struct {
	verbose  bool
	force    bool
	kill     bool
	config   string
	manifest string
	group    string
}

var options = Options{
	false,
	false,
	false,
	"",
	"",
	"",
}
var defaultManifests = []string{"crane.json", "crane.yaml", "crane.yml", "Cranefile"}

func manifestFiles() []string {
	var result = []string(nil)
	if len(options.manifest) > 0 {
		result = []string{options.manifest}
	} else {
		result = defaultManifests
	}
	return result
}

func isVerbose() bool {
	return options.verbose
}

func handleCmd() {
	var cmdLift = &cobra.Command{
		Use:   "lift",
		Short: "Build or pull images, then run or start the containers",
		Long: `
lift will use specified Dockerfiles to build all the containers, or the specified one(s).
If no Dockerfile is given, it will pull the image(s) from the given registry.`,
		Run: func(cmd *cobra.Command, args []string) {
			containers := getContainers(options)
			containers.lift(options.force, options.kill)
		},
	}

	var cmdProvision = &cobra.Command{
		Use:   "provision",
		Short: "Build or pull images",
		Long: `
provision will use specified Dockerfiles to build all the containers, or the specified one(s).
If no Dockerfile is given, it will pull the image(s) from the given registry.`,
		Run: func(cmd *cobra.Command, args []string) {
			containers := getContainers(options)
			containers.provision(options.force)
		},
	}

	var cmdRun = &cobra.Command{
		Use:   "run",
		Short: "Run the containers",
		Long:  `run will call docker run on all containers, or the specified one(s).`,
		Run: func(cmd *cobra.Command, args []string) {
			containers := getContainers(options)
			containers.run(options.force, options.kill)
		},
	}

	var cmdRm = &cobra.Command{
		Use:   "rm",
		Short: "Remove the containers",
		Long:  `rm will call docker rm on all containers, or the specified one(s).`,
		Run: func(cmd *cobra.Command, args []string) {
			containers := getContainers(options)
			containers.rm(options.force, options.kill)
		},
	}

	var cmdKill = &cobra.Command{
		Use:   "kill",
		Short: "Kill the containers",
		Long:  `kill will call docker kill on all containers, or the specified one(s).`,
		Run: func(cmd *cobra.Command, args []string) {
			containers := getContainers(options)
			containers.kill()
		},
	}

	var cmdStart = &cobra.Command{
		Use:   "start",
		Short: "Start the containers",
		Long:  `start will call docker start on all containers, or the specified one(s).`,
		Run: func(cmd *cobra.Command, args []string) {
			containers := getContainers(options)
			containers.start()
		},
	}

	var cmdStop = &cobra.Command{
		Use:   "stop",
		Short: "Stop the containers",
		Long:  `stop will call docker stop on all containers, or the specified one(s).`,
		Run: func(cmd *cobra.Command, args []string) {
			containers := getContainers(options)
			containers.stop()
		},
	}

	var cmdStatus = &cobra.Command{
		Use:   "status",
		Short: "Displays status of containers",
		Long:  `Displays the current status of all the containers, or the specified one(s).`,
		Run: func(cmd *cobra.Command, args []string) {
			containers := getContainers(options)
			containers.status()
		},
	}

	var cmdVersion = &cobra.Command{
		Use:   "version",
		Short: "Display version",
		Long:  `Displays the version of Crane.`,
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("v0.7.0")
		},
	}

	var craneCmd = &cobra.Command{
		Use:   "crane",
		Short: "crane - Lift containers with ease",
		Long: `
Crane is a little tool to orchestrate Docker containers.
It works by reading in JSON or YAML (either from crane.json, crane.yaml, the string specified in --config, or a json or yml file specified by --manifest) which describes how to obtain container images and how to run them.
See the corresponding docker commands for more information.`,
	}

	craneCmd.PersistentFlags().BoolVarP(&options.verbose, "verbose", "v", false, "verbose output")
	craneCmd.PersistentFlags().StringVarP(&options.config, "config", "c", "", "config to read from")
	craneCmd.PersistentFlags().StringVarP(&options.manifest, "manifest", "m", "", "config file to read from")
	craneCmd.PersistentFlags().StringVarP(&options.group, "group", "g", "", "group or container to restrict the command to")
	cmdLift.Flags().BoolVarP(&options.force, "force", "f", false, "rebuild all images")
	cmdLift.Flags().BoolVarP(&options.kill, "kill", "k", false, "kill containers")
	cmdProvision.Flags().BoolVarP(&options.force, "force", "f", false, "rebuild all images")
	cmdRun.Flags().BoolVarP(&options.force, "force", "f", false, "stop and remove running containers first")
	cmdRun.Flags().BoolVarP(&options.kill, "kill", "k", false, "when using --force, kill containers instead of stopping them")
	cmdRm.Flags().BoolVarP(&options.force, "force", "f", false, "stop running containers first")
	cmdRm.Flags().BoolVarP(&options.kill, "kill", "k", false, "when using --force, kill containers instead of stopping them")
	craneCmd.AddCommand(cmdLift, cmdProvision, cmdRun, cmdRm, cmdKill, cmdStart, cmdStop, cmdStatus, cmdVersion)
	craneCmd.Execute()
}
<|endoftext|>