個人的にGoはミドルウェアやコマンドラインツールの開発によく利用していますが、その理由の一つにシングルバイナリなのでデプロイが楽、というのがあります。一方で、(特に)サーバ系のミドルウェアだとちょっとしたWeb UIを付けたくなることがあります。こうなると、シングルバイナリのほかにHTMLやCSS、JavaScriptといったリソースファイルが多数付いてくるのでちょっと面倒です。
そこでgo-bindataを使って実行バイナリにそれらのリソースファイルをくっつけてしまうという方法があります。go-bindataは各リソースファイルの内容をGoのコードとして生成し、**Asset()**という関数を呼び出すことで内容を取得することができます。
go-bindataによるコード生成
まずは、go-bindataをインストールします。
go get -u github.com/jteeuwen/go-bindata/...
続いて今回の題材であるslackboardをgit cloneします。
git clone https://github.com/cubicdaiya/slackboard.git
slackboardはSlackのIncoming Webhooksを利用したプロキシサーバです。↓に実際の活用例についての資料があります。
で、大したことはありませんが、slackboardにはboostrapを利用した至極簡単なWeb UI機能があります。ソースコードのレイアウトはこんな感じです。
$ tree slackboard
slackboard/ui
├── css
│ ├── bootstrap.css
│ ├── bootstrap.css.map
│ ├── bootstrap.min.css
│ ├── bootstrap-theme.css
│ ├── bootstrap-theme.css.map
│ └── bootstrap-theme.min.css
├── fonts
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.svg
│ ├── glyphicons-halflings-regular.ttf
│ └── glyphicons-halflings-regular.woff
├── index.html
└── js
├── bootstrap.js
├── bootstrap.min.js
├── jquery-1.11.2.min.js
└── npm.js
このディレクトリに対してgo-bindataを実行するとbindata.goというファイルが生成されます。-pkg
にはパッケージ名を指定します。
go-bindata -pkg slackboard ./ui/*
生成されたbindata.goの先頭部分には取り込まれたリソースファイルの一覧がコメントで書き出されます。
// Code generated by go-bindata.
// sources:
// ui/css/bootstrap-theme.css
// ui/css/bootstrap-theme.css.map
// ui/css/bootstrap-theme.min.css
// ui/css/bootstrap.css
// ui/css/bootstrap.css.map
// ui/css/bootstrap.min.css
// ui/fonts/glyphicons-halflings-regular.eot
// ui/fonts/glyphicons-halflings-regular.svg
// ui/fonts/glyphicons-halflings-regular.ttf
// ui/fonts/glyphicons-halflings-regular.woff
// ui/index.html
// ui/js/bootstrap.js
// ui/js/bootstrap.min.js
// ui/js/jquery-1.11.2.min.js
// ui/js/npm.js
// DO NOT EDIT!
package slackboard
go-bindataで生成したGoのコードからリソースの内容を取得する
bindata.goにはAsset()という関数が定義されており、これを利用することでリソースの内容を取得できます。以下はui/index.htmlの内容を取得する例です。
// バイト配列(リソースの内容)とエラーを返す
bs, err := Asset("ui/index.html")
先頭のスラッシュが不要なので、HTTPサーバのURIを通して参照するようなケースではsliceで先頭のスラッシュを切り取ってリソースを取得しましょう。
p := r.URL.Path
bs, err := Asset(p[1:])
slackboardでgo-bindataを導入してみて
元々slackboardのWeb UI機能を利用するにはリソースファイルの配置するのと設定ファイル by TOMLにUIのドキュメントルートを設定する必要がありました。
# Web UIのドキュメントルート
[ui]
root = "/usr/local/share/slackboard"
今はgo-bindataでリソースファイルを実行バイナリにバンドルするようになっているので不要になっています。これでシングルバイナリの世界が実現できました。めでたしめでたし。
ちなみに、slackboardにgo-bindataを導入したのは今年の秋にみんなのGo言語【現場で使える実践テクニック】でgo-bindataの実例が紹介されていたのを読んだのがきっかけだったります。