<commit_before>package program

import (
	"bufio"
	"fmt"
	"github.com/gorilla/websocket"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"sync"
	"syscall"
)

const BUFFER_SIZE = 1000

type Subscriber interface {
	Unsubscribe(*websocket.Conn)
}

type Program struct {
	Name        string
	CommandPath string
	MainSource  string
	executions  []*Execution
	messages    chan *programExecutionsMessage
	subscribers map[*websocket.Conn]bool
	Config
	sync.RWMutex
}

type programExecutionsMessage struct {
	ProgramName          string `json:"programName"`
	ExecutionId          string `json:"executionId"`
	ExecutionTime        string `json:"executionTime"`
	ExecutionLastOutput  string `json:"executionLastOutput"`
	ExecutionStatus      string `json:"executionStatus"`
	ExecutionStatusLabel string `json:"executionStatusLabel"`
}

func forwardOutput(execution *Execution, messageType string, r io.Reader, finished chan interface{}) {
	scanner := bufio.NewScanner(r)

	for scanner.Scan() {
		execution.SendMessage(messageType, scanner.Text())
	}

	if err := scanner.Err(); err != nil {
		log.Println(execution.Program.Name, "scanner error", err)
	}

	finished <- struct{}{}
}

func (p *Program) Execute(startCh <-chan bool, ch chan<- ExitCode) (*Execution, error) {
	p.Lock()
	defer p.Unlock()

	ProgramLog(p, "executing command")
	cmd := exec.Command("bash", p.CommandPath)
	cmd.Dir = filepath.Dir(p.CommandPath)
	cmd.Env = os.Environ()
	ProgramLog(p, fmt.Sprintf("environment: %s", os.Environ()))

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return nil, err
	}

	stderr, err := cmd.StderrPipe()
	if err != nil {
		return nil, err
	}

	execution := NewExecution(p, cmd)
	cmd.Env = append(cmd.Env, "DAGR_EXECUTION_ID="+execution.Id)
	cmd.Env = append(cmd.Env, "DAGR_EXECUTION_URI=/executions/"+execution.Id)

	p.SendExecutionState(execution)
	messages := execution.messages
	stdoutFinished := make(chan interface{})
	stderrFinished := make(chan interface{})

	go forwardOutput(execution, "out", stdout, stdoutFinished)
	go forwardOutput(execution, "err", stderr, stderrFinished)

	go func() {
		ExecutionLog(execution, "waiting for execution start signal")
		<-startCh

		err = cmd.Start()
		if err != nil {
			execution.SendMessage("fail", fmt.Sprintf("failed to start: %s", err.Error()))
			execution.Finish(FailedCode)
			ch <- FailedCode
			return
		}
		execution.Started()

		defer close(messages)
		defer close(stdoutFinished)
		defer close(stderrFinished)

		// docs say we shouldn't call cmd.Wait() until all has been read, hence
		// the need for the 'finished' channels
		<-stdoutFinished
		<-stderrFinished

		err := cmd.Wait()
		if err == nil {
			execution.SendMessage("ok", "successfully completed")
			execution.Finish(SuccessCode)
			ch <- SuccessCode
			return
		}

		exitCode, err := extractExitCode(err)

		if err != nil {
			log.Println(p.Name, "failed to run", err)
			execution.SendMessage("fail", fmt.Sprint("failed to run ", err))
			execution.Finish(FailedCode)
			ch <- FailedCode
			return
		}

		ExecutionLog(execution, "exited with status", exitCode)
		execution.SendMessage("fail", fmt.Sprint("exited with status ", exitCode))
		execution.Finish(exitCode)
		ch <- exitCode
	}()

	p.executions = append(p.executions, execution)

	return execution, nil
}

func (p *Program) Executions() []*Execution {
	return p.executions
}

func (p *Program) SendExecutionState(e *Execution) {
	status := e.Status()
	programExecutionsMessage := &programExecutionsMessage{
		p.Name,
		e.Id,
		e.StartTime.Format("2 Jan 2006 15:04"),
		e.LastOutput("out"),
		status.name,
		status.label,
	}
	p.messages <- programExecutionsMessage
}

func (p *Program) Subscribe(c *websocket.Conn) {
	ProgramLog(p, "adding subscriber")
	p.subscribers[c] = true
}

func (p *Program) Unsubscribe(c *websocket.Conn) {
	ProgramLog(p, "removing subscriber")
	delete(p.subscribers, c)
}

func (p *Program) broadcast(msg *programExecutionsMessage) {
	p.RLock()
	defer p.RUnlock()
	for conn := range p.subscribers {
		if err := conn.WriteJSON(msg); err != nil {
			ProgramLog(p, "error when sending to websocket", err)
		}
	}
}

func extractExitCode(err error) (ExitCode, error) {
	switch ex := err.(type) {
	case *exec.ExitError:
		return ExitCode(ex.Sys().(syscall.WaitStatus).ExitStatus()), nil // assume Unix
	default:
		return 0, err
	}
}

func newProgram(name, commandPath, mainSource string, config *Config) *Program {
	return &Program{
		Name:        name,
		CommandPath: commandPath,
		MainSource:  mainSource,
		Config:      *config,
		messages:    make(chan *programExecutionsMessage, BUFFER_SIZE),
		subscribers: make(map[*websocket.Conn]bool),
	}
}

func startBroadcasting(program *Program) {
	go func() {
		for msg := range program.messages {
			program.broadcast(msg)
		}
	}()
}

func update(existingProgram, newProgram *Program) {
	existingProgram.MainSource = newProgram.MainSource
	existingProgram.Config = newProgram.Config
}

func ProgramLog(p *Program, args ...interface{}) {
	_, fn, line, _ := runtime.Caller(1)
	identity := []string{p.Name}
	s := fmt.Sprintf("%-25s", fmt.Sprintf("%s:%d", filepath.Base(fn), line))
	log.Println(append([]interface{}{s, identity}, args...)...)
}

func ExecutionLog(e *Execution, args ...interface{}) {
	_, fn, line, _ := runtime.Caller(1)
	identity := []string{e.Program.Name, e.Id}
	s := fmt.Sprintf("%-25s", fmt.Sprintf("%s:%d", filepath.Base(fn), line))
	log.Println(append([]interface{}{s, identity}, args...)...)
}
<commit_msg>reverting assumption that bash is available on the host machine<commit_after>package program

import (
	"bufio"
	"fmt"
	"github.com/gorilla/websocket"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"sync"
	"syscall"
)

const BUFFER_SIZE = 1000

type Subscriber interface {
	Unsubscribe(*websocket.Conn)
}

type Program struct {
	Name        string
	CommandPath string
	MainSource  string
	executions  []*Execution
	messages    chan *programExecutionsMessage
	subscribers map[*websocket.Conn]bool
	Config
	sync.RWMutex
}

type programExecutionsMessage struct {
	ProgramName          string `json:"programName"`
	ExecutionId          string `json:"executionId"`
	ExecutionTime        string `json:"executionTime"`
	ExecutionLastOutput  string `json:"executionLastOutput"`
	ExecutionStatus      string `json:"executionStatus"`
	ExecutionStatusLabel string `json:"executionStatusLabel"`
}

func forwardOutput(execution *Execution, messageType string, r io.Reader, finished chan interface{}) {
	scanner := bufio.NewScanner(r)

	for scanner.Scan() {
		execution.SendMessage(messageType, scanner.Text())
	}

	if err := scanner.Err(); err != nil {
		log.Println(execution.Program.Name, "scanner error", err)
	}

	finished <- struct{}{}
}

func (p *Program) Execute(startCh <-chan bool, ch chan<- ExitCode) (*Execution, error) {
	p.Lock()
	defer p.Unlock()

	ProgramLog(p, "executing command")
	cmd := exec.Command(p.CommandPath)
	cmd.Dir = filepath.Dir(p.CommandPath)
	cmd.Env = os.Environ()
	ProgramLog(p, fmt.Sprintf("environment: %s", os.Environ()))

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return nil, err
	}

	stderr, err := cmd.StderrPipe()
	if err != nil {
		return nil, err
	}

	execution := NewExecution(p, cmd)
	cmd.Env = append(cmd.Env, "DAGR_EXECUTION_ID="+execution.Id)
	cmd.Env = append(cmd.Env, "DAGR_EXECUTION_URI=/executions/"+execution.Id)

	p.SendExecutionState(execution)
	messages := execution.messages
	stdoutFinished := make(chan interface{})
	stderrFinished := make(chan interface{})

	go forwardOutput(execution, "out", stdout, stdoutFinished)
	go forwardOutput(execution, "err", stderr, stderrFinished)

	go func() {
		ExecutionLog(execution, "waiting for execution start signal")
		<-startCh

		err = cmd.Start()
		if err != nil {
			execution.SendMessage("fail", fmt.Sprintf("failed to start: %s", err.Error()))
			execution.Finish(FailedCode)
			ch <- FailedCode
			return
		}
		execution.Started()

		defer close(messages)
		defer close(stdoutFinished)
		defer close(stderrFinished)

		// docs say we shouldn't call cmd.Wait() until all has been read, hence
		// the need for the 'finished' channels
		<-stdoutFinished
		<-stderrFinished

		err := cmd.Wait()
		if err == nil {
			execution.SendMessage("ok", "successfully completed")
			execution.Finish(SuccessCode)
			ch <- SuccessCode
			return
		}

		exitCode, err := extractExitCode(err)

		if err != nil {
			log.Println(p.Name, "failed to run", err)
			execution.SendMessage("fail", fmt.Sprint("failed to run ", err))
			execution.Finish(FailedCode)
			ch <- FailedCode
			return
		}

		ExecutionLog(execution, "exited with status", exitCode)
		execution.SendMessage("fail", fmt.Sprint("exited with status ", exitCode))
		execution.Finish(exitCode)
		ch <- exitCode
	}()

	p.executions = append(p.executions, execution)

	return execution, nil
}

func (p *Program) Executions() []*Execution {
	return p.executions
}

func (p *Program) SendExecutionState(e *Execution) {
	status := e.Status()
	programExecutionsMessage := &programExecutionsMessage{
		p.Name,
		e.Id,
		e.StartTime.Format("2 Jan 2006 15:04"),
		e.LastOutput("out"),
		status.name,
		status.label,
	}
	p.messages <- programExecutionsMessage
}

func (p *Program) Subscribe(c *websocket.Conn) {
	ProgramLog(p, "adding subscriber")
	p.subscribers[c] = true
}

func (p *Program) Unsubscribe(c *websocket.Conn) {
	ProgramLog(p, "removing subscriber")
	delete(p.subscribers, c)
}

func (p *Program) broadcast(msg *programExecutionsMessage) {
	p.RLock()
	defer p.RUnlock()
	for conn := range p.subscribers {
		if err := conn.WriteJSON(msg); err != nil {
			ProgramLog(p, "error when sending to websocket", err)
		}
	}
}

func extractExitCode(err error) (ExitCode, error) {
	switch ex := err.(type) {
	case *exec.ExitError:
		return ExitCode(ex.Sys().(syscall.WaitStatus).ExitStatus()), nil // assume Unix
	default:
		return 0, err
	}
}

func newProgram(name, commandPath, mainSource string, config *Config) *Program {
	return &Program{
		Name:        name,
		CommandPath: commandPath,
		MainSource:  mainSource,
		Config:      *config,
		messages:    make(chan *programExecutionsMessage, BUFFER_SIZE),
		subscribers: make(map[*websocket.Conn]bool),
	}
}

func startBroadcasting(program *Program) {
	go func() {
		for msg := range program.messages {
			program.broadcast(msg)
		}
	}()
}

func update(existingProgram, newProgram *Program) {
	existingProgram.MainSource = newProgram.MainSource
	existingProgram.Config = newProgram.Config
}

func ProgramLog(p *Program, args ...interface{}) {
	_, fn, line, _ := runtime.Caller(1)
	identity := []string{p.Name}
	s := fmt.Sprintf("%-25s", fmt.Sprintf("%s:%d", filepath.Base(fn), line))
	log.Println(append([]interface{}{s, identity}, args...)...)
}

func ExecutionLog(e *Execution, args ...interface{}) {
	_, fn, line, _ := runtime.Caller(1)
	identity := []string{e.Program.Name, e.Id}
	s := fmt.Sprintf("%-25s", fmt.Sprintf("%s:%d", filepath.Base(fn), line))
	log.Println(append([]interface{}{s, identity}, args...)...)
}
<|endoftext|>


<commit_before>package parser

import (
	"fmt"
	"strings"
	"unicode/utf8"
)

type stateFn func(*lexer) stateFn

const (
	itemVersion  itemType = iota // Version string
	itemOperator                 // <, <=, >, >= =
	itemSet                      // Set seperated by whitespace
	itemRange                    // || ,
	itemAdvanced                 // ~, ^, -, x-ranges
	itemError
	itemEOF // End of input

	versionDEL = '.'
	operatorGT = '>'
	operatorGE = ">="
	operatorLT = '<'
	operatorLE = "<="
	operatorEQ = '='

	operatorTR = '~'
	operatorCR = '^'

	operatorRG = '|'
	operatorST = ' '
	operatorHY = '-'

	eof = -1

	numbers string = "0123456789"
	letters        = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-"

	dot        = "."
	hyphen     = "-"
	plus       = "+"
	delimiters = dot + hyphen + plus

	allchars  = alphanum + delimiters
	alphanum  = letters + numbers
	wildcards = "Xx*"
)

type itemType int

type item struct {
	typ itemType
	val string
}

func (i item) String() string {
	switch {
	case i.typ == itemEOF:
		return "EOF"
	case i.typ == itemError:
		return i.val
	}
	return fmt.Sprintf("%v", i.val)
}

type lexer struct {
	name  string    // used only for error reports.
	input string    // the string being scanned.
	start int       // start position of this item.
	pos   int       // current position in the input.
	width int       // width of last rune read from input.
	items chan item // channel of scanned items.
}

func lex(input string) (*lexer, chan item) {
	l := &lexer{
		input: input,
		items: make(chan item),
	}
	go l.run() // Concurrently run state machine.
	return l, l.items
}

func (l *lexer) run() {
	for state := lexMain; state != nil; {
		state = state(l)
	}
	close(l.items) // No more tokens will be delivered.
}

// emit passes an item back to the client.
func (l *lexer) emit(t itemType) {
	l.items <- item{t, l.input[l.start:l.pos]}
	l.start = l.pos
}

// next returns the next rune in the input.
func (l *lexer) next() (rn rune) {
	if l.pos >= len(l.input) {
		l.width = 0
		return eof
	}
	rn, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
	l.pos += l.width
	return rn
}

func (l *lexer) ignore() {
	l.start = l.pos
}

// peek returns but does not consume
// the next rune in the input.
func (l *lexer) peek() rune {
	rn := l.next()
	l.backup()
	return rn
}

func (l *lexer) backup() {
	l.pos -= l.width
}

func (l *lexer) rewind() {
	l.pos = l.start
}

// accept consumes the next rune
// if it's from the valid set.
func (l *lexer) accept(valid string) bool {
	if strings.IndexRune(valid, l.next()) >= 0 {
		return true
	}
	l.backup()
	return false
}

func (l *lexer) check(valid string) bool {
	if strings.IndexRune(valid, l.peek()) >= 0 {
		return true
	}
	return false
}

// acceptRun consumes a run of runes from the valid set.
func (l *lexer) acceptRun(valid string) {
	for strings.IndexRune(valid, l.next()) >= 0 {
	}
	l.backup()
}

func (l *lexer) errorf(format string, args ...interface{}) stateFn {
	l.items <- item{
		itemError,
		fmt.Sprintf(format, args...),
	}
	return nil
}

func lexMain(l *lexer) stateFn {
	switch r := l.peek(); {

	case r == eof || r == '\n':
		l.emit(itemEOF) // Useful to make EOF a token.
		return nil      // Stop the run loop.

	case '0' <= r && r <= '9':
		return lexVersion
	case r == operatorLT:
		return lexOperator
	case r == operatorGT:
		return lexOperator
	case r == operatorEQ:
		return lexOperator
	case r == operatorTR:
		return lexAdvancedRange
	case r == operatorCR:
		return lexAdvancedRange
	case r == operatorRG:
		return lexRange
	case r == operatorST:
		return lexSet
	case l.check(wildcards):
		return lexAdvancedVersion
	default:
		return l.errorf("invalid character:%v: %q", l.pos, string(r))
	}
}

func lexVersion(l *lexer) stateFn {

	l.acceptRun(numbers)
	if l.accept(dot) {
		if l.accept(numbers) {
			l.acceptRun(numbers)

			if l.accept(dot) {
				if l.accept(numbers) {
					l.acceptRun(numbers)

					if l.accept("+-") {
						if !l.accept(allchars) {
							return l.errorf("invalid character:%v: %q", l.pos, string(l.next()))
						}
						l.acceptRun(allchars)
					}

					if !isEnd(l.peek()) {
						return l.errorf("invalid character:%v: %q", l.pos, string(l.next()))
					}

					l.emit(itemVersion)
					return lexMain
				}
			}
		}
	}
	l.rewind()
	return lexAdvancedVersion
}

func lexOperator(l *lexer) stateFn {
	l.accept(string(operatorGT) + string(operatorLT))
	l.accept(string(operatorEQ))
	if !l.check(numbers) {
		return l.errorf("invalid character:%v: %q", l.pos, string(l.next()))
	}
	l.emit(itemOperator)
	return lexMain
}

func lexSet(l *lexer) stateFn {
	if l.accept(string(operatorST)) {
		if l.peek() == operatorRG {
			l.ignore()
			return lexRange
		}
		if l.peek() == operatorHY {
			l.ignore()
			return lexAdvancedRange
		}
		l.emit(itemSet)
	}
	return lexMain
}

func lexRange(l *lexer) stateFn {
	l.accept(string(operatorRG))
	if l.accept(string(operatorRG)) {
		l.emit(itemRange)
		if l.peek() == operatorST {
			l.next()
			l.ignore()
		}
		if isEnd(l.peek()) {
			return l.errorf("invalid character:%v: %q", l.pos, string(l.next()))
		}
		return lexMain
	}
	return l.errorf("invalid character:%v: %q", l.pos, string(l.next()))

}

func lexAdvancedRange(l *lexer) stateFn {
	if l.accept(string(operatorHY)) {
		l.emit(itemAdvanced)
		if l.peek() == operatorST {
			l.next()
			l.ignore()
		} else {
			return l.errorf("invalid character:%v: %q", l.pos, string(l.next()))
		}
		return lexMain
	}
	if l.accept(string(operatorCR) + string(operatorTR)) {
		l.emit(itemAdvanced)

		if !l.check(numbers) {
			return l.errorf("invalid character:%v: %q", l.pos, string(l.next()))
		}
	}

	return lexMain
}

func lexAdvancedVersion(l *lexer) stateFn {

	for i := 0; i <= 2; i++ {
		if !l.accept(wildcards) {
			if !l.accept(numbers) {
				return l.errorf("invalid character:%v: %q", l.pos, string(l.next()))
			}
			l.acceptRun(numbers)
		}

		if !l.accept(dot) {
			if !isEnd(l.peek()) {
				return l.errorf("invalid character:%v: %q", l.pos, string(l.next()))
			}
			l.emit(itemAdvanced)
			return lexMain
		}
	}
	return nil

}

func isEnd(r rune) bool {
	return (r == operatorST || r == eof || r == operatorRG)
}
<commit_msg>Fixed XRange lexing.<commit_after>package parser

import (
	"fmt"
	"strings"
	"unicode/utf8"
)

type stateFn func(*lexer) stateFn

const (
	itemVersion  itemType = iota // Version string
	itemOperator                 // <, <=, >, >= =
	itemSet                      // Set seperated by whitespace
	itemRange                    // || ,
	itemAdvanced                 // ~, ^, -, x-ranges
	itemError
	itemEOF // End of input

	versionDEL = '.'
	operatorGT = '>'
	operatorGE = ">="
	operatorLT = '<'
	operatorLE = "<="
	operatorEQ = '='

	operatorTR = '~'
	operatorCR = '^'

	operatorRG = '|'
	operatorST = ' '
	operatorHY = '-'

	eof = -1

	numbers string = "0123456789"
	letters        = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-"

	dot        = "."
	hyphen     = "-"
	plus       = "+"
	delimiters = dot + hyphen + plus

	allchars  = alphanum + delimiters
	alphanum  = letters + numbers
	wildcards = "Xx*"
)

type itemType int

type item struct {
	typ itemType
	val string
}

func (i item) String() string {
	switch {
	case i.typ == itemEOF:
		return "EOF"
	case i.typ == itemError:
		return i.val
	}
	return fmt.Sprintf("%v", i.val)
}

type lexer struct {
	name  string    // used only for error reports.
	input string    // the string being scanned.
	start int       // start position of this item.
	pos   int       // current position in the input.
	width int       // width of last rune read from input.
	items chan item // channel of scanned items.
}

func lex(input string) (*lexer, chan item) {
	l := &lexer{
		input: input,
		items: make(chan item),
	}
	go l.run() // Concurrently run state machine.
	return l, l.items
}

func (l *lexer) run() {
	for state := lexMain; state != nil; {
		state = state(l)
	}
	close(l.items) // No more tokens will be delivered.
}

// emit passes an item back to the client.
func (l *lexer) emit(t itemType) {
	l.items <- item{t, l.input[l.start:l.pos]}
	l.start = l.pos
}

// next returns the next rune in the input.
func (l *lexer) next() (rn rune) {
	if l.pos >= len(l.input) {
		l.width = 0
		return eof
	}
	rn, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
	l.pos += l.width
	return rn
}

func (l *lexer) ignore() {
	l.start = l.pos
}

// peek returns but does not consume
// the next rune in the input.
func (l *lexer) peek() rune {
	rn := l.next()
	l.backup()
	return rn
}

func (l *lexer) backup() {
	l.pos -= l.width
}

func (l *lexer) rewind() {
	l.pos = l.start
}

// accept consumes the next rune
// if it's from the valid set.
func (l *lexer) accept(valid string) bool {
	if strings.IndexRune(valid, l.next()) >= 0 {
		return true
	}
	l.backup()
	return false
}

func (l *lexer) check(valid string) bool {
	if strings.IndexRune(valid, l.peek()) >= 0 {
		return true
	}
	return false
}

// acceptRun consumes a run of runes from the valid set.
func (l *lexer) acceptRun(valid string) {
	for strings.IndexRune(valid, l.next()) >= 0 {
	}
	l.backup()
}

func (l *lexer) errorf(format string, args ...interface{}) stateFn {
	l.items <- item{
		itemError,
		fmt.Sprintf(format, args...),
	}
	return nil
}

func lexMain(l *lexer) stateFn {
	switch r := l.peek(); {

	case r == eof || r == '\n':
		l.emit(itemEOF) // Useful to make EOF a token.
		return nil      // Stop the run loop.

	case '0' <= r && r <= '9':
		return lexVersion
	case r == operatorLT:
		return lexOperator
	case r == operatorGT:
		return lexOperator
	case r == operatorEQ:
		return lexOperator
	case r == operatorTR:
		return lexAdvancedRange
	case r == operatorCR:
		return lexAdvancedRange
	case r == operatorRG:
		return lexRange
	case r == operatorST:
		return lexSet
	case l.check(wildcards):
		return lexAdvancedVersion
	default:
		return l.errorf("invalid character:%v: %q", l.pos, string(r))
	}
}

func lexVersion(l *lexer) stateFn {

	l.acceptRun(numbers)
	if l.accept(dot) {
		if l.accept(numbers) {
			l.acceptRun(numbers)

			if l.accept(dot) {
				if l.accept(numbers) {
					l.acceptRun(numbers)

					if l.accept("+-") {
						if !l.accept(allchars) {
							return l.errorf("invalid character:%v: %q", l.pos, string(l.next()))
						}
						l.acceptRun(allchars)
					}

					if !isEnd(l.peek()) {
						return l.errorf("invalid character:%v: %q", l.pos, string(l.next()))
					}

					l.emit(itemVersion)
					return lexMain
				}
			}
		}
	}
	l.rewind()
	return lexAdvancedVersion
}

func lexOperator(l *lexer) stateFn {
	l.accept(string(operatorGT) + string(operatorLT))
	l.accept(string(operatorEQ))
	if !l.check(numbers) {
		return l.errorf("invalid character:%v: %q", l.pos, string(l.next()))
	}
	l.emit(itemOperator)
	return lexMain
}

func lexSet(l *lexer) stateFn {
	if l.accept(string(operatorST)) {
		if l.peek() == operatorRG {
			l.ignore()
			return lexRange
		}
		if l.peek() == operatorHY {
			l.ignore()
			return lexAdvancedRange
		}
		l.emit(itemSet)
	}
	return lexMain
}

func lexRange(l *lexer) stateFn {
	l.accept(string(operatorRG))
	if l.accept(string(operatorRG)) {
		l.emit(itemRange)
		if l.peek() == operatorST {
			l.next()
			l.ignore()
		}
		if isEnd(l.peek()) {
			return l.errorf("invalid character:%v: %q", l.pos, string(l.next()))
		}
		return lexMain
	}
	return l.errorf("invalid character:%v: %q", l.pos, string(l.next()))

}

func lexAdvancedRange(l *lexer) stateFn {
	if l.accept(string(operatorHY)) {
		l.emit(itemAdvanced)
		if l.peek() == operatorST {
			l.next()
			l.ignore()
		} else {
			return l.errorf("invalid character:%v: %q", l.pos, string(l.next()))
		}
		return lexMain
	}
	if l.accept(string(operatorCR) + string(operatorTR)) {
		l.emit(itemAdvanced)

		if !l.check(numbers) {
			return l.errorf("invalid character:%v: %q", l.pos, string(l.next()))
		}
	}

	return lexMain
}

func lexAdvancedVersion(l *lexer) stateFn {
	// Syntax check
	for i := 0; i <= 2; i++ {
		if !l.accept(wildcards) {
			if !l.accept(numbers) {
				return l.errorf("invalid character:%v: %q", l.pos, string(l.next()))
			}
			l.acceptRun(numbers)
		}

		if !l.accept(dot) {
			if !isEnd(l.peek()) {
				return l.errorf("invalid character:%v: %q", l.pos, string(l.next()))
			}
			l.rewind()
			break
		}
	}

	// Generate item
	for i := 0; i <= 2; i++ {
		if !l.accept(wildcards) {
			l.acceptRun(numbers)
			l.accept(dot)
		} else {
			l.emit(itemAdvanced)
			break
		}
		if isEnd(l.peek()) {
			l.emit(itemAdvanced)
			break
		}
	}

	for !isEnd(l.next()) {
	}
	l.backup()
	l.ignore()

	return lexMain

}

func isEnd(r rune) bool {
	return (r == operatorST || r == eof || r == operatorRG)
}
<|endoftext|>


<commit_before>package parser

import (
  "fmt"
  bs_core "bitbucket.org/yyuu/bs/core"
)

type token struct {
  id int
  literal string
  location bs_core.Location
}

func (self token) String() string {
  return fmt.Sprintf("%s %d %q", self.location, self.id, self.literal)
}
<commit_msg>Display token type in its displayName<commit_after>package parser

import (
  "fmt"
  bs_core "bitbucket.org/yyuu/bs/core"
)

type token struct {
  id int
  literal string
  location bs_core.Location
}

func (self token) String() string {
  return fmt.Sprintf("%s %s %q", self.location, self.displayName(), self.literal)
}

func (self token) displayName() string {
  switch self.id {
    case EOF:           return "EOF"
    case SPACES:        return "SPACES"
    case BLOCK_COMMENT: return "BLOCK_COMMENT"
    case LINE_COMMENT:  return "LINE_COMMENT"
    case IDENTIFIER:    return "IDENTIFIER"
    case INTEGER:       return "INTEGER"
    case CHARACTER:     return "CHARACTER"
    case STRING:        return "STRING"
    case TYPENAME:      return "TYPENAME"

    /* keywords */
    case VOID:          return "VOID"
    case CHAR:          return "CHAR"
    case SHORT:         return "SHORT"
    case INT:           return "INT"
    case LONG:          return "LONG"
    case STRUCT:        return "STRUCT"
    case UNION:         return "UNION"
    case ENUM:          return "ENUM"
    case STATIC:        return "STATIC"
    case EXTERN:        return "EXTERN"
    case CONST:         return "CONST"
    case SIGNED:        return "SIGNED"
    case UNSIGNED:      return "UNSIGNED"
    case IF:            return "IF"
    case ELSE:          return "ELSE"
    case SWITCH:        return "SWITCH"
    case CASE:          return "CASE"
    case DEFAULT:       return "DEFAULT"
    case WHILE:         return "WHILE"
    case DO:            return "DO"
    case FOR:           return "FOR"
    case RETURN:        return "RETURN"
    case BREAK:         return "BREAK"
    case CONTINUE:      return "CONTINUE"
    case GOTO:          return "GOTO"
    case TYPEDEF:       return "TYPEDEF"
    case IMPORT:        return "IMPORT"
    case SIZEOF:        return "SIZEOF"

    /* operators */
    case DOTDOTDOT:     return "DOTDOTDOT"
    case LSHIFTEQ:      return "LSHIFTEQ"
    case RSHIFTEQ:      return "RSHIFTEQ"
    case NEQ:           return "NEQ"
    case MODEQ:         return "MODEQ"
    case ANDAND:        return "ANDAND"
    case ANDEQ:         return "ANDEQ"
    case MULEQ:         return "MULEQ"
    case PLUSPLUS:      return "PLUSPLUS"
    case PLUSEQ:        return "PLUSEQ"
    case MINUSMINUS:    return "MINUSMINUS"
    case MINUSEQ:       return "MINUSEQ"
    case ARROW:         return "ARROW"
    case DIVEQ:         return "DIVEQ"
    case LSHIFT:        return "LSHIFT"
    case LTEQ:          return "LTEQ"
    case EQEQ:          return "EQEQ"
    case GTEQ:          return "GTEQ"
    case RSHIFT:        return "RSHIFT"
    case XOREQ:         return "XOREQ"
    case OREQ:          return "OREQ"
    case OROR:          return "OROR"
    default: {
      return fmt.Sprintf("ID:%X", self.id)
    }
  }
}
<|endoftext|>


<commit_before>// Copyright 2011 Google Inc.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The uuid package generates and inspects UUIDs.
//
// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security Services.
//
// This package is a partial wrapper around the github.com/google/uuid package.  This package
// represents a UUID as []byte while github.com/google/uuid represents a UUID as [16]byte.
package uuid
<commit_msg>Fix up formatting of comment.<commit_after>// Copyright 2011 Google Inc.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The uuid package generates and inspects UUIDs.
//
// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security
// Services.
//
// This package is a partial wrapper around the github.com/google/uuid package.
// This package represents a UUID as []byte while github.com/google/uuid
// represents a UUID as [16]byte.
package uuid
<|endoftext|>


<commit_before>/*
 * MinIO Cloud Storage, (C) 2016, 2017, 2018, 2019 MinIO, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cmd

import (
	"net/http"

	"github.com/gorilla/mux"
)

const (
	adminAPIPathPrefix = "/minio/admin"
)

// adminAPIHandlers provides HTTP handlers for MinIO admin API.
type adminAPIHandlers struct {
}

// registerAdminRouter - Add handler functions for each service REST API routes.
func registerAdminRouter(router *mux.Router, enableConfigOps, enableIAMOps bool) {

	adminAPI := adminAPIHandlers{}
	// Admin router
	adminRouter := router.PathPrefix(adminAPIPathPrefix).Subrouter()

	// Version handler
	adminV1Router := adminRouter.PathPrefix("/v1").Subrouter()

	/// Service operations

	// Restart and stop MinIO service.
	adminV1Router.Methods(http.MethodPost).Path("/service").HandlerFunc(httpTraceAll(adminAPI.ServiceActionHandler)).Queries("action", "{action:.*}")
	// Update MinIO servers.
	adminV1Router.Methods(http.MethodPost).Path("/update").HandlerFunc(httpTraceAll(adminAPI.ServerUpdateHandler)).Queries("updateURL", "{updateURL:.*}")

	// Info operations
	adminV1Router.Methods(http.MethodGet).Path("/info").HandlerFunc(httpTraceAll(adminAPI.ServerInfoHandler))
	// Harware Info operations
	adminV1Router.Methods(http.MethodGet).Path("/hardware").HandlerFunc(httpTraceAll(adminAPI.ServerHardwareInfoHandler)).Queries("hwType", "{hwType:.*}")

	if globalIsDistXL || globalIsXL {
		/// Heal operations

		// Heal processing endpoint.
		adminV1Router.Methods(http.MethodPost).Path("/heal/").HandlerFunc(httpTraceAll(adminAPI.HealHandler))
		adminV1Router.Methods(http.MethodPost).Path("/heal/{bucket}").HandlerFunc(httpTraceAll(adminAPI.HealHandler))
		adminV1Router.Methods(http.MethodPost).Path("/heal/{bucket}/{prefix:.*}").HandlerFunc(httpTraceAll(adminAPI.HealHandler))

		adminV1Router.Methods(http.MethodPost).Path("/background-heal/status").HandlerFunc(httpTraceAll(adminAPI.BackgroundHealStatusHandler))

		/// Health operations

	}
	// Performance command - return performance details based on input type
	adminV1Router.Methods(http.MethodGet).Path("/performance").HandlerFunc(httpTraceAll(adminAPI.PerfInfoHandler)).Queries("perfType", "{perfType:.*}")

	// Profiling operations
	adminV1Router.Methods(http.MethodPost).Path("/profiling/start").HandlerFunc(httpTraceAll(adminAPI.StartProfilingHandler)).
		Queries("profilerType", "{profilerType:.*}")
	adminV1Router.Methods(http.MethodGet).Path("/profiling/download").HandlerFunc(httpTraceAll(adminAPI.DownloadProfilingHandler))

	/// Config operations
	if enableConfigOps {
		// Get config
		adminV1Router.Methods(http.MethodGet).Path("/config").HandlerFunc(httpTraceHdrs(adminAPI.GetConfigHandler))
		// Set config
		adminV1Router.Methods(http.MethodPut).Path("/config").HandlerFunc(httpTraceHdrs(adminAPI.SetConfigHandler))
	}

	if enableIAMOps {
		// -- IAM APIs --

		// Add policy IAM
		adminV1Router.Methods(http.MethodPut).Path("/add-canned-policy").HandlerFunc(httpTraceHdrs(adminAPI.AddCannedPolicy)).Queries("name",
			"{name:.*}")

		// Add user IAM
		adminV1Router.Methods(http.MethodPut).Path("/add-user").HandlerFunc(httpTraceHdrs(adminAPI.AddUser)).Queries("accessKey", "{accessKey:.*}")
		adminV1Router.Methods(http.MethodPut).Path("/set-user-status").HandlerFunc(httpTraceHdrs(adminAPI.SetUserStatus)).
			Queries("accessKey", "{accessKey:.*}").Queries("status", "{status:.*}")

		// Info policy IAM
		adminV1Router.Methods(http.MethodGet).Path("/info-canned-policy").HandlerFunc(httpTraceHdrs(adminAPI.InfoCannedPolicy)).Queries("name", "{name:.*}")

		// Remove policy IAM
		adminV1Router.Methods(http.MethodDelete).Path("/remove-canned-policy").HandlerFunc(httpTraceHdrs(adminAPI.RemoveCannedPolicy)).Queries("name", "{name:.*}")

		// Set user or group policy
		adminV1Router.Methods(http.MethodPut).Path("/set-user-or-group-policy").
			HandlerFunc(httpTraceHdrs(adminAPI.SetPolicyForUserOrGroup)).
			Queries("policyName", "{policyName:.*}", "userOrGroup", "{userOrGroup:.*}", "isGroup", "{isGroup:true|false}")

		// Remove user IAM
		adminV1Router.Methods(http.MethodDelete).Path("/remove-user").HandlerFunc(httpTraceHdrs(adminAPI.RemoveUser)).Queries("accessKey", "{accessKey:.*}")

		// List users
		adminV1Router.Methods(http.MethodGet).Path("/list-users").HandlerFunc(httpTraceHdrs(adminAPI.ListUsers))

		// User info
		adminV1Router.Methods(http.MethodGet).Path("/user-info").HandlerFunc(httpTraceHdrs(adminAPI.GetUserInfo)).Queries("accessKey", "{accessKey:.*}")

		// Add/Remove members from group
		adminV1Router.Methods(http.MethodPut).Path("/update-group-members").HandlerFunc(httpTraceHdrs(adminAPI.UpdateGroupMembers))

		// Get Group
		adminV1Router.Methods(http.MethodGet).Path("/group").HandlerFunc(httpTraceHdrs(adminAPI.GetGroup)).Queries("group", "{group:.*}")

		// List Groups
		adminV1Router.Methods(http.MethodGet).Path("/groups").HandlerFunc(httpTraceHdrs(adminAPI.ListGroups))

		// Set Group Status
		adminV1Router.Methods(http.MethodPut).Path("/set-group-status").HandlerFunc(httpTraceHdrs(adminAPI.SetGroupStatus)).Queries("group", "{group:.*}").Queries("status", "{status:.*}")

		// List policies
		adminV1Router.Methods(http.MethodGet).Path("/list-canned-policies").HandlerFunc(httpTraceHdrs(adminAPI.ListCannedPolicies))
	}

	// -- Top APIs --
	// Top locks
	adminV1Router.Methods(http.MethodGet).Path("/top/locks").HandlerFunc(httpTraceHdrs(adminAPI.TopLocksHandler))

	// HTTP Trace
	adminV1Router.Methods(http.MethodGet).Path("/trace").HandlerFunc(adminAPI.TraceHandler)

	// Console Logs
	adminV1Router.Methods(http.MethodGet).Path("/log").HandlerFunc(httpTraceAll(adminAPI.ConsoleLogHandler))

	// -- KMS APIs --
	//
	adminV1Router.Methods(http.MethodGet).Path("/kms/key/status").HandlerFunc(httpTraceAll(adminAPI.KMSKeyStatusHandler))

	// If none of the routes match, return error.
	adminV1Router.MethodNotAllowedHandler = http.HandlerFunc(httpTraceAll(versionMismatchHandler))
}
<commit_msg>Fix regression in admin router when no route matches (#8409)<commit_after>/*
 * MinIO Cloud Storage, (C) 2016, 2017, 2018, 2019 MinIO, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cmd

import (
	"net/http"

	"github.com/gorilla/mux"
)

const (
	adminAPIPathPrefix = "/minio/admin"
)

// adminAPIHandlers provides HTTP handlers for MinIO admin API.
type adminAPIHandlers struct {
}

// registerAdminRouter - Add handler functions for each service REST API routes.
func registerAdminRouter(router *mux.Router, enableConfigOps, enableIAMOps bool) {

	adminAPI := adminAPIHandlers{}
	// Admin router
	adminRouter := router.PathPrefix(adminAPIPathPrefix).Subrouter()

	// Version handler
	adminV1Router := adminRouter.PathPrefix("/v1").Subrouter()

	/// Service operations

	// Restart and stop MinIO service.
	adminV1Router.Methods(http.MethodPost).Path("/service").HandlerFunc(httpTraceAll(adminAPI.ServiceActionHandler)).Queries("action", "{action:.*}")
	// Update MinIO servers.
	adminV1Router.Methods(http.MethodPost).Path("/update").HandlerFunc(httpTraceAll(adminAPI.ServerUpdateHandler)).Queries("updateURL", "{updateURL:.*}")

	// Info operations
	adminV1Router.Methods(http.MethodGet).Path("/info").HandlerFunc(httpTraceAll(adminAPI.ServerInfoHandler))
	// Harware Info operations
	adminV1Router.Methods(http.MethodGet).Path("/hardware").HandlerFunc(httpTraceAll(adminAPI.ServerHardwareInfoHandler)).Queries("hwType", "{hwType:.*}")

	if globalIsDistXL || globalIsXL {
		/// Heal operations

		// Heal processing endpoint.
		adminV1Router.Methods(http.MethodPost).Path("/heal/").HandlerFunc(httpTraceAll(adminAPI.HealHandler))
		adminV1Router.Methods(http.MethodPost).Path("/heal/{bucket}").HandlerFunc(httpTraceAll(adminAPI.HealHandler))
		adminV1Router.Methods(http.MethodPost).Path("/heal/{bucket}/{prefix:.*}").HandlerFunc(httpTraceAll(adminAPI.HealHandler))

		adminV1Router.Methods(http.MethodPost).Path("/background-heal/status").HandlerFunc(httpTraceAll(adminAPI.BackgroundHealStatusHandler))

		/// Health operations

	}
	// Performance command - return performance details based on input type
	adminV1Router.Methods(http.MethodGet).Path("/performance").HandlerFunc(httpTraceAll(adminAPI.PerfInfoHandler)).Queries("perfType", "{perfType:.*}")

	// Profiling operations
	adminV1Router.Methods(http.MethodPost).Path("/profiling/start").HandlerFunc(httpTraceAll(adminAPI.StartProfilingHandler)).
		Queries("profilerType", "{profilerType:.*}")
	adminV1Router.Methods(http.MethodGet).Path("/profiling/download").HandlerFunc(httpTraceAll(adminAPI.DownloadProfilingHandler))

	/// Config operations
	if enableConfigOps {
		// Get config
		adminV1Router.Methods(http.MethodGet).Path("/config").HandlerFunc(httpTraceHdrs(adminAPI.GetConfigHandler))
		// Set config
		adminV1Router.Methods(http.MethodPut).Path("/config").HandlerFunc(httpTraceHdrs(adminAPI.SetConfigHandler))
	}

	if enableIAMOps {
		// -- IAM APIs --

		// Add policy IAM
		adminV1Router.Methods(http.MethodPut).Path("/add-canned-policy").HandlerFunc(httpTraceHdrs(adminAPI.AddCannedPolicy)).Queries("name",
			"{name:.*}")

		// Add user IAM
		adminV1Router.Methods(http.MethodPut).Path("/add-user").HandlerFunc(httpTraceHdrs(adminAPI.AddUser)).Queries("accessKey", "{accessKey:.*}")
		adminV1Router.Methods(http.MethodPut).Path("/set-user-status").HandlerFunc(httpTraceHdrs(adminAPI.SetUserStatus)).
			Queries("accessKey", "{accessKey:.*}").Queries("status", "{status:.*}")

		// Info policy IAM
		adminV1Router.Methods(http.MethodGet).Path("/info-canned-policy").HandlerFunc(httpTraceHdrs(adminAPI.InfoCannedPolicy)).Queries("name", "{name:.*}")

		// Remove policy IAM
		adminV1Router.Methods(http.MethodDelete).Path("/remove-canned-policy").HandlerFunc(httpTraceHdrs(adminAPI.RemoveCannedPolicy)).Queries("name", "{name:.*}")

		// Set user or group policy
		adminV1Router.Methods(http.MethodPut).Path("/set-user-or-group-policy").
			HandlerFunc(httpTraceHdrs(adminAPI.SetPolicyForUserOrGroup)).
			Queries("policyName", "{policyName:.*}", "userOrGroup", "{userOrGroup:.*}", "isGroup", "{isGroup:true|false}")

		// Remove user IAM
		adminV1Router.Methods(http.MethodDelete).Path("/remove-user").HandlerFunc(httpTraceHdrs(adminAPI.RemoveUser)).Queries("accessKey", "{accessKey:.*}")

		// List users
		adminV1Router.Methods(http.MethodGet).Path("/list-users").HandlerFunc(httpTraceHdrs(adminAPI.ListUsers))

		// User info
		adminV1Router.Methods(http.MethodGet).Path("/user-info").HandlerFunc(httpTraceHdrs(adminAPI.GetUserInfo)).Queries("accessKey", "{accessKey:.*}")

		// Add/Remove members from group
		adminV1Router.Methods(http.MethodPut).Path("/update-group-members").HandlerFunc(httpTraceHdrs(adminAPI.UpdateGroupMembers))

		// Get Group
		adminV1Router.Methods(http.MethodGet).Path("/group").HandlerFunc(httpTraceHdrs(adminAPI.GetGroup)).Queries("group", "{group:.*}")

		// List Groups
		adminV1Router.Methods(http.MethodGet).Path("/groups").HandlerFunc(httpTraceHdrs(adminAPI.ListGroups))

		// Set Group Status
		adminV1Router.Methods(http.MethodPut).Path("/set-group-status").HandlerFunc(httpTraceHdrs(adminAPI.SetGroupStatus)).Queries("group", "{group:.*}").Queries("status", "{status:.*}")

		// List policies
		adminV1Router.Methods(http.MethodGet).Path("/list-canned-policies").HandlerFunc(httpTraceHdrs(adminAPI.ListCannedPolicies))
	}

	// -- Top APIs --
	// Top locks
	adminV1Router.Methods(http.MethodGet).Path("/top/locks").HandlerFunc(httpTraceHdrs(adminAPI.TopLocksHandler))

	// HTTP Trace
	adminV1Router.Methods(http.MethodGet).Path("/trace").HandlerFunc(adminAPI.TraceHandler)

	// Console Logs
	adminV1Router.Methods(http.MethodGet).Path("/log").HandlerFunc(httpTraceAll(adminAPI.ConsoleLogHandler))

	// -- KMS APIs --
	//
	adminV1Router.Methods(http.MethodGet).Path("/kms/key/status").HandlerFunc(httpTraceAll(adminAPI.KMSKeyStatusHandler))

	// If none of the routes match, return error.
	adminV1Router.NotFoundHandler = http.HandlerFunc(httpTraceHdrs(notFoundHandler))
	adminV1Router.MethodNotAllowedHandler = http.HandlerFunc(httpTraceAll(versionMismatchHandler))
}
<|endoftext|>


<commit_before>// Copyright 2013 The Go Circuit Project
// Use of this source code is governed by the license for
// The Go Circuit Project, found in the LICENSE file.
//
// Authors:
//   2013 Petar Maymounkov <p@gocircuit.org>

package main

import (
	"fmt"
	"encoding/json"

	"github.com/gocircuit/circuit/client"
	"github.com/gocircuit/circuit/client/docker"

	"github.com/gocircuit/circuit/github.com/codegangsta/cli"
)

// circuit peek /X1234/hola/charlie
func peek(x *cli.Context) {
	defer func() {
		if r := recover(); r != nil {
			fatalf("error, likely due to missing server or misspelled anchor: %v", r)
		}
	}()
	c := dial(x)
	args := x.Args()
	if len(args) != 1 {
		fatalf("peek needs one anchor argument")
	}
	w, _ := parseGlob(args[0])
	switch t := c.Walk(w).Get().(type) {
	case client.Server:
		buf, _ := json.MarshalIndent(t.Peek(), "", "\t")
		fmt.Println(string(buf))
	case client.Chan:
		buf, _ := json.MarshalIndent(t.Stat(), "", "\t")
		fmt.Println(string(buf))
	case client.Proc:
		buf, _ := json.MarshalIndent(t.Peek(), "", "\t")
		fmt.Println(string(buf))
	case docker.Container:
		stat, err := t.Peek()
		if err != nil {
			fatalf("%v", err)
		}
		buf, _ := json.MarshalIndent(stat, "", "\t")
		fmt.Println(string(buf))
	case client.Subscription:
		buf, _ := json.MarshalIndent(t.Peek(), "", "\t")
		fmt.Println(string(buf))
	case nil:
		buf, _ := json.MarshalIndent(nil, "", "\t")
		fmt.Println(string(buf))
	default:
		fatalf("unknown element")
	}
}

func scrb(x *cli.Context) {
	defer func() {
		if r := recover(); r != nil {
			fatalf("error, likely due to missing server or misspelled anchor: %v", r)
		}
	}()
	c := dial(x)
	args := x.Args()
	if len(args) != 1 {
		fatalf("scrub needs one anchor argument")
	}
	w, _ := parseGlob(args[0])
	c.Walk(w).Scrub()
}
<commit_msg>integrate dns element with peek and scrub commands<commit_after>// Copyright 2013 The Go Circuit Project
// Use of this source code is governed by the license for
// The Go Circuit Project, found in the LICENSE file.
//
// Authors:
//   2013 Petar Maymounkov <p@gocircuit.org>

package main

import (
	"fmt"
	"encoding/json"

	"github.com/gocircuit/circuit/client"
	"github.com/gocircuit/circuit/client/docker"

	"github.com/gocircuit/circuit/github.com/codegangsta/cli"
)

// circuit peek /X1234/hola/charlie
func peek(x *cli.Context) {
	defer func() {
		if r := recover(); r != nil {
			fatalf("error, likely due to missing server or misspelled anchor: %v", r)
		}
	}()
	c := dial(x)
	args := x.Args()
	if len(args) != 1 {
		fatalf("peek needs one anchor argument")
	}
	w, _ := parseGlob(args[0])
	switch t := c.Walk(w).Get().(type) {
	case client.Server:
		buf, _ := json.MarshalIndent(t.Peek(), "", "\t")
		fmt.Println(string(buf))
	case client.Chan:
		buf, _ := json.MarshalIndent(t.Stat(), "", "\t")
		fmt.Println(string(buf))
	case client.Proc:
		buf, _ := json.MarshalIndent(t.Peek(), "", "\t")
		fmt.Println(string(buf))
	case client.Nameserver:
		buf, _ := json.MarshalIndent(t.Peek(), "", "\t")
		fmt.Println(string(buf))
	case docker.Container:
		stat, err := t.Peek()
		if err != nil {
			fatalf("%v", err)
		}
		buf, _ := json.MarshalIndent(stat, "", "\t")
		fmt.Println(string(buf))
	case client.Subscription:
		buf, _ := json.MarshalIndent(t.Peek(), "", "\t")
		fmt.Println(string(buf))
	case nil:
		buf, _ := json.MarshalIndent(nil, "", "\t")
		fmt.Println(string(buf))
	default:
		fatalf("unknown element")
	}
}

func scrb(x *cli.Context) {
	defer func() {
		if r := recover(); r != nil {
			fatalf("error, likely due to missing server or misspelled anchor: %v", r)
		}
	}()
	c := dial(x)
	args := x.Args()
	if len(args) != 1 {
		fatalf("scrub needs one anchor argument")
	}
	w, _ := parseGlob(args[0])
	c.Walk(w).Scrub()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/exec"
	"syscall"
	"time"

	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

// Version is inserted at build using --ldflags -X
// But we don't really build that way any longer.
// So include a fallback version number that's not useless.
var Version = "0.8.0"

const socketName = "/var/run/edgectl.socket"
const logfile = "/tmp/edgectl.log"
const apiVersion = 1

var displayVersion = fmt.Sprintf("v%s (api v%d)", Version, apiVersion)

const failedToConnect = "Unable to connect to the daemon (See \"edgectl help daemon\")"

var daemonHelp = `The Edge Control Daemon is a long-lived background component that manages
connections and network state.

Launch the Edge Control Daemon:
    sudo edgectl daemon

Examine the Daemon's log output in
    ` + logfile + `
to troubleshoot problems.
`

// edgectl is the full path to the Edge Control binary
var edgectl string

func main() {
	// Figure out our executable and save it
	if executable, err := os.Executable(); err != nil {
		fmt.Fprintf(os.Stderr, "Internal error: %v", err)
		os.Exit(1)
	} else {
		edgectl = executable
	}

	rootCmd := getRootCommand(false, false)
	err := rootCmd.Execute()
	if err != nil {
		os.Exit(1)
	}
}

func getRootCommand(daemonIsRunning, runningAsDaemon bool) *cobra.Command {
	myName := "Edge Control"
	if !(daemonIsRunning || runningAsDaemon) {
		myName = "Edge Control (daemon unavailable)"
	}

	rootCmd := &cobra.Command{
		Use:          "edgectl",
		Short:        myName,
		SilenceUsage: true, // https://github.com/spf13/cobra/issues/340
	}

	// Hidden/internal commands. These are called by Edge Control itself from
	// the correct context and execute in-place immediately.

	rootCmd.AddCommand(&cobra.Command{
		Use:    "daemon-foreground",
		Short:  "Launch Edge Control Daemon in the foreground (debug)",
		Args:   cobra.ExactArgs(0),
		Hidden: true,
		RunE: func(_ *cobra.Command, _ []string) error {
			return RunAsDaemon()
		},
	})
	rootCmd.AddCommand(&cobra.Command{
		Use:       "teleproxy",
		Short:     "Impersonate Teleproxy (for internal use)",
		Args:      cobra.ExactValidArgs(1),
		ValidArgs: []string{"intercept", "bridge"},
		Hidden:    true,
		RunE: func(_ *cobra.Command, args []string) error {
			if args[0] == "intercept" {
				return RunAsTeleproxyIntercept()
			} else {
				return RunAsTeleproxyBridge()
			}
		},
	})

	// Client commands. These are never sent to the daemon.

	rootCmd.AddCommand(&cobra.Command{
		Use:   "daemon",
		Short: "Launch Edge Control Daemon in the background (sudo)",
		Long:  daemonHelp,
		Args:  cobra.ExactArgs(0),
		RunE:  launchDaemon,
	})
	rootCmd.AddCommand(&cobra.Command{
		Use:   "login",
		Short: "Access the Ambassador Edge Stack admin UI",
		Args:  cobra.MaximumNArgs(1),
		RunE:  aesLogin,
	})

	// Daemon commands. These should be forwarded to the daemon.

	nilDaemon := &Daemon{}
	daemonCmd := nilDaemon.getRootCommand(nil, nil, nil)
	walkSubcommands(daemonCmd)
	rootCmd.AddCommand(daemonCmd.Commands()...)
	rootCmd.PersistentFlags().AddFlagSet(daemonCmd.PersistentFlags())

	return rootCmd
}

func walkSubcommands(cmd *cobra.Command) {
	for _, subCmd := range cmd.Commands() {
		walkSubcommands(subCmd)
	}
	if cmd.RunE != nil {
		cmd.RunE = forwardToDaemon
	}
}

func forwardToDaemon(cmd *cobra.Command, _ []string) error {
	err := mainViaDaemon()
	if err != nil {
		// The version command is special because it must emit the client
		// version if the daemon is unavailable.
		if cmd.Use == "version" {
			fmt.Println("Client", displayVersion)
		}
		fmt.Println(failedToConnect)
	}
	return err
}

func launchDaemon(ccmd *cobra.Command, _ []string) error {
	if os.Geteuid() != 0 {
		fmt.Println("Edge Control Daemon must be launched as root.")
		fmt.Printf("\n  sudo %s\n\n", ccmd.CommandPath())
		return errors.New("root privileges required")
	}
	fmt.Println("Launching Edge Control Daemon", displayVersion)

	cmd := exec.Command(edgectl, "daemon-foreground")
	cmd.Env = os.Environ()
	cmd.Stdin = nil
	cmd.Stdout = nil
	cmd.Stderr = nil
	cmd.ExtraFiles = nil
	cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
	err := cmd.Start()
	if err != nil {
		return errors.Wrap(err, "failed to launch the server")
	}

	success := false
	for count := 0; count < 40; count++ {
		if isServerRunning() {
			success = true
			break
		}
		if count == 4 {
			fmt.Println("Waiting for daemon to start...")
		}
		time.Sleep(250 * time.Millisecond)
	}
	if !success {
		fmt.Println("Server did not come up!")
		fmt.Printf("Take a look at %s for more information.\n", logfile)
		return errors.New("launch failed")
	}
	return nil
}
<commit_msg>Fix daemon check for help<commit_after>package main

import (
	"fmt"
	"os"
	"os/exec"
	"syscall"
	"time"

	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

// Version is inserted at build using --ldflags -X
// But we don't really build that way any longer.
// So include a fallback version number that's not useless.
var Version = "0.8.0"

const socketName = "/var/run/edgectl.socket"
const logfile = "/tmp/edgectl.log"
const apiVersion = 1

var displayVersion = fmt.Sprintf("v%s (api v%d)", Version, apiVersion)

const failedToConnect = "Unable to connect to the daemon (See \"edgectl help daemon\")"

var daemonHelp = `The Edge Control Daemon is a long-lived background component that manages
connections and network state.

Launch the Edge Control Daemon:
    sudo edgectl daemon

Examine the Daemon's log output in
    ` + logfile + `
to troubleshoot problems.
`

// edgectl is the full path to the Edge Control binary
var edgectl string

func main() {
	// Figure out our executable and save it
	if executable, err := os.Executable(); err != nil {
		fmt.Fprintf(os.Stderr, "Internal error: %v", err)
		os.Exit(1)
	} else {
		edgectl = executable
	}

	rootCmd := getRootCommand()
	err := rootCmd.Execute()
	if err != nil {
		os.Exit(1)
	}
}

func getRootCommand() *cobra.Command {
	myName := "Edge Control"
	if !isServerRunning() {
		myName = "Edge Control (daemon unavailable)"
	}

	rootCmd := &cobra.Command{
		Use:          "edgectl",
		Short:        myName,
		SilenceUsage: true, // https://github.com/spf13/cobra/issues/340
	}

	// Hidden/internal commands. These are called by Edge Control itself from
	// the correct context and execute in-place immediately.

	rootCmd.AddCommand(&cobra.Command{
		Use:    "daemon-foreground",
		Short:  "Launch Edge Control Daemon in the foreground (debug)",
		Args:   cobra.ExactArgs(0),
		Hidden: true,
		RunE: func(_ *cobra.Command, _ []string) error {
			return RunAsDaemon()
		},
	})
	rootCmd.AddCommand(&cobra.Command{
		Use:       "teleproxy",
		Short:     "Impersonate Teleproxy (for internal use)",
		Args:      cobra.ExactValidArgs(1),
		ValidArgs: []string{"intercept", "bridge"},
		Hidden:    true,
		RunE: func(_ *cobra.Command, args []string) error {
			if args[0] == "intercept" {
				return RunAsTeleproxyIntercept()
			} else {
				return RunAsTeleproxyBridge()
			}
		},
	})

	// Client commands. These are never sent to the daemon.

	rootCmd.AddCommand(&cobra.Command{
		Use:   "daemon",
		Short: "Launch Edge Control Daemon in the background (sudo)",
		Long:  daemonHelp,
		Args:  cobra.ExactArgs(0),
		RunE:  launchDaemon,
	})
	rootCmd.AddCommand(&cobra.Command{
		Use:   "login",
		Short: "Access the Ambassador Edge Stack admin UI",
		Args:  cobra.MaximumNArgs(1),
		RunE:  aesLogin,
	})

	// Daemon commands. These should be forwarded to the daemon.

	nilDaemon := &Daemon{}
	daemonCmd := nilDaemon.getRootCommand(nil, nil, nil)
	walkSubcommands(daemonCmd)
	rootCmd.AddCommand(daemonCmd.Commands()...)
	rootCmd.PersistentFlags().AddFlagSet(daemonCmd.PersistentFlags())

	return rootCmd
}

func walkSubcommands(cmd *cobra.Command) {
	for _, subCmd := range cmd.Commands() {
		walkSubcommands(subCmd)
	}
	if cmd.RunE != nil {
		cmd.RunE = forwardToDaemon
	}
}

func forwardToDaemon(cmd *cobra.Command, _ []string) error {
	err := mainViaDaemon()
	if err != nil {
		// The version command is special because it must emit the client
		// version if the daemon is unavailable.
		if cmd.Use == "version" {
			fmt.Println("Client", displayVersion)
		}
		fmt.Println(failedToConnect)
	}
	return err
}

func launchDaemon(ccmd *cobra.Command, _ []string) error {
	if os.Geteuid() != 0 {
		fmt.Println("Edge Control Daemon must be launched as root.")
		fmt.Printf("\n  sudo %s\n\n", ccmd.CommandPath())
		return errors.New("root privileges required")
	}
	fmt.Println("Launching Edge Control Daemon", displayVersion)

	cmd := exec.Command(edgectl, "daemon-foreground")
	cmd.Env = os.Environ()
	cmd.Stdin = nil
	cmd.Stdout = nil
	cmd.Stderr = nil
	cmd.ExtraFiles = nil
	cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
	err := cmd.Start()
	if err != nil {
		return errors.Wrap(err, "failed to launch the server")
	}

	success := false
	for count := 0; count < 40; count++ {
		if isServerRunning() {
			success = true
			break
		}
		if count == 4 {
			fmt.Println("Waiting for daemon to start...")
		}
		time.Sleep(250 * time.Millisecond)
	}
	if !success {
		fmt.Println("Server did not come up!")
		fmt.Printf("Take a look at %s for more information.\n", logfile)
		return errors.New("launch failed")
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright The Helm Authors.

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

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

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

package main

import (
	"fmt"
	"io"
	"text/template"

	"github.com/spf13/cobra"

	"helm.sh/helm/v3/cmd/helm/require"
	"helm.sh/helm/v3/internal/version"
)

const versionDesc = `
Show the version for Helm.

This will print a representation the version of Helm.
The output will look something like this:

version.BuildInfo{Version:"v2.0.0", GitCommit:"ff52399e51bb880526e9cd0ed8386f6433b74da1", GitTreeState:"clean"}

- Version is the semantic version of the release.
- GitCommit is the SHA for the commit that this version was built from.
- GitTreeState is "clean" if there are no local code changes when this binary was
  built, and "dirty" if the binary was built from locally modified code.
`

type versionOptions struct {
	short    bool
	template string
}

func newVersionCmd(out io.Writer) *cobra.Command {
	o := &versionOptions{}

	cmd := &cobra.Command{
		Use:   "version",
		Short: "print the client version information",
		Long:  versionDesc,
		Args:  require.NoArgs,
		RunE: func(cmd *cobra.Command, args []string) error {
			return o.run(out)
		},
	}
	f := cmd.Flags()
	f.BoolVar(&o.short, "short", false, "print the version number")
	f.StringVar(&o.template, "template", "", "template for version string format")
	f.BoolP("client", "c", true, "display client version information")
	f.MarkHidden("client")

	return cmd
}

func (o *versionOptions) run(out io.Writer) error {
	if o.template != "" {
		tt, err := template.New("_").Parse(o.template)
		if err != nil {
			return err
		}
		return tt.Execute(out, version.Get())
	}
	fmt.Fprintln(out, formatVersion(o.short))
	return nil
}

func formatVersion(short bool) string {
	v := version.Get()
	if short {
		if len(v.GitCommit) >= 7 {
			return fmt.Sprintf("%s+g%s", v.Version, v.GitCommit[:7])
		}
		return version.GetVersion()
	}
	return fmt.Sprintf("%#v", v)
}
<commit_msg>Adding template docs to the version command<commit_after>/*
Copyright The Helm Authors.

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

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

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

package main

import (
	"fmt"
	"io"
	"text/template"

	"github.com/spf13/cobra"

	"helm.sh/helm/v3/cmd/helm/require"
	"helm.sh/helm/v3/internal/version"
)

const versionDesc = `
Show the version for Helm.

This will print a representation the version of Helm.
The output will look something like this:

version.BuildInfo{Version:"v2.0.0", GitCommit:"ff52399e51bb880526e9cd0ed8386f6433b74da1", GitTreeState:"clean"}

- Version is the semantic version of the release.
- GitCommit is the SHA for the commit that this version was built from.
- GitTreeState is "clean" if there are no local code changes when this binary was
  built, and "dirty" if the binary was built from locally modified code.

When using the --template flag the following properties are available to use in
the template:

- .Version contains the semantic version of Helm
- .GitCommit is the git commit
- .GitTreeState is the state of the git tree when Helm was built
- .GoVersion contains the version of Go that Helm was compiled with
`

type versionOptions struct {
	short    bool
	template string
}

func newVersionCmd(out io.Writer) *cobra.Command {
	o := &versionOptions{}

	cmd := &cobra.Command{
		Use:   "version",
		Short: "print the client version information",
		Long:  versionDesc,
		Args:  require.NoArgs,
		RunE: func(cmd *cobra.Command, args []string) error {
			return o.run(out)
		},
	}
	f := cmd.Flags()
	f.BoolVar(&o.short, "short", false, "print the version number")
	f.StringVar(&o.template, "template", "", "template for version string format")
	f.BoolP("client", "c", true, "display client version information")
	f.MarkHidden("client")

	return cmd
}

func (o *versionOptions) run(out io.Writer) error {
	if o.template != "" {
		tt, err := template.New("_").Parse(o.template)
		if err != nil {
			return err
		}
		return tt.Execute(out, version.Get())
	}
	fmt.Fprintln(out, formatVersion(o.short))
	return nil
}

func formatVersion(short bool) string {
	v := version.Get()
	if short {
		if len(v.GitCommit) >= 7 {
			return fmt.Sprintf("%s+g%s", v.Version, v.GitCommit[:7])
		}
		return version.GetVersion()
	}
	return fmt.Sprintf("%#v", v)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/PuerkitoBio/juggler"
	"github.com/gorilla/websocket"
)

var (
	portFlag      = flag.Int("port", 9000, "port to listen on")
	readLimitFlag = flag.Int("read-limit", 4096, "read message size limit")
	readTOFlag    = flag.Duration("read-timeout", 10*time.Second, "read deadline duration")
	writeTOFlag   = flag.Duration("write-timeout", 10*time.Second, "write deadline duration")
)

func main() {
	flag.Parse()

	upg := &websocket.Upgrader{Subprotocols: juggler.Subprotocols}
	srv := &juggler.Server{
		ReadLimit:    int64(*readLimitFlag),
		ReadTimeout:  *readTOFlag,
		WriteTimeout: *writeTOFlag,
		ConnHandler:  juggler.ConnHandlerFunc(juggler.LogConn),
		ReadHandler:  juggler.MsgHandlerFunc(juggler.LogMsg),
	}
	http.Handle("/ws", juggler.Upgrade(upg, srv))

	log.Printf("juggler: listening on port %d", *portFlag)
	if err := http.ListenAndServe(fmt.Sprintf(":%d", *portFlag), nil); err != nil {
		log.Fatalf("juggler: ListenAndServe failed: %v", err)
	}
}
<commit_msg>juggler/cmd/juggler: update import path<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/PuerkitoBio/exp/juggler"
	"github.com/gorilla/websocket"
)

var (
	portFlag      = flag.Int("port", 9000, "port to listen on")
	readLimitFlag = flag.Int("read-limit", 4096, "read message size limit")
	readTOFlag    = flag.Duration("read-timeout", 10*time.Second, "read deadline duration")
	writeTOFlag   = flag.Duration("write-timeout", 10*time.Second, "write deadline duration")
)

func main() {
	flag.Parse()

	upg := &websocket.Upgrader{Subprotocols: juggler.Subprotocols}
	srv := &juggler.Server{
		ReadLimit:    int64(*readLimitFlag),
		ReadTimeout:  *readTOFlag,
		WriteTimeout: *writeTOFlag,
		ConnHandler:  juggler.ConnHandlerFunc(juggler.LogConn),
		ReadHandler:  juggler.MsgHandlerFunc(juggler.LogMsg),
	}
	http.Handle("/ws", juggler.Upgrade(upg, srv))

	log.Printf("juggler: listening on port %d", *portFlag)
	if err := http.ListenAndServe(fmt.Sprintf(":%d", *portFlag), nil); err != nil {
		log.Fatalf("juggler: ListenAndServe failed: %v", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"code.google.com/p/go.net/proxy"
	"flag"
	"fmt"
	"github.com/calmh/mole/ansi"
	"github.com/calmh/mole/conf"
	"io/ioutil"
	"os"
	"strings"
	"time"
)

func init() {
	commands["dig"] = command{commandDig, msgDigShort}
}

func commandDig(args []string) error {
	fs := flag.NewFlagSet("dig", flag.ExitOnError)
	local := fs.Bool("l", false, "Local file, not remote tunnel definition")
	qualify := fs.Bool("q", false, "Use <host>.<tunnel> for host aliases instead of just <host>")
	fs.Usage = usageFor(fs, msgDigUsage)
	fs.Parse(args)
	args = fs.Args()

	if len(args) != 1 {
		fs.Usage()
		os.Exit(3)
	}

	// Fail early in case we don't have root since it's always required on
	// platforms where it matters
	requireRoot("dig")

	var err error

	cl := NewClient(serverAddress(), moleIni.Get("server", "fingerprint"))
	_, err = authenticated(cl, func() (interface{}, error) { return cl.Ping() })
	fatalErr(err)

	var tun string
	if *local {
		fd, err := os.Open(args[0])
		fatalErr(err)
		bs, err := ioutil.ReadAll(fd)
		fatalErr(err)
		tun, err = cl.Deobfuscate(string(bs))
		fatalErr(err)
	} else {
		tun, err = cl.Get(args[0])
		fatalErr(err)
	}

	tun, err = cl.Deobfuscate(tun)
	fatalErr(err)
	cfg, err := conf.Load(bytes.NewBufferString(tun))
	fatalErr(err)

	if cfg == nil {
		return fmt.Errorf("no tunnel loaded")
	}

	var addrs []string
	if remapIntfs {
		cfg.Remap()
	} else {
		addrs = missingAddresses(cfg)
		if len(addrs) > 0 {
			addAddresses(addrs)
		}
	}

	infoln(sshPathStr(cfg.General.Main, cfg), "...")

	var vpn VPN
	if cfg.Vpnc != nil {
		vpn, err = startVpn("vpnc", cfg)
		fatalErr(err)
	} else if cfg.OpenConnect != nil {
		vpn, err = startVpn("openconnect", cfg)
		fatalErr(err)
	}

	var dialer Dialer = proxy.Direct
	if mh := cfg.General.Main; mh != "" {
		sshConn, err := sshHost(mh, cfg)
		fatalErr(err)
		dialer = sshConn

		// A REALY dirty keepalive mechanism.
		sess, err := sshConn.NewSession()
		fatalErr(err)
		stdout, err := sess.StdoutPipe()
		fatalErr(err)
		stderr, err := sess.StderrPipe()
		fatalErr(err)
		stdin, err := sess.StdinPipe()
		fatalErr(err)
		err = sess.Shell()
		fatalErr(err)

		go func() {
			bs := make([]byte, 1024)
			for {
				debugln("shell read stdout")
				_, err := stdout.Read(bs)
				if err != nil {
					warnln("keepalive stdout", err)
					return
				}
			}
		}()

		go func() {
			bs := make([]byte, 1024)
			for {
				debugln("shell read stderr")
				_, err := stderr.Read(bs)
				if err != nil {
					warnln("keepalive stderr", err)
					return
				}
			}
		}()

		go func() {
			for {
				time.Sleep(30 * time.Second)
				debugln("shell write")
				_, err := stdin.Write([]byte("\n"))
				if err != nil {
					warnln("keepalive stdin", err)
					return
				}
			}
		}()
	}

	fwdChan := startForwarder(dialer)
	sendForwards(fwdChan, cfg)

	setupHostsFile(args[0], cfg, *qualify)

	shell(fwdChan, cfg, dialer)

	restoreHostsFile(args[0], *qualify)

	if vpn != nil {
		vpn.Stop()
	}

	if !remapIntfs {
		addrs = extraneousAddresses(cfg)
		if len(addrs) > 0 {
			removeAddresses(addrs)
		}
	}

	okln("Done")
	printTotalStats()

	return nil
}

func sendForwards(fwdChan chan<- conf.ForwardLine, cfg *conf.Config) {
	for _, fwd := range cfg.Forwards {
		infoln(ansi.Bold(ansi.Cyan(fwd.Name)))
		if fwd.Comment != "" {
			lines := strings.Split(fwd.Comment, "\\n") // Yes, literal backslash-n
			for i := range lines {
				infoln(ansi.Cyan("  # " + lines[i]))
			}
		}
		for _, line := range fwd.Lines {
			infoln("  " + line.String())
			fwdChan <- line
		}
	}
}

func sshPathStr(hostname string, cfg *conf.Config) string {
	var this string
	if hostID, ok := cfg.HostsMap[hostname]; ok {
		host := cfg.Hosts[hostID]
		this = fmt.Sprintf("ssh://%s@%s", host.User, host.Name)

		if host.Via != "" {
			this = sshPathStr(host.Via, cfg) + " -> " + this
		}

		if host.SOCKS != "" {
			this = "SOCKS://" + host.SOCKS + " -> " + this
		}
	}

	if hostname == cfg.General.Main || hostname == "" {
		if cfg.Vpnc != nil {
			vpnc := fmt.Sprintf("vpnc://%s", cfg.Vpnc["IPSec_gateway"])
			if this == "" {
				return vpnc
			} else {
				this = vpnc + " -> " + this
			}
		} else if cfg.OpenConnect != nil {
			opnc := fmt.Sprintf("openconnect://%s", cfg.OpenConnect["server"])
			if this == "" {
				return opnc
			} else {
				this = opnc + " -> " + this
			}
		}
	}

	return this
}
<commit_msg>Clean up keepalives somewhat<commit_after>package main

import (
	"bytes"
	"code.google.com/p/go.net/proxy"
	"flag"
	"fmt"
	"github.com/calmh/mole/ansi"
	"github.com/calmh/mole/conf"
	"io/ioutil"
	"os"
	"strings"
	"time"
)

func init() {
	commands["dig"] = command{commandDig, msgDigShort}
}

func commandDig(args []string) error {
	fs := flag.NewFlagSet("dig", flag.ExitOnError)
	local := fs.Bool("l", false, "Local file, not remote tunnel definition")
	qualify := fs.Bool("q", false, "Use <host>.<tunnel> for host aliases instead of just <host>")
	fs.Usage = usageFor(fs, msgDigUsage)
	fs.Parse(args)
	args = fs.Args()

	if len(args) != 1 {
		fs.Usage()
		os.Exit(3)
	}

	// Fail early in case we don't have root since it's always required on
	// platforms where it matters
	requireRoot("dig")

	var err error

	cl := NewClient(serverAddress(), moleIni.Get("server", "fingerprint"))
	_, err = authenticated(cl, func() (interface{}, error) { return cl.Ping() })
	fatalErr(err)

	var tun string
	if *local {
		fd, err := os.Open(args[0])
		fatalErr(err)
		bs, err := ioutil.ReadAll(fd)
		fatalErr(err)
		tun, err = cl.Deobfuscate(string(bs))
		fatalErr(err)
	} else {
		tun, err = cl.Get(args[0])
		fatalErr(err)
	}

	tun, err = cl.Deobfuscate(tun)
	fatalErr(err)
	cfg, err := conf.Load(bytes.NewBufferString(tun))
	fatalErr(err)

	if cfg == nil {
		return fmt.Errorf("no tunnel loaded")
	}

	var addrs []string
	if remapIntfs {
		cfg.Remap()
	} else {
		addrs = missingAddresses(cfg)
		if len(addrs) > 0 {
			addAddresses(addrs)
		}
	}

	infoln(sshPathStr(cfg.General.Main, cfg), "...")

	var vpn VPN
	if cfg.Vpnc != nil {
		vpn, err = startVpn("vpnc", cfg)
		fatalErr(err)
	} else if cfg.OpenConnect != nil {
		vpn, err = startVpn("openconnect", cfg)
		fatalErr(err)
	}

	var dialer Dialer = proxy.Direct
	if mh := cfg.General.Main; mh != "" {
		sshConn, err := sshHost(mh, cfg)
		fatalErr(err)
		dialer = sshConn

		go func() {
			// Periodically connect to a forward to provide a primitive keepalive mechanism.
			for _, fwd := range cfg.Forwards {
				for _, line := range fwd.Lines {
					debugln("keepalive dial", line.DstString(0))
					conn, err := dialer.Dial("tcp", line.DstString(0))
					if err != nil {
						debugln("keepalive dial", err)
					}
					if conn != nil {
						conn.Close()
					}
					time.Sleep(30 * time.Second)
				}
			}
		}()
	}

	fwdChan := startForwarder(dialer)
	sendForwards(fwdChan, cfg)

	setupHostsFile(args[0], cfg, *qualify)

	shell(fwdChan, cfg, dialer)

	restoreHostsFile(args[0], *qualify)

	if vpn != nil {
		vpn.Stop()
	}

	if !remapIntfs {
		addrs = extraneousAddresses(cfg)
		if len(addrs) > 0 {
			removeAddresses(addrs)
		}
	}

	okln("Done")
	printTotalStats()

	return nil
}

func sendForwards(fwdChan chan<- conf.ForwardLine, cfg *conf.Config) {
	for _, fwd := range cfg.Forwards {
		infoln(ansi.Bold(ansi.Cyan(fwd.Name)))
		if fwd.Comment != "" {
			lines := strings.Split(fwd.Comment, "\\n") // Yes, literal backslash-n
			for i := range lines {
				infoln(ansi.Cyan("  # " + lines[i]))
			}
		}
		for _, line := range fwd.Lines {
			infoln("  " + line.String())
			fwdChan <- line
		}
	}
}

func sshPathStr(hostname string, cfg *conf.Config) string {
	var this string
	if hostID, ok := cfg.HostsMap[hostname]; ok {
		host := cfg.Hosts[hostID]
		this = fmt.Sprintf("ssh://%s@%s", host.User, host.Name)

		if host.Via != "" {
			this = sshPathStr(host.Via, cfg) + " -> " + this
		}

		if host.SOCKS != "" {
			this = "SOCKS://" + host.SOCKS + " -> " + this
		}
	}

	if hostname == cfg.General.Main || hostname == "" {
		if cfg.Vpnc != nil {
			vpnc := fmt.Sprintf("vpnc://%s", cfg.Vpnc["IPSec_gateway"])
			if this == "" {
				return vpnc
			} else {
				this = vpnc + " -> " + this
			}
		} else if cfg.OpenConnect != nil {
			opnc := fmt.Sprintf("openconnect://%s", cfg.OpenConnect["server"])
			if this == "" {
				return opnc
			} else {
				this = opnc + " -> " + this
			}
		}
	}

	return this
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"fmt"

	"github.com/pkg/errors"

	"github.com/spf13/cobra"

	"github.com/fatih/color"

	"github.com/havoc-io/mutagen/cmd"
	sessionpkg "github.com/havoc-io/mutagen/pkg/session"
	sessionsvcpkg "github.com/havoc-io/mutagen/pkg/session/service"
	"github.com/havoc-io/mutagen/pkg/sync"
)

func formatPath(path string) string {
	if path == "" {
		return "(root)"
	}
	return path
}

func formatConnectionStatus(connected bool) string {
	if connected {
		return "Connected"
	}
	return "Disconnected"
}

func printEndpointStatus(state *sessionpkg.State, alpha bool) {
	// Print the header for this endpoint.
	header := "Alpha:"
	if !alpha {
		header = "Beta:"
	}
	fmt.Println(header)

	// Print URL.
	url := state.Session.Alpha
	if !alpha {
		url = state.Session.Beta
	}
	fmt.Println("\tURL:", url.Format())

	// Print status.
	connected := state.AlphaConnected
	if !alpha {
		connected = state.BetaConnected
	}
	fmt.Println("\tStatus:", formatConnectionStatus(connected))

	// Print problems, if any.
	problems := state.AlphaProblems
	if !alpha {
		problems = state.BetaProblems
	}
	if len(problems) > 0 {
		color.Red("\tProblems:\n")
		for _, p := range problems {
			color.Red("\t\t%s: %v\n", formatPath(p.Path), p.Error)
		}
	}
}

func printSessionStatus(state *sessionpkg.State) {
	// Print status.
	statusString := state.Status.Description()
	if state.Session.Paused {
		statusString = color.YellowString("[Paused]")
	}
	fmt.Println("Status:", statusString)

	// Print the last error, if any.
	if state.LastError != "" {
		color.Red("Last error: %s\n", state.LastError)
	}
}

func formatEntryKind(entry *sync.Entry) string {
	if entry == nil {
		return "<non-existent>"
	} else if entry.Kind == sync.EntryKind_Directory {
		return "Directory"
	} else if entry.Kind == sync.EntryKind_File {
		if entry.Executable {
			return fmt.Sprintf("Executable File (%x)", entry.Digest)
		}
		return fmt.Sprintf("File (%x)", entry.Digest)
	} else if entry.Kind == sync.EntryKind_Symlink {
		return fmt.Sprintf("Symlink (%s)", entry.Target)
	} else {
		return "<unknown>"
	}
}

func printConflicts(conflicts []*sync.Conflict) {
	// Print the header.
	color.Red("Conflicts:\n")

	// Print conflicts.
	for i, c := range conflicts {
		// Print the alpha changes.
		for _, a := range c.AlphaChanges {
			color.Red(
				"\t(α) %s (%s -> %s)\n",
				formatPath(a.Path),
				formatEntryKind(a.Old),
				formatEntryKind(a.New),
			)
		}

		// Print the beta changes.
		for _, b := range c.BetaChanges {
			color.Red(
				"\t(β) %s (%s -> %s)\n",
				formatPath(b.Path),
				formatEntryKind(b.Old),
				formatEntryKind(b.New),
			)
		}

		// If we're not on the last conflict, print a newline.
		if i < len(conflicts)-1 {
			fmt.Println()
		}
	}
}

func listMain(command *cobra.Command, arguments []string) error {
	// Connect to the daemon and defer closure of the connection.
	daemonConnection, err := createDaemonClientConnection()
	if err != nil {
		return errors.Wrap(err, "unable to connect to daemon")
	}
	defer daemonConnection.Close()

	// Create a session service client.
	sessionService := sessionsvcpkg.NewSessionClient(daemonConnection)

	// Invoke list.
	request := &sessionsvcpkg.ListRequest{
		Specifications: arguments,
	}
	response, err := sessionService.List(context.Background(), request)
	if err != nil {
		return errors.Wrap(peelAwayRPCErrorLayer(err), "list failed")
	}

	// Validate the list response contents.
	for _, s := range response.SessionStates {
		if err = s.EnsureValid(); err != nil {
			return errors.Wrap(err, "invalid session state detected in response")
		}
	}

	// Loop through and print sessions.
	for _, state := range response.SessionStates {
		fmt.Println(delimiterLine)
		printSession(state, listConfiguration.long)
		printEndpointStatus(state, true)
		printEndpointStatus(state, false)
		printSessionStatus(state)
		if len(state.Conflicts) > 0 {
			printConflicts(state.Conflicts)
		}
	}
	fmt.Println(delimiterLine)

	// Success.
	return nil
}

var listCommand = &cobra.Command{
	Use:   "list [<session>...]",
	Short: "Lists existing synchronization sessions and their statuses",
	Run:   cmd.Mainify(listMain),
}

var listConfiguration struct {
	help bool
	long bool
}

func init() {
	// Bind flags to configuration. We manually add help to override the default
	// message, but Cobra still implements it automatically.
	flags := listCommand.Flags()
	flags.BoolVarP(&listConfiguration.help, "help", "h", false, "Show help information")
	flags.BoolVarP(&listConfiguration.long, "long", "l", false, "Show detailed session information")
}
<commit_msg>Modified list to avoid printing delimiter if no sessions exist.<commit_after>package main

import (
	"context"
	"fmt"

	"github.com/pkg/errors"

	"github.com/spf13/cobra"

	"github.com/fatih/color"

	"github.com/havoc-io/mutagen/cmd"
	sessionpkg "github.com/havoc-io/mutagen/pkg/session"
	sessionsvcpkg "github.com/havoc-io/mutagen/pkg/session/service"
	"github.com/havoc-io/mutagen/pkg/sync"
)

func formatPath(path string) string {
	if path == "" {
		return "(root)"
	}
	return path
}

func formatConnectionStatus(connected bool) string {
	if connected {
		return "Connected"
	}
	return "Disconnected"
}

func printEndpointStatus(state *sessionpkg.State, alpha bool) {
	// Print the header for this endpoint.
	header := "Alpha:"
	if !alpha {
		header = "Beta:"
	}
	fmt.Println(header)

	// Print URL.
	url := state.Session.Alpha
	if !alpha {
		url = state.Session.Beta
	}
	fmt.Println("\tURL:", url.Format())

	// Print status.
	connected := state.AlphaConnected
	if !alpha {
		connected = state.BetaConnected
	}
	fmt.Println("\tStatus:", formatConnectionStatus(connected))

	// Print problems, if any.
	problems := state.AlphaProblems
	if !alpha {
		problems = state.BetaProblems
	}
	if len(problems) > 0 {
		color.Red("\tProblems:\n")
		for _, p := range problems {
			color.Red("\t\t%s: %v\n", formatPath(p.Path), p.Error)
		}
	}
}

func printSessionStatus(state *sessionpkg.State) {
	// Print status.
	statusString := state.Status.Description()
	if state.Session.Paused {
		statusString = color.YellowString("[Paused]")
	}
	fmt.Println("Status:", statusString)

	// Print the last error, if any.
	if state.LastError != "" {
		color.Red("Last error: %s\n", state.LastError)
	}
}

func formatEntryKind(entry *sync.Entry) string {
	if entry == nil {
		return "<non-existent>"
	} else if entry.Kind == sync.EntryKind_Directory {
		return "Directory"
	} else if entry.Kind == sync.EntryKind_File {
		if entry.Executable {
			return fmt.Sprintf("Executable File (%x)", entry.Digest)
		}
		return fmt.Sprintf("File (%x)", entry.Digest)
	} else if entry.Kind == sync.EntryKind_Symlink {
		return fmt.Sprintf("Symlink (%s)", entry.Target)
	} else {
		return "<unknown>"
	}
}

func printConflicts(conflicts []*sync.Conflict) {
	// Print the header.
	color.Red("Conflicts:\n")

	// Print conflicts.
	for i, c := range conflicts {
		// Print the alpha changes.
		for _, a := range c.AlphaChanges {
			color.Red(
				"\t(α) %s (%s -> %s)\n",
				formatPath(a.Path),
				formatEntryKind(a.Old),
				formatEntryKind(a.New),
			)
		}

		// Print the beta changes.
		for _, b := range c.BetaChanges {
			color.Red(
				"\t(β) %s (%s -> %s)\n",
				formatPath(b.Path),
				formatEntryKind(b.Old),
				formatEntryKind(b.New),
			)
		}

		// If we're not on the last conflict, print a newline.
		if i < len(conflicts)-1 {
			fmt.Println()
		}
	}
}

func listMain(command *cobra.Command, arguments []string) error {
	// Connect to the daemon and defer closure of the connection.
	daemonConnection, err := createDaemonClientConnection()
	if err != nil {
		return errors.Wrap(err, "unable to connect to daemon")
	}
	defer daemonConnection.Close()

	// Create a session service client.
	sessionService := sessionsvcpkg.NewSessionClient(daemonConnection)

	// Invoke list.
	request := &sessionsvcpkg.ListRequest{
		Specifications: arguments,
	}
	response, err := sessionService.List(context.Background(), request)
	if err != nil {
		return errors.Wrap(peelAwayRPCErrorLayer(err), "list failed")
	}

	// Validate the list response contents.
	for _, s := range response.SessionStates {
		if err = s.EnsureValid(); err != nil {
			return errors.Wrap(err, "invalid session state detected in response")
		}
	}

	// Loop through and print sessions.
	for _, state := range response.SessionStates {
		fmt.Println(delimiterLine)
		printSession(state, listConfiguration.long)
		printEndpointStatus(state, true)
		printEndpointStatus(state, false)
		printSessionStatus(state)
		if len(state.Conflicts) > 0 {
			printConflicts(state.Conflicts)
		}
	}

	// Print a final delimiter line if there were any sessions.
	if len(response.SessionStates) > 0 {
		fmt.Println(delimiterLine)
	}

	// Success.
	return nil
}

var listCommand = &cobra.Command{
	Use:   "list [<session>...]",
	Short: "Lists existing synchronization sessions and their statuses",
	Run:   cmd.Mainify(listMain),
}

var listConfiguration struct {
	help bool
	long bool
}

func init() {
	// Bind flags to configuration. We manually add help to override the default
	// message, but Cobra still implements it automatically.
	flags := listCommand.Flags()
	flags.BoolVarP(&listConfiguration.help, "help", "h", false, "Show help information")
	flags.BoolVarP(&listConfiguration.long, "long", "l", false, "Show detailed session information")
}
<|endoftext|>


<commit_before>package main

import (
	"os"

	"github.com/spf13/cobra"

	"github.com/mutagen-io/mutagen/cmd"
	"github.com/mutagen-io/mutagen/cmd/mutagen/daemon"
	"github.com/mutagen-io/mutagen/cmd/mutagen/forward"
	"github.com/mutagen-io/mutagen/cmd/mutagen/project"
	"github.com/mutagen-io/mutagen/cmd/mutagen/sync"
	"github.com/mutagen-io/mutagen/pkg/prompt"
)

func rootMain(command *cobra.Command, arguments []string) error {
	// If no commands were given, then print help information and bail. We don't
	// have to worry about warning about arguments being present here (which
	// would be incorrect usage) because arguments can't even reach this point
	// (they will be mistaken for subcommands and a error will be displayed).
	command.Help()

	// Success.
	return nil
}

var rootCommand = &cobra.Command{
	Use:          "mutagen",
	Short:        "Mutagen is a remote development tool built on high-performance synchronization",
	RunE:         rootMain,
	SilenceUsage: true,
}

var rootConfiguration struct {
	// help indicates whether or not help information should be shown for the
	// command.
	help bool
}

func init() {
	// Disable alphabetical sorting of commands in help output. This is a global
	// setting that affects all Cobra command instances.
	cobra.EnableCommandSorting = false

	// Grab a handle for the command line flags.
	flags := rootCommand.Flags()

	// Disable alphabetical sorting of flags in help output.
	flags.SortFlags = false

	// Manually add a help flag to override the default message. Cobra will
	// still implement its logic automatically.
	flags.BoolVarP(&rootConfiguration.help, "help", "h", false, "Show help information")

	// Disable Cobra's use of mousetrap. This breaks daemon registration on
	// Windows because it tries to enforce that the CLI only be launched from
	// a console, which it's not when running automatically.
	cobra.MousetrapHelpText = ""

	// Register commands.
	// HACK: Add the sync commands as direct subcommands of the root command for
	// temporary backward compatibility.
	commands := []*cobra.Command{
		forward.RootCommand,
		sync.RootCommand,
		project.RootCommand,
		daemon.RootCommand,
		versionCommand,
		legalCommand,
		generateCommand,
	}
	commands = append(commands, sync.Commands...)
	rootCommand.AddCommand(commands...)

	// HACK: Register the sync subcommands with the sync command after
	// registering them with the root command so that they have the correct
	// parent command and thus the correct help output.
	sync.RootCommand.AddCommand(sync.Commands...)
}

func main() {
	// Check if a prompting environment is set. If so, treat this as a prompt
	// request. Prompting is sort of a special pseudo-command that's indicated
	// by the presence of an environment variable, and hence it has to be
	// handled in a bit of a special manner.
	if _, ok := os.LookupEnv(prompt.PrompterEnvironmentVariable); ok {
		if err := promptMain(os.Args[1:]); err != nil {
			cmd.Fatal(err)
		}
		return
	}

	// Handle terminal compatibility issues. If this call returns, it means that
	// we should proceed normally.
	cmd.HandleTerminalCompatibility()

	// HACK: Modify the root command's help function to hide sync commands.
	defaultHelpFunction := rootCommand.HelpFunc()
	rootCommand.SetHelpFunc(func(command *cobra.Command, arguments []string) {
		if command == rootCommand {
			for _, command := range sync.Commands {
				command.Hidden = true
			}
		}
		defaultHelpFunction(command, arguments)
	})

	// Execute the root command.
	if err := rootCommand.Execute(); err != nil {
		os.Exit(1)
	}
}
<commit_msg>Rearranged sync and forward commands in help output<commit_after>package main

import (
	"os"

	"github.com/spf13/cobra"

	"github.com/mutagen-io/mutagen/cmd"
	"github.com/mutagen-io/mutagen/cmd/mutagen/daemon"
	"github.com/mutagen-io/mutagen/cmd/mutagen/forward"
	"github.com/mutagen-io/mutagen/cmd/mutagen/project"
	"github.com/mutagen-io/mutagen/cmd/mutagen/sync"
	"github.com/mutagen-io/mutagen/pkg/prompt"
)

func rootMain(command *cobra.Command, arguments []string) error {
	// If no commands were given, then print help information and bail. We don't
	// have to worry about warning about arguments being present here (which
	// would be incorrect usage) because arguments can't even reach this point
	// (they will be mistaken for subcommands and a error will be displayed).
	command.Help()

	// Success.
	return nil
}

var rootCommand = &cobra.Command{
	Use:          "mutagen",
	Short:        "Mutagen is a remote development tool built on high-performance synchronization",
	RunE:         rootMain,
	SilenceUsage: true,
}

var rootConfiguration struct {
	// help indicates whether or not help information should be shown for the
	// command.
	help bool
}

func init() {
	// Disable alphabetical sorting of commands in help output. This is a global
	// setting that affects all Cobra command instances.
	cobra.EnableCommandSorting = false

	// Grab a handle for the command line flags.
	flags := rootCommand.Flags()

	// Disable alphabetical sorting of flags in help output.
	flags.SortFlags = false

	// Manually add a help flag to override the default message. Cobra will
	// still implement its logic automatically.
	flags.BoolVarP(&rootConfiguration.help, "help", "h", false, "Show help information")

	// Disable Cobra's use of mousetrap. This breaks daemon registration on
	// Windows because it tries to enforce that the CLI only be launched from
	// a console, which it's not when running automatically.
	cobra.MousetrapHelpText = ""

	// Register commands.
	// HACK: Add the sync commands as direct subcommands of the root command for
	// temporary backward compatibility.
	commands := []*cobra.Command{
		sync.RootCommand,
		forward.RootCommand,
		project.RootCommand,
		daemon.RootCommand,
		versionCommand,
		legalCommand,
		generateCommand,
	}
	commands = append(commands, sync.Commands...)
	rootCommand.AddCommand(commands...)

	// HACK: Register the sync subcommands with the sync command after
	// registering them with the root command so that they have the correct
	// parent command and thus the correct help output.
	sync.RootCommand.AddCommand(sync.Commands...)
}

func main() {
	// Check if a prompting environment is set. If so, treat this as a prompt
	// request. Prompting is sort of a special pseudo-command that's indicated
	// by the presence of an environment variable, and hence it has to be
	// handled in a bit of a special manner.
	if _, ok := os.LookupEnv(prompt.PrompterEnvironmentVariable); ok {
		if err := promptMain(os.Args[1:]); err != nil {
			cmd.Fatal(err)
		}
		return
	}

	// Handle terminal compatibility issues. If this call returns, it means that
	// we should proceed normally.
	cmd.HandleTerminalCompatibility()

	// HACK: Modify the root command's help function to hide sync commands.
	defaultHelpFunction := rootCommand.HelpFunc()
	rootCommand.SetHelpFunc(func(command *cobra.Command, arguments []string) {
		if command == rootCommand {
			for _, command := range sync.Commands {
				command.Hidden = true
			}
		}
		defaultHelpFunction(command, arguments)
	})

	// Execute the root command.
	if err := rootCommand.Execute(); err != nil {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"os/user"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/skratchdot/open-golang/open"
	"github.com/spf13/cobra"

	. "github.com/kkdai/photomgr"
)

func printPageResult(p *PTT, count int) {
	for i := 0; i < count; i++ {
		title := p.GetPostTitleByIndex(i)
		likeCount := p.GetPostStarByIndex(i)
		fmt.Printf("%d:[%d★]%s\n", i, likeCount, title)
	}
	fmt.Printf("(o: open file in fider, s: top page, n:next, p:prev, quit: quit program)\n")
}

type NullWriter int

func (NullWriter) Write([]byte) (int, error) { return 0, nil }

func main() {

	log.SetOutput(new(NullWriter))
	ptt := NewPTT()

	usr, _ := user.Current()
	ptt.BaseDir = fmt.Sprintf("%v/Pictures/iloveptt", usr.HomeDir)

	var workerNum int
	rootCmd := &cobra.Command{
		Use:   "iloveptt",
		Short: "Download all the images in given post url",
		Run: func(cmd *cobra.Command, args []string) {
			page := 0
			pagePostCoubt := 0
			pagePostCoubt = ptt.ParsePttPageByIndex(page)
			printPageResult(ptt, pagePostCoubt)

			scanner := bufio.NewScanner(os.Stdin)
			quit := false

			for !quit {
				fmt.Print("ptt:> ")

				if !scanner.Scan() {
					break
				}

				line := scanner.Text()
				parts := strings.Split(line, " ")
				cmd := parts[0]
				args := parts[1:]

				switch cmd {
				case "quit":
					quit = true
				case "n":
					page = page + 1
					pagePostCoubt = ptt.ParsePttPageByIndex(page)
					printPageResult(ptt, pagePostCoubt)
				case "p":
					if page > 0 {
						page = page - 1
					}
					pagePostCoubt = ptt.ParsePttPageByIndex(page)
					printPageResult(ptt, pagePostCoubt)
				case "s":
					page = 0
					pagePostCoubt = ptt.ParsePttPageByIndex(page)
					printPageResult(ptt, pagePostCoubt)
				case "o":
					open.Run(filepath.FromSlash(ptt.BaseDir))
				case "d":
					if len(args) == 0 {
						fmt.Println("You don't input any article index. Input as 'd 1'")
						continue
					}

					index, err := strconv.Atoi(args[0])
					if err != nil {
						fmt.Println(err)
						continue
					}

					url := ptt.GetPostUrlByIndex(index)

					if int(index) >= len(url) {
						fmt.Println("Invalid index")
						continue
					}

					if ptt.HasValidURL(url) {
						ptt.Crawler(url, 25)
						fmt.Println("Done!")
					} else {
						fmt.Println("Unsupport url:", url)
					}
				default:
					fmt.Println("Unrecognized command:", cmd, args)
				}
			}
		},
	}

	rootCmd.Flags().IntVarP(&workerNum, "worker", "w", 25, "Number of workers")
	rootCmd.Execute()
}
<commit_msg>fix typo<commit_after>package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"os/user"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/skratchdot/open-golang/open"
	"github.com/spf13/cobra"

	. "github.com/kkdai/photomgr"
)

func printPageResult(p *PTT, count int) {
	for i := 0; i < count; i++ {
		title := p.GetPostTitleByIndex(i)
		likeCount := p.GetPostStarByIndex(i)
		fmt.Printf("%d:[%d★]%s\n", i, likeCount, title)
	}
	fmt.Printf("(o: open file in fider, s: top page, n:next, p:prev, quit: quit program)\n")
}

type NullWriter int

func (NullWriter) Write([]byte) (int, error) { return 0, nil }

func main() {

	log.SetOutput(new(NullWriter))
	ptt := NewPTT()

	usr, _ := user.Current()
	ptt.BaseDir = fmt.Sprintf("%v/Pictures/iloveptt", usr.HomeDir)

	var workerNum int
	rootCmd := &cobra.Command{
		Use:   "iloveptt",
		Short: "Download all the images in given post url",
		Run: func(cmd *cobra.Command, args []string) {
			page := 0
			pagePostCount := 0
			pagePostCount = ptt.ParsePttPageByIndex(page)
			printPageResult(ptt, pagePostCount)

			scanner := bufio.NewScanner(os.Stdin)
			quit := false

			for !quit {
				fmt.Print("ptt:> ")

				if !scanner.Scan() {
					break
				}

				line := scanner.Text()
				parts := strings.Split(line, " ")
				cmd := parts[0]
				args := parts[1:]

				switch cmd {
				case "quit":
					quit = true
				case "n":
					page = page + 1
					pagePostCount = ptt.ParsePttPageByIndex(page)
					printPageResult(ptt, pagePostCount)
				case "p":
					if page > 0 {
						page = page - 1
					}
					pagePostCount = ptt.ParsePttPageByIndex(page)
					printPageResult(ptt, pagePostCount)
				case "s":
					page = 0
					pagePostCount = ptt.ParsePttPageByIndex(page)
					printPageResult(ptt, pagePostCount)
				case "o":
					open.Run(filepath.FromSlash(ptt.BaseDir))
				case "d":
					if len(args) == 0 {
						fmt.Println("You don't input any article index. Input as 'd 1'")
						continue
					}

					index, err := strconv.Atoi(args[0])
					if err != nil {
						fmt.Println(err)
						continue
					}

					url := ptt.GetPostUrlByIndex(index)

					if int(index) >= len(url) {
						fmt.Println("Invalid index")
						continue
					}

					if ptt.HasValidURL(url) {
						ptt.Crawler(url, 25)
						fmt.Println("Done!")
					} else {
						fmt.Println("Unsupport url:", url)
					}
				default:
					fmt.Println("Unrecognized command:", cmd, args)
				}
			}
		},
	}

	rootCmd.Flags().IntVarP(&workerNum, "worker", "w", 25, "Number of workers")
	rootCmd.Execute()
}
<|endoftext|>


<commit_before>package main

// The git commit that was compiled. This will be filled in by the compiler.
var GitCommit string

// The main version number that is being run at the moment.
const Version = "0.7.0"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
const VersionPrerelease = ""
<commit_msg>Puts tree into release mode.<commit_after>package main

// The git commit that was compiled. This will be filled in by the compiler.
var GitCommit string

// The main version number that is being run at the moment.
const Version = "0.8.0"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
const VersionPrerelease = ""
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package pathtools

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
)

// Based on Andrew Gerrand's "10 things you (probably) dont' know about Go"

var OsFs FileSystem = osFs{}

func MockFs(files map[string][]byte) FileSystem {
	fs := &mockFs{
		files: make(map[string][]byte, len(files)),
		dirs:  make(map[string]bool),
		all:   []string(nil),
	}

	for f, b := range files {
		fs.files[filepath.Clean(f)] = b
		dir := filepath.Dir(f)
		for dir != "." && dir != "/" {
			fs.dirs[dir] = true
			dir = filepath.Dir(dir)
		}
	}

	for f := range fs.files {
		fs.all = append(fs.all, f)
	}

	for d := range fs.dirs {
		fs.all = append(fs.all, d)
	}

	return fs
}

type FileSystem interface {
	Open(name string) (io.ReadCloser, error)
	Exists(name string) (bool, bool, error)
	Glob(pattern string, excludes []string) (matches, dirs []string, err error)
	glob(pattern string) (matches []string, err error)
	IsDir(name string) (bool, error)
}

// osFs implements FileSystem using the local disk.
type osFs struct{}

func (osFs) Open(name string) (io.ReadCloser, error) { return os.Open(name) }
func (osFs) Exists(name string) (bool, bool, error) {
	stat, err := os.Stat(name)
	if err == nil {
		return true, stat.IsDir(), nil
	} else if os.IsNotExist(err) {
		return false, false, nil
	} else {
		return false, false, err
	}
}

func (osFs) IsDir(name string) (bool, error) {
	info, err := os.Stat(name)
	if err != nil {
		return false, fmt.Errorf("unexpected error after glob: %s", err)
	}
	return info.IsDir(), nil
}

func (fs osFs) Glob(pattern string, excludes []string) (matches, dirs []string, err error) {
	return startGlob(fs, pattern, excludes)
}

func (osFs) glob(pattern string) ([]string, error) {
	return filepath.Glob(pattern)
}

type mockFs struct {
	files map[string][]byte
	dirs  map[string]bool
	all   []string
}

func (m *mockFs) Open(name string) (io.ReadCloser, error) {
	if f, ok := m.files[name]; ok {
		return struct {
			io.Closer
			*bytes.Reader
		}{
			ioutil.NopCloser(nil),
			bytes.NewReader(f),
		}, nil
	}

	return nil, &os.PathError{
		Op:   "open",
		Path: name,
		Err:  os.ErrNotExist,
	}
}

func (m *mockFs) Exists(name string) (bool, bool, error) {
	name = filepath.Clean(name)
	if _, ok := m.files[name]; ok {
		return ok, false, nil
	}
	if _, ok := m.dirs[name]; ok {
		return ok, true, nil
	}
	return false, false, nil
}

func (m *mockFs) IsDir(name string) (bool, error) {
	return m.dirs[filepath.Clean(name)], nil
}

func (m *mockFs) Glob(pattern string, excludes []string) (matches, dirs []string, err error) {
	return startGlob(m, pattern, excludes)
}

func (m *mockFs) glob(pattern string) ([]string, error) {
	var matches []string
	for _, f := range m.all {
		match, err := filepath.Match(pattern, f)
		if err != nil {
			return nil, err
		}
		if match {
			matches = append(matches, f)
		}
	}
	return matches, nil
}
<commit_msg>Add . and / to MockFs<commit_after>// Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package pathtools

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
)

// Based on Andrew Gerrand's "10 things you (probably) dont' know about Go"

var OsFs FileSystem = osFs{}

func MockFs(files map[string][]byte) FileSystem {
	fs := &mockFs{
		files: make(map[string][]byte, len(files)),
		dirs:  make(map[string]bool),
		all:   []string(nil),
	}

	for f, b := range files {
		fs.files[filepath.Clean(f)] = b
		dir := filepath.Dir(f)
		for dir != "." && dir != "/" {
			fs.dirs[dir] = true
			dir = filepath.Dir(dir)
		}
		fs.dirs[dir] = true
	}

	for f := range fs.files {
		fs.all = append(fs.all, f)
	}

	for d := range fs.dirs {
		fs.all = append(fs.all, d)
	}

	return fs
}

type FileSystem interface {
	Open(name string) (io.ReadCloser, error)
	Exists(name string) (bool, bool, error)
	Glob(pattern string, excludes []string) (matches, dirs []string, err error)
	glob(pattern string) (matches []string, err error)
	IsDir(name string) (bool, error)
}

// osFs implements FileSystem using the local disk.
type osFs struct{}

func (osFs) Open(name string) (io.ReadCloser, error) { return os.Open(name) }
func (osFs) Exists(name string) (bool, bool, error) {
	stat, err := os.Stat(name)
	if err == nil {
		return true, stat.IsDir(), nil
	} else if os.IsNotExist(err) {
		return false, false, nil
	} else {
		return false, false, err
	}
}

func (osFs) IsDir(name string) (bool, error) {
	info, err := os.Stat(name)
	if err != nil {
		return false, fmt.Errorf("unexpected error after glob: %s", err)
	}
	return info.IsDir(), nil
}

func (fs osFs) Glob(pattern string, excludes []string) (matches, dirs []string, err error) {
	return startGlob(fs, pattern, excludes)
}

func (osFs) glob(pattern string) ([]string, error) {
	return filepath.Glob(pattern)
}

type mockFs struct {
	files map[string][]byte
	dirs  map[string]bool
	all   []string
}

func (m *mockFs) Open(name string) (io.ReadCloser, error) {
	if f, ok := m.files[name]; ok {
		return struct {
			io.Closer
			*bytes.Reader
		}{
			ioutil.NopCloser(nil),
			bytes.NewReader(f),
		}, nil
	}

	return nil, &os.PathError{
		Op:   "open",
		Path: name,
		Err:  os.ErrNotExist,
	}
}

func (m *mockFs) Exists(name string) (bool, bool, error) {
	name = filepath.Clean(name)
	if _, ok := m.files[name]; ok {
		return ok, false, nil
	}
	if _, ok := m.dirs[name]; ok {
		return ok, true, nil
	}
	return false, false, nil
}

func (m *mockFs) IsDir(name string) (bool, error) {
	return m.dirs[filepath.Clean(name)], nil
}

func (m *mockFs) Glob(pattern string, excludes []string) (matches, dirs []string, err error) {
	return startGlob(m, pattern, excludes)
}

func (m *mockFs) glob(pattern string) ([]string, error) {
	var matches []string
	for _, f := range m.all {
		match, err := filepath.Match(pattern, f)
		if err != nil {
			return nil, err
		}
		if match {
			matches = append(matches, f)
		}
	}
	return matches, nil
}
<|endoftext|>