<commit_before>package sqlx

// Named Query Support
//
//  * BindMap - bind query bindvars to map/struct args
//	* NamedExec, NamedQuery - named query w/ struct or map
//  * NamedStmt - a pre-compiled named query which is a prepared statement
//
// Internal Interfaces:
//
//  * compileNamedQuery - rebind a named query, returning a query and list of names
//  * bindArgs, bindMapArgs, bindAnyArgs - given a list of names, return an arglist
//
import (
	"database/sql"
	"errors"
	"fmt"
	"reflect"
	"strconv"
	"unicode"

	"github.com/jmoiron/sqlx/reflectx"
)

// NamedStmt is a prepared statement that executes named queries.  Prepare it
// how you would execute a NamedQuery, but pass in a struct or map when executing.
type NamedStmt struct {
	Params      []string
	QueryString string
	Stmt        *Stmt
}

// Close closes the named statement.
func (n *NamedStmt) Close() error {
	return n.Stmt.Close()
}

// Exec executes a named statement using the struct passed.
func (n *NamedStmt) Exec(arg interface{}) (sql.Result, error) {
	args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper)
	if err != nil {
		return *new(sql.Result), err
	}
	return n.Stmt.Exec(args...)
}

// Query executes a named statement using the struct argument, returning rows.
func (n *NamedStmt) Query(arg interface{}) (*sql.Rows, error) {
	args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper)
	if err != nil {
		return nil, err
	}
	return n.Stmt.Query(args...)
}

// QueryRow executes a named statement against the database.  Because sqlx cannot
// create a *sql.Row with an error condition pre-set for binding errors, sqlx
// returns a *sqlx.Row instead.
func (n *NamedStmt) QueryRow(arg interface{}) *Row {
	args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper)
	if err != nil {
		return &Row{err: err}
	}
	return n.Stmt.QueryRowx(args...)
}

// MustExec execs a NamedStmt, panicing on error
func (n *NamedStmt) MustExec(arg interface{}) sql.Result {
	res, err := n.Exec(arg)
	if err != nil {
		panic(err)
	}
	return res
}

// Queryx using this NamedStmt
func (n *NamedStmt) Queryx(arg interface{}) (*Rows, error) {
	r, err := n.Query(arg)
	if err != nil {
		return nil, err
	}
	return &Rows{Rows: r, Mapper: n.Stmt.Mapper}, err
}

// QueryRowx this NamedStmt.  Because of limitations with QueryRow, this is
// an alias for QueryRow.
func (n *NamedStmt) QueryRowx(arg interface{}) *Row {
	return n.QueryRow(arg)
}

// Select using this NamedStmt
func (n *NamedStmt) Select(dest interface{}, arg interface{}) error {
	rows, err := n.Query(arg)
	if err != nil {
		return err
	}
	// if something happens here, we want to make sure the rows are Closed
	defer rows.Close()
	return scanAll(rows, dest, false)
}

// Get using this NamedStmt
func (n *NamedStmt) Get(dest interface{}, arg interface{}) error {
	r := n.QueryRowx(arg)
	return r.scanAny(dest, false)
}

// A union interface of preparer and binder, required to be able to prepare
// named statements (as the bindtype must be determined).
type namedPreparer interface {
	Preparer
	binder
}

func prepareNamed(p namedPreparer, query string) (*NamedStmt, error) {
	bindType := BindType(p.DriverName())
	q, args, err := compileNamedQuery([]byte(query), bindType)
	if err != nil {
		return nil, err
	}
	stmt, err := Preparex(p, q)
	if err != nil {
		return nil, err
	}
	return &NamedStmt{
		QueryString: q,
		Params:      args,
		Stmt:        stmt,
	}, nil
}

func bindAnyArgs(names []string, arg interface{}, m *reflectx.Mapper) ([]interface{}, error) {
	if maparg, ok := arg.(map[string]interface{}); ok {
		return bindMapArgs(names, maparg)
	}
	return bindArgs(names, arg, m)
}

// private interface to generate a list of interfaces from a given struct
// type, given a list of names to pull out of the struct.  Used by public
// BindStruct interface.
func bindArgs(names []string, arg interface{}, m *reflectx.Mapper) ([]interface{}, error) {
	arglist := make([]interface{}, 0, len(names))

	// grab the indirected value of arg
	v := reflect.ValueOf(arg)
	for v = reflect.ValueOf(arg); v.Kind() == reflect.Ptr; {
		v = v.Elem()
	}

	fields := m.TraversalsByName(v.Type(), names)
	for i, t := range fields {
		if len(t) == 0 {
			return arglist, fmt.Errorf("could not find name %s in %#v", names[i], arg)
		}
		val := reflectx.FieldByIndexesReadOnly(v, t)
		arglist = append(arglist, val.Interface())
	}

	return arglist, nil
}

// like bindArgs, but for maps.
func bindMapArgs(names []string, arg map[string]interface{}) ([]interface{}, error) {
	arglist := make([]interface{}, 0, len(names))

	for _, name := range names {
		val, ok := arg[name]
		if !ok {
			return arglist, fmt.Errorf("could not find name %s in %#v", name, arg)
		}
		arglist = append(arglist, val)
	}
	return arglist, nil
}

// bindStruct binds a named parameter query with fields from a struct argument.
// The rules for binding field names to parameter names follow the same
// conventions as for StructScan, including obeying the `db` struct tags.
func bindStruct(bindType int, query string, arg interface{}, m *reflectx.Mapper) (string, []interface{}, error) {
	bound, names, err := compileNamedQuery([]byte(query), bindType)
	if err != nil {
		return "", []interface{}{}, err
	}

	arglist, err := bindArgs(names, arg, m)
	if err != nil {
		return "", []interface{}{}, err
	}

	return bound, arglist, nil
}

// bindMap binds a named parameter query with a map of arguments.
func bindMap(bindType int, query string, args map[string]interface{}) (string, []interface{}, error) {
	bound, names, err := compileNamedQuery([]byte(query), bindType)
	if err != nil {
		return "", []interface{}{}, err
	}

	arglist, err := bindMapArgs(names, args)
	return bound, arglist, err
}

// -- Compilation of Named Queries

// Allow digits and letters in bind params;  additionally runes are
// checked against underscores, meaning that bind params can have be
// alphanumeric with underscores.  Mind the difference between unicode
// digits and numbers, where '5' is a digit but '五' is not.
var allowedBindRunes = []*unicode.RangeTable{unicode.Letter, unicode.Digit}

// FIXME: this function isn't safe for unicode named params, as a failing test
// can testify.  This is not a regression but a failure of the original code
// as well.  It should be modified to range over runes in a string rather than
// bytes, even though this is less convenient and slower.  Hopefully the
// addition of the prepared NamedStmt (which will only do this once) will make
// up for the slightly slower ad-hoc NamedExec/NamedQuery.

// compile a NamedQuery into an unbound query (using the '?' bindvar) and
// a list of names.
func compileNamedQuery(qs []byte, bindType int) (query string, names []string, err error) {
	names = make([]string, 0, 10)
	rebound := make([]byte, 0, len(qs))

	inName := false
	last := len(qs) - 1
	currentVar := 1
	name := make([]byte, 0, 10)

	for i, b := range qs {
		// a ':' while we're in a name is an error
		if b == ':' {
			// if this is the second ':' in a '::' escape sequence, append a ':'
			if inName && i > 0 && qs[i-1] == ':' {
				rebound = append(rebound, ':')
				inName = false
				continue
			} else if inName {
				err = errors.New("unexpected `:` while reading named param at " + strconv.Itoa(i))
				return query, names, err
			}
			inName = true
			name = []byte{}
			// if we're in a name, and this is an allowed character, continue
		} else if inName && (unicode.IsOneOf(allowedBindRunes, rune(b)) || b == '_') && i != last {
			// append the byte to the name if we are in a name and not on the last byte
			name = append(name, b)
			// if we're in a name and it's not an allowed character, the name is done
		} else if inName {
			inName = false
			// if this is the final byte of the string and it is part of the name, then
			// make sure to add it to the name
			if i == last && unicode.IsOneOf(allowedBindRunes, rune(b)) {
				name = append(name, b)
			}
			// add the string representation to the names list
			names = append(names, string(name))
			// add a proper bindvar for the bindType
			switch bindType {
			// oracle only supports named type bind vars even for positional
			case NAMED:
				rebound = append(rebound, ':')
				rebound = append(rebound, name...)
			case QUESTION, UNKNOWN:
				rebound = append(rebound, '?')
			case DOLLAR:
				rebound = append(rebound, '$')
				for _, b := range strconv.Itoa(currentVar) {
					rebound = append(rebound, byte(b))
				}
				currentVar++
			}
			// add this byte to string unless it was not part of the name
			if i != last {
				rebound = append(rebound, b)
			} else if !unicode.IsOneOf(allowedBindRunes, rune(b)) {
				rebound = append(rebound, b)
			}
		} else {
			// this is a normal byte and should just go onto the rebound query
			rebound = append(rebound, b)
		}
	}

	return string(rebound), names, err
}

// BindNamed binds a struct or a map to a query with named parameters.
// DEPRECATED: use sqlx.Named` instead of this, it may be removed in future.
func BindNamed(bindType int, query string, arg interface{}) (string, []interface{}, error) {
	return bindNamedMapper(bindType, query, arg, mapper())
}

// Named takes a query using named parameters and an argument and
// returns a new query with a list of args that can be executed by
// a database.  The return value uses the `?` bindvar.
func Named(query string, arg interface{}) (string, []interface{}, error) {
	return bindNamedMapper(QUESTION, query, arg, mapper())
}

func bindNamedMapper(bindType int, query string, arg interface{}, m *reflectx.Mapper) (string, []interface{}, error) {
	if maparg, ok := arg.(map[string]interface{}); ok {
		return bindMap(bindType, query, maparg)
	}
	return bindStruct(bindType, query, arg, m)
}

// NamedQuery binds a named query and then runs Query on the result using the
// provided Ext (sqlx.Tx, sqlx.Db).  It works with both structs and with
// map[string]interface{} types.
func NamedQuery(e Ext, query string, arg interface{}) (*Rows, error) {
	q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e))
	if err != nil {
		return nil, err
	}
	return e.Queryx(q, args...)
}

// NamedExec uses BindStruct to get a query executable by the driver and
// then runs Exec on the result.  Returns an error from the binding
// or the query excution itself.
func NamedExec(e Ext, query string, arg interface{}) (sql.Result, error) {
	q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e))
	if err != nil {
		return nil, err
	}
	return e.Exec(q, args...)
}
<commit_msg>Add NamedStmt.Selectx<commit_after>package sqlx

// Named Query Support
//
//  * BindMap - bind query bindvars to map/struct args
//	* NamedExec, NamedQuery - named query w/ struct or map
//  * NamedStmt - a pre-compiled named query which is a prepared statement
//
// Internal Interfaces:
//
//  * compileNamedQuery - rebind a named query, returning a query and list of names
//  * bindArgs, bindMapArgs, bindAnyArgs - given a list of names, return an arglist
//
import (
	"database/sql"
	"errors"
	"fmt"
	"reflect"
	"strconv"
	"unicode"

	"github.com/jmoiron/sqlx/reflectx"
)

// NamedStmt is a prepared statement that executes named queries.  Prepare it
// how you would execute a NamedQuery, but pass in a struct or map when executing.
type NamedStmt struct {
	Params      []string
	QueryString string
	Stmt        *Stmt
}

// Close closes the named statement.
func (n *NamedStmt) Close() error {
	return n.Stmt.Close()
}

// Exec executes a named statement using the struct passed.
func (n *NamedStmt) Exec(arg interface{}) (sql.Result, error) {
	args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper)
	if err != nil {
		return *new(sql.Result), err
	}
	return n.Stmt.Exec(args...)
}

// Query executes a named statement using the struct argument, returning rows.
func (n *NamedStmt) Query(arg interface{}) (*sql.Rows, error) {
	args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper)
	if err != nil {
		return nil, err
	}
	return n.Stmt.Query(args...)
}

// QueryRow executes a named statement against the database.  Because sqlx cannot
// create a *sql.Row with an error condition pre-set for binding errors, sqlx
// returns a *sqlx.Row instead.
func (n *NamedStmt) QueryRow(arg interface{}) *Row {
	args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper)
	if err != nil {
		return &Row{err: err}
	}
	return n.Stmt.QueryRowx(args...)
}

// MustExec execs a NamedStmt, panicing on error
func (n *NamedStmt) MustExec(arg interface{}) sql.Result {
	res, err := n.Exec(arg)
	if err != nil {
		panic(err)
	}
	return res
}

// Queryx using this NamedStmt
func (n *NamedStmt) Queryx(arg interface{}) (*Rows, error) {
	r, err := n.Query(arg)
	if err != nil {
		return nil, err
	}
	return &Rows{Rows: r, Mapper: n.Stmt.Mapper}, err
}

// QueryRowx this NamedStmt.  Because of limitations with QueryRow, this is
// an alias for QueryRow.
func (n *NamedStmt) QueryRowx(arg interface{}) *Row {
	return n.QueryRow(arg)
}

// Select using this NamedStmt
func (n *NamedStmt) Select(dest interface{}, arg interface{}) error {
	rows, err := n.Query(arg)
	if err != nil {
		return err
	}
	// if something happens here, we want to make sure the rows are Closed
	defer rows.Close()
	return scanAll(rows, dest, false)
}

// Selectx using this NamedStmt
func (n *NamedStmt) Selectx(dest interface{}, arg interface{}) error {
	rows, err := n.Queryx(arg)
	if err != nil {
		return err
	}
	// if something happens here, we want to make sure the rows are Closed
	defer rows.Close()
	return scanAll(rows, dest, false)
}

// Get using this NamedStmt
func (n *NamedStmt) Get(dest interface{}, arg interface{}) error {
	r := n.QueryRowx(arg)
	return r.scanAny(dest, false)
}

// A union interface of preparer and binder, required to be able to prepare
// named statements (as the bindtype must be determined).
type namedPreparer interface {
	Preparer
	binder
}

func prepareNamed(p namedPreparer, query string) (*NamedStmt, error) {
	bindType := BindType(p.DriverName())
	q, args, err := compileNamedQuery([]byte(query), bindType)
	if err != nil {
		return nil, err
	}
	stmt, err := Preparex(p, q)
	if err != nil {
		return nil, err
	}
	return &NamedStmt{
		QueryString: q,
		Params:      args,
		Stmt:        stmt,
	}, nil
}

func bindAnyArgs(names []string, arg interface{}, m *reflectx.Mapper) ([]interface{}, error) {
	if maparg, ok := arg.(map[string]interface{}); ok {
		return bindMapArgs(names, maparg)
	}
	return bindArgs(names, arg, m)
}

// private interface to generate a list of interfaces from a given struct
// type, given a list of names to pull out of the struct.  Used by public
// BindStruct interface.
func bindArgs(names []string, arg interface{}, m *reflectx.Mapper) ([]interface{}, error) {
	arglist := make([]interface{}, 0, len(names))

	// grab the indirected value of arg
	v := reflect.ValueOf(arg)
	for v = reflect.ValueOf(arg); v.Kind() == reflect.Ptr; {
		v = v.Elem()
	}

	fields := m.TraversalsByName(v.Type(), names)
	for i, t := range fields {
		if len(t) == 0 {
			return arglist, fmt.Errorf("could not find name %s in %#v", names[i], arg)
		}
		val := reflectx.FieldByIndexesReadOnly(v, t)
		arglist = append(arglist, val.Interface())
	}

	return arglist, nil
}

// like bindArgs, but for maps.
func bindMapArgs(names []string, arg map[string]interface{}) ([]interface{}, error) {
	arglist := make([]interface{}, 0, len(names))

	for _, name := range names {
		val, ok := arg[name]
		if !ok {
			return arglist, fmt.Errorf("could not find name %s in %#v", name, arg)
		}
		arglist = append(arglist, val)
	}
	return arglist, nil
}

// bindStruct binds a named parameter query with fields from a struct argument.
// The rules for binding field names to parameter names follow the same
// conventions as for StructScan, including obeying the `db` struct tags.
func bindStruct(bindType int, query string, arg interface{}, m *reflectx.Mapper) (string, []interface{}, error) {
	bound, names, err := compileNamedQuery([]byte(query), bindType)
	if err != nil {
		return "", []interface{}{}, err
	}

	arglist, err := bindArgs(names, arg, m)
	if err != nil {
		return "", []interface{}{}, err
	}

	return bound, arglist, nil
}

// bindMap binds a named parameter query with a map of arguments.
func bindMap(bindType int, query string, args map[string]interface{}) (string, []interface{}, error) {
	bound, names, err := compileNamedQuery([]byte(query), bindType)
	if err != nil {
		return "", []interface{}{}, err
	}

	arglist, err := bindMapArgs(names, args)
	return bound, arglist, err
}

// -- Compilation of Named Queries

// Allow digits and letters in bind params;  additionally runes are
// checked against underscores, meaning that bind params can have be
// alphanumeric with underscores.  Mind the difference between unicode
// digits and numbers, where '5' is a digit but '五' is not.
var allowedBindRunes = []*unicode.RangeTable{unicode.Letter, unicode.Digit}

// FIXME: this function isn't safe for unicode named params, as a failing test
// can testify.  This is not a regression but a failure of the original code
// as well.  It should be modified to range over runes in a string rather than
// bytes, even though this is less convenient and slower.  Hopefully the
// addition of the prepared NamedStmt (which will only do this once) will make
// up for the slightly slower ad-hoc NamedExec/NamedQuery.

// compile a NamedQuery into an unbound query (using the '?' bindvar) and
// a list of names.
func compileNamedQuery(qs []byte, bindType int) (query string, names []string, err error) {
	names = make([]string, 0, 10)
	rebound := make([]byte, 0, len(qs))

	inName := false
	last := len(qs) - 1
	currentVar := 1
	name := make([]byte, 0, 10)

	for i, b := range qs {
		// a ':' while we're in a name is an error
		if b == ':' {
			// if this is the second ':' in a '::' escape sequence, append a ':'
			if inName && i > 0 && qs[i-1] == ':' {
				rebound = append(rebound, ':')
				inName = false
				continue
			} else if inName {
				err = errors.New("unexpected `:` while reading named param at " + strconv.Itoa(i))
				return query, names, err
			}
			inName = true
			name = []byte{}
			// if we're in a name, and this is an allowed character, continue
		} else if inName && (unicode.IsOneOf(allowedBindRunes, rune(b)) || b == '_') && i != last {
			// append the byte to the name if we are in a name and not on the last byte
			name = append(name, b)
			// if we're in a name and it's not an allowed character, the name is done
		} else if inName {
			inName = false
			// if this is the final byte of the string and it is part of the name, then
			// make sure to add it to the name
			if i == last && unicode.IsOneOf(allowedBindRunes, rune(b)) {
				name = append(name, b)
			}
			// add the string representation to the names list
			names = append(names, string(name))
			// add a proper bindvar for the bindType
			switch bindType {
			// oracle only supports named type bind vars even for positional
			case NAMED:
				rebound = append(rebound, ':')
				rebound = append(rebound, name...)
			case QUESTION, UNKNOWN:
				rebound = append(rebound, '?')
			case DOLLAR:
				rebound = append(rebound, '$')
				for _, b := range strconv.Itoa(currentVar) {
					rebound = append(rebound, byte(b))
				}
				currentVar++
			}
			// add this byte to string unless it was not part of the name
			if i != last {
				rebound = append(rebound, b)
			} else if !unicode.IsOneOf(allowedBindRunes, rune(b)) {
				rebound = append(rebound, b)
			}
		} else {
			// this is a normal byte and should just go onto the rebound query
			rebound = append(rebound, b)
		}
	}

	return string(rebound), names, err
}

// BindNamed binds a struct or a map to a query with named parameters.
// DEPRECATED: use sqlx.Named` instead of this, it may be removed in future.
func BindNamed(bindType int, query string, arg interface{}) (string, []interface{}, error) {
	return bindNamedMapper(bindType, query, arg, mapper())
}

// Named takes a query using named parameters and an argument and
// returns a new query with a list of args that can be executed by
// a database.  The return value uses the `?` bindvar.
func Named(query string, arg interface{}) (string, []interface{}, error) {
	return bindNamedMapper(QUESTION, query, arg, mapper())
}

func bindNamedMapper(bindType int, query string, arg interface{}, m *reflectx.Mapper) (string, []interface{}, error) {
	if maparg, ok := arg.(map[string]interface{}); ok {
		return bindMap(bindType, query, maparg)
	}
	return bindStruct(bindType, query, arg, m)
}

// NamedQuery binds a named query and then runs Query on the result using the
// provided Ext (sqlx.Tx, sqlx.Db).  It works with both structs and with
// map[string]interface{} types.
func NamedQuery(e Ext, query string, arg interface{}) (*Rows, error) {
	q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e))
	if err != nil {
		return nil, err
	}
	return e.Queryx(q, args...)
}

// NamedExec uses BindStruct to get a query executable by the driver and
// then runs Exec on the result.  Returns an error from the binding
// or the query excution itself.
func NamedExec(e Ext, query string, arg interface{}) (sql.Result, error) {
	q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e))
	if err != nil {
		return nil, err
	}
	return e.Exec(q, args...)
}
<|endoftext|>


<commit_before>package model

import "net/url"

type Tag struct {
	Name string
	Url  string
}

func NewTag(name string) Tag {
	return Tag{
		Name: name,
		Url:  "/tags/" + url.QueryEscape(name),
	}
}
<commit_msg>[model] fix tag url escaped<commit_after>package model

type Tag struct {
	Name string
	Url  string
}

func NewTag(name string) Tag {
	return Tag{
		Name: name,
		Url:  "/tags/" + name,
	}
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2019 the Octant contributors. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"sync"
	"time"
)

var (
	VERSION    = "v0.9.1"
	GOPATH     = os.Getenv("GOPATH")
	GIT_COMMIT = gitCommit()
	BUILD_TIME = time.Now().UTC().Format(time.RFC3339)
	LD_FLAGS   = fmt.Sprintf("-X \"main.buildTime=%s\" -X main.gitCommit=%s", BUILD_TIME, GIT_COMMIT)
	GO_FLAGS   = fmt.Sprintf("-ldflags=%s", LD_FLAGS)
)

func main() {
	flag.Parse()
	for _, cmd := range flag.Args() {
		switch cmd {
		case "ci":
			test()
			vet()
			webDeps()
			webTest()
			webBuild()
			build()
		case "ci-quick":
			webDeps()
			webBuild()
			build()
		case "web-deps":
			webDeps()
		case "web-test":
			webDeps()
			webTest()
		case "web-build":
			webDeps()
			webBuild()
		case "web":
			webDeps()
			webTest()
			webBuild()
		case "clean":
			clean()
		case "generate":
			generate()
		case "vet":
			vet()
		case "test":
			generate()
			test()
		case "build":
			build()
		case "run-dev":
			runDev()
		case "go-install":
			goInstall()
		case "serve":
			serve()
		case "install-test-plugin":
			installTestPlugin()
		case "version":
			version()
		case "release":
			release()
		case "docker":
			docker()
		default:
			log.Fatalf("Unknown command %q", cmd)
		}
	}
}

func runCmd(command string, env map[string]string, args ...string) {
	cmd := newCmd(command, env, args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	log.Printf("Running: %s\n", cmd.String())
	if err := cmd.Run(); err != nil {
		log.Fatal(err)
	}
}

func newCmd(command string, env map[string]string, args ...string) *exec.Cmd {
	realCommand, err := exec.LookPath(command)
	if err != nil {
		log.Fatalf("unable to find command '%s'", command)
	}

	cmd := exec.Command(realCommand, args...)
	cmd.Env = os.Environ()
	// Setting Stdout here complains about it already being set?
	// cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	for k, v := range env {
		cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", k, v))
	}
	return cmd
}

func goInstall() {
	pkgs := []string{
		"github.com/GeertJohan/go.rice",
		"github.com/GeertJohan/go.rice/rice",
		"github.com/golang/mock/gomock",
		"github.com/golang/mock/mockgen",
		"github.com/golang/protobuf/protoc-gen-go",
	}
	for _, pkg := range pkgs {
		runCmd("go", map[string]string{"GO11MODULE": "on"}, "install", pkg)
	}
}

func clean() {
	removeFakes()
	if err := os.Remove("pkg/icon/rice-box.go"); err != nil {
		log.Fatalf("clean: %s", err)
	}
}

func generate() {
	removeFakes()
	runCmd("go", nil, "generate", "-v", "./pkg/...", "./internal/...")
}

func build() {
	newpath := filepath.Join(".", "build")
	os.MkdirAll(newpath, 0755)
	runCmd("go", nil, "build", "-o", "build/octant", GO_FLAGS, "-v", "./cmd/octant")
}

func runDev() {
	runCmd("build/octant", nil, "--enable-feature-applications=true")
}

func test() {
	runCmd("go", nil, "test", "-v", "./internal/...", "./pkg/...")
}

func vet() {
	runCmd("go", nil, "vet", "./internal/...", "./pkg/...")
}

func webDeps() {
	cmd := newCmd("npm", nil, "ci")
	cmd.Stdout = os.Stdout
	cmd.Dir = "./web"
	if err := cmd.Run(); err != nil {
		log.Fatalf("web-deps: %s", err)
	}
}

func webTest() {
	cmd := newCmd("npm", nil, "run", "test:headless")
	cmd.Stdout = os.Stdout
	cmd.Dir = "./web"
	if err := cmd.Run(); err != nil {
		log.Fatalf("web-test: %s", err)
	}
}

func webBuild() {
	cmd := newCmd("npm", nil, "run", "build")
	cmd.Stdout = os.Stdout
	cmd.Dir = "./web"
	if err := cmd.Run(); err != nil {
		log.Fatalf("web-build: %s", err)
	}
	runCmd("go", nil, "generate", "./web")
}

func serve() {
	var wg sync.WaitGroup

	uiVars := map[string]string{"API_BASE": "http://localhost:7777"}
	uiCmd := newCmd("npm", uiVars, "run", "start")
	uiCmd.Stdout = os.Stdout
	uiCmd.Dir = "./web"
	if err := uiCmd.Start(); err != nil {
		log.Fatalf("uiCmd: start: %s", err)
	}

	wg.Add(1)
	go func() {
		defer wg.Done()
		if err := uiCmd.Wait(); err != nil {
			log.Fatalf("serve: npm run: %s", err)
		}
	}()

	serverVars := map[string]string{
		"OCTANT_DISABLE_OPEN_BROWSER": "true",
		"OCTANT_LISTENER_ADDR":        "localhost:7777",
		"OCTANT_PROXY_FRONTEND":       "http://localhost:4200",
	}
	serverCmd := newCmd("go", serverVars, "run", "./cmd/octant/main.go")
	serverCmd.Stdout = os.Stdout
	if err := serverCmd.Start(); err != nil {
		log.Fatalf("serveCmd: start: %s", err)
	}

	wg.Add(1)
	go func() {
		defer wg.Done()
		if err := serverCmd.Wait(); err != nil {
			log.Fatalf("serve: go run: %s", err)
		}
	}()

	wg.Wait()
}

func installTestPlugin() {
	dir := pluginDir()
	log.Printf("Plugin path: %s", dir)
	os.MkdirAll(dir, 0755)
	pluginFile := fmt.Sprintf("%s/octant-sample-plugin", dir)
	runCmd("go", nil, "build", "-o", pluginFile, "github.com/vmware-tanzu/octant/cmd/octant-sample-plugin")
}

func version() {
	fmt.Println(VERSION)
}

func release() {
	runCmd("git", nil, "tag", "-a", VERSION, "-m", fmt.Sprintf("\"Release %s\"", VERSION))
	runCmd("git", nil, "push", "--follow-tags")
}

func docker() {
	dockerVars := map[string]string{
		"CGO_ENABLED": "0",
		"GOOS":        "linux",
		"GOARCH":      "amd64",
	}
	runCmd("go", dockerVars, "build", "-o", "octant", GO_FLAGS, "-v", "./cmd/octant/main.go")
}

func removeFakes() {
	checkDirs := []string{"pkg", "internal"}
	fakePaths := []string{}

	for _, dir := range checkDirs {
		err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
			if !info.IsDir() {
				return nil
			}
			if info.Name() == "fake" {
				fakePaths = append(fakePaths, filepath.Join(path, info.Name()))
			}
			return nil
		})
		if err != nil {
			log.Fatalf("generate (%s): %s", dir, err)
		}
	}

	log.Print("Removing fakes from pkg/ and internal/")
	for _, p := range fakePaths {
		os.RemoveAll(p)
	}
}

func gitCommit() string {
	cmd := newCmd("git", nil, "rev-parse", "--short", "HEAD")
	out, err := cmd.Output()
	if err != nil {
		log.Printf("gitCommit: %s", err)
		return ""
	}
	return fmt.Sprintf("%s", out)
}

func pluginDir() string {
	xdgConfigHome := os.Getenv("XDG_CONFIG_HOME")
	if xdgConfigHome != "" {
		return filepath.Join(xdgConfigHome, "octant", "plugins")
	} else if runtime.GOOS == "windows" {
		return filepath.Join(os.Getenv("LOCALAPPDATA"), "octant", "plugins")
	} else {
		return filepath.Join(os.Getenv("HOME"), ".config", "octant", "plugins")
	}
}
<commit_msg>Do not remove fakes when running "build.go clean"<commit_after>/*
Copyright (c) 2019 the Octant contributors. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"sync"
	"time"
)

var (
	VERSION    = "v0.9.1"
	GOPATH     = os.Getenv("GOPATH")
	GIT_COMMIT = gitCommit()
	BUILD_TIME = time.Now().UTC().Format(time.RFC3339)
	LD_FLAGS   = fmt.Sprintf("-X \"main.buildTime=%s\" -X main.gitCommit=%s", BUILD_TIME, GIT_COMMIT)
	GO_FLAGS   = fmt.Sprintf("-ldflags=%s", LD_FLAGS)
)

func main() {
	flag.Parse()
	for _, cmd := range flag.Args() {
		switch cmd {
		case "ci":
			test()
			vet()
			webDeps()
			webTest()
			webBuild()
			build()
		case "ci-quick":
			webDeps()
			webBuild()
			build()
		case "web-deps":
			webDeps()
		case "web-test":
			webDeps()
			webTest()
		case "web-build":
			webDeps()
			webBuild()
		case "web":
			webDeps()
			webTest()
			webBuild()
		case "clean":
			clean()
		case "generate":
			generate()
		case "vet":
			vet()
		case "test":
			generate()
			test()
		case "build":
			build()
		case "run-dev":
			runDev()
		case "go-install":
			goInstall()
		case "serve":
			serve()
		case "install-test-plugin":
			installTestPlugin()
		case "version":
			version()
		case "release":
			release()
		case "docker":
			docker()
		default:
			log.Fatalf("Unknown command %q", cmd)
		}
	}
}

func runCmd(command string, env map[string]string, args ...string) {
	cmd := newCmd(command, env, args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	log.Printf("Running: %s\n", cmd.String())
	if err := cmd.Run(); err != nil {
		log.Fatal(err)
	}
}

func newCmd(command string, env map[string]string, args ...string) *exec.Cmd {
	realCommand, err := exec.LookPath(command)
	if err != nil {
		log.Fatalf("unable to find command '%s'", command)
	}

	cmd := exec.Command(realCommand, args...)
	cmd.Env = os.Environ()
	// Setting Stdout here complains about it already being set?
	// cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	for k, v := range env {
		cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", k, v))
	}
	return cmd
}

func goInstall() {
	pkgs := []string{
		"github.com/GeertJohan/go.rice",
		"github.com/GeertJohan/go.rice/rice",
		"github.com/golang/mock/gomock",
		"github.com/golang/mock/mockgen",
		"github.com/golang/protobuf/protoc-gen-go",
	}
	for _, pkg := range pkgs {
		runCmd("go", map[string]string{"GO11MODULE": "on"}, "install", pkg)
	}
}

func clean() {
	if err := os.Remove("pkg/icon/rice-box.go"); err != nil {
		log.Fatalf("clean: %s", err)
	}
}

func generate() {
	removeFakes()
	runCmd("go", nil, "generate", "-v", "./pkg/...", "./internal/...")
}

func build() {
	newpath := filepath.Join(".", "build")
	os.MkdirAll(newpath, 0755)
	runCmd("go", nil, "build", "-o", "build/octant", GO_FLAGS, "-v", "./cmd/octant")
}

func runDev() {
	runCmd("build/octant", nil, "--enable-feature-applications=true")
}

func test() {
	runCmd("go", nil, "test", "-v", "./internal/...", "./pkg/...")
}

func vet() {
	runCmd("go", nil, "vet", "./internal/...", "./pkg/...")
}

func webDeps() {
	cmd := newCmd("npm", nil, "ci")
	cmd.Stdout = os.Stdout
	cmd.Dir = "./web"
	if err := cmd.Run(); err != nil {
		log.Fatalf("web-deps: %s", err)
	}
}

func webTest() {
	cmd := newCmd("npm", nil, "run", "test:headless")
	cmd.Stdout = os.Stdout
	cmd.Dir = "./web"
	if err := cmd.Run(); err != nil {
		log.Fatalf("web-test: %s", err)
	}
}

func webBuild() {
	cmd := newCmd("npm", nil, "run", "build")
	cmd.Stdout = os.Stdout
	cmd.Dir = "./web"
	if err := cmd.Run(); err != nil {
		log.Fatalf("web-build: %s", err)
	}
	runCmd("go", nil, "generate", "./web")
}

func serve() {
	var wg sync.WaitGroup

	uiVars := map[string]string{"API_BASE": "http://localhost:7777"}
	uiCmd := newCmd("npm", uiVars, "run", "start")
	uiCmd.Stdout = os.Stdout
	uiCmd.Dir = "./web"
	if err := uiCmd.Start(); err != nil {
		log.Fatalf("uiCmd: start: %s", err)
	}

	wg.Add(1)
	go func() {
		defer wg.Done()
		if err := uiCmd.Wait(); err != nil {
			log.Fatalf("serve: npm run: %s", err)
		}
	}()

	serverVars := map[string]string{
		"OCTANT_DISABLE_OPEN_BROWSER": "true",
		"OCTANT_LISTENER_ADDR":        "localhost:7777",
		"OCTANT_PROXY_FRONTEND":       "http://localhost:4200",
	}
	serverCmd := newCmd("go", serverVars, "run", "./cmd/octant/main.go")
	serverCmd.Stdout = os.Stdout
	if err := serverCmd.Start(); err != nil {
		log.Fatalf("serveCmd: start: %s", err)
	}

	wg.Add(1)
	go func() {
		defer wg.Done()
		if err := serverCmd.Wait(); err != nil {
			log.Fatalf("serve: go run: %s", err)
		}
	}()

	wg.Wait()
}

func installTestPlugin() {
	dir := pluginDir()
	log.Printf("Plugin path: %s", dir)
	os.MkdirAll(dir, 0755)
	pluginFile := fmt.Sprintf("%s/octant-sample-plugin", dir)
	runCmd("go", nil, "build", "-o", pluginFile, "github.com/vmware-tanzu/octant/cmd/octant-sample-plugin")
}

func version() {
	fmt.Println(VERSION)
}

func release() {
	runCmd("git", nil, "tag", "-a", VERSION, "-m", fmt.Sprintf("\"Release %s\"", VERSION))
	runCmd("git", nil, "push", "--follow-tags")
}

func docker() {
	dockerVars := map[string]string{
		"CGO_ENABLED": "0",
		"GOOS":        "linux",
		"GOARCH":      "amd64",
	}
	runCmd("go", dockerVars, "build", "-o", "octant", GO_FLAGS, "-v", "./cmd/octant/main.go")
}

func removeFakes() {
	checkDirs := []string{"pkg", "internal"}
	fakePaths := []string{}

	for _, dir := range checkDirs {
		err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
			if !info.IsDir() {
				return nil
			}
			if info.Name() == "fake" {
				fakePaths = append(fakePaths, filepath.Join(path, info.Name()))
			}
			return nil
		})
		if err != nil {
			log.Fatalf("generate (%s): %s", dir, err)
		}
	}

	log.Print("Removing fakes from pkg/ and internal/")
	for _, p := range fakePaths {
		os.RemoveAll(p)
	}
}

func gitCommit() string {
	cmd := newCmd("git", nil, "rev-parse", "--short", "HEAD")
	out, err := cmd.Output()
	if err != nil {
		log.Printf("gitCommit: %s", err)
		return ""
	}
	return fmt.Sprintf("%s", out)
}

func pluginDir() string {
	xdgConfigHome := os.Getenv("XDG_CONFIG_HOME")
	if xdgConfigHome != "" {
		return filepath.Join(xdgConfigHome, "octant", "plugins")
	} else if runtime.GOOS == "windows" {
		return filepath.Join(os.Getenv("LOCALAPPDATA"), "octant", "plugins")
	} else {
		return filepath.Join(os.Getenv("HOME"), ".config", "octant", "plugins")
	}
}
<|endoftext|>


<commit_before>// +build ignore

package main

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

var (
	verbose    bool
	keepGopath bool
	runTests   bool
	enableCGO  bool
)

var config = struct {
	Name      string
	Namespace string
	Main      string
	Tests     []string
}{
	Name:      "restic",                           // name of the program executable and directory
	Namespace: "",                                 // subdir of GOPATH, e.g. "github.com/foo/bar"
	Main:      "cmds/restic",                      // package name for the main package
	Tests:     []string{"restic/...", "cmds/..."}, // tests to run
}

// specialDir returns true if the file begins with a special character ('.' or '_').
func specialDir(name string) bool {
	if name == "." {
		return false
	}

	base := filepath.Base(name)
	if base == "vendor" || base[0] == '_' || base[0] == '.' {
		return true
	}

	return false
}

// excludePath returns true if the file should not be copied to the new GOPATH.
func excludePath(name string) bool {
	ext := path.Ext(name)
	if ext == ".go" || ext == ".s" || ext == ".h" {
		return false
	}

	parentDir := filepath.Base(filepath.Dir(name))
	if parentDir == "testdata" {
		return false
	}

	return true
}

// updateGopath builds a valid GOPATH at dst, with all Go files in src/ copied
// to dst/prefix/, so calling
//
//   updateGopath("/tmp/gopath", "/home/u/restic", "github.com/restic/restic")
//
// with "/home/u/restic" containing the file "foo.go" yields the following tree
// at "/tmp/gopath":
//
//   /tmp/gopath
//   └── src
//       └── github.com
//           └── restic
//               └── restic
//                   └── foo.go
func updateGopath(dst, src, prefix string) error {
	return filepath.Walk(src, func(name string, fi os.FileInfo, err error) error {
		if specialDir(name) {
			if fi.IsDir() {
				return filepath.SkipDir
			}

			return nil
		}

		if fi.IsDir() {
			return nil
		}

		if excludePath(name) {
			return nil
		}

		intermediatePath, err := filepath.Rel(src, name)
		if err != nil {
			return err
		}

		fileSrc := filepath.Join(src, intermediatePath)
		fileDst := filepath.Join(dst, "src", prefix, intermediatePath)

		return copyFile(fileDst, fileSrc)
	})
}

func directoryExists(dirname string) bool {
	stat, err := os.Stat(dirname)
	if err != nil && os.IsNotExist(err) {
		return false
	}

	return stat.IsDir()
}

// copyFile creates dst from src, preserving file attributes and timestamps.
func copyFile(dst, src string) error {
	fi, err := os.Stat(src)
	if err != nil {
		return err
	}

	fsrc, err := os.Open(src)
	if err != nil {
		return err
	}
	defer fsrc.Close()

	if err = os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
		fmt.Printf("MkdirAll(%v)\n", filepath.Dir(dst))
		return err
	}

	fdst, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer fdst.Close()

	_, err = io.Copy(fdst, fsrc)
	if err == nil {
		err = os.Chmod(dst, fi.Mode())
	}
	if err == nil {
		err = os.Chtimes(dst, fi.ModTime(), fi.ModTime())
	}

	return err
}

// die prints the message with fmt.Fprintf() to stderr and exits with an error
// code.
func die(message string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, message, args...)
	os.Exit(1)
}

func showUsage(output io.Writer) {
	fmt.Fprintf(output, "USAGE: go run build.go OPTIONS\n")
	fmt.Fprintf(output, "\n")
	fmt.Fprintf(output, "OPTIONS:\n")
	fmt.Fprintf(output, "  -v     --verbose       output more messages\n")
	fmt.Fprintf(output, "  -t     --tags          specify additional build tags\n")
	fmt.Fprintf(output, "  -k     --keep-gopath   do not remove the GOPATH after build\n")
	fmt.Fprintf(output, "  -T     --test          run tests\n")
	fmt.Fprintf(output, "  -o     --output        set output file name\n")
	fmt.Fprintf(output, "         --enable-cgo    use CGO to link against libc\n")
	fmt.Fprintf(output, "         --goos value    set GOOS for cross-compilation\n")
	fmt.Fprintf(output, "         --goarch value  set GOARCH for cross-compilation\n")
}

func verbosePrintf(message string, args ...interface{}) {
	if !verbose {
		return
	}

	fmt.Printf("build: "+message, args...)
}

// cleanEnv returns a clean environment with GOPATH and GOBIN removed (if
// present).
func cleanEnv() (env []string) {
	for _, v := range os.Environ() {
		if strings.HasPrefix(v, "GOPATH=") || strings.HasPrefix(v, "GOBIN=") {
			continue
		}

		env = append(env, v)
	}

	return env
}

// build runs "go build args..." with GOPATH set to gopath.
func build(cwd, goos, goarch, gopath string, args ...string) error {
	a := []string{"build"}
	a = append(a, "-asmflags", fmt.Sprintf("-trimpath=%s", gopath))
	a = append(a, "-gcflags", fmt.Sprintf("-trimpath=%s", gopath))
	a = append(a, args...)
	cmd := exec.Command("go", a...)
	cmd.Env = append(cleanEnv(), "GOPATH="+gopath, "GOARCH="+goarch, "GOOS="+goos)
	if !enableCGO {
		cmd.Env = append(cmd.Env, "CGO_ENABLED=0")
	}

	cmd.Dir = cwd
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	verbosePrintf("go %s\n", args)

	return cmd.Run()
}

// test runs "go test args..." with GOPATH set to gopath.
func test(cwd, gopath string, args ...string) error {
	args = append([]string{"test"}, args...)
	cmd := exec.Command("go", args...)
	cmd.Env = append(cleanEnv(), "GOPATH="+gopath)
	cmd.Dir = cwd
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	verbosePrintf("go %s\n", args)

	return cmd.Run()
}

// getVersion returns the version string from the file VERSION in the current
// directory.
func getVersionFromFile() string {
	buf, err := ioutil.ReadFile("VERSION")
	if err != nil {
		verbosePrintf("error reading file VERSION: %v\n", err)
		return ""
	}

	return strings.TrimSpace(string(buf))
}

// getVersion returns a version string which is a combination of the contents
// of the file VERSION in the current directory and the version from git (if
// available).
func getVersion() string {
	versionFile := getVersionFromFile()
	versionGit := getVersionFromGit()

	verbosePrintf("version from file 'VERSION' is %q, version from git %q\n",
		versionFile, versionGit)

	switch {
	case versionFile == "":
		return versionGit
	case versionGit == "":
		return versionFile
	}

	return fmt.Sprintf("%s (%s)", versionFile, versionGit)
}

// getVersionFromGit returns a version string that identifies the currently
// checked out git commit.
func getVersionFromGit() string {
	cmd := exec.Command("git", "describe",
		"--long", "--tags", "--dirty", "--always")
	out, err := cmd.Output()
	if err != nil {
		verbosePrintf("git describe returned error: %v\n", err)
		return ""
	}

	version := strings.TrimSpace(string(out))
	verbosePrintf("git version is %s\n", version)
	return version
}

// Constants represents a set of constants that are set in the final binary to
// the given value via compiler flags.
type Constants map[string]string

// LDFlags returns the string that can be passed to go build's `-ldflags`.
func (cs Constants) LDFlags() string {
	l := make([]string, 0, len(cs))

	for k, v := range cs {
		l = append(l, fmt.Sprintf(`-X "%s=%s"`, k, v))
	}

	return strings.Join(l, " ")
}

func main() {
	ver := runtime.Version()
	if strings.HasPrefix(ver, "go1") && ver < "go1.7" {
		fmt.Fprintf(os.Stderr, "Go version %s detected, restic requires at least Go 1.7\n", ver)
		os.Exit(1)
	}

	buildTags := []string{}

	skipNext := false
	params := os.Args[1:]

	targetGOOS := runtime.GOOS
	targetGOARCH := runtime.GOARCH

	var outputFilename string

	for i, arg := range params {
		if skipNext {
			skipNext = false
			continue
		}

		switch arg {
		case "-v", "--verbose":
			verbose = true
		case "-k", "--keep-gopath":
			keepGopath = true
		case "-t", "-tags", "--tags":
			if i+1 >= len(params) {
				die("-t given but no tag specified")
			}
			skipNext = true
			buildTags = strings.Split(params[i+1], " ")
		case "-o", "--output":
			skipNext = true
			outputFilename = params[i+1]
		case "-T", "--test":
			runTests = true
		case "--enable-cgo":
			enableCGO = true
		case "--goos":
			skipNext = true
			targetGOOS = params[i+1]
		case "--goarch":
			skipNext = true
			targetGOARCH = params[i+1]
		case "-h":
			showUsage(os.Stdout)
			return
		default:
			fmt.Fprintf(os.Stderr, "Error: unknown option %q\n\n", arg)
			showUsage(os.Stderr)
			os.Exit(1)
		}
	}

	if len(buildTags) == 0 {
		verbosePrintf("adding build-tag release\n")
		buildTags = []string{"release"}
	}

	for i := range buildTags {
		buildTags[i] = strings.TrimSpace(buildTags[i])
	}

	verbosePrintf("build tags: %s\n", buildTags)

	root, err := os.Getwd()
	if err != nil {
		die("Getwd(): %v\n", err)
	}

	gopath, err := ioutil.TempDir("", fmt.Sprintf("%v-build-", config.Name))
	if err != nil {
		die("TempDir(): %v\n", err)
	}

	verbosePrintf("create GOPATH at %v\n", gopath)
	if err = updateGopath(gopath, filepath.Join(root, "src"), config.Namespace); err != nil {
		die("copying files from %v/src to %v/src failed: %v\n", root, gopath, err)
	}

	vendor := filepath.Join(root, "vendor", "src")
	if directoryExists(vendor) {
		if err = updateGopath(gopath, vendor, ""); err != nil {
			die("copying files from %v to %v failed: %v\n", root, gopath, err)
		}
	}

	defer func() {
		if !keepGopath {
			verbosePrintf("remove %v\n", gopath)
			if err = os.RemoveAll(gopath); err != nil {
				die("remove GOPATH at %s failed: %v\n", err)
			}
		} else {
			verbosePrintf("leaving temporary GOPATH at %v\n", gopath)
		}
	}()

	if outputFilename == "" {
		outputFilename = config.Name
		if targetGOOS == "windows" {
			outputFilename += ".exe"
		}
	}

	cwd, err := os.Getwd()
	if err != nil {
		die("Getwd() returned %v\n", err)
	}
	output := outputFilename
	if !filepath.IsAbs(output) {
		output = filepath.Join(cwd, output)
	}

	version := getVersion()
	constants := Constants{}
	if version != "" {
		constants["main.version"] = version
	}
	ldflags := "-s -w " + constants.LDFlags()
	verbosePrintf("ldflags: %s\n", ldflags)

	args := []string{
		"-tags", strings.Join(buildTags, " "),
		"-ldflags", ldflags,
		"-o", output, config.Main,
	}

	err = build(filepath.Join(gopath, "src"), targetGOOS, targetGOARCH, gopath, args...)
	if err != nil {
		die("build failed: %v\n", err)
	}

	if runTests {
		verbosePrintf("running tests\n")

		err = test(cwd, gopath, config.Tests...)
		if err != nil {
			die("running tests failed: %v\n", err)
		}
	}
}
<commit_msg>Update build.go<commit_after>// +build ignore

package main

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

var (
	verbose    bool
	keepGopath bool
	runTests   bool
	enableCGO  bool
)

var config = struct {
	Name      string
	Namespace string
	Main      string
	Tests     []string
}{
	Name:      "restic",                              // name of the program executable and directory
	Namespace: "github.com/restic/restic",            // subdir of GOPATH, e.g. "github.com/foo/bar"
	Main:      "github.com/restic/restic/cmd/restic", // package name for the main package
	Tests:     []string{"internal/...", "cmd/..."},   // tests to run
}

// specialDir returns true if the file begins with a special character ('.' or '_').
func specialDir(name string) bool {
	if name == "." {
		return false
	}

	base := filepath.Base(name)
	if base == "vendor" || base[0] == '_' || base[0] == '.' {
		return true
	}

	return false
}

// excludePath returns true if the file should not be copied to the new GOPATH.
func excludePath(name string) bool {
	ext := path.Ext(name)
	if ext == ".go" || ext == ".s" || ext == ".h" {
		return false
	}

	parentDir := filepath.Base(filepath.Dir(name))
	if parentDir == "testdata" {
		return false
	}

	return true
}

// updateGopath builds a valid GOPATH at dst, with all Go files in src/ copied
// to dst/prefix/, so calling
//
//   updateGopath("/tmp/gopath", "/home/u/restic", "github.com/restic/restic")
//
// with "/home/u/restic" containing the file "foo.go" yields the following tree
// at "/tmp/gopath":
//
//   /tmp/gopath
//   └── src
//       └── github.com
//           └── restic
//               └── restic
//                   └── foo.go
func updateGopath(dst, src, prefix string) error {
	verbosePrintf("copy contents of %v to %v\n", src, filepath.Join(dst, prefix))
	return filepath.Walk(src, func(name string, fi os.FileInfo, err error) error {
		if name == src {
			return err
		}

		if specialDir(name) {
			if fi.IsDir() {
				return filepath.SkipDir
			}

			return nil
		}

		if err != nil {
			return err
		}

		if fi.IsDir() {
			return nil
		}

		if excludePath(name) {
			return nil
		}

		intermediatePath, err := filepath.Rel(src, name)
		if err != nil {
			return err
		}

		fileSrc := filepath.Join(src, intermediatePath)
		fileDst := filepath.Join(dst, "src", prefix, intermediatePath)

		return copyFile(fileDst, fileSrc)
	})
}

func directoryExists(dirname string) bool {
	stat, err := os.Stat(dirname)
	if err != nil && os.IsNotExist(err) {
		return false
	}

	return stat.IsDir()
}

// copyFile creates dst from src, preserving file attributes and timestamps.
func copyFile(dst, src string) error {
	fi, err := os.Stat(src)
	if err != nil {
		return err
	}

	fsrc, err := os.Open(src)
	if err != nil {
		return err
	}
	defer fsrc.Close()

	if err = os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
		fmt.Printf("MkdirAll(%v)\n", filepath.Dir(dst))
		return err
	}

	fdst, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer fdst.Close()

	_, err = io.Copy(fdst, fsrc)
	if err == nil {
		err = os.Chmod(dst, fi.Mode())
	}
	if err == nil {
		err = os.Chtimes(dst, fi.ModTime(), fi.ModTime())
	}

	return err
}

// die prints the message with fmt.Fprintf() to stderr and exits with an error
// code.
func die(message string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, message, args...)
	os.Exit(1)
}

func showUsage(output io.Writer) {
	fmt.Fprintf(output, "USAGE: go run build.go OPTIONS\n")
	fmt.Fprintf(output, "\n")
	fmt.Fprintf(output, "OPTIONS:\n")
	fmt.Fprintf(output, "  -v     --verbose       output more messages\n")
	fmt.Fprintf(output, "  -t     --tags          specify additional build tags\n")
	fmt.Fprintf(output, "  -k     --keep-gopath   do not remove the GOPATH after build\n")
	fmt.Fprintf(output, "  -T     --test          run tests\n")
	fmt.Fprintf(output, "  -o     --output        set output file name\n")
	fmt.Fprintf(output, "         --enable-cgo    use CGO to link against libc\n")
	fmt.Fprintf(output, "         --goos value    set GOOS for cross-compilation\n")
	fmt.Fprintf(output, "         --goarch value  set GOARCH for cross-compilation\n")
}

func verbosePrintf(message string, args ...interface{}) {
	if !verbose {
		return
	}

	fmt.Printf("build: "+message, args...)
}

// cleanEnv returns a clean environment with GOPATH and GOBIN removed (if
// present).
func cleanEnv() (env []string) {
	for _, v := range os.Environ() {
		if strings.HasPrefix(v, "GOPATH=") || strings.HasPrefix(v, "GOBIN=") {
			continue
		}

		env = append(env, v)
	}

	return env
}

// build runs "go build args..." with GOPATH set to gopath.
func build(cwd, goos, goarch, gopath string, args ...string) error {
	a := []string{"build"}
	a = append(a, "-asmflags", fmt.Sprintf("-trimpath=%s", gopath))
	a = append(a, "-gcflags", fmt.Sprintf("-trimpath=%s", gopath))
	a = append(a, args...)
	cmd := exec.Command("go", a...)
	cmd.Env = append(cleanEnv(), "GOPATH="+gopath, "GOARCH="+goarch, "GOOS="+goos)
	if !enableCGO {
		cmd.Env = append(cmd.Env, "CGO_ENABLED=0")
	}

	cmd.Dir = cwd
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	verbosePrintf("go %s\n", args)

	return cmd.Run()
}

// test runs "go test args..." with GOPATH set to gopath.
func test(cwd, gopath string, args ...string) error {
	args = append([]string{"test"}, args...)
	cmd := exec.Command("go", args...)
	cmd.Env = append(cleanEnv(), "GOPATH="+gopath)
	cmd.Dir = cwd
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	verbosePrintf("go %s\n", args)

	return cmd.Run()
}

// getVersion returns the version string from the file VERSION in the current
// directory.
func getVersionFromFile() string {
	buf, err := ioutil.ReadFile("VERSION")
	if err != nil {
		verbosePrintf("error reading file VERSION: %v\n", err)
		return ""
	}

	return strings.TrimSpace(string(buf))
}

// getVersion returns a version string which is a combination of the contents
// of the file VERSION in the current directory and the version from git (if
// available).
func getVersion() string {
	versionFile := getVersionFromFile()
	versionGit := getVersionFromGit()

	verbosePrintf("version from file 'VERSION' is %q, version from git %q\n",
		versionFile, versionGit)

	switch {
	case versionFile == "":
		return versionGit
	case versionGit == "":
		return versionFile
	}

	return fmt.Sprintf("%s (%s)", versionFile, versionGit)
}

// getVersionFromGit returns a version string that identifies the currently
// checked out git commit.
func getVersionFromGit() string {
	cmd := exec.Command("git", "describe",
		"--long", "--tags", "--dirty", "--always")
	out, err := cmd.Output()
	if err != nil {
		verbosePrintf("git describe returned error: %v\n", err)
		return ""
	}

	version := strings.TrimSpace(string(out))
	verbosePrintf("git version is %s\n", version)
	return version
}

// Constants represents a set of constants that are set in the final binary to
// the given value via compiler flags.
type Constants map[string]string

// LDFlags returns the string that can be passed to go build's `-ldflags`.
func (cs Constants) LDFlags() string {
	l := make([]string, 0, len(cs))

	for k, v := range cs {
		l = append(l, fmt.Sprintf(`-X "%s=%s"`, k, v))
	}

	return strings.Join(l, " ")
}

func main() {
	ver := runtime.Version()
	if strings.HasPrefix(ver, "go1") && ver < "go1.7" {
		fmt.Fprintf(os.Stderr, "Go version %s detected, restic requires at least Go 1.7\n", ver)
		os.Exit(1)
	}

	buildTags := []string{}

	skipNext := false
	params := os.Args[1:]

	targetGOOS := runtime.GOOS
	targetGOARCH := runtime.GOARCH

	var outputFilename string

	for i, arg := range params {
		if skipNext {
			skipNext = false
			continue
		}

		switch arg {
		case "-v", "--verbose":
			verbose = true
		case "-k", "--keep-gopath":
			keepGopath = true
		case "-t", "-tags", "--tags":
			if i+1 >= len(params) {
				die("-t given but no tag specified")
			}
			skipNext = true
			buildTags = strings.Split(params[i+1], " ")
		case "-o", "--output":
			skipNext = true
			outputFilename = params[i+1]
		case "-T", "--test":
			runTests = true
		case "--enable-cgo":
			enableCGO = true
		case "--goos":
			skipNext = true
			targetGOOS = params[i+1]
		case "--goarch":
			skipNext = true
			targetGOARCH = params[i+1]
		case "-h":
			showUsage(os.Stdout)
			return
		default:
			fmt.Fprintf(os.Stderr, "Error: unknown option %q\n\n", arg)
			showUsage(os.Stderr)
			os.Exit(1)
		}
	}

	if len(buildTags) == 0 {
		verbosePrintf("adding build-tag release\n")
		buildTags = []string{"release"}
	}

	for i := range buildTags {
		buildTags[i] = strings.TrimSpace(buildTags[i])
	}

	verbosePrintf("build tags: %s\n", buildTags)

	root, err := os.Getwd()
	if err != nil {
		die("Getwd(): %v\n", err)
	}

	gopath, err := ioutil.TempDir("", fmt.Sprintf("%v-build-", config.Name))
	if err != nil {
		die("TempDir(): %v\n", err)
	}

	verbosePrintf("create GOPATH at %v\n", gopath)
	if err = updateGopath(gopath, root, config.Namespace); err != nil {
		die("copying files from %v/src to %v/src failed: %v\n", root, gopath, err)
	}

	vendor := filepath.Join(root, "vendor")
	if directoryExists(vendor) {
		if err = updateGopath(gopath, vendor, filepath.Join(config.Namespace, "vendor")); err != nil {
			die("copying files from %v to %v failed: %v\n", root, gopath, err)
		}
	}

	defer func() {
		if !keepGopath {
			verbosePrintf("remove %v\n", gopath)
			if err = os.RemoveAll(gopath); err != nil {
				die("remove GOPATH at %s failed: %v\n", err)
			}
		} else {
			verbosePrintf("leaving temporary GOPATH at %v\n", gopath)
		}
	}()

	if outputFilename == "" {
		outputFilename = config.Name
		if targetGOOS == "windows" {
			outputFilename += ".exe"
		}
	}

	cwd, err := os.Getwd()
	if err != nil {
		die("Getwd() returned %v\n", err)
	}
	output := outputFilename
	if !filepath.IsAbs(output) {
		output = filepath.Join(cwd, output)
	}

	version := getVersion()
	constants := Constants{}
	if version != "" {
		constants["main.version"] = version
	}
	ldflags := "-s -w " + constants.LDFlags()
	verbosePrintf("ldflags: %s\n", ldflags)

	args := []string{
		"-tags", strings.Join(buildTags, " "),
		"-ldflags", ldflags,
		"-o", output, config.Main,
	}

	err = build(filepath.Join(gopath, "src"), targetGOOS, targetGOARCH, gopath, args...)
	if err != nil {
		die("build failed: %v\n", err)
	}

	if runTests {
		verbosePrintf("running tests\n")

		err = test(cwd, gopath, config.Tests...)
		if err != nil {
			die("running tests failed: %v\n", err)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 siv

// Given strings A and B with len(A) >= len(B), xor B onto the right end of A.
// This matches the xorend operator of RFC 5297.
func xorend(a, b []byte) []byte {
	return nil
}
<commit_msg>Implemented xorend.<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 siv

import (
	"github.com/jacobsa/aes/common"
)

// Given strings A and B with len(A) >= len(B), xor B onto the right end of A.
// This matches the xorend operator of RFC 5297.
func xorend(a, b []byte) []byte {
	aLen := len(a)
	bLen := len(b)

	if aLen < bLen {
		panic("Invalid lengths.")
	}

	difference := aLen - bLen
	return append(a[:difference], common.Xor(a[difference:], b)...)
}
<|endoftext|>


<commit_before>package gocb

import (
	"fmt"
)

// CouchbaseList represents a list document.
type CouchbaseList struct {
	collection *Collection
	id         string
}

// List returns a new CouchbaseList for the document specified by id.
func (c *Collection) List(id string) *CouchbaseList {
	return &CouchbaseList{
		collection: c,
		id:         id,
	}
}

// Iterator returns an iterable for all items in the list.
func (cl *CouchbaseList) Iterator() ([]interface{}, error) {
	content, err := cl.collection.Get(cl.id, nil)
	if err != nil {
		return nil, err
	}

	var listContents []interface{}
	err = content.Content(&listContents)
	if err != nil {
		return nil, err
	}

	return listContents, nil
}

// At retrieves the value specified at the given index from the list.
func (cl *CouchbaseList) At(index int, valuePtr interface{}) error {
	ops := make([]LookupInSpec, 1)
	ops[0] = GetSpec(fmt.Sprintf("[%d]", index), nil)
	result, err := cl.collection.LookupIn(cl.id, ops, nil)
	if err != nil {
		return err
	}

	return result.ContentAt(0, valuePtr)
}

// RemoveAt removes the value specified at the given index from the list.
func (cl *CouchbaseList) RemoveAt(index int) error {
	ops := make([]MutateInSpec, 1)
	ops[0] = RemoveSpec(fmt.Sprintf("[%d]", index), nil)
	_, err := cl.collection.MutateIn(cl.id, ops, nil)
	if err != nil {
		return err
	}

	return nil
}

// Append appends an item to the list.
func (cl *CouchbaseList) Append(val interface{}) error {
	ops := make([]MutateInSpec, 1)
	ops[0] = ArrayAppendSpec("", val, nil)
	_, err := cl.collection.MutateIn(cl.id, ops, &MutateInOptions{UpsertDocument: true})
	if err != nil {
		return err
	}

	return nil
}

// Prepend prepends an item to the list.
func (cl *CouchbaseList) Prepend(val interface{}) error {
	ops := make([]MutateInSpec, 1)
	ops[0] = ArrayPrependSpec("", val, nil)
	_, err := cl.collection.MutateIn(cl.id, ops, &MutateInOptions{UpsertDocument: true})
	if err != nil {
		return err
	}

	return nil
}

// IndexOf gets the index of the item in the list.
func (cl *CouchbaseList) IndexOf(val interface{}) (int, error) {
	content, err := cl.collection.Get(cl.id, nil)
	if err != nil {
		return 0, err
	}

	var listContents []interface{}
	err = content.Content(&listContents)
	if err != nil {
		return 0, err
	}

	for i, item := range listContents {
		if item == val {
			return i, nil
		}
	}

	return -1, nil
}

// Size returns the size of the list.
func (cl *CouchbaseList) Size() (int, error) {
	ops := make([]LookupInSpec, 1)
	ops[0] = CountSpec("", nil)
	result, err := cl.collection.LookupIn(cl.id, ops, nil)
	if err != nil {
		return 0, err
	}

	var count int
	err = result.ContentAt(0, &count)
	if err != nil {
		return 0, err
	}

	return count, nil
}

// Clear clears a list, also removing it.
func (cl *CouchbaseList) Clear() error {
	_, err := cl.collection.Remove(cl.id, nil)
	if err != nil {
		return err
	}

	return nil
}

// CouchbaseMap represents a map document.
type CouchbaseMap struct {
	collection *Collection
	id         string
}

// Map returns a new CouchbaseMap.
func (c *Collection) Map(id string) *CouchbaseMap {
	return &CouchbaseMap{
		collection: c,
		id:         id,
	}
}

// Iterator returns an iterable for all items in the map.
func (cl *CouchbaseMap) Iterator() (map[string]interface{}, error) {
	content, err := cl.collection.Get(cl.id, nil)
	if err != nil {
		return nil, err
	}

	var mapContents map[string]interface{}
	err = content.Content(&mapContents)
	if err != nil {
		return nil, err
	}

	return mapContents, nil
}

// At retrieves the item for the given id from the map.
func (cl *CouchbaseMap) At(id string, valuePtr interface{}) error {
	ops := make([]LookupInSpec, 1)
	ops[0] = GetSpec(fmt.Sprintf("[%s]", id), nil)
	result, err := cl.collection.LookupIn(cl.id, ops, nil)
	if err != nil {
		return err
	}

	return result.ContentAt(0, valuePtr)
}

// Add adds an item to the map.
func (cl *CouchbaseMap) Add(id string, val interface{}) error {
	ops := make([]MutateInSpec, 1)
	ops[0] = UpsertSpec(id, val, nil)
	_, err := cl.collection.MutateIn(cl.id, ops, &MutateInOptions{UpsertDocument: true})
	if err != nil {
		return err
	}

	return nil
}

// Remove removes an item from the map.
func (cl *CouchbaseMap) Remove(id string) error {
	ops := make([]MutateInSpec, 1)
	ops[0] = RemoveSpec(id, nil)
	_, err := cl.collection.MutateIn(cl.id, ops, nil)
	if err != nil {
		return err
	}

	return nil
}

// Exists verifies whether or a id exists in the map.
func (cl *CouchbaseMap) Exists(id string) (bool, error) {
	ops := make([]LookupInSpec, 1)
	ops[0] = ExistsSpec(fmt.Sprintf("[%s]", id), nil)
	result, err := cl.collection.LookupIn(cl.id, ops, nil)
	if err != nil {
		return false, err
	}

	return result.Exists(0), nil
}

// Size returns the size of the map.
func (cl *CouchbaseMap) Size() (int, error) {
	ops := make([]LookupInSpec, 1)
	ops[0] = CountSpec("", nil)
	result, err := cl.collection.LookupIn(cl.id, ops, nil)
	if err != nil {
		return 0, err
	}

	var count int
	err = result.ContentAt(0, &count)
	if err != nil {
		return 0, err
	}

	return count, nil
}

// Keys returns all of the keys within the map.
func (cl *CouchbaseMap) Keys() ([]string, error) {
	content, err := cl.collection.Get(cl.id, nil)
	if err != nil {
		return nil, err
	}

	var mapContents map[string]interface{}
	err = content.Content(&mapContents)
	if err != nil {
		return nil, err
	}

	var keys []string
	for id := range mapContents {
		keys = append(keys, id)
	}

	return keys, nil
}

// Values returns all of the values within the map.
func (cl *CouchbaseMap) Values() ([]interface{}, error) {
	content, err := cl.collection.Get(cl.id, nil)
	if err != nil {
		return nil, err
	}

	var mapContents map[string]interface{}
	err = content.Content(&mapContents)
	if err != nil {
		return nil, err
	}

	var values []interface{}
	for _, val := range mapContents {
		values = append(values, val)
	}

	return values, nil
}

// Clear clears a map, also removing it.
func (cl *CouchbaseMap) Clear() error {
	_, err := cl.collection.Remove(cl.id, nil)
	if err != nil {
		return err
	}

	return nil
}

// CouchbaseSet represents a set document.
type CouchbaseSet struct {
	id         string
	underlying *CouchbaseList
}

// Set returns a new CouchbaseSet.
func (c *Collection) Set(id string) *CouchbaseSet {
	return &CouchbaseSet{
		id:         id,
		underlying: c.List(id),
	}
}

// Iterator returns an iterable for all items in the set.
func (cs *CouchbaseSet) Iterator() ([]interface{}, error) {
	return cs.underlying.Iterator()
}

// Add adds a value to the set.
func (cs *CouchbaseSet) Add(val interface{}) error {
	ops := make([]MutateInSpec, 1)
	ops[0] = ArrayAddUniqueSpec("", val, nil)
	_, err := cs.underlying.collection.MutateIn(cs.id, ops, &MutateInOptions{UpsertDocument: true})
	if err != nil {
		return err
	}

	return nil
}

// Remove removes an value from the set.
func (cs *CouchbaseSet) Remove(val string) error {
	for {
		content, err := cs.underlying.collection.Get(cs.id, nil)
		if err != nil {
			return err
		}

		cas := content.Cas()

		var setContents []interface{}
		err = content.Content(&setContents)
		if err != nil {
			return err
		}

		indexToRemove := -1
		for i, item := range setContents {
			if item == val {
				indexToRemove = i
			}
		}

		if indexToRemove > -1 {
			ops := make([]MutateInSpec, 1)
			ops[0] = RemoveSpec(fmt.Sprintf("[%d]", indexToRemove), nil)
			_, err = cs.underlying.collection.MutateIn(cs.id, ops, &MutateInOptions{Cas: cas})
			if IsCasMismatchError(err) {
				continue
			}
			if err != nil {
				return err
			}
			break
		}
	}

	return nil
}

// Values returns all of the values within the set.
func (cs *CouchbaseSet) Values() ([]interface{}, error) {
	content, err := cs.underlying.collection.Get(cs.id, nil)
	if err != nil {
		return nil, err
	}

	var setContents []interface{}
	err = content.Content(&setContents)
	if err != nil {
		return nil, err
	}

	return setContents, nil
}

// Contains verifies whether or not a value exists within the set.
func (cs *CouchbaseSet) Contains(val string) (bool, error) {
	content, err := cs.underlying.collection.Get(cs.id, nil)
	if err != nil {
		return false, err
	}

	var setContents []interface{}
	err = content.Content(&setContents)
	if err != nil {
		return false, err
	}

	for _, item := range setContents {
		if item == val {
			return true, nil
		}
	}

	return false, nil
}

// Size returns the size of the set
func (cs *CouchbaseSet) Size() (int, error) {
	return cs.underlying.Size()
}

// Clear clears a set, also removing it.
func (cs *CouchbaseSet) Clear() error {
	err := cs.underlying.Clear()
	if err != nil {
		return err
	}

	return nil
}

// CouchbaseQueue represents a queue document.
type CouchbaseQueue struct {
	id         string
	underlying *CouchbaseList
}

// Queue returns a new CouchbaseQueue.
func (c *Collection) Queue(id string) *CouchbaseQueue {
	return &CouchbaseQueue{
		id:         id,
		underlying: c.List(id),
	}
}

// Iterator returns an iterable for all items in the queue.
func (cs *CouchbaseQueue) Iterator() ([]interface{}, error) {
	return cs.underlying.Iterator()
}

// Push pushes a value onto the queue.
func (cs *CouchbaseQueue) Push(val interface{}) error {
	return cs.underlying.Prepend(val)
}

// Pop pops an items off of the queue.
func (cs *CouchbaseQueue) Pop(valuePtr interface{}) error {
	for {
		ops := make([]LookupInSpec, 1)
		ops[0] = GetSpec("[-1]", nil)
		content, err := cs.underlying.collection.LookupIn(cs.id, ops, nil)
		if err != nil {
			return err
		}

		cas := content.Cas()
		err = content.ContentAt(0, valuePtr)
		if err != nil {
			return err
		}

		mutateOps := make([]MutateInSpec, 1)
		mutateOps[0] = RemoveSpec("[-1]", nil)
		_, err = cs.underlying.collection.MutateIn(cs.id, mutateOps, &MutateInOptions{Cas: cas})
		if IsCasMismatchError(err) {
			continue
		}
		if err != nil {
			return err
		}
		break
	}

	return nil
}

// Size returns the size of the queue.
func (cs *CouchbaseQueue) Size() (int, error) {
	return cs.underlying.Size()
}

// Clear clears a queue, also removing it.
func (cs *CouchbaseQueue) Clear() error {
	err := cs.underlying.Clear()
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>GOCBC-601: Bound datastruct Cas retries to 16 attempts<commit_after>package gocb

import (
	"fmt"

	"github.com/pkg/errors"
)

// CouchbaseList represents a list document.
type CouchbaseList struct {
	collection *Collection
	id         string
}

// List returns a new CouchbaseList for the document specified by id.
func (c *Collection) List(id string) *CouchbaseList {
	return &CouchbaseList{
		collection: c,
		id:         id,
	}
}

// Iterator returns an iterable for all items in the list.
func (cl *CouchbaseList) Iterator() ([]interface{}, error) {
	content, err := cl.collection.Get(cl.id, nil)
	if err != nil {
		return nil, err
	}

	var listContents []interface{}
	err = content.Content(&listContents)
	if err != nil {
		return nil, err
	}

	return listContents, nil
}

// At retrieves the value specified at the given index from the list.
func (cl *CouchbaseList) At(index int, valuePtr interface{}) error {
	ops := make([]LookupInSpec, 1)
	ops[0] = GetSpec(fmt.Sprintf("[%d]", index), nil)
	result, err := cl.collection.LookupIn(cl.id, ops, nil)
	if err != nil {
		return err
	}

	return result.ContentAt(0, valuePtr)
}

// RemoveAt removes the value specified at the given index from the list.
func (cl *CouchbaseList) RemoveAt(index int) error {
	ops := make([]MutateInSpec, 1)
	ops[0] = RemoveSpec(fmt.Sprintf("[%d]", index), nil)
	_, err := cl.collection.MutateIn(cl.id, ops, nil)
	if err != nil {
		return err
	}

	return nil
}

// Append appends an item to the list.
func (cl *CouchbaseList) Append(val interface{}) error {
	ops := make([]MutateInSpec, 1)
	ops[0] = ArrayAppendSpec("", val, nil)
	_, err := cl.collection.MutateIn(cl.id, ops, &MutateInOptions{UpsertDocument: true})
	if err != nil {
		return err
	}

	return nil
}

// Prepend prepends an item to the list.
func (cl *CouchbaseList) Prepend(val interface{}) error {
	ops := make([]MutateInSpec, 1)
	ops[0] = ArrayPrependSpec("", val, nil)
	_, err := cl.collection.MutateIn(cl.id, ops, &MutateInOptions{UpsertDocument: true})
	if err != nil {
		return err
	}

	return nil
}

// IndexOf gets the index of the item in the list.
func (cl *CouchbaseList) IndexOf(val interface{}) (int, error) {
	content, err := cl.collection.Get(cl.id, nil)
	if err != nil {
		return 0, err
	}

	var listContents []interface{}
	err = content.Content(&listContents)
	if err != nil {
		return 0, err
	}

	for i, item := range listContents {
		if item == val {
			return i, nil
		}
	}

	return -1, nil
}

// Size returns the size of the list.
func (cl *CouchbaseList) Size() (int, error) {
	ops := make([]LookupInSpec, 1)
	ops[0] = CountSpec("", nil)
	result, err := cl.collection.LookupIn(cl.id, ops, nil)
	if err != nil {
		return 0, err
	}

	var count int
	err = result.ContentAt(0, &count)
	if err != nil {
		return 0, err
	}

	return count, nil
}

// Clear clears a list, also removing it.
func (cl *CouchbaseList) Clear() error {
	_, err := cl.collection.Remove(cl.id, nil)
	if err != nil {
		return err
	}

	return nil
}

// CouchbaseMap represents a map document.
type CouchbaseMap struct {
	collection *Collection
	id         string
}

// Map returns a new CouchbaseMap.
func (c *Collection) Map(id string) *CouchbaseMap {
	return &CouchbaseMap{
		collection: c,
		id:         id,
	}
}

// Iterator returns an iterable for all items in the map.
func (cl *CouchbaseMap) Iterator() (map[string]interface{}, error) {
	content, err := cl.collection.Get(cl.id, nil)
	if err != nil {
		return nil, err
	}

	var mapContents map[string]interface{}
	err = content.Content(&mapContents)
	if err != nil {
		return nil, err
	}

	return mapContents, nil
}

// At retrieves the item for the given id from the map.
func (cl *CouchbaseMap) At(id string, valuePtr interface{}) error {
	ops := make([]LookupInSpec, 1)
	ops[0] = GetSpec(fmt.Sprintf("[%s]", id), nil)
	result, err := cl.collection.LookupIn(cl.id, ops, nil)
	if err != nil {
		return err
	}

	return result.ContentAt(0, valuePtr)
}

// Add adds an item to the map.
func (cl *CouchbaseMap) Add(id string, val interface{}) error {
	ops := make([]MutateInSpec, 1)
	ops[0] = UpsertSpec(id, val, nil)
	_, err := cl.collection.MutateIn(cl.id, ops, &MutateInOptions{UpsertDocument: true})
	if err != nil {
		return err
	}

	return nil
}

// Remove removes an item from the map.
func (cl *CouchbaseMap) Remove(id string) error {
	ops := make([]MutateInSpec, 1)
	ops[0] = RemoveSpec(id, nil)
	_, err := cl.collection.MutateIn(cl.id, ops, nil)
	if err != nil {
		return err
	}

	return nil
}

// Exists verifies whether or a id exists in the map.
func (cl *CouchbaseMap) Exists(id string) (bool, error) {
	ops := make([]LookupInSpec, 1)
	ops[0] = ExistsSpec(fmt.Sprintf("[%s]", id), nil)
	result, err := cl.collection.LookupIn(cl.id, ops, nil)
	if err != nil {
		return false, err
	}

	return result.Exists(0), nil
}

// Size returns the size of the map.
func (cl *CouchbaseMap) Size() (int, error) {
	ops := make([]LookupInSpec, 1)
	ops[0] = CountSpec("", nil)
	result, err := cl.collection.LookupIn(cl.id, ops, nil)
	if err != nil {
		return 0, err
	}

	var count int
	err = result.ContentAt(0, &count)
	if err != nil {
		return 0, err
	}

	return count, nil
}

// Keys returns all of the keys within the map.
func (cl *CouchbaseMap) Keys() ([]string, error) {
	content, err := cl.collection.Get(cl.id, nil)
	if err != nil {
		return nil, err
	}

	var mapContents map[string]interface{}
	err = content.Content(&mapContents)
	if err != nil {
		return nil, err
	}

	var keys []string
	for id := range mapContents {
		keys = append(keys, id)
	}

	return keys, nil
}

// Values returns all of the values within the map.
func (cl *CouchbaseMap) Values() ([]interface{}, error) {
	content, err := cl.collection.Get(cl.id, nil)
	if err != nil {
		return nil, err
	}

	var mapContents map[string]interface{}
	err = content.Content(&mapContents)
	if err != nil {
		return nil, err
	}

	var values []interface{}
	for _, val := range mapContents {
		values = append(values, val)
	}

	return values, nil
}

// Clear clears a map, also removing it.
func (cl *CouchbaseMap) Clear() error {
	_, err := cl.collection.Remove(cl.id, nil)
	if err != nil {
		return err
	}

	return nil
}

// CouchbaseSet represents a set document.
type CouchbaseSet struct {
	id         string
	underlying *CouchbaseList
}

// Set returns a new CouchbaseSet.
func (c *Collection) Set(id string) *CouchbaseSet {
	return &CouchbaseSet{
		id:         id,
		underlying: c.List(id),
	}
}

// Iterator returns an iterable for all items in the set.
func (cs *CouchbaseSet) Iterator() ([]interface{}, error) {
	return cs.underlying.Iterator()
}

// Add adds a value to the set.
func (cs *CouchbaseSet) Add(val interface{}) error {
	ops := make([]MutateInSpec, 1)
	ops[0] = ArrayAddUniqueSpec("", val, nil)
	_, err := cs.underlying.collection.MutateIn(cs.id, ops, &MutateInOptions{UpsertDocument: true})
	if err != nil {
		return err
	}

	return nil
}

// Remove removes an value from the set.
func (cs *CouchbaseSet) Remove(val string) error {
	for i := 0; i < 16; i++ {
		content, err := cs.underlying.collection.Get(cs.id, nil)
		if err != nil {
			return err
		}

		cas := content.Cas()

		var setContents []interface{}
		err = content.Content(&setContents)
		if err != nil {
			return err
		}

		indexToRemove := -1
		for i, item := range setContents {
			if item == val {
				indexToRemove = i
			}
		}

		if indexToRemove > -1 {
			ops := make([]MutateInSpec, 1)
			ops[0] = RemoveSpec(fmt.Sprintf("[%d]", indexToRemove), nil)
			_, err = cs.underlying.collection.MutateIn(cs.id, ops, &MutateInOptions{Cas: cas})
			if IsCasMismatchError(err) {
				continue
			}
			if err != nil {
				return err
			}
		}
		return nil
	}

	return errors.New("failed to perform operation after 16 retries")
}

// Values returns all of the values within the set.
func (cs *CouchbaseSet) Values() ([]interface{}, error) {
	content, err := cs.underlying.collection.Get(cs.id, nil)
	if err != nil {
		return nil, err
	}

	var setContents []interface{}
	err = content.Content(&setContents)
	if err != nil {
		return nil, err
	}

	return setContents, nil
}

// Contains verifies whether or not a value exists within the set.
func (cs *CouchbaseSet) Contains(val string) (bool, error) {
	content, err := cs.underlying.collection.Get(cs.id, nil)
	if err != nil {
		return false, err
	}

	var setContents []interface{}
	err = content.Content(&setContents)
	if err != nil {
		return false, err
	}

	for _, item := range setContents {
		if item == val {
			return true, nil
		}
	}

	return false, nil
}

// Size returns the size of the set
func (cs *CouchbaseSet) Size() (int, error) {
	return cs.underlying.Size()
}

// Clear clears a set, also removing it.
func (cs *CouchbaseSet) Clear() error {
	err := cs.underlying.Clear()
	if err != nil {
		return err
	}

	return nil
}

// CouchbaseQueue represents a queue document.
type CouchbaseQueue struct {
	id         string
	underlying *CouchbaseList
}

// Queue returns a new CouchbaseQueue.
func (c *Collection) Queue(id string) *CouchbaseQueue {
	return &CouchbaseQueue{
		id:         id,
		underlying: c.List(id),
	}
}

// Iterator returns an iterable for all items in the queue.
func (cs *CouchbaseQueue) Iterator() ([]interface{}, error) {
	return cs.underlying.Iterator()
}

// Push pushes a value onto the queue.
func (cs *CouchbaseQueue) Push(val interface{}) error {
	return cs.underlying.Prepend(val)
}

// Pop pops an items off of the queue.
func (cs *CouchbaseQueue) Pop(valuePtr interface{}) error {
	for i := 0; i < 16; i++ {
		ops := make([]LookupInSpec, 1)
		ops[0] = GetSpec("[-1]", nil)
		content, err := cs.underlying.collection.LookupIn(cs.id, ops, nil)
		if err != nil {
			return err
		}

		cas := content.Cas()
		err = content.ContentAt(0, valuePtr)
		if err != nil {
			return err
		}

		mutateOps := make([]MutateInSpec, 1)
		mutateOps[0] = RemoveSpec("[-1]", nil)
		_, err = cs.underlying.collection.MutateIn(cs.id, mutateOps, &MutateInOptions{Cas: cas})
		if IsCasMismatchError(err) {
			continue
		}
		if err != nil {
			return err
		}
		return nil
	}

	return errors.New("failed to perform operation after 16 retries")
}

// Size returns the size of the queue.
func (cs *CouchbaseQueue) Size() (int, error) {
	return cs.underlying.Size()
}

// Clear clears a queue, also removing it.
func (cs *CouchbaseQueue) Clear() error {
	err := cs.underlying.Clear()
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package parser

import (
	"github.com/Zac-Garby/pluto/ast"
	"github.com/Zac-Garby/pluto/token"
)

func (p *Parser) parseStatement() ast.Statement {
	var stmt ast.Statement

	if p.curIs(token.SEMI) {
		return nil
	} else if p.curIs(token.RETURN) {
		stmt = p.parseReturnStatement()
	} else if p.curIs(token.DEF) {
		stmt = p.parseDefStatement()
	} else if p.curIs(token.NEXT) {
		stmt = p.parseNextStatement()
	} else if p.curIs(token.BREAK) {
		stmt = p.parseBreakStatement()
	} else if p.curIs(token.CLASS) {
		stmt = p.parseClassDeclaration()
	} else {
		stmt = p.parseExpressionStatement()
	}

	if !p.expect(token.SEMI) {
		return nil
	}

	return stmt
}

func (p *Parser) parseBlockStatement() ast.Statement {
	block := &ast.BlockStatement{
		Tok:        p.cur,
		Statements: []ast.Statement{},
	}

	p.next()

	for !p.curIs(token.RBRACE) && !p.curIs(token.EOF) {
		stmt := p.parseStatement()

		if stmt != nil {
			block.Statements = append(block.Statements, stmt)
		}

		p.next()
	}

	return block
}

func (p *Parser) parseExpressionStatement() ast.Statement {
	stmt := &ast.ExpressionStatement{
		Tok:  p.cur,
		Expr: p.parseExpression(LOWEST),
	}

	if stmt.Expr == nil {
		return nil
	}

	return stmt
}

func (p *Parser) parseReturnStatement() ast.Statement {
	if p.peek.Type == token.SEMI {
		return &ast.ReturnStatement{
			Tok: p.cur,
		}
	}

	stmt := &ast.ReturnStatement{
		Tok: p.cur,
	}

	p.next()
	stmt.Value = p.parseExpression(LOWEST)

	return stmt
}

func (p *Parser) parseNextStatement() ast.Statement {
	return &ast.NextStatement{
		Tok: p.cur,
	}
}

func (p *Parser) parseBreakStatement() ast.Statement {
	return &ast.BreakStatement{
		Tok: p.cur,
	}
}

func (p *Parser) parseDefStatement() ast.Statement {
	stmt := &ast.FunctionDefinition{
		Tok: p.cur,
	}

	p.next()
	stmt.Pattern = p.parsePatternCall(token.LBRACE)

	if len(stmt.Pattern) == 0 {
		p.defaultErr("expected at least one item in a pattern")
		return nil
	}

	stmt.Body = p.parseBlockStatement()

	return stmt
}

func (p *Parser) parseInitStatement() ast.Statement {
	stmt := &ast.InitDefinition{
		Tok: p.cur,
	}

	p.next()
	stmt.Pattern = p.parsePatternCall(token.LBRACE)

	if len(stmt.Pattern) == 0 {
		p.defaultErr("expected at least one item in a pattern")
		return nil
	}

	stmt.Body = p.parseBlockStatement()

	return stmt
}

func (p *Parser) parseClassDeclaration() ast.Statement {
	stmt := &ast.ClassStatement{
		Tok: p.cur,
	}

	if !p.expect(token.ID) {
		return nil
	}

	stmt.Name = p.parseNonFnID()

	if p.peekIs(token.EXTENDS) {
		p.next()
		p.next()

		stmt.Parent = p.parseNonFnID()
	}

	if !p.expect(token.LBRACE) {
		return nil
	}

	p.next()

	if p.curIs(token.RBRACE) {
		return stmt
	}

	for p.curIs(token.INIT, token.DEF) {
		if p.curIs(token.INIT) {
			stmt.Methods = append(stmt.Methods, p.parseInitStatement())
		} else {
			stmt.Methods = append(stmt.Methods, p.parseDefStatement())
		}

		if !p.expect(token.SEMI) {
			return nil
		}

		if p.peekIs(token.INIT, token.DEF) {
			p.next()
		}
	}

	if !p.expect(token.RBRACE) {
		return nil
	}

	return stmt
}
<commit_msg>Parse import and use statements<commit_after>package parser

import (
	"github.com/Zac-Garby/pluto/ast"
	"github.com/Zac-Garby/pluto/token"
)

func (p *Parser) parseStatement() ast.Statement {
	var stmt ast.Statement

	if p.curIs(token.SEMI) {
		return nil
	} else if p.curIs(token.RETURN) {
		stmt = p.parseReturnStatement()
	} else if p.curIs(token.DEF) {
		stmt = p.parseDefStatement()
	} else if p.curIs(token.NEXT) {
		stmt = p.parseNextStatement()
	} else if p.curIs(token.BREAK) {
		stmt = p.parseBreakStatement()
	} else if p.curIs(token.CLASS) {
		stmt = p.parseClassDeclaration()
	} else if p.curIs(token.IMPORT) {
		stmt = p.parseImportStatement()
	} else if p.curIs(token.USE) {
		stmt = p.parseUseStatement()
	} else {
		stmt = p.parseExpressionStatement()
	}

	if !p.expect(token.SEMI) {
		return nil
	}

	return stmt
}

func (p *Parser) parseBlockStatement() ast.Statement {
	block := &ast.BlockStatement{
		Tok:        p.cur,
		Statements: []ast.Statement{},
	}

	p.next()

	for !p.curIs(token.RBRACE) && !p.curIs(token.EOF) {
		stmt := p.parseStatement()

		if stmt != nil {
			block.Statements = append(block.Statements, stmt)
		}

		p.next()
	}

	return block
}

func (p *Parser) parseExpressionStatement() ast.Statement {
	stmt := &ast.ExpressionStatement{
		Tok:  p.cur,
		Expr: p.parseExpression(LOWEST),
	}

	if stmt.Expr == nil {
		return nil
	}

	return stmt
}

func (p *Parser) parseReturnStatement() ast.Statement {
	if p.peek.Type == token.SEMI {
		return &ast.ReturnStatement{
			Tok: p.cur,
		}
	}

	stmt := &ast.ReturnStatement{
		Tok: p.cur,
	}

	p.next()
	stmt.Value = p.parseExpression(LOWEST)

	return stmt
}

func (p *Parser) parseNextStatement() ast.Statement {
	return &ast.NextStatement{
		Tok: p.cur,
	}
}

func (p *Parser) parseBreakStatement() ast.Statement {
	return &ast.BreakStatement{
		Tok: p.cur,
	}
}

func (p *Parser) parseDefStatement() ast.Statement {
	stmt := &ast.FunctionDefinition{
		Tok: p.cur,
	}

	p.next()
	stmt.Pattern = p.parsePatternCall(token.LBRACE)

	if len(stmt.Pattern) == 0 {
		p.defaultErr("expected at least one item in a pattern")
		return nil
	}

	stmt.Body = p.parseBlockStatement()

	return stmt
}

func (p *Parser) parseInitStatement() ast.Statement {
	stmt := &ast.InitDefinition{
		Tok: p.cur,
	}

	p.next()
	stmt.Pattern = p.parsePatternCall(token.LBRACE)

	if len(stmt.Pattern) == 0 {
		p.defaultErr("expected at least one item in a pattern")
		return nil
	}

	stmt.Body = p.parseBlockStatement()

	return stmt
}

func (p *Parser) parseClassDeclaration() ast.Statement {
	stmt := &ast.ClassStatement{
		Tok: p.cur,
	}

	if !p.expect(token.ID) {
		return nil
	}

	stmt.Name = p.parseNonFnID()

	if p.peekIs(token.EXTENDS) {
		p.next()
		p.next()

		stmt.Parent = p.parseNonFnID()
	}

	if !p.expect(token.LBRACE) {
		return nil
	}

	p.next()

	if p.curIs(token.RBRACE) {
		return stmt
	}

	for p.curIs(token.INIT, token.DEF) {
		if p.curIs(token.INIT) {
			stmt.Methods = append(stmt.Methods, p.parseInitStatement())
		} else {
			stmt.Methods = append(stmt.Methods, p.parseDefStatement())
		}

		if !p.expect(token.SEMI) {
			return nil
		}

		if p.peekIs(token.INIT, token.DEF) {
			p.next()
		}
	}

	if !p.expect(token.RBRACE) {
		return nil
	}

	return stmt
}

func (p *Parser) parseImportStatement() ast.Statement {
	stmt := &ast.ImportStatement{
		Tok: p.cur,
	}

	if !p.expect(token.STR) {
		return nil
	}

	stmt.Package = p.cur.Literal

	return stmt
}

func (p *Parser) parseUseStatement() ast.Statement {
	stmt := &ast.UseStatement{
		Tok: p.cur,
	}

	if !p.expect(token.STR) {
		return nil
	}

	stmt.Package = p.cur.Literal

	return stmt
}
<|endoftext|>


<commit_before>package command

import (
	"github.com/deweysasser/locksmith/connection"
	"github.com/deweysasser/locksmith/data"
	"github.com/deweysasser/locksmith/lib"
	"github.com/deweysasser/locksmith/output"
	"github.com/urfave/cli"
	"reflect"
	"sync"
	"fmt"
)

func CmdFetch(c *cli.Context) error {
	outputLevel(c)
	libWG := sync.WaitGroup{}
	ml := lib.MainLibrary{Path: datadir(c)}

	fKeys := data.NewFanInKey(nil)
	fAccounts := data.NewFanInAccount()

	libWG.Add(1)
	go ingestKeys(ml.Keys(), fKeys.Output(), &libWG)

	libWG.Add(1)
	go ingestAccounts(ml.Accounts(), fAccounts.Output(), &libWG)

	filter := buildFilterFromContext(c)

	for conn := range ml.Connections().List() {
		if filter(conn) {
			output.Verbosef("Fetching from %s\n", conn)
			k, a := fetchFrom(conn)
			fKeys.Add(k)
			fAccounts.Add(a)
		}
	}

	fKeys.Wait()
	fAccounts.Wait()
	libWG.Wait()

	return nil
}

func fetchFrom(conn interface{}) (keys <-  chan data.Key, accounts <- chan data.Account) {
	switch conn.(type) {
	case connection.Connection:
		//fmt.Println("Fetching from ", conn)
		return conn.(connection.Connection).Fetch()
	default:
		panic("Unknown connection type " + reflect.TypeOf(conn).Name())
	}
}

func ingestAccounts(alib lib.Library, accounts chan data.Account, wg *sync.WaitGroup) {
	defer wg.Done()
	i := 0
	for k := range accounts {
		i++
		id := alib.Id(k)
		if existing, err := alib.Fetch(id); err == nil {
			if existingacct, ok := existing.(data.Account); ok {
				existingacct.Merge(k)
				if e := alib.Store(existingacct); e != nil {
					output.Error(e)
				}
			} else {
				panic(fmt.Sprint("type for", id, " was not Account"))
			}
		} else {
			if e := alib.Store(k); e != nil {
				output.Error(e)
			}
		}
	}

	output.Normalf("Discovered %d accounts\n", i)
}

func ingestKeys(klib lib.Library, keys chan data.Key, wg *sync.WaitGroup) {
	defer wg.Done()
	i := 0
	for k := range keys {
		i++
		id := klib.Id(k)
		if existing, err := klib.Fetch(id); err == nil {
			existing.(data.Key).Merge(k)
			if e := klib.Store(existing); e != nil {
				output.Error(e)
			}
			// It's possible for a key primary ID to change if we didn't before have a public key.
			if klib.Id(existing) != id {
				output.Debug("Updating key id from", id, "to", klib.Id(existing))
				// If so, delete the previous key file.  This, however, takes they key out of the cache so we need to
				// re-cache it.  Storing it again puts it back in the cache at the cost of a bit more disk I/O (but code
				// simplicity)
				if e := klib.Delete(id); e == nil {
					if e := klib.Store(existing); e != nil {
						output.Error("Error re-storing", klib.Id(existing))
					}
				}
			}

		} else {
			if e := klib.Store(k); e != nil {
				output.Error(e)
			}
		}
	}

	output.Normalf("Discovered %d keys\n", i)
}
<commit_msg>Print number of unique keys/accounts processed<commit_after>package command

import (
	"github.com/deweysasser/locksmith/connection"
	"github.com/deweysasser/locksmith/data"
	"github.com/deweysasser/locksmith/lib"
	"github.com/deweysasser/locksmith/output"
	"github.com/urfave/cli"
	"reflect"
	"sync"
	"fmt"
)

func CmdFetch(c *cli.Context) error {
	outputLevel(c)
	libWG := sync.WaitGroup{}
	ml := lib.MainLibrary{Path: datadir(c)}

	fKeys := data.NewFanInKey(nil)
	fAccounts := data.NewFanInAccount()

	libWG.Add(1)
	go ingestKeys(ml.Keys(), fKeys.Output(), &libWG)

	libWG.Add(1)
	go ingestAccounts(ml.Accounts(), fAccounts.Output(), &libWG)

	filter := buildFilterFromContext(c)

	for conn := range ml.Connections().List() {
		if filter(conn) {
			output.Verbosef("Fetching from %s\n", conn)
			k, a := fetchFrom(conn)
			fKeys.Add(k)
			fAccounts.Add(a)
		}
	}

	fKeys.Wait()
	fAccounts.Wait()
	libWG.Wait()

	return nil
}

func fetchFrom(conn interface{}) (keys <-  chan data.Key, accounts <- chan data.Account) {
	switch conn.(type) {
	case connection.Connection:
		//fmt.Println("Fetching from ", conn)
		return conn.(connection.Connection).Fetch()
	default:
		panic("Unknown connection type " + reflect.TypeOf(conn).Name())
	}
}

func ingestAccounts(alib lib.Library, accounts chan data.Account, wg *sync.WaitGroup) {
	defer wg.Done()
	idmap := make(map[string] bool)
	i := 0
	for k := range accounts {
		i++
		id := alib.Id(k)
		idmap[id]=true
		if existing, err := alib.Fetch(id); err == nil {
			if existingacct, ok := existing.(data.Account); ok {
				existingacct.Merge(k)
				if e := alib.Store(existingacct); e != nil {
					output.Error(e)
				}
			} else {
				panic(fmt.Sprint("type for", id, " was not Account"))
			}
		} else {
			if e := alib.Store(k); e != nil {
				output.Error(e)
			}
		}
	}

	output.Normalf("Discovered %d accounts in %d references\n", len(idmap), i)
}

func ingestKeys(klib lib.Library, keys chan data.Key, wg *sync.WaitGroup) {
	defer wg.Done()
	idmap := make(map[string] bool)
	i := 0
	for k := range keys {
		i++
		id := klib.Id(k)
		idmap[id]=true
		if existing, err := klib.Fetch(id); err == nil {
			existing.(data.Key).Merge(k)
			if e := klib.Store(existing); e != nil {
				output.Error(e)
			}
			// It's possible for a key primary ID to change if we didn't before have a public key.
			if klib.Id(existing) != id {
				output.Debug("Updating key id from", id, "to", klib.Id(existing))
				// If so, delete the previous key file.  This, however, takes they key out of the cache so we need to
				// re-cache it.  Storing it again puts it back in the cache at the cost of a bit more disk I/O (but code
				// simplicity)
				if e := klib.Delete(id); e == nil {
					if e := klib.Store(existing); e != nil {
						output.Error("Error re-storing", klib.Id(existing))
					}
				}
			}

		} else {
			if e := klib.Store(k); e != nil {
				output.Error(e)
			}
		}
	}

	output.Normalf("Discovered %d keys in %d locations\n", len(idmap), i)
}
<|endoftext|>


<commit_before>package commands

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"unicode"

	"github.com/zetamatta/go-getch"

	"../dos"
)

type copymove_t struct {
	*exec.Cmd
	Action  func(src, dst string) error
	IsDirOk bool
}

func cmd_copy(cmd *exec.Cmd) (int, error) {
	return copymove_t{
		Cmd: cmd,
		Action: func(src, dst string) error {
			return dos.Copy(src, dst, false)
		},
	}.Run()
}

func cmd_move(cmd *exec.Cmd) (int, error) {
	return copymove_t{
		Cmd:     cmd,
		Action:  dos.Move,
		IsDirOk: true,
	}.Run()
}

func cmd_ln(cmd *exec.Cmd) (int, error) {
	if len(cmd.Args) >= 2 && cmd.Args[1] == "-s" {
		args := make([]string, 0, len(cmd.Args)-1)
		args = append(args, cmd.Args[0])
		args = append(args, cmd.Args[2:]...)
		cmd.Args = args
		return copymove_t{
			Cmd:     cmd,
			Action:  os.Symlink,
			IsDirOk: true,
		}.Run()
	} else {
		return copymove_t{
			Cmd:    cmd,
			Action: os.Link,
		}.Run()
	}
}

func (this copymove_t) Run() (int, error) {
	if len(this.Args) <= 2 {
		fmt.Fprintf(this.Stderr,
			"Usage: %s [/y] SOURCE-FILENAME DESITINATE-FILENAME\n"+
				"       %s [/y] FILENAMES... DESINATE-DIRECTORY\n",
			this.Args[0], this.Args[0])
		return 0, nil
	}
	fi, err := os.Stat(this.Args[len(this.Args)-1])
	isDir := err == nil && fi.Mode().IsDir()
	all := false
	srcs := this.Args[1 : len(this.Args)-1]
	for i, src := range srcs {
		if getch.IsCtrlCPressed() {
			fmt.Fprintln(this.Stderr, "^C")
			return 0, nil
		}
		if src == "/y" {
			all = true
			continue
		}
		dst := this.Args[len(this.Args)-1]
		if isDir {
			dst = filepath.Join(dst, filepath.Base(src))
		}
		if !this.IsDirOk {
			fi, err := os.Stat(src)
			if err == nil && fi.Mode().IsDir() {
				fmt.Fprintf(this.Stderr, "%s is directory and passed.\n", src)
				continue
			}
		}

		fmt.Fprintf(this.Stderr, "%s -> %s\n", src, dst)
		if !all {
			fi, err := os.Stat(dst)
			if fi != nil && err == nil {
				fmt.Fprintf(this.Stderr,
					"%s: override? [Yes/No/All/Quit] ",
					dst)
				ch := getch.Rune()
				if unicode.IsPrint(ch) {
					fmt.Fprintf(this.Stderr, "%c\n", ch)
				} else {
					fmt.Fprint(this.Stderr, "\n")
				}
				switch ch {
				case 'y', 'Y':

				case 'a', 'A':
					all = true
				case 'q', 'Q', rune(0x03):
					return 0, nil
				default:
					continue
				}
			}
		}
		err := this.Action(src, dst)
		if err != nil {
			if i >= len(srcs)-1 {
				return 1, err
			}
			fmt.Fprintf(this.Stderr, "%s\nContinue? [Yes/No] ", err.Error())
			ch := getch.Rune()
			if unicode.IsPrint(ch) {
				fmt.Fprintf(this.Stderr, "%c\n", ch)
			} else {
				fmt.Fprint(this.Stderr, "\n")
			}
			if ch != 'y' && ch != 'Y' {
				return 0, nil
			}
		}
	}
	return 0, nil
}
<commit_msg>copy & move regard the desitinate ending with \ : or dots as a directory<commit_after>package commands

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

	"github.com/zetamatta/go-getch"

	"../dos"
)

type copymove_t struct {
	*exec.Cmd
	Action  func(src, dst string) error
	IsDirOk bool
}

func cmd_copy(cmd *exec.Cmd) (int, error) {
	return copymove_t{
		Cmd: cmd,
		Action: func(src, dst string) error {
			return dos.Copy(src, dst, false)
		},
	}.Run()
}

func cmd_move(cmd *exec.Cmd) (int, error) {
	return copymove_t{
		Cmd:     cmd,
		Action:  dos.Move,
		IsDirOk: true,
	}.Run()
}

func cmd_ln(cmd *exec.Cmd) (int, error) {
	if len(cmd.Args) >= 2 && cmd.Args[1] == "-s" {
		args := make([]string, 0, len(cmd.Args)-1)
		args = append(args, cmd.Args[0])
		args = append(args, cmd.Args[2:]...)
		cmd.Args = args
		return copymove_t{
			Cmd:     cmd,
			Action:  os.Symlink,
			IsDirOk: true,
		}.Run()
	} else {
		return copymove_t{
			Cmd:    cmd,
			Action: os.Link,
		}.Run()
	}
}

var rxDir = regexp.MustCompile(`[\\/:].{1,2}$`)

func judgeDir(path string) bool {
	if path == "." || path == ".." || rxDir.MatchString(path) {
		return true
	}
	stat, err := os.Stat(path)
	if err != nil {
		return false
	}
	return stat.Mode().IsDir()
}

func (this copymove_t) Run() (int, error) {
	if len(this.Args) <= 2 {
		fmt.Fprintf(this.Stderr,
			"Usage: %s [/y] SOURCE-FILENAME DESITINATE-FILENAME\n"+
				"       %s [/y] FILENAMES... DESINATE-DIRECTORY\n",
			this.Args[0], this.Args[0])
		return 0, nil
	}
	all := false
	isDir := judgeDir(this.Args[len(this.Args)-1])
	srcs := this.Args[1 : len(this.Args)-1]
	for i, src := range srcs {
		if getch.IsCtrlCPressed() {
			fmt.Fprintln(this.Stderr, "^C")
			return 0, nil
		}
		if src == "/y" {
			all = true
			continue
		}
		dst := this.Args[len(this.Args)-1]
		if isDir {
			dst = filepath.Join(dst, filepath.Base(src))
		}
		if !this.IsDirOk {
			fi, err := os.Stat(src)
			if err == nil && fi.Mode().IsDir() {
				fmt.Fprintf(this.Stderr, "%s is directory and passed.\n", src)
				continue
			}
		}

		fmt.Fprintf(this.Stderr, "%s -> %s\n", src, dst)
		if !all {
			fi, err := os.Stat(dst)
			if fi != nil && err == nil {
				fmt.Fprintf(this.Stderr,
					"%s: override? [Yes/No/All/Quit] ",
					dst)
				ch := getch.Rune()
				if unicode.IsPrint(ch) {
					fmt.Fprintf(this.Stderr, "%c\n", ch)
				} else {
					fmt.Fprint(this.Stderr, "\n")
				}
				switch ch {
				case 'y', 'Y':

				case 'a', 'A':
					all = true
				case 'q', 'Q', rune(0x03):
					return 0, nil
				default:
					continue
				}
			}
		}
		err := this.Action(src, dst)
		if err != nil {
			if i >= len(srcs)-1 {
				return 1, err
			}
			fmt.Fprintf(this.Stderr, "%s\nContinue? [Yes/No] ", err.Error())
			ch := getch.Rune()
			if unicode.IsPrint(ch) {
				fmt.Fprintf(this.Stderr, "%c\n", ch)
			} else {
				fmt.Fprint(this.Stderr, "\n")
			}
			if ch != 'y' && ch != 'Y' {
				return 0, nil
			}
		}
	}
	return 0, nil
}
<|endoftext|>