<commit_before>package main

import (
	"fmt"
	"io"
	"os"
	"path/filepath"
	"regexp"

	"github.com/dustin/go-humanize"
)

const writeFlagsDefault = os.O_WRONLY | os.O_CREATE | os.O_TRUNC | os.O_EXCL
const writeFlagsOverwrite = os.O_WRONLY | os.O_CREATE | os.O_TRUNC
const defaultPerms = 0755

type CmdUnpack struct {
	cmd
	Verbose     bool   `short:"v" description:"Activates the verbose mode"`
	Overwrite   bool   `short:"o" description:"Overwrites the files if arleady exists"`
	IgnorePerms bool   `short:"i" description:"Ignore files permisisions"`
	Match       string `short:"m" description:"Only extract files matching the given regexp"`

	Output struct {
		Path string `positional-arg-name:"output" description:"files or directories to be add to the archive."`
	} `positional-args:"yes"`

	flags        int
	regexp       *regexp.Regexp
	matchingFunc func(string) bool
}

func (c *CmdUnpack) Execute(args []string) error {
	if err := c.validate(); err != nil {
		return err
	}

	if err := c.buildArchive(); err != nil {
		return err
	}

	if err := c.do(); err != nil {
		return err
	}

	return nil
}

func (c *CmdUnpack) validate() error {
	err := c.cmd.validate()
	if err != nil {
		return err
	}

	if _, err := os.Stat(c.Args.File); err != nil {
		return fmt.Errorf("Invalid input file %q, %s\n", c.Args.File, err.Error())
	}

	if c.Output.Path == "" {
		c.Output.Path = "."
	}

	c.flags = writeFlagsDefault
	if c.Overwrite {
		c.flags = writeFlagsOverwrite
	}

	c.matchingFunc = func(string) bool { return true }
	if c.Match != "" {
		c.regexp, err = regexp.Compile(c.Match)
		if err != nil {
			return fmt.Errorf("Invalid match regexp %q, %s\n", c.Match, err.Error())
		}

		c.matchingFunc = func(name string) bool {
			return c.regexp.MatchString(name)
		}
	}

	return nil
}

func (c *CmdUnpack) do() error {
	for _, fname := range c.a.Find(c.matchingFunc) {
		c.extract(fname)
	}

	return nil
}

func (c *CmdUnpack) extract(srcName string) {
	src, err := c.a.Open(srcName)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to open %q for read: %s\n", srcName, err.Error())
		return
	}

	defer src.Close()

	fi, _ := src.Stat()

	dstName := filepath.Join(c.Output.Path, srcName)
	dir := filepath.Dir(dstName)
	if err = os.MkdirAll(dir, 0755); err != nil {
		fmt.Fprintf(os.Stderr, "Unable to create dir %q: %s\n", dir, err.Error())
		return
	}

	perms := os.FileMode(defaultPerms)
	if !c.IgnorePerms {
		perms = fi.Mode().Perm()
	}

	dst, err := os.OpenFile(dstName, c.flags, perms)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to open %q for writing: %s\n", dstName, err.Error())
		return
	}

	defer dst.Close()

	if _, err := io.Copy(dst, src); err != nil {
		fmt.Fprintf(os.Stderr, "Unable to write %q : %s\n", srcName, err.Error())
		return
	}

	if c.Verbose {
		fmt.Println(srcName, humanize.Bytes(uint64(fi.Size())))
	}
}
<commit_msg>cmd: fixing unpack<commit_after>package main

import (
	"fmt"
	"io"
	"os"
	"path/filepath"
	"regexp"

	"github.com/mcuadros/go-raa"

	"github.com/dustin/go-humanize"
)

const writeFlagsDefault = os.O_WRONLY | os.O_CREATE | os.O_TRUNC | os.O_EXCL
const writeFlagsOverwrite = os.O_WRONLY | os.O_CREATE | os.O_TRUNC
const defaultPerms = 0755

type CmdUnpack struct {
	cmd
	Verbose     bool   `short:"v" description:"Activates the verbose mode"`
	Overwrite   bool   `short:"o" description:"Overwrites the files if arleady exists"`
	IgnorePerms bool   `short:"i" description:"Ignore files permisisions"`
	Match       string `short:"m" description:"Only extract files matching the given regexp"`

	Output struct {
		Path string `positional-arg-name:"output" description:"files or directories to be add to the archive."`
	} `positional-args:"yes"`

	flags        int
	regexp       *regexp.Regexp
	matchingFunc func(string) bool
}

func (c *CmdUnpack) Execute(args []string) error {
	if err := c.validate(); err != nil {
		return err
	}

	if err := c.openArchive(); err != nil {
		return err
	}

	if err := c.do(); err != nil {
		return err
	}

	return nil
}

func (c *CmdUnpack) validate() error {
	err := c.cmd.validate()
	if err != nil {
		return err
	}

	if _, err := os.Stat(c.Args.File); err != nil {
		return fmt.Errorf("Invalid input file %q, %s\n", c.Args.File, err.Error())
	}

	if c.Output.Path == "" {
		c.Output.Path = "."
	}

	c.flags = writeFlagsDefault
	if c.Overwrite {
		c.flags = writeFlagsOverwrite
	}

	c.matchingFunc = func(string) bool { return true }
	if c.Match != "" {
		c.regexp, err = regexp.Compile(c.Match)
		if err != nil {
			return fmt.Errorf("Invalid match regexp %q, %s\n", c.Match, err.Error())
		}

		c.matchingFunc = func(name string) bool {
			return c.regexp.MatchString(name)
		}
	}

	return nil
}

func (c *CmdUnpack) openArchive() error {
	a, err := raa.OpenArchive(c.Args.File)
	if err != nil {
		return err
	}

	c.a = a
	return nil
}

func (c *CmdUnpack) do() error {
	for _, fname := range c.a.Find(c.matchingFunc) {
		c.extract(fname)
	}

	return nil
}

func (c *CmdUnpack) extract(srcName string) {
	src, err := c.a.Open(srcName)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to open %q for read: %s\n", srcName, err.Error())
		return
	}

	defer src.Close()

	fi, _ := src.Stat()

	dstName := filepath.Join(c.Output.Path, srcName)
	dir := filepath.Dir(dstName)
	if err = os.MkdirAll(dir, 0755); err != nil {
		fmt.Fprintf(os.Stderr, "Unable to create dir %q: %s\n", dir, err.Error())
		return
	}

	perms := os.FileMode(defaultPerms)
	if !c.IgnorePerms {
		perms = fi.Mode().Perm()
	}

	dst, err := os.OpenFile(dstName, c.flags, perms)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to open %q for writing: %s\n", dstName, err.Error())
		return
	}

	defer dst.Close()

	if _, err := io.Copy(dst, src); err != nil {
		fmt.Fprintf(os.Stderr, "Unable to write %q : %s\n", srcName, err.Error())
		return
	}

	if c.Verbose {
		fmt.Println(srcName, humanize.Bytes(uint64(fi.Size())))
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main // import "mvdan.cc/sh/cmd/shfmt"

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"regexp"

	"mvdan.cc/sh/fileutil"
	"mvdan.cc/sh/syntax"
)

var (
	write       = flag.Bool("w", false, "write result to file instead of stdout")
	list        = flag.Bool("l", false, "list files whose formatting differs from shfmt's")
	simple      = flag.Bool("s", false, "simplify the code")
	langStr     = flag.String("ln", "", `language variant to parse (bash/posix/mksh) (default "bash")`)
	posix       = flag.Bool("p", false, "shorthand for -ln=posix")
	indent      = flag.Uint("i", 0, "indent: 0 for tabs (default), >0 for number of spaces")
	binNext     = flag.Bool("bn", false, "binary ops like && and | may start a line")
	caseIndent  = flag.Bool("ci", false, "switch cases will be indented")
	toJSON      = flag.Bool("exp.tojson", false, "print AST to stdout as a typed JSON")
	showVersion = flag.Bool("version", false, "show version and exit")

	parser            *syntax.Parser
	printer           *syntax.Printer
	readBuf, writeBuf bytes.Buffer

	copyBuf = make([]byte, 32*1024)

	out io.Writer = os.Stdout

	version = "v2.0.0"
)

func main() {
	flag.Usage = func() {
		fmt.Fprintln(os.Stderr, "usage: shfmt [flags] [path ...]")
		flag.PrintDefaults()
	}
	flag.Parse()

	if *showVersion {
		fmt.Println(version)
		return
	}
	if *posix && *langStr != "" {
		fmt.Fprintf(os.Stderr, "-p and -ln=lang cannot coexist\n")
		os.Exit(1)
	}
	lang := syntax.LangBash
	switch *langStr {
	case "bash", "":
	case "posix":
		lang = syntax.LangPOSIX
	case "mksh":
		lang = syntax.LangMirBSDKorn
	default:
		fmt.Fprintf(os.Stderr, "unknown shell language: %s\n", *langStr)
		os.Exit(1)
	}
	if *posix {
		lang = syntax.LangPOSIX
	}
	parser = syntax.NewParser(syntax.KeepComments, syntax.Variant(lang))
	printer = syntax.NewPrinter(func(p *syntax.Printer) {
		syntax.Indent(*indent)(p)
		if *binNext {
			syntax.BinaryNextLine(p)
		}
		if *caseIndent {
			syntax.SwitchCaseIndent(p)
		}
	})
	if flag.NArg() == 0 {
		if err := formatStdin(); err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		return
	}
	if *toJSON {
		fmt.Fprintln(os.Stderr, "-tojson can only be used with stdin/out")
		os.Exit(1)
	}
	anyErr := false
	for _, path := range flag.Args() {
		walk(path, func(err error) {
			anyErr = true
			fmt.Fprintln(os.Stderr, err)
		})
	}
	if anyErr {
		os.Exit(1)
	}
}

func formatStdin() error {
	if *write || *list {
		return fmt.Errorf("-w and -l can only be used on files")
	}
	prog, err := parser.Parse(os.Stdin, "")
	if err != nil {
		return err
	}
	if *simple {
		syntax.Simplify(prog)
	}
	if *toJSON {
		return writeJSON(out, prog, true)
	}
	return printer.Print(out, prog)
}

var vcsDir = regexp.MustCompile(`^\.(git|svn|hg)$`)

func walk(path string, onError func(error)) {
	info, err := os.Stat(path)
	if err != nil {
		onError(err)
		return
	}
	if !info.IsDir() {
		if err := formatPath(path, false); err != nil {
			onError(err)
		}
		return
	}
	filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
		if info.IsDir() && vcsDir.MatchString(info.Name()) {
			return filepath.SkipDir
		}
		if err != nil {
			onError(err)
			return nil
		}
		conf := fileutil.CouldBeScript(info)
		if conf == fileutil.ConfNotScript {
			return nil
		}
		err = formatPath(path, conf == fileutil.ConfIfShebang)
		if err != nil && !os.IsNotExist(err) {
			onError(err)
		}
		return nil
	})
}

func formatPath(path string, checkShebang bool) error {
	openMode := os.O_RDONLY
	if *write {
		openMode = os.O_RDWR
	}
	f, err := os.OpenFile(path, openMode, 0)
	if err != nil {
		return err
	}
	defer f.Close()
	readBuf.Reset()
	if checkShebang {
		n, err := f.Read(copyBuf[:32])
		if err != nil {
			return err
		}
		if !fileutil.HasShebang(copyBuf[:n]) {
			return nil
		}
		readBuf.Write(copyBuf[:n])
	}
	if _, err := io.CopyBuffer(&readBuf, f, copyBuf); err != nil {
		return err
	}
	src := readBuf.Bytes()
	prog, err := parser.Parse(&readBuf, path)
	if err != nil {
		return err
	}
	if *simple {
		syntax.Simplify(prog)
	}
	writeBuf.Reset()
	printer.Print(&writeBuf, prog)
	res := writeBuf.Bytes()
	if !bytes.Equal(src, res) {
		if *list {
			if _, err := fmt.Fprintln(out, path); err != nil {
				return err
			}
		}
		if *write {
			if err := f.Truncate(0); err != nil {
				return err
			}
			if _, err := f.Seek(0, io.SeekStart); err != nil {
				return err
			}
			if _, err := f.Write(res); err != nil {
				return err
			}
			if err := f.Close(); err != nil {
				return err
			}
		}
	}
	if !*list && !*write {
		if _, err := out.Write(res); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>cmd/shfmt: provide a custom flag help text<commit_after>// Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main // import "mvdan.cc/sh/cmd/shfmt"

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"regexp"

	"mvdan.cc/sh/fileutil"
	"mvdan.cc/sh/syntax"
)

var (
	write       = flag.Bool("w", false, "write result to file instead of stdout")
	list        = flag.Bool("l", false, "list files whose formatting differs from shfmt's")
	simple      = flag.Bool("s", false, "simplify the code")
	langStr     = flag.String("ln", "", `language variant to parse (bash/posix/mksh) (default "bash")`)
	posix       = flag.Bool("p", false, "shorthand for -ln=posix")
	indent      = flag.Uint("i", 0, "indent: 0 for tabs (default), >0 for number of spaces")
	binNext     = flag.Bool("bn", false, "binary ops like && and | may start a line")
	caseIndent  = flag.Bool("ci", false, "switch cases will be indented")
	toJSON      = flag.Bool("exp.tojson", false, "print AST to stdout as a typed JSON")
	showVersion = flag.Bool("version", false, "show version and exit")

	parser            *syntax.Parser
	printer           *syntax.Printer
	readBuf, writeBuf bytes.Buffer

	copyBuf = make([]byte, 32*1024)

	out io.Writer = os.Stdout

	version = "v2.0.0"
)

func main() {
	flag.Usage = func() {
		fmt.Fprint(os.Stderr, `usage: shfmt [flags] [path ...]

  -l        list files whose formatting differs from shfmt's
  -w        write result to file instead of stdout
  -s        simplify the code
  -version  show version and exit

  -ln str   language variant to parse (bash/posix/mksh, default "bash")
  -p        shorthand for -ln=posix

  -i uint   indent: 0 for tabs (default), >0 for number of spaces
  -bn       binary ops like && and | may start a line
  -ci       switch cases will be indented

  -exp.tojson  print AST to stdout as a typed JSON
`)
	}
	flag.Parse()

	if *showVersion {
		fmt.Println(version)
		return
	}
	if *posix && *langStr != "" {
		fmt.Fprintf(os.Stderr, "-p and -ln=lang cannot coexist\n")
		os.Exit(1)
	}
	lang := syntax.LangBash
	switch *langStr {
	case "bash", "":
	case "posix":
		lang = syntax.LangPOSIX
	case "mksh":
		lang = syntax.LangMirBSDKorn
	default:
		fmt.Fprintf(os.Stderr, "unknown shell language: %s\n", *langStr)
		os.Exit(1)
	}
	if *posix {
		lang = syntax.LangPOSIX
	}
	parser = syntax.NewParser(syntax.KeepComments, syntax.Variant(lang))
	printer = syntax.NewPrinter(func(p *syntax.Printer) {
		syntax.Indent(*indent)(p)
		if *binNext {
			syntax.BinaryNextLine(p)
		}
		if *caseIndent {
			syntax.SwitchCaseIndent(p)
		}
	})
	if flag.NArg() == 0 {
		if err := formatStdin(); err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		return
	}
	if *toJSON {
		fmt.Fprintln(os.Stderr, "-tojson can only be used with stdin/out")
		os.Exit(1)
	}
	anyErr := false
	for _, path := range flag.Args() {
		walk(path, func(err error) {
			anyErr = true
			fmt.Fprintln(os.Stderr, err)
		})
	}
	if anyErr {
		os.Exit(1)
	}
}

func formatStdin() error {
	if *write || *list {
		return fmt.Errorf("-w and -l can only be used on files")
	}
	prog, err := parser.Parse(os.Stdin, "")
	if err != nil {
		return err
	}
	if *simple {
		syntax.Simplify(prog)
	}
	if *toJSON {
		return writeJSON(out, prog, true)
	}
	return printer.Print(out, prog)
}

var vcsDir = regexp.MustCompile(`^\.(git|svn|hg)$`)

func walk(path string, onError func(error)) {
	info, err := os.Stat(path)
	if err != nil {
		onError(err)
		return
	}
	if !info.IsDir() {
		if err := formatPath(path, false); err != nil {
			onError(err)
		}
		return
	}
	filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
		if info.IsDir() && vcsDir.MatchString(info.Name()) {
			return filepath.SkipDir
		}
		if err != nil {
			onError(err)
			return nil
		}
		conf := fileutil.CouldBeScript(info)
		if conf == fileutil.ConfNotScript {
			return nil
		}
		err = formatPath(path, conf == fileutil.ConfIfShebang)
		if err != nil && !os.IsNotExist(err) {
			onError(err)
		}
		return nil
	})
}

func formatPath(path string, checkShebang bool) error {
	openMode := os.O_RDONLY
	if *write {
		openMode = os.O_RDWR
	}
	f, err := os.OpenFile(path, openMode, 0)
	if err != nil {
		return err
	}
	defer f.Close()
	readBuf.Reset()
	if checkShebang {
		n, err := f.Read(copyBuf[:32])
		if err != nil {
			return err
		}
		if !fileutil.HasShebang(copyBuf[:n]) {
			return nil
		}
		readBuf.Write(copyBuf[:n])
	}
	if _, err := io.CopyBuffer(&readBuf, f, copyBuf); err != nil {
		return err
	}
	src := readBuf.Bytes()
	prog, err := parser.Parse(&readBuf, path)
	if err != nil {
		return err
	}
	if *simple {
		syntax.Simplify(prog)
	}
	writeBuf.Reset()
	printer.Print(&writeBuf, prog)
	res := writeBuf.Bytes()
	if !bytes.Equal(src, res) {
		if *list {
			if _, err := fmt.Fprintln(out, path); err != nil {
				return err
			}
		}
		if *write {
			if err := f.Truncate(0); err != nil {
				return err
			}
			if _, err := f.Seek(0, io.SeekStart); err != nil {
				return err
			}
			if _, err := f.Write(res); err != nil {
				return err
			}
			if err := f.Close(); err != nil {
				return err
			}
		}
	}
	if !*list && !*write {
		if _, err := out.Write(res); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main

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

	"github.com/mvdan/sh"
)

var (
	write  = flag.Bool("w", false, "write result to file instead of stdout")
	list   = flag.Bool("l", false, "list files whose formatting differs from shfmt's")
	indent = flag.Int("i", 0, "indent: 0 for tabs (default), >0 for number of spaces")
)

var (
	config sh.PrintConfig
	buf    bytes.Buffer
)

func main() {
	flag.Parse()
	config.Spaces = *indent
	if flag.NArg() == 0 {
		if err := formatStdin(); err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		return
	}
	anyErr := false
	onError := func(err error) {
		anyErr = true
		fmt.Fprintln(os.Stderr, err)
	}
	for _, path := range flag.Args() {
		if err := walk(path, onError); err != nil {
			onError(err)
		}
	}
	if anyErr {
		os.Exit(1)
	}
}

func formatStdin() error {
	if *write || *list {
		return fmt.Errorf("-w and -l can only be used on files")
	}
	src, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		return err
	}
	prog, err := sh.Parse(src, "", sh.ParseComments)
	if err != nil {
		return err
	}
	return config.Fprint(os.Stdout, prog)
}

var (
	hidden    = regexp.MustCompile(`^\.[^/.]`)
	shellFile = regexp.MustCompile(`^.*\.(sh|bash)$`)
	shebang   = regexp.MustCompile(`^#!/(usr/)?bin/(env *)?(sh|bash)`)
)

func walk(path string, onError func(error)) error {
	info, err := os.Stat(path)
	if err != nil {
		return err
	}
	if !info.IsDir() {
		return formatPath(path, 0, true)
	}
	return filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
		if hidden.MatchString(path) {
			return filepath.SkipDir
		}
		if info.IsDir() {
			return nil
		}
		if err := formatPath(path, info.Size(), false); err != nil {
			onError(err)
		}
		return nil
	})
}

func empty(f *os.File) error {
	if err := f.Truncate(0); err != nil {
		return err
	}
	_, err := f.Seek(0, 0)
	return err
}

func validShebang(bs []byte) bool {
	return shebang.Match(bs[:32])
}

func formatPath(path string, size int64, always bool) error {
	shellExt := always || shellFile.MatchString(path)
	if !shellExt && strings.Contains(path, ".") {
		// has an unwanted extension
		return nil
	}
	if !shellExt && size < 8 {
		// cannot possibly hold valid shebang
		return nil
	}
	mode := os.O_RDONLY
	if *write {
		mode = os.O_RDWR
	}
	f, err := os.OpenFile(path, mode, 0)
	if err != nil {
		return err
	}
	defer f.Close()
	src, err := ioutil.ReadAll(f)
	if err != nil {
		return err
	}
	if !shellExt && !validShebang(src) {
		return nil
	}
	prog, err := sh.Parse(src, path, sh.ParseComments)
	if err != nil {
		return err
	}
	buf.Reset()
	if err := config.Fprint(&buf, prog); err != nil {
		return err
	}
	res := buf.Bytes()
	if !bytes.Equal(src, res) {
		if *list {
			fmt.Println(path)
		}
		if *write {
			if err := empty(f); err != nil {
				return err
			}
			if _, err := f.Write(res); err != nil {
				return err
			}
		}
	}
	if !*list && !*write {
		if _, err := os.Stdout.Write(res); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>cmd/shfmt: simplify shebang code<commit_after>// Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main

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

	"github.com/mvdan/sh"
)

var (
	write  = flag.Bool("w", false, "write result to file instead of stdout")
	list   = flag.Bool("l", false, "list files whose formatting differs from shfmt's")
	indent = flag.Int("i", 0, "indent: 0 for tabs (default), >0 for number of spaces")
)

var (
	config sh.PrintConfig
	buf    bytes.Buffer
)

func main() {
	flag.Parse()
	config.Spaces = *indent
	if flag.NArg() == 0 {
		if err := formatStdin(); err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		return
	}
	anyErr := false
	onError := func(err error) {
		anyErr = true
		fmt.Fprintln(os.Stderr, err)
	}
	for _, path := range flag.Args() {
		if err := walk(path, onError); err != nil {
			onError(err)
		}
	}
	if anyErr {
		os.Exit(1)
	}
}

func formatStdin() error {
	if *write || *list {
		return fmt.Errorf("-w and -l can only be used on files")
	}
	src, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		return err
	}
	prog, err := sh.Parse(src, "", sh.ParseComments)
	if err != nil {
		return err
	}
	return config.Fprint(os.Stdout, prog)
}

var (
	hidden       = regexp.MustCompile(`^\.[^/.]`)
	shellFile    = regexp.MustCompile(`^.*\.(sh|bash)$`)
	validShebang = regexp.MustCompile(`^#!/(usr/)?bin/(env *)?(sh|bash)`)
)

func walk(path string, onError func(error)) error {
	info, err := os.Stat(path)
	if err != nil {
		return err
	}
	if !info.IsDir() {
		return formatPath(path, 0, true)
	}
	return filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
		if hidden.MatchString(path) {
			return filepath.SkipDir
		}
		if info.IsDir() {
			return nil
		}
		if err := formatPath(path, info.Size(), false); err != nil {
			onError(err)
		}
		return nil
	})
}

func empty(f *os.File) error {
	if err := f.Truncate(0); err != nil {
		return err
	}
	_, err := f.Seek(0, 0)
	return err
}

func formatPath(path string, size int64, always bool) error {
	shellExt := always || shellFile.MatchString(path)
	if !shellExt && strings.Contains(path, ".") {
		// has an unwanted extension
		return nil
	}
	if !shellExt && size < 8 {
		// cannot possibly hold valid shebang
		return nil
	}
	mode := os.O_RDONLY
	if *write {
		mode = os.O_RDWR
	}
	f, err := os.OpenFile(path, mode, 0)
	if err != nil {
		return err
	}
	defer f.Close()
	src, err := ioutil.ReadAll(f)
	if err != nil {
		return err
	}
	if !shellExt && !validShebang.Match(src[:32]) {
		return nil
	}
	prog, err := sh.Parse(src, path, sh.ParseComments)
	if err != nil {
		return err
	}
	buf.Reset()
	if err := config.Fprint(&buf, prog); err != nil {
		return err
	}
	res := buf.Bytes()
	if !bytes.Equal(src, res) {
		if *list {
			fmt.Println(path)
		}
		if *write {
			if err := empty(f); err != nil {
				return err
			}
			if _, err := f.Write(res); err != nil {
				return err
			}
		}
	}
	if !*list && !*write {
		if _, err := os.Stdout.Write(res); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"flag"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/atlassian/smith/cmd/smith/app"
	"github.com/atlassian/smith/pkg/client"

	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/rest"
)

const (
	defaultResyncPeriod = 20 * time.Minute
)

func main() {
	if err := run(); err != nil && err != context.Canceled && err != context.DeadlineExceeded {
		log.Fatalln(err)
	}
}

func run() error {
	ctx, cancelFunc := context.WithCancel(context.Background())
	defer cancelFunc()
	cancelOnInterrupt(ctx, cancelFunc)

	return runWithContext(ctx)
}

func runWithContext(ctx context.Context) error {
	a := app.App{
		Workers: 2,
	}

	fs := flag.NewFlagSet(os.Args[0], flag.ExitOnError)
	fs.BoolVar(&a.DisablePodPreset, "disable-pod-preset", false, "Disable PodPreset support")
	scUrl := fs.String("service-catalog-url", "", "Service Catalog API server URL")
	fs.DurationVar(&a.ResyncPeriod, "resync-period", defaultResyncPeriod, "Resync period for informers")
	fs.StringVar(&a.Namespace, "namespace", meta_v1.NamespaceAll, "Namespace to use. All namespaces are used if empty string or omitted")
	fs.Parse(os.Args[1:]) // nolint: gas

	config, err := client.ConfigFromEnv()
	if err != nil {
		config, err = rest.InClusterConfig()
		if err != nil {
			return err
		}
	}
	config.UserAgent = "smith/" + Version + "/" + GitCommit
	a.RestConfig = config
	if *scUrl != "" {
		scConfig := *config // shallow copy
		scConfig.Host = *scUrl
		scConfig.TLSClientConfig = rest.TLSClientConfig{
			Insecure: true,
		}
		a.ServiceCatalogConfig = &scConfig
	}

	return a.Run(ctx)
}

// cancelOnInterrupt calls f when os.Interrupt or SIGTERM is received.
// It ignores subsequent interrupts on purpose - program should exit correctly after the first signal.
func cancelOnInterrupt(ctx context.Context, f context.CancelFunc) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		select {
		case <-ctx.Done():
		case <-c:
			f()
		}
	}()
}
<commit_msg>Allow Service Catalog to be enabled without explicit URL<commit_after>package main

import (
	"context"
	"flag"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/atlassian/smith/cmd/smith/app"
	"github.com/atlassian/smith/pkg/client"

	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/rest"
)

const (
	defaultResyncPeriod = 20 * time.Minute
)

func main() {
	if err := run(); err != nil && err != context.Canceled && err != context.DeadlineExceeded {
		log.Fatalln(err)
	}
}

func run() error {
	ctx, cancelFunc := context.WithCancel(context.Background())
	defer cancelFunc()
	cancelOnInterrupt(ctx, cancelFunc)

	return runWithContext(ctx)
}

func runWithContext(ctx context.Context) error {
	a := app.App{
		Workers: 2,
	}

	fs := flag.NewFlagSet(os.Args[0], flag.ExitOnError)
	fs.BoolVar(&a.DisablePodPreset, "disable-pod-preset", false, "Disable PodPreset support")
	scDisable := fs.Bool("disable-service-catalog", false, "Disable Service Catalog support")
	scUrl := fs.String("service-catalog-url", "", "Service Catalog API server URL")
	scInsecure := fs.Bool("service-catalog-insecure", false, "Disable TLS validation for Service Catalog")
	fs.DurationVar(&a.ResyncPeriod, "resync-period", defaultResyncPeriod, "Resync period for informers")
	fs.StringVar(&a.Namespace, "namespace", meta_v1.NamespaceAll, "Namespace to use. All namespaces are used if empty string or omitted")
	fs.Parse(os.Args[1:]) // nolint: gas

	config, err := client.ConfigFromEnv()
	if err != nil {
		config, err = rest.InClusterConfig()
		if err != nil {
			return err
		}
	}
	config.UserAgent = "smith/" + Version + "/" + GitCommit
	a.RestConfig = config
	if !*scDisable {
		scConfig := *config // shallow copy
		scConfig.TLSClientConfig.Insecure = *scInsecure
		if *scUrl != "" {
			scConfig.Host = *scUrl
		}
		a.ServiceCatalogConfig = &scConfig
	}

	return a.Run(ctx)
}

// cancelOnInterrupt calls f when os.Interrupt or SIGTERM is received.
// It ignores subsequent interrupts on purpose - program should exit correctly after the first signal.
func cancelOnInterrupt(ctx context.Context, f context.CancelFunc) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		select {
		case <-ctx.Done():
		case <-c:
			f()
		}
	}()
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/signal"
	"runtime/pprof"
	"syscall"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/spf13/cobra"
	"gopkg.in/yaml.v2"

	"github.com/jzelinskie/trakr/backend"
	httpfrontend "github.com/jzelinskie/trakr/frontend/http"
	udpfrontend "github.com/jzelinskie/trakr/frontend/udp"
)

type ConfigFile struct {
	Config struct {
		PrometheusAddr string `yaml:"prometheus_addr"`
		backend.BackendConfig
		HTTPConfig httpfrontend.Config `yaml:"http"`
		UDPConfig  udpfrontend.Config  `yaml:"udp"`
	} `yaml:"trakr"`
}

// ParseConfigFile returns a new ConfigFile given the path to a YAML
// configuration file.
//
// It supports relative and absolute paths and environment variables.
func ParseConfigFile(path string) (*ConfigFile, error) {
	if path == "" {
		return nil, errors.New("no config path specified")
	}

	f, err := os.Open(os.ExpandEnv(path))
	if err != nil {
		return nil, err
	}
	defer f.Close()

	contents, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}

	var cfgFile ConfigFile
	err = yaml.Unmarshal(contents, &cfgFile)
	if err != nil {
		return nil, err
	}

	return &cfgFile, nil
}

func main() {
	var configFilePath string
	var cpuProfilePath string

	var rootCmd = &cobra.Command{
		Use:   "trakr",
		Short: "BitTorrent Tracker",
		Long:  "A customizible, multi-protocol BitTorrent Tracker",
		Run: func(cmd *cobra.Command, args []string) {
			if err := func() error {
				if cpuProfilePath != "" {
					log.Println("enabled CPU profiling to " + cpuProfilePath)
					f, err := os.Create(cpuProfilePath)
					if err != nil {
						return err
					}
					pprof.StartCPUProfile(f)
					defer pprof.StopCPUProfile()
				}

				configFile, err := ParseConfigFile(configFilePath)
				if err != nil {
					return errors.New("failed to read config: " + err.Error())
				}

				go func() {
					promServer := http.Server{
						Addr:    configFile.Config.PrometheusAddr,
						Handler: prometheus.Handler(),
					}
					log.Println("started serving prometheus stats on", configFile.Config.PrometheusAddr)
					if err := promServer.ListenAndServe(); err != nil {
						log.Fatal(err)
					}
				}()

				// TODO create PeerStore
				// TODO create Hooks
				trackerBackend, err := backend.New(configFile.Config.BackendConfig, nil, nil, nil, nil, nil)
				if err != nil {
					return err
				}

				errChan := make(chan error)
				closedChan := make(chan struct{})

				var hFrontend *httpfrontend.Frontend
				var uFrontend *udpfrontend.Frontend

				if configFile.Config.HTTPConfig.Addr != "" {
					// TODO get the real TrackerLogic
					hFrontend = httpfrontend.NewFrontend(trackerBackend, configFile.Config.HTTPConfig)

					go func() {
						log.Println("started serving HTTP on", configFile.Config.HTTPConfig.Addr)
						if err := hFrontend.ListenAndServe(); err != nil {
							errChan <- errors.New("failed to cleanly shutdown HTTP frontend: " + err.Error())
						}
					}()
				}

				if configFile.Config.UDPConfig.Addr != "" {
					// TODO get the real TrackerLogic
					uFrontend = udpfrontend.NewFrontend(trackerBackend, configFile.Config.UDPConfig)

					go func() {
						log.Println("started serving UDP on", configFile.Config.UDPConfig.Addr)
						if err := uFrontend.ListenAndServe(); err != nil {
							errChan <- errors.New("failed to cleanly shutdown UDP frontend: " + err.Error())
						}
					}()
				}

				shutdown := make(chan os.Signal)
				signal.Notify(shutdown, syscall.SIGINT, syscall.SIGTERM)
				go func() {
					<-shutdown

					if uFrontend != nil {
						uFrontend.Stop()
					}

					if hFrontend != nil {
						hFrontend.Stop()
					}

					// TODO: stop PeerStore

					close(errChan)
					close(closedChan)
				}()

				for err := range errChan {
					if err != nil {
						close(shutdown)
						<-closedChan
						return err
					}
				}

				return nil
			}(); err != nil {
				log.Fatal(err)
			}
		},
	}

	rootCmd.Flags().StringVar(&configFilePath, "config", "/etc/trakr.yaml", "location of configuration file (defaults to /etc/trakr.yaml)")
	rootCmd.Flags().StringVarP(&cpuProfilePath, "cpuprofile", "", "", "location to save a CPU profile")

	if err := rootCmd.Execute(); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>remove default text (this is generated automatically)<commit_after>package main

import (
	"errors"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/signal"
	"runtime/pprof"
	"syscall"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/spf13/cobra"
	"gopkg.in/yaml.v2"

	"github.com/jzelinskie/trakr/backend"
	httpfrontend "github.com/jzelinskie/trakr/frontend/http"
	udpfrontend "github.com/jzelinskie/trakr/frontend/udp"
)

type ConfigFile struct {
	Config struct {
		PrometheusAddr string `yaml:"prometheus_addr"`
		backend.BackendConfig
		HTTPConfig httpfrontend.Config `yaml:"http"`
		UDPConfig  udpfrontend.Config  `yaml:"udp"`
	} `yaml:"trakr"`
}

// ParseConfigFile returns a new ConfigFile given the path to a YAML
// configuration file.
//
// It supports relative and absolute paths and environment variables.
func ParseConfigFile(path string) (*ConfigFile, error) {
	if path == "" {
		return nil, errors.New("no config path specified")
	}

	f, err := os.Open(os.ExpandEnv(path))
	if err != nil {
		return nil, err
	}
	defer f.Close()

	contents, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}

	var cfgFile ConfigFile
	err = yaml.Unmarshal(contents, &cfgFile)
	if err != nil {
		return nil, err
	}

	return &cfgFile, nil
}

func main() {
	var configFilePath string
	var cpuProfilePath string

	var rootCmd = &cobra.Command{
		Use:   "trakr",
		Short: "BitTorrent Tracker",
		Long:  "A customizible, multi-protocol BitTorrent Tracker",
		Run: func(cmd *cobra.Command, args []string) {
			if err := func() error {
				if cpuProfilePath != "" {
					log.Println("enabled CPU profiling to " + cpuProfilePath)
					f, err := os.Create(cpuProfilePath)
					if err != nil {
						return err
					}
					pprof.StartCPUProfile(f)
					defer pprof.StopCPUProfile()
				}

				configFile, err := ParseConfigFile(configFilePath)
				if err != nil {
					return errors.New("failed to read config: " + err.Error())
				}

				go func() {
					promServer := http.Server{
						Addr:    configFile.Config.PrometheusAddr,
						Handler: prometheus.Handler(),
					}
					log.Println("started serving prometheus stats on", configFile.Config.PrometheusAddr)
					if err := promServer.ListenAndServe(); err != nil {
						log.Fatal(err)
					}
				}()

				// TODO create PeerStore
				// TODO create Hooks
				trackerBackend, err := backend.New(configFile.Config.BackendConfig, nil, nil, nil, nil, nil)
				if err != nil {
					return err
				}

				errChan := make(chan error)
				closedChan := make(chan struct{})

				var hFrontend *httpfrontend.Frontend
				var uFrontend *udpfrontend.Frontend

				if configFile.Config.HTTPConfig.Addr != "" {
					// TODO get the real TrackerLogic
					hFrontend = httpfrontend.NewFrontend(trackerBackend, configFile.Config.HTTPConfig)

					go func() {
						log.Println("started serving HTTP on", configFile.Config.HTTPConfig.Addr)
						if err := hFrontend.ListenAndServe(); err != nil {
							errChan <- errors.New("failed to cleanly shutdown HTTP frontend: " + err.Error())
						}
					}()
				}

				if configFile.Config.UDPConfig.Addr != "" {
					// TODO get the real TrackerLogic
					uFrontend = udpfrontend.NewFrontend(trackerBackend, configFile.Config.UDPConfig)

					go func() {
						log.Println("started serving UDP on", configFile.Config.UDPConfig.Addr)
						if err := uFrontend.ListenAndServe(); err != nil {
							errChan <- errors.New("failed to cleanly shutdown UDP frontend: " + err.Error())
						}
					}()
				}

				shutdown := make(chan os.Signal)
				signal.Notify(shutdown, syscall.SIGINT, syscall.SIGTERM)
				go func() {
					<-shutdown

					if uFrontend != nil {
						uFrontend.Stop()
					}

					if hFrontend != nil {
						hFrontend.Stop()
					}

					// TODO: stop PeerStore

					close(errChan)
					close(closedChan)
				}()

				for err := range errChan {
					if err != nil {
						close(shutdown)
						<-closedChan
						return err
					}
				}

				return nil
			}(); err != nil {
				log.Fatal(err)
			}
		},
	}

	rootCmd.Flags().StringVar(&configFilePath, "config", "/etc/trakr.yaml", "location of configuration file")
	rootCmd.Flags().StringVarP(&cpuProfilePath, "cpuprofile", "", "", "location to save a CPU profile")

	if err := rootCmd.Execute(); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2012-2017 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// boot allows to handover a system running linuxboot/u-root
// to a legacy preinstalled operating system by replacing the traditional
// bootloader path

//
// Synopsis:
//	boot
//
// Description:
//	If returns to u-root shell, the code didn't found a local bootable option
//
// Notes:
//	The code is looking for boot/grub/grub.cfg file as to identify the
//	boot option.
//	The first bootable device found in the block device tree is the one used
//	Windows is not supported (that is a work in progress)
//
// Example:
//	boot -v 	- Start the script in verbose mode for debugging purpose

package main

import (
	"bufio"
	"encoding/binary"
	"fmt"
	"github.com/u-root/u-root/pkg/kexec"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
	"flag"
	"syscall"
)

const (
	bootableMBR = 0xaa55
	signatureOffset = 510
)

var verbose bool
type options struct {
        verbose bool
}

func blkDevicesList(blkpath string, devpath string) ([]string,error) {
	var blkDevices []string
	files, err := ioutil.ReadDir(blkpath)
	if err != nil {
		return blkDevices,err
	}
	for _, file := range files {
		check,err := os.Stat(blkpath + file.Name() + devpath)
		if ( check == nil ) {
                        continue
                }
                if ( err != nil ) {
                        continue
                }
		deviceEntry, err := ioutil.ReadDir(blkpath + file.Name() + devpath)
		if err != nil {
			if ( verbose ) {
				log.Printf("can t read directory")
			}
			continue
		}
		blkDevices = append(blkDevices, deviceEntry[0].Name())
	}
	return blkDevices,nil
}

// checkForBootableMBR is looking for bootable MBR signature
// Current support is limited to Hard disk devices and USB devices
func checkForBootableMBR(path string) (bool,error) {
	var sig uint16
	f, err := os.Open(path)
	if err != nil {
		return false, err
	}
	if err := binary.Read(io.NewSectionReader(f, signatureOffset, 2), binary.LittleEndian, &sig); err != nil {
		return false,err
	}
	if sig != bootableMBR {
		return false, nil
	}
	return true,nil
}

// getDevicePartList returns all devices attached to a specific name like /dev/sdaX where X can move from 0 to 127
// FIXME no support for devices which are included into subdirectory within /dev
func getDevicePartList(path string) ([]string,error) {
	var returnValue []string
	files, err := ioutil.ReadDir("/dev/")
	if err != nil {
		return returnValue, err
	}
	for _, file := range files {
		if strings.HasPrefix(file.Name(), path) {
			// We shall not return full device name
			if file.Name() != path {
				// We shall check that the remaining part is a number
				returnValue = append(returnValue, file.Name())
			}
		}
	}
	return returnValue, nil
}

// getSupportedFilesystem returns all block file system supported by the linuxboot kernel
func getSupportedFilesystem() ([]string, error) {
	var returnValue []string
	var err error
	fs, err := ioutil.ReadFile("/proc/filesystems")
	if err != nil {
		return returnValue, err
	}
	for _, f := range strings.Split(string(fs), "\n") {
		n := strings.Fields(f)
		if len(n) != 1 {
			continue
		}
		returnValue=append(returnValue,n[0])
	}
	return returnValue, err

}

// mountEntry tries to mount a specific block device
func mountEntry(path string, supportedFilesystem []string) (bool,error) {
	var returnValue bool
	var err error
	exist, err := os.Stat("/u-root")
        if exist == nil {
                err=syscall.Mkdir("/u-root", 0777)
                if ( err != nil ) {
                        return false,err
                }
        }
	var flags uintptr
	// Was supposed to be unecessary for kernel 4.x.x
	if verbose {
		log.Printf("/dev/" + path)
	}
	for _, filesystem := range supportedFilesystem {
		flags = syscall.MS_MGC_VAL
		// Need to load the filesystem kind supported
		exist, err = os.Stat("/u-root/"+path)
                if exist == nil {
                        err = syscall.Mkdir("/u-root/"+path, 0777)
                        if ( err != nil ) {
                                return false,err
                        }
                }
		err := syscall.Mount("/dev/"+path, "/u-root/"+path, filesystem, flags, "")
		if err == nil {
			return true, nil
		}
	}
	returnValue = false
	return returnValue, nil
}

func umountEntry(path string) bool {
	var returnValue bool
	var flags int
	// Was supposed to be unecessary for kernel 4.x.x
	flags = syscall.MNT_DETACH
	err := syscall.Unmount(path, flags)
	if err == nil {
		return true
	}
	returnValue = false
	return returnValue
}

// checkBootEntry is looking for grub.cfg file
// and return absolute path to it
func checkBootEntry(mountPoint string) string {
	_, err := os.Stat(mountPoint + "/boot")
	if err == nil {
		// The boot directory is there
		_, err2 := os.Stat(mountPoint + "/boot" + "/grub")
		if err2 == nil {
			_, err3 := os.Stat(mountPoint + "/boot" + "/grub" + "/grub.cfg")
			if err3 == nil {
				// found
				return (mountPoint + "/boot" + "/grub")
			}
		}
	}
	return ""

}

// getFileMenuContent is parsing a grub.cfg file
// input: absolute directory path to grub.cfg
// output: Return a list of strings with the following format
//	 line[3*x] - menuconfig
//	 line[3*x+1] - linux kernel + boot options
// 	 line[3*x+2] - initrd
// and the default boot entry configured into grub.cfg
func getFileMenuContent(path string) ([]string, int, error) {
	var returnValue []string
	var err error
	file, err := os.Open(path + "/grub.cfg")
	if ( err != nil ) {
		return returnValue,0,err
	}
	scanner := bufio.NewScanner(file)
	if err = scanner.Err(); err != nil {
		return returnValue,0,err
	}
	var status int
	var intReturn int
	intReturn = 0
	status = 0
	// When status = 0 we are looking for a menu entry
	// When status = 1 we are looking for a linux entry
	// When status = 2 we are looking for a initrd entry
	var trimmedLine string
	for scanner.Scan() {
		trimmedLine = strings.TrimSpace(scanner.Text())
		trimmedLine = strings.Join(strings.Fields(trimmedLine), " ")
		if strings.HasPrefix(trimmedLine, "#") {
			continue
		}
		if (strings.HasPrefix(trimmedLine, "set default=") ) && (status == 0) {
			fmt.Sscanf(trimmedLine, "set default=\"%d\"", &intReturn)
		}
		if (strings.HasPrefix(trimmedLine, "menuentry ")) && (status == 0) {
			status = 1
			returnValue = append(returnValue, trimmedLine)
		}
		if (strings.HasPrefix(trimmedLine, "linux ")) && (status == 1) {
			status = 2
			returnValue = append(returnValue, trimmedLine)
		}
		if (strings.HasPrefix(trimmedLine, "initrd ")) && (status == 2) {
			status = 0
			returnValue = append(returnValue, trimmedLine)
		}
	}
	err = file.Close()
	return returnValue, intReturn, err

}

func copyLocal(path string) (string,error) {
	var dest string
	var err error
	result := strings.Split(path, "/")
	for _, entry := range result {
		dest = entry
	}
	dest = "/tmp/" + dest
	srcFile, err := os.Open(path)
	if ( err != nil ) {
		return dest, err
	}

	destFile, err := os.Create(dest) // creates if file doesn't exist
	if ( err != nil ) {
		return dest, err
        }

	_, err = io.Copy(destFile, srcFile) // check first var for number of bytes copied
	if ( err != nil ) {
		return dest, err
        }

	err = destFile.Sync()
	if ( err != nil ) {
		return dest, err
        }
	err = destFile.Close()
	if ( err != nil ) {
		return dest, err
        }
	err = srcFile.Close()
	if ( err != nil ) {
		return dest, err
        }
	return dest, nil
}

// kexecEntry is booting new kernel based on the content of grub.cfg
func kexecEntry(grubConfPath string, mountPoint string) error {
	var fileMenuContent []string
	var entry int
	var localKernelPath string
	var localInitrdPath string
	if verbose {
		log.Printf(grubConfPath)
	}
	fileMenuContent, entry, err := getFileMenuContent(grubConfPath)
	if ( err != nil ) {
		return err
	}
	var kernel string
	var kernelParameter string
	var initrd string
	var kernelInfos []string
	kernelInfos = strings.Fields(fileMenuContent[3*entry+1])
	kernel = kernelInfos[1]
	var count int
	count = 0
	for _, field := range kernelInfos {
		if count > 1 {
			kernelParameter = kernelParameter + " " + field
		}
		count = count + 1
	}
	fmt.Sscanf(fileMenuContent[3*entry+2], "initrd %s", &initrd)
	if verbose {
		log.Printf("************** boot parameters  ********************")
		log.Printf(kernel)
		log.Printf(kernelParameter)
		log.Printf(initrd)
		log.Printf("****************************************************")
	}
	localKernelPath,err = copyLocal(mountPoint + kernel)
	if ( err != nil ) {
		return err
	}
	localInitrdPath,err = copyLocal(mountPoint + initrd)
	if ( err != nil ) {
		return err
	}
	if verbose {
		log.Printf(localKernelPath)
	}
	umountEntry(mountPoint)
	// We can kexec the kernel with localKernelPath as kernel entry, kernelParameter as parameter and initrd as initrd !
	log.Printf("Loading %s for kernel\n", localKernelPath)

	kernelDesc, err := os.OpenFile(localKernelPath, os.O_RDONLY, 0)
	if err != nil {
		return err
	}
	// defer kernelDesc.Close()

	var ramfs *os.File
	ramfs, err = os.OpenFile(localInitrdPath, os.O_RDONLY, 0)
	if err != nil {
		return err
	}
	// defer ramfs.Close()

	if err := kexec.FileLoad(kernelDesc, ramfs, kernelParameter); err != nil {
		return err
	}
 	err = ramfs.Close()
	if ( err != nil ) {
		return err
	}
	err = kernelDesc.Close()
	if ( err != nil ) {
		return err
	}
	if err := kexec.Reboot(); err != nil {
		return err
	}
	return err

}

func registerFlags(f *flag.FlagSet) *options {
        o := &options{}
        f.BoolVar(&o.verbose, "v", false, "Set verbose output")
        return o
}

func main() {
	var blkList []string
	var supportedFilesystem []string
	verbose = false
        opts := registerFlags(flag.CommandLine)
	flag.Parse()

        if opts.verbose != false {
		verbose = true
        }

	supportedFilesystem, err := getSupportedFilesystem()
	if ( err != nil ) {
                log.Panic("No filesystem support found")
        }
	if verbose {
		log.Printf("************** Supported Filesystem by current linuxboot ********************")
		for _, filesystem := range supportedFilesystem {
			log.Printf(filesystem)
		}
		log.Printf("*****************************************************************************")
	}
	blkList,err = blkDevicesList("/sys/dev/block/", "/device/block/")
	if ( err != nil ) {
		log.Fatal("No available block devices to boot from")
	}
	// We must validate if the MBR is bootable or not and keep the
	// devices which do have such support
	// drive are easy to detect
	for _, entry := range blkList {
		dev := filepath.Join("/dev", entry)
		b, err := checkForBootableMBR(dev)
		if err != nil {
			// Not sure it matters; there can be many bogus entries?
			log.Printf("MBR for %s failed: %v", dev, err)
		}
		if b {
			fmt.Println("Bootable device found")
			// We need to loop on the device entries which are into /dev/<device>X
			// and mount each partitions as to find /boot entry if it is available somewhere
			var devicePartList []string
			devicePartList,err := getDevicePartList(entry)
			if ( err != nil ) {
				continue
			}
			for _, deviceList := range devicePartList {
				mount, err := mountEntry(deviceList, supportedFilesystem)
				if ( err != nil ) {
					continue
				}
				if mount {
					if verbose {
						log.Printf("mount succeed")
					}
					var grubConfPath = checkBootEntry("/u-root/" + deviceList)
					if grubConfPath != "" {
						if verbose {
							log.Printf("calling basic kexec")
						}
						err = kexecEntry(grubConfPath, "/u-root/"+deviceList)
						if ( err != nil ) {
							log.Fatal("kexec failed")
						}
					}
				}
				umountEntry("/u-root/" + deviceList)
			}
		}
	}
	log.Printf("Sorry no bootable device found")
}
<commit_msg>enhance checkForBootableMBR return value by reporting only error when MBR is not identified as bootable<commit_after>// Copyright 2012-2017 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// boot allows to handover a system running linuxboot/u-root
// to a legacy preinstalled operating system by replacing the traditional
// bootloader path

//
// Synopsis:
//	boot
//
// Description:
//	If returns to u-root shell, the code didn't found a local bootable option
//
// Notes:
//	The code is looking for boot/grub/grub.cfg file as to identify the
//	boot option.
//	The first bootable device found in the block device tree is the one used
//	Windows is not supported (that is a work in progress)
//
// Example:
//	boot -v 	- Start the script in verbose mode for debugging purpose

package main

import (
	"bufio"
	"encoding/binary"
	"errors"
	"fmt"
	"github.com/u-root/u-root/pkg/kexec"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
	"flag"
	"syscall"
)

const (
	bootableMBR = 0xaa55
	signatureOffset = 510
)

var verbose bool
type options struct {
        verbose bool
}

func blkDevicesList(blkpath string, devpath string) ([]string,error) {
	var blkDevices []string
	files, err := ioutil.ReadDir(blkpath)
	if err != nil {
		return blkDevices,err
	}
	for _, file := range files {
		check,err := os.Stat(blkpath + file.Name() + devpath)
		if ( check == nil ) {
                        continue
                }
                if ( err != nil ) {
                        continue
                }
		deviceEntry, err := ioutil.ReadDir(blkpath + file.Name() + devpath)
		if err != nil {
			if ( verbose ) {
				log.Printf("can t read directory")
			}
			continue
		}
		blkDevices = append(blkDevices, deviceEntry[0].Name())
	}
	return blkDevices,nil
}

// checkForBootableMBR is looking for bootable MBR signature
// Current support is limited to Hard disk devices and USB devices
func checkForBootableMBR(path string) error {
	var sig uint16
	f, err := os.Open(path)
	if err != nil {
		return err
	}
	if err := binary.Read(io.NewSectionReader(f, signatureOffset, 2), binary.LittleEndian, &sig); err != nil {
		return err
	}
	if sig != bootableMBR {
		err := errors.New("Not a bootable device")
		return err
	}
	return nil
}

// getDevicePartList returns all devices attached to a specific name like /dev/sdaX where X can move from 0 to 127
// FIXME no support for devices which are included into subdirectory within /dev
func getDevicePartList(path string) ([]string,error) {
	var returnValue []string
	files, err := ioutil.ReadDir("/dev/")
	if err != nil {
		return returnValue, err
	}
	for _, file := range files {
		if strings.HasPrefix(file.Name(), path) {
			// We shall not return full device name
			if file.Name() != path {
				// We shall check that the remaining part is a number
				returnValue = append(returnValue, file.Name())
			}
		}
	}
	return returnValue, nil
}

// getSupportedFilesystem returns all block file system supported by the linuxboot kernel
func getSupportedFilesystem() ([]string, error) {
	var returnValue []string
	var err error
	fs, err := ioutil.ReadFile("/proc/filesystems")
	if err != nil {
		return returnValue, err
	}
	for _, f := range strings.Split(string(fs), "\n") {
		n := strings.Fields(f)
		if len(n) != 1 {
			continue
		}
		returnValue=append(returnValue,n[0])
	}
	return returnValue, err

}

// mountEntry tries to mount a specific block device
func mountEntry(path string, supportedFilesystem []string) (bool,error) {
	var returnValue bool
	var err error
	exist, err := os.Stat("/u-root")
        if exist == nil {
                err=syscall.Mkdir("/u-root", 0777)
                if ( err != nil ) {
                        return false,err
                }
        }
	var flags uintptr
	// Was supposed to be unecessary for kernel 4.x.x
	if verbose {
		log.Printf("/dev/" + path)
	}
	for _, filesystem := range supportedFilesystem {
		flags = syscall.MS_MGC_VAL
		// Need to load the filesystem kind supported
		exist, err = os.Stat("/u-root/"+path)
                if exist == nil {
                        err = syscall.Mkdir("/u-root/"+path, 0777)
                        if ( err != nil ) {
                                return false,err
                        }
                }
		err := syscall.Mount("/dev/"+path, "/u-root/"+path, filesystem, flags, "")
		if err == nil {
			return true, nil
		}
	}
	returnValue = false
	return returnValue, nil
}

func umountEntry(path string) bool {
	var returnValue bool
	var flags int
	// Was supposed to be unecessary for kernel 4.x.x
	flags = syscall.MNT_DETACH
	err := syscall.Unmount(path, flags)
	if err == nil {
		return true
	}
	returnValue = false
	return returnValue
}

// checkBootEntry is looking for grub.cfg file
// and return absolute path to it
func checkBootEntry(mountPoint string) string {
	_, err := os.Stat(mountPoint + "/boot")
	if err == nil {
		// The boot directory is there
		_, err2 := os.Stat(mountPoint + "/boot" + "/grub")
		if err2 == nil {
			_, err3 := os.Stat(mountPoint + "/boot" + "/grub" + "/grub.cfg")
			if err3 == nil {
				// found
				return (mountPoint + "/boot" + "/grub")
			}
		}
	}
	return ""

}

// getFileMenuContent is parsing a grub.cfg file
// input: absolute directory path to grub.cfg
// output: Return a list of strings with the following format
//	 line[3*x] - menuconfig
//	 line[3*x+1] - linux kernel + boot options
// 	 line[3*x+2] - initrd
// and the default boot entry configured into grub.cfg
func getFileMenuContent(path string) ([]string, int, error) {
	var returnValue []string
	var err error
	file, err := os.Open(path + "/grub.cfg")
	if ( err != nil ) {
		return returnValue,0,err
	}
	scanner := bufio.NewScanner(file)
	if err = scanner.Err(); err != nil {
		return returnValue,0,err
	}
	var status int
	var intReturn int
	intReturn = 0
	status = 0
	// When status = 0 we are looking for a menu entry
	// When status = 1 we are looking for a linux entry
	// When status = 2 we are looking for a initrd entry
	var trimmedLine string
	for scanner.Scan() {
		trimmedLine = strings.TrimSpace(scanner.Text())
		trimmedLine = strings.Join(strings.Fields(trimmedLine), " ")
		if strings.HasPrefix(trimmedLine, "#") {
			continue
		}
		if (strings.HasPrefix(trimmedLine, "set default=") ) && (status == 0) {
			fmt.Sscanf(trimmedLine, "set default=\"%d\"", &intReturn)
		}
		if (strings.HasPrefix(trimmedLine, "menuentry ")) && (status == 0) {
			status = 1
			returnValue = append(returnValue, trimmedLine)
		}
		if (strings.HasPrefix(trimmedLine, "linux ")) && (status == 1) {
			status = 2
			returnValue = append(returnValue, trimmedLine)
		}
		if (strings.HasPrefix(trimmedLine, "initrd ")) && (status == 2) {
			status = 0
			returnValue = append(returnValue, trimmedLine)
		}
	}
	err = file.Close()
	return returnValue, intReturn, err

}

func copyLocal(path string) (string,error) {
	var dest string
	var err error
	result := strings.Split(path, "/")
	for _, entry := range result {
		dest = entry
	}
	dest = "/tmp/" + dest
	srcFile, err := os.Open(path)
	if ( err != nil ) {
		return dest, err
	}

	destFile, err := os.Create(dest) // creates if file doesn't exist
	if ( err != nil ) {
		return dest, err
        }

	_, err = io.Copy(destFile, srcFile) // check first var for number of bytes copied
	if ( err != nil ) {
		return dest, err
        }

	err = destFile.Sync()
	if ( err != nil ) {
		return dest, err
        }
	err = destFile.Close()
	if ( err != nil ) {
		return dest, err
        }
	err = srcFile.Close()
	if ( err != nil ) {
		return dest, err
        }
	return dest, nil
}

// kexecEntry is booting new kernel based on the content of grub.cfg
func kexecEntry(grubConfPath string, mountPoint string) error {
	var fileMenuContent []string
	var entry int
	var localKernelPath string
	var localInitrdPath string
	if verbose {
		log.Printf(grubConfPath)
	}
	fileMenuContent, entry, err := getFileMenuContent(grubConfPath)
	if ( err != nil ) {
		return err
	}
	var kernel string
	var kernelParameter string
	var initrd string
	var kernelInfos []string
	kernelInfos = strings.Fields(fileMenuContent[3*entry+1])
	kernel = kernelInfos[1]
	var count int
	count = 0
	for _, field := range kernelInfos {
		if count > 1 {
			kernelParameter = kernelParameter + " " + field
		}
		count = count + 1
	}
	fmt.Sscanf(fileMenuContent[3*entry+2], "initrd %s", &initrd)
	if verbose {
		log.Printf("************** boot parameters  ********************")
		log.Printf(kernel)
		log.Printf(kernelParameter)
		log.Printf(initrd)
		log.Printf("****************************************************")
	}
	localKernelPath,err = copyLocal(mountPoint + kernel)
	if ( err != nil ) {
		return err
	}
	localInitrdPath,err = copyLocal(mountPoint + initrd)
	if ( err != nil ) {
		return err
	}
	if verbose {
		log.Printf(localKernelPath)
	}
	umountEntry(mountPoint)
	// We can kexec the kernel with localKernelPath as kernel entry, kernelParameter as parameter and initrd as initrd !
	log.Printf("Loading %s for kernel\n", localKernelPath)

	kernelDesc, err := os.OpenFile(localKernelPath, os.O_RDONLY, 0)
	if err != nil {
		return err
	}
	// defer kernelDesc.Close()

	var ramfs *os.File
	ramfs, err = os.OpenFile(localInitrdPath, os.O_RDONLY, 0)
	if err != nil {
		return err
	}
	// defer ramfs.Close()

	if err := kexec.FileLoad(kernelDesc, ramfs, kernelParameter); err != nil {
		return err
	}
 	err = ramfs.Close()
	if ( err != nil ) {
		return err
	}
	err = kernelDesc.Close()
	if ( err != nil ) {
		return err
	}
	if err := kexec.Reboot(); err != nil {
		return err
	}
	return err

}

func registerFlags(f *flag.FlagSet) *options {
        o := &options{}
        f.BoolVar(&o.verbose, "v", false, "Set verbose output")
        return o
}

func main() {
	var blkList []string
	var supportedFilesystem []string
	verbose = false
        opts := registerFlags(flag.CommandLine)
	flag.Parse()

        if opts.verbose != false {
		verbose = true
        }

	supportedFilesystem, err := getSupportedFilesystem()
	if ( err != nil ) {
                log.Panic("No filesystem support found")
        }
	if verbose {
		log.Printf("************** Supported Filesystem by current linuxboot ********************")
		for _, filesystem := range supportedFilesystem {
			log.Printf(filesystem)
		}
		log.Printf("*****************************************************************************")
	}
	blkList,err = blkDevicesList("/sys/dev/block/", "/device/block/")
	if ( err != nil ) {
		log.Fatal("No available block devices to boot from")
	}
	// We must validate if the MBR is bootable or not and keep the
	// devices which do have such support
	// drive are easy to detect
	for _, entry := range blkList {
		dev := filepath.Join("/dev", entry)
		err := checkForBootableMBR(dev)
		if err != nil {
			// Not sure it matters; there can be many bogus entries?
			log.Printf("MBR for %s failed: %v", dev, err)
			continue
		}
		fmt.Println("Bootable device found")
		// We need to loop on the device entries which are into /dev/<device>X
		// and mount each partitions as to find /boot entry if it is available somewhere
		var devicePartList []string
		devicePartList,err = getDevicePartList(entry)
		if ( err != nil ) {
			continue
		}
		for _, deviceList := range devicePartList {
			mount, err := mountEntry(deviceList, supportedFilesystem)
			if ( err != nil ) {
				continue
			}
			if mount {
				if verbose {
					log.Printf("mount succeed")
				}
				var grubConfPath = checkBootEntry("/u-root/" + deviceList)
				if grubConfPath != "" {
					if verbose {
						log.Printf("calling basic kexec")
					}
					err = kexecEntry(grubConfPath, "/u-root/"+deviceList)
					if ( err != nil ) {
						log.Fatal("kexec failed")
					}
				}
			}
			umountEntry("/u-root/" + deviceList)
		}
	}
	log.Printf("Sorry no bootable device found")
}
<|endoftext|>


<commit_before>package main

import (
	"goxgl/context"
	"goxgl/gl"
	"math"
	"math/rand"
	"strconv"
	"time"
)

type Box struct {
	bad    bool
	dirty  bool
	x      float32
	y      float32
	w      float32
	h      float32
	vx     float32
	vy     float32
	color  [3]float32
	vertex [8]gl.Float
}

func (p *Box) setColor(r, g, b float32) {
	p.color[0] = r
	p.color[1] = g
	p.color[2] = b
}

func (p *Box) setPosition(x, y float32) {
	p.x = x
	p.y = y
	p.dirty = true
}

func (p *Box) setSize(w, h float32) {
	p.w = w
	p.h = h
	p.dirty = true
}

func (p *Box) intersect(b *Box) bool {
	if p.x+p.w < b.x || p.y+p.h < b.y || b.x+b.w < p.x || b.y+b.h < p.y {
		return false
	}
	return true
}

func (p *Box) update(d float32) {
	if p.vx != 0 || p.vy != 0 {
		p.x += d * p.vx
		p.y += d * p.vy
		p.dirty = true
	}
}

func (p *Box) draw() {
	if p.dirty {
		l := gl.Float(p.x)
		t := gl.Float(p.y)
		r := gl.Float(p.x + p.w)
		b := gl.Float(p.y + p.h)
		p.vertex[0] = l
		p.vertex[1] = t
		p.vertex[2] = l
		p.vertex[3] = b
		p.vertex[4] = r
		p.vertex[5] = b
		p.vertex[6] = r
		p.vertex[7] = t
		p.dirty = false
	}
	gl.Color3f(gl.Float(p.color[0]), gl.Float(p.color[1]), gl.Float(p.color[2]))
	gl.VertexPointer(2, gl.FLOAT, 0, gl.PVoid(&p.vertex[0]))
	gl.DrawArrays(gl.QUADS, 0, 4)
}

const (
	gameWidth  = 320
	gameHeight = 320
	meVx       = 48
	meVy       = 48
)

var (
	over        bool
	score       float32
	genboxSlot  float32
	highest     float32
	highestText string  = "HIGHEST 0.0"
	meScale     float32 = 1.0
)

var (
	boxes []*Box
	me    *Box
)

func onInit() {
	initText()
	gl.Ortho(0.0, gl.Double(gameWidth), 0.0, gl.Double(gameHeight), -1.0, 1.0)
	gl.MatrixMode(gl.PROJECTION)
	gl.LoadIdentity()
	gl.ClearColor(0.0, 0.0, 0.0, 0.0)
	me = &Box{}
	me.setColor(1, 1, 1)
	me.setSize(6, 6)
}

func onSize(w, h int32) {
	gl.Viewport(0, 0, gl.Sizei(w), gl.Sizei(h))
}

func onDraw() {
	gl.Clear(gl.COLOR_BUFFER_BIT)
	drawText("SCORE "+strconv.FormatFloat(float64(score), 'f', 1, 32), 8, gameHeight-13-8)
	drawText(highestText, 8, gameHeight-26-8)
	if !over {
		gl.EnableClientState(gl.VERTEX_ARRAY)
		for _, b := range boxes {
			b.draw()
		}
		me.draw()
		gl.DisableClientState(gl.VERTEX_ARRAY)
	} else {
		drawText("GAME OVER", gameWidth/2-28, gameHeight/2+7)
	}
	context.SwapBuffer()
}

func onKeyDown(kc int) {
	switch kc {
	case context.KEYCODE_LEFT:
		me.vx = -meVx
	case context.KEYCODE_RIGHT:
		me.vx = meVx
	case context.KEYCODE_UP:
		me.vy = meVy
	case context.KEYCODE_DOWN:
		me.vy = -meVy
	case context.KEYCODE_SHIFT:
		meScale = 0.5
	default:
		if over {
			start()
			return
		}
	}
}

func onKeyUp(kc int) {
	switch kc {
	case context.KEYCODE_LEFT:
		if me.vx < 0 {
			me.vx = 0
		}
	case context.KEYCODE_RIGHT:
		if me.vx > 0 {
			me.vx = 0
		}
	case context.KEYCODE_UP:
		if me.vy > 0 {
			me.vy = 0
		}
	case context.KEYCODE_DOWN:
		if me.vy < 0 {
			me.vy = 0
		}
	case context.KEYCODE_SHIFT:
		meScale = 1.0
	}
}

func fixBox(b *Box) {
	if b.x < -b.w || b.x > gameWidth || b.y < -b.h || b.y > gameHeight {
		b.bad = true
	}
}

func fixMe(b *Box) {
	if b.x < 0 {
		b.x = 0
		b.dirty = true
	} else if b.x+b.w > gameWidth {
		b.x = gameWidth - b.w
		b.dirty = true
	}
	if b.y < 0 {
		b.y = 0
		b.dirty = true
	} else if b.y+b.h > gameHeight {
		b.y = gameHeight - b.w
		b.dirty = true
	}
}

func putBox(x, y, w, h, vx, vy float32) *Box {
	b := &Box{dirty: true, x: x, y: y, w: w, h: h, vx: vx, vy: vy}
	b.setColor(rand.Float32(), rand.Float32(), rand.Float32())
	return b
}

func start() {
	if len(boxes) > 0 {
		boxes = boxes[:0]
	}
	me.setPosition(gameWidth/2-5, gameHeight/2-5)
	score = 0.0
	genboxSlot = 0.0
	over = false
	go game()
}

func game() {
	fps := time.NewTicker(time.Second / 60.0)
	last := time.Now()
	for current := range fps.C {
		delta := float32(current.Sub(last)) / float32(time.Second)
		score += delta
		genboxSlot += delta
		if genboxSlot > 2.4 {
			b := int(math.Log2(float64(score)))
			for k := 0; k < 4; k++ {
				c := b + rand.Intn(4)
				for i := 0; i < c; i++ {
					var x float32
					var y float32
					if k&2 == 0 {
						x = float32((k & 1) * gameWidth)
						y = float32(rand.Intn(gameHeight))
					} else {
						x = float32(rand.Intn(gameWidth))
						y = float32((k & 1) * gameHeight)
					}
					vx := (me.x - x) * (0.4 + float32(rand.Intn(20))/100)
					vy := (me.y - y) * (0.4 + float32(rand.Intn(20))/100)
					boxes = append(boxes, putBox(x, y, 4, 4, vx, vy))
				}
			}
			genboxSlot = 0.0
		}
		for _, b := range boxes {
			b.update(delta)
			fixBox(b)
		}
		me.update(delta * meScale)
		fixMe(me)
		for _, b := range boxes {
			if b.intersect(me) {
				over = true
				break
			}
		}
		removed := 0
		for i := len(boxes) - 1; i >= 0; i-- {
			if boxes[i].bad {
				copy(boxes[i:], boxes[i+1:])
				removed++
			}
		}
		boxes = boxes[:len(boxes)-removed]
		context.RequsetRedraw()
		if over {
			if score > highest {
				highest = score
				highestText = "HIGHEST " + strconv.FormatFloat(float64(score), 'f', 1, 32)
			}
			break
		}
		last = current
	}
	fps.Stop()
}
<commit_msg>update<commit_after>package main

import (
	"goxgl/context"
	"goxgl/gl"
	"math"
	"math/rand"
	"strconv"
	"time"
)

type Box struct {
	bad    bool
	dirty  bool
	x      float32
	y      float32
	w      float32
	h      float32
	vx     float32
	vy     float32
	color  [3]float32
	vertex [8]gl.Float
}

func (p *Box) setColor(r, g, b float32) {
	p.color[0] = r
	p.color[1] = g
	p.color[2] = b
}

func (p *Box) setPosition(x, y float32) {
	p.x = x
	p.y = y
	p.dirty = true
}

func (p *Box) setSize(w, h float32) {
	p.w = w
	p.h = h
	p.dirty = true
}

func (p *Box) intersect(b *Box) bool {
	hw1 := p.w / 2
	hh1 := p.h / 2
	hw2 := b.w / 2
	hh2 := b.h / 2
	if p.x+hw1 < b.x-hw2 || p.y+hh1 < b.y-hh2 || b.x+hw2 < p.x-hw1 || b.y+hh2 < p.y-hh1 {
		return false
	}
	return true
}

func (p *Box) update(d float32) {
	if p.vx != 0 || p.vy != 0 {
		p.x += d * p.vx
		p.y += d * p.vy
		p.dirty = true
	}
}

func (p *Box) draw() {
	if p.dirty {
		hw := p.w / 2
		hh := p.h / 2
		l := gl.Float(p.x - hw)
		t := gl.Float(p.y - hh)
		r := gl.Float(p.x + hw)
		b := gl.Float(p.y + hh)
		p.vertex[0] = l
		p.vertex[1] = t
		p.vertex[2] = l
		p.vertex[3] = b
		p.vertex[4] = r
		p.vertex[5] = b
		p.vertex[6] = r
		p.vertex[7] = t
		p.dirty = false
	}
	gl.Color3f(gl.Float(p.color[0]), gl.Float(p.color[1]), gl.Float(p.color[2]))
	gl.VertexPointer(2, gl.FLOAT, 0, gl.PVoid(&p.vertex[0]))
	gl.DrawArrays(gl.QUADS, 0, 4)
}

const (
	gameWidth  = 320
	gameHeight = 320
	meVx       = 48
	meVy       = 48
)

var (
	over        bool
	score       float32
	genboxSlot  float32
	highest     float32
	highestText string  = "HIGHEST 0.0"
	meScale     float32 = 1.0
)

var (
	boxes []*Box
	me    *Box
)

func onInit() {
	initText()
	gl.Ortho(0.0, gl.Double(gameWidth), 0.0, gl.Double(gameHeight), -1.0, 1.0)
	gl.MatrixMode(gl.PROJECTION)
	gl.LoadIdentity()
	gl.ClearColor(0.0, 0.0, 0.0, 0.0)
	me = &Box{}
	me.setColor(1, 1, 1)
	me.setSize(6, 6)
}

func onSize(w, h int32) {
	gl.Viewport(0, 0, gl.Sizei(w), gl.Sizei(h))
}

func onDraw() {
	gl.Clear(gl.COLOR_BUFFER_BIT)
	drawText("SCORE "+strconv.FormatFloat(float64(score), 'f', 1, 32), 8, gameHeight-13-8)
	drawText(highestText, 8, gameHeight-26-8)
	if !over {
		gl.EnableClientState(gl.VERTEX_ARRAY)
		for _, b := range boxes {
			b.draw()
		}
		me.draw()
		gl.DisableClientState(gl.VERTEX_ARRAY)
	} else {
		drawText("GAME OVER", gameWidth/2-28, gameHeight/2+7)
	}
	context.SwapBuffer()
}

func onKeyDown(kc int) {
	switch kc {
	case context.KEYCODE_LEFT:
		me.vx = -meVx
	case context.KEYCODE_RIGHT:
		me.vx = meVx
	case context.KEYCODE_UP:
		me.vy = meVy
	case context.KEYCODE_DOWN:
		me.vy = -meVy
	case context.KEYCODE_SHIFT:
		meScale = 0.5
		me.setSize(2, 2)
	default:
		if over {
			start()
			return
		}
	}
}

func onKeyUp(kc int) {
	switch kc {
	case context.KEYCODE_LEFT:
		if me.vx < 0 {
			me.vx = 0
		}
	case context.KEYCODE_RIGHT:
		if me.vx > 0 {
			me.vx = 0
		}
	case context.KEYCODE_UP:
		if me.vy > 0 {
			me.vy = 0
		}
	case context.KEYCODE_DOWN:
		if me.vy < 0 {
			me.vy = 0
		}
	case context.KEYCODE_SHIFT:
		meScale = 1.0
		me.setSize(6, 6)
	}
}

func fixBox(b *Box) {
	hw := b.w / 2
	hh := b.h / 2
	if b.x < -hw || b.x > gameWidth+hw || b.y < -hh || b.y > gameHeight+hh {
		b.bad = true
	}
}

func fixMe(b *Box) {
	hw := b.w / 2
	hh := b.h / 2
	if b.x < hw {
		b.x = hw
		b.dirty = true
	} else if b.x+hw > gameWidth {
		b.x = gameWidth - hw
		b.dirty = true
	}
	if b.y < hh {
		b.y = hh
		b.dirty = true
	} else if b.y+hh > gameHeight {
		b.y = gameHeight - hh
		b.dirty = true
	}
}

func newBox(x, y, w, h, vx, vy float32) *Box {
	b := &Box{dirty: true, x: x, y: y, w: w, h: h, vx: vx, vy: vy}
	b.setColor(rand.Float32(), rand.Float32(), rand.Float32())
	return b
}

func start() {
	if len(boxes) > 0 {
		boxes = boxes[:0]
	}
	me.setPosition(gameWidth/2-5, gameHeight/2-5)
	me.setSize(6, 6)
	meScale = 1.0
	score = 0.0
	genboxSlot = 0.0
	over = false
	go game()
}

func game() {
	fps := time.NewTicker(time.Second / 60.0)
	last := time.Now()
	for current := range fps.C {
		delta := float32(current.Sub(last)) / float32(time.Second)
		score += delta
		genboxSlot += delta
		if genboxSlot > 2.4 {
			b := int(math.Log2(float64(score)))
			for k := 0; k < 4; k++ {
				c := b + rand.Intn(4)
				for i := 0; i < c; i++ {
					var x float32
					var y float32
					if k&2 == 0 {
						x = float32((k & 1) * gameWidth)
						y = float32(rand.Intn(gameHeight))
					} else {
						x = float32(rand.Intn(gameWidth))
						y = float32((k & 1) * gameHeight)
					}
					vx := (me.x - x) * (0.4 + float32(rand.Intn(20))/100)
					vy := (me.y - y) * (0.4 + float32(rand.Intn(20))/100)
					boxes = append(boxes, newBox(x, y, 4, 4, vx, vy))
				}
			}
			genboxSlot = 0.0
		}
		for _, b := range boxes {
			b.update(delta)
			fixBox(b)
		}
		me.update(delta * meScale)
		fixMe(me)
		for _, b := range boxes {
			if b.intersect(me) {
				over = true
				break
			}
		}
		removed := 0
		for i := len(boxes) - 1; i >= 0; i-- {
			if boxes[i].bad {
				copy(boxes[i:], boxes[i+1:])
				removed++
			}
		}
		boxes = boxes[:len(boxes)-removed]
		context.RequsetRedraw()
		if over {
			if score > highest {
				highest = score
				highestText = "HIGHEST " + strconv.FormatFloat(float64(score), 'f', 1, 32)
			}
			break
		}
		last = current
	}
	fps.Stop()
}
<|endoftext|>


<commit_before>package goriot

import (
	"fmt"
)

//Game represents a League of Legends game
type Game struct {
	ChampionID    int      `json:"championId"`
	CreateDate    int64    `json:"createDate"`
	FellowPlayers []Player `json:"fellowPlayers"`
	GameID        int64    `json:"gameId"`
	GameMode      string   `json:"gameMode"`
	GameType      string   `json:"gameType"`
	Invalid       bool     `json:"invalid"`
	Level         int      `json:"level"`
	MapID         int      `json:"mapId"`
	Spell1        int      `json:"spell1"`
	Spell2        int      `json:"spell2"`
	Statistics    GameStat `json:"stats"`
	SubType       string   `json:"subType"`
	TeamID        int      `json:"teamId"`
}

//Player represents a League of Legends player that was in the requested game
type Player struct {
	ChampionID int   `json:"championId"`
	SummonerID int64 `json:"summonerId"`
	TeamID     int   `json:"teamId"`
}

//GameStat represents a stat for the assosiated Game
type GameStat struct {
	Assists                         int  `json:"assists"`
	BarracksKilled                  int  `json:"barracksKilled"`
	ChampionsKilled                 int  `json:"championsKilled"`
	combatPlayerScore               int  `json:"combatPlayerScore"`
	ConsumablesPurchased            int  `json:"consumablesPurchased"`
	DamageDealtPlayer               int  `json:"damageDealtPlayer"`
	DoubleKills                     int  `json:"doubleKills"`
	FirstBlood                      int  `json:"firstBlood"`
	Gold                            int  `json:"gold"`
	GoldEarned                      int  `json:"goldEarned"`
	GoldSpent                       int  `json:"goldSpent"`
	Item0                           int  `json:"item0"`
	Item1                           int  `json:"item1"`
	Item2                           int  `json:"item2"`
	Item3                           int  `json:"item3"`
	Item4                           int  `json:"item4"`
	Item5                           int  `json:"item5"`
	Item6                           int  `json:"item6"`
	ItemsPurchased                  int  `json:"itemsPurchased"`
	KillingSprees                   int  `json:"killingSprees"`
	LargestCriticalStrike           int  `json:"largestCriticalStrike"`
	LargestKillingSpree             int  `json:"largestKillingSpree"`
	LargestMultiKill                int  `json:"largestMultiKill"`
	LegendaryItemsCreated           int  `json:"legendaryItemsCreated"`
	Level                           int  `json:"level"`
	MagicDamageDealtPlayer          int  `json:"magicDamageDealtPlayer"`
	MagicDamageDealtToChampions     int  `json:"magicDamageDealtToChampions"`
	MagicDamageTaken                int  `json:"magicDamageTaken"`
	MinionsDenied                   int  `json:"minionsDenied"`
	MinionsKilled                   int  `json:"minionsKilled"`
	NeutralMinionsKilled            int  `json:"neutralMinionsKilled"`
	NeutralMinionsKilledEnemyJungle int  `json:"neutralMinionsKilledEnemyJungle"`
	NeutralMinionsKilledYourJungle  int  `json:"neutralMinionsKilledYourJungle"`
	NexusKilled                     bool `json:"nexusKilled"`
	NodeCapture                     int  `json:"nodeCapture"`
	NodeCaptureAssist               int  `json:"nodeCaptureAssist"`
	NodeNeutralize                  int  `json:"nodeNeutralize"`
	NodeNeutralizeAssist            int  `json:"nodeNeutralizeAssist"`
	NumDeaths                       int  `json:"numDeaths"`
	NumItemsBought                  int  `json:"numItemsBought"`
	ObjectivePlayerSocre            int  `json:"objectivePlayerScore"`
	PentaKills                      int  `json:"pentaKills"`
	PhysicalDamageDealtPlayer       int  `json:"physicalDamageDealtPlayer"`
	PysicalDamageDealtToChampions   int  `json:"physicalDmageDealtToChampions"`
	PhysicalDamageTaken             int  `json:"physicalDamageTaken"`
	QuadraKills                     int  `json:"quadraKills"`
	SightWardsBought                int  `json:"sightWardsBought"`
	Spell1Cast                      int  `json:"spell1Cast"`
	Spell2Cast                      int  `json:"spell2Cast"`
	Spell3Cast                      int  `json:"spell3Cast"`
	Spell4Cast                      int  `json:"spell4Cast"`
	SummonSpell1Cast                int  `json:"summonSpell1Cast"`
	SummonSpell2Cast                int  `json:"summonSpell2Cast"`
	SuperMonsterKilled              int  `json:"superMonsterKilled"`
	Team                            int  `json:"team"`
	TeamObjective                   int  `json:"teamObjective"`
	TimePlayed                      int  `json:"timePlayed"`
	TotalDamageDealt                int  `json:"totalDamageDealt"`
	TotalDamageDealtToChampions     int  `json:"totalDamageDealtToChampions"`
	TotalDamageTaken                int  `json:"totalDamageTaken"`
	TotalHeal                       int  `json:"totalHeal"`
	TotalPlayerScore                int  `json:"totalPlayerScore"`
	TotalScoreRank                  int  `json:"totalScoreRank"`
	TotalTimeCrowdControlDealt      int  `json:"totalTimeCrowdControlDealt"`
	TotalUnitsHealed                int  `json:"totalUnitsHealed"`
	TripleKills                     int  `json:"tripleKills"`
	TrueDamageDealtPlayer           int  `json:"trueDamageDealtPlayer"`
	TrueDamageDealtToChampions      int  `json:"trueDamageDealtToChampions"`
	TrueDamageTaken                 int  `json:"trueDamageTaken"`
	TurretsKilled                   int  `json:"turretsKilled"`
	UnrealKills                     int  `json:"unrealKills"`
	VictoryPointTotal               int  `json:"victoryPointTotal"`
	VisionWardsBought               int  `json:"visionWardsBought"`
	WardKilled                      int  `json:"wardKilled"`
	WardPlaced                      int  `json:"wardPlaced"`
	Win                             bool `json:"win"`
}

type gamesList struct {
	Games []Game `json:"games"`
}

//RecentGameBySummoner retrieves the current list of recent games from the Riot Games API.
//It returns an array of Game(s) and any errors that occured from the server
//The global API key must be set before use
func RecentGameBySummoner(region string, summonerID int64) (games []Game, err error) {
	var gameslist gamesList
	if !IsKeySet() {
		return games, ErrAPIKeyNotSet
	}
	args := "api_key=" + apikey
	url := fmt.Sprintf("%v/lol/%v/v1.3/game/by-summoner/%d/recent?%v", BaseURL, region, summonerID, args)
	err = requestAndUnmarshal(url, &gameslist)
	if err != nil {
		return
	}

	return gameslist.Games, err
}
<commit_msg>Revert "Revert "Fixes typos in game.go. Thanks @mattcan for pointing out""<commit_after>package goriot

import (
	"fmt"
)

//Game represents a League of Legends game
type Game struct {
	ChampionID    int      `json:"championId"`
	CreateDate    int64    `json:"createDate"`
	FellowPlayers []Player `json:"fellowPlayers"`
	GameID        int64    `json:"gameId"`
	GameMode      string   `json:"gameMode"`
	GameType      string   `json:"gameType"`
	Invalid       bool     `json:"invalid"`
	Level         int      `json:"level"`
	MapID         int      `json:"mapId"`
	Spell1        int      `json:"spell1"`
	Spell2        int      `json:"spell2"`
	Statistics    GameStat `json:"stats"`
	SubType       string   `json:"subType"`
	TeamID        int      `json:"teamId"`
}

//Player represents a League of Legends player that was in the requested game
type Player struct {
	ChampionID int   `json:"championId"`
	SummonerID int64 `json:"summonerId"`
	TeamID     int   `json:"teamId"`
}

//GameStat represents a stat for the assosiated Game
type GameStat struct {
	Assists                         int  `json:"assists"`
	BarracksKilled                  int  `json:"barracksKilled"`
	ChampionsKilled                 int  `json:"championsKilled"`
	CombatPlayerScore               int  `json:"combatPlayerScore"`
	ConsumablesPurchased            int  `json:"consumablesPurchased"`
	DamageDealtPlayer               int  `json:"damageDealtPlayer"`
	DoubleKills                     int  `json:"doubleKills"`
	FirstBlood                      int  `json:"firstBlood"`
	Gold                            int  `json:"gold"`
	GoldEarned                      int  `json:"goldEarned"`
	GoldSpent                       int  `json:"goldSpent"`
	Item0                           int  `json:"item0"`
	Item1                           int  `json:"item1"`
	Item2                           int  `json:"item2"`
	Item3                           int  `json:"item3"`
	Item4                           int  `json:"item4"`
	Item5                           int  `json:"item5"`
	Item6                           int  `json:"item6"`
	ItemsPurchased                  int  `json:"itemsPurchased"`
	KillingSprees                   int  `json:"killingSprees"`
	LargestCriticalStrike           int  `json:"largestCriticalStrike"`
	LargestKillingSpree             int  `json:"largestKillingSpree"`
	LargestMultiKill                int  `json:"largestMultiKill"`
	LegendaryItemsCreated           int  `json:"legendaryItemsCreated"`
	Level                           int  `json:"level"`
	MagicDamageDealtPlayer          int  `json:"magicDamageDealtPlayer"`
	MagicDamageDealtToChampions     int  `json:"magicDamageDealtToChampions"`
	MagicDamageTaken                int  `json:"magicDamageTaken"`
	MinionsDenied                   int  `json:"minionsDenied"`
	MinionsKilled                   int  `json:"minionsKilled"`
	NeutralMinionsKilled            int  `json:"neutralMinionsKilled"`
	NeutralMinionsKilledEnemyJungle int  `json:"neutralMinionsKilledEnemyJungle"`
	NeutralMinionsKilledYourJungle  int  `json:"neutralMinionsKilledYourJungle"`
	NexusKilled                     bool `json:"nexusKilled"`
	NodeCapture                     int  `json:"nodeCapture"`
	NodeCaptureAssist               int  `json:"nodeCaptureAssist"`
	NodeNeutralize                  int  `json:"nodeNeutralize"`
	NodeNeutralizeAssist            int  `json:"nodeNeutralizeAssist"`
	NumDeaths                       int  `json:"numDeaths"`
	NumItemsBought                  int  `json:"numItemsBought"`
	ObjectivePlayerScore            int  `json:"objectivePlayerScore"`
	PentaKills                      int  `json:"pentaKills"`
	PhysicalDamageDealtPlayer       int  `json:"physicalDamageDealtPlayer"`
	PhysicalDamageDealtToChampions  int  `json:"physicalDamageDealtToChampions"`
	PhysicalDamageTaken             int  `json:"physicalDamageTaken"`
	QuadraKills                     int  `json:"quadraKills"`
	SightWardsBought                int  `json:"sightWardsBought"`
	Spell1Cast                      int  `json:"spell1Cast"`
	Spell2Cast                      int  `json:"spell2Cast"`
	Spell3Cast                      int  `json:"spell3Cast"`
	Spell4Cast                      int  `json:"spell4Cast"`
	SummonSpell1Cast                int  `json:"summonSpell1Cast"`
	SummonSpell2Cast                int  `json:"summonSpell2Cast"`
	SuperMonsterKilled              int  `json:"superMonsterKilled"`
	Team                            int  `json:"team"`
	TeamObjective                   int  `json:"teamObjective"`
	TimePlayed                      int  `json:"timePlayed"`
	TotalDamageDealt                int  `json:"totalDamageDealt"`
	TotalDamageDealtToChampions     int  `json:"totalDamageDealtToChampions"`
	TotalDamageTaken                int  `json:"totalDamageTaken"`
	TotalHeal                       int  `json:"totalHeal"`
	TotalPlayerScore                int  `json:"totalPlayerScore"`
	TotalScoreRank                  int  `json:"totalScoreRank"`
	TotalTimeCrowdControlDealt      int  `json:"totalTimeCrowdControlDealt"`
	TotalUnitsHealed                int  `json:"totalUnitsHealed"`
	TripleKills                     int  `json:"tripleKills"`
	TrueDamageDealtPlayer           int  `json:"trueDamageDealtPlayer"`
	TrueDamageDealtToChampions      int  `json:"trueDamageDealtToChampions"`
	TrueDamageTaken                 int  `json:"trueDamageTaken"`
	TurretsKilled                   int  `json:"turretsKilled"`
	UnrealKills                     int  `json:"unrealKills"`
	VictoryPointTotal               int  `json:"victoryPointTotal"`
	VisionWardsBought               int  `json:"visionWardsBought"`
	WardKilled                      int  `json:"wardKilled"`
	WardPlaced                      int  `json:"wardPlaced"`
	Win                             bool `json:"win"`
}

type gamesList struct {
	Games []Game `json:"games"`
}

//RecentGameBySummoner retrieves the current list of recent games from the Riot Games API.
//It returns an array of Game(s) and any errors that occured from the server
//The global API key must be set before use
func RecentGameBySummoner(region string, summonerID int64) (games []Game, err error) {
	var gameslist gamesList
	if !IsKeySet() {
		return games, ErrAPIKeyNotSet
	}
	args := "api_key=" + apikey
	url := fmt.Sprintf("%v/lol/%v/v1.3/game/by-summoner/%d/recent?%v", BaseURL, region, summonerID, args)
	err = requestAndUnmarshal(url, &gameslist)
	if err != nil {
		return
	}

	return gameslist.Games, err
}
<|endoftext|>