diff options
Diffstat (limited to 'patchid.go')
| -rw-r--r-- | patchid.go | 224 |
1 files changed, 120 insertions, 104 deletions
@@ -1,20 +1,16 @@ package gitpb import ( - "bufio" "bytes" "crypto/sha1" "encoding/hex" "fmt" - "io" "os/exec" "strings" "go.wit.com/log" ) -// git show 5b277e7686974d2195586d5f5b82838ee9ddb036 |git patch-id --stable -// bf86be06af03b1a89ee155b214358362ec76f7b6 5b277e7686974d2195586d5f5b82838ee9ddb036 // forged patch: "working on ping pong" // The --stable flag is an important detail. When you use it, git patch-id outputs two hashes: // <stable_patch_id> <unstable_patch_id> @@ -71,19 +67,53 @@ func (repo *Repo) FindPatchIdByHash(hash string) (string, error) { return fields[0], nil } -// ComputePatchID calculates the patch ID for a given patch file's content. -// It mimics the behavior of the `git patch-id` command by normalizing the -// patch content before hashing. -// -// Normalization rules: -// 1. It ignores all lines until the first "--- " line is encountered. -// 2. It ignores diff headers (lines starting with "---", "+++", "diff --git", "index"). -// 3. For content lines ('+', '-', or ' '), it keeps the first character and -// trims any trailing whitespace from the rest of the line before hashing. -// 4. All other lines (like hunk headers "@@ ... @@") are ignored. -func FindPatchIdByBytes(patchData io.Reader) (string, error) { - scanner := bufio.NewScanner(patchData) - var normalizedPatch bytes.Buffer +func (repo *Repo) FindPatchIdFromGitAm(gitam []byte) (string, string, error) { + return FindPatchIdFromGitAm(gitam) +} + +func FindPatchIdFromGitAm(gitam []byte) (string, string, error) { + // 1. Create the command. + cmd := exec.Command("git", "patch-id", "--stable") + + // 2. Set the command's Stdin to a reader created from our string. + // This is the key change. + cmd.Stdin = strings.NewReader(string(gitam)) + + // 3. We need buffers to capture the command's output. + var stdout, stderr bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = &stderr + + // 4. Run the command and wait for it to finish. + // cmd.Run() is a convenient wrapper around Start() and Wait(). + err := cmd.Run() + if err != nil { + // Include stderr in the error message for better debugging. + return "", "", fmt.Errorf("git patch-id command failed: %w\nStderr: %s", err, stderr.String()) + } + + fields := strings.Fields(stdout.String()) + if len(fields) != 2 { + return "", "", fmt.Errorf("git-patch-id produced empty output") + } + + return fields[0], fields[1], nil +} + +// computes the stable git patch-id from the output of git-am +// doesn't work. it needs to add the SHA-1 parts together +// cat WTF.2.diff | git patch-id --stable +// go.wit.com/apps/utils/forged +// git show 5b277e7686974d2195586d5f5b82838ee9ddb036 |git patch-id --stable +// bf86be06af03b1a89ee155b214358362ec76f7b6 5b277e7686974d2195586d5f5b82838ee9ddb036 +// 73d73e12dcd727721253140ea68441dd0b824f8c 0000000000000000000000000000000000000000 +// 515792a0c4965b69f6b9e7f89e2f896148b03c97 0000000000000000000000000000000000000000 +// 1dd8b4a7d7d42a78fd1ff84dcc2ac87bc7318ee6 0000000000000000000000000000000000000000 +// 8478bad3e1f97818a68a014a8f30f1b2951b026b 0000000000000000000000000000000000000000 +func FindPatchIdFromGitAmBroken(gitAmData []byte) string { + var lines []string + scanner := NewLinesScanner(strings.Split(string(gitAmData), "\n")) + // var normalizedPatch bytes.Buffer var inPatchBody bool for scanner.Scan() { @@ -91,7 +121,7 @@ func FindPatchIdByBytes(patchData io.Reader) (string, error) { // The patch content officially starts at the first `---` line. // This helps skip email headers in patches generated by `git format-patch`. - if !inPatchBody && strings.HasPrefix(line, "---") { + if !inPatchBody && strings.HasPrefix(line, "diff ") { inPatchBody = true } @@ -99,101 +129,87 @@ func FindPatchIdByBytes(patchData io.Reader) (string, error) { continue } - // Skip headers and metadata lines - if strings.HasPrefix(line, "---") || - strings.HasPrefix(line, "+++") || - strings.HasPrefix(line, "index") || - strings.HasPrefix(line, "diff --git") { - continue - } - - // Process only the actual content lines (context, addition, deletion) - if len(line) > 0 && (line[0] == ' ' || line[0] == '+' || line[0] == '-') { - // Keep the first character (' ', '+', or '-') - firstChar := line[0] - content := line[1:] - - // Trim trailing whitespace from the content part of the line - trimmedContent := strings.TrimRight(content, " ") - - // Write the normalized line to our buffer for hashing - normalizedPatch.WriteByte(firstChar) - normalizedPatch.WriteString(trimmedContent) - normalizedPatch.WriteByte('\n') + if line == "-- " { + break } - // All other lines (e.g., "@@ ... @@") are ignored. - } - - if err := scanner.Err(); err != nil { - return "", fmt.Errorf("error reading patch data: %w", err) - } + lines = append(lines, line) - // Calculate the SHA-1 hash of the normalized patch content - hash := sha1.Sum(normalizedPatch.Bytes()) - patchID := hex.EncodeToString(hash[:]) - - return patchID, nil -} + /* + // Skip headers and metadata lines + if strings.HasPrefix(line, "---") || + strings.HasPrefix(line, "+++") || + strings.HasPrefix(line, "index") || + strings.HasPrefix(line, "diff --git") { + continue + } -/* -// --- Example Usage --- + normalizedPatch.WriteString(line + "\n") + */ + /* + // Process only the actual content lines (context, addition, deletion) + if len(line) > 0 && (line[0] == ' ' || line[0] == '+' || line[0] == '-') { + // Keep the first character (' ', '+', or '-') + firstChar := line[0] + content := line[1:] -func main() { - // Example 1: Using a string as input - patchString := ` -From 2f42795678c7113f7437c04f56570c08b68850f4 Mon Sep 17 00:00:00 2001 -From: A Developer <[email protected]> -Subject: [PATCH] Example change to demonstrate patch-id + // Trim trailing whitespace from the content part of the line + trimmedContent := strings.TrimRight(content, " ") ---- a/README.md -+++ b/README.md -@@ -1,3 +1,4 @@ - # My Project - --This is a sample project. -+This is a sample project. -+It has an additional line. -` - stringReader := strings.NewReader(patchString) - patchID, err := ComputePatchID(stringReader) - if err != nil { - fmt.Fprintf(os.Stderr, "Error computing patch ID from string: %v\n", err) - return + // Write the normalized line to our buffer for hashing + normalizedPatch.WriteByte(firstChar) + normalizedPatch.WriteString(trimmedContent) + normalizedPatch.WriteByte('\n') + } + // All other lines (e.g., "@@ ... @@") are ignored. + */ } - fmt.Printf("Patch ID from string: %s\n", patchID) - // Example 2: Reading from a file - // Create a temporary patch file for demonstration - patchContent := []byte(patchString) - tmpfile, err := os.CreateTemp("", "example.*.patch") - if err != nil { - fmt.Fprintf(os.Stderr, "Error creating temp file: %v\n", err) - return - } - defer os.Remove(tmpfile.Name()) // clean up + // var fullhash [20]byte - if _, err := tmpfile.Write(patchContent); err != nil { - fmt.Fprintf(os.Stderr, "Error writing to temp file: %v\n", err) - return - } - if err := tmpfile.Close(); err != nil { - fmt.Fprintf(os.Stderr, "Error closing temp file: %v\n", err) - return + var final string + for _, line := range lines { + if strings.HasPrefix(line, "---") { + // final += "---\n" + final += line + "\n" + continue + } + if strings.HasPrefix(line, "+++") { + // final += "+++\n" + final += line + "\n" + continue + } + if strings.HasPrefix(line, "index") { + // final += "index\n" + // final += line + "\n" + continue + } + if strings.HasPrefix(line, "@@") { + // final += "@@\n" + continue + } + if strings.HasPrefix(line, "diff --git") { + if len(final) != 0 { + hash := sha1.Sum([]byte(final)) + // fullhash ?? hash + patchId := hex.EncodeToString(hash[:]) + log.Info("partial hash", patchId) + } + log.Printf("%s", final) + // final += "diff --git\n" + final = line + "\n" + // final = "" + continue + } + final += line + "\n" } - // Open the file to pass to our function - file, err := os.Open(tmpfile.Name()) - if err != nil { - fmt.Fprintf(os.Stderr, "Error opening temp file: %v\n", err) - return - } - defer file.Close() + // final = strings.TrimSuffix(final, "\n") - patchIDFromFile, err := ComputePatchID(file) - if err != nil { - fmt.Fprintf(os.Stderr, "Error computing patch ID from file: %v\n", err) - return - } - fmt.Printf("Patch ID from file: %s\n", patchIDFromFile) + // Calculate the SHA-1 hash of the normalized patch content + // hash := sha1.Sum(normalizedPatch.Bytes()) + hash := sha1.Sum([]byte(final)) + patchID := hex.EncodeToString(hash[:]) + // log.Printf("%s", final) + // log.Info(strings.Join(lines, "\n")) + return patchID } -*/ |
