<commit_before>package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"

	mp "github.com/mackerelio/go-mackerel-plugin-helper"
)

var graphdef map[string](mp.Graphs) = map[string](mp.Graphs){
	"docker.cpuacct.#": mp.Graphs{
		Label: "Docker CPU",
		Unit:  "integer",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "user", Label: "User", Diff: true, Stacked: true, Type: "uint64"},
			mp.Metrics{Name: "system", Label: "System", Diff: true, Stacked: true, Type: "uint64"},
		},
	},
	"docker.memory.#": mp.Graphs{
		Label: "Docker Memory",
		Unit:  "integer",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "cache", Label: "Cache", Diff: false, Stacked: true},
			mp.Metrics{Name: "rss", Label: "RSS", Diff: false, Stacked: true},
		},
	},
	"docker.blkio.io_queued.#": mp.Graphs{
		Label: "Docker BlkIO Queued",
		Unit:  "integer",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "read", Label: "Read", Diff: false, Stacked: true},
			mp.Metrics{Name: "write", Label: "Write", Diff: false, Stacked: true},
			mp.Metrics{Name: "sync", Label: "Sync", Diff: false, Stacked: true},
			mp.Metrics{Name: "async", Label: "Async", Diff: false, Stacked: true},
		},
	},
	"docker.blkio.io_serviced.#": mp.Graphs{
		Label: "Docker BlkIO IOPS",
		Unit:  "integer",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "read", Label: "Read", Diff: true, Stacked: true, Type: "uint64"},
			mp.Metrics{Name: "write", Label: "Write", Diff: true, Stacked: true, Type: "uint64"},
			mp.Metrics{Name: "sync", Label: "Sync", Diff: true, Stacked: true, Type: "uint64"},
			mp.Metrics{Name: "async", Label: "Async", Diff: true, Stacked: true, Type: "uint64"},
		},
	},
	"docker.blkio.io_service_bytes.#": mp.Graphs{
		Label: "Docker BlkIO Bytes",
		Unit:  "integer",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "read", Label: "Read", Diff: true, Stacked: true, Type: "uint64"},
			mp.Metrics{Name: "write", Label: "Write", Diff: true, Stacked: true, Type: "uint64"},
			mp.Metrics{Name: "sync", Label: "Sync", Diff: true, Stacked: true, Type: "uint64"},
			mp.Metrics{Name: "async", Label: "Async", Diff: true, Stacked: true, Type: "uint64"},
		},
	},
}

type DockerPlugin struct {
	Host          string
	DockerCommand string
	Tempfile      string
	pathBuilder   *pathBuilder
}

func getFile(path string) (string, error) {
	cmd := exec.Command("cat", path)
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		return "", err
	}
	return out.String(), nil
}

func exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return true, err
}

var normalizeMetricRe = regexp.MustCompile(`[^-a-zA-Z0-9_]`)

func normalizeMetricName(str string) string {
	return normalizeMetricRe.ReplaceAllString(str, "_")
}

func (m DockerPlugin) getDockerPs() (string, error) {
	cmd := exec.Command(m.DockerCommand, "--host", m.Host, "ps", "--no-trunc")
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		return "", err
	}
	return out.String(), nil
}

func findPrefixPath() (string, error) {
	pathCandidate := []string{"/host/cgroup/", "/cgroup", "/host/sys/fs/cgroup", "/sys/fs/cgroup"}
	for _, path := range pathCandidate {
		result, err := exists(path)
		if err != nil {
			return "", err
		}
		if result {
			return path, nil
		}
	}
	return "", errors.New("No prefix path is found.")
}

type pathBuilder struct {
	prefix   string
	pathType pathType
}

type pathType uint8

const (
	pathUnknown pathType = iota
	pathDocker
	pathLxc
	pathSlice
)

func newPathBuilder() (*pathBuilder, error) {
	prefixPath, err := findPrefixPath()
	if err != nil {
		return nil, err
	}
	pathT, err := guessPathType(prefixPath)
	if err != nil {
		return nil, err
	}
	return &pathBuilder{
		prefix:   prefixPath,
		pathType: pathT,
	}, nil
}

func (pb *pathBuilder) build(id, metric, postfix string) string {
	switch pb.pathType {
	case pathDocker:
		return fmt.Sprintf("%s/%s/docker/%s/%s.%s", pb.prefix, metric, id, metric, postfix)
	case pathLxc:
		return fmt.Sprintf("%s/%s/lxc/%s/%s.%s", pb.prefix, metric, id, metric, postfix)
	case pathSlice:
		return fmt.Sprintf("%s/%s/system.slice/docker-%s.scope/%s.%s", pb.prefix, metric, id, metric, postfix)
	default:
		return ""
	}
}

func guessPathType(prefix string) (pathType, error) {
	if ok, err := exists(prefix + "/memory/system.slice/"); ok && err == nil {
		return pathSlice, nil
	}
	if ok, err := exists(prefix + "/memory/docker/"); ok && err == nil {
		return pathDocker, nil
	}
	if ok, err := exists(prefix + "/memory/lxc/"); ok && err == nil {
		return pathLxc, nil
	}
	return pathUnknown, fmt.Errorf("can't resolve runtime metrics path")
}

func (m DockerPlugin) FetchMetrics() (map[string]interface{}, error) {
	dockerStats := map[string][]string{}
	data, err := m.getDockerPs()
	if err != nil {
		return nil, err
	}
	lines := strings.Split(data, "\n")
	for n, line := range lines {
		if n == 0 {
			continue
		}
		fields := regexp.MustCompile(" +").Split(line, -1)
		if len(fields) > 3 {
			dockerStats[fields[0]] = []string{fields[1], fields[len(fields)-2]}
		}
	}
	pb := m.pathBuilder

	metrics := map[string][]string{
		"cpuacct": []string{"user", "system"},
		"memory":  []string{"cache", "rss"},
	}

	res := map[string]interface{}{}
	for id, name := range dockerStats {
		for metric, stats := range metrics {
			ret, err := exists(pb.build(id, metric, "stat"))
			if ret == false {
				continue
			}
			data, err := getFile(pb.build(id, metric, "stat"))
			if err != nil {
				return nil, err
			}
			for _, stat := range stats {
				re := regexp.MustCompile(stat + " (\\d+)")
				m := re.FindStringSubmatch(data)
				if m != nil {
					res[fmt.Sprintf("docker.%s.%s_%s.%s", metric, normalizeMetricName(name[0]), id[0:6], stat)] = m[1]
				}
			}
		}

		// blkio statistics
		for _, blkioType := range []string{"io_queued", "io_serviced", "io_service_bytes"} {
			ret, err := exists(pb.build(id, "blkio", blkioType))
			if ret == false {
				continue
			}
			data, err := getFile(pb.build(id, "blkio", blkioType))
			if err != nil {
				return nil, err
			}
			for _, stat := range []string{"Read", "Write", "Sync", "Async"} {
				re := regexp.MustCompile(stat + " (\\d+)")
				matchs := re.FindAllStringSubmatch(data, -1)
				v := 0.0
				for _, m := range matchs {
					if m != nil {
						ret, _ := strconv.ParseFloat(m[1], 64)
						v += ret
					}
				}
				res[fmt.Sprintf("docker.blkio.%s.%s_%s.%s", blkioType, normalizeMetricName(name[0]), id[0:6], strings.ToLower(stat))] = v
			}
		}

	}

	return res, nil
}

func (m DockerPlugin) GraphDefinition() map[string](mp.Graphs) {
	return graphdef
}

func main() {
	optHost := flag.String("host", "unix:///var/run/docker.sock", "Host for socket")
	optCommand := flag.String("command", "docker", "Command path to docker")
	optTempfile := flag.String("tempfile", "", "Temp file name")
	flag.Parse()

	var docker DockerPlugin

	docker.Host = fmt.Sprintf("%s", *optHost)
	docker.DockerCommand = *optCommand
	_, err := exec.LookPath(docker.DockerCommand)
	if err != nil {
		log.Fatalf("Docker command is not found: %s", docker.DockerCommand)
	}

	pb, err := newPathBuilder()
	if err != nil {
		log.Fatalf("failed to resolve docker metrics path: %s. It may be no Docker containers exists.", err)
	}
	docker.pathBuilder = pb

	helper := mp.NewMackerelPlugin(docker)

	if *optTempfile != "" {
		helper.Tempfile = *optTempfile
	} else {
		helper.Tempfile = fmt.Sprintf("/tmp/mackerel-plugin-docker-%s", normalizeMetricName(*optHost))
	}

	if os.Getenv("MACKEREL_AGENT_PLUGIN_META") != "" {
		helper.OutputDefinitions()
	} else {
		helper.OutputValues()
	}
}
<commit_msg>make checking existances of statistics files better<commit_after>package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"

	mp "github.com/mackerelio/go-mackerel-plugin-helper"
)

var graphdef map[string](mp.Graphs) = map[string](mp.Graphs){
	"docker.cpuacct.#": mp.Graphs{
		Label: "Docker CPU",
		Unit:  "integer",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "user", Label: "User", Diff: true, Stacked: true, Type: "uint64"},
			mp.Metrics{Name: "system", Label: "System", Diff: true, Stacked: true, Type: "uint64"},
		},
	},
	"docker.memory.#": mp.Graphs{
		Label: "Docker Memory",
		Unit:  "integer",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "cache", Label: "Cache", Diff: false, Stacked: true},
			mp.Metrics{Name: "rss", Label: "RSS", Diff: false, Stacked: true},
		},
	},
	"docker.blkio.io_queued.#": mp.Graphs{
		Label: "Docker BlkIO Queued",
		Unit:  "integer",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "read", Label: "Read", Diff: false, Stacked: true},
			mp.Metrics{Name: "write", Label: "Write", Diff: false, Stacked: true},
			mp.Metrics{Name: "sync", Label: "Sync", Diff: false, Stacked: true},
			mp.Metrics{Name: "async", Label: "Async", Diff: false, Stacked: true},
		},
	},
	"docker.blkio.io_serviced.#": mp.Graphs{
		Label: "Docker BlkIO IOPS",
		Unit:  "integer",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "read", Label: "Read", Diff: true, Stacked: true, Type: "uint64"},
			mp.Metrics{Name: "write", Label: "Write", Diff: true, Stacked: true, Type: "uint64"},
			mp.Metrics{Name: "sync", Label: "Sync", Diff: true, Stacked: true, Type: "uint64"},
			mp.Metrics{Name: "async", Label: "Async", Diff: true, Stacked: true, Type: "uint64"},
		},
	},
	"docker.blkio.io_service_bytes.#": mp.Graphs{
		Label: "Docker BlkIO Bytes",
		Unit:  "integer",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "read", Label: "Read", Diff: true, Stacked: true, Type: "uint64"},
			mp.Metrics{Name: "write", Label: "Write", Diff: true, Stacked: true, Type: "uint64"},
			mp.Metrics{Name: "sync", Label: "Sync", Diff: true, Stacked: true, Type: "uint64"},
			mp.Metrics{Name: "async", Label: "Async", Diff: true, Stacked: true, Type: "uint64"},
		},
	},
}

type DockerPlugin struct {
	Host          string
	DockerCommand string
	Tempfile      string
	pathBuilder   *pathBuilder
}

func getFile(path string) (string, error) {
	cmd := exec.Command("cat", path)
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		return "", err
	}
	return out.String(), nil
}

func exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return true, err
}

var normalizeMetricRe = regexp.MustCompile(`[^-a-zA-Z0-9_]`)

func normalizeMetricName(str string) string {
	return normalizeMetricRe.ReplaceAllString(str, "_")
}

func (m DockerPlugin) getDockerPs() (string, error) {
	cmd := exec.Command(m.DockerCommand, "--host", m.Host, "ps", "--no-trunc")
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		return "", err
	}
	return out.String(), nil
}

func findPrefixPath() (string, error) {
	pathCandidate := []string{"/host/cgroup/", "/cgroup", "/host/sys/fs/cgroup", "/sys/fs/cgroup"}
	for _, path := range pathCandidate {
		result, err := exists(path)
		if err != nil {
			return "", err
		}
		if result {
			return path, nil
		}
	}
	return "", errors.New("No prefix path is found.")
}

type pathBuilder struct {
	prefix   string
	pathType pathType
}

type pathType uint8

const (
	pathUnknown pathType = iota
	pathDocker
	pathLxc
	pathSlice
)

func newPathBuilder() (*pathBuilder, error) {
	prefixPath, err := findPrefixPath()
	if err != nil {
		return nil, err
	}
	pathT, err := guessPathType(prefixPath)
	if err != nil {
		return nil, err
	}
	return &pathBuilder{
		prefix:   prefixPath,
		pathType: pathT,
	}, nil
}

func (pb *pathBuilder) build(id, metric, postfix string) string {
	switch pb.pathType {
	case pathDocker:
		return fmt.Sprintf("%s/%s/docker/%s/%s.%s", pb.prefix, metric, id, metric, postfix)
	case pathLxc:
		return fmt.Sprintf("%s/%s/lxc/%s/%s.%s", pb.prefix, metric, id, metric, postfix)
	case pathSlice:
		return fmt.Sprintf("%s/%s/system.slice/docker-%s.scope/%s.%s", pb.prefix, metric, id, metric, postfix)
	default:
		return ""
	}
}

func guessPathType(prefix string) (pathType, error) {
	if ok, err := exists(prefix + "/memory/system.slice/"); ok && err == nil {
		return pathSlice, nil
	}
	if ok, err := exists(prefix + "/memory/docker/"); ok && err == nil {
		return pathDocker, nil
	}
	if ok, err := exists(prefix + "/memory/lxc/"); ok && err == nil {
		return pathLxc, nil
	}
	return pathUnknown, fmt.Errorf("can't resolve runtime metrics path")
}

func (m DockerPlugin) FetchMetrics() (map[string]interface{}, error) {
	dockerStats := map[string][]string{}
	data, err := m.getDockerPs()
	if err != nil {
		return nil, err
	}
	lines := strings.Split(data, "\n")
	for n, line := range lines {
		if n == 0 {
			continue
		}
		fields := regexp.MustCompile(" +").Split(line, -1)
		if len(fields) > 3 {
			dockerStats[fields[0]] = []string{fields[1], fields[len(fields)-2]}
		}
	}
	pb := m.pathBuilder

	metrics := map[string][]string{
		"cpuacct": []string{"user", "system"},
		"memory":  []string{"cache", "rss"},
	}

	res := map[string]interface{}{}
	for id, name := range dockerStats {
		for metric, stats := range metrics {
			if ok, err := exists(pb.build(id, metric, "stat")); !ok || err != nil {
				continue
			}
			data, err := getFile(pb.build(id, metric, "stat"))
			if err != nil {
				return nil, err
			}
			for _, stat := range stats {
				re := regexp.MustCompile(stat + " (\\d+)")
				m := re.FindStringSubmatch(data)
				if m != nil {
					res[fmt.Sprintf("docker.%s.%s_%s.%s", metric, normalizeMetricName(name[0]), id[0:6], stat)] = m[1]
				}
			}
		}

		// blkio statistics
		for _, blkioType := range []string{"io_queued", "io_serviced", "io_service_bytes"} {
			if ok, err := exists(pb.build(id, "blkio", blkioType)); !ok || err != nil {
				continue
			}
			data, err := getFile(pb.build(id, "blkio", blkioType))
			if err != nil {
				return nil, err
			}
			for _, stat := range []string{"Read", "Write", "Sync", "Async"} {
				re := regexp.MustCompile(stat + " (\\d+)")
				matchs := re.FindAllStringSubmatch(data, -1)
				v := 0.0
				for _, m := range matchs {
					if m != nil {
						ret, _ := strconv.ParseFloat(m[1], 64)
						v += ret
					}
				}
				res[fmt.Sprintf("docker.blkio.%s.%s_%s.%s", blkioType, normalizeMetricName(name[0]), id[0:6], strings.ToLower(stat))] = v
			}
		}

	}

	return res, nil
}

func (m DockerPlugin) GraphDefinition() map[string](mp.Graphs) {
	return graphdef
}

func main() {
	optHost := flag.String("host", "unix:///var/run/docker.sock", "Host for socket")
	optCommand := flag.String("command", "docker", "Command path to docker")
	optTempfile := flag.String("tempfile", "", "Temp file name")
	flag.Parse()

	var docker DockerPlugin

	docker.Host = fmt.Sprintf("%s", *optHost)
	docker.DockerCommand = *optCommand
	_, err := exec.LookPath(docker.DockerCommand)
	if err != nil {
		log.Fatalf("Docker command is not found: %s", docker.DockerCommand)
	}

	pb, err := newPathBuilder()
	if err != nil {
		log.Fatalf("failed to resolve docker metrics path: %s. It may be no Docker containers exists.", err)
	}
	docker.pathBuilder = pb

	helper := mp.NewMackerelPlugin(docker)

	if *optTempfile != "" {
		helper.Tempfile = *optTempfile
	} else {
		helper.Tempfile = fmt.Sprintf("/tmp/mackerel-plugin-docker-%s", normalizeMetricName(*optHost))
	}

	if os.Getenv("MACKEREL_AGENT_PLUGIN_META") != "" {
		helper.OutputDefinitions()
	} else {
		helper.OutputValues()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/user"
	"syscall"
	"time"

	"github.com/tftp-go-team/hooktftp/src/config"
	"github.com/tftp-go-team/hooktftp/src/hooks"
	"github.com/tftp-go-team/hooktftp/src/logger"
	"github.com/tftp-go-team/libgotftp/src"
)

var HOOKS []hooks.Hook
var CONFIG_PATH string = "/etc/hooktftp.yml"

func handleRRQ(res *tftp.RRQresponse) {

	started := time.Now()

	path := res.Request.Path

	logger.Info(fmt.Sprintf(
		"GET %s blocksize %d from %s",
		path,
		res.Request.Blocksize,
		*res.Request.Addr,
	))

	var outReader, errReader io.ReadCloser
	var len int
	for _, hook := range HOOKS {
		var err error
		outReader, errReader, len, err = hook(res.Request.Path, *res.Request)
		if err == hooks.NO_MATCH {
			continue
		} else if err != nil {

			if err, ok := err.(*os.PathError); ok {
				res.WriteError(tftp.NOT_FOUND, err.Error())
				return
			}

			logger.Err("Failed to execute hook for '%v' error: %v", res.Request.Path, err)
			res.WriteError(tftp.UNKNOWN_ERROR, "Hook failed: "+err.Error())
			return
		}
		defer func() {
			err := outReader.Close()
			if err != nil {
				logger.Err("Failed to close reader for %s: %s", res.Request.Path, err)
			}
		}()
		break
	}

	if errReader != nil {
		go func() {
			defer func() {
				if err := errReader.Close(); err != nil {
					logger.Err("Failed to close error reader for %s: %s", res.Request.Path, err)
				}
			}()

			var bytesRead int
			var err error
			b := make([]byte, 4096)

			for ; err != io.EOF; bytesRead, err = errReader.Read(b) {
				if err != nil {
					logger.Err("Error while reading error reader: %s", err)
					return
				} else if bytesRead > 0 {
					logger.Warning("Hook error: %s", b[:bytesRead])
				}
			}
		}()
	}

	if outReader == nil {
		res.WriteError(tftp.NOT_FOUND, "No hook matches")
		return
	}

	if res.Request.TransferSize != -1 {
		res.TransferSize = len
	}

	if err := res.WriteOACK(); err != nil {
		logger.Err("Failed to write OACK", err)
		return
	}

	b := make([]byte, res.Request.Blocksize)

	totalBytes := 0

	for {
		bytesRead, err := outReader.Read(b)
		totalBytes += bytesRead

		if err == io.EOF {
			if _, err := res.Write(b[:bytesRead]); err != nil {
				logger.Err("Failed to write last bytes of the reader: %s", err)
				return
			}
			res.End()
			break
		} else if err != nil {
			logger.Err("Error while reading %s: %s", outReader, err)
			res.WriteError(tftp.UNKNOWN_ERROR, err.Error())
			return
		}

		if _, err := res.Write(b[:bytesRead]); err != nil {
			logger.Err("Failed to write bytes for %s: %s", path, err)
			return
		}
	}

	took := time.Since(started)

	speed := float64(totalBytes) / took.Seconds() / 1024 / 1024

	logger.Info("Sent %v bytes in %v %f MB/s\n", totalBytes, took, speed)
}

func main() {

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "\nUsage: %s [-v] [config]\n", os.Args[0])
	}
	verbose := flag.Bool("v", false, "a bool")
	flag.Parse()

	if !*verbose {
		e := logger.Initialize("hooktftp")
		if e != nil {
			log.Fatal("Failed to initialize logger")
		}
	}

	if len(flag.Args()) > 0 {
		CONFIG_PATH = flag.Args()[0]
	}

	logger.Info("Reading hooks from %s", CONFIG_PATH)

	configData, err := ioutil.ReadFile(CONFIG_PATH)

	if err != nil {
		logger.Crit("Failed to read config: %s", err)
		return
	}

	conf, err := config.ParseYaml(configData)
	if err != nil {
		logger.Crit("Failed to parse config: %s", err)
		return
	}

	for _, hookDef := range conf.HookDefs {
		logger.Notice("Compiling hook %s", hookDef)

		// Create new hookDef variable for the hookDef pointer for each loop
		// iteration. Go reuses the hookDef variable and if we pass pointer to
		// that terrible things happen.
		newPointer := hookDef
		hook, err := hooks.CompileHook(&newPointer)
		if err != nil {
			logger.Crit("Failed to compile hook %s: %s", hookDef, err)
			return
		}
		HOOKS = append(HOOKS, hook)
	}

	if conf.Port == "" {
		conf.Port = "69"
	}

	addr, err := net.ResolveUDPAddr("udp", conf.Host+":"+conf.Port)
	if err != nil {
		logger.Crit("Failed to resolve address: %s", err)
		return
	}

	server, err := tftp.NewTFTPServer(addr)
	if err != nil {
		logger.Crit("Failed to listen: %s", err)
		return
	}

	logger.Notice("Listening on %s:%d", conf.Host, conf.Port)

	if conf.User != "" {
		err := DropPrivileges(conf.User)
		if err != nil {
			logger.Crit("Failed to drop privileges to '%s' error: %v", conf.User, err)
			return
		}
		currentUser, _ := user.Current()
		logger.Notice("Dropped privileges to %s", currentUser)
	}

	if conf.User == "" && syscall.Getuid() == 0 {
		logger.Warning("Running as root and 'user' is not set in %s", CONFIG_PATH)
	}

	for {
		res, err := server.Accept()
		if err != nil {
			logger.Err("Bad tftp request: %s", err)
			continue
		}

		go handleRRQ(res)
	}

	logger.Close()

}
<commit_msg>When logging hooks stderr, handle potential read error after logging<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/user"
	"syscall"
	"time"

	"github.com/tftp-go-team/hooktftp/src/config"
	"github.com/tftp-go-team/hooktftp/src/hooks"
	"github.com/tftp-go-team/hooktftp/src/logger"
	"github.com/tftp-go-team/libgotftp/src"
)

var HOOKS []hooks.Hook
var CONFIG_PATH string = "/etc/hooktftp.yml"

func handleRRQ(res *tftp.RRQresponse) {

	started := time.Now()

	path := res.Request.Path

	logger.Info(fmt.Sprintf(
		"GET %s blocksize %d from %s",
		path,
		res.Request.Blocksize,
		*res.Request.Addr,
	))

	var outReader, errReader io.ReadCloser
	var len int
	for _, hook := range HOOKS {
		var err error
		outReader, errReader, len, err = hook(res.Request.Path, *res.Request)
		if err == hooks.NO_MATCH {
			continue
		} else if err != nil {

			if err, ok := err.(*os.PathError); ok {
				res.WriteError(tftp.NOT_FOUND, err.Error())
				return
			}

			logger.Err("Failed to execute hook for '%v' error: %v", res.Request.Path, err)
			res.WriteError(tftp.UNKNOWN_ERROR, "Hook failed: "+err.Error())
			return
		}
		defer func() {
			err := outReader.Close()
			if err != nil {
				logger.Err("Failed to close reader for %s: %s", res.Request.Path, err)
			}
		}()
		break
	}

	if errReader != nil {
		go func() {
			defer func() {
				if err := errReader.Close(); err != nil {
					logger.Err("Failed to close error reader for %s: %s", res.Request.Path, err)
				}
			}()

			var bytesRead int
			var err error
			b := make([]byte, 4096)

			for ; err != io.EOF; bytesRead, err = errReader.Read(b) {
				if bytesRead > 0 {
					logger.Warning("Hook error: %s", b[:bytesRead])
				}
				if err != nil {
					logger.Err("Error while reading error reader: %s", err)
					return
				}
			}
		}()
	}

	if outReader == nil {
		res.WriteError(tftp.NOT_FOUND, "No hook matches")
		return
	}

	if res.Request.TransferSize != -1 {
		res.TransferSize = len
	}

	if err := res.WriteOACK(); err != nil {
		logger.Err("Failed to write OACK", err)
		return
	}

	b := make([]byte, res.Request.Blocksize)

	totalBytes := 0

	for {
		bytesRead, err := outReader.Read(b)
		totalBytes += bytesRead

		if err == io.EOF {
			if _, err := res.Write(b[:bytesRead]); err != nil {
				logger.Err("Failed to write last bytes of the reader: %s", err)
				return
			}
			res.End()
			break
		} else if err != nil {
			logger.Err("Error while reading %s: %s", outReader, err)
			res.WriteError(tftp.UNKNOWN_ERROR, err.Error())
			return
		}

		if _, err := res.Write(b[:bytesRead]); err != nil {
			logger.Err("Failed to write bytes for %s: %s", path, err)
			return
		}
	}

	took := time.Since(started)

	speed := float64(totalBytes) / took.Seconds() / 1024 / 1024

	logger.Info("Sent %v bytes in %v %f MB/s\n", totalBytes, took, speed)
}

func main() {

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "\nUsage: %s [-v] [config]\n", os.Args[0])
	}
	verbose := flag.Bool("v", false, "a bool")
	flag.Parse()

	if !*verbose {
		e := logger.Initialize("hooktftp")
		if e != nil {
			log.Fatal("Failed to initialize logger")
		}
	}

	if len(flag.Args()) > 0 {
		CONFIG_PATH = flag.Args()[0]
	}

	logger.Info("Reading hooks from %s", CONFIG_PATH)

	configData, err := ioutil.ReadFile(CONFIG_PATH)

	if err != nil {
		logger.Crit("Failed to read config: %s", err)
		return
	}

	conf, err := config.ParseYaml(configData)
	if err != nil {
		logger.Crit("Failed to parse config: %s", err)
		return
	}

	for _, hookDef := range conf.HookDefs {
		logger.Notice("Compiling hook %s", hookDef)

		// Create new hookDef variable for the hookDef pointer for each loop
		// iteration. Go reuses the hookDef variable and if we pass pointer to
		// that terrible things happen.
		newPointer := hookDef
		hook, err := hooks.CompileHook(&newPointer)
		if err != nil {
			logger.Crit("Failed to compile hook %s: %s", hookDef, err)
			return
		}
		HOOKS = append(HOOKS, hook)
	}

	if conf.Port == "" {
		conf.Port = "69"
	}

	addr, err := net.ResolveUDPAddr("udp", conf.Host+":"+conf.Port)
	if err != nil {
		logger.Crit("Failed to resolve address: %s", err)
		return
	}

	server, err := tftp.NewTFTPServer(addr)
	if err != nil {
		logger.Crit("Failed to listen: %s", err)
		return
	}

	logger.Notice("Listening on %s:%d", conf.Host, conf.Port)

	if conf.User != "" {
		err := DropPrivileges(conf.User)
		if err != nil {
			logger.Crit("Failed to drop privileges to '%s' error: %v", conf.User, err)
			return
		}
		currentUser, _ := user.Current()
		logger.Notice("Dropped privileges to %s", currentUser)
	}

	if conf.User == "" && syscall.Getuid() == 0 {
		logger.Warning("Running as root and 'user' is not set in %s", CONFIG_PATH)
	}

	for {
		res, err := server.Accept()
		if err != nil {
			logger.Err("Bad tftp request: %s", err)
			continue
		}

		go handleRRQ(res)
	}

	logger.Close()

}
<|endoftext|>


<commit_before>package input

import (
	"compress/gzip"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/mcuadros/harvesterd/src/intf"
	. "github.com/mcuadros/harvesterd/src/logger"

	"gopkg.in/amz.v1/aws"
	"gopkg.in/amz.v1/s3"
)

type S3Config struct {
	AccessKey string
	SecretKey string
	Region    string
	Bucket    string
	Format    string `description:"A valid format name."`
	Prefix    string `description:"Limits the response to keys that begin with the specified prefix."`
	Delimiter string `description:"A delimiter is a character you use to group keys."`
	Marker    string `description:"Specifies the key to start with when listing objects in a bucket."`
	MaxKeys   int    `description:"Sets the maximum number of keys returned."`
	TrackFile string `description:"File for track the read files."`
	Gzip      bool
}

type S3 struct {
	*helper
	bucket    *s3.Bucket
	current   *s3.Key
	trackFile string
}

func NewS3(config *S3Config, format intf.Format) *S3 {
	input := &S3{helper: newHelper(format)}
	input.SetConfig(config)

	return input
}

func (i *S3) SetConfig(c *S3Config) {
	client := s3.New(aws.Auth{c.AccessKey, c.SecretKey}, aws.Regions[c.Region])
	i.bucket = client.Bucket(c.Bucket)

	r, err := i.bucket.List(c.Prefix, c.Delimiter, c.Marker, c.MaxKeys)
	if err != nil {
		Critical("list bucket %s: %v", c.Bucket, err)
	}

	for _, key := range r.Contents {
		i.factories = append(i.factories, i.createReaderFactory(key, c.Gzip))

	}

	if c.TrackFile == "" {
		return
	}

	i.trackFile = c.TrackFile

	i.helper.readerEOF = func() error {
		if i.current == nil {
			return nil
		}

		track := i.getTrackFilename()
		if err := os.MkdirAll(filepath.Dir(track), 0644); err != nil {
			return err
		}

		return ioutil.WriteFile(track, []byte(i.current.LastModified), 0644)
	}
}

func (i *S3) getTrackFilename() string {
	return fmt.Sprintf(i.trackFile, i.current.Key)
}

func (i *S3) isCurrentKeyProcessed() bool {
	if i.current == nil || i.trackFile == "" {
		return false
	}

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

	return false
}

func (i *S3) createReaderFactory(key s3.Key, isGzip bool) ReaderFactory {
	return func() io.Reader {
		i.current = &key
		if i.isCurrentKeyProcessed() {
			Info("Skipping file %s", key.Key)
			return nil
		}

		var reader io.Reader
		var err error
		reader, err = i.bucket.GetReader(key.Key)
		if err != nil {
			Critical("open %s: %v", key.Key, err)
		}

		if isGzip {
			reader, err = gzip.NewReader(reader)
			if err != nil {
				Critical("gzip open %s: %v", key.Key, err)
			}
		}

		return reader
	}
}
<commit_msg>input: fix s3 track file verification<commit_after>package input

import (
	"compress/gzip"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/mcuadros/harvesterd/src/intf"
	. "github.com/mcuadros/harvesterd/src/logger"

	"gopkg.in/amz.v1/aws"
	"gopkg.in/amz.v1/s3"
)

type S3Config struct {
	AccessKey string
	SecretKey string
	Region    string
	Bucket    string
	Format    string `description:"A valid format name."`
	Prefix    string `description:"Limits the response to keys that begin with the specified prefix."`
	Delimiter string `description:"A delimiter is a character you use to group keys."`
	Marker    string `description:"Specifies the key to start with when listing objects in a bucket."`
	MaxKeys   int    `description:"Sets the maximum number of keys returned."`
	TrackFile string `description:"File for track the read files."`
	Gzip      bool
}

type S3 struct {
	*helper
	bucket    *s3.Bucket
	current   *s3.Key
	trackFile string
}

func NewS3(config *S3Config, format intf.Format) *S3 {
	input := &S3{helper: newHelper(format)}
	input.SetConfig(config)

	return input
}

func (i *S3) SetConfig(c *S3Config) {
	client := s3.New(aws.Auth{c.AccessKey, c.SecretKey}, aws.Regions[c.Region])
	i.bucket = client.Bucket(c.Bucket)

	r, err := i.bucket.List(c.Prefix, c.Delimiter, c.Marker, c.MaxKeys)
	if err != nil {
		Critical("list bucket %s: %v", c.Bucket, err)
	}

	for _, key := range r.Contents {
		i.factories = append(i.factories, i.createReaderFactory(key, c.Gzip))

	}

	if c.TrackFile == "" {
		return
	}

	i.trackFile = c.TrackFile

	i.helper.readerEOF = func() error {
		if i.current == nil {
			return nil
		}

		track := i.getTrackFilename()
		if err := os.MkdirAll(filepath.Dir(track), 0644); err != nil {
			return err
		}

		return ioutil.WriteFile(track, []byte(i.current.LastModified), 0644)
	}
}

func (i *S3) getTrackFilename() string {
	return fmt.Sprintf(i.trackFile, i.current.Key)
}

func (i *S3) isCurrentKeyProcessed() bool {
	if i.current == nil || i.trackFile == "" {
		return false
	}

	if _, err := os.Stat(i.getTrackFilename()); err == nil {
		return true
	}

	return false
}

func (i *S3) createReaderFactory(key s3.Key, isGzip bool) ReaderFactory {
	return func() io.Reader {
		i.current = &key
		if i.isCurrentKeyProcessed() {
			Info("Skipping file %s", key.Key)
			return nil
		}

		var reader io.Reader
		var err error
		reader, err = i.bucket.GetReader(key.Key)
		if err != nil {
			Critical("open %s: %v", key.Key, err)
		}

		if isGzip {
			reader, err = gzip.NewReader(reader)
			if err != nil {
				Critical("gzip open %s: %v", key.Key, err)
			}
		}

		return reader
	}
}
<|endoftext|>


<commit_before>//+build !windows

package utils

import (
	"github.com/docker/docker/api/types"
	"github.com/patrickmn/go-cache"
	"github.com/pkg/errors"
	"github.com/rancher/agent/utilities/constants"
	"github.com/vishvananda/netlink"
	"github.com/vishvananda/netns"
	"time"
)

const (
	cniLabels = "io.rancher.network.cni"
	linkName  = "eth0"
)

func getIP(inspect types.ContainerJSON, c *cache.Cache) (string, error) {
	if val, ok := inspect.Config.Labels[cniLabels]; ok && val == "true" && c != nil {
		cacheIP, ok := c.Get(inspect.Config.Labels[constants.UUIDLabel])
		if ok && InterfaceToString(cacheIP) == "error" {
			c.Delete(inspect.Config.Labels[constants.UUIDLabel])
			return "", errors.New("Timeout getting IP address")
		} else if ok {
			c.Delete(inspect.Config.Labels[constants.UUIDLabel])
			return InterfaceToString(cacheIP), nil
		}
		ip, err := lookUpIP(inspect.ID)
		if err != nil {
			c.Add(inspect.Config.Labels[constants.UUIDLabel], "error", cache.DefaultExpiration)
			return "", err
		}
		c.Add(inspect.Config.Labels[constants.UUIDLabel], ip, cache.DefaultExpiration)
		return ip, nil
	}
	return inspect.NetworkSettings.IPAddress, nil
}

func lookUpIP(id string) (string, error) {
	endTime := time.Now().Add(time.Duration(1) * time.Minute)
	initTime := time.Duration(250) * time.Millisecond
	maxTime := time.Duration(2) * time.Second
	for {
		// back off
		nsHandler, err := netns.GetFromDocker(id)
		if err != nil {
			continue
		}
		handler, err := netlink.NewHandleAt(nsHandler)
		if err != nil {
			continue
		}
		link, err := handler.LinkByName(linkName)
		if err != nil {
			continue
		}
		addrs, err := handler.AddrList(link, netlink.FAMILY_V4)
		if err != nil {
			continue
		}
		if len(addrs) > 0 {
			return addrs[0].IP.String(), nil
		}
		time.Sleep(initTime)
		initTime = initTime * 2
		if initTime.Seconds() > maxTime.Seconds() {
			initTime = maxTime
		}
		if time.Now().After(endTime) {
			return "", errors.New("Timeout getting IP address")
		}
	}
}
<commit_msg>Get pid from docker<commit_after>//+build !windows

package utils

import (
	"github.com/docker/docker/api/types"
	"github.com/patrickmn/go-cache"
	"github.com/pkg/errors"
	"github.com/rancher/agent/utilities/constants"
	"github.com/vishvananda/netlink"
	"github.com/vishvananda/netns"
	"time"
)

const (
	cniLabels = "io.rancher.network.cni"
	linkName  = "eth0"
)

func getIP(inspect types.ContainerJSON, c *cache.Cache) (string, error) {
	if val, ok := inspect.Config.Labels[cniLabels]; ok && val == "true" && c != nil {
		cacheIP, ok := c.Get(inspect.Config.Labels[constants.UUIDLabel])
		if ok && InterfaceToString(cacheIP) == "error" {
			c.Delete(inspect.Config.Labels[constants.UUIDLabel])
			return "", errors.New("Timeout getting IP address")
		} else if ok {
			c.Delete(inspect.Config.Labels[constants.UUIDLabel])
			return InterfaceToString(cacheIP), nil
		}
		ip, err := lookUpIP(inspect)
		if err != nil {
			c.Add(inspect.Config.Labels[constants.UUIDLabel], "error", cache.DefaultExpiration)
			return "", err
		}
		c.Add(inspect.Config.Labels[constants.UUIDLabel], ip, cache.DefaultExpiration)
		return ip, nil
	}
	return inspect.NetworkSettings.IPAddress, nil
}

func lookUpIP(inspect types.ContainerJSON) (string, error) {
	endTime := time.Now().Add(time.Duration(1) * time.Minute)
	initTime := time.Duration(250) * time.Millisecond
	maxTime := time.Duration(2) * time.Second
	for {
		// back off
		nsHandler, err := netns.GetFromPid(inspect.State.Pid)
		if err != nil {
			continue
		}
		handler, err := netlink.NewHandleAt(nsHandler)
		if err != nil {
			continue
		}
		link, err := handler.LinkByName(linkName)
		if err != nil {
			continue
		}
		addrs, err := handler.AddrList(link, netlink.FAMILY_V4)
		if err != nil {
			continue
		}
		if len(addrs) > 0 {
			return addrs[0].IP.String(), nil
		}
		time.Sleep(initTime)
		initTime = initTime * 2
		if initTime.Seconds() > maxTime.Seconds() {
			initTime = maxTime
		}
		if time.Now().After(endTime) {
			return "", errors.New("Timeout getting IP address")
		}
	}
}
<|endoftext|>


<commit_before>package geyser

var pingMsg = []byte(`{"event":"pusher:ping","data":{}}`)
<commit_msg>added unsubscribe, subscribe, and pong messages<commit_after>package geyser

import (
	"fmt"
)

var subscribeCache = make(map[string][]byte)
var unsubscribeCache = make(map[string][]byte)

var pingMsg = []byte(`{"event":"pusher:ping","data":{}}`)
var pongMsg = []byte(`{"event":"pusher:pong","data":{}}`)

func subscribe(channelName string) []byte {
	msg, ok := subscribeCache[channelName]
	if !ok {
		msg = []byte(fmt.Sprintf(`{"event":"pusher:subscribe", "data":"{\"channel\":\"%s\"}"}`, channelName))
		subscribeCache[channelName] = msg
	}
	return msg
}

func unsubscribe(channelName string) []byte {
	msg, ok := unsubscribeCache[channelName]
	if !ok {
		msg = []byte(fmt.Sprintf(`{"event":"pusher:unsubscribe", "data":"{\"channel\":\"%s\"}"}`, channelName))
		unsubscribeCache[channelName] = msg
	}
	return msg
}
<|endoftext|>


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

package main

import (
	"fmt"
	"time"

	"../lib/twodee"
	"github.com/go-gl/mathgl/mgl32"
)

type Mob interface {
	Bored(time.Duration) bool
	SetFrames(f []int)
	Detect(dist float32) bool
	Pos() twodee.Point
	Bounds() twodee.Rectangle
	SearchPattern() []mgl32.Vec2
	Speed() float32
	MoveTo(twodee.Point)
}

type Mobile struct {
	DetectionRadius float32
	BoredThreshold  time.Duration
	speed           float32
	searchPattern   []mgl32.Vec2
}

func (m *Mobile) Bored(d time.Duration) bool {
	return d >= m.BoredThreshold
}

func (m *Mobile) Detect(d float32) bool {
	return d <= m.DetectionRadius
}

func (m *Mobile) SearchPattern() []mgl32.Vec2 {
	return m.searchPattern
}

func (m *Mobile) Speed() float32 {
	return m.speed
}

// TODO: this should probably just kill the player?
func (m *Mobile) HandleCollision(p *Player) {}

// MoveMob moves the mob along the given vector, which should be normalized.
func MoveMob(m Mob, v mgl32.Vec2, l *Level) {
	bounds := m.Bounds()
	pos := m.Pos()
	v = l.Collisions.FixMove(mgl32.Vec4{
		bounds.Min.X,
		bounds.Min.Y,
		bounds.Max.X,
		bounds.Max.Y,
	}, v, 0.5, 0.5)
	p := twodee.Pt(pos.X+v[0], pos.Y+v[1])
	m.MoveTo(p)
}

// MobState is implemented by various states responsible for controlling mobile
// entities.
// ExamineWorld examines the current state of the game and determines which
// state
type MobState interface {
	// ExamineWorld examines the current state of the game and determines
	// which state the mobile should transition to. It's legal to return
	// either the current MobState or nil, indicating that the mobile
	// should transition to a previous state.
	ExamineWorld(Mob, *Level) (newState MobState)
	// Update should be called each frame and may update values in the
	// current state or call functions on the mob.
	Update(Mob, time.Duration)
	// Enter should be called when entering this MobState.
	Enter(Mob)
	// Enter should be called when exiting this MobState.
	Exit(Mob)
}

type BaseState struct {
	Name string
}

func (s *BaseState) ExamineWorld(m Mob, l *Level) MobState {
	return s
}
func (s *BaseState) Update(m Mob, d time.Duration) {}
func (s *BaseState) Enter(m Mob) {
	fmt.Printf("Entering the %v state.\n", s.Name)
}
func (s *BaseState) Exit(m Mob) {
	fmt.Printf("Exiting the %v state.\n", s.Name)
}

// VegState encapsulates the state of being a vegetable.
type VegState struct {
	*BaseState
}

func NewVegState() *VegState {
	return &VegState{&BaseState{"Veggie"}}
}

// ExamineWorld always returns a new SearchState.
func (s *VegState) ExamineWorld(m Mob, l *Level) MobState {
	return &SearchState{m.SearchPattern(), 0, &BaseState{"Search"}}
}

// SearchState is the state during which a mobile is aimlessly wandering,
// hoping to chance across the player.
// TODO: Implement Enter and Exit to have searching animations.
type SearchState struct {
	Pattern        []mgl32.Vec2
	targetPointIdx int
	*BaseState
}

// ExamineWorld returns HuntState if the player is seen, otherwise the mob
// continues wandering according to its search pattern.
func (s *SearchState) ExamineWorld(m Mob, l *Level) MobState {
	if playerSeen(m, l) {
		return NewHuntState()
	}
	if len(s.Pattern) == 0 {
		// Do nothing right now with no search pattern.
		return s
	}
	tv := s.Pattern[s.targetPointIdx]
	mv := mgl32.Vec2{m.Pos().X, m.Pos().Y}
	if tv.Sub(mv).Len() < 2 { // CLOSE ENOUGH!
		s.targetPointIdx = (s.targetPointIdx + 1) % len(s.Pattern)
		tv = s.Pattern[s.targetPointIdx]
	}
	MoveMob(m, tv.Sub(mv).Normalize().Mul(m.Speed()), l)
	return s
}

// HuntState is the state during which a mobile is actively hunting the player.
type HuntState struct {
	durSinceLastContact time.Duration
	*BaseState
}

func NewHuntState() *HuntState {
	return &HuntState{0, &BaseState{"Hunt"}}
}

// ExamineWorld returns the current state if the player is currently seen or
// the mob is not yet tired of chasing. Otherwise, it returns nil.
func (h *HuntState) ExamineWorld(m Mob, l *Level) MobState {
	if playerSeen(m, l) {
		h.durSinceLastContact = time.Duration(0)
		return h
	}
	if !m.Bored(h.durSinceLastContact) {
		return h
	}
	return nil
}

// Update resets the player's hiding timer if the player is seen, otherwise it
// increments.
func (h *HuntState) Update(m Mob, d time.Duration) {
	h.durSinceLastContact += d
}

// playerSeen returns true if the player is currently visible to the mob and
// within its detection radius.
func playerSeen(m Mob, l *Level) bool {
	c := l.Collisions
	mpv := mgl32.Vec2{m.Pos().X, m.Pos().Y}
	ppv := mgl32.Vec2{l.Player.Pos().X, l.Player.Pos().Y}
	if c.CanSee(mpv, ppv, 0.5, 0.5) && m.Detect(mpv.Sub(ppv).Len()) {
		return true
	}
	return false
}
<commit_msg>Make the mob chase the player while in HuntState.<commit_after>// Copyright 2015 Pikkpoiss
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"time"

	"../lib/twodee"
	"github.com/go-gl/mathgl/mgl32"
)

type Mob interface {
	Bored(time.Duration) bool
	SetFrames(f []int)
	Detect(dist float32) bool
	Pos() twodee.Point
	Bounds() twodee.Rectangle
	SearchPattern() []mgl32.Vec2
	Speed() float32
	MoveTo(twodee.Point)
}

type Mobile struct {
	DetectionRadius float32
	BoredThreshold  time.Duration
	speed           float32
	searchPattern   []mgl32.Vec2
}

func (m *Mobile) Bored(d time.Duration) bool {
	return d >= m.BoredThreshold
}

func (m *Mobile) Detect(d float32) bool {
	return d <= m.DetectionRadius
}

func (m *Mobile) SearchPattern() []mgl32.Vec2 {
	return m.searchPattern
}

func (m *Mobile) Speed() float32 {
	return m.speed
}

// TODO: this should probably just kill the player?
func (m *Mobile) HandleCollision(p *Player) {}

// MoveMob moves the mob along the given vector, which should be normalized.
func MoveMob(m Mob, v mgl32.Vec2, l *Level) {
	bounds := m.Bounds()
	pos := m.Pos()
	v = l.Collisions.FixMove(mgl32.Vec4{
		bounds.Min.X,
		bounds.Min.Y,
		bounds.Max.X,
		bounds.Max.Y,
	}, v, 0.5, 0.5)
	p := twodee.Pt(pos.X+v[0], pos.Y+v[1])
	m.MoveTo(p)
}

// MobState is implemented by various states responsible for controlling mobile
// entities.
// ExamineWorld examines the current state of the game and determines which
// state
type MobState interface {
	// ExamineWorld examines the current state of the game and determines
	// which state the mobile should transition to. It's legal to return
	// either the current MobState or nil, indicating that the mobile
	// should transition to a previous state.
	ExamineWorld(Mob, *Level) (newState MobState)
	// Update should be called each frame and may update values in the
	// current state or call functions on the mob.
	Update(Mob, time.Duration)
	// Enter should be called when entering this MobState.
	Enter(Mob)
	// Enter should be called when exiting this MobState.
	Exit(Mob)
}

type BaseState struct {
	Name string
}

func (s *BaseState) ExamineWorld(m Mob, l *Level) MobState {
	return s
}
func (s *BaseState) Update(m Mob, d time.Duration) {}
func (s *BaseState) Enter(m Mob) {
	fmt.Printf("Entering the %v state.\n", s.Name)
}
func (s *BaseState) Exit(m Mob) {
	fmt.Printf("Exiting the %v state.\n", s.Name)
}

// VegState encapsulates the state of being a vegetable.
type VegState struct {
	*BaseState
}

func NewVegState() *VegState {
	return &VegState{&BaseState{"Veggie"}}
}

// ExamineWorld always returns a new SearchState.
func (s *VegState) ExamineWorld(m Mob, l *Level) MobState {
	return &SearchState{m.SearchPattern(), 0, &BaseState{"Search"}}
}

// SearchState is the state during which a mobile is aimlessly wandering,
// hoping to chance across the player.
// TODO: Implement Enter and Exit to have searching animations.
type SearchState struct {
	Pattern        []mgl32.Vec2
	targetPointIdx int
	*BaseState
}

// ExamineWorld returns HuntState if the player is seen, otherwise the mob
// continues wandering according to its search pattern.
func (s *SearchState) ExamineWorld(m Mob, l *Level) MobState {
	if playerSeen(m, l) {
		return NewHuntState()
	}
	if len(s.Pattern) == 0 {
		// Do nothing right now with no search pattern.
		return s
	}
	tv := s.Pattern[s.targetPointIdx]
	mv := mgl32.Vec2{m.Pos().X, m.Pos().Y}
	if tv.Sub(mv).Len() < 2 { // CLOSE ENOUGH!
		s.targetPointIdx = (s.targetPointIdx + 1) % len(s.Pattern)
		tv = s.Pattern[s.targetPointIdx]
	}
	MoveMob(m, tv.Sub(mv).Normalize().Mul(m.Speed()), l)
	return s
}

// HuntState is the state during which a mobile is actively hunting the player.
type HuntState struct {
	durSinceLastContact time.Duration
	*BaseState
}

func NewHuntState() *HuntState {
	return &HuntState{0, &BaseState{"Hunt"}}
}

// ExamineWorld returns the current state if the player is currently seen or
// the mob is not yet tired of chasing. Otherwise, it returns nil.
func (s *HuntState) ExamineWorld(m Mob, l *Level) (ns MobState) {
	if playerSeen(m, l) {
		s.durSinceLastContact = time.Duration(0)
		ns = s
	}
	if !m.Bored(s.durSinceLastContact) {
		ns = s
	}
	if ns != nil {
		// Chase player! Maybe swing!
		tv := mgl32.Vec2{l.Player.Pos().X, l.Player.Pos().Y}
		mv := mgl32.Vec2{m.Pos().X, m.Pos().Y}
		if tv.Sub(mv).Len() < 1 {
			// return swing state
		}
		MoveMob(m, tv.Sub(mv).Normalize().Mul(m.Speed()), l)
	}
	return ns
}

// Update resets the player's hiding timer if the player is seen, otherwise it
// increments.
func (s *HuntState) Update(m Mob, d time.Duration) {
	s.durSinceLastContact += d
}

// playerSeen returns true if the player is currently visible to the mob and
// within its detection radius.
func playerSeen(m Mob, l *Level) bool {
	c := l.Collisions
	mpv := mgl32.Vec2{m.Pos().X, m.Pos().Y}
	ppv := mgl32.Vec2{l.Player.Pos().X, l.Player.Pos().Y}
	if c.CanSee(mpv, ppv, 0.5, 0.5) && m.Detect(mpv.Sub(ppv).Len()) {
		return true
	}
	return false
}
<|endoftext|>


<commit_before>// Copyright The OpenTelemetry 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.
//
// Example application showcasing opentelemetry Go using the OTLP wire
// protocol

package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"go.opentelemetry.io/otel/api/global"
	"go.opentelemetry.io/otel/api/kv"
	"go.opentelemetry.io/otel/api/metric"
	"go.opentelemetry.io/otel/exporters/otlp"
	"go.opentelemetry.io/otel/sdk/metric/controller/push"
	"go.opentelemetry.io/otel/sdk/metric/selector/simple"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
)

// Initializes an OTLP exporter, and configures the corresponding trace and
// metric providers.
func initProvider() (*otlp.Exporter, *push.Controller) {
	exp, err := otlp.NewExporter(
		otlp.WithInsecure(),
		otlp.WithAddress("localhost:55680"),
	)
	handleErr(err, "Failed to create exporter: $v")

	traceProvider, err := sdktrace.NewProvider(
		sdktrace.WithConfig(sdktrace.Config{DefaultSampler: sdktrace.AlwaysSample()}),
		sdktrace.WithSyncer(exp),
	)
	handleErr(err, "Failed to create trace provider: %v")

	pusher := push.New(
		simple.NewWithExactDistribution(),
		exp,
		push.WithStateful(true),
		push.WithPeriod(2*time.Second),
	)

	global.SetTraceProvider(traceProvider)
	global.SetMeterProvider(pusher.Provider())
	pusher.Start()

	return exp, pusher
}

func main() {
	exp, pusher := initProvider()
	defer handleErr(exp.Stop(), "Failed to stop exporter")
	defer pusher.Stop() // pushes any last exports to the receiver

	tracer := global.Tracer("mage-sense")
	meter := global.Meter("mage-read")

	// labels represent additional descriptors that can be bound to a metric
	// observer or recorder. In this case they describe the location in
	// which a spell scroll is scribed.
	commonLabels := []kv.KeyValue{
		kv.String("work-room", "East Scriptorium"),
		kv.String("occupancy", "69,105"),
		kv.String("priority", "Ultra"),
	}

	// Observer metric example
	oneMetricCB := func(_ context.Context, result metric.Float64ObserverResult) {
		result.Observe(1, commonLabels...)
	}
	_ = metric.Must(meter).NewFloat64ValueObserver("scrying.glass.one", oneMetricCB,
		metric.WithDescription("A ValueObserver set to 1.0"),
	)

	// Recorder metric example
	valuerecorder := metric.Must(meter).
		NewFloat64ValueRecorder("scrying.glass.two").
		Bind(commonLabels...)
	defer valuerecorder.Unbind()

	// work begins
	ctx, span := tracer.Start(context.Background(), "Archmage-Overlord-Inspection")
	for i := 0; i < 10; i++ {
		_, innerSpan := tracer.Start(ctx, fmt.Sprintf("Minion-%d", i))
		log.Println("Minions hard at work, scribing...")
		valuerecorder.Record(ctx, float64(i)*1.5)

		<-time.After(time.Second)
		innerSpan.End()
	}

	span.End()
	<-time.After(time.Second)

	log.Println("Spell-scroll scribed!")
}

func handleErr(err error, message string) {
	if err != nil {
		log.Fatalf("%s: %v", message, err)
	}
}
<commit_msg>Fixed OTLP example's accidental early close of exporter<commit_after>// Copyright The OpenTelemetry 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.
//
// Example application showcasing opentelemetry Go using the OTLP wire
// protocol

package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"go.opentelemetry.io/otel/api/global"
	"go.opentelemetry.io/otel/api/kv"
	"go.opentelemetry.io/otel/api/metric"
	"go.opentelemetry.io/otel/exporters/otlp"
	"go.opentelemetry.io/otel/sdk/metric/controller/push"
	"go.opentelemetry.io/otel/sdk/metric/selector/simple"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
)

// Initializes an OTLP exporter, and configures the corresponding trace and
// metric providers.
func initProvider() (*otlp.Exporter, *push.Controller) {
	exp, err := otlp.NewExporter(
		otlp.WithInsecure(),
		otlp.WithAddress("localhost:55680"),
	)
	handleErr(err, "Failed to create exporter: $v")

	traceProvider, err := sdktrace.NewProvider(
		sdktrace.WithConfig(sdktrace.Config{DefaultSampler: sdktrace.AlwaysSample()}),
		sdktrace.WithSyncer(exp),
	)
	handleErr(err, "Failed to create trace provider: %v")

	pusher := push.New(
		simple.NewWithExactDistribution(),
		exp,
		push.WithStateful(true),
		push.WithPeriod(2*time.Second),
	)

	global.SetTraceProvider(traceProvider)
	global.SetMeterProvider(pusher.Provider())
	pusher.Start()

	return exp, pusher
}

func main() {
	exp, pusher := initProvider()
	defer func() { handleErr(exp.Stop(), "Failed to stop exporter") }()
	defer pusher.Stop() // pushes any last exports to the receiver

	tracer := global.Tracer("mage-sense")
	meter := global.Meter("mage-read")

	// labels represent additional descriptors that can be bound to a metric
	// observer or recorder. In this case they describe the location in
	// which a spell scroll is scribed.
	commonLabels := []kv.KeyValue{
		kv.String("work-room", "East Scriptorium"),
		kv.String("occupancy", "69,105"),
		kv.String("priority", "Ultra"),
	}

	// Observer metric example
	oneMetricCB := func(_ context.Context, result metric.Float64ObserverResult) {
		result.Observe(1, commonLabels...)
	}
	_ = metric.Must(meter).NewFloat64ValueObserver("scrying.glass.one", oneMetricCB,
		metric.WithDescription("A ValueObserver set to 1.0"),
	)

	// Recorder metric example
	valuerecorder := metric.Must(meter).
		NewFloat64ValueRecorder("scrying.glass.two").
		Bind(commonLabels...)
	defer valuerecorder.Unbind()

	// work begins
	ctx, span := tracer.Start(context.Background(), "Archmage-Overlord-Inspection")
	for i := 0; i < 10; i++ {
		_, innerSpan := tracer.Start(ctx, fmt.Sprintf("Minion-%d", i))
		log.Println("Minions hard at work, scribing...")
		valuerecorder.Record(ctx, float64(i)*1.5)

		<-time.After(time.Second)
		innerSpan.End()
	}

	span.End()
	<-time.After(time.Second)

	log.Println("Spell-scroll scribed!")
}

func handleErr(err error, message string) {
	if err != nil {
		log.Fatalf("%s: %v", message, err)
	}
}
<|endoftext|>


<commit_before>package vcs

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"text/template"
	"time"

	"github.com/timeglass/glass/_vendor/github.com/hashicorp/errwrap"
)

var TimeSpentNotesRef = "time-spent"

const (
	TOTAL_PREFIX = "total="
)

var PrepCommitTmpl = template.Must(template.New("name").Parse(`#!/bin/sh
# only add time to template and message sources
# @see http://git-scm.com/docs/githooks#_prepare_commit_msg
case "$2" in
message|template)
	# -m method
	printf "$(cat $1)$(glass -s status --commit-template)" > "$1" ;;
"")
	# interactive method
	printf "$(glass -s status --commit-template)\n$(cat $1)" > "$1" ;;
esac
`))

var PostCommitTmpl = template.Must(template.New("name").Parse(`#!/bin/sh
#persist (punch) to newly created commit and reset the timer
glass status -t "{{"{{"}}.{{"}}"}}" | glass punch
glass reset
`))

var PrePushTmpl = template.Must(template.New("name").Parse(`#!/bin/sh
#push time data
glass push $1
`))

type gitTimeData struct {
	total time.Duration
}

func (g *gitTimeData) Total() time.Duration { return g.total }

type Git struct {
	dir  string
	root string
	init string
}

func NewGit(dir string) *Git {
	return &Git{
		init: dir,
	}
}

func (g *Git) Name() string { return "git" }
func (g *Git) IsAvailable() bool {
	outbuff := bytes.NewBuffer(nil)
	cmd := exec.Command("git", "rev-parse", "--show-toplevel")
	cmd.Stdout = outbuff

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

	g.root = strings.TrimSpace(outbuff.String())
	g.dir = filepath.Join(g.root, ".git")
	return true
}

func (g *Git) Root() string {
	return g.root
}

func (g *Git) DefaultRemote() (string, error) {
	outbuff := bytes.NewBuffer(nil)
	cmd := exec.Command("git", "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}")
	cmd.Stdout = outbuff

	err := cmd.Run()
	if err != nil {
		return "", ErrNoRemote
	}

	//outbuff should contain full path to remote branch that is tracked for
	//the current local branch (e.g origin/remote_branch), we are only interested
	//in the first part as notes are kept in their own branch
	return strings.SplitN(outbuff.String(), "/", 2)[0], nil
}

func (g *Git) Show(commit string) (TimeData, error) {
	data := &gitTimeData{}
	args := []string{"notes", "--ref=" + TimeSpentNotesRef, "show", commit}
	outbuff := bytes.NewBuffer(nil)
	errbuff := bytes.NewBuffer(nil)
	cmd := exec.Command("git", args...)
	cmd.Stdout = outbuff
	cmd.Stderr = errbuff

	err := cmd.Run()
	if err != nil && strings.Contains(errbuff.String(), "No note found for object") {
		return data, ErrNoCommitTimeData
	}

	//in other cases present user with git output
	_, err2 := io.Copy(os.Stderr, errbuff)
	if err2 != nil {
		return data, err
	}

	if err != nil {
		return data, errwrap.Wrapf(fmt.Sprintf("Failed to show time for commit '%s' using git args %s: {{err}}", commit, args), err)
	}

	//scan lines in note
	scanner := bufio.NewScanner(outbuff)
	for scanner.Scan() {
		line := scanner.Text()

		//@todo for now only read total line
		if strings.HasPrefix(line, TOTAL_PREFIX) {
			t, err := time.ParseDuration(line[len(TOTAL_PREFIX):])
			if err != nil {
				return data, errwrap.Wrapf(fmt.Sprintf("Failed to parse time from line '%s': {{err}}"), err)
			}

			data.total = t
		}
	}
	if err := scanner.Err(); err != nil {
		return data, errwrap.Wrapf(fmt.Sprintf("Failed to scan note for commit '%s': {{err}}"), err)
	}

	return data, nil
}

func (g *Git) Persist(t time.Duration) error {
	args := []string{"notes", "--ref=" + TimeSpentNotesRef, "add", "-f", "-m", fmt.Sprintf("%s%s", TOTAL_PREFIX, t)}
	cmd := exec.Command("git", args...)
	err := cmd.Run()
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to persist time '%s' using git command %s: {{err}}", t, args), err)
	}

	return nil
}

func (g *Git) Pull(remote string) error {
	args := []string{"fetch", remote, fmt.Sprintf("refs/notes/%s:refs/notes/%s", TimeSpentNotesRef, TimeSpentNotesRef)}
	cmd := exec.Command("git", args...)
	buff := bytes.NewBuffer(nil)

	cmd.Stdout = os.Stdout
	cmd.Stderr = buff

	err := cmd.Run()
	if err != nil && strings.Contains(buff.String(), "Couldn't find remote ref") {
		return ErrNoRemoteTimeData
	}

	//in other cases present user with git output
	_, err2 := io.Copy(os.Stderr, buff)
	if err2 != nil {
		return err
	}

	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to fetch from remote '%s' using git command %s: {{err}}", remote, args), err)
	}

	return nil
}

func (g *Git) Push(remote string, refs string) error {

	//if time ref is already pushed, dont do it again
	if strings.Contains(refs, TimeSpentNotesRef) {
		return nil
	}

	args := []string{"push", remote, fmt.Sprintf("refs/notes/%s", TimeSpentNotesRef)}
	cmd := exec.Command("git", args...)
	buff := bytes.NewBuffer(nil)

	cmd.Stdout = os.Stdout
	cmd.Stderr = buff

	err := cmd.Run()
	if err != nil && strings.Contains(buff.String(), "src refspec refs/notes/"+TimeSpentNotesRef+" does not match any") {
		return ErrNoLocalTimeData
	}

	//in other cases present user with git output
	_, err2 := io.Copy(os.Stderr, buff)
	if err2 != nil {
		return err
	}

	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to push to remote '%s' using git command %s: {{err}}", remote, args), err)
	}

	return nil
}

func (g *Git) Hook() error {
	hpath := filepath.Join(g.dir, "hooks")

	//prepare commit msg: status()
	prepcopath := filepath.Join(hpath, "prepare-commit-msg")
	prepcof, err := os.Create(prepcopath)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to create prepare-commit-msg  '%s': {{err}}", prepcof.Name()), err)
	}

	err = os.Chmod(prepcopath, 0766)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to make prepare-commit-msg file '%s' executable: {{err}}", hpath), err)
	}

	err = PrepCommitTmpl.Execute(prepcof, struct{}{})
	if err != nil {
		return errwrap.Wrapf("Failed to run post-commit template: {{err}}", err)
	}

	//post commit: lap()
	postcopath := filepath.Join(hpath, "post-commit")
	postcof, err := os.Create(postcopath)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to create post-commit '%s': {{err}}", postcof.Name()), err)
	}

	err = os.Chmod(postcopath, 0766)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to make post-commit file '%s' executable: {{err}}", hpath), err)
	}

	err = PostCommitTmpl.Execute(postcof, struct{}{})
	if err != nil {
		return errwrap.Wrapf("Failed to run post-commit template: {{err}}", err)
	}

	//post receive: push()
	prepushpath := filepath.Join(hpath, "pre-push")
	prepushf, err := os.Create(prepushpath)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to create pre-push  '%s': {{err}}", prepushf.Name()), err)
	}

	err = os.Chmod(prepushpath, 0766)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to make pre-push file '%s' executable: {{err}}", hpath), err)
	}

	err = PrePushTmpl.Execute(prepushf, struct{}{})
	if err != nil {
		return errwrap.Wrapf("Failed to run pre-push template: {{err}}", err)
	}

	return nil
}
<commit_msg>even less verbose [spent 1m0s]<commit_after>package vcs

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"text/template"
	"time"

	"github.com/timeglass/glass/_vendor/github.com/hashicorp/errwrap"
)

var TimeSpentNotesRef = "time-spent"

const (
	TOTAL_PREFIX = "total="
)

var PrepCommitTmpl = template.Must(template.New("name").Parse(`#!/bin/sh
# only add time to template and message sources
# @see http://git-scm.com/docs/githooks#_prepare_commit_msg
case "$2" in
message|template)
	# -m method
	printf "$(cat $1)$(glass -s status --commit-template)" > "$1" ;;
"")
	# interactive method
	printf "$(glass -s status --commit-template)\n$(cat $1)" > "$1" ;;
esac
`))

var PostCommitTmpl = template.Must(template.New("name").Parse(`#!/bin/sh
#persist (punch) to newly created commit and reset the timer
glass -s status -t "{{"{{"}}.{{"}}"}}" | glass punch
glass reset
`))

var PrePushTmpl = template.Must(template.New("name").Parse(`#!/bin/sh
#push time data
glass push $1
`))

type gitTimeData struct {
	total time.Duration
}

func (g *gitTimeData) Total() time.Duration { return g.total }

type Git struct {
	dir  string
	root string
	init string
}

func NewGit(dir string) *Git {
	return &Git{
		init: dir,
	}
}

func (g *Git) Name() string { return "git" }
func (g *Git) IsAvailable() bool {
	outbuff := bytes.NewBuffer(nil)
	cmd := exec.Command("git", "rev-parse", "--show-toplevel")
	cmd.Stdout = outbuff

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

	g.root = strings.TrimSpace(outbuff.String())
	g.dir = filepath.Join(g.root, ".git")
	return true
}

func (g *Git) Root() string {
	return g.root
}

func (g *Git) DefaultRemote() (string, error) {
	outbuff := bytes.NewBuffer(nil)
	cmd := exec.Command("git", "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}")
	cmd.Stdout = outbuff

	err := cmd.Run()
	if err != nil {
		return "", ErrNoRemote
	}

	//outbuff should contain full path to remote branch that is tracked for
	//the current local branch (e.g origin/remote_branch), we are only interested
	//in the first part as notes are kept in their own branch
	return strings.SplitN(outbuff.String(), "/", 2)[0], nil
}

func (g *Git) Show(commit string) (TimeData, error) {
	data := &gitTimeData{}
	args := []string{"notes", "--ref=" + TimeSpentNotesRef, "show", commit}
	outbuff := bytes.NewBuffer(nil)
	errbuff := bytes.NewBuffer(nil)
	cmd := exec.Command("git", args...)
	cmd.Stdout = outbuff
	cmd.Stderr = errbuff

	err := cmd.Run()
	if err != nil && strings.Contains(errbuff.String(), "No note found for object") {
		return data, ErrNoCommitTimeData
	}

	//in other cases present user with git output
	_, err2 := io.Copy(os.Stderr, errbuff)
	if err2 != nil {
		return data, err
	}

	if err != nil {
		return data, errwrap.Wrapf(fmt.Sprintf("Failed to show time for commit '%s' using git args %s: {{err}}", commit, args), err)
	}

	//scan lines in note
	scanner := bufio.NewScanner(outbuff)
	for scanner.Scan() {
		line := scanner.Text()

		//@todo for now only read total line
		if strings.HasPrefix(line, TOTAL_PREFIX) {
			t, err := time.ParseDuration(line[len(TOTAL_PREFIX):])
			if err != nil {
				return data, errwrap.Wrapf(fmt.Sprintf("Failed to parse time from line '%s': {{err}}"), err)
			}

			data.total = t
		}
	}
	if err := scanner.Err(); err != nil {
		return data, errwrap.Wrapf(fmt.Sprintf("Failed to scan note for commit '%s': {{err}}"), err)
	}

	return data, nil
}

func (g *Git) Persist(t time.Duration) error {
	args := []string{"notes", "--ref=" + TimeSpentNotesRef, "add", "-f", "-m", fmt.Sprintf("%s%s", TOTAL_PREFIX, t)}
	cmd := exec.Command("git", args...)
	err := cmd.Run()
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to persist time '%s' using git command %s: {{err}}", t, args), err)
	}

	return nil
}

func (g *Git) Pull(remote string) error {
	args := []string{"fetch", remote, fmt.Sprintf("refs/notes/%s:refs/notes/%s", TimeSpentNotesRef, TimeSpentNotesRef)}
	cmd := exec.Command("git", args...)
	buff := bytes.NewBuffer(nil)

	cmd.Stdout = os.Stdout
	cmd.Stderr = buff

	err := cmd.Run()
	if err != nil && strings.Contains(buff.String(), "Couldn't find remote ref") {
		return ErrNoRemoteTimeData
	}

	//in other cases present user with git output
	_, err2 := io.Copy(os.Stderr, buff)
	if err2 != nil {
		return err
	}

	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to fetch from remote '%s' using git command %s: {{err}}", remote, args), err)
	}

	return nil
}

func (g *Git) Push(remote string, refs string) error {

	//if time ref is already pushed, dont do it again
	if strings.Contains(refs, TimeSpentNotesRef) {
		return nil
	}

	args := []string{"push", remote, fmt.Sprintf("refs/notes/%s", TimeSpentNotesRef)}
	cmd := exec.Command("git", args...)
	buff := bytes.NewBuffer(nil)

	cmd.Stdout = os.Stdout
	cmd.Stderr = buff

	err := cmd.Run()
	if err != nil && strings.Contains(buff.String(), "src refspec refs/notes/"+TimeSpentNotesRef+" does not match any") {
		return ErrNoLocalTimeData
	}

	//in other cases present user with git output
	_, err2 := io.Copy(os.Stderr, buff)
	if err2 != nil {
		return err
	}

	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to push to remote '%s' using git command %s: {{err}}", remote, args), err)
	}

	return nil
}

func (g *Git) Hook() error {
	hpath := filepath.Join(g.dir, "hooks")

	//prepare commit msg: status()
	prepcopath := filepath.Join(hpath, "prepare-commit-msg")
	prepcof, err := os.Create(prepcopath)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to create prepare-commit-msg  '%s': {{err}}", prepcof.Name()), err)
	}

	err = os.Chmod(prepcopath, 0766)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to make prepare-commit-msg file '%s' executable: {{err}}", hpath), err)
	}

	err = PrepCommitTmpl.Execute(prepcof, struct{}{})
	if err != nil {
		return errwrap.Wrapf("Failed to run post-commit template: {{err}}", err)
	}

	//post commit: lap()
	postcopath := filepath.Join(hpath, "post-commit")
	postcof, err := os.Create(postcopath)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to create post-commit '%s': {{err}}", postcof.Name()), err)
	}

	err = os.Chmod(postcopath, 0766)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to make post-commit file '%s' executable: {{err}}", hpath), err)
	}

	err = PostCommitTmpl.Execute(postcof, struct{}{})
	if err != nil {
		return errwrap.Wrapf("Failed to run post-commit template: {{err}}", err)
	}

	//post receive: push()
	prepushpath := filepath.Join(hpath, "pre-push")
	prepushf, err := os.Create(prepushpath)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to create pre-push  '%s': {{err}}", prepushf.Name()), err)
	}

	err = os.Chmod(prepushpath, 0766)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to make pre-push file '%s' executable: {{err}}", hpath), err)
	}

	err = PrePushTmpl.Execute(prepushf, struct{}{})
	if err != nil {
		return errwrap.Wrapf("Failed to run pre-push template: {{err}}", err)
	}

	return nil
}
<|endoftext|>


<commit_before>package vcs

import (
	"fmt"
	"os"
	"path/filepath"
	"text/template"

	"github.com/hashicorp/errwrap"
)

var PostCheckoutTmpl = template.Must(template.New("name").Parse(`#!/bin/sh

echo checkout!
`))

var PostCommitTmpl = template.Must(template.New("name").Parse(`#!/bin/sh

echo commit!
`))

type Git struct {
	dir string
}

func NewGit(dir string) *Git {
	return &Git{
		dir: filepath.Join(dir, ".git"),
	}
}

func (g *Git) Name() string { return "git" }
func (g *Git) Supported() bool {
	fi, err := os.Stat(g.dir)
	if err != nil || !fi.IsDir() {
		return false
	}

	return true
}

func (g *Git) Hook() error {
	hpath := filepath.Join(g.dir, "hooks")

	postchf, err := os.Create(filepath.Join(hpath, "post-checkout"))
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to create post-checkout '%s': {{err}}", postchf.Name()), err)
	}

	err = postchf.Chmod(0766)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to make post-checkout file '%s' executable: {{err}}", hpath), err)
	}

	err = PostCheckoutTmpl.Execute(postchf, struct{}{})
	if err != nil {
		return errwrap.Wrapf("Failed to run post-checkout template: {{err}}", err)
	}

	postcof, err := os.Create(filepath.Join(hpath, "post-commit"))
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to create post-commit  '%s': {{err}}", postchf.Name()), err)
	}

	err = postcof.Chmod(0766)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to make post-commit file '%s' executable: {{err}}", hpath), err)
	}

	err = PostCommitTmpl.Execute(postcof, struct{}{})
	if err != nil {
		return errwrap.Wrapf("Failed to run post-commit template: {{err}}", err)
	}

	return nil
}
<commit_msg>test prep commit  +test<commit_after>package vcs

import (
	"fmt"
	"os"
	"path/filepath"
	"text/template"

	"github.com/hashicorp/errwrap"
)

var PostCheckoutTmpl = template.Must(template.New("name").Parse(`#!/bin/sh

#args:
#Ref of the previous HEAD, ref of the new HEAD, flag indicating whether it was a branch checkout

echo checkout!
`))

var PrepCommitTmpl = template.Must(template.New("name").Parse(`#!/bin/sh

echo " +test" >> "$1"
`))

type Git struct {
	dir string
}

func NewGit(dir string) *Git {
	return &Git{
		dir: filepath.Join(dir, ".git"),
	}
}

func (g *Git) Name() string { return "git" }
func (g *Git) Supported() bool {
	fi, err := os.Stat(g.dir)
	if err != nil || !fi.IsDir() {
		return false
	}

	return true
}

func (g *Git) Hook() error {
	hpath := filepath.Join(g.dir, "hooks")

	postchf, err := os.Create(filepath.Join(hpath, "post-checkout"))
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to create post-checkout '%s': {{err}}", postchf.Name()), err)
	}

	err = postchf.Chmod(0766)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to make post-checkout file '%s' executable: {{err}}", hpath), err)
	}

	err = PostCheckoutTmpl.Execute(postchf, struct{}{})
	if err != nil {
		return errwrap.Wrapf("Failed to run post-checkout template: {{err}}", err)
	}

	prepcof, err := os.Create(filepath.Join(hpath, "prepare-commit-msg"))
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to create post-commit  '%s': {{err}}", postchf.Name()), err)
	}

	err = prepcof.Chmod(0766)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to make post-commit file '%s' executable: {{err}}", hpath), err)
	}

	err = PrepCommitTmpl.Execute(prepcof, struct{}{})
	if err != nil {
		return errwrap.Wrapf("Failed to run post-commit template: {{err}}", err)
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2015 The Serulian Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// Some code based on the Golang VCS portion of the cmd package:
// https://golang.org/src/cmd/go/vcs.go

//go:generate stringer -type=VCSKind

// vcs package defines helpers functions and interfaces for working with Version Control Systems
// such as git, including discovery of VCS information based on the Golang VCS discovery protocol.
//
// The discovery protocol is documented loosely here: https://golang.org/cmd/go/#hdr-Remote_import_paths
package vcs

import (
	"fmt"
	"log"
	"os"
	"path"
)

// IsVCSRootDirectory returns true if the given local file system path is a VCS root directory.
// Note that this method will return false if the path does not exist locally.
func IsVCSRootDirectory(localPath string) bool {
	_, hasHandler := detectHandler(localPath)
	return hasHandler
}

// PerformVCSCheckout performs the checkout and updating of the given VCS path and returns
// the local system directory at which the package was checked out.
//
// pkgCacheRootPath holds the path of the root directory that forms the package cache.
//
// vcsDevelopmentDirectories specifies optional directories to check for branchless and tagless copies
// of the repository first. If found, the copy will be used in lieu of a normal checkout.
func PerformVCSCheckout(vcsPath string, pkgCacheRootPath string, vcsDevelopmentDirectories ...string) (string, error, string) {
	// Parse the VCS path.
	parsedPath, perr := ParseVCSPath(vcsPath)
	if perr != nil {
		return "", perr, ""
	}

	var err error
	var warning string

	// Check for a local development cache.
	if parsedPath.isRepoOnlyReference() {
		for _, directoryPath := range vcsDevelopmentDirectories {
			fullCheckDirectory := path.Join(directoryPath, parsedPath.url)
			if _, err := os.Stat(fullCheckDirectory); err == nil {
				// Found a local copy. Returning it.
				log.Printf("Found a local HEAD copy of package %s under development directory %s", parsedPath.url, directoryPath)
				warning = fmt.Sprintf(
					`Package '%s' does not specify a tag, commit or branch and a local copy was found under development directory '%s'. VCS checkout will be skipped and the local copy used instead. To return to normal VCS behavior for this package, remove the --vcs-dev-dir flag or specify the package's tag, commit or branch.`, parsedPath.String(), directoryPath)
				return fullCheckDirectory, nil, warning
			}
		}
	}

	// Conduct the checkout or pull.
	fullCacheDirectory := path.Join(pkgCacheRootPath, parsedPath.cacheDirectory())
	err, warning = checkCacheAndPull(parsedPath, fullCacheDirectory)

	// Warn if the package is a HEAD checkout.
	if err == nil && warning == "" && parsedPath.isHEAD() {
		warning = fmt.Sprintf("Package '%s' points to HEAD of a branch or commit and will be updated on every build", parsedPath.String())
	}

	// If the parsed path is a subdirectory of the checkout, return a reference to it.
	if err == nil && parsedPath.subpackage != "" {
		subpackageCacheDirectory := path.Join(fullCacheDirectory, parsedPath.subpackage)
		if _, serr := os.Stat(subpackageCacheDirectory); os.IsNotExist(serr) {
			return "", fmt.Errorf("Subpackage '%s' does not exist under VCS package '%s'", parsedPath.subpackage, parsedPath.url), warning
		}
		return subpackageCacheDirectory, nil, warning
	}

	return fullCacheDirectory, err, warning
}

// InspectInfo holds all the data returned from a call to PerformVCSCheckoutAndInspect.
type InspectInfo struct {
	CommitSHA string
	Tags      []string
}

// PerformVCSCheckoutAndInspect performs the checkout and updating of the given VCS path and returns
// the commit SHA of the package, as well as its tags.
//
// pkgCacheRootPath holds the path of the root directory that forms the package cache.
//
// vcsDevelopmentDirectories specifies optional directories to check for branchless and tagless copies
// of the repository first. If found, the copy will be used in lieu of a normal checkout.
func PerformVCSCheckoutAndInspect(vcsPath string, pkgCacheRootPath string, vcsDevelopmentDirectories ...string) (InspectInfo, error, string) {
	directory, err, warning := PerformVCSCheckout(vcsPath, pkgCacheRootPath, vcsDevelopmentDirectories...)
	if err != nil {
		return InspectInfo{}, err, warning
	}

	handler, _ := detectHandler(directory)
	sha, err := handler.inspect(directory)
	if err != nil {
		return InspectInfo{}, err, warning
	}

	tags, err := handler.listTags(directory)
	if err != nil {
		return InspectInfo{}, err, warning
	}

	return InspectInfo{sha, tags}, nil, warning
}

// checkCacheAndPull conducts the cache check and necessary pulls.
func checkCacheAndPull(parsedPath vcsPackagePath, fullCacheDirectory string) (error, string) {
	// TODO(jschorr): Should we delete the package cache directory here if there was an error?

	// Check the package cache for the path.
	log.Printf("Checking cache directory %s", fullCacheDirectory)
	if _, err := os.Stat(fullCacheDirectory); os.IsNotExist(err) {
		// Do a full checkout.
		return performFullCheckout(parsedPath, fullCacheDirectory)
	}

	// If the cache exists, we only perform an update to the VCS package if the package
	// is marked as pointing to HEAD of a branch or commit. Tagged VCS packages are always left alone.
	log.Printf("Cache directory %s exists", fullCacheDirectory)
	if parsedPath.isHEAD() {
		return performUpdateCheckout(parsedPath, fullCacheDirectory)
	}

	log.Printf("Cache directory %s exists and points to tag %s; no update needed", fullCacheDirectory, parsedPath.tag)
	return nil, ""
}

// performFullCheckout performs a full VCS checkout of the given package path.
func performFullCheckout(path vcsPackagePath, fullCacheDirectory string) (error, string) {
	// Lookup the VCS discovery information.
	discovery, err := DiscoverVCSInformation(path.url)
	if err != nil {
		return err, ""
	}

	// Perform a full checkout.
	handler, ok := vcsByKind[discovery.Kind]
	if !ok {
		panic("Unknown VCS handler")
	}

	warning, err := handler.checkout(path, discovery, fullCacheDirectory)
	return err, warning
}

// performUpdateCheckout performs a VCS update of the given package path.
func performUpdateCheckout(path vcsPackagePath, fullCacheDirectory string) (error, string) {
	// Detect the kind of VCS based on the checkout.
	handler, ok := detectHandler(fullCacheDirectory)
	if !ok {
		return fmt.Errorf("Could not detect VCS for directory: %s", fullCacheDirectory), ""
	}

	// If the checkout has changes, warn, but nothing more to do.
	if handler.check(fullCacheDirectory) {
		warning := fmt.Sprintf("VCS Package '%s' has changes on the local file system and will therefore not be updated", path.String())
		return nil, warning
	}

	// Otherwise, perform a pull to update.
	err := handler.update(fullCacheDirectory)
	return err, ""
}
<commit_msg>Adds a function for retrieving the local path of a VCS directory<commit_after>// Copyright 2015 The Serulian Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// Some code based on the Golang VCS portion of the cmd package:
// https://golang.org/src/cmd/go/vcs.go

//go:generate stringer -type=VCSKind

// vcs package defines helpers functions and interfaces for working with Version Control Systems
// such as git, including discovery of VCS information based on the Golang VCS discovery protocol.
//
// The discovery protocol is documented loosely here: https://golang.org/cmd/go/#hdr-Remote_import_paths
package vcs

import (
	"fmt"
	"log"
	"os"
	"path"
)

// IsVCSRootDirectory returns true if the given local file system path is a VCS root directory.
// Note that this method will return false if the path does not exist locally.
func IsVCSRootDirectory(localPath string) bool {
	_, hasHandler := detectHandler(localPath)
	return hasHandler
}

// GetVCSCheckoutDirectory returns the path of the directory into which the given VCS path will checked out,
// if PerformVCSCheckout is called.
func GetVCSCheckoutDirectory(vcsPath string, pkgCacheRootPath string, vcsDevelopmentDirectories ...string) (string, error) {
	// Parse the VCS path.
	parsedPath, perr := ParseVCSPath(vcsPath)
	if perr != nil {
		return "", perr
	}

	// Check for a local development cache.
	if parsedPath.isRepoOnlyReference() {
		for _, directoryPath := range vcsDevelopmentDirectories {
			fullCheckDirectory := path.Join(directoryPath, parsedPath.url)
			if _, err := os.Stat(fullCheckDirectory); err == nil {
				return fullCheckDirectory, nil
			}
		}
	}

	fullCacheDirectory := path.Join(pkgCacheRootPath, parsedPath.cacheDirectory())
	return fullCacheDirectory, nil
}

// PerformVCSCheckout performs the checkout and updating of the given VCS path and returns
// the local system directory at which the package was checked out.
//
// pkgCacheRootPath holds the path of the root directory that forms the package cache.
//
// vcsDevelopmentDirectories specifies optional directories to check for branchless and tagless copies
// of the repository first. If found, the copy will be used in lieu of a normal checkout.
func PerformVCSCheckout(vcsPath string, pkgCacheRootPath string, vcsDevelopmentDirectories ...string) (string, error, string) {
	// Parse the VCS path.
	parsedPath, perr := ParseVCSPath(vcsPath)
	if perr != nil {
		return "", perr, ""
	}

	var err error
	var warning string

	// Check for a local development cache.
	if parsedPath.isRepoOnlyReference() {
		for _, directoryPath := range vcsDevelopmentDirectories {
			fullCheckDirectory := path.Join(directoryPath, parsedPath.url)
			if _, err := os.Stat(fullCheckDirectory); err == nil {
				// Found a local copy. Returning it.
				log.Printf("Found a local HEAD copy of package %s under development directory %s", parsedPath.url, directoryPath)
				warning = fmt.Sprintf(
					`Package '%s' does not specify a tag, commit or branch and a local copy was found under development directory '%s'. VCS checkout will be skipped and the local copy used instead. To return to normal VCS behavior for this package, remove the --vcs-dev-dir flag or specify the package's tag, commit or branch.`, parsedPath.String(), directoryPath)
				return fullCheckDirectory, nil, warning
			}
		}
	}

	// Conduct the checkout or pull.
	fullCacheDirectory := path.Join(pkgCacheRootPath, parsedPath.cacheDirectory())
	err, warning = checkCacheAndPull(parsedPath, fullCacheDirectory)

	// Warn if the package is a HEAD checkout.
	if err == nil && warning == "" && parsedPath.isHEAD() {
		warning = fmt.Sprintf("Package '%s' points to HEAD of a branch or commit and will be updated on every build", parsedPath.String())
	}

	// If the parsed path is a subdirectory of the checkout, return a reference to it.
	if err == nil && parsedPath.subpackage != "" {
		subpackageCacheDirectory := path.Join(fullCacheDirectory, parsedPath.subpackage)
		if _, serr := os.Stat(subpackageCacheDirectory); os.IsNotExist(serr) {
			return "", fmt.Errorf("Subpackage '%s' does not exist under VCS package '%s'", parsedPath.subpackage, parsedPath.url), warning
		}
		return subpackageCacheDirectory, nil, warning
	}

	return fullCacheDirectory, err, warning
}

// InspectInfo holds all the data returned from a call to PerformVCSCheckoutAndInspect.
type InspectInfo struct {
	CommitSHA string
	Tags      []string
}

// PerformVCSCheckoutAndInspect performs the checkout and updating of the given VCS path and returns
// the commit SHA of the package, as well as its tags.
//
// pkgCacheRootPath holds the path of the root directory that forms the package cache.
//
// vcsDevelopmentDirectories specifies optional directories to check for branchless and tagless copies
// of the repository first. If found, the copy will be used in lieu of a normal checkout.
func PerformVCSCheckoutAndInspect(vcsPath string, pkgCacheRootPath string, vcsDevelopmentDirectories ...string) (InspectInfo, error, string) {
	directory, err, warning := PerformVCSCheckout(vcsPath, pkgCacheRootPath, vcsDevelopmentDirectories...)
	if err != nil {
		return InspectInfo{}, err, warning
	}

	handler, _ := detectHandler(directory)
	sha, err := handler.inspect(directory)
	if err != nil {
		return InspectInfo{}, err, warning
	}

	tags, err := handler.listTags(directory)
	if err != nil {
		return InspectInfo{}, err, warning
	}

	return InspectInfo{sha, tags}, nil, warning
}

// checkCacheAndPull conducts the cache check and necessary pulls.
func checkCacheAndPull(parsedPath vcsPackagePath, fullCacheDirectory string) (error, string) {
	// TODO(jschorr): Should we delete the package cache directory here if there was an error?

	// Check the package cache for the path.
	log.Printf("Checking cache directory %s", fullCacheDirectory)
	if _, err := os.Stat(fullCacheDirectory); os.IsNotExist(err) {
		// Do a full checkout.
		return performFullCheckout(parsedPath, fullCacheDirectory)
	}

	// If the cache exists, we only perform an update to the VCS package if the package
	// is marked as pointing to HEAD of a branch or commit. Tagged VCS packages are always left alone.
	log.Printf("Cache directory %s exists", fullCacheDirectory)
	if parsedPath.isHEAD() {
		return performUpdateCheckout(parsedPath, fullCacheDirectory)
	}

	log.Printf("Cache directory %s exists and points to tag %s; no update needed", fullCacheDirectory, parsedPath.tag)
	return nil, ""
}

// performFullCheckout performs a full VCS checkout of the given package path.
func performFullCheckout(path vcsPackagePath, fullCacheDirectory string) (error, string) {
	// Lookup the VCS discovery information.
	discovery, err := DiscoverVCSInformation(path.url)
	if err != nil {
		return err, ""
	}

	// Perform a full checkout.
	handler, ok := vcsByKind[discovery.Kind]
	if !ok {
		panic("Unknown VCS handler")
	}

	warning, err := handler.checkout(path, discovery, fullCacheDirectory)
	return err, warning
}

// performUpdateCheckout performs a VCS update of the given package path.
func performUpdateCheckout(path vcsPackagePath, fullCacheDirectory string) (error, string) {
	// Detect the kind of VCS based on the checkout.
	handler, ok := detectHandler(fullCacheDirectory)
	if !ok {
		return fmt.Errorf("Could not detect VCS for directory: %s", fullCacheDirectory), ""
	}

	// If the checkout has changes, warn, but nothing more to do.
	if handler.check(fullCacheDirectory) {
		warning := fmt.Sprintf("VCS Package '%s' has changes on the local file system and will therefore not be updated", path.String())
		return nil, warning
	}

	// Otherwise, perform a pull to update.
	err := handler.update(fullCacheDirectory)
	return err, ""
}
<|endoftext|>


<commit_before>//
// Copyright © 2016-2017 Guy M. Allard
//
// 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 stompngo

/*
	Provide package version information.  A nod to the concept of semver.

	Example:
		fmt.Println("current stompngo version", stompngo.Version())

*/

import (
	"fmt"
)

var (
	pref = "v" // Prefix

	major = "1" // Major

	minor = "0" // Minor

	patch = "6" // Patch

	//patch = "6.plvl.001" // Patch
)

func Version() string {
	return fmt.Sprintf("%s%s.%s.%s", pref, major, minor, patch)
}
<commit_msg>Patch level bump.<commit_after>//
// Copyright © 2016-2017 Guy M. Allard
//
// 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 stompngo

/*
	Provide package version information.  A nod to the concept of semver.

	Example:
		fmt.Println("current stompngo version", stompngo.Version())

*/

import (
	"fmt"
)

var (
	pref = "v" // Prefix

	major = "1" // Major

	minor = "0" // Minor

	//patch = "6" // Patch

	patch = "6.plvl.001" // Patch
)

func Version() string {
	return fmt.Sprintf("%s%s.%s.%s", pref, major, minor, patch)
}
<|endoftext|>


<commit_before>// nsq is the official Go package for NSQ (http://nsq.io/)
//
// It provides high-level Consumer and Producer types as well as low-level
// functions to communicate over the NSQ protocol
package nsq

// VERSION
const VERSION = "1.0.4"
<commit_msg>bump v1.0.5-alpha<commit_after>// nsq is the official Go package for NSQ (http://nsq.io/)
//
// It provides high-level Consumer and Producer types as well as low-level
// functions to communicate over the NSQ protocol
package nsq

// VERSION
const VERSION = "1.0.5-alpha"
<|endoftext|>


<commit_before>package main

const (
	// Release is the asset version of the site. Bump when any assets are
	// updated to blow away any browser caches.
	Release = "78"
)
<commit_msg>Bump assets version<commit_after>package main

const (
	// Release is the asset version of the site. Bump when any assets are
	// updated to blow away any browser caches.
	Release = "79"
)
<|endoftext|>


<commit_before>// Package nsq is the official Go package for NSQ (http://nsq.io/)
//
// It provides high-level Consumer and Producer types as well as low-level
// functions to communicate over the NSQ protocol
package nsq

// VERSION
const VERSION = "1.1.5 HA"
<commit_msg>bump version<commit_after>// Package nsq is the official Go package for NSQ (http://nsq.io/)
//
// It provides high-level Consumer and Producer types as well as low-level
// functions to communicate over the NSQ protocol
package nsq

// VERSION
const VERSION = "1.1.6 HA"
<|endoftext|>


<commit_before>// Copyright 2016-2020 The Libsacloud 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 libsacloud

// Version バージョン
const Version = "2.1.4"
<commit_msg>Bump to v2.1.5<commit_after>// Copyright 2016-2020 The Libsacloud 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 libsacloud

// Version バージョン
const Version = "2.1.5"
<|endoftext|>