mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
Add colorful outputs & remove md text (#13)
* fix: parsePackageInfo to handle pkg names with special character * Enhance pmg outputs by adding colors and removing markdown notions * Update pkg/wrapper/npm_base.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com> * Update npm_base.go Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com> * test: add tests for removeMarkdown * chore: remove duplicate code * refactor: convert TerminalColors to global var and split markdown utils --------- Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -5,6 +5,7 @@ go 1.24.1
|
|||||||
require (
|
require (
|
||||||
buf.build/gen/go/safedep/api/grpc/go v1.5.1-20250418165058-162f6b0cc319.2
|
buf.build/gen/go/safedep/api/grpc/go v1.5.1-20250418165058-162f6b0cc319.2
|
||||||
buf.build/gen/go/safedep/api/protocolbuffers/go v1.36.6-20250418165058-162f6b0cc319.1
|
buf.build/gen/go/safedep/api/protocolbuffers/go v1.36.6-20250418165058-162f6b0cc319.1
|
||||||
|
github.com/fatih/color v1.18.0
|
||||||
github.com/jedib0t/go-pretty/v6 v6.6.7
|
github.com/jedib0t/go-pretty/v6 v6.6.7
|
||||||
github.com/safedep/dry v0.0.0-20250410092643-c7079e2f9442
|
github.com/safedep/dry v0.0.0-20250410092643-c7079e2f9442
|
||||||
github.com/safedep/vet v1.10.1
|
github.com/safedep/vet v1.10.1
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
headerBulletRegex = regexp.MustCompile(`(?m)^(#{1,6}\s+|[-*]\s{1,}|\d+\.\s+|>\s+)`)
|
||||||
|
inlineCodeRegex = regexp.MustCompile("`{1,3}([^`]*)`{1,3}")
|
||||||
|
horizontalRuleRegex = regexp.MustCompile(`(?m)^\s*(-{3,}|\*{3,}|\_{3,})\s*$`)
|
||||||
|
boldItalicRegex = regexp.MustCompile(`(?:\*\*\*|___)(.*?)(?:\*\*\*|___)`)
|
||||||
|
boldRegex = regexp.MustCompile(`(?:\*\*|__)(.*?)(?:\*\*|__)`)
|
||||||
|
italicRegex = regexp.MustCompile(`(?:\*|_)(.*?)(?:\*|_)`)
|
||||||
|
strikethroughRegex = regexp.MustCompile(`~~([^~]+)~~`)
|
||||||
|
inlineLinkRegex = regexp.MustCompile(`\[([^\]]+)\]\((\S+?)\)`)
|
||||||
|
imageRegex = regexp.MustCompile(`!\[([^\]]*)\]\((\S+?)\)`)
|
||||||
|
extraSpacesRegex = regexp.MustCompile(`\s+`)
|
||||||
|
)
|
||||||
|
|
||||||
|
func removeMarkdown(text string) string {
|
||||||
|
// Remove bold italic (***bolditalic*** or ___bolditalic___)
|
||||||
|
text = boldItalicRegex.ReplaceAllString(text, "$1")
|
||||||
|
|
||||||
|
// Remove bold (**bold** or __bold__)
|
||||||
|
text = boldRegex.ReplaceAllString(text, "$1")
|
||||||
|
|
||||||
|
// Remove italic (*italic* or _italic_)
|
||||||
|
text = italicRegex.ReplaceAllString(text, "$1")
|
||||||
|
|
||||||
|
// Remove strikethrough (~~text~~)
|
||||||
|
text = strikethroughRegex.ReplaceAllString(text, "$1")
|
||||||
|
|
||||||
|
// Remove inline code (`code`)
|
||||||
|
text = inlineCodeRegex.ReplaceAllString(text, "$1")
|
||||||
|
|
||||||
|
// Remove links [text](url)
|
||||||
|
text = inlineLinkRegex.ReplaceAllString(text, "$1")
|
||||||
|
|
||||||
|
// Remove images 
|
||||||
|
text = imageRegex.ReplaceAllString(text, "$1")
|
||||||
|
|
||||||
|
// Remove horizontal rules
|
||||||
|
text = horizontalRuleRegex.ReplaceAllString(text, "")
|
||||||
|
|
||||||
|
// Remove headers, blockquotes, bullets (e.g., ### Heading, > Quote, - Item)
|
||||||
|
text = headerBulletRegex.ReplaceAllString(text, "")
|
||||||
|
|
||||||
|
// Normalize extra spaces
|
||||||
|
text = extraSpacesRegex.ReplaceAllString(text, " ")
|
||||||
|
|
||||||
|
// Trim leading/trailing whitespace
|
||||||
|
return strings.TrimSpace(text)
|
||||||
|
}
|
||||||
@@ -10,14 +10,19 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func ConfirmInstallation(maliciousPkgs map[string]string) bool {
|
func ConfirmInstallation(maliciousPkgs map[string]string) bool {
|
||||||
fmt.Printf("\nWARNING: %d potentially malicious packages detected!\n", len(maliciousPkgs))
|
|
||||||
fmt.Println("The following packages have been flagged:")
|
fmt.Printf("\n%s\n", colors.Red("⚠️ WARNING: %d potentially malicious packages detected!", len(maliciousPkgs)))
|
||||||
|
fmt.Println(colors.Yellow("The following packages have been flagged:"))
|
||||||
|
|
||||||
for name, reason := range maliciousPkgs {
|
for name, reason := range maliciousPkgs {
|
||||||
fmt.Printf("- %s: %s\n", name, reason)
|
fmt.Printf("%s %s: %s\n",
|
||||||
|
colors.Cyan("•"), // bullet point
|
||||||
|
colors.Yellow(name),
|
||||||
|
removeMarkdown(reason),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Print("\nDo you want to continue with installation? (y/N): ")
|
fmt.Print("\n", colors.Green("Do you want to continue with installation? (y/N): "))
|
||||||
reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
response, err := reader.ReadString('\n')
|
response, err := reader.ReadString('\n')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import "github.com/fatih/color"
|
||||||
|
|
||||||
|
type TerminalColors struct {
|
||||||
|
Red func(format string, a ...interface{}) string
|
||||||
|
Yellow func(format string, a ...interface{}) string
|
||||||
|
Cyan func(format string, a ...interface{}) string
|
||||||
|
Green func(format string, a ...interface{}) string
|
||||||
|
}
|
||||||
|
|
||||||
|
var colors = TerminalColors{
|
||||||
|
Red: color.New(color.FgRed, color.Bold).SprintfFunc(),
|
||||||
|
Yellow: color.New(color.FgYellow).SprintfFunc(),
|
||||||
|
Cyan: color.New(color.FgCyan).SprintfFunc(),
|
||||||
|
Green: color.New(color.FgGreen).SprintfFunc(),
|
||||||
|
}
|
||||||
@@ -168,3 +168,45 @@ func TestParsePackageInfo(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRemoveMarkdown(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
input string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
// Bold
|
||||||
|
{"This is **bold** text", "This is bold text"},
|
||||||
|
{"This is __bold__ text", "This is bold text"},
|
||||||
|
|
||||||
|
// Italic
|
||||||
|
{"This is *italic* text", "This is italic text"},
|
||||||
|
{"This is _italic_ text", "This is italic text"},
|
||||||
|
|
||||||
|
// Code
|
||||||
|
{"This is `code` inline", "This is code inline"},
|
||||||
|
|
||||||
|
// Link
|
||||||
|
{"Click [here](https://example.com)", "Click here"},
|
||||||
|
|
||||||
|
// Headings
|
||||||
|
{"# Heading 1", "Heading 1"},
|
||||||
|
{"### Subheading", "Subheading"},
|
||||||
|
|
||||||
|
// Combined formatting
|
||||||
|
{"__*bold and italic*__", "bold and italic"},
|
||||||
|
{"This is **bold** and `code`", "This is bold and code"},
|
||||||
|
|
||||||
|
// No markdown
|
||||||
|
{"Just plain text", "Just plain text"},
|
||||||
|
|
||||||
|
// Complex mixed
|
||||||
|
{"### Title\nSome **bold** text and a [link](http://url.com).", "Title\nSome bold text and a link."},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
result := removeMarkdown(tt.input)
|
||||||
|
if result != tt.expected {
|
||||||
|
t.Errorf("removeMarkdown(%q) = %q; want %q", tt.input, result, tt.expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/fatih/color"
|
||||||
"github.com/safedep/dry/log"
|
"github.com/safedep/dry/log"
|
||||||
"github.com/safedep/pmg/internal/ui"
|
"github.com/safedep/pmg/internal/ui"
|
||||||
"github.com/safedep/pmg/pkg/analyser"
|
"github.com/safedep/pmg/pkg/analyser"
|
||||||
@@ -28,8 +29,8 @@ func NewPackageManagerWrapper(registryType registry.RegistryType) *PackageManage
|
|||||||
|
|
||||||
func (pmw *PackageManagerWrapper) Wrap() error {
|
func (pmw *PackageManagerWrapper) Wrap() error {
|
||||||
ui.StartProgressWriter()
|
ui.StartProgressWriter()
|
||||||
|
var DefaultProgressTotal = 5
|
||||||
progressTracker := ui.TrackProgress(fmt.Sprintf("Scanning %s ", pmw.PackageName), 5)
|
progressTracker := ui.TrackProgress(fmt.Sprintf("Scanning %s ", pmw.PackageName), DefaultProgressTotal)
|
||||||
if pmw.PackageName == "" {
|
if pmw.PackageName == "" {
|
||||||
return fmt.Errorf("package name cannot be empty")
|
return fmt.Errorf("package name cannot be empty")
|
||||||
}
|
}
|
||||||
@@ -133,7 +134,8 @@ func (pmw *PackageManagerWrapper) analyzeDependencies(ctx context.Context, deps
|
|||||||
log.Infof("Installation canceled due to security concerns")
|
log.Infof("Installation canceled due to security concerns")
|
||||||
return fmt.Errorf("installation canceled")
|
return fmt.Errorf("installation canceled")
|
||||||
}
|
}
|
||||||
log.Warnf("Continuing installation despite security warnings...")
|
yellow := color.New(color.FgYellow, color.Bold).SprintfFunc()
|
||||||
|
log.Warnf(yellow("Continuing installation despite security warnings..."))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
Reference in New Issue
Block a user