Help us understand the problem. What is going on with this article?

golang のサブコマンドで GetWild

More than 3 years have passed since last update.

この記事は GetWild Advent Calendar 2016 - Qiita の12日目の記事です。

~ get wild and tough ~ と言われたらもちろんシティーハンターですね。今回、記事を書くにあたって、AAを探しましたが、シティーハンターのあまりネタとしては使いにくいAAしかなくて「ぐぬぬ…」となりました…


「Get wild 禁断症状」とは

業務中にGETWILD分が切れて禁断症状がでそうになった際に必死に耐えるための方法論~#ghq ないし go getで頑張る

go get もしくは ghq get もGETWILDするチャンスかもしれません。出来る時にしておかないと頭の中をエンドレスでGETWILDが流れ、ゾーン状態はどこへやら、いつの間にか1日が終わってしまうかもしれません :scream:

なるほどなるほど。 go get という文脈にカスタマイズされた Get wild が効果を発揮すればいいんですね。わかります。

無いならば 作ってしまおう ゲッワイルド

go getwild コマンド

単純に github.com/kaneshin/getwild のようなリポジトリを作って getwild コマンドを作ればいいと思うんですが、それだと何も面白くないので、今回はあまりやらないことをやろうと思います。

go のサブコマンド

golang を使っている人はわかると思いますが、go コマンドには複数の(サブ)コマンドが存在しています。

$ go help
Go is a tool for managing Go source code.

Usage:

        go command [arguments]

The commands are:

        build       compile packages and dependencies
        clean       remove object files
        doc         show documentation for package or symbol
        env         print Go environment information
        fix         run go tool fix on packages
        fmt         run gofmt on package sources
        generate    generate Go files by processing source
        get         download and install packages and dependencies
        install     compile and install packages and dependencies
        list        list packages
        run         compile and run Go program
        test        test packages
        tool        run specified go tool
        version     print Go version
        vet         run go tool vet on packages

Use "go help [command]" for more information about a command.

今回のターゲットとして、ここに getwild を追加することを目標とします。

go/src/cmd/go

go コマンドのカスタマイズ方法ですが、とても簡単です。まず、適当にファイルを用意します。今回は getwild.go を用意しています。

go/src/cmd/go/getwild.go

$ cd go/src/cmd/go
$ vim getwild.go

実装

package main

import (
    "fmt"
    "os"
)

var cmdGetWild = &Command{
    UsageLine: "getwild [-tough]",
    Short:     "get wild and tough",
    Long: `
Print just the 'get wild'.

The -tough flag prints more message we want.
    `,
}

var getTough = cmdGetWild.Flag.Bool("tough", false, "")

func init() {
    addBuildFlags(cmdGetWild)
    cmdGetWild.Run = runGetWild // break init loop
}

func runGetWild(cmd *Command, args []string) {
    fmt.Fprint(os.Stdout, textGet, textWild)
    args = append([]string{"-f", "-u"}, args...)
    if *getTough {
        args = append([]string{"-t"}, args...)
        fmt.Fprint(os.Stdout, textAnd, textTough)
    }

    cmdGet.Flag.Parse(args)
    args = cmdGet.Flag.Args()
    cmdGet.Run(cmdGet, args)
}

const (
    textGet = `
 ________  _______  _________
|\   ____\|\  ___ \|\___   ___\
\ \  \___|\ \   __/\|___ \  \_|
 \ \  \  __\ \  \_|/__  \ \  \
  \ \  \|\  \ \  \_|\ \  \ \  \
   \ \_______\ \_______\  \ \__\
    \|_______|\|_______|   \|__|
`

    textWild = `
 ___       __   ___  ___       ________
|\  \     |\  \|\  \|\  \     |\   ___ \
\ \  \    \ \  \ \  \ \  \    \ \  \_|\ \
 \ \  \  __\ \  \ \  \ \  \    \ \  \ \\ \
  \ \  \|\__\_\  \ \  \ \  \____\ \  \_\\ \
   \ \____________\ \__\ \_______\ \_______\
    \|____________|\|__|\|_______|\|_______|
`

    textAnd = `
 ________  ________   ________
|\   __  \|\   ___  \|\   ___ \
\ \  \|\  \ \  \\ \  \ \  \_|\ \
 \ \   __  \ \  \\ \  \ \  \ \\ \
  \ \  \ \  \ \  \\ \  \ \  \_\\ \
   \ \__\ \__\ \__\\ \__\ \_______\
    \|__|\|__|\|__| \|__|\|_______|
`

    textTough = `
 _________  ________  ___  ___  ________  ___  ___
|\___   ___\\   __  \|\  \|\  \|\   ____\|\  \|\  \
\|___ \  \_\ \  \|\  \ \  \\\  \ \  \___|\ \  \\\  \
     \ \  \ \ \  \\\  \ \  \\\  \ \  \  __\ \   __  \
      \ \  \ \ \  \\\  \ \  \\\  \ \  \|\  \ \  \ \  \
       \ \__\ \ \_______\ \_______\ \_______\ \__\ \__\
        \|__|  \|_______|\|_______|\|_______|\|__|\|__|
`
)

Commandの用意

var cmdGetWild = &Command{
    UsageLine: "getwild [-tough]",
    Short:     "get wild and tough",
    Long: `
Print just the 'get wild'.

The -tough flag prints more message we want.
    `,
}

このように、cmd/go 内に定義されている Command 構造体をコマンド用に定義しておきます。

そして、このコマンドにフラグ(オプション)を定義することも可能です。

var getTough = cmdGetWild.Flag.Bool("tough", false, "")

ここまで実装したらおまじないのように init() で初期化を行っておきます。

func init() {
    addBuildFlags(cmdGetWild)
    cmdGetWild.Run = runGetWild
}

実行されるのは runGetWild 関数で、下記のように定義しています。

func runGetWild(cmd *Command, args []string) {
    fmt.Fprint(os.Stdout, textGet, textWild)
    args = append([]string{"-f", "-u"}, args...)
    if *getTough {
        args = append([]string{"-t"}, args...)
        fmt.Fprint(os.Stdout, textAnd, textTough)
    }

    cmdGet.Flag.Parse(args)
    args = cmdGet.Flag.Args()
    cmdGet.Run(cmdGet, args)
}

特定の文字列を出現させて、そのあとは go get -f -u と同じ効果で go get を行うようにしています。

go/src/cmd/go/main.go

main.goのコマンドのリストに定義したコマンドを設定します。

// Commands lists the available commands and help topics.
// The order here is the order in which they are printed by 'go help'.
var commands = []*Command{
        cmdBuild,
        cmdClean,
        cmdDoc,
        cmdEnv,
        cmdFix,
        cmdFmt,
        cmdGenerate,
        cmdGet,
        cmdGetWild,  // <= New!!
        cmdInstall,
        cmdList,
        cmdRun,
        cmdTest,
        cmdTool,
        cmdVersion,
        cmdVet,

        helpC,
        helpBuildmode,
        helpFileType,
        helpGopath,
        helpEnvironment,
        helpImportPath,
        helpPackages,
        helpTestflag,
        helpTestfunc,
}

コンパイル

人によって環境が違うと思いますが、下記のようにコンパイルします。

$ cd go/src
$ GOROOT_BOOTSTRAP=~/go1.7.4 ./make.bash 

このようにコンパイルすることによって、 go/bin に成果物が出力されます。

go getwild の実行

$ cd go/bin
$ ./go help
Go is a tool for managing Go source code.

Usage:

    go command [arguments]

The commands are:

    build       compile packages and dependencies
    clean       remove object files
    doc         show documentation for package or symbol
    env         print Go environment information
    fix         run go tool fix on packages
    fmt         run gofmt on package sources
    generate    generate Go files by processing source
    get         download and install packages and dependencies
    getwild     get wild and tough
    install     compile and install packages and dependencies
    list        list packages
    run         compile and run Go program
    test        test packages
    tool        run specified go tool
    version     print Go version
    vet         run go tool vet on packages

Use "go help [command]" for more information about a command.
$ cd go/bin
$ ./go getwild help
usage: getwild [-tough]

Print just the 'get wild'.

The -tough flag prints more message we want.

出力

-tough と -v オプションを付けて github.com/kaneshin/gate/cmd/gatecli をインストールします。

$ ./go getwild -tough -v github.com/kaneshin/gate/cmd/gatecli

 ________  _______  _________
|\   ____\|\  ___ \|\___   ___\
\ \  \___|\ \   __/\|___ \  \_|
 \ \  \  __\ \  \_|/__  \ \  \
  \ \  \|\  \ \  \_|\ \  \ \  \
   \ \_______\ \_______\  \ \__\
    \|_______|\|_______|   \|__|

 ___       __   ___  ___       ________
|\  \     |\  \|\  \|\  \     |\   ___ \
\ \  \    \ \  \ \  \ \  \    \ \  \_|\ \
 \ \  \  __\ \  \ \  \ \  \    \ \  \ \\ \
  \ \  \|\__\_\  \ \  \ \  \____\ \  \_\\ \
   \ \____________\ \__\ \_______\ \_______\
    \|____________|\|__|\|_______|\|_______|

 ________  ________   ________
|\   __  \|\   ___  \|\   ___ \
\ \  \|\  \ \  \\ \  \ \  \_|\ \
 \ \   __  \ \  \\ \  \ \  \ \\ \
  \ \  \ \  \ \  \\ \  \ \  \_\\ \
   \ \__\ \__\ \__\\ \__\ \_______\
    \|__|\|__|\|__| \|__|\|_______|

 _________  ________  ___  ___  ________  ___  ___
|\___   ___\\   __  \|\  \|\  \|\   ____\|\  \|\  \
\|___ \  \_\ \  \|\  \ \  \\\  \ \  \___|\ \  \\\  \
     \ \  \ \ \  \\\  \ \  \\\  \ \  \  __\ \   __  \
      \ \  \ \ \  \\\  \ \  \\\  \ \  \|\  \ \  \ \  \
       \ \__\ \ \_______\ \_______\ \_______\ \__\ \__\
        \|__|  \|_______|\|_______|\|_______|\|__|\|__|
github.com/kaneshin/gate (download)
github.com/BurntSushi/toml (download)

このように、GET WILD AND TOUGH を出力したうえで go get -v を行います。

おわりに

go のコマンド自身は golang で書かれているのでカスタマイズは比較的簡単に行うことができるので、自身でカスタマイズしちゃいましょう!

kaneshin
I'm the CTO at Eureka. I relish building things with Go, C, PHP, Bash and so on. I have substantial experience in cloud solutions which are GCP and AWS. I also have a strong mathematics experience.
https://kaneshin.co
eure
オンラインデーティングサービス「Pairs」の運営・開発をしている企業。様々なモダンな技術を駆使してビジネスを成長させています。
https://eure.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away