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

fix: interactively delete environment when it was relocated #1102

Merged
merged 1 commit into from
Apr 2, 2024
Merged
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
fix: issue 1081
  • Loading branch information
baszalmstra committed Apr 2, 2024
commit 1495ce8f9a9b8599d950b85da7340b3ef97692c9
2 changes: 1 addition & 1 deletion src/cli/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ pub async fn execute(args: Args) -> miette::Result<()> {
let spec_platforms = &args.platform;

// Sanity check of prefix location
verify_prefix_location_unchanged(project.default_environment().dir().as_path())?;
verify_prefix_location_unchanged(project.default_environment().dir().as_path()).await?;

// Add the platform if it is not already present
let platforms_to_add = spec_platforms
Expand Down
2 changes: 1 addition & 1 deletion src/cli/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ pub async fn execute(args: Args) -> miette::Result<()> {
Project::load_or_else_discover(args.manifest_path.as_deref())?.with_cli_config(args.config);

// Sanity check of prefix location
verify_prefix_location_unchanged(project.default_environment().dir().as_path())?;
verify_prefix_location_unchanged(project.default_environment().dir().as_path()).await?;

// Extract the passed in environment name.
let explicit_environment = args
Expand Down
66 changes: 51 additions & 15 deletions src/environment.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::lock_file::UvResolutionContext;
use crate::progress::await_in_progress;
use crate::project::grouped_environment::GroupedEnvironmentName;
use crate::{
consts, install, install_pypi,
Expand All @@ -13,8 +14,9 @@ use crate::{
},
Project,
};
use dialoguer::theme::ColorfulTheme;
use indexmap::IndexMap;
use miette::IntoDiagnostic;
use miette::{IntoDiagnostic, WrapErr};
use rattler::{
install::{PythonInfo, Transaction},
package_cache::PackageCache,
Expand All @@ -23,12 +25,13 @@ use rattler_conda_types::{Channel, Platform, PrefixRecord, RepoDataRecord};
use rattler_lock::{PypiPackageData, PypiPackageEnvironmentData};
use rattler_repodata_gateway::sparse::SparseRepoData;
use reqwest_middleware::ClientWithMiddleware;
use std::convert::identity;
use std::{collections::HashMap, io::ErrorKind, path::Path, sync::Arc};

/// Verify the location of the prefix folder is not changed so the applied prefix path is still valid.
/// Errors when there is a file system error or the path does not align with the defined prefix.
/// Returns false when the file is not present.
pub fn verify_prefix_location_unchanged(environment_dir: &Path) -> miette::Result<()> {
pub async fn verify_prefix_location_unchanged(environment_dir: &Path) -> miette::Result<()> {
let prefix_file = environment_dir
.join("conda-meta")
.join(consts::PREFIX_FILE_NAME);
Expand All @@ -48,16 +51,49 @@ pub fn verify_prefix_location_unchanged(environment_dir: &Path) -> miette::Resul
}
// Check if the path in the file aligns with the current path.
Ok(p) if prefix_file.starts_with(&p) => Ok(()),
Ok(p) => Err(miette::miette!(
"the project location seems to be change from `{}` to `{}`, this is not allowed.\
\nPlease remove the `{}` folder and run again",
p,
prefix_file
.parent()
.expect("prefix_file should always be a file")
.display(),
consts::PIXI_DIR
)),
Ok(p) => {
let path = Path::new(&p);
prefix_location_changed(environment_dir, path.parent().unwrap_or(path)).await
}
}
}

/// Called when the prefix has moved to a new location.
///
/// Allows interactive users to delete the location and continue.
async fn prefix_location_changed(
environment_dir: &Path,
previous_dir: &Path,
) -> miette::Result<()> {
let theme = ColorfulTheme {
active_item_style: console::Style::new().for_stderr().magenta(),
..ColorfulTheme::default()
};

let user_value = dialoguer::Confirm::with_theme(&theme)
.with_prompt(format!(
"The environment directory seems have to moved! Environments are non-relocatable, moving them can cause issues.\n\n\t{} -> {}\n\nThis can be fixed by reinstall the environment from the lock-file in the new location.\n\nDo you want to automatically recreate the environment?",
previous_dir.display(),
environment_dir.display()
))
.report(false)
.default(true)
.interact_opt()
.map_or(None, identity);
if user_value == Some(true) {
await_in_progress("removing old environment", |_| {
tokio::fs::remove_dir_all(environment_dir)
})
.await
.into_diagnostic()
.context("failed to remove old environment directory")?;
Ok(())
} else {
Err(miette::diagnostic!(
help = "Remove the environment directory, pixi will recreate it on the next run.",
"The environment directory has moved from `{}` to `{}`. Environments are non-relocatable, moving them can cause issues.", previous_dir.display(), environment_dir.display()
)
.into())
}
}

Expand Down Expand Up @@ -113,9 +149,9 @@ fn create_history_file(environment_dir: &Path) -> miette::Result<()> {
/// 1. It verifies that the prefix location is unchanged.
/// 2. It verifies that the system requirements are met.
/// 3. It verifies the absence of the `env` folder.
pub fn sanity_check_project(project: &Project) -> miette::Result<()> {
pub async fn sanity_check_project(project: &Project) -> miette::Result<()> {
// Sanity check of prefix location
verify_prefix_location_unchanged(project.default_environment().dir().as_path())?;
verify_prefix_location_unchanged(project.default_environment().dir().as_path()).await?;

// Make sure the system requirements are met
verify_current_platform_has_required_virtual_packages(&project.default_environment())
Expand Down Expand Up @@ -188,7 +224,7 @@ pub async fn get_up_to_date_prefix(
}

// Make sure the project is in a sane state
sanity_check_project(project)?;
sanity_check_project(project).await?;

// Ensure that the lock-file is up-to-date
let mut lock_file = project
Expand Down
Loading