<commit_before>package ant

import (
	"log"
	"time"

	"github.com/NebulousLabs/Sia/api"
	"github.com/NebulousLabs/Sia/types"
)

// blockMining unlocks the wallet and mines some currency.  If more than 100
// seconds passes before the wallet has received some amount of currency, this
// job will print an error.
func (j *jobRunner) blockMining(desiredBalance types.Currency) {
	j.tg.Add()
	defer j.tg.Done()

	minerRunning := true
	err := j.client.Get("/miner/start", nil)
	if err != nil {
		log.Printf("[%v blockMining ERROR]: %v\n", j.siaDirectory, err)
		return
	}

	// Every 100 seconds, verify that the balance has increased.
	// if the balance is above desiredBalance, throttle the miner.
	// if desiredBalance is zero, the miner runs forever.
	runForever := desiredBalance.Cmp(types.ZeroCurrency) == 0

	for {
		select {
		case <-j.tg.StopChan():
			return
		case <-time.After(time.Second * 100):
		}

		if runForever {
			continue
		}

		var walletInfo api.WalletGET
		err = j.client.Get("/wallet", &walletInfo)
		if err != nil {
			log.Printf("[%v blockMining ERROR]: %v\n", j.siaDirectory, err)
			return
		}

		haveDesiredBalance := walletInfo.ConfirmedSiacoinBalance.Cmp(desiredBalance) > 0
		if !minerRunning && !haveDesiredBalance {
			log.Printf("[%v miner INFO]: not enough currency, starting the miner\n", j.siaDirectory)
			minerRunning = true
			if err = j.client.Get("/miner/start", nil); err != nil {
				log.Printf("[%v miner ERROR]: %v\n", j.siaDirectory, err)
				return
			}
		} else if minerRunning && haveDesiredBalance {
			log.Printf("[%v miner INFO]: mined enough currency, stopping the miner\n", j.siaDirectory)
			minerRunning = false
			if err = j.client.Get("/miner/stop", nil); err != nil {
				log.Printf("[%v miner ERROR]: %v\n", j.siaDirectory, err)
				return
			}
		}
	}
}
<commit_msg>clean up blockMining<commit_after>package ant

import (
	"log"
	"time"

	"github.com/NebulousLabs/Sia/api"
	"github.com/NebulousLabs/Sia/types"
)

// blockMining mines blocks until desiredBalance is reached. If desiredBalance
// is zero, blockMining will start the miner and return, mining indefinitely.
func (j *jobRunner) blockMining(desiredBalance types.Currency) {
	j.tg.Add()
	defer j.tg.Done()

	minerRunning := true
	err := j.client.Get("/miner/start", nil)
	if err != nil {
		log.Printf("[%v blockMining ERROR]: %v\n", j.siaDirectory, err)
		return
	}

	// If desiredBalance is zero, just return, leaving the miner running.
	runForever := desiredBalance.Cmp(types.ZeroCurrency) == 0
	if runForever {
		return
	}

	// Every 20 seconds, check if the balance has exceeded the desiredBalance. If
	// it has and the miner is running, the miner is throttled. If the desired
	// balance has not been reached and the miner is not running, the miner is
	// started.
	for {
		select {
		case <-j.tg.StopChan():
			return
		case <-time.After(time.Second * 20):
		}

		var walletInfo api.WalletGET
		err = j.client.Get("/wallet", &walletInfo)
		if err != nil {
			log.Printf("[%v blockMining ERROR]: %v\n", j.siaDirectory, err)
			return
		}

		haveDesiredBalance := walletInfo.ConfirmedSiacoinBalance.Cmp(desiredBalance) > 0
		if !minerRunning && !haveDesiredBalance {
			log.Printf("[%v miner INFO]: not enough currency, starting the miner\n", j.siaDirectory)
			minerRunning = true
			if err = j.client.Get("/miner/start", nil); err != nil {
				log.Printf("[%v miner ERROR]: %v\n", j.siaDirectory, err)
				return
			}
		} else if minerRunning && haveDesiredBalance {
			log.Printf("[%v miner INFO]: mined enough currency, stopping the miner\n", j.siaDirectory)
			minerRunning = false
			if err = j.client.Get("/miner/stop", nil); err != nil {
				log.Printf("[%v miner ERROR]: %v\n", j.siaDirectory, err)
				return
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

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

type Executor struct {
	rules         map[string]*Rule
	implicitRules []*Rule
	suffixRules   map[string][]*Rule
	firstRule     *Rule
}

func newExecutor() *Executor {
	return &Executor{
		rules:       make(map[string]*Rule),
		suffixRules: make(map[string][]*Rule),
	}
}

// TODO(ukai): use time.Time?
func getTimestamp(filename string) int64 {
	st, err := os.Stat(filename)
	if err != nil {
		return -2
	}
	return st.ModTime().Unix()
}

func (ex *Executor) runCommands(cmds []string, output string) error {
Loop:
	for _, cmd := range cmds {
		echo := true
		ignoreErr := false
		for {
			if cmd == "" {
				continue Loop
			}
			switch cmd[0] {
			case '@':
				echo = false
				cmd = cmd[1:]
				continue
			case '-':
				ignoreErr = true
				cmd = cmd[1:]
				continue
			}
			break
		}
		if echo {
			fmt.Printf("%s\n", cmd)
		}

		args := []string{"/bin/sh", "-c", cmd}
		cmd := exec.Cmd{
			Path: args[0],
			Args: args,
		}
		out, err := cmd.CombinedOutput()
		exit := 0
		if err != nil {
			exit = 1
			if err, ok := err.(*exec.ExitError); ok {
				if w, ok := err.ProcessState.Sys().(syscall.WaitStatus); ok {
					exit = w.ExitStatus()
				}
			} else {
				return err
			}
		}
		fmt.Printf("%s", out)
		if exit != 0 {
			if ignoreErr {
				fmt.Printf("[%s] Error %d (ignored)\n", output, exit)
				continue
			}
			return fmt.Errorf("command failed: %q. Error %d", cmd, exit)
		}
	}
	return nil
}

func escapeVar(v string) string {
	return strings.Replace(v, "$", "$$", -1)
}

func replaceSuffix(s string, newsuf string) string {
	// TODO: Factor out the logic around suffix rules and use
	// it from substitution references.
	// http://www.gnu.org/software/make/manual/make.html#Substitution-Refs
	oldsuf := filepath.Ext(s)
	return fmt.Sprintf("%s.%s", s[:len(s)-len(oldsuf)], newsuf)
}

func (ex *Executor) pickRule(output string) (*Rule, bool) {
	rule, present := ex.rules[output]
	if present {
		return rule, true
	}

	for _, rule := range ex.implicitRules {
		if matchPattern(rule.outputPatterns[0], output) {
			return rule, true
		}
	}

	outputSuffix := filepath.Ext(output)
	if len(outputSuffix) > 0 && outputSuffix[0] == '.' {
		rules, present := ex.suffixRules[outputSuffix[1:]]
		if present {
			for _, rule := range rules {
				if len(rule.inputs) != 1 {
					panic(fmt.Sprintf("unexpected number of input for a suffix rule (%d)", len(rule.inputs)))
				}
				if exists(replaceSuffix(output, rule.inputs[0])) {
					return rule, true
				}
			}
		}
	}

	return nil, false
}

func (ex *Executor) build(vars map[string]string, output string) (int64, error) {
	Log("Building: %s", output)
	outputTs := getTimestamp(output)

	rule, present := ex.pickRule(output)
	if !present {
		if outputTs >= 0 {
			return outputTs, nil
		}
		return outputTs, fmt.Errorf("no rule to make target %q", output)
	}

	latest := int64(-1)
	var actualInputs []string
	for _, input := range rule.inputs {
		if len(rule.outputPatterns) > 0 {
			if len(rule.outputPatterns) > 1 {
				panic("TODO: multiple output pattern is not supported yet")
			}
			input = substPattern(rule.outputPatterns[0], input, output)
		} else if rule.isSuffixRule {
			input = replaceSuffix(output, input)
		}
		actualInputs = append(actualInputs, input)

		ts, err := ex.build(vars, input)
		if err != nil {
			return outputTs, err
		}
		if latest < ts {
			latest = ts
		}
	}

	if outputTs >= latest {
		return outputTs, nil
	}

	localVars := make(map[string]string)
	for k, v := range vars {
		localVars[k] = v
	}
	// automatic variables.
	localVars["@"] = escapeVar(output)
	if len(actualInputs) > 0 {
		localVars["<"] = escapeVar(actualInputs[0])
		localVars["^"] = escapeVar(strings.Join(actualInputs, " "))
	}
	Log("local vars: %q", localVars)
	ev := newEvaluator(localVars)
	var cmds []string
	for _, cmd := range rule.cmds {
		if strings.IndexByte(cmd, '$') < 0 {
			// fast path.
			cmds = append(cmds, cmd)
			continue
		}
		ecmd := ev.evalExpr(cmd)
		Log("build eval:%q => %q", cmd, ecmd)
		cmds = append(cmds, strings.Split(ecmd, "\n")...)
	}

	err := ex.runCommands(cmds, output)
	if err != nil {
		return outputTs, err
	}

	outputTs = getTimestamp(output)
	if outputTs < 0 {
		outputTs = time.Now().Unix()
	}
	return outputTs, nil
}

func (ex *Executor) populateSuffixRule(rule *Rule, output string) bool {
	if len(output) == 0 || output[0] != '.' {
		return false
	}
	rest := output[1:]
	dotIndex := strings.IndexByte(rest, '.')
	// If there is only a single dot or the third dot, this is not a
	// suffix rule.
	if dotIndex < 0 || strings.IndexByte(rest[dotIndex+1:], '.') >= 0 {
		return false
	}

	// This is a suffix rule.
	inputSuffix := rest[:dotIndex]
	outputSuffix := rest[dotIndex+1:]
	r := &Rule{}
	*r = *rule
	r.inputs = []string{inputSuffix}
	r.isSuffixRule = true
	ex.suffixRules[outputSuffix] = append([]*Rule{r}, ex.suffixRules[outputSuffix]...)
	return true
}

func (ex *Executor) populateExplicitRule(rule *Rule) {
	for _, output := range rule.outputs {
		isSuffixRule := ex.populateSuffixRule(rule, output)

		if oldRule, present := ex.rules[output]; present {
			if oldRule.isDoubleColon != rule.isDoubleColon {
				Error(rule.filename, rule.lineno, "*** target file %q has both : and :: entries.", output)
			}
			if len(oldRule.cmds) > 0 && len(rule.cmds) > 0 && !isSuffixRule && !rule.isDoubleColon {
				Warn(rule.filename, rule.cmdLineno, "overriding commands for target %q", output)
				Warn(oldRule.filename, oldRule.cmdLineno, "ignoring old commands for target %q", output)
			}
			r := &Rule{}
			*r = *rule
			if rule.isDoubleColon {
				r.cmds = append(oldRule.cmds, r.cmds...)
			}
			r.inputs = append(r.inputs, oldRule.inputs...)
			ex.rules[output] = r
		} else {
			ex.rules[output] = rule
			if ex.firstRule == nil && !isSuffixRule {
				ex.firstRule = rule
			}
		}
	}
}

func (ex *Executor) populateImplicitRule(rule *Rule) {
	for _, outputPattern := range rule.outputPatterns {
		r := &Rule{}
		*r = *rule
		r.outputPatterns = []string{outputPattern}
		ex.implicitRules = append(ex.implicitRules, r)
	}
}

func (ex *Executor) populateRules(er *EvalResult) {
	for _, rule := range er.rules {
		ex.populateExplicitRule(rule)

		if len(rule.outputs) == 0 {
			ex.populateImplicitRule(rule)
		}
	}

	// Reverse the implicit rule for easier lookup.
	for i, r := range ex.implicitRules {
		if i >= len(ex.implicitRules) / 2 {
			break
		}
		j := len(ex.implicitRules)-i-1
		ex.implicitRules[i] = ex.implicitRules[j]
		ex.implicitRules[j] = r
	}
}

func (ex *Executor) exec(er *EvalResult, targets []string) error {
	ex.populateRules(er)

	if len(targets) == 0 {
		if ex.firstRule == nil {
			ErrorNoLocation("*** No targets.")
		}
		targets = append(targets, ex.firstRule.outputs[0])
	}

	for _, target := range targets {
		_, err := ex.build(er.vars, target)
		if err != nil {
			return err
		}
	}
	return nil
}

func Exec(er *EvalResult, targets []string) error {
	ex := newExecutor()
	return ex.exec(er, targets)
}
<commit_msg>Handle multiple implicit patterns properly<commit_after>package main

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

type Executor struct {
	rules         map[string]*Rule
	implicitRules []*Rule
	suffixRules   map[string][]*Rule
	firstRule     *Rule
}

func newExecutor() *Executor {
	return &Executor{
		rules:       make(map[string]*Rule),
		suffixRules: make(map[string][]*Rule),
	}
}

// TODO(ukai): use time.Time?
func getTimestamp(filename string) int64 {
	st, err := os.Stat(filename)
	if err != nil {
		return -2
	}
	return st.ModTime().Unix()
}

func (ex *Executor) runCommands(cmds []string, output string) error {
Loop:
	for _, cmd := range cmds {
		echo := true
		ignoreErr := false
		for {
			if cmd == "" {
				continue Loop
			}
			switch cmd[0] {
			case '@':
				echo = false
				cmd = cmd[1:]
				continue
			case '-':
				ignoreErr = true
				cmd = cmd[1:]
				continue
			}
			break
		}
		if echo {
			fmt.Printf("%s\n", cmd)
		}

		args := []string{"/bin/sh", "-c", cmd}
		cmd := exec.Cmd{
			Path: args[0],
			Args: args,
		}
		out, err := cmd.CombinedOutput()
		exit := 0
		if err != nil {
			exit = 1
			if err, ok := err.(*exec.ExitError); ok {
				if w, ok := err.ProcessState.Sys().(syscall.WaitStatus); ok {
					exit = w.ExitStatus()
				}
			} else {
				return err
			}
		}
		fmt.Printf("%s", out)
		if exit != 0 {
			if ignoreErr {
				fmt.Printf("[%s] Error %d (ignored)\n", output, exit)
				continue
			}
			return fmt.Errorf("command failed: %q. Error %d", cmd, exit)
		}
	}
	return nil
}

func escapeVar(v string) string {
	return strings.Replace(v, "$", "$$", -1)
}

func replaceSuffix(s string, newsuf string) string {
	// TODO: Factor out the logic around suffix rules and use
	// it from substitution references.
	// http://www.gnu.org/software/make/manual/make.html#Substitution-Refs
	oldsuf := filepath.Ext(s)
	return fmt.Sprintf("%s.%s", s[:len(s)-len(oldsuf)], newsuf)
}

func (ex *Executor) canPickImplicitRule(rule *Rule, output string) bool {
	outputPattern := rule.outputPatterns[0]
	if !matchPattern(outputPattern, output) {
		return false
	}
	for _, input := range rule.inputs {
		input = substPattern(outputPattern, input, output)
		if !exists(input) {
			return false
		}
	}
	return true
}

func (ex *Executor) pickRule(output string) (*Rule, bool) {
	rule, present := ex.rules[output]
	if present {
		return rule, true
	}

	for _, rule := range ex.implicitRules {
		if ex.canPickImplicitRule(rule, output) {
			return rule, true
		}
	}

	outputSuffix := filepath.Ext(output)
	if len(outputSuffix) > 0 && outputSuffix[0] == '.' {
		rules, present := ex.suffixRules[outputSuffix[1:]]
		if present {
			for _, rule := range rules {
				if len(rule.inputs) != 1 {
					panic(fmt.Sprintf("unexpected number of input for a suffix rule (%d)", len(rule.inputs)))
				}
				if exists(replaceSuffix(output, rule.inputs[0])) {
					return rule, true
				}
			}
		}
	}

	return nil, false
}

func (ex *Executor) build(vars map[string]string, output string) (int64, error) {
	Log("Building: %s", output)
	outputTs := getTimestamp(output)

	rule, present := ex.pickRule(output)
	if !present {
		if outputTs >= 0 {
			return outputTs, nil
		}
		return outputTs, fmt.Errorf("no rule to make target %q", output)
	}

	latest := int64(-1)
	var actualInputs []string
	for _, input := range rule.inputs {
		if len(rule.outputPatterns) > 0 {
			if len(rule.outputPatterns) > 1 {
				panic("TODO: multiple output pattern is not supported yet")
			}
			input = substPattern(rule.outputPatterns[0], input, output)
		} else if rule.isSuffixRule {
			input = replaceSuffix(output, input)
		}
		actualInputs = append(actualInputs, input)

		ts, err := ex.build(vars, input)
		if err != nil {
			return outputTs, err
		}
		if latest < ts {
			latest = ts
		}
	}

	if outputTs >= latest {
		return outputTs, nil
	}

	localVars := make(map[string]string)
	for k, v := range vars {
		localVars[k] = v
	}
	// automatic variables.
	localVars["@"] = escapeVar(output)
	if len(actualInputs) > 0 {
		localVars["<"] = escapeVar(actualInputs[0])
		localVars["^"] = escapeVar(strings.Join(actualInputs, " "))
	}
	Log("local vars: %q", localVars)
	ev := newEvaluator(localVars)
	var cmds []string
	for _, cmd := range rule.cmds {
		if strings.IndexByte(cmd, '$') < 0 {
			// fast path.
			cmds = append(cmds, cmd)
			continue
		}
		ecmd := ev.evalExpr(cmd)
		Log("build eval:%q => %q", cmd, ecmd)
		cmds = append(cmds, strings.Split(ecmd, "\n")...)
	}

	err := ex.runCommands(cmds, output)
	if err != nil {
		return outputTs, err
	}

	outputTs = getTimestamp(output)
	if outputTs < 0 {
		outputTs = time.Now().Unix()
	}
	return outputTs, nil
}

func (ex *Executor) populateSuffixRule(rule *Rule, output string) bool {
	if len(output) == 0 || output[0] != '.' {
		return false
	}
	rest := output[1:]
	dotIndex := strings.IndexByte(rest, '.')
	// If there is only a single dot or the third dot, this is not a
	// suffix rule.
	if dotIndex < 0 || strings.IndexByte(rest[dotIndex+1:], '.') >= 0 {
		return false
	}

	// This is a suffix rule.
	inputSuffix := rest[:dotIndex]
	outputSuffix := rest[dotIndex+1:]
	r := &Rule{}
	*r = *rule
	r.inputs = []string{inputSuffix}
	r.isSuffixRule = true
	ex.suffixRules[outputSuffix] = append([]*Rule{r}, ex.suffixRules[outputSuffix]...)
	return true
}

func (ex *Executor) populateExplicitRule(rule *Rule) {
	for _, output := range rule.outputs {
		isSuffixRule := ex.populateSuffixRule(rule, output)

		if oldRule, present := ex.rules[output]; present {
			if oldRule.isDoubleColon != rule.isDoubleColon {
				Error(rule.filename, rule.lineno, "*** target file %q has both : and :: entries.", output)
			}
			if len(oldRule.cmds) > 0 && len(rule.cmds) > 0 && !isSuffixRule && !rule.isDoubleColon {
				Warn(rule.filename, rule.cmdLineno, "overriding commands for target %q", output)
				Warn(oldRule.filename, oldRule.cmdLineno, "ignoring old commands for target %q", output)
			}
			r := &Rule{}
			*r = *rule
			if rule.isDoubleColon {
				r.cmds = append(oldRule.cmds, r.cmds...)
			}
			r.inputs = append(r.inputs, oldRule.inputs...)
			ex.rules[output] = r
		} else {
			ex.rules[output] = rule
			if ex.firstRule == nil && !isSuffixRule {
				ex.firstRule = rule
			}
		}
	}
}

func (ex *Executor) populateImplicitRule(rule *Rule) {
	for _, outputPattern := range rule.outputPatterns {
		r := &Rule{}
		*r = *rule
		r.outputPatterns = []string{outputPattern}
		ex.implicitRules = append(ex.implicitRules, r)
	}
}

func (ex *Executor) populateRules(er *EvalResult) {
	for _, rule := range er.rules {
		ex.populateExplicitRule(rule)

		if len(rule.outputs) == 0 {
			ex.populateImplicitRule(rule)
		}
	}

	// Reverse the implicit rule for easier lookup.
	for i, r := range ex.implicitRules {
		if i >= len(ex.implicitRules) / 2 {
			break
		}
		j := len(ex.implicitRules)-i-1
		ex.implicitRules[i] = ex.implicitRules[j]
		ex.implicitRules[j] = r
	}
}

func (ex *Executor) exec(er *EvalResult, targets []string) error {
	ex.populateRules(er)

	if len(targets) == 0 {
		if ex.firstRule == nil {
			ErrorNoLocation("*** No targets.")
		}
		targets = append(targets, ex.firstRule.outputs[0])
	}

	for _, target := range targets {
		_, err := ex.build(er.vars, target)
		if err != nil {
			return err
		}
	}
	return nil
}

func Exec(er *EvalResult, targets []string) error {
	ex := newExecutor()
	return ex.exec(er, targets)
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"math"
	"strconv"

	"code.google.com/p/goprotobuf/proto"

	pb "github.com/dgryski/carbonzipper/carbonzipperpb"
)

// expression parser

type exprType int

const (
	etMetric exprType = iota
	etFunc
	etConst
)

type expr struct {
	target    string
	etype     exprType
	val       float64
	args      []*expr
	argString string
}

func (e *expr) metrics() []string {

	switch e.etype {
	case etMetric:
		return []string{e.target}
	case etConst:
		return nil
	case etFunc:
		var r []string
		for _, a := range e.args {
			r = append(r, a.metrics()...)
		}
		return r
	}

	return nil
}

func parseExpr(e string) (*expr, string, error) {

	if '0' <= e[0] && e[0] <= '9' {
		val, e, err := parseConst(e)
		return &expr{val: val, etype: etConst}, e, err
	}

	name, e := parseName(e)

	if e != "" && e[0] == '(' {
		exp := &expr{target: name, etype: etFunc}

		argString, args, e, err := parseArgList(e)
		exp.argString = argString
		exp.args = args

		return exp, e, err
	}

	return &expr{target: name}, e, nil
}

var (
	ErrMissingComma        = errors.New("missing comma")
	ErrUnexpectedCharacter = errors.New("unexpected character")
)

func parseArgList(e string) (string, []*expr, string, error) {

	var args []*expr

	if e[0] != '(' {
		panic("arg list should start with paren")
	}

	argString := e[1:]

	e = e[1:]

	for {
		var arg *expr
		var err error
		arg, e, err = parseExpr(e)
		if err != nil {
			return "", nil, "", err
		}
		args = append(args, arg)

		if e == "" {
			return "", nil, "", ErrMissingComma
		}

		if e[0] == ')' {
			return argString[:len(argString)-len(e)], args, e[1:], nil
		}

		if e[0] != ',' && e[0] != ' ' {
			return "", nil, "", ErrUnexpectedCharacter
		}

		e = e[1:]
	}
}

func isNameChar(r byte) bool {
	return false ||
		'a' <= r && r <= 'z' ||
		'A' <= r && r <= 'Z' ||
		'0' <= r && r <= '9' ||
		r == '.' || r == '_' || r == '-' || r == '*'
}

func isDigit(r byte) bool {
	return '0' <= r && r <= '9'
}

func parseConst(s string) (float64, string, error) {

	var i int
	for i < len(s) && isDigit(s[i]) {
		i++
	}

	v, err := strconv.ParseFloat(s[:i], 64)
	if err != nil {
		return 0, "", err
	}

	return v, s[i:], err
}

func parseName(s string) (string, string) {

	var i int
	for i < len(s) && isNameChar(s[i]) {
		i++
	}

	if i == len(s) {
		return s, ""
	}

	return s[:i], s[i:]
}

func evalExpr(e *expr, values map[string][]*pb.FetchResponse) []*pb.FetchResponse {

	switch e.etype {
	case etMetric:
		return values[e.target]
	case etConst:
		p := pb.FetchResponse{Name: proto.String(e.target), Values: []float64{e.val}}
		return []*pb.FetchResponse{&p}
	}

	// evaluate the function
	switch e.target {
	case "keepLastValue":

		arg := evalExpr(e.args[0], values)

		keep := -1

		if len(e.args) > 1 {

			n := evalExpr(e.args[1], values)
			if len(n) != 1 || len(n[0].Values) != 1 {
				// fail
				return nil
			}

			keep = int(n[0].Values[0])

		}

		var results []*pb.FetchResponse

		for _, a := range arg {
			r := pb.FetchResponse{
				Name:     proto.String(fmt.Sprintf("keepLastValue(%s,%d)", e.argString, keep)),
				Values:   make([]float64, len(a.Values)),
				IsAbsent: make([]bool, len(a.Values)),
				StepTime: a.StepTime,
			}

			prev := math.NaN()
			missing := 0

			for i, v := range a.Values {
				if a.IsAbsent[i] {

					if (keep < 0 || missing < keep) && !math.IsNaN(prev) {
						r.Values[i] = prev
						missing++
					} else {
						r.IsAbsent[i] = true
					}

					continue
				}
				missing = 0
				prev = v
				r.Values[i] = v
			}
			results = append(results, &r)
		}
		return results

	case "movingAverage":
		arg := evalExpr(e.args[0], values)
		n := evalExpr(e.args[1], values)
		if len(n) != 1 || len(n[0].Values) != 1 {
			// fail
			return nil
		}

		windowSize := int(n[0].Values[0])

		var result []*pb.FetchResponse

		for _, a := range arg {
			w := &Windowed{data: make([]float64, windowSize)}
			r := pb.FetchResponse{
				Name:     proto.String(fmt.Sprintf("movingAverage(%s, %d)", *a.Name, windowSize)),
				Values:   make([]float64, len(a.Values)),
				IsAbsent: make([]bool, len(a.Values)),
				StepTime: a.StepTime,
			}
			for i, v := range a.Values {
				if a.IsAbsent[i] {
					// make sure missing values are ignored
					v = 0
				}
				w.Push(v)
				r.Values[i] = w.Mean()
			}
			result = append(result, &r)
		}
		return result

	case "nonNegativeDerivative":
		arg := evalExpr(e.args[0], values)
		var result []*pb.FetchResponse
		for _, a := range arg {
			r := pb.FetchResponse{
				Name:     proto.String(fmt.Sprintf("nonNegativeDerivative(%s)", *a.Name)),
				Values:   make([]float64, len(a.Values)),
				IsAbsent: make([]bool, len(a.Values)),
				StepTime: a.StepTime,
			}
			prev := a.Values[0]
			for i, v := range a.Values {
				if i == 0 || a.IsAbsent[i] {
					r.IsAbsent[i] = true
					continue
				}

				r.Values[i] = v - prev
				if r.Values[i] < 0 {
					r.Values[i] = 0
					r.IsAbsent[i] = true
				}
				prev = v
			}
			result = append(result, &r)
		}
		return result

	case "scale":
		arg := evalExpr(e.args[0], values)
		n := evalExpr(e.args[1], values)
		if len(n) != 1 || len(n[0].Values) != 1 {
			// fail
			return nil
		}

		scale := n[0].Values[0]

		var results []*pb.FetchResponse

		for _, a := range arg {
			r := pb.FetchResponse{
				Name:     proto.String(fmt.Sprintf("scale(%s,%g)", e.argString, scale)),
				Values:   make([]float64, len(a.Values)),
				IsAbsent: make([]bool, len(a.Values)),
				StepTime: a.StepTime,
			}

			for i, v := range a.Values {
				if a.IsAbsent[i] {
					r.Values[i] = 0
					r.IsAbsent[i] = true
					continue
				}
				r.Values[i] = v * scale
			}
			results = append(results, &r)
		}
		return results

	case "scaleToSeconds":
		arg := evalExpr(e.args[0], values)
		n := evalExpr(e.args[1], values)
		if len(n) != 1 || len(n[0].Values) != 1 {
			// fail
			return nil
		}

		seconds := n[0].Values[0]

		var results []*pb.FetchResponse

		for _, a := range arg {
			r := pb.FetchResponse{
				Name:     proto.String(fmt.Sprintf("scale(%s,%g)", e.argString, seconds)),
				Values:   make([]float64, len(a.Values)),
				StepTime: a.StepTime,
				IsAbsent: make([]bool, len(a.Values)),
			}

			factor := seconds / float64(*a.StepTime)

			for i, v := range a.Values {
				if a.IsAbsent[i] {
					r.Values[i] = 0
					r.IsAbsent[i] = true
					continue
				}
				r.Values[i] = v * factor
			}
			results = append(results, &r)
		}
		return results

	case "sum", "sumSeries":
		// TODO(dgryski): make sure the arrays are all the same 'size'
		var args []*pb.FetchResponse
		for _, arg := range e.args {
			a := evalExpr(arg, values)
			args = append(args, a...)
		}
		r := pb.FetchResponse{
			Name:     proto.String(fmt.Sprintf("sum(%s)", e.argString)),
			Values:   make([]float64, len(args[0].Values)),
			IsAbsent: make([]bool, len(args[0].Values)),
			StepTime: args[0].StepTime,
		}
		for _, arg := range args {
			for i, v := range arg.Values {
				if arg.IsAbsent[i] {
					continue
				}
				r.Values[i] += v
			}
		}
		return []*pb.FetchResponse{&r}
	}

	return nil
}

// From github.com/dgryski/go-onlinestats
// Copied here because we don't need the rest of the package, and we only need
// a small part of this type

type Windowed struct {
	data   []float64
	head   int
	length int
	sum    float64
}

func (w *Windowed) Push(n float64) {
	old := w.data[w.head]

	w.length++

	w.data[w.head] = n
	w.head++
	if w.head >= len(w.data) {
		w.head = 0
	}

	w.sum -= old
	w.sum += n
}

func (w *Windowed) Len() int {
	if w.length < len(w.data) {
		return w.length
	}

	return len(w.data)
}

func (w *Windowed) Mean() float64 { return w.sum / float64(w.Len()) }
<commit_msg>Populate StartTime/StopTime in response structs<commit_after>package main

import (
	"errors"
	"fmt"
	"math"
	"strconv"

	"code.google.com/p/goprotobuf/proto"

	pb "github.com/dgryski/carbonzipper/carbonzipperpb"
)

// expression parser

type exprType int

const (
	etMetric exprType = iota
	etFunc
	etConst
)

type expr struct {
	target    string
	etype     exprType
	val       float64
	args      []*expr
	argString string
}

func (e *expr) metrics() []string {

	switch e.etype {
	case etMetric:
		return []string{e.target}
	case etConst:
		return nil
	case etFunc:
		var r []string
		for _, a := range e.args {
			r = append(r, a.metrics()...)
		}
		return r
	}

	return nil
}

func parseExpr(e string) (*expr, string, error) {

	if '0' <= e[0] && e[0] <= '9' {
		val, e, err := parseConst(e)
		return &expr{val: val, etype: etConst}, e, err
	}

	name, e := parseName(e)

	if e != "" && e[0] == '(' {
		exp := &expr{target: name, etype: etFunc}

		argString, args, e, err := parseArgList(e)
		exp.argString = argString
		exp.args = args

		return exp, e, err
	}

	return &expr{target: name}, e, nil
}

var (
	ErrMissingComma        = errors.New("missing comma")
	ErrUnexpectedCharacter = errors.New("unexpected character")
)

func parseArgList(e string) (string, []*expr, string, error) {

	var args []*expr

	if e[0] != '(' {
		panic("arg list should start with paren")
	}

	argString := e[1:]

	e = e[1:]

	for {
		var arg *expr
		var err error
		arg, e, err = parseExpr(e)
		if err != nil {
			return "", nil, "", err
		}
		args = append(args, arg)

		if e == "" {
			return "", nil, "", ErrMissingComma
		}

		if e[0] == ')' {
			return argString[:len(argString)-len(e)], args, e[1:], nil
		}

		if e[0] != ',' && e[0] != ' ' {
			return "", nil, "", ErrUnexpectedCharacter
		}

		e = e[1:]
	}
}

func isNameChar(r byte) bool {
	return false ||
		'a' <= r && r <= 'z' ||
		'A' <= r && r <= 'Z' ||
		'0' <= r && r <= '9' ||
		r == '.' || r == '_' || r == '-' || r == '*'
}

func isDigit(r byte) bool {
	return '0' <= r && r <= '9'
}

func parseConst(s string) (float64, string, error) {

	var i int
	for i < len(s) && isDigit(s[i]) {
		i++
	}

	v, err := strconv.ParseFloat(s[:i], 64)
	if err != nil {
		return 0, "", err
	}

	return v, s[i:], err
}

func parseName(s string) (string, string) {

	var i int
	for i < len(s) && isNameChar(s[i]) {
		i++
	}

	if i == len(s) {
		return s, ""
	}

	return s[:i], s[i:]
}

func evalExpr(e *expr, values map[string][]*pb.FetchResponse) []*pb.FetchResponse {

	switch e.etype {
	case etMetric:
		return values[e.target]
	case etConst:
		p := pb.FetchResponse{Name: proto.String(e.target), Values: []float64{e.val}}
		return []*pb.FetchResponse{&p}
	}

	// evaluate the function
	switch e.target {
	case "keepLastValue":

		arg := evalExpr(e.args[0], values)

		keep := -1

		if len(e.args) > 1 {

			n := evalExpr(e.args[1], values)
			if len(n) != 1 || len(n[0].Values) != 1 {
				// fail
				return nil
			}

			keep = int(n[0].Values[0])

		}

		var results []*pb.FetchResponse

		for _, a := range arg {
			r := pb.FetchResponse{
				Name:      proto.String(fmt.Sprintf("keepLastValue(%s,%d)", e.argString, keep)),
				Values:    make([]float64, len(a.Values)),
				IsAbsent:  make([]bool, len(a.Values)),
				StepTime:  a.StepTime,
				StartTime: a.StartTime,
				StopTime:  a.StopTime,
			}

			prev := math.NaN()
			missing := 0

			for i, v := range a.Values {
				if a.IsAbsent[i] {

					if (keep < 0 || missing < keep) && !math.IsNaN(prev) {
						r.Values[i] = prev
						missing++
					} else {
						r.IsAbsent[i] = true
					}

					continue
				}
				missing = 0
				prev = v
				r.Values[i] = v
			}
			results = append(results, &r)
		}
		return results

	case "movingAverage":
		arg := evalExpr(e.args[0], values)
		n := evalExpr(e.args[1], values)
		if len(n) != 1 || len(n[0].Values) != 1 {
			// fail
			return nil
		}

		windowSize := int(n[0].Values[0])

		var result []*pb.FetchResponse

		for _, a := range arg {
			w := &Windowed{data: make([]float64, windowSize)}
			r := pb.FetchResponse{
				Name:      proto.String(fmt.Sprintf("movingAverage(%s, %d)", *a.Name, windowSize)),
				Values:    make([]float64, len(a.Values)),
				IsAbsent:  make([]bool, len(a.Values)),
				StepTime:  a.StepTime,
				StartTime: a.StartTime,
				StopTime:  a.StopTime,
			}
			for i, v := range a.Values {
				if a.IsAbsent[i] {
					// make sure missing values are ignored
					v = 0
				}
				w.Push(v)
				r.Values[i] = w.Mean()
			}
			result = append(result, &r)
		}
		return result

	case "nonNegativeDerivative":
		arg := evalExpr(e.args[0], values)
		var result []*pb.FetchResponse
		for _, a := range arg {
			r := pb.FetchResponse{
				Name:      proto.String(fmt.Sprintf("nonNegativeDerivative(%s)", *a.Name)),
				Values:    make([]float64, len(a.Values)),
				IsAbsent:  make([]bool, len(a.Values)),
				StepTime:  a.StepTime,
				StartTime: a.StartTime,
				StopTime:  a.StopTime,
			}
			prev := a.Values[0]
			for i, v := range a.Values {
				if i == 0 || a.IsAbsent[i] {
					r.IsAbsent[i] = true
					continue
				}

				r.Values[i] = v - prev
				if r.Values[i] < 0 {
					r.Values[i] = 0
					r.IsAbsent[i] = true
				}
				prev = v
			}
			result = append(result, &r)
		}
		return result

	case "scale":
		arg := evalExpr(e.args[0], values)
		n := evalExpr(e.args[1], values)
		if len(n) != 1 || len(n[0].Values) != 1 {
			// fail
			return nil
		}

		scale := n[0].Values[0]

		var results []*pb.FetchResponse

		for _, a := range arg {
			r := pb.FetchResponse{
				Name:      proto.String(fmt.Sprintf("scale(%s,%g)", e.argString, scale)),
				Values:    make([]float64, len(a.Values)),
				IsAbsent:  make([]bool, len(a.Values)),
				StepTime:  a.StepTime,
				StartTime: a.StartTime,
				StopTime:  a.StopTime,
			}

			for i, v := range a.Values {
				if a.IsAbsent[i] {
					r.Values[i] = 0
					r.IsAbsent[i] = true
					continue
				}
				r.Values[i] = v * scale
			}
			results = append(results, &r)
		}
		return results

	case "scaleToSeconds":
		arg := evalExpr(e.args[0], values)
		n := evalExpr(e.args[1], values)
		if len(n) != 1 || len(n[0].Values) != 1 {
			// fail
			return nil
		}

		seconds := n[0].Values[0]

		var results []*pb.FetchResponse

		for _, a := range arg {
			r := pb.FetchResponse{
				Name:      proto.String(fmt.Sprintf("scale(%s,%g)", e.argString, seconds)),
				Values:    make([]float64, len(a.Values)),
				StepTime:  a.StepTime,
				IsAbsent:  make([]bool, len(a.Values)),
				StartTime: a.StartTime,
				StopTime:  a.StopTime,
			}

			factor := seconds / float64(*a.StepTime)

			for i, v := range a.Values {
				if a.IsAbsent[i] {
					r.Values[i] = 0
					r.IsAbsent[i] = true
					continue
				}
				r.Values[i] = v * factor
			}
			results = append(results, &r)
		}
		return results

	case "sum", "sumSeries":
		// TODO(dgryski): make sure the arrays are all the same 'size'
		var args []*pb.FetchResponse
		for _, arg := range e.args {
			a := evalExpr(arg, values)
			args = append(args, a...)
		}
		r := pb.FetchResponse{
			Name:      proto.String(fmt.Sprintf("sum(%s)", e.argString)),
			Values:    make([]float64, len(args[0].Values)),
			IsAbsent:  make([]bool, len(args[0].Values)),
			StepTime:  args[0].StepTime,
			StartTime: args[0].StartTime,
			StopTime:  args[0].StopTime,
		}
		for _, arg := range args {
			for i, v := range arg.Values {
				if arg.IsAbsent[i] {
					continue
				}
				r.Values[i] += v
			}
		}
		return []*pb.FetchResponse{&r}
	}

	return nil
}

// From github.com/dgryski/go-onlinestats
// Copied here because we don't need the rest of the package, and we only need
// a small part of this type

type Windowed struct {
	data   []float64
	head   int
	length int
	sum    float64
}

func (w *Windowed) Push(n float64) {
	old := w.data[w.head]

	w.length++

	w.data[w.head] = n
	w.head++
	if w.head >= len(w.data) {
		w.head = 0
	}

	w.sum -= old
	w.sum += n
}

func (w *Windowed) Len() int {
	if w.length < len(w.data) {
		return w.length
	}

	return len(w.data)
}

func (w *Windowed) Mean() float64 { return w.sum / float64(w.Len()) }
<|endoftext|>


<commit_before>type Ext2Sb struct {
	SInodesCount int32
	SBlocksCount int32
	SRBlocksCount int32
	SFreeBlocksCount int32
	SFreeInodesCount int32
	SFirstDataBlock int32
	SLogBlockSize int32
	SLogClusterSize int32
	SBlocksPerGroup int32
	SClustersPerGroup int32
	SInodesPerGroup int32
	SMtime int32
	SWtime int32
	SMntCount int16
	SMaxMntCount int16
	SMagic int16
	SState int16
	SErrors int16
	SMinorRevLevel int16
	SLastcheck int32
	SCheckinterval int32
	SCreatorOs int32
	SRevLevel int32
	SDefResUID int16
	SDefResGID int16
	SFirstIno int32
	SInodeSize int16
	SBlockGroupNr int16
	SFeatureCompat int32
	SFeatureIncompat int32
	SFeatureROCompat int32
	SUUID [16]byte
	SVolumeName [16]byte
	SLastMounted [64]byte
	SAlgorithmUsageBitmap int32
	SPreallocBlocks uint8
	SPreallocDirBlocks uint8
	SReservedGdtBlocks int16
	SJournalUUID [16]byte
	SJournalInum int32
	SJournalDev int32
	SLastOrphan int32
	SHashSeed [4]int32
	SDefHashVersion byte
	SJnlBackupType byte
	SDefaultMountOpts int32
	SFirstMetaBg int32
	SMkfsTime int32
	SJnlBlocks [17]int32
	SBlocksCountHi int32
	SRBlocksCountHi int32
	SFreeBlocksCountHi int32
	SMinExtraIsize int16
	SWantExtraIsize int16
	SFlags int32
	SRaidStride int16
	SMmpInterval int16
	SMmpBlock int64
	SRaidStripeWidth int32
	SLogGroupsPerFlex byte
	SChecksumType byte
	SReservedPad int16
	SKbytesWritten int64
	SSnapshotInum int32
	SSnapshotId int32
	SSnapshotRBlocksCount int64
	SSnapshotList int32
	SErrorCount int32
	SFirstErrorTime int32
	SFirstErrorIno int32
	SFirstErrorBlock int64
	SFirstErrorFunc [32]byte
	SFirstErrorLine int32
	SLastErrorTime int32
	SLastErrorIno int32
	SLastErrorLine int32
	SLastErrorBlock int64
	SLastErrorFunc [32]byte
	SMountOpts [64]byte
	SUsrQuotaInum int32
	SGrpQuotaInum int32
	SOverheadBlocks int32
	SBackupBgs [2]int32
	SReserved [106]int32
	SChecksum int32
}
<commit_msg>And yeah, __le32 and __le16 are unsigned, dur<commit_after>type Ext2Sb struct {
	SInodesCount uint32
	SBlocksCount uint32
	SRBlocksCount uint32
	SFreeBlocksCount uint32
	SFreeInodesCount uint32
	SFirstDataBlock uint32
	SLogBlockSize uint32
	SLogClusterSize uint32
	SBlocksPerGroup uint32
	SClustersPerGroup uint32
	SInodesPerGroup uint32
	SMtime uint32
	SWtime uint32
	SMntCount uint16
	SMaxMntCount uint16
	SMagic uint16
	SState uint16
	SErrors uint16
	SMinorRevLevel uint16
	SLastcheck uint32
	SCheckinterval uint32
	SCreatorOs uint32
	SRevLevel uint32
	SDefResUID uint16
	SDefResGID uint16
	SFirstIno uint32
	SInodeSize uint16
	SBlockGroupNr uint16
	SFeatureCompat uint32
	SFeatureIncompat uint32
	SFeatureROCompat uint32
	SUUID [16]byte
	SVolumeName [16]byte
	SLastMounted [64]byte
	SAlgorithmUsageBitmap uint32
	SPreallocBlocks uint8
	SPreallocDirBlocks uint8
	SReservedGdtBlocks uint16
	SJournalUUID [16]byte
	SJournalInum uint32
	SJournalDev uint32
	SLastOrphan uint32
	SHashSeed [4]uint32
	SDefHashVersion byte
	SJnlBackupType byte
	SDefaultMountOpts uint32
	SFirstMetaBg uint32
	SMkfsTime uint32
	SJnlBlocks [17]uint32
	SBlocksCountHi uint32
	SRBlocksCountHi uint32
	SFreeBlocksCountHi uint32
	SMinExtraIsize uint16
	SWantExtraIsize uint16
	SFlags uint32
	SRaidStride uint16
	SMmpInterval uint16
	SMmpBlock uint64
	SRaidStripeWidth uint32
	SLogGroupsPerFlex byte
	SChecksumType byte
	SReservedPad uint16
	SKbytesWritten uint64
	SSnapshotInum uint32
	SSnapshotId uint32
	SSnapshotRBlocksCount uint64
	SSnapshotList uint32
	SErrorCount uint32
	SFirstErrorTime uint32
	SFirstErrorIno uint32
	SFirstErrorBlock uint64
	SFirstErrorFunc [32]byte
	SFirstErrorLine uint32
	SLastErrorTime uint32
	SLastErrorIno uint32
	SLastErrorLine uint32
	SLastErrorBlock uint64
	SLastErrorFunc [32]byte
	SMountOpts [64]byte
	SUsrQuotaInum uint32
	SGrpQuotaInum uint32
	SOverheadBlocks uint32
	SBackupBgs [2]uint32
	SReserved [106]uint32
	SChecksum uint32
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes 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 mount

import (
	"errors"
	"os"
	"path/filepath"
	"sync"

	"github.com/golang/glog"
)

// FakeMounter implements mount.Interface for tests.
type FakeMounter struct {
	MountPoints []MountPoint
	Log         []FakeAction
	Filesystem  map[string]FileType
	// Some tests run things in parallel, make sure the mounter does not produce
	// any golang's DATA RACE warnings.
	mutex sync.Mutex
}

var _ Interface = &FakeMounter{}

// Values for FakeAction.Action
const FakeActionMount = "mount"
const FakeActionUnmount = "unmount"

// FakeAction objects are logged every time a fake mount or unmount is called.
type FakeAction struct {
	Action string // "mount" or "unmount"
	Target string // applies to both mount and unmount actions
	Source string // applies only to "mount" actions
	FSType string // applies only to "mount" actions
}

func (f *FakeMounter) ResetLog() {
	f.mutex.Lock()
	defer f.mutex.Unlock()

	f.Log = []FakeAction{}
}

func (f *FakeMounter) Mount(source string, target string, fstype string, options []string) error {
	f.mutex.Lock()
	defer f.mutex.Unlock()

	opts := []string{}

	for _, option := range options {
		// find 'bind' option
		if option == "bind" {
			// This is a bind-mount. In order to mimic linux behaviour, we must
			// use the original device of the bind-mount as the real source.
			// E.g. when mounted /dev/sda like this:
			//      $ mount /dev/sda /mnt/test
			//      $ mount -o bind /mnt/test /mnt/bound
			// then /proc/mount contains:
			// /dev/sda /mnt/test
			// /dev/sda /mnt/bound
			// (and not /mnt/test /mnt/bound)
			// I.e. we must use /dev/sda as source instead of /mnt/test in the
			// bind mount.
			for _, mnt := range f.MountPoints {
				if source == mnt.Path {
					source = mnt.Device
					break
				}
			}
		}
		// find 'ro' option
		if option == "ro" {
			// reuse MountPoint.Opts field to mark mount as readonly
			opts = append(opts, "ro")
		}
	}

	// If target is a symlink, get its absolute path
	absTarget, err := filepath.EvalSymlinks(target)
	if err != nil {
		absTarget = target
	}

	f.MountPoints = append(f.MountPoints, MountPoint{Device: source, Path: absTarget, Type: fstype, Opts: opts})
	glog.V(5).Infof("Fake mounter: mounted %s to %s", source, absTarget)
	f.Log = append(f.Log, FakeAction{Action: FakeActionMount, Target: absTarget, Source: source, FSType: fstype})
	return nil
}

func (f *FakeMounter) Unmount(target string) error {
	f.mutex.Lock()
	defer f.mutex.Unlock()

	// If target is a symlink, get its absolute path
	absTarget, err := filepath.EvalSymlinks(target)
	if err != nil {
		absTarget = target
	}

	newMountpoints := []MountPoint{}
	for _, mp := range f.MountPoints {
		if mp.Path == absTarget {
			glog.V(5).Infof("Fake mounter: unmounted %s from %s", mp.Device, absTarget)
			// Don't copy it to newMountpoints
			continue
		}
		newMountpoints = append(newMountpoints, MountPoint{Device: mp.Device, Path: mp.Path, Type: mp.Type})
	}
	f.MountPoints = newMountpoints
	f.Log = append(f.Log, FakeAction{Action: FakeActionUnmount, Target: absTarget})
	return nil
}

func (f *FakeMounter) List() ([]MountPoint, error) {
	f.mutex.Lock()
	defer f.mutex.Unlock()

	return f.MountPoints, nil
}

func (f *FakeMounter) IsMountPointMatch(mp MountPoint, dir string) bool {
	return mp.Path == dir
}

func (f *FakeMounter) IsNotMountPoint(dir string) (bool, error) {
	return IsNotMountPoint(f, dir)
}

func (f *FakeMounter) IsLikelyNotMountPoint(file string) (bool, error) {
	f.mutex.Lock()
	defer f.mutex.Unlock()

	_, err := os.Stat(file)
	if err != nil {
		return true, err
	}

	// If file is a symlink, get its absolute path
	absFile, err := filepath.EvalSymlinks(file)
	if err != nil {
		absFile = file
	}

	for _, mp := range f.MountPoints {
		if mp.Path == absFile {
			glog.V(5).Infof("isLikelyNotMountPoint for %s: mounted %s, false", file, mp.Path)
			return false, nil
		}
	}
	glog.V(5).Infof("isLikelyNotMountPoint for %s: true", file)
	return true, nil
}

func (f *FakeMounter) DeviceOpened(pathname string) (bool, error) {
	f.mutex.Lock()
	defer f.mutex.Unlock()

	for _, mp := range f.MountPoints {
		if mp.Device == pathname {
			return true, nil
		}
	}
	return false, nil
}

func (f *FakeMounter) PathIsDevice(pathname string) (bool, error) {
	return true, nil
}

func (f *FakeMounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) {
	return getDeviceNameFromMount(f, mountPath, pluginDir)
}

func (f *FakeMounter) MakeRShared(path string) error {
	return nil
}

func (f *FakeMounter) GetFileType(pathname string) (FileType, error) {
	if t, ok := f.Filesystem[pathname]; ok {
		return t, nil
	}
	return FileType("Directory"), nil
}

func (f *FakeMounter) MakeDir(pathname string) error {
	return nil
}

func (f *FakeMounter) MakeFile(pathname string) error {
	return nil
}

func (f *FakeMounter) ExistsPath(pathname string) (bool, error) {
	if _, ok := f.Filesystem[pathname]; ok {
		return true, nil
	}
	return false, nil
}

func (f *FakeMounter) EvalHostSymlinks(pathname string) (string, error) {
	return pathname, nil
}

func (f *FakeMounter) PrepareSafeSubpath(subPath Subpath) (newHostPath string, cleanupAction func(), err error) {
	return subPath.Path, nil, nil
}

func (f *FakeMounter) CleanSubPaths(podDir string, volumeName string) error {
	return nil
}
func (mounter *FakeMounter) SafeMakeDir(pathname string, base string, perm os.FileMode) error {
	return nil
}

func (f *FakeMounter) GetMountRefs(pathname string) ([]string, error) {
	realpath, err := filepath.EvalSymlinks(pathname)
	if err != nil {
		// Ignore error in FakeMounter, because we actually didn't create files.
		realpath = pathname
	}
	return getMountRefsByDev(f, realpath)
}

func (f *FakeMounter) GetFSGroup(pathname string) (int64, error) {
	return -1, errors.New("GetFSGroup not implemented")
}

func (f *FakeMounter) GetSELinuxSupport(pathname string) (bool, error) {
	return false, errors.New("GetSELinuxSupport not implemented")
}

func (f *FakeMounter) GetMode(pathname string) (os.FileMode, error) {
	return 0, errors.New("not implemented")
}
<commit_msg>Make sure we pass mount options while creating bind mounts<commit_after>/*
Copyright 2015 The Kubernetes 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 mount

import (
	"errors"
	"os"
	"path/filepath"
	"sync"

	"github.com/golang/glog"
)

// FakeMounter implements mount.Interface for tests.
type FakeMounter struct {
	MountPoints []MountPoint
	Log         []FakeAction
	Filesystem  map[string]FileType
	// Some tests run things in parallel, make sure the mounter does not produce
	// any golang's DATA RACE warnings.
	mutex sync.Mutex
}

var _ Interface = &FakeMounter{}

// Values for FakeAction.Action
const FakeActionMount = "mount"
const FakeActionUnmount = "unmount"

// FakeAction objects are logged every time a fake mount or unmount is called.
type FakeAction struct {
	Action string // "mount" or "unmount"
	Target string // applies to both mount and unmount actions
	Source string // applies only to "mount" actions
	FSType string // applies only to "mount" actions
}

func (f *FakeMounter) ResetLog() {
	f.mutex.Lock()
	defer f.mutex.Unlock()

	f.Log = []FakeAction{}
}

func (f *FakeMounter) Mount(source string, target string, fstype string, options []string) error {
	f.mutex.Lock()
	defer f.mutex.Unlock()

	opts := []string{}

	for _, option := range options {
		// find 'bind' option
		if option == "bind" {
			// This is a bind-mount. In order to mimic linux behaviour, we must
			// use the original device of the bind-mount as the real source.
			// E.g. when mounted /dev/sda like this:
			//      $ mount /dev/sda /mnt/test
			//      $ mount -o bind /mnt/test /mnt/bound
			// then /proc/mount contains:
			// /dev/sda /mnt/test
			// /dev/sda /mnt/bound
			// (and not /mnt/test /mnt/bound)
			// I.e. we must use /dev/sda as source instead of /mnt/test in the
			// bind mount.
			for _, mnt := range f.MountPoints {
				if source == mnt.Path {
					source = mnt.Device
					break
				}
			}
		}
		// reuse MountPoint.Opts field to mark mount as readonly
		opts = append(opts, option)
	}

	// If target is a symlink, get its absolute path
	absTarget, err := filepath.EvalSymlinks(target)
	if err != nil {
		absTarget = target
	}
	f.MountPoints = append(f.MountPoints, MountPoint{Device: source, Path: absTarget, Type: fstype, Opts: opts})
	glog.V(5).Infof("Fake mounter: mounted %s to %s", source, absTarget)
	f.Log = append(f.Log, FakeAction{Action: FakeActionMount, Target: absTarget, Source: source, FSType: fstype})
	return nil
}

func (f *FakeMounter) Unmount(target string) error {
	f.mutex.Lock()
	defer f.mutex.Unlock()

	// If target is a symlink, get its absolute path
	absTarget, err := filepath.EvalSymlinks(target)
	if err != nil {
		absTarget = target
	}

	newMountpoints := []MountPoint{}
	for _, mp := range f.MountPoints {
		if mp.Path == absTarget {
			glog.V(5).Infof("Fake mounter: unmounted %s from %s", mp.Device, absTarget)
			// Don't copy it to newMountpoints
			continue
		}
		newMountpoints = append(newMountpoints, MountPoint{Device: mp.Device, Path: mp.Path, Type: mp.Type})
	}
	f.MountPoints = newMountpoints
	f.Log = append(f.Log, FakeAction{Action: FakeActionUnmount, Target: absTarget})
	return nil
}

func (f *FakeMounter) List() ([]MountPoint, error) {
	f.mutex.Lock()
	defer f.mutex.Unlock()

	return f.MountPoints, nil
}

func (f *FakeMounter) IsMountPointMatch(mp MountPoint, dir string) bool {
	return mp.Path == dir
}

func (f *FakeMounter) IsNotMountPoint(dir string) (bool, error) {
	return IsNotMountPoint(f, dir)
}

func (f *FakeMounter) IsLikelyNotMountPoint(file string) (bool, error) {
	f.mutex.Lock()
	defer f.mutex.Unlock()

	_, err := os.Stat(file)
	if err != nil {
		return true, err
	}

	// If file is a symlink, get its absolute path
	absFile, err := filepath.EvalSymlinks(file)
	if err != nil {
		absFile = file
	}

	for _, mp := range f.MountPoints {
		if mp.Path == absFile {
			glog.V(5).Infof("isLikelyNotMountPoint for %s: mounted %s, false", file, mp.Path)
			return false, nil
		}
	}
	glog.V(5).Infof("isLikelyNotMountPoint for %s: true", file)
	return true, nil
}

func (f *FakeMounter) DeviceOpened(pathname string) (bool, error) {
	f.mutex.Lock()
	defer f.mutex.Unlock()

	for _, mp := range f.MountPoints {
		if mp.Device == pathname {
			return true, nil
		}
	}
	return false, nil
}

func (f *FakeMounter) PathIsDevice(pathname string) (bool, error) {
	return true, nil
}

func (f *FakeMounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) {
	return getDeviceNameFromMount(f, mountPath, pluginDir)
}

func (f *FakeMounter) MakeRShared(path string) error {
	return nil
}

func (f *FakeMounter) GetFileType(pathname string) (FileType, error) {
	if t, ok := f.Filesystem[pathname]; ok {
		return t, nil
	}
	return FileType("Directory"), nil
}

func (f *FakeMounter) MakeDir(pathname string) error {
	return nil
}

func (f *FakeMounter) MakeFile(pathname string) error {
	return nil
}

func (f *FakeMounter) ExistsPath(pathname string) (bool, error) {
	if _, ok := f.Filesystem[pathname]; ok {
		return true, nil
	}
	return false, nil
}

func (f *FakeMounter) EvalHostSymlinks(pathname string) (string, error) {
	return pathname, nil
}

func (f *FakeMounter) PrepareSafeSubpath(subPath Subpath) (newHostPath string, cleanupAction func(), err error) {
	return subPath.Path, nil, nil
}

func (f *FakeMounter) CleanSubPaths(podDir string, volumeName string) error {
	return nil
}
func (mounter *FakeMounter) SafeMakeDir(pathname string, base string, perm os.FileMode) error {
	return nil
}

func (f *FakeMounter) GetMountRefs(pathname string) ([]string, error) {
	realpath, err := filepath.EvalSymlinks(pathname)
	if err != nil {
		// Ignore error in FakeMounter, because we actually didn't create files.
		realpath = pathname
	}
	return getMountRefsByDev(f, realpath)
}

func (f *FakeMounter) GetFSGroup(pathname string) (int64, error) {
	return -1, errors.New("GetFSGroup not implemented")
}

func (f *FakeMounter) GetSELinuxSupport(pathname string) (bool, error) {
	return false, errors.New("GetSELinuxSupport not implemented")
}

func (f *FakeMounter) GetMode(pathname string) (os.FileMode, error) {
	return 0, errors.New("not implemented")
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"
)

type options struct {
	repeatRows, limit int
	source            string
}

var (
	curFile *os.File
	prefix  string
)

func processCmdLineFlags(opts *options) {
	flag.StringVar(&(*opts).source, "source", "", "Name of the source file (if not using stdin)")
	flag.IntVar(&(*opts).repeatRows, "repeat", 1, "How many rows to repeat on subsequent files")
	flag.IntVar(&(*opts).limit, "limit", 1000, "Number of rows per output file (not counting repeated/header rows)")
	flag.Parse()

	if opts.source != "" {
		prefix = strings.TrimSuffix(opts.source, filepath.Ext(opts.source))
	} else {
		prefix = "file"
	}
}

func scan(what io.Reader, opts *options) {
	defer curFile.Close()
	scanner, i, repeats := bufio.NewScanner(what), 0, []string{}
	for i = 0; i < opts.repeatRows && scanner.Scan(); i++ {
		repeats = append(repeats, scanner.Text())
	}

	i = 0
	for scanner.Scan() {
		write(scanner.Text(), i, &repeats, opts.limit)
		i++
	}

	if err := scanner.Err(); err != nil {
		log.Fatal(err)
	}
}

func write(line string, i int, repeats *[]string, limit int) {
	if i%limit == 0 {
		if curFile != nil {
			curFile.Close()
		}

		curFile = createFile(fmt.Sprintf("%s_%02d.csv", prefix, (i/limit)+1))
		for _, repeat := range *repeats {
			fmt.Fprintln(curFile, repeat)
		}
	}

	fmt.Fprintln(curFile, line)
}

func main() {
	opts := new(options)
	if processCmdLineFlags(opts); stdinReady() {
		scan(os.Stdin, opts)
	} else if opts.source != "" {
		f := openFile(opts.source)
		defer f.Close()
		scan(f, opts)
	} else {
		fmt.Println("No source available, please see help (also available with -h):")
		flag.PrintDefaults()
	}
}
<commit_msg>A little refactoring for clarity<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"
)

type options struct {
	repeatRows, limit int
	source            string
}

var (
	curFile *os.File
	prefix  string
)

func processCmdLineFlags(opts *options) {
	flag.StringVar(&(*opts).source, "source", "", "Name of the source file (if not using stdin)")
	flag.IntVar(&(*opts).repeatRows, "repeat", 1, "How many rows to repeat on subsequent files")
	flag.IntVar(&(*opts).limit, "limit", 1000, "Number of rows per output file (not counting repeated/header rows)")
	flag.Parse()

	if opts.source != "" {
		prefix = strings.TrimSuffix(opts.source, filepath.Ext(opts.source))
	} else {
		prefix = "file"
	}
}

func scan(what io.Reader, opts *options) {
	defer curFile.Close()
	scanner, lineno, repeats := bufio.NewScanner(what), 0, []string{}
	for j := 0; j < opts.repeatRows && scanner.Scan(); j++ {
		repeats = append(repeats, scanner.Text())
	}

	for scanner.Scan() {
		write(scanner.Text(), lineno, &repeats, opts.limit)
		lineno++
	}

	if err := scanner.Err(); err != nil {
		log.Fatal(err)
	}
}

func write(line string, lineno int, repeats *[]string, limit int) {
	if lineno%limit == 0 {
		if curFile != nil {
			curFile.Close()
		}

		curFile = createFile(fmt.Sprintf("%s_%02d.csv", prefix, (lineno/limit)+1))
		for _, repeat := range *repeats {
			fmt.Fprintln(curFile, repeat)
		}
	}

	fmt.Fprintln(curFile, line)
}

func main() {
	opts := new(options)
	if processCmdLineFlags(opts); stdinReady() {
		scan(os.Stdin, opts)
	} else if opts.source != "" {
		f := openFile(opts.source)
		defer f.Close()
		scan(f, opts)
	} else {
		fmt.Println("No source available, please see help (also available with -h):")
		flag.PrintDefaults()
	}
}
<|endoftext|>


<commit_before>package clui

import (
	term "github.com/nsf/termbox-go"
)

// ThumbPosition returns a scrollbar thumb position depending
// on currently active item(itemNo), total number of items
// (itemCount), and length/height of the scrollbar(length)
// including arrows. Returns position in interval of (1..lenght-2)
// or -1 if the thumb is not visible
func ThumbPosition(itemNo, itemCount, length int) int {
	length -= 2
	if itemNo < 0 {
		return -1
	}
	if itemNo >= itemCount-1 {
		return length - 1
	}

	if length < 4 {
		return 0
	}

	ydiff := int(float32(itemNo) / float32(itemCount-1.0) * float32(length-1))
	return ydiff
}

// ItemByThumbPosition calculates item number by scrollbar
// thumb position. Position - thumb position inside scrollbar,
// itemCount - total number of items, lenght - lenght or heigth
// of scrollbar. Return -1 if it is not possible to calculate:
// e.g, itemCount equals zero
func ItemByThumbPosition(position, itemCount, length int) int {
	length -= 2
	if position < 1 {
		return -1
	}
	if itemCount < 1 {
		return -1
	}
	if itemCount == 1 {
		return 0
	}

	newPos := int(float32(itemCount-1)*float32(position-1)/float32(length-1) + 0.9)

	if newPos < 0 {
		newPos = 0
	} else if newPos >= itemCount {
		newPos = itemCount - 1
	}

	return newPos
}

// ChildAt returns the children of parent control that is at absolute
// coordinates x, y. Returns nil if x, y are outside parent control and
// returns parent if no child is at x, y
func ChildAt(parent Control, x, y int) Control {
	px, py := parent.Pos()
	pw, ph := parent.Size()
	if px > x || py > y || px+pw <= x || py+ph <= y {
		return nil
	}

	if len(parent.Children()) == 0 {
		return parent
	}

	var ctrl Control
	ctrl = parent
	for _, child := range parent.Children() {
		check := ChildAt(child, x, y)
		if check != nil {
			ctrl = check
			break
		}
	}

	return ctrl
}

// DeactivateControls makes all children of parent inactive
func DeactivateControls(parent Control) {
	for _, ctrl := range parent.Children() {
		if ctrl.Active() {
			ctrl.SetActive(false)
			ctrl.ProcessEvent(Event{Type: EventActivate, X: 0})
		}

		DeactivateControls(ctrl)
	}
}

// ActivateControl makes control active and disables all other children of
// the parent. Returns true if control was found and activated
func ActivateControl(parent, control Control) bool {
	DeactivateControls(parent)
	res := false
	ctrl := FindChild(parent, control)
	if ctrl != nil {
		res = true
		if !ctrl.Active() {
			ctrl.ProcessEvent(Event{Type: EventActivate, X: 1})
			ctrl.SetActive(true)
		}
	}

	return res
}

// FindChild returns control if it is a child of the parent and nil otherwise
func FindChild(parent, control Control) Control {
	var res Control

	if parent == control {
		return parent
	}

	for _, ctrl := range parent.Children() {
		if ctrl == control {
			res = ctrl
			break
		}

		res = FindChild(ctrl, control)
		if res != nil {
			break
		}
	}

	return res
}

// IsMouseClickEvent returns if a user action can be treated as mouse click.
func IsMouseClickEvent(ev Event) bool {
	if ev.Type == EventClick {
		return true
	}
	if ev.Type == EventMouse && ev.Key == term.MouseLeft {
		return true
	}

	return false
}

// FindFirstControl returns the first child for that fn returns true.
// The function is used to find active or tab-stop control
func FindFirstControl(parent Control, fn func(Control) bool) Control {
	linear := getLinearControlList(parent, fn)
	if len(linear) == 0 {
		return nil
	}

	return linear[0]
}

// FindLastControl returns the first child for that fn returns true.
// The function is used by TAB processing method if a user goes backwards
// with TAB key - not supported now
func FindLastControl(parent Control, fn func(Control) bool) Control {
	linear := getLinearControlList(parent, fn)

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

	return linear[len(linear)-1]
}

// ActiveControl returns the active child of the parent or nil if no child is
// active
func ActiveControl(parent Control) Control {
	fnActive := func(c Control) bool {
		return c.Active()
	}
	return FindFirstControl(parent, fnActive)
}

// FindFirstActiveControl returns the first active control of a parent
func FindFirstActiveControl(parent Control) Control {
	for _, curr := range getLinearControlList(parent, nil) {
		if curr.Active() {
			return curr
		}
	}
	return nil
}

func getLinearControlList(parent Control, fn func(Control) bool) []Control {
	result := []Control{}

	for _, curr := range parent.Children() {
		if fn(curr) {
			result = append(result, curr)
		}

		if len(curr.Children()) == 0 {
			continue
		}

		ch := getLinearControlList(curr, fn)
		if len(ch) != 0 {
			result = append(result, ch...)
		}
	}

	return result
}

// NextControl returns the next or previous child (depends on next parameter)
// that has tab-stop feature on. Used by library when processing TAB key
func NextControl(parent Control, curr Control, next bool) Control {
	fnTab := func(c Control) bool {
		return c.TabStop() && c.Visible() && c.Enabled()
	}

	linear := getLinearControlList(parent, fnTab)

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

	var pIndex, nIndex int

	for i, ch := range linear {
		if ch != curr {
			continue
		}

		pIndex = i - 1
		nIndex = i + 1
		break
	}

	if nIndex > len(linear)-1 {
		nIndex = 0
	}

	if pIndex < 0 {
		pIndex = len(linear) - 1
	}

	if next {
		return linear[nIndex]
	} else {
		return linear[pIndex]
	}
}

// SendEventToChild tries to find a child control that should recieve the evetn
// For mouse click events it looks for a control at coordinates of event,
// makes it active, and then sends the event to it.
// If it is not mouse click event then it looks for the first active child and
// sends the event to it if it is not nil
func SendEventToChild(parent Control, ev Event) bool {
	var child Control
	if IsMouseClickEvent(ev) {
		child = ChildAt(parent, ev.X, ev.Y)
		if child != nil && !child.Active() {
			ActivateControl(parent, child)
		}
	} else {
		child = ActiveControl(parent)
	}

	if child != nil && child != parent {
		return child.ProcessEvent(ev)
	}

	return false
}
<commit_msg>fix getLinearControlList() fn callback call<commit_after>package clui

import (
	term "github.com/nsf/termbox-go"
)

// ThumbPosition returns a scrollbar thumb position depending
// on currently active item(itemNo), total number of items
// (itemCount), and length/height of the scrollbar(length)
// including arrows. Returns position in interval of (1..lenght-2)
// or -1 if the thumb is not visible
func ThumbPosition(itemNo, itemCount, length int) int {
	length -= 2
	if itemNo < 0 {
		return -1
	}
	if itemNo >= itemCount-1 {
		return length - 1
	}

	if length < 4 {
		return 0
	}

	ydiff := int(float32(itemNo) / float32(itemCount-1.0) * float32(length-1))
	return ydiff
}

// ItemByThumbPosition calculates item number by scrollbar
// thumb position. Position - thumb position inside scrollbar,
// itemCount - total number of items, lenght - lenght or heigth
// of scrollbar. Return -1 if it is not possible to calculate:
// e.g, itemCount equals zero
func ItemByThumbPosition(position, itemCount, length int) int {
	length -= 2
	if position < 1 {
		return -1
	}
	if itemCount < 1 {
		return -1
	}
	if itemCount == 1 {
		return 0
	}

	newPos := int(float32(itemCount-1)*float32(position-1)/float32(length-1) + 0.9)

	if newPos < 0 {
		newPos = 0
	} else if newPos >= itemCount {
		newPos = itemCount - 1
	}

	return newPos
}

// ChildAt returns the children of parent control that is at absolute
// coordinates x, y. Returns nil if x, y are outside parent control and
// returns parent if no child is at x, y
func ChildAt(parent Control, x, y int) Control {
	px, py := parent.Pos()
	pw, ph := parent.Size()
	if px > x || py > y || px+pw <= x || py+ph <= y {
		return nil
	}

	if len(parent.Children()) == 0 {
		return parent
	}

	var ctrl Control
	ctrl = parent
	for _, child := range parent.Children() {
		check := ChildAt(child, x, y)
		if check != nil {
			ctrl = check
			break
		}
	}

	return ctrl
}

// DeactivateControls makes all children of parent inactive
func DeactivateControls(parent Control) {
	for _, ctrl := range parent.Children() {
		if ctrl.Active() {
			ctrl.SetActive(false)
			ctrl.ProcessEvent(Event{Type: EventActivate, X: 0})
		}

		DeactivateControls(ctrl)
	}
}

// ActivateControl makes control active and disables all other children of
// the parent. Returns true if control was found and activated
func ActivateControl(parent, control Control) bool {
	DeactivateControls(parent)
	res := false
	ctrl := FindChild(parent, control)
	if ctrl != nil {
		res = true
		if !ctrl.Active() {
			ctrl.ProcessEvent(Event{Type: EventActivate, X: 1})
			ctrl.SetActive(true)
		}
	}

	return res
}

// FindChild returns control if it is a child of the parent and nil otherwise
func FindChild(parent, control Control) Control {
	var res Control

	if parent == control {
		return parent
	}

	for _, ctrl := range parent.Children() {
		if ctrl == control {
			res = ctrl
			break
		}

		res = FindChild(ctrl, control)
		if res != nil {
			break
		}
	}

	return res
}

// IsMouseClickEvent returns if a user action can be treated as mouse click.
func IsMouseClickEvent(ev Event) bool {
	if ev.Type == EventClick {
		return true
	}
	if ev.Type == EventMouse && ev.Key == term.MouseLeft {
		return true
	}

	return false
}

// FindFirstControl returns the first child for that fn returns true.
// The function is used to find active or tab-stop control
func FindFirstControl(parent Control, fn func(Control) bool) Control {
	linear := getLinearControlList(parent, fn)
	if len(linear) == 0 {
		return nil
	}

	return linear[0]
}

// FindLastControl returns the first child for that fn returns true.
// The function is used by TAB processing method if a user goes backwards
// with TAB key - not supported now
func FindLastControl(parent Control, fn func(Control) bool) Control {
	linear := getLinearControlList(parent, fn)

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

	return linear[len(linear)-1]
}

// ActiveControl returns the active child of the parent or nil if no child is
// active
func ActiveControl(parent Control) Control {
	fnActive := func(c Control) bool {
		return c.Active()
	}
	return FindFirstControl(parent, fnActive)
}

// FindFirstActiveControl returns the first active control of a parent
func FindFirstActiveControl(parent Control) Control {
	for _, curr := range getLinearControlList(parent, nil) {
		if curr.Active() {
			return curr
		}
	}
	return nil
}

func getLinearControlList(parent Control, fn func(Control) bool) []Control {
	result := []Control{}

	for _, curr := range parent.Children() {
		if fn != nil && fn(curr) {
			result = append(result, curr)
		}

		if len(curr.Children()) == 0 {
			continue
		}

		ch := getLinearControlList(curr, fn)
		if len(ch) != 0 {
			result = append(result, ch...)
		}
	}

	return result
}

// NextControl returns the next or previous child (depends on next parameter)
// that has tab-stop feature on. Used by library when processing TAB key
func NextControl(parent Control, curr Control, next bool) Control {
	fnTab := func(c Control) bool {
		return c.TabStop() && c.Visible() && c.Enabled()
	}

	linear := getLinearControlList(parent, fnTab)

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

	var pIndex, nIndex int

	for i, ch := range linear {
		if ch != curr {
			continue
		}

		pIndex = i - 1
		nIndex = i + 1
		break
	}

	if nIndex > len(linear)-1 {
		nIndex = 0
	}

	if pIndex < 0 {
		pIndex = len(linear) - 1
	}

	if next {
		return linear[nIndex]
	} else {
		return linear[pIndex]
	}
}

// SendEventToChild tries to find a child control that should recieve the evetn
// For mouse click events it looks for a control at coordinates of event,
// makes it active, and then sends the event to it.
// If it is not mouse click event then it looks for the first active child and
// sends the event to it if it is not nil
func SendEventToChild(parent Control, ev Event) bool {
	var child Control
	if IsMouseClickEvent(ev) {
		child = ChildAt(parent, ev.X, ev.Y)
		if child != nil && !child.Active() {
			ActivateControl(parent, child)
		}
	} else {
		child = ActiveControl(parent)
	}

	if child != nil && child != parent {
		return child.ProcessEvent(ev)
	}

	return false
}
<|endoftext|>


<commit_before>package ctxerr

import (
	"fmt"

	"github.com/fatih/color"
)

func init() {
	color.NoColor = true
}

func ExamplePoint() {
	fmt.Println(New("00100", Point(1, 3)))
	// Output:
	// 1:3:
	// 1 | 00100
	//   |   ^
}

func ExampleRange() {
	fmt.Println(New("01110", Range(1, 2, 1, 4)))
	// Output:
	// 1:2-4:
	// 1 | 01110
	//   |  ^^^
}

func ExampleRange_multiline() {
	fmt.Println(New("00001\n11110", Range(1, 5, 2, 4)))
	// Output:
	// 1:5-2:4:
	// 1 | 00001
	//   |     ^
	// 2 | 11110
	//   | ^^^^
}

func ExampleCtx_String_hint() {
	ctx := New("010101102110", Point(1, 9))
	ctx.Hint = "don't worry, bender"
	fmt.Println(ctx)
	// Output:
	// 1:9:
	// 1 | 010101102110
	//   |         ^ don't worry, bender
}

func ExampleCtx_String_contextLimited() {
	in := `1st
2nd
3rd has an error
4th
5th`
	ctx := New(in, Point(3, 12))
	ctx.Context = 1
	fmt.Println(ctx)
	// Output:
	// 3:12:
	// 2 | 2nd
	// 3 | 3rd has an error
	//   |            ^
	// 4 | 4th
}

func ExampleCtx_String_contextLimitedMultiline() {
	in := `1st
2nd
3rd has an error
4th still has an error
5th`
	ctx := New(in, Range(3, 1, 4, 22))
	ctx.Context = 1
	fmt.Println(ctx)
	// Output:
	// 3:1-4:22:
	// 2 | 2nd
	// 3 | 3rd has an error
	//   | ^^^^^^^^^^^^^^^^
	// 4 | 4th still has an error
	//   | ^^^^^^^^^^^^^^^^^^^^^^
	// 5 | 5th
}

func ExampleCtx_String_contextAll() {
	in := `1st
2nd
3rd has an error
4th
5th`
	ctx := New(in, Point(3, 12))
	ctx.Context = -1
	fmt.Println(ctx)
	// Output:
	// 3:12:
	// 1 | 1st
	// 2 | 2nd
	// 3 | 3rd has an error
	//   |            ^
	// 4 | 4th
	// 5 | 5th
}

func ExampleCtx_String_path() {
	ctx := New("42", Point(1, 1))
	ctx.Path = "/tmp/ctxerr/answer.txt"
	fmt.Println(ctx)
	// Output:
	// /tmp/ctxerr/answer.txt:1:1:
	// 1 | 42
	//   | ^
}

func ExampleCtx_Err() {
	err := New("ab!cd", Point(1, 3))
	err.Err = fmt.Errorf("not a letter")
	fmt.Println(err)
	// Output:
	// not a letter
	// 1:3:
	// 1 | ab!cd
	//   |   ^
}

func ExampleCtx_String_tabwidth() {
	in := "\tfoo\tbar"
	ctx := New(in, Point(1, 5))
	fmt.Println(ctx)
	// Output:
	// 1:5:
	// 1 |     foo    bar
	//   |        ^^^^
}

func ExampleNewFromPath() {
	cerr, err := NewFromPath("LICENSE", Range(1, 1, 1, 3))
	if err != nil {
		fmt.Println(err)
		return
	}
	cerr.Context = 0
	fmt.Println(cerr)
	// Output:
	// LICENSE:1:1-3:
	// 1 | MIT License
	//   | ^^^
}
<commit_msg>Test NewFromPath with missing file<commit_after>package ctxerr

import (
	"fmt"
	"os"
	"testing"

	"github.com/fatih/color"
)

func init() {
	color.NoColor = true
}

func ExamplePoint() {
	fmt.Println(New("00100", Point(1, 3)))
	// Output:
	// 1:3:
	// 1 | 00100
	//   |   ^
}

func ExampleRange() {
	fmt.Println(New("01110", Range(1, 2, 1, 4)))
	// Output:
	// 1:2-4:
	// 1 | 01110
	//   |  ^^^
}

func ExampleRange_multiline() {
	fmt.Println(New("00001\n11110", Range(1, 5, 2, 4)))
	// Output:
	// 1:5-2:4:
	// 1 | 00001
	//   |     ^
	// 2 | 11110
	//   | ^^^^
}

func ExampleCtx_String_hint() {
	ctx := New("010101102110", Point(1, 9))
	ctx.Hint = "don't worry, bender"
	fmt.Println(ctx)
	// Output:
	// 1:9:
	// 1 | 010101102110
	//   |         ^ don't worry, bender
}

func ExampleCtx_String_contextLimited() {
	in := `1st
2nd
3rd has an error
4th
5th`
	ctx := New(in, Point(3, 12))
	ctx.Context = 1
	fmt.Println(ctx)
	// Output:
	// 3:12:
	// 2 | 2nd
	// 3 | 3rd has an error
	//   |            ^
	// 4 | 4th
}

func ExampleCtx_String_contextLimitedMultiline() {
	in := `1st
2nd
3rd has an error
4th still has an error
5th`
	ctx := New(in, Range(3, 1, 4, 22))
	ctx.Context = 1
	fmt.Println(ctx)
	// Output:
	// 3:1-4:22:
	// 2 | 2nd
	// 3 | 3rd has an error
	//   | ^^^^^^^^^^^^^^^^
	// 4 | 4th still has an error
	//   | ^^^^^^^^^^^^^^^^^^^^^^
	// 5 | 5th
}

func ExampleCtx_String_contextAll() {
	in := `1st
2nd
3rd has an error
4th
5th`
	ctx := New(in, Point(3, 12))
	ctx.Context = -1
	fmt.Println(ctx)
	// Output:
	// 3:12:
	// 1 | 1st
	// 2 | 2nd
	// 3 | 3rd has an error
	//   |            ^
	// 4 | 4th
	// 5 | 5th
}

func ExampleCtx_String_path() {
	ctx := New("42", Point(1, 1))
	ctx.Path = "/tmp/ctxerr/answer.txt"
	fmt.Println(ctx)
	// Output:
	// /tmp/ctxerr/answer.txt:1:1:
	// 1 | 42
	//   | ^
}

func ExampleCtx_Err() {
	err := New("ab!cd", Point(1, 3))
	err.Err = fmt.Errorf("not a letter")
	fmt.Println(err)
	// Output:
	// not a letter
	// 1:3:
	// 1 | ab!cd
	//   |   ^
}

func ExampleCtx_String_tabwidth() {
	in := "\tfoo\tbar"
	ctx := New(in, Point(1, 5))
	fmt.Println(ctx)
	// Output:
	// 1:5:
	// 1 |     foo    bar
	//   |        ^^^^
}

func ExampleNewFromPath() {
	cerr, err := NewFromPath("LICENSE", Range(1, 1, 1, 3))
	if err != nil {
		fmt.Println(err)
		return
	}
	cerr.Context = 0
	fmt.Println(cerr)
	// Output:
	// LICENSE:1:1-3:
	// 1 | MIT License
	//   | ^^^
}

func TestNewFromPath_NoSuchFile(t *testing.T) {
	_, err := NewFromPath("foo.txt", Point(1, 1))
	if err == nil {
		t.Error("expected error, got nil")
	}
	if !os.IsNotExist(err) {
		t.Errorf("expected %#v, got %#v", os.ErrNotExist.Error(), err.Error())
	}
}
<|endoftext|>


<commit_before>package mathgl

import "math"

func Rotate2D(angle float64) Matrix {
	sin,cos := math.Sin(angle), math.Cos(angle)
	return *unsafeMatrixFromSlice(ScalarSlice([]interface{}{cos, -sin, sin, cos}, FLOAT64), FLOAT64, 2, 2)
}

// Rotates about X-axis
// [1 0 0]
// [0 c -s]
// [0 s c ]
func Rotate3DX(angle float64) Matrix {
	sin,cos := math.Sin(angle), math.Cos(angle)
	return *unsafeMatrixFromSlice(ScalarSlice([]interface{}{1,0,0,0,cos, -sin, 0, sin, cos}, FLOAT64), FLOAT64, 3, 3)
}

// Rotates around Y-axis
// [c 0 s]
// [0 1 0]
// [s 0 c ]
func Rotate3DY(angle float64) Matrix {
	sin,cos := math.Sin(angle), math.Cos(angle)
	return *unsafeMatrixFromSlice(ScalarSlice([]interface{}{cos,0,sin,0,1, 0, -sin, 0, cos}, FLOAT64), FLOAT64, 3, 3)
}

// Rotates about Z-axis
// [c -s 0]
// [s c 0]
// [0 0 1 ]
func Rotate3DZ(angle float64) Matrix {
	sin,cos := math.Sin(angle), math.Cos(angle)
	return *unsafeMatrixFromSlice(ScalarSlice([]interface{}{cos,-sin,0,-sin,cos,0, 0, 0, 1}, FLOAT64), FLOAT64, 3, 3)
}

// Returns a 2D homogeneous (3x3) transformation matrix
func Transform2D(Tx, Ty float64) Matrix {
	return *unsafeMatrixFromSlice(ScalarSlice([]interface{}{1,0,Tx,0,1,Ty,0,0, 1}, FLOAT64), FLOAT64, 3, 3)
}

// Returns a 3D homogeneous (4x4) transformation matrix
func Transform3D(Tx, Ty, Tz float64) Matrix {
	return *unsafeMatrixFromSlice(ScalarSlice([]interface{}{1,0,0,Tx,0,1,0,Ty,0,0, 1,Tz,0,0,0,1}, FLOAT64), FLOAT64, 3, 3)
}

// TODO: Quaternion rotation<commit_msg>Minor bugfix<commit_after>package mathgl

import "math"

func Rotate2D(angle float64) Matrix {
	sin,cos := math.Sin(angle), math.Cos(angle)
	return *unsafeMatrixFromSlice(ScalarSlice([]interface{}{cos, -sin, sin, cos}, FLOAT64), FLOAT64, 2, 2)
}

// Rotates about X-axis
// [1 0 0]
// [0 c -s]
// [0 s c ]
func Rotate3DX(angle float64) Matrix {
	sin,cos := math.Sin(angle), math.Cos(angle)
	return *unsafeMatrixFromSlice(ScalarSlice([]interface{}{1,0,0,0,cos, -sin, 0, sin, cos}, FLOAT64), FLOAT64, 3, 3)
}

// Rotates around Y-axis
// [c 0 s]
// [0 1 0]
// [s 0 c ]
func Rotate3DY(angle float64) Matrix {
	sin,cos := math.Sin(angle), math.Cos(angle)
	return *unsafeMatrixFromSlice(ScalarSlice([]interface{}{cos,0,sin,0,1, 0, -sin, 0, cos}, FLOAT64), FLOAT64, 3, 3)
}

// Rotates about Z-axis
// [c -s 0]
// [s c 0]
// [0 0 1 ]
func Rotate3DZ(angle float64) Matrix {
	sin,cos := math.Sin(angle), math.Cos(angle)
	return *unsafeMatrixFromSlice(ScalarSlice([]interface{}{cos,-sin,0,-sin,cos,0, 0, 0, 1}, FLOAT64), FLOAT64, 3, 3)
}

// Returns a 2D homogeneous (3x3) transformation matrix
func Transform2D(Tx, Ty float64) Matrix {
	return *unsafeMatrixFromSlice(ScalarSlice([]interface{}{1,0,Tx,0,1,Ty,0,0, 1}, FLOAT64), FLOAT64, 3, 3)
}

// Returns a 3D homogeneous (4x4) transformation matrix
func Transform3D(Tx, Ty, Tz float64) Matrix {
	return *unsafeMatrixFromSlice(ScalarSlice([]interface{}{1,0,0,Tx,0,1,0,Ty,0,0, 1,Tz,0,0,0,1}, FLOAT64), FLOAT64, 4, 4)
}

// TODO: Homogeneous conversion, homogeneous rotation matrices
// TODO: Quaternion rotation
<|endoftext|>


<commit_before>package fftw

// #cgo LDFLAGS: -lfftw3 -lm
// #include <fftw3.h>
import "C"

import (
  "reflect"
  "runtime"
  "unsafe"
)

type Plan struct {
  fftw_p C.fftw_plan
}
func destroyPlan(p *Plan) {
  C.fftw_destroy_plan(p.fftw_p)
}
func newPlan(fftw_p C.fftw_plan) *Plan {
  np := new(Plan)
  np.fftw_p = fftw_p
  runtime.SetFinalizer(np, destroyPlan)
  return np
}
func (p *Plan) Execute() {
  C.fftw_execute(p.fftw_p)
}

type Direction int
var Forward  Direction = C.FFTW_FORWARD
var Backward Direction = C.FFTW_BACKWARD

type Flag uint
var Estimate Flag = C.FFTW_ESTIMATE
var Measure  Flag = C.FFTW_MEASURE

func Alloc1d(n int) []complex128 {
  buffer := (unsafe.Pointer)(C.fftw_malloc((C.size_t)(16 * n)))
  slice := (*[1<<30]complex128)(buffer)[:n]
  header := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
  header.Cap = n
  return slice
}
func Alloc2d(n0,n1 int) [][]complex128 {
  a := Alloc1d(n0 * n1)
  r := make([][]complex128, n0)
  for i := range r {
    r[i] = a[i*n1 : (i+1)*n1]
  }
  return r
}
func Alloc3d(n0,n1,n2 int) [][][]complex128 {
  a := Alloc1d(n0 * n1 * n2)
  r := make([][][]complex128, n0)
  for i := range r {
    b := make([][]complex128, n1)
    for j := range b {
      b[j] = a[i*(n1*n2) + j*n2 : i*(n1*n2) + (j+1)*n2]
    }
    r[i] = b
  }
  return r
}

func PlanDft1d(in,out []complex128, dir Direction, flag Flag) *Plan {
  // TODO: check that len(in) == len(out)
  fftw_in := (*C.fftw_complex)((unsafe.Pointer)(&in[0]))
  fftw_out := (*C.fftw_complex)((unsafe.Pointer)(&out[0]))
  p := C.fftw_plan_dft_1d((C.int)(len(in)), fftw_in, fftw_out, C.int(dir), C.uint(flag))
  return newPlan(p)
}

func PlanDft2d(in,out [][]complex128, dir Direction, flag Flag) *Plan {
  // TODO: check that in and out have the same dimensions
  fftw_in := (*C.fftw_complex)((unsafe.Pointer)(&in[0][0]))
  fftw_out := (*C.fftw_complex)((unsafe.Pointer)(&out[0][0]))
  p := C.fftw_plan_dft_2d((C.int)(len(in)), (C.int)(len(in[0])), fftw_in, fftw_out, C.int(dir), C.uint(flag))
  return newPlan(p)
}

func PlanDft3d(in,out [][][]complex128, dir Direction, flag Flag) *Plan {
  // TODO: check that in and out have the same dimensions
  fftw_in := (*C.fftw_complex)((unsafe.Pointer)(&in[0][0][0]))
  fftw_out := (*C.fftw_complex)((unsafe.Pointer)(&out[0][0][0]))
  p := C.fftw_plan_dft_3d((C.int)(len(in)), (C.int)(len(in[0])), (C.int)(len(in[0][0])), fftw_in, fftw_out, C.int(dir), C.uint(flag))
  return newPlan(p)
}

// TODO: Once we can create go arrays out of pre-existing data we can do these real-to-complex and complex-to-real
//       transforms in-place.
// The real-to-complex and complex-to-real transforms save roughly a factor of two in time and space, with
// the following caveats:
// 1. The real array is of size N, the complex array is of size N/2+1.
// 2. The output array contains only the non-redundant output, the complete output is symmetric and the last half
//    is the complex conjugate of the first half.
// 3. Doing a complex-to-real transform destroys the input signal.
func PlanDftR2C1d(in []float64, out []complex128, flag Flag) *Plan {
  // TODO: check that in and out have the appropriate dimensions
  fftw_in := (*C.double)((unsafe.Pointer)(&in[0]))
  fftw_out := (*C.fftw_complex)((unsafe.Pointer)(&out[0]))
  p := C.fftw_plan_dft_r2c_1d((C.int)(len(in)), fftw_in, fftw_out, C.uint(flag))
  return newPlan(p)
}

// Note: Executing this plan will destroy the data contained by in
func PlanDftC2R1d(in []complex128, out []float64, flag Flag) *Plan {
  // TODO: check that in and out have the appropriate dimensions
  fftw_in := (*C.fftw_complex)((unsafe.Pointer)(&in[0]))
  fftw_out := (*C.double)((unsafe.Pointer)(&out[0]))
  p := C.fftw_plan_dft_c2r_1d((C.int)(len(out)), fftw_in, fftw_out, C.uint(flag))
  return newPlan(p)
}

<commit_msg>Avoids [1<<30]complex128 issue that prevents 386 build.<commit_after>package fftw

// #cgo LDFLAGS: -lfftw3 -lm
// #include <fftw3.h>
import "C"

import (
  "reflect"
  "runtime"
  "unsafe"
)

type Plan struct {
  fftw_p C.fftw_plan
}
func destroyPlan(p *Plan) {
  C.fftw_destroy_plan(p.fftw_p)
}
func newPlan(fftw_p C.fftw_plan) *Plan {
  np := new(Plan)
  np.fftw_p = fftw_p
  runtime.SetFinalizer(np, destroyPlan)
  return np
}
func (p *Plan) Execute() {
  C.fftw_execute(p.fftw_p)
}

type Direction int
var Forward  Direction = C.FFTW_FORWARD
var Backward Direction = C.FFTW_BACKWARD

type Flag uint
var Estimate Flag = C.FFTW_ESTIMATE
var Measure  Flag = C.FFTW_MEASURE

func Alloc1d(n int) []complex128 {
  buffer := (unsafe.Pointer)(C.fftw_malloc((C.size_t)(16 * n)))
  var slice []complex128
  header := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
  *header = reflect.SliceHeader{uintptr(buffer), n, n}
  return slice
}
func Alloc2d(n0,n1 int) [][]complex128 {
  a := Alloc1d(n0 * n1)
  r := make([][]complex128, n0)
  for i := range r {
    r[i] = a[i*n1 : (i+1)*n1]
  }
  return r
}
func Alloc3d(n0,n1,n2 int) [][][]complex128 {
  a := Alloc1d(n0 * n1 * n2)
  r := make([][][]complex128, n0)
  for i := range r {
    b := make([][]complex128, n1)
    for j := range b {
      b[j] = a[i*(n1*n2) + j*n2 : i*(n1*n2) + (j+1)*n2]
    }
    r[i] = b
  }
  return r
}

func PlanDft1d(in,out []complex128, dir Direction, flag Flag) *Plan {
  // TODO: check that len(in) == len(out)
  fftw_in := (*C.fftw_complex)((unsafe.Pointer)(&in[0]))
  fftw_out := (*C.fftw_complex)((unsafe.Pointer)(&out[0]))
  p := C.fftw_plan_dft_1d((C.int)(len(in)), fftw_in, fftw_out, C.int(dir), C.uint(flag))
  return newPlan(p)
}

func PlanDft2d(in,out [][]complex128, dir Direction, flag Flag) *Plan {
  // TODO: check that in and out have the same dimensions
  fftw_in := (*C.fftw_complex)((unsafe.Pointer)(&in[0][0]))
  fftw_out := (*C.fftw_complex)((unsafe.Pointer)(&out[0][0]))
  p := C.fftw_plan_dft_2d((C.int)(len(in)), (C.int)(len(in[0])), fftw_in, fftw_out, C.int(dir), C.uint(flag))
  return newPlan(p)
}

func PlanDft3d(in,out [][][]complex128, dir Direction, flag Flag) *Plan {
  // TODO: check that in and out have the same dimensions
  fftw_in := (*C.fftw_complex)((unsafe.Pointer)(&in[0][0][0]))
  fftw_out := (*C.fftw_complex)((unsafe.Pointer)(&out[0][0][0]))
  p := C.fftw_plan_dft_3d((C.int)(len(in)), (C.int)(len(in[0])), (C.int)(len(in[0][0])), fftw_in, fftw_out, C.int(dir), C.uint(flag))
  return newPlan(p)
}

// TODO: Once we can create go arrays out of pre-existing data we can do these real-to-complex and complex-to-real
//       transforms in-place.
// The real-to-complex and complex-to-real transforms save roughly a factor of two in time and space, with
// the following caveats:
// 1. The real array is of size N, the complex array is of size N/2+1.
// 2. The output array contains only the non-redundant output, the complete output is symmetric and the last half
//    is the complex conjugate of the first half.
// 3. Doing a complex-to-real transform destroys the input signal.
func PlanDftR2C1d(in []float64, out []complex128, flag Flag) *Plan {
  // TODO: check that in and out have the appropriate dimensions
  fftw_in := (*C.double)((unsafe.Pointer)(&in[0]))
  fftw_out := (*C.fftw_complex)((unsafe.Pointer)(&out[0]))
  p := C.fftw_plan_dft_r2c_1d((C.int)(len(in)), fftw_in, fftw_out, C.uint(flag))
  return newPlan(p)
}

// Note: Executing this plan will destroy the data contained by in
func PlanDftC2R1d(in []complex128, out []float64, flag Flag) *Plan {
  // TODO: check that in and out have the appropriate dimensions
  fftw_in := (*C.fftw_complex)((unsafe.Pointer)(&in[0]))
  fftw_out := (*C.double)((unsafe.Pointer)(&out[0]))
  p := C.fftw_plan_dft_c2r_1d((C.int)(len(out)), fftw_in, fftw_out, C.uint(flag))
  return newPlan(p)
}

<|endoftext|>


<commit_before>// Package file provides simple utility functions to be used with files
package file

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

// Copy copies the file or directory from source path to destination path.
// Directories are copied recursively. Copy does not handle symlinks currently.
func Copy(src, dst string) error {
	if dst == "." {
		dst = filepath.Base(src)
	}

	if src == dst {
		return fmt.Errorf("%s and %s are identical (not copied).", src, dst)
	}

	if !Exists(src) {
		return fmt.Errorf("%s: no such file or directory.", src)
	}

	if Exists(dst) && IsFile(dst) {
		return fmt.Errorf("%s is a directory (not copied).", src)
	}

	srcBase, _ := filepath.Split(src)
	walks := 0

	// dstPath returns the rewritten destination path for the given source path
	dstPath := func(srcPath string) string {
		srcPath = strings.TrimPrefix(srcPath, srcBase)

		// foo/example/hello.txt -> bar/example/hello.txt
		if walks != 0 {
			return filepath.Join(dst, srcPath)
		}

		// hello.txt -> example/hello.txt
		if Exists(dst) && !IsFile(dst) {
			return filepath.Join(dst, filepath.Base(srcPath))
		}

		// hello.txt -> test.txt
		return dst
	}

	filepath.Walk(src, func(srcPath string, file os.FileInfo, err error) error {
		defer func() { walks++ }()

		if file.IsDir() {
			os.MkdirAll(dstPath(srcPath), 0755)
		} else {
			err = copyFile(srcPath, dstPath(srcPath))
			if err != nil {
				fmt.Println(err)
			}
		}

		return nil
	})

	return nil
}

// IsFile checks wether the given file is a directory or not. It panics if an
// error is occured. Use IsFileOk to use the returned error.
func IsFile(file string) bool {
	ok, err := IsFileOk(file)
	if err != nil {
		panic(err)
	}

	return ok
}

// IsFileOk checks whether the given file is a directory or not.
func IsFileOk(file string) (bool, error) {
	sf, err := os.Open(file)
	if err != nil {
		return false, err
	}
	defer sf.Close()

	fi, err := sf.Stat()
	if err != nil {
		return false, err
	}

	if fi.IsDir() {
		return false, nil
	}

	return true, nil
}

// Exists checks whether the given file exists or not. It panics if an error
// is occured. Use ExistsOk to use the returned error.
func Exists(file string) bool {
	ok, err := ExistsOk(file)
	if err != nil {
		panic(err)
	}

	return ok
}

// ExistsOk checks whether the given file exists or not.
func ExistsOk(file string) (bool, error) {
	_, err := os.Stat(file)
	if err == nil {
		return true, nil // file exist
	}

	if os.IsNotExist(err) {
		return false, nil // file does not exist
	}

	return false, err
}

func copyFile(src, dst string) error {
	sf, err := os.Open(src)
	if err != nil {
		return err
	}
	defer sf.Close()

	fi, err := sf.Stat()
	if err != nil {
		return err
	}

	if fi.IsDir() {
		return errors.New("src is a directory, please provide a file")
	}

	df, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, fi.Mode())
	if err != nil {
		return err
	}
	defer df.Close()

	if _, err := io.Copy(df, sf); err != nil {
		return err
	}

	return nil
}

// TODO: implement those functions
func isReadable(mode os.FileMode) bool { return mode&0400 != 0 }

func isWritable(mode os.FileMode) bool { return mode&0200 != 0 }

func isExecutable(mode os.FileMode) bool { return mode&0100 != 0 }
<commit_msg>Add comment<commit_after>// Package file provides simple utility functions to be used with files
package file

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

// Copy copies the file or directory from source path to destination path.
// Directories are copied recursively. Copy does not handle symlinks currently.
func Copy(src, dst string) error {
	if dst == "." {
		dst = filepath.Base(src)
	}

	if src == dst {
		return fmt.Errorf("%s and %s are identical (not copied).", src, dst)
	}

	if !Exists(src) {
		return fmt.Errorf("%s: no such file or directory.", src)
	}

	if Exists(dst) && IsFile(dst) {
		return fmt.Errorf("%s is a directory (not copied).", src)
	}

	srcBase, _ := filepath.Split(src)
	walks := 0

	// dstPath returns the rewritten destination path for the given source path
	dstPath := func(srcPath string) string {
		// some/random/long/path/example/hello.txt -> example/hello.txt
		srcPath = strings.TrimPrefix(srcPath, srcBase)

		// example/hello.txt -> destination/example/hello.txt
		if walks != 0 {
			return filepath.Join(dst, srcPath)
		}

		// hello.txt -> example/hello.txt
		if Exists(dst) && !IsFile(dst) {
			return filepath.Join(dst, filepath.Base(srcPath))
		}

		// hello.txt -> test.txt
		return dst
	}

	filepath.Walk(src, func(srcPath string, file os.FileInfo, err error) error {
		defer func() { walks++ }()

		if file.IsDir() {
			fmt.Printf("copy dir from '%s' to '%s'\n", srcPath, dstPath(srcPath))
			os.MkdirAll(dstPath(srcPath), 0755)
		} else {
			fmt.Printf("copy file from '%s' to '%s'\n", srcPath, dstPath(srcPath))
			err = copyFile(srcPath, dstPath(srcPath))
			if err != nil {
				fmt.Println(err)
			}
		}

		return nil
	})

	return nil
}

// IsFile checks wether the given file is a directory or not. It panics if an
// error is occured. Use IsFileOk to use the returned error.
func IsFile(file string) bool {
	ok, err := IsFileOk(file)
	if err != nil {
		panic(err)
	}

	return ok
}

// IsFileOk checks whether the given file is a directory or not.
func IsFileOk(file string) (bool, error) {
	sf, err := os.Open(file)
	if err != nil {
		return false, err
	}
	defer sf.Close()

	fi, err := sf.Stat()
	if err != nil {
		return false, err
	}

	if fi.IsDir() {
		return false, nil
	}

	return true, nil
}

// Exists checks whether the given file exists or not. It panics if an error
// is occured. Use ExistsOk to use the returned error.
func Exists(file string) bool {
	ok, err := ExistsOk(file)
	if err != nil {
		panic(err)
	}

	return ok
}

// ExistsOk checks whether the given file exists or not.
func ExistsOk(file string) (bool, error) {
	_, err := os.Stat(file)
	if err == nil {
		return true, nil // file exist
	}

	if os.IsNotExist(err) {
		return false, nil // file does not exist
	}

	return false, err
}

func copyFile(src, dst string) error {
	sf, err := os.Open(src)
	if err != nil {
		return err
	}
	defer sf.Close()

	fi, err := sf.Stat()
	if err != nil {
		return err
	}

	if fi.IsDir() {
		return errors.New("src is a directory, please provide a file")
	}

	df, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, fi.Mode())
	if err != nil {
		return err
	}
	defer df.Close()

	if _, err := io.Copy(df, sf); err != nil {
		return err
	}

	return nil
}

// TODO: implement those functions
func isReadable(mode os.FileMode) bool { return mode&0400 != 0 }

func isWritable(mode os.FileMode) bool { return mode&0200 != 0 }

func isExecutable(mode os.FileMode) bool { return mode&0100 != 0 }
<|endoftext|>


<commit_before>// Package file provides simple utility functions to be used with files
package file

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

// Copy copies the file or directory from source path to destination path.
// Directories are copied recursively. Copy does not handle symlinks currently.
func Copy(src, dst string) error {
	if src == dst {
		return fmt.Errorf("%s and %s are identical (not copied).", src, dst)
	}

	if !Exists(src) {
		return fmt.Errorf("%s: no such file or directory.", src)
	}

	if Exists(dst) && IsFile(dst) {
		return fmt.Errorf("%s is a directory (not copied).", src)
	}

	walks := 0

	// dstPath returns the rewritten destination path for the given source path
	dstPath := func(path string) string {
		// foo/example/hello.txt -> bar/example/hello.txt
		if walks != 0 {
			return strings.Replace(path, src, dst, 1)
		}

		// hello.txt -> example/hello.txt
		if Exists(dst) && !IsFile(dst) {
			return filepath.Join(dst, filepath.Base(path))
		}

		// hello.txt -> test.txt
		return dst
	}

	filepath.Walk(src, func(srcPath string, file os.FileInfo, err error) error {
		defer func() { walks++ }()

		if file.IsDir() {
			os.MkdirAll(dstPath(srcPath), 0755)
		} else {
			err = copyFile(srcPath, dstPath(srcPath))
			if err != nil {
				fmt.Println(err)
			}
		}

		return nil
	})

	return nil
}

// IsFile checks wether the given file is a directory or not. It panics if an
// error is occured. Use IsFileOk to use the returned error.
func IsFile(file string) bool {
	ok, err := IsFileOk(file)
	if err != nil {
		panic(err)
	}

	return ok
}

// IsFileOk checks whether the given file is a directory or not.
func IsFileOk(file string) (bool, error) {
	sf, err := os.Open(file)
	if err != nil {
		return false, err
	}
	defer sf.Close()

	fi, err := sf.Stat()
	if err != nil {
		return false, err
	}

	if fi.IsDir() {
		return false, nil
	}

	return true, nil
}

// Exists checks whether the given file exists or not. It panics if an error
// is occured. Use ExistsOk to use the returned error.
func Exists(file string) bool {
	ok, err := ExistsOk(file)
	if err != nil {
		panic(err)
	}

	return ok
}

// ExistsOk checks whether the given file exists or not.
func ExistsOk(file string) (bool, error) {
	_, err := os.Stat(file)
	if err == nil {
		return true, nil // file exist
	}

	if os.IsNotExist(err) {
		return false, nil // file does not exist
	}

	return false, err
}

func copyFile(src, dst string) error {
	sf, err := os.Open(src)
	if err != nil {
		return err
	}
	defer sf.Close()

	fi, err := sf.Stat()
	if err != nil {
		return err
	}

	if fi.IsDir() {
		return errors.New("src is a directory, please provide a file")
	}

	df, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, fi.Mode())
	if err != nil {
		return err
	}
	defer df.Close()

	if _, err := io.Copy(df, sf); err != nil {
		return err
	}

	return nil
}

// TODO: implement those functions
func isReadable(mode os.FileMode) bool { return mode&0400 != 0 }

func isWritable(mode os.FileMode) bool { return mode&0200 != 0 }

func isExecutable(mode os.FileMode) bool { return mode&0100 != 0 }
<commit_msg>Fix passing "." as current dir.<commit_after>// Package file provides simple utility functions to be used with files
package file

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

// Copy copies the file or directory from source path to destination path.
// Directories are copied recursively. Copy does not handle symlinks currently.
func Copy(src, dst string) error {
	if dst == "." {
		dst = filepath.Base(src)
	}

	if src == dst {
		return fmt.Errorf("%s and %s are identical (not copied).", src, dst)
	}

	if !Exists(src) {
		return fmt.Errorf("%s: no such file or directory.", src)
	}

	if Exists(dst) && IsFile(dst) {
		return fmt.Errorf("%s is a directory (not copied).", src)
	}

	walks := 0

	// dstPath returns the rewritten destination path for the given source path
	dstPath := func(path string) string {
		// foo/example/hello.txt -> bar/example/hello.txt
		if walks != 0 {
			return strings.Replace(path, src, dst, 1)
		}

		// hello.txt -> example/hello.txt
		if Exists(dst) && !IsFile(dst) {
			return filepath.Join(dst, filepath.Base(path))
		}

		// hello.txt -> test.txt
		return dst
	}

	filepath.Walk(src, func(srcPath string, file os.FileInfo, err error) error {
		defer func() { walks++ }()

		if file.IsDir() {
			os.MkdirAll(dstPath(srcPath), 0755)
		} else {
			err = copyFile(srcPath, dstPath(srcPath))
			if err != nil {
				fmt.Println(err)
			}
		}

		return nil
	})

	return nil
}

// IsFile checks wether the given file is a directory or not. It panics if an
// error is occured. Use IsFileOk to use the returned error.
func IsFile(file string) bool {
	ok, err := IsFileOk(file)
	if err != nil {
		panic(err)
	}

	return ok
}

// IsFileOk checks whether the given file is a directory or not.
func IsFileOk(file string) (bool, error) {
	sf, err := os.Open(file)
	if err != nil {
		return false, err
	}
	defer sf.Close()

	fi, err := sf.Stat()
	if err != nil {
		return false, err
	}

	if fi.IsDir() {
		return false, nil
	}

	return true, nil
}

// Exists checks whether the given file exists or not. It panics if an error
// is occured. Use ExistsOk to use the returned error.
func Exists(file string) bool {
	ok, err := ExistsOk(file)
	if err != nil {
		panic(err)
	}

	return ok
}

// ExistsOk checks whether the given file exists or not.
func ExistsOk(file string) (bool, error) {
	_, err := os.Stat(file)
	if err == nil {
		return true, nil // file exist
	}

	if os.IsNotExist(err) {
		return false, nil // file does not exist
	}

	return false, err
}

func copyFile(src, dst string) error {
	sf, err := os.Open(src)
	if err != nil {
		return err
	}
	defer sf.Close()

	fi, err := sf.Stat()
	if err != nil {
		return err
	}

	if fi.IsDir() {
		return errors.New("src is a directory, please provide a file")
	}

	df, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, fi.Mode())
	if err != nil {
		return err
	}
	defer df.Close()

	if _, err := io.Copy(df, sf); err != nil {
		return err
	}

	return nil
}

// TODO: implement those functions
func isReadable(mode os.FileMode) bool { return mode&0400 != 0 }

func isWritable(mode os.FileMode) bool { return mode&0200 != 0 }

func isExecutable(mode os.FileMode) bool { return mode&0100 != 0 }
<|endoftext|>