<commit_before>package cmd

import (
	"context"
	"fmt"
	"os"
	"os/exec"
	"path"

	"github.com/Songmu/prompter"
	"github.com/bfirsh/whalebrew/client"
	"github.com/bfirsh/whalebrew/packages"
	dockerClient "github.com/docker/docker/client"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var customPackageName string

func init() {
	installCommand.Flags().StringVarP(&customPackageName, "name", "n", "", "Name to give installed package. Defaults to image name.")

	RootCmd.AddCommand(installCommand)
}

var installCommand = &cobra.Command{
	Use:   "install IMAGENAME",
	Short: "Install a package",
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) < 1 {
			return cmd.Help()
		}
		if len(args) > 1 {
			return fmt.Errorf("Only one image can be installed at a time")
		}

		imageName := args[0]

		cli, err := client.NewClient()
		if err != nil {
			return err
		}
		imageInspect, _, err := cli.ImageInspectWithRaw(context.Background(), imageName)
		if err != nil {
			if dockerClient.IsErrNotFound(err) {
				fmt.Printf("Unable to find image '%s' locally\n", imageName)
				if err = pullImage(imageName); err != nil {
					return err
				}
				// retry
				imageInspect, _, err = cli.ImageInspectWithRaw(context.Background(), imageName)
				if err != nil {
					return err
				}
			} else {
				return fmt.Errorf("failed to inspect docker image: %v", err)
			}
		}
		if imageInspect.ContainerConfig.Entrypoint == nil {
			return fmt.Errorf("the image '%s' is not compatible with Whalebrew: it does not have an entrypoint", imageName)
		}

		pkg, err := packages.NewPackageFromImage(imageName, imageInspect)
		if err != nil {
			return err
		}
		if customPackageName != "" {
			pkg.Name = customPackageName
		}

		if pkg.DisplayPreinstallMessage() {
			if !prompter.YN("Is this okay?", true) {
				if prompter.YN(fmt.Sprintf("Remove %s image?", imageName), true) {
					if err = removeImage(imageName); err != nil {
						return err
					}
				}
				return nil
			}
		}
		pm := packages.NewPackageManager(viper.GetString("install_path"))
		err = pm.Install(pkg)
		if err != nil {
			return err
		}
		fmt.Printf("🐳  Installed %s to %s\n", imageName, path.Join(pm.InstallPath, pkg.Name))
		return nil
	},
}

func pullImage(image string) error {
	c := exec.Command("docker", "pull", image)
	c.Stdout = os.Stdout
	c.Stderr = os.Stderr
	return c.Run()
}

func removeImage(image string) error {
	c := exec.Command("docker", "rmi", image)
	c.Stdout = os.Stdout
	c.Stderr = os.Stderr
	return c.Run()
}
<commit_msg>Don't ask to remove image after stopping install<commit_after>package cmd

import (
	"context"
	"fmt"
	"os"
	"os/exec"
	"path"

	"github.com/Songmu/prompter"
	"github.com/bfirsh/whalebrew/client"
	"github.com/bfirsh/whalebrew/packages"
	dockerClient "github.com/docker/docker/client"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var customPackageName string

func init() {
	installCommand.Flags().StringVarP(&customPackageName, "name", "n", "", "Name to give installed package. Defaults to image name.")

	RootCmd.AddCommand(installCommand)
}

var installCommand = &cobra.Command{
	Use:   "install IMAGENAME",
	Short: "Install a package",
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) < 1 {
			return cmd.Help()
		}
		if len(args) > 1 {
			return fmt.Errorf("Only one image can be installed at a time")
		}

		imageName := args[0]

		cli, err := client.NewClient()
		if err != nil {
			return err
		}
		imageInspect, _, err := cli.ImageInspectWithRaw(context.Background(), imageName)
		if err != nil {
			if dockerClient.IsErrNotFound(err) {
				fmt.Printf("Unable to find image '%s' locally\n", imageName)
				if err = pullImage(imageName); err != nil {
					return err
				}
				// retry
				imageInspect, _, err = cli.ImageInspectWithRaw(context.Background(), imageName)
				if err != nil {
					return err
				}
			} else {
				return fmt.Errorf("failed to inspect docker image: %v", err)
			}
		}
		if imageInspect.ContainerConfig.Entrypoint == nil {
			return fmt.Errorf("the image '%s' is not compatible with Whalebrew: it does not have an entrypoint", imageName)
		}

		pkg, err := packages.NewPackageFromImage(imageName, imageInspect)
		if err != nil {
			return err
		}
		if customPackageName != "" {
			pkg.Name = customPackageName
		}

		if pkg.DisplayPreinstallMessage() {
			if !prompter.YN("Is this okay?", true) {
				return nil
			}
		}
		pm := packages.NewPackageManager(viper.GetString("install_path"))
		err = pm.Install(pkg)
		if err != nil {
			return err
		}
		fmt.Printf("🐳  Installed %s to %s\n", imageName, path.Join(pm.InstallPath, pkg.Name))
		return nil
	},
}

func pullImage(image string) error {
	c := exec.Command("docker", "pull", image)
	c.Stdout = os.Stdout
	c.Stderr = os.Stderr
	return c.Run()
}
<|endoftext|>


<commit_before>package main

// jwt either encodes or decodes stdin, writing to stdout using provided key
// data.
//
//
// Example:
//		# decode and verify a token
//		echo "" |jwt -dec -k rsa.pem
//		echo ""t

import (
	"bytes"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rsa"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"strings"

	"github.com/knq/jwt"
	"github.com/knq/pemutil"
)

var (
	flagEnc = flag.Bool("enc", false, "encode token from json data provided from stdin, or via name=value pairs passed on the command line")
	flagDec = flag.Bool("dec", false, "decode and verify token read from stdin using the provided key data")
	flagKey = flag.String("k", "", "path to PEM-encoded file containing key data")
	flagAlg = flag.String("alg", "", "override signing algorithm")
)

func main() {
	var err error

	// parse parameters
	flag.Parse()

	// make sure k parameter is specified
	if *flagKey == "" {
		fmt.Fprintln(os.Stderr, "error: must supply a key")
		os.Exit(1)
	}

	// inspect remaining args
	args := flag.Args()
	if len(args) > 0 && *flagDec {
		fmt.Fprintln(os.Stderr, "error: unknown args passed for -dec")
		os.Exit(1)
	}

	// if there are command line args and enc, then build js from them
	var in []byte
	if len(args) > 0 && *flagEnc {
		in, err = buildEncArgs(args)
	} else {
		in, err = ioutil.ReadAll(os.Stdin)
	}
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	// read key data
	pem := pemutil.Store{}
	err = pemutil.PEM{*flagKey}.Load(pem)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %s\n", err)
		os.Exit(1)
	}

	// determine alg
	var alg jwt.Algorithm
	if *flagAlg != "" {
		err = (&alg).UnmarshalText([]byte(*flagAlg))
	} else if *flagDec {
		alg, err = jwt.PeekAlgorithm(in)
	} else {
		alg, err = getAlgFromKeyData(pem)
	}
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	// create signer
	signer, err := alg.New(pem)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	// encode or decode
	var out []byte
	switch {
	case *flagDec:
		out, err = doDec(signer, in)

	case *flagEnc:
		out, err = doEnc(signer, in)

	default:
		err = errors.New("please specify -enc or -dec")
	}
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	os.Stdout.Write(out)
}

// getSuitableAlgFromCurve inspects the key length in curve, and determines the
// corresponding jwt.Algorithm.
func getSuitableAlgFromCurve(curve elliptic.Curve) (jwt.Algorithm, error) {
	curveBitSize := curve.Params().BitSize

	// compute curve key len
	keyLen := curveBitSize / 8
	if curveBitSize%8 > 0 {
		keyLen++
	}

	// determine alg
	var alg jwt.Algorithm
	switch 2 * keyLen {
	case 64:
		alg = jwt.ES256
	case 96:
		alg = jwt.ES384
	case 132:
		alg = jwt.ES512

	default:
		return jwt.NONE, fmt.Errorf("invalid key length %d", keyLen)
	}

	return alg, nil
}

// getAlgFromKeyData determines the best jwt.Algorithm suitable based on the
// set of given crypto primitives in pem.
func getAlgFromKeyData(pem pemutil.Store) (jwt.Algorithm, error) {
	for _, v := range pem {
		// loop over crypto primitives in pemstore, and do type assertion. if
		// ecdsa.{PublicKey,PrivateKey} found, then use corresponding ESXXX as
		// algo. if rsa, then use DefaultRSAAlgorithm. if []byte, then use
		// DefaultHMACAlgorithm.
		switch k := v.(type) {
		case []byte:
			return jwt.HS512, nil

		case *ecdsa.PrivateKey:
			return getSuitableAlgFromCurve(k.Curve)

		case *ecdsa.PublicKey:
			return getSuitableAlgFromCurve(k.Curve)

		case *rsa.PrivateKey:
			return jwt.PS512, nil

		case *rsa.PublicKey:
			return jwt.PS512, nil
		}
	}

	return jwt.NONE, errors.New("cannot determine key type")
}

// buildEncArgs builds and encodes passed argument strings in the form of
// name=val as a json object.
func buildEncArgs(args []string) ([]byte, error) {
	m := make(map[string]interface{})

	// loop over args, splitting on '=', and attempt parsing of value
	for _, arg := range args {
		a := strings.SplitN(arg, "=", 2)
		var val interface{}

		// attempt to parse
		if len(a) == 1 { // assume bool, set as true
			val = true
		} else if u, err := strconv.ParseUint(a[1], 10, 64); err == nil {
			val = u
		} else if i, err := strconv.ParseInt(a[1], 10, 64); err == nil {
			val = i
		} else if f, err := strconv.ParseFloat(a[1], 64); err == nil {
			val = f
		} else if b, err := strconv.ParseBool(a[1]); err == nil {
			val = b
		} else if s, err := strconv.Unquote(a[1]); err == nil {
			val = s
		} else { // treat as string
			val = a[1]
		}

		m[a[0]] = val
	}

	return json.Marshal(m)
}

// UnstructuredToken is a jwt compatible token for encoding/decoding unknown
// jwt payloads.
type UnstructuredToken struct {
	Header    map[string]interface{} `json:"header" jwt:"header"`
	Payload   map[string]interface{} `json:"payload" jwt:"payload"`
	Signature []byte                 `json:"signature" jwt:"signature"`
}

// doDec decodes in as a JWT.
func doDec(signer jwt.Signer, in []byte) ([]byte, error) {
	var err error

	// decode token
	ut := UnstructuredToken{}
	err = signer.Decode(bytes.TrimSpace(in), &ut)
	if err != nil {
		return nil, err
	}

	// pretty format output
	out, err := json.MarshalIndent(&ut, "", "  ")
	if err != nil {
		return nil, err
	}

	return out, nil
}

// doEnc encodes in as the payload in a JWT.
func doEnc(signer jwt.Signer, in []byte) ([]byte, error) {
	var err error

	// make sure its valid json first
	m := make(map[string]interface{})
	err = json.Unmarshal(in, &m)
	if err != nil {
		return nil, err
	}

	// encode claims
	out, err := signer.Encode(&m)
	if err != nil {
		return nil, err
	}

	return out, nil
}
<commit_msg>Fixing issues with the jwt cli number decoding<commit_after>package main

// jwt either encodes or decodes stdin, writing to stdout using provided key
// data.
//
//
// Example:
//		# decode and verify a token
//		echo "" |jwt -dec -k rsa.pem
//		echo ""t

import (
	"bytes"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rsa"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"strings"

	"github.com/knq/jwt"
	"github.com/knq/pemutil"
)

var (
	flagEnc = flag.Bool("enc", false, "encode token from json data provided from stdin, or via name=value pairs passed on the command line")
	flagDec = flag.Bool("dec", false, "decode and verify token read from stdin using the provided key data")
	flagKey = flag.String("k", "", "path to PEM-encoded file containing key data")
	flagAlg = flag.String("alg", "", "override signing algorithm")
)

func main() {
	var err error

	// parse parameters
	flag.Parse()

	// make sure k parameter is specified
	if *flagKey == "" {
		fmt.Fprintln(os.Stderr, "error: must supply a key")
		os.Exit(1)
	}

	// inspect remaining args
	args := flag.Args()
	if len(args) > 0 && *flagDec {
		fmt.Fprintln(os.Stderr, "error: unknown args passed for -dec")
		os.Exit(1)
	}

	// if there are command line args and enc, then build js from them
	var in []byte
	if len(args) > 0 && *flagEnc {
		in, err = buildEncArgs(args)
	} else {
		in, err = ioutil.ReadAll(os.Stdin)
	}
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	// read key data
	pem := pemutil.Store{}
	err = pemutil.PEM{*flagKey}.Load(pem)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %s\n", err)
		os.Exit(1)
	}

	// determine alg
	var alg jwt.Algorithm
	if *flagAlg != "" {
		err = (&alg).UnmarshalText([]byte(*flagAlg))
	} else if *flagDec {
		alg, err = jwt.PeekAlgorithm(in)
	} else {
		alg, err = getAlgFromKeyData(pem)
	}
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	// create signer
	signer, err := alg.New(pem)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	// encode or decode
	var out []byte
	switch {
	case *flagDec:
		out, err = doDec(signer, in)

	case *flagEnc:
		out, err = doEnc(signer, in)

	default:
		err = errors.New("please specify -enc or -dec")
	}
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	os.Stdout.Write(out)
}

// getSuitableAlgFromCurve inspects the key length in curve, and determines the
// corresponding jwt.Algorithm.
func getSuitableAlgFromCurve(curve elliptic.Curve) (jwt.Algorithm, error) {
	curveBitSize := curve.Params().BitSize

	// compute curve key len
	keyLen := curveBitSize / 8
	if curveBitSize%8 > 0 {
		keyLen++
	}

	// determine alg
	var alg jwt.Algorithm
	switch 2 * keyLen {
	case 64:
		alg = jwt.ES256
	case 96:
		alg = jwt.ES384
	case 132:
		alg = jwt.ES512

	default:
		return jwt.NONE, fmt.Errorf("invalid key length %d", keyLen)
	}

	return alg, nil
}

// getAlgFromKeyData determines the best jwt.Algorithm suitable based on the
// set of given crypto primitives in pem.
func getAlgFromKeyData(pem pemutil.Store) (jwt.Algorithm, error) {
	for _, v := range pem {
		// loop over crypto primitives in pemstore, and do type assertion. if
		// ecdsa.{PublicKey,PrivateKey} found, then use corresponding ESXXX as
		// algo. if rsa, then use DefaultRSAAlgorithm. if []byte, then use
		// DefaultHMACAlgorithm.
		switch k := v.(type) {
		case []byte:
			return jwt.HS512, nil

		case *ecdsa.PrivateKey:
			return getSuitableAlgFromCurve(k.Curve)

		case *ecdsa.PublicKey:
			return getSuitableAlgFromCurve(k.Curve)

		case *rsa.PrivateKey:
			return jwt.PS512, nil

		case *rsa.PublicKey:
			return jwt.PS512, nil
		}
	}

	return jwt.NONE, errors.New("cannot determine key type")
}

// buildEncArgs builds and encodes passed argument strings in the form of
// name=val as a json object.
func buildEncArgs(args []string) ([]byte, error) {
	m := make(map[string]interface{})

	// loop over args, splitting on '=', and attempt parsing of value
	for _, arg := range args {
		a := strings.SplitN(arg, "=", 2)
		var val interface{}

		// attempt to parse
		if len(a) == 1 { // assume bool, set as true
			val = true
		} else if u, err := strconv.ParseUint(a[1], 10, 64); err == nil {
			val = u
		} else if i, err := strconv.ParseInt(a[1], 10, 64); err == nil {
			val = i
		} else if f, err := strconv.ParseFloat(a[1], 64); err == nil {
			val = f
		} else if b, err := strconv.ParseBool(a[1]); err == nil {
			val = b
		} else if s, err := strconv.Unquote(a[1]); err == nil {
			val = s
		} else { // treat as string
			val = a[1]
		}

		m[a[0]] = val
	}

	return json.Marshal(m)
}

// UnstructuredToken is a jwt compatible token for encoding/decoding unknown
// jwt payloads.
type UnstructuredToken struct {
	Header    map[string]interface{} `json:"header" jwt:"header"`
	Payload   map[string]interface{} `json:"payload" jwt:"payload"`
	Signature []byte                 `json:"signature" jwt:"signature"`
}

// doDec decodes in as a JWT.
func doDec(signer jwt.Signer, in []byte) ([]byte, error) {
	var err error

	// decode token
	ut := UnstructuredToken{}
	err = signer.Decode(bytes.TrimSpace(in), &ut)
	if err != nil {
		return nil, err
	}

	// pretty format output
	out, err := json.MarshalIndent(&ut, "", "  ")
	if err != nil {
		return nil, err
	}

	return out, nil
}

// doEnc encodes in as the payload in a JWT.
func doEnc(signer jwt.Signer, in []byte) ([]byte, error) {
	var err error

	// make sure its valid json first
	m := make(map[string]interface{})

	// do the initial decode
	d := json.NewDecoder(bytes.NewBuffer(in))
	d.UseNumber()
	err = d.Decode(&m)
	if err != nil {
		return nil, err
	}

	// encode claims
	out, err := signer.Encode(&m)
	if err != nil {
		return nil, err
	}

	return out, nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"errors"
	"fmt"
	"io"
	"os"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ecs"
	"github.com/spf13/cobra"
)

type oneshotCmd struct {
	cluster     string
	taskDefName string
	command     []string
}

func NewOneshotCommand(out, errOut io.Writer) *cobra.Command {
	f := &oneshotCmd{}
	cmd := &cobra.Command{
		Use:   "oneshot [options] COMMAND",
		Short: "",
		Run: func(cmd *cobra.Command, args []string) {
			f.command = args

			l := NewLogger(f.cluster, f.taskDefName, "", out)
			err := f.execute(cmd, args, l)
			if err != nil {
				l.log(fmt.Sprintf("error: %s\n", err.Error()))
			}
		},
	}
	cmd.Flags().StringVar(&f.cluster, "cluster", "", "ECS cluster name")
	cmd.Flags().StringVar(&f.taskDefName, "taskdef-name", "", "ECS task definition name")

	return cmd
}

func (f *oneshotCmd) execute(_ *cobra.Command, args []string, l *logger) error {
	if f.cluster == "" {
		return errors.New("--cluster is required")
	}

	if f.taskDefName == "" {
		return errors.New("--taskdef-name is required")
	}

	if len(f.command) == 0 {
		return errors.New("COMMAND is required")
	}

	region := getAWSRegion()
	if region == "" {
		return errors.New("AWS region is not found. please set a AWS_DEFAULT_REGION or AWS_REGION")
	}

	sess, err := session.NewSession()
	if err != nil {
		return err
	}

	client := ecs.New(sess, &aws.Config{
		Region: aws.String(region),
	})

	taskDef, err := f.describeTaskDefinition(client, f.taskDefName)
	if err != nil {
		return err
	}

	task, err := f.runTask(client, taskDef, f.command)
	if err != nil {
		return err
	}

	l.log("task started\n")

	status, err := f.waitTask(client, task, l)
	if err != nil {
		return err
	}

	os.Exit(status.ExitCode)

	return nil
}

type taskStatus struct {
	ExitCode      int
	StoppedReason string
}

func (f *oneshotCmd) runTask(client *ecs.ECS, taskDef *ecs.TaskDefinition, command []string) (*ecs.Task, error) {
	var commands []*string
	for _, v := range command {
		commands = append(commands, aws.String(v))
	}
	params := &ecs.RunTaskInput{
		Cluster:        aws.String(f.cluster),
		TaskDefinition: taskDef.TaskDefinitionArn,
		Overrides: &ecs.TaskOverride{
			ContainerOverrides: []*ecs.ContainerOverride{
				{
					Name:    aws.String(f.taskDefName),
					Command: commands,
				},
			},
		},
		Count:     aws.Int64(1),
		StartedBy: aws.String("shipctl oneshot"),
	}
	res, err := client.RunTask(params)
	if err != nil {
		return nil, err
	}

	if len(res.Failures) > 0 {
		msg := ""
		for _, v := range res.Failures {
			msg += fmt.Sprintf("    %s\n", *v.Reason)
		}
		return nil, errors.New("failed to runTask\n" + msg)
	}

	return res.Tasks[0], nil
}

func (f *oneshotCmd) waitTask(client *ecs.ECS, task *ecs.Task, l *logger) (*taskStatus, error) {
	start := time.Now()
	t := time.NewTicker(10 * time.Second)
	for {
		select {
		case <-t.C:
			re, err := f.describeTask(client, task)
			if err != nil {
				return nil, err
			}

			elapsed := time.Now().Sub(start)
			l.log(fmt.Sprintf("still running... [%s]\n", (elapsed/time.Second)*time.Second))

			if *re.LastStatus == "STOPPED" {
				status := &taskStatus{
					StoppedReason: *re.StoppedReason,
				}
				if re.Containers[0].ExitCode != nil {
					status.ExitCode = int(*re.Containers[0].ExitCode)
				}
				return status, nil
			}
		}
	}
}

func (f *oneshotCmd) describeTask(client *ecs.ECS, task *ecs.Task) (*ecs.Task, error) {
	params := &ecs.DescribeTasksInput{
		Tasks: []*string{
			task.TaskArn,
		},
		Cluster: task.ClusterArn,
	}
	res, err := client.DescribeTasks(params)
	if err != nil {
		return nil, err
	}

	if len(res.Failures) > 0 {
		msg := ""
		for _, v := range res.Failures {
			msg += fmt.Sprintf("    %s\n", *v.Reason)
		}
		return nil, errors.New("failed to runTask\n" + msg)
	}

	return res.Tasks[0], nil
}

func (f *oneshotCmd) describeTaskDefinition(client *ecs.ECS, name string) (*ecs.TaskDefinition, error) {
	params := &ecs.DescribeTaskDefinitionInput{
		TaskDefinition: aws.String(name),
	}

	res, err := client.DescribeTaskDefinition(params)
	if err != nil {
		return nil, err
	}

	return res.TaskDefinition, nil
}
<commit_msg>add revision option for oneshot<commit_after>package cmd

import (
	"errors"
	"fmt"
	"io"
	"os"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ecs"
	"github.com/spf13/cobra"
)

type oneshotCmd struct {
	cluster     string
	taskDefName string
	command     []string
	revision    int
}

func NewOneshotCommand(out, errOut io.Writer) *cobra.Command {
	f := &oneshotCmd{}
	cmd := &cobra.Command{
		Use:   "oneshot [options] COMMAND",
		Short: "",
		Run: func(cmd *cobra.Command, args []string) {
			f.command = args

			l := NewLogger(f.cluster, f.taskDefName, "", out)
			err := f.execute(cmd, args, l)
			if err != nil {
				l.log(fmt.Sprintf("error: %s\n", err.Error()))
			}
		},
	}
	cmd.Flags().StringVar(&f.cluster, "cluster", "", "ECS cluster name")
	cmd.Flags().StringVar(&f.taskDefName, "taskdef-name", "", "ECS task definition name")
	cmd.Flags().IntVar(&f.revision, "revision", 0, "revision of ECS task definition")

	return cmd
}

func (f *oneshotCmd) execute(_ *cobra.Command, args []string, l *logger) error {
	if f.cluster == "" {
		return errors.New("--cluster is required")
	}

	if f.taskDefName == "" {
		return errors.New("--taskdef-name is required")
	}

	if len(f.command) == 0 {
		return errors.New("COMMAND is required")
	}

	region := getAWSRegion()
	if region == "" {
		return errors.New("AWS region is not found. please set a AWS_DEFAULT_REGION or AWS_REGION")
	}

	sess, err := session.NewSession()
	if err != nil {
		return err
	}

	client := ecs.New(sess, &aws.Config{
		Region: aws.String(region),
	})

	taskDef, err := f.describeTaskDefinition(client, f.taskDefName)
	if err != nil {
		return err
	}

	arn := *taskDef.TaskDefinitionArn
	arn, err = specifyRevision(f.revision, arn)
	if err != nil {
		return err
	}

	taskDef, err = f.describeTaskDefinition(client, arn)
	if err != nil {
		return err
	}

	task, err := f.runTask(client, taskDef, f.command)
	if err != nil {
		return err
	}

	l.log("task started\n")

	status, err := f.waitTask(client, task, l)
	if err != nil {
		return err
	}

	os.Exit(status.ExitCode)

	return nil
}

type taskStatus struct {
	ExitCode      int
	StoppedReason string
}

func (f *oneshotCmd) runTask(client *ecs.ECS, taskDef *ecs.TaskDefinition, command []string) (*ecs.Task, error) {
	var commands []*string
	for _, v := range command {
		commands = append(commands, aws.String(v))
	}

	params := &ecs.RunTaskInput{
		Cluster:        aws.String(f.cluster),
		TaskDefinition: taskDef.TaskDefinitionArn,
		Overrides: &ecs.TaskOverride{
			ContainerOverrides: []*ecs.ContainerOverride{
				{
					Name:    aws.String(f.taskDefName),
					Command: commands,
				},
			},
		},
		Count:     aws.Int64(1),
		StartedBy: aws.String("shipctl oneshot"),
	}
	res, err := client.RunTask(params)
	if err != nil {
		return nil, err
	}

	if len(res.Failures) > 0 {
		msg := ""
		for _, v := range res.Failures {
			msg += fmt.Sprintf("    %s\n", *v.Reason)
		}
		return nil, errors.New("failed to runTask\n" + msg)
	}

	return res.Tasks[0], nil
}

func (f *oneshotCmd) waitTask(client *ecs.ECS, task *ecs.Task, l *logger) (*taskStatus, error) {
	start := time.Now()
	t := time.NewTicker(10 * time.Second)
	for {
		select {
		case <-t.C:
			re, err := f.describeTask(client, task)
			if err != nil {
				return nil, err
			}

			elapsed := time.Now().Sub(start)
			l.log(fmt.Sprintf("still running... [%s]\n", (elapsed/time.Second)*time.Second))

			if *re.LastStatus == "STOPPED" {
				status := &taskStatus{
					StoppedReason: *re.StoppedReason,
				}
				if re.Containers[0].ExitCode != nil {
					status.ExitCode = int(*re.Containers[0].ExitCode)
				}
				return status, nil
			}
		}
	}
}

func (f *oneshotCmd) describeTask(client *ecs.ECS, task *ecs.Task) (*ecs.Task, error) {
	params := &ecs.DescribeTasksInput{
		Tasks: []*string{
			task.TaskArn,
		},
		Cluster: task.ClusterArn,
	}
	res, err := client.DescribeTasks(params)
	if err != nil {
		return nil, err
	}

	if len(res.Failures) > 0 {
		msg := ""
		for _, v := range res.Failures {
			msg += fmt.Sprintf("    %s\n", *v.Reason)
		}
		return nil, errors.New("failed to runTask\n" + msg)
	}

	return res.Tasks[0], nil
}

func (f *oneshotCmd) describeTaskDefinition(client *ecs.ECS, name string) (*ecs.TaskDefinition, error) {
	params := &ecs.DescribeTaskDefinitionInput{
		TaskDefinition: aws.String(name),
	}

	res, err := client.DescribeTaskDefinition(params)
	if err != nil {
		return nil, err
	}

	return res.TaskDefinition, nil
}
<|endoftext|>


<commit_before>// +build from_src_run

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

// The run program is invoked via "go run" from src/run.bash or
// src/run.bat conditionally builds and runs the cmd/api tool.
//
// TODO(bradfitz): the "conditional" condition is always true.
// We should only do this if the user has the hg codereview extension
// enabled and verifies that the go.tools subrepo is checked out with
// a suitably recently version. In prep for the cmd/api rewrite.
package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
)

// goToolsVersion is the hg revision of the go.tools subrepo we need
// to build cmd/api.  This only needs to be updated whenever a go/types
// bug fix is needed by the cmd/api tool.
const goToolsVersion = "6698ca2900e2"

var goroot string

func main() {
	log.SetFlags(0)
	goroot = os.Getenv("GOROOT") // should be set by run.{bash,bat}
	if goroot == "" {
		log.Fatal("No $GOROOT set.")
	}
	isGoDeveloper := exec.Command("hg", "pq").Run() == nil
	if !isGoDeveloper && !forceAPICheck() {
		fmt.Println("Skipping cmd/api checks; hg codereview extension not available and GO_FORCE_API_CHECK not set")
		return
	}

	gopath := prepGoPath()

	cmd := exec.Command("go", "install", "--tags=api_tool", "cmd/api")
	cmd.Env = append([]string{"GOPATH=" + gopath}, os.Environ()...)
	out, err := cmd.CombinedOutput()
	if err != nil {
		log.Fatalf("Error installing cmd/api: %v\n%s", err, out)
	}

	out, err = exec.Command("go", "tool", "api",
		"-c", file("go1", "go1.1"),
		"-next", file("next"),
		"-except", file("except")).CombinedOutput()
	if err != nil {
		log.Fatalf("Error running API checker: %v\n%s", err, out)
	}
}

// file expands s to $GOROOT/api/s.txt.
// If there are more than 1, they're comma-separated.
func file(s ...string) string {
	if len(s) > 1 {
		return file(s[0]) + "," + file(s[1:]...)
	}
	return filepath.Join(goroot, "api", s[0]+".txt")
}

// GO_FORCE_API_CHECK is set by builders.
func forceAPICheck() bool {
	v, _ := strconv.ParseBool(os.Getenv("GO_FORCE_API_CHECK"))
	return v
}

// prepGoPath returns a GOPATH for the "go" tool to compile the API tool with.
// It tries to re-use a go.tools checkout from a previous run if possible,
// else it hg clones it.
func prepGoPath() string {
	const tempBase = "go.tools.TMP"

	// The GOPATH we'll return
	gopath := filepath.Join(os.TempDir(), "gopath-api", goToolsVersion)

	// cloneDir is where we run "hg clone".
	cloneDir := filepath.Join(gopath, "src", "code.google.com", "p")

	// The dir we clone into. We only atomically rename it to finalDir on
	// clone success.
	tmpDir := filepath.Join(cloneDir, tempBase)

	// finalDir is where the checkout will live once it's complete.
	// If this exists already, we're done.
	finalDir := filepath.Join(cloneDir, "go.tools")

	if fi, err := os.Stat(finalDir); err == nil && fi.IsDir() {
		return gopath
	}

	if err := os.MkdirAll(cloneDir, 0700); err != nil {
		log.Fatal(err)
	}
	cmd := exec.Command("hg",
		"clone", "--rev="+goToolsVersion,
		"https://code.google.com/p/go.tools",
		tempBase)
	cmd.Dir = cloneDir
	out, err := cmd.CombinedOutput()
	if err != nil {
		log.Fatalf("Error running hg clone on go.tools: %v\n%s", err, out)
	}
	if err := os.Rename(tmpDir, finalDir); err != nil {
		log.Fatal(err)
	}
	return gopath
}
<commit_msg>cmd/api: show output of api tool even if exit status is 0<commit_after>// +build from_src_run

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

// The run program is invoked via "go run" from src/run.bash or
// src/run.bat conditionally builds and runs the cmd/api tool.
//
// TODO(bradfitz): the "conditional" condition is always true.
// We should only do this if the user has the hg codereview extension
// enabled and verifies that the go.tools subrepo is checked out with
// a suitably recently version. In prep for the cmd/api rewrite.
package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
)

// goToolsVersion is the hg revision of the go.tools subrepo we need
// to build cmd/api.  This only needs to be updated whenever a go/types
// bug fix is needed by the cmd/api tool.
const goToolsVersion = "6698ca2900e2"

var goroot string

func main() {
	log.SetFlags(0)
	goroot = os.Getenv("GOROOT") // should be set by run.{bash,bat}
	if goroot == "" {
		log.Fatal("No $GOROOT set.")
	}
	isGoDeveloper := exec.Command("hg", "pq").Run() == nil
	if !isGoDeveloper && !forceAPICheck() {
		fmt.Println("Skipping cmd/api checks; hg codereview extension not available and GO_FORCE_API_CHECK not set")
		return
	}

	gopath := prepGoPath()

	cmd := exec.Command("go", "install", "--tags=api_tool", "cmd/api")
	cmd.Env = append([]string{"GOPATH=" + gopath}, os.Environ()...)
	out, err := cmd.CombinedOutput()
	if err != nil {
		log.Fatalf("Error installing cmd/api: %v\n%s", err, out)
	}

	out, err = exec.Command("go", "tool", "api",
		"-c", file("go1", "go1.1"),
		"-next", file("next"),
		"-except", file("except")).CombinedOutput()
	if err != nil {
		log.Fatalf("Error running API checker: %v\n%s", err, out)
	}
	fmt.Print(string(out))
}

// file expands s to $GOROOT/api/s.txt.
// If there are more than 1, they're comma-separated.
func file(s ...string) string {
	if len(s) > 1 {
		return file(s[0]) + "," + file(s[1:]...)
	}
	return filepath.Join(goroot, "api", s[0]+".txt")
}

// GO_FORCE_API_CHECK is set by builders.
func forceAPICheck() bool {
	v, _ := strconv.ParseBool(os.Getenv("GO_FORCE_API_CHECK"))
	return v
}

// prepGoPath returns a GOPATH for the "go" tool to compile the API tool with.
// It tries to re-use a go.tools checkout from a previous run if possible,
// else it hg clones it.
func prepGoPath() string {
	const tempBase = "go.tools.TMP"

	// The GOPATH we'll return
	gopath := filepath.Join(os.TempDir(), "gopath-api", goToolsVersion)

	// cloneDir is where we run "hg clone".
	cloneDir := filepath.Join(gopath, "src", "code.google.com", "p")

	// The dir we clone into. We only atomically rename it to finalDir on
	// clone success.
	tmpDir := filepath.Join(cloneDir, tempBase)

	// finalDir is where the checkout will live once it's complete.
	// If this exists already, we're done.
	finalDir := filepath.Join(cloneDir, "go.tools")

	if fi, err := os.Stat(finalDir); err == nil && fi.IsDir() {
		return gopath
	}

	if err := os.MkdirAll(cloneDir, 0700); err != nil {
		log.Fatal(err)
	}
	cmd := exec.Command("hg",
		"clone", "--rev="+goToolsVersion,
		"https://code.google.com/p/go.tools",
		tempBase)
	cmd.Dir = cloneDir
	out, err := cmd.CombinedOutput()
	if err != nil {
		log.Fatalf("Error running hg clone on go.tools: %v\n%s", err, out)
	}
	if err := os.Rename(tmpDir, finalDir); err != nil {
		log.Fatal(err)
	}
	return gopath
}
<|endoftext|>


<commit_before>// Copyright © 2016 Prometheus Team
//
// 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 (
	"bufio"
	"bytes"
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"time"

	"github.com/google/go-github/v25/github"
	"github.com/pkg/errors"
	"golang.org/x/oauth2"

	"github.com/prometheus/promu/util/retry"
)

var (
	releasecmd     = app.Command("release", "Upload all release files to the Github release")
	timeout        = releasecmd.Flag("timeout", "Upload timeout").Duration()
	allowedRetries = releasecmd.Flag("retry", "Number of retries to perform when upload fails").
			Default("2").Int()
	releaseLocation = releasecmd.Arg("location", "Location of files to release").Default(".").Strings()
	versionRe       = regexp.MustCompile(`^\d+\.\d+\.\d+(-.+)?$`)
)

func isPrerelease(version string) (bool, error) {
	matches := versionRe.FindStringSubmatch(version)
	if matches == nil {
		return false, errors.Errorf("invalid version %s", version)
	}
	return matches[1] != "", nil
}

func runRelease(location string) {
	token := os.Getenv("GITHUB_TOKEN")
	if len(token) == 0 {
		fatal(errors.New("GITHUB_TOKEN not defined"))
	}

	ctx := context.Background()
	if *timeout != time.Duration(0) {
		var cancel context.CancelFunc
		ctx, cancel = context.WithTimeout(ctx, *timeout)
		defer cancel()
	}
	client := github.NewClient(
		oauth2.NewClient(
			ctx,
			oauth2.StaticTokenSource(
				&oauth2.Token{AccessToken: token},
			),
		),
	)

	prerelease, err := isPrerelease(projInfo.Version)
	if err != nil {
		fatal(err)
	}

	// Find the GitHub release matching with the tag. We need to list all
	// releases because it is the only way to get draft releases too.
	var (
		release *github.RepositoryRelease
		opts    = &github.ListOptions{}
		tag     = fmt.Sprintf("v%s", projInfo.Version)
	)
	for {
		releases, resp, err := client.Repositories.ListReleases(ctx, projInfo.Owner, projInfo.Name, opts)
		if err != nil {
			fatal(errors.Wrap(err, "failed to list releases"))
		}
		for _, r := range releases {
			if r.GetTagName() == tag {
				release = r
				break
			}
		}
		if release != nil || resp.NextPage == 0 {
			break
		}
		opts.Page = resp.NextPage
	}
	if release == nil {
		// Create a draft release if none exists already.
		var (
			err        error
			draft      = true
			name, body = getChangelog(projInfo.Version, readChangelog())
		)
		if name != "" {
			release, _, err = client.Repositories.CreateRelease(
				ctx,
				projInfo.Owner,
				projInfo.Name,
				&github.RepositoryRelease{
					TagName:         &tag,
					TargetCommitish: &projInfo.Revision,
					Name:            &name,
					Body:            &body,
					Draft:           &draft,
					Prerelease:      &prerelease,
				})
			if err != nil {
				fatal(errors.Wrap(err, fmt.Sprintf("failed to create a draft release for %s", projInfo.Version)))
			}
		} else {
			fmt.Println("fail to parse CHANGELOG.md")
		}
	}

	if err := filepath.Walk(location, releaseFile(ctx, client, release)); err != nil {
		// Remove incomplete assets.
		// See https://developer.github.com/v3/repos/releases/#response-for-upstream-failure
		opts = &github.ListOptions{}
		for {
			assets, resp, err := client.Repositories.ListReleaseAssets(ctx, projInfo.Owner, projInfo.Name, release.GetID(), opts)
			if err != nil {
				break
			}
			for _, asset := range assets {
				if strings.EqualFold(asset.GetState(), "starter") {
					_, _ = client.Repositories.DeleteReleaseAsset(ctx, projInfo.Owner, projInfo.Name, asset.GetID())
				}
			}
			if resp.NextPage == 0 {
				break
			}
			opts.Page = resp.NextPage
		}
		fatal(errors.Wrap(err, "failed to upload all files"))
	}
}

func releaseFile(ctx context.Context, client *github.Client, release *github.RepositoryRelease) func(string, os.FileInfo, error) error {
	return func(path string, fi os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if fi.IsDir() {
			return nil
		}

		// Check if the asset has already been uploaded and remove it if it is a draft release.
		filename := filepath.Base(path)
		opts := &github.ListOptions{}
		for {
			assets, resp, err := client.Repositories.ListReleaseAssets(ctx, projInfo.Owner, projInfo.Name, release.GetID(), opts)
			if err != nil {
				return errors.Wrap(err, "failed to list release assets")
			}
			var stop bool
			for _, asset := range assets {
				if asset.GetName() == filename {
					var err error
					stop = true
					if release.GetDraft() {
						_, err = client.Repositories.DeleteReleaseAsset(ctx, projInfo.Owner, projInfo.Name, asset.GetID())
						if err != nil {
							err = errors.Wrapf(err, "failed to delete existing asset %q", filename)
						}
					} else {
						err = errors.Errorf("%q already exists", filename)
					}
					if err != nil {
						return err
					}
					break
				}
			}
			if stop || resp.NextPage == 0 {
				break
			}
			opts.Page = resp.NextPage
		}

		maxAttempts := *allowedRetries + 1
		err = retry.Do(func(attempt int) (bool, error) {
			again := attempt < maxAttempts

			f, err := os.Open(path)
			if err != nil {
				return again, err
			}

			_, _, err = client.Repositories.UploadReleaseAsset(
				ctx,
				projInfo.Owner, projInfo.Name, release.GetID(),
				&github.UploadOptions{Name: filename},
				f)
			if err != nil {
				time.Sleep(2 * time.Second)
			}

			return again, err
		})
		if err != nil {
			return errors.Wrapf(err, "failed to upload %q after %d attempts", filename, maxAttempts)
		}
		fmt.Println(" > uploaded", filename)

		return nil
	}
}

func readChangelog() io.ReadCloser {
	f, err := os.Open("CHANGELOG.md")
	if err != nil {
		fmt.Printf("fail to read CHANGELOG.md: %v\n", err)
		return ioutil.NopCloser(&bytes.Buffer{})
	}
	return f
}

// getChangelog returns the changelog's header and body for a given version.
func getChangelog(version string, rc io.ReadCloser) (string, string) {
	defer rc.Close()

	var (
		scanner = bufio.NewScanner(rc)
		s       []string
		header  string
		reading bool
	)
	for (len(s) == 0 || reading) && scanner.Scan() {
		text := scanner.Text()
		switch {
		case strings.HasPrefix(text, "## "+version+" "):
			reading = true
			header = strings.TrimSpace(strings.TrimPrefix(text, "##"))
		case strings.HasPrefix(text, "## "):
			reading = false
		case reading:
			if len(s) == 0 && strings.TrimSpace(text) == "" {
				continue
			}
			s = append(s, scanner.Text())
		}
	}

	return header, strings.Join(s, "\n")
}
<commit_msg>improve error handling when parsing CHANGELOG<commit_after>// Copyright © 2016 Prometheus Team
//
// 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 (
	"bufio"
	"bytes"
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"time"

	"github.com/google/go-github/v25/github"
	"github.com/pkg/errors"
	"golang.org/x/oauth2"

	"github.com/prometheus/promu/util/retry"
)

var (
	releasecmd     = app.Command("release", "Upload all release files to the Github release")
	timeout        = releasecmd.Flag("timeout", "Upload timeout").Duration()
	allowedRetries = releasecmd.Flag("retry", "Number of retries to perform when upload fails").
			Default("2").Int()
	releaseLocation = releasecmd.Arg("location", "Location of files to release").Default(".").Strings()
	versionRe       = regexp.MustCompile(`^\d+\.\d+\.\d+(-.+)?$`)
)

func isPrerelease(version string) (bool, error) {
	matches := versionRe.FindStringSubmatch(version)
	if matches == nil {
		return false, errors.Errorf("invalid version %s", version)
	}
	return matches[1] != "", nil
}

func runRelease(location string) {
	token := os.Getenv("GITHUB_TOKEN")
	if len(token) == 0 {
		fatal(errors.New("GITHUB_TOKEN not defined"))
	}

	ctx := context.Background()
	if *timeout != time.Duration(0) {
		var cancel context.CancelFunc
		ctx, cancel = context.WithTimeout(ctx, *timeout)
		defer cancel()
	}
	client := github.NewClient(
		oauth2.NewClient(
			ctx,
			oauth2.StaticTokenSource(
				&oauth2.Token{AccessToken: token},
			),
		),
	)

	prerelease, err := isPrerelease(projInfo.Version)
	if err != nil {
		fatal(err)
	}

	// Find the GitHub release matching with the tag. We need to list all
	// releases because it is the only way to get draft releases too.
	var (
		release *github.RepositoryRelease
		opts    = &github.ListOptions{}
		tag     = fmt.Sprintf("v%s", projInfo.Version)
	)
	for {
		releases, resp, err := client.Repositories.ListReleases(ctx, projInfo.Owner, projInfo.Name, opts)
		if err != nil {
			fatal(errors.Wrap(err, "failed to list releases"))
		}
		for _, r := range releases {
			if r.GetTagName() == tag {
				release = r
				break
			}
		}
		if release != nil || resp.NextPage == 0 {
			break
		}
		opts.Page = resp.NextPage
	}
	if release == nil {
		// Create a draft release if none exists already.
		var (
			err        error
			draft      = true
			name, body = getChangelog(projInfo.Version, readChangelog())
		)
		if name != "" {
			release, _, err = client.Repositories.CreateRelease(
				ctx,
				projInfo.Owner,
				projInfo.Name,
				&github.RepositoryRelease{
					TagName:         &tag,
					TargetCommitish: &projInfo.Revision,
					Name:            &name,
					Body:            &body,
					Draft:           &draft,
					Prerelease:      &prerelease,
				})
			if err != nil {
				fatal(errors.Wrap(err, fmt.Sprintf("failed to create a draft release for %s", projInfo.Version)))
			}
		} else {
			fatal(errors.New("unable to locate release information in changelog for selected version '" + projInfo.Version + "'."))
		}
	}

	if err := filepath.Walk(location, releaseFile(ctx, client, release)); err != nil {
		// Remove incomplete assets.
		// See https://developer.github.com/v3/repos/releases/#response-for-upstream-failure
		opts = &github.ListOptions{}
		for {
			assets, resp, err := client.Repositories.ListReleaseAssets(ctx, projInfo.Owner, projInfo.Name, release.GetID(), opts)
			if err != nil {
				break
			}
			for _, asset := range assets {
				if strings.EqualFold(asset.GetState(), "starter") {
					_, _ = client.Repositories.DeleteReleaseAsset(ctx, projInfo.Owner, projInfo.Name, asset.GetID())
				}
			}
			if resp.NextPage == 0 {
				break
			}
			opts.Page = resp.NextPage
		}
		fatal(errors.Wrap(err, "failed to upload all files"))
	}
}

func releaseFile(ctx context.Context, client *github.Client, release *github.RepositoryRelease) func(string, os.FileInfo, error) error {
	return func(path string, fi os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if fi.IsDir() {
			return nil
		}

		// Check if the asset has already been uploaded and remove it if it is a draft release.
		filename := filepath.Base(path)
		opts := &github.ListOptions{}
		for {
			assets, resp, err := client.Repositories.ListReleaseAssets(ctx, projInfo.Owner, projInfo.Name, release.GetID(), opts)
			if err != nil {
				return errors.Wrap(err, "failed to list release assets")
			}
			var stop bool
			for _, asset := range assets {
				if asset.GetName() == filename {
					var err error
					stop = true
					if release.GetDraft() {
						_, err = client.Repositories.DeleteReleaseAsset(ctx, projInfo.Owner, projInfo.Name, asset.GetID())
						if err != nil {
							err = errors.Wrapf(err, "failed to delete existing asset %q", filename)
						}
					} else {
						err = errors.Errorf("%q already exists", filename)
					}
					if err != nil {
						return err
					}
					break
				}
			}
			if stop || resp.NextPage == 0 {
				break
			}
			opts.Page = resp.NextPage
		}

		maxAttempts := *allowedRetries + 1
		err = retry.Do(func(attempt int) (bool, error) {
			again := attempt < maxAttempts

			f, err := os.Open(path)
			if err != nil {
				return again, err
			}

			_, _, err = client.Repositories.UploadReleaseAsset(
				ctx,
				projInfo.Owner, projInfo.Name, release.GetID(),
				&github.UploadOptions{Name: filename},
				f)
			if err != nil {
				time.Sleep(2 * time.Second)
			}

			return again, err
		})
		if err != nil {
			return errors.Wrapf(err, "failed to upload %q after %d attempts", filename, maxAttempts)
		}
		fmt.Println(" > uploaded", filename)

		return nil
	}
}

func readChangelog() io.ReadCloser {
	f, err := os.Open("CHANGELOG.md")
	if err != nil {
		fmt.Printf("fail to read CHANGELOG.md: %v\n", err)
		return ioutil.NopCloser(&bytes.Buffer{})
	}
	return f
}

// getChangelog returns the changelog's header and body for a given version.
// Returns empty strings if the given version is not found.
func getChangelog(version string, rc io.ReadCloser) (string, string) {
	defer rc.Close()

	var (
		scanner = bufio.NewScanner(rc)
		s       []string
		header  string
		reading bool

		releaseHeaderPattern = "## " + strings.ReplaceAll(version, ".", "\\.") + " / \\d{4}-\\d{2}-\\d{2}"
	)
	for (len(s) == 0 || reading) && scanner.Scan() {
		text := scanner.Text()
		switch {
		case strings.HasPrefix(text, "## "+version):
			if valid, _ := regexp.MatchString(releaseHeaderPattern, text); !valid {
				fatal(errors.New("Found invalid release header in changelog for version '" + version + "'.  " +
					"Expected format '## " + version + " / YYYY-MM-DD'. Found '" + text + "'"))
			}
			reading = true
			header = strings.TrimSpace(strings.TrimPrefix(text, "##"))
		case strings.HasPrefix(text, "## "):
			reading = false
		case reading:
			if len(s) == 0 && strings.TrimSpace(text) == "" {
				continue
			}
			s = append(s, scanner.Text())
		}
	}

	return header, strings.Join(s, "\n")
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 Brian Hetro <whee@smaertness.net>
// Use of this source code is governed by the ISC
// license which can be found in the LICENSE file.

package main

import (
	"io"
	"os"

	docopt "github.com/docopt/docopt-go"
	"github.com/whee/rp"
)

func main() {
	usage := `Redis Pipe.

Usage:
  rp -r <name>
  rp -w <name> [-p]

Options:
  -r, --read PIPE    Read from pipe named PIPE.
  -w, --write PIPE   Write to pipe named PIPE.
  -p, --passthrough  Pass written data to standard output.`

	arguments, _ := docopt.Parse(usage, nil, true, "Redis Pipe 0.1", false)

	if wp, ok := arguments["--write"]; ok && wp != nil {
		t, err := rp.NewWriter(wp.(string))
		if err != nil {
			panic(err)
		}
		defer t.Close()
		io.Copy(t, os.Stdin)
	} else if r, ok := arguments["--read"]; ok && r != nil {
		t, err := rp.NewReader(r.(string))
		if err != nil {
			panic(err)
		}
		defer t.Close()
		io.Copy(os.Stdout, t)
	}
}
<commit_msg>main: Cleanup.<commit_after>// Copyright (c) 2014 Brian Hetro <whee@smaertness.net>
// Use of this source code is governed by the ISC
// license which can be found in the LICENSE file.

package main

import (
	"io"
	"os"

	docopt "github.com/docopt/docopt-go"
	"github.com/whee/rp"
)

func main() {
	usage := `Redis Pipe.

Usage:
  rp -r <name>
  rp -w <name> [-p]

Options:
  -r, --read PIPE    Read from pipe named PIPE.
  -w, --write PIPE   Write to pipe named PIPE.
  -p, --passthrough  Pass written data to standard output.`

	arguments, _ := docopt.Parse(usage, nil, true, "Redis Pipe 0.1", false)
	if wp, ok := arguments["--write"]; ok && wp != nil {
		writeTo(wp.(string))
	} else if r, ok := arguments["--read"]; ok && r != nil {
		readFrom(r.(string))
	}
}

func writeTo(name string) (int64, error) {
	t, err := rp.NewWriter(name)
	if err != nil {
		return 0, err
	}
	defer t.Close()
	return io.Copy(t, os.Stdin)
}

func readFrom(name string) (int64, error) {
	t, err := rp.NewReader(name)
	if err != nil {
		return 0, err
	}
	defer t.Close()
	return io.Copy(os.Stdout, t)
}
<|endoftext|>


<commit_before>// Copyright 2010 The draw2d Authors. All rights reserved.
// created: 21/11/2010 by Laurent Le Goff

// +build ignore

package main

import (
	"bufio"
	"fmt"
	"image"
	"image/color"
	"image/png"
	"log"
	"math"
	"os"

	"github.com/llgcode/draw2d"
)

const (
	w, h = 512, 512
)

var (
	lastTime int64
	folder   = "../resource/result/"
)

func initGc(w, h int) (image.Image, draw2d.GraphicContext) {
	i := image.NewRGBA(image.Rect(0, 0, w, h))
	gc := draw2d.NewGraphicContext(i)

	gc.SetStrokeColor(image.Black)
	gc.SetFillColor(image.White)
	// fill the background
	//gc.Clear()

	return i, gc
}

func saveToPngFile(TestName string, m image.Image) {
	filePath := folder + TestName + ".png"
	f, err := os.Create(filePath)
	if err != nil {
		log.Println(err)
		os.Exit(1)
	}
	defer f.Close()
	b := bufio.NewWriter(f)
	err = png.Encode(b, m)
	if err != nil {
		log.Println(err)
		os.Exit(1)
	}
	err = b.Flush()
	if err != nil {
		log.Println(err)
		os.Exit(1)
	}
	fmt.Printf("Wrote %s OK.\n", filePath)
}

/*

*/
func TestRectangle() {
	i, gc := initGc(w, h)
	gc.Translate(10, 10)
	gc.MoveTo(0.0, 0.0)
	gc.LineTo(100.0, 00.0)
	gc.LineTo(100.0, 100.0)
	gc.LineTo(0.0, 100.0)
	gc.LineTo(0.0, 0.0)
	gc.FillStroke()
	saveToPngFile("TestRectangle", i)
}

/*

*/
func TestDrawArc() {
	i, gc := initGc(w, h)
	// draw an arc
	xc, yc := 128.0, 128.0
	radiusX, radiusY := 100.0, 100.0
	startAngle := 45.0 * (math.Pi / 180.0) /* angles are specified */
	angle := 135 * (math.Pi / 180.0)       /* in radians           */
	gc.SetLineWidth(10)
	gc.SetLineCap(draw2d.ButtCap)
	gc.SetStrokeColor(image.Black)
	gc.ArcTo(xc, yc, radiusX, radiusY, startAngle, angle)
	gc.Stroke()
	// fill a circle
	gc.SetStrokeColor(color.NRGBA{255, 0x33, 0x33, 0x80})
	gc.SetFillColor(color.NRGBA{255, 0x33, 0x33, 0x80})
	gc.SetLineWidth(6)

	gc.MoveTo(xc, yc)
	gc.LineTo(xc+math.Cos(startAngle)*radiusX, yc+math.Sin(startAngle)*radiusY)
	gc.MoveTo(xc, yc)
	gc.LineTo(xc-radiusX, yc)
	gc.Stroke()

	gc.ArcTo(xc, yc, 10.0, 10.0, 0, 2*math.Pi)
	gc.Fill()
	saveToPngFile("TestDrawArc", i)
}

/*

*/
func TestDrawArcNegative() {
	i, gc := initGc(w, h)
	// draw an arc
	xc, yc := 128.0, 128.0
	radiusX, radiusY := 100.0, 100.0
	startAngle := 45.0 * (math.Pi / 180.0) /* angles are specified */
	angle := -225 * (math.Pi / 180.0)      /* in radians           */
	gc.SetLineWidth(10)
	gc.SetLineCap(draw2d.ButtCap)
	gc.SetStrokeColor(image.Black)

	gc.ArcTo(xc, yc, radiusX, radiusY, startAngle, angle)
	gc.Stroke()
	// fill a circle
	gc.SetStrokeColor(color.NRGBA{255, 0x33, 0x33, 0x80})
	gc.SetFillColor(color.NRGBA{255, 0x33, 0x33, 0x80})
	gc.SetLineWidth(6)

	gc.MoveTo(xc, yc)
	gc.LineTo(xc+math.Cos(startAngle)*radiusX, yc+math.Sin(startAngle)*radiusY)
	gc.MoveTo(xc, yc)
	gc.LineTo(xc-radiusX, yc)
	gc.Stroke()

	gc.ArcTo(xc, yc, 10.0, 10.0, 0, 2*math.Pi)
	gc.Fill()
	saveToPngFile("TestDrawArcNegative", i)
}

func TestCurveRectangle() {
	i, gc := initGc(w, h)

	/* a custom shape that could be wrapped in a function */
	x0, y0 := 25.6, 25.6 /* parameters like cairo_rectangle */
	rect_width, rect_height := 204.8, 204.8
	radius := 102.4 /* and an approximate curvature radius */

	x1 := x0 + rect_width
	y1 := y0 + rect_height
	if rect_width/2 < radius {
		if rect_height/2 < radius {
			gc.MoveTo(x0, (y0+y1)/2)
			gc.CubicCurveTo(x0, y0, x0, y0, (x0+x1)/2, y0)
			gc.CubicCurveTo(x1, y0, x1, y0, x1, (y0+y1)/2)
			gc.CubicCurveTo(x1, y1, x1, y1, (x1+x0)/2, y1)
			gc.CubicCurveTo(x0, y1, x0, y1, x0, (y0+y1)/2)
		} else {
			gc.MoveTo(x0, y0+radius)
			gc.CubicCurveTo(x0, y0, x0, y0, (x0+x1)/2, y0)
			gc.CubicCurveTo(x1, y0, x1, y0, x1, y0+radius)
			gc.LineTo(x1, y1-radius)
			gc.CubicCurveTo(x1, y1, x1, y1, (x1+x0)/2, y1)
			gc.CubicCurveTo(x0, y1, x0, y1, x0, y1-radius)
		}
	} else {
		if rect_height/2 < radius {
			gc.MoveTo(x0, (y0+y1)/2)
			gc.CubicCurveTo(x0, y0, x0, y0, x0+radius, y0)
			gc.LineTo(x1-radius, y0)
			gc.CubicCurveTo(x1, y0, x1, y0, x1, (y0+y1)/2)
			gc.CubicCurveTo(x1, y1, x1, y1, x1-radius, y1)
			gc.LineTo(x0+radius, y1)
			gc.CubicCurveTo(x0, y1, x0, y1, x0, (y0+y1)/2)
		} else {
			gc.MoveTo(x0, y0+radius)
			gc.CubicCurveTo(x0, y0, x0, y0, x0+radius, y0)
			gc.LineTo(x1-radius, y0)
			gc.CubicCurveTo(x1, y0, x1, y0, x1, y0+radius)
			gc.LineTo(x1, y1-radius)
			gc.CubicCurveTo(x1, y1, x1, y1, x1-radius, y1)
			gc.LineTo(x0+radius, y1)
			gc.CubicCurveTo(x0, y1, x0, y1, x0, y1-radius)
		}
	}
	gc.Close()

	gc.SetFillColor(color.NRGBA{0x80, 0x80, 0xFF, 0xFF})
	gc.SetStrokeColor(color.NRGBA{0x80, 0, 0, 0x80})
	gc.SetLineWidth(10.0)
	gc.FillStroke()

	saveToPngFile("TestCurveRectangle", i)
}

/*

*/
func TestDrawCubicCurve() {
	i, gc := initGc(w, h)
	// draw a cubic curve
	x, y := 25.6, 128.0
	x1, y1 := 102.4, 230.4
	x2, y2 := 153.6, 25.6
	x3, y3 := 230.4, 128.0

	gc.SetFillColor(color.NRGBA{0xAA, 0xAA, 0xAA, 0xFF})
	gc.SetLineWidth(10)
	gc.MoveTo(x, y)
	gc.CubicCurveTo(x1, y1, x2, y2, x3, y3)
	gc.Stroke()

	gc.SetStrokeColor(color.NRGBA{0xFF, 0x33, 0x33, 0x88})

	gc.SetLineWidth(6)
	// draw segment of curve
	gc.MoveTo(x, y)
	gc.LineTo(x1, y1)
	gc.LineTo(x2, y2)
	gc.LineTo(x3, y3)
	gc.Stroke()
	saveToPngFile("TestDrawCubicCurve", i)
}

/*

*/
func TestDash() {
	i, gc := initGc(w, h)
	gc.SetLineDash([]float64{50, 10, 10, 10}, -50.0)
	gc.SetLineCap(draw2d.ButtCap)
	gc.SetLineJoin(draw2d.BevelJoin)
	gc.SetLineWidth(10)

	gc.MoveTo(128.0, 25.6)
	gc.LineTo(128.0, 25.6)
	gc.LineTo(230.4, 230.4)
	gc.RLineTo(-102.4, 0.0)
	gc.CubicCurveTo(51.2, 230.4, 51.2, 128.0, 128.0, 128.0)
	gc.Stroke()
	gc.SetLineDash(nil, 0.0)
	saveToPngFile("TestDash", i)
}

/*

*/
func TestFillStroke() {
	i, gc := initGc(w, h)
	gc.MoveTo(128.0, 25.6)
	gc.LineTo(230.4, 230.4)
	gc.RLineTo(-102.4, 0.0)
	gc.CubicCurveTo(51.2, 230.4, 51.2, 128.0, 128.0, 128.0)
	gc.Close()

	gc.MoveTo(64.0, 25.6)
	gc.RLineTo(51.2, 51.2)
	gc.RLineTo(-51.2, 51.2)
	gc.RLineTo(-51.2, -51.2)
	gc.Close()

	gc.SetLineWidth(10.0)
	gc.SetFillColor(color.NRGBA{0, 0, 0xFF, 0xFF})
	gc.SetStrokeColor(image.Black)
	gc.FillStroke()
	saveToPngFile("TestFillStroke", i)
}

/*

*/
func TestFillStyle() {
	i, gc := initGc(w, h)
	gc.SetLineWidth(6)

	draw2d.Rect(gc, 12, 12, 244, 70)

	wheel1 := new(draw2d.PathStorage)
	wheel1.ArcTo(64, 64, 40, 40, 0, 2*math.Pi)
	wheel2 := new(draw2d.PathStorage)
	wheel2.ArcTo(192, 64, 40, 40, 0, 2*math.Pi)

	gc.SetFillRule(draw2d.FillRuleEvenOdd)
	gc.SetFillColor(color.NRGBA{0, 0xB2, 0, 0xFF})

	gc.SetStrokeColor(image.Black)
	gc.FillStroke(wheel1, wheel2)

	draw2d.Rect(gc, 12, 140, 244, 198)
	wheel1 = new(draw2d.PathStorage)
	wheel1.ArcTo(64, 192, 40, 40, 0, 2*math.Pi)
	wheel2 = new(draw2d.PathStorage)
	wheel2.ArcTo(192, 192, 40, 40, 0, -2*math.Pi)

	gc.SetFillRule(draw2d.FillRuleWinding)
	gc.SetFillColor(color.NRGBA{0, 0, 0xE5, 0xFF})
	gc.FillStroke(wheel1, wheel2)
	saveToPngFile("TestFillStyle", i)
}

func TestMultiSegmentCaps() {
	i, gc := initGc(w, h)
	gc.MoveTo(50.0, 75.0)
	gc.LineTo(200.0, 75.0)

	gc.MoveTo(50.0, 125.0)
	gc.LineTo(200.0, 125.0)

	gc.MoveTo(50.0, 175.0)
	gc.LineTo(200.0, 175.0)

	gc.SetLineWidth(30.0)
	gc.SetLineCap(draw2d.RoundCap)
	gc.Stroke()
	saveToPngFile("TestMultiSegmentCaps", i)
}

func TestRoundRectangle() {
	i, gc := initGc(w, h)
	/* a custom shape that could be wrapped in a function */
	x, y := 25.6, 25.6
	width, height := 204.8, 204.8
	aspect := 1.0                  /* aspect ratio */
	corner_radius := height / 10.0 /* and corner curvature radius */

	radius := corner_radius / aspect
	degrees := math.Pi / 180.0

	gc.ArcTo(x+width-radius, y+radius, radius, radius, -90*degrees, 90*degrees)
	gc.ArcTo(x+width-radius, y+height-radius, radius, radius, 0*degrees, 90*degrees)
	gc.ArcTo(x+radius, y+height-radius, radius, radius, 90*degrees, 90*degrees)
	gc.ArcTo(x+radius, y+radius, radius, radius, 180*degrees, 90*degrees)
	gc.Close()

	gc.SetFillColor(color.NRGBA{0x80, 0x80, 0xFF, 0xFF})
	gc.SetStrokeColor(color.NRGBA{0x80, 0, 0, 0x80})
	gc.SetLineWidth(10.0)
	gc.FillStroke()

	saveToPngFile("TestRoundRectangle", i)
}

func TestLineCap() {
	i, gc := initGc(w, h)
	gc.SetLineWidth(30.0)
	gc.SetLineCap(draw2d.ButtCap)
	gc.MoveTo(64.0, 50.0)
	gc.LineTo(64.0, 200.0)
	gc.Stroke()
	gc.SetLineCap(draw2d.RoundCap)
	gc.MoveTo(128.0, 50.0)
	gc.LineTo(128.0, 200.0)
	gc.Stroke()
	gc.SetLineCap(draw2d.SquareCap)
	gc.MoveTo(192.0, 50.0)
	gc.LineTo(192.0, 200.0)
	gc.Stroke()

	/* draw helping lines */
	gc.SetStrokeColor(color.NRGBA{0xFF, 0x33, 0x33, 0xFF})
	gc.SetLineWidth(2.56)
	gc.MoveTo(64.0, 50.0)
	gc.LineTo(64.0, 200.0)
	gc.MoveTo(128.0, 50.0)
	gc.LineTo(128.0, 200.0)
	gc.MoveTo(192.0, 50.0)
	gc.LineTo(192.0, 200.0)
	gc.Stroke()
	saveToPngFile("TestLineCap", i)
}
func TestLineJoin() {
	i, gc := initGc(w, h)
	gc.SetLineWidth(40.96)
	gc.MoveTo(76.8, 84.48)
	gc.RLineTo(51.2, -51.2)
	gc.RLineTo(51.2, 51.2)
	gc.SetLineJoin(draw2d.MiterJoin) /* default */
	gc.Stroke()

	gc.MoveTo(76.8, 161.28)
	gc.RLineTo(51.2, -51.2)
	gc.RLineTo(51.2, 51.2)
	gc.SetLineJoin(draw2d.BevelJoin)
	gc.Stroke()

	gc.MoveTo(76.8, 238.08)
	gc.RLineTo(51.2, -51.2)
	gc.RLineTo(51.2, 51.2)
	gc.SetLineJoin(draw2d.RoundJoin)
	gc.Stroke()
	saveToPngFile("TestLineJoin", i)
}

func TestBubble() {
	i, gc := initGc(w, h)
	gc.BeginPath()
	gc.MoveTo(75, 25)
	gc.QuadCurveTo(25, 25, 25, 62.5)
	gc.QuadCurveTo(25, 100, 50, 100)
	gc.QuadCurveTo(50, 120, 30, 125)
	gc.QuadCurveTo(60, 120, 65, 100)
	gc.QuadCurveTo(125, 100, 125, 62.5)
	gc.QuadCurveTo(125, 25, 75, 25)
	gc.Stroke()
	saveToPngFile("TestBubble", i)
}

func TestStar() {
	i, gc := initGc(w, h)
	for i := 0.0; i < 360; i = i + 10 { // Go from 0 to 360 degrees in 10 degree steps
		gc.Save()
		gc.SetLineWidth(5) // Keep rotations temporary
		gc.Translate(144, 144)
		gc.Rotate(i * (math.Pi / 180.0)) // Rotate by degrees on stack from 'for'
		gc.MoveTo(0, 0)
		gc.LineTo(72, 0)
		gc.Stroke()
		gc.Restore()
	}
	saveToPngFile("TestStar", i)
}

func TestTransform() {
	i, gc := initGc(800, 600)

	gc.Save()
	gc.Translate(40, 40) // Set origin to (40, 40)
	gc.BeginPath()
	gc.MoveTo(0, 0)
	gc.RLineTo(72, 0)
	gc.RLineTo(0, 72)
	gc.RLineTo(-72, 0)
	gc.Close()
	gc.Stroke()
	gc.Restore()

	gc.Save()
	gc.Translate(100, 150)            // Translate origin to (100, 150)
	gc.Rotate(30 * (math.Pi / 180.0)) // Rotate counter-clockwise by 30 degrees
	gc.BeginPath()
	gc.MoveTo(0, 0)
	gc.RLineTo(72, 0)
	gc.RLineTo(0, 72)
	gc.RLineTo(-72, 0)
	gc.Close() // Draw box...
	gc.Stroke()
	gc.Restore()

	gc.Save()
	gc.Translate(40, 300) // Translate to  (40, 300)
	gc.Scale(0.5, 1)      // Reduce x coord by 1/2, y coord left alone
	gc.BeginPath()
	gc.MoveTo(0, 0)
	gc.RLineTo(72, 0)
	gc.RLineTo(0, 72)
	gc.RLineTo(-72, 0)
	gc.Close() // Draw box...
	gc.Stroke()
	gc.Restore()

	gc.Save()
	gc.Translate(300, 300)            // Set origin to (300, 300)
	gc.Rotate(45 * (math.Pi / 180.0)) // Rotate coordinates by 45 degrees
	gc.Scale(0.5, 1)                  // Scale coordinates
	gc.BeginPath()
	gc.MoveTo(0, 0)
	gc.RLineTo(72, 0)
	gc.RLineTo(0, 72)
	gc.RLineTo(-72, 0)
	gc.Close() // Draw box
	gc.Stroke()
	gc.Restore()

	saveToPngFile("TestTransform", i)
}

func TestPathTransform() {
	i, gc := initGc(800, 600)
	gc.SetLineWidth(20)
	gc.Scale(1, 4)
	gc.ArcTo(200, 80, 50, 50, 0, math.Pi*2)
	gc.Close()
	gc.Stroke()
	saveToPngFile("TestPathTransform", i)
}

func TestFillString() {
	draw2d.SetFontFolder("../resource/font/")
	i, gc := initGc(100, 100)
	draw2d.RoundRect(gc, 5, 5, 95, 95, 10, 10)
	gc.FillStroke()
	gc.SetFillColor(image.Black)
	gc.SetFontSize(18)
	gc.Translate(6, 52)
	gc.SetFontData(draw2d.FontData{"luxi", draw2d.FontFamilyMono, draw2d.FontStyleBold | draw2d.FontStyleItalic})
	width := gc.FillString("cou")
	gc.Translate(width+1, 0)
	left, top, right, bottom := gc.GetStringBounds("cou")
	gc.SetStrokeColor(color.NRGBA{255, 0x33, 0x33, 0x80})
	draw2d.Rect(gc, left, top, right, bottom)
	gc.SetLineWidth(3.0)
	gc.Stroke()
	gc.SetStrokeColor(image.Black)
	gc.SetLineWidth(1.0)
	gc.StrokeString("cou")
	saveToPngFile("TestFillString", i)
}

func TestBigPicture() {
	i, gc := initGc(w, h)
	gc.SetLineWidth(10)

	draw2d.Rect(gc, 0, 0, w, h)
	gc.Fill()
	saveToPngFile("TestBigPicture", i)
}

func main() {
	TestPath()
	TestDrawArc()
	TestDrawArcNegative()
	TestCurveRectangle()
	TestDrawCubicCurve()
	TestDash()
	TestFillStroke()
	TestFillStyle()
	TestMultiSegmentCaps()
	TestRoundRectangle()
	TestLineCap()
	TestLineJoin()
	TestBubble()
	TestStar()
	TestTransform()
	TestPathTransform()
	TestFillString()
	TestBigPicture()
}
<commit_msg>remove sample cmd<commit_after><|endoftext|>


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

package main

import (
	"bufio"
	"encoding/json"
	"os"
	"text/template"
)

var cmdList = &Command{
	UsageLine: "list [-e] [-f format] [-json] [importpath...]",
	Short:     "list packages",
	Long: `
List lists the packages named by the import paths, one per line.

The default output shows the package import path:

    code.google.com/p/google-api-go-client/books/v1
    code.google.com/p/goauth2/oauth
    code.google.com/p/sqlite

The -f flag specifies an alternate format for the list,
using the syntax of package template.  The default output
is equivalent to -f '{{.ImportPath}}'.  The struct
being passed to the template is:

    type Package struct {
        Name       string // package name
        Doc        string // package documentation string
        ImportPath string // import path of package in dir
        Dir        string // directory containing package sources
        Version    string // version of installed package (TODO)
        Stale      bool   // would 'go install' do anything for this package?

        // Source files
        GoFiles      []string // .go source files (excluding CgoFiles, TestGoFiles, and XTestGoFiles)
        TestGoFiles  []string // _test.go source files internal to the package they are testing
        XTestGoFiles []string // _test.go source files external to the package they are testing
        CFiles       []string // .c source files
        HFiles       []string // .h source files
        SFiles       []string // .s source files
        CgoFiles     []string // .go sources files that import "C"

        // Dependency information
        Imports []string // import paths used by this package
        Deps    []string // all (recursively) imported dependencies

        // Error information
        Incomplete bool            // this package or a dependency has an error
        Error *PackageError        // error loading package
        DepsErrors []*PackageError // errors loading dependencies
    }

The -json flag causes the package data to be printed in JSON format
instead of using the template format.

The -e flag changes the handling of erroneous packages, those that
cannot be found or are malformed.  By default, the list command
prints an error to standard error for each erroneous package and
omits the packages from consideration during the usual printing.
With the -e flag, the list command never prints errors to standard
error and instead processes the erroneous packages with the usual
printing.  Erroneous packages will have a non-empty ImportPath and
a non-nil Error field; other information may or may not be missing
(zeroed).

For more about import paths, see 'go help importpath'.
	`,
}

func init() {
	cmdList.Run = runList // break init cycle
}

var listE = cmdList.Flag.Bool("e", false, "")
var listFmt = cmdList.Flag.String("f", "{{.ImportPath}}", "")
var listJson = cmdList.Flag.Bool("json", false, "")
var nl = []byte{'\n'}

func runList(cmd *Command, args []string) {
	out := bufio.NewWriter(os.Stdout)
	defer out.Flush()

	var do func(*Package)
	if *listJson {
		do = func(p *Package) {
			b, err := json.MarshalIndent(p, "", "\t")
			if err != nil {
				out.Flush()
				fatalf("%s", err)
			}
			out.Write(b)
			out.Write(nl)
		}
	} else {
		tmpl, err := template.New("main").Parse(*listFmt + "\n")
		if err != nil {
			fatalf("%s", err)
		}
		do = func(p *Package) {
			if err := tmpl.Execute(out, p); err != nil {
				out.Flush()
				fatalf("%s", err)
			}
		}
	}

	load := packages
	if *listE {
		load = packagesAndErrors
	}

	for _, pkg := range load(args) {
		do(pkg)
	}
}
<commit_msg>cmd/go: in list, don't print blank lines for no output Otherwise         go list -f "{{if .Stale}}{{.ImportPath}}{{end}}" all and similar commands can print pages of empty lines.<commit_after>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bufio"
	"encoding/json"
	"io"
	"os"
	"text/template"
)

var cmdList = &Command{
	UsageLine: "list [-e] [-f format] [-json] [importpath...]",
	Short:     "list packages",
	Long: `
List lists the packages named by the import paths, one per line.

The default output shows the package import path:

    code.google.com/p/google-api-go-client/books/v1
    code.google.com/p/goauth2/oauth
    code.google.com/p/sqlite

The -f flag specifies an alternate format for the list,
using the syntax of package template.  The default output
is equivalent to -f '{{.ImportPath}}'.  The struct
being passed to the template is:

    type Package struct {
        Name       string // package name
        Doc        string // package documentation string
        ImportPath string // import path of package in dir
        Dir        string // directory containing package sources
        Version    string // version of installed package (TODO)
        Stale      bool   // would 'go install' do anything for this package?

        // Source files
        GoFiles      []string // .go source files (excluding CgoFiles, TestGoFiles, and XTestGoFiles)
        TestGoFiles  []string // _test.go source files internal to the package they are testing
        XTestGoFiles []string // _test.go source files external to the package they are testing
        CFiles       []string // .c source files
        HFiles       []string // .h source files
        SFiles       []string // .s source files
        CgoFiles     []string // .go sources files that import "C"

        // Dependency information
        Imports []string // import paths used by this package
        Deps    []string // all (recursively) imported dependencies

        // Error information
        Incomplete bool            // this package or a dependency has an error
        Error *PackageError        // error loading package
        DepsErrors []*PackageError // errors loading dependencies
    }

The -json flag causes the package data to be printed in JSON format
instead of using the template format.

The -e flag changes the handling of erroneous packages, those that
cannot be found or are malformed.  By default, the list command
prints an error to standard error for each erroneous package and
omits the packages from consideration during the usual printing.
With the -e flag, the list command never prints errors to standard
error and instead processes the erroneous packages with the usual
printing.  Erroneous packages will have a non-empty ImportPath and
a non-nil Error field; other information may or may not be missing
(zeroed).

For more about import paths, see 'go help importpath'.
	`,
}

func init() {
	cmdList.Run = runList // break init cycle
}

var listE = cmdList.Flag.Bool("e", false, "")
var listFmt = cmdList.Flag.String("f", "{{.ImportPath}}", "")
var listJson = cmdList.Flag.Bool("json", false, "")
var nl = []byte{'\n'}

func runList(cmd *Command, args []string) {
	out := newCountingWriter(os.Stdout)
	defer out.w.Flush()

	var do func(*Package)
	if *listJson {
		do = func(p *Package) {
			b, err := json.MarshalIndent(p, "", "\t")
			if err != nil {
				out.Flush()
				fatalf("%s", err)
			}
			out.Write(b)
			out.Write(nl)
		}
	} else {
		tmpl, err := template.New("main").Parse(*listFmt)
		if err != nil {
			fatalf("%s", err)
		}
		do = func(p *Package) {
			out.Reset()
			if err := tmpl.Execute(out, p); err != nil {
				out.Flush()
				fatalf("%s", err)
			}
			if out.Count() > 0 {
				out.w.WriteRune('\n')
			}
		}
	}

	load := packages
	if *listE {
		load = packagesAndErrors
	}

	for _, pkg := range load(args) {
		do(pkg)
	}
}

// CountingWriter counts its data, so we can avoid appending a newline
// if there was no actual output.
type CountingWriter struct {
	w     *bufio.Writer
	count int64
}

func newCountingWriter(w io.Writer) *CountingWriter {
	return &CountingWriter{
		w: bufio.NewWriter(w),
	}
}

func (cw *CountingWriter) Write(p []byte) (n int, err error) {
	cw.count += int64(len(p))
	return cw.w.Write(p)
}

func (cw *CountingWriter) Flush() {
	cw.w.Flush()
}

func (cw *CountingWriter) Reset() {
	cw.count = 0
}

func (cw *CountingWriter) Count() int64 {
	return cw.count
}
<|endoftext|>


<commit_before>// Copyright © 2017 Mikael Berthe <mikael@lilotux.net>
//
// Licensed under the MIT license.
// Please see the LICENSE file is this directory.

package cmd

import (
	"os"

	"github.com/spf13/cobra"

	"github.com/McKael/madon"
	"github.com/McKael/madonctl/printer"
)

// madonctlVersion contains the version of the madonctl tool
// and the version of the madon library it is linked with.
type madonctlVersion struct {
	AppName      string `json:"application_name"`
	Version      string `json:"version"`
	MadonVersion string `json:"madon_version"`
}

// VERSION of the madonctl application
var VERSION = "0.6.1-dev"

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Display " + AppName + " version",
	RunE: func(cmd *cobra.Command, args []string) error {
		const versionTemplate = `This is {{.application_name}} ` +
			`version {{.version}} ` +
			`(using madon library version {{.madon_version}}).{{"\n"}}`
		var v = madonctlVersion{
			AppName:      AppName,
			Version:      VERSION,
			MadonVersion: madon.MadonVersion,
		}
		var p printer.ResourcePrinter
		var err error
		if getOutputFormat() == "plain" {
			pOptions := printer.Options{"template": versionTemplate}
			p, err = printer.NewPrinterTemplate(pOptions)
		} else {
			p, err = getPrinter()
		}
		if err != nil {
			errPrint("Error: %s", err.Error())
			os.Exit(1)
		}
		return p.PrintObj(v, nil, "")
	},
}

func init() {
	RootCmd.AddCommand(versionCmd)
}
<commit_msg>Version 0.6.1<commit_after>// Copyright © 2017 Mikael Berthe <mikael@lilotux.net>
//
// Licensed under the MIT license.
// Please see the LICENSE file is this directory.

package cmd

import (
	"os"

	"github.com/spf13/cobra"

	"github.com/McKael/madon"
	"github.com/McKael/madonctl/printer"
)

// madonctlVersion contains the version of the madonctl tool
// and the version of the madon library it is linked with.
type madonctlVersion struct {
	AppName      string `json:"application_name"`
	Version      string `json:"version"`
	MadonVersion string `json:"madon_version"`
}

// VERSION of the madonctl application
var VERSION = "0.6.1"

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Display " + AppName + " version",
	RunE: func(cmd *cobra.Command, args []string) error {
		const versionTemplate = `This is {{.application_name}} ` +
			`version {{.version}} ` +
			`(using madon library version {{.madon_version}}).{{"\n"}}`
		var v = madonctlVersion{
			AppName:      AppName,
			Version:      VERSION,
			MadonVersion: madon.MadonVersion,
		}
		var p printer.ResourcePrinter
		var err error
		if getOutputFormat() == "plain" {
			pOptions := printer.Options{"template": versionTemplate}
			p, err = printer.NewPrinterTemplate(pOptions)
		} else {
			p, err = getPrinter()
		}
		if err != nil {
			errPrint("Error: %s", err.Error())
			os.Exit(1)
		}
		return p.PrintObj(v, nil, "")
	},
}

func init() {
	RootCmd.AddCommand(versionCmd)
}
<|endoftext|>


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

//go:generate ./mkalldocs.sh

package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	"cmd/go/internal/base"
	"cmd/go/internal/bug"
	"cmd/go/internal/cfg"
	"cmd/go/internal/clean"
	"cmd/go/internal/doc"
	"cmd/go/internal/envcmd"
	"cmd/go/internal/fix"
	"cmd/go/internal/fmtcmd"
	"cmd/go/internal/generate"
	"cmd/go/internal/get"
	"cmd/go/internal/help"
	"cmd/go/internal/list"
	"cmd/go/internal/modcmd"
	"cmd/go/internal/modfetch"
	"cmd/go/internal/modget"
	"cmd/go/internal/modload"
	"cmd/go/internal/run"
	"cmd/go/internal/test"
	"cmd/go/internal/tool"
	"cmd/go/internal/version"
	"cmd/go/internal/vet"
	"cmd/go/internal/work"
)

func init() {
	base.Go.Commands = []*base.Command{
		bug.CmdBug,
		work.CmdBuild,
		clean.CmdClean,
		doc.CmdDoc,
		envcmd.CmdEnv,
		fix.CmdFix,
		fmtcmd.CmdFmt,
		generate.CmdGenerate,
		get.CmdGet,
		work.CmdInstall,
		list.CmdList,
		modcmd.CmdMod,
		run.CmdRun,
		test.CmdTest,
		tool.CmdTool,
		version.CmdVersion,
		vet.CmdVet,

		help.HelpBuildmode,
		help.HelpC,
		help.HelpCache,
		help.HelpEnvironment,
		help.HelpFileType,
		help.HelpGopath,
		get.HelpGopathGet,
		modfetch.HelpGoproxy,
		help.HelpImportPath,
		modload.HelpModules,
		modget.HelpModuleGet,
		help.HelpPackages,
		test.HelpTestflag,
		test.HelpTestfunc,
	}
}

func main() {
	_ = go11tag
	flag.Usage = base.Usage
	flag.Parse()
	log.SetFlags(0)

	args := flag.Args()
	if len(args) < 1 {
		base.Usage()
	}

	if modload.MustUseModules {
		// If running with modules force-enabled, change get now to change help message.
		*get.CmdGet = *modget.CmdGet
	}

	cfg.CmdName = args[0] // for error messages
	if args[0] == "help" {
		help.Help(args[1:])
		return
	}

	// Diagnose common mistake: GOPATH==GOROOT.
	// This setting is equivalent to not setting GOPATH at all,
	// which is not what most people want when they do it.
	if gopath := cfg.BuildContext.GOPATH; filepath.Clean(gopath) == filepath.Clean(runtime.GOROOT()) {
		fmt.Fprintf(os.Stderr, "warning: GOPATH set to GOROOT (%s) has no effect\n", gopath)
	} else {
		for _, p := range filepath.SplitList(gopath) {
			// Some GOPATHs have empty directory elements - ignore them.
			// See issue 21928 for details.
			if p == "" {
				continue
			}
			// Note: using HasPrefix instead of Contains because a ~ can appear
			// in the middle of directory elements, such as /tmp/git-1.8.2~rc3
			// or C:\PROGRA~1. Only ~ as a path prefix has meaning to the shell.
			if strings.HasPrefix(p, "~") {
				fmt.Fprintf(os.Stderr, "go: GOPATH entry cannot start with shell metacharacter '~': %q\n", p)
				os.Exit(2)
			}
			if !filepath.IsAbs(p) {
				fmt.Fprintf(os.Stderr, "go: GOPATH entry is relative; must be absolute path: %q.\nFor more details see: 'go help gopath'\n", p)
				os.Exit(2)
			}
		}
	}

	if fi, err := os.Stat(cfg.GOROOT); err != nil || !fi.IsDir() {
		fmt.Fprintf(os.Stderr, "go: cannot find GOROOT directory: %v\n", cfg.GOROOT)
		os.Exit(2)
	}

	// TODO(rsc): Remove all these helper prints in Go 1.12.
	switch args[0] {
	case "mod":
		if len(args) >= 2 {
			flag := args[1]
			if strings.HasPrefix(flag, "--") {
				flag = flag[1:]
			}
			if i := strings.Index(flag, "="); i >= 0 {
				flag = flag[:i]
			}
			switch flag {
			case "-sync":
				fmt.Fprintf(os.Stderr, "go: go mod -sync is now go mod tidy\n")
				os.Exit(2)
			case "-init", "-fix", "-graph", "-vendor", "-verify":
				fmt.Fprintf(os.Stderr, "go: go mod %s is now go mod %s\n", flag, flag[1:])
				os.Exit(2)
			case "-fmt", "-json", "-module", "-require", "-droprequire", "-replace", "-dropreplace", "-exclude", "-dropexclude":
				fmt.Fprintf(os.Stderr, "go: go mod %s is now go mod edit %s\n", flag, flag)
				os.Exit(2)
			}
		}
	case "vendor":
		fmt.Fprintf(os.Stderr, "go: vgo vendor is now go mod vendor\n")
		os.Exit(2)
	case "verify":
		fmt.Fprintf(os.Stderr, "go: vgo verify is now go mod verify\n")
		os.Exit(2)
	}

	if args[0] == "get" {
		// Replace get with module-aware get if appropriate.
		// Note that if MustUseModules is true, this happened already above,
		// but no harm in doing it again.
		if modload.Init(); modload.Enabled() {
			*get.CmdGet = *modget.CmdGet
		}
	}

	// Set environment (GOOS, GOARCH, etc) explicitly.
	// In theory all the commands we invoke should have
	// the same default computation of these as we do,
	// but in practice there might be skew
	// This makes sure we all agree.
	cfg.OrigEnv = os.Environ()
	cfg.CmdEnv = envcmd.MkEnv()
	for _, env := range cfg.CmdEnv {
		if os.Getenv(env.Name) != env.Value {
			os.Setenv(env.Name, env.Value)
		}
	}

BigCmdLoop:
	for bigCmd := base.Go; ; {
		for _, cmd := range bigCmd.Commands {
			if cmd.Name() != args[0] {
				continue
			}
			if len(cmd.Commands) > 0 {
				bigCmd = cmd
				args = args[1:]
				if len(args) == 0 {
					help.PrintUsage(os.Stderr, bigCmd)
				}
				if args[0] == "help" {
					// Accept 'go mod help' and 'go mod help foo' for 'go help mod' and 'go help mod foo'.
					help.Help(append(strings.Split(cfg.CmdName, " "), args[1:]...))
					return
				}
				cfg.CmdName += " " + args[0]
				continue BigCmdLoop
			}
			if !cmd.Runnable() {
				continue
			}
			cmd.Flag.Usage = func() { cmd.Usage() }
			if cmd.CustomFlags {
				args = args[1:]
			} else {
				base.SetFromGOFLAGS(cmd.Flag)
				cmd.Flag.Parse(args[1:])
				args = cmd.Flag.Args()
			}
			cmd.Run(cmd, args)
			base.Exit()
			return
		}
		helpArg := ""
		if i := strings.LastIndex(cfg.CmdName, " "); i >= 0 {
			helpArg = " " + cfg.CmdName[:i]
		}
		fmt.Fprintf(os.Stderr, "go %s: unknown command\nRun 'go help%s' for usage.\n", cfg.CmdName, helpArg)
		base.SetExitStatus(2)
		base.Exit()
	}
}

func init() {
	base.Usage = mainUsage
}

func mainUsage() {
	// special case "go test -h"
	if len(os.Args) > 1 && os.Args[1] == "test" {
		test.Usage()
	}
	help.PrintUsage(os.Stderr, base.Go)
	os.Exit(2)
}
<commit_msg>cmd/go: avoid panic on 'go mod' without arguments<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:generate ./mkalldocs.sh

package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	"cmd/go/internal/base"
	"cmd/go/internal/bug"
	"cmd/go/internal/cfg"
	"cmd/go/internal/clean"
	"cmd/go/internal/doc"
	"cmd/go/internal/envcmd"
	"cmd/go/internal/fix"
	"cmd/go/internal/fmtcmd"
	"cmd/go/internal/generate"
	"cmd/go/internal/get"
	"cmd/go/internal/help"
	"cmd/go/internal/list"
	"cmd/go/internal/modcmd"
	"cmd/go/internal/modfetch"
	"cmd/go/internal/modget"
	"cmd/go/internal/modload"
	"cmd/go/internal/run"
	"cmd/go/internal/test"
	"cmd/go/internal/tool"
	"cmd/go/internal/version"
	"cmd/go/internal/vet"
	"cmd/go/internal/work"
)

func init() {
	base.Go.Commands = []*base.Command{
		bug.CmdBug,
		work.CmdBuild,
		clean.CmdClean,
		doc.CmdDoc,
		envcmd.CmdEnv,
		fix.CmdFix,
		fmtcmd.CmdFmt,
		generate.CmdGenerate,
		get.CmdGet,
		work.CmdInstall,
		list.CmdList,
		modcmd.CmdMod,
		run.CmdRun,
		test.CmdTest,
		tool.CmdTool,
		version.CmdVersion,
		vet.CmdVet,

		help.HelpBuildmode,
		help.HelpC,
		help.HelpCache,
		help.HelpEnvironment,
		help.HelpFileType,
		help.HelpGopath,
		get.HelpGopathGet,
		modfetch.HelpGoproxy,
		help.HelpImportPath,
		modload.HelpModules,
		modget.HelpModuleGet,
		help.HelpPackages,
		test.HelpTestflag,
		test.HelpTestfunc,
	}
}

func main() {
	_ = go11tag
	flag.Usage = base.Usage
	flag.Parse()
	log.SetFlags(0)

	args := flag.Args()
	if len(args) < 1 {
		base.Usage()
	}

	if modload.MustUseModules {
		// If running with modules force-enabled, change get now to change help message.
		*get.CmdGet = *modget.CmdGet
	}

	cfg.CmdName = args[0] // for error messages
	if args[0] == "help" {
		help.Help(args[1:])
		return
	}

	// Diagnose common mistake: GOPATH==GOROOT.
	// This setting is equivalent to not setting GOPATH at all,
	// which is not what most people want when they do it.
	if gopath := cfg.BuildContext.GOPATH; filepath.Clean(gopath) == filepath.Clean(runtime.GOROOT()) {
		fmt.Fprintf(os.Stderr, "warning: GOPATH set to GOROOT (%s) has no effect\n", gopath)
	} else {
		for _, p := range filepath.SplitList(gopath) {
			// Some GOPATHs have empty directory elements - ignore them.
			// See issue 21928 for details.
			if p == "" {
				continue
			}
			// Note: using HasPrefix instead of Contains because a ~ can appear
			// in the middle of directory elements, such as /tmp/git-1.8.2~rc3
			// or C:\PROGRA~1. Only ~ as a path prefix has meaning to the shell.
			if strings.HasPrefix(p, "~") {
				fmt.Fprintf(os.Stderr, "go: GOPATH entry cannot start with shell metacharacter '~': %q\n", p)
				os.Exit(2)
			}
			if !filepath.IsAbs(p) {
				fmt.Fprintf(os.Stderr, "go: GOPATH entry is relative; must be absolute path: %q.\nFor more details see: 'go help gopath'\n", p)
				os.Exit(2)
			}
		}
	}

	if fi, err := os.Stat(cfg.GOROOT); err != nil || !fi.IsDir() {
		fmt.Fprintf(os.Stderr, "go: cannot find GOROOT directory: %v\n", cfg.GOROOT)
		os.Exit(2)
	}

	// TODO(rsc): Remove all these helper prints in Go 1.12.
	switch args[0] {
	case "mod":
		if len(args) >= 2 {
			flag := args[1]
			if strings.HasPrefix(flag, "--") {
				flag = flag[1:]
			}
			if i := strings.Index(flag, "="); i >= 0 {
				flag = flag[:i]
			}
			switch flag {
			case "-sync":
				fmt.Fprintf(os.Stderr, "go: go mod -sync is now go mod tidy\n")
				os.Exit(2)
			case "-init", "-fix", "-graph", "-vendor", "-verify":
				fmt.Fprintf(os.Stderr, "go: go mod %s is now go mod %s\n", flag, flag[1:])
				os.Exit(2)
			case "-fmt", "-json", "-module", "-require", "-droprequire", "-replace", "-dropreplace", "-exclude", "-dropexclude":
				fmt.Fprintf(os.Stderr, "go: go mod %s is now go mod edit %s\n", flag, flag)
				os.Exit(2)
			}
		}
	case "vendor":
		fmt.Fprintf(os.Stderr, "go: vgo vendor is now go mod vendor\n")
		os.Exit(2)
	case "verify":
		fmt.Fprintf(os.Stderr, "go: vgo verify is now go mod verify\n")
		os.Exit(2)
	}

	if args[0] == "get" {
		// Replace get with module-aware get if appropriate.
		// Note that if MustUseModules is true, this happened already above,
		// but no harm in doing it again.
		if modload.Init(); modload.Enabled() {
			*get.CmdGet = *modget.CmdGet
		}
	}

	// Set environment (GOOS, GOARCH, etc) explicitly.
	// In theory all the commands we invoke should have
	// the same default computation of these as we do,
	// but in practice there might be skew
	// This makes sure we all agree.
	cfg.OrigEnv = os.Environ()
	cfg.CmdEnv = envcmd.MkEnv()
	for _, env := range cfg.CmdEnv {
		if os.Getenv(env.Name) != env.Value {
			os.Setenv(env.Name, env.Value)
		}
	}

BigCmdLoop:
	for bigCmd := base.Go; ; {
		for _, cmd := range bigCmd.Commands {
			if cmd.Name() != args[0] {
				continue
			}
			if len(cmd.Commands) > 0 {
				bigCmd = cmd
				args = args[1:]
				if len(args) == 0 {
					help.PrintUsage(os.Stderr, bigCmd)
					base.SetExitStatus(2)
					base.Exit()
				}
				if args[0] == "help" {
					// Accept 'go mod help' and 'go mod help foo' for 'go help mod' and 'go help mod foo'.
					help.Help(append(strings.Split(cfg.CmdName, " "), args[1:]...))
					return
				}
				cfg.CmdName += " " + args[0]
				continue BigCmdLoop
			}
			if !cmd.Runnable() {
				continue
			}
			cmd.Flag.Usage = func() { cmd.Usage() }
			if cmd.CustomFlags {
				args = args[1:]
			} else {
				base.SetFromGOFLAGS(cmd.Flag)
				cmd.Flag.Parse(args[1:])
				args = cmd.Flag.Args()
			}
			cmd.Run(cmd, args)
			base.Exit()
			return
		}
		helpArg := ""
		if i := strings.LastIndex(cfg.CmdName, " "); i >= 0 {
			helpArg = " " + cfg.CmdName[:i]
		}
		fmt.Fprintf(os.Stderr, "go %s: unknown command\nRun 'go help%s' for usage.\n", cfg.CmdName, helpArg)
		base.SetExitStatus(2)
		base.Exit()
	}
}

func init() {
	base.Usage = mainUsage
}

func mainUsage() {
	// special case "go test -h"
	if len(os.Args) > 1 && os.Args[1] == "test" {
		test.Usage()
	}
	help.PrintUsage(os.Stderr, base.Go)
	os.Exit(2)
}
<|endoftext|>