V novém Go 1.16 kromě jiného přibyla nové directiva na úrovni balíčku //go:embed
.
Ta umožňuje v čase kompilace zahrnout do binarního výstupu soubory, které potřebujete. Například CSS a JS pro váš webserver nebo zakladní konfigurační soubory v JSONu nebo YAMLu apod.
Nebudu se zabývat všemy aspekty této directivy, to už skvěle udělal Ben Johnson v svém článku How to Use //go:embed, který všem doporučuji přečíst.
Teď k mému příkladu. Mám jednoduchý CLI nástroj pro práci s Github Actions, který generuje badge do readme a vytvoří zakladní workflow soubory pro moje nejpoužívanější použití v Go a Node.js.
Právě ta druhá funkce kde se generuje Yaml soubor je skvělá pro //go:embed
. Templates zůstanou v repozitáři jako soubory, ale nemusím je nikde stahovat nebo mít nějak extra v balíčku.
Nejdříve co potřebujete. V go.mod
mám definované tyto závislosti:
module github.com/abtris/ga-badge
go 1.16
require github.com/urfave/cli/v2 v2.3.0
Jak vidíte je to jen Go 1.16+ a knihovna na práci s flagy pro CLI. Zvolil jsem tuto jednodušší knihovnu než moji obvyklou cobra, protože nečekám, že by bylo potřeba více příkazů než 5. Ale i tak mi chyběl generátor, který CLI příkazdy sám vytváří, je to rychlejší než to psát.
Go embed musíte definovat na úrovni celkého balíčku a nemůžete to definovat uvnitř funkcí. Já jsem zvolil kombinaci s embed.FS
, kdy přes masku máte přístup k celému stromu souborů, u mě jsou to všechny YAML soubory ve složce templates
.
//go:embed templates/*.yaml
var files embed.FS
Když máte takto definované jaké soubory chcete použít tak vlastní použití je velmi jednoduché.
data, err := files.ReadFile("templates/go.yaml")
if err != nil {
return "", fmt.Errorf("Error read file")
}
Soubor načtete jako []byte
a potom s ním pracujete standardně pomocí io/ioutil
balíčku nebo co zrovna potřebujete.
Použití je přímočaré a dá se velmi dobře použít v mnoha situacích. Zatím mám cesty k souborům na přímo, ale to se dá vylepšit přes funkci ReadDir
, kdy si vrátíte kolekci []fs.DirEntry
se soubory v embed filesystému.
templates, _ := fs.ReadDir(files, "templates")
Tak pokud používáte Go a potřebujete občas nějaký soubor přímo do zkompilovaného binárky tak teď víte jak na to.