この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
よく訓練されたアップル信者、都元です。最近社内のメンバーがみんなGo言語の世界で楽しそうなので、私も混ざってみることにしました。最初のセットアップや基礎文法等は、私も平行して急いで学ぶGo langシリーズで勉強中です。
コマンドラインツールが作りたい
と思っています。ちょっとしたものを作るとしたらPythonなのかな、と思って友達のPythonistaにインタビューをしたところ、「ちょっとしたツール作るとかって用途の人は Golangに移行した(えっ」という衝撃的なコメントを貰い、もうこの際だからGo勉強すっかという空気になった次第。
具体的な環境構築
基本的には急いで学ぶGo langシリーズを読めばいいのですが、一点迷ったのがディレクトリ構成です。
Go言語で幸せになれる10のテクニックでは「GOPATHは一つだけ (Use a single GOPATH)」という指針が紹介されています。当初はこの通りで行こうと考えたのですが、IDE(IntelliJ IDEA)と組み合わせる構成を考えた際に矛盾が発生してしまいました。
- GOPATHは一つだけ。(指針)
- 1つの環境で、複数の独立したプロジェクトを並行開発したい。(直近ではやらないしろ、当然出来るようにはしておきたい。)
- そしてもちろん、プロジェクト単位でgitリポジトリを構成したい。(要求)
- git管理の対象となるルート・ディレクトリは$GOPATHではなく、$GOPATH/src/github.com/(username)/(repository)である。(慣例)
- IDEAは(Eclipseと違って)Workspaceという考え方がなく、プロジェクト単位でウィンドウを開く。(仕様)
- IDEAのGo language support pluginでは、GOPATHをプロジェクトとして扱う。(仕様)
といった感じで、もうプロジェクト毎にGOPATH作ってしまったほうが良い、という判断をしました。間違ってるかもしれませんが。ひとまず判断。
というわけで、作業ディレクトリとしてプロジェクト(ここではusername/foobar)を作り、その直下はこのような構成にすることにしました。
.
├── .idea
├── bin
├── pkg
└── src
├── github.com
│ ├── username
│ │ └── foobar
│ │ ├── .git
│ │ ├── .gitignore
│ │ ├── LICENSE
│ │ ├── README.md
│ │ └── *.go
│ └── (other-dependencies)
└── (other-dependencies)
GitHubで新規プロジェクトを作り、.gitignoreやLICENSE等を作ってもらいましょう。
その上でGitHub上のリソースをcloneします。
$ cd $GOPATH/src/github.com/username
$ git clone git@github.com:username/foobar.git
cli-init
cli-initというツールがあります。詳しくは作者さんの高速にGo言語のCLIツールをつくるcli-initというツールをつくったをご覧いただければ分かりますが、この手順に則って、プロジェクトのスケルトンを作ってみます。
まずcli-initのインストール
$ cd $GOPATH
$ go get -d github.com/tcnksm/cli-init
$ cd $GOPATH/src/github.com/tcnksm/cli-init
$ make install
$ cd $GOPATH
$ cli-init --version
cli-init v0.1.0
以上です。ちなみにこのツールはグローバルにインストールされる訳ではなく、実行ファイルは$GOPATH/bin/cli-initに入ります。
スケルトンの作成
$ cd $GOPATH/src/github.com/username
$ mv foobar foobar-tmp
$ cli-init -s foo,bar,baz,qux foobar
$ mv foobar/* foobar-tmp/
$ rmdir foobar
$ mv foobar-tmp foobar
GitHubに作ってもらった.gitignore等を活かすために、少々ゴニョゴニョしてますが、主要なコマンドは3行目だけです。ちなみに既存ディレクトリにcli-initを実行してしまうと、下記のような確認の上で、中身を綺麗さっぱり消されてしまいます。
foobar is already exists, overwrite it? [Y/n]: Y
ビルドとインストール
任意のディレクトリで下記コマンドを実行することで、カレントディレクトリにfoobar実行ファイルが生成されます。
$ go build github.com/username/foobar
$ ./foobar
NAME:
foobar -
USAGE:
foobar [global options] command [command options] [arguments...]
VERSION:
0.1.0
AUTHOR:
Daisuke Miyamoto - <miyamoto.daisuke@example.com>
COMMANDS:
foo
bar
baz
qux
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--help, -h show help
--version, -v print the version
流行りの(?)メイン+サブコマンド形式のCLI実行ファイルが出来ました。
本格的にインストールする場合は下記コマンド。これは$GOPATH/bin/foobarが生成されます。
$ go install github.com/username/foobar
ソースコード
さて、cli-initが生成してくれたコードをざっと見ていきましょう。まずはfoobar.goを見てみます。このスケルトンではgithub.com/codegangsta/cliというパッケージライブラリを使っています。CLIコマンドを作るためのフレームワークですね。ヘルプに表示するための情報を諸々設定しているのが分かります。
package main
import (
"os"
"github.com/codegangsta/cli"
)
func main() {
app := cli.NewApp()
app.Name = "foobar"
app.Version = Version
app.Usage = ""
app.Author = "Daisuke Miyamoto"
app.Email = "miyamoto.daisuke@example.com"
app.Commands = Commands
app.Run(os.Args)
}
各コマンドの実装はcommands.goに有ります。複雑なものであれば、コマンド毎にファイル分割するのもいいですね。
package main
import (
"log"
"os"
"github.com/codegangsta/cli"
)
var Commands = []cli.Command{
commandFoo,
commandBar,
commandBaz,
commandQux,
}
var commandFoo = cli.Command{
Name: "foo",
Usage: "",
Description: `
`,
Action: doFoo,
}
var commandBar = cli.Command{
Name: "bar",
Usage: "",
Description: `
`,
Action: doBar,
}
var commandBaz = cli.Command{
Name: "baz",
Usage: "",
Description: `
`,
Action: doBaz,
}
var commandQux = cli.Command{
Name: "qux",
Usage: "",
Description: `
`,
Action: doQux,
}
func debug(v ...interface{}) {
if os.Getenv("DEBUG") != "" {
log.Println(v...)
}
}
func assert(err error) {
if err != nil {
log.Fatal(err)
}
}
func doFoo(c *cli.Context) {
}
func doBar(c *cli.Context) {
}
func doBaz(c *cli.Context) {
}
func doQux(c *cli.Context) {
}
まとめ
というわけで、Goを使ってコマンドラインツールがさらっと書けるようになりました。近々何か作ってみたいと思います。