mdlinkt/main.go

160 lines
3.5 KiB
Go
Raw Normal View History

2023-12-24 17:02:13 +00:00
package main
import (
"bufio"
"flag"
2023-12-24 17:37:07 +00:00
"fmt"
2023-12-24 17:02:13 +00:00
"net/http"
"os"
"regexp"
"strings"
2023-12-29 20:05:02 +00:00
"sync"
2023-12-24 17:37:07 +00:00
"time"
2023-12-24 17:02:13 +00:00
"github.com/fatih/color"
)
type LinkCheckResult struct {
Link string
IsValid bool
StatusCode int
}
2023-12-29 20:05:02 +00:00
var wg sync.WaitGroup
var verboseMode bool
2023-12-24 17:37:07 +00:00
func logWithColor(level string, msg string, args ...interface{}) {
2023-12-29 20:05:02 +00:00
if verboseMode {
timestamp := time.Now().Format("2006/01/02 15:04:05")
colorFunc := color.New(color.FgWhite).SprintFunc()
switch level {
case "ERROR":
colorFunc = color.New(color.FgRed).SprintFunc()
case "WARN":
colorFunc = color.New(color.FgYellow).SprintFunc()
case "INFO":
colorFunc = color.New(color.FgCyan).SprintFunc()
}
fmt.Printf("%s %s %s\n", timestamp, colorFunc(level), fmt.Sprintf(msg, args...))
2023-12-24 17:37:07 +00:00
}
}
2023-12-24 17:02:13 +00:00
func main() {
filename := flag.String("file", "", "Markdown file to test")
2023-12-29 20:05:02 +00:00
verboseFlag := flag.Bool("verbose", false, "Enable verbose mode")
2023-12-24 17:02:13 +00:00
failedOnly := flag.Bool("failed-only", false, "Return only failed links")
flag.Parse()
2023-12-29 20:05:02 +00:00
verboseMode = *verboseFlag
2023-12-24 17:02:13 +00:00
if *filename == "" {
2023-12-24 17:37:07 +00:00
logWithColor("INFO", "Please provide a markdown file.")
2023-12-24 17:02:13 +00:00
os.Exit(1)
}
file, err := os.Open(*filename)
if err != nil {
2023-12-24 17:37:07 +00:00
logWithColor("ERROR", "Failed to open file: %v", err)
2023-12-24 17:02:13 +00:00
os.Exit(1)
}
if file == nil {
logWithColor("ERROR", "File is nil")
os.Exit(1)
}
2023-12-24 17:02:13 +00:00
defer file.Close()
scanner := bufio.NewScanner(file)
if scanner == nil {
logWithColor("ERROR", "Scanner is nil")
os.Exit(1)
}
2023-12-24 17:02:13 +00:00
re := regexp.MustCompile(`\[(.*?)\]\((.*?)\)`)
results := []LinkCheckResult{}
2023-12-29 20:05:02 +00:00
resChan := make(chan LinkCheckResult, 1000) // buffered channel for storing responses
2023-12-24 17:02:13 +00:00
for scanner.Scan() {
line := scanner.Text()
matches := re.FindAllStringSubmatch(line, -1)
for _, match := range matches {
2023-12-29 20:05:02 +00:00
wg.Add(1)
go func(link string, verboseFlag *bool) {
defer wg.Done()
resp, err := http.Head(link)
if err != nil || resp == nil {
logWithColor("ERROR", "Invalid link: %s", link)
resChan <- LinkCheckResult{
Link: link,
IsValid: false,
StatusCode: http.StatusBadRequest,
}
} else {
isValid := resp.StatusCode == http.StatusOK
result := LinkCheckResult{
Link: link,
IsValid: isValid,
StatusCode: resp.StatusCode,
}
resChan <- result
if *verboseFlag || (!*failedOnly && !isValid) {
statusColor := color.GreenString
if !isValid {
statusColor = color.RedString
}
logWithColor("INFO", "%s: %s", link, statusColor("%d", resp.StatusCode))
}
2023-12-24 17:02:13 +00:00
}
2023-12-29 20:05:02 +00:00
}(strings.TrimSpace(match[2]), verboseFlag)
2023-12-24 17:02:13 +00:00
}
}
2023-12-29 20:05:02 +00:00
wg.Wait()
close(resChan)
for res := range resChan {
results = append(results, res)
}
2023-12-24 17:02:13 +00:00
if err := scanner.Err(); err != nil {
2023-12-24 17:37:07 +00:00
logWithColor("ERROR", "Error scanning file: %v", err)
2023-12-24 17:02:13 +00:00
os.Exit(1)
}
2023-12-29 20:05:02 +00:00
// summary
2023-12-24 17:02:13 +00:00
validCount := 0
invalidCount := 0
for _, result := range results {
if result.IsValid {
validCount++
} else {
invalidCount++
}
}
summaryColor := color.GreenString
if invalidCount > 0 {
summaryColor = color.RedString
}
2023-12-29 20:05:02 +00:00
logWithColor("INFO", summaryColor("Summary: %d valid links, %d invalid links"), validCount, invalidCount)
2023-12-24 17:02:13 +00:00
if *failedOnly {
for _, result := range results {
if !result.IsValid {
2023-12-24 17:37:07 +00:00
logWithColor("ERROR", "Failed link: %s", result.Link)
2023-12-24 17:02:13 +00:00
}
}
2023-12-29 20:05:02 +00:00
} else if *verboseFlag {
for _, result := range results {
statusColor := color.GreenString
if !result.IsValid {
statusColor = color.RedString
}
logWithColor("INFO", "%s: %s", result.Link, statusColor("%d", result.StatusCode))
}
2023-12-24 17:02:13 +00:00
}
if invalidCount > 0 {
os.Exit(1)
}
}