Задача упаковки статических ресурсов в один жирный бинарник стоит не так часто, но в одном из проектов все-таки это понадобилось. Посмотрев на разные библиотеки из awesome go, остановился на наверное самом простом и более для меня понятном go rice.
В чем фишка? Мы меняем вызовы os.Open на box.Open, далее запускаем утилиту rice embed-go, которая создает для нас rice-box.go с нужным массивом байтов внутри. Утилита сканирует наш код и вызовы box.Open и добавляет файлы в файл rice-box.go
Пример использования:
func main() {
conf := rice.Config{
LocateOrder: []rice.LocateMethod{rice.LocateFS, rice.LocateEmbedded, rice.LocateAppended},
}
box, err := conf.FindBox("assets")
if err != nil {
log.Fatalf("error opening rice.Box: %s\n", err)
}
f, err := box.Open("goalie.png")
if err != nil {
log.Fatalf("could not open file: %s\n", err)
}
fmt.Println(f)
// then use our files in our code...
}
Далее запускаем rice embed-go. После этой операции у нас должен появиться файл rice-box.go примерно такого содержания:
package main
import (
"time"
"github.com/GeertJohan/go.rice/embedded"
)
func init() {
// define files
file2 := &embedded.EmbeddedFile{
Filename: ".DS_Store",
FileModTime: time.Unix(1600898893, 0),
Content: string("\x00\x00\x00\x01Bud1\x00\x00\x10\x00\x00\x00\b\x00\x00\x00\x10\x00\x00\x00\x00%\x00\x00\x00\x00\
...
...
Рассмотрим нашу конфигурацию:
conf := rice.Config{
LocateOrder: []rice.LocateMethod{rice.LocateFS, rice.LocateEmbedded, rice.LocateAppended},
}
В dev окружении при наличии реальных файлов go rice будет искать сначала файлы с диска, если нет то будет смотреть rice-box.go Ну и при сборе приложения после запуска rice утилиты файлы будут вшиты в наш бинарник — что нам и требовалось.