Edited at

Golangで実装するCUIコマンド

More than 3 years have passed since last update.

最近、RDB(Mysql)を操作するバッチ処理を実装することが多く、お勉強がてらgolangを使い始めました。

やることはいつも


  • パラメーター判断

  • トランザクション制御

  • ログ出力

こんな感じなので、

golangの動作確認を兼ねて、コマンドアプリのひな型になりそうなサンプルを作りました。

package main

import (
"flag"
"fmt"
"time"
"os"
)

const VERSION = `0.0.1`

type ErrMessage struct {
What string
}
func (e ErrMessage) Error() string {
return fmt.Sprintf("%v: %v", time.Now(), e.What)
}

var (
version = flag.Bool("V", false, "display version information")
failure = flag.Bool("failure", false, "失敗させます")
)

func DoSomething(str string) (err error) {
defer func() {
// panicがおきたらRollback
if e := recover(); e != nil {
fmt.Fprintf(os.Stderr, "Rollback!!\n")
// エラーメッセージフォーマット変換
x, _ := e.(string)
err = ErrMessage{x}
}
}()

if *failure {
// Error発生
panic("DoSomething error...")
}

fmt.Fprintf(os.Stdout, "%s\n", str)
return nil
}

func main() {
flag.Parse()
if *version {
fmt.Printf("dosomething %s\n", VERSION)
os.Exit(0)
}

str := "do something & commit!!"
err := DoSomething(str)
if err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err)
os.Exit(1)
}

str = "and finish!!"
fmt.Fprintf(os.Stdout, "%s\n", str)
}

パラメーターの実装は、flagを使えば楽ですね。

トランザクション制御について、

異常時のRollBackを実行するには、deferとrecover()を使えば良さそうです。

どのような動きになるのか、パラメーターで動作を分けて試してみました。

また、

ログ出力時、メッセージフォーマットを自作するサンプルがあったので、採用してみました。

正常時のログはStdoutへ、異常時はStderrへ出力したいですから、そのあたりも実装してます。

fmt.Fprintf() に標準出力(os.Stdout)、標準エラー(os.Stderr)のファイルディスクリプタを渡します。

さて、実行してみましょう。

実行時パラメータ無しで、正常終了します。

$ (コマンド) 2>./stderr.log 1>./stdout.log

などとやれば、stderr.log には、何も出力されず、

stdout.log にログが出力されます。

failureパラメータをつけると、異常時の動作を確認できます。

(実際にはこんなパラメータは要らないですが...)

$ (コマンド) --failure 2>./stderr.log 1>./stdout.log

stderr.log で、deferに指定した処理が実行されたことがわかります。

stdout.logには出力されません。

何か異常があれば、すぐにpanic()を起こしてrollbackしてしまいましょう。