forked from tangled.org/core
this repo has no description
1package patchutil 2 3import ( 4 "fmt" 5 "regexp" 6 "strings" 7 8 "github.com/bluekeyes/go-gitdiff/gitdiff" 9) 10 11type FormatPatch struct { 12 *gitdiff.PatchHeader 13 Patch string 14} 15 16func ExtractPatches(formatPatch string) ([]FormatPatch, error) { 17 patches := splitFormatPatch(formatPatch) 18 19 result := []FormatPatch{} 20 21 for _, patch := range patches { 22 _, headerStr, err := gitdiff.Parse(strings.NewReader(patch)) 23 if err != nil { 24 return nil, fmt.Errorf("failed to parse patch: %w", err) 25 } 26 27 header, err := gitdiff.ParsePatchHeader(headerStr) 28 if err != nil { 29 return nil, fmt.Errorf("failed to parse patch header: %w", err) 30 } 31 32 result = append(result, FormatPatch{ 33 PatchHeader: header, 34 Patch: patch, 35 }) 36 } 37 38 return result, nil 39} 40 41// Very basic validation to check if it looks like a diff/patch 42// A valid patch usually starts with diff or --- lines or git format-patch header 43func IsPatchValid(patch string) bool { 44 // Basic validation to check if it looks like a diff/patch 45 // A valid patch usually starts with diff or --- lines 46 if len(patch) == 0 { 47 return false 48 } 49 50 lines := strings.Split(patch, "\n") 51 if len(lines) < 2 { 52 return false 53 } 54 55 // Check for common patch format markers 56 firstLine := strings.TrimSpace(lines[0]) 57 return strings.HasPrefix(firstLine, "diff ") || 58 strings.HasPrefix(firstLine, "--- ") || 59 strings.HasPrefix(firstLine, "Index: ") || 60 strings.HasPrefix(firstLine, "+++ ") || 61 strings.HasPrefix(firstLine, "@@ ") || 62 strings.HasPrefix(firstLine, "From ") && strings.Contains(firstLine, " Mon Sep 17 00:00:00 2001") || 63 strings.HasPrefix(firstLine, "From: ") 64} 65 66func IsFormatPatch(patch string) bool { 67 lines := strings.Split(patch, "\n") 68 if len(lines) < 2 { 69 return false 70 } 71 72 firstLine := strings.TrimSpace(lines[0]) 73 if strings.HasPrefix(firstLine, "From ") && strings.Contains(firstLine, " Mon Sep 17 00:00:00 2001") { 74 return true 75 } 76 77 headerCount := 0 78 for i := range min(10, len(lines)) { 79 line := strings.TrimSpace(lines[i]) 80 if strings.HasPrefix(line, "From: ") || 81 strings.HasPrefix(line, "Date: ") || 82 strings.HasPrefix(line, "Subject: ") || 83 strings.HasPrefix(line, "commit ") { 84 headerCount++ 85 } 86 if strings.HasPrefix(line, "diff --git ") { 87 return true 88 } 89 } 90 91 return headerCount >= 2 92} 93 94func splitFormatPatch(patchText string) []string { 95 // The pattern to match is "From " followed by a commit hash and the rest of that line 96 re := regexp.MustCompile(`(?m)^From [0-9a-f]{40} .*$`) 97 98 // Find all starting positions of patches 99 indexes := re.FindAllStringIndex(patchText, -1) 100 101 if len(indexes) == 0 { 102 // No patches found 103 return []string{} 104 } 105 106 patches := make([]string, len(indexes)) 107 108 for i := range indexes { 109 startPos := indexes[i][0] 110 endPos := len(patchText) 111 112 // If there's a next patch, set end position to the start of the next patch 113 if i < len(indexes)-1 { 114 endPos = indexes[i+1][0] 115 } 116 117 // Extract the patch and trim any whitespace 118 patches[i] = strings.TrimSpace(patchText[startPos:endPos]) 119 } 120 return patches 121}