Merge "runtimes/google/rt: bring back tests for runtime shutdown."
diff --git a/lib/cmdline/cmdline.go b/lib/cmdline/cmdline.go
deleted file mode 100644
index 5c71607..0000000
--- a/lib/cmdline/cmdline.go
+++ /dev/null
@@ -1,506 +0,0 @@
-// Package cmdline provides a data-driven framework to simplify writing
-// command-line programs. It includes built-in support for formatted help.
-//
-// Commands may be linked together to form a command tree. Since commands may
-// be arbitrarily nested within other commands, it's easy to create wrapper
-// programs that invoke existing commands.
-//
-// The syntax for each command-line program is:
-//
-// command [flags] [subcommand [flags]]* [args]
-//
-// Each sequence of flags on the command-line is associated with the command
-// that immediately precedes them. Global flags registered with the standard
-// flags package are allowed anywhere a command-specific flag is allowed.
-package cmdline
-
-import (
- "flag"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "strconv"
- "strings"
-
- "veyron.io/veyron/veyron/lib/textutil"
-)
-
-// ErrExitCode may be returned by the Run function of a Command to cause the
-// program to exit with a specific error code.
-type ErrExitCode int
-
-func (x ErrExitCode) Error() string {
- return fmt.Sprintf("exit code %d", x)
-}
-
-// ErrUsage is returned to indicate an error in command usage; e.g. unknown
-// flags, subcommands or args. It corresponds to exit code 1.
-const ErrUsage = ErrExitCode(1)
-
-// Command represents a single command in a command-line program. A program
-// with subcommands is represented as a root Command with children representing
-// each subcommand. The command graph must be a tree; each command may either
-// have exactly one parent (a sub-command), or no parent (the root), and cycles
-// are not allowed. This makes it easier to display the usage for subcommands.
-type Command struct {
- Name string // Name of the command.
- Short string // Short description, shown in help called on parent.
- Long string // Long description, shown in help called on itself.
- Flags flag.FlagSet // Flags for the command.
- ArgsName string // Name of the args, shown in usage line.
- ArgsLong string // Long description of the args, shown in help.
-
- // Children of the command. The framework will match args[0] against each
- // child's name, and call Run on the first matching child.
- Children []*Command
-
- // Topics that provide additional info via the default help command.
- Topics []Topic
-
- // Run is a function that runs cmd with args. If both Children and Run are
- // specified, Run will only be called if none of the children match. It is an
- // error if neither is specified. The special ErrExitCode error may be
- // returned to indicate the command should exit with a specific exit code.
- Run func(cmd *Command, args []string) error
-
- // parent holds the parent of this Command, or nil if this is the root.
- parent *Command
-
- // stdout and stderr are set through Init.
- stdout, stderr io.Writer
-
- // parseFlags holds the merged flags used for parsing. Each command starts
- // with its own Flags, and we merge in all global flags. If the same flag is
- // specified in both sets, the command's own flag wins.
- parseFlags *flag.FlagSet
-
- // isDefaultHelp indicates whether this is the the default help command
- // provided by the framework.
- isDefaultHelp bool
-
- // TODO(toddw): If necessary we can add alias support, e.g. for abbreviations.
- // Alias map[string]string
-}
-
-// Topic represents an additional help topic that is accessed via the default
-// help command.
-type Topic struct {
- Name string // Name of the topic.
- Short string // Short description, shown in help for the command.
- Long string // Long description, shown in help for this topic.
-}
-
-// style describes the formatting style for usage descriptions.
-type style int
-
-const (
- styleText style = iota // Default style, good for cmdline output.
- styleGoDoc // Style good for godoc processing.
-)
-
-// String returns the human-readable representation of the style.
-func (s *style) String() string {
- switch *s {
- case styleText:
- return "text"
- case styleGoDoc:
- return "godoc"
- default:
- panic(fmt.Errorf("Unhandled style %d", *s))
- }
-}
-
-// Set implements the flag.Value interface method.
-func (s *style) Set(value string) error {
- switch value {
- case "text":
- *s = styleText
- case "godoc":
- *s = styleGoDoc
- default:
- return fmt.Errorf("Unknown style %q", value)
- }
- return nil
-}
-
-// Stdout is where output goes. Typically os.Stdout.
-func (cmd *Command) Stdout() io.Writer {
- return cmd.stdout
-}
-
-// Stderr is where error messages go. Typically os.Stderr
-func (cmd *Command) Stderr() io.Writer {
- return cmd.stderr
-}
-
-// UsageErrorf prints the error message represented by the printf-style format
-// string and args, followed by the usage description of cmd. Returns ErrUsage
-// to make it easy to use from within the cmd.Run function.
-func (cmd *Command) UsageErrorf(format string, v ...interface{}) error {
- fmt.Fprint(cmd.stderr, "ERROR: ")
- fmt.Fprintf(cmd.stderr, format, v...)
- fmt.Fprint(cmd.stderr, "\n\n")
- cmd.writeUsage(cmd.stderr)
- return ErrUsage
-}
-
-// Have a reasonable default for the output width in runes.
-const defaultWidth = 80
-
-func outputWidth() int {
- if width, err := strconv.Atoi(os.Getenv("CMDLINE_WIDTH")); err == nil && width != 0 {
- return width
- }
- if _, width, err := textutil.TerminalSize(); err == nil && width != 0 {
- return width
- }
- return defaultWidth
-}
-
-func (cmd *Command) writeUsage(w io.Writer) {
- lineWriter := textutil.NewUTF8LineWriter(w, outputWidth())
- cmd.usage(lineWriter, true)
- lineWriter.Flush()
-}
-
-// usage prints the usage of cmd to the writer. The firstCall boolean is set to
-// false when printing usage for multiple commands, and is used to avoid
-// printing redundant information (e.g. help command, global flags).
-func (cmd *Command) usage(w *textutil.LineWriter, firstCall bool) {
- fmt.Fprintln(w, cmd.Long)
- fmt.Fprintln(w)
- // Usage line.
- hasFlags := numFlags(&cmd.Flags) > 0
- fmt.Fprintln(w, "Usage:")
- path := cmd.namePath()
- pathf := " " + path
- if hasFlags {
- pathf += " [flags]"
- }
- if len(cmd.Children) > 0 {
- fmt.Fprintln(w, pathf, "<command>")
- }
- if cmd.Run != nil {
- if cmd.ArgsName != "" {
- fmt.Fprintln(w, pathf, cmd.ArgsName)
- } else {
- fmt.Fprintln(w, pathf)
- }
- }
- if len(cmd.Children) == 0 && cmd.Run == nil {
- // This is a specification error.
- fmt.Fprintln(w, pathf, "[ERROR: neither Children nor Run is specified]")
- }
- // Commands.
- const minNameWidth = 11
- if len(cmd.Children) > 0 {
- fmt.Fprintln(w)
- fmt.Fprintln(w, "The", path, "commands are:")
- nameWidth := minNameWidth
- for _, child := range cmd.Children {
- if len(child.Name) > nameWidth {
- nameWidth = len(child.Name)
- }
- }
- // Print as a table with aligned columns Name and Short.
- w.SetIndents(spaces(3), spaces(3+nameWidth+1))
- for _, child := range cmd.Children {
- // Don't repeatedly list default help command.
- if !child.isDefaultHelp || firstCall {
- fmt.Fprintf(w, "%-[1]*[2]s %[3]s", nameWidth, child.Name, child.Short)
- w.Flush()
- }
- }
- w.SetIndents()
- if firstCall {
- fmt.Fprintf(w, "Run \"%s help [command]\" for command usage.\n", path)
- }
- }
- // Args.
- if cmd.Run != nil && cmd.ArgsLong != "" {
- fmt.Fprintln(w)
- fmt.Fprintln(w, cmd.ArgsLong)
- }
- // Help topics.
- if len(cmd.Topics) > 0 {
- fmt.Fprintln(w)
- fmt.Fprintln(w, "The", path, "additional help topics are:")
- nameWidth := minNameWidth
- for _, topic := range cmd.Topics {
- if len(topic.Name) > nameWidth {
- nameWidth = len(topic.Name)
- }
- }
- // Print as a table with aligned columns Name and Short.
- w.SetIndents(spaces(3), spaces(3+nameWidth+1))
- for _, topic := range cmd.Topics {
- fmt.Fprintf(w, "%-[1]*[2]s %[3]s", nameWidth, topic.Name, topic.Short)
- w.Flush()
- }
- w.SetIndents()
- if firstCall {
- fmt.Fprintf(w, "Run \"%s help [topic]\" for topic details.\n", path)
- }
- }
- // Flags.
- if hasFlags {
- fmt.Fprintln(w)
- fmt.Fprintln(w, "The", path, "flags are:")
- printFlags(w, &cmd.Flags)
- }
- // Global flags.
- if numFlags(flag.CommandLine) > 0 && firstCall {
- fmt.Fprintln(w)
- fmt.Fprintln(w, "The global flags are:")
- printFlags(w, flag.CommandLine)
- }
-}
-
-// namePath returns the path of command names up to cmd.
-func (cmd *Command) namePath() string {
- var path []string
- for ; cmd != nil; cmd = cmd.parent {
- path = append([]string{cmd.Name}, path...)
- }
- return strings.Join(path, " ")
-}
-
-func numFlags(set *flag.FlagSet) (num int) {
- set.VisitAll(func(*flag.Flag) {
- num++
- })
- return
-}
-
-func printFlags(w *textutil.LineWriter, set *flag.FlagSet) {
- set.VisitAll(func(f *flag.Flag) {
- fmt.Fprintf(w, " -%s=%s", f.Name, f.DefValue)
- w.SetIndents(spaces(3))
- fmt.Fprintln(w, f.Usage)
- w.SetIndents()
- })
-}
-
-func spaces(count int) string {
- return strings.Repeat(" ", count)
-}
-
-// newDefaultHelp creates a new default help command. We need to create new
-// instances since the parent for each help command is different.
-func newDefaultHelp() *Command {
- helpStyle := styleText
- help := &Command{
- Name: helpName,
- Short: "Display help for commands or topics",
- Long: `
-Help with no args displays the usage of the parent command.
-
-Help with args displays the usage of the specified sub-command or help topic.
-
-"help ..." recursively displays help for all commands and topics.
-
-The output is formatted to a target width in runes. The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars. By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
-`,
- ArgsName: "[command/topic ...]",
- ArgsLong: `
-[command/topic ...] optionally identifies a specific sub-command or help topic.
-`,
- Run: func(cmd *Command, args []string) error {
- // Help applies to its parent - e.g. "foo help" applies to the foo command.
- lineWriter := textutil.NewUTF8LineWriter(cmd.stdout, outputWidth())
- defer lineWriter.Flush()
- return runHelp(lineWriter, cmd.parent, args, helpStyle)
- },
- isDefaultHelp: true,
- }
- help.Flags.Var(&helpStyle, "style", `The formatting style for help output, either "text" or "godoc".`)
- return help
-}
-
-const helpName = "help"
-
-// runHelp runs the "help" command.
-func runHelp(w *textutil.LineWriter, cmd *Command, args []string, style style) error {
- if len(args) == 0 {
- cmd.usage(w, true)
- return nil
- }
- if args[0] == "..." {
- recursiveHelp(w, cmd, style, true)
- return nil
- }
- // Try to display help for the subcommand.
- subName, subArgs := args[0], args[1:]
- for _, child := range cmd.Children {
- if child.Name == subName {
- return runHelp(w, child, subArgs, style)
- }
- }
- // Try to display help for the help topic.
- for _, topic := range cmd.Topics {
- if topic.Name == subName {
- fmt.Fprintln(w, topic.Long)
- return nil
- }
- }
- return cmd.UsageErrorf("%s: unknown command or topic %q", cmd.namePath(), subName)
-}
-
-// recursiveHelp prints help recursively via DFS from this cmd onward.
-func recursiveHelp(w *textutil.LineWriter, cmd *Command, style style, firstCall bool) {
- if !firstCall {
- lineBreak(w, style)
- // Title-case required for godoc to recognize this as a section header.
- header := strings.Title(cmd.namePath())
- fmt.Fprintln(w, header)
- fmt.Fprintln(w)
- }
- cmd.usage(w, firstCall)
- for _, child := range cmd.Children {
- // Don't repeatedly print default help command.
- if !child.isDefaultHelp || firstCall {
- recursiveHelp(w, child, style, false)
- }
- }
- for _, topic := range cmd.Topics {
- lineBreak(w, style)
- // Title-case required for godoc to recognize this as a section header.
- header := strings.Title(cmd.namePath()+" "+topic.Name) + " - help topic"
- fmt.Fprintln(w, header)
- fmt.Fprintln(w)
- fmt.Fprintln(w, topic.Long)
- }
-}
-
-func lineBreak(w *textutil.LineWriter, style style) {
- w.Flush()
- switch style {
- case styleText:
- width := w.Width()
- if width < 0 {
- // If the user has chosen an "unlimited" word-wrapping width, we still
- // need a reasonable width for our visual line break.
- width = defaultWidth
- }
- fmt.Fprintln(w, strings.Repeat("=", width))
- case styleGoDoc:
- fmt.Fprintln(w)
- }
- w.Flush()
-}
-
-func trimNewlines(s *string) { *s = strings.Trim(*s, "\n") }
-
-// Init initializes all nodes in the command tree rooted at cmd. Init must be
-// called before Execute.
-func (cmd *Command) Init(parent *Command, stdout, stderr io.Writer) {
- cmd.parent = parent
- cmd.stdout = stdout
- cmd.stderr = stderr
- trimNewlines(&cmd.Short)
- trimNewlines(&cmd.Long)
- trimNewlines(&cmd.ArgsLong)
- for tx := range cmd.Topics {
- trimNewlines(&cmd.Topics[tx].Short)
- trimNewlines(&cmd.Topics[tx].Long)
- }
- // Add help command, if it doesn't already exist.
- hasHelp := false
- for _, child := range cmd.Children {
- if child.Name == helpName {
- hasHelp = true
- break
- }
- }
- if !hasHelp && cmd.Name != helpName && len(cmd.Children) > 0 {
- cmd.Children = append(cmd.Children, newDefaultHelp())
- }
- // Merge command-specific and global flags into parseFlags. We want to handle
- // all error output ourselves, so we:
- // 1) Set flag.ContinueOnError so that Parse() doesn't exit or panic.
- // 2) Discard all output (can't be nil, that means stderr).
- // 3) Set an empty Usage function (can't be nil, that means default).
- cmd.parseFlags = flag.NewFlagSet(cmd.Name, flag.ContinueOnError)
- cmd.parseFlags.SetOutput(ioutil.Discard)
- cmd.parseFlags.Usage = emptyUsage
- mergeFlags(cmd.parseFlags, &cmd.Flags)
- mergeFlags(cmd.parseFlags, flag.CommandLine)
- // Call children recursively.
- for _, child := range cmd.Children {
- child.Init(cmd, stdout, stderr)
- }
-}
-
-func mergeFlags(dst, src *flag.FlagSet) {
- src.VisitAll(func(f *flag.Flag) {
- trimNewlines(&f.Usage)
- if dst.Lookup(f.Name) == nil {
- dst.Var(f.Value, f.Name, f.Usage)
- }
- })
-}
-
-func emptyUsage() {}
-
-// Execute the command with the given args. The returned error is ErrUsage if
-// there are usage errors, otherwise it is whatever the leaf command returns
-// from its Run function.
-func (cmd *Command) Execute(args []string) error {
- path := cmd.namePath()
- // Parse the merged flags.
- if err := cmd.parseFlags.Parse(args); err != nil {
- if err == flag.ErrHelp {
- cmd.writeUsage(cmd.stdout)
- return nil
- }
- return cmd.UsageErrorf("%s: %v", path, err)
- }
- args = cmd.parseFlags.Args()
- // Look for matching children.
- if len(args) > 0 {
- subName, subArgs := args[0], args[1:]
- for _, child := range cmd.Children {
- if child.Name == subName {
- return child.Execute(subArgs)
- }
- }
- }
- // No matching children, try Run.
- if cmd.Run != nil {
- if cmd.ArgsName == "" && len(args) > 0 {
- if len(cmd.Children) > 0 {
- return cmd.UsageErrorf("%s: unknown command %q", path, args[0])
- }
- return cmd.UsageErrorf("%s doesn't take any arguments", path)
- }
- return cmd.Run(cmd, args)
- }
- switch {
- case len(cmd.Children) == 0:
- return cmd.UsageErrorf("%s: neither Children nor Run is specified", path)
- case len(args) > 0:
- return cmd.UsageErrorf("%s: unknown command %q", path, args[0])
- default:
- return cmd.UsageErrorf("%s: no command specified", path)
- }
-}
-
-// Main executes the command tree rooted at cmd, writing output to os.Stdout,
-// writing errors to os.Stderr, and getting args from os.Args. We'll call
-// os.Exit with a non-zero exit code on errors. It's meant as a simple
-// one-liner for the main function of command-line tools.
-func (cmd *Command) Main() {
- cmd.Init(nil, os.Stdout, os.Stderr)
- if err := cmd.Execute(os.Args[1:]); err != nil {
- if code, ok := err.(ErrExitCode); ok {
- os.Exit(int(code))
- }
- fmt.Fprintln(os.Stderr, "ERROR:", err)
- os.Exit(2)
- }
-}
diff --git a/lib/cmdline/cmdline_test.go b/lib/cmdline/cmdline_test.go
deleted file mode 100644
index 6cf6b0e..0000000
--- a/lib/cmdline/cmdline_test.go
+++ /dev/null
@@ -1,2238 +0,0 @@
-package cmdline
-
-import (
- "bytes"
- "errors"
- "flag"
- "fmt"
- "os"
- "regexp"
- "strings"
- "testing"
-)
-
-var (
- errEcho = errors.New("echo error")
- flagExtra bool
- optNoNewline bool
- flagTopLevelExtra bool
- globalFlag1 string
- globalFlag2 *int64
-)
-
-// runEcho is used to implement commands for our tests.
-func runEcho(cmd *Command, args []string) error {
- if len(args) == 1 {
- if args[0] == "error" {
- return errEcho
- } else if args[0] == "bad_arg" {
- return cmd.UsageErrorf("Invalid argument %v", args[0])
- }
- }
- if flagExtra {
- args = append(args, "extra")
- }
- if flagTopLevelExtra {
- args = append(args, "tlextra")
- }
- if optNoNewline {
- fmt.Fprint(cmd.Stdout(), args)
- } else {
- fmt.Fprintln(cmd.Stdout(), args)
- }
- return nil
-}
-
-// runHello is another function for test commands.
-func runHello(cmd *Command, args []string) error {
- if flagTopLevelExtra {
- args = append(args, "tlextra")
- }
- fmt.Fprintln(cmd.Stdout(), strings.Join(append([]string{"Hello"}, args...), " "))
- return nil
-}
-
-type testCase struct {
- Args []string
- Err error
- Stdout string
- Stderr string
- GlobalFlag1 string
- GlobalFlag2 int64
-}
-
-func init() {
- os.Setenv("CMDLINE_WIDTH", "80") // make sure the formatting stays the same.
- flag.StringVar(&globalFlag1, "global1", "", "global test flag 1")
- globalFlag2 = flag.Int64("global2", 0, "global test flag 2")
-}
-
-func stripOutput(got string) string {
- // The global flags include the flags from the testing package, so strip them
- // out before the comparison.
- re := regexp.MustCompile(" -test[^\n]+\n(?: [^\n]+\n)+")
- return re.ReplaceAllLiteralString(got, "")
-}
-
-func runTestCases(t *testing.T, cmd *Command, tests []testCase) {
- for _, test := range tests {
- // Reset global variables before running each test case.
- var stdout bytes.Buffer
- var stderr bytes.Buffer
- flagExtra = false
- flagTopLevelExtra = false
- optNoNewline = false
- globalFlag1 = ""
- *globalFlag2 = 0
-
- // Run the execute function and check against expected results.
- cmd.Init(nil, &stdout, &stderr)
- if err := cmd.Execute(test.Args); err != test.Err {
- t.Errorf("Ran with args %q\n GOT error:\n%q\nWANT error:\n%q", test.Args, err, test.Err)
- }
- if got, want := stripOutput(stdout.String()), test.Stdout; got != want {
- t.Errorf("Ran with args %q\n GOT stdout:\n%q\nWANT stdout:\n%q", test.Args, got, want)
- }
- if got, want := stripOutput(stderr.String()), test.Stderr; got != want {
- t.Errorf("Ran with args %q\n GOT stderr:\n%q\nWANT stderr:\n%q", test.Args, got, want)
- }
- if got, want := globalFlag1, test.GlobalFlag1; got != want {
- t.Errorf("global1 flag got %q, want %q", got, want)
- }
- if got, want := *globalFlag2, test.GlobalFlag2; got != want {
- t.Errorf("global2 flag got %q, want %q", got, want)
- }
- }
-}
-
-func TestNoCommands(t *testing.T) {
- cmd := &Command{
- Name: "nocmds",
- Short: "Nocmds is invalid.",
- Long: "Nocmds has no commands and no run function.",
- }
-
- var tests = []testCase{
- {
- Args: []string{},
- Err: ErrUsage,
- Stderr: `ERROR: nocmds: neither Children nor Run is specified
-
-Nocmds has no commands and no run function.
-
-Usage:
- nocmds [ERROR: neither Children nor Run is specified]
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"foo"},
- Err: ErrUsage,
- Stderr: `ERROR: nocmds: neither Children nor Run is specified
-
-Nocmds has no commands and no run function.
-
-Usage:
- nocmds [ERROR: neither Children nor Run is specified]
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- }
- runTestCases(t, cmd, tests)
-}
-
-func TestOneCommand(t *testing.T) {
- cmdEcho := &Command{
- Name: "echo",
- Short: "Print strings on stdout",
- Long: `
-Echo prints any strings passed in to stdout.
-`,
- Run: runEcho,
- ArgsName: "[strings]",
- ArgsLong: "[strings] are arbitrary strings that will be echoed.",
- }
-
- prog := &Command{
- Name: "onecmd",
- Short: "Onecmd program.",
- Long: "Onecmd only has the echo command.",
- Children: []*Command{cmdEcho},
- }
-
- var tests = []testCase{
- {
- Args: []string{},
- Err: ErrUsage,
- Stderr: `ERROR: onecmd: no command specified
-
-Onecmd only has the echo command.
-
-Usage:
- onecmd <command>
-
-The onecmd commands are:
- echo Print strings on stdout
- help Display help for commands or topics
-Run "onecmd help [command]" for command usage.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"foo"},
- Err: ErrUsage,
- Stderr: `ERROR: onecmd: unknown command "foo"
-
-Onecmd only has the echo command.
-
-Usage:
- onecmd <command>
-
-The onecmd commands are:
- echo Print strings on stdout
- help Display help for commands or topics
-Run "onecmd help [command]" for command usage.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"help"},
- Stdout: `Onecmd only has the echo command.
-
-Usage:
- onecmd <command>
-
-The onecmd commands are:
- echo Print strings on stdout
- help Display help for commands or topics
-Run "onecmd help [command]" for command usage.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"help", "echo"},
- Stdout: `Echo prints any strings passed in to stdout.
-
-Usage:
- onecmd echo [strings]
-
-[strings] are arbitrary strings that will be echoed.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"help", "help"},
- Stdout: `Help with no args displays the usage of the parent command.
-
-Help with args displays the usage of the specified sub-command or help topic.
-
-"help ..." recursively displays help for all commands and topics.
-
-The output is formatted to a target width in runes. The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars. By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
-
-Usage:
- onecmd help [flags] [command/topic ...]
-
-[command/topic ...] optionally identifies a specific sub-command or help topic.
-
-The onecmd help flags are:
- -style=text
- The formatting style for help output, either "text" or "godoc".
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"help", "..."},
- Stdout: `Onecmd only has the echo command.
-
-Usage:
- onecmd <command>
-
-The onecmd commands are:
- echo Print strings on stdout
- help Display help for commands or topics
-Run "onecmd help [command]" for command usage.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-================================================================================
-Onecmd Echo
-
-Echo prints any strings passed in to stdout.
-
-Usage:
- onecmd echo [strings]
-
-[strings] are arbitrary strings that will be echoed.
-================================================================================
-Onecmd Help
-
-Help with no args displays the usage of the parent command.
-
-Help with args displays the usage of the specified sub-command or help topic.
-
-"help ..." recursively displays help for all commands and topics.
-
-The output is formatted to a target width in runes. The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars. By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
-
-Usage:
- onecmd help [flags] [command/topic ...]
-
-[command/topic ...] optionally identifies a specific sub-command or help topic.
-
-The onecmd help flags are:
- -style=text
- The formatting style for help output, either "text" or "godoc".
-`,
- },
- {
- Args: []string{"help", "foo"},
- Err: ErrUsage,
- Stderr: `ERROR: onecmd: unknown command or topic "foo"
-
-Onecmd only has the echo command.
-
-Usage:
- onecmd <command>
-
-The onecmd commands are:
- echo Print strings on stdout
- help Display help for commands or topics
-Run "onecmd help [command]" for command usage.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"echo", "foo", "bar"},
- Stdout: "[foo bar]\n",
- },
- {
- Args: []string{"echo", "error"},
- Err: errEcho,
- },
- {
- Args: []string{"echo", "bad_arg"},
- Err: ErrUsage,
- Stderr: `ERROR: Invalid argument bad_arg
-
-Echo prints any strings passed in to stdout.
-
-Usage:
- onecmd echo [strings]
-
-[strings] are arbitrary strings that will be echoed.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- }
- runTestCases(t, prog, tests)
-}
-
-func TestMultiCommands(t *testing.T) {
- cmdEcho := &Command{
- Run: runEcho,
- Name: "echo",
- Short: "Print strings on stdout",
- Long: `
-Echo prints any strings passed in to stdout.
-`,
- ArgsName: "[strings]",
- ArgsLong: "[strings] are arbitrary strings that will be echoed.",
- }
- var cmdEchoOpt = &Command{
- Run: runEcho,
- Name: "echoopt",
- Short: "Print strings on stdout, with opts",
- // Try varying number of header/trailer newlines around the long description.
- Long: `Echoopt prints any args passed in to stdout.
-
-
-`,
- ArgsName: "[args]",
- ArgsLong: "[args] are arbitrary strings that will be echoed.",
- }
- cmdEchoOpt.Flags.BoolVar(&optNoNewline, "n", false, "Do not output trailing newline")
-
- prog := &Command{
- Name: "multi",
- Short: "Multi test command",
- Long: "Multi has two variants of echo.",
- Children: []*Command{cmdEcho, cmdEchoOpt},
- }
- prog.Flags.BoolVar(&flagExtra, "extra", false, "Print an extra arg")
-
- var tests = []testCase{
- {
- Args: []string{},
- Err: ErrUsage,
- Stderr: `ERROR: multi: no command specified
-
-Multi has two variants of echo.
-
-Usage:
- multi [flags] <command>
-
-The multi commands are:
- echo Print strings on stdout
- echoopt Print strings on stdout, with opts
- help Display help for commands or topics
-Run "multi help [command]" for command usage.
-
-The multi flags are:
- -extra=false
- Print an extra arg
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"help"},
- Stdout: `Multi has two variants of echo.
-
-Usage:
- multi [flags] <command>
-
-The multi commands are:
- echo Print strings on stdout
- echoopt Print strings on stdout, with opts
- help Display help for commands or topics
-Run "multi help [command]" for command usage.
-
-The multi flags are:
- -extra=false
- Print an extra arg
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"help", "..."},
- Stdout: `Multi has two variants of echo.
-
-Usage:
- multi [flags] <command>
-
-The multi commands are:
- echo Print strings on stdout
- echoopt Print strings on stdout, with opts
- help Display help for commands or topics
-Run "multi help [command]" for command usage.
-
-The multi flags are:
- -extra=false
- Print an extra arg
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-================================================================================
-Multi Echo
-
-Echo prints any strings passed in to stdout.
-
-Usage:
- multi echo [strings]
-
-[strings] are arbitrary strings that will be echoed.
-================================================================================
-Multi Echoopt
-
-Echoopt prints any args passed in to stdout.
-
-Usage:
- multi echoopt [flags] [args]
-
-[args] are arbitrary strings that will be echoed.
-
-The multi echoopt flags are:
- -n=false
- Do not output trailing newline
-================================================================================
-Multi Help
-
-Help with no args displays the usage of the parent command.
-
-Help with args displays the usage of the specified sub-command or help topic.
-
-"help ..." recursively displays help for all commands and topics.
-
-The output is formatted to a target width in runes. The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars. By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
-
-Usage:
- multi help [flags] [command/topic ...]
-
-[command/topic ...] optionally identifies a specific sub-command or help topic.
-
-The multi help flags are:
- -style=text
- The formatting style for help output, either "text" or "godoc".
-`,
- },
- {
- Args: []string{"help", "echo"},
- Stdout: `Echo prints any strings passed in to stdout.
-
-Usage:
- multi echo [strings]
-
-[strings] are arbitrary strings that will be echoed.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"help", "echoopt"},
- Stdout: `Echoopt prints any args passed in to stdout.
-
-Usage:
- multi echoopt [flags] [args]
-
-[args] are arbitrary strings that will be echoed.
-
-The multi echoopt flags are:
- -n=false
- Do not output trailing newline
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"help", "foo"},
- Err: ErrUsage,
- Stderr: `ERROR: multi: unknown command or topic "foo"
-
-Multi has two variants of echo.
-
-Usage:
- multi [flags] <command>
-
-The multi commands are:
- echo Print strings on stdout
- echoopt Print strings on stdout, with opts
- help Display help for commands or topics
-Run "multi help [command]" for command usage.
-
-The multi flags are:
- -extra=false
- Print an extra arg
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"echo", "foo", "bar"},
- Stdout: "[foo bar]\n",
- },
- {
- Args: []string{"-extra", "echo", "foo", "bar"},
- Stdout: "[foo bar extra]\n",
- },
- {
- Args: []string{"echo", "error"},
- Err: errEcho,
- },
- {
- Args: []string{"echoopt", "foo", "bar"},
- Stdout: "[foo bar]\n",
- },
- {
- Args: []string{"-extra", "echoopt", "foo", "bar"},
- Stdout: "[foo bar extra]\n",
- },
- {
- Args: []string{"echoopt", "-n", "foo", "bar"},
- Stdout: "[foo bar]",
- },
- {
- Args: []string{"-extra", "echoopt", "-n", "foo", "bar"},
- Stdout: "[foo bar extra]",
- },
- {
- Args: []string{"-global1=globalStringValue", "-extra", "echoopt", "-n", "foo", "bar"},
- Stdout: "[foo bar extra]",
- GlobalFlag1: "globalStringValue",
- },
- {
- Args: []string{"-global2=42", "echoopt", "-n", "foo", "bar"},
- Stdout: "[foo bar]",
- GlobalFlag2: 42,
- },
- {
- Args: []string{"-global1=globalStringOtherValue", "-global2=43", "-extra", "echoopt", "-n", "foo", "bar"},
- Stdout: "[foo bar extra]",
- GlobalFlag1: "globalStringOtherValue",
- GlobalFlag2: 43,
- },
- {
- Args: []string{"echoopt", "error"},
- Err: errEcho,
- },
- {
- Args: []string{"echo", "-n", "foo", "bar"},
- Err: ErrUsage,
- Stderr: `ERROR: multi echo: flag provided but not defined: -n
-
-Echo prints any strings passed in to stdout.
-
-Usage:
- multi echo [strings]
-
-[strings] are arbitrary strings that will be echoed.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"-nosuchflag", "echo", "foo", "bar"},
- Err: ErrUsage,
- Stderr: `ERROR: multi: flag provided but not defined: -nosuchflag
-
-Multi has two variants of echo.
-
-Usage:
- multi [flags] <command>
-
-The multi commands are:
- echo Print strings on stdout
- echoopt Print strings on stdout, with opts
- help Display help for commands or topics
-Run "multi help [command]" for command usage.
-
-The multi flags are:
- -extra=false
- Print an extra arg
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- }
- runTestCases(t, prog, tests)
-}
-
-func TestMultiLevelCommands(t *testing.T) {
- cmdEcho := &Command{
- Run: runEcho,
- Name: "echo",
- Short: "Print strings on stdout",
- Long: `
-Echo prints any strings passed in to stdout.
-`,
- ArgsName: "[strings]",
- ArgsLong: "[strings] are arbitrary strings that will be echoed.",
- }
- cmdEchoOpt := &Command{
- Run: runEcho,
- Name: "echoopt",
- Short: "Print strings on stdout, with opts",
- // Try varying number of header/trailer newlines around the long description.
- Long: `Echoopt prints any args passed in to stdout.
-
-
-`,
- ArgsName: "[args]",
- ArgsLong: "[args] are arbitrary strings that will be echoed.",
- }
- cmdEchoOpt.Flags.BoolVar(&optNoNewline, "n", false, "Do not output trailing newline")
- cmdHello := &Command{
- Run: runHello,
- Name: "hello",
- Short: "Print strings on stdout preceded by \"Hello\"",
- Long: `
-Hello prints any strings passed in to stdout preceded by "Hello".
-`,
- ArgsName: "[strings]",
- ArgsLong: "[strings] are arbitrary strings that will be printed.",
- }
- echoProg := &Command{
- Name: "echoprog",
- Short: "Set of echo commands",
- Long: "Echoprog has two variants of echo.",
- Children: []*Command{cmdEcho, cmdEchoOpt},
- Topics: []Topic{
- {Name: "topic3", Short: "Help topic 3 short", Long: "Help topic 3 long."},
- },
- }
- echoProg.Flags.BoolVar(&flagExtra, "extra", false, "Print an extra arg")
- prog := &Command{
- Name: "toplevelprog",
- Short: "Top level prog",
- Long: "Toplevelprog has the echo subprogram and the hello command.",
- Children: []*Command{echoProg, cmdHello},
- Topics: []Topic{
- {Name: "topic1", Short: "Help topic 1 short", Long: "Help topic 1 long."},
- {Name: "topic2", Short: "Help topic 2 short", Long: "Help topic 2 long."},
- },
- }
- prog.Flags.BoolVar(&flagTopLevelExtra, "tlextra", false, "Print an extra arg for all commands")
-
- var tests = []testCase{
- {
- Args: []string{},
- Err: ErrUsage,
- Stderr: `ERROR: toplevelprog: no command specified
-
-Toplevelprog has the echo subprogram and the hello command.
-
-Usage:
- toplevelprog [flags] <command>
-
-The toplevelprog commands are:
- echoprog Set of echo commands
- hello Print strings on stdout preceded by "Hello"
- help Display help for commands or topics
-Run "toplevelprog help [command]" for command usage.
-
-The toplevelprog additional help topics are:
- topic1 Help topic 1 short
- topic2 Help topic 2 short
-Run "toplevelprog help [topic]" for topic details.
-
-The toplevelprog flags are:
- -tlextra=false
- Print an extra arg for all commands
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"help"},
- Stdout: `Toplevelprog has the echo subprogram and the hello command.
-
-Usage:
- toplevelprog [flags] <command>
-
-The toplevelprog commands are:
- echoprog Set of echo commands
- hello Print strings on stdout preceded by "Hello"
- help Display help for commands or topics
-Run "toplevelprog help [command]" for command usage.
-
-The toplevelprog additional help topics are:
- topic1 Help topic 1 short
- topic2 Help topic 2 short
-Run "toplevelprog help [topic]" for topic details.
-
-The toplevelprog flags are:
- -tlextra=false
- Print an extra arg for all commands
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"help", "..."},
- Stdout: `Toplevelprog has the echo subprogram and the hello command.
-
-Usage:
- toplevelprog [flags] <command>
-
-The toplevelprog commands are:
- echoprog Set of echo commands
- hello Print strings on stdout preceded by "Hello"
- help Display help for commands or topics
-Run "toplevelprog help [command]" for command usage.
-
-The toplevelprog additional help topics are:
- topic1 Help topic 1 short
- topic2 Help topic 2 short
-Run "toplevelprog help [topic]" for topic details.
-
-The toplevelprog flags are:
- -tlextra=false
- Print an extra arg for all commands
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-================================================================================
-Toplevelprog Echoprog
-
-Echoprog has two variants of echo.
-
-Usage:
- toplevelprog echoprog [flags] <command>
-
-The toplevelprog echoprog commands are:
- echo Print strings on stdout
- echoopt Print strings on stdout, with opts
-
-The toplevelprog echoprog additional help topics are:
- topic3 Help topic 3 short
-
-The toplevelprog echoprog flags are:
- -extra=false
- Print an extra arg
-================================================================================
-Toplevelprog Echoprog Echo
-
-Echo prints any strings passed in to stdout.
-
-Usage:
- toplevelprog echoprog echo [strings]
-
-[strings] are arbitrary strings that will be echoed.
-================================================================================
-Toplevelprog Echoprog Echoopt
-
-Echoopt prints any args passed in to stdout.
-
-Usage:
- toplevelprog echoprog echoopt [flags] [args]
-
-[args] are arbitrary strings that will be echoed.
-
-The toplevelprog echoprog echoopt flags are:
- -n=false
- Do not output trailing newline
-================================================================================
-Toplevelprog Echoprog Topic3 - help topic
-
-Help topic 3 long.
-================================================================================
-Toplevelprog Hello
-
-Hello prints any strings passed in to stdout preceded by "Hello".
-
-Usage:
- toplevelprog hello [strings]
-
-[strings] are arbitrary strings that will be printed.
-================================================================================
-Toplevelprog Help
-
-Help with no args displays the usage of the parent command.
-
-Help with args displays the usage of the specified sub-command or help topic.
-
-"help ..." recursively displays help for all commands and topics.
-
-The output is formatted to a target width in runes. The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars. By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
-
-Usage:
- toplevelprog help [flags] [command/topic ...]
-
-[command/topic ...] optionally identifies a specific sub-command or help topic.
-
-The toplevelprog help flags are:
- -style=text
- The formatting style for help output, either "text" or "godoc".
-================================================================================
-Toplevelprog Topic1 - help topic
-
-Help topic 1 long.
-================================================================================
-Toplevelprog Topic2 - help topic
-
-Help topic 2 long.
-`,
- },
- {
- Args: []string{"help", "echoprog"},
- Stdout: `Echoprog has two variants of echo.
-
-Usage:
- toplevelprog echoprog [flags] <command>
-
-The toplevelprog echoprog commands are:
- echo Print strings on stdout
- echoopt Print strings on stdout, with opts
- help Display help for commands or topics
-Run "toplevelprog echoprog help [command]" for command usage.
-
-The toplevelprog echoprog additional help topics are:
- topic3 Help topic 3 short
-Run "toplevelprog echoprog help [topic]" for topic details.
-
-The toplevelprog echoprog flags are:
- -extra=false
- Print an extra arg
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"help", "topic1"},
- Stdout: `Help topic 1 long.
-`,
- },
- {
- Args: []string{"help", "topic2"},
- Stdout: `Help topic 2 long.
-`,
- },
- {
- Args: []string{"echoprog", "help", "..."},
- Stdout: `Echoprog has two variants of echo.
-
-Usage:
- toplevelprog echoprog [flags] <command>
-
-The toplevelprog echoprog commands are:
- echo Print strings on stdout
- echoopt Print strings on stdout, with opts
- help Display help for commands or topics
-Run "toplevelprog echoprog help [command]" for command usage.
-
-The toplevelprog echoprog additional help topics are:
- topic3 Help topic 3 short
-Run "toplevelprog echoprog help [topic]" for topic details.
-
-The toplevelprog echoprog flags are:
- -extra=false
- Print an extra arg
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-================================================================================
-Toplevelprog Echoprog Echo
-
-Echo prints any strings passed in to stdout.
-
-Usage:
- toplevelprog echoprog echo [strings]
-
-[strings] are arbitrary strings that will be echoed.
-================================================================================
-Toplevelprog Echoprog Echoopt
-
-Echoopt prints any args passed in to stdout.
-
-Usage:
- toplevelprog echoprog echoopt [flags] [args]
-
-[args] are arbitrary strings that will be echoed.
-
-The toplevelprog echoprog echoopt flags are:
- -n=false
- Do not output trailing newline
-================================================================================
-Toplevelprog Echoprog Help
-
-Help with no args displays the usage of the parent command.
-
-Help with args displays the usage of the specified sub-command or help topic.
-
-"help ..." recursively displays help for all commands and topics.
-
-The output is formatted to a target width in runes. The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars. By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
-
-Usage:
- toplevelprog echoprog help [flags] [command/topic ...]
-
-[command/topic ...] optionally identifies a specific sub-command or help topic.
-
-The toplevelprog echoprog help flags are:
- -style=text
- The formatting style for help output, either "text" or "godoc".
-================================================================================
-Toplevelprog Echoprog Topic3 - help topic
-
-Help topic 3 long.
-`,
- },
- {
- Args: []string{"echoprog", "help", "echoopt"},
- Stdout: `Echoopt prints any args passed in to stdout.
-
-Usage:
- toplevelprog echoprog echoopt [flags] [args]
-
-[args] are arbitrary strings that will be echoed.
-
-The toplevelprog echoprog echoopt flags are:
- -n=false
- Do not output trailing newline
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"help", "echoprog", "topic3"},
- Stdout: `Help topic 3 long.
-`,
- },
- {
- Args: []string{"echoprog", "help", "topic3"},
- Stdout: `Help topic 3 long.
-`,
- },
- {
- Args: []string{"help", "hello"},
- Stdout: `Hello prints any strings passed in to stdout preceded by "Hello".
-
-Usage:
- toplevelprog hello [strings]
-
-[strings] are arbitrary strings that will be printed.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"help", "foo"},
- Err: ErrUsage,
- Stderr: `ERROR: toplevelprog: unknown command or topic "foo"
-
-Toplevelprog has the echo subprogram and the hello command.
-
-Usage:
- toplevelprog [flags] <command>
-
-The toplevelprog commands are:
- echoprog Set of echo commands
- hello Print strings on stdout preceded by "Hello"
- help Display help for commands or topics
-Run "toplevelprog help [command]" for command usage.
-
-The toplevelprog additional help topics are:
- topic1 Help topic 1 short
- topic2 Help topic 2 short
-Run "toplevelprog help [topic]" for topic details.
-
-The toplevelprog flags are:
- -tlextra=false
- Print an extra arg for all commands
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"echoprog", "echo", "foo", "bar"},
- Stdout: "[foo bar]\n",
- },
- {
- Args: []string{"echoprog", "-extra", "echo", "foo", "bar"},
- Stdout: "[foo bar extra]\n",
- },
- {
- Args: []string{"echoprog", "echo", "error"},
- Err: errEcho,
- },
- {
- Args: []string{"echoprog", "echoopt", "foo", "bar"},
- Stdout: "[foo bar]\n",
- },
- {
- Args: []string{"echoprog", "-extra", "echoopt", "foo", "bar"},
- Stdout: "[foo bar extra]\n",
- },
- {
- Args: []string{"echoprog", "echoopt", "-n", "foo", "bar"},
- Stdout: "[foo bar]",
- },
- {
- Args: []string{"echoprog", "-extra", "echoopt", "-n", "foo", "bar"},
- Stdout: "[foo bar extra]",
- },
- {
- Args: []string{"echoprog", "echoopt", "error"},
- Err: errEcho,
- },
- {
- Args: []string{"--tlextra", "echoprog", "-extra", "echoopt", "foo", "bar"},
- Stdout: "[foo bar extra tlextra]\n",
- },
- {
- Args: []string{"hello", "foo", "bar"},
- Stdout: "Hello foo bar\n",
- },
- {
- Args: []string{"--tlextra", "hello", "foo", "bar"},
- Stdout: "Hello foo bar tlextra\n",
- },
- {
- Args: []string{"hello", "--extra", "foo", "bar"},
- Err: ErrUsage,
- Stderr: `ERROR: toplevelprog hello: flag provided but not defined: -extra
-
-Hello prints any strings passed in to stdout preceded by "Hello".
-
-Usage:
- toplevelprog hello [strings]
-
-[strings] are arbitrary strings that will be printed.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"-extra", "echoprog", "echoopt", "foo", "bar"},
- Err: ErrUsage,
- Stderr: `ERROR: toplevelprog: flag provided but not defined: -extra
-
-Toplevelprog has the echo subprogram and the hello command.
-
-Usage:
- toplevelprog [flags] <command>
-
-The toplevelprog commands are:
- echoprog Set of echo commands
- hello Print strings on stdout preceded by "Hello"
- help Display help for commands or topics
-Run "toplevelprog help [command]" for command usage.
-
-The toplevelprog additional help topics are:
- topic1 Help topic 1 short
- topic2 Help topic 2 short
-Run "toplevelprog help [topic]" for topic details.
-
-The toplevelprog flags are:
- -tlextra=false
- Print an extra arg for all commands
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- }
- runTestCases(t, prog, tests)
-}
-
-func TestMultiLevelCommandsOrdering(t *testing.T) {
- cmdHello11 := &Command{
- Name: "hello11",
- Short: "Print strings on stdout preceded by \"Hello\"",
- Long: `
-Hello prints any strings passed in to stdout preceded by "Hello".
-`,
- ArgsName: "[strings]",
- ArgsLong: "[strings] are arbitrary strings that will be printed.",
- Run: runHello,
- }
- cmdHello12 := &Command{
- Name: "hello12",
- Short: "Print strings on stdout preceded by \"Hello\"",
- Long: `
-Hello prints any strings passed in to stdout preceded by "Hello".
-`,
- ArgsName: "[strings]",
- ArgsLong: "[strings] are arbitrary strings that will be printed.",
- Run: runHello,
- }
- cmdHello21 := &Command{
- Name: "hello21",
- Short: "Print strings on stdout preceded by \"Hello\"",
- Long: `
-Hello prints any strings passed in to stdout preceded by "Hello".
-`,
- ArgsName: "[strings]",
- ArgsLong: "[strings] are arbitrary strings that will be printed.",
- Run: runHello,
- }
- cmdHello22 := &Command{
- Name: "hello22",
- Short: "Print strings on stdout preceded by \"Hello\"",
- Long: `
-Hello prints any strings passed in to stdout preceded by "Hello".
-`,
- ArgsName: "[strings]",
- ArgsLong: "[strings] are arbitrary strings that will be printed.",
- Run: runHello,
- }
- cmdHello31 := &Command{
- Name: "hello31",
- Short: "Print strings on stdout preceded by \"Hello\"",
- Long: `
-Hello prints any strings passed in to stdout preceded by "Hello".
-`,
- ArgsName: "[strings]",
- ArgsLong: "[strings] are arbitrary strings that will be printed.",
- Run: runHello,
- }
- cmdHello32 := &Command{
- Name: "hello32",
- Short: "Print strings on stdout preceded by \"Hello\"",
- Long: `
-Hello prints any strings passed in to stdout preceded by "Hello".
-`,
- ArgsName: "[strings]",
- ArgsLong: "[strings] are arbitrary strings that will be printed.",
- Run: runHello,
- }
- progHello3 := &Command{
- Name: "prog3",
- Short: "Set of hello commands",
- Long: "Prog3 has two variants of hello.",
- Children: []*Command{cmdHello31, cmdHello32},
- }
- progHello2 := &Command{
- Name: "prog2",
- Short: "Set of hello commands",
- Long: "Prog2 has two variants of hello and a subprogram prog3.",
- Children: []*Command{cmdHello21, progHello3, cmdHello22},
- }
- progHello1 := &Command{
- Name: "prog1",
- Short: "Set of hello commands",
- Long: "Prog1 has two variants of hello and a subprogram prog2.",
- Children: []*Command{cmdHello11, cmdHello12, progHello2},
- }
-
- var tests = []testCase{
- {
- Args: []string{},
- Err: ErrUsage,
- Stderr: `ERROR: prog1: no command specified
-
-Prog1 has two variants of hello and a subprogram prog2.
-
-Usage:
- prog1 <command>
-
-The prog1 commands are:
- hello11 Print strings on stdout preceded by "Hello"
- hello12 Print strings on stdout preceded by "Hello"
- prog2 Set of hello commands
- help Display help for commands or topics
-Run "prog1 help [command]" for command usage.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"help"},
- Stdout: `Prog1 has two variants of hello and a subprogram prog2.
-
-Usage:
- prog1 <command>
-
-The prog1 commands are:
- hello11 Print strings on stdout preceded by "Hello"
- hello12 Print strings on stdout preceded by "Hello"
- prog2 Set of hello commands
- help Display help for commands or topics
-Run "prog1 help [command]" for command usage.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"help", "..."},
- Stdout: `Prog1 has two variants of hello and a subprogram prog2.
-
-Usage:
- prog1 <command>
-
-The prog1 commands are:
- hello11 Print strings on stdout preceded by "Hello"
- hello12 Print strings on stdout preceded by "Hello"
- prog2 Set of hello commands
- help Display help for commands or topics
-Run "prog1 help [command]" for command usage.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-================================================================================
-Prog1 Hello11
-
-Hello prints any strings passed in to stdout preceded by "Hello".
-
-Usage:
- prog1 hello11 [strings]
-
-[strings] are arbitrary strings that will be printed.
-================================================================================
-Prog1 Hello12
-
-Hello prints any strings passed in to stdout preceded by "Hello".
-
-Usage:
- prog1 hello12 [strings]
-
-[strings] are arbitrary strings that will be printed.
-================================================================================
-Prog1 Prog2
-
-Prog2 has two variants of hello and a subprogram prog3.
-
-Usage:
- prog1 prog2 <command>
-
-The prog1 prog2 commands are:
- hello21 Print strings on stdout preceded by "Hello"
- prog3 Set of hello commands
- hello22 Print strings on stdout preceded by "Hello"
-================================================================================
-Prog1 Prog2 Hello21
-
-Hello prints any strings passed in to stdout preceded by "Hello".
-
-Usage:
- prog1 prog2 hello21 [strings]
-
-[strings] are arbitrary strings that will be printed.
-================================================================================
-Prog1 Prog2 Prog3
-
-Prog3 has two variants of hello.
-
-Usage:
- prog1 prog2 prog3 <command>
-
-The prog1 prog2 prog3 commands are:
- hello31 Print strings on stdout preceded by "Hello"
- hello32 Print strings on stdout preceded by "Hello"
-================================================================================
-Prog1 Prog2 Prog3 Hello31
-
-Hello prints any strings passed in to stdout preceded by "Hello".
-
-Usage:
- prog1 prog2 prog3 hello31 [strings]
-
-[strings] are arbitrary strings that will be printed.
-================================================================================
-Prog1 Prog2 Prog3 Hello32
-
-Hello prints any strings passed in to stdout preceded by "Hello".
-
-Usage:
- prog1 prog2 prog3 hello32 [strings]
-
-[strings] are arbitrary strings that will be printed.
-================================================================================
-Prog1 Prog2 Hello22
-
-Hello prints any strings passed in to stdout preceded by "Hello".
-
-Usage:
- prog1 prog2 hello22 [strings]
-
-[strings] are arbitrary strings that will be printed.
-================================================================================
-Prog1 Help
-
-Help with no args displays the usage of the parent command.
-
-Help with args displays the usage of the specified sub-command or help topic.
-
-"help ..." recursively displays help for all commands and topics.
-
-The output is formatted to a target width in runes. The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars. By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
-
-Usage:
- prog1 help [flags] [command/topic ...]
-
-[command/topic ...] optionally identifies a specific sub-command or help topic.
-
-The prog1 help flags are:
- -style=text
- The formatting style for help output, either "text" or "godoc".
-`,
- },
- {
- Args: []string{"prog2", "help", "..."},
- Stdout: `Prog2 has two variants of hello and a subprogram prog3.
-
-Usage:
- prog1 prog2 <command>
-
-The prog1 prog2 commands are:
- hello21 Print strings on stdout preceded by "Hello"
- prog3 Set of hello commands
- hello22 Print strings on stdout preceded by "Hello"
- help Display help for commands or topics
-Run "prog1 prog2 help [command]" for command usage.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-================================================================================
-Prog1 Prog2 Hello21
-
-Hello prints any strings passed in to stdout preceded by "Hello".
-
-Usage:
- prog1 prog2 hello21 [strings]
-
-[strings] are arbitrary strings that will be printed.
-================================================================================
-Prog1 Prog2 Prog3
-
-Prog3 has two variants of hello.
-
-Usage:
- prog1 prog2 prog3 <command>
-
-The prog1 prog2 prog3 commands are:
- hello31 Print strings on stdout preceded by "Hello"
- hello32 Print strings on stdout preceded by "Hello"
-================================================================================
-Prog1 Prog2 Prog3 Hello31
-
-Hello prints any strings passed in to stdout preceded by "Hello".
-
-Usage:
- prog1 prog2 prog3 hello31 [strings]
-
-[strings] are arbitrary strings that will be printed.
-================================================================================
-Prog1 Prog2 Prog3 Hello32
-
-Hello prints any strings passed in to stdout preceded by "Hello".
-
-Usage:
- prog1 prog2 prog3 hello32 [strings]
-
-[strings] are arbitrary strings that will be printed.
-================================================================================
-Prog1 Prog2 Hello22
-
-Hello prints any strings passed in to stdout preceded by "Hello".
-
-Usage:
- prog1 prog2 hello22 [strings]
-
-[strings] are arbitrary strings that will be printed.
-================================================================================
-Prog1 Prog2 Help
-
-Help with no args displays the usage of the parent command.
-
-Help with args displays the usage of the specified sub-command or help topic.
-
-"help ..." recursively displays help for all commands and topics.
-
-The output is formatted to a target width in runes. The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars. By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
-
-Usage:
- prog1 prog2 help [flags] [command/topic ...]
-
-[command/topic ...] optionally identifies a specific sub-command or help topic.
-
-The prog1 prog2 help flags are:
- -style=text
- The formatting style for help output, either "text" or "godoc".
-`,
- },
- {
- Args: []string{"prog2", "prog3", "help", "..."},
- Stdout: `Prog3 has two variants of hello.
-
-Usage:
- prog1 prog2 prog3 <command>
-
-The prog1 prog2 prog3 commands are:
- hello31 Print strings on stdout preceded by "Hello"
- hello32 Print strings on stdout preceded by "Hello"
- help Display help for commands or topics
-Run "prog1 prog2 prog3 help [command]" for command usage.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-================================================================================
-Prog1 Prog2 Prog3 Hello31
-
-Hello prints any strings passed in to stdout preceded by "Hello".
-
-Usage:
- prog1 prog2 prog3 hello31 [strings]
-
-[strings] are arbitrary strings that will be printed.
-================================================================================
-Prog1 Prog2 Prog3 Hello32
-
-Hello prints any strings passed in to stdout preceded by "Hello".
-
-Usage:
- prog1 prog2 prog3 hello32 [strings]
-
-[strings] are arbitrary strings that will be printed.
-================================================================================
-Prog1 Prog2 Prog3 Help
-
-Help with no args displays the usage of the parent command.
-
-Help with args displays the usage of the specified sub-command or help topic.
-
-"help ..." recursively displays help for all commands and topics.
-
-The output is formatted to a target width in runes. The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars. By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
-
-Usage:
- prog1 prog2 prog3 help [flags] [command/topic ...]
-
-[command/topic ...] optionally identifies a specific sub-command or help topic.
-
-The prog1 prog2 prog3 help flags are:
- -style=text
- The formatting style for help output, either "text" or "godoc".
-`,
- },
- {
- Args: []string{"help", "prog2", "prog3", "..."},
- Stdout: `Prog3 has two variants of hello.
-
-Usage:
- prog1 prog2 prog3 <command>
-
-The prog1 prog2 prog3 commands are:
- hello31 Print strings on stdout preceded by "Hello"
- hello32 Print strings on stdout preceded by "Hello"
- help Display help for commands or topics
-Run "prog1 prog2 prog3 help [command]" for command usage.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-================================================================================
-Prog1 Prog2 Prog3 Hello31
-
-Hello prints any strings passed in to stdout preceded by "Hello".
-
-Usage:
- prog1 prog2 prog3 hello31 [strings]
-
-[strings] are arbitrary strings that will be printed.
-================================================================================
-Prog1 Prog2 Prog3 Hello32
-
-Hello prints any strings passed in to stdout preceded by "Hello".
-
-Usage:
- prog1 prog2 prog3 hello32 [strings]
-
-[strings] are arbitrary strings that will be printed.
-================================================================================
-Prog1 Prog2 Prog3 Help
-
-Help with no args displays the usage of the parent command.
-
-Help with args displays the usage of the specified sub-command or help topic.
-
-"help ..." recursively displays help for all commands and topics.
-
-The output is formatted to a target width in runes. The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars. By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
-
-Usage:
- prog1 prog2 prog3 help [flags] [command/topic ...]
-
-[command/topic ...] optionally identifies a specific sub-command or help topic.
-
-The prog1 prog2 prog3 help flags are:
- -style=text
- The formatting style for help output, either "text" or "godoc".
-`,
- },
- {
- Args: []string{"help", "-style=godoc", "..."},
- Stdout: `Prog1 has two variants of hello and a subprogram prog2.
-
-Usage:
- prog1 <command>
-
-The prog1 commands are:
- hello11 Print strings on stdout preceded by "Hello"
- hello12 Print strings on stdout preceded by "Hello"
- prog2 Set of hello commands
- help Display help for commands or topics
-Run "prog1 help [command]" for command usage.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-
-Prog1 Hello11
-
-Hello prints any strings passed in to stdout preceded by "Hello".
-
-Usage:
- prog1 hello11 [strings]
-
-[strings] are arbitrary strings that will be printed.
-
-Prog1 Hello12
-
-Hello prints any strings passed in to stdout preceded by "Hello".
-
-Usage:
- prog1 hello12 [strings]
-
-[strings] are arbitrary strings that will be printed.
-
-Prog1 Prog2
-
-Prog2 has two variants of hello and a subprogram prog3.
-
-Usage:
- prog1 prog2 <command>
-
-The prog1 prog2 commands are:
- hello21 Print strings on stdout preceded by "Hello"
- prog3 Set of hello commands
- hello22 Print strings on stdout preceded by "Hello"
-
-Prog1 Prog2 Hello21
-
-Hello prints any strings passed in to stdout preceded by "Hello".
-
-Usage:
- prog1 prog2 hello21 [strings]
-
-[strings] are arbitrary strings that will be printed.
-
-Prog1 Prog2 Prog3
-
-Prog3 has two variants of hello.
-
-Usage:
- prog1 prog2 prog3 <command>
-
-The prog1 prog2 prog3 commands are:
- hello31 Print strings on stdout preceded by "Hello"
- hello32 Print strings on stdout preceded by "Hello"
-
-Prog1 Prog2 Prog3 Hello31
-
-Hello prints any strings passed in to stdout preceded by "Hello".
-
-Usage:
- prog1 prog2 prog3 hello31 [strings]
-
-[strings] are arbitrary strings that will be printed.
-
-Prog1 Prog2 Prog3 Hello32
-
-Hello prints any strings passed in to stdout preceded by "Hello".
-
-Usage:
- prog1 prog2 prog3 hello32 [strings]
-
-[strings] are arbitrary strings that will be printed.
-
-Prog1 Prog2 Hello22
-
-Hello prints any strings passed in to stdout preceded by "Hello".
-
-Usage:
- prog1 prog2 hello22 [strings]
-
-[strings] are arbitrary strings that will be printed.
-
-Prog1 Help
-
-Help with no args displays the usage of the parent command.
-
-Help with args displays the usage of the specified sub-command or help topic.
-
-"help ..." recursively displays help for all commands and topics.
-
-The output is formatted to a target width in runes. The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars. By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
-
-Usage:
- prog1 help [flags] [command/topic ...]
-
-[command/topic ...] optionally identifies a specific sub-command or help topic.
-
-The prog1 help flags are:
- -style=text
- The formatting style for help output, either "text" or "godoc".
-`,
- },
- }
-
- runTestCases(t, progHello1, tests)
-}
-
-func TestCommandAndArgs(t *testing.T) {
- cmdEcho := &Command{
- Name: "echo",
- Short: "Print strings on stdout",
- Long: `
-Echo prints any strings passed in to stdout.
-`,
- Run: runEcho,
- ArgsName: "[strings]",
- ArgsLong: "[strings] are arbitrary strings that will be echoed.",
- }
-
- prog := &Command{
- Name: "cmdargs",
- Short: "Cmdargs program.",
- Long: "Cmdargs has the echo command and a Run function with args.",
- Children: []*Command{cmdEcho},
- Run: runHello,
- ArgsName: "[strings]",
- ArgsLong: "[strings] are arbitrary strings that will be printed.",
- }
-
- var tests = []testCase{
- {
- Args: []string{},
- Stdout: "Hello\n",
- },
- {
- Args: []string{"foo"},
- Stdout: "Hello foo\n",
- },
- {
- Args: []string{"help"},
- Stdout: `Cmdargs has the echo command and a Run function with args.
-
-Usage:
- cmdargs <command>
- cmdargs [strings]
-
-The cmdargs commands are:
- echo Print strings on stdout
- help Display help for commands or topics
-Run "cmdargs help [command]" for command usage.
-
-[strings] are arbitrary strings that will be printed.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"help", "echo"},
- Stdout: `Echo prints any strings passed in to stdout.
-
-Usage:
- cmdargs echo [strings]
-
-[strings] are arbitrary strings that will be echoed.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"help", "..."},
- Stdout: `Cmdargs has the echo command and a Run function with args.
-
-Usage:
- cmdargs <command>
- cmdargs [strings]
-
-The cmdargs commands are:
- echo Print strings on stdout
- help Display help for commands or topics
-Run "cmdargs help [command]" for command usage.
-
-[strings] are arbitrary strings that will be printed.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-================================================================================
-Cmdargs Echo
-
-Echo prints any strings passed in to stdout.
-
-Usage:
- cmdargs echo [strings]
-
-[strings] are arbitrary strings that will be echoed.
-================================================================================
-Cmdargs Help
-
-Help with no args displays the usage of the parent command.
-
-Help with args displays the usage of the specified sub-command or help topic.
-
-"help ..." recursively displays help for all commands and topics.
-
-The output is formatted to a target width in runes. The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars. By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
-
-Usage:
- cmdargs help [flags] [command/topic ...]
-
-[command/topic ...] optionally identifies a specific sub-command or help topic.
-
-The cmdargs help flags are:
- -style=text
- The formatting style for help output, either "text" or "godoc".
-`,
- },
- {
- Args: []string{"help", "foo"},
- Err: ErrUsage,
- Stderr: `ERROR: cmdargs: unknown command or topic "foo"
-
-Cmdargs has the echo command and a Run function with args.
-
-Usage:
- cmdargs <command>
- cmdargs [strings]
-
-The cmdargs commands are:
- echo Print strings on stdout
- help Display help for commands or topics
-Run "cmdargs help [command]" for command usage.
-
-[strings] are arbitrary strings that will be printed.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"echo", "foo", "bar"},
- Stdout: "[foo bar]\n",
- },
- {
- Args: []string{"echo", "error"},
- Err: errEcho,
- },
- {
- Args: []string{"echo", "bad_arg"},
- Err: ErrUsage,
- Stderr: `ERROR: Invalid argument bad_arg
-
-Echo prints any strings passed in to stdout.
-
-Usage:
- cmdargs echo [strings]
-
-[strings] are arbitrary strings that will be echoed.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- }
- runTestCases(t, prog, tests)
-}
-
-func TestCommandAndRunNoArgs(t *testing.T) {
- cmdEcho := &Command{
- Name: "echo",
- Short: "Print strings on stdout",
- Long: `
-Echo prints any strings passed in to stdout.
-`,
- Run: runEcho,
- ArgsName: "[strings]",
- ArgsLong: "[strings] are arbitrary strings that will be echoed.",
- }
-
- prog := &Command{
- Name: "cmdrun",
- Short: "Cmdrun program.",
- Long: "Cmdrun has the echo command and a Run function with no args.",
- Children: []*Command{cmdEcho},
- Run: runHello,
- }
-
- var tests = []testCase{
- {
- Args: []string{},
- Stdout: "Hello\n",
- },
- {
- Args: []string{"foo"},
- Err: ErrUsage,
- Stderr: `ERROR: cmdrun: unknown command "foo"
-
-Cmdrun has the echo command and a Run function with no args.
-
-Usage:
- cmdrun <command>
- cmdrun
-
-The cmdrun commands are:
- echo Print strings on stdout
- help Display help for commands or topics
-Run "cmdrun help [command]" for command usage.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"help"},
- Stdout: `Cmdrun has the echo command and a Run function with no args.
-
-Usage:
- cmdrun <command>
- cmdrun
-
-The cmdrun commands are:
- echo Print strings on stdout
- help Display help for commands or topics
-Run "cmdrun help [command]" for command usage.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"help", "echo"},
- Stdout: `Echo prints any strings passed in to stdout.
-
-Usage:
- cmdrun echo [strings]
-
-[strings] are arbitrary strings that will be echoed.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"help", "..."},
- Stdout: `Cmdrun has the echo command and a Run function with no args.
-
-Usage:
- cmdrun <command>
- cmdrun
-
-The cmdrun commands are:
- echo Print strings on stdout
- help Display help for commands or topics
-Run "cmdrun help [command]" for command usage.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-================================================================================
-Cmdrun Echo
-
-Echo prints any strings passed in to stdout.
-
-Usage:
- cmdrun echo [strings]
-
-[strings] are arbitrary strings that will be echoed.
-================================================================================
-Cmdrun Help
-
-Help with no args displays the usage of the parent command.
-
-Help with args displays the usage of the specified sub-command or help topic.
-
-"help ..." recursively displays help for all commands and topics.
-
-The output is formatted to a target width in runes. The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars. By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
-
-Usage:
- cmdrun help [flags] [command/topic ...]
-
-[command/topic ...] optionally identifies a specific sub-command or help topic.
-
-The cmdrun help flags are:
- -style=text
- The formatting style for help output, either "text" or "godoc".
-`,
- },
- {
- Args: []string{"help", "foo"},
- Err: ErrUsage,
- Stderr: `ERROR: cmdrun: unknown command or topic "foo"
-
-Cmdrun has the echo command and a Run function with no args.
-
-Usage:
- cmdrun <command>
- cmdrun
-
-The cmdrun commands are:
- echo Print strings on stdout
- help Display help for commands or topics
-Run "cmdrun help [command]" for command usage.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"echo", "foo", "bar"},
- Stdout: "[foo bar]\n",
- },
- {
- Args: []string{"echo", "error"},
- Err: errEcho,
- },
- {
- Args: []string{"echo", "bad_arg"},
- Err: ErrUsage,
- Stderr: `ERROR: Invalid argument bad_arg
-
-Echo prints any strings passed in to stdout.
-
-Usage:
- cmdrun echo [strings]
-
-[strings] are arbitrary strings that will be echoed.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- }
- runTestCases(t, prog, tests)
-}
-
-func TestLongCommandsHelp(t *testing.T) {
- cmdLong := &Command{
- Name: "thisisaverylongcommand",
- Short: "the short description of the very long command is very long, and will have to be wrapped",
- Long: "The long description of the very long command is also very long, and will similarly have to be wrapped",
- Run: runEcho,
- }
- cmdShort := &Command{
- Name: "x",
- Short: "description of short command.",
- Long: "blah blah blah",
- Run: runEcho,
- }
- prog := &Command{
- Name: "program",
- Short: "Test help strings when there are long commands.",
- Long: "Test help strings when there are long commands.",
- Children: []*Command{cmdShort, cmdLong},
- }
- var tests = []testCase{
- {
- Args: []string{"help"},
- Stdout: `Test help strings when there are long commands.
-
-Usage:
- program <command>
-
-The program commands are:
- x description of short command.
- thisisaverylongcommand the short description of the very long command is very
- long, and will have to be wrapped
- help Display help for commands or topics
-Run "program help [command]" for command usage.
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- {
- Args: []string{"help", "thisisaverylongcommand"},
- Stdout: `The long description of the very long command is also very long, and will
-similarly have to be wrapped
-
-Usage:
- program thisisaverylongcommand
-
-The global flags are:
- -global1=
- global test flag 1
- -global2=0
- global test flag 2
-`,
- },
- }
- runTestCases(t, prog, tests)
-}
diff --git a/lib/filelocker/locker.go b/lib/filelocker/locker.go
index 5e6674f..43dfd5f 100644
--- a/lib/filelocker/locker.go
+++ b/lib/filelocker/locker.go
@@ -18,7 +18,7 @@
// Lock locks the provided file.
//
// If the file is already locked then the calling goroutine
-// blocks until the lock can be acquired.
+// blocks until the lock can be grabbed.
//
// The file must exist otherwise an error is returned.
func Lock(filepath string) (Unlocker, error) {
@@ -32,6 +32,21 @@
return &unlocker{file}, nil
}
+// TryLock tries to grab a lock on the provided file and
+// returns an error if it fails. This function is non-blocking.
+//
+// The file must exist otherwise an error is returned.
+func TryLock(filepath string) (Unlocker, error) {
+ file, err := os.Open(filepath)
+ if err != nil {
+ return nil, err
+ }
+ if err = syscall.Flock(int(file.Fd()), syscall.LOCK_EX|syscall.LOCK_NB); err != nil {
+ return nil, err
+ }
+ return &unlocker{file}, nil
+}
+
// unlocker implements Unlocker.
type unlocker struct {
file *os.File
diff --git a/lib/filelocker/locker_test.go b/lib/filelocker/locker_test.go
index 0060210..f3ce658 100644
--- a/lib/filelocker/locker_test.go
+++ b/lib/filelocker/locker_test.go
@@ -6,6 +6,7 @@
"io"
"io/ioutil"
"os"
+ "syscall"
"testing"
"time"
@@ -14,7 +15,7 @@
)
func init() {
- modules.RegisterChild("testLockUnlockChild", "", testLockUnlockChild)
+ modules.RegisterChild("testLockChild", "", testLockChild)
}
func TestHelperProcess(t *testing.T) {
@@ -39,7 +40,7 @@
}
}
-func testLockUnlockChild(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+func testLockChild(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
// Lock the file
unlocker, err := Lock(args[1])
if err != nil {
@@ -58,13 +59,13 @@
return nil
}
-func TestLockUnlockInterProcess(t *testing.T) {
+func TestLockInterProcess(t *testing.T) {
filepath := newFile()
defer os.Remove(filepath)
sh := modules.NewShell()
defer sh.Cleanup(os.Stderr, os.Stderr)
- h, err := sh.Start("testLockUnlockChild", nil, filepath)
+ h, err := sh.Start("testLockChild", nil, filepath)
if err != nil {
t.Fatalf("sh.Start failed: %v", err)
}
@@ -97,7 +98,7 @@
s.ExpectEOF()
}
-func TestLockUnlockIntraProcess(t *testing.T) {
+func TestLockIntraProcess(t *testing.T) {
filepath := newFile()
defer os.Remove(filepath)
@@ -127,3 +128,33 @@
t.Fatal("Another goroutine failed to grab the lock after this goroutine released it")
}
}
+
+func TestTryLock(t *testing.T) {
+ filepath := newFile()
+ defer os.Remove(filepath)
+
+ sh := modules.NewShell()
+ defer sh.Cleanup(os.Stderr, os.Stderr)
+ h, err := sh.Start("testLockChild", nil, filepath)
+ if err != nil {
+ t.Fatalf("sh.Start failed: %v", err)
+ }
+ s := expect.NewSession(t, h.Stdout(), time.Minute)
+
+ // Test that child grabbed the lock.
+ s.Expect("locked")
+
+ // Test that parent cannot grab the lock, and then send a message
+ // to the child to release the lock.
+ if _, err := TryLock(filepath); err != syscall.EWOULDBLOCK {
+ t.Fatal("TryLock returned error: %v, want: %v", err, syscall.EWOULDBLOCK)
+ }
+
+ // Test that the parent can grab the lock after the child has released it.
+ h.Stdin().Write([]byte("unlock\n"))
+ s.Expect("unlocked")
+ if _, err = TryLock(filepath); err != nil {
+ t.Fatalf("TryLock failed: %v", err)
+ }
+ s.ExpectEOF()
+}
diff --git a/lib/textutil/doc.go b/lib/textutil/doc.go
deleted file mode 100644
index cd28c8c..0000000
--- a/lib/textutil/doc.go
+++ /dev/null
@@ -1,5 +0,0 @@
-// Package textutil implements utilities for handling human-readable text.
-//
-// This package includes a combination of low-level and high-level utilities.
-// The main high-level utility is available as NewUTF8LineWriter.
-package textutil
diff --git a/lib/textutil/line_writer.go b/lib/textutil/line_writer.go
deleted file mode 100644
index c7df3a5..0000000
--- a/lib/textutil/line_writer.go
+++ /dev/null
@@ -1,445 +0,0 @@
-package textutil
-
-import (
- "fmt"
- "io"
- "unicode"
-)
-
-// LineWriter implements an io.Writer filter that formats input text into output
-// lines with a given target width in runes.
-//
-// Each input rune is classified into one of three kinds:
-// EOL: end-of-line, consisting of \f, \n, \r, \v, U+2028 or U+2029
-// Space: defined by unicode.IsSpace
-// Letter: everything else
-//
-// The input text is expected to consist of words, defined as sequences of
-// letters. Sequences of words form paragraphs, where paragraphs are separated
-// by either blank lines (that contain no letters), or an explicit U+2029
-// ParagraphSeparator. Input lines with leading spaces are treated verbatim.
-//
-// Paragraphs are output as word-wrapped lines; line breaks only occur at word
-// boundaries. Output lines are usually no longer than the target width. The
-// exceptions are single words longer than the target width, which are output on
-// their own line, and verbatim lines, which may be arbitrarily longer or
-// shorter than the width.
-//
-// Output lines never contain trailing spaces. Only verbatim output lines may
-// contain leading spaces. Spaces separating input words are output verbatim,
-// unless it would result in a line with leading or trailing spaces.
-//
-// EOL runes within the input text are never written to the output; the output
-// line terminator and paragraph separator may be configured, and some EOL may
-// be output as a single space ' ' to maintain word separation.
-//
-// The algorithm greedily fills each output line with as many words as it can,
-// assuming that all Unicode code points have the same width. Invalid UTF-8 is
-// silently transformed to the replacement character U+FFFD and treated as a
-// single rune.
-//
-// Flush must be called after the last call to Write; the input is buffered.
-//
-// Implementation note: line breaking is a complicated topic. This approach
-// attempts to be simple and useful; a full implementation conforming to
-// Unicode Standard Annex #14 would be complicated, and is not implemented.
-// Languages that don't use spaces to separate words (e.g. CJK) won't work
-// well under the current approach.
-//
-// http://www.unicode.org/reports/tr14 [Unicode Line Breaking Algorithm]
-// http://www.unicode.org/versions/Unicode4.0.0/ch05.pdf [5.8 Newline Guidelines]
-type LineWriter struct {
- // State configured by the user.
- w io.Writer
- runeDecoder RuneChunkDecoder
- width runePos
- lineTerm []byte
- paragraphSep string
- indents []string
-
- // The buffer contains a single output line.
- lineBuf byteRuneBuffer
-
- // Keep track of the previous state and rune.
- prevState state
- prevRune rune
-
- // Keep track of blank input lines.
- inputLineHasLetter bool
-
- // lineBuf positions where the line starts (after separators and indents), a
- // new word has started and the last word has ended.
- lineStart bytePos
- newWordStart bytePos
- lastWordEnd bytePos
-
- // Keep track of paragraph terminations and line indices, so we can output the
- // paragraph separator and indents correctly.
- terminateParagraph bool
- paragraphLineIndex int
- wroteFirstLine bool
-}
-
-type state int
-
-const (
- stateWordWrap state = iota // Perform word-wrapping [start state]
- stateVerbatim // Verbatim output-line, no word-wrapping
- stateSkipSpace // Skip spaces in input line.
-)
-
-// NewLineWriter returns a new LineWriter with the given target width in runes,
-// producing output on the underlying writer w. The dec and enc are used to
-// respectively decode runes from Write calls, and encode runes to w.
-func NewLineWriter(w io.Writer, width int, dec RuneChunkDecoder, enc RuneEncoder) *LineWriter {
- ret := &LineWriter{
- w: w,
- runeDecoder: dec,
- width: runePos(width),
- lineTerm: []byte("\n"),
- paragraphSep: "\n",
- prevState: stateWordWrap,
- prevRune: LineSeparator,
- lineBuf: byteRuneBuffer{enc: enc},
- }
- ret.resetLine()
- return ret
-}
-
-// NewUTF8LineWriter returns a new LineWriter filter that implements io.Writer,
-// and decodes and encodes runes in UTF-8.
-func NewUTF8LineWriter(w io.Writer, width int) *LineWriter {
- return NewLineWriter(w, width, &UTF8ChunkDecoder{}, UTF8Encoder{})
-}
-
-// Width returns the target width in runes. If width < 0 the width is
-// unlimited; each paragraph is output as a single line.
-func (w *LineWriter) Width() int { return int(w.width) }
-
-// SetLineTerminator sets the line terminator for subsequent Write calls. Every
-// output line is terminated with term; EOL runes from the input are never
-// written to the output. A new LineWriter instance uses "\n" as the default
-// line terminator.
-//
-// Calls Flush internally, and returns any Flush error.
-func (w *LineWriter) SetLineTerminator(term string) error {
- if err := w.Flush(); err != nil {
- return err
- }
- w.lineTerm = []byte(term)
- w.resetLine()
- return nil
-}
-
-// SetParagraphSeparator sets the paragraph separator for subsequent Write
-// calls. Every consecutive pair of non-empty paragraphs is separated with sep;
-// EOL runes from the input are never written to the output. A new LineWriter
-// instance uses "\n" as the default paragraph separator.
-//
-// Calls Flush internally, and returns any Flush error.
-func (w *LineWriter) SetParagraphSeparator(sep string) error {
- if err := w.Flush(); err != nil {
- return err
- }
- w.paragraphSep = sep
- w.resetLine()
- return nil
-}
-
-// SetIndents sets the indentation for subsequent Write calls. Multiple indents
-// may be set, corresponding to the indent to use for the corresponding
-// paragraph line. E.g. SetIndents("AA", "BBB", C") means the first line in
-// each paragraph is indented with "AA", the second line in each paragraph is
-// indented with "BBB", and all subsequent lines in each paragraph are indented
-// with "C".
-//
-// SetIndents() is equivalent to SetIndents(""), SetIndents("", ""), etc.
-//
-// A new LineWriter instance has no indents by default.
-//
-// Calls Flush internally, and returns any Flush error.
-func (w *LineWriter) SetIndents(indents ...string) error {
- if err := w.Flush(); err != nil {
- return err
- }
- // Copy indents in case the user passed the slice via SetIndents(p...), and
- // canonicalize the all empty case to nil.
- allEmpty := true
- w.indents = make([]string, len(indents))
- for ix, indent := range indents {
- w.indents[ix] = indent
- if indent != "" {
- allEmpty = false
- }
- }
- if allEmpty {
- w.indents = nil
- }
- w.resetLine()
- return nil
-}
-
-// Write implements io.Writer by buffering data into the LineWriter w. Actual
-// writes to the underlying writer may occur, and may include data buffered in
-// either this Write call or previous Write calls.
-//
-// Flush must be called after the last call to Write.
-func (w *LineWriter) Write(data []byte) (int, error) {
- return RuneChunkWrite(w.runeDecoder, w.addRune, data)
-}
-
-// Flush flushes any remaining buffered text, and resets the paragraph line
-// count back to 0, so that indents will be applied starting from the first
-// line. It does not imply a paragraph separator; repeated calls to Flush with
-// no intervening calls to other methods is equivalent to a single Flush.
-//
-// Flush must be called after the last call to Write, and may be called an
-// arbitrary number of times before the last Write.
-func (w *LineWriter) Flush() error {
- if err := RuneChunkFlush(w.runeDecoder, w.addRune); err != nil {
- return err
- }
- // Add U+2028 to force the last line (if any) to be written.
- if err := w.addRune(LineSeparator); err != nil {
- return err
- }
- // Reset the paragraph line count.
- w.paragraphLineIndex = 0
- w.resetLine()
- return nil
-}
-
-// addRune is called every time w.runeDecoder decodes a full rune.
-func (w *LineWriter) addRune(r rune) error {
- state, lineBreak := w.nextState(r, w.updateRune(r))
- if lineBreak {
- if err := w.writeLine(); err != nil {
- return err
- }
- }
- w.bufferRune(r, state, lineBreak)
- w.prevState = state
- w.prevRune = r
- return nil
-}
-
-// We classify each incoming rune into three kinds for easier handling.
-type kind int
-
-const (
- kindEOL kind = iota
- kindSpace
- kindLetter
-)
-
-func runeKind(r rune) kind {
- switch r {
- case '\f', '\n', '\r', '\v', LineSeparator, ParagraphSeparator:
- return kindEOL
- }
- if unicode.IsSpace(r) {
- return kindSpace
- }
- return kindLetter
-}
-
-func (w *LineWriter) updateRune(r rune) bool {
- forceLineBreak := false
- switch kind := runeKind(r); kind {
- case kindEOL:
- // Update lastWordEnd if the last word just ended.
- if w.newWordStart != -1 {
- w.newWordStart = -1
- w.lastWordEnd = w.lineBuf.ByteLen()
- }
- switch {
- case w.prevRune == '\r' && r == '\n':
- // Treat "\r\n" as a single EOL; we've already handled the logic for '\r',
- // so there's nothing to do when we see '\n'.
- case r == LineSeparator:
- // Treat U+2028 as a pure line break; it's never a paragraph break.
- forceLineBreak = true
- case r == ParagraphSeparator || !w.inputLineHasLetter:
- // The paragraph has just been terminated if we see an explicit U+2029, or
- // if we see a blank line, which may contain spaces.
- forceLineBreak = true
- w.terminateParagraph = true
- }
- w.inputLineHasLetter = false
- case kindSpace:
- // Update lastWordEnd if the last word just ended.
- if w.newWordStart != -1 {
- w.newWordStart = -1
- w.lastWordEnd = w.lineBuf.ByteLen()
- }
- case kindLetter:
- // Update newWordStart if a new word just started.
- if w.newWordStart == -1 {
- w.newWordStart = w.lineBuf.ByteLen()
- }
- w.inputLineHasLetter = true
- w.terminateParagraph = false
- default:
- panic(fmt.Errorf("textutil: updateRune unhandled kind %d", kind))
- }
- return forceLineBreak
-}
-
-// nextState returns the next state and whether we should break the line.
-//
-// Here's a handy table that describes all the scenarios in which we will line
-// break input text, grouped by the reason for the break. The current position
-// is the last non-* rune in each pattern, which is where we decide to break.
-//
-// w.prevState Next state Buffer reset
-// ----------- ---------- ------------
-// ===== Force line break (U+2028 / U+2029, blank line) =====
-// a..*|*** * wordWrap empty
-// a._.|*** * wordWrap empty
-// a+**|*** * wordWrap empty
-//
-// ===== verbatim: wait for any EOL =====
-// _*.*|*** verbatim wordWrap empty
-//
-// ===== wordWrap: switch to verbatim =====
-// a._*|*** wordWrap verbatim empty
-//
-// ===== wordWrap: line is too wide =====
-// abc.|*** wordWrap wordWrap empty
-// abcd|.** wordWrap wordWrap empty
-// abcd|e.* wordWrap wordWrap empty
-// a_cd|.** wordWrap wordWrap empty
-//
-// abc_|*** wordWrap skipSpace empty
-// abcd|_** wordWrap skipSpace empty
-// abcd|e_* wordWrap skipSpace empty
-// a_cd|_** wordWrap skipSpace empty
-//
-// a_cd|e** wordWrap start newWordStart
-//
-// LEGEND
-// abcde Letter
-// . End-of-line
-// + End-of-line (only U+2028 / U+2029)
-// _ Space
-// * Any rune (letter, line-end or space)
-// | Visual indication of width=4, has no width itself.
-//
-// Note that Flush calls behave exactly as if an explicit U+2028 line separator
-// were added to the end of all buffered data.
-func (w *LineWriter) nextState(r rune, forceLineBreak bool) (state, bool) {
- if forceLineBreak {
- return stateWordWrap, true
- }
- kind := runeKind(r)
- // Handle non word-wrap states, which are easy.
- switch w.prevState {
- case stateVerbatim:
- if kind == kindEOL {
- return stateWordWrap, true
- }
- return stateVerbatim, false
- case stateSkipSpace:
- if kind == kindSpace {
- return stateSkipSpace, false
- }
- return stateWordWrap, false
- }
- // Handle stateWordWrap, which is more complicated.
-
- // Switch to the verbatim state when we see a space right after an EOL.
- if runeKind(w.prevRune) == kindEOL && kind == kindSpace {
- return stateVerbatim, true
- }
- // Break on EOL or space when the line is too wide. See above table.
- if w.width >= 0 && w.width <= w.lineBuf.RuneLen()+1 {
- switch kind {
- case kindEOL:
- return stateWordWrap, true
- case kindSpace:
- return stateSkipSpace, true
- }
- // case kindLetter falls through
- }
- // Handle the newWordStart case in the above table.
- if w.width >= 0 && w.width < w.lineBuf.RuneLen()+1 && w.newWordStart != w.lineStart {
- return stateWordWrap, true
- }
- // Stay in the wordWrap state and don't break the line.
- return stateWordWrap, false
-}
-
-func (w *LineWriter) writeLine() error {
- if w.lastWordEnd == -1 {
- // Don't write blank lines, but we must reset the line in case the paragraph
- // has just been terminated.
- w.resetLine()
- return nil
- }
- // Write the line (without trailing spaces) followed by the line terminator.
- line := w.lineBuf.Bytes()[:w.lastWordEnd]
- if _, err := w.w.Write(line); err != nil {
- return err
- }
- if _, err := w.w.Write(w.lineTerm); err != nil {
- return err
- }
- // Reset the line buffer.
- w.wroteFirstLine = true
- w.paragraphLineIndex++
- if w.newWordStart != -1 {
- // If we have an unterminated new word, we must be in the newWordStart case
- // in the table above. Handle the special buffer reset here.
- newWord := string(w.lineBuf.Bytes()[w.newWordStart:])
- w.resetLine()
- w.newWordStart = w.lineBuf.ByteLen()
- w.lineBuf.WriteString(newWord)
- } else {
- w.resetLine()
- }
- return nil
-}
-
-func (w *LineWriter) resetLine() {
- w.lineBuf.Reset()
- w.newWordStart = -1
- w.lastWordEnd = -1
- // Write the paragraph separator if the previous paragraph has terminated.
- // This consumes no runes from the line width.
- if w.wroteFirstLine && w.terminateParagraph {
- w.lineBuf.WriteString0Runes(w.paragraphSep)
- w.paragraphLineIndex = 0
- }
- // Add indent; a non-empty indent consumes runes from the line width.
- var indent string
- switch {
- case w.paragraphLineIndex < len(w.indents):
- indent = w.indents[w.paragraphLineIndex]
- case len(w.indents) > 0:
- indent = w.indents[len(w.indents)-1]
- }
- w.lineBuf.WriteString(indent)
- w.lineStart = w.lineBuf.ByteLen()
-}
-
-func (w *LineWriter) bufferRune(r rune, state state, lineBreak bool) {
- // Never add leading spaces to the buffer in the wordWrap state.
- wordWrapNoLeadingSpaces := state == stateWordWrap && !lineBreak
- switch kind := runeKind(r); kind {
- case kindEOL:
- // When we're word-wrapping and we see a letter followed by EOL, we convert
- // the EOL into a single space in the buffer, to break the previous word
- // from the next word.
- if wordWrapNoLeadingSpaces && runeKind(w.prevRune) == kindLetter {
- w.lineBuf.WriteRune(' ')
- }
- case kindSpace:
- if wordWrapNoLeadingSpaces || state == stateVerbatim {
- w.lineBuf.WriteRune(r)
- }
- case kindLetter:
- w.lineBuf.WriteRune(r)
- default:
- panic(fmt.Errorf("textutil: bufferRune unhandled kind %d", kind))
- }
-}
diff --git a/lib/textutil/line_writer_test.go b/lib/textutil/line_writer_test.go
deleted file mode 100644
index 29db23f..0000000
--- a/lib/textutil/line_writer_test.go
+++ /dev/null
@@ -1,268 +0,0 @@
-package textutil
-
-import (
- "bytes"
- "io"
- "strings"
- "testing"
-)
-
-type lp struct {
- line, para string
-}
-
-var (
- allIndents = [][]int{nil, {}, {1}, {2}, {1, 2}, {2, 1}}
- allIndents1 = [][]int{{1}, {2}, {1, 2}, {2, 1}}
-)
-
-func TestLineWriter(t *testing.T) {
- tests := []struct {
- Width int
- Indents [][]int
- In string // See xlateIn for details on the format
- Want string // See xlateWant for details on the format
- }{
- // Completely blank input yields empty output.
- {4, allIndents, "", ""},
- {4, allIndents, " ", ""},
- {4, allIndents, " ", ""},
- {4, allIndents, " ", ""},
- {4, allIndents, " ", ""},
- {4, allIndents, " ", ""},
- {4, allIndents, " ", ""},
- {4, allIndents, "F N R V L P ", ""},
- // Single words never get word-wrapped, even if they're long.
- {4, allIndents, "a", "0a."},
- {4, allIndents, "ab", "0ab."},
- {4, allIndents, "abc", "0abc."},
- {4, allIndents, "abcd", "0abcd."},
- {4, allIndents, "abcde", "0abcde."},
- {4, allIndents, "abcdef", "0abcdef."},
- // Word-wrapping boundary conditions.
- {4, allIndents, "abc ", "0abc."},
- {4, allIndents, "abc ", "0abc."},
- {4, allIndents, "abcN", "0abc."},
- {4, allIndents, "abcN ", "0abc."},
- {4, allIndents, "abcd ", "0abcd."},
- {4, allIndents, "abcd ", "0abcd."},
- {4, allIndents, "abcdN", "0abcd."},
- {4, allIndents, "abcdN ", "0abcd."},
- {4, [][]int{nil}, "a cd", "0a cd."},
- {4, [][]int{nil}, "a cd ", "0a cd."},
- {4, [][]int{nil}, "a cdN", "0a cd."},
- {4, allIndents1, "a cd", "0a.1cd."},
- {4, allIndents1, "a cd ", "0a.1cd."},
- {4, allIndents1, "a cdN", "0a.1cd."},
- {4, allIndents, "a cde", "0a.1cde."},
- {4, allIndents, "a cde ", "0a.1cde."},
- {4, allIndents, "a cdeN", "0a.1cde."},
- {4, [][]int{nil}, "a d", "0a d."},
- {4, [][]int{nil}, "a d ", "0a d."},
- {4, [][]int{nil}, "a dN", "0a d."},
- {4, allIndents1, "a d", "0a.1d."},
- {4, allIndents1, "a d ", "0a.1d."},
- {4, allIndents1, "a dN", "0a.1d."},
- {4, allIndents, "a de", "0a.1de."},
- {4, allIndents, "a de ", "0a.1de."},
- {4, allIndents, "a deN", "0a.1de."},
- // Multi-line word-wrapping boundary conditions.
- {4, allIndents, "abc e", "0abc.1e."},
- {4, allIndents, "abc.e", "0abc.1e."},
- {4, allIndents, "abc efgh", "0abc.1efgh."},
- {4, allIndents, "abc.efgh", "0abc.1efgh."},
- {4, allIndents, "abc efghi", "0abc.1efghi."},
- {4, allIndents, "abc.efghi", "0abc.1efghi."},
- {4, [][]int{nil}, "abc e gh", "0abc.1e gh."},
- {4, [][]int{nil}, "abc.e.gh", "0abc.1e gh."},
- {4, allIndents1, "abc e gh", "0abc.1e.2gh."},
- {4, allIndents1, "abc.e.gh", "0abc.1e.2gh."},
- {4, allIndents, "abc e ghijk", "0abc.1e.2ghijk."},
- {4, allIndents, "abc.e.ghijk", "0abc.1e.2ghijk."},
- // Verbatim lines.
- {4, allIndents, " b", "0 b."},
- {4, allIndents, " bc", "0 bc."},
- {4, allIndents, " bcd", "0 bcd."},
- {4, allIndents, " bcde", "0 bcde."},
- {4, allIndents, " bcdef", "0 bcdef."},
- {4, allIndents, " bcdefg", "0 bcdefg."},
- {4, allIndents, " b de ghijk", "0 b de ghijk."},
- // Verbatim lines before word-wrapped lines.
- {4, allIndents, " b.vw yz", "0 b.1vw.2yz."},
- {4, allIndents, " bc.vw yz", "0 bc.1vw.2yz."},
- {4, allIndents, " bcd.vw yz", "0 bcd.1vw.2yz."},
- {4, allIndents, " bcde.vw yz", "0 bcde.1vw.2yz."},
- {4, allIndents, " bcdef.vw yz", "0 bcdef.1vw.2yz."},
- {4, allIndents, " bcdefg.vw yz", "0 bcdefg.1vw.2yz."},
- {4, allIndents, " b de ghijk.vw yz", "0 b de ghijk.1vw.2yz."},
- // Verbatim lines after word-wrapped lines.
- {4, allIndents, "vw yz. b", "0vw.1yz.2 b."},
- {4, allIndents, "vw yz. bc", "0vw.1yz.2 bc."},
- {4, allIndents, "vw yz. bcd", "0vw.1yz.2 bcd."},
- {4, allIndents, "vw yz. bcde", "0vw.1yz.2 bcde."},
- {4, allIndents, "vw yz. bcdef", "0vw.1yz.2 bcdef."},
- {4, allIndents, "vw yz. bcdefg", "0vw.1yz.2 bcdefg."},
- {4, allIndents, "vw yz. b de ghijk", "0vw.1yz.2 b de ghijk."},
- // Verbatim lines between word-wrapped lines.
- {4, allIndents, "vw yz. b.mn pq", "0vw.1yz.2 b.2mn.2pq."},
- {4, allIndents, "vw yz. bc.mn pq", "0vw.1yz.2 bc.2mn.2pq."},
- {4, allIndents, "vw yz. bcd.mn pq", "0vw.1yz.2 bcd.2mn.2pq."},
- {4, allIndents, "vw yz. bcde.mn pq", "0vw.1yz.2 bcde.2mn.2pq."},
- {4, allIndents, "vw yz. bcdef.mn pq", "0vw.1yz.2 bcdef.2mn.2pq."},
- {4, allIndents, "vw yz. bcdefg.mn pq", "0vw.1yz.2 bcdefg.2mn.2pq."},
- {4, allIndents, "vw yz. b de ghijk.mn pq", "0vw.1yz.2 b de ghijk.2mn.2pq."},
- // Multi-paragraphs via explicit U+2029, and multi-newline.
- {4, allIndents, "ab de ghPij lm op", "0ab.1de.2gh.:0ij.1lm.2op."},
- {4, allIndents, "ab.de.ghPij.lm.op", "0ab.1de.2gh.:0ij.1lm.2op."},
- {4, allIndents, "ab de gh Pij lm op", "0ab.1de.2gh.:0ij.1lm.2op."},
- {4, allIndents, "ab.de.gh Pij.lm.op", "0ab.1de.2gh.:0ij.1lm.2op."},
- {4, allIndents, "ab de ghNNij lm op", "0ab.1de.2gh.:0ij.1lm.2op."},
- {4, allIndents, "ab.de.ghNNij.lm.op", "0ab.1de.2gh.:0ij.1lm.2op."},
- {4, allIndents, "ab de ghNNNij lm op", "0ab.1de.2gh.:0ij.1lm.2op."},
- {4, allIndents, "ab.de.ghNNNij.lm.op", "0ab.1de.2gh.:0ij.1lm.2op."},
- {4, allIndents, "ab de gh N Nij lm op", "0ab.1de.2gh.:0ij.1lm.2op."},
- {4, allIndents, "ab.de.gh N Nij.lm.op", "0ab.1de.2gh.:0ij.1lm.2op."},
- {4, allIndents, "ab de gh N N Nij lm op", "0ab.1de.2gh.:0ij.1lm.2op."},
- {4, allIndents, "ab.de.gh N N Nij.lm.op", "0ab.1de.2gh.:0ij.1lm.2op."},
- // Special-case /r/n is a single EOL, but may be combined.
- {4, allIndents, "ab de ghRNij lm op", "0ab.1de.2gh.2ij.2lm.2op."},
- {4, allIndents, "ab.de.ghRNij.lm.op", "0ab.1de.2gh.2ij.2lm.2op."},
- {4, allIndents, "ab de gh RNij lm op", "0ab.1de.2gh.2ij.2lm.2op."},
- {4, allIndents, "ab.de.gh RNij.lm.op", "0ab.1de.2gh.2ij.2lm.2op."},
- {4, allIndents, "ab de ghRNRNij lm op", "0ab.1de.2gh.:0ij.1lm.2op."},
- {4, allIndents, "ab.de.ghRNRNij.lm.op", "0ab.1de.2gh.:0ij.1lm.2op."},
- {4, allIndents, "ab de gh RN RNij lm op", "0ab.1de.2gh.:0ij.1lm.2op."},
- {4, allIndents, "ab.de.gh RN RNij.lm.op", "0ab.1de.2gh.:0ij.1lm.2op."},
- {4, allIndents, "ab de ghR Nij lm op", "0ab.1de.2gh.:0ij.1lm.2op."},
- {4, allIndents, "ab.de.ghR Nij.lm.op", "0ab.1de.2gh.:0ij.1lm.2op."},
- // Line separator via explicit U+2028 ends lines, but not paragraphs.
- {4, allIndents, "aLcd", "0a.1cd."},
- {4, allIndents, "a Lcd", "0a.1cd."},
- {4, allIndents, "aLLcd", "0a.1cd."},
- {4, allIndents, "a LLcd", "0a.1cd."},
- // 0 width ends up with one word per line, except verbatim lines.
- {0, allIndents, "a c e", "0a.1c.2e."},
- {0, allIndents, "a cd fghij", "0a.1cd.2fghij."},
- {0, allIndents, "a. cd fghij.l n", "0a.1 cd fghij.2l.2n."},
- // -1 width ends up with all words on same line, except verbatim lines.
- {-1, allIndents, "a c e", "0a c e."},
- {-1, allIndents, "a cd fghij", "0a cd fghij."},
- {-1, allIndents, "a. cd fghij.l n", "0a.1 cd fghij.2l n."},
- }
- for _, test := range tests {
- // Run with a variety of chunk sizes.
- for _, sizes := range [][]int{nil, {1}, {2}, {1, 2}, {2, 1}} {
- // Run with a variety of line terminators and paragraph separators.
- for _, lp := range []lp{{}, {"\n", "\n"}, {"L", "P"}, {"LLL", "PPP"}} {
- // Run with a variety of indents.
- if len(test.Indents) == 0 {
- t.Errorf("%d %q %q has no indents, use [][]int{nil} rather than nil", test.Width, test.In, test.Want)
- }
- for _, indents := range test.Indents {
- var buf bytes.Buffer
- w := newUTF8LineWriter(t, &buf, test.Width, lp, indents)
- lineWriterWriteFlush(t, w, xlateIn(test.In), sizes)
- if got, want := buf.String(), xlateWant(test.Want, lp, indents); got != want {
- t.Errorf("%q sizes:%v lp:%q indents:%v got %q, want %q", test.In, sizes, lp, indents, got, want)
- }
- }
- }
- }
- }
-}
-
-// xlateIn translates our test.In pattern into an actual input string to feed
-// into the writer. The point is to make it easy to specify the various control
-// sequences in a single character, so it's easier to understand.
-func xlateIn(text string) string {
- text = strings.Replace(text, "F", "\f", -1)
- text = strings.Replace(text, "N", "\n", -1)
- text = strings.Replace(text, ".", "\n", -1) // Also allow . for easier reading
- text = strings.Replace(text, "R", "\r", -1)
- text = strings.Replace(text, "V", "\v", -1)
- text = strings.Replace(text, "L", "\u2028", -1)
- text = strings.Replace(text, "P", "\u2029", -1)
- return text
-}
-
-// xlateWant translates our test.Want pattern into an actual expected string to
-// compare against the output. The point is to make it easy to read and write
-// the expected patterns, and to make it easy to test various indents.
-func xlateWant(text string, lp lp, indents []int) string {
- // Dot "." and colon ":" in the want string indicate line terminators and
- // paragraph separators, respectively.
- line := lp.line
- if line == "" {
- line = "\n"
- }
- text = strings.Replace(text, ".", line, -1)
- para := lp.para
- if para == "" {
- para = "\n"
- }
- text = strings.Replace(text, ":", para, -1)
- // The numbers in the want string indicate paragraph line numbers, to make it
- // easier to automatically replace for various indent configurations.
- switch len(indents) {
- case 0:
- text = strings.Replace(text, "0", "", -1)
- text = strings.Replace(text, "1", "", -1)
- text = strings.Replace(text, "2", "", -1)
- case 1:
- text = strings.Replace(text, "0", spaces(indents[0]), -1)
- text = strings.Replace(text, "1", spaces(indents[0]), -1)
- text = strings.Replace(text, "2", spaces(indents[0]), -1)
- case 2:
- text = strings.Replace(text, "0", spaces(indents[0]), -1)
- text = strings.Replace(text, "1", spaces(indents[1]), -1)
- text = strings.Replace(text, "2", spaces(indents[1]), -1)
- case 3:
- text = strings.Replace(text, "0", spaces(indents[0]), -1)
- text = strings.Replace(text, "1", spaces(indents[1]), -1)
- text = strings.Replace(text, "2", spaces(indents[2]), -1)
- }
- return text
-}
-
-func spaces(count int) string {
- return strings.Repeat(" ", count)
-}
-
-func newUTF8LineWriter(t *testing.T, buf io.Writer, width int, lp lp, indents []int) *LineWriter {
- w := NewUTF8LineWriter(buf, width)
- if lp.line != "" || lp.para != "" {
- if err := w.SetLineTerminator(lp.line); err != nil {
- t.Errorf("SetLineTerminator(%q) got %v, want nil", lp.line, err)
- }
- if err := w.SetParagraphSeparator(lp.para); err != nil {
- t.Errorf("SetParagraphSeparator(%q) got %v, want nil", lp.para, err)
- }
- }
- if indents != nil {
- indentStrs := make([]string, len(indents))
- for ix, indent := range indents {
- indentStrs[ix] = spaces(indent)
- }
- if err := w.SetIndents(indentStrs...); err != nil {
- t.Errorf("SetIndents(%v) got %v, want nil", indentStrs, err)
- }
- }
- return w
-}
-
-func lineWriterWriteFlush(t *testing.T, w *LineWriter, text string, sizes []int) {
- // Write chunks of different sizes until we've exhausted the input.
- remain := text
- for ix := 0; len(remain) > 0; ix++ {
- var chunk []byte
- chunk, remain = nextChunk(remain, sizes, ix)
- got, err := w.Write(chunk)
- if want := len(chunk); got != want || err != nil {
- t.Errorf("%q Write(%q) got (%d,%v), want (%d,nil)", text, chunk, got, err, want)
- }
- }
- // Flush the writer.
- if err := w.Flush(); err != nil {
- t.Errorf("%q Flush() got %v, want nil", text, err)
- }
-}
diff --git a/lib/textutil/rune.go b/lib/textutil/rune.go
deleted file mode 100644
index 57db02e..0000000
--- a/lib/textutil/rune.go
+++ /dev/null
@@ -1,119 +0,0 @@
-package textutil
-
-import (
- "bytes"
-)
-
-// TODO(toddw): Add UTF16 support.
-
-const (
- EOF = rune(-1) // Indicates the end of a rune stream.
- LineSeparator = '\u2028' // Unicode line separator rune.
- ParagraphSeparator = '\u2029' // Unicode paragraph separator rune.
-)
-
-// RuneEncoder is the interface to an encoder of a stream of runes into
-// bytes.Buffer.
-type RuneEncoder interface {
- // Encode encodes r into buf.
- Encode(r rune, buf *bytes.Buffer)
-}
-
-// RuneStreamDecoder is the interface to a decoder of a contiguous stream of
-// runes.
-type RuneStreamDecoder interface {
- // Next returns the next rune. Invalid encodings are returned as U+FFFD.
- // Returns EOF at the end of the stream.
- Next() rune
- // BytePos returns the current byte position in the original data buffer.
- BytePos() int
-}
-
-// RuneChunkDecoder is the interface to a decoder of a stream of encoded runes
-// that may be arbitrarily chunked.
-//
-// Implementations of RuneChunkDecoder are commonly used to implement io.Writer
-// wrappers, to handle buffering when chunk boundaries may occur in the middle
-// of an encoded rune.
-type RuneChunkDecoder interface {
- // Decode returns a RuneStreamDecoder that decodes the data chunk. Call Next
- // repeatedly on the returned stream until it returns EOF to decode the chunk.
- Decode(chunk []byte) RuneStreamDecoder
- // DecodeLeftover returns a RuneStreamDecoder that decodes leftover buffered
- // data. Call Next repeatedly on the returned stream until it returns EOF to
- // ensure all buffered data is processed.
- DecodeLeftover() RuneStreamDecoder
-}
-
-// RuneChunkWrite is a helper that calls d.Decode(data) and repeatedly calls
-// Next in a loop, calling fn for every rune that is decoded. Returns the
-// number of bytes in data that were successfully processed. If fn returns an
-// error, Write will return with that error, without processing any more data.
-//
-// This is a convenience for implementing io.Writer, given a RuneChunkDecoder.
-func RuneChunkWrite(d RuneChunkDecoder, fn func(rune) error, data []byte) (int, error) {
- stream := d.Decode(data)
- for r := stream.Next(); r != EOF; r = stream.Next() {
- if err := fn(r); err != nil {
- return stream.BytePos(), err
- }
- }
- return stream.BytePos(), nil
-}
-
-// RuneChunkFlush is a helper that calls d.DecodeLeftover and repeatedly calls
-// Next in a loop, calling fn for every rune that is decoded. If fn returns an
-// error, Flush will return with that error, without processing any more data.
-//
-// This is a convenience for implementing an additional Flush() call on an
-// implementation of io.Writer, given a RuneChunkDecoder.
-func RuneChunkFlush(d RuneChunkDecoder, fn func(rune) error) error {
- stream := d.DecodeLeftover()
- for r := stream.Next(); r != EOF; r = stream.Next() {
- if err := fn(r); err != nil {
- return err
- }
- }
- return nil
-}
-
-// bytePos and runePos distinguish positions that are used in either domain;
-// we're trying to avoid silly mistakes like adding a bytePos to a runePos.
-type bytePos int
-type runePos int
-
-// byteRuneBuffer maintains a buffer with both byte and rune based positions.
-type byteRuneBuffer struct {
- enc RuneEncoder
- buf bytes.Buffer
- runeLen runePos
-}
-
-func (b *byteRuneBuffer) ByteLen() bytePos { return bytePos(b.buf.Len()) }
-func (b *byteRuneBuffer) RuneLen() runePos { return b.runeLen }
-func (b *byteRuneBuffer) Bytes() []byte { return b.buf.Bytes() }
-
-func (b *byteRuneBuffer) Reset() {
- b.buf.Reset()
- b.runeLen = 0
-}
-
-// WriteRune writes r into b.
-func (b *byteRuneBuffer) WriteRune(r rune) {
- b.enc.Encode(r, &b.buf)
- b.runeLen++
-}
-
-// WriteString writes str into b.
-func (b *byteRuneBuffer) WriteString(str string) {
- for _, r := range str {
- b.WriteRune(r)
- }
-}
-
-// WriteString0Runes writes str into b, not incrementing the rune length.
-func (b *byteRuneBuffer) WriteString0Runes(str string) {
- for _, r := range str {
- b.enc.Encode(r, &b.buf)
- }
-}
diff --git a/lib/textutil/utf8.go b/lib/textutil/utf8.go
deleted file mode 100644
index 349033e..0000000
--- a/lib/textutil/utf8.go
+++ /dev/null
@@ -1,167 +0,0 @@
-package textutil
-
-import (
- "bytes"
- "fmt"
- "unicode/utf8"
-)
-
-// UTF8Encoder implements RuneEncoder for the UTF-8 encoding.
-type UTF8Encoder struct{}
-
-var _ RuneEncoder = UTF8Encoder{}
-
-// Encode encodes r into buf in the UTF-8 encoding.
-func (UTF8Encoder) Encode(r rune, buf *bytes.Buffer) { buf.WriteRune(r) }
-
-// UTF8ChunkDecoder implements RuneChunkDecoder for a stream of UTF-8 data that
-// is arbitrarily chunked.
-//
-// UTF-8 is a byte-wise encoding that may use multiple bytes to encode a single
-// rune. This decoder buffers partial runes that have been split across chunks,
-// so that a full rune is returned when the subsequent data chunk is provided.
-//
-// This is commonly used to implement an io.Writer wrapper over UTF-8 text. It
-// is useful since the data provided to Write calls may be arbitrarily chunked.
-//
-// The zero UTF8ChunkDecoder is a decoder with an empty buffer.
-type UTF8ChunkDecoder struct {
- // The only state we keep is the last partial rune we've encountered.
- partial [utf8.UTFMax]byte
- partialLen int
-}
-
-var _ RuneChunkDecoder = (*UTF8ChunkDecoder)(nil)
-
-// Decode returns a RuneStreamDecoder that decodes the data chunk. Call Next
-// repeatedly on the returned stream until it returns EOF to decode the chunk.
-//
-// If the data is chunked in the middle of an encoded rune, the final partial
-// rune in the chunk will be buffered, and the next call to Decode will continue
-// by combining the buffered data with the next chunk.
-//
-// Invalid encodings are transformed into U+FFFD, one byte at a time. See
-// unicode/utf8.DecodeRune for details.
-func (d *UTF8ChunkDecoder) Decode(chunk []byte) RuneStreamDecoder {
- return &utf8Stream{d, chunk, 0}
-}
-
-// DecodeLeftover returns a RuneStreamDecoder that decodes leftover buffered
-// data. Call Next repeatedly on the returned stream until it returns EOF to
-// ensure all buffered data is processed.
-//
-// Since the only data that is buffered is the final partial rune, the returned
-// RuneStreamDecoder will only contain U+FFFD or EOF.
-func (d *UTF8ChunkDecoder) DecodeLeftover() RuneStreamDecoder {
- return &utf8LeftoverStream{d, 0}
-}
-
-// nextRune decodes the next rune, logically combining any previously buffered
-// data with the data chunk. It returns the decoded rune and the byte size of
-// the data that was used for the decoding.
-//
-// The returned size may be > 0 even if the returned rune == EOF, if a partial
-// rune was detected and buffered. The returned size may be 0 even if the
-// returned rune != EOF, if previously buffered data was decoded.
-func (d *UTF8ChunkDecoder) nextRune(data []byte) (rune, int) {
- if d.partialLen > 0 {
- return d.nextRunePartial(data)
- }
- r, size := utf8.DecodeRune(data)
- if r == utf8.RuneError && !utf8.FullRune(data) {
- // Initialize the partial rune buffer with remaining data.
- d.partialLen = copy(d.partial[:], data)
- return d.verifyPartial(d.partialLen, data)
- }
- return r, size
-}
-
-// nextRunePartial implements nextRune when there is a previously buffered
-// partial rune.
-func (d *UTF8ChunkDecoder) nextRunePartial(data []byte) (rune, int) {
- // Append as much data as we can to the partial rune, and see if it's full.
- oldLen := d.partialLen
- d.partialLen += copy(d.partial[oldLen:], data)
- if !utf8.FullRune(d.partial[:d.partialLen]) {
- // We still don't have a full rune - keep waiting.
- return d.verifyPartial(d.partialLen-oldLen, data)
- }
- // We finally have a full rune.
- r, size := utf8.DecodeRune(d.partial[:d.partialLen])
- if size < oldLen {
- // This occurs when we have a multi-byte rune that has the right number of
- // bytes, but is an invalid code point.
- //
- // Say oldLen=2, and we just received the third byte of a 3-byte rune which
- // isn't a UTF-8 trailing byte. In this case utf8.DecodeRune returns U+FFFD
- // and size=1, to indicate we should skip the first byte.
- //
- // We shift the unread portion of the old partial data forward, and update
- // the partial len so that it's strictly decreasing. The strictly
- // decreasing property isn't necessary for correctness, but helps avoid
- // repeatedly copying data into the partial buffer unecessarily.
- copy(d.partial[:], d.partial[size:oldLen])
- d.partialLen = oldLen - size
- return r, 0
- }
- // We've used all the old buffered data; start decoding directly from data.
- d.partialLen = 0
- return r, size - oldLen
-}
-
-// verifyPartial is called when we don't have a full rune, and ncopy bytes have
-// been copied from data into the decoder partial rune buffer. We expect that
-// all data has been buffered and we return EOF and the total size of the data.
-func (d *UTF8ChunkDecoder) verifyPartial(ncopy int, data []byte) (rune, int) {
- if ncopy < len(data) {
- // Something's very wrong if we managed to fill d.partial without copying
- // all the data; any sequence of utf8.UTFMax bytes must be a full rune.
- panic(fmt.Errorf("UTF8ChunkDecoder: partial rune %v with leftover data %v", d.partial[:d.partialLen], data[ncopy:]))
- }
- return EOF, len(data)
-}
-
-// utf8Stream implements UTF8ChunkDecoder.Decode.
-type utf8Stream struct {
- d *UTF8ChunkDecoder
- data []byte
- pos int
-}
-
-var _ RuneStreamDecoder = (*utf8Stream)(nil)
-
-func (s *utf8Stream) Next() rune {
- if s.pos == len(s.data) {
- return EOF
- }
- r, size := s.d.nextRune(s.data[s.pos:])
- s.pos += size
- return r
-}
-
-func (s *utf8Stream) BytePos() int {
- return s.pos
-}
-
-// utf8LeftoverStream implements UTF8ChunkDecoder.DecodeLeftover.
-type utf8LeftoverStream struct {
- d *UTF8ChunkDecoder
- pos int
-}
-
-var _ RuneStreamDecoder = (*utf8LeftoverStream)(nil)
-
-func (s *utf8LeftoverStream) Next() rune {
- if s.d.partialLen == 0 {
- return EOF
- }
- r, size := utf8.DecodeRune(s.d.partial[:s.d.partialLen])
- copy(s.d.partial[:], s.d.partial[size:])
- s.d.partialLen -= size
- s.pos += size
- return r
-}
-
-func (s *utf8LeftoverStream) BytePos() int {
- return s.pos
-}
diff --git a/lib/textutil/utf8_test.go b/lib/textutil/utf8_test.go
deleted file mode 100644
index 7517bef..0000000
--- a/lib/textutil/utf8_test.go
+++ /dev/null
@@ -1,110 +0,0 @@
-package textutil
-
-import (
- "reflect"
- "testing"
-)
-
-func TestUTF8ChunkDecoder(t *testing.T) {
- r2 := "Δ"
- r3 := "王"
- r4 := "\U0001F680"
- tests := []struct {
- Text string
- Want []rune
- }{
- {"", nil},
- {"a", []rune{'a'}},
- {"abc", []rune{'a', 'b', 'c'}},
- {"abc def ghi", []rune{'a', 'b', 'c', ' ', 'd', 'e', 'f', ' ', 'g', 'h', 'i'}},
- // 2-byte runes.
- {"ΔΘΠΣΦ", []rune{'Δ', 'Θ', 'Π', 'Σ', 'Φ'}},
- // 3-byte runes.
- {"王普澤世界", []rune{'王', '普', '澤', '世', '界'}},
- // 4-byte runes.
- {"\U0001F680\U0001F681\U0001F682\U0001F683", []rune{'\U0001F680', '\U0001F681', '\U0001F682', '\U0001F683'}},
- // Mixed-bytes.
- {"aΔ王\U0001F680æ™®Θb", []rune{'a', 'Δ', '王', '\U0001F680', 'æ™®', 'Θ', 'b'}},
- // Error runes translated to U+FFFD.
- {"\uFFFD", []rune{'\uFFFD'}},
- {"a\uFFFDb", []rune{'a', '\uFFFD', 'b'}},
- {"\xFF", []rune{'\uFFFD'}},
- {"a\xFFb", []rune{'a', '\uFFFD', 'b'}},
- // Multi-byte full runes.
- {r2, []rune{[]rune(r2)[0]}},
- {r3, []rune{[]rune(r3)[0]}},
- {r4, []rune{[]rune(r4)[0]}},
- // Partial runes translated to U+FFFD.
- {r2[:1], []rune{'\uFFFD'}},
- {r3[:1], []rune{'\uFFFD'}},
- {r3[:2], []rune{'\uFFFD', '\uFFFD'}},
- {r4[:1], []rune{'\uFFFD'}},
- {r4[:2], []rune{'\uFFFD', '\uFFFD'}},
- {r4[:3], []rune{'\uFFFD', '\uFFFD', '\uFFFD'}},
- // Leading partial runes translated to U+FFFD.
- {r2[:1] + "b", []rune{'\uFFFD', 'b'}},
- {r3[:1] + "b", []rune{'\uFFFD', 'b'}},
- {r3[:2] + "b", []rune{'\uFFFD', '\uFFFD', 'b'}},
- {r4[:1] + "b", []rune{'\uFFFD', 'b'}},
- {r4[:2] + "b", []rune{'\uFFFD', '\uFFFD', 'b'}},
- {r4[:3] + "b", []rune{'\uFFFD', '\uFFFD', '\uFFFD', 'b'}},
- // Trailing partial runes translated to U+FFFD.
- {"a" + r2[:1], []rune{'a', '\uFFFD'}},
- {"a" + r3[:1], []rune{'a', '\uFFFD'}},
- {"a" + r3[:2], []rune{'a', '\uFFFD', '\uFFFD'}},
- {"a" + r4[:1], []rune{'a', '\uFFFD'}},
- {"a" + r4[:2], []rune{'a', '\uFFFD', '\uFFFD'}},
- {"a" + r4[:3], []rune{'a', '\uFFFD', '\uFFFD', '\uFFFD'}},
- // Bracketed partial runes translated to U+FFFD.
- {"a" + r2[:1] + "b", []rune{'a', '\uFFFD', 'b'}},
- {"a" + r3[:1] + "b", []rune{'a', '\uFFFD', 'b'}},
- {"a" + r3[:2] + "b", []rune{'a', '\uFFFD', '\uFFFD', 'b'}},
- {"a" + r4[:1] + "b", []rune{'a', '\uFFFD', 'b'}},
- {"a" + r4[:2] + "b", []rune{'a', '\uFFFD', '\uFFFD', 'b'}},
- {"a" + r4[:3] + "b", []rune{'a', '\uFFFD', '\uFFFD', '\uFFFD', 'b'}},
- }
- for _, test := range tests {
- // Run with a variety of chunk sizes.
- for _, sizes := range [][]int{nil, {1}, {2}, {1, 2}, {2, 1}, {3}, {1, 2, 3}} {
- got := runeChunkWriteFlush(t, test.Text, sizes)
- if want := test.Want; !reflect.DeepEqual(got, want) {
- t.Errorf("%q got %v, want %v", test.Text, got, want)
- }
- }
- }
-}
-
-func runeChunkWriteFlush(t *testing.T, text string, sizes []int) []rune {
- var dec UTF8ChunkDecoder
- var runes []rune
- addRune := func(r rune) error {
- runes = append(runes, r)
- return nil
- }
- // Write chunks of different sizes until we've exhausted the input text.
- remain := text
- for ix := 0; len(remain) > 0; ix++ {
- var chunk []byte
- chunk, remain = nextChunk(remain, sizes, ix)
- got, err := RuneChunkWrite(&dec, addRune, chunk)
- if want := len(chunk); got != want || err != nil {
- t.Errorf("%q RuneChunkWrite(%q) got (%d,%v), want (%d,nil)", text, chunk, got, err, want)
- }
- }
- // Flush the decoder.
- if err := RuneChunkFlush(&dec, addRune); err != nil {
- t.Errorf("%q RuneChunkFlush got %v, want nil", text, err)
- }
- return runes
-}
-
-func nextChunk(text string, sizes []int, index int) (chunk []byte, remain string) {
- if len(sizes) == 0 {
- return []byte(text), ""
- }
- size := sizes[index%len(sizes)]
- if size >= len(text) {
- return []byte(text), ""
- }
- return []byte(text[:size]), text[size:]
-}
diff --git a/lib/textutil/util.go b/lib/textutil/util.go
deleted file mode 100644
index 85402de..0000000
--- a/lib/textutil/util.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package textutil
-
-import (
- "syscall"
- "unsafe"
-)
-
-// TerminalSize returns the dimensions of the terminal, if it's available from
-// the OS, otherwise returns an error.
-func TerminalSize() (row, col int, _ error) {
- // Try getting the terminal size from stdout, stderr and stdin respectively.
- // We try each of these in turn because the mechanism we're using fails if any
- // of the fds is redirected on the command line. E.g. "tool | less" redirects
- // the stdout of tool to the stdin of less, and will mean tool cannot retrieve
- // the terminal size from stdout.
- //
- // TODO(toddw): This probably only works on some linux / unix variants; add
- // build tags and support different platforms.
- if row, col, err := terminalSize(syscall.Stdout); err == nil {
- return row, col, err
- }
- if row, col, err := terminalSize(syscall.Stderr); err == nil {
- return row, col, err
- }
- return terminalSize(syscall.Stdin)
-}
-
-func terminalSize(fd int) (int, int, error) {
- var ws winsize
- if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&ws))); err != 0 {
- return 0, 0, err
- }
- return int(ws.row), int(ws.col), nil
-}
-
-// winsize must correspond to the struct defined in "sys/ioctl.h". Do not
-// export this struct; it's a platform-specific implementation detail.
-type winsize struct {
- row, col, xpixel, ypixel uint16
-}
diff --git a/runtimes/google/ipc/client.go b/runtimes/google/ipc/client.go
index 15d20ef..2121314 100644
--- a/runtimes/google/ipc/client.go
+++ b/runtimes/google/ipc/client.go
@@ -106,8 +106,10 @@
delete(c.vcMap, ep.String())
}
sm := c.streamMgr
+ vcOpts := make([]stream.VCOpt, len(c.vcOpts))
+ copy(vcOpts, c.vcOpts)
c.vcMapMu.Unlock()
- vc, err := sm.Dial(ep, c.vcOpts...)
+ vc, err := sm.Dial(ep, vcOpts...)
c.vcMapMu.Lock()
if err != nil {
return nil, err
diff --git a/security/util.go b/security/util.go
index e7ed33f..ea9df1c 100644
--- a/security/util.go
+++ b/security/util.go
@@ -118,28 +118,6 @@
return json.NewEncoder(w).Encode(acl)
}
-// CaveatValidators returns the set of security.CaveatValidators
-// obtained by decoding the provided caveat bytes.
-//
-// It is an error if any of the provided caveat bytes cannot
-// be decoded into a security.CaveatValidator.
-// TODO(suharshs,ashankar,ataly): Rather than quitting on non-decodable caveats, just skip
-// them and return on caveats that we can decode.
-func CaveatValidators(caveats ...security.Caveat) ([]security.CaveatValidator, error) {
- if len(caveats) == 0 {
- return nil, nil
- }
- validators := make([]security.CaveatValidator, len(caveats))
- for i, c := range caveats {
- var v security.CaveatValidator
- if err := vom.NewDecoder(bytes.NewReader(c.ValidatorVOM)).Decode(&v); err != nil {
- return nil, fmt.Errorf("caveat bytes could not be VOM-decoded: %s", err)
- }
- validators[i] = v
- }
- return validators, nil
-}
-
// ThirdPartyCaveats returns the set of security.ThirdPartyCaveats
// that could be successfully decoded from the provided caveat bytes.
func ThirdPartyCaveats(caveats ...security.Caveat) []security.ThirdPartyCaveat {
diff --git a/security/util_test.go b/security/util_test.go
index daf4fc1..2274a70 100644
--- a/security/util_test.go
+++ b/security/util_test.go
@@ -5,7 +5,6 @@
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
- "fmt"
"reflect"
"testing"
@@ -133,29 +132,14 @@
{C{newCaveat(tp)}, V{tp}, TP{tp}},
{C{newCaveat(fp), newCaveat(tp)}, V{fp, tp}, TP{tp}},
}
- for i, d := range testdata {
- // Test CaveatValidators.
- got, err := CaveatValidators(d.caveats...)
- if err != nil {
- t.Errorf("CaveatValidators(%v) failed: %s", d.caveats, err)
- continue
- }
- if !reflect.DeepEqual(got, d.validators) {
- fmt.Println("TEST ", i)
- t.Errorf("CaveatValidators(%v): got: %#v, want: %#v", d.caveats, got, d.validators)
- continue
- }
- if _, err := CaveatValidators(append(d.caveats, invalid)...); err == nil {
- t.Errorf("CaveatValidators(%v) succeeded unexpectedly", d.caveats)
- continue
- }
+ for _, d := range testdata {
// Test ThirdPartyCaveats.
if got := ThirdPartyCaveats(d.caveats...); !reflect.DeepEqual(got, d.tpCaveats) {
t.Errorf("ThirdPartyCaveats(%v): got: %#v, want: %#v", d.caveats, got, d.tpCaveats)
continue
}
if got := ThirdPartyCaveats(append(d.caveats, invalid)...); !reflect.DeepEqual(got, d.tpCaveats) {
- t.Errorf("ThirdPartyCaveats(%v): got: %#v, want: %#v", d.caveats, got, d.tpCaveats)
+ t.Errorf("ThirdPartyCaveats(%v, invalid): got: %#v, want: %#v", d.caveats, got, d.tpCaveats)
continue
}
}
diff --git a/services/identity/auditor/blessing_auditor.go b/services/identity/auditor/blessing_auditor.go
index b00d28d..998797c 100644
--- a/services/identity/auditor/blessing_auditor.go
+++ b/services/identity/auditor/blessing_auditor.go
@@ -129,21 +129,13 @@
if err = vom.NewDecoder(bytes.NewBuffer(dbentry.caveats)).Decode(&b.Caveats); err != nil {
return BlessingEntry{DecodeError: fmt.Errorf("failed to decode caveats: %s", err)}
}
- if b.RevocationCaveatID, err = revocationCaveatID(b.Caveats); err != nil {
- return BlessingEntry{DecodeError: fmt.Errorf("error getting revocationCaveatID: %s", err)}
- }
+ b.RevocationCaveatID = revocationCaveatID(b.Caveats)
return b
}
-func revocationCaveatID(caveats []security.Caveat) (string, error) {
- validators, err := vsecurity.CaveatValidators(caveats...)
- if err != nil {
- return "", err
+func revocationCaveatID(caveats []security.Caveat) string {
+ for _, tpcav := range vsecurity.ThirdPartyCaveats(caveats...) {
+ return tpcav.ID()
}
- for _, cav := range validators {
- if tpcav, ok := cav.(security.ThirdPartyCaveat); ok {
- return tpcav.ID(), nil
- }
- }
- return "", nil
+ return ""
}
diff --git a/services/mgmt/logreader/impl/logfile.go b/services/mgmt/logreader/impl/logfile.go
index b29f416..fd6f354 100644
--- a/services/mgmt/logreader/impl/logfile.go
+++ b/services/mgmt/logreader/impl/logfile.go
@@ -12,6 +12,7 @@
"strings"
"veyron.io/veyron/veyron2/ipc"
+ "veyron.io/veyron/veyron2/services/mgmt/logreader"
"veyron.io/veyron/veyron2/services/mgmt/logreader/types"
"veyron.io/veyron/veyron2/verror"
"veyron.io/veyron/veyron2/vlog"
@@ -26,7 +27,7 @@
// NewLogFileService returns a new log file server.
func NewLogFileService(root, suffix string) interface{} {
- return &logfileService{filepath.Clean(root), suffix}
+ return logreader.LogFileServer(&logfileService{filepath.Clean(root), suffix})
}
// translateNameToFilename returns the file name that corresponds to the object
@@ -53,7 +54,7 @@
}
// Size returns the size of the log file, in bytes.
-func (i *logfileService) Size(call ipc.ServerCall) (int64, error) {
+func (i *logfileService) Size(ipc.ServerContext) (int64, error) {
vlog.VI(1).Infof("%v.Size()", i.suffix)
fname, err := translateNameToFilename(i.root, i.suffix)
if err != nil {
@@ -74,7 +75,7 @@
}
// ReadLog returns log entries from the log file.
-func (i *logfileService) ReadLog(call ipc.ServerCall, startpos int64, numEntries int32, follow bool) (int64, error) {
+func (i *logfileService) ReadLog(ctx logreader.LogFileReadLogContext, startpos int64, numEntries int32, follow bool) (int64, error) {
vlog.VI(1).Infof("%v.ReadLog(%v, %v, %v)", i.suffix, startpos, numEntries, follow)
fname, err := translateNameToFilename(i.root, i.suffix)
if err != nil {
@@ -87,7 +88,7 @@
}
return 0, errOperationFailed
}
- reader := newFollowReader(call, f, startpos, follow)
+ reader := newFollowReader(ctx, f, startpos, follow)
if numEntries == types.AllEntries {
numEntries = int32(math.MaxInt32)
}
@@ -102,7 +103,7 @@
if err != nil {
return reader.tell(), errOperationFailed
}
- if err := call.Send(types.LogEntry{Position: offset, Line: line}); err != nil {
+ if err := ctx.SendStream().Send(types.LogEntry{Position: offset, Line: line}); err != nil {
return reader.tell(), err
}
}
diff --git a/services/mgmt/logreader/impl/reader.go b/services/mgmt/logreader/impl/reader.go
index 0a063b1..97d1272 100644
--- a/services/mgmt/logreader/impl/reader.go
+++ b/services/mgmt/logreader/impl/reader.go
@@ -14,7 +14,7 @@
// - it aborts when the parent RPC is canceled.
type followReader struct {
reader io.ReadSeeker
- call ipc.ServerCall
+ ctx ipc.ServerContext
offset int64
follow bool
err error
@@ -22,11 +22,11 @@
}
// newFollowReader is the factory for followReader.
-func newFollowReader(call ipc.ServerCall, reader io.ReadSeeker, startpos int64, follow bool) *followReader {
+func newFollowReader(ctx ipc.ServerContext, reader io.ReadSeeker, startpos int64, follow bool) *followReader {
_, err := reader.Seek(startpos, 0)
return &followReader{
reader: reader,
- call: call,
+ ctx: ctx,
offset: startpos,
follow: follow,
err: err,
@@ -43,9 +43,9 @@
return 0, f.err
}
for {
- if f.call != nil {
+ if f.ctx != nil {
select {
- case <-f.call.Done():
+ case <-f.ctx.Done():
return 0, errCanceled
default:
}
diff --git a/services/mgmt/pprof/impl/server.go b/services/mgmt/pprof/impl/server.go
index 8f2f39a..21e300d 100644
--- a/services/mgmt/pprof/impl/server.go
+++ b/services/mgmt/pprof/impl/server.go
@@ -8,12 +8,13 @@
"time"
"veyron.io/veyron/veyron2/ipc"
+ spprof "veyron.io/veyron/veyron2/services/mgmt/pprof"
"veyron.io/veyron/veyron2/verror"
)
// NewPProfService returns a new pprof service implementation.
func NewPProfService() interface{} {
- return &pprofService{}
+ return spprof.PProfServer(&pprofService{})
}
type pprofService struct {
@@ -39,14 +40,12 @@
// addresses that pprof needs. Passing debug=1 adds comments translating
// addresses to function names and line numbers, so that a programmer
// can read the profile without tools.
-//
-// TODO(toddw): Change ipc.ServerCall into a struct stub context.
-func (pprofService) Profile(call ipc.ServerCall, name string, debug int32) error {
+func (pprofService) Profile(ctx spprof.PProfProfileContext, name string, debug int32) error {
profile := pprof.Lookup(name)
if profile == nil {
return verror.NoExistf("profile does not exist")
}
- if err := profile.WriteTo(&streamWriter{call}, int(debug)); err != nil {
+ if err := profile.WriteTo(&streamWriter{ctx.SendStream()}, int(debug)); err != nil {
return verror.Convert(err)
}
return nil
@@ -54,13 +53,11 @@
// CPUProfile enables CPU profiling for the requested duration and
// streams the profile data.
-//
-// TODO(toddw): Change ipc.ServerCall into a struct stub context.
-func (pprofService) CPUProfile(call ipc.ServerCall, seconds int32) error {
+func (pprofService) CPUProfile(ctx spprof.PProfCPUProfileContext, seconds int32) error {
if seconds <= 0 || seconds > 3600 {
return verror.BadArgf("invalid number of seconds: %d", seconds)
}
- if err := pprof.StartCPUProfile(&streamWriter{call}); err != nil {
+ if err := pprof.StartCPUProfile(&streamWriter{ctx.SendStream()}); err != nil {
return verror.Convert(err)
}
time.Sleep(time.Duration(seconds) * time.Second)
@@ -82,11 +79,13 @@
}
type streamWriter struct {
- call ipc.ServerCall
+ sender interface {
+ Send(item []byte) error
+ }
}
func (w *streamWriter) Write(p []byte) (int, error) {
- if err := w.call.Send(p); err != nil {
+ if err := w.sender.Send(p); err != nil {
return 0, err
}
return len(p), nil
diff --git a/services/mgmt/stats/impl/stats.go b/services/mgmt/stats/impl/stats.go
index 1b4b7dc..b398ee8 100644
--- a/services/mgmt/stats/impl/stats.go
+++ b/services/mgmt/stats/impl/stats.go
@@ -5,11 +5,13 @@
import (
"time"
- "veyron.io/veyron/veyron/lib/stats"
+ libstats "veyron.io/veyron/veyron/lib/stats"
"veyron.io/veyron/veyron2/ipc"
"veyron.io/veyron/veyron2/naming"
+ "veyron.io/veyron/veyron2/services/mgmt/stats"
"veyron.io/veyron/veyron2/services/mgmt/stats/types"
+ "veyron.io/veyron/veyron2/services/watch"
watchtypes "veyron.io/veyron/veyron2/services/watch/types"
"veyron.io/veyron/veyron2/vdl/vdlutil"
"veyron.io/veyron/veyron2/verror"
@@ -30,19 +32,19 @@
// NewStatsService returns a stats server implementation. The value of watchFreq
// is used to specify the time between WatchGlob updates.
func NewStatsService(suffix string, watchFreq time.Duration) interface{} {
- return &statsService{suffix, watchFreq}
+ return stats.StatsServer(&statsService{suffix, watchFreq})
}
// Glob returns the name of all objects that match pattern.
-func (i *statsService) Glob(ctx *ipc.GlobContextStub, pattern string) error {
+func (i *statsService) Glob(ctx ipc.GlobContext, pattern string) error {
vlog.VI(1).Infof("%v.Glob(%q)", i.suffix, pattern)
- it := stats.Glob(i.suffix, pattern, time.Time{}, false)
+ it := libstats.Glob(i.suffix, pattern, time.Time{}, false)
for it.Advance() {
ctx.SendStream().Send(naming.VDLMountEntry{Name: it.Value().Key})
}
if err := it.Err(); err != nil {
- if err == stats.ErrNotFound {
+ if err == libstats.ErrNotFound {
return errNotFound
}
return errOperationFailed
@@ -52,7 +54,7 @@
// WatchGlob returns the name and value of the objects that match the request,
// followed by periodic updates when values change.
-func (i *statsService) WatchGlob(call ipc.ServerCall, req watchtypes.GlobRequest) error {
+func (i *statsService) WatchGlob(ctx watch.GlobWatcherWatchGlobContext, req watchtypes.GlobRequest) error {
vlog.VI(1).Infof("%v.WatchGlob(%+v)", i.suffix, req)
var t time.Time
@@ -60,7 +62,7 @@
for {
prevTime := t
t = time.Now()
- it := stats.Glob(i.suffix, req.Pattern, prevTime, true)
+ it := libstats.Glob(i.suffix, req.Pattern, prevTime, true)
changes := []watchtypes.Change{}
for it.Advance() {
v := it.Value()
@@ -72,18 +74,18 @@
changes = append(changes, c)
}
if err := it.Err(); err != nil {
- if err == stats.ErrNotFound {
+ if err == libstats.ErrNotFound {
return errNotFound
}
return errOperationFailed
}
for _, change := range changes {
- if err := call.Send(change); err != nil {
+ if err := ctx.SendStream().Send(change); err != nil {
return err
}
}
select {
- case <-call.Done():
+ case <-ctx.Done():
break Loop
case <-time.After(i.watchFreq):
}
@@ -95,11 +97,11 @@
func (i *statsService) Value(ctx ipc.ServerContext) (vdlutil.Any, error) {
vlog.VI(1).Infof("%v.Value()", i.suffix)
- v, err := stats.Value(i.suffix)
+ v, err := libstats.Value(i.suffix)
switch err {
- case stats.ErrNotFound:
+ case libstats.ErrNotFound:
return nil, errNotFound
- case stats.ErrNoValue:
+ case libstats.ErrNoValue:
return nil, errNoValue
case nil:
return v, nil
diff --git a/services/mgmt/vtrace/impl/vtrace.go b/services/mgmt/vtrace/impl/vtrace.go
index 3f29f26..d389436 100644
--- a/services/mgmt/vtrace/impl/vtrace.go
+++ b/services/mgmt/vtrace/impl/vtrace.go
@@ -2,6 +2,7 @@
import (
"veyron.io/veyron/veyron2/ipc"
+ svtrace "veyron.io/veyron/veyron2/services/mgmt/vtrace"
"veyron.io/veyron/veyron2/uniqueid"
"veyron.io/veyron/veyron2/verror2"
"veyron.io/veyron/veyron2/vtrace"
@@ -19,13 +20,12 @@
return *tr, nil
}
-// TODO(toddw): Change ipc.ServerCall into a struct stub context.
-func (v *vtraceService) AllTraces(call ipc.ServerCall) error {
+func (v *vtraceService) AllTraces(ctx svtrace.StoreAllTracesContext) error {
// TODO(mattr): Consider changing the store to allow us to iterate through traces
// when there are many.
traces := v.store.TraceRecords()
for i := range traces {
- if err := call.Send(traces[i]); err != nil {
+ if err := ctx.SendStream().Send(traces[i]); err != nil {
return err
}
}
@@ -33,5 +33,5 @@
}
func NewVtraceService(store vtrace.Store) interface{} {
- return &vtraceService{store}
+ return svtrace.StoreServer(&vtraceService{store})
}
diff --git a/tools/application/impl.go b/tools/application/impl.go
index 2d06ad5..e37608f 100644
--- a/tools/application/impl.go
+++ b/tools/application/impl.go
@@ -11,9 +11,8 @@
"strings"
"time"
- "veyron.io/veyron/veyron/lib/cmdline"
+ "veyron.io/lib/cmdline"
"veyron.io/veyron/veyron/services/mgmt/repository"
-
"veyron.io/veyron/veyron2/context"
"veyron.io/veyron/veyron2/rt"
"veyron.io/veyron/veyron2/services/mgmt/application"
diff --git a/tools/application/main.go b/tools/application/main.go
index a99a159..9e5d556 100644
--- a/tools/application/main.go
+++ b/tools/application/main.go
@@ -1,11 +1,5 @@
// The following enables go generate to generate the doc.go file.
-// Things to look out for:
-// 1) go:generate evaluates double-quoted strings into a single argument.
-// 2) go:generate performs $NAME expansion, so the bash cmd can't contain '$'.
-// 3) We generate into a *.tmp file first, otherwise go run will pick up the
-// initially empty *.go file, and fail.
-//
-//go:generate bash -c "{ echo -e '// This file was auto-generated via go generate.\n// DO NOT UPDATE MANUALLY\n\n/*' && veyron go run *.go help -style=godoc ... && echo -e '*/\npackage main'; } > ./doc.go.tmp && mv ./doc.go.tmp ./doc.go"
+//go:generate go run $VEYRON_ROOT/lib/cmdline/testdata/gendoc.go .
package main
diff --git a/tools/binary/impl.go b/tools/binary/impl.go
index 1df2314..69f0f51 100644
--- a/tools/binary/impl.go
+++ b/tools/binary/impl.go
@@ -3,7 +3,7 @@
import (
"fmt"
- "veyron.io/veyron/veyron/lib/cmdline"
+ "veyron.io/lib/cmdline"
"veyron.io/veyron/veyron/services/mgmt/lib/binary"
)
diff --git a/tools/binary/main.go b/tools/binary/main.go
index a99a159..9e5d556 100644
--- a/tools/binary/main.go
+++ b/tools/binary/main.go
@@ -1,11 +1,5 @@
// The following enables go generate to generate the doc.go file.
-// Things to look out for:
-// 1) go:generate evaluates double-quoted strings into a single argument.
-// 2) go:generate performs $NAME expansion, so the bash cmd can't contain '$'.
-// 3) We generate into a *.tmp file first, otherwise go run will pick up the
-// initially empty *.go file, and fail.
-//
-//go:generate bash -c "{ echo -e '// This file was auto-generated via go generate.\n// DO NOT UPDATE MANUALLY\n\n/*' && veyron go run *.go help -style=godoc ... && echo -e '*/\npackage main'; } > ./doc.go.tmp && mv ./doc.go.tmp ./doc.go"
+//go:generate go run $VEYRON_ROOT/lib/cmdline/testdata/gendoc.go .
package main
diff --git a/tools/build/impl.go b/tools/build/impl.go
index 1d39669..a4b9b87 100644
--- a/tools/build/impl.go
+++ b/tools/build/impl.go
@@ -10,8 +10,7 @@
"strings"
"time"
- "veyron.io/veyron/veyron/lib/cmdline"
-
+ "veyron.io/lib/cmdline"
"veyron.io/veyron/veyron2/context"
"veyron.io/veyron/veyron2/rt"
vbuild "veyron.io/veyron/veyron2/services/mgmt/build"
diff --git a/tools/build/main.go b/tools/build/main.go
index a99a159..9e5d556 100644
--- a/tools/build/main.go
+++ b/tools/build/main.go
@@ -1,11 +1,5 @@
// The following enables go generate to generate the doc.go file.
-// Things to look out for:
-// 1) go:generate evaluates double-quoted strings into a single argument.
-// 2) go:generate performs $NAME expansion, so the bash cmd can't contain '$'.
-// 3) We generate into a *.tmp file first, otherwise go run will pick up the
-// initially empty *.go file, and fail.
-//
-//go:generate bash -c "{ echo -e '// This file was auto-generated via go generate.\n// DO NOT UPDATE MANUALLY\n\n/*' && veyron go run *.go help -style=godoc ... && echo -e '*/\npackage main'; } > ./doc.go.tmp && mv ./doc.go.tmp ./doc.go"
+//go:generate go run $VEYRON_ROOT/lib/cmdline/testdata/gendoc.go .
package main
diff --git a/tools/debug/impl.go b/tools/debug/impl.go
index 36faee4..f3dc121 100644
--- a/tools/debug/impl.go
+++ b/tools/debug/impl.go
@@ -12,12 +12,11 @@
"sync"
"time"
- "veyron.io/veyron/veyron/lib/cmdline"
+ "veyron.io/lib/cmdline"
"veyron.io/veyron/veyron/lib/glob"
"veyron.io/veyron/veyron/lib/signals"
"veyron.io/veyron/veyron/services/mgmt/pprof/client"
istats "veyron.io/veyron/veyron/services/mgmt/stats"
-
"veyron.io/veyron/veyron2/context"
"veyron.io/veyron/veyron2/naming"
"veyron.io/veyron/veyron2/rt"
diff --git a/tools/debug/main.go b/tools/debug/main.go
index a99a159..9e5d556 100644
--- a/tools/debug/main.go
+++ b/tools/debug/main.go
@@ -1,11 +1,5 @@
// The following enables go generate to generate the doc.go file.
-// Things to look out for:
-// 1) go:generate evaluates double-quoted strings into a single argument.
-// 2) go:generate performs $NAME expansion, so the bash cmd can't contain '$'.
-// 3) We generate into a *.tmp file first, otherwise go run will pick up the
-// initially empty *.go file, and fail.
-//
-//go:generate bash -c "{ echo -e '// This file was auto-generated via go generate.\n// DO NOT UPDATE MANUALLY\n\n/*' && veyron go run *.go help -style=godoc ... && echo -e '*/\npackage main'; } > ./doc.go.tmp && mv ./doc.go.tmp ./doc.go"
+//go:generate go run $VEYRON_ROOT/lib/cmdline/testdata/gendoc.go .
package main
diff --git a/tools/mgmt/nodex/acl_impl.go b/tools/mgmt/nodex/acl_impl.go
index 384d0a7..ca2b0a9 100644
--- a/tools/mgmt/nodex/acl_impl.go
+++ b/tools/mgmt/nodex/acl_impl.go
@@ -6,13 +6,12 @@
"fmt"
"sort"
+ "veyron.io/lib/cmdline"
"veyron.io/veyron/veyron2/rt"
"veyron.io/veyron/veyron2/security"
"veyron.io/veyron/veyron2/services/mgmt/node"
"veyron.io/veyron/veyron2/services/security/access"
"veyron.io/veyron/veyron2/verror"
-
- "veyron.io/veyron/veyron/lib/cmdline"
)
var cmdGet = &cmdline.Command{
diff --git a/tools/mgmt/nodex/associate_impl.go b/tools/mgmt/nodex/associate_impl.go
index a3d2a49..342c35f 100644
--- a/tools/mgmt/nodex/associate_impl.go
+++ b/tools/mgmt/nodex/associate_impl.go
@@ -4,8 +4,7 @@
"fmt"
"time"
- "veyron.io/veyron/veyron/lib/cmdline"
-
+ "veyron.io/lib/cmdline"
"veyron.io/veyron/veyron2/rt"
"veyron.io/veyron/veyron2/services/mgmt/node"
)
diff --git a/tools/mgmt/nodex/impl.go b/tools/mgmt/nodex/impl.go
index e062da2..3507e12 100644
--- a/tools/mgmt/nodex/impl.go
+++ b/tools/mgmt/nodex/impl.go
@@ -3,13 +3,12 @@
import (
"fmt"
+ "veyron.io/lib/cmdline"
"veyron.io/veyron/veyron2/ipc"
"veyron.io/veyron/veyron2/naming"
"veyron.io/veyron/veyron2/rt"
"veyron.io/veyron/veyron2/security"
"veyron.io/veyron/veyron2/services/mgmt/node"
-
- "veyron.io/veyron/veyron/lib/cmdline"
)
var cmdInstall = &cmdline.Command{
diff --git a/tools/mgmt/nodex/instance_impl.go b/tools/mgmt/nodex/instance_impl.go
index 251db6f..f328193 100644
--- a/tools/mgmt/nodex/instance_impl.go
+++ b/tools/mgmt/nodex/instance_impl.go
@@ -5,10 +5,9 @@
import (
"fmt"
+ "veyron.io/lib/cmdline"
"veyron.io/veyron/veyron2/rt"
"veyron.io/veyron/veyron2/services/mgmt/node"
-
- "veyron.io/veyron/veyron/lib/cmdline"
)
var cmdStop = &cmdline.Command{
diff --git a/tools/mgmt/nodex/main.go b/tools/mgmt/nodex/main.go
index b3c5b7b..9e5d556 100644
--- a/tools/mgmt/nodex/main.go
+++ b/tools/mgmt/nodex/main.go
@@ -1,13 +1,5 @@
// The following enables go generate to generate the doc.go file.
-// Things to look out for:
-// 1) go:generate evaluates double-quoted strings into a single argument.
-// 2) go:generate performs $NAME expansion, so the bash cmd can't contain '$'.
-// 3) We generate into a *.tmp file first, otherwise go run will pick up the
-// initially empty *.go file, and fail.
-// TODO(rjkroege): The below fails because _test.go files are present. Fix this.
-// An alternative in Sam/Acme: Edit /\/\*/+1, /\*\//-1 <./nodex help -style'='godoc ...
-//
-//go:generate bash -c "{ echo -e '// This file was auto-generated via go generate.\n// DO NOT UPDATE MANUALLY\n\n/*' && veyron go run *.go help -style=godoc ... && echo -e '*/\npackage main'; } > ./doc.go.tmp && mv ./doc.go.tmp ./doc.go"
+//go:generate go run $VEYRON_ROOT/lib/cmdline/testdata/gendoc.go .
package main
diff --git a/tools/mounttable/impl.go b/tools/mounttable/impl.go
index 99bd958..efa69fc 100644
--- a/tools/mounttable/impl.go
+++ b/tools/mounttable/impl.go
@@ -4,8 +4,7 @@
"fmt"
"time"
- "veyron.io/veyron/veyron/lib/cmdline"
-
+ "veyron.io/lib/cmdline"
"veyron.io/veyron/veyron2/context"
"veyron.io/veyron/veyron2/naming"
"veyron.io/veyron/veyron2/options"
diff --git a/tools/mounttable/main.go b/tools/mounttable/main.go
index a99a159..9e5d556 100644
--- a/tools/mounttable/main.go
+++ b/tools/mounttable/main.go
@@ -1,11 +1,5 @@
// The following enables go generate to generate the doc.go file.
-// Things to look out for:
-// 1) go:generate evaluates double-quoted strings into a single argument.
-// 2) go:generate performs $NAME expansion, so the bash cmd can't contain '$'.
-// 3) We generate into a *.tmp file first, otherwise go run will pick up the
-// initially empty *.go file, and fail.
-//
-//go:generate bash -c "{ echo -e '// This file was auto-generated via go generate.\n// DO NOT UPDATE MANUALLY\n\n/*' && veyron go run *.go help -style=godoc ... && echo -e '*/\npackage main'; } > ./doc.go.tmp && mv ./doc.go.tmp ./doc.go"
+//go:generate go run $VEYRON_ROOT/lib/cmdline/testdata/gendoc.go .
package main
diff --git a/tools/namespace/impl.go b/tools/namespace/impl.go
index 759548d..a1f1f47 100644
--- a/tools/namespace/impl.go
+++ b/tools/namespace/impl.go
@@ -4,7 +4,7 @@
"fmt"
"time"
- "veyron.io/veyron/veyron/lib/cmdline"
+ "veyron.io/lib/cmdline"
"veyron.io/veyron/veyron2/naming"
"veyron.io/veyron/veyron2/rt"
"veyron.io/veyron/veyron2/vlog"
diff --git a/tools/namespace/main.go b/tools/namespace/main.go
index a99a159..9e5d556 100644
--- a/tools/namespace/main.go
+++ b/tools/namespace/main.go
@@ -1,11 +1,5 @@
// The following enables go generate to generate the doc.go file.
-// Things to look out for:
-// 1) go:generate evaluates double-quoted strings into a single argument.
-// 2) go:generate performs $NAME expansion, so the bash cmd can't contain '$'.
-// 3) We generate into a *.tmp file first, otherwise go run will pick up the
-// initially empty *.go file, and fail.
-//
-//go:generate bash -c "{ echo -e '// This file was auto-generated via go generate.\n// DO NOT UPDATE MANUALLY\n\n/*' && veyron go run *.go help -style=godoc ... && echo -e '*/\npackage main'; } > ./doc.go.tmp && mv ./doc.go.tmp ./doc.go"
+//go:generate go run $VEYRON_ROOT/lib/cmdline/testdata/gendoc.go .
package main
diff --git a/tools/principal/main.go b/tools/principal/main.go
index 5112eef..9096bb3 100644
--- a/tools/principal/main.go
+++ b/tools/principal/main.go
@@ -12,17 +12,16 @@
"os/user"
"time"
+ "veyron.io/lib/cmdline"
+ profile "veyron.io/veyron/veyron/profiles/static"
+ vsecurity "veyron.io/veyron/veyron/security"
+ "veyron.io/veyron/veyron/services/identity"
"veyron.io/veyron/veyron2"
"veyron.io/veyron/veyron2/ipc"
"veyron.io/veyron/veyron2/naming"
"veyron.io/veyron/veyron2/rt"
"veyron.io/veyron/veyron2/security"
"veyron.io/veyron/veyron2/vom"
-
- "veyron.io/veyron/veyron/lib/cmdline"
- profile "veyron.io/veyron/veyron/profiles/static"
- vsecurity "veyron.io/veyron/veyron/security"
- "veyron.io/veyron/veyron/services/identity"
)
var (
diff --git a/tools/profile/impl.go b/tools/profile/impl.go
index 2216a60..459b2ab 100644
--- a/tools/profile/impl.go
+++ b/tools/profile/impl.go
@@ -4,10 +4,9 @@
"fmt"
"time"
- "veyron.io/veyron/veyron/lib/cmdline"
+ "veyron.io/lib/cmdline"
"veyron.io/veyron/veyron/services/mgmt/profile"
"veyron.io/veyron/veyron/services/mgmt/repository"
-
"veyron.io/veyron/veyron2/rt"
"veyron.io/veyron/veyron2/services/mgmt/build"
)
diff --git a/tools/profile/main.go b/tools/profile/main.go
index a99a159..9e5d556 100644
--- a/tools/profile/main.go
+++ b/tools/profile/main.go
@@ -1,11 +1,5 @@
// The following enables go generate to generate the doc.go file.
-// Things to look out for:
-// 1) go:generate evaluates double-quoted strings into a single argument.
-// 2) go:generate performs $NAME expansion, so the bash cmd can't contain '$'.
-// 3) We generate into a *.tmp file first, otherwise go run will pick up the
-// initially empty *.go file, and fail.
-//
-//go:generate bash -c "{ echo -e '// This file was auto-generated via go generate.\n// DO NOT UPDATE MANUALLY\n\n/*' && veyron go run *.go help -style=godoc ... && echo -e '*/\npackage main'; } > ./doc.go.tmp && mv ./doc.go.tmp ./doc.go"
+//go:generate go run $VEYRON_ROOT/lib/cmdline/testdata/gendoc.go .
package main
diff --git a/tools/vrpc/impl.go b/tools/vrpc/impl.go
index 8891515..7d0e560 100644
--- a/tools/vrpc/impl.go
+++ b/tools/vrpc/impl.go
@@ -6,9 +6,9 @@
"io"
"time"
- "veyron.io/veyron/veyron/lib/cmdline"
+ "veyron.io/lib/cmdline"
+ _ "veyron.io/veyron/veyron/profiles/static"
idl_test_base "veyron.io/veyron/veyron/tools/vrpc/test_base"
-
"veyron.io/veyron/veyron2"
"veyron.io/veyron/veyron2/context"
"veyron.io/veyron/veyron2/ipc"
diff --git a/tools/vrpc/impl_test.go b/tools/vrpc/impl_test.go
index 49e94e1..f585f2b 100644
--- a/tools/vrpc/impl_test.go
+++ b/tools/vrpc/impl_test.go
@@ -6,15 +6,14 @@
"strings"
"testing"
+ "veyron.io/lib/cmdline"
+ "veyron.io/veyron/veyron/profiles"
+ "veyron.io/veyron/veyron/tools/vrpc/test_base"
"veyron.io/veyron/veyron2"
"veyron.io/veyron/veyron2/ipc"
"veyron.io/veyron/veyron2/naming"
"veyron.io/veyron/veyron2/rt"
"veyron.io/veyron/veyron2/vlog"
-
- "veyron.io/veyron/veyron/lib/cmdline"
- "veyron.io/veyron/veyron/profiles"
- "veyron.io/veyron/veyron/tools/vrpc/test_base"
)
type server struct{}
diff --git a/tools/vrpc/main.go b/tools/vrpc/main.go
index 3c2043c..f52ab6f 100644
--- a/tools/vrpc/main.go
+++ b/tools/vrpc/main.go
@@ -1,11 +1,5 @@
// The following enables go generate to generate the doc.go file.
-// Things to look out for:
-// 1) go:generate evaluates double-quoted strings into a single argument.
-// 2) go:generate performs $NAME expansion, so the bash cmd can't contain '$'.
-// 3) We generate into a *.tmp file first, otherwise go run will pick up the
-// initially empty *.go file, and fail.
-//
-//go:generate bash -c "{ echo -e '// This file was auto-generated via go generate.\n// DO NOT UPDATE MANUALLY\n\n/*' && veyron go run *.go help -style=godoc ... && echo -e '*/\npackage main'; } > ./doc.go.tmp && mv ./doc.go.tmp ./doc.go"
+//go:generate go run $VEYRON_ROOT/lib/cmdline/testdata/gendoc.go .
package main