in go/pkg/client/tree.go [163:254]
func loadFiles(execRoot, localWorkingDir, remoteWorkingDir string, excl []*command.InputExclusion, filesToProcess []string, fs map[string]*fileSysNode, cache filemetadata.Cache, opts *TreeSymlinkOpts) error {
if opts == nil {
opts = DefaultTreeSymlinkOpts()
}
for len(filesToProcess) != 0 {
path := filesToProcess[0]
filesToProcess = filesToProcess[1:]
if path == "" {
return errors.New("empty Input, use \".\" for entire exec root")
}
absPath := filepath.Join(execRoot, path)
normPath, remoteNormPath, err := getExecRootRelPaths(absPath, execRoot, localWorkingDir, remoteWorkingDir)
if err != nil {
return err
}
meta := cache.Get(absPath)
switch {
// An implication of this is that, if a path is a symlink to a
// directory, then the symlink attribute takes precedence.
case meta.Symlink != nil && meta.Symlink.IsDangling && !opts.Preserved:
// For now, we do not treat a dangling symlink as an error. In the case
// where the symlink is not preserved (i.e. needs to be converted to a
// file), we simply ignore this path in the finalized tree.
continue
case meta.Symlink != nil && opts.Preserved:
if shouldIgnore(absPath, command.SymlinkInputType, excl) {
continue
}
targetExecRoot, targetSymDir, err := getTargetRelPath(execRoot, normPath, meta.Symlink)
if err != nil {
return err
}
fs[remoteNormPath] = &fileSysNode{
// We cannot directly use meta.Symlink.Target, because it could be
// an absolute path. Since the remote worker will map the exec root
// to a different directory, we must strip away the local exec root.
// See https://github.com/bazelbuild/remote-apis-sdks/pull/229#discussion_r524830458
symlink: &symlinkNode{target: targetSymDir},
}
if !meta.Symlink.IsDangling && opts.FollowsTarget {
// getTargetRelPath validates this target is under execRoot,
// and the iteration loop will get the relative path to execRoot,
filesToProcess = append(filesToProcess, targetExecRoot)
}
case meta.IsDirectory:
if shouldIgnore(absPath, command.DirectoryInputType, excl) {
continue
} else if meta.Err != nil {
return meta.Err
}
f, err := os.Open(absPath)
if err != nil {
return err
}
files, err := f.Readdirnames(-1)
f.Close()
if err != nil {
return err
}
if len(files) == 0 {
if normPath != "." {
fs[remoteNormPath] = &fileSysNode{emptyDirectoryMarker: true}
}
continue
}
for _, f := range files {
filesToProcess = append(filesToProcess, filepath.Join(normPath, f))
}
default:
if shouldIgnore(absPath, command.FileInputType, excl) {
continue
} else if meta.Err != nil {
return meta.Err
}
fs[remoteNormPath] = &fileSysNode{
file: &fileNode{
ue: uploadinfo.EntryFromFile(meta.Digest, absPath),
isExecutable: meta.IsExecutable,
},
}
}
}
return nil
}