fix: exclude files in copy_to_directory before checking their realpath (#857)

diff --git a/tools/copy_to_directory/main.go b/tools/copy_to_directory/main.go
index aadf748..dba6bda 100644
--- a/tools/copy_to_directory/main.go
+++ b/tools/copy_to_directory/main.go
@@ -26,7 +26,6 @@
 	WorkspacePath string `json:"workspace_path"`
 	Hardlink      bool   `json:"hardlink"`
 
-	Realpath string
 	FileInfo fs.FileInfo
 }
 
@@ -131,9 +130,6 @@
 	// 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.
 	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
@@ -157,53 +153,6 @@
 			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 := common.Realpath(p)
-			if err != nil {
-				if os.IsNotExist(err) {
-					return fmt.Errorf("failed to get realpath of dangling symlink %s: %w", p, err)
-				}
-				return fmt.Errorf("failed to get realpath of %s: %w", p, err)
-			}
-			if srcPaths[linkPath] {
-				// recursive symlink; silently ignore
-				return nil
-			}
-			stat, err := os.Stat(linkPath)
-			if err != nil {
-				return fmt.Errorf("failed to stat file %s pointed to by symlink %s: %w", linkPath, p, err)
-			}
-			if stat.IsDir() {
-				// symlink points to a directory
-				f := fileInfo{
-					Package:       file.Package,
-					Path:          linkPath,
-					RootPath:      file.RootPath,
-					ShortPath:     file.ShortPath,
-					Workspace:     file.Workspace,
-					WorkspacePath: file.WorkspacePath,
-					Hardlink:      file.Hardlink,
-					FileInfo:      stat,
-				}
-				return w.copyDir(cfg, srcPaths, f)
-			} else {
-				// symlink points to a regular file
-				f := fileInfo{
-					Package:       file.Package,
-					Path:          linkPath,
-					RootPath:      file.RootPath,
-					ShortPath:     path.Join(file.ShortPath, r),
-					Workspace:     file.Workspace,
-					WorkspacePath: path.Join(file.WorkspacePath, r),
-					Hardlink:      file.Hardlink,
-					FileInfo:      stat,
-				}
-				return w.copyPath(cfg, f)
-			}
-		}
-
-		// a regular file
 		f := fileInfo{
 			Package:       file.Package,
 			Path:          p,
@@ -214,7 +163,43 @@
 			Hardlink:      file.Hardlink,
 			FileInfo:      info,
 		}
-		return w.copyPath(cfg, f)
+
+		outputPath, err := w.calculateOutputPath(cfg, f)
+		if err != nil {
+			return fmt.Errorf("failed to calculate output path for %s: %w", file.WorkspacePath, err)
+		}
+		if outputPath == "" {
+			// this path is excluded
+			return nil
+		}
+
+		// if file is a symlink, resolve its realpath
+		if info.Mode()&os.ModeSymlink == os.ModeSymlink {
+			realpath, err := common.Realpath(p)
+			if err != nil {
+				if os.IsNotExist(err) {
+					return fmt.Errorf("failed to get realpath of dangling symlink %s: %w", p, err)
+				}
+				return fmt.Errorf("failed to get realpath of %s: %w", p, err)
+			}
+			if srcPaths[realpath] {
+				// recursive symlink; silently ignore
+				return nil
+			}
+			stat, err := os.Stat(realpath)
+			if err != nil {
+				return fmt.Errorf("failed to stat file %s pointed to by symlink %s: %w", realpath, p, err)
+			}
+			f.Path = realpath
+			f.FileInfo = stat
+
+			if stat.IsDir() {
+				// symlink points to a directory
+				return w.copyDir(cfg, srcPaths, f)
+			}
+		}
+
+		return w.copyPath(cfg, f, outputPath)
 	})
 }
 
@@ -305,16 +290,7 @@
 	return path.Join(cfg.Dst, outputPath), nil
 }
 
-func (w *walker) copyPath(cfg *config, file fileInfo) error {
-	outputPath, err := w.calculateOutputPath(cfg, file)
-	if err != nil {
-		return fmt.Errorf("failed to calculate output path %s: %w", file.WorkspacePath, err)
-	}
-	if outputPath == "" {
-		// this path is excluded
-		return nil
-	}
-
+func (w *walker) copyPath(cfg *config, file fileInfo, outputPath string) error {
 	// add this file to the copy Paths
 	dup, exists := copySet[outputPath]
 	if exists {
@@ -329,7 +305,7 @@
 
 	outputDir := path.Dir(outputPath)
 	if !mkdirSet[outputDir] {
-		if err = os.MkdirAll(outputDir, os.ModePerm); err != nil {
+		if err := os.MkdirAll(outputDir, os.ModePerm); err != nil {
 			return err
 		}
 		// https://pkg.go.dev/path#Dir
@@ -353,10 +329,27 @@
 		if err != nil {
 			return fmt.Errorf("failed to lstat file %s: %w", file.Path, err)
 		}
+		file.FileInfo = info
 
+		// if file is a directory, then short-circuit without calculating the output path
+		if file.FileInfo.IsDir() {
+			if err := w.copyDir(cfg, nil, file); err != nil {
+				return err
+			}
+			continue
+		}
+
+		outputPath, err := w.calculateOutputPath(cfg, file)
+		if err != nil {
+			return fmt.Errorf("failed to calculate output path for %s: %w", file.WorkspacePath, err)
+		}
+		if outputPath == "" {
+			// this path is excluded
+			continue
+		}
+
+		// if file is a symlink, resolve its realpath
 		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 := common.Realpath(file.Path)
 			if err != nil {
 				if os.IsNotExist(err) {
@@ -368,20 +361,20 @@
 			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.Path = realpath
 			file.FileInfo = stat
-		} else {
-			file.FileInfo = info
+
+			if file.FileInfo.IsDir() {
+				// symlink points to a directory
+				if err := w.copyDir(cfg, nil, file); err != nil {
+					return err
+				}
+				continue
+			}
 		}
 
-		if file.FileInfo.IsDir() {
-			if err := w.copyDir(cfg, nil, file); err != nil {
-				return err
-			}
-		} else {
-			if err := w.copyPath(cfg, file); err != nil {
-				return err
-			}
+		if err := w.copyPath(cfg, file, outputPath); err != nil {
+			return err
 		}
 	}
 	return nil