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

// Benchmany runs Go benchmarks across many git commits.
//
// Usage:
//
//	benchmany run [-C git-dir] [-n iterations] <commit or range>...
//
//      benchmany plot [-C git-dir] <commit or range>...
//
//      benchmany list [-C git-dir] <commit or range>...
//
// run
//
// "benchmany run" runs the benchmarks in the current directory
// <iterations> times for each commit in <commit or range> and writes
// the benchmark results to log.<commit hash>. Benchmarks may be Go
// testing framework benchmarks or benchmarks from
// golang.org/x/benchmarks.
//
// <commit or range>... can be either a list of individual commits or
// a revision range. For the spelling of a revision range, see
// "SPECIFYING RANGES" in gitrevisions(7). For exact details, see the
// --no-walk option to git-rev-list(1).
//
// Benchmany will check out each revision in git-dir. The current
// directory may or may not be in the same git repository as git-dir.
// If git-dir refers to a Go installation, benchmany will run
// make.bash at each revision; otherwise, it assumes go test can
// rebuild the necessary dependencies.
//
// Benchmany is safe to interrupt. If it is restarted, it will parse
// the benchmark log files to recover its state.
//
// Benchmany supports multiple ways of prioritizing the order in which
// individual iterations are run. By default, it runs in "sequential"
// mode: it runs the first iteration of all benchmarks, then the
// second, and so forth. It also supports a "spread" mode designed to
// quickly get coverage for large sets of revisions. This mode
// randomizes the order to run iterations in, but biases this order
// toward covering an evenly distributed set of revisions early and
// finishing all of the iterations of the revisions it has started on
// before moving on to new revisions. This way, if benchmany is
// interrupted, the revisions benchmarked cover the space more-or-less
// evenly.
//
// plot
//
// "benchmany plot" reads the benchmark logs generated by "benchmany
// run" for the given <commit or range> and outputs tables that can be
// used to plot these benchmarks over time.
//
// list
//
// "benchmany list" prints a list of log file names generated by
// "benchmany run" for the given <commit or range>. By default, logs
// are listed from oldest to newest revision. This is useful as input
// to comparison tools like http://rsc.io/benchstat.
package main

import (
	"flag"
	"fmt"
	"os"
	"os/exec"
	"strings"
)

var gitDir string
var dryRun bool

// maxFails is the maximum number of benchmark run failures to
// tolerate for a commit before giving up on trying to benchmark that
// commit. Build failures always disqualify a commit.
const maxFails = 5

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s <subcommand> <args...>\n\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "Subcommands:\n")
		for _, sub := range subcommands {
			fmt.Fprintf(os.Stderr, "  %s %s\n", sub.name, sub.desc)
		}
		fmt.Fprintf(os.Stderr, "See %s <subcommand> -h for details.\n", os.Args[0])
	}
	flag.Parse()
	if flag.NArg() < 1 || subcommands[flag.Arg(0)] == nil {
		flag.Usage()
		os.Exit(2)
	}

	sub := subcommands[flag.Arg(0)]
	sub.flags.Parse(flag.Args()[1:])
	sub.cmd()
}

type subcommand struct {
	name, desc string
	cmd        func()
	flags      *flag.FlagSet
}

var subcommands = make(map[string]*subcommand)

func registerSubcommand(name, desc string, cmd func(), flags *flag.FlagSet) {
	subcommands[name] = &subcommand{name, desc, cmd, flags}
}

// git runs git subcommand subcmd and returns its stdout. If git
// fails, it prints the failure and exits.
func git(subcmd string, args ...string) string {
	gitargs := []string{}
	if gitDir != "" {
		gitargs = append(gitargs, "-C", gitDir)
	}
	gitargs = append(gitargs, subcmd)
	gitargs = append(gitargs, args...)
	cmd := exec.Command("git", gitargs...)
	cmd.Stderr = os.Stderr
	if dryRun {
		dryPrint(cmd)
		if !(subcmd == "rev-parse" || subcmd == "rev-list" || subcmd == "show") {
			return ""
		}
	}
	out, err := cmd.Output()
	if err != nil {
		fmt.Fprintf(os.Stderr, "git %s failed: %s", args, err)
		os.Exit(1)
	}
	return string(out)
}

func dryPrint(cmd *exec.Cmd) {
	out := shellEscape(cmd.Path)
	for _, a := range cmd.Args[1:] {
		out += " " + shellEscape(a)
	}
	if cmd.Dir != "" {
		out = fmt.Sprintf("(cd %s && %s)", shellEscape(cmd.Dir), out)
	}
	fmt.Fprintln(os.Stderr, out)
}

func shellEscape(x string) string {
	if len(x) == 0 {
		return "''"
	}
	for _, r := range x {
		if 'a' <= r && r <= 'z' || 'A' <= r && r <= 'Z' || '0' <= r && r <= '9' || strings.ContainsRune("@%_-+:,./", r) {
			continue
		}
		// Unsafe character.
		return "'" + strings.Replace(x, "'", "'\"'\"'", -1) + "'"
	}
	return x
}

func exists(path string) bool {
	_, err := os.Stat(path)
	return !os.IsNotExist(err)
}

func trimNL(s string) string {
	return strings.TrimRight(s, "\n")
}

// indent returns s with each line indented by four spaces. If s is
// non-empty, the returned string is guaranteed to end in a "\n".
func indent(s string) string {
	if len(s) == 0 {
		return s
	}
	if strings.HasSuffix(s, "\n") {
		s = s[:len(s)-1]
	}
	return "    " + strings.Replace(s, "\n", "\n    ", -1) + "\n"
}

// lines splits s in to lines. It omits a final blank line, if any.
func lines(s string) []string {
	l := strings.Split(s, "\n")
	if len(l) > 0 && l[len(l)-1] == "" {
		l = l[:len(l)-1]
	}
	return l
}
<commit_msg>benchmany: improve git failure message<commit_after>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Benchmany runs Go benchmarks across many git commits.
//
// Usage:
//
//	benchmany run [-C git-dir] [-n iterations] <commit or range>...
//
//      benchmany plot [-C git-dir] <commit or range>...
//
//      benchmany list [-C git-dir] <commit or range>...
//
// run
//
// "benchmany run" runs the benchmarks in the current directory
// <iterations> times for each commit in <commit or range> and writes
// the benchmark results to log.<commit hash>. Benchmarks may be Go
// testing framework benchmarks or benchmarks from
// golang.org/x/benchmarks.
//
// <commit or range>... can be either a list of individual commits or
// a revision range. For the spelling of a revision range, see
// "SPECIFYING RANGES" in gitrevisions(7). For exact details, see the
// --no-walk option to git-rev-list(1).
//
// Benchmany will check out each revision in git-dir. The current
// directory may or may not be in the same git repository as git-dir.
// If git-dir refers to a Go installation, benchmany will run
// make.bash at each revision; otherwise, it assumes go test can
// rebuild the necessary dependencies.
//
// Benchmany is safe to interrupt. If it is restarted, it will parse
// the benchmark log files to recover its state.
//
// Benchmany supports multiple ways of prioritizing the order in which
// individual iterations are run. By default, it runs in "sequential"
// mode: it runs the first iteration of all benchmarks, then the
// second, and so forth. It also supports a "spread" mode designed to
// quickly get coverage for large sets of revisions. This mode
// randomizes the order to run iterations in, but biases this order
// toward covering an evenly distributed set of revisions early and
// finishing all of the iterations of the revisions it has started on
// before moving on to new revisions. This way, if benchmany is
// interrupted, the revisions benchmarked cover the space more-or-less
// evenly.
//
// plot
//
// "benchmany plot" reads the benchmark logs generated by "benchmany
// run" for the given <commit or range> and outputs tables that can be
// used to plot these benchmarks over time.
//
// list
//
// "benchmany list" prints a list of log file names generated by
// "benchmany run" for the given <commit or range>. By default, logs
// are listed from oldest to newest revision. This is useful as input
// to comparison tools like http://rsc.io/benchstat.
package main

import (
	"flag"
	"fmt"
	"os"
	"os/exec"
	"strings"
)

var gitDir string
var dryRun bool

// maxFails is the maximum number of benchmark run failures to
// tolerate for a commit before giving up on trying to benchmark that
// commit. Build failures always disqualify a commit.
const maxFails = 5

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s <subcommand> <args...>\n\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "Subcommands:\n")
		for _, sub := range subcommands {
			fmt.Fprintf(os.Stderr, "  %s %s\n", sub.name, sub.desc)
		}
		fmt.Fprintf(os.Stderr, "See %s <subcommand> -h for details.\n", os.Args[0])
	}
	flag.Parse()
	if flag.NArg() < 1 || subcommands[flag.Arg(0)] == nil {
		flag.Usage()
		os.Exit(2)
	}

	sub := subcommands[flag.Arg(0)]
	sub.flags.Parse(flag.Args()[1:])
	sub.cmd()
}

type subcommand struct {
	name, desc string
	cmd        func()
	flags      *flag.FlagSet
}

var subcommands = make(map[string]*subcommand)

func registerSubcommand(name, desc string, cmd func(), flags *flag.FlagSet) {
	subcommands[name] = &subcommand{name, desc, cmd, flags}
}

// git runs git subcommand subcmd and returns its stdout. If git
// fails, it prints the failure and exits.
func git(subcmd string, args ...string) string {
	gitargs := []string{}
	if gitDir != "" {
		gitargs = append(gitargs, "-C", gitDir)
	}
	gitargs = append(gitargs, subcmd)
	gitargs = append(gitargs, args...)
	cmd := exec.Command("git", gitargs...)
	cmd.Stderr = os.Stderr
	if dryRun {
		dryPrint(cmd)
		if !(subcmd == "rev-parse" || subcmd == "rev-list" || subcmd == "show") {
			return ""
		}
	}
	out, err := cmd.Output()
	if err != nil {
		fmt.Fprintf(os.Stderr, "git %s failed: %s", shellEscapeList(gitargs), err)
		os.Exit(1)
	}
	return string(out)
}

func dryPrint(cmd *exec.Cmd) {
	out := shellEscape(cmd.Path)
	for _, a := range cmd.Args[1:] {
		out += " " + shellEscape(a)
	}
	if cmd.Dir != "" {
		out = fmt.Sprintf("(cd %s && %s)", shellEscape(cmd.Dir), out)
	}
	fmt.Fprintln(os.Stderr, out)
}

func shellEscape(x string) string {
	if len(x) == 0 {
		return "''"
	}
	for _, r := range x {
		if 'a' <= r && r <= 'z' || 'A' <= r && r <= 'Z' || '0' <= r && r <= '9' || strings.ContainsRune("@%_-+:,./", r) {
			continue
		}
		// Unsafe character.
		return "'" + strings.Replace(x, "'", "'\"'\"'", -1) + "'"
	}
	return x
}

func shellEscapeList(xs []string) string {
	out := make([]string, len(xs))
	for i, x := range xs {
		out[i] = shellEscape(x)
	}
	return strings.Join(out, " ")
}

func exists(path string) bool {
	_, err := os.Stat(path)
	return !os.IsNotExist(err)
}

func trimNL(s string) string {
	return strings.TrimRight(s, "\n")
}

// indent returns s with each line indented by four spaces. If s is
// non-empty, the returned string is guaranteed to end in a "\n".
func indent(s string) string {
	if len(s) == 0 {
		return s
	}
	if strings.HasSuffix(s, "\n") {
		s = s[:len(s)-1]
	}
	return "    " + strings.Replace(s, "\n", "\n    ", -1) + "\n"
}

// lines splits s in to lines. It omits a final blank line, if any.
func lines(s string) []string {
	l := strings.Split(s, "\n")
	if len(l) > 0 && l[len(l)-1] == "" {
		l = l[:len(l)-1]
	}
	return l
}
<|endoftext|>


<commit_before>//  Copyright (c) 2014 Couchbase, Inc.
//  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 main

import (
	"flag"
	"fmt"
	"os"
	"path"
	"sort"
	"strings"
)

type Flags struct {
	BindAddr   string
	DataDir    string
	Help       bool
	StaticDir  string
	StaticETag string
	Server     string
	Tags       string
	Container  string
	Version    bool
	Weight     int
	Register   string
	CfgConnect string
}

var flags Flags
var flagAliases map[string][]string

func init() {
	flagAliases = initFlags(&flags)
}

func initFlags(flags *Flags) map[string][]string {
	flagAliases := map[string][]string{} // main flag name => all aliases.
	flagKinds := map[string]string{}

	s := func(v *string, names []string, kind string,
		defaultVal, usage string) { // String cmd-line param.
		for _, name := range names {
			flag.StringVar(v, name, defaultVal, usage)
		}
		flagAliases[names[0]] = names
		flagKinds[names[0]] = kind
	}

	i := func(v *int, names []string, kind string,
		defaultVal int, usage string) { // Integer cmd-line param.
		for _, name := range names {
			flag.IntVar(v, name, defaultVal, usage)
		}
		flagAliases[names[0]] = names
		flagKinds[names[0]] = kind
	}

	b := func(v *bool, names []string, kind string,
		defaultVal bool, usage string) { // Bool cmd-line param.
		for _, name := range names {
			flag.BoolVar(v, name, defaultVal, usage)
		}
		flagAliases[names[0]] = names
		flagKinds[names[0]] = kind
	}

	s(&flags.BindAddr,
		[]string{"bindAddr"}, "ADDR:PORT", "localhost:8095",
		"http listen address:port")
	s(&flags.DataDir,
		[]string{"dataDir", "data"}, "DIR", "data",
		"directory path where index data and"+
			"\nlocal configuration files will be stored")
	b(&flags.Help,
		[]string{"help", "?", "H", "h"}, "", false,
		"print this usage message and exit")
	s(&flags.StaticDir,
		[]string{"staticDir"}, "DIR", "static",
		"directory for static web UI content")
	s(&flags.StaticETag,
		[]string{"staticETag"}, "ETAG", "",
		"static etag value")
	s(&flags.Server,
		[]string{"server"}, "URL", "",
		"url to datasource server;"+
			"\nexample for couchbase: http://localhost:8091")
	s(&flags.Tags,
		[]string{"tags"}, "TAGS", "",
		"comma-separated list of tags (or roles) for this node")
	s(&flags.Container,
		[]string{"container"}, "PATH", "",
		"slash separated path of parent containers for this node,"+
			"\nfor shelf/rack/row/zone awareness")
	b(&flags.Version,
		[]string{"version", "v"}, "", false,
		"print version string and exit")
	i(&flags.Weight,
		[]string{"weight"}, "INT", 1,
		"weight of this node (a more capable node has higher weight)")
	s(&flags.Register,
		[]string{"register"}, "REGISTER", "wanted",
		"register this node as wanted, wantedForce,"+
			"\nknown, knownForce, unwanted, unknown or unchanged")
	s(&flags.CfgConnect,
		[]string{"cfgConnect", "cfg"}, "CFG_CONNECT", "simple",
		"connection string/info to configuration provider")

	flag.Usage = func() {
		if !flags.Help {
			return
		}

		base := path.Base(os.Args[0])

		fmt.Fprintf(os.Stderr,
			"%s: couchbase full-text server\n\n", base)
		fmt.Fprintf(os.Stderr, "more information is available at:\n"+
			"  http://github.com/couchbaselabs/cbft\n\n")
		fmt.Fprintf(os.Stderr, "usage:\n  %s [flags]\n\n", base)
		fmt.Fprintf(os.Stderr, "flags:\n")

		flagsByName := map[string]*flag.Flag{}
		flag.VisitAll(func(f *flag.Flag) {
			flagsByName[f.Name] = f
		})

		flags := []string(nil)
		for name := range flagAliases {
			flags = append(flags, name)
		}
		sort.Strings(flags)

		for _, name := range flags {
			aliases := flagAliases[name]
			a := []string(nil)
			for i := len(aliases) - 1; i >= 0; i-- {
				a = append(a, aliases[i])
			}
			f := flagsByName[name]
			fmt.Fprintf(os.Stderr, "  -%s %s\n",
				strings.Join(a, ", -"), flagKinds[name])
			fmt.Fprintf(os.Stderr, "      %s\n",
				strings.Join(strings.Split(f.Usage, "\n"),
					"\n      "))
		}
	}

	return flagAliases
}
<commit_msg>more cmd-line param description strings<commit_after>//  Copyright (c) 2014 Couchbase, Inc.
//  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 main

import (
	"flag"
	"fmt"
	"os"
	"path"
	"sort"
	"strings"
)

type Flags struct {
	BindAddr   string
	CfgConnect string
	Container  string
	DataDir    string
	Help       bool
	Register   string
	StaticDir  string
	StaticETag string
	Server     string
	Tags       string
	Version    bool
	Weight     int
}

var flags Flags
var flagAliases map[string][]string

func init() {
	flagAliases = initFlags(&flags)
}

func initFlags(flags *Flags) map[string][]string {
	flagAliases := map[string][]string{} // main flag name => all aliases.
	flagKinds := map[string]string{}

	s := func(v *string, names []string, kind string,
		defaultVal, usage string) { // String cmd-line param.
		for _, name := range names {
			flag.StringVar(v, name, defaultVal, usage)
		}
		flagAliases[names[0]] = names
		flagKinds[names[0]] = kind
	}

	i := func(v *int, names []string, kind string,
		defaultVal int, usage string) { // Integer cmd-line param.
		for _, name := range names {
			flag.IntVar(v, name, defaultVal, usage)
		}
		flagAliases[names[0]] = names
		flagKinds[names[0]] = kind
	}

	b := func(v *bool, names []string, kind string,
		defaultVal bool, usage string) { // Bool cmd-line param.
		for _, name := range names {
			flag.BoolVar(v, name, defaultVal, usage)
		}
		flagAliases[names[0]] = names
		flagKinds[names[0]] = kind
	}

	s(&flags.BindAddr,
		[]string{"bindAddr"}, "ADDR:PORT", "localhost:8095",
		"http listen address:port")
	s(&flags.CfgConnect,
		[]string{"cfgConnect", "cfg"}, "CFG_CONNECT", "simple",
		"connection string/info to a configuration provider;"+
			"\nexamples:"+
			"\n* simple (for local-only, single-node configuration)"+
			"\n* couchbase:http://BUCKET@HOST:PORT"+
			"\n* couchbase:http://my-cfg-bucket@127.0.0.1:8091")
	s(&flags.Container,
		[]string{"container"}, "PATH", "",
		"slash separated path of logical parent containers"+
			"\nfor this node, for shelf/rack/row/zone awareness")
	s(&flags.DataDir,
		[]string{"dataDir", "data"}, "DIR", "data",
		"directory path where index data and local"+
			"\nconfiguration files will be stored")
	b(&flags.Help,
		[]string{"help", "?", "H", "h"}, "", false,
		"print this usage message and exit")
	s(&flags.Register,
		[]string{"register"}, "REGISTER", "wanted",
		"register this node as wanted, wantedForce,"+
			"\nknown, knownForce, unwanted, unknown or unchanged")
	s(&flags.StaticDir,
		[]string{"staticDir"}, "DIR", "static",
		"directory for static web UI content")
	s(&flags.StaticETag,
		[]string{"staticETag"}, "ETAG", "",
		"etag for static web UI content")
	s(&flags.Server,
		[]string{"server"}, "URL", "",
		"url to datasource server;"+
			"\nexample for couchbase: http://localhost:8091")
	s(&flags.Tags,
		[]string{"tags"}, "TAGS", "",
		"comma-separated list of tags (allowed roles)"+
			"\nfor this node, such as:"+
			"\nfeed, janitor, pindex, planner, queryer")
	b(&flags.Version,
		[]string{"version", "v"}, "", false,
		"print version string and exit")
	i(&flags.Weight,
		[]string{"weight"}, "INTEGER", 1,
		"weight of this node (a more capable node has higher weight)")

	flag.Usage = func() {
		if !flags.Help {
			return
		}

		base := path.Base(os.Args[0])

		fmt.Fprintf(os.Stderr,
			"%s: couchbase full-text server\n\n", base)
		fmt.Fprintf(os.Stderr, "more information is available at:\n"+
			"  http://github.com/couchbaselabs/cbft\n\n")
		fmt.Fprintf(os.Stderr, "usage:\n  %s [flags]\n\n", base)
		fmt.Fprintf(os.Stderr, "flags:\n")

		flagsByName := map[string]*flag.Flag{}
		flag.VisitAll(func(f *flag.Flag) {
			flagsByName[f.Name] = f
		})

		flags := []string(nil)
		for name := range flagAliases {
			flags = append(flags, name)
		}
		sort.Strings(flags)

		for _, name := range flags {
			aliases := flagAliases[name]
			a := []string(nil)
			for i := len(aliases) - 1; i >= 0; i-- {
				a = append(a, aliases[i])
			}
			f := flagsByName[name]
			fmt.Fprintf(os.Stderr, "  -%s %s\n",
				strings.Join(a, ", -"), flagKinds[name])
			fmt.Fprintf(os.Stderr, "      %s\n",
				strings.Join(strings.Split(f.Usage, "\n"),
					"\n      "))
		}
	}

	return flagAliases
}
<|endoftext|>


<commit_before>package cmd

import (
	"github.com/varunamachi/orekng/data"
	"gopkg.in/urfave/cli.v1"
)

//ClientCommandProvider - Providers commands for running Orek app as client
type ClientCommandProvider struct{}

func

//GetCommands - gives commands for running Orek app as client to Orek Service
func (ccp *ClientCommandProvider) GetCommands() cli.Command {
	subcmds := []cli.Command{
		listUsersCommand(),
		showUserCommand(),
		showUserWithEmailCommand(),
		createUserCommand(),
		updateUserCommand(),
		deleteUserCommand(),

		listEndpointsCommand(),
		showEndpointCommand(),
		createEndpointCommand(),
		updateEndpointCommand(),
		deleteEndpointCommand(),

		listVariablesCommand(),
		listVariablesForEndpointCommand(),
		showVariableCommand(),
		createVariableCommand(),
		updateVariableCommand(),
		deleteVariableCommand(),

		listParametersCommand(),
		listParametersForEndpointCommand(),
		showParameterCommand(),
		createParameterCommand(),
		updateParameterCommand(),
		deleteParameterCommand(),

		listUserGroupsCommand(),
		showUserGroupCommand(),
		createUserGroupCommand(),
		updateUserGroupCommand(),
		deleteUserGroupCommand(),

		addUserToGroupCommand(),
		removeUserFromGroupCommand(),
		getUsersInGroupCommand(),
		getGroupsForUserCommand(),

		clearValuesForVariableCommand(),
		getValuesForVariableCommand(),

		setPasswordCommand(),
		updatePasswordCommand(),
	}
	return cli.Command{
		Name:        "client",
		Subcommands: subcmds,
		Flags:       []cli.Flag{},
	}
}

func listUsersCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "list-users",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func showUserCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name: "show-user",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "user-name",
				Value: "",
				Usage: "The unique user_name for the user",
			},
		},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func showUserWithEmailCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func createUserCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name: "create-user",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "user-name",
				Value: "",
				Usage: "The unique user_name for the user",
			},
			cli.StringFlag{
				Name:  "first-name",
				Value: "",
				Usage: "The first name of the user",
			},
			cli.StringFlag{
				Name:  "second-name",
				Value: "",
				Usage: "The second name of the user",
			},
			cli.StringFlag{
				Name:  "email",
				Value: "",
				Usage: "Email of the user",
			},
		},
		Action: func(ctx *cli.Context) (err error) {
			argetr := ArgGetter{Ctx: ctx}
			userName := argetr.GetRequiredString("user-name")
			email := argetr.GetRequiredString("email")
			firstName := argetr.GetString("first-name")
			secondName := argetr.GetString("second-name")
			if argetr.Err == nil {
				//Below should only run if it is local mode otherwise should use
				//the not yet implemented REST client mode
				err = data.GetDataStore().CreateUser(&data.User{
					Name:       userName,
					FirstName:  firstName,
					SecondName: secondName,
					Email:      email,
				})

			}
			return err
		},
	}
	return cmd
}

func updateUserCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func deleteUserCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func listEndpointsCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func showEndpointCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func createEndpointCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func updateEndpointCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func deleteEndpointCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func listVariablesCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func listVariablesForEndpointCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func showVariableCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func createVariableCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func updateVariableCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func deleteVariableCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func listParametersCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func listParametersForEndpointCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func showParameterCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func createParameterCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func updateParameterCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func deleteParameterCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func listUserGroupsCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func showUserGroupCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func createUserGroupCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func updateUserGroupCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func deleteUserGroupCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func addUserToGroupCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func removeUserFromGroupCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func getUsersInGroupCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func getGroupsForUserCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func clearValuesForVariableCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func getValuesForVariableCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func setPasswordCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func updatePasswordCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}
<commit_msg>Fix for a typo<commit_after>package cmd

import (
	"github.com/varunamachi/orekng/data"
	"gopkg.in/urfave/cli.v1"
)

//ClientCommandProvider - Providers commands for running Orek app as client
type ClientCommandProvider struct{}

//GetCommands - gives commands for running Orek app as client to Orek Service
func (ccp *ClientCommandProvider) GetCommands() cli.Command {
	subcmds := []cli.Command{
		listUsersCommand(),
		showUserCommand(),
		showUserWithEmailCommand(),
		createUserCommand(),
		updateUserCommand(),
		deleteUserCommand(),

		listEndpointsCommand(),
		showEndpointCommand(),
		createEndpointCommand(),
		updateEndpointCommand(),
		deleteEndpointCommand(),

		listVariablesCommand(),
		listVariablesForEndpointCommand(),
		showVariableCommand(),
		createVariableCommand(),
		updateVariableCommand(),
		deleteVariableCommand(),

		listParametersCommand(),
		listParametersForEndpointCommand(),
		showParameterCommand(),
		createParameterCommand(),
		updateParameterCommand(),
		deleteParameterCommand(),

		listUserGroupsCommand(),
		showUserGroupCommand(),
		createUserGroupCommand(),
		updateUserGroupCommand(),
		deleteUserGroupCommand(),

		addUserToGroupCommand(),
		removeUserFromGroupCommand(),
		getUsersInGroupCommand(),
		getGroupsForUserCommand(),

		clearValuesForVariableCommand(),
		getValuesForVariableCommand(),

		setPasswordCommand(),
		updatePasswordCommand(),
	}
	return cli.Command{
		Name:        "client",
		Subcommands: subcmds,
		Flags:       []cli.Flag{},
	}
}

func listUsersCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "list-users",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func showUserCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name: "show-user",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "user-name",
				Value: "",
				Usage: "The unique user_name for the user",
			},
		},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func showUserWithEmailCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func createUserCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name: "create-user",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "user-name",
				Value: "",
				Usage: "The unique user_name for the user",
			},
			cli.StringFlag{
				Name:  "first-name",
				Value: "",
				Usage: "The first name of the user",
			},
			cli.StringFlag{
				Name:  "second-name",
				Value: "",
				Usage: "The second name of the user",
			},
			cli.StringFlag{
				Name:  "email",
				Value: "",
				Usage: "Email of the user",
			},
		},
		Action: func(ctx *cli.Context) (err error) {
			argetr := ArgGetter{Ctx: ctx}
			userName := argetr.GetRequiredString("user-name")
			email := argetr.GetRequiredString("email")
			firstName := argetr.GetString("first-name")
			secondName := argetr.GetString("second-name")
			if argetr.Err == nil {
				//Below should only run if it is local mode otherwise should use
				//the not yet implemented REST client mode
				err = data.GetDataStore().CreateUser(&data.User{
					Name:       userName,
					FirstName:  firstName,
					SecondName: secondName,
					Email:      email,
				})

			}
			return err
		},
	}
	return cmd
}

func updateUserCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func deleteUserCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func listEndpointsCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func showEndpointCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func createEndpointCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func updateEndpointCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func deleteEndpointCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func listVariablesCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func listVariablesForEndpointCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func showVariableCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func createVariableCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func updateVariableCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func deleteVariableCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func listParametersCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func listParametersForEndpointCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func showParameterCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func createParameterCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func updateParameterCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func deleteParameterCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func listUserGroupsCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func showUserGroupCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func createUserGroupCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func updateUserGroupCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func deleteUserGroupCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func addUserToGroupCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func removeUserFromGroupCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func getUsersInGroupCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func getGroupsForUserCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func clearValuesForVariableCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func getValuesForVariableCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func setPasswordCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}

func updatePasswordCommand() (cmd cli.Command) {
	cmd = cli.Command{
		Name:  "",
		Flags: []cli.Flag{},
		Action: func(ctx *cli.Context) (err error) {
			return err
		},
	}
	return cmd
}
<|endoftext|>


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

package main

import (
	"bytes"
	"testing"
	"text/tabwriter"

	"strings"

	"github.com/golang/dep"
	"github.com/golang/dep/gps"
)

func TestStatusFormatVersion(t *testing.T) {
	t.Parallel()

	tests := map[gps.Version]string{
		nil: "",
		gps.NewBranch("master"):        "branch master",
		gps.NewVersion("1.0.0"):        "1.0.0",
		gps.Revision("flooboofoobooo"): "flooboo",
	}
	for version, expected := range tests {
		str := formatVersion(version)
		if str != expected {
			t.Fatalf("expected '%v', got '%v'", expected, str)
		}
	}
}

func TestBasicLine(t *testing.T) {
	project := dep.Project{}
	aSemverConstraint, _ := gps.NewSemverConstraint("1.2.3")

	tests := []struct {
		name            string
		status          BasicStatus
		wantDotStatus   []string
		wantJSONStatus  []string
		wantTableStatus []string
	}{
		{
			name: "BasicStatus with ProjectRoot only",
			status: BasicStatus{
				ProjectRoot: "github.com/foo/bar",
			},
			wantDotStatus:   []string{`[label="github.com/foo/bar"];`},
			wantJSONStatus:  []string{`"Version":""`, `"Revision":""`},
			wantTableStatus: []string{`github.com/foo/bar                                         0`},
		},
		{
			name: "BasicStatus with Revision",
			status: BasicStatus{
				ProjectRoot: "github.com/foo/bar",
				Revision:    gps.Revision("flooboofoobooo"),
			},
			wantDotStatus:   []string{`[label="github.com/foo/bar\nflooboo"];`},
			wantJSONStatus:  []string{`"Version":""`, `"Revision":"flooboofoobooo"`, `"Constraint":""`},
			wantTableStatus: []string{`github.com/foo/bar                       flooboo           0`},
		},
		{
			name: "BasicStatus with Version and Revision",
			status: BasicStatus{
				ProjectRoot: "github.com/foo/bar",
				Version:     gps.NewVersion("1.0.0"),
				Revision:    gps.Revision("flooboofoobooo"),
			},
			wantDotStatus:   []string{`[label="github.com/foo/bar\n1.0.0"];`},
			wantJSONStatus:  []string{`"Version":"1.0.0"`, `"Revision":"flooboofoobooo"`, `"Constraint":""`},
			wantTableStatus: []string{`github.com/foo/bar              1.0.0    flooboo           0`},
		},
		{
			name: "BasicStatus with Constraint, Version and Revision",
			status: BasicStatus{
				ProjectRoot: "github.com/foo/bar",
				Constraint:  aSemverConstraint,
				Version:     gps.NewVersion("1.0.0"),
				Revision:    gps.Revision("revxyz"),
			},
			wantDotStatus:   []string{`[label="github.com/foo/bar\n1.0.0"];`},
			wantJSONStatus:  []string{`"Revision":"revxyz"`, `"Constraint":"1.2.3"`, `"Version":"1.0.0"`},
			wantTableStatus: []string{`github.com/foo/bar  1.2.3       1.0.0    revxyz            0`},
		},
		{
			name: "BasicStatus with update error",
			status: BasicStatus{
				ProjectRoot: "github.com/foo/bar",
				hasError:    true,
			},
			wantDotStatus:   []string{`[label="github.com/foo/bar"];`},
			wantJSONStatus:  []string{`"Version":""`, `"Revision":""`, `"Latest":"unknown"`},
			wantTableStatus: []string{`github.com/foo/bar                                 unknown  0`},
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			var buf bytes.Buffer

			dotout := &dotOutput{
				p: &project,
				w: &buf,
			}
			dotout.BasicHeader()
			dotout.BasicLine(&test.status)
			dotout.BasicFooter()

			for _, wantStatus := range test.wantDotStatus {
				if ok := strings.Contains(buf.String(), wantStatus); !ok {
					t.Errorf("Did not find expected node status: \n\t(GOT) %v \n\t(WNT) %v", buf.String(), wantStatus)
				}
			}

			buf.Reset()

			jsonout := &jsonOutput{w: &buf}

			jsonout.BasicHeader()
			jsonout.BasicLine(&test.status)
			jsonout.BasicFooter()

			for _, wantStatus := range test.wantJSONStatus {
				if ok := strings.Contains(buf.String(), wantStatus); !ok {
					t.Errorf("Did not find expected JSON status: \n\t(GOT) %v \n\t(WNT) %v", buf.String(), wantStatus)
				}
			}

			buf.Reset()

			tabw := tabwriter.NewWriter(&buf, 0, 4, 2, ' ', 0)

			tableout := &tableOutput{w: tabw}

			tableout.BasicHeader()
			tableout.BasicLine(&test.status)
			tableout.BasicFooter()

			for _, wantStatus := range test.wantTableStatus {
				if ok := strings.Contains(buf.String(), wantStatus); !ok {
					t.Errorf("Did not find expected Table status: \n\t(GOT) %v \n\t(WNT) %v", buf.String(), wantStatus)
				}
			}
		})
	}
}

func TestBasicStatusGetConsolidatedConstraint(t *testing.T) {
	aSemverConstraint, _ := gps.NewSemverConstraint("1.2.1")

	testCases := []struct {
		name           string
		basicStatus    BasicStatus
		wantConstraint string
	}{
		{
			name:           "empty BasicStatus",
			basicStatus:    BasicStatus{},
			wantConstraint: "",
		},
		{
			name: "BasicStatus with Any Constraint",
			basicStatus: BasicStatus{
				Constraint: gps.Any(),
			},
			wantConstraint: "*",
		},
		{
			name: "BasicStatus with Semver Constraint",
			basicStatus: BasicStatus{
				Constraint: aSemverConstraint,
			},
			wantConstraint: "1.2.1",
		},
		{
			name: "BasicStatus with Override",
			basicStatus: BasicStatus{
				Constraint:  aSemverConstraint,
				hasOverride: true,
			},
			wantConstraint: "1.2.1 (override)",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			if tc.basicStatus.getConsolidatedConstraint() != tc.wantConstraint {
				t.Errorf("unexpected consolidated constraint: \n\t(GOT) %v \n\t(WNT) %v", tc.basicStatus.getConsolidatedConstraint(), tc.wantConstraint)
			}
		})
	}
}

func TestBasicStatusGetConsolidatedVersion(t *testing.T) {
	testCases := []struct {
		name        string
		basicStatus BasicStatus
		wantVersion string
	}{
		{
			name:        "empty BasicStatus",
			basicStatus: BasicStatus{},
			wantVersion: "",
		},
		{
			name: "BasicStatus with Version and Revision",
			basicStatus: BasicStatus{
				Version:  gps.NewVersion("1.0.0"),
				Revision: gps.Revision("revxyz"),
			},
			wantVersion: "1.0.0",
		},
		{
			name: "BasicStatus with only Revision",
			basicStatus: BasicStatus{
				Revision: gps.Revision("revxyz"),
			},
			wantVersion: "revxyz",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			if tc.basicStatus.getConsolidatedVersion() != tc.wantVersion {
				t.Errorf("unexpected consolidated version: \n\t(GOT) %v \n\t(WNT) %v", tc.basicStatus.getConsolidatedVersion(), tc.wantVersion)
			}
		})
	}
}

func TestBasicStatusGetConsolidatedLatest(t *testing.T) {
	testCases := []struct {
		name        string
		basicStatus BasicStatus
		revSize     uint8
		wantLatest  string
	}{
		{
			name:        "empty BasicStatus",
			basicStatus: BasicStatus{},
			revSize:     shortRev,
			wantLatest:  "",
		},
		{
			name: "nil latest",
			basicStatus: BasicStatus{
				Latest: nil,
			},
			revSize:    shortRev,
			wantLatest: "",
		},
		{
			name: "with error",
			basicStatus: BasicStatus{
				hasError: true,
			},
			revSize:    shortRev,
			wantLatest: "unknown",
		},
		{
			name: "short latest",
			basicStatus: BasicStatus{
				Latest: gps.Revision("adummylonglongrevision"),
			},
			revSize:    shortRev,
			wantLatest: "adummyl",
		},
		{
			name: "long latest",
			basicStatus: BasicStatus{
				Latest: gps.Revision("adummylonglongrevision"),
			},
			revSize:    longRev,
			wantLatest: "adummylonglongrevision",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			gotRev := tc.basicStatus.getConsolidatedLatest(tc.revSize)
			if gotRev != tc.wantLatest {
				t.Errorf("unexpected consolidated latest: \n\t(GOT) %v \n\t(WNT) %v", gotRev, tc.wantLatest)
			}
		})
	}
}
<commit_msg>test(status): Add TestCollectConstraints<commit_after>// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"io/ioutil"
	"log"
	"reflect"
	"testing"
	"text/tabwriter"

	"strings"

	"github.com/golang/dep"
	"github.com/golang/dep/gps"
	"github.com/golang/dep/internal/test"
)

func TestStatusFormatVersion(t *testing.T) {
	t.Parallel()

	tests := map[gps.Version]string{
		nil: "",
		gps.NewBranch("master"):        "branch master",
		gps.NewVersion("1.0.0"):        "1.0.0",
		gps.Revision("flooboofoobooo"): "flooboo",
	}
	for version, expected := range tests {
		str := formatVersion(version)
		if str != expected {
			t.Fatalf("expected '%v', got '%v'", expected, str)
		}
	}
}

func TestBasicLine(t *testing.T) {
	project := dep.Project{}
	aSemverConstraint, _ := gps.NewSemverConstraint("1.2.3")

	tests := []struct {
		name            string
		status          BasicStatus
		wantDotStatus   []string
		wantJSONStatus  []string
		wantTableStatus []string
	}{
		{
			name: "BasicStatus with ProjectRoot only",
			status: BasicStatus{
				ProjectRoot: "github.com/foo/bar",
			},
			wantDotStatus:   []string{`[label="github.com/foo/bar"];`},
			wantJSONStatus:  []string{`"Version":""`, `"Revision":""`},
			wantTableStatus: []string{`github.com/foo/bar                                         0`},
		},
		{
			name: "BasicStatus with Revision",
			status: BasicStatus{
				ProjectRoot: "github.com/foo/bar",
				Revision:    gps.Revision("flooboofoobooo"),
			},
			wantDotStatus:   []string{`[label="github.com/foo/bar\nflooboo"];`},
			wantJSONStatus:  []string{`"Version":""`, `"Revision":"flooboofoobooo"`, `"Constraint":""`},
			wantTableStatus: []string{`github.com/foo/bar                       flooboo           0`},
		},
		{
			name: "BasicStatus with Version and Revision",
			status: BasicStatus{
				ProjectRoot: "github.com/foo/bar",
				Version:     gps.NewVersion("1.0.0"),
				Revision:    gps.Revision("flooboofoobooo"),
			},
			wantDotStatus:   []string{`[label="github.com/foo/bar\n1.0.0"];`},
			wantJSONStatus:  []string{`"Version":"1.0.0"`, `"Revision":"flooboofoobooo"`, `"Constraint":""`},
			wantTableStatus: []string{`github.com/foo/bar              1.0.0    flooboo           0`},
		},
		{
			name: "BasicStatus with Constraint, Version and Revision",
			status: BasicStatus{
				ProjectRoot: "github.com/foo/bar",
				Constraint:  aSemverConstraint,
				Version:     gps.NewVersion("1.0.0"),
				Revision:    gps.Revision("revxyz"),
			},
			wantDotStatus:   []string{`[label="github.com/foo/bar\n1.0.0"];`},
			wantJSONStatus:  []string{`"Revision":"revxyz"`, `"Constraint":"1.2.3"`, `"Version":"1.0.0"`},
			wantTableStatus: []string{`github.com/foo/bar  1.2.3       1.0.0    revxyz            0`},
		},
		{
			name: "BasicStatus with update error",
			status: BasicStatus{
				ProjectRoot: "github.com/foo/bar",
				hasError:    true,
			},
			wantDotStatus:   []string{`[label="github.com/foo/bar"];`},
			wantJSONStatus:  []string{`"Version":""`, `"Revision":""`, `"Latest":"unknown"`},
			wantTableStatus: []string{`github.com/foo/bar                                 unknown  0`},
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			var buf bytes.Buffer

			dotout := &dotOutput{
				p: &project,
				w: &buf,
			}
			dotout.BasicHeader()
			dotout.BasicLine(&test.status)
			dotout.BasicFooter()

			for _, wantStatus := range test.wantDotStatus {
				if ok := strings.Contains(buf.String(), wantStatus); !ok {
					t.Errorf("Did not find expected node status: \n\t(GOT) %v \n\t(WNT) %v", buf.String(), wantStatus)
				}
			}

			buf.Reset()

			jsonout := &jsonOutput{w: &buf}

			jsonout.BasicHeader()
			jsonout.BasicLine(&test.status)
			jsonout.BasicFooter()

			for _, wantStatus := range test.wantJSONStatus {
				if ok := strings.Contains(buf.String(), wantStatus); !ok {
					t.Errorf("Did not find expected JSON status: \n\t(GOT) %v \n\t(WNT) %v", buf.String(), wantStatus)
				}
			}

			buf.Reset()

			tabw := tabwriter.NewWriter(&buf, 0, 4, 2, ' ', 0)

			tableout := &tableOutput{w: tabw}

			tableout.BasicHeader()
			tableout.BasicLine(&test.status)
			tableout.BasicFooter()

			for _, wantStatus := range test.wantTableStatus {
				if ok := strings.Contains(buf.String(), wantStatus); !ok {
					t.Errorf("Did not find expected Table status: \n\t(GOT) %v \n\t(WNT) %v", buf.String(), wantStatus)
				}
			}
		})
	}
}

func TestBasicStatusGetConsolidatedConstraint(t *testing.T) {
	aSemverConstraint, _ := gps.NewSemverConstraint("1.2.1")

	testCases := []struct {
		name           string
		basicStatus    BasicStatus
		wantConstraint string
	}{
		{
			name:           "empty BasicStatus",
			basicStatus:    BasicStatus{},
			wantConstraint: "",
		},
		{
			name: "BasicStatus with Any Constraint",
			basicStatus: BasicStatus{
				Constraint: gps.Any(),
			},
			wantConstraint: "*",
		},
		{
			name: "BasicStatus with Semver Constraint",
			basicStatus: BasicStatus{
				Constraint: aSemverConstraint,
			},
			wantConstraint: "1.2.1",
		},
		{
			name: "BasicStatus with Override",
			basicStatus: BasicStatus{
				Constraint:  aSemverConstraint,
				hasOverride: true,
			},
			wantConstraint: "1.2.1 (override)",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			if tc.basicStatus.getConsolidatedConstraint() != tc.wantConstraint {
				t.Errorf("unexpected consolidated constraint: \n\t(GOT) %v \n\t(WNT) %v", tc.basicStatus.getConsolidatedConstraint(), tc.wantConstraint)
			}
		})
	}
}

func TestBasicStatusGetConsolidatedVersion(t *testing.T) {
	testCases := []struct {
		name        string
		basicStatus BasicStatus
		wantVersion string
	}{
		{
			name:        "empty BasicStatus",
			basicStatus: BasicStatus{},
			wantVersion: "",
		},
		{
			name: "BasicStatus with Version and Revision",
			basicStatus: BasicStatus{
				Version:  gps.NewVersion("1.0.0"),
				Revision: gps.Revision("revxyz"),
			},
			wantVersion: "1.0.0",
		},
		{
			name: "BasicStatus with only Revision",
			basicStatus: BasicStatus{
				Revision: gps.Revision("revxyz"),
			},
			wantVersion: "revxyz",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			if tc.basicStatus.getConsolidatedVersion() != tc.wantVersion {
				t.Errorf("unexpected consolidated version: \n\t(GOT) %v \n\t(WNT) %v", tc.basicStatus.getConsolidatedVersion(), tc.wantVersion)
			}
		})
	}
}

func TestBasicStatusGetConsolidatedLatest(t *testing.T) {
	testCases := []struct {
		name        string
		basicStatus BasicStatus
		revSize     uint8
		wantLatest  string
	}{
		{
			name:        "empty BasicStatus",
			basicStatus: BasicStatus{},
			revSize:     shortRev,
			wantLatest:  "",
		},
		{
			name: "nil latest",
			basicStatus: BasicStatus{
				Latest: nil,
			},
			revSize:    shortRev,
			wantLatest: "",
		},
		{
			name: "with error",
			basicStatus: BasicStatus{
				hasError: true,
			},
			revSize:    shortRev,
			wantLatest: "unknown",
		},
		{
			name: "short latest",
			basicStatus: BasicStatus{
				Latest: gps.Revision("adummylonglongrevision"),
			},
			revSize:    shortRev,
			wantLatest: "adummyl",
		},
		{
			name: "long latest",
			basicStatus: BasicStatus{
				Latest: gps.Revision("adummylonglongrevision"),
			},
			revSize:    longRev,
			wantLatest: "adummylonglongrevision",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			gotRev := tc.basicStatus.getConsolidatedLatest(tc.revSize)
			if gotRev != tc.wantLatest {
				t.Errorf("unexpected consolidated latest: \n\t(GOT) %v \n\t(WNT) %v", gotRev, tc.wantLatest)
			}
		})
	}
}

func TestCollectConstraints(t *testing.T) {
	ver1, _ := gps.NewSemverConstraintIC("v1.0.0")
	ver08, _ := gps.NewSemverConstraintIC("v0.8.0")
	ver2, _ := gps.NewSemverConstraintIC("v2.0.0")

	cases := []struct {
		name            string
		project         dep.Project
		wantConstraints map[string][]gps.Constraint
	}{
		{
			name: "without any constraints",
			project: dep.Project{
				Lock: &dep.Lock{
					P: []gps.LockedProject{
						gps.NewLockedProject(
							gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/sdboyer/deptest")},
							gps.NewVersion("v1.0.0"),
							[]string{"."},
						),
					},
				},
			},
			wantConstraints: map[string][]gps.Constraint{},
		},
		{
			name: "with multiple constraints",
			project: dep.Project{
				Lock: &dep.Lock{
					P: []gps.LockedProject{
						gps.NewLockedProject(
							gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/sdboyer/deptest")},
							gps.NewVersion("v1.0.0"),
							[]string{"."},
						),
						gps.NewLockedProject(
							gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/darkowlzz/deptest-project-1")},
							gps.NewVersion("v0.1.0"),
							[]string{"."},
						),
						gps.NewLockedProject(
							gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/darkowlzz/deptest-project-2")},
							gps.NewBranch("master").Pair(gps.Revision("824a8d56a4c6b2f4718824a98cd6d70d3dbd4c3e")),
							[]string{"."},
						),
					},
				},
			},
			wantConstraints: map[string][]gps.Constraint{
				"github.com/sdboyer/deptest":    []gps.Constraint{ver1, ver08},
				"github.com/sdboyer/deptestdos": []gps.Constraint{ver2},
				"github.com/sdboyer/dep-test":   []gps.Constraint{ver1},
			},
		},
		{
			name: "skip projects with invalid versions",
			project: dep.Project{
				Lock: &dep.Lock{
					P: []gps.LockedProject{
						gps.NewLockedProject(
							gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/darkowlzz/deptest-project-1")},
							gps.NewVersion("v0.1.0"),
							[]string{"."},
						),
						gps.NewLockedProject(
							gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/darkowlzz/deptest-project-2")},
							gps.NewVersion("v1.0.0"),
							[]string{"."},
						),
					},
				},
			},
			wantConstraints: map[string][]gps.Constraint{
				"github.com/sdboyer/deptest": []gps.Constraint{ver1},
			},
		},
	}

	h := test.NewHelper(t)
	defer h.Cleanup()

	h.TempDir("src")
	pwd := h.Path(".")
	discardLogger := log.New(ioutil.Discard, "", 0)

	ctx := &dep.Ctx{
		GOPATH: pwd,
		Out:    discardLogger,
		Err:    discardLogger,
	}

	sm, err := ctx.SourceManager()
	h.Must(err)
	defer sm.Release()

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			gotConstraints := collectConstraints(ctx, &c.project, sm)

			if !reflect.DeepEqual(gotConstraints, c.wantConstraints) {
				t.Fatalf("Unexpected collected constraints: \n\t(GOT): %v\n\t(WNT): %v", gotConstraints, c.wantConstraints)
			}
		})
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"net/url"
	"os"
	"runtime"
	"runtime/pprof"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/belogik/goes"
	"github.com/miku/dupsquash"
)

type Work struct {
	Indices    []string
	Connection dupsquash.SearchConnection

	Fields        []string
	LikeText      string
	MinTermFreq   int
	MaxQueryTerms int
	Size          int

	Values []string
}

func Worker(in chan *Work, out chan [][]string, wg *sync.WaitGroup) {
	defer wg.Done()
	for work := range in {
		var query = map[string]interface{}{
			"query": map[string]interface{}{
				"more_like_this": map[string]interface{}{
					"fields":          work.Fields,
					"like_text":       work.LikeText,
					"min_term_freq":   work.MinTermFreq,
					"max_query_terms": work.MaxQueryTerms,
				},
			},
			"size": work.Size,
		}
		queryResults := Query(work.Connection, &work.Indices, &query)
		var results [][]string
		for _, result := range queryResults {
			parts := append(work.Values, result...)
			results = append(results, parts)
		}
		out <- results
	}
}

// FanInWriter writes the channel content to the writer
func FanInWriter(writer io.Writer, in chan [][]string, done chan bool) {
	for results := range in {
		for _, result := range results {
			writer.Write([]byte(strings.Join(result, "\t")))
			writer.Write([]byte("\n"))
		}
	}
	done <- true
}

// Query runs `query` over connection `conn` on `indices` and returns a slice of string slices
func Query(conn dupsquash.SearchConnection, indices *[]string, query *map[string]interface{}) [][]string {
	extraArgs := make(url.Values, 1)
	searchResults, err := conn.Search(*query, *indices, []string{""}, extraArgs)
	if err != nil {
		log.Fatalln(err)
	}
	results := make([][]string, len(searchResults.Hits.Hits))
	for i, hit := range searchResults.Hits.Hits {
		results[i] = []string{hit.Index, hit.Type, hit.Id, strconv.FormatFloat(hit.Score, 'f', 3, 64)}
	}
	return results
}

func main() {

	esHost := flag.String("host", "localhost", "elasticsearch host")
	esPort := flag.String("port", "9200", "elasticsearch port")
	likeText := flag.String("like", "", "more like this queries like-text")
	likeFile := flag.String("file", "", "input file")
	fileColumn := flag.String("columns", "1", "which column to use as like-text")
	columnDelimiter := flag.String("delimiter", "\t", "column delimiter of the input file")
	columnNull := flag.String("null", "<NULL>", "column value to ignore")
	indicesString := flag.String("indices", "", "index or indices to query")
	indexFields := flag.String("fields", "content.245.a content.245.b", "index fields to query")
	minTermFreq := flag.Int("min-term-freq", 1, "min term frequency")
	maxQueryTerms := flag.Int("max-query-terms", 25, "max query terms")
	size := flag.Int("size", 5, "maximum number of similar records to report")
	numWorkers := flag.Int("workers", runtime.NumCPU(), "number of workers to use")
	version := flag.Bool("v", false, "prints current program version")
	cpuprofile := flag.String("cpuprofile", "", "write cpu profile to file")

	var PrintUsage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [OPTIONS]\n", os.Args[0])
		flag.PrintDefaults()
	}

	flag.Parse()

	if *version {
		fmt.Printf("%s\n", dupsquash.AppVersion)
		return
	}

	if *likeText == "" && *likeFile == "" {
		PrintUsage()
		os.Exit(1)
	}

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	runtime.GOMAXPROCS(*numWorkers)

	conn := goes.NewConnection(*esHost, *esPort)
	fields := strings.Fields(*indexFields)
	indices := strings.Fields(*indicesString)

	if *likeFile != "" {
		if _, err := os.Stat(*likeFile); os.IsNotExist(err) {
			log.Fatalf("no such file or directory: %s\n", *likeFile)
		}

		file, err := os.Open(*likeFile)
		if err != nil {
			log.Fatal(err)
		}
		defer file.Close()

		scanner := bufio.NewScanner(file)
		projector, err := dupsquash.ParseIndices(*fileColumn)
		if err != nil {
			log.Fatalf("could not parse column indices: %s\n", *fileColumn)
		}

		queue := make(chan *Work)
		results := make(chan [][]string)
		done := make(chan bool)

		writer := bufio.NewWriter(os.Stdout)
		defer writer.Flush()
		go FanInWriter(writer, results, done)

		var wg sync.WaitGroup
		for i := 0; i < *numWorkers; i++ {
			wg.Add(1)
			go Worker(queue, results, &wg)
		}

		for scanner.Scan() {
			values := strings.Split(scanner.Text(), *columnDelimiter)
			likeText, err := dupsquash.ConcatenateValuesNull(values, projector, *columnNull)
			if err != nil {
				log.Fatal(err)
			}

			work := Work{
				Indices:       indices,
				Connection:    conn,
				Fields:        fields,
				LikeText:      likeText,
				MinTermFreq:   *minTermFreq,
				MaxQueryTerms: *maxQueryTerms,
				Size:          *size,
				Values:        values,
			}
			queue <- &work
		}

		if err := scanner.Err(); err != nil {
			log.Fatal(err)
		}

		close(queue)
		wg.Wait()
		close(results)
		select {
		case <-time.After(1e9):
			break
		case <-done:
			break
		}
		return
	}

	if *likeText != "" {
		var query = map[string]interface{}{
			"query": map[string]interface{}{
				"more_like_this": map[string]interface{}{
					"fields":          fields,
					"like_text":       *likeText,
					"min_term_freq":   *minTermFreq,
					"max_query_terms": *maxQueryTerms,
				},
			},
			"size": *size,
		}

		results := Query(conn, &indices, &query)
		for _, result := range results {
			fmt.Println(strings.Join(result, "\t"))
		}
		return
	}
}
<commit_msg>reworked query to return source values as well<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"net/url"
	"os"
	"runtime"
	"runtime/pprof"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/belogik/goes"
	"github.com/miku/dupsquash"
)

type Work struct {
	Indices    []string
	Connection dupsquash.SearchConnection

	NullValue     string
	Fields        []string
	LikeText      string
	MinTermFreq   int
	MaxQueryTerms int
	Size          int

	Values []string
}

func Worker(in chan *Work, out chan [][]string, wg *sync.WaitGroup) {
	defer wg.Done()
	for work := range in {
		var query = map[string]interface{}{
			"query": map[string]interface{}{
				"more_like_this": map[string]interface{}{
					"fields":          work.Fields,
					"like_text":       work.LikeText,
					"min_term_freq":   work.MinTermFreq,
					"max_query_terms": work.MaxQueryTerms,
				},
			},
			"size": work.Size,
		}
		queryResults := QueryField(work, &query)
		var results [][]string
		for _, result := range queryResults {
			parts := append(work.Values, result...)
			results = append(results, parts)
		}
		out <- results
	}
}

// FanInWriter writes the channel content to the writer
func FanInWriter(writer io.Writer, in chan [][]string, done chan bool) {
	for results := range in {
		for _, result := range results {
			writer.Write([]byte(strings.Join(result, "\t")))
			writer.Write([]byte("\n"))
		}
	}
	done <- true
}

func QueryField(work *Work, query *map[string]interface{}) [][]string {
	extraArgs := make(url.Values, 1)
	searchResults, err := work.Connection.Search(*query, work.Indices, []string{""}, extraArgs)
	if err != nil {
		log.Fatalln(err)
	}
	var results [][]string
	for _, hit := range searchResults.Hits.Hits {
		var values []string
		for _, field := range work.Fields {
			value := dupsquash.Value(field, hit.Source)
			switch value.(type) {
			case string:
				values = append(values, value.(string))
			case nil:
				values = append(values, work.NullValue)
			default:
				continue
			}
		}
		fields := append([]string{hit.Index, hit.Type, hit.Id, strconv.FormatFloat(hit.Score, 'f', 3, 64)}, values...)
		results = append(results, fields)
	}
	return results
}

func main() {

	esHost := flag.String("host", "localhost", "elasticsearch host")
	esPort := flag.String("port", "9200", "elasticsearch port")
	likeText := flag.String("like", "", "more like this queries like-text")
	likeFile := flag.String("file", "", "input file")
	fileColumn := flag.String("columns", "1", "which column to use as like-text")
	columnDelimiter := flag.String("delimiter", "\t", "column delimiter of the input file")
	columnNull := flag.String("null", "NOT_AVAILABLE", "column value to ignore")
	indicesString := flag.String("indices", "", "index or indices to query")
	indexFields := flag.String("fields", "content.245.a content.245.b", "index fields to query")
	minTermFreq := flag.Int("min-term-freq", 1, "min term frequency")
	maxQueryTerms := flag.Int("max-query-terms", 25, "max query terms")
	size := flag.Int("size", 5, "maximum number of similar records to report")
	numWorkers := flag.Int("workers", runtime.NumCPU(), "number of workers to use")
	version := flag.Bool("v", false, "prints current program version")
	cpuprofile := flag.String("cpuprofile", "", "write cpu profile to file")

	var PrintUsage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [OPTIONS]\n", os.Args[0])
		flag.PrintDefaults()
	}

	flag.Parse()

	if *version {
		fmt.Printf("%s\n", dupsquash.AppVersion)
		return
	}

	if *likeText == "" && *likeFile == "" {
		PrintUsage()
		os.Exit(1)
	}

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	runtime.GOMAXPROCS(*numWorkers)

	conn := goes.NewConnection(*esHost, *esPort)
	fields := strings.Fields(*indexFields)
	indices := strings.Fields(*indicesString)

	if *likeFile != "" {
		if _, err := os.Stat(*likeFile); os.IsNotExist(err) {
			log.Fatalf("no such file or directory: %s\n", *likeFile)
		}

		file, err := os.Open(*likeFile)
		if err != nil {
			log.Fatal(err)
		}
		defer file.Close()

		scanner := bufio.NewScanner(file)
		projector, err := dupsquash.ParseIndices(*fileColumn)
		if err != nil {
			log.Fatalf("could not parse column indices: %s\n", *fileColumn)
		}

		queue := make(chan *Work)
		results := make(chan [][]string)
		done := make(chan bool)

		writer := bufio.NewWriter(os.Stdout)
		defer writer.Flush()
		go FanInWriter(writer, results, done)

		var wg sync.WaitGroup
		for i := 0; i < *numWorkers; i++ {
			wg.Add(1)
			go Worker(queue, results, &wg)
		}

		for scanner.Scan() {
			values := strings.Split(scanner.Text(), *columnDelimiter)
			likeText, err := dupsquash.ConcatenateValuesNull(values, projector, *columnNull)
			if err != nil {
				log.Fatal(err)
			}

			work := Work{
				Indices:       indices,
				Connection:    conn,
				Fields:        fields,
				NullValue:     *columnNull,
				LikeText:      likeText,
				MinTermFreq:   *minTermFreq,
				MaxQueryTerms: *maxQueryTerms,
				Size:          *size,
				Values:        values,
			}
			queue <- &work
		}

		if err := scanner.Err(); err != nil {
			log.Fatal(err)
		}

		close(queue)
		wg.Wait()
		close(results)
		select {
		case <-time.After(1e9):
			break
		case <-done:
			break
		}
		return
	}

	if *likeText != "" {
		var query = map[string]interface{}{
			"query": map[string]interface{}{
				"more_like_this": map[string]interface{}{
					"fields":          fields,
					"like_text":       *likeText,
					"min_term_freq":   *minTermFreq,
					"max_query_terms": *maxQueryTerms,
				},
			},
			"size": *size,
		}

		work := Work{
			Indices:       indices,
			Connection:    conn,
			Fields:        fields,
			NullValue:     *columnNull,
			LikeText:      *likeText,
			MinTermFreq:   *minTermFreq,
			MaxQueryTerms: *maxQueryTerms,
			Size:          *size,
			Values:        []string{},
		}
		results := QueryField(&work, &query)
		for _, result := range results {
			fmt.Println(strings.Join(result, "\t"))
		}
		return
	}
}
<|endoftext|>


<commit_before>/*
 * fscrypt.go - File which starts up and runs the application. Initializes
 * information about the application like the name, version, author, etc...
 *
 * Copyright 2017 Google Inc.
 * Author: Joe Richey (joerichey@google.com)
 *
 * 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.
 */

/*
fscrypt is a command line tool for managing linux filesystem encryption.
*/

// +build linux,cgo

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"time"

	"golang.org/x/sys/unix"

	"github.com/google/fscrypt/security"
	"github.com/urfave/cli"
)

var (
	// Current version of the program (set by Makefile)
	version string
	// Formatted build time (set by Makefile)
	buildTime string
	// Authors to display in the info command
	Authors = []cli.Author{{
		Name:  "Joe Richey",
		Email: "joerichey@google.com",
	}}
)

func main() {
	cli.AppHelpTemplate = appHelpTemplate
	cli.CommandHelpTemplate = commandHelpTemplate
	cli.SubcommandHelpTemplate = subcommandHelpTemplate

	// Create our command line application
	app := cli.NewApp()
	app.Usage = shortUsage
	app.Authors = Authors
	app.Copyright = apache2GoogleCopyright

	// Grab the version and compilation time passed in from the Makefile.
	app.Version = version
	app.Compiled, _ = time.Parse(time.UnixDate, buildTime)
	app.OnUsageError = onUsageError

	// Setup global flags
	cli.HelpFlag = helpFlag
	cli.VersionFlag = versionFlag
	cli.VersionPrinter = func(c *cli.Context) {
		cli.HelpPrinter(c.App.Writer, versionInfoTemplate, c.App)
	}
	app.Flags = universalFlags

	// We hide the help subcommand so that "fscrypt <command> --help" works
	// and "fscrypt <command> help" does not.
	app.HideHelp = true

	// Initialize command list and setup all of the commands.
	app.Action = defaultAction
	app.Commands = []cli.Command{Setup, Encrypt, Unlock, Purge, Status, Metadata}
	for i := range app.Commands {
		setupCommand(&app.Commands[i])
	}

	app.Run(os.Args)
}

// setupCommand performs some common setup for each command. This includes
// hiding the help, formating the description, adding in the necessary
// flags, setting up error handlers, etc... Note that the command is modified
// in place and its subcommands are also setup.
func setupCommand(command *cli.Command) {
	command.Description = wrapText(command.Description, indentLength)
	command.HideHelp = true
	command.Flags = append(command.Flags, universalFlags...)

	if command.Action == nil {
		command.Action = defaultAction
	}

	// Setup function handlers
	command.OnUsageError = onUsageError
	if len(command.Subcommands) == 0 {
		command.Before = setupBefore
	} else {
		// Cleanup subcommands (if applicable)
		for i := range command.Subcommands {
			setupCommand(&command.Subcommands[i])
		}
	}
}

// setupBefore makes sure our logs, errors, and output are going to the correct
// io.Writers and that we haven't over-specified our flags. We only print the
// logs when using verbose, and only print normal stuff when not using quiet.
// When running with sudo, this function also verifies that we have the proper
// keyring linkage enabled.
func setupBefore(c *cli.Context) error {
	log.SetOutput(ioutil.Discard)
	c.App.Writer = ioutil.Discard

	if verboseFlag.Value {
		log.SetOutput(os.Stdout)
	}
	if !quietFlag.Value {
		c.App.Writer = os.Stdout
	}

	if unix.Geteuid() != 0 {
		return nil // Must be root to setup links
	}
	euid, err := strconv.Atoi(os.Getenv("SUDO_UID"))
	if err != nil {
		return nil // Must be running with sudo
	}
	egid, err := strconv.Atoi(os.Getenv("SUDO_GID"))
	if err != nil {
		return nil // Must be running with sudo
	}

	// Dropping and raising privileges checks the needed keyring link.
	privs, err := security.DropThreadPrivileges(euid, egid)
	if err != nil {
		return newExitError(c, err)
	}
	if err := security.RaiseThreadPrivileges(privs); err != nil {
		return newExitError(c, err)
	}
	return nil
}

// defaultAction will be run when no command is specified.
func defaultAction(c *cli.Context) error {
	// Always default to showing the help
	if helpFlag.Value {
		cli.ShowAppHelp(c)
		return nil
	}

	// Only exit when not calling with the help command
	var message string
	if args := c.Args(); args.Present() {
		message = fmt.Sprintf("command \"%s\" not found", args.First())
	} else {
		message = "no command was specified"
	}
	return &usageError{c, message}
}
<commit_msg>cmd/fscrypt: Stop dropping/raising for sudo<commit_after>/*
 * fscrypt.go - File which starts up and runs the application. Initializes
 * information about the application like the name, version, author, etc...
 *
 * Copyright 2017 Google Inc.
 * Author: Joe Richey (joerichey@google.com)
 *
 * 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.
 */

/*
fscrypt is a command line tool for managing linux filesystem encryption.
*/

// +build linux,cgo

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"time"

	"github.com/urfave/cli"
)

var (
	// Current version of the program (set by Makefile)
	version string
	// Formatted build time (set by Makefile)
	buildTime string
	// Authors to display in the info command
	Authors = []cli.Author{{
		Name:  "Joe Richey",
		Email: "joerichey@google.com",
	}}
)

func main() {
	cli.AppHelpTemplate = appHelpTemplate
	cli.CommandHelpTemplate = commandHelpTemplate
	cli.SubcommandHelpTemplate = subcommandHelpTemplate

	// Create our command line application
	app := cli.NewApp()
	app.Usage = shortUsage
	app.Authors = Authors
	app.Copyright = apache2GoogleCopyright

	// Grab the version and compilation time passed in from the Makefile.
	app.Version = version
	app.Compiled, _ = time.Parse(time.UnixDate, buildTime)
	app.OnUsageError = onUsageError

	// Setup global flags
	cli.HelpFlag = helpFlag
	cli.VersionFlag = versionFlag
	cli.VersionPrinter = func(c *cli.Context) {
		cli.HelpPrinter(c.App.Writer, versionInfoTemplate, c.App)
	}
	app.Flags = universalFlags

	// We hide the help subcommand so that "fscrypt <command> --help" works
	// and "fscrypt <command> help" does not.
	app.HideHelp = true

	// Initialize command list and setup all of the commands.
	app.Action = defaultAction
	app.Commands = []cli.Command{Setup, Encrypt, Unlock, Purge, Status, Metadata}
	for i := range app.Commands {
		setupCommand(&app.Commands[i])
	}

	app.Run(os.Args)
}

// setupCommand performs some common setup for each command. This includes
// hiding the help, formating the description, adding in the necessary
// flags, setting up error handlers, etc... Note that the command is modified
// in place and its subcommands are also setup.
func setupCommand(command *cli.Command) {
	command.Description = wrapText(command.Description, indentLength)
	command.HideHelp = true
	command.Flags = append(command.Flags, universalFlags...)

	if command.Action == nil {
		command.Action = defaultAction
	}

	// Setup function handlers
	command.OnUsageError = onUsageError
	if len(command.Subcommands) == 0 {
		command.Before = setupBefore
	} else {
		// Cleanup subcommands (if applicable)
		for i := range command.Subcommands {
			setupCommand(&command.Subcommands[i])
		}
	}
}

// setupBefore makes sure our logs, errors, and output are going to the correct
// io.Writers and that we haven't over-specified our flags. We only print the
// logs when using verbose, and only print normal stuff when not using quiet.
// When running with sudo, this function also verifies that we have the proper
// keyring linkage enabled.
func setupBefore(c *cli.Context) error {
	log.SetOutput(ioutil.Discard)
	c.App.Writer = ioutil.Discard

	if verboseFlag.Value {
		log.SetOutput(os.Stdout)
	}
	if !quietFlag.Value {
		c.App.Writer = os.Stdout
	}
	return nil
}

// defaultAction will be run when no command is specified.
func defaultAction(c *cli.Context) error {
	// Always default to showing the help
	if helpFlag.Value {
		cli.ShowAppHelp(c)
		return nil
	}

	// Only exit when not calling with the help command
	var message string
	if args := c.Args(); args.Present() {
		message = fmt.Sprintf("command \"%s\" not found", args.First())
	} else {
		message = "no command was specified"
	}
	return &usageError{c, message}
}
<|endoftext|>


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

package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"time"
)

var (
	dir    = flag.String("dir", "", "Directory to put data files")
	update = flag.Duration("update", 0, "If non-zero, duratation in past to update from.")
	report = flag.Bool("report", false, "Dump a report")
)

const (
	maxItemsPerPage = 1000

	rvTimeFormat = "2006-01-02 15:04:05"

	// closed=1 means "unknown"
	queryTmpl = "https://codereview.appspot.com/search?closed=1&owner=&{{CC_OR_REVIEWER}}=golang-dev@googlegroups.com&repo_guid=&base=&private=1&created_before=&created_after=&modified_before=&modified_after=&order=-modified&format=json&keys_only=False&with_messages=False&cursor={{CURSOR}}&limit={{LIMIT}}"

	// JSON with the text of messages. e.g.
	// https://codereview.appspot.com/api/6454085?messages=true
	reviewTmpl = "https://codereview.appspot.com/api/{{ISSUE_NUMBER}}?messages=true"
)

// itemsPerPage is the number of items to fetch for a single page.
// Changed by tests.
var itemsPerPage = 100 // maxItemsPerPage

var updatewg = new(sync.WaitGroup)

func main() {
	flag.Parse()
	if *dir == "" {
		log.Fatalf("--dir flag is required.")
	}
	if fi, err := os.Stat(*dir); err != nil || !fi.IsDir() {
		log.Fatalf("Directory %q needs to exist.", *dir)
	}

	if *update != 0 {
		for _, to := range []string{"reviewer", "cc"} {
			updatewg.Add(1)
			go loadReviews(to, updatewg)
		}
		updatewg.Wait()

		for _, r := range allReviews() {
			for _, patchID := range r.PatchSets {
				updatewg.Add(1)
				go func(r *Review, id int) {
					defer updatewg.Done()
					if err := r.LoadPatchMeta(id); err != nil {
						log.Fatal(err)
					}
				}(r, patchID)
			}
		}
		updatewg.Wait()
	}

	if *report {
		open := 0
		closed := 0
		for _, r := range allReviews() {
			if r.Closed {
				closed++
			} else {
				open++
			}
		}
		fmt.Printf("open: %d, closed: %d\n", open, closed)
	}
}

func allReviews() []*Review {
	var ret []*Review
	issueRE := regexp.MustCompile(`^([0-9]+)\.json$`)
	err := filepath.Walk(filepath.Join(*dir, "reviews"), func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if !info.Mode().IsRegular() {
			return nil
		}
		if m := issueRE.FindStringSubmatch(info.Name()); m != nil {
			id, _ := strconv.Atoi(m[1])
			r, err := loadDiskFullReview(id)
			if err != nil {
				return err
			}
			ret = append(ret, r)
		}
		return nil
	})
	if err != nil {
		log.Fatalf("Error loading all issues from disk: %v", err)
	}
	return ret
}

func loadReviews(to string, wg *sync.WaitGroup) {
	defer wg.Done()
	cursor := ""
	oldestWant := time.Now().Add(-*update).Format(rvTimeFormat)
	for {
		url := urlWithParams(queryTmpl, map[string]string{
			"CC_OR_REVIEWER": to,
			"CURSOR":         cursor,
			"LIMIT":          fmt.Sprint(itemsPerPage),
		})
		log.Printf("Fetching %s", url)
		res, err := http.Get(url)
		if err != nil {
			log.Fatal(err)
		}
		var reviews []*Review
		reviews, cursor, err = ParseReviews(res.Body)
		if err != nil {
			log.Fatal(err)
		}
		ngood := 0 // where good means "new enough"
		nold := 0
		for _, r := range reviews {
			if r.Modified >= oldestWant {
				ngood++
				wg.Add(1)
				go updateReview(r, wg)
			} else {
				nold++
			}
		}
		log.Printf("for cursor %q, Got %d reviews (%d in time window, %d old)", cursor, len(reviews), ngood, nold)
		res.Body.Close()
		if cursor == "" || ngood == 0 || nold > 0 {
			break
		}
	}
}

var httpGate = make(chan bool, 25)

func gate() (ungate func()) {
	httpGate <- true
	return func() {
		<-httpGate
	}
}

// updateReview checks to see if r (which lacks comments) has a higher
// modification time than the version we have on disk and if necessary
// fetches the full (with comments) version of r and puts it on disk.
func updateReview(r *Review, wg *sync.WaitGroup) {
	defer wg.Done()
	dr, err := loadDiskFullReview(r.Issue)
	if err == nil && dr.Modified == r.Modified {
		// Nothing to do.
		return
	}
	if err != nil && !os.IsNotExist(err) {
		log.Fatalf("Error loading issue %d: %v", r.Issue, err)
	}

	dstFile := issueDiskPath(r.Issue)
	dir := filepath.Dir(dstFile)
	if err := os.MkdirAll(dir, 0755); err != nil {
		log.Fatal(err)
	}

	defer gate()()

	url := urlWithParams(reviewTmpl, map[string]string{
		"ISSUE_NUMBER": fmt.Sprint(r.Issue),
	})
	log.Printf("Fetching %s", url)
	res, err := http.Get(url)
	if err != nil || res.StatusCode != 200 {
		log.Fatalf("Error fetching %s: %+v, %v", url, res, err)
	}
	defer res.Body.Close()

	if err := writeReadableJSON(dstFile, res.Body); err != nil {
		log.Fatal(err)
	}
}

func writeReadableJSON(dstFile string, r io.Reader) error {
	all, err := ioutil.ReadAll(r)
	if err != nil {
		return err
	}
	var buf bytes.Buffer
	if err := json.Indent(&buf, all, "", "\t"); err != nil {
		log.Fatal(err)
	}

	dir := filepath.Dir(dstFile)
	tf, err := ioutil.TempFile(dir, "tmp")
	if err != nil {
		return err
	}
	_, err = tf.Write(buf.Bytes())
	if err != nil {
		return err
	}
	if err := tf.Close(); err != nil {
		return err
	}
	return os.Rename(tf.Name(), dstFile)
}

func issueDiskPath(id int) string {
	base := fmt.Sprintf("%d.json", id)
	return filepath.Join(*dir, "reviews", base[:3], base)
}

func patchDiskPatch(issue, patch int) string {
	base := fmt.Sprintf("%d-patch-%d.json", issue, patch)
	return filepath.Join(*dir, "reviews", base[:3], base)
}

func loadDiskFullReview(id int) (*Review, error) {
	path := issueDiskPath(id)
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	r := new(Review)
	return r, json.NewDecoder(f).Decode(&r)
}

var urlParam = regexp.MustCompile(`{{\w+}}`)

func urlWithParams(urlTempl string, m map[string]string) string {
	return urlParam.ReplaceAllStringFunc(urlTempl, func(param string) string {
		return url.QueryEscape(m[strings.Trim(param, "{}")])
	})
}

type issueResult struct {
	Closed   bool   `json:"closed"`
	Modified string `json:"modified"`
}

type Message struct {
	Sender string `json:"sender"`
	Text   string `json:"text"`
	Date   string `json:"date"` // "2012-04-07 00:51:58.602055"
}

type byMessageDate []*Message

func (s byMessageDate) Len() int           { return len(s) }
func (s byMessageDate) Less(i, j int) bool { return s[i].Date < s[j].Date }
func (s byMessageDate) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }

type monthQueryResult struct {
	Cursor  string    `json:"cursor"`
	Results []*Review `json:"results"`
}

// Time unmarshals a time in rietveld's format.
type Time time.Time

func (t *Time) UnmarshalJSON(b []byte) error {
	if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' {
		return fmt.Errorf("types: failed to unmarshal non-string value %q as an RFC 3339 time")
	}
	// TODO: pic
	tm, err := time.Parse("2006-01-02 15:04:05", string(b[1:len(b)-1]))
	if err != nil {
		return err
	}
	*t = Time(tm)
	return nil
}

func (t Time) String() string { return time.Time(t).String() }

type Review struct {
	Issue      int        `json:"issue"`
	Desc       string     `json:"description"`
	OwnerEmail string     `json:"owner_email"`
	Owner      string     `json:"owner"`
	Created    Time       `json:"created"`
	Modified   string     `json:"modified"` // just a string; more reliable to do string equality tests on it
	Messages   []*Message `json:"messages"`
	Reviewers  []string   `json:"reviewers"`
	CC         []string   `json:"cc"`
	Closed     bool       `json:"closed"`
	PatchSets  []int      `json:"patchsets"`
}

func ParseReviews(r io.Reader) (reviews []*Review, cursor string, err error) {
	var d monthQueryResult
	err = json.NewDecoder(r).Decode(&d)
	return d.Results, d.Cursor, err
}

// Reviewer returns the email address of an explicit reviewer, if any, else
// returns the empty string.
func (r *Review) Reviewer() string {
	for _, who := range r.Reviewers {
		if strings.HasSuffix(who, "@googlegroups.com") {
			continue
		}
		return who
	}
	return ""
}

func (r *Review) LoadPatchMeta(patch int) error {
	path := patchDiskPatch(r.Issue, patch)
	if fi, err := os.Stat(path); err == nil && fi.Size() != 0 {
		return nil
	}

	defer gate()()

	url := fmt.Sprintf("https://codereview.appspot.com/api/%d/%d", r.Issue, patch)
	log.Printf("Fetching patch %s", url)
	res, err := http.Get(url)
	if err != nil || res.StatusCode != 200 {
		return fmt.Errorf("Error fetching %s (issue %d, patch %d): %+v, %v", url, r.Issue, patch, res, err)
	}
	defer res.Body.Close()

	return writeReadableJSON(path, res.Body)
}
<commit_msg>Simplify<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"time"
)

var (
	dir    = flag.String("dir", "", "Directory to put data files. Optional.")
	update = flag.Bool("update", false, "Whether to update.")
	report = flag.Bool("report", false, "Dump a report")
)

const (
	maxItemsPerPage = 1000

	rvTimeFormat = "2006-01-02 15:04:05"

	// closed=1 means "unknown"
	queryTmpl = "https://codereview.appspot.com/search?closed=1&owner=&{{CC_OR_REVIEWER}}=golang-dev@googlegroups.com&repo_guid=&base=&private=1&created_before=&created_after=&modified_before=&modified_after=&order=-modified&format=json&keys_only=False&with_messages=False&cursor={{CURSOR}}&limit={{LIMIT}}"

	// JSON with the text of messages. e.g.
	// https://codereview.appspot.com/api/6454085?messages=true
	reviewTmpl = "https://codereview.appspot.com/api/{{ISSUE_NUMBER}}?messages=true"
)

// itemsPerPage is the number of items to fetch for a single page.
// Changed by tests.
var itemsPerPage = 100 // maxItemsPerPage

var updatewg = new(sync.WaitGroup)

var reviewMap = map[int]*Review{}

func main() {
	flag.Parse()
	if *dir == "" {
		*dir = findDir()
	}
	if fi, err := os.Stat(*dir); err != nil || !fi.IsDir() {
		log.Fatalf("Directory %q needs to exist.", *dir)
	}

	for _, r := range allReviews() {
		reviewMap[r.Issue] = r
	}

	if *update {
		for _, to := range []string{"reviewer", "cc"} {
			updatewg.Add(1)
			go loadReviews(to, updatewg)
		}
		updatewg.Wait()

		for _, r := range reviewMap {
			for _, patchID := range r.PatchSets {
				updatewg.Add(1)
				go func(r *Review, id int) {
					defer updatewg.Done()
					if err := r.LoadPatchMeta(id); err != nil {
						log.Fatal(err)
					}
				}(r, patchID)
			}
		}
		updatewg.Wait()
	}

	if *report {
		open := 0
		closed := 0
		for _, r := range allReviews() {
			if r.Closed {
				closed++
			} else {
				open++
			}
		}
		fmt.Printf("open: %d, closed: %d\n", open, closed)
	}
}

func findDir() string {
	if os.Getenv("GOPATH") == "" {
		log.Fatalf("No GOPATH. Can't infer -dir flag.")
	}
	for _, d := range filepath.SplitList(os.Getenv("GOPATH")) {
		for _, qdir := range []string{"qopher", "github.com/bradfitz/qopher"} {
			dir := filepath.Join(d, filepath.FromSlash("src/"+qdir+"/data"))
			if fi, err := os.Stat(dir); err == nil && fi.IsDir() {
				return dir
			}
		}
	}
	log.Fatalf("Failed to find qopher dir.")
	panic("")
}

func allReviews() []*Review {
	var ret []*Review
	issueRE := regexp.MustCompile(`^([0-9]+)\.json$`)
	err := filepath.Walk(filepath.Join(*dir, "reviews"), func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if !info.Mode().IsRegular() {
			return nil
		}
		if m := issueRE.FindStringSubmatch(info.Name()); m != nil {
			id, _ := strconv.Atoi(m[1])
			r, err := loadDiskFullReview(id)
			if err != nil {
				return err
			}
			ret = append(ret, r)
		}
		return nil
	})
	if err != nil {
		log.Fatalf("Error loading all issues from disk: %v", err)
	}
	return ret
}

func loadReviews(to string, wg *sync.WaitGroup) {
	defer wg.Done()
	cursor := ""
	for {
		url := urlWithParams(queryTmpl, map[string]string{
			"CC_OR_REVIEWER": to,
			"CURSOR":         cursor,
			"LIMIT":          fmt.Sprint(itemsPerPage),
		})
		log.Printf("Fetching %s", url)
		res, err := http.Get(url)
		if err != nil {
			log.Fatal(err)
		}
		var reviews []*Review
		reviews, cursor, err = ParseReviews(res.Body)
		if err != nil {
			log.Fatal(err)
		}
		var nfetch, nold int
		for _, r := range reviews {
			old := reviewMap[r.Issue]
			if old != nil && old.Modified == r.Modified {
				nold++
			} else {
				nfetch++
				wg.Add(1)
				go updateReview(r, wg)
			}
		}
		log.Printf("for cursor %q, Got %d reviews (%d updated, %d old)", cursor, len(reviews), nfetch, nold)
		res.Body.Close()
		if cursor == "" || len(reviews) == 0 || nold > 0 {
			break
		}
	}
}

var httpGate = make(chan bool, 25)

func gate() (ungate func()) {
	httpGate <- true
	return func() {
		<-httpGate
	}
}

// updateReview checks to see if r (which lacks comments) has a higher
// modification time than the version we have on disk and if necessary
// fetches the full (with comments) version of r and puts it on disk.
func updateReview(r *Review, wg *sync.WaitGroup) {
	defer wg.Done()
	dr, err := loadDiskFullReview(r.Issue)
	if err == nil && dr.Modified == r.Modified {
		// Nothing to do.
		return
	}
	if err != nil && !os.IsNotExist(err) {
		log.Fatalf("Error loading issue %d: %v", r.Issue, err)
	}

	dstFile := issueDiskPath(r.Issue)
	dir := filepath.Dir(dstFile)
	if err := os.MkdirAll(dir, 0755); err != nil {
		log.Fatal(err)
	}

	defer gate()()

	url := urlWithParams(reviewTmpl, map[string]string{
		"ISSUE_NUMBER": fmt.Sprint(r.Issue),
	})
	log.Printf("Fetching %s", url)
	res, err := http.Get(url)
	if err != nil || res.StatusCode != 200 {
		log.Fatalf("Error fetching %s: %+v, %v", url, res, err)
	}
	defer res.Body.Close()

	if err := writeReadableJSON(dstFile, res.Body); err != nil {
		log.Fatal(err)
	}
}

func writeReadableJSON(dstFile string, r io.Reader) error {
	all, err := ioutil.ReadAll(r)
	if err != nil {
		return err
	}
	var buf bytes.Buffer
	if err := json.Indent(&buf, all, "", "\t"); err != nil {
		log.Fatal(err)
	}

	dir := filepath.Dir(dstFile)
	tf, err := ioutil.TempFile(dir, "tmp")
	if err != nil {
		return err
	}
	_, err = tf.Write(buf.Bytes())
	if err != nil {
		return err
	}
	if err := tf.Close(); err != nil {
		return err
	}
	return os.Rename(tf.Name(), dstFile)
}

func issueDiskPath(id int) string {
	base := fmt.Sprintf("%d.json", id)
	return filepath.Join(*dir, "reviews", base[:3], base)
}

func patchDiskPatch(issue, patch int) string {
	base := fmt.Sprintf("%d-patch-%d.json", issue, patch)
	return filepath.Join(*dir, "reviews", base[:3], base)
}

func loadDiskFullReview(id int) (*Review, error) {
	path := issueDiskPath(id)
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	r := new(Review)
	return r, json.NewDecoder(f).Decode(&r)
}

var urlParam = regexp.MustCompile(`{{\w+}}`)

func urlWithParams(urlTempl string, m map[string]string) string {
	return urlParam.ReplaceAllStringFunc(urlTempl, func(param string) string {
		return url.QueryEscape(m[strings.Trim(param, "{}")])
	})
}

type issueResult struct {
	Closed   bool   `json:"closed"`
	Modified string `json:"modified"`
}

type Message struct {
	Sender string `json:"sender"`
	Text   string `json:"text"`
	Date   string `json:"date"` // "2012-04-07 00:51:58.602055"
}

type byMessageDate []*Message

func (s byMessageDate) Len() int           { return len(s) }
func (s byMessageDate) Less(i, j int) bool { return s[i].Date < s[j].Date }
func (s byMessageDate) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }

type monthQueryResult struct {
	Cursor  string    `json:"cursor"`
	Results []*Review `json:"results"`
}

// Time unmarshals a time in rietveld's format.
type Time time.Time

func (t *Time) UnmarshalJSON(b []byte) error {
	if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' {
		return fmt.Errorf("types: failed to unmarshal non-string value %q as an RFC 3339 time")
	}
	// TODO: pic
	tm, err := time.Parse("2006-01-02 15:04:05", string(b[1:len(b)-1]))
	if err != nil {
		return err
	}
	*t = Time(tm)
	return nil
}

func (t Time) String() string { return time.Time(t).String() }

type Review struct {
	Issue      int        `json:"issue"`
	Desc       string     `json:"description"`
	OwnerEmail string     `json:"owner_email"`
	Owner      string     `json:"owner"`
	Created    Time       `json:"created"`
	Modified   string     `json:"modified"` // just a string; more reliable to do string equality tests on it
	Messages   []*Message `json:"messages"`
	Reviewers  []string   `json:"reviewers"`
	CC         []string   `json:"cc"`
	Closed     bool       `json:"closed"`
	PatchSets  []int      `json:"patchsets"`
}

func ParseReviews(r io.Reader) (reviews []*Review, cursor string, err error) {
	var d monthQueryResult
	err = json.NewDecoder(r).Decode(&d)
	return d.Results, d.Cursor, err
}

// Reviewer returns the email address of an explicit reviewer, if any, else
// returns the empty string.
func (r *Review) Reviewer() string {
	for _, who := range r.Reviewers {
		if strings.HasSuffix(who, "@googlegroups.com") {
			continue
		}
		return who
	}
	return ""
}

func (r *Review) LoadPatchMeta(patch int) error {
	path := patchDiskPatch(r.Issue, patch)
	if fi, err := os.Stat(path); err == nil && fi.Size() != 0 {
		return nil
	}

	defer gate()()

	url := fmt.Sprintf("https://codereview.appspot.com/api/%d/%d", r.Issue, patch)
	log.Printf("Fetching patch %s", url)
	res, err := http.Get(url)
	if err != nil || res.StatusCode != 200 {
		return fmt.Errorf("Error fetching %s (issue %d, patch %d): %+v, %v", url, r.Issue, patch, res, err)
	}
	defer res.Body.Close()

	return writeReadableJSON(path, res.Body)
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"

	"github.com/fd0/khepri"
	"github.com/fd0/khepri/backend"
)

func commandList(be backend.Server, key *khepri.Key, args []string) error {
	if len(args) != 1 {
		return errors.New("usage: list [data|trees|snapshots|keys|locks]")
	}

	var (
		t    backend.Type
		each func(backend.Server, backend.Type, func(backend.ID, []byte, error)) error = backend.Each
	)
	switch args[0] {
	case "data":
		t = backend.Data
		each = key.Each
	case "trees":
		t = backend.Tree
		each = key.Each
	case "snapshots":
		t = backend.Snapshot
	case "keys":
		t = backend.Key
	case "locks":
		t = backend.Lock
	default:
		return errors.New("invalid type")
	}

	return each(be, t, func(id backend.ID, data []byte, err error) {
		if t == backend.Data || t == backend.Tree {
			fmt.Printf("%s %s\n", id, backend.Hash(data))
		} else {
			fmt.Printf("%s\n", id)
		}
	})
}
<commit_msg>Add "list maps" command<commit_after>package main

import (
	"errors"
	"fmt"

	"github.com/fd0/khepri"
	"github.com/fd0/khepri/backend"
)

func commandList(be backend.Server, key *khepri.Key, args []string) error {
	if len(args) != 1 {
		return errors.New("usage: list [data|trees|snapshots|keys|locks]")
	}

	var (
		t    backend.Type
		each func(backend.Server, backend.Type, func(backend.ID, []byte, error)) error = backend.Each
	)
	switch args[0] {
	case "data":
		t = backend.Data
		each = key.Each
	case "trees":
		t = backend.Tree
		each = key.Each
	case "snapshots":
		t = backend.Snapshot
	case "maps":
		t = backend.Map
	case "keys":
		t = backend.Key
	case "locks":
		t = backend.Lock
	default:
		return errors.New("invalid type")
	}

	return each(be, t, func(id backend.ID, data []byte, err error) {
		if t == backend.Data || t == backend.Tree {
			fmt.Printf("%s %s\n", id, backend.Hash(data))
		} else {
			fmt.Printf("%s\n", id)
		}
	})
}
<|endoftext|>