<commit_before>package mysqldriver

import (
	"errors"
	"net"

	"github.com/pubnative/mysqlproto-go"
)

type Conn struct {
	stream *mysqlproto.Stream
}

type Stats struct {
	Syscalls int
}

func NewConn(username, password, protocol, address, database string) (Conn, error) {
	conn, err := net.Dial(protocol, address)
	if err != nil {
		return Conn{}, err
	}

	stream := mysqlproto.NewStream(conn)

	if err = handshake(stream, username, password, database); err != nil {
		return Conn{}, err
	}

	if err = setUTF8Charset(stream); err != nil {
		return Conn{}, err
	}

	return Conn{stream}, nil
}

func (c Conn) Close() error {
	return c.stream.Close()
}

func (c Conn) Stats() Stats {
	return Stats{
		Syscalls: c.stream.Syscalls(),
	}
}

func (s Stats) Add(stats Stats) Stats {
	return Stats{
		Syscalls: s.Syscalls + stats.Syscalls,
	}
}

func handshake(stream *mysqlproto.Stream, username, password, database string) error {
	packet, err := mysqlproto.ReadHandshakeV10(stream)
	if err != nil {
		return err
	}

	flags := packet.CapabilityFlags
	flags &= ^mysqlproto.CLIENT_SSL
	flags &= ^mysqlproto.CLIENT_COMPRESS

	res := mysqlproto.HandshakeResponse41(
		packet.CapabilityFlags&(flags),
		packet.CharacterSet,
		username,
		password,
		packet.AuthPluginData,
		database,
		packet.AuthPluginName,
		nil,
	)

	if _, err := stream.Write(res); err != nil {
		return err
	}

	packetOK, err := stream.NextPacket()
	if err != nil {
		return err
	}

	if packetOK.Payload[0] != mysqlproto.PACKET_OK {
		return errors.New("Error occured during handshake with a server")
	}

	return nil
}

func setUTF8Charset(stream *mysqlproto.Stream) error {
	data := mysqlproto.ComQueryRequest([]byte("SET NAMES utf8"))
	if _, err := stream.Write(data); err != nil {
		return err
	}

	packetOK, err := stream.NextPacket()
	if err != nil {
		return err
	}

	if packetOK.Payload[0] != mysqlproto.PACKET_OK {
		return errors.New("Error occured during setting charset")
	}

	return nil
}
<commit_msg>Unsupported capabilities are controlled on a protocol level<commit_after>package mysqldriver

import (
	"errors"
	"net"

	"github.com/pubnative/mysqlproto-go"
)

type Conn struct {
	stream *mysqlproto.Stream
}

type Stats struct {
	Syscalls int
}

func NewConn(username, password, protocol, address, database string) (Conn, error) {
	conn, err := net.Dial(protocol, address)
	if err != nil {
		return Conn{}, err
	}

	stream := mysqlproto.NewStream(conn)

	if err = handshake(stream, username, password, database); err != nil {
		return Conn{}, err
	}

	if err = setUTF8Charset(stream); err != nil {
		return Conn{}, err
	}

	return Conn{stream}, nil
}

func (c Conn) Close() error {
	return c.stream.Close()
}

func (c Conn) Stats() Stats {
	return Stats{
		Syscalls: c.stream.Syscalls(),
	}
}

func (s Stats) Add(stats Stats) Stats {
	return Stats{
		Syscalls: s.Syscalls + stats.Syscalls,
	}
}

func handshake(stream *mysqlproto.Stream, username, password, database string) error {
	packet, err := mysqlproto.ReadHandshakeV10(stream)
	if err != nil {
		return err
	}

	res := mysqlproto.HandshakeResponse41(
		packet.CapabilityFlags,
		packet.CharacterSet,
		username,
		password,
		packet.AuthPluginData,
		database,
		packet.AuthPluginName,
		nil,
	)

	if _, err := stream.Write(res); err != nil {
		return err
	}

	packetOK, err := stream.NextPacket()
	if err != nil {
		return err
	}

	if packetOK.Payload[0] != mysqlproto.PACKET_OK {
		return errors.New("Error occured during handshake with a server")
	}

	return nil
}

func setUTF8Charset(stream *mysqlproto.Stream) error {
	data := mysqlproto.ComQueryRequest([]byte("SET NAMES utf8"))
	if _, err := stream.Write(data); err != nil {
		return err
	}

	packetOK, err := stream.NextPacket()
	if err != nil {
		return err
	}

	if packetOK.Payload[0] != mysqlproto.PACKET_OK {
		return errors.New("Error occured during setting charset")
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"strings"

	"k8s.io/kubernetes/pkg/util/file"

	"github.com/flant/dapp/pkg/build"
	"github.com/flant/dapp/pkg/config"
	"github.com/flant/dapp/pkg/dapp"
	"github.com/flant/dapp/pkg/docker"
	"github.com/flant/dapp/pkg/docker_registry"
	"github.com/flant/dapp/pkg/git_repo"
	"github.com/flant/dapp/pkg/lock"
	"github.com/flant/dapp/pkg/slug"
	"github.com/flant/dapp/pkg/ssh_agent"
)

type buildRubyCliOptions struct {
	Name             string   `json:"name"`
	Dir              string   `json:"dir"`
	BuildDir         string   `json:"build_dir"`
	TmpDirPrefix     string   `json:"tmp_dir_prefix"`
	SSHKey           []string `json:"ssh_key"`
	RegistryUsername string   `json:"registry_username"`
	RegistryPassword string   `json:"registry_password"`
	Registry         string   `json:"repo"`
}

func runBuild(rubyCliOptions buildRubyCliOptions) error {
	if err := lock.Init(); err != nil {
		return err
	}

	if err := ssh_agent.Init(rubyCliOptions.SSHKey); err != nil {
		return fmt.Errorf("cannot initialize ssh-agent: %s", err)
	}

	projectDir, err := getProjectDir(rubyCliOptions)
	if err != nil {
		return fmt.Errorf("getting project dir failed: %s", err)
	}

	projectName, err := getProjectName(projectDir, rubyCliOptions)
	if err != nil {
		return fmt.Errorf("getting project name failed: %s", err)
	}

	buildDir, err := getProjectBuildDir(projectName, rubyCliOptions)
	if err != nil {
		return fmt.Errorf("getting project build dir failed: %s", err)
	}

	tmpDir, err := getProjectTmpDir(rubyCliOptions)
	if err != nil {
		return fmt.Errorf("getting project tmp dir failed: %s", err)
	}

	hostDockerConfigDir, err := hostDockerConfigDir(tmpDir, rubyCliOptions)
	if err != nil {
		return fmt.Errorf("getting host docker config dir failed: %s", err)
	}

	if err := docker.Init(hostDockerConfigDir); err != nil {
		return err
	}

	dappfile, err := parseDappfile(projectDir)
	if err != nil {
		return fmt.Errorf("parsing dappfile failed: %s", err)
	}

	c := build.NewConveyor(dappfile, projectDir, projectName, buildDir, tmpDir)
	if err = c.Build(); err != nil {
		return err
	}

	return nil
}

func parseDappfile(projectDir string) ([]*config.Dimg, error) {
	for _, dappfileName := range []string{"dappfile.yml", "dappfile.yaml"} {
		dappfilePath := path.Join(projectDir, dappfileName)
		if exist, err := file.FileExists(dappfilePath); err != nil {
			return nil, err
		} else if exist {
			return config.ParseDimgs(dappfilePath)
		}
	}

	return nil, errors.New("dappfile.y[a]ml not found")
}

func getProjectDir(rubyCliOptions buildRubyCliOptions) (string, error) {
	if rubyCliOptions.Dir != "" {
		return rubyCliOptions.Dir, nil
	}

	currentDir, err := os.Getwd()
	if err != nil {
		return "", err
	}

	return currentDir, nil
}

func getProjectBuildDir(projectName string, options buildRubyCliOptions) (string, error) {
	if options.BuildDir != "" {
		return options.BuildDir, nil
	} else {
		projectBuildDir := path.Join(dapp.GetHomeDir(), "build", projectName)

		if err := os.MkdirAll(projectBuildDir, os.ModePerm); err != nil {
			return "", err
		}

		return projectBuildDir, nil
	}
}

func getProjectTmpDir(options buildRubyCliOptions) (string, error) {
	var tmpDirPrefix string
	if options.TmpDirPrefix != "" {
		tmpDirPrefix = options.TmpDirPrefix
	} else {
		tmpDirPrefix = "dapp-"
	}

	return ioutil.TempDir("", tmpDirPrefix)
}

func getProjectName(projectDir string, rubyCliOptions buildRubyCliOptions) (string, error) {
	name := path.Base(projectDir)

	if rubyCliOptions.Name != "" {
		name = rubyCliOptions.Name
	} else {
		exist, err := isGitOwnRepoExists(projectDir)
		if err != nil {
			return "", err
		}

		if exist {
			remoteOriginUrl, err := gitOwnRepoOriginUrl(projectDir)
			if err != nil {
				return "", err
			}

			if remoteOriginUrl != "" {
				parts := strings.Split(remoteOriginUrl, "/")
				repoName := parts[len(parts)-1]

				gitEnding := ".git"
				if strings.HasSuffix(repoName, gitEnding) {
					repoName = repoName[0 : len(repoName)-len(gitEnding)]
				}

				name = repoName
			}
		}
	}

	return slug.Slug(name), nil
}

func isGitOwnRepoExists(projectDir string) (bool, error) {
	fileInfo, err := os.Stat(path.Join(projectDir, ".git"))
	if err != nil && os.IsNotExist(err) {
		return false, nil
	}

	return fileInfo.IsDir(), nil
}

func gitOwnRepoOriginUrl(projectDir string) (string, error) {
	localGitRepo := &git_repo.Local{
		Path:   projectDir,
		GitDir: path.Join(projectDir, ".git"),
	}

	remoteOriginUrl, err := localGitRepo.RemoteOriginUrl()
	if err != nil {
		return "", nil
	}

	return remoteOriginUrl, nil
}

func hostDockerConfigDir(projectTmpDir string, rubyCliOptions buildRubyCliOptions) (string, error) {
	dappDockerConfigEnv := os.Getenv("DAPP_DOCKER_CONFIG")

	username, password, err := dockerCredentials(rubyCliOptions)
	if err != nil {
		return "", err
	}
	areDockerCredentialsNotEmpty := username != "" && password != ""

	if areDockerCredentialsNotEmpty && rubyCliOptions.Registry != "" {
		tmpDockerConfigDir := path.Join(projectTmpDir, "docker")

		if err := os.Mkdir(tmpDockerConfigDir, os.ModePerm); err != nil {
			return "", err
		}

		return tmpDockerConfigDir, nil
	} else if dappDockerConfigEnv != "" {
		return dappDockerConfigEnv, nil
	} else {
		return path.Join(os.Getenv("HOME"), ".docker"), nil
	}
}

func dockerCredentials(rubyCliOptions buildRubyCliOptions) (string, string, error) {
	if rubyCliOptions.RegistryUsername != "" && rubyCliOptions.RegistryPassword != "" {
		return rubyCliOptions.RegistryUsername, rubyCliOptions.RegistryPassword, nil
	} else if os.Getenv("DAPP_DOCKER_CONFIG") != "" {
		return "", "", nil
	} else {
		isGCR, err := isGCR(rubyCliOptions)
		if err != nil {
			return "", "", err
		}

		dappIgnoreCIDockerAutologinEnv := os.Getenv("DAPP_IGNORE_CI_DOCKER_AUTOLOGIN")
		if isGCR || dappIgnoreCIDockerAutologinEnv != "" {
			return "", "", nil
		}

		ciRegistryEnv := os.Getenv("CI_REGISTRY")
		ciJobTokenEnv := os.Getenv("CI_JOB_TOKEN")
		if ciRegistryEnv != "" && ciJobTokenEnv != "" {
			return "gitlab-ci-token", ciJobTokenEnv, nil
		}
	}

	return "", "", nil
}

func isGCR(rubyCliOptions buildRubyCliOptions) (bool, error) {
	registryOption := rubyCliOptions.Registry
	if registryOption != "" {
		if registryOption == ":minikube" {
			return false, nil
		}

		return docker_registry.IsGCR(registryOption)
	}

	return false, nil
}
<commit_msg>[go build] init git<commit_after>package main

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"strings"

	"k8s.io/kubernetes/pkg/util/file"

	"github.com/flant/dapp/pkg/build"
	"github.com/flant/dapp/pkg/config"
	"github.com/flant/dapp/pkg/dapp"
	"github.com/flant/dapp/pkg/docker"
	"github.com/flant/dapp/pkg/docker_registry"
	"github.com/flant/dapp/pkg/git_repo"
	"github.com/flant/dapp/pkg/lock"
	"github.com/flant/dapp/pkg/slug"
	"github.com/flant/dapp/pkg/ssh_agent"
	"github.com/flant/dapp/pkg/true_git"
)

type buildRubyCliOptions struct {
	Name             string   `json:"name"`
	Dir              string   `json:"dir"`
	BuildDir         string   `json:"build_dir"`
	TmpDirPrefix     string   `json:"tmp_dir_prefix"`
	SSHKey           []string `json:"ssh_key"`
	RegistryUsername string   `json:"registry_username"`
	RegistryPassword string   `json:"registry_password"`
	Registry         string   `json:"repo"`
}

func runBuild(rubyCliOptions buildRubyCliOptions) error {
	if err := lock.Init(); err != nil {
		return err
	}

	if err := ssh_agent.Init(rubyCliOptions.SSHKey); err != nil {
		return fmt.Errorf("cannot initialize ssh-agent: %s", err)
	}

	if err := true_git.Init(); err != nil {
		return err
	}

	projectDir, err := getProjectDir(rubyCliOptions)
	if err != nil {
		return fmt.Errorf("getting project dir failed: %s", err)
	}

	projectName, err := getProjectName(projectDir, rubyCliOptions)
	if err != nil {
		return fmt.Errorf("getting project name failed: %s", err)
	}

	buildDir, err := getProjectBuildDir(projectName, rubyCliOptions)
	if err != nil {
		return fmt.Errorf("getting project build dir failed: %s", err)
	}

	tmpDir, err := getProjectTmpDir(rubyCliOptions)
	if err != nil {
		return fmt.Errorf("getting project tmp dir failed: %s", err)
	}

	hostDockerConfigDir, err := hostDockerConfigDir(tmpDir, rubyCliOptions)
	if err != nil {
		return fmt.Errorf("getting host docker config dir failed: %s", err)
	}

	if err := docker.Init(hostDockerConfigDir); err != nil {
		return err
	}

	dappfile, err := parseDappfile(projectDir)
	if err != nil {
		return fmt.Errorf("parsing dappfile failed: %s", err)
	}

	c := build.NewConveyor(dappfile, projectDir, projectName, buildDir, tmpDir)
	if err = c.Build(); err != nil {
		return err
	}

	return nil
}

func parseDappfile(projectDir string) ([]*config.Dimg, error) {
	for _, dappfileName := range []string{"dappfile.yml", "dappfile.yaml"} {
		dappfilePath := path.Join(projectDir, dappfileName)
		if exist, err := file.FileExists(dappfilePath); err != nil {
			return nil, err
		} else if exist {
			return config.ParseDimgs(dappfilePath)
		}
	}

	return nil, errors.New("dappfile.y[a]ml not found")
}

func getProjectDir(rubyCliOptions buildRubyCliOptions) (string, error) {
	if rubyCliOptions.Dir != "" {
		return rubyCliOptions.Dir, nil
	}

	currentDir, err := os.Getwd()
	if err != nil {
		return "", err
	}

	return currentDir, nil
}

func getProjectBuildDir(projectName string, options buildRubyCliOptions) (string, error) {
	if options.BuildDir != "" {
		return options.BuildDir, nil
	} else {
		projectBuildDir := path.Join(dapp.GetHomeDir(), "build", projectName)

		if err := os.MkdirAll(projectBuildDir, os.ModePerm); err != nil {
			return "", err
		}

		return projectBuildDir, nil
	}
}

func getProjectTmpDir(options buildRubyCliOptions) (string, error) {
	var tmpDirPrefix string
	if options.TmpDirPrefix != "" {
		tmpDirPrefix = options.TmpDirPrefix
	} else {
		tmpDirPrefix = "dapp-"
	}

	return ioutil.TempDir("", tmpDirPrefix)
}

func getProjectName(projectDir string, rubyCliOptions buildRubyCliOptions) (string, error) {
	name := path.Base(projectDir)

	if rubyCliOptions.Name != "" {
		name = rubyCliOptions.Name
	} else {
		exist, err := isGitOwnRepoExists(projectDir)
		if err != nil {
			return "", err
		}

		if exist {
			remoteOriginUrl, err := gitOwnRepoOriginUrl(projectDir)
			if err != nil {
				return "", err
			}

			if remoteOriginUrl != "" {
				parts := strings.Split(remoteOriginUrl, "/")
				repoName := parts[len(parts)-1]

				gitEnding := ".git"
				if strings.HasSuffix(repoName, gitEnding) {
					repoName = repoName[0 : len(repoName)-len(gitEnding)]
				}

				name = repoName
			}
		}
	}

	return slug.Slug(name), nil
}

func isGitOwnRepoExists(projectDir string) (bool, error) {
	fileInfo, err := os.Stat(path.Join(projectDir, ".git"))
	if err != nil && os.IsNotExist(err) {
		return false, nil
	}

	return fileInfo.IsDir(), nil
}

func gitOwnRepoOriginUrl(projectDir string) (string, error) {
	localGitRepo := &git_repo.Local{
		Path:   projectDir,
		GitDir: path.Join(projectDir, ".git"),
	}

	remoteOriginUrl, err := localGitRepo.RemoteOriginUrl()
	if err != nil {
		return "", nil
	}

	return remoteOriginUrl, nil
}

func hostDockerConfigDir(projectTmpDir string, rubyCliOptions buildRubyCliOptions) (string, error) {
	dappDockerConfigEnv := os.Getenv("DAPP_DOCKER_CONFIG")

	username, password, err := dockerCredentials(rubyCliOptions)
	if err != nil {
		return "", err
	}
	areDockerCredentialsNotEmpty := username != "" && password != ""

	if areDockerCredentialsNotEmpty && rubyCliOptions.Registry != "" {
		tmpDockerConfigDir := path.Join(projectTmpDir, "docker")

		if err := os.Mkdir(tmpDockerConfigDir, os.ModePerm); err != nil {
			return "", err
		}

		return tmpDockerConfigDir, nil
	} else if dappDockerConfigEnv != "" {
		return dappDockerConfigEnv, nil
	} else {
		return path.Join(os.Getenv("HOME"), ".docker"), nil
	}
}

func dockerCredentials(rubyCliOptions buildRubyCliOptions) (string, string, error) {
	if rubyCliOptions.RegistryUsername != "" && rubyCliOptions.RegistryPassword != "" {
		return rubyCliOptions.RegistryUsername, rubyCliOptions.RegistryPassword, nil
	} else if os.Getenv("DAPP_DOCKER_CONFIG") != "" {
		return "", "", nil
	} else {
		isGCR, err := isGCR(rubyCliOptions)
		if err != nil {
			return "", "", err
		}

		dappIgnoreCIDockerAutologinEnv := os.Getenv("DAPP_IGNORE_CI_DOCKER_AUTOLOGIN")
		if isGCR || dappIgnoreCIDockerAutologinEnv != "" {
			return "", "", nil
		}

		ciRegistryEnv := os.Getenv("CI_REGISTRY")
		ciJobTokenEnv := os.Getenv("CI_JOB_TOKEN")
		if ciRegistryEnv != "" && ciJobTokenEnv != "" {
			return "gitlab-ci-token", ciJobTokenEnv, nil
		}
	}

	return "", "", nil
}

func isGCR(rubyCliOptions buildRubyCliOptions) (bool, error) {
	registryOption := rubyCliOptions.Registry
	if registryOption != "" {
		if registryOption == ":minikube" {
			return false, nil
		}

		return docker_registry.IsGCR(registryOption)
	}

	return false, nil
}
<|endoftext|>


<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.

// +build go1.5

// Bundle creates a single-source-file version of a source package
// suitable for inclusion in a particular target package.
//
// Usage:
//
//	bundle [-o file] [-dst path] [-pkg name] [-prefix p] [-import old=new] <src>
//
// The src argument specifies the import path of the package to bundle.
// The bundling of a directory of source files into a single source file
// necessarily imposes a number of constraints.
// The package being bundled must not use cgo; must not use conditional
// file compilation, whether with build tags or system-specific file names
// like code_amd64.go; must not depend on any special comments, which
// may not be preserved; must not use any assembly sources;
// must not use renaming imports; and must not use reflection-based APIs
// that depend on the specific names of types or struct fields.
//
// By default, bundle writes the bundled code to standard output.
// If the -o argument is given, bundle writes to the named file
// and also includes a ``//go:generate'' comment giving the exact
// command line used, for regenerating the file with ``go generate.''
//
// Bundle customizes its output for inclusion in a particular package, the destination package.
// By default bundle assumes the destination is the package in the current directory,
// but the destination package can be specified explicitly using the -dst option,
// which takes an import path as its argument.
// If the source package imports the destination package, bundle will remove
// those imports and rewrite any references to use direct references to the
// corresponding symbols.
// Bundle also must write a package declaration in the output and must
// choose a name to use in that declaration.
// If the -package option is given, bundle uses that name.
// Otherwise, if the -dst option is given, bundle uses the last
// element of the destination import path.
// Otherwise, by default bundle uses the package name found in the
// package sources in the current directory.
//
// To avoid collisions, bundle inserts a prefix at the beginning of
// every package-level const, func, type, and var identifier in src's code,
// updating references accordingly. The default prefix is the package name
// of the source package followed by an underscore. The -prefix option
// specifies an alternate prefix.
//
// Occasionally it is necessary to rewrite imports during the bundling
// process. The -import option, which may be repeated, specifies that
// an import of "old" should be rewritten to import "new" instead.
//
// Example
//
// Bundle archive/zip for inclusion in cmd/dist:
//
//	cd $GOROOT/src/cmd/dist
//	bundle -o zip.go archive/zip
//
// Bundle golang.org/x/net/http2 for inclusion in net/http,
// prefixing all identifiers by "http2" instead of "http2_",
// and rewriting the import "golang.org/x/net/http2/hpack"
// to "internal/golang.org/x/net/http2/hpack":
//
//	cd $GOROOT/src/net/http
//	bundle -o h2_bundle.go \
//		-prefix http2 \
//		-import golang.org/x/net/http2/hpack=internal/golang.org/x/net/http2/hpack \
//		golang.org/x/net/http2
//
// Two ways to update the http2 bundle:
//
//	go generate net/http
//
//	cd $GOROOT/src/net/http
//	go generate
//
// Update both bundles, restricting ``go generate'' to running bundle commands:
//
//	go generate -run bundle cmd/dist net/http
//
package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"go/build"
	"go/format"
	"go/parser"
	"go/token"
	"go/types"
	"io/ioutil"
	"log"
	"os"
	"path"
	"strings"

	"golang.org/x/tools/go/loader"
)

var (
	outputFile = flag.String("o", "", "write output to `file` (default standard output)")
	dstPath    = flag.String("dst", "", "set destination import `path` (default taken from current directory)")
	pkgName    = flag.String("pkg", "", "set destination package `name` (default taken from current directory)")
	prefix     = flag.String("prefix", "", "set bundled identifier prefix to `p` (default source package name + \"_\")")

	importMap = map[string]string{}
)

func init() {
	flag.Var(flagFunc(addImportMap), "import", "rewrite import using `map`, of form old=new (can be repeated)")
}

func addImportMap(s string) {
	if strings.Count(s, "=") != 1 {
		log.Fatal("-import argument must be of the form old=new")
	}
	i := strings.Index(s, "=")
	old, new := s[:i], s[i+1:]
	if old == "" || new == "" {
		log.Fatal("-import argument must be of the form old=new; old and new must be non-empty")
	}
	importMap[old] = new
}

func usage() {
	fmt.Fprintf(os.Stderr, "Usage: bundle [options] <src>\n")
	flag.PrintDefaults()
	os.Exit(2)
}

func main() {
	log.SetPrefix("bundle: ")
	log.SetFlags(0)

	flag.Usage = usage
	flag.Parse()
	args := flag.Args()
	if len(args) != 1 {
		usage()
	}

	if *dstPath != "" {
		if *pkgName == "" {
			*pkgName = path.Base(*dstPath)
		}
	} else {
		wd, _ := os.Getwd()
		pkg, err := build.ImportDir(wd, 0)
		if err != nil {
			log.Fatalf("cannot find package in current directory: %v", err)
		}
		*dstPath = pkg.ImportPath
		if *pkgName == "" {
			*pkgName = pkg.Name
		}
	}

	code, err := bundle(args[0], *dstPath, *pkgName, *prefix)
	if err != nil {
		log.Fatal(err)
	}
	if *outputFile != "" {
		err := ioutil.WriteFile(*outputFile, code, 0666)
		if err != nil {
			log.Fatal(err)
		}
	} else {
		_, err := os.Stdout.Write(code)
		if err != nil {
			log.Fatal(err)
		}
	}
}

// isStandardImportPath is copied from cmd/go in the standard library.
func isStandardImportPath(path string) bool {
	i := strings.Index(path, "/")
	if i < 0 {
		i = len(path)
	}
	elem := path[:i]
	return !strings.Contains(elem, ".")
}

var ctxt = &build.Default

func bundle(src, dst, dstpkg, prefix string) ([]byte, error) {
	// Load the initial package.
	conf := loader.Config{ParserMode: parser.ParseComments, Build: ctxt}
	conf.TypeCheckFuncBodies = func(p string) bool { return p == src }
	conf.Import(src)

	lprog, err := conf.Load()
	if err != nil {
		return nil, err
	}

	info := lprog.Package(src)
	if prefix == "" {
		pkgName := info.Files[0].Name.Name
		prefix = pkgName + "_"
	}

	objsToUpdate := make(map[types.Object]bool)
	var rename func(from types.Object)
	rename = func(from types.Object) {
		if !objsToUpdate[from] {
			objsToUpdate[from] = true

			// Renaming a type that is used as an embedded field
			// requires renaming the field too. e.g.
			// 	type T int // if we rename this to U..
			// 	var s struct {T}
			// 	print(s.T) // ...this must change too
			if _, ok := from.(*types.TypeName); ok {
				for id, obj := range info.Uses {
					if obj == from {
						if field := info.Defs[id]; field != nil {
							rename(field)
						}
					}
				}
			}
		}
	}

	// Rename each package-level object.
	scope := info.Pkg.Scope()
	for _, name := range scope.Names() {
		rename(scope.Lookup(name))
	}

	var out bytes.Buffer

	fmt.Fprintf(&out, "// Code generated by golang.org/x/tools/cmd/bundle.\n")
	if *outputFile != "" {
		fmt.Fprintf(&out, "//go:generate bundle %s\n", strings.Join(os.Args[1:], " "))
	} else {
		fmt.Fprintf(&out, "//   $ bundle %s\n", strings.Join(os.Args[1:], " "))
	}
	fmt.Fprintf(&out, "\n")

	// Concatenate package comments from all files...
	for _, f := range info.Files {
		if doc := f.Doc.Text(); strings.TrimSpace(doc) != "" {
			for _, line := range strings.Split(doc, "\n") {
				fmt.Fprintf(&out, "// %s\n", line)
			}
		}
	}
	// ...but don't let them become the actual package comment.
	fmt.Fprintln(&out)

	fmt.Fprintf(&out, "package %s\n\n", dstpkg)

	// Print a single declaration that imports all necessary packages.
	// TODO(adonovan):
	// - support renaming imports.
	// - preserve comments from the original import declarations.
	for _, f := range info.Files {
		for _, imp := range f.Imports {
			if imp.Name != nil {
				return nil, fmt.Errorf("%s: renaming imports not supported",
					lprog.Fset.Position(imp.Pos()))
			}
		}
	}

	var pkgStd, pkgExt []string
	for _, p := range info.Pkg.Imports() {
		if p.Path() == dst {
			continue
		}
		x, ok := importMap[p.Path()]
		if !ok {
			x = p.Path()
		}
		if isStandardImportPath(x) {
			pkgStd = append(pkgStd, x)
		} else {
			pkgExt = append(pkgExt, x)
		}
	}

	fmt.Fprintln(&out, "import (")
	for _, p := range pkgStd {
		fmt.Fprintf(&out, "\t%q\n", p)
	}
	if len(pkgExt) > 0 {
		fmt.Fprintln(&out)
		for _, p := range pkgExt {
			fmt.Fprintf(&out, "\t%q\n", p)
		}
	}
	fmt.Fprintln(&out, ")\n")

	// Modify and print each file.
	for _, f := range info.Files {
		// Update renamed identifiers.
		for id, obj := range info.Defs {
			if objsToUpdate[obj] {
				id.Name = prefix + obj.Name()
			}
		}
		for id, obj := range info.Uses {
			if objsToUpdate[obj] {
				id.Name = prefix + obj.Name()
			}
		}

		// For each qualified identifier that refers to the
		// destination package, remove the qualifier.
		// The "@@@." strings are removed in postprocessing.
		ast.Inspect(f, func(n ast.Node) bool {
			if sel, ok := n.(*ast.SelectorExpr); ok {
				if id, ok := sel.X.(*ast.Ident); ok {
					if obj, ok := info.Uses[id].(*types.PkgName); ok {
						if obj.Imported().Path() == dst {
							id.Name = "@@@"
						}
					}
				}
			}
			return true
		})

		// Pretty-print package-level declarations.
		// but no package or import declarations.
		//
		// TODO(adonovan): this may cause loss of comments
		// preceding or associated with the package or import
		// declarations or not associated with any declaration.
		// Check.
		var buf bytes.Buffer
		for _, decl := range f.Decls {
			if decl, ok := decl.(*ast.GenDecl); ok && decl.Tok == token.IMPORT {
				continue
			}
			buf.Reset()
			format.Node(&buf, lprog.Fset, decl)
			// Remove each "@@@." in the output.
			// TODO(adonovan): not hygienic.
			out.Write(bytes.Replace(buf.Bytes(), []byte("@@@."), nil, -1))
			out.WriteString("\n\n")
		}
	}

	// Now format the entire thing.
	result, err := format.Source(out.Bytes())
	if err != nil {
		log.Fatalf("formatting failed: %v", err)
	}

	return result, nil
}

type flagFunc func(string)

func (f flagFunc) Set(s string) error {
	f(s)
	return nil
}

func (f flagFunc) String() string { return "" }
<commit_msg>cmd/bundle: More idiomatic flag.Usage.<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.

// +build go1.5

// Bundle creates a single-source-file version of a source package
// suitable for inclusion in a particular target package.
//
// Usage:
//
//	bundle [-o file] [-dst path] [-pkg name] [-prefix p] [-import old=new] <src>
//
// The src argument specifies the import path of the package to bundle.
// The bundling of a directory of source files into a single source file
// necessarily imposes a number of constraints.
// The package being bundled must not use cgo; must not use conditional
// file compilation, whether with build tags or system-specific file names
// like code_amd64.go; must not depend on any special comments, which
// may not be preserved; must not use any assembly sources;
// must not use renaming imports; and must not use reflection-based APIs
// that depend on the specific names of types or struct fields.
//
// By default, bundle writes the bundled code to standard output.
// If the -o argument is given, bundle writes to the named file
// and also includes a ``//go:generate'' comment giving the exact
// command line used, for regenerating the file with ``go generate.''
//
// Bundle customizes its output for inclusion in a particular package, the destination package.
// By default bundle assumes the destination is the package in the current directory,
// but the destination package can be specified explicitly using the -dst option,
// which takes an import path as its argument.
// If the source package imports the destination package, bundle will remove
// those imports and rewrite any references to use direct references to the
// corresponding symbols.
// Bundle also must write a package declaration in the output and must
// choose a name to use in that declaration.
// If the -package option is given, bundle uses that name.
// Otherwise, if the -dst option is given, bundle uses the last
// element of the destination import path.
// Otherwise, by default bundle uses the package name found in the
// package sources in the current directory.
//
// To avoid collisions, bundle inserts a prefix at the beginning of
// every package-level const, func, type, and var identifier in src's code,
// updating references accordingly. The default prefix is the package name
// of the source package followed by an underscore. The -prefix option
// specifies an alternate prefix.
//
// Occasionally it is necessary to rewrite imports during the bundling
// process. The -import option, which may be repeated, specifies that
// an import of "old" should be rewritten to import "new" instead.
//
// Example
//
// Bundle archive/zip for inclusion in cmd/dist:
//
//	cd $GOROOT/src/cmd/dist
//	bundle -o zip.go archive/zip
//
// Bundle golang.org/x/net/http2 for inclusion in net/http,
// prefixing all identifiers by "http2" instead of "http2_",
// and rewriting the import "golang.org/x/net/http2/hpack"
// to "internal/golang.org/x/net/http2/hpack":
//
//	cd $GOROOT/src/net/http
//	bundle -o h2_bundle.go \
//		-prefix http2 \
//		-import golang.org/x/net/http2/hpack=internal/golang.org/x/net/http2/hpack \
//		golang.org/x/net/http2
//
// Two ways to update the http2 bundle:
//
//	go generate net/http
//
//	cd $GOROOT/src/net/http
//	go generate
//
// Update both bundles, restricting ``go generate'' to running bundle commands:
//
//	go generate -run bundle cmd/dist net/http
//
package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"go/build"
	"go/format"
	"go/parser"
	"go/token"
	"go/types"
	"io/ioutil"
	"log"
	"os"
	"path"
	"strings"

	"golang.org/x/tools/go/loader"
)

var (
	outputFile = flag.String("o", "", "write output to `file` (default standard output)")
	dstPath    = flag.String("dst", "", "set destination import `path` (default taken from current directory)")
	pkgName    = flag.String("pkg", "", "set destination package `name` (default taken from current directory)")
	prefix     = flag.String("prefix", "", "set bundled identifier prefix to `p` (default source package name + \"_\")")

	importMap = map[string]string{}
)

func init() {
	flag.Var(flagFunc(addImportMap), "import", "rewrite import using `map`, of form old=new (can be repeated)")
}

func addImportMap(s string) {
	if strings.Count(s, "=") != 1 {
		log.Fatal("-import argument must be of the form old=new")
	}
	i := strings.Index(s, "=")
	old, new := s[:i], s[i+1:]
	if old == "" || new == "" {
		log.Fatal("-import argument must be of the form old=new; old and new must be non-empty")
	}
	importMap[old] = new
}

func usage() {
	fmt.Fprintf(os.Stderr, "Usage: bundle [options] <src>\n")
	flag.PrintDefaults()
}

func main() {
	log.SetPrefix("bundle: ")
	log.SetFlags(0)

	flag.Usage = usage
	flag.Parse()
	args := flag.Args()
	if len(args) != 1 {
		usage()
		os.Exit(2)
	}

	if *dstPath != "" {
		if *pkgName == "" {
			*pkgName = path.Base(*dstPath)
		}
	} else {
		wd, _ := os.Getwd()
		pkg, err := build.ImportDir(wd, 0)
		if err != nil {
			log.Fatalf("cannot find package in current directory: %v", err)
		}
		*dstPath = pkg.ImportPath
		if *pkgName == "" {
			*pkgName = pkg.Name
		}
	}

	code, err := bundle(args[0], *dstPath, *pkgName, *prefix)
	if err != nil {
		log.Fatal(err)
	}
	if *outputFile != "" {
		err := ioutil.WriteFile(*outputFile, code, 0666)
		if err != nil {
			log.Fatal(err)
		}
	} else {
		_, err := os.Stdout.Write(code)
		if err != nil {
			log.Fatal(err)
		}
	}
}

// isStandardImportPath is copied from cmd/go in the standard library.
func isStandardImportPath(path string) bool {
	i := strings.Index(path, "/")
	if i < 0 {
		i = len(path)
	}
	elem := path[:i]
	return !strings.Contains(elem, ".")
}

var ctxt = &build.Default

func bundle(src, dst, dstpkg, prefix string) ([]byte, error) {
	// Load the initial package.
	conf := loader.Config{ParserMode: parser.ParseComments, Build: ctxt}
	conf.TypeCheckFuncBodies = func(p string) bool { return p == src }
	conf.Import(src)

	lprog, err := conf.Load()
	if err != nil {
		return nil, err
	}

	info := lprog.Package(src)
	if prefix == "" {
		pkgName := info.Files[0].Name.Name
		prefix = pkgName + "_"
	}

	objsToUpdate := make(map[types.Object]bool)
	var rename func(from types.Object)
	rename = func(from types.Object) {
		if !objsToUpdate[from] {
			objsToUpdate[from] = true

			// Renaming a type that is used as an embedded field
			// requires renaming the field too. e.g.
			// 	type T int // if we rename this to U..
			// 	var s struct {T}
			// 	print(s.T) // ...this must change too
			if _, ok := from.(*types.TypeName); ok {
				for id, obj := range info.Uses {
					if obj == from {
						if field := info.Defs[id]; field != nil {
							rename(field)
						}
					}
				}
			}
		}
	}

	// Rename each package-level object.
	scope := info.Pkg.Scope()
	for _, name := range scope.Names() {
		rename(scope.Lookup(name))
	}

	var out bytes.Buffer

	fmt.Fprintf(&out, "// Code generated by golang.org/x/tools/cmd/bundle.\n")
	if *outputFile != "" {
		fmt.Fprintf(&out, "//go:generate bundle %s\n", strings.Join(os.Args[1:], " "))
	} else {
		fmt.Fprintf(&out, "//   $ bundle %s\n", strings.Join(os.Args[1:], " "))
	}
	fmt.Fprintf(&out, "\n")

	// Concatenate package comments from all files...
	for _, f := range info.Files {
		if doc := f.Doc.Text(); strings.TrimSpace(doc) != "" {
			for _, line := range strings.Split(doc, "\n") {
				fmt.Fprintf(&out, "// %s\n", line)
			}
		}
	}
	// ...but don't let them become the actual package comment.
	fmt.Fprintln(&out)

	fmt.Fprintf(&out, "package %s\n\n", dstpkg)

	// Print a single declaration that imports all necessary packages.
	// TODO(adonovan):
	// - support renaming imports.
	// - preserve comments from the original import declarations.
	for _, f := range info.Files {
		for _, imp := range f.Imports {
			if imp.Name != nil {
				return nil, fmt.Errorf("%s: renaming imports not supported",
					lprog.Fset.Position(imp.Pos()))
			}
		}
	}

	var pkgStd, pkgExt []string
	for _, p := range info.Pkg.Imports() {
		if p.Path() == dst {
			continue
		}
		x, ok := importMap[p.Path()]
		if !ok {
			x = p.Path()
		}
		if isStandardImportPath(x) {
			pkgStd = append(pkgStd, x)
		} else {
			pkgExt = append(pkgExt, x)
		}
	}

	fmt.Fprintln(&out, "import (")
	for _, p := range pkgStd {
		fmt.Fprintf(&out, "\t%q\n", p)
	}
	if len(pkgExt) > 0 {
		fmt.Fprintln(&out)
		for _, p := range pkgExt {
			fmt.Fprintf(&out, "\t%q\n", p)
		}
	}
	fmt.Fprintln(&out, ")\n")

	// Modify and print each file.
	for _, f := range info.Files {
		// Update renamed identifiers.
		for id, obj := range info.Defs {
			if objsToUpdate[obj] {
				id.Name = prefix + obj.Name()
			}
		}
		for id, obj := range info.Uses {
			if objsToUpdate[obj] {
				id.Name = prefix + obj.Name()
			}
		}

		// For each qualified identifier that refers to the
		// destination package, remove the qualifier.
		// The "@@@." strings are removed in postprocessing.
		ast.Inspect(f, func(n ast.Node) bool {
			if sel, ok := n.(*ast.SelectorExpr); ok {
				if id, ok := sel.X.(*ast.Ident); ok {
					if obj, ok := info.Uses[id].(*types.PkgName); ok {
						if obj.Imported().Path() == dst {
							id.Name = "@@@"
						}
					}
				}
			}
			return true
		})

		// Pretty-print package-level declarations.
		// but no package or import declarations.
		//
		// TODO(adonovan): this may cause loss of comments
		// preceding or associated with the package or import
		// declarations or not associated with any declaration.
		// Check.
		var buf bytes.Buffer
		for _, decl := range f.Decls {
			if decl, ok := decl.(*ast.GenDecl); ok && decl.Tok == token.IMPORT {
				continue
			}
			buf.Reset()
			format.Node(&buf, lprog.Fset, decl)
			// Remove each "@@@." in the output.
			// TODO(adonovan): not hygienic.
			out.Write(bytes.Replace(buf.Bytes(), []byte("@@@."), nil, -1))
			out.WriteString("\n\n")
		}
	}

	// Now format the entire thing.
	result, err := format.Source(out.Bytes())
	if err != nil {
		log.Fatalf("formatting failed: %v", err)
	}

	return result, nil
}

type flagFunc func(string)

func (f flagFunc) Set(s string) error {
	f(s)
	return nil
}

func (f flagFunc) String() string { return "" }
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2020 Sylvain Baubeau
 *
 * 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 ofthe 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 specificlanguage governing permissions and
 * limitations under the License.
 *
 */

package client

import (
	"fmt"
	"os"
	"time"

	"github.com/skydive-project/skydive/api/client"
	"github.com/skydive-project/skydive/api/types"
	api "github.com/skydive-project/skydive/api/types"
	"github.com/skydive-project/skydive/config"
	"github.com/skydive-project/skydive/graffiti/graph"
	"github.com/skydive-project/skydive/graffiti/logging"
	usertopology "github.com/skydive-project/skydive/topology/enhancers"
	"github.com/skydive-project/skydive/validator"

	"github.com/spf13/cobra"
)

var host string

// NodeCmd skydive node rule root command
var NodeCmd = &cobra.Command{
	Use:          "node",
	Short:        "node",
	Long:         "node",
	SilenceUsage: false,
}

// NodeCreate skydive node create command
var NodeCreate = &cobra.Command{
	Use:          "create",
	Short:        "create",
	Long:         "create",
	SilenceUsage: false,

	Run: func(cmd *cobra.Command, args []string) {
		client, err := client.NewCrudClientFromConfig(&AuthenticationOpts)
		if err != nil {
			exitOnError(err)
		}

		m, err := usertopology.DefToMetadata(metadata, graph.Metadata{})
		if err != nil {
			exitOnError(err)
		}

		if nodeName != "" {
			m["Name"] = nodeName
		}

		if nodeType != "" {
			m["Type"] = nodeType
		}

		node := api.Node(*graph.CreateNode(graph.GenID(), m, graph.Time(time.Now()), host, config.AgentService))

		if err = validator.Validate("node", &node); err != nil {
			exitOnError(fmt.Errorf("Error while validating node: %s", err))
		}

		if err = client.Create("node", &node, nil); err != nil {
			exitOnError(err)
		}

		printJSON(node)
	},
}

// NodeList node list command
var NodeList = &cobra.Command{
	Use:   "list",
	Short: "List nodes",
	Long:  "List nodes",
	Run: func(cmd *cobra.Command, args []string) {
		var nodes map[string]types.Node
		client, err := client.NewCrudClientFromConfig(&AuthenticationOpts)
		if err != nil {
			exitOnError(err)
		}
		if err := client.List("node", &nodes); err != nil {
			exitOnError(err)
		}
		printJSON(nodes)
	},
}

// NodeGet node get command
var NodeGet = &cobra.Command{
	Use:   "get [node]",
	Short: "Display node",
	Long:  "Display node",
	PreRun: func(cmd *cobra.Command, args []string) {
		if len(args) == 0 {
			cmd.Usage()
			os.Exit(1)
		}
	},
	Run: func(cmd *cobra.Command, args []string) {
		var node types.Node
		client, err := client.NewCrudClientFromConfig(&AuthenticationOpts)
		if err != nil {
			exitOnError(err)
		}

		if err := client.Get("node", args[0], &node); err != nil {
			exitOnError(err)
		}
		printJSON(&node)
	},
}

// NodeDelete node delete command
var NodeDelete = &cobra.Command{
	Use:   "delete [node]",
	Short: "Delete node",
	Long:  "Delete node",
	PreRun: func(cmd *cobra.Command, args []string) {
		if len(args) == 0 {
			cmd.Usage()
			os.Exit(1)
		}
	},
	Run: func(cmd *cobra.Command, args []string) {
		client, err := client.NewCrudClientFromConfig(&AuthenticationOpts)
		if err != nil {
			exitOnError(err)
		}

		for _, id := range args {
			if err := client.Delete("node", id); err != nil {
				logging.GetLogger().Error(err)
			}
		}
	},
}

func addCreateNodeFlags(cmd *cobra.Command) {
	host, _ = os.Hostname()
	cmd.Flags().StringVarP(&nodeType, "node-type", "", "", "node type")
	cmd.Flags().StringVarP(&metadata, "metadata", "", "", "node metadata, key value pairs. 'k1=v1, k2=v2'")
	cmd.Flags().StringVarP(&metadata, "host", "", host, "host")
}

func init() {
	NodeCmd.AddCommand(NodeList)
	NodeCmd.AddCommand(NodeGet)
	NodeCmd.AddCommand(NodeCreate)
	NodeCmd.AddCommand(NodeDelete)

	addCreateNodeFlags(NodeCreate)
}
<commit_msg>Add missing node-name argument to command line<commit_after>/*
 * Copyright (C) 2020 Sylvain Baubeau
 *
 * 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 ofthe 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 specificlanguage governing permissions and
 * limitations under the License.
 *
 */

package client

import (
	"fmt"
	"os"
	"time"

	"github.com/skydive-project/skydive/api/client"
	"github.com/skydive-project/skydive/api/types"
	api "github.com/skydive-project/skydive/api/types"
	"github.com/skydive-project/skydive/config"
	"github.com/skydive-project/skydive/graffiti/graph"
	"github.com/skydive-project/skydive/graffiti/logging"
	usertopology "github.com/skydive-project/skydive/topology/enhancers"
	"github.com/skydive-project/skydive/validator"

	"github.com/spf13/cobra"
)

var host string

// NodeCmd skydive node rule root command
var NodeCmd = &cobra.Command{
	Use:          "node",
	Short:        "node",
	Long:         "node",
	SilenceUsage: false,
}

// NodeCreate skydive node create command
var NodeCreate = &cobra.Command{
	Use:          "create",
	Short:        "create",
	Long:         "create",
	SilenceUsage: false,

	Run: func(cmd *cobra.Command, args []string) {
		client, err := client.NewCrudClientFromConfig(&AuthenticationOpts)
		if err != nil {
			exitOnError(err)
		}

		m, err := usertopology.DefToMetadata(metadata, graph.Metadata{})
		if err != nil {
			exitOnError(err)
		}

		if nodeName != "" {
			m["Name"] = nodeName
		}

		if nodeType != "" {
			m["Type"] = nodeType
		}

		node := api.Node(*graph.CreateNode(graph.GenID(), m, graph.Time(time.Now()), host, config.AgentService))

		if err = validator.Validate("node", &node); err != nil {
			exitOnError(fmt.Errorf("Error while validating node: %s", err))
		}

		if err = client.Create("node", &node, nil); err != nil {
			exitOnError(err)
		}

		printJSON(node)
	},
}

// NodeList node list command
var NodeList = &cobra.Command{
	Use:   "list",
	Short: "List nodes",
	Long:  "List nodes",
	Run: func(cmd *cobra.Command, args []string) {
		var nodes map[string]types.Node
		client, err := client.NewCrudClientFromConfig(&AuthenticationOpts)
		if err != nil {
			exitOnError(err)
		}
		if err := client.List("node", &nodes); err != nil {
			exitOnError(err)
		}
		printJSON(nodes)
	},
}

// NodeGet node get command
var NodeGet = &cobra.Command{
	Use:   "get [node]",
	Short: "Display node",
	Long:  "Display node",
	PreRun: func(cmd *cobra.Command, args []string) {
		if len(args) == 0 {
			cmd.Usage()
			os.Exit(1)
		}
	},
	Run: func(cmd *cobra.Command, args []string) {
		var node types.Node
		client, err := client.NewCrudClientFromConfig(&AuthenticationOpts)
		if err != nil {
			exitOnError(err)
		}

		if err := client.Get("node", args[0], &node); err != nil {
			exitOnError(err)
		}
		printJSON(&node)
	},
}

// NodeDelete node delete command
var NodeDelete = &cobra.Command{
	Use:   "delete [node]",
	Short: "Delete node",
	Long:  "Delete node",
	PreRun: func(cmd *cobra.Command, args []string) {
		if len(args) == 0 {
			cmd.Usage()
			os.Exit(1)
		}
	},
	Run: func(cmd *cobra.Command, args []string) {
		client, err := client.NewCrudClientFromConfig(&AuthenticationOpts)
		if err != nil {
			exitOnError(err)
		}

		for _, id := range args {
			if err := client.Delete("node", id); err != nil {
				logging.GetLogger().Error(err)
			}
		}
	},
}

func addCreateNodeFlags(cmd *cobra.Command) {
	host, _ = os.Hostname()
	cmd.Flags().StringVarP(&nodeName, "node-name", "", "", "node name")
	cmd.Flags().StringVarP(&nodeType, "node-type", "", "", "node type")
	cmd.Flags().StringVarP(&metadata, "metadata", "", "", "node metadata, key value pairs. 'k1=v1, k2=v2'")
	cmd.Flags().StringVarP(&metadata, "host", "", host, "host")
}

func init() {
	NodeCmd.AddCommand(NodeList)
	NodeCmd.AddCommand(NodeGet)
	NodeCmd.AddCommand(NodeCreate)
	NodeCmd.AddCommand(NodeDelete)

	addCreateNodeFlags(NodeCreate)
}
<|endoftext|>


<commit_before>// Copyright 2021 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 (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/google/go-cmp/cmp"
	"golang.org/x/vulndb/osv"
)

func loadDB(dbPath string) (osv.DBIndex, map[string][]osv.Entry, error) {
	index := osv.DBIndex{}
	dbMap := map[string][]osv.Entry{}

	var loadDir func(string) error
	loadDir = func(path string) error {
		dir, err := ioutil.ReadDir(path)
		if err != nil {
			return err
		}
		for _, f := range dir {
			fpath := filepath.Join(path, f.Name())
			if f.IsDir() {
				if err := loadDir(fpath); err != nil {
					return err
				}
				continue
			}
			content, err := ioutil.ReadFile(fpath)
			if err != nil {
				return err
			}
			if path == dbPath && f.Name() == "index.json" {
				if err := json.Unmarshal(content, &index); err != nil {
					return fmt.Errorf("unable to parse %q: %s", fpath, err)
				}
			} else if path == filepath.Join(dbPath, "byID") {
				var entry osv.Entry
				if err := json.Unmarshal(content, &entry); err != nil {
					return fmt.Errorf("unable to parse %q: %s", fpath, err)
				}
				fname := strings.TrimPrefix(fpath, dbPath)
				dbMap[fname] = []osv.Entry{entry}
			} else {
				var entries []osv.Entry
				if err := json.Unmarshal(content, &entries); err != nil {
					return fmt.Errorf("unable to parse %q: %s", fpath, err)
				}
				module := strings.TrimPrefix(fpath, dbPath)
				dbMap[module] = entries
			}
		}
		return nil
	}
	if err := loadDir(dbPath); err != nil {
		return nil, nil, err
	}
	return index, dbMap, nil
}

func main() {
	if len(os.Args) != 3 {
		fmt.Fprintln(os.Stderr, "usage: dbdiff db-a db-b")
		os.Exit(1)
	}
	indexA, dbA, err := loadDB(os.Args[1])
	if err != nil {
		fmt.Fprintf(os.Stderr, "unable to load %q: %s\n", os.Args[1], err)
		os.Exit(1)
	}
	indexB, dbB, err := loadDB(os.Args[2])
	if err != nil {
		fmt.Fprintf(os.Stderr, "unable to load %q: %s\n", os.Args[2], err)
		os.Exit(1)
	}
	indexDiff := cmp.Diff(indexA, indexB)
	if indexDiff == "" {
		indexDiff = "(no change)"
	}
	dbDiff := cmp.Diff(dbA, dbB)
	if dbDiff == "" {
		dbDiff = "(no change)"
	}
	fmt.Printf("# index\n%s\n\n# db\n%s\n", indexDiff, dbDiff)
}
<commit_msg>cmd/dbdiff: change by-ID directory name<commit_after>// Copyright 2021 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 (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/google/go-cmp/cmp"
	"golang.org/x/vulndb/osv"
)

func loadDB(dbPath string) (osv.DBIndex, map[string][]osv.Entry, error) {
	index := osv.DBIndex{}
	dbMap := map[string][]osv.Entry{}

	var loadDir func(string) error
	loadDir = func(path string) error {
		dir, err := ioutil.ReadDir(path)
		if err != nil {
			return err
		}
		for _, f := range dir {
			fpath := filepath.Join(path, f.Name())
			if f.IsDir() {
				if err := loadDir(fpath); err != nil {
					return err
				}
				continue
			}
			content, err := ioutil.ReadFile(fpath)
			if err != nil {
				return err
			}
			if path == dbPath && f.Name() == "index.json" {
				if err := json.Unmarshal(content, &index); err != nil {
					return fmt.Errorf("unable to parse %q: %s", fpath, err)
				}
			} else if path == filepath.Join(dbPath, "ID") {
				var entry osv.Entry
				if err := json.Unmarshal(content, &entry); err != nil {
					return fmt.Errorf("unable to parse %q: %s", fpath, err)
				}
				fname := strings.TrimPrefix(fpath, dbPath)
				dbMap[fname] = []osv.Entry{entry}
			} else {
				var entries []osv.Entry
				if err := json.Unmarshal(content, &entries); err != nil {
					return fmt.Errorf("unable to parse %q: %s", fpath, err)
				}
				module := strings.TrimPrefix(fpath, dbPath)
				dbMap[module] = entries
			}
		}
		return nil
	}
	if err := loadDir(dbPath); err != nil {
		return nil, nil, err
	}
	return index, dbMap, nil
}

func main() {
	if len(os.Args) != 3 {
		fmt.Fprintln(os.Stderr, "usage: dbdiff db-a db-b")
		os.Exit(1)
	}
	indexA, dbA, err := loadDB(os.Args[1])
	if err != nil {
		fmt.Fprintf(os.Stderr, "unable to load %q: %s\n", os.Args[1], err)
		os.Exit(1)
	}
	indexB, dbB, err := loadDB(os.Args[2])
	if err != nil {
		fmt.Fprintf(os.Stderr, "unable to load %q: %s\n", os.Args[2], err)
		os.Exit(1)
	}
	indexDiff := cmp.Diff(indexA, indexB)
	if indexDiff == "" {
		indexDiff = "(no change)"
	}
	dbDiff := cmp.Diff(dbA, dbB)
	if dbDiff == "" {
		dbDiff = "(no change)"
	}
	fmt.Printf("# index\n%s\n\n# db\n%s\n", indexDiff, dbDiff)
}
<|endoftext|>


<commit_before>/*
Copyright 2018 Harvey OS Team

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors
   may be used to endorse or promote products derived from this software
   without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package main

import (
	"bytes"
	"debug/elf"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"math"
	"os"
	"path"
)

var dry = flag.Bool("dryrun", true, "don't really do it")

func gencode(w io.Writer, n, t string, m []byte, start, end uint64) {
	fmt.Fprintf(os.Stderr, "Write %v %v start %v end %v\n", n, t, start, end)
	fmt.Fprintf(w, "u64 %v_%v_start = %#x;\n", n, t, start)
	fmt.Fprintf(w, "u64 %v_%v_end = %#x;\n", n, t, end)
	fmt.Fprintf(w, "u64 %v_%v_len = %#x;\n", n, t, end-start)
	fmt.Fprintf(w, "u8 %v_%v_out[] = {\n", n, t)
	for i := uint64(start); i < end; i += 16 {
		for j := uint64(0); i+j < end && j < 16; j++ {
			fmt.Fprintf(w, "%#02x, ", m[j+i])
		}
		fmt.Fprintf(w, "\n")
	}
	fmt.Fprintf(w, "};\n")
}
func main() {
	flag.Parse()
	a := flag.Args()
	w := &bytes.Buffer{}
	for _, n := range a[1:] {
		f, err := elf.Open(n)
		if err != nil {
			fmt.Printf("%v %v\n", n, err)
			continue
		}
		var dataend, codeend, end uint64
		var datastart, codestart, start uint64
		datastart, codestart, start = math.MaxUint64, math.MaxUint64, math.MaxUint64
		mem := []byte{}
		for _, v := range f.Progs {
			if v.Type != elf.PT_LOAD {
				continue
			}
			fmt.Fprintf(os.Stderr, "processing %v\n", v)
			// MUST alignt to 2M page boundary.
			// then MUST allocate a []byte that
			// is the right size. And MUST
			// see if by some off chance it
			// joins to a pre-existing segment.
			// It's easier than it seems. We produce ONE text
			// array and ONE data array. So it's a matter of creating
			// a virtual memory space with an assumed starting point of
			// 0x200000, and filling it. We just grow that as needed.

			curstart := v.Vaddr & ^uint64(0xfff) // 0x1fffff)
			curend := v.Vaddr + v.Memsz
			fmt.Fprintf(os.Stderr, "s %x e %x\n", curstart, curend)
			if curend > end {
				nmem := make([]byte, curend)
				copy(nmem, mem)
				mem = nmem
			}
			if curstart < start {
				start = curstart
			}

			if v.Flags&elf.PF_X == elf.PF_X {
				if curstart < codestart {
					codestart = curstart
				}
				if curend > codeend {
					codeend = curend
				}
				fmt.Fprintf(os.Stderr, "code s %v e %v\n", codestart, codeend)
			} else {
				if curstart < datastart {
					datastart = curstart
				}
				if curend > dataend {
					dataend = curend
				}
				fmt.Fprintf(os.Stderr, "data s %v e %v\n", datastart, dataend)
			}
			for i := uint64(0); i < v.Filesz; i++ {
				if amt, err := v.ReadAt(mem[v.Vaddr+i:], int64(i)); err != nil && err != io.EOF {
					fmt.Fprintf(os.Stderr, "%v: %v\n", amt, err)
					os.Exit(1)
				} else if amt == 0 {
					if i < v.Filesz {
						fmt.Fprintf(os.Stderr, "%v: Short read: %v of %v\n", v, i, v.Filesz)
						os.Exit(1)
					}
					break
				} else {
					i = i + uint64(amt)
					fmt.Fprintf(os.Stderr, "i now %v\n", i)
				}
			}
			fmt.Fprintf(os.Stderr, "Processed %v\n", v)
		}
		fmt.Fprintf(os.Stderr, "gencode\n")
		_, file := path.Split(n)
		fmt.Fprintf(w, "uintptr_t %v_main = %v;\n", n, f.Entry)
		gencode(w, file, "code", mem, codestart, codeend)
		gencode(w, file, "data", mem, datastart, dataend)
	}
	if err := ioutil.WriteFile(a[0], w.Bytes(), 0444); err != nil {
		fmt.Fprintf(os.Stderr, "elf2c: write %s failed: %v\n", a[0], err)
	}

}
<commit_msg>Revert "elf2c: fix int overflow"<commit_after>/*
Copyright 2018 Harvey OS Team

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors
   may be used to endorse or promote products derived from this software
   without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package main

import (
	"bytes"
	"debug/elf"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"math"
	"os"
	"path"
)

var dry = flag.Bool("dryrun", true, "don't really do it")

func gencode(w io.Writer, n, t string, m []byte, start, end uint64) {
	fmt.Fprintf(os.Stderr, "Write %v %v start %v end %v\n", n, t, start, end)
	fmt.Fprintf(w, "int %v_%v_start = %v;\n", n, t, start)
	fmt.Fprintf(w, "int %v_%v_end = %v;\n", n, t, end)
	fmt.Fprintf(w, "int %v_%v_len = %v;\n", n, t, end-start)
	fmt.Fprintf(w, "uint8_t %v_%v_out[] = {\n", n, t)
	for i := uint64(start); i < end; i += 16 {
		for j := uint64(0); i+j < end && j < 16; j++ {
			fmt.Fprintf(w, "0x%02x, ", m[j+i])
		}
		fmt.Fprintf(w, "\n")
	}
	fmt.Fprintf(w, "};\n")
}
func main() {
	flag.Parse()
	a := flag.Args()
	w := &bytes.Buffer{}
	for _, n := range a[1:] {
		f, err := elf.Open(n)
		if err != nil {
			fmt.Printf("%v %v\n", n, err)
			continue
		}
		var dataend, codeend, end uint64
		var datastart, codestart, start uint64
		datastart, codestart, start = math.MaxUint64, math.MaxUint64, math.MaxUint64
		mem := []byte{}
		for _, v := range f.Progs {
			if v.Type != elf.PT_LOAD {
				continue
			}
			fmt.Fprintf(os.Stderr, "processing %v\n", v)
			// MUST alignt to 2M page boundary.
			// then MUST allocate a []byte that
			// is the right size. And MUST
			// see if by some off chance it
			// joins to a pre-existing segment.
			// It's easier than it seems. We produce ONE text
			// array and ONE data array. So it's a matter of creating
			// a virtual memory space with an assumed starting point of
			// 0x200000, and filling it. We just grow that as needed.

			curstart := v.Vaddr & ^uint64(0xfff) // 0x1fffff)
			curend := v.Vaddr + v.Memsz
			fmt.Fprintf(os.Stderr, "s %x e %x\n", curstart, curend)
			if curend > end {
				nmem := make([]byte, curend)
				copy(nmem, mem)
				mem = nmem
			}
			if curstart < start {
				start = curstart
			}

			if v.Flags&elf.PF_X == elf.PF_X {
				if curstart < codestart {
					codestart = curstart
				}
				if curend > codeend {
					codeend = curend
				}
				fmt.Fprintf(os.Stderr, "code s %v e %v\n", codestart, codeend)
			} else {
				if curstart < datastart {
					datastart = curstart
				}
				if curend > dataend {
					dataend = curend
				}
				fmt.Fprintf(os.Stderr, "data s %v e %v\n", datastart, dataend)
			}
			for i := uint64(0); i < v.Filesz; i++ {
				if amt, err := v.ReadAt(mem[v.Vaddr+i:], int64(i)); err != nil && err != io.EOF {
					fmt.Fprintf(os.Stderr, "%v: %v\n", amt, err)
					os.Exit(1)
				} else if amt == 0 {
					if i < v.Filesz {
						fmt.Fprintf(os.Stderr, "%v: Short read: %v of %v\n", v, i, v.Filesz)
						os.Exit(1)
					}
					break
				} else {
					i = i + uint64(amt)
					fmt.Fprintf(os.Stderr, "i now %v\n", i)
				}
			}
			fmt.Fprintf(os.Stderr, "Processed %v\n", v)
		}
		fmt.Fprintf(os.Stderr, "gencode\n")
		_, file := path.Split(n)
		fmt.Fprintf(w, "uintptr_t %v_main = %v;\n", n, f.Entry)
		gencode(w, file, "code", mem, codestart, codeend)
		gencode(w, file, "data", mem, datastart, dataend)
	}
	if err := ioutil.WriteFile(a[0], w.Bytes(), 0444); err != nil {
		fmt.Fprintf(os.Stderr, "elf2c: write %s failed: %v\n", a[0], err)
	}

}
<|endoftext|>


<commit_before>// Copyright 2018 Google LLC All Rights Reserved.
//
// 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 (
	"bytes"
	"log"
	"os"
	"os/exec"

	"github.com/spf13/cobra"
)

// runCmd is suitable for use with cobra.Command's Run field.
type runCmd func(*cobra.Command, []string)

// passthru returns a runCmd that simply passes our CLI arguments
// through to a binary named command.
func passthru(command string) runCmd {
	return func(_ *cobra.Command, _ []string) {
		// Start building a command line invocation by passing
		// through our arguments to command's CLI.
		cmd := exec.Command(command, os.Args[1:]...)

		// Pass through our environment
		cmd.Env = os.Environ()
		// Pass through our stdfoo
		cmd.Stderr = os.Stderr
		cmd.Stdout = os.Stdout
		cmd.Stdin = os.Stdin

		// Run it.
		if err := cmd.Run(); err != nil {
			log.Fatalf("error executing %q command with args: %v; %v", command, os.Args[1:], err)
		}
	}
}

// addKubeCommands augments our CLI surface with a passthru delete command, and an apply
// command that realizes the promise of ko, as outlined here:
//    https://github.com/google/go-containerregistry/issues/80
func addKubeCommands(topLevel *cobra.Command) {
	topLevel.AddCommand(&cobra.Command{
		Use:   "delete",
		Short: `See "kubectl help delete" for detailed usage.`,
		Run:   passthru("kubectl"),
		// We ignore unknown flags to avoid importing everything Go exposes
		// from our commands.
		FParseErrWhitelist: cobra.FParseErrWhitelist{
			UnknownFlags: true,
		},
	})

	lo := &LocalOptions{}
	fo := &FilenameOptions{}
	apply := &cobra.Command{
		Use:   "apply -f FILENAME",
		Short: "Apply the input files with image references resolved to built/pushed image digests.",
		Long:  `This sub-command finds import path references within the provided files, builds them into Go binaries, containerizes them, publishes them, and then feeds the resulting yaml into "kubectl apply".`,
		Example: `
  # Build and publish import path references to a Docker
  # Registry as:
  #   ${KO_DOCKER_REPO}/<import path>
  # Then, feed the resulting yaml into "kubectl apply".
  # When KO_DOCKER_REPO is ko.local, it is the same as if -L were passed.
  ko apply -f config/

  # Build and publish import path references to a Docker
  # daemon as:
  #   ko.local/<import path>
  # Then, feed the resulting yaml into "kubectl apply"
  ko apply -L -f config/`,
		Run: func(cmd *cobra.Command, args []string) {
			// TODO(mattmoor): Use io.Pipe to avoid buffering the whole thing.
			buf := bytes.NewBuffer(nil)
			resolveFilesToWriter(fo, lo, buf)

			// Issue a "kubectl apply" command reading from stdin,
			// to which we will pipe the resolved files.
			kubectlCmd := exec.Command("kubectl", "apply", "-f", "-")

			// Pass through our environment
			kubectlCmd.Env = os.Environ()
			// Pass through our std{out,err} and make our resolved buffer stdin.
			kubectlCmd.Stderr = os.Stderr
			kubectlCmd.Stdout = os.Stdout
			kubectlCmd.Stdin = buf

			// Run it.
			if err := kubectlCmd.Run(); err != nil {
				log.Fatalf("error executing \"kubectl apply\": %v", err)
			}
		},
	}
	addLocalArg(apply, lo)
	addFileArg(apply, fo)
	topLevel.AddCommand(apply)

	resolve := &cobra.Command{
		Use:   "resolve -f FILENAME",
		Short: "Print the input files with image references resolved to built/pushed image digests.",
		Long:  `This sub-command finds import path references within the provided files, builds them into Go binaries, containerizes them, publishes them, and prints the resulting yaml.`,
		Example: `
  # Build and publish import path references to a Docker
  # Registry as:
  #   ${KO_DOCKER_REPO}/<import path>
  # When KO_DOCKER_REPO is ko.local, it is the same as if -L were passed.
  ko resolve -f config/

  # Build and publish import path references to a Docker
  # daemon as:
  #   ko.local/<import path>
  ko resolve -L -f config/`,
		Run: func(cmd *cobra.Command, args []string) {
			resolveFilesToWriter(fo, lo, os.Stdout)
		},
	}
	addLocalArg(resolve, lo)
	addFileArg(resolve, fo)
	topLevel.AddCommand(resolve)

	publish := &cobra.Command{
		Use:   "publish IMPORTPATH...",
		Short: "Build and publish container images from the given importpaths.",
		Long:  `This sub-command builds the provided import paths into Go binaries, containerizes them, and publishes them.`,
		Example: `
  # Build and publish import path references to a Docker
  # Registry as:
  #   ${KO_DOCKER_REPO}/<import path>
  # When KO_DOCKER_REPO is ko.local, it is the same as if -L were passed.
  ko publish github.com/foo/bar/cmd/baz github.com/foo/bar/cmd/blah

  # Build and publish import path references to a Docker
  # daemon as:
  #   ko.local/<import path>
  ko publish -L github.com/foo/bar/cmd/baz github.com/foo/bar/cmd/blah`,
		Args: cobra.MinimumNArgs(1),
		Run: func(_ *cobra.Command, args []string) {
			publishImages(args, lo)
		},
	}
	addLocalArg(publish, lo)
	topLevel.AddCommand(publish)
}
<commit_msg>Reject unrecognized arguments. (#183)<commit_after>// Copyright 2018 Google LLC All Rights Reserved.
//
// 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 (
	"bytes"
	"log"
	"os"
	"os/exec"

	"github.com/spf13/cobra"
)

// runCmd is suitable for use with cobra.Command's Run field.
type runCmd func(*cobra.Command, []string)

// passthru returns a runCmd that simply passes our CLI arguments
// through to a binary named command.
func passthru(command string) runCmd {
	return func(_ *cobra.Command, _ []string) {
		// Start building a command line invocation by passing
		// through our arguments to command's CLI.
		cmd := exec.Command(command, os.Args[1:]...)

		// Pass through our environment
		cmd.Env = os.Environ()
		// Pass through our stdfoo
		cmd.Stderr = os.Stderr
		cmd.Stdout = os.Stdout
		cmd.Stdin = os.Stdin

		// Run it.
		if err := cmd.Run(); err != nil {
			log.Fatalf("error executing %q command with args: %v; %v", command, os.Args[1:], err)
		}
	}
}

// addKubeCommands augments our CLI surface with a passthru delete command, and an apply
// command that realizes the promise of ko, as outlined here:
//    https://github.com/google/go-containerregistry/issues/80
func addKubeCommands(topLevel *cobra.Command) {
	topLevel.AddCommand(&cobra.Command{
		Use:   "delete",
		Short: `See "kubectl help delete" for detailed usage.`,
		Run:   passthru("kubectl"),
		// We ignore unknown flags to avoid importing everything Go exposes
		// from our commands.
		FParseErrWhitelist: cobra.FParseErrWhitelist{
			UnknownFlags: true,
		},
	})

	lo := &LocalOptions{}
	fo := &FilenameOptions{}
	apply := &cobra.Command{
		Use:   "apply -f FILENAME",
		Short: "Apply the input files with image references resolved to built/pushed image digests.",
		Long:  `This sub-command finds import path references within the provided files, builds them into Go binaries, containerizes them, publishes them, and then feeds the resulting yaml into "kubectl apply".`,
		Example: `
  # Build and publish import path references to a Docker
  # Registry as:
  #   ${KO_DOCKER_REPO}/<import path>
  # Then, feed the resulting yaml into "kubectl apply".
  # When KO_DOCKER_REPO is ko.local, it is the same as if -L were passed.
  ko apply -f config/

  # Build and publish import path references to a Docker
  # daemon as:
  #   ko.local/<import path>
  # Then, feed the resulting yaml into "kubectl apply"
  ko apply -L -f config/`,
		Args: cobra.NoArgs,
		Run: func(cmd *cobra.Command, args []string) {
			// TODO(mattmoor): Use io.Pipe to avoid buffering the whole thing.
			buf := bytes.NewBuffer(nil)
			resolveFilesToWriter(fo, lo, buf)

			// Issue a "kubectl apply" command reading from stdin,
			// to which we will pipe the resolved files.
			kubectlCmd := exec.Command("kubectl", "apply", "-f", "-")

			// Pass through our environment
			kubectlCmd.Env = os.Environ()
			// Pass through our std{out,err} and make our resolved buffer stdin.
			kubectlCmd.Stderr = os.Stderr
			kubectlCmd.Stdout = os.Stdout
			kubectlCmd.Stdin = buf

			// Run it.
			if err := kubectlCmd.Run(); err != nil {
				log.Fatalf("error executing \"kubectl apply\": %v", err)
			}
		},
	}
	addLocalArg(apply, lo)
	addFileArg(apply, fo)
	topLevel.AddCommand(apply)

	resolve := &cobra.Command{
		Use:   "resolve -f FILENAME",
		Short: "Print the input files with image references resolved to built/pushed image digests.",
		Long:  `This sub-command finds import path references within the provided files, builds them into Go binaries, containerizes them, publishes them, and prints the resulting yaml.`,
		Example: `
  # Build and publish import path references to a Docker
  # Registry as:
  #   ${KO_DOCKER_REPO}/<import path>
  # When KO_DOCKER_REPO is ko.local, it is the same as if -L were passed.
  ko resolve -f config/

  # Build and publish import path references to a Docker
  # daemon as:
  #   ko.local/<import path>
  ko resolve -L -f config/`,
		Args: cobra.NoArgs,
		Run: func(cmd *cobra.Command, args []string) {
			resolveFilesToWriter(fo, lo, os.Stdout)
		},
	}
	addLocalArg(resolve, lo)
	addFileArg(resolve, fo)
	topLevel.AddCommand(resolve)

	publish := &cobra.Command{
		Use:   "publish IMPORTPATH...",
		Short: "Build and publish container images from the given importpaths.",
		Long:  `This sub-command builds the provided import paths into Go binaries, containerizes them, and publishes them.`,
		Example: `
  # Build and publish import path references to a Docker
  # Registry as:
  #   ${KO_DOCKER_REPO}/<import path>
  # When KO_DOCKER_REPO is ko.local, it is the same as if -L were passed.
  ko publish github.com/foo/bar/cmd/baz github.com/foo/bar/cmd/blah

  # Build and publish import path references to a Docker
  # daemon as:
  #   ko.local/<import path>
  ko publish -L github.com/foo/bar/cmd/baz github.com/foo/bar/cmd/blah`,
		Args: cobra.MinimumNArgs(1),
		Run: func(_ *cobra.Command, args []string) {
			publishImages(args, lo)
		},
	}
	addLocalArg(publish, lo)
	topLevel.AddCommand(publish)
}
<|endoftext|>


<commit_before>// Copyright 2015 CoreOS, 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 (
	"fmt"
	"os"

	"github.com/coreos/mantle/Godeps/_workspace/src/github.com/spf13/cobra"
	"github.com/coreos/mantle/cli"
	"github.com/coreos/mantle/kola/register"
)

var (
	root = &cobra.Command{
		Use:   "kolet [command]",
		Short: "Native code runner for kola",
	}

	cmdRun = &cobra.Command{
		Use:   "run <test name> <func name>",
		Short: "Run native tests a group at a time",
		Run:   Run,
	}
)

func main() {
	root.AddCommand(cmdRun)
	cli.Execute(root)
}

// test runner
func Run(cmd *cobra.Command, args []string) {
	if len(args) != 2 {
		fmt.Fprintf(os.Stderr, "kolet: Extra arguements specified. Usage: 'kolet run <test name> <func name>'\n")
		os.Exit(2)
	}
	testname, funcname := args[0], args[1]

	// find test with matching name
	test, ok := register.Tests[testname]
	if !ok {
		fmt.Fprintf(os.Stderr, "kolet: test group not found\n")
		os.Exit(1)
	}
	// find native function in test
	f, ok := test.NativeFuncs[funcname]
	if !ok {
		fmt.Fprintf(os.Stderr, "kolet: native function not found\n")
		os.Exit(1)
	}
	err := f()
	if err != nil {
		fmt.Fprintf(os.Stderr, "kolet: on native test %v: %v", funcname, err)
		os.Exit(1)
	}
}
<commit_msg>cmd/kolet: be more verbose about test/func failures<commit_after>// Copyright 2015 CoreOS, 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 (
	"fmt"
	"os"

	"github.com/coreos/mantle/Godeps/_workspace/src/github.com/spf13/cobra"
	"github.com/coreos/mantle/cli"
	"github.com/coreos/mantle/kola/register"
)

var (
	root = &cobra.Command{
		Use:   "kolet [command]",
		Short: "Native code runner for kola",
	}

	cmdRun = &cobra.Command{
		Use:   "run <test name> <func name>",
		Short: "Run native tests a group at a time",
		Run:   Run,
	}
)

func main() {
	root.AddCommand(cmdRun)
	cli.Execute(root)
}

// test runner
func Run(cmd *cobra.Command, args []string) {
	if len(args) != 2 {
		fmt.Fprintf(os.Stderr, "kolet: Extra arguements specified. Usage: 'kolet run <test name> <func name>'\n")
		os.Exit(2)
	}
	testname, funcname := args[0], args[1]

	// find test with matching name
	test, ok := register.Tests[testname]
	if !ok {
		fmt.Fprintf(os.Stderr, "kolet: test group %q not found\n", testname)
		os.Exit(1)
	}
	// find native function in test
	f, ok := test.NativeFuncs[funcname]
	if !ok {
		fmt.Fprintf(os.Stderr, "kolet: native function %q not found\n", funcname)
		os.Exit(1)
	}
	err := f()
	if err != nil {
		fmt.Fprintf(os.Stderr, "kolet: on native test %v: %v", funcname, err)
		os.Exit(1)
	}
}
<|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.

// oracle: a tool for answering questions about Go source code.
// http://golang.org/s/oracle-design
// http://golang.org/s/oracle-user-manual
//
// Run with -help flag or help subcommand for usage information.
//
package main

import (
	"bufio"
	"encoding/json"
	"encoding/xml"
	"flag"
	"fmt"
	"go/build"
	"io"
	"log"
	"os"
	"runtime"
	"runtime/pprof"

	"code.google.com/p/go.tools/importer"
	"code.google.com/p/go.tools/oracle"
)

var posFlag = flag.String("pos", "",
	"Filename and byte offset or extent of a syntax element about which to query, "+
		"e.g. foo.go:#123,#456, bar.go:#123.")

var ptalogFlag = flag.String("ptalog", "",
	"Location of the points-to analysis log file, or empty to disable logging.")

var formatFlag = flag.String("format", "plain", "Output format.  One of {plain,json,xml}.")

// TODO(adonovan): eliminate or flip this flag after PTA presolver is implemented.
var reflectFlag = flag.Bool("reflect", true, "Analyze reflection soundly (slow).")

const useHelp = "Run 'oracle -help' for more information.\n"

const helpMessage = `Go source code oracle.
Usage: oracle [<flag> ...] <mode> <args> ...

The -format flag controls the output format:
	plain	an editor-friendly format in which every line of output
		is of the form "pos: text", where pos is "-" if unknown.
	json	structured data in JSON syntax.
	xml	structured data in XML syntax.

The -pos flag is required in all modes except 'callgraph'.

The mode argument determines the query to perform:

	callees	  	show possible targets of selected function call
	callers	  	show possible callers of selected function
	callgraph 	show complete callgraph of program
	callstack 	show path from callgraph root to selected function
	describe  	describe selected syntax: definition, methods, etc
	freevars  	show free variables of selection
	implements	show 'implements' relation for selected package
	peers     	show send/receive corresponding to selected channel op
	referrers 	show all refs to entity denoted by selected identifier

The user manual is available here:  http://golang.org/s/oracle-user-manual

Examples:

Describe the syntax at offset 530 in this file (an import spec):
% oracle -pos=src/code.google.com/p/go.tools/cmd/oracle/main.go:#530 describe \
   code.google.com/p/go.tools/cmd/oracle

Print the callgraph of the trivial web-server in JSON format:
% oracle -format=json src/pkg/net/http/triv.go callgraph
` + importer.InitialPackagesUsage

var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")

func init() {
	// If $GOMAXPROCS isn't set, use the full capacity of the machine.
	// For small machines, use at least 4 threads.
	if os.Getenv("GOMAXPROCS") == "" {
		n := runtime.NumCPU()
		if n < 4 {
			n = 4
		}
		runtime.GOMAXPROCS(n)
	}
}

func printHelp() {
	fmt.Println(helpMessage)
	fmt.Println("Flags:")
	flag.PrintDefaults()
}

func main() {
	// Don't print full help unless -help was requested.
	// Just gently remind users that it's there.
	flag.Usage = func() { fmt.Fprint(os.Stderr, useHelp) }
	flag.CommandLine.Init(os.Args[0], flag.ContinueOnError) // hack
	if err := flag.CommandLine.Parse(os.Args[1:]); err != nil {
		// (err has already been printed)
		if err == flag.ErrHelp {
			printHelp()
		}
		os.Exit(2)
	}

	args := flag.Args()
	if len(args) == 0 || args[0] == "" {
		fmt.Fprint(os.Stderr, "Error: a mode argument is required.\n"+useHelp)
		os.Exit(2)
	}

	mode := args[0]
	args = args[1:]
	if mode == "help" {
		printHelp()
		os.Exit(2)
	}

	if len(args) == 0 {
		fmt.Fprint(os.Stderr, "Error: no package arguments.\n"+useHelp)
		os.Exit(2)
	}

	// Set up points-to analysis log file.
	var ptalog io.Writer
	if *ptalogFlag != "" {
		if f, err := os.Create(*ptalogFlag); err != nil {
			log.Fatalf("Failed to create PTA log file: %s", err)
		} else {
			buf := bufio.NewWriter(f)
			ptalog = buf
			defer func() {
				buf.Flush()
				f.Close()
			}()
		}
	}

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

	// -format flag
	switch *formatFlag {
	case "json", "plain", "xml":
		// ok
	default:
		fmt.Fprintf(os.Stderr, "Error: illegal -format value: %q.\n"+useHelp, *formatFlag)
		os.Exit(2)
	}

	// Ask the oracle.
	res, err := oracle.Query(args, mode, *posFlag, ptalog, &build.Default, *reflectFlag)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s.\n", err)
		os.Exit(1)
	}

	// Print the result.
	switch *formatFlag {
	case "json":
		b, err := json.MarshalIndent(res.Serial(), "", "\t")
		if err != nil {
			fmt.Fprintf(os.Stderr, "JSON error: %s.\n", err)
			os.Exit(1)
		}
		os.Stdout.Write(b)

	case "xml":
		b, err := xml.MarshalIndent(res.Serial(), "", "\t")
		if err != nil {
			fmt.Fprintf(os.Stderr, "XML error: %s.\n", err)
			os.Exit(1)
		}
		os.Stdout.Write(b)

	case "plain":
		res.WriteTo(os.Stdout)
	}
}
<commit_msg>go.tools/cmd/oracle: output help messages to stderr for consistency Fixes issue 6838.<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.

// oracle: a tool for answering questions about Go source code.
// http://golang.org/s/oracle-design
// http://golang.org/s/oracle-user-manual
//
// Run with -help flag or help subcommand for usage information.
//
package main

import (
	"bufio"
	"encoding/json"
	"encoding/xml"
	"flag"
	"fmt"
	"go/build"
	"io"
	"log"
	"os"
	"runtime"
	"runtime/pprof"

	"code.google.com/p/go.tools/importer"
	"code.google.com/p/go.tools/oracle"
)

var posFlag = flag.String("pos", "",
	"Filename and byte offset or extent of a syntax element about which to query, "+
		"e.g. foo.go:#123,#456, bar.go:#123.")

var ptalogFlag = flag.String("ptalog", "",
	"Location of the points-to analysis log file, or empty to disable logging.")

var formatFlag = flag.String("format", "plain", "Output format.  One of {plain,json,xml}.")

// TODO(adonovan): eliminate or flip this flag after PTA presolver is implemented.
var reflectFlag = flag.Bool("reflect", true, "Analyze reflection soundly (slow).")

const useHelp = "Run 'oracle -help' for more information.\n"

const helpMessage = `Go source code oracle.
Usage: oracle [<flag> ...] <mode> <args> ...

The -format flag controls the output format:
	plain	an editor-friendly format in which every line of output
		is of the form "pos: text", where pos is "-" if unknown.
	json	structured data in JSON syntax.
	xml	structured data in XML syntax.

The -pos flag is required in all modes except 'callgraph'.

The mode argument determines the query to perform:

	callees	  	show possible targets of selected function call
	callers	  	show possible callers of selected function
	callgraph 	show complete callgraph of program
	callstack 	show path from callgraph root to selected function
	describe  	describe selected syntax: definition, methods, etc
	freevars  	show free variables of selection
	implements	show 'implements' relation for selected package
	peers     	show send/receive corresponding to selected channel op
	referrers 	show all refs to entity denoted by selected identifier

The user manual is available here:  http://golang.org/s/oracle-user-manual

Examples:

Describe the syntax at offset 530 in this file (an import spec):
% oracle -pos=src/code.google.com/p/go.tools/cmd/oracle/main.go:#530 describe \
   code.google.com/p/go.tools/cmd/oracle

Print the callgraph of the trivial web-server in JSON format:
% oracle -format=json src/pkg/net/http/triv.go callgraph
` + importer.InitialPackagesUsage

var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")

func init() {
	// If $GOMAXPROCS isn't set, use the full capacity of the machine.
	// For small machines, use at least 4 threads.
	if os.Getenv("GOMAXPROCS") == "" {
		n := runtime.NumCPU()
		if n < 4 {
			n = 4
		}
		runtime.GOMAXPROCS(n)
	}
}

func printHelp() {
	fmt.Fprintln(os.Stderr, helpMessage)
	fmt.Fprintln(os.Stderr, "Flags:")
	flag.PrintDefaults()
}

func main() {
	// Don't print full help unless -help was requested.
	// Just gently remind users that it's there.
	flag.Usage = func() { fmt.Fprint(os.Stderr, useHelp) }
	flag.CommandLine.Init(os.Args[0], flag.ContinueOnError) // hack
	if err := flag.CommandLine.Parse(os.Args[1:]); err != nil {
		// (err has already been printed)
		if err == flag.ErrHelp {
			printHelp()
		}
		os.Exit(2)
	}

	args := flag.Args()
	if len(args) == 0 || args[0] == "" {
		fmt.Fprint(os.Stderr, "Error: a mode argument is required.\n"+useHelp)
		os.Exit(2)
	}

	mode := args[0]
	args = args[1:]
	if mode == "help" {
		printHelp()
		os.Exit(2)
	}

	if len(args) == 0 {
		fmt.Fprint(os.Stderr, "Error: no package arguments.\n"+useHelp)
		os.Exit(2)
	}

	// Set up points-to analysis log file.
	var ptalog io.Writer
	if *ptalogFlag != "" {
		if f, err := os.Create(*ptalogFlag); err != nil {
			log.Fatalf("Failed to create PTA log file: %s", err)
		} else {
			buf := bufio.NewWriter(f)
			ptalog = buf
			defer func() {
				buf.Flush()
				f.Close()
			}()
		}
	}

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

	// -format flag
	switch *formatFlag {
	case "json", "plain", "xml":
		// ok
	default:
		fmt.Fprintf(os.Stderr, "Error: illegal -format value: %q.\n"+useHelp, *formatFlag)
		os.Exit(2)
	}

	// Ask the oracle.
	res, err := oracle.Query(args, mode, *posFlag, ptalog, &build.Default, *reflectFlag)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s.\n", err)
		os.Exit(1)
	}

	// Print the result.
	switch *formatFlag {
	case "json":
		b, err := json.MarshalIndent(res.Serial(), "", "\t")
		if err != nil {
			fmt.Fprintf(os.Stderr, "JSON error: %s.\n", err)
			os.Exit(1)
		}
		os.Stdout.Write(b)

	case "xml":
		b, err := xml.MarshalIndent(res.Serial(), "", "\t")
		if err != nil {
			fmt.Fprintf(os.Stderr, "XML error: %s.\n", err)
			os.Exit(1)
		}
		os.Stdout.Write(b)

	case "plain":
		res.WriteTo(os.Stdout)
	}
}
<|endoftext|>


<commit_before>// Command rqlite is the command-line interface for rqlite.
package main

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"

	"github.com/Bowery/prompt"
	"github.com/mkideal/cli"
)

const maxRedirect = 21

type argT struct {
	cli.Helper
	Protocol string `cli:"s,scheme" usage:"protocol scheme (http or https)" dft:"http"`
	Host     string `cli:"H,host" usage:"rqlited host address" dft:"127.0.0.1"`
	Port     uint16 `cli:"p,port" usage:"rqlited host port" dft:"4001"`
	Prefix   string `cli:"P,prefix" usage:"rqlited HTTP URL prefix" dft:"/"`
	Insecure bool   `cli:"i,insecure" usage:"do not verify rqlited HTTPS certificate" dft:"false"`
}

const cliHelp = `.help				Show this message
.indexes			Show names of all indexes
.schema				Show CREATE statements for all tables
.status				Show status and diagnostic information for connected node
.expvar				Show expvar (Go runtime) information for connected node
.tables				List names of tables
`

func main() {
	cli.SetUsageStyle(cli.ManualStyle)
	cli.Run(new(argT), func(ctx *cli.Context) error {
		argv := ctx.Argv().(*argT)
		if argv.Help {
			ctx.WriteUsage()
			return nil
		}

		prefix := fmt.Sprintf("%s:%d>", argv.Host, argv.Port)
	FOR_READ:
		for {
			line, err := prompt.Basic(prefix, false)
			if err != nil {
				return err
			}
			line = strings.TrimSpace(line)
			if line == "" {
				continue
			}
			var (
				index = strings.Index(line, " ")
				cmd   = line
			)
			if index >= 0 {
				cmd = line[:index]
			}
			cmd = strings.ToUpper(cmd)
			switch cmd {
			case ".TABLES":
				err = query(ctx, cmd, `SELECT name FROM sqlite_master WHERE type="table"`, argv)
			case ".INDEXES":
				err = query(ctx, cmd, `SELECT sql FROM sqlite_master WHERE type="index"`, argv)
			case ".SCHEMA":
				err = query(ctx, cmd, "SELECT sql FROM sqlite_master", argv)
			case ".STATUS":
				err = status(ctx, cmd, line, argv)
			case ".EXPVAR":
				err = expvar(ctx, cmd, line, argv)
			case ".HELP":
				err = help(ctx, cmd, line, argv)
			case ".QUIT", "QUIT", "EXIT":
				break FOR_READ
			case "SELECT":
				err = query(ctx, cmd, line, argv)
			default:
				err = execute(ctx, cmd, line, argv)
			}
			if err != nil {
				ctx.String("%s %v\n", ctx.Color().Red("ERR!"), err)
			}
		}
		ctx.String("bye~\n")
		return nil
	})
}

func makeJSONBody(line string) string {
	data, err := json.MarshalIndent([]string{line}, "", "    ")
	if err != nil {
		return ""
	}
	return string(data)
}

func help(ctx *cli.Context, cmd, line string, argv *argT) error {
	fmt.Printf(cliHelp)
	return nil
}

func status(ctx *cli.Context, cmd, line string, argv *argT) error {
	url := fmt.Sprintf("%s://%s:%d/status", argv.Protocol, argv.Host, argv.Port)
	return cliJSON(ctx, cmd, line, url, argv)
}

func expvar(ctx *cli.Context, cmd, line string, argv *argT) error {
	url := fmt.Sprintf("%s://%s:%d/debug/vars", argv.Protocol, argv.Host, argv.Port)
	return cliJSON(ctx, cmd, line, url, argv)
}

func sendRequest(ctx *cli.Context, urlStr string, line string, argv *argT, ret interface{}) error {
	data := makeJSONBody(line)
	url := urlStr

	client := http.Client{Transport: &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: argv.Insecure},
	}}

	// Explicitly handle redirects.
	client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
		return http.ErrUseLastResponse
	}

	nRedirect := 0
	for {
		resp, err := client.Post(url, "application/json", strings.NewReader(data))
		if err != nil {
			return err
		}
		defer resp.Body.Close()

		if resp.StatusCode == http.StatusUnauthorized {
			return fmt.Errorf("unauthorized")
		}

		// Check for redirect.
		if resp.StatusCode == http.StatusMovedPermanently {
			nRedirect++
			if nRedirect > maxRedirect {
				return fmt.Errorf("maximum leader redirect limit exceeded")
			}
			url = resp.Header["Location"][0]
			continue
		}

		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return err
		}

		if err := json.Unmarshal(body, ret); err != nil {
			return err
		}
		return nil
	}
}

// cliJSON fetches JSON from a URL, and displays it at the CLI.
func cliJSON(ctx *cli.Context, cmd, line, url string, argv *argT) error {
	// Recursive JSON printer.
	var pprint func(indent int, m map[string]interface{})
	pprint = func(indent int, m map[string]interface{}) {
		indentation := "  "
		for k, v := range m {
			if v == nil {
				continue
			}
			switch v.(type) {
			case map[string]interface{}:
				for i := 0; i < indent; i++ {
					fmt.Print(indentation)
				}
				fmt.Printf("%s:\n", k)
				pprint(indent+1, v.(map[string]interface{}))
			default:
				for i := 0; i < indent; i++ {
					fmt.Print(indentation)
				}
				fmt.Printf("%s: %v\n", k, v)
			}
		}
	}

	client := http.Client{Transport: &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: argv.Insecure},
	}}
	resp, err := client.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode == http.StatusUnauthorized {
		return fmt.Errorf("unauthorized")
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	ret := make(map[string]interface{})
	if err := json.Unmarshal(body, &ret); err != nil {
		return err
	}

	// Specific key requested?
	parts := strings.Split(line, " ")
	if len(parts) >= 2 {
		ret = map[string]interface{}{parts[1]: ret[parts[1]]}
	}
	pprint(0, ret)

	return nil
}
<commit_msg>CLI doesn't need to send indented JSON<commit_after>// Command rqlite is the command-line interface for rqlite.
package main

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"

	"github.com/Bowery/prompt"
	"github.com/mkideal/cli"
)

const maxRedirect = 21

type argT struct {
	cli.Helper
	Protocol string `cli:"s,scheme" usage:"protocol scheme (http or https)" dft:"http"`
	Host     string `cli:"H,host" usage:"rqlited host address" dft:"127.0.0.1"`
	Port     uint16 `cli:"p,port" usage:"rqlited host port" dft:"4001"`
	Prefix   string `cli:"P,prefix" usage:"rqlited HTTP URL prefix" dft:"/"`
	Insecure bool   `cli:"i,insecure" usage:"do not verify rqlited HTTPS certificate" dft:"false"`
}

const cliHelp = `.help				Show this message
.indexes			Show names of all indexes
.schema				Show CREATE statements for all tables
.status				Show status and diagnostic information for connected node
.expvar				Show expvar (Go runtime) information for connected node
.tables				List names of tables
`

func main() {
	cli.SetUsageStyle(cli.ManualStyle)
	cli.Run(new(argT), func(ctx *cli.Context) error {
		argv := ctx.Argv().(*argT)
		if argv.Help {
			ctx.WriteUsage()
			return nil
		}

		prefix := fmt.Sprintf("%s:%d>", argv.Host, argv.Port)
	FOR_READ:
		for {
			line, err := prompt.Basic(prefix, false)
			if err != nil {
				return err
			}
			line = strings.TrimSpace(line)
			if line == "" {
				continue
			}
			var (
				index = strings.Index(line, " ")
				cmd   = line
			)
			if index >= 0 {
				cmd = line[:index]
			}
			cmd = strings.ToUpper(cmd)
			switch cmd {
			case ".TABLES":
				err = query(ctx, cmd, `SELECT name FROM sqlite_master WHERE type="table"`, argv)
			case ".INDEXES":
				err = query(ctx, cmd, `SELECT sql FROM sqlite_master WHERE type="index"`, argv)
			case ".SCHEMA":
				err = query(ctx, cmd, "SELECT sql FROM sqlite_master", argv)
			case ".STATUS":
				err = status(ctx, cmd, line, argv)
			case ".EXPVAR":
				err = expvar(ctx, cmd, line, argv)
			case ".HELP":
				err = help(ctx, cmd, line, argv)
			case ".QUIT", "QUIT", "EXIT":
				break FOR_READ
			case "SELECT":
				err = query(ctx, cmd, line, argv)
			default:
				err = execute(ctx, cmd, line, argv)
			}
			if err != nil {
				ctx.String("%s %v\n", ctx.Color().Red("ERR!"), err)
			}
		}
		ctx.String("bye~\n")
		return nil
	})
}

func makeJSONBody(line string) string {
	data, err := json.Marshal([]string{line})
	if err != nil {
		return ""
	}
	return string(data)
}

func help(ctx *cli.Context, cmd, line string, argv *argT) error {
	fmt.Printf(cliHelp)
	return nil
}

func status(ctx *cli.Context, cmd, line string, argv *argT) error {
	url := fmt.Sprintf("%s://%s:%d/status", argv.Protocol, argv.Host, argv.Port)
	return cliJSON(ctx, cmd, line, url, argv)
}

func expvar(ctx *cli.Context, cmd, line string, argv *argT) error {
	url := fmt.Sprintf("%s://%s:%d/debug/vars", argv.Protocol, argv.Host, argv.Port)
	return cliJSON(ctx, cmd, line, url, argv)
}

func sendRequest(ctx *cli.Context, urlStr string, line string, argv *argT, ret interface{}) error {
	data := makeJSONBody(line)
	url := urlStr

	client := http.Client{Transport: &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: argv.Insecure},
	}}

	// Explicitly handle redirects.
	client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
		return http.ErrUseLastResponse
	}

	nRedirect := 0
	for {
		resp, err := client.Post(url, "application/json", strings.NewReader(data))
		if err != nil {
			return err
		}
		defer resp.Body.Close()

		if resp.StatusCode == http.StatusUnauthorized {
			return fmt.Errorf("unauthorized")
		}

		// Check for redirect.
		if resp.StatusCode == http.StatusMovedPermanently {
			nRedirect++
			if nRedirect > maxRedirect {
				return fmt.Errorf("maximum leader redirect limit exceeded")
			}
			url = resp.Header["Location"][0]
			continue
		}

		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return err
		}

		if err := json.Unmarshal(body, ret); err != nil {
			return err
		}
		return nil
	}
}

// cliJSON fetches JSON from a URL, and displays it at the CLI.
func cliJSON(ctx *cli.Context, cmd, line, url string, argv *argT) error {
	// Recursive JSON printer.
	var pprint func(indent int, m map[string]interface{})
	pprint = func(indent int, m map[string]interface{}) {
		indentation := "  "
		for k, v := range m {
			if v == nil {
				continue
			}
			switch v.(type) {
			case map[string]interface{}:
				for i := 0; i < indent; i++ {
					fmt.Print(indentation)
				}
				fmt.Printf("%s:\n", k)
				pprint(indent+1, v.(map[string]interface{}))
			default:
				for i := 0; i < indent; i++ {
					fmt.Print(indentation)
				}
				fmt.Printf("%s: %v\n", k, v)
			}
		}
	}

	client := http.Client{Transport: &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: argv.Insecure},
	}}
	resp, err := client.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode == http.StatusUnauthorized {
		return fmt.Errorf("unauthorized")
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	ret := make(map[string]interface{})
	if err := json.Unmarshal(body, &ret); err != nil {
		return err
	}

	// Specific key requested?
	parts := strings.Split(line, " ")
	if len(parts) >= 2 {
		ret = map[string]interface{}{parts[1]: ret[parts[1]]}
	}
	pprint(0, ret)

	return nil
}
<|endoftext|>