Задача упаковки статических ресурсов в один жирный бинарник стоит не так часто, но в одном из проектов все-таки это понадобилось. Посмотрев на разные библиотеки из 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 утилиты файлы будут вшиты в наш бинарник — что нам и требовалось.