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

// This file contains the code dealing with package directory trees.

package main

import (
	"bytes"
	"go/doc"
	"go/parser"
	"io/ioutil"
	"os"
	pathutil "path"
	"strings"
	"unicode"
)

type Directory struct {
	Depth int
	Path  string // includes Name
	Name  string
	Text  string       // package documentation, if any
	Dirs  []*Directory // subdirectories
}

func isGoFile(f *os.FileInfo) bool {
	return f.IsRegular() &&
		!strings.HasPrefix(f.Name, ".") && // ignore .files
		pathutil.Ext(f.Name) == ".go"
}

func isPkgFile(f *os.FileInfo) bool {
	return isGoFile(f) &&
		!strings.HasSuffix(f.Name, "_test.go") // ignore test files
}

func isPkgDir(f *os.FileInfo) bool {
	return f.IsDirectory() && len(f.Name) > 0 && f.Name[0] != '_'
}

func firstSentence(s string) string {
	i := -1 // index+1 of first terminator (punctuation ending a sentence)
	j := -1 // index+1 of first terminator followed by white space
	prev := 'A'
	for k, ch := range s {
		k1 := k + 1
		if ch == '.' || ch == '!' || ch == '?' {
			if i < 0 {
				i = k1 // first terminator
			}
			if k1 < len(s) && s[k1] <= ' ' {
				if j < 0 {
					j = k1 // first terminator followed by white space
				}
				if !unicode.IsUpper(prev) {
					j = k1
					break
				}
			}
		}
		prev = ch
	}

	if j < 0 {
		// use the next best terminator
		j = i
		if j < 0 {
			// no terminator at all, use the entire string
			j = len(s)
		}
	}

	return s[0:j]
}

type treeBuilder struct {
	pathFilter func(string) bool
	maxDepth   int
}

func (b *treeBuilder) newDirTree(path, name string, depth int) *Directory {
	if b.pathFilter != nil && !b.pathFilter(path) {
		return nil
	}

	if depth >= b.maxDepth {
		// return a dummy directory so that the parent directory
		// doesn't get discarded just because we reached the max
		// directory depth
		return &Directory{depth, path, name, "", nil}
	}

	list, _ := ioutil.ReadDir(path) // ignore errors

	// determine number of subdirectories and package files
	ndirs := 0
	nfiles := 0
	var synopses [4]string // prioritized package documentation (0 == highest priority)
	for _, d := range list {
		switch {
		case isPkgDir(d):
			ndirs++
		case isPkgFile(d):
			nfiles++
			if synopses[0] == "" {
				// no "optimal" package synopsis yet; continue to collect synopses
				file, err := parser.ParseFile(pathutil.Join(path, d.Name), nil,
					parser.ParseComments|parser.PackageClauseOnly)
				if err == nil && file.Doc != nil {
					// prioritize documentation
					i := -1
					switch file.Name.Name {
					case name:
						i = 0 // normal case: directory name matches package name
					case fakePkgName:
						i = 1 // synopses for commands
					case "main":
						i = 2 // directory contains a main package
					default:
						i = 3 // none of the above
					}
					if 0 <= i && i < len(synopses) && synopses[i] == "" {
						synopses[i] = firstSentence(doc.CommentText(file.Doc))
					}
				}
			}
		}
	}

	// create subdirectory tree
	var dirs []*Directory
	if ndirs > 0 {
		dirs = make([]*Directory, ndirs)
		i := 0
		for _, d := range list {
			if isPkgDir(d) {
				dd := b.newDirTree(pathutil.Join(path, d.Name), d.Name, depth+1)
				if dd != nil {
					dirs[i] = dd
					i++
				}
			}
		}
		dirs = dirs[0:i]
	}

	// if there are no package files and no subdirectories
	// (with package files), ignore the directory
	if nfiles == 0 && len(dirs) == 0 {
		return nil
	}

	// select the highest-priority synopsis for the directory entry, if any
	synopsis := ""
	for _, synopsis = range synopses {
		if synopsis != "" {
			break
		}
	}

	return &Directory{depth, path, name, synopsis, dirs}
}

// newDirectory creates a new package directory tree with at most maxDepth
// levels, anchored at root. The result tree is pruned such that it only
// contains directories that contain package files or that contain
// subdirectories containing package files (transitively). If a non-nil
// pathFilter is provided, directory paths additionally must be accepted
// by the filter (i.e., pathFilter(path) must be true). If a value >= 0 is
// provided for maxDepth, nodes at larger depths are pruned as well; they
// are assumed to contain package files even if their contents are not known
// (i.e., in this case the tree may contain directories w/o any package files).
//
func newDirectory(root string, pathFilter func(string) bool, maxDepth int) *Directory {
	d, err := os.Lstat(root)
	if err != nil || !isPkgDir(d) {
		return nil
	}
	if maxDepth < 0 {
		maxDepth = 1e6 // "infinity"
	}
	b := treeBuilder{pathFilter, maxDepth}
	return b.newDirTree(root, d.Name, 0)
}

func (dir *Directory) writeLeafs(buf *bytes.Buffer) {
	if dir != nil {
		if len(dir.Dirs) == 0 {
			buf.WriteString(dir.Path)
			buf.WriteByte('\n')
			return
		}

		for _, d := range dir.Dirs {
			d.writeLeafs(buf)
		}
	}
}

func (dir *Directory) walk(c chan<- *Directory, skipRoot bool) {
	if dir != nil {
		if !skipRoot {
			c <- dir
		}
		for _, d := range dir.Dirs {
			d.walk(c, false)
		}
	}
}

func (dir *Directory) iter(skipRoot bool) <-chan *Directory {
	c := make(chan *Directory)
	go func() {
		dir.walk(c, skipRoot)
		close(c)
	}()
	return c
}

func (dir *Directory) lookupLocal(name string) *Directory {
	for _, d := range dir.Dirs {
		if d.Name == name {
			return d
		}
	}
	return nil
}

// lookup looks for the *Directory for a given path, relative to dir.
func (dir *Directory) lookup(path string) *Directory {
	d := strings.Split(dir.Path, "/", -1)
	p := strings.Split(path, "/", -1)
	i := 0
	for i < len(d) {
		if i >= len(p) || d[i] != p[i] {
			return nil
		}
		i++
	}
	for dir != nil && i < len(p) {
		dir = dir.lookupLocal(p[i])
		i++
	}
	return dir
}

// DirEntry describes a directory entry. The Depth and Height values
// are useful for presenting an entry in an indented fashion.
//
type DirEntry struct {
	Depth    int    // >= 0
	Height   int    // = DirList.MaxHeight - Depth, > 0
	Path     string // includes Name, relative to DirList root
	Name     string
	Synopsis string
}

type DirList struct {
	MaxHeight int // directory tree height, > 0
	List      []DirEntry
}

// listing creates a (linear) directory listing from a directory tree.
// If skipRoot is set, the root directory itself is excluded from the list.
//
func (root *Directory) listing(skipRoot bool) *DirList {
	if root == nil {
		return nil
	}

	// determine number of entries n and maximum height
	n := 0
	minDepth := 1 << 30 // infinity
	maxDepth := 0
	for d := range root.iter(skipRoot) {
		n++
		if minDepth > d.Depth {
			minDepth = d.Depth
		}
		if maxDepth < d.Depth {
			maxDepth = d.Depth
		}
	}
	maxHeight := maxDepth - minDepth + 1

	if n == 0 {
		return nil
	}

	// create list
	list := make([]DirEntry, n)
	i := 0
	for d := range root.iter(skipRoot) {
		p := &list[i]
		p.Depth = d.Depth - minDepth
		p.Height = maxHeight - p.Depth
		// the path is relative to root.Path - remove the root.Path
		// prefix (the prefix should always be present but avoid
		// crashes and check)
		path := d.Path
		if strings.HasPrefix(d.Path, root.Path) {
			path = d.Path[len(root.Path):]
		}
		// remove trailing '/' if any - path must be relative
		if len(path) > 0 && path[0] == '/' {
			path = path[1:]
		}
		p.Path = path
		p.Name = d.Name
		p.Synopsis = d.Text
		i++
	}

	return &DirList{maxHeight, list}
}
<commit_msg>godoc: only show directories containing true package files<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains the code dealing with package directory trees.

package main

import (
	"bytes"
	"go/doc"
	"go/parser"
	"io/ioutil"
	"os"
	pathutil "path"
	"strings"
	"unicode"
)

type Directory struct {
	Depth int
	Path  string // includes Name
	Name  string
	Text  string       // package documentation, if any
	Dirs  []*Directory // subdirectories
}

func isGoFile(f *os.FileInfo) bool {
	return f.IsRegular() &&
		!strings.HasPrefix(f.Name, ".") && // ignore .files
		pathutil.Ext(f.Name) == ".go"
}

func isPkgFile(f *os.FileInfo) bool {
	return isGoFile(f) &&
		!strings.HasSuffix(f.Name, "_test.go") // ignore test files
}

func isPkgDir(f *os.FileInfo) bool {
	return f.IsDirectory() && len(f.Name) > 0 && f.Name[0] != '_'
}

func firstSentence(s string) string {
	i := -1 // index+1 of first terminator (punctuation ending a sentence)
	j := -1 // index+1 of first terminator followed by white space
	prev := 'A'
	for k, ch := range s {
		k1 := k + 1
		if ch == '.' || ch == '!' || ch == '?' {
			if i < 0 {
				i = k1 // first terminator
			}
			if k1 < len(s) && s[k1] <= ' ' {
				if j < 0 {
					j = k1 // first terminator followed by white space
				}
				if !unicode.IsUpper(prev) {
					j = k1
					break
				}
			}
		}
		prev = ch
	}

	if j < 0 {
		// use the next best terminator
		j = i
		if j < 0 {
			// no terminator at all, use the entire string
			j = len(s)
		}
	}

	return s[0:j]
}

type treeBuilder struct {
	pathFilter func(string) bool
	maxDepth   int
}

func (b *treeBuilder) newDirTree(path, name string, depth int) *Directory {
	if b.pathFilter != nil && !b.pathFilter(path) {
		return nil
	}

	if depth >= b.maxDepth {
		// return a dummy directory so that the parent directory
		// doesn't get discarded just because we reached the max
		// directory depth
		return &Directory{depth, path, name, "", nil}
	}

	list, _ := ioutil.ReadDir(path) // ignore errors

	// determine number of subdirectories and if there are package files
	ndirs := 0
	hasPkgFiles := false
	var synopses [4]string // prioritized package documentation (0 == highest priority)
	for _, d := range list {
		switch {
		case isPkgDir(d):
			ndirs++
		case isPkgFile(d):
			// looks like a package file, but may just be a file ending in ".go";
			// don't just count it yet (otherwise we may end up with hasPkgFiles even
			// though the directory doesn't contain any real package files - was bug)
			if synopses[0] == "" {
				// no "optimal" package synopsis yet; continue to collect synopses
				file, err := parser.ParseFile(pathutil.Join(path, d.Name), nil,
					parser.ParseComments|parser.PackageClauseOnly)
				if err == nil {
					hasPkgFiles = true
					if file.Doc != nil {
						// prioritize documentation
						i := -1
						switch file.Name.Name {
						case name:
							i = 0 // normal case: directory name matches package name
						case fakePkgName:
							i = 1 // synopses for commands
						case "main":
							i = 2 // directory contains a main package
						default:
							i = 3 // none of the above
						}
						if 0 <= i && i < len(synopses) && synopses[i] == "" {
							synopses[i] = firstSentence(doc.CommentText(file.Doc))
						}
					}
				}
			}
		}
	}

	// create subdirectory tree
	var dirs []*Directory
	if ndirs > 0 {
		dirs = make([]*Directory, ndirs)
		i := 0
		for _, d := range list {
			if isPkgDir(d) {
				dd := b.newDirTree(pathutil.Join(path, d.Name), d.Name, depth+1)
				if dd != nil {
					dirs[i] = dd
					i++
				}
			}
		}
		dirs = dirs[0:i]
	}

	// if there are no package files and no subdirectories
	// containing package files, ignore the directory
	if !hasPkgFiles && len(dirs) == 0 {
		return nil
	}

	// select the highest-priority synopsis for the directory entry, if any
	synopsis := ""
	for _, synopsis = range synopses {
		if synopsis != "" {
			break
		}
	}

	return &Directory{depth, path, name, synopsis, dirs}
}

// newDirectory creates a new package directory tree with at most maxDepth
// levels, anchored at root. The result tree is pruned such that it only
// contains directories that contain package files or that contain
// subdirectories containing package files (transitively). If a non-nil
// pathFilter is provided, directory paths additionally must be accepted
// by the filter (i.e., pathFilter(path) must be true). If a value >= 0 is
// provided for maxDepth, nodes at larger depths are pruned as well; they
// are assumed to contain package files even if their contents are not known
// (i.e., in this case the tree may contain directories w/o any package files).
//
func newDirectory(root string, pathFilter func(string) bool, maxDepth int) *Directory {
	d, err := os.Lstat(root)
	if err != nil || !isPkgDir(d) {
		return nil
	}
	if maxDepth < 0 {
		maxDepth = 1e6 // "infinity"
	}
	b := treeBuilder{pathFilter, maxDepth}
	return b.newDirTree(root, d.Name, 0)
}

func (dir *Directory) writeLeafs(buf *bytes.Buffer) {
	if dir != nil {
		if len(dir.Dirs) == 0 {
			buf.WriteString(dir.Path)
			buf.WriteByte('\n')
			return
		}

		for _, d := range dir.Dirs {
			d.writeLeafs(buf)
		}
	}
}

func (dir *Directory) walk(c chan<- *Directory, skipRoot bool) {
	if dir != nil {
		if !skipRoot {
			c <- dir
		}
		for _, d := range dir.Dirs {
			d.walk(c, false)
		}
	}
}

func (dir *Directory) iter(skipRoot bool) <-chan *Directory {
	c := make(chan *Directory)
	go func() {
		dir.walk(c, skipRoot)
		close(c)
	}()
	return c
}

func (dir *Directory) lookupLocal(name string) *Directory {
	for _, d := range dir.Dirs {
		if d.Name == name {
			return d
		}
	}
	return nil
}

// lookup looks for the *Directory for a given path, relative to dir.
func (dir *Directory) lookup(path string) *Directory {
	d := strings.Split(dir.Path, "/", -1)
	p := strings.Split(path, "/", -1)
	i := 0
	for i < len(d) {
		if i >= len(p) || d[i] != p[i] {
			return nil
		}
		i++
	}
	for dir != nil && i < len(p) {
		dir = dir.lookupLocal(p[i])
		i++
	}
	return dir
}

// DirEntry describes a directory entry. The Depth and Height values
// are useful for presenting an entry in an indented fashion.
//
type DirEntry struct {
	Depth    int    // >= 0
	Height   int    // = DirList.MaxHeight - Depth, > 0
	Path     string // includes Name, relative to DirList root
	Name     string
	Synopsis string
}

type DirList struct {
	MaxHeight int // directory tree height, > 0
	List      []DirEntry
}

// listing creates a (linear) directory listing from a directory tree.
// If skipRoot is set, the root directory itself is excluded from the list.
//
func (root *Directory) listing(skipRoot bool) *DirList {
	if root == nil {
		return nil
	}

	// determine number of entries n and maximum height
	n := 0
	minDepth := 1 << 30 // infinity
	maxDepth := 0
	for d := range root.iter(skipRoot) {
		n++
		if minDepth > d.Depth {
			minDepth = d.Depth
		}
		if maxDepth < d.Depth {
			maxDepth = d.Depth
		}
	}
	maxHeight := maxDepth - minDepth + 1

	if n == 0 {
		return nil
	}

	// create list
	list := make([]DirEntry, n)
	i := 0
	for d := range root.iter(skipRoot) {
		p := &list[i]
		p.Depth = d.Depth - minDepth
		p.Height = maxHeight - p.Depth
		// the path is relative to root.Path - remove the root.Path
		// prefix (the prefix should always be present but avoid
		// crashes and check)
		path := d.Path
		if strings.HasPrefix(d.Path, root.Path) {
			path = d.Path[len(root.Path):]
		}
		// remove trailing '/' if any - path must be relative
		if len(path) > 0 && path[0] == '/' {
			path = path[1:]
		}
		p.Path = path
		p.Name = d.Name
		p.Synopsis = d.Text
		i++
	}

	return &DirList{maxHeight, list}
}
<|endoftext|>


<commit_before>package fasta

import (
	"github.com/craiglowe/gonomics/dna"
	"testing"
)

var seqOneA, _ = dna.StringToBases("ACGTacgTCATCATCATTACTACTAC")
var seqOneB, _ = dna.StringToBases("acgtACGTACGT")
var seqOneC, _ = dna.StringToBases("ACGTACGTACGTT")
var readWriteTests = []struct {
	filename string // input
	data     []Fasta
}{
	{"testdata/testOne.fa", []Fasta{{"apple", seqOneA}, {"banana", seqOneB}, {"carrot", seqOneC}}},
}

func TestRead(t *testing.T) {
	for _, test := range readWriteTests {
		actual, err := Read(test.filename)
		if err != nil {
			t.Errorf("Reading %s gave an error..", test.filename)
		}
		if !AllAreEqual(test.data, actual) {
			t.Errorf("The %s file was not read correctly.", test.filename)
		}
	}
}

func TestWriteAndRead(t *testing.T) {
	for _, test := range readWriteTests {
		Write(test.filename+".tmp", test.data)
		actual, err := Read(test.filename + ".tmp")
		if err != nil {
			t.Errorf("Reading %s gave an error.", test.filename)
		}
		if !AllAreEqual(test.data, actual) {
			t.Errorf("The %s file was not read correctly.", test.filename)
		}
	}
}
<commit_msg>delete temp file created in testing<commit_after>package fasta

import (
	"github.com/craiglowe/gonomics/dna"
	"testing"
	"os"
)

var seqOneA, _ = dna.StringToBases("ACGTacgTCATCATCATTACTACTAC")
var seqOneB, _ = dna.StringToBases("acgtACGTACGT")
var seqOneC, _ = dna.StringToBases("ACGTACGTACGTT")
var readWriteTests = []struct {
	filename string // input
	data     []Fasta
}{
	{"testdata/testOne.fa", []Fasta{{"apple", seqOneA}, {"banana", seqOneB}, {"carrot", seqOneC}}},
}

func TestRead(t *testing.T) {
	for _, test := range readWriteTests {
		actual, err := Read(test.filename)
		if err != nil {
			t.Errorf("Reading %s gave an error..", test.filename)
		}
		if !AllAreEqual(test.data, actual) {
			t.Errorf("The %s file was not read correctly.", test.filename)
		}
	}
}

func TestWriteAndRead(t *testing.T) {
	for _, test := range readWriteTests {
		tempFile := test.filename + ".tmp"
		Write(tempFile, test.data)
		actual, err := Read(tempFile)
		if err != nil {
			t.Errorf("Reading %s gave an error.", test.filename)
		}
		if !AllAreEqual(test.data, actual) {
			t.Errorf("The %s file was not read correctly.", test.filename)
		}
		err = os.Remove(tempFile)
		if err != nil {
                        t.Errorf("Deleting temp file %s gave an error.", tempFile)
                }
	}
}
<|endoftext|>


<commit_before>package benchdb

import (
	"bytes"
	"crypto/rand"
	"database/sql"
	"encoding/hex"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strings"
	"time"

	_ "github.com/lib/pq"

	"golang.org/x/tools/benchmark/parse"
)

// A BenchDB manges the execution of benchmark tests using go test and
// writing a parse.Set to a database.
//
// Implementations of BenchDB for different databases are allowed by way
// of the WriteSet method.
type BenchDB interface {
	// Run executes go test bench for benchmarks matching regex in the current
	// directory. By default it does not run unit tests by way of setting test.run
	// to XXX in the call to go test. It also parses the benchSet and calls WriteSet
	// to write the benchmark data to a database. It returns any error encountered.
	Run(regex string) error

	// WriteSet is responsible for opening a postgres database connection and writing
	// a parsed benchSet to a db table. It closes the connection, returns the number of
	// benchmark tests written, and any error encountered.
	WriteSet(parse.Set) (int, error)
}

// BenchPSQL represents a BenchDB that writes benchmarks to a postgres
// database.
type BenchPSQL struct {
	Driver    string // database driver name
	ConnStr   string // sql connection string
	TableName string // database table name

	dbConn *sql.DB
}

// Run runs go test benchmarks matching regex in the current directory and writes
// benchmark data to a PSQL database by calling WriteSet. It returns any error
// encountered.
func (benchdb *BenchPSQL) Run(regex string) error {
	// Exec a subprocess for go test bench and write
	// to both stdout and a byte buffer.
	cmd := exec.Command("go", "test", "-bench", regex,
		"-test.run", "XXX", "-benchmem")
	var out bytes.Buffer
	var stderr bytes.Buffer
	cmd.Stdout = io.MultiWriter(os.Stdout, &out)
	cmd.Stderr = io.Writer(&stderr)
	err := cmd.Run()
	if err != nil {
		fmt.Printf("%s", out.String())
		fmt.Printf("%s", stderr.String())
		return fmt.Errorf("command failed: %v", err)
	}

	benchSet, err := parse.ParseSet(&out)
	if err != nil {
		return fmt.Errorf("failed to parse benchmark data: %v", err)
	}

	// Writes parse set to sql database.
	_, err = benchdb.WriteSet(benchSet)
	if err != nil {
		return fmt.Errorf("failed to write benchSet to db: %v", err)
	}
	return nil
}

const nsha = 7

func latestGitSha() (string, error) {
	out, err := exec.Command("git", "rev-parse", "HEAD").Output()
	if err != nil {
		return "", fmt.Errorf("failed to get latest git sha: %v\n", err)
	}
	return string(out[:nsha]), nil
}

func uuid() (string, error) {
	b := make([]byte, 16)
	if _, err := io.ReadFull(rand.Reader, b); err != nil {
		return "", err
	}
	return hex.EncodeToString(b), nil
}

// WriteSet is responsible for opening a postgres database connection and writing
// a parsed benchSet to a db table. It closes the connection, returns the number of
// benchmark tests written, and any error encountered.
//
// A new sql transaction is created and committed per Benchmark in benchSet. This way if a
// db failure occurs all data from the benchSet is not lost.
func (benchdb *BenchPSQL) WriteSet(benchSet parse.Set) (int, error) {
	sqlDB, err := sql.Open(benchdb.Driver, benchdb.ConnStr)
	if err != nil {
		return 0, fmt.Errorf("could not connect to db: %v", err)
	}
	defer sqlDB.Close()
	benchdb.dbConn = sqlDB

	batchId, err := uuid()
	if err != nil {
		return 0, fmt.Errorf("could not generate batch id: %v\n", err)
	}

	cnt := 0
	for _, b := range benchSet {
		n := len(b)
		for i := 0; i < n; i++ {
			val := b[i]
			err := saveBenchmark(benchdb.dbConn, benchdb.TableName, batchId, *val)
			if err != nil {
				return 0, fmt.Errorf("failed to save benchmark: %v", err)
			}
			cnt++
		}
	}
	return cnt, nil
}

func saveBenchmark(dbConn *sql.DB, table, batchId string, b parse.Benchmark) error {
	// Create a transaction per Benchmark.
	tx, err := dbConn.Begin()
	if err != nil {
		return err
	}
	defer tx.Rollback()

	sha, err := latestGitSha()
	if err != nil {
		return err
	}

	q := fmt.Sprintf(`
        INSERT INTO %s
        (batch_id, latest_sha, datetime, name, n, ns_op, allocated_bytes_op, allocs_op)
        VALUES
        ($1, $2, $3, $4, $5, $6, $7, $8)
        `, table)

	// Strips of leading Benchmark string in Benchmark.Name
	name := strings.TrimPrefix(strings.TrimSpace(b.Name), "Benchmark")
	ts := time.Now().UTC()

	_, err = tx.Exec(q,
		batchId, sha, ts, name, b.N, b.NsPerOp, b.AllocedBytesPerOp, b.AllocsPerOp)
	if err != nil {
		return err
	}
	return tx.Commit()
}
<commit_msg>using attaching os.Stderr to command<commit_after>package benchdb

import (
	"bytes"
	"crypto/rand"
	"database/sql"
	"encoding/hex"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strings"
	"time"

	_ "github.com/lib/pq"

	"golang.org/x/tools/benchmark/parse"
)

// A BenchDB manges the execution of benchmark tests using go test and
// writing a parse.Set to a database.
//
// Implementations of BenchDB for different databases are allowed by way
// of the WriteSet method.
type BenchDB interface {
	// Run executes go test bench for benchmarks matching regex in the current
	// directory. By default it does not run unit tests by way of setting test.run
	// to XXX in the call to go test. It also parses the benchSet and calls WriteSet
	// to write the benchmark data to a database. It returns any error encountered.
	Run(regex string) error

	// WriteSet is responsible for opening a postgres database connection and writing
	// a parsed benchSet to a db table. It closes the connection, returns the number of
	// benchmark tests written, and any error encountered.
	WriteSet(parse.Set) (int, error)
}

// BenchPSQL represents a BenchDB that writes benchmarks to a postgres
// database.
type BenchPSQL struct {
	Driver    string // database driver name
	ConnStr   string // sql connection string
	TableName string // database table name

	dbConn *sql.DB
}

// Run runs go test benchmarks matching regex in the current directory and writes
// benchmark data to a PSQL database by calling WriteSet. It returns any error
// encountered.
func (benchdb *BenchPSQL) Run(regex string) error {
	// Exec a subprocess for go test bench and write
	// to both stdout and a byte buffer.
	cmd := exec.Command("go", "test", "-bench", regex,
		"-test.run", "XXX", "-benchmem")
	var out bytes.Buffer
	cmd.Stdout = io.MultiWriter(os.Stdout, &out)
	cmd.Stderr = io.Writer(os.Stderr)
	err := cmd.Run()
	if err != nil {
		return fmt.Errorf("command failed: %v", err)
	}

	benchSet, err := parse.ParseSet(&out)
	if err != nil {
		return fmt.Errorf("failed to parse benchmark data: %v", err)
	}

	// Writes parse set to sql database.
	_, err = benchdb.WriteSet(benchSet)
	if err != nil {
		return fmt.Errorf("failed to write benchSet to db: %v", err)
	}
	return nil
}

const nsha = 7

func latestGitSha() (string, error) {
	out, err := exec.Command("git", "rev-parse", "HEAD").Output()
	if err != nil {
		return "", fmt.Errorf("failed to get latest git sha: %v\n", err)
	}
	return string(out[:nsha]), nil
}

func uuid() (string, error) {
	b := make([]byte, 16)
	if _, err := io.ReadFull(rand.Reader, b); err != nil {
		return "", err
	}
	return hex.EncodeToString(b), nil
}

// WriteSet is responsible for opening a postgres database connection and writing
// a parsed benchSet to a db table. It closes the connection, returns the number of
// benchmark tests written, and any error encountered.
//
// A new sql transaction is created and committed per Benchmark in benchSet. This way if a
// db failure occurs all data from the benchSet is not lost.
func (benchdb *BenchPSQL) WriteSet(benchSet parse.Set) (int, error) {
	sqlDB, err := sql.Open(benchdb.Driver, benchdb.ConnStr)
	if err != nil {
		return 0, fmt.Errorf("could not connect to db: %v", err)
	}
	defer sqlDB.Close()
	benchdb.dbConn = sqlDB

	batchId, err := uuid()
	if err != nil {
		return 0, fmt.Errorf("could not generate batch id: %v\n", err)
	}

	cnt := 0
	for _, b := range benchSet {
		n := len(b)
		for i := 0; i < n; i++ {
			val := b[i]
			err := saveBenchmark(benchdb.dbConn, benchdb.TableName, batchId, *val)
			if err != nil {
				return 0, fmt.Errorf("failed to save benchmark: %v", err)
			}
			cnt++
		}
	}
	return cnt, nil
}

func saveBenchmark(dbConn *sql.DB, table, batchId string, b parse.Benchmark) error {
	// Create a transaction per Benchmark.
	tx, err := dbConn.Begin()
	if err != nil {
		return err
	}
	defer tx.Rollback()

	sha, err := latestGitSha()
	if err != nil {
		return err
	}

	q := fmt.Sprintf(`
        INSERT INTO %s
        (batch_id, latest_sha, datetime, name, n, ns_op, allocated_bytes_op, allocs_op)
        VALUES
        ($1, $2, $3, $4, $5, $6, $7, $8)
        `, table)

	// Strips of leading Benchmark string in Benchmark.Name
	name := strings.TrimPrefix(strings.TrimSpace(b.Name), "Benchmark")
	ts := time.Now().UTC()

	_, err = tx.Exec(q,
		batchId, sha, ts, name, b.N, b.NsPerOp, b.AllocedBytesPerOp, b.AllocsPerOp)
	if err != nil {
		return err
	}
	return tx.Commit()
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	irc "github.com/fluffle/goirc/client"
	"io"
	"os"
	"strings"
)

func handleStdin(conn *irc.Conn, quit chan<- bool) {
	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		text := scanner.Text()
		if strings.TrimSpace(text) != "" {
			handleInputLine(conn, text)
		}
	}
	if err := scanner.Err(); err != nil {
		if err == io.EOF {
			quit <- false
		} else {
			fmt.Fprintln(os.Stderr, "reading standard input:", err)
		}
	}
}

func handleInputLine(conn *irc.Conn, text string) {
	words := strings.SplitN(text, " ", 2)
	cmd := words[0]
	if !strings.HasPrefix(cmd, "/") {
		return
	}
	cmd = cmd[1:]

	if f, ok := inputCommands[cmd]; ok {
		f(conn, words[1])
	}
}

var inputCommands = map[string]func(*irc.Conn, string){
	"raw": func(conn *irc.Conn, text string) {
		fmt.Println(text)
		conn.Raw(text)
	},
	"msg": func(conn *irc.Conn, text string) {
		words := strings.SplitN(text, " ", 2)
		if len(words) != 2 || words[0] == "" || words[1] == "" {
			fmt.Fprintln(os.Stderr, "usage: /msg target text")
			return
		}
		fmt.Printf("--> %s: %s\n", words[0], words[1])
		conn.Privmsg(words[0], words[1])
	},
	"notice": func(conn *irc.Conn, text string) {
		words := strings.SplitN(text, " ", 2)
		if len(words) != 2 || words[0] == "" || words[1] == "" {
			fmt.Fprintln(os.Stderr, "usage: /notice target text")
			return
		}
		fmt.Printf("--> NOTICE[%s]: %s\n", words[0], words[1])
		conn.Notice(words[0], words[1])
	},
}
<commit_msg>Add /me command<commit_after>package main

import (
	"bufio"
	"fmt"
	irc "github.com/fluffle/goirc/client"
	"io"
	"os"
	"strings"
)

func handleStdin(conn *irc.Conn, quit chan<- bool) {
	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		text := scanner.Text()
		if strings.TrimSpace(text) != "" {
			handleInputLine(conn, text)
		}
	}
	if err := scanner.Err(); err != nil {
		if err == io.EOF {
			quit <- false
		} else {
			fmt.Fprintln(os.Stderr, "reading standard input:", err)
		}
	}
}

func handleInputLine(conn *irc.Conn, text string) {
	words := strings.SplitN(text, " ", 2)
	cmd := words[0]
	if !strings.HasPrefix(cmd, "/") {
		return
	}
	cmd = cmd[1:]

	if f, ok := inputCommands[cmd]; ok {
		f(conn, words[1])
	}
}

var inputCommands = map[string]func(*irc.Conn, string){
	"raw": func(conn *irc.Conn, text string) {
		fmt.Println(text)
		conn.Raw(text)
	},
	"msg": func(conn *irc.Conn, text string) {
		words := strings.SplitN(text, " ", 2)
		if len(words) != 2 || words[0] == "" || words[1] == "" {
			fmt.Fprintln(os.Stderr, "usage: /msg target text")
			return
		}
		fmt.Printf("--> %s: %s\n", words[0], words[1])
		conn.Privmsg(words[0], words[1])
	},
	"notice": func(conn *irc.Conn, text string) {
		words := strings.SplitN(text, " ", 2)
		if len(words) != 2 || words[0] == "" || words[1] == "" {
			fmt.Fprintln(os.Stderr, "usage: /notice target text")
			return
		}
		fmt.Printf("--> NOTICE[%s]: %s\n", words[0], words[1])
		conn.Notice(words[0], words[1])
	},
	"me": func(conn *irc.Conn, text string) {
		words := strings.SplitN(text, " ", 2)
		if len(words) != 2 || words[0] == "" || words[1] == "" {
			fmt.Fprintln(os.Stderr, "usage: /me target text")
			return
		}
		fmt.Printf("--> %s ACTION: %s %s\n", words[0], conn.Me.Nick, words[1])
		conn.Action(words[0], words[1])
	},
}
<|endoftext|>


<commit_before>// steam.go

package steam

/*
#cgo CFLAGS: -I$GOPATH/steamworks_sdk_128/public/steam
#cgo amd64 !windows LDFLAGS: -L$GOPATH/steamworks_sdk_128/redistributable_bin/linux64 -lsteam_api
#cgo windows CFLAGS: -DIS_WINDOWS=1
#cgo !windows CFLAGS: -DIS_WINDOWS=0 -DSTEAM_API_NODLL
#include "wrapper.h"
*/
import "C"

import (
	"log"
)

// Shutdown calls STEAMAPI_Shutdown()
func Shutdown() {
	_, err := C.SteamShutdown()
	if err != nil {
		log.Fatal(err)
	}
}

// IsSteamRunning returns true if steam client is running.
func IsSteamRunning() bool {
	n, err := C.SteamIsSteamRunning()
	if err != nil {
		log.Fatal(err)
	}

	return n != 0
}

// Init calls STEAMAPI_InitSafe() and CSteamAPIContext.Init()
func Init() bool {
	n, err := C.SteamInit()
	if err != nil {
		log.Fatal(err)
	}

	return n != 0
}

//export GoLogFatal
/*
func GoLogFatal(s C.CString) {
	log.Fatal(C.GoString(s))
}
*/
<commit_msg>Added build constraints and additional cgo directives.<commit_after>// steam.go
// +build linux,amd64 windows,amd64

package steam

/*
#cgo linux amd64 LDFLAGS: -L$GOPATH/steamworks_sdk_128/redistributable_bin/linux64 -lsteam_api
#cgo linux 386 LDFLAGS: -L$GOPATH/steamworks_sdk_128/redistributable_bin/linux32
#cgo darwin LDFLAGS: -L$GOPATH/steamworks_sdk_128/redistributable_bin/osx32
#cgo windows amd64 LDFLAGS: -L$GOPATH/steamworks_sdk_128/redistributable_bin/win64
#cgo windows 386 LDFLAGS: -L$GOPATH/steamworks_sdk_128/redistributable_bin
#cgo windows CFLAGS: -DIS_WINDOWS=1
#cgo !windows CFLAGS: -DIS_WINDOWS=0 -DSTEAM_API_NODLL
#include "wrapper.h"
*/
import "C"

import (
	"log"
)

// Shutdown calls STEAMAPI_Shutdown()
func Shutdown() {
	_, err := C.SteamShutdown()
	if err != nil {
		log.Fatal(err)
	}
}

// IsSteamRunning returns true if steam client is running.
func IsSteamRunning() bool {
	n, err := C.SteamIsSteamRunning()
	if err != nil {
		log.Fatal(err)
	}

	return n != 0
}

// Init calls STEAMAPI_InitSafe() and CSteamAPIContext.Init()
func Init() bool {
	n, err := C.SteamInit()
	if err != nil {
		log.Fatal(err)
	}

	return n != 0
}

//export GoLogFatal
/*
func GoLogFatal(s C.CString) {
	log.Fatal(C.GoString(s))
}
*/
<|endoftext|>


<commit_before>package buf

import "github.com/bufbuild/buf/internal/pkg/cli/clicobra"

const version = "0.8.0-dev"

// Main is the main.
func Main(use string, options ...RootCommandOption) {
	clicobra.Main(newRootCommand(use, options...), version)
}

// NewRootCommand creates a new root Command.
func NewRootCommand(use string, options ...RootCommandOption) *clicobra.Command {
	return newRootCommand(use, options...)
}

// RootCommandOption is an option for a root Command.
type RootCommandOption func(*clicobra.Command, *Flags)
<commit_msg>Update to v0.8.0<commit_after>package buf

import "github.com/bufbuild/buf/internal/pkg/cli/clicobra"

const version = "0.8.0"

// Main is the main.
func Main(use string, options ...RootCommandOption) {
	clicobra.Main(newRootCommand(use, options...), version)
}

// NewRootCommand creates a new root Command.
func NewRootCommand(use string, options ...RootCommandOption) *clicobra.Command {
	return newRootCommand(use, options...)
}

// RootCommandOption is an option for a root Command.
type RootCommandOption func(*clicobra.Command, *Flags)
<|endoftext|>


<commit_before>/*
 * Copyright 2016 Frank Wessels <fwessels@xs4all.nl>
 *
 * 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 cas

import (
	"os"
	"io"
	"io/ioutil"
	"github.com/stretchr/testify/assert"
	"testing"
	"strings"
	"bytes"
	"github.com/s3git/s3git-go/internal/config"
	"github.com/s3git/s3git-go/internal/kv"
)

func TestWriteSingleChunk(t *testing.T) {

	path := setupRepo(t)
	defer teardownRepo(path)

	input := "hello s3git\n"

	rootKeyStr := writeTo(t, strings.NewReader(input))
	output := readBack(t, rootKeyStr)

	assert.Equal(t, input, output, "Input and output are different")
}

func writeTo(t *testing.T, r io.Reader) string {

	cw := MakeWriter(BLOB)
	defer cw.Close()

	_, err := io.Copy(cw, r)
	assert.Nil(t, err)

	rootKeyStr, _, _, err := cw.Flush()
	assert.Nil(t, err)

	return rootKeyStr
}

func readBack(t *testing.T, hash string) string {

	cr := MakeReader(hash)
	assert.NotEmpty(t, cr)

	buf := bytes.NewBuffer(nil)

	size := 0
	array := make([]byte, config.Config.ChunkSize)
	for {
		read, err := cr.Read(array)
		size += read
		if read > 0 {
			_, err := buf.Write(array[:read])
			assert.Nil(t, err)
		}
		if err == io.EOF {
			break
		}
	}

	return string(buf.Bytes())
}

func setupRepo(t *testing.T) (string) {
	path, _ := ioutil.TempDir("", "s3git-cas-")

	config.SaveConfig(path)

	success, err := config.LoadConfig(path)
	assert.Nil(t, err)
	assert.Equal(t, true, success, "Failed to init repo")
	kv.OpenDatabase()

	return path
}

func teardownRepo(path string) {
	defer os.RemoveAll(path)
}
<commit_msg>More test cases for cas<commit_after>/*
 * Copyright 2016 Frank Wessels <fwessels@xs4all.nl>
 *
 * 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 cas

import (
	"os"
	"io"
	"io/ioutil"
	"github.com/stretchr/testify/assert"
	"testing"
	"strings"
	"bytes"
	"github.com/s3git/s3git-go/internal/config"
	"github.com/s3git/s3git-go/internal/kv"
	"math/rand"
	"time"
)

func TestWriteSingleChunk(t *testing.T) {

	path := setupRepo(t)
	defer teardownRepo(path)

	input := "hello s3git\n"

	rootKeyStr := writeTo(t, strings.NewReader(input))
	output := readBack(t, rootKeyStr)

	assert.Equal(t, input, output, "Input and output are different")
}

func TestWriteTwoChunks(t *testing.T) {

	path := setupRepo(t)
	defer teardownRepo(path)

	input := strings.Repeat("0123456789abcdef", 7.5*1024*1024/16)

	rootKeyStr := writeTo(t, strings.NewReader(input))
	output := readBack(t, rootKeyStr)

	assert.Equal(t, input, output, "Input and output are different")
}

func TestWriteManyChunks(t *testing.T) {

	path := setupRepo(t)
	defer teardownRepo(path)

	input := strings.Repeat("0123456789abcdef", 22.5*1024*1024/16)

	rootKeyStr := writeTo(t, strings.NewReader(input))
	output := readBack(t, rootKeyStr)

	assert.Equal(t, input, output, "Input and output are different")
}

func TestWriteDifferentChunkSize(t *testing.T) {

	path := setupRepo(t)
	defer teardownRepo(path)

	config.Config.ChunkSize = 1*1024*1024

	input := strings.Repeat("0123456789abcdef", int((0.5+float32(random(5, 10)))*1024*1024/16))

	rootKeyStr := writeTo(t, strings.NewReader(input))
	output := readBack(t, rootKeyStr)

	assert.Equal(t, input, output, "Input and output are different")
}

func writeTo(t *testing.T, r io.Reader) string {

	cw := MakeWriter(BLOB)
	defer cw.Close()

	_, err := io.Copy(cw, r)
	assert.Nil(t, err)

	rootKeyStr, _, _, err := cw.Flush()
	assert.Nil(t, err)

	return rootKeyStr
}

func readBack(t *testing.T, hash string) string {

	cr := MakeReader(hash)
	assert.NotEmpty(t, cr)

	buf := bytes.NewBuffer(nil)

	size := 0
	array := make([]byte, config.Config.ChunkSize)
	for {
		read, err := cr.Read(array)
		size += read
		if read > 0 {
			_, err := buf.Write(array[:read])
			assert.Nil(t, err)
		}
		if err == io.EOF {
			break
		}
	}

	return string(buf.Bytes())
}

func setupRepo(t *testing.T) (string) {
	path, _ := ioutil.TempDir("", "s3git-cas-")

	config.SaveConfig(path)

	success, err := config.LoadConfig(path)
	assert.Nil(t, err)
	assert.Equal(t, true, success, "Failed to init repo")
	kv.OpenDatabase()

	return path
}

func teardownRepo(path string) {
	defer os.RemoveAll(path)
}

func random(min, max int) int {
	rand.Seed(time.Now().Unix())
	return rand.Intn(max - min) + min
}
<|endoftext|>


<commit_before>package convert

import (
	"bytes"
	"fmt"
	"io"
	"net/url"
	"sort"
	"strings"

	"golang.org/x/net/html"
)

var heading = map[string]bool{
	"h1": true,
	"h2": true,
	"h3": true,
	"h4": true,
	"h5": true,
	"h6": true,
}

func recurse(n *html.Node, f func(c *html.Node) error) error {
	c := n.FirstChild
	for c != nil {
		next := c.NextSibling
		if err := recurse(c, f); err != nil {
			return err
		}
		if err := f(c); err != nil {
			return err
		}
		c = next
	}
	return nil
}

type ref struct {
	pos  []int
	dest string
}

type byStart []ref

func (p byStart) Len() int {
	return len(p)
}
func (p byStart) Less(i, j int) bool {
	return p[i].pos[0] < p[j].pos[0]
}
func (p byStart) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}

func findXrefs(txt string) [][]int {
	var results [][]int

	lastWordBoundary := -1
	lastOpeningParen := -1

	for i, r := range txt {
		switch {
		case 'a' <= r && r <= 'z':
		case 'A' <= r && r <= 'Z':
		case '0' <= r && r <= '9':
		case r == '-':
		case r == '.':
		case r == '_':
		case r == '(':
			lastOpeningParen = i
		case r == ')':
			if lastOpeningParen > -1 &&
				lastWordBoundary < (lastOpeningParen-1) {
				results = append(results, []int{lastWordBoundary + 1, i + 1})
			}
		default:
			lastWordBoundary = i
			lastOpeningParen = -1
		}
	}
	return results
}

func xrefMatches(txt string, resolve func(ref string) string) []ref {
	xrefm := findXrefs(txt)
	matches := make([]ref, 0, len(xrefm))
	for _, r := range xrefm {
		url := resolve(txt[r[0]:r[1]])
		if url == "" {
			continue
		}
		matches = append(matches, ref{
			pos:  r,
			dest: url})
	}
	return matches
}

// findUrls finds anything that roughly like a URL. Matches are
// filtered by checking whether (net/url).Parse returns an error.
func findUrls(txt string) [][]int {
	var results [][]int

	lastWordBoundary := -1
	lastColon := -1
	lastSlash := -1
	inUrl := false

	for i, r := range txt {
		switch {
		case 'a' <= r && r <= 'z':
		case 'A' <= r && r <= 'Z':
		case '0' <= r && r <= '9':
		case r == ':':
			lastColon = i
		case r == '/':
			if lastColon > -1 && lastColon == i-2 && lastSlash == i-1 && lastWordBoundary < (lastColon-1) {
				inUrl = true
			}
			lastSlash = i
		default:
			if inUrl && r != ' ' {
				continue
			}
			if inUrl && r == ' ' {
				results = append(results, []int{lastWordBoundary + 1, i})
				inUrl = false
			}

			lastWordBoundary = i
			lastSlash = -1
			lastColon = -1
		}
	}
	if inUrl {
		results = append(results, []int{lastWordBoundary + 1, len(txt)})
	}
	return results
}

func urlMatches(txt string) []ref {
	urlm := findUrls(txt)
	matches := make([]ref, 0, len(urlm))
	for _, r := range urlm {
		match := txt[r[0]:r[1]]
		u, err := url.Parse(match)
		if err != nil {
			continue
		}
		matches = append(matches, ref{
			pos:  r,
			dest: u.String()})
	}
	return matches
}

func xref(txt string, resolve func(ref string) string) []*html.Node {
	urlm := urlMatches(txt)
	// all xref matches (unfiltered)
	xrefa := xrefMatches(txt, resolve)
	// filter out xrefs which
	xrefm := make([]ref, 0, len(xrefa))
	for _, x := range xrefa {
		// TODO: better algorithm
		var found bool
		for _, u := range urlm {
			if x.pos[0] >= u.pos[0] && x.pos[1] <= u.pos[1] {
				found = true
				break
			}
		}
		if found {
			continue
		}
		xrefm = append(xrefm, x)
	}

	matches := append(xrefm, urlm...)
	if len(matches) == 0 {
		return nil
	}
	sort.Sort(byStart(matches))

	var res []*html.Node
	var last int
	for _, m := range matches {
		match := txt[m.pos[0]:m.pos[1]]

		res = append(res, &html.Node{
			Type: html.TextNode,
			Data: txt[last:m.pos[0]],
		})
		a := &html.Node{
			Type: html.ElementNode,
			Data: "a",
			Attr: []html.Attribute{
				{Key: "href", Val: m.dest},
			},
		}
		a.AppendChild(&html.Node{
			Type: html.TextNode,
			Data: match,
		})
		res = append(res, a)
		last = m.pos[1]
	}
	res = append(res, &html.Node{
		Type: html.TextNode,
		Data: txt[last:],
	})

	return res
}

func plaintext(n *html.Node) string {
	var result string
	for c := n.FirstChild; c != nil; c = c.NextSibling {
		result = result + plaintext(c)
	}
	if n.Type == html.TextNode {
		return result + n.Data
	}
	return result
}

func headTable(n *html.Node) bool {
	for _, a := range n.Attr {
		if a.Key == "class" && a.Val == "head" {
			return true
		}
	}
	return false
}

func replaceId(n *html.Node, id string) {
	for idx, a := range n.Attr {
		if a.Key == "id" {
			n.Attr[idx].Val = id
			return
		}
	}
	n.Attr = append(n.Attr, html.Attribute{
		Key: "id",
		Val: id,
	})
}

func postprocess(resolve func(ref string) string, n *html.Node, toc *[]string) error {
	if n.Parent == nil {
		return nil
	}

	// Remove <html>, <head> and <body> tags, as we are dealing with
	// an HTML fragment that is included in an existing document, not
	// a document itself.
	if n.Type == html.ElementNode &&
		(n.Data == "html" ||
			n.Data == "head" ||
			n.Data == "body") {
		c := n.FirstChild
		for c != nil {
			next := c.NextSibling
			n.RemoveChild(c)
			n.Parent.InsertBefore(c, n)
			c = next
		}
		n.Parent.RemoveChild(n)
		return nil
	}

	if n.Type == html.ElementNode && heading[n.Data] {
		// Derive and set an id="" attribute for the heading
		text := plaintext(n)
		// HTML5 requires that ids must contain at least one character
		// and may not contain any spaces, see
		// http://stackoverflow.com/a/79022/712014
		id := strings.Replace(text, " ", "_", -1)
		u := url.URL{Fragment: id}
		replaceId(n, id)
		// Insert an <a> element into the heading, after the text. Via
		// CSS, this link will only be made visible while hovering.
		a := &html.Node{
			Type: html.ElementNode,
			Data: "a",
			Attr: []html.Attribute{
				{Key: "class", Val: "anchor"},
				{Key: "href", Val: u.String()},
			},
		}
		a.AppendChild(&html.Node{
			Type: html.TextNode,
			Data: "¶",
		})
		n.AppendChild(a)

		if n.Data == "h1" && toc != nil {
			*toc = append(*toc, text)
		}
	}

	if resolve == nil {
		return nil
	}

	// resolve cross references
	if n.Type == html.TextNode {
		replacements := xref(n.Data, resolve)
		for _, r := range replacements {
			n.Parent.InsertBefore(r, n)
		}
		if replacements != nil {
			n.Parent.RemoveChild(n)
			return nil
		}
	}
	if n.Type == html.TextNode &&
		strings.HasPrefix(n.Data, "(") &&
		strings.Index(n.Data, ")") > -1 &&
		n.PrevSibling != nil {
		replacements := xref(plaintext(n.PrevSibling)+n.Data, resolve)
		if replacements != nil {
			n.Parent.RemoveChild(n.PrevSibling)
			for _, r := range replacements {
				n.Parent.InsertBefore(r, n)
			}
			n.Parent.RemoveChild(n)
		}
		return nil
	}

	return nil

}

// TODO(stapelberg): ToHTML’s output currently is used directly as
// (html/template).HTML, i.e. “known safe HTML document fragment”. We
// should be more aggressive in whitelisting the allowed tags.
//
// resolve, if non-nil, will be called to resolve a reference (like
// “rm(1)”) into a URL.
func (p *Process) ToHTML(r io.Reader, resolve func(ref string) string) (doc string, toc []string, err error) {
	stdout, stderr, err := p.mandoc(r)
	if stderr != "" {
		return "", nil, fmt.Errorf("mandoc failed: %v", stderr)
	}
	if err != nil {
		return "", nil, fmt.Errorf("running mandoc failed: %v", err)
	}

	parsed, err := html.Parse(strings.NewReader(stdout))
	if err != nil {
		return "", nil, err
	}

	err = recurse(parsed, func(n *html.Node) error { return postprocess(resolve, n, &toc) })
	if err != nil {
		return "", toc, err
	}
	var rendered bytes.Buffer
	if err := html.Render(&rendered, parsed); err != nil {
		return "", toc, err
	}
	return rendered.String(), toc, nil
}
<commit_msg>Combine multiple empty case statements into one<commit_after>package convert

import (
	"bytes"
	"fmt"
	"io"
	"net/url"
	"sort"
	"strings"

	"golang.org/x/net/html"
)

var heading = map[string]bool{
	"h1": true,
	"h2": true,
	"h3": true,
	"h4": true,
	"h5": true,
	"h6": true,
}

func recurse(n *html.Node, f func(c *html.Node) error) error {
	c := n.FirstChild
	for c != nil {
		next := c.NextSibling
		if err := recurse(c, f); err != nil {
			return err
		}
		if err := f(c); err != nil {
			return err
		}
		c = next
	}
	return nil
}

type ref struct {
	pos  []int
	dest string
}

type byStart []ref

func (p byStart) Len() int {
	return len(p)
}
func (p byStart) Less(i, j int) bool {
	return p[i].pos[0] < p[j].pos[0]
}
func (p byStart) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}

func findXrefs(txt string) [][]int {
	var results [][]int

	lastWordBoundary := -1
	lastOpeningParen := -1

	for i, r := range txt {
		switch {
		case 'a' <= r && r <= 'z' ||
			'A' <= r && r <= 'Z' ||
			'0' <= r && r <= '9' ||
			r == '-' ||
			r == '.' ||
			r == '_':
		case r == '(':
			lastOpeningParen = i
		case r == ')':
			if lastOpeningParen > -1 &&
				lastWordBoundary < (lastOpeningParen-1) {
				results = append(results, []int{lastWordBoundary + 1, i + 1})
			}
		default:
			lastWordBoundary = i
			lastOpeningParen = -1
		}
	}
	return results
}

func xrefMatches(txt string, resolve func(ref string) string) []ref {
	xrefm := findXrefs(txt)
	matches := make([]ref, 0, len(xrefm))
	for _, r := range xrefm {
		url := resolve(txt[r[0]:r[1]])
		if url == "" {
			continue
		}
		matches = append(matches, ref{
			pos:  r,
			dest: url})
	}
	return matches
}

// findUrls finds anything that roughly like a URL. Matches are
// filtered by checking whether (net/url).Parse returns an error.
func findUrls(txt string) [][]int {
	var results [][]int

	lastWordBoundary := -1
	lastColon := -1
	lastSlash := -1
	inUrl := false

	for i, r := range txt {
		switch {
		case 'a' <= r && r <= 'z' ||
			'A' <= r && r <= 'Z' ||
			'0' <= r && r <= '9':
		case r == ':':
			lastColon = i
		case r == '/':
			if lastColon > -1 && lastColon == i-2 && lastSlash == i-1 && lastWordBoundary < (lastColon-1) {
				inUrl = true
			}
			lastSlash = i
		default:
			if inUrl && r != ' ' {
				continue
			}
			if inUrl && r == ' ' {
				results = append(results, []int{lastWordBoundary + 1, i})
				inUrl = false
			}

			lastWordBoundary = i
			lastSlash = -1
			lastColon = -1
		}
	}
	if inUrl {
		results = append(results, []int{lastWordBoundary + 1, len(txt)})
	}
	return results
}

func urlMatches(txt string) []ref {
	urlm := findUrls(txt)
	matches := make([]ref, 0, len(urlm))
	for _, r := range urlm {
		match := txt[r[0]:r[1]]
		u, err := url.Parse(match)
		if err != nil {
			continue
		}
		matches = append(matches, ref{
			pos:  r,
			dest: u.String()})
	}
	return matches
}

func xref(txt string, resolve func(ref string) string) []*html.Node {
	urlm := urlMatches(txt)
	// all xref matches (unfiltered)
	xrefa := xrefMatches(txt, resolve)
	// filter out xrefs which
	xrefm := make([]ref, 0, len(xrefa))
	for _, x := range xrefa {
		// TODO: better algorithm
		var found bool
		for _, u := range urlm {
			if x.pos[0] >= u.pos[0] && x.pos[1] <= u.pos[1] {
				found = true
				break
			}
		}
		if found {
			continue
		}
		xrefm = append(xrefm, x)
	}

	matches := append(xrefm, urlm...)
	if len(matches) == 0 {
		return nil
	}
	sort.Sort(byStart(matches))

	var res []*html.Node
	var last int
	for _, m := range matches {
		match := txt[m.pos[0]:m.pos[1]]

		res = append(res, &html.Node{
			Type: html.TextNode,
			Data: txt[last:m.pos[0]],
		})
		a := &html.Node{
			Type: html.ElementNode,
			Data: "a",
			Attr: []html.Attribute{
				{Key: "href", Val: m.dest},
			},
		}
		a.AppendChild(&html.Node{
			Type: html.TextNode,
			Data: match,
		})
		res = append(res, a)
		last = m.pos[1]
	}
	res = append(res, &html.Node{
		Type: html.TextNode,
		Data: txt[last:],
	})

	return res
}

func plaintext(n *html.Node) string {
	var result string
	for c := n.FirstChild; c != nil; c = c.NextSibling {
		result = result + plaintext(c)
	}
	if n.Type == html.TextNode {
		return result + n.Data
	}
	return result
}

func headTable(n *html.Node) bool {
	for _, a := range n.Attr {
		if a.Key == "class" && a.Val == "head" {
			return true
		}
	}
	return false
}

func replaceId(n *html.Node, id string) {
	for idx, a := range n.Attr {
		if a.Key == "id" {
			n.Attr[idx].Val = id
			return
		}
	}
	n.Attr = append(n.Attr, html.Attribute{
		Key: "id",
		Val: id,
	})
}

func postprocess(resolve func(ref string) string, n *html.Node, toc *[]string) error {
	if n.Parent == nil {
		return nil
	}

	// Remove <html>, <head> and <body> tags, as we are dealing with
	// an HTML fragment that is included in an existing document, not
	// a document itself.
	if n.Type == html.ElementNode &&
		(n.Data == "html" ||
			n.Data == "head" ||
			n.Data == "body") {
		c := n.FirstChild
		for c != nil {
			next := c.NextSibling
			n.RemoveChild(c)
			n.Parent.InsertBefore(c, n)
			c = next
		}
		n.Parent.RemoveChild(n)
		return nil
	}

	if n.Type == html.ElementNode && heading[n.Data] {
		// Derive and set an id="" attribute for the heading
		text := plaintext(n)
		// HTML5 requires that ids must contain at least one character
		// and may not contain any spaces, see
		// http://stackoverflow.com/a/79022/712014
		id := strings.Replace(text, " ", "_", -1)
		u := url.URL{Fragment: id}
		replaceId(n, id)
		// Insert an <a> element into the heading, after the text. Via
		// CSS, this link will only be made visible while hovering.
		a := &html.Node{
			Type: html.ElementNode,
			Data: "a",
			Attr: []html.Attribute{
				{Key: "class", Val: "anchor"},
				{Key: "href", Val: u.String()},
			},
		}
		a.AppendChild(&html.Node{
			Type: html.TextNode,
			Data: "¶",
		})
		n.AppendChild(a)

		if n.Data == "h1" && toc != nil {
			*toc = append(*toc, text)
		}
	}

	if resolve == nil {
		return nil
	}

	// resolve cross references
	if n.Type == html.TextNode {
		replacements := xref(n.Data, resolve)
		for _, r := range replacements {
			n.Parent.InsertBefore(r, n)
		}
		if replacements != nil {
			n.Parent.RemoveChild(n)
			return nil
		}
	}
	if n.Type == html.TextNode &&
		strings.HasPrefix(n.Data, "(") &&
		strings.Index(n.Data, ")") > -1 &&
		n.PrevSibling != nil {
		replacements := xref(plaintext(n.PrevSibling)+n.Data, resolve)
		if replacements != nil {
			n.Parent.RemoveChild(n.PrevSibling)
			for _, r := range replacements {
				n.Parent.InsertBefore(r, n)
			}
			n.Parent.RemoveChild(n)
		}
		return nil
	}

	return nil

}

// TODO(stapelberg): ToHTML’s output currently is used directly as
// (html/template).HTML, i.e. “known safe HTML document fragment”. We
// should be more aggressive in whitelisting the allowed tags.
//
// resolve, if non-nil, will be called to resolve a reference (like
// “rm(1)”) into a URL.
func (p *Process) ToHTML(r io.Reader, resolve func(ref string) string) (doc string, toc []string, err error) {
	stdout, stderr, err := p.mandoc(r)
	if stderr != "" {
		return "", nil, fmt.Errorf("mandoc failed: %v", stderr)
	}
	if err != nil {
		return "", nil, fmt.Errorf("running mandoc failed: %v", err)
	}

	parsed, err := html.Parse(strings.NewReader(stdout))
	if err != nil {
		return "", nil, err
	}

	err = recurse(parsed, func(n *html.Node) error { return postprocess(resolve, n, &toc) })
	if err != nil {
		return "", toc, err
	}
	var rendered bytes.Buffer
	if err := html.Render(&rendered, parsed); err != nil {
		return "", toc, err
	}
	return rendered.String(), toc, nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/tueftler/doget/command"
	"github.com/tueftler/doget/command/dump"
	"github.com/tueftler/doget/command/transform"
	"github.com/tueftler/doget/config"
	"github.com/tueftler/doget/dockerfile"
	"github.com/tueftler/doget/use"
	"os"
)

var (
	parser   = dockerfile.NewParser().Extend("USE", use.Extension)
	commands = map[string]command.Command{
		"dump":      dump.NewCommand("dump"),
		"transform": transform.NewCommand("transform"),
	}
)

func configuration(file string) (*config.Configuration, error) {
	if file == "" {
		return config.Default().Merge(config.SearchPath()...)
	} else {
		return config.Empty().MustMerge(file)
	}
}

func main() {
	var (
		cmdName    = flag.String("#1", "", "Command, one of [dump, transform]")
		configFile = flag.String("config", "", "Configuration file to use")
	)
	flag.Parse()

	configuration, err := configuration(*configFile)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}

	*cmdName = flag.Arg(0)
	if delegate, ok := commands[*cmdName]; ok {
		args := flag.Args()
		if err := delegate.Run(configuration, parser, args[1:len(args)]); err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
	} else {
		fmt.Printf("Cannot handle command %q\n", cmdName)
		flag.Usage()
		os.Exit(2)
	}
}
<commit_msg>Fix usage<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/tueftler/doget/command"
	"github.com/tueftler/doget/command/dump"
	"github.com/tueftler/doget/command/transform"
	"github.com/tueftler/doget/config"
	"github.com/tueftler/doget/dockerfile"
	"github.com/tueftler/doget/use"
	"os"
)

var (
	parser   = dockerfile.NewParser().Extend("USE", use.Extension)
	commands = map[string]command.Command{
		"dump":      dump.NewCommand("dump"),
		"transform": transform.NewCommand("transform"),
	}
)

func configuration(file string) (*config.Configuration, error) {
	if file == "" {
		return config.Default().Merge(config.SearchPath()...)
	} else {
		return config.Empty().MustMerge(file)
	}
}

func main() {
	var (
		cmdName    = flag.String("#1", "", "Command, one of [dump, transform]")
		configFile = flag.String("config", "", "Configuration file to use")
	)
	flag.Parse()

	configuration, err := configuration(*configFile)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}

	*cmdName = flag.Arg(0)
	if delegate, ok := commands[*cmdName]; ok {
		args := flag.Args()
		if err := delegate.Run(configuration, parser, args[1:len(args)]); err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
	} else {
		fmt.Printf("Cannot handle command %q\n", *cmdName)
		flag.Usage()
		os.Exit(2)
	}
}
<|endoftext|>


<commit_before>package gcache

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

	"google.golang.org/api/drive/v3"
	"google.golang.org/api/googleapi"
)

const ()

var (
	parentFolderID string
	random         *rand.Rand

	folderParams = &drive.File{
		Name:     folderName,
		MimeType: mimeGSuiteFolder,
	}

	folderName       string
	folderPermission *drive.Permission
)

func init() {
	random = rand.New(rand.NewSource(time.Now().UnixNano()))
}

// SetFolder sets name and permission to a top folder on Google Drive.
func SetFolder(
	name string,
	permission *drive.Permission,
) {
	folderName = name
	folderPermission = permission
}

func getParentFolderID(
	r *http.Request,
) (
	string,
	error,
) {
	if parentFolderID != "" {
		return parentFolderID, nil
	}
	parentFolderID, err := getDriveFolder(r)
	if err != nil {
		return "", err
	}
	return parentFolderID, nil
}

func getDriveFolder(
	r *http.Request,
) (
	string,
	error,
) {

retry:
	service, err := drive.New(createGDriveClient(r))
	if err != nil {
		if IsInvalidSecurityTicket(err) {
			oauth2TokenSource = nil
			goto retry
		}
		return "", err
	}

	fileList, err := service.Files.List().PageSize(1).Spaces("drive").Q(
		fmt.Sprintf("name='%s' and mimeType='%s'", folderName, mimeGSuiteFolder),
	).Fields(MinimumField).Do()
	if err != nil {
		return "", err
	}
	if len(fileList.Files) == 1 {
		return fileList.Files[0].Id, nil
	}

	return createDriveFolder(r)
}

func createDriveFolder(
	r *http.Request,
) (
	string,
	error,
) {

retry:
	service, err := drive.New(createGDriveClient(r))
	if err != nil {
		if IsInvalidSecurityTicket(err) {
			oauth2TokenSource = nil
			goto retry
		}
		return "", err
	}

	file, err := service.Files.Create(folderParams).Do()
	if err != nil {
		return "", err
	}
	_, err = service.Permissions.Create(file.Id, folderPermission).Do()
	if err != nil {
		return "", err
	}
	return file.Id, nil
}

// StoreGDrive stores a file to Google Drive.
func StoreGDrive(
	r *http.Request,
	name string,
	payload *[]byte,
) error {
	n := 1
retry:
	service, err := drive.New(createGDriveClient(r))
	if err != nil {
		if IsInvalidSecurityTicket(err) {
			oauth2TokenSource = nil
			goto retry
		} else if IsServerError(err) {
			n, err = sleeping(n)
			if err == nil {
				goto retry
			}
		}
		return err
	}

	folderID, err := getParentFolderID(r)
	if err != nil {
		return err
	}

	_, err = service.Files.Create(&drive.File{
		Name:     name,
		MimeType: mimeGSuiteDoc,
		Parents:  []string{folderID},
	}).Media(bytes.NewReader(*payload), googleapi.ContentType(mimeTxt)).Do()
	if err != nil {
		if IsInvalidSecurityTicket(err) {
			oauth2TokenSource = nil
			goto retry
		} else if IsServerError(err) {
			n, err = sleeping(n)
			if err == nil {
				goto retry
			}
		}
		return err
	}
	return nil
}

func sleeping(
	n int,
) (
	int,
	error,
) {
	if n > 16 {
		return 0, errors.New("Sleeping Timeout")
	}
	time.Sleep(time.Duration(n)*time.Second + time.Duration(random.Intn(1000))*time.Millisecond)
	return n * 2, nil
}
<commit_msg>StoreGDrive returns dive.File<commit_after>package gcache

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

	"google.golang.org/api/drive/v3"
	"google.golang.org/api/googleapi"
)

const ()

var (
	parentFolderID string
	random         *rand.Rand

	folderParams = &drive.File{
		Name:     folderName,
		MimeType: mimeGSuiteFolder,
	}

	folderName       string
	folderPermission *drive.Permission
)

func init() {
	random = rand.New(rand.NewSource(time.Now().UnixNano()))
}

// SetFolder sets name and permission to a top folder on Google Drive.
func SetFolder(
	name string,
	permission *drive.Permission,
) {
	folderName = name
	folderPermission = permission
}

func getParentFolderID(
	r *http.Request,
) (
	string,
	error,
) {
	if parentFolderID != "" {
		return parentFolderID, nil
	}
	parentFolderID, err := getDriveFolder(r)
	if err != nil {
		return "", err
	}
	return parentFolderID, nil
}

func getDriveFolder(
	r *http.Request,
) (
	string,
	error,
) {

retry:
	service, err := drive.New(createGDriveClient(r))
	if err != nil {
		if IsInvalidSecurityTicket(err) {
			oauth2TokenSource = nil
			goto retry
		}
		return "", err
	}

	fileList, err := service.Files.List().PageSize(1).Spaces("drive").Q(
		fmt.Sprintf("name='%s' and mimeType='%s'", folderName, mimeGSuiteFolder),
	).Fields(MinimumField).Do()
	if err != nil {
		return "", err
	}
	if len(fileList.Files) == 1 {
		return fileList.Files[0].Id, nil
	}

	return createDriveFolder(r)
}

func createDriveFolder(
	r *http.Request,
) (
	string,
	error,
) {

retry:
	service, err := drive.New(createGDriveClient(r))
	if err != nil {
		if IsInvalidSecurityTicket(err) {
			oauth2TokenSource = nil
			goto retry
		}
		return "", err
	}

	file, err := service.Files.Create(folderParams).Do()
	if err != nil {
		return "", err
	}
	_, err = service.Permissions.Create(file.Id, folderPermission).Do()
	if err != nil {
		return "", err
	}
	return file.Id, nil
}

// StoreGDrive stores a file to Google Drive.
func StoreGDrive(
	r *http.Request,
	name string,
	payload *[]byte,
) (
	*drive.File,
	error,
) {
	n := 1
retry:
	service, err := drive.New(createGDriveClient(r))
	if err != nil {
		if IsInvalidSecurityTicket(err) {
			oauth2TokenSource = nil
			goto retry
		} else if IsServerError(err) {
			n, err = sleeping(n)
			if err == nil {
				goto retry
			}
		}
		return nil, err
	}

	folderID, err := getParentFolderID(r)
	if err != nil {
		return nil, err
	}

	file, err := service.Files.Create(&drive.File{
		Name:     name,
		MimeType: mimeGSuiteDoc,
		Parents:  []string{folderID},
	}).Media(bytes.NewReader(*payload), googleapi.ContentType(mimeTxt)).Do()
	if err != nil {
		if IsInvalidSecurityTicket(err) {
			oauth2TokenSource = nil
			goto retry
		} else if IsServerError(err) {
			n, err = sleeping(n)
			if err == nil {
				goto retry
			}
		}
		return nil, err
	}
	return file, nil
}

func sleeping(
	n int,
) (
	int,
	error,
) {
	if n > 16 {
		return 0, errors.New("Sleeping Timeout")
	}
	time.Sleep(time.Duration(n)*time.Second + time.Duration(random.Intn(1000))*time.Millisecond)
	return n * 2, nil
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "io"
    "os"
    "os/signal"
    "strings"
    "sync"
    "syscall"
    "time"
    "github.com/jessevdk/go-flags"
    "github.com/tillberg/ansi-log"
    "github.com/tillberg/bismuth"
)

var OptsCommon struct {
    Verbose bool `short:"v" long:"verbose" description:"Show verbose debug information"`
    Version bool `long:"version"`
    NoColor bool `long:"no-color"`
    InstallDeps bool `long:"install-deps"`
}

var OptsSync struct {
    IdentityFile string `short:"i" long:"identity"`
    Dev bool `long:"dev"`
    Positional struct {
        LocalPath  string
    } `positional-args:"yes" required:"yes"`
}

func EnsureBuild(local *SyncContext, ctx *SyncContext) (didSomething bool, err error) {
    status := ctx.Logger()
    desiredGitVersion := GitVersion
    if ctx.IsWindows() {
        desiredGitVersion = GitWinVersion
    }
    exists, err := ctx.PathExists(GutExePath)
    if err != nil { return false, err }
    if exists {
        actualGutVersion, err := ctx.Output(ctx.AbsPath(GutExePath), "--version")
        if err != nil { return false, err }
        if strings.Contains(string(actualGutVersion), strings.TrimLeft(desiredGitVersion, "v")) {
            return false, nil
        }
    }
    status.Printf("@(dim:Need to build gut on) %s@(dim:.)\n", ctx.NameAnsi())
    err = EnsureGutFolders(ctx)
    if err != nil { return false, err }
    err = GutBuildPrepare(local, ctx)
    if err != nil { return false, err }
    var buildPath string
    if ctx.IsLocal() {
        if ctx.IsWindows() {
            buildPath = GutWinSrcPath
        } else {
            buildPath = GutSrcPath
        }
    } else {
        buildPath = GutSrcTmpPath
        status.Printf("@(dim:Uploading) %s @(dim:to) %s@(dim:...)", local.PathAnsi(GutSrcPath), ctx.PathAnsi(buildPath))
        chanErr := make(chan error)
        stdinChan := make(chan io.WriteCloser)
        go func() {
            ctx.Mkdirp(buildPath)
            err := ctx.QuotePipeIn("untar", stdinChan, ctx.AbsPath(buildPath), "tar", "xf", "-")
            chanErr<-err
        }()
        ctxStdin := <-stdinChan
        err = local.QuotePipeOut("tar", ctxStdin, local.AbsPath(GutSrcPath), "tar", "cf", "-", "--exclude=.git", "--exclude=t", "./")
        if err != nil { return false, err }
        err = <-chanErr
        if err != nil { return false, err }
        status.Printf("@(dim: done.)\n")
    }
    err = GutBuild(ctx, buildPath)
    if err != nil { return false, err }
    status.Printf("@(dim:Cleaning up...)")
    err = GutUnprepare(local, ctx)
    if err != nil { return false, err }
    status.Printf("@(dim: done.)\n")
    return true, nil
}

func doSession(ctx *SyncContext, done chan bool) {
    err := ctx.QuoteShell("test", "echo -n 'working... '; sleep 0.01; hostname")
    if err != nil {
        log.Fatalf("unable to connect: %s", err)
    }
    done <- true
}

const commitDebounceDuration = 100 * time.Millisecond
func Sync(local *SyncContext, remotes []*SyncContext) (err error) {
    status := local.NewLogger("sync")
    defer status.Close()
    hostsStr := local.SyncPathAnsi()
    commaStr := status.Colorify("@(dim:, )")
    andStr := status.Colorify("@(dim:and )")
    for i, ctx := range remotes {
        if len(remotes) >= 2 {
            hostsStr += commaStr
        }
        if i == len(remotes) - 1 {
            if len(remotes) < 2 {
                hostsStr += " "
            }
            hostsStr += andStr
        }
        hostsStr += ctx.SyncPathAnsi()
    }
    status.Printf("@(dim:Starting gut-sync between) %s@(dim:.)\n", hostsStr)

    allContexts := append([]*SyncContext{local}, remotes...)

    for _, ctx := range allContexts {
        _, err = EnsureBuild(local, ctx)
        if err != nil { status.Bail(err) }
    }

    ports, err := FindOpenPorts(2, allContexts...)
    if err != nil { status.Bail(err) }
    // status.Printf("Using ports %v\n", ports)
    gutdPort := ports[0]
    autosshMonitorPort := ports[1]

    for _, ctx := range allContexts {
        if !ctx.IsLocal() {
            err = StartSshTunnel(local, ctx, gutdPort, autosshMonitorPort)
            if err != nil { status.Bail(err) }
        }
    }

    repoName := RandSeq(12)
    GutDaemon(local, repoName, gutdPort)

    // Find tailHash, if any. Bail if there are conflicting tailHashes.
    tailHash := ""
    var tailHashFoundOn *SyncContext
    localTailHash, err := local.GetTailHash()
    if err != nil { status.Bail(err) }
    if localTailHash != "" {
        tailHash = localTailHash
        tailHashFoundOn = local
    }
    setupGutOrigin := func(ctx *SyncContext) {
        _err := GutSetupOrigin(ctx, repoName, gutdPort)
        if _err != nil { status.Bail(_err) }
    }
    contextsNeedInit := []*SyncContext{}
    for _, ctx := range remotes {
        myTailHash, err := ctx.GetTailHash()
        if err != nil { status.Bail(err) }
        if myTailHash == "" {
            err = AssertSyncFolderIsEmpty(ctx)
            if err != nil { status.Bail(err) }
            contextsNeedInit = append(contextsNeedInit, ctx)
        } else {
            if tailHash == "" {
                tailHash = myTailHash
                tailHashFoundOn = ctx
            } else {
                if tailHash != myTailHash {
                    status.Printf("@(error:Found different gut repo base commits:)\n")
                    status.Printf("@(error:[)@(commit:%s)@(error:]) on %s\n",
                                  TrimCommit(tailHash), tailHashFoundOn.SyncPathAnsi())
                    status.Printf("@(error:[)@(commit:%s)@(error:]) on %s\n",
                                  TrimCommit(myTailHash), ctx.SyncPathAnsi())
                    Shutdown(status.Colorify("@(error:Cannot sync incompatible gut repos.)"))
                }
                setupGutOrigin(ctx)
            }
        }
    }
    if localTailHash == "" {
        if tailHash == "" {
            status.Printf("@(dim:No existing gut repo found. Initializing gut repo in %s.)\n", local.SyncPathAnsi())
            err = GutInit(local)
            if err != nil { status.Bail(err) }
            setupGutOrigin(local)
            err = GutEnsureInitialCommit(local)
            if err != nil { status.Bail(err) }
            tailHash, err = local.GetTailHash()
            if err != nil { status.Bail(err) }
            if tailHash == "" {
                Shutdown(status.Colorify("Failed to initialize new gut repo."))
            }
            tailHashFoundOn = local
        } else {
            err = GutInit(local)
            if err != nil { status.Bail(err) }
            setupGutOrigin(local)
            err = GutPush(tailHashFoundOn)
            if err != nil { status.Bail(err) }
            err = GutCheckout(local, tailHashFoundOn.BranchName())
            if err != nil { status.Bail(err) }
        }
    } else {
        setupGutOrigin(local)
    }
    for _, ctx := range contextsNeedInit {
        err = GutInit(ctx)
        if err != nil { status.Bail(err) }
        setupGutOrigin(ctx)
        err = ctx.GutPull()
        if err != nil { status.Bail(err) }
    }

    type FileEvent struct {
        ctx *SyncContext
        filepath string
    }
    eventChan := make(chan FileEvent)

    commitAndUpdate := func(src *SyncContext, changedPaths []string, updateUntracked bool) (err error) {
        prefix := CommonPathPrefix(changedPaths...)
        if prefix != "" {
            // git is annoying if you try to git-add git-ignored files (printing a message that is very helpful when there is a human
            // attached to stdin/stderr), so let's always just target the last *folder* by lopping off everything after the last slash:
            lastIndex := strings.LastIndex(prefix, "/")
            if lastIndex == -1 {
                prefix = ""
            } else {
                prefix = prefix[:lastIndex+1]
            }
        }
        if prefix == "" {
            prefix = "."
        }
        changed, err := GutCommit(src, prefix, updateUntracked)
        if err != nil { status.Bail(err) }
        if changed {
            if src != local {
                err = GutPush(src)
                if err != nil { status.Bail(err) }
                err = GutMerge(local, src.BranchName())
                if err != nil { status.Bail(err) }
            }
            done := make(chan error)
            for _, _ctx := range remotes {
                if _ctx != src {
                    go func(ctx *SyncContext) {
                        done<-ctx.GutPull()
                    }(_ctx)
                }
            }
            for _, ctx := range remotes {
                if ctx != src {
                    err = <-done
                    if err == NeedsCommitError {
                        status.Printf("@(dim:Need to commit on) %s @(dim:before it can pull.)\n", ctx.NameAnsi())
                        // Queue up an event to force checking for changes. Saying that
                        // .gutignore changed is a kludgy way to get it to check for files
                        // that should be untracked.
                        eventChan<-FileEvent{ctx, ".gutignore"}
                        err = nil
                    }
                    if err != nil { status.Bail(err) }
                }
            }
        }
        return nil
    }

    fileEventCallbackGen := func(ctx *SyncContext) func(filepath string) {
        return func(filepath string) {
            eventChan<-FileEvent{ctx, filepath}
        }
    }

    for _, ctx := range allContexts {
        WatchForChanges(ctx, fileEventCallbackGen(ctx))
    }
    // The filesystem watchers are not necessarily listening to all updates yet, so we could miss file changes that occur between the
    // commit_and_update calls below and the time that the filesystem watches are attached.
    for _, ctx := range allContexts {
        commitAndUpdate(ctx, []string{}, true)
    }

    var haveChanges bool
    var changedPaths map[*SyncContext]map[string]bool
    var changedIgnore map[*SyncContext]bool
    clearChanges := func() {
        haveChanges = false
        changedPaths = make(map[*SyncContext]map[string]bool)
        changedIgnore = make(map[*SyncContext]bool)
    }
    clearChanges()
    flushChanges := func() {
        for ctx, pathMap := range changedPaths {
            paths := []string{}
            for path, _ := range pathMap {
                paths = append(paths, path)
            }
            _, changedThisIgnore := changedIgnore[ctx]
            commitAndUpdate(ctx, paths, changedThisIgnore)
        }
        clearChanges()
    }

    var event FileEvent
    for {
        if haveChanges {
            select {
                case event = <-eventChan:
                    break
                case <-time.After(commitDebounceDuration):
                    flushChanges()
                    continue
            }
        } else {
            event = <-eventChan
        }
        parts := strings.Split(event.filepath, "/")
        skip := false
        for _, part := range parts {
            if part == ".gut" {
                skip = true
            } else if part == ".gutignore" {
                changedIgnore[event.ctx] = true
            }
        }
        if skip { continue }
        // status.Printf("@(dim:[)%s@(dim:] changed on) %s\n", event.filepath, event.ctx.NameAnsi())
        haveChanges = true
        ctxChanged, ok := changedPaths[event.ctx]
        if !ok {
             ctxChanged = make(map[string]bool)
             changedPaths[event.ctx] = ctxChanged
        }
        ctxChanged[event.filepath] = true
    }
    return nil
}

var shutdownLock sync.Mutex
func Shutdown(reason string) {
    shutdownLock.Lock()
    status := log.New(os.Stderr, "", 0)
    if reason != "" {
        status.Printf("%s ", reason)
    }
    status.Printf("Stopping all subprocesses...")
    done := make(chan bool)
    for _, _ctx := range AllSyncContexts {
        go func(ctx *SyncContext) {
            ctx.KillAllSessions()
            // This generally shouldn't *do* anything other than
            // clean up the PID files, as the killing would have
            // been done already in KillAllSessions.
            ctx.KillAllViaPidfiles()
            ctx.Close()
            done<-true
        }(_ctx)
    }
    for _, _ = range AllSyncContexts {
        <-done
    }
    status.Printf(" Exiting.")
    fmt.Println()
    os.Exit(1)
}

func main() {
    log.EnableMultilineMode()
    log.EnableColorTemplate()
    log.AddAnsiColorCode("error", 31)
    log.AddAnsiColorCode("commit", 32)
    status := log.New(os.Stderr, "", 0)
    var args []string = os.Args[1:]
    if len(args) == 0 {
        status.Fatalln("You must specify a gut-command, e.g. `gut sync ...`")
    }
    var cmd = args[0]
    args = args[1:]
    if IsGitCommand(cmd) {
        var gutExe = PathInUserHome(GutExePath)
        syscall.Exec(gutExe, append([]string { gutExe }, args...), os.Environ())
        status.Fatalf("Failed to exec %s", gutExe)
    }
    var argsRemaining, err = flags.ParseArgs(&OptsCommon, args)
    if err != nil { status.Fatal(err) }
    // fmt.Printf("color: %s\n", OptsCommon.NoColor)
    if OptsCommon.Version {
        status.Print("gut-sync version XXXXX")
        os.Exit(0)
    }
    bismuth.SetVerbose(OptsCommon.Verbose)

    signalChan := make(chan os.Signal, 1)
    signal.Notify(signalChan, os.Interrupt)
    go func() {
        <-signalChan
        Shutdown("Received SIGINT.")
    }()

    if cmd == "build" {
        var local = NewSyncContext()
        err := local.Connect()
        if err != nil { status.Fatal(err) }
        didSomething, err := EnsureBuild(local, local)
        if err != nil { status.Fatal(err) }
        if !didSomething {
            status.Printf("@(dim:gut) " + GitVersion + " @(dim:has already been built.)\n")
        }
    } else if cmd == "sync" {
        var remoteArgs, err = flags.ParseArgs(&OptsSync, argsRemaining)
        if err != nil { status.Fatal(err) }

        local := NewSyncContext()
        err = local.ParseSyncPath(OptsSync.Positional.LocalPath)
        if err != nil { status.Fatal(err) }
        err = local.Connect()
        if err != nil { status.Fatal(err) }
        local.KillAllViaPidfiles()

        remotes := []*SyncContext{}
        for _, remotePath := range remoteArgs {
            remote := NewSyncContext()
            err = remote.ParseSyncPath(remotePath)
            if err != nil { status.Fatal(err) }
            err = remote.Connect()
            if err != nil { status.Fatal(err) }
            remote.KillAllViaPidfiles()
            remotes = append(remotes, remote)
        }

        err = Sync(local, remotes)
        if err != nil { status.Fatal(err) }
    }
}
<commit_msg>Formatting improvements<commit_after>package main

import (
    "fmt"
    "io"
    "os"
    "os/signal"
    "strings"
    "sync"
    "syscall"
    "time"
    "github.com/jessevdk/go-flags"
    "github.com/tillberg/ansi-log"
    "github.com/tillberg/bismuth"
)

var OptsCommon struct {
    Verbose bool `short:"v" long:"verbose" description:"Show verbose debug information"`
    Version bool `long:"version"`
    NoColor bool `long:"no-color"`
    InstallDeps bool `long:"install-deps"`
}

var OptsSync struct {
    IdentityFile string `short:"i" long:"identity"`
    Dev bool `long:"dev"`
    Positional struct {
        LocalPath  string
    } `positional-args:"yes" required:"yes"`
}

func EnsureBuild(local *SyncContext, ctx *SyncContext) (didSomething bool, err error) {
    status := ctx.Logger()
    desiredGitVersion := GitVersion
    if ctx.IsWindows() {
        desiredGitVersion = GitWinVersion
    }
    exists, err := ctx.PathExists(GutExePath)
    if err != nil { return false, err }
    if exists {
        actualGutVersion, err := ctx.Output(ctx.AbsPath(GutExePath), "--version")
        if err != nil { return false, err }
        if strings.Contains(string(actualGutVersion), strings.TrimLeft(desiredGitVersion, "v")) {
            return false, nil
        }
    }
    status.Printf("@(dim:Need to build gut on) %s@(dim:.)\n", ctx.NameAnsi())
    err = EnsureGutFolders(ctx)
    if err != nil { return false, err }
    err = GutBuildPrepare(local, ctx)
    if err != nil { return false, err }
    var buildPath string
    if ctx.IsLocal() {
        if ctx.IsWindows() {
            buildPath = GutWinSrcPath
        } else {
            buildPath = GutSrcPath
        }
    } else {
        buildPath = GutSrcTmpPath
        status.Printf("@(dim:Uploading) %s @(dim:to) %s@(dim:...)", local.PathAnsi(GutSrcPath), ctx.PathAnsi(buildPath))
        chanErr := make(chan error)
        stdinChan := make(chan io.WriteCloser)
        go func() {
            ctx.Mkdirp(buildPath)
            err := ctx.QuotePipeIn("untar", stdinChan, ctx.AbsPath(buildPath), "tar", "xf", "-")
            chanErr<-err
        }()
        ctxStdin := <-stdinChan
        err = local.QuotePipeOut("tar", ctxStdin, local.AbsPath(GutSrcPath), "tar", "cf", "-", "--exclude=.git", "--exclude=t", "./")
        if err != nil { return false, err }
        err = <-chanErr
        if err != nil { return false, err }
        status.Printf("@(dim: done.)\n")
    }
    err = GutBuild(ctx, buildPath)
    if err != nil { return false, err }
    status.Printf("@(dim:Cleaning up...)")
    err = GutUnprepare(local, ctx)
    if err != nil { return false, err }
    status.Printf("@(dim: done.)\n")
    return true, nil
}

func doSession(ctx *SyncContext, done chan bool) {
    err := ctx.QuoteShell("test", "echo -n 'working... '; sleep 0.01; hostname")
    if err != nil {
        log.Fatalf("unable to connect: %s", err)
    }
    done <- true
}

const commitDebounceDuration = 100 * time.Millisecond
func Sync(local *SyncContext, remotes []*SyncContext) (err error) {
    status := local.NewLogger("sync")
    defer status.Close()
    hostsStr := local.SyncPathAnsi()
    commaStr := status.Colorify("@(dim:, )")
    andStr := status.Colorify("@(dim:and )")
    for i, ctx := range remotes {
        if len(remotes) >= 2 {
            hostsStr += commaStr
        }
        if i == len(remotes) - 1 {
            if len(remotes) < 2 {
                hostsStr += " "
            }
            hostsStr += andStr
        }
        hostsStr += ctx.SyncPathAnsi()
    }
    status.Printf("@(dim:Starting gut-sync between) %s@(dim:.)\n", hostsStr)

    allContexts := append([]*SyncContext{local}, remotes...)

    for _, ctx := range allContexts {
        _, err = EnsureBuild(local, ctx)
        if err != nil { status.Bail(err) }
    }

    ports, err := FindOpenPorts(2, allContexts...)
    if err != nil { status.Bail(err) }
    // status.Printf("Using ports %v\n", ports)
    gutdPort := ports[0]
    autosshMonitorPort := ports[1]

    for _, ctx := range allContexts {
        if !ctx.IsLocal() {
            err = StartSshTunnel(local, ctx, gutdPort, autosshMonitorPort)
            if err != nil { status.Bail(err) }
        }
    }

    repoName := RandSeq(12)
    GutDaemon(local, repoName, gutdPort)

    // Find tailHash, if any. Bail if there are conflicting tailHashes.
    tailHash := ""
    var tailHashFoundOn *SyncContext
    localTailHash, err := local.GetTailHash()
    if err != nil { status.Bail(err) }
    if localTailHash != "" {
        tailHash = localTailHash
        tailHashFoundOn = local
    }
    setupGutOrigin := func(ctx *SyncContext) {
        _err := GutSetupOrigin(ctx, repoName, gutdPort)
        if _err != nil { status.Bail(_err) }
    }
    contextsNeedInit := []*SyncContext{}
    for _, ctx := range remotes {
        myTailHash, err := ctx.GetTailHash()
        if err != nil { status.Bail(err) }
        if myTailHash == "" {
            err = AssertSyncFolderIsEmpty(ctx)
            if err != nil { status.Bail(err) }
            contextsNeedInit = append(contextsNeedInit, ctx)
        } else {
            if tailHash == "" {
                tailHash = myTailHash
                tailHashFoundOn = ctx
            } else {
                if tailHash != myTailHash {
                    status.Printf("@(error:Found different gut repo base commits:)\n")
                    status.Printf("@(commit:%s) @(error:on) %s\n",
                                  TrimCommit(tailHash), tailHashFoundOn.SyncPathAnsi())
                    status.Printf("@(commit:%s) @(error:on) %s\n",
                                  TrimCommit(myTailHash), ctx.SyncPathAnsi())
                    Shutdown(status.Colorify("@(error:Cannot sync incompatible gut repos.)"))
                }
                setupGutOrigin(ctx)
            }
        }
    }
    if localTailHash == "" {
        if tailHash == "" {
            status.Printf("@(dim:No existing gut repo found. Initializing gut repo in %s.)\n", local.SyncPathAnsi())
            err = GutInit(local)
            if err != nil { status.Bail(err) }
            setupGutOrigin(local)
            err = GutEnsureInitialCommit(local)
            if err != nil { status.Bail(err) }
            tailHash, err = local.GetTailHash()
            if err != nil { status.Bail(err) }
            if tailHash == "" {
                Shutdown(status.Colorify("Failed to initialize new gut repo."))
            }
            tailHashFoundOn = local
        } else {
            err = GutInit(local)
            if err != nil { status.Bail(err) }
            setupGutOrigin(local)
            err = GutPush(tailHashFoundOn)
            if err != nil { status.Bail(err) }
            err = GutCheckout(local, tailHashFoundOn.BranchName())
            if err != nil { status.Bail(err) }
        }
    } else {
        setupGutOrigin(local)
    }
    for _, ctx := range contextsNeedInit {
        err = GutInit(ctx)
        if err != nil { status.Bail(err) }
        setupGutOrigin(ctx)
        err = ctx.GutPull()
        if err != nil { status.Bail(err) }
    }

    type FileEvent struct {
        ctx *SyncContext
        filepath string
    }
    eventChan := make(chan FileEvent)

    commitAndUpdate := func(src *SyncContext, changedPaths []string, updateUntracked bool) (err error) {
        prefix := CommonPathPrefix(changedPaths...)
        if prefix != "" {
            // git is annoying if you try to git-add git-ignored files (printing a message that is very helpful when there is a human
            // attached to stdin/stderr), so let's always just target the last *folder* by lopping off everything after the last slash:
            lastIndex := strings.LastIndex(prefix, "/")
            if lastIndex == -1 {
                prefix = ""
            } else {
                prefix = prefix[:lastIndex+1]
            }
        }
        if prefix == "" {
            prefix = "."
        }
        changed, err := GutCommit(src, prefix, updateUntracked)
        if err != nil { status.Bail(err) }
        if changed {
            if src != local {
                err = GutPush(src)
                if err != nil { status.Bail(err) }
                err = GutMerge(local, src.BranchName())
                if err != nil { status.Bail(err) }
            }
            done := make(chan error)
            for _, _ctx := range remotes {
                if _ctx != src {
                    go func(ctx *SyncContext) {
                        done<-ctx.GutPull()
                    }(_ctx)
                }
            }
            for _, ctx := range remotes {
                if ctx != src {
                    err = <-done
                    if err == NeedsCommitError {
                        status.Printf("@(dim:Need to commit on) %s @(dim:before it can pull.)\n", ctx.NameAnsi())
                        // Queue up an event to force checking for changes. Saying that
                        // .gutignore changed is a kludgy way to get it to check for files
                        // that should be untracked.
                        eventChan<-FileEvent{ctx, ".gutignore"}
                        err = nil
                    }
                    if err != nil { status.Bail(err) }
                }
            }
        }
        return nil
    }

    fileEventCallbackGen := func(ctx *SyncContext) func(filepath string) {
        return func(filepath string) {
            eventChan<-FileEvent{ctx, filepath}
        }
    }

    for _, ctx := range allContexts {
        WatchForChanges(ctx, fileEventCallbackGen(ctx))
    }
    // The filesystem watchers are not necessarily listening to all updates yet, so we could miss file changes that occur between the
    // commit_and_update calls below and the time that the filesystem watches are attached.
    for _, ctx := range allContexts {
        commitAndUpdate(ctx, []string{}, true)
    }

    var haveChanges bool
    var changedPaths map[*SyncContext]map[string]bool
    var changedIgnore map[*SyncContext]bool
    clearChanges := func() {
        haveChanges = false
        changedPaths = make(map[*SyncContext]map[string]bool)
        changedIgnore = make(map[*SyncContext]bool)
    }
    clearChanges()
    flushChanges := func() {
        for ctx, pathMap := range changedPaths {
            paths := []string{}
            for path, _ := range pathMap {
                paths = append(paths, path)
            }
            _, changedThisIgnore := changedIgnore[ctx]
            commitAndUpdate(ctx, paths, changedThisIgnore)
        }
        clearChanges()
    }

    var event FileEvent
    for {
        if haveChanges {
            select {
                case event = <-eventChan:
                    break
                case <-time.After(commitDebounceDuration):
                    flushChanges()
                    continue
            }
        } else {
            event = <-eventChan
        }
        parts := strings.Split(event.filepath, "/")
        skip := false
        for _, part := range parts {
            if part == ".gut" {
                skip = true
            } else if part == ".gutignore" {
                changedIgnore[event.ctx] = true
            }
        }
        if skip { continue }
        // status.Printf("@(dim:[)%s@(dim:] changed on) %s\n", event.filepath, event.ctx.NameAnsi())
        haveChanges = true
        ctxChanged, ok := changedPaths[event.ctx]
        if !ok {
             ctxChanged = make(map[string]bool)
             changedPaths[event.ctx] = ctxChanged
        }
        ctxChanged[event.filepath] = true
    }
    return nil
}

var shutdownLock sync.Mutex
func Shutdown(reason string) {
    shutdownLock.Lock()
    status := log.New(os.Stderr, "", 0)
    if reason != "" {
        status.Printf("%s ", reason)
    }
    status.Printf("Stopping all subprocesses...\n")
    done := make(chan bool)
    for _, _ctx := range AllSyncContexts {
        go func(ctx *SyncContext) {
            ctx.KillAllSessions()
            // This generally shouldn't *do* anything other than
            // clean up the PID files, as the killing would have
            // been done already in KillAllSessions.
            ctx.KillAllViaPidfiles()
            ctx.Close()
            done<-true
        }(_ctx)
    }
    for _, _ = range AllSyncContexts {
        <-done
    }
    status.Printf("Exiting.")
    fmt.Println()
    os.Exit(1)
}

func main() {
    log.EnableMultilineMode()
    log.EnableColorTemplate()
    log.AddAnsiColorCode("error", 31)
    log.AddAnsiColorCode("commit", 32)
    status := log.New(os.Stderr, "", 0)
    var args []string = os.Args[1:]
    if len(args) == 0 {
        status.Fatalln("You must specify a gut-command, e.g. `gut sync ...`")
    }
    var cmd = args[0]
    args = args[1:]
    if IsGitCommand(cmd) {
        var gutExe = PathInUserHome(GutExePath)
        syscall.Exec(gutExe, append([]string { gutExe }, args...), os.Environ())
        status.Fatalf("Failed to exec %s", gutExe)
    }
    var argsRemaining, err = flags.ParseArgs(&OptsCommon, args)
    if err != nil { status.Fatal(err) }
    // fmt.Printf("color: %s\n", OptsCommon.NoColor)
    if OptsCommon.Version {
        status.Print("gut-sync version XXXXX")
        os.Exit(0)
    }
    bismuth.SetVerbose(OptsCommon.Verbose)

    signalChan := make(chan os.Signal, 1)
    signal.Notify(signalChan, os.Interrupt)
    go func() {
        <-signalChan
        Shutdown("Received SIGINT.")
    }()

    if cmd == "build" {
        var local = NewSyncContext()
        err := local.Connect()
        if err != nil { status.Fatal(err) }
        didSomething, err := EnsureBuild(local, local)
        if err != nil { status.Fatal(err) }
        if !didSomething {
            status.Printf("@(dim:gut) " + GitVersion + " @(dim:has already been built.)\n")
        }
    } else if cmd == "sync" {
        var remoteArgs, err = flags.ParseArgs(&OptsSync, argsRemaining)
        if err != nil { status.Fatal(err) }

        local := NewSyncContext()
        err = local.ParseSyncPath(OptsSync.Positional.LocalPath)
        if err != nil { status.Fatal(err) }
        err = local.Connect()
        if err != nil { status.Fatal(err) }
        local.KillAllViaPidfiles()

        remotes := []*SyncContext{}
        for _, remotePath := range remoteArgs {
            remote := NewSyncContext()
            err = remote.ParseSyncPath(remotePath)
            if err != nil { status.Fatal(err) }
            err = remote.Connect()
            if err != nil { status.Fatal(err) }
            remote.KillAllViaPidfiles()
            remotes = append(remotes, remote)
        }

        err = Sync(local, remotes)
        if err != nil { status.Fatal(err) }
    }
}
<|endoftext|>


<commit_before>package php

import (
	"fmt"
	"strings"
	"unicode/utf8"
)

type lexer struct {
	lastPos int
	pos     int
	start   int
	width   int
	input   string
	items   chan item // channel of scanned items.
}

func newLexer(input string) *lexer {
	l := &lexer{
		input: input,
		items: make(chan item),
	}
	return l
}

// stateFn represents the state of the scanner
// as a function that returns the next state.
type stateFn func(*lexer) stateFn

// run lexes the input by executing state functions until
// the state is nil.
func (l *lexer) run() {
	for state := lexHTML; state != nil; {
		state = state(l)
	}
	close(l.items) // No more tokens will be delivered.
}

func (l *lexer) emit(t itemType) {
	i := item{t, l.start, l.input[l.start:l.pos]}
	fmt.Println(i)
	l.items <- i
	l.start = l.pos
}

// nextItem returns the next item from the input.
func (l *lexer) nextItem() item {
	item := <-l.items
	l.lastPos = item.pos
	return item
}

// peek returns but does not consume the next rune in the input.
func (l *lexer) peek() rune {
	r := l.next()
	l.backup()
	return r
}

// backup steps back one rune. Can only be called once per call of next.
func (l *lexer) backup() {
	l.pos -= l.width
}

func (l *lexer) accept(valid string) bool {
	if strings.IndexRune(valid, l.next()) >= 0 {
		return true
	}
	l.backup()
	return false
}

// acceptRun consumes a run of runes from the valid set.
func (l *lexer) acceptRun(valid string) {
	for strings.IndexRune(valid, l.next()) >= 0 {
	}
	l.backup()
}

func (l *lexer) next() rune {
	if int(l.pos) >= len(l.input) {
		l.width = 0
		return eof
	}
	r, w := utf8.DecodeRuneInString(l.input[l.pos:])
	l.width = w
	l.pos += l.width
	return r
}

// ignore skips over the pending input before this point.
func (l *lexer) ignore() {
	l.start = l.pos
}

func (l *lexer) skipSpace() {
	r := l.next()
	for isSpace(r) {
		r = l.next()
	}
	l.backup()
	l.ignore()
}

func (l *lexer) errorf(format string, args ...interface{}) stateFn {
	l.items <- item{itemError, l.start, fmt.Sprintf(format, args...)}
	return nil
}

// isSpace reports whether r is a space character.
func isSpace(r rune) bool {
	return r == ' ' || r == '\t' || r == '\n'
}
<commit_msg>Removing a print statement from the lexer<commit_after>package php

import (
	"fmt"
	"strings"
	"unicode/utf8"
)

type lexer struct {
	lastPos int
	pos     int
	start   int
	width   int
	input   string
	items   chan item // channel of scanned items.
}

func newLexer(input string) *lexer {
	l := &lexer{
		input: input,
		items: make(chan item),
	}
	return l
}

// stateFn represents the state of the scanner
// as a function that returns the next state.
type stateFn func(*lexer) stateFn

// run lexes the input by executing state functions until
// the state is nil.
func (l *lexer) run() {
	for state := lexHTML; state != nil; {
		state = state(l)
	}
	close(l.items) // No more tokens will be delivered.
}

func (l *lexer) emit(t itemType) {
	i := item{t, l.start, l.input[l.start:l.pos]}
	l.items <- i
	l.start = l.pos
}

// nextItem returns the next item from the input.
func (l *lexer) nextItem() item {
	item := <-l.items
	l.lastPos = item.pos
	return item
}

// peek returns but does not consume the next rune in the input.
func (l *lexer) peek() rune {
	r := l.next()
	l.backup()
	return r
}

// backup steps back one rune. Can only be called once per call of next.
func (l *lexer) backup() {
	l.pos -= l.width
}

func (l *lexer) accept(valid string) bool {
	if strings.IndexRune(valid, l.next()) >= 0 {
		return true
	}
	l.backup()
	return false
}

// acceptRun consumes a run of runes from the valid set.
func (l *lexer) acceptRun(valid string) {
	for strings.IndexRune(valid, l.next()) >= 0 {
	}
	l.backup()
}

func (l *lexer) next() rune {
	if int(l.pos) >= len(l.input) {
		l.width = 0
		return eof
	}
	r, w := utf8.DecodeRuneInString(l.input[l.pos:])
	l.width = w
	l.pos += l.width
	return r
}

// ignore skips over the pending input before this point.
func (l *lexer) ignore() {
	l.start = l.pos
}

func (l *lexer) skipSpace() {
	r := l.next()
	for isSpace(r) {
		r = l.next()
	}
	l.backup()
	l.ignore()
}

func (l *lexer) errorf(format string, args ...interface{}) stateFn {
	l.items <- item{itemError, l.start, fmt.Sprintf(format, args...)}
	return nil
}

// isSpace reports whether r is a space character.
func isSpace(r rune) bool {
	return r == ' ' || r == '\t' || r == '\n'
}
<|endoftext|>