func loadFiles()

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
}