<p dir="auto">by <strong>untheoretic</strong>:</p>
<pre class="notranslate">Please find a reasonable way to transport things that can't be (principally) embedded in
the source code to some place where
they could be found.

An (sad) example would be a go-gtk based program that must have
a several non-go files for the gtk runtime.</pre>
<p dir="auto">There are many tools to embed static asset files into binaries:</p>
<ul dir="auto">
<li><a href="https://godoc.org/perkeep.org/pkg/fileembed" rel="nofollow">https://godoc.org/perkeep.org/pkg/fileembed</a> / perkeep.org/pkg/fileembed/genfileembed</li>
<li><a href="https://godoc.org/github.com/gobuffalo/packr" rel="nofollow">https://godoc.org/github.com/gobuffalo/packr</a></li>
<li><a href="https://godoc.org/github.com/knadh/stuffbin" rel="nofollow">https://godoc.org/github.com/knadh/stuffbin</a></li>
<li><a href="https://github.com/rakyll/statik">https://github.com/rakyll/statik</a></li>
<li>Bazel <a href="https://github.com/bazelbuild/rules_go/blob/master/go/extras.rst#go-embed-data">go_embed_data</a></li>
</ul>
<p dir="auto">Actually, <a href="https://tech.townsourced.com/post/embedding-static-files-in-go/" rel="nofollow">https://tech.townsourced.com/post/embedding-static-files-in-go/</a> lists more:</p>
<ul dir="auto">
<li>vfsgen - <a href="https://github.com/shurcooL/vfsgen">https://github.com/shurcooL/vfsgen</a></li>
<li>go.rice - <a href="https://github.com/GeertJohan/go.rice">https://github.com/GeertJohan/go.rice</a></li>
<li>statik - <a href="https://github.com/rakyll/statik">https://github.com/rakyll/statik</a></li>
<li>esc - <a href="https://github.com/mjibson/esc">https://github.com/mjibson/esc</a></li>
<li>go-embed - <a href="https://github.com/pyros2097/go-embed">https://github.com/pyros2097/go-embed</a></li>
<li>go-resources - <a href="https://github.com/omeid/go-resources">https://github.com/omeid/go-resources</a></li>
<li>statics - <a href="https://github.com/go-playground/statics">https://github.com/go-playground/statics</a></li>
<li>templify - <a href="https://github.com/wlbr/templify">https://github.com/wlbr/templify</a></li>
<li>gnoso/go-bindata - <a href="https://github.com/gnoso/go-bindata">https://github.com/gnoso/go-bindata</a></li>
<li>shuLhan/go-bindata - <a href="https://github.com/shuLhan/go-bindata">https://github.com/shuLhan/go-bindata</a></li>
<li>fileb0x - <a href="https://github.com/UnnoTed/fileb0x">https://github.com/UnnoTed/fileb0x</a></li>
<li>gobundle - <a href="https://github.com/alecthomas/gobundle">https://github.com/alecthomas/gobundle</a></li>
<li>parcello - <a href="https://github.com/phogolabs/parcello">https://github.com/phogolabs/parcello</a></li>
</ul>
<h2 dir="auto">Proposal</h2>
<p dir="auto">I think it's time to do this well once &amp; reduce duplication, adding official support for embedding file resources into the cmd/go tool.</p>
<h2 dir="auto">Problems with the current situation:</h2>
<ul dir="auto">
<li>There are too many tools</li>
<li>Using a go:generate-based solution bloats the git history with a second (and slightly larger) copy of each file.</li>
<li>Not using go:generate means not being <code class="notranslate">go install</code>-able or making people write their own Makefiles, etc.</li>
</ul>
<h2 dir="auto">Goals:</h2>
<ul dir="auto">
<li>don't check in generated files</li>
<li>don't generate *.go files at all (at least not in user's workspace)</li>
<li>make <code class="notranslate">go install</code> / <code class="notranslate">go build</code> do the embedding automatically</li>
<li>let user choose per file/glob which type of access is needed (e.g. []byte, <code class="notranslate">func() io.Reader</code>, <code class="notranslate">io.ReaderAt</code>, etc)</li>
<li>Maybe store assets compressed in the binary where appropriate (e.g. if user only needs an <code class="notranslate">io.Reader</code>)? (<strong>edit</strong>: but probably not; see comments below)</li>
<li><strong>No code execution at compilation time</strong>; that is a long-standing Go policy. <code class="notranslate">go build</code> or <code class="notranslate">go install</code> can not run arbitrary code, just like <code class="notranslate">go:generate</code> doesn't run automatically at install time.</li>
</ul>
<p dir="auto">The two main implementation approaches are <code class="notranslate">//go:embed Logo logo.jpg</code> or a well-known package (<code class="notranslate">var Logo = embed.File("logo.jpg")</code>).</p>
<h2 dir="auto">go:embed approach</h2>
<p dir="auto">For a <code class="notranslate">go:embed</code> approach, one might say that any <code class="notranslate">go/build</code>-selected <code class="notranslate">*.go</code> file can contain something like:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="//go:embed Logo logo.jpg"><pre class="notranslate"><code class="notranslate">//go:embed Logo logo.jpg
</code></pre></div>
<p dir="auto">Which, say, compiles to:</p>
<div class="highlight highlight-source-go notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="func Logo() *io.SectionReader"><pre class="notranslate"><span class="pl-k">func</span> <span class="pl-en">Logo</span>() <span class="pl-c1">*</span>io.<span class="pl-smi">SectionReader</span></pre></div>
<p dir="auto">(adding a dependency to the <code class="notranslate">io</code> package)</p>
<p dir="auto">Or:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="//go:embedglob Assets assets/*.css assets/*.js"><pre class="notranslate"><code class="notranslate">//go:embedglob Assets assets/*.css assets/*.js
</code></pre></div>
<p dir="auto">compiling to, say:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="var Assets interface{
     Files() []string
     Open func(name string) *io.SectionReader
} = runtime.EmbedAsset(123)"><pre class="notranslate"><code class="notranslate">var Assets interface{
     Files() []string
     Open func(name string) *io.SectionReader
} = runtime.EmbedAsset(123)
</code></pre></div>
<p dir="auto">Obviously this isn't fully fleshed out. There'd need to be something for compressed files too that yield only an <code class="notranslate">io.Reader</code>.</p>
<h2 dir="auto">embed package approach</h2>
<p dir="auto">The other high-level approach is to not have a magic <code class="notranslate">//go:embed</code> syntax and instead just let users write Go code in some new <code class="notranslate">"embed"</code> or <code class="notranslate">"golang.org/x/foo/embed"</code> package:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="var Static = embed.Dir(&quot;static&quot;)
var Logo = embed.File(&quot;images/logo.jpg&quot;)
var Words = embed.CompressedReader(&quot;dict/words&quot;)"><pre class="notranslate"><code class="notranslate">var Static = embed.Dir("static")
var Logo = embed.File("images/logo.jpg")
var Words = embed.CompressedReader("dict/words")
</code></pre></div>
<p dir="auto">Then have cmd/go recognize the calls to embed.Foo("foo/*.js") etc and glob do the work in cmd/go, rather than at runtime. Or maybe certain build tags or flags could make it fall back to doing things at runtime instead. Perkeep (linked above) has such a mode, which is nice to speed up incremental development where you don't care about linking one big binary.</p>
<h2 dir="auto">Concerns</h2>
<ul dir="auto">
<li>Pick a style (//go:embed* vs a magic package).</li>
<li>Block certain files?
<ul dir="auto">
<li>Probably block embedding <code class="notranslate">../../../../../../../../../../etc/shadow</code></li>
<li>Maybe block reaching into <code class="notranslate">.git</code> too</li>
</ul>
</li>
</ul>