<commit_before>// The go-vcs program exposes go-vcs's library functionality through a
// command-line interface.
package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"path/filepath"

	"github.com/kr/text"
	"github.com/sourcegraph/go-vcs/vcs"
	_ "github.com/sourcegraph/go-vcs/vcs/git_libgit2"
)

var (
	sshKeyFile = flag.String("i", "", "ssh key file")
)

func main() {
	log.SetFlags(0)
	flag.Parse()

	if flag.NArg() == 0 {
		log.Fatal("Must specify a subcommand.")
	}

	subcmd := flag.Arg(0)
	args := flag.Args()[1:]
	switch subcmd {
	case "git-clone-mirror":
		if len(args) != 2 {
			log.Fatal("git-clone requires 2 args: clone URL and dir.")
		}
		cloneURLStr, dir := args[0], args[1]

		cloneURL, err := url.Parse(cloneURLStr)
		if err != nil {
			log.Fatal(err)
		}

		if _, err := os.Stat(dir); !os.IsNotExist(err) {
			log.Fatalf("Clone destination dir must not exist: %s.", dir)
		}
		if _, err := os.Stat(filepath.Join(dir, "..")); err != nil {
			log.Fatalf("Clone destination dir parent must exist: %s.", filepath.Join(dir, ".."))
		}

		log.Printf("Cloning %s to %s...", cloneURL, dir)

		repo, err := vcs.CloneMirror("git", cloneURL.String(), dir)
		if err != nil {
			log.Fatal(err)
		}

		log.Printf("Cloned: %T.", repo)

	case "show":
		if len(args) != 1 {
			log.Fatal("show takes 1 argument (revspec).")
		}
		revspec := args[0]

		repo, err := vcs.Open("git", ".")
		if err != nil {
			log.Fatal(err)
		}

		commitID, err := repo.ResolveRevision(revspec)
		if err != nil {
			log.Fatal(err)
		}

		commit, err := repo.GetCommit(commitID)
		if err != nil {
			log.Fatal(err)
		}

		fmt.Printf("# Revspec %q resolves to commit %s:\n", revspec, commitID)
		printCommit(commit)

	case "show-file":
		if err := os.Chdir("/tmp/vcsstore/hg/https/bitbucket.org/atlassian/connector-commons"); err != nil {
			log.Fatal(err)
		}

		if len(args) != 2 {
			log.Fatal("show-file takes 2 arguments.")
		}

		repo, err := vcs.Open("hg", ".")
		if err != nil {
			log.Fatal(err)
		}

		rev, err := repo.ResolveRevision(args[0])
		if err != nil {
			log.Fatal(err)
		}

		fs, err := repo.FileSystem(rev)
		if err != nil {
			log.Fatal(err)
		}

		f, err := fs.Open(args[1])
		if err != nil {
			log.Fatal(err)
		}

		b, err := ioutil.ReadAll(f)
		if err != nil {
			log.Fatal(err)
		}
		if _, err := os.Stdout.Write(b); err != nil {
			log.Fatal(err)
		}
	case "log":
		if len(args) != 0 {
			log.Fatal("log takes no arguments.")
		}

		repo, err := vcs.Open("git", ".")
		if err != nil {
			log.Fatal(err)
		}

		master, err := repo.ResolveRevision("master")
		if err != nil {
			log.Fatal(err)
		}

		commits, total, err := repo.Commits(vcs.CommitsOptions{Head: master})
		if err != nil {
			log.Fatal(err)
		}

		fmt.Printf("# Commits (%d total):\n", total)
		for _, c := range commits {
			printCommit(c)
		}
	}
}

func printCommit(c *vcs.Commit) {
	fmt.Printf("%s\n%s <%s> at %s\n%s\n\n", c.ID, c.Author.Name, c.Author.Email, c.Author.Date, text.Indent(c.Message, "\t"))
}
<commit_msg>branches command for debugging<commit_after>// The go-vcs program exposes go-vcs's library functionality through a
// command-line interface.
package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"path/filepath"

	"github.com/kr/text"
	"github.com/sourcegraph/go-vcs/vcs"
	_ "github.com/sourcegraph/go-vcs/vcs/git_libgit2"
)

var (
	sshKeyFile = flag.String("i", "", "ssh key file")
)

func main() {
	log.SetFlags(0)
	flag.Parse()

	if flag.NArg() == 0 {
		log.Fatal("Must specify a subcommand.")
	}

	subcmd := flag.Arg(0)
	args := flag.Args()[1:]
	switch subcmd {
	case "git-clone-mirror":
		if len(args) != 2 {
			log.Fatal("git-clone requires 2 args: clone URL and dir.")
		}
		cloneURLStr, dir := args[0], args[1]

		cloneURL, err := url.Parse(cloneURLStr)
		if err != nil {
			log.Fatal(err)
		}

		if _, err := os.Stat(dir); !os.IsNotExist(err) {
			log.Fatalf("Clone destination dir must not exist: %s.", dir)
		}
		if _, err := os.Stat(filepath.Join(dir, "..")); err != nil {
			log.Fatalf("Clone destination dir parent must exist: %s.", filepath.Join(dir, ".."))
		}

		log.Printf("Cloning %s to %s...", cloneURL, dir)

		repo, err := vcs.CloneMirror("git", cloneURL.String(), dir)
		if err != nil {
			log.Fatal(err)
		}

		log.Printf("Cloned: %T.", repo)

	case "show":
		if len(args) != 1 {
			log.Fatal("show takes 1 argument (revspec).")
		}
		revspec := args[0]

		repo, err := vcs.Open("git", ".")
		if err != nil {
			log.Fatal(err)
		}

		commitID, err := repo.ResolveRevision(revspec)
		if err != nil {
			log.Fatal(err)
		}

		commit, err := repo.GetCommit(commitID)
		if err != nil {
			log.Fatal(err)
		}

		fmt.Printf("# Revspec %q resolves to commit %s:\n", revspec, commitID)
		printCommit(commit)

	case "show-file":
		if err := os.Chdir("/tmp/vcsstore/hg/https/bitbucket.org/atlassian/connector-commons"); err != nil {
			log.Fatal(err)
		}

		if len(args) != 2 {
			log.Fatal("show-file takes 2 arguments.")
		}

		repo, err := vcs.Open("hg", ".")
		if err != nil {
			log.Fatal(err)
		}

		rev, err := repo.ResolveRevision(args[0])
		if err != nil {
			log.Fatal(err)
		}

		fs, err := repo.FileSystem(rev)
		if err != nil {
			log.Fatal(err)
		}

		f, err := fs.Open(args[1])
		if err != nil {
			log.Fatal(err)
		}

		b, err := ioutil.ReadAll(f)
		if err != nil {
			log.Fatal(err)
		}
		if _, err := os.Stdout.Write(b); err != nil {
			log.Fatal(err)
		}
	case "log":
		if len(args) != 0 {
			log.Fatal("log takes no arguments.")
		}

		repo, err := vcs.Open("git", ".")
		if err != nil {
			log.Fatal(err)
		}

		master, err := repo.ResolveRevision("master")
		if err != nil {
			log.Fatal(err)
		}

		commits, total, err := repo.Commits(vcs.CommitsOptions{Head: master})
		if err != nil {
			log.Fatal(err)
		}

		fmt.Printf("# Commits (%d total):\n", total)
		for _, c := range commits {
			printCommit(c)
		}

	case "branches":
		if len(args) != 0 {
			log.Fatal("branches takes no arguments.")
		}

		repo, err := vcs.Open("hg", ".")
		if err != nil {
			log.Fatal(err)
		}

		branches, err := repo.Branches()
		if err != nil {
			log.Fatal(err)
		}

		fmt.Printf("# Branches (%d total):\n", len(branches))
		for _, b := range branches {
			fmt.Printf("%s %s\n", b.Head, b.Name)
		}
	}
}

func printCommit(c *vcs.Commit) {
	fmt.Printf("%s\n%s <%s> at %s\n%s\n\n", c.ID, c.Author.Name, c.Author.Email, c.Author.Date, text.Indent(c.Message, "\t"))
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cmd

import (
	"context"
	"os"
	"os/user"

	"cloud.google.com/go/storage"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"

	"k8s.io/release/pkg/release"
)

const description = `
Used for pushing developer builds and Jenkins' continuous builds.

Developer pushes simply run as they do pushing to devel/ on GCS.
In --ci mode, 'push' runs in mock mode by default. Use --nomock to do
a real push.

Federation values are just passed through as exported global vars still
due to the fact that we're still leveraging the existing federation
interface in kubernetes proper.

push                       - Do a developer push
push --nomock --federation --ci
                           - Do a (non-mocked) CI push with federation
push --bucket=kubernetes-release-$USER
                           - Do a developer push to kubernetes-release-$USER`

const (
	errInvalidVersion = "invalid build version"
	errDirtyWithCI    = "dirty build with ci"
	errUnknownUser    = "unable to determine current user"
	errConnectGCP     = "unable to authenticate to GCP"
	errUnknownBucket  = "specified release bucket is unknown"
)

type pushBuildOptions struct {
	bucket           string
	dockerRegistry   string
	extraPublishFile string
	gcsSuffix        string
	releaseKind      string
	releaseType      string
	versionSuffix    string
	allowDup         bool
	ci               bool
	federation       bool
	noUpdateLatest   bool
	privateBucket    bool
}

var pushBuildOpts = &pushBuildOptions{}

var pushBuildCmd = &cobra.Command{
	Use:     "push [--federation] [--noupdatelatest] [--ci] [--bucket=<GS bucket>] [--private-bucket]",
	Short:   "push kubernetes release artifacts to GCS",
	Example: description,
	RunE: func(cmd *cobra.Command, args []string) error {
		if err := runPushBuild(pushBuildOpts); err != nil {
			return err
		}

		return nil
	},
}

func init() {
	pushBuildCmd.PersistentFlags().BoolVar(
		&pushBuildOpts.allowDup,
		"allow-dup",
		false,
		"Do not exit error if the build already exists on the gcs path",
	)
	pushBuildCmd.PersistentFlags().BoolVar(
		&pushBuildOpts.ci,
		"ci",
		false,
		"Used when called from Jenkins (for ci runs)",
	)
	pushBuildCmd.PersistentFlags().BoolVar(
		&pushBuildOpts.federation,
		"federation",
		false,
		"Enable FEDERATION push",
	)
	pushBuildCmd.PersistentFlags().BoolVar(
		&pushBuildOpts.noUpdateLatest,
		"noupdatelatest",
		false,
		"Do not update the latest file",
	)
	pushBuildCmd.PersistentFlags().BoolVar(
		&pushBuildOpts.privateBucket,
		"private-bucket",
		false, "Do not mark published bits on GCS as publicly readable",
	)
	pushBuildCmd.PersistentFlags().StringVar(
		&pushBuildOpts.bucket,
		"bucket",
		"devel",
		"Specify an alternate bucket for pushes (normally 'devel' or 'ci')",
	)
	pushBuildCmd.PersistentFlags().StringVar(
		&pushBuildOpts.dockerRegistry,
		"docker-registry",
		"",
		"If set, push docker images to specified registry/project",
	)
	pushBuildCmd.PersistentFlags().StringVar(
		&pushBuildOpts.extraPublishFile,
		"extra-publish-file",
		"",
		"Used when need to upload additional version file to GCS. The path is relative and is append to a GCS path. (--ci only)",
	)
	pushBuildCmd.PersistentFlags().StringVar(
		&pushBuildOpts.gcsSuffix,
		"gcs-suffix",
		"",
		"Specify a suffix to append to the upload destination on GCS",
	)
	pushBuildCmd.PersistentFlags().StringVar(
		&pushBuildOpts.releaseKind,
		"release-kind",
		"kubernetes",
		"Kind of release to push to GCS. Supported values are kubernetes (default) or federation",
	)
	pushBuildCmd.PersistentFlags().StringVar(
		&pushBuildOpts.releaseType,
		"release-type",
		"devel",
		"Specify an alternate bucket for pushes (normally 'devel' or 'ci')",
	)
	pushBuildCmd.PersistentFlags().StringVar(
		&pushBuildOpts.versionSuffix,
		"version-suffix",
		"",
		"Append suffix to version name if set",
	)

	rootCmd.AddCommand(pushBuildCmd)
}

func runPushBuild(opts *pushBuildOptions) error {
	var latest string
	releaseKind := opts.releaseKind

	// Check if latest build uses bazel
	dir, err := os.Getwd()
	if err != nil {
		logrus.Errorf("Unable to get working directory: %v", err)
		return err
	}

	isBazel, err := release.BuiltWithBazel(dir, releaseKind)
	if err != nil {
		logrus.Errorf("Unable to identify if release built with Bazel: %v", err)
		return err
	}

	if isBazel {
		logrus.Info("Using Bazel build version")
		version, err := release.ReadBazelVersion(dir)
		if err != nil {
			logrus.Errorf("Unable to read Bazel build version", err)
			return err
		}
		latest = version
	} else {
		logrus.Info("Using Dockerized build version")
		version, err := release.ReadDockerizedVersion(dir, releaseKind)
		if err != nil {
			logrus.Errorf("Unable to read Dockerized build version: %v", err)
			return err
		}
		latest = version
	}

	logrus.Info("Found build version: " + latest)

	valid, err := release.IsValidReleaseBuild(latest)
	if err != nil {
		logrus.Errorf("Unable to determine is release build version is valid: %v", err)
		return err
	}
	if !valid {
		logrus.Error("Build version is not valid for release")
		return errors.New(errInvalidVersion)
	}

	if opts.ci && release.IsDirtyBuild(latest) {
		logrus.Error(`Refusing to push dirty build with --ci flag given.\n
			CI builds should always be performed from clean commits`)
		return errors.New(errDirtyWithCI)
	}

	if opts.versionSuffix != "" {
		latest += "-" + opts.versionSuffix
	}

	gcsDest := opts.releaseType

	// TODO: is this how we want to handle gcs dest args?
	if opts.ci {
		gcsDest = "ci"
	}

	gcsDest += opts.gcsSuffix

	releaseBucket := opts.bucket
	if !rootOpts.nomock {
		u, err := user.Current()
		if err != nil {
			logrus.Error("Unable to identify current user")
			return errors.New(errUnknownUser)
		}

		releaseBucket += "-" + u.Username
	}

	client, err := storage.NewClient(context.Background())
	if err != nil {
		logrus.Error("error fetching gcloud credentials %s... try running \"gcloud auth application-default login\"", err)
		return errors.New(errConnectGCP)
	}

	bucket := client.Bucket(releaseBucket)
	if bucket == nil {
		logrus.Errorf("unable to identify specified bucket for artifacts: %s", releaseBucket)
		return errors.New(errUnknownBucket)
	}

	// Check if bucket exists.
	if _, err = bucket.Attrs(context.Background()); err != nil {
		logrus.Error("Unable to find release artifact bucket")
		return err
	}

	return nil
}
<commit_msg>krelpush: clean up returned errors<commit_after>/*
Copyright 2019 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cmd

import (
	"context"
	"os"
	"os/user"

	"cloud.google.com/go/storage"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"

	"k8s.io/release/pkg/release"
)

const description = `
Used for pushing developer builds and Jenkins' continuous builds.

Developer pushes simply run as they do pushing to devel/ on GCS.
In --ci mode, 'push' runs in mock mode by default. Use --nomock to do
a real push.

Federation values are just passed through as exported global vars still
due to the fact that we're still leveraging the existing federation
interface in kubernetes proper.

push                       - Do a developer push
push --nomock --federation --ci
                           - Do a (non-mocked) CI push with federation
push --bucket=kubernetes-release-$USER
                           - Do a developer push to kubernetes-release-$USER`

type pushBuildOptions struct {
	bucket           string
	dockerRegistry   string
	extraPublishFile string
	gcsSuffix        string
	releaseKind      string
	releaseType      string
	versionSuffix    string
	allowDup         bool
	ci               bool
	federation       bool
	noUpdateLatest   bool
	privateBucket    bool
}

var pushBuildOpts = &pushBuildOptions{}

var pushBuildCmd = &cobra.Command{
	Use:     "push [--federation] [--noupdatelatest] [--ci] [--bucket=<GS bucket>] [--private-bucket]",
	Short:   "push kubernetes release artifacts to GCS",
	Example: description,
	RunE: func(cmd *cobra.Command, args []string) error {
		if err := runPushBuild(pushBuildOpts); err != nil {
			return err
		}

		return nil
	},
}

func init() {
	pushBuildCmd.PersistentFlags().BoolVar(
		&pushBuildOpts.allowDup,
		"allow-dup",
		false,
		"Do not exit error if the build already exists on the gcs path",
	)
	pushBuildCmd.PersistentFlags().BoolVar(
		&pushBuildOpts.ci,
		"ci",
		false,
		"Used when called from Jenkins (for ci runs)",
	)
	pushBuildCmd.PersistentFlags().BoolVar(
		&pushBuildOpts.federation,
		"federation",
		false,
		"Enable FEDERATION push",
	)
	pushBuildCmd.PersistentFlags().BoolVar(
		&pushBuildOpts.noUpdateLatest,
		"noupdatelatest",
		false,
		"Do not update the latest file",
	)
	pushBuildCmd.PersistentFlags().BoolVar(
		&pushBuildOpts.privateBucket,
		"private-bucket",
		false, "Do not mark published bits on GCS as publicly readable",
	)
	pushBuildCmd.PersistentFlags().StringVar(
		&pushBuildOpts.bucket,
		"bucket",
		"devel",
		"Specify an alternate bucket for pushes (normally 'devel' or 'ci')",
	)
	pushBuildCmd.PersistentFlags().StringVar(
		&pushBuildOpts.dockerRegistry,
		"docker-registry",
		"",
		"If set, push docker images to specified registry/project",
	)
	pushBuildCmd.PersistentFlags().StringVar(
		&pushBuildOpts.extraPublishFile,
		"extra-publish-file",
		"",
		"Used when need to upload additional version file to GCS. The path is relative and is append to a GCS path. (--ci only)",
	)
	pushBuildCmd.PersistentFlags().StringVar(
		&pushBuildOpts.gcsSuffix,
		"gcs-suffix",
		"",
		"Specify a suffix to append to the upload destination on GCS",
	)
	pushBuildCmd.PersistentFlags().StringVar(
		&pushBuildOpts.releaseKind,
		"release-kind",
		"kubernetes",
		"Kind of release to push to GCS. Supported values are kubernetes (default) or federation",
	)
	pushBuildCmd.PersistentFlags().StringVar(
		&pushBuildOpts.releaseType,
		"release-type",
		"devel",
		"Specify an alternate bucket for pushes (normally 'devel' or 'ci')",
	)
	pushBuildCmd.PersistentFlags().StringVar(
		&pushBuildOpts.versionSuffix,
		"version-suffix",
		"",
		"Append suffix to version name if set",
	)

	rootCmd.AddCommand(pushBuildCmd)
}

func runPushBuild(opts *pushBuildOptions) error {
	var latest string
	releaseKind := opts.releaseKind

	// Check if latest build uses bazel
	dir, err := os.Getwd()
	if err != nil {
		return errors.Wrapf(err, "Unable to get working directory: %v")
	}

	isBazel, err := release.BuiltWithBazel(dir, releaseKind)
	if err != nil {
		return errors.Wrapf(err, "Unable to identify if release built with Bazel: %v")
	}

	if isBazel {
		logrus.Info("Using Bazel build version")
		version, err := release.ReadBazelVersion(dir)
		if err != nil {
			return errors.Wrapf(err, "Unable to read Bazel build version: %v")
		}
		latest = version
	} else {
		logrus.Info("Using Dockerized build version")
		version, err := release.ReadDockerizedVersion(dir, releaseKind)
		if err != nil {
			return errors.Wrapf(err, "Unable to read Dockerized build version: %v")
		}
		latest = version
	}

	logrus.Infof("Found build version: %s", latest)

	valid, err := release.IsValidReleaseBuild(latest)
	if err != nil {
		return errors.Wrapf(err, "Unable to determine if release build version is valid: %v")
	}
	if !valid {
		return errors.Errorf("Build version %s is not valid for release", latest)
	}

	if opts.ci && release.IsDirtyBuild(latest) {
		return errors.New(`Refusing to push dirty build with --ci flag given.\n
			CI builds should always be performed from clean commits`)
	}

	if opts.versionSuffix != "" {
		latest += "-" + opts.versionSuffix
	}

	gcsDest := opts.releaseType

	// TODO: is this how we want to handle gcs dest args?
	if opts.ci {
		gcsDest = "ci"
	}

	gcsDest += opts.gcsSuffix

	releaseBucket := opts.bucket
	if !rootOpts.nomock {
		u, err := user.Current()
		if err != nil {
			return errors.Wrapf(err, "Unable to identify current user: %v")
		}

		releaseBucket += "-" + u.Username
	}

	client, err := storage.NewClient(context.Background())
	if err != nil {
		return errors.Wrapf(err, "error fetching gcloud credentials %v... try running \"gcloud auth application-default login\"")
	}

	bucket := client.Bucket(releaseBucket)
	if bucket == nil {
		return errors.Errorf("unable to identify specified bucket for artifacts: %s", releaseBucket)
	}

	// Check if bucket exists.
	if _, err = bucket.Attrs(context.Background()); err != nil {
		return errors.Wrapf(err, "Unable to find release artifact bucket: %v")
	}

	return nil
}
<|endoftext|>


<commit_before>package clinamespace

import (
	"github.com/containerum/chkit/pkg/model/namespace"
	"github.com/sirupsen/logrus"

	"github.com/containerum/chkit/cmd/util"
	"github.com/containerum/chkit/pkg/model"
	"gopkg.in/urfave/cli.v2"
)

// GetNamespace -- commmand 'get' entity data
var GetNamespace = &cli.Command{
	Name:        "namespace",
	Aliases:     []string{"ns", "namespaces"},
	Description: `shows namespace data or namespace list. Aliases: ns, namespaces`,
	Usage:       `shows namespace data or namespace list`,
	Action: func(ctx *cli.Context) error {
		client := util.GetClient(ctx)
		defer util.StoreClient(ctx, client)
		var showItem model.Renderer
		var err error

		switch ctx.NArg() {
		case 1:
			namespaceLabel := ctx.Args().First()
			logrus.Debugf("getting namespace %q", namespaceLabel)
			showItem, err = client.GetNamespace(namespaceLabel)
			if err != nil {
				logrus.Debugf("fatal error: %v", err)
				return err
			}
		default:
			var list namespace.NamespaceList
			logrus.Debugf("getting namespace list")
			list, err := client.GetNamespaceList()
			if err != nil {
				logrus.Debugf("fatal error: %v", err)
				return err
			}
			showItem = list
		}
		err = util.WriteData(ctx, showItem)
		if err != nil {
			logrus.Debugf("fatal error: %v", err)
		}
		return err
	},
	Flags: []cli.Flag{
		&cli.StringFlag{
			Name:    "file",
			Usage:   "file to write output",
			Aliases: []string{"f"},
		},
		&cli.StringFlag{
			Name:    "output",
			Usage:   "define output formats: yaml, json",
			Aliases: []string{"o"},
		},
	},
}
<commit_msg>extract aliases<commit_after>package clinamespace

import (
	"github.com/containerum/chkit/pkg/model/namespace"
	"github.com/sirupsen/logrus"

	"github.com/containerum/chkit/cmd/util"
	"github.com/containerum/chkit/pkg/model"
	"gopkg.in/urfave/cli.v2"
)

var aliases = []string{"ns", "namespaces"}

// GetNamespace -- commmand 'get' entity data
var GetNamespace = &cli.Command{
	Name:        "namespace",
	Aliases:     aliases,
	Description: `shows namespace data or namespace list. Aliases: ns, namespaces`,
	Usage:       `shows namespace data or namespace list`,
	Action: func(ctx *cli.Context) error {
		client := util.GetClient(ctx)
		defer util.StoreClient(ctx, client)
		var showItem model.Renderer
		var err error

		switch ctx.NArg() {
		case 1:
			namespaceLabel := ctx.Args().First()
			logrus.Debugf("getting namespace %q", namespaceLabel)
			showItem, err = client.GetNamespace(namespaceLabel)
			if err != nil {
				logrus.Debugf("fatal error: %v", err)
				return err
			}
		default:
			var list namespace.NamespaceList
			logrus.Debugf("getting namespace list")
			list, err := client.GetNamespaceList()
			if err != nil {
				logrus.Debugf("fatal error: %v", err)
				return err
			}
			showItem = list
		}
		err = util.WriteData(ctx, showItem)
		if err != nil {
			logrus.Debugf("fatal error: %v", err)
		}
		return err
	},
	Flags: []cli.Flag{
		&cli.StringFlag{
			Name:    "file",
			Usage:   "file to write output",
			Aliases: []string{"f"},
		},
		&cli.StringFlag{
			Name:    "output",
			Usage:   "define output formats: yaml, json",
			Aliases: []string{"o"},
		},
	},
}
<|endoftext|>


<commit_before>package main

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

func newProjectInDir(path string) error {
	// set path to be nested inside $GOPATH/src
	gopath := os.Getenv("GOPATH")
	path = filepath.Join(gopath, "src", path)

	// check if anything exists at the path, ask if it should be overwritten
	if _, err := os.Stat(path); !os.IsNotExist(err) {
		fmt.Println("Path exists, overwrite contents? (y/N):")

		var answer string
		_, err := fmt.Scanf("%s\n", &answer)
		if err != nil {
			if err.Error() == "unexpected newline" {
				answer = ""
			} else {
				return err
			}
		}

		answer = strings.ToLower(answer)

		switch answer {
		case "n", "no", "\r\n", "\n", "":
			fmt.Println("")

		case "y", "yes":
			err := os.RemoveAll(path)
			if err != nil {
				return fmt.Errorf("Failed to overwrite %s. \n%s", path, err)
			}

			return createProjInDir(path)

		default:
			fmt.Println("Input not recognized. No files overwritten. Answer as 'y' or 'n' only.")
		}

		return nil
	}

	return createProjInDir(path)
}

var ponzuRepo = []string{"github.com", "bosssauce", "ponzu"}

func createProjInDir(path string) error {
	gopath := os.Getenv("GOPATH")
	repo := ponzuRepo
	local := filepath.Join(gopath, "src", filepath.Join(repo...))
	network := "https://" + strings.Join(repo, "/") + ".git"

	// create the directory or overwrite it
	err := os.MkdirAll(path, os.ModeDir|os.ModePerm)
	if err != nil {
		return err
	}

	if dev {
		if fork != "" {
			local = filepath.Join(gopath, "src", fork)
		}

		devClone := exec.Command("git", "clone", local, "--branch", "ponzu-dev", "--single-branch", path)
		devClone.Stdout = os.Stdout
		devClone.Stderr = os.Stderr

		err = devClone.Start()
		if err != nil {
			return err
		}

		err = devClone.Wait()
		if err != nil {
			return err
		}

		err = vendorCorePackages(path)
		if err != nil {
			return err
		}

		fmt.Println("Dev build cloned from " + local + ":ponzu-dev")
		return nil
	}

	// try to git clone the repository from the local machine's $GOPATH
	localClone := exec.Command("git", "clone", local, path)
	localClone.Stdout = os.Stdout
	localClone.Stderr = os.Stderr

	err = localClone.Start()
	if err != nil {
		return err
	}
	err = localClone.Wait()
	if err != nil {
		fmt.Println("Couldn't clone from", local, ". Trying network...")

		// try to git clone the repository over the network
		networkClone := exec.Command("git", "clone", network, path)
		networkClone.Stdout = os.Stdout
		networkClone.Stderr = os.Stderr

		err = networkClone.Start()
		if err != nil {
			fmt.Println("Network clone failed to start. Try again and make sure you have a network connection.")
			return err
		}
		err = networkClone.Wait()
		if err != nil {
			fmt.Println("Network clone failure.")
			// failed
			return fmt.Errorf("Failed to clone files from local machine [%s] and over the network [%s].\n%s", local, network, err)
		}
	}

	// create an internal vendor directory in ./cmd/ponzu and move content,
	// management and system packages into it
	err = vendorCorePackages(path)
	if err != nil {
		return err
	}

	gitDir := filepath.Join(path, ".git")
	err = os.RemoveAll(gitDir)
	if err != nil {
		fmt.Println("Failed to remove .git directory from your project path. Consider removing it manually.")
	}

	fmt.Println("New ponzu project created at", path)
	return nil
}

func vendorCorePackages(path string) error {
	vendorPath := filepath.Join(path, "cmd", "ponzu", "vendor", "github.com", "bosssauce", "ponzu")
	err := os.MkdirAll(vendorPath, os.ModeDir|os.ModePerm)
	if err != nil {
		return err
	}

	dirs := []string{"content", "management", "system"}
	for _, dir := range dirs {
		err = os.Rename(filepath.Join(path, dir), filepath.Join(vendorPath, dir))
		if err != nil {
			return err
		}
	}

	// create a user content directory
	contentPath := filepath.Join(path, "content")
	err = os.Mkdir(contentPath, os.ModeDir|os.ModePerm)
	if err != nil {
		return err
	}

	return nil
}

func copyFile(src, dst string) error {
	noRoot := strings.Split(src, string(filepath.Separator))[1:]
	path := filepath.Join(noRoot...)
	dstFile, err := os.Create(filepath.Join(dst, path))
	defer dstFile.Close()
	if err != nil {
		return err
	}

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

	_, err = io.Copy(dstFile, srcFile)
	if err != nil {
		return err
	}

	return nil
}

func copyFilesWarnConflicts(srcDir, dstDir string, conflicts []string) error {
	err := filepath.Walk(srcDir, func(path string, info os.FileInfo, err error) error {
		fmt.Println(path)
		if err != nil {
			return err
		}

		if info.IsDir() {
			fmt.Println(path, srcDir)
			if len(path) > len(srcDir) {
				path = path[len(srcDir)+1:]
			}
			dir := filepath.Join(dstDir, path)
			err := os.MkdirAll(dir, os.ModeDir|os.ModePerm)
			if err != nil {
				return err
			}

			return nil
		}

		for _, conflict := range conflicts {
			if info.Name() == conflict {
				fmt.Println("Ponzu couldn't fully build your project:")
				fmt.Println("You must rename the following file, as it conflicts with Ponzu core:")
				fmt.Println(path)

				fmt.Println("Once the files above have been renamed, run '$ ponzu build' to retry.")
				return errors.New("Ponzu has very few internal conflicts, sorry for the inconvenience.")
			}
		}

		err = copyFile(path, dstDir)
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		return err
	}

	return nil
}

func buildPonzuServer(args []string) error {
	pwd, err := os.Getwd()
	if err != nil {
		return err
	}

	// copy all ./content files to internal vendor directory
	src := "content"
	dst := filepath.Join("cmd", "ponzu", "vendor", "github.com", "bosssauce", "ponzu", "content")
	err = copyFilesWarnConflicts(src, dst, []string{"item.go", "types.go"})
	if err != nil {
		return err
	}

	// copy all ./addons files & dirs to internal vendor directory
	src = "addons"
	dst = filepath.Join("cmd", "ponzu", "vendor")
	err = copyFilesWarnConflicts(src, dst, nil)
	if err != nil {
		return err
	}

	// execute go build -o ponzu-cms cmd/ponzu/*.go
	mainPath := filepath.Join(pwd, "cmd", "ponzu", "main.go")
	optsPath := filepath.Join(pwd, "cmd", "ponzu", "options.go")
	genPath := filepath.Join(pwd, "cmd", "ponzu", "generate.go")
	build := exec.Command("go", "build", "-o", "ponzu-server", mainPath, optsPath, genPath)
	build.Stderr = os.Stderr
	build.Stdout = os.Stdout

	err = build.Start()
	if err != nil {
		return errors.New("Ponzu build step failed. Please try again. " + "\n" + err.Error())

	}
	err = build.Wait()
	if err != nil {
		return errors.New("Ponzu build step failed. Please try again. " + "\n" + err.Error())

	}

	return nil
}
<commit_msg>debug<commit_after>package main

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

func newProjectInDir(path string) error {
	// set path to be nested inside $GOPATH/src
	gopath := os.Getenv("GOPATH")
	path = filepath.Join(gopath, "src", path)

	// check if anything exists at the path, ask if it should be overwritten
	if _, err := os.Stat(path); !os.IsNotExist(err) {
		fmt.Println("Path exists, overwrite contents? (y/N):")

		var answer string
		_, err := fmt.Scanf("%s\n", &answer)
		if err != nil {
			if err.Error() == "unexpected newline" {
				answer = ""
			} else {
				return err
			}
		}

		answer = strings.ToLower(answer)

		switch answer {
		case "n", "no", "\r\n", "\n", "":
			fmt.Println("")

		case "y", "yes":
			err := os.RemoveAll(path)
			if err != nil {
				return fmt.Errorf("Failed to overwrite %s. \n%s", path, err)
			}

			return createProjInDir(path)

		default:
			fmt.Println("Input not recognized. No files overwritten. Answer as 'y' or 'n' only.")
		}

		return nil
	}

	return createProjInDir(path)
}

var ponzuRepo = []string{"github.com", "bosssauce", "ponzu"}

func createProjInDir(path string) error {
	gopath := os.Getenv("GOPATH")
	repo := ponzuRepo
	local := filepath.Join(gopath, "src", filepath.Join(repo...))
	network := "https://" + strings.Join(repo, "/") + ".git"

	// create the directory or overwrite it
	err := os.MkdirAll(path, os.ModeDir|os.ModePerm)
	if err != nil {
		return err
	}

	if dev {
		if fork != "" {
			local = filepath.Join(gopath, "src", fork)
		}

		devClone := exec.Command("git", "clone", local, "--branch", "ponzu-dev", "--single-branch", path)
		devClone.Stdout = os.Stdout
		devClone.Stderr = os.Stderr

		err = devClone.Start()
		if err != nil {
			return err
		}

		err = devClone.Wait()
		if err != nil {
			return err
		}

		err = vendorCorePackages(path)
		if err != nil {
			return err
		}

		fmt.Println("Dev build cloned from " + local + ":ponzu-dev")
		return nil
	}

	// try to git clone the repository from the local machine's $GOPATH
	localClone := exec.Command("git", "clone", local, path)
	localClone.Stdout = os.Stdout
	localClone.Stderr = os.Stderr

	err = localClone.Start()
	if err != nil {
		return err
	}
	err = localClone.Wait()
	if err != nil {
		fmt.Println("Couldn't clone from", local, ". Trying network...")

		// try to git clone the repository over the network
		networkClone := exec.Command("git", "clone", network, path)
		networkClone.Stdout = os.Stdout
		networkClone.Stderr = os.Stderr

		err = networkClone.Start()
		if err != nil {
			fmt.Println("Network clone failed to start. Try again and make sure you have a network connection.")
			return err
		}
		err = networkClone.Wait()
		if err != nil {
			fmt.Println("Network clone failure.")
			// failed
			return fmt.Errorf("Failed to clone files from local machine [%s] and over the network [%s].\n%s", local, network, err)
		}
	}

	// create an internal vendor directory in ./cmd/ponzu and move content,
	// management and system packages into it
	err = vendorCorePackages(path)
	if err != nil {
		return err
	}

	gitDir := filepath.Join(path, ".git")
	err = os.RemoveAll(gitDir)
	if err != nil {
		fmt.Println("Failed to remove .git directory from your project path. Consider removing it manually.")
	}

	fmt.Println("New ponzu project created at", path)
	return nil
}

func vendorCorePackages(path string) error {
	vendorPath := filepath.Join(path, "cmd", "ponzu", "vendor", "github.com", "bosssauce", "ponzu")
	err := os.MkdirAll(vendorPath, os.ModeDir|os.ModePerm)
	if err != nil {
		return err
	}

	dirs := []string{"content", "management", "system"}
	for _, dir := range dirs {
		err = os.Rename(filepath.Join(path, dir), filepath.Join(vendorPath, dir))
		if err != nil {
			return err
		}
	}

	// create a user content directory
	contentPath := filepath.Join(path, "content")
	err = os.Mkdir(contentPath, os.ModeDir|os.ModePerm)
	if err != nil {
		return err
	}

	return nil
}

func copyFile(src, dst string) error {
	noRoot := strings.Split(src, string(filepath.Separator))[1:]
	path := filepath.Join(noRoot...)
	fmt.Println("dstFile:", filepath.Join(dst, path))
	dstFile, err := os.Create(filepath.Join(dst, path))
	defer dstFile.Close()
	if err != nil {
		return err
	}

	fmt.Println("srcFile:", src)
	srcFile, err := os.Open(src)
	defer srcFile.Close()
	if err != nil {
		return err
	}

	_, err = io.Copy(dstFile, srcFile)
	if err != nil {
		return err
	}

	return nil
}

func copyFilesWarnConflicts(srcDir, dstDir string, conflicts []string) error {
	err := filepath.Walk(srcDir, func(path string, info os.FileInfo, err error) error {
		fmt.Println("hit:", path)
		if err != nil {
			return err
		}

		if info.IsDir() {
			if len(path) > len(srcDir) {
				path = path[len(srcDir)+1:]
			}
			dir := filepath.Join(dstDir, path)
			err := os.MkdirAll(dir, os.ModeDir|os.ModePerm)
			if err != nil {
				return err
			}

			return nil
		}

		for _, conflict := range conflicts {
			if info.Name() == conflict {
				fmt.Println("Ponzu couldn't fully build your project:")
				fmt.Println("You must rename the following file, as it conflicts with Ponzu core:")
				fmt.Println(path)

				fmt.Println("Once the files above have been renamed, run '$ ponzu build' to retry.")
				return errors.New("Ponzu has very few internal conflicts, sorry for the inconvenience.")
			}
		}

		err = copyFile(path, dstDir)
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		return err
	}

	return nil
}

func buildPonzuServer(args []string) error {
	pwd, err := os.Getwd()
	if err != nil {
		return err
	}

	// copy all ./content files to internal vendor directory
	src := "content"
	dst := filepath.Join("cmd", "ponzu", "vendor", "github.com", "bosssauce", "ponzu", "content")
	err = copyFilesWarnConflicts(src, dst, []string{"item.go", "types.go"})
	if err != nil {
		return err
	}

	// copy all ./addons files & dirs to internal vendor directory
	src = "addons"
	dst = filepath.Join("cmd", "ponzu", "vendor")
	err = copyFilesWarnConflicts(src, dst, nil)
	if err != nil {
		return err
	}

	// execute go build -o ponzu-cms cmd/ponzu/*.go
	mainPath := filepath.Join(pwd, "cmd", "ponzu", "main.go")
	optsPath := filepath.Join(pwd, "cmd", "ponzu", "options.go")
	genPath := filepath.Join(pwd, "cmd", "ponzu", "generate.go")
	build := exec.Command("go", "build", "-o", "ponzu-server", mainPath, optsPath, genPath)
	build.Stderr = os.Stderr
	build.Stdout = os.Stdout

	err = build.Start()
	if err != nil {
		return errors.New("Ponzu build step failed. Please try again. " + "\n" + err.Error())

	}
	err = build.Wait()
	if err != nil {
		return errors.New("Ponzu build step failed. Please try again. " + "\n" + err.Error())

	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2019 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmdrunner

import (
	"context"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	swarminglib "go.chromium.org/luci/client/cmd/swarming/lib"
	clientswarming "go.chromium.org/luci/client/swarming"
	"go.chromium.org/luci/common/errors"
	commonisolated "go.chromium.org/luci/common/isolated"
	"go.chromium.org/luci/common/isolatedclient"
	"go.chromium.org/luci/common/logging"
	"go.chromium.org/luci/common/system/environ"
	"go.chromium.org/luci/common/system/exec2"
	"go.chromium.org/luci/common/system/filesystem"
)

// ErrHardTimeout is error for timeout from Run command.
var ErrHardTimeout = errors.Reason("timeout happens").Err()

type cipdInfo struct {
	binaryPath string
	cacheDir   string
}

// environSystem is used for mocking in test.
var environSystem = environ.System

// getCommandEnv returns full OS environment to run a command in.
// Sets up TEMP, puts directory with cipd binary in front of PATH, exposes
// CIPD_CACHE_DIR env var, and installs all env_prefixes.
func getCommandEnv(ctx context.Context, tmpDir string, cipdInfo *cipdInfo, runDir string, env environ.Env, envPrefixes map[string][]string, outDir, botFile string) (environ.Env, error) {
	out := environSystem()

	err := env.Iter(func(k, v string) error {
		if v == "" {
			out.Remove(k)
			return nil
		}
		p, err := clientswarming.ReplaceCommandParameters(ctx, v, outDir, botFile)
		if err != nil {
			return fmt.Errorf("failed to call replaceParameters for %s: %v", v, err)
		}
		out.Set(k, p)
		return nil
	})
	if err != nil {
		return nil, err
	}

	if cipdInfo != nil {
		binDir := filepath.Dir(cipdInfo.binaryPath)
		out.Set("PATH", binDir+string(filepath.ListSeparator)+out.GetEmpty("PATH"))
		out.Set("CIPD_CACHE_DIR", cipdInfo.cacheDir)
	}

	for key, paths := range envPrefixes {
		newPaths := make([]string, 0, len(paths))
		for _, p := range paths {
			newPaths = append(newPaths, filepath.Clean(filepath.Join(runDir, p)))
		}
		if cur, ok := out.Get(key); ok {
			newPaths = append(newPaths, cur)
		}
		out.Set(key, strings.Join(newPaths, string(filepath.ListSeparator)))
	}

	// * python respects $TMPDIR, $TEMP, and $TMP in this order, regardless of
	//   platform. So $TMPDIR must be set on all platforms.
	//   https://github.com/python/cpython/blob/2.7/Lib/tempfile.py#L155
	out.Set("TMPDIR", tmpDir)
	if runtime.GOOS == "windows" {
		// * chromium's base utils uses GetTempPath().
		//    https://cs.chromium.org/chromium/src/base/files/file_util_win.cc?q=GetTempPath
		// * Go uses GetTempPath().
		// * GetTempDir() uses %TMP%, then %TEMP%, then other stuff. So %TMP% must be
		//   set.
		//   https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-gettemppathw
		out.Set("TMP", tmpDir)
		// https://blogs.msdn.microsoft.com/oldnewthing/20150417-00/?p=44213
		out.Set("TEMP", tmpDir)
	} else if runtime.GOOS == "darwin" {
		// * Chromium uses an hack on macOS before calling into
		//   NSTemporaryDirectory().
		//   https://cs.chromium.org/chromium/src/base/files/file_util_mac.mm?q=GetTempDir
		//   https://developer.apple.com/documentation/foundation/1409211-nstemporarydirectory
		out.Set("MAC_CHROMIUM_TMPDIR", tmpDir)
	} else {
		// TMPDIR is specified as the POSIX standard envvar for the temp directory.
		// http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html
		// * mktemp on linux respects $TMPDIR.
		// * Chromium respects $TMPDIR on linux.
		//   https://cs.chromium.org/chromium/src/base/files/file_util_posix.cc?q=GetTempDir
		// * Go uses $TMPDIR.
		//   https://go.googlesource.com/go/+/go1.10.3/src/os/file_unix.go#307
	}

	return out, nil
}

// Run runs the command.
func Run(ctx context.Context, command []string, cwd string, env environ.Env, hardTimeout time.Duration, gracePeriod time.Duration, lowerPriority bool, containment bool) (int, error) {
	logging.Infof(ctx, "runCommand(%s, %s, %s, %s, %s, %s, %s)", command, cwd, env, hardTimeout, gracePeriod, lowerPriority, containment)

	cmd := exec2.CommandContext(ctx, command[0], command[1:]...)
	cmd.Env = env.Sorted()
	cmd.Dir = cwd
	// TODO(tikuta): handle STOP_SIGNALS

	if err := cmd.Start(); err != nil {
		fmt.Fprintf(os.Stderr, "failed to run command %s: %v\n", command, err)
		fmt.Fprint(os.Stderr, `<The executable does not exist or a dependent library is missing>
<Check for missing .so/.dll in the .isolate or GN file>
`)
		if _, ok := environ.System().Get(swarminglib.TaskIDEnvVar); ok {
			fmt.Fprint(os.Stderr, `<See the task's page for commands to help diagnose this issue by reproducing the task locally>
`)
		}
		return 1, errors.Annotate(err, "failed to start command").Err()
	}

	errCh := make(chan error, 1)
	go func() {
		err := cmd.Wait()
		if e, ok := err.(*exec.ExitError); ok && e.Exited() {
			// Ignore exited error.
			err = nil
		} else {
			cmd.Kill()
		}
		errCh <- err
	}()

	select {
	case err := <-errCh:
		if err != nil {
			return 1, err
		}
		return cmd.ProcessState.ExitCode(), nil
	case <-time.After(hardTimeout):
	}

	if err := cmd.Terminate(); err != nil {
		logging.Warningf(ctx, "failed to call Terminate: %v", err)
	}

	select {
	case err := <-errCh:
		if err != nil {
			return 1, err
		}
		// Process exited fast enough after a nudge. Happy path.
		return cmd.ProcessState.ExitCode(), ErrHardTimeout
	case <-time.After(gracePeriod):
	}

	// Process didn't exit in time after a nudge, try to kill it.
	cmd.Kill()
	return 1, ErrHardTimeout
}

func linkOutputsToOutdir(runDir, outDir string, outputs []string) error {
	if err := filesystem.CreateDirectories(outDir, outputs); err != nil {
		return errors.Annotate(err, "failed to create directory").Err()
	}

	for _, output := range outputs {
		src := filepath.Join(runDir, output)
		dst := filepath.Join(outDir, output)
		if err := filesystem.HardlinkRecursively(src, dst); err != nil {
			return errors.Annotate(err, "failed to copy output from %s to %s", src, dst).Err()
		}
	}

	return nil
}

// UploadStats is stats of upload or uploadThenDelete.
type UploadStats struct {
	Duration time.Duration `json:"duration"`

	ItemsCold []byte `json:"items_cold"`
	ItemsHot  []byte `json:"items_hot"`
}

func upload(ctx context.Context, client *isolatedclient.Client, baseDir, outDir string) (commonisolated.HexDigest, *UploadStats, error) {
	start := time.Now()
	absOutDir := filepath.Join(baseDir, outDir)

	isEmpty, err := filesystem.IsEmptyDir(absOutDir)
	if err != nil {
		return "", nil, errors.Annotate(err, "failed to call IsEmptyDir(%s)", absOutDir).Err()
	}

	var stats UploadStats
	var digest commonisolated.HexDigest

	if !isEmpty {
		// TODO: implement CAS archive.
	}

	stats.Duration = time.Now().Sub(start)
	return digest, &stats, nil
}

func uploadThenDelete(ctx context.Context, client *isolatedclient.Client, baseDir, outDir string) (digest commonisolated.HexDigest, stats *UploadStats, err error) {
	start := time.Now()

	defer func() {
		absOutDir := filepath.Join(baseDir, outDir)
		removeErr := filesystem.RemoveAll(absOutDir)
		if err == nil && removeErr != nil {
			err = errors.Annotate(removeErr, "failed to call RemoveAll(%s)", absOutDir).Err()
		}
		stats.Duration = time.Now().Sub(start)
	}()

	digest, stats, err = upload(ctx, client, baseDir, outDir)
	if err != nil {
		return "", nil, errors.Annotate(err, "failed to call upload").Err()
	}

	return digest, stats, nil
}
<commit_msg>Remove common/{isolated, isolatedclient} from cmdrunner<commit_after>// Copyright 2019 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmdrunner

import (
	"context"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	swarminglib "go.chromium.org/luci/client/cmd/swarming/lib"
	clientswarming "go.chromium.org/luci/client/swarming"
	"go.chromium.org/luci/common/errors"
	"go.chromium.org/luci/common/logging"
	"go.chromium.org/luci/common/system/environ"
	"go.chromium.org/luci/common/system/exec2"
	"go.chromium.org/luci/common/system/filesystem"
)

// ErrHardTimeout is error for timeout from Run command.
var ErrHardTimeout = errors.Reason("timeout happens").Err()

type cipdInfo struct {
	binaryPath string
	cacheDir   string
}

// environSystem is used for mocking in test.
var environSystem = environ.System

// getCommandEnv returns full OS environment to run a command in.
// Sets up TEMP, puts directory with cipd binary in front of PATH, exposes
// CIPD_CACHE_DIR env var, and installs all env_prefixes.
func getCommandEnv(ctx context.Context, tmpDir string, cipdInfo *cipdInfo, runDir string, env environ.Env, envPrefixes map[string][]string, outDir, botFile string) (environ.Env, error) {
	out := environSystem()

	err := env.Iter(func(k, v string) error {
		if v == "" {
			out.Remove(k)
			return nil
		}
		p, err := clientswarming.ReplaceCommandParameters(ctx, v, outDir, botFile)
		if err != nil {
			return fmt.Errorf("failed to call replaceParameters for %s: %v", v, err)
		}
		out.Set(k, p)
		return nil
	})
	if err != nil {
		return nil, err
	}

	if cipdInfo != nil {
		binDir := filepath.Dir(cipdInfo.binaryPath)
		out.Set("PATH", binDir+string(filepath.ListSeparator)+out.GetEmpty("PATH"))
		out.Set("CIPD_CACHE_DIR", cipdInfo.cacheDir)
	}

	for key, paths := range envPrefixes {
		newPaths := make([]string, 0, len(paths))
		for _, p := range paths {
			newPaths = append(newPaths, filepath.Clean(filepath.Join(runDir, p)))
		}
		if cur, ok := out.Get(key); ok {
			newPaths = append(newPaths, cur)
		}
		out.Set(key, strings.Join(newPaths, string(filepath.ListSeparator)))
	}

	// * python respects $TMPDIR, $TEMP, and $TMP in this order, regardless of
	//   platform. So $TMPDIR must be set on all platforms.
	//   https://github.com/python/cpython/blob/2.7/Lib/tempfile.py#L155
	out.Set("TMPDIR", tmpDir)
	if runtime.GOOS == "windows" {
		// * chromium's base utils uses GetTempPath().
		//    https://cs.chromium.org/chromium/src/base/files/file_util_win.cc?q=GetTempPath
		// * Go uses GetTempPath().
		// * GetTempDir() uses %TMP%, then %TEMP%, then other stuff. So %TMP% must be
		//   set.
		//   https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-gettemppathw
		out.Set("TMP", tmpDir)
		// https://blogs.msdn.microsoft.com/oldnewthing/20150417-00/?p=44213
		out.Set("TEMP", tmpDir)
	} else if runtime.GOOS == "darwin" {
		// * Chromium uses an hack on macOS before calling into
		//   NSTemporaryDirectory().
		//   https://cs.chromium.org/chromium/src/base/files/file_util_mac.mm?q=GetTempDir
		//   https://developer.apple.com/documentation/foundation/1409211-nstemporarydirectory
		out.Set("MAC_CHROMIUM_TMPDIR", tmpDir)
	} else {
		// TMPDIR is specified as the POSIX standard envvar for the temp directory.
		// http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html
		// * mktemp on linux respects $TMPDIR.
		// * Chromium respects $TMPDIR on linux.
		//   https://cs.chromium.org/chromium/src/base/files/file_util_posix.cc?q=GetTempDir
		// * Go uses $TMPDIR.
		//   https://go.googlesource.com/go/+/go1.10.3/src/os/file_unix.go#307
	}

	return out, nil
}

// Run runs the command.
func Run(ctx context.Context, command []string, cwd string, env environ.Env, hardTimeout time.Duration, gracePeriod time.Duration, lowerPriority bool, containment bool) (int, error) {
	logging.Infof(ctx, "runCommand(%s, %s, %s, %s, %s, %s, %s)", command, cwd, env, hardTimeout, gracePeriod, lowerPriority, containment)

	cmd := exec2.CommandContext(ctx, command[0], command[1:]...)
	cmd.Env = env.Sorted()
	cmd.Dir = cwd
	// TODO(tikuta): handle STOP_SIGNALS

	if err := cmd.Start(); err != nil {
		fmt.Fprintf(os.Stderr, "failed to run command %s: %v\n", command, err)
		fmt.Fprint(os.Stderr, `<The executable does not exist or a dependent library is missing>
<Check for missing .so/.dll in the .isolate or GN file>
`)
		if _, ok := environ.System().Get(swarminglib.TaskIDEnvVar); ok {
			fmt.Fprint(os.Stderr, `<See the task's page for commands to help diagnose this issue by reproducing the task locally>
`)
		}
		return 1, errors.Annotate(err, "failed to start command").Err()
	}

	errCh := make(chan error, 1)
	go func() {
		err := cmd.Wait()
		if e, ok := err.(*exec.ExitError); ok && e.Exited() {
			// Ignore exited error.
			err = nil
		} else {
			cmd.Kill()
		}
		errCh <- err
	}()

	select {
	case err := <-errCh:
		if err != nil {
			return 1, err
		}
		return cmd.ProcessState.ExitCode(), nil
	case <-time.After(hardTimeout):
	}

	if err := cmd.Terminate(); err != nil {
		logging.Warningf(ctx, "failed to call Terminate: %v", err)
	}

	select {
	case err := <-errCh:
		if err != nil {
			return 1, err
		}
		// Process exited fast enough after a nudge. Happy path.
		return cmd.ProcessState.ExitCode(), ErrHardTimeout
	case <-time.After(gracePeriod):
	}

	// Process didn't exit in time after a nudge, try to kill it.
	cmd.Kill()
	return 1, ErrHardTimeout
}

func linkOutputsToOutdir(runDir, outDir string, outputs []string) error {
	if err := filesystem.CreateDirectories(outDir, outputs); err != nil {
		return errors.Annotate(err, "failed to create directory").Err()
	}

	for _, output := range outputs {
		src := filepath.Join(runDir, output)
		dst := filepath.Join(outDir, output)
		if err := filesystem.HardlinkRecursively(src, dst); err != nil {
			return errors.Annotate(err, "failed to copy output from %s to %s", src, dst).Err()
		}
	}

	return nil
}

// UploadStats is stats of upload or uploadThenDelete.
type UploadStats struct {
	Duration time.Duration `json:"duration"`

	ItemsCold []byte `json:"items_cold"`
	ItemsHot  []byte `json:"items_hot"`
}

func upload(ctx context.Context, baseDir, outDir string) (*UploadStats, error) {
	start := time.Now()
	absOutDir := filepath.Join(baseDir, outDir)

	isEmpty, err := filesystem.IsEmptyDir(absOutDir)
	if err != nil {
		return nil, errors.Annotate(err, "failed to call IsEmptyDir(%s)", absOutDir).Err()
	}

	var stats UploadStats

	if !isEmpty {
		// TODO: implement CAS archive.
	}

	stats.Duration = time.Now().Sub(start)
	return &stats, nil
}

func uploadThenDelete(ctx context.Context, baseDir, outDir string) (stats *UploadStats, err error) {
	start := time.Now()

	defer func() {
		absOutDir := filepath.Join(baseDir, outDir)
		removeErr := filesystem.RemoveAll(absOutDir)
		if err == nil && removeErr != nil {
			err = errors.Annotate(removeErr, "failed to call RemoveAll(%s)", absOutDir).Err()
		}
		stats.Duration = time.Now().Sub(start)
	}()

	stats, err = upload(ctx, baseDir, outDir)
	if err != nil {
		return nil, errors.Annotate(err, "failed to call upload").Err()
	}

	return stats, nil
}
<|endoftext|>


<commit_before>// Package safecookie provides secure encoding and decoding for cookies which
// provides both confidentiality and authenticity against both active and
// passive attackers.
//
// It does so by sealing a cookie's value with an AEAD using the cookie's name
// as the authenticated data. If the cookie's name or value change at all, the
// opening process will fail.
//
// This provides some important guarantees:
//
//     - No one who does not have the secret key can read the cookie's plaintext
//       value.
//
//     - No one who does not have the secret key can create a cookie which will
//       be considered valid.
//
//     - Any cookie which has had its name or value changed will be considered
//       invalid.
//
// Cookie values are gobs, so be sure to register the types via
// gob.RegisterType.
package safecookie

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/base64"
	"encoding/gob"
	"errors"
	"net/http"
)

var (
	// ErrInvalidCookie is returned if the cookie is invalid.
	ErrInvalidCookie = errors.New("invalid cookie")
)

// SafeCookie seals cookies and opens them.
type SafeCookie struct {
	// AEAD is the Authenticated Encryption And Data algorithm to use for
	// encrypting and decrypting cookie values.
	AEAD cipher.AEAD
}

// NewGCM returns a new AES-GCM-based SafeCookie instance given a 128-, 192-, or
// 256-bit key.
func NewGCM(key []byte) (*SafeCookie, error) {
	b, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	gcm, err := cipher.NewGCM(b)
	if err != nil {
		return nil, err
	}

	return &SafeCookie{AEAD: gcm}, nil
}

// Seal marshals the given value into a gob, encrypts that using the cookie's
// name as authenticated data, and sets the cookie's value to the Base64-encoded
// ciphertext.
func (sc *SafeCookie) Seal(e interface{}, c *http.Cookie) error {
	w := bytes.NewBuffer(nil)
	if err := gob.NewEncoder(w).Encode(e); err != nil {
		return err
	}

	nonce := make([]byte, sc.AEAD.NonceSize())
	if _, err := rand.Read(nonce); err != nil {
		return err
	}

	ciphertext := sc.AEAD.Seal(nonce, nonce, w.Bytes(), []byte(c.Name))
	c.Value = base64.URLEncoding.EncodeToString(ciphertext)

	return nil
}

// Open decodes the cookie's value as Base64, decrypts it (authenticating the
// cookie name), and unmarshals the resulting gob into the given pointer. If the
// cookie is invalid, it returns ErrInvalidCookie.
func (sc *SafeCookie) Open(c *http.Cookie, e interface{}) error {
	b, err := base64.URLEncoding.DecodeString(c.Value)
	if err != nil || len(b) <= sc.AEAD.NonceSize() {
		return ErrInvalidCookie
	}

	nonce := b[:sc.AEAD.NonceSize()]
	ciphertext := b[sc.AEAD.NonceSize():]

	b, err = sc.AEAD.Open(nil, nonce, ciphertext, []byte(c.Name))
	if err != nil {
		return ErrInvalidCookie
	}

	return gob.NewDecoder(bytes.NewReader(b)).Decode(e)
}
<commit_msg>Docfix.<commit_after>// Package safecookie provides secure encoding and decoding for cookies which
// provides both confidentiality and authenticity against both active and
// passive attackers.
//
// It does so by sealing a cookie's value with an AEAD using the cookie's name
// as the authenticated data. If the cookie's name or value change at all, the
// opening process will fail.
//
// This provides some important guarantees:
//
//     - No one who does not have the secret key can read the cookie's plaintext
//       value.
//
//     - No one who does not have the secret key can create a cookie which will
//       be considered valid.
//
//     - Any cookie which has had its name or value changed will be considered
//       invalid.
//
// Cookie values are gobs, so be sure to register the types via gob.Register.
package safecookie

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/base64"
	"encoding/gob"
	"errors"
	"net/http"
)

var (
	// ErrInvalidCookie is returned if the cookie is invalid.
	ErrInvalidCookie = errors.New("invalid cookie")
)

// SafeCookie seals cookies and opens them.
type SafeCookie struct {
	// AEAD is the Authenticated Encryption And Data algorithm to use for
	// encrypting and decrypting cookie values.
	AEAD cipher.AEAD
}

// NewGCM returns a new AES-GCM-based SafeCookie instance given a 128-, 192-, or
// 256-bit key.
func NewGCM(key []byte) (*SafeCookie, error) {
	b, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	gcm, err := cipher.NewGCM(b)
	if err != nil {
		return nil, err
	}

	return &SafeCookie{AEAD: gcm}, nil
}

// Seal marshals the given value into a gob, encrypts that using the cookie's
// name as authenticated data, and sets the cookie's value to the Base64-encoded
// ciphertext.
func (sc *SafeCookie) Seal(e interface{}, c *http.Cookie) error {
	w := bytes.NewBuffer(nil)
	if err := gob.NewEncoder(w).Encode(e); err != nil {
		return err
	}

	nonce := make([]byte, sc.AEAD.NonceSize())
	if _, err := rand.Read(nonce); err != nil {
		return err
	}

	ciphertext := sc.AEAD.Seal(nonce, nonce, w.Bytes(), []byte(c.Name))
	c.Value = base64.URLEncoding.EncodeToString(ciphertext)

	return nil
}

// Open decodes the cookie's value as Base64, decrypts it (authenticating the
// cookie name), and unmarshals the resulting gob into the given pointer. If the
// cookie is invalid, it returns ErrInvalidCookie.
func (sc *SafeCookie) Open(c *http.Cookie, e interface{}) error {
	b, err := base64.URLEncoding.DecodeString(c.Value)
	if err != nil || len(b) <= sc.AEAD.NonceSize() {
		return ErrInvalidCookie
	}

	nonce := b[:sc.AEAD.NonceSize()]
	ciphertext := b[sc.AEAD.NonceSize():]

	b, err = sc.AEAD.Open(nil, nonce, ciphertext, []byte(c.Name))
	if err != nil {
		return ErrInvalidCookie
	}

	return gob.NewDecoder(bytes.NewReader(b)).Decode(e)
}
<|endoftext|>


<commit_before>/*
 * Datadog API for Go
 *
 * Please see the included LICENSE file for licensing information.
 *
 * Copyright 2013 by authors and contributors.
 */

package datadog

import (
	"fmt"
)

// GraphDefinitionRequests are the actual elements in a graph definition.
type GraphDefinitionRequests struct {
	Query   string `json:"q"`
	Stacked bool   `json:"stacked"`
}

// GraphDefinition encapsulates configuration information for a graph.
type GraphDefinition struct {
	Viz      string                    `json:"viz"`
	Requests []GraphDefinitionRequests `json:"requests"`
}

// GraphEvents are events that show on a graph.
type GraphEvents struct {
}

// Graph represents a graph that might exist on a dashboard.
type Graph struct {
	Title      string          `json:"title"`
	Events     []GraphEvents   `json:"events"`
	Definition GraphDefinition `json:"definition"`
}

// Dashboard represents a user created dashboard. This is the full dashboard
// struct when we load a dashboard in detail.
type Dashboard struct {
	Id          int     `json:"id"`
	Description string  `json:"description"`
	Title       string  `json:"title"`
	Graphs      []Graph `json:"graphs"`
}

// DashboardLite represents a user created dashboard. This is the mini
// struct when we load the summaries.
type DashboardLite struct {
	Id          int    `json:"id,string"` // TODO: Remove ',string'.
	Resource    string `json:"resource"`
	Description string `json:"description"`
	Title       string `json:"title"`
}

// reqGetDashboards from /api/v1/dash
type reqGetDashboards struct {
	Dashboards []DashboardLite `json:"dashes"`
}

// reqGetDashboard from /api/v1/dash/:dashboard_id
type reqGetDashboard struct {
	Resource  string    `json:"resource"`
	Url       string    `json:"url"`
	Dashboard Dashboard `json:"dash"`
}

// GetDashboard returns a single dashboard created on this account.
func (self *Client) GetDashboard(id int) (*Dashboard, error) {
	var out reqGetDashboard
	err := self.doJsonRequest("GET", fmt.Sprintf("/v1/dash/%d", id), nil, &out)
	if err != nil {
		return nil, err
	}
	return &out.Dashboard, nil
}

// GetDashboards returns a list of all dashboards created on this account.
func (self *Client) GetDashboards() ([]DashboardLite, error) {
	var out reqGetDashboards
	err := self.doJsonRequest("GET", "/v1/dash", nil, &out)
	if err != nil {
		return nil, err
	}
	return out.Dashboards, nil
}

// DeleteDashboard deletes a dashboard by the identifier.
func (self *Client) DeleteDashboard(id int) error {
	return self.doJsonRequest("DELETE", fmt.Sprintf("/v1/dash/%d", id), nil, nil)
}

// CreateDashboard creates a new dashboard when given a Dashboard struct. Note
// that the Id, Resource, Url and similar elements are not used in creation.
func (self *Client) CreateDashboard(dash *Dashboard) (*Dashboard, error) {
	var out reqGetDashboard
	err := self.doJsonRequest("POST", "/v1/dash", dash, &out)
	if err != nil {
		return nil, err
	}
	return &out.Dashboard, nil
}

// UpdateDashboard in essence takes a Dashboard struct and persists it back to
// the server. Use this if you've updated your local and need to push it back.
func (self *Client) UpdateDashboard(dash *Dashboard) error {
	err := self.doJsonRequest("PUT",
		fmt.Sprintf("/v1/dash/%d", dash.Id), dash, nil)
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>Collapse graph related structs<commit_after>/*
 * Datadog API for Go
 *
 * Please see the included LICENSE file for licensing information.
 *
 * Copyright 2013 by authors and contributors.
 */

package datadog

import (
	"fmt"
)

// Graph represents a graph that might exist on a dashboard.
type Graph struct {
	Title      string     `json:"title"`
	Events     []struct{} `json:"events"`
	Definition struct {
		Viz      string `json:"viz"`
		Requests []struct {
			Query   string `json:"q"`
			Stacked bool   `json:"stacked"`
		} `json:"requests"`
	} `json:"definition"`
}

// Dashboard represents a user created dashboard. This is the full dashboard
// struct when we load a dashboard in detail.
type Dashboard struct {
	Id          int     `json:"id"`
	Description string  `json:"description"`
	Title       string  `json:"title"`
	Graphs      []Graph `json:"graphs"`
}

// DashboardLite represents a user created dashboard. This is the mini
// struct when we load the summaries.
type DashboardLite struct {
	Id          int    `json:"id,string"` // TODO: Remove ',string'.
	Resource    string `json:"resource"`
	Description string `json:"description"`
	Title       string `json:"title"`
}

// reqGetDashboards from /api/v1/dash
type reqGetDashboards struct {
	Dashboards []DashboardLite `json:"dashes"`
}

// reqGetDashboard from /api/v1/dash/:dashboard_id
type reqGetDashboard struct {
	Resource  string    `json:"resource"`
	Url       string    `json:"url"`
	Dashboard Dashboard `json:"dash"`
}

// GetDashboard returns a single dashboard created on this account.
func (self *Client) GetDashboard(id int) (*Dashboard, error) {
	var out reqGetDashboard
	err := self.doJsonRequest("GET", fmt.Sprintf("/v1/dash/%d", id), nil, &out)
	if err != nil {
		return nil, err
	}
	return &out.Dashboard, nil
}

// GetDashboards returns a list of all dashboards created on this account.
func (self *Client) GetDashboards() ([]DashboardLite, error) {
	var out reqGetDashboards
	err := self.doJsonRequest("GET", "/v1/dash", nil, &out)
	if err != nil {
		return nil, err
	}
	return out.Dashboards, nil
}

// DeleteDashboard deletes a dashboard by the identifier.
func (self *Client) DeleteDashboard(id int) error {
	return self.doJsonRequest("DELETE", fmt.Sprintf("/v1/dash/%d", id), nil, nil)
}

// CreateDashboard creates a new dashboard when given a Dashboard struct. Note
// that the Id, Resource, Url and similar elements are not used in creation.
func (self *Client) CreateDashboard(dash *Dashboard) (*Dashboard, error) {
	var out reqGetDashboard
	err := self.doJsonRequest("POST", "/v1/dash", dash, &out)
	if err != nil {
		return nil, err
	}
	return &out.Dashboard, nil
}

// UpdateDashboard in essence takes a Dashboard struct and persists it back to
// the server. Use this if you've updated your local and need to push it back.
func (self *Client) UpdateDashboard(dash *Dashboard) error {
	err := self.doJsonRequest("PUT",
		fmt.Sprintf("/v1/dash/%d", dash.Id), dash, nil)
	if err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"encoding/json"
	"net/http"
	"os"
	"strings"

	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
	"github.com/xyproto/simpleredis"
)

var (
	masterPool *simpleredis.ConnectionPool
	replicaPool  *simpleredis.ConnectionPool
)

func ListRangeHandler(rw http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["key"]
	list := simpleredis.NewList(replicaPool, key)
	members := HandleError(list.GetAll()).([]string)
	membersJSON := HandleError(json.MarshalIndent(members, "", "  ")).([]byte)
	rw.Write(membersJSON)
}

func ListPushHandler(rw http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["key"]
	value := mux.Vars(req)["value"]
	list := simpleredis.NewList(masterPool, key)
	HandleError(nil, list.Add(value))
	ListRangeHandler(rw, req)
}

func InfoHandler(rw http.ResponseWriter, req *http.Request) {
	info := HandleError(masterPool.Get(0).Do("INFO")).([]byte)
	rw.Write(info)
}

func EnvHandler(rw http.ResponseWriter, req *http.Request) {
	environment := make(map[string]string)
	for _, item := range os.Environ() {
		splits := strings.Split(item, "=")
		key := splits[0]
		val := strings.Join(splits[1:], "=")
		environment[key] = val
	}

	envJSON := HandleError(json.MarshalIndent(environment, "", "  ")).([]byte)
	rw.Write(envJSON)
}

func HandleError(result interface{}, err error) (r interface{}) {
	if err != nil {
		panic(err)
	}
	return result
}

func main() {
	masterPool = simpleredis.NewConnectionPoolHost("redis-master:6379")
	defer masterPool.Close()
	replicaPool = simpleredis.NewConnectionPoolHost("redis-slave:6379")
	defer replicaPool.Close()

	r := mux.NewRouter()
	r.Path("/lrange/{key}").Methods("GET").HandlerFunc(ListRangeHandler)
	r.Path("/rpush/{key}/{value}").Methods("GET").HandlerFunc(ListPushHandler)
	r.Path("/info").Methods("GET").HandlerFunc(InfoHandler)
	r.Path("/env").Methods("GET").HandlerFunc(EnvHandler)

	n := negroni.Classic()
	n.UseHandler(r)
	n.Run(":3000")
}
<commit_msg>more main.go fix up<commit_after>/*
Copyright 2014 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"encoding/json"
	"net/http"
	"os"
	"strings"

	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
	"github.com/xyproto/simpleredis"
)

var (
	masterPool *simpleredis.ConnectionPool
	replicaPool  *simpleredis.ConnectionPool
)

func ListRangeHandler(rw http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["key"]
	list := simpleredis.NewList(replicaPool, key)
	members := HandleError(list.GetAll()).([]string)
	membersJSON := HandleError(json.MarshalIndent(members, "", "  ")).([]byte)
	rw.Write(membersJSON)
}

func ListPushHandler(rw http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["key"]
	value := mux.Vars(req)["value"]
	list := simpleredis.NewList(masterPool, key)
	HandleError(nil, list.Add(value))
	ListRangeHandler(rw, req)
}

func InfoHandler(rw http.ResponseWriter, req *http.Request) {
	info := HandleError(masterPool.Get(0).Do("INFO")).([]byte)
	rw.Write(info)
}

func EnvHandler(rw http.ResponseWriter, req *http.Request) {
	environment := make(map[string]string)
	for _, item := range os.Environ() {
		splits := strings.Split(item, "=")
		key := splits[0]
		val := strings.Join(splits[1:], "=")
		environment[key] = val
	}

	envJSON := HandleError(json.MarshalIndent(environment, "", "  ")).([]byte)
	rw.Write(envJSON)
}

func HandleError(result interface{}, err error) (r interface{}) {
	if err != nil {
		panic(err)
	}
	return result
}

func main() {
	masterPool = simpleredis.NewConnectionPoolHost("redis-master:6379")
	defer masterPool.Close()
	replicaPool = simpleredis.NewConnectionPoolHost("redis-replica:6379")
	defer replicaPool.Close()

	r := mux.NewRouter()
	r.Path("/lrange/{key}").Methods("GET").HandlerFunc(ListRangeHandler)
	r.Path("/rpush/{key}/{value}").Methods("GET").HandlerFunc(ListPushHandler)
	r.Path("/info").Methods("GET").HandlerFunc(InfoHandler)
	r.Path("/env").Methods("GET").HandlerFunc(EnvHandler)

	n := negroni.Classic()
	n.UseHandler(r)
	n.Run(":3000")
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"

	"github.com/ant0ine/go-json-rest/rest"
	"github.com/codegangsta/cli"
)

const (
	EnvProd = "prod"
	EnvDev  = "dev"
)

var DefaultDevStack = []rest.Middleware{

	// logging
	&rest.AccessLogApacheMiddleware{},
	&rest.TimerMiddleware{},
	&rest.RecorderMiddleware{},

	// catches the panic errors that occur with stack trace
	&rest.RecoverMiddleware{
		EnableResponseStackTrace: true,
	},

	// json pretty print
	&rest.JsonIndentMiddleware{},

	// verifies the request Content-Type header
	// The expected Content-Type is 'application/json'
	// if the content is non-null
	&rest.ContentTypeCheckerMiddleware{},
}

var DefaultProdStack = []rest.Middleware{

	// logging
	&rest.AccessLogJsonMiddleware{
		// No prefix or other fields, entire output is JSON encoded and could break it.
		Logger: log.New(os.Stdout, "", 0),
	},
	&rest.TimerMiddleware{},
	&rest.RecorderMiddleware{},

	// catches the panic errorsx
	&rest.RecoverMiddleware{},

	// response compression
	&rest.GzipMiddleware{},

	// verifies the request Content-Type header
	// The expected Content-Type is 'application/json'
	// if the content is non-null
	&rest.ContentTypeCheckerMiddleware{},
}

func InstallMiddleware(c *cli.Context, api *rest.Api) {

	env := c.String(EnvFlag)

	switch env {
	case EnvProd:
		api.Use(DefaultProdStack...)
	case EnvDev:
		api.Use(DefaultDevStack...)
	default:
		log.Fatal(InvalidValueError(EnvFlag, env))
	}

	api.Use(&rest.CorsMiddleware{
		RejectNonCorsRequests: false,
		// Accept all requests
		// Should be tested with some list
		OriginValidator: func(origin string, request *rest.Request) bool {
			return true
		},
	})

	api.Use(&rest.AuthBasicMiddleware{
		Realm: "artifacts",
		Authenticator: func(userId string, password string) bool {
			if userId == password {
				return true
			}
			return false
		},
	})
}
<commit_msg>Remove authentication to simplify integration with UI.<commit_after>package main

import (
	"log"
	"os"

	"github.com/ant0ine/go-json-rest/rest"
	"github.com/codegangsta/cli"
)

const (
	EnvProd = "prod"
	EnvDev  = "dev"
)

var DefaultDevStack = []rest.Middleware{

	// logging
	&rest.AccessLogApacheMiddleware{},
	&rest.TimerMiddleware{},
	&rest.RecorderMiddleware{},

	// catches the panic errors that occur with stack trace
	&rest.RecoverMiddleware{
		EnableResponseStackTrace: true,
	},

	// json pretty print
	&rest.JsonIndentMiddleware{},

	// verifies the request Content-Type header
	// The expected Content-Type is 'application/json'
	// if the content is non-null
	&rest.ContentTypeCheckerMiddleware{},
}

var DefaultProdStack = []rest.Middleware{

	// logging
	&rest.AccessLogJsonMiddleware{
		// No prefix or other fields, entire output is JSON encoded and could break it.
		Logger: log.New(os.Stdout, "", 0),
	},
	&rest.TimerMiddleware{},
	&rest.RecorderMiddleware{},

	// catches the panic errorsx
	&rest.RecoverMiddleware{},

	// response compression
	&rest.GzipMiddleware{},

	// verifies the request Content-Type header
	// The expected Content-Type is 'application/json'
	// if the content is non-null
	&rest.ContentTypeCheckerMiddleware{},
}

func InstallMiddleware(c *cli.Context, api *rest.Api) {

	env := c.String(EnvFlag)

	switch env {
	case EnvProd:
		api.Use(DefaultProdStack...)
	case EnvDev:
		api.Use(DefaultDevStack...)
	default:
		log.Fatal(InvalidValueError(EnvFlag, env))
	}

	api.Use(&rest.CorsMiddleware{
		RejectNonCorsRequests: false,
		// Accept all requests
		// Should be tested with some list
		OriginValidator: func(origin string, request *rest.Request) bool {
			return true
		},
	})
}
<|endoftext|>


<commit_before>package buffalo

import (
	"reflect"
	"runtime"
	"strings"
)

type MiddlewareFunc func(Handler) Handler

func (a *App) Use(mw MiddlewareFunc) {
	stack := a.middlewareStack.stack
	a.middlewareStack.stack = append(stack, mw)
}

func (a *App) Skip(mw MiddlewareFunc, handlers ...Handler) {
	ms := &a.middlewareStack
	ms.skip(mw, handlers...)
}

type middlewareStack struct {
	stack []MiddlewareFunc
	skips map[string]bool
}

func (ms *middlewareStack) skip(mw MiddlewareFunc, handlers ...Handler) {
	for _, h := range handlers {
		ms.skips[funcKey(mw, h)] = true
	}
}

func (ms *middlewareStack) handler(h Handler) Handler {
	if len(ms.stack) > 0 {
		mh := func(_ Handler) Handler {
			return h
		}

		tstack := []MiddlewareFunc{mh}

		sl := len(ms.stack) - 1
		for i := sl; i >= 0; i-- {
			mw := ms.stack[i]
			if !ms.skips[funcKey(mw, h)] {
				tstack = append(tstack, mw)
			}
		}

		for _, mw := range tstack {
			h = mw(h)
		}
		return h
	}
	return h
}

func newMiddlewareStack(mws ...MiddlewareFunc) middlewareStack {
	return middlewareStack{
		stack: mws,
		skips: map[string]bool{},
	}
}

func funcKey(funcs ...interface{}) string {
	names := []string{}
	for _, f := range funcs {
		n := runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
		names = append(names, n)
	}
	return strings.Join(names, "/")
}
<commit_msg>accepted multiple MiddlewareFuncs with Use<commit_after>package buffalo

import (
	"reflect"
	"runtime"
	"strings"
)

type MiddlewareFunc func(Handler) Handler

func (a *App) Use(mw ...MiddlewareFunc) {
	stack := a.middlewareStack.stack
	a.middlewareStack.stack = append(stack, mw...)
}

func (a *App) Skip(mw MiddlewareFunc, handlers ...Handler) {
	ms := &a.middlewareStack
	ms.skip(mw, handlers...)
}

type middlewareStack struct {
	stack []MiddlewareFunc
	skips map[string]bool
}

func (ms *middlewareStack) skip(mw MiddlewareFunc, handlers ...Handler) {
	for _, h := range handlers {
		ms.skips[funcKey(mw, h)] = true
	}
}

func (ms *middlewareStack) handler(h Handler) Handler {
	if len(ms.stack) > 0 {
		mh := func(_ Handler) Handler {
			return h
		}

		tstack := []MiddlewareFunc{mh}

		sl := len(ms.stack) - 1
		for i := sl; i >= 0; i-- {
			mw := ms.stack[i]
			if !ms.skips[funcKey(mw, h)] {
				tstack = append(tstack, mw)
			}
		}

		for _, mw := range tstack {
			h = mw(h)
		}
		return h
	}
	return h
}

func newMiddlewareStack(mws ...MiddlewareFunc) middlewareStack {
	return middlewareStack{
		stack: mws,
		skips: map[string]bool{},
	}
}

func funcKey(funcs ...interface{}) string {
	names := []string{}
	for _, f := range funcs {
		n := runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
		names = append(names, n)
	}
	return strings.Join(names, "/")
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
)

func HTTPSRedirect(w http.ResponseWriter, r *http.Request) {
	http.Redirect(w, r, fmt.Sprintf("https://%s:443%s", SERVER_ADDR, r.RequestURI), http.StatusMovedPermanently)
}

// Adds `Access-Control-*` headers to response
func CorsMiddleware(fn func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "OPTIONS" {
			w.Header().Set("Access-Control-Allow-Methods", "GET, POST")
			w.Header().Set("Access-Control-Max-Age", strconv.Itoa(60*60*6))
			w.Header().Set("Access-Control-Allow-Headers", "CONTENT-TYPE, ACCEPT")
			// FIXME: for some reason, the `Access-Control-Request-Headers` never seems to exist in requests
			// if v, ok := r.Header["Access-Control-Request-Headers"]; ok {
			//  w.Header().Set("Access-Control-Allow-Headers", v[0])
			// }
			return
		}
		w.Header().Set("Access-Control-Allow-Origin", "*")
		fn(w, r)
	}
}

// Decodes JSON from request, passes decoded data to handler
func DecodeJSONMiddleware(fn func(http.ResponseWriter, *http.Request, map[string]string)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		data, err := decodeJSON(w, r)
		if err != nil {
			return
		}
		fn(w, r, data)
	}
}

// Decodes JSON from request, returns decoded map or err if couldn't decode
// Limited to decoding strings only. Could return a map[string]interface{}
// and type assert in handlers, but not for this project
func decodeJSON(w http.ResponseWriter, r *http.Request) (map[string]string, error) {
	defer r.Body.Close()
	dec := json.NewDecoder(r.Body)
	data := make(map[string]string)
	if err := dec.Decode(&data); err != nil {
		errlogger.Println(err)
		WriteJSONError(w, DECODE_ERR_S, http.StatusBadRequest)
		return nil, err
	}
	return data, nil
}

// Encode JSON data, sets content-type, return err if problem encoding data
// logs an error on its own to let caller use this function with less hassle
// when encoding responses
func WriteJSON(w http.ResponseWriter, data map[string]interface{}, code int) error {
	w.Header().Set("Content-Type", "application/json")
	enc := json.NewEncoder(w)
	w.WriteHeader(code)
	if err := enc.Encode(&data); err != nil {
		errlogger.Println(err)
		return err
	}
	return nil
}

// Writes msg as JSON to request with given code
func WriteJSONError(w http.ResponseWriter, msg string, code int) {
	WriteJSON(w, map[string]interface{}{"message": msg}, code)
}
<commit_msg>fix https redirect mulligan<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
)

func HTTPSRedirect(w http.ResponseWriter, r *http.Request) {
	http.Redirect(w, r, fmt.Sprintf("https://textremind.net%s", r.RequestURI), http.StatusMovedPermanently)
}

// Adds `Access-Control-*` headers to response
func CorsMiddleware(fn func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "OPTIONS" {
			w.Header().Set("Access-Control-Allow-Methods", "GET, POST")
			w.Header().Set("Access-Control-Max-Age", strconv.Itoa(60*60*6))
			w.Header().Set("Access-Control-Allow-Headers", "CONTENT-TYPE, ACCEPT")
			// FIXME: for some reason, the `Access-Control-Request-Headers` never seems to exist in requests
			// if v, ok := r.Header["Access-Control-Request-Headers"]; ok {
			//  w.Header().Set("Access-Control-Allow-Headers", v[0])
			// }
			return
		}
		w.Header().Set("Access-Control-Allow-Origin", "*")
		fn(w, r)
	}
}

// Decodes JSON from request, passes decoded data to handler
func DecodeJSONMiddleware(fn func(http.ResponseWriter, *http.Request, map[string]string)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		data, err := decodeJSON(w, r)
		if err != nil {
			return
		}
		fn(w, r, data)
	}
}

// Decodes JSON from request, returns decoded map or err if couldn't decode
// Limited to decoding strings only. Could return a map[string]interface{}
// and type assert in handlers, but not for this project
func decodeJSON(w http.ResponseWriter, r *http.Request) (map[string]string, error) {
	defer r.Body.Close()
	dec := json.NewDecoder(r.Body)
	data := make(map[string]string)
	if err := dec.Decode(&data); err != nil {
		errlogger.Println(err)
		WriteJSONError(w, DECODE_ERR_S, http.StatusBadRequest)
		return nil, err
	}
	return data, nil
}

// Encode JSON data, sets content-type, return err if problem encoding data
// logs an error on its own to let caller use this function with less hassle
// when encoding responses
func WriteJSON(w http.ResponseWriter, data map[string]interface{}, code int) error {
	w.Header().Set("Content-Type", "application/json")
	enc := json.NewEncoder(w)
	w.WriteHeader(code)
	if err := enc.Encode(&data); err != nil {
		errlogger.Println(err)
		return err
	}
	return nil
}

// Writes msg as JSON to request with given code
func WriteJSONError(w http.ResponseWriter, msg string, code int) {
	WriteJSON(w, map[string]interface{}{"message": msg}, code)
}
<|endoftext|>


<commit_before>package container

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
)

// Runner runs commands specified by a Command. The default implementation uses
// Docker, but MockExecutor also implements this interface and may be used
// during testing (by temporarily changing the DefaultRunner variable). The sole
// purpose of this interface is to allow mocking.
type Runner interface {
	Run(*Command) ([]byte, error)
}

var DefaultRunner Runner = dockerRunner{}

var RunRetries = 3

type dockerRunner struct{}

func (_ dockerRunner) Run(c *Command) ([]byte, error) {
	tmpDir, err := ioutil.TempDir("", "sg-docker")
	if err != nil {
		return nil, err
	}
	defer os.RemoveAll(tmpDir)

	image := "sg-temp:" + filepath.Base(tmpDir)

	cmdJSON, err := json.Marshal(c.Cmd)
	if err != nil {
		return nil, err
	}

	// Build Docker container.
	dockerfile := c.Dockerfile

	// AddFiles
	for i, f := range c.AddFiles {
		if i == 0 {
			dockerfile = append(dockerfile, '\n')
		}

		// Copy to the Docker context dir so we can ADD it.
		name := filepath.Base(f[0])
		err = cp(f[0], filepath.Join(tmpDir, name))
		if err != nil {
			return nil, err
		}
		dockerfile = append(dockerfile, []byte(fmt.Sprintf("ADD %s %s\n", "./"+name, f[1]))...)
	}

	// AddDirs
	for i, d := range c.AddDirs {
		if i == 0 {
			dockerfile = append(dockerfile, '\n')
		}

		// Move repository to Docker context dir and ADD it.
		dirName := filepath.Base(d[0])
		err := cp(d[0], filepath.Join(tmpDir, dirName))
		if err != nil {
			return nil, err
		}
		dockerfile = append(dockerfile, []byte(fmt.Sprintf("ADD %s %s\n", "./"+dirName, d[1]))...)
	}

	dockerfile = append(dockerfile, c.PreCmdDockerfile...)

	dockerfile = append(dockerfile, []byte(fmt.Sprintf("\nCMD %s", cmdJSON))...)
	err = ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0700)
	if err != nil {
		return nil, err
	}
	buildCmd := exec.Command("docker", "build", "--rm=false", "-t", image, ".")
	buildCmd.Dir = tmpDir
	buildCmd.Stdout, buildCmd.Stderr = c.Stderr, c.Stderr
	err = buildCmd.Run()
	if err != nil {
		return nil, err
	}

	for i := 0; i < RunRetries; i++ {
		remainingAttempts := RunRetries - i - 1
		runOptions := append([]string{}, c.RunOptions...)
		if c.Dir != "" {
			runOptions = append(runOptions, "--workdir="+c.Dir)
		}
		args := append([]string{"run"}, runOptions...)
		args = append(args, image)
		runCmd := exec.Command("docker", args...)
		runCmd.Stderr = os.Stderr

		// Get original output.
		data, err := runCmd.Output()
		if err != nil {
			if remainingAttempts == 0 {
				return nil, err
			} else {
				log.Printf("Command failed: docker %v: %s (retrying %d more times)", args, err, remainingAttempts)
				continue
			}
		}

		// Transform.
		if c.Transform != nil {
			data, err = c.Transform(data)
			if err != nil {
				return nil, err
			}
		}

		return data, nil
	}

	panic("unreachable")
}

type MockRunner struct {
	Cmds []*Command
}

func (r *MockRunner) Run(c *Command) ([]byte, error) {
	r.Cmds = append(r.Cmds, c)
	return nil, nil
}

var _ Runner = &MockRunner{}

func cp(src, dst string) error {
	cmd := exec.Command("cp", "-R", "--no-dereference", "--preserve=mode,ownership,timestamps", src, dst)
	out, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("cp %s %s failed: %s: %q", src, dst, err, out)
	}
	return nil
}
<commit_msg>retry<commit_after>package container

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
)

// Runner runs commands specified by a Command. The default implementation uses
// Docker, but MockExecutor also implements this interface and may be used
// during testing (by temporarily changing the DefaultRunner variable). The sole
// purpose of this interface is to allow mocking.
type Runner interface {
	Run(*Command) ([]byte, error)
}

var DefaultRunner Runner = dockerRunner{}

var (
	RunRetries   = 3
	BuildRetries = 3
)

type dockerRunner struct{}

func (_ dockerRunner) Run(c *Command) ([]byte, error) {
	tmpDir, err := ioutil.TempDir("", "sg-docker")
	if err != nil {
		return nil, err
	}
	defer os.RemoveAll(tmpDir)

	image := "sg-temp:" + filepath.Base(tmpDir)

	cmdJSON, err := json.Marshal(c.Cmd)
	if err != nil {
		return nil, err
	}

	// Build Docker container.
	dockerfile := c.Dockerfile

	// AddFiles
	for i, f := range c.AddFiles {
		if i == 0 {
			dockerfile = append(dockerfile, '\n')
		}

		// Copy to the Docker context dir so we can ADD it.
		name := filepath.Base(f[0])
		err = cp(f[0], filepath.Join(tmpDir, name))
		if err != nil {
			return nil, err
		}
		dockerfile = append(dockerfile, []byte(fmt.Sprintf("ADD %s %s\n", "./"+name, f[1]))...)
	}

	// AddDirs
	for i, d := range c.AddDirs {
		if i == 0 {
			dockerfile = append(dockerfile, '\n')
		}

		// Move repository to Docker context dir and ADD it.
		dirName := filepath.Base(d[0])
		err := cp(d[0], filepath.Join(tmpDir, dirName))
		if err != nil {
			return nil, err
		}
		dockerfile = append(dockerfile, []byte(fmt.Sprintf("ADD %s %s\n", "./"+dirName, d[1]))...)
	}

	dockerfile = append(dockerfile, c.PreCmdDockerfile...)

	dockerfile = append(dockerfile, []byte(fmt.Sprintf("\nCMD %s", cmdJSON))...)
	err = ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0700)
	if err != nil {
		return nil, err
	}
	buildCmd := exec.Command("docker", "build", "--rm=false", "-t", image, ".")
	buildCmd.Dir = tmpDir
	buildCmd.Stdout, buildCmd.Stderr = c.Stderr, c.Stderr

	for i := 0; i < BuildRetries; i++ {
		remainingAttempts := RunRetries - i - 1
		err = buildCmd.Run()
		if err != nil {
			if remainingAttempts == 0 {
				return nil, err
			} else {
				log.Printf("Command failed: %v: %s (retrying %d more times)", buildCmd.Args, err, remainingAttempts)
				continue
			}
		}
		break
	}

	for i := 0; i < RunRetries; i++ {
		remainingAttempts := RunRetries - i - 1
		runOptions := append([]string{}, c.RunOptions...)
		if c.Dir != "" {
			runOptions = append(runOptions, "--workdir="+c.Dir)
		}
		args := append([]string{"run"}, runOptions...)
		args = append(args, image)
		runCmd := exec.Command("docker", args...)
		runCmd.Stderr = os.Stderr

		// Get original output.
		data, err := runCmd.Output()
		if err != nil {
			if remainingAttempts == 0 {
				return nil, err
			} else {
				log.Printf("Command failed: %v: %s (retrying %d more times)", runCmd.Args, err, remainingAttempts)
				continue
			}
		}

		// Transform.
		if c.Transform != nil {
			data, err = c.Transform(data)
			if err != nil {
				return nil, err
			}
		}

		return data, nil
	}

	panic("unreachable")
}

type MockRunner struct {
	Cmds []*Command
}

func (r *MockRunner) Run(c *Command) ([]byte, error) {
	r.Cmds = append(r.Cmds, c)
	return nil, nil
}

var _ Runner = &MockRunner{}

func cp(src, dst string) error {
	cmd := exec.Command("cp", "-R", "--no-dereference", "--preserve=mode,ownership,timestamps", src, dst)
	out, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("cp %s %s failed: %s: %q", src, dst, err, out)
	}
	return nil
}
<|endoftext|>


<commit_before>// Package regserv implements a registration server kite. Users can register
// to a kite infrastructure by running "kite register" command.
package regserv

import (
	"errors"
	"os"
	"strings"
	"time"

	"github.com/dgrijalva/jwt-go"
	"github.com/koding/kite"
	"github.com/koding/kite/config"
	"github.com/koding/kite/kitekey"
	"github.com/koding/kite/kontrolclient"
	"github.com/koding/kite/registration"
	"github.com/koding/kite/server"
	"github.com/nu7hatch/gouuid"
)

const Version = "0.0.2"

// RegServ is a registration kite. Users can register their machines by
// running "kite register" command.
type RegServ struct {
	Server       *server.Server
	Authenticate func(r *kite.Request) error
	publicKey    string
	privateKey   string
}

func New(conf *config.Config, pubKey, privKey string) *RegServ {
	k := kite.New("regserv", Version)
	k.Config = conf
	r := &RegServ{
		Server:     server.New(k),
		publicKey:  pubKey,
		privateKey: privKey,
	}
	k.HandleFunc("register", r.handleRegister)
	return r
}

func (s *RegServ) Run() {
	kon := kontrolclient.New(s.Server.Kite)
	reg := registration.New(kon)

	connected, err := kon.DialForever()
	if err != nil {
		s.Server.Log.Fatal(err.Error())
	}
	s.Server.Start()
	go func() {
		<-connected
		reg.RegisterToProxyAndKontrol()
	}()

	<-s.Server.CloseNotify()
}

// RegisterSelf registers this host and writes a key to ~/.kite/kite.key
func (s *RegServ) RegisterSelf() error {
	hostname, err := os.Hostname()
	if err != nil {
		return err
	}
	key, err := s.register(s.Server.Config.Username, hostname)
	if err != nil {
		return err
	}
	return kitekey.Write(key)
}

func (s *RegServ) handleRegister(r *kite.Request) (interface{}, error) {
	var args struct {
		Hostname string
	}
	r.Args.One().MustUnmarshal(&args)

	if s.Authenticate != nil {
		if err := s.Authenticate(r); err != nil {
			return nil, errors.New("cannot authenticate user")
		}
	}

	return s.register(r.Username, args.Hostname)
}

func (s *RegServ) register(username, hostname string) (kiteKey string, err error) {
	tknID, err := uuid.NewV4()
	if err != nil {
		return "", errors.New("cannot generate a token")
	}

	token := jwt.New(jwt.GetSigningMethod("RS256"))

	token.Claims = map[string]interface{}{
		"iss":        s.Server.Kite.Kite().Username,       // Issuer
		"sub":        username,                            // Subject
		"aud":        hostname,                            // Hostname of registered machine
		"iat":        time.Now().UTC().Unix(),             // Issued At
		"jti":        tknID.String(),                      // JWT ID
		"kontrolURL": s.Server.Config.KontrolURL.String(), // Kontrol URL
		"kontrolKey": strings.TrimSpace(s.publicKey),      // Public key of kontrol
	}

	s.Server.Log.Info("Registered user: %s", username)

	return token.SignedString([]byte(s.privateKey))
}
<commit_msg>get username from options<commit_after>// Package regserv implements a registration server kite. Users can register
// to a kite infrastructure by running "kite register" command.
package regserv

import (
	"errors"
	"os"
	"strings"
	"time"

	"github.com/dgrijalva/jwt-go"
	"github.com/koding/kite"
	"github.com/koding/kite/config"
	"github.com/koding/kite/kitekey"
	"github.com/koding/kite/kontrolclient"
	"github.com/koding/kite/registration"
	"github.com/koding/kite/server"
	"github.com/nu7hatch/gouuid"
)

const Version = "0.0.2"

// RegServ is a registration kite. Users can register their machines by
// running "kite register" command.
type RegServ struct {
	Server       *server.Server
	Authenticate func(r *kite.Request) error
	publicKey    string
	privateKey   string
}

func New(conf *config.Config, pubKey, privKey string) *RegServ {
	k := kite.New("regserv", Version)
	k.Config = conf
	r := &RegServ{
		Server:     server.New(k),
		publicKey:  pubKey,
		privateKey: privKey,
	}
	k.HandleFunc("register", r.handleRegister)
	return r
}

func (s *RegServ) Run() {
	kon := kontrolclient.New(s.Server.Kite)
	reg := registration.New(kon)

	connected, err := kon.DialForever()
	if err != nil {
		s.Server.Log.Fatal(err.Error())
	}
	s.Server.Start()
	go func() {
		<-connected
		reg.RegisterToProxyAndKontrol()
	}()

	<-s.Server.CloseNotify()
}

// RegisterSelf registers this host and writes a key to ~/.kite/kite.key
func (s *RegServ) RegisterSelf() error {
	hostname, err := os.Hostname()
	if err != nil {
		return err
	}
	key, err := s.register(s.Server.Config.Username, hostname)
	if err != nil {
		return err
	}
	return kitekey.Write(key)
}

func (s *RegServ) handleRegister(r *kite.Request) (interface{}, error) {
	var args struct {
		Hostname string
	}
	r.Args.One().MustUnmarshal(&args)

	if s.Authenticate != nil {
		if err := s.Authenticate(r); err != nil {
			return nil, errors.New("cannot authenticate user")
		}
	}

	return s.register(r.Client.Kite.Username, args.Hostname)
}

func (s *RegServ) register(username, hostname string) (kiteKey string, err error) {
	tknID, err := uuid.NewV4()
	if err != nil {
		return "", errors.New("cannot generate a token")
	}

	token := jwt.New(jwt.GetSigningMethod("RS256"))

	token.Claims = map[string]interface{}{
		"iss":        s.Server.Kite.Kite().Username,       // Issuer
		"sub":        username,                            // Subject
		"aud":        hostname,                            // Hostname of registered machine
		"iat":        time.Now().UTC().Unix(),             // Issued At
		"jti":        tknID.String(),                      // JWT ID
		"kontrolURL": s.Server.Config.KontrolURL.String(), // Kontrol URL
		"kontrolKey": strings.TrimSpace(s.publicKey),      // Public key of kontrol
	}

	s.Server.Log.Info("Registered user: %s", username)

	return token.SignedString([]byte(s.privateKey))
}
<|endoftext|>


<commit_before>package replay

import (
	"fmt"
	"net/http"
)

// Replayer provides us with a mechanism to replay HTTP requests
type Replayer struct {
	req *http.Request

	writer http.ResponseWriter

	target *Target

	Errors chan error

	// Current play record
	Play Play

	// List of previous plays for request
	plays []Play
}

func NewReplayer(req *http.Request, w http.ResponseWriter) (*Replayer, error) {
	r := Replayer{
		req:    req,
		writer: w,
	}

	return r.init()
}

// Records request to replay it
func (r *Replayer) init() (*Replayer, error) {
	target, err := NewTarget(r.req)
	if err != nil {
		return nil, err
	}

	r.target = target

	return r, nil
}

// Reset the Replayer's state so it's ready to be replayed
func (r *Replayer) Stop() {
	r.plays = append(r.plays, r.Play)
	r.Play = Play{}
}

func (r *Replayer) Replay() (*http.Request, error) {
	return r.target.Request()
}

////
// http.ResponseWriter methods
////

func (r *Replayer) Header() http.Header {
	fmt.Printf("Getting headers")
	return r.writer.Header()
}

func (r *Replayer) Write(data []byte) (int, error) {
	fmt.Printf("Writing %d bytes\n", len(data))
	r.Play.Bytes += len(data)
	r.Play.Writes += 1
	return r.writer.Write(data)
}

func (r *Replayer) WriteHeader(status int) {
	fmt.Printf("Writing status %d\n", status)
	r.Play.Status = status
	r.writer.WriteHeader(status)
}

func (r *Replayer) GetError() error {
	if r.Play.Status >= 500 {
		return fmt.Errorf("Status code is %d", r.Play.Status)
	}

	return nil
}
<commit_msg>Don't write data for failing requests<commit_after>package replay

import (
	"fmt"
	"net/http"
)

// Replayer provides us with a mechanism to replay HTTP requests
type Replayer struct {
	req *http.Request

	writer http.ResponseWriter

	target *Target

	Errors chan error

	// Current play record
	Play Play

	// List of previous plays for request
	plays []Play
}

func NewReplayer(req *http.Request, w http.ResponseWriter) (*Replayer, error) {
	r := Replayer{
		req:    req,
		writer: w,
	}

	return r.init()
}

// Records request to replay it
func (r *Replayer) init() (*Replayer, error) {
	target, err := NewTarget(r.req)
	if err != nil {
		return nil, err
	}

	r.target = target

	return r, nil
}

// Reset the Replayer's state so it's ready to be replayed
func (r *Replayer) Stop() {
	r.plays = append(r.plays, r.Play)
	r.Play = Play{}
}

func (r *Replayer) Replay() (*http.Request, error) {
	return r.target.Request()
}

////
// http.ResponseWriter methods
////

func (r *Replayer) Header() http.Header {
	fmt.Printf("Getting headers")
	return r.writer.Header()
}

func (r *Replayer) Write(data []byte) (int, error) {
	// Don't write any data (this will be retried)
	if r.IsFailed() {
		return len(data), nil
	}

	fmt.Printf("Writing %d bytes\n", len(data))
	r.Play.Bytes += len(data)
	r.Play.Writes += 1
	return r.writer.Write(data)
}

func (r *Replayer) WriteHeader(status int) {
	r.Play.Status = status

	// This request is failing don't write out please ...
	if r.IsFailed() {
		return
	}

	r.writer.WriteHeader(status)
}

func (r *Replayer) GetError() error {
	if r.Play.Status >= 500 {
		return fmt.Errorf("Status code is %d", r.Play.Status)
	}

	return nil
}

func (r *Replayer) IsFailed() bool {
	return r.GetError() != nil
}
<|endoftext|>