Skip to content

Instantly share code, notes, and snippets.

@njhale
Last active August 15, 2023 18:28
Show Gist options
  • Save njhale/f8b06cc742a8f04030e0c0e18d1779a7 to your computer and use it in GitHub Desktop.
Save njhale/f8b06cc742a8f04030e0c0e18d1779a7 to your computer and use it in GitHub Desktop.
Clone a directory for the lifetime of a Go test
package forkdir
import (
"fmt"
"io"
"os"
"path/filepath"
"testing"
"github.com/acorn-io/z"
)
// ForkDir creates a temporary copy of a directory tree and returns its path.
// Each copy is tied to the lifetime of the test that created it, and is deleted when that test is over.
func ForkDir(t *testing.T, path string) (forkPath string) {
t.Helper()
// Create a temporary directory to hold the copies
pattern := fmt.Sprintf("%s.*.%s", t.Name(), filepath.Base(path))
forkPath = z.MustBe(os.MkdirTemp("", pattern))
// Be sure to delete the copy once the test that requested it is done
t.Cleanup(func() {
z.Must(os.Remove(forkPath))
})
copyFile := func(src, dest string) {
srcFile, destFile := z.MustBe(os.Open(src)), z.MustBe(os.Create(dest))
defer func() { z.Must(srcFile.Close(), destFile.Close()) }()
z.MustBe(io.Copy(destFile, srcFile))
}
var copyDir func(string, string)
copyDir = func(src, dest string) {
for _, fd := range z.MustBe(os.ReadDir(src)) {
name := fd.Name()
nextSrc, nextDest := filepath.Join(src, name), filepath.Join(dest, name)
switch mode := fd.Type(); {
case mode.IsDir():
// Traverse subtree
copyDir(nextSrc, nextDest)
case mode.IsRegular():
// Copy regular file
copyFile(nextSrc, nextDest)
}
// Ignore links and other file types
}
}
copyDir(path, forkPath)
return forkPath
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment