Use a single wrapper binary for all command line tools

This is because Go has a multi megabyte overhead for its binaries
This commit is contained in:
Kovid Goyal 2022-08-15 08:16:00 +05:30
parent abaafc2d68
commit aaf0dea8dc
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
5 changed files with 60 additions and 36 deletions

2
go.mod
View File

@ -15,5 +15,5 @@ require (
github.com/mattn/go-colorable v0.1.9 // indirect github.com/mattn/go-colorable v0.1.9 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect github.com/mattn/go-isatty v0.0.14 // indirect
github.com/rivo/uniseg v0.2.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 // indirect golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
) )

3
go.sum
View File

@ -21,8 +21,7 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJ
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=

View File

@ -88,16 +88,8 @@ var yellow_fmt = color.New(color.FgYellow).SprintFunc()
var blue_fmt = color.New(color.FgBlue).SprintFunc() var blue_fmt = color.New(color.FgBlue).SprintFunc()
var green_fmt = color.New(color.FgGreen).SprintFunc() var green_fmt = color.New(color.FgGreen).SprintFunc()
func cmd_name(cmd *cobra.Command) string {
if cmd.Annotations != nil {
parts := strings.Split(cmd.Annotations["exe"], " ")
return parts[len(parts)-1]
}
return cmd.Name()
}
func print_created_by(root *cobra.Command) { func print_created_by(root *cobra.Command) {
fmt.Println(italic_fmt(root.Annotations["exe"]), opt_fmt(root.Version), "created by", title_fmt("Kovid Goyal")) fmt.Println(italic_fmt(root.Name()), opt_fmt(root.Version), "created by", title_fmt("Kovid Goyal"))
} }
func print_line_with_indent(text string, indent string, screen_width int) { func print_line_with_indent(text string, indent string, screen_width int) {
@ -238,7 +230,17 @@ func show_usage(cmd *cobra.Command) error {
if tty_size_err == nil && ws.Cols < 80 { if tty_size_err == nil && ws.Cols < 80 {
screen_width = int(ws.Cols) screen_width = int(ws.Cols)
} }
fmt.Println(title_fmt("Usage")+":", exe_fmt(cmd.Annotations["exe"]), cmd.Use) use := cmd.Use
idx := strings.Index(use, " ")
if idx > -1 {
use = use[idx + 1:]
}
var parent_names []string
cmd.VisitParents(func(p *cobra.Command) {
parent_names = append(parent_names, p.Name())
})
parent_names = append(parent_names, cmd.Name())
fmt.Println(title_fmt("Usage")+":", exe_fmt(strings.Join(parent_names, " ")), use)
fmt.Println() fmt.Println()
if len(cmd.Long) > 0 { if len(cmd.Long) > 0 {
print_with_indent(cmd.Long, "", screen_width) print_with_indent(cmd.Long, "", screen_width)
@ -249,12 +251,12 @@ func show_usage(cmd *cobra.Command) error {
fmt.Println() fmt.Println()
fmt.Println(title_fmt("Commands") + ":") fmt.Println(title_fmt("Commands") + ":")
for _, child := range cmd.Commands() { for _, child := range cmd.Commands() {
fmt.Println(" ", opt_fmt(cmd_name(child))) fmt.Println(" ", opt_fmt(child.Name()))
print_with_indent(child.Short, " ", screen_width) print_with_indent(child.Short, " ", screen_width)
} }
fmt.Println() fmt.Println()
print_with_indent("Get help for an individual command by running:", "", screen_width) print_with_indent("Get help for an individual command by running:", "", screen_width)
fmt.Println(" ", cmd.Annotations["exe"], italic_fmt("command"), "-h") fmt.Println(" ", cmd.Name(), italic_fmt("command"), "-h")
} }
if cmd.HasAvailableFlags() { if cmd.HasAvailableFlags() {
options_title := cmd.Annotations["options_title"] options_title := cmd.Annotations["options_title"]
@ -272,7 +274,9 @@ func show_usage(cmd *cobra.Command) error {
defval := "" defval := ""
switch flag.Value.Type() { switch flag.Value.Type() {
default: default:
defval = fmt.Sprintf("[=%s]", italic_fmt(flag.DefValue)) if (flag.DefValue != "") {
defval = fmt.Sprintf("[=%s]", italic_fmt(flag.DefValue))
}
case "bool": case "bool":
case "count": case "count":
} }
@ -285,7 +289,7 @@ func show_usage(cmd *cobra.Command) error {
case "help": case "help":
msg = "Print this help message" msg = "Print this help message"
case "version": case "version":
msg = "Print the version of " + RootCmd.Annotations["exe"] + ": " + italic_fmt(RootCmd.Version) msg = "Print the version of " + RootCmd.Name() + ": " + italic_fmt(RootCmd.Version)
} }
print_with_indent(msg, " ", screen_width) print_with_indent(msg, " ", screen_width)
if cmd.Annotations["choices-"+flag.Name] != "" { if cmd.Annotations["choices-"+flag.Name] != "" {
@ -307,12 +311,20 @@ func show_usage(cmd *cobra.Command) error {
return nil return nil
} }
func CreateCommand(cmd *cobra.Command, exe string) *cobra.Command { func CreateCommand(cmd *cobra.Command) *cobra.Command {
cmd.Annotations = make(map[string]string) cmd.Annotations = make(map[string]string)
cmd.Annotations["exe"] = exe if cmd.Run == nil {
cmd.Run = SubCommandRequired
}
return cmd return cmd
} }
func SubCommandRequired(cmd *cobra.Command, args []string) {
cmd.Usage()
fmt.Fprintln(os.Stderr, color.RedString("\nNo command specified for "+cmd.Name()))
os.Exit(1)
}
func Init(root *cobra.Command) { func Init(root *cobra.Command) {
RootCmd = root RootCmd = root
root.Version = kitty.VersionString root.Version = kitty.VersionString

View File

@ -1,10 +1,7 @@
package main package at
import ( import (
"fmt"
"os"
"github.com/fatih/color"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"kitty/tools/cli" "kitty/tools/cli"
@ -12,18 +9,13 @@ import (
) )
var encrypt_cmd = crypto.Encrypt_cmd var encrypt_cmd = crypto.Encrypt_cmd
var exe_name = "kitty-at"
func main() { func EntryPoint(tool_root *cobra.Command) *cobra.Command {
var root = cli.CreateCommand(&cobra.Command{ var root = cli.CreateCommand(&cobra.Command{
Use: "[global options] command [command options] [command args]", Use: "@ [global options] command [command options] [command args]",
Short: "Control kitty remotely", Short: "Control kitty remotely",
Long: "Control kitty by sending it commands. Set the allow_remote_control option in kitty.conf or use a password, for this to work.", Long: "Control kitty by sending it commands. Set the allow_remote_control option in kitty.conf or use a password, for this to work.",
Run: func(cmd *cobra.Command, args []string) { })
cmd.Usage()
fmt.Fprintln(os.Stderr, color.RedString("\nNo command specified for "+exe_name))
},
}, exe_name)
root.Annotations["options_title"] = "Global options" root.Annotations["options_title"] = "Global options"
root.PersistentFlags().String("password", "", root.PersistentFlags().String("password", "",
@ -32,9 +24,5 @@ func main() {
" accepted before or is pre-configured in :file:`kitty.conf`.") " accepted before or is pre-configured in :file:`kitty.conf`.")
cli.PersistentChoices(root, "use-password", "If no password is available, kitty will usually just send the remote control command without a password. This option can be used to force it to always or never use the supplied password.", "if-available", "always", "never") cli.PersistentChoices(root, "use-password", "If no password is available, kitty will usually just send the remote control command without a password. This option can be used to force it to always or never use the supplied password.", "if-available", "always", "never")
cli.Init(root) return root
if err := root.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
} }

25
tools/cmd/main.go Normal file
View File

@ -0,0 +1,25 @@
package main
import (
"fmt"
"os"
"github.com/spf13/cobra"
"kitty/tools/cli"
"kitty/tools/cmd/at"
)
func main() {
var root = cli.CreateCommand(&cobra.Command{
Use: "kitty-tool command [command options] [command args]",
Short: "Fast, statically compiled implementations for various kitty command-line tools",
})
root.AddCommand(at.EntryPoint(root))
cli.Init(root)
if err := root.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}