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 Files []*gitdiff.File 13 *gitdiff.PatchHeader 14} 15 16func ExtractPatches(formatPatch string) ([]FormatPatch, error) { 17 patches := splitFormatPatch(formatPatch) 18 19 result := []FormatPatch{} 20 21 for _, patch := range patches { 22 files, 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 Files: files, 34 PatchHeader: header, 35 }) 36 } 37 38 return result, nil 39} 40 41// IsPatchValid checks if the given patch string is valid. 42// It performs very basic sniffing for either git-diff or git-format-patch 43// header lines. 44func IsPatchValid(patch string) bool { 45 if len(patch) == 0 { 46 return false 47 } 48 49 lines := strings.Split(patch, "\n") 50 if len(lines) < 2 { 51 return false 52 } 53 54 firstLine := strings.TrimSpace(lines[0]) 55 return strings.HasPrefix(firstLine, "diff ") || 56 strings.HasPrefix(firstLine, "--- ") || 57 strings.HasPrefix(firstLine, "Index: ") || 58 strings.HasPrefix(firstLine, "+++ ") || 59 strings.HasPrefix(firstLine, "@@ ") || 60 strings.HasPrefix(firstLine, "From ") && strings.Contains(firstLine, " Mon Sep 17 00:00:00 2001") || 61 strings.HasPrefix(firstLine, "From: ") 62} 63 64func IsFormatPatch(patch string) bool { 65 lines := strings.Split(patch, "\n") 66 if len(lines) < 2 { 67 return false 68 } 69 70 firstLine := strings.TrimSpace(lines[0]) 71 if strings.HasPrefix(firstLine, "From ") && strings.Contains(firstLine, " Mon Sep 17 00:00:00 2001") { 72 return true 73 } 74 75 headerCount := 0 76 for i := range min(10, len(lines)) { 77 line := strings.TrimSpace(lines[i]) 78 if strings.HasPrefix(line, "From: ") || 79 strings.HasPrefix(line, "Date: ") || 80 strings.HasPrefix(line, "Subject: ") || 81 strings.HasPrefix(line, "commit ") { 82 headerCount++ 83 } 84 if strings.HasPrefix(line, "diff --git ") { 85 return true 86 } 87 } 88 89 return headerCount >= 2 90} 91 92func splitFormatPatch(patchText string) []string { 93 re := regexp.MustCompile(`(?m)^From [0-9a-f]{40} .*$`) 94 95 indexes := re.FindAllStringIndex(patchText, -1) 96 97 if len(indexes) == 0 { 98 return []string{} 99 } 100 101 patches := make([]string, len(indexes)) 102 103 for i := range indexes { 104 startPos := indexes[i][0] 105 endPos := len(patchText) 106 107 if i < len(indexes)-1 { 108 endPos = indexes[i+1][0] 109 } 110 111 patches[i] = strings.TrimSpace(patchText[startPos:endPos]) 112 } 113 return patches 114}