<commit_before>package image

import (
	"errors"
	"fmt"
	"image"
	"image/color"
	b "scummatlas/binaryutils"
	l "scummatlas/condlog"
)

const (
	_ = iota
	METHOD_UNKNOWN
	METHOD_UNCOMPRESSED
	METHOD_ONE
	METHOD_TWO
	HORIZONTAL
	VERTICAL
	TRANSP
	NO_TRANSP
)

var transparent = color.RGBA{0, 0, 0, 0}
var opaque = color.RGBA{0, 0, 0, 255}

func drawStripe(img *image.RGBA, stripNumber int, data []byte, pal color.Palette, transpIndex uint8) {

	stripeType, err := getCompressionMethod(stripNumber, data[0])
	if err != nil {
		l.Log("image", "Error getting compression method "+err.Error())
		return
	}

	height := img.Rect.Size().Y
	totalPixels := 8 * height
	currentPixel := 0

	curPal := uint8(data[1])

	curSubs := uint8(1)

	setColor := func() {
		var x, y int
		if stripeType.direction == HORIZONTAL {
			x = (currentPixel) % 8
			y = (currentPixel) / 8
		} else {
			y = (currentPixel) % height
			x = (currentPixel) / height
		}
		x += 8 * stripNumber
		if curPal >= 0 {
			if stripeType.transparent == TRANSP && curPal == transpIndex {
				img.Set(x, y, color.RGBA{0, 0, 0, 0})
			} else {
				img.Set(x, y, pal[curPal])
			}
		} else {
			panic("Out of palette")
		}
		currentPixel++
	}

	bs := b.NewBitStream(data[2:])

	setColor()
	if stripeType.method == METHOD_TWO {
		for currentPixel < totalPixels {
			if bs.GetBit() == 1 {
				if bs.GetBit() == 1 {
					palShift := bs.GetBits(3) - 4
					if palShift == 0 {
						length := int(bs.GetBits(8))
						for i := 0; i < length-1; i++ {
							setColor()
						}
					} else {
						curPal += palShift
					}
				} else { // 10 Read new palette index
					curPal = bs.GetBits(stripeType.paletteLength)
				}
			} else { // 0 Draw next pixel with current palette index
			}
			setColor()
		}
	} else {
		for currentPixel < totalPixels {
			if bs.GetBit() == 1 {
				if bs.GetBit() == 1 {
					if bs.GetBit() == 1 {
						//Negate the subtraction variable. Subtract it from the palette index, and draw the next pixel.
						curSubs = -curSubs
					}
					//Subtract the subtraction variable from the palette index, and draw the next pixel.
					curPal -= curSubs
				} else { //10, read new palette index
					curPal = bs.GetBits(stripeType.paletteLength)
					curSubs = 1
				}
			} else { // 0, draw next pixel with current palette index
			}
			setColor()
		}
	}
}

type StripeType struct {
	code          byte
	method        int
	direction     int
	transparent   int
	paletteLength uint8
}

func getCompressionMethod(stripNumber int, code byte) (StripeType, error) {
	stripe := StripeType{
		direction:     HORIZONTAL,
		method:        METHOD_UNKNOWN,
		transparent:   NO_TRANSP,
		paletteLength: 255,
	}

	if code == 0x01 {
		stripe.method = METHOD_UNCOMPRESSED
	} else if code >= 0x0e && code <= 0x30 {
		stripe.method = METHOD_ONE
	} else if code >= 0x40 && code <= 0x80 {
		stripe.method = METHOD_TWO
	}

	if (code >= 0x03 && code <= 0x12) ||
		(code >= 0x22 && code <= 0x26) {
		stripe.direction = VERTICAL
	}

	if (code >= 0x22 && code <= 0x30) ||
		(code >= 0x54 && code <= 0x6c) {
		stripe.transparent = TRANSP
	}

	codes := []uint8{0x0e, 0x18, 0x22, 0x2c, 0x40, 0x54, 0x68, 0x7c}

	for _, v := range codes {
		if code >= v && code <= v+4 {
			stripe.paletteLength = code - (v - 4)
			break
		}
	}

	if stripe.method == METHOD_UNKNOWN {
		return stripe, errors.New(fmt.Sprintf("Unknown method for code %x", code))
	}

	return stripe, nil
}

func printStripeInfo(stripNumber int, code byte) {
	stripeType, err := getCompressionMethod(stripNumber, code)
	if err != nil {
		l.Log("image", fmt.Sprintf("Error with stripe %d: %v", stripNumber, err.Error()))
		return
	}

	out := fmt.Sprintf("%v\t0x%X\t", stripNumber, code)
	if stripeType.method == METHOD_ONE {
		out += "   1"
	} else if stripeType.method == METHOD_TWO {
		out += "   2"
	}
	if stripeType.direction == VERTICAL {
		out += "\tVert"
	} else {
		out += "\tHoriz"
	}
	out += "\t" + string(stripeType.paletteLength)
	if stripeType.transparent == TRANSP {
		out += "\tYes"
	} else {
		out += "\tNo"
	}
	l.Log("image", out)
}

func drawStripeMask(img *image.RGBA, stripeNumber int, data []byte, offset int, height int) {
	drawSingleColorLine := func(y int, color color.RGBA) {
		for x := 0; x < 8; x++ {
			img.Set(stripeNumber*8+x, y, color)
		}
	}

	bitmap := make([]byte, 0, height)

	linesLeft := height
	for linesLeft > 0 {
		count := data[offset]
		if count&0x80 > 0 {
			count = count & 0x7f
			value := data[offset+1]
			offset += 2
			for count > 0 && linesLeft > 0 {
				bitmap = append(bitmap, value)
				linesLeft--
				count--
			}
		} else {
			offset++
			for count > 0 && linesLeft > 0 {
				value := data[offset]
				bitmap = append(bitmap, value)
				offset++
				linesLeft--
				count--
			}
		}
	}

	for y, value := range bitmap {
		if value == 0x00 {
			drawSingleColorLine(y, transparent)
		} else if value == 0xFF {
			drawSingleColorLine(y, opaque)
		} else {
			for x, bit := range b.ByteToBits(value) {
				color := transparent
				if bit > 0 {
					color = opaque
				}
				img.Set(stripeNumber*8+x, y, color)
			}
		}
	}
}
<commit_msg>Perfect image decompression<commit_after>package image

import (
	"errors"
	"fmt"
	"image"
	"image/color"
	b "scummatlas/binaryutils"
	l "scummatlas/condlog"
)

const (
	_ = iota
	METHOD_UNKNOWN
	METHOD_UNCOMPRESSED
	METHOD_ONE //ScummVM's UnkB
	METHOD_TWO //ScummVM's UnkA
	HORIZONTAL
	VERTICAL
	TRANSP
	NO_TRANSP
)

var transparent = color.RGBA{0, 0, 0, 0}
var opaque = color.RGBA{0, 0, 0, 255}

type StripeType struct {
	code          byte
	method        int
	direction     int
	transparent   int
	paletteLength uint8
}

func drawStripe(img *image.RGBA, stripNumber int, data []byte, pal color.Palette, transpIndex uint8) {

	stripeType, err := getCompressionMethod(stripNumber, data[0])
	if err != nil {
		l.Log("image", "Error getting compression method "+err.Error())
		return
	}

	height := img.Rect.Size().Y
	totalPixels := 8 * height
	currentPixel := 0

	curPal := uint8(data[1])
	curSubs := uint8(1)
	bs := b.NewBitStream(data[2:])

	setColor := func() {
		var x, y int
		if stripeType.direction == HORIZONTAL {
			x = (currentPixel) % 8
			y = (currentPixel) / 8
		} else {
			y = (currentPixel) % height
			x = (currentPixel) / height
		}
		x += 8 * stripNumber
		if curPal >= 0 {
			if stripeType.transparent == TRANSP && curPal == transpIndex {
				img.Set(x, y, transparent)
			} else {
				img.Set(x, y, pal[curPal])
			}
		} else {
			panic("Out of palette")
		}
		currentPixel++
	}

	readPaletteColor := func() {
		curPal = bs.GetBits(stripeType.paletteLength)
	}

	setColor()

	if stripeType.method == METHOD_TWO {
		for currentPixel < totalPixels {
			if bs.GetBit() == 1 {
				if bs.GetBit() == 1 {
					palShift := bs.GetBits(3) - 4
					if palShift > 0 {
						curPal += palShift
					} else {
						length := int(bs.GetBits(8))
						for i := 0; i < length-1; i++ {
							setColor()
						}
					}
				} else {
					readPaletteColor()
				}
			}
			setColor()
		}
	}
	if stripeType.method == METHOD_ONE {
		for currentPixel < totalPixels {
			if bs.GetBit() == 1 {
				if bs.GetBit() == 1 {
					if bs.GetBit() == 1 {
						curSubs = -curSubs
					}
					curPal -= curSubs
				} else {
					readPaletteColor()
					curSubs = 1
				}
			}
			setColor()
		}
	}
}

func getCompressionMethod(stripNumber int, code byte) (StripeType, error) {
	stripe := StripeType{
		direction:     HORIZONTAL,
		method:        METHOD_UNKNOWN,
		transparent:   NO_TRANSP,
		paletteLength: 255,
	}

	if code == 0x01 {
		stripe.method = METHOD_UNCOMPRESSED
	} else if code >= 0x0e && code <= 0x30 {
		stripe.method = METHOD_ONE
	} else if code >= 0x40 && code <= 0x80 {
		stripe.method = METHOD_TWO
	}

	if (code >= 0x03 && code <= 0x12) ||
		(code >= 0x22 && code <= 0x26) {
		stripe.direction = VERTICAL
	}

	if (code >= 0x22 && code <= 0x30) ||
		(code >= 0x54 && code <= 0x6c) {
		stripe.transparent = TRANSP
	}

	codes := []uint8{0x0e, 0x18, 0x22, 0x2c, 0x40, 0x54, 0x68, 0x7c}

	for _, v := range codes {
		if code >= v && code <= v+4 {
			stripe.paletteLength = code - (v - 4)
			break
		}
	}

	if stripe.method == METHOD_UNKNOWN {
		return stripe, errors.New(fmt.Sprintf("Unknown method for code %x", code))
	}

	return stripe, nil
}

func printStripeInfo(stripNumber int, code byte) {
	stripeType, err := getCompressionMethod(stripNumber, code)
	if err != nil {
		l.Log("image", fmt.Sprintf("Error with stripe %d: %v", stripNumber, err.Error()))
		return
	}

	out := fmt.Sprintf("%v\t0x%X\t", stripNumber, code)
	if stripeType.method == METHOD_ONE {
		out += "   1"
	} else if stripeType.method == METHOD_TWO {
		out += "   2"
	}
	if stripeType.direction == VERTICAL {
		out += "\tVert"
	} else {
		out += "\tHoriz"
	}
	out += "\t" + string(stripeType.paletteLength)
	if stripeType.transparent == TRANSP {
		out += "\tYes"
	} else {
		out += "\tNo"
	}
	l.Log("image", out)
}

func drawStripeMask(img *image.RGBA, stripeNumber int, data []byte, offset int, height int) {
	drawSingleColorLine := func(y int, color color.RGBA) {
		for x := 0; x < 8; x++ {
			img.Set(stripeNumber*8+x, y, color)
		}
	}

	bitmap := make([]byte, 0, height)

	linesLeft := height
	for linesLeft > 0 {
		count := data[offset]
		if count&0x80 > 0 {
			count = count & 0x7f
			value := data[offset+1]
			offset += 2
			for count > 0 && linesLeft > 0 {
				bitmap = append(bitmap, value)
				linesLeft--
				count--
			}
		} else {
			offset++
			for count > 0 && linesLeft > 0 {
				value := data[offset]
				bitmap = append(bitmap, value)
				offset++
				linesLeft--
				count--
			}
		}
	}

	for y, value := range bitmap {
		if value == 0x00 {
			drawSingleColorLine(y, transparent)
		} else if value == 0xFF {
			drawSingleColorLine(y, opaque)
		} else {
			for x, bit := range b.ByteToBits(value) {
				color := transparent
				if bit > 0 {
					color = opaque
				}
				img.Set(stripeNumber*8+x, y, color)
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"fmt"

	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/goph/emperror"
	"github.com/goph/fxt"
	"github.com/goph/fxt/debug"
	"github.com/goph/fxt/errors"
	fxlog "github.com/goph/fxt/log"
	"github.com/goph/healthz"
	"go.uber.org/fx"
)

func main() {
	status := healthz.NewStatusChecker(healthz.Healthy)
	var ext struct {
		Config       *Config
		Closer       fxt.Closer
		Logger       log.Logger
		ErrorHandler emperror.Handler

		DebugErr debug.Err
	}

	app := fx.New(
		fx.NopLogger,
		fxt.Bootstrap,
		fx.Provide(
			NewConfig,

			// Log and error handling
			NewLoggerConfig,
			fxlog.NewLogger,
			errors.NewHandler,

			// Debug server
			NewDebugConfig,
			debug.NewServer,
			debug.NewHealthCollector,
		),
		fx.Invoke(func(collector healthz.Collector) {
			collector.RegisterChecker(healthz.ReadinessCheck, status)
		}),
		fx.Extract(&ext),
	)

	err := app.Err()
	if err != nil {
		panic(err)
	}

	// Close resources even when there is an error
	defer ext.Closer.Close()

	// Register error handler to recover from panics
	defer emperror.HandleRecover(ext.ErrorHandler)

	level.Info(ext.Logger).Log(
		"msg", fmt.Sprintf("starting %s", FriendlyServiceName),
		"version", Version,
		"commit_hash", CommitHash,
		"build_date", BuildDate,
	)

	err = app.Start(context.Background())
	if err != nil {
		// Try gracefully stopping already started resources
		ctx, cancel := context.WithTimeout(context.Background(), ext.Config.ShutdownTimeout)
		defer cancel()

		app.Stop(ctx)

		panic(err)
	}

	select {
	case sig := <-app.Done():
		level.Info(ext.Logger).Log("msg", fmt.Sprintf("captured %v signal", sig))

	case err := <-ext.DebugErr:
		if err != nil {
			err = emperror.WithStack(emperror.WithMessage(err, "debug server crashed"))
			ext.ErrorHandler.Handle(err)
		}
	}

	status.SetStatus(healthz.Unhealthy)

	ctx, cancel := context.WithTimeout(context.Background(), ext.Config.ShutdownTimeout)
	defer cancel()

	err = app.Stop(ctx)
	emperror.HandleIfErr(ext.ErrorHandler, err)
}
<commit_msg>Deferred shutdown<commit_after>package main

import (
	"context"
	"fmt"

	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/goph/emperror"
	"github.com/goph/fxt"
	"github.com/goph/fxt/debug"
	"github.com/goph/fxt/errors"
	fxlog "github.com/goph/fxt/log"
	"github.com/goph/healthz"
	"go.uber.org/fx"
)

func main() {
	status := healthz.NewStatusChecker(healthz.Healthy)
	var ext struct {
		Config       *Config
		Closer       fxt.Closer
		Logger       log.Logger
		ErrorHandler emperror.Handler

		DebugErr debug.Err
	}

	app := fx.New(
		fx.NopLogger,
		fxt.Bootstrap,
		fx.Provide(
			NewConfig,

			// Log and error handling
			NewLoggerConfig,
			fxlog.NewLogger,
			errors.NewHandler,

			// Debug server
			NewDebugConfig,
			debug.NewServer,
			debug.NewHealthCollector,
		),
		fx.Invoke(func(collector healthz.Collector) {
			collector.RegisterChecker(healthz.ReadinessCheck, status)
		}),
		fx.Extract(&ext),
	)

	err := app.Err()
	if err != nil {
		panic(err)
	}

	// Close resources even when there is an error
	defer ext.Closer.Close()

	// Register error handler to recover from panics
	defer emperror.HandleRecover(ext.ErrorHandler)

	level.Info(ext.Logger).Log(
		"msg", fmt.Sprintf("starting %s", FriendlyServiceName),
		"version", Version,
		"commit_hash", CommitHash,
		"build_date", BuildDate,
	)

	// Shutdown regardless there is an error or the application just normally quits
	defer func() {
		status.SetStatus(healthz.Unhealthy)

		ctx, cancel := context.WithTimeout(context.Background(), ext.Config.ShutdownTimeout)
		defer cancel()

		err = app.Stop(ctx)
		emperror.HandleIfErr(ext.ErrorHandler, err)
	}()

	err = app.Start(context.Background())
	if err != nil {
		panic(err)
	}

	select {
	case sig := <-app.Done():
		level.Info(ext.Logger).Log("msg", fmt.Sprintf("captured %v signal", sig))

	case err := <-ext.DebugErr:
		if err != nil {
			err = emperror.WithStack(emperror.WithMessage(err, "debug server crashed"))
			ext.ErrorHandler.Handle(err)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 The kubecfg 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 (
	"bytes"
	"encoding/json"
	goflag "flag"
	"fmt"
	"io"
	"io/ioutil"
	"net/url"
	"os"
	"path/filepath"
	"strings"

	"github.com/genuinetools/reg/registry"

	jsonnet "github.com/google/go-jsonnet"
	log "github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"golang.org/x/crypto/ssh/terminal"
	"k8s.io/apimachinery/pkg/api/meta"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/client-go/discovery"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/restmapper"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/klog"

	"github.com/bitnami/kubecfg/utils"

	// Register auth plugins
	_ "k8s.io/client-go/plugin/pkg/client/auth"
)

const (
	flagVerbose    = "verbose"
	flagJpath      = "jpath"
	flagJUrl       = "jurl"
	flagExtVar     = "ext-str"
	flagExtVarFile = "ext-str-file"
	flagTlaVar     = "tla-str"
	flagTlaVarFile = "tla-str-file"
	flagResolver   = "resolve-images"
	flagResolvFail = "resolve-images-error"
)

var clientConfig clientcmd.ClientConfig
var overrides clientcmd.ConfigOverrides

func init() {
	RootCmd.PersistentFlags().CountP(flagVerbose, "v", "Increase verbosity. May be given multiple times.")
	RootCmd.PersistentFlags().StringArrayP(flagJpath, "J", nil, "Additional jsonnet library search path. May be repeated.")
	RootCmd.MarkPersistentFlagFilename(flagJpath)
	RootCmd.PersistentFlags().StringArrayP(flagJUrl, "U", nil, "Additional jsonnet library search path given as a URL. May be repeated.")
	RootCmd.PersistentFlags().StringSliceP(flagExtVar, "V", nil, "Values of external variables")
	RootCmd.PersistentFlags().StringSlice(flagExtVarFile, nil, "Read external variable from a file")
	RootCmd.MarkPersistentFlagFilename(flagExtVarFile)
	RootCmd.PersistentFlags().StringSliceP(flagTlaVar, "A", nil, "Values of top level arguments")
	RootCmd.PersistentFlags().StringSlice(flagTlaVarFile, nil, "Read top level argument from a file")
	RootCmd.MarkPersistentFlagFilename(flagTlaVarFile)
	RootCmd.PersistentFlags().String(flagResolver, "noop", "Change implementation of resolveImage native function. One of: noop, registry")
	RootCmd.PersistentFlags().String(flagResolvFail, "warn", "Action when resolveImage fails. One of ignore,warn,error")

	// The "usual" clientcmd/kubectl flags
	loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
	loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig
	kflags := clientcmd.RecommendedConfigOverrideFlags("")
	RootCmd.PersistentFlags().StringVar(&loadingRules.ExplicitPath, "kubeconfig", "", "Path to a kube config. Only required if out-of-cluster")
	RootCmd.MarkPersistentFlagFilename("kubeconfig")
	clientcmd.BindOverrideFlags(&overrides, RootCmd.PersistentFlags(), kflags)
	clientConfig = clientcmd.NewInteractiveDeferredLoadingClientConfig(loadingRules, &overrides, os.Stdin)
}

// RootCmd is the root of cobra subcommand tree
var RootCmd = &cobra.Command{
	Use:           "kubecfg",
	Short:         "Synchronise Kubernetes resources with config files",
	SilenceErrors: true,
	SilenceUsage:  true,
	PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
		goflag.CommandLine.Parse([]string{})
		flags := cmd.Flags()
		out := cmd.OutOrStderr()
		log.SetOutput(out)

		logFmt := NewLogFormatter(out)
		log.SetFormatter(logFmt)

		verbosity, err := flags.GetCount(flagVerbose)
		if err != nil {
			return err
		}
		log.SetLevel(logLevel(verbosity))

		// Ask me how much I love glog/klog's interface.
		logflags := goflag.NewFlagSet(os.Args[0], goflag.ExitOnError)
		klog.InitFlags(logflags)
		logflags.Set("logtostderr", "true")
		if verbosity >= 2 {
			// Semi-arbitrary mapping to klog level.
			logflags.Set("v", fmt.Sprintf("%d", verbosity*3))
		}

		return nil
	},
}

// clientConfig.Namespace() is broken in client-go 3.0:
// namespace in config erroneously overrides explicit --namespace
func defaultNamespace(c clientcmd.ClientConfig) (string, error) {
	if overrides.Context.Namespace != "" {
		return overrides.Context.Namespace, nil
	}
	ns, _, err := c.Namespace()
	return ns, err
}

func logLevel(verbosity int) log.Level {
	switch verbosity {
	case 0:
		return log.InfoLevel
	default:
		return log.DebugLevel
	}
}

type logFormatter struct {
	escapes  *terminal.EscapeCodes
	colorise bool
}

// NewLogFormatter creates a new log.Formatter customised for writer
func NewLogFormatter(out io.Writer) log.Formatter {
	var ret = logFormatter{}
	if f, ok := out.(*os.File); ok {
		ret.colorise = terminal.IsTerminal(int(f.Fd()))
		ret.escapes = terminal.NewTerminal(f, "").Escape
	}
	return &ret
}

func (f *logFormatter) levelEsc(level log.Level) []byte {
	switch level {
	case log.DebugLevel:
		return []byte{}
	case log.WarnLevel:
		return f.escapes.Yellow
	case log.ErrorLevel, log.FatalLevel, log.PanicLevel:
		return f.escapes.Red
	default:
		return f.escapes.Blue
	}
}

func (f *logFormatter) Format(e *log.Entry) ([]byte, error) {
	buf := bytes.Buffer{}
	if f.colorise {
		buf.Write(f.levelEsc(e.Level))
		fmt.Fprintf(&buf, "%-5s ", strings.ToUpper(e.Level.String()))
		buf.Write(f.escapes.Reset)
	}

	buf.WriteString(strings.TrimSpace(e.Message))
	buf.WriteString("\n")

	return buf.Bytes(), nil
}

// NB: `path` is assumed to be in native-OS path separator form
func dirURL(path string) *url.URL {
	path = filepath.ToSlash(path)
	if path[len(path)-1] != '/' {
		// trailing slash is important
		path = path + "/"
	}
	return &url.URL{Scheme: "file", Path: path}
}

// JsonnetVM constructs a new jsonnet.VM, according to command line
// flags
func JsonnetVM(cmd *cobra.Command) (*jsonnet.VM, error) {
	vm := jsonnet.MakeVM()
	flags := cmd.Flags()

	var searchUrls []*url.URL

	jpath := filepath.SplitList(os.Getenv("KUBECFG_JPATH"))

	jpathArgs, err := flags.GetStringArray(flagJpath)
	if err != nil {
		return nil, err
	}
	jpath = append(jpath, jpathArgs...)

	for _, p := range jpath {
		p, err := filepath.Abs(p)
		if err != nil {
			return nil, err
		}
		searchUrls = append(searchUrls, dirURL(p))
	}

	sURLs, err := flags.GetStringArray(flagJUrl)
	if err != nil {
		return nil, err
	}

	// Special URL scheme used to find embedded content
	sURLs = append(sURLs, "internal:///")

	for _, ustr := range sURLs {
		u, err := url.Parse(ustr)
		if err != nil {
			return nil, err
		}
		if u.Path[len(u.Path)-1] != '/' {
			u.Path = u.Path + "/"
		}
		searchUrls = append(searchUrls, u)
	}

	for _, u := range searchUrls {
		log.Debugln("Jsonnet search path:", u)
	}

	vm.Importer(utils.MakeUniversalImporter(searchUrls))

	extvars, err := flags.GetStringSlice(flagExtVar)
	if err != nil {
		return nil, err
	}
	for _, extvar := range extvars {
		kv := strings.SplitN(extvar, "=", 2)
		switch len(kv) {
		case 1:
			v, present := os.LookupEnv(kv[0])
			if present {
				vm.ExtVar(kv[0], v)
			} else {
				return nil, fmt.Errorf("Missing environment variable: %s", kv[0])
			}
		case 2:
			vm.ExtVar(kv[0], kv[1])
		}
	}

	extvarfiles, err := flags.GetStringSlice(flagExtVarFile)
	if err != nil {
		return nil, err
	}
	for _, extvar := range extvarfiles {
		kv := strings.SplitN(extvar, "=", 2)
		if len(kv) != 2 {
			return nil, fmt.Errorf("Failed to parse %s: missing '=' in %s", flagExtVarFile, extvar)
		}
		v, err := ioutil.ReadFile(kv[1])
		if err != nil {
			return nil, err
		}
		vm.ExtVar(kv[0], string(v))
	}

	tlavars, err := flags.GetStringSlice(flagTlaVar)
	if err != nil {
		return nil, err
	}
	for _, tlavar := range tlavars {
		kv := strings.SplitN(tlavar, "=", 2)
		switch len(kv) {
		case 1:
			v, present := os.LookupEnv(kv[0])
			if present {
				vm.TLAVar(kv[0], v)
			} else {
				return nil, fmt.Errorf("Missing environment variable: %s", kv[0])
			}
		case 2:
			vm.TLAVar(kv[0], kv[1])
		}
	}

	tlavarfiles, err := flags.GetStringSlice(flagTlaVarFile)
	if err != nil {
		return nil, err
	}
	for _, tlavar := range tlavarfiles {
		kv := strings.SplitN(tlavar, "=", 2)
		if len(kv) != 2 {
			return nil, fmt.Errorf("Failed to parse %s: missing '=' in %s", flagTlaVarFile, tlavar)
		}
		v, err := ioutil.ReadFile(kv[1])
		if err != nil {
			return nil, err
		}
		vm.TLAVar(kv[0], string(v))
	}

	resolver, err := buildResolver(cmd)
	if err != nil {
		return nil, err
	}
	utils.RegisterNativeFuncs(vm, resolver)

	return vm, nil
}

func buildResolver(cmd *cobra.Command) (utils.Resolver, error) {
	flags := cmd.Flags()
	resolver, err := flags.GetString(flagResolver)
	if err != nil {
		return nil, err
	}
	failAction, err := flags.GetString(flagResolvFail)
	if err != nil {
		return nil, err
	}

	ret := resolverErrorWrapper{}

	switch failAction {
	case "ignore":
		ret.OnErr = func(error) error { return nil }
	case "warn":
		ret.OnErr = func(err error) error {
			log.Warning(err.Error())
			return nil
		}
	case "error":
		ret.OnErr = func(err error) error { return err }
	default:
		return nil, fmt.Errorf("Bad value for --%s: %s", flagResolvFail, failAction)
	}

	switch resolver {
	case "noop":
		ret.Inner = utils.NewIdentityResolver()
	case "registry":
		ret.Inner = utils.NewRegistryResolver(registry.Opt{})
	default:
		return nil, fmt.Errorf("Bad value for --%s: %s", flagResolver, resolver)
	}

	return &ret, nil
}

type resolverErrorWrapper struct {
	Inner utils.Resolver
	OnErr func(error) error
}

func (r *resolverErrorWrapper) Resolve(image *utils.ImageName) error {
	err := r.Inner.Resolve(image)
	if err != nil {
		err = r.OnErr(err)
	}
	return err
}

func readObjs(cmd *cobra.Command, paths []string) ([]*unstructured.Unstructured, error) {
	vm, err := JsonnetVM(cmd)
	if err != nil {
		return nil, err
	}

	res := []*unstructured.Unstructured{}
	for _, path := range paths {
		objs, err := utils.Read(vm, path)
		if err != nil {
			return nil, fmt.Errorf("Error reading %s: %v", path, err)
		}
		res = append(res, utils.FlattenToV1(objs)...)
	}
	return res, nil
}

// For debugging
func dumpJSON(v interface{}) string {
	buf := bytes.NewBuffer(nil)
	enc := json.NewEncoder(buf)
	enc.SetIndent("", "  ")
	if err := enc.Encode(v); err != nil {
		return err.Error()
	}
	return string(buf.Bytes())
}

func getDynamicClients(cmd *cobra.Command) (dynamic.Interface, meta.RESTMapper, discovery.DiscoveryInterface, error) {
	conf, err := clientConfig.ClientConfig()
	if err != nil {
		return nil, nil, nil, fmt.Errorf("Unable to read kubectl config: %v", err)
	}

	disco, err := discovery.NewDiscoveryClientForConfig(conf)
	if err != nil {
		return nil, nil, nil, err
	}
	discoCache := utils.NewMemcachedDiscoveryClient(disco)

	mapper := restmapper.NewDeferredDiscoveryRESTMapper(discoCache)

	cl, err := dynamic.NewForConfig(conf)
	if err != nil {
		return nil, nil, nil, err
	}

	return cl, mapper, discoCache, nil
}
<commit_msg>Document KUBECFG_JPATH<commit_after>// Copyright 2017 The kubecfg 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 (
	"bytes"
	"encoding/json"
	goflag "flag"
	"fmt"
	"io"
	"io/ioutil"
	"net/url"
	"os"
	"path/filepath"
	"strings"

	"github.com/genuinetools/reg/registry"

	jsonnet "github.com/google/go-jsonnet"
	log "github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"golang.org/x/crypto/ssh/terminal"
	"k8s.io/apimachinery/pkg/api/meta"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/client-go/discovery"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/restmapper"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/klog"

	"github.com/bitnami/kubecfg/utils"

	// Register auth plugins
	_ "k8s.io/client-go/plugin/pkg/client/auth"
)

const (
	flagVerbose    = "verbose"
	flagJpath      = "jpath"
	flagJUrl       = "jurl"
	flagExtVar     = "ext-str"
	flagExtVarFile = "ext-str-file"
	flagTlaVar     = "tla-str"
	flagTlaVarFile = "tla-str-file"
	flagResolver   = "resolve-images"
	flagResolvFail = "resolve-images-error"
)

var clientConfig clientcmd.ClientConfig
var overrides clientcmd.ConfigOverrides

func init() {
	RootCmd.PersistentFlags().CountP(flagVerbose, "v", "Increase verbosity. May be given multiple times.")
	RootCmd.PersistentFlags().StringArrayP(flagJpath, "J", nil, "Additional jsonnet library search path, appended to the ones in the KUBECFG_JPATH env var. May be repeated.")
	RootCmd.MarkPersistentFlagFilename(flagJpath)
	RootCmd.PersistentFlags().StringArrayP(flagJUrl, "U", nil, "Additional jsonnet library search path given as a URL. May be repeated.")
	RootCmd.PersistentFlags().StringSliceP(flagExtVar, "V", nil, "Values of external variables")
	RootCmd.PersistentFlags().StringSlice(flagExtVarFile, nil, "Read external variable from a file")
	RootCmd.MarkPersistentFlagFilename(flagExtVarFile)
	RootCmd.PersistentFlags().StringSliceP(flagTlaVar, "A", nil, "Values of top level arguments")
	RootCmd.PersistentFlags().StringSlice(flagTlaVarFile, nil, "Read top level argument from a file")
	RootCmd.MarkPersistentFlagFilename(flagTlaVarFile)
	RootCmd.PersistentFlags().String(flagResolver, "noop", "Change implementation of resolveImage native function. One of: noop, registry")
	RootCmd.PersistentFlags().String(flagResolvFail, "warn", "Action when resolveImage fails. One of ignore,warn,error")

	// The "usual" clientcmd/kubectl flags
	loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
	loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig
	kflags := clientcmd.RecommendedConfigOverrideFlags("")
	RootCmd.PersistentFlags().StringVar(&loadingRules.ExplicitPath, "kubeconfig", "", "Path to a kube config. Only required if out-of-cluster")
	RootCmd.MarkPersistentFlagFilename("kubeconfig")
	clientcmd.BindOverrideFlags(&overrides, RootCmd.PersistentFlags(), kflags)
	clientConfig = clientcmd.NewInteractiveDeferredLoadingClientConfig(loadingRules, &overrides, os.Stdin)
}

// RootCmd is the root of cobra subcommand tree
var RootCmd = &cobra.Command{
	Use:           "kubecfg",
	Short:         "Synchronise Kubernetes resources with config files",
	SilenceErrors: true,
	SilenceUsage:  true,
	PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
		goflag.CommandLine.Parse([]string{})
		flags := cmd.Flags()
		out := cmd.OutOrStderr()
		log.SetOutput(out)

		logFmt := NewLogFormatter(out)
		log.SetFormatter(logFmt)

		verbosity, err := flags.GetCount(flagVerbose)
		if err != nil {
			return err
		}
		log.SetLevel(logLevel(verbosity))

		// Ask me how much I love glog/klog's interface.
		logflags := goflag.NewFlagSet(os.Args[0], goflag.ExitOnError)
		klog.InitFlags(logflags)
		logflags.Set("logtostderr", "true")
		if verbosity >= 2 {
			// Semi-arbitrary mapping to klog level.
			logflags.Set("v", fmt.Sprintf("%d", verbosity*3))
		}

		return nil
	},
}

// clientConfig.Namespace() is broken in client-go 3.0:
// namespace in config erroneously overrides explicit --namespace
func defaultNamespace(c clientcmd.ClientConfig) (string, error) {
	if overrides.Context.Namespace != "" {
		return overrides.Context.Namespace, nil
	}
	ns, _, err := c.Namespace()
	return ns, err
}

func logLevel(verbosity int) log.Level {
	switch verbosity {
	case 0:
		return log.InfoLevel
	default:
		return log.DebugLevel
	}
}

type logFormatter struct {
	escapes  *terminal.EscapeCodes
	colorise bool
}

// NewLogFormatter creates a new log.Formatter customised for writer
func NewLogFormatter(out io.Writer) log.Formatter {
	var ret = logFormatter{}
	if f, ok := out.(*os.File); ok {
		ret.colorise = terminal.IsTerminal(int(f.Fd()))
		ret.escapes = terminal.NewTerminal(f, "").Escape
	}
	return &ret
}

func (f *logFormatter) levelEsc(level log.Level) []byte {
	switch level {
	case log.DebugLevel:
		return []byte{}
	case log.WarnLevel:
		return f.escapes.Yellow
	case log.ErrorLevel, log.FatalLevel, log.PanicLevel:
		return f.escapes.Red
	default:
		return f.escapes.Blue
	}
}

func (f *logFormatter) Format(e *log.Entry) ([]byte, error) {
	buf := bytes.Buffer{}
	if f.colorise {
		buf.Write(f.levelEsc(e.Level))
		fmt.Fprintf(&buf, "%-5s ", strings.ToUpper(e.Level.String()))
		buf.Write(f.escapes.Reset)
	}

	buf.WriteString(strings.TrimSpace(e.Message))
	buf.WriteString("\n")

	return buf.Bytes(), nil
}

// NB: `path` is assumed to be in native-OS path separator form
func dirURL(path string) *url.URL {
	path = filepath.ToSlash(path)
	if path[len(path)-1] != '/' {
		// trailing slash is important
		path = path + "/"
	}
	return &url.URL{Scheme: "file", Path: path}
}

// JsonnetVM constructs a new jsonnet.VM, according to command line
// flags
func JsonnetVM(cmd *cobra.Command) (*jsonnet.VM, error) {
	vm := jsonnet.MakeVM()
	flags := cmd.Flags()

	var searchUrls []*url.URL

	jpath := filepath.SplitList(os.Getenv("KUBECFG_JPATH"))

	jpathArgs, err := flags.GetStringArray(flagJpath)
	if err != nil {
		return nil, err
	}
	jpath = append(jpath, jpathArgs...)

	for _, p := range jpath {
		p, err := filepath.Abs(p)
		if err != nil {
			return nil, err
		}
		searchUrls = append(searchUrls, dirURL(p))
	}

	sURLs, err := flags.GetStringArray(flagJUrl)
	if err != nil {
		return nil, err
	}

	// Special URL scheme used to find embedded content
	sURLs = append(sURLs, "internal:///")

	for _, ustr := range sURLs {
		u, err := url.Parse(ustr)
		if err != nil {
			return nil, err
		}
		if u.Path[len(u.Path)-1] != '/' {
			u.Path = u.Path + "/"
		}
		searchUrls = append(searchUrls, u)
	}

	for _, u := range searchUrls {
		log.Debugln("Jsonnet search path:", u)
	}

	vm.Importer(utils.MakeUniversalImporter(searchUrls))

	extvars, err := flags.GetStringSlice(flagExtVar)
	if err != nil {
		return nil, err
	}
	for _, extvar := range extvars {
		kv := strings.SplitN(extvar, "=", 2)
		switch len(kv) {
		case 1:
			v, present := os.LookupEnv(kv[0])
			if present {
				vm.ExtVar(kv[0], v)
			} else {
				return nil, fmt.Errorf("Missing environment variable: %s", kv[0])
			}
		case 2:
			vm.ExtVar(kv[0], kv[1])
		}
	}

	extvarfiles, err := flags.GetStringSlice(flagExtVarFile)
	if err != nil {
		return nil, err
	}
	for _, extvar := range extvarfiles {
		kv := strings.SplitN(extvar, "=", 2)
		if len(kv) != 2 {
			return nil, fmt.Errorf("Failed to parse %s: missing '=' in %s", flagExtVarFile, extvar)
		}
		v, err := ioutil.ReadFile(kv[1])
		if err != nil {
			return nil, err
		}
		vm.ExtVar(kv[0], string(v))
	}

	tlavars, err := flags.GetStringSlice(flagTlaVar)
	if err != nil {
		return nil, err
	}
	for _, tlavar := range tlavars {
		kv := strings.SplitN(tlavar, "=", 2)
		switch len(kv) {
		case 1:
			v, present := os.LookupEnv(kv[0])
			if present {
				vm.TLAVar(kv[0], v)
			} else {
				return nil, fmt.Errorf("Missing environment variable: %s", kv[0])
			}
		case 2:
			vm.TLAVar(kv[0], kv[1])
		}
	}

	tlavarfiles, err := flags.GetStringSlice(flagTlaVarFile)
	if err != nil {
		return nil, err
	}
	for _, tlavar := range tlavarfiles {
		kv := strings.SplitN(tlavar, "=", 2)
		if len(kv) != 2 {
			return nil, fmt.Errorf("Failed to parse %s: missing '=' in %s", flagTlaVarFile, tlavar)
		}
		v, err := ioutil.ReadFile(kv[1])
		if err != nil {
			return nil, err
		}
		vm.TLAVar(kv[0], string(v))
	}

	resolver, err := buildResolver(cmd)
	if err != nil {
		return nil, err
	}
	utils.RegisterNativeFuncs(vm, resolver)

	return vm, nil
}

func buildResolver(cmd *cobra.Command) (utils.Resolver, error) {
	flags := cmd.Flags()
	resolver, err := flags.GetString(flagResolver)
	if err != nil {
		return nil, err
	}
	failAction, err := flags.GetString(flagResolvFail)
	if err != nil {
		return nil, err
	}

	ret := resolverErrorWrapper{}

	switch failAction {
	case "ignore":
		ret.OnErr = func(error) error { return nil }
	case "warn":
		ret.OnErr = func(err error) error {
			log.Warning(err.Error())
			return nil
		}
	case "error":
		ret.OnErr = func(err error) error { return err }
	default:
		return nil, fmt.Errorf("Bad value for --%s: %s", flagResolvFail, failAction)
	}

	switch resolver {
	case "noop":
		ret.Inner = utils.NewIdentityResolver()
	case "registry":
		ret.Inner = utils.NewRegistryResolver(registry.Opt{})
	default:
		return nil, fmt.Errorf("Bad value for --%s: %s", flagResolver, resolver)
	}

	return &ret, nil
}

type resolverErrorWrapper struct {
	Inner utils.Resolver
	OnErr func(error) error
}

func (r *resolverErrorWrapper) Resolve(image *utils.ImageName) error {
	err := r.Inner.Resolve(image)
	if err != nil {
		err = r.OnErr(err)
	}
	return err
}

func readObjs(cmd *cobra.Command, paths []string) ([]*unstructured.Unstructured, error) {
	vm, err := JsonnetVM(cmd)
	if err != nil {
		return nil, err
	}

	res := []*unstructured.Unstructured{}
	for _, path := range paths {
		objs, err := utils.Read(vm, path)
		if err != nil {
			return nil, fmt.Errorf("Error reading %s: %v", path, err)
		}
		res = append(res, utils.FlattenToV1(objs)...)
	}
	return res, nil
}

// For debugging
func dumpJSON(v interface{}) string {
	buf := bytes.NewBuffer(nil)
	enc := json.NewEncoder(buf)
	enc.SetIndent("", "  ")
	if err := enc.Encode(v); err != nil {
		return err.Error()
	}
	return string(buf.Bytes())
}

func getDynamicClients(cmd *cobra.Command) (dynamic.Interface, meta.RESTMapper, discovery.DiscoveryInterface, error) {
	conf, err := clientConfig.ClientConfig()
	if err != nil {
		return nil, nil, nil, fmt.Errorf("Unable to read kubectl config: %v", err)
	}

	disco, err := discovery.NewDiscoveryClientForConfig(conf)
	if err != nil {
		return nil, nil, nil, err
	}
	discoCache := utils.NewMemcachedDiscoveryClient(disco)

	mapper := restmapper.NewDeferredDiscoveryRESTMapper(discoCache)

	cl, err := dynamic.NewForConfig(conf)
	if err != nil {
		return nil, nil, nil, err
	}

	return cl, mapper, discoCache, nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"io"
	"os"
	"runtime"

	"github.com/exercism/cli/api"
	"github.com/exercism/cli/config"
	"github.com/exercism/cli/debug"
	"github.com/spf13/cobra"
)

var (
	// BinaryName is the name of the app.
	// By default this is exercism, but people
	// are free to name this however they want.
	// The usage examples and help strings should reflect
	// the actual name of the binary.
	BinaryName string
	// Out is used to write to information.
	Out io.Writer
	// Err is used to write errors.
	Err io.Writer
	// In is used to provide mocked test input (i.e. for prompts).
	In io.Reader
)

// RootCmd represents the base command when called without any subcommands.
var RootCmd = &cobra.Command{
	Use:   BinaryName,
	Short: "A friendly command-line interface to Exercism.",
	Long: `A command-line interface for the v2 redesign of Exercism.

Download exercises and submit your solutions.`,
	SilenceUsage: true,
	PersistentPreRun: func(cmd *cobra.Command, args []string) {
		if verbose, _ := cmd.Flags().GetBool("verbose"); verbose {
			debug.Verbose = verbose
		}
	},
}

// Execute adds all child commands to the root command.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Fprintf(Err, "%s\n", err.Error())
		os.Exit(-1)
	}
}

func init() {
	BinaryName = os.Args[0]
	config.SetDefaultDirName(BinaryName)
	Out = os.Stdout
	Err = os.Stderr
	In = os.Stdin
	api.UserAgent = fmt.Sprintf("github.com/exercism/cli v%s (%s/%s)", Version, runtime.GOOS, runtime.GOARCH)
	RootCmd.PersistentFlags().BoolP("verbose", "v", false, "verbose output")
}
<commit_msg>Do not double-print the command errors<commit_after>package cmd

import (
	"fmt"
	"io"
	"os"
	"runtime"

	"github.com/exercism/cli/api"
	"github.com/exercism/cli/config"
	"github.com/exercism/cli/debug"
	"github.com/spf13/cobra"
)

var (
	// BinaryName is the name of the app.
	// By default this is exercism, but people
	// are free to name this however they want.
	// The usage examples and help strings should reflect
	// the actual name of the binary.
	BinaryName string
	// Out is used to write to information.
	Out io.Writer
	// Err is used to write errors.
	Err io.Writer
	// In is used to provide mocked test input (i.e. for prompts).
	In io.Reader
)

// RootCmd represents the base command when called without any subcommands.
var RootCmd = &cobra.Command{
	Use:   BinaryName,
	Short: "A friendly command-line interface to Exercism.",
	Long: `A command-line interface for the v2 redesign of Exercism.

Download exercises and submit your solutions.`,
	SilenceUsage: true,
	PersistentPreRun: func(cmd *cobra.Command, args []string) {
		if verbose, _ := cmd.Flags().GetBool("verbose"); verbose {
			debug.Verbose = verbose
		}
	},
}

// Execute adds all child commands to the root command.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		os.Exit(-1)
	}
}

func init() {
	BinaryName = os.Args[0]
	config.SetDefaultDirName(BinaryName)
	Out = os.Stdout
	Err = os.Stderr
	In = os.Stdin
	api.UserAgent = fmt.Sprintf("github.com/exercism/cli v%s (%s/%s)", Version, runtime.GOOS, runtime.GOARCH)
	RootCmd.PersistentFlags().BoolP("verbose", "v", false, "verbose output")
}
<|endoftext|>


<commit_before>// Copyright © 2015 NAME HERE <EMAIL ADDRESS>
//
// 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 (
	"encoding/csv"
	"fmt"
	br "github.com/cheggaaa/pb"
	pb "github.com/clawio/clawiobench/proto/metadata"
	"github.com/spf13/cobra"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"time"
)

var childrenFlag bool

var statCmd = &cobra.Command{
	Use:   "stat <path>",
	Short: "Benchmark getting resource information using stat",
	RunE:  stat,
}

func stat(cmd *cobra.Command, args []string) error {

	if len(args) != 1 {
		cmd.Help()
		return nil
	}

	token, err := getToken()
	if err != nil {
		return err
	}

	con, err := grpc.Dial(metaAddr, grpc.WithInsecure())
	if err != nil {
		return err
	}
	defer con.Close()

	c := pb.NewMetaClient(con)

	benchStart := time.Now()

	total := 0
	errorProbes := 0

	errChan := make(chan error)
	resChan := make(chan string)
	doneChan := make(chan bool)
	limitChan := make(chan int, concurrencyFlag)

	for i := 0; i < concurrencyFlag; i++ {
		limitChan <- 1
	}

	var bar *br.ProgressBar
	if progressBar {
		bar = br.StartNew(probesFlag)
	}

	for i := 0; i < probesFlag; i++ {
		go func() {
			<-limitChan
			defer func() {
				limitChan <- 1
			}()
			in := &pb.StatReq{}
			in.AccessToken = token
			in.Path = args[0]
			in.Children = childrenFlag
			ctx := context.Background()
			_, err := c.Stat(ctx, in)
			if err != nil {
				errChan <- err
				return
			}
			doneChan <- true
			resChan <- ""
		}()
	}

	for {
		select {
		case _ = <-doneChan:
			total++
			if progressBar {
				bar.Increment()
			}
		case res := <-resChan:
			log.Printf("Worker %s has finished", res)
		case err := <-errChan:
			log.Error(err)
			errorProbes++
			total++
			if progressBar {
				bar.Increment()
			}
		}
		if total == probesFlag {
			break
		}
	}

	if progressBar {
		bar.Finish()
	}

	numberRequests := probesFlag
	concurrency := concurrencyFlag
	totalTime := time.Since(benchStart).Seconds()
	failedRequests := errorProbes
	frequency := float64(numberRequests) / totalTime
	period := float64(1 / frequency)

	data := [][]string{
		{"NUMBER", "CONCURRENCY", "TIME", "FAILED", "FREQ", "PERIOD"},
		{fmt.Sprintf("%d", numberRequests), fmt.Sprintf("%d", concurrency), fmt.Sprintf("%f", totalTime), fmt.Sprintf("%d", failedRequests), fmt.Sprintf("%f", frequency), fmt.Sprintf("%f", period)},
	}
	w := csv.NewWriter(output)
	for _, d := range data {
		if err := w.Write(d); err != nil {
			return err
		}
	}
	w.Flush()

	if err := w.Error(); err != nil {
		return err
	}
	return nil
}

func init() {
	RootCmd.AddCommand(statCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// statCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// statCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

	statCmd.Flags().BoolVarP(&childrenFlag, "children", "", false, "Show children objects inside container")
}
<commit_msg>Substract failed requests from freq<commit_after>// Copyright © 2015 NAME HERE <EMAIL ADDRESS>
//
// 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 (
	"encoding/csv"
	"fmt"
	br "github.com/cheggaaa/pb"
	pb "github.com/clawio/clawiobench/proto/metadata"
	"github.com/spf13/cobra"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"time"
)

var childrenFlag bool

var statCmd = &cobra.Command{
	Use:   "stat <path>",
	Short: "Benchmark getting resource information using stat",
	RunE:  stat,
}

func stat(cmd *cobra.Command, args []string) error {

	if len(args) != 1 {
		cmd.Help()
		return nil
	}

	token, err := getToken()
	if err != nil {
		return err
	}

	con, err := grpc.Dial(metaAddr, grpc.WithInsecure())
	if err != nil {
		return err
	}
	defer con.Close()

	c := pb.NewMetaClient(con)

	benchStart := time.Now()

	total := 0
	errorProbes := 0

	errChan := make(chan error)
	resChan := make(chan string)
	doneChan := make(chan bool)
	limitChan := make(chan int, concurrencyFlag)

	for i := 0; i < concurrencyFlag; i++ {
		limitChan <- 1
	}

	var bar *br.ProgressBar
	if progressBar {
		bar = br.StartNew(probesFlag)
	}

	for i := 0; i < probesFlag; i++ {
		go func() {
			<-limitChan
			defer func() {
				limitChan <- 1
			}()
			in := &pb.StatReq{}
			in.AccessToken = token
			in.Path = args[0]
			in.Children = childrenFlag
			ctx := context.Background()
			_, err := c.Stat(ctx, in)
			if err != nil {
				errChan <- err
				return
			}
			doneChan <- true
			resChan <- ""
		}()
	}

	for {
		select {
		case _ = <-doneChan:
			total++
			if progressBar {
				bar.Increment()
			}
		case res := <-resChan:
			log.Printf("Worker %s has finished", res)
		case err := <-errChan:
			log.Error(err)
			errorProbes++
			total++
			if progressBar {
				bar.Increment()
			}
		}
		if total == probesFlag {
			break
		}
	}

	if progressBar {
		bar.Finish()
	}

	numberRequests := probesFlag
	concurrency := concurrencyFlag
	totalTime := time.Since(benchStart).Seconds()
	failedRequests := errorProbes
	frequency := float64(numberRequests-failedRequests) / totalTime
	period := float64(1 / frequency)

	data := [][]string{
		{"NUMBER", "CONCURRENCY", "TIME", "FAILED", "FREQ", "PERIOD"},
		{fmt.Sprintf("%d", numberRequests), fmt.Sprintf("%d", concurrency), fmt.Sprintf("%f", totalTime), fmt.Sprintf("%d", failedRequests), fmt.Sprintf("%f", frequency), fmt.Sprintf("%f", period)},
	}
	w := csv.NewWriter(output)
	for _, d := range data {
		if err := w.Write(d); err != nil {
			return err
		}
	}
	w.Flush()

	if err := w.Error(); err != nil {
		return err
	}
	return nil
}

func init() {
	RootCmd.AddCommand(statCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// statCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// statCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

	statCmd.Flags().BoolVarP(&childrenFlag, "children", "", false, "Show children objects inside container")
}
<|endoftext|>


<commit_before>func main() {
	var T int
	fmt.Scan(&T)
	for t := 0; t < T; t++ {
	  var N int
	  fmt.Scan(&N)

	  ps := make([]int, N, N)

	  for d := 0; d < N; d++ {
		  fmt.Scan(&dishes[d])
	  }
	  sort.Sort(sort.Reverse(sort.IntSlice(dishes)))

	  min := 10000
	  for lim := 1; lim <= dishes[0]; lim++ {
		  moves := 0
		  for _, dish := range dishes {
			  moves += (dish - 1) / lim
		  }
		  if moves < ret {
			  min = moves
		  }
	  }

		 fmt.Printf("Case #%v: %v\n", t+1, min)
	}
  }<commit_msg>Revert "Pancakes problem with Go"<commit_after><|endoftext|>


<commit_before>// Copyright 2009 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 os

import (
	"syscall"
	"time"
)

func sameFile(sys1, sys2 interface{}) bool {
	stat1 := sys1.(*syscall.Stat_t)
	stat2 := sys2.(*syscall.Stat_t)
	return stat1.Dev == stat2.Dev && stat1.Ino == stat2.Ino
}

func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
	fs := &fileStat{
		name:    basename(name),
		size:    int64(st.Size),
		modTime: timespecToTime(st.Mtim),
		Sys:     st,
	}
	fs.mode = FileMode(st.Mode & 0777)
	switch st.Mode & syscall.S_IFMT {
	case syscall.S_IFBLK:
		fs.mode |= ModeDevice
	case syscall.S_IFCHR:
		fs.mode |= ModeDevice | ModeCharDevice
	case syscall.S_IFDIR:
		fs.mode |= ModeDir
	case syscall.S_IFIFO:
		fs.mode |= ModeNamedPipe
	case syscall.S_IFLNK:
		fs.mode |= ModeSymlink
	case syscall.S_IFREG:
		// nothing to do
	case syscall.S_IFSOCK:
		fs.mode |= ModeSocket
	}
	if st.Mode&syscall.S_ISGID != 0 {
		fs.mode |= ModeSetgid
	}
	if st.Mode&syscall.S_ISUID != 0 {
		fs.mode |= ModeSetuid
	}
	if st.Mode&syscall.S_ISVTX != 0 {
		fs.mode |= ModeSticky
	}
	return fs
}

func timespecToTime(ts syscall.Timespec) time.Time {
	return time.Unix(int64(ts.Sec), int64(ts.Nsec))
}

// For testing.
func atime(fi FileInfo) time.Time {
	return timespecToTime(fi.Sys().(*syscall.Stat_t).Atim)
}
<commit_msg>os: fix NetBSD build<commit_after>// Copyright 2009 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 os

import (
	"syscall"
	"time"
)

func sameFile(sys1, sys2 interface{}) bool {
	stat1 := sys1.(*syscall.Stat_t)
	stat2 := sys2.(*syscall.Stat_t)
	return stat1.Dev == stat2.Dev && stat1.Ino == stat2.Ino
}

func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
	fs := &fileStat{
		name:    basename(name),
		size:    int64(st.Size),
		modTime: timespecToTime(st.Mtim),
		sys:     st,
	}
	fs.mode = FileMode(st.Mode & 0777)
	switch st.Mode & syscall.S_IFMT {
	case syscall.S_IFBLK:
		fs.mode |= ModeDevice
	case syscall.S_IFCHR:
		fs.mode |= ModeDevice | ModeCharDevice
	case syscall.S_IFDIR:
		fs.mode |= ModeDir
	case syscall.S_IFIFO:
		fs.mode |= ModeNamedPipe
	case syscall.S_IFLNK:
		fs.mode |= ModeSymlink
	case syscall.S_IFREG:
		// nothing to do
	case syscall.S_IFSOCK:
		fs.mode |= ModeSocket
	}
	if st.Mode&syscall.S_ISGID != 0 {
		fs.mode |= ModeSetgid
	}
	if st.Mode&syscall.S_ISUID != 0 {
		fs.mode |= ModeSetuid
	}
	if st.Mode&syscall.S_ISVTX != 0 {
		fs.mode |= ModeSticky
	}
	return fs
}

func timespecToTime(ts syscall.Timespec) time.Time {
	return time.Unix(int64(ts.Sec), int64(ts.Nsec))
}

// For testing.
func atime(fi FileInfo) time.Time {
	return timespecToTime(fi.Sys().(*syscall.Stat_t).Atim)
}
<|endoftext|>


<commit_before>// Copyright 2016 The clang-server 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 symbol

import (
	"path/filepath"
	"reflect"
	"time"

	"github.com/go-clang/v3.9/clang"
	flatbuffers "github.com/google/flatbuffers/go"
	"github.com/zchee/clang-server/symbol/internal/symbol"
)

// ----------------------------------------------------------------------------

// File represents a C/C++ source file.
//
// table File {
//   Name: string;
//   TranslationUnit: string;
//   Symbols: [Info];
//   Headers: [Header];
//   Includes: [string];
// }
type File struct {
	name            string
	translationUnit []byte
	locations       map[Location]ID
	symbols         map[ID]*Info
	headers         []*Header

	builder *flatbuffers.Builder

	file *symbol.File
}

func NewFile(name string) *File {
	return &File{
		name:      name,
		locations: make(map[Location]ID),
		symbols:   make(map[ID]*Info),
		builder:   flatbuffers.NewBuilder(0),
	}
}

func GetRootAsFile(buf []byte, offset flatbuffers.UOffsetT) *File {
	return &File{
		file: symbol.GetRootAsFile(buf, offset),
	}
}

func (f *File) Name() string {
	return string(f.file.Name())
}

func (f *File) TranslationUnit() []byte {
	return f.file.TranslationUnit()
}

func (f *File) Symbols() []*Info {
	n := f.file.SymbolsLength()
	symbols := make([]*Info, n)

	for i := 0; i < n; i++ {
		obj := new(symbol.Info)
		if f.file.Symbols(obj, i) {
			symbols[i] = &Info{info: obj}
		}
	}

	return symbols
}

func (f *File) Header() []*Header {
	n := f.file.HeadersLength()
	hedears := make([]*Header, n)

	for i := 0; i < n; i++ {
		obj := new(symbol.Header)
		if f.file.Headers(obj, i) {
			hedears[i] = &Header{header: obj}
		}
	}

	return hedears
}

func (f *File) AddTranslationUnit(buf []byte) {
	f.translationUnit = buf
}

// AddSymbol adds the symbol data into File.
func (f *File) addSymbol(loc, def Location) {
	id := ToID(loc.usr)

	sym, ok := f.symbols[id]
	if !ok {
		sym = &Info{id: id}
	}
	sym.decls = append(sym.decls, loc)

	if def.isExist() {
		sym.def = def
	}

	f.locations[loc] = id
	f.symbols[id] = sym
}

// AddDecl add decl data into File.
func (f *File) AddDecl(loc Location) {
	f.addSymbol(loc, Location{})
}

// AddDefinition add definition data into File.
func (f *File) AddDefinition(loc, def Location) {
	f.addSymbol(loc, def)
}

// notExistHeaderName return the not exist header name magic words.
func notExistHeaderName(headPath string) string {
	// adding magic to filename to not confuse it with real files
	return "IDoNotReallyExist-" + filepath.Base(headPath)
}

// AddHeader add header data into File.
func (f *File) AddHeader(includePath string, headerFile clang.File) {
	hdr := new(Header)
	if headerFile.Name() == "" {
		hdr.fileid = ToFileID(notExistHeaderName(filepath.Clean(headerFile.Name())))
		hdr.mtime = time.Now()
	} else {
		hdr.fileid = ToFileID(filepath.Clean(headerFile.Name()))
		hdr.mtime = headerFile.Time()
	}

	f.headers = append(f.headers, hdr)
}

// AddCaller add caller data into File.
func (f *File) AddCaller(sym, def Location, funcCall bool) {
	id := ToID(sym.usr)

	syms, ok := f.symbols[id]
	if !ok {
		syms = &Info{id: id}
	}

	syms.callers = append(syms.callers, &Caller{
		location: sym,
		funcCall: funcCall,
	})

	f.symbols[id] = syms
}

// Serialize serializes the File.
func (f *File) Serialize() *flatbuffers.Builder {
	fname := f.builder.CreateString(f.name)
	tu := f.builder.CreateByteString(f.translationUnit)

	hdrNum := len(f.headers)
	hdrOffsets := make([]flatbuffers.UOffsetT, 0, hdrNum)
	for _, hdr := range f.headers {
		hdrOffsets = append(hdrOffsets, hdr.serialize(f.builder))
	}
	symbol.FileStartHeadersVector(f.builder, hdrNum)
	for i := hdrNum - 1; i >= 0; i-- {
		f.builder.PrependUOffsetT(hdrOffsets[i])
	}
	headerVecOffset := f.builder.EndVector(hdrNum)

	symbolNum := len(f.symbols)
	symbolOffsets := make([]flatbuffers.UOffsetT, 0, symbolNum)
	for _, info := range f.symbols {
		symbolOffsets = append(symbolOffsets, info.serialize(f.builder))
	}
	symbol.FileStartSymbolsVector(f.builder, symbolNum)
	for i := symbolNum - 1; i >= 0; i-- {
		f.builder.PrependUOffsetT(symbolOffsets[i])
	}
	symbolVecOffset := f.builder.EndVector(symbolNum)

	symbol.FileStart(f.builder)
	symbol.FileAddName(f.builder, fname)
	symbol.FileAddTranslationUnit(f.builder, tu)
	symbol.FileAddSymbols(f.builder, symbolVecOffset)
	symbol.FileAddHeaders(f.builder, headerVecOffset)

	f.builder.Finish(symbol.FileEnd(f.builder))

	return f.builder
}

// ----------------------------------------------------------------------------

// Info represents a location of C/C++ cursor symbol information.
//
// table Info {
//   ID: string;
//   Decls: [Location];
//   Def: Location;
// }
type Info struct {
	id      ID
	decls   []Location
	def     Location
	callers []*Caller

	info *symbol.Info
}

// serialize serializes the Info.
func (info *Info) serialize(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
	id := builder.CreateString(info.id.String())

	declsNum := len(info.decls)
	var declVecOffset flatbuffers.UOffsetT
	if declsNum > 0 {
		declsOffsets := make([]flatbuffers.UOffsetT, 0, declsNum)
		for _, decl := range info.decls {
			declsOffsets = append(declsOffsets, decl.serialize(builder))
		}
		symbol.InfoStartDeclsVector(builder, declsNum)
		for i := declsNum - 1; i >= 0; i-- {
			builder.PrependUOffsetT(declsOffsets[i])
		}
		declVecOffset = builder.EndVector(declsNum)
	}

	defOffset := info.def.serialize(builder)

	callersNum := len(info.callers)
	var callerVecOffset flatbuffers.UOffsetT
	if callersNum > 0 {
		callersOffsets := make([]flatbuffers.UOffsetT, 0, callersNum)
		for _, caller := range info.callers {
			callersOffsets = append(callersOffsets, caller.serialize(builder))
		}
		symbol.InfoStartCallersVector(builder, callersNum)
		for i := callersNum - 1; i >= 0; i-- {
			builder.PrependUOffsetT(callersOffsets[i])
		}
		callerVecOffset = builder.EndVector(callersNum)
	}

	symbol.InfoStart(builder)
	symbol.InfoAddID(builder, id)
	symbol.InfoAddDecls(builder, declVecOffset)
	symbol.InfoAddDef(builder, defOffset)
	symbol.InfoAddCallers(builder, callerVecOffset)

	return symbol.InfoEnd(builder)
}

func (info *Info) ID() ID {
	return ToID(string(info.info.ID()))
}

func (info *Info) Decls() []Location {
	n := info.info.DeclsLength()
	decls := make([]Location, n)

	for i := 0; i < n; i++ {
		obj := new(symbol.Location)
		if info.info.Decls(obj, i) {
			decls[i] = Location{location: obj}
		}
	}

	return decls
}

func (info *Info) Def() Location {
	obj := new(symbol.Location)
	info.info.Def(obj)

	return Location{location: obj}
}

func (info *Info) Callers() []*Caller {
	n := info.info.CallersLength()
	callers := make([]*Caller, n)

	for i := 0; i < n; i++ {
		obj := new(symbol.Caller)
		if info.info.Callers(obj, i) {
			callers[i] = &Caller{caller: obj}
		}
	}

	return callers
}

// ----------------------------------------------------------------------------

// Header represents a location of include header file.
//
// table Header {
//   FileID: string (id: 0, required, key); // -> []byte
//   Mtime: long (id: 1); // time.Time.Unix(): int64
// }
type Header struct {
	fileid FileID
	mtime  time.Time

	header *symbol.Header
}

func (h *Header) FileID() FileID {
	return ToFileID(string(h.header.FileID()))
}

func (h *Header) Mtime() int64 {
	return h.header.Mtime()
}

func (h *Header) serialize(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
	fid := builder.CreateString(h.fileid.String())

	symbol.HeaderStart(builder)

	symbol.HeaderAddFileID(builder, fid)
	symbol.HeaderAddMtime(builder, h.mtime.Unix())

	return symbol.HeaderEnd(builder)
}

// ----------------------------------------------------------------------------

// Caller represents a location of caller function.
//
// table Caller {
//   Location: Location (required);
//   FuncCall: bool = false; // -> byte
// }
type Caller struct {
	location Location
	funcCall bool

	caller *symbol.Caller
}

func (c *Caller) Location() Location {
	obj := new(symbol.Location)
	c.caller.Location(obj)

	return Location{location: obj}
}

func (c *Caller) FuncCall() bool {
	return c.caller.FuncCall() != 0
}

func (c *Caller) serialize(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
	locOffset := c.location.serialize(builder)

	symbol.CallerStart(builder)

	symbol.CallerAddLocation(builder, locOffset)
	funcCall := byte(0)
	if c.funcCall {
		funcCall = byte(1)
	}
	symbol.CallerAddFuncCall(builder, funcCall)

	return symbol.CallerEnd(builder)
}

// ----------------------------------------------------------------------------

// Location location of symbol.
// TODO(zchee): method receiver is pointer for location?
//
// table Location {
//   FileName: string;
//   Line: uint;
//   Col: uint = 0;
//   Offset: uint;
//   USR: string;
// }
type Location struct {
	fileName string
	line     uint32
	col      uint32
	offset   uint32
	usr      string

	location *symbol.Location
}

func (l *Location) FileName() string {
	if l.location == nil {
		return l.fileName
	}
	return string(l.location.FileName())
}

func (l *Location) Line() uint32 {
	return l.location.Line()
}

func (l *Location) Col() uint32 {
	return l.location.Col()
}

func (l *Location) Offset() uint32 {
	return l.location.Offset()
}

func (l *Location) USR() string {
	if l.location == nil {
		return l.usr
	}
	return string(l.location.USR())
}

func (l *Location) serialize(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
	fname := builder.CreateString(l.fileName)
	usr := builder.CreateString(l.usr)

	symbol.LocationStart(builder)

	symbol.LocationAddFileName(builder, fname)
	symbol.LocationAddLine(builder, l.line)
	symbol.LocationAddCol(builder, l.col)
	symbol.LocationAddOffset(builder, l.offset)
	symbol.LocationAddUSR(builder, usr)

	return symbol.LocationEnd(builder)
}

// TODO(zchee): avoid reflection
func (l *Location) isExist() bool {
	return !reflect.DeepEqual(l, Location{})
}
<commit_msg>symbol: add godoc comments for wrapper of flatbuffers functions<commit_after>// Copyright 2016 The clang-server 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 symbol

import (
	"path/filepath"
	"reflect"
	"time"

	"github.com/go-clang/v3.9/clang"
	flatbuffers "github.com/google/flatbuffers/go"
	"github.com/zchee/clang-server/symbol/internal/symbol"
)

// ----------------------------------------------------------------------------

// File represents a C/C++ source file.
//
// table File {
//   Name: string;
//   TranslationUnit: string;
//   Symbols: [Info];
//   Headers: [Header];
//   Includes: [string];
// }
type File struct {
	name            string
	translationUnit []byte
	locations       map[Location]ID
	symbols         map[ID]*Info
	headers         []*Header

	builder *flatbuffers.Builder

	file *symbol.File
}

// NewFile return the new File.
func NewFile(name string) *File {
	return &File{
		name:      name,
		locations: make(map[Location]ID),
		symbols:   make(map[ID]*Info),
		builder:   flatbuffers.NewBuilder(0),
	}
}

// GetRootAsFile gets the root of flatbuffers binary.
func GetRootAsFile(buf []byte, offset flatbuffers.UOffsetT) *File {
	return &File{
		file: symbol.GetRootAsFile(buf, offset),
	}
}

// Name return the filename.
func (f *File) Name() string {
	return string(f.file.Name())
}

// TranslationUnit return the libclang translation unit data.
func (f *File) TranslationUnit() []byte {
	return f.file.TranslationUnit()
}

// Symbols return the C/C++ files symbols.
func (f *File) Symbols() []*Info {
	n := f.file.SymbolsLength()
	symbols := make([]*Info, n)

	for i := 0; i < n; i++ {
		obj := new(symbol.Info)
		if f.file.Symbols(obj, i) {
			symbols[i] = &Info{info: obj}
		}
	}

	return symbols
}

// Header return the C/C++ files included header files.
func (f *File) Header() []*Header {
	n := f.file.HeadersLength()
	hedears := make([]*Header, n)

	for i := 0; i < n; i++ {
		obj := new(symbol.Header)
		if f.file.Headers(obj, i) {
			hedears[i] = &Header{header: obj}
		}
	}

	return hedears
}

// AddTranslationUnit add TranslationUnit data to File.
func (f *File) AddTranslationUnit(buf []byte) {
	f.translationUnit = buf
}

// AddSymbol adds the symbol data into File.
func (f *File) addSymbol(loc, def Location) {
	id := ToID(loc.usr)

	sym, ok := f.symbols[id]
	if !ok {
		sym = &Info{id: id}
	}
	sym.decls = append(sym.decls, loc)

	if def.isExist() {
		sym.def = def
	}

	f.locations[loc] = id
	f.symbols[id] = sym
}

// AddDecl add decl data into File.
func (f *File) AddDecl(loc Location) {
	f.addSymbol(loc, Location{})
}

// AddDefinition add definition data into File.
func (f *File) AddDefinition(loc, def Location) {
	f.addSymbol(loc, def)
}

// notExistHeaderName return the not exist header name magic words.
func notExistHeaderName(headPath string) string {
	// adding magic to filename to not confuse it with real files
	return "IDoNotReallyExist-" + filepath.Base(headPath)
}

// AddHeader add header data into File.
func (f *File) AddHeader(includePath string, headerFile clang.File) {
	hdr := new(Header)
	if headerFile.Name() == "" {
		hdr.fileid = ToFileID(notExistHeaderName(filepath.Clean(headerFile.Name())))
		hdr.mtime = time.Now()
	} else {
		hdr.fileid = ToFileID(filepath.Clean(headerFile.Name()))
		hdr.mtime = headerFile.Time()
	}

	f.headers = append(f.headers, hdr)
}

// AddCaller add caller data into File.
func (f *File) AddCaller(sym, def Location, funcCall bool) {
	id := ToID(sym.usr)

	syms, ok := f.symbols[id]
	if !ok {
		syms = &Info{id: id}
	}

	syms.callers = append(syms.callers, &Caller{
		location: sym,
		funcCall: funcCall,
	})

	f.symbols[id] = syms
}

// Serialize serializes the File.
func (f *File) Serialize() *flatbuffers.Builder {
	fname := f.builder.CreateString(f.name)
	tu := f.builder.CreateByteString(f.translationUnit)

	hdrNum := len(f.headers)
	hdrOffsets := make([]flatbuffers.UOffsetT, 0, hdrNum)
	for _, hdr := range f.headers {
		hdrOffsets = append(hdrOffsets, hdr.serialize(f.builder))
	}
	symbol.FileStartHeadersVector(f.builder, hdrNum)
	for i := hdrNum - 1; i >= 0; i-- {
		f.builder.PrependUOffsetT(hdrOffsets[i])
	}
	headerVecOffset := f.builder.EndVector(hdrNum)

	symbolNum := len(f.symbols)
	symbolOffsets := make([]flatbuffers.UOffsetT, 0, symbolNum)
	for _, info := range f.symbols {
		symbolOffsets = append(symbolOffsets, info.serialize(f.builder))
	}
	symbol.FileStartSymbolsVector(f.builder, symbolNum)
	for i := symbolNum - 1; i >= 0; i-- {
		f.builder.PrependUOffsetT(symbolOffsets[i])
	}
	symbolVecOffset := f.builder.EndVector(symbolNum)

	symbol.FileStart(f.builder)
	symbol.FileAddName(f.builder, fname)
	symbol.FileAddTranslationUnit(f.builder, tu)
	symbol.FileAddSymbols(f.builder, symbolVecOffset)
	symbol.FileAddHeaders(f.builder, headerVecOffset)

	f.builder.Finish(symbol.FileEnd(f.builder))

	return f.builder
}

// ----------------------------------------------------------------------------

// Info represents a location of C/C++ cursor symbol information.
//
// table Info {
//   ID: string;
//   Decls: [Location];
//   Def: Location;
// }
type Info struct {
	id      ID
	decls   []Location
	def     Location
	callers []*Caller

	info *symbol.Info
}

// serialize serializes the Info.
func (info *Info) serialize(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
	id := builder.CreateString(info.id.String())

	declsNum := len(info.decls)
	var declVecOffset flatbuffers.UOffsetT
	if declsNum > 0 {
		declsOffsets := make([]flatbuffers.UOffsetT, 0, declsNum)
		for _, decl := range info.decls {
			declsOffsets = append(declsOffsets, decl.serialize(builder))
		}
		symbol.InfoStartDeclsVector(builder, declsNum)
		for i := declsNum - 1; i >= 0; i-- {
			builder.PrependUOffsetT(declsOffsets[i])
		}
		declVecOffset = builder.EndVector(declsNum)
	}

	defOffset := info.def.serialize(builder)

	callersNum := len(info.callers)
	var callerVecOffset flatbuffers.UOffsetT
	if callersNum > 0 {
		callersOffsets := make([]flatbuffers.UOffsetT, 0, callersNum)
		for _, caller := range info.callers {
			callersOffsets = append(callersOffsets, caller.serialize(builder))
		}
		symbol.InfoStartCallersVector(builder, callersNum)
		for i := callersNum - 1; i >= 0; i-- {
			builder.PrependUOffsetT(callersOffsets[i])
		}
		callerVecOffset = builder.EndVector(callersNum)
	}

	symbol.InfoStart(builder)
	symbol.InfoAddID(builder, id)
	symbol.InfoAddDecls(builder, declVecOffset)
	symbol.InfoAddDef(builder, defOffset)
	symbol.InfoAddCallers(builder, callerVecOffset)

	return symbol.InfoEnd(builder)
}

// ID return the symbol ID which hashed blake2b.
func (info *Info) ID() ID {
	return ToID(string(info.info.ID()))
}

// Decls return the symbol declarations information.
func (info *Info) Decls() []Location {
	n := info.info.DeclsLength()
	decls := make([]Location, n)

	for i := 0; i < n; i++ {
		obj := new(symbol.Location)
		if info.info.Decls(obj, i) {
			decls[i] = Location{location: obj}
		}
	}

	return decls
}

// Def return the symbol definition information.
func (info *Info) Def() Location {
	obj := new(symbol.Location)
	info.info.Def(obj)

	return Location{location: obj}
}

// Callers return the symbol callers information.
func (info *Info) Callers() []*Caller {
	n := info.info.CallersLength()
	callers := make([]*Caller, n)

	for i := 0; i < n; i++ {
		obj := new(symbol.Caller)
		if info.info.Callers(obj, i) {
			callers[i] = &Caller{caller: obj}
		}
	}

	return callers
}

// ----------------------------------------------------------------------------

// Header represents a location of include header file.
//
// table Header {
//   FileID: string (id: 0, required, key); // -> []byte
//   Mtime: long (id: 1); // time.Time.Unix(): int64
// }
type Header struct {
	fileid FileID
	mtime  time.Time

	header *symbol.Header
}

// FileID return the header FileID.
func (h *Header) FileID() FileID {
	return ToFileID(string(h.header.FileID()))
}

// Mtime return the header modified time.
func (h *Header) Mtime() int64 {
	return h.header.Mtime()
}

// serialize serializes the h data to flatbuffers.UOffsetT.
func (h *Header) serialize(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
	fid := builder.CreateString(h.fileid.String())

	symbol.HeaderStart(builder)

	symbol.HeaderAddFileID(builder, fid)
	symbol.HeaderAddMtime(builder, h.mtime.Unix())

	return symbol.HeaderEnd(builder)
}

// ----------------------------------------------------------------------------

// Caller represents a location of caller function.
//
// table Caller {
//   Location: Location (required);
//   FuncCall: bool = false; // -> byte
// }
type Caller struct {
	location Location
	funcCall bool

	caller *symbol.Caller
}

// Location return the location of caller function.
func (c *Caller) Location() Location {
	obj := new(symbol.Location)
	c.caller.Location(obj)

	return Location{location: obj}
}

// FuncCall reports whether caller is function call.
func (c *Caller) FuncCall() bool {
	return c.caller.FuncCall() != 0
}

// serialize serializes the c data to flatbuffers.UOffsetT.
func (c *Caller) serialize(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
	locOffset := c.location.serialize(builder)

	symbol.CallerStart(builder)

	symbol.CallerAddLocation(builder, locOffset)
	funcCall := byte(0)
	if c.funcCall {
		funcCall = byte(1)
	}
	symbol.CallerAddFuncCall(builder, funcCall)

	return symbol.CallerEnd(builder)
}

// ----------------------------------------------------------------------------

// Location location of symbol.
// TODO(zchee): method receiver is pointer for location?
//
// table Location {
//   FileName: string;
//   Line: uint;
//   Col: uint = 0;
//   Offset: uint;
//   USR: string;
// }
type Location struct {
	fileName string
	line     uint32
	col      uint32
	offset   uint32
	usr      string

	location *symbol.Location
}

// FileName return the filename of location.
func (l *Location) FileName() string {
	if l.location == nil {
		return l.fileName
	}
	return string(l.location.FileName())
}

// Line return the line number of symbol location.
func (l *Location) Line() uint32 {
	return l.location.Line()
}

// Col return the column number of symbol location.
func (l *Location) Col() uint32 {
	return l.location.Col()
}

// Offset return the byte offset of symbol location.
func (l *Location) Offset() uint32 {
	return l.location.Offset()
}

// USR return the Unified Symbol Resolution of symbol.
func (l *Location) USR() string {
	if l.location == nil {
		return l.usr
	}
	return string(l.location.USR())
}

// serialize serializes the l data to flatbuffers.UOffsetT.
func (l *Location) serialize(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
	fname := builder.CreateString(l.fileName)
	usr := builder.CreateString(l.usr)

	symbol.LocationStart(builder)

	symbol.LocationAddFileName(builder, fname)
	symbol.LocationAddLine(builder, l.line)
	symbol.LocationAddCol(builder, l.col)
	symbol.LocationAddOffset(builder, l.offset)
	symbol.LocationAddUSR(builder, usr)

	return symbol.LocationEnd(builder)
}

// TODO(zchee): avoid reflection
func (l *Location) isExist() bool {
	return !reflect.DeepEqual(l, Location{})
}
<|endoftext|>


<commit_before>package cli

import (
	"bytes"
	"flag"
	"fmt"
	"os"
	"strings"
	"text/tabwriter"
)

/*
Cmd represents a command (or sub command) in a CLI application. It should be constructed
by calling Command() on an app to create a top level command or by calling Command() on another
command to create a sub command
*/
type Cmd struct {
	// The code to execute when this command is matched
	Action func()
	// The command options and arguments
	Spec string
	// The command error handling strategy
	ErrorHandling flag.ErrorHandling

	init CmdInitializer
	name string
	desc string

	commands   []*Cmd
	options    []*opt
	optionsIdx map[string]*opt
	args       []*arg
	argsIdx    map[string]*arg

	parents []string

	fsm *state
}

/*
BoolParam represents a Bool option or argument
*/
type BoolParam interface{}

/*
StringParam represents a String option or argument
*/
type StringParam interface{}

/*
IntParam represents an Int option or argument
*/
type IntParam interface{}

/*
StringsParam represents a string slice option or argument
*/
type StringsParam interface{}

/*
IntsParam represents an int slice option or argument
*/
type IntsParam interface{}

/*
CmdInitializer is a function that configures a command by adding options, arguments, a spec, sub commands and the code
to execute when the command is called
*/
type CmdInitializer func(*Cmd)

/*
Command adds a new (sub) command to c where name is the command name (what you type in the console),
description is what would be shown in the help messages, e.g.:

	Usage: git [OPTIONS] COMMAND [arg...]

	Commands:
	  $name	$desc

the last argument, init, is a function that will be called by mow.cli to further configure the created
(sub) command, e.g. to add options, arguments and the code to execute
*/
func (c *Cmd) Command(name, desc string, init CmdInitializer) {
	c.commands = append(c.commands, &Cmd{
		ErrorHandling: c.ErrorHandling,
		name:          name,
		desc:          desc,
		init:          init,
		commands:      []*Cmd{},
		options:       []*opt{},
		optionsIdx:    map[string]*opt{},
		args:          []*arg{},
		argsIdx:       map[string]*arg{},
	})
}

/*
Bool can be used to add a bool option or argument to a command.
It accepts either a BoolOpt or a BoolArg struct.

The result should be stored in a variable (a pointer to a bool) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) Bool(p BoolParam) *bool {
	switch x := p.(type) {
	case BoolOpt:
		return c.mkOpt(opt{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue}, x.Value).(*bool)
	case BoolArg:
		return c.mkArg(arg{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue}, x.Value).(*bool)
	default:
		panic(fmt.Sprintf("Unhandled param %v", p))
	}
}

/*
String can be used to add a string option or argument to a command.
It accepts either a StringOpt or a StringArg struct.

The result should be stored in a variable (a pointer to a string) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) String(p StringParam) *string {
	switch x := p.(type) {
	case StringOpt:
		return c.mkOpt(opt{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue}, x.Value).(*string)
	case StringArg:
		return c.mkArg(arg{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue}, x.Value).(*string)
	default:
		panic(fmt.Sprintf("Unhandled param %v", p))
	}
}

/*
Int can be used to add an int option or argument to a command.
It accepts either a IntOpt or a IntArg struct.

The result should be stored in a variable (a pointer to an int) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) Int(p IntParam) *int {
	switch x := p.(type) {
	case IntOpt:
		return c.mkOpt(opt{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue}, x.Value).(*int)
	case IntArg:
		return c.mkArg(arg{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue}, x.Value).(*int)
	default:
		panic(fmt.Sprintf("Unhandled param %v", p))
	}
}

/*
Strings can be used to add a string slice option or argument to a command.
It accepts either a StringsOpt or a StringsArg struct.

The result should be stored in a variable (a pointer to a string slice) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) Strings(p StringsParam) *[]string {
	switch x := p.(type) {
	case StringsOpt:
		return c.mkOpt(opt{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue}, x.Value).(*[]string)
	case StringsArg:
		return c.mkArg(arg{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue}, x.Value).(*[]string)
	default:
		panic(fmt.Sprintf("Unhandled param %v", p))
	}
}

/*
Ints can be used to add an int slice option or argument to a command.
It accepts either a IntsOpt or a IntsArg struct.

The result should be stored in a variable (a pointer to an int slice) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) Ints(p IntsParam) *[]int {
	switch x := p.(type) {
	case IntsOpt:
		return c.mkOpt(opt{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue}, x.Value).(*[]int)
	case IntsArg:
		return c.mkArg(arg{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue}, x.Value).(*[]int)
	default:
		panic(fmt.Sprintf("Unhandled param %v", p))
	}
}

func (c *Cmd) doInit() error {
	if c.init != nil {
		c.init(c)
	}

	parents := append(c.parents, c.name)

	for _, sub := range c.commands {
		sub.parents = parents
	}

	if len(c.Spec) == 0 {
		if len(c.options) > 0 {
			c.Spec = "[OPTIONS] "
		}
		for _, arg := range c.args {
			c.Spec += arg.name + " "
		}
	}
	fsm, err := uParse(c)
	if err != nil {
		return err
	}
	c.fsm = fsm
	return nil
}

func (c *Cmd) onError(err error) {
	if err != nil {
		switch c.ErrorHandling {
		case flag.ExitOnError:
			os.Exit(2)
		case flag.PanicOnError:
			panic(err)
		}
	} else {
		if c.ErrorHandling == flag.ExitOnError {
			os.Exit(2)
		}
	}
}

/*
PrintHelp prints the command's help message.
In most cases the library users won't need to call this method, unless
a more complex validation is needed
*/
func (c *Cmd) PrintHelp() {
	out := os.Stderr

	full := append(c.parents, c.name)
	sub := ""
	if len(c.commands) > 0 {
		sub = "COMMAND [arg...]"
	}
	path := strings.Join(full, " ")
	fmt.Fprintf(out, "\nUsage: %s %s %s\n\n", path, c.Spec, sub)
	if len(c.desc) > 0 {
		fmt.Fprintf(out, "%s\n", c.desc)
	}

	w := tabwriter.NewWriter(out, 15, 1, 3, ' ', 0)

	if len(c.args) > 0 {
		fmt.Fprintf(out, "\nArguments:\n")

		for _, arg := range c.args {
			desc := c.formatDescription(arg.desc, arg.envVar)
			value := c.formatArgValue(arg)

			fmt.Fprintf(w, "  %s%s\t%s\n", arg.name, value, desc)
		}
		w.Flush()
	}

	if len(c.options) > 0 {
		fmt.Fprintf(out, "\nOptions:\n")

		for _, opt := range c.options {
			desc := c.formatDescription(opt.desc, opt.envVar)
			value := c.formatOptValue(opt)
			fmt.Fprintf(w, "  %s%s\t%s\n", strings.Join(opt.names, ", "), value, desc)
		}
		w.Flush()
	}

	if len(c.commands) > 0 {
		fmt.Fprintf(out, "\nCommands:\n")

		for _, c := range c.commands {
			fmt.Fprintf(w, "  %s\t%s\n", c.name, c.desc)
		}
		w.Flush()
	}

	if len(c.commands) > 0 {
		fmt.Fprintf(out, "\nRun '%s COMMAND --help' for more information on a command.\n", path)
	}
}

func (c *Cmd) formatArgValue(arg *arg) string {
	var value string
	if arg.hideValue {
		value = " "
	} else {
		value = fmt.Sprintf("=%#v", arg.get())
	}
	return value
}

func (c *Cmd) formatOptValue(opt *opt) string {
	var value string
	if opt.hideValue {
		value = " "
	} else {
		value = fmt.Sprintf("=%#v", opt.get())
	}
	return value
}

func (c *Cmd) formatDescription(desc, envVar string) string {
	var b bytes.Buffer
	b.WriteString(desc)
	if len(envVar) > 0 {
		b.WriteString(" (")
		sep := ""
		for _, envVal := range strings.Split(envVar, " ") {
			b.WriteString(fmt.Sprintf("%s$%s", sep, envVal))
			sep = " "
		}
		b.WriteString(")")
	}
	return strings.TrimSpace(b.String())
}

func (c *Cmd) parse(args []string) error {
	if c.helpRequested(args) {
		c.PrintHelp()
		c.onError(nil)
		return nil
	}

	nargs, nargsLen, err := c.normalize(args)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
		c.PrintHelp()
		c.onError(err)
		return err
	}

	if err := c.fsm.parse(nargs); err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
		c.PrintHelp()
		c.onError(err)
		return err
	}

	args = args[nargsLen:]
	if len(args) == 0 {
		if c.Action != nil {
			c.Action()
			return nil
		}
		c.PrintHelp()
		c.onError(nil)
		return nil
	}

	arg := args[0]
	for _, sub := range c.commands {
		if arg == sub.name {
			if err := sub.doInit(); err != nil {
				panic(err)
			}
			return sub.parse(args[1:])
		}
	}

	switch {
	case strings.HasPrefix(arg, "-"):
		fmt.Fprintf(os.Stderr, "Error: illegal option %s\n", arg)
	default:
		fmt.Fprintf(os.Stderr, "Error: illegal input %s\n", arg)
	}
	c.PrintHelp()
	c.onError(err)
	return err

}

func (c *Cmd) helpRequested(args []string) bool {
	for _, arg := range args {
		for _, sub := range c.commands {
			if arg == sub.name {
				return false
			}
		}
		if arg == "-h" || arg == "--help" {
			return true
		}
	}
	return false
}

func (c *Cmd) normalize(args []string) (res []string, consumed int, err error) {
	err = nil
	res = []string{}
	consumed = 0
	afterOptionsEnd := false
	for _, arg := range args {
		for _, sub := range c.commands {
			if arg == sub.name {
				return
			}
		}
		switch {
		case arg == "-":
			res = append(res, arg)
		case !afterOptionsEnd && arg == "--":
			res = append(res, arg)
			afterOptionsEnd = true
		case !afterOptionsEnd && strings.HasPrefix(arg, "--"):
			var parts []string
			parts, err = c.normalizeLongOpt(arg)
			if err != nil {
				return
			}
			res = append(res, parts...)

		case !afterOptionsEnd && strings.HasPrefix(arg, "-"):
			var parts []string
			parts, err = c.normalizeShortOpt(arg)
			if err != nil {
				return
			}
			res = append(res, parts...)
		default:
			res = append(res, arg)
		}
		consumed++
	}
	return
}

func (c *Cmd) normalizeLongOpt(arg string) ([]string, error) {
	res := []string{}
	kv := strings.Split(arg, "=")
	name := kv[0]

	opt, declared := c.optionsIdx[name]
	if !declared {
		return nil, fmt.Errorf("Illegal option %s", name)
	}

	if len(kv) == 2 {
		res = append(res, name, kv[1])
	} else {
		res = append(res, name)
		if opt.isBool() {
			res = append(res, "true")
		}
	}

	return res, nil
}

func (c *Cmd) normalizeShortOpt(arg string) ([]string, error) {
	res := []string{}
	if len(arg) > 1 {
		name := arg[0:2]
		opt, declared := c.optionsIdx[name]
		if !declared {
			return nil, fmt.Errorf("Illegal option %s", name)
		}
		switch {
		case opt.isBool():
			res = append(res, name)
			if len(arg) == 2 {
				res = append(res, "true")
				return res, nil
			}
			rem := arg[2:]
			if strings.HasPrefix(rem, "=") {
				res = append(res, rem[1:])
				return res, nil
			}
			res = append(res, "true")
			parts, err := c.normalizeShortOpt("-" + rem)
			if err != nil {
				return nil, err
			}
			res = append(res, parts...)
			return res, nil
		default:
			res = append(res, name)
			if len(arg) > 2 {
				val := arg[2:]
				if strings.HasPrefix(val, "=") {
					val = arg[3:]
				}
				res = append(res, val)
			}
		}
	}
	return res, nil
}
<commit_msg>Trim the spec strings before printing them in the help messages<commit_after>package cli

import (
	"bytes"
	"flag"
	"fmt"
	"os"
	"strings"
	"text/tabwriter"
)

/*
Cmd represents a command (or sub command) in a CLI application. It should be constructed
by calling Command() on an app to create a top level command or by calling Command() on another
command to create a sub command
*/
type Cmd struct {
	// The code to execute when this command is matched
	Action func()
	// The command options and arguments
	Spec string
	// The command error handling strategy
	ErrorHandling flag.ErrorHandling

	init CmdInitializer
	name string
	desc string

	commands   []*Cmd
	options    []*opt
	optionsIdx map[string]*opt
	args       []*arg
	argsIdx    map[string]*arg

	parents []string

	fsm *state
}

/*
BoolParam represents a Bool option or argument
*/
type BoolParam interface{}

/*
StringParam represents a String option or argument
*/
type StringParam interface{}

/*
IntParam represents an Int option or argument
*/
type IntParam interface{}

/*
StringsParam represents a string slice option or argument
*/
type StringsParam interface{}

/*
IntsParam represents an int slice option or argument
*/
type IntsParam interface{}

/*
CmdInitializer is a function that configures a command by adding options, arguments, a spec, sub commands and the code
to execute when the command is called
*/
type CmdInitializer func(*Cmd)

/*
Command adds a new (sub) command to c where name is the command name (what you type in the console),
description is what would be shown in the help messages, e.g.:

	Usage: git [OPTIONS] COMMAND [arg...]

	Commands:
	  $name	$desc

the last argument, init, is a function that will be called by mow.cli to further configure the created
(sub) command, e.g. to add options, arguments and the code to execute
*/
func (c *Cmd) Command(name, desc string, init CmdInitializer) {
	c.commands = append(c.commands, &Cmd{
		ErrorHandling: c.ErrorHandling,
		name:          name,
		desc:          desc,
		init:          init,
		commands:      []*Cmd{},
		options:       []*opt{},
		optionsIdx:    map[string]*opt{},
		args:          []*arg{},
		argsIdx:       map[string]*arg{},
	})
}

/*
Bool can be used to add a bool option or argument to a command.
It accepts either a BoolOpt or a BoolArg struct.

The result should be stored in a variable (a pointer to a bool) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) Bool(p BoolParam) *bool {
	switch x := p.(type) {
	case BoolOpt:
		return c.mkOpt(opt{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue}, x.Value).(*bool)
	case BoolArg:
		return c.mkArg(arg{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue}, x.Value).(*bool)
	default:
		panic(fmt.Sprintf("Unhandled param %v", p))
	}
}

/*
String can be used to add a string option or argument to a command.
It accepts either a StringOpt or a StringArg struct.

The result should be stored in a variable (a pointer to a string) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) String(p StringParam) *string {
	switch x := p.(type) {
	case StringOpt:
		return c.mkOpt(opt{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue}, x.Value).(*string)
	case StringArg:
		return c.mkArg(arg{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue}, x.Value).(*string)
	default:
		panic(fmt.Sprintf("Unhandled param %v", p))
	}
}

/*
Int can be used to add an int option or argument to a command.
It accepts either a IntOpt or a IntArg struct.

The result should be stored in a variable (a pointer to an int) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) Int(p IntParam) *int {
	switch x := p.(type) {
	case IntOpt:
		return c.mkOpt(opt{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue}, x.Value).(*int)
	case IntArg:
		return c.mkArg(arg{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue}, x.Value).(*int)
	default:
		panic(fmt.Sprintf("Unhandled param %v", p))
	}
}

/*
Strings can be used to add a string slice option or argument to a command.
It accepts either a StringsOpt or a StringsArg struct.

The result should be stored in a variable (a pointer to a string slice) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) Strings(p StringsParam) *[]string {
	switch x := p.(type) {
	case StringsOpt:
		return c.mkOpt(opt{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue}, x.Value).(*[]string)
	case StringsArg:
		return c.mkArg(arg{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue}, x.Value).(*[]string)
	default:
		panic(fmt.Sprintf("Unhandled param %v", p))
	}
}

/*
Ints can be used to add an int slice option or argument to a command.
It accepts either a IntsOpt or a IntsArg struct.

The result should be stored in a variable (a pointer to an int slice) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) Ints(p IntsParam) *[]int {
	switch x := p.(type) {
	case IntsOpt:
		return c.mkOpt(opt{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue}, x.Value).(*[]int)
	case IntsArg:
		return c.mkArg(arg{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue}, x.Value).(*[]int)
	default:
		panic(fmt.Sprintf("Unhandled param %v", p))
	}
}

func (c *Cmd) doInit() error {
	if c.init != nil {
		c.init(c)
	}

	parents := append(c.parents, c.name)

	for _, sub := range c.commands {
		sub.parents = parents
	}

	if len(c.Spec) == 0 {
		if len(c.options) > 0 {
			c.Spec = "[OPTIONS] "
		}
		for _, arg := range c.args {
			c.Spec += arg.name + " "
		}
	}
	fsm, err := uParse(c)
	if err != nil {
		return err
	}
	c.fsm = fsm
	return nil
}

func (c *Cmd) onError(err error) {
	if err != nil {
		switch c.ErrorHandling {
		case flag.ExitOnError:
			os.Exit(2)
		case flag.PanicOnError:
			panic(err)
		}
	} else {
		if c.ErrorHandling == flag.ExitOnError {
			os.Exit(2)
		}
	}
}

/*
PrintHelp prints the command's help message.
In most cases the library users won't need to call this method, unless
a more complex validation is needed
*/
func (c *Cmd) PrintHelp() {
	out := os.Stderr

	full := append(c.parents, c.name)
	sub := ""
	if len(c.commands) > 0 {
		sub = "COMMAND [arg...]"
	}
	path := strings.Join(full, " ")
	fmt.Fprintf(out, "\nUsage: %s %s %s\n\n", path, strings.TrimSpace(c.Spec), sub)
	if len(c.desc) > 0 {
		fmt.Fprintf(out, "%s\n", c.desc)
	}

	w := tabwriter.NewWriter(out, 15, 1, 3, ' ', 0)

	if len(c.args) > 0 {
		fmt.Fprintf(out, "\nArguments:\n")

		for _, arg := range c.args {
			desc := c.formatDescription(arg.desc, arg.envVar)
			value := c.formatArgValue(arg)

			fmt.Fprintf(w, "  %s%s\t%s\n", arg.name, value, desc)
		}
		w.Flush()
	}

	if len(c.options) > 0 {
		fmt.Fprintf(out, "\nOptions:\n")

		for _, opt := range c.options {
			desc := c.formatDescription(opt.desc, opt.envVar)
			value := c.formatOptValue(opt)
			fmt.Fprintf(w, "  %s%s\t%s\n", strings.Join(opt.names, ", "), value, desc)
		}
		w.Flush()
	}

	if len(c.commands) > 0 {
		fmt.Fprintf(out, "\nCommands:\n")

		for _, c := range c.commands {
			fmt.Fprintf(w, "  %s\t%s\n", c.name, c.desc)
		}
		w.Flush()
	}

	if len(c.commands) > 0 {
		fmt.Fprintf(out, "\nRun '%s COMMAND --help' for more information on a command.\n", path)
	}
}

func (c *Cmd) formatArgValue(arg *arg) string {
	var value string
	if arg.hideValue {
		value = " "
	} else {
		value = fmt.Sprintf("=%#v", arg.get())
	}
	return value
}

func (c *Cmd) formatOptValue(opt *opt) string {
	var value string
	if opt.hideValue {
		value = " "
	} else {
		value = fmt.Sprintf("=%#v", opt.get())
	}
	return value
}

func (c *Cmd) formatDescription(desc, envVar string) string {
	var b bytes.Buffer
	b.WriteString(desc)
	if len(envVar) > 0 {
		b.WriteString(" (")
		sep := ""
		for _, envVal := range strings.Split(envVar, " ") {
			b.WriteString(fmt.Sprintf("%s$%s", sep, envVal))
			sep = " "
		}
		b.WriteString(")")
	}
	return strings.TrimSpace(b.String())
}

func (c *Cmd) parse(args []string) error {
	if c.helpRequested(args) {
		c.PrintHelp()
		c.onError(nil)
		return nil
	}

	nargs, nargsLen, err := c.normalize(args)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
		c.PrintHelp()
		c.onError(err)
		return err
	}

	if err := c.fsm.parse(nargs); err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
		c.PrintHelp()
		c.onError(err)
		return err
	}

	args = args[nargsLen:]
	if len(args) == 0 {
		if c.Action != nil {
			c.Action()
			return nil
		}
		c.PrintHelp()
		c.onError(nil)
		return nil
	}

	arg := args[0]
	for _, sub := range c.commands {
		if arg == sub.name {
			if err := sub.doInit(); err != nil {
				panic(err)
			}
			return sub.parse(args[1:])
		}
	}

	switch {
	case strings.HasPrefix(arg, "-"):
		fmt.Fprintf(os.Stderr, "Error: illegal option %s\n", arg)
	default:
		fmt.Fprintf(os.Stderr, "Error: illegal input %s\n", arg)
	}
	c.PrintHelp()
	c.onError(err)
	return err

}

func (c *Cmd) helpRequested(args []string) bool {
	for _, arg := range args {
		for _, sub := range c.commands {
			if arg == sub.name {
				return false
			}
		}
		if arg == "-h" || arg == "--help" {
			return true
		}
	}
	return false
}

func (c *Cmd) normalize(args []string) (res []string, consumed int, err error) {
	err = nil
	res = []string{}
	consumed = 0
	afterOptionsEnd := false
	for _, arg := range args {
		for _, sub := range c.commands {
			if arg == sub.name {
				return
			}
		}
		switch {
		case arg == "-":
			res = append(res, arg)
		case !afterOptionsEnd && arg == "--":
			res = append(res, arg)
			afterOptionsEnd = true
		case !afterOptionsEnd && strings.HasPrefix(arg, "--"):
			var parts []string
			parts, err = c.normalizeLongOpt(arg)
			if err != nil {
				return
			}
			res = append(res, parts...)

		case !afterOptionsEnd && strings.HasPrefix(arg, "-"):
			var parts []string
			parts, err = c.normalizeShortOpt(arg)
			if err != nil {
				return
			}
			res = append(res, parts...)
		default:
			res = append(res, arg)
		}
		consumed++
	}
	return
}

func (c *Cmd) normalizeLongOpt(arg string) ([]string, error) {
	res := []string{}
	kv := strings.Split(arg, "=")
	name := kv[0]

	opt, declared := c.optionsIdx[name]
	if !declared {
		return nil, fmt.Errorf("Illegal option %s", name)
	}

	if len(kv) == 2 {
		res = append(res, name, kv[1])
	} else {
		res = append(res, name)
		if opt.isBool() {
			res = append(res, "true")
		}
	}

	return res, nil
}

func (c *Cmd) normalizeShortOpt(arg string) ([]string, error) {
	res := []string{}
	if len(arg) > 1 {
		name := arg[0:2]
		opt, declared := c.optionsIdx[name]
		if !declared {
			return nil, fmt.Errorf("Illegal option %s", name)
		}
		switch {
		case opt.isBool():
			res = append(res, name)
			if len(arg) == 2 {
				res = append(res, "true")
				return res, nil
			}
			rem := arg[2:]
			if strings.HasPrefix(rem, "=") {
				res = append(res, rem[1:])
				return res, nil
			}
			res = append(res, "true")
			parts, err := c.normalizeShortOpt("-" + rem)
			if err != nil {
				return nil, err
			}
			res = append(res, parts...)
			return res, nil
		default:
			res = append(res, name)
			if len(arg) > 2 {
				val := arg[2:]
				if strings.HasPrefix(val, "=") {
					val = arg[3:]
				}
				res = append(res, val)
			}
		}
	}
	return res, nil
}
<|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 sync

import "sync/atomic"

// A WaitGroup waits for a collection of goroutines to finish.
// The main goroutine calls Add to set the number of
// goroutines to wait for.  Then each of the goroutines
// runs and calls Done when finished.  At the same time,
// Wait can be used to block until all goroutines have finished.
//
// For example:
//
//   for i := 0; i < n; i++ {
//       if !condition(i) {
//           continue
//       }
//       wg.Add(1)
//       go func() {
//           // Do something.
//           wg.Done()
//       }()
//   }
//   wg.Wait()
//
type WaitGroup struct {
	m       Mutex
	counter int32
	waiters int32
	sema    *uint32
}

// WaitGroup creates a new semaphore each time the old semaphore
// is released. This is to avoid the following race:
//
// G1: Add(1)
// G1: go G2()
// G1: Wait() // Context switch after Unlock() and before Semacquire().
// G2: Done() // Release semaphore: sema == 1, waiters == 0. G1 doesn't run yet.
// G3: Wait() // Finds counter == 0, waiters == 0, doesn't block.
// G3: Add(1) // Makes counter == 1, waiters == 0.
// G3: go G4()
// G3: Wait() // G1 still hasn't run, G3 finds sema == 1, unblocked! Bug.

// Add adds delta, which may be negative, to the WaitGroup counter.
// If the counter becomes zero, all goroutines blocked on Wait() are released.
func (wg *WaitGroup) Add(delta int) {
	v := atomic.AddInt32(&wg.counter, int32(delta))
	if v < 0 {
		panic("sync: negative WaitGroup count")
	}
	if v > 0 || atomic.LoadInt32(&wg.waiters) == 0 {
		return
	}
	wg.m.Lock()
	for i := int32(0); i < wg.waiters; i++ {
		runtime_Semrelease(wg.sema)
	}
	wg.waiters = 0
	wg.sema = nil
	wg.m.Unlock()
}

// Done decrements the WaitGroup counter.
func (wg *WaitGroup) Done() {
	wg.Add(-1)
}

// Wait blocks until the WaitGroup counter is zero.
func (wg *WaitGroup) Wait() {
	if atomic.LoadInt32(&wg.counter) == 0 {
		return
	}
	wg.m.Lock()
	atomic.AddInt32(&wg.waiters, 1)
	// This code is racing with the unlocked path in Add above.
	// The code above modifies counter and then reads waiters.
	// We must modify waiters and then read counter (the opposite order)
	// to avoid missing an Add.
	if atomic.LoadInt32(&wg.counter) == 0 {
		atomic.AddInt32(&wg.waiters, -1)
		wg.m.Unlock()
		return
	}
	if wg.sema == nil {
		wg.sema = new(uint32)
	}
	s := wg.sema
	wg.m.Unlock()
	runtime_Semacquire(s)
}
<commit_msg>sync: remove old WaitGroup example The docs look awkward - there is a paragraph "For example:" with a plain text example, and straight below it a real Example.<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 sync

import "sync/atomic"

// A WaitGroup waits for a collection of goroutines to finish.
// The main goroutine calls Add to set the number of
// goroutines to wait for.  Then each of the goroutines
// runs and calls Done when finished.  At the same time,
// Wait can be used to block until all goroutines have finished.
type WaitGroup struct {
	m       Mutex
	counter int32
	waiters int32
	sema    *uint32
}

// WaitGroup creates a new semaphore each time the old semaphore
// is released. This is to avoid the following race:
//
// G1: Add(1)
// G1: go G2()
// G1: Wait() // Context switch after Unlock() and before Semacquire().
// G2: Done() // Release semaphore: sema == 1, waiters == 0. G1 doesn't run yet.
// G3: Wait() // Finds counter == 0, waiters == 0, doesn't block.
// G3: Add(1) // Makes counter == 1, waiters == 0.
// G3: go G4()
// G3: Wait() // G1 still hasn't run, G3 finds sema == 1, unblocked! Bug.

// Add adds delta, which may be negative, to the WaitGroup counter.
// If the counter becomes zero, all goroutines blocked on Wait() are released.
func (wg *WaitGroup) Add(delta int) {
	v := atomic.AddInt32(&wg.counter, int32(delta))
	if v < 0 {
		panic("sync: negative WaitGroup count")
	}
	if v > 0 || atomic.LoadInt32(&wg.waiters) == 0 {
		return
	}
	wg.m.Lock()
	for i := int32(0); i < wg.waiters; i++ {
		runtime_Semrelease(wg.sema)
	}
	wg.waiters = 0
	wg.sema = nil
	wg.m.Unlock()
}

// Done decrements the WaitGroup counter.
func (wg *WaitGroup) Done() {
	wg.Add(-1)
}

// Wait blocks until the WaitGroup counter is zero.
func (wg *WaitGroup) Wait() {
	if atomic.LoadInt32(&wg.counter) == 0 {
		return
	}
	wg.m.Lock()
	atomic.AddInt32(&wg.waiters, 1)
	// This code is racing with the unlocked path in Add above.
	// The code above modifies counter and then reads waiters.
	// We must modify waiters and then read counter (the opposite order)
	// to avoid missing an Add.
	if atomic.LoadInt32(&wg.counter) == 0 {
		atomic.AddInt32(&wg.waiters, -1)
		wg.m.Unlock()
		return
	}
	if wg.sema == nil {
		wg.sema = new(uint32)
	}
	s := wg.sema
	wg.m.Unlock()
	runtime_Semacquire(s)
}
<|endoftext|>