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