/* * Minio Cloud Storage, (C) 2015 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package main import ( "encoding/json" "errors" "net/http" "net/url" "runtime" "time" "github.com/fatih/color" "github.com/minio/cli" "github.com/minio/minio-xl/pkg/probe" ) // command specific flags. var ( updateFlags = []cli.Flag{ cli.BoolFlag{ Name: "help, h", Usage: "Help for update.", }, cli.BoolFlag{ Name: "experimental, E", Usage: "Check experimental update.", }, } ) // Check for new software updates. var updateCmd = cli.Command{ Name: "update", Usage: "Check for a new software update.", Action: mainUpdate, Flags: updateFlags, CustomHelpTemplate: `Name: minio {{.Name}} - {{.Usage}} USAGE: minio {{.Name}} [FLAGS] FLAGS: {{range .Flags}}{{.}} {{end}} EXAMPLES: 1. Check for any new official release. $ minio {{.Name}} 2. Check for any new experimental release. $ minio {{.Name}} --experimental `, } // update URL endpoints. const ( minioUpdateStableURL = "https://dl.minio.io:9000/updates/updates.json" minioUpdateExperimentalURL = "https://dl.minio.io:9000/updates/experimental.json" ) // minioUpdates container to hold updates json. type minioUpdates struct { BuildDate string Platforms map[string]string } // updateMessage container to hold update messages. type updateMessage struct { Status string `json:"status"` Update bool `json:"update"` Download string `json:"downloadURL"` Version string `json:"version"` } // String colorized update message. func (u updateMessage) String() string { if !u.Update { updateMessage := color.New(color.FgGreen, color.Bold).SprintfFunc() return updateMessage("You are already running the most recent version of ‘minio’.") } var msg string if runtime.GOOS == "windows" { msg = "Download " + u.Download } else { msg = "Download " + u.Download } msg, err := colorizeUpdateMessage(msg) fatalIf(err.Trace(msg), "Unable to colorize experimental update notification string ‘"+msg+"’.", nil) return msg } // JSON jsonified update message. func (u updateMessage) JSON() string { u.Status = "success" updateMessageJSONBytes, err := json.Marshal(u) fatalIf(probe.NewError(err), "Unable to marshal into JSON.", nil) return string(updateMessageJSONBytes) } // verify updates for releases. func getReleaseUpdate(updateURL string) { data, e := http.Get(updateURL) fatalIf(probe.NewError(e), "Unable to read from update URL ‘"+updateURL+"’.", nil) if minioVersion == "UNOFFICIAL.GOGET" { fatalIf(probe.NewError(errors.New("")), "Update mechanism is not supported for ‘go get’ based binary builds. Please download official releases from https://minio.io/#minio", nil) } current, e := time.Parse(time.RFC3339, minioVersion) fatalIf(probe.NewError(e), "Unable to parse version string as time.", nil) if current.IsZero() { fatalIf(probe.NewError(errors.New("")), "Updates not supported for custom builds. Version field is empty. Please download official releases from https://minio.io/#minio", nil) } var updates minioUpdates decoder := json.NewDecoder(data.Body) e = decoder.Decode(&updates) fatalIf(probe.NewError(e), "Unable to decode update notification.", nil) latest, e := time.Parse(time.RFC3339, updates.BuildDate) if e != nil { latest, e = time.Parse(http.TimeFormat, updates.BuildDate) fatalIf(probe.NewError(e), "Unable to parse BuildDate.", nil) } if latest.IsZero() { fatalIf(probe.NewError(errors.New("")), "Unable to validate any update available at this time. Please open an issue at https://github.com/minio/minio/issues", nil) } updateURLParse, err := url.Parse(updateURL) if err != nil { fatalIf(probe.NewError(err), "Unable to parse URL: "+updateURL, nil) } downloadURL := updateURLParse.Scheme + "://" + updateURLParse.Host + "/" + updates.Platforms[runtime.GOOS+"-"+runtime.GOARCH] updateMsg := updateMessage{ Download: downloadURL, Version: minioVersion, } if latest.After(current) { updateMsg.Update = true } Println(updateMsg) } // main entry point for update command. func mainUpdate(ctx *cli.Context) { // Check for update. if ctx.Bool("experimental") { getReleaseUpdate(minioUpdateExperimentalURL) } else { getReleaseUpdate(minioUpdateStableURL) } }