<commit_before>package main

import (
	"log"
	"math"
	"net"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/pborman/uuid"

	"flag"

	couchbasearray "github.com/andrewwebber/couchbase-array"
)

var servicePathFlag = flag.String("s", "/services/couchbase-array", "etcd directory")
var heartBeatFlag = flag.Int("h", 3, "heart beat loop in seconds")
var ttlFlag = flag.Int("ttl", 30, "time to live in seconds")
var debugFlag = flag.Bool("v", false, "verbose")
var machineIdentiferFlag = flag.String("ip", "", "machine ip address")
var whatIfFlag = flag.Bool("t", false, "what if")
var cliBase = flag.String("cli", "/opt/couchbase/bin/couchbase-cli", "path to couchbase cli")
var masterNodeAnnouncePathFlag = flag.String("m", "/services/couchbase", "announce etcd path for the master IP")

func main() {
	log.SetFlags(log.Llongfile)
	flag.Parse()
	log.Println("Couchbase Cluster Node")
	couchbasearray.TTL = uint64(*ttlFlag)
	log.Printf("TTL %v\n", couchbasearray.TTL)

	machineIdentifier := *machineIdentiferFlag
	if machineIdentifier == "" {
		var err error
		machineIdentifier, err = getMachineIdentifier()
		if err != nil {
			log.Fatal(err)
		}
	}

	log.Printf("Machine ID: %s\n", machineIdentifier)

	sessionID := uuid.New()
	var isClusterMember bool

	go func() {
		for {
			announcments, err := couchbasearray.GetClusterAnnouncements(*servicePathFlag)
			if err != nil {
				log.Println(err)
				continue
			}

			machineState, ok := announcments[sessionID]
			if !ok {
				machineState = couchbasearray.NodeState{
					IPAddress:    machineIdentifier,
					SessionID:    sessionID,
					Master:       false,
					State:        "",
					DesiredState: ""}
			}

			currentStates, err := couchbasearray.GetClusterStates(*servicePathFlag)

			master, err := couchbasearray.GetMasterNode(currentStates)
			if err != nil {
				err := couchbasearray.AcquireLock(sessionID, *servicePathFlag+"/master", 5)
				if err == nil {
					stopScheduler := make(chan bool)
					go couchbasearray.StartScheduler(*servicePathFlag, *heartBeatFlag, stopScheduler, *masterNodeAnnouncePathFlag)
					go func() {
						failoverSet := false
						for {
							lockErr := couchbasearray.AcquireLock(sessionID, *servicePathFlag+"/master", 5)
							if lockErr != nil {
								log.Println(lockErr)
								stopScheduler <- true
								return
							}

							if !failoverSet {
								if failOverErr := setAutoFailover(machineIdentifier, 31); err != nil {
									log.Println(failOverErr)
								} else {
									failoverSet = true
								}
							}

							time.Sleep(4 * time.Second)
						}
					}()
				}

				if err != nil && err != couchbasearray.ErrLockInUse {
					log.Println(err)
					continue
				}
			} else {
				if state, ok := currentStates[sessionID]; ok {
					if state.DesiredState != machineState.State {
						log.Printf("DesiredState: %s - Current State: %s", state.DesiredState, machineState.State)

						switch state.DesiredState {
						case couchbasearray.SchedulerStateClustered:
							log.Println("rebalancing")

							if master.IPAddress == machineIdentifier {
								log.Println("Already master no action required")
							} else {
								log.Printf("rebalancing with master node %s\n", master.IPAddress)
								if !*whatIfFlag {
									if isClusterMember {
										err = recoverNode(master.IPAddress, machineIdentifier)
									}

									err = rebalanceNode(master.IPAddress, machineIdentifier)
								}
							}

							if err == nil {
								machineState.State = state.DesiredState
							} else {
								log.Println(err)
							}

						case couchbasearray.SchedulerStateNew:
							log.Println("adding server to cluster")
							master, err := couchbasearray.GetMasterNode(currentStates)
							if err != nil {
								log.Println(err)
							} else {
								if master.IPAddress == machineIdentifier {
									log.Println("Already master no action required")
								} else {
									log.Printf("Adding to master node %s\n", master.IPAddress)
									if !*whatIfFlag {
										isClusterMember, err = addNodeToCluster(master.IPAddress, machineIdentifier)
									}
								}

								if err == nil {
									machineState.State = state.DesiredState
								} else {
									log.Println(err)
								}
							}
						default:
							log.Println(state.DesiredState)
							log.Fatal("unknown state")
						}
					}
				} else {
					log.Println("Running")
				}
			}

			err = couchbasearray.SetClusterAnnouncement(*servicePathFlag, machineState)
			if err != nil {
				log.Println(err)
			}

			time.Sleep(time.Duration(*heartBeatFlag) * time.Second)
		}
	}()

	ch := make(chan os.Signal)
	signal.Notify(ch, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGKILL)
	log.Println(<-ch)
	log.Println("Failing over")

	currentStates, err := couchbasearray.GetClusterStates(*servicePathFlag)
	if err != nil {
		log.Fatal(err)
		return
	}

	master, err := couchbasearray.GetMasterNode(currentStates)
	if err != nil {
		log.Fatal(err)
		return
	}

	err = failoverClusterNode(master.IPAddress, machineIdentifier)
	if err != nil {
		log.Fatal(err)
	}

	err = rebalanceNode(master.IPAddress, machineIdentifier)
	if err != nil {
		log.Fatal(err)
	}
}

func getMachineIdentifier() (string, error) {

	addrs, err := net.InterfaceAddrs()
	if err != nil {
		log.Fatalln(err)
	}

	var result string
	for _, a := range addrs {
		if ipnet, ok := a.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
			if ipnet.IP.To4() != nil {
				result = ipnet.IP.String()
				log.Println(ipnet.Network())
				log.Printf("Found IP %s\n", result)
				break
			}
		}
	}

	if result != "" {
		return result, nil
	}

	return os.Hostname()
}

type function func() error

func exponential(operation function, maxRetries int) error {
	var err error
	var sleepTime int
	for i := 0; i < maxRetries; i++ {
		err = operation()
		if err == nil {
			return nil
		}
		if i == 0 {
			sleepTime = 1
		} else {
			sleepTime = int(math.Exp2(float64(i)) * 100)
		}
		time.Sleep(time.Duration(sleepTime) * time.Millisecond)
		log.Printf("Retry exponential: Attempt %d, sleep %d", i, sleepTime)
	}

	return err
}
<commit_msg>rebalance on exit now configurable<commit_after>package main

import (
	"log"
	"math"
	"net"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/pborman/uuid"

	"flag"

	couchbasearray "github.com/andrewwebber/couchbase-array"
)

var servicePathFlag = flag.String("s", "/services/couchbase-array", "etcd directory")
var heartBeatFlag = flag.Int("h", 3, "heart beat loop in seconds")
var ttlFlag = flag.Int("ttl", 30, "time to live in seconds")
var debugFlag = flag.Bool("v", false, "verbose")
var rebalanceOnExitFlag = flag.Bool("r", false, "rebalance on exit")
var machineIdentiferFlag = flag.String("ip", "", "machine ip address")
var whatIfFlag = flag.Bool("t", false, "what if")
var cliBase = flag.String("cli", "/opt/couchbase/bin/couchbase-cli", "path to couchbase cli")
var masterNodeAnnouncePathFlag = flag.String("m", "/services/couchbase", "announce etcd path for the master IP")

func main() {
	log.SetFlags(log.Llongfile)
	flag.Parse()
	log.Println("Couchbase Cluster Node")
	couchbasearray.TTL = uint64(*ttlFlag)
	log.Printf("TTL %v\n", couchbasearray.TTL)

	machineIdentifier := *machineIdentiferFlag
	if machineIdentifier == "" {
		var err error
		machineIdentifier, err = getMachineIdentifier()
		if err != nil {
			log.Fatal(err)
		}
	}

	log.Printf("Machine ID: %s\n", machineIdentifier)

	sessionID := uuid.New()
	var isClusterMember bool

	go func() {
		for {
			announcments, err := couchbasearray.GetClusterAnnouncements(*servicePathFlag)
			if err != nil {
				log.Println(err)
				continue
			}

			machineState, ok := announcments[sessionID]
			if !ok {
				machineState = couchbasearray.NodeState{
					IPAddress:    machineIdentifier,
					SessionID:    sessionID,
					Master:       false,
					State:        "",
					DesiredState: ""}
			}

			currentStates, err := couchbasearray.GetClusterStates(*servicePathFlag)

			master, err := couchbasearray.GetMasterNode(currentStates)
			if err != nil {
				err := couchbasearray.AcquireLock(sessionID, *servicePathFlag+"/master", 5)
				if err == nil {
					stopScheduler := make(chan bool)
					go couchbasearray.StartScheduler(*servicePathFlag, *heartBeatFlag, stopScheduler, *masterNodeAnnouncePathFlag)
					go func() {
						failoverSet := false
						for {
							lockErr := couchbasearray.AcquireLock(sessionID, *servicePathFlag+"/master", 5)
							if lockErr != nil {
								log.Println(lockErr)
								stopScheduler <- true
								return
							}

							if !failoverSet {
								if failOverErr := setAutoFailover(machineIdentifier, 31); err != nil {
									log.Println(failOverErr)
								} else {
									failoverSet = true
								}
							}

							time.Sleep(4 * time.Second)
						}
					}()
				}

				if err != nil && err != couchbasearray.ErrLockInUse {
					log.Println(err)
					continue
				}
			} else {
				if state, ok := currentStates[sessionID]; ok {
					if state.DesiredState != machineState.State {
						log.Printf("DesiredState: %s - Current State: %s", state.DesiredState, machineState.State)

						switch state.DesiredState {
						case couchbasearray.SchedulerStateClustered:
							log.Println("rebalancing")

							if master.IPAddress == machineIdentifier {
								log.Println("Already master no action required")
							} else {
								log.Printf("rebalancing with master node %s\n", master.IPAddress)
								if !*whatIfFlag {
									if isClusterMember {
										err = recoverNode(master.IPAddress, machineIdentifier)
									}

									err = rebalanceNode(master.IPAddress, machineIdentifier)
								}
							}

							if err == nil {
								machineState.State = state.DesiredState
							} else {
								log.Println(err)
							}

						case couchbasearray.SchedulerStateNew:
							log.Println("adding server to cluster")
							master, err := couchbasearray.GetMasterNode(currentStates)
							if err != nil {
								log.Println(err)
							} else {
								if master.IPAddress == machineIdentifier {
									log.Println("Already master no action required")
								} else {
									log.Printf("Adding to master node %s\n", master.IPAddress)
									if !*whatIfFlag {
										isClusterMember, err = addNodeToCluster(master.IPAddress, machineIdentifier)
									}
								}

								if err == nil {
									machineState.State = state.DesiredState
								} else {
									log.Println(err)
								}
							}
						default:
							log.Println(state.DesiredState)
							log.Fatal("unknown state")
						}
					}
				} else {
					log.Println("Running")
				}
			}

			err = couchbasearray.SetClusterAnnouncement(*servicePathFlag, machineState)
			if err != nil {
				log.Println(err)
			}

			time.Sleep(time.Duration(*heartBeatFlag) * time.Second)
		}
	}()

	ch := make(chan os.Signal)
	signal.Notify(ch, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGKILL)
	log.Println(<-ch)
	log.Println("Failing over")

	currentStates, err := couchbasearray.GetClusterStates(*servicePathFlag)
	if err != nil {
		log.Fatal(err)
		return
	}

	master, err := couchbasearray.GetMasterNode(currentStates)
	if err != nil {
		log.Fatal(err)
		return
	}

	err = failoverClusterNode(master.IPAddress, machineIdentifier)
	if err != nil {
		log.Fatal(err)
	}

	if *rebalanceOnExitFlag {
		err = rebalanceNode(master.IPAddress, machineIdentifier)
		if err != nil {
			log.Fatal(err)
		}
	}
}

func getMachineIdentifier() (string, error) {

	addrs, err := net.InterfaceAddrs()
	if err != nil {
		log.Fatalln(err)
	}

	var result string
	for _, a := range addrs {
		if ipnet, ok := a.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
			if ipnet.IP.To4() != nil {
				result = ipnet.IP.String()
				log.Println(ipnet.Network())
				log.Printf("Found IP %s\n", result)
				break
			}
		}
	}

	if result != "" {
		return result, nil
	}

	return os.Hostname()
}

type function func() error

func exponential(operation function, maxRetries int) error {
	var err error
	var sleepTime int
	for i := 0; i < maxRetries; i++ {
		err = operation()
		if err == nil {
			return nil
		}
		if i == 0 {
			sleepTime = 1
		} else {
			sleepTime = int(math.Exp2(float64(i)) * 100)
		}
		time.Sleep(time.Duration(sleepTime) * time.Millisecond)
		log.Printf("Retry exponential: Attempt %d, sleep %d", i, sleepTime)
	}

	return err
}
<|endoftext|>


<commit_before>package rest

import (
	"testing"
	"net/http/httptest"
	"os"
	"log"

	"github.com/gin-gonic/gin"
	"github.com/popstas/pixel-server/app/pixel"
)

func getServer() Server{
	p := pixel.SerialPixel{Serial: pixel.NullWriter{}, Testing: true}
	s := Server{Pixel: p}
	return s
}

func sendKapacitorRequestFromFile(fileName string, r *gin.Engine) (*httptest.ResponseRecorder){
	response := httptest.NewRecorder()
	f, _ := os.Open(fileName)
	request := httptest.NewRequest("POST", "/kapacitor", f)
	r.ServeHTTP(response, request)
	return response
}

func TestKapacitor(t *testing.T) {
	var response *httptest.ResponseRecorder
	s := getServer()
	r := s.GetEngine()
	//httptest.NewServer(e)

	// TODO: remove cwd after first commit
	cwd, _ := os.Getwd()
	log.Printf("current directory: %v", cwd)

	response = sendKapacitorRequestFromFile("fixtures/kapacitor_warning.json", r)
	log.Printf("Response: %v", response)

	response = sendKapacitorRequestFromFile("fixtures/kapacitor_critical.json", r)
	log.Printf("Response: %v", response)

	response = sendKapacitorRequestFromFile("fixtures/kapacitor_ok.json", r)
	log.Printf("Response: %v", response)
}<commit_msg>test(rest): remove cwd check<commit_after>package rest

import (
	"testing"
	"net/http/httptest"
	"os"
	"log"

	"github.com/gin-gonic/gin"
	"github.com/popstas/pixel-server/app/pixel"
)

func getServer() Server{
	p := pixel.SerialPixel{Serial: pixel.NullWriter{}, Testing: true}
	s := Server{Pixel: p}
	return s
}

func sendKapacitorRequestFromFile(fileName string, r *gin.Engine) (*httptest.ResponseRecorder){
	response := httptest.NewRecorder()
	f, _ := os.Open(fileName)
	request := httptest.NewRequest("POST", "/kapacitor", f)
	r.ServeHTTP(response, request)
	return response
}

func TestKapacitor(t *testing.T) {
	var response *httptest.ResponseRecorder
	s := getServer()
	r := s.GetEngine()
	//httptest.NewServer(e)

	response = sendKapacitorRequestFromFile("fixtures/kapacitor_warning.json", r)
	log.Printf("Response: %v", response)

	response = sendKapacitorRequestFromFile("fixtures/kapacitor_critical.json", r)
	log.Printf("Response: %v", response)

	response = sendKapacitorRequestFromFile("fixtures/kapacitor_ok.json", r)
	log.Printf("Response: %v", response)
}<|endoftext|>


<commit_before>package ghostrace

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

	"./memio"
	"./process"
	"./sys"
	"./sys/call"
)

type execCb func(c *call.Execve) bool

type Tracer interface {
	ExecFilter(cb execCb)
	Spawn(cmd string, args ...string) (chan *Event, error)
	Trace(pid int) (chan *Event, error)
}

type LinuxTracer struct {
	execFilter execCb
}

func NewTracer() Tracer {
	return &LinuxTracer{}
}

func (t *LinuxTracer) ExecFilter(cb execCb) {
	t.execFilter = cb
}

func (t *LinuxTracer) Spawn(cmd string, args ...string) (chan *Event, error) {
	pid, err := syscall.ForkExec(cmd, args, &syscall.ProcAttr{
		Sys:   &syscall.SysProcAttr{Ptrace: true},
		Files: []uintptr{0, 1, 2},
	})
	if err != nil {
		return nil, err
	}
	return t.traceProcess(pid, true)
}

func (t *LinuxTracer) Trace(pid int) (chan *Event, error) {
	return t.traceProcess(pid, false)
}

func (t *LinuxTracer) traceProcess(pid int, spawned bool) (chan *Event, error) {
	ret := make(chan *Event)
	errChan := make(chan error)
	go func() {
		runtime.LockOSThread()
		defer runtime.UnlockOSThread()
		defer close(ret)

		spawnChild := -1
		if spawned {
			spawnChild = pid
		} else {
			if err := syscall.PtraceAttach(pid); err != nil {
				errChan <- err
				return
			}
		}
		errChan <- nil

		first := true
		table := make(map[int]*tracedProc)
		// we need to catch interrupts so we don't leave other processes in a bad state
		// TODO: make the interrupt catching behavior optional (but default)?
		var interrupted syscall.Signal
		signalChan := make(chan os.Signal, 1)
		signal.Notify(signalChan, syscall.SIGINT, syscall.SIGHUP, syscall.SIGTERM, syscall.SIGPIPE, syscall.SIGQUIT)
		go func() {
			for sig := range signalChan {
				// TODO: send an interrupt event back over the channel?
				// otherwise just make the other side also listen for interrupts
				interrupted = sig.(syscall.Signal)
			}
		}()
		for interrupted == 0 {
			var status syscall.WaitStatus
			pid, err := syscall.Wait4(-1, &status, syscall.WALL, nil)
			if err != nil {
				if err == syscall.EINTR {
					continue
				} else if err == syscall.ECHILD && len(table) == 0 {
					break
				}
				fmt.Println("DEBUG:", err)
				break
			}
			traced, ok := table[pid]
			if status.Exited() && ok {
				// process exit
				// TODO: send an event into channel here
				delete(table, pid)
				continue
			}
			if !status.Stopped() {
				continue
			}
			sig := status.StopSignal()
			if !ok {
				proc, err := process.FindPid(pid)
				if err != nil {
					fmt.Println("DEBUG:", err)
					continue
				}
				t, err := newTracedProc(proc, first && !spawned)
				if err != nil {
					fmt.Println("DEBUG:", err)
					continue
				}
				first = false
				traced = t
				table[pid] = t
			}
			if status.TrapCause() != -1 {
				// PTRACE_EVENT_*
				sig = syscall.Signal(0)
			} else if sig == syscall.SIGSTOP && traced.EatOneSigstop {
				// look for a SIGSTOP
				traced.EatOneSigstop = false
				sig = syscall.Signal(0)
			} else if interrupted != 0 {
				break
			}
			if sig == syscall.SIGTRAP|0x80 {
				// handle a syscall
				var sc sys.Syscall
				var err error
				if sc, err = traced.Syscall(); err != nil {
					fmt.Println("DEBUG:", err)
					continue
				}
				if sc != nil {
					ret <- &Event{
						Process: traced.Process,
						Syscall: sc,
					}
					// TODO: need to update the proc's exe/cmdline after execve
					// maybe add a proc.Reset()?
					if execve, ok := sc.(*call.Execve); ok {
						if t.execFilter != nil && !t.execFilter(execve) {
							syscall.PtraceDetach(pid)
						}
					}
				}
				sig = syscall.Signal(0)
			}
			// TODO: send events upstream for signals

			// continue and pass signal
			if err = syscall.PtraceSyscall(pid, int(sig)); err != nil {
				break
			}
		}
		exitSig := interrupted
		if exitSig == 0 {
			exitSig = syscall.SIGTERM
		}
		if spawnChild >= 0 {
			syscall.Kill(pid, syscall.SIGCONT)
			syscall.Kill(pid, exitSig)
		}
		if interrupted != 0 {
			for pid, traced := range table {
				// if we're expecting a SIGSTOP, skip this and wait for it
				// otherwise the child will be detached into a an immediate SIGSTOP which is awkward for everyone
				if !traced.EatOneSigstop {
					if err := syscall.PtraceDetach(pid); err == nil || err != syscall.ESRCH {
						continue
					}
					if err := syscall.Kill(pid, 0); err != nil && err != syscall.ESRCH {
						continue
					}
					if err := syscall.Kill(pid, syscall.SIGSTOP); err != nil && err != syscall.ESRCH {
						continue
					}
				}
				for {
					var status syscall.WaitStatus
					if _, err := syscall.Wait4(pid, &status, syscall.WALL, nil); err != nil {
						if err == syscall.EINTR {
							continue
						}
						break
					}
					if !status.Stopped() {
						break
					}
					// Linux wants a SIGSTOP before you detach from a process
					sig := status.StopSignal()
					if sig == syscall.SIGSTOP {
						syscall.PtraceDetach(pid)
						break
					}
					if sig&syscall.SIGTRAP != 0 {
						sig = syscall.Signal(0)
					}
					if err := syscall.PtraceCont(pid, int(sig)); err != nil && err != syscall.ESRCH {
						break
					}
				}
			}
		}
	}()
	err := <-errChan
	if err != nil {
		return nil, err
	}
	return ret, nil
}

type tracedProc struct {
	Process       process.Process
	Codec         *sys.Codec
	StopSig       syscall.Signal
	NewSyscall    bool
	SavedRegs     syscall.PtraceRegs
	EatOneSigstop bool
}

func newTracedProc(proc process.Process, eat bool) (*tracedProc, error) {
	pid := proc.Pid()
	options := syscall.PTRACE_O_TRACECLONE | syscall.PTRACE_O_TRACEFORK | syscall.PTRACE_O_TRACEVFORK | syscall.PTRACE_O_TRACESYSGOOD
	if err := syscall.PtraceSetOptions(pid, options); err != nil {
		return nil, err
	}
	var readMem = func(p []byte, addr uint64) (int, error) {
		return syscall.PtracePeekData(pid, uintptr(addr), p)
	}
	var writeMem = func(p []byte, addr uint64) (int, error) {
		return syscall.PtracePokeData(pid, uintptr(addr), p)
	}
	codec, err := sys.NewCodec(sys.ARCH_X86_64, sys.OS_LINUX, memio.NewMemIO(readMem, writeMem))
	if err != nil {
		return nil, err
	}
	return &tracedProc{
		Process:       proc,
		Codec:         codec,
		NewSyscall:    true,
		EatOneSigstop: eat,
	}, nil
}

func (t *tracedProc) Syscall() (ret sys.Syscall, err error) {
	pid := t.Process.Pid()
	if t.NewSyscall {
		t.NewSyscall = false
		if err = syscall.PtraceGetRegs(pid, &t.SavedRegs); err != nil {
			return
		}
	} else {
		t.NewSyscall = true
	}
	name := t.Codec.GetName(int(t.SavedRegs.Orig_rax))
	if t.NewSyscall != (name == "execve") {
		regs := &t.SavedRegs
		var newRegs syscall.PtraceRegs
		syscall.PtraceGetRegs(pid, &newRegs)
		args := []uint64{regs.Rdi, regs.Rsi, regs.Rdx, regs.R10, regs.R8, regs.R9}
		sc, err := t.Codec.DecodeRet(int(regs.Orig_rax), args, newRegs.Rax)
		if err != nil {
			fmt.Println(err)
		} else {
			ret = sc
		}
	}
	return
}
<commit_msg>better spawn and detach behavior<commit_after>package ghostrace

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

	"./memio"
	"./process"
	"./sys"
	"./sys/call"
)

type execCb func(c *call.Execve) bool

type Tracer interface {
	ExecFilter(cb execCb)
	Spawn(cmd string, args ...string) (chan *Event, error)
	Trace(pid int) (chan *Event, error)
}

type LinuxTracer struct {
	execFilter execCb
}

func NewTracer() Tracer {
	return &LinuxTracer{}
}

func (t *LinuxTracer) ExecFilter(cb execCb) {
	t.execFilter = cb
}

func (t *LinuxTracer) Spawn(cmd string, args ...string) (chan *Event, error) {
	pid, err := syscall.ForkExec(cmd, args, &syscall.ProcAttr{
		Sys:   &syscall.SysProcAttr{Ptrace: true},
		Files: []uintptr{0, 1, 2},
	})
	if err != nil {
		return nil, err
	}
	return t.traceProcess(pid, true)
}

func (t *LinuxTracer) Trace(pid int) (chan *Event, error) {
	return t.traceProcess(pid, false)
}

func (t *LinuxTracer) traceProcess(pid int, spawned bool) (chan *Event, error) {
	ret := make(chan *Event)
	errChan := make(chan error)
	go func() {
		runtime.LockOSThread()
		defer runtime.UnlockOSThread()
		defer close(ret)

		spawnChild := -1
		if spawned {
			spawnChild = pid
		} else {
			if err := syscall.PtraceAttach(pid); err != nil {
				errChan <- err
				return
			}
		}
		errChan <- nil

		first := true
		table := make(map[int]*tracedProc)
		// we need to catch interrupts so we don't leave other processes in a bad state
		// TODO: make the interrupt catching behavior optional (but default)?
		var interrupted syscall.Signal
		signalChan := make(chan os.Signal, 1)
		signal.Notify(signalChan, syscall.SIGINT, syscall.SIGHUP, syscall.SIGTERM, syscall.SIGPIPE, syscall.SIGQUIT)
		go func() {
			for sig := range signalChan {
				// TODO: send an interrupt event back over the channel?
				// otherwise just make the other side also listen for interrupts
				interrupted = sig.(syscall.Signal)
			}
		}()
		for interrupted == 0 {
			var status syscall.WaitStatus
			pid, err := syscall.Wait4(-1, &status, syscall.WALL, nil)
			if err != nil {
				if err == syscall.EINTR {
					continue
				} else if err == syscall.ECHILD && len(table) == 0 {
					break
				}
				fmt.Println("DEBUG:", err)
				break
			}
			sig := status.StopSignal()
			traced, ok := table[pid]
			if status.Exited() && ok {
				// process exit
				// TODO: send an event into channel here
				delete(table, pid)
				continue
			}
			// check for new pid
			if !ok {
				proc, err := process.FindPid(pid)
				if err != nil {
					fmt.Println("DEBUG:", err)
					continue
				}
				t, err := newTracedProc(proc, !first || !spawned)
				if err != nil {
					fmt.Println("DEBUG:", err)
					continue
				}
				first = false
				traced = t
				table[pid] = t
			}
			if status.TrapCause() != -1 {
				// handle PTRACE_EVENT_*
				sig = syscall.Signal(0)
			} else if sig == syscall.SIGSTOP && traced.EatOneSigstop {
				// handle first SIGSTOP
				traced.EatOneSigstop = false
				sig = syscall.Signal(0)
			} else if sig != syscall.SIGTRAP|0x80 && interrupted != 0 {
				// we can interrupt if it's NOT a syscall delivery
				break
			} else if sig == syscall.SIGTRAP|0x80 {
				// handle a syscall delivery
				var sc sys.Syscall
				var err error
				if sc, err = traced.Syscall(); err != nil {
					fmt.Println("DEBUG:", err)
					continue
				}
				if sc != nil {
					ret <- &Event{
						Process: traced.Process,
						Syscall: sc,
					}
					// TODO: need to update the proc's exe/cmdline after execve
					// maybe add a proc.Reset()?
					if execve, ok := sc.(*call.Execve); ok {
						if t.execFilter != nil && !t.execFilter(execve) {
							traced.Detach()
							delete(table, pid)
						}
					}
				}
				sig = syscall.Signal(0)
			}
			// TODO: send events upstream for signals

			// continue and pass signal (which might be zero from earlier code)
			if err = syscall.PtraceSyscall(pid, int(sig)); err != nil && err != syscall.ESRCH {
				break
			}
		}
		exitSig := interrupted
		if exitSig == 0 {
			exitSig = syscall.SIGTERM
		}
		if spawnChild >= 0 {
			syscall.Kill(pid, syscall.SIGCONT)
			syscall.Kill(pid, exitSig)
		}
		if interrupted != 0 {
			for _, traced := range table {
				traced.Detach()
			}
		}
	}()
	err := <-errChan
	if err != nil {
		return nil, err
	}
	return ret, nil
}

type tracedProc struct {
	Process       process.Process
	Codec         *sys.Codec
	StopSig       syscall.Signal
	NewSyscall    bool
	SavedRegs     syscall.PtraceRegs
	EatOneSigstop bool
}

func newTracedProc(proc process.Process, eat bool) (*tracedProc, error) {
	pid := proc.Pid()
	options := syscall.PTRACE_O_TRACECLONE | syscall.PTRACE_O_TRACEFORK | syscall.PTRACE_O_TRACEVFORK | syscall.PTRACE_O_TRACESYSGOOD
	if err := syscall.PtraceSetOptions(pid, options); err != nil {
		return nil, err
	}
	var readMem = func(p []byte, addr uint64) (int, error) {
		return syscall.PtracePeekData(pid, uintptr(addr), p)
	}
	var writeMem = func(p []byte, addr uint64) (int, error) {
		return syscall.PtracePokeData(pid, uintptr(addr), p)
	}
	codec, err := sys.NewCodec(sys.ARCH_X86_64, sys.OS_LINUX, memio.NewMemIO(readMem, writeMem))
	if err != nil {
		return nil, err
	}
	return &tracedProc{
		Process:       proc,
		Codec:         codec,
		NewSyscall:    true,
		EatOneSigstop: eat,
	}, nil
}

func (t *tracedProc) Syscall() (ret sys.Syscall, err error) {
	pid := t.Process.Pid()
	if t.NewSyscall {
		t.NewSyscall = false
		if err = syscall.PtraceGetRegs(pid, &t.SavedRegs); err != nil {
			return
		}
	} else {
		t.NewSyscall = true
	}
	name := t.Codec.GetName(int(t.SavedRegs.Orig_rax))
	if t.NewSyscall != (name == "execve") {
		regs := &t.SavedRegs
		var newRegs syscall.PtraceRegs
		syscall.PtraceGetRegs(pid, &newRegs)
		args := []uint64{regs.Rdi, regs.Rsi, regs.Rdx, regs.R10, regs.R8, regs.R9}
		sc, err := t.Codec.DecodeRet(int(regs.Orig_rax), args, newRegs.Rax)
		if err != nil {
			fmt.Println(err)
		} else {
			ret = sc
		}
	}
	return
}

func (t *tracedProc) Detach() error {
	pid := t.Process.Pid()
	// if we're expecting a SIGSTOP, skip this and wait for it
	// otherwise the child will be detached into a an immediate SIGSTOP which is awkward for everyone
	if !t.EatOneSigstop {
		if err := syscall.PtraceDetach(pid); err == nil || err != nil && err != syscall.ESRCH {
			return err
		}
		if err := syscall.Kill(pid, 0); err != nil && err != syscall.ESRCH {
			return err
		}
		if err := syscall.Kill(pid, syscall.SIGSTOP); err != nil && err != syscall.ESRCH {
			return err
		}
	}
	for {
		var status syscall.WaitStatus
		if _, err := syscall.Wait4(pid, &status, syscall.WALL, nil); err != nil {
			if err == syscall.EINTR {
				continue
			}
			return err
		}
		if !status.Stopped() {
			break
		}
		// Linux wants a SIGSTOP before you detach from a process
		sig := status.StopSignal()
		if sig == syscall.SIGSTOP {
			syscall.PtraceDetach(pid)
			break
		}
		if sig&syscall.SIGTRAP != 0 {
			sig = syscall.Signal(0)
		}
		if err := syscall.PtraceCont(pid, int(sig)); err != nil && err != syscall.ESRCH {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package arn

// AniListAnimeList ...
type AniListAnimeList struct {
	ID          int    `json:"id"`
	DisplayName string `json:"display_name"`
	// AnimeTime       int           `json:"anime_time"`
	// MangaChap       int           `json:"manga_chap"`
	// About           string        `json:"about"`
	// ListOrder       int           `json:"list_order"`
	// AdultContent    bool          `json:"adult_content"`
	// ForumHomepage   int           `json:"forum_homepage"`
	// LegacyLists     bool          `json:"legacy_lists"`
	// Donator         int           `json:"donator"`
	// Following       bool          `json:"following"`
	// ImageURLLge     string        `json:"image_url_lge"`
	// ImageURLMed     string        `json:"image_url_med"`
	// ImageURLBanner  string        `json:"image_url_banner"`
	// TitleLanguage   string        `json:"title_language"`
	// ScoreType       int           `json:"score_type"`
	// CustomListAnime []string      `json:"custom_list_anime"`
	// CustomListManga []interface{} `json:"custom_list_manga"`
	// Stats           struct {
	// 	StatusDistribution struct {
	// 		Anime struct {
	// 			Watching    int `json:"watching"`
	// 			PlanToWatch int `json:"plan to watch"`
	// 			Completed   int `json:"completed"`
	// 			Dropped     int `json:"dropped"`
	// 			OnHold      int `json:"on-hold"`
	// 		} `json:"anime"`
	// 		Manga struct {
	// 			Reading    int `json:"reading"`
	// 			PlanToRead int `json:"plan to read"`
	// 			Completed  int `json:"completed"`
	// 			Dropped    int `json:"dropped"`
	// 			OnHold     int `json:"on-hold"`
	// 		} `json:"manga"`
	// 	} `json:"status_distribution"`
	// 	ScoreDistribution struct {
	// 		Anime struct {
	// 			Num10  int `json:"10"`
	// 			Num20  int `json:"20"`
	// 			Num30  int `json:"30"`
	// 			Num40  int `json:"40"`
	// 			Num50  int `json:"50"`
	// 			Num60  int `json:"60"`
	// 			Num70  int `json:"70"`
	// 			Num80  int `json:"80"`
	// 			Num90  int `json:"90"`
	// 			Num100 int `json:"100"`
	// 		} `json:"anime"`
	// 		Manga struct {
	// 			Num10  int `json:"10"`
	// 			Num20  int `json:"20"`
	// 			Num30  int `json:"30"`
	// 			Num40  int `json:"40"`
	// 			Num50  int `json:"50"`
	// 			Num60  int `json:"60"`
	// 			Num70  int `json:"70"`
	// 			Num80  int `json:"80"`
	// 			Num90  int `json:"90"`
	// 			Num100 int `json:"100"`
	// 		} `json:"manga"`
	// 	} `json:"score_distribution"`
	// 	FavouriteGenres struct {
	// 		Drama         int `json:"Drama"`
	// 		Action        int `json:"Action"`
	// 		Comedy        int `json:"Comedy"`
	// 		Adventure     int `json:"Adventure"`
	// 		Romance       int `json:"Romance"`
	// 		Psychological int `json:"Psychological"`
	// 		Fantasy       int `json:"Fantasy"`
	// 		Mystery       int `json:"Mystery"`
	// 		SciFi         int `json:"Sci-Fi"`
	// 		Thriller      int `json:"Thriller"`
	// 	} `json:"favourite_genres"`
	// 	ListScores struct {
	// 		Anime struct {
	// 			Mean              int `json:"mean"`
	// 			StandardDeviation int `json:"standard_deviation"`
	// 		} `json:"anime"`
	// 		Manga struct {
	// 			Mean              int `json:"mean"`
	// 			StandardDeviation int `json:"standard_deviation"`
	// 		} `json:"manga"`
	// 	} `json:"list_scores"`
	// } `json:"stats"`
	// AdvancedRating      bool          `json:"advanced_rating"`
	// AdvancedRatingNames []interface{} `json:"advanced_rating_names"`
	// Notifications       int           `json:"notifications"`
	// AiringNotifications int           `json:"airing_notifications"`
	// UpdatedAt           int           `json:"updated_at"`
	Lists struct {
		Completed   []*AniListAnimeListItem `json:"completed"`
		Watching    []*AniListAnimeListItem `json:"watching"`
		PlanToWatch []*AniListAnimeListItem `json:"plan_to_watch"`
		Dropped     []*AniListAnimeListItem `json:"dropped"`
		OnHold      []*AniListAnimeListItem `json:"on_hold"`
	} `json:"lists"`
	CustomLists map[string][]*AniListAnimeListItem `json:"custom_lists"`
	// CSS         struct {
	// 	URL    string `json:"url"`
	// 	Popup  bool   `json:"popup"`
	// 	Count  bool   `json:"count"`
	// 	Covers string `json:"covers"`
	// } `json:"css"`
}
<commit_msg>Made CustomLists an interface<commit_after>package arn

// AniListAnimeList ...
type AniListAnimeList struct {
	ID          int    `json:"id"`
	DisplayName string `json:"display_name"`
	// AnimeTime       int           `json:"anime_time"`
	// MangaChap       int           `json:"manga_chap"`
	// About           string        `json:"about"`
	// ListOrder       int           `json:"list_order"`
	// AdultContent    bool          `json:"adult_content"`
	// ForumHomepage   int           `json:"forum_homepage"`
	// LegacyLists     bool          `json:"legacy_lists"`
	// Donator         int           `json:"donator"`
	// Following       bool          `json:"following"`
	// ImageURLLge     string        `json:"image_url_lge"`
	// ImageURLMed     string        `json:"image_url_med"`
	// ImageURLBanner  string        `json:"image_url_banner"`
	// TitleLanguage   string        `json:"title_language"`
	// ScoreType       int           `json:"score_type"`
	// CustomListAnime []string      `json:"custom_list_anime"`
	// CustomListManga []interface{} `json:"custom_list_manga"`
	// Stats           struct {
	// 	StatusDistribution struct {
	// 		Anime struct {
	// 			Watching    int `json:"watching"`
	// 			PlanToWatch int `json:"plan to watch"`
	// 			Completed   int `json:"completed"`
	// 			Dropped     int `json:"dropped"`
	// 			OnHold      int `json:"on-hold"`
	// 		} `json:"anime"`
	// 		Manga struct {
	// 			Reading    int `json:"reading"`
	// 			PlanToRead int `json:"plan to read"`
	// 			Completed  int `json:"completed"`
	// 			Dropped    int `json:"dropped"`
	// 			OnHold     int `json:"on-hold"`
	// 		} `json:"manga"`
	// 	} `json:"status_distribution"`
	// 	ScoreDistribution struct {
	// 		Anime struct {
	// 			Num10  int `json:"10"`
	// 			Num20  int `json:"20"`
	// 			Num30  int `json:"30"`
	// 			Num40  int `json:"40"`
	// 			Num50  int `json:"50"`
	// 			Num60  int `json:"60"`
	// 			Num70  int `json:"70"`
	// 			Num80  int `json:"80"`
	// 			Num90  int `json:"90"`
	// 			Num100 int `json:"100"`
	// 		} `json:"anime"`
	// 		Manga struct {
	// 			Num10  int `json:"10"`
	// 			Num20  int `json:"20"`
	// 			Num30  int `json:"30"`
	// 			Num40  int `json:"40"`
	// 			Num50  int `json:"50"`
	// 			Num60  int `json:"60"`
	// 			Num70  int `json:"70"`
	// 			Num80  int `json:"80"`
	// 			Num90  int `json:"90"`
	// 			Num100 int `json:"100"`
	// 		} `json:"manga"`
	// 	} `json:"score_distribution"`
	// 	FavouriteGenres struct {
	// 		Drama         int `json:"Drama"`
	// 		Action        int `json:"Action"`
	// 		Comedy        int `json:"Comedy"`
	// 		Adventure     int `json:"Adventure"`
	// 		Romance       int `json:"Romance"`
	// 		Psychological int `json:"Psychological"`
	// 		Fantasy       int `json:"Fantasy"`
	// 		Mystery       int `json:"Mystery"`
	// 		SciFi         int `json:"Sci-Fi"`
	// 		Thriller      int `json:"Thriller"`
	// 	} `json:"favourite_genres"`
	// 	ListScores struct {
	// 		Anime struct {
	// 			Mean              int `json:"mean"`
	// 			StandardDeviation int `json:"standard_deviation"`
	// 		} `json:"anime"`
	// 		Manga struct {
	// 			Mean              int `json:"mean"`
	// 			StandardDeviation int `json:"standard_deviation"`
	// 		} `json:"manga"`
	// 	} `json:"list_scores"`
	// } `json:"stats"`
	// AdvancedRating      bool          `json:"advanced_rating"`
	// AdvancedRatingNames []interface{} `json:"advanced_rating_names"`
	// Notifications       int           `json:"notifications"`
	// AiringNotifications int           `json:"airing_notifications"`
	// UpdatedAt           int           `json:"updated_at"`
	Lists struct {
		Completed   []*AniListAnimeListItem `json:"completed"`
		Watching    []*AniListAnimeListItem `json:"watching"`
		PlanToWatch []*AniListAnimeListItem `json:"plan_to_watch"`
		Dropped     []*AniListAnimeListItem `json:"dropped"`
		OnHold      []*AniListAnimeListItem `json:"on_hold"`
	} `json:"lists"`
	CustomLists interface{} `json:"custom_lists"`
	// CSS         struct {
	// 	URL    string `json:"url"`
	// 	Popup  bool   `json:"popup"`
	// 	Count  bool   `json:"count"`
	// 	Covers string `json:"covers"`
	// } `json:"css"`
}
<|endoftext|>


<commit_before>package commands

import (
	"time"

	"nvim-go/config"
	"nvim-go/context"
	"nvim-go/nvim"

	"github.com/garyburd/neovim-go/vim"
	"github.com/garyburd/neovim-go/vim/plugin"
)

func init() {
	plugin.HandleCommand("Gotest", &plugin.CommandOptions{Eval: "expand('%:p:h')"}, cmdTest)
}

func cmdTest(v *vim.Vim, dir string) {
	go Test(v, dir)
}

// Test run the package test command use compile tool that determined from
// the directory structure.
func Test(v *vim.Vim, dir string) error {
	defer nvim.Profile(time.Now(), "GoTest")
	var ctxt = context.Build{}
	defer ctxt.SetContext(dir)()

	cmd := []string{ctxt.Tool, "test", "-v", "./..."}

	term := nvim.NewTerminal(v, cmd, config.TerminalMode)

	rootDir := context.FindVcsRoot(dir)
	term.Dir = rootDir

	if err := term.Run(); err != nil {
		return err
	}

	return nil
}
<commit_msg>TestSwitch: Add GoTestSwitch command<commit_after>package commands

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"os"
	"path/filepath"
	"strings"
	"time"

	"nvim-go/config"
	"nvim-go/context"
	"nvim-go/nvim"

	"github.com/garyburd/neovim-go/vim"
	"github.com/garyburd/neovim-go/vim/plugin"
	"golang.org/x/tools/go/ast/astutil"
)

func init() {
	plugin.HandleCommand("Gotest", &plugin.CommandOptions{Eval: "expand('%:p:h')"}, cmdTest)
	plugin.HandleCommand("GoTestSwitch", &plugin.CommandOptions{Eval: "[getcwd(), expand('%:p')]"}, cmdTestSwitch)
}

func cmdTest(v *vim.Vim, dir string) {
	go Test(v, dir)
}

// Test run the package test command use compile tool that determined from
// the directory structure.
func Test(v *vim.Vim, dir string) error {
	defer nvim.Profile(time.Now(), "GoTest")
	var ctxt = context.Build{}
	defer ctxt.SetContext(dir)()

	cmd := []string{ctxt.Tool, "test", "-v", "./..."}

	term := nvim.NewTerminal(v, cmd, config.TerminalMode)

	rootDir := context.FindVcsRoot(dir)
	term.Dir = rootDir

	if err := term.Run(); err != nil {
		return err
	}

	return nil
}

var (
	fset       = token.NewFileSet() // *token.FileSet
	parserMode parser.Mode          // uint
	pos        token.Pos
)

var (
	testPrefix     = "Test"
	testSuffix     = "_test"
	isTest         bool
	fnName         string
	fnNameNoExport string
)

type cmdTestSwitchEval struct {
	Cwd  string `msgpack:",array"`
	File string
}

func cmdTestSwitch(v *vim.Vim, eval cmdTestSwitchEval) {
	go TestSwitch(v, eval)
}

func TestSwitch(v *vim.Vim, eval cmdTestSwitchEval) error {
	defer nvim.Profile(time.Now(), "TestSwitch")

	// Check the current buffer name whether '*_test.go'.
	fname := eval.File
	exp := filepath.Ext(fname)
	var switchfile string
	if strings.Index(fname, testSuffix) == -1 {
		isTest = false
		switchfile = strings.Replace(fname, exp, testSuffix+exp, 1) // not testfile
	} else {
		isTest = true
		switchfile = strings.Replace(fname, testSuffix+exp, exp, 1) // testfile
	}
	// Check the exists of switch destination file.
	if _, err := os.Stat(switchfile); err != nil {
		return nvim.EchohlErr(v, "GoTestSwitch", "Switch destination file file does not exist")
	}

	var ctxt = context.Build{}
	dir, _ := filepath.Split(fname)
	defer ctxt.SetContext(filepath.Dir(dir))()

	// Gets the current buffer information.
	p := v.NewPipeline()
	p.CurrentBuffer(&b)
	if err := p.Wait(); err != nil {
		return err
	}

	// Get the byte offset of current cursor position from buffer.
	// TODO(zchee): Eval 'line2byte(line('.'))+(col('.')-2)' is faster and safer?
	byteOffset, err := nvim.ByteOffset(p)
	if err != nil {
		return err
	}
	// Get the 2d byte slice of current buffer.
	var buf [][]byte
	p.BufferLines(b, 0, -1, true, &buf)
	if err := p.Wait(); err != nil {
		return err
	}

	f, err := parse(fname, fset, bytes.Join(buf, []byte{'\n'})) // *ast.File
	if err != nil {
		return err
	}
	offset := fset.File(f.Pos()).Pos(byteOffset) // token.Pos

	// Parses the function ast node from the current cursor position.
	qpos, _ := astutil.PathEnclosingInterval(f, offset, offset) // path []ast.Node, exact bool
	for _, q := range qpos {
		switch x := q.(type) {
		case *ast.FuncDecl:
			if x.Name != nil { // *ast.Ident
				name := fmt.Sprintf("%s", x.Name)
				if !isTest {
					// fnNameNoExport is empty because Test function would be exported.
					fnName = fmt.Sprintf("%s%s%s", testPrefix, bytes.ToUpper([]byte{name[0]}), name[1:])
				} else {
					fnName = strings.Replace(name, testPrefix, "", 1)
					fnNameNoExport = fmt.Sprintf("%s%s", bytes.ToLower([]byte{fnName[0]}), fnName[1:])
				}
			}
		}
	}

	// Get the switch destination file ast node.
	fswitch, err := parse(switchfile, fset, nil) // *ast.File
	if err != nil {
		return err
	}

	// Parses the switch destination file ast node.
	ast.Walk(visitorFunc(parseFunc), fswitch)

	filename, line, col := nvim.SplitPos(fset.Position(pos).String(), eval.Cwd)
	loclist := append([]*nvim.ErrorlistData{}, &nvim.ErrorlistData{
		FileName: filename,
		LNum:     line,
		Col:      col,
	})
	if err := nvim.SetLoclist(p, loclist); err != nil {
		return err
	}

	// Jump to the corresponds function.
	p.Command("silent ll | normal zt")
	// Define the mapping to add 'zt' to <C-o> in the buffer local.
	p.Command("nnoremap <silent><buffer> <C-o> <C-o>zt")

	return p.Wait()
}

// Wrapper of the parser.ParseFile()
func parse(filename string, fset *token.FileSet, src interface{}) (*ast.File, error) {
	file, err := parser.ParseFile(fset, filename, src, parserMode)
	if err != nil {
		return nil, err
	}

	return file, err
}

// visitorFunc for ast.Visit type.
type visitorFunc func(n ast.Node) ast.Visitor

// visit for ast.Visit function.
func (f visitorFunc) Visit(n ast.Node) ast.Visitor {
	return f(n)
}

// Core of the parser of the ast node.
func parseFunc(node ast.Node) ast.Visitor {
	switch x := node.(type) {
	default:
		return visitorFunc(parseFunc)
	case *ast.FuncDecl:
		if x.Name.Name == fnName || x.Name.Name == fnNameNoExport { // *ast.Ident.string
			pos = x.Name.NamePos
			return nil
		}
	}

	return nil
}
<|endoftext|>


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

package commands

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"os"
	"path/filepath"
	"strings"
	"time"

	"nvim-go/config"
	"nvim-go/context"
	"nvim-go/nvim"
	"nvim-go/nvim/profile"
	"nvim-go/nvim/quickfix"
	"nvim-go/nvim/terminal"
	"nvim-go/pathutil"

	"github.com/garyburd/neovim-go/vim"
	"github.com/garyburd/neovim-go/vim/plugin"
	"golang.org/x/tools/go/ast/astutil"
)

func init() {
	plugin.HandleCommand("Gotest", &plugin.CommandOptions{NArgs: "*", Eval: "expand('%:p:h')"}, cmdTest)
	plugin.HandleCommand("GoTestSwitch", &plugin.CommandOptions{Eval: "[getcwd(), expand('%:p')]"}, cmdTestSwitch)
}

func cmdTest(v *vim.Vim, args []string, dir string) {
	go Test(v, args, dir)
}

var term *terminal.Terminal

// Test run the package test command use compile tool that determined from
// the directory structure.
func Test(v *vim.Vim, args []string, dir string) error {
	defer profile.Start(time.Now(), "GoTest")

	ctxt := new(context.Context)
	defer ctxt.Build.SetContext(dir)()

	cmd := []string{ctxt.Build.Tool, "test"}
	args = append(args, config.TestArgs...)
	if len(args) > 0 {
		cmd = append(cmd, args...)
	}
	if ctxt.Build.Tool == "go" {
		cmd = append(cmd, string("./..."))
	}

	if term == nil {
		term = terminal.NewTerminal(v, "__GO_TEST__", cmd, config.TerminalMode)
	}
	rootDir := pathutil.FindVcsRoot(dir)
	term.Dir = rootDir

	if err := term.Run(cmd); err != nil {
		return err
	}

	return nil
}

var (
	fset       = token.NewFileSet() // *token.FileSet
	parserMode parser.Mode          // uint
	pos        token.Pos

	testPrefix     = "Test"
	testSuffix     = "_test"
	isTest         bool
	fnName         string
	fnNameNoExport string
)

type cmdTestSwitchEval struct {
	Cwd  string `msgpack:",array"`
	File string
}

func cmdTestSwitch(v *vim.Vim, eval cmdTestSwitchEval) {
	go TestSwitch(v, eval)
}

// TestSwitch switch to corresponds current cursor (test)function.
func TestSwitch(v *vim.Vim, eval cmdTestSwitchEval) error {
	defer profile.Start(time.Now(), "TestSwitch")

	// Check the current buffer name whether '*_test.go'.
	fname := eval.File
	exp := filepath.Ext(fname)
	var switchfile string
	if strings.Index(fname, testSuffix) == -1 {
		isTest = false
		switchfile = strings.Replace(fname, exp, testSuffix+exp, 1) // not testfile
	} else {
		isTest = true
		switchfile = strings.Replace(fname, testSuffix+exp, exp, 1) // testfile
	}

	// Check the exists of switch destination file.
	if _, err := os.Stat(switchfile); err != nil {
		return nvim.EchohlErr(v, "GoTestSwitch", "Switch destination file does not exist")
	}

	ctxt := new(context.Context)
	dir, _ := filepath.Split(fname)
	defer ctxt.Build.SetContext(filepath.Dir(dir))()

	var (
		b vim.Buffer
		w vim.Window
	)

	// Gets the current buffer information.
	p := v.NewPipeline()
	p.CurrentBuffer(&b)
	p.CurrentWindow(&w)
	if err := p.Wait(); err != nil {
		return err
	}

	// Get the byte offset of current cursor position from buffer.
	// TODO(zchee): Eval 'line2byte(line('.'))+(col('.')-2)' is faster and safer?
	byteOffset, err := nvim.ByteOffsetPipe(p, b, w)
	if err != nil {
		return err
	}
	// Get the 2d byte slice of current buffer.
	var buf [][]byte
	p.BufferLines(b, 0, -1, true, &buf)
	if err := p.Wait(); err != nil {
		return err
	}

	f, err := parse(fname, fset, bytes.Join(buf, []byte{'\n'})) // *ast.File
	if err != nil {
		return err
	}
	offset := fset.File(f.Pos()).Pos(byteOffset) // token.Pos

	// Parses the function ast node from the current cursor position.
	qpos, _ := astutil.PathEnclosingInterval(f, offset, offset) // path []ast.Node, exact bool
	for _, q := range qpos {
		switch x := q.(type) {
		case *ast.FuncDecl:
			if x.Name != nil { // *ast.Ident
				name := fmt.Sprintf("%s", x.Name)
				// TODO(zchee): Support parses the function struct name.
				// If the function has a struct, gotests will be generated the
				// mixed camel case test function name include struct name for prefix.
				if !isTest {
					fnName = fmt.Sprintf("%s%s%s", testPrefix, bytes.ToUpper([]byte{name[0]}), name[1:])
				} else {
					fnName = strings.Replace(name, testPrefix, "", 1)
				}
				fnNameNoExport = fmt.Sprintf("%s%s", bytes.ToLower([]byte{fnName[0]}), fnName[1:])
			}
		}
	}

	// Get the switch destination file ast node.
	fswitch, err := parse(switchfile, fset, nil) // *ast.File
	if err != nil {
		return err
	}

	if pos != token.NoPos {
		pos = 0
	}
	// Parses the switch destination file ast node.
	ast.Walk(visitorFunc(parseFunc), fswitch)

	if !pos.IsValid() {
		return nvim.EchohlErr(v, "GoTestSwitch", "Not found the switch destination function")
	}

	filename, line, col := quickfix.SplitPos(fset.Position(pos).String(), eval.Cwd)
	loclist := append([]*quickfix.ErrorlistData{}, &quickfix.ErrorlistData{
		FileName: filename,
		LNum:     line,
		Col:      col,
	})
	if err := quickfix.SetLoclist(v, loclist); err != nil {
		return err
	}

	// Jump to the corresponds function.
	p.Command(fmt.Sprintf("edit %s", filename))
	p.Command("normal! zz")

	return p.Wait()
}

// Wrapper of the parser.ParseFile()
func parse(filename string, fset *token.FileSet, src interface{}) (*ast.File, error) {
	file, err := parser.ParseFile(fset, filename, src, parserMode)
	if err != nil {
		return nil, err
	}

	return file, err
}

// visitorFunc for ast.Visit type.
type visitorFunc func(n ast.Node) ast.Visitor

// visit for ast.Visit function.
func (f visitorFunc) Visit(n ast.Node) ast.Visitor {
	return f(n)
}

// Core of the parser of the ast node.
func parseFunc(node ast.Node) ast.Visitor {
	switch x := node.(type) {
	default:
		return visitorFunc(parseFunc)
	case *ast.FuncDecl:
		if x.Name.Name == fnName || x.Name.Name == fnNameNoExport || indexFuncName(x.Name.Name, fnName, fnNameNoExport) { // x.Name.Name: *ast.Ident.string
			pos = x.Name.NamePos
			return nil
		}
	}

	return nil
}

func indexFuncName(s string, sep ...string) bool {
	for _, fn := range sep {
		i := strings.Index(fn, s)
		if i > -1 {
			return true
		}
	}

	return false
}
<commit_msg>cmds/test: Remove profile and Fix set term.Dir timing<commit_after>// Copyright 2016 Koichi Shiraishi. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package commands

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"os"
	"path/filepath"
	"strings"

	"nvim-go/config"
	"nvim-go/context"
	"nvim-go/nvim"
	"nvim-go/nvim/quickfix"
	"nvim-go/nvim/terminal"
	"nvim-go/pathutil"

	"github.com/garyburd/neovim-go/vim"
	"github.com/garyburd/neovim-go/vim/plugin"
	"golang.org/x/tools/go/ast/astutil"
)

func init() {
	plugin.HandleCommand("Gotest", &plugin.CommandOptions{NArgs: "*", Eval: "expand('%:p:h')"}, cmdTest)
	plugin.HandleCommand("GoTestSwitch", &plugin.CommandOptions{Eval: "[getcwd(), expand('%:p')]"}, cmdTestSwitch)
}

func cmdTest(v *vim.Vim, args []string, dir string) {
	go Test(v, args, dir)
}

var term *terminal.Terminal

// Test run the package test command use compile tool that determined from
// the directory structure.
func Test(v *vim.Vim, args []string, dir string) error {
	ctxt := new(context.Context)
	defer ctxt.Build.SetContext(dir)()

	cmd := []string{ctxt.Build.Tool, "test"}
	args = append(args, config.TestArgs...)
	if len(args) > 0 {
		cmd = append(cmd, args...)
	}

	if ctxt.Build.Tool == "go" {
		cmd = append(cmd, string("./..."))
	}

	if term == nil {
		term = terminal.NewTerminal(v, "__GO_TEST__", cmd, config.TerminalMode)
		term.Dir = pathutil.FindVcsRoot(dir)
	}

	if err := term.Run(cmd); err != nil {
		return err
	}

	return nil
}

var (
	fset       = token.NewFileSet() // *token.FileSet
	parserMode parser.Mode          // uint
	pos        token.Pos

	testPrefix     = "Test"
	testSuffix     = "_test"
	isTest         bool
	fnName         string
	fnNameNoExport string
)

type cmdTestSwitchEval struct {
	Cwd  string `msgpack:",array"`
	File string
}

func cmdTestSwitch(v *vim.Vim, eval cmdTestSwitchEval) {
	go TestSwitch(v, eval)
}

// TestSwitch switch to corresponds current cursor (test)function.
func TestSwitch(v *vim.Vim, eval cmdTestSwitchEval) error {
	// Check the current buffer name whether '*_test.go'.
	fname := eval.File
	exp := filepath.Ext(fname)
	var switchfile string
	if strings.Index(fname, testSuffix) == -1 {
		isTest = false
		switchfile = strings.Replace(fname, exp, testSuffix+exp, 1) // not testfile
	} else {
		isTest = true
		switchfile = strings.Replace(fname, testSuffix+exp, exp, 1) // testfile
	}

	// Check the exists of switch destination file.
	if _, err := os.Stat(switchfile); err != nil {
		return nvim.EchohlErr(v, "GoTestSwitch", "Switch destination file does not exist")
	}

	ctxt := new(context.Context)
	dir, _ := filepath.Split(fname)
	defer ctxt.Build.SetContext(filepath.Dir(dir))()

	var (
		b vim.Buffer
		w vim.Window
	)

	// Gets the current buffer information.
	p := v.NewPipeline()
	p.CurrentBuffer(&b)
	p.CurrentWindow(&w)
	if err := p.Wait(); err != nil {
		return err
	}

	// Get the byte offset of current cursor position from buffer.
	// TODO(zchee): Eval 'line2byte(line('.'))+(col('.')-2)' is faster and safer?
	byteOffset, err := nvim.ByteOffsetPipe(p, b, w)
	if err != nil {
		return err
	}
	// Get the 2d byte slice of current buffer.
	var buf [][]byte
	p.BufferLines(b, 0, -1, true, &buf)
	if err := p.Wait(); err != nil {
		return err
	}

	f, err := parse(fname, fset, bytes.Join(buf, []byte{'\n'})) // *ast.File
	if err != nil {
		return err
	}
	offset := fset.File(f.Pos()).Pos(byteOffset) // token.Pos

	// Parses the function ast node from the current cursor position.
	qpos, _ := astutil.PathEnclosingInterval(f, offset, offset) // path []ast.Node, exact bool
	for _, q := range qpos {
		switch x := q.(type) {
		case *ast.FuncDecl:
			if x.Name != nil { // *ast.Ident
				name := fmt.Sprintf("%s", x.Name)
				// TODO(zchee): Support parses the function struct name.
				// If the function has a struct, gotests will be generated the
				// mixed camel case test function name include struct name for prefix.
				if !isTest {
					fnName = fmt.Sprintf("%s%s%s", testPrefix, bytes.ToUpper([]byte{name[0]}), name[1:])
				} else {
					fnName = strings.Replace(name, testPrefix, "", 1)
				}
				fnNameNoExport = fmt.Sprintf("%s%s", bytes.ToLower([]byte{fnName[0]}), fnName[1:])
			}
		}
	}

	// Get the switch destination file ast node.
	fswitch, err := parse(switchfile, fset, nil) // *ast.File
	if err != nil {
		return err
	}

	if pos != token.NoPos {
		pos = 0
	}
	// Parses the switch destination file ast node.
	ast.Walk(visitorFunc(parseFunc), fswitch)

	if !pos.IsValid() {
		return nvim.EchohlErr(v, "GoTestSwitch", "Not found the switch destination function")
	}

	filename, line, col := quickfix.SplitPos(fset.Position(pos).String(), eval.Cwd)
	loclist := append([]*quickfix.ErrorlistData{}, &quickfix.ErrorlistData{
		FileName: filename,
		LNum:     line,
		Col:      col,
	})
	if err := quickfix.SetLoclist(v, loclist); err != nil {
		return err
	}

	// Jump to the corresponds function.
	p.Command(fmt.Sprintf("edit %s", filename))
	p.Command("normal! zz")

	return p.Wait()
}

// Wrapper of the parser.ParseFile()
func parse(filename string, fset *token.FileSet, src interface{}) (*ast.File, error) {
	file, err := parser.ParseFile(fset, filename, src, parserMode)
	if err != nil {
		return nil, err
	}

	return file, err
}

// visitorFunc for ast.Visit type.
type visitorFunc func(n ast.Node) ast.Visitor

// visit for ast.Visit function.
func (f visitorFunc) Visit(n ast.Node) ast.Visitor {
	return f(n)
}

// Core of the parser of the ast node.
func parseFunc(node ast.Node) ast.Visitor {
	switch x := node.(type) {
	default:
		return visitorFunc(parseFunc)
	case *ast.FuncDecl:
		if x.Name.Name == fnName || x.Name.Name == fnNameNoExport || indexFuncName(x.Name.Name, fnName, fnNameNoExport) { // x.Name.Name: *ast.Ident.string
			pos = x.Name.NamePos
			return nil
		}
	}

	return nil
}

func indexFuncName(s string, sep ...string) bool {
	for _, fn := range sep {
		i := strings.Index(fn, s)
		if i > -1 {
			return true
		}
	}

	return false
}
<|endoftext|>


<commit_before>package plugin

import (
	log "github.com/Sirupsen/logrus"
	"github.com/yuin/gluamapper"
	"github.com/yuin/gopher-lua"
)

// Plugin module handles the registration
// and management of plugins.
type Plugin struct {
	Plugins map[string]luaPlugin
	help    map[string]string
}

type luaPlugin struct {
	Name        string
	Description string
	Help        string
	Bind        map[string]*lua.LFunction
}

// NewPluginModule returns a new plugin module
func NewPluginModule() *Plugin {
	return &Plugin{
		Plugins: make(map[string]luaPlugin),
		help:    make(map[string]string),
	}
}

// Register will register the plugin module to
// the given lua state.
func (p *Plugin) Register(state *lua.LState) {
	state.PreloadModule("plugin", p.loader)
}

func (p *Plugin) loader(state *lua.LState) int {
	// Bind the functions to the module
	module := state.SetFuncs(state.NewTable(), map[string]lua.LGFunction{
		"add": p.Add,
	})

	// Push the module, exposing it to the Lua state
	state.Push(module)

	return 1
}

// Add will add a new plugin to the system
func (p *Plugin) Add(state *lua.LState) int {
	// Build the logger
	logger := log.WithField("file", state.Where(1))

	// Check so we get the required number of parameters
	if state.GetTop() != 1 {
		logger.Errorf("Plugin:Add takes one parameter, we got '%d'", state.GetTop())
		return 0
	}

	// Get the table
	if state.Get(1).Type() != lua.LTTable {
		logger.Errorf("Geoffrey:Add takes table as a parameter, we got '%s'", state.Get(1).Type().String())
		return 0
	}
	table := state.Get(1).(*lua.LTable)

	// The registered plugin
	var plugin luaPlugin

	// Map the table
	if err := gluamapper.Map(table, &plugin); err != nil {
		logger.WithError(err).Errorln("Could not parse the plugin")
		return 0
	}

	if _, ok := p.Plugins[plugin.Name]; ok {
		logger.Errorf("Plugin with name '%s' already exist", plugin.Name)
		return 0
	}

	p.Plugins[plugin.Name] = plugin

	if plugin.Help != "" {
		p.help[plugin.Name] = plugin.Help
	}

	logger.Infof("Registered plugin '%s'", plugin.Name)

	return 0
}

// Help will return the help string for the given function
// if it exists.
func (p *Plugin) Help(state *lua.LState) int {
	if val, ok := p.help[state.ToString(-1)]; ok && val != "" {
		state.Push(lua.LString(val))
	} else {
		state.Push(lua.LString("No help exists for that function"))
	}

	return 1
}
<commit_msg>expose the help command to lua<commit_after>package plugin

import (
	log "github.com/Sirupsen/logrus"
	"github.com/yuin/gluamapper"
	"github.com/yuin/gopher-lua"
)

// Plugin module handles the registration
// and management of plugins.
type Plugin struct {
	Plugins map[string]luaPlugin
	help    map[string]string
}

type luaPlugin struct {
	Name        string
	Description string
	Help        string
	Bind        map[string]*lua.LFunction
}

// NewPluginModule returns a new plugin module
func NewPluginModule() *Plugin {
	return &Plugin{
		Plugins: make(map[string]luaPlugin),
		help:    make(map[string]string),
	}
}

// Register will register the plugin module to
// the given lua state.
func (p *Plugin) Register(state *lua.LState) {
	state.PreloadModule("plugin", p.loader)
}

func (p *Plugin) loader(state *lua.LState) int {
	// Bind the functions to the module
	module := state.SetFuncs(state.NewTable(), map[string]lua.LGFunction{
		"add":  p.Add,
		"help": p.Help,
	})

	// Push the module, exposing it to the Lua state
	state.Push(module)

	return 1
}

// Add will add a new plugin to the system
func (p *Plugin) Add(state *lua.LState) int {
	// Build the logger
	logger := log.WithField("file", state.Where(1))

	// Check so we get the required number of parameters
	if state.GetTop() != 1 {
		logger.Errorf("Plugin:Add takes one parameter, we got '%d'", state.GetTop())
		return 0
	}

	// Get the table
	if state.Get(1).Type() != lua.LTTable {
		logger.Errorf("Geoffrey:Add takes table as a parameter, we got '%s'", state.Get(1).Type().String())
		return 0
	}
	table := state.Get(1).(*lua.LTable)

	// The registered plugin
	var plugin luaPlugin

	// Map the table
	if err := gluamapper.Map(table, &plugin); err != nil {
		logger.WithError(err).Errorln("Could not parse the plugin")
		return 0
	}

	if _, ok := p.Plugins[plugin.Name]; ok {
		logger.Errorf("Plugin with name '%s' already exist", plugin.Name)
		return 0
	}

	p.Plugins[plugin.Name] = plugin

	if plugin.Help != "" {
		p.help[plugin.Name] = plugin.Help
	}

	logger.Infof("Registered plugin '%s'", plugin.Name)

	return 0
}

// Help will return the help string for the given function
// if it exists.
func (p *Plugin) Help(state *lua.LState) int {
	if val, ok := p.help[state.ToString(-1)]; ok && val != "" {
		state.Push(lua.LString(val))
	} else {
		state.Push(lua.LString("No help exists for that function"))
	}

	return 1
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"os"
)

const version = "0.1.3"

func testPrint(w io.Writer) {
	fmt.Fprint(w, "Hello world!! "+version+"\n")
}

func main() {
	testPrint(os.Stdout)
}
<commit_msg>Change output format without change version<commit_after>package main

import (
	"fmt"
	"io"
	"os"
)

const version = "0.1.3"

func testPrint(w io.Writer) {
	fmt.Fprint(w, "Hello world!! ["+version+"]\n")
}

func main() {
	testPrint(os.Stdout)
}
<|endoftext|>


<commit_before>package renter

import (
	"crypto/rand"
	"errors"
	"time"

	"github.com/NebulousLabs/Sia/modules"
)

const (
	maxUploadAttempts = 8
)

// threadedUploadPiece will upload the piece of a file to a randomly chosen
// host. If the wallet has insufficient balance to support uploading,
// uploadPiece will give up. The file uploading can be continued using a repair
// tool. Upon completion, the memory containg the piece's information is
// updated.
func (r *Renter) threadedUploadPiece(up modules.UploadParams, piece *FilePiece) {
	// Set 'Repairing' for the piece to true.
	r.mu.Lock()
	piece.Repairing = true
	r.mu.Unlock()

	// Try 'maxUploadAttempts' hosts before giving up.
	for attempts := 0; attempts < maxUploadAttempts; attempts++ {
		// Select a host. An error here is unrecoverable.
		host, err := r.hostDB.RandomHost()
		if err != nil {
			return
		}

		// Negotiate the contract with the host. If the negotiation is
		// unsuccessful, we need to try again with a new host. Otherwise, the
		// file will be uploaded and we'll be done.
		contract, contractID, err := r.negotiateContract(host, up)
		if err != nil {
			// The previous attempt didn't work. We will try again after
			// sleeping for a randomized amount of time to increase our chances
			// of success. This will help spread things out if there are
			// problems with network congestion or other randomized issues.
			randSource := make([]byte, 1)
			rand.Read(randSource)
			time.Sleep(time.Duration(attempts) * time.Duration(attempts) * 250 * time.Millisecond * time.Duration(randSource[0]))
			continue
		}

		r.mu.Lock()
		*piece = FilePiece{
			Active:     true,
			Repairing:  false,
			Contract:   contract,
			ContractID: contractID,
			HostIP:     host.IPAddress,
		}
		r.save()
		r.mu.Unlock()
		return
	}
}

// Upload takes an upload parameters, which contain a file to upload, and then
// creates a redundant copy of the file on the Sia network.
func (r *Renter) Upload(up modules.UploadParams) error {
	r.mu.Lock()
	defer r.mu.Unlock()

	// Check for a nickname conflict.
	_, exists := r.files[up.Nickname]
	if exists {
		return errors.New("file with that nickname already exists")
	}

	// Check that the hostdb is sufficiently large to support an upload. Right
	// now that value is set to 3, but in the future the logic will be a bit
	// more complex; once there is erasure coding we'll want to hit the minimum
	// number of pieces plus some buffer before we decide that an upload is
	// okay.
	if len(r.hostDB.ActiveHosts()) < 1 {
		return errors.New("not enough hosts on the network to upload a file :( - maybe you need to upgrade your software")
	}

	// Upload a piece to every host on the network.
	r.files[up.Nickname] = File{
		nickname:     up.Nickname,
		pieces:       make([]FilePiece, up.Pieces),
		startHeight:  r.state.Height() + up.Duration,
		renter:       r,
		uploadParams: up,
	}
	for i := range r.files[up.Nickname].pieces {
		// threadedUploadPiece will change the memory that the piece points to,
		// which is useful because it means the file itself can be renamed but
		// will still point to the same underlying pieces.
		go r.threadedUploadPiece(up, &r.files[up.Nickname].pieces[i])
	}
	r.save()

	return nil
}
<commit_msg>return error if balance is too low to upload<commit_after>package renter

import (
	"crypto/rand"
	"errors"
	"os"
	"time"

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

const (
	maxUploadAttempts = 8
)

// checkWalletBalance looks at an upload and determines if there is enough
// money in the wallet to support such an upload. An error is returned if it is
// determined that there is not enough money.
func (r *Renter) checkWalletBalance(up modules.UploadParams) error {
	// Get the size of the file.
	fileInfo, err := os.Stat(up.Filename)
	if err != nil {
		return err
	}
	curSize := types.NewCurrency64(uint64(fileInfo.Size()))

	// TODO: Change average to median so that outliers are ignored.
	sampleSize := 12
	var averagePrice types.Currency
	for i := 0; i < sampleSize; i++ {
		potentialHost, err := r.hostDB.RandomHost()
		if err != nil {
			return err
		}
		averagePrice = averagePrice.Add(potentialHost.Price)
	}
	averagePrice = averagePrice.Div(types.NewCurrency64(uint64(sampleSize)))
	estimatedCost := averagePrice.Mul(types.NewCurrency64(uint64(up.Duration))).Mul(curSize)
	bufferedCost := estimatedCost.Mul(types.NewCurrency64(2))

	if bufferedCost.Cmp(r.wallet.Balance(false)) > 0 {
		return errors.New("insufficient balance for upload")
	}
	return nil
}

// threadedUploadPiece will upload the piece of a file to a randomly chosen
// host. If the wallet has insufficient balance to support uploading,
// uploadPiece will give up. The file uploading can be continued using a repair
// tool. Upon completion, the memory containg the piece's information is
// updated.
func (r *Renter) threadedUploadPiece(up modules.UploadParams, piece *FilePiece) {
	// Set 'Repairing' for the piece to true.
	r.mu.Lock()
	piece.Repairing = true
	r.mu.Unlock()

	// Try 'maxUploadAttempts' hosts before giving up.
	for attempts := 0; attempts < maxUploadAttempts; attempts++ {
		// Select a host. An error here is unrecoverable.
		host, err := r.hostDB.RandomHost()
		if err != nil {
			return
		}

		// Negotiate the contract with the host. If the negotiation is
		// unsuccessful, we need to try again with a new host. Otherwise, the
		// file will be uploaded and we'll be done.
		contract, contractID, err := r.negotiateContract(host, up)
		if err != nil {
			// The previous attempt didn't work. We will try again after
			// sleeping for a randomized amount of time to increase our chances
			// of success. This will help spread things out if there are
			// problems with network congestion or other randomized issues.
			randSource := make([]byte, 1)
			rand.Read(randSource)
			time.Sleep(time.Duration(attempts) * time.Duration(attempts) * 250 * time.Millisecond * time.Duration(randSource[0]))
			continue
		}

		r.mu.Lock()
		*piece = FilePiece{
			Active:     true,
			Repairing:  false,
			Contract:   contract,
			ContractID: contractID,
			HostIP:     host.IPAddress,
		}
		r.save()
		r.mu.Unlock()
		return
	}
}

// Upload takes an upload parameters, which contain a file to upload, and then
// creates a redundant copy of the file on the Sia network.
func (r *Renter) Upload(up modules.UploadParams) error {
	r.mu.Lock()
	defer r.mu.Unlock()

	err := r.checkWalletBalance(up)
	if err != nil {
		return err
	}

	// Check for a nickname conflict.
	_, exists := r.files[up.Nickname]
	if exists {
		return errors.New("file with that nickname already exists")
	}

	// Check that the hostdb is sufficiently large to support an upload. Right
	// now that value is set to 3, but in the future the logic will be a bit
	// more complex; once there is erasure coding we'll want to hit the minimum
	// number of pieces plus some buffer before we decide that an upload is
	// okay.
	if len(r.hostDB.ActiveHosts()) < 1 {
		return errors.New("not enough hosts on the network to upload a file :( - maybe you need to upgrade your software")
	}

	// Upload a piece to every host on the network.
	r.files[up.Nickname] = File{
		nickname:     up.Nickname,
		pieces:       make([]FilePiece, up.Pieces),
		startHeight:  r.state.Height() + up.Duration,
		renter:       r,
		uploadParams: up,
	}
	for i := range r.files[up.Nickname].pieces {
		// threadedUploadPiece will change the memory that the piece points to,
		// which is useful because it means the file itself can be renamed but
		// will still point to the same underlying pieces.
		go r.threadedUploadPiece(up, &r.files[up.Nickname].pieces[i])
	}
	r.save()

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/Cepave/open-falcon-backend/common/logruslog"
	"github.com/Cepave/open-falcon-backend/common/vipercfg"
	"github.com/Cepave/open-falcon-backend/modules/transfer/g"
	"github.com/Cepave/open-falcon-backend/modules/transfer/http"
	"github.com/Cepave/open-falcon-backend/modules/transfer/proc"
	"github.com/Cepave/open-falcon-backend/modules/transfer/receiver"
	"github.com/Cepave/open-falcon-backend/modules/transfer/sender"
	flag "github.com/spf13/pflag"
	"os"
)

func main() {
	vipercfg.Parse()
	vipercfg.Bind()

	if vipercfg.Config().GetBool("version") {
		fmt.Println(g.VERSION)
		os.Exit(0)
	}
	if vipercfg.Config().GetBool("vg") {
		fmt.Println(g.VERSION, g.COMMIT)
		os.Exit(0)
	}

	// global config
	vipercfg.Load()
	g.ParseConfig(vipercfg.Config().GetString("config"))
	logruslog.Init()
	// proc
	proc.Start()

	sender.Start()
	receiver.Start()

	// http
	http.Start()

	select {}
}
<commit_msg>removed unuessery commit file<commit_after>package main

import (
	"fmt"
	"github.com/Cepave/open-falcon-backend/common/logruslog"
	"github.com/Cepave/open-falcon-backend/common/vipercfg"
	"github.com/Cepave/open-falcon-backend/modules/transfer/g"
	"github.com/Cepave/open-falcon-backend/modules/transfer/http"
	"github.com/Cepave/open-falcon-backend/modules/transfer/proc"
	"github.com/Cepave/open-falcon-backend/modules/transfer/receiver"
	"github.com/Cepave/open-falcon-backend/modules/transfer/sender"
	"os"
)

func main() {
	vipercfg.Parse()
	vipercfg.Bind()

	if vipercfg.Config().GetBool("version") {
		fmt.Println(g.VERSION)
		os.Exit(0)
	}
	if vipercfg.Config().GetBool("vg") {
		fmt.Println(g.VERSION, g.COMMIT)
		os.Exit(0)
	}

	// global config
	vipercfg.Load()
	g.ParseConfig(vipercfg.Config().GetString("config"))
	logruslog.Init()
	// proc
	proc.Start()

	sender.Start()
	receiver.Start()

	// http
	http.Start()

	select {}
}
<|endoftext|>


<commit_before>package wallet

import (
	"sort"

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

const (
	// defragThreshold is the number of outputs a wallet is allowed before it is
	// defragmented.
	defragThreshold = 20

	// defragBatchSize defines how many outputs are combined during one defrag.
	defragBatchSize = 15
)

// defragWallet computes the sum of the 15 largest outputs in the wallet and
// sends that sum to itself, effectively defragmenting the wallet. This defrag
// operation is only performed if the wallet has greater than defragThreshold
// outputs.
func (w *Wallet) defragWallet() {
	if len(w.siacoinOutputs) < defragThreshold {
		return
	}

	// grab all the outputs from the wallet and sort them from
	// largest -> smallest
	var so sortedOutputs
	for scoid, sco := range w.siacoinOutputs {
		so.ids = append(so.ids, scoid)
		so.outputs = append(so.outputs, sco)
	}
	sort.Sort(sort.Reverse(so))

	// choose the defragBatchSizeth largest outputs from the wallet and sum them
	defragOutputs := so.outputs[:defragBatchSize]
	var totalOutputValue types.Currency
	for _, output := range defragOutputs {
		totalOutputValue = totalOutputValue.Add(output.Value)
	}

	w.log.Printf("defragmenting wallet: %v outputs, %v total value\n", len(defragOutputs), totalOutputValue)

	// grab a new address from the wallet
	addr, err := w.nextPrimarySeedAddress()
	if err != nil {
		w.log.Println("error getting an address for defrag: ", err)
		return
	}

	// send the sum of the outputs to this wallet. This operation is done in a
	// goroutine since defragWallet() is called under lock.
	go func() {
		_, err := w.SendSiacoins(totalOutputValue, addr.UnlockHash())
		if err != nil {
			w.log.Println("error after call to SendSiacoins: ", err)
		}
	}()
}
<commit_msg>tweak constants, add defrag transaction size logging<commit_after>package wallet

import (
	"sort"

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

const (
	// defragThreshold is the number of outputs a wallet is allowed before it is
	// defragmented.
	defragThreshold = 50

	// defragBatchSize defines how many outputs are combined during one defrag.
	defragBatchSize = 40
)

// defragWallet computes the sum of the 15 largest outputs in the wallet and
// sends that sum to itself, effectively defragmenting the wallet. This defrag
// operation is only performed if the wallet has greater than defragThreshold
// outputs.
func (w *Wallet) defragWallet() {
	if len(w.siacoinOutputs) < defragThreshold {
		return
	}

	// grab all the outputs from the wallet and sort them from
	// largest -> smallest
	var so sortedOutputs
	for scoid, sco := range w.siacoinOutputs {
		so.ids = append(so.ids, scoid)
		so.outputs = append(so.outputs, sco)
	}
	sort.Sort(sort.Reverse(so))

	// choose the defragBatchSizeth largest outputs from the wallet and sum them
	defragOutputs := so.outputs[:defragBatchSize]
	var totalOutputValue types.Currency
	for _, output := range defragOutputs {
		totalOutputValue = totalOutputValue.Add(output.Value)
	}

	w.log.Printf("defragmenting wallet: %v outputs, %v total value\n", len(defragOutputs), totalOutputValue)

	// grab a new address from the wallet
	addr, err := w.nextPrimarySeedAddress()
	if err != nil {
		w.log.Println("error getting an address for defrag: ", err)
		return
	}

	// send the sum of the outputs to this wallet. This operation is done in a
	// goroutine since defragWallet() is called under lock.
	go func() {
		txns, err := w.SendSiacoins(totalOutputValue, addr.UnlockHash())
		if err != nil {
			w.log.Println("error after call to SendSiacoins: ", err)
		}

		w.log.Println("defrag transaction size: ", len(encoding.Marshal(txns)))
	}()
}
<|endoftext|>


<commit_before>package main

import(
  "fmt"
  "io"
  "io/ioutil"
  "crypto/sha1"
  "os"
  "os/exec"
  "path/filepath"
  "bytes"
  "runtime"
  "strings"
  "github.com/kr/s3/s3util"
  "github.com/jessevdk/go-flags"
)

const VERSION = "0.2.0"

const(
  ERR_WRONG_USAGE    = 2
  ERR_NO_CREDENTIALS = 3
  ERR_NO_BUNDLE      = 4
  ERR_BUNDLE_EXISTS  = 5
  ERR_NO_GEMLOCK     = 6
)

var options struct {
  Prefix    string `long:"prefix"     description:"Custom archive filename (default: current dir)"`
  Path      string `long:"path"       description:"Path to directory with .bundle (default: current)"`
  AccessKey string `long:"access-key" description:"S3 Access key"`
  SecretKey string `long:"secret-key" description:"S3 Secret key"`
  Bucket    string `long:"bucket"     description:"S3 Bucket name"`
}

func terminate(message string, exit_code int) {
  fmt.Fprintln(os.Stderr, message)
  os.Exit(exit_code)
}

func terminateWithError(err error, exit_code int) {
  fmt.Fprintln(os.Stderr, err)
  os.Exit(exit_code)
}

func fileExists(path string) bool {
  _, err := os.Stat(path)
  return err == nil
}

func open(s string) (io.ReadCloser, error) {
  if isURL(s) {
    return s3util.Open(s, nil)
  }
  return os.Open(s)
}

func create(s string) (io.WriteCloser, error) {
  if isURL(s) {
    return s3util.Create(s, nil, nil)
  }
  return os.Create(s)
}

func isURL(s string) bool {
  return strings.HasPrefix(s, "http://") || strings.HasPrefix(s, "https://")
}

func s3url(filename string) string {
  format := "https://s3.amazonaws.com/%s/%s"
  url := fmt.Sprintf(format, options.Bucket, filename)

  return url
}

func sh(command string) (string, error) {
  var output bytes.Buffer

  cmd := exec.Command("bash", "-c", command)

  cmd.Stdout = &output
  cmd.Stderr = &output

  err := cmd.Run()
  return output.String(), err
}

func calculateChecksum(buffer string) string {
  h := sha1.New()
  io.WriteString(h, buffer)
  return fmt.Sprintf("%x", h.Sum(nil))
}

func transferArchive(file string, url string) {
  s3util.DefaultConfig.AccessKey = options.AccessKey
  s3util.DefaultConfig.SecretKey = options.SecretKey

  r, err := open(file)
  if err != nil {
    terminateWithError(err, 1)
  }

  w, err := create(url)
  if err != nil {
    terminateWithError(err, 1)
  }

  _, err = io.Copy(w, r)
  if err != nil {
    terminateWithError(err, 1)
  }

  err = w.Close()
  if err != nil {
    terminateWithError(err, 1)
  }
}

func extractArchive(filename string, path string) bool {
  cmd_mkdir   := fmt.Sprintf("cd %s && mkdir .bundle", path)
  cmd_move    := fmt.Sprintf("mv %s %s/.bundle/bundle_cache.tar.gz", filename, path)
  cmd_extract := fmt.Sprintf("cd %s/.bundle && tar -xzf ./bundle_cache.tar.gz", path)
  cmd_remove  := fmt.Sprintf("rm %s/.bundle/bundle_cache.tar.gz", path)

  if _, err := sh(cmd_mkdir) ; err != nil {
    fmt.Println("Bundle directory '.bundle' already exists")
    return false
  }

  if _, err := sh(cmd_move) ; err != nil {
    fmt.Println("Unable to move file")
    return false
  }

  if out, err := sh(cmd_extract) ; err != nil {
    fmt.Println("Unable to extract:", out)
    return false
  }

  if _, err := sh(cmd_remove) ; err != nil {
    fmt.Println("Unable to remove archive")
    return false
  }

  return true
}

func envDefined(name string) bool {
  result := os.Getenv(name)
  return len(result) > 0
}

func checkS3Credentials() {
  if len(options.AccessKey) == 0 {
    terminate("Please provide S3 access key", ERR_NO_CREDENTIALS)
  }

  if len(options.SecretKey) == 0 {
    terminate("Please provide S3 secret key", ERR_NO_CREDENTIALS)
  }

  if len(options.Bucket) == 0 {
    terminate("Please provide S3 bucket name", ERR_NO_CREDENTIALS)
  }
}

func printUsage() {
  terminate("Usage: bundle_cache [download|upload]", ERR_WRONG_USAGE)
}

func upload(bundle_path string, archive_path string, archive_url string) {
  cache_file := fmt.Sprintf("%s/.bundle_cache", options.Path)

  if fileExists(cache_file) {
    fmt.Println("Your bundle is cached. Skipping...")
    os.Exit(0)
  }

  if !fileExists(bundle_path) {
    terminate("Bundle path does not exist", ERR_NO_BUNDLE)
  }

  fmt.Println("Archiving...")
  cmd := fmt.Sprintf("cd %s && tar -czf %s .", bundle_path, archive_path)
  if _, err := sh(cmd); err != nil {
    terminate("Failed to make archive.", 1)
  }

  fmt.Println("Transferring...")
  transferArchive(archive_path, archive_url)

  os.Exit(0)
}

func download(path string, bundle_path string, archive_path string, archive_url string) {
  if fileExists(bundle_path) {
    terminate("Bundle path already exists, skipping.", 0)
  }

  /* Download archive from S3 */
  fmt.Println("Downloading...", archive_url)
  transferArchive(archive_url, archive_path)

  /* Extract archive into bundle directory */
  fmt.Println("Extracting...")
  extractArchive(archive_path, path)

  /* Create a temp file in path to indicate that bundle was cached */
  cache_file := fmt.Sprintf("%s/.bundle_cache", options.Path)
  if !fileExists(cache_file) {
    sh(fmt.Sprintf("touch %s", cache_file))
  }

  os.Exit(0)
}

func main() {
  new_args, err := flags.ParseArgs(&options, os.Args)

  if err != nil {
    fmt.Println(err)
    os.Exit(ERR_WRONG_USAGE)
  }

  if len(options.AccessKey) == 0 && envDefined("S3_ACCESS_KEY") {
    options.AccessKey = os.Getenv("S3_ACCESS_KEY")
  }

  if len(options.SecretKey) == 0 && envDefined("S3_SECRET_KEY") {
    options.SecretKey = os.Getenv("S3_SECRET_KEY")
  }

  if len(options.Bucket) == 0 && envDefined("S3_BUCKET") {
    options.Bucket = os.Getenv("S3_BUCKET")
  }

  args := new_args[1:]

  if len(args) != 1 {
    printUsage()
  }

  action := args[0]

  checkS3Credentials()

  if len(options.Path) == 0 {
    options.Path, _ = os.Getwd()
  }

  if len(options.Prefix) == 0 {
    options.Prefix = filepath.Base(options.Path)
  }

  bundle_path   := fmt.Sprintf("%s/.bundle", options.Path)
  lockfile_path := fmt.Sprintf("%s/Gemfile.lock", options.Path)

  if !fileExists(lockfile_path) {
    message := fmt.Sprintf("%s does not exist", lockfile_path)
    terminate(message, ERR_NO_GEMLOCK)
  }

  lockfile, err := ioutil.ReadFile(lockfile_path)
  if err != nil {
    terminate("Unable to read Gemfile.lock", 1)
  }

  checksum     := calculateChecksum(string(lockfile))
  archive_name := fmt.Sprintf("%s_%s_%s.tar.gz", options.Prefix, checksum, runtime.GOARCH)
  archive_path := fmt.Sprintf("/tmp/%s", archive_name)
  archive_url  := s3url(archive_name)

  if fileExists(archive_path) {
    if os.Remove(archive_path) != nil {
      terminate("Failed to remove existing archive", 1)
    }
  }

  if action == "upload" || action == "up" {
    upload(bundle_path, archive_path, archive_url)
  }

  if action == "download" || action == "down" {
    download(options.Path, bundle_path, archive_path, archive_url)
  }

  fmt.Println("Invalid command:", action)
  printUsage()
}
<commit_msg>Refactor to use options<commit_after>package main

import(
  "fmt"
  "io"
  "io/ioutil"
  "crypto/sha1"
  "os"
  "os/exec"
  "path/filepath"
  "bytes"
  "runtime"
  "strings"
  "github.com/kr/s3/s3util"
  "github.com/jessevdk/go-flags"
)

const VERSION = "0.2.0"

const(
  ERR_OK             = 0
  ERR_WRONG_USAGE    = 2
  ERR_NO_CREDENTIALS = 3
  ERR_NO_BUNDLE      = 4
  ERR_BUNDLE_EXISTS  = 5
  ERR_NO_GEMLOCK     = 6
)

var options struct {
  Prefix        string `long:"prefix"     description:"Custom archive filename (default: current dir)"`
  Path          string `long:"path"       description:"Path to directory with .bundle (default: current)"`
  AccessKey     string `long:"access-key" description:"S3 Access key"`
  SecretKey     string `long:"secret-key" description:"S3 Secret key"`
  Bucket        string `long:"bucket"     description:"S3 Bucket name"`
  BundlePath    string
  LockFilePath  string
  CacheFilePath string
  ArchiveName   string
  ArchivePath   string
  ArchiveUrl    string
}

func terminate(message string, exit_code int) {
  fmt.Fprintln(os.Stderr, message)
  os.Exit(exit_code)
}

func terminateWithError(err error, exit_code int) {
  fmt.Fprintln(os.Stderr, err)
  os.Exit(exit_code)
}

func fileExists(path string) bool {
  _, err := os.Stat(path)
  return err == nil
}

func open(s string) (io.ReadCloser, error) {
  if isURL(s) {
    return s3util.Open(s, nil)
  }
  return os.Open(s)
}

func create(s string) (io.WriteCloser, error) {
  if isURL(s) {
    return s3util.Create(s, nil, nil)
  }
  return os.Create(s)
}

func isURL(s string) bool {
  return strings.HasPrefix(s, "http://") || strings.HasPrefix(s, "https://")
}

func s3url(filename string) string {
  format := "https://s3.amazonaws.com/%s/%s"
  url := fmt.Sprintf(format, options.Bucket, filename)

  return url
}

func sh(command string) (string, error) {
  var output bytes.Buffer

  cmd := exec.Command("bash", "-c", command)

  cmd.Stdout = &output
  cmd.Stderr = &output

  err := cmd.Run()
  return output.String(), err
}

func calculateChecksum(buffer string) string {
  h := sha1.New()
  io.WriteString(h, buffer)
  return fmt.Sprintf("%x", h.Sum(nil))
}

func transferArchive(file string, url string) {
  s3util.DefaultConfig.AccessKey = options.AccessKey
  s3util.DefaultConfig.SecretKey = options.SecretKey

  r, err := open(file)
  if err != nil {
    terminateWithError(err, 1)
  }

  w, err := create(url)
  if err != nil {
    terminateWithError(err, 1)
  }

  _, err = io.Copy(w, r)
  if err != nil {
    terminateWithError(err, 1)
  }

  err = w.Close()
  if err != nil {
    terminateWithError(err, 1)
  }
}

func extractArchive(filename string, path string) bool {
  cmd_mkdir   := fmt.Sprintf("cd %s && mkdir .bundle", path)
  cmd_move    := fmt.Sprintf("mv %s %s/.bundle/bundle_cache.tar.gz", filename, path)
  cmd_extract := fmt.Sprintf("cd %s/.bundle && tar -xzf ./bundle_cache.tar.gz", path)
  cmd_remove  := fmt.Sprintf("rm %s/.bundle/bundle_cache.tar.gz", path)

  if _, err := sh(cmd_mkdir) ; err != nil {
    fmt.Println("Bundle directory '.bundle' already exists")
    return false
  }

  if _, err := sh(cmd_move) ; err != nil {
    fmt.Println("Unable to move file")
    return false
  }

  if out, err := sh(cmd_extract) ; err != nil {
    fmt.Println("Unable to extract:", out)
    return false
  }

  if _, err := sh(cmd_remove) ; err != nil {
    fmt.Println("Unable to remove archive")
    return false
  }

  return true
}

func envDefined(name string) bool {
  result := os.Getenv(name)
  return len(result) > 0
}

func checkS3Credentials() {
  if len(options.AccessKey) == 0 && envDefined("S3_ACCESS_KEY") {
    options.AccessKey = os.Getenv("S3_ACCESS_KEY")
  }

  if len(options.SecretKey) == 0 && envDefined("S3_SECRET_KEY") {
    options.SecretKey = os.Getenv("S3_SECRET_KEY")
  }

  if len(options.Bucket) == 0 && envDefined("S3_BUCKET") {
    options.Bucket = os.Getenv("S3_BUCKET")
  }

  if len(options.AccessKey) == 0 {
    terminate("Please provide S3 access key", ERR_NO_CREDENTIALS)
  }

  if len(options.SecretKey) == 0 {
    terminate("Please provide S3 secret key", ERR_NO_CREDENTIALS)
  }

  if len(options.Bucket) == 0 {
    terminate("Please provide S3 bucket name", ERR_NO_CREDENTIALS)
  }
}

func printUsage() {
  terminate("Usage: bundle_cache [download|upload]", ERR_WRONG_USAGE)
}

func upload() {
  if fileExists(options.CacheFilePath) {
    terminate("Your bundle is cached, skipping.", ERR_OK)
  }

  if !fileExists(options.BundlePath) {
    terminate("Bundle path does not exist", ERR_NO_BUNDLE)
  }

  fmt.Println("Archiving...")
  cmd := fmt.Sprintf("cd %s && tar -czf %s .", options.BundlePath, options.ArchivePath)
  if _, err := sh(cmd); err != nil {
    terminate("Failed to make archive.", 1)
  }

  fmt.Println("Uploading bundle to S3...")
  transferArchive(options.ArchivePath, options.ArchiveUrl)

  fmt.Println("Done")
  os.Exit(0)
}

func download() {
  if fileExists(options.BundlePath) {
    terminate("Bundle path already exists, skipping.", 0)
  }

  fmt.Println("Downloading bundle from S3...", options.ArchiveUrl)
  transferArchive(options.ArchiveUrl, options.ArchivePath)

  /* Extract archive into bundle directory */
  fmt.Println("Extracting...")
  extractArchive(options.ArchivePath, options.Path)

  /* Create a temp file in path to indicate that bundle was cached */
  if !fileExists(options.CacheFilePath) {
    sh(fmt.Sprintf("touch %s", options.CacheFilePath))
  }

  fmt.Println("Done")
  os.Exit(0)
}

func main() {
  new_args, err := flags.ParseArgs(&options, os.Args)

  if err != nil {
    fmt.Println(err)
    os.Exit(ERR_WRONG_USAGE)
  }

  args := new_args[1:]

  if len(args) != 1 {
    printUsage()
  }

  action := args[0]

  checkS3Credentials()

  if len(options.Path) == 0 {
    options.Path, _ = os.Getwd()
  }

  if len(options.Prefix) == 0 {
    options.Prefix = filepath.Base(options.Path)
  }

  options.BundlePath    = fmt.Sprintf("%s/.bundle", options.Path)
  options.LockFilePath  = fmt.Sprintf("%s/Gemfile.lock", options.Path)
  options.CacheFilePath = fmt.Sprintf("%s/.bundle_cache", options.Path)

  if !fileExists(options.LockFilePath) {
    message := fmt.Sprintf("%s does not exist", options.LockFilePath)
    terminate(message, ERR_NO_GEMLOCK)
  }

  lockfile, err := ioutil.ReadFile(options.LockFilePath)
  if err != nil {
    terminate("Unable to read Gemfile.lock", 1)
  }

  checksum  := calculateChecksum(string(lockfile))

  options.ArchiveName = fmt.Sprintf("%s_%s_%s.tar.gz", options.Prefix, checksum, runtime.GOARCH)
  options.ArchivePath = fmt.Sprintf("/tmp/%s", options.ArchiveName)
  options.ArchiveUrl  = s3url(options.ArchiveName)

  if fileExists(options.ArchivePath) {
    if os.Remove(options.ArchivePath) != nil {
      terminate("Failed to remove existing archive", 1)
    }
  }

  if action == "upload" {
    upload()
  }

  if action == "download" {
    download()
  }

  fmt.Println("Invalid command:", action)
  printUsage()
}
<|endoftext|>


<commit_before>package chart

const (
	// DefaultMovingAverageWindowSize is the default number of values to average.
	DefaultMovingAverageWindowSize = 5
)

// MovingAverageSeries is a computed series.
type MovingAverageSeries struct {
	Name  string
	Style Style
	YAxis YAxisType

	WindowSize  int
	InnerSeries ValueProvider

	valueBuffer *RingBuffer
}

// GetName returns the name of the time series.
func (mas MovingAverageSeries) GetName() string {
	return mas.Name
}

// GetStyle returns the line style.
func (mas MovingAverageSeries) GetStyle() Style {
	return mas.Style
}

// GetYAxis returns which YAxis the series draws on.
func (mas MovingAverageSeries) GetYAxis() YAxisType {
	return mas.YAxis
}

// Len returns the number of elements in the series.
func (mas *MovingAverageSeries) Len() int {
	return mas.InnerSeries.Len()
}

// GetValue gets a value at a given index.
func (mas *MovingAverageSeries) GetValue(index int) (x float64, y float64) {
	if mas.valueBuffer == nil {
		mas.valueBuffer = NewRingBufferWithCapacity(mas.GetWindowSize())
	}
	if mas.valueBuffer.Len() >= mas.GetWindowSize() {
		mas.valueBuffer.Dequeue()
	}
	px, py := mas.InnerSeries.GetValue(index)
	mas.valueBuffer.Enqueue(py)
	x = px
	y = mas.getAverage()
	return
}

// GetWindowSize returns the window size.
func (mas MovingAverageSeries) GetWindowSize(defaults ...int) int {
	if mas.WindowSize == 0 {
		if len(defaults) > 0 {
			return defaults[0]
		}
		return DefaultMovingAverageWindowSize
	}
	return mas.WindowSize
}

func (mas MovingAverageSeries) getAverage() float64 {
	var accum float64
	mas.valueBuffer.Each(func(v interface{}) {
		if typed, isTyped := v.(float64); isTyped {
			accum += typed
		}
	})
	return accum / float64(mas.valueBuffer.Len())
}

// Render renders the series.
func (mas *MovingAverageSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) {
	style := mas.Style.WithDefaultsFrom(defaults)
	DrawLineSeries(r, canvasBox, xrange, yrange, style, mas)
}
<commit_msg>adding a `GetLastValue()` function to MovingAverageSeries.<commit_after>package chart

const (
	// DefaultMovingAverageWindowSize is the default number of values to average.
	DefaultMovingAverageWindowSize = 5
)

// MovingAverageSeries is a computed series.
type MovingAverageSeries struct {
	Name  string
	Style Style
	YAxis YAxisType

	WindowSize  int
	InnerSeries ValueProvider

	valueBuffer *RingBuffer
}

// GetName returns the name of the time series.
func (mas MovingAverageSeries) GetName() string {
	return mas.Name
}

// GetStyle returns the line style.
func (mas MovingAverageSeries) GetStyle() Style {
	return mas.Style
}

// GetYAxis returns which YAxis the series draws on.
func (mas MovingAverageSeries) GetYAxis() YAxisType {
	return mas.YAxis
}

// Len returns the number of elements in the series.
func (mas *MovingAverageSeries) Len() int {
	return mas.InnerSeries.Len()
}

// GetValue gets a value at a given index.
func (mas *MovingAverageSeries) GetValue(index int) (x float64, y float64) {
	if mas.InnerSeries == nil {
		return
	}
	if mas.valueBuffer == nil {
		mas.valueBuffer = NewRingBufferWithCapacity(mas.GetWindowSize())
	}
	if mas.valueBuffer.Len() >= mas.GetWindowSize() {
		mas.valueBuffer.Dequeue()
	}
	px, py := mas.InnerSeries.GetValue(index)
	mas.valueBuffer.Enqueue(py)
	x = px
	y = mas.getAverage(mas.valueBuffer)
	return
}

// GetLastValue computes the last moving average value but walking back window size samples,
// and recomputing the last moving average chunk.
func (mas MovingAverageSeries) GetLastValue() (x float64, y float64) {
	if mas.InnerSeries == nil {
		return
	}
	windowSize := mas.GetWindowSize()
	seriesLength := mas.InnerSeries.Len()
	startAt := seriesLength - (windowSize + 1)
	if (seriesLength - startAt) < 0 {
		startAt = 0
	}
	vb := NewRingBufferWithCapacity(windowSize)
	for index := startAt; index < seriesLength; index++ {
		xn, yn := mas.InnerSeries.GetValue(index)
		vb.Enqueue(yn)
		x = xn
	}
	y = mas.getAverage(vb)
	return
}

// GetWindowSize returns the window size.
func (mas MovingAverageSeries) GetWindowSize(defaults ...int) int {
	if mas.WindowSize == 0 {
		if len(defaults) > 0 {
			return defaults[0]
		}
		return DefaultMovingAverageWindowSize
	}
	return mas.WindowSize
}

func (mas MovingAverageSeries) getAverage(valueBuffer *RingBuffer) float64 {
	var accum float64
	valueBuffer.Each(func(v interface{}) {
		if typed, isTyped := v.(float64); isTyped {
			accum += typed
		}
	})
	return accum / float64(mas.valueBuffer.Len())
}

// Render renders the series.
func (mas *MovingAverageSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) {
	style := mas.Style.WithDefaultsFrom(defaults)
	DrawLineSeries(r, canvasBox, xrange, yrange, style, mas)
}
<|endoftext|>


<commit_before>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package client

import (
	"errors"

	"golang.org/x/net/context"

	"github.com/keybase/cli"
	"github.com/keybase/client/go/libcmdline"
	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/go-framed-msgpack-rpc/rpc"
)

type CmdEncrypt struct {
	libkb.Contextified
	filter         UnixFilter
	recipients     []string
	noSelfEncrypt  bool
	binary         bool
	hideRecipients bool
	hideSelf       bool
	signcrypt      bool
}

func NewCmdEncrypt(cl *libcmdline.CommandLine, g *libkb.GlobalContext) cli.Command {
	return cli.Command{
		Name:         "encrypt",
		ArgumentHelp: "<usernames...>",
		Usage:        "Encrypt messages or files for keybase users",
		Action: func(c *cli.Context) {
			cl.ChooseCommand(&CmdEncrypt{
				Contextified: libkb.NewContextified(g),
			}, "encrypt", c)
		},
		Flags: []cli.Flag{
			cli.BoolFlag{
				Name:  "b, binary",
				Usage: "Output in binary (rather than ASCII/armored).",
			},
			cli.StringFlag{
				Name:  "i, infile",
				Usage: "Specify an input file.",
			},
			cli.StringFlag{
				Name:  "m, message",
				Usage: "Provide the message on the command line.",
			},
			cli.StringFlag{
				Name:  "o, outfile",
				Usage: "Specify an outfile (stdout by default).",
			},
			cli.BoolFlag{
				Name:  "hide-recipients",
				Usage: "Don't include recipients in metadata",
			},
			cli.BoolFlag{
				Name: "anonymous",
				Usage: "Don't include sender or recipients in metadata. " +
					"Implies --hide-recipients.",
			},
			cli.BoolFlag{
				Name:  "no-self",
				Usage: "Don't encrypt for yourself",
			},
			// A temporary flag. Soon this will be the default.
			cli.BoolFlag{
				Name:  "signcrypt",
				Usage: "TEMPORARY",
			},
		},
	}
}

func (c *CmdEncrypt) Run() error {
	cli, err := GetSaltpackClient(c.G())
	if err != nil {
		return err
	}

	protocols := []rpc.Protocol{
		NewStreamUIProtocol(c.G()),
		NewSecretUIProtocol(c.G()),
		NewIdentifyUIProtocol(c.G()),
	}
	if err := RegisterProtocolsWithContext(protocols, c.G()); err != nil {
		return err
	}

	snk, src, err := c.filter.ClientFilterOpen(c.G())
	if err != nil {
		return err
	}

	opts := keybase1.SaltpackEncryptOptions{
		Recipients:     c.recipients,
		NoSelfEncrypt:  c.noSelfEncrypt,
		Binary:         c.binary,
		HideRecipients: c.hideRecipients,
		HideSelf:       c.hideSelf,
		Signcrypt:      c.signcrypt,
	}
	arg := keybase1.SaltpackEncryptArg{Source: src, Sink: snk, Opts: opts}
	err = cli.SaltpackEncrypt(context.TODO(), arg)
	cerr := c.filter.Close(err)
	return libkb.PickFirstError(err, cerr)
}

func (c *CmdEncrypt) GetUsage() libkb.Usage {
	return libkb.Usage{
		API:       true,
		Config:    true,
		KbKeyring: true,
	}
}

func (c *CmdEncrypt) ParseArgv(ctx *cli.Context) error {
	if len(ctx.Args()) == 0 {
		return errors.New("Encrypt needs at least one recipient")
	}
	c.recipients = ctx.Args()

	msg := ctx.String("message")
	outfile := ctx.String("outfile")
	infile := ctx.String("infile")
	c.noSelfEncrypt = ctx.Bool("no-self")
	c.binary = ctx.Bool("binary")
	// --anonymous means hide both self and recipients.
	c.hideSelf = ctx.Bool("anonymous")
	c.hideRecipients = ctx.Bool("hide-recipients") || ctx.Bool("anonymous")
	c.signcrypt = ctx.Bool("signcrypt")
	if err := c.filter.FilterInit(msg, infile, outfile); err != nil {
		return err
	}

	return nil
}
<commit_msg>gate the --signcrypt flag to dev mode<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package client

import (
	"errors"

	"golang.org/x/net/context"

	"github.com/keybase/cli"
	"github.com/keybase/client/go/libcmdline"
	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/go-framed-msgpack-rpc/rpc"
)

type CmdEncrypt struct {
	libkb.Contextified
	filter         UnixFilter
	recipients     []string
	noSelfEncrypt  bool
	binary         bool
	hideRecipients bool
	hideSelf       bool
	signcrypt      bool
}

func NewCmdEncrypt(cl *libcmdline.CommandLine, g *libkb.GlobalContext) cli.Command {
	flags := []cli.Flag{
		cli.BoolFlag{
			Name:  "b, binary",
			Usage: "Output in binary (rather than ASCII/armored).",
		},
		cli.StringFlag{
			Name:  "i, infile",
			Usage: "Specify an input file.",
		},
		cli.StringFlag{
			Name:  "m, message",
			Usage: "Provide the message on the command line.",
		},
		cli.StringFlag{
			Name:  "o, outfile",
			Usage: "Specify an outfile (stdout by default).",
		},
		cli.BoolFlag{
			Name:  "hide-recipients",
			Usage: "Don't include recipients in metadata",
		},
		cli.BoolFlag{
			Name: "anonymous",
			Usage: "Don't include sender or recipients in metadata. " +
				"Implies --hide-recipients.",
		},
		cli.BoolFlag{
			Name:  "no-self",
			Usage: "Don't encrypt for yourself",
		},
	}

	// A temporary flag. Soon this will be the default. (Note that the regular
	// RunMode() config has not yet been parsed from the command line, so we
	// use DefaultRunMode instead.)
	if libkb.DefaultRunMode == libkb.DevelRunMode {
		flags = append(flags, cli.BoolFlag{
			Name:  "signcrypt",
			Usage: "TEMPORARY",
		})
	}

	return cli.Command{
		Name:         "encrypt",
		ArgumentHelp: "<usernames...>",
		Usage:        "Encrypt messages or files for keybase users",
		Action: func(c *cli.Context) {
			cl.ChooseCommand(&CmdEncrypt{
				Contextified: libkb.NewContextified(g),
			}, "encrypt", c)
		},
		Flags: flags,
	}
}

func (c *CmdEncrypt) Run() error {
	cli, err := GetSaltpackClient(c.G())
	if err != nil {
		return err
	}

	protocols := []rpc.Protocol{
		NewStreamUIProtocol(c.G()),
		NewSecretUIProtocol(c.G()),
		NewIdentifyUIProtocol(c.G()),
	}
	if err := RegisterProtocolsWithContext(protocols, c.G()); err != nil {
		return err
	}

	snk, src, err := c.filter.ClientFilterOpen(c.G())
	if err != nil {
		return err
	}

	opts := keybase1.SaltpackEncryptOptions{
		Recipients:     c.recipients,
		NoSelfEncrypt:  c.noSelfEncrypt,
		Binary:         c.binary,
		HideRecipients: c.hideRecipients,
		HideSelf:       c.hideSelf,
		Signcrypt:      c.signcrypt,
	}
	arg := keybase1.SaltpackEncryptArg{Source: src, Sink: snk, Opts: opts}
	err = cli.SaltpackEncrypt(context.TODO(), arg)
	cerr := c.filter.Close(err)
	return libkb.PickFirstError(err, cerr)
}

func (c *CmdEncrypt) GetUsage() libkb.Usage {
	return libkb.Usage{
		API:       true,
		Config:    true,
		KbKeyring: true,
	}
}

func (c *CmdEncrypt) ParseArgv(ctx *cli.Context) error {
	if len(ctx.Args()) == 0 {
		return errors.New("Encrypt needs at least one recipient")
	}
	c.recipients = ctx.Args()

	msg := ctx.String("message")
	outfile := ctx.String("outfile")
	infile := ctx.String("infile")
	c.noSelfEncrypt = ctx.Bool("no-self")
	c.binary = ctx.Bool("binary")
	// --anonymous means hide both self and recipients.
	c.hideSelf = ctx.Bool("anonymous")
	c.hideRecipients = ctx.Bool("hide-recipients") || ctx.Bool("anonymous")
	c.signcrypt = ctx.Bool("signcrypt")
	if err := c.filter.FilterInit(msg, infile, outfile); err != nil {
		return err
	}

	return nil
}
<|endoftext|>