// Main starts mc application func Main() { // Enable profiling supported modes are [cpu, mem, block]. // ``MC_PROFILER`` supported options are [cpu, mem, block]. switch os.Getenv("MC_PROFILER") { case "cpu": defer profile.Start(profile.CPUProfile, profile.ProfilePath(mustGetProfileDir())).Stop() case "mem": defer profile.Start(profile.MemProfile, profile.ProfilePath(mustGetProfileDir())).Stop() case "block": defer profile.Start(profile.BlockProfile, profile.ProfilePath(mustGetProfileDir())).Stop() } probe.Init() // Set project's root source path. probe.SetAppInfo("Release-Tag", ReleaseTag) probe.SetAppInfo("Commit", ShortCommitID) app := registerApp() app.Before = registerBefore app.ExtraInfo = func() map[string]string { if _, e := pb.GetTerminalWidth(); e != nil { globalQuiet = true } if globalDebug { return getSystemData() } return make(map[string]string) } app.RunAndExitOnError() }
// colorizeUpdateMessage - inspired from Yeoman project npm package https://github.com/yeoman/update-notifier. func colorizeUpdateMessage(updateString string) (string, *probe.Error) { // initialize coloring cyan := color.New(color.FgCyan, color.Bold).SprintFunc() yellow := color.New(color.FgYellow, color.Bold).SprintfFunc() // calculate length without color coding, due to ANSI color characters padded to actual // string the final length is wrong than the original string length. line1Str := fmt.Sprintf(" New update available, please execute the following command to update: ") line2Str := fmt.Sprintf(" %s ", updateString) line1Length := len(line1Str) line2Length := len(line2Str) // populate lines with color coding. line1InColor := line1Str line2InColor := fmt.Sprintf(" %s ", cyan(updateString)) // calculate the rectangular box size. maxContentWidth := int(math.Max(float64(line1Length), float64(line2Length))) line1Rest := maxContentWidth - line1Length line2Rest := maxContentWidth - line2Length termWidth, e := pb.GetTerminalWidth() if e != nil { return "", probe.NewError(e) } var message string switch { case len(line2Str) > termWidth: message = "\n" + line1InColor + "\n" + line2InColor + "\n" default: // on windows terminal turn off unicode characters. var top, bottom, sideBar string if runtime.GOOS == "windows" { top = yellow("*" + strings.Repeat("*", maxContentWidth) + "*") bottom = yellow("*" + strings.Repeat("*", maxContentWidth) + "*") sideBar = yellow("|") } else { // color the rectangular box, use unicode characters here. top = yellow("┏" + strings.Repeat("━", maxContentWidth) + "┓") bottom = yellow("┗" + strings.Repeat("━", maxContentWidth) + "┛") sideBar = yellow("┃") } // fill spaces to the rest of the area. spacePaddingLine1 := strings.Repeat(" ", line1Rest) spacePaddingLine2 := strings.Repeat(" ", line2Rest) // construct the final message. message = "\n" + top + "\n" + sideBar + line1InColor + spacePaddingLine1 + sideBar + "\n" + sideBar + line2InColor + spacePaddingLine2 + sideBar + "\n" + bottom + "\n" } // return the final message return message, nil }
// colorizeUpdateMessage - inspired from Yeoman project npm package https://github.com/yeoman/update-notifier func colorizeUpdateMessage(updateString string) string { // Initialize coloring. cyan := color.New(color.FgCyan, color.Bold).SprintFunc() yellow := color.New(color.FgYellow, color.Bold).SprintfFunc() // Calculate length without color coding, due to ANSI color // characters padded to actual string the final length is wrong // than the original string length. line1Str := fmt.Sprintf(" New update: %s ", updateString) line1Length := len(line1Str) // Populate lines with color coding. line1InColor := fmt.Sprintf(" New update: %s ", cyan(updateString)) // Calculate the rectangular box size. maxContentWidth := line1Length line1Rest := maxContentWidth - line1Length // termWidth is set to a default one to use when we are // not able to calculate terminal width via OS syscalls termWidth := 25 if width, err := pb.GetTerminalWidth(); err == nil { termWidth = width } var message string switch { case len(line1Str) > termWidth: message = "\n" + line1InColor + "\n" default: // On windows terminal turn off unicode characters. var top, bottom, sideBar string if runtime.GOOS == "windows" { top = yellow("*" + strings.Repeat("*", maxContentWidth) + "*") bottom = yellow("*" + strings.Repeat("*", maxContentWidth) + "*") sideBar = yellow("|") } else { // Color the rectangular box, use unicode characters here. top = yellow("┏" + strings.Repeat("━", maxContentWidth) + "┓") bottom = yellow("┗" + strings.Repeat("━", maxContentWidth) + "┛") sideBar = yellow("┃") } // Fill spaces to the rest of the area. spacePaddingLine1 := strings.Repeat(" ", line1Rest) // Construct the final message. message = "\n" + top + "\n" + sideBar + line1InColor + spacePaddingLine1 + sideBar + "\n" + bottom + "\n" } // Return the final message. return message }
// scanBarFactory returns a progress bar function to report URL scanning. func scanBarFactory() scanBarFunc { fileCount := 0 termWidth, e := pb.GetTerminalWidth() fatalIf(probe.NewError(e), "Unable to get terminal size. Please use --quiet option.") // Cursor animate channel. cursorCh := cursorAnimate() return func(source string) { scanPrefix := fmt.Sprintf("[%s] %s ", humanize.Comma(int64(fileCount)), string(<-cursorCh)) source = fixateScanBar(source, termWidth-len([]rune(scanPrefix))) barText := scanPrefix + source console.PrintC("\r" + barText + "\r") fileCount++ } }
// scanBarFactory returns a progress bar function to report URL scanning. func scanBarFactory() scanBarFunc { fileCount := 0 termWidth, err := pb.GetTerminalWidth() if err != nil { termWidth = 80 } // Cursor animate channel. cursorCh := cursorAnimate() return func(source string) { scanPrefix := fmt.Sprintf("[%s] %s ", humanize.Comma(int64(fileCount)), string(<-cursorCh)) source = fixateScanBar(source, termWidth-len([]rune(scanPrefix))) barText := scanPrefix + source console.PrintC("\r" + barText + "\r") fileCount++ } }
// FormatJSONSyntaxError generates a pretty printed json syntax error since // golang doesn't provide an easy way to report the location of the error func FormatJSONSyntaxError(data io.Reader, sErr *json.SyntaxError) error { if sErr == nil { return nil } var readLine bytes.Buffer bio := bufio.NewReader(data) errLine := int64(1) readBytes := int64(0) // termWidth is set to a default one to use when we are // not able to calculate terminal width via OS syscalls termWidth := 25 // errorShift is the length of the minimum needed place for // error msg accessories, like <--, etc.. We calculate it // dynamically to avoid an eventual bug after modifying errorFmt errorShift := len(fmt.Sprintf(errorFmt, 1, "")) if width, err := pb.GetTerminalWidth(); err == nil { termWidth = width } for { b, err := bio.ReadByte() if err != nil { if err != io.EOF { return err } break } readBytes++ if readBytes > sErr.Offset { break } switch b { case '\n': readLine.Reset() errLine++ case '\t': readLine.WriteByte(' ') case '\r': break default: readLine.WriteByte(b) } } lineLen := readLine.Len() idx := lineLen - termWidth + errorShift if idx < 0 || idx > lineLen-1 { idx = 0 } errorStr := fmt.Sprintf("JSON syntax error at line %d, col %d : %s.\n", errLine, readLine.Len(), sErr) errorStr += fmt.Sprintf(errorFmt, errLine, readLine.String()[idx:]) return errors.New(errorStr) }