Files
pmg/internal/ui/ui.go
T

128 lines
2.7 KiB
Go
Raw Normal View History

2025-05-14 14:01:20 +05:30
package ui
import (
"fmt"
"os"
"strings"
2025-05-14 18:56:58 +05:30
"github.com/safedep/pmg/analyzer"
2025-05-14 14:01:20 +05:30
)
// The UI is internal to PMG and opinionated for the CLI.
// It is not intended to be used outside of PMG.
type VerbosityLevel int
const (
// PMG is hidden from the user except for errors
// and when malicious packages are detected
VerbosityLevelSilent VerbosityLevel = iota
// Show minimal status updates
VerbosityLevelNormal
// Show verbose status updates and information including
// information about malicious packages
VerbosityLevelVerbose
)
var verbosityLevel VerbosityLevel = VerbosityLevelNormal
func SetVerbosityLevel(level VerbosityLevel) {
verbosityLevel = level
}
func ClearStatus() {
StopSpinner()
fmt.Print("\r")
}
func Block() error {
StopSpinner()
2025-05-14 18:56:58 +05:30
fmt.Println()
fmt.Println(Colors.Red("❌ Malicious package blocked!"))
2025-05-14 14:01:20 +05:30
os.Exit(1)
return nil
}
func SetStatus(status string) {
if verbosityLevel == VerbosityLevelSilent {
return
}
StopSpinner()
2025-05-14 18:56:58 +05:30
StartSpinnerWithColor(fmt.Sprintf("️ %s", status), Colors.Green)
2025-05-14 14:01:20 +05:30
}
2025-05-14 18:56:58 +05:30
func GetConfirmationOnMalware(malwarePackages []*analyzer.PackageVersionAnalysisResult) (bool, error) {
2025-05-14 14:01:20 +05:30
StopSpinner()
2025-05-14 19:08:25 +05:30
2025-05-14 18:56:58 +05:30
fmt.Println()
2025-05-14 19:08:25 +05:30
fmt.Println(Colors.Red(fmt.Sprintf("🚨 Suspicious package(s) detected: %d", len(malwarePackages))))
2025-05-14 14:01:20 +05:30
2025-05-14 18:56:58 +05:30
for _, mp := range malwarePackages {
2025-05-14 19:08:25 +05:30
fmt.Println()
2025-05-14 18:56:58 +05:30
fmt.Println("⚠️ ", Colors.Red(fmt.Sprintf("%s@%s", mp.PackageVersion.GetPackage().GetName(),
mp.PackageVersion.GetVersion())))
2025-05-14 19:08:25 +05:30
if verbosityLevel == VerbosityLevelVerbose {
fmt.Println(Colors.Yellow(termWidthFormatText(mp.Summary, 60)))
if mp.ReferenceURL != "" {
fmt.Println()
fmt.Println(Colors.Yellow(fmt.Sprintf("Reference: %s", mp.ReferenceURL)))
}
fmt.Println()
}
2025-05-14 14:01:20 +05:30
}
fmt.Println()
fmt.Print(Colors.Yellow("Do you want to continue with the installation? (y/N) "))
var response string
// We don't care about the error here because we will return false
// if the user doesn't provide a valid response
_, _ = fmt.Scanln(&response)
if len(response) == 0 {
return false, nil
}
response = strings.ToLower(response)
if response == "y" || response == "yes" || response[0] == 'y' {
return true, nil
}
return false, nil
}
2025-05-14 18:56:58 +05:30
2025-05-15 14:00:18 +05:30
func Fatalf(msg string, args ...interface{}) {
ClearStatus()
fmt.Println(Colors.Red(fmt.Sprintf(msg, args...)))
os.Exit(1)
}
2025-05-14 18:56:58 +05:30
// Format the string to be maximum maxWidth. Use newlines to wrap the text.
func termWidthFormatText(text string, maxWidth int) string {
words := strings.Split(text, " ")
lines := []string{}
currentLine := ""
for _, word := range words {
if len(currentLine)+len(word) > maxWidth {
lines = append(lines, currentLine)
currentLine = word
} else {
currentLine += " " + word
}
}
return strings.Join(lines, "\n")
}