fix: on Windows you must call filepath.Walkdir on the realpath and not the symlink path (#335)

This commit is contained in:
Greg Magolan 2023-01-16 15:41:39 -08:00 committed by GitHub
parent ce043b299d
commit 74caa5c097
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 50 additions and 16 deletions

View File

@ -21,6 +21,14 @@ def go_dependencies():
sum = "h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=",
version = "v0.5.8",
)
go_repository(
name = "com_github_yookoala_realpath",
build_file_proto_mode = "disable_global",
importpath = "github.com/yookoala/realpath",
sum = "h1:7OA9pj4FZd+oZDsyvXWQvjn5oBdcHRTV44PpdMSuImQ=",
version = "v1.0.0",
)
go_repository(
name = "org_golang_x_exp",
build_file_proto_mode = "disable_global",

1
go.mod
View File

@ -4,5 +4,6 @@ go 1.19
require (
github.com/bmatcuk/doublestar/v4 v4.6.0
github.com/yookoala/realpath v1.0.0
golang.org/x/exp v0.0.0-20221230185412-738e83a70c30
)

2
go.sum
View File

@ -1,4 +1,6 @@
github.com/bmatcuk/doublestar/v4 v4.6.0 h1:HTuxyug8GyFbRkrffIpzNCSK4luc0TY3wzXvzIZhEXc=
github.com/bmatcuk/doublestar/v4 v4.6.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/yookoala/realpath v1.0.0 h1:7OA9pj4FZd+oZDsyvXWQvjn5oBdcHRTV44PpdMSuImQ=
github.com/yookoala/realpath v1.0.0/go.mod h1:gJJMA9wuX7AcqLy1+ffPatSCySA1FQ2S8Ya9AIoYBpE=
golang.org/x/exp v0.0.0-20221230185412-738e83a70c30 h1:m9O6OTJ627iFnN2JIWfdqlZCzneRO6EEBsHXI25P8ws=
golang.org/x/exp v0.0.0-20221230185412-738e83a70c30/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=

View File

@ -1,6 +1,8 @@
package common
import "path/filepath"
import (
"path/filepath"
)
// Same as filepath.Rel except that it normalizes result to forward slashes
// slashes since filepath.Rel will convert to system slashes

View File

@ -5,7 +5,10 @@ go_library(
srcs = ["main.go"],
importpath = "github.com/aspect-build/bazel-lib/tools/copy_directory",
visibility = ["//visibility:public"],
deps = ["//tools/common"],
deps = [
"//tools/common",
"@com_github_yookoala_realpath//:go_default_library",
],
)
go_binary(

View File

@ -5,11 +5,11 @@ import (
"io/fs"
"log"
"os"
"path"
"path/filepath"
"sync"
"github.com/aspect-build/bazel-lib/tools/common"
"github.com/yookoala/realpath"
)
type pathSet map[string]bool
@ -46,13 +46,10 @@ func copyDir(src string, dst string) error {
if info.Mode()&os.ModeSymlink == os.ModeSymlink {
// symlink to directories are intentionally never followed by filepath.Walk to avoid infinite recursion
linkPath, err := os.Readlink(p)
linkPath, err := realpath.Realpath(p)
if err != nil {
return err
}
if !path.IsAbs(linkPath) {
linkPath = path.Join(path.Dir(p), linkPath)
}
if srcPaths[linkPath] {
// recursive symlink; silently ignore
return nil

View File

@ -8,6 +8,7 @@ go_library(
deps = [
"//tools/common",
"@com_github_bmatcuk_doublestar_v4//:doublestar",
"@com_github_yookoala_realpath//:go_default_library",
"@org_golang_x_exp//maps",
],
)

View File

@ -14,6 +14,7 @@ import (
"github.com/aspect-build/bazel-lib/tools/common"
"github.com/bmatcuk/doublestar/v4"
"github.com/yookoala/realpath"
"golang.org/x/exp/maps"
)
@ -26,6 +27,7 @@ type fileInfo struct {
WorkspacePath string `json:"workspace_path"`
Hardlink bool `json:"hardlink"`
Realpath string
FileInfo fs.FileInfo
}
@ -124,7 +126,11 @@ func copyDir(cfg *config, srcPaths pathSet, file fileInfo) error {
srcPaths[file.Path] = true
// filepath.WalkDir walks the file tree rooted at root, calling fn for each file or directory in
// the tree, including root. See https://pkg.go.dev/path/filepath#WalkDir for more info.
return filepath.WalkDir(file.Path, func(p string, dirEntry fs.DirEntry, err error) error {
walkPath := file.Path
if file.Realpath != "" {
walkPath = file.Realpath
}
return filepath.WalkDir(walkPath, func(p string, dirEntry fs.DirEntry, err error) error {
if err != nil {
return err
}
@ -142,20 +148,17 @@ func copyDir(cfg *config, srcPaths pathSet, file fileInfo) error {
return err
}
r, err := common.FileRel(file.Path, p)
r, err := common.FileRel(walkPath, p)
if err != nil {
return err
}
if info.Mode()&os.ModeSymlink == os.ModeSymlink {
// symlink to directories are intentionally never followed by filepath.Walk to avoid infinite recursion
linkPath, err := os.Readlink(p)
linkPath, err := realpath.Realpath(p)
if err != nil {
return err
}
if !path.IsAbs(linkPath) {
linkPath = path.Join(path.Dir(p), linkPath)
}
if srcPaths[linkPath] {
// recursive symlink; silently ignore
return nil
@ -330,11 +333,28 @@ func copyPath(cfg *config, file fileInfo) error {
func copyPaths(cfg *config) error {
for _, file := range cfg.Files {
stat, err := os.Stat(file.Path)
info, err := os.Lstat(file.Path)
if err != nil {
return fmt.Errorf("failed to stat file %s: %w", file.Path, err)
return fmt.Errorf("failed to lstat file %s: %w", file.Path, err)
}
file.FileInfo = stat
if info.Mode()&os.ModeSymlink == os.ModeSymlink {
// On Windows, filepath.WalkDir doesn't like directory symlinks so we must
// call filepath.WalkDir on the realpath
realpath, err := realpath.Realpath(file.Path)
if err != nil {
return err
}
stat, err := os.Stat(realpath)
if err != nil {
return fmt.Errorf("failed to stat file %s pointed to by symlink %s: %w", realpath, file.Path, err)
}
file.Realpath = realpath
file.FileInfo = stat
} else {
file.FileInfo = info
}
if file.FileInfo.IsDir() {
if err := copyDir(cfg, nil, file); err != nil {
return err