<commit_before>// Copyright (c) 2012 VMware, Inc.

package main

import (
	"flag"
	"fmt"
	"github.com/cloudfoundry/gonit"
	"log"
	"net/rpc"
	"net/rpc/jsonrpc"
	"net/url"
	"os"
	"os/signal"
	"path/filepath"
	"syscall"
	"time"
)

var (
	// flags
	config     string
	pidfile    string
	rpcUrl     string
	polltime   time.Duration
	group      bool
	foreground bool
	version    bool

	// defaults
	home           = os.Getenv("HOME")
	name           = filepath.Base(os.Args[0]) // gonit
	defaultPidFile = filepath.Join(home, "."+name+".pid")
	defaultRpcUrl  = filepath.Join(home, "."+name+".sock")

	// internal
	api       *gonit.API
	rpcServer *gonit.RpcServer
)

func main() {
	parseFlags()

	if version {
		showVersion()
		return
	}

	configManager := &gonit.ConfigManager{}

	if config != "" {
		err := configManager.Parse(config)
		if err != nil {
			log.Fatal(err)
		}
	}

	api = gonit.NewAPI(configManager)

	args := flag.Args()
	if len(args) == 0 {
		if polltime != 0 {
			runDaemon()
		} else {
			log.Fatal("Nothing todo (yet)")
		}
	} else {
		// example: gonit stop all
		cmd := args[0]
		var arg string
		if len(args) == 2 {
			arg = args[1]
		}
		runCommand(cmd, arg)
	}
}

func parseFlags() {
	flag.BoolVar(&version, "V", false, "Print version number")
	flag.BoolVar(&group, "g", false, "Use process group")
	flag.BoolVar(&foreground, "I", false, "Do not run in background")
	flag.StringVar(&config, "c", "", "Config path")
	// XXX should be able to use gonit.yml for the following opts
	flag.StringVar(&pidfile, "p", defaultPidFile, "Pid file path")
	flag.StringVar(&rpcUrl, "s", defaultRpcUrl, "RPC server URL")
	flag.DurationVar(&polltime, "d", 0, "Run as a daemon with duration")

	flag.Parse()
}

func rpcClient() *rpc.Client {
	url, err := url.Parse(rpcUrl)
	if err != nil {
		log.Fatal(err)
	}

	network := url.Scheme
	if network == "" {
		network = "unix"
	}

	var address string
	if network == "unix" {
		address = url.Path
	} else {
		address = url.Host
	}

	client, err := jsonrpc.Dial(network, address)
	if err != nil {
		log.Fatal(err)
	}

	return client
}

func runCommand(cmd, arg string) {
	var client gonit.CliClient

	if isRunning() {
		rpc := rpcClient()
		defer rpc.Close()
		client = gonit.NewRemoteClient(rpc, api)
	} else {
		client = gonit.NewLocalClient(api)
	}

	method, name := gonit.RpcArgs(cmd, arg, group)

	reply, err := client.Call(method, name)

	if err != nil {
		log.Fatal(err)
	}

	if formatter, ok := reply.(gonit.CliFormatter); ok {
		formatter.Print(os.Stdout)
	} else {
		log.Printf("%#v", reply) // TODO make perty
	}
}

func reload() {
	log.Printf("XXX reload config")
}

func wakeup() {
	log.Printf("XXX wakeup")
}

func shutdown() {
	log.Printf("Quit")

	if rpcServer != nil {
		rpcServer.Shutdown()
	}

	os.Exit(0)
}

func start() {
	var err error

	rpcServer, err = gonit.NewRpcServer(rpcUrl)
	if err != nil {
		log.Fatal(err)
	}

	rpc.Register(api)

	go rpcServer.Serve()
}

var handlers = map[syscall.Signal]func(){
	syscall.SIGTERM: shutdown,
	syscall.SIGINT:  shutdown,
	syscall.SIGHUP:  reload,
	syscall.SIGUSR1: wakeup,
}

func loop() {
	sigchan := make(chan os.Signal, 1)
	for sig, _ := range handlers {
		signal.Notify(sigchan, sig)
	}

	for {
		select {
		case signal := <-sigchan:
			sig, _ := signal.(syscall.Signal)
			if handler, ok := handlers[sig]; ok {
				handler()
			}
		}
	}
}

func isRunning() bool {
	pid, err := gonit.ReadPidFile(pidfile)

	return err == nil && syscall.Kill(pid, 0) == nil
}

func runDaemon() {
	if isRunning() {
		log.Fatalf("%s daemon is already running", name)
	}

	if !foreground {
		log.Print("daemonize - not yet supported")
	}

	log.Printf("Saving %s daemon pid to file=%s", name, pidfile)
	err := gonit.WritePidFile(os.Getpid(), pidfile)
	if err != nil {
		log.Fatal(err)
	}
	defer os.Remove(pidfile)

	start()
	loop()
}

func showVersion() {
	fmt.Printf("Gonit version %s\n", gonit.VERSION)
}
<commit_msg>Improve usage (help) message<commit_after>// Copyright (c) 2012 VMware, Inc.

package main

import (
	"flag"
	"fmt"
	"github.com/cloudfoundry/gonit"
	"log"
	"net/rpc"
	"net/rpc/jsonrpc"
	"net/url"
	"os"
	"os/signal"
	"path/filepath"
	"syscall"
	"time"
)

var (
	// flags
	config     string
	pidfile    string
	rpcUrl     string
	polltime   time.Duration
	group      bool
	foreground bool
	version    bool

	// defaults
	home           = os.Getenv("HOME")
	name           = filepath.Base(os.Args[0]) // gonit
	defaultPidFile = filepath.Join(home, "."+name+".pid")
	defaultRpcUrl  = filepath.Join(home, "."+name+".sock")

	// internal
	api       *gonit.API
	rpcServer *gonit.RpcServer
)

func main() {
	parseFlags()

	if version {
		showVersion()
		return
	}

	configManager := &gonit.ConfigManager{}

	if config != "" {
		err := configManager.Parse(config)
		if err != nil {
			log.Fatal(err)
		}
	}

	api = gonit.NewAPI(configManager)

	args := flag.Args()
	if len(args) == 0 {
		if polltime != 0 {
			runDaemon()
		} else {
			log.Fatal("Nothing todo (yet)")
		}
	} else {
		// example: gonit stop all
		cmd := args[0]
		var arg string
		if len(args) == 2 {
			arg = args[1]
		}
		runCommand(cmd, arg)
	}
}

func parseFlags() {
	flag.BoolVar(&version, "V", false, "Print version number")
	flag.BoolVar(&group, "g", false, "Use process group")
	flag.BoolVar(&foreground, "I", false, "Do not run in background")
	flag.StringVar(&config, "c", "", "Config path")
	// XXX should be able to use gonit.yml for the following opts
	flag.StringVar(&pidfile, "p", defaultPidFile, "Pid file path")
	flag.StringVar(&rpcUrl, "s", defaultRpcUrl, "RPC server URL")
	flag.DurationVar(&polltime, "d", 0, "Run as a daemon with duration")

	const named = "the named process or group"
	const all = "all processes"

	actions := []struct {
		usage       string
		description string
		what        string
	}{
		{"start all", "Start", all},
		{"start name", "Only start", named},
		{"stop all", "Stop", all},
		{"stop name", "Only stop", named},
		{"restart all", "Restart", all},
		{"restart name", "Only restart", named},
		{"monitor all", "Enable monitoring for", all},
		{"monitor name", "Only enable monitoring of", named},
		{"unmonitor all", "Disable monitoring for", all},
		{"unmonitor name", "Only disable monitoring of", named},
		{"status all", "Print full status info for", all},
		{"status name", "Only print short status info for", named},
		{"summary", "Print short status information for", all},
	}

	flag.Usage = func() {
		fmt.Println("Usage:", name, "[options] {arguments}")

		fmt.Println("Options are as follows:")
		flag.PrintDefaults()

		fmt.Println("Optional action arguments are as follows:")
		for _, action := range actions {
			fmt.Printf("  %-20s - %s %s\n", action.usage,
				action.description, action.what)
		}
	}

	flag.Parse()
}

func rpcClient() *rpc.Client {
	url, err := url.Parse(rpcUrl)
	if err != nil {
		log.Fatal(err)
	}

	network := url.Scheme
	if network == "" {
		network = "unix"
	}

	var address string
	if network == "unix" {
		address = url.Path
	} else {
		address = url.Host
	}

	client, err := jsonrpc.Dial(network, address)
	if err != nil {
		log.Fatal(err)
	}

	return client
}

func runCommand(cmd, arg string) {
	var client gonit.CliClient

	if isRunning() {
		rpc := rpcClient()
		defer rpc.Close()
		client = gonit.NewRemoteClient(rpc, api)
	} else {
		client = gonit.NewLocalClient(api)
	}

	method, name := gonit.RpcArgs(cmd, arg, group)

	reply, err := client.Call(method, name)

	if err != nil {
		log.Fatal(err)
	}

	if formatter, ok := reply.(gonit.CliFormatter); ok {
		formatter.Print(os.Stdout)
	} else {
		log.Printf("%#v", reply) // TODO make perty
	}
}

func reload() {
	log.Printf("XXX reload config")
}

func wakeup() {
	log.Printf("XXX wakeup")
}

func shutdown() {
	log.Printf("Quit")

	if rpcServer != nil {
		rpcServer.Shutdown()
	}

	os.Exit(0)
}

func start() {
	var err error

	rpcServer, err = gonit.NewRpcServer(rpcUrl)
	if err != nil {
		log.Fatal(err)
	}

	rpc.Register(api)

	go rpcServer.Serve()
}

var handlers = map[syscall.Signal]func(){
	syscall.SIGTERM: shutdown,
	syscall.SIGINT:  shutdown,
	syscall.SIGHUP:  reload,
	syscall.SIGUSR1: wakeup,
}

func loop() {
	sigchan := make(chan os.Signal, 1)
	for sig, _ := range handlers {
		signal.Notify(sigchan, sig)
	}

	for {
		select {
		case signal := <-sigchan:
			sig, _ := signal.(syscall.Signal)
			if handler, ok := handlers[sig]; ok {
				handler()
			}
		}
	}
}

func isRunning() bool {
	pid, err := gonit.ReadPidFile(pidfile)

	return err == nil && syscall.Kill(pid, 0) == nil
}

func runDaemon() {
	if isRunning() {
		log.Fatalf("%s daemon is already running", name)
	}

	if !foreground {
		log.Print("daemonize - not yet supported")
	}

	log.Printf("Saving %s daemon pid to file=%s", name, pidfile)
	err := gonit.WritePidFile(os.Getpid(), pidfile)
	if err != nil {
		log.Fatal(err)
	}
	defer os.Remove(pidfile)

	start()
	loop()
}

func showVersion() {
	fmt.Printf("Gonit version %s\n", gonit.VERSION)
}
<|endoftext|>


<commit_before>// Package edit implements the line editor for Elvish.
//
// The line editor is based on the cli package, which implements a general,
// Elvish-agnostic line editor, and multiple "addon" packages. This package
// glues them together and provides Elvish bindings for them.
package edit

import (
	"fmt"
	"os"
	"strings"
	"sync"

	"github.com/elves/elvish/pkg/cli"
	"github.com/elves/elvish/pkg/cli/histutil"
	"github.com/elves/elvish/pkg/eval"
	"github.com/elves/elvish/pkg/eval/vals"
	"github.com/elves/elvish/pkg/eval/vars"
	"github.com/elves/elvish/pkg/parse"
	"github.com/elves/elvish/pkg/store"
)

// Editor is the interface line editor for Elvish.
type Editor struct {
	app cli.App
	ns  eval.Ns

	excMutex sync.RWMutex
	excList  vals.List
}

// An interface that wraps notifyf and notifyError. It is only implemented by
// the *Editor type; functions may take a notifier instead of *Editor argument
// to make it clear that they do not depend on other parts of *Editor.
type notifier interface {
	notifyf(format string, args ...interface{})
	notifyError(ctx string, e error)
}

// NewEditor creates a new editor from input and output terminal files.
func NewEditor(tty cli.TTY, ev *eval.Evaler, st store.Store) *Editor {
	appSpec := cli.AppSpec{TTY: tty}

	fuser, err := histutil.NewFuser(st)
	if err != nil {
		// TODO(xiaq): Report the error.
	}

	if fuser != nil {
		appSpec.AfterReadline = []func(string){func(code string) {
			if code != "" && !strings.HasPrefix(code, " ") {
				fuser.AddCmd(code)
			}
			// TODO(xiaq): Handle the error.
		}}
	}

	// Declare the Editor with a nil App first; some initialization functions
	// require a notifier as an argument, but does not use it immediately.
	ed := &Editor{ns: eval.Ns{}, excList: vals.EmptyList}
	initHighlighter(&appSpec, ev)
	initConfigAPI(&appSpec, ev, ed.ns)
	initInsertAPI(&appSpec, ed, ev, ed.ns)
	initPrompts(&appSpec, ed, ev, ed.ns)
	ed.app = cli.NewApp(appSpec)

	initExceptionsAPI(ed)
	initCommandAPI(ed, ev)
	initListings(ed, ev, st, fuser)
	initNavigation(ed, ev)
	initCompletion(ed, ev)
	initHistWalk(ed, ev, fuser)
	initInstant(ed, ev)
	initMinibuf(ed, ev)

	initBufferBuiltins(ed.app, ed.ns)
	initTTYBuiltins(ed.app, tty, ed.ns)
	initMiscBuiltins(ed.app, ed.ns)
	initStateAPI(ed.app, ed.ns)
	initStoreAPI(ed.app, ed.ns, fuser)
	evalDefaultBinding(ev, ed.ns)

	return ed
}

//elvdoc:var exceptions
//
// A list of exceptions thrown from callbacks such as prompts. Useful for
// examining tracebacks and other metadata.

func initExceptionsAPI(ed *Editor) {
	ed.ns.Add("exceptions", vars.FromPtrWithMutex(&ed.excList, &ed.excMutex))
}

func evalDefaultBinding(ev *eval.Evaler, ns eval.Ns) {
	// TODO(xiaq): The evaler API should accodomate the use case of evaluating a
	// piece of code in an alternative global namespace.

	src := parse.Source{Name: "[default bindings]", Code: defaultBindingsElv}
	tree, err := parse.Parse(src)
	if err != nil {
		panic(err)
	}
	op, err := ev.CompileWithGlobal(tree, ns, nil)
	if err != nil {
		panic(err)
	}
	// TODO(xiaq): Use stdPorts when it is possible to do so.
	fm := eval.NewTopFrame(ev, src, []*eval.Port{
		{File: os.Stdin}, {File: os.Stdout}, {File: os.Stderr},
	})
	fm.SetLocal(ns)
	err = fm.Eval(op)
	if err != nil {
		panic(err)
	}
}

// ReadCode reads input from the user.
func (ed *Editor) ReadCode() (string, error) {
	return ed.app.ReadCode()
}

// Ns returns a namespace for manipulating the editor from Elvish code.
func (ed *Editor) Ns() eval.Ns {
	return ed.ns
}

func (ed *Editor) notify(s string) { ed.app.Notify(s) }

func (ed *Editor) notifyf(format string, args ...interface{}) {
	ed.app.Notify(fmt.Sprintf(format, args...))
}

func (ed *Editor) notifyError(ctx string, e error) {
	ed.notifyf("[%v error] %v", ctx, e)
	if exc, ok := e.(*eval.Exception); ok {
		ed.excMutex.Lock()
		defer ed.excMutex.Unlock()
		ed.excList = ed.excList.Cons(exc)
		ed.notifyf(`see stack trace with "use exc; exc:show $edit:exceptions[%d]"`,
			ed.excList.Len()-1)
	}
}
<commit_msg>pkg/edit: Always show errors in one notification.<commit_after>// Package edit implements the line editor for Elvish.
//
// The line editor is based on the cli package, which implements a general,
// Elvish-agnostic line editor, and multiple "addon" packages. This package
// glues them together and provides Elvish bindings for them.
package edit

import (
	"fmt"
	"os"
	"strings"
	"sync"

	"github.com/elves/elvish/pkg/cli"
	"github.com/elves/elvish/pkg/cli/histutil"
	"github.com/elves/elvish/pkg/eval"
	"github.com/elves/elvish/pkg/eval/vals"
	"github.com/elves/elvish/pkg/eval/vars"
	"github.com/elves/elvish/pkg/parse"
	"github.com/elves/elvish/pkg/store"
)

// Editor is the interface line editor for Elvish.
type Editor struct {
	app cli.App
	ns  eval.Ns

	excMutex sync.RWMutex
	excList  vals.List
}

// An interface that wraps notifyf and notifyError. It is only implemented by
// the *Editor type; functions may take a notifier instead of *Editor argument
// to make it clear that they do not depend on other parts of *Editor.
type notifier interface {
	notifyf(format string, args ...interface{})
	notifyError(ctx string, e error)
}

// NewEditor creates a new editor from input and output terminal files.
func NewEditor(tty cli.TTY, ev *eval.Evaler, st store.Store) *Editor {
	appSpec := cli.AppSpec{TTY: tty}

	fuser, err := histutil.NewFuser(st)
	if err != nil {
		// TODO(xiaq): Report the error.
	}

	if fuser != nil {
		appSpec.AfterReadline = []func(string){func(code string) {
			if code != "" && !strings.HasPrefix(code, " ") {
				fuser.AddCmd(code)
			}
			// TODO(xiaq): Handle the error.
		}}
	}

	// Declare the Editor with a nil App first; some initialization functions
	// require a notifier as an argument, but does not use it immediately.
	ed := &Editor{ns: eval.Ns{}, excList: vals.EmptyList}
	initHighlighter(&appSpec, ev)
	initConfigAPI(&appSpec, ev, ed.ns)
	initInsertAPI(&appSpec, ed, ev, ed.ns)
	initPrompts(&appSpec, ed, ev, ed.ns)
	ed.app = cli.NewApp(appSpec)

	initExceptionsAPI(ed)
	initCommandAPI(ed, ev)
	initListings(ed, ev, st, fuser)
	initNavigation(ed, ev)
	initCompletion(ed, ev)
	initHistWalk(ed, ev, fuser)
	initInstant(ed, ev)
	initMinibuf(ed, ev)

	initBufferBuiltins(ed.app, ed.ns)
	initTTYBuiltins(ed.app, tty, ed.ns)
	initMiscBuiltins(ed.app, ed.ns)
	initStateAPI(ed.app, ed.ns)
	initStoreAPI(ed.app, ed.ns, fuser)
	evalDefaultBinding(ev, ed.ns)

	return ed
}

//elvdoc:var exceptions
//
// A list of exceptions thrown from callbacks such as prompts. Useful for
// examining tracebacks and other metadata.

func initExceptionsAPI(ed *Editor) {
	ed.ns.Add("exceptions", vars.FromPtrWithMutex(&ed.excList, &ed.excMutex))
}

func evalDefaultBinding(ev *eval.Evaler, ns eval.Ns) {
	// TODO(xiaq): The evaler API should accodomate the use case of evaluating a
	// piece of code in an alternative global namespace.

	src := parse.Source{Name: "[default bindings]", Code: defaultBindingsElv}
	tree, err := parse.Parse(src)
	if err != nil {
		panic(err)
	}
	op, err := ev.CompileWithGlobal(tree, ns, nil)
	if err != nil {
		panic(err)
	}
	// TODO(xiaq): Use stdPorts when it is possible to do so.
	fm := eval.NewTopFrame(ev, src, []*eval.Port{
		{File: os.Stdin}, {File: os.Stdout}, {File: os.Stderr},
	})
	fm.SetLocal(ns)
	err = fm.Eval(op)
	if err != nil {
		panic(err)
	}
}

// ReadCode reads input from the user.
func (ed *Editor) ReadCode() (string, error) {
	return ed.app.ReadCode()
}

// Ns returns a namespace for manipulating the editor from Elvish code.
func (ed *Editor) Ns() eval.Ns {
	return ed.ns
}

func (ed *Editor) notify(s string) { ed.app.Notify(s) }

func (ed *Editor) notifyf(format string, args ...interface{}) {
	ed.app.Notify(fmt.Sprintf(format, args...))
}

func (ed *Editor) notifyError(ctx string, e error) {
	if exc, ok := e.(*eval.Exception); ok {
		ed.excMutex.Lock()
		defer ed.excMutex.Unlock()
		ed.excList = ed.excList.Cons(exc)
		ed.notifyf("[%v error] %v\n"+
			`see stack trace with "use exc; exc:show $edit:exceptions[%d]"`,
			ctx, e, ed.excList.Len()-1)
	} else {
		ed.notifyf("[%v error] %v", ctx, e)
	}
}
<|endoftext|>


<commit_before>package fs

import (
	"os"
	"path"
)

const (
	swanPkg = "github.com/intelsdi-x/athena"
)

// GetSwanPath returns absolute path to Swan root directory.
func GetSwanPath() string {
	return path.Join(os.Getenv("GOPATH"), "src", swanPkg)
}

// GetSwanBuildPath returns absolute path to Swan build directory.
func GetSwanBuildPath() string {
	return path.Join(os.Getenv("GOPATH"), "src", swanPkg, "build")
}

// GetSwanWorkloadsPath returns absolute path to Swan workloads directory.
func GetSwanWorkloadsPath() string {
	return path.Join(os.Getenv("GOPATH"), "src", swanPkg, "workloads")
}

// GetSwanExperimentPath returns absolute path to Swan experiment directory.
func GetSwanExperimentPath() string {
	return path.Join(os.Getenv("GOPATH"), "src", swanPkg, "experiments")
}

// GetSwanBinPath returns absolute path to Swan misc/bin directory.
func GetSwanBinPath() string {
	return path.Join(os.Getenv("GOPATH"), "src", swanPkg, "misc", "bin")
}
<commit_msg>Split: we need this path to point at Swan<commit_after>package fs

import (
	"os"
	"path"
)

const (
	//TODO: refactor this; it needs to be project agnostic
	swanPkg = "github.com/intelsdi-x/swan"
)

// GetSwanPath returns absolute path to Swan root directory.
func GetSwanPath() string {
	return path.Join(os.Getenv("GOPATH"), "src", swanPkg)
}

// GetSwanBuildPath returns absolute path to Swan build directory.
func GetSwanBuildPath() string {
	return path.Join(os.Getenv("GOPATH"), "src", swanPkg, "build")
}

// GetSwanWorkloadsPath returns absolute path to Swan workloads directory.
func GetSwanWorkloadsPath() string {
	return path.Join(os.Getenv("GOPATH"), "src", swanPkg, "workloads")
}

// GetSwanExperimentPath returns absolute path to Swan experiment directory.
func GetSwanExperimentPath() string {
	return path.Join(os.Getenv("GOPATH"), "src", swanPkg, "experiments")
}

// GetSwanBinPath returns absolute path to Swan misc/bin directory.
func GetSwanBinPath() string {
	return path.Join(os.Getenv("GOPATH"), "src", swanPkg, "misc", "bin")
}
<|endoftext|>


<commit_before>package pkger

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
)

var prettyGitHashGetArgs = []string{"log", "-n", "1", "--pretty=format:'%H'"}

type PkgInfo struct {
	CommitHash string
	GoVersion  string
	OsInfo     string
}

func (p *PkgInfo) String() string {
	return fmt.Sprintf("Commit Hash: %s\nGo Version: %s\nOS: %s",
		p.CommitHash, p.GoVersion, p.OsInfo)
}

func goSrcify(p string) string {
	goPath := os.Getenv("GOPATH")
	return filepath.Join(goPath, "src", p)
}

var GoSrcify = goSrcify

func Recon(pkgPath string) (pkgInfo *PkgInfo, err error) {
	var gitProgPath, pkgPathAbs string

	// Firstly look up if they've got Git
	gitProgPath, err = exec.LookPath("git")
	if err != nil {
		return
	}

	pkgPathAbs = goSrcify(pkgPath)

	args := []string{gitProgPath}
	args = append(args, prettyGitHashGetArgs...)

	cmd := exec.Cmd{
		Args: args,
		Dir:  pkgPathAbs,
		Path: gitProgPath,
	}

	var output []byte
	if output, err = cmd.Output(); err != nil {
		return
	}

	pkgInfo = &PkgInfo{
		CommitHash: string(output),
		OsInfo:     strings.Join([]string{runtime.GOOS, runtime.GOARCH}, "/"),
		GoVersion:  runtime.Version(),
	}

	return
}
<commit_msg>pkger: add BuildTime field<commit_after>package pkger

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

var prettyGitHashGetArgs = []string{"log", "-n", "1", "--pretty=format:'%H'"}

type PkgInfo struct {
	CommitHash string
	GoVersion  string
	OsInfo     string
	BuildTime  string
}

func (p *PkgInfo) String() string {
	return fmt.Sprintf("Commit Hash: %s\nGo Version: %s\nOS: %s\nBuildTime: %v",
		p.CommitHash, p.GoVersion, p.OsInfo, p.BuildTime)
}

func goSrcify(p string) string {
	goPath := os.Getenv("GOPATH")
	return filepath.Join(goPath, "src", p)
}

var GoSrcify = goSrcify

func Recon(pkgPath string) (pkgInfo *PkgInfo, err error) {
	var gitProgPath, pkgPathAbs string

	// Firstly look up if they've got Git
	gitProgPath, err = exec.LookPath("git")
	if err != nil {
		return
	}

	pkgPathAbs = goSrcify(pkgPath)

	args := []string{gitProgPath}
	args = append(args, prettyGitHashGetArgs...)

	cmd := exec.Cmd{
		Args: args,
		Dir:  pkgPathAbs,
		Path: gitProgPath,
	}

	var output []byte
	if output, err = cmd.Output(); err != nil {
		return
	}

	pkgInfo = &PkgInfo{
		CommitHash: string(output),
		OsInfo:     strings.Join([]string{runtime.GOOS, runtime.GOARCH}, "/"),
		GoVersion:  runtime.Version(),
		BuildTime:  time.Now().String(),
	}

	return
}
<|endoftext|>


<commit_before>package aws

import (
	"io/ioutil"
	"os"
	"path"

	"path/filepath"
	"sync"

	"io"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/hashicorp/go-multierror"
)

// S3BulkUploadTask uploads local files in src dir into s3 dst folder.
type S3BulkUploadTask struct {
	Session     *session.Session
	SrcDir      string
	S3DstFolder string
	Bucket      string
}

// NewS3BulkUploadTask creates a s3 bulk upload task.
func NewS3BulkUploadTask(sess *session.Session, srcDir, s3DstDir, bucket string) *S3BulkUploadTask {
	return &S3BulkUploadTask{
		Session:     sess,
		SrcDir:      srcDir,
		S3DstFolder: s3DstDir,
		Bucket:      bucket,
	}
}

// Execute implement Task.Execute
func (up *S3BulkUploadTask) Execute() error {
	files, err := readFilesInDir(up.SrcDir)
	if err != nil {
		return err
	}

	svc := s3.New(up.Session)

	wg := sync.WaitGroup{}
	errChan := make(chan error)
	for _, info := range files {
		wg.Add(1)
		go func(info os.FileInfo) {
			defer wg.Done()

			srcFile := filepath.Join(up.SrcDir, info.Name())
			dstS3Key := path.Join(up.S3DstFolder, info.Name())
			file, err := os.Open(srcFile)
			if err != nil {
				errChan <- err
				return
			}
			defer file.Close()

			_, err = putObject(svc, &s3.PutObjectInput{
				Key:    aws.String(dstS3Key),
				Bucket: aws.String(up.Bucket),
				Body:   file,
			})
			if err != nil {
				errChan <- err
			}
		}(info)
	}

	resultChan := make(chan error)
	go func() {
		var result *multierror.Error
		for err := range errChan {
			result = multierror.Append(result, err)
		}
		resultChan <- result.ErrorOrNil()
	}()

	wg.Wait()
	close(errChan)

	return <-resultChan
}

func readFilesInDir(dir string) ([]os.FileInfo, error) {
	entries, err := ioutil.ReadDir(dir)
	if err != nil {
		return nil, err
	}

	files := make([]os.FileInfo, 0, len(entries))
	for _, e := range entries {
		if e.IsDir() {
			continue
		}
		files = append(files, e)
	}

	return files, nil
}

// for mock testing
var putObject = func(svc *s3.S3, input *s3.PutObjectInput) (*s3.PutObjectOutput, error) {
	return svc.PutObject(input)
}

// S3BulkDownloadTask downloads files in s3 folder into local dst dir.
type S3BulkDownloadTask struct {
	Session     *session.Session
	S3SrcFolder string
	DstDir      string
	Bucket      string
}

// NewS3BulkDownloadTask creates a s3 bulk download task.
func NewS3BulkDownloadTask(sess *session.Session, s3SrcFolder, dstDir, bucket string) *S3BulkDownloadTask {
	return &S3BulkDownloadTask{
		Session:     sess,
		S3SrcFolder: s3SrcFolder,
		DstDir:      dstDir,
		Bucket:      bucket,
	}
}

// Execute implement Task.Execute.
func (down *S3BulkDownloadTask) Execute() error {
	svc := s3.New(down.Session)

	list, err := listObjectsV2(svc, &s3.ListObjectsV2Input{
		Bucket:    aws.String(down.Bucket),
		Delimiter: aws.String("/"),
		Prefix:    aws.String(down.S3SrcFolder),
	})
	if err != nil {
		return err
	}

	wg := sync.WaitGroup{}
	errChan := make(chan error)
	for _, c := range list.Contents {
		wg.Add(1)
		go func(c *s3.Object) {
			defer wg.Done()

			out, err := getObject(svc, &s3.GetObjectInput{
				Key:    c.Key,
				Bucket: aws.String(down.Bucket),
			})
			if err != nil {
				errChan <- err
				return
			}

			dstPath := filepath.Join(down.DstDir, path.Base(*c.Key))
			file, err := os.Create(dstPath)
			if err != nil {
				errChan <- err
				return
			}
			defer file.Close()

			_, err = io.Copy(file, out.Body)
			if err != nil {
				errChan <- err
			}
		}(c)
	}

	resultChan := make(chan error)
	go func() {
		var result *multierror.Error
		for err := range errChan {
			result = multierror.Append(result, err)
		}
		resultChan <- result.ErrorOrNil()
	}()

	wg.Wait()
	close(errChan)

	return <-resultChan
}

// for mock testing
var getObject = func(svc *s3.S3, input *s3.GetObjectInput) (*s3.GetObjectOutput, error) {
	return svc.GetObject(input)
}
var listObjectsV2 = func(svc *s3.S3, input *s3.ListObjectsV2Input) (*s3.ListObjectsV2Output, error) {
	return svc.ListObjectsV2(input)
}
<commit_msg>Fix specify s3 folder<commit_after>package aws

import (
	"io/ioutil"
	"os"
	"path"

	"path/filepath"
	"sync"

	"io"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/hashicorp/go-multierror"
)

// S3BulkUploadTask uploads local files in src dir into s3 dst folder.
type S3BulkUploadTask struct {
	Session     *session.Session
	SrcDir      string
	S3DstFolder string
	Bucket      string
}

// NewS3BulkUploadTask creates a s3 bulk upload task.
func NewS3BulkUploadTask(sess *session.Session, srcDir, s3DstDir, bucket string) *S3BulkUploadTask {
	return &S3BulkUploadTask{
		Session:     sess,
		SrcDir:      srcDir,
		S3DstFolder: s3DstDir,
		Bucket:      bucket,
	}
}

// Execute implement Task.Execute
func (up *S3BulkUploadTask) Execute() error {
	files, err := readFilesInDir(up.SrcDir)
	if err != nil {
		return err
	}

	svc := s3.New(up.Session)

	wg := sync.WaitGroup{}
	errChan := make(chan error)
	for _, info := range files {
		wg.Add(1)
		go func(info os.FileInfo) {
			defer wg.Done()

			srcFile := filepath.Join(up.SrcDir, info.Name())
			dstS3Key := path.Join(up.S3DstFolder, info.Name())
			file, err := os.Open(srcFile)
			if err != nil {
				errChan <- err
				return
			}
			defer file.Close()

			_, err = putObject(svc, &s3.PutObjectInput{
				Key:    aws.String(dstS3Key),
				Bucket: aws.String(up.Bucket),
				Body:   file,
			})
			if err != nil {
				errChan <- err
			}
		}(info)
	}

	resultChan := make(chan error)
	go func() {
		var result *multierror.Error
		for err := range errChan {
			result = multierror.Append(result, err)
		}
		resultChan <- result.ErrorOrNil()
	}()

	wg.Wait()
	close(errChan)

	return <-resultChan
}

func readFilesInDir(dir string) ([]os.FileInfo, error) {
	entries, err := ioutil.ReadDir(dir)
	if err != nil {
		return nil, err
	}

	files := make([]os.FileInfo, 0, len(entries))
	for _, e := range entries {
		if e.IsDir() {
			continue
		}
		files = append(files, e)
	}

	return files, nil
}

// for mock testing
var putObject = func(svc *s3.S3, input *s3.PutObjectInput) (*s3.PutObjectOutput, error) {
	return svc.PutObject(input)
}

// S3BulkDownloadTask downloads files in s3 folder into local dst dir.
type S3BulkDownloadTask struct {
	Session     *session.Session
	S3SrcFolder string
	DstDir      string
	Bucket      string
}

// NewS3BulkDownloadTask creates a s3 bulk download task.
func NewS3BulkDownloadTask(sess *session.Session, s3SrcFolder, dstDir, bucket string) *S3BulkDownloadTask {
	return &S3BulkDownloadTask{
		Session:     sess,
		S3SrcFolder: s3SrcFolder,
		DstDir:      dstDir,
		Bucket:      bucket,
	}
}

// Execute implement Task.Execute.
func (down *S3BulkDownloadTask) Execute() error {
	svc := s3.New(down.Session)

	list, err := listObjectsV2(svc, &s3.ListObjectsV2Input{
		Bucket:    aws.String(down.Bucket),
		Delimiter: aws.String("/"),
		Prefix:    aws.String(down.S3SrcFolder + "/"),
	})
	if err != nil {
		return err
	}

	wg := sync.WaitGroup{}
	errChan := make(chan error)
	for _, c := range list.Contents {
		wg.Add(1)
		go func(c *s3.Object) {
			defer wg.Done()

			out, err := getObject(svc, &s3.GetObjectInput{
				Key:    c.Key,
				Bucket: aws.String(down.Bucket),
			})
			if err != nil {
				errChan <- err
				return
			}

			dstPath := filepath.Join(down.DstDir, path.Base(*c.Key))
			file, err := os.Create(dstPath)
			if err != nil {
				errChan <- err
				return
			}
			defer file.Close()

			_, err = io.Copy(file, out.Body)
			if err != nil {
				errChan <- err
			}
		}(c)
	}

	resultChan := make(chan error)
	go func() {
		var result *multierror.Error
		for err := range errChan {
			result = multierror.Append(result, err)
		}
		resultChan <- result.ErrorOrNil()
	}()

	wg.Wait()
	close(errChan)

	return <-resultChan
}

// for mock testing
var getObject = func(svc *s3.S3, input *s3.GetObjectInput) (*s3.GetObjectOutput, error) {
	return svc.GetObject(input)
}
var listObjectsV2 = func(svc *s3.S3, input *s3.ListObjectsV2Input) (*s3.ListObjectsV2Output, error) {
	return svc.ListObjectsV2(input)
}
<|endoftext|>


<commit_before>//+build ignore

package main

import (
	"bytes"
	"errors"
	"go/ast"
	"go/parser"
	"go/printer"
	"go/token"
	"io/ioutil"
	"log"
	"strconv"
)

func AddImportToFile(file, imprt string) ([]byte, error) {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, file, nil, parser.ParseComments)
	if err != nil {
		return nil, err
	}

	for _, s := range f.Imports {
		iSpec := &ast.ImportSpec{Path: &ast.BasicLit{Value: s.Path.Value}}
		if iSpec.Path.Value == strconv.Quote(imprt) {
			return nil, errors.New("coredns import already found")
		}
	}

	for i := 0; i < len(f.Decls); i++ {
		d := f.Decls[i]

		switch d.(type) {
		case *ast.FuncDecl:
			// No action
		case *ast.GenDecl:
			dd := d.(*ast.GenDecl)

			// IMPORT Declarations
			if dd.Tok == token.IMPORT {
				// Add the new import
				iSpec := &ast.ImportSpec{Name: &ast.Ident{Name: "_"}, Path: &ast.BasicLit{Value: strconv.Quote(imprt)}}
				dd.Specs = append(dd.Specs, iSpec)
				break
			}
		}
	}

	ast.SortImports(fset, f)

	out, err := GenerateFile(fset, f)
	return out, err
}

func GenerateFile(fset *token.FileSet, file *ast.File) ([]byte, error) {
	var output []byte
	buffer := bytes.NewBuffer(output)
	if err := printer.Fprint(buffer, fset, file); err != nil {
		return nil, err
	}

	return buffer.Bytes(), nil
}

const (
	coredns = "github.com/miekg/coredns/core"
	// If everything is OK and we are sitting in CoreDNS' dir, this is where run.go should be.
	caddyrun = "../../mholt/caddy/caddy/caddymain/run.go"
)

func main() {
	out, err := AddImportToFile(caddyrun, coredns)
	if err != nil {
		log.Printf("failed to add import: %s", err)
		return
	}
	if err := ioutil.WriteFile(caddyrun, out, 0644); err != nil {
		log.Fatalf("failed to write go file: %s", err)
	}
}
<commit_msg>Use go/ast for adding coredns (#228)<commit_after>//+build ignore

package main

import (
	"bytes"
	"go/ast"
	"go/parser"
	"go/printer"
	"go/token"
	"io/ioutil"
	"log"

	"golang.org/x/tools/go/ast/astutil"
)

func GenerateFile(fset *token.FileSet, file *ast.File) ([]byte, error) {
	var output []byte
	buffer := bytes.NewBuffer(output)
	if err := printer.Fprint(buffer, fset, file); err != nil {
		return nil, err
	}

	return buffer.Bytes(), nil
}

func main() {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, caddyrun, nil, parser.ParseComments)
	if err != nil {
		log.Fatalf("failed to parse %s: %s", caddyrun, err)
	}
	astutil.AddNamedImport(fset, f, "_", coredns)
	astutil.DeleteNamedImport(fset, f, "_", caddy)

	out, err := GenerateFile(fset, f)
	if err := ioutil.WriteFile(caddyrun, out, 0644); err != nil {
		log.Fatalf("failed to write go file: %s", err)
	}
}

const (
	coredns = "github.com/miekg/coredns/core"
	caddy   = "github.com/mholt/caddy/caddyhttp"

	// If everything is OK and we are sitting in CoreDNS' dir, this is where run.go should be.
	caddyrun = "../../mholt/caddy/caddy/caddymain/run.go"
)
<|endoftext|>


<commit_before>package plugins

import (
	"ircclient"
	"fmt"
	"log"
	"strings"
)

type Greeter struct {
	ic *ircclient.IRCClient
}

func (g *Greeter) Register(ic *ircclient.IRCClient) {
	g.ic = ic
}

func (g *Greeter) String() string {
	return "greeter"
}

func (g *Greeter) Info() string {
	return "greets everyone joining a channel"
}

func (g *Greeter) ProcessLine(msg *ircclient.IRCMessage) {
	if msg.Command != "JOIN" { // TODO: numeric command
		return
	}
	just_nick := strings.SplitN(msg.Source, "!", 2)[0]
	c, exists := g.ic.GetPlugin("config")
	if !exists {
		log.Println("plugin \"config\" doesn't exist")
		return
	}
	conf, _ := c.(*ircclient.ConfigPlugin)
	conf.Lock() // muss ich bei read-only garned, oder?
	our_nick, _ := conf.Conf.String("Server", "nick")
	conf.Unlock()

	if just_nick == our_nick { // don't welcome ourselves
		log.Println("o: " + our_nick + ", j: " + just_nick)
		return
	}
	ret := fmt.Sprintf("PRIVMSG %s :hi %s", msg.Target, just_nick)
	//log.Println("greeter ret: " + ret)
	g.ic.SendLine(ret)
}

func (g *Greeter) ProcessCommand(cmd *ircclient.IRCCommand) {
	return
}

func (g *Greeter) Unregister() {
	// nothing to do here
}
<commit_msg>Removed useless TODO<commit_after>package plugins

import (
	"ircclient"
	"fmt"
	"log"
	"strings"
)

type Greeter struct {
	ic *ircclient.IRCClient
}

func (g *Greeter) Register(ic *ircclient.IRCClient) {
	g.ic = ic
}

func (g *Greeter) String() string {
	return "greeter"
}

func (g *Greeter) Info() string {
	return "greets everyone joining a channel"
}

func (g *Greeter) ProcessLine(msg *ircclient.IRCMessage) {
	if msg.Command != "JOIN" {
		return
	}
	just_nick := strings.SplitN(msg.Source, "!", 2)[0]
	c, exists := g.ic.GetPlugin("config")
	if !exists {
		log.Println("plugin \"config\" doesn't exist")
		return
	}
	conf, _ := c.(*ircclient.ConfigPlugin)
	conf.Lock() // muss ich bei read-only garned, oder?
	our_nick, _ := conf.Conf.String("Server", "nick")
	conf.Unlock()

	if just_nick == our_nick { // don't welcome ourselves
		log.Println("o: " + our_nick + ", j: " + just_nick)
		return
	}
	ret := fmt.Sprintf("PRIVMSG %s :hi %s", msg.Target, just_nick)
	//log.Println("greeter ret: " + ret)
	g.ic.SendLine(ret)
}

func (g *Greeter) ProcessCommand(cmd *ircclient.IRCCommand) {
	return
}

func (g *Greeter) Unregister() {
	// nothing to do here
}
<|endoftext|>


<commit_before>package main

func main() {
}
<commit_msg>add GPIO library.<commit_after>package main

import (
	"fmt"
	"github.com/stianeikeland/go-rpio"
	"os"
	"time"
)

var (

)

func main() {
	if err := rpio.Open(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	defer rpio.Close()

	time.Now()
}
<|endoftext|>


<commit_before>//
// Copyright 2017, Sander van Harmelen
//
// 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 gitlab

import (
	"fmt"
	"net/url"
)

// LabelsService handles communication with the label related methods of the
// GitLab API.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html
type LabelsService struct {
	client *Client
}

// Label represents a GitLab label.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html
type Label struct {
	ID                     int    `json:"id"`
	Name                   string `json:"name"`
	Color                  string `json:"color"`
	Description            string `json:"description"`
	OpenIssuesCount        int    `json:"open_issues_count"`
	ClosedIssuesCount      int    `json:"closed_issues_count"`
	OpenMergeRequestsCount int    `json:"open_merge_requests_count"`
	Subscribed             bool   `json:"subscribed"`
	Priority               int    `json:"priority"`
}

func (l Label) String() string {
	return Stringify(l)
}

// ListLabelsOptions represents the available ListLabels() options.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#list-labels
type ListLabelsOptions ListOptions

// ListLabels gets all labels for given project.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#list-labels
func (s *LabelsService) ListLabels(pid interface{}, opt *ListLabelsOptions, options ...OptionFunc) ([]*Label, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/labels", url.QueryEscape(project))

	req, err := s.client.NewRequest("GET", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	var l []*Label
	resp, err := s.client.Do(req, &l)
	if err != nil {
		return nil, resp, err
	}

	return l, resp, err
}

// CreateLabelOptions represents the available CreateLabel() options.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#create-a-new-label
type CreateLabelOptions struct {
	Name        *string `url:"name,omitempty" json:"name,omitempty"`
	Color       *string `url:"color,omitempty" json:"color,omitempty"`
	Description *string `url:"description,omitempty" json:"description,omitempty"`
}

// CreateLabel creates a new label for given repository with given name and
// color.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#create-a-new-label
func (s *LabelsService) CreateLabel(pid interface{}, opt *CreateLabelOptions, options ...OptionFunc) (*Label, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/labels", url.QueryEscape(project))

	req, err := s.client.NewRequest("POST", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	l := new(Label)
	resp, err := s.client.Do(req, l)
	if err != nil {
		return nil, resp, err
	}

	return l, resp, err
}

// DeleteLabelOptions represents the available DeleteLabel() options.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label
type DeleteLabelOptions struct {
	Name *string `url:"name,omitempty" json:"name,omitempty"`
}

// DeleteLabel deletes a label given by its name.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label
func (s *LabelsService) DeleteLabel(pid interface{}, opt *DeleteLabelOptions, options ...OptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/labels", url.QueryEscape(project))

	req, err := s.client.NewRequest("DELETE", u, opt, options)
	if err != nil {
		return nil, err
	}

	return s.client.Do(req, nil)
}

// UpdateLabelOptions represents the available UpdateLabel() options.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label
type UpdateLabelOptions struct {
	Name        *string `url:"name,omitempty" json:"name,omitempty"`
	NewName     *string `url:"new_name,omitempty" json:"new_name,omitempty"`
	Color       *string `url:"color,omitempty" json:"color,omitempty"`
	Description *string `url:"description,omitempty" json:"description,omitempty"`
}

// UpdateLabel updates an existing label with new name or now color. At least
// one parameter is required, to update the label.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#edit-an-existing-label
func (s *LabelsService) UpdateLabel(pid interface{}, opt *UpdateLabelOptions, options ...OptionFunc) (*Label, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/labels", url.QueryEscape(project))

	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	l := new(Label)
	resp, err := s.client.Do(req, l)
	if err != nil {
		return nil, resp, err
	}

	return l, resp, err
}

// SubscribeToLabel subscribes the authenticated user to a label to receive
// notifications. If the user is already subscribed to the label, the status
// code 304 is returned.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/labels.html#subscribe-to-a-label
func (s *LabelsService) SubscribeToLabel(pid interface{}, labelID interface{}, options ...OptionFunc) (*Label, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	label, err := parseID(labelID)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/labels/%s/subscribe", url.QueryEscape(project), label)

	req, err := s.client.NewRequest("POST", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	l := new(Label)
	resp, err := s.client.Do(req, l)
	if err != nil {
		return nil, resp, err
	}

	return l, resp, err
}

// UnsubscribeFromLabel unsubscribes the authenticated user from a label to not
// receive notifications from it. If the user is not subscribed to the label, the
// status code 304 is returned.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/labels.html#unsubscribe-from-a-label
func (s *LabelsService) UnsubscribeFromLabel(pid interface{}, labelID interface{}, options ...OptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	label, err := parseID(labelID)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/labels/%s/unsubscribe", url.QueryEscape(project), label)

	req, err := s.client.NewRequest("POST", u, nil, options)
	if err != nil {
		return nil, err
	}

	return s.client.Do(req, nil)
}
<commit_msg>Support the Gitlab inconsistency around label names (#490)<commit_after>//
// Copyright 2017, Sander van Harmelen
//
// 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 gitlab

import (
	"encoding/json"
	"fmt"
	"net/url"
)

// LabelsService handles communication with the label related methods of the
// GitLab API.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html
type LabelsService struct {
	client *Client
}

// Label represents a GitLab label.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html
type Label struct {
	ID                     int    `json:"id"`
	Name                   string `json:"name"`
	Color                  string `json:"color"`
	Description            string `json:"description"`
	OpenIssuesCount        int    `json:"open_issues_count"`
	ClosedIssuesCount      int    `json:"closed_issues_count"`
	OpenMergeRequestsCount int    `json:"open_merge_requests_count"`
	Subscribed             bool   `json:"subscribed"`
	Priority               int    `json:"priority"`
}

// UnmarshalJSON implements the json.Unmarshaler interface.
func (l *Label) UnmarshalJSON(data []byte) error {
	type alias Label
	if err := json.Unmarshal(data, (*alias)(l)); err != nil {
		return err
	}

	if l.Name == "" {
		var raw map[string]interface{}
		if err := json.Unmarshal(data, &raw); err != nil {
			return err
		}
		if title, ok := raw["title"].(string); ok {
			l.Name = title
		}
	}

	return nil
}

func (l Label) String() string {
	return Stringify(l)
}

// ListLabelsOptions represents the available ListLabels() options.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#list-labels
type ListLabelsOptions ListOptions

// ListLabels gets all labels for given project.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#list-labels
func (s *LabelsService) ListLabels(pid interface{}, opt *ListLabelsOptions, options ...OptionFunc) ([]*Label, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/labels", url.QueryEscape(project))

	req, err := s.client.NewRequest("GET", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	var l []*Label
	resp, err := s.client.Do(req, &l)
	if err != nil {
		return nil, resp, err
	}

	return l, resp, err
}

// CreateLabelOptions represents the available CreateLabel() options.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#create-a-new-label
type CreateLabelOptions struct {
	Name        *string `url:"name,omitempty" json:"name,omitempty"`
	Color       *string `url:"color,omitempty" json:"color,omitempty"`
	Description *string `url:"description,omitempty" json:"description,omitempty"`
}

// CreateLabel creates a new label for given repository with given name and
// color.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#create-a-new-label
func (s *LabelsService) CreateLabel(pid interface{}, opt *CreateLabelOptions, options ...OptionFunc) (*Label, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/labels", url.QueryEscape(project))

	req, err := s.client.NewRequest("POST", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	l := new(Label)
	resp, err := s.client.Do(req, l)
	if err != nil {
		return nil, resp, err
	}

	return l, resp, err
}

// DeleteLabelOptions represents the available DeleteLabel() options.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label
type DeleteLabelOptions struct {
	Name *string `url:"name,omitempty" json:"name,omitempty"`
}

// DeleteLabel deletes a label given by its name.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label
func (s *LabelsService) DeleteLabel(pid interface{}, opt *DeleteLabelOptions, options ...OptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/labels", url.QueryEscape(project))

	req, err := s.client.NewRequest("DELETE", u, opt, options)
	if err != nil {
		return nil, err
	}

	return s.client.Do(req, nil)
}

// UpdateLabelOptions represents the available UpdateLabel() options.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label
type UpdateLabelOptions struct {
	Name        *string `url:"name,omitempty" json:"name,omitempty"`
	NewName     *string `url:"new_name,omitempty" json:"new_name,omitempty"`
	Color       *string `url:"color,omitempty" json:"color,omitempty"`
	Description *string `url:"description,omitempty" json:"description,omitempty"`
}

// UpdateLabel updates an existing label with new name or now color. At least
// one parameter is required, to update the label.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#edit-an-existing-label
func (s *LabelsService) UpdateLabel(pid interface{}, opt *UpdateLabelOptions, options ...OptionFunc) (*Label, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/labels", url.QueryEscape(project))

	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	l := new(Label)
	resp, err := s.client.Do(req, l)
	if err != nil {
		return nil, resp, err
	}

	return l, resp, err
}

// SubscribeToLabel subscribes the authenticated user to a label to receive
// notifications. If the user is already subscribed to the label, the status
// code 304 is returned.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/labels.html#subscribe-to-a-label
func (s *LabelsService) SubscribeToLabel(pid interface{}, labelID interface{}, options ...OptionFunc) (*Label, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	label, err := parseID(labelID)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/labels/%s/subscribe", url.QueryEscape(project), label)

	req, err := s.client.NewRequest("POST", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	l := new(Label)
	resp, err := s.client.Do(req, l)
	if err != nil {
		return nil, resp, err
	}

	return l, resp, err
}

// UnsubscribeFromLabel unsubscribes the authenticated user from a label to not
// receive notifications from it. If the user is not subscribed to the label, the
// status code 304 is returned.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/labels.html#unsubscribe-from-a-label
func (s *LabelsService) UnsubscribeFromLabel(pid interface{}, labelID interface{}, options ...OptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	label, err := parseID(labelID)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/labels/%s/unsubscribe", url.QueryEscape(project), label)

	req, err := s.client.NewRequest("POST", u, nil, options)
	if err != nil {
		return nil, err
	}

	return s.client.Do(req, nil)
}
<|endoftext|>


<commit_before>package drain

import (
	"fmt"
	"regexp"
	"strconv"
)

type LogplexError struct {
	Code  int // L11, L12, etc.
	Count int // Count of logs referenced in the error
	Msg   string
}

func parseLogplexError(msg string) (*LogplexError, error) {
	// Data:Error L10 (output buffer overflow):
	//    491 messages dropped since 2015-09-15T16:22:24+00:00.
	r := regexp.MustCompile(
		`Error L(?P<num>\d+) .*\: (?P<count>\d+) .*`).FindAllStringSubmatch(msg, -1)
	if len(r) < 1 || len(r[0]) < 3 {
		return nil, fmt.Errorf("invalid lerror line")
	}
	num, err := strconv.Atoi(r[0][1])
	if err != nil {
		return nil, err
	}
	count, err := strconv.Atoi(r[0][2])
	if err != nil {
		return nil, err
	}
	return &LogplexError{num, count, msg}, nil
}

func (err LogplexError) Error() string {
	return fmt.Sprintf("L%d: %s", err.Code, err.Msg)
}
<commit_msg>Fix parsing of L errors without parenthesis<commit_after>package drain

import (
	"fmt"
	"regexp"
	"strconv"
)

type LogplexError struct {
	Code  int // L11, L12, etc.
	Count int // Count of logs referenced in the error
	Msg   string
}

func parseLogplexError(msg string) (*LogplexError, error) {
	// Data:Error L10 (output buffer overflow):
	//    491 messages dropped since 2015-09-15T16:22:24+00:00.
	r := regexp.MustCompile(
		`Error L(?P<num>\d+).*\: (?P<count>\d+) .*`).FindAllStringSubmatch(msg, -1)
	if len(r) < 1 || len(r[0]) < 3 {
		return nil, fmt.Errorf("invalid lerror line")
	}
	num, err := strconv.Atoi(r[0][1])
	if err != nil {
		return nil, err
	}
	count, err := strconv.Atoi(r[0][2])
	if err != nil {
		return nil, err
	}
	return &LogplexError{num, count, msg}, nil
}

func (err LogplexError) Error() string {
	return fmt.Sprintf("L%d: %s", err.Code, err.Msg)
}
<|endoftext|>


<commit_before>package dns

// Holds a bunch of helper functions for dealing with labels.

// SplitDomainName splits a name string into it's labels.
// www.miek.nl. returns []string{"www", "miek", "nl"}
// .www.miek.nl. returns []string{"", "www", "miek", "nl"},
// The root label (.) returns nil. Note that using
// strings.Split(s) will work in most cases, but does not handle
// escaped dots (\.) for instance.
func SplitDomainName(s string) (labels []string) {
	if len(s) == 0 {
		return nil
	}
	fqdnEnd := 0 // offset of the final '.' or the length of the name
	idx := Split(s)
	begin := 0
	if s[len(s)-1] == '.' {
		fqdnEnd = len(s) - 1
	} else {
		fqdnEnd = len(s)
	}

	switch len(idx) {
	case 0:
		return nil
	case 1:
		// no-op
	default:
		end := 0
		for i := 1; i < len(idx); i++ {
			end = idx[i]
			labels = append(labels, s[begin:end-1])
			begin = end
		}
	}

	labels = append(labels, s[begin:fqdnEnd])
	return labels
}

// CompareDomainName compares the names s1 and s2 and
// returns how many labels they have in common starting from the *right*.
// The comparison stops at the first inequality. The names are not downcased
// before the comparison.
//
// www.miek.nl. and miek.nl. have two labels in common: miek and nl
// www.miek.nl. and www.bla.nl. have one label in common: nl
func CompareDomainName(s1, s2 string) (n int) {
	s1 = Fqdn(s1)
	s2 = Fqdn(s2)
	l1 := Split(s1)
	l2 := Split(s2)

	// the first check: root label
	if l1 == nil || l2 == nil {
		return
	}

	j1 := len(l1) - 1 // end
	i1 := len(l1) - 2 // start
	j2 := len(l2) - 1
	i2 := len(l2) - 2
	// the second check can be done here: last/only label
	// before we fall through into the for-loop below
	if s1[l1[j1]:] == s2[l2[j2]:] {
		n++
	} else {
		return
	}
	for {
		if i1 < 0 || i2 < 0 {
			break
		}
		if s1[l1[i1]:l1[j1]] == s2[l2[i2]:l2[j2]] {
			n++
		} else {
			break
		}
		j1--
		i1--
		j2--
		i2--
	}
	return
}

// CountLabel counts the the number of labels in the string s.
func CountLabel(s string) (labels int) {
	if s == "." {
		return
	}
	off := 0
	end := false
	for {
		off, end = NextLabel(s, off)
		labels++
		if end {
			return
		}
	}
}

// Split splits a name s into its label indexes.
// www.miek.nl. returns []int{0, 4, 9}, www.miek.nl also returns []int{0, 4, 9}.
// .www.miek.nl. returns []int{0, 1, 5, 10}
// The root name (.) returns nil. Also see SplitDomainName.
func Split(s string) []int {
	if s == "." {
		return nil
	}
	idx := make([]int, 1, 3)
	off := 0
	end := false

	for {
		off, end = NextLabel(s, off)
		if end {
			return idx
		}
		idx = append(idx, off)
	}
}

// NextLabel returns the index of the start of the next label in the
// string s starting at offset.
// The bool end is true when the end of the string has been reached.
// Also see PrevLabel.
func NextLabel(s string, offset int) (i int, end bool) {
	quote := false
	for i = offset; i < len(s)-1; i++ {
		switch s[i] {
		case '\\':
			quote = !quote
		default:
			quote = false
		case '.':
			if quote {
				quote = !quote
				continue
			}
			return i + 1, false
		}
	}
	return i + 1, true
}

// PrevLabel returns the index of the label when starting from the right and
// jumping n labels to the left.
// The bool start is true when the start of the string has been overshot.
// Also see NextLabel.
func PrevLabel(s string, n int) (i int, start bool) {
	if n == 0 {
		return len(s), false
	}
	lab := Split(s)
	if lab == nil {
		return 0, true
	}
	if n > len(lab) {
		return 0, true
	}
	return lab[len(lab)-n], false
}
<commit_msg>Improve docs on the label functions<commit_after>package dns

// Holds a bunch of helper functions for dealing with labels.

// SplitDomainName splits a name string into it's labels.
// www.miek.nl. returns []string{"www", "miek", "nl"}
// .www.miek.nl. returns []string{"", "www", "miek", "nl"},
// The root label (.) returns nil. Note that using
// strings.Split(s) will work in most cases, but does not handle
// escaped dots (\.) for instance.
// s must be a syntactically valid domain name, see IsDomainName.
func SplitDomainName(s string) (labels []string) {
	if len(s) == 0 {
		return nil
	}
	fqdnEnd := 0 // offset of the final '.' or the length of the name
	idx := Split(s)
	begin := 0
	if s[len(s)-1] == '.' {
		fqdnEnd = len(s) - 1
	} else {
		fqdnEnd = len(s)
	}

	switch len(idx) {
	case 0:
		return nil
	case 1:
		// no-op
	default:
		end := 0
		for i := 1; i < len(idx); i++ {
			end = idx[i]
			labels = append(labels, s[begin:end-1])
			begin = end
		}
	}

	labels = append(labels, s[begin:fqdnEnd])
	return labels
}

// CompareDomainName compares the names s1 and s2 and
// returns how many labels they have in common starting from the *right*.
// The comparison stops at the first inequality. The names are not downcased
// before the comparison.
//
// www.miek.nl. and miek.nl. have two labels in common: miek and nl
// www.miek.nl. and www.bla.nl. have one label in common: nl
//
// s1 and s2 must be syntactically valid domain names.
func CompareDomainName(s1, s2 string) (n int) {
	s1 = Fqdn(s1)
	s2 = Fqdn(s2)
	l1 := Split(s1)
	l2 := Split(s2)

	// the first check: root label
	if l1 == nil || l2 == nil {
		return
	}

	j1 := len(l1) - 1 // end
	i1 := len(l1) - 2 // start
	j2 := len(l2) - 1
	i2 := len(l2) - 2
	// the second check can be done here: last/only label
	// before we fall through into the for-loop below
	if s1[l1[j1]:] == s2[l2[j2]:] {
		n++
	} else {
		return
	}
	for {
		if i1 < 0 || i2 < 0 {
			break
		}
		if s1[l1[i1]:l1[j1]] == s2[l2[i2]:l2[j2]] {
			n++
		} else {
			break
		}
		j1--
		i1--
		j2--
		i2--
	}
	return
}

// CountLabel counts the the number of labels in the string s.
// s must be a syntactically valid domain name.
func CountLabel(s string) (labels int) {
	if s == "." {
		return
	}
	off := 0
	end := false
	for {
		off, end = NextLabel(s, off)
		labels++
		if end {
			return
		}
	}
}

// Split splits a name s into its label indexes.
// www.miek.nl. returns []int{0, 4, 9}, www.miek.nl also returns []int{0, 4, 9}.
// The root name (.) returns nil. Also see SplitDomainName.
// s must be a syntactically valid domain name.
func Split(s string) []int {
	if s == "." {
		return nil
	}
	idx := make([]int, 1, 3)
	off := 0
	end := false

	for {
		off, end = NextLabel(s, off)
		if end {
			return idx
		}
		idx = append(idx, off)
	}
}

// NextLabel returns the index of the start of the next label in the
// string s starting at offset.
// The bool end is true when the end of the string has been reached.
// Also see PrevLabel.
func NextLabel(s string, offset int) (i int, end bool) {
	quote := false
	for i = offset; i < len(s)-1; i++ {
		switch s[i] {
		case '\\':
			quote = !quote
		default:
			quote = false
		case '.':
			if quote {
				quote = !quote
				continue
			}
			return i + 1, false
		}
	}
	return i + 1, true
}

// PrevLabel returns the index of the label when starting from the right and
// jumping n labels to the left.
// The bool start is true when the start of the string has been overshot.
// Also see NextLabel.
func PrevLabel(s string, n int) (i int, start bool) {
	if n == 0 {
		return len(s), false
	}
	lab := Split(s)
	if lab == nil {
		return 0, true
	}
	if n > len(lab) {
		return 0, true
	}
	return lab[len(lab)-n], false
}
<|endoftext|>


<commit_before>package jo

import (
	"fmt"
)

// Events signal a change in context, for example the start of
// a string literal.
type Event int

const (
	Primitive Event = 1 << (5 + iota)
	Composite
	Start
	End
)

const (
	Continue    Event = iota
	SyntaxError       = iota
	Done              = iota

	ObjectStart = iota | Composite | Start
	ObjectEnd   = iota | Composite | End
	ArrayStart  = iota | Composite | Start
	ArrayEnd    = iota | Composite | End

	KeyStart = iota | Start
	KeyEnd   = iota | End

	StringStart = iota | Primitive | Start
	StringEnd   = iota | Primitive | End
	NumberStart = iota | Primitive | Start
	NumberEnd   = iota | Primitive | End
	BoolStart   = iota | Primitive | Start
	BoolEnd     = iota | Primitive | End
	NullStart   = iota | Primitive | Start
	NullEnd     = iota | Primitive | End
)

// String returns the name of the event.
func (e Event) String() string {
	switch e {
	case Continue:
		return "Continue"
	case SyntaxError:
		return "SyntaxError"
	case Done:
		return "Done"
	case ObjectStart:
		return "ObjectStart"
	case ObjectEnd:
		return "ObjectEnd"
	case KeyStart:
		return "KeyStart"
	case KeyEnd:
		return "KeyEnd"
	case ArrayStart:
		return "ArrayStart"
	case ArrayEnd:
		return "ArrayEnd"
	case StringStart:
		return "StringStart"
	case StringEnd:
		return "StringEnd"
	case NumberStart:
		return "NumberStart"
	case NumberEnd:
		return "NumberEnd"
	case BoolStart:
		return "BoolStart"
	case BoolEnd:
		return "BoolEnd"
	case NullStart:
		return "NullStart"
	case NullEnd:
		return "NullEnd"
	}
	return "<unknown event>"
}

// Parser is the state machine used while parsing a stream of JSON data.
// It requires no initialization before use.
type Parser struct {
	state int
	stack []int

	depth, limit int
	drop, empty  int

	key bool
}

const (
	_Value int = iota
	_Done

	_ObjectKeyOrBrace   // {
	_ObjectKeyDone      // {"foo
	_ObjectColon        // {"foo"
	_ObjectCommaOrBrace // {"foo":"bar"
	_ObjectKey          // {"foo":"bar",

	_ArrayValueOrBracket // [
	_ArrayCommaOrBracket // ["any value"

	// leading whitespace must be be consumed before any of
	// the states listed above are processed
	__CONSUME_SPACE__

	_StringUnicode  // "\u
	_StringUnicode2 // "\u1
	_StringUnicode3 // "\u12
	_StringUnicode4 // "\u123
	_String         // "
	_StringDone     // "foo
	_StringEscaped  // "\

	_NumberNegative      // -
	_NumberZero          // 0
	_Number              // 123
	_NumberDotFirstDigit // 123.
	_NumberDotDigit      // 123.4
	_NumberExpSign       // 123e
	_NumberExpFirstDigit // 123e+
	_NumberExpDigit      // 123e+1

	_True  // t
	_True2 // tr
	_True3 // tru

	_False  // f
	_False2 // fa
	_False3 // fal
	_False4 // fals

	_Null  // n
	_Null2 // nu
	_Null3 // nul
)

var expected = map[int]string{
	_Value:               "start of JSON value",
	_Done:                "end of input",
	_ObjectKeyOrBrace:    "object key or '}'",
	_ObjectColon:         "':'",
	_ObjectCommaOrBrace:  "',' or '}'",
	_ObjectKey:           "object key",
	_ArrayValueOrBracket: "array element or ']'",
	_ArrayCommaOrBracket: "',' or ']'",
	_StringUnicode:       "hexadecimal digit",
	_StringUnicode2:      "hexadecimal digit",
	_StringUnicode3:      "hexadecimal digit",
	_StringUnicode4:      "hexadecimal digit",
	_String:              "valid string character or '\"'",
	_StringEscaped:       "'b', 'f', 'n', 'r', 't', 'u', '\\', '/' or '\"'",
	_NumberNegative:      "digit",
	_NumberZero:          "'.', 'e' or 'E'",
	_NumberDotFirstDigit: "digit",
	_NumberExpSign:       "'-', '+' or digit",
	_NumberExpFirstDigit: "digit",
	_True:                "'r' in literal true",
	_True2:               "'u' in literal true",
	_True3:               "'e' in literal true",
	_False:               "'a' in literal false",
	_False2:              "'l' in literal false",
	_False3:              "'s' in literal false",
	_False4:              "'e' in literal false",
	_Null:                "'u' in literal null",
	_Null2:               "'l' in literal null",
	_Null3:               "'l' in literal null",
}

// Next parses a slice of JSON data, signalling the first change in context by
// returning the number of bytes read and an appropriate event. If parsing
// concludes without any change in parser state, the Continue psuedo-event
// will be returned instead.
//
// When the event returned is SyntaxError, the error return value will describe
// why parsing failed.
func (p *Parser) Next(data []byte) (int, Event, error) {
	for i := 0; i < len(data); i++ {
		ev := Continue
		b := data[i]

		// trim insignificant whitespace
		if p.state < __CONSUME_SPACE__ && isSpace(b) {
			continue
		}

		switch p.state {
		case _Value:
			if b == '{' {
				ev = ObjectStart
				p.state = _ObjectKeyOrBrace
			} else if b == '[' {
				ev = ArrayStart
				p.state = _ArrayValueOrBracket
			} else if b == '"' {
				ev = StringStart
				p.state = _String
				p.push(_StringDone)
			} else if b == '-' {
				ev = NumberStart
				p.state = _NumberNegative
			} else if b == '0' {
				ev = NumberStart
				p.state = _NumberZero
			} else if '1' <= b && b <= '9' {
				ev = NumberStart
				p.state = _Number
			} else if b == 't' {
				ev = BoolStart
				p.state = _True
			} else if b == 'f' {
				ev = BoolStart
				p.state = _False
			} else if b == 'n' {
				ev = NullStart
				p.state = _Null
			} else {
				goto abort
			}

		case _ObjectKeyOrBrace:
			if b == '}' {
				ev = ObjectEnd
				p.state = p.pop()
				break
			}

			// if it's not a brace, it must be a key
			p.state = _ObjectKey
			fallthrough

		case _ObjectKey:
			if b == '"' {
				ev = KeyStart
				p.state = _String
				p.push(_ObjectKeyDone)
			} else {
				goto abort
			}

		case _ObjectKeyDone:
			// we wouldn't be here unless b == '"', so we can avoid
			// checking it again
			ev = KeyEnd
			p.state = _ObjectColon

		case _ObjectColon:
			if b == ':' {
				p.state = _Value
				p.push(_ObjectCommaOrBrace)
			} else {
				goto abort
			}

		case _ObjectCommaOrBrace:
			if b == ',' {
				p.state = _ObjectKey
			} else if b == '}' {
				ev = ObjectEnd
				p.state = p.pop()
			} else {
				goto abort
			}

		case _ArrayValueOrBracket:
			if b == ']' {
				ev = ArrayEnd
				p.state = p.pop()
			} else {
				p.state = _Value
				p.push(_ArrayCommaOrBracket)

				// rewind and let _Value parse this byte for us
				i--
			}

		case _ArrayCommaOrBracket:
			if b == ',' {
				p.state = _Value
				p.push(_ArrayCommaOrBracket)
			} else if b == ']' {
				ev = ArrayEnd
				p.state = p.pop()
			} else {
				goto abort
			}

		case _StringUnicode,
			_StringUnicode2,
			_StringUnicode3,
			_StringUnicode4:
			if isHex(b) {
				// move on to the next unicode byte state, or back to
				// `_String` if this was the fourth hexadecimal
				// character after "\u"
				p.state++
			} else {
				goto abort
			}

		case _String:
			if b == '"' {
				// forget we saw the double quote, let the next state
				// "discover" it instead
				i--
				p.state = p.pop()
			} else if b == '\\' {
				p.state = _StringEscaped
			} else if b < 0x20 {
				goto abort
			}

		case _StringDone:
			// we wouldn't be here unless b == '"', so we can avoid
			// checking it again
			ev = StringEnd
			p.state = p.pop()

		case _StringEscaped:
			switch b {
			case 'b', 'f', 'n', 'r', 't', '\\', '/', '"':
				p.state = _String
			case 'u':
				p.state = _StringUnicode
			default:
				goto abort
			}

		case _NumberNegative:
			if b == '0' {
				p.state = _NumberZero
			} else if '1' <= b && b <= '9' {
				p.state = _Number
			} else {
				goto abort
			}

		case _Number:
			if b >= '0' && b <= '9' {
				break
			}
			fallthrough

		case _NumberZero:
			if b == '.' {
				p.state = _NumberDotFirstDigit
			} else if b == 'e' || b == 'E' {
				p.state = _NumberExpSign
			} else {
				ev = NumberEnd
				p.state = p.pop()

				// rewind a byte, because the character we encountered was
				// not part of the number
				i--
			}

		case _NumberDotFirstDigit:
			if b >= '0' && b <= '9' {
				p.state = _NumberDotDigit
			} else {
				goto abort
			}

		case _NumberDotDigit:
			if b == 'e' || b == 'E' {
				p.state = _NumberExpSign
			} else if b < '0' || b > '9' {
				ev = NumberEnd
				p.state = p.pop()

				// rewind a byte, because the character we encountered was
				// not part of the number
				i--
			}

		case _NumberExpSign:
			p.state = _NumberExpFirstDigit
			if b == '+' || b == '-' {
				break
			}
			fallthrough

		case _NumberExpFirstDigit:
			if b < '0' || b > '9' {
				goto abort
			} else {
				p.state++
			}

		case _NumberExpDigit:
			if b < '0' || b > '9' {
				ev = NumberEnd
				p.state = p.pop()

				// rewind a byte, because the character we encountered was
				// not part of the number
				i--
			}

		case _True:
			if b == 'r' {
				p.state = _True2
			} else {
				goto abort
			}

		case _True2:
			if b == 'u' {
				p.state = _True3
			} else {
				goto abort
			}

		case _True3:
			if b == 'e' {
				ev = BoolEnd
				p.state = p.pop()
			} else {
				goto abort
			}

		case _False:
			if b == 'a' {
				p.state = _False2
			} else {
				goto abort
			}

		case _False2:
			if b == 'l' {
				p.state = _False3
			} else {
				goto abort
			}

		case _False3:
			if b == 's' {
				p.state = _False4
			} else {
				goto abort
			}

		case _False4:
			if b == 'e' {
				ev = BoolEnd
				p.state = p.pop()
			} else {
				goto abort
			}

		case _Null:
			if b == 'u' {
				p.state = _Null2
			} else {
				goto abort
			}

		case _Null2:
			if b == 'l' {
				p.state = _Null3
			} else {
				goto abort
			}

		case _Null3:
			if b == 'l' {
				ev = NullEnd
				p.state = p.pop()
			} else {
				goto abort
			}

		case _Done:
			// only whitespace characters are legal after the
			// top-level value
			goto abort

		default:
			panic("invalid state")
		}

		// if this byte didn't yield an event, continue with
		// the next one
		if ev == Continue {
			continue
		}

		// if the event indicates a change in depth, update p.depth
		switch {
		case ev == KeyStart:
			p.depth++
			p.key = true

		case ev&(Composite|Primitive) != 0 && ev&Start != 0:
			if p.key {
				p.key = false
			} else {
				p.depth++
			}

		case ev&(Composite|Primitive) != 0 && ev&End != 0:
			p.depth--
		}

		// determine if we should emit this event or not
		if p.drop > 0 || p.empty > 0 {
			if p.depth > p.limit {
				continue
			}

			p.limit--

			if p.drop > 0 {
				p.drop--
				continue
			} else {
				p.empty--
				if ev&End == 0 {
					continue
				}
			}
		}

		return i + 1, ev, nil

	abort:
		return i, SyntaxError, fmt.Errorf("expected %s, found %q",
			expected[p.state], b)
	}

	return len(data), Continue, nil
}

// push puts a new state at the top of the stack.
func (p *Parser) push(state int) {
	p.stack = append(p.stack, state)
}

// pop retrieves the top state in the stack.
func (p *Parser) pop() int {
	length := len(p.stack)

	// if the state queue is empty, the top level value has ended
	if length == 0 {
		return _Done
	}

	state := p.stack[length-1]
	p.stack = p.stack[:length-1]

	return state
}

// End informs the parser not to expect any further input (i.e. EOF).
//
// A SyntaxError event and a relevant error will be returned if the method
// was invoked before the top-level had been completely parsed. Returns either
// a NumberEnd or Done event otherwise.
func (p *Parser) End() (Event, error) {
	switch p.state {
	case _Done:
		return Done, nil
	case _NumberZero, _Number, _NumberDotDigit, _NumberExpDigit:
		if p.depth == 1 {
			p.state = _Done
			return NumberEnd, nil
		}
	}

	return SyntaxError, fmt.Errorf("expected %s, found end of input",
		expected[p.state])
}

// Reset resets the parser struct to its initial state. Convenient when parsing
// a stream of more than one JSON value (simply reset the parser after each Done
// event).
func (p *Parser) Reset() {
	*p = Parser{}
}

// Depth returns the current value depth.
func (p *Parser) Depth() int {
	return p.depth
}

func isSpace(b byte) bool {
	return b == ' ' || b == '\t' || b == '\n' || b == '\r'
}

func isHex(b byte) bool {
	return (b >= '0' && b <= '9') ||
		(b >= 'a' && b <= 'f') ||
		(b >= 'A' && b <= 'F')
}
<commit_msg>Remove Parser.Depth<commit_after>package jo

import (
	"fmt"
)

// Events signal a change in context, for example the start of
// a string literal.
type Event int

const (
	Primitive Event = 1 << (5 + iota)
	Composite
	Start
	End
)

const (
	Continue    Event = iota
	SyntaxError       = iota
	Done              = iota

	ObjectStart = iota | Composite | Start
	ObjectEnd   = iota | Composite | End
	ArrayStart  = iota | Composite | Start
	ArrayEnd    = iota | Composite | End

	KeyStart = iota | Start
	KeyEnd   = iota | End

	StringStart = iota | Primitive | Start
	StringEnd   = iota | Primitive | End
	NumberStart = iota | Primitive | Start
	NumberEnd   = iota | Primitive | End
	BoolStart   = iota | Primitive | Start
	BoolEnd     = iota | Primitive | End
	NullStart   = iota | Primitive | Start
	NullEnd     = iota | Primitive | End
)

// String returns the name of the event.
func (e Event) String() string {
	switch e {
	case Continue:
		return "Continue"
	case SyntaxError:
		return "SyntaxError"
	case Done:
		return "Done"
	case ObjectStart:
		return "ObjectStart"
	case ObjectEnd:
		return "ObjectEnd"
	case KeyStart:
		return "KeyStart"
	case KeyEnd:
		return "KeyEnd"
	case ArrayStart:
		return "ArrayStart"
	case ArrayEnd:
		return "ArrayEnd"
	case StringStart:
		return "StringStart"
	case StringEnd:
		return "StringEnd"
	case NumberStart:
		return "NumberStart"
	case NumberEnd:
		return "NumberEnd"
	case BoolStart:
		return "BoolStart"
	case BoolEnd:
		return "BoolEnd"
	case NullStart:
		return "NullStart"
	case NullEnd:
		return "NullEnd"
	}
	return "<unknown event>"
}

// Parser is the state machine used while parsing a stream of JSON data.
// It requires no initialization before use.
type Parser struct {
	state int
	stack []int
}

const (
	_Value int = iota
	_Done

	_ObjectKeyOrBrace   // {
	_ObjectKeyDone      // {"foo
	_ObjectColon        // {"foo"
	_ObjectCommaOrBrace // {"foo":"bar"
	_ObjectKey          // {"foo":"bar",

	_ArrayValueOrBracket // [
	_ArrayCommaOrBracket // ["any value"

	// leading whitespace must be be consumed before any of
	// the states listed above are processed
	__CONSUME_SPACE__

	_StringUnicode  // "\u
	_StringUnicode2 // "\u1
	_StringUnicode3 // "\u12
	_StringUnicode4 // "\u123
	_String         // "
	_StringDone     // "foo
	_StringEscaped  // "\

	_NumberNegative      // -
	_NumberZero          // 0
	_Number              // 123
	_NumberDotFirstDigit // 123.
	_NumberDotDigit      // 123.4
	_NumberExpSign       // 123e
	_NumberExpFirstDigit // 123e+
	_NumberExpDigit      // 123e+1

	_True  // t
	_True2 // tr
	_True3 // tru

	_False  // f
	_False2 // fa
	_False3 // fal
	_False4 // fals

	_Null  // n
	_Null2 // nu
	_Null3 // nul
)

var expected = map[int]string{
	_Value:               "start of JSON value",
	_Done:                "end of input",
	_ObjectKeyOrBrace:    "object key or '}'",
	_ObjectColon:         "':'",
	_ObjectCommaOrBrace:  "',' or '}'",
	_ObjectKey:           "object key",
	_ArrayValueOrBracket: "array element or ']'",
	_ArrayCommaOrBracket: "',' or ']'",
	_StringUnicode:       "hexadecimal digit",
	_StringUnicode2:      "hexadecimal digit",
	_StringUnicode3:      "hexadecimal digit",
	_StringUnicode4:      "hexadecimal digit",
	_String:              "valid string character or '\"'",
	_StringEscaped:       "'b', 'f', 'n', 'r', 't', 'u', '\\', '/' or '\"'",
	_NumberNegative:      "digit",
	_NumberZero:          "'.', 'e' or 'E'",
	_NumberDotFirstDigit: "digit",
	_NumberExpSign:       "'-', '+' or digit",
	_NumberExpFirstDigit: "digit",
	_True:                "'r' in literal true",
	_True2:               "'u' in literal true",
	_True3:               "'e' in literal true",
	_False:               "'a' in literal false",
	_False2:              "'l' in literal false",
	_False3:              "'s' in literal false",
	_False4:              "'e' in literal false",
	_Null:                "'u' in literal null",
	_Null2:               "'l' in literal null",
	_Null3:               "'l' in literal null",
}

// Next parses a slice of JSON data, signalling the first change in context by
// returning the number of bytes read and an appropriate event. If parsing
// concludes without any change in parser state, the Continue psuedo-event
// will be returned instead.
//
// When the event returned is SyntaxError, the error return value will describe
// why parsing failed.
func (p *Parser) Next(data []byte) (int, Event, error) {
	for i := 0; i < len(data); i++ {
		ev := Continue
		b := data[i]

		// trim insignificant whitespace
		if p.state < __CONSUME_SPACE__ && isSpace(b) {
			continue
		}

		switch p.state {
		case _Value:
			if b == '{' {
				ev = ObjectStart
				p.state = _ObjectKeyOrBrace
			} else if b == '[' {
				ev = ArrayStart
				p.state = _ArrayValueOrBracket
			} else if b == '"' {
				ev = StringStart
				p.state = _String
				p.push(_StringDone)
			} else if b == '-' {
				ev = NumberStart
				p.state = _NumberNegative
			} else if b == '0' {
				ev = NumberStart
				p.state = _NumberZero
			} else if '1' <= b && b <= '9' {
				ev = NumberStart
				p.state = _Number
			} else if b == 't' {
				ev = BoolStart
				p.state = _True
			} else if b == 'f' {
				ev = BoolStart
				p.state = _False
			} else if b == 'n' {
				ev = NullStart
				p.state = _Null
			} else {
				goto abort
			}

		case _ObjectKeyOrBrace:
			if b == '}' {
				ev = ObjectEnd
				p.state = p.pop()
				break
			}

			// if it's not a brace, it must be a key
			p.state = _ObjectKey
			fallthrough

		case _ObjectKey:
			if b == '"' {
				ev = KeyStart
				p.state = _String
				p.push(_ObjectKeyDone)
			} else {
				goto abort
			}

		case _ObjectKeyDone:
			// we wouldn't be here unless b == '"', so we can avoid
			// checking it again
			ev = KeyEnd
			p.state = _ObjectColon

		case _ObjectColon:
			if b == ':' {
				p.state = _Value
				p.push(_ObjectCommaOrBrace)
			} else {
				goto abort
			}

		case _ObjectCommaOrBrace:
			if b == ',' {
				p.state = _ObjectKey
			} else if b == '}' {
				ev = ObjectEnd
				p.state = p.pop()
			} else {
				goto abort
			}

		case _ArrayValueOrBracket:
			if b == ']' {
				ev = ArrayEnd
				p.state = p.pop()
			} else {
				p.state = _Value
				p.push(_ArrayCommaOrBracket)

				// rewind and let _Value parse this byte for us
				i--
			}

		case _ArrayCommaOrBracket:
			if b == ',' {
				p.state = _Value
				p.push(_ArrayCommaOrBracket)
			} else if b == ']' {
				ev = ArrayEnd
				p.state = p.pop()
			} else {
				goto abort
			}

		case _StringUnicode,
			_StringUnicode2,
			_StringUnicode3,
			_StringUnicode4:
			if isHex(b) {
				// move on to the next unicode byte state, or back to
				// `_String` if this was the fourth hexadecimal
				// character after "\u"
				p.state++
			} else {
				goto abort
			}

		case _String:
			if b == '"' {
				// forget we saw the double quote, let the next state
				// "discover" it instead
				i--
				p.state = p.pop()
			} else if b == '\\' {
				p.state = _StringEscaped
			} else if b < 0x20 {
				goto abort
			}

		case _StringDone:
			// we wouldn't be here unless b == '"', so we can avoid
			// checking it again
			ev = StringEnd
			p.state = p.pop()

		case _StringEscaped:
			switch b {
			case 'b', 'f', 'n', 'r', 't', '\\', '/', '"':
				p.state = _String
			case 'u':
				p.state = _StringUnicode
			default:
				goto abort
			}

		case _NumberNegative:
			if b == '0' {
				p.state = _NumberZero
			} else if '1' <= b && b <= '9' {
				p.state = _Number
			} else {
				goto abort
			}

		case _Number:
			if b >= '0' && b <= '9' {
				break
			}
			fallthrough

		case _NumberZero:
			if b == '.' {
				p.state = _NumberDotFirstDigit
			} else if b == 'e' || b == 'E' {
				p.state = _NumberExpSign
			} else {
				ev = NumberEnd
				p.state = p.pop()

				// rewind a byte, because the character we encountered was
				// not part of the number
				i--
			}

		case _NumberDotFirstDigit:
			if b >= '0' && b <= '9' {
				p.state = _NumberDotDigit
			} else {
				goto abort
			}

		case _NumberDotDigit:
			if b == 'e' || b == 'E' {
				p.state = _NumberExpSign
			} else if b < '0' || b > '9' {
				ev = NumberEnd
				p.state = p.pop()

				// rewind a byte, because the character we encountered was
				// not part of the number
				i--
			}

		case _NumberExpSign:
			p.state = _NumberExpFirstDigit
			if b == '+' || b == '-' {
				break
			}
			fallthrough

		case _NumberExpFirstDigit:
			if b < '0' || b > '9' {
				goto abort
			} else {
				p.state++
			}

		case _NumberExpDigit:
			if b < '0' || b > '9' {
				ev = NumberEnd
				p.state = p.pop()

				// rewind a byte, because the character we encountered was
				// not part of the number
				i--
			}

		case _True:
			if b == 'r' {
				p.state = _True2
			} else {
				goto abort
			}

		case _True2:
			if b == 'u' {
				p.state = _True3
			} else {
				goto abort
			}

		case _True3:
			if b == 'e' {
				ev = BoolEnd
				p.state = p.pop()
			} else {
				goto abort
			}

		case _False:
			if b == 'a' {
				p.state = _False2
			} else {
				goto abort
			}

		case _False2:
			if b == 'l' {
				p.state = _False3
			} else {
				goto abort
			}

		case _False3:
			if b == 's' {
				p.state = _False4
			} else {
				goto abort
			}

		case _False4:
			if b == 'e' {
				ev = BoolEnd
				p.state = p.pop()
			} else {
				goto abort
			}

		case _Null:
			if b == 'u' {
				p.state = _Null2
			} else {
				goto abort
			}

		case _Null2:
			if b == 'l' {
				p.state = _Null3
			} else {
				goto abort
			}

		case _Null3:
			if b == 'l' {
				ev = NullEnd
				p.state = p.pop()
			} else {
				goto abort
			}

		case _Done:
			// only whitespace characters are legal after the
			// top-level value
			goto abort

		default:
			panic("invalid state")
		}

		// if this byte didn't yield an event, continue with
		// the next one
		if ev == Continue {
			continue
		}

		return i + 1, ev, nil

	abort:
		return i, SyntaxError, fmt.Errorf("expected %s, found %q",
			expected[p.state], b)
	}

	return len(data), Continue, nil
}

// push puts a new state at the top of the stack.
func (p *Parser) push(state int) {
	p.stack = append(p.stack, state)
}

// pop retrieves the top state in the stack.
func (p *Parser) pop() int {
	length := len(p.stack)

	// if the state queue is empty, the top level value has ended
	if length == 0 {
		return _Done
	}

	state := p.stack[length-1]
	p.stack = p.stack[:length-1]

	return state
}

// End informs the parser not to expect any further input (i.e. EOF).
//
// A SyntaxError event and a relevant error will be returned if the method
// was invoked before the top-level had been completely parsed. Returns either
// a NumberEnd or Done event otherwise.
func (p *Parser) End() (Event, error) {
	switch p.state {
	case _Done:
		return Done, nil
	case _NumberZero, _Number, _NumberDotDigit, _NumberExpDigit:
		if len(p.stack) == 0 {
			p.state = _Done
			return NumberEnd, nil
		}
	}

	return SyntaxError, fmt.Errorf("expected %s, found end of input",
		expected[p.state])
}

// Reset resets the parser struct to its initial state. Convenient when parsing
// a stream of more than one JSON value (simply reset the parser after each Done
// event).
func (p *Parser) Reset() {
	*p = Parser{}
}

func isSpace(b byte) bool {
	return b == ' ' || b == '\t' || b == '\n' || b == '\r'
}

func isHex(b byte) bool {
	return (b >= '0' && b <= '9') ||
		(b >= 'a' && b <= 'f') ||
		(b >= 'A' && b <= 'F')
}
<|endoftext|>


<commit_before>package configparser

import (
	"errors"
	"io"
)

// ConfigParser provides the needed machinery to retrieve configuration values
// of any basic type
type ConfigParser interface {
	// Get searches and retrieves any kind of data type
	Get(string) interface{}
	// GetFloat checks for the given key value of type `float`
	// If such a key exists but of a different data type, returns `ErrIncompatibleType` error
	// If it misses the key, returns ErrorDoesNotExist
	GetFloat(string) (float64, error)
	// GetBool checks for the given key value of type `bool`
	// If such a key exists but of a different data type, returns `ErrIncompatibleType` error
	// If it misses the key, returns ErrorDoesNotExist
	GetBool(string) (bool, error)
	// GetString checks for the given key value of type `string`
	// If such a key exists but of a different data type, returns `ErrIncompatibleType` error
	// If it misses the key, returns ErrorDoesNotExist
	GetString(string) (string, error)
}

var (
	// ErrDoesNotExist is the error returned when the value being retrieved is not defined
	// in the specified configuration
	ErrDoesNotExist = errors.New("Config value does not exist")
	// ErrIncompatibleType is the error returned when the value being retrieved is not
	// compatible with the specified
	ErrIncompatibleType = errors.New("Incompatible type for stored value")
	// ErrDecoding is returned when the content of the config reader could not be decoded
	// with the provided format
	ErrDecoding = errors.New("Error decoding the reader")
)

// NewJSONConfigReader reads from reader which should be valid json, and returns a ConfigParser
func NewJSONConfigReader(reader io.Reader) (ConfigParser, error) {
	return nil, nil
}
<commit_msg>Implement `NewJSONConfigReader`<commit_after>package configparser

import (
	"encoding/json"
	"errors"
	"io"

	"github.com/kingzbauer/json_cli/jsongear"
)

// ConfigParser provides the needed machinery to retrieve configuration values
// of any basic type
type ConfigParser interface {
	// Get searches and retrieves any kind of data type
	Get(string) interface{}
	// GetFloat checks for the given key value of type `float`
	// If such a key exists but of a different data type, returns `ErrIncompatibleType` error
	// If it misses the key, returns ErrorDoesNotExist
	GetFloat(string) (float64, error)
	// GetBool checks for the given key value of type `bool`
	// If such a key exists but of a different data type, returns `ErrIncompatibleType` error
	// If it misses the key, returns ErrorDoesNotExist
	GetBool(string) (bool, error)
	// GetString checks for the given key value of type `string`
	// If such a key exists but of a different data type, returns `ErrIncompatibleType` error
	// If it misses the key, returns ErrorDoesNotExist
	GetString(string) (string, error)
}

var (
	// ErrDoesNotExist is the error returned when the value being retrieved is not defined
	// in the specified configuration
	ErrDoesNotExist = errors.New("Config value does not exist")
	// ErrIncompatibleType is the error returned when the value being retrieved is not
	// compatible with the specified
	ErrIncompatibleType = errors.New("Incompatible type for stored value")
)

// NewJSONConfigReader reads from reader which should be valid json, and returns a ConfigParser
func NewJSONConfigReader(reader io.Reader) (ConfigParser, error) {
	config := new(configParser)
	if err := json.NewDecoder(reader).Decode(&config.data); err != nil {
		return nil, err
	}

	return config, nil
}

type configParser struct {
	data interface{}
}

func (config *configParser) Get(key string) interface{} {
	return jsongear.Get(key, config.data)
}

func (config *configParser) GetFloat(key string) (float64, error) {
	v := jsongear.Get(key, config.data)
	if v == nil {
		return 0, ErrDoesNotExist
	}

	if floatV, ok := v.(float64); ok {
		return floatV, nil
	}
	return 0, ErrIncompatibleType
}

func (config *configParser) GetString(key string) (string, error) {
	v := jsongear.Get(key, config.data)
	if v == nil {
		return "", ErrDoesNotExist
	}

	if strV, ok := v.(string); ok {
		return strV, nil
	}
	return "", ErrIncompatibleType
}

func (config *configParser) GetBool(key string) (bool, error) {
	v := jsongear.Get(key, config.data)
	if v == nil {
		return false, ErrDoesNotExist
	}

	if boolV, ok := v.(bool); ok {
		return boolV, nil
	}
	return false, ErrIncompatibleType
}
<|endoftext|>