Edited at

[Go言語]codegangsta/cliで、サブコマンドとして外部コマンドをとれるようにしてみた

More than 5 years have passed since last update.


codegangsta/cli

コンソールアプリを作るのに便利なライブラリ。

簡単に、オプションやサブコマンドを扱える。


サブコマンドとして外部コマンドをとる

gitコマンドのようにPATHの通っているところにgit-xxxxみたいな実行可能ファイルがあると、git xxxxみたいに、あたかもgitコマンドのサブコマンドとして扱える。

codegangsta/cliを使って同じようなことをしたい。

cli.AppBeforeというフィールドがあり、サブコマンドを実行する前に実行できる関数を設定できる。

また、exec.LookPathを使えば、PATHの通った実行可能ファイルの絶対パスを探すことができる。

この2つを使って、サブコマンドが実行される前に、プログラミング引数の2番目の値を実行可能ファイルとして探し出し、Beforeでその外部コマンドを実行するような、cli.Commandを作成して、Appにサブコマンドとして登録してやればよい。


main.go

package main

import (
"github.com/codegangsta/cli"
"os"
"os/exec"
"strings"
)

func main() {
app := cli.NewApp()
app.Before = func(c *cli.Context) error {
args := c.Args()
if len(args) <= 0 {
return nil
}

subcommand := args.First()
for _, c := range app.Commands {
if c.HasName(subcommand) {
return nil
}
}

path, err := exec.LookPath(app.Name + "-" + subcommand)
if err != nil {
return err
}

app.Commands = append(app.Commands, cli.Command{
Name: subcommand,
Action: func(c *cli.Context) {
cmd := exec.Command(path, strings.Join(os.Args[2:], " "))
cmd.Stdout = os.Stdout
cmd.Stdin = os.Stdin
cmd.Stderr = os.Stderr
cmd.Run()
},
})

return nil
}
app.Run(os.Args)
}



sub.go

package main

import (
"fmt"
"github.com/codegangsta/cli"
"os"
)

func main() {
app := cli.NewApp()
app.Action = func(c *cli.Context) {
args := c.Args()
if len(args) <= 0 {
fmt.Println("no params")
return
}

fmt.Println(args.First())
}
app.Run(os.Args)
}


main.goはメインとなるプログラムで以下の様にビルドするとする。

% go build -o main main.go

sub.goはサブコマンドとして呼び出すコマンドで、以下の様にビルドするとする。

% go build -o main-sub sub.go

このようにすると、以下のようにsub.goから作った実行可能ファイルを、mainのサブコマンドとして実行できる。

% ./main sub hogehoge

hogehoge