diff --git a/HISTORY.md b/HISTORY.md index 2ed273f6..b7b71028 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,6 +2,27 @@ **How to upgrade**: remove your `$GOPATH/src/github.com/kataras/iris` folder, open your command-line and execute this command: `go get -u github.com/kataras/iris`. +## 4.2.3 -> 4.2.4 + +- **NEW Experimental feature**: Updater with a `CheckForUpdates` [configuration](https://github.com/kataras/iris/blob/master/configuration.go) field, as requested [here](https://github.com/kataras/iris/issues/401) +```go +// CheckForUpdates will try to search for newer version of Iris based on the https://github.com/kataras/iris/releases +// If a newer version found then the app will ask the he dev/user if want to update the 'x' version +// if 'y' is pressed then the updater will try to install the latest version +// the updater, will notify the dev/user that the update is finished and should restart the App manually. +// Notes: +// 1. Experimental feature +// 2. If setted to true, the app will have a little startup delay +// 3. If you as developer edited the $GOPATH/src/github/kataras or any other Iris' Go dependencies at the past +// then the update process will fail. +// +// Usage: iris.Set(iris.OptionCheckForUpdates(true)) or +// iris.Config.CheckForUpdates = true or +// app := iris.New(iris.OptionCheckForUpdates(true)) +// Default is false +CheckForUpdates bool +``` + ## 4.2.2 -> 4.2.3 - [Add IsAjax() convenience method](https://github.com/kataras/iris/issues/423) diff --git a/README.md b/README.md index 452d5131..dc182b76 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@
-Releases +Releases Examples @@ -181,7 +181,7 @@ I recommend writing your API tests using this new library, [httpexpect](https:// Versioning ------------ -Current: **v4.2.3** +Current: **v4.2.4** > Iris is an active project @@ -224,7 +224,7 @@ License can be found [here](LICENSE). [Travis]: http://travis-ci.org/kataras/iris [License Widget]: https://img.shields.io/badge/license-Apache%202.0%20%20-E91E63.svg?style=flat-square [License]: https://github.com/kataras/iris/blob/master/LICENSE -[Release Widget]: https://img.shields.io/badge/release-v4.2.3-blue.svg?style=flat-square +[Release Widget]: https://img.shields.io/badge/release-v4.2.4-blue.svg?style=flat-square [Release]: https://github.com/kataras/iris/releases [Chat Widget]: https://img.shields.io/badge/community-chat-00BCD4.svg?style=flat-square [Chat]: https://kataras.rocket.chat/channel/iris diff --git a/configuration.go b/configuration.go index 7ecb970a..2b536357 100644 --- a/configuration.go +++ b/configuration.go @@ -41,6 +41,22 @@ func (o OptionSet) Set(c *Configuration) { // // Configuration is also implements the OptionSet so it's a valid option itself, this is briliant enough type Configuration struct { + // CheckForUpdates will try to search for newer version of Iris based on the https://github.com/kataras/iris/releases + // If a newer version found then the app will ask the he dev/user if want to update the 'x' version + // if 'y' is pressed then the updater will try to install the latest version + // the updater, will notify the dev/user that the update is finished and should restart the App manually. + // Notes: + // 1. Experimental feature + // 2. If setted to true, the app will have a little startup delay + // 3. If you as developer edited the $GOPATH/src/github/kataras or any other Iris' Go dependencies at the past + // then the update process will fail. + // + // Usage: iris.Set(iris.OptionCheckForUpdates(true)) or + // iris.Config.CheckForUpdates = true or + // app := iris.New(iris.OptionCheckForUpdates(true)) + // Default is false + CheckForUpdates bool + // DisablePathCorrection corrects and redirects the requested path to the registed path // for example, if /home/ path is requested but no handler for this Route found, // then the Router checks if /home handler exists, if yes, @@ -151,6 +167,27 @@ func (c Configuration) Set(main *Configuration) { // All options starts with "Option" preffix in order to be easier to find what dev searching for var ( + // OptionCheckForUpdates will try to search for newer version of Iris based on the https://github.com/kataras/iris/releases + // If a newer version found then the app will ask the he dev/user if want to update the 'x' version + // if 'y' is pressed then the updater will try to install the latest version + // the updater, will notify the dev/user that the update is finished and should restart the App manually. + // Notes: + // 1. Experimental feature + // 2. If setted to true, the app will have a little startup delay + // 3. If you as developer edited the $GOPATH/src/github/kataras or any other Iris' Go dependencies at the past + // then the update process will fail. + // + // Usage: iris.Set(iris.OptionCheckForUpdates(true)) or + // iris.Config.CheckForUpdates = true or + // app := iris.New(iris.OptionCheckForUpdates(true)) + // Default is false + OptionCheckForUpdates = func(val bool) OptionSet { + return func(c *Configuration) { + c.CheckForUpdates = val + } + + } + // OptionDisablePathCorrection corrects and redirects the requested path to the registed path // for example, if /home/ path is requested but no handler for this Route found, // then the Router checks if /home handler exists, if yes, @@ -163,12 +200,14 @@ var ( } } + // OptionDisablePathEscape when is false then its escapes the path, the named parameters (if any). OptionDisablePathEscape = func(val bool) OptionSet { return func(c *Configuration) { c.DisablePathEscape = val } } + // OptionDisableBanner outputs the iris banner at startup // // Default is false @@ -177,6 +216,7 @@ var ( c.DisableBanner = val } } + // OptionLoggerOut is the destination for output // // Default is os.Stdout @@ -185,6 +225,7 @@ var ( c.LoggerOut = val } } + // OptionLoggerPreffix is the logger's prefix to write at beginning of each line // // Default is [IRIS] @@ -193,6 +234,7 @@ var ( c.LoggerPreffix = val } } + // OptionProfilePath a the route path, set it to enable http pprof tool // Default is empty, if you set it to a $path, these routes will handled: OptionProfilePath = func(val string) OptionSet { @@ -200,6 +242,7 @@ var ( c.ProfilePath = val } } + // OptionDisableTemplateEngines set to true to disable loading the default template engine (html/template) and disallow the use of iris.UseEngine // Default is false OptionDisableTemplateEngines = func(val bool) OptionSet { @@ -207,6 +250,7 @@ var ( c.DisableTemplateEngines = val } } + // OptionIsDevelopment iris will act like a developer, for example // If true then re-builds the templates on each request // Default is false @@ -215,12 +259,14 @@ var ( c.IsDevelopment = val } } + // OptionTimeFormat time format for any kind of datetime parsing OptionTimeFormat = func(val string) OptionSet { return func(c *Configuration) { c.TimeFormat = val } } + // OptionCharset character encoding for various rendering // used for templates and the rest of the responses // Default is "UTF-8" @@ -229,6 +275,7 @@ var ( c.Charset = val } } + // OptionGzip enables gzip compression on your Render actions, this includes any type of render, templates and pure/raw content // If you don't want to enable it globaly, you could just use the third parameter on context.Render("myfileOrResponse", structBinding{}, iris.RenderOptions{"gzip": true}) // Default is false @@ -282,6 +329,7 @@ var ( // DefaultConfiguration returns the default configuration for an Iris station, fills the main Configuration func DefaultConfiguration() Configuration { return Configuration{ + CheckForUpdates: false, DisablePathCorrection: DefaultDisablePathCorrection, DisablePathEscape: DefaultDisablePathEscape, DisableBanner: false, diff --git a/iris.go b/iris.go index 91a56644..edeec268 100644 --- a/iris.go +++ b/iris.go @@ -77,8 +77,8 @@ import ( ) const ( - // Version of the iris - Version = "4.2.3" + // Version is the current version of the Iris web framework + Version = "4.2.4" banner = ` _____ _ |_ _| (_) @@ -257,6 +257,56 @@ func (s *Framework) Set(setters ...OptionSetter) { for _, setter := range setters { setter.Set(s.Config) } + + // because of the reason that an update can be executed while Iris is running, + // this is the only configuration field which is re-checked at runtime for that type of action. + // + // note: we could use the IsDevelopment configuration field to do that BUT + // the developer may want to check for updates without, for example, re-build template files (comes from IsDevelopment) on each request + if s.Config.CheckForUpdates { + if s.updateIris() { // if updated, then do not run the web server + exitWaitDuration := time.Duration(0) + if s.Logger != nil { + exitWaitDuration = 5 * time.Second + s.Logger.Println("exiting now...") + } + + time.AfterFunc(exitWaitDuration, func() { + os.Exit(0) + }) + } + } +} + +// global once because is not necessary to check for updates on more than one iris station* +var updateOnce sync.Once + +const ( + githubOwner = "kataras" + githubRepo = "iris" +) + +func (s *Framework) updateIris() bool { + updated := false + + updateOnce.Do(func() { + writer := s.Config.LoggerOut + + if writer == nil { + writer = os.Stdout // we need a writer because the update process will not be silent. + } + + fs.DefaultUpdaterAlreadyInstalledMessage = "INFO: Running with the latest version(%s)\n" + updater, err := fs.GetUpdater(githubOwner, githubRepo, Version) + + if err != nil { + writer.Write([]byte("Update failed: " + err.Error())) + } + + updated = updater.Run(fs.Stdout(writer), fs.Stderr(writer), fs.Silent(false)) + }) + + return updated } func (s *Framework) initialize() {