in src/rust/engine/fs/src/snapshot.rs [110:196]
fn ingest_directory_from_sorted_path_stats<
S: StoreFileByDigest<Error> + Sized + Clone,
Error: fmt::Debug + 'static + Send,
>(
store: Store,
file_digester: &S,
path_stats: &[PathStat],
) -> BoxFuture<Digest, String> {
let mut file_futures: Vec<BoxFuture<bazel_protos::remote_execution::FileNode, String>> =
Vec::new();
let mut dir_futures: Vec<BoxFuture<bazel_protos::remote_execution::DirectoryNode, String>> =
Vec::new();
for (first_component, group) in &path_stats
.iter()
.cloned()
.group_by(|s| s.path().components().next().unwrap().as_os_str().to_owned())
{
let mut path_group: Vec<PathStat> = group.collect();
if path_group.len() == 1 && path_group[0].path().components().count() == 1 {
// Exactly one entry with exactly one component indicates either a file in this directory,
// or an empty directory.
// If the child is a non-empty directory, or a file therein, there must be multiple
// PathStats with that prefix component, and we will handle that in the recursive
// save_directory call.
match path_group.pop().unwrap() {
PathStat::File { ref stat, .. } => {
let is_executable = stat.is_executable;
file_futures.push(
file_digester
.clone()
.store_by_digest(stat.clone())
.map_err(|e| format!("{:?}", e))
.and_then(move |digest| {
let mut file_node = bazel_protos::remote_execution::FileNode::new();
file_node.set_name(osstring_as_utf8(first_component)?);
file_node.set_digest((&digest).into());
file_node.set_is_executable(is_executable);
Ok(file_node)
})
.to_boxed(),
);
}
PathStat::Dir { .. } => {
// Because there are no children of this Dir, it must be empty.
dir_futures.push(
store
.record_directory(&bazel_protos::remote_execution::Directory::new(), true)
.map(move |digest| {
let mut directory_node = bazel_protos::remote_execution::DirectoryNode::new();
directory_node.set_name(osstring_as_utf8(first_component).unwrap());
directory_node.set_digest((&digest).into());
directory_node
})
.to_boxed(),
);
}
}
} else {
dir_futures.push(
// TODO: Memoize this in the graph
Snapshot::ingest_directory_from_sorted_path_stats(
store.clone(),
file_digester,
&paths_of_child_dir(path_group),
)
.and_then(move |digest| {
let mut dir_node = bazel_protos::remote_execution::DirectoryNode::new();
dir_node.set_name(osstring_as_utf8(first_component)?);
dir_node.set_digest((&digest).into());
Ok(dir_node)
})
.to_boxed(),
);
}
}
join_all(dir_futures)
.join(join_all(file_futures))
.and_then(move |(dirs, files)| {
let mut directory = bazel_protos::remote_execution::Directory::new();
directory.set_directories(protobuf::RepeatedField::from_vec(dirs));
directory.set_files(protobuf::RepeatedField::from_vec(files));
store.record_directory(&directory, true)
})
.to_boxed()
}