@@ -68,12 +68,14 @@ type Commit struct { |
| 68 |
} |
68 |
} |
| 69 |
|
69 |
|
| 70 |
type TreeEntry struct { |
70 |
type TreeEntry struct { |
| 71 |
Mode string |
71 |
Mode string |
| 72 |
Type string |
72 |
Type string |
| 73 |
OID string |
73 |
OID string |
| 74 |
Size int64 |
74 |
Size int64 |
| 75 |
Name string |
75 |
Name string |
| 76 |
URL string |
76 |
URL string |
|
|
77 |
CommitMessage string |
|
|
78 |
CommitURL string |
| 77 |
} |
79 |
} |
| 78 |
|
80 |
|
| 79 |
type Crumb struct { |
81 |
type Crumb struct { |
@@ -326,6 +328,9 @@ func (g *Generator) treePage(ctx context.Context, branch, oid, dir string, summa |
| 326 |
entries[i].URL = routeURL(g.BaseURL, path.Join("blob", branch, fullPath)) |
328 |
entries[i].URL = routeURL(g.BaseURL, path.Join("blob", branch, fullPath)) |
| 327 |
} |
329 |
} |
| 328 |
} |
330 |
} |
|
|
331 |
if err := g.populateEntryCommits(ctx, oid, dir, entries, summary.CommitsURL); err != nil { |
|
|
332 |
return Page{}, err |
|
|
333 |
} |
| 329 |
data := g.pageData("tree", g.RepoName, branch, summary) |
334 |
data := g.pageData("tree", g.RepoName, branch, summary) |
| 330 |
data.Path = dir |
335 |
data.Path = dir |
| 331 |
data.Breadcrumbs = g.breadcrumbs(branch, dir) |
336 |
data.Breadcrumbs = g.breadcrumbs(branch, dir) |
@@ -353,6 +358,60 @@ func (g *Generator) treePage(ctx context.Context, branch, oid, dir string, summa |
| 353 |
return Page{Route: path.Join("tree", branch, dir), Body: body, ContentType: "text/html; charset=utf-8", Cache: siteCache}, nil |
358 |
return Page{Route: path.Join("tree", branch, dir), Body: body, ContentType: "text/html; charset=utf-8", Cache: siteCache}, nil |
| 354 |
} |
359 |
} |
| 355 |
|
360 |
|
|
|
361 |
func (g *Generator) populateEntryCommits(ctx context.Context, oid, dir string, entries []TreeEntry, commitsURL string) error { |
|
|
362 |
if len(entries) == 0 { |
|
|
363 |
return nil |
|
|
364 |
} |
|
|
365 |
ctx, cancel := context.WithCancel(ctx) |
|
|
366 |
defer cancel() |
|
|
367 |
workers := min(8, len(entries)) |
|
|
368 |
jobs := make(chan int) |
|
|
369 |
var wait sync.WaitGroup |
|
|
370 |
var once sync.Once |
|
|
371 |
var firstErr error |
|
|
372 |
for range workers { |
|
|
373 |
wait.Add(1) |
|
|
374 |
go func() { |
|
|
375 |
defer wait.Done() |
|
|
376 |
for index := range jobs { |
|
|
377 |
commit, err := g.entryCommit(ctx, oid, path.Join(dir, entries[index].Name)) |
|
|
378 |
if err != nil { |
|
|
379 |
once.Do(func() { |
|
|
380 |
firstErr = err |
|
|
381 |
cancel() |
|
|
382 |
}) |
|
|
383 |
continue |
|
|
384 |
} |
|
|
385 |
entries[index].CommitMessage = commit.Message |
|
|
386 |
entries[index].CommitURL = commitsURL + "#" + commit.OID |
|
|
387 |
} |
|
|
388 |
}() |
|
|
389 |
} |
|
|
390 |
sendJobs: |
|
|
391 |
for index := range entries { |
|
|
392 |
select { |
|
|
393 |
case jobs <- index: |
|
|
394 |
case <-ctx.Done(): |
|
|
395 |
break sendJobs |
|
|
396 |
} |
|
|
397 |
} |
|
|
398 |
close(jobs) |
|
|
399 |
wait.Wait() |
|
|
400 |
return firstErr |
|
|
401 |
} |
|
|
402 |
|
|
|
403 |
func (g *Generator) entryCommit(ctx context.Context, oid, filePath string) (Commit, error) { |
|
|
404 |
out, err := g.Git.Run(ctx, "--literal-pathspecs", "log", "-1", "--format=%H%x00%s", oid, "--", filePath) |
|
|
405 |
if err != nil { |
|
|
406 |
return Commit{}, err |
|
|
407 |
} |
|
|
408 |
fields := strings.Split(strings.TrimSpace(string(out)), "\x00") |
|
|
409 |
if len(fields) != 2 || fields[0] == "" { |
|
|
410 |
return Commit{}, fmt.Errorf("could not find the latest commit for %s", filePath) |
|
|
411 |
} |
|
|
412 |
return Commit{OID: fields[0], Message: fields[1]}, nil |
|
|
413 |
} |
|
|
414 |
|
| 356 |
func (g *Generator) blobPages(ctx context.Context, branch, oid string, entry TreeEntry, summary branchSummary) ([]Page, error) { |
415 |
func (g *Generator) blobPages(ctx context.Context, branch, oid string, entry TreeEntry, summary branchSummary) ([]Page, error) { |
| 357 |
var content []byte |
416 |
var content []byte |
| 358 |
var err error |
417 |
var err error |