forked from tangled.org/core
Monorepo for Tangled — https://tangled.org

fix memleak issue

thanks pprof

Changed files
+84 -36
appview
pages
templates
repo
fragments
pulls
state
cmd
interdiff
interdiff
+6 -2
appview/pages/templates/repo/fragments/interdiff.html
··· 11 <div class="overflow-x-auto"> 12 <ul class="dark:text-gray-200"> 13 {{ range $diff }} 14 - <li><a href="#file-{{ .Name }}" class="dark:hover:text-gray-300">{{ .Name }} ({{ .Status.StatusKind }})</a></li> 15 {{ end }} 16 </ul> 17 </div> ··· 24 <section class="mt-6 border border-gray-200 dark:border-gray-700 w-full mx-auto rounded bg-white dark:bg-gray-800 drop-shadow-sm"> 25 <div id="file-{{ .Name }}"> 26 <div id="diff-file"> 27 - <details open> 28 <summary class="list-none cursor-pointer sticky top-0"> 29 <div id="diff-file-header" class="rounded cursor-pointer bg-white dark:bg-gray-800 flex justify-between"> 30 <div id="left-side-items" class="p-2 flex gap-2 items-center overflow-x-auto"> ··· 73 {{ if .Status.IsUnchanged }} 74 <p class="text-center text-gray-400 dark:text-gray-500 p-4"> 75 This file has not been changed. 76 </p> 77 {{ else if .Status.IsError }} 78 <p class="text-center text-gray-400 dark:text-gray-500 p-4">
··· 11 <div class="overflow-x-auto"> 12 <ul class="dark:text-gray-200"> 13 {{ range $diff }} 14 + <li><a href="#file-{{ .Name }}" class="dark:hover:text-gray-300">{{ .Name }}</a></li> 15 {{ end }} 16 </ul> 17 </div> ··· 24 <section class="mt-6 border border-gray-200 dark:border-gray-700 w-full mx-auto rounded bg-white dark:bg-gray-800 drop-shadow-sm"> 25 <div id="file-{{ .Name }}"> 26 <div id="diff-file"> 27 + <details {{ if not (.Status.IsOnlyInOne) }}open{{end}}> 28 <summary class="list-none cursor-pointer sticky top-0"> 29 <div id="diff-file-header" class="rounded cursor-pointer bg-white dark:bg-gray-800 flex justify-between"> 30 <div id="left-side-items" class="p-2 flex gap-2 items-center overflow-x-auto"> ··· 73 {{ if .Status.IsUnchanged }} 74 <p class="text-center text-gray-400 dark:text-gray-500 p-4"> 75 This file has not been changed. 76 + </p> 77 + {{ else if .Status.IsRebased }} 78 + <p class="text-center text-gray-400 dark:text-gray-500 p-4"> 79 + This patch was likely rebased, as context lines do not match. 80 </p> 81 {{ else if .Status.IsError }} 82 <p class="text-center text-gray-400 dark:text-gray-500 p-4">
+1
appview/pages/templates/repo/pulls/pull.html
··· 64 href="/{{ $.RepoInfo.FullName }}/pulls/{{ $.Pull.PullId }}/round/{{.RoundNumber}}/interdiff"> 65 {{ i "file-diff" "w-4 h-4" }} <span class="hidden md:inline">interdiff</span> 66 </a> 67 {{ end }} 68 {{ end }} 69 </div>
··· 64 href="/{{ $.RepoInfo.FullName }}/pulls/{{ $.Pull.PullId }}/round/{{.RoundNumber}}/interdiff"> 65 {{ i "file-diff" "w-4 h-4" }} <span class="hidden md:inline">interdiff</span> 66 </a> 67 + <span id="interdiff-error-{{.RoundNumber}}"></span> 68 {{ end }} 69 {{ end }} 70 </div>
+13 -5
appview/state/pull.go
··· 351 } 352 } 353 354 - currentPatch, _, _ := gitdiff.Parse(strings.NewReader(pull.Submissions[roundIdInt].Patch)) 355 - previousPatch, _, _ := gitdiff.Parse(strings.NewReader(pull.Submissions[roundIdInt-1].Patch)) 356 357 interdiff := interdiff.Interdiff(previousPatch, currentPatch) 358 359 - for _, f := range interdiff.Files { 360 - fmt.Printf("%s, %+v\n-----", f.Name, f.File) 361 - } 362 s.pages.RepoPullInterdiffPage(w, pages.RepoPullInterdiffParams{ 363 LoggedInUser: s.auth.GetUser(r), 364 RepoInfo: f.RepoInfo(s, user),
··· 351 } 352 } 353 354 + currentPatch, _, err := gitdiff.Parse(strings.NewReader(pull.Submissions[roundIdInt].Patch)) 355 + if err != nil { 356 + log.Println("failed to interdiff; current patch malformed") 357 + s.pages.Notice(w, fmt.Sprintf("interdiff-error-%d", roundIdInt), "Failed to calculate interdiff; current patch is invalid.") 358 + return 359 + } 360 + 361 + previousPatch, _, err := gitdiff.Parse(strings.NewReader(pull.Submissions[roundIdInt-1].Patch)) 362 + if err != nil { 363 + log.Println("failed to interdiff; previous patch malformed") 364 + s.pages.Notice(w, fmt.Sprintf("interdiff-error-%d", roundIdInt), "Failed to calculate interdiff; previous patch is invalid.") 365 + return 366 + } 367 368 interdiff := interdiff.Interdiff(previousPatch, currentPatch) 369 370 s.pages.RepoPullInterdiffPage(w, pages.RepoPullInterdiffParams{ 371 LoggedInUser: s.auth.GetUser(r), 372 RepoInfo: f.RepoInfo(s, user),
+7 -2
cmd/interdiff/main.go
··· 9 ) 10 11 func main() { 12 - patch1, err := os.Open("patches/g1.patch") 13 if err != nil { 14 fmt.Println(err) 15 } 16 - patch2, err := os.Open("patches/g2.patch") 17 if err != nil { 18 fmt.Println(err) 19 }
··· 9 ) 10 11 func main() { 12 + if len(os.Args) != 3 { 13 + fmt.Println("Usage: interdiff <patch1> <patch2>") 14 + os.Exit(1) 15 + } 16 + 17 + patch1, err := os.Open(os.Args[1]) 18 if err != nil { 19 fmt.Println(err) 20 } 21 + patch2, err := os.Open(os.Args[2]) 22 if err != nil { 23 fmt.Println(err) 24 }
+57 -27
interdiff/interdiff.go
··· 64 } 65 } 66 67 // rebuild the original file from a patch 68 func CreateOriginal(file *gitdiff.File) ReconstructedFile { 69 rf := ReconstructedFile{ ··· 92 } 93 94 type MergeError struct { 95 - msg string 96 - mismatchingLines []int64 97 } 98 99 func (m MergeError) Error() string { 100 - return fmt.Sprintf("%s: %v", m.msg, m.mismatchingLines) 101 } 102 103 // best effort merging of two reconstructed files 104 func (this *ReconstructedFile) Merge(other *ReconstructedFile) (*ReconstructedFile, error) { 105 - mismatchingLines := []int64{} 106 mergedFile := ReconstructedFile{} 107 108 var i, j int64 ··· 127 128 if line1.LineNumber == line2.LineNumber { 129 if line1.Content != line2.Content { 130 - mismatchingLines = append(mismatchingLines, line1.LineNumber) 131 } else { 132 mergedFile.AddLine(line1) 133 - i++ 134 - j++ 135 } 136 } else if line1.LineNumber < line2.LineNumber { 137 mergedFile.AddLine(line1) 138 i++ ··· 142 } 143 } 144 145 - if len(mismatchingLines) > 0 { 146 - return nil, MergeError{ 147 - msg: "mismatching lines; this patch might have undergone rebase", 148 - mismatchingLines: mismatchingLines, 149 - } 150 - } else { 151 - return &mergedFile, nil 152 - } 153 } 154 155 func (r *ReconstructedFile) Apply(patch *gitdiff.File) (string, error) { ··· 302 func interdiffFiles(f1, f2 *gitdiff.File) *InterdiffFile { 303 re1 := CreateOriginal(f1) 304 re2 := CreateOriginal(f2) 305 - var interdiffFile InterdiffFile 306 - var status InterdiffFileStatus 307 308 merged, err := re1.Merge(&re2) 309 if err != nil { 310 - status = InterdiffFileStatus{ 311 StatusKind: StatusRebased, 312 Error: err, 313 } 314 } 315 316 rev1, err := merged.Apply(f1) 317 if err != nil { 318 - status = InterdiffFileStatus{ 319 StatusKind: StatusError, 320 Error: err, 321 } 322 } 323 324 rev2, err := merged.Apply(f2) 325 if err != nil { 326 - status = InterdiffFileStatus{ 327 StatusKind: StatusError, 328 Error: err, 329 } 330 } 331 332 diff, err := Unified(rev1, bestName(f1), rev2, bestName(f2)) 333 if err != nil { 334 - status = InterdiffFileStatus{ 335 StatusKind: StatusError, 336 Error: err, 337 } 338 } 339 340 parsed, _, err := gitdiff.Parse(strings.NewReader(diff)) 341 if err != nil { 342 - status = InterdiffFileStatus{ 343 StatusKind: StatusError, 344 Error: err, 345 } 346 } 347 348 if len(parsed) != 1 { 349 // files are identical? 350 - status = InterdiffFileStatus{ 351 StatusKind: StatusUnchanged, 352 } 353 } 354 355 - interdiffFile.Status = status 356 - interdiffFile.Name = bestName(f1) 357 - 358 if interdiffFile.Status.StatusKind == StatusOk { 359 interdiffFile.File = parsed[0] 360 } ··· 386 // we have f1 and f2, calculate interdiff 387 interdiffFile = interdiffFiles(f1, f2) 388 } else { 389 - // only in patch 1 390 interdiffFile = &InterdiffFile{ 391 File: f1, 392 Status: InterdiffFileStatus{ 393 StatusKind: StatusOnlyInOne, 394 }, ··· 408 409 result.Files = append(result.Files, &InterdiffFile{ 410 File: f2, 411 Status: InterdiffFileStatus{ 412 StatusKind: StatusOnlyInTwo, 413 },
··· 64 } 65 } 66 67 + // in-place reverse of a diff 68 + func reverseDiff(file *gitdiff.File) { 69 + file.OldName, file.NewName = file.NewName, file.OldName 70 + file.OldMode, file.NewMode = file.NewMode, file.OldMode 71 + file.BinaryFragment, file.ReverseBinaryFragment = file.ReverseBinaryFragment, file.BinaryFragment 72 + 73 + for _, fragment := range file.TextFragments { 74 + // swap postions 75 + fragment.OldPosition, fragment.NewPosition = fragment.NewPosition, fragment.OldPosition 76 + fragment.OldLines, fragment.NewLines = fragment.NewLines, fragment.OldLines 77 + fragment.LinesAdded, fragment.LinesDeleted = fragment.LinesDeleted, fragment.LinesAdded 78 + 79 + for i := range fragment.Lines { 80 + switch fragment.Lines[i].Op { 81 + case gitdiff.OpAdd: 82 + fragment.Lines[i].Op = gitdiff.OpDelete 83 + case gitdiff.OpDelete: 84 + fragment.Lines[i].Op = gitdiff.OpAdd 85 + default: 86 + // do nothing 87 + } 88 + } 89 + } 90 + } 91 + 92 // rebuild the original file from a patch 93 func CreateOriginal(file *gitdiff.File) ReconstructedFile { 94 rf := ReconstructedFile{ ··· 117 } 118 119 type MergeError struct { 120 + msg string 121 + mismatchingLine int64 122 } 123 124 func (m MergeError) Error() string { 125 + return fmt.Sprintf("%s: %v", m.msg, m.mismatchingLine) 126 } 127 128 // best effort merging of two reconstructed files 129 func (this *ReconstructedFile) Merge(other *ReconstructedFile) (*ReconstructedFile, error) { 130 mergedFile := ReconstructedFile{} 131 132 var i, j int64 ··· 151 152 if line1.LineNumber == line2.LineNumber { 153 if line1.Content != line2.Content { 154 + return nil, MergeError{ 155 + msg: "mismatching lines, this patch might have undergone rebase", 156 + mismatchingLine: line1.LineNumber, 157 + } 158 } else { 159 mergedFile.AddLine(line1) 160 } 161 + i++ 162 + j++ 163 } else if line1.LineNumber < line2.LineNumber { 164 mergedFile.AddLine(line1) 165 i++ ··· 169 } 170 } 171 172 + return &mergedFile, nil 173 } 174 175 func (r *ReconstructedFile) Apply(patch *gitdiff.File) (string, error) { ··· 322 func interdiffFiles(f1, f2 *gitdiff.File) *InterdiffFile { 323 re1 := CreateOriginal(f1) 324 re2 := CreateOriginal(f2) 325 + 326 + interdiffFile := InterdiffFile{ 327 + Name: bestName(f1), 328 + } 329 330 merged, err := re1.Merge(&re2) 331 if err != nil { 332 + interdiffFile.Status = InterdiffFileStatus{ 333 StatusKind: StatusRebased, 334 Error: err, 335 } 336 + return &interdiffFile 337 } 338 339 rev1, err := merged.Apply(f1) 340 if err != nil { 341 + interdiffFile.Status = InterdiffFileStatus{ 342 StatusKind: StatusError, 343 Error: err, 344 } 345 + return &interdiffFile 346 } 347 348 rev2, err := merged.Apply(f2) 349 if err != nil { 350 + interdiffFile.Status = InterdiffFileStatus{ 351 StatusKind: StatusError, 352 Error: err, 353 } 354 + return &interdiffFile 355 } 356 357 diff, err := Unified(rev1, bestName(f1), rev2, bestName(f2)) 358 if err != nil { 359 + interdiffFile.Status = InterdiffFileStatus{ 360 StatusKind: StatusError, 361 Error: err, 362 } 363 + return &interdiffFile 364 } 365 366 parsed, _, err := gitdiff.Parse(strings.NewReader(diff)) 367 if err != nil { 368 + interdiffFile.Status = InterdiffFileStatus{ 369 StatusKind: StatusError, 370 Error: err, 371 } 372 + return &interdiffFile 373 } 374 375 if len(parsed) != 1 { 376 // files are identical? 377 + interdiffFile.Status = InterdiffFileStatus{ 378 StatusKind: StatusUnchanged, 379 } 380 + return &interdiffFile 381 } 382 383 if interdiffFile.Status.StatusKind == StatusOk { 384 interdiffFile.File = parsed[0] 385 } ··· 411 // we have f1 and f2, calculate interdiff 412 interdiffFile = interdiffFiles(f1, f2) 413 } else { 414 + // only in patch 1, this change would have to be "inverted" to dissapear 415 + // from patch 2, so we reverseDiff(f1) 416 + reverseDiff(f1) 417 + 418 interdiffFile = &InterdiffFile{ 419 File: f1, 420 + Name: fileName, 421 Status: InterdiffFileStatus{ 422 StatusKind: StatusOnlyInOne, 423 }, ··· 437 438 result.Files = append(result.Files, &InterdiffFile{ 439 File: f2, 440 + Name: fileName, 441 Status: InterdiffFileStatus{ 442 StatusKind: StatusOnlyInTwo, 443 },