From 414c1ad1ae31470de66a1f4597d73b4f550c07d8 Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Mon, 19 Sep 2022 01:15:38 +0300 Subject: [PATCH] add support for embed.FS --- HISTORY.md | 3 + _examples/README.md | 3 +- .../assets/css/main.css | 5 + .../assets/favicon.ico | Bin .../assets/js/main.js | 1 + .../bindata.go | 0 .../embedding-files-into-app-bindata/main.go | 44 ++++++++ .../main_test.go | 94 ++++++++++++++++++ .../embedding-files-into-app/main.go | 14 ++- .../embedding-files-into-app/main_test.go | 9 +- .../bindata.go | 6 +- .../main.go | 2 +- .../main_test.go | 2 +- cli.go | 1 + core/router/api_builder.go | 17 ++++ 15 files changed, 179 insertions(+), 22 deletions(-) create mode 100644 _examples/file-server/embedding-files-into-app-bindata/assets/css/main.css rename _examples/file-server/{embedding-files-into-app => embedding-files-into-app-bindata}/assets/favicon.ico (100%) create mode 100644 _examples/file-server/embedding-files-into-app-bindata/assets/js/main.js rename _examples/file-server/{embedding-files-into-app => embedding-files-into-app-bindata}/bindata.go (100%) create mode 100644 _examples/file-server/embedding-files-into-app-bindata/main.go create mode 100644 _examples/file-server/embedding-files-into-app-bindata/main_test.go rename _examples/file-server/{embedding-gzipped-files-into-app => embedding-gzipped-files-into-app-bindata}/bindata.go (99%) rename _examples/file-server/{embedding-gzipped-files-into-app => embedding-gzipped-files-into-app-bindata}/main.go (92%) rename _examples/file-server/{embedding-gzipped-files-into-app => embedding-gzipped-files-into-app-bindata}/main_test.go (97%) diff --git a/HISTORY.md b/HISTORY.md index 05cee57e..708da47d 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -28,6 +28,9 @@ The codebase for Dependency Injection, Internationalization and localization and ## Fixes and Improvements +- Add support for `embed.FS` on `app.HandleDir`. +- Minor fixes. + - Enable setting a custom "go-redis" client through `SetClient` go redis driver method or `Client` struct field on sessions/database/redis driver as requested at [chat](https://chat.iris-go.com). - Ignore `"csrf.token"` form data key when missing on `ctx.ReadForm` by default as requested at [#1941](https://github.com/kataras/iris/issues/1941). diff --git a/_examples/README.md b/_examples/README.md index 55e5ddda..5ded95e1 100644 --- a/_examples/README.md +++ b/_examples/README.md @@ -119,7 +119,8 @@ * [Favicon](file-server/favicon/main.go) * [Basic](file-server/basic/main.go) * [Embedding Files Into App Executable File](file-server/embedding-files-into-app/main.go) - * [Embedding Gzipped Files Into App Executable File](file-server/embedding-gzipped-files-into-app/main.go) + * [Embedding Files Into App Executable File (Bindata)](file-server/embedding-files-into-app-bindata/main.go) + * [Embedding Gzipped Files Into App Executable File (Bindata)](file-server/embedding-gzipped-files-into-app-bindata/main.go) * [Send Files (rate limiter included)](file-server/send-files/main.go) * Single Page Applications * [Vue Router](file-server/spa-vue-router) diff --git a/_examples/file-server/embedding-files-into-app-bindata/assets/css/main.css b/_examples/file-server/embedding-files-into-app-bindata/assets/css/main.css new file mode 100644 index 00000000..9749e5ad --- /dev/null +++ b/_examples/file-server/embedding-files-into-app-bindata/assets/css/main.css @@ -0,0 +1,5 @@ +html { + font-family: sans-serif; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100% +} \ No newline at end of file diff --git a/_examples/file-server/embedding-files-into-app/assets/favicon.ico b/_examples/file-server/embedding-files-into-app-bindata/assets/favicon.ico similarity index 100% rename from _examples/file-server/embedding-files-into-app/assets/favicon.ico rename to _examples/file-server/embedding-files-into-app-bindata/assets/favicon.ico diff --git a/_examples/file-server/embedding-files-into-app-bindata/assets/js/main.js b/_examples/file-server/embedding-files-into-app-bindata/assets/js/main.js new file mode 100644 index 00000000..07f93514 --- /dev/null +++ b/_examples/file-server/embedding-files-into-app-bindata/assets/js/main.js @@ -0,0 +1 @@ +console.log("example"); \ No newline at end of file diff --git a/_examples/file-server/embedding-files-into-app/bindata.go b/_examples/file-server/embedding-files-into-app-bindata/bindata.go similarity index 100% rename from _examples/file-server/embedding-files-into-app/bindata.go rename to _examples/file-server/embedding-files-into-app-bindata/bindata.go diff --git a/_examples/file-server/embedding-files-into-app-bindata/main.go b/_examples/file-server/embedding-files-into-app-bindata/main.go new file mode 100644 index 00000000..f14b9b93 --- /dev/null +++ b/_examples/file-server/embedding-files-into-app-bindata/main.go @@ -0,0 +1,44 @@ +package main + +import ( + "github.com/kataras/iris/v12" +) + +// Follow these steps first: +// $ go install github.com/go-bindata/go-bindata/v3/go-bindata@latest +// $ go-bindata -prefix "assets" -fs ./assets/... +// $ go run . +// "physical" files are not used, you can delete the "assets" folder and run the example. +// +// See `file-server/embedding-gzipped-files-into-app-bindata` and +// 'file-server/embedding-files-into-app` examples as well. +func newApp() *iris.Application { + app := iris.New() + app.Logger().SetLevel("debug") + + app.HandleDir("/static", AssetFile()) + + /* + Or if you need to cache them inside the memory (requires the assets folder + to be located near the executable program): + app.HandleDir("/static", iris.Dir("./assets"), iris.DirOptions{ + IndexName: "index.html", + Cache: iris.DirCacheOptions{ + Enable: true, + Encodings: []string{"gzip"}, + CompressIgnore: iris.MatchImagesAssets, + CompressMinSize: 30 * iris.B, + }, + }) + */ + return app +} + +func main() { + app := newApp() + + // http://localhost:8080/static/css/main.css + // http://localhost:8080/static/js/main.js + // http://localhost:8080/static/favicon.ico + app.Listen(":8080") +} diff --git a/_examples/file-server/embedding-files-into-app-bindata/main_test.go b/_examples/file-server/embedding-files-into-app-bindata/main_test.go new file mode 100644 index 00000000..c8dcf3fd --- /dev/null +++ b/_examples/file-server/embedding-files-into-app-bindata/main_test.go @@ -0,0 +1,94 @@ +package main + +import ( + "os" + "path/filepath" + "runtime" + "strings" + "testing" + + "github.com/kataras/iris/v12/httptest" +) + +type resource string + +// content types that are used in the ./assets, +// we could use the detectContentType that iris do but it's better +// to do it manually so we can test if that returns the correct result on embedding files. +func (r resource) contentType() string { + switch filepath.Ext(r.String()) { + case ".js": + return "text/javascript" + case ".css": + return "text/css" + case ".ico": + return "image/x-icon" + case ".html": + return "text/html" + default: + return "text/plain" + } +} + +func (r resource) String() string { + return string(r) +} + +func (r resource) strip(strip string) string { + s := r.String() + return strings.TrimPrefix(s, strip) +} + +func (r resource) loadFromBase(dir string) string { + filename := r.strip("/static") + + fullpath := filepath.Join(dir, filename) + + b, err := os.ReadFile(fullpath) + if err != nil { + panic(fullpath + " failed with error: " + err.Error()) + } + + result := string(b) + + if runtime.GOOS != "windows" { + result = strings.ReplaceAll(result, "\n", "\r\n") + result = strings.ReplaceAll(result, "\r\r", "") + } + return result +} + +var urls = []resource{ + "/static/css/main.css", + "/static/js/main.js", + "/static/favicon.ico", +} + +// if bindata's values matches with the assets/... contents +// and secondly if the HandleDir had successfully registered +// the routes and gave the correct response. +func TestEmbeddingFilesIntoApp(t *testing.T) { + app := newApp() + e := httptest.New(t, app) + + route := app.GetRouteReadOnly("GET/static/{file:path}") + if route == nil { + t.Fatalf("expected a route to serve embedded files") + } + + if runtime.GOOS != "windows" { + // remove the embedded static favicon for !windows, + // it should be built for unix-specific in order to be work + urls = urls[0 : len(urls)-1] + } + + for _, u := range urls { + url := u.String() + contents := u.loadFromBase("./assets") + + e.GET(url).Expect(). + Status(httptest.StatusOK). + ContentType(u.contentType()). + Body().Equal(contents) + } +} diff --git a/_examples/file-server/embedding-files-into-app/main.go b/_examples/file-server/embedding-files-into-app/main.go index 01f3d2c9..4f71cc15 100644 --- a/_examples/file-server/embedding-files-into-app/main.go +++ b/_examples/file-server/embedding-files-into-app/main.go @@ -1,21 +1,19 @@ package main import ( + "embed" + "github.com/kataras/iris/v12" ) -// Follow these steps first: -// $ go install github.com/go-bindata/go-bindata/v3/go-bindata@latest -// $ go-bindata -prefix "assets" -fs ./assets/... -// $ go run . -// "physical" files are not used, you can delete the "assets" folder and run the example. -// -// See `file-server/embedding-gzipped-files-into-app` example as well. +//go:embed assets/* +var fs embed.FS + func newApp() *iris.Application { app := iris.New() app.Logger().SetLevel("debug") - app.HandleDir("/static", AssetFile()) + app.HandleDir("/static", fs) /* Or if you need to cache them inside the memory (requires the assets folder diff --git a/_examples/file-server/embedding-files-into-app/main_test.go b/_examples/file-server/embedding-files-into-app/main_test.go index aa6eda89..ee3f6283 100644 --- a/_examples/file-server/embedding-files-into-app/main_test.go +++ b/_examples/file-server/embedding-files-into-app/main_test.go @@ -40,9 +40,7 @@ func (r resource) strip(strip string) string { } func (r resource) loadFromBase(dir string) string { - filename := r.String() - - filename = r.strip("/static") + filename := r.strip("/static") fullpath := filepath.Join(dir, filename) @@ -52,11 +50,6 @@ func (r resource) loadFromBase(dir string) string { } result := string(b) - - if runtime.GOOS != "windows" { - result = strings.ReplaceAll(result, "\n", "\r\n") - result = strings.ReplaceAll(result, "\r\r", "") - } return result } diff --git a/_examples/file-server/embedding-gzipped-files-into-app/bindata.go b/_examples/file-server/embedding-gzipped-files-into-app-bindata/bindata.go similarity index 99% rename from _examples/file-server/embedding-gzipped-files-into-app/bindata.go rename to _examples/file-server/embedding-gzipped-files-into-app-bindata/bindata.go index 4c8c93b4..a4167288 100644 --- a/_examples/file-server/embedding-gzipped-files-into-app/bindata.go +++ b/_examples/file-server/embedding-gzipped-files-into-app-bindata/bindata.go @@ -1,9 +1,9 @@ // Code generated by go-bindata. (@generated) DO NOT EDIT. // Package main generated by go-bindata.// sources: -// ../embedding-files-into-app/assets/css/main.css -// ../embedding-files-into-app/assets/favicon.ico -// ../embedding-files-into-app/assets/js/main.js +// ../embedding-files-into-app-bindata/assets/css/main.css +// ../embedding-files-into-app-bindata/assets/favicon.ico +// ../embedding-files-into-app-bindata/assets/js/main.js package main import ( diff --git a/_examples/file-server/embedding-gzipped-files-into-app/main.go b/_examples/file-server/embedding-gzipped-files-into-app-bindata/main.go similarity index 92% rename from _examples/file-server/embedding-gzipped-files-into-app/main.go rename to _examples/file-server/embedding-gzipped-files-into-app-bindata/main.go index c6168578..78809bbe 100644 --- a/_examples/file-server/embedding-gzipped-files-into-app/main.go +++ b/_examples/file-server/embedding-gzipped-files-into-app-bindata/main.go @@ -7,7 +7,7 @@ import ( // How to run: // // $ go install github.com/go-bindata/go-bindata/v3/go-bindata@latest -// $ go-bindata -prefix "../embedding-files-into-app/assets/" -fs ../embedding-files-into-app/assets/... +// $ go-bindata -prefix "../embedding-files-into-app-bindata/assets/" -fs ../embedding-files-into-app-bindata/assets/... // $ go run -mod=mod . // Time to complete the compression and caching of [2/3] files: 31.9998ms // Total size reduced from 156.6 kB to: diff --git a/_examples/file-server/embedding-gzipped-files-into-app/main_test.go b/_examples/file-server/embedding-gzipped-files-into-app-bindata/main_test.go similarity index 97% rename from _examples/file-server/embedding-gzipped-files-into-app/main_test.go rename to _examples/file-server/embedding-gzipped-files-into-app-bindata/main_test.go index 0e678f0d..b4f4c3e4 100644 --- a/_examples/file-server/embedding-gzipped-files-into-app/main_test.go +++ b/_examples/file-server/embedding-gzipped-files-into-app-bindata/main_test.go @@ -84,7 +84,7 @@ func TestEmbeddingGzipFilesIntoApp(t *testing.T) { for i, u := range urls { url := u.String() - rawContents := u.loadFromBase("../embedding-files-into-app/assets") + rawContents := u.loadFromBase("../embedding-files-into-app-bindata/assets") shouldBeCompressed := int64(len(rawContents)) >= dirOptions.Cache.CompressMinSize request := e.GET(url) diff --git a/cli.go b/cli.go index 8a6e324e..e756194e 100644 --- a/cli.go +++ b/cli.go @@ -13,6 +13,7 @@ import ( "strings" "github.com/kataras/iris/v12/context" + "gopkg.in/yaml.v3" ) diff --git a/core/router/api_builder.go b/core/router/api_builder.go index c1f51240..07c0ca92 100644 --- a/core/router/api_builder.go +++ b/core/router/api_builder.go @@ -1,8 +1,10 @@ package router import ( + "embed" "errors" "fmt" + stdfs "io/fs" "net/http" "os" "path" @@ -633,6 +635,21 @@ func (api *APIBuilder) HandleDir(requestPath string, fsOrDir interface{}, opts . fs = http.Dir(v) case http.FileSystem: fs = v + case embed.FS: + direEtries, err := v.ReadDir(".") + if err != nil { + panic(err) + } + + if len(direEtries) == 0 { + panic("HandleDir: no directories found under the embedded file system") + } + + subfs, err := stdfs.Sub(v, direEtries[0].Name()) + if err != nil { + panic(err) + } + fs = http.FS(subfs) default: panic(fmt.Errorf(`unexpected "fsOrDir" argument type of %T (string or http.FileSystem)`, v)) }