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

June 25, 2014

この記事はQiitaの記事をエクスポートしたものです。内容が古くなっている可能性があります。

codegangsta/cli

コンソールアプリを作るのに便利なライブラリ。 簡単に、オプションやサブコマンドを扱える。

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

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

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

cli.AppBeforeというフィールドがあり、サブコマンドを実行する前に実行できる関数を設定できる。 また、exec.LookPathを使えば、PATHの通った実行可能ファイルの絶対パスを探すことができる。 この2つを使って、サブコマンドが実行される前に、プログラミング引数の2番目の値を実行可能ファイルとして探し出し、Beforeでその外部コマンドを実行するような、cli.Commandを作成して、Appにサブコマンドとして登録してやればよい。

  • http://golang.org/pkg/os/exec/#LookPath

    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)
    }
    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