Skip to content

Commit e7760fd

Browse files
Remove frozen environment protection files during uninstallation (#180)
* Add functionality to find and remove frozen files * Optimize frozen file search * First pass at testing frozen file removal * First pass at testing frozen file removal * Move out of main function * Handle potential permissions errors * Add test_uninstallation_frozen_environment * Test across multiple frozen environments * Remove old code * Setup custom envs dir * Add news file * Apply suggestions from code review Co-authored-by: Marco Esters <mesters@anaconda.com> * Leverage existing env dir detection * Revert to testing only one environment * Use tmp_env instead of conda_cli * Apply suggestions from code review Co-authored-by: Marco Esters <mesters@anaconda.com> --------- Co-authored-by: Marco Esters <mesters@anaconda.com>
1 parent 8294d60 commit e7760fd

File tree

3 files changed

+51
-5
lines changed

3 files changed

+51
-5
lines changed

news/180-remove-frozen-files

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
### Enhancements
2+
3+
* Remove frozen environment protection files before environment removal during uninstallation. (#180)
4+
5+
### Bug fixes
6+
7+
* <news item>
8+
9+
### Deprecations
10+
11+
* <news item>
12+
13+
### Docs
14+
15+
* <news item>
16+
17+
### Other
18+
19+
* <news item>

src/conda_constructor/uninstall.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from pathlib import Path
55
from shutil import rmtree
66

7-
from conda.base.constants import COMPATIBLE_SHELLS, PREFIX_MAGIC_FILE
7+
from conda.base.constants import COMPATIBLE_SHELLS, PREFIX_FROZEN_FILE, PREFIX_MAGIC_FILE
88
from conda.base.context import context, reset_context
99
from conda.cli.main import main as conda_main
1010
from conda.common.compat import on_win
@@ -32,7 +32,7 @@ def _is_subdir(directory: Path, root: Path) -> bool:
3232
return directory == root or root in directory.parents
3333

3434

35-
def _remove_file_directory(file: Path):
35+
def _remove_file_directory(file: Path, raise_on_error: bool = False):
3636
"""
3737
Try to remove a file or directory.
3838
@@ -45,8 +45,12 @@ def _remove_file_directory(file: Path):
4545
rmtree(file)
4646
elif file.is_symlink() or file.is_file():
4747
file.unlink()
48-
except PermissionError:
49-
pass
48+
except PermissionError as e:
49+
if raise_on_error:
50+
raise PermissionError(
51+
f"Could not remove {file}. "
52+
"You may need to re-run with elevated privileges or manually remove this file."
53+
) from e
5054

5155

5256
def _remove_config_file_and_parents(file: Path):
@@ -201,6 +205,11 @@ def _remove_environments(prefix: Path, prefixes: list[Path]):
201205
# Otherwise, parent environments will delete the environment directory and
202206
# uninstallation logic (removing shortcuts, pre-unlink scripts, etc.) cannot be run.
203207
for env_prefix in reversed(prefixes):
208+
# Unprotect frozen environments first
209+
frozen_file = env_prefix / PREFIX_FROZEN_FILE
210+
if frozen_file.is_file():
211+
_remove_file_directory(frozen_file, raise_on_error=True)
212+
204213
install_shortcut(env_prefix, root_prefix=menuinst_base_prefix, remove=True)
205214
# If conda_root_prefix is the same as prefix, conda remove will not be able
206215
# to remove that environment, so temporarily unset it.

tests/test_uninstall.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from typing import TYPE_CHECKING
1010

1111
import pytest
12-
from conda.base.constants import COMPATIBLE_SHELLS
12+
from conda.base.constants import COMPATIBLE_SHELLS, PREFIX_FROZEN_FILE
1313
from conda.common.path import win_path_to_unix
1414
from conda.core.initialize import (
1515
Result,
@@ -114,6 +114,24 @@ def test_uninstallation(
114114
assert str(base_env) not in environments and str(second_env) in environments
115115

116116

117+
def test_uninstallation_frozen_environment(
118+
tmp_env: TmpEnvFixture,
119+
):
120+
"""Test that frozen environments are removed during uninstallation."""
121+
with tmp_env() as frozen_env:
122+
# Create frozen file in the environment
123+
frozen_file = frozen_env / PREFIX_FROZEN_FILE
124+
frozen_file.touch()
125+
assert frozen_file.exists()
126+
127+
# Run uninstaller on the environment
128+
run_uninstaller(frozen_env)
129+
130+
# Verify frozen file and environment are removed
131+
assert not frozen_file.exists()
132+
assert not frozen_env.exists()
133+
134+
117135
@pytest.mark.parametrize("remove", (True, False), ids=("remove directory", "keep directory"))
118136
def test_uninstallation_envs_dirs(
119137
mock_system_paths: dict[str, Path],

0 commit comments

Comments
 (0)