Documentation
¶
Overview ¶
Package bonzai provides a rooted node tree of commands and singular parameters making tab completion a breeze and complicated applications much easier to intuit without reading all the docs. Documentation is embedded with each command removing the need for separate man pages and such and can be viewed as text or a locally served web page.
Rooted Node Tree ¶
Commands and parameters are linked to create a rooted node tree of the following types of nodes:
- Leaves with a method and optional parameters
- Branches with leaves, other branches, and a optional method
- Parameters, single words that are passed to a leaf command
Index ¶
- Variables
- func ArgsFrom(line string) []string
- func ArgsOrIn(args []string) string
- func AutoUpdate(version, versurl, binurl, sumurl string)
- func CompareUpdated(current int, remoteURL string) int
- func CompareVersions(current, remoteURL string) int
- func Exec(args ...string) error
- func Exit()
- func ExitError(err ...interface{})
- func ExitOff()
- func ExitOn()
- func ReplaceSelf(url, checksum string) error
- func Run(args ...string) error
- type Cmd
- func (x *Cmd) Add(name string, aliases ...string) *Cmd
- func (x *Cmd) Branch() string
- func (x *Cmd) Cmd(name string) *Cmd
- func (x *Cmd) CmdNames() []string
- func (x *Cmd) GetCaller() comp.Command
- func (x *Cmd) GetCommands() []string
- func (x *Cmd) GetCompleter() comp.Completer
- func (x *Cmd) GetHidden() []string
- func (x *Cmd) GetName() string
- func (x *Cmd) GetOther() map[string]string
- func (x *Cmd) GetParams() []string
- func (x *Cmd) IsHidden(name string) bool
- func (x *Cmd) MissingConfig(path string) error
- func (x *Cmd) Param(p string) string
- func (x *Cmd) Q(q string) string
- func (x *Cmd) Run()
- func (x *Cmd) Seek(args []string) (*Cmd, []string)
- func (x *Cmd) Unimplemented() error
- func (x *Cmd) UsageError() error
- type Method
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var Aliases = make(map[string][]string)
Aliases allows Bonzai tree developers to create aliases (similar to shell aliases) that are directly translated into arguments to the Bonzai tree executable by overriding the os.Args in a controlled way. The value of an alias is always a slice of strings that will replace the os.Args[2:]. A slice is used (instead of a string parsed with strings.Fields) to ensure that hard-coded arguments containing whitespace are properly handled.
var DefaultConfigurer = new(config.Configurer)
DefaultConfigurer is assigned to the Cmd.Root.Config during Cmd.Run. It is conventional for only Cmd.Root to have a Configurer defined.
var DoNotExit bool
DoNotExit effectively disables Exit and ExitError allowing the program to continue running, usually for test evaluation.
var ExeName string
ExeName holds just the base name of the executable without any suffix (ex: .exe) and is set at init() time (see ExePath).
var ExePath string
ExePath holds the full path to the current running process executable which is determined at init() time by calling os.Executable and passing it to path/filepath.EvalSymlinks to ensure it is the actual binary executable file. Errors are reported to stderr, but there should never be an error logged unless something is wrong with the Go runtime environment.
Functions ¶
func ArgsFrom ¶
ArgsFrom returns a list of field strings split on space with an extra trailing special space item appended if the line has any trailing spaces at all signifying a definite word boundary and not a potential prefix.
Example ¶
package main
import (
"fmt"
"github.com/rwxrob/bonzai"
)
func main() {
fmt.Printf("%q\n", bonzai.ArgsFrom(`greet hi french`))
fmt.Printf("%q\n", bonzai.ArgsFrom(`greet hi french `))
}
Output: ["greet" "hi" "french"] ["greet" "hi" "french" ""]
func ArgsOrIn ¶ added in v0.0.29
ArgsOrIn takes an slice or nil as argument and if the slice has any length greater than 0 returns all the argument joined together with a single space between them. Otherwise, will read standard input until end of file reached (Cntl-D).
Example (Args_Joined) ¶
package main
import (
"fmt"
"github.com/rwxrob/bonzai"
)
func main() {
fmt.Println(bonzai.ArgsOrIn([]string{"some", "thing"}))
}
Output: some thing
Example (Read_Nil) ¶
package main
import (
"fmt"
"os"
"github.com/rwxrob/bonzai"
)
func main() {
orig := os.Stdin
defer func() { os.Stdin = orig }()
os.Stdin, _ = os.Open(`testdata/in`)
fmt.Println(bonzai.ArgsOrIn(nil))
}
Output: some thing
Example (Read_Zero_Args) ¶
package main
import (
"fmt"
"os"
"github.com/rwxrob/bonzai"
)
func main() {
orig := os.Stdin
defer func() { os.Stdin = orig }()
os.Stdin, _ = os.Open(`testdata/in`)
fmt.Println(bonzai.ArgsOrIn([]string{}))
}
Output: some thing
func AutoUpdate ¶ added in v0.0.19
func AutoUpdate(version, versurl, binurl, sumurl string)
AutoUpdate automatically updates the current process executable version by starting a goroutine that checks the current semantic version (version) against a remote one (versurl) and calling ReplaceSelf with the URL of the binary (binurl) and checksum (sumurl) if and update is needed. Note that the binary will often be named quite differently than the name of the currently running executable (ex: foo-mac -> foo, foo-linux.
If a URL to a checksum file (sumurl) is not empty will optionally validate the new version downloaded against the checksum before replacing the currently running process executable with the new one. The format of the checksum file is the same as that output by any of the major checksum commands (sha512sum, for example) with one or more lines beginning with the checksum, whitespace, and then the name of the file. A single checksum file can be used for multiple versions but the most recent should always be at the top. When the update completes a message notifying of the update is logged to stderr.
The function will fail silently under any of the following conditions:
- current user does not have write access to executable
- unable to establish a network connection
- checksum provided does not match
Since AutoUpdate happens in the background no return value is provided. To enable logging of the update process (presumably for debugging) add the AutoUpdate flag to the Trace flags (trace.Flags|=trace.AutoUpdate). Also see Cmd.AutoUpdate.
func CompareUpdated ¶ added in v0.0.21
CompareUpdated compares the current isosec integer (second at GMT) to that retrieved from the URL (usually pointing to a file called UPDATED) which must return nothing but a single isosec integer (which is unmarshaled as a JSON number). Returns 1 if current is more recent, 0 if they are equal, -1 if current is older, and -2 if unable to determine (which will also log any error encountered).
Example ¶
package main
import (
"fmt"
"net/http"
ht "net/http/httptest"
"github.com/rwxrob/bonzai"
)
func main() {
handler := http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, `20220322080540`)
})
older := ht.NewServer(handler)
defer older.Close()
handler = http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, `20220322080546`)
})
newer := ht.NewServer(handler)
defer newer.Close()
handler = http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, `20220322080542`)
})
same := ht.NewServer(handler)
defer same.Close()
fmt.Println(bonzai.CompareUpdated(20220322080542, older.URL))
fmt.Println(bonzai.CompareUpdated(20220322080542, newer.URL))
fmt.Println(bonzai.CompareUpdated(20220322080542, same.URL))
fmt.Println(bonzai.CompareUpdated(20220322080542, "foobar"))
}
Output: -1 1 0 -2
func CompareVersions ¶ added in v0.0.21
CompareVersions compares the current semantic version string to that retrieved from the URL (usually pointing to a file called VERSION) which must return nothing but a single semantic version. Like semver.Compare returns 0 if they are the same, 1 if current is more recent, -1 if current is behind remote, and -2 if unable to retrieve the remote semver string (in which case an error is also logged).
Example ¶
package main
import (
"fmt"
"net/http"
ht "net/http/httptest"
"github.com/rwxrob/bonzai"
)
func main() {
handler := http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, `"v0.0.1"`)
})
older := ht.NewServer(handler)
defer older.Close()
handler = http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, `"v0.1.0"`)
})
newer := ht.NewServer(handler)
defer newer.Close()
handler = http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, `"v0.0.2"`)
})
same := ht.NewServer(handler)
defer same.Close()
fmt.Println(bonzai.CompareVersions(`v0.0.2`, older.URL))
fmt.Println(bonzai.CompareVersions(`v0.0.2`, newer.URL))
fmt.Println(bonzai.CompareVersions(`v0.0.2`, same.URL))
fmt.Println(bonzai.CompareVersions(`v0.0.2`, "foobar"))
}
Output: 1 -1 0 -2
func Exec ¶ added in v0.0.21
Exec (not to be confused with Execute) will check for the existence of the first argument as an executable on the system and then execute it using syscall.Exec(), which replaces the currently running program with the new one in all respects (stdin, stdout, stderr, process ID, signal handling, etc).
Note that although this is exceptionally faster and cleaner than calling any of the os/exec variations it may be less compatible with different operating systems.
func Exit ¶
func Exit()
Exit calls os.Exit(0) unless DoNotExit has been set to true. Cmds should never call Exit themselves returning a nil error from their Methods instead.
func ExitError ¶
func ExitError(err ...interface{})
ExitError prints err and exits with 1 return value unless DoNotExit has been set to true. Commands should usually never call ExitError themselves returning an error from their Method instead.
func ReplaceSelf ¶ added in v0.0.19
ReplaceSelf replaces the current running executable at its current location with the successfully retrieved file at the specified URL or file path and duplicates the original files permissions. Only http and https URLs are currently supported. If not empty, a checksum file will be fetched from sumurl and used to validate the download before making the replacement. For security reasons, no backup copy of the replaced executable is kept. Also see AutoUpdate.
func Run ¶ added in v0.0.21
Run checks for existence of first argument as an executable on the system and then runs it without exiting in a way that is supported across different operating systems. The stdin, stdout, and stderr are connected directly to that of the calling program. Use more specific exec alternatives if intercepting stdout and stderr are desired. Also see Exec.
Types ¶
type Cmd ¶
type Cmd struct {
Name string `json:"name,omitempty"`
Aliases []string `json:"aliases,omitempty"`
Summary string `json:"summary,omitempty"`
Usage string `json:"usage,omitempty"`
Version string `json:"version,omitempty"`
Updated int `json:"updated,omitempty"` // isosec
Copyright string `json:"copyright,omitempty"`
License string `json:"license,omitempty"`
Description string `json:"description,omitempty"`
Site string `json:"site,omitempty"`
Source string `json:"source,omitempty"`
Issues string `json:"issues,omitempty"`
Other map[string]string `json:"issues,omitempty"`
Commands []*Cmd `json:"commands,omitempty"`
Params []string `json:"params,omitempty"`
Hidden []string `json:"hide,omitempty"`
Completer comp.Completer `json:"-"`
Conf conf.Configurer `json:"-"`
Root *Cmd `json:"-"`
Caller *Cmd `json:"-"`
Call Method `json:"-"`
MinArgs int `json:"-"`
// contains filtered or unexported fields
}
func (*Cmd) Add ¶
Add creates a new Cmd and sets the name and aliases and adds to Commands returning a reference to the new Cmd. The name must be first.
func (*Cmd) Branch ¶ added in v0.0.26
Branch returns the dotted path to this command location within the parent tree. This is useful for associating configuration and other data specifically with this command. The branch path is determined by walking backward from current Caller up rather than depending on anything from the command line used to invoke the composing binary.
Example ¶
package main
import (
"fmt"
"os"
"github.com/rwxrob/bonzai"
)
func main() {
bonzai.ExitOff()
z := new(bonzai.Cmd)
c := z.Add("some")
//fmt.Print(z.Commands[0].Name)
c = c.Add("thing")
//fmt.Print(z.Commands[0].Commands[0].Name)
c = c.Add("deep")
//fmt.Print(z.Commands[0].Commands[0].Commands[0].Name)
c.Call = func(x *bonzai.Cmd, _ ...string) error {
fmt.Println(x.Branch())
return nil
}
defer func() { args := os.Args; os.Args = args }()
os.Args = []string{"z", "some", "thing", "deep"}
z.Run()
}
Output: some.thing.deep
func (*Cmd) CmdNames ¶
Example ¶
package main
import (
"fmt"
"github.com/rwxrob/bonzai"
)
func main() {
foo := new(bonzai.Cmd)
foo.Add("bar")
foo.Add("blah")
foo.Add("other")
fmt.Println(foo.CmdNames())
}
Output: [bar blah other]
func (*Cmd) GetCommands ¶
GetCommands fulfills the comp.Command interface.
Example ¶
package main
import (
"fmt"
"github.com/rwxrob/bonzai"
)
func main() {
foo := new(bonzai.Cmd)
foo.Add("bar")
foo.Add("blah")
foo.Add("other")
fmt.Println(foo.GetCommands())
}
Output: [bar blah other]
func (*Cmd) GetCompleter ¶
GetCompleter fulfills the Command interface.
func (*Cmd) GetParams ¶
GetParams fulfills the comp.Command interface.
Example ¶
package main
import (
"fmt"
"github.com/rwxrob/bonzai"
)
func main() {
foo := new(bonzai.Cmd)
foo.Params = []string{"box", "bing", "and"}
fmt.Println(foo.GetParams())
}
Output: [box bing and]
func (*Cmd) IsHidden ¶
IsHidden returns true if the specified name is in the list of Hidden commands.
func (*Cmd) MissingConfig ¶ added in v0.0.29
MissingConfig returns an error showing the expected configuration entry that is missing from the given path.
func (*Cmd) Q ¶ added in v0.0.28
Q is a shorter version of x.Conf.Query(x.Root.Name,x.Branch()+"."+q) for convenience.
func (*Cmd) Run ¶
func (x *Cmd) Run()
Run is for running a command within a specific runtime (shell) and performs completion if completion context is detected. Otherwise, it executes the leaf Cmd returned from Seek calling its Method, and then Exits. Normally, Run is called from within main() to convert the Cmd into an actual executable program and normally it exits the program. Exiting can be controlled, however, with ExitOn/ExitOff when testing or for other purposes requiring multiple Run calls. Using Call instead will also just call the Cmd's Call Method without exiting. Note: Only bash runtime ("COMP_LINE") is currently supported, but others such a zsh and shell-less REPLs are planned.
func (*Cmd) Seek ¶
Example ¶
package main
import (
"fmt"
"github.com/rwxrob/bonzai"
"github.com/rwxrob/bonzai/inc/help"
)
func main() {
hello := &bonzai.Cmd{
Name: `hello`,
Params: []string{"there"},
Call: func(_ *bonzai.Cmd, args ...string) error {
if len(args) > 0 {
fmt.Printf("hello %v\n", args[0])
return nil
}
fmt.Println("hello")
return nil
},
}
hi := &bonzai.Cmd{
Name: `hi`,
Params: []string{"there", "ya"},
Call: func(_ *bonzai.Cmd, args ...string) error {
if len(args) > 0 {
fmt.Printf("hi %v\n", args[0])
return nil
}
fmt.Println("hi")
return nil
},
}
yo := &bonzai.Cmd{
Name: `yo`,
Call: func(x *bonzai.Cmd, args ...string) error {
fmt.Println("yo")
return nil
},
}
salut := &bonzai.Cmd{
Name: `salut`,
Params: []string{"la"},
Call: func(_ *bonzai.Cmd, args ...string) error {
if len(args) > 0 {
fmt.Printf("salut %v\n", args[0])
return nil
}
fmt.Println("salut")
return nil
},
}
french := &bonzai.Cmd{
Name: `french`,
Aliases: []string{"fr"},
Commands: []*bonzai.Cmd{help.Cmd, salut},
}
greet := &bonzai.Cmd{
Name: `greet`,
Commands: []*bonzai.Cmd{help.Cmd, yo, hi, hello, french},
}
cmd, args := greet.Seek(bonzai.ArgsFrom(`hi there`))
fmt.Printf("%v %q\n", cmd.Name, args)
cmd, args = greet.Seek(bonzai.ArgsFrom(`french salut`))
fmt.Printf("%v %q\n", cmd.Name, args)
cmd, args = greet.Seek(bonzai.ArgsFrom(`french salut `))
fmt.Printf("%v %q\n", cmd.Name, args)
cmd, args = greet.Seek(bonzai.ArgsFrom(`french h`))
fmt.Printf("%v %q\n", cmd.Name, args)
cmd, args = greet.Seek(bonzai.ArgsFrom(`french help`))
fmt.Printf("%v %q\n", cmd.Name, args)
}
Output: hi ["there"] salut [] salut [""] french ["h"] help []
func (*Cmd) Unimplemented ¶ added in v0.0.24
Unimplemented returns an error with a single-line usage string.
func (*Cmd) UsageError ¶ added in v0.0.7
UsageError returns an error with a single-line usage string.
type Method ¶
Method defines the main code to execute for a command (Cmd). By convention the parameter list should be named "args" if there are args expected and underscore (_) if not. Methods must never write error output to anything but standard error and should almost always use the log package to do so.
Directories
¶
| Path | Synopsis |
|---|---|
|
anim
module
|
|
|
choose
module
|
|
|
cmds
|
|
|
help
module
|
|
|
kimono
module
|
|
|
rayfish
module
|
|
|
sunrise
module
|
|
|
vars
module
|
|
|
completers/git
module
|
|
|
completers/git/examples/tags
module
|
|
|
depends
module
|
|
|
ds
module
|
|
|
dtime
module
|
|
|
edit
module
|
|
|
fn
module
|
|
|
tr
module
|
|
|
futil
module
|
|
|
github
module
|
|
|
Package inc contains a predefined set of popular commands that some may choose to include/compose into their Bonzai command trees.
|
Package inc contains a predefined set of popular commands that some may choose to include/compose into their Bonzai command trees. |
|
is
module
|
|
|
json
module
|
|
|
funcs
module
|
|
|
renderers/less
module
|
|
|
renderers/man
module
|
|
|
renderers/plain
module
|
|
|
viewers/less
module
|
|
|
old
|
|
|
is
Package z (often imported as "is") defines the Bonzai Parsing Expression Grammar Notation (BPEGN) (aka "Bonzai Scanner Expect" language) implemented entirely using Go types (mostly slices and structs).
|
Package z (often imported as "is") defines the Bonzai Parsing Expression Grammar Notation (BPEGN) (aka "Bonzai Scanner Expect" language) implemented entirely using Go types (mostly slices and structs). |
|
opts
module
|
|
|
persisters
module
|
|
|
injson
module
|
|
|
inmem
module
|
|
|
inprops
module
|
|
|
inyaml
module
|
|
|
pkg
|
|
|
cmd/bon
module
|
|
|
cmd/clip
module
|
|
|
cmd/var
module
|
|
|
run
module
|
|
|
scanner
module
|
|
|
term
module
|
|
|
test
|
|
|
multicall
module
|
|
|
tinout
module
|
|
|
to
module
|
|
|
Package trace provides a tracing framework for use by Bonzai applications.
|
Package trace provides a tracing framework for use by Bonzai applications. |
|
uniq
module
|
|
|
vars
module
|
|
|
web
module
|
|
|
yaml
module
|
|
|
yq
module
|
|
|
yt
module
|