diff --git a/crates/rattler/src/install/mod.rs b/crates/rattler/src/install/mod.rs index 82c6bfbf1..68dc8fe79 100644 --- a/crates/rattler/src/install/mod.rs +++ b/crates/rattler/src/install/mod.rs @@ -56,6 +56,7 @@ use rattler_conda_types::{ prefix_record::PathsEntry, Platform, }; +use rattler_package_streaming::{fs::extract, ExtractError}; use simple_spawn_blocking::Cancelled; use tokio::task::JoinError; use tracing::instrument; @@ -102,6 +103,14 @@ pub enum InstallError { #[error("failed to create target directory")] FailedToCreateTargetDirectory(#[source] std::io::Error), + /// Failed to create a temporary directory. + #[error("failed to create temporary directory")] + FailedToCreateTempDirectory(#[source] std::io::Error), + + /// Failed to extract a conda package. + #[error("failed to extract conda package")] + FailedToExtractPackage(#[source] ExtractError), + /// A noarch package could not be installed because no python version was /// specified. #[error("cannot install noarch python package because there is no python version specified")] @@ -242,6 +251,29 @@ pub struct InstallOptions { pub apple_codesign_behavior: AppleCodeSignBehavior, } +/// Given a non-extracted conda package (`package_path`), installs its files +/// to the `target_dir`. +/// +/// Returns a [`PathsEntry`] for every file that was linked into the target +/// directory. The entries are ordered in the same order as they appear in the +/// `paths.json` file of the package. +pub async fn link_package_from_archive( + package_path: &Path, + target_dir: &Path, + driver: &InstallDriver, + options: InstallOptions, +) -> Result, InstallError> { + let temp_dir = tempfile::tempdir().map_err(InstallError::FailedToCreateTempDirectory)?; + tracing::debug!( + "extracting {} to temporary directory {}", + package_path.display(), + temp_dir.path().display() + ); + + extract(package_path, temp_dir.path()).map_err(InstallError::FailedToExtractPackage)?; + link_package(temp_dir.path(), target_dir, driver, options).await +} + /// Given an extracted package archive (`package_dir`), installs its files to /// the `target_dir`. /// @@ -722,7 +754,9 @@ mod test { use crate::{ get_test_data_dir, - install::{link_package, InstallDriver, InstallOptions, PythonInfo}, + install::{ + link_package, link_package_from_archive, InstallDriver, InstallOptions, PythonInfo, + }, package_cache::PackageCache, }; @@ -876,4 +910,29 @@ mod test { insta::assert_yaml_snapshot!(paths); } + + #[rstest::rstest] + #[case("clobber-tar-bz2", "clobber/clobber-1-0.1.0-h4616a5c_0.tar.bz2")] + #[case("clobber-conda", "clobber/clobber-python-0.1.0-cpython.conda")] + #[tracing_test::traced_test] + #[tokio::test] + async fn test_link_package_from_archive(#[case] package: &str, #[case] package_path: &str) { + let environment_dir = tempfile::TempDir::new().unwrap(); + + let package_path = get_test_data_dir().join(package_path); + + let install_driver = InstallDriver::default(); + + // Link the package + let paths = link_package_from_archive( + &package_path, + environment_dir.path(), + &install_driver, + InstallOptions::default(), + ) + .await + .unwrap(); + + insta::assert_yaml_snapshot!(format!("link_package_from_archive-{}", package), paths); + } } diff --git a/crates/rattler/src/install/snapshots/rattler__install__test__link_package_from_archive-clobber-conda.snap b/crates/rattler/src/install/snapshots/rattler__install__test__link_package_from_archive-clobber-conda.snap new file mode 100644 index 000000000..52b542814 --- /dev/null +++ b/crates/rattler/src/install/snapshots/rattler__install__test__link_package_from_archive-clobber-conda.snap @@ -0,0 +1,11 @@ +--- +source: crates/rattler/src/install/mod.rs +assertion_line: 937 +expression: paths +snapshot_kind: text +--- +- _path: bin/python + path_type: hardlink + sha256: 9e13091076809d9c845dc484b21ae2ba965895705d7fec77dd51ec3af7e26e31 + sha256_in_prefix: 9e13091076809d9c845dc484b21ae2ba965895705d7fec77dd51ec3af7e26e31 + size_in_bytes: 8 diff --git a/crates/rattler/src/install/snapshots/rattler__install__test__link_package_from_archive-clobber-tar-bz2.snap b/crates/rattler/src/install/snapshots/rattler__install__test__link_package_from_archive-clobber-tar-bz2.snap new file mode 100644 index 000000000..4daa57049 --- /dev/null +++ b/crates/rattler/src/install/snapshots/rattler__install__test__link_package_from_archive-clobber-tar-bz2.snap @@ -0,0 +1,16 @@ +--- +source: crates/rattler/src/install/mod.rs +assertion_line: 937 +expression: paths +snapshot_kind: text +--- +- _path: another-clobber.txt + path_type: hardlink + sha256: dd79cf28afefb8038e9ca3141f2d47ca3c764cd50b880eb65263705792b909c8 + sha256_in_prefix: dd79cf28afefb8038e9ca3141f2d47ca3c764cd50b880eb65263705792b909c8 + size_in_bytes: 10 +- _path: clobber.txt + path_type: hardlink + sha256: dd79cf28afefb8038e9ca3141f2d47ca3c764cd50b880eb65263705792b909c8 + sha256_in_prefix: dd79cf28afefb8038e9ca3141f2d47ca3c764cd50b880eb65263705792b909c8 + size_in_bytes: 10