<commit_before>package main

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"os"

	"github.com/MartinSahlen/go-cloud-fn/express-wrapper"
	"github.com/MartinSahlen/go-cloud-fn/router"
	"github.com/gopherjs/gopherjs/js"
)

var googleCloudFunctionName = os.Getenv("GOOGLE_CLOUD_FUNCTION_NAME")

func rootHandler(res express.Response, req express.Request) {
	res.Headers.Write("content-type", "application/json")
	res.Status = 404
	res.Write(req.JSON())
}

func helloHandler(res express.Response, req express.Request) {
	res.Headers.Write("content-type", "application/json")
	res.Status = 200
	res.Write(req.JSON())
}

type Website struct {
	URL string `json:"url"`
}

func websiteHandler(res express.Response, req express.Request) {

	var site Website
	err := json.Unmarshal(req.Body, &site)

	res.Headers.Write("content-type", "text/html")

	log.Println(string(req.Body))

	if err != nil {
		log.Println("json error" + err.Error())
		res.Write([]byte(err.Error()))
		return
	}

	log.Println(site)

	go func() {
		r, err := http.DefaultClient.Get(site.URL)

		if err != nil {
			log.Println(err.Error())
			res.Write([]byte(err.Error()))
			return
		}

		byt, err := ioutil.ReadAll(r.Body)

		if err != nil {
			log.Println(err.Error())
			res.Write([]byte(err.Error()))
			return
		}

		res.Status = 200
		res.Write(byt)
	}()

}

//EntryPoint is the main handler and entrypoint for the google cloud function
func EntryPoint(req, res *js.Object) {

	r := router.New(rootHandler)
	r.Handle("GET", "/hello/:ergegr", helloHandler)
	r.Handle("POST", "/site", websiteHandler)

	r.Serve(express.NewResponse(res), express.NewRequest(req))
}

func main() {
	if googleCloudFunctionName == "" {
		googleCloudFunctionName = "helloGO"
	}
	js.Module.Get("exports").Set(googleCloudFunctionName, EntryPoint)
}
<commit_msg>Use validation<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"

	"github.com/MartinSahlen/go-cloud-fn/express-wrapper"
	"github.com/MartinSahlen/go-cloud-fn/router"
	"github.com/gopherjs/gopherjs/js"
	"gopkg.in/go-playground/validator.v9"
)

var googleCloudFunctionName = os.Getenv("GOOGLE_CLOUD_FUNCTION_NAME")

func rootHandler(res express.Response, req express.Request) {
	res.Headers.Write("content-type", "application/json")
	res.Status = 404
	res.Write(req.JSON())
}

func helloHandler(res express.Response, req express.Request) {
	res.Headers.Write("content-type", "application/json")
	res.Status = 200
	res.Write(req.JSON())
}

type Website struct {
	URL string `json:"url"validate:"required"`
}

func websiteHandler(res express.Response, req express.Request) {
	validate := validator.New()
	var site Website
	err := json.Unmarshal(req.Body, &site)

	res.Headers.Write("content-type", "text/html")

	log.Println(string(req.Body))

	if err != nil {
		log.Println("json error" + err.Error())
		res.Write([]byte(err.Error()))
		return
	}

	err = validate.Struct(site)
	if err != nil {
		errs := err.(validator.ValidationErrors)

		for _, err := range errs {

			fmt.Println(err.Namespace())
			fmt.Println(err.Field())
			fmt.Println(err.StructNamespace()) // can differ when a custom TagNameFunc is registered or
			fmt.Println(err.StructField())     // by passing alt name to ReportError like below
			fmt.Println(err.Tag())
			fmt.Println(err.ActualTag())
			fmt.Println(err.Kind())
			fmt.Println(err.Type())
			fmt.Println(err.Value())
			fmt.Println(err.Param())
			fmt.Println()
		}

		bytes, err := json.Marshal(errs)
		if err != nil {
			res.Write([]byte(err.Error()))
			return
		}
		res.Status = 400
		res.Write(bytes)
		return
	}

	go func() {
		r, err := http.DefaultClient.Get(site.URL)

		if err != nil {
			log.Println(err.Error())
			res.Write([]byte(err.Error()))
			return
		}

		byt, err := ioutil.ReadAll(r.Body)

		if err != nil {
			log.Println(err.Error())
			res.Write([]byte(err.Error()))
			return
		}

		res.Status = 200
		res.Write(byt)
	}()

}

//EntryPoint is the main handler and entrypoint for the google cloud function
func EntryPoint(req, res *js.Object) {

	r := router.New(rootHandler)
	r.Handle("GET", "/hello/:ergegr", helloHandler)
	r.Handle("POST", "/site", websiteHandler)

	r.Serve(express.NewResponse(res), express.NewRequest(req))
}

func main() {
	if googleCloudFunctionName == "" {
		googleCloudFunctionName = "helloGO"
	}
	js.Module.Get("exports").Set(googleCloudFunctionName, EntryPoint)
}
<|endoftext|>


<commit_before>// Package c2go contains the main function for running the executable.
package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"reflect"
	"regexp"
	"strings"

	"github.com/elliotchance/c2go/ast"
	"github.com/elliotchance/c2go/program"
	"github.com/elliotchance/c2go/transpiler"
)

// Version can be requested through the command line with:
//
//     c2go -v
//
// See https://github.com/elliotchance/c2go/wiki/Release-Process
const Version = "0.12.3"

type ProgramArgs struct {
	verbose     bool
	ast         bool
	inputFile   string
	outputFile  string
	packageName string
}

func readAST(data []byte) []string {
	uncolored := regexp.MustCompile(`\x1b\[[\d;]+m`).ReplaceAll(data, []byte{})
	return strings.Split(string(uncolored), "\n")
}

type treeNode struct {
	indent int
	node   ast.Node
}

func convertLinesToNodes(lines []string) []treeNode {
	nodes := []treeNode{}
	for _, line := range lines {
		if strings.TrimSpace(line) == "" {
			continue
		}

		// It is tempting to discard null AST nodes, but these may
		// have semantic importance: for example, they represent omitted
		// for-loop conditions, as in for(;;).
		line = strings.Replace(line, "<<<NULL>>>", "NullStmt", 1)

		indentAndType := regexp.MustCompile("^([|\\- `]*)(\\w+)").FindStringSubmatch(line)
		if len(indentAndType) == 0 {
			panic(fmt.Sprintf("Cannot understand line '%s'", line))
		}

		offset := len(indentAndType[1])
		node := ast.Parse(line[offset:])

		indentLevel := len(indentAndType[1]) / 2
		nodes = append(nodes, treeNode{indentLevel, node})
	}

	return nodes
}

// buildTree convert an array of nodes, each prefixed with a depth into a tree.
func buildTree(nodes []treeNode, depth int) []ast.Node {
	if len(nodes) == 0 {
		return []ast.Node{}
	}

	// Split the list into sections, treat each section as a a tree with its own root.
	sections := [][]treeNode{}
	for _, node := range nodes {
		if node.indent == depth {
			sections = append(sections, []treeNode{node})
		} else {
			sections[len(sections)-1] = append(sections[len(sections)-1], node)
		}
	}

	results := []ast.Node{}
	for _, section := range sections {
		slice := []treeNode{}
		for _, n := range section {
			if n.indent > depth {
				slice = append(slice, n)
			}
		}

		children := buildTree(slice, depth+1)
		for _, child := range children {
			section[0].node.AddChild(child)
		}
		results = append(results, section[0].node)
	}

	return results
}

func ToJSON(tree []interface{}) []map[string]interface{} {
	r := make([]map[string]interface{}, len(tree))

	for j, n := range tree {
		rn := reflect.ValueOf(n).Elem()
		r[j] = make(map[string]interface{})
		r[j]["node"] = rn.Type().Name()

		for i := 0; i < rn.NumField(); i++ {
			name := strings.ToLower(rn.Type().Field(i).Name)
			value := rn.Field(i).Interface()

			if name == "children" {
				v := value.([]interface{})

				if len(v) == 0 {
					continue
				}

				value = ToJSON(v)
			}

			r[j][name] = value
		}
	}

	return r
}

func Check(prefix string, e error) {
	if e != nil {
		panic(prefix + e.Error())
	}
}

func Start(args ProgramArgs) {
	if os.Getenv("GOPATH") == "" {
		panic("The $GOPATH must be set.")
	}

	// 1. Compile it first (checking for errors)
	_, err := os.Stat(args.inputFile)
	Check("", err)

	// 2. Preprocess
	pp, err := exec.Command("clang", "-E", args.inputFile).Output()
	Check("preprocess failed: ", err)

	pp_file_path := path.Join(os.TempDir(), "pp.c")
	err = ioutil.WriteFile(pp_file_path, pp, 0644)
	Check("writing to /tmp/pp.c failed: ", err)

	// 3. Generate JSON from AST
	ast_pp, err := exec.Command("clang", "-Xclang", "-ast-dump", "-fsyntax-only", pp_file_path).Output()
	if err != nil {
		// If clang fails it still prints out the AST, so we have to run it
		// again to get the real error.
		errBody, _ := exec.Command("clang", pp_file_path).CombinedOutput()

		panic("clang failed: " + err.Error() + ":\n\n" + string(errBody))
	}

	lines := readAST(ast_pp)
	if args.ast {
		for _, l := range lines {
			fmt.Println(l)
		}
		fmt.Println()
	}

	nodes := convertLinesToNodes(lines)
	tree := buildTree(nodes, 0)

	p := program.NewProgram()
	p.Verbose = args.verbose

	err = transpiler.TranspileAST(args.inputFile, args.packageName, p, tree[0].(ast.Node))
	if err != nil {
		panic(err)
	}

	outputFilePath := args.outputFile

	if outputFilePath == "" {
		cleanFileName := filepath.Clean(filepath.Base(args.inputFile))
		extension := filepath.Ext(args.inputFile)

		outputFilePath = cleanFileName[0:len(cleanFileName)-len(extension)] + ".go"
	}

	err = ioutil.WriteFile(outputFilePath, []byte(p.String()), 0755)
	Check("writing C output file failed: ", err)
}

func main() {
	var (
		versionFlag       = flag.Bool("v", false, "print the version and exit")
		transpileCommand  = flag.NewFlagSet("transpile", flag.ContinueOnError)
		verboseFlag       = transpileCommand.Bool("V", false, "print progress as comments")
		outputFlag        = transpileCommand.String("o", "", "output Go generated code to the specified file")
		packageFlag       = transpileCommand.String("p", "main", "set the name of the generated package")
		transpileHelpFlag = transpileCommand.Bool("h", false, "print help information")
		astCommand        = flag.NewFlagSet("ast", flag.ContinueOnError)
		astHelpFlag       = astCommand.Bool("h", false, "print help information")
	)

	flag.Usage = func() {
		usage := "Usage: %s [-v] [<command>] [<flags>] file.c\n\n"
		usage += "Commands:\n"
		usage += "  transpile\ttranspile an input C source file to Go\n"
		usage += "  ast\t\tprint AST before translated Go code\n\n"

		usage += "Flags:\n"
		fmt.Fprintf(os.Stderr, usage, os.Args[0])
		flag.PrintDefaults()
	}

	flag.Parse()

	if *versionFlag {
		// Simply print out the version and exit.
		fmt.Println(Version)
		return
	}

	if flag.NArg() < 1 {
		flag.Usage()
		os.Exit(1)
	}

	args := ProgramArgs{verbose: *verboseFlag, ast: false}

	switch os.Args[1] {
	case "ast":
		astCommand.Parse(os.Args[2:])

		if *astHelpFlag || astCommand.NArg() == 0 {
			fmt.Fprintf(os.Stderr, "Usage: %s ast file.c\n", os.Args[0])
			astCommand.PrintDefaults()
			os.Exit(1)
		}

		args.ast = true
		args.inputFile = astCommand.Arg(0)

		Start(args)
	case "transpile":
		transpileCommand.Parse(os.Args[2:])

		if *transpileHelpFlag || transpileCommand.NArg() == 0 {
			fmt.Fprintf(os.Stderr, "Usage: %s transpile [-V] [-o file.go] [-p package] file.c\n", os.Args[0])
			transpileCommand.PrintDefaults()
			os.Exit(1)
		}

		args.inputFile = transpileCommand.Arg(0)
		args.outputFile = *outputFlag
		args.packageName = *packageFlag

		Start(args)
	default:
		flag.Usage()
		os.Exit(1)
	}
}
<commit_msg>Bump version<commit_after>// Package c2go contains the main function for running the executable.
package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"reflect"
	"regexp"
	"strings"

	"github.com/elliotchance/c2go/ast"
	"github.com/elliotchance/c2go/program"
	"github.com/elliotchance/c2go/transpiler"
)

// Version can be requested through the command line with:
//
//     c2go -v
//
// See https://github.com/elliotchance/c2go/wiki/Release-Process
const Version = "0.12.4"

type ProgramArgs struct {
	verbose     bool
	ast         bool
	inputFile   string
	outputFile  string
	packageName string
}

func readAST(data []byte) []string {
	uncolored := regexp.MustCompile(`\x1b\[[\d;]+m`).ReplaceAll(data, []byte{})
	return strings.Split(string(uncolored), "\n")
}

type treeNode struct {
	indent int
	node   ast.Node
}

func convertLinesToNodes(lines []string) []treeNode {
	nodes := []treeNode{}
	for _, line := range lines {
		if strings.TrimSpace(line) == "" {
			continue
		}

		// It is tempting to discard null AST nodes, but these may
		// have semantic importance: for example, they represent omitted
		// for-loop conditions, as in for(;;).
		line = strings.Replace(line, "<<<NULL>>>", "NullStmt", 1)

		indentAndType := regexp.MustCompile("^([|\\- `]*)(\\w+)").FindStringSubmatch(line)
		if len(indentAndType) == 0 {
			panic(fmt.Sprintf("Cannot understand line '%s'", line))
		}

		offset := len(indentAndType[1])
		node := ast.Parse(line[offset:])

		indentLevel := len(indentAndType[1]) / 2
		nodes = append(nodes, treeNode{indentLevel, node})
	}

	return nodes
}

// buildTree convert an array of nodes, each prefixed with a depth into a tree.
func buildTree(nodes []treeNode, depth int) []ast.Node {
	if len(nodes) == 0 {
		return []ast.Node{}
	}

	// Split the list into sections, treat each section as a a tree with its own root.
	sections := [][]treeNode{}
	for _, node := range nodes {
		if node.indent == depth {
			sections = append(sections, []treeNode{node})
		} else {
			sections[len(sections)-1] = append(sections[len(sections)-1], node)
		}
	}

	results := []ast.Node{}
	for _, section := range sections {
		slice := []treeNode{}
		for _, n := range section {
			if n.indent > depth {
				slice = append(slice, n)
			}
		}

		children := buildTree(slice, depth+1)
		for _, child := range children {
			section[0].node.AddChild(child)
		}
		results = append(results, section[0].node)
	}

	return results
}

func ToJSON(tree []interface{}) []map[string]interface{} {
	r := make([]map[string]interface{}, len(tree))

	for j, n := range tree {
		rn := reflect.ValueOf(n).Elem()
		r[j] = make(map[string]interface{})
		r[j]["node"] = rn.Type().Name()

		for i := 0; i < rn.NumField(); i++ {
			name := strings.ToLower(rn.Type().Field(i).Name)
			value := rn.Field(i).Interface()

			if name == "children" {
				v := value.([]interface{})

				if len(v) == 0 {
					continue
				}

				value = ToJSON(v)
			}

			r[j][name] = value
		}
	}

	return r
}

func Check(prefix string, e error) {
	if e != nil {
		panic(prefix + e.Error())
	}
}

func Start(args ProgramArgs) {
	if os.Getenv("GOPATH") == "" {
		panic("The $GOPATH must be set.")
	}

	// 1. Compile it first (checking for errors)
	_, err := os.Stat(args.inputFile)
	Check("", err)

	// 2. Preprocess
	pp, err := exec.Command("clang", "-E", args.inputFile).Output()
	Check("preprocess failed: ", err)

	pp_file_path := path.Join(os.TempDir(), "pp.c")
	err = ioutil.WriteFile(pp_file_path, pp, 0644)
	Check("writing to /tmp/pp.c failed: ", err)

	// 3. Generate JSON from AST
	ast_pp, err := exec.Command("clang", "-Xclang", "-ast-dump", "-fsyntax-only", pp_file_path).Output()
	if err != nil {
		// If clang fails it still prints out the AST, so we have to run it
		// again to get the real error.
		errBody, _ := exec.Command("clang", pp_file_path).CombinedOutput()

		panic("clang failed: " + err.Error() + ":\n\n" + string(errBody))
	}

	lines := readAST(ast_pp)
	if args.ast {
		for _, l := range lines {
			fmt.Println(l)
		}
		fmt.Println()
	}

	nodes := convertLinesToNodes(lines)
	tree := buildTree(nodes, 0)

	p := program.NewProgram()
	p.Verbose = args.verbose

	err = transpiler.TranspileAST(args.inputFile, args.packageName, p, tree[0].(ast.Node))
	if err != nil {
		panic(err)
	}

	outputFilePath := args.outputFile

	if outputFilePath == "" {
		cleanFileName := filepath.Clean(filepath.Base(args.inputFile))
		extension := filepath.Ext(args.inputFile)

		outputFilePath = cleanFileName[0:len(cleanFileName)-len(extension)] + ".go"
	}

	err = ioutil.WriteFile(outputFilePath, []byte(p.String()), 0755)
	Check("writing C output file failed: ", err)
}

func main() {
	var (
		versionFlag       = flag.Bool("v", false, "print the version and exit")
		transpileCommand  = flag.NewFlagSet("transpile", flag.ContinueOnError)
		verboseFlag       = transpileCommand.Bool("V", false, "print progress as comments")
		outputFlag        = transpileCommand.String("o", "", "output Go generated code to the specified file")
		packageFlag       = transpileCommand.String("p", "main", "set the name of the generated package")
		transpileHelpFlag = transpileCommand.Bool("h", false, "print help information")
		astCommand        = flag.NewFlagSet("ast", flag.ContinueOnError)
		astHelpFlag       = astCommand.Bool("h", false, "print help information")
	)

	flag.Usage = func() {
		usage := "Usage: %s [-v] [<command>] [<flags>] file.c\n\n"
		usage += "Commands:\n"
		usage += "  transpile\ttranspile an input C source file to Go\n"
		usage += "  ast\t\tprint AST before translated Go code\n\n"

		usage += "Flags:\n"
		fmt.Fprintf(os.Stderr, usage, os.Args[0])
		flag.PrintDefaults()
	}

	flag.Parse()

	if *versionFlag {
		// Simply print out the version and exit.
		fmt.Println(Version)
		return
	}

	if flag.NArg() < 1 {
		flag.Usage()
		os.Exit(1)
	}

	args := ProgramArgs{verbose: *verboseFlag, ast: false}

	switch os.Args[1] {
	case "ast":
		astCommand.Parse(os.Args[2:])

		if *astHelpFlag || astCommand.NArg() == 0 {
			fmt.Fprintf(os.Stderr, "Usage: %s ast file.c\n", os.Args[0])
			astCommand.PrintDefaults()
			os.Exit(1)
		}

		args.ast = true
		args.inputFile = astCommand.Arg(0)

		Start(args)
	case "transpile":
		transpileCommand.Parse(os.Args[2:])

		if *transpileHelpFlag || transpileCommand.NArg() == 0 {
			fmt.Fprintf(os.Stderr, "Usage: %s transpile [-V] [-o file.go] [-p package] file.c\n", os.Args[0])
			transpileCommand.PrintDefaults()
			os.Exit(1)
		}

		args.inputFile = transpileCommand.Arg(0)
		args.outputFile = *outputFlag
		args.packageName = *packageFlag

		Start(args)
	default:
		flag.Usage()
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"os"
	"os/signal"
	"runtime/pprof"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/cenkalti/log"
	"github.com/cenkalti/rain/client"
	"github.com/cenkalti/rain/internal/clientversion"
	"github.com/cenkalti/rain/internal/logger"
	"github.com/cenkalti/rain/rpc/rpcclient"
	"github.com/cenkalti/rain/rpc/rpcserver"
	"github.com/cenkalti/rain/rpc/rpctypes"
	"github.com/cenkalti/rain/torrent"
	"github.com/cenkalti/rain/torrent/resume/torrentresume"
	"github.com/cenkalti/rain/torrent/storage/filestorage"
	// "github.com/mitchellh/go-homedir"
	"github.com/hokaccha/go-prettyjson"
	"github.com/urfave/cli"
)

var (
	app = cli.NewApp()
	clt *rpcclient.RPCClient
)

func main() {
	app.Version = clientversion.Version
	app.Usage = "BitTorrent client"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "config, c",
			Usage: "read config from `FILE`",
		},
		cli.StringFlag{
			Name:  "cpuprofile",
			Usage: "write cpu profile to `FILE`",
		},
		cli.BoolFlag{
			Name:  "debug, d",
			Usage: "enable debug log",
		},
		cli.StringFlag{
			Name:  "logfile",
			Usage: "write log to `FILE`",
		},
	}
	app.Before = handleBeforeCommand
	app.After = handleAfterCommand
	app.Commands = []cli.Command{
		{
			Name:      "download",
			Usage:     "download torrent or magnet",
			ArgsUsage: "[torrent path or magnet link]",
			Action:    handleDownload,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "dest",
					Usage: "save files under `DIR`",
					Value: ".",
				},
				cli.IntFlag{
					Name:  "port",
					Usage: "peer listen port",
				},
				cli.BoolFlag{
					Name:  "seed",
					Usage: "continue seeding after download finishes",
				},
			},
		},
		{
			Name:  "client",
			Usage: "send request to RPC server",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "url",
					Usage: "URL of RPC server",
					Value: "localhost:7246",
				},
			},
			Before: handleBeforeClient,
			Subcommands: []cli.Command{
				{
					Name:   "list",
					Usage:  "list torrents",
					Action: handleList,
				},
				{
					Name:   "add",
					Usage:  "add torrent or magnet",
					Action: handleAdd,
				},
				{
					Name:   "remove",
					Usage:  "remove torrent",
					Action: handleRemove,
				},
				{
					Name:   "stats",
					Usage:  "get stats of torrent",
					Action: handleStats,
				},
				{
					Name:   "start",
					Usage:  "start torrent",
					Action: handleStart,
				},
				{
					Name:   "stop",
					Usage:  "stop",
					Action: handleStop,
				},
			},
		},
		{
			Name:  "server",
			Usage: "run RPC server",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "addr",
					Usage: "listen addr",
					Value: "0.0.0.0:7246",
				},
			},
			Action: handleServer,
		},
	}
	err := app.Run(os.Args)
	if err != nil {
		log.Fatal(err)
	}
}

func handleBeforeCommand(c *cli.Context) error {
	cpuprofile := c.GlobalString("cpuprofile")
	if cpuprofile != "" {
		f, err := os.Create(cpuprofile)
		if err != nil {
			log.Fatal("could not create CPU profile: ", err)
		}
		if err := pprof.StartCPUProfile(f); err != nil {
			log.Fatal("could not start CPU profile: ", err)
		}
	}
	// configPath := c.GlobalString("config")
	// if configPath != "" {
	// 	cp, err := homedir.Expand(configPath)
	// 	if err != nil {
	// 		log.Fatal(err)
	// 	}
	// 	err = cfg.LoadFile(cp)
	// 	if err != nil {
	// 		log.Fatal(err)
	// 	}
	// }
	logFile := c.GlobalString("logfile")
	if logFile != "" {
		f, err := os.Create(logFile)
		if err != nil {
			log.Fatal("could not create log file: ", err)
		}
		logger.SetHandler(log.NewFileHandler(f))
	}
	if c.GlobalBool("debug") {
		logger.SetLevel(log.DEBUG)
	}
	return nil
}

func handleAfterCommand(c *cli.Context) error {
	if c.GlobalString("cpuprofile") != "" {
		pprof.StopCPUProfile()
	}
	return nil
}

func handleDownload(c *cli.Context) error {
	path := c.Args().Get(0)
	if path == "" {
		return errors.New("first argument must be a torrent file or magnet link")
	}
	sto, err := filestorage.New(c.String("dest"))
	if err != nil {
		log.Fatal(err)
	}
	var t *torrent.Torrent
	if strings.HasPrefix(path, "magnet:") {
		t, err = torrent.NewMagnet(path, c.Int("port"), sto)
	} else {
		f, err2 := os.Open(path) // nolint: gosec
		if err2 != nil {
			log.Fatal(err2)
		}
		t, err = torrent.New(f, c.Int("port"), sto)
		_ = f.Close()
	}
	if err != nil {
		log.Fatal(err)
	}
	defer t.Close()

	res, err := torrentresume.New(t.Name()+"."+t.InfoHash()+".resume", []byte(t.InfoHash()))
	if err != nil {
		log.Fatal(err)
	}
	err = t.SetResume(res)
	if err != nil {
		log.Fatal(err)
	}

	go printStats(t)
	t.Start()

	sigC := make(chan os.Signal, 1)
	signal.Notify(sigC, syscall.SIGINT, syscall.SIGTERM)

	completeC := t.NotifyComplete()
	errC := t.NotifyError()
	for {
		select {
		case <-completeC:
			completeC = nil
			if !c.Bool("seed") {
				t.Stop()
				continue
			}
		case <-sigC:
			t.Stop()
		case err = <-errC:
			return err
		}
	}
}

func printStats(t *torrent.Torrent) {
	for range time.Tick(1000 * time.Millisecond) {
		b, err2 := prettyjson.Marshal(t.Stats())
		if err2 != nil {
			log.Fatal(err2)
		}
		fmt.Println(string(b))
	}
}

func handleServer(c *cli.Context) error {
	clt, _ := client.New(nil)
	addr := c.String("addr")
	srv := rpcserver.New(clt, addr)
	log.Infoln("RPC server is listening on", addr)
	return srv.ListenAndServe()
}

func handleBeforeClient(c *cli.Context) error {
	var err error
	clt, err = rpcclient.New(c.String("url"))
	return err
}

func handleList(c *cli.Context) error {
	resp, err := clt.ListTorrents()
	if err != nil {
		return err
	}
	b, err := prettyjson.Marshal(resp)
	if err != nil {
		return err
	}
	os.Stdout.Write(b)
	os.Stdout.WriteString("\n")
	return nil
}

func handleAdd(c *cli.Context) error {
	var resp *rpctypes.AddTorrentResponse
	var err error
	arg := c.Args().Get(0)
	if strings.HasPrefix(arg, "magnet:") {
		resp, err = clt.AddMagnet(arg)
	} else {
		var f *os.File
		f, err = os.Open(arg) // nolint: gosec
		if err != nil {
			return err
		}
		resp, err = clt.AddTorrent(f)
		_ = f.Close()
	}
	if err != nil {
		return err
	}
	b, err := prettyjson.Marshal(resp)
	if err != nil {
		return err
	}
	os.Stdout.Write(b)
	os.Stdout.WriteString("\n")
	return nil
}

func handleRemove(c *cli.Context) error {
	id, err := strconv.ParseUint(c.Args().Get(0), 10, 64)
	if err != nil {
		return err
	}
	_, err = clt.RemoveTorrent(id)
	return err
}

func handleStats(c *cli.Context) error {
	id, err := strconv.ParseUint(c.Args().Get(0), 10, 64)
	if err != nil {
		return err
	}
	resp, err := clt.GetTorrentStats(id)
	if err != nil {
		return err
	}
	b, err := prettyjson.Marshal(resp)
	if err != nil {
		return err
	}
	os.Stdout.Write(b)
	os.Stdout.WriteString("\n")
	return nil
}

func handleStart(c *cli.Context) error {
	id, err := strconv.ParseUint(c.Args().Get(0), 10, 64)
	if err != nil {
		return err
	}
	_, err = clt.StartTorrent(id)
	return err
}

func handleStop(c *cli.Context) error {
	id, err := strconv.ParseUint(c.Args().Get(0), 10, 64)
	if err != nil {
		return err
	}
	_, err = clt.StopTorrent(id)
	return err
}
<commit_msg>fix linter<commit_after>package main

import (
	"errors"
	"fmt"
	"os"
	"os/signal"
	"runtime/pprof"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/cenkalti/log"
	"github.com/cenkalti/rain/client"
	"github.com/cenkalti/rain/internal/clientversion"
	"github.com/cenkalti/rain/internal/logger"
	"github.com/cenkalti/rain/rpc/rpcclient"
	"github.com/cenkalti/rain/rpc/rpcserver"
	"github.com/cenkalti/rain/rpc/rpctypes"
	"github.com/cenkalti/rain/torrent"
	"github.com/cenkalti/rain/torrent/resume/torrentresume"
	"github.com/cenkalti/rain/torrent/storage/filestorage"
	// "github.com/mitchellh/go-homedir"
	"github.com/hokaccha/go-prettyjson"
	"github.com/urfave/cli"
)

var (
	app = cli.NewApp()
	clt *rpcclient.RPCClient
)

func main() {
	app.Version = clientversion.Version
	app.Usage = "BitTorrent client"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "config, c",
			Usage: "read config from `FILE`",
		},
		cli.StringFlag{
			Name:  "cpuprofile",
			Usage: "write cpu profile to `FILE`",
		},
		cli.BoolFlag{
			Name:  "debug, d",
			Usage: "enable debug log",
		},
		cli.StringFlag{
			Name:  "logfile",
			Usage: "write log to `FILE`",
		},
	}
	app.Before = handleBeforeCommand
	app.After = handleAfterCommand
	app.Commands = []cli.Command{
		{
			Name:      "download",
			Usage:     "download torrent or magnet",
			ArgsUsage: "[torrent path or magnet link]",
			Action:    handleDownload,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "dest",
					Usage: "save files under `DIR`",
					Value: ".",
				},
				cli.IntFlag{
					Name:  "port",
					Usage: "peer listen port",
				},
				cli.BoolFlag{
					Name:  "seed",
					Usage: "continue seeding after download finishes",
				},
			},
		},
		{
			Name:  "client",
			Usage: "send request to RPC server",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "url",
					Usage: "URL of RPC server",
					Value: "localhost:7246",
				},
			},
			Before: handleBeforeClient,
			Subcommands: []cli.Command{
				{
					Name:   "list",
					Usage:  "list torrents",
					Action: handleList,
				},
				{
					Name:   "add",
					Usage:  "add torrent or magnet",
					Action: handleAdd,
				},
				{
					Name:   "remove",
					Usage:  "remove torrent",
					Action: handleRemove,
				},
				{
					Name:   "stats",
					Usage:  "get stats of torrent",
					Action: handleStats,
				},
				{
					Name:   "start",
					Usage:  "start torrent",
					Action: handleStart,
				},
				{
					Name:   "stop",
					Usage:  "stop",
					Action: handleStop,
				},
			},
		},
		{
			Name:  "server",
			Usage: "run RPC server",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "addr",
					Usage: "listen addr",
					Value: "0.0.0.0:7246",
				},
			},
			Action: handleServer,
		},
	}
	err := app.Run(os.Args)
	if err != nil {
		log.Fatal(err)
	}
}

func handleBeforeCommand(c *cli.Context) error {
	cpuprofile := c.GlobalString("cpuprofile")
	if cpuprofile != "" {
		f, err := os.Create(cpuprofile)
		if err != nil {
			log.Fatal("could not create CPU profile: ", err)
		}
		if err := pprof.StartCPUProfile(f); err != nil {
			log.Fatal("could not start CPU profile: ", err)
		}
	}
	// configPath := c.GlobalString("config")
	// if configPath != "" {
	// 	cp, err := homedir.Expand(configPath)
	// 	if err != nil {
	// 		log.Fatal(err)
	// 	}
	// 	err = cfg.LoadFile(cp)
	// 	if err != nil {
	// 		log.Fatal(err)
	// 	}
	// }
	logFile := c.GlobalString("logfile")
	if logFile != "" {
		f, err := os.Create(logFile)
		if err != nil {
			log.Fatal("could not create log file: ", err)
		}
		logger.SetHandler(log.NewFileHandler(f))
	}
	if c.GlobalBool("debug") {
		logger.SetLevel(log.DEBUG)
	}
	return nil
}

func handleAfterCommand(c *cli.Context) error {
	if c.GlobalString("cpuprofile") != "" {
		pprof.StopCPUProfile()
	}
	return nil
}

func handleDownload(c *cli.Context) error {
	path := c.Args().Get(0)
	if path == "" {
		return errors.New("first argument must be a torrent file or magnet link")
	}
	sto, err := filestorage.New(c.String("dest"))
	if err != nil {
		log.Fatal(err)
	}
	var t *torrent.Torrent
	if strings.HasPrefix(path, "magnet:") {
		t, err = torrent.NewMagnet(path, c.Int("port"), sto)
	} else {
		f, err2 := os.Open(path) // nolint: gosec
		if err2 != nil {
			log.Fatal(err2)
		}
		t, err = torrent.New(f, c.Int("port"), sto)
		_ = f.Close()
	}
	if err != nil {
		log.Fatal(err)
	}
	defer t.Close()

	res, err := torrentresume.New(t.Name()+"."+t.InfoHash()+".resume", []byte(t.InfoHash()))
	if err != nil {
		log.Fatal(err)
	}
	err = t.SetResume(res)
	if err != nil {
		log.Fatal(err)
	}

	go printStats(t)
	t.Start()

	sigC := make(chan os.Signal, 1)
	signal.Notify(sigC, syscall.SIGINT, syscall.SIGTERM)

	completeC := t.NotifyComplete()
	errC := t.NotifyError()
	for {
		select {
		case <-completeC:
			completeC = nil
			if !c.Bool("seed") {
				t.Stop()
				continue
			}
		case <-sigC:
			t.Stop()
		case err = <-errC:
			return err
		}
	}
}

func printStats(t *torrent.Torrent) {
	for range time.Tick(1000 * time.Millisecond) {
		b, err2 := prettyjson.Marshal(t.Stats())
		if err2 != nil {
			log.Fatal(err2)
		}
		fmt.Println(string(b))
	}
}

func handleServer(c *cli.Context) error {
	clt, _ := client.New(nil)
	addr := c.String("addr")
	srv := rpcserver.New(clt, addr)
	log.Infoln("RPC server is listening on", addr)
	return srv.ListenAndServe()
}

func handleBeforeClient(c *cli.Context) error {
	var err error
	clt, err = rpcclient.New(c.String("url"))
	return err
}

func handleList(c *cli.Context) error {
	resp, err := clt.ListTorrents()
	if err != nil {
		return err
	}
	b, err := prettyjson.Marshal(resp)
	if err != nil {
		return err
	}
	_, _ = os.Stdout.Write(b)
	_, _ = os.Stdout.WriteString("\n")
	return nil
}

func handleAdd(c *cli.Context) error {
	var resp *rpctypes.AddTorrentResponse
	var err error
	arg := c.Args().Get(0)
	if strings.HasPrefix(arg, "magnet:") {
		resp, err = clt.AddMagnet(arg)
	} else {
		var f *os.File
		f, err = os.Open(arg) // nolint: gosec
		if err != nil {
			return err
		}
		resp, err = clt.AddTorrent(f)
		_ = f.Close()
	}
	if err != nil {
		return err
	}
	b, err := prettyjson.Marshal(resp)
	if err != nil {
		return err
	}
	_, _ = os.Stdout.Write(b)
	_, _ = os.Stdout.WriteString("\n")
	return nil
}

func handleRemove(c *cli.Context) error {
	id, err := strconv.ParseUint(c.Args().Get(0), 10, 64)
	if err != nil {
		return err
	}
	_, err = clt.RemoveTorrent(id)
	return err
}

func handleStats(c *cli.Context) error {
	id, err := strconv.ParseUint(c.Args().Get(0), 10, 64)
	if err != nil {
		return err
	}
	resp, err := clt.GetTorrentStats(id)
	if err != nil {
		return err
	}
	b, err := prettyjson.Marshal(resp)
	if err != nil {
		return err
	}
	_, _ = os.Stdout.Write(b)
	_, _ = os.Stdout.WriteString("\n")
	return nil
}

func handleStart(c *cli.Context) error {
	id, err := strconv.ParseUint(c.Args().Get(0), 10, 64)
	if err != nil {
		return err
	}
	_, err = clt.StartTorrent(id)
	return err
}

func handleStop(c *cli.Context) error {
	id, err := strconv.ParseUint(c.Args().Get(0), 10, 64)
	if err != nil {
		return err
	}
	_, err = clt.StopTorrent(id)
	return err
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path"
	"strings"

	plugin "code.google.com/p/goprotobuf/compiler/plugin"
	"code.google.com/p/goprotobuf/proto"

	"github.com/dsymonds/gotoc/parser"
	"github.com/dsymonds/gotoc/resolver"
)

var (
	// Flags
	helpShort = flag.Bool("h", false, "Show usage text (same as --help).")
	helpLong  = flag.Bool("help", false, "Show usage text (same as -h).")

	importPath     = flag.String("import_path", ".", "Comma-separated list of paths to search for imports.")
	pluginBinary   = flag.String("plugin", "protoc-gen-go", "The code generator plugin to use.")
	descriptorOnly = flag.Bool("descriptor_only", false, "Whether to print out only the FileDescriptorSet.")
)

func fullPath(binary string, paths []string) string {
	if strings.Index(binary, "/") >= 0 {
		// path with path component
		return binary
	}
	for _, p := range paths {
		full := path.Join(p, binary)
		fi, err := os.Stat(full)
		if err == nil && !fi.IsDir() {
			return full
		}
	}
	return ""
}

func main() {
	flag.Usage = usage
	flag.Parse()
	if *helpShort || *helpLong || flag.NArg() == 0 {
		flag.Usage()
		os.Exit(1)
	}

	fds, err := parser.ParseFiles(flag.Args(), strings.Split(*importPath, ","))
	if err != nil {
		log.Fatalf("Failed parsing: %v", err)
	}
	if err := resolver.ResolveSymbols(fds); err != nil {
		log.Fatalf("Failed resolving symbols: %v", err)
	}

	if *descriptorOnly {
		proto.MarshalText(os.Stdout, fds)
		os.Exit(0)
	}

	fmt.Println("-----")
	proto.MarshalText(os.Stdout, fds)
	fmt.Println("-----")

	// Prepare request.
	cgRequest := &plugin.CodeGeneratorRequest{
		FileToGenerate: flag.Args(),
		// TODO: proto_file should be topologically sorted (bottom-up)
		ProtoFile: fds.File,
	}
	buf, err := proto.Marshal(cgRequest)
	if err != nil {
		log.Fatalf("Failed marshaling CG request: %v", err)
	}

	// Find plugin.
	pluginPath := fullPath(*pluginBinary, strings.Split(os.Getenv("PATH"), ":"))
	if pluginPath == "" {
		log.Fatalf("Failed finding plugin binary %q", *pluginBinary)
	}

	// Run the plugin subprocess.
	cmd := &exec.Cmd{
		Path:   pluginPath,
		Stdin:  bytes.NewBuffer(buf),
		Stderr: os.Stderr,
	}
	buf, err = cmd.Output()
	if err != nil {
		log.Fatalf("Failed running plugin: %v", err)
	}

	// Parse the response.
	cgResponse := new(plugin.CodeGeneratorResponse)
	if err = proto.Unmarshal(buf, cgResponse); err != nil {
		log.Fatalf("Failed unmarshaling CG response: %v", err)
	}

	// TODO: check cgResponse.Error

	// TODO: write files
	for _, f := range cgResponse.File {
		fmt.Printf("--[ %v ]--\n", proto.GetString(f.Name))
		fmt.Println(proto.GetString(f.Content))
	}
	fmt.Println("-----")
}

func usage() {
	fmt.Fprintf(os.Stderr, "Usage:  %s [options] <foo.proto> ...\n", os.Args[0])
	flag.PrintDefaults()
}
<commit_msg>Write output files.<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"strings"

	plugin "code.google.com/p/goprotobuf/compiler/plugin"
	"code.google.com/p/goprotobuf/proto"

	"github.com/dsymonds/gotoc/parser"
	"github.com/dsymonds/gotoc/resolver"
)

var (
	// Flags
	helpShort = flag.Bool("h", false, "Show usage text (same as --help).")
	helpLong  = flag.Bool("help", false, "Show usage text (same as -h).")

	importPath     = flag.String("import_path", ".", "Comma-separated list of paths to search for imports.")
	pluginBinary   = flag.String("plugin", "protoc-gen-go", "The code generator plugin to use.")
	descriptorOnly = flag.Bool("descriptor_only", false, "Whether to print out only the FileDescriptorSet.")
)

func fullPath(binary string, paths []string) string {
	if strings.Index(binary, "/") >= 0 {
		// path with path component
		return binary
	}
	for _, p := range paths {
		full := path.Join(p, binary)
		fi, err := os.Stat(full)
		if err == nil && !fi.IsDir() {
			return full
		}
	}
	return ""
}

func main() {
	flag.Usage = usage
	flag.Parse()
	if *helpShort || *helpLong || flag.NArg() == 0 {
		flag.Usage()
		os.Exit(1)
	}

	fds, err := parser.ParseFiles(flag.Args(), strings.Split(*importPath, ","))
	if err != nil {
		log.Fatalf("Failed parsing: %v", err)
	}
	if err := resolver.ResolveSymbols(fds); err != nil {
		log.Fatalf("Failed resolving symbols: %v", err)
	}

	if *descriptorOnly {
		proto.MarshalText(os.Stdout, fds)
		os.Exit(0)
	}

	//fmt.Println("-----")
	//proto.MarshalText(os.Stdout, fds)
	//fmt.Println("-----")

	// Prepare request.
	cgRequest := &plugin.CodeGeneratorRequest{
		FileToGenerate: flag.Args(),
		// TODO: proto_file should be topologically sorted (bottom-up)
		ProtoFile: fds.File,
	}
	buf, err := proto.Marshal(cgRequest)
	if err != nil {
		log.Fatalf("Failed marshaling CG request: %v", err)
	}

	// Find plugin.
	pluginPath := fullPath(*pluginBinary, strings.Split(os.Getenv("PATH"), ":"))
	if pluginPath == "" {
		log.Fatalf("Failed finding plugin binary %q", *pluginBinary)
	}

	// Run the plugin subprocess.
	cmd := &exec.Cmd{
		Path:   pluginPath,
		Stdin:  bytes.NewBuffer(buf),
		Stderr: os.Stderr,
	}
	buf, err = cmd.Output()
	if err != nil {
		log.Fatalf("Failed running plugin: %v", err)
	}

	// Parse the response.
	cgResponse := new(plugin.CodeGeneratorResponse)
	if err = proto.Unmarshal(buf, cgResponse); err != nil {
		log.Fatalf("Failed unmarshaling CG response: %v", err)
	}

	// TODO: check cgResponse.Error

	for _, f := range cgResponse.File {
		// TODO: If f.Name is nil, the content should be appended to the previous file.
		if f.Name == nil || f.Content == nil {
			log.Fatal("Malformed CG response")
		}
		if err := ioutil.WriteFile(*f.Name, []byte(*f.Content), 0644); err != nil {
			log.Fatalf("Failed writing output file: %v", err)
		}
	}
}

func usage() {
	fmt.Fprintf(os.Stderr, "Usage:  %s [options] <foo.proto> ...\n", os.Args[0])
	flag.PrintDefaults()
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/go-chi/chi"
	"github.com/go-chi/chi/middleware"
	"github.com/unrolled/secure"
	"gopkg.in/reportportal/commons-go.v5/commons"
	"gopkg.in/reportportal/commons-go.v5/conf"
	"gopkg.in/reportportal/commons-go.v5/server"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

func main() {

	currDir, e := os.Getwd()
	if nil != e {
		log.Fatalf("Cannot get workdir: %s", e.Error())
	}

	cfg := conf.EmptyConfig()

	rpConf := struct {
		Cfg         *conf.ServerConfig
		StaticsPath string `env:"RP_STATICS_PATH"`
	}{
		Cfg:         cfg,
		StaticsPath: currDir,
	}

	err := conf.LoadConfig(&rpConf)
	if nil != err {
		log.Fatalf("Cannot log app config")
	}

	info := commons.GetBuildInfo()
	info.Name = "Service UI"

	srv := server.New(rpConf.Cfg, info)
	srv.WithRouter(func(router *chi.Mux) {

		//apply compression
		router.Use(middleware.DefaultCompress)
		router.Use(middleware.Logger)

		//content security policy
		csp := map[string][]string{
			"default-src": {"'self'", "'unsafe-inline'", "*.uservoice.com"},
			"script-src": {
				"'self'",
				"'unsafe-inline'",
				"'unsafe-eval'",
				"status.reportportal.io",
				"www.google-analytics.com",
				"stats.g.doubleclick.net",
				"*.epam.com",
				"*.uservoice.com",
			},
			"img-src":    {"'self'", "data:", "www.google-analytics.com", "stats.g.doubleclick.net", "*.epam.com", "*.uservoice.com"},
			"object-src": {"'self'"},
		}

		//apply content security policies
		router.Use(func(next http.Handler) http.Handler {
			return secure.New(secure.Options{
				ContentTypeNosniff:    true,
				BrowserXssFilter:      true,
				ContentSecurityPolicy: buildCSP(csp),
				STSSeconds:            315360000,
				STSIncludeSubdomains:  true,
				STSPreload:            true,
			}).Handler(next)
		})

		err := os.Chdir(rpConf.StaticsPath)
		if nil != err {
			log.Fatalf("Dir %s not found", rpConf.StaticsPath)
		}

		router.Handle("/*", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			//trim query params
			ext := filepath.Ext(trimQuery(r.URL.String(), "?"))

			// never cache html
			if "/" == r.URL.String() || ".html" == ext {
				w.Header().Add("Cache-Control", "no-cache")
			}

			http.FileServer(http.Dir(rpConf.StaticsPath)).ServeHTTP(&redirectingRW{ResponseWriter: w, Request: r}, r)
		}))

	})

	srv.StartServer()

}

func trimQuery(s string, sep string) string {
	sepIndex := strings.Index(s, sep)
	if -1 != sepIndex {
		return s[:sepIndex]
	}
	return s
}

func buildCSP(csp map[string][]string) string {
	var instr []string
	for k, v := range csp {
		instr = append(instr, k+" "+strings.Join(v, " "))
	}
	return strings.Join(instr, "; ")

}

type redirectingRW struct {
	*http.Request
	http.ResponseWriter
	ignore bool
}

func (hrw *redirectingRW) Header() http.Header {
	return hrw.ResponseWriter.Header()
}

func (hrw *redirectingRW) WriteHeader(status int) {
	if status == 404 {
		hrw.ignore = true
		http.Redirect(hrw.ResponseWriter, hrw.Request, "/ui/#notfound", http.StatusTemporaryRedirect)
	} else {
		hrw.ResponseWriter.WriteHeader(status)
	}

}

func (hrw *redirectingRW) Write(p []byte) (int, error) {
	if hrw.ignore {
		return len(p), nil
	}
	return hrw.ResponseWriter.Write(p)
}
<commit_msg>Csp fix<commit_after>package main

import (
	"github.com/go-chi/chi"
	"github.com/go-chi/chi/middleware"
	"github.com/unrolled/secure"
	"gopkg.in/reportportal/commons-go.v5/commons"
	"gopkg.in/reportportal/commons-go.v5/conf"
	"gopkg.in/reportportal/commons-go.v5/server"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

func main() {

	currDir, e := os.Getwd()
	if nil != e {
		log.Fatalf("Cannot get workdir: %s", e.Error())
	}

	cfg := conf.EmptyConfig()

	rpConf := struct {
		Cfg         *conf.ServerConfig
		StaticsPath string `env:"RP_STATICS_PATH"`
	}{
		Cfg:         cfg,
		StaticsPath: currDir,
	}

	err := conf.LoadConfig(&rpConf)
	if nil != err {
		log.Fatalf("Cannot log app config")
	}

	info := commons.GetBuildInfo()
	info.Name = "Service UI"

	srv := server.New(rpConf.Cfg, info)
	srv.WithRouter(func(router *chi.Mux) {

		//apply compression
		router.Use(middleware.DefaultCompress)
		router.Use(middleware.Logger)

		//content security policy
		csp := map[string][]string{
			"default-src": {"'self'", "'unsafe-inline'", "*.uservoice.com"},
			"script-src": {
				"'self'",
				"'unsafe-inline'",
				"'unsafe-eval'",
				"status.reportportal.io",
				"www.google-analytics.com",
				"stats.g.doubleclick.net",
				"*.epam.com",
				"*.uservoice.com",
			},
			"img-src":    {"'self'", "data:", "www.google-analytics.com", "stats.g.doubleclick.net", "*.epam.com", "*.uservoice.com", "*.saucelabs.com"},
			"video-src": {"'self'", "*.saucelabs.com"},
			"object-src": {"'self'", "*.saucelabs.com"},
		}

		//apply content security policies
		router.Use(func(next http.Handler) http.Handler {
			return secure.New(secure.Options{
				ContentTypeNosniff:    true,
				BrowserXssFilter:      true,
				ContentSecurityPolicy: buildCSP(csp),
				STSSeconds:            315360000,
				STSIncludeSubdomains:  true,
				STSPreload:            true,
			}).Handler(next)
		})

		err := os.Chdir(rpConf.StaticsPath)
		if nil != err {
			log.Fatalf("Dir %s not found", rpConf.StaticsPath)
		}

		router.Handle("/*", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			//trim query params
			ext := filepath.Ext(trimQuery(r.URL.String(), "?"))

			// never cache html
			if "/" == r.URL.String() || ".html" == ext {
				w.Header().Add("Cache-Control", "no-cache")
			}

			http.FileServer(http.Dir(rpConf.StaticsPath)).ServeHTTP(&redirectingRW{ResponseWriter: w, Request: r}, r)
		}))

	})

	srv.StartServer()

}

func trimQuery(s string, sep string) string {
	sepIndex := strings.Index(s, sep)
	if -1 != sepIndex {
		return s[:sepIndex]
	}
	return s
}

func buildCSP(csp map[string][]string) string {
	var instr []string
	for k, v := range csp {
		instr = append(instr, k+" "+strings.Join(v, " "))
	}
	return strings.Join(instr, "; ")

}

type redirectingRW struct {
	*http.Request
	http.ResponseWriter
	ignore bool
}

func (hrw *redirectingRW) Header() http.Header {
	return hrw.ResponseWriter.Header()
}

func (hrw *redirectingRW) WriteHeader(status int) {
	if status == 404 {
		hrw.ignore = true
		http.Redirect(hrw.ResponseWriter, hrw.Request, "/ui/#notfound", http.StatusTemporaryRedirect)
	} else {
		hrw.ResponseWriter.WriteHeader(status)
	}

}

func (hrw *redirectingRW) Write(p []byte) (int, error) {
	if hrw.ignore {
		return len(p), nil
	}
	return hrw.ResponseWriter.Write(p)
}
<|endoftext|>


<commit_before>package main

// vouch
// github.com/vouch/vouch-proxy

import (
	"net/http"
	"os"
	"strconv"
	"time"

	log "github.com/Sirupsen/logrus"

	"github.com/gorilla/mux"

	"github.com/vouch/vouch-proxy/handlers"
	"github.com/vouch/vouch-proxy/pkg/cfg"
	"github.com/vouch/vouch-proxy/pkg/timelog"
	tran "github.com/vouch/vouch-proxy/pkg/transciever"
)

// version and semver get overwritten by build with
// go build -i -v -ldflags="-X main.version=$(git describe --always --long) -X main.semver=v$(git semver get)"

var (
	version   = "undefined"
	builddt   = "undefined"
	host      = "undefined"
	semver    = "undefined"
	branch    = "undefined"
	staticDir = "/static/"
)

func init() {
	// var listen = cfg.Cfg.Listen + ":" + strconv.Itoa(cfg.Cfg.Port)
}

func main() {
	var listen = cfg.Cfg.Listen + ":" + strconv.Itoa(cfg.Cfg.Port)
	log.WithFields(log.Fields{
		// "semver":    semver,
		"version":   version,
		"buildtime": builddt,
		"buildhost": host,
		"branch":    branch,
		"semver":    semver,
		"listen":    listen}).Info("starting " + cfg.Branding.CcName)

	mux := mux.NewRouter()

	authH := http.HandlerFunc(handlers.ValidateRequestHandler)
	mux.HandleFunc("/validate", timelog.TimeLog(authH))
	mux.HandleFunc("/_external-auth-{id}", timelog.TimeLog(authH))

	loginH := http.HandlerFunc(handlers.LoginHandler)
	mux.HandleFunc("/login", timelog.TimeLog(loginH))

	logoutH := http.HandlerFunc(handlers.LogoutHandler)
	mux.HandleFunc("/logout", timelog.TimeLog(logoutH))

	callH := http.HandlerFunc(handlers.CallbackHandler)
	mux.HandleFunc("/auth", timelog.TimeLog(callH))

	healthH := http.HandlerFunc(handlers.HealthcheckHandler)
	mux.HandleFunc("/healthcheck", timelog.TimeLog(healthH))

	// serve static files from /static if present (probably in a docker container), otherwise from ./static
	_, err := os.Stat(staticDir)
	staticFiles := staticDir
	if err != nil {
		staticFiles = "." + staticDir
	}
	log.Debugf("serving static files from %s", staticFiles)
	// https://golangcode.com/serve-static-assets-using-the-mux-router/
	mux.PathPrefix(staticDir).Handler(http.StripPrefix(staticDir, (http.FileServer(http.Dir(staticFiles)))))

	if cfg.Cfg.WebApp {
		log.Info("enabling websocket")
		tran.ExplicitInit()
		mux.Handle("/ws", tran.WS)
	}

	// socketio := tran.NewServer()
	// mux.Handle("/socket.io/", cors.AllowAll(socketio))
	// http.Handle("/socket.io/", tran.Server)

	srv := &http.Server{
		Handler: mux,
		Addr:    listen,
		// Good practice: enforce timeouts for servers you create!
		WriteTimeout: 15 * time.Second,
		ReadTimeout:  15 * time.Second,
		/// logrus has an example of using ErrorLog but it doesn't apply to this MUX implimentation
		// https://github.com/sirupsen/logrus#logger-as-an-iowriter
		// ErrorLog:     log.New(w, "", 0),
	}

	log.Fatal(srv.ListenAndServe())

}
<commit_msg>#58 always serve ./static, report full path if debug<commit_after>package main

// vouch
// github.com/vouch/vouch-proxy

import (
	"net/http"
	"path/filepath"
	"strconv"
	"time"

	log "github.com/Sirupsen/logrus"

	"github.com/gorilla/mux"

	"github.com/vouch/vouch-proxy/handlers"
	"github.com/vouch/vouch-proxy/pkg/cfg"
	"github.com/vouch/vouch-proxy/pkg/timelog"
	tran "github.com/vouch/vouch-proxy/pkg/transciever"
)

// version and semver get overwritten by build with
// go build -i -v -ldflags="-X main.version=$(git describe --always --long) -X main.semver=v$(git semver get)"

var (
	version   = "undefined"
	builddt   = "undefined"
	host      = "undefined"
	semver    = "undefined"
	branch    = "undefined"
	staticDir = "/static/"
)

func init() {
	// var listen = cfg.Cfg.Listen + ":" + strconv.Itoa(cfg.Cfg.Port)
}

func main() {
	var listen = cfg.Cfg.Listen + ":" + strconv.Itoa(cfg.Cfg.Port)
	log.WithFields(log.Fields{
		// "semver":    semver,
		"version":   version,
		"buildtime": builddt,
		"buildhost": host,
		"branch":    branch,
		"semver":    semver,
		"listen":    listen}).Info("starting " + cfg.Branding.CcName)

	mux := mux.NewRouter()

	authH := http.HandlerFunc(handlers.ValidateRequestHandler)
	mux.HandleFunc("/validate", timelog.TimeLog(authH))
	mux.HandleFunc("/_external-auth-{id}", timelog.TimeLog(authH))

	loginH := http.HandlerFunc(handlers.LoginHandler)
	mux.HandleFunc("/login", timelog.TimeLog(loginH))

	logoutH := http.HandlerFunc(handlers.LogoutHandler)
	mux.HandleFunc("/logout", timelog.TimeLog(logoutH))

	callH := http.HandlerFunc(handlers.CallbackHandler)
	mux.HandleFunc("/auth", timelog.TimeLog(callH))

	healthH := http.HandlerFunc(handlers.HealthcheckHandler)
	mux.HandleFunc("/healthcheck", timelog.TimeLog(healthH))

	if log.GetLevel() == log.DebugLevel {
		path, err := filepath.Abs(staticDir)
		if err != nil {
			log.Errorf("couldn't find static assets at %s", path)
		}
		log.Debugf("serving static files from %s", path)
	}
	// https://golangcode.com/serve-static-assets-using-the-mux-router/
	mux.PathPrefix(staticDir).Handler(http.StripPrefix(staticDir, (http.FileServer(http.Dir("." + staticDir)))))

	if cfg.Cfg.WebApp {
		log.Info("enabling websocket")
		tran.ExplicitInit()
		mux.Handle("/ws", tran.WS)
	}

	// socketio := tran.NewServer()
	// mux.Handle("/socket.io/", cors.AllowAll(socketio))
	// http.Handle("/socket.io/", tran.Server)

	srv := &http.Server{
		Handler: mux,
		Addr:    listen,
		// Good practice: enforce timeouts for servers you create!
		WriteTimeout: 15 * time.Second,
		ReadTimeout:  15 * time.Second,
		/// logrus has an example of using ErrorLog but it doesn't apply to this MUX implimentation
		// https://github.com/sirupsen/logrus#logger-as-an-iowriter
		// ErrorLog:     log.New(w, "", 0),
	}

	log.Fatal(srv.ListenAndServe())

}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"encoding/csv"
	"encoding/xml"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	r "reflect"
	"regexp"
	"strings"
)

func main() {
	var fp *os.File
	var err error

	// パース対象の xml ファイル名を引数に受ける
	fp, err = os.Open(os.Args[1])
	failOnError(err)
	defer fp.Close()

	reader := bufio.NewReaderSize(fp, 4096)

	var m map[string]string = map[string]string{}
	var playDataList []playData
	var shouldSet bool
	var key string
	d := xml.NewDecoder(reader)
	for {
		token, err := d.Token()
		if err == io.EOF {
			err = nil
			break
		}
		if err != nil {
			panic(err)
		}
		switch token.(type) {
		case xml.StartElement:
			if token.(xml.StartElement).Name.Local == "key" {
				shouldSet = false
			} else {
				shouldSet = true
			}
		case xml.EndElement:
			//do nothing
		case xml.CharData:
			if string(token.(xml.CharData)) == "Track ID" {
				// CharData が Track ID が来る＝今まで処理対象だったレコードの終了処理をする ＆ 次のレコードに処理を移す
				d := playData{}
				MapToStruct(m, &d)

				if d.TrackNumber != "" {
					playDataList = append(playDataList, d)
					// fmt.Println(d)
				}

				m = map[string]string{}
			}
			if shouldSet && key != "" {
				m[key] = string(token.(xml.CharData))
				key = ""
			} else {
				key = string(token.(xml.CharData))
			}
		case xml.Comment:
			//do nothing
		case xml.ProcInst:
			//do nothing
		case xml.Directive:
			//do nothing
		default:
			panic("unknown xml token.")
		}
	}

	// 出力する csv ファイル名として用いるために、xml ファイルの最終更新日時を取得
	finfo, err_finfo := fp.Stat()
	failOnError(err_finfo)
	ts := finfo.ModTime()
	mod_date := fmt.Sprintf("%d%02d%02d%02d%02d%02d", ts.Year(), ts.Month(), ts.Day(), ts.Hour(), ts.Minute(), ts.Second())

	export_csv(mod_date, playDataList)

	//外部コマンドを実行し、プロジェクト名を取得する
	cmd := exec.Command("gcloud", "config", "list")
	var out bytes.Buffer
	cmd.Stdout = &out
	failOnError(cmd.Run())
	fmt.Printf("in all caps: %q\n", out.String())
	//外部コマンドの実行結果からプロジェクト名を抽出する
	re, _ := regexp.Compile("\nproject = (.+)\n")
	one := re.Find([]byte(out.String()))
	fmt.Println("Find:", string(one))
	replace_re, _ := regexp.Compile("project|\\s|\n|=")
	project_name := replace_re.ReplaceAllString(string(one), "")
	fmt.Println("project_name:", string(project_name))
	//バケットが既に作成済みかどうかを調べて、未作成なら作成する
	cmd = exec.Command("gsutil", "ls")
	var ls_out bytes.Buffer
	cmd.Stdout = &ls_out
	failOnError(cmd.Run())
	fmt.Printf("in all caps: %q\n", ls_out.String())
	if m, _ := regexp.MatchString("gs://"+project_name+"-csv/\n", ls_out.String()); m {
		fmt.Println("バケット作成済み")
	} else {
		fmt.Println("バケット未作成")
		cmd = exec.Command("gsutil", "mb", "gs://"+project_name+"-csv")
		failOnError(cmd.Run())
		fmt.Println("バケット作成完了")
	}
	//作成したcsvファイルをアップロード
	cmd = exec.Command("gsutil", "cp", "csv/"+mod_date+".csv", "gs://"+project_name+"-csv")
	failOnError(cmd.Run())
	fmt.Println("gcsへのアップロードを完了")
	//BigQueryにデータセットが作成済みかどうかを調べて、未作成なら作成する
	ds_name := strings.Replace(project_name, "-", "_", -1) + "_ds"
	cmd = exec.Command("bq", "ls")
	var ds_out bytes.Buffer
	cmd.Stdout = &ds_out
	failOnError(cmd.Run())
	fmt.Printf("in all caps: %q\n", ds_out.String())
	fmt.Printf("ds_name: %q\n", ds_name)

	if m2, _ := regexp.MatchString("\n  "+ds_name+"  \n", ds_out.String()); m2 {
		fmt.Println("データセット作成済み")
	} else {
		fmt.Println("データセット未作成")
		cmd = exec.Command("bq", "mk", ds_name)
		failOnError(cmd.Run())
		fmt.Println("データセット作成完了")
	}

}

func export_csv(mod_date string, playDataList []playData) {
	// csv ディレクトリがなかったら作る
	failOnError(os.MkdirAll("./csv", 0744))
	filepath := fmt.Sprintf("./csv/%s.csv", mod_date)
	file, err := os.OpenFile(filepath, os.O_WRONLY|os.O_CREATE, 0600)
	failOnError(err)
	defer file.Close()

	err = file.Truncate(0) // ファイルを空にする(同一ファイルに対して2回目以降の実施の場合)
	failOnError(err)

	writer := csv.NewWriter(file)

	for _, data := range playDataList {
		structVal := r.Indirect(r.ValueOf(data))
		typ := structVal.Type()
		var raw []string

		for i := 0; i < typ.NumField(); i++ {
			field := structVal.Field(i)
			value := fmt.Sprintf("%v", field.Interface())
			raw = append(raw, strings.Replace(value, "\n", " ", -1))
		}
		writer.Write(raw)
	}
	writer.Flush()
}

func MapToStruct(mapVal map[string]string, val interface{}) (ok bool) {
	structVal := r.Indirect(r.ValueOf(val))
	for name, elem := range mapVal {
		// ここで来る name は　plist の key エレメントの値なのでスペースを含んでいる。
		// 一方 struct のフィールド名からはスペースを除去している。
		f := structVal.FieldByName(strings.Replace(name, " ", "", -1))
		if f.IsValid() {
			f.Set(r.ValueOf(elem))
		}
	}
	return
}

func failOnError(err error) {
	if err != nil {
		log.Fatal("Error:", err)
		panic(err)
	}
}

type playData struct {
	Artist               string
	Album                string
	Genre                string
	Kind                 string
	Size                 string
	TotalTime            string
	TrackNumber          string
	DateModified         string
	DateAdded            string
	BitRate              string
	SampleRate           string
	PersistentID         string
	TrackType            string
	Location             string
	FileFolderCount      string
	LibraryFolderCount   string
	PlayCount            string
	PlayDate             string
	PlayDateUTC          string
	Rating               string
	AlbumRating          string
	AlbumRatingComputed  string
	ArtworkCount         string
	SkipCount            string
	SkipDate             string
	Disabled             string
	SortAlbum            string
	Year                 string
	Comments             string
	SortName             string
	SortArtist           string
	VolumeAdjustment     string
	AlbumArtist          string
	DiscNumber           string
	DiscCount            string
	TrackCount           string
	ReleaseDate          string
	Protected            string
	Purchased            string
	Compilation          string
	Composer             string
	HasVideo             string
	VideoWidth           string
	VideoHeight          string
	Movie                string
	Master               string
	PlaylistID           string
	PlaylistPersistentID string
	Visible              string
	AllItems             string
	PlaylistItems        string
	SmartCriteria        string
}
<commit_msg>bqへのロードを行う<commit_after>package main

import (
	"bufio"
	"bytes"
	"encoding/csv"
	"encoding/xml"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	r "reflect"
	"regexp"
	"strings"
)

func main() {
	var fp *os.File
	var err error

	// パース対象の xml ファイル名を引数に受ける
	fp, err = os.Open(os.Args[1])
	failOnError(err)
	defer fp.Close()

	reader := bufio.NewReaderSize(fp, 4096)

	var m map[string]string = map[string]string{}
	var playDataList []playData
	var shouldSet bool
	var key string
	d := xml.NewDecoder(reader)
	for {
		token, err := d.Token()
		if err == io.EOF {
			err = nil
			break
		}
		if err != nil {
			panic(err)
		}
		switch token.(type) {
		case xml.StartElement:
			if token.(xml.StartElement).Name.Local == "key" {
				shouldSet = false
			} else {
				shouldSet = true
			}
		case xml.EndElement:
			//do nothing
		case xml.CharData:
			if string(token.(xml.CharData)) == "Track ID" {
				// CharData が Track ID が来る＝今まで処理対象だったレコードの終了処理をする ＆ 次のレコードに処理を移す
				d := playData{}
				MapToStruct(m, &d)

				if d.TrackNumber != "" {
					playDataList = append(playDataList, d)
					// fmt.Println(d)
				}

				m = map[string]string{}
			}
			if shouldSet && key != "" {
				m[key] = string(token.(xml.CharData))
				key = ""
			} else {
				key = string(token.(xml.CharData))
			}
		case xml.Comment:
			//do nothing
		case xml.ProcInst:
			//do nothing
		case xml.Directive:
			//do nothing
		default:
			panic("unknown xml token.")
		}
	}

	// 出力する csv ファイル名として用いるために、xml ファイルの最終更新日時を取得
	finfo, err_finfo := fp.Stat()
	failOnError(err_finfo)
	ts := finfo.ModTime()
	mod_date := fmt.Sprintf("%d%02d%02d%02d%02d%02d", ts.Year(), ts.Month(), ts.Day(), ts.Hour(), ts.Minute(), ts.Second())

	export_csv(mod_date, playDataList)

	//外部コマンドを実行し、プロジェクト名を取得する
	cmd := exec.Command("gcloud", "config", "list")
	var out bytes.Buffer
	cmd.Stdout = &out
	failOnError(cmd.Run())
	fmt.Printf("in all caps: %q\n", out.String())
	//外部コマンドの実行結果からプロジェクト名を抽出する
	re, _ := regexp.Compile("\nproject = (.+)\n")
	one := re.Find([]byte(out.String()))
	fmt.Println("Find:", string(one))
	replace_re, _ := regexp.Compile("project|\\s|\n|=")
	project_name := replace_re.ReplaceAllString(string(one), "")
	fmt.Println("project_name:", string(project_name))
	//バケットが既に作成済みかどうかを調べて、未作成なら作成する
	cmd = exec.Command("gsutil", "ls")
	var ls_out bytes.Buffer
	cmd.Stdout = &ls_out
	failOnError(cmd.Run())
	fmt.Printf("in all caps: %q\n", ls_out.String())
	if m, _ := regexp.MatchString("gs://"+project_name+"-csv/\n", ls_out.String()); m {
		fmt.Println("バケット作成済み")
	} else {
		fmt.Println("バケット未作成")
		cmd = exec.Command("gsutil", "mb", "gs://"+project_name+"-csv")
		failOnError(cmd.Run())
		fmt.Println("バケット作成完了")
	}
	//作成したcsvファイルをアップロード
	cmd = exec.Command("gsutil", "cp", "csv/"+mod_date+".csv", "gs://"+project_name+"-csv")
	failOnError(cmd.Run())
	fmt.Println("gcsへのアップロードを完了")
	//BigQueryにデータセットが作成済みかどうかを調べて、未作成なら作成する
	ds_name := strings.Replace(project_name, "-", "_", -1) + "_ds"
	cmd = exec.Command("bq", "ls")
	var ds_out bytes.Buffer
	cmd.Stdout = &ds_out
	failOnError(cmd.Run())
	fmt.Printf("in all caps: %q\n", ds_out.String())
	fmt.Printf("ds_name: %q\n", ds_name)

	if m2, _ := regexp.MatchString("\n  "+ds_name+"\\s+\n", ds_out.String()); m2 {
		fmt.Println("データセット作成済み")
	} else {
		fmt.Println("データセット未作成")
		cmd = exec.Command("bq", "mk", ds_name)
		failOnError(cmd.Run())
		fmt.Println("データセット作成完了")
	}
	//データセット内に既にテーブルがあるかどうかを調べ、なかったときだけロードを実施する（追記されてしまうため）
	cmd = exec.Command("bq", "ls", ds_name)
	var ds_ls_out bytes.Buffer
	cmd.Stdout = &ds_ls_out
	failOnError(cmd.Run())
	fmt.Printf("in all caps: %q\n", ds_ls_out.String())

	if m3, _ := regexp.MatchString("\n\\s+"+mod_date+"\\s+TABLE\\s+\n", ds_ls_out.String()); m3 {
		fmt.Println("当該データロード済み")
	} else {
		fmt.Println("当該データ未ロード")
		//作成したデータセットにデータをロードする
		cmd = exec.Command("bq", "load", "--schema=playdata_schema.json", ds_name+"."+mod_date, "gs://"+project_name+"-csv/"+mod_date+".csv")
		failOnError(cmd.Run())
		fmt.Println("bqへのロードを完了")
	}
	//ロードに使用したcsvファイルをgcsから削除する
	cmd = exec.Command("gsutil", "rm", "gs://"+project_name+"-csv/"+mod_date+".csv")
	failOnError(cmd.Run())
	fmt.Println("gcs上のファイルの削除を完了")
}

func export_csv(mod_date string, playDataList []playData) {
	// csv ディレクトリがなかったら作る
	failOnError(os.MkdirAll("./csv", 0744))
	filepath := fmt.Sprintf("./csv/%s.csv", mod_date)
	file, err := os.OpenFile(filepath, os.O_WRONLY|os.O_CREATE, 0600)
	failOnError(err)
	defer file.Close()

	err = file.Truncate(0) // ファイルを空にする(同一ファイルに対して2回目以降の実施の場合)
	failOnError(err)

	writer := csv.NewWriter(file)

	for _, data := range playDataList {
		structVal := r.Indirect(r.ValueOf(data))
		typ := structVal.Type()
		var raw []string

		for i := 0; i < typ.NumField(); i++ {
			field := structVal.Field(i)
			value := fmt.Sprintf("%v", field.Interface())
			raw = append(raw, strings.Replace(value, "\n", " ", -1))
		}
		writer.Write(raw)
	}
	writer.Flush()
}

func MapToStruct(mapVal map[string]string, val interface{}) (ok bool) {
	structVal := r.Indirect(r.ValueOf(val))
	for name, elem := range mapVal {
		// ここで来る name は　plist の key エレメントの値なのでスペースを含んでいる。
		// 一方 struct のフィールド名からはスペースを除去している。
		f := structVal.FieldByName(strings.Replace(name, " ", "", -1))
		if f.IsValid() {
			f.Set(r.ValueOf(elem))
		}
	}
	return
}

func failOnError(err error) {
	if err != nil {
		log.Fatal("Error:", err)
		panic(err)
	}
}

type playData struct {
	Artist               string
	Album                string
	Genre                string
	Kind                 string
	Size                 string
	TotalTime            string
	TrackNumber          string
	DateModified         string
	DateAdded            string
	BitRate              string
	SampleRate           string
	PersistentID         string
	TrackType            string
	Location             string
	FileFolderCount      string
	LibraryFolderCount   string
	PlayCount            string
	PlayDate             string
	PlayDateUTC          string
	Rating               string
	AlbumRating          string
	AlbumRatingComputed  string
	ArtworkCount         string
	SkipCount            string
	SkipDate             string
	Disabled             string
	SortAlbum            string
	Year                 string
	Comments             string
	SortName             string
	SortArtist           string
	VolumeAdjustment     string
	AlbumArtist          string
	DiscNumber           string
	DiscCount            string
	TrackCount           string
	ReleaseDate          string
	Protected            string
	Purchased            string
	Compilation          string
	Composer             string
	HasVideo             string
	VideoWidth           string
	VideoHeight          string
	Movie                string
	Master               string
	PlaylistID           string
	PlaylistPersistentID string
	Visible              string
	AllItems             string
	PlaylistItems        string
	SmartCriteria        string
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/http"
	"strings"

	"github.com/julienschmidt/httprouter"
)

func helloWorld(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	fmt.Fprintf(w, "Hello, World")
}

func catalog(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	catalog, err := Asset("config/settings.json")
	if err != nil {
		return
	}
	fmt.Fprintf(w, string(catalog))
}

func createInstance(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	dbname := fmt.Sprintf("d%s", ps.ByName("instance_id"))
	dashboard_url, err := createDatabase(strings.Replace(dbname, "-", "_", -1))

	if err == nil {
		fmt.Fprintf(w, dashboard_url)
	} else {
		w.WriteHeader(err.Code)
		fmt.Fprintf(w, err.Err.Error())
	}
}

func deleteInstance(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	dbname := fmt.Sprintf("d%s", ps.ByName("instance_id"))

	err := deleteDatabase(strings.Replace(dbname, "-", "_", -1))
	if err == nil {
		fmt.Fprintf(w, " ")
	} else {
		w.WriteHeader(err.Code)
		fmt.Fprintf(w, err.Err.Error())
	}
}

func Router() *httprouter.Router {
	router := httprouter.New()
	router.GET("/", helloWorld)
	router.GET("/v2/catalog", basicAuth(catalog))
	router.PUT("/v2/service_instances/:instance_id", basicAuth(createInstance))
	router.DELETE("/v2/service_instances/:instance_id", basicAuth(deleteInstance))
	return router
}

func main() {
	router := Router()
	log.Fatal(http.ListenAndServe(":8080", router))
}
<commit_msg>Return json responses instead of strings.<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strings"

	"github.com/julienschmidt/httprouter"
)

func helloWorld(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	fmt.Fprintf(w, "Hello, World")
}

func catalog(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	catalog, err := Asset("config/settings.json")
	if err != nil {
		return
	}
	fmt.Fprintf(w, string(catalog))
}

func createInstance(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	dbname := fmt.Sprintf("d%s", ps.ByName("instance_id"))
	dashboard_url, err := createDatabase(strings.Replace(dbname, "-", "_", -1))

	response := make(map[string]string)

	if err == nil {
		response["dashboard_url"] = dashboard_url
	} else {
		w.WriteHeader(err.Code)
		response["description"] = err.Err.Error()
	}
	w.Header().Set("Content-Type", "application/json")
	j, _ := json.Marshal(response)
	w.Write(j)
}

func deleteInstance(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	dbname := fmt.Sprintf("d%s", ps.ByName("instance_id"))

	response := make(map[string]string)
	err := deleteDatabase(strings.Replace(dbname, "-", "_", -1))
	if err != nil {
		w.WriteHeader(err.Code)
		response["description"] = err.Err.Error()
	}
	w.Header().Set("Content-Type", "application/json")
	j, _ := json.Marshal(response)
	w.Write(j)
}

func Router() *httprouter.Router {
	router := httprouter.New()
	router.GET("/", helloWorld)
	router.GET("/v2/catalog", basicAuth(catalog))
	router.PUT("/v2/service_instances/:instance_id", basicAuth(createInstance))
	router.DELETE("/v2/service_instances/:instance_id", basicAuth(deleteInstance))
	router.PUT("/v2/service_instances/:instance_id/service_bindings/:binding_id",
		basicAuth(createBinding))
	return router
}

func main() {
	router := Router()
	log.Fatal(http.ListenAndServe(":8080", router))
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"io/ioutil"
	"os"

	"github.com/cucumber/godog"
	"github.com/ii/xds-test-harness/internal/parser"
	"github.com/ii/xds-test-harness/internal/runner"
	"github.com/ii/xds-test-harness/internal/types"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
	"github.com/spf13/pflag"
)

var (
	debug          = pflag.BoolP("debug", "D", false, "sets log level to debug")
	config         = pflag.StringP("config", "C", "", "Path to optional config file. This file sets the adapter and target addresses and supported variants.")
	adapterAddress = pflag.StringP("adapter", "A", ":17000", "port of adapter on target")
	targetAddress  = pflag.StringP("target", "T", ":18000", "port of xds target to test")
	nodeID         = pflag.StringP("nodeID", "N", "test-id", "node id of target")
	variant        = pflag.StringArrayP("variant", "V", []string{"sotw non-aggregated", "sotw aggregated", "incremental non-aggregated", "incremental aggregated"}, "xDS protocol variant your server supports. Add a separate flag per each supported variant.\n Possibleariants are: sotw non-aggregated\n, sotw aggregated\n, incremental non-aggregated\n, incremental aggregated\n.")
	godogOpts      = godog.Options{}
)

func init() {
	godog.BindCommandLineFlags("godog.", &godogOpts)
	zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
	log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
	zerolog.SetGlobalLevel(zerolog.InfoLevel)
}

func main() {
	pflag.Parse()
	godogTags := godogOpts.Tags

	if *debug {
		zerolog.SetGlobalLevel(zerolog.DebugLevel)
	}

	// default to using CLI Flag for settings
	err, supportedVariants := parser.ParseSupportedVariants(*variant)
	if err != nil {
		log.Fatal().Msgf("Cannot parse variants from CLI: %v\n", err)
	}
	// If config present, use it for all non-debugging values
	if *config != "" {
		*targetAddress, *adapterAddress, *nodeID, supportedVariants = parser.ValuesFromConfig(*config)
	}

	var results types.Results
	for _, variant := range supportedVariants {
		log.Info().
			Msgf("Starting Tests for %v\n", string(variant))

		suite := runner.NewSuite(variant)
		err, variantResults := suite.Run(*adapterAddress, *targetAddress, *nodeID, godogTags)
		if err != nil {
			log.Fatal().
				Msgf("Error when attempting to run test suite: %v\n", err)
		}
		results = runner.UpdateResults(results, variantResults)
	}
	log.Info().
		Msgf("All done, here are your results!!: %v\n", results)

	file, _ := json.MarshalIndent(results, "", "  ")
	_ = ioutil.WriteFile("results.json", file, 0644)
	os.Exit(0)
}
<commit_msg>Add basic results printout at end of suite<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	// "strings"

	"github.com/cucumber/godog"
	"github.com/ii/xds-test-harness/internal/parser"
	"github.com/ii/xds-test-harness/internal/runner"
	"github.com/ii/xds-test-harness/internal/types"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
	"github.com/spf13/pflag"
)

var (
	debug          = pflag.BoolP("debug", "D", false, "sets log level to debug")
	config         = pflag.StringP("config", "C", "", "Path to optional config file. This file sets the adapter and target addresses and supported variants.")
	adapterAddress = pflag.StringP("adapter", "A", ":17000", "port of adapter on target")
	targetAddress  = pflag.StringP("target", "T", ":18000", "port of xds target to test")
	nodeID         = pflag.StringP("nodeID", "N", "test-id", "node id of target")
	variant        = pflag.StringArrayP("variant", "V", []string{"sotw non-aggregated", "sotw aggregated", "incremental non-aggregated", "incremental aggregated"}, "xDS protocol variant your server supports. Add a separate flag per each supported variant.\n Possibleariants are: sotw non-aggregated\n, sotw aggregated\n, incremental non-aggregated\n, incremental aggregated\n.")
	godogOpts      = godog.Options{}
)

func init() {
	godog.BindCommandLineFlags("godog.", &godogOpts)
	zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
	log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
	zerolog.SetGlobalLevel(zerolog.InfoLevel)
}

func main() {
	pflag.Parse()
	godogTags := godogOpts.Tags

	if *debug {
		zerolog.SetGlobalLevel(zerolog.DebugLevel)
	}

	// default to using CLI Flag for settings
	err, supportedVariants := parser.ParseSupportedVariants(*variant)
	if err != nil {
		log.Fatal().Msgf("Cannot parse variants from CLI: %v\n", err)
	}
	// If config present, use it for all non-debugging values
	if *config != "" {
		*targetAddress, *adapterAddress, *nodeID, supportedVariants = parser.ValuesFromConfig(*config)
	}

	var results types.Results
	for _, variant := range supportedVariants {
		log.Info().
			Msgf("Starting Tests for %v\n", string(variant))

		suite := runner.NewSuite(variant)
		err, variantResults := suite.Run(*adapterAddress, *targetAddress, *nodeID, godogTags)
		if err != nil {
			log.Fatal().
				Msgf("Error when attempting to run test suite: %v\n", err)
		}
		results = runner.UpdateResults(results, variantResults)
	}
	printResults(results)

	file, _ := json.MarshalIndent(results, "", "  ")
	_ = ioutil.WriteFile("results.json", file, 0644)
	os.Exit(0)
}

func printResults(results types.Results) {

	divider := "-------------------"
	fmt.Println("\nTest Suite Finished\n" + divider)
	fmt.Printf("Ran %v tests across %v variants\n\n", results.Total, len(results.Variants))
	fmt.Printf("Passed: %v\nFailed: %v", results.Passed, results.Failed)
	fmt.Printf("\n\nResults broken down by Variant....\n\n")
	for _, variant := range results.ResultsByVariant {
		fmt.Println(variant.Name+"\n"+divider)
		fmt.Println(variantResults(variant))
	}
}

func variantResults(results types.VariantResults) string {
	total := fmt.Sprintf("Total tests: %v\n", results.Total)
	passed := fmt.Sprintf("Passed: %v\n", results.Passed)
	failed := fmt.Sprintf("Failed: %v\n", results.Failed)
	var failedTests string
	if len(results.FailedTests) > 0 {
		failedTests = "Failed Tests:\n"
		for _, test := range results.FailedTests {
			failedTests = failedTests + "  - " + test.Scenario + "\n"
		}
	}
	return total + passed + failed + failedTests
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"

	"github.com/mitchellh/go-homedir"
)

func shortUsage() {
	os.Stderr.WriteString(`
usage: vub [option(s)] <repository-uri>
try 'vub --help' for more information.
`[1:])
}

func usage() {
	os.Stderr.WriteString(`
usage: vub [option(s)] <repository-uri>
install Vim plugin to under the management of vim-unbundle.

options:
  -h, --help                show this help message
  -f, --filetype=TYPE       installing under the ftbundle/TYPE
`[1:])
}

var (
	ShortGitHubURI = regexp.MustCompile(`^[\w\-.]+/[\w\-.]+$`)
)

func ToSourceURI(uri string) (string, error) {
	switch {
	case ShortGitHubURI.MatchString(uri):
		return "https://github.com/" + uri, nil
	default:
		return uri, nil
	}
}

var (
	home, errInit = homedir.Dir()
	dotvim        = filepath.Join(home, ".vim")
)

func ToDestinationPath(uri, filetype string) (string, error) {
	name := filepath.Base(uri)
	if filetype == "" {
		return filepath.Join(dotvim, "bundle", name), nil
	}
	return filepath.Join(dotvim, "ftbundle", filetype, name), nil
}

type Package struct {
	src string
	dst string
}

func NewPackage(uri, filetype string) (*Package, error) {
	src, err := ToSourceURI(uri)
	if err != nil {
		return nil, err
	}
	dst, err := ToDestinationPath(uri, filetype)
	if err != nil {
		return nil, err
	}
	return &Package{
		src: src,
		dst: dst,
	}, nil
}

func (p *Package) ToCommand() *exec.Cmd {
	return exec.Command("git", "clone", p.src, p.dst)
}

func main() {
	var filetype string
	flag.StringVar(&filetype, "f", "", "")
	flag.StringVar(&filetype, "filetype", "", "")

	var isHelp bool
	flag.BoolVar(&isHelp, "h", false, "")
	flag.BoolVar(&isHelp, "help", false, "")
	flag.Usage = usage
	flag.Parse()
	switch {
	case isHelp:
		usage()
		os.Exit(0)
	case flag.NArg() < 1:
		shortUsage()
		os.Exit(2)
	}
	uri := flag.Arg(0)

	p, err := NewPackage(uri, filetype)
	if err != nil {
		fmt.Fprintln(os.Stderr, "vub:", err)
		os.Exit(2)
	}

	c := p.ToCommand()
	if err := c.Run(); err != nil {
		fmt.Fprintln(os.Stderr, "vub:", err)
		os.Exit(1)
	}
}
<commit_msg>Implement set Verbose<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"

	"github.com/mitchellh/go-homedir"
)

func shortUsage() {
	os.Stderr.WriteString(`
usage: vub [option(s)] <repository-uri>
try 'vub --help' for more information.
`[1:])
}

func usage() {
	os.Stderr.WriteString(`
usage: vub [option(s)] <repository-uri>
install Vim plugin to under the management of vim-unbundle.

options:
  -h, --help                show this help message
  -f, --filetype=TYPE       installing under the ftbundle/TYPE
`[1:])
}

var (
	ShortGitHubURI = regexp.MustCompile(`^[\w\-.]+/[\w\-.]+$`)
)

func ToSourceURI(uri string) (string, error) {
	switch {
	case ShortGitHubURI.MatchString(uri):
		return "https://github.com/" + uri, nil
	default:
		return uri, nil
	}
}

var (
	home, errInit = homedir.Dir()
	dotvim        = filepath.Join(home, ".vim")
)

func ToDestinationPath(uri, filetype string) (string, error) {
	name := filepath.Base(uri)
	if filetype == "" {
		return filepath.Join(dotvim, "bundle", name), nil
	}
	return filepath.Join(dotvim, "ftbundle", filetype, name), nil
}

type Package struct {
	verbose bool
	src     string
	dst     string
}

func NewPackage(uri, filetype string) (*Package, error) {
	src, err := ToSourceURI(uri)
	if err != nil {
		return nil, err
	}
	dst, err := ToDestinationPath(uri, filetype)
	if err != nil {
		return nil, err
	}
	return &Package{
		src: src,
		dst: dst,
	}, nil
}

func (p *Package) ToCommand() *exec.Cmd {
	return exec.Command("git", "clone", p.src, p.dst)
}

func (p *Package) Verbose(enable bool) {
	p.verbose = enable
}

func main() {
	var filetype string
	flag.StringVar(&filetype, "f", "", "")
	flag.StringVar(&filetype, "filetype", "", "")

	var isHelp bool
	flag.BoolVar(&isHelp, "h", false, "")
	flag.BoolVar(&isHelp, "help", false, "")
	flag.Usage = usage
	flag.Parse()
	switch {
	case isHelp:
		usage()
		os.Exit(0)
	case flag.NArg() < 1:
		shortUsage()
		os.Exit(2)
	}
	uri := flag.Arg(0)

	p, err := NewPackage(uri, filetype)
	if err != nil {
		fmt.Fprintln(os.Stderr, "vub:", err)
		os.Exit(2)
	}

	c := p.ToCommand()
	if err := c.Run(); err != nil {
		fmt.Fprintln(os.Stderr, "vub:", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os/exec"
	"time"

	"github.com/zenhack/my-status-monitor/battery"
)

const (
)

func emit(str string) {
	cmd := exec.Command("xsetroot", "-name", str)
	cmd.Run()
}

func main() {
	timeFormat := "Mon Jan 2 3:04 PM"
	myBattery := &battery.Battery{Path: "/sys/class/power_supply/BAT0/"}

	go myBattery.Monitor()
	go myBattery.NotifyDaemon()

	for {
		t := time.Now()
		state := myBattery.State
		if state != nil {
			emit(fmt.Sprintf("%v | %s", state, t.Format(timeFormat)))
		} else {
			emit(t.Format(timeFormat))
		}
		time.Sleep(time.Second)
	}
}
<commit_msg>Deleted an empty const declaration, and ran gofmt.<commit_after>package main

import (
	"fmt"
	"os/exec"
	"time"

	"github.com/zenhack/my-status-monitor/battery"
)

func emit(str string) {
	cmd := exec.Command("xsetroot", "-name", str)
	cmd.Run()
}

func main() {
	timeFormat := "Mon Jan 2 3:04 PM"
	myBattery := &battery.Battery{Path: "/sys/class/power_supply/BAT0/"}

	go myBattery.Monitor()
	go myBattery.NotifyDaemon()

	for {
		t := time.Now()
		state := myBattery.State
		if state != nil {
			emit(fmt.Sprintf("%v | %s", state, t.Format(timeFormat)))
		} else {
			emit(t.Format(timeFormat))
		}
		time.Sleep(time.Second)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"path"
	"strings"
	"sync"
)

// Printed for -help, -h or with wrong number of arguments
var usage = `Usage: %s githubname backupdir

  githubname  github user or organization name to get the repositories from
  backupdir   directory path to save the repositories to

`

type repo struct {
	Name   string
	GitURL string `json:"git_url"`
}

var maxWorkers = 10
var githubAPI = "https://api.github.com"

// Get command line arguments and start updating repositories
func main() {
	logger := log.New(os.Stderr, "", log.Ldate|log.Ltime|log.Lshortfile|log.LUTC)
	name, backupDir, verbose := parseArgs()
	client := http.DefaultClient

	category, err := getCategory(name, client)
	if err != nil {
		logger.Fatal(err)
	}
	url, err := setMaxPageSize(strings.Join([]string{githubAPI, category, name, "repos"}, "/"))
	if err != nil {
		logger.Fatal(err)
	}
	repos, err := getRepos(url, client)
	if err != nil {
		logger.Fatal(err)
	}

	if verbose {
		logger.Println("Backup for", category[:len(category)-1], name, "with", len(repos), "repositories")
	}

	jobs := make(chan repo)

	workers := maxWorkers
	if len(repos) < maxWorkers {
		workers = len(repos)
	}

	var wg sync.WaitGroup
	wg.Add(workers)

	for w := 0; w < workers; w++ {
		go func() {
			defer wg.Done()
			for r := range jobs {
				err := updateRepo(backupDir, r, logger, verbose)
				if err != nil {
					logger.Println(err)
				}
			}
		}()
	}

	for _, r := range repos {
		jobs <- r
	}
	close(jobs)
	wg.Wait()
}

// Get the two positional arguments githubname and backupdir
func parseArgs() (string, string, bool) {
	verbose := flag.Bool("verbose", false, "print progress information")
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, usage, os.Args[0])
		flag.PrintDefaults()
	}
	flag.Parse()
	args := flag.Args()
	if len(args) != 2 {
		flag.Usage()
		os.Exit(1)
	}
	return args[0], args[1], *verbose
}

// Returns "users" or "orgs" depending on type of account
func getCategory(name string, client *http.Client) (string, error) {
	res, err := client.Get(strings.Join([]string{githubAPI, "users", name}, "/"))
	if err != nil {
		return "", fmt.Errorf("cannot get user info: %v", err)
	}
	defer func() {
		_ = res.Body.Close()
	}()
	if res.StatusCode >= 300 {
		return "", fmt.Errorf("bad response from %s: %v", res.Request.URL, res.Status)
	}

	var account struct {
		Type string
	}
	err = json.NewDecoder(res.Body).Decode(&account)
	if err != nil {
		return "", fmt.Errorf("cannot decode JSON response: %v", err)
	}

	if account.Type == "User" {
		return "users", nil
	}
	if account.Type == "Organization" {
		return "orgs", nil
	}
	return "", fmt.Errorf("unknown type of account %s for name %s", account.Type, name)
}

// Get repositories from Github.
// Follow "next" links recursivly.
func getRepos(u string, client *http.Client) ([]repo, error) {
	res, err := client.Get(u)
	if err != nil {
		return nil, fmt.Errorf("cannot get repos: %v", err)
	}
	defer func() {
		_ = res.Body.Close()
	}()
	if res.StatusCode >= 300 {
		return nil, fmt.Errorf("bad response from %s: %v", res.Request.URL, res.Status)
	}

	var repos []repo
	err = json.NewDecoder(res.Body).Decode(&repos)
	if err != nil {
		return nil, fmt.Errorf("cannot decode JSON response: %v", err)
	}

	linkHeader := res.Header["Link"]
	if len(linkHeader) > 0 {
		firstLink := strings.Split(linkHeader[0], ",")[0]
		if strings.Contains(firstLink, "rel=\"next\"") {
			urlInBrackets := strings.Split(firstLink, ";")[0]
			nextRepos, err := getRepos(urlInBrackets[1:len(urlInBrackets)-1], client)
			return append(repos, nextRepos...), err
		}
	}

	return repos, nil
}

//  Adds per_page=100 to a URL
func setMaxPageSize(rawURL string) (string, error) {
	u, err := url.Parse(rawURL)
	if err != nil {
		return "", fmt.Errorf("cannot parse url: %v", err)
	}
	q := u.Query()
	q.Set("per_page", "100")
	u.RawQuery = q.Encode()
	return u.String(), nil
}

// Clone new repo or pull in existing repo
func updateRepo(backupDir string, r repo, logger *log.Logger, verbose bool) error {
	repoDir := path.Join(backupDir, r.Name)

	var cmd *exec.Cmd
	repoExists, err := exists(repoDir)
	if err != nil {
		return fmt.Errorf("cannot check if repo exists: %v", err)
	}
	if repoExists {
		if verbose {
			logger.Println("Update repository:", r.Name)
		}
		cmd = exec.Command("git", "pull")
		cmd.Dir = repoDir
	} else {
		if verbose {
			logger.Println("Clone  repository:", r.Name)
		}
		cmd = exec.Command("git", "clone", r.GitURL, repoDir)
	}

	err = cmd.Run()
	if err != nil {
		// Give enough information to reproduce command
		return fmt.Errorf("error running command `%v` (`%v`) in dir `%v` with env `%v`: %v", cmd.Args, cmd.Path, cmd.Dir, cmd.Env, err)
	}
	return nil
}

// Check if a file or directory exists
func exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}
		return false, fmt.Errorf("cannot get stats for path `%s`: %v", path, err)
	}
	return true, nil
}
<commit_msg>use tab for aligning verbose log output<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"path"
	"strings"
	"sync"
)

// Printed for -help, -h or with wrong number of arguments
var usage = `Usage: %s githubname backupdir

  githubname  github user or organization name to get the repositories from
  backupdir   directory path to save the repositories to

`

type repo struct {
	Name   string
	GitURL string `json:"git_url"`
}

var maxWorkers = 10
var githubAPI = "https://api.github.com"

// Get command line arguments and start updating repositories
func main() {
	logger := log.New(os.Stderr, "", log.Ldate|log.Ltime|log.Lshortfile|log.LUTC)
	name, backupDir, verbose := parseArgs()
	client := http.DefaultClient

	category, err := getCategory(name, client)
	if err != nil {
		logger.Fatal(err)
	}
	url, err := setMaxPageSize(strings.Join([]string{githubAPI, category, name, "repos"}, "/"))
	if err != nil {
		logger.Fatal(err)
	}
	repos, err := getRepos(url, client)
	if err != nil {
		logger.Fatal(err)
	}

	if verbose {
		logger.Println("Backup for", category[:len(category)-1], name, "with", len(repos), "repositories")
	}

	jobs := make(chan repo)

	workers := maxWorkers
	if len(repos) < maxWorkers {
		workers = len(repos)
	}

	var wg sync.WaitGroup
	wg.Add(workers)

	for w := 0; w < workers; w++ {
		go func() {
			defer wg.Done()
			for r := range jobs {
				err := updateRepo(backupDir, r, logger, verbose)
				if err != nil {
					logger.Println(err)
				}
			}
		}()
	}

	for _, r := range repos {
		jobs <- r
	}
	close(jobs)
	wg.Wait()
}

// Get the two positional arguments githubname and backupdir
func parseArgs() (string, string, bool) {
	verbose := flag.Bool("verbose", false, "print progress information")
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, usage, os.Args[0])
		flag.PrintDefaults()
	}
	flag.Parse()
	args := flag.Args()
	if len(args) != 2 {
		flag.Usage()
		os.Exit(1)
	}
	return args[0], args[1], *verbose
}

// Returns "users" or "orgs" depending on type of account
func getCategory(name string, client *http.Client) (string, error) {
	res, err := client.Get(strings.Join([]string{githubAPI, "users", name}, "/"))
	if err != nil {
		return "", fmt.Errorf("cannot get user info: %v", err)
	}
	defer func() {
		_ = res.Body.Close()
	}()
	if res.StatusCode >= 300 {
		return "", fmt.Errorf("bad response from %s: %v", res.Request.URL, res.Status)
	}

	var account struct {
		Type string
	}
	err = json.NewDecoder(res.Body).Decode(&account)
	if err != nil {
		return "", fmt.Errorf("cannot decode JSON response: %v", err)
	}

	if account.Type == "User" {
		return "users", nil
	}
	if account.Type == "Organization" {
		return "orgs", nil
	}
	return "", fmt.Errorf("unknown type of account %s for name %s", account.Type, name)
}

// Get repositories from Github.
// Follow "next" links recursivly.
func getRepos(u string, client *http.Client) ([]repo, error) {
	res, err := client.Get(u)
	if err != nil {
		return nil, fmt.Errorf("cannot get repos: %v", err)
	}
	defer func() {
		_ = res.Body.Close()
	}()
	if res.StatusCode >= 300 {
		return nil, fmt.Errorf("bad response from %s: %v", res.Request.URL, res.Status)
	}

	var repos []repo
	err = json.NewDecoder(res.Body).Decode(&repos)
	if err != nil {
		return nil, fmt.Errorf("cannot decode JSON response: %v", err)
	}

	linkHeader := res.Header["Link"]
	if len(linkHeader) > 0 {
		firstLink := strings.Split(linkHeader[0], ",")[0]
		if strings.Contains(firstLink, "rel=\"next\"") {
			urlInBrackets := strings.Split(firstLink, ";")[0]
			nextRepos, err := getRepos(urlInBrackets[1:len(urlInBrackets)-1], client)
			return append(repos, nextRepos...), err
		}
	}

	return repos, nil
}

//  Adds per_page=100 to a URL
func setMaxPageSize(rawURL string) (string, error) {
	u, err := url.Parse(rawURL)
	if err != nil {
		return "", fmt.Errorf("cannot parse url: %v", err)
	}
	q := u.Query()
	q.Set("per_page", "100")
	u.RawQuery = q.Encode()
	return u.String(), nil
}

// Clone new repo or pull in existing repo
func updateRepo(backupDir string, r repo, logger *log.Logger, verbose bool) error {
	repoDir := path.Join(backupDir, r.Name)

	var cmd *exec.Cmd
	repoExists, err := exists(repoDir)
	if err != nil {
		return fmt.Errorf("cannot check if repo exists: %v", err)
	}
	if repoExists {
		if verbose {
			logger.Println("Update	repository:", r.Name)
		}
		cmd = exec.Command("git", "pull")
		cmd.Dir = repoDir
	} else {
		if verbose {
			logger.Println("Clone	repository:", r.Name)
		}
		cmd = exec.Command("git", "clone", r.GitURL, repoDir)
	}

	err = cmd.Run()
	if err != nil {
		// Give enough information to reproduce command
		return fmt.Errorf("error running command `%v` (`%v`) in dir `%v` with env `%v`: %v", cmd.Args, cmd.Path, cmd.Dir, cmd.Env, err)
	}
	return nil
}

// Check if a file or directory exists
func exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}
		return false, fmt.Errorf("cannot get stats for path `%s`: %v", path, err)
	}
	return true, nil
}
<|endoftext|>