Commit c47c3494 authored by Keegan Carruthers-Smith's avatar Keegan Carruthers-Smith Committed by GitHub

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.
parent a640e337
......@@ -125,7 +125,13 @@ func (s *Serve) Repos() ([]Repo, error) {
var repos []Repo
var reposRootIsRepo bool
err := filepath.Walk(s.Root, func(path string, fi os.FileInfo, fileErr error) error {
root, err := filepath.EvalSymlinks(s.Root)
if err != nil {
s.Info.Printf("WARN: ignoring error searching %s: %v", root, err)
return nil, nil
}
err = filepath.Walk(root, func(path string, fi os.FileInfo, fileErr error) error {
if fileErr != nil {
s.Info.Printf("WARN: ignoring error searching %s: %v", path, fileErr)
return nil
......@@ -150,11 +156,11 @@ func (s *Serve) Repos() ([]Repo, error) {
return nil
}
subpath, err := filepath.Rel(s.Root, path)
subpath, err := filepath.Rel(root, path)
if err != nil {
// According to WalkFunc docs, path is always filepath.Join(root,
// subpath). So Rel should always work.
s.Info.Fatalf("filepath.Walk returned %s which is not relative to %s: %v", path, s.Root, err)
s.Info.Fatalf("filepath.Walk returned %s which is not relative to %s: %v", path, root, err)
}
name := filepath.ToSlash(subpath)
......@@ -190,7 +196,7 @@ func (s *Serve) Repos() ([]Repo, error) {
// Update all names to be relative to the parent of reposRoot. This is to
// give a better name than "." for repos root
abs, err := filepath.Abs(s.Root)
abs, err := filepath.Abs(root)
if err != nil {
return nil, fmt.Errorf("failed to get the absolute path of reposRoot: %w", err)
}
......
......@@ -80,6 +80,39 @@ func TestReposHandler(t *testing.T) {
}
testReposHandler(t, h, want)
})
// Ensure everything still works if root is a symlink
t.Run("rooted-"+tc.name, func(t *testing.T) {
root := gitInitRepos(t, tc.repos...)
// This is the difference, we create a symlink for root
{
tmp, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { os.RemoveAll(tmp) })
symlink := filepath.Join(tmp, "symlink-root")
if err := os.Symlink(root, symlink); err != nil {
t.Fatal(err)
}
root = symlink
}
h := (&Serve{
Info: testLogger(t),
Debug: discardLogger,
Addr: testAddress,
Root: root,
}).handler()
var want []Repo
for _, name := range tc.repos {
want = append(want, Repo{Name: name, URI: path.Join("/repos", name)})
}
testReposHandler(t, h, want)
})
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment