From e05b99a4fc16c3a0cb9df3f2af414d21cf97bbaf Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Fri, 10 Oct 2025 20:12:38 +0200 Subject: [PATCH] make platform more flexible --- crates/rattler-bin/src/commands/create.rs | 2 +- crates/rattler/src/install/installer/mod.rs | 4 +- crates/rattler/src/install/mod.rs | 21 ++- crates/rattler/src/install/transaction.rs | 8 +- .../src/channel/channel_url.rs | 2 +- crates/rattler_conda_types/src/channel/mod.rs | 16 +- crates/rattler_conda_types/src/platform.rs | 173 +++++++++++++----- crates/rattler_index/src/lib.rs | 23 ++- crates/rattler_lock/src/lib.rs | 6 +- crates/rattler_lock/src/parse/deserialize.rs | 7 +- crates/rattler_lock/src/parse/serialize.rs | 2 +- crates/rattler_lock/src/parse/v3.rs | 4 +- crates/rattler_menuinst/src/lib.rs | 4 +- .../src/gateway/mod.rs | 2 +- .../src/gateway/remote_subdir/tokio.rs | 2 +- .../src/gateway/remote_subdir/wasm.rs | 2 +- .../src/gateway/subdir_builder.rs | 6 +- crates/rattler_shell/src/activation.rs | 8 +- crates/rattler_solve/tests/backends.rs | 2 +- crates/rattler_upload/src/upload/opt.rs | 5 +- crates/rattler_virtual_packages/src/lib.rs | 2 +- py-rattler/src/channel/mod.rs | 2 +- tools/create-resolvo-snapshot/src/main.rs | 5 +- 23 files changed, 201 insertions(+), 107 deletions(-) diff --git a/crates/rattler-bin/src/commands/create.rs b/crates/rattler-bin/src/commands/create.rs index 395833d27..433d56b56 100644 --- a/crates/rattler-bin/src/commands/create.rs +++ b/crates/rattler-bin/src/commands/create.rs @@ -194,7 +194,7 @@ pub async fn create(opt: Opt) -> miette::Result<()> { gateway .query( channels, - [install_platform, Platform::NoArch], + [install_platform.clone(), Platform::NoArch], specs.clone(), ) .recursive(true), diff --git a/crates/rattler/src/install/installer/mod.rs b/crates/rattler/src/install/installer/mod.rs index f86f2a9b3..ecd880bd9 100644 --- a/crates/rattler/src/install/installer/mod.rs +++ b/crates/rattler/src/install/installer/mod.rs @@ -386,7 +386,7 @@ impl Installer { desired_records.iter(), self.reinstall_packages.as_ref(), self.ignored_packages.as_ref(), - target_platform, + target_platform.clone(), )?; // If transaction is non-empty, we need full prefix records for file operations // Reload them and reconstruct the transaction with full records @@ -407,7 +407,7 @@ impl Installer { desired_records.iter(), self.reinstall_packages.as_ref(), self.ignored_packages.as_ref(), - target_platform, + target_platform.clone(), )?; } diff --git a/crates/rattler/src/install/mod.rs b/crates/rattler/src/install/mod.rs index c4dd6fcf6..c913197fa 100644 --- a/crates/rattler/src/install/mod.rs +++ b/crates/rattler/src/install/mod.rs @@ -396,6 +396,7 @@ pub async fn link_package( let package_dir = package_dir.to_owned(); let target_dir = target_dir.to_owned(); let target_prefix = target_prefix.clone(); + let platform_clone = platform.clone(); let install_future = async move { let _permit = driver.acquire_io_permit().await; @@ -415,7 +416,7 @@ pub async fn link_package( allow_symbolic_links && !cloned_entry.no_link, allow_hard_links && !cloned_entry.no_link, allow_ref_links && !cloned_entry.no_link, - platform, + platform_clone, options.apple_codesign_behavior, ) }) @@ -482,22 +483,24 @@ pub async fn link_package( // Create entry points for each listed item. This is different between Windows // and unix because on Windows, two PathEntry's are created whereas on // Linux only one is created. + let is_windows = platform.is_windows(); for entry_point in entry_points { let python_info = python_info.clone(); let target_dir = target_dir.to_owned(); let target_prefix = target_prefix.clone(); + let platform_clone = platform.clone(); let entry_point_fut = async move { // Acquire an IO permit let _permit = driver.acquire_io_permit().await; - let entries = if platform.is_windows() { + let entries = if platform_clone.is_windows() { match create_windows_python_entry_point( &target_dir, &target_prefix, &entry_point, &python_info, - &platform, + &platform_clone, ) { Ok([a, b]) => vec![ (number_of_paths_entries, a), @@ -521,7 +524,7 @@ pub async fn link_package( }; pending_futures.push(entry_point_fut.boxed()); - number_of_paths_entries += if platform.is_windows() { 2 } else { 1 }; + number_of_paths_entries += if is_windows { 2 } else { 1 }; } } @@ -810,6 +813,7 @@ pub fn link_package_sync( // Link the individual files in parallel let link_target_prefix = target_prefix.clone(); let package_dir = package_dir.to_path_buf(); + let platform_clone = platform.clone(); let mut paths = paths_by_directory .into_values() .collect_vec() @@ -832,7 +836,7 @@ pub fn link_package_sync( allow_symbolic_links && !entry.no_link, allow_hard_links && !entry.no_link, allow_ref_links && !entry.no_link, - platform, + platform_clone.clone(), options.apple_codesign_behavior, ); @@ -900,7 +904,8 @@ pub fn link_package_sync( // Create entry points for each listed item. This is different between Windows // and unix because on Windows, two PathEntry's are created whereas on // Linux only one is created. - let mut entry_point_paths = if platform.is_windows() { + let is_windows = platform.is_windows(); + let mut entry_point_paths = if is_windows { entry_points .into_iter() // .into_par_iter() @@ -1200,7 +1205,7 @@ mod test { assert_eq!( env.platform, - Some(current_platform), + Some(current_platform.clone()), "the platform for which the explicit lock file was created does not match the current platform" ); @@ -1224,7 +1229,7 @@ mod test { .default_environment() .expect("no default environment in lock file"); - let Some(packages) = lock_env.packages(current_platform) else { + let Some(packages) = lock_env.packages(current_platform.clone()) else { panic!( "the platform for which the explicit lock file was created does not match the current platform" ) diff --git a/crates/rattler/src/install/transaction.rs b/crates/rattler/src/install/transaction.rs index 1648dda54..046cf3a07 100644 --- a/crates/rattler/src/install/transaction.rs +++ b/crates/rattler/src/install/transaction.rs @@ -197,8 +197,8 @@ where let desired_packages = desired.into_iter().collect::>(); // Determine the python version used in the current situation. - let current_python_info = find_python_info(¤t_packages, platform)?; - let desired_python_info = find_python_info(&desired_packages, platform)?; + let current_python_info = find_python_info(¤t_packages, &platform)?; + let desired_python_info = find_python_info(&desired_packages, &platform)?; let needs_python_relink = match (¤t_python_info, &desired_python_info) { (Some(current), Some(desired)) => desired.is_relink_required(current), _ => false, @@ -393,7 +393,7 @@ impl Transaction { /// none of the packages refers to a Python installation. fn find_python_info( records: impl IntoIterator, - platform: Platform, + platform: &Platform, ) -> Result, PythonInfoError> { records .into_iter() @@ -402,7 +402,7 @@ fn find_python_info( PythonInfo::from_version( record.version(), record.python_site_packages_path(), - platform, + platform.clone(), ) }) .map_or(Ok(None), |info| info.map(Some)) diff --git a/crates/rattler_conda_types/src/channel/channel_url.rs b/crates/rattler_conda_types/src/channel/channel_url.rs index 39bf65e50..aa52f82a1 100644 --- a/crates/rattler_conda_types/src/channel/channel_url.rs +++ b/crates/rattler_conda_types/src/channel/channel_url.rs @@ -27,7 +27,7 @@ impl ChannelUrl { } /// Append the platform to the base url. - pub fn platform_url(&self, platform: Platform) -> Url { + pub fn platform_url(&self, platform: &Platform) -> Url { self.0 .join(&format!("{}/", platform.as_str())) // trailing slash is important here as this signifies a directory .expect("platform is a valid url fragment") diff --git a/crates/rattler_conda_types/src/channel/mod.rs b/crates/rattler_conda_types/src/channel/mod.rs index 9e08776a1..c9f1f9b4a 100644 --- a/crates/rattler_conda_types/src/channel/mod.rs +++ b/crates/rattler_conda_types/src/channel/mod.rs @@ -349,7 +349,7 @@ impl Channel { } /// Returns the Urls for the given platform - pub fn platform_url(&self, platform: Platform) -> Url { + pub fn platform_url(&self, platform: &Platform) -> Url { self.base_url.platform_url(platform) } @@ -357,7 +357,7 @@ impl Channel { pub fn platforms_url(&self) -> Vec<(Platform, Url)> { self.platforms_or_default() .iter() - .map(|&platform| (platform, self.platform_url(platform))) + .map(|platform| (platform.clone(), self.platform_url(platform))) .collect() } @@ -443,9 +443,11 @@ fn parse_platforms(channel: &str) -> Result<(Option>, &str), Parse /// Returns the default platforms. These are based on the platform this binary /// was build for as well as platform agnostic platforms. -pub(crate) const fn default_platforms() -> &'static [Platform] { - const CURRENT_PLATFORMS: [Platform; 2] = [Platform::current(), Platform::NoArch]; - &CURRENT_PLATFORMS +pub(crate) fn default_platforms() -> &'static [Platform] { + use std::sync::LazyLock; + static CURRENT_PLATFORMS: LazyLock<[Platform; 2]> = + LazyLock::new(|| [Platform::current(), Platform::NoArch]); + &*CURRENT_PLATFORMS } /// Returns the specified path as an absolute path @@ -653,7 +655,7 @@ mod tests { assert_eq!(channel.platforms, None); assert_eq!(channel.name(), "http://localhost:1234/"); - let noarch_url = channel.platform_url(Platform::NoArch); + let noarch_url = channel.platform_url(&Platform::NoArch); assert_eq!(noarch_url.to_string(), "http://localhost:1234/noarch/"); assert!(matches!( @@ -677,7 +679,7 @@ mod tests { "https://conda.anaconda.org/conda-forge/".parse().unwrap() ); assert_eq!(channel.name.as_deref(), Some("conda-forge")); - assert_eq!(channel.platforms, Some(vec![platform])); + assert_eq!(channel.platforms, Some(vec![platform.clone()])); let channel = Channel::from_str( format!("https://conda.anaconda.org/pkgs/main[{platform}]"), diff --git a/crates/rattler_conda_types/src/platform.rs b/crates/rattler_conda_types/src/platform.rs index cfe3f677b..8e6394299 100644 --- a/crates/rattler_conda_types/src/platform.rs +++ b/crates/rattler_conda_types/src/platform.rs @@ -14,7 +14,7 @@ use thiserror::Error; /// A platform supported by Conda. #[allow(missing_docs)] #[non_exhaustive] // The `Platform` enum is non-exhaustive to allow for future extensions without breaking changes. -#[derive(EnumIter, Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[derive(EnumIter, Debug, Clone, Eq, PartialEq, Hash)] pub enum Platform { NoArch, Unknown, @@ -45,6 +45,11 @@ pub enum Platform { WasiWasm32, ZosZ, + + /// A custom platform string not in the predefined list. + /// This allows users to define arbitrary platforms like "foobar-64". + #[strum(disabled)] + Custom(Box), } impl PartialOrd for Platform { @@ -55,7 +60,12 @@ impl PartialOrd for Platform { impl Ord for Platform { fn cmp(&self, other: &Self) -> Ordering { - self.as_str().cmp(other.as_str()) + match (self, other) { + (Platform::Custom(a), Platform::Custom(b)) => a.cmp(b), + (Platform::Custom(a), other) => a.as_ref().cmp(other.as_str()), + (this, Platform::Custom(b)) => this.as_str().cmp(b.as_ref()), + (a, b) => a.as_str().cmp(b.as_str()), + } } } @@ -197,8 +207,42 @@ impl Platform { } /// Returns a string representation of the platform. - pub fn as_str(self) -> &'static str { - self.into() + pub fn as_str(&self) -> &str { + match self { + Platform::Custom(s) => s.as_ref(), + _ => self.static_str(), + } + } + + /// Returns a static string representation of the platform. + /// Returns None for custom platforms. + const fn static_str(&self) -> &'static str { + match self { + Platform::NoArch => "noarch", + Platform::Linux32 => "linux-32", + Platform::Linux64 => "linux-64", + Platform::LinuxAarch64 => "linux-aarch64", + Platform::LinuxArmV6l => "linux-armv6l", + Platform::LinuxArmV7l => "linux-armv7l", + Platform::LinuxLoong64 => "linux-loong64", + Platform::LinuxPpc64le => "linux-ppc64le", + Platform::LinuxPpc64 => "linux-ppc64", + Platform::LinuxPpc => "linux-ppc", + Platform::LinuxS390X => "linux-s390x", + Platform::LinuxRiscv32 => "linux-riscv32", + Platform::LinuxRiscv64 => "linux-riscv64", + Platform::FreeBsd64 => "freebsd-64", + Platform::Osx64 => "osx-64", + Platform::OsxArm64 => "osx-arm64", + Platform::Win32 => "win-32", + Platform::Win64 => "win-64", + Platform::WinArm64 => "win-arm64", + Platform::EmscriptenWasm32 => "emscripten-wasm32", + Platform::WasiWasm32 => "wasi-wasm32", + Platform::ZosZ => "zos-z", + Platform::Unknown => "unknown", + Platform::Custom(_) => "custom", + } } /// Iterate over all Platform variants @@ -207,19 +251,19 @@ impl Platform { } /// Returns true if the platform is a windows based platform. - pub const fn is_windows(self) -> bool { + pub fn is_windows(&self) -> bool { matches!(self, Platform::Win32 | Platform::Win64 | Platform::WinArm64) } /// Returns true if the platform is a unix based platform. - pub const fn is_unix(self) -> bool { + pub fn is_unix(&self) -> bool { self.is_linux() || self.is_osx() || matches!(self, Platform::EmscriptenWasm32 | Platform::FreeBsd64) } /// Returns true if the platform is a linux based platform. - pub const fn is_linux(self) -> bool { + pub fn is_linux(&self) -> bool { matches!( self, Platform::Linux32 @@ -238,7 +282,7 @@ impl Platform { } /// Returns true if the platform is an macOS based platform. - pub const fn is_osx(self) -> bool { + pub fn is_osx(&self) -> bool { matches!(self, Platform::Osx64 | Platform::OsxArm64) } @@ -264,6 +308,8 @@ impl Platform { Platform::EmscriptenWasm32 => Some("emscripten"), Platform::WasiWasm32 => Some("wasi"), Platform::ZosZ => Some("zos"), + // For custom platforms, try to extract the OS part (before the hyphen) + Platform::Custom(s) => s.split('-').next(), } } } @@ -313,44 +359,12 @@ impl FromStr for Platform { "emscripten-wasm32" => Platform::EmscriptenWasm32, "wasi-wasm32" => Platform::WasiWasm32, "zos-z" => Platform::ZosZ, - string => { - return Err(ParsePlatformError { - string: string.to_owned(), - }); - } + // Accept any other string as a custom platform + string => Platform::Custom(string.into()), }) } } -impl From for &'static str { - fn from(platform: Platform) -> Self { - match platform { - Platform::NoArch => "noarch", - Platform::Linux32 => "linux-32", - Platform::Linux64 => "linux-64", - Platform::LinuxAarch64 => "linux-aarch64", - Platform::LinuxArmV6l => "linux-armv6l", - Platform::LinuxArmV7l => "linux-armv7l", - Platform::LinuxLoong64 => "linux-loong64", - Platform::LinuxPpc64le => "linux-ppc64le", - Platform::LinuxPpc64 => "linux-ppc64", - Platform::LinuxPpc => "linux-ppc", - Platform::LinuxS390X => "linux-s390x", - Platform::LinuxRiscv32 => "linux-riscv32", - Platform::LinuxRiscv64 => "linux-riscv64", - Platform::FreeBsd64 => "freebsd-64", - Platform::Osx64 => "osx-64", - Platform::OsxArm64 => "osx-arm64", - Platform::Win32 => "win-32", - Platform::Win64 => "win-64", - Platform::WinArm64 => "win-arm64", - Platform::EmscriptenWasm32 => "emscripten-wasm32", - Platform::WasiWasm32 => "wasi-wasm32", - Platform::ZosZ => "zos-z", - Platform::Unknown => "unknown", - } - } -} impl Platform { /// Return the arch string for the platform @@ -377,6 +391,10 @@ impl Platform { Platform::WinArm64 | Platform::OsxArm64 => Some(Arch::Arm64), Platform::EmscriptenWasm32 | Platform::WasiWasm32 => Some(Arch::Wasm32), Platform::ZosZ => Some(Arch::Z), + // For custom platforms, try to parse the architecture part (after the hyphen) + Platform::Custom(s) => { + s.split('-').nth(1).and_then(|arch| arch.parse::().ok()) + } } } } @@ -539,9 +557,11 @@ mod tests { } #[test] - fn test_parse_platform_error() { - let err = "foo".parse::().unwrap_err(); - println!("{err}"); + fn test_parse_platform_unknown_becomes_custom() { + // Unknown platforms are now parsed as custom platforms + let platform = "foo".parse::().unwrap(); + assert!(matches!(platform, Platform::Custom(_))); + assert_eq!(platform.as_str(), "foo"); } #[test] @@ -577,4 +597,67 @@ mod tests { assert_eq!(Platform::NoArch.arch(), None); assert_eq!(Platform::ZosZ.arch(), Some(Arch::Z)); } + + #[test] + fn test_custom_platform() { + // Parse a custom platform + let platform: Platform = "foobar-64".parse().unwrap(); + assert!(matches!(platform, Platform::Custom(_))); + assert_eq!(platform.as_str(), "foobar-64"); + assert_eq!(platform.to_string(), "foobar-64"); + + // Test with another custom platform + let platform2: Platform = "myos-arm64".parse().unwrap(); + assert!(matches!(platform2, Platform::Custom(_))); + assert_eq!(platform2.as_str(), "myos-arm64"); + + // Test only_platform extraction + assert_eq!(platform.only_platform(), Some("foobar")); + assert_eq!(platform2.only_platform(), Some("myos")); + + // Test arch extraction for custom platforms + let custom_with_known_arch: Platform = "myos-x86_64".parse().unwrap(); + assert_eq!(custom_with_known_arch.arch(), Some(Arch::X86_64)); + + let custom_with_arm64: Platform = "myos-arm64".parse().unwrap(); + assert_eq!(custom_with_arm64.arch(), Some(Arch::Arm64)); + + // Custom platform with unknown arch should return None + let custom_unknown_arch: Platform = "myos-unknownarch".parse().unwrap(); + assert_eq!(custom_unknown_arch.arch(), None); + } + + #[test] + fn test_custom_platform_helpers() { + let platform: Platform = "foobar-64".parse().unwrap(); + + // Custom platforms should return false for all helper methods + assert!(!platform.is_windows()); + assert!(!platform.is_unix()); + assert!(!platform.is_linux()); + assert!(!platform.is_osx()); + } + + #[test] + fn test_custom_platform_serde() { + // Test serialization + let platform: Platform = "foobar-64".parse().unwrap(); + let serialized = serde_json::to_string(&platform).unwrap(); + assert_eq!(serialized, "\"foobar-64\""); + + // Test deserialization + let deserialized: Platform = serde_json::from_str("\"foobar-64\"").unwrap(); + assert_eq!(deserialized, platform); + assert_eq!(deserialized.as_str(), "foobar-64"); + } + + #[test] + fn test_custom_platform_ordering() { + let platform1: Platform = "aaa-64".parse().unwrap(); + let platform2: Platform = "bbb-64".parse().unwrap(); + let platform3: Platform = Platform::Linux64; + + assert!(platform1 < platform2); + assert!(platform1 < platform3); + } } diff --git a/crates/rattler_index/src/lib.rs b/crates/rattler_index/src/lib.rs index 9081a55d0..bd7f9ca49 100644 --- a/crates/rattler_index/src/lib.rs +++ b/crates/rattler_index/src/lib.rs @@ -417,7 +417,7 @@ async fn index_subdir( let request_start_time = SystemTime::now(); match index_subdir_inner( - subdir, + subdir.clone(), op.clone(), force, write_zst, @@ -484,7 +484,7 @@ async fn index_subdir_inner( // Step 1: Collect ETags/metadata for all critical files upfront let metadata = RepodataMetadataCollection::new( &op, - subdir, + subdir.clone(), repodata_patch.is_some(), write_zst, write_shards, @@ -596,6 +596,7 @@ async fn index_subdir_inner( let pb = pb.clone(); let semaphore = semaphore.clone(); let cache = cache.clone(); + let subdir_clone = subdir.clone(); async move { let _permit = semaphore .acquire() @@ -603,11 +604,11 @@ async fn index_subdir_inner( .expect("Semaphore was unexpectedly closed"); pb.set_message(format!( "Indexing {} {}", - subdir.as_str(), + subdir_clone.as_str(), console::style(&filename).dim() )); - let record = read_and_parse_package(&op, &cache, subdir, &filename).await?; + let record = read_and_parse_package(&op, &cache, subdir_clone, &filename).await?; pb.inc(1); Ok::<(String, PackageRecord), std::io::Error>((filename, record)) @@ -686,7 +687,7 @@ async fn index_subdir_inner( write_repodata( repodata_before_patches, repodata_patch, - subdir, + subdir.clone(), op, &metadata, ) @@ -772,6 +773,7 @@ pub async fn write_repodata( if metadata.repodata_shards.is_some() { // See CEP 16 tracing::info!("Creating sharded repodata"); + let subdir_str = subdir.as_str(); let mut shards_by_package_names: HashMap = HashMap::new(); for (k, package_record) in repodata.conda_packages { let package_name = package_record.name.as_normalized(); @@ -810,7 +812,7 @@ pub async fn write_repodata( let sharded_repodata = ShardedRepodata { info: ShardedSubdirInfo { - subdir: subdir.to_string(), + subdir: subdir_str.to_string(), base_url: "".into(), shards_base_url: "./shards/".into(), created_at: Some(chrono::Utc::now()), @@ -825,8 +827,9 @@ pub async fn write_repodata( // todo max parallel for (_, (digest, encoded_shard)) in shards { let op = op.clone(); + let subdir_owned = subdir_str.to_string(); let future = async move || { - let shard_path = format!("{subdir}/shards/{digest:x}.msgpack.zst"); + let shard_path = format!("{subdir_owned}/shards/{digest:x}.msgpack.zst"); tracing::trace!("Writing repodata shard to {shard_path}"); match op .write_with(&shard_path, encoded_shard) @@ -854,7 +857,7 @@ pub async fn write_repodata( // Write sharded repodata index with conditional check if let Some(repodata_shards_metadata) = &metadata.repodata_shards { - let repodata_shards_path = format!("{subdir}/{REPODATA_SHARDS}"); + let repodata_shards_path = format!("{}/{}", subdir_str, REPODATA_SHARDS); tracing::trace!("Writing repodata shards to {repodata_shards_path}"); let sharded_repodata_encoded = serialize_msgpack_zst(&sharded_repodata)?; crate::utils::write_with_metadata_check( @@ -1083,7 +1086,7 @@ pub async fn index( let cache = cache::PackageRecordCache::new(); let task = index_subdir( - *subdir, + subdir.clone(), op.clone(), force, write_zst, @@ -1096,7 +1099,7 @@ pub async fn index( cache, ) .instrument(tracing::info_span!("index_subdir", subdir = %subdir)); - tasks.push((*subdir, task)); + tasks.push((subdir.clone(), task)); } let mut stats = IndexStats { diff --git a/crates/rattler_lock/src/lib.rs b/crates/rattler_lock/src/lib.rs index 8b485aeb5..6e5e793e0 100644 --- a/crates/rattler_lock/src/lib.rs +++ b/crates/rattler_lock/src/lib.rs @@ -264,7 +264,7 @@ impl<'lock> Environment<'lock> { /// Returns all the platforms for which we have a locked-down environment. pub fn platforms(&self) -> impl ExactSizeIterator + '_ { - self.data().packages.keys().copied() + self.data().packages.keys().cloned() } /// Returns the channels that are used by this environment. @@ -325,7 +325,7 @@ impl<'lock> Environment<'lock> { let env_data = self.data(); env_data.packages.iter().map(move |(platform, packages)| { ( - *platform, + platform.clone(), packages.iter().map(move |package| match package { EnvironmentPackageData::Conda(data) => { LockedPackageRef::Conda(&self.lock_file.inner.conda_packages[*data]) @@ -357,7 +357,7 @@ impl<'lock> Environment<'lock> { &self.lock_file.inner.pypi_environment_package_data[*env_data_idx], )), }); - (*platform, records) + (platform.clone(), records) }) } diff --git a/crates/rattler_lock/src/parse/deserialize.rs b/crates/rattler_lock/src/parse/deserialize.rs index 200d1e286..30493138e 100644 --- a/crates/rattler_lock/src/parse/deserialize.rs +++ b/crates/rattler_lock/src/parse/deserialize.rs @@ -205,6 +205,7 @@ fn parse_from_lock

( .packages .into_iter() .map(|(platform, packages)| { + let platform_clone = platform.clone(); let packages = packages .into_iter() .map(|p| { @@ -235,7 +236,7 @@ fn parse_from_lock

( .filter(|&idx| { let conda_package = &conda_packages[*idx]; conda_package.record().subdir.as_str() - == platform.as_str() + == platform_clone.as_str() }) .peekable(); @@ -306,7 +307,7 @@ fn parse_from_lock

( package_index.ok_or_else(|| { ParseCondaLockError::MissingPackage( environment_name.clone(), - platform, + platform_clone.clone(), conda, ) })?, @@ -317,7 +318,7 @@ fn parse_from_lock

( *pypi_url_lookup.get(&pypi).ok_or_else(|| { ParseCondaLockError::MissingPackage( environment_name.clone(), - platform, + platform_clone.clone(), pypi, ) })?, diff --git a/crates/rattler_lock/src/parse/serialize.rs b/crates/rattler_lock/src/parse/serialize.rs index 96287f1a1..39637126d 100644 --- a/crates/rattler_lock/src/parse/serialize.rs +++ b/crates/rattler_lock/src/parse/serialize.rs @@ -56,7 +56,7 @@ impl<'a> SerializableEnvironment<'a> { .iter() .map(|(platform, packages)| { ( - *platform, + platform.clone(), packages .iter() .map(|&package_data| { diff --git a/crates/rattler_lock/src/parse/v3.rs b/crates/rattler_lock/src/parse/v3.rs index f451e74a3..8863ffbfe 100644 --- a/crates/rattler_lock/src/parse/v3.rs +++ b/crates/rattler_lock/src/parse/v3.rs @@ -167,7 +167,7 @@ pub fn parse_v3_or_lower( .and_then(|split| split.rev().nth(1)) }) .and_then(|subdir_str| Platform::from_str(subdir_str).ok()) - .unwrap_or(platform); + .unwrap_or(platform.clone()); let location = UrlOrPath::Url(value.url).normalize().into_owned(); let derived = LocationDerivedFields::new(&location); @@ -248,7 +248,7 @@ pub fn parse_v3_or_lower( }; per_platform - .entry(package.platform) + .entry(platform) .or_default() .insert(pkg); } diff --git a/crates/rattler_menuinst/src/lib.rs b/crates/rattler_menuinst/src/lib.rs index 5d770d3f5..f400eb223 100644 --- a/crates/rattler_menuinst/src/lib.rs +++ b/crates/rattler_menuinst/src/lib.rs @@ -93,7 +93,7 @@ pub fn install_menuitems_for_record( &full_path, target_prefix, target_prefix, - platform, + platform.clone(), menu_mode, )?; @@ -121,7 +121,7 @@ pub fn install_menuitems( ) -> Result, MenuInstError> { let text = std::fs::read_to_string(file)?; let menu_inst: MenuInstSchema = serde_json::from_str(&text)?; - let placeholders = BaseMenuItemPlaceholders::new(base_prefix, prefix, platform); + let placeholders = BaseMenuItemPlaceholders::new(base_prefix, prefix, platform.clone()); let mut trackers = Vec::new(); for item in menu_inst.menu_items { diff --git a/crates/rattler_repodata_gateway/src/gateway/mod.rs b/crates/rattler_repodata_gateway/src/gateway/mod.rs index 6f8d007bc..524fcfb5d 100644 --- a/crates/rattler_repodata_gateway/src/gateway/mod.rs +++ b/crates/rattler_repodata_gateway/src/gateway/mod.rs @@ -230,7 +230,7 @@ impl GatewayInner { platform: Platform, reporter: Option>, ) -> Result, GatewayError> { - let key = (channel.clone(), platform); + let key = (channel.clone(), platform.clone()); let channel = channel.clone(); self.subdirs diff --git a/crates/rattler_repodata_gateway/src/gateway/remote_subdir/tokio.rs b/crates/rattler_repodata_gateway/src/gateway/remote_subdir/tokio.rs index 8c4e18c6c..f4be89fb2 100644 --- a/crates/rattler_repodata_gateway/src/gateway/remote_subdir/tokio.rs +++ b/crates/rattler_repodata_gateway/src/gateway/remote_subdir/tokio.rs @@ -23,7 +23,7 @@ impl RemoteSubdirClient { source_config: SourceConfig, reporter: Option>, ) -> Result { - let subdir_url = channel.platform_url(platform); + let subdir_url = channel.platform_url(&platform); // Fetch the repodata from the remote server let repodata = fetch_repo_data( diff --git a/crates/rattler_repodata_gateway/src/gateway/remote_subdir/wasm.rs b/crates/rattler_repodata_gateway/src/gateway/remote_subdir/wasm.rs index 2c1a78ef3..dfa7d1b5f 100644 --- a/crates/rattler_repodata_gateway/src/gateway/remote_subdir/wasm.rs +++ b/crates/rattler_repodata_gateway/src/gateway/remote_subdir/wasm.rs @@ -26,7 +26,7 @@ impl RemoteSubdirClient { source_config: SourceConfig, reporter: Option>, ) -> Result { - let subdir_url = channel.platform_url(platform); + let subdir_url = channel.platform_url(&platform); // Fetch the repodata from the remote server let repodata_bytes = fetch_repo_data( diff --git a/crates/rattler_repodata_gateway/src/gateway/subdir_builder.rs b/crates/rattler_repodata_gateway/src/gateway/subdir_builder.rs index 016c73c64..e7a7a50e1 100644 --- a/crates/rattler_repodata_gateway/src/gateway/subdir_builder.rs +++ b/crates/rattler_repodata_gateway/src/gateway/subdir_builder.rs @@ -40,7 +40,7 @@ impl<'g> SubdirBuilder<'g> { } pub async fn build(self) -> Result { - let url = self.channel.platform_url(self.platform); + let url = self.channel.platform_url(&self.platform); let subdir_data = if url.scheme() == "file" { if let Some(path) = url_to_path(&url) { @@ -119,7 +119,7 @@ impl<'g> SubdirBuilder<'g> { ) -> Result { let client = remote_subdir::RemoteSubdirClient::new( self.channel.clone(), - self.platform, + self.platform.clone(), self.gateway.client.clone(), #[cfg(not(target_arch = "wasm32"))] self.gateway.cache.clone(), @@ -152,7 +152,7 @@ impl<'g> SubdirBuilder<'g> { async fn build_local(&self, path: &Path) -> Result { let channel = self.channel.clone(); - let platform = self.platform; + let platform = self.platform.clone(); let path = path.join("repodata.json"); let build_client = move || LocalSubdirClient::from_file(&path, channel.clone(), platform.as_str()); diff --git a/crates/rattler_shell/src/activation.rs b/crates/rattler_shell/src/activation.rs index 5bc004464..2b23b3397 100644 --- a/crates/rattler_shell/src/activation.rs +++ b/crates/rattler_shell/src/activation.rs @@ -463,14 +463,14 @@ impl Activator { &self, variables: ActivationVariables, ) -> Result, ActivationError> { - let mut script = ShellScript::new(self.shell_type.clone(), self.platform); + let mut script = ShellScript::new(self.shell_type.clone(), self.platform.clone()); let mut path = variables.path.clone().unwrap_or_default(); if let Some(conda_prefix) = variables.conda_prefix { let deactivate = Activator::from_path( Path::new(&conda_prefix), self.shell_type.clone(), - self.platform, + self.platform.clone(), )?; for (key, _) in &deactivate.env_vars { @@ -537,7 +537,7 @@ impl Activator { &self, variables: ActivationVariables, ) -> Result, ActivationError> { - let mut script = ShellScript::new(self.shell_type.clone(), self.platform); + let mut script = ShellScript::new(self.shell_type.clone(), self.platform.clone()); // Get the current CONDA shell level from passed environment variables let current_conda_shlvl = variables @@ -625,7 +625,7 @@ impl Activator { // the activation script followed by again emitting all environment // variables. Any changes should then become visible. let mut activation_detection_script = - ShellScript::new(self.shell_type.clone(), self.platform); + ShellScript::new(self.shell_type.clone(), self.platform.clone()); activation_detection_script .print_env()? .echo(ENV_START_SEPARATOR)? diff --git a/crates/rattler_solve/tests/backends.rs b/crates/rattler_solve/tests/backends.rs index 0c526dd6b..d7c081a92 100644 --- a/crates/rattler_solve/tests/backends.rs +++ b/crates/rattler_solve/tests/backends.rs @@ -646,7 +646,7 @@ mod libsolv_c { &ChannelConfig::default_with_root_dir(std::env::current_dir().unwrap()), ) .unwrap() - .platform_url(rattler_conda_types::Platform::Linux64) + .platform_url(&rattler_conda_types::Platform::Linux64) .to_string(), &repo_data, None, diff --git a/crates/rattler_upload/src/upload/opt.rs b/crates/rattler_upload/src/upload/opt.rs index e170a579b..099dd58ce 100644 --- a/crates/rattler_upload/src/upload/opt.rs +++ b/crates/rattler_upload/src/upload/opt.rs @@ -638,14 +638,15 @@ impl DebugData { /// Generate a new `TestData` struct from `TestOpts` and an optional pixi /// config. `TestOpts` have higher priority than the pixi config. pub fn from_opts_and_config(opts: DebugOpts, config: Option) -> Self { + let target_platform = opts.target_platform.unwrap_or(Platform::current()); Self { recipe_path: opts.recipe, output_dir: opts.output.unwrap_or_else(|| PathBuf::from("./output")), build_platform: opts.build_platform.unwrap_or(Platform::current()), - target_platform: opts.target_platform.unwrap_or(Platform::current()), + target_platform: target_platform.clone(), host_platform: opts .host_platform - .unwrap_or_else(|| opts.target_platform.unwrap_or(Platform::current())), + .unwrap_or_else(|| target_platform), channels: opts.channels, common: CommonData::from_opts_and_config(opts.common, config.unwrap_or_default()), output_name: opts.output_name, diff --git a/crates/rattler_virtual_packages/src/lib.rs b/crates/rattler_virtual_packages/src/lib.rs index 875e79cdd..e0a7a2405 100644 --- a/crates/rattler_virtual_packages/src/lib.rs +++ b/crates/rattler_virtual_packages/src/lib.rs @@ -312,7 +312,7 @@ impl VirtualPackages { .archspec .as_ref() .unwrap_or(&Override::DefaultEnvVar), - || Ok(Archspec::from_platform(platform)), + || Ok(Archspec::from_platform(platform.clone())), )?; Ok(Self { diff --git a/py-rattler/src/channel/mod.rs b/py-rattler/src/channel/mod.rs index 2a6b1ecf4..0d74d3655 100644 --- a/py-rattler/src/channel/mod.rs +++ b/py-rattler/src/channel/mod.rs @@ -79,7 +79,7 @@ impl PyChannel { /// Returns the Urls for the given platform. pub fn platform_url(&self, platform: &PyPlatform) -> String { - self.inner.platform_url((*platform).into()).into() + self.inner.platform_url(&(*platform).into()).into() } } diff --git a/tools/create-resolvo-snapshot/src/main.rs b/tools/create-resolvo-snapshot/src/main.rs index 763519feb..1cb2886df 100644 --- a/tools/create-resolvo-snapshot/src/main.rs +++ b/tools/create-resolvo-snapshot/src/main.rs @@ -42,7 +42,7 @@ async fn main() { let client = LazyClient::default(); let mut records = Vec::new(); - for &subdir in &subdirs { + for subdir in &subdirs { eprintln!("fetching repodata for {subdir:?}.."); let repodata = rattler_repodata_gateway::fetch::fetch_repo_data( channel.platform_url(subdir), @@ -92,8 +92,7 @@ async fn main() { channel.name(), subdirs .iter() - .copied() - .map(Platform::as_str) + .map(|p| p.as_str()) .sorted() .join("-") )