<commit_before>package main

import (
	"flag"
	"fmt"
	"net/http"
	_ "net/http/pprof"
	"os"
	"path/filepath"
	"runtime"
	"sort"
	"time"

	"github.com/labstack/echo"

	"github.com/qiniu/log"

	"github.com/qiniu/logkit/cli"
	config "github.com/qiniu/logkit/conf"
	_ "github.com/qiniu/logkit/metric/builtin"
	"github.com/qiniu/logkit/mgr"
	"github.com/qiniu/logkit/times"
	_ "github.com/qiniu/logkit/transforms/builtin"
	. "github.com/qiniu/logkit/utils/models"
	utilsos "github.com/qiniu/logkit/utils/os"
)

//Config of logkit
type Config struct {
	MaxProcs          int      `json:"max_procs"`
	DebugLevel        int      `json:"debug_level"`
	ProfileHost       string   `json:"profile_host"`
	ConfsPath         []string `json:"confs_path"`
	LogPath           string   `json:"log"`
	CleanSelfLog      bool     `json:"clean_self_log"`
	CleanSelfDir      string   `json:"clean_self_dir"`
	CleanSelfPattern  string   `json:"clean_self_pattern"`
	CleanSelfDuration string   `json:"clean_self_duration"`
	CleanSelfLogCnt   int      `json:"clean_self_cnt"`
	TimeLayouts       []string `json:"timeformat_layouts"`
	StaticRootPath    string   `json:"static_root_path"`
	mgr.ManagerConfig
}

var conf Config

const (
	NextVersion        = "v1.5.5"
	defaultReserveCnt  = 5
	defaultLogDir      = "./"
	defaultLogPattern  = "*.log-*"
	defaultLogDuration = 10 * time.Minute
	defaultRotateSize  = 100 * 1024 * 1024
)

const usage = `logkit, Very easy-to-use server agent for collecting & sending logs & metrics.

Usage:

  logkit [commands|flags]

The commands & flags are:

  -v                 print the version to stdout.
  -h                 print logkit usage info to stdout.
  -upgrade           check and upgrade version.

  -f <file>          configuration file to load

Examples:

  # start logkit
  logkit -f logkit.conf

  # check version
  logkit -v

  # checking and upgrade version
  logkit -upgrade
`

var (
	fversion = flag.Bool("v", false, "print the version to stdout")
	upgrade  = flag.Bool("upgrade", false, "check and upgrade version")
	confName = flag.String("f", "logkit.conf", "configuration file to load")
)

func getValidPath(confPaths []string) (paths []string) {
	paths = make([]string, 0)
	exits := make(map[string]bool)
	for _, v := range confPaths {
		rp, err := filepath.Abs(v)
		if err != nil {
			log.Errorf("Get real path of ConfsPath %v error %v, ignore it", v, rp)
			continue
		}
		if _, ok := exits[rp]; ok {
			log.Errorf("ConfsPath %v duplicated, ignore", rp)
			continue
		}
		exits[rp] = true
		paths = append(paths, rp)
	}
	return
}

type MatchFile struct {
	Name    string
	ModTime time.Time
}

type MatchFiles []MatchFile

func (f MatchFiles) Len() int           { return len(f) }
func (f MatchFiles) Swap(i, j int)      { f[i], f[j] = f[j], f[i] }
func (f MatchFiles) Less(i, j int) bool { return f[i].ModTime.Before(f[j].ModTime) }

func cleanLogkitLog(dir, pattern string, reserveCnt int) {
	var err error
	path := filepath.Join(dir, pattern)
	matches, err := filepath.Glob(path)
	if err != nil {
		log.Errorf("filepath.Glob path %v error %v", path, err)
		return
	}
	var files MatchFiles
	for _, name := range matches {
		info, err := os.Stat(name)
		if err != nil {
			log.Errorf("os.Stat name %v error %v", name, err)
			continue
		}
		files = append(files, MatchFile{
			Name:    name,
			ModTime: info.ModTime(),
		})
	}
	if len(files) <= reserveCnt {
		return
	}
	sort.Sort(files)
	for _, f := range files[0 : len(files)-reserveCnt] {
		err := os.Remove(f.Name)
		if err != nil {
			log.Errorf("Remove %s failed , error: %v", f, err)
			continue
		}
	}
	return
}

func loopCleanLogkitLog(dir, pattern string, reserveCnt int, duration string, exitchan chan struct{}) {
	if len(dir) <= 0 {
		dir = defaultLogDir
	}
	if len(pattern) <= 0 {
		pattern = defaultLogPattern
	}
	if reserveCnt <= 0 {
		reserveCnt = defaultReserveCnt
	}
	var (
		dur time.Duration
		err error
	)
	if duration != "" {
		dur, err = time.ParseDuration(duration)
		if err != nil {
			log.Warnf("clean self duration parse failed: %v, Valid time units are 'ns', 'us' (or 'µs'), 'ms', 's', 'm', 'h'. Use default duration: 10m", err)
			dur = defaultLogDuration
		}
	} else {
		dur = defaultLogDuration
	}
	ticker := time.NewTicker(dur)
	defer ticker.Stop()
	for {
		select {
		case <-exitchan:
			return
		case <-ticker.C:
			cleanLogkitLog(dir, pattern, reserveCnt)
		}
	}
}

func rotateLog(path string) (file *os.File, err error) {
	newfile := path + "-" + time.Now().Format("0102030405")
	file, err = os.OpenFile(newfile, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666)
	if err != nil {
		err = fmt.Errorf("rotateLog open newfile %v err %v", newfile, err)
		return
	}
	log.SetOutput(file)
	return
}

func loopRotateLogs(path string, rotateSize int64, dur time.Duration, exitchan chan struct{}) {
	file, err := rotateLog(path)
	if err != nil {
		log.Fatal(err)
	}
	ticker := time.NewTicker(dur)
	defer ticker.Stop()
	for {
		select {
		case <-exitchan:
			return
		case <-ticker.C:
			info, err := file.Stat()
			if err != nil {
				log.Warnf("stat log error %v", err)
			} else {
				if info.Size() >= rotateSize {
					newfile, err := rotateLog(path)
					if err != nil {
						log.Errorf("rotate log %v error %v, use old log to write logkit log", path, err)
					} else {
						file.Close()
						file = newfile
					}
				}
			}

		}
	}
}

func usageExit(rc int) {
	fmt.Println(usage)
	os.Exit(rc)
}

//！！！注意： 自动生成 grok pattern代码，下述注释请勿删除！！！
//go:generate go run tools/generators/grok_pattern_generator.go
func main() {
	flag.Usage = func() { usageExit(0) }
	flag.Parse()
	switch {
	case *fversion:
		fmt.Println("logkit version: ", NextVersion)
		osInfo := utilsos.GetOSInfo()
		fmt.Println("Hostname: ", osInfo.Hostname)
		fmt.Println("Core: ", osInfo.Core)
		fmt.Println("OS: ", osInfo.OS)
		fmt.Println("Platform: ", osInfo.Platform)
		return
	case *upgrade:
		cli.CheckAndUpgrade(NextVersion)
		return
	}

	if err := config.LoadEx(&conf, *confName); err != nil {
		log.Fatal("config.Load failed:", err)
	}
	if conf.TimeLayouts != nil {
		times.AddLayout(conf.TimeLayouts)
	}
	if conf.MaxProcs <= 0 {
		conf.MaxProcs = NumCPU
	}
	MaxProcs = conf.MaxProcs
	runtime.GOMAXPROCS(conf.MaxProcs)
	log.SetOutputLevel(conf.DebugLevel)

	var (
		stopRotate         = make(chan struct{}, 0)
		logdir, logpattern string
		err                error
	)
	defer close(stopRotate)
	if conf.LogPath != "" {
		logdir, logpattern, err = LogDirAndPattern(conf.LogPath)
		if err != nil {
			log.Fatal(err)
		}
		go loopRotateLogs(filepath.Join(logdir, logpattern), defaultRotateSize, 10*time.Second, stopRotate)
		conf.CleanSelfPattern = logpattern + "-*"
		conf.CleanSelfDir = logdir
		conf.ManagerConfig.CollectLogPath = filepath.Join(logdir, logpattern+"-*")
	}

	log.Infof("Welcome to use Logkit, Version: %v \n\nConfig: %#v", NextVersion, conf)
	m, err := mgr.NewManager(conf.ManagerConfig)
	if err != nil {
		log.Fatalf("NewManager: %v", err)
	}
	m.Version = NextVersion

	if m.CollectLogRunner != nil {
		go m.CollectLogRunner.Run()
		time.Sleep(time.Second) // 等待1秒让收集器启动
	}

	paths := getValidPath(conf.ConfsPath)
	if len(paths) <= 0 {
		log.Warnf("Cannot read or create any ConfsPath %v", conf.ConfsPath)
	}
	if err = m.Watch(paths); err != nil {
		log.Fatalf("watch path error %v", err)
	}
	m.RestoreWebDir()

	stopClean := make(chan struct{}, 0)
	defer close(stopClean)
	if conf.CleanSelfLog {
		if conf.CleanSelfDir == "" && logdir != "" {
			conf.CleanSelfDir = logdir
		}
		if conf.CleanSelfPattern == "" && logpattern != "" {
			conf.CleanSelfPattern = logpattern + "-*"
		}
		go loopCleanLogkitLog(conf.CleanSelfDir, conf.CleanSelfPattern, conf.CleanSelfLogCnt, conf.CleanSelfDuration, stopClean)
	}
	if len(conf.BindHost) > 0 {
		m.BindHost = conf.BindHost
	}
	e := echo.New()
	e.Static("/", conf.StaticRootPath)

	// start rest service
	rs := mgr.NewRestService(m, e)
	if conf.ProfileHost != "" {
		log.Infof("go profile_host was open at %v", conf.ProfileHost)
		go func() {
			log.Fatal(http.ListenAndServe(conf.ProfileHost, nil))
		}()
	}
	if err = rs.Register(); err != nil {
		log.Fatalf("register master error %v", err)
	}
	utilsos.WaitForInterrupt(func() {
		rs.Stop()
		if conf.CleanSelfLog {
			stopClean <- struct{}{}
		}
		m.Stop()
	})
}
<commit_msg>change version to 1.5.6<commit_after>package main

import (
	"flag"
	"fmt"
	"net/http"
	_ "net/http/pprof"
	"os"
	"path/filepath"
	"runtime"
	"sort"
	"time"

	"github.com/labstack/echo"

	"github.com/qiniu/log"

	"github.com/qiniu/logkit/cli"
	config "github.com/qiniu/logkit/conf"
	_ "github.com/qiniu/logkit/metric/builtin"
	"github.com/qiniu/logkit/mgr"
	"github.com/qiniu/logkit/times"
	_ "github.com/qiniu/logkit/transforms/builtin"
	. "github.com/qiniu/logkit/utils/models"
	utilsos "github.com/qiniu/logkit/utils/os"
)

//Config of logkit
type Config struct {
	MaxProcs          int      `json:"max_procs"`
	DebugLevel        int      `json:"debug_level"`
	ProfileHost       string   `json:"profile_host"`
	ConfsPath         []string `json:"confs_path"`
	LogPath           string   `json:"log"`
	CleanSelfLog      bool     `json:"clean_self_log"`
	CleanSelfDir      string   `json:"clean_self_dir"`
	CleanSelfPattern  string   `json:"clean_self_pattern"`
	CleanSelfDuration string   `json:"clean_self_duration"`
	CleanSelfLogCnt   int      `json:"clean_self_cnt"`
	TimeLayouts       []string `json:"timeformat_layouts"`
	StaticRootPath    string   `json:"static_root_path"`
	mgr.ManagerConfig
}

var conf Config

const (
	NextVersion        = "v1.5.6"
	defaultReserveCnt  = 5
	defaultLogDir      = "./"
	defaultLogPattern  = "*.log-*"
	defaultLogDuration = 10 * time.Minute
	defaultRotateSize  = 100 * 1024 * 1024
)

const usage = `logkit, Very easy-to-use server agent for collecting & sending logs & metrics.

Usage:

  logkit [commands|flags]

The commands & flags are:

  -v                 print the version to stdout.
  -h                 print logkit usage info to stdout.
  -upgrade           check and upgrade version.

  -f <file>          configuration file to load

Examples:

  # start logkit
  logkit -f logkit.conf

  # check version
  logkit -v

  # checking and upgrade version
  logkit -upgrade
`

var (
	fversion = flag.Bool("v", false, "print the version to stdout")
	upgrade  = flag.Bool("upgrade", false, "check and upgrade version")
	confName = flag.String("f", "logkit.conf", "configuration file to load")
)

func getValidPath(confPaths []string) (paths []string) {
	paths = make([]string, 0)
	exits := make(map[string]bool)
	for _, v := range confPaths {
		rp, err := filepath.Abs(v)
		if err != nil {
			log.Errorf("Get real path of ConfsPath %v error %v, ignore it", v, rp)
			continue
		}
		if _, ok := exits[rp]; ok {
			log.Errorf("ConfsPath %v duplicated, ignore", rp)
			continue
		}
		exits[rp] = true
		paths = append(paths, rp)
	}
	return
}

type MatchFile struct {
	Name    string
	ModTime time.Time
}

type MatchFiles []MatchFile

func (f MatchFiles) Len() int           { return len(f) }
func (f MatchFiles) Swap(i, j int)      { f[i], f[j] = f[j], f[i] }
func (f MatchFiles) Less(i, j int) bool { return f[i].ModTime.Before(f[j].ModTime) }

func cleanLogkitLog(dir, pattern string, reserveCnt int) {
	var err error
	path := filepath.Join(dir, pattern)
	matches, err := filepath.Glob(path)
	if err != nil {
		log.Errorf("filepath.Glob path %v error %v", path, err)
		return
	}
	var files MatchFiles
	for _, name := range matches {
		info, err := os.Stat(name)
		if err != nil {
			log.Errorf("os.Stat name %v error %v", name, err)
			continue
		}
		files = append(files, MatchFile{
			Name:    name,
			ModTime: info.ModTime(),
		})
	}
	if len(files) <= reserveCnt {
		return
	}
	sort.Sort(files)
	for _, f := range files[0 : len(files)-reserveCnt] {
		err := os.Remove(f.Name)
		if err != nil {
			log.Errorf("Remove %s failed , error: %v", f, err)
			continue
		}
	}
	return
}

func loopCleanLogkitLog(dir, pattern string, reserveCnt int, duration string, exitchan chan struct{}) {
	if len(dir) <= 0 {
		dir = defaultLogDir
	}
	if len(pattern) <= 0 {
		pattern = defaultLogPattern
	}
	if reserveCnt <= 0 {
		reserveCnt = defaultReserveCnt
	}
	var (
		dur time.Duration
		err error
	)
	if duration != "" {
		dur, err = time.ParseDuration(duration)
		if err != nil {
			log.Warnf("clean self duration parse failed: %v, Valid time units are 'ns', 'us' (or 'µs'), 'ms', 's', 'm', 'h'. Use default duration: 10m", err)
			dur = defaultLogDuration
		}
	} else {
		dur = defaultLogDuration
	}
	ticker := time.NewTicker(dur)
	defer ticker.Stop()
	for {
		select {
		case <-exitchan:
			return
		case <-ticker.C:
			cleanLogkitLog(dir, pattern, reserveCnt)
		}
	}
}

func rotateLog(path string) (file *os.File, err error) {
	newfile := path + "-" + time.Now().Format("0102030405")
	file, err = os.OpenFile(newfile, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666)
	if err != nil {
		err = fmt.Errorf("rotateLog open newfile %v err %v", newfile, err)
		return
	}
	log.SetOutput(file)
	return
}

func loopRotateLogs(path string, rotateSize int64, dur time.Duration, exitchan chan struct{}) {
	file, err := rotateLog(path)
	if err != nil {
		log.Fatal(err)
	}
	ticker := time.NewTicker(dur)
	defer ticker.Stop()
	for {
		select {
		case <-exitchan:
			return
		case <-ticker.C:
			info, err := file.Stat()
			if err != nil {
				log.Warnf("stat log error %v", err)
			} else {
				if info.Size() >= rotateSize {
					newfile, err := rotateLog(path)
					if err != nil {
						log.Errorf("rotate log %v error %v, use old log to write logkit log", path, err)
					} else {
						file.Close()
						file = newfile
					}
				}
			}

		}
	}
}

func usageExit(rc int) {
	fmt.Println(usage)
	os.Exit(rc)
}

//！！！注意： 自动生成 grok pattern代码，下述注释请勿删除！！！
//go:generate go run tools/generators/grok_pattern_generator.go
func main() {
	flag.Usage = func() { usageExit(0) }
	flag.Parse()
	switch {
	case *fversion:
		fmt.Println("logkit version: ", NextVersion)
		osInfo := utilsos.GetOSInfo()
		fmt.Println("Hostname: ", osInfo.Hostname)
		fmt.Println("Core: ", osInfo.Core)
		fmt.Println("OS: ", osInfo.OS)
		fmt.Println("Platform: ", osInfo.Platform)
		return
	case *upgrade:
		cli.CheckAndUpgrade(NextVersion)
		return
	}

	if err := config.LoadEx(&conf, *confName); err != nil {
		log.Fatal("config.Load failed:", err)
	}
	if conf.TimeLayouts != nil {
		times.AddLayout(conf.TimeLayouts)
	}
	if conf.MaxProcs <= 0 {
		conf.MaxProcs = NumCPU
	}
	MaxProcs = conf.MaxProcs
	runtime.GOMAXPROCS(conf.MaxProcs)
	log.SetOutputLevel(conf.DebugLevel)

	var (
		stopRotate         = make(chan struct{}, 0)
		logdir, logpattern string
		err                error
	)
	defer close(stopRotate)
	if conf.LogPath != "" {
		logdir, logpattern, err = LogDirAndPattern(conf.LogPath)
		if err != nil {
			log.Fatal(err)
		}
		go loopRotateLogs(filepath.Join(logdir, logpattern), defaultRotateSize, 10*time.Second, stopRotate)
		conf.CleanSelfPattern = logpattern + "-*"
		conf.CleanSelfDir = logdir
		conf.ManagerConfig.CollectLogPath = filepath.Join(logdir, logpattern+"-*")
	}

	log.Infof("Welcome to use Logkit, Version: %v \n\nConfig: %#v", NextVersion, conf)
	m, err := mgr.NewManager(conf.ManagerConfig)
	if err != nil {
		log.Fatalf("NewManager: %v", err)
	}
	m.Version = NextVersion

	if m.CollectLogRunner != nil {
		go m.CollectLogRunner.Run()
		time.Sleep(time.Second) // 等待1秒让收集器启动
	}

	paths := getValidPath(conf.ConfsPath)
	if len(paths) <= 0 {
		log.Warnf("Cannot read or create any ConfsPath %v", conf.ConfsPath)
	}
	if err = m.Watch(paths); err != nil {
		log.Fatalf("watch path error %v", err)
	}
	m.RestoreWebDir()

	stopClean := make(chan struct{}, 0)
	defer close(stopClean)
	if conf.CleanSelfLog {
		if conf.CleanSelfDir == "" && logdir != "" {
			conf.CleanSelfDir = logdir
		}
		if conf.CleanSelfPattern == "" && logpattern != "" {
			conf.CleanSelfPattern = logpattern + "-*"
		}
		go loopCleanLogkitLog(conf.CleanSelfDir, conf.CleanSelfPattern, conf.CleanSelfLogCnt, conf.CleanSelfDuration, stopClean)
	}
	if len(conf.BindHost) > 0 {
		m.BindHost = conf.BindHost
	}
	e := echo.New()
	e.Static("/", conf.StaticRootPath)

	// start rest service
	rs := mgr.NewRestService(m, e)
	if conf.ProfileHost != "" {
		log.Infof("go profile_host was open at %v", conf.ProfileHost)
		go func() {
			log.Fatal(http.ListenAndServe(conf.ProfileHost, nil))
		}()
	}
	if err = rs.Register(); err != nil {
		log.Fatalf("register master error %v", err)
	}
	utilsos.WaitForInterrupt(func() {
		rs.Stop()
		if conf.CleanSelfLog {
			stopClean <- struct{}{}
		}
		m.Stop()
	})
}
<|endoftext|>


<commit_before>package atlas

import (
	"errors"
	"github.com/bndr/gopencils"
	"log"
	"fmt"
)

var (
	allTypes = []string{
		"dns",
		"http",
		"ntp",
		"ping",
		"sslcert",
		"traceroute",
		"wifi",
	}
)

// ErrInvalidMeasurementType is a new error
var ErrInvalidMeasurementType = errors.New("invalid measurement type")

// -- private

// checkType verify that the type is valid
func checkType(d Definition) (valid bool) {
	valid = false
	for _, t := range allTypes {
		if d.Type == t {
			valid = true
			break
		}
	}
	return
}

// checkTypeAs is a shortcut
func checkTypeAs(d Definition, t string) (valid bool) {
	valid = true
	if checkType(d) && d.Type != t {
		valid = false
	}
	return
}

// checkAllTypesAs is a generalization of checkTypeAs
func checkAllTypesAs(dl []Definition, t string) (valid bool) {
	valid = true
	for _, d := range dl {
		if d.Type != t {
			valid = false
			break
		}
	}
	return
}

// measurementList is our main answer
type measurementList struct {
	Count    int
	Next     string
	Previous string
	Results  []Measurement
}

// fetch the given resource
func fetchOneMeasurementPage(api *gopencils.Resource, opts map[string]string) (raw *measurementList, err error) {
	r, err := api.Res("measurements", &raw).Get(opts)
	if err != nil {
		log.Printf("err: %v", err)
		err = fmt.Errorf("%v - r:%v\n", err, r)
	}
	//log.Printf(">> rawlist=%+v r=%+v Next=|%s|", rawlist, r, rawlist.Next)
	return
}

// -- public

// GetMeasurement gets info for a single one
func GetMeasurement(id int) (m *Measurement, err error) {
	key, ok := HasAPIKey()
	api := gopencils.Api(apiEndpoint, nil)

	// Add at least one option, the APIkey if present
	var opts map[string]string

	if ok {
		opts["key"] = key
	}

	r, err := api.Res("measurements").Id(id, &m).Get(opts)
	if err != nil {
		err = fmt.Errorf("%v - r:%#v\n", err, r.Raw)
		return
	}
	return
}

// GetMeasurements gets info for a set
func GetMeasurements(opts map[string]string) (m []Measurement, err error) {
	key, ok := HasAPIKey()
	api := gopencils.Api(apiEndpoint, nil)

	// Add at least one option, the APIkey if present
	if ok {
		opts["key"] = key
	}

	rawlist, err := fetchOneMeasurementPage(api, opts)

	// Empty answer
	if rawlist.Count == 0 {
		return nil, fmt.Errorf("empty measurement list")
	}

	var res []Measurement

	res = append(res, rawlist.Results...)
	if rawlist.Next != "" {
		// We have pagination
		for pn := getPageNum(rawlist.Next); rawlist.Next != ""; pn = getPageNum(rawlist.Next) {
			opts["page"] = pn

			rawlist, err = fetchOneMeasurementPage(api, opts)
			if err != nil {
				return
			}

			res = append(res, rawlist.Results...)
		}
	}
	m = res
	return
}

// DNS creates a measurement
func DNS(d Definition) (m *Measurement, err error) {
	if checkTypeAs(d, "dns") {
		err = ErrInvalidMeasurementType
		return
	}
	return
}

// HTTP creates a measurement
func HTTP(d Definition) (m *Measurement, err error) {
	if checkTypeAs(d, "http") {
		err = ErrInvalidMeasurementType
		return
	}
	return
}

// NTP creates a measurement
func NTP(d Definition) (m *Measurement, err error) {
	if checkTypeAs(d, "ntp") {
		err = ErrInvalidMeasurementType
		return
	}
	return
}

// Ping creates a measurement
func Ping(d MeasurementRequest) (m *Measurement, err error) {
	if checkTypeAs(d.Definitions[0], "ping") {
		err = ErrInvalidMeasurementType
		return
	}
	return
}

// SSLCert creates a measurement
func SSLCert(d Definition) (m *Measurement, err error) {
	if checkTypeAs(d, "sslcert") {
		err = ErrInvalidMeasurementType
		return
	}
	return
}

// Traceroute creates a measurement
func Traceroute(d Definition) (m *Measurement, err error) {
	if checkTypeAs(d, "traceroute") {
		err = ErrInvalidMeasurementType
		return
	}
	return
}

// Measurement-related methods

// Start is for starting a given measurement
func (m *Measurement) Start(id int) (err error) {
	return nil
}

// Stop is for stopping a given measurement
func (m *Measurement) Stop(id int) (err error) {
	return nil
}
<commit_msg>New error for invalid api_key.<commit_after>package atlas

import (
	"errors"
	"github.com/bndr/gopencils"
	"log"
	"fmt"
)

var (
	allTypes = []string{
		"dns",
		"http",
		"ntp",
		"ping",
		"sslcert",
		"traceroute",
		"wifi",
	}
)

// ErrInvalidMeasurementType is a new error
var ErrInvalidMeasurementType = errors.New("invalid measurement type")

var ErrInvalidAPIKey = errors.New("invalid API key")

// -- private

// checkType verify that the type is valid
func checkType(d Definition) (valid bool) {
	valid = false
	for _, t := range allTypes {
		if d.Type == t {
			valid = true
			break
		}
	}
	return
}

// checkTypeAs is a shortcut
func checkTypeAs(d Definition, t string) (valid bool) {
	valid = true
	if checkType(d) && d.Type != t {
		valid = false
	}
	return
}

// checkAllTypesAs is a generalization of checkTypeAs
func checkAllTypesAs(dl []Definition, t string) (valid bool) {
	valid = true
	for _, d := range dl {
		if d.Type != t {
			valid = false
			break
		}
	}
	return
}

// measurementList is our main answer
type measurementList struct {
	Count    int
	Next     string
	Previous string
	Results  []Measurement
}

// fetch the given resource
func fetchOneMeasurementPage(api *gopencils.Resource, opts map[string]string) (raw *measurementList, err error) {
	r, err := api.Res("measurements", &raw).Get(opts)
	if err != nil {
		log.Printf("err: %v", err)
		err = fmt.Errorf("%v - r:%v\n", err, r)
	}
	//log.Printf(">> rawlist=%+v r=%+v Next=|%s|", rawlist, r, rawlist.Next)
	return
}

// -- public

// GetMeasurement gets info for a single one
func GetMeasurement(id int) (m *Measurement, err error) {
	key, ok := HasAPIKey()
	api := gopencils.Api(apiEndpoint, nil)

	// Add at least one option, the APIkey if present
	var opts map[string]string

	if ok {
		opts["key"] = key
	}

	r, err := api.Res("measurements").Id(id, &m).Get(opts)
	if err != nil {
		err = fmt.Errorf("%v - r:%#v\n", err, r.Raw)
		return
	}
	return
}

// GetMeasurements gets info for a set
func GetMeasurements(opts map[string]string) (m []Measurement, err error) {
	key, ok := HasAPIKey()
	api := gopencils.Api(apiEndpoint, nil)

	// Add at least one option, the APIkey if present
	if ok {
		opts["key"] = key
	}

	rawlist, err := fetchOneMeasurementPage(api, opts)

	// Empty answer
	if rawlist.Count == 0 {
		return nil, fmt.Errorf("empty measurement list")
	}

	var res []Measurement

	res = append(res, rawlist.Results...)
	if rawlist.Next != "" {
		// We have pagination
		for pn := getPageNum(rawlist.Next); rawlist.Next != ""; pn = getPageNum(rawlist.Next) {
			opts["page"] = pn

			rawlist, err = fetchOneMeasurementPage(api, opts)
			if err != nil {
				return
			}

			res = append(res, rawlist.Results...)
		}
	}
	m = res
	return
}

// DNS creates a measurement
func DNS(d Definition) (m *Measurement, err error) {
	if checkTypeAs(d, "dns") {
		err = ErrInvalidMeasurementType
		return
	}
	return
}

// HTTP creates a measurement
func HTTP(d Definition) (m *Measurement, err error) {
	if checkTypeAs(d, "http") {
		err = ErrInvalidMeasurementType
		return
	}
	return
}

// NTP creates a measurement
func NTP(d Definition) (m *Measurement, err error) {
	if checkTypeAs(d, "ntp") {
		err = ErrInvalidMeasurementType
		return
	}
	return
}

// Ping creates a measurement
func Ping(d MeasurementRequest) (m *Measurement, err error) {
	if checkTypeAs(d.Definitions[0], "ping") {
		err = ErrInvalidMeasurementType
		return
	}
	return
}

// SSLCert creates a measurement
func SSLCert(d Definition) (m *Measurement, err error) {
	if checkTypeAs(d, "sslcert") {
		err = ErrInvalidMeasurementType
		return
	}
	return
}

// Traceroute creates a measurement
func Traceroute(d Definition) (m *Measurement, err error) {
	if checkTypeAs(d, "traceroute") {
		err = ErrInvalidMeasurementType
		return
	}
	return
}

// Measurement-related methods

// Start is for starting a given measurement
func (m *Measurement) Start(id int) (err error) {
	return nil
}

// Stop is for stopping a given measurement
func (m *Measurement) Stop(id int) (err error) {
	return nil
}
<|endoftext|>


<commit_before>// +build !jenkins

package main

import (
	"github.com/jmcvetta/neoism"
	"github.com/stretchr/testify/assert"
	"os"
	"testing"
)

func TestCreate(t *testing.T) {
	assert := assert.New(t)
	person := person{UUID: "123", Name: "Test", Identifiers: []identifier{identifier{fsAuthority, "FACTSET_ID"}}}

	url := os.Getenv("NEO4J_TEST_URL")
	if url == "" {
		url := "http://localhost:7474/db/data"
	}

	db, err := neoism.Connect(url)
	assert.NoError(err, "Failed to connect to Neo4j")
	peopleDriver = NewPeopleCypherDriver(db)

	assert.NoError(peopleDriver.Write(person), "Failed to write person")

	storedPerson, found, err := peopleDriver.Read("123")

	assert.NoError(err, "Error finding person")
	assert.True(found, "Didn't find person")
	assert.Equal(person, storedPerson, "people should be the same")
}
<commit_msg>Fix test build issue<commit_after>// +build !jenkins

package main

import (
	"github.com/jmcvetta/neoism"
	"github.com/stretchr/testify/assert"
	"os"
	"testing"
)

func TestCreate(t *testing.T) {
	assert := assert.New(t)
	person := person{UUID: "123", Name: "Test", Identifiers: []identifier{identifier{fsAuthority, "FACTSET_ID"}}}

	url := os.Getenv("NEO4J_TEST_URL")
	if url == "" {
		url = "http://localhost:7474/db/data"
	}

	db, err := neoism.Connect(url)
	assert.NoError(err, "Failed to connect to Neo4j")
	peopleDriver = NewPeopleCypherDriver(db)

	assert.NoError(peopleDriver.Write(person), "Failed to write person")

	storedPerson, found, err := peopleDriver.Read("123")

	assert.NoError(err, "Error finding person")
	assert.True(found, "Didn't find person")
	assert.Equal(person, storedPerson, "people should be the same")
}
<|endoftext|>


<commit_before>package main

import (
  "database/sql"
  "encoding/json"
  "errors"
  "fmt"
  "net/http"
  "net/url"
  "os"
  "strconv"
  _ "github.com/lib/pq"
  "github.com/rcrowley/go-tigertonic"
  "github.com/rkbodenner/meeple_mover/record"
  "github.com/rkbodenner/parallel_universe/collection"
  "github.com/rkbodenner/parallel_universe/game"
  "github.com/rkbodenner/parallel_universe/session"
)

var players = make([]*game.Player, 0)
var playerIndex = make(map[uint64]*game.Player)

func initPlayerData(db *sql.DB) {
  rows, err := db.Query("SELECT * FROM players")
  if nil != err {
    fmt.Print(err)
  }
  for rows.Next() {
    var name string
    var id int
    if err := rows.Scan(&id, &name); err != nil {
      fmt.Print(err)
    }
    players = append(players, &game.Player{id, name})
  }

  for _,player := range players {
    playerIndex[(uint64)(player.Id)] = player
  }
}

var gameCollection = collection.NewCollection()
var gameIndex = make(map[uint64]*game.Game)

// Add IDs to setup rules for a game, if they exist in the DB
func initSetupRuleIds(db *sql.DB, g *game.Game) error {
  rows, err := db.Query("SELECT id, description FROM setup_rules WHERE game_id = $1", g.Id)
  if nil != err {
     return err
  }
  for rows.Next() {
    var id int
    var description string
    if err := rows.Scan(&id, &description); nil != err {
      return err
    }
    for _, rule := range g.SetupRules {
      if rule.Description == description {
        rule.Id = id
        break
      }
    }
  }
  return nil
}

func initGameData(db *sql.DB) error {
  for i,game := range gameCollection.Games {
    game.Id = (uint)(i+1)
    gameIndex[(uint64)(i+1)] = game

    if err := initSetupRuleIds(db, game); err != nil {
      return err
    }
  }
  return nil
}

var sessions []*session.Session
var sessionIndex = make(map[uint64]*session.Session)

func initSessionData(db *sql.DB) {
  // Fixture data
  sessions = make([]*session.Session, 2)
  sessions[0] = session.NewSession(gameCollection.Games[0], players)
  sessions[0].Step(players[0])
  sessions[0].Step(players[1])

  sessions[1] = session.NewSession(gameCollection.Games[1], players)
  sessions[1].Step(players[0])
  sessions[1].Step(players[1])

  for i,session := range sessions[:1] {
    session.Id = (uint)(i+1)
    sessionIndex[(uint64)(i+1)] = session
  }

  /*
  // Select record from DB
  session := session.NewSession(nil, make([]*game.Player, 0))
  sessionRec := record.NewSessionRecord(session)
  err := sessionRec.Find(db, 68)
  if nil != err {
    fmt.Printf("Error finding session 68: %s\n", err)
  }
  sessions = append(sessions, session)
  /*
  // All records from DB
  records := &record.SessionRecordList{}
  err := records.FindAll(db)
  if nil != err {
    fmt.Println(err)
  }
  sessions = records.List()
  */
}

type CollectionHandler struct{}
func (h CollectionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  err := json.NewEncoder(w).Encode(gameCollection)
  if ( nil != err ) {
    fmt.Fprintln(w, err)
  }
}

type GameHandler struct{}
func (h GameHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  id_str := r.URL.Query().Get("id")
  id, err := strconv.ParseUint(id_str, 10, 64)
  if nil != err {
    http.Error(w, "Not found", http.StatusNotFound)
    return
  }

  game, ok := gameIndex[id]
  if ok {
    err := json.NewEncoder(w).Encode(game)
    if ( nil != err ) {
      http.Error(w, "Error", http.StatusInternalServerError)
    }
  } else {
    http.Error(w, "Not found", http.StatusNotFound)
  }
}

type PlayersHandler struct{}
func (h PlayersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  err := json.NewEncoder(w).Encode(players)
  if ( nil != err ) {
    fmt.Fprintln(w, err)
  }
}

type PlayerHandler struct{}
func (h PlayerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  player_id_str := r.URL.Query().Get("player_id")
  player_id, err := strconv.ParseUint(player_id_str, 10, 64)
  if nil != err {
    http.Error(w, "Not found", http.StatusNotFound)
    return
  }

  player, ok := playerIndex[player_id]
  if ok {
    err = json.NewEncoder(w).Encode(player)
    if ( nil != err ) {
      http.Error(w, "Error", http.StatusInternalServerError)
    }
  } else {
    http.Error(w, "Not found", http.StatusNotFound)
  }
}

type SessionsHandler struct{}
func (h SessionsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  err := json.NewEncoder(w).Encode(sessions)
  if ( nil != err ) {
    http.Error(w, "Error", http.StatusInternalServerError)
  }
}

type SessionCreateHandler struct {
  db *sql.DB
}
type SessionCreateHash struct {
  StartedDate string `json:"started_date"`
  Game string `json:"game"`
  Players []string `json:"players"`
}
type SessionCreateRequest struct {
  Session SessionCreateHash `json:"session"`
}

func fetchPlayersById(db *sql.DB, playerIds []int) ([]*game.Player, error) {
  players := make([]*game.Player, len(playerIds))

  for i, playerId := range playerIds {
    var name string
    err := db.QueryRow("SELECT name FROM players WHERE id = $1", playerId).Scan(&name)
    if err != nil {
       return players, err
    }
    players[i] = &game.Player{playerId, name}
  }

  return players, nil
}

// Persist a new session
func (handler SessionCreateHandler) marshalFunc() (func(*url.URL, http.Header, *SessionCreateRequest) (int, http.Header, *session.Session, error)) {
  return func(u *url.URL, h http.Header, rq *SessionCreateRequest) (int, http.Header, *session.Session, error) {
    var err error

    var game_id uint64
    game_id, err = strconv.ParseUint(rq.Session.Game, 10, 64)
    if nil != err {
      return http.StatusBadRequest, nil, nil, errors.New("Expected integer game ID")
    }

    player_ids := make([]int, 0)
    for _, player_id_str := range rq.Session.Players {
      player_id, err := strconv.ParseInt(player_id_str, 10, 32)
      if nil != err {
        return http.StatusBadRequest, nil, nil, errors.New("Expected integer player ID")
      }
      player_ids = append(player_ids, (int)(player_id))
    }

    var players []*game.Player
    players, err = fetchPlayersById(handler.db, player_ids)
    if nil != err {
      return http.StatusInternalServerError, nil, nil, err
    }
    fmt.Printf("Found %d matching players\n", len(players))

    session := session.NewSession(gameIndex[game_id], players)

    err = record.NewSessionRecord(session).Create(handler.db)
    if nil != err {
      return http.StatusInternalServerError, nil, nil, err
    }

    sessionIndex[(uint64)(session.Id)] = session

    session.Print()

    return http.StatusCreated, nil, session, nil
  }
}

type SessionHandler struct{}
func (h SessionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  id_str := r.URL.Query().Get("session_id")
  id, err := strconv.ParseUint(id_str, 10, 64)
  if nil != err {
    http.Error(w, "Not found", http.StatusNotFound)
    return
  }

  session, ok := sessionIndex[id]
  if ok {
    err := json.NewEncoder(w).Encode(session)
    if ( nil != err ) {
      http.Error(w, "Error", http.StatusInternalServerError)
    }
  } else {
    http.Error(w, "Not found", http.StatusNotFound)
  }
}

type StepHandler struct{}
func (h StepHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  session_id_str := r.URL.Query().Get("session_id")
  session_id, err := strconv.ParseUint(session_id_str, 10, 64)
  if nil != err {
    http.Error(w, "Session not found", http.StatusNotFound)
    return
  }
  session,ok := sessionIndex[session_id]
  if !ok {
    http.Error(w, "Session not found", http.StatusNotFound)
    return
  }

  player_id_str := r.URL.Query().Get("player_id")
  player_id, err := strconv.ParseUint(player_id_str, 10, 64)
  if nil != err {
    http.Error(w, "Player not found", http.StatusNotFound)
    return
  }
  player, ok := playerIndex[player_id]
  if !ok {
    http.Error(w, "Player not found", http.StatusNotFound)
    return
  }

  step_desc,err := url.QueryUnescape(r.URL.Query().Get("step_desc"))
  for _,step := range session.SetupSteps {
    if ( step.Rule.Description == step_desc && step.CanBeOwnedBy(player) ) {
      step.Finish()  // FIXME. Should look in request data to see what to change.
      session.Step(player)
      session.Print()
      return
    }
  }
  http.Error(w, "Step not found", http.StatusNotFound)
}

func main() {
  connectString := "user=ralph dbname=meeple_mover sslmode=disable"
  herokuConnectString := os.Getenv("HEROKU_POSTGRESQL_SILVER_URL")
  if herokuConnectString != "" {
    connectString = herokuConnectString
  }

  db, err := sql.Open("postgres", connectString)
  if err != nil {
    fmt.Print(err)
  } else {
    fmt.Println("Connected to database")
  }

  initPlayerData(db)
  initGameData(db)
  initSessionData(db)

  var origin string
  origin = os.Getenv("MEEPLE_MOVER_ORIGIN_URL")
  if "" == origin {
    origin = "http://localhost:8000"
  }
  cors := tigertonic.NewCORSBuilder().AddAllowedOrigins(origin).AddAllowedHeaders("Content-Type")

  mux := tigertonic.NewTrieServeMux()
  mux.Handle("GET", "/games", cors.Build(CollectionHandler{}))
  mux.Handle("GET", "/games/{id}", cors.Build(GameHandler{}))
  mux.Handle("GET", "/players", cors.Build(PlayersHandler{}))
  mux.Handle("GET", "/players/{player_id}", cors.Build(PlayerHandler{}))
  mux.Handle("GET", "/sessions", cors.Build(SessionsHandler{}))
  mux.Handle("POST", "/sessions", cors.Build(tigertonic.Marshaled(SessionCreateHandler{db}.marshalFunc())))
  mux.Handle("GET", "/sessions/{session_id}", cors.Build(SessionHandler{}))
  mux.Handle("PUT", "/sessions/{session_id}/players/{player_id}/steps/{step_desc}", cors.Build(StepHandler{}))

  var port string
  port = os.Getenv("PORT")
  if "" == port {
    port = "8080"
  }

  http.ListenAndServe(fmt.Sprintf(":%s", port), mux)

  db.Close()
}
<commit_msg>Fix bug: New session's players did not have a first step to display<commit_after>package main

import (
  "database/sql"
  "encoding/json"
  "errors"
  "fmt"
  "net/http"
  "net/url"
  "os"
  "strconv"
  _ "github.com/lib/pq"
  "github.com/rcrowley/go-tigertonic"
  "github.com/rkbodenner/meeple_mover/record"
  "github.com/rkbodenner/parallel_universe/collection"
  "github.com/rkbodenner/parallel_universe/game"
  "github.com/rkbodenner/parallel_universe/session"
)

var players = make([]*game.Player, 0)
var playerIndex = make(map[uint64]*game.Player)

func initPlayerData(db *sql.DB) {
  rows, err := db.Query("SELECT * FROM players")
  if nil != err {
    fmt.Print(err)
  }
  for rows.Next() {
    var name string
    var id int
    if err := rows.Scan(&id, &name); err != nil {
      fmt.Print(err)
    }
    players = append(players, &game.Player{id, name})
  }

  for _,player := range players {
    playerIndex[(uint64)(player.Id)] = player
  }
}

var gameCollection = collection.NewCollection()
var gameIndex = make(map[uint64]*game.Game)

// Add IDs to setup rules for a game, if they exist in the DB
func initSetupRuleIds(db *sql.DB, g *game.Game) error {
  rows, err := db.Query("SELECT id, description FROM setup_rules WHERE game_id = $1", g.Id)
  if nil != err {
     return err
  }
  for rows.Next() {
    var id int
    var description string
    if err := rows.Scan(&id, &description); nil != err {
      return err
    }
    for _, rule := range g.SetupRules {
      if rule.Description == description {
        rule.Id = id
        break
      }
    }
  }
  return nil
}

func initGameData(db *sql.DB) error {
  for i,game := range gameCollection.Games {
    game.Id = (uint)(i+1)
    gameIndex[(uint64)(i+1)] = game

    if err := initSetupRuleIds(db, game); err != nil {
      return err
    }
  }
  return nil
}

var sessions []*session.Session
var sessionIndex = make(map[uint64]*session.Session)

func initSessionData(db *sql.DB) {
  // Fixture data
  sessions = make([]*session.Session, 2)
  sessions[0] = session.NewSession(gameCollection.Games[0], players)
  sessions[0].Step(players[0])
  sessions[0].Step(players[1])

  sessions[1] = session.NewSession(gameCollection.Games[1], players)
  sessions[1].Step(players[0])
  sessions[1].Step(players[1])

  for i,session := range sessions[:1] {
    session.Id = (uint)(i+1)
    sessionIndex[(uint64)(i+1)] = session
  }

  /*
  // Select record from DB
  session := session.NewSession(nil, make([]*game.Player, 0))
  sessionRec := record.NewSessionRecord(session)
  err := sessionRec.Find(db, 68)
  if nil != err {
    fmt.Printf("Error finding session 68: %s\n", err)
  }
  sessions = append(sessions, session)
  /*
  // All records from DB
  records := &record.SessionRecordList{}
  err := records.FindAll(db)
  if nil != err {
    fmt.Println(err)
  }
  sessions = records.List()
  */
}

type CollectionHandler struct{}
func (h CollectionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  err := json.NewEncoder(w).Encode(gameCollection)
  if ( nil != err ) {
    fmt.Fprintln(w, err)
  }
}

type GameHandler struct{}
func (h GameHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  id_str := r.URL.Query().Get("id")
  id, err := strconv.ParseUint(id_str, 10, 64)
  if nil != err {
    http.Error(w, "Not found", http.StatusNotFound)
    return
  }

  game, ok := gameIndex[id]
  if ok {
    err := json.NewEncoder(w).Encode(game)
    if ( nil != err ) {
      http.Error(w, "Error", http.StatusInternalServerError)
    }
  } else {
    http.Error(w, "Not found", http.StatusNotFound)
  }
}

type PlayersHandler struct{}
func (h PlayersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  err := json.NewEncoder(w).Encode(players)
  if ( nil != err ) {
    fmt.Fprintln(w, err)
  }
}

type PlayerHandler struct{}
func (h PlayerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  player_id_str := r.URL.Query().Get("player_id")
  player_id, err := strconv.ParseUint(player_id_str, 10, 64)
  if nil != err {
    http.Error(w, "Not found", http.StatusNotFound)
    return
  }

  player, ok := playerIndex[player_id]
  if ok {
    err = json.NewEncoder(w).Encode(player)
    if ( nil != err ) {
      http.Error(w, "Error", http.StatusInternalServerError)
    }
  } else {
    http.Error(w, "Not found", http.StatusNotFound)
  }
}

type SessionsHandler struct{}
func (h SessionsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  err := json.NewEncoder(w).Encode(sessions)
  if ( nil != err ) {
    http.Error(w, "Error", http.StatusInternalServerError)
  }
}

type SessionCreateHandler struct {
  db *sql.DB
}
type SessionCreateHash struct {
  StartedDate string `json:"started_date"`
  Game string `json:"game"`
  Players []string `json:"players"`
}
type SessionCreateRequest struct {
  Session SessionCreateHash `json:"session"`
}

func fetchPlayersById(db *sql.DB, playerIds []int) ([]*game.Player, error) {
  players := make([]*game.Player, len(playerIds))

  for i, playerId := range playerIds {
    var name string
    err := db.QueryRow("SELECT name FROM players WHERE id = $1", playerId).Scan(&name)
    if err != nil {
       return players, err
    }
    players[i] = &game.Player{playerId, name}
  }

  return players, nil
}

// Persist a new session
func (handler SessionCreateHandler) marshalFunc() (func(*url.URL, http.Header, *SessionCreateRequest) (int, http.Header, *session.Session, error)) {
  return func(u *url.URL, h http.Header, rq *SessionCreateRequest) (int, http.Header, *session.Session, error) {
    var err error

    var game_id uint64
    game_id, err = strconv.ParseUint(rq.Session.Game, 10, 64)
    if nil != err {
      return http.StatusBadRequest, nil, nil, errors.New("Expected integer game ID")
    }

    player_ids := make([]int, 0)
    for _, player_id_str := range rq.Session.Players {
      player_id, err := strconv.ParseInt(player_id_str, 10, 32)
      if nil != err {
        return http.StatusBadRequest, nil, nil, errors.New("Expected integer player ID")
      }
      player_ids = append(player_ids, (int)(player_id))
    }

    var players []*game.Player
    players, err = fetchPlayersById(handler.db, player_ids)
    if nil != err {
      return http.StatusInternalServerError, nil, nil, err
    }
    fmt.Printf("Found %d matching players\n", len(players))

    session := session.NewSession(gameIndex[game_id], players)
    session.StepAllPlayers()

    err = record.NewSessionRecord(session).Create(handler.db)
    if nil != err {
      return http.StatusInternalServerError, nil, nil, err
    }

    sessionIndex[(uint64)(session.Id)] = session

    session.Print()

    return http.StatusCreated, nil, session, nil
  }
}

type SessionHandler struct{}
func (h SessionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  id_str := r.URL.Query().Get("session_id")
  id, err := strconv.ParseUint(id_str, 10, 64)
  if nil != err {
    http.Error(w, "Not found", http.StatusNotFound)
    return
  }

  session, ok := sessionIndex[id]
  if ok {
    err := json.NewEncoder(w).Encode(session)
    if ( nil != err ) {
      http.Error(w, "Error", http.StatusInternalServerError)
    }
  } else {
    http.Error(w, "Not found", http.StatusNotFound)
  }
}

type StepHandler struct{}
func (h StepHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  session_id_str := r.URL.Query().Get("session_id")
  session_id, err := strconv.ParseUint(session_id_str, 10, 64)
  if nil != err {
    http.Error(w, "Session not found", http.StatusNotFound)
    return
  }
  session,ok := sessionIndex[session_id]
  if !ok {
    http.Error(w, "Session not found", http.StatusNotFound)
    return
  }

  player_id_str := r.URL.Query().Get("player_id")
  player_id, err := strconv.ParseUint(player_id_str, 10, 64)
  if nil != err {
    http.Error(w, "Player not found", http.StatusNotFound)
    return
  }
  player, ok := playerIndex[player_id]
  if !ok {
    http.Error(w, "Player not found", http.StatusNotFound)
    return
  }

  step_desc,err := url.QueryUnescape(r.URL.Query().Get("step_desc"))
  for _,step := range session.SetupSteps {
    if ( step.Rule.Description == step_desc && step.CanBeOwnedBy(player) ) {
      step.Finish()  // FIXME. Should look in request data to see what to change.
      session.Step(player)
      session.Print()
      return
    }
  }
  http.Error(w, "Step not found", http.StatusNotFound)
}

func main() {
  connectString := "user=ralph dbname=meeple_mover sslmode=disable"
  herokuConnectString := os.Getenv("HEROKU_POSTGRESQL_SILVER_URL")
  if herokuConnectString != "" {
    connectString = herokuConnectString
  }

  db, err := sql.Open("postgres", connectString)
  if err != nil {
    fmt.Print(err)
  } else {
    fmt.Println("Connected to database")
  }

  initPlayerData(db)
  initGameData(db)
  initSessionData(db)

  var origin string
  origin = os.Getenv("MEEPLE_MOVER_ORIGIN_URL")
  if "" == origin {
    origin = "http://localhost:8000"
  }
  cors := tigertonic.NewCORSBuilder().AddAllowedOrigins(origin).AddAllowedHeaders("Content-Type")

  mux := tigertonic.NewTrieServeMux()
  mux.Handle("GET", "/games", cors.Build(CollectionHandler{}))
  mux.Handle("GET", "/games/{id}", cors.Build(GameHandler{}))
  mux.Handle("GET", "/players", cors.Build(PlayersHandler{}))
  mux.Handle("GET", "/players/{player_id}", cors.Build(PlayerHandler{}))
  mux.Handle("GET", "/sessions", cors.Build(SessionsHandler{}))
  mux.Handle("POST", "/sessions", cors.Build(tigertonic.Marshaled(SessionCreateHandler{db}.marshalFunc())))
  mux.Handle("GET", "/sessions/{session_id}", cors.Build(SessionHandler{}))
  mux.Handle("PUT", "/sessions/{session_id}/players/{player_id}/steps/{step_desc}", cors.Build(StepHandler{}))

  var port string
  port = os.Getenv("PORT")
  if "" == port {
    port = "8080"
  }

  http.ListenAndServe(fmt.Sprintf(":%s", port), mux)

  db.Close()
}
<|endoftext|>


<commit_before>package main

import (
	"log"
)

var allPersons = make([]*PersonMetrics, 8)

func MetricParser() {
	for i := range allPersons {
		allPersons[i] = &PersonMetrics{Person: i + 1, BodyMetrics: make(map[int]BodyMetric)}
	}
	for {
		partial_metric := <-metric_chan
		log.Printf("Received partial metric: %+v\n", partial_metric)
		UpdatePerson(partial_metric.Person)
		UpdateBody(partial_metric.Body)
		UpdateWeight(partial_metric.Weight)
	}
}

func GetPersonMetrics(personId int) *PersonMetrics {
	person := allPersons[personId-1]
	return person
}

func UpdatePerson(update Person) {
	if !update.Valid {
		return
	}
	log.Printf("Received person metrics: %+v", update)
	person := GetPersonMetrics(update.Person)
	person.Gender = update.Gender
	person.Age = update.Age
	person.Size = update.Size
	person.Activity = update.Activity
	PrintPerson(person)
}

func UpdateBody(update Body) {
	if !update.Valid {
		return
	}
	log.Printf("Received body metrics: %+v", update)
	person := GetPersonMetrics(update.Person)
	_, ok := person.BodyMetrics[update.Timestamp]
	if !ok {
		log.Printf("No body metric - creating")
		person.BodyMetrics[update.Timestamp] = BodyMetric{}
	}
	bodyMetric, _ := person.BodyMetrics[update.Timestamp]
	bodyMetric.Timestamp = update.Timestamp
	bodyMetric.Kcal = update.Kcal
	bodyMetric.Fat = update.Fat
	bodyMetric.Tbw = update.Tbw
	bodyMetric.Muscle = update.Muscle
	bodyMetric.Bone = update.Bone
	person.BodyMetrics[update.Timestamp] = bodyMetric
	PrintPerson(person)
}
func UpdateWeight(update Weight) {
	if !update.Valid {
		return
	}
	log.Printf("Received weight metrics: %+v", update)
	person := GetPersonMetrics(update.Person)
	_, ok := person.BodyMetrics[update.Timestamp]
	if !ok {
		log.Printf("No body metric - creating")
		person.BodyMetrics[update.Timestamp] = BodyMetric{}
	}
	bodyMetric, _ := person.BodyMetrics[update.Timestamp]
	bodyMetric.Weight = update.Weight
	bodyMetric.Timestamp = update.Timestamp
	person.BodyMetrics[update.Timestamp] = bodyMetric
	PrintPerson(person)
}
func PrintPerson(person *PersonMetrics) {
	log.Printf("Person information: %+v", person)
}
<commit_msg>Add BMI calculations<commit_after>package main

import (
	"log"
	"math"
)

var allPersons = make([]*PersonMetrics, 8)

func MetricParser() {
	for i := range allPersons {
		allPersons[i] = &PersonMetrics{Person: i + 1, BodyMetrics: make(map[int]BodyMetric)}
	}
	for {
		partial_metric := <-metric_chan
		UpdatePerson(partial_metric.Person)
		UpdateBody(partial_metric.Body)
		UpdateWeight(partial_metric.Weight)
	}
}

func GetPersonMetrics(personId int) *PersonMetrics {
	person := allPersons[personId-1]
	return person
}

func UpdatePerson(update Person) {
	if !update.Valid {
		return
	}
	log.Printf("Received person metrics: %+v", update)
	person := GetPersonMetrics(update.Person)
	person.Gender = update.Gender
	person.Age = update.Age
	person.Size = update.Size
	person.Activity = update.Activity
	PrintPerson(person)
}

func UpdateBody(update Body) {
	if !update.Valid {
		return
	}
	log.Printf("Received body metrics: %+v", update)
	person := GetPersonMetrics(update.Person)
	_, ok := person.BodyMetrics[update.Timestamp]
	if !ok {
		log.Printf("No body metric - creating")
		person.BodyMetrics[update.Timestamp] = BodyMetric{}
	}
	bodyMetric := person.BodyMetrics[update.Timestamp]
	bodyMetric.Timestamp = update.Timestamp
	bodyMetric.Kcal = update.Kcal
	bodyMetric.Fat = update.Fat
	bodyMetric.Tbw = update.Tbw
	bodyMetric.Muscle = update.Muscle
	bodyMetric.Bone = update.Bone
	person.BodyMetrics[update.Timestamp] = bodyMetric
	PrintPerson(person)
}
func UpdateWeight(update Weight) {
	if !update.Valid {
		return
	}
	log.Printf("Received weight metrics: %+v", update)
	person := GetPersonMetrics(update.Person)
	_, ok := person.BodyMetrics[update.Timestamp]
	if !ok {
		log.Printf("No body metric - creating")
		person.BodyMetrics[update.Timestamp] = BodyMetric{}
	}
	bodyMetric := person.BodyMetrics[update.Timestamp]
	bodyMetric.Weight = update.Weight
	bodyMetric.Timestamp = update.Timestamp
	if bodyMetric.Weight > 0 && person.Size > 0 {
		bodyMetric.Bmi = bodyMetric.Weight / float32(math.Pow(float64(person.Size)/100, 2))
	}

	person.BodyMetrics[update.Timestamp] = bodyMetric
	PrintPerson(person)
}
func PrintPerson(person *PersonMetrics) {
	log.Printf("Person information: %+v", person)
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 The Go Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd.

// Package lintutil provides helpers for writing linter command lines.
package lintutil // import "honnef.co/go/tools/lint/lintutil"

import (
	"errors"
	"flag"
	"fmt"
	"go/build"
	"go/types"
	"log"
	"os"
	"runtime/pprof"
	"strconv"
	"strings"
	"time"

	"honnef.co/go/tools/lint"
	"honnef.co/go/tools/lint/lintutil/format"
	"honnef.co/go/tools/version"

	"golang.org/x/tools/go/packages"
)

func usage(name string, flags *flag.FlagSet) func() {
	return func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] # runs on package in current directory\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] packages\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] directory\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] files... # must be a single package\n", name)
		fmt.Fprintf(os.Stderr, "Flags:\n")
		flags.PrintDefaults()
	}
}

func resolveRelative(importPaths []string, tags []string) (goFiles bool, err error) {
	if len(importPaths) == 0 {
		return false, nil
	}
	if strings.HasSuffix(importPaths[0], ".go") {
		// User is specifying a package in terms of .go files, don't resolve
		return true, nil
	}
	wd, err := os.Getwd()
	if err != nil {
		return false, err
	}
	ctx := build.Default
	ctx.BuildTags = tags
	for i, path := range importPaths {
		bpkg, err := ctx.Import(path, wd, build.FindOnly)
		if err != nil {
			return false, fmt.Errorf("can't load package %q: %v", path, err)
		}
		importPaths[i] = bpkg.ImportPath
	}
	return false, nil
}

func parseIgnore(s string) ([]lint.Ignore, error) {
	var out []lint.Ignore
	if len(s) == 0 {
		return nil, nil
	}
	for _, part := range strings.Fields(s) {
		p := strings.Split(part, ":")
		if len(p) != 2 {
			return nil, errors.New("malformed ignore string")
		}
		path := p[0]
		checks := strings.Split(p[1], ",")
		out = append(out, &lint.GlobIgnore{Pattern: path, Checks: checks})
	}
	return out, nil
}

type versionFlag int

func (v *versionFlag) String() string {
	return fmt.Sprintf("1.%d", *v)
}

func (v *versionFlag) Set(s string) error {
	if len(s) < 3 {
		return errors.New("invalid Go version")
	}
	if s[0] != '1' {
		return errors.New("invalid Go version")
	}
	if s[1] != '.' {
		return errors.New("invalid Go version")
	}
	i, err := strconv.Atoi(s[2:])
	*v = versionFlag(i)
	return err
}

func (v *versionFlag) Get() interface{} {
	return int(*v)
}

func FlagSet(name string) *flag.FlagSet {
	flags := flag.NewFlagSet("", flag.ExitOnError)
	flags.Usage = usage(name, flags)
	flags.String("tags", "", "List of `build tags`")
	flags.String("ignore", "", "Space separated list of checks to ignore, in the following format: 'import/path/file.go:Check1,Check2,...' Both the import path and file name sections support globbing, e.g. 'os/exec/*_test.go'")
	flags.Bool("tests", true, "Include tests")
	flags.Bool("version", false, "Print version and exit")
	flags.Bool("show-ignored", false, "Don't filter ignored problems")
	flags.String("f", "text", "Output `format` (valid choices are 'text' and 'json')")

	flags.Int("debug.max-concurrent-jobs", 0, "Number of jobs to run concurrently")
	flags.Bool("debug.print-stats", false, "Print debug statistics")
	flags.String("debug.cpuprofile", "", "Write CPU profile to `file`")

	tags := build.Default.ReleaseTags
	v := tags[len(tags)-1][2:]
	version := new(versionFlag)
	if err := version.Set(v); err != nil {
		panic(fmt.Sprintf("internal error: %s", err))
	}

	flags.Var(version, "go", "Target Go `version` in the format '1.x'")
	return flags
}

type CheckerConfig struct {
	Checker     lint.Checker
	ExitNonZero bool
}

func ProcessFlagSet(confs map[string]CheckerConfig, fs *flag.FlagSet) {
	tags := fs.Lookup("tags").Value.(flag.Getter).Get().(string)
	ignore := fs.Lookup("ignore").Value.(flag.Getter).Get().(string)
	tests := fs.Lookup("tests").Value.(flag.Getter).Get().(bool)
	goVersion := fs.Lookup("go").Value.(flag.Getter).Get().(int)
	formatter := fs.Lookup("f").Value.(flag.Getter).Get().(string)
	printVersion := fs.Lookup("version").Value.(flag.Getter).Get().(bool)
	showIgnored := fs.Lookup("show-ignored").Value.(flag.Getter).Get().(bool)

	maxConcurrentJobs := fs.Lookup("debug.max-concurrent-jobs").Value.(flag.Getter).Get().(int)
	printStats := fs.Lookup("debug.print-stats").Value.(flag.Getter).Get().(bool)
	cpuProfile := fs.Lookup("debug.cpuprofile").Value.(flag.Getter).Get().(string)

	exit := os.Exit
	if cpuProfile != "" {
		f, err := os.Create(cpuProfile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		exit = func(code int) {
			pprof.StopCPUProfile()
			os.Exit(code)
		}
	}

	if printVersion {
		version.Print()
		exit(0)
	}

	var cs []lint.Checker
	for _, conf := range confs {
		cs = append(cs, conf.Checker)
	}
	ps, err := Lint(cs, fs.Args(), &Options{
		Tags:          strings.Fields(tags),
		LintTests:     tests,
		Ignores:       ignore,
		GoVersion:     goVersion,
		ReturnIgnored: showIgnored,

		MaxConcurrentJobs: maxConcurrentJobs,
		PrintStats:        printStats,
	})
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		exit(1)
	}

	var f format.Formatter
	switch formatter {
	case "text":
		f = format.Text{W: os.Stdout}
	case "stylish":
		f = &format.Stylish{W: os.Stdout}
	case "json":
		f = format.JSON{W: os.Stdout}
	default:
		fmt.Fprintf(os.Stderr, "unsupported output format %q\n", formatter)
		exit(2)
	}

	var (
		total    int
		errors   int
		warnings int
	)

	total = len(ps)
	for _, p := range ps {
		conf, ok := confs[p.Checker]
		if !ok || conf.ExitNonZero {
			errors++
		} else {
			warnings++
		}
		f.Format(p)
	}
	if f, ok := f.(format.Statter); ok {
		f.Stats(total, errors, warnings)
	}
	if errors > 0 {
		exit(1)
	}
}

type Options struct {
	Tags          []string
	LintTests     bool
	Ignores       string
	GoVersion     int
	ReturnIgnored bool

	MaxConcurrentJobs int
	PrintStats        bool
}

func Lint(cs []lint.Checker, paths []string, opt *Options) ([]lint.Problem, error) {
	stats := lint.PerfStats{
		CheckerInits: map[string]time.Duration{},
	}

	if opt == nil {
		opt = &Options{}
	}
	ignores, err := parseIgnore(opt.Ignores)
	if err != nil {
		return nil, err
	}

	ctx := build.Default
	// XXX nothing cares about built tags right now
	ctx.BuildTags = opt.Tags
	conf := &packages.Config{
		Mode:  packages.LoadAllSyntax,
		Tests: opt.LintTests,
		Error: func(err error) {},
	}

	t := time.Now()
	pkgs, err := packages.Load(conf, paths...)
	if err != nil {
		return nil, err
	}
	stats.PackageLoading = time.Since(t)

	var problems []lint.Problem
	workingPkgs := make([]*packages.Package, 0, len(pkgs))
	for _, pkg := range pkgs {
		if pkg.IllTyped {
			problems = append(problems, compileErrors(pkg)...)
		} else {
			workingPkgs = append(workingPkgs, pkg)
		}
	}

	if len(workingPkgs) == 0 {
		return problems, nil
	}

	l := &lint.Linter{
		Checkers:      cs,
		Ignores:       ignores,
		GoVersion:     opt.GoVersion,
		ReturnIgnored: opt.ReturnIgnored,

		MaxConcurrentJobs: opt.MaxConcurrentJobs,
		PrintStats:        opt.PrintStats,
	}
	problems = append(problems, l.Lint(workingPkgs, &stats)...)

	return problems, nil
}

func compileErrors(pkg *packages.Package) []lint.Problem {
	if !pkg.IllTyped {
		return nil
	}
	if len(pkg.Errors) == 0 {
		// transitively ill-typed
		var ps []lint.Problem
		for _, imp := range pkg.Imports {
			ps = append(ps, compileErrors(imp)...)
		}
		return ps
	}
	var ps []lint.Problem
	for _, err := range pkg.Errors {
		var p lint.Problem
		switch err := err.(type) {
		case types.Error:
			p = lint.Problem{
				Position: err.Fset.Position(err.Pos),
				Text:     err.Msg,
				Checker:  "compiler",
				Check:    "compile",
			}
		default:
			fmt.Fprintf(os.Stderr, "internal error: unhandled error type %T\n", err)
		}
		ps = append(ps, p)
	}
	return ps
}

func ProcessArgs(name string, cs map[string]CheckerConfig, args []string) {
	flags := FlagSet(name)
	flags.Parse(args)

	ProcessFlagSet(cs, flags)
}
<commit_msg>lint/lintutil: no args means check the current directory<commit_after>// Copyright (c) 2013 The Go Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd.

// Package lintutil provides helpers for writing linter command lines.
package lintutil // import "honnef.co/go/tools/lint/lintutil"

import (
	"errors"
	"flag"
	"fmt"
	"go/build"
	"go/types"
	"log"
	"os"
	"runtime/pprof"
	"strconv"
	"strings"
	"time"

	"honnef.co/go/tools/lint"
	"honnef.co/go/tools/lint/lintutil/format"
	"honnef.co/go/tools/version"

	"golang.org/x/tools/go/packages"
)

func usage(name string, flags *flag.FlagSet) func() {
	return func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] # runs on package in current directory\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] packages\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] directory\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] files... # must be a single package\n", name)
		fmt.Fprintf(os.Stderr, "Flags:\n")
		flags.PrintDefaults()
	}
}

func resolveRelative(importPaths []string, tags []string) (goFiles bool, err error) {
	if len(importPaths) == 0 {
		return false, nil
	}
	if strings.HasSuffix(importPaths[0], ".go") {
		// User is specifying a package in terms of .go files, don't resolve
		return true, nil
	}
	wd, err := os.Getwd()
	if err != nil {
		return false, err
	}
	ctx := build.Default
	ctx.BuildTags = tags
	for i, path := range importPaths {
		bpkg, err := ctx.Import(path, wd, build.FindOnly)
		if err != nil {
			return false, fmt.Errorf("can't load package %q: %v", path, err)
		}
		importPaths[i] = bpkg.ImportPath
	}
	return false, nil
}

func parseIgnore(s string) ([]lint.Ignore, error) {
	var out []lint.Ignore
	if len(s) == 0 {
		return nil, nil
	}
	for _, part := range strings.Fields(s) {
		p := strings.Split(part, ":")
		if len(p) != 2 {
			return nil, errors.New("malformed ignore string")
		}
		path := p[0]
		checks := strings.Split(p[1], ",")
		out = append(out, &lint.GlobIgnore{Pattern: path, Checks: checks})
	}
	return out, nil
}

type versionFlag int

func (v *versionFlag) String() string {
	return fmt.Sprintf("1.%d", *v)
}

func (v *versionFlag) Set(s string) error {
	if len(s) < 3 {
		return errors.New("invalid Go version")
	}
	if s[0] != '1' {
		return errors.New("invalid Go version")
	}
	if s[1] != '.' {
		return errors.New("invalid Go version")
	}
	i, err := strconv.Atoi(s[2:])
	*v = versionFlag(i)
	return err
}

func (v *versionFlag) Get() interface{} {
	return int(*v)
}

func FlagSet(name string) *flag.FlagSet {
	flags := flag.NewFlagSet("", flag.ExitOnError)
	flags.Usage = usage(name, flags)
	flags.String("tags", "", "List of `build tags`")
	flags.String("ignore", "", "Space separated list of checks to ignore, in the following format: 'import/path/file.go:Check1,Check2,...' Both the import path and file name sections support globbing, e.g. 'os/exec/*_test.go'")
	flags.Bool("tests", true, "Include tests")
	flags.Bool("version", false, "Print version and exit")
	flags.Bool("show-ignored", false, "Don't filter ignored problems")
	flags.String("f", "text", "Output `format` (valid choices are 'text' and 'json')")

	flags.Int("debug.max-concurrent-jobs", 0, "Number of jobs to run concurrently")
	flags.Bool("debug.print-stats", false, "Print debug statistics")
	flags.String("debug.cpuprofile", "", "Write CPU profile to `file`")

	tags := build.Default.ReleaseTags
	v := tags[len(tags)-1][2:]
	version := new(versionFlag)
	if err := version.Set(v); err != nil {
		panic(fmt.Sprintf("internal error: %s", err))
	}

	flags.Var(version, "go", "Target Go `version` in the format '1.x'")
	return flags
}

type CheckerConfig struct {
	Checker     lint.Checker
	ExitNonZero bool
}

func ProcessFlagSet(confs map[string]CheckerConfig, fs *flag.FlagSet) {
	tags := fs.Lookup("tags").Value.(flag.Getter).Get().(string)
	ignore := fs.Lookup("ignore").Value.(flag.Getter).Get().(string)
	tests := fs.Lookup("tests").Value.(flag.Getter).Get().(bool)
	goVersion := fs.Lookup("go").Value.(flag.Getter).Get().(int)
	formatter := fs.Lookup("f").Value.(flag.Getter).Get().(string)
	printVersion := fs.Lookup("version").Value.(flag.Getter).Get().(bool)
	showIgnored := fs.Lookup("show-ignored").Value.(flag.Getter).Get().(bool)

	maxConcurrentJobs := fs.Lookup("debug.max-concurrent-jobs").Value.(flag.Getter).Get().(int)
	printStats := fs.Lookup("debug.print-stats").Value.(flag.Getter).Get().(bool)
	cpuProfile := fs.Lookup("debug.cpuprofile").Value.(flag.Getter).Get().(string)

	exit := os.Exit
	if cpuProfile != "" {
		f, err := os.Create(cpuProfile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		exit = func(code int) {
			pprof.StopCPUProfile()
			os.Exit(code)
		}
	}

	if printVersion {
		version.Print()
		exit(0)
	}

	var cs []lint.Checker
	for _, conf := range confs {
		cs = append(cs, conf.Checker)
	}
	ps, err := Lint(cs, fs.Args(), &Options{
		Tags:          strings.Fields(tags),
		LintTests:     tests,
		Ignores:       ignore,
		GoVersion:     goVersion,
		ReturnIgnored: showIgnored,

		MaxConcurrentJobs: maxConcurrentJobs,
		PrintStats:        printStats,
	})
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		exit(1)
	}

	var f format.Formatter
	switch formatter {
	case "text":
		f = format.Text{W: os.Stdout}
	case "stylish":
		f = &format.Stylish{W: os.Stdout}
	case "json":
		f = format.JSON{W: os.Stdout}
	default:
		fmt.Fprintf(os.Stderr, "unsupported output format %q\n", formatter)
		exit(2)
	}

	var (
		total    int
		errors   int
		warnings int
	)

	total = len(ps)
	for _, p := range ps {
		conf, ok := confs[p.Checker]
		if !ok || conf.ExitNonZero {
			errors++
		} else {
			warnings++
		}
		f.Format(p)
	}
	if f, ok := f.(format.Statter); ok {
		f.Stats(total, errors, warnings)
	}
	if errors > 0 {
		exit(1)
	}
}

type Options struct {
	Tags          []string
	LintTests     bool
	Ignores       string
	GoVersion     int
	ReturnIgnored bool

	MaxConcurrentJobs int
	PrintStats        bool
}

func Lint(cs []lint.Checker, paths []string, opt *Options) ([]lint.Problem, error) {
	stats := lint.PerfStats{
		CheckerInits: map[string]time.Duration{},
	}

	if opt == nil {
		opt = &Options{}
	}
	ignores, err := parseIgnore(opt.Ignores)
	if err != nil {
		return nil, err
	}

	ctx := build.Default
	// XXX nothing cares about built tags right now
	ctx.BuildTags = opt.Tags
	conf := &packages.Config{
		Mode:  packages.LoadAllSyntax,
		Tests: opt.LintTests,
		Error: func(err error) {},
	}

	t := time.Now()
	if len(paths) == 0 {
		paths = []string{"."}
	}
	pkgs, err := packages.Load(conf, paths...)
	if err != nil {
		return nil, err
	}
	stats.PackageLoading = time.Since(t)

	var problems []lint.Problem
	workingPkgs := make([]*packages.Package, 0, len(pkgs))
	for _, pkg := range pkgs {
		if pkg.IllTyped {
			problems = append(problems, compileErrors(pkg)...)
		} else {
			workingPkgs = append(workingPkgs, pkg)
		}
	}

	if len(workingPkgs) == 0 {
		return problems, nil
	}

	l := &lint.Linter{
		Checkers:      cs,
		Ignores:       ignores,
		GoVersion:     opt.GoVersion,
		ReturnIgnored: opt.ReturnIgnored,

		MaxConcurrentJobs: opt.MaxConcurrentJobs,
		PrintStats:        opt.PrintStats,
	}
	problems = append(problems, l.Lint(workingPkgs, &stats)...)

	return problems, nil
}

func compileErrors(pkg *packages.Package) []lint.Problem {
	if !pkg.IllTyped {
		return nil
	}
	if len(pkg.Errors) == 0 {
		// transitively ill-typed
		var ps []lint.Problem
		for _, imp := range pkg.Imports {
			ps = append(ps, compileErrors(imp)...)
		}
		return ps
	}
	var ps []lint.Problem
	for _, err := range pkg.Errors {
		var p lint.Problem
		switch err := err.(type) {
		case types.Error:
			p = lint.Problem{
				Position: err.Fset.Position(err.Pos),
				Text:     err.Msg,
				Checker:  "compiler",
				Check:    "compile",
			}
		default:
			fmt.Fprintf(os.Stderr, "internal error: unhandled error type %T\n", err)
		}
		ps = append(ps, p)
	}
	return ps
}

func ProcessArgs(name string, cs map[string]CheckerConfig, args []string) {
	flags := FlagSet(name)
	flags.Parse(args)

	ProcessFlagSet(cs, flags)
}
<|endoftext|>


<commit_before>package dependency

import (
	"errors"
	"fmt"
	"log"
	"regexp"
)

// Node is a node entry in Consul
type Node struct {
	Node    string
	Address string
}

type CatalogNodes struct {
	rawKey     string
	DataCenter string
}

// Fetch queries the Consul API defined by the given client and returns a slice
// of Node objects
func (d *CatalogNodes) Fetch(clients *ClientSet, opts *QueryOptions) (interface{}, *ResponseMetadata, error) {
	if opts == nil {
		opts = &QueryOptions{}
	}

	consulOpts := opts.consulQueryOptions()
	if d.DataCenter != "" {
		consulOpts.Datacenter = d.DataCenter
	}

	log.Printf("[DEBUG] (%s) querying Consul with %+v", d.Display(), consulOpts)

	consul, err := clients.Consul()
	if err != nil {
		return nil, nil, fmt.Errorf("catalog nodes: error getting client: %s", err)
	}

	catalog := consul.Catalog()
	n, qm, err := catalog.Nodes(consulOpts)
	if err != nil {
		return nil, nil, fmt.Errorf("catalog nodes: error fetching: %s", err)
	}

	log.Printf("[DEBUG] (%s) Consul returned %d nodes", d.Display(), len(n))

	nodes := make([]*Node, 0, len(n))
	for _, node := range n {
		nodes = append(nodes, &Node{
			Node:    node.Node,
			Address: node.Address,
		})
	}

	rm := &ResponseMetadata{
		LastIndex:   qm.LastIndex,
		LastContact: qm.LastContact,
	}

	return nodes, rm, nil
}

func (d *CatalogNodes) HashCode() string {
	return fmt.Sprintf("CatalogNodes|%s", d.rawKey)
}

func (d *CatalogNodes) Display() string {
	if d.rawKey == "" {
		return fmt.Sprintf(`"nodes"`)
	}

	return fmt.Sprintf(`"nodes(%s)"`, d.rawKey)
}

// ParseCatalogNodes parses a string of the format @dc.
func ParseCatalogNodes(s ...string) (*CatalogNodes, error) {
	switch len(s) {
	case 0:
		return &CatalogNodes{rawKey: ""}, nil
	case 1:
		dc := s[0]

		re := regexp.MustCompile(`\A` +
			`(@(?P<datacenter>[[:word:]\.\-]+))?` +
			`\z`)
		names := re.SubexpNames()
		match := re.FindAllStringSubmatch(dc, -1)

		if len(match) == 0 {
			return nil, errors.New("invalid node dependency format")
		}

		r := match[0]

		m := map[string]string{}
		for i, n := range r {
			if names[i] != "" {
				m[names[i]] = n
			}
		}

		nd := &CatalogNodes{
			rawKey:     dc,
			DataCenter: m["datacenter"],
		}

		return nd, nil
	default:
		return nil, fmt.Errorf("expected 0 or 1 arguments, got %d", len(s))
	}
}
<commit_msg>Sort nodes<commit_after>package dependency

import (
	"errors"
	"fmt"
	"log"
	"regexp"
	"sort"
)

// Node is a node entry in Consul
type Node struct {
	Node    string
	Address string
}

type CatalogNodes struct {
	rawKey     string
	DataCenter string
}

// Fetch queries the Consul API defined by the given client and returns a slice
// of Node objects
func (d *CatalogNodes) Fetch(clients *ClientSet, opts *QueryOptions) (interface{}, *ResponseMetadata, error) {
	if opts == nil {
		opts = &QueryOptions{}
	}

	consulOpts := opts.consulQueryOptions()
	if d.DataCenter != "" {
		consulOpts.Datacenter = d.DataCenter
	}

	log.Printf("[DEBUG] (%s) querying Consul with %+v", d.Display(), consulOpts)

	consul, err := clients.Consul()
	if err != nil {
		return nil, nil, fmt.Errorf("catalog nodes: error getting client: %s", err)
	}

	catalog := consul.Catalog()
	n, qm, err := catalog.Nodes(consulOpts)
	if err != nil {
		return nil, nil, fmt.Errorf("catalog nodes: error fetching: %s", err)
	}

	log.Printf("[DEBUG] (%s) Consul returned %d nodes", d.Display(), len(n))

	nodes := make([]*Node, 0, len(n))
	for _, node := range n {
		nodes = append(nodes, &Node{
			Node:    node.Node,
			Address: node.Address,
		})
	}
	sort.Stable(NodeList(nodes))

	rm := &ResponseMetadata{
		LastIndex:   qm.LastIndex,
		LastContact: qm.LastContact,
	}

	return nodes, rm, nil
}

func (d *CatalogNodes) HashCode() string {
	return fmt.Sprintf("CatalogNodes|%s", d.rawKey)
}

func (d *CatalogNodes) Display() string {
	if d.rawKey == "" {
		return fmt.Sprintf(`"nodes"`)
	}

	return fmt.Sprintf(`"nodes(%s)"`, d.rawKey)
}

// ParseCatalogNodes parses a string of the format @dc.
func ParseCatalogNodes(s ...string) (*CatalogNodes, error) {
	switch len(s) {
	case 0:
		return &CatalogNodes{rawKey: ""}, nil
	case 1:
		dc := s[0]

		re := regexp.MustCompile(`\A` +
			`(@(?P<datacenter>[[:word:]\.\-]+))?` +
			`\z`)
		names := re.SubexpNames()
		match := re.FindAllStringSubmatch(dc, -1)

		if len(match) == 0 {
			return nil, errors.New("invalid node dependency format")
		}

		r := match[0]

		m := map[string]string{}
		for i, n := range r {
			if names[i] != "" {
				m[names[i]] = n
			}
		}

		nd := &CatalogNodes{
			rawKey:     dc,
			DataCenter: m["datacenter"],
		}

		return nd, nil
	default:
		return nil, fmt.Errorf("expected 0 or 1 arguments, got %d", len(s))
	}
}

type NodeList []*Node

func (s NodeList) Len() int      { return len(s) }
func (s NodeList) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s NodeList) Less(i, j int) bool {
	if s[i].Node == s[j].Node {
		return s[i].Address <= s[j].Address
	}
	return s[i].Node <= s[j].Node
}
<|endoftext|>


<commit_before>// +build linux
package devmapper

import (
	"fmt"
	"github.com/stretchr/testify/assert"
	"os"
	"os/exec"
	"reflect"
	"strings"
	"testing"
)

const (
	dataDev     = "/dev/loop0"
	metadataDev = "/dev/loop1"
	poolName    = "test_pool"
	devRoot     = "/tmp/devmapper"
)

func setUp() error {
	cmd := exec.Command("mkdir", "-p", devRoot)
	err := cmd.Run()
	if err != nil {
		return err
	}
	return nil
}

func tearDown() error {
	cmd := exec.Command("dmsetup", "remove", poolName)
	err := cmd.Run()
	if err != nil {
		return err
	}
	cmd = exec.Command("rm", "-rf", devRoot)
	err = cmd.Run()
	if err != nil {
		return err
	}
	return nil
}

func TestMain(m *testing.M) {
	err := setUp()
	if err != nil {
		fmt.Println("Failed to setup due to ", err)
		os.Exit(-1)
	}

	errCode := m.Run()

	err = tearDown()
	if err != nil {
		fmt.Println("Failed to tear down due to ", err)
		os.Exit(-1)
	}

	os.Exit(errCode)
}

func TestInit(t *testing.T) {
	config := make(map[string]string)

	_, err := Init(devRoot, config)
	assert.NotNil(t, err)
	assert.Equal(t, err.Error(), "data device or metadata device unspecified")

	config[DM_DATA_DEV] = dataDev
	config[DM_METADATA_DEV] = metadataDev
	config[DM_THINPOOL_BLOCK_SIZE] = "100"
	_, err = Init(devRoot, config)
	assert.NotNil(t, err)
	assert.True(t, strings.HasPrefix(err.Error(), "Block size must"))

	config[DM_THINPOOL_NAME] = "test_pool"
	delete(config, DM_THINPOOL_BLOCK_SIZE)

	driver, err := Init(devRoot, config)
	assert.Nil(t, err)

	newDriver, err := Init(devRoot, config)
	assert.Nil(t, err)

	drv1, ok := driver.(*Driver)
	assert.True(t, ok)
	drv2, ok := newDriver.(*Driver)
	assert.True(t, ok)

	if !reflect.DeepEqual(*drv1, *drv2) {
		t.Fatal("Fail to verify the information from driver config")
	}

	assert.Equal(t, drv1.configFile, devRoot+"/devicemapper.cfg")

	assert.Equal(t, drv1.DataDevice, dataDev)
	assert.Equal(t, drv1.MetadataDevice, metadataDev)
}

func TestVolumeCreate(t *testing.T) {
}
<commit_msg>Add test cases for volume and snapshot<commit_after>// +build linux
package devmapper

import (
	"code.google.com/p/go-uuid/uuid"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/stretchr/testify/require"
	"os"
	"os/exec"
	"reflect"
	"strings"
	"testing"
)

const (
	dataDev     = "/dev/loop0"
	metadataDev = "/dev/loop1"
	poolName    = "test_pool"
	devRoot     = "/tmp/devmapper"
	volumeSize  = 1 << 27
)

func setUp() error {
	log.SetLevel(log.DebugLevel)
	log.SetOutput(os.Stderr)

	cmd := exec.Command("mkdir", "-p", devRoot)
	err := cmd.Run()
	if err != nil {
		return err
	}
	return nil
}

func tearDown() error {
	cmd := exec.Command("rm", "-rf", devRoot)
	err := cmd.Run()
	if err != nil {
		return err
	}
	cmd = exec.Command("dmsetup", "remove", poolName)
	err = cmd.Run()
	if err != nil {
		return err
	}
	return nil
}

func TestMain(m *testing.M) {
	err := setUp()
	if err != nil {
		fmt.Println("Failed to setup due to ", err)
		os.Exit(-1)
	}

	errCode := m.Run()

	err = tearDown()
	if err != nil {
		fmt.Println("Failed to tear down due to ", err)
		os.Exit(-1)
	}

	os.Exit(errCode)
}

func TestInit(t *testing.T) {
	config := make(map[string]string)

	_, err := Init(devRoot, config)
	require.NotNil(t, err)
	require.Equal(t, err.Error(), "data device or metadata device unspecified")

	config[DM_DATA_DEV] = dataDev
	config[DM_METADATA_DEV] = metadataDev
	config[DM_THINPOOL_BLOCK_SIZE] = "100"
	_, err = Init(devRoot, config)
	require.NotNil(t, err)
	require.True(t, strings.HasPrefix(err.Error(), "Block size must"))

	config[DM_THINPOOL_NAME] = "test_pool"
	delete(config, DM_THINPOOL_BLOCK_SIZE)

	driver, err := Init(devRoot, config)
	require.Nil(t, err)

	newDriver, err := Init(devRoot, config)
	require.Nil(t, err)

	drv1, ok := driver.(*Driver)
	require.True(t, ok)
	drv2, ok := newDriver.(*Driver)
	require.True(t, ok)

	if !reflect.DeepEqual(*drv1, *drv2) {
		t.Fatal("Fail to verify the information from driver config")
	}

	require.Equal(t, drv1.configFile, devRoot+"/devicemapper.cfg")

	require.Equal(t, drv1.DataDevice, dataDev)
	require.Equal(t, drv1.MetadataDevice, metadataDev)
}

func TestVolume(t *testing.T) {
	driver, err := Init(devRoot, nil)
	require.Nil(t, err)

	drv := driver.(*Driver)
	lastDevId := drv.LastDevId
	volumeId := uuid.New()
	err = driver.CreateVolume(volumeId, "", volumeSize)
	require.Nil(t, err)

	require.Equal(t, drv.LastDevId, lastDevId+1)

	volumeId2 := uuid.New()

	err = driver.CreateVolume(volumeId2, "", volumeSize)
	require.Nil(t, err)

	err = driver.ListVolumes()
	require.Nil(t, err)

	err = driver.DeleteVolume(volumeId2)
	require.Nil(t, err)

	err = driver.DeleteVolume(volumeId)
	require.Nil(t, err)
}

func TestSnapshot(t *testing.T) {
	driver, err := Init(devRoot, nil)
	require.Nil(t, err)

	volumeId := uuid.New()
	err = driver.CreateVolume(volumeId, "", volumeSize)
	require.Nil(t, err)

	snapshotId := uuid.New()
	err = driver.CreateSnapshot(snapshotId, volumeId)
	require.Nil(t, err)

	snapshotId2 := uuid.New()
	err = driver.CreateSnapshot(snapshotId2, volumeId)
	require.Nil(t, err)

	err = driver.ListSnapshot("")
	require.Nil(t, err)

	err = driver.ListSnapshot(volumeId)
	require.Nil(t, err)

	err = driver.DeleteSnapshot(snapshotId, volumeId)
	require.Nil(t, err)

	err = driver.DeleteVolume(volumeId)
	require.NotNil(t, err)
	require.True(t, strings.HasSuffix(err.Error(), "delete snapshots first"))

	err = driver.DeleteSnapshot(snapshotId2, volumeId)
	require.Nil(t, err)

	err = driver.DeleteVolume(volumeId)
	require.Nil(t, err)

}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"log"
	"strings"
	"time"

	"github.com/Xe/x/web/tokiponatokens"
)

const (
	actionFront  = "lawa,insa"
	actionMarkov = "sitelen"
	actionWhat   = "seme"
)

var (
	ErrUnknownAction = errors.New("ijo-kesi: unknown action")
)

type Request struct {
	Address []string
	Action  string
	Subject string
	Punct   string
}

func parseRequest(inp tokiponatokens.Sentence) (*Request, error) {
	var result Request

	for _, part := range inp {
		log.Printf("%s", part)
		switch part.Type {
		case tokiponatokens.PartAddress:
			for i, pt := range part.Parts {
				if i == 0 {
					result.Address = append(result.Address, pt.Tokens[0])
					continue
				}

				result.Address = append(result.Address, strings.Title(strings.Join(pt.Tokens, "")))
			}
		case tokiponatokens.PartSubject:
			if len(part.Tokens) == 0 {
				sub := strings.Title(strings.Join(part.Parts[1].Tokens, ""))
				result.Subject = sub
			} else {
				sub := strings.Join(part.Tokens, " ")
				result.Subject = sub
			}
		case tokiponatokens.PartObjectMarker:
			act := strings.Join(part.Tokens, ",")

			switch act {
			case actionFront, actionWhat, actionMarkov:
			default:
				return nil, ErrUnknownAction
			}

			result.Action = act
		case tokiponatokens.PartPunctuation:
			result.Punct = part.Tokens[0]
		}
	}

	return &result, nil
}

func TimeToQualifier(t time.Time) string {
	const (
		nowRange = 15 * time.Minute
	)

	s := time.Since(t)
	if s > 0 {
		return "tenpo kama"
	}

	if s < nowRange {
		return "tenpo ni"
	}

	return "tenpo pini"
}
<commit_msg>ilo-kesi: toki ala e sitelen pi toki pona pali<commit_after>package main

import (
	"errors"
	"strings"
	"time"

	"github.com/Xe/x/web/tokiponatokens"
)

const (
	actionFront  = "lawa,insa"
	actionMarkov = "sitelen"
	actionWhat   = "seme"
)

var (
	ErrUnknownAction = errors.New("ijo-kesi: unknown action")
)

type Request struct {
	Address []string
	Action  string
	Subject string
	Punct   string
}

func parseRequest(inp tokiponatokens.Sentence) (*Request, error) {
	var result Request

	for _, part := range inp {
		switch part.Type {
		case tokiponatokens.PartAddress:
			for i, pt := range part.Parts {
				if i == 0 {
					result.Address = append(result.Address, pt.Tokens[0])
					continue
				}

				result.Address = append(result.Address, strings.Title(strings.Join(pt.Tokens, "")))
			}
		case tokiponatokens.PartSubject:
			if len(part.Tokens) == 0 {
				sub := strings.Title(strings.Join(part.Parts[1].Tokens, ""))
				result.Subject = sub
			} else {
				sub := strings.Join(part.Tokens, " ")
				result.Subject = sub
			}
		case tokiponatokens.PartObjectMarker:
			act := strings.Join(part.Tokens, ",")

			switch act {
			case actionFront, actionWhat, actionMarkov:
			default:
				return nil, ErrUnknownAction
			}

			result.Action = act
		case tokiponatokens.PartPunctuation:
			result.Punct = part.Tokens[0]
		}
	}

	return &result, nil
}

func TimeToQualifier(t time.Time) string {
	const (
		nowRange = 15 * time.Minute
	)

	s := time.Since(t)
	if s > 0 {
		return "tenpo kama"
	}

	if s < nowRange {
		return "tenpo ni"
	}

	return "tenpo pini"
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package fake

import (
	"fmt"

	openapi_v2 "github.com/googleapis/gnostic/openapiv2"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/version"
	kubeversion "k8s.io/client-go/pkg/version"
	restclient "k8s.io/client-go/rest"
	"k8s.io/client-go/testing"
)

// FakeDiscovery implements discovery.DiscoveryInterface and sometimes calls testing.Fake.Invoke with an action,
// but doesn't respect the return value if any. There is a way to fake static values like ServerVersion by using the Faked... fields on the struct.
type FakeDiscovery struct {
	*testing.Fake
	FakedServerVersion *version.Info
}

// ServerResourcesForGroupVersion returns the supported resources for a group
// and version.
func (c *FakeDiscovery) ServerResourcesForGroupVersion(groupVersion string) (*metav1.APIResourceList, error) {
	action := testing.ActionImpl{
		Verb:     "get",
		Resource: schema.GroupVersionResource{Resource: "resource"},
	}
	c.Invokes(action, nil)
	for _, resourceList := range c.Resources {
		if resourceList.GroupVersion == groupVersion {
			return resourceList, nil
		}
	}
	return nil, fmt.Errorf("GroupVersion %q not found", groupVersion)
}

// ServerResources returns the supported resources for all groups and versions.
// Deprecated: use ServerGroupsAndResources instead.
func (c *FakeDiscovery) ServerResources() ([]*metav1.APIResourceList, error) {
	_, rs, err := c.ServerGroupsAndResources()
	return rs, err
}

// ServerGroupsAndResources returns the supported groups and resources for all groups and versions.
func (c *FakeDiscovery) ServerGroupsAndResources() ([]*metav1.APIGroup, []*metav1.APIResourceList, error) {
	sgs, err := c.ServerGroups()
	if err != nil {
		return nil, nil, err
	}
	resultGroups := []*metav1.APIGroup{}
	for i := range sgs.Groups {
		resultGroups = append(resultGroups, &sgs.Groups[i])
	}

	action := testing.ActionImpl{
		Verb:     "get",
		Resource: schema.GroupVersionResource{Resource: "resource"},
	}
	c.Invokes(action, nil)
	return resultGroups, c.Resources, nil
}

// ServerPreferredResources returns the supported resources with the version
// preferred by the server.
func (c *FakeDiscovery) ServerPreferredResources() ([]*metav1.APIResourceList, error) {
	return nil, nil
}

// ServerPreferredNamespacedResources returns the supported namespaced resources
// with the version preferred by the server.
func (c *FakeDiscovery) ServerPreferredNamespacedResources() ([]*metav1.APIResourceList, error) {
	return nil, nil
}

// ServerGroups returns the supported groups, with information like supported
// versions and the preferred version.
func (c *FakeDiscovery) ServerGroups() (*metav1.APIGroupList, error) {
	action := testing.ActionImpl{
		Verb:     "get",
		Resource: schema.GroupVersionResource{Resource: "group"},
	}
	c.Invokes(action, nil)

	groups := map[string]*metav1.APIGroup{}

	for _, res := range c.Resources {
		gv, err := schema.ParseGroupVersion(res.GroupVersion)
		if err != nil {
			return nil, err
		}
		group := groups[gv.Group]
		if group == nil {
			group = &metav1.APIGroup{
				Name: gv.Group,
				PreferredVersion: metav1.GroupVersionForDiscovery{
					GroupVersion: res.GroupVersion,
					Version:      gv.Version,
				},
			}
			groups[gv.Group] = group
		}

		group.Versions = append(group.Versions, metav1.GroupVersionForDiscovery{
			GroupVersion: res.GroupVersion,
			Version:      gv.Version,
		})
	}

	list := &metav1.APIGroupList{}
	for _, apiGroup := range groups {
		list.Groups = append(list.Groups, *apiGroup)
	}

	return list, nil

}

// ServerVersion retrieves and parses the server's version.
func (c *FakeDiscovery) ServerVersion() (*version.Info, error) {
	action := testing.ActionImpl{}
	action.Verb = "get"
	action.Resource = schema.GroupVersionResource{Resource: "version"}
	c.Invokes(action, nil)

	if c.FakedServerVersion != nil {
		return c.FakedServerVersion, nil
	}

	versionInfo := kubeversion.Get()
	return &versionInfo, nil
}

// OpenAPISchema retrieves and parses the swagger API schema the server supports.
func (c *FakeDiscovery) OpenAPISchema() (*openapi_v2.Document, error) {
	return &openapi_v2.Document{}, nil
}

// RESTClient returns a RESTClient that is used to communicate with API server
// by this client implementation.
func (c *FakeDiscovery) RESTClient() restclient.Interface {
	return nil
}
<commit_msg>Return StatusError 404 in fake client when resource is not found<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package fake

import (
	"fmt"
	"net/http"

	openapi_v2 "github.com/googleapis/gnostic/openapiv2"

	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/version"
	kubeversion "k8s.io/client-go/pkg/version"
	restclient "k8s.io/client-go/rest"
	"k8s.io/client-go/testing"
)

// FakeDiscovery implements discovery.DiscoveryInterface and sometimes calls testing.Fake.Invoke with an action,
// but doesn't respect the return value if any. There is a way to fake static values like ServerVersion by using the Faked... fields on the struct.
type FakeDiscovery struct {
	*testing.Fake
	FakedServerVersion *version.Info
}

// ServerResourcesForGroupVersion returns the supported resources for a group
// and version.
func (c *FakeDiscovery) ServerResourcesForGroupVersion(groupVersion string) (*metav1.APIResourceList, error) {
	action := testing.ActionImpl{
		Verb:     "get",
		Resource: schema.GroupVersionResource{Resource: "resource"},
	}
	c.Invokes(action, nil)
	for _, resourceList := range c.Resources {
		if resourceList.GroupVersion == groupVersion {
			return resourceList, nil
		}
	}
	return nil, &errors.StatusError{
		ErrStatus: metav1.Status{
			Status:  metav1.StatusFailure,
			Code:    http.StatusNotFound,
			Reason:  metav1.StatusReasonNotFound,
			Message: fmt.Sprintf("the server could not find the requested resource, GroupVersion %q not found", groupVersion),
		}}
}

// ServerResources returns the supported resources for all groups and versions.
// Deprecated: use ServerGroupsAndResources instead.
func (c *FakeDiscovery) ServerResources() ([]*metav1.APIResourceList, error) {
	_, rs, err := c.ServerGroupsAndResources()
	return rs, err
}

// ServerGroupsAndResources returns the supported groups and resources for all groups and versions.
func (c *FakeDiscovery) ServerGroupsAndResources() ([]*metav1.APIGroup, []*metav1.APIResourceList, error) {
	sgs, err := c.ServerGroups()
	if err != nil {
		return nil, nil, err
	}
	resultGroups := []*metav1.APIGroup{}
	for i := range sgs.Groups {
		resultGroups = append(resultGroups, &sgs.Groups[i])
	}

	action := testing.ActionImpl{
		Verb:     "get",
		Resource: schema.GroupVersionResource{Resource: "resource"},
	}
	c.Invokes(action, nil)
	return resultGroups, c.Resources, nil
}

// ServerPreferredResources returns the supported resources with the version
// preferred by the server.
func (c *FakeDiscovery) ServerPreferredResources() ([]*metav1.APIResourceList, error) {
	return nil, nil
}

// ServerPreferredNamespacedResources returns the supported namespaced resources
// with the version preferred by the server.
func (c *FakeDiscovery) ServerPreferredNamespacedResources() ([]*metav1.APIResourceList, error) {
	return nil, nil
}

// ServerGroups returns the supported groups, with information like supported
// versions and the preferred version.
func (c *FakeDiscovery) ServerGroups() (*metav1.APIGroupList, error) {
	action := testing.ActionImpl{
		Verb:     "get",
		Resource: schema.GroupVersionResource{Resource: "group"},
	}
	c.Invokes(action, nil)

	groups := map[string]*metav1.APIGroup{}

	for _, res := range c.Resources {
		gv, err := schema.ParseGroupVersion(res.GroupVersion)
		if err != nil {
			return nil, err
		}
		group := groups[gv.Group]
		if group == nil {
			group = &metav1.APIGroup{
				Name: gv.Group,
				PreferredVersion: metav1.GroupVersionForDiscovery{
					GroupVersion: res.GroupVersion,
					Version:      gv.Version,
				},
			}
			groups[gv.Group] = group
		}

		group.Versions = append(group.Versions, metav1.GroupVersionForDiscovery{
			GroupVersion: res.GroupVersion,
			Version:      gv.Version,
		})
	}

	list := &metav1.APIGroupList{}
	for _, apiGroup := range groups {
		list.Groups = append(list.Groups, *apiGroup)
	}

	return list, nil

}

// ServerVersion retrieves and parses the server's version.
func (c *FakeDiscovery) ServerVersion() (*version.Info, error) {
	action := testing.ActionImpl{}
	action.Verb = "get"
	action.Resource = schema.GroupVersionResource{Resource: "version"}
	c.Invokes(action, nil)

	if c.FakedServerVersion != nil {
		return c.FakedServerVersion, nil
	}

	versionInfo := kubeversion.Get()
	return &versionInfo, nil
}

// OpenAPISchema retrieves and parses the swagger API schema the server supports.
func (c *FakeDiscovery) OpenAPISchema() (*openapi_v2.Document, error) {
	return &openapi_v2.Document{}, nil
}

// RESTClient returns a RESTClient that is used to communicate with API server
// by this client implementation.
func (c *FakeDiscovery) RESTClient() restclient.Interface {
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"os/signal"

	"code.google.com/p/go-imap/go1/imap"
	"code.google.com/p/gopass"
)

var (
	login   = flag.String("login", "", "Your login")
	mailbox = flag.String("mailbox", "[Gmail]/All Mail", "The mailbox to watch")
	server  = flag.String("server", "imap.gmail.com", "Your IMAP server with TLS")
)

func main() {
	flag.Parse()
	if *login == "" {
		fmt.Println("I need at least your login!\n")
		flag.Usage()
		os.Exit(1)
	}

	pass, err := gopass.GetPass("Password: ")
	if err != nil {
		log.Fatal(err)
	}

	quit := make(chan os.Signal)
	signal.Notify(quit, os.Interrupt, os.Kill)
	go func() {
		<-quit
		os.Exit(0)
	}()

	for {
		c, err := imap.DialTLS(*server, &tls.Config{})
		if err != nil {
			log.Fatal(err)
		}

		_, err = c.Auth(imap.PlainAuth(*login, pass, ""))
		if err != nil {
			log.Fatal(err)
		}

		log.Println("Successfully authed")

		cmd, err := c.Select(*mailbox, true)
		if err != nil {
			log.Println("select")
			log.Fatal(err)
		}
		if _, err = cmd.Result(imap.OK); err != nil {
			log.Fatal(err)
		}

		log.Println("Successfully selected ", *mailbox)

		cmd, err = c.Idle()
		if err != nil {
			log.Fatal(err)
		}

		log.Println("Starting idle...")
		c.Data = nil

		for cmd.InProgress() {
			err := c.Recv(-1)
			if err != nil {
				if err != io.EOF {
					log.Println(err)
				}
				break
			}

			for _, rsp := range c.Data {
				if rsp.Label == "EXISTS" {
					log.Println("New message, running sync...")
					cmd := exec.Command("offlineimap", "-u", "Quiet")
					cmd.Stdout = os.Stderr
					cmd.Stderr = os.Stderr
					err := cmd.Run()
					if err != nil {
						log.Printf("Error running sync: %s\n", err)
					}
					log.Println("Ran sync")
				}
			}

			c.Data = nil
		}
	}
}
<commit_msg>Be resilient to all network/timeout problems<commit_after>package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"time"

	"code.google.com/p/go-imap/go1/imap"
	"code.google.com/p/gopass"
)

var (
	login   = flag.String("login", "", "Your login")
	mailbox = flag.String("mailbox", "[Gmail]/All Mail", "The mailbox to watch")
	server  = flag.String("server", "imap.gmail.com", "Your IMAP server with TLS")
)

func main() {
	flag.Parse()
	if *login == "" {
		fmt.Println("I need at least your login!\n")
		flag.Usage()
		os.Exit(1)
	}

	pass, err := gopass.GetPass("Password: ")
	if err != nil {
		log.Fatal(err)
	}

	quit := make(chan os.Signal)
	signal.Notify(quit, os.Interrupt, os.Kill)
	go func() {
		<-quit
		os.Exit(0)
	}()

	connect := func(server string) (c *imap.Client, err error) {
		c, err = imap.DialTLS(server, &tls.Config{})
		if err != nil {
			return
		}

		_, err = c.Auth(imap.PlainAuth(*login, pass, ""))
		if err != nil {
			return
		}

		log.Println("Successfully authed")

		cmd, err := c.Select(*mailbox, true)
		if err != nil {
			log.Println("Error selecting mailbox: ", err)
			return
		}
		_, err = cmd.Result(imap.OK)
		if err != nil {
			return
		}

		log.Println("Successfully selected ", *mailbox)

		_, err = c.Idle()
		if err != nil {
			return
		}

		log.Println("Starting idle...")
		c.Data = nil

		return
	}

loop:
	for {
		c, err := connect(*server)
		if err != nil {
			continue
		}

	recv:
		for {
			err = c.Recv(29 * time.Minute)
			if err != nil {
				switch err {
				case io.EOF:
					log.Println("EOF")
					// "Normal" case: we have finished receiving all remote data
					break recv
				case imap.ErrTimeout:
					_, err = c.IdleTerm()
					if err != nil {
						log.Println(err)
						continue loop
					}

					_, err = c.Idle()
					if err != nil {
						log.Println(err)
						continue loop
					}
				default:
					log.Println("Error while receiving content: ", err)
					continue loop
				}
			}
		}

		for _, rsp := range c.Data {
			if rsp.Label == "EXISTS" {
				log.Println("New message, running sync...")
				cmd := exec.Command("offlineimap", "-u", "Quiet")
				cmd.Stdout = os.Stderr
				cmd.Stderr = os.Stderr
				err := cmd.Run()
				if err != nil {
					log.Printf("Error running sync: %s\n", err)
				}
				log.Println("Ran sync")
			}
		}

		c.Data = nil
	}
}
<|endoftext|>