GoでCLIツールを作ってinstallする
GoでCLIを自作してinstallするまでの一連の流れを紹介します。
ツールを作る
例えば、次のようなecho
コマンドと同じような動作をするmyecho
を作成します。
package main import ( "flag" "fmt" ) func main() { flag.Parse() args := flag.Args() cmd := "" for _, arg := range args { cmd += arg + " " } fmt.Println(cmd) }
この時点では次のように実して動作を確認できます。
$ go run *go hoge fuga hoge fuga
インストールする
modulesを設定しておきます。
例えばmyecho
というツール名にしたい場合は、次のようにmodulesを設定します。
ここで設定した名前がツールを使うときに呼び出すコマンドになります。
(modulesを設定していない場合、main.goが置かれているディレクトリ名がツール名になるようです)
$ go mod init myecho
次のコマンドでビルド&インストールします。
GOPATH
を設定している場合は$GOPATH/bin
、設定していない場合は$HOME/go/bin
がインストール先になります。
$ go install
実行する
以下のように実行できれば成功です。
$ myecho hoge fuga hoge fuga
次のようにエラーが出る場合はPATHが通っていない可能性があるので、PATHを通す必要があります。
bash: myecho: command not found
$HOME/go/bin
にPATHを通す場合は、~/.bash_profile
にPATH=$PATH:$HOME/go/bin
のように記載することでPATHを通します。
記入後、次のようにコマンドを実行して設定を有効にします。
$ source ~/.bash_profile
mapの値を更新したい場合
Goでmapの値を更新したい場合
次のようにmapへ直接更新することはできない
type Sample struct { state bool } var samples = map[string]Sample{ "hoge": {true}, "fuga": {false}, } fmt.Println(samples["hoge"].state) // getはできる samples["hoge"].state = false // setはできない
https://play.golang.org/p/8ZobtXRtw86
次のように更新した値でmapの内容を書き換える必要がある。
type Sample struct { state bool } var samples = map[string]Sample{ "hoge": {true}, "fuga": {false}, } s := samples["hoge"] s.state = false samples["hoge"] = s // 更新したもので置き換える fmt.Println(samples)
コマンドラインにオプションを付ける
自作のコマンドラインツールで、オプションon/offで動作を変えたい。
flag
packageを使う。
次のように-opt
を付けるだけで動作を変えたい場合はboolを使うことになる。
mytool -opt
func main() { opt := flag.Bool("opt", false, "オプションの説明") // デフォルト値=falseに設定する例 flag.Parse() if opt { // opt設定時の処理 } else { // opt未設定時の処理 } }
コマンドラインでディレクトリを受け取る
自作のコマンドラインツールでディレクトリを受け取って、
絶対パス、相対パスどちらも同じように扱いたい。
そんな場合はfilepath.Abs
を使って絶対パスに置き換えてしまうのが良さそう。
filepath.Abs
は絶対パスを渡しても問題なく動作する。
path1, _ := filepath.Abs("./sample") fmt.Println(apath) path2, _ := filepath.Abs("/usr/local/bin") fmt.Println(upath)
なので、こんな感じで使うことになる。
func main() { dir := flag.String("d", "", "ディレクトリ") flag.Parse() path := filepath.Abs(dir) fmt.Println(path) }
DockerHubで自分が付けたスターのリストを表示する
タイトル通りの内容です。
自分がスターを付けたコンテナの表示方法がわからなかったので探しました。
まずタイトルバー部分の自分のアカウントをクリックします。
表示されたページのStarredがスターを付けたリストです。
ginでHTTP RequestのPathParameterを受け取る
Path Parameterの後ろに階層がある場合
次のようなAPIを定義する
GET /user/:name/profile GET /uesr/:name/history
これをginで実装する方法は公式ページにも紹介されている。
r.GET("/user/:name/*action", func(c *gin.Context) { name := c.Param("name") action := c.Param("action") message := name + " is " + action c.String(http.StatusOK, message) })
もちろん単純に1つずつ実装しても動作する。
r.GET("/user/:name/profile", func(c *gin.Context) { name := c.Param("name") message := name + " profile" c.String(http.StatusOK, message) }) r.GET("/user/:name/history", func(c *gin.Context) { name := c.Param("name") message := name + " history" c.String(http.StatusOK, message) })
間に1つ以上の階層が挟まる場合
上で紹介したAPIの:name
とaction
の間にgroup
という階層を挟んだ例。
GET /user/:name/group/profile GET /user/:name/group/history
これも同じ内容で実装できる。もちろん単純に1つずつ実装しても動作する。
r.GET("/user/:name/group/*action", func(c *gin.Context) { name := c.Param("name") action := c.Param("action") message := name + " is " + action c.String(http.StatusOK, message) })
または、次のコードでも動作はできる。
ただし、この場合はaction = /group/profile
のようにパスが渡される。
r.GET("/user/:name/*action", func(c *gin.Context) { name := c.Param("name") action := c.Param("action") message := name + " is " + action c.String(http.StatusOK, message) })
HTTP Requestのパラメータ
HTTP Requestのパラメータは以下の3種類がある。
- パスパラメータ
- クエリパラメータ
- リクエストボディパラメータ
パスパラメータ(Path Parameter)
単一のパラメータ
基本的な書き方は次の通り
設計書
/item/{pathparameter} /item/:pathparameter
呼び出し方法
http://example.com/item/1
複数のパラメータ
複数のパスパラメータを含むこともできる
設計書
/item/{group}/user/{level} /item/:group/user/:level
呼び出し方法
http://example.com/item/1/user/10
Go Ginでの実装方法
r := gin.Default() r.GET("/item/:pathparameter", func(c *gin.Context) { key := c.Param("pathparameter") fmt.Println(key) })
クエリパラメータ(Query Parameter)
単一のパラメータ
設計書
/item{?queryparameter}
呼び出し方法
http://example.com/item?queryparameter=1
複数のパラメータ
設計書
/item{?group, level}
呼び出し方法
http://example.com/item?group=1&level=10
Go Ginでの実装方法
r := gin.Default() r.GET("/item", func(c *gin.Context) { key := c.Query("queryparameter") fmt.Println(key) })
リクエストボディパラメータ
設計書
Parameters
やRequest
に書かれているもの。
json形式で表現されることが多い。
呼び出し方法
bodyに設定する必要がある。
ここでは curlでの呼び出しを例として挙げる。
curl -X POST -H "Content-Type: application/json" -d '{"Name":"bluemon", "Age":"35"}' 'http://example.com/item'
Go Ginでの実装方法
r := gin.Default() r.POST("/item", func(c *gin.Context) { buf := make([]byte, 1024) n, _ := c.Request.Body.Read(buf) fmt.Println(string(buf[0:n])) })