<commit_before>package cmd

import (
	"fmt"
	"os"

	"github.com/ncw/rclone/fs"
	"github.com/ncw/rclone/fs/config/configflags"
	"github.com/ncw/rclone/fs/filter/filterflags"
	"github.com/ncw/rclone/fs/rc/rcflags"
	"github.com/ncw/rclone/lib/atexit"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

// Root is the main rclone command
var Root = &cobra.Command{
	Use:   "rclone",
	Short: "Sync files and directories to and from local and remote object stores - " + fs.Version,
	Long: `
Rclone syncs files to and from cloud storage providers as well as
mounting them, listing them in lots of different ways.

See the home page (https://rclone.org/) for installation, usage,
documentation, changelog and configuration walkthroughs.

`,
	PersistentPostRun: func(cmd *cobra.Command, args []string) {
		fs.Debugf("rclone", "Version %q finishing with parameters %q", fs.Version, os.Args)
		atexit.Run()
	},
}

// root help command
var helpCommand = &cobra.Command{
	Use:   "help",
	Short: Root.Short,
	Long:  Root.Long,
}

// Show the flags
var helpFlags = &cobra.Command{
	Use:   "flags",
	Short: "Show the global flags for rclone",
	Run: func(command *cobra.Command, args []string) {
		_ = command.Usage()
	},
}

// runRoot implements the main rclone command with no subcommands
func runRoot(cmd *cobra.Command, args []string) {
	if version {
		ShowVersion()
		resolveExitCode(nil)
	} else {
		_ = cmd.Usage()
		if len(args) > 0 {
			_, _ = fmt.Fprintf(os.Stderr, "Command not found.\n")
		}
		resolveExitCode(errorCommandNotFound)
	}
}

// setupRootCommand sets default usage, help, and error handling for
// the root command.
//
// Helpful example: http://rtfcode.com/xref/moby-17.03.2-ce/cli/cobra.go
func setupRootCommand(rootCmd *cobra.Command) {
	// Add global flags
	configflags.AddFlags(pflag.CommandLine)
	filterflags.AddFlags(pflag.CommandLine)
	rcflags.AddFlags(pflag.CommandLine)

	Root.Run = runRoot
	Root.Flags().BoolVarP(&version, "version", "V", false, "Print the version number")

	cobra.AddTemplateFunc("showGlobalFlags", func(cmd *cobra.Command) bool {
		return cmd.CalledAs() == "flags"
	})
	cobra.AddTemplateFunc("showCommands", func(cmd *cobra.Command) bool {
		return cmd.CalledAs() != "flags"
	})
	cobra.AddTemplateFunc("showLocalFlags", func(cmd *cobra.Command) bool {
		return cmd.CalledAs() != "rclone"
	})
	cobra.AddTemplateFunc("backendFlags", func(cmd *cobra.Command, include bool) *pflag.FlagSet {
		backendFlagSet := pflag.NewFlagSet("Backend Flags", pflag.ExitOnError)
		cmd.InheritedFlags().VisitAll(func(flag *pflag.Flag) {
			if _, ok := backendFlags[flag.Name]; ok == include {
				backendFlagSet.AddFlag(flag)
			}
		})
		return backendFlagSet
	})
	rootCmd.SetUsageTemplate(usageTemplate)
	// rootCmd.SetHelpTemplate(helpTemplate)
	// rootCmd.SetFlagErrorFunc(FlagErrorFunc)
	rootCmd.SetHelpCommand(helpCommand)
	// rootCmd.PersistentFlags().BoolP("help", "h", false, "Print usage")
	// rootCmd.PersistentFlags().MarkShorthandDeprecated("help", "please use --help")

	rootCmd.AddCommand(helpCommand)
	helpCommand.AddCommand(helpFlags)
	// rootCmd.AddCommand(helpBackend)
	// rootCmd.AddCommand(helpBackends)

	cobra.OnInitialize(initConfig)

}

var usageTemplate = `Usage:{{if .Runnable}}
  {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}}
  {{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}}

Aliases:
  {{.NameAndAliases}}{{end}}{{if .HasExample}}

Examples:
{{.Example}}{{end}}{{if and (showCommands .) .HasAvailableSubCommands}}

Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}}
  {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if and (showLocalFlags .) .HasAvailableLocalFlags}}

Flags:
{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if and (showGlobalFlags .) .HasAvailableInheritedFlags}}

Global Flags:
{{(backendFlags . false).FlagUsages | trimTrailingWhitespaces}}

Backend Flags:
{{(backendFlags . true).FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}}

Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}}
  {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}

Use "{{.CommandPath}} [command] --help" for more information about a command.
Use "rclone help flags" for more information about global flags.
Use "rclone help backends" for a list of supported services.
`
<commit_msg>cmd: Implement specialised help for flags and backends - fixes #2541<commit_after>package cmd

import (
	"fmt"
	"log"
	"os"
	"regexp"
	"strings"

	"github.com/ncw/rclone/fs"
	"github.com/ncw/rclone/fs/config/configflags"
	"github.com/ncw/rclone/fs/filter/filterflags"
	"github.com/ncw/rclone/fs/rc/rcflags"
	"github.com/ncw/rclone/lib/atexit"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

// Root is the main rclone command
var Root = &cobra.Command{
	Use:   "rclone",
	Short: "Show help for rclone commands, flags and backends.",
	Long: `
Rclone syncs files to and from cloud storage providers as well as
mounting them, listing them in lots of different ways.

See the home page (https://rclone.org/) for installation, usage,
documentation, changelog and configuration walkthroughs.

`,
	PersistentPostRun: func(cmd *cobra.Command, args []string) {
		fs.Debugf("rclone", "Version %q finishing with parameters %q", fs.Version, os.Args)
		atexit.Run()
	},
}

// root help command
var helpCommand = &cobra.Command{
	Use:   "help",
	Short: Root.Short,
	Long:  Root.Long,
	Run: func(command *cobra.Command, args []string) {
		Root.SetOutput(os.Stdout)
		_ = Root.Usage()
	},
}

// to filter the flags with
var flagsRe *regexp.Regexp

// Show the flags
var helpFlags = &cobra.Command{
	Use:   "flags [<regexp to match>]",
	Short: "Show the global flags for rclone",
	Run: func(command *cobra.Command, args []string) {
		if len(args) > 0 {
			re, err := regexp.Compile(args[0])
			if err != nil {
				log.Fatalf("Failed to compile flags regexp: %v", err)
			}
			flagsRe = re
		}
		Root.SetOutput(os.Stdout)
		_ = command.Usage()
	},
}

// Show the backends
var helpBackends = &cobra.Command{
	Use:   "backends",
	Short: "List the backends available",
	Run: func(command *cobra.Command, args []string) {
		showBackends()
	},
}

// Show a single backend
var helpBackend = &cobra.Command{
	Use:   "backend <name>",
	Short: "List full info about a backend",
	Run: func(command *cobra.Command, args []string) {
		if len(args) == 0 {
			Root.SetOutput(os.Stdout)
			_ = command.Usage()
			return
		}
		showBackend(args[0])
	},
}

// runRoot implements the main rclone command with no subcommands
func runRoot(cmd *cobra.Command, args []string) {
	if version {
		ShowVersion()
		resolveExitCode(nil)
	} else {
		_ = cmd.Usage()
		if len(args) > 0 {
			_, _ = fmt.Fprintf(os.Stderr, "Command not found.\n")
		}
		resolveExitCode(errorCommandNotFound)
	}
}

// setupRootCommand sets default usage, help, and error handling for
// the root command.
//
// Helpful example: http://rtfcode.com/xref/moby-17.03.2-ce/cli/cobra.go
func setupRootCommand(rootCmd *cobra.Command) {
	// Add global flags
	configflags.AddFlags(pflag.CommandLine)
	filterflags.AddFlags(pflag.CommandLine)
	rcflags.AddFlags(pflag.CommandLine)

	Root.Run = runRoot
	Root.Flags().BoolVarP(&version, "version", "V", false, "Print the version number")

	cobra.AddTemplateFunc("showGlobalFlags", func(cmd *cobra.Command) bool {
		return cmd.CalledAs() == "flags"
	})
	cobra.AddTemplateFunc("showCommands", func(cmd *cobra.Command) bool {
		return cmd.CalledAs() != "flags"
	})
	cobra.AddTemplateFunc("showLocalFlags", func(cmd *cobra.Command) bool {
		// Don't show local flags (which are the global ones on the root) on "rclone" and
		// "rclone help" (which shows the global help)
		return cmd.CalledAs() != "rclone" && cmd.CalledAs() != ""
	})
	cobra.AddTemplateFunc("backendFlags", func(cmd *cobra.Command, include bool) *pflag.FlagSet {
		backendFlagSet := pflag.NewFlagSet("Backend Flags", pflag.ExitOnError)
		cmd.InheritedFlags().VisitAll(func(flag *pflag.Flag) {
			matched := flagsRe == nil || flagsRe.MatchString(flag.Name)
			if _, ok := backendFlags[flag.Name]; matched && ok == include {
				backendFlagSet.AddFlag(flag)
			}
		})
		return backendFlagSet
	})
	rootCmd.SetUsageTemplate(usageTemplate)
	// rootCmd.SetHelpTemplate(helpTemplate)
	// rootCmd.SetFlagErrorFunc(FlagErrorFunc)
	rootCmd.SetHelpCommand(helpCommand)
	// rootCmd.PersistentFlags().BoolP("help", "h", false, "Print usage")
	// rootCmd.PersistentFlags().MarkShorthandDeprecated("help", "please use --help")

	rootCmd.AddCommand(helpCommand)
	helpCommand.AddCommand(helpFlags)
	helpCommand.AddCommand(helpBackends)
	helpCommand.AddCommand(helpBackend)

	cobra.OnInitialize(initConfig)

}

var usageTemplate = `Usage:{{if .Runnable}}
  {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}}
  {{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}}

Aliases:
  {{.NameAndAliases}}{{end}}{{if .HasExample}}

Examples:
{{.Example}}{{end}}{{if and (showCommands .) .HasAvailableSubCommands}}

Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}}
  {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if and (showLocalFlags .) .HasAvailableLocalFlags}}

Flags:
{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if and (showGlobalFlags .) .HasAvailableInheritedFlags}}

Global Flags:
{{(backendFlags . false).FlagUsages | trimTrailingWhitespaces}}

Backend Flags:
{{(backendFlags . true).FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}}

Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}}
  {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}

Use "rclone [command] --help" for more information about a command.
Use "rclone help flags" for to see the global flags.
Use "rclone help backends" for a list of supported services.
`

// show all the backends
func showBackends() {
	fmt.Printf("All rclone backends:\n\n")
	for _, backend := range fs.Registry {
		fmt.Printf("  %-12s %s\n", backend.Prefix, backend.Description)
	}
	fmt.Printf("\nTo see more info about a particular backend use:\n")
	fmt.Printf("  rclone help backend <name>\n")
}

func quoteString(v interface{}) string {
	switch v.(type) {
	case string:
		return fmt.Sprintf("%q", v)
	}
	return fmt.Sprint(v)
}

// show a single backend
func showBackend(name string) {
	backend, err := fs.Find(name)
	if err != nil {
		log.Fatal(err)
	}
	var standardOptions, advancedOptions fs.Options
	done := map[string]struct{}{}
	for _, opt := range backend.Options {
		// Skip if done already (eg with Provider options)
		if _, doneAlready := done[opt.Name]; doneAlready {
			continue
		}
		if opt.Advanced {
			advancedOptions = append(advancedOptions, opt)
		} else {
			standardOptions = append(standardOptions, opt)
		}
	}
	optionsType := "standard"
	for _, opts := range []fs.Options{standardOptions, advancedOptions} {
		if len(opts) == 0 {
			continue
		}
		fmt.Printf("### %s Options\n\n", strings.Title(optionsType))
		fmt.Printf("Here are the %s options specific to %s (%s).\n\n", optionsType, backend.Name, backend.Description)
		optionsType = "advanced"
		for _, opt := range opts {
			done[opt.Name] = struct{}{}
			fmt.Printf("#### --%s\n\n", opt.FlagName(backend.Prefix))
			fmt.Printf("%s\n\n", opt.Help)
			fmt.Printf("- Config:      %s\n", opt.Name)
			fmt.Printf("- Env Var:     %s\n", opt.EnvVarName(backend.Prefix))
			fmt.Printf("- Type:        %s\n", opt.Type())
			fmt.Printf("- Default:     %s\n", quoteString(opt.GetValue()))
			if len(opt.Examples) > 0 {
				fmt.Printf("- Examples:\n")
				for _, ex := range opt.Examples {
					fmt.Printf("    - %s\n", quoteString(ex.Value))
					for _, line := range strings.Split(ex.Help, "\n") {
						fmt.Printf("        - %s\n", line)
					}
				}
			}
			fmt.Printf("\n")
		}
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"path"

	"github.com/blang/semver"

	"github.com/containerum/chkit/pkg/client"
	"github.com/sirupsen/logrus"
	cli "gopkg.in/urfave/cli.v2"
)

const (
	Version        = "3.0.0-alpha"
	containerumAPI = "https://94.130.09.147:8082"
	FlagConfigFile = "config"
	FlagAPIaddr    = "apiaddr"
)

func Run(args []string) error {
	log := logrus.New()
	log.Formatter = &logrus.TextFormatter{}
	log.Level = logrus.InfoLevel

	configPath, err := configPath()
	if err != nil {
		log.WithError(err).
			Errorf("error while getting homedir path")
		return err
	}
	var App = &cli.App{
		Name:    "chkit",
		Usage:   "containerum cli",
		Version: semver.MustParse(Version).String(),
		Action: func(ctx *cli.Context) error {
			err := setupClient(ctx)
			if err != nil {
				log.Error(err)
				return err
			}
			clientConfig := getClient(ctx).Config
			log.Infof("logged as %q", clientConfig.Username)
			return err
		},
		Metadata: map[string]interface{}{
			"client":     chClient.Client{},
			"configPath": configPath,
			"log":        log,
		},
		Commands: []*cli.Command{
			commandLogin,
		},
		Flags: []cli.Flag{
			&cli.StringFlag{
				Name:    "config",
				Usage:   "config file",
				Aliases: []string{"c"},
				Value:   path.Join(configPath, "config.toml"),
			},
			&cli.StringFlag{
				Name:    "api",
				Usage:   "API address",
				Value:   containerumAPI,
				Hidden:  true,
				EnvVars: []string{"CONTAINERUM_API"},
			},
		},
	}
	return App.Run(args)
}
<commit_msg>refactor<commit_after>package cmd

import (
	"path"

	"github.com/blang/semver"

	"github.com/containerum/chkit/pkg/client"
	"github.com/sirupsen/logrus"
	cli "gopkg.in/urfave/cli.v2"
)

const (
	Version        = "3.0.0-alpha"
	containerumAPI = "https://94.130.09.147:8082"
	FlagConfigFile = "config"
	FlagAPIaddr    = "apiaddr"
)

func Run(args []string) error {
	log := logrus.New()
	log.Formatter = &logrus.TextFormatter{}
	log.Level = logrus.InfoLevel

	configPath, err := configPath()
	if err != nil {
		log.WithError(err).
			Errorf("error while getting homedir path")
		return err
	}
	var App = &cli.App{
		Name:    "chkit",
		Usage:   "containerum cli",
		Version: semver.MustParse(Version).String(),
		Action: func(ctx *cli.Context) error {
			err := configurate(ctx)
			if err != nil {
				log.Error(err)
				return err
			}
			clientConfig := getClient(ctx).Config
			log.Infof("logged as %q", clientConfig.Username)
			return err
		},
		Metadata: map[string]interface{}{
			"client":     chClient.Client{},
			"configPath": configPath,
			"log":        log,
		},
		Commands: []*cli.Command{
			commandLogin,
		},
		Flags: []cli.Flag{
			&cli.StringFlag{
				Name:    "config",
				Usage:   "config file",
				Aliases: []string{"c"},
				Value:   path.Join(configPath, "config.toml"),
			},
			&cli.StringFlag{
				Name:    "api",
				Usage:   "API address",
				Value:   containerumAPI,
				Hidden:  true,
				EnvVars: []string{"CONTAINERUM_API"},
			},
		},
	}
	return App.Run(args)
}
<|endoftext|>


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

package cmd

import (
	"fmt"
	"os"
	"strconv"

	fqdn "github.com/ShowMax/go-fqdn"
	humanize "github.com/dustin/go-humanize"
	"github.com/olekukonko/tablewriter"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"github.com/veino/bitfan/lib"
	"github.com/veino/veino/runtime"
)

func init() {
	RootCmd.AddCommand(listCmd)
	listCmd.Flags().StringP("host", "H", "127.0.0.1:5123", "Service Host to connect to")
}

// listCmd represents the list command
var listCmd = &cobra.Command{
	Use:     "list",
	Short:   "List running pipelines",
	Aliases: []string{"ls"},
	Long:    ``,
	PreRun: func(cmd *cobra.Command, args []string) {
		viper.BindPFlag("host", cmd.Flags().Lookup("host"))
	},
	Run: func(cmd *cobra.Command, args []string) {
		// TODO: Work your own magic here
		s := lib.ApiClient(viper.GetString("host"))

		// Send a request & read result
		var pipelines = map[int]*runtime.Pipeline{}
		if err := s.Request("findPipelines", "", &pipelines); err != nil {
			fmt.Printf("list error: %v\n", err.Error())
		} else {

			table := tablewriter.NewWriter(os.Stdout)
			table.SetHeader([]string{
				"ID",
				"name",
				"Started",
				"configuration",
			})

			for _, pipeline := range pipelines {
				host := ""
				if pipeline.ConfigHostLocation != fqdn.Get() {
					host = pipeline.ConfigHostLocation + "@"
				}

				table.Append([]string{
					strconv.Itoa(pipeline.ID),
					pipeline.Label,
					humanize.Time(pipeline.StartedAt),
					fmt.Sprintf("%s%s",
						host,
						pipeline.ConfigLocation),
				})
			}
			// table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false})
			table.SetCenterSeparator("+")
			table.Render()

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

package cmd

import (
	"fmt"
	"os"
	"strconv"

	fqdn "github.com/ShowMax/go-fqdn"
	"github.com/olekukonko/tablewriter"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"github.com/veino/bitfan/lib"
	"github.com/veino/veino/runtime"
)

func init() {
	RootCmd.AddCommand(listCmd)
	listCmd.Flags().StringP("host", "H", "127.0.0.1:5123", "Service Host to connect to")
}

// listCmd represents the list command
var listCmd = &cobra.Command{
	Use:     "list",
	Short:   "List running pipelines",
	Aliases: []string{"ls"},
	Long:    ``,
	PreRun: func(cmd *cobra.Command, args []string) {
		viper.BindPFlag("host", cmd.Flags().Lookup("host"))
	},
	Run: func(cmd *cobra.Command, args []string) {
		// TODO: Work your own magic here
		s := lib.ApiClient(viper.GetString("host"))

		// Send a request & read result
		var pipelines = map[int]*runtime.Pipeline{}
		if err := s.Request("findPipelines", "", &pipelines); err != nil {
			fmt.Printf("list error: %v\n", err.Error())
		} else {

			table := tablewriter.NewWriter(os.Stdout)
			table.SetHeader([]string{
				"ID",
				"name",
				"configuration",
			})

			for _, pipeline := range pipelines {
				host := ""
				if pipeline.ConfigHostLocation != fqdn.Get() {
					host = pipeline.ConfigHostLocation + "@"
				}

				table.Append([]string{
					strconv.Itoa(pipeline.ID),
					pipeline.Label,
					fmt.Sprintf("%s%s",
						host,
						pipeline.ConfigLocation),
				})
			}
			// table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false})
			table.SetCenterSeparator("+")
			table.Render()

		}
	},
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/hex"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"strings"

	sphinx "github.com/LightningNetwork/lightning-onion"
	"github.com/roasbeef/btcd/btcec"
	"github.com/roasbeef/btcd/chaincfg"
)

func main() {
	args := os.Args

	assocData := bytes.Repeat([]byte{'B'}, 32)

	if len(args) == 1 {
		fmt.Printf("Usage: %s (generate|decode) <private-keys>\n", args[0])
	} else if args[1] == "generate" {
		var privKeys []*btcec.PrivateKey
		var route []*btcec.PublicKey
		for i, hexKey := range args[2:] {
			binKey, err := hex.DecodeString(hexKey)
			if err != nil || len(binKey) != 32 {
				log.Fatalf("%s is not a valid hex privkey %s", hexKey, err)
			}
			privkey, pubkey := btcec.PrivKeyFromBytes(btcec.S256(), binKey)
			route = append(route, pubkey)
			privKeys = append(privKeys, privkey)
			fmt.Fprintf(os.Stderr, "Node %d pubkey %x\n", i, pubkey.SerializeCompressed())
		}

		sessionKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), bytes.Repeat([]byte{'A'}, 32))

		var hopPayloads [][]byte
		for i := 0; i < len(route); i++ {
			payload := bytes.Repeat([]byte{'A'}, 20)
			hopPayloads = append(hopPayloads, payload)
		}

		msg, err := sphinx.NewOnionPacket(route, sessionKey, hopPayloads, assocData)
		if err != nil {
			log.Fatalf("Error creating message: %v", err)
		}

		w := bytes.NewBuffer([]byte{})
		err = msg.Encode(w)

		if err != nil {
			log.Fatalf("Error serializing message: %v", err)
		}

		fmt.Printf("%x\n", w.Bytes())
	} else if args[1] == "decode" {
		binKey, err := hex.DecodeString(args[2])
		if len(binKey) != 32 || err != nil {
			log.Fatalf("Argument not a valid hex private key")
		}

		hexBytes, _ := ioutil.ReadAll(os.Stdin)
		binMsg, err := hex.DecodeString(strings.TrimSpace(string(hexBytes)))
		if err != nil {
			log.Fatalf("Error decoding message: %s", err)
		}

		privkey, _ := btcec.PrivKeyFromBytes(btcec.S256(), binKey)
		s := sphinx.NewRouter(privkey, &chaincfg.TestNet3Params)

		var packet sphinx.OnionPacket
		err = packet.Decode(bytes.NewBuffer(binMsg))

		if err != nil {
			log.Fatalf("Error parsing message: %v", err)
		}
		p, err := s.ProcessOnionPacket(&packet, assocData)
		if err != nil {
			log.Fatalf("Failed to decode message: %s", err)
		}

		w := bytes.NewBuffer([]byte{})
		err = p.Packet.Encode(w)

		if err != nil {
			log.Fatalf("Error serializing message: %v", err)
		}
		fmt.Printf("%x\n", w.Bytes())
	}
}
<commit_msg>cmd/main: use lower-case import path for LightningNetwork<commit_after>package main

import (
	"bytes"
	"encoding/hex"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"strings"

	sphinx "github.com/lightningnetwork/lightning-onion"
	"github.com/roasbeef/btcd/btcec"
	"github.com/roasbeef/btcd/chaincfg"
)

// main implements a simple command line utility that can be used in order to
// either generate a fresh mix-header or decode and fully process an existing
// one given a private key.
func main() {
	args := os.Args

	assocData := bytes.Repeat([]byte{'B'}, 32)

	if len(args) == 1 {
		fmt.Printf("Usage: %s (generate|decode) <private-keys>\n", args[0])
	} else if args[1] == "generate" {
		var privKeys []*btcec.PrivateKey
		var route []*btcec.PublicKey
		for i, hexKey := range args[2:] {
			binKey, err := hex.DecodeString(hexKey)
			if err != nil || len(binKey) != 32 {
				log.Fatalf("%s is not a valid hex privkey %s", hexKey, err)
			}
			privkey, pubkey := btcec.PrivKeyFromBytes(btcec.S256(), binKey)
			route = append(route, pubkey)
			privKeys = append(privKeys, privkey)
			fmt.Fprintf(os.Stderr, "Node %d pubkey %x\n", i, pubkey.SerializeCompressed())
		}

		sessionKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), bytes.Repeat([]byte{'A'}, 32))

		var hopPayloads [][]byte
		for i := 0; i < len(route); i++ {
			payload := bytes.Repeat([]byte{'A'}, 20)
			hopPayloads = append(hopPayloads, payload)
		}

		msg, err := sphinx.NewOnionPacket(route, sessionKey, hopPayloads, assocData)
		if err != nil {
			log.Fatalf("Error creating message: %v", err)
		}

		w := bytes.NewBuffer([]byte{})
		err = msg.Encode(w)

		if err != nil {
			log.Fatalf("Error serializing message: %v", err)
		}

		fmt.Printf("%x\n", w.Bytes())
	} else if args[1] == "decode" {
		binKey, err := hex.DecodeString(args[2])
		if len(binKey) != 32 || err != nil {
			log.Fatalf("Argument not a valid hex private key")
		}

		hexBytes, _ := ioutil.ReadAll(os.Stdin)
		binMsg, err := hex.DecodeString(strings.TrimSpace(string(hexBytes)))
		if err != nil {
			log.Fatalf("Error decoding message: %s", err)
		}

		privkey, _ := btcec.PrivKeyFromBytes(btcec.S256(), binKey)
		s := sphinx.NewRouter(privkey, &chaincfg.TestNet3Params)

		var packet sphinx.OnionPacket
		err = packet.Decode(bytes.NewBuffer(binMsg))

		if err != nil {
			log.Fatalf("Error parsing message: %v", err)
		}
		p, err := s.ProcessOnionPacket(&packet, assocData)
		if err != nil {
			log.Fatalf("Failed to decode message: %s", err)
		}

		w := bytes.NewBuffer([]byte{})
		err = p.Packet.Encode(w)

		if err != nil {
			log.Fatalf("Error serializing message: %v", err)
		}
		fmt.Printf("%x\n", w.Bytes())
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"github.com/qiniu/qshell/v2/iqshell"
	"github.com/qiniu/qshell/v2/iqshell/common/config"
	"github.com/qiniu/qshell/v2/iqshell/common/data"
	"github.com/spf13/cobra"
	"os"
)

var cfg iqshell.Config

const (
	bash_completion_func = `__qshell_parse_get()
{
    local qshell_output out
    if qshell_output=$(qshell user ls --name 2>/dev/null); then
        out=($(echo "${qshell_output}"))
        COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) )
    fi
}

__qshell_get_resource()
{
    __qshell_parse_get
    if [[ $? -eq 0 ]]; then
        return 0
    fi
}

__custom_func() {
    case ${last_command} in
        qshell_user_cu)
            __qshell_get_resource
            return
            ;;
        *)
            ;;
    esac
}
`
)

// rootCmd cobra root cmd, all other commands is children or subchildren of this root cmd
var rootCmd = &cobra.Command{
	Use:                    "qshell",
	Short:                  "Qiniu commandline tool for managing your bucket and CDN",
	Version:                data.Version,
	BashCompletionFunction: bash_completion_func,
}

func init() {
	cfg = iqshell.Config{
		DebugEnable:    false,
		DDebugEnable:   false,
		ConfigFilePath: "",
		Local:          false,
		CmdCfg: config.Config{
			Credentials: nil,
			UseHttps:    "",
			Hosts:       &config.Hosts{},
			Up:          &config.Up{},
			Download:    &config.Download{},
		},
	}
	rootCmd.PersistentFlags().BoolVarP(&cfg.DebugEnable, "debug", "d", false, "debug mode")
	// ddebug 开启 client debug
	rootCmd.PersistentFlags().BoolVarP(&cfg.DDebugEnable, "ddebug", "D", false, "deep debug mode")
	rootCmd.PersistentFlags().StringVarP(&cfg.ConfigFilePath, "config", "C", "", "config file (default is $HOME/.qshell.json)")
	rootCmd.PersistentFlags().BoolVarP(&cfg.Local, "local", "L", false, "use current directory as config file path")
}

func loadConfig() {
	err := iqshell.Load(cfg)

	if err != nil {
		_, _ = fmt.Fprintf(os.Stderr, "load error: %v\n", err)
		os.Exit(data.STATUS_ERROR)
	}
}

func Execute() {
	if err := rootCmd.Execute(); err != nil {
		_, _ = fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(1)
	}
}
<commit_msg>adjust root cfg init<commit_after>package cmd

import (
	"fmt"
	"github.com/qiniu/go-sdk/v7/storage"
	"github.com/qiniu/qshell/v2/iqshell"
	"github.com/qiniu/qshell/v2/iqshell/common/config"
	"github.com/qiniu/qshell/v2/iqshell/common/data"
	"github.com/spf13/cobra"
	"os"
)

var cfg = iqshell.Config{
	DebugEnable:    false,
	DDebugEnable:   false,
	ConfigFilePath: "",
	Local:          false,
	CmdCfg: config.Config{
		Credentials: nil,
		UseHttps:    "",
		Hosts:       &config.Hosts{},
		Up:          &config.Up{
			LogSetting: &config.LogSetting{},
			Tasks: &config.Tasks{},
			Retry: &config.Retry{},
			Policy: &storage.PutPolicy{},
		},
		Download:    &config.Download{
			LogSetting: &config.LogSetting{},
			Tasks: &config.Tasks{},
			Retry: &config.Retry{},
		},
	},
}

const (
	bash_completion_func = `__qshell_parse_get()
{
    local qshell_output out
    if qshell_output=$(qshell user ls --name 2>/dev/null); then
        out=($(echo "${qshell_output}"))
        COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) )
    fi
}

__qshell_get_resource()
{
    __qshell_parse_get
    if [[ $? -eq 0 ]]; then
        return 0
    fi
}

__custom_func() {
    case ${last_command} in
        qshell_user_cu)
            __qshell_get_resource
            return
            ;;
        *)
            ;;
    esac
}
`
)

// rootCmd cobra root cmd, all other commands is children or subchildren of this root cmd
var rootCmd = &cobra.Command{
	Use:                    "qshell",
	Short:                  "Qiniu commandline tool for managing your bucket and CDN",
	Version:                data.Version,
	BashCompletionFunction: bash_completion_func,
}

func init() {
	rootCmd.PersistentFlags().BoolVarP(&cfg.DebugEnable, "debug", "d", false, "debug mode")
	// ddebug 开启 client debug
	rootCmd.PersistentFlags().BoolVarP(&cfg.DDebugEnable, "ddebug", "D", false, "deep debug mode")
	rootCmd.PersistentFlags().StringVarP(&cfg.ConfigFilePath, "config", "C", "", "config file (default is $HOME/.qshell.json)")
	rootCmd.PersistentFlags().BoolVarP(&cfg.Local, "local", "L", false, "use current directory as config file path")
}

func loadConfig() {
	err := iqshell.Load(cfg)

	if err != nil {
		_, _ = fmt.Fprintf(os.Stderr, "load error: %v\n", err)
		os.Exit(data.STATUS_ERROR)
	}
}

func Execute() {
	if err := rootCmd.Execute(); err != nil {
		_, _ = fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"context"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"regexp"
	"strconv"
	"strings"
	"unicode"
	"unicode/utf8"

	"github.com/PuerkitoBio/goquery"
	"github.com/fatih/color"
	"github.com/spf13/cobra"
)

var (
	errColor   func(string, ...interface{}) string = color.HiYellowString
	countColor func(string, ...interface{}) string = color.HiYellowString
)

type exitCode int

const (
	normal exitCode = iota
	abnormal
)

func (c exitCode) Exit() {
	os.Exit(int(c))
}

func newRootCmd(newOut, newErr io.Writer, args []string) *cobra.Command {

	cmd := &cobra.Command{
		Use:           "kuroneko [flags] 伝票番号",
		Short:         "ヤマト運輸のステータス取得",
		SilenceErrors: true,
		SilenceUsage:  true,

		Args: func(cmd *cobra.Command, args []string) error {
			if len(args) > 1 {
				count := strconv.Itoa(len(args))
				return fmt.Errorf("accepts at most 1 arg(s), received %s", errColor(count))
			}

			if len(args) == 0 {
				return coloredError("伝票番号を入力してください")
			}

			return nil
		},

		PreRunE: func(cmd *cobra.Command, args []string) error {
			flagCount := cmd.Flags().NFlag()
			if flagCount > 1 {
				count := strconv.Itoa(flagCount)
				return fmt.Errorf("accepte at most 1 flag(s), received %s", errColor(count))
			}

			serial, err := cmd.Flags().GetInt("serial")
			if err != nil {
				return err
			}

			if serial < 1 || serial > 10 {
				return coloredError("連番で取得できるのは 1~10件 までです")
			}

			return nil
		},

		RunE: func(cmd *cobra.Command, args []string) error {
			trackingNumber := args[0]
			tracker := newTracker(cmd)
			return tracker.track(trackingNumber)
		},
	}

	cmd.Flags().IntP("serial", "s", 1, "連番取得(10件まで)")
	cmd.SetArgs(args)
	cmd.SetOut(newOut)
	cmd.SetErr(newErr)

	return cmd
}

func Execute(newOut, newErr io.Writer, args []string) exitCode {
	cmd := newRootCmd(newOut, newErr, args)
	if err := cmd.Execute(); err != nil {
		cmd.PrintErrf("Error: %+v\n", err)
		return abnormal
	}
	return normal
}

func init() {}

func makeSpace(count int) string {
	// 注:全角スペース
	s := "　"
	return strings.Repeat(s, count)
}

type tracker interface {
	track(s string) error
}

func newTracker(cmd *cobra.Command) tracker {
	flagCount := cmd.Flags().NFlag()
	switch flagCount {
	case 0:
		return &trackShipmentsOne{
			cmd: cmd,
		}
	default:
		// PreRunEでエラーチェック済み
		serial, _ := cmd.Flags().GetInt("serial")
		return &trackShipmentsMultiple{
			cmd:    cmd,
			serial: serial,
		}
	}
}

type trackShipmentsOne struct {
	cmd *cobra.Command
}

func (t *trackShipmentsOne) track(s string) error {
	values := url.Values{}
	values.Add("number01", s)

	contactUrl := "http://toi.kuronekoyamato.co.jp/cgi-bin/tneko"
	resp, err := http.PostForm(contactUrl, values)
	if err != nil {
		return err
	}

	defer resp.Body.Close()

	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		return err
	}

	w := t.cmd.OutOrStdout()
	trackNumber := doc.Find(".tracking-invoice-block-title").Text()
	trackNumber = strings.Replace(
		trackNumber, "1件目：", "伝票番号 ", -1,
	)
	stateTitle := doc.Find(".tracking-invoice-block-state-title").Text()
	stateSummary := doc.Find(".tracking-invoice-block-state-summary").Text()
	fmt.Fprintf(w, "%s\n%s\n%s\n", trackNumber, stateTitle, stateSummary)

	informations := doc.Find(".tracking-invoice-block-summary ul li").Map(
		func(_ int, s *goquery.Selection) string {
			item := s.Find(".item").Text()
			data := s.Find(".data").Text()
			return item + data
		},
	)
	if len(informations) != 0 {
		fmt.Fprintf(w, "\n")
		for _, info := range informations {
			fmt.Fprintf(w, "%s\n", info)
		}
		fmt.Fprintf(w, "\n")
	}

	doc.Find(".tracking-invoice-block-detail ol li").Each(func(_ int, args *goquery.Selection) {
		item := args.Find(".item").Text()
		itemLength := utf8.RuneCountInString(item)
		whitespace := 15 - itemLength
		space := makeSpace(whitespace)
		item = item + space
		date := args.Find(".date").Text()
		if date == "" {
			date = "              "
		}
		name := args.Find(".name").Text()
		nameLength := utf8.RuneCountInString(name)
		whitespace = 20 - nameLength
		space = makeSpace(whitespace)
		name = name + space
		fmt.Fprintf(w, "%s| %s | %s|\n", item, date, name)
	})

	underLine := strings.Repeat("-", 90)
	fmt.Fprintf(w, "%s\n", underLine)

	return nil
}

type trackShipmentsMultiple struct {
	cmd    *cobra.Command
	serial int
}

func (t *trackShipmentsMultiple) track(s string) error {
	trackingNumber := removeHyphen(s)
	if !isInt(trackingNumber) {
		return coloredError("不正な数値です")
	}

	if !is12or11Digits(trackingNumber) {
		return coloredError("12 or 11桁の伝票番号を入力してください")
	}

	if !isCorrectNumber(trackingNumber) {
		return coloredError("伝票番号に誤りがあります")
	}

	ctx, cancel := context.WithCancel(context.Background())
	ch := sevenCheckCalculate(ctx, trackingNumber[:len(trackingNumber)-1])
	values := url.Values{}

	var i int
	for i = 0; i < t.serial; i++ {
		querykey := fmt.Sprintf("number%02d", i+1)
		values.Add(querykey, <-ch)
	}
	cancel()

	contactUrl := "http://toi.kuronekoyamato.co.jp/cgi-bin/tneko"
	resp, err := http.PostForm(contactUrl, values)
	if err != nil {
		return err
	}

	defer resp.Body.Close()

	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		return err
	}

	w := t.cmd.OutOrStdout()
	doc.Find(".parts-tracking-invoice-block").Each(func(i int, args *goquery.Selection) {
		count := strconv.Itoa(i+1) + "件目"
		trackNumber := args.Find(".tracking-invoice-block-title").Text()
		rep := regexp.MustCompile(`[0-9]*件目：`)
		trackNumber = rep.ReplaceAllString(trackNumber, "伝票番号 ")
		stateTitle := args.Find(".tracking-invoice-block-state-title").Text()
		stateSummary := args.Find(".tracking-invoice-block-state-summary").Text()
		fmt.Fprintf(w, "%s\n%s\n%s\n%s\n", countColor(count), trackNumber, stateTitle, stateSummary)

		informations := args.Find(".tracking-invoice-block-summary ul li").Map(
			func(_ int, s *goquery.Selection) string {
				item := s.Find(".item").Text()
				data := s.Find(".data").Text()
				return item + data
			},
		)
		if len(informations) != 0 {
			fmt.Fprintf(w, "\n")
			for _, info := range informations {
				fmt.Fprintf(w, "%s\n", info)
			}
			fmt.Fprintf(w, "\n")
		}

		args.Find(".tracking-invoice-block-detail ol li").Each(func(_ int, s *goquery.Selection) {
			item := s.Find(".item").Text()
			itemLength := utf8.RuneCountInString(item)
			whitespace := 15 - itemLength
			space := makeSpace(whitespace)
			item = item + space
			date := s.Find(".date").Text()
			if date == "" {
				date = "              "
			}
			name := s.Find(".name").Text()
			nameLength := utf8.RuneCountInString(name)
			whitespace = 20 - nameLength
			space = makeSpace(whitespace)
			name = name + space
			fmt.Fprintf(w, "%s| %s | %s|\n", item, date, name)
		})
		underLine := strings.Repeat("-", 90)
		fmt.Fprintf(w, "%s\n", underLine)
	})

	return nil
}

func coloredError(s string) error {
	return errors.New(errColor(s))
}

func removeHyphen(s string) string {
	if strings.Contains(s, "-") {
		removed := strings.Replace(s, "-", "", -1)
		return removed
	}
	return s
}

func sevenCheckCalculate(ctx context.Context, n string) <-chan string {
	ch := make(chan string)
	const coef = 7
	var format = "%012s"
	if len(n) == 10 {
		format = "%011s"
	}
	go func() {
		sign, _ := strconv.ParseInt(n, 10, 64)
	LOOP:
		for {
			select {
			case <-ctx.Done():
				break LOOP
			default:
				digit := sign % coef
				digitStr := strconv.FormatInt(digit, 10)
				trackingNumber := strconv.FormatInt(sign, 10) + digitStr
				zeroPaddingNumber := fmt.Sprintf(format, trackingNumber)
				ch <- zeroPaddingNumber
				sign++
			}
		}
		close(ch)
	}()
	return ch
}

func isCorrectNumber(s string) bool {
	const coef = 7
	lastDigits := s[len(s)-1:]
	otherDigits := s[:len(s)-1]
	sign, _ := strconv.ParseInt(otherDigits, 10, 64)
	digit := sign % coef
	return lastDigits == fmt.Sprint(digit)
}

func isInt(s string) bool {
	for _, c := range s {
		if !unicode.IsDigit(c) {
			return false
		}
	}
	return true
}

func is12or11Digits(s string) bool {
	if len(s) == 12 || len(s) == 11 {
		return true
	}
	return false
}
<commit_msg>refactor<commit_after>package cmd

import (
	"context"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"
	"unicode"
	"unicode/utf8"

	"github.com/PuerkitoBio/goquery"
	"github.com/fatih/color"
	"github.com/spf13/cobra"
)

var (
	errColor   func(string, ...interface{}) string = color.HiYellowString
	countColor func(string, ...interface{}) string = color.HiYellowString
)

type exitCode int

const (
	normal exitCode = iota
	abnormal
)

func (c exitCode) Exit() {
	os.Exit(int(c))
}

func newRootCmd(newOut, newErr io.Writer, args []string) *cobra.Command {

	cmd := &cobra.Command{
		Use:           "kuroneko [flags] 伝票番号",
		Short:         "ヤマト運輸のステータス取得",
		SilenceErrors: true,
		SilenceUsage:  true,

		Args: func(cmd *cobra.Command, args []string) error {
			if len(args) > 1 {
				count := strconv.Itoa(len(args))
				return fmt.Errorf("accepts at most 1 arg(s), received %s", errColor(count))
			}

			if len(args) == 0 {
				return coloredError("伝票番号を入力してください")
			}

			return nil
		},

		PreRunE: func(cmd *cobra.Command, args []string) error {
			flagCount := cmd.Flags().NFlag()
			if flagCount > 1 {
				count := strconv.Itoa(flagCount)
				return fmt.Errorf("accepte at most 1 flag(s), received %s", errColor(count))
			}

			serial, err := cmd.Flags().GetString("serial")
			if err != nil {
				return err
			}

			i, err := strconv.Atoi(serial)
			if err != nil {
				return coloredError("連番を整数で入力してください")
			}

			if i < 1 || i > 10 {
				return coloredError("連番で取得できるのは 1~10件 までです")
			}

			return nil
		},

		RunE: func(cmd *cobra.Command, args []string) error {
			trackingNumber := args[0]
			tracker := newTracker(cmd)
			return tracker.track(trackingNumber)
		},
	}

	cmd.Flags().StringP("serial", "s", "1", "連番取得(10件まで)")
	cmd.SetArgs(args)
	cmd.SetOut(newOut)
	cmd.SetErr(newErr)

	return cmd
}

func Execute(newOut, newErr io.Writer, args []string) exitCode {
	cmd := newRootCmd(newOut, newErr, args)
	if err := cmd.Execute(); err != nil {
		cmd.PrintErrf("Error: %+v\n", err)
		return abnormal
	}
	return normal
}

func init() {}

func makeSpace(count int) string {
	// 注:全角スペース
	s := "　"
	return strings.Repeat(s, count)
}

type tracker interface {
	track(s string) error
}

func newTracker(cmd *cobra.Command) tracker {
	flagCount := cmd.Flags().NFlag()
	switch flagCount {
	case 0:
		return &trackShipmentsOne{
			cmd: cmd,
		}
	default:
		// PreRunEでエラーチェック済み
		s, _ := cmd.Flags().GetString("serial")
		serial, _ := strconv.Atoi(s)
		return &trackShipmentsMultiple{
			cmd:    cmd,
			serial: serial,
		}
	}
}

type trackShipmentsOne struct {
	cmd *cobra.Command
}

func (t *trackShipmentsOne) track(s string) error {
	values := url.Values{}
	values.Add("number01", s)

	contactUrl := "http://toi.kuronekoyamato.co.jp/cgi-bin/tneko"
	http.DefaultClient.Timeout = 10 * time.Second
	resp, err := http.PostForm(contactUrl, values)
	if err != nil {
		return err
	}

	defer resp.Body.Close()

	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		return err
	}

	w := t.cmd.OutOrStdout()
	trackNumber := doc.Find(".tracking-invoice-block-title").Text()
	trackNumber = strings.Replace(
		trackNumber, "1件目：", "伝票番号 ", -1,
	)
	stateTitle := doc.Find(".tracking-invoice-block-state-title").Text()
	stateSummary := doc.Find(".tracking-invoice-block-state-summary").Text()
	fmt.Fprintf(w, "%s\n%s\n%s\n", trackNumber, stateTitle, stateSummary)

	informations := doc.Find(".tracking-invoice-block-summary ul li").Map(
		func(_ int, s *goquery.Selection) string {
			item := s.Find(".item").Text()
			data := s.Find(".data").Text()
			return item + data
		},
	)
	if len(informations) != 0 {
		fmt.Fprintf(w, "\n")
		for _, info := range informations {
			fmt.Fprintf(w, "%s\n", info)
		}
		fmt.Fprintf(w, "\n")
	}

	doc.Find(".tracking-invoice-block-detail ol li").Each(func(_ int, args *goquery.Selection) {
		item := args.Find(".item").Text()
		itemLength := utf8.RuneCountInString(item)
		whitespace := 15 - itemLength
		space := makeSpace(whitespace)
		item = item + space
		date := args.Find(".date").Text()
		if date == "" {
			date = "              "
		}
		name := args.Find(".name").Text()
		nameLength := utf8.RuneCountInString(name)
		whitespace = 20 - nameLength
		space = makeSpace(whitespace)
		name = name + space
		fmt.Fprintf(w, "%s| %s | %s|\n", item, date, name)
	})

	underLine := strings.Repeat("-", 90)
	fmt.Fprintf(w, "%s\n", underLine)

	return nil
}

type trackShipmentsMultiple struct {
	cmd    *cobra.Command
	serial int
}

func (t *trackShipmentsMultiple) track(s string) error {
	trackingNumber := removeHyphen(s)
	if !isInt(trackingNumber) {
		return coloredError("不正な数値です")
	}

	if !is12or11Digits(trackingNumber) {
		return coloredError("12 or 11桁の伝票番号を入力してください")
	}

	if !isCorrectNumber(trackingNumber) {
		return coloredError("伝票番号に誤りがあります")
	}

	ctx, cancel := context.WithCancel(context.Background())
	ch := sevenCheckCalculate(ctx, trackingNumber[:len(trackingNumber)-1])
	values := url.Values{}

	var i int
	for i = 0; i < t.serial; i++ {
		querykey := fmt.Sprintf("number%02d", i+1)
		values.Add(querykey, <-ch)
	}
	cancel()

	contactUrl := "http://toi.kuronekoyamato.co.jp/cgi-bin/tneko"
	http.DefaultClient.Timeout = 30 * time.Second
	resp, err := http.PostForm(contactUrl, values)
	if err != nil {
		return err
	}

	defer resp.Body.Close()

	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		return err
	}

	w := t.cmd.OutOrStdout()
	doc.Find(".parts-tracking-invoice-block").Each(func(i int, args *goquery.Selection) {
		count := strconv.Itoa(i+1) + "件目"
		trackNumber := args.Find(".tracking-invoice-block-title").Text()
		rep := regexp.MustCompile(`[0-9]*件目：`)
		trackNumber = rep.ReplaceAllString(trackNumber, "伝票番号 ")
		stateTitle := args.Find(".tracking-invoice-block-state-title").Text()
		stateSummary := args.Find(".tracking-invoice-block-state-summary").Text()
		fmt.Fprintf(w, "%s\n%s\n%s\n%s\n", countColor(count), trackNumber, stateTitle, stateSummary)

		informations := args.Find(".tracking-invoice-block-summary ul li").Map(
			func(_ int, s *goquery.Selection) string {
				item := s.Find(".item").Text()
				data := s.Find(".data").Text()
				return item + data
			},
		)
		if len(informations) != 0 {
			fmt.Fprintf(w, "\n")
			for _, info := range informations {
				fmt.Fprintf(w, "%s\n", info)
			}
			fmt.Fprintf(w, "\n")
		}

		args.Find(".tracking-invoice-block-detail ol li").Each(func(_ int, s *goquery.Selection) {
			item := s.Find(".item").Text()
			itemLength := utf8.RuneCountInString(item)
			whitespace := 15 - itemLength
			space := makeSpace(whitespace)
			item = item + space
			date := s.Find(".date").Text()
			if date == "" {
				date = "              "
			}
			name := s.Find(".name").Text()
			nameLength := utf8.RuneCountInString(name)
			whitespace = 20 - nameLength
			space = makeSpace(whitespace)
			name = name + space
			fmt.Fprintf(w, "%s| %s | %s|\n", item, date, name)
		})
		underLine := strings.Repeat("-", 90)
		fmt.Fprintf(w, "%s\n", underLine)
	})

	return nil
}

func coloredError(s string) error {
	return errors.New(errColor(s))
}

func removeHyphen(s string) string {
	if strings.Contains(s, "-") {
		removed := strings.Replace(s, "-", "", -1)
		return removed
	}
	return s
}

func sevenCheckCalculate(ctx context.Context, n string) <-chan string {
	ch := make(chan string)
	const coef = 7
	var format = "%012s"
	if len(n) == 10 {
		format = "%011s"
	}
	go func() {
		sign, _ := strconv.ParseInt(n, 10, 64)
	LOOP:
		for {
			select {
			case <-ctx.Done():
				break LOOP
			default:
				digit := sign % coef
				digitStr := strconv.FormatInt(digit, 10)
				trackingNumber := strconv.FormatInt(sign, 10) + digitStr
				zeroPaddingNumber := fmt.Sprintf(format, trackingNumber)
				ch <- zeroPaddingNumber
				sign++
			}
		}
		close(ch)
	}()
	return ch
}

func isCorrectNumber(s string) bool {
	const coef = 7
	lastDigits := s[len(s)-1:]
	otherDigits := s[:len(s)-1]
	sign, _ := strconv.ParseInt(otherDigits, 10, 64)
	digit := sign % coef
	return lastDigits == fmt.Sprint(digit)
}

func isInt(s string) bool {
	for _, c := range s {
		if !unicode.IsDigit(c) {
			return false
		}
	}
	return true
}

func is12or11Digits(s string) bool {
	if len(s) == 12 || len(s) == 11 {
		return true
	}
	return false
}
<|endoftext|>


<commit_before>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package cmd

import (
	"context"
	"fmt"
	"io"
	"io/ioutil"
	stdlog "log"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/fatih/color"
	"github.com/mattn/go-colorable"
	"github.com/mattn/go-isatty"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"

	"go.k6.io/k6/lib/consts"
	"go.k6.io/k6/log"
)

var BannerColor = color.New(color.FgCyan)

//TODO: remove these global variables
//nolint:gochecknoglobals
var (
	outMutex   = &sync.Mutex{}
	isDumbTerm = os.Getenv("TERM") == "dumb"
	stdoutTTY  = !isDumbTerm && (isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd()))
	stderrTTY  = !isDumbTerm && (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd()))
	stdout     = &consoleWriter{colorable.NewColorableStdout(), stdoutTTY, outMutex, nil}
	stderr     = &consoleWriter{colorable.NewColorableStderr(), stderrTTY, outMutex, nil}
)

const (
	defaultConfigFileName   = "config.json"
	waitRemoteLoggerTimeout = time.Second * 5
)

//TODO: remove these global variables
//nolint:gochecknoglobals
var defaultConfigFilePath = defaultConfigFileName // Updated with the user's config folder in the init() function below
//nolint:gochecknoglobals
var configFilePath = os.Getenv("K6_CONFIG") // Overridden by `-c`/`--config` flag!

//nolint:gochecknoglobals
var (
	// TODO: have environment variables for configuring these? hopefully after we move away from global vars though...
	quiet   bool
	noColor bool
	address string
)

// This is to keep all fields needed for the main/root k6 command
type rootCommand struct {
	ctx            context.Context
	logger         *logrus.Logger
	fallbackLogger logrus.FieldLogger
	cmd            *cobra.Command
	loggerStopped  <-chan struct{}
	logOutput      string
	logFmt         string
	loggerIsRemote bool
	verbose        bool
}

func newRootCommand(ctx context.Context, logger *logrus.Logger, fallbackLogger logrus.FieldLogger) *rootCommand {
	c := &rootCommand{
		ctx:            ctx,
		logger:         logger,
		fallbackLogger: fallbackLogger,
	}
	// the base command when called without any subcommands.
	c.cmd = &cobra.Command{
		Use:               "k6",
		Short:             "a next-generation load generator",
		Long:              BannerColor.Sprintf("\n%s", consts.Banner()),
		SilenceUsage:      true,
		SilenceErrors:     true,
		PersistentPreRunE: c.persistentPreRunE,
	}

	confDir, err := os.UserConfigDir()
	if err != nil {
		logrus.WithError(err).Warn("could not get config directory")
		confDir = ".config"
	}
	defaultConfigFilePath = filepath.Join(
		confDir,
		"loadimpact",
		"k6",
		defaultConfigFileName,
	)

	c.cmd.PersistentFlags().AddFlagSet(c.rootCmdPersistentFlagSet())
	return c
}

func (c *rootCommand) persistentPreRunE(cmd *cobra.Command, args []string) error {
	var err error
	if !cmd.Flags().Changed("log-output") {
		if envLogOutput, ok := os.LookupEnv("K6_LOG_OUTPUT"); ok {
			c.logOutput = envLogOutput
		}
	}
	c.loggerStopped, err = c.setupLoggers()
	if err != nil {
		return err
	}
	select {
	case <-c.loggerStopped:
	default:
		c.loggerIsRemote = true
	}

	if noColor {
		// TODO: figure out something else... currently, with the wrappers
		// below, we're stripping any colors from the output after we've
		// added them. The problem is that, besides being very inefficient,
		// this actually also strips other special characters from the
		// intended output, like the progressbar formatting ones, which
		// would otherwise be fine (in a TTY).
		//
		// It would be much better if we avoid messing with the output and
		// instead have a parametrized instance of the color library. It
		// will return colored output if colors are enabled and simply
		// return the passed input as-is (i.e. be a noop) if colors are
		// disabled...
		stdout.Writer = colorable.NewNonColorable(os.Stdout)
		stderr.Writer = colorable.NewNonColorable(os.Stderr)
	}
	stdlog.SetOutput(c.logger.Writer())
	c.logger.Debugf("k6 version: v%s", consts.FullVersion())
	return nil
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	logger := &logrus.Logger{
		Out:       os.Stderr,
		Formatter: new(logrus.TextFormatter),
		Hooks:     make(logrus.LevelHooks),
		Level:     logrus.InfoLevel,
	}

	var fallbackLogger logrus.FieldLogger = &logrus.Logger{
		Out:       os.Stderr,
		Formatter: new(logrus.TextFormatter),
		Hooks:     make(logrus.LevelHooks),
		Level:     logrus.InfoLevel,
	}

	c := newRootCommand(ctx, logger, fallbackLogger)

	loginCmd := getLoginCmd()
	loginCmd.AddCommand(getLoginCloudCommand(logger), getLoginInfluxDBCommand(logger))
	c.cmd.AddCommand(
		getArchiveCmd(logger),
		getCloudCmd(ctx, logger),
		getConvertCmd(),
		getInspectCmd(logger),
		loginCmd,
		getPauseCmd(ctx),
		getResumeCmd(ctx),
		getScaleCmd(ctx),
		getRunCmd(ctx, logger),
		getStatsCmd(ctx),
		getStatusCmd(ctx),
		getVersionCmd(),
	)

	if err := c.cmd.Execute(); err != nil {
		fields := logrus.Fields{}
		code := -1
		if e, ok := err.(ExitCode); ok {
			code = e.Code
			if e.Hint != "" {
				fields["hint"] = e.Hint
			}
		}

		logger.WithFields(fields).Error(err)
		if c.loggerIsRemote {
			fallbackLogger.WithFields(fields).Error(err)
			cancel()
			c.waitRemoteLogger()
		}

		os.Exit(code)
	}

	cancel()
	c.waitRemoteLogger()
}

func (c *rootCommand) waitRemoteLogger() {
	if c.loggerIsRemote {
		select {
		case <-c.loggerStopped:
		case <-time.After(waitRemoteLoggerTimeout):
			c.fallbackLogger.Error("Remote logger didn't stop in %s", waitRemoteLoggerTimeout)
		}
	}
}

func (c *rootCommand) rootCmdPersistentFlagSet() *pflag.FlagSet {
	flags := pflag.NewFlagSet("", pflag.ContinueOnError)
	// TODO: figure out a better way to handle the CLI flags - global variables are not very testable... :/
	flags.BoolVarP(&c.verbose, "verbose", "v", false, "enable verbose logging")
	flags.BoolVarP(&quiet, "quiet", "q", false, "disable progress updates")
	flags.BoolVar(&noColor, "no-color", false, "disable colored output")
	flags.StringVar(&c.logOutput, "log-output", "stderr",
		"change the output for k6 logs, possible values are stderr,stdout,none,loki[=host:port]")
	flags.StringVar(&c.logFmt, "logformat", "", "log output format") // TODO rename to log-format and warn on old usage
	flags.StringVarP(&address, "address", "a", "localhost:6565", "address for the api server")

	// TODO: Fix... This default value needed, so both CLI flags and environment variables work
	flags.StringVarP(&configFilePath, "config", "c", configFilePath, "JSON config file")
	// And we also need to explicitly set the default value for the usage message here, so things
	// like `K6_CONFIG="blah" k6 run -h` don't produce a weird usage message
	flags.Lookup("config").DefValue = defaultConfigFilePath
	must(cobra.MarkFlagFilename(flags, "config"))
	return flags
}

// fprintf panics when where's an error writing to the supplied io.Writer
func fprintf(w io.Writer, format string, a ...interface{}) (n int) {
	n, err := fmt.Fprintf(w, format, a...)
	if err != nil {
		panic(err.Error())
	}
	return n
}

// RawFormatter it does nothing with the message just prints it
type RawFormatter struct{}

// Format renders a single log entry
func (f RawFormatter) Format(entry *logrus.Entry) ([]byte, error) {
	return append([]byte(entry.Message), '\n'), nil
}

// The returned channel will be closed when the logger has finished flushing and pushing logs after
// the provided context is closed. It is closed if the logger isn't buffering and sending messages
// Asynchronously
func (c *rootCommand) setupLoggers() (<-chan struct{}, error) {
	ch := make(chan struct{})
	close(ch)

	if c.verbose {
		c.logger.SetLevel(logrus.DebugLevel)
	}
	switch c.logOutput {
	case "stderr":
		c.logger.SetOutput(stderr)
	case "stdout":
		c.logger.SetOutput(stdout)
	case "none":
		c.logger.SetOutput(ioutil.Discard)
	default:
		if !strings.HasPrefix(c.logOutput, "loki") {
			return nil, fmt.Errorf("unsupported log output `%s`", c.logOutput)
		}
		ch = make(chan struct{})
		hook, err := log.LokiFromConfigLine(c.ctx, c.fallbackLogger, c.logOutput, ch)
		if err != nil {
			return nil, err
		}
		c.logger.AddHook(hook)
		c.logger.SetOutput(ioutil.Discard) // don't output to anywhere else
		c.logFmt = "raw"
		noColor = true // disable color
	}

	switch c.logFmt {
	case "raw":
		c.logger.SetFormatter(&RawFormatter{})
		c.logger.Debug("Logger format: RAW")
	case "json":
		c.logger.SetFormatter(&logrus.JSONFormatter{})
		c.logger.Debug("Logger format: JSON")
	default:
		c.logger.SetFormatter(&logrus.TextFormatter{ForceColors: stderrTTY, DisableColors: noColor})
		c.logger.Debug("Logger format: TEXT")
	}
	return ch, nil
}
<commit_msg>Differentiate between stderr and stdout TTY detection for loggers<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package cmd

import (
	"context"
	"fmt"
	"io"
	"io/ioutil"
	stdlog "log"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/fatih/color"
	"github.com/mattn/go-colorable"
	"github.com/mattn/go-isatty"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"

	"go.k6.io/k6/lib/consts"
	"go.k6.io/k6/log"
)

var BannerColor = color.New(color.FgCyan)

//TODO: remove these global variables
//nolint:gochecknoglobals
var (
	outMutex   = &sync.Mutex{}
	isDumbTerm = os.Getenv("TERM") == "dumb"
	stdoutTTY  = !isDumbTerm && (isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd()))
	stderrTTY  = !isDumbTerm && (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd()))
	stdout     = &consoleWriter{colorable.NewColorableStdout(), stdoutTTY, outMutex, nil}
	stderr     = &consoleWriter{colorable.NewColorableStderr(), stderrTTY, outMutex, nil}
)

const (
	defaultConfigFileName   = "config.json"
	waitRemoteLoggerTimeout = time.Second * 5
)

//TODO: remove these global variables
//nolint:gochecknoglobals
var defaultConfigFilePath = defaultConfigFileName // Updated with the user's config folder in the init() function below
//nolint:gochecknoglobals
var configFilePath = os.Getenv("K6_CONFIG") // Overridden by `-c`/`--config` flag!

//nolint:gochecknoglobals
var (
	// TODO: have environment variables for configuring these? hopefully after we move away from global vars though...
	quiet   bool
	noColor bool
	address string
)

// This is to keep all fields needed for the main/root k6 command
type rootCommand struct {
	ctx            context.Context
	logger         *logrus.Logger
	fallbackLogger logrus.FieldLogger
	cmd            *cobra.Command
	loggerStopped  <-chan struct{}
	logOutput      string
	logFmt         string
	loggerIsRemote bool
	verbose        bool
}

func newRootCommand(ctx context.Context, logger *logrus.Logger, fallbackLogger logrus.FieldLogger) *rootCommand {
	c := &rootCommand{
		ctx:            ctx,
		logger:         logger,
		fallbackLogger: fallbackLogger,
	}
	// the base command when called without any subcommands.
	c.cmd = &cobra.Command{
		Use:               "k6",
		Short:             "a next-generation load generator",
		Long:              BannerColor.Sprintf("\n%s", consts.Banner()),
		SilenceUsage:      true,
		SilenceErrors:     true,
		PersistentPreRunE: c.persistentPreRunE,
	}

	confDir, err := os.UserConfigDir()
	if err != nil {
		logrus.WithError(err).Warn("could not get config directory")
		confDir = ".config"
	}
	defaultConfigFilePath = filepath.Join(
		confDir,
		"loadimpact",
		"k6",
		defaultConfigFileName,
	)

	c.cmd.PersistentFlags().AddFlagSet(c.rootCmdPersistentFlagSet())
	return c
}

func (c *rootCommand) persistentPreRunE(cmd *cobra.Command, args []string) error {
	var err error
	if !cmd.Flags().Changed("log-output") {
		if envLogOutput, ok := os.LookupEnv("K6_LOG_OUTPUT"); ok {
			c.logOutput = envLogOutput
		}
	}
	c.loggerStopped, err = c.setupLoggers()
	if err != nil {
		return err
	}
	select {
	case <-c.loggerStopped:
	default:
		c.loggerIsRemote = true
	}

	if noColor {
		// TODO: figure out something else... currently, with the wrappers
		// below, we're stripping any colors from the output after we've
		// added them. The problem is that, besides being very inefficient,
		// this actually also strips other special characters from the
		// intended output, like the progressbar formatting ones, which
		// would otherwise be fine (in a TTY).
		//
		// It would be much better if we avoid messing with the output and
		// instead have a parametrized instance of the color library. It
		// will return colored output if colors are enabled and simply
		// return the passed input as-is (i.e. be a noop) if colors are
		// disabled...
		stdout.Writer = colorable.NewNonColorable(os.Stdout)
		stderr.Writer = colorable.NewNonColorable(os.Stderr)
	}
	stdlog.SetOutput(c.logger.Writer())
	c.logger.Debugf("k6 version: v%s", consts.FullVersion())
	return nil
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	logger := &logrus.Logger{
		Out:       os.Stderr,
		Formatter: new(logrus.TextFormatter),
		Hooks:     make(logrus.LevelHooks),
		Level:     logrus.InfoLevel,
	}

	var fallbackLogger logrus.FieldLogger = &logrus.Logger{
		Out:       os.Stderr,
		Formatter: new(logrus.TextFormatter),
		Hooks:     make(logrus.LevelHooks),
		Level:     logrus.InfoLevel,
	}

	c := newRootCommand(ctx, logger, fallbackLogger)

	loginCmd := getLoginCmd()
	loginCmd.AddCommand(getLoginCloudCommand(logger), getLoginInfluxDBCommand(logger))
	c.cmd.AddCommand(
		getArchiveCmd(logger),
		getCloudCmd(ctx, logger),
		getConvertCmd(),
		getInspectCmd(logger),
		loginCmd,
		getPauseCmd(ctx),
		getResumeCmd(ctx),
		getScaleCmd(ctx),
		getRunCmd(ctx, logger),
		getStatsCmd(ctx),
		getStatusCmd(ctx),
		getVersionCmd(),
	)

	if err := c.cmd.Execute(); err != nil {
		fields := logrus.Fields{}
		code := -1
		if e, ok := err.(ExitCode); ok {
			code = e.Code
			if e.Hint != "" {
				fields["hint"] = e.Hint
			}
		}

		logger.WithFields(fields).Error(err)
		if c.loggerIsRemote {
			fallbackLogger.WithFields(fields).Error(err)
			cancel()
			c.waitRemoteLogger()
		}

		os.Exit(code)
	}

	cancel()
	c.waitRemoteLogger()
}

func (c *rootCommand) waitRemoteLogger() {
	if c.loggerIsRemote {
		select {
		case <-c.loggerStopped:
		case <-time.After(waitRemoteLoggerTimeout):
			c.fallbackLogger.Error("Remote logger didn't stop in %s", waitRemoteLoggerTimeout)
		}
	}
}

func (c *rootCommand) rootCmdPersistentFlagSet() *pflag.FlagSet {
	flags := pflag.NewFlagSet("", pflag.ContinueOnError)
	// TODO: figure out a better way to handle the CLI flags - global variables are not very testable... :/
	flags.BoolVarP(&c.verbose, "verbose", "v", false, "enable verbose logging")
	flags.BoolVarP(&quiet, "quiet", "q", false, "disable progress updates")
	flags.BoolVar(&noColor, "no-color", false, "disable colored output")
	flags.StringVar(&c.logOutput, "log-output", "stderr",
		"change the output for k6 logs, possible values are stderr,stdout,none,loki[=host:port]")
	flags.StringVar(&c.logFmt, "logformat", "", "log output format") // TODO rename to log-format and warn on old usage
	flags.StringVarP(&address, "address", "a", "localhost:6565", "address for the api server")

	// TODO: Fix... This default value needed, so both CLI flags and environment variables work
	flags.StringVarP(&configFilePath, "config", "c", configFilePath, "JSON config file")
	// And we also need to explicitly set the default value for the usage message here, so things
	// like `K6_CONFIG="blah" k6 run -h` don't produce a weird usage message
	flags.Lookup("config").DefValue = defaultConfigFilePath
	must(cobra.MarkFlagFilename(flags, "config"))
	return flags
}

// fprintf panics when where's an error writing to the supplied io.Writer
func fprintf(w io.Writer, format string, a ...interface{}) (n int) {
	n, err := fmt.Fprintf(w, format, a...)
	if err != nil {
		panic(err.Error())
	}
	return n
}

// RawFormatter it does nothing with the message just prints it
type RawFormatter struct{}

// Format renders a single log entry
func (f RawFormatter) Format(entry *logrus.Entry) ([]byte, error) {
	return append([]byte(entry.Message), '\n'), nil
}

// The returned channel will be closed when the logger has finished flushing and pushing logs after
// the provided context is closed. It is closed if the logger isn't buffering and sending messages
// Asynchronously
func (c *rootCommand) setupLoggers() (<-chan struct{}, error) {
	ch := make(chan struct{})
	close(ch)

	if c.verbose {
		c.logger.SetLevel(logrus.DebugLevel)
	}

	loggerForceColors := false // disable color by default
	switch c.logOutput {
	case "stderr":
		loggerForceColors = !noColor && stderrTTY
		c.logger.SetOutput(stderr)
	case "stdout":
		loggerForceColors = !noColor && stdoutTTY
		c.logger.SetOutput(stdout)
	case "none":
		c.logger.SetOutput(ioutil.Discard)
	default:
		if !strings.HasPrefix(c.logOutput, "loki") {
			return nil, fmt.Errorf("unsupported log output `%s`", c.logOutput)
		}
		ch = make(chan struct{})
		hook, err := log.LokiFromConfigLine(c.ctx, c.fallbackLogger, c.logOutput, ch)
		if err != nil {
			return nil, err
		}
		c.logger.AddHook(hook)
		c.logger.SetOutput(ioutil.Discard) // don't output to anywhere else
		c.logFmt = "raw"
	}

	switch c.logFmt {
	case "raw":
		c.logger.SetFormatter(&RawFormatter{})
		c.logger.Debug("Logger format: RAW")
	case "json":
		c.logger.SetFormatter(&logrus.JSONFormatter{})
		c.logger.Debug("Logger format: JSON")
	default:
		c.logger.SetFormatter(&logrus.TextFormatter{ForceColors: loggerForceColors, DisableColors: noColor})
		c.logger.Debug("Logger format: TEXT")
	}
	return ch, nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"io"

	"github.com/spf13/cobra"
	"github.com/spinnaker/spin/cmd/application"
	"github.com/spinnaker/spin/cmd/pipeline"
)

type RootOptions struct {
	configFile       string
	GateEndpoint     string
	ignoreCertErrors bool
	quiet            bool
	color            bool
	outputFormat     string
}

func Execute(out io.Writer) error {
	cmd := NewCmdRoot(out)
	return cmd.Execute()
}

func NewCmdRoot(out io.Writer) *cobra.Command {
	options := RootOptions{}

	cmd := &cobra.Command{
		Short: `Global Options:

		--gate-endpoint               Gate (API server) endpoint.
		--no-color                    Removes color from CLI output.
		--insecure=false              Ignore certificate errors during connection to endpoints.
		--quiet=false                 Squelch non-essential output.
		--output <output format>      Formats CLI output.
	`,
		SilenceUsage: true,
	}

	cmd.PersistentFlags().StringVar(&options.configFile, "config", "", "config file (default is $HOME/.spin/config)")
	cmd.PersistentFlags().StringVar(&options.GateEndpoint, "gate-endpoint", "", "Gate (API server) endpoint. Default http://localhost:8084")
	cmd.PersistentFlags().BoolVar(&options.ignoreCertErrors, "insecure", false, "Ignore Certificate Errors")
	cmd.PersistentFlags().BoolVar(&options.quiet, "quiet", false, "Squelch non-essential output")
	cmd.PersistentFlags().BoolVar(&options.color, "no-color", true, "Disable color")
	// TODO(jacobkiefer): Codify the json-path as part of an OutputConfig or
	// something similar. Sets the stage for yaml output, etc.
	cmd.PersistentFlags().StringVar(&options.outputFormat, "output", "", "Configure output formatting")

	// create subcommands
	cmd.AddCommand(application.NewApplicationCmd(out))
	cmd.AddCommand(pipeline.NewPipelineCmd(out))

	return cmd
}
<commit_msg>fix(root): Adds version to support version flags. (#79)<commit_after>package cmd

import (
	"io"

	"github.com/spf13/cobra"
	"github.com/spinnaker/spin/cmd/application"
	"github.com/spinnaker/spin/cmd/pipeline"
	"github.com/spinnaker/spin/version"
)

type RootOptions struct {
	configFile       string
	GateEndpoint     string
	ignoreCertErrors bool
	quiet            bool
	color            bool
	outputFormat     string
}

func Execute(out io.Writer) error {
	cmd := NewCmdRoot(out)
	return cmd.Execute()
}

func NewCmdRoot(out io.Writer) *cobra.Command {
	options := RootOptions{}

	cmd := &cobra.Command{
		Short: `Global Options:

		--gate-endpoint               Gate (API server) endpoint.
		--no-color                    Removes color from CLI output.
		--insecure=false              Ignore certificate errors during connection to endpoints.
		--quiet=false                 Squelch non-essential output.
		--output <output format>      Formats CLI output.
	`,
		SilenceUsage: true,
		Version:      version.String(),
	}

	cmd.PersistentFlags().StringVar(&options.configFile, "config", "", "config file (default is $HOME/.spin/config)")
	cmd.PersistentFlags().StringVar(&options.GateEndpoint, "gate-endpoint", "", "Gate (API server) endpoint. Default http://localhost:8084")
	cmd.PersistentFlags().BoolVar(&options.ignoreCertErrors, "insecure", false, "Ignore Certificate Errors")
	cmd.PersistentFlags().BoolVar(&options.quiet, "quiet", false, "Squelch non-essential output")
	cmd.PersistentFlags().BoolVar(&options.color, "no-color", true, "Disable color")
	// TODO(jacobkiefer): Codify the json-path as part of an OutputConfig or
	// something similar. Sets the stage for yaml output, etc.
	cmd.PersistentFlags().StringVar(&options.outputFormat, "output", "", "Configure output formatting")

	// create subcommands
	cmd.AddCommand(application.NewApplicationCmd(out))
	cmd.AddCommand(pipeline.NewPipelineCmd(out))

	return cmd
}
<|endoftext|>


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

package cmd

import (
	"fmt"
	"os"

	"github.com/fkautz/sentry/sentrylib"
	"github.com/fsnotify/fsnotify"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var cfgFile string

var cfg *sentrylib.Config

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "sentry",
	Short: "A brief description of your application",
	Long: `A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
	// Uncomment the following line if your bare application
	// has an action associated with it:
	//	Run: func(cmd *cobra.Command, args []string) { },
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)

	// Here you will define your flags and configuration settings.
	// Cobra supports Persistent Flags, which, if defined here,
	// will be global for your application.

	RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.sentry.yaml)")
	// Cobra also supports local flags, which will only run
	// when this action is called directly.
	RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if cfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(cfgFile)
	}

	viper.SetConfigName("sentry") // name of config file (without extension)
	viper.AddConfigPath("$HOME")  // adding home directory as first search path
	viper.AddConfigPath(".")
	viper.AutomaticEnv() // read in environment variables that match

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}

	cfg = &sentrylib.Config{}
	viper.Unmarshal(cfg)

	viper.WatchConfig()
	viper.OnConfigChange(func(e fsnotify.Event) {
		fmt.Println("Config file changed", e)
		viper.Unmarshal(cfg)
	})
}
<commit_msg>Fixing --config not working<commit_after>// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"fmt"
	"os"

	"github.com/fkautz/sentry/sentrylib"
	"github.com/fsnotify/fsnotify"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var cfgFile string

var cfg *sentrylib.Config

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "sentry",
	Short: "A brief description of your application",
	Long: `A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
	// Uncomment the following line if your bare application
	// has an action associated with it:
	//	Run: func(cmd *cobra.Command, args []string) { },
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)

	// Here you will define your flags and configuration settings.
	// Cobra supports Persistent Flags, which, if defined here,
	// will be global for your application.

	RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.sentry.yaml)")
	// Cobra also supports local flags, which will only run
	// when this action is called directly.
	RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	fmt.Println("cfgFile: " + cfgFile)
	if cfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(cfgFile)
	} else {
		viper.SetConfigName("sentry") // name of config file (without extension)
		viper.AddConfigPath("$HOME")  // adding home directory as first search path
		viper.AddConfigPath(".")
		viper.AutomaticEnv() // read in environment variables that match
	}

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}

	cfg = &sentrylib.Config{}
	viper.Unmarshal(cfg)

	viper.WatchConfig()
	viper.OnConfigChange(func(e fsnotify.Event) {
		fmt.Println("Config file changed", e)
		viper.Unmarshal(cfg)
	})
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/robfig/revel"
	"github.com/robfig/revel/harness"
	"github.com/robfig/revel/modules/testrunner/app/controllers"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"strings"
	"time"
)

var cmdTest = &Command{
	UsageLine: "test [import path] [run mode]",
	Short:     "run all tests from the command-line",
	Long: `
Run all tests for the Revel app named by the given import path.

For example, to run the booking sample application's tests:

    revel test github.com/robfig/revel/samples/booking dev

The run mode is used to select which set of app.conf configuration should
apply and may be used to determine logic in the application itself.

Run mode defaults to "dev".`,
}

func init() {
	cmdTest.Run = testApp
}

func testApp(args []string) {
	var err error
	if len(args) == 0 {
		errorf("No import path given.\nRun 'revel help test' for usage.\n")
	}

	mode := "dev"
	if len(args) == 2 {
		mode = args[1]
	}

	// Find and parse app.conf
	revel.Init(mode, args[0], "")

	// Ensure that the testrunner is loaded in this mode.
	testRunnerFound := false
	for _, module := range revel.Modules {
		if module.ImportPath == "github.com/robfig/revel/modules/testrunner" {
			testRunnerFound = true
			break
		}
	}
	if !testRunnerFound {
		errorf(`Error: The testrunner module is not running.

You can add it to a run mode configuration with the following line:

	module.testrunner = github.com/robfig/revel/modules/testrunner

`)
	}

	// Create a directory to hold the test result files.
	resultPath := path.Join(revel.BasePath, "test-results")
	if err = os.RemoveAll(resultPath); err != nil {
		errorf("Failed to remove test result directory %s: %s", resultPath, err)
	}
	if err = os.Mkdir(resultPath, 0777); err != nil {
		errorf("Failed to create test result directory %s: %s", resultPath, err)
	}

	// Direct all the output into a file in the test-results directory.
	file, err := os.OpenFile(path.Join(resultPath, "app.log"), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err != nil {
		errorf("Failed to create log file: %s", err)
	}

	app, reverr := harness.Build()
	if reverr != nil {
		errorf("Error building: %s", reverr)
	}
	cmd := app.Cmd()
	cmd.Stderr = file
	cmd.Stdout = file

	// Start the app...
	cmd.Start()
	defer cmd.Kill()
	revel.INFO.Printf("Testing %s (%s) in %s mode\n", revel.AppName, revel.ImportPath, mode)

	// Get a list of tests.
	var testSuites []controllers.TestSuiteDesc
	baseUrl := fmt.Sprintf("http://127.0.0.1:%d", revel.HttpPort)
	resp, err := http.Get(baseUrl + "/@tests.list")
	if err != nil {
		errorf("Failed to request test list: %s", err)
	}
	defer resp.Body.Close()
	json.NewDecoder(resp.Body).Decode(&testSuites)

	fmt.Printf("\n%d test suite%s to run.\n", len(testSuites), pluralize(len(testSuites), "", "s"))
	fmt.Println()

	// Load the result template, which we execute for each suite.
	TemplateLoader := revel.NewTemplateLoader(revel.TemplatePaths)
	if err := TemplateLoader.Refresh(); err != nil {
		errorf("Failed to compile templates: %s", err)
	}
	resultTemplate, err := TemplateLoader.Template("TestRunner/SuiteResult.html")
	if err != nil {
		errorf("Failed to load suite result template: %s", err)
	}

	// Run each suite.
	failedResults := make([]controllers.TestSuiteResult)
	overallSuccess := true
	for _, suite := range testSuites {
		// Print the name of the suite we're running.
		name := suite.Name
		if len(name) > 22 {
			name = name[:19] + "..."
		}
		fmt.Printf("%-22s", name)

		// Run every test.
		startTime := time.Now()
		suiteResult := controllers.TestSuiteResult{Name: suite.Name, Passed: true}
		for _, test := range suite.Tests {
			testUrl := baseUrl + "/@tests/" + suite.Name + "/" + test.Name
			resp, err := http.Get(testUrl)
			if err != nil {
				errorf("Failed to fetch test result at url %s: %s", testUrl, err)
			}
			defer resp.Body.Close()

			var testResult controllers.TestResult
			json.NewDecoder(resp.Body).Decode(&testResult)
			if !testResult.Passed {
				suiteResult.Passed = false
			}
			suiteResult.Results = append(suiteResult.Results, testResult)
		}
		overallSuccess = overallSuccess && suiteResult.Passed

		// Print result.  (Just PASSED or FAILED, and the time taken)
		suiteResultStr, suiteAlert := "PASSED", ""
		if !suiteResult.Passed {
			suiteResultStr, suiteAlert = "FAILED", "!"
			failedResults = append(failedResults, suiteResult)
		}
		fmt.Printf("%8s%3s%6ds\n", suiteResultStr, suiteAlert, int(time.Since(startTime).Seconds()))
		// Create the result HTML file.
		suiteResultFilename := path.Join(resultPath,
			fmt.Sprintf("%s.%s.html", suite.Name, strings.ToLower(suiteResultStr)))
		suiteResultFile, err := os.Create(suiteResultFilename)
		if err != nil {
			errorf("Failed to create result file %s: %s", suiteResultFilename, err)
		}
		if err = resultTemplate.Render(suiteResultFile, suiteResult); err != nil {
			errorf("Failed to render result template: %s", err)
		}
	}

	fmt.Println()
	if overallSuccess {
		writeResultFile(resultPath, "result.passed", "passed")
		fmt.Println("All Tests Passed.")
	} else {
		for _, failedResult := range failedResults {
			fmt.Printf("Failures:\n")
			for _, result := range failedResult.Results {
				if !result.Passed {
					fmt.Printf("%s.%s\n", failedResult.Name, result.Name)
					fmt.Printf("%s\n\n", result.ErrorSummary)
				}
			}
		}
		writeResultFile(resultPath, "result.failed", "failed")
		errorf("Some tests failed.  See file://%s for results.", resultPath)
	}
}

func writeResultFile(resultPath, name, content string) {
	if err := ioutil.WriteFile(path.Join(resultPath, name), []byte(content), 0666); err != nil {
		errorf("Failed to write result file %s: %s", path.Join(resultPath, name), err)
	}
}

func pluralize(num int, singular, plural string) string {
	if num == 1 {
		return singular
	}
	return plural
}
<commit_msg>Fix build breakage<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/robfig/revel"
	"github.com/robfig/revel/harness"
	"github.com/robfig/revel/modules/testrunner/app/controllers"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"strings"
	"time"
)

var cmdTest = &Command{
	UsageLine: "test [import path] [run mode]",
	Short:     "run all tests from the command-line",
	Long: `
Run all tests for the Revel app named by the given import path.

For example, to run the booking sample application's tests:

    revel test github.com/robfig/revel/samples/booking dev

The run mode is used to select which set of app.conf configuration should
apply and may be used to determine logic in the application itself.

Run mode defaults to "dev".`,
}

func init() {
	cmdTest.Run = testApp
}

func testApp(args []string) {
	var err error
	if len(args) == 0 {
		errorf("No import path given.\nRun 'revel help test' for usage.\n")
	}

	mode := "dev"
	if len(args) == 2 {
		mode = args[1]
	}

	// Find and parse app.conf
	revel.Init(mode, args[0], "")

	// Ensure that the testrunner is loaded in this mode.
	testRunnerFound := false
	for _, module := range revel.Modules {
		if module.ImportPath == "github.com/robfig/revel/modules/testrunner" {
			testRunnerFound = true
			break
		}
	}
	if !testRunnerFound {
		errorf(`Error: The testrunner module is not running.

You can add it to a run mode configuration with the following line:

	module.testrunner = github.com/robfig/revel/modules/testrunner

`)
	}

	// Create a directory to hold the test result files.
	resultPath := path.Join(revel.BasePath, "test-results")
	if err = os.RemoveAll(resultPath); err != nil {
		errorf("Failed to remove test result directory %s: %s", resultPath, err)
	}
	if err = os.Mkdir(resultPath, 0777); err != nil {
		errorf("Failed to create test result directory %s: %s", resultPath, err)
	}

	// Direct all the output into a file in the test-results directory.
	file, err := os.OpenFile(path.Join(resultPath, "app.log"), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err != nil {
		errorf("Failed to create log file: %s", err)
	}

	app, reverr := harness.Build()
	if reverr != nil {
		errorf("Error building: %s", reverr)
	}
	cmd := app.Cmd()
	cmd.Stderr = file
	cmd.Stdout = file

	// Start the app...
	cmd.Start()
	defer cmd.Kill()
	revel.INFO.Printf("Testing %s (%s) in %s mode\n", revel.AppName, revel.ImportPath, mode)

	// Get a list of tests.
	var testSuites []controllers.TestSuiteDesc
	baseUrl := fmt.Sprintf("http://127.0.0.1:%d", revel.HttpPort)
	resp, err := http.Get(baseUrl + "/@tests.list")
	if err != nil {
		errorf("Failed to request test list: %s", err)
	}
	defer resp.Body.Close()
	json.NewDecoder(resp.Body).Decode(&testSuites)

	fmt.Printf("\n%d test suite%s to run.\n", len(testSuites), pluralize(len(testSuites), "", "s"))
	fmt.Println()

	// Load the result template, which we execute for each suite.
	TemplateLoader := revel.NewTemplateLoader(revel.TemplatePaths)
	if err := TemplateLoader.Refresh(); err != nil {
		errorf("Failed to compile templates: %s", err)
	}
	resultTemplate, err := TemplateLoader.Template("TestRunner/SuiteResult.html")
	if err != nil {
		errorf("Failed to load suite result template: %s", err)
	}

	// Run each suite.
	var (
		overallSuccess = true
		failedResults []controllers.TestSuiteResult
	)
	for _, suite := range testSuites {
		// Print the name of the suite we're running.
		name := suite.Name
		if len(name) > 22 {
			name = name[:19] + "..."
		}
		fmt.Printf("%-22s", name)

		// Run every test.
		startTime := time.Now()
		suiteResult := controllers.TestSuiteResult{Name: suite.Name, Passed: true}
		for _, test := range suite.Tests {
			testUrl := baseUrl + "/@tests/" + suite.Name + "/" + test.Name
			resp, err := http.Get(testUrl)
			if err != nil {
				errorf("Failed to fetch test result at url %s: %s", testUrl, err)
			}
			defer resp.Body.Close()

			var testResult controllers.TestResult
			json.NewDecoder(resp.Body).Decode(&testResult)
			if !testResult.Passed {
				suiteResult.Passed = false
			}
			suiteResult.Results = append(suiteResult.Results, testResult)
		}
		overallSuccess = overallSuccess && suiteResult.Passed

		// Print result.  (Just PASSED or FAILED, and the time taken)
		suiteResultStr, suiteAlert := "PASSED", ""
		if !suiteResult.Passed {
			suiteResultStr, suiteAlert = "FAILED", "!"
			failedResults = append(failedResults, suiteResult)
		}
		fmt.Printf("%8s%3s%6ds\n", suiteResultStr, suiteAlert, int(time.Since(startTime).Seconds()))
		// Create the result HTML file.
		suiteResultFilename := path.Join(resultPath,
			fmt.Sprintf("%s.%s.html", suite.Name, strings.ToLower(suiteResultStr)))
		suiteResultFile, err := os.Create(suiteResultFilename)
		if err != nil {
			errorf("Failed to create result file %s: %s", suiteResultFilename, err)
		}
		if err = resultTemplate.Render(suiteResultFile, suiteResult); err != nil {
			errorf("Failed to render result template: %s", err)
		}
	}

	fmt.Println()
	if overallSuccess {
		writeResultFile(resultPath, "result.passed", "passed")
		fmt.Println("All Tests Passed.")
	} else {
		for _, failedResult := range failedResults {
			fmt.Printf("Failures:\n")
			for _, result := range failedResult.Results {
				if !result.Passed {
					fmt.Printf("%s.%s\n", failedResult.Name, result.Name)
					fmt.Printf("%s\n\n", result.ErrorSummary)
				}
			}
		}
		writeResultFile(resultPath, "result.failed", "failed")
		errorf("Some tests failed.  See file://%s for results.", resultPath)
	}
}

func writeResultFile(resultPath, name, content string) {
	if err := ioutil.WriteFile(path.Join(resultPath, name), []byte(content), 0666); err != nil {
		errorf("Failed to write result file %s: %s", path.Join(resultPath, name), err)
	}
}

func pluralize(num int, singular, plural string) string {
	if num == 1 {
		return singular
	}
	return plural
}
<|endoftext|>


<commit_before>package cmds

import (
	"io"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"
	"syscall"
)

const (
	statusURL = "https://otale.github.io/status/version.json"
	pidFile   = "tale.pid"
)

// StartAction 启动 tale 博客
func StartAction() error {
	os.Remove(pidFile)
	shell := "nohup java -Xms256m -Xmx256m -Dfile.encoding=UTF-8 -jar tale-letast.jar > /dev/null 2>&1 & echo $! > " + pidFile
	_, _, _, err := StartCmd(shell)
	if err != nil {
		return err
	}
	log.Println("博客程序已经启动成功，可使用 log 命令查看日志")
	return err
}

// StopAction 停止 tale 博客
func StopAction() error {
	dat, err := ioutil.ReadFile(pidFile)
	if err != nil {
		log.Println("博客程序已经停止")
		return nil
	}
	log.Println("pid:", strings.TrimSpace(string(dat)))

	pid, err := strconv.Atoi(strings.TrimSpace(string(dat)))
	if err != nil {
		return err
	}
	err = syscall.Kill(pid, syscall.Signal(2))
	// _, err = KillPID(pid)
	if err != nil {
		log.Println("err", err)
		return err
	}
	err = os.Remove(pidFile)
	if err != nil {
		return err
	}
	log.Println("博客程序已经停止")
	return nil
}

// RestartAction 重启 tale 博客
func RestartAction() error {
	err := StopAction()
	if err == nil {
		StartAction()
	}
	return err
}

// StatusAction 查看博客运行状态
func StatusAction() error {
	dat, err := ioutil.ReadFile(pidFile)
	if err != nil {
		log.Println("博客已经停止运行")
		return nil
	}
	pid := strings.TrimSpace(string(dat))
	if pid == "" {
		log.Println("博客已经停止运行")
		return nil
	}
	pidInt, err := strconv.Atoi(strings.TrimSpace(string(dat)))
	if err != nil {
		return err
	}
	_, err = os.FindProcess(pidInt)
	if err != nil {
		return nil
	}
	log.Println("Tale 博客正在运行")
	return nil
}

// LogAction 输出日志
func LogAction() error {
	_, stdout, stderr, err := StartCmd("tail -f logs/tale.log")
	if err != nil {
		return err
	}
	go io.Copy(os.Stdout, stdout)
	go io.Copy(os.Stderr, stderr)
	select {}
}

// UpgradeAction 升级博客
func UpgradeAction() error {
	return nil
}

// BackupAction 备份博客，SQL和当前全部状态
func BackupAction() error {
	return nil
}
<commit_msg>:bug: fixed repeat start<commit_after>package cmds

import (
	"io"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"
)

const (
	statusURL = "https://otale.github.io/status/version.json"
	pidFile   = "tale.pid"
)

// StartAction 启动 tale 博客
func StartAction() error {
	dat, err := ioutil.ReadFile(pidFile)
	if err == nil {
		pid := strings.TrimSpace(string(dat))
		if pid != "" {
			pidInt, err := strconv.Atoi(strings.TrimSpace(string(dat)))
			if err != nil {
				return err
			}
			_, err = os.FindProcess(pidInt)
			if err != nil {
				return nil
			}
			log.Println("博客已经启动成功，请停止后重启.")
			return nil
		}
	}

	os.Remove(pidFile)
	shell := "nohup java -Xms256m -Xmx256m -Dfile.encoding=UTF-8 -jar tale-letast.jar > /dev/null 2>&1 & echo $! > " + pidFile
	_, _, _, err = StartCmd(shell)
	if err != nil {
		return err
	}
	log.Println("博客程序已经启动成功，可使用 log 命令查看日志")
	return err
}

// StopAction 停止 tale 博客
func StopAction() error {
	dat, err := ioutil.ReadFile(pidFile)
	if err != nil {
		log.Println("博客程序已经停止")
		return nil
	}
	log.Println("pid:", strings.TrimSpace(string(dat)))

	pid, err := strconv.Atoi(strings.TrimSpace(string(dat)))
	if err != nil {
		return err
	}
	KillPID(pid)
	err = os.Remove(pidFile)
	if err != nil {
		return err
	}
	log.Println("博客程序已经停止")
	return nil
}

// RestartAction 重启 tale 博客
func RestartAction() error {
	err := StopAction()
	if err == nil {
		StartAction()
	}
	return err
}

// StatusAction 查看博客运行状态
func StatusAction() error {
	dat, err := ioutil.ReadFile(pidFile)
	if err != nil {
		log.Println("博客已经停止运行")
		return nil
	}
	pid := strings.TrimSpace(string(dat))
	if pid == "" {
		log.Println("博客已经停止运行")
		return nil
	}
	pidInt, err := strconv.Atoi(strings.TrimSpace(string(dat)))
	if err != nil {
		return err
	}
	_, err = os.FindProcess(pidInt)
	if err != nil {
		return nil
	}
	log.Println("Tale 博客正在运行")
	return nil
}

// LogAction 输出日志
func LogAction() error {
	_, stdout, stderr, err := StartCmd("tail -f logs/tale.log")
	if err != nil {
		return err
	}
	go io.Copy(os.Stdout, stdout)
	go io.Copy(os.Stderr, stderr)
	select {}
}

// UpgradeAction 升级博客
func UpgradeAction() error {
	return nil
}

// BackupAction 备份博客，SQL和当前全部状态
func BackupAction() error {
	return nil
}
<|endoftext|>


<commit_before><commit_msg>netflow default enabled, workers # changed to 200<commit_after><|endoftext|>


<commit_before>// +build !arm

package library

import (
	"github.com/deepglint/streamtools/st/blocks"
)

var Blocks = map[string]func() blocks.BlockInterface{
	"bang":               NewBang,
	"cache":              NewCache,
	"categorical":        NewCategorical,
	"count":              NewCount,
	"dedupe":             NewDeDupe,
	"fft":                NewFFT,
	"filter":             NewFilter,
	"fromamqp":           NewFromAMQP,
	"fromemail":          NewFromEmail,
	"fromfile":           NewFromFile,
	"fromHTTPGetRequest": NewFromHTTPGetRequest,
	"fromhttpstream":     NewFromHTTPStream,
	"fromnsq":            NewFromNSQ,
	"frompost":           NewFromPost,
	"fromsqs":            NewFromSQS,
	"fromwebsocket":      NewFromWebsocket,
	"fromudp":            NewFromUDP,
	"gaussian":           NewGaussian,
	"gethttp":            NewGetHTTP,
	"histogram":          NewHistogram,
	"join":               NewJoin,
	"kullbackleibler":    NewKullbackLeibler,
	"learn":              NewLearn,
	"linearModel":        NewLinearModel,
	"logisticModel":      NewLogisticModel,
	"map":                NewMap,
	"mask":               NewMask,
	"movingaverage":      NewMovingAverage,
	"packbycount":        NewPackByCount,
	"packbyinterval":     NewPackByInterval,
	"packbyvalue":        NewPackByValue,
	"parsecsv":           NewParseCSV,
	"parsexml":           NewParseXML,
	"poisson":            NewPoisson,
	"javascript":         NewJavascript,
	"queue":              NewQueue,
	"redis":              NewRedis,
	"set":                NewSet,
	"sync":               NewSync,
	"ticker":             NewTicker,
	"timeseries":         NewTimeseries,
	"toamqp":             NewToAMQP,
	"tobeanstalkd":       NewToBeanstalkd,
	"toelasticsearch":    NewToElasticsearch,
	"toemail":            NewToEmail,
	"tofile":             NewToFile,
	"toggle":             NewToggle,
	"toHTTPGetRequest":   NewToHTTPGetRequest,
	"tolog":              NewToLog,
	"tomongodb":          NewToMongoDB,
	"tonsq":              NewToNSQ,
	"tonsqmulti":         NewToNSQMulti,
	"unpack":             NewUnpack,
	"webRequest":         NewWebRequest,
	"zipf":               NewZipf,
	"exponential":        NewExponential,
}

var BlockDefs = map[string]*blocks.BlockDef{}

func Start() {
	for k, newBlock := range Blocks {
		b := newBlock()
		b.Build(blocks.BlockChans{nil, nil, nil, nil, nil, nil, nil, nil})
		b.Setup()
		BlockDefs[k] = b.GetDef()
	}
}
<commit_msg>Added helper method for customized blocks.<commit_after>// +build !arm

package library

import (
	"github.com/deepglint/streamtools/st/blocks"
	"sync"
)

var Blocks = map[string]func() blocks.BlockInterface{
	"bang":               NewBang,
	"cache":              NewCache,
	"categorical":        NewCategorical,
	"count":              NewCount,
	"dedupe":             NewDeDupe,
	"fft":                NewFFT,
	"filter":             NewFilter,
	"fromamqp":           NewFromAMQP,
	"fromemail":          NewFromEmail,
	"fromfile":           NewFromFile,
	"fromHTTPGetRequest": NewFromHTTPGetRequest,
	"fromhttpstream":     NewFromHTTPStream,
	"fromnsq":            NewFromNSQ,
	"frompost":           NewFromPost,
	"fromsqs":            NewFromSQS,
	"fromwebsocket":      NewFromWebsocket,
	"fromudp":            NewFromUDP,
	"gaussian":           NewGaussian,
	"gethttp":            NewGetHTTP,
	"histogram":          NewHistogram,
	"join":               NewJoin,
	"kullbackleibler":    NewKullbackLeibler,
	"learn":              NewLearn,
	"linearModel":        NewLinearModel,
	"logisticModel":      NewLogisticModel,
	"map":                NewMap,
	"mask":               NewMask,
	"movingaverage":      NewMovingAverage,
	"packbycount":        NewPackByCount,
	"packbyinterval":     NewPackByInterval,
	"packbyvalue":        NewPackByValue,
	"parsecsv":           NewParseCSV,
	"parsexml":           NewParseXML,
	"poisson":            NewPoisson,
	"javascript":         NewJavascript,
	"queue":              NewQueue,
	"redis":              NewRedis,
	"set":                NewSet,
	"sync":               NewSync,
	"ticker":             NewTicker,
	"timeseries":         NewTimeseries,
	"toamqp":             NewToAMQP,
	"tobeanstalkd":       NewToBeanstalkd,
	"toelasticsearch":    NewToElasticsearch,
	"toemail":            NewToEmail,
	"tofile":             NewToFile,
	"toggle":             NewToggle,
	"toHTTPGetRequest":   NewToHTTPGetRequest,
	"tolog":              NewToLog,
	"tomongodb":          NewToMongoDB,
	"tonsq":              NewToNSQ,
	"tonsqmulti":         NewToNSQMulti,
	"unpack":             NewUnpack,
	"webRequest":         NewWebRequest,
	"zipf":               NewZipf,
	"exponential":        NewExponential,
}

var BlockDefs = map[string]*blocks.BlockDef{}
var blocksMutex = new(sync.Mutex)

func RegisterBlock(id string, constructor func() blocks.BlockInterface) bool {
	blocksMutex.Lock()
	defer blocksMutex.Unlock()
	if _, ok := Blocks[id]; ok {
		return false
	}
	Blocks[id] = constructor
	return true
}

func RegisterBlocks(blocks map[string]func() blocks.BlockInterface) {
	for k, f := range blocks {
		RegisterBlock(k, f)
	}
}

func Start() {
	for k, newBlock := range Blocks {
		b := newBlock()
		b.Build(blocks.BlockChans{nil, nil, nil, nil, nil, nil, nil, nil})
		b.Setup()
		BlockDefs[k] = b.GetDef()
	}
}
<|endoftext|>