mirror of
https://github.com/minio/mc.git
synced 2025-11-12 01:02:26 +03:00
216 lines
6.3 KiB
Go
216 lines
6.3 KiB
Go
/*
|
||
* Minio Client (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"
|
||
"net/http"
|
||
"runtime"
|
||
"strings"
|
||
"time"
|
||
|
||
"github.com/fatih/color"
|
||
"github.com/minio/cli"
|
||
"github.com/minio/mc/pkg/console"
|
||
"github.com/minio/minio-xl/pkg/probe"
|
||
)
|
||
|
||
// Check for new software updates.
|
||
var updateCmd = cli.Command{
|
||
Name: "update",
|
||
Usage: "Check for new software updates.",
|
||
Action: mainUpdate,
|
||
CustomHelpTemplate: `Name:
|
||
mc {{.Name}} - {{.Usage}}
|
||
|
||
USAGE:
|
||
mc {{.Name}} release
|
||
mc {{.Name}} experimental
|
||
|
||
EXAMPLES:
|
||
1. Check for new official releases
|
||
$ mc {{.Name}} release
|
||
|
||
2. Check for new experimental releases
|
||
$ mc {{.Name}} experimental
|
||
`,
|
||
}
|
||
|
||
// Updates container to hold updates json
|
||
type Updates struct {
|
||
BuildDate string
|
||
Platforms map[string]string
|
||
}
|
||
|
||
// UpdateMessage container to hold update messages
|
||
type UpdateMessage struct {
|
||
Update bool `json:"update"`
|
||
Download string `json:"downloadURL"`
|
||
Version string `json:"version"`
|
||
}
|
||
|
||
// String colorized update message
|
||
func (u UpdateMessage) String() string {
|
||
if u.Update {
|
||
var msg string
|
||
if runtime.GOOS == "windows" {
|
||
msg = "mc.exe cp " + u.Download + " .\\mc.exe"
|
||
} else {
|
||
msg = "mc cp " + u.Download + " ./mc.new; chmod 755 ./mc.new"
|
||
}
|
||
msg, err := colorizeUpdateMessage(msg)
|
||
fatalIf(err.Trace(msg), "Unable to colorize experimental update notification string ‘"+msg+"’.")
|
||
return msg
|
||
}
|
||
return console.Colorize("UpdateMessage", "You are already running the most recent version of ‘mc’.")
|
||
}
|
||
|
||
// JSON jsonified update message
|
||
func (u UpdateMessage) JSON() string {
|
||
updateMessageJSONBytes, err := json.Marshal(u)
|
||
fatalIf(probe.NewError(err), "Unable to marshal into JSON.")
|
||
|
||
return string(updateMessageJSONBytes)
|
||
}
|
||
|
||
const (
|
||
mcUpdateURL = "https://dl.minio.io:9000/updates/updates.json"
|
||
mcExperimentalURL = "https://dl.minio.io:9000/updates/experimental.json"
|
||
)
|
||
|
||
func checkUpdateSyntax(ctx *cli.Context) {
|
||
if ctx.Args().First() == "help" || !ctx.Args().Present() {
|
||
cli.ShowCommandHelpAndExit(ctx, "update", 1) // last argument is exit code
|
||
}
|
||
arg := strings.TrimSpace(ctx.Args().First())
|
||
if arg != "release" && arg != "experimental" {
|
||
fatalIf(errInvalidArgument().Trace(arg), "Unrecognized argument provided.")
|
||
}
|
||
}
|
||
|
||
func setUpdatePalette(style string) {
|
||
console.SetCustomPalette(map[string]*color.Color{
|
||
"UpdateMessage": color.New(color.FgGreen, color.Bold),
|
||
})
|
||
if style == "light" {
|
||
console.SetCustomPalette(map[string]*color.Color{
|
||
"UpdateMessage": color.New(color.FgWhite, color.Bold),
|
||
})
|
||
return
|
||
}
|
||
/// Add more styles here
|
||
if style == "nocolor" {
|
||
// All coloring options exhausted, setting nocolor safely
|
||
console.SetNoColor()
|
||
}
|
||
}
|
||
|
||
// mainUpdate -
|
||
func mainUpdate(ctx *cli.Context) {
|
||
checkUpdateSyntax(ctx)
|
||
|
||
setUpdatePalette(ctx.GlobalString("colors"))
|
||
|
||
arg := strings.TrimSpace(ctx.Args().First())
|
||
switch arg {
|
||
case "release":
|
||
getReleaseUpdate()
|
||
case "experimental":
|
||
getExperimentalUpdate()
|
||
}
|
||
}
|
||
|
||
func getExperimentalUpdate() {
|
||
clnt, err := url2Client(mcExperimentalURL)
|
||
fatalIf(err.Trace(mcExperimentalURL), "Unable to initalize experimental URL.")
|
||
|
||
data, _, err := clnt.GetObject(0, 0)
|
||
fatalIf(err.Trace(mcExperimentalURL), "Unable to read from experimental URL ‘"+mcExperimentalURL+"’.")
|
||
|
||
current, e := time.Parse(http.TimeFormat, mcVersion)
|
||
fatalIf(probe.NewError(e), "Unable to parse Version string as time.")
|
||
|
||
if current.IsZero() {
|
||
fatalIf(errDummy().Trace(), "Experimental updates not supported for custom build. Version field is empty. Please download official releases from https://dl.minio.io:9000")
|
||
}
|
||
|
||
var experimentals Updates
|
||
decoder := json.NewDecoder(data)
|
||
e = decoder.Decode(&experimentals)
|
||
fatalIf(probe.NewError(e), "Unable to decode experimental update notification.")
|
||
|
||
latest, e := time.Parse(http.TimeFormat, experimentals.BuildDate)
|
||
fatalIf(probe.NewError(e), "Unable to parse BuildDate.")
|
||
|
||
if latest.IsZero() {
|
||
fatalIf(errDummy().Trace(), "Unable to validate any experimental update available at this time. Please open an issue at https://github.com/minio/mc/issues")
|
||
}
|
||
|
||
mcExperimentalURLParse := clnt.URL()
|
||
downloadURL := (mcExperimentalURLParse.Scheme + "://" +
|
||
mcExperimentalURLParse.Host +
|
||
string(mcExperimentalURLParse.Separator) +
|
||
experimentals.Platforms[runtime.GOOS])
|
||
|
||
updateMessage := UpdateMessage{
|
||
Download: downloadURL,
|
||
Version: mcVersion,
|
||
}
|
||
if latest.After(current) {
|
||
updateMessage.Update = true
|
||
}
|
||
Prints("%s\n", updateMessage)
|
||
}
|
||
|
||
func getReleaseUpdate() {
|
||
clnt, err := url2Client(mcUpdateURL)
|
||
fatalIf(err.Trace(mcUpdateURL), "Unable to initalize update URL.")
|
||
|
||
data, _, err := clnt.GetObject(0, 0)
|
||
fatalIf(err.Trace(mcUpdateURL), "Unable to read from update URL ‘"+mcUpdateURL+"’.")
|
||
|
||
current, e := time.Parse(http.TimeFormat, mcVersion)
|
||
fatalIf(probe.NewError(e), "Unable to parse Version string as time.")
|
||
|
||
if current.IsZero() {
|
||
fatalIf(errDummy().Trace(), "Updates not supported for custom build. Version field is empty. Please download official releases from https://dl.minio.io:9000")
|
||
}
|
||
|
||
var updates Updates
|
||
decoder := json.NewDecoder(data)
|
||
e = decoder.Decode(&updates)
|
||
fatalIf(probe.NewError(e), "Unable to decode update notification.")
|
||
|
||
latest, e := time.Parse(http.TimeFormat, updates.BuildDate)
|
||
fatalIf(probe.NewError(e), "Unable to parse BuildDate.")
|
||
|
||
if latest.IsZero() {
|
||
fatalIf(errDummy().Trace(), "Unable to validate any update available at this time. Please open an issue at https://github.com/minio/mc/issues")
|
||
}
|
||
|
||
mcUpdateURLParse := clnt.URL()
|
||
downloadURL := mcUpdateURLParse.Scheme + "://" + mcUpdateURLParse.Host + string(mcUpdateURLParse.Separator) + updates.Platforms[runtime.GOOS]
|
||
updateMessage := UpdateMessage{
|
||
Download: downloadURL,
|
||
Version: mcVersion,
|
||
}
|
||
if latest.After(current) {
|
||
updateMessage.Update = true
|
||
}
|
||
Prints("%s\n", updateMessage)
|
||
}
|