github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/cmd/update-notifier.go (about) 1 // Copyright (c) 2015-2022 MinIO, Inc. 2 // 3 // This file is part of MinIO Object Storage stack 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package cmd 19 20 import ( 21 "fmt" 22 "math" 23 "runtime" 24 "strings" 25 "time" 26 27 "github.com/cheggaaa/pb" 28 humanize "github.com/dustin/go-humanize" 29 ) 30 31 // prepareUpdateMessage - prepares the update message, only if a 32 // newer version is available. 33 func prepareUpdateMessage(downloadURL string, older time.Duration) string { 34 if downloadURL == "" || older <= 0 { 35 return "" 36 } 37 38 // Compute friendly duration string to indicate time 39 // difference between newer and current release. 40 t := time.Time{} 41 newerThan := humanize.RelTime(t, t.Add(older), "ago", "") 42 43 // Return the nicely colored and formatted update message. 44 return colorizeUpdateMessage(downloadURL, newerThan) 45 } 46 47 // colorizeUpdateMessage - inspired from Yeoman project npm package https://github.com/yeoman/update-notifier 48 func colorizeUpdateMessage(updateString, newerThan string) string { 49 msgLine1Fmt := " You are running an older version of mc released %s " 50 msgLine2Fmt := " Update: %s " 51 52 // Calculate length *without* color coding: with ANSI terminal 53 // color characters, the result is incorrect. 54 line1Length := len(fmt.Sprintf(msgLine1Fmt, newerThan)) 55 line2Length := len(fmt.Sprintf(msgLine2Fmt, updateString)) 56 57 // Populate lines with color coding. 58 line1InColor := fmt.Sprintf(msgLine1Fmt, colorYellowBold(newerThan)) 59 line2InColor := fmt.Sprintf(msgLine2Fmt, colorCyanBold(updateString)) 60 61 // calculate the rectangular box size. 62 maxContentWidth := int(math.Max(float64(line1Length), float64(line2Length))) 63 64 // termWidth is set to a default one to use when we are 65 // not able to calculate terminal width via OS syscalls 66 termWidth := 25 67 if width, err := pb.GetTerminalWidth(); err == nil { 68 termWidth = width 69 } 70 71 // Box cannot be printed if terminal width is small than maxContentWidth 72 if maxContentWidth > termWidth { 73 return "\n" + line1InColor + "\n" + line2InColor + "\n\n" 74 } 75 76 topLeftChar := "┏" 77 topRightChar := "┓" 78 bottomLeftChar := "┗" 79 bottomRightChar := "┛" 80 horizBarChar := "━" 81 vertBarChar := "┃" 82 // on windows terminal turn off unicode characters. 83 if runtime.GOOS == "windows" { 84 topLeftChar = "+" 85 topRightChar = "+" 86 bottomLeftChar = "+" 87 bottomRightChar = "+" 88 horizBarChar = "-" 89 vertBarChar = "|" 90 } 91 92 lines := []string{ 93 colorYellowBold(topLeftChar + strings.Repeat(horizBarChar, maxContentWidth) + topRightChar), 94 vertBarChar + line1InColor + strings.Repeat(" ", maxContentWidth-line1Length) + vertBarChar, 95 vertBarChar + line2InColor + strings.Repeat(" ", maxContentWidth-line2Length) + vertBarChar, 96 colorYellowBold(bottomLeftChar + strings.Repeat(horizBarChar, maxContentWidth) + bottomRightChar), 97 } 98 return "\n" + strings.Join(lines, "\n") + "\n" 99 }