[譯]在go可執行檔中嵌入資料

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

原文地址 https://scene-si.org/2017/08/22/embedding-data-in-go-executables/

假如你已經關注了我一段時間,應該知道我正在開發Pendulum編輯器作為每天至少編碼一小時的#100DaysOfCode挑戰。Pendulum是一個非常適合編輯簡單文本和markdown檔案的基於web的編輯器。

實際上這篇文章就是用它寫的。它由go後端和VueJS前端組成。我希望它便於使用並提供包含一切的單個可執行檔,因此使用者不需要下載安裝器並解壓檔案。我需要找個能把所有東西打包到一塊的方案。我決定用go-bindata以代碼產生的方式來把所有資料通過 go build 添加到可執行檔中。

代碼產生?

當然這很簡單。例如 go-bindata 工具可以幫我們從public_html目錄產生對應的 .go 檔案。這對我的應用程式情境來說是極好的。不過為什麼要用bash指令碼或者makefile來產生它呢?因為這樣我們在執行go build之前就只需要通過執行一下go generate利用go的代碼產生工具了如果還不熟悉代碼產生,你只需要在你代碼的某處加上簡單的注釋,用main.go舉個例子:

package main//go:generate echo "Hello world"func main() {}

執行go generate時,可以看到輸出了 “Hello world” 。這不是你用 go generate 產生代碼的實際需求。你在//go:generate後面寫的一切都會執行。如果你想的話,甚至可以執行go build

package main//go:generate echo "Hello world"//go:generate go run main.gofunc main() {    println("Hello world from Go")}

運行這個會有預期的輸出:

%go generateHello worldHello world from Go

旗開得勝!go generate 很有意思。Node程式通過babel來使Node ES5運行時相容ES6/ES7的文法。人們正嘗試用類似的途徑為go提供超出語言目前功能的特性。

例如,genny主要針對強型別代碼的產生,因此不再需要手動複製粘貼。不過Have這樣的項目更接近Babel對Node的處理–提供轉換到go的語言。目前我還不清楚這方面更有吸引力的其他嘗試。不過關於Go2及泛型的討論似乎比較有趣。

這對我們的應用情境來說略顯枯燥,我們只是要把一些資料打包到程式中。那麼閑話休提,書歸正傳:

//go:generate go-bindata -prefix front/src -o assets/bindata.go -pkg assets -nomemcopy front/src/dist/...

這一行略長,就把它拆分來看:

  • //go:generate - 為go generate作提示
  • go-bindata - 要執行的主命令
  • -prefix front/src - 排除“front/src”包
  • -o assets/bindata.go - 指定輸出檔案
  • -pkg assets - 要產生的包名
  • -nomemcopy - 對記憶體佔用的最佳化
  • front/src/dist/... - 要打包的地方

這會在應用目錄下建立一個可以簡單的用app/assets匯入的assets包,其中app對應的是應用目錄。

通過HTTP提供內嵌檔案服務

這稍微有點複雜。不過看一下文檔之後就簡單了。如果要基於本地檔案提供服務,你大致需要下面這幾行類似的代碼:

folder := http.Dir("/")server := http.FileServer(folder)http.Handle("/", server)

實際上,go-bindata-assetfs包已經提供了一個http.FileServer實現。這個用起來就夠簡單了:

import "github.com/elazarl/go-bindata-assetfs"import "app/assets"// ...func main() {    // ...    files := assetfs.AssetFS{        Asset:     assets.Asset,        AssetDir:  assets.AssetDir,        AssetInfo: assets.AssetInfo,        Prefix:    "dist",    }    server := http.FileServer(&files)    // ...}

還有一個小問題。我用的是啟用了pushHistory的VueJS應用。這就意味著,使用者使用時會看到沒有釋伴符(雜湊,#)的類似/blog/about.md的普通連結。這些需要被應用處理的連結內容在asset中並不存在。

這個問題也不難解決。assetfs.AssetFS結構體有一個AssetsInfo方法(相當於os.Stat)和一個Asset方法(有點像ioutil.ReadFile)。這使檢查一個檔案是否存在於asset,若不存在則輸出另一個檔案成為可能:

// Serves index.html in case the requested file isn't found// (or some other os.Stat error)func serveIndex(serve http.Handler, fs assetfs.AssetFS) http.HandlerFunc {    return func(w http.ResponseWriter, r *http.Request) {        _, err := fs.AssetInfo(path.Join(fs.Prefix, r.URL.Path))        if err != nil {            contents, err := fs.Asset(path.Join(fs.Prefix, "index.html"))            if err != nil {                http.Error(w, err.Error(), http.StatusNotFound)                return            }            w.Header().Set("Content-Type", "text/html")            w.Write(contents)            return        }        serve.ServeHTTP(w, r)    }}

如果找到了檔案,就用預置的ServeHTTP方法取代我自己的實現。採用這種方法只需要對我們之前定義的handler稍作調整:

http.HandleFunc("/", serveIndex(server, assets))

serveIndex函數返回一個http.HandlerFunc,這行是相應的修改。這就提供了你用 go generate 和 go-bindata 添加到應用中的資料服務的完整實現。如果你想跳過//go:generate環節把這些放到CI指令碼中也是可以的。

鑒於此我實現了Pendulum的單個可執行發布版本。可以從GitHub發布頁擷取並嘗試。

編輯:改進serveIndex樣本 感謝@Rdihipone

當你看到了這裡…

要是你能買本我的書定是極好的:

  • API Foundations in Go
  • 12 Factor Apps with Docker and Go
  • The SaaS Handbook (work in progress)

I promise you’ll learn a lot more if you buy one. Buying a copy supports me writing more about similar topics. Say thank you and buy my books.Feel free to send me an email if you want to book my time for consultancy/freelance services. I’m great at APIs, Go, Docker, VueJS and scaling services, among many other things.

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.