1
0
mirror of https://github.com/kataras/iris.git synced 2026-01-10 05:25:58 +00:00

Update to version 8.5.5 | Read HISTORY.md

Former-commit-id: dced7d472edabbab4f80c76051f13261928a8dea
This commit is contained in:
kataras
2017-11-02 05:54:33 +02:00
parent 666bcacf20
commit 15feaf0237
100 changed files with 13338 additions and 13155 deletions

View File

@@ -0,0 +1,93 @@
package maintenance
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/url"
"github.com/kataras/iris/core/maintenance/client"
"github.com/kataras/iris/core/maintenance/encoding"
"github.com/kataras/survey"
)
// question describes the question which will be used
// for the survey in order to authenticate the local iris.
type question struct {
Message string `json:"message"`
}
func hasInternetConnection() (bool, bool) {
r, err := client.PostForm("", nil)
if err != nil {
// no internet connection
return false, false
}
defer r.Body.Close()
return true, r.StatusCode == 204
}
func ask() bool {
qs := fetchQuestions()
var lastResponseUnsed string
for _, q := range qs {
survey.AskOne(&survey.Input{Message: q.Message}, &lastResponseUnsed, validate(q))
}
return lastResponseUnsed != ""
}
// fetchQuestions returns a list of questions
// fetched by the authority server.
func fetchQuestions() (qs []question) {
r, err := client.PostForm("/survey/ask", nil)
if err != nil {
return
}
defer r.Body.Close()
if err := encoding.UnmarshalBody(r.Body, &qs, json.Unmarshal); err != nil {
return
}
return
}
func validate(q question) survey.Validator {
return func(answer interface{}) error {
if err := survey.Required(answer); err != nil {
return err
}
ans, ok := answer.(string)
if !ok {
return fmt.Errorf("bug: expected string but got %v", answer)
}
data := url.Values{
"q": []string{q.Message},
"ans": []string{ans},
"current_version": []string{Version},
}
r, err := client.PostForm("/survey/submit", data)
if err != nil {
// error from server-side, allow.
return nil
}
defer r.Body.Close()
if r.StatusCode == 200 {
// read the whole thing, it has nothing.
io.Copy(ioutil.Discard, r.Body)
return nil // pass, no any errors.
}
// now, if invalid;
got, err := ioutil.ReadAll(r.Body)
if err != nil {
return nil
}
errMsg := string(got)
return fmt.Errorf(errMsg)
}
}

View File

@@ -0,0 +1,41 @@
package client
import (
"bytes"
"net"
"net/http"
"net/url"
"time"
"github.com/kataras/iris/core/netutil"
)
const host = "http://live.iris-go.com"
// PostForm performs the PostForm with a secure client.
func PostForm(p string, data url.Values) (*http.Response, error) {
client := netutil.Client(25 * time.Second)
if len(data) == 0 {
data = make(url.Values, 1)
}
data.Set("X-Auth", a)
u := host + p
r, err := client.PostForm(u, data)
return r, err
}
var a string
func init() {
interfaces, err := net.Interfaces()
if err == nil {
for _, f := range interfaces {
if f.Flags&net.FlagUp != 0 && bytes.Compare(f.HardwareAddr, nil) != 0 {
a = f.HardwareAddr.String()
break
}
}
}
}

View File

@@ -0,0 +1,33 @@
package encoding
import (
"errors"
"io"
"io/ioutil"
"reflect"
)
// UnmarshalerFunc is the Unmarshaler compatible type.
//
// See 'unmarshalBody' for more.
type UnmarshalerFunc func(data []byte, v interface{}) error
// UnmarshalBody reads the request's body and binds it to a value or pointer of any type.
func UnmarshalBody(body io.Reader, v interface{}, unmarshaler UnmarshalerFunc) error {
if body == nil {
return errors.New("unmarshal: empty body")
}
rawData, err := ioutil.ReadAll(body)
if err != nil {
return err
}
// check if v is already a pointer, if yes then pass as it's
if reflect.TypeOf(v).Kind() == reflect.Ptr {
return unmarshaler(rawData, v)
}
// finally, if the v doesn't contains a self-body decoder and it's not a pointer
// use the custom unmarshaler to bind the body
return unmarshaler(rawData, &v)
}

View File

@@ -0,0 +1,6 @@
package maintenance
// Start starts the maintenance process.
func Start() {
CheckForUpdates()
}

View File

@@ -0,0 +1,83 @@
package maintenance
import (
"fmt"
"os"
"os/exec"
"github.com/kataras/iris/core/maintenance/version"
"github.com/kataras/golog"
"github.com/kataras/survey"
)
const (
// Version is the string representation of the current local Iris Web Framework version.
Version = "8.5.5"
)
// CheckForUpdates checks for any available updates
// and asks for the user if want to update now or not.
func CheckForUpdates() {
v := version.Acquire()
updateAvailale := v.Compare(Version) == version.Smaller
if updateAvailale {
has, ft := hasInternetConnection()
canUpdate := (has && ft && ask()) || !has || !ft
if canUpdate {
installVersion(v)
}
}
}
func installVersion(v version.Version) {
// on help? when asking for installing the new update
// and when answering "No".
ignoreUpdatesMsg := "Would you like to ignore future updates? Disable the version checker via:\napp.Run(..., iris.WithoutVersionChecker)"
// if update available ask for update action.
shouldUpdateNowMsg :=
fmt.Sprintf("A new version is available online[%s < %s].\nRelease notes: %s.\nUpdate now?",
Version, v.String(),
v.ChangelogURL)
var confirmUpdate bool
survey.AskOne(&survey.Confirm{
Message: shouldUpdateNowMsg,
Help: ignoreUpdatesMsg,
}, &confirmUpdate, nil)
// run the updater last, so the user can star the repo and at the same time
// the app will update her/his local iris.
if confirmUpdate { // it's true only when update was available and user typed "yes".
repo := "github.com/kataras/iris/..."
cmd := exec.Command("go", "get", "-u", "-v", repo)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stdout
if err := cmd.Run(); err != nil {
golog.Warnf("unexpected message while trying to go get,\nif you edited the original source code then you've to remove the whole $GOPATH/src/github.com/kataras folder and execute `go get -u github.com/kataras/iris/...` manually\n%v", err)
return
}
golog.Infof("Update process finished.\nManual rebuild and restart is required to apply the changes...\n")
return
}
// if update was available but chosen not to update then just continue...
}
/* Author's note:
We could use github webhooks to automatic notify for updates
when a new update is pushed to the repository
even when server is already started and running but this would expose
a route which dev may don't know about, so let it for now but if
they ask it then I should add an optional configuration field
to "live/realtime update" and implement the idea (which is already implemented in the iris-go server).
*/
/* Author's note:
The old remote endpoint for version checker is still available on the server for backwards
compatibility with older clients, it will stay there for a long period of time.
*/

View File

@@ -0,0 +1,59 @@
package version
import (
"io/ioutil"
"strings"
"time"
"github.com/hashicorp/go-version"
"github.com/kataras/golog"
"github.com/kataras/iris/core/netutil"
)
const (
versionURL = "https://raw.githubusercontent.com/kataras/iris/master/VERSION"
)
func fetch() (*version.Version, string) {
client := netutil.Client(time.Duration(30 * time.Second))
r, err := client.Get(versionURL)
if err != nil {
golog.Debugf("err: %v\n", err)
return nil, ""
}
defer r.Body.Close()
if r.StatusCode >= 400 {
golog.Debugf("Internet connection is missing, updater is unable to fetch the latest Iris version\n", err)
return nil, ""
}
b, err := ioutil.ReadAll(r.Body)
if len(b) == 0 || err != nil {
golog.Debugf("err: %v\n", err)
return nil, ""
}
var (
fetchedVersion = string(b)
changelogURL string
)
// Example output:
// Version(8.5.5)
// 8.5.5:https://github.com/kataras/iris/blob/master/HISTORY.md#tu-02-november-2017--v855
if idx := strings.IndexByte(fetchedVersion, ':'); idx > 0 {
changelogURL = fetchedVersion[idx+1:]
fetchedVersion = fetchedVersion[0:idx]
}
latestVersion, err := version.NewVersion(fetchedVersion)
if err != nil {
golog.Debugf("while fetching and parsing latest version from github: %v\n", err)
return nil, ""
}
return latestVersion, changelogURL
}

View File

@@ -0,0 +1,64 @@
package version
import (
"time"
"github.com/hashicorp/go-version"
)
// Version is a version wrapper which
// contains some additional customized properties.
type Version struct {
version.Version
WrittenAt time.Time
ChangelogURL string
}
// Result is the compare result type.
// Available types are Invalid, Smaller, Equal or Larger.
type Result int32
const (
// Smaller when the compared version is smaller than the latest one.
Smaller Result = -1
// Equal when the compared version is equal with the latest one.
Equal Result = 0
// Larger when the compared version is larger than the latest one.
Larger Result = 1
// Invalid means that an error occurred when comparing the versions.
Invalid Result = -2
)
// Compare compares the "versionStr" with the latest Iris version,
// opossite to the version package
// it returns the result of the "versionStr" not the "v" itself.
func (v *Version) Compare(versionStr string) Result {
if len(v.Version.String()) == 0 {
// if version not refreshed, by an internet connection lose,
// then return Invalid.
return Invalid
}
other, err := version.NewVersion(versionStr)
if err != nil {
return Invalid
}
return Result(other.Compare(&v.Version))
}
// Acquire returns the latest version info wrapper.
// It calls the fetch.
func Acquire() (v Version) {
newVersion, changelogURL := fetch()
if newVersion == nil { // if github was down then don't panic, just set it as the smallest version.
newVersion, _ = version.NewVersion("0.0.1")
}
v = Version{
Version: *newVersion,
WrittenAt: time.Now(),
ChangelogURL: changelogURL,
}
return
}