Skip to content

Commit c47c349

Browse files
authored
servegit: eval symlinks on root (#454)
This is a useful use case which allows changing your root by updating a symlink. Additionally it is convenient. We have to explicitly resolve the symlink since filepath.Walk does not support resolving symlinks. We resolve the symlink each time we crawl so the user can update the value of the symlink at runtime. Note: we still ignore symlinks with the repos directory. Supporting that would be more complex due to symlink cycles.
1 parent a640e33 commit c47c349

File tree

2 files changed

+43
-4
lines changed

2 files changed

+43
-4
lines changed

internal/servegit/serve.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,13 @@ func (s *Serve) Repos() ([]Repo, error) {
125125
var repos []Repo
126126
var reposRootIsRepo bool
127127

128-
err := filepath.Walk(s.Root, func(path string, fi os.FileInfo, fileErr error) error {
128+
root, err := filepath.EvalSymlinks(s.Root)
129+
if err != nil {
130+
s.Info.Printf("WARN: ignoring error searching %s: %v", root, err)
131+
return nil, nil
132+
}
133+
134+
err = filepath.Walk(root, func(path string, fi os.FileInfo, fileErr error) error {
129135
if fileErr != nil {
130136
s.Info.Printf("WARN: ignoring error searching %s: %v", path, fileErr)
131137
return nil
@@ -150,11 +156,11 @@ func (s *Serve) Repos() ([]Repo, error) {
150156
return nil
151157
}
152158

153-
subpath, err := filepath.Rel(s.Root, path)
159+
subpath, err := filepath.Rel(root, path)
154160
if err != nil {
155161
// According to WalkFunc docs, path is always filepath.Join(root,
156162
// subpath). So Rel should always work.
157-
s.Info.Fatalf("filepath.Walk returned %s which is not relative to %s: %v", path, s.Root, err)
163+
s.Info.Fatalf("filepath.Walk returned %s which is not relative to %s: %v", path, root, err)
158164
}
159165

160166
name := filepath.ToSlash(subpath)
@@ -190,7 +196,7 @@ func (s *Serve) Repos() ([]Repo, error) {
190196

191197
// Update all names to be relative to the parent of reposRoot. This is to
192198
// give a better name than "." for repos root
193-
abs, err := filepath.Abs(s.Root)
199+
abs, err := filepath.Abs(root)
194200
if err != nil {
195201
return nil, fmt.Errorf("failed to get the absolute path of reposRoot: %w", err)
196202
}

internal/servegit/serve_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,39 @@ func TestReposHandler(t *testing.T) {
8080
}
8181
testReposHandler(t, h, want)
8282
})
83+
84+
// Ensure everything still works if root is a symlink
85+
t.Run("rooted-"+tc.name, func(t *testing.T) {
86+
root := gitInitRepos(t, tc.repos...)
87+
88+
// This is the difference, we create a symlink for root
89+
{
90+
tmp, err := ioutil.TempDir("", "")
91+
if err != nil {
92+
t.Fatal(err)
93+
}
94+
t.Cleanup(func() { os.RemoveAll(tmp) })
95+
96+
symlink := filepath.Join(tmp, "symlink-root")
97+
if err := os.Symlink(root, symlink); err != nil {
98+
t.Fatal(err)
99+
}
100+
root = symlink
101+
}
102+
103+
h := (&Serve{
104+
Info: testLogger(t),
105+
Debug: discardLogger,
106+
Addr: testAddress,
107+
Root: root,
108+
}).handler()
109+
110+
var want []Repo
111+
for _, name := range tc.repos {
112+
want = append(want, Repo{Name: name, URI: path.Join("/repos", name)})
113+
}
114+
testReposHandler(t, h, want)
115+
})
83116
}
84117
}
85118

0 commit comments

Comments
 (0)