<commit_before>package cmd

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

	"github.com/mitchellh/go-homedir"
	"github.com/pkg/errors"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"github.com/vektra/mockery/v2/pkg"
	"github.com/vektra/mockery/v2/pkg/config"
	"github.com/vektra/mockery/v2/pkg/logging"
	"golang.org/x/crypto/ssh/terminal"
	"golang.org/x/tools/go/packages"
)

var (
	cfgFile = ""
)

func init() {
	cobra.OnInitialize(initConfig)
}

func NewRootCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "mockery",
		Short: "Generate mock objects for your Golang interfaces",
		RunE: func(cmd *cobra.Command, args []string) error {
			r, err := GetRootAppFromViper(viper.GetViper())
			if err != nil {
				printStackTrace(err)
				return err
			}
			return r.Run()
		},
	}

	pFlags := cmd.PersistentFlags()
	pFlags.StringVar(&cfgFile, "config", "", "config file to use")
	pFlags.String("name", "", "name or matching regular expression of interface to generate mock for")
	pFlags.Bool("print", false, "print the generated mock to stdout")
	pFlags.String("output", "./mocks", "directory to write mocks to")
	pFlags.String("outpkg", "mocks", "name of generated package")
	pFlags.String("packageprefix", "", "prefix for the generated package name, it is ignored if outpkg is also specified.")
	pFlags.String("dir", ".", "directory to search for interfaces")
	pFlags.BoolP("recursive", "r", false, "recurse search into sub-directories")
	pFlags.Bool("all", false, "generates mocks for all found interfaces in all sub-directories")
	pFlags.Bool("inpackage", false, "generate a mock that goes inside the original package")
	pFlags.Bool("testonly", false, "generate a mock in a _test.go file")
	pFlags.String("case", "camel", "name the mocked file using casing convention [camel, snake, underscore]")
	pFlags.String("note", "", "comment to insert into prologue of each generated file")
	pFlags.String("cpuprofile", "", "write cpu profile to file")
	pFlags.Bool("version", false, "prints the installed version of mockery")
	pFlags.Bool("quiet", false, `suppresses logger output (equivalent to --log-level="")`)
	pFlags.Bool("keeptree", false, "keep the tree structure of the original interface files into a different repository. Must be used with XX")
	pFlags.String("tags", "", "space-separated list of additional build tags to use")
	pFlags.String("filename", "", "name of generated file (only works with -name and no regex)")
	pFlags.String("structname", "", "name of generated struct (only works with -name and no regex)")
	pFlags.String("log-level", "info", "Level of logging")
	pFlags.String("srcpkg", "", "source pkg to search for interfaces")
	pFlags.BoolP("dry-run", "d", false, "Do a dry run, don't modify any files")
	pFlags.Bool("disable-version-string", false, "Do not insert the version string into the generated mock file.")
	pFlags.String("boilerplate-file", "", "File to read a boilerplate text from. Text should be a go block comment, i.e. /* ... */")
	pFlags.Bool("unroll-variadic", true, "For functions with variadic arguments, do not unroll the arguments into the underlying testify call. Instead, pass variadic slice as-is.")
	pFlags.Bool("exported", false, "Generates public mocks for private interfaces.")
	pFlags.Bool("with-expecter", false, "Generate expecter utility around mock's On, Run and Return methods with explicit types. This option is NOT compatible with -unroll-variadic=false")

	viper.BindPFlags(pFlags)

	cmd.AddCommand(NewShowConfigCmd())
	return cmd
}

type stackTracer interface {
	StackTrace() errors.StackTrace
}

func printStackTrace(e error) {
	fmt.Printf("%v\n", e)
	if err, ok := e.(stackTracer); ok {
		for _, f := range err.StackTrace() {
			fmt.Printf("%+s:%d\n", f, f)
		}
	}

}

// Execute executes the cobra CLI workflow
func Execute() {
	if err := NewRootCmd().Execute(); err != nil {
		// printStackTrace(err)
		os.Exit(1)
	}
}

func initConfig() {
	viper.SetEnvPrefix("mockery")
	viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
	viper.AutomaticEnv()

	if cfgFile != "" {
		// Use config file from the flag.
		viper.SetConfigFile(cfgFile)
	} else if viper.IsSet("config") {
		viper.SetConfigFile(viper.GetString("config"))
	} else {
		// Find home directory.
		home, err := homedir.Dir()
		if err != nil {
			log.Fatal().Err(err).Msgf("Failed to find homedir")
		}

		// Search config in home directory with name ".cobra" (without extension).
		viper.AddConfigPath(".")
		viper.AddConfigPath(home)
		viper.SetConfigName(".mockery")
	}

	// Note we purposely ignore the error. Don't care if we can't find a config file.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Fprintf(os.Stderr, "Using config file: %s\n", viper.ConfigFileUsed())
	}
}

const regexMetadataChars = "\\.+*?()|[]{}^$"

type RootApp struct {
	config.Config
}

func GetRootAppFromViper(v *viper.Viper) (*RootApp, error) {
	r := &RootApp{}
	if err := v.UnmarshalExact(&r.Config); err != nil {
		return nil, errors.Wrapf(err, "failed to get config")
	}
	return r, nil
}

func (r *RootApp) Run() error {
	var recursive bool
	var filter *regexp.Regexp
	var err error
	var limitOne bool

	if r.Quiet {
		// if "quiet" flag is set, disable logging
		r.Config.LogLevel = ""
	}

	log, err := getLogger(r.Config.LogLevel)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to initialize logger: %v\n", err)
		return err
	}
	log = log.With().Bool(logging.LogKeyDryRun, r.Config.DryRun).Logger()
	log.Info().Msgf("Starting mockery")
	ctx := log.WithContext(context.Background())

	if r.Config.Version {
		fmt.Println(config.GetSemverInfo())
		return nil
	} else if r.Config.Name != "" && r.Config.All {
		log.Fatal().Msgf("Specify --name or --all, but not both")
	} else if (r.Config.FileName != "" || r.Config.StructName != "") && r.Config.All {
		log.Fatal().Msgf("Cannot specify --filename or --structname with --all")
	} else if r.Config.Dir != "" && r.Config.Dir != "." && r.Config.SrcPkg != "" {
		log.Fatal().Msgf("Specify -dir or -srcpkg, but not both")
	} else if r.Config.Name != "" {
		recursive = r.Config.Recursive
		if strings.ContainsAny(r.Config.Name, regexMetadataChars) {
			if filter, err = regexp.Compile(r.Config.Name); err != nil {
				log.Fatal().Err(err).Msgf("Invalid regular expression provided to -name")
			} else if r.Config.FileName != "" || r.Config.StructName != "" {
				log.Fatal().Msgf("Cannot specify --filename or --structname with regex in --name")
			}
		} else {
			filter = regexp.MustCompile(fmt.Sprintf("^%s$", r.Config.Name))
			limitOne = true
		}
	} else if r.Config.All {
		recursive = true
		filter = regexp.MustCompile(".*")
	} else {
		log.Fatal().Msgf("Use --name to specify the name of the interface or --all for all interfaces found")
	}

	if r.Config.Profile != "" {
		f, err := os.Create(r.Config.Profile)
		if err != nil {
			return errors.Wrapf(err, "Failed to create profile file")
		}

		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	var osp pkg.OutputStreamProvider
	if r.Config.Print {
		osp = &pkg.StdoutStreamProvider{}
	} else {
		osp = &pkg.FileOutputStreamProvider{
			Config:                    r.Config,
			BaseDir:                   r.Config.Output,
			InPackage:                 r.Config.InPackage,
			TestOnly:                  r.Config.TestOnly,
			Case:                      r.Config.Case,
			KeepTree:                  r.Config.KeepTree,
			KeepTreeOriginalDirectory: r.Config.Dir,
			FileName:                  r.Config.FileName,
		}
	}

	baseDir := r.Config.Dir

	if r.Config.SrcPkg != "" {
		pkgs, err := packages.Load(&packages.Config{
			Mode: packages.NeedFiles,
		}, r.Config.SrcPkg)
		if err != nil || len(pkgs) == 0 {
			log.Fatal().Err(err).Msgf("Failed to load package %s", r.Config.SrcPkg)
		}

		// NOTE: we only pass one package name (config.SrcPkg) to packages.Load
		// it should return one package at most
		pkg := pkgs[0]

		if pkg.Errors != nil {
			log.Fatal().Err(pkg.Errors[0]).Msgf("Failed to load package %s", r.Config.SrcPkg)
		}

		if len(pkg.GoFiles) == 0 {
			log.Fatal().Msgf("No go files in package %s", r.Config.SrcPkg)
		}
		baseDir = filepath.Dir(pkg.GoFiles[0])
	}

	var boilerplate string
	if r.Config.BoilerplateFile != "" {
		data, err := os.ReadFile(r.Config.BoilerplateFile)
		if err != nil {
			log.Fatal().Msgf("Failed to read boilerplate file %s: %v", r.Config.BoilerplateFile, err)
		}
		boilerplate = string(data)
	}

	visitor := &pkg.GeneratorVisitor{
		Config:            r.Config,
		InPackage:         r.Config.InPackage,
		Note:              r.Config.Note,
		Boilerplate:       boilerplate,
		Osp:               osp,
		PackageName:       r.Config.Outpkg,
		PackageNamePrefix: r.Config.Packageprefix,
		StructName:        r.Config.StructName,
	}

	walker := pkg.Walker{
		Config:    r.Config,
		BaseDir:   baseDir,
		Recursive: recursive,
		Filter:    filter,
		LimitOne:  limitOne,
		BuildTags: strings.Split(r.Config.BuildTags, " "),
	}

	generated := walker.Walk(ctx, visitor)

	if r.Config.Name != "" && !generated {
		log.Fatal().Msgf("Unable to find '%s' in any go files under this path", r.Config.Name)
	}
	return nil
}

type timeHook struct{}

func (t timeHook) Run(e *zerolog.Event, level zerolog.Level, msg string) {
	e.Time("time", time.Now())
}

func getLogger(levelStr string) (zerolog.Logger, error) {
	level, err := zerolog.ParseLevel(levelStr)
	if err != nil {
		return zerolog.Logger{}, errors.Wrapf(err, "Couldn't parse log level")
	}
	out := os.Stderr
	writer := zerolog.ConsoleWriter{
		Out:        out,
		TimeFormat: time.RFC822,
	}
	if !terminal.IsTerminal(int(out.Fd())) {
		writer.NoColor = true
	}
	log := zerolog.New(writer).
		Hook(timeHook{}).
		Level(level).
		With().
		Str("version", config.GetSemverInfo()).
		Logger()

	return log, nil
}
<commit_msg>cmd: respect TERM=dumb by not using colors<commit_after>package cmd

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

	"github.com/mitchellh/go-homedir"
	"github.com/pkg/errors"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"github.com/vektra/mockery/v2/pkg"
	"github.com/vektra/mockery/v2/pkg/config"
	"github.com/vektra/mockery/v2/pkg/logging"
	"golang.org/x/crypto/ssh/terminal"
	"golang.org/x/tools/go/packages"
)

var (
	cfgFile = ""
)

func init() {
	cobra.OnInitialize(initConfig)
}

func NewRootCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "mockery",
		Short: "Generate mock objects for your Golang interfaces",
		RunE: func(cmd *cobra.Command, args []string) error {
			r, err := GetRootAppFromViper(viper.GetViper())
			if err != nil {
				printStackTrace(err)
				return err
			}
			return r.Run()
		},
	}

	pFlags := cmd.PersistentFlags()
	pFlags.StringVar(&cfgFile, "config", "", "config file to use")
	pFlags.String("name", "", "name or matching regular expression of interface to generate mock for")
	pFlags.Bool("print", false, "print the generated mock to stdout")
	pFlags.String("output", "./mocks", "directory to write mocks to")
	pFlags.String("outpkg", "mocks", "name of generated package")
	pFlags.String("packageprefix", "", "prefix for the generated package name, it is ignored if outpkg is also specified.")
	pFlags.String("dir", ".", "directory to search for interfaces")
	pFlags.BoolP("recursive", "r", false, "recurse search into sub-directories")
	pFlags.Bool("all", false, "generates mocks for all found interfaces in all sub-directories")
	pFlags.Bool("inpackage", false, "generate a mock that goes inside the original package")
	pFlags.Bool("testonly", false, "generate a mock in a _test.go file")
	pFlags.String("case", "camel", "name the mocked file using casing convention [camel, snake, underscore]")
	pFlags.String("note", "", "comment to insert into prologue of each generated file")
	pFlags.String("cpuprofile", "", "write cpu profile to file")
	pFlags.Bool("version", false, "prints the installed version of mockery")
	pFlags.Bool("quiet", false, `suppresses logger output (equivalent to --log-level="")`)
	pFlags.Bool("keeptree", false, "keep the tree structure of the original interface files into a different repository. Must be used with XX")
	pFlags.String("tags", "", "space-separated list of additional build tags to use")
	pFlags.String("filename", "", "name of generated file (only works with -name and no regex)")
	pFlags.String("structname", "", "name of generated struct (only works with -name and no regex)")
	pFlags.String("log-level", "info", "Level of logging")
	pFlags.String("srcpkg", "", "source pkg to search for interfaces")
	pFlags.BoolP("dry-run", "d", false, "Do a dry run, don't modify any files")
	pFlags.Bool("disable-version-string", false, "Do not insert the version string into the generated mock file.")
	pFlags.String("boilerplate-file", "", "File to read a boilerplate text from. Text should be a go block comment, i.e. /* ... */")
	pFlags.Bool("unroll-variadic", true, "For functions with variadic arguments, do not unroll the arguments into the underlying testify call. Instead, pass variadic slice as-is.")
	pFlags.Bool("exported", false, "Generates public mocks for private interfaces.")
	pFlags.Bool("with-expecter", false, "Generate expecter utility around mock's On, Run and Return methods with explicit types. This option is NOT compatible with -unroll-variadic=false")

	viper.BindPFlags(pFlags)

	cmd.AddCommand(NewShowConfigCmd())
	return cmd
}

type stackTracer interface {
	StackTrace() errors.StackTrace
}

func printStackTrace(e error) {
	fmt.Printf("%v\n", e)
	if err, ok := e.(stackTracer); ok {
		for _, f := range err.StackTrace() {
			fmt.Printf("%+s:%d\n", f, f)
		}
	}

}

// Execute executes the cobra CLI workflow
func Execute() {
	if err := NewRootCmd().Execute(); err != nil {
		// printStackTrace(err)
		os.Exit(1)
	}
}

func initConfig() {
	viper.SetEnvPrefix("mockery")
	viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
	viper.AutomaticEnv()

	if cfgFile != "" {
		// Use config file from the flag.
		viper.SetConfigFile(cfgFile)
	} else if viper.IsSet("config") {
		viper.SetConfigFile(viper.GetString("config"))
	} else {
		// Find home directory.
		home, err := homedir.Dir()
		if err != nil {
			log.Fatal().Err(err).Msgf("Failed to find homedir")
		}

		// Search config in home directory with name ".cobra" (without extension).
		viper.AddConfigPath(".")
		viper.AddConfigPath(home)
		viper.SetConfigName(".mockery")
	}

	// Note we purposely ignore the error. Don't care if we can't find a config file.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Fprintf(os.Stderr, "Using config file: %s\n", viper.ConfigFileUsed())
	}
}

const regexMetadataChars = "\\.+*?()|[]{}^$"

type RootApp struct {
	config.Config
}

func GetRootAppFromViper(v *viper.Viper) (*RootApp, error) {
	r := &RootApp{}
	if err := v.UnmarshalExact(&r.Config); err != nil {
		return nil, errors.Wrapf(err, "failed to get config")
	}
	return r, nil
}

func (r *RootApp) Run() error {
	var recursive bool
	var filter *regexp.Regexp
	var err error
	var limitOne bool

	if r.Quiet {
		// if "quiet" flag is set, disable logging
		r.Config.LogLevel = ""
	}

	log, err := getLogger(r.Config.LogLevel)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to initialize logger: %v\n", err)
		return err
	}
	log = log.With().Bool(logging.LogKeyDryRun, r.Config.DryRun).Logger()
	log.Info().Msgf("Starting mockery")
	ctx := log.WithContext(context.Background())

	if r.Config.Version {
		fmt.Println(config.GetSemverInfo())
		return nil
	} else if r.Config.Name != "" && r.Config.All {
		log.Fatal().Msgf("Specify --name or --all, but not both")
	} else if (r.Config.FileName != "" || r.Config.StructName != "") && r.Config.All {
		log.Fatal().Msgf("Cannot specify --filename or --structname with --all")
	} else if r.Config.Dir != "" && r.Config.Dir != "." && r.Config.SrcPkg != "" {
		log.Fatal().Msgf("Specify -dir or -srcpkg, but not both")
	} else if r.Config.Name != "" {
		recursive = r.Config.Recursive
		if strings.ContainsAny(r.Config.Name, regexMetadataChars) {
			if filter, err = regexp.Compile(r.Config.Name); err != nil {
				log.Fatal().Err(err).Msgf("Invalid regular expression provided to -name")
			} else if r.Config.FileName != "" || r.Config.StructName != "" {
				log.Fatal().Msgf("Cannot specify --filename or --structname with regex in --name")
			}
		} else {
			filter = regexp.MustCompile(fmt.Sprintf("^%s$", r.Config.Name))
			limitOne = true
		}
	} else if r.Config.All {
		recursive = true
		filter = regexp.MustCompile(".*")
	} else {
		log.Fatal().Msgf("Use --name to specify the name of the interface or --all for all interfaces found")
	}

	if r.Config.Profile != "" {
		f, err := os.Create(r.Config.Profile)
		if err != nil {
			return errors.Wrapf(err, "Failed to create profile file")
		}

		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	var osp pkg.OutputStreamProvider
	if r.Config.Print {
		osp = &pkg.StdoutStreamProvider{}
	} else {
		osp = &pkg.FileOutputStreamProvider{
			Config:                    r.Config,
			BaseDir:                   r.Config.Output,
			InPackage:                 r.Config.InPackage,
			TestOnly:                  r.Config.TestOnly,
			Case:                      r.Config.Case,
			KeepTree:                  r.Config.KeepTree,
			KeepTreeOriginalDirectory: r.Config.Dir,
			FileName:                  r.Config.FileName,
		}
	}

	baseDir := r.Config.Dir

	if r.Config.SrcPkg != "" {
		pkgs, err := packages.Load(&packages.Config{
			Mode: packages.NeedFiles,
		}, r.Config.SrcPkg)
		if err != nil || len(pkgs) == 0 {
			log.Fatal().Err(err).Msgf("Failed to load package %s", r.Config.SrcPkg)
		}

		// NOTE: we only pass one package name (config.SrcPkg) to packages.Load
		// it should return one package at most
		pkg := pkgs[0]

		if pkg.Errors != nil {
			log.Fatal().Err(pkg.Errors[0]).Msgf("Failed to load package %s", r.Config.SrcPkg)
		}

		if len(pkg.GoFiles) == 0 {
			log.Fatal().Msgf("No go files in package %s", r.Config.SrcPkg)
		}
		baseDir = filepath.Dir(pkg.GoFiles[0])
	}

	var boilerplate string
	if r.Config.BoilerplateFile != "" {
		data, err := os.ReadFile(r.Config.BoilerplateFile)
		if err != nil {
			log.Fatal().Msgf("Failed to read boilerplate file %s: %v", r.Config.BoilerplateFile, err)
		}
		boilerplate = string(data)
	}

	visitor := &pkg.GeneratorVisitor{
		Config:            r.Config,
		InPackage:         r.Config.InPackage,
		Note:              r.Config.Note,
		Boilerplate:       boilerplate,
		Osp:               osp,
		PackageName:       r.Config.Outpkg,
		PackageNamePrefix: r.Config.Packageprefix,
		StructName:        r.Config.StructName,
	}

	walker := pkg.Walker{
		Config:    r.Config,
		BaseDir:   baseDir,
		Recursive: recursive,
		Filter:    filter,
		LimitOne:  limitOne,
		BuildTags: strings.Split(r.Config.BuildTags, " "),
	}

	generated := walker.Walk(ctx, visitor)

	if r.Config.Name != "" && !generated {
		log.Fatal().Msgf("Unable to find '%s' in any go files under this path", r.Config.Name)
	}
	return nil
}

type timeHook struct{}

func (t timeHook) Run(e *zerolog.Event, level zerolog.Level, msg string) {
	e.Time("time", time.Now())
}

func getLogger(levelStr string) (zerolog.Logger, error) {
	level, err := zerolog.ParseLevel(levelStr)
	if err != nil {
		return zerolog.Logger{}, errors.Wrapf(err, "Couldn't parse log level")
	}
	out := os.Stderr
	writer := zerolog.ConsoleWriter{
		Out:        out,
		TimeFormat: time.RFC822,
	}
	if !terminal.IsTerminal(int(out.Fd())) || os.Getenv("TERM") == "dumb" {
		writer.NoColor = true
	}
	log := zerolog.New(writer).
		Hook(timeHook{}).
		Level(level).
		With().
		Str("version", config.GetSemverInfo()).
		Logger()

	return log, nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/nightlyone/lockfile"
	"io"
	"log"
	"log/syslog"
	"math/rand"
	"os"
	"os/exec"
	"path/filepath"
	"sync"
	"time"
)

// Avoid thundering herd problem on remote services used by this command.
// Interval will be 0, if this is not an issue.
func SpreadWait(interval time.Duration) {
	if interval > 0 {
		// Seed random generator with current process ID
		rand.Seed(int64(os.Getpid()))
		// Sleep for random amount of time within interval
		time.Sleep(time.Duration(rand.Int63n(int64(interval))))
	}
}

// Ok states that execution went well. Logs debug output and reports ok to
// monitoring.
func Ok() {
	log.Println("Ok")
	monitor(monitorOk, "")
}

// NotAvailable states that the command could not be started successfully. It
// might not be installed or has other problems.
func NotAvailable(err error) {
	s := fmt.Sprintln("Cannot start command: ", err)
	log.Println("FATAL:", s)
	monitor(monitorUnknown, s)
}

// TimedOut states that the command took too long and reports failure to the
// monitoring.
func TimedOut() {
	s := "execution took too long"
	log.Println("FATAL:", s)
	monitor(monitorCritical, s)
}

// Busy states that the command hangs and reports failure to the monitoring.
// Those tasks should be automatically killed, if it happens often.
func Busy() {
	s := "previous invocation of command still running"
	log.Println("FATAL:", s)
	monitor(monitorCritical, s)
}

// Failed states that the command didn't execute successfully and reports
// failure to the monitoring. Also Logs error output.
func Failed(err error) {
	s := fmt.Sprintln("Failed to execute: ", err)
	log.Println("FATAL:", s)
	monitor(monitorCritical, s)
}

var useSyslog bool

// derive logger
func getLogger() (logger io.Writer, err error) {
	if useSyslog {
		logger, err = syslog.New(syslog.LOG_NOTICE, monitoringEvent)
	} else {
		logger = os.Stderr
	}
	if err != nil {
		log.SetOutput(logger)
	}
	return logger, err
}

// pipe r to logger in the background
func logStream(r io.Reader, logger io.Writer, wg *sync.WaitGroup) {
	wg.Add(1)

	go func() {
		for {
			if _, err := io.Copy(logger, r); err != nil {
				break
			}
		}
		wg.Done()
	}()
}

func main() {
	var cmd *exec.Cmd
	var interval, timeout time.Duration
	var wg sync.WaitGroup
	var pipeStderr, pipeStdout bool

	// FIXME(mlafeldt) add command-line options for kill or wait on busy
	// state
	log.SetFlags(0)

	flag.DurationVar(&interval, "i", -1,
		"set execution interval for command, e.g. 45s, 2m, 1h30m, default: 1/10 of timeout")
	flag.DurationVar(&timeout, "t", 1*time.Minute,
		"set execution timeout for command, e.g. 45s, 2m, 1h30m, default: 1m")
	flag.BoolVar(&useSyslog, "l", false, "log via syslog")
	flag.BoolVar(&pipeStderr, "e", true, "pipe stderr to log")
	flag.BoolVar(&pipeStdout, "o", true, "pipe stdout to log")
	flag.Parse()

	if flag.NArg() < 1 {
		log.Fatal("FATAL: no command to execute")
		return
	}

	command := flag.Arg(0)
	monitoringEvent = filepath.Base(command)
	logger, err := getLogger()
	if err != nil {
		log.Fatal("FATAL: cannot contact syslog")
	}

	if interval >= timeout {
		log.Fatal("FATAL: interval >= timeout, no time left for actual command execution")
		return
	}

	if interval == -1 {
		interval = timeout / 10
	}

	loadMonitoringCommands()

	// FIXME(nightlyone) try two intervals instead of one?
	timer := time.AfterFunc(timeout, func() {
		TimedOut()
		if cmd != nil && cmd.Process != nil {
			cmd.Process.Kill()
			// FIXME(nightlyone) log the kill
		}
		os.Exit(0)
	})

	SpreadWait(interval)

	// Ensures that only one of these command runs concurrently on this
	// machine.  Also cleans up stale locks of dead instances.
	lock_dir := os.TempDir()
	os.Mkdir(filepath.Join(lock_dir, monitoringEvent), 0700)
	lock, _ := lockfile.New(filepath.Join(lock_dir, monitoringEvent, monitoringEvent+".lock"))
	if err := lock.TryLock(); err != nil {
		if err != lockfile.ErrBusy {
			log.Printf("ERROR: locking %s: reason: %v\n", lock, err)
		}
		timer.Stop()
		Busy()
		return
	}
	defer lock.Unlock()

	cmd = exec.Command(command, flag.Args()[1:]...)

	if pipeStdout {
		stdout, err := cmd.StdoutPipe()
		if err != nil {
			log.Fatal(err)
		}
		logStream(stdout, logger, &wg)
	}

	if pipeStderr {
		stderr, err := cmd.StderrPipe()
		if err != nil {
			log.Fatal(err)
		}
		logStream(stderr, logger, &wg)
	}

	if err := cmd.Start(); err != nil {
		timer.Stop()
		NotAvailable(err)
		return
	}

	if err := cmd.Wait(); err != nil {
		timer.Stop()
		Failed(err)
	} else {
		timer.Stop()
		Ok()
	}

	wg.Wait()
}
<commit_msg>Rename l option to s for clarity<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/nightlyone/lockfile"
	"io"
	"log"
	"log/syslog"
	"math/rand"
	"os"
	"os/exec"
	"path/filepath"
	"sync"
	"time"
)

// Avoid thundering herd problem on remote services used by this command.
// Interval will be 0, if this is not an issue.
func SpreadWait(interval time.Duration) {
	if interval > 0 {
		// Seed random generator with current process ID
		rand.Seed(int64(os.Getpid()))
		// Sleep for random amount of time within interval
		time.Sleep(time.Duration(rand.Int63n(int64(interval))))
	}
}

// Ok states that execution went well. Logs debug output and reports ok to
// monitoring.
func Ok() {
	log.Println("Ok")
	monitor(monitorOk, "")
}

// NotAvailable states that the command could not be started successfully. It
// might not be installed or has other problems.
func NotAvailable(err error) {
	s := fmt.Sprintln("Cannot start command: ", err)
	log.Println("FATAL:", s)
	monitor(monitorUnknown, s)
}

// TimedOut states that the command took too long and reports failure to the
// monitoring.
func TimedOut() {
	s := "execution took too long"
	log.Println("FATAL:", s)
	monitor(monitorCritical, s)
}

// Busy states that the command hangs and reports failure to the monitoring.
// Those tasks should be automatically killed, if it happens often.
func Busy() {
	s := "previous invocation of command still running"
	log.Println("FATAL:", s)
	monitor(monitorCritical, s)
}

// Failed states that the command didn't execute successfully and reports
// failure to the monitoring. Also Logs error output.
func Failed(err error) {
	s := fmt.Sprintln("Failed to execute: ", err)
	log.Println("FATAL:", s)
	monitor(monitorCritical, s)
}

var useSyslog bool

// derive logger
func getLogger() (logger io.Writer, err error) {
	if useSyslog {
		logger, err = syslog.New(syslog.LOG_NOTICE, monitoringEvent)
	} else {
		logger = os.Stderr
	}
	if err != nil {
		log.SetOutput(logger)
	}
	return logger, err
}

// pipe r to logger in the background
func logStream(r io.Reader, logger io.Writer, wg *sync.WaitGroup) {
	wg.Add(1)

	go func() {
		for {
			if _, err := io.Copy(logger, r); err != nil {
				break
			}
		}
		wg.Done()
	}()
}

func main() {
	var cmd *exec.Cmd
	var interval, timeout time.Duration
	var wg sync.WaitGroup
	var pipeStderr, pipeStdout bool

	// FIXME(mlafeldt) add command-line options for kill or wait on busy
	// state
	log.SetFlags(0)

	flag.DurationVar(&interval, "i", -1,
		"set execution interval for command, e.g. 45s, 2m, 1h30m, default: 1/10 of timeout")
	flag.DurationVar(&timeout, "t", 1*time.Minute,
		"set execution timeout for command, e.g. 45s, 2m, 1h30m, default: 1m")
	flag.BoolVar(&useSyslog, "s", false, "log via syslog")
	flag.BoolVar(&pipeStderr, "e", true, "pipe stderr to log")
	flag.BoolVar(&pipeStdout, "o", true, "pipe stdout to log")
	flag.Parse()

	if flag.NArg() < 1 {
		log.Fatal("FATAL: no command to execute")
		return
	}

	command := flag.Arg(0)
	monitoringEvent = filepath.Base(command)
	logger, err := getLogger()
	if err != nil {
		log.Fatal("FATAL: cannot contact syslog")
	}

	if interval >= timeout {
		log.Fatal("FATAL: interval >= timeout, no time left for actual command execution")
		return
	}

	if interval == -1 {
		interval = timeout / 10
	}

	loadMonitoringCommands()

	// FIXME(nightlyone) try two intervals instead of one?
	timer := time.AfterFunc(timeout, func() {
		TimedOut()
		if cmd != nil && cmd.Process != nil {
			cmd.Process.Kill()
			// FIXME(nightlyone) log the kill
		}
		os.Exit(0)
	})

	SpreadWait(interval)

	// Ensures that only one of these command runs concurrently on this
	// machine.  Also cleans up stale locks of dead instances.
	lock_dir := os.TempDir()
	os.Mkdir(filepath.Join(lock_dir, monitoringEvent), 0700)
	lock, _ := lockfile.New(filepath.Join(lock_dir, monitoringEvent, monitoringEvent+".lock"))
	if err := lock.TryLock(); err != nil {
		if err != lockfile.ErrBusy {
			log.Printf("ERROR: locking %s: reason: %v\n", lock, err)
		}
		timer.Stop()
		Busy()
		return
	}
	defer lock.Unlock()

	cmd = exec.Command(command, flag.Args()[1:]...)

	if pipeStdout {
		stdout, err := cmd.StdoutPipe()
		if err != nil {
			log.Fatal(err)
		}
		logStream(stdout, logger, &wg)
	}

	if pipeStderr {
		stderr, err := cmd.StderrPipe()
		if err != nil {
			log.Fatal(err)
		}
		logStream(stderr, logger, &wg)
	}

	if err := cmd.Start(); err != nil {
		timer.Stop()
		NotAvailable(err)
		return
	}

	if err := cmd.Wait(); err != nil {
		timer.Stop()
		Failed(err)
	} else {
		timer.Stop()
		Ok()
	}

	wg.Wait()
}
<|endoftext|>


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

package cmd

import (
	"context"
	"fmt"
	"path/filepath"
	"strings"
	"time"

	"github.com/fatih/color"
	"github.com/minio/cli"
	json "github.com/minio/mc/pkg/colorjson"
	"github.com/minio/mc/pkg/probe"
	"github.com/minio/minio/pkg/console"
)

var (
	rbFlags = []cli.Flag{
		cli.BoolFlag{
			Name:  "force",
			Usage: "force a recursive remove operation on all object versions",
		},
		cli.BoolFlag{
			Name:  "dangerous",
			Usage: "allow site-wide removal of objects",
		},
	}
)

// remove a bucket.
var rbCmd = cli.Command{
	Name:   "rb",
	Usage:  "remove a bucket",
	Action: mainRemoveBucket,
	Before: setGlobalsFromContext,
	Flags:  append(rbFlags, globalFlags...),
	CustomHelpTemplate: `NAME:
  {{.HelpName}} - {{.Usage}}

USAGE:
  {{.HelpName}} [FLAGS] TARGET [TARGET...]
{{if .VisibleFlags}}
FLAGS:
  {{range .VisibleFlags}}{{.}}
  {{end}}{{end}}
EXAMPLES:
  1. Remove an empty bucket on Amazon S3 cloud storage
     {{.Prompt}} {{.HelpName}} s3/mybucket

  2. Remove a directory hierarchy.
     {{.Prompt}} {{.HelpName}} /tmp/this/new/dir1

  3. Remove bucket 'jazz-songs' and all its contents
     {{.Prompt}} {{.HelpName}} --force s3/jazz-songs

  4. Remove all buckets and objects recursively from S3 host
     {{.Prompt}} {{.HelpName}} --force --dangerous s3
`,
}

// removeBucketMessage is container for delete bucket success and failure messages.
type removeBucketMessage struct {
	Status string `json:"status"`
	Bucket string `json:"bucket"`
}

// String colorized delete bucket message.
func (s removeBucketMessage) String() string {
	return console.Colorize("RemoveBucket", fmt.Sprintf("Removed `%s` successfully.", s.Bucket))
}

// JSON jsonified remove bucket message.
func (s removeBucketMessage) JSON() string {
	removeBucketJSONBytes, e := json.Marshal(s)
	fatalIf(probe.NewError(e), "Unable to marshal into JSON.")

	return string(removeBucketJSONBytes)
}

// Validate command line arguments.
func checkRbSyntax(ctx context.Context, cliCtx *cli.Context) {
	if !cliCtx.Args().Present() {
		exitCode := 1
		cli.ShowCommandHelpAndExit(cliCtx, "rb", exitCode)
	}
	// Set command flags from context.
	isForce := cliCtx.Bool("force")
	isDangerous := cliCtx.Bool("dangerous")

	for _, url := range cliCtx.Args() {
		if isNamespaceRemoval(ctx, url) {
			if isForce && isDangerous {
				continue
			}
			fatalIf(errDummy().Trace(),
				"This operation results in **site-wide** removal of buckets. If you are really sure, retry this command with ‘--force’ and ‘--dangerous’ flags.")
		}
	}
}

// Delete a bucket and all its objects and versions will be removed as well.
func deleteBucket(ctx context.Context, url string) *probe.Error {
	targetAlias, targetURL, _ := mustExpandAlias(url)
	clnt, pErr := newClientFromAlias(targetAlias, targetURL)
	if pErr != nil {
		return pErr
	}
	var isIncomplete bool
	isRemoveBucket := true
	contentCh := make(chan *ClientContent)
	errorCh := clnt.Remove(ctx, isIncomplete, isRemoveBucket, false, contentCh)

	go func() {
		defer close(contentCh)
		opts := ListOptions{
			isRecursive:       true,
			withOlderVersions: true,
			withDeleteMarkers: true,
			showDir:           DirLast,
		}

		for content := range clnt.List(ctx, opts) {
			if content.Err != nil {
				contentCh <- content
				continue
			}

			urlString := content.URL.Path

			select {
			case contentCh <- content:
			case <-ctx.Done():
				return
			}

			// list internally mimics recursive directory listing of object prefixes for s3 similar to FS.
			// The rmMessage needs to be printed only for actual buckets being deleted and not objects.
			tgt := strings.TrimPrefix(urlString, string(filepath.Separator))
			if !strings.Contains(tgt, string(filepath.Separator)) && tgt != targetAlias {
				printMsg(removeBucketMessage{
					Bucket: targetAlias + urlString, Status: "success",
				})
			}
		}

		// Remove the given url since the user will always want to remove it.
		alias, _ := url2Alias(targetURL)
		if alias != "" {
			contentCh <- &ClientContent{URL: *newClientURL(targetURL)}
		}
	}()

	for perr := range errorCh {
		switch perr.ToGoError().(type) {
		case PathInsufficientPermission:
			errorIf(perr.Trace(url), "Failed to remove `"+url+"`.")
			// Ignore Permission error.
			continue
		}
		return perr
	}
	return nil
}

// isNamespaceRemoval returns true if alias
// is not qualified by bucket
func isNamespaceRemoval(ctx context.Context, url string) bool {
	// clean path for aliases like s3/.
	//Note: UNC path using / works properly in go 1.9.2 even though it breaks the UNC specification.
	url = filepath.ToSlash(filepath.Clean(url))
	// namespace removal applies only for non FS. So filter out if passed url represents a directory
	if !isAliasURLDir(ctx, url, nil, time.Time{}) {
		_, path := url2Alias(url)
		return (path == "")
	}
	return false
}

// mainRemoveBucket is entry point for rb command.
func mainRemoveBucket(cliCtx *cli.Context) error {
	ctx, cancelRemoveBucket := context.WithCancel(globalContext)
	defer cancelRemoveBucket()

	// check 'rb' cli arguments.
	checkRbSyntax(ctx, cliCtx)
	isForce := cliCtx.Bool("force")

	// Additional command specific theme customization.
	console.SetColor("RemoveBucket", color.New(color.FgGreen, color.Bold))

	var cErr error
	for _, targetURL := range cliCtx.Args() {
		// Instantiate client for URL.
		clnt, err := newClient(targetURL)
		if err != nil {
			errorIf(err.Trace(targetURL), "Invalid target `"+targetURL+"`.")
			cErr = exitStatus(globalErrorExitStatus)
			continue
		}
		_, err = clnt.Stat(ctx, StatOptions{})
		if err != nil {
			switch err.ToGoError().(type) {
			case BucketNameEmpty:
			default:
				errorIf(err.Trace(targetURL), "Unable to validate target `"+targetURL+"`.")
				cErr = exitStatus(globalErrorExitStatus)
				continue

			}
		}

		// Check if the bucket contains any object, version or delete marker.
		isEmpty := true
		opts := ListOptions{
			isRecursive:       true,
			showDir:           DirNone,
			withOlderVersions: true,
			withDeleteMarkers: true,
		}

		listCtx, listCancel := context.WithCancel(ctx)
		for obj := range clnt.List(listCtx, opts) {
			if obj.Err != nil {
				continue
			}
			isEmpty = false
			break
		}
		listCancel()

		// For all recursive operations make sure to check for 'force' flag.
		if !isForce && !isEmpty {
			fatalIf(errDummy().Trace(), "`"+targetURL+"` is not empty. Retry this command with ‘--force’ flag if you want to remove `"+targetURL+"` and all its contents")
		}

		e := deleteBucket(ctx, targetURL)
		fatalIf(e.Trace(targetURL), "Failed to remove `"+targetURL+"`.")

		if !isNamespaceRemoval(ctx, targetURL) {
			printMsg(removeBucketMessage{
				Bucket: targetURL, Status: "success",
			})
		}
	}
	return cErr
}
<commit_msg>continue to remove content upon any error (#3383)<commit_after>/*
 * MinIO Client (C) 2019-2020 MinIO, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cmd

import (
	"context"
	"fmt"
	"path/filepath"
	"strings"
	"time"

	"github.com/fatih/color"
	"github.com/minio/cli"
	json "github.com/minio/mc/pkg/colorjson"
	"github.com/minio/mc/pkg/probe"
	"github.com/minio/minio/pkg/console"
)

var (
	rbFlags = []cli.Flag{
		cli.BoolFlag{
			Name:  "force",
			Usage: "force a recursive remove operation on all object versions",
		},
		cli.BoolFlag{
			Name:  "dangerous",
			Usage: "allow site-wide removal of objects",
		},
	}
)

// remove a bucket.
var rbCmd = cli.Command{
	Name:   "rb",
	Usage:  "remove a bucket",
	Action: mainRemoveBucket,
	Before: setGlobalsFromContext,
	Flags:  append(rbFlags, globalFlags...),
	CustomHelpTemplate: `NAME:
  {{.HelpName}} - {{.Usage}}

USAGE:
  {{.HelpName}} [FLAGS] TARGET [TARGET...]
{{if .VisibleFlags}}
FLAGS:
  {{range .VisibleFlags}}{{.}}
  {{end}}{{end}}
EXAMPLES:
  1. Remove an empty bucket on Amazon S3 cloud storage
     {{.Prompt}} {{.HelpName}} s3/mybucket

  2. Remove a directory hierarchy.
     {{.Prompt}} {{.HelpName}} /tmp/this/new/dir1

  3. Remove bucket 'jazz-songs' and all its contents
     {{.Prompt}} {{.HelpName}} --force s3/jazz-songs

  4. Remove all buckets and objects recursively from S3 host
     {{.Prompt}} {{.HelpName}} --force --dangerous s3
`,
}

// removeBucketMessage is container for delete bucket success and failure messages.
type removeBucketMessage struct {
	Status string `json:"status"`
	Bucket string `json:"bucket"`
}

// String colorized delete bucket message.
func (s removeBucketMessage) String() string {
	return console.Colorize("RemoveBucket", fmt.Sprintf("Removed `%s` successfully.", s.Bucket))
}

// JSON jsonified remove bucket message.
func (s removeBucketMessage) JSON() string {
	removeBucketJSONBytes, e := json.Marshal(s)
	fatalIf(probe.NewError(e), "Unable to marshal into JSON.")

	return string(removeBucketJSONBytes)
}

// Validate command line arguments.
func checkRbSyntax(ctx context.Context, cliCtx *cli.Context) {
	if !cliCtx.Args().Present() {
		exitCode := 1
		cli.ShowCommandHelpAndExit(cliCtx, "rb", exitCode)
	}
	// Set command flags from context.
	isForce := cliCtx.Bool("force")
	isDangerous := cliCtx.Bool("dangerous")

	for _, url := range cliCtx.Args() {
		if isNamespaceRemoval(ctx, url) {
			if isForce && isDangerous {
				continue
			}
			fatalIf(errDummy().Trace(),
				"This operation results in **site-wide** removal of buckets. If you are really sure, retry this command with ‘--force’ and ‘--dangerous’ flags.")
		}
	}
}

// Delete a bucket and all its objects and versions will be removed as well.
func deleteBucket(ctx context.Context, url string) *probe.Error {
	targetAlias, targetURL, _ := mustExpandAlias(url)
	clnt, pErr := newClientFromAlias(targetAlias, targetURL)
	if pErr != nil {
		return pErr
	}
	var isIncomplete bool
	isRemoveBucket := true
	contentCh := make(chan *ClientContent)
	errorCh := clnt.Remove(ctx, isIncomplete, isRemoveBucket, false, contentCh)

	go func() {
		defer close(contentCh)
		opts := ListOptions{
			isRecursive:       true,
			withOlderVersions: true,
			withDeleteMarkers: true,
			showDir:           DirLast,
		}

		for content := range clnt.List(ctx, opts) {
			if content.Err != nil {
				contentCh <- content
				continue
			}

			urlString := content.URL.Path

			select {
			case contentCh <- content:
			case <-ctx.Done():
				return
			}

			// list internally mimics recursive directory listing of object prefixes for s3 similar to FS.
			// The rmMessage needs to be printed only for actual buckets being deleted and not objects.
			tgt := strings.TrimPrefix(urlString, string(filepath.Separator))
			if !strings.Contains(tgt, string(filepath.Separator)) && tgt != targetAlias {
				printMsg(removeBucketMessage{
					Bucket: targetAlias + urlString, Status: "success",
				})
			}
		}

		// Remove the given url since the user will always want to remove it.
		alias, _ := url2Alias(targetURL)
		if alias != "" {
			contentCh <- &ClientContent{URL: *newClientURL(targetURL)}
		}
	}()

	for perr := range errorCh {
		errorIf(perr.Trace(url), "Failed to remove `"+url+"`, continuing..")
	}
	return nil
}

// isNamespaceRemoval returns true if alias
// is not qualified by bucket
func isNamespaceRemoval(ctx context.Context, url string) bool {
	// clean path for aliases like s3/.
	//Note: UNC path using / works properly in go 1.9.2 even though it breaks the UNC specification.
	url = filepath.ToSlash(filepath.Clean(url))
	// namespace removal applies only for non FS. So filter out if passed url represents a directory
	if !isAliasURLDir(ctx, url, nil, time.Time{}) {
		_, path := url2Alias(url)
		return (path == "")
	}
	return false
}

// mainRemoveBucket is entry point for rb command.
func mainRemoveBucket(cliCtx *cli.Context) error {
	ctx, cancelRemoveBucket := context.WithCancel(globalContext)
	defer cancelRemoveBucket()

	// check 'rb' cli arguments.
	checkRbSyntax(ctx, cliCtx)
	isForce := cliCtx.Bool("force")

	// Additional command specific theme customization.
	console.SetColor("RemoveBucket", color.New(color.FgGreen, color.Bold))

	var cErr error
	for _, targetURL := range cliCtx.Args() {
		// Instantiate client for URL.
		clnt, err := newClient(targetURL)
		if err != nil {
			errorIf(err.Trace(targetURL), "Invalid target `"+targetURL+"`.")
			cErr = exitStatus(globalErrorExitStatus)
			continue
		}
		_, err = clnt.Stat(ctx, StatOptions{})
		if err != nil {
			switch err.ToGoError().(type) {
			case BucketNameEmpty:
			default:
				errorIf(err.Trace(targetURL), "Unable to validate target `"+targetURL+"`.")
				cErr = exitStatus(globalErrorExitStatus)
				continue

			}
		}

		// Check if the bucket contains any object, version or delete marker.
		isEmpty := true
		opts := ListOptions{
			isRecursive:       true,
			showDir:           DirNone,
			withOlderVersions: true,
			withDeleteMarkers: true,
		}

		listCtx, listCancel := context.WithCancel(ctx)
		for obj := range clnt.List(listCtx, opts) {
			if obj.Err != nil {
				continue
			}
			isEmpty = false
			break
		}
		listCancel()

		// For all recursive operations make sure to check for 'force' flag.
		if !isForce && !isEmpty {
			fatalIf(errDummy().Trace(), "`"+targetURL+"` is not empty. Retry this command with ‘--force’ flag if you want to remove `"+targetURL+"` and all its contents")
		}

		e := deleteBucket(ctx, targetURL)
		fatalIf(e.Trace(targetURL), "Failed to remove `"+targetURL+"`.")

		if !isNamespaceRemoval(ctx, targetURL) {
			printMsg(removeBucketMessage{
				Bucket: targetURL, Status: "success",
			})
		}
	}
	return cErr
}
<|endoftext|>


<commit_before>package cmd

import "github.com/spf13/cobra"

func init() {
	RootCmd.AddCommand(versionCmd)
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Displays the version of mbt",
	Run: func(cmd *cobra.Command, args []string) {
		println("0.6.0")
	},
}
<commit_msg>Bump version<commit_after>package cmd

import "github.com/spf13/cobra"

func init() {
	RootCmd.AddCommand(versionCmd)
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Displays the version of mbt",
	Run: func(cmd *cobra.Command, args []string) {
		println("0.7.0")
	},
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"os"

	"github.com/robdimsdale/wundergo"
	"github.com/robdimsdale/wundergo/logger"
	"github.com/robdimsdale/wundergo/oauth"
)

var (
	// version is deliberately left uninitialized so it can be set at compile-time
	version string

	accessToken = flag.String("accessToken", "", "Wunderlist access token")
	clientID    = flag.String("clientID", "", "Wunderlist client ID")

	logLevel = flag.String("logLevel", "info", "log level: debug, info, error or fatal")
)

func main() {
	if version == "" {
		version = "dev"
	}

	if len(os.Args) > 1 {
		arg := os.Args[1]
		if arg == "version" || arg == "-v" || arg == "--version" {
			fmt.Printf("%s\n", version)
			os.Exit(0)
		}
	}

	flag.Parse()

	logger := logger.NewLogger(logger.LogLevelFromString(*logLevel))

	if *accessToken == "" {
		logger.Error("exiting", errors.New("accessToken must be provided"))
		os.Exit(2)
	}

	if *clientID == "" {
		logger.Error("exiting", errors.New("clientID must be provided"))
		os.Exit(2)
	}

	client := oauth.NewClient(*accessToken, *clientID, wundergo.APIURL, logger)

	args := flag.Args()
	if len(args) == 0 {
		logger.Info("no command specified - exiting")
		os.Exit(2)
	}

	if args[0] == "folders" {
		folders, err := client.Folders()
		if err != nil {
			logger.Error("exiting", err)
			os.Exit(1)
		}
		json.NewEncoder(os.Stdout).Encode(folders)
	}

	if args[0] == "delete-all-folders" {
		err := client.DeleteAllFolders()
		if err != nil {
			logger.Error("exiting", err)
			os.Exit(1)
		}
		fmt.Printf("All folders deleted successfully")
	}

	if args[0] == "lists" {
		lists, err := client.Lists()
		if err != nil {
			logger.Error("exiting", err)
			os.Exit(1)
		}
		json.NewEncoder(os.Stdout).Encode(lists)
	}

	if args[0] == "delete-all-lists" {
		err := client.DeleteAllLists()
		if err != nil {
			logger.Error("exiting", err)
			os.Exit(1)
		}
		fmt.Printf("All lists deleted successfully")
	}

	if args[0] == "tasks" {
		tasks, err := client.Tasks()
		if err != nil {
			logger.Error("exiting", err)
			os.Exit(1)
		}
		json.NewEncoder(os.Stdout).Encode(tasks)
	}

	if args[0] == "delete-all-tasks" {
		err := client.DeleteAllTasks()
		if err != nil {
			logger.Error("exiting", err)
			os.Exit(1)
		}
		fmt.Printf("All tasks deleted successfully")
	}
}
<commit_msg>Enable wl binary to read credentials from environment variables.<commit_after>package main

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"os"

	"github.com/robdimsdale/wundergo"
	"github.com/robdimsdale/wundergo/logger"
	"github.com/robdimsdale/wundergo/oauth"
)

var (
	// version is deliberately left uninitialized so it can be set at compile-time
	version string

	accessToken = flag.String("accessToken", "", "Wunderlist access token")
	clientID    = flag.String("clientID", "", "Wunderlist client ID")

	logLevel = flag.String("logLevel", "info", "log level: debug, info, error or fatal")
)

func main() {
	if version == "" {
		version = "dev"
	}

	if len(os.Args) > 1 {
		arg := os.Args[1]
		if arg == "version" || arg == "-v" || arg == "--version" {
			fmt.Printf("%s\n", version)
			os.Exit(0)
		}
	}

	flag.Parse()

	logger := logger.NewLogger(logger.LogLevelFromString(*logLevel))

	var wlAccessToken string
	if *accessToken != "" {
		wlAccessToken = *accessToken
	} else {
		wlAccessToken = os.Getenv("WL_ACCESS_TOKEN")
	}

	if wlAccessToken == "" {
		logger.Error(
			"exiting",
			errors.New("accessToken not found. Either provide the flag -accessToken or set the environment variable WL_ACCESS_TOKEN"))
		os.Exit(2)
	}

	var wlClientID string
	if *clientID != "" {
		wlClientID = *clientID
	} else {
		wlClientID = os.Getenv("WL_CLIENT_ID")
	}

	if wlClientID == "" {
		logger.Error(
			"exiting",
			errors.New("clientID not found. Either provide the flag -clientID or set the environment variable WL_CLIENT_ID"))
		os.Exit(2)
	}

	client := oauth.NewClient(
		wlAccessToken,
		wlClientID,
		wundergo.APIURL,
		logger,
	)

	args := flag.Args()
	if len(args) == 0 {
		logger.Info("no command specified - exiting")
		os.Exit(2)
	}

	if args[0] == "folders" {
		folders, err := client.Folders()
		if err != nil {
			logger.Error("exiting", err)
			os.Exit(1)
		}
		json.NewEncoder(os.Stdout).Encode(folders)
	}

	if args[0] == "delete-all-folders" {
		err := client.DeleteAllFolders()
		if err != nil {
			logger.Error("exiting", err)
			os.Exit(1)
		}
		fmt.Printf("All folders deleted successfully")
	}

	if args[0] == "lists" {
		lists, err := client.Lists()
		if err != nil {
			logger.Error("exiting", err)
			os.Exit(1)
		}
		json.NewEncoder(os.Stdout).Encode(lists)
	}

	if args[0] == "delete-all-lists" {
		err := client.DeleteAllLists()
		if err != nil {
			logger.Error("exiting", err)
			os.Exit(1)
		}
		fmt.Printf("All lists deleted successfully")
	}

	if args[0] == "tasks" {
		tasks, err := client.Tasks()
		if err != nil {
			logger.Error("exiting", err)
			os.Exit(1)
		}
		json.NewEncoder(os.Stdout).Encode(tasks)
	}

	if args[0] == "delete-all-tasks" {
		err := client.DeleteAllTasks()
		if err != nil {
			logger.Error("exiting", err)
			os.Exit(1)
		}
		fmt.Printf("All tasks deleted successfully")
	}
}
<|endoftext|>


<commit_before>package beanstalkd

import (
	"bufio"
	"strings"
	"testing"

	"github.com/influxdata/telegraf/testutil"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestBeanstalkdGeneratesMetrics(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration test in short mode")
	}

	m := &Beanstalkd{
		Servers: []string{testutil.GetLocalHost()},
	}

	var acc testutil.Accumulator

	err := m.Gather(&acc)
	require.NoError(t, err)

	intMetrics := []string{"current-jobs-urgent", "current-jobs-ready", "current-jobs-reserved",
		"current-jobs-delayed", "current-jobs-buried", "cmd-put", "cmd-peek", "cmd-peek-ready",
		"cmd-peek-delayed", "cmd-peek-buried", "cmd-reserve", "cmd-reserve-with-timeout",
		"cmd-delete", "cmd-release", "cmd-use", "cmd-watch", "cmd-ignore",
		"cmd-bury", "cmd-kick", "cmd-touch", "cmd-stats", "cmd-stats-job",
		"cmd-stats-tube", "cmd-list-tubes", "cmd-list-tube-used", "cmd-list-tubes-watched",
		"cmd-pause-tube", "job-timeouts", "total-jobs",
		"current-tubes", "current-connections", "current-producers",
		"current-workers", "current-waiting", "total-connections", "uptime",
		"binlog-oldest-index", "binlog-current-index", "binlog-records-migrated",
		"binlog-records-written", "binlog-max-size",
	}

	for _, metric := range intMetrics {
		assert.True(t, acc.HasIntField("beanstalkd", metric), metric)
	}
}

func TestBeanstalkdParseMetrics(t *testing.T) {
	r := bufio.NewReader(strings.NewReader(beanstalkdStats))
	values, err := parseResponse(r)
	require.NoError(t, err, "Error parsing beanstalkd response")

	tests := []struct {
		key   string
		value string
	}{
		{"current-jobs-urgent", "0"},
		{"current-jobs-ready", "0"},
		{"current-jobs-reserved", "0"},
		{"current-jobs-delayed", "0"},
		{"current-jobs-buried", "0"},
		{"cmd-put", "613"},
		{"cmd-peek", "0"},
		{"cmd-peek-ready", "0"},
		{"cmd-peek-delayed", "0"},
		{"cmd-peek-buried", "0"},
		{"cmd-reserve", "805"},
		{"cmd-reserve-with-timeout", "0"},
		{"cmd-delete", "613"},
		{"cmd-release", "0"},
		{"cmd-use", "613"},
		{"cmd-watch", "805"},
		{"cmd-ignore", "805"},
		{"cmd-bury", "0"},
		{"cmd-kick", "0"},
		{"cmd-touch", "0"},
		{"cmd-stats", "5"},
		{"cmd-stats-job", "0"},
		{"cmd-stats-tube", "0"},
		{"cmd-list-tubes", "0"},
		{"cmd-list-tube-used", "0"},
		{"cmd-list-tubes-watched", "0"},
		{"cmd-pause-tube", "0"},
		{"job-timeouts", "0"},
		{"total-jobs", "613"},
		{"current-tubes", "1"},
		{"current-connections", "1"},
		{"current-producers", "0"},
		{"current-workers", "0"},
		{"current-waiting", "0"},
		{"total-connections", "809"},
		{"uptime", "8007"},
		{"binlog-oldest-index", "10"},
		{"binlog-current-index", "10"},
		{"binlog-records-migrated", "0"},
		{"binlog-records-written", "1226"},
		{"binlog-max-size", "10485760"},
	}

	for _, test := range tests {
		value, ok := values[test.key]
		if !ok {
			t.Errorf("Did not find key for metric %s in values", test.key)
			continue
		}
		if value != test.value {
			t.Errorf("Metric: %s, Expected: %s, actual: %s",
				test.key, test.value, value)
		}
	}
}

var beanstalkdStats = `---
current-jobs-urgent: 0
current-jobs-ready: 0
current-jobs-reserved: 0
current-jobs-delayed: 0
current-jobs-buried: 0
cmd-put: 613
cmd-peek: 0
cmd-peek-ready: 0
cmd-peek-delayed: 0
cmd-peek-buried: 0
cmd-reserve: 805
cmd-reserve-with-timeout: 0
cmd-delete: 613
cmd-release: 0
cmd-use: 613
cmd-watch: 805
cmd-ignore: 805
cmd-bury: 0
cmd-kick: 0
cmd-touch: 0
cmd-stats: 1
cmd-stats-job: 0
cmd-stats-tube: 0
cmd-list-tubes: 0
cmd-list-tube-used: 0
cmd-list-tubes-watched: 0
cmd-pause-tube: 0
job-timeouts: 0
total-jobs: 613
current-tubes: 1
current-connections: 1
current-producers: 0
current-workers: 0
current-waiting: 0
total-connections: 806
version: 1.10
rusage-utime: 0.060000
rusage-stime: 0.212000
uptime: 7754
binlog-oldest-index: 10
binlog-current-index: 10
binlog-records-migrated: 0
binlog-records-written: 1226
binlog-max-size: 10485760
id: 95dd7f24ee126dd6
hostname: irrlab

`
<commit_msg>TestBeanstalkdParseMetrics expected values mismatch<commit_after>package beanstalkd

import (
	"bufio"
	"strings"
	"testing"

	"github.com/influxdata/telegraf/testutil"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestBeanstalkdGeneratesMetrics(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration test in short mode")
	}

	m := &Beanstalkd{
		Servers: []string{testutil.GetLocalHost()},
	}

	var acc testutil.Accumulator

	err := m.Gather(&acc)
	require.NoError(t, err)

	intMetrics := []string{"current-jobs-urgent", "current-jobs-ready", "current-jobs-reserved",
		"current-jobs-delayed", "current-jobs-buried", "cmd-put", "cmd-peek", "cmd-peek-ready",
		"cmd-peek-delayed", "cmd-peek-buried", "cmd-reserve", "cmd-reserve-with-timeout",
		"cmd-delete", "cmd-release", "cmd-use", "cmd-watch", "cmd-ignore",
		"cmd-bury", "cmd-kick", "cmd-touch", "cmd-stats", "cmd-stats-job",
		"cmd-stats-tube", "cmd-list-tubes", "cmd-list-tube-used", "cmd-list-tubes-watched",
		"cmd-pause-tube", "job-timeouts", "total-jobs",
		"current-tubes", "current-connections", "current-producers",
		"current-workers", "current-waiting", "total-connections", "uptime",
		"binlog-oldest-index", "binlog-current-index", "binlog-records-migrated",
		"binlog-records-written", "binlog-max-size",
	}

	for _, metric := range intMetrics {
		assert.True(t, acc.HasIntField("beanstalkd", metric), metric)
	}
}

func TestBeanstalkdParseMetrics(t *testing.T) {
	r := bufio.NewReader(strings.NewReader(beanstalkdStats))
	values, err := parseResponse(r)
	require.NoError(t, err, "Error parsing beanstalkd response")

	tests := []struct {
		key   string
		value string
	}{
		{"current-jobs-urgent", "0"},
		{"current-jobs-ready", "0"},
		{"current-jobs-reserved", "0"},
		{"current-jobs-delayed", "0"},
		{"current-jobs-buried", "0"},
		{"cmd-put", "613"},
		{"cmd-peek", "0"},
		{"cmd-peek-ready", "0"},
		{"cmd-peek-delayed", "0"},
		{"cmd-peek-buried", "0"},
		{"cmd-reserve", "805"},
		{"cmd-reserve-with-timeout", "0"},
		{"cmd-delete", "613"},
		{"cmd-release", "0"},
		{"cmd-use", "613"},
		{"cmd-watch", "805"},
		{"cmd-ignore", "805"},
		{"cmd-bury", "0"},
		{"cmd-kick", "0"},
		{"cmd-touch", "0"},
		{"cmd-stats", "5"},
		{"cmd-stats-job", "0"},
		{"cmd-stats-tube", "0"},
		{"cmd-list-tubes", "0"},
		{"cmd-list-tube-used", "0"},
		{"cmd-list-tubes-watched", "0"},
		{"cmd-pause-tube", "0"},
		{"job-timeouts", "0"},
		{"total-jobs", "613"},
		{"current-tubes", "1"},
		{"current-connections", "1"},
		{"current-producers", "0"},
		{"current-workers", "0"},
		{"current-waiting", "0"},
		{"total-connections", "809"},
		{"uptime", "8007"},
		{"binlog-oldest-index", "10"},
		{"binlog-current-index", "10"},
		{"binlog-records-migrated", "0"},
		{"binlog-records-written", "1226"},
		{"binlog-max-size", "10485760"},
	}

	for _, test := range tests {
		value, ok := values[test.key]
		if !ok {
			t.Errorf("Did not find key for metric %s in values", test.key)
			continue
		}
		if value != test.value {
			t.Errorf("Metric: %s, Expected: %s, actual: %s",
				test.key, test.value, value)
		}
	}
}

var beanstalkdStats = `---
current-jobs-urgent: 0
current-jobs-ready: 0
current-jobs-reserved: 0
current-jobs-delayed: 0
current-jobs-buried: 0
cmd-put: 613
cmd-peek: 0
cmd-peek-ready: 0
cmd-peek-delayed: 0
cmd-peek-buried: 0
cmd-reserve: 805
cmd-reserve-with-timeout: 0
cmd-delete: 613
cmd-release: 0
cmd-use: 613
cmd-watch: 805
cmd-ignore: 805
cmd-bury: 0
cmd-kick: 0
cmd-touch: 0
cmd-stats: 5
cmd-stats-job: 0
cmd-stats-tube: 0
cmd-list-tubes: 0
cmd-list-tube-used: 0
cmd-list-tubes-watched: 0
cmd-pause-tube: 0
job-timeouts: 0
total-jobs: 613
current-tubes: 1
current-connections: 1
current-producers: 0
current-workers: 0
current-waiting: 0
total-connections: 809
version: 1.10
rusage-utime: 0.060000
rusage-stime: 0.212000
uptime: 8007
binlog-oldest-index: 10
binlog-current-index: 10
binlog-records-migrated: 0
binlog-records-written: 1226
binlog-max-size: 10485760
id: 95dd7f24ee126dd6
hostname: irrlab

`
<|endoftext|>


<commit_before>// Copyright (c) 2018 Cisco and/or its affiliates.
//
// 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 utils

import (
	"encoding/json"
	"fmt"
	"reflect"

	"github.com/gogo/protobuf/jsonpb"
	"github.com/gogo/protobuf/proto"
)

// RecordedProtoMessage is a proto.Message suitable for recording and access via
// REST API.
type RecordedProtoMessage struct {
	proto.Message
	ProtoMsgName string
}

// ProtoWithName is used to marshall proto message data alongside the proto
// message name.
type ProtoWithName struct {
	ProtoMsgName string
	ProtoMsgData string
}

// MarshalJSON marshalls proto message using the marshaller from jsonpb.
// The jsonpb package produces a different output than the standard "encoding/json"
// package, which does not operate correctly on protocol buffers.
func (p *RecordedProtoMessage) MarshalJSON() ([]byte, error) {
	var (
		msgName string
		msgData string
		err     error
	)
	if p != nil {
		msgName = proto.MessageName(p.Message)
		marshaller := &jsonpb.Marshaler{}
		msgData, err = marshaller.MarshalToString(p.Message)
		if err != nil {
			return nil, err
		}
	}
	pwn, err := json.Marshal(
		ProtoWithName{ProtoMsgName: msgName, ProtoMsgData: msgData})
	if err != nil {
		return nil, err
	}
	fmt.Printf("MARSHALLED: %s\n", string(pwn))
	return pwn, nil
}

// UnmarshalJSON un-marshalls proto message using the marshaller from jsonpb.
// The jsonpb package produces a different output than the standard "encoding/json"
// package, which does not operate correctly on protocol buffers.
func (p *RecordedProtoMessage) UnmarshalJSON(data []byte) error {
	fmt.Printf("UNMARSHALL: %s\n", string(data))
	pwn := ProtoWithName{}
	err := json.Unmarshal(data, &pwn)
	if err != nil {
		return err
	}
	p.ProtoMsgName = pwn.ProtoMsgName
	if p.ProtoMsgName == "" {
		return nil
	}
	msgType := proto.MessageType(pwn.ProtoMsgName)
	if msgType == nil {
		return fmt.Errorf("unknown proto message: %s", p.ProtoMsgName)
	}
	msg := reflect.New(msgType.Elem()).Interface().(proto.Message)
	err = jsonpb.UnmarshalString(pwn.ProtoMsgData, msg)
	if err != nil {
		return err
	}
	p.Message = msg
	return nil
}

// RecordProtoMessage prepares proto message for recording and potential
// access via REST API.
// Note: no need to clone the message - once un-marshalled, the content is never
// changed (otherwise it would break prev-new value comparisons).
func RecordProtoMessage(msg proto.Message) *RecordedProtoMessage {
	if msg == nil {
		return nil
	}
	return &RecordedProtoMessage{
		Message:      msg,
		ProtoMsgName: proto.MessageName(msg),
	}
}
<commit_msg>Remove temporary prints used for debugging (#1459)<commit_after>// Copyright (c) 2018 Cisco and/or its affiliates.
//
// 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 utils

import (
	"encoding/json"
	"fmt"
	"reflect"

	"github.com/gogo/protobuf/jsonpb"
	"github.com/gogo/protobuf/proto"
)

// RecordedProtoMessage is a proto.Message suitable for recording and access via
// REST API.
type RecordedProtoMessage struct {
	proto.Message
	ProtoMsgName string
}

// ProtoWithName is used to marshall proto message data alongside the proto
// message name.
type ProtoWithName struct {
	ProtoMsgName string
	ProtoMsgData string
}

// MarshalJSON marshalls proto message using the marshaller from jsonpb.
// The jsonpb package produces a different output than the standard "encoding/json"
// package, which does not operate correctly on protocol buffers.
func (p *RecordedProtoMessage) MarshalJSON() ([]byte, error) {
	var (
		msgName string
		msgData string
		err     error
	)
	if p != nil {
		msgName = proto.MessageName(p.Message)
		marshaller := &jsonpb.Marshaler{}
		msgData, err = marshaller.MarshalToString(p.Message)
		if err != nil {
			return nil, err
		}
	}
	pwn, err := json.Marshal(
		ProtoWithName{ProtoMsgName: msgName, ProtoMsgData: msgData})
	if err != nil {
		return nil, err
	}
	return pwn, nil
}

// UnmarshalJSON un-marshalls proto message using the marshaller from jsonpb.
// The jsonpb package produces a different output than the standard "encoding/json"
// package, which does not operate correctly on protocol buffers.
func (p *RecordedProtoMessage) UnmarshalJSON(data []byte) error {
	pwn := ProtoWithName{}
	err := json.Unmarshal(data, &pwn)
	if err != nil {
		return err
	}
	p.ProtoMsgName = pwn.ProtoMsgName
	if p.ProtoMsgName == "" {
		return nil
	}
	msgType := proto.MessageType(pwn.ProtoMsgName)
	if msgType == nil {
		return fmt.Errorf("unknown proto message: %s", p.ProtoMsgName)
	}
	msg := reflect.New(msgType.Elem()).Interface().(proto.Message)
	err = jsonpb.UnmarshalString(pwn.ProtoMsgData, msg)
	if err != nil {
		return err
	}
	p.Message = msg
	return nil
}

// RecordProtoMessage prepares proto message for recording and potential
// access via REST API.
// Note: no need to clone the message - once un-marshalled, the content is never
// changed (otherwise it would break prev-new value comparisons).
func RecordProtoMessage(msg proto.Message) *RecordedProtoMessage {
	if msg == nil {
		return nil
	}
	return &RecordedProtoMessage{
		Message:      msg,
		ProtoMsgName: proto.MessageName(msg),
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 The appc 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 docker2aci

import "github.com/appc/spec/schema"

var Version = "0.9.1"
var AppcVersion = schema.AppContainerVersion
<commit_msg>version: bump to v0.9.1+git<commit_after>// Copyright 2016 The appc 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 docker2aci

import "github.com/appc/spec/schema"

var Version = "0.9.1+git"
var AppcVersion = schema.AppContainerVersion
<|endoftext|>


<commit_before>/* Copyright (C) 2015-2020 김운하 (unha.kim@ghts.org)

이 파일은 GHTS의 일부입니다.

이 프로그램은 자유 소프트웨어입니다.
소프트웨어의 피양도자는 자유 소프트웨어 재단이 공표한 GNU LGPL 2.1판
규정에 따라 프로그램을 개작하거나 재배포할 수 있습니다.

이 프로그램은 유용하게 사용될 수 있으리라는 희망에서 배포되고 있지만,
특정한 목적에 적합하다거나, 이익을 안겨줄 수 있다는 묵시적인 보증을 포함한
어떠한 형태의 보증도 제공하지 않습니다.
보다 자세한 사항에 대해서는 GNU LGPL 2.1판을 참고하시기 바랍니다.
GNU LGPL 2.1판은 이 프로그램과 함께 제공됩니다.
만약, 이 문서가 누락되어 있다면 자유 소프트웨어 재단으로 문의하시기 바랍니다.
(자유 소프트웨어 재단 : Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA)

Copyright (C) 2015-2020년 UnHa Kim (unha.kim@ghts.org)

This file is part of GHTS.

GHTS is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, version 2.1 of the License.

GHTS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with GHTS.  If not, see <http://www.gnu.org/licenses/>. */

package xt

import (
	"fmt"
	"github.com/ghts/ghts/lib"
	"os"
	"reflect"
	"strconv"
	"strings"
)

func f속성값_초기화(질의값 interface{}) interface{} {
	값 := reflect.ValueOf(질의값).Elem()

	for i := 0; i < 값.NumField(); i++ {
		switch {
		case !strings.HasPrefix(값.Type().Field(i).Name, "X_"),
			값.Field(i).Kind() != reflect.Uint8,
			!값.Field(i).CanSet():
			continue
		}

		값.Field(i).SetUint(0x20)
	}

	return 값.Interface()
}

func F서버_구분() T서버_구분 {
	if 구분값, 에러 := lib.F2정수(os.Getenv(P서버_구분_환경변수명)); 에러 == nil && T서버_구분(구분값) == P서버_실거래 {
		return P서버_실거래
	} else {
		return P서버_모의투자
	}
}

func F서버_구분_설정(서버_구분 T서버_구분) {
	os.Setenv(P서버_구분_환경변수명, strconv.Itoa(int(서버_구분)))
}

func F주소_C32_호출() lib.T주소 {
	for {
		// 환경변수를 통하면 자동으로 자식 프로세스에 같은 값이 전달된다.
		if 주소, 에러 := lib.F2정수(os.Getenv(P주소_C32_호출_환경변수명)); 에러 != nil {
			F주소_설정()
		} else {
			return lib.T주소(주소)
		}
	}
}

func F주소_C32_콜백() lib.T주소 {
	for {
		// 환경변수를 통하면 자동으로 자식 프로세스에 같은 값이 전달된다.
		if 주소, 에러 := lib.F2정수(os.Getenv(P주소_C32_콜백_환경변수명)); 에러 != nil {
			F주소_설정()
		} else {
			return lib.T주소(주소)
		}
	}
}

func F주소_실시간() lib.T주소 {
	for {
		// 환경변수를 통하면 자동으로 자식 프로세스에 같은 값이 전달된다.
		if 주소, 에러 := lib.F2정수(os.Getenv(P주소_실시간_환경변수명)); 에러 != nil {
			F주소_설정()
		} else {
			return lib.T주소(주소)
		}
	}
}

func F주소_설정() {
	주소_설정_잠금.Lock()
	defer 주소_설정_잠금.Unlock()

	if 주소_설정_완료.G값() {
		return
	}

	for {
		임의_포트_번호 := lib.F임의_범위_이내_정수값(0, 30000)
		주소_C32_호출 := lib.T주소(임의_포트_번호)
		주소_C32_콜백 := lib.T주소(임의_포트_번호 + 1)
		주소_실시간 := lib.T주소(임의_포트_번호 + 2)

		if lib.F포트_닫힘_확인(주소_C32_호출) &&
			lib.F포트_닫힘_확인(주소_C32_콜백) &&
			lib.F포트_닫힘_확인(주소_실시간) {
			// 환경변수를 통하면 자동으로 자식 프로세스에 같은 값이 전달된다.
			os.Setenv(P주소_C32_호출_환경변수명, strconv.Itoa(int(주소_C32_호출)))
			os.Setenv(P주소_C32_콜백_환경변수명, strconv.Itoa(int(주소_C32_콜백)))
			os.Setenv(P주소_실시간_환경변수명, strconv.Itoa(int(주소_실시간)))
			주소_설정_완료.S값(true)

			fmt.Println("****************************************")
			fmt.Printf(" Xing API 호출 URL : %v\n", F주소_C32_호출().URL())
			fmt.Println("****************************************")

			return
		}
	}
}

func F주소_재설정() {
	주소_설정_완료.S값(false)
	F주소_설정()
}
<commit_msg>웹서버 URL 출력 문자열 수정.<commit_after>/* Copyright (C) 2015-2020 김운하 (unha.kim@ghts.org)

이 파일은 GHTS의 일부입니다.

이 프로그램은 자유 소프트웨어입니다.
소프트웨어의 피양도자는 자유 소프트웨어 재단이 공표한 GNU LGPL 2.1판
규정에 따라 프로그램을 개작하거나 재배포할 수 있습니다.

이 프로그램은 유용하게 사용될 수 있으리라는 희망에서 배포되고 있지만,
특정한 목적에 적합하다거나, 이익을 안겨줄 수 있다는 묵시적인 보증을 포함한
어떠한 형태의 보증도 제공하지 않습니다.
보다 자세한 사항에 대해서는 GNU LGPL 2.1판을 참고하시기 바랍니다.
GNU LGPL 2.1판은 이 프로그램과 함께 제공됩니다.
만약, 이 문서가 누락되어 있다면 자유 소프트웨어 재단으로 문의하시기 바랍니다.
(자유 소프트웨어 재단 : Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA)

Copyright (C) 2015-2020년 UnHa Kim (unha.kim@ghts.org)

This file is part of GHTS.

GHTS is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, version 2.1 of the License.

GHTS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with GHTS.  If not, see <http://www.gnu.org/licenses/>. */

package xt

import (
	"fmt"
	"github.com/ghts/ghts/lib"
	"os"
	"reflect"
	"strconv"
	"strings"
)

func f속성값_초기화(질의값 interface{}) interface{} {
	값 := reflect.ValueOf(질의값).Elem()

	for i := 0; i < 값.NumField(); i++ {
		switch {
		case !strings.HasPrefix(값.Type().Field(i).Name, "X_"),
			값.Field(i).Kind() != reflect.Uint8,
			!값.Field(i).CanSet():
			continue
		}

		값.Field(i).SetUint(0x20)
	}

	return 값.Interface()
}

func F서버_구분() T서버_구분 {
	if 구분값, 에러 := lib.F2정수(os.Getenv(P서버_구분_환경변수명)); 에러 == nil && T서버_구분(구분값) == P서버_실거래 {
		return P서버_실거래
	} else {
		return P서버_모의투자
	}
}

func F서버_구분_설정(서버_구분 T서버_구분) {
	os.Setenv(P서버_구분_환경변수명, strconv.Itoa(int(서버_구분)))
}

func F주소_C32_호출() lib.T주소 {
	for {
		// 환경변수를 통하면 자동으로 자식 프로세스에 같은 값이 전달된다.
		if 주소, 에러 := lib.F2정수(os.Getenv(P주소_C32_호출_환경변수명)); 에러 != nil {
			F주소_설정()
		} else {
			return lib.T주소(주소)
		}
	}
}

func F주소_C32_콜백() lib.T주소 {
	for {
		// 환경변수를 통하면 자동으로 자식 프로세스에 같은 값이 전달된다.
		if 주소, 에러 := lib.F2정수(os.Getenv(P주소_C32_콜백_환경변수명)); 에러 != nil {
			F주소_설정()
		} else {
			return lib.T주소(주소)
		}
	}
}

func F주소_실시간() lib.T주소 {
	for {
		// 환경변수를 통하면 자동으로 자식 프로세스에 같은 값이 전달된다.
		if 주소, 에러 := lib.F2정수(os.Getenv(P주소_실시간_환경변수명)); 에러 != nil {
			F주소_설정()
		} else {
			return lib.T주소(주소)
		}
	}
}

func F주소_설정() {
	주소_설정_잠금.Lock()
	defer 주소_설정_잠금.Unlock()

	if 주소_설정_완료.G값() {
		return
	}

	for {
		임의_포트_번호 := lib.F임의_범위_이내_정수값(0, 30000)
		주소_C32_호출 := lib.T주소(임의_포트_번호)
		주소_C32_콜백 := lib.T주소(임의_포트_번호 + 1)
		주소_실시간 := lib.T주소(임의_포트_번호 + 2)

		if lib.F포트_닫힘_확인(주소_C32_호출) &&
			lib.F포트_닫힘_확인(주소_C32_콜백) &&
			lib.F포트_닫힘_확인(주소_실시간) {
			// 환경변수를 통하면 자동으로 자식 프로세스에 같은 값이 전달된다.
			os.Setenv(P주소_C32_호출_환경변수명, strconv.Itoa(int(주소_C32_호출)))
			os.Setenv(P주소_C32_콜백_환경변수명, strconv.Itoa(int(주소_C32_콜백)))
			os.Setenv(P주소_실시간_환경변수명, strconv.Itoa(int(주소_실시간)))
			주소_설정_완료.S값(true)

			fmt.Println("***************************************************")
			fmt.Printf("* Xing API 호출 URL : '%v' *\n", F주소_C32_호출().URL())
			fmt.Println("***************************************************")

			return
		}
	}
}

func F주소_재설정() {
	주소_설정_완료.S값(false)
	F주소_설정()
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/codegangsta/cli"
	"github.com/elwinar/rambler/migration"
)

func Apply(c *cli.Context) {
	Env, _, Info, Error, err := bootstrap(c)
	if err != nil {
		Error.Fatalln("unable to load configuration file:", err)
	}

	s, err := migration.NewService(*Env)
	if err != nil {
		Error.Fatalln("unable to initialize the migration service:", err)
	}

	exists, err := s.MigrationTableExists()
	if err != nil {
		Error.Fatalln("failed to look for migration table:", err)
	}

	if !exists {
		Info.Println("migration table not found")
		err := s.CreateMigrationTable()
		if err != nil {
			Error.Fatalln("unable to create the migration table:", err)
		}
		Info.Println("created")
	}

	applied, err := s.ListAppliedMigrations()
	if err != nil {
		Error.Fatalln("failed to list applied migrations:", err)
	}

	available, err := s.ListAvailableMigrations()
	if err != nil {
		Error.Fatalln("failed to list available migrations:", err)
	}

	var i, j int = 0, 0
	for i < len(available) && j < len(applied) {
		if available[i] < applied[j] {
			Error.Fatalln("out of order migration", available[i])
		}

		if available[i] > applied[j] {
			Error.Fatalln("missing mgiration", applied[j])
		}

		i++
		j++
	}

	if j != len(applied) {
		Error.Fatalln("missing mgiration", applied[j])
	}

	for _, v := range available[i:] {
		m, err := migration.NewMigration(Env.Directory, v)
		if err != nil {
			Error.Fatalln("failed to retrieve migration", v, ":", err)
		}

		Info.Println("applying", m.Name)

		tx, err := s.StartTransaction()
		if err != nil {
			Error.Fatalln("failed to start transaction:", err)
		}

		for _, statement := range m.Scan("up") {
			_, sqlerr := tx.Exec(statement)

			if sqlerr != nil {
				Error.Println("migration failed:", sqlerr)
				txerr := tx.Rollback()

				if txerr != nil {
					Error.Fatalln("rollback failed:", txerr)
				}

				Error.Fatalln("successfully rolled back")
			}
		}

		err = s.SetMigrationApplied(m.Version, m.Description)
		if err != nil {
			Error.Fatalln("unable to set migration as applied:", err)
		}

		txerr := tx.Commit()
		if txerr != nil {
			Error.Fatalln("commit failed:", txerr)
		}

		if !c.Bool("all") {
			break
		}
	}

	return
}
<commit_msg>Add statements printing on debug output<commit_after>package main

import (
	"github.com/codegangsta/cli"
	"github.com/elwinar/rambler/migration"
)

func Apply(c *cli.Context) {
	Env, Debug, Info, Error, err := bootstrap(c)
	if err != nil {
		Error.Fatalln("unable to load configuration file:", err)
	}

	s, err := migration.NewService(*Env)
	if err != nil {
		Error.Fatalln("unable to initialize the migration service:", err)
	}

	exists, err := s.MigrationTableExists()
	if err != nil {
		Error.Fatalln("failed to look for migration table:", err)
	}

	if !exists {
		Info.Println("migration table not found")
		err := s.CreateMigrationTable()
		if err != nil {
			Error.Fatalln("unable to create the migration table:", err)
		}
		Info.Println("created")
	}

	applied, err := s.ListAppliedMigrations()
	if err != nil {
		Error.Fatalln("failed to list applied migrations:", err)
	}

	available, err := s.ListAvailableMigrations()
	if err != nil {
		Error.Fatalln("failed to list available migrations:", err)
	}

	var i, j int = 0, 0
	for i < len(available) && j < len(applied) {
		if available[i] < applied[j] {
			Error.Fatalln("out of order migration", available[i])
		}

		if available[i] > applied[j] {
			Error.Fatalln("missing mgiration", applied[j])
		}

		i++
		j++
	}

	if j != len(applied) {
		Error.Fatalln("missing mgiration", applied[j])
	}

	for _, v := range available[i:] {
		m, err := migration.NewMigration(Env.Directory, v)
		if err != nil {
			Error.Fatalln("failed to retrieve migration", v, ":", err)
		}

		Info.Println("applying", m.Name)

		tx, err := s.StartTransaction()
		if err != nil {
			Error.Fatalln("failed to start transaction:", err)
		}

		for _, statement := range m.Scan("up") {
			Debug.Println(statement)
			_, sqlerr := tx.Exec(statement)

			if sqlerr != nil {
				Error.Println("migration failed:", sqlerr)
				txerr := tx.Rollback()

				if txerr != nil {
					Error.Fatalln("rollback failed:", txerr)
				}

				Error.Fatalln("successfully rolled back")
			}
		}

		err = s.SetMigrationApplied(m.Version, m.Description)
		if err != nil {
			Error.Fatalln("unable to set migration as applied:", err)
		}

		txerr := tx.Commit()
		if txerr != nil {
			Error.Fatalln("commit failed:", txerr)
		}

		if !c.Bool("all") {
			break
		}
	}

	return
}
<|endoftext|>


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

// Package astar implements the A* shortest path finding algorithm.
package astar

import (
	"container/heap"
)

type Node interface{}

type Graph interface {
	Neighbours(n Node) []Node
}

type CostFunc func(a, b Node) float64

type Path []Node

func newPath(start Node) Path {
	return []Node{start}
}

func (p Path) last() Node {
	return p[len(p)-1]
}

func (p Path) cont(n Node) Path {
	newPath := make([]Node, len(p), len(p)+1)
	copy(newPath, p)
	newPath = append(newPath, n)
	return newPath
}

func (p Path) Cost(d CostFunc) (c float64) {
	for i := 1; i < len(p); i++ {
		c += d(p[i-1], p[i])
	}
	return c
}

// FindPath finds the shortest path between start and dest in graph g
// using the cost function d and the cost heuristic function h.
func FindPath(g Graph, start, dest Node, d, h CostFunc) Path {
	closed := make(map[Node]bool)

	pq := &priorityQueue{}
	heap.Init(pq)
	heap.Push(pq, &item{value: newPath(start)})

	for pq.Len() > 0 {
		p := heap.Pop(pq).(*item).value.(Path)
		if closed[p.last()] {
			continue
		}
		if p.last() == dest {
			// Path found
			return p
		}
		n := p.last()
		closed[n] = true

		for _, nb := range g.Neighbours(n) {
			newPath := p.cont(nb)
			heap.Push(pq, &item{
				value:    newPath,
				priority: newPath.Cost(d) + h(nb, dest),
			})
		}
	}

	// No path found
	return nil
}
<commit_msg>add doc comments<commit_after>// Copyright 2013 Frederik Zipp. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package astar implements the A* shortest path finding algorithm.
package astar

import (
	"container/heap"
)

// Node represents a node in a graph and can be anything.
type Node interface{}

// The Graph interface is the minimal interface a graph data structure
// must satisfy to be suitable for the A* algorithm.
type Graph interface {
	// Neighbours returns the neighbour nodes of node n in the graph.
	Neighbours(n Node) []Node
}

// A CostFunc is a function that returns a cost for the transition
// from node a to node b.
type CostFunc func(a, b Node) float64

// A Path is a sequence of nodes in a graph.
type Path []Node

func newPath(start Node) Path {
	return []Node{start}
}

func (p Path) last() Node {
	return p[len(p)-1]
}

func (p Path) cont(n Node) Path {
	newPath := make([]Node, len(p), len(p)+1)
	copy(newPath, p)
	newPath = append(newPath, n)
	return newPath
}

// Cost calculates the total cost of path p by applying the cost function d
// to all path segments and returning the sum.
func (p Path) Cost(d CostFunc) (c float64) {
	for i := 1; i < len(p); i++ {
		c += d(p[i-1], p[i])
	}
	return c
}

// FindPath finds the shortest path between start and dest in graph g
// using the cost function d and the cost heuristic function h.
func FindPath(g Graph, start, dest Node, d, h CostFunc) Path {
	closed := make(map[Node]bool)

	pq := &priorityQueue{}
	heap.Init(pq)
	heap.Push(pq, &item{value: newPath(start)})

	for pq.Len() > 0 {
		p := heap.Pop(pq).(*item).value.(Path)
		if closed[p.last()] {
			continue
		}
		if p.last() == dest {
			// Path found
			return p
		}
		n := p.last()
		closed[n] = true

		for _, nb := range g.Neighbours(n) {
			newPath := p.cont(nb)
			heap.Push(pq, &item{
				value:    newPath,
				priority: newPath.Cost(d) + h(nb, dest),
			})
		}
	}

	// No path found
	return nil
}
<|endoftext|>


<commit_before>package auth

import (
	"encoding/base64"
	"net/http"
)

func Basic(username string, password string) http.HandlerFunc {
	var siteAuth = base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
	return func(res http.ResponseWriter, req *http.Request) {
		auth := req.Header.Get("Authorization")
		if auth != "Basic "+siteAuth {
			res.Header().Set("WWW-Authenticate", "Basic realm=\"Authorization Required\"")
			http.Error(res, "Not Authorized", http.StatusUnauthorized)
		}
	}
}
<commit_msg>-n [Migrated] API Docs<commit_after>package auth

import (
	"encoding/base64"
	"net/http"
)

// Handler that authenticates via Basic Auth. Writes a http.StatusUnauthorized
// if authentication fails
func Basic(username string, password string) http.HandlerFunc {
	var siteAuth = base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
	return func(res http.ResponseWriter, req *http.Request) {
		auth := req.Header.Get("Authorization")
		if auth != "Basic "+siteAuth {
			res.Header().Set("WWW-Authenticate", "Basic realm=\"Authorization Required\"")
			http.Error(res, "Not Authorized", http.StatusUnauthorized)
		}
	}
}
<|endoftext|>


<commit_before>package dsc

import (
	"compress/gzip"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
)

type batch struct {
	processed      int
	tempDir        string
	tempFile       string
	size           int
	sql            string
	writer         *gzip.Writer
	values         []interface{}
	placeholders   string
	columns        string
	dataIndexes    []int
	firstSeq       int64
	bulkInsertType string
	manager        *AbstractManager
	sqlProvider    func(item interface{}) *ParametrizedSQL
	updateId       func(index int, seq int64)
	connection     Connection
	table          string
}

func (b *batch) flush() (int, error) {
	if b.sql == "" {
		return 0, nil
	}

	var dataIndexes = b.dataIndexes
	b.dataIndexes = []int{}
	switch b.bulkInsertType {
	case CopyLocalInsert:
		defer os.Remove(b.tempFile)
		err := b.writer.Flush()
		if err != nil {
			return 0, err
		}
		err = b.writer.Close()
		if err != nil {
			return 0, err
		}
	case BulkInsertAllType:
		b.sql += " SELECT 1 FROM DUAL"
	}
	result, err := b.manager.ExecuteOnConnection(b.connection, b.sql, b.values)
	b.dataIndexes = []int{}
	b.sql = ""
	b.values = []interface{}{}
	if err != nil {
		return 0, err
	}
	affected, err := result.RowsAffected()
	if err != nil {
		return 0, err
	}
	for _, i := range dataIndexes {
		b.firstSeq++
		b.updateId(i, b.firstSeq)
	}
	b.firstSeq = 0
	return int(affected), nil
}

func (b *batch) expandedValues(parametrizedSQL *ParametrizedSQL) string {
	recordLine := b.manager.ExpandSQL(b.placeholders, parametrizedSQL.Values)
	if breakCount := strings.Count(recordLine, "\n"); breakCount > 0 {
		recordLine = strings.Replace(recordLine, "\n", "", breakCount)
	}
	return recordLine + "\n"
}

func (b *batch) transformFirst(parametrizedSQL *ParametrizedSQL) error {
	b.sql = parametrizedSQL.SQL
	b.values = parametrizedSQL.Values
	fragment := " VALUES"
	valuesIndex := strings.Index(parametrizedSQL.SQL, fragment)
	if beginIndex := strings.Index(parametrizedSQL.SQL, "("); beginIndex != -1 {
		names := string(parametrizedSQL.SQL[beginIndex+1:])
		if endIndex := strings.Index(names, ")"); endIndex != -1 {
			b.columns = string(names[:endIndex])
		}
	}
	b.placeholders = strings.Trim(strings.TrimSpace(string(parametrizedSQL.SQL[valuesIndex+7:])), "()")
	switch b.bulkInsertType {
	case CopyLocalInsert:
		b.tempDir = b.manager.config.GetString("tempDir", os.TempDir())
		if b.columns == "" {
			return fmt.Errorf("columns were empty")
		}
		file, err := ioutil.TempFile(b.tempDir, "temp")
		if err != nil {
			return err
		}
		b.tempFile = file.Name()
		b.writer = gzip.NewWriter(file)
		if _, err := b.writer.Write([]byte(b.expandedValues(parametrizedSQL))); err != nil {
			return err
		}
		b.sql = fmt.Sprintf(`COPY %v(%v)
FROM LOCAL '%v' GZIP
DELIMITER ','
NULL AS 'null'
ENCLOSED BY ''''
`, b.table, b.columns, file.Name())
		b.values = make([]interface{}, 0)
	case UnionSelectInsert:
		valuesIndex := strings.Index(parametrizedSQL.SQL, " VALUES")
		selectAll := " SELECT " + b.expandedValues(parametrizedSQL)
		selectAll = b.manager.ExpandSQL(selectAll, parametrizedSQL.Values)
		parametrizedSQL.Values = []interface{}{}
		b.sql = b.sql[:valuesIndex] + " " + selectAll

	case BulkInsertAllType:
		b.sql = strings.Replace(b.sql, "INSERT ", "INSERT ALL ", 1)
	default:

	}
	return nil
}

func (b *batch) transformNext(parametrizedSQL *ParametrizedSQL) error {
	switch b.bulkInsertType {
	case CopyLocalInsert:
		_, err := b.writer.Write([]byte(b.expandedValues(parametrizedSQL)))
		return err
	case UnionSelectInsert:
		b.sql += "\nUNION ALL SELECT " + b.expandedValues(parametrizedSQL)
	case BulkInsertAllType:
		b.sql += fmt.Sprintf("\nINTO %v(%v) VALUES(%v)", b.table, b.columns, b.placeholders)
		b.values = append(b.values, parametrizedSQL.Values...)
	default:
		b.sql += fmt.Sprintf(",(%v)", b.placeholders)
		b.values = append(b.values, parametrizedSQL.Values...)
	}
	return nil
}

func (b *batch) persist(index int, item interface{}) error {
	parametrizedSQL := b.sqlProvider(item)
	if len(parametrizedSQL.Values) == 1 && parametrizedSQL.Type == SQLTypeUpdate {
		//nothing to udpate, one parameter is ID=? without values to update
		return nil
	}
	if parametrizedSQL.Type == SQLTypeInsert && b.size > 0 {
		if len(b.dataIndexes) > b.size {
			if _, err := b.flush(); err != nil {
				return err
			}
		}
		b.dataIndexes = append(b.dataIndexes, index)
		if isFirst := len(b.sql) == 0; isFirst {
			return b.transformFirst(parametrizedSQL)
		}
		return b.transformNext(parametrizedSQL)
	}
	result, err := b.manager.ExecuteOnConnection(b.connection, parametrizedSQL.SQL, parametrizedSQL.Values)
	if err != nil {
		return err
	}
	affected, err := result.RowsAffected()
	if err != nil {
		return err
	}
	b.processed += int(affected)
	seq, _ := result.LastInsertId()
	if b.size > 0 && b.firstSeq == 0 {
		b.firstSeq = seq
	}
	b.updateId(index, seq)
	return nil
}

func newBatch(table string, connection Connection, manager *AbstractManager, sqlProvider func(item interface{}) *ParametrizedSQL, updateId func(index int, seq int64)) *batch {
	dialect := GetDatastoreDialect(manager.Config().DriverName)
	var batchSize = manager.Config().GetInt(BatchSizeKey, defaultBatchSize)
	Logf("batch size: %v\n", batchSize)
	canUseBatch := dialect != nil && dialect.CanPersistBatch() && batchSize > 1
	if !canUseBatch {
		batchSize = 0
	}
	insertType := ""
	if dialect != nil {
		insertType = dialect.BulkInsertType()
	}
	return &batch{
		connection:     connection,
		updateId:       updateId,
		sqlProvider:    sqlProvider,
		size:           batchSize,
		values:         []interface{}{},
		dataIndexes:    []int{},
		bulkInsertType: insertType,
		manager:        manager,
		table:          table,
	}
}
<commit_msg>added dataset prefix to copy<commit_after>package dsc

import (
	"compress/gzip"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
)

type batch struct {
	processed      int
	tempDir        string
	tempFile       string
	size           int
	sql            string
	writer         *gzip.Writer
	values         []interface{}
	placeholders   string
	columns        string
	dataIndexes    []int
	firstSeq       int64
	bulkInsertType string
	manager        *AbstractManager
	sqlProvider    func(item interface{}) *ParametrizedSQL
	updateId       func(index int, seq int64)
	connection     Connection
	table          string
}

func (b *batch) flush() (int, error) {
	if b.sql == "" {
		return 0, nil
	}

	var dataIndexes = b.dataIndexes
	b.dataIndexes = []int{}
	switch b.bulkInsertType {
	case CopyLocalInsert:
		defer os.Remove(b.tempFile)
		err := b.writer.Flush()
		if err != nil {
			return 0, err
		}
		err = b.writer.Close()
		if err != nil {
			return 0, err
		}
	case BulkInsertAllType:
		b.sql += " SELECT 1 FROM DUAL"
	}
	result, err := b.manager.ExecuteOnConnection(b.connection, b.sql, b.values)
	b.dataIndexes = []int{}
	b.sql = ""
	b.values = []interface{}{}
	if err != nil {
		return 0, err
	}
	affected, err := result.RowsAffected()
	if err != nil {
		return 0, err
	}
	for _, i := range dataIndexes {
		b.firstSeq++
		b.updateId(i, b.firstSeq)
	}
	b.firstSeq = 0
	return int(affected), nil
}

func (b *batch) expandedValues(parametrizedSQL *ParametrizedSQL) string {
	recordLine := b.manager.ExpandSQL(b.placeholders, parametrizedSQL.Values)
	if breakCount := strings.Count(recordLine, "\n"); breakCount > 0 {
		recordLine = strings.Replace(recordLine, "\n", "", breakCount)
	}
	return recordLine + "\n"
}

func (b *batch) transformFirst(parametrizedSQL *ParametrizedSQL) error {
	b.sql = parametrizedSQL.SQL
	b.values = parametrizedSQL.Values
	fragment := " VALUES"
	valuesIndex := strings.Index(parametrizedSQL.SQL, fragment)
	if beginIndex := strings.Index(parametrizedSQL.SQL, "("); beginIndex != -1 {
		names := string(parametrizedSQL.SQL[beginIndex+1:])
		if endIndex := strings.Index(names, ")"); endIndex != -1 {
			b.columns = string(names[:endIndex])
		}
	}
	b.placeholders = strings.Trim(strings.TrimSpace(string(parametrizedSQL.SQL[valuesIndex+7:])), "()")
	switch b.bulkInsertType {
	case CopyLocalInsert:
		b.tempDir = b.manager.config.GetString("tempDir", os.TempDir())
		if b.columns == "" {
			return fmt.Errorf("columns were empty")
		}
		file, err := ioutil.TempFile(b.tempDir, "temp")
		if err != nil {
			return err
		}
		b.tempFile = file.Name()
		b.writer = gzip.NewWriter(file)
		if _, err := b.writer.Write([]byte(b.expandedValues(parametrizedSQL))); err != nil {
			return err
		}

		dialect := GetDatastoreDialect(b.manager.config.DriverName)
		table := b.table
		if db, _ := dialect.GetCurrentDatastore(b.manager); db != "" {
			table = db + "." + table
		}
		b.sql = fmt.Sprintf(`COPY %v(%v)
FROM LOCAL '%v' GZIP
DELIMITER ','
NULL AS 'null'
ENCLOSED BY ''''
`, table, b.columns, file.Name())
		b.values = make([]interface{}, 0)
	case UnionSelectInsert:
		valuesIndex := strings.Index(parametrizedSQL.SQL, " VALUES")
		selectAll := " SELECT " + b.expandedValues(parametrizedSQL)
		selectAll = b.manager.ExpandSQL(selectAll, parametrizedSQL.Values)
		parametrizedSQL.Values = []interface{}{}
		b.sql = b.sql[:valuesIndex] + " " + selectAll

	case BulkInsertAllType:
		b.sql = strings.Replace(b.sql, "INSERT ", "INSERT ALL ", 1)
	default:

	}
	return nil
}

func (b *batch) transformNext(parametrizedSQL *ParametrizedSQL) error {
	switch b.bulkInsertType {
	case CopyLocalInsert:
		_, err := b.writer.Write([]byte(b.expandedValues(parametrizedSQL)))
		return err
	case UnionSelectInsert:
		b.sql += "\nUNION ALL SELECT " + b.expandedValues(parametrizedSQL)
	case BulkInsertAllType:
		b.sql += fmt.Sprintf("\nINTO %v(%v) VALUES(%v)", b.table, b.columns, b.placeholders)
		b.values = append(b.values, parametrizedSQL.Values...)
	default:
		b.sql += fmt.Sprintf(",(%v)", b.placeholders)
		b.values = append(b.values, parametrizedSQL.Values...)
	}
	return nil
}

func (b *batch) persist(index int, item interface{}) error {
	parametrizedSQL := b.sqlProvider(item)
	if len(parametrizedSQL.Values) == 1 && parametrizedSQL.Type == SQLTypeUpdate {
		//nothing to udpate, one parameter is ID=? without values to update
		return nil
	}
	if parametrizedSQL.Type == SQLTypeInsert && b.size > 0 {
		if len(b.dataIndexes) > b.size {
			if _, err := b.flush(); err != nil {
				return err
			}
		}
		b.dataIndexes = append(b.dataIndexes, index)
		if isFirst := len(b.sql) == 0; isFirst {
			return b.transformFirst(parametrizedSQL)
		}
		return b.transformNext(parametrizedSQL)
	}
	result, err := b.manager.ExecuteOnConnection(b.connection, parametrizedSQL.SQL, parametrizedSQL.Values)
	if err != nil {
		return err
	}
	affected, err := result.RowsAffected()
	if err != nil {
		return err
	}
	b.processed += int(affected)
	seq, _ := result.LastInsertId()
	if b.size > 0 && b.firstSeq == 0 {
		b.firstSeq = seq
	}
	b.updateId(index, seq)
	return nil
}

func newBatch(table string, connection Connection, manager *AbstractManager, sqlProvider func(item interface{}) *ParametrizedSQL, updateId func(index int, seq int64)) *batch {
	dialect := GetDatastoreDialect(manager.Config().DriverName)
	var batchSize = manager.Config().GetInt(BatchSizeKey, defaultBatchSize)
	Logf("batch size: %v\n", batchSize)
	canUseBatch := dialect != nil && dialect.CanPersistBatch() && batchSize > 1
	if !canUseBatch {
		batchSize = 0
	}
	insertType := ""
	if dialect != nil {
		insertType = dialect.BulkInsertType()
	}
	return &batch{
		connection:     connection,
		updateId:       updateId,
		sqlProvider:    sqlProvider,
		size:           batchSize,
		values:         []interface{}{},
		dataIndexes:    []int{},
		bulkInsertType: insertType,
		manager:        manager,
		table:          table,
	}
}
<|endoftext|>


<commit_before>package bconf

import (
	"encoding/json"
	"sort"
)

type Bconf map[string]interface{}

type sortednode []struct {
	k string
	v interface{}
}

func (bc *Bconf)LoadJson(js []byte) error {
	err := json.Unmarshal(js, bc)

	if bc != nil && len(*bc) > 0 {
		*bc = normalize(*bc)
	}

	return err
}

/*
 * Normalize what we read from json by changing the data types from
 * map[string]interface{} into Bconf
 */
func normalize(bc Bconf) Bconf {
	nb := make(Bconf)
	for k, v := range(bc) {
		var nv interface{}
		switch (v.(type)) {
		case map[string]interface{}:
			nv = normalize(Bconf(v.(map[string]interface{})))
		default:
			nv = v
		}
		nb[k] = nv
	}
	return nb
}

func (bc Bconf) get(k ...string) interface{} {
	if len(k) == 0 {
		return bc
	}

	n := bc[k[0]]

	if len(k) == 1 {
		return n
	}

	switch (n.(type)) {
	case Bconf:
		return n.(Bconf).get(k[1:]...)
	}

	return nil
}

func (bc Bconf)GetNode(k ...string) Bconf {
	n := bc.get(k...)
	return Bconf(n.(Bconf))
}

func (bc Bconf)GetString(k ...string) string {
	if len(k) == 0 {
		return ""
	}
	n := bc[k[0]]
	switch (n.(type)) {
	case string:
		if len(k) == 1 {
			return n.(string)
		}
		return ""
	default:
		return n.(Bconf).GetString(k[1:]...)
	}
	return ""
}

func (bc Bconf)ForeachVal(f func(k,v string)) {
	for k, v := range(bc) {
		switch(v.(type)) {
		case string:
			f(k, v.(string))
		}
	}
}

func (sn sortednode) Len() int {
	return len(sn)
}

func (sn sortednode) Less(i, j int) bool {
	return sn[i].k < sn[j].k
}

func (sn sortednode) Swap(i, j int) {
	sn[i], sn[j] = sn[j], sn[i]
}

func (bc Bconf) tosortednode() sortednode {
	sn := make(sortednode, len(bc))
	i := 0
	for sn[i].k, sn[i].v = range(bc) {
		i++
	}
	sort.Sort(sn)
	return sn
}

func (bc Bconf)ForeachSorted(f func(k, v string)) {
	sn := bc.tosortednode()
	for _, s := range(sn) {
		switch(s.v.(type)) {
		case string:
			f(s.k, s.v.(string))
		}
	}
}
<commit_msg>Fail in GetNode if we didn't find a node instead of doing a brutal cast that might fail.<commit_after>package bconf

import (
	"encoding/json"
	"sort"
)

type Bconf map[string]interface{}

type sortednode []struct {
	k string
	v interface{}
}

func (bc *Bconf)LoadJson(js []byte) error {
	err := json.Unmarshal(js, bc)

	if bc != nil && len(*bc) > 0 {
		*bc = normalize(*bc)
	}

	return err
}

/*
 * Normalize what we read from json by changing the data types from
 * map[string]interface{} into Bconf
 */
func normalize(bc Bconf) Bconf {
	nb := make(Bconf)
	for k, v := range(bc) {
		var nv interface{}
		switch (v.(type)) {
		case map[string]interface{}:
			nv = normalize(Bconf(v.(map[string]interface{})))
		default:
			nv = v
		}
		nb[k] = nv
	}
	return nb
}

func (bc Bconf) get(k ...string) interface{} {
	if len(k) == 0 {
		return bc
	}

	n := bc[k[0]]

	if len(k) == 1 {
		return n
	}

	switch (n.(type)) {
	case Bconf:
		return n.(Bconf).get(k[1:]...)
	}

	return nil
}

func (bc Bconf)GetNode(k ...string) Bconf {
	n := bc.get(k...)
	switch (n.(type)) {
	case Bconf:
		return n
	}
	return nil
}

func (bc Bconf)GetString(k ...string) string {
	if len(k) == 0 {
		return ""
	}
	n := bc[k[0]]
	switch (n.(type)) {
	case string:
		if len(k) == 1 {
			return n.(string)
		}
		return ""
	default:
		return n.(Bconf).GetString(k[1:]...)
	}
	return ""
}

func (bc Bconf)ForeachVal(f func(k,v string)) {
	for k, v := range(bc) {
		switch(v.(type)) {
		case string:
			f(k, v.(string))
		}
	}
}

func (sn sortednode) Len() int {
	return len(sn)
}

func (sn sortednode) Less(i, j int) bool {
	return sn[i].k < sn[j].k
}

func (sn sortednode) Swap(i, j int) {
	sn[i], sn[j] = sn[j], sn[i]
}

func (bc Bconf) tosortednode() sortednode {
	sn := make(sortednode, len(bc))
	i := 0
	for sn[i].k, sn[i].v = range(bc) {
		i++
	}
	sort.Sort(sn)
	return sn
}

func (bc Bconf)ForeachSorted(f func(k, v string)) {
	sn := bc.tosortednode()
	for _, s := range(sn) {
		switch(s.v.(type)) {
		case string:
			f(s.k, s.v.(string))
		}
	}
}
<|endoftext|>