Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: factor gateway data fetch and solve into a function #1793

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 11 additions & 46 deletions src/cli/exec.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::{
hash::{DefaultHasher, Hash, Hasher},
path::Path,
str::FromStr,
};

Expand All @@ -10,14 +9,12 @@ use rattler::{
install::{IndicatifReporter, Installer},
package_cache::PackageCache,
};
use rattler_conda_types::{GenericVirtualPackage, MatchSpec, PackageName, Platform};
use rattler_solve::{resolvo::Solver, SolverImpl, SolverTask};
use rattler_virtual_packages::VirtualPackage;
use rattler_conda_types::{MatchSpec, PackageName, Platform};
use reqwest_middleware::ClientWithMiddleware;

use crate::prefix::Prefix;
use crate::{cli::global::common::solve_package_records, prefix::Prefix};
use pixi_config::{self, Config, ConfigCli};
use pixi_progress::{await_in_progress, global_multi_progress, wrap_in_progress};
use pixi_progress::{global_multi_progress, wrap_in_progress};
use pixi_utils::{reqwest::build_reqwest_clients, PrefixGuard};

use super::cli_config::ChannelsConfig;
Expand Down Expand Up @@ -84,14 +81,13 @@ impl EnvironmentHash {
/// CLI entry point for `pixi runx`
pub async fn execute(args: Args) -> miette::Result<()> {
let config = Config::with_cli_config(&args.config);
let cache_dir = pixi_config::get_cache_dir().context("failed to determine cache directory")?;
let (_, client) = build_reqwest_clients(Some(&config));

let mut command_args = args.command.iter();
let command = command_args.next().ok_or_else(|| miette::miette!(help ="i.e when specifying specs explicitly use a command at the end: `pixi exec -s python==3.12 python`", "missing required command to execute",))?;
let (_, client) = build_reqwest_clients(Some(&config));

// Create the environment to run the command in.
let prefix = create_exec_prefix(&args, &cache_dir, &config, &client).await?;
let prefix = create_exec_prefix(&args, &config, &client).await?;

// Get environment variables from the activation
let activation_env = run_activation(&prefix).await?;
Expand All @@ -114,11 +110,11 @@ pub async fn execute(args: Args) -> miette::Result<()> {
/// Creates a prefix for the `pixi exec` command.
pub async fn create_exec_prefix(
args: &Args,
cache_dir: &Path,
config: &Config,
client: &ClientWithMiddleware,
) -> miette::Result<Prefix> {
let environment_name = EnvironmentHash::from_args(args, config).name();
let cache_dir = pixi_config::get_cache_dir().context("failed to determine cache directory")?;
let prefix = Prefix::new(cache_dir.join("cached-envs-v0").join(environment_name));

let mut guard = PrefixGuard::new(prefix.root())
Expand Down Expand Up @@ -164,50 +160,19 @@ pub async fn create_exec_prefix(
args.specs.clone()
};

// Get the repodata for the specs
let repodata = await_in_progress("fetching repodata for environment", |_| async {
gateway
.query(
args.channels.resolve_from_config(config),
[Platform::current(), Platform::NoArch],
specs.clone(),
)
.recursive(true)
.execute()
.await
})
.await
.into_diagnostic()
.context("failed to get repodata")?;

// Determine virtual packages of the current platform
let virtual_packages = VirtualPackage::current()
.into_diagnostic()
.context("failed to determine virtual packages")?
.iter()
.cloned()
.map(GenericVirtualPackage::from)
.collect();

// Solve the environment
let channels = args.channels.resolve_from_config(config);
let solved_records =
solve_package_records(&gateway, Platform::current(), channels, specs.clone()).await?;

// Install the environment
tracing::info!(
"creating environment in {}",
dunce::canonicalize(prefix.root())
.as_deref()
.unwrap_or(prefix.root())
.display()
);
let solved_records = wrap_in_progress("solving environment", move || {
Solver.solve(SolverTask {
specs,
virtual_packages,
..SolverTask::from_iter(&repodata)
})
})
.into_diagnostic()
.context("failed to solve environment")?;

// Install the environment
Installer::new()
.with_download_client(client.clone())
.with_reporter(
Expand Down
65 changes: 62 additions & 3 deletions src/cli/global/common.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
use std::path::PathBuf;

use miette::IntoDiagnostic;
use rattler_conda_types::{Channel, ChannelConfig, PackageName, PrefixRecord};
use miette::{Context, IntoDiagnostic};
use pixi_progress::{await_in_progress, wrap_in_progress};
use rattler_conda_types::{
Channel, ChannelConfig, GenericVirtualPackage, MatchSpec, PackageName, Platform, PrefixRecord,
RepoDataRecord,
};
use rattler_repodata_gateway::Gateway;
use rattler_solve::{resolvo::Solver, SolverImpl, SolverTask};
use rattler_virtual_packages::VirtualPackage;

use crate::{prefix::Prefix, repodata};
use pixi_config::home_path;
Expand Down Expand Up @@ -110,6 +117,58 @@ pub(super) fn channel_name_from_prefix(
.unwrap_or_else(|_| prefix_package.repodata_record.channel.clone())
}

/// Solve package records from [`Gateway`] for the given package MatchSpec
///
/// # Returns
///
/// The package records (with dependencies records) for the given package
/// MatchSpec
pub async fn solve_package_records<AsChannel, ChannelIter>(
gateway: &Gateway,
platform: Platform,
channels: ChannelIter,
specs: Vec<MatchSpec>,
) -> miette::Result<Vec<RepoDataRecord>>
where
AsChannel: Into<Channel>,
ChannelIter: IntoIterator<Item = AsChannel>,
{
// Get the repodata for the specs
let repodata = await_in_progress("fetching repodata for environment", |_| async {
gateway
.query(channels, [platform, Platform::NoArch], specs.clone())
.recursive(true)
.execute()
.await
})
.await
.into_diagnostic()
.context("failed to get repodata")?;

// Determine virtual packages of the current platform
// We cannot infer virtual_packages for another platform
let virtual_packages = VirtualPackage::current()
.into_diagnostic()
.context("failed to determine virtual packages")?
.iter()
.cloned()
.map(GenericVirtualPackage::from)
.collect();

// Solve the environment
let solved_records = wrap_in_progress("solving environment", move || {
Solver.solve(SolverTask {
specs,
virtual_packages,
..SolverTask::from_iter(&repodata)
})
})
.into_diagnostic()
.context("failed to solve environment")?;

Ok(solved_records)
}

/// Find the globally installed package with the given [`PackageName`]
///
/// # Returns
Expand All @@ -128,7 +187,7 @@ pub(super) async fn find_installed_package(
find_designated_package(&prefix, package_name).await
}

/// Find the designated package in the given [`Prefix`]
/// Find the designated package in the given prefix
///
/// # Returns
///
Expand Down
66 changes: 17 additions & 49 deletions src/cli/global/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,28 @@ use std::{
use clap::Parser;
use indexmap::IndexMap;
use itertools::Itertools;
use miette::{Context, IntoDiagnostic};
use miette::IntoDiagnostic;

use pixi_utils::reqwest::build_reqwest_clients;
use rattler::{
install::{DefaultProgressFormatter, IndicatifReporter, Installer},
package_cache::PackageCache,
};
use rattler_conda_types::{
GenericVirtualPackage, MatchSpec, PackageName, Platform, PrefixRecord, RepoDataRecord,
};
use rattler_conda_types::{MatchSpec, PackageName, Platform, PrefixRecord, RepoDataRecord};
use rattler_shell::{
activation::{ActivationVariables, Activator, PathModificationBehavior},
shell::{Shell, ShellEnum},
};
use rattler_solve::{resolvo::Solver, SolverImpl, SolverTask};
use rattler_virtual_packages::VirtualPackage;
use reqwest_middleware::ClientWithMiddleware;

use super::common::{channel_name_from_prefix, find_designated_package, BinDir, BinEnvDir};
use crate::{
cli::cli_config::ChannelsConfig, cli::has_specs::HasSpecs, prefix::Prefix,
cli::{cli_config::ChannelsConfig, global::common::solve_package_records, has_specs::HasSpecs},
prefix::Prefix,
rlimit::try_increase_rlimit_to_sensible,
};
use pixi_config::{self, Config, ConfigCli};
use pixi_progress::{await_in_progress, global_multi_progress, wrap_in_progress};
use pixi_progress::{await_in_progress, global_multi_progress};

/// Installs the defined package in a global accessible location.
#[derive(Parser, Debug)]
Expand Down Expand Up @@ -286,8 +284,8 @@ pub fn prompt_user_to_continue(

/// Install a global command
pub async fn execute(args: Args) -> miette::Result<()> {
// Figure out what channels we are using
let config = Config::with_cli_config(&args.config);
let (_, client) = build_reqwest_clients(Some(&config));
let channels = args.channels.resolve_from_config(&config);

let specs = args.specs()?;
Expand All @@ -297,52 +295,22 @@ pub async fn execute(args: Args) -> miette::Result<()> {
return Ok(());
}

// Fetch the repodata
let (_, auth_client) = build_reqwest_clients(Some(&config));

let gateway = config.gateway(auth_client.clone());

let repodata = gateway
.query(
channels,
[args.platform, Platform::NoArch],
specs.values().cloned().collect_vec(),
)
.recursive(true)
.await
.into_diagnostic()?;

// Determine virtual packages of the current platform
let virtual_packages = VirtualPackage::current()
.into_diagnostic()
.context("failed to determine virtual packages")?
.iter()
.cloned()
.map(GenericVirtualPackage::from)
.collect();

// Solve the environment
let solver_specs = specs.clone();
let solved_records = wrap_in_progress("solving environment", move || {
Solver.solve(SolverTask {
specs: solver_specs.values().cloned().collect_vec(),
virtual_packages,
..SolverTask::from_iter(&repodata)
})
})
.into_diagnostic()
.context("failed to solve environment")?;
// Construct a gateway to get repodata.
let gateway = config.gateway(client.clone());

// Install the package(s)
let mut executables = vec![];
for (package_name, _) in specs {
let (prefix_package, scripts, _) = globally_install_package(
&package_name,
solved_records.clone(),
auth_client.clone(),
for (package_name, package_matchspec) in specs {
let records = solve_package_records(
&gateway,
args.platform,
channels.clone(),
vec![package_matchspec],
)
.await?;

let (prefix_package, scripts, _) =
globally_install_package(&package_name, records, client.clone(), args.platform).await?;
let channel_name =
channel_name_from_prefix(&prefix_package, config.global_channel_config());
let record = &prefix_package.repodata_record.package_record;
Expand Down
2 changes: 1 addition & 1 deletion src/cli/global/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use clap::Parser;

mod common;
pub mod common;
mod install;
mod list;
mod remove;
Expand Down
Loading
Loading