Description
Apologies if this has been asked or answered before.
I've worked extensively with cobra for creating cli interfaces. One sort of creative approach I've taken on occasion is to re-invoke a program (on linux) with different arguments / flags using os.Args[0]
. For example:
import("github.com/bitfield/script")
...
conf, _ := script.Exec(os.Args[0] + " cli config gen -ynN --nofetch").String()
_, err := script.Exec(os.Args[0] + " visor -a '" + conf + "'").Stdout()
This allows accessing subcommands from the code in what I consider to be a highly convenient way.
However, in the context of a mobile / android application, using ...Exec(os.Args[0]...
does not work.
(in case you are wondering, the error is gojni executable not found in PATH
)
I know that it's possible to do this from the code itself, however I note certain anomalies in attempting to figure out how to do so:
package main
import (
"fmt"
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{Use: "app", Short: "A simple command-line app"}
var greeting string
var greetCmd = &cobra.Command{
Use: "greet",
Short: "Prints a greeting message",
Run: func(cmd *cobra.Command, args []string) {
name, _ := cmd.Flags().GetString("name")
fmt.Printf("Hello, %s!\n", name)
},
}
func init() {
greetCmd.Flags().StringVarP(&greeting, "name", "n", "World", "Specify the name to greet")
rootCmd.AddCommand(greetCmd)
}
func main() {
if err := greetCmd.Execute(); err != nil {
fmt.Println(err)
return
}
}
Now, I would suppose that this program would output as though the greetCmd was run, but this is not the case. It simply prints the main help menu
$ go run main.go
A simple command-line app
Usage:
app [command]
Available Commands:
completion Generate the autocompletion script for the specified shell
greet Prints a greeting message
help Help about any command
Flags:
-h, --help help for app
Use "app [command] --help" for more information about a command.
perhaps I can just reassign rootCmd to greetCmd like this?:
func init() {
greetCmd.Flags().StringVarP(&greeting, "name", "n", "World", "Specify the name to greet")
rootCmd.AddCommand(greetCmd)
rootCmd = greetCmd
}
or even rootCmd = &cobra.Command{}
But that changes nothing..
However, when I don't add greetCmd to rootCmd, it works more or less as intended:
func init() {
greetCmd.Flags().StringVarP(&greeting, "name", "n", "World", "Specify the name to greet")
//rootCmd.AddCommand(greetCmd)
//rootCmd = greetCmd
}
func main() {
if err := greetCmd.Execute(); err != nil {
fmt.Println(err)
return
}
}
output
$ go run main.go
Hello, World!
I would think that doing this
rootCmd.AddCommand(greetCmd)
rootCmd = &cobra.Command{}
should effectively reset the rootCmd; however, this isn't the case.
So this presents a challenge in that it's not possible to undo rootCmd.AddCommand()
once it's been done, unless there is something I'm missing?
As far as I can tell, by default the command which is not a child of another command but has children of it's own is the one which is invoked.
Is it possible to remove its children?
The larger issue
It's possible to compile a golang application into an .apk for android using gomobile
. In order to port an existing application to android which uses cobra, basically the mobile ui can be included as a subcommand of the existing application. And the golang mobile libraries will still work on desktop, so the UI can be tested without an emulator or anything.
But on android, the subcommand containing the mobile UI needs to be more or less the default invocation of the application, because it's not possible to specify any subcommands or flags to the application when it's launched as an android app from an installed .apk.
For the program in question, I need basically to invoke two subcommands, preferably with flags, from the existing code. I hope it's possible to do this without selectively changing the command structure itself depending on operating system. It should be possible to override anything, but it looks more and more like the only alternative is to detect os as android and change the command structure from there. Such a change would present real challenges to testing and may not prove viable.