Skip to content

Commit

Permalink
feat: use system-tools from build prefix if they are available (#825)
Browse files Browse the repository at this point in the history
  • Loading branch information
wolfv authored Apr 29, 2024
1 parent e1fa6bb commit d52acf2
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 16 deletions.
4 changes: 3 additions & 1 deletion src/post_process/relink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ pub fn relink(temp_files: &TempFiles, output: &Output) -> Result<(), RelinkError
let encoded_prefix = &temp_files.encoded_prefix;

let mut binaries = HashSet::new();
// allow to use tools from build prefix such as patchelf, install_name_tool, ...
let system_tools = output.system_tools.with_build_prefix(output.build_prefix());

for (p, content_type) in temp_files.content_type_map() {
let metadata = fs::symlink_metadata(p)?;
Expand All @@ -185,7 +187,7 @@ pub fn relink(temp_files: &TempFiles, output: &Output) -> Result<(), RelinkError
encoded_prefix,
&rpaths,
rpath_allowlist,
&output.system_tools,
&system_tools,
)?;
binaries.insert(p.clone());
}
Expand Down
63 changes: 48 additions & 15 deletions src/system_tools.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
//! System tools are installed on the system (git, patchelf, install_name_tool, etc.)
use rattler_conda_types::Platform;
use rattler_shell::{activation::Activator, shell};
use serde::{Deserialize, Serialize, Serializer};
use std::{
collections::{BTreeMap, HashMap},
path::PathBuf,
path::{Path, PathBuf},
process::Command,
sync::{Arc, Mutex},
};
Expand Down Expand Up @@ -59,6 +61,7 @@ pub struct SystemTools {
rattler_build_version: String,
used_tools: Arc<Mutex<HashMap<Tool, String>>>,
found_tools: Arc<Mutex<HashMap<Tool, PathBuf>>>,
build_prefix: Option<PathBuf>,
}

impl Default for SystemTools {
Expand All @@ -67,6 +70,7 @@ impl Default for SystemTools {
rattler_build_version: env!("CARGO_PKG_VERSION").to_string(),
used_tools: Arc::new(Mutex::new(HashMap::new())),
found_tools: Arc::new(Mutex::new(HashMap::new())),
build_prefix: None,
}
}
}
Expand All @@ -77,6 +81,15 @@ impl SystemTools {
Self::default()
}

/// Create a copy of the system tools object and add a build prefix to search for tools.
/// Tools that are found in the build prefix are not added to the used tools list.
pub fn with_build_prefix(&self, prefix: &Path) -> Self {
Self {
build_prefix: Some(prefix.to_path_buf()),
..self.clone()
}
}

/// Create a new system tools object from a previous run so that we can warn if the versions
/// of the tools have changed
pub fn from_previous_run(
Expand All @@ -95,15 +108,32 @@ impl SystemTools {
rattler_build_version,
used_tools: Arc::new(Mutex::new(used_tools)),
found_tools: Arc::new(Mutex::new(HashMap::new())),
build_prefix: None,
}
}

/// Find the tool in the system and return the path to the tool
fn find_tool(&self, tool: Tool) -> Result<PathBuf, which::Error> {
let which = |tool: &str| -> Result<PathBuf, which::Error> {
if let Some(build_prefix) = &self.build_prefix {
let build_prefix_activator =
Activator::from_path(build_prefix, shell::Bash, Platform::current()).unwrap();

let paths = std::env::join_paths(build_prefix_activator.paths).ok();
let mut found_tool = which::which_in_global(&tool, paths)?;

// if the tool is found in the build prefix, return it
if let Some(found_tool) = found_tool.next() {
return Ok(found_tool);
}
}
which::which(tool)
};

let (tool_path, found_version) = match tool {
Tool::Patchelf => {
let path = which::which("patchelf")?;
// patchelf version
let path = which("patchelf")?;
// patch elf version
let output = std::process::Command::new(&path)
.arg("--version")
.output()
Expand All @@ -113,15 +143,15 @@ impl SystemTools {
(path, found_version.to_string())
}
Tool::InstallNameTool => {
let path = which::which("install_name_tool")?;
let path = which("install_name_tool")?;
(path, "".to_string())
}
Tool::Codesign => {
let path = which::which("codesign")?;
let path = which("codesign")?;
(path, "".to_string())
}
Tool::Git => {
let path = which::which("git")?;
let path = which("git")?;
let output = std::process::Command::new(&path)
.arg("--version")
.output()
Expand All @@ -131,7 +161,7 @@ impl SystemTools {
(path, found_version.to_string())
}
Tool::Patch => {
let path = which::which("patch")?;
let path = which("patch")?;
let version = std::process::Command::new(&path)
.arg("--version")
.output()
Expand All @@ -147,6 +177,13 @@ impl SystemTools {

let found_version = found_version.trim().to_string();

if let Some(build_prefix) = &self.build_prefix {
// Do not cache tools found in the (temporary) build prefix
if tool_path.starts_with(build_prefix) {
return Ok(tool_path);
}
}

self.found_tools
.lock()
.unwrap()
Expand All @@ -171,14 +208,9 @@ impl SystemTools {
/// Create a new `std::process::Command` for the given tool. The command is created with the
/// path to the tool and can be further configured with arguments and environment variables.
pub fn call(&self, tool: Tool) -> Result<Command, ToolError> {
let found_tool = self.found_tools.lock().unwrap().get(&tool).cloned();
let tool_path = if let Some(tool) = found_tool {
tool
} else {
self.find_tool(tool)
.map_err(|e| ToolError::ToolNotFound(tool, e))?
};

let tool_path = self
.find_tool(tool)
.map_err(|e| ToolError::ToolNotFound(tool, e))?;
Ok(std::process::Command::new(tool_path))
}
}
Expand Down Expand Up @@ -244,6 +276,7 @@ mod tests {
rattler_build_version: "0.0.0".to_string(),
used_tools: Arc::new(Mutex::new(used_tools)),
found_tools: Arc::new(Mutex::new(HashMap::new())),
build_prefix: None,
};

let json = serde_json::to_string_pretty(&system_tool).unwrap();
Expand Down

0 comments on commit d52acf2

Please sign in to comment.