<commit_before>package main

import (
	"fmt"
	color "github.com/fatih/color"
	//pretty "github.com/kr/pretty"
	goyaml "gopkg.in/yaml.v2"
	"io/ioutil"
	"os"
	"reflect"
)

func main() {
	file1 := os.Args[1]
	file2 := os.Args[2]

	buf, err := ioutil.ReadFile(file1)
	if err != nil {
		panic(err)
	}
	m1 := make(map[interface{}]interface{})
	err = goyaml.Unmarshal([]byte(buf), &m1)
	if err != nil {
		panic(err)
	}

	buf2, err := ioutil.ReadFile(file2)
	if err != nil {
		panic(err)
	}
	m2 := make(map[interface{}]interface{})
	err = goyaml.Unmarshal([]byte(buf2), &m2)
	if err != nil {
		panic(err)
	}

	m3 := make(map[interface{}]interface{})
	addLeftParam(m3, m1)
	addRightParam(m3, m2)

	ommitSameParam(m3)
	//pretty.Printf("%# v\n\n", m3)

	printDiffYaml(m3, "")
}

type Comparer struct {
	leftValue  interface{}
	rightValue interface{}
}

type Empty struct {
}

func addLeftParam(mergedMap, leftMap map[interface{}]interface{}) {
	for key, value := range leftMap {
		if value == nil || reflect.TypeOf(value).Kind() != reflect.Map {
			mergedMap[key] = value
		} else {
			if _, ok := mergedMap[key]; !ok {
				mergedMap[key] = make(map[interface{}]interface{})
			}
			addLeftParam(mergedMap[key].(map[interface{}]interface{}), leftMap[key].(map[interface{}]interface{}))
		}
	}
}

func addRightParam(mergedMap, rightMap map[interface{}]interface{}) {
	for key, value := range rightMap {
		if value == nil || reflect.TypeOf(value).Kind() != reflect.Map {
			if _, ok := mergedMap[key]; !ok {
				mergedMap[key] = Comparer{Empty{}, value}
			} else if mergedMap[key] == nil {
				mergedMap[key] = Comparer{nil, value}
			} else {
				mergedMap[key] = Comparer{mergedMap[key], value}
			}
		} else {
			if _, ok := mergedMap[key]; !ok {
				mergedMap[key] = make(map[interface{}]interface{})
			}
			if mergedMap[key] == nil || reflect.TypeOf(mergedMap[key]).Kind() != reflect.Map {
				mergedMap[key] = Comparer{mergedMap[key], value}
			} else {
				addRightParam(mergedMap[key].(map[interface{}]interface{}), rightMap[key].(map[interface{}]interface{}))
			}
		}
	}

	setComparer(mergedMap)
}

func setComparer(mergedMap map[interface{}]interface{}) {
	for key, value := range mergedMap {
		if value == nil {
			mergedMap[key] = Comparer{nil, Empty{}}
		} else if reflect.TypeOf(value).Kind() == reflect.Map {
			setComparer(mergedMap[key].(map[interface{}]interface{}))
		} else {
			vt := reflect.TypeOf(value).Kind()
			if vt != reflect.Map && vt != reflect.Struct {
				mergedMap[key] = Comparer{value, Empty{}}
			}
		}
	}
}

func ommitSameParam(m map[interface{}]interface{}) {
	for key, value := range m {
		if reflect.TypeOf(value).Kind() != reflect.Map {
			tmp := value.(Comparer)
			if reflect.DeepEqual(tmp.leftValue, tmp.rightValue) {
				delete(m, key)
			}
		} else {
			ommitSameParam(m[key].(map[interface{}]interface{}))
			if len(m[key].(map[interface{}]interface{})) == 0 {
				delete(m, key)
			}
		}
	}
}

func printDiffYaml(m map[interface{}]interface{}, indent string) {
	for key, value := range m {
		if reflect.TypeOf(value).Kind() == reflect.Map {
			println(indent + key.(string) + ":")
			printDiffYaml(m[key].(map[interface{}]interface{}), indent+"    ")
		} else {
			tmp := value.(Comparer)
			println(indent + key.(string) + ":")
			color.Set(color.FgRed)
			printValue(tmp.leftValue, indent+"  - ")
			color.Set(color.FgGreen)
			printValue(tmp.rightValue, indent+"  + ")
			color.Unset()
		}

	}
}

func printValue(value interface{}, indent string) {
	if value != nil {
		if reflect.TypeOf(value).Kind() < reflect.Array {
			fmt.Printf("%s%#v\n", indent, reflect.ValueOf(value).Interface())
		}

		switch reflect.TypeOf(value).Kind() {
		case reflect.Slice:
			fmt.Printf("%s[", indent)
			for i, v := range value.([]interface{}) {
				if i != 0 {
					fmt.Print(", ")
				}
				fmt.Printf("%#v", reflect.ValueOf(v).Interface())
			}
			println("]")
		case reflect.String:
			fmt.Printf("%s%#v\n", indent, reflect.ValueOf(value).Interface())
		case reflect.Map:
			for key, v := range value.(map[interface{}]interface{}) {
				println(indent + key.(string) + ":")
				printValue(v, "    "+indent)
			}
		}

	} else {
		println(indent + "null")
	}
}
<commit_msg>go fmt<commit_after>package main

import (
	"fmt"
	color "github.com/fatih/color"
	//pretty "github.com/kr/pretty"
	goyaml "gopkg.in/yaml.v2"
	"io/ioutil"
	"os"
	"reflect"
)

func main() {
	file1 := os.Args[1]
	file2 := os.Args[2]

	buf, err := ioutil.ReadFile(file1)
	if err != nil {
		panic(err)
	}
	m1 := make(map[interface{}]interface{})
	err = goyaml.Unmarshal([]byte(buf), &m1)
	if err != nil {
		panic(err)
	}

	buf2, err := ioutil.ReadFile(file2)
	if err != nil {
		panic(err)
	}
	m2 := make(map[interface{}]interface{})
	err = goyaml.Unmarshal([]byte(buf2), &m2)
	if err != nil {
		panic(err)
	}

	m3 := make(map[interface{}]interface{})
	addLeftParam(m3, m1)
	addRightParam(m3, m2)

	ommitSameParam(m3)
	//pretty.Printf("%# v\n\n", m3)

	printDiffYaml(m3, "")
}

type Comparer struct {
	leftValue  interface{}
	rightValue interface{}
}

type Empty struct {
}

func addLeftParam(mergedMap, leftMap map[interface{}]interface{}) {
	for key, value := range leftMap {
		if value == nil || reflect.TypeOf(value).Kind() != reflect.Map {
			mergedMap[key] = value
		} else {
			if _, ok := mergedMap[key]; !ok {
				mergedMap[key] = make(map[interface{}]interface{})
			}
			addLeftParam(mergedMap[key].(map[interface{}]interface{}), leftMap[key].(map[interface{}]interface{}))
		}
	}
}

func addRightParam(mergedMap, rightMap map[interface{}]interface{}) {
	for key, value := range rightMap {
		if value == nil || reflect.TypeOf(value).Kind() != reflect.Map {
			if _, ok := mergedMap[key]; !ok {
				mergedMap[key] = Comparer{Empty{}, value}
			} else if mergedMap[key] == nil {
				mergedMap[key] = Comparer{nil, value}
			} else {
				mergedMap[key] = Comparer{mergedMap[key], value}
			}
		} else {
			if _, ok := mergedMap[key]; !ok {
				mergedMap[key] = make(map[interface{}]interface{})
			}
			if mergedMap[key] == nil || reflect.TypeOf(mergedMap[key]).Kind() != reflect.Map {
				mergedMap[key] = Comparer{mergedMap[key], value}
			} else {
				addRightParam(mergedMap[key].(map[interface{}]interface{}), rightMap[key].(map[interface{}]interface{}))
			}
		}
	}

	setComparer(mergedMap)
}

func setComparer(mergedMap map[interface{}]interface{}) {
	for key, value := range mergedMap {
		if value == nil {
			mergedMap[key] = Comparer{nil, Empty{}}
		} else if reflect.TypeOf(value).Kind() == reflect.Map {
			setComparer(mergedMap[key].(map[interface{}]interface{}))
		} else {
			vt := reflect.TypeOf(value).Kind()
			if vt != reflect.Map && vt != reflect.Struct {
				mergedMap[key] = Comparer{value, Empty{}}
			}
		}
	}
}

func ommitSameParam(m map[interface{}]interface{}) {
	for key, value := range m {
		if reflect.TypeOf(value).Kind() != reflect.Map {
			tmp := value.(Comparer)
			if reflect.DeepEqual(tmp.leftValue, tmp.rightValue) {
				delete(m, key)
			}
		} else {
			ommitSameParam(m[key].(map[interface{}]interface{}))
			if len(m[key].(map[interface{}]interface{})) == 0 {
				delete(m, key)
			}
		}
	}
}

func printDiffYaml(m map[interface{}]interface{}, indent string) {
	for key, value := range m {
		if reflect.TypeOf(value).Kind() == reflect.Map {
			println(indent + key.(string) + ":")
			printDiffYaml(m[key].(map[interface{}]interface{}), indent+"    ")
		} else {
			tmp := value.(Comparer)
			println(indent + key.(string) + ":")
			color.Set(color.FgRed)
			printValue(tmp.leftValue, indent+"  - ")
			color.Set(color.FgGreen)
			printValue(tmp.rightValue, indent+"  + ")
			color.Unset()
		}

	}
}

func printValue(value interface{}, indent string) {
	if value != nil {
		if reflect.TypeOf(value).Kind() < reflect.Array {
			fmt.Printf("%s%#v\n", indent, reflect.ValueOf(value).Interface())
		}

		switch reflect.TypeOf(value).Kind() {
		case reflect.Slice:
			fmt.Printf("%s[", indent)
			for i, v := range value.([]interface{}) {
				if i != 0 {
					fmt.Print(", ")
				}
				fmt.Printf("%#v", reflect.ValueOf(v).Interface())
			}
			println("]")
		case reflect.String:
			fmt.Printf("%s%#v\n", indent, reflect.ValueOf(value).Interface())
		case reflect.Map:
			for key, v := range value.(map[interface{}]interface{}) {
				println(indent + key.(string) + ":")
				printValue(v, "    "+indent)
			}
		}

	} else {
		println(indent + "null")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"
)

var (
	// Version can be auto-set at build time using an ldflag
	//   go build -ldflags "-X main.Version `git describe --tags --always`"
	Version string

	// DepsFile specifies the Godeps file used by gdm
	DepsFile string = "Godeps"

	// Parallel specifies whether to 'restore' in parallel
	// This is primarily for debug/logging purposes
	Parallel bool = true
)

const usage = `Go Dependency Manager (gdm), a lightweight tool for managing Go dependencies.

Usage:

    gdm <command> [-f GODEPS_FILE] [-v]

The commands are:

    restore   Check out revisions defined in Godeps file to $GOPATH.
    save      Saves currently checked-out dependencies from $GOPATH to Godeps file.
    brew      Outputs homebrew go_resource entries to stdout.
    version   Prints the version.
`

func main() {
	flag.Usage = usageExit
	flag.Parse()
	args := flag.Args()
	var verbose bool
	if len(args) < 1 {
		usageExit()
	} else if len(args) > 1 {
		set := flag.NewFlagSet("", flag.ExitOnError)
		set.StringVar(&DepsFile, "f", "Godeps", "Specify the name/location of Godeps file")
		set.BoolVar(&verbose, "v", false, "Verbose mode")
		set.BoolVar(&Parallel, "parallel", true, "Execute gdm restore in parallel")
		set.Parse(os.Args[2:])
	}

	wd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	gopath, err := getGoPath(wd)
	if err != nil {
		fmt.Fprintf(os.Stderr, err.Error())
		os.Exit(1)
	}

	switch args[0] {
	case "save", "bootstrap":
		splash(wd, gopath)
		save(wd, gopath, verbose)
	case "restore", "get", "sync", "checkout":
		splash(wd, gopath)
		restore(wd, gopath, verbose)
	case "brew", "homebrew":
		splash(wd, gopath)
		homebrew(wd, gopath, verbose)
	case "version":
		fmt.Printf("gdm - version %s\n", Version)
	default:
		usageExit()
	}
}

func splash(wd, gopath string) {
	fmt.Println("======= Go Dependency Manager =======")
	fmt.Println("= working dir:", wd)
	fmt.Println("= GOPATH:     ", gopath)
	fmt.Println("=====================================")
}

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

// getGoPath returns a single GOPATH. If there are multiple defined in the users
// $GOPATH env variable, then getGoPath validates that the working directory is
// part of one of the GOPATHs, and uses the first one it finds that does.
func getGoPath(wd string) (string, error) {
	gopath := os.Getenv("GOPATH")
	if gopath == "" {
		return "", fmt.Errorf("GOPATH must be set to use gdm")
	}

	// Split out multiple GOPATHs if necessary
	if strings.Contains(gopath, string(os.PathListSeparator)) {
		paths := strings.Split(gopath, string(os.PathListSeparator))
		for _, path := range paths {
			if strings.Contains(wd, path) {
				gopath = path
				break
			}
		}
	}

	if !strings.Contains(wd, gopath) {
		return "", fmt.Errorf("gdm can only be executed within a directory in"+
			" the GOPATH, wd: %s, gopath: %s", wd, gopath)
	}
	return gopath, nil
}

func homebrew(wd, gopath string, verbose bool) {
	imports, err := ImportsFromPath(wd, gopath, verbose)
	if err != nil {
		fmt.Printf("Fatal error: %s", err)
		os.Exit(1)
	}

	fmt.Println()
	for _, i := range imports {
		fmt.Printf("  go_resource \"%s\" do\n", i.ImportPath)
		fmt.Printf("    url \"%s.%s\",\n", i.Repo.Repo, i.Repo.VCS.Cmd)
		fmt.Printf("    :revision => \"%s\"\n", i.Rev)
		fmt.Printf("  end\n")
		fmt.Println()
	}
}

func save(wd, gopath string, verbose bool) {
	imports, err := ImportsFromPath(wd, gopath, verbose)
	if err != nil {
		fmt.Printf("Fatal error: %s", err)
		os.Exit(1)
	}

	f, err := os.Create(filepath.Join(wd, DepsFile))
	if err != nil {
		fmt.Printf("Fatal error: %s", err)
		os.Exit(1)
	}
	defer f.Close()
	w := bufio.NewWriter(f)
	for _, i := range imports {
		fmt.Printf("> Saving Import [%s] Revision [%s]\n", i.ImportPath, i.Rev)
		_, err = w.WriteString(fmt.Sprintf("%s %s\n", i.ImportPath, i.Rev))
		if err != nil {
			fmt.Printf("Fatal error: %s", err)
			os.Exit(1)
		}
	}
	w.Flush()
}

func restore(wd, gopath string, verbose bool) {
	imports := ImportsFromFile(filepath.Join(wd, DepsFile))
	if Parallel {
		restoreParallel(imports, gopath, verbose)
	} else {
		restoreSerial(imports, gopath, verbose)
	}
}

func restoreParallel(imports []*Import, gopath string, verbose bool) {
	var wg sync.WaitGroup
	wg.Add(len(imports))
	errC := make(chan error, len(imports))
	for _, i := range imports {
		i.Verbose = verbose
		go func(I *Import) {
			defer wg.Done()
			err := I.RestoreImport(gopath)
			if err != nil {
				errC <- err
			}
		}(i)
		// arbitrary sleep to avoid overloading a single clone endpoint
		time.Sleep(time.Millisecond * 30)
	}
	wg.Wait()
	close(errC)
	if len(errC) > 0 {
		fmt.Println()
		fmt.Println("ERROR restoring some imports:")
		for err := range errC {
			fmt.Printf("-   %s", err)
		}
		os.Exit(1)
	}
}

func restoreSerial(imports []*Import, gopath string, verbose bool) {
	for _, i := range imports {
		i.Verbose = verbose
		i.RestoreImport(gopath)
	}
}
<commit_msg>Update Homebrew go_resource style (#19)<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"
)

var (
	// Version can be auto-set at build time using an ldflag
	//   go build -ldflags "-X main.Version `git describe --tags --always`"
	Version string

	// DepsFile specifies the Godeps file used by gdm
	DepsFile string = "Godeps"

	// Parallel specifies whether to 'restore' in parallel
	// This is primarily for debug/logging purposes
	Parallel bool = true
)

const usage = `Go Dependency Manager (gdm), a lightweight tool for managing Go dependencies.

Usage:

    gdm <command> [-f GODEPS_FILE] [-v]

The commands are:

    restore   Check out revisions defined in Godeps file to $GOPATH.
    save      Saves currently checked-out dependencies from $GOPATH to Godeps file.
    brew      Outputs homebrew go_resource entries to stdout.
    version   Prints the version.
`

func main() {
	flag.Usage = usageExit
	flag.Parse()
	args := flag.Args()
	var verbose bool
	if len(args) < 1 {
		usageExit()
	} else if len(args) > 1 {
		set := flag.NewFlagSet("", flag.ExitOnError)
		set.StringVar(&DepsFile, "f", "Godeps", "Specify the name/location of Godeps file")
		set.BoolVar(&verbose, "v", false, "Verbose mode")
		set.BoolVar(&Parallel, "parallel", true, "Execute gdm restore in parallel")
		set.Parse(os.Args[2:])
	}

	wd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	gopath, err := getGoPath(wd)
	if err != nil {
		fmt.Fprintf(os.Stderr, err.Error())
		os.Exit(1)
	}

	switch args[0] {
	case "save", "bootstrap":
		splash(wd, gopath)
		save(wd, gopath, verbose)
	case "restore", "get", "sync", "checkout":
		splash(wd, gopath)
		restore(wd, gopath, verbose)
	case "brew", "homebrew":
		splash(wd, gopath)
		homebrew(wd, gopath, verbose)
	case "version":
		fmt.Printf("gdm - version %s\n", Version)
	default:
		usageExit()
	}
}

func splash(wd, gopath string) {
	fmt.Println("======= Go Dependency Manager =======")
	fmt.Println("= working dir:", wd)
	fmt.Println("= GOPATH:     ", gopath)
	fmt.Println("=====================================")
}

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

// getGoPath returns a single GOPATH. If there are multiple defined in the users
// $GOPATH env variable, then getGoPath validates that the working directory is
// part of one of the GOPATHs, and uses the first one it finds that does.
func getGoPath(wd string) (string, error) {
	gopath := os.Getenv("GOPATH")
	if gopath == "" {
		return "", fmt.Errorf("GOPATH must be set to use gdm")
	}

	// Split out multiple GOPATHs if necessary
	if strings.Contains(gopath, string(os.PathListSeparator)) {
		paths := strings.Split(gopath, string(os.PathListSeparator))
		for _, path := range paths {
			if strings.Contains(wd, path) {
				gopath = path
				break
			}
		}
	}

	if !strings.Contains(wd, gopath) {
		return "", fmt.Errorf("gdm can only be executed within a directory in"+
			" the GOPATH, wd: %s, gopath: %s", wd, gopath)
	}
	return gopath, nil
}

func homebrew(wd, gopath string, verbose bool) {
	imports, err := ImportsFromPath(wd, gopath, verbose)
	if err != nil {
		fmt.Printf("Fatal error: %s", err)
		os.Exit(1)
	}

	fmt.Println()
	for _, i := range imports {
		fmt.Printf("  go_resource \"%s\" do\n", i.ImportPath)
		fmt.Printf("    url \"%s.%s\",\n", i.Repo.Repo, i.Repo.VCS.Cmd)
		fmt.Printf("        :revision => \"%s\"\n", i.Rev)
		fmt.Printf("  end\n")
		fmt.Println()
	}
}

func save(wd, gopath string, verbose bool) {
	imports, err := ImportsFromPath(wd, gopath, verbose)
	if err != nil {
		fmt.Printf("Fatal error: %s", err)
		os.Exit(1)
	}

	f, err := os.Create(filepath.Join(wd, DepsFile))
	if err != nil {
		fmt.Printf("Fatal error: %s", err)
		os.Exit(1)
	}
	defer f.Close()
	w := bufio.NewWriter(f)
	for _, i := range imports {
		fmt.Printf("> Saving Import [%s] Revision [%s]\n", i.ImportPath, i.Rev)
		_, err = w.WriteString(fmt.Sprintf("%s %s\n", i.ImportPath, i.Rev))
		if err != nil {
			fmt.Printf("Fatal error: %s", err)
			os.Exit(1)
		}
	}
	w.Flush()
}

func restore(wd, gopath string, verbose bool) {
	imports := ImportsFromFile(filepath.Join(wd, DepsFile))
	if Parallel {
		restoreParallel(imports, gopath, verbose)
	} else {
		restoreSerial(imports, gopath, verbose)
	}
}

func restoreParallel(imports []*Import, gopath string, verbose bool) {
	var wg sync.WaitGroup
	wg.Add(len(imports))
	errC := make(chan error, len(imports))
	for _, i := range imports {
		i.Verbose = verbose
		go func(I *Import) {
			defer wg.Done()
			err := I.RestoreImport(gopath)
			if err != nil {
				errC <- err
			}
		}(i)
		// arbitrary sleep to avoid overloading a single clone endpoint
		time.Sleep(time.Millisecond * 30)
	}
	wg.Wait()
	close(errC)
	if len(errC) > 0 {
		fmt.Println()
		fmt.Println("ERROR restoring some imports:")
		for err := range errC {
			fmt.Printf("-   %s", err)
		}
		os.Exit(1)
	}
}

func restoreSerial(imports []*Import, gopath string, verbose bool) {
	for _, i := range imports {
		i.Verbose = verbose
		i.RestoreImport(gopath)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/khezen/bulklog/config"
	"github.com/khezen/bulklog/server"
)

func main() {
	quit := make(chan error)
	var err error
	cfg, err := config.Get()
	if err != nil {
		panic(err)
	}
	server, err := server.New(cfg, quit)
	if err != nil {
		panic(err)
	}
	go server.ListenAndServe()
	err = <-quit
	panic(err)
}
<commit_msg>sall for consumers<commit_after>package main

import (
	"fmt"
	"time"

	"github.com/khezen/bulklog/config"
	"github.com/khezen/bulklog/server"
)

const (
	maxTries    = 30
	retryPeriod = 5 * time.Second
)

var (
	quit  chan error
	cfg   *config.Config
	serv  *server.Server
	err   error
	timer *time.Timer
	i     int
)

func main() {
	quit = make(chan error)
	var err error
	cfg, err = config.Get()
	if err != nil {
		panic(err)
	}
	for {
		serv, err = server.New(cfg, quit)
		if err != nil {
			if i < maxTries {
				fmt.Println(err)
				timer = time.NewTimer(retryPeriod)
				<-timer.C
				i++
			} else {
				panic(err)
			}
		} else {
			break
		}
	}
	if err != nil {
		panic(err)
	}
	go serv.ListenAndServe()
	err = <-quit
	panic(err)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"context"
	"fmt"
	"os"
	"runtime"
	"sort"
	"strings"
	"sync"
	"time"

	"github.com/fatih/color"
	"github.com/fd0/termstatus"
	"github.com/spf13/pflag"
)

var opts = struct {
	threads     int
	placeholder string
}{}

func init() {
	pflag.IntVarP(&opts.threads, "procs", "p", runtime.NumCPU(), "number of parallel porgrams")
	pflag.StringVar(&opts.placeholder, "replace", "{}", "replace this string in the command to run")
	pflag.Parse()
}

func parseInput(ch chan<- *Command, cmd string, args []string) {
	defer close(ch)

	sc := bufio.NewScanner(os.Stdin)

	for sc.Scan() {
		cmdName := cmd
		cmdArgs := make([]string, len(args))

		line := strings.TrimSpace(sc.Text())

		if line == "" {
			fmt.Fprintf(os.Stderr, "ignoring empty line\n")
			continue
		}

		if cmd == opts.placeholder {
			cmdName = line
		}

		for i, arg := range args {
			if arg == opts.placeholder {
				cmdArgs[i] = line
				continue
			}

			cmdArgs[i] = args[i]
		}

		ch <- &Command{
			Tag:  line,
			Cmd:  cmdName,
			Args: cmdArgs,
		}
	}
}

func checkForPlaceholder(cmdname string, args []string) {
	if cmdname == opts.placeholder {
		return
	}

	for _, arg := range args {
		if arg == opts.placeholder {
			return
		}
	}

	fmt.Fprintf(os.Stderr, "no placeholder found\n")
	os.Exit(2)
}

// Status is one message printed by a command.
type Status struct {
	Tag     string
	Message string
	Error   bool

	Done  bool
	Start bool
}

func formatDuration(d time.Duration) string {
	sec := uint64(d / time.Second)

	hours := sec / 3600
	sec -= hours * 3600
	min := sec / 60
	sec -= min * 60
	if hours > 0 {
		return fmt.Sprintf("%d:%02d:%02d", hours, min, sec)
	}

	return fmt.Sprintf("%d:%02d", min, sec)
}

var (
	colorTag       = color.New(color.FgYellow).SprintFunc()
	colorError     = color.New(color.FgRed, color.Bold).SprintFunc()
	colorTimestamp = color.New(color.FgBlue).SprintFunc()

	colorStatusLine = color.New(color.ReverseVideo, color.Bold).SprintFunc()
)

func updateTerminal(t *termstatus.Terminal, start time.Time, processed, failed int, data map[string]string) {
	keys := make([]string, 0, len(data))
	for k := range data {
		keys = append(keys, k)
	}
	sort.Sort(sort.StringSlice(keys))

	lines := make([]string, 0, len(data)+3)
	lines = append(lines, colorStatusLine(fmt.Sprintf("[%s] %d processed (%s failed), %d/%d workers:",
		formatDuration(time.Since(start)),
		processed,
		colorError(failed),
		len(data),
		opts.threads)))

	for _, key := range keys {
		lines = append(lines, data[key])
	}

	t.SetStatus(lines)
}

const timeFormat = "2006-01-02 15:04:05"

func status(ctx context.Context, wg *sync.WaitGroup, t *termstatus.Terminal, outCh <-chan Status) {
	defer wg.Done()
	stat := make(map[string]string)

	start := time.Now()
	ticker := time.NewTicker(200 * time.Millisecond)
	defer ticker.Stop()

	var stats = struct {
		processed int
		failed    int
	}{}

	defer func() {
		t.Finish()
		fmt.Printf("\nprocessed %d items (%d failures) in %s\n",
			stats.processed,
			stats.failed,
			formatDuration(time.Since(start)))
	}()

	for {
		select {
		case <-ctx.Done():
			return
		case s, ok := <-outCh:
			if !ok {
				return
			}

			var msg string
			if s.Start {
				msg = s.Tag
			}

			if s.Message != "" {
				msg = s.Message
				if s.Error {
					msg = fmt.Sprintf("%v %v", colorError("error"), colorError(s.Message))
				}
			}

			if msg != "" {
				t.Printf("%v %v %v",
					colorTimestamp(time.Now().Format(timeFormat)),
					colorTag(s.Tag), msg)
			}

			stat[s.Tag] = fmt.Sprintf("%v %v", colorTag(s.Tag), msg)

			if s.Done {
				stats.processed++

				if s.Error {
					stats.failed++
				}

				delete(stat, s.Tag)
			}

			updateTerminal(t, start, stats.processed, stats.failed, stat)
		case <-ticker.C:
			updateTerminal(t, start, stats.processed, stats.failed, stat)
		}
	}
}

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	t := termstatus.New(ctx, os.Stdout)
	outCh := make(chan Status)

	var statusWg sync.WaitGroup
	statusWg.Add(1)
	go status(ctx, &statusWg, t, outCh)

	ch := make(chan *Command)

	var workersWg sync.WaitGroup
	for i := 0; i < opts.threads; i++ {
		workersWg.Add(1)
		go worker(&workersWg, ch, outCh)
	}

	args := pflag.Args()
	if len(args) == 0 {
		fmt.Fprintf(os.Stderr, "no command given\n")
		pflag.Usage()
		os.Exit(1)
	}

	cmdname := args[0]
	args = args[1:]

	checkForPlaceholder(cmdname, args)

	go parseInput(ch, cmdname, args)

	workersWg.Wait()
	close(outCh)

	statusWg.Wait()
}
<commit_msg>Fix colors, remove extra output<commit_after>package main

import (
	"bufio"
	"context"
	"fmt"
	"os"
	"runtime"
	"sort"
	"strings"
	"sync"
	"time"

	"github.com/fatih/color"
	"github.com/fd0/termstatus"
	"github.com/spf13/pflag"
)

var opts = struct {
	threads     int
	placeholder string
}{}

func init() {
	pflag.IntVarP(&opts.threads, "procs", "p", runtime.NumCPU(), "number of parallel porgrams")
	pflag.StringVar(&opts.placeholder, "replace", "{}", "replace this string in the command to run")
	pflag.Parse()
}

func parseInput(ch chan<- *Command, cmd string, args []string) {
	defer close(ch)

	sc := bufio.NewScanner(os.Stdin)

	for sc.Scan() {
		cmdName := cmd
		cmdArgs := make([]string, len(args))

		line := strings.TrimSpace(sc.Text())

		if line == "" {
			fmt.Fprintf(os.Stderr, "ignoring empty line\n")
			continue
		}

		if cmd == opts.placeholder {
			cmdName = line
		}

		for i, arg := range args {
			if arg == opts.placeholder {
				cmdArgs[i] = line
				continue
			}

			cmdArgs[i] = args[i]
		}

		ch <- &Command{
			Tag:  line,
			Cmd:  cmdName,
			Args: cmdArgs,
		}
	}
}

func checkForPlaceholder(cmdname string, args []string) {
	if cmdname == opts.placeholder {
		return
	}

	for _, arg := range args {
		if arg == opts.placeholder {
			return
		}
	}

	fmt.Fprintf(os.Stderr, "no placeholder found\n")
	os.Exit(2)
}

// Status is one message printed by a command.
type Status struct {
	Tag     string
	Message string
	Error   bool

	Done  bool
	Start bool
}

func formatDuration(d time.Duration) string {
	sec := uint64(d / time.Second)

	hours := sec / 3600
	sec -= hours * 3600
	min := sec / 60
	sec -= min * 60
	if hours > 0 {
		return fmt.Sprintf("%d:%02d:%02d", hours, min, sec)
	}

	return fmt.Sprintf("%d:%02d", min, sec)
}

var (
	colorTag       = color.New(color.Reset, color.FgYellow).SprintFunc()
	colorError     = color.New(color.Reset, color.FgRed, color.Bold).SprintFunc()
	colorTimestamp = color.New(color.Reset, color.FgBlue).SprintFunc()

	colorStatusLine = color.New(color.Bold, color.ReverseVideo).SprintFunc()
)

func updateTerminal(t *termstatus.Terminal, start time.Time, processed, failed int, data map[string]string) {
	keys := make([]string, 0, len(data))
	for k := range data {
		keys = append(keys, k)
	}
	sort.Sort(sort.StringSlice(keys))

	lines := make([]string, 0, len(data)+3)
	lines = append(lines, colorStatusLine(fmt.Sprintf("[%s] %d processed (%d failed), %d/%d workers:",
		formatDuration(time.Since(start)),
		processed,
		failed,
		len(data),
		opts.threads)))

	for _, key := range keys {
		lines = append(lines, data[key])
	}

	t.SetStatus(lines)
}

const timeFormat = "2006-01-02 15:04:05"

func status(ctx context.Context, wg *sync.WaitGroup, t *termstatus.Terminal, outCh <-chan Status) {
	defer wg.Done()
	stat := make(map[string]string)

	start := time.Now()
	ticker := time.NewTicker(200 * time.Millisecond)
	defer ticker.Stop()

	var stats = struct {
		processed int
		failed    int
	}{}

	defer func() {
		t.Finish()
		fmt.Printf("\nprocessed %d items (%d failures) in %s\n",
			stats.processed,
			stats.failed,
			formatDuration(time.Since(start)))
	}()

	for {
		select {
		case <-ctx.Done():
			return
		case s, ok := <-outCh:
			if !ok {
				return
			}

			var msg string
			if s.Message != "" {
				msg = s.Message
				if s.Error {
					msg = fmt.Sprintf("%v %v", colorError("error"), colorError(s.Message))
				}
			}

			if msg != "" {
				t.Printf("%v %v %v",
					colorTimestamp(time.Now().Format(timeFormat)),
					colorTag(s.Tag), msg)
			}

			stat[s.Tag] = fmt.Sprintf("%v %v", colorTag(s.Tag), msg)

			if s.Done {
				stats.processed++

				if s.Error {
					stats.failed++
				}

				delete(stat, s.Tag)
			}

			updateTerminal(t, start, stats.processed, stats.failed, stat)
		case <-ticker.C:
			updateTerminal(t, start, stats.processed, stats.failed, stat)
		}
	}
}

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	t := termstatus.New(ctx, os.Stdout)
	outCh := make(chan Status)

	var statusWg sync.WaitGroup
	statusWg.Add(1)
	go status(ctx, &statusWg, t, outCh)

	ch := make(chan *Command)

	var workersWg sync.WaitGroup
	for i := 0; i < opts.threads; i++ {
		workersWg.Add(1)
		go worker(&workersWg, ch, outCh)
	}

	args := pflag.Args()
	if len(args) == 0 {
		fmt.Fprintf(os.Stderr, "no command given\n")
		pflag.Usage()
		os.Exit(1)
	}

	cmdname := args[0]
	args = args[1:]

	checkForPlaceholder(cmdname, args)

	go parseInput(ch, cmdname, args)

	workersWg.Wait()
	close(outCh)

	statusWg.Wait()
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"sync/atomic"
	"time"
)

var (
	procs = flag.Int("p", runtime.NumCPU(), "how many processes to use for counting lines")
	exts  = flag.String("ext", "", "only extensions ('go,html,js')")
)

func ShouldExamine(ext string) bool {
	if *exts == "" {
		return true
	}
	ext = strings.ToLower("," + strings.TrimPrefix(ext, ".") + ",")
	return strings.Contains(*exts, ext)
}

func main() {
	flag.Parse()

	path := flag.Arg(0)
	if path == "" {
		path = "."
	}

	if *exts != "" {
		*exts = "," + *exts + ","
	}

	var progress int64
	fmtprogress := func() string {
		v := atomic.LoadInt64(&progress)
		return "    files " + strconv.Itoa(int(v))
	}

	work := make(chan string, 100)
	results := make(chan CountByExt, *procs)
	go IterateDir(path, work)

	for i := 0; i < *procs; i++ {
		go FileWorker(work, results, &progress)
	}

	total := make(CountByExt)
	for N := *procs; N > 0; {
		select {
		case <-time.After(100 * time.Millisecond):
			line := fmtprogress()
			backspace := strings.Repeat("\r", len(line))
			fmt.Print(line, backspace)
		case result := <-results:
			for _, s := range result {
				total.Add(s)
			}
			N--
		}
	}
	fmt.Println(fmtprogress())
	fmt.Println()

	counts := make(Counts, 0, len(total))
	for _, c := range total {
		counts = append(counts, c)
	}
	sort.Sort(ByCode{counts})

	summary := Count{}

	fmt.Printf("%-12s %12s %12s %12s %12s\n", "extension", "files", "binary", "blank", "code")
	fmt.Println(strings.Repeat("-", 12*5+4))
	for _, count := range counts {
		summary.Add(count)
		fmt.Printf("%-12s %12d %12d %12d %12d\n", count.Ext, count.Files, count.Binary, count.Blank, count.Code)
	}
	fmt.Println(strings.Repeat("-", 12*5+4))
	fmt.Printf("%-12s %12d %12d %12d %12d\n", "summary", summary.Files, summary.Binary, summary.Blank, summary.Code)
}

func FileWorker(files chan string, result chan CountByExt, progress *int64) {
	total := make(CountByExt)
	defer func() { result <- total }()

	for file := range files {
		count, err := CountLines(file)
		if err != nil {
			continue
		}
		total.Add(count)
		atomic.AddInt64(progress, 1)
	}
}

func IterateDir(root string, work chan string) {
	walk := func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		if info.IsDir() {
			info.Mode()
			filename := info.Name()
			if len(filename) > 1 && filename[0] == '.' {
				return filepath.SkipDir
			}
			return nil
		}

		// if a filename contains ~ we assume it's a temporary file
		if strings.Contains(filepath.Base(path), "~") {
			return nil
		}

		if !ShouldExamine(filepath.Ext(path)) {
			return nil
		}

		work <- path
		return nil
	}

	err := filepath.Walk(root, walk)
	if err != nil {
		log.Println(err)
	}

	close(work)
}
<commit_msg>Support multiple paths on the command line<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"sync/atomic"
	"time"
)

var (
	procs = flag.Int("p", runtime.NumCPU(), "how many processes to use for counting lines")
	exts  = flag.String("ext", "", "only extensions ('go,html,js')")
)

func ShouldExamine(ext string) bool {
	if *exts == "" {
		return true
	}
	ext = strings.ToLower("," + strings.TrimPrefix(ext, ".") + ",")
	return strings.Contains(*exts, ext)
}

func main() {
	flag.Parse()

	paths := flag.Args()
	if len(paths) == 0 {
		paths = []string{"."}
	}

	if *exts != "" {
		*exts = "," + *exts + ","
	}

	var progress int64
	fmtprogress := func() string {
		v := atomic.LoadInt64(&progress)
		return "    files " + strconv.Itoa(int(v))
	}

	work := make(chan string, 100)
	results := make(chan CountByExt, *procs)
	go IterateDir(work, paths...)

	for i := 0; i < *procs; i++ {
		go FileWorker(work, results, &progress)
	}

	total := make(CountByExt)
	for N := *procs; N > 0; {
		select {
		case <-time.After(100 * time.Millisecond):
			line := fmtprogress()
			backspace := strings.Repeat("\r", len(line))
			fmt.Print(line, backspace)
		case result := <-results:
			for _, s := range result {
				total.Add(s)
			}
			N--
		}
	}
	fmt.Println(fmtprogress())
	fmt.Println()

	counts := make(Counts, 0, len(total))
	for _, c := range total {
		counts = append(counts, c)
	}
	sort.Sort(ByCode{counts})

	summary := Count{}

	fmt.Printf("%-12s %12s %12s %12s %12s\n", "extension", "files", "binary", "blank", "code")
	fmt.Println(strings.Repeat("-", 12*5+4))
	for _, count := range counts {
		summary.Add(count)
		fmt.Printf("%-12s %12d %12d %12d %12d\n", count.Ext, count.Files, count.Binary, count.Blank, count.Code)
	}
	fmt.Println(strings.Repeat("-", 12*5+4))
	fmt.Printf("%-12s %12d %12d %12d %12d\n", "summary", summary.Files, summary.Binary, summary.Blank, summary.Code)
}

func FileWorker(files chan string, result chan CountByExt, progress *int64) {
	total := make(CountByExt)
	defer func() { result <- total }()

	for file := range files {
		count, err := CountLines(file)
		if err != nil {
			continue
		}
		total.Add(count)
		atomic.AddInt64(progress, 1)
	}
}

func IterateDir(work chan string, roots ...string) {
	walk := func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		if info.IsDir() {
			info.Mode()
			filename := info.Name()
			if len(filename) > 1 && filename[0] == '.' {
				return filepath.SkipDir
			}
			return nil
		}

		// if a filename contains ~ we assume it's a temporary file
		if strings.Contains(filepath.Base(path), "~") {
			return nil
		}

		if !ShouldExamine(filepath.Ext(path)) {
			return nil
		}

		work <- path
		return nil
	}

	for _, root := range roots {
		err := filepath.Walk(root, walk)
		if err != nil {
			log.Println(err)
		}
	}

	close(work)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"log"
	"os"

	"github.com/nlopes/slack"

	k8s "k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/watch"
)

type message struct {
	msg       string
	obj       string
	name      string
	reason    string
	component string
	color     string
	count     int
	eventType string
}

type messager interface {
	sendMessage(message) error
}

func getWhitelist(wlStr string) (wl whitelist) {
	if wlStr == "" {
		return nil
	}

	if err := json.Unmarshal([]byte(wlStr), &wl); err != nil {
		return nil
	}

	return wl
}

func getTypes(typeStr string) (tm map[watch.EventType]bool) {
	if typeStr == "" {
		return nil
	}

	var types []watch.EventType
	if err := json.Unmarshal([]byte(typeStr), &types); err != nil {
		return nil
	}

	tm = make(map[watch.EventType]bool)
	for _, t := range types {
		tm[t] = true
	}

	return tm
}

func main() {
	cl, err := k8s.NewInCluster()
	if err != nil {
		log.Fatalf("Failed to create client: %s", err)
	}

	kube := &kubeCfg{
		kubeClient: cl,
		types:      getTypes(os.Getenv("EVENT_TYPES")),
		whitelist:  getWhitelist(os.Getenv("WHITELIST")),
	}

	msgr := &slackCfg{
		messagePoster: slack.New(os.Getenv("SLACK_TOKEN")),
		channel:       os.Getenv("SLACK_CHANNEL"),
		env:           os.Getenv("ENV"),
	}

	err = kube.watchEvents(msgr)
	if err != nil {
		log.Fatalf("Error from watchEvents(): %s", err)
	}

	log.Println("Terminating...")
}
<commit_msg>Increase verbosity on startup<commit_after>package main

import (
	"encoding/json"
	"log"
	"os"

	"github.com/nlopes/slack"

	k8s "k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/watch"
)

type message struct {
	msg       string
	obj       string
	name      string
	reason    string
	component string
	color     string
	count     int
	eventType string
}

type messager interface {
	sendMessage(message) error
}

func getWhitelist(wlStr string) (wl whitelist) {
	if wlStr == "" {
		return nil
	}

	if err := json.Unmarshal([]byte(wlStr), &wl); err != nil {
		return nil
	}

	return wl
}

func getTypes(typeStr string) (tm map[watch.EventType]bool) {
	if typeStr == "" {
		return nil
	}

	var types []watch.EventType
	if err := json.Unmarshal([]byte(typeStr), &types); err != nil {
		return nil
	}

	tm = make(map[watch.EventType]bool)
	for _, t := range types {
		tm[t] = true
	}

	return tm
}

func main() {
	cl, err := k8s.NewInCluster()
	if err != nil {
		log.Fatalf("Failed to create client: %s", err)
	}

	kube := &kubeCfg{
		kubeClient: cl,
		types:      getTypes(os.Getenv("EVENT_TYPES")),
		whitelist:  getWhitelist(os.Getenv("WHITELIST")),
	}

	if kube.types != nil {
		log.Printf("types filtered: %v", kube.types)
	}

	if kube.whitelist != nil {
		log.Printf("whitelist configured:")
		for _, w := range kube.whitelist {
			log.Printf("entry: %v", w)
		}
	}

	msgr := &slackCfg{
		messagePoster: slack.New(os.Getenv("SLACK_TOKEN")),
		channel:       os.Getenv("SLACK_CHANNEL"),
		env:           os.Getenv("ENV"),
	}

	log.Printf("posting to channel %s", msgr.channel)
	if msgr.env != "" {
		log.Printf("running in env %s", msgr.env)
	}

	err = kube.watchEvents(msgr)
	if err != nil {
		log.Fatalf("Error from watchEvents(): %s", err)
	}

	log.Println("Terminating...")
}
<|endoftext|>


<commit_before>/*
 * Copyright 2016 Martin Helmich <kontakt@martin-helmich.de>
 *
 * 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 (
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"github.com/hpcloud/tail"
	"github.com/martin-helmich/prometheus-nginxlog-exporter/config"
	"github.com/martin-helmich/prometheus-nginxlog-exporter/discovery"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/satyrius/gonx"
	"github.com/martin-helmich/prometheus-nginxlog-exporter/relabeling"
)

// Metrics is a struct containing pointers to all metrics that should be
// exposed to Prometheus
type Metrics struct {
	countTotal          *prometheus.CounterVec
	bytesTotal          *prometheus.CounterVec
	upstreamSeconds     *prometheus.SummaryVec
	upstreamSecondsHist *prometheus.HistogramVec
	responseSeconds     *prometheus.SummaryVec
	responseSecondsHist *prometheus.HistogramVec
}

// Init initializes a metrics struct
func (m *Metrics) Init(cfg *config.NamespaceConfig) {
	cfg.MustCompile()

	labels := cfg.OrderedLabelNames

	for _, r := range relabeling.DefaultRelabelings {
		labels = append(labels, r.TargetLabel)
	}

	for i := range cfg.RelabelConfigs {
		labels = append(labels, cfg.RelabelConfigs[i].TargetLabel)
	}

	m.countTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
		Namespace: cfg.Name,
		Name:      "http_response_count_total",
		Help:      "Amount of processed HTTP requests",
	}, labels)

	m.bytesTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
		Namespace: cfg.Name,
		Name:      "http_response_size_bytes",
		Help:      "Total amount of transferred bytes",
	}, labels)

	m.upstreamSeconds = prometheus.NewSummaryVec(prometheus.SummaryOpts{
		Namespace: cfg.Name,
		Name:      "http_upstream_time_seconds",
		Help:      "Time needed by upstream servers to handle requests",
	}, labels)

	m.upstreamSecondsHist = prometheus.NewHistogramVec(prometheus.HistogramOpts{
		Namespace: cfg.Name,
		Name:      "http_upstream_time_seconds_hist",
		Help:      "Time needed by upstream servers to handle requests",
	}, labels)

	m.responseSeconds = prometheus.NewSummaryVec(prometheus.SummaryOpts{
		Namespace: cfg.Name,
		Name:      "http_response_time_seconds",
		Help:      "Time needed by NGINX to handle requests",
	}, labels)

	m.responseSecondsHist = prometheus.NewHistogramVec(prometheus.HistogramOpts{
		Namespace: cfg.Name,
		Name:      "http_response_time_seconds_hist",
		Help:      "Time needed by NGINX to handle requests",
	}, labels)

	prometheus.MustRegister(m.countTotal)
	prometheus.MustRegister(m.bytesTotal)
	prometheus.MustRegister(m.upstreamSeconds)
	prometheus.MustRegister(m.upstreamSecondsHist)
	prometheus.MustRegister(m.responseSeconds)
	prometheus.MustRegister(m.responseSecondsHist)
}

func main() {
	var opts config.StartupFlags
	var cfg = config.Config{
		Listen: config.ListenConfig{
			Port:    4040,
			Address: "0.0.0.0",
		},
	}

	flag.IntVar(&opts.ListenPort, "listen-port", 4040, "HTTP port to listen on")
	flag.StringVar(&opts.Format, "format", `$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"`, "NGINX access log format")
	flag.StringVar(&opts.Namespace, "namespace", "nginx", "namespace to use for metric names")
	flag.StringVar(&opts.ConfigFile, "config-file", "", "Configuration file to read from")
	flag.BoolVar(&opts.EnableExperimentalFeatures, "enable-experimental", false, "Set this flag to enable experimental features")
	flag.Parse()

	opts.Filenames = flag.Args()

	if opts.ConfigFile != "" {
		fmt.Printf("loading configuration file %s\n", opts.ConfigFile)
		if err := config.LoadConfigFromFile(&cfg, opts.ConfigFile); err != nil {
			panic(err)
		}
	} else if err := config.LoadConfigFromFlags(&cfg, &opts); err != nil {
		panic(err)
	}

	fmt.Printf("using configuration %s\n", cfg)

	if stabilityError := cfg.StabilityWarnings(); stabilityError != nil && !opts.EnableExperimentalFeatures {
		fmt.Fprintf(os.Stderr, "Your configuration file contains an option that is explicitly labeled as experimental feature:\n\n  %s\n\n", stabilityError.Error())
		fmt.Fprintln(os.Stderr, "Use the -enable-experimental flag or the enable_experimental option to enable these features. Use them at your own peril.")

		os.Exit(1)
	}

	if cfg.Consul.Enable {
		registrator, err := discovery.NewConsulRegistrator(&cfg)
		if err != nil {
			panic(err)
		}

		fmt.Printf("registering service in Consul\n")
		if err := registrator.RegisterConsul(); err != nil {
			panic(err)
		}

		exitChan := make(chan os.Signal, 1)
		signal.Notify(exitChan, os.Interrupt, syscall.SIGTERM)

		go func() {
			<-exitChan
			fmt.Printf("unregistering service in Consul\n")
			registrator.UnregisterConsul()
			os.Exit(0)
		}()
	}

	for _, ns := range cfg.Namespaces {
		fmt.Printf("starting listener for namespace %s\n", ns.Name)

		go func(nsCfg config.NamespaceConfig) {
			parser := gonx.NewParser(nsCfg.Format)

			metrics := Metrics{}
			metrics.Init(&nsCfg)

			for _, f := range nsCfg.SourceFiles {
				t, err := tail.TailFile(f, tail.Config{
					Follow: true,
					ReOpen: true,
					Poll:   true,
				})
				if err != nil {
					panic(err)
				}

				go func(nsCfg config.NamespaceConfig) {
					relabelings := relabeling.NewRelabelings(nsCfg.RelabelConfigs)
					relabelings = append(relabeling.DefaultRelabelings, relabelings...)

					staticLabelValues := nsCfg.OrderedLabelValues

					totalLabelCount := len(staticLabelValues) + len(relabelings)
					relabelLabelOffset := len(staticLabelValues)
					labelValues := make([]string, totalLabelCount)

					for i := range staticLabelValues {
						labelValues[i] = staticLabelValues[i]
					}

					for line := range t.Lines {
						entry, err := parser.ParseString(line.Text)
						if err != nil {
							fmt.Printf("error while parsing line '%s': %s", line.Text, err)
							continue
						}

						for i := range relabelings {
							if str, err := entry.Field(relabelings[i].SourceValue); err == nil {
								mapped, err := relabelings[i].Map(str)
								if err == nil {
									labelValues[i + relabelLabelOffset] = mapped
								}
							}
						}

						metrics.countTotal.WithLabelValues(labelValues...).Inc()

						if bytes, err := entry.FloatField("body_bytes_sent"); err == nil {
							metrics.bytesTotal.WithLabelValues(labelValues...).Add(bytes)
						}

						if upstreamTime, err := entry.FloatField("upstream_response_time"); err == nil {
							metrics.upstreamSeconds.WithLabelValues(labelValues...).Observe(upstreamTime)
							metrics.upstreamSecondsHist.WithLabelValues(labelValues...).Observe(upstreamTime)
						}

						if responseTime, err := entry.FloatField("request_time"); err == nil {
							metrics.responseSeconds.WithLabelValues(labelValues...).Observe(responseTime)
							metrics.responseSecondsHist.WithLabelValues(labelValues...).Observe(responseTime)
						}
					}
				}(nsCfg)
			}
		}(ns)
	}

	listenAddr := fmt.Sprintf("%s:%d", cfg.Listen.Address, cfg.Listen.Port)
	fmt.Printf("running HTTP server on address %s\n", listenAddr)

	http.Handle("/metrics", prometheus.Handler())
	http.ListenAndServe(listenAddr, nil)
}
<commit_msg>Add missing line break after printing parsing error<commit_after>/*
 * Copyright 2016 Martin Helmich <kontakt@martin-helmich.de>
 *
 * 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 (
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"github.com/hpcloud/tail"
	"github.com/martin-helmich/prometheus-nginxlog-exporter/config"
	"github.com/martin-helmich/prometheus-nginxlog-exporter/discovery"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/satyrius/gonx"
	"github.com/martin-helmich/prometheus-nginxlog-exporter/relabeling"
)

// Metrics is a struct containing pointers to all metrics that should be
// exposed to Prometheus
type Metrics struct {
	countTotal          *prometheus.CounterVec
	bytesTotal          *prometheus.CounterVec
	upstreamSeconds     *prometheus.SummaryVec
	upstreamSecondsHist *prometheus.HistogramVec
	responseSeconds     *prometheus.SummaryVec
	responseSecondsHist *prometheus.HistogramVec
}

// Init initializes a metrics struct
func (m *Metrics) Init(cfg *config.NamespaceConfig) {
	cfg.MustCompile()

	labels := cfg.OrderedLabelNames

	for _, r := range relabeling.DefaultRelabelings {
		labels = append(labels, r.TargetLabel)
	}

	for i := range cfg.RelabelConfigs {
		labels = append(labels, cfg.RelabelConfigs[i].TargetLabel)
	}

	m.countTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
		Namespace: cfg.Name,
		Name:      "http_response_count_total",
		Help:      "Amount of processed HTTP requests",
	}, labels)

	m.bytesTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
		Namespace: cfg.Name,
		Name:      "http_response_size_bytes",
		Help:      "Total amount of transferred bytes",
	}, labels)

	m.upstreamSeconds = prometheus.NewSummaryVec(prometheus.SummaryOpts{
		Namespace: cfg.Name,
		Name:      "http_upstream_time_seconds",
		Help:      "Time needed by upstream servers to handle requests",
	}, labels)

	m.upstreamSecondsHist = prometheus.NewHistogramVec(prometheus.HistogramOpts{
		Namespace: cfg.Name,
		Name:      "http_upstream_time_seconds_hist",
		Help:      "Time needed by upstream servers to handle requests",
	}, labels)

	m.responseSeconds = prometheus.NewSummaryVec(prometheus.SummaryOpts{
		Namespace: cfg.Name,
		Name:      "http_response_time_seconds",
		Help:      "Time needed by NGINX to handle requests",
	}, labels)

	m.responseSecondsHist = prometheus.NewHistogramVec(prometheus.HistogramOpts{
		Namespace: cfg.Name,
		Name:      "http_response_time_seconds_hist",
		Help:      "Time needed by NGINX to handle requests",
	}, labels)

	prometheus.MustRegister(m.countTotal)
	prometheus.MustRegister(m.bytesTotal)
	prometheus.MustRegister(m.upstreamSeconds)
	prometheus.MustRegister(m.upstreamSecondsHist)
	prometheus.MustRegister(m.responseSeconds)
	prometheus.MustRegister(m.responseSecondsHist)
}

func main() {
	var opts config.StartupFlags
	var cfg = config.Config{
		Listen: config.ListenConfig{
			Port:    4040,
			Address: "0.0.0.0",
		},
	}

	flag.IntVar(&opts.ListenPort, "listen-port", 4040, "HTTP port to listen on")
	flag.StringVar(&opts.Format, "format", `$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"`, "NGINX access log format")
	flag.StringVar(&opts.Namespace, "namespace", "nginx", "namespace to use for metric names")
	flag.StringVar(&opts.ConfigFile, "config-file", "", "Configuration file to read from")
	flag.BoolVar(&opts.EnableExperimentalFeatures, "enable-experimental", false, "Set this flag to enable experimental features")
	flag.Parse()

	opts.Filenames = flag.Args()

	if opts.ConfigFile != "" {
		fmt.Printf("loading configuration file %s\n", opts.ConfigFile)
		if err := config.LoadConfigFromFile(&cfg, opts.ConfigFile); err != nil {
			panic(err)
		}
	} else if err := config.LoadConfigFromFlags(&cfg, &opts); err != nil {
		panic(err)
	}

	fmt.Printf("using configuration %s\n", cfg)

	if stabilityError := cfg.StabilityWarnings(); stabilityError != nil && !opts.EnableExperimentalFeatures {
		fmt.Fprintf(os.Stderr, "Your configuration file contains an option that is explicitly labeled as experimental feature:\n\n  %s\n\n", stabilityError.Error())
		fmt.Fprintln(os.Stderr, "Use the -enable-experimental flag or the enable_experimental option to enable these features. Use them at your own peril.")

		os.Exit(1)
	}

	if cfg.Consul.Enable {
		registrator, err := discovery.NewConsulRegistrator(&cfg)
		if err != nil {
			panic(err)
		}

		fmt.Printf("registering service in Consul\n")
		if err := registrator.RegisterConsul(); err != nil {
			panic(err)
		}

		exitChan := make(chan os.Signal, 1)
		signal.Notify(exitChan, os.Interrupt, syscall.SIGTERM)

		go func() {
			<-exitChan
			fmt.Printf("unregistering service in Consul\n")
			registrator.UnregisterConsul()
			os.Exit(0)
		}()
	}

	for _, ns := range cfg.Namespaces {
		fmt.Printf("starting listener for namespace %s\n", ns.Name)

		go func(nsCfg config.NamespaceConfig) {
			parser := gonx.NewParser(nsCfg.Format)

			metrics := Metrics{}
			metrics.Init(&nsCfg)

			for _, f := range nsCfg.SourceFiles {
				t, err := tail.TailFile(f, tail.Config{
					Follow: true,
					ReOpen: true,
					Poll:   true,
				})
				if err != nil {
					panic(err)
				}

				go func(nsCfg config.NamespaceConfig) {
					relabelings := relabeling.NewRelabelings(nsCfg.RelabelConfigs)
					relabelings = append(relabeling.DefaultRelabelings, relabelings...)

					staticLabelValues := nsCfg.OrderedLabelValues

					totalLabelCount := len(staticLabelValues) + len(relabelings)
					relabelLabelOffset := len(staticLabelValues)
					labelValues := make([]string, totalLabelCount)

					for i := range staticLabelValues {
						labelValues[i] = staticLabelValues[i]
					}

					for line := range t.Lines {
						entry, err := parser.ParseString(line.Text)
						if err != nil {
							fmt.Printf("error while parsing line '%s': %s\n", line.Text, err)
							continue
						}

						for i := range relabelings {
							if str, err := entry.Field(relabelings[i].SourceValue); err == nil {
								mapped, err := relabelings[i].Map(str)
								if err == nil {
									labelValues[i + relabelLabelOffset] = mapped
								}
							}
						}

						metrics.countTotal.WithLabelValues(labelValues...).Inc()

						if bytes, err := entry.FloatField("body_bytes_sent"); err == nil {
							metrics.bytesTotal.WithLabelValues(labelValues...).Add(bytes)
						}

						if upstreamTime, err := entry.FloatField("upstream_response_time"); err == nil {
							metrics.upstreamSeconds.WithLabelValues(labelValues...).Observe(upstreamTime)
							metrics.upstreamSecondsHist.WithLabelValues(labelValues...).Observe(upstreamTime)
						}

						if responseTime, err := entry.FloatField("request_time"); err == nil {
							metrics.responseSeconds.WithLabelValues(labelValues...).Observe(responseTime)
							metrics.responseSecondsHist.WithLabelValues(labelValues...).Observe(responseTime)
						}
					}
				}(nsCfg)
			}
		}(ns)
	}

	listenAddr := fmt.Sprintf("%s:%d", cfg.Listen.Address, cfg.Listen.Port)
	fmt.Printf("running HTTP server on address %s\n", listenAddr)

	http.Handle("/metrics", prometheus.Handler())
	http.ListenAndServe(listenAddr, nil)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/russross/blackfriday"
	"net/http"
	"os"
)

func main() {
	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}

	http.HandleFunc("/markdown", GenerateMarkdown)
	http.Handle("/", http.FileServer(http.Dir("public")))
	http.ListenAndServe(":"+port, nil)
}

func GenerateMarkdown(rw http.ResponseWriter, r *http.Request) {
	markdown := blackfriday.MarkdownCommon([]byte(r.FormValue("body")))
	rw.Write(markdown)
}
<commit_msg>Do not export GenerateMarkdown func<commit_after>package main

import (
	"github.com/russross/blackfriday"
	"net/http"
	"os"
)

func main() {
	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}

	http.HandleFunc("/markdown", generateMarkdown)
	http.Handle("/", http.FileServer(http.Dir("public")))
	http.ListenAndServe(":"+port, nil)
}

func generateMarkdown(rw http.ResponseWriter, r *http.Request) {
	markdown := blackfriday.MarkdownCommon([]byte(r.FormValue("body")))
	rw.Write(markdown)
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"math/rand"
	"net/http"
	"time"

	"gopkg.in/alecthomas/kingpin.v2"

	log "github.com/Sirupsen/logrus"
)

const (
	interval  = 3 * time.Second
	execDigit = 5
	baseURL   = "https://git.io"
)

var (
	n = kingpin.Flag("dry-run", "dry run mode.").Short('n').Bool()
	c = new(http.Client)
)

func init() {
	kingpin.Parse()
	c.CheckRedirect = func(req *http.Request, via []*http.Request) error { return errors.New("not redirect") }
}

func main() {
	runes := []rune{'0'}

	for {
		checkPath("/" + string(runes))

		runes = advanceRunes(runes)

		if len(runes) > execDigit {
			// exit
			break
		}

		time.Sleep(interval)
	}
}

func checkPath(path string) {
	if *n {
		dryRun(path)
		return
	}

	resp, err := c.Get(baseURL + path)
	if err == nil {
		resp.Body.Close()
	}

	if resp.StatusCode == 404 {
		okLog(path)
	} else {
		ngLog(path, resp.Header.Get("Location"))
	}
}

func advanceRunes(runes []rune) []rune {
	if runes[len(runes)-1] == 'Z' {
		// carry over
		addFlg := true
		for i := len(runes) - 1; i > -1; i-- {
			beforeRune := runes[i]
			runes[i] = getNextRune(runes[i])
			if beforeRune != 'Z' {
				addFlg = false
				break
			}
		}

		if addFlg {
			runes = append(runes, '0')
		}
	} else {
		runes[len(runes)-1] = getNextRune(runes[len(runes)-1])
	}

	return runes
}

func getNextRune(r rune) rune {
	// 0 -> 9, a -> z, A -> Z
	if r == '9' {
		return 'a'
	} else if r == 'z' {
		return 'A'
	} else if r == 'Z' {
		return '0'
	}

	r++
	return r
}

func okLog(path string) {
	log.WithFields(log.Fields{"path": path}).Info("ok!")
}

func ngLog(path string, location string) {
	log.WithFields(log.Fields{"path": path, "location": location}).Error("ng.")
}

func dryRun(path string) {
	if rand.Intn(2) == 1 {
		okLog(path)
	} else {
		ngLog(path, "https://example.com/")
	}
}
<commit_msg>add interval option. #6<commit_after>package main

import (
	"errors"
	"math/rand"
	"net/http"
	"time"

	"gopkg.in/alecthomas/kingpin.v2"

	log "github.com/Sirupsen/logrus"
)

const (
	execDigit = 5
	baseURL   = "https://git.io"
)

var (
	interval = kingpin.Flag("interval", "interval time.").Default((3 * time.Second).String()).Duration()
	n        = kingpin.Flag("dry-run", "dry run mode.").Short('n').Bool()
	c        = new(http.Client)
)

func init() {
	kingpin.Parse()
	c.CheckRedirect = func(req *http.Request, via []*http.Request) error { return errors.New("not redirect") }
}

func main() {
	runes := []rune{'0'}

	for {
		checkPath("/" + string(runes))

		runes = advanceRunes(runes)

		if len(runes) > execDigit {
			// exit
			break
		}

		time.Sleep(*interval)
	}
}

func checkPath(path string) {
	if *n {
		dryRun(path)
		return
	}

	resp, err := c.Get(baseURL + path)
	if err == nil {
		resp.Body.Close()
	}

	if resp.StatusCode == 404 {
		okLog(path)
	} else {
		ngLog(path, resp.Header.Get("Location"))
	}
}

func advanceRunes(runes []rune) []rune {
	if runes[len(runes)-1] == 'Z' {
		// carry over
		addFlg := true
		for i := len(runes) - 1; i > -1; i-- {
			beforeRune := runes[i]
			runes[i] = getNextRune(runes[i])
			if beforeRune != 'Z' {
				addFlg = false
				break
			}
		}

		if addFlg {
			runes = append(runes, '0')
		}
	} else {
		runes[len(runes)-1] = getNextRune(runes[len(runes)-1])
	}

	return runes
}

func getNextRune(r rune) rune {
	// 0 -> 9, a -> z, A -> Z
	if r == '9' {
		return 'a'
	} else if r == 'z' {
		return 'A'
	} else if r == 'Z' {
		return '0'
	}

	r++
	return r
}

func okLog(path string) {
	log.WithFields(log.Fields{"path": path}).Info("ok!")
}

func ngLog(path string, location string) {
	log.WithFields(log.Fields{"path": path, "location": location}).Error("ng.")
}

func dryRun(path string) {
	if rand.Intn(2) == 1 {
		okLog(path)
	} else {
		ngLog(path, "https://example.com/")
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 HyperHQ Inc.
//
// SPDX-License-Identifier: Apache-2.0
//

package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log/syslog"
	"os"
	"os/signal"
	"runtime"
	"sync"
	"time"

	opentracing "github.com/opentracing/opentracing-go"
	"github.com/sirupsen/logrus"
	lSyslog "github.com/sirupsen/logrus/hooks/syslog"
	context "golang.org/x/net/context"
)

const (
	shimName    = "kata-shim"
	exitFailure = 1
	exitSuccess = 0
	// Max number of threads the shim should consume.
	// We choose 6 as we want a couple of threads for the runtime (gc etc.)
	// and couple of threads for our parallel user code, such as the copy
	// code in shim.go
	maxThreads = 6
)

// version is the shim version. This variable is populated at build time.
var version = "unknown"

var debug bool

// if true, coredump when an internal error occurs or a fatal signal is received
var crashOnError = false

// if true, enable opentracing support.
var tracing = false

var shimLog *logrus.Entry

func logger() *logrus.Entry {
	return shimLog
}

func initLogger(logLevel, container, execID string, announceFields logrus.Fields, loggerOutput io.Writer) error {
	shimLog = logrus.WithFields(logrus.Fields{
		"name":      shimName,
		"pid":       os.Getpid(),
		"source":    "shim",
		"container": container,
		"exec-id":   execID,
	})

	shimLog.Logger.Formatter = &logrus.TextFormatter{TimestampFormat: time.RFC3339Nano}

	level, err := logrus.ParseLevel(logLevel)
	if err != nil {
		return err
	}

	shimLog.Logger.SetLevel(level)

	shimLog.Logger.Out = loggerOutput

	hook, err := lSyslog.NewSyslogHook("", "", syslog.LOG_INFO|syslog.LOG_USER, shimName)
	if err == nil {
		shimLog.Logger.AddHook(hook)
	}

	logger().WithFields(announceFields).Info("announce")

	return nil
}

func setThreads() {
	// If GOMAXPROCS has not been set, restrict our thread usage
	// so we don't grow many idle threads on large core count systems,
	// which un-necessarily consume host PID space (and thus set an
	// artificial max limit on the number of concurrent containers we can
	// run)
	if os.Getenv("GOMAXPROCS") == "" {
		if runtime.NumCPU() > maxThreads {
			runtime.GOMAXPROCS(maxThreads)
		}
	}
}

func realMain(ctx context.Context) (exitCode int) {
	var (
		logLevel      string
		agentAddr     string
		container     string
		execID        string
		terminal      bool
		proxyExitCode bool
		showVersion   bool
	)

	setThreads()

	flag.BoolVar(&debug, "debug", false, "enable debug mode")
	flag.BoolVar(&tracing, "trace", false, "enable opentracing support")
	flag.BoolVar(&showVersion, "version", false, "display program version and exit")
	flag.StringVar(&logLevel, "log", "warn", "set shim log level: debug, info, warn, error, fatal or panic")
	flag.StringVar(&agentAddr, "agent", "", "agent gRPC socket endpoint")

	flag.StringVar(&container, "container", "", "container id for the shim")
	flag.StringVar(&execID, "exec-id", "", "process id for the shim")
	flag.BoolVar(&terminal, "terminal", false, "specify if a terminal is setup")
	flag.BoolVar(&proxyExitCode, "proxy-exit-code", true, "proxy exit code of the process")

	flag.Parse()

	if showVersion {
		fmt.Printf("%v version %v\n", shimName, version)
		return exitSuccess
	}

	if logLevel == "debug" {
		debug = true
	}

	if debug {
		crashOnError = true
	}

	if agentAddr == "" || container == "" || execID == "" {
		logger().WithField("agentAddr", agentAddr).WithField("container", container).WithField("exec-id", execID).Error("container ID, exec ID and agent socket endpoint must be set")
		return exitFailure
	}

	announceFields := logrus.Fields{
		"version":         version,
		"debug":           debug,
		"log-level":       logLevel,
		"agent-socket":    agentAddr,
		"terminal":        terminal,
		"proxy-exit-code": proxyExitCode,
		"tracing":         tracing,
	}

	// The final parameter makes sure all output going to stdout/stderr is discarded.
	err := initLogger(logLevel, container, execID, announceFields, ioutil.Discard)
	if err != nil {
		logger().WithError(err).WithField("loglevel", logLevel).Error("invalid log level")
		return exitFailure
	}

	// Initialise tracing now the logger is ready
	tracer, err := createTracer(shimName)
	if err != nil {
		logger().WithError(err).Fatal("failed to setup tracing")
		return exitFailure
	}

	// create root span
	span := tracer.StartSpan("realMain")
	ctx = opentracing.ContextWithSpan(ctx, span)
	defer span.Finish()

	shim, err := newShim(ctx, agentAddr, container, execID)
	if err != nil {
		logger().WithError(err).Error("failed to create new shim")
		return exitFailure
	}

	// winsize
	if terminal {
		termios, err := setupTerminal(int(os.Stdin.Fd()))
		if err != nil {
			logger().WithError(err).Error("failed to set raw terminal")
			return exitFailure
		}
		defer restoreTerminal(int(os.Stdin.Fd()), termios)
	}

	// signals
	sigc := shim.handleSignals(ctx, os.Stdin)
	defer signal.Stop(sigc)

	// This wait call cannot be deferred and has to wait for every
	// input/output to return before the code tries to go further
	// and wait for the process. Indeed, after the process has been
	// waited for, we cannot expect to do any more calls related to
	// this process since it is going to be removed from the agent.
	wg := &sync.WaitGroup{}

	// Encapsulate the call the I/O handling function in a span here since
	// that function returns quickly and we want to know how long I/O
	// took.
	stdioSpan, _ := trace(ctx, "proxyStdio")

	// Add a tag to allow the I/O to be filtered out.
	stdioSpan.SetTag("category", "interactive")

	shim.proxyStdio(wg, terminal)

	wg.Wait()

	stdioSpan.Finish()

	// wait until exit
	exitcode, err := shim.wait()
	if err != nil {
		logger().WithError(err).WithField("exec-id", execID).Error("failed waiting for process")
		return exitFailure
	} else if proxyExitCode {
		logger().WithField("exitcode", exitcode).Info("using shim to proxy exit code")
		if exitcode != 0 {
			return int(exitcode)
		}
	}

	return exitSuccess
}

func main() {
	// create a new empty context
	ctx := context.Background()

	defer handlePanic(ctx)

	exitCode := realMain(ctx)

	stopTracing(ctx)

	os.Exit(exitCode)
}
<commit_msg>logger: log to std logger if shimLog is not yet inited<commit_after>// Copyright 2017 HyperHQ Inc.
//
// SPDX-License-Identifier: Apache-2.0
//

package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log/syslog"
	"os"
	"os/signal"
	"runtime"
	"sync"
	"time"

	opentracing "github.com/opentracing/opentracing-go"
	"github.com/sirupsen/logrus"
	lSyslog "github.com/sirupsen/logrus/hooks/syslog"
	context "golang.org/x/net/context"
)

const (
	shimName    = "kata-shim"
	exitFailure = 1
	exitSuccess = 0
	// Max number of threads the shim should consume.
	// We choose 6 as we want a couple of threads for the runtime (gc etc.)
	// and couple of threads for our parallel user code, such as the copy
	// code in shim.go
	maxThreads = 6
)

// version is the shim version. This variable is populated at build time.
var version = "unknown"

var debug bool

// if true, coredump when an internal error occurs or a fatal signal is received
var crashOnError = false

// if true, enable opentracing support.
var tracing = false

var shimLog *logrus.Entry

func logger() *logrus.Entry {
	if shimLog != nil {
		return shimLog
	}
	return logrus.NewEntry(logrus.StandardLogger())
}

func initLogger(logLevel, container, execID string, announceFields logrus.Fields, loggerOutput io.Writer) error {
	shimLog = logrus.WithFields(logrus.Fields{
		"name":      shimName,
		"pid":       os.Getpid(),
		"source":    "shim",
		"container": container,
		"exec-id":   execID,
	})

	shimLog.Logger.Formatter = &logrus.TextFormatter{TimestampFormat: time.RFC3339Nano}

	level, err := logrus.ParseLevel(logLevel)
	if err != nil {
		return err
	}

	shimLog.Logger.SetLevel(level)

	shimLog.Logger.Out = loggerOutput

	hook, err := lSyslog.NewSyslogHook("", "", syslog.LOG_INFO|syslog.LOG_USER, shimName)
	if err == nil {
		shimLog.Logger.AddHook(hook)
	}

	logger().WithFields(announceFields).Info("announce")

	return nil
}

func setThreads() {
	// If GOMAXPROCS has not been set, restrict our thread usage
	// so we don't grow many idle threads on large core count systems,
	// which un-necessarily consume host PID space (and thus set an
	// artificial max limit on the number of concurrent containers we can
	// run)
	if os.Getenv("GOMAXPROCS") == "" {
		if runtime.NumCPU() > maxThreads {
			runtime.GOMAXPROCS(maxThreads)
		}
	}
}

func realMain(ctx context.Context) (exitCode int) {
	var (
		logLevel      string
		agentAddr     string
		container     string
		execID        string
		terminal      bool
		proxyExitCode bool
		showVersion   bool
	)

	setThreads()

	flag.BoolVar(&debug, "debug", false, "enable debug mode")
	flag.BoolVar(&tracing, "trace", false, "enable opentracing support")
	flag.BoolVar(&showVersion, "version", false, "display program version and exit")
	flag.StringVar(&logLevel, "log", "warn", "set shim log level: debug, info, warn, error, fatal or panic")
	flag.StringVar(&agentAddr, "agent", "", "agent gRPC socket endpoint")

	flag.StringVar(&container, "container", "", "container id for the shim")
	flag.StringVar(&execID, "exec-id", "", "process id for the shim")
	flag.BoolVar(&terminal, "terminal", false, "specify if a terminal is setup")
	flag.BoolVar(&proxyExitCode, "proxy-exit-code", true, "proxy exit code of the process")

	flag.Parse()

	if showVersion {
		fmt.Printf("%v version %v\n", shimName, version)
		return exitSuccess
	}

	if logLevel == "debug" {
		debug = true
	}

	if debug {
		crashOnError = true
	}

	if agentAddr == "" || container == "" || execID == "" {
		logger().WithField("agentAddr", agentAddr).WithField("container", container).WithField("exec-id", execID).Error("container ID, exec ID and agent socket endpoint must be set")
		return exitFailure
	}

	announceFields := logrus.Fields{
		"version":         version,
		"debug":           debug,
		"log-level":       logLevel,
		"agent-socket":    agentAddr,
		"terminal":        terminal,
		"proxy-exit-code": proxyExitCode,
		"tracing":         tracing,
	}

	// The final parameter makes sure all output going to stdout/stderr is discarded.
	err := initLogger(logLevel, container, execID, announceFields, ioutil.Discard)
	if err != nil {
		logger().WithError(err).WithField("loglevel", logLevel).Error("invalid log level")
		return exitFailure
	}

	// Initialise tracing now the logger is ready
	tracer, err := createTracer(shimName)
	if err != nil {
		logger().WithError(err).Fatal("failed to setup tracing")
		return exitFailure
	}

	// create root span
	span := tracer.StartSpan("realMain")
	ctx = opentracing.ContextWithSpan(ctx, span)
	defer span.Finish()

	shim, err := newShim(ctx, agentAddr, container, execID)
	if err != nil {
		logger().WithError(err).Error("failed to create new shim")
		return exitFailure
	}

	// winsize
	if terminal {
		termios, err := setupTerminal(int(os.Stdin.Fd()))
		if err != nil {
			logger().WithError(err).Error("failed to set raw terminal")
			return exitFailure
		}
		defer restoreTerminal(int(os.Stdin.Fd()), termios)
	}

	// signals
	sigc := shim.handleSignals(ctx, os.Stdin)
	defer signal.Stop(sigc)

	// This wait call cannot be deferred and has to wait for every
	// input/output to return before the code tries to go further
	// and wait for the process. Indeed, after the process has been
	// waited for, we cannot expect to do any more calls related to
	// this process since it is going to be removed from the agent.
	wg := &sync.WaitGroup{}

	// Encapsulate the call the I/O handling function in a span here since
	// that function returns quickly and we want to know how long I/O
	// took.
	stdioSpan, _ := trace(ctx, "proxyStdio")

	// Add a tag to allow the I/O to be filtered out.
	stdioSpan.SetTag("category", "interactive")

	shim.proxyStdio(wg, terminal)

	wg.Wait()

	stdioSpan.Finish()

	// wait until exit
	exitcode, err := shim.wait()
	if err != nil {
		logger().WithError(err).WithField("exec-id", execID).Error("failed waiting for process")
		return exitFailure
	} else if proxyExitCode {
		logger().WithField("exitcode", exitcode).Info("using shim to proxy exit code")
		if exitcode != 0 {
			return int(exitcode)
		}
	}

	return exitSuccess
}

func main() {
	// create a new empty context
	ctx := context.Background()

	defer handlePanic(ctx)

	exitCode := realMain(ctx)

	stopTracing(ctx)

	os.Exit(exitCode)
}
<|endoftext|>


<commit_before>package main

import (
	"archive/tar"
	"bytes"
	"compress/gzip"
	"encoding/json"
	"errors"
	"flag"
	"github.com/gorilla/mux"
	"io"
	"log"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"strings"
)

func (bh BoxHandler) GetBox(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	user := vars["user"]
	boxName := vars["boxname"]
	log.Println("Queried for ", user, "/", boxName)
	box := bh.Boxes[user][boxName]

	jsonResponse, _ := json.Marshal(box)

	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.Write(jsonResponse)
}

func (bh BoxHandler) DownloadBox(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	user := vars["user"]
	boxName := vars["boxname"]
	log.Println("Downloading ", user, "/", boxName)

	localBoxfile := bh.Boxes[user][boxName]
	http.ServeFile(w, r, localBoxfile.LocalBoxFile)
}

func (bh BoxHandler) CheckBox(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	user := vars["user"]
	boxName := vars["boxname"]
	log.Println("Checking ", user, "/", boxName)

	localBoxfile := bh.Boxes[user][boxName]
	if localBoxfile.Username != "" {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
	} else {
		w.WriteHeader(http.StatusNotFound)
	}
}
func (bh BoxHandler) NotFound(w http.ResponseWriter, r *http.Request) {
	log.Println("404 :", r.URL.Path, " ", r.Method)
	w.WriteHeader(http.StatusNotFound)
}

func main() {

	directory := flag.String("d", "./", "Base directory containing .box files")
	port := flag.String("port", "8099", "Port to listen on.")
	hostname := flag.String("hostname", "localhost", "Hostname for static box content.")

	absolute := *directory
	if !path.IsAbs(*directory) {
		wd, _ := os.Getwd()
		absolute = path.Clean(path.Join(wd, *directory))
	}

	log.Println("Serving files from: ", *directory)
	boxfiles := getBoxList(absolute)
	boxdata := getBoxData(boxfiles)
	boxes := createBoxes(boxdata, port, hostname)

	for namespace, boxinfo := range boxes {
		for boxname, _ := range boxinfo {
			log.Println(strings.Join([]string{"Found: ", namespace, "/", boxname}, ""))
		}
	}

	bh := BoxHandler{}
	bh.Boxes = boxes

	m := mux.NewRouter()
	m.HandleFunc("/{user}/{boxname}", bh.GetBox).Methods("GET")
	m.HandleFunc("/{user}/{boxname}", bh.CheckBox).Methods("HEAD")
	//Handling downloads that look like Vagrant Cloud
	//https://vagrantcloud.com/benphegan/boot2docker/version/2/provider/vmware_desktop.box
	m.HandleFunc("/{user}/{boxname}/{version}/provider/{boxfile}", bh.DownloadBox).Methods("GET")
	m.NotFoundHandler = http.HandlerFunc(bh.NotFound)
	http.Handle("/", m)

	log.Println("Listening on port: ", *port)
	http.ListenAndServe(":"+*port, nil)
}

type BoxHandler struct {
	Boxes map[string]map[string]Box
}

func createBoxes(sb []SimpleBox, port *string, hostname *string) map[string]map[string]Box {
	boxes := make(map[string]map[string]Box)
	for _, b := range sb {
		box := Box{}
		box.Name = b.Username + "/" + b.Boxname
		box.Username = b.Username
		box.Private = false
		box.LocalBoxFile = b.Location

		provider := Provider{}
		provider.Name = b.Provider
		provider.Hosted = "true"
		provider.DownloadUrl = "http://" + *hostname + ":" + *port + "/" + b.Username + "/" + b.Boxname + "/1/provider/" + b.Provider + ".box"
		provider.Url = provider.DownloadUrl
		version := Version{}
		version.Status = "active"
		version.Version = "1.0"

		version.Providers = []Provider{provider}

		box.Versions = []Version{version}
		box.CurrentVersion = version
		boxes[b.Username] = make(map[string]Box)
		boxes[b.Username][b.Boxname] = box
	}
	return boxes
}

func getBoxList(directory string) []string {
	directoryglob := path.Join(directory, "*.box")
	files, _ := filepath.Glob(directoryglob)
	return files
}

func getBoxData(boxfiles []string) []SimpleBox {
	results := []SimpleBox{}
	for _, b := range boxfiles {
		nameparts := strings.Split(filepath.Base(b), "-VAGRANTSLASH-")
		if len(nameparts) == 2 {
			provider, _ := getProvider(b)
			newbox := SimpleBox{}
			newbox.Username = nameparts[0]
			newbox.Boxname = nameparts[1][0 : len(nameparts[1])-4]
			newbox.Location = b
			newbox.Provider = provider.Provider
			results = append(results, newbox)
		}
	}
	return results
}

func getProvider(location string) (BoxMetadata, error) {

	log.Println("Checking: ", location)
	//boxes are .tar.gz so we have to get a gzip stream and pass to tar.
	f, _ := os.Open(location)
	r, _ := gzip.NewReader(f)
	tr := tar.NewReader(r)
	// Iterate through the files in the archive.
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			// end of tar archive
			break
		}
		if err != nil {
			log.Fatalln(err)
		}

		if hdr.Name == "metadata.json" {
			metadata := BoxMetadata{}

			boxmetadata := BoxMetadata{}

			buf := new(bytes.Buffer)
			buf.ReadFrom(tr)

			json.Unmarshal(buf.Bytes(), &boxmetadata)
			metadata.Provider = boxmetadata.Provider
			return metadata, nil
		}

	}
	return BoxMetadata{}, errors.New("box: could not find metadata.json or box malformed")
}

type BoxMetadata struct {
	Provider string `json:"provider"`
}

type SimpleBox struct {
	Username string
	Boxname  string
	Location string
	Provider string
}

type Box struct {
	Created             string    `json:"created_at"`
	Updated             string    `json:"updated_at"`
	Tag                 string    `json:"tag"`
	Name                string    `json:"name"`
	ShortDescription    string    `json:"short_description"`
	DescriptionHtml     string    `json:"description_html"`
	DescriptionMarkdown string    `json:"description_markdown"`
	Username            string    `json:"username"`
	Private             bool      `json:"private"`
	CurrentVersion      Version   `json:"current_version"`
	Versions            []Version `json:"versions"`
	LocalBoxFile        string    `json:"-"`
}

type Version struct {
	Version             string     `json:"version"`
	Status              string     `json:"status"`
	DescriptionHtml     string     `json:"description_html"`
	DescriptionMarkdown string     `json:"description_markdown"`
	Created             string     `json:"created_at"`
	Updated             string     `json:"updated_at"`
	Number              int        `json:"number"`
	Downloads           int        `json:"downloads"`
	ReleaseUrl          string     `json:"release_url"`
	RevokeUrl           string     `json:"revoke_url"`
	Providers           []Provider `json:"providers"`
}

type Provider struct {
	Name        string `json:"name"`
	Hosted      string `json:"hosted"`
	HostedToken string `json:"hosted_token"`
	OriginalUrl string `json:"original_url"`
	UploadUrl   string `json:"upload_url"`
	Created     string `json:"created_at"`
	Updated     string `json:"updated_at"`
	DownloadUrl string `json:"download_url"`
	Url         string `json:"url"`
}
<commit_msg>Fix missing flag.Parse() and change port to Int.<commit_after>package main

import (
	"archive/tar"
	"bytes"
	"compress/gzip"
	"encoding/json"
	"errors"
	"flag"
	"github.com/gorilla/mux"
	"io"
	"log"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"
)

func (bh BoxHandler) GetBox(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	user := vars["user"]
	boxName := vars["boxname"]
	log.Println("Queried for ", user, "/", boxName)
	box := bh.Boxes[user][boxName]

	jsonResponse, _ := json.Marshal(box)

	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.Write(jsonResponse)
}

func (bh BoxHandler) DownloadBox(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	user := vars["user"]
	boxName := vars["boxname"]
	log.Println("Downloading ", user, "/", boxName)

	localBoxfile := bh.Boxes[user][boxName]
	http.ServeFile(w, r, localBoxfile.LocalBoxFile)
}

func (bh BoxHandler) CheckBox(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	user := vars["user"]
	boxName := vars["boxname"]
	log.Println("Checking ", user, "/", boxName)

	localBoxfile := bh.Boxes[user][boxName]
	if localBoxfile.Username != "" {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
	} else {
		w.WriteHeader(http.StatusNotFound)
	}
}
func (bh BoxHandler) NotFound(w http.ResponseWriter, r *http.Request) {
	log.Println("404 :", r.URL.Path, " ", r.Method)
	w.WriteHeader(http.StatusNotFound)
}

func main() {

	directory := flag.String("d", "./", "Base directory containing .box files")
	port := flag.Int("port", 8099, "Port to listen on.")
	hostname := flag.String("hostname", "localhost", "Hostname for static box content.")

	flag.Parse()

	absolute := *directory
	if !path.IsAbs(*directory) {
		wd, _ := os.Getwd()
		absolute = path.Clean(path.Join(wd, *directory))
	}

	log.Println("Responding on host: ", *hostname)
	log.Println("Serving files from: ", *directory)
	boxfiles := getBoxList(absolute)
	boxdata := getBoxData(boxfiles)
	boxes := createBoxes(boxdata, *port, hostname)

	for namespace, boxinfo := range boxes {
		for boxname, _ := range boxinfo {
			log.Println(strings.Join([]string{"Found: ", namespace, "/", boxname}, ""))
		}
	}

	bh := BoxHandler{}
	bh.Boxes = boxes

	m := mux.NewRouter()
	m.HandleFunc("/{user}/{boxname}", bh.GetBox).Methods("GET")
	m.HandleFunc("/{user}/{boxname}", bh.CheckBox).Methods("HEAD")
	//Handling downloads that look like Vagrant Cloud
	//https://vagrantcloud.com/benphegan/boot2docker/version/2/provider/vmware_desktop.box
	m.HandleFunc("/{user}/{boxname}/{version}/provider/{boxfile}", bh.DownloadBox).Methods("GET")
	m.NotFoundHandler = http.HandlerFunc(bh.NotFound)
	http.Handle("/", m)

	log.Println("Listening on port: ", *port)
	http.ListenAndServe(":"+strconv.Itoa(*port), nil)
}

type BoxHandler struct {
	Boxes map[string]map[string]Box
}

func createBoxes(sb []SimpleBox, port int, hostname *string) map[string]map[string]Box {
	boxes := make(map[string]map[string]Box)
	for _, b := range sb {
		box := Box{}
		box.Name = b.Username + "/" + b.Boxname
		box.Username = b.Username
		box.Private = false
		box.LocalBoxFile = b.Location

		provider := Provider{}
		provider.Name = b.Provider
		provider.Hosted = "true"
		provider.DownloadUrl = "http://" + *hostname + ":" + strconv.Itoa(port) + "/" + b.Username + "/" + b.Boxname + "/1/provider/" + b.Provider + ".box"
		provider.Url = provider.DownloadUrl
		version := Version{}
		version.Status = "active"
		version.Version = "1.0"

		version.Providers = []Provider{provider}

		box.Versions = []Version{version}
		box.CurrentVersion = version
		boxes[b.Username] = make(map[string]Box)
		boxes[b.Username][b.Boxname] = box
	}
	return boxes
}

func getBoxList(directory string) []string {
	directoryglob := path.Join(directory, "*.box")
	files, _ := filepath.Glob(directoryglob)
	return files
}

func getBoxData(boxfiles []string) []SimpleBox {
	results := []SimpleBox{}
	for _, b := range boxfiles {
		nameparts := strings.Split(filepath.Base(b), "-VAGRANTSLASH-")
		if len(nameparts) == 2 {
			provider, _ := getProvider(b)
			newbox := SimpleBox{}
			newbox.Username = nameparts[0]
			newbox.Boxname = nameparts[1][0 : len(nameparts[1])-4]
			newbox.Location = b
			newbox.Provider = provider.Provider
			results = append(results, newbox)
		}
	}
	return results
}

func getProvider(location string) (BoxMetadata, error) {

	log.Println("Checking: ", location)
	//boxes are .tar.gz so we have to get a gzip stream and pass to tar.
	f, _ := os.Open(location)
	r, _ := gzip.NewReader(f)
	tr := tar.NewReader(r)
	// Iterate through the files in the archive.
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			// end of tar archive
			break
		}
		if err != nil {
			log.Fatalln(err)
		}

		if hdr.Name == "metadata.json" {
			metadata := BoxMetadata{}

			boxmetadata := BoxMetadata{}

			buf := new(bytes.Buffer)
			buf.ReadFrom(tr)

			json.Unmarshal(buf.Bytes(), &boxmetadata)
			metadata.Provider = boxmetadata.Provider
			return metadata, nil
		}

	}
	return BoxMetadata{}, errors.New("box: could not find metadata.json or box malformed")
}

type BoxMetadata struct {
	Provider string `json:"provider"`
}

type SimpleBox struct {
	Username string
	Boxname  string
	Location string
	Provider string
}

type Box struct {
	Created             string    `json:"created_at"`
	Updated             string    `json:"updated_at"`
	Tag                 string    `json:"tag"`
	Name                string    `json:"name"`
	ShortDescription    string    `json:"short_description"`
	DescriptionHtml     string    `json:"description_html"`
	DescriptionMarkdown string    `json:"description_markdown"`
	Username            string    `json:"username"`
	Private             bool      `json:"private"`
	CurrentVersion      Version   `json:"current_version"`
	Versions            []Version `json:"versions"`
	LocalBoxFile        string    `json:"-"`
}

type Version struct {
	Version             string     `json:"version"`
	Status              string     `json:"status"`
	DescriptionHtml     string     `json:"description_html"`
	DescriptionMarkdown string     `json:"description_markdown"`
	Created             string     `json:"created_at"`
	Updated             string     `json:"updated_at"`
	Number              int        `json:"number"`
	Downloads           int        `json:"downloads"`
	ReleaseUrl          string     `json:"release_url"`
	RevokeUrl           string     `json:"revoke_url"`
	Providers           []Provider `json:"providers"`
}

type Provider struct {
	Name        string `json:"name"`
	Hosted      string `json:"hosted"`
	HostedToken string `json:"hosted_token"`
	OriginalUrl string `json:"original_url"`
	UploadUrl   string `json:"upload_url"`
	Created     string `json:"created_at"`
	Updated     string `json:"updated_at"`
	DownloadUrl string `json:"download_url"`
	Url         string `json:"url"`
}
<|endoftext|>


<commit_before>// 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"
	"log"
	"net/http"
	"os"
	"strings"

	"github.com/line/line-bot-sdk-go/linebot"
)

var bot *linebot.Client

//PetDB :
var PetDB *Pets

func main() {
	var err error
	PetDB = NewPets()
	bot, err = linebot.New(os.Getenv("ChannelSecret"), os.Getenv("ChannelAccessToken"))
	log.Println("Bot:", bot, " err:", err)
	http.HandleFunc("/callback", callbackHandler)
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)
}

func callbackHandler(w http.ResponseWriter, r *http.Request) {
	events, err := bot.ParseRequest(r)
	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}
	for _, event := range events {
		if event.Type == linebot.EventTypeMessage {
			switch message := event.Message.(type) {
			case *linebot.TextMessage:
				var pet *Pet
				log.Println(message.Text)
				inText := strings.ToLower(message.Text)
				if strings.Contains(inText, "狗") || strings.Contains(inText, "dog") {
					pet = PetDB.GetNextDog()
				} else if strings.Contains(inText, "貓") || strings.Contains(inText, "cat") {
					pet = PetDB.GetNextCat()
				}

				if pet == nil {
					pet = PetDB.GetNextPet()
				}

				out := fmt.Sprintf("您好，目前的動物：名為%s, 所在地為:%s, 敘述: %s 電話為:%s", pet.Name, pet.Resettlement, pet.Note, pet.Phone)
				if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(out), linebot.NewImageMessage(pet.ImageName, pet.ImageName)).Do(); err != nil {
					log.Print(err)
				}

				log.Println("Img:", pet.ImageName)

				if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewImageMessage(pet.ImageName, pet.ImageName)).Do(); err != nil {
					log.Print(err)
				}
			}
		}
	}
}
<commit_msg>rollback image integrate message, because Line only support https image url.<commit_after>// 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"
	"log"
	"net/http"
	"os"
	"strings"

	"github.com/line/line-bot-sdk-go/linebot"
)

var bot *linebot.Client

//PetDB :
var PetDB *Pets

func main() {
	var err error
	PetDB = NewPets()
	bot, err = linebot.New(os.Getenv("ChannelSecret"), os.Getenv("ChannelAccessToken"))
	log.Println("Bot:", bot, " err:", err)
	http.HandleFunc("/callback", callbackHandler)
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)
}

func callbackHandler(w http.ResponseWriter, r *http.Request) {
	events, err := bot.ParseRequest(r)
	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}
	for _, event := range events {
		if event.Type == linebot.EventTypeMessage {
			switch message := event.Message.(type) {
			case *linebot.TextMessage:
				var pet *Pet
				log.Println(message.Text)
				inText := strings.ToLower(message.Text)
				if strings.Contains(inText, "狗") || strings.Contains(inText, "dog") {
					pet = PetDB.GetNextDog()
				} else if strings.Contains(inText, "貓") || strings.Contains(inText, "cat") {
					pet = PetDB.GetNextCat()
				}

				if pet == nil {
					pet = PetDB.GetNextPet()
				}

				out := fmt.Sprintf("您好，目前的動物：名為%s, 所在地為:%s, 敘述: %s 電話為:%s 圖片網址在: %s", pet.Name, pet.Resettlement, pet.Note, pet.Phone, pet.ImageName)
				if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(out)).Do(); err != nil {
					log.Print(err)
				}

				log.Println("Img:", pet.ImageName)

				if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewImageMessage(pet.ImageName, pet.ImageName)).Do(); err != nil {
					log.Print(err)
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>package shufn

// Calc determines the minimum mod and an appropriate mult for passing to New.
func Calc(rangeMin, rangeMax, start uint64) (mult, mod, min, max, start uint64) {
	if rangeMax < rangeMin {
		rangeMin, rangeMax = rangeMax, rangeMin
	}

	primes := primesPast(rangeMax - rangeMin + 1)
	if len(primes) == 0 {
		return 1, 2, rangeMin, rangeMax, start
	}

	mod = primes[len(primes)-1]
	roots := primePrimitiveRoots(mod, primes)
	mult = roots[len(roots)*2/3]

	return mult, mod, rangeMin, rangeMax, start
}

// primesPast returns all prime numbers up to the next prime above min.
func primesPast(min uint64) (primes []uint64) {
	if min < 2 {
		return nil
	}
Sieve:
	for p := uint64(2); ; p += 1 + (p & 1) {
		for _, prime := range primes {
			if p%prime == 0 {
				continue Sieve
			}
		}
		primes = append(primes, p)
		if p > min {
			return
		}
	}
}

// primePrimitiveRoots returns the primitive roots of the prime t.
// Based on https://math.stackexchange.com/a/133720.
func primePrimitiveRoots(t uint64, primes []uint64) []uint64 {
	// s is Euler's Totient phi(prime), where phi(t) := t - 1 if t is prime.
	s := t - 1
	factors := primeFactors(s, primes)

	// For any primitive root a, and any exponent p in the set of powers, a^p mod t != 1.
	powers := make([]uint64, len(factors))
	for i, factor := range factors {
		powers[i] = s / factor
	}

	// Find the lowest a >= 2 which satisfies a^p mod t != 1 for all p in powers.
	a, found := uint64(2), false
FirstRoot:
	for ; a < t; a++ {
		for _, power := range powers {
			if modExp(a, power, t) == 1 {
				continue FirstRoot
			}
		}

		found = true
		break
	}
	if !found {
		return nil
	}

	// Find the other primitive roots.
	roots := []uint64{a}
	for p := uint64(2); p < t; p++ {
		if gcd(s, p) == 1 {
			roots = append(roots, modExp(a, p, t))
		}
	}

	return roots
}

// primeFactors determines which primes are factors of n.
func primeFactors(n uint64, primes []uint64) []uint64 {
	factors := make([]uint64, 0)
	for _, f := range primes {
		if n == 1 {
			break
		}
		if n%f == 0 {
			factors = append(factors, f)
			n /= f
		}
		for n%f == 0 {
			n /= f
		}
	}
	return factors
}

// gcd calculates the greatest common divisor of a and b.
func gcd(a, b uint64) uint64 {
	if b > a {
		a, b = b, a
	}
	for {
		c := a % b
		if c == 0 {
			return b
		}
		a, b = b, c
	}
}

// modExp calculates modular exponentiation with exponentiation by squaring, O(log exponent).
// https://github.com/mgenware/go-modular-exponentiation/blob/73cf1e8d902ec78e27667be3e1b4d365de3c0aec/modexp.go#L31-L46
func modExp(base, exponent, modulus uint64) uint64 {
	if modulus == 1 {
		return 0
	}
	if exponent == 0 {
		return 1
	}

	result := modExp(base, exponent/2, modulus)
	result = (result * result) % modulus
	if exponent&1 != 0 {
		return ((base % modulus) * result) % modulus
	}
	return result % modulus
}
<commit_msg>Fix Calc duplicate arguments<commit_after>package shufn

// Calc determines the minimum mod and an appropriate mult for passing to New.
func Calc(rangeMin, rangeMax, start uint64) (mult, mod, min, max, strt uint64) {
	if rangeMax < rangeMin {
		rangeMin, rangeMax = rangeMax, rangeMin
	}

	primes := primesPast(rangeMax - rangeMin + 1)
	if len(primes) == 0 {
		return 1, 2, rangeMin, rangeMax, start
	}

	mod = primes[len(primes)-1]
	roots := primePrimitiveRoots(mod, primes)
	mult = roots[len(roots)*2/3]

	return mult, mod, rangeMin, rangeMax, start
}

// primesPast returns all prime numbers up to the next prime above min.
func primesPast(min uint64) (primes []uint64) {
	if min < 2 {
		return nil
	}
Sieve:
	for p := uint64(2); ; p += 1 + (p & 1) {
		for _, prime := range primes {
			if p%prime == 0 {
				continue Sieve
			}
		}
		primes = append(primes, p)
		if p > min {
			return
		}
	}
}

// primePrimitiveRoots returns the primitive roots of the prime t.
// Based on https://math.stackexchange.com/a/133720.
func primePrimitiveRoots(t uint64, primes []uint64) []uint64 {
	// s is Euler's Totient phi(prime), where phi(t) := t - 1 if t is prime.
	s := t - 1
	factors := primeFactors(s, primes)

	// For any primitive root a, and any exponent p in the set of powers, a^p mod t != 1.
	powers := make([]uint64, len(factors))
	for i, factor := range factors {
		powers[i] = s / factor
	}

	// Find the lowest a >= 2 which satisfies a^p mod t != 1 for all p in powers.
	a, found := uint64(2), false
FirstRoot:
	for ; a < t; a++ {
		for _, power := range powers {
			if modExp(a, power, t) == 1 {
				continue FirstRoot
			}
		}

		found = true
		break
	}
	if !found {
		return nil
	}

	// Find the other primitive roots.
	roots := []uint64{a}
	for p := uint64(2); p < t; p++ {
		if gcd(s, p) == 1 {
			roots = append(roots, modExp(a, p, t))
		}
	}

	return roots
}

// primeFactors determines which primes are factors of n.
func primeFactors(n uint64, primes []uint64) []uint64 {
	factors := make([]uint64, 0)
	for _, f := range primes {
		if n == 1 {
			break
		}
		if n%f == 0 {
			factors = append(factors, f)
			n /= f
		}
		for n%f == 0 {
			n /= f
		}
	}
	return factors
}

// gcd calculates the greatest common divisor of a and b.
func gcd(a, b uint64) uint64 {
	if b > a {
		a, b = b, a
	}
	for {
		c := a % b
		if c == 0 {
			return b
		}
		a, b = b, c
	}
}

// modExp calculates modular exponentiation with exponentiation by squaring, O(log exponent).
// https://github.com/mgenware/go-modular-exponentiation/blob/73cf1e8d902ec78e27667be3e1b4d365de3c0aec/modexp.go#L31-L46
func modExp(base, exponent, modulus uint64) uint64 {
	if modulus == 1 {
		return 0
	}
	if exponent == 0 {
		return 1
	}

	result := modExp(base, exponent/2, modulus)
	result = (result * result) % modulus
	if exponent&1 != 0 {
		return ((base % modulus) * result) % modulus
	}
	return result % modulus
}
<|endoftext|>