<commit_before>package main

import (
    "fmt"
    "errors"
    "bytes"
    "io/ioutil"
    "path/filepath"
    "bufio"
    "os"
    "strings"
    "regexp"
    flags "github.com/jessevdk/go-flags"
)

const (
    Author  = "webdevops.io"
    Version = "0.4.0"
)

type changeset struct {
    Search      *regexp.Regexp
    Replace     string
    MatchFound  bool
}

var opts struct {
    Mode                    string   `short:"m"  long:"mode"                          description:"replacement mode - replace: replace match with term; line: replace line with term; lineinfile: replace line with term or if not found append to term to file" default:"replace" choice:"replace" choice:"line" choice:"lineinfile"`
    ModeIsReplaceMatch      bool
    ModeIsReplaceLine       bool
    ModeIsLineInFile        bool
    Search                  []string `short:"s"  long:"search"       required:"true"  description:"search term"`
    Replace                 []string `short:"r"  long:"replace"      required:"true"  description:"replacement term" `
    IgnoreCase              bool     `short:"i"  long:"ignore-case"                   description:"ignore pattern case"`
    Once                    bool     `           long:"once"                          description:"replace search term only one in a file"`
    OnceRemoveMatch         bool     `           long:"once-remove-match"             description:"replace search term only one in a file and also don't keep matching lines (for line and lineinfile mode)"`
    Regex                   bool     `           long:"regex"                         description:"treat pattern as regex"`
    RegexBackref            bool     `           long:"regex-backrefs"                description:"enable backreferences in replace term"`
    RegexPosix              bool     `           long:"regex-posix"                   description:"parse regex term as POSIX regex"`
    Path                    string   `           long:"path"                          description:"use files in this path"`
    PathPattern             string   `           long:"path-pattern"                  description:"file pattern (* for wildcard, only basename of file)"`
    PathRegex               string   `           long:"path-regex"                    description:"file pattern (regex, full path)"`
    IgnoreEmpty             bool     `           long:"ignore-empty"                  description:"ignore empty file list, otherwise this will result in an error"`
    Verbose                 bool     `short:"v"  long:"verbose"                       description:"verbose mode"`
    DryRun                  bool     `           long:"dry-run"                       description:"dry run mode"`
    ShowVersion             bool     `short:"V"  long:"version"                       description:"show version and exit"`
    ShowHelp                bool     `short:"h"  long:"help"                          description:"show this help message"`
}

var pathFilterDirectories = []string{"autom4te.cache", "blib", "_build", ".bzr", ".cdv", "cover_db", "CVS", "_darcs", "~.dep", "~.dot", ".git", ".hg", "~.nib", ".pc", "~.plst", "RCS", "SCCS", "_sgbak", ".svn", "_obj", ".idea"}

// Apply changesets to file
func applyChangesetsToFile(filepath string, changesets []changeset) {
    // try open file
    file, err := os.Open(filepath)
    if err != nil {
        panic(err)
    }

    writeBufferToFile := false
    var buffer bytes.Buffer

    r := bufio.NewReader(file)
    line, e := Readln(r)
    for e == nil {
        writeLine := true

        for i := range changesets {
            changeset := changesets[i]

            // --once, only do changeset once if already applied to file
            if opts.Once && changeset.MatchFound {
                // --once-without-match, skip matching lines
                if opts.OnceRemoveMatch && searchMatch(line, changeset) {
                    // matching line, not writing to buffer as requsted
                    writeLine = false
                    writeBufferToFile = true
                    break
                }
            } else {
                // search and replace
                if searchMatch(line, changeset) {
                    // --mode=line or --mode=lineinfile
                    if opts.ModeIsReplaceLine || opts.ModeIsLineInFile {
                        // replace whole line with replace term
                        line = changeset.Replace
                    } else {
                        // replace only term inside line
                        line = replaceText(line, changeset)
                    }

                    changesets[i].MatchFound = true
                    writeBufferToFile = true
                }
            }
        }

        if (writeLine) {
            buffer.WriteString(line + "\n")
        }

        line, e = Readln(r)
    }

    // --mode=lineinfile
    if opts.ModeIsLineInFile {
        for i := range changesets {
            changeset := changesets[i]
            if !changeset.MatchFound {
                buffer.WriteString(changeset.Replace + "\n")
                writeBufferToFile = true
            }
        }
    }

    if writeBufferToFile {
        writeContentToFile(filepath, buffer)
    } else {
        logMessage(fmt.Sprintf("%s no match", filepath))
    }
}

// Readln returns a single line (without the ending \n)
// from the input buffered reader.
// An error is returned iff there is an error with the
// buffered reader.
func Readln(r *bufio.Reader) (string, error) {
  var (isPrefix bool = true
       err error = nil
       line, ln []byte
      )
  for isPrefix && err == nil {
      line, isPrefix, err = r.ReadLine()
      ln = append(ln, line...)
  }
  return string(ln),err
}

// Checks if there is a match in content, based on search options
func searchMatch(content string, changeset changeset) (bool) {
    if changeset.Search.MatchString(content) {
        return true
    }

    return false
}

// Replace text in whole content based on search options
func replaceText(content string, changeset changeset) (string) {
    // --regex-backrefs
    if opts.RegexBackref {
        return changeset.Search.ReplaceAllString(content, changeset.Replace)
    } else {
        return changeset.Search.ReplaceAllLiteralString(content, changeset.Replace)
    }
}

// Write content to file
func writeContentToFile(filepath string, content bytes.Buffer) {
    // --dry-run
    if opts.DryRun {
        title := fmt.Sprintf("%s:", filepath)

        fmt.Println()
        fmt.Println(title)
        fmt.Println(strings.Repeat("-", len(title)))
        fmt.Println(content.String())
        fmt.Println()
    } else {
        var err error
        err = ioutil.WriteFile(filepath, content.Bytes(), 0)
        if err != nil {
            panic(err)
        }

        logMessage(fmt.Sprintf("%s found and replaced match", filepath))
    }
}

// Log message
func logMessage(message string) {
    if opts.Verbose {
        fmt.Println(message)
    }
}

// Log error object as message
func logError(err error) {
    fmt.Printf("Error: %s\n", err)
}

// Build search term
// Compiles regexp if regexp is used
func buildSearchTerm(term string) (*regexp.Regexp) {
    var ret *regexp.Regexp
    var regex string

    // --regex
    if opts.Regex {
        // use search term as regex
        regex = term
    } else {
        // use search term as normal string, escape it for regex usage
        regex = regexp.QuoteMeta(term)
    }

    // --ignore-case
    if opts.IgnoreCase {
        regex = "(?i:" + regex + ")"
    }

    // --verbose
    if opts.Verbose {
        logMessage(fmt.Sprintf("Using regular expression: %s", regex))
    }

    // --regex-posix
    if opts.RegexPosix {
        ret = regexp.MustCompilePOSIX(regex)
    } else {
        ret = regexp.MustCompile(regex)
    }

    return ret
}

// check if string is contained in an array
func contains(slice []string, item string) bool {
    set := make(map[string]struct{}, len(slice))
    for _, s := range slice {
        set[s] = struct{}{}
    }

    _, ok := set[item]
    return ok
}

// search files in path
func searchFilesInPath(path string, callback func(os.FileInfo, string)) {
        var pathRegex *regexp.Regexp

        // --path-regex
        if (opts.PathRegex != "") {
            pathRegex = regexp.MustCompile(opts.PathRegex)
        }

        // collect all files
        filepath.Walk(path, func(path string, f os.FileInfo, err error) error {
            filename := f.Name()

            // skip directories
            if f.IsDir() {
                if contains(pathFilterDirectories, f.Name()) {
                    return filepath.SkipDir
                }

                return nil
            }

            // --path-pattern
            if (opts.PathPattern != "") {
                matched, _ := filepath.Match(opts.PathPattern, filename)
                if (!matched) {
                    return nil
                }
            }

            // --path-regex
            if pathRegex != nil {
                if (!pathRegex.MatchString(path)) {
                    return nil
                }
            }

            callback(f, path)
            return nil
        })
}

// handle special cli options
// eg. --help
//     --version
//     --path
//     --mode=...
//     --once-without-match
func handleSpecialCliOptions(argparser *flags.Parser, args []string) ([]string) {
    // --version
    if (opts.ShowVersion) {
        fmt.Printf("goreplace version %s\n", Version)
        os.Exit(0)
    }

    // --help
    if (opts.ShowHelp) {
        argparser.WriteHelp(os.Stdout)
        os.Exit(1)
    }

    // --mode
    switch mode := opts.Mode; mode {
        case "replace":
            opts.ModeIsReplaceMatch = true
            opts.ModeIsReplaceLine = false
            opts.ModeIsLineInFile = false
        case "line":
            opts.ModeIsReplaceMatch = false
            opts.ModeIsReplaceLine = true
            opts.ModeIsLineInFile = false
        case "lineinfile":
            opts.ModeIsReplaceMatch = false
            opts.ModeIsReplaceLine = false
            opts.ModeIsLineInFile = true
    }

    // --path
    if (opts.Path != "") {
        searchFilesInPath(opts.Path, func(f os.FileInfo, path string) {
            args = append(args, path)
        })
    }

    // --once-without-match
    if opts.OnceRemoveMatch {
        // implicit enables once mode
        opts.Once = true
    }

    return args
}

func main() {
    var changesets = []changeset {}

    var argparser = flags.NewParser(&opts, flags.PassDoubleDash)
    args, err := argparser.Parse()

    args = handleSpecialCliOptions(argparser, args)

    // check if there is an parse error
    if err != nil {
        logError(err)
        fmt.Println()
        argparser.WriteHelp(os.Stdout)
        os.Exit(1)
    }

    // check if search and replace options have equal lenght (equal number of options)
    if len(opts.Search) != len(opts.Replace) {
        // error: unequal numbers of search and replace options
        err := errors.New("Unequal numbers of search or replace options")
        logError(err)
        fmt.Println()
        argparser.WriteHelp(os.Stdout)
        os.Exit(1)
    }

    // build changesets
    for i := range opts.Search {
        search := opts.Search[i]
        replace := opts.Replace[i]

        changeset := changeset{buildSearchTerm(search), replace, false}

        changesets = append(changesets, changeset)
    }

     // check if there is at least one file to process
    if (len(args) == 0) {
        if (opts.IgnoreEmpty) {
            // no files found, but we should ignore empty filelist
            logMessage("No files found, requsted to ignore this")
            os.Exit(0)
        } else {
            // no files found, print error and exit with error code
            err := errors.New("No files specified")
            logError(err)
            fmt.Println()
            argparser.WriteHelp(os.Stdout)
            os.Exit(1)
        }
    }

    // process file list
    for i := range args {
        var file string
        file = args[i]

        applyChangesetsToFile(file, changesets)
    }

    os.Exit(0)
}
<commit_msg>Implement parallelization<commit_after>package main

import (
    "fmt"
    "sync"
    "errors"
    "bytes"
    "io/ioutil"
    "path/filepath"
    "bufio"
    "os"
    "strings"
    "regexp"
    flags "github.com/jessevdk/go-flags"
)

const (
    Author  = "webdevops.io"
    Version = "0.4.0"
)

type changeset struct {
    Search      *regexp.Regexp
    Replace     string
    MatchFound  bool
}

type changeresult struct {
    File   fileitem
    Output string
    Status bool
}

type fileitem struct {
    Path        string
}

var opts struct {
    Mode                    string   `short:"m"  long:"mode"                          description:"replacement mode - replace: replace match with term; line: replace line with term; lineinfile: replace line with term or if not found append to term to file" default:"replace" choice:"replace" choice:"line" choice:"lineinfile"`
    ModeIsReplaceMatch      bool
    ModeIsReplaceLine       bool
    ModeIsLineInFile        bool
    Search                  []string `short:"s"  long:"search"       required:"true"  description:"search term"`
    Replace                 []string `short:"r"  long:"replace"      required:"true"  description:"replacement term" `
    IgnoreCase              bool     `short:"i"  long:"ignore-case"                   description:"ignore pattern case"`
    Once                    bool     `           long:"once"                          description:"replace search term only one in a file"`
    OnceRemoveMatch         bool     `           long:"once-remove-match"             description:"replace search term only one in a file and also don't keep matching lines (for line and lineinfile mode)"`
    Regex                   bool     `           long:"regex"                         description:"treat pattern as regex"`
    RegexBackref            bool     `           long:"regex-backrefs"                description:"enable backreferences in replace term"`
    RegexPosix              bool     `           long:"regex-posix"                   description:"parse regex term as POSIX regex"`
    Path                    string   `           long:"path"                          description:"use files in this path"`
    PathPattern             string   `           long:"path-pattern"                  description:"file pattern (* for wildcard, only basename of file)"`
    PathRegex               string   `           long:"path-regex"                    description:"file pattern (regex, full path)"`
    IgnoreEmpty             bool     `           long:"ignore-empty"                  description:"ignore empty file list, otherwise this will result in an error"`
    Verbose                 bool     `short:"v"  long:"verbose"                       description:"verbose mode"`
    DryRun                  bool     `           long:"dry-run"                       description:"dry run mode"`
    ShowVersion             bool     `short:"V"  long:"version"                       description:"show version and exit"`
    ShowHelp                bool     `short:"h"  long:"help"                          description:"show this help message"`
}

var pathFilterDirectories = []string{"autom4te.cache", "blib", "_build", ".bzr", ".cdv", "cover_db", "CVS", "_darcs", "~.dep", "~.dot", ".git", ".hg", "~.nib", ".pc", "~.plst", "RCS", "SCCS", "_sgbak", ".svn", "_obj", ".idea"}

// Apply changesets to file
func applyChangesetsToFile(fileitem fileitem, changesets []changeset) (string, bool) {
    output := ""
    status := true

    // try open file
    file, err := os.Open(fileitem.Path)
    if err != nil {
        panic(err)
    }

    writeBufferToFile := false
    var buffer bytes.Buffer

    r := bufio.NewReader(file)
    line, e := Readln(r)
    for e == nil {
        writeLine := true

        for i := range changesets {
            changeset := changesets[i]

            // --once, only do changeset once if already applied to file
            if opts.Once && changeset.MatchFound {
                // --once-without-match, skip matching lines
                if opts.OnceRemoveMatch && searchMatch(line, changeset) {
                    // matching line, not writing to buffer as requsted
                    writeLine = false
                    writeBufferToFile = true
                    break
                }
            } else {
                // search and replace
                if searchMatch(line, changeset) {
                    // --mode=line or --mode=lineinfile
                    if opts.ModeIsReplaceLine || opts.ModeIsLineInFile {
                        // replace whole line with replace term
                        line = changeset.Replace
                    } else {
                        // replace only term inside line
                        line = replaceText(line, changeset)
                    }

                    changesets[i].MatchFound = true
                    writeBufferToFile = true
                }
            }
        }

        if (writeLine) {
            buffer.WriteString(line + "\n")
        }

        line, e = Readln(r)
    }

    // --mode=lineinfile
    if opts.ModeIsLineInFile {
        for i := range changesets {
            changeset := changesets[i]
            if !changeset.MatchFound {
                buffer.WriteString(changeset.Replace + "\n")
                writeBufferToFile = true
            }
        }
    }

    if writeBufferToFile {
        output, status = writeContentToFile(fileitem, buffer)
    } else {
        output = fmt.Sprintf("%s no match", fileitem.Path)
    }

    return output, status
}

// Readln returns a single line (without the ending \n)
// from the input buffered reader.
// An error is returned iff there is an error with the
// buffered reader.
func Readln(r *bufio.Reader) (string, error) {
  var (isPrefix bool = true
       err error = nil
       line, ln []byte
      )
  for isPrefix && err == nil {
      line, isPrefix, err = r.ReadLine()
      ln = append(ln, line...)
  }
  return string(ln),err
}

// Checks if there is a match in content, based on search options
func searchMatch(content string, changeset changeset) (bool) {
    if changeset.Search.MatchString(content) {
        return true
    }

    return false
}

// Replace text in whole content based on search options
func replaceText(content string, changeset changeset) (string) {
    // --regex-backrefs
    if opts.RegexBackref {
        return changeset.Search.ReplaceAllString(content, changeset.Replace)
    } else {
        return changeset.Search.ReplaceAllLiteralString(content, changeset.Replace)
    }
}

// Write content to file
func writeContentToFile(fileitem fileitem, content bytes.Buffer) (string, bool) {
    // --dry-run
    if opts.DryRun {
        return content.String(), true
    } else {
        var err error
        err = ioutil.WriteFile(fileitem.Path, content.Bytes(), 0)
        if err != nil {
            panic(err)
        }

        return fmt.Sprintf("%s found and replaced match\n", fileitem.Path), true
    }
}

// Log message
func logMessage(message string) {
    if opts.Verbose {
        fmt.Println(message)
    }
}

// Log error object as message
func logError(err error) {
    fmt.Printf("Error: %s\n", err)
}

// Build search term
// Compiles regexp if regexp is used
func buildSearchTerm(term string) (*regexp.Regexp) {
    var ret *regexp.Regexp
    var regex string

    // --regex
    if opts.Regex {
        // use search term as regex
        regex = term
    } else {
        // use search term as normal string, escape it for regex usage
        regex = regexp.QuoteMeta(term)
    }

    // --ignore-case
    if opts.IgnoreCase {
        regex = "(?i:" + regex + ")"
    }

    // --verbose
    if opts.Verbose {
        logMessage(fmt.Sprintf("Using regular expression: %s", regex))
    }

    // --regex-posix
    if opts.RegexPosix {
        ret = regexp.MustCompilePOSIX(regex)
    } else {
        ret = regexp.MustCompile(regex)
    }

    return ret
}

// check if string is contained in an array
func contains(slice []string, item string) bool {
    set := make(map[string]struct{}, len(slice))
    for _, s := range slice {
        set[s] = struct{}{}
    }

    _, ok := set[item]
    return ok
}

// search files in path
func searchFilesInPath(path string, callback func(os.FileInfo, string)) {
        var pathRegex *regexp.Regexp

        // --path-regex
        if (opts.PathRegex != "") {
            pathRegex = regexp.MustCompile(opts.PathRegex)
        }

        // collect all files
        filepath.Walk(path, func(path string, f os.FileInfo, err error) error {
            filename := f.Name()

            // skip directories
            if f.IsDir() {
                if contains(pathFilterDirectories, f.Name()) {
                    return filepath.SkipDir
                }

                return nil
            }

            // --path-pattern
            if (opts.PathPattern != "") {
                matched, _ := filepath.Match(opts.PathPattern, filename)
                if (!matched) {
                    return nil
                }
            }

            // --path-regex
            if pathRegex != nil {
                if (!pathRegex.MatchString(path)) {
                    return nil
                }
            }

            callback(f, path)
            return nil
        })
}

// handle special cli options
// eg. --help
//     --version
//     --path
//     --mode=...
//     --once-without-match
func handleSpecialCliOptions(argparser *flags.Parser, args []string) ([]string) {
    // --version
    if (opts.ShowVersion) {
        fmt.Printf("goreplace version %s\n", Version)
        os.Exit(0)
    }

    // --help
    if (opts.ShowHelp) {
        argparser.WriteHelp(os.Stdout)
        os.Exit(1)
    }

    // --mode
    switch mode := opts.Mode; mode {
        case "replace":
            opts.ModeIsReplaceMatch = true
            opts.ModeIsReplaceLine = false
            opts.ModeIsLineInFile = false
        case "line":
            opts.ModeIsReplaceMatch = false
            opts.ModeIsReplaceLine = true
            opts.ModeIsLineInFile = false
        case "lineinfile":
            opts.ModeIsReplaceMatch = false
            opts.ModeIsReplaceLine = false
            opts.ModeIsLineInFile = true
    }

    // --path
    if (opts.Path != "") {
        searchFilesInPath(opts.Path, func(f os.FileInfo, path string) {
            args = append(args, path)
        })
    }

    // --once-without-match
    if opts.OnceRemoveMatch {
        // implicit enables once mode
        opts.Once = true
    }

    return args
}

func main() {
    var changesets = []changeset {}

    var argparser = flags.NewParser(&opts, flags.PassDoubleDash)
    args, err := argparser.Parse()

    args = handleSpecialCliOptions(argparser, args)

    // check if there is an parse error
    if err != nil {
        logError(err)
        fmt.Println()
        argparser.WriteHelp(os.Stdout)
        os.Exit(1)
    }

    // check if search and replace options have equal lenght (equal number of options)
    if len(opts.Search) != len(opts.Replace) {
        // error: unequal numbers of search and replace options
        err := errors.New("Unequal numbers of search or replace options")
        logError(err)
        fmt.Println()
        argparser.WriteHelp(os.Stdout)
        os.Exit(1)
    }

    // build changesets
    for i := range opts.Search {
        search := opts.Search[i]
        replace := opts.Replace[i]

        changeset := changeset{buildSearchTerm(search), replace, false}

        changesets = append(changesets, changeset)
    }

     // check if there is at least one file to process
    if (len(args) == 0) {
        if (opts.IgnoreEmpty) {
            // no files found, but we should ignore empty filelist
            logMessage("No files found, requsted to ignore this")
            os.Exit(0)
        } else {
            // no files found, print error and exit with error code
            err := errors.New("No files specified")
            logError(err)
            fmt.Println()
            argparser.WriteHelp(os.Stdout)
            os.Exit(1)
        }
    }

    results := make(chan changeresult)

    var wg sync.WaitGroup

    // process file list
    for i := range args {
        file := fileitem{args[i]}

        wg.Add(1)
        go func(file fileitem, changesets []changeset) {
            output, status := applyChangesetsToFile(file, changesets)
            results <- changeresult{file, output, status}
            wg.Done()
        } (file, changesets);
    }

    // wait for all changes to be processed
    go func() {
        wg.Wait()
        close(results)
    }()

    // show results
    if opts.Verbose {
        for result := range results {
            title := fmt.Sprintf("%s:", result.File.Path)

            fmt.Println()
            fmt.Println(title)
            fmt.Println(strings.Repeat("-", len(title)))
            fmt.Println()
            fmt.Println(result.Output)
            fmt.Println()
        }
    }

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


<commit_before>package main

import (
	"os"
	"path/filepath"
	"fmt"
	"regexp"
	"bytes"
	"strings"
	goopt "github.com/droundy/goopt"
	"./highlight"
	"./ignore"
)

var Author = "Alexander Solovyov"
var Version = "0.3"
var Summary = "gr [OPTS] string-to-search\n"

var byteNewLine []byte = []byte("\n")
// FIXME: global variable :(
// Used to prevent appear of sparse newline at the end of output
var prependNewLine = false

type StringList []string

var IgnoreDirs = StringList{"autom4te.cache", "blib", "_build", ".bzr", ".cdv",
	"cover_db", "CVS", "_darcs", "~.dep", "~.dot", ".git", ".hg", "~.nib",
	".pc", "~.plst", "RCS", "SCCS", "_sgbak", ".svn", "_obj"}

type RegexpList []*regexp.Regexp

var IgnoreFiles = newRegexpList([]string{`~$`, `#.+#$`, `[._].*\.swp$`,
	`core\.[0-9]+$`, `\.pyc$`, `\.o$`, `\.6$`})

var onlyName = goopt.Flag([]string{"-n", "--filename"}, []string{},
	"print only filenames", "")
var ignoreFiles = goopt.Strings([]string{"-x", "--exclude"}, "RE",
	"exclude files that match the regexp from search")
var singleline = goopt.Flag([]string{"-s", "--singleline"}, []string{},
	"match on a single line (^/$ will be beginning/end of line)", "")
var replace = goopt.String([]string{"-r", "--replace"}, "",
	"replace found substrings with this string")
var force = goopt.Flag([]string{"--force"}, []string{},
	"force replacement in binary files", "")

func main() {
	goopt.Author = Author
	goopt.Version = Version
	goopt.Summary = Summary
	goopt.Parse(nil)

	cwd, _ := os.Getwd()
	ignorer := ignore.New(cwd)
	goopt.Summary += fmt.Sprintf("\n%s\n", ignorer)

	ignorer.Append(*ignoreFiles)

	if len(goopt.Args) == 0 {
		println(goopt.Usage())
		return
	}

	pattern, err := regexp.Compile(goopt.Args[0])
	errhandle(err, true, "can't compile regexp %s", goopt.Args[0])

	searchFiles(pattern, ignorer)
}

func errhandle(err os.Error, exit bool, moreinfo string, a ...interface{}) {
	if err == nil {
		return
	}
	fmt.Fprintf(os.Stderr, "ERR %s\n%s\n", err,
		fmt.Sprintf(moreinfo, a...))
	if exit {
		os.Exit(1)
	}
}

func searchFiles(pattern *regexp.Regexp, ignorer ignore.Ignorer) {
	v := &GRVisitor{pattern, ignorer}

	errors := make(chan os.Error, 64)

	filepath.Walk(".", v, errors)

	select {
	case err := <-errors:
		errhandle(err, true, "some error")
	default:
	}
}

type GRVisitor struct {
	pattern *regexp.Regexp
	ignorer ignore.Ignorer
}

func (v *GRVisitor) VisitDir(fn string, fi *os.FileInfo) bool {
	return !v.ignorer.Ignore(fi.Name, true)
}

func (v *GRVisitor) VisitFile(fn string, fi *os.FileInfo) {
	if !fi.IsRegular() {
		return
	}

	if fi.Size >= 1024*1024*10 {
		fmt.Fprintf(os.Stderr, "Skipping %s, too big: %d\n", fn, fi.Size)
		return
	}

	if fi.Size == 0 {
		return
	}

	if v.ignorer.Ignore(fn, false) {
		return
	}

	f, content := v.GetFileAndContent(fn, fi)
	defer f.Close()

	if len(*replace) == 0 {
		v.SearchFile(fn, content)
		return
	}

	changed, result := v.ReplaceInFile(fn, content)
	if changed {
		f.Seek(0, 0)
		n, err := f.Write(result)
		errhandle(err, true, "Error writing replacement in file %s", fn)
		if int64(n) > fi.Size {
			err := f.Truncate(int64(n))
			errhandle(err, true, "Error truncating file to size %d", f)
		}
	}
}

func (v *GRVisitor) GetFileAndContent(fn string, fi *os.FileInfo) (f *os.File, content []byte) {
	var err os.Error
	var msg string

	if len(*replace) > 0 {
		f, err = os.Open(fn, os.O_RDWR, 0666)
		msg = "can't open file %s for reading and writing"
	} else {
		f, err = os.Open(fn, os.O_RDONLY, 0666)
		msg = "can't open file %s for reading"
	}

	if err != nil {
		errhandle(err, false, msg, fn)
		return
	}

	content = make([]byte, fi.Size)
	n, err := f.Read(content)
	errhandle(err, true, "can't read file %s", fn)
	if int64(n) != fi.Size {
		panic(fmt.Sprintf("Not whole file was read, only %d from %d",
			n, fi.Size))
	}

	return
}

func (v *GRVisitor) SearchFile(fn string, content []byte) {
	lines := IntList([]int{})
	binary := false

	if bytes.IndexByte(content, 0) != -1 {
		binary = true
	}

	for _, info := range v.FindAllIndex(content) {
		if lines.Contains(info.num) {
			continue
		}

		if prependNewLine {
			fmt.Println("")
			prependNewLine = false
		}

		var first = len(lines) == 0
		lines = append(lines, info.num)

		if first {
			if binary && !*onlyName {
				fmt.Printf("Binary file %s matches\n", fn)
				break
			} else {
				highlight.Printf("green", "%s\n", fn)
			}
		}

		if *onlyName {
			return
		}

		highlight.Printf("bold yellow", "%d:", info.num)
		highlight.Reprintlnf("on_yellow", v.pattern, "%s", info.line)
	}

	if len(lines) > 0 {
		prependNewLine = true
	}
}

func getSuffix(num int) string {
	if num > 1 {
		return "s"
	}
	return ""
}

func (v *GRVisitor) ReplaceInFile(fn string, content []byte) (changed bool, result []byte) {
	changed = false
	binary := false
	changenum := 0

	if *singleline {
		panic("Can't handle singleline replacements yet")
	}

	if bytes.IndexByte(content, 0) != -1 {
		binary = true
	}

	result = v.pattern.ReplaceAllFunc(content, func (s []byte) []byte {
		if binary && !*force {
			errhandle(
				os.NewError("supply --force to force change of binary file"),
				false, "")
		}
		if !changed {
			changed = true
			highlight.Printf("green", "%s", fn)
		}

		changenum += 1
		return []byte(*replace)
	})

	if changenum > 0 {
		highlight.Printf("bold yellow", " - %d change%s made\n",
			changenum, getSuffix(changenum))
	}

	return changed, result
}

type LineInfo struct {
	num  int
	line []byte
}

// will return slice of [linenum, line] slices
func (v *GRVisitor) FindAllIndex(content []byte) (res []*LineInfo) {
	linenum := 1

	if *singleline {
		begin, end := 0, 0
		for i := 0; i < len(content); i++ {
			if content[i] == '\n' {
				end = i
				line := content[begin:end]
				if v.pattern.Match(line) {
					res = append(res, &LineInfo{linenum, line})
				}
				linenum += 1
				begin = end + 1
			}
		}
		return res
	}

	last := 0
	for _, bounds := range v.pattern.FindAllIndex(content, -1) {
		linenum += bytes.Count(content[last:bounds[0]], byteNewLine)
		last = bounds[0]
		begin, end := beginend(content, bounds[0], bounds[1])
		res = append(res, &LineInfo{linenum, content[begin:end]})
	}
	return res
}

// Given a []byte, start and finish of some inner slice, will find nearest
// newlines on both ends of this slice
func beginend(s []byte, start int, finish int) (begin int, end int) {
	begin = 0
	end = len(s)

	for i := start; i >= 0; i-- {
		if s[i] == byteNewLine[0] {
			begin = i + 1
			break
		}
	}

	// -1 to check if current location is not end of string
	for i := finish - 1; i < len(s); i++ {
		if s[i] == byteNewLine[0] {
			end = i
			break
		}
	}

	return
}

type IntList []int
func (il IntList) Contains(i int) bool {
	for _, x := range il {
		if x == i {
			return true
		}
	}
	return false
}

func (sl StringList) Contains(s string) bool {
	for _, x := range sl {
		if x == s {
			return true
		}
	}
	return false
}

func (sl StringList) Join(sep string) string {
	return strings.Join(sl, sep)
}

func (rl RegexpList) Match(s string) bool {
	for _, x := range rl {
		if x.Match([]byte(s)) {
			return true
		}
	}
	return false
}

func (rl RegexpList) Join(sep string) string {
	arr := make([]string, len(rl))
	for i, x := range rl {
		arr[i] = x.String()
	}
	return strings.Join(arr, sep)
}

func newRegexpList(sa []string) RegexpList {
	ra := make(RegexpList, len(sa))
	for i, s := range sa {
		ra[i] = regexp.MustCompile(s)
	}
	return ra
}
<commit_msg>delete unused code<commit_after>package main

import (
	"os"
	"path/filepath"
	"fmt"
	"regexp"
	"bytes"
	goopt "github.com/droundy/goopt"
	"./highlight"
	"./ignore"
)

var Author = "Alexander Solovyov"
var Version = "0.3"
var Summary = "gr [OPTS] string-to-search\n"

var byteNewLine []byte = []byte("\n")
// FIXME: global variable :(
// Used to prevent appear of sparse newline at the end of output
var prependNewLine = false

var onlyName = goopt.Flag([]string{"-n", "--filename"}, []string{},
	"print only filenames", "")
var ignoreFiles = goopt.Strings([]string{"-x", "--exclude"}, "RE",
	"exclude files that match the regexp from search")
var singleline = goopt.Flag([]string{"-s", "--singleline"}, []string{},
	"match on a single line (^/$ will be beginning/end of line)", "")
var replace = goopt.String([]string{"-r", "--replace"}, "",
	"replace found substrings with this string")
var force = goopt.Flag([]string{"--force"}, []string{},
	"force replacement in binary files", "")

func main() {
	goopt.Author = Author
	goopt.Version = Version
	goopt.Summary = Summary
	goopt.Parse(nil)

	cwd, _ := os.Getwd()
	ignorer := ignore.New(cwd)
	goopt.Summary += fmt.Sprintf("\n%s\n", ignorer)

	ignorer.Append(*ignoreFiles)

	if len(goopt.Args) == 0 {
		println(goopt.Usage())
		return
	}

	pattern, err := regexp.Compile(goopt.Args[0])
	errhandle(err, true, "can't compile regexp %s", goopt.Args[0])

	searchFiles(pattern, ignorer)
}

func errhandle(err os.Error, exit bool, moreinfo string, a ...interface{}) {
	if err == nil {
		return
	}
	fmt.Fprintf(os.Stderr, "ERR %s\n%s\n", err,
		fmt.Sprintf(moreinfo, a...))
	if exit {
		os.Exit(1)
	}
}

func searchFiles(pattern *regexp.Regexp, ignorer ignore.Ignorer) {
	v := &GRVisitor{pattern, ignorer}

	errors := make(chan os.Error, 64)

	filepath.Walk(".", v, errors)

	select {
	case err := <-errors:
		errhandle(err, true, "some error")
	default:
	}
}

type GRVisitor struct {
	pattern *regexp.Regexp
	ignorer ignore.Ignorer
}

func (v *GRVisitor) VisitDir(fn string, fi *os.FileInfo) bool {
	return !v.ignorer.Ignore(fi.Name, true)
}

func (v *GRVisitor) VisitFile(fn string, fi *os.FileInfo) {
	if !fi.IsRegular() {
		return
	}

	if fi.Size >= 1024*1024*10 {
		fmt.Fprintf(os.Stderr, "Skipping %s, too big: %d\n", fn, fi.Size)
		return
	}

	if fi.Size == 0 {
		return
	}

	if v.ignorer.Ignore(fn, false) {
		return
	}

	f, content := v.GetFileAndContent(fn, fi)
	defer f.Close()

	if len(*replace) == 0 {
		v.SearchFile(fn, content)
		return
	}

	changed, result := v.ReplaceInFile(fn, content)
	if changed {
		f.Seek(0, 0)
		n, err := f.Write(result)
		errhandle(err, true, "Error writing replacement in file %s", fn)
		if int64(n) > fi.Size {
			err := f.Truncate(int64(n))
			errhandle(err, true, "Error truncating file to size %d", f)
		}
	}
}

func (v *GRVisitor) GetFileAndContent(fn string, fi *os.FileInfo) (f *os.File, content []byte) {
	var err os.Error
	var msg string

	if len(*replace) > 0 {
		f, err = os.Open(fn, os.O_RDWR, 0666)
		msg = "can't open file %s for reading and writing"
	} else {
		f, err = os.Open(fn, os.O_RDONLY, 0666)
		msg = "can't open file %s for reading"
	}

	if err != nil {
		errhandle(err, false, msg, fn)
		return
	}

	content = make([]byte, fi.Size)
	n, err := f.Read(content)
	errhandle(err, true, "can't read file %s", fn)
	if int64(n) != fi.Size {
		panic(fmt.Sprintf("Not whole file was read, only %d from %d",
			n, fi.Size))
	}

	return
}

func (v *GRVisitor) SearchFile(fn string, content []byte) {
	lines := IntList([]int{})
	binary := false

	if bytes.IndexByte(content, 0) != -1 {
		binary = true
	}

	for _, info := range v.FindAllIndex(content) {
		if lines.Contains(info.num) {
			continue
		}

		if prependNewLine {
			fmt.Println("")
			prependNewLine = false
		}

		var first = len(lines) == 0
		lines = append(lines, info.num)

		if first {
			if binary && !*onlyName {
				fmt.Printf("Binary file %s matches\n", fn)
				break
			} else {
				highlight.Printf("green", "%s\n", fn)
			}
		}

		if *onlyName {
			return
		}

		highlight.Printf("bold yellow", "%d:", info.num)
		highlight.Reprintlnf("on_yellow", v.pattern, "%s", info.line)
	}

	if len(lines) > 0 {
		prependNewLine = true
	}
}

func getSuffix(num int) string {
	if num > 1 {
		return "s"
	}
	return ""
}

func (v *GRVisitor) ReplaceInFile(fn string, content []byte) (changed bool, result []byte) {
	changed = false
	binary := false
	changenum := 0

	if *singleline {
		panic("Can't handle singleline replacements yet")
	}

	if bytes.IndexByte(content, 0) != -1 {
		binary = true
	}

	result = v.pattern.ReplaceAllFunc(content, func (s []byte) []byte {
		if binary && !*force {
			errhandle(
				os.NewError("supply --force to force change of binary file"),
				false, "")
		}
		if !changed {
			changed = true
			highlight.Printf("green", "%s", fn)
		}

		changenum += 1
		return []byte(*replace)
	})

	if changenum > 0 {
		highlight.Printf("bold yellow", " - %d change%s made\n",
			changenum, getSuffix(changenum))
	}

	return changed, result
}

type LineInfo struct {
	num  int
	line []byte
}

// will return slice of [linenum, line] slices
func (v *GRVisitor) FindAllIndex(content []byte) (res []*LineInfo) {
	linenum := 1

	if *singleline {
		begin, end := 0, 0
		for i := 0; i < len(content); i++ {
			if content[i] == '\n' {
				end = i
				line := content[begin:end]
				if v.pattern.Match(line) {
					res = append(res, &LineInfo{linenum, line})
				}
				linenum += 1
				begin = end + 1
			}
		}
		return res
	}

	last := 0
	for _, bounds := range v.pattern.FindAllIndex(content, -1) {
		linenum += bytes.Count(content[last:bounds[0]], byteNewLine)
		last = bounds[0]
		begin, end := beginend(content, bounds[0], bounds[1])
		res = append(res, &LineInfo{linenum, content[begin:end]})
	}
	return res
}

// Given a []byte, start and finish of some inner slice, will find nearest
// newlines on both ends of this slice
func beginend(s []byte, start int, finish int) (begin int, end int) {
	begin = 0
	end = len(s)

	for i := start; i >= 0; i-- {
		if s[i] == byteNewLine[0] {
			begin = i + 1
			break
		}
	}

	// -1 to check if current location is not end of string
	for i := finish - 1; i < len(s); i++ {
		if s[i] == byteNewLine[0] {
			end = i
			break
		}
	}

	return
}

type IntList []int
func (il IntList) Contains(i int) bool {
	for _, x := range il {
		if x == i {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>// Copyright 2018 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// Package gvisor provides support for gVisor, user-space kernel, testing.
// See https://github.com/google/gvisor
package gvisor

import (
	"bytes"
	"fmt"
	"io"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"
	"time"

	"github.com/google/syzkaller/pkg/config"
	"github.com/google/syzkaller/pkg/osutil"
	"github.com/google/syzkaller/vm/vmimpl"
)

func init() {
	vmimpl.Register("gvisor", ctor)
}

type Config struct {
	Count     int    `json:"count"` // number of VMs to use
	RunscArgs string `json:"runsc_args"`
}

type Pool struct {
	env *vmimpl.Env
	cfg *Config
}

type instance struct {
	cfg      *Config
	image    string
	debug    bool
	rootDir  string
	imageDir string
	name     string
	port     int
	cmd      *exec.Cmd
	merger   *vmimpl.OutputMerger
}

func ctor(env *vmimpl.Env) (vmimpl.Pool, error) {
	cfg := &Config{
		Count: 1,
	}
	if err := config.LoadData(env.Config, cfg); err != nil {
		return nil, fmt.Errorf("failed to parse vm config: %v", err)
	}
	if cfg.Count < 1 || cfg.Count > 1000 {
		return nil, fmt.Errorf("invalid config param count: %v, want [1, 1000]", cfg.Count)
	}
	if env.Debug {
		cfg.Count = 1
	}
	if !osutil.IsExist(env.Image) {
		return nil, fmt.Errorf("image file %q does not exist", env.Image)
	}
	pool := &Pool{
		cfg: cfg,
		env: env,
	}
	return pool, nil
}

func (pool *Pool) Count() int {
	return pool.cfg.Count
}

func (pool *Pool) Create(workdir string, index int) (vmimpl.Instance, error) {
	rootDir := filepath.Clean(filepath.Join(workdir, "..", "gvisor_root"))
	imageDir := filepath.Join(workdir, "image")
	bundleDir := filepath.Join(workdir, "bundle")
	osutil.MkdirAll(rootDir)
	osutil.MkdirAll(bundleDir)
	osutil.MkdirAll(imageDir)
	vmConfig := fmt.Sprintf(configTempl, imageDir)
	if err := osutil.WriteFile(filepath.Join(bundleDir, "config.json"), []byte(vmConfig)); err != nil {
		return nil, err
	}
	if err := osutil.CopyFile(os.Args[0], filepath.Join(imageDir, "init")); err != nil {
		return nil, err
	}

	rpipe, wpipe, err := osutil.LongPipe()
	if err != nil {
		return nil, err
	}
	var tee io.Writer
	if pool.env.Debug {
		tee = os.Stdout
	}
	merger := vmimpl.NewOutputMerger(tee)
	merger.Add("gvisor", rpipe)

	inst := &instance{
		cfg:      pool.cfg,
		image:    pool.env.Image,
		debug:    pool.env.Debug,
		rootDir:  rootDir,
		imageDir: imageDir,
		name:     fmt.Sprintf("%v-%v", pool.env.Name, index),
		merger:   merger,
	}

	// Kill the previous instance in case it's still running.
	osutil.Run(time.Minute, inst.runscCmd("delete", "-force", inst.name))
	time.Sleep(3 * time.Second)

	cmd := inst.runscCmd("run", "-bundle", bundleDir, inst.name)
	cmd.Stdout = wpipe
	cmd.Stderr = wpipe
	if err := cmd.Start(); err != nil {
		wpipe.Close()
		merger.Wait()
		return nil, err
	}
	inst.cmd = cmd
	wpipe.Close()

	if err := inst.waitBoot(); err != nil {
		inst.Close()
		return nil, err
	}
	return inst, nil
}

func (inst *instance) waitBoot() error {
	errorMsg := []byte("FATAL ERROR:")
	bootedMsg := []byte(initStartMsg)
	timeout := time.NewTimer(time.Minute)
	defer timeout.Stop()
	var output []byte
	for {
		select {
		case out := <-inst.merger.Output:
			output = append(output, out...)
			if pos := bytes.Index(output, errorMsg); pos != -1 {
				end := bytes.IndexByte(output[pos:], '\n')
				if end == -1 {
					end = len(output)
				} else {
					end += pos
				}
				return vmimpl.BootError{
					Title:  string(output[pos:end]),
					Output: output,
				}
			}
			if bytes.Contains(output, bootedMsg) {
				return nil
			}
		case err := <-inst.merger.Err:
			return vmimpl.BootError{
				Title:  fmt.Sprintf("runsc failed: %v", err),
				Output: output,
			}
		case <-timeout.C:
			return vmimpl.BootError{
				Title:  "init process did not start",
				Output: output,
			}
		}
	}
}

func (inst *instance) runscCmd(add ...string) *exec.Cmd {
	args := []string{
		"-root", inst.rootDir,
		"-network=none",
	}
	args = append(args, strings.Split(inst.cfg.RunscArgs, " ")...)
	args = append(args, add...)
	cmd := osutil.Command(inst.image, args...)
	cmd.Env = []string{
		"GOTRACEBACK=all",
		"GORACE=halt_on_error=1",
	}
	return cmd
}

func (inst *instance) Close() {
	time.Sleep(3 * time.Second)
	osutil.Run(time.Minute, inst.runscCmd("delete", "-force", inst.name))
	inst.cmd.Process.Kill()
	inst.merger.Wait()
	inst.cmd.Wait()
	osutil.Run(time.Minute, inst.runscCmd("delete", "-force", inst.name))
	time.Sleep(3 * time.Second)
}

func (inst *instance) Forward(port int) (string, error) {
	if inst.port != 0 {
		return "", fmt.Errorf("forward port is already setup")
	}
	inst.port = port
	return "stdin", nil
}

func (inst *instance) Copy(hostSrc string) (string, error) {
	fname := filepath.Base(hostSrc)
	if err := osutil.CopyFile(hostSrc, filepath.Join(inst.imageDir, fname)); err != nil {
		return "", err
	}
	if err := os.Chmod(inst.imageDir, 0777); err != nil {
		return "", err
	}
	return filepath.Join("/", fname), nil
}

func (inst *instance) Run(timeout time.Duration, stop <-chan bool, command string) (
	<-chan []byte, <-chan error, error) {
	args := []string{"exec", "-user=0:0"}
	for _, c := range sandboxCaps {
		args = append(args, "-cap", c)
	}
	args = append(args, inst.name)
	args = append(args, strings.Split(command, " ")...)
	cmd := inst.runscCmd(args...)

	rpipe, wpipe, err := osutil.LongPipe()
	if err != nil {
		return nil, nil, err
	}
	defer wpipe.Close()
	inst.merger.Add("cmd", rpipe)
	cmd.Stdout = wpipe
	cmd.Stderr = wpipe

	guestSock, err := inst.guestProxy()
	if err != nil {
		return nil, nil, err
	}
	if guestSock != nil {
		defer guestSock.Close()
		cmd.Stdin = guestSock
	}

	if err := cmd.Start(); err != nil {
		return nil, nil, err
	}
	errc := make(chan error, 1)
	signal := func(err error) {
		select {
		case errc <- err:
		default:
		}
	}

	go func() {
		select {
		case <-time.After(timeout):
			signal(vmimpl.ErrTimeout)
		case <-stop:
			signal(vmimpl.ErrTimeout)
		case err := <-inst.merger.Err:
			cmd.Process.Kill()
			if cmdErr := cmd.Wait(); cmdErr == nil {
				// If the command exited successfully, we got EOF error from merger.
				// But in this case no error has happened and the EOF is expected.
				err = nil
			}
			signal(err)
			return
		}
		cmd.Process.Kill()
		cmd.Wait()
	}()
	return inst.merger.Output, errc, nil
}

func (inst *instance) guestProxy() (*os.File, error) {
	if inst.port == 0 {
		return nil, nil
	}
	// One does not simply let gvisor guest connect to host tcp port.
	// We create a unix socket, pass it to guest in stdin.
	// Guest will use it instead of dialing manager directly.
	// On host we connect to manager tcp port and proxy between the tcp and unix connections.
	socks, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
	if err != nil {
		return nil, err
	}
	hostSock := os.NewFile(uintptr(socks[0]), "host unix proxy")
	guestSock := os.NewFile(uintptr(socks[1]), "guest unix proxy")
	conn, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%v", inst.port))
	if err != nil {
		conn.Close()
		hostSock.Close()
		guestSock.Close()
		return nil, err
	}
	go func() {
		io.Copy(hostSock, conn)
		hostSock.Close()
	}()
	go func() {
		io.Copy(conn, hostSock)
		conn.Close()
	}()
	return guestSock, nil
}

func (inst *instance) Diagnose() bool {
	osutil.Run(time.Minute, inst.runscCmd("debug", "-stacks", inst.name))
	return true
}

func init() {
	if os.Getenv("SYZ_GVISOR_PROXY") != "" {
		fmt.Fprintf(os.Stderr, initStartMsg)
		select {}
	}
}

const initStartMsg = "SYZKALLER INIT STARTED\n"

const configTempl = `
{
	"root": {
		"path": "%v",
		"readonly": true
	},
	"process":{
                "args": ["/init"],
                "cwd": "/tmp",
                "env": ["SYZ_GVISOR_PROXY=1"]
	}
}
`

var sandboxCaps = []string{
	"CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID",
	"CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE",
	"CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW",
	"CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT",
	"CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE",
	"CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE",
	"CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN",
	"CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ",
}
<commit_msg>vm/gvisor: always give vm all caps<commit_after>// Copyright 2018 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// Package gvisor provides support for gVisor, user-space kernel, testing.
// See https://github.com/google/gvisor
package gvisor

import (
	"bytes"
	"fmt"
	"io"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"
	"time"

	"github.com/google/syzkaller/pkg/config"
	"github.com/google/syzkaller/pkg/osutil"
	"github.com/google/syzkaller/vm/vmimpl"
)

func init() {
	vmimpl.Register("gvisor", ctor)
}

type Config struct {
	Count     int    `json:"count"` // number of VMs to use
	RunscArgs string `json:"runsc_args"`
}

type Pool struct {
	env *vmimpl.Env
	cfg *Config
}

type instance struct {
	cfg      *Config
	image    string
	debug    bool
	rootDir  string
	imageDir string
	name     string
	port     int
	cmd      *exec.Cmd
	merger   *vmimpl.OutputMerger
}

func ctor(env *vmimpl.Env) (vmimpl.Pool, error) {
	cfg := &Config{
		Count: 1,
	}
	if err := config.LoadData(env.Config, cfg); err != nil {
		return nil, fmt.Errorf("failed to parse vm config: %v", err)
	}
	if cfg.Count < 1 || cfg.Count > 1000 {
		return nil, fmt.Errorf("invalid config param count: %v, want [1, 1000]", cfg.Count)
	}
	if env.Debug {
		cfg.Count = 1
	}
	if !osutil.IsExist(env.Image) {
		return nil, fmt.Errorf("image file %q does not exist", env.Image)
	}
	pool := &Pool{
		cfg: cfg,
		env: env,
	}
	return pool, nil
}

func (pool *Pool) Count() int {
	return pool.cfg.Count
}

func (pool *Pool) Create(workdir string, index int) (vmimpl.Instance, error) {
	rootDir := filepath.Clean(filepath.Join(workdir, "..", "gvisor_root"))
	imageDir := filepath.Join(workdir, "image")
	bundleDir := filepath.Join(workdir, "bundle")
	osutil.MkdirAll(rootDir)
	osutil.MkdirAll(bundleDir)
	osutil.MkdirAll(imageDir)

	caps := ""
	for _, c := range sandboxCaps {
		if caps != "" {
			caps += ", "
		}
		caps += "\"" + c + "\""
	}
	vmConfig := fmt.Sprintf(configTempl, imageDir, caps)
	if err := osutil.WriteFile(filepath.Join(bundleDir, "config.json"), []byte(vmConfig)); err != nil {
		return nil, err
	}
	if err := osutil.CopyFile(os.Args[0], filepath.Join(imageDir, "init")); err != nil {
		return nil, err
	}

	rpipe, wpipe, err := osutil.LongPipe()
	if err != nil {
		return nil, err
	}
	var tee io.Writer
	if pool.env.Debug {
		tee = os.Stdout
	}
	merger := vmimpl.NewOutputMerger(tee)
	merger.Add("gvisor", rpipe)

	inst := &instance{
		cfg:      pool.cfg,
		image:    pool.env.Image,
		debug:    pool.env.Debug,
		rootDir:  rootDir,
		imageDir: imageDir,
		name:     fmt.Sprintf("%v-%v", pool.env.Name, index),
		merger:   merger,
	}

	// Kill the previous instance in case it's still running.
	osutil.Run(time.Minute, inst.runscCmd("delete", "-force", inst.name))
	time.Sleep(3 * time.Second)

	cmd := inst.runscCmd("run", "-bundle", bundleDir, inst.name)
	cmd.Stdout = wpipe
	cmd.Stderr = wpipe
	if err := cmd.Start(); err != nil {
		wpipe.Close()
		merger.Wait()
		return nil, err
	}
	inst.cmd = cmd
	wpipe.Close()

	if err := inst.waitBoot(); err != nil {
		inst.Close()
		return nil, err
	}
	return inst, nil
}

func (inst *instance) waitBoot() error {
	errorMsg := []byte("FATAL ERROR:")
	bootedMsg := []byte(initStartMsg)
	timeout := time.NewTimer(time.Minute)
	defer timeout.Stop()
	var output []byte
	for {
		select {
		case out := <-inst.merger.Output:
			output = append(output, out...)
			if pos := bytes.Index(output, errorMsg); pos != -1 {
				end := bytes.IndexByte(output[pos:], '\n')
				if end == -1 {
					end = len(output)
				} else {
					end += pos
				}
				return vmimpl.BootError{
					Title:  string(output[pos:end]),
					Output: output,
				}
			}
			if bytes.Contains(output, bootedMsg) {
				return nil
			}
		case err := <-inst.merger.Err:
			return vmimpl.BootError{
				Title:  fmt.Sprintf("runsc failed: %v", err),
				Output: output,
			}
		case <-timeout.C:
			return vmimpl.BootError{
				Title:  "init process did not start",
				Output: output,
			}
		}
	}
}

func (inst *instance) runscCmd(add ...string) *exec.Cmd {
	args := []string{
		"-root", inst.rootDir,
		"-network=none",
	}
	args = append(args, strings.Split(inst.cfg.RunscArgs, " ")...)
	args = append(args, add...)
	cmd := osutil.Command(inst.image, args...)
	cmd.Env = []string{
		"GOTRACEBACK=all",
		"GORACE=halt_on_error=1",
	}
	return cmd
}

func (inst *instance) Close() {
	time.Sleep(3 * time.Second)
	osutil.Run(time.Minute, inst.runscCmd("delete", "-force", inst.name))
	inst.cmd.Process.Kill()
	inst.merger.Wait()
	inst.cmd.Wait()
	osutil.Run(time.Minute, inst.runscCmd("delete", "-force", inst.name))
	time.Sleep(3 * time.Second)
}

func (inst *instance) Forward(port int) (string, error) {
	if inst.port != 0 {
		return "", fmt.Errorf("forward port is already setup")
	}
	inst.port = port
	return "stdin", nil
}

func (inst *instance) Copy(hostSrc string) (string, error) {
	fname := filepath.Base(hostSrc)
	if err := osutil.CopyFile(hostSrc, filepath.Join(inst.imageDir, fname)); err != nil {
		return "", err
	}
	if err := os.Chmod(inst.imageDir, 0777); err != nil {
		return "", err
	}
	return filepath.Join("/", fname), nil
}

func (inst *instance) Run(timeout time.Duration, stop <-chan bool, command string) (
	<-chan []byte, <-chan error, error) {
	args := []string{"exec", "-user=0:0"}
	for _, c := range sandboxCaps {
		args = append(args, "-cap", c)
	}
	args = append(args, inst.name)
	args = append(args, strings.Split(command, " ")...)
	cmd := inst.runscCmd(args...)

	rpipe, wpipe, err := osutil.LongPipe()
	if err != nil {
		return nil, nil, err
	}
	defer wpipe.Close()
	inst.merger.Add("cmd", rpipe)
	cmd.Stdout = wpipe
	cmd.Stderr = wpipe

	guestSock, err := inst.guestProxy()
	if err != nil {
		return nil, nil, err
	}
	if guestSock != nil {
		defer guestSock.Close()
		cmd.Stdin = guestSock
	}

	if err := cmd.Start(); err != nil {
		return nil, nil, err
	}
	errc := make(chan error, 1)
	signal := func(err error) {
		select {
		case errc <- err:
		default:
		}
	}

	go func() {
		select {
		case <-time.After(timeout):
			signal(vmimpl.ErrTimeout)
		case <-stop:
			signal(vmimpl.ErrTimeout)
		case err := <-inst.merger.Err:
			cmd.Process.Kill()
			if cmdErr := cmd.Wait(); cmdErr == nil {
				// If the command exited successfully, we got EOF error from merger.
				// But in this case no error has happened and the EOF is expected.
				err = nil
			}
			signal(err)
			return
		}
		cmd.Process.Kill()
		cmd.Wait()
	}()
	return inst.merger.Output, errc, nil
}

func (inst *instance) guestProxy() (*os.File, error) {
	if inst.port == 0 {
		return nil, nil
	}
	// One does not simply let gvisor guest connect to host tcp port.
	// We create a unix socket, pass it to guest in stdin.
	// Guest will use it instead of dialing manager directly.
	// On host we connect to manager tcp port and proxy between the tcp and unix connections.
	socks, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
	if err != nil {
		return nil, err
	}
	hostSock := os.NewFile(uintptr(socks[0]), "host unix proxy")
	guestSock := os.NewFile(uintptr(socks[1]), "guest unix proxy")
	conn, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%v", inst.port))
	if err != nil {
		conn.Close()
		hostSock.Close()
		guestSock.Close()
		return nil, err
	}
	go func() {
		io.Copy(hostSock, conn)
		hostSock.Close()
	}()
	go func() {
		io.Copy(conn, hostSock)
		conn.Close()
	}()
	return guestSock, nil
}

func (inst *instance) Diagnose() bool {
	osutil.Run(time.Minute, inst.runscCmd("debug", "-stacks", inst.name))
	return true
}

func init() {
	if os.Getenv("SYZ_GVISOR_PROXY") != "" {
		fmt.Fprintf(os.Stderr, initStartMsg)
		select {}
	}
}

const initStartMsg = "SYZKALLER INIT STARTED\n"

const configTempl = `
{
	"root": {
		"path": "%[1]v",
		"readonly": true
	},
	"process":{
                "args": ["/init"],
                "cwd": "/tmp",
                "env": ["SYZ_GVISOR_PROXY=1"],
                "capabilities": {
                	"bounding": [%[2]v],
                	"effective": [%[2]v],
                	"inheritable": [%[2]v],
                	"permitted": [%[2]v],
                	"ambient": [%[2]v]
                }
	}
}
`

var sandboxCaps = []string{
	"CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID",
	"CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE",
	"CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW",
	"CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT",
	"CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE",
	"CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE",
	"CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN",
	"CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ",
}
<|endoftext|>


<commit_before>package handlers

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

	"github.com/gorilla/mux"
	"github.com/gorilla/websocket"
	"github.com/play-with-docker/play-with-docker/event"
	"github.com/twinj/uuid"
)

var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool { return true },
}

type message struct {
	Name string        `json:"name"`
	Args []interface{} `json:"args"`
}

type socket struct {
	c         *websocket.Conn
	mx        sync.Mutex
	listeners map[string][]func(args ...interface{})
	r         *http.Request
	id        string
	closed    bool
}

func newSocket(r *http.Request, c *websocket.Conn) *socket {
	return &socket{
		c:         c,
		listeners: map[string][]func(args ...interface{}){},
		r:         r,
		id:        uuid.NewV4().String(),
	}
}

func (s *socket) Id() string {
	return s.id
}

func (s *socket) Request() *http.Request {
	return s.r
}

func (s *socket) Close() {
	s.closed = true
	s.onMessage(message{Name: "close"})
}

func (s *socket) process() {
	defer s.Close()
	for {
		mt, m, err := s.c.ReadMessage()
		if err != nil {
			log.Printf("Error reading message from websocket. Got: %v\n", err)
			break
		}
		if mt != websocket.TextMessage {
			log.Printf("Received websocket message, but it is not a text message.\n")
			continue
		}
		go func() {
			var msg message
			if err := json.Unmarshal(m, &msg); err != nil {
				log.Printf("Cannot unmarshal message received from websocket. Got: %v\n", err)
				return
			}
			s.onMessage(msg)
		}()
	}
}

func (s *socket) onMessage(msg message) {
	s.mx.Lock()
	defer s.mx.Unlock()

	cbs, found := s.listeners[msg.Name]
	if !found {
		return
	}
	for _, cb := range cbs {
		go cb(msg.Args...)
	}
}

func (s *socket) Emit(ev string, args ...interface{}) {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.closed {
		return
	}

	m := message{Name: ev, Args: args}
	b, err := json.Marshal(m)
	if err != nil {
		log.Printf("Cannot marshal event to json. Got: %v\n", err)
		return
	}
	if err := s.c.WriteMessage(websocket.TextMessage, b); err != nil {
		log.Printf("Cannot write event to websocket connection. Got: %v\n", err)
		s.Close()
		return
	}
}

func (s *socket) On(ev string, cb func(args ...interface{})) {
	s.mx.Lock()
	defer s.mx.Unlock()
	listeners, found := s.listeners[ev]
	if !found {
		listeners = []func(args ...interface{}){}
	}
	listeners = append(listeners, cb)
	s.listeners[ev] = listeners
}

func WSH(w http.ResponseWriter, r *http.Request) {
	c, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Print("upgrade:", err)
		return
	}
	defer c.Close()

	s := newSocket(r, c)
	ws(s)
	s.process()
}

func ws(so *socket) {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println("Recovered from ", r)
		}
	}()
	vars := mux.Vars(so.Request())

	sessionId := vars["sessionId"]

	session := core.SessionGet(sessionId)
	if session == nil {
		log.Printf("Session with id [%s] does not exist!\n", sessionId)
		return
	}

	client := core.ClientNew(so.Id(), session)

	m, err := NewManager(session)
	if err != nil {
		log.Printf("Error creating terminal manager. Got: %v", err)
		return
	}

	go m.Receive(func(name string, data []byte) {
		so.Emit("instance terminal out", name, string(data))
	})
	go m.Status(func(name, status string) {
		so.Emit("instance terminal status", name, status)
	})

	err = m.Start()
	if err != nil {
		log.Println(err)
		return
	}

	so.On("session close", func(args ...interface{}) {
		m.Close()
		core.SessionClose(session)
	})

	so.On("instance terminal in", func(args ...interface{}) {
		name := args[0].(string)
		data := args[1].(string)
		m.Send(name, []byte(data))
	})

	so.On("instance viewport resize", func(args ...interface{}) {
		// User resized his viewport
		cols := args[0].(float64)
		rows := args[1].(float64)
		core.ClientResizeViewPort(client, uint(cols), uint(rows))
	})

	so.On("close", func(args ...interface{}) {
		m.Close()
		core.ClientClose(client)
	})

	e.OnAny(func(eventType event.EventType, sessionId string, args ...interface{}) {
		if session.Id == sessionId {
			so.Emit(eventType.String(), args...)
		}
	})
}
<commit_msg>Add check to avoid panic when receiving msg<commit_after>package handlers

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

	"github.com/gorilla/mux"
	"github.com/gorilla/websocket"
	"github.com/play-with-docker/play-with-docker/event"
	"github.com/twinj/uuid"
)

var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool { return true },
}

type message struct {
	Name string        `json:"name"`
	Args []interface{} `json:"args"`
}

type socket struct {
	c         *websocket.Conn
	mx        sync.Mutex
	listeners map[string][]func(args ...interface{})
	r         *http.Request
	id        string
	closed    bool
}

func newSocket(r *http.Request, c *websocket.Conn) *socket {
	return &socket{
		c:         c,
		listeners: map[string][]func(args ...interface{}){},
		r:         r,
		id:        uuid.NewV4().String(),
	}
}

func (s *socket) Id() string {
	return s.id
}

func (s *socket) Request() *http.Request {
	return s.r
}

func (s *socket) Close() {
	s.closed = true
	s.onMessage(message{Name: "close"})
}

func (s *socket) process() {
	defer s.Close()
	for {
		mt, m, err := s.c.ReadMessage()
		if err != nil {
			log.Printf("Error reading message from websocket. Got: %v\n", err)
			break
		}
		if mt != websocket.TextMessage {
			log.Printf("Received websocket message, but it is not a text message.\n")
			continue
		}
		go func() {
			var msg message
			if err := json.Unmarshal(m, &msg); err != nil {
				log.Printf("Cannot unmarshal message received from websocket. Got: %v\n", err)
				return
			}
			s.onMessage(msg)
		}()
	}
}

func (s *socket) onMessage(msg message) {
	s.mx.Lock()
	defer s.mx.Unlock()

	cbs, found := s.listeners[msg.Name]
	if !found {
		return
	}
	for _, cb := range cbs {
		go cb(msg.Args...)
	}
}

func (s *socket) Emit(ev string, args ...interface{}) {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.closed {
		return
	}

	m := message{Name: ev, Args: args}
	b, err := json.Marshal(m)
	if err != nil {
		log.Printf("Cannot marshal event to json. Got: %v\n", err)
		return
	}
	if err := s.c.WriteMessage(websocket.TextMessage, b); err != nil {
		log.Printf("Cannot write event to websocket connection. Got: %v\n", err)
		s.Close()
		return
	}
}

func (s *socket) On(ev string, cb func(args ...interface{})) {
	s.mx.Lock()
	defer s.mx.Unlock()
	listeners, found := s.listeners[ev]
	if !found {
		listeners = []func(args ...interface{}){}
	}
	listeners = append(listeners, cb)
	s.listeners[ev] = listeners
}

func WSH(w http.ResponseWriter, r *http.Request) {
	c, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Print("upgrade:", err)
		return
	}
	defer c.Close()

	s := newSocket(r, c)
	ws(s)
	s.process()
}

func ws(so *socket) {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println("Recovered from ", r)
		}
	}()
	vars := mux.Vars(so.Request())

	sessionId := vars["sessionId"]

	session := core.SessionGet(sessionId)
	if session == nil {
		log.Printf("Session with id [%s] does not exist!\n", sessionId)
		return
	}

	client := core.ClientNew(so.Id(), session)

	m, err := NewManager(session)
	if err != nil {
		log.Printf("Error creating terminal manager. Got: %v", err)
		return
	}

	go m.Receive(func(name string, data []byte) {
		so.Emit("instance terminal out", name, string(data))
	})
	go m.Status(func(name, status string) {
		so.Emit("instance terminal status", name, status)
	})

	err = m.Start()
	if err != nil {
		log.Println(err)
		return
	}

	so.On("session close", func(args ...interface{}) {
		m.Close()
		core.SessionClose(session)
	})

	so.On("instance terminal in", func(args ...interface{}) {
		if len(args) == 2 && args[0] != nil && args[1] != nil {
			name := args[0].(string)
			data := args[1].(string)
			m.Send(name, []byte(data))
		}
	})

	so.On("instance viewport resize", func(args ...interface{}) {
		if len(args) == 2 && args[0] != nil && args[1] != nil {
			// User resized his viewport
			cols := args[0].(float64)
			rows := args[1].(float64)
			core.ClientResizeViewPort(client, uint(cols), uint(rows))
		}
	})

	so.On("close", func(args ...interface{}) {
		m.Close()
		core.ClientClose(client)
	})

	e.OnAny(func(eventType event.EventType, sessionId string, args ...interface{}) {
		if session.Id == sessionId {
			so.Emit(eventType.String(), args...)
		}
	})
}
<|endoftext|>


<commit_before>// Copyright (c) 2016, Joseph deBlaquiere <jadeblaquiere@yahoo.com>
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// * Neither the name of ciphrtxt nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package ciphrtxt

import (
	// "bytes"
	"encoding/json"
	"fmt"
	"time"

	cwebsocket "github.com/jadeblaquiere/websocket-client"
)

const (
	DefaultWatchdogTimeout = 150 * time.Second
	DefaultTimeTickle      = 30 * time.Second
	DefaultStatusTickle    = 300 * time.Second
)

type WSDisconnectFunc func()

type WSProtocolHandler interface {
	TxHeader(rmh *RawMessageHeader)
	OnDisconnect(f WSDisconnectFunc)
	Status() *StatusResponse
}

func NewWSProtocolHandler(con cwebsocket.ClientConnection, local *LocalHeaderCache, remote *HeaderCache) WSProtocolHandler {
	wsh := wsHandler{
		con:    con,
		local:  local,
		remote: remote,
	}
	wsh.setup()
	return &wsh
}

type wsHandler struct {
	con          cwebsocket.ClientConnection
	local        *LocalHeaderCache
	remote       *HeaderCache
	tmpStatus    StatusResponse
	disconnect   WSDisconnectFunc
	watchdog     *time.Timer
	timeTickle   *time.Timer
	statusTickle *time.Timer
}

func (wsh *wsHandler) resetTimeTickle() {
	if !wsh.timeTickle.Stop() {
		<-wsh.timeTickle.C
	}
	wsh.timeTickle.Reset(DefaultTimeTickle)
	wsh.resetWatchdog()
}

func (wsh *wsHandler) resetStatusTickle() {
	if !wsh.statusTickle.Stop() {
		<-wsh.statusTickle.C
	}
	wsh.statusTickle.Reset(DefaultStatusTickle)
	wsh.resetWatchdog()
}

func (wsh *wsHandler) resetWatchdog() {
	if !wsh.watchdog.Stop() {
		<-wsh.watchdog.C
	}
	wsh.watchdog.Reset(DefaultWatchdogTimeout)
}

func (wsh *wsHandler) txTime(t int) {
	wsh.resetTimeTickle()
	if wsh.remote != nil {
		fmt.Printf("tx->TIME to %s:%d\n", wsh.remote.host, wsh.remote.port)
	} else {
		fmt.Printf("tx->TIME to Pending Peer\n")
	}
	wsh.con.Emit("response-time", int(time.Now().Unix()))
}

func (wsh *wsHandler) rxTime(t int) {
	wsh.resetWatchdog()
	if wsh.remote != nil {
		fmt.Printf("rx<-TIME from %s:%d\n", wsh.remote.host, wsh.remote.port)
		wsh.remote.serverTime = uint32(t)
	}
}

func (wsh *wsHandler) txStatus(t int) {
	wsh.resetWatchdog()
	j, err := json.Marshal(wsh.local.Status())
	if err == nil {
		if wsh.remote != nil {
			fmt.Printf("tx->STATUS to %s:%d\n", wsh.remote.host, wsh.remote.port)
		} else {
			fmt.Printf("tx->STATUS to Pending Peer\n")
		}
		wsh.con.Emit("response-status", j)
	}
}

func (wsh *wsHandler) rxStatus(m []byte) {
	var status StatusResponse
	err := json.Unmarshal(m, &status)
	if err == nil {
		wsh.resetStatusTickle()
		if wsh.remote != nil {
			fmt.Printf("rx<-STATUS from %s:%d\n", wsh.remote.host, wsh.remote.port)
			wsh.remote.status = status
		} else {
			fmt.Printf("rx<-STATUS from Pending Peer %s:%d\n", status.Network.Host, status.Network.MSGPort)
			wsh.tmpStatus = status
		}
	}
}

func (wsh *wsHandler) TxHeader(rmh *RawMessageHeader) {
	fmt.Printf("tx->HEADER to %s:%d\n", wsh.remote.host, wsh.remote.port)
	wsh.con.Emit("response-header", rmh.Serialize())
}

func (wsh *wsHandler) rxHeader(s string) {
	rmh := &RawMessageHeader{}
	err := rmh.Deserialize(s)
	if err == nil {
		wsh.resetWatchdog()
		if wsh.remote != nil {
			fmt.Printf("rx<-HEADER from %s:%d\n", wsh.remote.host, wsh.remote.port)
			insert, err := wsh.remote.Insert(rmh)
			if err != nil {
				return
			}
			if insert {
				_, _ = wsh.local.Insert(rmh)
			}
		}
	}
}

func (wsh *wsHandler) OnDisconnect(f WSDisconnectFunc) {
	wsh.disconnect = f
}

func (wsh *wsHandler) Status() *StatusResponse {
	if wsh.remote != nil {
		return &wsh.remote.status
	} else {
		return &wsh.tmpStatus
	}
}

func (wsh *wsHandler) setup() {
	wsh.con.On("request-time", wsh.txTime)
	wsh.con.On("response-time", wsh.rxTime)
	wsh.con.On("request-status", wsh.txStatus)
	wsh.con.On("response-status", wsh.rxStatus)
	wsh.con.On("response-header", wsh.rxHeader)
	wsh.con.OnDisconnect(func() {
		if wsh.disconnect != nil {
			wsh.disconnect()
		}
	})
	wsh.watchdog = time.NewTimer(DefaultWatchdogTimeout)
	wsh.timeTickle = time.NewTimer(DefaultTimeTickle)
	wsh.statusTickle = time.NewTimer(DefaultStatusTickle)

	go wsh.eventLoop()
}

func (wsh *wsHandler) eventLoop() {
	for {
		select {
		case <-wsh.watchdog.C:
			fmt.Println("Watchdog expired, closing connection")
			wsh.con.Disconnect()
			if wsh.disconnect != nil {
				wsh.disconnect()
			}
			return
		case <-wsh.timeTickle.C:
			if wsh.remote != nil {
				fmt.Printf("tx->TIME REQUEST to %s:%d\n", wsh.remote.host, wsh.remote.port)
			} else {
				fmt.Printf("tx->TIME REQUEST to Pending Peer\n")
			}
			wsh.con.Emit("request-time", int(0))
			wsh.timeTickle.Reset(DefaultTimeTickle)
			continue
		case <-wsh.statusTickle.C:
			if wsh.remote != nil {
				fmt.Printf("tx->STATUS REQUEST to %s:%d\n", wsh.remote.host, wsh.remote.port)
			} else {
				fmt.Printf("tx->STATUS REQUEST to Pending Peer\n")
			}
			wsh.con.Emit("request-status", int(0))
			wsh.statusTickle.Reset(DefaultStatusTickle)
			continue
		}
	}
}
<commit_msg>fixing race condition, create timers before enabling handlers that reset timers<commit_after>// Copyright (c) 2016, Joseph deBlaquiere <jadeblaquiere@yahoo.com>
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// * Neither the name of ciphrtxt nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package ciphrtxt

import (
	// "bytes"
	"encoding/json"
	"fmt"
	"time"

	cwebsocket "github.com/jadeblaquiere/websocket-client"
)

const (
	DefaultWatchdogTimeout = 150 * time.Second
	DefaultTimeTickle      = 30 * time.Second
	DefaultStatusTickle    = 300 * time.Second
)

type WSDisconnectFunc func()

type WSProtocolHandler interface {
	TxHeader(rmh *RawMessageHeader)
	OnDisconnect(f WSDisconnectFunc)
	Status() *StatusResponse
}

func NewWSProtocolHandler(con cwebsocket.ClientConnection, local *LocalHeaderCache, remote *HeaderCache) WSProtocolHandler {
	wsh := wsHandler{
		con:    con,
		local:  local,
		remote: remote,
	}
	wsh.setup()
	return &wsh
}

type wsHandler struct {
	con          cwebsocket.ClientConnection
	local        *LocalHeaderCache
	remote       *HeaderCache
	tmpStatus    StatusResponse
	disconnect   WSDisconnectFunc
	watchdog     *time.Timer
	timeTickle   *time.Timer
	statusTickle *time.Timer
}

func (wsh *wsHandler) resetTimeTickle() {
	if !wsh.timeTickle.Stop() {
		<-wsh.timeTickle.C
	}
	wsh.timeTickle.Reset(DefaultTimeTickle)
	wsh.resetWatchdog()
}

func (wsh *wsHandler) resetStatusTickle() {
	if !wsh.statusTickle.Stop() {
		<-wsh.statusTickle.C
	}
	wsh.statusTickle.Reset(DefaultStatusTickle)
	wsh.resetWatchdog()
}

func (wsh *wsHandler) resetWatchdog() {
	if !wsh.watchdog.Stop() {
		<-wsh.watchdog.C
	}
	wsh.watchdog.Reset(DefaultWatchdogTimeout)
}

func (wsh *wsHandler) txTime(t int) {
	wsh.resetTimeTickle()
	if wsh.remote != nil {
		fmt.Printf("tx->TIME to %s:%d\n", wsh.remote.host, wsh.remote.port)
	} else {
		fmt.Printf("tx->TIME to Pending Peer\n")
	}
	wsh.con.Emit("response-time", int(time.Now().Unix()))
}

func (wsh *wsHandler) rxTime(t int) {
	wsh.resetWatchdog()
	if wsh.remote != nil {
		fmt.Printf("rx<-TIME from %s:%d\n", wsh.remote.host, wsh.remote.port)
		wsh.remote.serverTime = uint32(t)
	}
}

func (wsh *wsHandler) txStatus(t int) {
	wsh.resetWatchdog()
	j, err := json.Marshal(wsh.local.Status())
	if err == nil {
		if wsh.remote != nil {
			fmt.Printf("tx->STATUS to %s:%d\n", wsh.remote.host, wsh.remote.port)
		} else {
			fmt.Printf("tx->STATUS to Pending Peer\n")
		}
		wsh.con.Emit("response-status", j)
	}
}

func (wsh *wsHandler) rxStatus(m []byte) {
	var status StatusResponse
	err := json.Unmarshal(m, &status)
	if err == nil {
		wsh.resetStatusTickle()
		if wsh.remote != nil {
			fmt.Printf("rx<-STATUS from %s:%d\n", wsh.remote.host, wsh.remote.port)
			wsh.remote.status = status
		} else {
			fmt.Printf("rx<-STATUS from Pending Peer %s:%d\n", status.Network.Host, status.Network.MSGPort)
			wsh.tmpStatus = status
		}
	}
}

func (wsh *wsHandler) TxHeader(rmh *RawMessageHeader) {
	fmt.Printf("tx->HEADER to %s:%d\n", wsh.remote.host, wsh.remote.port)
	wsh.con.Emit("response-header", rmh.Serialize())
}

func (wsh *wsHandler) rxHeader(s string) {
	rmh := &RawMessageHeader{}
	err := rmh.Deserialize(s)
	if err == nil {
		wsh.resetWatchdog()
		if wsh.remote != nil {
			fmt.Printf("rx<-HEADER from %s:%d\n", wsh.remote.host, wsh.remote.port)
			insert, err := wsh.remote.Insert(rmh)
			if err != nil {
				return
			}
			if insert {
				_, _ = wsh.local.Insert(rmh)
			}
		}
	}
}

func (wsh *wsHandler) OnDisconnect(f WSDisconnectFunc) {
	wsh.disconnect = f
}

func (wsh *wsHandler) Status() *StatusResponse {
	if wsh.remote != nil {
		return &wsh.remote.status
	} else {
		return &wsh.tmpStatus
	}
}

func (wsh *wsHandler) setup() {
	wsh.watchdog = time.NewTimer(DefaultWatchdogTimeout)
	wsh.timeTickle = time.NewTimer(DefaultTimeTickle)
	wsh.statusTickle = time.NewTimer(DefaultStatusTickle)
	wsh.con.On("request-time", wsh.txTime)
	wsh.con.On("response-time", wsh.rxTime)
	wsh.con.On("request-status", wsh.txStatus)
	wsh.con.On("response-status", wsh.rxStatus)
	wsh.con.On("response-header", wsh.rxHeader)
	wsh.con.OnDisconnect(func() {
		if wsh.disconnect != nil {
			wsh.disconnect()
		}
	})

	go wsh.eventLoop()
}

func (wsh *wsHandler) eventLoop() {
	for {
		select {
		case <-wsh.watchdog.C:
			fmt.Println("Watchdog expired, closing connection")
			wsh.con.Disconnect()
			if wsh.disconnect != nil {
				wsh.disconnect()
			}
			return
		case <-wsh.timeTickle.C:
			if wsh.remote != nil {
				fmt.Printf("tx->TIME REQUEST to %s:%d\n", wsh.remote.host, wsh.remote.port)
			} else {
				fmt.Printf("tx->TIME REQUEST to Pending Peer\n")
			}
			wsh.con.Emit("request-time", int(0))
			wsh.timeTickle.Reset(DefaultTimeTickle)
			continue
		case <-wsh.statusTickle.C:
			if wsh.remote != nil {
				fmt.Printf("tx->STATUS REQUEST to %s:%d\n", wsh.remote.host, wsh.remote.port)
			} else {
				fmt.Printf("tx->STATUS REQUEST to Pending Peer\n")
			}
			wsh.con.Emit("request-status", int(0))
			wsh.statusTickle.Reset(DefaultStatusTickle)
			continue
		}
	}
}
<|endoftext|>


<commit_before>package google

import (
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func dataSourceGoogleContainerCluster() *schema.Resource {
	// Generate datasource schema from resource
	dsSchema := datasourceSchemaFromResourceSchema(resourceContainerCluster().Schema)

	// Set 'Required' schema elements
	addRequiredFieldsToSchema(dsSchema, "name")

	// Set 'Optional' schema elements
	addOptionalFieldsToSchema(dsSchema, "project", "location")

	return &schema.Resource{
		Read:   datasourceContainerClusterRead,
		Schema: dsSchema,
	}
}

func datasourceContainerClusterRead(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	clusterName := d.Get("name").(string)

	location, err := getLocation(d, config)
	if err != nil {
		return err
	}

	project, err := getProject(d, config)
	if err != nil {
		return err
	}

	d.SetId(containerClusterFullName(project, location, clusterName))

	return resourceContainerClusterRead(d, meta)
}
<commit_msg>throw error if datasource not found (#6786)<commit_after>package google

import (
	"fmt"

	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func dataSourceGoogleContainerCluster() *schema.Resource {
	// Generate datasource schema from resource
	dsSchema := datasourceSchemaFromResourceSchema(resourceContainerCluster().Schema)

	// Set 'Required' schema elements
	addRequiredFieldsToSchema(dsSchema, "name")

	// Set 'Optional' schema elements
	addOptionalFieldsToSchema(dsSchema, "project", "location")

	return &schema.Resource{
		Read:   datasourceContainerClusterRead,
		Schema: dsSchema,
	}
}

func datasourceContainerClusterRead(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	clusterName := d.Get("name").(string)

	location, err := getLocation(d, config)
	if err != nil {
		return err
	}

	project, err := getProject(d, config)
	if err != nil {
		return err
	}

	id := containerClusterFullName(project, location, clusterName)

	d.SetId(id)

	if err := resourceContainerClusterRead(d, meta); err != nil {
		return err
	}

	if d.Id() == "" {
		return fmt.Errorf("%s not found", id)
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	//"github.com/go-yaml/yaml"
)

func main() {
	fmt.Printf("Hello, world!\n")
}
<commit_msg>Read the file<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	//"github.com/go-yaml/yaml"
)

func main() {
	fmt.Printf("Readin input.yaml!\n")

	data, err := ioutil.ReadFile("input.yaml")
	if err != nil {
		panic(err)
	}
	fmt.Print(string(data))
}
<|endoftext|>


<commit_before>/*
Copyright 2018 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 autoscaling

import (
	"fmt"
	"time"

	"github.com/onsi/ginkgo"
	"github.com/onsi/gomega"
	appsv1 "k8s.io/api/apps/v1"
	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	vpa_types "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/poc.autoscaling.k8s.io/v1alpha1"
	vpa_clientset "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/client/clientset/versioned"
	"k8s.io/kubernetes/test/e2e/framework"
)

const (
	recommenderComponent         = "recommender"
	updateComponent              = "updater"
	admissionControllerComponent = "admission-controller"
	fullVpaSuite                 = "full-vpa"
	actuationSuite               = "actuation"
	pollInterval                 = 10 * time.Second
	pollTimeout                  = 15 * time.Minute
)

func e2eDescribe(scenario, name string, body func()) bool {
	return ginkgo.Describe(fmt.Sprintf("[VPA] [%s] %s", scenario, name), body)
}

func recommenderE2eDescribe(name string, body func()) bool {
	return e2eDescribe(recommenderComponent, name, body)
}

func updaterE2eDescribe(name string, body func()) bool {
	return e2eDescribe(updateComponent, name, body)
}

func admissionControllerE2eDescribe(name string, body func()) bool {
	return e2eDescribe(admissionControllerComponent, name, body)
}

func fullVpaE2eDescribe(name string, body func()) bool {
	return e2eDescribe(fullVpaSuite, name, body)
}

func actuationSuiteE2eDescribe(name string, body func()) bool {
	return e2eDescribe(actuationSuite, name, body)
}

func newHamsterDeployment(f *framework.Framework) *appsv1.Deployment {
	d := framework.NewDeployment("hamster-deployment", 3, map[string]string{"app": "hamster"}, "hamster", "k8s.gcr.io/ubuntu-slim:0.1", appsv1.RollingUpdateDeploymentStrategyType)
	d.ObjectMeta.Namespace = f.Namespace.Name
	d.Spec.Template.Spec.Containers[0].Command = []string{"/bin/sh"}
	d.Spec.Template.Spec.Containers[0].Args = []string{"-c", "/usr/bin/yes >/dev/null"}
	return d
}

func newHamsterDeploymentWithResources(f *framework.Framework, cpuQuantity, memoryQuantity resource.Quantity) *appsv1.Deployment {
	d := newHamsterDeployment(f)
	d.Spec.Template.Spec.Containers[0].Resources.Requests = v1.ResourceList{
		v1.ResourceCPU:    cpuQuantity,
		v1.ResourceMemory: memoryQuantity,
	}
	return d
}

func newVPA(f *framework.Framework, name string, selector *metav1.LabelSelector) *vpa_types.VerticalPodAutoscaler {
	updateMode := vpa_types.UpdateModeAuto
	vpa := vpa_types.VerticalPodAutoscaler{
		ObjectMeta: metav1.ObjectMeta{
			Name:      name,
			Namespace: f.Namespace.Name,
		},
		Spec: vpa_types.VerticalPodAutoscalerSpec{
			Selector: selector,
			UpdatePolicy: &vpa_types.PodUpdatePolicy{
				UpdateMode: &updateMode,
			},
			ResourcePolicy: &vpa_types.PodResourcePolicy{
				ContainerPolicies: []vpa_types.ContainerResourcePolicy{},
			},
		},
	}
	return &vpa
}

func installVPA(f *framework.Framework, vpa *vpa_types.VerticalPodAutoscaler) {
	ns := f.Namespace.Name
	config, err := framework.LoadConfig()
	gomega.Expect(err).NotTo(gomega.HaveOccurred())
	vpaClientSet := vpa_clientset.NewForConfigOrDie(config)
	vpaClient := vpaClientSet.PocV1alpha1()
	_, err = vpaClient.VerticalPodAutoscalers(ns).Create(vpa)
	gomega.Expect(err).NotTo(gomega.HaveOccurred())
}

func parseQuantityOrDie(text string) resource.Quantity {
	quantity, err := resource.ParseQuantity(text)
	gomega.Expect(err).NotTo(gomega.HaveOccurred())
	return quantity
}
<commit_msg>Add sigdescribe to VPA e2e tests.<commit_after>/*
Copyright 2018 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 autoscaling

import (
	"fmt"
	"time"

	"github.com/onsi/ginkgo"
	"github.com/onsi/gomega"
	appsv1 "k8s.io/api/apps/v1"
	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	vpa_types "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/poc.autoscaling.k8s.io/v1alpha1"
	vpa_clientset "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/client/clientset/versioned"
	"k8s.io/kubernetes/test/e2e/framework"
)

const (
	recommenderComponent         = "recommender"
	updateComponent              = "updater"
	admissionControllerComponent = "admission-controller"
	fullVpaSuite                 = "full-vpa"
	actuationSuite               = "actuation"
	pollInterval                 = 10 * time.Second
	pollTimeout                  = 15 * time.Minute
)

// SIGDescribe adds sig-autoscaling tag to test description.
func SIGDescribe(text string, body func()) bool {
	return ginkgo.Describe(fmt.Sprintf("[sig-autoscaling] %v", text), body)
}

// E2eDescribe describes a VPA e2e test.
func E2eDescribe(scenario, name string, body func()) bool {
	return SIGDescribe(fmt.Sprintf("[VPA] [%s] %s", scenario, name), body)
}

func recommenderE2eDescribe(name string, body func()) bool {
	return E2eDescribe(recommenderComponent, name, body)
}

func updaterE2eDescribe(name string, body func()) bool {
	return E2eDescribe(updateComponent, name, body)
}

func admissionControllerE2eDescribe(name string, body func()) bool {
	return E2eDescribe(admissionControllerComponent, name, body)
}

func fullVpaE2eDescribe(name string, body func()) bool {
	return E2eDescribe(fullVpaSuite, name, body)
}

func actuationSuiteE2eDescribe(name string, body func()) bool {
	return E2eDescribe(actuationSuite, name, body)
}

func newHamsterDeployment(f *framework.Framework) *appsv1.Deployment {
	d := framework.NewDeployment("hamster-deployment", 3, map[string]string{"app": "hamster"}, "hamster", "k8s.gcr.io/ubuntu-slim:0.1", appsv1.RollingUpdateDeploymentStrategyType)
	d.ObjectMeta.Namespace = f.Namespace.Name
	d.Spec.Template.Spec.Containers[0].Command = []string{"/bin/sh"}
	d.Spec.Template.Spec.Containers[0].Args = []string{"-c", "/usr/bin/yes >/dev/null"}
	return d
}

func newHamsterDeploymentWithResources(f *framework.Framework, cpuQuantity, memoryQuantity resource.Quantity) *appsv1.Deployment {
	d := newHamsterDeployment(f)
	d.Spec.Template.Spec.Containers[0].Resources.Requests = v1.ResourceList{
		v1.ResourceCPU:    cpuQuantity,
		v1.ResourceMemory: memoryQuantity,
	}
	return d
}

func newVPA(f *framework.Framework, name string, selector *metav1.LabelSelector) *vpa_types.VerticalPodAutoscaler {
	updateMode := vpa_types.UpdateModeAuto
	vpa := vpa_types.VerticalPodAutoscaler{
		ObjectMeta: metav1.ObjectMeta{
			Name:      name,
			Namespace: f.Namespace.Name,
		},
		Spec: vpa_types.VerticalPodAutoscalerSpec{
			Selector: selector,
			UpdatePolicy: &vpa_types.PodUpdatePolicy{
				UpdateMode: &updateMode,
			},
			ResourcePolicy: &vpa_types.PodResourcePolicy{
				ContainerPolicies: []vpa_types.ContainerResourcePolicy{},
			},
		},
	}
	return &vpa
}

func installVPA(f *framework.Framework, vpa *vpa_types.VerticalPodAutoscaler) {
	ns := f.Namespace.Name
	config, err := framework.LoadConfig()
	gomega.Expect(err).NotTo(gomega.HaveOccurred())
	vpaClientSet := vpa_clientset.NewForConfigOrDie(config)
	vpaClient := vpaClientSet.PocV1alpha1()
	_, err = vpaClient.VerticalPodAutoscalers(ns).Create(vpa)
	gomega.Expect(err).NotTo(gomega.HaveOccurred())
}

func parseQuantityOrDie(text string) resource.Quantity {
	quantity, err := resource.ParseQuantity(text)
	gomega.Expect(err).NotTo(gomega.HaveOccurred())
	return quantity
}
<|endoftext|>


<commit_before>package amesh

type Area struct {
	Id     int
	Name   string
	Width  int
	Height int
	Left   int
	Top    int
}

const (
	wholeWidth  = 3080
	wholeHeight = 1920
	zoomWidth   = 770
	zoomHeight  = 480
)

var areas = map[int]Area{
	0:  Area{0, "全体", wholeWidth, wholeHeight, 0, 0},
	1:  Area{1, "台東", zoomWidth, zoomHeight, 1708, 555},
	2:  Area{2, "江東", zoomWidth, zoomHeight, 1739, 710},
	3:  Area{3, "板橋", zoomWidth, zoomHeight, 1500, 570},
	4:  Area{4, "新宿", zoomWidth, zoomHeight, 1516, 679},
	5:  Area{5, "世田谷", zoomWidth, zoomHeight, 1516, 819},
	6:  Area{6, "東村山", zoomWidth, zoomHeight, 1197, 570},
	7:  Area{7, "府中", zoomWidth, zoomHeight, 1197, 679},
	8:  Area{8, "町田", zoomWidth, zoomHeight, 1117, 850},
	9:  Area{9, "青梅", zoomWidth, zoomHeight, 910, 523},
	10: Area{10, "あきるの", zoomWidth, zoomHeight, 878, 601},
	11: Area{11, "八王子", zoomWidth, zoomHeight, 958, 741},
	12: Area{12, "檜原", zoomWidth, zoomHeight, 686, 617},
	13: Area{13, "奥多摩", zoomWidth, zoomHeight, 638, 461},
}

func GetArea(id int) (Area, bool) {
	a, ok := areas[id]
	return a, ok
}

func GetAreaOrWhole(id int) Area {
	a, ok := GetArea(id)
	if ok {
		return a
	} else {
		a, _ := GetArea(0)
		return a
	}
}
<commit_msg>make areas public<commit_after>package amesh

type Area struct {
	Id     int
	Name   string
	Width  int
	Height int
	Left   int
	Top    int
}

const (
	wholeWidth  = 3080
	wholeHeight = 1920
	zoomWidth   = 770
	zoomHeight  = 480
)

var Areas = map[int]Area{
	0:  Area{0, "全体", wholeWidth, wholeHeight, 0, 0},
	1:  Area{1, "台東", zoomWidth, zoomHeight, 1708, 555},
	2:  Area{2, "江東", zoomWidth, zoomHeight, 1739, 710},
	3:  Area{3, "板橋", zoomWidth, zoomHeight, 1500, 570},
	4:  Area{4, "新宿", zoomWidth, zoomHeight, 1516, 679},
	5:  Area{5, "世田谷", zoomWidth, zoomHeight, 1516, 819},
	6:  Area{6, "東村山", zoomWidth, zoomHeight, 1197, 570},
	7:  Area{7, "府中", zoomWidth, zoomHeight, 1197, 679},
	8:  Area{8, "町田", zoomWidth, zoomHeight, 1117, 850},
	9:  Area{9, "青梅", zoomWidth, zoomHeight, 910, 523},
	10: Area{10, "あきるの", zoomWidth, zoomHeight, 878, 601},
	11: Area{11, "八王子", zoomWidth, zoomHeight, 958, 741},
	12: Area{12, "檜原", zoomWidth, zoomHeight, 686, 617},
	13: Area{13, "奥多摩", zoomWidth, zoomHeight, 638, 461},
}

func GetArea(id int) (Area, bool) {
	a, ok := Areas[id]
	return a, ok
}

func GetAreaOrWhole(id int) Area {
	a, ok := GetArea(id)
	if ok {
		return a
	} else {
		a, _ := GetArea(0)
		return a
	}
}
<|endoftext|>