diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 03e248fcd..3bd9242a9 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -189,6 +189,33 @@ pixi update --dry-run pixi update --no-install boto3 ``` +## `upgrade` + +The `upgrade` command checks if there are newer versions of the dependencies and upgrades them in the [manifest file](project_configuration.md). +`update` updates dependencies in the lock file while still fulfilling the version requirements set in the manifest. +`upgrade` loosens the requirements for the given packages, updates the lock file and the adapts the manifest accordingly. + +##### Arguments + +1. `[PACKAGES]...` The packages to upgrade, space separated. If no packages are provided, all packages will be upgraded. + +##### Options +- `--manifest-path `: the path to [manifest file](project_configuration.md), by default it searches for one in the parent directories. +- `--feature (-e)`: The feature to upgrade, if none are provided all features are upgraded. +- `--no-install`: Don't install the (solve) environment needed for solving pypi-dependencies. +- `--json`: Output the changes in json format. +- `--dry-run (-n)`: Only show the changes that would be made, without actually updating the manifest, lock file, or environment. + +```shell +pixi upgrade +pixi upgrade numpy +pixi upgrade numpy pandas +pixi upgrade --manifest-path ~/myproject/pixi.toml numpy +pixi upgrade --feature lint python +pixi upgrade --json +pixi upgrade --dry-run +``` + ## `run` The `run` commands first checks if the environment is ready to use. diff --git a/src/cli/add.rs b/src/cli/add.rs index 35b4d53bd..0c79a6f8b 100644 --- a/src/cli/add.rs +++ b/src/cli/add.rs @@ -1,38 +1,14 @@ -use std::{ - collections::{HashMap, HashSet}, - str::FromStr, -}; - use clap::Parser; use indexmap::IndexMap; -use itertools::Itertools; -use pep440_rs::VersionSpecifiers; -use pep508_rs::{Requirement, VersionOrUrl::VersionSpecifier}; -use pixi_config::PinningStrategy; -use pixi_manifest::{ - pypi::PyPiPackageName, DependencyOverwriteBehavior, FeatureName, FeaturesExt, HasFeaturesIter, - SpecType, -}; -use rattler_conda_types::{MatchSpec, Platform, Version}; -use rattler_lock::{LockFile, Package}; +use pixi_manifest::FeatureName; use super::has_specs::HasSpecs; -use crate::environment::LockFileUsage; use crate::{ cli::cli_config::{DependencyConfig, PrefixUpdateConfig, ProjectConfig}, environment::verify_prefix_location_unchanged, - load_lock_file, - lock_file::{filter_lock_file, LockFileDerivedData, UpdateContext, UpdateMode}, - project::{grouped_environment::GroupedEnvironment, DependencyType, Project}, + project::{DependencyType, Project}, }; -/// List of packages that are not following the semver versioning scheme -/// but will use the minor version by default when adding a dependency. -// Don't forget to add to the docstring if you add a package here! -const NON_SEMVER_PACKAGES: [&str; 11] = [ - "python", "rust", "julia", "gcc", "gxx", "gfortran", "nodejs", "deno", "r", "r-base", "perl", -]; - /// Adds dependencies to the project /// /// The dependencies should be defined as MatchSpec for conda package, or a PyPI @@ -101,9 +77,9 @@ pub struct Args { pub async fn execute(args: Args) -> miette::Result<()> { let (dependency_config, prefix_update_config, project_config) = ( - args.dependency_config, - args.prefix_update_config, - args.project_config, + &args.dependency_config, + &args.prefix_update_config, + &args.project_config, ); let mut project = Project::load_or_else_discover(project_config.manifest_path.as_deref())? @@ -115,349 +91,44 @@ pub async fn execute(args: Args) -> miette::Result<()> { // Add the platform if it is not already present project .manifest - .add_platforms(dependency_config.platform.iter(), &FeatureName::Default)?; + .add_platforms(dependency_config.platforms.iter(), &FeatureName::Default)?; - // Add the individual specs to the project. - let mut conda_specs_to_add_constraints_for = IndexMap::new(); - let mut pypi_specs_to_add_constraints_for = IndexMap::new(); - let mut conda_packages = HashSet::new(); - let mut pypi_packages = HashSet::new(); - match dependency_config.dependency_type() { + let (match_specs, pypi_deps) = match dependency_config.dependency_type() { DependencyType::CondaDependency(spec_type) => { - let specs = dependency_config.specs()?; - let channel_config = project.channel_config(); - for (name, spec) in specs { - let added = project.manifest.add_dependency( - &spec, - spec_type, - &dependency_config.platform, - &dependency_config.feature_name(), - DependencyOverwriteBehavior::Overwrite, - &channel_config, - )?; - if added { - if spec.version.is_none() { - conda_specs_to_add_constraints_for.insert(name.clone(), (spec_type, spec)); - } - conda_packages.insert(name); - } - } + let match_specs = dependency_config + .specs()? + .into_iter() + .map(|(name, spec)| (name, (spec, spec_type))) + .collect(); + let pypi_deps = IndexMap::default(); + (match_specs, pypi_deps) } DependencyType::PypiDependency => { - let specs = dependency_config.pypi_deps(&project)?; - for (name, spec) in specs { - let added = project.manifest.add_pep508_dependency( - &spec, - &dependency_config.platform, - &dependency_config.feature_name(), - Some(args.editable), - DependencyOverwriteBehavior::Overwrite, - )?; - if added { - if spec.version_or_url.is_none() { - pypi_specs_to_add_constraints_for.insert(name.clone(), spec); - } - pypi_packages.insert(name.as_normalized().clone()); - } - } + let match_specs = IndexMap::default(); + let pypi_deps = dependency_config.pypi_deps(&project)?; + (match_specs, pypi_deps) } - } - - // If the lock-file should not be updated we only need to save the project. - if prefix_update_config.lock_file_usage() != LockFileUsage::Update { - project.save()?; - - // Notify the user we succeeded. - dependency_config.display_success("Added", HashMap::default()); - - Project::warn_on_discovered_from_env(project_config.manifest_path.as_deref()); - return Ok(()); - } - - // Load the current lock-file - let lock_file = load_lock_file(&project).await?; - - // Determine the environments that are affected by the change. - let feature_name = dependency_config.feature_name(); - let affected_environments = project - .environments() - .iter() - // Filter out any environment that does not contain the feature we modified - .filter(|e| e.features().any(|f| f.name == feature_name)) - // Expand the selection to also included any environment that shares the same solve - // group - .flat_map(|e| { - GroupedEnvironment::from(e.clone()) - .environments() - .collect_vec() - }) - .unique() - .collect_vec(); - let default_environment_is_affected = - affected_environments.contains(&project.default_environment()); - - tracing::debug!( - "environments affected by the add command: {}", - affected_environments.iter().map(|e| e.name()).format(", ") - ); - - // Determine the combination of platforms and environments that are affected by - // the command - let affect_environment_and_platforms = affected_environments - .into_iter() - // Create an iterator over all environment and platform combinations - .flat_map(|e| e.platforms().into_iter().map(move |p| (e.clone(), p))) - // Filter out any platform that is not affected by the changes. - .filter(|(_, platform)| { - dependency_config.platform.is_empty() || dependency_config.platform.contains(platform) - }) - .map(|(e, p)| (e.name().to_string(), p)) - .collect_vec(); - - // Create an updated lock-file where the dependencies to be added are removed - // from the lock-file. - let unlocked_lock_file = unlock_packages( - &project, - &lock_file, - conda_packages, - pypi_packages, - affect_environment_and_platforms - .iter() - .map(|(e, p)| (e.as_str(), *p)) - .collect(), - ); - - // Solve the updated project. - let LockFileDerivedData { - project: _, // We don't need the project here - lock_file, - package_cache, - uv_context, - updated_conda_prefixes, - updated_pypi_prefixes, - io_concurrency_limit, - } = UpdateContext::builder(&project) - .with_lock_file(unlocked_lock_file) - .with_no_install(prefix_update_config.no_install()) - .finish()? - .update() - .await?; - - // Update the constraints of specs that didn't have a version constraint based - // on the contents of the lock-file. - let implicit_constraints = if !conda_specs_to_add_constraints_for.is_empty() { - update_conda_specs_from_lock_file( - &mut project, - &lock_file, - conda_specs_to_add_constraints_for, - affect_environment_and_platforms, - &feature_name, - &dependency_config.platform, - )? - } else if !pypi_specs_to_add_constraints_for.is_empty() { - update_pypi_specs_from_lock_file( - &mut project, - &lock_file, - pypi_specs_to_add_constraints_for, - affect_environment_and_platforms, - &feature_name, - &dependency_config.platform, - args.editable, - )? - } else { - HashMap::new() - }; - - // Write the lock-file and the project to disk - project.save()?; - - // Reconstruct the lock-file derived data. - let mut updated_lock_file = LockFileDerivedData { - project: &project, - lock_file, - package_cache, - updated_conda_prefixes, - updated_pypi_prefixes, - uv_context, - io_concurrency_limit, }; - if !prefix_update_config.no_lockfile_update { - updated_lock_file.write_to_disk()?; - } + // TODO: add dry_run logic to add + let dry_run = false; + + let update_deps = project + .update_dependencies( + match_specs, + pypi_deps, + prefix_update_config, + &args.dependency_config.feature, + &args.dependency_config.platforms, + args.editable, + dry_run, + ) + .await?; - // Install/update the default environment if: - // - we are not skipping the installation, - // - there is only the default environment, - // - and the default environment is affected by the changes, - if !prefix_update_config.no_install() - && project.environments().len() == 1 - && default_environment_is_affected - { - updated_lock_file - .prefix(&project.default_environment(), UpdateMode::Revalidate) - .await?; + if let Some(update_deps) = update_deps { + // Notify the user we succeeded + dependency_config.display_success("Added", update_deps.implicit_constraints); } - // Notify the user we succeeded. - dependency_config.display_success("Added", implicit_constraints); - Project::warn_on_discovered_from_env(project_config.manifest_path.as_deref()); Ok(()) } - -/// Update the pypi specs of newly added packages based on the contents of the -/// updated lock-file. -fn update_pypi_specs_from_lock_file( - project: &mut Project, - updated_lock_file: &LockFile, - pypi_specs_to_add_constraints_for: IndexMap, - affect_environment_and_platforms: Vec<(String, Platform)>, - feature_name: &FeatureName, - platforms: &[Platform], - editable: bool, -) -> miette::Result> { - let mut implicit_constraints = HashMap::new(); - - let pypi_records = affect_environment_and_platforms - .into_iter() - // Get all the conda and pypi records for the combination of environments and - // platforms - .filter_map(|(env, platform)| { - let locked_env = updated_lock_file.environment(&env)?; - locked_env.pypi_packages_for_platform(platform) - }) - .flatten() - .collect_vec(); - - let pinning_strategy = project.config().pinning_strategy.unwrap_or_default(); - - // Determine the versions of the packages in the lock-file - for (name, req) in pypi_specs_to_add_constraints_for { - let version_constraint = pinning_strategy.determine_version_constraint( - pypi_records - .iter() - .filter_map(|(data, _)| { - if &data.name == name.as_normalized() { - Version::from_str(&data.version.to_string()).ok() - } else { - None - } - }) - .collect_vec() - .iter(), - ); - - let version_spec = - version_constraint.and_then(|spec| VersionSpecifiers::from_str(&spec.to_string()).ok()); - if let Some(version_spec) = version_spec { - implicit_constraints.insert(name.as_source().to_string(), version_spec.to_string()); - let req = Requirement { - version_or_url: Some(VersionSpecifier(version_spec)), - ..req - }; - project.manifest.add_pep508_dependency( - &req, - platforms, - feature_name, - Some(editable), - DependencyOverwriteBehavior::Overwrite, - )?; - } - } - - Ok(implicit_constraints) -} - -/// Update the conda specs of newly added packages based on the contents of the -/// updated lock-file. -fn update_conda_specs_from_lock_file( - project: &mut Project, - updated_lock_file: &LockFile, - conda_specs_to_add_constraints_for: IndexMap< - rattler_conda_types::PackageName, - (SpecType, MatchSpec), - >, - affect_environment_and_platforms: Vec<(String, Platform)>, - feature_name: &FeatureName, - platforms: &[Platform], -) -> miette::Result> { - let mut implicit_constraints = HashMap::new(); - - // Determine the conda records that were affected by the add. - let conda_records = affect_environment_and_platforms - .into_iter() - // Get all the conda and pypi records for the combination of environments and - // platforms - .filter_map(|(env, platform)| { - let locked_env = updated_lock_file.environment(&env)?; - locked_env - .conda_repodata_records_for_platform(platform) - .ok()? - }) - .flatten() - .collect_vec(); - - let mut pinning_strategy = project.config().pinning_strategy; - let channel_config = project.channel_config(); - for (name, (spec_type, spec)) in conda_specs_to_add_constraints_for { - // Edge case: some packages are a special case where we want to pin the minor version by default. - // This is done to avoid early user confusion when the minor version changes and environments magically start breaking. - // This move a `>=3.13, <4` to a `>=3.13, <3.14` constraint. - if NON_SEMVER_PACKAGES.contains(&name.as_normalized()) && pinning_strategy.is_none() { - tracing::info!( - "Pinning {} to minor version by default", - name.as_normalized() - ); - pinning_strategy = Some(PinningStrategy::Minor); - } - - let version_constraint = pinning_strategy - .unwrap_or_default() - .determine_version_constraint(conda_records.iter().filter_map(|record| { - if record.package_record.name == name { - Some(record.package_record.version.version()) - } else { - None - } - })); - - if let Some(version_constraint) = version_constraint { - implicit_constraints - .insert(name.as_source().to_string(), version_constraint.to_string()); - let spec = MatchSpec { - version: Some(version_constraint), - ..spec - }; - project.manifest.add_dependency( - &spec, - spec_type, - platforms, - feature_name, - DependencyOverwriteBehavior::Overwrite, - &channel_config, - )?; - } - } - - Ok(implicit_constraints) -} - -/// Constructs a new lock-file where some of the constraints have been removed. -fn unlock_packages( - project: &Project, - lock_file: &LockFile, - conda_packages: HashSet, - pypi_packages: HashSet, - affected_environments: HashSet<(&str, Platform)>, -) -> LockFile { - filter_lock_file(project, lock_file, |env, platform, package| { - if affected_environments.contains(&(env.name().as_str(), platform)) { - match package { - Package::Conda(package) => !conda_packages.contains(&package.package_record().name), - Package::Pypi(package) => !pypi_packages.contains(&package.data().package.name), - } - } else { - true - } - }) -} diff --git a/src/cli/cli_config.rs b/src/cli/cli_config.rs index 9fe27b09e..9fcd00eb4 100644 --- a/src/cli/cli_config.rs +++ b/src/cli/cli_config.rs @@ -151,12 +151,12 @@ pub struct DependencyConfig { pub pypi: bool, /// The platform(s) for which the dependency should be modified - #[arg(long, short)] - pub platform: Vec, + #[arg(long = "platform", short)] + pub platforms: Vec, /// The feature for which the dependency should be modified - #[arg(long, short)] - pub feature: Option, + #[clap(long, short, default_value_t)] + pub feature: FeatureName, } impl DependencyConfig { @@ -171,11 +171,7 @@ impl DependencyConfig { DependencyType::CondaDependency(SpecType::Run) } } - pub(crate) fn feature_name(&self) -> FeatureName { - self.feature - .clone() - .map_or(FeatureName::Default, FeatureName::Named) - } + pub(crate) fn display_success( &self, operation: &str, @@ -207,14 +203,14 @@ impl DependencyConfig { } // Print something if we've modified for platforms - if !self.platform.is_empty() { + if !self.platforms.is_empty() { eprintln!( "{operation} these only for platform(s): {}", - console::style(self.platform.iter().join(", ")).bold() + console::style(self.platforms.iter().join(", ")).bold() ) } // Print something if we've modified for features - if let Some(feature) = &self.feature { + if let FeatureName::Named(feature) = &self.feature { { eprintln!( "{operation} these only for feature: {}", diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 7c749dc2a..d526639eb 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -35,6 +35,7 @@ pub mod shell_hook; pub mod task; pub mod tree; pub mod update; +pub mod upgrade; pub mod upload; #[derive(Parser, Debug)] @@ -106,6 +107,7 @@ pub enum Command { #[clap(visible_alias = "i")] Install(install::Args), Update(update::Args), + Upgrade(upgrade::Args), #[clap(visible_alias = "r")] Run(run::Args), @@ -290,6 +292,7 @@ pub async fn execute_command(command: Command) -> miette::Result<()> { Command::List(cmd) => list::execute(cmd).await, Command::Tree(cmd) => tree::execute(cmd).await, Command::Update(cmd) => update::execute(cmd).await, + Command::Upgrade(cmd) => upgrade::execute(cmd).await, Command::Exec(args) => exec::execute(args).await, } } diff --git a/src/cli/remove.rs b/src/cli/remove.rs index 8bea71e24..7dde9f224 100644 --- a/src/cli/remove.rs +++ b/src/cli/remove.rs @@ -47,8 +47,8 @@ pub async fn execute(args: Args) -> miette::Result<()> { .manifest .remove_pypi_dependency( name, - &dependency_config.platform, - &dependency_config.feature_name(), + &dependency_config.platforms, + &dependency_config.feature, ) .wrap_err(format!( "failed to remove PyPI dependency: '{}'", @@ -63,8 +63,8 @@ pub async fn execute(args: Args) -> miette::Result<()> { .remove_dependency( name, spec_type, - &dependency_config.platform, - &dependency_config.feature_name(), + &dependency_config.platforms, + &dependency_config.feature, ) .wrap_err(format!( "failed to remove dependency: '{}'", diff --git a/src/cli/update.rs b/src/cli/update.rs index 15876f1fe..e10ecaf3a 100644 --- a/src/cli/update.rs +++ b/src/cli/update.rs @@ -1,32 +1,24 @@ -use std::{ - borrow::Cow, - cmp::Ordering, - collections::HashSet, - io::{stdout, Write}, -}; +use std::{cmp::Ordering, collections::HashSet}; use fancy_display::FancyDisplay; -use crate::cli::cli_config::ProjectConfig; +use crate::{ + cli::cli_config::ProjectConfig, + diff::{LockFileDiff, LockFileJsonDiff}, +}; use crate::{ load_lock_file, lock_file::{filter_lock_file, UpdateContext}, Project, }; -use ahash::HashMap; use clap::Parser; -use indexmap::IndexMap; -use itertools::{Either, Itertools}; +use itertools::Itertools; use miette::{Context, IntoDiagnostic, MietteDiagnostic}; use pixi_config::ConfigCli; use pixi_consts::consts; use pixi_manifest::EnvironmentName; -use pixi_manifest::FeaturesExt; use rattler_conda_types::Platform; use rattler_lock::{LockFile, Package}; -use serde::Serialize; -use serde_json::Value; -use tabwriter::TabWriter; /// Update dependencies as recorded in the local lock file #[derive(Parser, Debug, Default)] @@ -186,7 +178,7 @@ pub async fn execute(args: Args) -> miette::Result<()> { let json = serde_json::to_string_pretty(&json_diff).expect("failed to convert to json"); println!("{}", json); } else if diff.is_empty() { - println!( + eprintln!( "{}Lock-file was already up-to-date", console::style(console::Emoji("✔ ", "")).green() ); @@ -279,495 +271,3 @@ fn unlock_packages(project: &Project, lock_file: &LockFile, specs: &UpdateSpecs) !specs.should_relax(env.name(), &platform, package) }) } - -// Represents the differences between two sets of packages. -#[derive(Default, Clone)] -pub struct PackagesDiff { - pub added: Vec, - pub removed: Vec, - pub changed: Vec<(rattler_lock::Package, rattler_lock::Package)>, -} - -impl PackagesDiff { - /// Returns true if the diff is empty. - pub(crate) fn is_empty(&self) -> bool { - self.added.is_empty() && self.removed.is_empty() && self.changed.is_empty() - } -} - -/// Contains the changes between two lock-files. -pub struct LockFileDiff { - pub environment: IndexMap>, -} - -impl LockFileDiff { - /// Determine the difference between two lock-files. - pub(crate) fn from_lock_files(previous: &LockFile, current: &LockFile) -> Self { - let mut result = Self { - environment: IndexMap::new(), - }; - - for (environment_name, environment) in current.environments() { - let previous = previous.environment(environment_name); - - let mut environment_diff = IndexMap::new(); - - for (platform, packages) in environment.packages_by_platform() { - // Determine the packages that were previously there. - let (mut previous_conda_packages, mut previous_pypi_packages): ( - HashMap<_, _>, - HashMap<_, _>, - ) = previous - .as_ref() - .and_then(|e| e.packages(platform)) - .into_iter() - .flatten() - .partition_map(|p| match p { - rattler_lock::Package::Conda(p) => { - Either::Left((p.package_record().name.clone(), p)) - } - rattler_lock::Package::Pypi(p) => { - Either::Right((p.data().package.name.clone(), p)) - } - }); - - let mut diff = PackagesDiff::default(); - - // Find new and changed packages - for package in packages { - match package { - Package::Conda(p) => { - let name = &p.package_record().name; - match previous_conda_packages.remove(name) { - Some(previous) if previous.url() != p.url() => { - diff.changed - .push((Package::Conda(previous), Package::Conda(p))); - } - None => { - diff.added.push(Package::Conda(p)); - } - _ => {} - } - } - Package::Pypi(p) => { - let name = &p.data().package.name; - match previous_pypi_packages.remove(name) { - Some(previous) if previous.url() != p.url() => { - diff.changed - .push((Package::Pypi(previous), Package::Pypi(p))); - } - None => { - diff.added.push(Package::Pypi(p)); - } - _ => {} - } - } - } - } - - // Determine packages that were removed - for (_, p) in previous_conda_packages { - diff.removed.push(Package::Conda(p)); - } - for (_, p) in previous_pypi_packages { - diff.removed.push(Package::Pypi(p)); - } - - environment_diff.insert(platform, diff); - } - - // Find platforms that were completely removed - for (platform, packages) in previous - .as_ref() - .map(|e| e.packages_by_platform()) - .into_iter() - .flatten() - .filter(|(platform, _)| !environment_diff.contains_key(platform)) - .collect_vec() - { - let mut diff = PackagesDiff::default(); - for package in packages { - match package { - Package::Conda(p) => { - diff.removed.push(Package::Conda(p)); - } - Package::Pypi(p) => { - diff.removed.push(Package::Pypi(p)); - } - } - } - environment_diff.insert(platform, diff); - } - - // Remove empty diffs - environment_diff.retain(|_, diff| !diff.is_empty()); - - result - .environment - .insert(environment_name.to_string(), environment_diff); - } - - // Find environments that were completely removed - for (environment_name, environment) in previous - .environments() - .filter(|(name, _)| !result.environment.contains_key(*name)) - .collect_vec() - { - let mut environment_diff = IndexMap::new(); - for (platform, packages) in environment.packages_by_platform() { - let mut diff = PackagesDiff::default(); - for package in packages { - match package { - Package::Conda(p) => { - diff.removed.push(Package::Conda(p)); - } - Package::Pypi(p) => { - diff.removed.push(Package::Pypi(p)); - } - } - } - environment_diff.insert(platform, diff); - } - result - .environment - .insert(environment_name.to_string(), environment_diff); - } - - // Remove empty environments - result.environment.retain(|_, diff| !diff.is_empty()); - - result - } - - /// Returns true if the diff is empty. - pub(crate) fn is_empty(&self) -> bool { - self.environment.is_empty() - } - - // Format the lock-file diff. - pub(crate) fn print(&self) -> std::io::Result<()> { - let mut writer = TabWriter::new(stdout()); - for (idx, (environment_name, environment)) in self - .environment - .iter() - .sorted_by(|(a, _), (b, _)| a.cmp(b)) - .enumerate() - { - // Find the changes that happened in all platforms. - let changes_by_platform = environment - .into_iter() - .map(|(platform, packages)| { - let changes = Self::format_changes(packages) - .into_iter() - .collect::>(); - (platform, changes) - }) - .collect::>(); - - // Find the changes that happened in all platforms. - let common_changes = changes_by_platform - .iter() - .fold(None, |acc, (_, changes)| match acc { - None => Some(changes.clone()), - Some(acc) => Some(acc.intersection(changes).cloned().collect()), - }) - .unwrap_or_default(); - - // Add a new line between environments - if idx > 0 { - writeln!(writer, "\t\t\t",)?; - } - - writeln!( - writer, - "{}: {}\t\t\t", - console::style("Environment").underlined(), - consts::ENVIRONMENT_STYLE.apply_to(environment_name) - )?; - - // Print the common changes. - for (_, line) in common_changes.iter().sorted_by_key(|(name, _)| name) { - writeln!(writer, " {}", line)?; - } - - // Print the per-platform changes. - for (platform, changes) in changes_by_platform { - let mut changes = changes - .iter() - .filter(|change| !common_changes.contains(change)) - .sorted_by_key(|(name, _)| name) - .peekable(); - if changes.peek().is_some() { - writeln!( - writer, - "{}: {}:{}\t\t\t", - console::style("Platform").underlined(), - consts::ENVIRONMENT_STYLE.apply_to(environment_name), - consts::PLATFORM_STYLE.apply_to(platform), - )?; - for (_, line) in changes { - writeln!(writer, " {}", line)?; - } - } - } - } - - writer.flush()?; - - Ok(()) - } - - fn format_changes(packages: &PackagesDiff) -> Vec<(Cow<'_, str>, String)> { - enum Change<'i> { - Added(&'i Package), - Removed(&'i Package), - Changed(&'i Package, &'i Package), - } - - fn format_package_identifier(package: &Package) -> String { - match package { - Package::Conda(p) => format!( - "{} {}", - &p.package_record().version.as_str(), - &p.package_record().build - ), - Package::Pypi(p) => p.data().package.version.to_string(), - } - } - - itertools::chain!( - packages.added.iter().map(Change::Added), - packages.removed.iter().map(Change::Removed), - packages.changed.iter().map(|a| Change::Changed(&a.0, &a.1)) - ) - .sorted_by_key(|c| match c { - Change::Added(p) => p.name(), - Change::Removed(p) => p.name(), - Change::Changed(p, _) => p.name(), - }) - .map(|p| match p { - Change::Added(p) => ( - p.name(), - format!( - "{} {} {}\t{}\t\t", - console::style("+").green(), - match p { - Package::Conda(_) => consts::CondaEmoji.to_string(), - Package::Pypi(_) => consts::PypiEmoji.to_string(), - }, - p.name(), - format_package_identifier(p) - ), - ), - Change::Removed(p) => ( - p.name(), - format!( - "{} {} {}\t{}\t\t", - console::style("-").red(), - match p { - Package::Conda(_) => consts::CondaEmoji.to_string(), - Package::Pypi(_) => consts::PypiEmoji.to_string(), - }, - p.name(), - format_package_identifier(p) - ), - ), - Change::Changed(previous, current) => { - fn choose_style<'a>(a: &'a str, b: &'a str) -> console::StyledObject<&'a str> { - if a == b { - console::style(a).dim() - } else { - console::style(a) - } - } - - let name = previous.name(); - let line = match (previous, current) { - (Package::Conda(previous), Package::Conda(current)) => { - let previous = previous.package_record(); - let current = current.package_record(); - - format!( - "{} {} {}\t{} {}\t->\t{} {}", - console::style("~").yellow(), - consts::CondaEmoji, - name, - choose_style(&previous.version.as_str(), ¤t.version.as_str()), - choose_style(previous.build.as_str(), current.build.as_str()), - choose_style(¤t.version.as_str(), &previous.version.as_str()), - choose_style(current.build.as_str(), previous.build.as_str()), - ) - } - (Package::Pypi(previous), Package::Pypi(current)) => { - let previous = previous.data().package; - let current = current.data().package; - - format!( - "{} {} {}\t{}\t->\t{}", - console::style("~").yellow(), - consts::PypiEmoji, - name, - choose_style( - &previous.version.to_string(), - ¤t.version.to_string() - ), - choose_style( - ¤t.version.to_string(), - &previous.version.to_string() - ), - ) - } - _ => unreachable!(), - }; - - (name, line) - } - }) - .collect() - } -} - -#[derive(Serialize, Clone)] -pub struct JsonPackageDiff { - name: String, - before: Option, - after: Option, - #[serde(rename = "type")] - ty: JsonPackageType, - #[serde(skip_serializing_if = "std::ops::Not::not")] - explicit: bool, -} - -#[derive(Serialize, Copy, Clone)] -#[serde(rename_all = "kebab-case")] -pub enum JsonPackageType { - Conda, - Pypi, -} - -#[derive(Serialize, Clone)] -pub struct LockFileJsonDiff { - pub version: usize, - pub environment: IndexMap>>, -} - -impl LockFileJsonDiff { - fn new(project: &Project, value: LockFileDiff) -> Self { - let mut environment = IndexMap::new(); - - for (environment_name, environment_diff) in value.environment { - let mut environment_diff_json = IndexMap::new(); - - for (platform, packages_diff) in environment_diff { - let conda_dependencies = project - .environment(environment_name.as_str()) - .map(|env| env.dependencies(None, Some(platform))) - .unwrap_or_default(); - - let pypi_dependencies = project - .environment(environment_name.as_str()) - .map(|env| env.pypi_dependencies(Some(platform))) - .unwrap_or_default(); - - let add_diffs = packages_diff.added.into_iter().map(|new| match new { - Package::Conda(pkg) => JsonPackageDiff { - name: pkg.package_record().name.as_normalized().to_string(), - before: None, - after: Some(serde_json::to_value(&pkg).unwrap()), - ty: JsonPackageType::Conda, - explicit: conda_dependencies.contains_key(&pkg.package_record().name), - }, - Package::Pypi(pkg) => JsonPackageDiff { - name: pkg.data().package.name.as_dist_info_name().into_owned(), - before: None, - after: Some(serde_json::to_value(&pkg).unwrap()), - ty: JsonPackageType::Pypi, - explicit: pypi_dependencies.contains_key(&pkg.data().package.name), - }, - }); - - let removed_diffs = packages_diff.removed.into_iter().map(|old| match old { - Package::Conda(pkg) => JsonPackageDiff { - name: pkg.package_record().name.as_normalized().to_string(), - before: Some(serde_json::to_value(&pkg).unwrap()), - after: None, - ty: JsonPackageType::Conda, - explicit: conda_dependencies.contains_key(&pkg.package_record().name), - }, - - Package::Pypi(pkg) => JsonPackageDiff { - name: pkg.data().package.name.as_dist_info_name().into_owned(), - before: Some(serde_json::to_value(&pkg).unwrap()), - after: None, - ty: JsonPackageType::Pypi, - explicit: pypi_dependencies.contains_key(&pkg.data().package.name), - }, - }); - - let changed_diffs = packages_diff.changed.into_iter().map(|(old, new)| match (old, new) { - (Package::Conda(old), Package::Conda(new)) => - { - let before = serde_json::to_value(&old).unwrap(); - let after = serde_json::to_value(&new).unwrap(); - let (before, after) = compute_json_diff(before, after); - JsonPackageDiff { - name: old.package_record().name.as_normalized().to_string(), - before: Some(before), - after: Some(after), - ty: JsonPackageType::Conda, - explicit: conda_dependencies.contains_key(&old.package_record().name), - } - } - (Package::Pypi(old), Package::Pypi(new)) => { - let before = serde_json::to_value(&old).unwrap(); - let after = serde_json::to_value(&new).unwrap(); - let (before, after) = compute_json_diff(before, after); - JsonPackageDiff { - name: old.data().package.name.as_dist_info_name().into_owned(), - before: Some(before), - after: Some(after), - ty: JsonPackageType::Pypi, - explicit: pypi_dependencies.contains_key(&old.data().package.name), - } - } - _ => unreachable!("packages cannot change type, they are represented as removals and inserts instead"), - }); - - let packages_diff_json = add_diffs - .chain(removed_diffs) - .chain(changed_diffs) - .sorted_by_key(|diff| diff.name.clone()) - .collect_vec(); - - environment_diff_json.insert(platform, packages_diff_json); - } - - environment.insert(environment_name, environment_diff_json); - } - - Self { - version: 1, - environment, - } - } -} - -fn compute_json_diff( - mut a: serde_json::Value, - mut b: serde_json::Value, -) -> (serde_json::Value, serde_json::Value) { - if let (Some(a), Some(b)) = (a.as_object_mut(), b.as_object_mut()) { - a.retain(|key, value| { - if let Some(other_value) = b.get(key) { - if other_value == value { - b.remove(key); - return false; - } - } else { - b.insert(key.to_string(), Value::Null); - } - true - }); - } - (a, b) -} diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs new file mode 100644 index 000000000..428e3a5b0 --- /dev/null +++ b/src/cli/upgrade.rs @@ -0,0 +1,255 @@ +use std::cmp::Ordering; +use std::sync::Arc; + +use crate::cli::cli_config::ProjectConfig; +use crate::Project; +use clap::Parser; +use fancy_display::FancyDisplay; +use itertools::Itertools; +use miette::MietteDiagnostic; +use miette::{Context, IntoDiagnostic}; + +use super::cli_config::PrefixUpdateConfig; +use crate::diff::LockFileJsonDiff; +use pep508_rs::MarkerTree; +use pep508_rs::Requirement; +use pixi_manifest::FeatureName; +use pixi_manifest::PyPiRequirement; +use pixi_manifest::SpecType; +use pixi_spec::PixiSpec; +use rattler_conda_types::MatchSpec; + +/// Update dependencies as recorded in the local lock file +#[derive(Parser, Debug, Default)] +pub struct Args { + #[clap(flatten)] + pub project_config: ProjectConfig, + + #[clap(flatten)] + pub prefix_update_config: PrefixUpdateConfig, + + #[clap(flatten)] + pub specs: UpgradeSpecsArgs, + + /// Output the changes in JSON format. + #[clap(long)] + pub json: bool, + + /// Only show the changes that would be made, without actually updating the manifest, lock file, or environment. + #[clap(short = 'n', long)] + pub dry_run: bool, +} + +#[derive(Parser, Debug, Default)] +pub struct UpgradeSpecsArgs { + /// The packages to upgrade + pub packages: Option>, + + /// The feature to update + #[clap(long = "feature", short = 'f', default_value_t)] + pub feature: FeatureName, + + /// The packages which should be excluded + #[clap(long, conflicts_with = "packages")] + pub exclude: Option>, +} + +pub async fn execute(args: Args) -> miette::Result<()> { + let mut project = Project::load_or_else_discover(args.project_config.manifest_path.as_deref())? + .with_cli_config(args.prefix_update_config.config.clone()); + + // Ensure that the given feature exists + let Some(feature) = project.manifest.feature(&args.specs.feature) else { + miette::bail!( + "could not find a feature named {}", + args.specs.feature.fancy_display() + ) + }; + + // TODO: Also support build and host + let spec_type = SpecType::Run; + let match_spec_iter = feature + .dependencies(Some(spec_type), None) + .into_iter() + .flat_map(|deps| deps.into_owned()); + + let pypi_deps_iter = feature + .pypi_dependencies(None) + .into_iter() + .flat_map(|deps| deps.into_owned()); + + // If the user specified a package name, check to see if it is even there. + if let Some(package_names) = &args.specs.packages { + let available_packages = match_spec_iter + .clone() + .map(|(name, _)| name.as_normalized().to_string()) + .chain( + pypi_deps_iter + .clone() + .map(|(name, _)| name.as_normalized().to_string()), + ) + .collect_vec(); + + for package in package_names { + ensure_package_exists(package, &available_packages)? + } + } + + let match_specs = match_spec_iter + // Don't upgrade excluded packages + .filter(|(name, _)| match &args.specs.exclude { + None => true, + Some(exclude) if exclude.contains(&name.as_normalized().to_string()) => false, + _ => true, + }) + // If specific packages have been requested, only upgrade those + .filter(|(name, _)| match &args.specs.packages { + None => true, + Some(packages) if packages.contains(&name.as_normalized().to_string()) => true, + _ => false, + }) + // Only upgrade version specs + .filter_map(|(name, req)| match req { + PixiSpec::DetailedVersion(version_spec) => { + let channel = version_spec + .channel + .and_then(|c| c.into_channel(&project.channel_config()).ok()) + .map(Arc::new); + Some(( + name.clone(), + ( + MatchSpec { + name: Some(name), + channel, + ..Default::default() + }, + spec_type, + ), + )) + } + PixiSpec::Version(_) => Some((name.clone(), (MatchSpec::from(name), spec_type))), + _ => None, + }) + .collect(); + + let pypi_deps = pypi_deps_iter + // Don't upgrade excluded packages + .filter(|(name, _)| match &args.specs.exclude { + None => true, + Some(exclude) if exclude.contains(&name.as_normalized().to_string()) => false, + _ => true, + }) + // If specific packages have been requested, only upgrade those + .filter(|(name, _)| match &args.specs.packages { + None => true, + Some(packages) if packages.contains(&name.as_normalized().to_string()) => true, + _ => false, + }) + // Only upgrade version specs + .filter_map(|(name, req)| match req { + PyPiRequirement::Version { extras, .. } => Some(( + name.clone(), + Requirement { + name: name.as_normalized().clone(), + extras, + marker: MarkerTree::default(), + origin: None, + version_or_url: None, + }, + )), + PyPiRequirement::RawVersion(_) => Some(( + name.clone(), + Requirement { + name: name.as_normalized().clone(), + extras: Vec::default(), + marker: MarkerTree::default(), + origin: None, + version_or_url: None, + }, + )), + _ => None, + }) + .collect(); + + let update_deps = project + .update_dependencies( + match_specs, + pypi_deps, + &args.prefix_update_config, + &args.specs.feature, + &[], + false, + args.dry_run, + ) + .await?; + + // Is there something to report? + if let Some(update_deps) = update_deps { + let diff = update_deps.lock_file_diff; + // Format as json? + if args.json { + let json_diff = LockFileJsonDiff::new(&project, diff); + let json = serde_json::to_string_pretty(&json_diff).expect("failed to convert to json"); + println!("{}", json); + } else { + diff.print() + .into_diagnostic() + .context("failed to print lock-file diff")?; + } + } else { + eprintln!( + "{}All packages are already up-to-date", + console::style(console::Emoji("✔ ", "")).green() + ); + } + + Project::warn_on_discovered_from_env(args.project_config.manifest_path.as_deref()); + Ok(()) +} + +/// Ensures the existence of the specified package +/// +/// # Returns +/// +/// Returns `miette::Result` with a descriptive error message +/// if the package does not exist. +fn ensure_package_exists(package_name: &str, available_packages: &[String]) -> miette::Result<()> { + let similar_names = available_packages + .iter() + .unique() + .filter_map(|name| { + let distance = strsim::jaro(package_name, name); + if distance > 0.6 { + Some((name, distance)) + } else { + None + } + }) + .sorted_by(|(_, a), (_, b)| b.partial_cmp(a).unwrap_or(Ordering::Equal)) + .take(5) + .map(|(name, _)| name) + .collect_vec(); + + if similar_names.first().map(|s| s.as_str()) == Some(package_name) { + return Ok(()); + } + + let message = format!("could not find a package named '{package_name}'"); + + Err(MietteDiagnostic { + message, + code: None, + severity: None, + help: if !similar_names.is_empty() { + Some(format!( + "did you mean '{}'?", + similar_names.iter().format("', '") + )) + } else { + None + }, + url: None, + labels: None, + } + .into()) +} diff --git a/src/diff.rs b/src/diff.rs new file mode 100644 index 000000000..b14560d4f --- /dev/null +++ b/src/diff.rs @@ -0,0 +1,509 @@ +use std::{ + borrow::Cow, + collections::HashSet, + io::{stderr, Write}, +}; + +use crate::Project; +use ahash::HashMap; +use indexmap::IndexMap; +use itertools::{Either, Itertools}; +use pixi_consts::consts; +use pixi_manifest::FeaturesExt; +use rattler_conda_types::Platform; +use rattler_lock::{LockFile, Package}; +use serde::Serialize; +use serde_json::Value; +use tabwriter::TabWriter; + +// Represents the differences between two sets of packages. +#[derive(Default, Clone)] +pub struct PackagesDiff { + pub added: Vec, + pub removed: Vec, + pub changed: Vec<(rattler_lock::Package, rattler_lock::Package)>, +} + +impl PackagesDiff { + /// Returns true if the diff is empty. + pub(crate) fn is_empty(&self) -> bool { + self.added.is_empty() && self.removed.is_empty() && self.changed.is_empty() + } +} + +/// Contains the changes between two lock-files. +pub struct LockFileDiff { + pub environment: IndexMap>, +} + +impl LockFileDiff { + /// Determine the difference between two lock-files. + pub(crate) fn from_lock_files(previous: &LockFile, current: &LockFile) -> Self { + let mut result = Self { + environment: IndexMap::new(), + }; + + for (environment_name, environment) in current.environments() { + let previous = previous.environment(environment_name); + + let mut environment_diff = IndexMap::new(); + + for (platform, packages) in environment.packages_by_platform() { + // Determine the packages that were previously there. + let (mut previous_conda_packages, mut previous_pypi_packages): ( + HashMap<_, _>, + HashMap<_, _>, + ) = previous + .as_ref() + .and_then(|e| e.packages(platform)) + .into_iter() + .flatten() + .partition_map(|p| match p { + rattler_lock::Package::Conda(p) => { + Either::Left((p.package_record().name.clone(), p)) + } + rattler_lock::Package::Pypi(p) => { + Either::Right((p.data().package.name.clone(), p)) + } + }); + + let mut diff = PackagesDiff::default(); + + // Find new and changed packages + for package in packages { + match package { + Package::Conda(p) => { + let name = &p.package_record().name; + match previous_conda_packages.remove(name) { + Some(previous) if previous.url() != p.url() => { + diff.changed + .push((Package::Conda(previous), Package::Conda(p))); + } + None => { + diff.added.push(Package::Conda(p)); + } + _ => {} + } + } + Package::Pypi(p) => { + let name = &p.data().package.name; + match previous_pypi_packages.remove(name) { + Some(previous) if previous.url() != p.url() => { + diff.changed + .push((Package::Pypi(previous), Package::Pypi(p))); + } + None => { + diff.added.push(Package::Pypi(p)); + } + _ => {} + } + } + } + } + + // Determine packages that were removed + for (_, p) in previous_conda_packages { + diff.removed.push(Package::Conda(p)); + } + for (_, p) in previous_pypi_packages { + diff.removed.push(Package::Pypi(p)); + } + + environment_diff.insert(platform, diff); + } + + // Find platforms that were completely removed + for (platform, packages) in previous + .as_ref() + .map(|e| e.packages_by_platform()) + .into_iter() + .flatten() + .filter(|(platform, _)| !environment_diff.contains_key(platform)) + .collect_vec() + { + let mut diff = PackagesDiff::default(); + for package in packages { + match package { + Package::Conda(p) => { + diff.removed.push(Package::Conda(p)); + } + Package::Pypi(p) => { + diff.removed.push(Package::Pypi(p)); + } + } + } + environment_diff.insert(platform, diff); + } + + // Remove empty diffs + environment_diff.retain(|_, diff| !diff.is_empty()); + + result + .environment + .insert(environment_name.to_string(), environment_diff); + } + + // Find environments that were completely removed + for (environment_name, environment) in previous + .environments() + .filter(|(name, _)| !result.environment.contains_key(*name)) + .collect_vec() + { + let mut environment_diff = IndexMap::new(); + for (platform, packages) in environment.packages_by_platform() { + let mut diff = PackagesDiff::default(); + for package in packages { + match package { + Package::Conda(p) => { + diff.removed.push(Package::Conda(p)); + } + Package::Pypi(p) => { + diff.removed.push(Package::Pypi(p)); + } + } + } + environment_diff.insert(platform, diff); + } + result + .environment + .insert(environment_name.to_string(), environment_diff); + } + + // Remove empty environments + result.environment.retain(|_, diff| !diff.is_empty()); + + result + } + + /// Returns true if the diff is empty. + pub(crate) fn is_empty(&self) -> bool { + self.environment.is_empty() + } + + // Format the lock-file diff. + pub(crate) fn print(&self) -> std::io::Result<()> { + let mut writer = TabWriter::new(stderr()); + for (idx, (environment_name, environment)) in self + .environment + .iter() + .sorted_by(|(a, _), (b, _)| a.cmp(b)) + .enumerate() + { + // Find the changes that happened in all platforms. + let changes_by_platform = environment + .into_iter() + .map(|(platform, packages)| { + let changes = Self::format_changes(packages) + .into_iter() + .collect::>(); + (platform, changes) + }) + .collect::>(); + + // Find the changes that happened in all platforms. + let common_changes = changes_by_platform + .iter() + .fold(None, |acc, (_, changes)| match acc { + None => Some(changes.clone()), + Some(acc) => Some(acc.intersection(changes).cloned().collect()), + }) + .unwrap_or_default(); + + // Add a new line between environments + if idx > 0 { + writeln!(writer, "\t\t\t",)?; + } + + writeln!( + writer, + "{}: {}\t\t\t", + console::style("Environment").underlined(), + consts::ENVIRONMENT_STYLE.apply_to(environment_name) + )?; + + // Print the common changes. + for (_, line) in common_changes.iter().sorted_by_key(|(name, _)| name) { + writeln!(writer, " {}", line)?; + } + + // Print the per-platform changes. + for (platform, changes) in changes_by_platform { + let mut changes = changes + .iter() + .filter(|change| !common_changes.contains(change)) + .sorted_by_key(|(name, _)| name) + .peekable(); + if changes.peek().is_some() { + writeln!( + writer, + "{}: {}:{}\t\t\t", + console::style("Platform").underlined(), + consts::ENVIRONMENT_STYLE.apply_to(environment_name), + consts::PLATFORM_STYLE.apply_to(platform), + )?; + for (_, line) in changes { + writeln!(writer, " {}", line)?; + } + } + } + } + + writer.flush()?; + + Ok(()) + } + + fn format_changes(packages: &PackagesDiff) -> Vec<(Cow<'_, str>, String)> { + enum Change<'i> { + Added(&'i Package), + Removed(&'i Package), + Changed(&'i Package, &'i Package), + } + + fn format_package_identifier(package: &Package) -> String { + match package { + Package::Conda(p) => format!( + "{} {}", + &p.package_record().version.as_str(), + &p.package_record().build + ), + Package::Pypi(p) => p.data().package.version.to_string(), + } + } + + itertools::chain!( + packages.added.iter().map(Change::Added), + packages.removed.iter().map(Change::Removed), + packages.changed.iter().map(|a| Change::Changed(&a.0, &a.1)) + ) + .sorted_by_key(|c| match c { + Change::Added(p) => p.name(), + Change::Removed(p) => p.name(), + Change::Changed(p, _) => p.name(), + }) + .map(|p| match p { + Change::Added(p) => ( + p.name(), + format!( + "{} {} {}\t{}\t\t", + console::style("+").green(), + match p { + Package::Conda(_) => consts::CondaEmoji.to_string(), + Package::Pypi(_) => consts::PypiEmoji.to_string(), + }, + p.name(), + format_package_identifier(p) + ), + ), + Change::Removed(p) => ( + p.name(), + format!( + "{} {} {}\t{}\t\t", + console::style("-").red(), + match p { + Package::Conda(_) => consts::CondaEmoji.to_string(), + Package::Pypi(_) => consts::PypiEmoji.to_string(), + }, + p.name(), + format_package_identifier(p) + ), + ), + Change::Changed(previous, current) => { + fn choose_style<'a>(a: &'a str, b: &'a str) -> console::StyledObject<&'a str> { + if a == b { + console::style(a).dim() + } else { + console::style(a) + } + } + + let name = previous.name(); + let line = match (previous, current) { + (Package::Conda(previous), Package::Conda(current)) => { + let previous = previous.package_record(); + let current = current.package_record(); + + format!( + "{} {} {}\t{} {}\t->\t{} {}", + console::style("~").yellow(), + consts::CondaEmoji, + name, + choose_style(&previous.version.as_str(), ¤t.version.as_str()), + choose_style(previous.build.as_str(), current.build.as_str()), + choose_style(¤t.version.as_str(), &previous.version.as_str()), + choose_style(current.build.as_str(), previous.build.as_str()), + ) + } + (Package::Pypi(previous), Package::Pypi(current)) => { + let previous = previous.data().package; + let current = current.data().package; + + format!( + "{} {} {}\t{}\t->\t{}", + console::style("~").yellow(), + consts::PypiEmoji, + name, + choose_style( + &previous.version.to_string(), + ¤t.version.to_string() + ), + choose_style( + ¤t.version.to_string(), + &previous.version.to_string() + ), + ) + } + _ => unreachable!(), + }; + + (name, line) + } + }) + .collect() + } +} + +#[derive(Serialize, Clone)] +pub struct JsonPackageDiff { + name: String, + before: Option, + after: Option, + #[serde(rename = "type")] + ty: JsonPackageType, + #[serde(skip_serializing_if = "std::ops::Not::not")] + explicit: bool, +} + +#[derive(Serialize, Copy, Clone)] +#[serde(rename_all = "kebab-case")] +pub enum JsonPackageType { + Conda, + Pypi, +} + +#[derive(Serialize, Clone)] +pub struct LockFileJsonDiff { + pub version: usize, + pub environment: IndexMap>>, +} + +impl LockFileJsonDiff { + pub fn new(project: &Project, value: LockFileDiff) -> Self { + let mut environment = IndexMap::new(); + + for (environment_name, environment_diff) in value.environment { + let mut environment_diff_json = IndexMap::new(); + + for (platform, packages_diff) in environment_diff { + let conda_dependencies = project + .environment(environment_name.as_str()) + .map(|env| env.dependencies(None, Some(platform))) + .unwrap_or_default(); + + let pypi_dependencies = project + .environment(environment_name.as_str()) + .map(|env| env.pypi_dependencies(Some(platform))) + .unwrap_or_default(); + + let add_diffs = packages_diff.added.into_iter().map(|new| match new { + Package::Conda(pkg) => JsonPackageDiff { + name: pkg.package_record().name.as_normalized().to_string(), + before: None, + after: Some(serde_json::to_value(&pkg).unwrap()), + ty: JsonPackageType::Conda, + explicit: conda_dependencies.contains_key(&pkg.package_record().name), + }, + Package::Pypi(pkg) => JsonPackageDiff { + name: pkg.data().package.name.as_dist_info_name().into_owned(), + before: None, + after: Some(serde_json::to_value(&pkg).unwrap()), + ty: JsonPackageType::Pypi, + explicit: pypi_dependencies.contains_key(&pkg.data().package.name), + }, + }); + + let removed_diffs = packages_diff.removed.into_iter().map(|old| match old { + Package::Conda(pkg) => JsonPackageDiff { + name: pkg.package_record().name.as_normalized().to_string(), + before: Some(serde_json::to_value(&pkg).unwrap()), + after: None, + ty: JsonPackageType::Conda, + explicit: conda_dependencies.contains_key(&pkg.package_record().name), + }, + + Package::Pypi(pkg) => JsonPackageDiff { + name: pkg.data().package.name.as_dist_info_name().into_owned(), + before: Some(serde_json::to_value(&pkg).unwrap()), + after: None, + ty: JsonPackageType::Pypi, + explicit: pypi_dependencies.contains_key(&pkg.data().package.name), + }, + }); + + let changed_diffs = packages_diff.changed.into_iter().map(|(old, new)| match (old, new) { + (Package::Conda(old), Package::Conda(new)) => + { + let before = serde_json::to_value(&old).unwrap(); + let after = serde_json::to_value(&new).unwrap(); + let (before, after) = compute_json_diff(before, after); + JsonPackageDiff { + name: old.package_record().name.as_normalized().to_string(), + before: Some(before), + after: Some(after), + ty: JsonPackageType::Conda, + explicit: conda_dependencies.contains_key(&old.package_record().name), + } + } + (Package::Pypi(old), Package::Pypi(new)) => { + let before = serde_json::to_value(&old).unwrap(); + let after = serde_json::to_value(&new).unwrap(); + let (before, after) = compute_json_diff(before, after); + JsonPackageDiff { + name: old.data().package.name.as_dist_info_name().into_owned(), + before: Some(before), + after: Some(after), + ty: JsonPackageType::Pypi, + explicit: pypi_dependencies.contains_key(&old.data().package.name), + } + } + _ => unreachable!("packages cannot change type, they are represented as removals and inserts instead"), + }); + + let packages_diff_json = add_diffs + .chain(removed_diffs) + .chain(changed_diffs) + .sorted_by_key(|diff| diff.name.clone()) + .collect_vec(); + + environment_diff_json.insert(platform, packages_diff_json); + } + + environment.insert(environment_name, environment_diff_json); + } + + Self { + version: 1, + environment, + } + } +} + +fn compute_json_diff( + mut a: serde_json::Value, + mut b: serde_json::Value, +) -> (serde_json::Value, serde_json::Value) { + if let (Some(a), Some(b)) = (a.as_object_mut(), b.as_object_mut()) { + a.retain(|key, value| { + if let Some(other_value) = b.get(key) { + if other_value == value { + b.remove(key); + return false; + } + } else { + b.insert(key.to_string(), Value::Null); + } + true + }); + } + (a, b) +} diff --git a/src/lib.rs b/src/lib.rs index 5470fa23d..ce8438777 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ pub mod activation; pub mod cli; pub(crate) mod conda_pypi_clobber; +mod diff; pub mod environment; mod global; mod install_pypi; diff --git a/src/project/mod.rs b/src/project/mod.rs index ccc8bac59..14254daee 100644 --- a/src/project/mod.rs +++ b/src/project/mod.rs @@ -14,31 +14,44 @@ use std::{ fmt::{Debug, Formatter}, hash::Hash, path::{Path, PathBuf}, + str::FromStr, sync::{Arc, OnceLock}, }; use async_once_cell::OnceCell as AsyncCell; pub use environment::Environment; +use grouped_environment::GroupedEnvironment; pub use has_project_ref::HasProjectRef; -use indexmap::Equivalent; +use indexmap::{Equivalent, IndexMap}; use itertools::Itertools; use miette::IntoDiagnostic; use once_cell::sync::OnceCell; -use pixi_config::Config; +use pep440_rs::VersionSpecifiers; +use pep508_rs::{Requirement, VersionOrUrl::VersionSpecifier}; +use pixi_config::{Config, PinningStrategy}; use pixi_consts::consts; use pixi_manifest::{ - EnvironmentName, Environments, HasManifestRef, Manifest, ParsedManifest, SpecType, + pypi::PyPiPackageName, DependencyOverwriteBehavior, EnvironmentName, Environments, FeatureName, + FeaturesExt, HasFeaturesIter, HasManifestRef, Manifest, ParsedManifest, SpecType, }; use pixi_utils::reqwest::build_reqwest_clients; use pypi_mapping::{ChannelName, CustomMapping, MappingLocation, MappingSource}; -use rattler_conda_types::{Channel, ChannelConfig, Version}; +use rattler_conda_types::{Channel, ChannelConfig, MatchSpec, PackageName, Platform, Version}; +use rattler_lock::{LockFile, Package}; use rattler_repodata_gateway::Gateway; use reqwest_middleware::ClientWithMiddleware; pub use solve_group::SolveGroup; use url::{ParseError, Url}; use xxhash_rust::xxh3::xxh3_64; -use crate::activation::{initialize_env_variables, CurrentEnvVarBehavior}; +use crate::{ + activation::{initialize_env_variables, CurrentEnvVarBehavior}, + cli::cli_config::PrefixUpdateConfig, + diff::LockFileDiff, + environment::LockFileUsage, + load_lock_file, + lock_file::{filter_lock_file, LockFileDerivedData, UpdateContext, UpdateMode}, +}; static CUSTOM_TARGET_DIR_WARN: OnceCell<()> = OnceCell::new(); @@ -93,6 +106,13 @@ impl EnvironmentVars { } } +/// List of packages that are not following the semver versioning scheme +/// but will use the minor version by default when adding a dependency. +// Don't forget to add to the docstring if you add a package here! +const NON_SEMVER_PACKAGES: [&str; 11] = [ + "python", "rust", "julia", "gcc", "gxx", "gfortran", "nodejs", "deno", "r", "r-base", "perl", +]; + /// The pixi project, this main struct to interact with the project. This struct /// holds the `Manifest` and has functions to modify or request information from /// it. This allows in the future to have multiple environments or manifests @@ -604,6 +624,342 @@ impl Project { pub fn manifest(&self) -> &Manifest { &self.manifest } + + /// Update the manifest with the given package specs, and upgrade the packages if possible + /// + /// 1. Modify the manifest with the given package specs, if no version is given, use `no-pin` strategy + /// 2. Update the lock file + /// 3. Given packages without version restrictions will get a semver restriction + #[allow(clippy::too_many_arguments)] + pub async fn update_dependencies( + &mut self, + match_specs: IndexMap, + pypi_deps: IndexMap, + prefix_update_config: &PrefixUpdateConfig, + feature_name: &FeatureName, + platforms: &[Platform], + editable: bool, + dry_run: bool, + ) -> Result, miette::Error> { + let mut conda_specs_to_add_constraints_for = IndexMap::new(); + let mut pypi_specs_to_add_constraints_for = IndexMap::new(); + let mut conda_packages = HashSet::new(); + let mut pypi_packages = HashSet::new(); + let channel_config = self.channel_config(); + for (name, (spec, spec_type)) in match_specs { + let added = self.manifest.add_dependency( + &spec, + spec_type, + platforms, + feature_name, + DependencyOverwriteBehavior::Overwrite, + &channel_config, + )?; + if added { + if spec.version.is_none() { + conda_specs_to_add_constraints_for.insert(name.clone(), (spec_type, spec)); + } + conda_packages.insert(name); + } + } + + for (name, spec) in pypi_deps { + let added = self.manifest.add_pep508_dependency( + &spec, + platforms, + feature_name, + Some(editable), + DependencyOverwriteBehavior::Overwrite, + )?; + if added { + if spec.version_or_url.is_none() { + pypi_specs_to_add_constraints_for.insert(name.clone(), spec); + } + pypi_packages.insert(name.as_normalized().clone()); + } + } + + // Only save to disk if not a dry run + if !dry_run { + self.save()?; + } + + if prefix_update_config.lock_file_usage() != LockFileUsage::Update { + return Ok(None); + } + + let original_lock_file = load_lock_file(self).await?; + let affected_environments = self + .environments() + .iter() + // Filter out any environment that does not contain the feature we modified + .filter(|e| e.features().any(|f| f.name == *feature_name)) + // Expand the selection to also included any environment that shares the same solve + // group + .flat_map(|e| { + GroupedEnvironment::from(e.clone()) + .environments() + .collect_vec() + }) + .unique() + .collect_vec(); + let default_environment_is_affected = + affected_environments.contains(&self.default_environment()); + tracing::debug!( + "environments affected by the add command: {}", + affected_environments.iter().map(|e| e.name()).format(", ") + ); + let affect_environment_and_platforms = affected_environments + .into_iter() + // Create an iterator over all environment and platform combinations + .flat_map(|e| e.platforms().into_iter().map(move |p| (e.clone(), p))) + // Filter out any platform that is not affected by the changes. + .filter(|(_, platform)| platforms.is_empty() || platforms.contains(platform)) + .map(|(e, p)| (e.name().to_string(), p)) + .collect_vec(); + let unlocked_lock_file = self.unlock_packages( + &original_lock_file, + conda_packages, + pypi_packages, + affect_environment_and_platforms + .iter() + .map(|(e, p)| (e.as_str(), *p)) + .collect(), + ); + let LockFileDerivedData { + project: _, // We don't need the project here + lock_file, + package_cache, + uv_context, + updated_conda_prefixes, + updated_pypi_prefixes, + io_concurrency_limit, + } = UpdateContext::builder(self) + .with_lock_file(unlocked_lock_file) + .with_no_install(prefix_update_config.no_install() || dry_run) + .finish()? + .update() + .await?; + + let mut implicit_constraints = HashMap::new(); + if !conda_specs_to_add_constraints_for.is_empty() { + let conda_constraints = self.update_conda_specs_from_lock_file( + &lock_file, + conda_specs_to_add_constraints_for, + affect_environment_and_platforms.clone(), + feature_name, + platforms, + )?; + implicit_constraints.extend(conda_constraints); + } + + if !pypi_specs_to_add_constraints_for.is_empty() { + let pypi_constraints = self.update_pypi_specs_from_lock_file( + &lock_file, + pypi_specs_to_add_constraints_for, + affect_environment_and_platforms, + feature_name, + platforms, + editable, + )?; + implicit_constraints.extend(pypi_constraints); + } + + // Only write to disk if not a dry run + if !dry_run { + self.save()?; + } + + let mut updated_lock_file = LockFileDerivedData { + project: self, + lock_file, + package_cache, + updated_conda_prefixes, + updated_pypi_prefixes, + uv_context, + io_concurrency_limit, + }; + if !prefix_update_config.no_lockfile_update && !dry_run { + updated_lock_file.write_to_disk()?; + } + if !prefix_update_config.no_install() + && !dry_run + && self.environments().len() == 1 + && default_environment_is_affected + { + updated_lock_file + .prefix(&self.default_environment(), UpdateMode::Revalidate) + .await?; + } + + let lock_file_diff = + LockFileDiff::from_lock_files(&original_lock_file, &updated_lock_file.lock_file); + + Ok(Some(UpdateDeps { + implicit_constraints, + lock_file_diff, + })) + } + + /// Constructs a new lock-file where some of the constraints have been removed. + fn unlock_packages( + &self, + lock_file: &LockFile, + conda_packages: HashSet, + pypi_packages: HashSet, + affected_environments: HashSet<(&str, Platform)>, + ) -> LockFile { + filter_lock_file(self, lock_file, |env, platform, package| { + if affected_environments.contains(&(env.name().as_str(), platform)) { + match package { + Package::Conda(package) => { + !conda_packages.contains(&package.package_record().name) + } + Package::Pypi(package) => !pypi_packages.contains(&package.data().package.name), + } + } else { + true + } + }) + } + + /// Update the conda specs of newly added packages based on the contents of the + /// updated lock-file. + fn update_conda_specs_from_lock_file( + &mut self, + updated_lock_file: &LockFile, + conda_specs_to_add_constraints_for: IndexMap, + affect_environment_and_platforms: Vec<(String, Platform)>, + feature_name: &FeatureName, + platforms: &[Platform], + ) -> miette::Result> { + let mut implicit_constraints = HashMap::new(); + + // Determine the conda records that were affected by the add. + let conda_records = affect_environment_and_platforms + .into_iter() + // Get all the conda and pypi records for the combination of environments and + // platforms + .filter_map(|(env, platform)| { + let locked_env = updated_lock_file.environment(&env)?; + locked_env + .conda_repodata_records_for_platform(platform) + .ok()? + }) + .flatten() + .collect_vec(); + + let mut pinning_strategy = self.config().pinning_strategy; + let channel_config = self.channel_config(); + for (name, (spec_type, spec)) in conda_specs_to_add_constraints_for { + // Edge case: some packages are a special case where we want to pin the minor version by default. + // This is done to avoid early user confusion when the minor version changes and environments magically start breaking. + // This move a `>=3.13, <4` to a `>=3.13, <3.14` constraint. + if NON_SEMVER_PACKAGES.contains(&name.as_normalized()) && pinning_strategy.is_none() { + tracing::info!( + "Pinning {} to minor version by default", + name.as_normalized() + ); + pinning_strategy = Some(PinningStrategy::Minor); + } + let version_constraint = pinning_strategy + .unwrap_or_default() + .determine_version_constraint(conda_records.iter().filter_map(|record| { + if record.package_record.name == name { + Some(record.package_record.version.version()) + } else { + None + } + })); + + if let Some(version_constraint) = version_constraint { + implicit_constraints + .insert(name.as_source().to_string(), version_constraint.to_string()); + let spec = MatchSpec { + version: Some(version_constraint), + ..spec + }; + self.manifest.add_dependency( + &spec, + spec_type, + platforms, + feature_name, + DependencyOverwriteBehavior::Overwrite, + &channel_config, + )?; + } + } + + Ok(implicit_constraints) + } + + /// Update the pypi specs of newly added packages based on the contents of the + /// updated lock-file. + fn update_pypi_specs_from_lock_file( + &mut self, + updated_lock_file: &LockFile, + pypi_specs_to_add_constraints_for: IndexMap, + affect_environment_and_platforms: Vec<(String, Platform)>, + feature_name: &FeatureName, + platforms: &[Platform], + editable: bool, + ) -> miette::Result> { + let mut implicit_constraints = HashMap::new(); + + let pypi_records = affect_environment_and_platforms + .into_iter() + // Get all the conda and pypi records for the combination of environments and + // platforms + .filter_map(|(env, platform)| { + let locked_env = updated_lock_file.environment(&env)?; + locked_env.pypi_packages_for_platform(platform) + }) + .flatten() + .collect_vec(); + + let pinning_strategy = self.config().pinning_strategy.unwrap_or_default(); + + // Determine the versions of the packages in the lock-file + for (name, req) in pypi_specs_to_add_constraints_for { + let version_constraint = pinning_strategy.determine_version_constraint( + pypi_records + .iter() + .filter_map(|(data, _)| { + if &data.name == name.as_normalized() { + Version::from_str(&data.version.to_string()).ok() + } else { + None + } + }) + .collect_vec() + .iter(), + ); + + let version_spec = version_constraint + .and_then(|spec| VersionSpecifiers::from_str(&spec.to_string()).ok()); + if let Some(version_spec) = version_spec { + implicit_constraints.insert(name.as_source().to_string(), version_spec.to_string()); + let req = Requirement { + version_or_url: Some(VersionSpecifier(version_spec)), + ..req + }; + self.manifest.add_pep508_dependency( + &req, + platforms, + feature_name, + Some(editable), + DependencyOverwriteBehavior::Overwrite, + )?; + } + } + + Ok(implicit_constraints) + } +} + +pub struct UpdateDeps { + pub implicit_constraints: HashMap, + pub lock_file_diff: LockFileDiff, } impl<'source> HasManifestRef<'source> for &'source Project { diff --git a/tests/data/channels/channels/dummy_channel_1/linux-64/dummy-a-0.1.0-hb0f4dca_0.conda b/tests/data/channels/channels/dummy_channel_1/linux-64/dummy-a-0.1.0-hb0f4dca_0.conda index 978134a51..14e747199 100644 Binary files a/tests/data/channels/channels/dummy_channel_1/linux-64/dummy-a-0.1.0-hb0f4dca_0.conda and b/tests/data/channels/channels/dummy_channel_1/linux-64/dummy-a-0.1.0-hb0f4dca_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_1/linux-64/dummy-b-0.1.0-hb0f4dca_0.conda b/tests/data/channels/channels/dummy_channel_1/linux-64/dummy-b-0.1.0-hb0f4dca_0.conda index cf94e8764..a984f9135 100644 Binary files a/tests/data/channels/channels/dummy_channel_1/linux-64/dummy-b-0.1.0-hb0f4dca_0.conda and b/tests/data/channels/channels/dummy_channel_1/linux-64/dummy-b-0.1.0-hb0f4dca_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_1/linux-64/dummy-c-0.1.0-hb0f4dca_0.conda b/tests/data/channels/channels/dummy_channel_1/linux-64/dummy-c-0.1.0-hb0f4dca_0.conda index 2d4d42844..e7a664506 100644 Binary files a/tests/data/channels/channels/dummy_channel_1/linux-64/dummy-c-0.1.0-hb0f4dca_0.conda and b/tests/data/channels/channels/dummy_channel_1/linux-64/dummy-c-0.1.0-hb0f4dca_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_1/linux-64/dummy-d-0.1.0-hb0f4dca_0.conda b/tests/data/channels/channels/dummy_channel_1/linux-64/dummy-d-0.1.0-hb0f4dca_0.conda index a7c81fdb5..442a1c0cc 100644 Binary files a/tests/data/channels/channels/dummy_channel_1/linux-64/dummy-d-0.1.0-hb0f4dca_0.conda and b/tests/data/channels/channels/dummy_channel_1/linux-64/dummy-d-0.1.0-hb0f4dca_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_1/linux-64/dummy_e-0.1.0-hb0f4dca_0.conda b/tests/data/channels/channels/dummy_channel_1/linux-64/dummy_e-0.1.0-hb0f4dca_0.conda index d48612ef2..9be8f35ec 100644 Binary files a/tests/data/channels/channels/dummy_channel_1/linux-64/dummy_e-0.1.0-hb0f4dca_0.conda and b/tests/data/channels/channels/dummy_channel_1/linux-64/dummy_e-0.1.0-hb0f4dca_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_1/linux-64/repodata.json b/tests/data/channels/channels/dummy_channel_1/linux-64/repodata.json index 819327f5d..cf54aabe4 100644 --- a/tests/data/channels/channels/dummy_channel_1/linux-64/repodata.json +++ b/tests/data/channels/channels/dummy_channel_1/linux-64/repodata.json @@ -11,13 +11,13 @@ "depends": [ "dummy-c" ], - "md5": "b4372fef02827c469883d7895af3e56a", + "md5": "9e3022e5b3092c45015196ed3a679bca", "name": "dummy-a", "platform": "linux", - "sha256": "e84dd5c11f72f6714f81e6bafeadadfef021be09de27f9d065d51672174d873e", - "size": 1240, + "sha256": "602570943a8b4856bd4a6ad04c3ddea01d0a165cf5c0299fce45f7641ac2ac8e", + "size": 1242, "subdir": "linux-64", - "timestamp": 1730882682784, + "timestamp": 1730898132208, "version": "0.1.0" }, "dummy-b-0.1.0-hb0f4dca_0.conda": { @@ -25,13 +25,13 @@ "build": "hb0f4dca_0", "build_number": 0, "depends": [], - "md5": "b1ae5b6aa955304bf2dbe70dbba144a1", + "md5": "ba79f8081f0a1e87356c82a169c29b5b", "name": "dummy-b", "platform": "linux", - "sha256": "09c142a72559535bad3f101d46461838677c22df0cc2c9c0d0b897ea2dbcdac8", - "size": 1154, + "sha256": "daf38b547f42b8b581da0c50a54bee4d4a8bcbfc8c8790c8315e844e0f961f23", + "size": 1156, "subdir": "linux-64", - "timestamp": 1730882682784, + "timestamp": 1730898132208, "version": "0.1.0" }, "dummy-c-0.1.0-hb0f4dca_0.conda": { @@ -39,13 +39,13 @@ "build": "hb0f4dca_0", "build_number": 0, "depends": [], - "md5": "de1bcaea088baae533c9a0322123eca4", + "md5": "0ea2b9fed053c6618c82a8f54ecb9391", "name": "dummy-c", "platform": "linux", - "sha256": "247433e0bb1f79e82b7d48e4f933babc146358edcca69146714ae45347f111b9", + "sha256": "b9ccb4610c0e77694197a4c9a83c0e034c586d733367fef7167032826069b3b7", "size": 1157, "subdir": "linux-64", - "timestamp": 1730882682784, + "timestamp": 1730898132208, "version": "0.1.0" }, "dummy-d-0.1.0-hb0f4dca_0.conda": { @@ -55,13 +55,13 @@ "depends": [ "dummy-x" ], - "md5": "ac7ba71425f5a31c9d3e3b72a9586007", + "md5": "4e12f116517dad87732e54df1ec216a1", "name": "dummy-d", "platform": "linux", - "sha256": "d0e38029083dbff0a5bf434f4004c99ecbe040531bcd23e006c573eef0d14802", - "size": 1169, + "sha256": "1b2193383211a8b9eac6418a6d1ca84d92c88fe6c25d9227e2b3b573e0e87c6f", + "size": 1168, "subdir": "linux-64", - "timestamp": 1730882682784, + "timestamp": 1730898132208, "version": "0.1.0" }, "dummy_e-0.1.0-hb0f4dca_0.conda": { @@ -69,13 +69,13 @@ "build": "hb0f4dca_0", "build_number": 0, "depends": [], - "md5": "8ca3e5384e4c15e4aafd862cff970a83", + "md5": "44a05cf560c85eff8cd31d597eac9e04", "name": "dummy_e", "platform": "linux", - "sha256": "c40d1efec234270877a6dbbd8ccc7ee440020757869c02fd78d3a00346a127c3", - "size": 1156, + "sha256": "2dedb0328e6ccb55ebfc6e52ca09823713febf54c09aaf7117fb66ad1160ca0c", + "size": 1157, "subdir": "linux-64", - "timestamp": 1730882682784, + "timestamp": 1730898132208, "version": "0.1.0" } }, diff --git a/tests/data/channels/channels/dummy_channel_1/osx-64/dummy-a-0.1.0-h0dc7051_0.conda b/tests/data/channels/channels/dummy_channel_1/osx-64/dummy-a-0.1.0-h0dc7051_0.conda index bd5cbfa65..aff48a099 100644 Binary files a/tests/data/channels/channels/dummy_channel_1/osx-64/dummy-a-0.1.0-h0dc7051_0.conda and b/tests/data/channels/channels/dummy_channel_1/osx-64/dummy-a-0.1.0-h0dc7051_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_1/osx-64/dummy-b-0.1.0-h0dc7051_0.conda b/tests/data/channels/channels/dummy_channel_1/osx-64/dummy-b-0.1.0-h0dc7051_0.conda index 97ef5914c..40a182f9c 100644 Binary files a/tests/data/channels/channels/dummy_channel_1/osx-64/dummy-b-0.1.0-h0dc7051_0.conda and b/tests/data/channels/channels/dummy_channel_1/osx-64/dummy-b-0.1.0-h0dc7051_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_1/osx-64/dummy-c-0.1.0-h0dc7051_0.conda b/tests/data/channels/channels/dummy_channel_1/osx-64/dummy-c-0.1.0-h0dc7051_0.conda index 14808fa3d..3b44a6a4a 100644 Binary files a/tests/data/channels/channels/dummy_channel_1/osx-64/dummy-c-0.1.0-h0dc7051_0.conda and b/tests/data/channels/channels/dummy_channel_1/osx-64/dummy-c-0.1.0-h0dc7051_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_1/osx-64/dummy-d-0.1.0-h0dc7051_0.conda b/tests/data/channels/channels/dummy_channel_1/osx-64/dummy-d-0.1.0-h0dc7051_0.conda index 0106dd533..e3f3057d0 100644 Binary files a/tests/data/channels/channels/dummy_channel_1/osx-64/dummy-d-0.1.0-h0dc7051_0.conda and b/tests/data/channels/channels/dummy_channel_1/osx-64/dummy-d-0.1.0-h0dc7051_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_1/osx-64/dummy_e-0.1.0-h0dc7051_0.conda b/tests/data/channels/channels/dummy_channel_1/osx-64/dummy_e-0.1.0-h0dc7051_0.conda index 4777785fa..11b5e1c2c 100644 Binary files a/tests/data/channels/channels/dummy_channel_1/osx-64/dummy_e-0.1.0-h0dc7051_0.conda and b/tests/data/channels/channels/dummy_channel_1/osx-64/dummy_e-0.1.0-h0dc7051_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_1/osx-64/repodata.json b/tests/data/channels/channels/dummy_channel_1/osx-64/repodata.json index ab157f906..df4d6553a 100644 --- a/tests/data/channels/channels/dummy_channel_1/osx-64/repodata.json +++ b/tests/data/channels/channels/dummy_channel_1/osx-64/repodata.json @@ -11,13 +11,13 @@ "depends": [ "dummy-c" ], - "md5": "ef7c66b3ed929b54af6309e30b02599d", + "md5": "f0b93ffa2b933543088e14481cff1c6c", "name": "dummy-a", "platform": "osx", - "sha256": "a2693f090068ae4114e78ad3b44a764113fd86a7eabd34b2a2d8274671f63464", - "size": 1240, + "sha256": "ed8a1ae490eff14a210b1949a2e99cdc1a0bf8309f641f4ee5008520817fea06", + "size": 1241, "subdir": "osx-64", - "timestamp": 1730882682955, + "timestamp": 1730898132397, "version": "0.1.0" }, "dummy-b-0.1.0-h0dc7051_0.conda": { @@ -25,13 +25,13 @@ "build": "h0dc7051_0", "build_number": 0, "depends": [], - "md5": "fb5301251dd060bb635854db188a32f5", + "md5": "9796ad981f289e954eb810d5a4ecb660", "name": "dummy-b", "platform": "osx", - "sha256": "9c1775df7c7d89634eaabfddf22944ce3f40f4c17672db71d8e313d5191a03cf", - "size": 1149, + "sha256": "b072ad6c52e6edf7297c06ef68b278ee31f5e36d1caf058180b75588e6c7bc30", + "size": 1150, "subdir": "osx-64", - "timestamp": 1730882682955, + "timestamp": 1730898132397, "version": "0.1.0" }, "dummy-c-0.1.0-h0dc7051_0.conda": { @@ -39,13 +39,13 @@ "build": "h0dc7051_0", "build_number": 0, "depends": [], - "md5": "02977d3caf1cce991ff9a4c91ba5a700", + "md5": "f20b0c0f48a7ba5a9d3bfbba98c3c67f", "name": "dummy-c", "platform": "osx", - "sha256": "e5d6a31ba915c3f44fca36ad6d6c5ecd8df8e5c7098348250be34fed1736cef6", - "size": 1150, + "sha256": "59b2e33644e78ab7b517369a8e80b8d167cf3894020fd3b7195318fcf6083548", + "size": 1151, "subdir": "osx-64", - "timestamp": 1730882682955, + "timestamp": 1730898132397, "version": "0.1.0" }, "dummy-d-0.1.0-h0dc7051_0.conda": { @@ -55,13 +55,13 @@ "depends": [ "dummy-x" ], - "md5": "68e2d91c0a339f635ae07adfe98af364", + "md5": "102c1e0b4d9f43776717b5664ad86ea5", "name": "dummy-d", "platform": "osx", - "sha256": "3ac265659d73e18bca3fbc309009464fb9196f9aed7201c5c93f97f471d554b0", - "size": 1166, + "sha256": "40dc0982a8325bca00bd607837eebb4b5e89818c24c04922a12c8c1996e4977d", + "size": 1167, "subdir": "osx-64", - "timestamp": 1730882682955, + "timestamp": 1730898132396, "version": "0.1.0" }, "dummy_e-0.1.0-h0dc7051_0.conda": { @@ -69,13 +69,13 @@ "build": "h0dc7051_0", "build_number": 0, "depends": [], - "md5": "921119541e1cadd56fceb649dcc0c2c5", + "md5": "5cb25825488e2f51cb61eaea00784647", "name": "dummy_e", "platform": "osx", - "sha256": "11049456d245e02d8698773d40b2b2a47fc648e1a23240cbb6d1ef4a5ebbfafa", - "size": 1149, + "sha256": "aa67d4080afe626e2149a87fd12a192147327f76493302906a6f0d3c1dad4a2d", + "size": 1150, "subdir": "osx-64", - "timestamp": 1730882682955, + "timestamp": 1730898132397, "version": "0.1.0" } }, diff --git a/tests/data/channels/channels/dummy_channel_1/osx-arm64/dummy-a-0.1.0-h60d57d3_0.conda b/tests/data/channels/channels/dummy_channel_1/osx-arm64/dummy-a-0.1.0-h60d57d3_0.conda index 7516062d0..871ed462a 100644 Binary files a/tests/data/channels/channels/dummy_channel_1/osx-arm64/dummy-a-0.1.0-h60d57d3_0.conda and b/tests/data/channels/channels/dummy_channel_1/osx-arm64/dummy-a-0.1.0-h60d57d3_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_1/osx-arm64/dummy-b-0.1.0-h60d57d3_0.conda b/tests/data/channels/channels/dummy_channel_1/osx-arm64/dummy-b-0.1.0-h60d57d3_0.conda index 584ca58ca..d4ca876ed 100644 Binary files a/tests/data/channels/channels/dummy_channel_1/osx-arm64/dummy-b-0.1.0-h60d57d3_0.conda and b/tests/data/channels/channels/dummy_channel_1/osx-arm64/dummy-b-0.1.0-h60d57d3_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_1/osx-arm64/dummy-c-0.1.0-h60d57d3_0.conda b/tests/data/channels/channels/dummy_channel_1/osx-arm64/dummy-c-0.1.0-h60d57d3_0.conda index 0b4ce47d4..0cf0627ab 100644 Binary files a/tests/data/channels/channels/dummy_channel_1/osx-arm64/dummy-c-0.1.0-h60d57d3_0.conda and b/tests/data/channels/channels/dummy_channel_1/osx-arm64/dummy-c-0.1.0-h60d57d3_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_1/osx-arm64/dummy-d-0.1.0-h60d57d3_0.conda b/tests/data/channels/channels/dummy_channel_1/osx-arm64/dummy-d-0.1.0-h60d57d3_0.conda index db6a67e2f..5dcf0f6e6 100644 Binary files a/tests/data/channels/channels/dummy_channel_1/osx-arm64/dummy-d-0.1.0-h60d57d3_0.conda and b/tests/data/channels/channels/dummy_channel_1/osx-arm64/dummy-d-0.1.0-h60d57d3_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_1/osx-arm64/dummy_e-0.1.0-h60d57d3_0.conda b/tests/data/channels/channels/dummy_channel_1/osx-arm64/dummy_e-0.1.0-h60d57d3_0.conda index 409c8e141..b02eede3d 100644 Binary files a/tests/data/channels/channels/dummy_channel_1/osx-arm64/dummy_e-0.1.0-h60d57d3_0.conda and b/tests/data/channels/channels/dummy_channel_1/osx-arm64/dummy_e-0.1.0-h60d57d3_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_1/osx-arm64/repodata.json b/tests/data/channels/channels/dummy_channel_1/osx-arm64/repodata.json index 4ab127c69..0b8032a23 100644 --- a/tests/data/channels/channels/dummy_channel_1/osx-arm64/repodata.json +++ b/tests/data/channels/channels/dummy_channel_1/osx-arm64/repodata.json @@ -11,13 +11,13 @@ "depends": [ "dummy-c" ], - "md5": "b059a8930497742b4f1803f919517b52", + "md5": "838eb7e1214fae014d0a987859f859af", "name": "dummy-a", "platform": "osx", - "sha256": "d5ed2d936a173deb6d59e625f2b6f52f8ff7f2201b83225bb5c2c4bed4b920cd", - "size": 1237, + "sha256": "d76bd1ace7187f11ae12bb6bffe3006e43a36e7d29ceda51ce0116477a259bb2", + "size": 1240, "subdir": "osx-arm64", - "timestamp": 1730882682867, + "timestamp": 1730898132307, "version": "0.1.0" }, "dummy-b-0.1.0-h60d57d3_0.conda": { @@ -25,13 +25,13 @@ "build": "h60d57d3_0", "build_number": 0, "depends": [], - "md5": "459d9b61cbd83823b306417fdc5e44d3", + "md5": "ed8f85c5c7b99235b77f729c77da5e20", "name": "dummy-b", "platform": "osx", - "sha256": "cbc8b1af3cbc320113901f7d3b0ee31885ebaac4d6d8fa4b8226613742242942", - "size": 1154, + "sha256": "fc19ef430dce6fe01f1172e7a99f2d6d24279149ab1df370120da93bbb958f69", + "size": 1155, "subdir": "osx-arm64", - "timestamp": 1730882682867, + "timestamp": 1730898132307, "version": "0.1.0" }, "dummy-c-0.1.0-h60d57d3_0.conda": { @@ -39,13 +39,13 @@ "build": "h60d57d3_0", "build_number": 0, "depends": [], - "md5": "9ed09c9981c8f1dc5b2d3f3b9b445259", + "md5": "51422bf40c92483b988ae0329c5cabe7", "name": "dummy-c", "platform": "osx", - "sha256": "227d10c2558f17eea02d6301338f0dbb0b8561fce075518c3dde987251185fb3", - "size": 1155, + "sha256": "63847478ea06ea5c025e29a803dc43f48e05b701258cc060e8a570b4ab634018", + "size": 1154, "subdir": "osx-arm64", - "timestamp": 1730882682867, + "timestamp": 1730898132307, "version": "0.1.0" }, "dummy-d-0.1.0-h60d57d3_0.conda": { @@ -55,13 +55,13 @@ "depends": [ "dummy-x" ], - "md5": "ae6dbf7c3ab36afa5002ac4a584c14f1", + "md5": "9b5038e47b58cb8b848f4c653e032bb5", "name": "dummy-d", "platform": "osx", - "sha256": "609d73e95c912efd835af0e1730405e8707ba6492f56ad6e6d597a1d474e86b9", - "size": 1166, + "sha256": "2b16ec795114f502afa2395b123c63ed0ecbd56b021d1f0b396d072c87f627a2", + "size": 1168, "subdir": "osx-arm64", - "timestamp": 1730882682867, + "timestamp": 1730898132307, "version": "0.1.0" }, "dummy_e-0.1.0-h60d57d3_0.conda": { @@ -69,13 +69,13 @@ "build": "h60d57d3_0", "build_number": 0, "depends": [], - "md5": "99f43eb754564b03c0b3b0246cc78ef3", + "md5": "307c471891a2cef3b53523682b65711c", "name": "dummy_e", "platform": "osx", - "sha256": "63af46a043b6b02feb687553114561239ba46c6780bc5d07b79c5472b78bce92", - "size": 1153, + "sha256": "44886db4bf8db2b3223c4aa7bf8eb7b07748d86b13da4ebd644fc7cd1a444f61", + "size": 1155, "subdir": "osx-arm64", - "timestamp": 1730882682867, + "timestamp": 1730898132307, "version": "0.1.0" } }, diff --git a/tests/data/channels/channels/dummy_channel_1/win-64/dummy-a-0.1.0-h9490d1a_0.conda b/tests/data/channels/channels/dummy_channel_1/win-64/dummy-a-0.1.0-h9490d1a_0.conda index 1984ccb8e..dbf4b4cb0 100644 Binary files a/tests/data/channels/channels/dummy_channel_1/win-64/dummy-a-0.1.0-h9490d1a_0.conda and b/tests/data/channels/channels/dummy_channel_1/win-64/dummy-a-0.1.0-h9490d1a_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_1/win-64/dummy-b-0.1.0-h9490d1a_0.conda b/tests/data/channels/channels/dummy_channel_1/win-64/dummy-b-0.1.0-h9490d1a_0.conda index 195691abd..82eedb084 100644 Binary files a/tests/data/channels/channels/dummy_channel_1/win-64/dummy-b-0.1.0-h9490d1a_0.conda and b/tests/data/channels/channels/dummy_channel_1/win-64/dummy-b-0.1.0-h9490d1a_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_1/win-64/dummy-c-0.1.0-h9490d1a_0.conda b/tests/data/channels/channels/dummy_channel_1/win-64/dummy-c-0.1.0-h9490d1a_0.conda index fb48758c6..890e6cbb3 100644 Binary files a/tests/data/channels/channels/dummy_channel_1/win-64/dummy-c-0.1.0-h9490d1a_0.conda and b/tests/data/channels/channels/dummy_channel_1/win-64/dummy-c-0.1.0-h9490d1a_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_1/win-64/dummy-d-0.1.0-h9490d1a_0.conda b/tests/data/channels/channels/dummy_channel_1/win-64/dummy-d-0.1.0-h9490d1a_0.conda index 408aa1ad1..2a2f72eca 100644 Binary files a/tests/data/channels/channels/dummy_channel_1/win-64/dummy-d-0.1.0-h9490d1a_0.conda and b/tests/data/channels/channels/dummy_channel_1/win-64/dummy-d-0.1.0-h9490d1a_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_1/win-64/dummy_e-0.1.0-h9490d1a_0.conda b/tests/data/channels/channels/dummy_channel_1/win-64/dummy_e-0.1.0-h9490d1a_0.conda index 6c93ed3bc..cbdb346a5 100644 Binary files a/tests/data/channels/channels/dummy_channel_1/win-64/dummy_e-0.1.0-h9490d1a_0.conda and b/tests/data/channels/channels/dummy_channel_1/win-64/dummy_e-0.1.0-h9490d1a_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_1/win-64/repodata.json b/tests/data/channels/channels/dummy_channel_1/win-64/repodata.json index e0179cfb3..389b9f52f 100644 --- a/tests/data/channels/channels/dummy_channel_1/win-64/repodata.json +++ b/tests/data/channels/channels/dummy_channel_1/win-64/repodata.json @@ -11,13 +11,13 @@ "depends": [ "dummy-c" ], - "md5": "63aabe516762edc60fd2125a48804608", + "md5": "3f444debe78692289e67811c2316fc6a", "name": "dummy-a", "platform": "win", - "sha256": "f5e370e17eea2f30c2712d7fd7182cf6d32584a4ed7e6ea23ab59367824c40a4", + "sha256": "8222d7e5f9b215559e8ac911b064c4d87dceaab4d9054308eaa33276488e6e27", "size": 1246, "subdir": "win-64", - "timestamp": 1730882682691, + "timestamp": 1730898132124, "version": "0.1.0" }, "dummy-b-0.1.0-h9490d1a_0.conda": { @@ -25,13 +25,13 @@ "build": "h9490d1a_0", "build_number": 0, "depends": [], - "md5": "7108066567485324ad6878ffcfe6322f", + "md5": "3b5dd75611f655ad1aabe21a846ea3ac", "name": "dummy-b", "platform": "win", - "sha256": "8a73a081adf6c4ddb6d66f62b7be8be83726ff287168e505f5dabf6e598212cb", - "size": 1159, + "sha256": "08c1afaee9577ab6aeabf4c9918719b77ad890d63082e55f7edddd411c06b009", + "size": 1157, "subdir": "win-64", - "timestamp": 1730882682691, + "timestamp": 1730898132124, "version": "0.1.0" }, "dummy-c-0.1.0-h9490d1a_0.conda": { @@ -39,13 +39,13 @@ "build": "h9490d1a_0", "build_number": 0, "depends": [], - "md5": "2095877190911b58cfbc5403e4c567a3", + "md5": "088b5e2e04b51f3650653d524fa4c8a5", "name": "dummy-c", "platform": "win", - "sha256": "078d295c689ff3b4fa7dac6beef706d7979f27725fb17c5a173a8ee755b778e1", + "sha256": "00e1b007fab059653a7bb953de1b8745ed1cb1811953d742290504be6e888774", "size": 1157, "subdir": "win-64", - "timestamp": 1730882682691, + "timestamp": 1730898132124, "version": "0.1.0" }, "dummy-d-0.1.0-h9490d1a_0.conda": { @@ -55,13 +55,13 @@ "depends": [ "dummy-x" ], - "md5": "5be8b235959148e6027431e708a9140b", + "md5": "1663e50d6bb75b95808c877bd79628ef", "name": "dummy-d", "platform": "win", - "sha256": "f336584618f41a561e6004c1e64bd3345679a838c4a011df1bbbb1d8baae143f", - "size": 1176, + "sha256": "00d4b0579b61eff982db49f3227f68dd6b25fc1bdaf7e4736b3c876e4c06550c", + "size": 1173, "subdir": "win-64", - "timestamp": 1730882682691, + "timestamp": 1730898132124, "version": "0.1.0" }, "dummy_e-0.1.0-h9490d1a_0.conda": { @@ -69,13 +69,13 @@ "build": "h9490d1a_0", "build_number": 0, "depends": [], - "md5": "3e7f9cb688e7840e0bc4816ee16a01ad", + "md5": "4814b700ab73c8ca0cda30de842d4770", "name": "dummy_e", "platform": "win", - "sha256": "b9359b192cd8e35a302e69f640fa49db67395f0a52d3414a436ef3025dc830ce", + "sha256": "2f3a1cc01daecfc007d80858805e1a79b89adcc21c91e9a4b8ae125a1e658891", "size": 1158, "subdir": "win-64", - "timestamp": 1730882682691, + "timestamp": 1730898132124, "version": "0.1.0" } }, diff --git a/tests/data/channels/channels/dummy_channel_2/linux-64/dummy-b-0.1.0-hb0f4dca_0.conda b/tests/data/channels/channels/dummy_channel_2/linux-64/dummy-b-0.1.0-hb0f4dca_0.conda index 22a04d058..b8fcd674f 100644 Binary files a/tests/data/channels/channels/dummy_channel_2/linux-64/dummy-b-0.1.0-hb0f4dca_0.conda and b/tests/data/channels/channels/dummy_channel_2/linux-64/dummy-b-0.1.0-hb0f4dca_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_2/linux-64/dummy-x-0.1.0-hb0f4dca_0.conda b/tests/data/channels/channels/dummy_channel_2/linux-64/dummy-x-0.1.0-hb0f4dca_0.conda index e60abc044..22a36e7c6 100644 Binary files a/tests/data/channels/channels/dummy_channel_2/linux-64/dummy-x-0.1.0-hb0f4dca_0.conda and b/tests/data/channels/channels/dummy_channel_2/linux-64/dummy-x-0.1.0-hb0f4dca_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_2/linux-64/repodata.json b/tests/data/channels/channels/dummy_channel_2/linux-64/repodata.json index 9de50ee45..f34b7c9d8 100644 --- a/tests/data/channels/channels/dummy_channel_2/linux-64/repodata.json +++ b/tests/data/channels/channels/dummy_channel_2/linux-64/repodata.json @@ -9,13 +9,13 @@ "build": "hb0f4dca_0", "build_number": 0, "depends": [], - "md5": "511324c0c6369a876ece2b53c737fbf7", + "md5": "5999cc251f2427c4020179f874a44ec6", "name": "dummy-b", "platform": "linux", - "sha256": "811c3ecaa81f3680d5deb18e71e923249485d18247f64c22473e69da7a1af3ae", - "size": 1158, + "sha256": "5973cc8ff460a97fcbbd31cecd02d41f4dfbf191e170176351a65f8549219b9e", + "size": 1157, "subdir": "linux-64", - "timestamp": 1730882683088, + "timestamp": 1730898132532, "version": "0.1.0" }, "dummy-x-0.1.0-hb0f4dca_0.conda": { @@ -23,13 +23,13 @@ "build": "hb0f4dca_0", "build_number": 0, "depends": [], - "md5": "1a00531fb43d3ebac5269ad31d509d85", + "md5": "83e6f2e970e6a485bbdde0ba355ad9cc", "name": "dummy-x", "platform": "linux", - "sha256": "1fcfc6126d2f3d4eacf87bd7e119a86bed85fbe9d6a7f9a3189238210668f8d4", + "sha256": "6a2ba209a1736f9bbc91e4770fd1dd9a6f448dc1be3504f2b934c33c284bc0fe", "size": 1156, "subdir": "linux-64", - "timestamp": 1730882683088, + "timestamp": 1730898132532, "version": "0.1.0" } }, diff --git a/tests/data/channels/channels/dummy_channel_2/osx-64/dummy-b-0.1.0-h0dc7051_0.conda b/tests/data/channels/channels/dummy_channel_2/osx-64/dummy-b-0.1.0-h0dc7051_0.conda index 7bce03735..441e2b579 100644 Binary files a/tests/data/channels/channels/dummy_channel_2/osx-64/dummy-b-0.1.0-h0dc7051_0.conda and b/tests/data/channels/channels/dummy_channel_2/osx-64/dummy-b-0.1.0-h0dc7051_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_2/osx-64/dummy-x-0.1.0-h0dc7051_0.conda b/tests/data/channels/channels/dummy_channel_2/osx-64/dummy-x-0.1.0-h0dc7051_0.conda index 61584cd5a..bfcff63eb 100644 Binary files a/tests/data/channels/channels/dummy_channel_2/osx-64/dummy-x-0.1.0-h0dc7051_0.conda and b/tests/data/channels/channels/dummy_channel_2/osx-64/dummy-x-0.1.0-h0dc7051_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_2/osx-64/repodata.json b/tests/data/channels/channels/dummy_channel_2/osx-64/repodata.json index ed4e00617..3a21f0664 100644 --- a/tests/data/channels/channels/dummy_channel_2/osx-64/repodata.json +++ b/tests/data/channels/channels/dummy_channel_2/osx-64/repodata.json @@ -9,13 +9,13 @@ "build": "h0dc7051_0", "build_number": 0, "depends": [], - "md5": "5128f8b1901245f0a3e9948982fa553c", + "md5": "017d34f4de6894ab134b67aeaf314b11", "name": "dummy-b", "platform": "osx", - "sha256": "80477e99f4a5762c156b326cfeeead05066f1a2e04156bf2df0e92c459dfed75", - "size": 1151, + "sha256": "c7a6c8596c39218a0b11fd40ef8ae1b5ab63995b94ec3644dcca6fb8ffefe763", + "size": 1150, "subdir": "osx-64", - "timestamp": 1730882683186, + "timestamp": 1730898132631, "version": "0.1.0" }, "dummy-x-0.1.0-h0dc7051_0.conda": { @@ -23,13 +23,13 @@ "build": "h0dc7051_0", "build_number": 0, "depends": [], - "md5": "32a4a13e3b35b8296d29ba3afadae3ad", + "md5": "54adbbf15ee081c9d6728556263b5f0b", "name": "dummy-x", "platform": "osx", - "sha256": "5467e5c8e3d01c694cf60d9a75fcd3f073185d684d2a528464b48c906caee3e4", + "sha256": "75454ecb66f5921652e704ae4681862f37e379e8c8eb09fb4ad8cd78069464a2", "size": 1149, "subdir": "osx-64", - "timestamp": 1730882683186, + "timestamp": 1730898132631, "version": "0.1.0" } }, diff --git a/tests/data/channels/channels/dummy_channel_2/osx-arm64/dummy-b-0.1.0-h60d57d3_0.conda b/tests/data/channels/channels/dummy_channel_2/osx-arm64/dummy-b-0.1.0-h60d57d3_0.conda index 88a938367..d06291521 100644 Binary files a/tests/data/channels/channels/dummy_channel_2/osx-arm64/dummy-b-0.1.0-h60d57d3_0.conda and b/tests/data/channels/channels/dummy_channel_2/osx-arm64/dummy-b-0.1.0-h60d57d3_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_2/osx-arm64/dummy-x-0.1.0-h60d57d3_0.conda b/tests/data/channels/channels/dummy_channel_2/osx-arm64/dummy-x-0.1.0-h60d57d3_0.conda index 344ac8df7..0376a2323 100644 Binary files a/tests/data/channels/channels/dummy_channel_2/osx-arm64/dummy-x-0.1.0-h60d57d3_0.conda and b/tests/data/channels/channels/dummy_channel_2/osx-arm64/dummy-x-0.1.0-h60d57d3_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_2/osx-arm64/repodata.json b/tests/data/channels/channels/dummy_channel_2/osx-arm64/repodata.json index 6259b4353..c07fc9cf5 100644 --- a/tests/data/channels/channels/dummy_channel_2/osx-arm64/repodata.json +++ b/tests/data/channels/channels/dummy_channel_2/osx-arm64/repodata.json @@ -9,13 +9,13 @@ "build": "h60d57d3_0", "build_number": 0, "depends": [], - "md5": "a22df54a7df3caafeffe37c4bd4a1cde", + "md5": "0eae7022f8c4ee6b2f2e045e084706f7", "name": "dummy-b", "platform": "osx", - "sha256": "eb425909fd234a2390810f3062fdadca76d63bf78a059402e06a7bf27e4599e0", - "size": 1156, + "sha256": "4dbd1d9589cfb97dc778f766fbdeb6a516965ed1b24692fd10b25b3596378af4", + "size": 1155, "subdir": "osx-arm64", - "timestamp": 1730882683138, + "timestamp": 1730898132583, "version": "0.1.0" }, "dummy-x-0.1.0-h60d57d3_0.conda": { @@ -23,13 +23,13 @@ "build": "h60d57d3_0", "build_number": 0, "depends": [], - "md5": "6e74dc81a43eb78d0e03a8849eb66c1d", + "md5": "c629b99c51eb9577dc9716412f32eaf4", "name": "dummy-x", "platform": "osx", - "sha256": "ace0648a470996b0fee62ec106128fdbc6a4d07c2ae675302867ce333352e1bf", + "sha256": "e23fc4f1e611d0924d31d53bb48e1e16bba07936a821ce8e67fb3bb7cc7a8f0a", "size": 1154, "subdir": "osx-arm64", - "timestamp": 1730882683138, + "timestamp": 1730898132583, "version": "0.1.0" } }, diff --git a/tests/data/channels/channels/dummy_channel_2/win-64/dummy-b-0.1.0-h9490d1a_0.conda b/tests/data/channels/channels/dummy_channel_2/win-64/dummy-b-0.1.0-h9490d1a_0.conda index 3030158f1..72d2c7a2a 100644 Binary files a/tests/data/channels/channels/dummy_channel_2/win-64/dummy-b-0.1.0-h9490d1a_0.conda and b/tests/data/channels/channels/dummy_channel_2/win-64/dummy-b-0.1.0-h9490d1a_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_2/win-64/dummy-x-0.1.0-h9490d1a_0.conda b/tests/data/channels/channels/dummy_channel_2/win-64/dummy-x-0.1.0-h9490d1a_0.conda index 22c808d7b..f8e35a523 100644 Binary files a/tests/data/channels/channels/dummy_channel_2/win-64/dummy-x-0.1.0-h9490d1a_0.conda and b/tests/data/channels/channels/dummy_channel_2/win-64/dummy-x-0.1.0-h9490d1a_0.conda differ diff --git a/tests/data/channels/channels/dummy_channel_2/win-64/repodata.json b/tests/data/channels/channels/dummy_channel_2/win-64/repodata.json index e5bcccf89..18e973373 100644 --- a/tests/data/channels/channels/dummy_channel_2/win-64/repodata.json +++ b/tests/data/channels/channels/dummy_channel_2/win-64/repodata.json @@ -9,13 +9,13 @@ "build": "h9490d1a_0", "build_number": 0, "depends": [], - "md5": "cfc1c9a6069d8d02fd4303edb8279f72", + "md5": "d7bc95b275a95933afdcfc8b43485ea6", "name": "dummy-b", "platform": "win", - "sha256": "96534008d2a1ea10cb44732041fa675474492abc719f243475925250107378b1", + "sha256": "8665d5f04c8149ab3c8b0860a183c2193de796fdfbf536be6b168fa9e36f3604", "size": 1157, "subdir": "win-64", - "timestamp": 1730882683040, + "timestamp": 1730898132483, "version": "0.1.0" }, "dummy-x-0.1.0-h9490d1a_0.conda": { @@ -23,13 +23,13 @@ "build": "h9490d1a_0", "build_number": 0, "depends": [], - "md5": "f89e7197ba481dcb69444abd36eb4e38", + "md5": "5b55c726ced58cc0b00c24b5e0dceb22", "name": "dummy-x", "platform": "win", - "sha256": "4eba0aefec42272478f98f2a0490d3cc4fe96c2d899b82326e11e7c6aaae39b8", - "size": 1157, + "sha256": "a59d0e871826438b2d8abbdec0ec4429b40442b58e966c3dd21656ded2d87f4d", + "size": 1159, "subdir": "win-64", - "timestamp": 1730882683040, + "timestamp": 1730898132483, "version": "0.1.0" } }, diff --git a/tests/data/channels/channels/global_update_channel_1/linux-64/package-0.1.0-hb0f4dca_0.conda b/tests/data/channels/channels/global_update_channel_1/linux-64/package-0.1.0-hb0f4dca_0.conda deleted file mode 100644 index 6759ad1e5..000000000 Binary files a/tests/data/channels/channels/global_update_channel_1/linux-64/package-0.1.0-hb0f4dca_0.conda and /dev/null differ diff --git a/tests/data/channels/channels/global_update_channel_1/linux-64/package-0.2.0-hb0f4dca_0.conda b/tests/data/channels/channels/global_update_channel_1/linux-64/package-0.2.0-hb0f4dca_0.conda deleted file mode 100644 index c9db8f7e9..000000000 Binary files a/tests/data/channels/channels/global_update_channel_1/linux-64/package-0.2.0-hb0f4dca_0.conda and /dev/null differ diff --git a/tests/data/channels/channels/global_update_channel_1/linux-64/package2-0.1.0-hb0f4dca_0.conda b/tests/data/channels/channels/global_update_channel_1/linux-64/package2-0.1.0-hb0f4dca_0.conda deleted file mode 100644 index 02634e37b..000000000 Binary files a/tests/data/channels/channels/global_update_channel_1/linux-64/package2-0.1.0-hb0f4dca_0.conda and /dev/null differ diff --git a/tests/data/channels/channels/global_update_channel_1/linux-64/package2-0.2.0-hb0f4dca_0.conda b/tests/data/channels/channels/global_update_channel_1/linux-64/package2-0.2.0-hb0f4dca_0.conda deleted file mode 100644 index b6b583d19..000000000 Binary files a/tests/data/channels/channels/global_update_channel_1/linux-64/package2-0.2.0-hb0f4dca_0.conda and /dev/null differ diff --git a/tests/data/channels/channels/global_update_channel_1/osx-64/package-0.1.0-h0dc7051_0.conda b/tests/data/channels/channels/global_update_channel_1/osx-64/package-0.1.0-h0dc7051_0.conda deleted file mode 100644 index f9b296ba8..000000000 Binary files a/tests/data/channels/channels/global_update_channel_1/osx-64/package-0.1.0-h0dc7051_0.conda and /dev/null differ diff --git a/tests/data/channels/channels/global_update_channel_1/osx-64/package-0.2.0-h0dc7051_0.conda b/tests/data/channels/channels/global_update_channel_1/osx-64/package-0.2.0-h0dc7051_0.conda deleted file mode 100644 index 6d76bfdf2..000000000 Binary files a/tests/data/channels/channels/global_update_channel_1/osx-64/package-0.2.0-h0dc7051_0.conda and /dev/null differ diff --git a/tests/data/channels/channels/global_update_channel_1/osx-64/package2-0.1.0-h0dc7051_0.conda b/tests/data/channels/channels/global_update_channel_1/osx-64/package2-0.1.0-h0dc7051_0.conda deleted file mode 100644 index ab79a17d1..000000000 Binary files a/tests/data/channels/channels/global_update_channel_1/osx-64/package2-0.1.0-h0dc7051_0.conda and /dev/null differ diff --git a/tests/data/channels/channels/global_update_channel_1/osx-64/package2-0.2.0-h0dc7051_0.conda b/tests/data/channels/channels/global_update_channel_1/osx-64/package2-0.2.0-h0dc7051_0.conda deleted file mode 100644 index c8b9f5604..000000000 Binary files a/tests/data/channels/channels/global_update_channel_1/osx-64/package2-0.2.0-h0dc7051_0.conda and /dev/null differ diff --git a/tests/data/channels/channels/global_update_channel_1/osx-arm64/package-0.1.0-h60d57d3_0.conda b/tests/data/channels/channels/global_update_channel_1/osx-arm64/package-0.1.0-h60d57d3_0.conda deleted file mode 100644 index 53d5f0938..000000000 Binary files a/tests/data/channels/channels/global_update_channel_1/osx-arm64/package-0.1.0-h60d57d3_0.conda and /dev/null differ diff --git a/tests/data/channels/channels/global_update_channel_1/osx-arm64/package-0.2.0-h60d57d3_0.conda b/tests/data/channels/channels/global_update_channel_1/osx-arm64/package-0.2.0-h60d57d3_0.conda deleted file mode 100644 index b47718e59..000000000 Binary files a/tests/data/channels/channels/global_update_channel_1/osx-arm64/package-0.2.0-h60d57d3_0.conda and /dev/null differ diff --git a/tests/data/channels/channels/global_update_channel_1/osx-arm64/package2-0.1.0-h60d57d3_0.conda b/tests/data/channels/channels/global_update_channel_1/osx-arm64/package2-0.1.0-h60d57d3_0.conda deleted file mode 100644 index 59e218fad..000000000 Binary files a/tests/data/channels/channels/global_update_channel_1/osx-arm64/package2-0.1.0-h60d57d3_0.conda and /dev/null differ diff --git a/tests/data/channels/channels/global_update_channel_1/osx-arm64/package2-0.2.0-h60d57d3_0.conda b/tests/data/channels/channels/global_update_channel_1/osx-arm64/package2-0.2.0-h60d57d3_0.conda deleted file mode 100644 index fdd726c7e..000000000 Binary files a/tests/data/channels/channels/global_update_channel_1/osx-arm64/package2-0.2.0-h60d57d3_0.conda and /dev/null differ diff --git a/tests/data/channels/channels/global_update_channel_1/win-64/package-0.1.0-h9490d1a_0.conda b/tests/data/channels/channels/global_update_channel_1/win-64/package-0.1.0-h9490d1a_0.conda deleted file mode 100644 index cfeff2940..000000000 Binary files a/tests/data/channels/channels/global_update_channel_1/win-64/package-0.1.0-h9490d1a_0.conda and /dev/null differ diff --git a/tests/data/channels/channels/global_update_channel_1/win-64/package-0.2.0-h9490d1a_0.conda b/tests/data/channels/channels/global_update_channel_1/win-64/package-0.2.0-h9490d1a_0.conda deleted file mode 100644 index f37d96b0b..000000000 Binary files a/tests/data/channels/channels/global_update_channel_1/win-64/package-0.2.0-h9490d1a_0.conda and /dev/null differ diff --git a/tests/data/channels/channels/global_update_channel_1/win-64/package2-0.1.0-h9490d1a_0.conda b/tests/data/channels/channels/global_update_channel_1/win-64/package2-0.1.0-h9490d1a_0.conda deleted file mode 100644 index b7df01936..000000000 Binary files a/tests/data/channels/channels/global_update_channel_1/win-64/package2-0.1.0-h9490d1a_0.conda and /dev/null differ diff --git a/tests/data/channels/channels/global_update_channel_1/win-64/package2-0.2.0-h9490d1a_0.conda b/tests/data/channels/channels/global_update_channel_1/win-64/package2-0.2.0-h9490d1a_0.conda deleted file mode 100644 index bb8266e05..000000000 Binary files a/tests/data/channels/channels/global_update_channel_1/win-64/package2-0.2.0-h9490d1a_0.conda and /dev/null differ diff --git a/tests/data/channels/channels/multiple_versions_channel_1/linux-64/package-0.1.0-hb0f4dca_0.conda b/tests/data/channels/channels/multiple_versions_channel_1/linux-64/package-0.1.0-hb0f4dca_0.conda new file mode 100644 index 000000000..943a782c4 Binary files /dev/null and b/tests/data/channels/channels/multiple_versions_channel_1/linux-64/package-0.1.0-hb0f4dca_0.conda differ diff --git a/tests/data/channels/channels/multiple_versions_channel_1/linux-64/package-0.2.0-hb0f4dca_0.conda b/tests/data/channels/channels/multiple_versions_channel_1/linux-64/package-0.2.0-hb0f4dca_0.conda new file mode 100644 index 000000000..7ba5a21a6 Binary files /dev/null and b/tests/data/channels/channels/multiple_versions_channel_1/linux-64/package-0.2.0-hb0f4dca_0.conda differ diff --git a/tests/data/channels/channels/multiple_versions_channel_1/linux-64/package2-0.1.0-hb0f4dca_0.conda b/tests/data/channels/channels/multiple_versions_channel_1/linux-64/package2-0.1.0-hb0f4dca_0.conda new file mode 100644 index 000000000..327296c5a Binary files /dev/null and b/tests/data/channels/channels/multiple_versions_channel_1/linux-64/package2-0.1.0-hb0f4dca_0.conda differ diff --git a/tests/data/channels/channels/multiple_versions_channel_1/linux-64/package2-0.2.0-hb0f4dca_0.conda b/tests/data/channels/channels/multiple_versions_channel_1/linux-64/package2-0.2.0-hb0f4dca_0.conda new file mode 100644 index 000000000..bfe47f296 Binary files /dev/null and b/tests/data/channels/channels/multiple_versions_channel_1/linux-64/package2-0.2.0-hb0f4dca_0.conda differ diff --git a/tests/data/channels/channels/global_update_channel_1/linux-64/repodata.json b/tests/data/channels/channels/multiple_versions_channel_1/linux-64/repodata.json similarity index 62% rename from tests/data/channels/channels/global_update_channel_1/linux-64/repodata.json rename to tests/data/channels/channels/multiple_versions_channel_1/linux-64/repodata.json index 87445f83e..6caed42de 100644 --- a/tests/data/channels/channels/global_update_channel_1/linux-64/repodata.json +++ b/tests/data/channels/channels/multiple_versions_channel_1/linux-64/repodata.json @@ -9,13 +9,13 @@ "build": "hb0f4dca_0", "build_number": 0, "depends": [], - "md5": "5e79bbc5cd9db61d680084ca3573fa20", + "md5": "a2f28b306e1ad1196ca6dae59e96a18d", "name": "package", "platform": "linux", - "sha256": "24e19b4d25b83fc4f7b381747ff11e52a0da0c04dfcf36ce0ba1fd78e1282f35", + "sha256": "cc382444ece609943e5d4ec18abf5aeabfc364ac59c1eed30c89524db92c8805", "size": 1237, "subdir": "linux-64", - "timestamp": 1730882683283, + "timestamp": 1730898132739, "version": "0.1.0" }, "package-0.2.0-hb0f4dca_0.conda": { @@ -23,13 +23,13 @@ "build": "hb0f4dca_0", "build_number": 0, "depends": [], - "md5": "d8aea0002ae5c51d17488ecf0bfa2d6c", + "md5": "868a498e8f36354c28d91005752797d5", "name": "package", "platform": "linux", - "sha256": "6858edcfc63a66585518e37d1e7c5476132f71cbf7c0561461a9264f448e1981", - "size": 1240, + "sha256": "74fc123c3902ba53e570ed9172a591d7025cec9995193500bd4aee672a565da3", + "size": 1239, "subdir": "linux-64", - "timestamp": 1730882683476, + "timestamp": 1730898132949, "version": "0.2.0" }, "package2-0.1.0-hb0f4dca_0.conda": { @@ -37,13 +37,13 @@ "build": "hb0f4dca_0", "build_number": 0, "depends": [], - "md5": "f256d49e273aa9990bed9120fa4db12e", + "md5": "e764e06f7d440c3358f10a4e15f8bda5", "name": "package2", "platform": "linux", - "sha256": "d211b3a80dc2adc2e279b1ad31b30a7d82a27a82cabdf4dbfc9d393d7858be37", - "size": 1158, + "sha256": "f0826cb7a6f56741d320dbfd783d28c7ea63b860ac4abcaa73373c0e408fe9d3", + "size": 1161, "subdir": "linux-64", - "timestamp": 1730882683283, + "timestamp": 1730898132739, "version": "0.1.0" }, "package2-0.2.0-hb0f4dca_0.conda": { @@ -51,13 +51,13 @@ "build": "hb0f4dca_0", "build_number": 0, "depends": [], - "md5": "d8dd33fda32f051fe64990f89e3e1241", + "md5": "2341a61eac6973353c46a795a292b8f9", "name": "package2", "platform": "linux", - "sha256": "b64af15a2d0139b98d8865f8b9eab74f567836260f02c85ebf7cef6174c4fad5", - "size": 1159, + "sha256": "3269562fee84b6c1b5af97bfb31d0db6c128a7253f16e60895bd4117408ec58c", + "size": 1158, "subdir": "linux-64", - "timestamp": 1730882683476, + "timestamp": 1730898132949, "version": "0.2.0" } }, diff --git a/tests/data/channels/channels/global_update_channel_1/noarch/repodata.json b/tests/data/channels/channels/multiple_versions_channel_1/noarch/repodata.json similarity index 100% rename from tests/data/channels/channels/global_update_channel_1/noarch/repodata.json rename to tests/data/channels/channels/multiple_versions_channel_1/noarch/repodata.json diff --git a/tests/data/channels/channels/multiple_versions_channel_1/osx-64/package-0.1.0-h0dc7051_0.conda b/tests/data/channels/channels/multiple_versions_channel_1/osx-64/package-0.1.0-h0dc7051_0.conda new file mode 100644 index 000000000..e90cbc1db Binary files /dev/null and b/tests/data/channels/channels/multiple_versions_channel_1/osx-64/package-0.1.0-h0dc7051_0.conda differ diff --git a/tests/data/channels/channels/multiple_versions_channel_1/osx-64/package-0.2.0-h0dc7051_0.conda b/tests/data/channels/channels/multiple_versions_channel_1/osx-64/package-0.2.0-h0dc7051_0.conda new file mode 100644 index 000000000..89853bb29 Binary files /dev/null and b/tests/data/channels/channels/multiple_versions_channel_1/osx-64/package-0.2.0-h0dc7051_0.conda differ diff --git a/tests/data/channels/channels/multiple_versions_channel_1/osx-64/package2-0.1.0-h0dc7051_0.conda b/tests/data/channels/channels/multiple_versions_channel_1/osx-64/package2-0.1.0-h0dc7051_0.conda new file mode 100644 index 000000000..10630b324 Binary files /dev/null and b/tests/data/channels/channels/multiple_versions_channel_1/osx-64/package2-0.1.0-h0dc7051_0.conda differ diff --git a/tests/data/channels/channels/multiple_versions_channel_1/osx-64/package2-0.2.0-h0dc7051_0.conda b/tests/data/channels/channels/multiple_versions_channel_1/osx-64/package2-0.2.0-h0dc7051_0.conda new file mode 100644 index 000000000..2957953e7 Binary files /dev/null and b/tests/data/channels/channels/multiple_versions_channel_1/osx-64/package2-0.2.0-h0dc7051_0.conda differ diff --git a/tests/data/channels/channels/global_update_channel_1/osx-64/repodata.json b/tests/data/channels/channels/multiple_versions_channel_1/osx-64/repodata.json similarity index 62% rename from tests/data/channels/channels/global_update_channel_1/osx-64/repodata.json rename to tests/data/channels/channels/multiple_versions_channel_1/osx-64/repodata.json index 6bb7166e0..608b2a966 100644 --- a/tests/data/channels/channels/global_update_channel_1/osx-64/repodata.json +++ b/tests/data/channels/channels/multiple_versions_channel_1/osx-64/repodata.json @@ -9,13 +9,13 @@ "build": "h0dc7051_0", "build_number": 0, "depends": [], - "md5": "e5b4b0f0147cf78038010b9b0515f635", + "md5": "4e840b763722d23947a58cb583598112", "name": "package", "platform": "osx", - "sha256": "36cde80b2c7a12f41e7cae52d5af2b172e59db3c41ee7e1006a22a508671a66e", - "size": 1230, + "sha256": "6879c4592a030f28f6d971b2f22668179ce4f795205b44a29b0338ab612f7a51", + "size": 1231, "subdir": "osx-64", - "timestamp": 1730882683379, + "timestamp": 1730898132845, "version": "0.1.0" }, "package-0.2.0-h0dc7051_0.conda": { @@ -23,13 +23,13 @@ "build": "h0dc7051_0", "build_number": 0, "depends": [], - "md5": "19235bf7d4d135339b0f60b29768d4bc", + "md5": "8cc0b6cec2e59931ddadca42240ff7f0", "name": "package", "platform": "osx", - "sha256": "9b8792daf9d9b8389286f06a64eac282f3232e801a16e69cd6f87c720432526c", - "size": 1231, + "sha256": "6dab29d04cf60699d6e3b63247dbbb76212f707f79d4ec7660d42553684a02fe", + "size": 1230, "subdir": "osx-64", - "timestamp": 1730882683576, + "timestamp": 1730898133054, "version": "0.2.0" }, "package2-0.1.0-h0dc7051_0.conda": { @@ -37,13 +37,13 @@ "build": "h0dc7051_0", "build_number": 0, "depends": [], - "md5": "28bfb8cea4844c74225df39605518dde", + "md5": "55569971ef4023d3d8bc4406e07dfd50", "name": "package2", "platform": "osx", - "sha256": "fb3555fb7f569b1c33d0be4a1f5a5ac34b36622e19062f07091354072e293533", - "size": 1158, + "sha256": "25f70b1283ccdc00cd052d0b392d2fc11753574073eb00140f5064b1c587eccd", + "size": 1159, "subdir": "osx-64", - "timestamp": 1730882683379, + "timestamp": 1730898132846, "version": "0.1.0" }, "package2-0.2.0-h0dc7051_0.conda": { @@ -51,13 +51,13 @@ "build": "h0dc7051_0", "build_number": 0, "depends": [], - "md5": "ebe04c93f9d2523aa322815945bc6e01", + "md5": "fbbb2080c0cf031504886eaf4e57c6a4", "name": "package2", "platform": "osx", - "sha256": "75c4a64dfcaa2dd4725ad92fb47dac5f8dba44f21c3f768b1a5d67382e492246", - "size": 1157, + "sha256": "7b0844fb3358077e0929c5c3da1d11c68514b8a29bba7ee766073f600be03a76", + "size": 1158, "subdir": "osx-64", - "timestamp": 1730882683576, + "timestamp": 1730898133054, "version": "0.2.0" } }, diff --git a/tests/data/channels/channels/multiple_versions_channel_1/osx-arm64/package-0.1.0-h60d57d3_0.conda b/tests/data/channels/channels/multiple_versions_channel_1/osx-arm64/package-0.1.0-h60d57d3_0.conda new file mode 100644 index 000000000..c5222ee8c Binary files /dev/null and b/tests/data/channels/channels/multiple_versions_channel_1/osx-arm64/package-0.1.0-h60d57d3_0.conda differ diff --git a/tests/data/channels/channels/multiple_versions_channel_1/osx-arm64/package-0.2.0-h60d57d3_0.conda b/tests/data/channels/channels/multiple_versions_channel_1/osx-arm64/package-0.2.0-h60d57d3_0.conda new file mode 100644 index 000000000..2acdd9e19 Binary files /dev/null and b/tests/data/channels/channels/multiple_versions_channel_1/osx-arm64/package-0.2.0-h60d57d3_0.conda differ diff --git a/tests/data/channels/channels/multiple_versions_channel_1/osx-arm64/package2-0.1.0-h60d57d3_0.conda b/tests/data/channels/channels/multiple_versions_channel_1/osx-arm64/package2-0.1.0-h60d57d3_0.conda new file mode 100644 index 000000000..426cc44af Binary files /dev/null and b/tests/data/channels/channels/multiple_versions_channel_1/osx-arm64/package2-0.1.0-h60d57d3_0.conda differ diff --git a/tests/data/channels/channels/multiple_versions_channel_1/osx-arm64/package2-0.2.0-h60d57d3_0.conda b/tests/data/channels/channels/multiple_versions_channel_1/osx-arm64/package2-0.2.0-h60d57d3_0.conda new file mode 100644 index 000000000..c97944095 Binary files /dev/null and b/tests/data/channels/channels/multiple_versions_channel_1/osx-arm64/package2-0.2.0-h60d57d3_0.conda differ diff --git a/tests/data/channels/channels/global_update_channel_1/osx-arm64/repodata.json b/tests/data/channels/channels/multiple_versions_channel_1/osx-arm64/repodata.json similarity index 59% rename from tests/data/channels/channels/global_update_channel_1/osx-arm64/repodata.json rename to tests/data/channels/channels/multiple_versions_channel_1/osx-arm64/repodata.json index 47733950d..1896d3393 100644 --- a/tests/data/channels/channels/global_update_channel_1/osx-arm64/repodata.json +++ b/tests/data/channels/channels/multiple_versions_channel_1/osx-arm64/repodata.json @@ -9,13 +9,13 @@ "build": "h60d57d3_0", "build_number": 0, "depends": [], - "md5": "65bf49140037803094927ea00d1a7b63", + "md5": "066f9bdf289cc4e12ed885bcffdb026b", "name": "package", "platform": "osx", - "sha256": "41265f0165572ba6ceb2c5733f8fa500a2a92846f015333f4577cab98f14d821", - "size": 1237, + "sha256": "d81a3861e03f8f90dbb4ece27bafc267564a5dd6667f81af2a78fd0618ec7147", + "size": 1238, "subdir": "osx-arm64", - "timestamp": 1730882683331, + "timestamp": 1730898132792, "version": "0.1.0" }, "package-0.2.0-h60d57d3_0.conda": { @@ -23,13 +23,13 @@ "build": "h60d57d3_0", "build_number": 0, "depends": [], - "md5": "b3492a159f38452b118705ef7e854304", + "md5": "a38507e7536708b09b42ec84103eb635", "name": "package", "platform": "osx", - "sha256": "96851c508999ca72a7d54548d0328bfbe4619cfb797ca4f0ddbce05478444396", - "size": 1239, + "sha256": "a0562541a0cb6f91fba34734ff2fa4bf31dbe2d5f42b6bf7372160c7063f1bd2", + "size": 1230, "subdir": "osx-arm64", - "timestamp": 1730882683525, + "timestamp": 1730898133, "version": "0.2.0" }, "package2-0.1.0-h60d57d3_0.conda": { @@ -37,13 +37,13 @@ "build": "h60d57d3_0", "build_number": 0, "depends": [], - "md5": "841d2cbb31ec33865c5932b4fde3277f", + "md5": "d91c7863513e7900022e2847fa709c44", "name": "package2", "platform": "osx", - "sha256": "b1b9704c43b86c517507cfeeb088c22b90afe4d0d13aef6ba91a5e12aaddb495", - "size": 1158, + "sha256": "54b560e721fae0674ce64ede3cc12e93a33ccee0164b08af9b88de2ad1bf537a", + "size": 1159, "subdir": "osx-arm64", - "timestamp": 1730882683330, + "timestamp": 1730898132792, "version": "0.1.0" }, "package2-0.2.0-h60d57d3_0.conda": { @@ -51,13 +51,13 @@ "build": "h60d57d3_0", "build_number": 0, "depends": [], - "md5": "4e69c129c2b05cd2af183aa8b62be089", + "md5": "da479bbc76cf304ff31f5d4a3610364f", "name": "package2", "platform": "osx", - "sha256": "4a0fb25c7b0c27b1656a6f656290b124201cdff1aa9e4734cf4bdf4eaf38df1e", - "size": 1157, + "sha256": "6788f6d1d79bbdc280eee31d9565ca6e355cfe83198aa8c9b8468892e22f9d0a", + "size": 1151, "subdir": "osx-arm64", - "timestamp": 1730882683525, + "timestamp": 1730898133, "version": "0.2.0" } }, diff --git a/tests/data/channels/channels/multiple_versions_channel_1/win-64/package-0.1.0-h9490d1a_0.conda b/tests/data/channels/channels/multiple_versions_channel_1/win-64/package-0.1.0-h9490d1a_0.conda new file mode 100644 index 000000000..e732d3440 Binary files /dev/null and b/tests/data/channels/channels/multiple_versions_channel_1/win-64/package-0.1.0-h9490d1a_0.conda differ diff --git a/tests/data/channels/channels/multiple_versions_channel_1/win-64/package-0.2.0-h9490d1a_0.conda b/tests/data/channels/channels/multiple_versions_channel_1/win-64/package-0.2.0-h9490d1a_0.conda new file mode 100644 index 000000000..8c6ad3e75 Binary files /dev/null and b/tests/data/channels/channels/multiple_versions_channel_1/win-64/package-0.2.0-h9490d1a_0.conda differ diff --git a/tests/data/channels/channels/multiple_versions_channel_1/win-64/package2-0.1.0-h9490d1a_0.conda b/tests/data/channels/channels/multiple_versions_channel_1/win-64/package2-0.1.0-h9490d1a_0.conda new file mode 100644 index 000000000..d7d3597c8 Binary files /dev/null and b/tests/data/channels/channels/multiple_versions_channel_1/win-64/package2-0.1.0-h9490d1a_0.conda differ diff --git a/tests/data/channels/channels/multiple_versions_channel_1/win-64/package2-0.2.0-h9490d1a_0.conda b/tests/data/channels/channels/multiple_versions_channel_1/win-64/package2-0.2.0-h9490d1a_0.conda new file mode 100644 index 000000000..14998289e Binary files /dev/null and b/tests/data/channels/channels/multiple_versions_channel_1/win-64/package2-0.2.0-h9490d1a_0.conda differ diff --git a/tests/data/channels/channels/global_update_channel_1/win-64/repodata.json b/tests/data/channels/channels/multiple_versions_channel_1/win-64/repodata.json similarity index 60% rename from tests/data/channels/channels/global_update_channel_1/win-64/repodata.json rename to tests/data/channels/channels/multiple_versions_channel_1/win-64/repodata.json index 78ca6bf61..dfa9f377a 100644 --- a/tests/data/channels/channels/global_update_channel_1/win-64/repodata.json +++ b/tests/data/channels/channels/multiple_versions_channel_1/win-64/repodata.json @@ -9,13 +9,13 @@ "build": "h9490d1a_0", "build_number": 0, "depends": [], - "md5": "49d5d6240f19c2928b3973f567e84b25", + "md5": "745d63cedc7ab134762eed55fa130224", "name": "package", "platform": "win", - "sha256": "349a37ec0022898e81a963916628593accaef30c9377b5990913fa9796debd00", - "size": 1238, + "sha256": "3ca104fc659f7e7d43f028665ff009b1afbd1df45c6a55787176eda973746a87", + "size": 1240, "subdir": "win-64", - "timestamp": 1730882683234, + "timestamp": 1730898132680, "version": "0.1.0" }, "package-0.2.0-h9490d1a_0.conda": { @@ -23,13 +23,13 @@ "build": "h9490d1a_0", "build_number": 0, "depends": [], - "md5": "e01e6d3106b436c37accac64ecf549bc", + "md5": "986f652f269e8ac205f395581a5cc59f", "name": "package", "platform": "win", - "sha256": "8d1e4104be07954631e6b5d445ee460437e7fea460247874be8d64bdb30bf028", + "sha256": "c5d72e133b9f37f2030a92149375f1ae1a6ac5bcfc3e373364c4bbf5dbeb8c98", "size": 1241, "subdir": "win-64", - "timestamp": 1730882683428, + "timestamp": 1730898132900, "version": "0.2.0" }, "package2-0.1.0-h9490d1a_0.conda": { @@ -37,13 +37,13 @@ "build": "h9490d1a_0", "build_number": 0, "depends": [], - "md5": "c669c43f74e3d7ebab21c1ed589ef187", + "md5": "ed3dbf7b4f1b80b63f9ff6e34c5501a8", "name": "package2", "platform": "win", - "sha256": "51f8a3cd73ebbfc7eee9a33916c8e2969b00213f51f09f5da7ffa7fa3db43711", - "size": 1171, + "sha256": "1038a96bafb2fb49357848d5c9aca6a67cdd89d6c4d04ed6ce4480eff6b81a81", + "size": 1169, "subdir": "win-64", - "timestamp": 1730882683234, + "timestamp": 1730898132681, "version": "0.1.0" }, "package2-0.2.0-h9490d1a_0.conda": { @@ -51,13 +51,13 @@ "build": "h9490d1a_0", "build_number": 0, "depends": [], - "md5": "51221484d48da06b158535f915aa14e5", + "md5": "07a7e70d365efdcc754bf329feb3d95a", "name": "package2", "platform": "win", - "sha256": "f63e2b193beea02bf7151cd432138fcfb71a9517dec0f35310132cf9aed50087", - "size": 1170, + "sha256": "ea6324a02aaf3f5ef7ad9f3e164aeb81f8c7dd46b5b25eb026101c53d81aca47", + "size": 1168, "subdir": "win-64", - "timestamp": 1730882683428, + "timestamp": 1730898132900, "version": "0.2.0" } }, diff --git a/tests/data/channels/channels/non_self_expose_channel_1/linux-64/jupyter-0.1.0-hb0f4dca_0.conda b/tests/data/channels/channels/non_self_expose_channel_1/linux-64/jupyter-0.1.0-hb0f4dca_0.conda index f684e485e..1d41343dd 100644 Binary files a/tests/data/channels/channels/non_self_expose_channel_1/linux-64/jupyter-0.1.0-hb0f4dca_0.conda and b/tests/data/channels/channels/non_self_expose_channel_1/linux-64/jupyter-0.1.0-hb0f4dca_0.conda differ diff --git a/tests/data/channels/channels/non_self_expose_channel_1/linux-64/jupyter-core-0.1.0-hb0f4dca_0.conda b/tests/data/channels/channels/non_self_expose_channel_1/linux-64/jupyter-core-0.1.0-hb0f4dca_0.conda index bbd7419b3..0b30c5f7c 100644 Binary files a/tests/data/channels/channels/non_self_expose_channel_1/linux-64/jupyter-core-0.1.0-hb0f4dca_0.conda and b/tests/data/channels/channels/non_self_expose_channel_1/linux-64/jupyter-core-0.1.0-hb0f4dca_0.conda differ diff --git a/tests/data/channels/channels/non_self_expose_channel_1/linux-64/repodata.json b/tests/data/channels/channels/non_self_expose_channel_1/linux-64/repodata.json index f834a82a3..83354200f 100644 --- a/tests/data/channels/channels/non_self_expose_channel_1/linux-64/repodata.json +++ b/tests/data/channels/channels/non_self_expose_channel_1/linux-64/repodata.json @@ -11,13 +11,13 @@ "depends": [ "jupyter-core" ], - "md5": "cb595183e841d1923914490d729cac99", + "md5": "e21e5d39645428ebcc38113558eae5d8", "name": "jupyter", "platform": "linux", - "sha256": "2962dde9565b1ef6e9f048ae1f1214e6498ae413ba83162da7963bb0db58c356", - "size": 992, + "sha256": "f326acf6bcd44f203a9e2375c8a646f42c649a08de22f4a9c7758ee78fa16704", + "size": 993, "subdir": "linux-64", - "timestamp": 1730882683675, + "timestamp": 1730898133150, "version": "0.1.0" }, "jupyter-core-0.1.0-hb0f4dca_0.conda": { @@ -25,13 +25,13 @@ "build": "hb0f4dca_0", "build_number": 0, "depends": [], - "md5": "b9d3081d340d5fa547d44a4789c2625b", + "md5": "ffac5d2147953383cf34752e2996d066", "name": "jupyter-core", "platform": "linux", - "sha256": "5777385da69c36d4e6f3a42ba3d9b25bdcca3ee05c305edd7fb3f55271fb533c", - "size": 1180, + "sha256": "7a6f7fa35475b5370a4081c27d15f3e5f5cfe59a33fa010fa573badb503c16ff", + "size": 1179, "subdir": "linux-64", - "timestamp": 1730882683675, + "timestamp": 1730898133150, "version": "0.1.0" } }, diff --git a/tests/data/channels/channels/non_self_expose_channel_1/osx-64/jupyter-0.1.0-h0dc7051_0.conda b/tests/data/channels/channels/non_self_expose_channel_1/osx-64/jupyter-0.1.0-h0dc7051_0.conda index 3e10e4342..088829755 100644 Binary files a/tests/data/channels/channels/non_self_expose_channel_1/osx-64/jupyter-0.1.0-h0dc7051_0.conda and b/tests/data/channels/channels/non_self_expose_channel_1/osx-64/jupyter-0.1.0-h0dc7051_0.conda differ diff --git a/tests/data/channels/channels/non_self_expose_channel_1/osx-64/jupyter-core-0.1.0-h0dc7051_0.conda b/tests/data/channels/channels/non_self_expose_channel_1/osx-64/jupyter-core-0.1.0-h0dc7051_0.conda index dc220ea9d..154b9be67 100644 Binary files a/tests/data/channels/channels/non_self_expose_channel_1/osx-64/jupyter-core-0.1.0-h0dc7051_0.conda and b/tests/data/channels/channels/non_self_expose_channel_1/osx-64/jupyter-core-0.1.0-h0dc7051_0.conda differ diff --git a/tests/data/channels/channels/non_self_expose_channel_1/osx-64/repodata.json b/tests/data/channels/channels/non_self_expose_channel_1/osx-64/repodata.json index 7a5b5d74d..33952f8ca 100644 --- a/tests/data/channels/channels/non_self_expose_channel_1/osx-64/repodata.json +++ b/tests/data/channels/channels/non_self_expose_channel_1/osx-64/repodata.json @@ -11,13 +11,13 @@ "depends": [ "jupyter-core" ], - "md5": "023004aa4810f883a639e1cb91403544", + "md5": "521a7441ff2515d8f662cd64a2bd0779", "name": "jupyter", "platform": "osx", - "sha256": "3a06249dcf578a7b655b9eda7135bfdcf25abd3aabc8e0ff60cb8d0424703572", - "size": 990, + "sha256": "a4b91bd16c655cf91addacd1e6f8a81c2142f79b061045da252bbb9af5e3fb0d", + "size": 991, "subdir": "osx-64", - "timestamp": 1730882683767, + "timestamp": 1730898133244, "version": "0.1.0" }, "jupyter-core-0.1.0-h0dc7051_0.conda": { @@ -25,13 +25,13 @@ "build": "h0dc7051_0", "build_number": 0, "depends": [], - "md5": "335408ca470afbca9e49df4e449e70e6", + "md5": "18f2ebe336c8f9c89ef2e3ac6e8af241", "name": "jupyter-core", "platform": "osx", - "sha256": "356de3d66124d460675dcb86e8c4ff6ce30040b93cd9304fe2a4417fbf202ec6", - "size": 1178, + "sha256": "fdc800c1690a78f679d8445f7da1d20856b58bc0cea15204818002d8b462357c", + "size": 1177, "subdir": "osx-64", - "timestamp": 1730882683767, + "timestamp": 1730898133244, "version": "0.1.0" } }, diff --git a/tests/data/channels/channels/non_self_expose_channel_1/osx-arm64/jupyter-0.1.0-h60d57d3_0.conda b/tests/data/channels/channels/non_self_expose_channel_1/osx-arm64/jupyter-0.1.0-h60d57d3_0.conda index f41fd735f..3d2681d7a 100644 Binary files a/tests/data/channels/channels/non_self_expose_channel_1/osx-arm64/jupyter-0.1.0-h60d57d3_0.conda and b/tests/data/channels/channels/non_self_expose_channel_1/osx-arm64/jupyter-0.1.0-h60d57d3_0.conda differ diff --git a/tests/data/channels/channels/non_self_expose_channel_1/osx-arm64/jupyter-core-0.1.0-h60d57d3_0.conda b/tests/data/channels/channels/non_self_expose_channel_1/osx-arm64/jupyter-core-0.1.0-h60d57d3_0.conda index 424a382f0..dedb92d73 100644 Binary files a/tests/data/channels/channels/non_self_expose_channel_1/osx-arm64/jupyter-core-0.1.0-h60d57d3_0.conda and b/tests/data/channels/channels/non_self_expose_channel_1/osx-arm64/jupyter-core-0.1.0-h60d57d3_0.conda differ diff --git a/tests/data/channels/channels/non_self_expose_channel_1/osx-arm64/repodata.json b/tests/data/channels/channels/non_self_expose_channel_1/osx-arm64/repodata.json index b13c1cb74..536d79b69 100644 --- a/tests/data/channels/channels/non_self_expose_channel_1/osx-arm64/repodata.json +++ b/tests/data/channels/channels/non_self_expose_channel_1/osx-arm64/repodata.json @@ -11,13 +11,13 @@ "depends": [ "jupyter-core" ], - "md5": "03fa978eea80fa3d72b28ffdeeabae41", + "md5": "ab87fefd9d91e53bdf24e3fa81d8dc2f", "name": "jupyter", "platform": "osx", - "sha256": "da2d9bb9b19a49e1d13fb26f539e11519b8d963cab1148797c226ebdb55ffe5c", - "size": 990, + "sha256": "bdf53fb2268e9e9558dc4694550c34297c8bb0a9f9253aec5291a6303d6ef88a", + "size": 991, "subdir": "osx-arm64", - "timestamp": 1730882683723, + "timestamp": 1730898133196, "version": "0.1.0" }, "jupyter-core-0.1.0-h60d57d3_0.conda": { @@ -25,13 +25,13 @@ "build": "h60d57d3_0", "build_number": 0, "depends": [], - "md5": "bb1c733fb00e41254542e01e0d856902", + "md5": "9513cce3dd18ea97cda6210e5fd038c1", "name": "jupyter-core", "platform": "osx", - "sha256": "b4b37e45c580898f1861c96a255c6eeb9bb0731fdf03d21b79433967ec7cc441", + "sha256": "27b8c5b6e216129cd6a6d9cf7a43b627c038b2529660b6d81fc7459ab1e12965", "size": 1178, "subdir": "osx-arm64", - "timestamp": 1730882683723, + "timestamp": 1730898133196, "version": "0.1.0" } }, diff --git a/tests/data/channels/channels/non_self_expose_channel_1/win-64/jupyter-0.1.0-h9490d1a_0.conda b/tests/data/channels/channels/non_self_expose_channel_1/win-64/jupyter-0.1.0-h9490d1a_0.conda index ac133ab0b..5cab8c43a 100644 Binary files a/tests/data/channels/channels/non_self_expose_channel_1/win-64/jupyter-0.1.0-h9490d1a_0.conda and b/tests/data/channels/channels/non_self_expose_channel_1/win-64/jupyter-0.1.0-h9490d1a_0.conda differ diff --git a/tests/data/channels/channels/non_self_expose_channel_1/win-64/jupyter-core-0.1.0-h9490d1a_0.conda b/tests/data/channels/channels/non_self_expose_channel_1/win-64/jupyter-core-0.1.0-h9490d1a_0.conda index 8093dff4f..615edf4d5 100644 Binary files a/tests/data/channels/channels/non_self_expose_channel_1/win-64/jupyter-core-0.1.0-h9490d1a_0.conda and b/tests/data/channels/channels/non_self_expose_channel_1/win-64/jupyter-core-0.1.0-h9490d1a_0.conda differ diff --git a/tests/data/channels/channels/non_self_expose_channel_1/win-64/repodata.json b/tests/data/channels/channels/non_self_expose_channel_1/win-64/repodata.json index d767008fe..41e8e1d9c 100644 --- a/tests/data/channels/channels/non_self_expose_channel_1/win-64/repodata.json +++ b/tests/data/channels/channels/non_self_expose_channel_1/win-64/repodata.json @@ -11,13 +11,13 @@ "depends": [ "jupyter-core" ], - "md5": "2c41f4f745411d30032d76f9539cc775", + "md5": "b084adf91a0b0cc9248389c203e6b0c6", "name": "jupyter", "platform": "win", - "sha256": "e174e76342a7648f06ba661d9dca624b0bf148b6da62ca7105a802b6406c2439", - "size": 993, + "sha256": "484c47d5b5715943af1589f08764eaed7fbd9a9eb156c76d8c195a8f4744ba03", + "size": 992, "subdir": "win-64", - "timestamp": 1730882683631, + "timestamp": 1730898133106, "version": "0.1.0" }, "jupyter-core-0.1.0-h9490d1a_0.conda": { @@ -25,13 +25,13 @@ "build": "h9490d1a_0", "build_number": 0, "depends": [], - "md5": "7c351321fa2921a0581eb65c67adf541", + "md5": "2ccc77fec0a0a6bd881e1114f2ac4ae8", "name": "jupyter-core", "platform": "win", - "sha256": "fb051f22a0f70203e694b64bcc37fe1dfb0a3cba8f0c27a14d26a36d7406d89a", + "sha256": "823222c9ea2f41898aec542eda9f68867f6f21b33d775f215be68568494690e5", "size": 1184, "subdir": "win-64", - "timestamp": 1730882683631, + "timestamp": 1730898133106, "version": "0.1.0" } }, diff --git a/tests/data/channels/channels/non_self_expose_channel_2/linux-64/jupyter-0.1.0-hb0f4dca_0.conda b/tests/data/channels/channels/non_self_expose_channel_2/linux-64/jupyter-0.1.0-hb0f4dca_0.conda index 64415cab4..77190f350 100644 Binary files a/tests/data/channels/channels/non_self_expose_channel_2/linux-64/jupyter-0.1.0-hb0f4dca_0.conda and b/tests/data/channels/channels/non_self_expose_channel_2/linux-64/jupyter-0.1.0-hb0f4dca_0.conda differ diff --git a/tests/data/channels/channels/non_self_expose_channel_2/linux-64/jupyter-core-0.2.0-hb0f4dca_0.conda b/tests/data/channels/channels/non_self_expose_channel_2/linux-64/jupyter-core-0.2.0-hb0f4dca_0.conda index 523bf1a97..8223f7ae4 100644 Binary files a/tests/data/channels/channels/non_self_expose_channel_2/linux-64/jupyter-core-0.2.0-hb0f4dca_0.conda and b/tests/data/channels/channels/non_self_expose_channel_2/linux-64/jupyter-core-0.2.0-hb0f4dca_0.conda differ diff --git a/tests/data/channels/channels/non_self_expose_channel_2/linux-64/repodata.json b/tests/data/channels/channels/non_self_expose_channel_2/linux-64/repodata.json index 75af9795a..e16e5adb4 100644 --- a/tests/data/channels/channels/non_self_expose_channel_2/linux-64/repodata.json +++ b/tests/data/channels/channels/non_self_expose_channel_2/linux-64/repodata.json @@ -11,13 +11,13 @@ "depends": [ "jupyter-core" ], - "md5": "4f378a46d647f6727cd68a182ad9d2f6", + "md5": "f573365a3c55a98cc1fec9cd46994b6f", "name": "jupyter", "platform": "linux", - "sha256": "b0089d4a756b1469b9492c054a8882aa4ef74ca7f14fe5a183faccc658267480", - "size": 992, + "sha256": "1be25cb22a8315b150e6009dabcf5bd98ea084d4a92c3c89f0253451b0303e60", + "size": 993, "subdir": "linux-64", - "timestamp": 1730882683856, + "timestamp": 1730898133339, "version": "0.1.0" }, "jupyter-core-0.2.0-hb0f4dca_0.conda": { @@ -25,13 +25,13 @@ "build": "hb0f4dca_0", "build_number": 0, "depends": [], - "md5": "772667e1b6f96a356898f20c14f429da", + "md5": "9f9bd66dab65c8163aa352861bd9cbfd", "name": "jupyter-core", "platform": "linux", - "sha256": "056c6fc011158c4aaf1a14704ed71bcc2b9ff762543149b64ce81bca4f6190a0", - "size": 1180, + "sha256": "1a5b2ddf62347cf6c942c8d393d7d46cf960bc78ade4ee28e9d029771371d21a", + "size": 1179, "subdir": "linux-64", - "timestamp": 1730882683856, + "timestamp": 1730898133340, "version": "0.2.0" } }, diff --git a/tests/data/channels/channels/non_self_expose_channel_2/osx-64/jupyter-0.1.0-h0dc7051_0.conda b/tests/data/channels/channels/non_self_expose_channel_2/osx-64/jupyter-0.1.0-h0dc7051_0.conda index 356ebf68a..792c382a0 100644 Binary files a/tests/data/channels/channels/non_self_expose_channel_2/osx-64/jupyter-0.1.0-h0dc7051_0.conda and b/tests/data/channels/channels/non_self_expose_channel_2/osx-64/jupyter-0.1.0-h0dc7051_0.conda differ diff --git a/tests/data/channels/channels/non_self_expose_channel_2/osx-64/jupyter-core-0.2.0-h0dc7051_0.conda b/tests/data/channels/channels/non_self_expose_channel_2/osx-64/jupyter-core-0.2.0-h0dc7051_0.conda index 6487fbd09..344157039 100644 Binary files a/tests/data/channels/channels/non_self_expose_channel_2/osx-64/jupyter-core-0.2.0-h0dc7051_0.conda and b/tests/data/channels/channels/non_self_expose_channel_2/osx-64/jupyter-core-0.2.0-h0dc7051_0.conda differ diff --git a/tests/data/channels/channels/non_self_expose_channel_2/osx-64/repodata.json b/tests/data/channels/channels/non_self_expose_channel_2/osx-64/repodata.json index 8b50edc73..2c83bf9c4 100644 --- a/tests/data/channels/channels/non_self_expose_channel_2/osx-64/repodata.json +++ b/tests/data/channels/channels/non_self_expose_channel_2/osx-64/repodata.json @@ -11,13 +11,13 @@ "depends": [ "jupyter-core" ], - "md5": "9050eef2b2323a5fe1d96955a0c92546", + "md5": "5864c37ec76421f67fbbaa180f2a3255", "name": "jupyter", "platform": "osx", - "sha256": "32a9d5a24c33728d1609b8e7ac12354e64cd1b81207fd664da4e4e65749df153", + "sha256": "7580d8c3a5eec707ca9ce642425e083205385103414bab3fe3d8b6a18f6cf109", "size": 991, "subdir": "osx-64", - "timestamp": 1730882683945, + "timestamp": 1730898133432, "version": "0.1.0" }, "jupyter-core-0.2.0-h0dc7051_0.conda": { @@ -25,13 +25,13 @@ "build": "h0dc7051_0", "build_number": 0, "depends": [], - "md5": "91077143a2bbe9e8f4c585e1b5151bd9", + "md5": "8f2e95f21707480920e7b5dbac0f4d08", "name": "jupyter-core", "platform": "osx", - "sha256": "fb7aa3f1a9b211deb6fc8d488c280acba8451bf8fb5a7d1fea59938f1151afdf", + "sha256": "b88f90c20bf198878bc49ba806715590b7fbe0470b9db09c567489c36a0833ea", "size": 1177, "subdir": "osx-64", - "timestamp": 1730882683945, + "timestamp": 1730898133432, "version": "0.2.0" } }, diff --git a/tests/data/channels/channels/non_self_expose_channel_2/osx-arm64/jupyter-0.1.0-h60d57d3_0.conda b/tests/data/channels/channels/non_self_expose_channel_2/osx-arm64/jupyter-0.1.0-h60d57d3_0.conda index b72abb567..5b29d20e4 100644 Binary files a/tests/data/channels/channels/non_self_expose_channel_2/osx-arm64/jupyter-0.1.0-h60d57d3_0.conda and b/tests/data/channels/channels/non_self_expose_channel_2/osx-arm64/jupyter-0.1.0-h60d57d3_0.conda differ diff --git a/tests/data/channels/channels/non_self_expose_channel_2/osx-arm64/jupyter-core-0.2.0-h60d57d3_0.conda b/tests/data/channels/channels/non_self_expose_channel_2/osx-arm64/jupyter-core-0.2.0-h60d57d3_0.conda index 2d45d8e70..4f7336fd4 100644 Binary files a/tests/data/channels/channels/non_self_expose_channel_2/osx-arm64/jupyter-core-0.2.0-h60d57d3_0.conda and b/tests/data/channels/channels/non_self_expose_channel_2/osx-arm64/jupyter-core-0.2.0-h60d57d3_0.conda differ diff --git a/tests/data/channels/channels/non_self_expose_channel_2/osx-arm64/repodata.json b/tests/data/channels/channels/non_self_expose_channel_2/osx-arm64/repodata.json index 13c04f54e..5ead9e4af 100644 --- a/tests/data/channels/channels/non_self_expose_channel_2/osx-arm64/repodata.json +++ b/tests/data/channels/channels/non_self_expose_channel_2/osx-arm64/repodata.json @@ -11,13 +11,13 @@ "depends": [ "jupyter-core" ], - "md5": "59b33b8e1582a456177c62549126a957", + "md5": "dcdba2684e9b362a8b146d42e9d5c1ac", "name": "jupyter", "platform": "osx", - "sha256": "986b5452abbbe0f287232995895bf3da11979e55c94e5dc40f8cf2323c30fd1d", - "size": 990, + "sha256": "5c5c4d8abf9e7a3976572d2cf4c601ea7d56e415d8fd7e43cea9a5fc5f0ce4c7", + "size": 991, "subdir": "osx-arm64", - "timestamp": 1730882683902, + "timestamp": 1730898133387, "version": "0.1.0" }, "jupyter-core-0.2.0-h60d57d3_0.conda": { @@ -25,13 +25,13 @@ "build": "h60d57d3_0", "build_number": 0, "depends": [], - "md5": "0703061d24bfae840e1d6b724dcb5846", + "md5": "7a0d4ee42bff11fe98e53df9f85a65fa", "name": "jupyter-core", "platform": "osx", - "sha256": "15a3ac3afde9d5ce5ac869361c90b5a1c117f88a31ffe8ad1bf97b57bed95c62", + "sha256": "21323847eb4ad0711523cf3ff7329988d81ea130741822bc3c6602cc6300358d", "size": 1178, "subdir": "osx-arm64", - "timestamp": 1730882683902, + "timestamp": 1730898133387, "version": "0.2.0" } }, diff --git a/tests/data/channels/channels/non_self_expose_channel_2/win-64/jupyter-0.1.0-h9490d1a_0.conda b/tests/data/channels/channels/non_self_expose_channel_2/win-64/jupyter-0.1.0-h9490d1a_0.conda index 9e0691fe8..c5d44b5c8 100644 Binary files a/tests/data/channels/channels/non_self_expose_channel_2/win-64/jupyter-0.1.0-h9490d1a_0.conda and b/tests/data/channels/channels/non_self_expose_channel_2/win-64/jupyter-0.1.0-h9490d1a_0.conda differ diff --git a/tests/data/channels/channels/non_self_expose_channel_2/win-64/jupyter-core-0.2.0-h9490d1a_0.conda b/tests/data/channels/channels/non_self_expose_channel_2/win-64/jupyter-core-0.2.0-h9490d1a_0.conda index 031b95017..db986d3af 100644 Binary files a/tests/data/channels/channels/non_self_expose_channel_2/win-64/jupyter-core-0.2.0-h9490d1a_0.conda and b/tests/data/channels/channels/non_self_expose_channel_2/win-64/jupyter-core-0.2.0-h9490d1a_0.conda differ diff --git a/tests/data/channels/channels/non_self_expose_channel_2/win-64/repodata.json b/tests/data/channels/channels/non_self_expose_channel_2/win-64/repodata.json index b1f231267..3321c4d7c 100644 --- a/tests/data/channels/channels/non_self_expose_channel_2/win-64/repodata.json +++ b/tests/data/channels/channels/non_self_expose_channel_2/win-64/repodata.json @@ -11,13 +11,13 @@ "depends": [ "jupyter-core" ], - "md5": "c25f398901237e51abb2df8f7ce43638", + "md5": "79449188cf7890c58129c1382006cb4d", "name": "jupyter", "platform": "win", - "sha256": "837d83bc02753162dc2a97d632cfb59ce4b7839d173312eb98c0698783252cda", - "size": 992, + "sha256": "dea256127dbe4145790c7d3cb7f1df3671613476ac684f470effae164b4a2feb", + "size": 993, "subdir": "win-64", - "timestamp": 1730882683810, + "timestamp": 1730898133293, "version": "0.1.0" }, "jupyter-core-0.2.0-h9490d1a_0.conda": { @@ -25,13 +25,13 @@ "build": "h9490d1a_0", "build_number": 0, "depends": [], - "md5": "a6d579036bbfb657d5d11ee34d098b75", + "md5": "927402097618f1aef1971f6415235c04", "name": "jupyter-core", "platform": "win", - "sha256": "edbb1dd6f9868a46af965834db5fddb20ce8273bbc563e7b5d593be938a5dcf8", + "sha256": "21ca5e89ad4f5e1b05002c086b971b0ae36f2313b411f9bd963e12c40c8d7c08", "size": 1185, "subdir": "win-64", - "timestamp": 1730882683810, + "timestamp": 1730898133293, "version": "0.2.0" } }, diff --git a/tests/data/channels/channels/trampoline_1/linux-64/dummy-trampoline-0.1.0-hb0f4dca_0.conda b/tests/data/channels/channels/trampoline_1/linux-64/dummy-trampoline-0.1.0-hb0f4dca_0.conda index 2168cb806..5e331b14c 100644 Binary files a/tests/data/channels/channels/trampoline_1/linux-64/dummy-trampoline-0.1.0-hb0f4dca_0.conda and b/tests/data/channels/channels/trampoline_1/linux-64/dummy-trampoline-0.1.0-hb0f4dca_0.conda differ diff --git a/tests/data/channels/channels/trampoline_1/linux-64/repodata.json b/tests/data/channels/channels/trampoline_1/linux-64/repodata.json index 7f361f243..a11b5d683 100644 --- a/tests/data/channels/channels/trampoline_1/linux-64/repodata.json +++ b/tests/data/channels/channels/trampoline_1/linux-64/repodata.json @@ -9,13 +9,13 @@ "build": "hb0f4dca_0", "build_number": 0, "depends": [], - "md5": "0af1320be2d353a132d4d532fbae8597", + "md5": "347d5984630e6be5217bfbf485be24b9", "name": "dummy-trampoline", "platform": "linux", - "sha256": "d653d6c75b3fe8137c19b5f3e6575c86192659b48d591f9e5d2f693ba53926a4", + "sha256": "6ab98c0e5b7aba534d4b4e881cc8dab471a695bf47c53fd654cc3aed0fa776e7", "size": 1624, "subdir": "linux-64", - "timestamp": 1730882684037, + "timestamp": 1730898133538, "version": "0.1.0" } }, diff --git a/tests/data/channels/channels/trampoline_1/osx-64/dummy-trampoline-0.1.0-h0dc7051_0.conda b/tests/data/channels/channels/trampoline_1/osx-64/dummy-trampoline-0.1.0-h0dc7051_0.conda index 165807f0b..13934e10a 100644 Binary files a/tests/data/channels/channels/trampoline_1/osx-64/dummy-trampoline-0.1.0-h0dc7051_0.conda and b/tests/data/channels/channels/trampoline_1/osx-64/dummy-trampoline-0.1.0-h0dc7051_0.conda differ diff --git a/tests/data/channels/channels/trampoline_1/osx-64/repodata.json b/tests/data/channels/channels/trampoline_1/osx-64/repodata.json index a06dfda0f..682534266 100644 --- a/tests/data/channels/channels/trampoline_1/osx-64/repodata.json +++ b/tests/data/channels/channels/trampoline_1/osx-64/repodata.json @@ -9,13 +9,13 @@ "build": "h0dc7051_0", "build_number": 0, "depends": [], - "md5": "05afb1e0cd362eb7e5ddfe5e6835a564", + "md5": "8ac53c67bbd2cc5b2fecb8a5647a02c6", "name": "dummy-trampoline", "platform": "osx", - "sha256": "c2de62b59f3c45ff9688e93aba1a32da493c07a0cb7bc45d8ffd38a01f6502b0", + "sha256": "419aada6da7a0aa1b332c2d3b8a5b34a517100040073e4399967ed4975f06141", "size": 1622, "subdir": "osx-64", - "timestamp": 1730882684119, + "timestamp": 1730898133623, "version": "0.1.0" } }, diff --git a/tests/data/channels/channels/trampoline_1/osx-arm64/dummy-trampoline-0.1.0-h60d57d3_0.conda b/tests/data/channels/channels/trampoline_1/osx-arm64/dummy-trampoline-0.1.0-h60d57d3_0.conda index b9ee3c5b4..bda8a5492 100644 Binary files a/tests/data/channels/channels/trampoline_1/osx-arm64/dummy-trampoline-0.1.0-h60d57d3_0.conda and b/tests/data/channels/channels/trampoline_1/osx-arm64/dummy-trampoline-0.1.0-h60d57d3_0.conda differ diff --git a/tests/data/channels/channels/trampoline_1/osx-arm64/repodata.json b/tests/data/channels/channels/trampoline_1/osx-arm64/repodata.json index c35ecf4da..31bd62f21 100644 --- a/tests/data/channels/channels/trampoline_1/osx-arm64/repodata.json +++ b/tests/data/channels/channels/trampoline_1/osx-arm64/repodata.json @@ -9,13 +9,13 @@ "build": "h60d57d3_0", "build_number": 0, "depends": [], - "md5": "efc5d391bc12a5e6b680e3318c16037f", + "md5": "276bdf61769e64a9b26cc5ffe9b91828", "name": "dummy-trampoline", "platform": "osx", - "sha256": "58721bb18088e785ad87e8caafbcdd9a5edf7d6df54c3937e8a26efc1051f55b", + "sha256": "912102acdd17263520f72afa7f080081615ffbf8e36b1be64ca923f039c9564f", "size": 1622, "subdir": "osx-arm64", - "timestamp": 1730882684077, + "timestamp": 1730898133580, "version": "0.1.0" } }, diff --git a/tests/data/channels/channels/trampoline_1/win-64/dummy-trampoline-0.1.0-h9490d1a_0.conda b/tests/data/channels/channels/trampoline_1/win-64/dummy-trampoline-0.1.0-h9490d1a_0.conda index 54ca63ef5..1eb7dab0f 100644 Binary files a/tests/data/channels/channels/trampoline_1/win-64/dummy-trampoline-0.1.0-h9490d1a_0.conda and b/tests/data/channels/channels/trampoline_1/win-64/dummy-trampoline-0.1.0-h9490d1a_0.conda differ diff --git a/tests/data/channels/channels/trampoline_1/win-64/repodata.json b/tests/data/channels/channels/trampoline_1/win-64/repodata.json index 22f913a4e..9c4c8691f 100644 --- a/tests/data/channels/channels/trampoline_1/win-64/repodata.json +++ b/tests/data/channels/channels/trampoline_1/win-64/repodata.json @@ -9,13 +9,13 @@ "build": "h9490d1a_0", "build_number": 0, "depends": [], - "md5": "7306456e8f73515ea178635bc267e773", + "md5": "231a9110ff4cd7021a5e6f3708045ab6", "name": "dummy-trampoline", "platform": "win", - "sha256": "7911e2c3e5b3d412c4ce75d9020424283eb1604cc87f361d5646901ab0a2996b", - "size": 1603, + "sha256": "78d7357684cff33081f8197a92ddeaa95c109cebaef605b536d21740035dcaff", + "size": 1602, "subdir": "win-64", - "timestamp": 1730882683987, + "timestamp": 1730898133481, "version": "0.1.0" } }, diff --git a/tests/data/channels/channels/trampoline_2/linux-64/dummy-trampoline-0.2.0-hb0f4dca_0.conda b/tests/data/channels/channels/trampoline_2/linux-64/dummy-trampoline-0.2.0-hb0f4dca_0.conda index d7ba9f948..369e9d527 100644 Binary files a/tests/data/channels/channels/trampoline_2/linux-64/dummy-trampoline-0.2.0-hb0f4dca_0.conda and b/tests/data/channels/channels/trampoline_2/linux-64/dummy-trampoline-0.2.0-hb0f4dca_0.conda differ diff --git a/tests/data/channels/channels/trampoline_2/linux-64/repodata.json b/tests/data/channels/channels/trampoline_2/linux-64/repodata.json index 5ce4d29be..e5e314e92 100644 --- a/tests/data/channels/channels/trampoline_2/linux-64/repodata.json +++ b/tests/data/channels/channels/trampoline_2/linux-64/repodata.json @@ -9,13 +9,13 @@ "build": "hb0f4dca_0", "build_number": 0, "depends": [], - "md5": "1f83a1294e46f34d5ad06b1ba21f1fe8", + "md5": "5cf3ff552794c2244ded9cb84111a5de", "name": "dummy-trampoline", "platform": "linux", - "sha256": "0316f0ae52043907d398c0eff2094981a9b09fa1bf96b0ccf721d97e12d7c2b3", - "size": 1632, + "sha256": "e0002e6221ca171cc2b87f981c997e58c1ea210da680b7f63182970d96a80c97", + "size": 1630, "subdir": "linux-64", - "timestamp": 1730882684201, + "timestamp": 1730898133718, "version": "0.2.0" } }, diff --git a/tests/data/channels/channels/trampoline_2/osx-64/dummy-trampoline-0.2.0-h0dc7051_0.conda b/tests/data/channels/channels/trampoline_2/osx-64/dummy-trampoline-0.2.0-h0dc7051_0.conda index bc19ec72a..880c96d6c 100644 Binary files a/tests/data/channels/channels/trampoline_2/osx-64/dummy-trampoline-0.2.0-h0dc7051_0.conda and b/tests/data/channels/channels/trampoline_2/osx-64/dummy-trampoline-0.2.0-h0dc7051_0.conda differ diff --git a/tests/data/channels/channels/trampoline_2/osx-64/repodata.json b/tests/data/channels/channels/trampoline_2/osx-64/repodata.json index 94fc77525..cc9c6845e 100644 --- a/tests/data/channels/channels/trampoline_2/osx-64/repodata.json +++ b/tests/data/channels/channels/trampoline_2/osx-64/repodata.json @@ -9,13 +9,13 @@ "build": "h0dc7051_0", "build_number": 0, "depends": [], - "md5": "74f32d57ede54674516b3fe8de1a7d9e", + "md5": "ed82cfca5dc790ce8600cd7f93c7e685", "name": "dummy-trampoline", "platform": "osx", - "sha256": "76821e964b6fc2c6fda9ceecffa505d94facbf4df0f4efded3373f8bac01bdf9", - "size": 1633, + "sha256": "d352817b1fd10ef2816a94bcae75569f4d788341bfb09bea1c8ae80eac3f5719", + "size": 1629, "subdir": "osx-64", - "timestamp": 1730882684284, + "timestamp": 1730898133805, "version": "0.2.0" } }, diff --git a/tests/data/channels/channels/trampoline_2/osx-arm64/dummy-trampoline-0.2.0-h60d57d3_0.conda b/tests/data/channels/channels/trampoline_2/osx-arm64/dummy-trampoline-0.2.0-h60d57d3_0.conda index ada8c260f..c6f7c6e07 100644 Binary files a/tests/data/channels/channels/trampoline_2/osx-arm64/dummy-trampoline-0.2.0-h60d57d3_0.conda and b/tests/data/channels/channels/trampoline_2/osx-arm64/dummy-trampoline-0.2.0-h60d57d3_0.conda differ diff --git a/tests/data/channels/channels/trampoline_2/osx-arm64/repodata.json b/tests/data/channels/channels/trampoline_2/osx-arm64/repodata.json index 87f1f95f7..18f124c37 100644 --- a/tests/data/channels/channels/trampoline_2/osx-arm64/repodata.json +++ b/tests/data/channels/channels/trampoline_2/osx-arm64/repodata.json @@ -9,13 +9,13 @@ "build": "h60d57d3_0", "build_number": 0, "depends": [], - "md5": "4e04031c0753ab3c0d0e71e6eb55d998", + "md5": "33dff0375ebac00e35f37e8140a7805f", "name": "dummy-trampoline", "platform": "osx", - "sha256": "0c688c0c6cf58c092202bf89d3dfe0b0c8238f80d1082e334c0c07e0a43ac652", - "size": 1632, + "sha256": "897ae0414a05ac9bbccf6b640ec60049f209a6f54158ab4b8700e70909be9f14", + "size": 1629, "subdir": "osx-arm64", - "timestamp": 1730882684242, + "timestamp": 1730898133762, "version": "0.2.0" } }, diff --git a/tests/data/channels/channels/trampoline_2/win-64/dummy-trampoline-0.2.0-h9490d1a_0.conda b/tests/data/channels/channels/trampoline_2/win-64/dummy-trampoline-0.2.0-h9490d1a_0.conda index aadc6a33b..4e8abc84b 100644 Binary files a/tests/data/channels/channels/trampoline_2/win-64/dummy-trampoline-0.2.0-h9490d1a_0.conda and b/tests/data/channels/channels/trampoline_2/win-64/dummy-trampoline-0.2.0-h9490d1a_0.conda differ diff --git a/tests/data/channels/channels/trampoline_2/win-64/repodata.json b/tests/data/channels/channels/trampoline_2/win-64/repodata.json index b126b3263..1158f6d52 100644 --- a/tests/data/channels/channels/trampoline_2/win-64/repodata.json +++ b/tests/data/channels/channels/trampoline_2/win-64/repodata.json @@ -9,13 +9,13 @@ "build": "h9490d1a_0", "build_number": 0, "depends": [], - "md5": "d4027e514f8e4dab24b285d33e8439f1", + "md5": "ce4e3a397793d4ddcc34398f4593b10d", "name": "dummy-trampoline", "platform": "win", - "sha256": "030dcaa53192a76593b6567da4041c7b7e07fb8c399db4743801b6b08d1cf0dd", + "sha256": "058f5d3c112b76ee73a4dbefb7bbcb977c088be84545ac7f4a2cd386a237051f", "size": 1610, "subdir": "win-64", - "timestamp": 1730882684160, + "timestamp": 1730898133667, "version": "0.2.0" } }, diff --git a/tests/data/channels/mappings.toml b/tests/data/channels/mappings.toml index 734f0a9d4..6912706be 100644 --- a/tests/data/channels/mappings.toml +++ b/tests/data/channels/mappings.toml @@ -1,7 +1,7 @@ "dummy_channel_1.yaml" = "dummy_channel_1" "dummy_channel_2.yaml" = "dummy_channel_2" -"global_update_channel_1_010.yaml" = "global_update_channel_1" -"global_update_channel_1_020.yaml" = "global_update_channel_1" +"multiple_versions_channel_1_010.yaml" = "multiple_versions_channel_1" +"multiple_versions_channel_1_020.yaml" = "multiple_versions_channel_1" "non_self_expose_channel_1.yaml" = "non_self_expose_channel_1" "non_self_expose_channel_2.yaml" = "non_self_expose_channel_2" "trampoline/trampoline_1.yaml" = "trampoline_1" diff --git a/tests/data/channels/recipes/global_update_channel_1_010.yaml b/tests/data/channels/recipes/multiple_versions_channel_1_010.yaml similarity index 95% rename from tests/data/channels/recipes/global_update_channel_1_010.yaml rename to tests/data/channels/recipes/multiple_versions_channel_1_010.yaml index df78a0a0e..d1abfb773 100644 --- a/tests/data/channels/recipes/global_update_channel_1_010.yaml +++ b/tests/data/channels/recipes/multiple_versions_channel_1_010.yaml @@ -1,5 +1,5 @@ recipe: - name: global-update-channel + name: multiple-versions-channel version: 1.0.0 context: @@ -10,6 +10,7 @@ outputs: version: ${{ version }} build: + number: 0 script: - mkdir -p $PREFIX/bin # Expose two binaries, with and without version number diff --git a/tests/data/channels/recipes/global_update_channel_1_020.yaml b/tests/data/channels/recipes/multiple_versions_channel_1_020.yaml similarity index 96% rename from tests/data/channels/recipes/global_update_channel_1_020.yaml rename to tests/data/channels/recipes/multiple_versions_channel_1_020.yaml index 090dddb19..6238927d1 100644 --- a/tests/data/channels/recipes/global_update_channel_1_020.yaml +++ b/tests/data/channels/recipes/multiple_versions_channel_1_020.yaml @@ -1,5 +1,5 @@ recipe: - name: global-update-channel + name: multiple-versions-channel version: 1.0.0 context: diff --git a/tests/integration_python/conftest.py b/tests/integration_python/conftest.py index aac4807fc..d897b4eba 100644 --- a/tests/integration_python/conftest.py +++ b/tests/integration_python/conftest.py @@ -34,8 +34,8 @@ def dummy_channel_2(channels: Path) -> str: @pytest.fixture -def global_update_channel_1(channels: Path) -> str: - return channels.joinpath("global_update_channel_1").as_uri() +def multiple_versions_channel_1(channels: Path) -> str: + return channels.joinpath("multiple_versions_channel_1").as_uri() @pytest.fixture diff --git a/tests/integration_python/global/test_global.py b/tests/integration_python/global/test_global.py index dcac849a5..b6ccd8605 100644 --- a/tests/integration_python/global/test_global.py +++ b/tests/integration_python/global/test_global.py @@ -1094,14 +1094,14 @@ def test_install_multi_env_install(pixi: Path, tmp_path: Path, dummy_channel_1: @pytest.mark.skipif(platform.system() == "Windows", reason="Not reliable on Windows") -def test_pixi_install_cleanup(pixi: Path, tmp_path: Path, global_update_channel_1: str) -> None: +def test_pixi_install_cleanup(pixi: Path, tmp_path: Path, multiple_versions_channel_1: str) -> None: env = {"PIXI_HOME": str(tmp_path)} package0_1_0 = tmp_path / "bin" / exec_extension("package0.1.0") package0_2_0 = tmp_path / "bin" / exec_extension("package0.2.0") verify_cli_command( - [pixi, "global", "install", "--channel", global_update_channel_1, "package==0.1.0"], + [pixi, "global", "install", "--channel", multiple_versions_channel_1, "package==0.1.0"], env=env, ) assert package0_1_0.is_file() @@ -1110,7 +1110,7 @@ def test_pixi_install_cleanup(pixi: Path, tmp_path: Path, global_update_channel_ # Install the same package but with a different version # The old version should be removed and the new version should be installed without error. verify_cli_command( - [pixi, "global", "install", "--channel", global_update_channel_1, "package==0.2.0"], + [pixi, "global", "install", "--channel", multiple_versions_channel_1, "package==0.2.0"], env=env, ) @@ -1339,7 +1339,7 @@ def test_uninstall_only_reverts_failing(pixi: Path, tmp_path: Path, dummy_channe def test_global_update_single_package( - pixi: Path, tmp_path: Path, global_update_channel_1: str + pixi: Path, tmp_path: Path, multiple_versions_channel_1: str ) -> None: env = {"PIXI_HOME": str(tmp_path)} # Test update with no environments @@ -1350,7 +1350,7 @@ def test_global_update_single_package( # Test update of a single package verify_cli_command( - [pixi, "global", "install", "--channel", global_update_channel_1, "package 0.1.0"], + [pixi, "global", "install", "--channel", multiple_versions_channel_1, "package 0.1.0"], env=env, ) # Replace the version with a "*" @@ -1397,7 +1397,7 @@ def test_global_update_single_package_with_transient_dependency( def test_global_update_all_packages( - pixi: Path, tmp_path: Path, global_update_channel_1: str + pixi: Path, tmp_path: Path, multiple_versions_channel_1: str ) -> None: env = {"PIXI_HOME": str(tmp_path)} @@ -1407,7 +1407,7 @@ def test_global_update_all_packages( "global", "install", "--channel", - global_update_channel_1, + multiple_versions_channel_1, "package2==0.1.0", "package==0.1.0", ], @@ -1450,7 +1450,7 @@ def test_global_update_all_packages( def test_global_update_multiple_packages_in_one_env( - pixi: Path, tmp_path: Path, global_update_channel_1: str + pixi: Path, tmp_path: Path, multiple_versions_channel_1: str ) -> None: env = {"PIXI_HOME": str(tmp_path)} @@ -1460,7 +1460,7 @@ def test_global_update_multiple_packages_in_one_env( "global", "install", "--channel", - global_update_channel_1, + multiple_versions_channel_1, "--environment", "my-packages", "package2==0.1.0", @@ -1506,14 +1506,14 @@ def test_global_update_multiple_packages_in_one_env( assert "0.2.0" in bin_file_package2.read_text() -def test_pixi_update_cleanup(pixi: Path, tmp_path: Path, global_update_channel_1: str) -> None: +def test_pixi_update_cleanup(pixi: Path, tmp_path: Path, multiple_versions_channel_1: str) -> None: env = {"PIXI_HOME": str(tmp_path)} package0_1_0 = tmp_path / "bin" / exec_extension("package0.1.0") package0_2_0 = tmp_path / "bin" / exec_extension("package0.2.0") verify_cli_command( - [pixi, "global", "install", "--channel", global_update_channel_1, "package==0.1.0"], + [pixi, "global", "install", "--channel", multiple_versions_channel_1, "package==0.1.0"], env=env, ) assert package0_1_0.is_file() @@ -1543,7 +1543,7 @@ def test_pixi_update_cleanup(pixi: Path, tmp_path: Path, global_update_channel_1 def test_pixi_update_subset_expose( - pixi: Path, tmp_path: Path, global_update_channel_1: str + pixi: Path, tmp_path: Path, multiple_versions_channel_1: str ) -> None: env = {"PIXI_HOME": str(tmp_path)} @@ -1551,7 +1551,7 @@ def test_pixi_update_subset_expose( package0_2_0 = tmp_path / "bin" / exec_extension("package0.2.0") verify_cli_command( - [pixi, "global", "install", "--channel", global_update_channel_1, "package==0.1.0"], + [pixi, "global", "install", "--channel", multiple_versions_channel_1, "package==0.1.0"], env=env, ) assert package0_1_0.is_file() diff --git a/tests/integration_python/test_main_cli.py b/tests/integration_python/test_main_cli.py index 36385231d..2fa34d978 100644 --- a/tests/integration_python/test_main_cli.py +++ b/tests/integration_python/test_main_cli.py @@ -1,5 +1,8 @@ +import os from pathlib import Path from .common import verify_cli_command, ExitCode, PIXI_VERSION +import tomllib +import json import pytest @@ -290,3 +293,215 @@ def test_pixi_init_pyproject(pixi: Path, tmp_path: Path) -> None: verify_cli_command([pixi, "init", tmp_path, "--format", "pyproject"], ExitCode.SUCCESS) # Verify that install works verify_cli_command([pixi, "install", "--manifest-path", manifest_path], ExitCode.SUCCESS) + + +def test_upgrade_package_does_not_exist( + pixi: Path, tmp_path: Path, multiple_versions_channel_1: str +) -> None: + manifest_path = tmp_path / "pixi.toml" + + # Create a new project + verify_cli_command([pixi, "init", "--channel", multiple_versions_channel_1, tmp_path]) + + # Add package + verify_cli_command([pixi, "add", "--manifest-path", manifest_path, "package"]) + + # Similar package names that don't exist should get suggestions + verify_cli_command( + [pixi, "upgrade", "--manifest-path", manifest_path, "package_similar_name"], + ExitCode.FAILURE, + stderr_contains=[ + "could not find a package named 'package_similar_name'", + "did you mean 'package'", + ], + ) + + verify_cli_command( + [pixi, "upgrade", "--manifest-path", manifest_path, "different_name"], + ExitCode.FAILURE, + stderr_contains="could not find a package named 'different_name'", + stderr_excludes="did you mean 'package'", + ) + + +def test_upgrade_conda_package( + pixi: Path, tmp_path: Path, multiple_versions_channel_1: str +) -> None: + manifest_path = tmp_path / "pixi.toml" + + # Create a new project + verify_cli_command([pixi, "init", "--channel", multiple_versions_channel_1, tmp_path]) + + # Add package pinned to version 0.1.0 + verify_cli_command( + [ + pixi, + "add", + "--manifest-path", + manifest_path, + f"package==0.1.0[channel={multiple_versions_channel_1},build_number=0]", + ] + ) + parsed_manifest = tomllib.loads(manifest_path.read_text()) + package = parsed_manifest["dependencies"]["package"] + assert package["version"] == "==0.1.0" + assert package["channel"] == multiple_versions_channel_1 + assert package["build-number"] == "==0" + + # Upgrade package, it should now be at 0.2.0, with semver ranges + # The channel should still be specified + verify_cli_command( + [pixi, "upgrade", "--manifest-path", manifest_path, "package"], + stderr_contains=["package", "0.1.0", "0.2.0"], + ) + parsed_manifest = tomllib.loads(manifest_path.read_text()) + package = parsed_manifest["dependencies"]["package"] + assert package["version"] == ">=0.2.0,<0.3" + assert package["channel"] == multiple_versions_channel_1 + assert "build-number" not in package + + +def test_upgrade_exclude(pixi: Path, tmp_path: Path, multiple_versions_channel_1: str) -> None: + manifest_path = tmp_path / "pixi.toml" + + # Create a new project + verify_cli_command([pixi, "init", "--channel", multiple_versions_channel_1, tmp_path]) + + # Add package pinned to version 0.1.0 + verify_cli_command( + [pixi, "add", "--manifest-path", manifest_path, "package==0.1.0", "package2==0.1.0"] + ) + parsed_manifest = tomllib.loads(manifest_path.read_text()) + assert parsed_manifest["dependencies"]["package"] == "==0.1.0" + assert parsed_manifest["dependencies"]["package2"] == "==0.1.0" + + # Upgrade package, it should now be at 0.2.0, with semver ranges + # package2, should still be at 0.1.0, since we excluded it + verify_cli_command( + [pixi, "upgrade", "--manifest-path", manifest_path, "--exclude", "package2"], + stderr_contains=["package", "0.1.0", "0.2.0"], + stderr_excludes="package2", + ) + parsed_manifest = tomllib.loads(manifest_path.read_text()) + assert parsed_manifest["dependencies"]["package"] == ">=0.2.0,<0.3" + assert parsed_manifest["dependencies"]["package2"] == "==0.1.0" + + +def test_upgrade_json_output(pixi: Path, tmp_path: Path, multiple_versions_channel_1: str) -> None: + manifest_path = tmp_path / "pixi.toml" + + # Create a new project + verify_cli_command([pixi, "init", "--channel", multiple_versions_channel_1, tmp_path]) + + # Add package pinned to version 0.1.0 + verify_cli_command( + [pixi, "add", "--manifest-path", manifest_path, "package==0.1.0", "package2==0.1.0"] + ) + parsed_manifest = tomllib.loads(manifest_path.read_text()) + assert parsed_manifest["dependencies"]["package"] == "==0.1.0" + assert parsed_manifest["dependencies"]["package2"] == "==0.1.0" + + # Check if json output is correct and readable + result = verify_cli_command( + [pixi, "upgrade", "--manifest-path", manifest_path, "--json"], + stdout_contains=["package", "package2", "0.1.0", "0.2.0", 'version": ', "before", "after"], + ) + + data = json.loads(result.stdout) + assert data["environment"]["default"] + + +def test_upgrade_dryrun(pixi: Path, tmp_path: Path, multiple_versions_channel_1: str) -> None: + manifest_path = tmp_path / "pixi.toml" + lock_file_path = tmp_path / "pixi.lock" + # Create a new project + verify_cli_command([pixi, "init", "--channel", multiple_versions_channel_1, tmp_path]) + + # Add package pinned to version 0.1.0 + verify_cli_command( + [pixi, "add", "--manifest-path", manifest_path, "package==0.1.0", "package2==0.1.0"] + ) + + manifest_content = manifest_path.read_text() + lock_file_content = lock_file_path.read_text() + # Rename .pixi folder, no remove to avoid remove logic. + os.renames(tmp_path / ".pixi", tmp_path / ".pixi_backup") + + parsed_manifest = tomllib.loads(manifest_path.read_text()) + assert parsed_manifest["dependencies"]["package"] == "==0.1.0" + assert parsed_manifest["dependencies"]["package2"] == "==0.1.0" + + verify_cli_command( + [pixi, "upgrade", "--manifest-path", manifest_path, "--dry-run"], + stderr_contains=["package", "0.1.0", "0.2.0"], + ) + + # Verify the manifest, lock file and .pixi folder are not modified + assert manifest_path.read_text() == manifest_content + assert lock_file_path.read_text() == lock_file_content + assert not os.path.exists(tmp_path / ".pixi") + + +@pytest.mark.slow +def test_upgrade_pypi_package(pixi: Path, tmp_path: Path) -> None: + manifest_path = tmp_path / "pixi.toml" + + # Create a new project + verify_cli_command([pixi, "init", tmp_path]) + + # Add python + verify_cli_command([pixi, "add", "--manifest-path", manifest_path, "python=3.13"]) + + # Add httpx pinned to version 0.26.0 + verify_cli_command( + [ + pixi, + "add", + "--manifest-path", + manifest_path, + "--pypi", + "httpx[cli]==0.26.0", + ] + ) + parsed_manifest = tomllib.loads(manifest_path.read_text()) + assert parsed_manifest["pypi-dependencies"]["httpx"]["version"] == "==0.26.0" + assert parsed_manifest["pypi-dependencies"]["httpx"]["extras"] == ["cli"] + + # Upgrade httpx, it should now be upgraded + # Extras should be preserved + verify_cli_command( + [pixi, "upgrade", "--manifest-path", manifest_path, "httpx"], + stderr_contains=["httpx", "0.26.0"], + ) + parsed_manifest = tomllib.loads(manifest_path.read_text()) + assert parsed_manifest["pypi-dependencies"]["httpx"]["version"] != "==0.26.0" + assert parsed_manifest["pypi-dependencies"]["httpx"]["extras"] == ["cli"] + + +@pytest.mark.slow +def test_upgrade_pypi_and_conda_package(pixi: Path, tmp_path: Path) -> None: + manifest_path = tmp_path / "pyproject.toml" + + # Create a new project + verify_cli_command([pixi, "init", "--format", "pyproject", tmp_path]) + + # Add pinned numpy as conda and pypi dependency + verify_cli_command([pixi, "add", "--manifest-path", manifest_path, "numpy==1.*"]) + verify_cli_command([pixi, "add", "--manifest-path", manifest_path, "--pypi", "numpy==1.*"]) + + parsed_manifest = tomllib.loads(manifest_path.read_text()) + numpy_pypi = parsed_manifest["project"]["dependencies"][0] + assert numpy_pypi == "numpy==1.*" + numpy_conda = parsed_manifest["tool"]["pixi"]["dependencies"]["numpy"] + assert numpy_conda == "1.*" + + # Upgrade numpy, both conda and pypi should be upgraded + verify_cli_command( + [pixi, "upgrade", "--manifest-path", manifest_path, "numpy"], + stderr_contains=["numpy", "1."], + ) + parsed_manifest = tomllib.loads(manifest_path.read_text()) + numpy_pypi = parsed_manifest["project"]["dependencies"][0] + assert "1.*" not in numpy_pypi + numpy_conda = parsed_manifest["tool"]["pixi"]["dependencies"]["numpy"] + assert numpy_conda != "1.*" diff --git a/tests/integration_rust/common/builders.rs b/tests/integration_rust/common/builders.rs index 2e551c10a..4bdef2660 100644 --- a/tests/integration_rust/common/builders.rs +++ b/tests/integration_rust/common/builders.rs @@ -37,7 +37,7 @@ use pixi::{ task::TaskName, DependencyType, }; -use pixi_manifest::{EnvironmentName, SpecType}; +use pixi_manifest::{EnvironmentName, FeatureName, SpecType}; use rattler_conda_types::{NamedChannelOrUrl, Platform}; use url::Url; @@ -138,8 +138,8 @@ pub trait HasDependencyConfig: Sized { host: false, build: false, pypi: false, - platform: Default::default(), - feature: None, + platforms: Default::default(), + feature: Default::default(), } } @@ -175,7 +175,7 @@ pub trait HasDependencyConfig: Sized { } fn set_platforms(mut self, platforms: &[Platform]) -> Self { - self.dependency_config().platform.extend(platforms.iter()); + self.dependency_config().platforms.extend(platforms.iter()); self } } @@ -193,7 +193,7 @@ impl AddBuilder { } pub fn with_feature(mut self, feature: impl ToString) -> Self { - self.args.dependency_config.feature = Some(feature.to_string()); + self.args.dependency_config.feature = FeatureName::Named(feature.to_string()); self } }