diff --git a/FAQ.md b/FAQ.md index 26eed099..72e6f57a 100644 --- a/FAQ.md +++ b/FAQ.md @@ -1,5 +1,15 @@ # FAQ +## [![iris](https://img.shields.io/badge/iris-powered-2196f3.svg?style=for-the-badge)](https://github.com/kataras/iris) + +Add a `badge` to your open-source projects powered by [Iris](https://iris-go.com) by pasting the below code snippet to the project repo's README.md: + +```md +[![iris](https://img.shields.io/badge/iris-powered-2196f3.svg?style=for-the-badge)](https://github.com/kataras/iris) +``` + +> The badge is optionally, of course, it is just a simple and fast way to support Iris. The badge is work of a third-party, taken from https://github.com/blob-go/blob-go which was published by our friend @clover113 and we loved it<3 + ## How to upgrade ```sh diff --git a/Gopkg.lock b/Gopkg.lock index 2bf5a8ef..1f27500d 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -173,7 +173,7 @@ branch = "master" name = "github.com/satori/go.uuid" packages = ["."] - revision = "5bf94b69c6b68ee1b541973bb8e1144db23a194b" + revision = "f58768cc1a7a7e77a3bd49e98cdd21419399b6a3" [[projects]] branch = "master" diff --git a/Gopkg.toml b/Gopkg.toml index 896ead1b..27f27ed5 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -63,8 +63,8 @@ name = "github.com/ryanuber/columnize" [[constraint]] + branch = "v1.2.0" name = "github.com/satori/go.uuid" - revision = "5bf94b69c6b68ee1b541973bb8e1144db23a194b" [[constraint]] branch = "master" diff --git a/HISTORY.md b/HISTORY.md index b7409a22..397f433d 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -17,6 +17,34 @@ Developers are not forced to upgrade if they don't really need it. Upgrade whene **How to upgrade**: Open your command-line and execute this command: `go get -u github.com/kataras/iris` or let the automatic updater do that for you. +# Mo, 15 Jenuary 2018 | v10.0.1 + +Not any serious problems were found to be resolved here but one, the first one which is important for devs that used the [cache](cache) package. + +- fix a single one cache handler didn't work across multiple route handlers at the same time https://github.com/kataras/iris/pull/852, as reported at https://github.com/kataras/iris/issues/850 +- merge PR https://github.com/kataras/iris/pull/862 +- do not allow concurrent access to the `ExecuteWriter -> Load` when `view#Engine##Reload` was true, as requested at https://github.com/kataras/iris/issues/872 +- badge for open-source projects powered by Iris, learn how to add that badge to your open-source project at [FAQ.md](FAQ.md) file + +## New Backers + +1. https://opencollective.com/cetin-basoz + +## New Translations + +1. The Chinese README_ZH.md and HISTORY_ZH.md was translated by @Zeno-Code via https://github.com/kataras/iris/pull/858 +2. New Russian README_RU.md translations by @merrydii via https://github.com/kataras/iris/pull/857 +3. New Greek README_GR.md and HISTORY_GR.md translations via https://github.com/kataras/iris/commit/8c4e17c2a5433c36c148a51a945c4dc35fbe502a#diff-74b06c740d860f847e7b577ad58ddde0 and https://github.com/kataras/iris/commit/bb5a81c540b34eaf5c6c8e993f644a0e66a78fb8 + +## New Examples + +1. [MVC - Register Middleware](_examples/mvc/middleware) + +## New Articles + +1. [A Todo MVC Application using Iris and Vue.js](https://hackernoon.com/a-todo-mvc-application-using-iris-and-vue-js-5019ff870064) +2. [A Hasura starter project with a ready to deploy Golang hello-world web app with IRIS](bit.ly/2lmKaAZ) + # Mo, 01 Jenuary 2018 | v10.0.0 We must thanks [Mrs. Diana](https://www.instagram.com/merry.dii/) for our awesome new [logo](https://iris-go.com/images/icon.svg)! diff --git a/HISTORY_GR.md b/HISTORY_GR.md index 69252565..a50e173f 100644 --- a/HISTORY_GR.md +++ b/HISTORY_GR.md @@ -17,6 +17,31 @@ **Πώς να αναβαθμίσετε**: Ανοίξτε την γραμμή εντολών σας και εκτελέστε αυτήν την εντολή: `go get -u github.com/kataras/iris` ή αφήστε το αυτόματο updater να το κάνει αυτό για σας. +# Mo, 15 Jenuary 2018 | v10.0.1 + +- διόρθωση του cache handler που δεν δούλευε όπως έπρεπε όταν γινόταν εγγραφή σε πάνω από ένα handler, παλιότερα ήταν ένα cache handler προς ένα route handler, τώρα το ίδιο handler μπορεί να καταχωρηθεί σε όσα route handlers θέλετε https://github.com/kataras/iris/pull/852, όπως είχε αναφερθεί στο https://github.com/kataras/iris/issues/850 +- συγχώνευση PR https://github.com/kataras/iris/pull/862 +- απαγόρευση της ταυτόχρονης προσπέλασης του `ExecuteWriter -> Load` όταν το `view#Engine##Reload` είναι true, όπως είχε ζητηθεί στο https://github.com/kataras/iris/issues/872 + +## Νέοι Υποστηρικτές + +1. https://opencollective.com/cetin-basoz + +## Νέες Μεταφράσεις + +1. Aναβαθμίσεις για την Κινέζικη μετάφραση README_ZH.md (νέο) και HISTORY_ZH.md από @Zeno-Code μέσω του https://github.com/kataras/iris/pull/858 +2. Το Ρώσικο README_RU.md μεταφράστηκε από την @merrydii μέσω του https://github.com/kataras/iris/pull/857 +3. Τα Ελληνικά README_GR.md και HISTORY_GR.md μεταφράστηκαν μέσω των https://github.com/kataras/iris/commit/8c4e17c2a5433c36c148a51a945c4dc35fbe502a#diff-74b06c740d860f847e7b577ad58ddde0 και https://github.com/kataras/iris/commit/bb5a81c540b34eaf5c6c8e993f644a0e66a78fb8 + +## Νέα Παραδείγματα + +1. [MVC - Register Middleware](_examples/mvc/middleware) + +## Νέα Άρθρα + +1. [A Todo MVC Application using Iris and Vue.js](https://hackernoon.com/a-todo-mvc-application-using-iris-and-vue-js-5019ff870064) +2. [A Hasura starter project with a ready to deploy Golang hello-world web app with IRIS](bit.ly/2lmKaAZ) + # Mo, 01 Jenuary 2018 | v10.0.0 Πρέπει να ευχαριστήσουμε την [Κυρία Diana](https://www.instagram.com/merry.dii/) για το νέο μας [λογότυπο](https://iris-go.com/images/icon.svg)! diff --git a/HISTORY_ZH.md b/HISTORY_ZH.md index 1ba89069..5a07d33b 100644 --- a/HISTORY_ZH.md +++ b/HISTORY_ZH.md @@ -17,6 +17,10 @@ **如何升级**: 打开命令行执行以下命令: `go get -u github.com/kataras/iris` 或者等待自动更新。 +# Mo, 15 Jenuary 2018 | v10.0.1 + +Translation is missing for this specific history entry, please navigate through [english version of HISTORY.md](HISTORY.md#mo-15-jenuary-2018--v1001) instead or check back later on. + # 2018 元旦 | v10.0.0 版本发布 我们必须感谢 [Mrs. Diana](https://www.instagram.com/merry.dii/) 帮我们绘制的漂亮 [logo](https://iris-go.com/images/icon.svg)! diff --git a/README.md b/README.md index 0c15f863..2c8480eb 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ _Updated at: [Tuesday, 21 November 2017](_benchmarks/README_UNIX.md)_ ## Support -- [HISTORY](HISTORY.md#mo-01-jenuary-2018--v1000) file is your best friend, it contains information about the latest features and changes +- [HISTORY](HISTORY.md#mo-15-jenuary-2018--v1001) file is your best friend, it contains information about the latest features and changes - Did you happen to find a bug? Post it at [github issues](https://github.com/kataras/iris/issues) - Do you have any questions or need to speak with someone experienced to solve a problem at real-time? Join us to the [community chat](https://chat.iris-go.com) - Complete our form-based user experience report by clicking [here](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link) diff --git a/README_GR.md b/README_GR.md index ff248b2d..14378dc6 100644 --- a/README_GR.md +++ b/README_GR.md @@ -108,7 +108,7 @@ _Η τελευταία ενημέρωση έγινε την [Τρίτη, 21 Νο ## Υποστήριξη -- To [HISTORY](HISTORY_GR.md#mo-01-jenuary-2018--v1000) αρχείο είναι ο καλύτερος σας φίλος, περιέχει πληροφορίες σχετικά με τις τελευταίες λειτουργίες(features) και αλλαγές +- To [HISTORY](HISTORY_GR.md#mo-15-jenuary-2018--v1001) αρχείο είναι ο καλύτερος σας φίλος, περιέχει πληροφορίες σχετικά με τις τελευταίες λειτουργίες(features) και αλλαγές - Μήπως τυχαίνει να βρήκατε κάποιο bug; Δημοσιεύστε το στα [github issues](https://github.com/kataras/iris/issues) - Έχετε οποιεσδήποτε ερωτήσεις ή πρέπει να μιλήσετε με κάποιον έμπειρο για την επίλυση ενός προβλήματος σε πραγματικό χρόνο; Ελάτε μαζί μας στην [συνομιλία κοινότητας](https://chat.iris-go.com) - Συμπληρώστε την αναφορά εμπειρίας χρήστη κάνοντας κλικ [εδώ](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link) diff --git a/README_RU.md b/README_RU.md index 9bf9ce8b..09495551 100644 --- a/README_RU.md +++ b/README_RU.md @@ -106,7 +106,7 @@ _Обновлено: [Вторник, 21 ноября 2017 г.](_benchmarks/READ ## Поддержка -- Файл [HISTORY](HISTORY.md#mo-01-jenuary-2018--v1000) - ваш лучший друг, он содержит информацию о последних особенностях и всех изменениях +- Файл [HISTORY](HISTORY.md#mo-15-jenuary-2018--v1001) - ваш лучший друг, он содержит информацию о последних особенностях и всех изменениях - Вы случайно обнаружили ошибку? Опубликуйте ее на [Github вопросы](https://github.com/kataras/iris/issues) - У Вас есть какие-либо вопросы или Вам нужно поговорить с кем-то, кто бы смог решить Вашу проблему в режиме реального времени? Присоединяйтесь к нам в [чате сообщества](https://chat.iris-go.com) - Заполните наш отчет о пользовательском опыте на основе формы, нажав [здесь](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link) diff --git a/README_ZH.md b/README_ZH.md index f5300deb..5931b944 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -102,7 +102,7 @@ _更新于: [2017年11月21日星期二](_benchmarks/README_UNIX.md)_ ## 支持 -- [更新记录](HISTORY_ZH.md#mo-01-jenuary-2018--v1000) 是您最好的朋友,它包含有关最新功能和更改的信息 +- [更新记录](HISTORY_ZH.md#mo-15-jenuary-2018--v1001) 是您最好的朋友,它包含有关最新功能和更改的信息 - 你碰巧找到了一个错误? 请提交 [github issues](https://github.com/kataras/iris/issues) - 您是否有任何疑问或需要与有经验的人士交谈以实时解决问题? [加入我们的聊天](https://chat.iris-go.com) - [点击这里完成我们基于表单的用户体验报告](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link) diff --git a/VERSION b/VERSION index 2823854a..b3fd8049 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -10.0.0:https://github.com/kataras/iris/blob/master/HISTORY.md#mo-01-jenuary-2018--v1000 \ No newline at end of file +10.0.1:https://github.com/kataras/iris/blob/master/HISTORY.md#mo-15-jenuary-2018--v1001 \ No newline at end of file diff --git a/_examples/routing/main.go b/_examples/routing/main.go index 5d4ddc50..d9af5f3d 100644 --- a/_examples/routing/main.go +++ b/_examples/routing/main.go @@ -119,6 +119,12 @@ func newApp() *iris.Application { ctx.Write(b) }) + app.HandleMany("POST PUT", "/postvalue", func(ctx iris.Context) { + name := ctx.PostValueDefault("name", "iris") + headervale := ctx.GetHeader("headername") + ctx.Writef("Hello %s | %s", name, headervale) + }) + return app } @@ -152,11 +158,13 @@ func main() { http://mysubdomain.localhost:8080/ // PUT + http://localhost:8080/postvalue http://localhost:8080/games/42/players/93 http://localhost:8080/games/42/clans/clan/93 // POST http://localhost:8080/ + http://localhost:8080/postvalue http://localhost:8080/games/42/clans http://localhost:8080/games/42/players http://localhost:8080/games/42/clans/93/leave diff --git a/_examples/routing/main_test.go b/_examples/routing/main_test.go index 71b6143d..e588ea85 100644 --- a/_examples/routing/main_test.go +++ b/_examples/routing/main_test.go @@ -129,4 +129,13 @@ func TestRouting(t *testing.T) { // test with larger body sent and wait for the custom response largerBSent := make([]byte, maxBodySize+1, maxBodySize+1) e.POST("/").WithBytes(largerBSent).Expect().Status(httptest.StatusBadRequest).Body().Equal("http: request body too large") + + // test the post value (both post and put) and headers. + e.PUT("/postvalue").WithFormField("name", "test_put"). + WithHeader("headername", "headervalue_put").Expect(). + Status(httptest.StatusOK).Body().Equal("Hello test_put | headervalue_put") + + e.POST("/postvalue").WithFormField("name", "test_post"). + WithHeader("headername", "headervalue_post").Expect(). + Status(httptest.StatusOK).Body().Equal("Hello test_post | headervalue_post") } diff --git a/_examples/view/overview/main.go b/_examples/view/overview/main.go index a5ffca0d..38756d93 100644 --- a/_examples/view/overview/main.go +++ b/_examples/view/overview/main.go @@ -1,8 +1,6 @@ package main -import ( - "github.com/kataras/iris" -) +import "github.com/kataras/iris" func main() { app := iris.New() diff --git a/core/maintenance/version.go b/core/maintenance/version.go index ffed1c9c..04e68446 100644 --- a/core/maintenance/version.go +++ b/core/maintenance/version.go @@ -13,7 +13,7 @@ import ( const ( // Version is the string representation of the current local Iris Web Framework version. - Version = "10.0.0" + Version = "10.0.1" ) // CheckForUpdates checks for any available updates diff --git a/view/amber.go b/view/amber.go index 84d6d97f..056fbfa0 100644 --- a/view/amber.go +++ b/view/amber.go @@ -20,9 +20,8 @@ type AmberEngine struct { namesFn func() []string // for embedded, in combination with directory & extension reload bool // - rmu sync.RWMutex // locks for funcs + rmu sync.RWMutex // locks for `ExecuteWiter` when `reload` is true. funcs map[string]interface{} - mu sync.Mutex // locks for template files load templateCache map[string]*template.Template } @@ -57,6 +56,10 @@ func (s *AmberEngine) Binary(assetFn func(name string) ([]byte, error), namesFn // Reload if setted to true the templates are reloading on each render, // use it when you're in development and you're boring of restarting // the whole app when you edit a template file. +// +// Note that if `true` is passed then only one `View -> ExecuteWriter` will be render each time, +// no concurrent access across clients, use it only on development status. +// It's good to be used side by side with the https://github.com/kataras/rizla reloader for go source files. func (s *AmberEngine) Reload(developmentMode bool) *AmberEngine { s.reload = developmentMode return s @@ -116,8 +119,6 @@ func (s *AmberEngine) loadDirectory() error { templates, err := amber.CompileDir(dir, opt, amber.DefaultOptions) // this returns the map with stripped extension, we want extension so we copy the map if err == nil { - s.mu.Lock() - defer s.mu.Unlock() s.templateCache = make(map[string]*template.Template) for k, v := range templates { name := filepath.ToSlash(k + opt.Ext) @@ -155,9 +156,6 @@ func (s *AmberEngine) loadAssets() error { } amber.FuncMap = funcs //set the funcs - s.mu.Lock() - defer s.mu.Unlock() - names := namesFn() for _, path := range names { @@ -192,21 +190,22 @@ func (s *AmberEngine) loadAssets() error { } func (s *AmberEngine) fromCache(relativeName string) *template.Template { - s.mu.Lock() tmpl, ok := s.templateCache[relativeName] if ok { - s.mu.Unlock() return tmpl } - s.mu.Unlock() return nil } // ExecuteWriter executes a template and writes its result to the w writer. // layout here is useless. func (s *AmberEngine) ExecuteWriter(w io.Writer, filename string, layout string, bindingData interface{}) error { - // reload the templates if reload configuration field is true + // re-parse the templates if reload is enabled. if s.reload { + // locks to fix #872, it's the simplest solution and the most correct, + // to execute writers with "wait list", one at a time. + s.rmu.Lock() + defer s.rmu.Unlock() if err := s.Load(); err != nil { return err } diff --git a/view/django.go b/view/django.go index 5dbe1118..47817b98 100644 --- a/view/django.go +++ b/view/django.go @@ -106,7 +106,7 @@ type DjangoEngine struct { namesFn func() []string // for embedded, in combination with directory & extension reload bool // - rmu sync.RWMutex // locks for filters and globals + rmu sync.RWMutex // locks for filters, globals and `ExecuteWiter` when `reload` is true. // filters for pongo2, map[name of the filter] the filter function . The filters are auto register filters map[string]FilterFunction // globals share context fields between templates. https://github.com/flosch/pongo2/issues/35 @@ -147,6 +147,10 @@ func (s *DjangoEngine) Binary(assetFn func(name string) ([]byte, error), namesFn // Reload if setted to true the templates are reloading on each render, // use it when you're in development and you're boring of restarting // the whole app when you edit a template file. +// +// Note that if `true` is passed then only one `View -> ExecuteWriter` will be render each time, +// no concurrent access across clients, use it only on development status. +// It's good to be used side by side with the https://github.com/kataras/rizla reloader for go source files. func (s *DjangoEngine) Reload(developmentMode bool) *DjangoEngine { s.reload = developmentMode return s @@ -373,8 +377,12 @@ func (s *DjangoEngine) fromCache(relativeName string) *pongo2.Template { // ExecuteWriter executes a templates and write its results to the w writer // layout here is useless. func (s *DjangoEngine) ExecuteWriter(w io.Writer, filename string, layout string, bindingData interface{}) error { - // reload the templates if reload configuration field is true + // re-parse the templates if reload is enabled. if s.reload { + // locks to fix #872, it's the simplest solution and the most correct, + // to execute writers with "wait list", one at a time. + s.rmu.Lock() + defer s.rmu.Unlock() if err := s.Load(); err != nil { return err } diff --git a/view/handlebars.go b/view/handlebars.go index fac1d85e..bfede2be 100644 --- a/view/handlebars.go +++ b/view/handlebars.go @@ -22,9 +22,8 @@ type HandlebarsEngine struct { reload bool // if true, each time the ExecuteWriter is called the templates will be reloaded. // parser configuration layout string - rmu sync.RWMutex // locks for helpers + rmu sync.RWMutex // locks for helpers and `ExecuteWiter` when `reload` is true. helpers map[string]interface{} - mu sync.Mutex // locks for template files load templateCache map[string]*raymond.Template } @@ -66,6 +65,10 @@ func (s *HandlebarsEngine) Binary(assetFn func(name string) ([]byte, error), nam // Reload if setted to true the templates are reloading on each render, // use it when you're in development and you're boring of restarting // the whole app when you edit a template file. +// +// Note that if `true` is passed then only one `View -> ExecuteWriter` will be render each time, +// no concurrent access across clients, use it only on development status. +// It's good to be used side by side with the https://github.com/kataras/rizla reloader for go source files. func (s *HandlebarsEngine) Reload(developmentMode bool) *HandlebarsEngine { s.reload = developmentMode return s @@ -123,8 +126,7 @@ func (s *HandlebarsEngine) loadDirectory() error { // the render works like {{ render "myfile.html" theContext.PartialContext}} // instead of the html/template engine which works like {{ render "myfile.html"}} and accepts the parent binding, with handlebars we can't do that because of lack of runtime helpers (dublicate error) - s.mu.Lock() - defer s.mu.Unlock() + var templateErr error filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { if info == nil || info.IsDir() { @@ -181,9 +183,6 @@ func (s *HandlebarsEngine) loadAssets() error { } var templateErr error - s.mu.Lock() - defer s.mu.Unlock() - names := namesFn() for _, path := range names { if !strings.HasPrefix(path, virtualDirectory) { @@ -219,14 +218,11 @@ func (s *HandlebarsEngine) loadAssets() error { } func (s *HandlebarsEngine) fromCache(relativeName string) *raymond.Template { - s.mu.Lock() tmpl, ok := s.templateCache[relativeName] - if ok { - s.mu.Unlock() - return tmpl + if !ok { + return nil } - s.mu.Unlock() - return nil + return tmpl } func (s *HandlebarsEngine) executeTemplateBuf(name string, binding interface{}) (string, error) { @@ -238,8 +234,12 @@ func (s *HandlebarsEngine) executeTemplateBuf(name string, binding interface{}) // ExecuteWriter executes a template and writes its result to the w writer. func (s *HandlebarsEngine) ExecuteWriter(w io.Writer, filename string, layout string, bindingData interface{}) error { - // reload the templates if reload configuration field is true + // re-parse the templates if reload is enabled. if s.reload { + // locks to fix #872, it's the simplest solution and the most correct, + // to execute writers with "wait list", one at a time. + s.rmu.Lock() + defer s.rmu.Unlock() if err := s.Load(); err != nil { return err } diff --git a/view/html.go b/view/html.go index 0b2747e7..24bb20ea 100644 --- a/view/html.go +++ b/view/html.go @@ -10,6 +10,7 @@ import ( "path/filepath" "strings" "sync" + "time" ) type ( @@ -20,7 +21,7 @@ type ( extension string assetFn func(name string) ([]byte, error) // for embedded, in combination with directory & extension namesFn func() []string // for embedded, in combination with directory & extension - reload bool // if true, each time the ExecuteWriter is called the templates will be reloaded. + reload bool // if true, each time the ExecuteWriter is called the templates will be reloaded, each ExecuteWriter waits to be finished before writing to a new one. // parser configuration options []string // text options left string @@ -32,7 +33,6 @@ type ( // middleware func(name string, contents string) (string, error) - mu sync.Mutex // locks for template files loader Templates *template.Template // } @@ -94,6 +94,10 @@ func (s *HTMLEngine) Binary(assetFn func(name string) ([]byte, error), namesFn f // Reload if setted to true the templates are reloading on each render, // use it when you're in development and you're boring of restarting // the whole app when you edit a template file. +// +// Note that if `true` is passed then only one `View -> ExecuteWriter` will be render each time, +// no concurrent access across clients, use it only on development status. +// It's good to be used side by side with the https://github.com/kataras/rizla reloader for go source files. func (s *HTMLEngine) Reload(developmentMode bool) *HTMLEngine { s.reload = developmentMode return s @@ -118,9 +122,9 @@ func (s *HTMLEngine) Reload(developmentMode bool) *HTMLEngine { // Execution stops immediately with an error. // func (s *HTMLEngine) Option(opt ...string) *HTMLEngine { - s.mu.Lock() + s.rmu.Lock() s.options = append(s.options, opt...) - s.mu.Unlock() + s.rmu.Unlock() return s } @@ -180,6 +184,15 @@ func (s *HTMLEngine) AddFunc(funcName string, funcBody interface{}) { // // Returns an error if something bad happens, user is responsible to catch it. func (s *HTMLEngine) Load() error { + // No need to make this with a complicated and "pro" way, just add lockers to the `ExecuteWriter`. + // if `Reload(true)` and add a note for non conc access on dev mode. + // atomic.StoreUint32(&s.isLoading, 1) + // s.rmu.Lock() + // defer func() { + // s.rmu.Unlock() + // atomic.StoreUint32(&s.isLoading, 0) + // }() + if s.assetFn != nil && s.namesFn != nil { // NOT NECESSARY "fix" of https://github.com/kataras/iris/issues/784, // IT'S BAD CODE WRITTEN WE KEEP HERE ONLY FOR A REMINDER @@ -256,10 +269,10 @@ func (s *HTMLEngine) loadDirectory() error { templateErr = err return err } - s.mu.Lock() + //s.mu.Lock() // Add our funcmaps. _, err = tmpl.Funcs(emptyFuncs).Funcs(s.funcs).Parse(contents) - s.mu.Unlock() + //s.mu.Unlock() if err != nil { templateErr = err return err @@ -406,11 +419,10 @@ func (s *HTMLEngine) layoutFuncsFor(name string, binding interface{}) { return template.HTML(buf.String()), err }, } - s.rmu.RLock() + for k, v := range s.layoutFuncs { funcs[k] = v } - s.rmu.RUnlock() if tpl := s.Templates.Lookup(name); tpl != nil { tpl.Funcs(funcs) } @@ -429,10 +441,16 @@ func (s *HTMLEngine) runtimeFuncsFor(name string, binding interface{}) { } } +var zero = time.Time{} + // ExecuteWriter executes a template and writes its result to the w writer. func (s *HTMLEngine) ExecuteWriter(w io.Writer, name string, layout string, bindingData interface{}) error { - // reload the templates if reload configuration field is true + // re-parse the templates if reload is enabled. if s.reload { + // locks to fix #872, it's the simplest solution and the most correct, + // to execute writers with "wait list", one at a time. + s.rmu.Lock() + defer s.rmu.Unlock() if err := s.Load(); err != nil { return err }