go.rice の使い方を調査した
Awesome Go から見繕って go.rice を使ってみることにした。
感想
「こう使いたい」という気持ちと go.rice の作法にずれがあって少しとまどった
失敗例
初期値では モジュールのルートディレクトリからの相対パス ではなく、FindBox や MustFindBox を呼び出しているコードが含まれるパッケージからの相対パス になる。
README を流し読みして失敗したけど、実装を読んだらなるほどそういうことかと感心させられた。
ソースコードと失敗する様子
$ find . -type f ./example.exe ./go.mod ./go.sum ./main.go ./pkg/example/example.go ./template/hello.tmpl
// ./main.go package main import ( "log" "gist.github.com/yujiorama/gorice-invalid/pkg/example" ) func main() { log.Println(example.A()) } // ./pkg/example/example.go package example import ( "fmt" "strings" "text/template" rice "github.com/GeertJohan/go.rice" ) func A() string { box, err := rice.FindBox("template") if err != nil { return fmt.Sprintf("%v", err) } helloTemplate, err := box.String("hello.tmpl") if err != nil { return fmt.Sprintf("%v", err) } tmpl, err := template.New("message").Parse(helloTemplate) if err != nil { return fmt.Sprintf("%v", err) } var message strings.Builder err = tmpl.Execute(&message, "go.rice") if err != nil { return fmt.Sprintf("%v", err) } return message.String() }
このファイル構成では初期設定のままファイルを埋め込むコマンド rice append
が失敗する。
(エラーメッセージよりどうやらパッケージの相対パスに配置されていることを期待している雰囲気を感じた)
$ go build -o example.exe $ rice append --import-path pkg/example/example.go --exec example.exe Error: box "C:\Users\y_okazawa\work\gorice-tutorial\pkg\example\template" not found on disk
実装を確認
- FindBox
findBox
にdefaultLocateOrder
を指定している
- findBox
order
に応じて探索先を変更している
- defaultLocateOrder
と、一通り読んでから order
は Config
オブジェクトで制御できることがわかった。
正しい使い方
パッケージの相対パスから探索させるときのファイル配置とソースコード
$ find . -type f ./example.exe ./go.mod ./go.sum ./main.go ./pkg/example/example.go ./pkg/example/template/hello.tmpl
// ./pkg/example/example.go package example import ( "fmt" "strings" "text/template" rice "github.com/GeertJohan/go.rice" ) func A() string { box, err := rice.FindBox("template") if err != nil { return fmt.Sprintf("%v", err) } helloTemplate, err := box.String("hello.tmpl") if err != nil { return fmt.Sprintf("%v", err) } tmpl, err := template.New("message").Parse(helloTemplate) if err != nil { return fmt.Sprintf("%v", err) } var message strings.Builder err = tmpl.Execute(&message, "go.rice") if err != nil { return fmt.Sprintf("%v", err) } return message.String() }
初期設定では FindBox
を呼び出している example.go
のパッケージ example
から相対パスで template
を探索する。
(rice append
がそういう動作をする。)
$ rm -f example.exe $ go build -o example.exe $ rice append --import-path pkg/example/example.go --exec example.exe $ ./example.exe 2020/03/02 09:53:51 Hello go.rice World
実行時ディレクトリから探索させるときのファイル配置とソースコード
$ find . -type f ./example.exe ./go.mod ./go.sum ./main.go ./pkg/example/example.go ./pkg/example/template/hello.tmpl ./template/hello.tmpl $ cat ./pkg/example/template/hello.tmpl (inside) Hello {{.}} World $ cat ./template/hello.tmpl (outside) Hello {{.}} World
// ./pkg/example/example.go package example import ( "fmt" "strings" "text/template" rice "github.com/GeertJohan/go.rice" ) func A() string { config := rice.Config{ LocateOrder: []rice.LocateMethod{ rice.LocateWorkingDirectory, rice.LocateEmbedded, rice.LocateAppended, rice.LocateFS, }, } box, err := config.FindBox("template") if err != nil { return fmt.Sprintf("%v", err) } helloTemplate, err := box.String("hello.tmpl") if err != nil { return fmt.Sprintf("%v", err) } tmpl, err := template.New("message").Parse(helloTemplate) if err != nil { return fmt.Sprintf("%v", err) } var message strings.Builder err = tmpl.Execute(&message, "go.rice") if err != nil { return fmt.Sprintf("%v", err) } return message.String() }
実行時の作業ディレクトリから相対パスでディレクトリを見つけたらそちらを利用する。
$ rm -f example.exe $ go build -o example.exe $ rice append --import-path pkg/example/example.go --exec example.exe $ ./example.exe 2020/03/02 12:30:30 (outside) Hello go.rice World
実行時の作業ディレクトリから相対パスでディレクトリを見つけられなかったら埋め込みしたリソースを利用する。
$ mv template template.1 $ ./example.exe 2020/03/02 12:31:26 (inside) Hello go.rice World