From e3ff2872701d9f1d6f4f5223641092ec19c10a7a Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Mon, 1 Nov 2021 00:16:41 +0100 Subject: runner: detect file conflicts in dependencies again The new code will also detect conflicts between the rootfs and individual dependencies. --- crates/runner/src/task.rs | 67 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 2 deletions(-) (limited to 'crates/runner/src/task.rs') diff --git a/crates/runner/src/task.rs b/crates/runner/src/task.rs index 941e5f1..174768c 100644 --- a/crates/runner/src/task.rs +++ b/crates/runner/src/task.rs @@ -1,8 +1,8 @@ use std::{ - collections::{BTreeMap, HashMap}, + collections::{BTreeMap, HashMap, HashSet}, io::{self, BufWriter}, os::unix::prelude::CommandExt, - path::Path, + path::{Path, PathBuf}, process::{self, Command, Stdio}, time::Instant, }; @@ -18,6 +18,7 @@ use serde::Serialize; use tee_readwrite::{TeeReader, TeeWriter}; use common::{error::*, string_hash::*, types::*}; +use walkdir::WalkDir; use super::{ jobserver::Jobserver, @@ -126,6 +127,59 @@ fn init_task(input_hash: &InputHash, task: &Task) -> Result { Ok(mount) } +fn get_contents, P2: AsRef>( + path: P1, + prefix: P2, +) -> Result<(HashSet, HashSet)> { + let mut dirs = HashSet::new(); + let mut files = HashSet::new(); + + let root: PathBuf = Path::new("/").join(prefix.as_ref()); + + for result in WalkDir::new(path.as_ref()).min_depth(1).into_iter() { + let entry = result + .with_context(|| format!("Failed to list contents of directory {:?}", path.as_ref()))?; + let is_dir = entry.file_type().is_dir(); + let entry_path = root.join(entry.into_path().strip_prefix(path.as_ref()).unwrap()); + if is_dir { + dirs.insert(entry_path); + } else { + files.insert(entry_path); + } + } + + dirs.insert(root); + + Ok((dirs, files)) +} + +fn check_conflicts( + dirs1: &HashSet, + files1: &HashSet, + dirs2: &HashSet, + files2: &HashSet, +) -> Result<()> { + let mut conflicts = Vec::new(); + + conflicts.extend(files1.intersection(files2)); + conflicts.extend(dirs1.intersection(files2)); + conflicts.extend(files1.intersection(dirs2)); + + if !conflicts.is_empty() { + let mut conflict_strings: Box<[_]> = conflicts + .into_iter() + .map(|path| path.to_string_lossy().to_string()) + .collect(); + conflict_strings.sort(); + return Err(Error::new(format!( + "Found the following file conflicts in dependencies:\n{}", + conflict_strings.join("\n") + ))); + } + + Ok(()) +} + fn init_task_rootfs(input_hash: &InputHash, depends: &DependMap) -> Result> { let task_tmp_dir = paths::task_tmp_dir(input_hash); let mount_target = paths::join(&[&task_tmp_dir, paths::TASK_TMP_ROOTFS_SUBDIR]); @@ -143,6 +197,8 @@ fn init_task_rootfs(input_hash: &InputHash, depends: &DependMap) -> Result Result = dep_hashes.iter().map(paths::depend_dir).collect(); + for dep in dep_paths.iter() { + let (dep_dirs, dep_files) = get_contents(dep, path)?; + check_conflicts(&dirs, &files, &dep_dirs, &dep_files)?; + dirs.extend(dep_dirs); + files.extend(dep_files); + } + let options = format!( "xino=off,index=off,metacopy=off,lowerdir={lower}:{base}", lower = dep_paths.join(":"), -- cgit v1.2.3