Monorepo for Tangled
tangled.org
1package repo
2
3import (
4 "fmt"
5 "strings"
6 "time"
7
8 "tangled.org/core/types"
9)
10
11// renderUnifiedDiff reconstructs a unified diff from a NiceDiff.
12func renderUnifiedDiff(nd *types.NiceDiff) string {
13 if nd == nil {
14 return ""
15 }
16 var sb strings.Builder
17 for _, d := range nd.Diff {
18 oldName := d.Name.Old
19 newName := d.Name.New
20 if oldName == "" {
21 oldName = newName
22 }
23 if newName == "" {
24 newName = oldName
25 }
26
27 fmt.Fprintf(&sb, "diff --git a/%s b/%s\n", oldName, newName)
28 switch {
29 case d.IsNew:
30 fmt.Fprintf(&sb, "new file mode 100644\n")
31 fmt.Fprintf(&sb, "--- /dev/null\n")
32 fmt.Fprintf(&sb, "+++ b/%s\n", newName)
33 case d.IsDelete:
34 fmt.Fprintf(&sb, "deleted file mode 100644\n")
35 fmt.Fprintf(&sb, "--- a/%s\n", oldName)
36 fmt.Fprintf(&sb, "+++ /dev/null\n")
37 case d.IsRename:
38 fmt.Fprintf(&sb, "rename from %s\n", oldName)
39 fmt.Fprintf(&sb, "rename to %s\n", newName)
40 fmt.Fprintf(&sb, "--- a/%s\n", oldName)
41 fmt.Fprintf(&sb, "+++ b/%s\n", newName)
42 default:
43 fmt.Fprintf(&sb, "--- a/%s\n", oldName)
44 fmt.Fprintf(&sb, "+++ b/%s\n", newName)
45 }
46
47 for i := range d.TextFragments {
48 sb.WriteString(d.TextFragments[i].String())
49 }
50 }
51 return sb.String()
52}
53
54// renderFormatPatch reconstructs an email-style format-patch from a NiceDiff.
55func renderFormatPatch(nd *types.NiceDiff) string {
56 if nd == nil {
57 return ""
58 }
59 c := nd.Commit
60
61 // subject: first line of commit message
62 subject := c.Message
63 if i := strings.IndexByte(subject, '\n'); i >= 0 {
64 subject = subject[:i]
65 }
66
67 // body: rest of message after first line
68 body := ""
69 if i := strings.Index(c.Message, "\n\n"); i >= 0 {
70 body = strings.TrimRight(c.Message[i+2:], "\n")
71 }
72
73 date := c.Author.When.UTC().Format(time.RFC1123Z)
74
75 var sb strings.Builder
76 fmt.Fprintf(&sb, "From %s Mon Sep 17 00:00:00 2001\n", c.Hash.String())
77 fmt.Fprintf(&sb, "From: %s <%s>\n", c.Author.Name, c.Author.Email)
78 fmt.Fprintf(&sb, "Date: %s\n", date)
79 fmt.Fprintf(&sb, "Subject: [PATCH] %s\n", subject)
80 sb.WriteString("\n")
81 if body != "" {
82 sb.WriteString(body)
83 sb.WriteString("\n")
84 }
85 sb.WriteString("---\n")
86
87 // stat summary
88 for _, d := range nd.Diff {
89 name := d.Name.New
90 if name == "" {
91 name = d.Name.Old
92 }
93 stats := d.Stats()
94 fmt.Fprintf(&sb, " %s | %d %s\n", name, stats.Insertions+stats.Deletions,
95 strings.Repeat("+", int(stats.Insertions))+strings.Repeat("-", int(stats.Deletions)))
96 }
97 fmt.Fprintf(&sb, " %d file(s) changed, %d insertion(s)(+), %d deletion(s)(-)\n\n",
98 nd.Stat.FilesChanged, nd.Stat.Insertions, nd.Stat.Deletions)
99
100 sb.WriteString(renderUnifiedDiff(nd))
101 sb.WriteString("\n--\ntangled.sh\n")
102 return sb.String()
103}