1package web
2
3import (
4 "net/http"
5
6 "github.com/charmbracelet/log/v2"
7 "github.com/charmbracelet/soft-serve/git"
8 "github.com/charmbracelet/soft-serve/pkg/config"
9 "github.com/charmbracelet/soft-serve/pkg/proto"
10 "github.com/gorilla/mux"
11)
12
13// TreeData contains data for rendering directory tree view.
14type TreeData struct {
15 RepoBaseData
16 Ref string
17 Path string
18 Entries git.Entries
19 IsCommitHash bool
20}
21
22func repoTree(w http.ResponseWriter, r *http.Request) {
23 ctx := r.Context()
24 logger := log.FromContext(ctx)
25 cfg := config.FromContext(ctx)
26 repo := proto.RepositoryFromContext(ctx)
27 if repo == nil {
28 renderNotFound(w, r)
29 return
30 }
31
32 gr, err := openRepository(repo)
33 if err != nil {
34 logger.Debug("failed to open repository", "repo", repo.Name(), "err", err)
35 renderInternalServerError(w, r)
36 return
37 }
38
39 vars := mux.Vars(r)
40 refAndPath := vars["refAndPath"]
41 ref, path := parseRefAndPath(gr, refAndPath)
42
43 if ref == "" {
44 head, err := gr.HEAD()
45 if err == nil && head != nil {
46 ref = head.Name().Short()
47 }
48 }
49
50 refObj, isCommitHash, err := resolveAndBuildRef(gr, ref)
51 if err != nil {
52 logger.Debug("failed to resolve ref or commit", "repo", repo.Name(), "ref", ref, "err", err)
53 renderNotFound(w, r)
54 return
55 }
56
57 tree, err := gr.TreePath(refObj, path)
58 if err != nil {
59 logger.Debug("failed to get tree path", "repo", repo.Name(), "ref", ref, "path", path, "err", err)
60 renderNotFound(w, r)
61 return
62 }
63
64 entries, err := tree.Entries()
65 if err != nil {
66 logger.Debug("failed to get tree entries", "err", err)
67 renderInternalServerError(w, r)
68 return
69 }
70
71 entries.Sort()
72
73 defaultBranch := getDefaultBranch(gr)
74
75 repoDisplayName := repo.ProjectName()
76 if repoDisplayName == "" {
77 repoDisplayName = repo.Name()
78 }
79
80 title := repo.Name()
81 if path != "." {
82 title += "/" + path
83 }
84 title += " at "
85 if isCommitHash && len(ref) > 7 {
86 title += ref[:7]
87 } else {
88 title += ref
89 }
90 title += " | " + repoDisplayName
91
92 // Build fallback description matching title information
93 descFallback := "Browse "
94 if path != "." {
95 descFallback += path + " at "
96 }
97 if isCommitHash && len(ref) > 7 {
98 descFallback += ref[:7]
99 } else {
100 descFallback += ref
101 }
102 descFallback += " in " + repoDisplayName
103
104 description := getRepoDescriptionOrFallback(repo, descFallback)
105
106 data := TreeData{
107 RepoBaseData: RepoBaseData{
108 BaseData: BaseData{
109 ServerName: cfg.Name,
110 ActiveTab: "tree",
111 Title: title,
112 Description: description,
113 },
114 Repo: repo,
115 DefaultBranch: defaultBranch,
116 },
117 Ref: ref,
118 Path: path,
119 Entries: entries,
120 IsCommitHash: isCommitHash,
121 }
122
123 renderHTML(w, "tree.html", data)
124}