<commit_before>package main // import "github.com/gaia-docker/tugbot"

import (
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"os"
	"os/signal"
	"strings"
	"sync"
	"syscall"

	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/gaia-docker/tugbot-common/event"
	"github.com/gaia-docker/tugbot/actions"
	"github.com/gaia-docker/tugbot/container"
	"github.com/samalba/dockerclient"
)

var (
	client    container.Client
	names     []string
	wgr       sync.WaitGroup
	wgp       sync.WaitGroup
	publisher event.Publisher
)

const (
	// Release version
	Release = "v0.2.0"
)

func init() {
	log.SetLevel(log.InfoLevel)
}

func main() {
	rootCertPath := "/etc/ssl/docker"

	if os.Getenv("DOCKER_CERT_PATH") != "" {
		rootCertPath = os.Getenv("DOCKER_CERT_PATH")
	}

	app := cli.NewApp()
	app.Name = "Tugbot"
	app.Version = Release
	app.Usage = "Tugbot is a continuous testing framework for Docker based environments. Tugbot monitors changes in a runtime environment (host, os, container), runs tests (packaged into Test Containers), when event occured and collects test results."
	app.ArgsUsage = "test containers: name, list of names, or none (for all test containers)"
	app.Before = before
	app.Action = start
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "host, H",
			Usage:  "daemon socket to connect to",
			Value:  "unix:///var/run/docker.sock",
			EnvVar: "DOCKER_HOST",
		},
		cli.BoolFlag{
			Name:  "tls",
			Usage: "use TLS; implied by --tlsverify",
		},
		cli.BoolFlag{
			Name:   "tlsverify",
			Usage:  "use TLS and verify the remote",
			EnvVar: "DOCKER_TLS_VERIFY",
		},
		cli.StringFlag{
			Name:  "tlscacert",
			Usage: "trust certs signed only by this CA",
			Value: fmt.Sprintf("%s/ca.pem", rootCertPath),
		},
		cli.StringFlag{
			Name:  "tlscert",
			Usage: "client certificate for TLS authentication",
			Value: fmt.Sprintf("%s/cert.pem", rootCertPath),
		},
		cli.StringFlag{
			Name:  "tlskey",
			Usage: "client key for TLS authentication",
			Value: fmt.Sprintf("%s/key.pem", rootCertPath),
		},
		cli.BoolFlag{
			Name:  "debug",
			Usage: "enable debug mode with verbose logging",
		},
		cli.StringFlag{
			Name:   "webhooks",
			Usage:  "list of urls sperated by ';'",
			Value:  "http://result-service:8080/events",
			EnvVar: "TUGBOT_WEBHOOKS",
		},
	}

	if err := app.Run(os.Args); err != nil {
		log.Fatal(err)
	}
}

func before(c *cli.Context) error {
	if c.GlobalBool("debug") {
		log.SetLevel(log.DebugLevel)
	}

	// Set-up container client
	tls, err := tlsConfig(c)
	if err != nil {
		return err
	}

	client = container.NewClient(c.GlobalString("host"), tls, !c.GlobalBool("no-pull"))

	return nil
}

func start(c *cli.Context) {
	names = c.Args()
	startMonitorEvents(c)
	log.Info("Tugbot Started OK")
	waitForInterrupt()
}

func startMonitorEvents(c *cli.Context) {
	client.StartMonitorEvents(runTestContainers)
	webhook := c.GlobalString("webhook")
	if webhook != "" {
		publisher = event.NewPublisher(strings.Split(webhook, ";"))
		client.StartMonitorEvents(publishEvent)
	}
}

func runTestContainers(e *dockerclient.Event, ec chan error, args ...interface{}) {
	wgr.Add(1)
	if err := actions.Run(client, names, e); err != nil {
		log.Error(err)
	}
	wgr.Done()
}

func publishEvent(e *dockerclient.Event, ec chan error, args ...interface{}) {
	wgp.Add(1)
	publisher.Publish(e)
	wgp.Done()
}

func waitForInterrupt() {
	// Graceful shut-down on SIGINT/SIGTERM/SIGQUIT
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT)
	<-c
	log.Debug("Stop monitoring events ...")
	wgr.Wait()
	client.StopAllMonitorEvents()
	log.Debug("Graceful exit :-)")
	os.Exit(1)
}

// tlsConfig translates the command-line options into a tls.Config struct
func tlsConfig(c *cli.Context) (*tls.Config, error) {
	var tlsConfig *tls.Config
	var err error
	caCertFlag := c.GlobalString("tlscacert")
	certFlag := c.GlobalString("tlscert")
	keyFlag := c.GlobalString("tlskey")

	if c.GlobalBool("tls") || c.GlobalBool("tlsverify") {
		tlsConfig = &tls.Config{
			InsecureSkipVerify: !c.GlobalBool("tlsverify"),
		}

		// Load CA cert
		if caCertFlag != "" {
			var caCert []byte

			if strings.HasPrefix(caCertFlag, "/") {
				caCert, err = ioutil.ReadFile(caCertFlag)
				if err != nil {
					return nil, err
				}
			} else {
				caCert = []byte(caCertFlag)
			}

			caCertPool := x509.NewCertPool()
			caCertPool.AppendCertsFromPEM(caCert)

			tlsConfig.RootCAs = caCertPool
		}

		// Load client certificate
		if certFlag != "" && keyFlag != "" {
			var cert tls.Certificate

			if strings.HasPrefix(certFlag, "/") && strings.HasPrefix(keyFlag, "/") {
				cert, err = tls.LoadX509KeyPair(certFlag, keyFlag)
				if err != nil {
					return nil, err
				}
			} else {
				cert, err = tls.X509KeyPair([]byte(certFlag), []byte(keyFlag))
				if err != nil {
					return nil, err
				}
			}
			tlsConfig.Certificates = []tls.Certificate{cert}
		}
	}

	return tlsConfig, nil
}
<commit_msg>Fix cli var;<commit_after>package main // import "github.com/gaia-docker/tugbot"

import (
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"os"
	"os/signal"
	"strings"
	"sync"
	"syscall"

	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/gaia-docker/tugbot-common/event"
	"github.com/gaia-docker/tugbot/actions"
	"github.com/gaia-docker/tugbot/container"
	"github.com/samalba/dockerclient"
)

var (
	client    container.Client
	names     []string
	wgr       sync.WaitGroup
	wgp       sync.WaitGroup
	publisher event.Publisher
)

const (
	// Release version
	Release = "v0.2.0"
)

func init() {
	log.SetLevel(log.InfoLevel)
}

func main() {
	rootCertPath := "/etc/ssl/docker"

	if os.Getenv("DOCKER_CERT_PATH") != "" {
		rootCertPath = os.Getenv("DOCKER_CERT_PATH")
	}

	app := cli.NewApp()
	app.Name = "Tugbot"
	app.Version = Release
	app.Usage = "Tugbot is a continuous testing framework for Docker based environments. Tugbot monitors changes in a runtime environment (host, os, container), runs tests (packaged into Test Containers), when event occured and collects test results."
	app.ArgsUsage = "test containers: name, list of names, or none (for all test containers)"
	app.Before = before
	app.Action = start
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "host, H",
			Usage:  "daemon socket to connect to",
			Value:  "unix:///var/run/docker.sock",
			EnvVar: "DOCKER_HOST",
		},
		cli.BoolFlag{
			Name:  "tls",
			Usage: "use TLS; implied by --tlsverify",
		},
		cli.BoolFlag{
			Name:   "tlsverify",
			Usage:  "use TLS and verify the remote",
			EnvVar: "DOCKER_TLS_VERIFY",
		},
		cli.StringFlag{
			Name:  "tlscacert",
			Usage: "trust certs signed only by this CA",
			Value: fmt.Sprintf("%s/ca.pem", rootCertPath),
		},
		cli.StringFlag{
			Name:  "tlscert",
			Usage: "client certificate for TLS authentication",
			Value: fmt.Sprintf("%s/cert.pem", rootCertPath),
		},
		cli.StringFlag{
			Name:  "tlskey",
			Usage: "client key for TLS authentication",
			Value: fmt.Sprintf("%s/key.pem", rootCertPath),
		},
		cli.BoolFlag{
			Name:  "debug",
			Usage: "enable debug mode with verbose logging",
		},
		cli.StringFlag{
			Name:   "webhooks",
			Usage:  "list of urls sperated by ';'",
			Value:  "http://result-service:8080/events",
			EnvVar: "TUGBOT_WEBHOOKS",
		},
	}

	if err := app.Run(os.Args); err != nil {
		log.Fatal(err)
	}
}

func before(c *cli.Context) error {
	if c.GlobalBool("debug") {
		log.SetLevel(log.DebugLevel)
	}

	// Set-up container client
	tls, err := tlsConfig(c)
	if err != nil {
		return err
	}

	client = container.NewClient(c.GlobalString("host"), tls, !c.GlobalBool("no-pull"))

	return nil
}

func start(c *cli.Context) {
	names = c.Args()
	startMonitorEvents(c)
	log.Info("Tugbot Started OK")
	waitForInterrupt()
}

func startMonitorEvents(c *cli.Context) {
	client.StartMonitorEvents(runTestContainers)
	webhooks := c.GlobalString("webhooks")
	if webhooks != "" {
		publisher = event.NewPublisher(strings.Split(webhooks, ";"))
		client.StartMonitorEvents(publishEvent)
	}
}

func runTestContainers(e *dockerclient.Event, ec chan error, args ...interface{}) {
	wgr.Add(1)
	if err := actions.Run(client, names, e); err != nil {
		log.Error(err)
	}
	wgr.Done()
}

func publishEvent(e *dockerclient.Event, ec chan error, args ...interface{}) {
	wgp.Add(1)
	publisher.Publish(e)
	wgp.Done()
}

func waitForInterrupt() {
	// Graceful shut-down on SIGINT/SIGTERM/SIGQUIT
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT)
	<-c
	log.Debug("Stop monitoring events ...")
	wgr.Wait()
	client.StopAllMonitorEvents()
	log.Debug("Graceful exit :-)")
	os.Exit(1)
}

// tlsConfig translates the command-line options into a tls.Config struct
func tlsConfig(c *cli.Context) (*tls.Config, error) {
	var tlsConfig *tls.Config
	var err error
	caCertFlag := c.GlobalString("tlscacert")
	certFlag := c.GlobalString("tlscert")
	keyFlag := c.GlobalString("tlskey")

	if c.GlobalBool("tls") || c.GlobalBool("tlsverify") {
		tlsConfig = &tls.Config{
			InsecureSkipVerify: !c.GlobalBool("tlsverify"),
		}

		// Load CA cert
		if caCertFlag != "" {
			var caCert []byte

			if strings.HasPrefix(caCertFlag, "/") {
				caCert, err = ioutil.ReadFile(caCertFlag)
				if err != nil {
					return nil, err
				}
			} else {
				caCert = []byte(caCertFlag)
			}

			caCertPool := x509.NewCertPool()
			caCertPool.AppendCertsFromPEM(caCert)

			tlsConfig.RootCAs = caCertPool
		}

		// Load client certificate
		if certFlag != "" && keyFlag != "" {
			var cert tls.Certificate

			if strings.HasPrefix(certFlag, "/") && strings.HasPrefix(keyFlag, "/") {
				cert, err = tls.LoadX509KeyPair(certFlag, keyFlag)
				if err != nil {
					return nil, err
				}
			} else {
				cert, err = tls.X509KeyPair([]byte(certFlag), []byte(keyFlag))
				if err != nil {
					return nil, err
				}
			}
			tlsConfig.Certificates = []tls.Certificate{cert}
		}
	}

	return tlsConfig, nil
}
<|endoftext|>


<commit_before>// Package c2go contains the main function for running the executable.
//
// Installation
//
//     go get -u github.com/elliotchance/c2go
//
// Usage
//
//     c2go myfile.c
//
package main

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

	"errors"

	"github.com/elliotchance/c2go/ast"
	"github.com/elliotchance/c2go/preprocessor"
	"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 = "v0.18.6 Tantalum 2017-12-14"

var stderr io.Writer = os.Stderr

// ProgramArgs defines the options available when processing the program. There
// is no constructor since the zeroed out values are the appropriate defaults -
// you need only set the options you need.
//
// TODO: Better separation on CLI modes
// https://github.com/elliotchance/c2go/issues/134
//
// Do not instantiate this directly. Instead use DefaultProgramArgs(); then
// modify any specific attributes.
type ProgramArgs struct {
	verbose     bool
	ast         bool
	inputFiles  []string
	clangFlags  []string
	outputFile  string
	packageName string

	// A private option to output the Go as a *_test.go file.
	outputAsTest bool
}

// DefaultProgramArgs default value of ProgramArgs
func DefaultProgramArgs() ProgramArgs {
	return ProgramArgs{
		verbose:      false,
		ast:          false,
		packageName:  "main",
		clangFlags:   []string{},
		outputAsTest: false,
	}
}

func readAST(data []byte) []string {
	return strings.Split(string(data), "\n")
}

type treeNode struct {
	indent int
	node   ast.Node
}

func convertLinesToNodes(lines []string) []treeNode {
	nodes := make([]treeNode, len(lines))
	var counter int
	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)
		trimmed := strings.TrimLeft(line, "|\\- `")
		node := ast.Parse(trimmed)
		indentLevel := (len(line) - len(trimmed)) / 2
		nodes[counter] = treeNode{indentLevel, node}
		counter++
	}
	nodes = nodes[0:counter]

	return nodes
}

func convertLinesToNodesParallel(lines []string) []treeNode {
	// function f separate full list on 2 parts and
	// then each part can recursive run function f
	var f func([]string, int) []treeNode

	f = func(lines []string, deep int) []treeNode {
		deep = deep - 2
		part := len(lines) / 2

		var tr1 = make(chan []treeNode)
		var tr2 = make(chan []treeNode)

		go func(lines []string, deep int) {
			if deep <= 0 || len(lines) < deep {
				tr1 <- convertLinesToNodes(lines)
				return
			}
			tr1 <- f(lines, deep)
		}(lines[0:part], deep)

		go func(lines []string, deep int) {
			if deep <= 0 || len(lines) < deep {
				tr2 <- convertLinesToNodes(lines)
				return
			}
			tr2 <- f(lines, deep)
		}(lines[part:], deep)

		defer close(tr1)
		defer close(tr2)

		return append(<-tr1, <-tr2...)
	}

	// Parameter of deep - can be any, but effective to use
	// same amount of CPU
	return f(lines, runtime.NumCPU())
}

// buildTree converts 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 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
}

// Start begins transpiling an input file.
func Start(args ProgramArgs) (err error) {
	if args.verbose {
		fmt.Println("Start tanspiling ...")
	}

	if os.Getenv("GOPATH") == "" {
		return fmt.Errorf("The $GOPATH must be set")
	}

	// 1. Compile it first (checking for errors)
	for _, in := range args.inputFiles {
		_, err := os.Stat(in)
		if err != nil {
			return fmt.Errorf("Input file %s is not found", in)
		}
	}

	// 2. Preprocess
	if args.verbose {
		fmt.Println("Running clang preprocessor...")
	}

	pp, err := preprocessor.Analyze(args.inputFiles, args.clangFlags)
	if err != nil {
		return err
	}

	if args.verbose {
		fmt.Println("Writing preprocessor ...")
	}
	dir, err := ioutil.TempDir("", "c2go")
	if err != nil {
		return fmt.Errorf("Cannot create temp folder: %v", err)
	}
	defer os.RemoveAll(dir) // clean up

	ppFilePath := path.Join(dir, "pp.c")
	err = ioutil.WriteFile(ppFilePath, pp, 0644)
	if err != nil {
		return fmt.Errorf("writing to %s failed: %v", ppFilePath, err)
	}

	// 3. Generate JSON from AST
	if args.verbose {
		fmt.Println("Running clang for AST tree...")
	}
	astPP, err := exec.Command("clang", "-Xclang", "-ast-dump", "-fsyntax-only", "-fno-color-diagnostics", ppFilePath).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", ppFilePath).CombinedOutput()

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

	if args.verbose {
		fmt.Println("Reading clang AST tree...")
	}
	lines := readAST(astPP)
	if args.ast {
		for _, l := range lines {
			fmt.Println(l)
		}
		fmt.Println()

		return nil
	}

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

	// Converting to nodes
	if args.verbose {
		fmt.Println("Converting to nodes...")
	}
	nodes := convertLinesToNodesParallel(lines)

	// build tree
	if args.verbose {
		fmt.Println("Building tree...")
	}
	tree := buildTree(nodes, 0)
	ast.FixPositions(tree)

	// Repair the floating literals. See RepairFloatingLiteralsFromSource for
	// more information.
	floatingErrors := ast.RepairFloatingLiteralsFromSource(tree[0], ppFilePath)

	for _, fErr := range floatingErrors {
		message := fmt.Sprintf("could not read exact floating literal: %s",
			fErr.Err.Error())
		p.AddMessage(p.GenerateWarningMessage(errors.New(message), fErr.Node))
	}

	outputFilePath := args.outputFile

	if outputFilePath == "" {
		// Choose inputFile for creating name of output file
		input := args.inputFiles[0]
		// We choose name for output Go code at the base
		// on filename for choosed input file
		cleanFileName := filepath.Clean(filepath.Base(input))
		extension := filepath.Ext(input)
		outputFilePath = cleanFileName[0:len(cleanFileName)-len(extension)] + ".go"
	}

	// transpile ast tree
	if args.verbose {
		fmt.Println("Transpiling tree...")
	}

	err = transpiler.TranspileAST(args.outputFile, args.packageName, p, tree[0].(ast.Node))
	if err != nil {
		return fmt.Errorf("cannot transpile AST : %v", err)
	}

	// write the output Go code
	if args.verbose {
		fmt.Println("Writing the output Go code...")
	}
	err = ioutil.WriteFile(outputFilePath, []byte(p.String()), 0644)
	if err != nil {
		return fmt.Errorf("writing Go output file failed: %v", err)
	}

	return nil
}

type inputDataFlags []string

func (i *inputDataFlags) String() (s string) {
	for pos, item := range *i {
		s += fmt.Sprintf("Flag %d. %s\n", pos, item)
	}
	return
}

func (i *inputDataFlags) Set(value string) error {
	*i = append(*i, value)
	return nil
}

var clangFlags inputDataFlags

func init() {
	transpileCommand.Var(&clangFlags, "clang-flag", "Pass arguments to clang. You may provide multiple -clang-flag items.")
}

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")
)

func main() {
	code := runCommand()
	if code != 0 {
		os.Exit(code)
	}
}

func runCommand() int {

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

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

	transpileCommand.SetOutput(stderr)
	astCommand.SetOutput(stderr)

	flag.Parse()

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

	if flag.NArg() < 1 {
		flag.Usage()
		return 1
	}

	args := DefaultProgramArgs()

	switch os.Args[1] {
	case "ast":
		err := astCommand.Parse(os.Args[2:])
		if err != nil {
			fmt.Printf("ast command cannot parse: %v", err)
			return 1
		}

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

		args.ast = true
		args.inputFiles = astCommand.Args()
	case "transpile":
		err := transpileCommand.Parse(os.Args[2:])
		if err != nil {
			fmt.Printf("transpile command cannot parse: %v", err)
			return 1
		}

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

		args.inputFiles = transpileCommand.Args()
		args.outputFile = *outputFlag
		args.packageName = *packageFlag
		args.verbose = *verboseFlag
		args.clangFlags = clangFlags
	default:
		flag.Usage()
		return 1
	}

	if err := Start(args); err != nil {
		fmt.Printf("Error: %v\n", err)
		return 1
	}

	return 0
}
<commit_msg>Bump version: v0.18.7 Tantalum 2017-12-18<commit_after>// Package c2go contains the main function for running the executable.
//
// Installation
//
//     go get -u github.com/elliotchance/c2go
//
// Usage
//
//     c2go myfile.c
//
package main

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

	"errors"

	"github.com/elliotchance/c2go/ast"
	"github.com/elliotchance/c2go/preprocessor"
	"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 = "v0.18.7 Tantalum 2017-12-18"

var stderr io.Writer = os.Stderr

// ProgramArgs defines the options available when processing the program. There
// is no constructor since the zeroed out values are the appropriate defaults -
// you need only set the options you need.
//
// TODO: Better separation on CLI modes
// https://github.com/elliotchance/c2go/issues/134
//
// Do not instantiate this directly. Instead use DefaultProgramArgs(); then
// modify any specific attributes.
type ProgramArgs struct {
	verbose     bool
	ast         bool
	inputFiles  []string
	clangFlags  []string
	outputFile  string
	packageName string

	// A private option to output the Go as a *_test.go file.
	outputAsTest bool
}

// DefaultProgramArgs default value of ProgramArgs
func DefaultProgramArgs() ProgramArgs {
	return ProgramArgs{
		verbose:      false,
		ast:          false,
		packageName:  "main",
		clangFlags:   []string{},
		outputAsTest: false,
	}
}

func readAST(data []byte) []string {
	return strings.Split(string(data), "\n")
}

type treeNode struct {
	indent int
	node   ast.Node
}

func convertLinesToNodes(lines []string) []treeNode {
	nodes := make([]treeNode, len(lines))
	var counter int
	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)
		trimmed := strings.TrimLeft(line, "|\\- `")
		node := ast.Parse(trimmed)
		indentLevel := (len(line) - len(trimmed)) / 2
		nodes[counter] = treeNode{indentLevel, node}
		counter++
	}
	nodes = nodes[0:counter]

	return nodes
}

func convertLinesToNodesParallel(lines []string) []treeNode {
	// function f separate full list on 2 parts and
	// then each part can recursive run function f
	var f func([]string, int) []treeNode

	f = func(lines []string, deep int) []treeNode {
		deep = deep - 2
		part := len(lines) / 2

		var tr1 = make(chan []treeNode)
		var tr2 = make(chan []treeNode)

		go func(lines []string, deep int) {
			if deep <= 0 || len(lines) < deep {
				tr1 <- convertLinesToNodes(lines)
				return
			}
			tr1 <- f(lines, deep)
		}(lines[0:part], deep)

		go func(lines []string, deep int) {
			if deep <= 0 || len(lines) < deep {
				tr2 <- convertLinesToNodes(lines)
				return
			}
			tr2 <- f(lines, deep)
		}(lines[part:], deep)

		defer close(tr1)
		defer close(tr2)

		return append(<-tr1, <-tr2...)
	}

	// Parameter of deep - can be any, but effective to use
	// same amount of CPU
	return f(lines, runtime.NumCPU())
}

// buildTree converts 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 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
}

// Start begins transpiling an input file.
func Start(args ProgramArgs) (err error) {
	if args.verbose {
		fmt.Println("Start tanspiling ...")
	}

	if os.Getenv("GOPATH") == "" {
		return fmt.Errorf("The $GOPATH must be set")
	}

	// 1. Compile it first (checking for errors)
	for _, in := range args.inputFiles {
		_, err := os.Stat(in)
		if err != nil {
			return fmt.Errorf("Input file %s is not found", in)
		}
	}

	// 2. Preprocess
	if args.verbose {
		fmt.Println("Running clang preprocessor...")
	}

	pp, err := preprocessor.Analyze(args.inputFiles, args.clangFlags)
	if err != nil {
		return err
	}

	if args.verbose {
		fmt.Println("Writing preprocessor ...")
	}
	dir, err := ioutil.TempDir("", "c2go")
	if err != nil {
		return fmt.Errorf("Cannot create temp folder: %v", err)
	}
	defer os.RemoveAll(dir) // clean up

	ppFilePath := path.Join(dir, "pp.c")
	err = ioutil.WriteFile(ppFilePath, pp, 0644)
	if err != nil {
		return fmt.Errorf("writing to %s failed: %v", ppFilePath, err)
	}

	// 3. Generate JSON from AST
	if args.verbose {
		fmt.Println("Running clang for AST tree...")
	}
	astPP, err := exec.Command("clang", "-Xclang", "-ast-dump", "-fsyntax-only", "-fno-color-diagnostics", ppFilePath).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", ppFilePath).CombinedOutput()

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

	if args.verbose {
		fmt.Println("Reading clang AST tree...")
	}
	lines := readAST(astPP)
	if args.ast {
		for _, l := range lines {
			fmt.Println(l)
		}
		fmt.Println()

		return nil
	}

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

	// Converting to nodes
	if args.verbose {
		fmt.Println("Converting to nodes...")
	}
	nodes := convertLinesToNodesParallel(lines)

	// build tree
	if args.verbose {
		fmt.Println("Building tree...")
	}
	tree := buildTree(nodes, 0)
	ast.FixPositions(tree)

	// Repair the floating literals. See RepairFloatingLiteralsFromSource for
	// more information.
	floatingErrors := ast.RepairFloatingLiteralsFromSource(tree[0], ppFilePath)

	for _, fErr := range floatingErrors {
		message := fmt.Sprintf("could not read exact floating literal: %s",
			fErr.Err.Error())
		p.AddMessage(p.GenerateWarningMessage(errors.New(message), fErr.Node))
	}

	outputFilePath := args.outputFile

	if outputFilePath == "" {
		// Choose inputFile for creating name of output file
		input := args.inputFiles[0]
		// We choose name for output Go code at the base
		// on filename for choosed input file
		cleanFileName := filepath.Clean(filepath.Base(input))
		extension := filepath.Ext(input)
		outputFilePath = cleanFileName[0:len(cleanFileName)-len(extension)] + ".go"
	}

	// transpile ast tree
	if args.verbose {
		fmt.Println("Transpiling tree...")
	}

	err = transpiler.TranspileAST(args.outputFile, args.packageName, p, tree[0].(ast.Node))
	if err != nil {
		return fmt.Errorf("cannot transpile AST : %v", err)
	}

	// write the output Go code
	if args.verbose {
		fmt.Println("Writing the output Go code...")
	}
	err = ioutil.WriteFile(outputFilePath, []byte(p.String()), 0644)
	if err != nil {
		return fmt.Errorf("writing Go output file failed: %v", err)
	}

	return nil
}

type inputDataFlags []string

func (i *inputDataFlags) String() (s string) {
	for pos, item := range *i {
		s += fmt.Sprintf("Flag %d. %s\n", pos, item)
	}
	return
}

func (i *inputDataFlags) Set(value string) error {
	*i = append(*i, value)
	return nil
}

var clangFlags inputDataFlags

func init() {
	transpileCommand.Var(&clangFlags, "clang-flag", "Pass arguments to clang. You may provide multiple -clang-flag items.")
}

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")
)

func main() {
	code := runCommand()
	if code != 0 {
		os.Exit(code)
	}
}

func runCommand() int {

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

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

	transpileCommand.SetOutput(stderr)
	astCommand.SetOutput(stderr)

	flag.Parse()

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

	if flag.NArg() < 1 {
		flag.Usage()
		return 1
	}

	args := DefaultProgramArgs()

	switch os.Args[1] {
	case "ast":
		err := astCommand.Parse(os.Args[2:])
		if err != nil {
			fmt.Printf("ast command cannot parse: %v", err)
			return 1
		}

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

		args.ast = true
		args.inputFiles = astCommand.Args()
	case "transpile":
		err := transpileCommand.Parse(os.Args[2:])
		if err != nil {
			fmt.Printf("transpile command cannot parse: %v", err)
			return 1
		}

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

		args.inputFiles = transpileCommand.Args()
		args.outputFile = *outputFlag
		args.packageName = *packageFlag
		args.verbose = *verboseFlag
		args.clangFlags = clangFlags
	default:
		flag.Usage()
		return 1
	}

	if err := Start(args); err != nil {
		fmt.Printf("Error: %v\n", err)
		return 1
	}

	return 0
}
<|endoftext|>


<commit_before>/**
 * @file main.go
 * @author Mikhail Klementyev jollheef<AT>riseup.net
 * @license GNU AGPLv3
 * @date October, 2015
 * @brief task-based ctf daemon
 *
 * Entry point for task-based ctf daemon
 */

package main

import (
	"database/sql"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"syscall"
	"time"

	"github.com/jollheef/henhouse/config"
	"github.com/jollheef/henhouse/db"
	"github.com/jollheef/henhouse/game"
	"github.com/jollheef/henhouse/scoreboard"
	kingpin "gopkg.in/alecthomas/kingpin.v2"
)

var (
	configPath = kingpin.Arg("config",
		"Path to configuration file.").Required().String()

	dbReinit = kingpin.Flag("reinit", "Reinit database.").Bool()
)

var (
	// CommitID fill in ./build.sh
	CommitID string
	// BuildDate fill in ./build.sh
	BuildDate string
	// BuildTime fill in ./build.sh
	BuildTime string
)

func checkTaskNameEn(task *config.Task){
	if task.NameEn == "" {
		task.NameEn = task.Name
	}
	return
}

func checkTaskName(task *config.Task){
	if task.Name == "" {
		task.Name = task.NameEn
	}
	return
}

func checkTaskDescriptionEn(task *config.Task){
	if task.DescriptionEn == "" {
		task.DescriptionEn = task.Description
	}
	return
}

func checkTaskDescriprion(task *config.Task){
	if task.Description == "" {
		task.Description = task.DescriptionEn
	}
	return
}

func reinitDatabase(database *sql.DB, cfg config.Config) (err error) {
	log.Println("Reinit database")

	for _, team := range cfg.Teams {
		log.Println("Add team", team.Name)
		err = db.AddTeam(database, &db.Team{
			Name:  team.Name,
			Desc:  team.Description,
			Token: team.Token,
			Test:  team.Test,
		})
		if err != nil {
			return
		}
	}

	entries, err := ioutil.ReadDir(cfg.TaskDir)
	if err != nil {
		return
	}

	var categories []db.Category

	for _, entry := range entries {

		if entry.IsDir() {
			continue
		}

		var content []byte
		content, err = ioutil.ReadFile(cfg.TaskDir + "/" +
			entry.Name())
		if err != nil {
			return
		}

		var task config.Task
		task, err = config.ParseXMLTask(content)
		if err != nil {
			return
		}

		var finded bool
		var taskCategory db.Category
		for _, cat := range categories {
			if cat.Name == task.Category {
				finded = true
				taskCategory = cat
				break
			}
		}

		if !finded {
			taskCategory.Name = task.Category

			err = db.AddCategory(database, &taskCategory)
			if err != nil {
				return
			}

			categories = append(categories, taskCategory)

			log.Println("Add category", taskCategory.Name)
		}

		checkTaskNameEn(&task)

		checkTaskName(&task)

		checkTaskDescriptionEn(&task)

		checkTaskDescriprion(&task)

		err = db.AddTask(database, &db.Task{
			Name:          task.Name,
			Desc:          task.Description,
			NameEn:        task.NameEn,
			DescEn:        task.DescriptionEn,
			Tags:          task.Tags,
			CategoryID:    taskCategory.ID,
			Level:         task.Level,
			Flag:          task.Flag,
			Price:         500,   // TODO support non-shared task
			Shared:        true,  // TODO support non-shared task
			MaxSharePrice: 500,   // TODO support value from xml
			MinSharePrice: 100,   // TODO support value from xml
			Opened:        false, // by default task is closed
			Author:        task.Author,
			ForceClosed:   task.ForceClosed,
		})

		log.Println("Add task", task.Name)

		if err != nil {
			return
		}
	}

	return
}

func checkTaskPrices(cfg *config.Config)(err error){
	if cfg.TaskPrice.P200 == 0 || cfg.TaskPrice.P300 == 0 ||
		cfg.TaskPrice.P400 == 0 || cfg.TaskPrice.P500 == 0 {
		err = errors.New("Error: Task price not setted")
	}
	return
}

func initGame(database *sql.DB, cfg config.Config) (err error) {

	var teamBase float64

	if cfg.TaskPrice.UseNonLinear {
		teamBase, err = game.CalcTeamsBase(database)
		if err != nil {
			return
		}
		log.Println("Use teams amount based on session counter")
	} else if cfg.TaskPrice.UseTeamsBase {
		teamBase = float64(cfg.TaskPrice.TeamsBase)
		log.Println("Set teams base to", cfg.TaskPrice.TeamsBase)
	} else {
		teamBase = float64(len(cfg.Teams))
		log.Println("Use teams amount as teams base")
	}

	log.Println("Start game at", cfg.Game.Start.Time)
	log.Println("End game at", cfg.Game.End.Time)
	g, err := game.NewGame(database, cfg.Game.Start.Time,
		cfg.Game.End.Time, teamBase)
	if err != nil {
		return
	}

	if cfg.TaskPrice.UseNonLinear {
		go g.TeamsBaseUpdater(database,
			cfg.Scoreboard.RecalcTimeout.Duration)
	}

	err = checkTaskPrices(&cfg)
	if err != nil{
		return
	}

	fmt := "Set task price %d if solved less than %d%%\n"
	log.Printf(fmt, 200, cfg.TaskPrice.P200)
	log.Printf(fmt, 300, cfg.TaskPrice.P300)
	log.Printf(fmt, 400, cfg.TaskPrice.P400)
	log.Printf(fmt, 500, cfg.TaskPrice.P500)

	g.SetTaskPrice(cfg.TaskPrice.P500, cfg.TaskPrice.P400,
		cfg.TaskPrice.P300, cfg.TaskPrice.P200)

	log.Println("Set task open timeout to", cfg.Task.OpenTimeout.Duration)
	g.OpenTimeout = cfg.Task.OpenTimeout.Duration

	if cfg.Task.AutoOpen {
		log.Println("Auto open tasks after",
			cfg.Task.AutoOpenTimeout.Duration)
	} else {
		log.Println("Auto open tasks disabled")
	}

	g.AutoOpen = cfg.Task.AutoOpen
	g.AutoOpenTimeout = cfg.Task.AutoOpenTimeout.Duration

	go g.Run()

	infoD := cfg.WebsocketTimeout.Info.Duration
	if infoD != 0 {
		scoreboard.InfoTimeout = infoD
	}
	log.Println("Update info timeout:", scoreboard.InfoTimeout)

	scoreboardD := cfg.WebsocketTimeout.Scoreboard.Duration
	if scoreboardD != 0 {
		scoreboard.ScoreboardTimeout = scoreboardD
	}
	log.Println("Update scoreboard timeout:", scoreboard.ScoreboardTimeout)

	tasksD := cfg.WebsocketTimeout.Tasks.Duration
	if tasksD != 0 {
		scoreboard.TasksTimeout = tasksD
	}
	log.Println("Update tasks timeout:", scoreboard.TasksTimeout)

	flagSendD := cfg.Flag.SendTimeout.Duration
	if flagSendD != 0 {
		scoreboard.FlagTimeout = flagSendD
	}
	log.Println("Flag timeout:", scoreboard.FlagTimeout)

	scoreboardRecalcD := cfg.Scoreboard.RecalcTimeout.Duration
	if scoreboardRecalcD != 0 {
		scoreboard.ScoreboardRecalcTimeout = scoreboardRecalcD
	}

	log.Println("Score recalc timeout:", scoreboard.ScoreboardRecalcTimeout)

	log.Println("Use html files from", cfg.Scoreboard.WwwPath)
	log.Println("Listen at", cfg.Scoreboard.Addr)
	err = scoreboard.Scoreboard(database, &g,
		cfg.Scoreboard.WwwPath,
		cfg.Scoreboard.TemplatePath,
		cfg.Scoreboard.Addr)

	return
}

func main() {

	if len(CommitID) > 7 {
		CommitID = CommitID[:7] // abbreviated commit hash
	}

	version := BuildDate + " " + CommitID +
		" (Mikhail Klementyev <jollheef@riseup.net>)"

	kingpin.Version(version)

	kingpin.Parse()

	fmt.Println(version)

	cfg, err := config.ReadConfig(*configPath)
	if err != nil {
		log.Fatalln("Cannot open config:", err)
	}

	logFile, err := os.OpenFile(cfg.LogFile,
		os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		log.Fatalln("Cannot open file:", err)
	}
	defer logFile.Close()
	log.SetOutput(logFile)

	log.Println(version)

	var rlim syscall.Rlimit
	err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlim)
	if err != nil {
		log.Fatalln("Getrlimit fail:", err)
	}

	log.Println("RLIMIT_NOFILE CUR:", rlim.Cur, "MAX:", rlim.Max)

	var database *sql.DB

	if *dbReinit {

		if cfg.Database.SafeReinit {
			if time.Now().After(cfg.Game.Start.Time) {
				log.Fatalln("Reinit after start not allowed")
			}
		}

		database, err = db.InitDatabase(cfg.Database.Connection)
		if err != nil {
			log.Fatalln("Error:", err)
		}

		err = db.CleanDatabase(database)
		if err != nil {
			log.Fatalln("Error:", err)
		}

		defer database.Close()

		err = reinitDatabase(database, cfg)
		if err != nil {
			log.Fatalln("Error:", err)
		}

	} else {

		database, err = db.OpenDatabase(cfg.Database.Connection)
		if err != nil {
			log.Fatalln("Error:", err)
		}

		defer database.Close()
	}

	log.Println("Set max db connections to", cfg.Database.MaxConnections)
	database.SetMaxOpenConns(cfg.Database.MaxConnections)

	err = initGame(database, cfg)
	if err != nil {
		log.Fatalln("Error:", err)
	}
}
<commit_msg>add fillTranslateFallback<commit_after>/**
 * @file main.go
 * @author Mikhail Klementyev jollheef<AT>riseup.net
 * @license GNU AGPLv3
 * @date October, 2015
 * @brief task-based ctf daemon
 *
 * Entry point for task-based ctf daemon
 */

package main

import (
	"database/sql"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"syscall"
	"time"

	"github.com/jollheef/henhouse/config"
	"github.com/jollheef/henhouse/db"
	"github.com/jollheef/henhouse/game"
	"github.com/jollheef/henhouse/scoreboard"
	kingpin "gopkg.in/alecthomas/kingpin.v2"
)

var (
	configPath = kingpin.Arg("config",
		"Path to configuration file.").Required().String()

	dbReinit = kingpin.Flag("reinit", "Reinit database.").Bool()
)

var (
	// CommitID fill in ./build.sh
	CommitID string
	// BuildDate fill in ./build.sh
	BuildDate string
	// BuildTime fill in ./build.sh
	BuildTime string
)

func fillTranslateFallback(task * config.Task) {
	if task.NameEn == "" {
		task.NameEn = task.Name
	}
	if task.Name == "" {
		task.Name = task.NameEn
	}
	if task.DescriptionEn == "" {
		task.DescriptionEn = task.Description
	}
	if task.Description == "" {
		task.Description = task.DescriptionEn
	}
	return
}

func reinitDatabase(database *sql.DB, cfg config.Config) (err error) {
	log.Println("Reinit database")

	for _, team := range cfg.Teams {
		log.Println("Add team", team.Name)
		err = db.AddTeam(database, &db.Team{
			Name:  team.Name,
			Desc:  team.Description,
			Token: team.Token,
			Test:  team.Test,
		})
		if err != nil {
			return
		}
	}

	entries, err := ioutil.ReadDir(cfg.TaskDir)
	if err != nil {
		return
	}

	var categories []db.Category

	for _, entry := range entries {

		if entry.IsDir() {
			continue
		}

		var content []byte
		content, err = ioutil.ReadFile(cfg.TaskDir + "/" +
			entry.Name())
		if err != nil {
			return
		}

		var task config.Task
		task, err = config.ParseXMLTask(content)
		if err != nil {
			return
		}

		var finded bool
		var taskCategory db.Category
		for _, cat := range categories {
			if cat.Name == task.Category {
				finded = true
				taskCategory = cat
				break
			}
		}

		if !finded {
			taskCategory.Name = task.Category

			err = db.AddCategory(database, &taskCategory)
			if err != nil {
				return
			}

			categories = append(categories, taskCategory)

			log.Println("Add category", taskCategory.Name)
		}

		fillTranslateFallback(&task)

		err = db.AddTask(database, &db.Task{
			Name:          task.Name,
			Desc:          task.Description,
			NameEn:        task.NameEn,
			DescEn:        task.DescriptionEn,
			Tags:          task.Tags,
			CategoryID:    taskCategory.ID,
			Level:         task.Level,
			Flag:          task.Flag,
			Price:         500,   // TODO support non-shared task
			Shared:        true,  // TODO support non-shared task
			MaxSharePrice: 500,   // TODO support value from xml
			MinSharePrice: 100,   // TODO support value from xml
			Opened:        false, // by default task is closed
			Author:        task.Author,
			ForceClosed:   task.ForceClosed,
		})

		log.Println("Add task", task.Name)

		if err != nil {
			return
		}
	}

	return
}

func checkTaskPrices(cfg *config.Config)(err error){
	if cfg.TaskPrice.P200 == 0 || cfg.TaskPrice.P300 == 0 ||
		cfg.TaskPrice.P400 == 0 || cfg.TaskPrice.P500 == 0 {
		err = errors.New("Error: Task price not setted")
	}
	return
}

func initGame(database *sql.DB, cfg config.Config) (err error) {

	var teamBase float64

	if cfg.TaskPrice.UseNonLinear {
		teamBase, err = game.CalcTeamsBase(database)
		if err != nil {
			return
		}
		log.Println("Use teams amount based on session counter")
	} else if cfg.TaskPrice.UseTeamsBase {
		teamBase = float64(cfg.TaskPrice.TeamsBase)
		log.Println("Set teams base to", cfg.TaskPrice.TeamsBase)
	} else {
		teamBase = float64(len(cfg.Teams))
		log.Println("Use teams amount as teams base")
	}

	log.Println("Start game at", cfg.Game.Start.Time)
	log.Println("End game at", cfg.Game.End.Time)
	g, err := game.NewGame(database, cfg.Game.Start.Time,
		cfg.Game.End.Time, teamBase)
	if err != nil {
		return
	}

	if cfg.TaskPrice.UseNonLinear {
		go g.TeamsBaseUpdater(database,
			cfg.Scoreboard.RecalcTimeout.Duration)
	}

	err = checkTaskPrices(&cfg)
	if err != nil{
		return
	}

	fmt := "Set task price %d if solved less than %d%%\n"
	log.Printf(fmt, 200, cfg.TaskPrice.P200)
	log.Printf(fmt, 300, cfg.TaskPrice.P300)
	log.Printf(fmt, 400, cfg.TaskPrice.P400)
	log.Printf(fmt, 500, cfg.TaskPrice.P500)

	g.SetTaskPrice(cfg.TaskPrice.P500, cfg.TaskPrice.P400,
		cfg.TaskPrice.P300, cfg.TaskPrice.P200)

	log.Println("Set task open timeout to", cfg.Task.OpenTimeout.Duration)
	g.OpenTimeout = cfg.Task.OpenTimeout.Duration

	if cfg.Task.AutoOpen {
		log.Println("Auto open tasks after",
			cfg.Task.AutoOpenTimeout.Duration)
	} else {
		log.Println("Auto open tasks disabled")
	}

	g.AutoOpen = cfg.Task.AutoOpen
	g.AutoOpenTimeout = cfg.Task.AutoOpenTimeout.Duration

	go g.Run()

	infoD := cfg.WebsocketTimeout.Info.Duration
	if infoD != 0 {
		scoreboard.InfoTimeout = infoD
	}
	log.Println("Update info timeout:", scoreboard.InfoTimeout)

	scoreboardD := cfg.WebsocketTimeout.Scoreboard.Duration
	if scoreboardD != 0 {
		scoreboard.ScoreboardTimeout = scoreboardD
	}
	log.Println("Update scoreboard timeout:", scoreboard.ScoreboardTimeout)

	tasksD := cfg.WebsocketTimeout.Tasks.Duration
	if tasksD != 0 {
		scoreboard.TasksTimeout = tasksD
	}
	log.Println("Update tasks timeout:", scoreboard.TasksTimeout)

	flagSendD := cfg.Flag.SendTimeout.Duration
	if flagSendD != 0 {
		scoreboard.FlagTimeout = flagSendD
	}
	log.Println("Flag timeout:", scoreboard.FlagTimeout)

	scoreboardRecalcD := cfg.Scoreboard.RecalcTimeout.Duration
	if scoreboardRecalcD != 0 {
		scoreboard.ScoreboardRecalcTimeout = scoreboardRecalcD
	}

	log.Println("Score recalc timeout:", scoreboard.ScoreboardRecalcTimeout)

	log.Println("Use html files from", cfg.Scoreboard.WwwPath)
	log.Println("Listen at", cfg.Scoreboard.Addr)
	err = scoreboard.Scoreboard(database, &g,
		cfg.Scoreboard.WwwPath,
		cfg.Scoreboard.TemplatePath,
		cfg.Scoreboard.Addr)

	return
}

func main() {

	if len(CommitID) > 7 {
		CommitID = CommitID[:7] // abbreviated commit hash
	}

	version := BuildDate + " " + CommitID +
		" (Mikhail Klementyev <jollheef@riseup.net>)"

	kingpin.Version(version)

	kingpin.Parse()

	fmt.Println(version)

	cfg, err := config.ReadConfig(*configPath)
	if err != nil {
		log.Fatalln("Cannot open config:", err)
	}

	logFile, err := os.OpenFile(cfg.LogFile,
		os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		log.Fatalln("Cannot open file:", err)
	}
	defer logFile.Close()
	log.SetOutput(logFile)

	log.Println(version)

	var rlim syscall.Rlimit
	err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlim)
	if err != nil {
		log.Fatalln("Getrlimit fail:", err)
	}

	log.Println("RLIMIT_NOFILE CUR:", rlim.Cur, "MAX:", rlim.Max)

	var database *sql.DB

	if *dbReinit {

		if cfg.Database.SafeReinit {
			if time.Now().After(cfg.Game.Start.Time) {
				log.Fatalln("Reinit after start not allowed")
			}
		}

		database, err = db.InitDatabase(cfg.Database.Connection)
		if err != nil {
			log.Fatalln("Error:", err)
		}

		err = db.CleanDatabase(database)
		if err != nil {
			log.Fatalln("Error:", err)
		}

		defer database.Close()

		err = reinitDatabase(database, cfg)
		if err != nil {
			log.Fatalln("Error:", err)
		}

	} else {

		database, err = db.OpenDatabase(cfg.Database.Connection)
		if err != nil {
			log.Fatalln("Error:", err)
		}

		defer database.Close()
	}

	log.Println("Set max db connections to", cfg.Database.MaxConnections)
	database.SetMaxOpenConns(cfg.Database.MaxConnections)

	err = initGame(database, cfg)
	if err != nil {
		log.Fatalln("Error:", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
)

var (
	Version = "0.0.6"
	GitHash = "NO GIT HASH"
)

var (
	inFileFlag = flag.String("in", "", "Input file")
	outDirFlag = flag.String("out", "", "Output directory")
)

func printFlagUsageAndExit() {
	flag.Usage()
	os.Exit(2)
}

type generatedSingleEntityFiles struct {
	SchemaCreate            []byte
	Entity                  []byte
	EntityHelpers           []byte
	Iterator                []byte
	Repository              []byte
	StatementBuilderFactory []byte
}

func generateSingleEntityFiles(entity *GeneratorEntity, packageName string) (generated *generatedSingleEntityFiles, err error) {
	defer handleDeferAndSetError(&err)

	generated = &generatedSingleEntityFiles{
		SchemaCreate:            NewAppender().AppendSchemaCreate(entity).AsGoFile(packageName),
		Entity:                  NewAppender().AppendEntityStructs(entity).AsGoFile(packageName),
		EntityHelpers:           NewAppender().AppendEntityHelpers(entity).AsGoFile(packageName),
		Iterator:                NewAppender().AppendEntityIterators(entity).AsGoFile(packageName),
		Repository:              NewAppender().AppendRepoInterface(entity).AsGoFile(packageName),
		StatementBuilderFactory: NewAppender().AppendStatementBuilderFactory(entity).AsGoFile(packageName),
	}
	err = nil
	return
}

type generatedMultipleEntityFiles struct {
	RepositoryFactory         []byte
	StatementBuilderFactories []byte
}

func generateMultipleEntityFiles(generatorSetup *GeneratorSetup, packageName string) (generated *generatedMultipleEntityFiles, err error) {
	defer handleDeferAndSetError(&err)

	generated = &generatedMultipleEntityFiles{
		RepositoryFactory:         NewAppender().AppendRepositoryFactories(generatorSetup).AsGoFile(packageName),
		StatementBuilderFactories: NewAppender().AppendStatementBuilderFactories(generatorSetup).AsGoFile(packageName),
	}
	err = nil
	return
}

func main() {
	flag.Parse()
	fmt.Println(fmt.Sprintf("Running version '%s' and git hash '%s'", Version, GitHash))

	if len(*inFileFlag) == 0 ||
		len(*outDirFlag) == 0 {

		printFlagUsageAndExit()
	}

	generatorSetup, err := LoadGeneratorSetup(*inFileFlag)
	if err != nil {
		log.Fatal(err)
	}

	outFileDirNameOnly := filepath.Base(*outDirFlag)
	packageName := outFileDirNameOnly

	type fileToWrite struct {
		FilePath string
		Content  []byte
	}
	var filesToWrite []*fileToWrite

	for _, entity := range generatorSetup.Entities {
		generated, err := generateSingleEntityFiles(entity, packageName)
		if err != nil {
			log.Fatal(err)
		}

		filesToWrite = append(filesToWrite,
			&fileToWrite{FilePath: filepath.Join(*outDirFlag, entity.EntityName+"_schema_create.go"), Content: generated.SchemaCreate},
			&fileToWrite{FilePath: filepath.Join(*outDirFlag, entity.EntityName+"_entity.go"), Content: generated.Entity},
			&fileToWrite{FilePath: filepath.Join(*outDirFlag, entity.EntityName+"_helpers.go"), Content: generated.EntityHelpers},
			&fileToWrite{FilePath: filepath.Join(*outDirFlag, entity.EntityName+"_iterator.go"), Content: generated.Iterator},
			&fileToWrite{FilePath: filepath.Join(*outDirFlag, entity.EntityName+"_repository.go"), Content: generated.Repository},
			&fileToWrite{FilePath: filepath.Join(*outDirFlag, entity.EntityName+"_stmt_bldr_factory.go"), Content: generated.StatementBuilderFactory},
		)
	}

	generatedMultiEntity, err := generateMultipleEntityFiles(generatorSetup, packageName)
	if err != nil {
		log.Fatal(err)
	}
	filesToWrite = append(filesToWrite,
		&fileToWrite{FilePath: filepath.Join(*outDirFlag, "repository_factory.go"), Content: generatedMultiEntity.RepositoryFactory},
		&fileToWrite{FilePath: filepath.Join(*outDirFlag, "statement_builder_factories.go"), Content: generatedMultiEntity.StatementBuilderFactories},
	)

	for _, f := range filesToWrite {
		err = ioutil.WriteFile(f.FilePath, f.Content, 0655)
		if err != nil {
			log.Fatal(err)
		}
	}
}
<commit_msg>chore: bump version to 0.0.7<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
)

var (
	Version = "0.0.7"
	GitHash = "NO GIT HASH"
)

var (
	inFileFlag = flag.String("in", "", "Input file")
	outDirFlag = flag.String("out", "", "Output directory")
)

func printFlagUsageAndExit() {
	flag.Usage()
	os.Exit(2)
}

type generatedSingleEntityFiles struct {
	SchemaCreate            []byte
	Entity                  []byte
	EntityHelpers           []byte
	Iterator                []byte
	Repository              []byte
	StatementBuilderFactory []byte
}

func generateSingleEntityFiles(entity *GeneratorEntity, packageName string) (generated *generatedSingleEntityFiles, err error) {
	defer handleDeferAndSetError(&err)

	generated = &generatedSingleEntityFiles{
		SchemaCreate:            NewAppender().AppendSchemaCreate(entity).AsGoFile(packageName),
		Entity:                  NewAppender().AppendEntityStructs(entity).AsGoFile(packageName),
		EntityHelpers:           NewAppender().AppendEntityHelpers(entity).AsGoFile(packageName),
		Iterator:                NewAppender().AppendEntityIterators(entity).AsGoFile(packageName),
		Repository:              NewAppender().AppendRepoInterface(entity).AsGoFile(packageName),
		StatementBuilderFactory: NewAppender().AppendStatementBuilderFactory(entity).AsGoFile(packageName),
	}
	err = nil
	return
}

type generatedMultipleEntityFiles struct {
	RepositoryFactory         []byte
	StatementBuilderFactories []byte
}

func generateMultipleEntityFiles(generatorSetup *GeneratorSetup, packageName string) (generated *generatedMultipleEntityFiles, err error) {
	defer handleDeferAndSetError(&err)

	generated = &generatedMultipleEntityFiles{
		RepositoryFactory:         NewAppender().AppendRepositoryFactories(generatorSetup).AsGoFile(packageName),
		StatementBuilderFactories: NewAppender().AppendStatementBuilderFactories(generatorSetup).AsGoFile(packageName),
	}
	err = nil
	return
}

func main() {
	flag.Parse()
	fmt.Println(fmt.Sprintf("Running version '%s' and git hash '%s'", Version, GitHash))

	if len(*inFileFlag) == 0 ||
		len(*outDirFlag) == 0 {

		printFlagUsageAndExit()
	}

	generatorSetup, err := LoadGeneratorSetup(*inFileFlag)
	if err != nil {
		log.Fatal(err)
	}

	outFileDirNameOnly := filepath.Base(*outDirFlag)
	packageName := outFileDirNameOnly

	type fileToWrite struct {
		FilePath string
		Content  []byte
	}
	var filesToWrite []*fileToWrite

	for _, entity := range generatorSetup.Entities {
		generated, err := generateSingleEntityFiles(entity, packageName)
		if err != nil {
			log.Fatal(err)
		}

		filesToWrite = append(filesToWrite,
			&fileToWrite{FilePath: filepath.Join(*outDirFlag, entity.EntityName+"_schema_create.go"), Content: generated.SchemaCreate},
			&fileToWrite{FilePath: filepath.Join(*outDirFlag, entity.EntityName+"_entity.go"), Content: generated.Entity},
			&fileToWrite{FilePath: filepath.Join(*outDirFlag, entity.EntityName+"_helpers.go"), Content: generated.EntityHelpers},
			&fileToWrite{FilePath: filepath.Join(*outDirFlag, entity.EntityName+"_iterator.go"), Content: generated.Iterator},
			&fileToWrite{FilePath: filepath.Join(*outDirFlag, entity.EntityName+"_repository.go"), Content: generated.Repository},
			&fileToWrite{FilePath: filepath.Join(*outDirFlag, entity.EntityName+"_stmt_bldr_factory.go"), Content: generated.StatementBuilderFactory},
		)
	}

	generatedMultiEntity, err := generateMultipleEntityFiles(generatorSetup, packageName)
	if err != nil {
		log.Fatal(err)
	}
	filesToWrite = append(filesToWrite,
		&fileToWrite{FilePath: filepath.Join(*outDirFlag, "repository_factory.go"), Content: generatedMultiEntity.RepositoryFactory},
		&fileToWrite{FilePath: filepath.Join(*outDirFlag, "statement_builder_factories.go"), Content: generatedMultiEntity.StatementBuilderFactories},
	)

	for _, f := range filesToWrite {
		err = ioutil.WriteFile(f.FilePath, f.Content, 0655)
		if err != nil {
			log.Fatal(err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"
)

// nagios exit codes
const (
	OK = iota
	WARNING
	CRITICAL
	UNKNOWN
)

// export NCG2=debug
const DEBUG = "NCG2"

// license information
const (
        author = "Antonino Catinello"
        license = "BSD"
        year = "2016"
        copyright = "\u00A9"
)

var (
	// command line arguments
	link *string
	user *string
	pass *string
	version *bool
	// using ssl to avoid name conflict with tls
	ssl *bool
	// env debugging variable
	debug string
	// performence data
	pdata string
	// version value
	id string
)

// handle performence data output
func perf(elapsed, total, inputs, tput, index float64) {
	pdata = fmt.Sprintf("time=%f;;;; total=%.f;;;; sources=%.f;;;; throughput=%.f;;;; index_failures=%.f;;;;", elapsed, total, inputs, tput, index)
}

// handle args
func init() {
	link = flag.String("l", "http://localhost:12900", "Graylog2 API URL")
	user = flag.String("u", "", "API username")
	pass = flag.String("p", "", "API password")
	ssl = flag.Bool("insecure", false, "Accept insecure SSL/TLS certificates.")
	version = flag.Bool("version", false, "Display version and license information.")
	debug = os.Getenv(DEBUG)
	perf(0, 0, 0, 0, 0)
}

// return nagios codes on quit
func quit(status int, message string, err error) {
	var ev string

	switch status {
	case OK:
		ev = "OK"
	case WARNING:
		ev = "WARNING"
	case CRITICAL:
		ev = "CRITICAL"
	case UNKNOWN:
		ev = "UNKNOWN"
	}

	// if debugging is enabled
	// print errors
	if len(debug) != 0 {
		fmt.Println(err)
	}

	fmt.Printf("%s - %s|%s\n", ev, message, pdata)
	os.Exit(status)
}

// parse link
func parse(link *string) string {
	l, err := url.Parse(*link)
	if err != nil {
		quit(UNKNOWN, "Can not parse given URL.", err)
	}

	if !strings.Contains(l.Host, ":") {
		quit(UNKNOWN, "Port number is missing. Try "+l.Scheme+"://hostname:port", err)
	}

	if !strings.HasPrefix(l.Scheme, "HTTP") && !strings.HasPrefix(l.Scheme, "http") {
		quit(UNKNOWN, "Only HTTP is supported as protocol.", err)
	}

	return l.Scheme + "://" + l.Host
}

func main() {
	flag.Parse()

	if *version {
		fmt.Printf("Version: %v License: %v %v %v %v\n", id, license, copyright, year, author)
		os.Exit(3)
	}

	if len(*user) == 0 || len(*pass) == 0 {
		flag.PrintDefaults()
		os.Exit(3)
	}

	c := parse(link)
	start := time.Now()

	system := query(c+"/system", *user, *pass)
	if system["is_processing"].(bool) != true {
		quit(CRITICAL, "Service is not processing!", nil)
	}
	if strings.Compare(system["lifecycle"].(string), "running") != 0 {
		quit(WARNING, fmt.Sprintf("lifecycle: %v", system["lifecycle"].(string)), nil)
	}
	if strings.Compare(system["lb_status"].(string), "alive") != 0 {
		quit(WARNING, fmt.Sprintf("lb_status: %v", system["lb_status"].(string)), nil)
	}

	index := query(c+"/system/indexer/failures", *user, *pass)
	tput := query(c+"/system/throughput", *user, *pass)
	inputs := query(c+"/system/inputs", *user, *pass)
	total := query(c+"/count/total", *user, *pass)

	elapsed := time.Since(start)

	perf(elapsed.Seconds(), total["events"].(float64), inputs["total"].(float64), tput["throughput"].(float64), index["total"].(float64))
	quit(OK, fmt.Sprintf("Service is running!\n%.f total events processed\n%.f index failures\n%.f throughput\n%.f sources\nCheck took %v",
		total["events"].(float64), index["total"].(float64), tput["throughput"].(float64), inputs["total"].(float64), elapsed), nil)
}

// call Graylog2 HTTP API
func query(target string, user string, pass string) map[string]interface{} {
	var client *http.Client
	var data map[string]interface{}

	if *ssl {
		tp := &http.Transport{
			// keep this necessary evil for internal servers with custom certs?
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		}

		client = &http.Client{Transport: tp}
	} else {
		client = &http.Client{}
	}

	req, err := http.NewRequest("GET", target, nil)
	req.SetBasicAuth(user, pass)

	res, err := client.Do(req)
	if err != nil {
		quit(CRITICAL, "Can not connect to Graylog2 API", err)
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		quit(CRITICAL, "No response received from Graylog2 API", err)
	}

	if len(debug) != 0 {
		fmt.Println(string(body))
	}

	err = json.Unmarshal(body, &data)
	if err != nil {
		quit(UNKNOWN, "Can not parse JSON from Graylog2 API", err)
	}

	if res.StatusCode != 200 {
		quit(CRITICAL, fmt.Sprintf("Graylog2 API replied with HTTP code %v", res.StatusCode), err)
	}

	return data
}
<commit_msg>set "Accept: application/json" header to work with the api endpoint<commit_after>package main

import (
	"crypto/tls"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"
)

// nagios exit codes
const (
	OK = iota
	WARNING
	CRITICAL
	UNKNOWN
)

// export NCG2=debug
const DEBUG = "NCG2"

// license information
const (
        author = "Antonino Catinello"
        license = "BSD"
        year = "2016"
        copyright = "\u00A9"
)

var (
	// command line arguments
	link *string
	user *string
	pass *string
	version *bool
	// using ssl to avoid name conflict with tls
	ssl *bool
	// env debugging variable
	debug string
	// performence data
	pdata string
	// version value
	id string
)

// handle performence data output
func perf(elapsed, total, inputs, tput, index float64) {
	pdata = fmt.Sprintf("time=%f;;;; total=%.f;;;; sources=%.f;;;; throughput=%.f;;;; index_failures=%.f;;;;", elapsed, total, inputs, tput, index)
}

// handle args
func init() {
	link = flag.String("l", "http://localhost:12900", "Graylog2 API URL")
	user = flag.String("u", "", "API username")
	pass = flag.String("p", "", "API password")
	ssl = flag.Bool("insecure", false, "Accept insecure SSL/TLS certificates.")
	version = flag.Bool("version", false, "Display version and license information.")
	debug = os.Getenv(DEBUG)
	perf(0, 0, 0, 0, 0)
}

// return nagios codes on quit
func quit(status int, message string, err error) {
	var ev string

	switch status {
	case OK:
		ev = "OK"
	case WARNING:
		ev = "WARNING"
	case CRITICAL:
		ev = "CRITICAL"
	case UNKNOWN:
		ev = "UNKNOWN"
	}

	// if debugging is enabled
	// print errors
	if len(debug) != 0 {
		fmt.Println(err)
	}

	fmt.Printf("%s - %s|%s\n", ev, message, pdata)
	os.Exit(status)
}

// parse link
func parse(link *string) string {
	l, err := url.Parse(*link)
	if err != nil {
		quit(UNKNOWN, "Can not parse given URL.", err)
	}

	if !strings.Contains(l.Host, ":") {
		quit(UNKNOWN, "Port number is missing. Try "+l.Scheme+"://hostname:port", err)
	}

	if !strings.HasPrefix(l.Scheme, "HTTP") && !strings.HasPrefix(l.Scheme, "http") {
		quit(UNKNOWN, "Only HTTP is supported as protocol.", err)
	}

	return l.Scheme + "://" + l.Host
}

func main() {
	flag.Parse()

	if *version {
		fmt.Printf("Version: %v License: %v %v %v %v\n", id, license, copyright, year, author)
		os.Exit(3)
	}

	if len(*user) == 0 || len(*pass) == 0 {
		flag.PrintDefaults()
		os.Exit(3)
	}

	c := parse(link)
	start := time.Now()

	system := query(c+"/system", *user, *pass)
	if system["is_processing"].(bool) != true {
		quit(CRITICAL, "Service is not processing!", nil)
	}
	if strings.Compare(system["lifecycle"].(string), "running") != 0 {
		quit(WARNING, fmt.Sprintf("lifecycle: %v", system["lifecycle"].(string)), nil)
	}
	if strings.Compare(system["lb_status"].(string), "alive") != 0 {
		quit(WARNING, fmt.Sprintf("lb_status: %v", system["lb_status"].(string)), nil)
	}

	index := query(c+"/system/indexer/failures", *user, *pass)
	tput := query(c+"/system/throughput", *user, *pass)
	inputs := query(c+"/system/inputs", *user, *pass)
	total := query(c+"/count/total", *user, *pass)

	elapsed := time.Since(start)

	perf(elapsed.Seconds(), total["events"].(float64), inputs["total"].(float64), tput["throughput"].(float64), index["total"].(float64))
	quit(OK, fmt.Sprintf("Service is running!\n%.f total events processed\n%.f index failures\n%.f throughput\n%.f sources\nCheck took %v",
		total["events"].(float64), index["total"].(float64), tput["throughput"].(float64), inputs["total"].(float64), elapsed), nil)
}

// call Graylog2 HTTP API
func query(target string, user string, pass string) map[string]interface{} {
	var client *http.Client
	var data map[string]interface{}

	if *ssl {
		tp := &http.Transport{
			// keep this necessary evil for internal servers with custom certs?
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		}

		client = &http.Client{Transport: tp}
	} else {
		client = &http.Client{}
	}

	req, err := http.NewRequest("GET", target, nil)
	req.SetBasicAuth(user, pass)
	req.Header.Set("Accept", "application/json")

	res, err := client.Do(req)
	if err != nil {
		quit(CRITICAL, "Can not connect to Graylog2 API", err)
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		quit(CRITICAL, "No response received from Graylog2 API", err)
	}

	if len(debug) != 0 {
		fmt.Println(string(body))
	}

	err = json.Unmarshal(body, &data)
	if err != nil {
		quit(UNKNOWN, "Can not parse JSON from Graylog2 API", err)
	}

	if res.StatusCode != 200 {
		quit(CRITICAL, fmt.Sprintf("Graylog2 API replied with HTTP code %v", res.StatusCode), err)
	}

	return data
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"compress/gzip"
	"encoding/json"
	"flag"
	"fmt"
	"html"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"regexp"
	"strings"
	"text/template"
)

const (
	MaxErrors     = 3
	MaxPages      = 1
	MinReputation = 400
	APIKeyPath    = "./_secret/api.key"
	ApiURL        = "https://api.stackexchange.com/2.2/users?page="
	CQuery        = "pagesize=100&order=desc&sort=reputation&site=stackoverflow"
)

type SOUsers struct {
	Items []struct {
		BadgeCounts struct {
			Bronze int `json:"bronze"`
			Silver int `json:"silver"`
			Gold   int `json:"gold"`
		} `json:"badge_counts"`
		AccountID               int    `json:"account_id"`
		IsEmployee              bool   `json:"is_employee"`
		LastModifiedDate        int    `json:"last_modified_date"`
		LastAccessDate          int    `json:"last_access_date"`
		Age                     int    `json:"age,omitempty"`
		ReputationChangeYear    int    `json:"reputation_change_year"`
		ReputationChangeQuarter int    `json:"reputation_change_quarter"`
		ReputationChangeMonth   int    `json:"reputation_change_month"`
		ReputationChangeWeek    int    `json:"reputation_change_week"`
		ReputationChangeDay     int    `json:"reputation_change_day"`
		Reputation              int    `json:"reputation"`
		CreationDate            int    `json:"creation_date"`
		UserType                string `json:"user_type"`
		UserID                  int    `json:"user_id"`
		AcceptRate              int    `json:"accept_rate,omitempty"`
		Location                string `json:"location,omitempty"`
		WebsiteURL              string `json:"website_url,omitempty"`
		Link                    string `json:"link"`
		ProfileImage            string `json:"profile_image"`
		DisplayName             string `json:"display_name"`
	} `json:"items"`
	HasMore        bool `json:"has_more"`
	QuotaMax       int  `json:"quota_max"`
	QuotaRemaining int  `json:"quota_remaining"`
}

type SOUserRank struct {
	Rank         int    `json:"rank"`
	AccountID    int    `json:"account_id"`
	DisplayName  string `json:"display_name"`
	Reputation   int    `json:"reputation"`
	Location     string `json:"location,omitempty"`
	WebsiteURL   string `json:"website_url,omitempty"`
	Link         string `json:"link"`
	ProfileImage string `json:"profile_image"`
}

type Ranks []SOUserRank

var (
	Trace    *log.Logger
	Info     *log.Logger
	Warning  *log.Logger
	Error    *log.Logger
	location = flag.String("location", "spain", "location")
	jsonfile = flag.String("json", "", "json sample file")
	jsonrsp  = flag.String("jsonrsp", "", "json response file")
	mdrsp    = flag.String("mdrsp", "", "markdown response file")
	limit    = flag.Int("limit", 20, "max number of records")
)

func Init(
	traceHandle io.Writer,
	infoHandle io.Writer,
	warningHandle io.Writer,
	errorHandle io.Writer) {

	Trace = log.New(traceHandle,
		"TRACE: ",
		log.Ldate|log.Ltime|log.Lshortfile)

	Info = log.New(infoHandle,
		"INFO: ",
		log.Ldate|log.Ltime|log.Lshortfile)

	Warning = log.New(warningHandle,
		"WARN: ",
		log.Ldate|log.Ltime|log.Lshortfile)

	Error = log.New(errorHandle,
		"ERROR: ",
		log.Ldate|log.Ltime|log.Lshortfile)

}

func Decode(r io.Reader) (users *SOUsers, err error) {

	users = new(SOUsers)
	return users, json.NewDecoder(r).Decode(users)
}

func StreamHTTP(page int, key string) (users *SOUsers, err error) {

	var reader io.ReadCloser

	url := fmt.Sprintf("%s%d&%s%s", ApiURL, page, CQuery, key)
	Trace.Println(url)

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		Trace.Println(err)
		return users, err
	}

	req.Header.Set("Accept-Encoding", "gzip")

	response, err := http.DefaultClient.Do(req)
	if err != nil {
		Trace.Println(err)
		return users, err
	}
	defer response.Body.Close()

	switch response.Header.Get("Content-Encoding") {
	case "gzip":
		reader, err = gzip.NewReader(response.Body)
		if err != nil {
			Trace.Println(err)
			return users, err
		}
		defer reader.Close()
	default:
		reader = response.Body
	}
	return Decode(reader)
}

func StreamFile(jsonfile string) (users *SOUsers, err error) {
	reader, err := os.Open(jsonfile)
	defer reader.Close()

	return Decode(reader)
}

func GetUserInfo(users *SOUsers, location *regexp.Regexp, counter *int, limit int, ranks *Ranks) (rep bool) {

	for _, user := range users.Items {
		if user.Reputation < MinReputation {
			return false
		}
		if location.MatchString(user.Location) {
			*counter += 1
			if *counter == 1 {
				fmt.Printf("%4s %-30s %6s %-30s\n", "Rank", "Name", "Rep", "Location")
			}

			if *counter > limit && limit != 0 {
				return false
			}
			s := SOUserRank{Rank: *counter,
				AccountID:    user.AccountID,
				DisplayName:  user.DisplayName,
				Reputation:   user.Reputation,
				Location:     user.Location,
				WebsiteURL:   user.WebsiteURL,
				Link:         user.Link,
				ProfileImage: user.ProfileImage}

			*ranks = append(*ranks, s)

			fmt.Printf("%4d %-30s %6d %-30s %s\n", *counter, html.UnescapeString(user.DisplayName),
				user.Reputation, html.UnescapeString(user.Location), user.WebsiteURL)

		}
	}
	return true
}

func DumpJson(path *string, ranks *Ranks) {
	Trace.Printf("Writing to: %s\n", *path)
	jsonenc, _ := json.MarshalIndent(*ranks, "", " ")
	f, err := os.Create(*path)
	if err != nil {
		panic(err)
	}
	defer f.Close()
	w := bufio.NewWriter(f)
	n4, err := w.WriteString(string(jsonenc))
	if err != nil {
		panic(err)
	}
	Trace.Printf("Wrote %d bytes to %s\n", n4, *jsonrsp)

	w.Flush()
}

func DumpMarkdown(ranks Ranks) {
	tmpl, _ := template.New("test").Parse("{{.Rank}} {{.DisplayName}}\n")
	for _, userRank := range ranks {
		_ = tmpl.Execute(os.Stdout, userRank)
	}
}

func GetKey() (key string, err error) {
	_, err = os.Stat(APIKeyPath)

	if err != nil {
		return "", fmt.Errorf("Can't find API key: %s", APIKeyPath)
	}

	strkey, err := ioutil.ReadFile(APIKeyPath)
	if err != nil {
		return "", fmt.Errorf("Can't load API key: %s", err)
	}

	return fmt.Sprintf("&key=%s", strings.TrimRight(string(strkey)[:], "\n")), nil
}

func main() {
	flag.Parse()

	Init(ioutil.Discard, os.Stdout, os.Stdout, os.Stderr)
	Trace.Println("location: ", *location)
	Trace.Println("json: ", *jsonfile)
	Trace.Println("jsontest: ", *jsonfile)
	Trace.Println("jsonrsp: ", *jsonrsp)
	Trace.Println("mdrsp: ", *mdrsp)
	Trace.Println("limit: ", *limit)

	re := regexp.MustCompile(fmt.Sprintf("(?i)%s", *location))

	stop := false
	streamErrors := 0
	currentPage := 1
	counter := 0

	var users *SOUsers
	var ranks Ranks

	for {
		if *jsonfile == "" {
			key, err := GetKey()
			if err != nil {
				Warning.Println(err)
			}
			users, err = StreamHTTP(currentPage, key)
			if err != nil || len(users.Items) == 0 {

				Warning.Println("Can't stream data.")
				streamErrors += 1
				if streamErrors >= MaxErrors {
					Error.Println("Max retry number reached")
					os.Exit(5)
				}
				continue
			}
		} else {
			var err error
			users, err = StreamFile(*jsonfile)
			if err != nil {
				Error.Println("Can't decode json file.")
				os.Exit(5)
			}
			stop = true
		}

		repLimit := GetUserInfo(users, re, &counter, *limit, &ranks)
		if !repLimit {
			break
		}

		currentPage += 1
		if (currentPage >= MaxPages && MaxPages != 0) || !users.HasMore || stop {
			break
		}
	}

	if counter == 0 {
		Warning.Println("No results found.")
		os.Exit(0)
	}

	if *mdrsp != "" {
		DumpMarkdown(ranks)
	}

	if *jsonrsp != "" {
		DumpJson(jsonrsp, &ranks)
	}
	Trace.Printf("%d users found.\n", counter)
}
<commit_msg>head markdown added<commit_after>package main

import (
	"bufio"
	"compress/gzip"
	"encoding/json"
	"flag"
	"fmt"
	"html"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"regexp"
	"strings"
	"text/template"
)

const (
	MaxErrors     = 3
	MaxPages      = 1
	MinReputation = 400
	APIKeyPath    = "./_secret/api.key"
	ApiURL        = "https://api.stackexchange.com/2.2/users?page="
	CQuery        = "pagesize=100&order=desc&sort=reputation&site=stackoverflow"
)

type SOUsers struct {
	Items []struct {
		BadgeCounts struct {
			Bronze int `json:"bronze"`
			Silver int `json:"silver"`
			Gold   int `json:"gold"`
		} `json:"badge_counts"`
		AccountID               int    `json:"account_id"`
		IsEmployee              bool   `json:"is_employee"`
		LastModifiedDate        int    `json:"last_modified_date"`
		LastAccessDate          int    `json:"last_access_date"`
		Age                     int    `json:"age,omitempty"`
		ReputationChangeYear    int    `json:"reputation_change_year"`
		ReputationChangeQuarter int    `json:"reputation_change_quarter"`
		ReputationChangeMonth   int    `json:"reputation_change_month"`
		ReputationChangeWeek    int    `json:"reputation_change_week"`
		ReputationChangeDay     int    `json:"reputation_change_day"`
		Reputation              int    `json:"reputation"`
		CreationDate            int    `json:"creation_date"`
		UserType                string `json:"user_type"`
		UserID                  int    `json:"user_id"`
		AcceptRate              int    `json:"accept_rate,omitempty"`
		Location                string `json:"location,omitempty"`
		WebsiteURL              string `json:"website_url,omitempty"`
		Link                    string `json:"link"`
		ProfileImage            string `json:"profile_image"`
		DisplayName             string `json:"display_name"`
	} `json:"items"`
	HasMore        bool `json:"has_more"`
	QuotaMax       int  `json:"quota_max"`
	QuotaRemaining int  `json:"quota_remaining"`
}

type SOUserRank struct {
	Rank         int    `json:"rank"`
	AccountID    int    `json:"account_id"`
	DisplayName  string `json:"display_name"`
	Reputation   int    `json:"reputation"`
	Location     string `json:"location,omitempty"`
	WebsiteURL   string `json:"website_url,omitempty"`
	Link         string `json:"link"`
	ProfileImage string `json:"profile_image"`
}

type Ranks []SOUserRank

var (
	Trace    *log.Logger
	Info     *log.Logger
	Warning  *log.Logger
	Error    *log.Logger
	location = flag.String("location", "spain", "location")
	jsonfile = flag.String("json", "", "json sample file")
	jsonrsp  = flag.String("jsonrsp", "", "json response file")
	mdrsp    = flag.String("mdrsp", "", "markdown response file")
	limit    = flag.Int("limit", 20, "max number of records")
)

func Init(
	traceHandle io.Writer,
	infoHandle io.Writer,
	warningHandle io.Writer,
	errorHandle io.Writer) {

	Trace = log.New(traceHandle,
		"TRACE: ",
		log.Ldate|log.Ltime|log.Lshortfile)

	Info = log.New(infoHandle,
		"INFO: ",
		log.Ldate|log.Ltime|log.Lshortfile)

	Warning = log.New(warningHandle,
		"WARN: ",
		log.Ldate|log.Ltime|log.Lshortfile)

	Error = log.New(errorHandle,
		"ERROR: ",
		log.Ldate|log.Ltime|log.Lshortfile)

}

func Decode(r io.Reader) (users *SOUsers, err error) {

	users = new(SOUsers)
	return users, json.NewDecoder(r).Decode(users)
}

func StreamHTTP(page int, key string) (users *SOUsers, err error) {

	var reader io.ReadCloser

	url := fmt.Sprintf("%s%d&%s%s", ApiURL, page, CQuery, key)
	Trace.Println(url)

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		Trace.Println(err)
		return users, err
	}

	req.Header.Set("Accept-Encoding", "gzip")

	response, err := http.DefaultClient.Do(req)
	if err != nil {
		Trace.Println(err)
		return users, err
	}
	defer response.Body.Close()

	switch response.Header.Get("Content-Encoding") {
	case "gzip":
		reader, err = gzip.NewReader(response.Body)
		if err != nil {
			Trace.Println(err)
			return users, err
		}
		defer reader.Close()
	default:
		reader = response.Body
	}
	return Decode(reader)
}

func StreamFile(jsonfile string) (users *SOUsers, err error) {
	reader, err := os.Open(jsonfile)
	defer reader.Close()

	return Decode(reader)
}

func GetUserInfo(users *SOUsers, location *regexp.Regexp, counter *int, limit int, ranks *Ranks) (rep bool) {

	for _, user := range users.Items {
		if user.Reputation < MinReputation {
			return false
		}
		if location.MatchString(user.Location) {
			*counter += 1
			if *counter == 1 {
				fmt.Printf("%4s %-30s %6s %-30s\n", "Rank", "Name", "Rep", "Location")
			}

			if *counter > limit && limit != 0 {
				return false
			}
			s := SOUserRank{Rank: *counter,
				AccountID:    user.AccountID,
				DisplayName:  user.DisplayName,
				Reputation:   user.Reputation,
				Location:     user.Location,
				WebsiteURL:   user.WebsiteURL,
				Link:         user.Link,
				ProfileImage: user.ProfileImage}

			*ranks = append(*ranks, s)

			fmt.Printf("%4d %-30s %6d %-30s %s\n", *counter, html.UnescapeString(user.DisplayName),
				user.Reputation, html.UnescapeString(user.Location), user.WebsiteURL)

		}
	}
	return true
}

func DumpJson(path *string, ranks *Ranks) {
	Trace.Printf("Writing to: %s\n", *path)
	jsonenc, _ := json.MarshalIndent(*ranks, "", " ")
	f, err := os.Create(*path)
	if err != nil {
		panic(err)
	}
	defer f.Close()
	w := bufio.NewWriter(f)
	n4, err := w.WriteString(string(jsonenc))
	if err != nil {
		panic(err)
	}
	Trace.Printf("Wrote %d bytes to %s\n", n4, *jsonrsp)

	w.Flush()
}

func DumpMarkdown(ranks Ranks) {
	head := "Rank|Name|Rep|Location|Web|Avatar\n----|----|---|--------|---|------\n"

	userfmt := "{{.Rank}}|[{{.DisplayName}}]({{.Link}})|{{.Reputation}}|{{.Location}}|{{.WebsiteURL}}|![Avatar]({{.ProfileImage}})\n"

	fmt.Println(head)

	tmpl, _ := template.New("test").Parse(userfmt)
	for _, userRank := range ranks {
		_ = tmpl.Execute(os.Stdout, userRank)
	}
}

func GetKey() (key string, err error) {
	_, err = os.Stat(APIKeyPath)

	if err != nil {
		return "", fmt.Errorf("Can't find API key: %s", APIKeyPath)
	}

	strkey, err := ioutil.ReadFile(APIKeyPath)
	if err != nil {
		return "", fmt.Errorf("Can't load API key: %s", err)
	}

	return fmt.Sprintf("&key=%s", strings.TrimRight(string(strkey)[:], "\n")), nil
}

func main() {
	flag.Parse()

	Init(ioutil.Discard, os.Stdout, os.Stdout, os.Stderr)
	Trace.Println("location: ", *location)
	Trace.Println("json: ", *jsonfile)
	Trace.Println("jsontest: ", *jsonfile)
	Trace.Println("jsonrsp: ", *jsonrsp)
	Trace.Println("mdrsp: ", *mdrsp)
	Trace.Println("limit: ", *limit)

	re := regexp.MustCompile(fmt.Sprintf("(?i)%s", *location))

	stop := false
	streamErrors := 0
	currentPage := 1
	counter := 0

	var users *SOUsers
	var ranks Ranks

	for {
		if *jsonfile == "" {
			key, err := GetKey()
			if err != nil {
				Warning.Println(err)
			}
			users, err = StreamHTTP(currentPage, key)
			if err != nil || len(users.Items) == 0 {

				Warning.Println("Can't stream data.")
				streamErrors += 1
				if streamErrors >= MaxErrors {
					Error.Println("Max retry number reached")
					os.Exit(5)
				}
				continue
			}
		} else {
			var err error
			users, err = StreamFile(*jsonfile)
			if err != nil {
				Error.Println("Can't decode json file.")
				os.Exit(5)
			}
			stop = true
		}

		repLimit := GetUserInfo(users, re, &counter, *limit, &ranks)
		if !repLimit {
			break
		}

		currentPage += 1
		if (currentPage >= MaxPages && MaxPages != 0) || !users.HasMore || stop {
			break
		}
	}

	if counter == 0 {
		Warning.Println("No results found.")
		os.Exit(0)
	}

	if *mdrsp != "" {
		DumpMarkdown(ranks)
	}

	if *jsonrsp != "" {
		DumpJson(jsonrsp, &ranks)
	}
	Trace.Printf("%d users found.\n", counter)
}
<|endoftext|>


<commit_before>package freeway

import (
	"net"
)

// The content of an RPC reponse UDP packet
type ReplyPacket struct {
	NamedReturns map[string]interface{} "r"
	PacketType   string                 "y"
	Transaction  string                 "t"
}

type IncomingReplyPacket struct {
	ReplyPacket
	Source *net.UDPAddr
}

func NewReplyPacket(transaction string, args map[string]interface{}) *ReplyPacket {
	return &ReplyPacket{
		NamedReturns: args,
		PacketType:   krpcReply,
		Transaction:  transaction,
	}
}

func NewPingReply(transaction string, localPeerID ID) *ReplyPacket {
	args := make(map[string]interface{})
	args["id"] = localPeerID.String()
	return NewReplyPacket(transaction, args)
}

func NewFindNodeReply(transaction string, localPeerID ID, peers []*Peer) *ReplyPacket {
	args := make(map[string]interface{})
	args["id"] = localPeerID.String()
	args["nodes"] = string(PeerArray(peers).CompactInfo())
	return NewReplyPacket(transaction, args)
}

type Response struct {
	dht     *DHT
	dest    *Peer
	message *ReplyPacket
}

func NewResponse(dht *DHT, dest *Peer, message *ReplyPacket) *Response {
	return &Response{
		dht:     dht,
		dest:    dest,
		message: message,
	}
}

// Structure of a FindNode RPC-reply.
type FindNodeResponse struct {
	Source *Peer
	Peers  []*Peer
}
<commit_msg>Fixed field struct tag for bencode.<commit_after>package freeway

import (
	"net"
)

// The content of an RPC reponse UDP packet
type ReplyPacket struct {
	NamedReturns map[string]interface{} `bencode:"r"`
	PacketType   string                 `bencode:"y"`
	Transaction  string                 `bencode:"t"`
}

type IncomingReplyPacket struct {
	ReplyPacket
	Source *net.UDPAddr
}

func NewReplyPacket(transaction string, args map[string]interface{}) *ReplyPacket {
	return &ReplyPacket{
		NamedReturns: args,
		PacketType:   krpcReply,
		Transaction:  transaction,
	}
}

func NewPingReply(transaction string, localPeerID ID) *ReplyPacket {
	args := make(map[string]interface{})
	args["id"] = localPeerID.String()
	return NewReplyPacket(transaction, args)
}

func NewFindNodeReply(transaction string, localPeerID ID, peers []*Peer) *ReplyPacket {
	args := make(map[string]interface{})
	args["id"] = localPeerID.String()
	args["nodes"] = string(PeerArray(peers).CompactInfo())
	return NewReplyPacket(transaction, args)
}

type Response struct {
	dht     *DHT
	dest    *Peer
	message *ReplyPacket
}

func NewResponse(dht *DHT, dest *Peer, message *ReplyPacket) *Response {
	return &Response{
		dht:     dht,
		dest:    dest,
		message: message,
	}
}

// Structure of a FindNode RPC-reply.
type FindNodeResponse struct {
	Source *Peer
	Peers  []*Peer
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package cm

import (
	"bufio"
	"fmt"
	"os"
	"path/filepath"
	"strconv"

	libcontainercgroups "github.com/opencontainers/runc/libcontainer/cgroups"

	"k8s.io/kubernetes/pkg/api/v1"
	"k8s.io/kubernetes/pkg/kubelet/qos"
)

const (
	// Taken from lmctfy https://github.com/google/lmctfy/blob/master/lmctfy/controllers/cpu_controller.cc
	MinShares     = 2
	SharesPerCPU  = 1024
	MilliCPUToCPU = 1000

	// 100000 is equivalent to 100ms
	QuotaPeriod    = 100000
	MinQuotaPeriod = 1000
)

// MilliCPUToQuota converts milliCPU to CFS quota and period values.
func MilliCPUToQuota(milliCPU int64) (quota int64, period int64) {
	// CFS quota is measured in two values:
	//  - cfs_period_us=100ms (the amount of time to measure usage across)
	//  - cfs_quota=20ms (the amount of cpu time allowed to be used across a period)
	// so in the above example, you are limited to 20% of a single CPU
	// for multi-cpu environments, you just scale equivalent amounts

	if milliCPU == 0 {
		return
	}

	// we set the period to 100ms by default
	period = QuotaPeriod

	// we then convert your milliCPU to a value normalized over a period
	quota = (milliCPU * QuotaPeriod) / MilliCPUToCPU

	// quota needs to be a minimum of 1ms.
	if quota < MinQuotaPeriod {
		quota = MinQuotaPeriod
	}

	return
}

// MilliCPUToShares converts the milliCPU to CFS shares.
func MilliCPUToShares(milliCPU int64) int64 {
	if milliCPU == 0 {
		// Docker converts zero milliCPU to unset, which maps to kernel default
		// for unset: 1024. Return 2 here to really match kernel default for
		// zero milliCPU.
		return MinShares
	}
	// Conceptually (milliCPU / milliCPUToCPU) * sharesPerCPU, but factored to improve rounding.
	shares := (milliCPU * SharesPerCPU) / MilliCPUToCPU
	if shares < MinShares {
		return MinShares
	}
	return shares
}

// ResourceConfigForPod takes the input pod and outputs the cgroup resource config.
func ResourceConfigForPod(pod *v1.Pod) *ResourceConfig {
	// sum requests and limits, track if limits were applied for each resource.
	cpuRequests := int64(0)
	cpuLimits := int64(0)
	memoryLimits := int64(0)
	memoryLimitsDeclared := true
	cpuLimitsDeclared := true
	for _, container := range pod.Spec.Containers {
		cpuRequests += container.Resources.Requests.Cpu().MilliValue()
		cpuLimits += container.Resources.Limits.Cpu().MilliValue()
		if container.Resources.Limits.Cpu().IsZero() {
			cpuLimitsDeclared = false
		}
		memoryLimits += container.Resources.Limits.Memory().Value()
		if container.Resources.Limits.Memory().IsZero() {
			memoryLimitsDeclared = false
		}
	}

	// convert to CFS values
	cpuShares := MilliCPUToShares(cpuRequests)
	cpuQuota, cpuPeriod := MilliCPUToQuota(cpuLimits)

	// determine the qos class
	qosClass := qos.GetPodQOS(pod)

	// build the result
	result := &ResourceConfig{}
	if qosClass == v1.PodQOSGuaranteed {
		result.CpuShares = &cpuShares
		result.CpuQuota = &cpuQuota
		result.CpuPeriod = &cpuPeriod
		result.Memory = &memoryLimits
	} else if qosClass == v1.PodQOSBurstable {
		result.CpuShares = &cpuShares
		if cpuLimitsDeclared {
			result.CpuQuota = &cpuQuota
			result.CpuPeriod = &cpuPeriod
		}
		if memoryLimitsDeclared {
			result.Memory = &memoryLimits
		}
	} else {
		shares := int64(MinShares)
		result.CpuShares = &shares
	}
	return result
}

// GetCgroupSubsystems returns information about the mounted cgroup subsystems
func GetCgroupSubsystems() (*CgroupSubsystems, error) {
	// get all cgroup mounts.
	allCgroups, err := libcontainercgroups.GetCgroupMounts(true)
	if err != nil {
		return &CgroupSubsystems{}, err
	}
	if len(allCgroups) == 0 {
		return &CgroupSubsystems{}, fmt.Errorf("failed to find cgroup mounts")
	}
	mountPoints := make(map[string]string, len(allCgroups))
	for _, mount := range allCgroups {
		for _, subsystem := range mount.Subsystems {
			mountPoints[subsystem] = mount.Mountpoint
		}
	}
	return &CgroupSubsystems{
		Mounts:      allCgroups,
		MountPoints: mountPoints,
	}, nil
}

// getCgroupProcs takes a cgroup directory name as an argument
// reads through the cgroup's procs file and returns a list of tgid's.
// It returns an empty list if a procs file doesn't exists
func getCgroupProcs(dir string) ([]int, error) {
	procsFile := filepath.Join(dir, "cgroup.procs")
	f, err := os.Open(procsFile)
	if err != nil {
		if os.IsNotExist(err) {
			// The procsFile does not exist, So no pids attached to this directory
			return []int{}, nil
		}
		return nil, err
	}
	defer f.Close()

	s := bufio.NewScanner(f)
	out := []int{}
	for s.Scan() {
		if t := s.Text(); t != "" {
			pid, err := strconv.Atoi(t)
			if err != nil {
				return nil, fmt.Errorf("unexpected line in %v; could not convert to pid: %v", procsFile, err)
			}
			out = append(out, pid)
		}
	}
	return out, nil
}
<commit_msg>UPSTREAM: 44898: while calculating pod's cpu limits, need to count in init-container<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package cm

import (
	"bufio"
	"fmt"
	"os"
	"path/filepath"
	"strconv"

	libcontainercgroups "github.com/opencontainers/runc/libcontainer/cgroups"

	"k8s.io/kubernetes/pkg/api/v1"
	"k8s.io/kubernetes/pkg/kubelet/qos"
)

const (
	// Taken from lmctfy https://github.com/google/lmctfy/blob/master/lmctfy/controllers/cpu_controller.cc
	MinShares     = 2
	SharesPerCPU  = 1024
	MilliCPUToCPU = 1000

	// 100000 is equivalent to 100ms
	QuotaPeriod    = 100000
	MinQuotaPeriod = 1000
)

// MilliCPUToQuota converts milliCPU to CFS quota and period values.
func MilliCPUToQuota(milliCPU int64) (quota int64, period int64) {
	// CFS quota is measured in two values:
	//  - cfs_period_us=100ms (the amount of time to measure usage across)
	//  - cfs_quota=20ms (the amount of cpu time allowed to be used across a period)
	// so in the above example, you are limited to 20% of a single CPU
	// for multi-cpu environments, you just scale equivalent amounts

	if milliCPU == 0 {
		return
	}

	// we set the period to 100ms by default
	period = QuotaPeriod

	// we then convert your milliCPU to a value normalized over a period
	quota = (milliCPU * QuotaPeriod) / MilliCPUToCPU

	// quota needs to be a minimum of 1ms.
	if quota < MinQuotaPeriod {
		quota = MinQuotaPeriod
	}

	return
}

// MilliCPUToShares converts the milliCPU to CFS shares.
func MilliCPUToShares(milliCPU int64) int64 {
	if milliCPU == 0 {
		// Docker converts zero milliCPU to unset, which maps to kernel default
		// for unset: 1024. Return 2 here to really match kernel default for
		// zero milliCPU.
		return MinShares
	}
	// Conceptually (milliCPU / milliCPUToCPU) * sharesPerCPU, but factored to improve rounding.
	shares := (milliCPU * SharesPerCPU) / MilliCPUToCPU
	if shares < MinShares {
		return MinShares
	}
	return shares
}

// ResourceConfigForPod takes the input pod and outputs the cgroup resource config.
func ResourceConfigForPod(pod *v1.Pod) *ResourceConfig {
	// sum requests and limits.
	reqs, limits, err := v1.PodRequestsAndLimits(pod)
	if err != nil {
		return &ResourceConfig{}
	}

	cpuRequests := int64(0)
	cpuLimits := int64(0)
	memoryLimits := int64(0)
	if request, found := reqs[v1.ResourceCPU]; found {
		cpuRequests = request.MilliValue()
	}
	if limit, found := limits[v1.ResourceCPU]; found {
		cpuLimits = limit.MilliValue()
	}
	if limit, found := limits[v1.ResourceMemory]; found {
		memoryLimits = limit.Value()
	}

	// convert to CFS values
	cpuShares := MilliCPUToShares(cpuRequests)
	cpuQuota, cpuPeriod := MilliCPUToQuota(cpuLimits)

	// track if limits were applied for each resource.
	memoryLimitsDeclared := true
	cpuLimitsDeclared := true
	for _, container := range pod.Spec.Containers {
		if container.Resources.Limits.Cpu().IsZero() {
			cpuLimitsDeclared = false
		}
		if container.Resources.Limits.Memory().IsZero() {
			memoryLimitsDeclared = false
		}
	}

	// determine the qos class
	qosClass := qos.GetPodQOS(pod)

	// build the result
	result := &ResourceConfig{}
	if qosClass == v1.PodQOSGuaranteed {
		result.CpuShares = &cpuShares
		result.CpuQuota = &cpuQuota
		result.CpuPeriod = &cpuPeriod
		result.Memory = &memoryLimits
	} else if qosClass == v1.PodQOSBurstable {
		result.CpuShares = &cpuShares
		if cpuLimitsDeclared {
			result.CpuQuota = &cpuQuota
			result.CpuPeriod = &cpuPeriod
		}
		if memoryLimitsDeclared {
			result.Memory = &memoryLimits
		}
	} else {
		shares := int64(MinShares)
		result.CpuShares = &shares
	}
	return result
}

// GetCgroupSubsystems returns information about the mounted cgroup subsystems
func GetCgroupSubsystems() (*CgroupSubsystems, error) {
	// get all cgroup mounts.
	allCgroups, err := libcontainercgroups.GetCgroupMounts(true)
	if err != nil {
		return &CgroupSubsystems{}, err
	}
	if len(allCgroups) == 0 {
		return &CgroupSubsystems{}, fmt.Errorf("failed to find cgroup mounts")
	}
	mountPoints := make(map[string]string, len(allCgroups))
	for _, mount := range allCgroups {
		for _, subsystem := range mount.Subsystems {
			mountPoints[subsystem] = mount.Mountpoint
		}
	}
	return &CgroupSubsystems{
		Mounts:      allCgroups,
		MountPoints: mountPoints,
	}, nil
}

// getCgroupProcs takes a cgroup directory name as an argument
// reads through the cgroup's procs file and returns a list of tgid's.
// It returns an empty list if a procs file doesn't exists
func getCgroupProcs(dir string) ([]int, error) {
	procsFile := filepath.Join(dir, "cgroup.procs")
	f, err := os.Open(procsFile)
	if err != nil {
		if os.IsNotExist(err) {
			// The procsFile does not exist, So no pids attached to this directory
			return []int{}, nil
		}
		return nil, err
	}
	defer f.Close()

	s := bufio.NewScanner(f)
	out := []int{}
	for s.Scan() {
		if t := s.Text(); t != "" {
			pid, err := strconv.Atoi(t)
			if err != nil {
				return nil, fmt.Errorf("unexpected line in %v; could not convert to pid: %v", procsFile, err)
			}
			out = append(out, pid)
		}
	}
	return out, nil
}
<|endoftext|>