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

Add front-end implementation for conda-standalone uninstall subcommand #897

Merged
merged 26 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
b38e95c
Add option to use standalone binary for uninstallation
marcoesters Oct 11, 2024
c323060
Add conda-standalone uninstall to NSIS template
marcoesters Oct 11, 2024
21fc398
Use AbortRetryNSExecWait to call conda-standalone uninstaller
marcoesters Oct 17, 2024
292e2ba
Add uninstallation options panel
marcoesters Oct 29, 2024
d5e11b5
Improve typing for uninstall command templating
marcoesters Oct 29, 2024
67d3620
Implement conda-standalone uninstall command into Windows uninstaller…
marcoesters Oct 30, 2024
00b1608
Add standalone uninstaller options panel
marcoesters Nov 1, 2024
e102de6
Merge branch 'main' of github.com:conda/constructor into uninstall-st…
marcoesters Nov 11, 2024
a5b3ac3
Update documentation
marcoesters Nov 11, 2024
9ecf634
Make /RemoceCondaRcs CLI parsing logic more concise
marcoesters Nov 12, 2024
4209d7b
Add tests
marcoesters Nov 12, 2024
f6e5d83
Add news file
marcoesters Nov 13, 2024
7efbc74
Replace pipe operator with Union
marcoesters Nov 13, 2024
d1f221d
Ensure that ON_CI=False for CI="0"
marcoesters Nov 18, 2024
19dc456
Update uninstallation commands
marcoesters Nov 25, 2024
014f69f
Update CLI options documentation
marcoesters Nov 25, 2024
d851c57
Update uninstaller documentation
marcoesters Nov 25, 2024
837a741
Update description of uninstallation options in the GUI
marcoesters Nov 25, 2024
af2fcad
Merge branch 'main' of github.com:conda/constructor into uninstall-st…
marcoesters Nov 25, 2024
e07a541
Replace UNINSTALL_MENUS with UNINSTALL_COMMANDS
marcoesters Nov 25, 2024
23f913a
Fix jinja syntax
marcoesters Nov 25, 2024
a663b24
Document uninstaller subcommand for Unix
marcoesters Dec 2, 2024
4ed7cb0
Merge branch 'main' into uninstall-standalone
jaimergp Dec 5, 2024
d3ed416
Debug: print directory contents for standalone uninstaller
marcoesters Dec 5, 2024
c8ee571
Merge branch 'uninstall-standalone' of github.com:marcoesters/constru…
marcoesters Dec 5, 2024
152abb2
Always remove installation directory
marcoesters Dec 5, 2024
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
8 changes: 8 additions & 0 deletions CONSTRUCT.md
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,14 @@ Allowed keys are:
license text. Only relevant if include_text is True. Any str accepted by open()'s 'errors'
argument is valid. See https://docs.python.org/3/library/functions.html#open.

### `uninstall_with_conda_exe`

_required:_ no<br/>
_type:_ boolean<br/>

Use the standalone binary to perform the uninstallation.
Requires conda-standalone 24.11.0 or newer.


## Available selectors
- `aarch64`
Expand Down
5 changes: 5 additions & 0 deletions constructor/construct.py
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,11 @@
- `text_errors` (optional str, default=`None`): How to handle decoding errors when reading the
license text. Only relevant if include_text is True. Any str accepted by open()'s 'errors'
argument is valid. See https://docs.python.org/3/library/functions.html#open.
'''),

('uninstall_with_conda_exe', False, bool, '''
Use the standalone binary to perform the uninstallation.
Requires conda-standalone 24.11.0 or newer.
'''),
]

Expand Down
10 changes: 9 additions & 1 deletion constructor/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,14 @@ def main_build(dir_path, output_dir='.', platform=cc_platform,
# TODO: Investigate errors on Windows and re-enable
sys.exit("Error: micromamba is not supported on Windows installers.")

if (
info.get("uninstall_with_conda_exe")
and not (
exe_type == StandaloneExe.CONDA and exe_version and exe_version >= Version("24.11.0")
)
):
sys.exit("Error: uninstalling with conda.exe requires conda-standalone 24.11.0 or newer.")

logger.debug('conda packages download: %s', info['_download_dir'])

for key in ('welcome_image_text', 'header_image_text'):
Expand Down Expand Up @@ -184,7 +192,7 @@ def main_build(dir_path, output_dir='.', platform=cc_platform,
"Will assume it is compatible with shortcuts."
)
elif sys.platform != "win32" and (
exe_type != StandaloneExe.CONDA or exe_version < Version("23.11.0")
exe_type != StandaloneExe.CONDA or (exe_version and exe_version < Version("23.11.0"))
):
logger.warning("conda-standalone 23.11.0 or above is required for shortcuts on Unix.")
info['_enable_shortcuts'] = "incompatible"
Expand Down
109 changes: 109 additions & 0 deletions constructor/nsis/StandaloneUninstallerOptions.nsh
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
var UninstCustomOptions
var UninstCustomOptions.RemoveCondaRcs_User
var UninstCustomOptions.RemoveCondaRcs_System
var UninstCustomOptions.RemoveCaches
var UninstCustomOptions.CondaClean

# These are the checkbox states, to be used by the uninstaller
var UninstRemoveCondaRcs_User_State
var UninstRemoveCondaRcs_System_State
var UninstRemoveCaches_State
var UninstCondaClean_State

Function un.UninstCustomOptions_InitDefaults
StrCpy $UninstRemoveCondaRcs_User_State ${BST_UNCHECKED}
StrCpy $UninstRemoveCondaRcs_System_State ${BST_UNCHECKED}
StrCpy $UninstRemoveCaches_State ${BST_UNCHECKED}
StrCpy $UninstCondaClean_State ${BST_UNCHECKED}
FunctionEnd

Function un.UninstCustomOptions_Show
${If} $UninstCondaClean_State == ""
Abort
${EndIf}
# Create dialog
nsDialogs::Create 1018
Pop $UninstCustomOptions
${If} $UninstCustomOptions == error
Abort
${EndIf}

!insertmacro MUI_HEADER_TEXT \
"Advanced uninstallation options" \
"Remove configuration and cache files"

# We will use $5 as the y axis accumulator, starting at 0
# We sum the the number of 'u' units added by 'NSD_Create*' functions
IntOp $5 0 + 0

# Option to remove .condarc files
${NSD_CreateCheckbox} 0 "$5u" 100% 11u "Remove user configuration files."
IntOp $5 $5 + 11
Pop $UninstCustomOptions.RemoveCondaRcs_User
${NSD_SetState} $UninstCustomOptions.RemoveCondaRcs_User $UninstRemoveCondaRcs_User_State
${NSD_OnClick} $UninstCustomOptions.RemoveCondaRcs_User un.UninstRemoveCondarcs_User_Onclick
${NSD_CreateLabel} 5% "$5u" 90% 10u \
"This removes .condarc files in the Users directory."
IntOp $5 $5 + 10

${If} ${UAC_IsAdmin}
${NSD_CreateCheckbox} 0 "$5u" 100% 11u "Remove system-wide configuration files."
IntOp $5 $5 + 11
Pop $UninstCustomOptions.RemoveCondaRcs_System
${NSD_SetState} $UninstCustomOptions.RemoveCondaRcs_System $UninstRemoveCondaRcs_System_State
${NSD_OnClick} $UninstCustomOptions.RemoveCondaRcs_System un.UninstRemoveCondarcs_System_Onclick
${NSD_CreateLabel} 5% "$5u" 90% 10u \
"This removes .condarc files in the ProgramData directory."
IntOp $5 $5 + 10
${EndIf}

# Option to remove cache files
${NSD_CreateCheckbox} 0 "$5u" 100% 11u "Remove cache files."
IntOp $5 $5 + 11
Pop $UninstCustomOptions.RemoveCaches
${NSD_SetState} $UninstCustomOptions.RemoveCaches $UninstRemoveCaches_State
${NSD_OnClick} $UninstCustomOptions.RemoveCaches un.UninstRemoveCaches_Onclick
${NSD_CreateLabel} 5% "$5u" 90% 10u \
"This removes the .conda directory in the user folder and conda system cache files."
IntOp $5 $5 + 10

# Option to run conda --clean
${NSD_CreateCheckbox} 0 "$5u" 100% 11u "Remove index and package files."
IntOp $5 $5 + 11
Pop $UninstCustomOptions.CondaClean
${NSD_SetState} $UninstCustomOptions.CondaClean $UninstCondaClean_State
${NSD_OnClick} $UninstCustomOptions.CondaClean un.UninstCondaClean_Onclick
${NSD_CreateLabel} 5% "$5u" 90% 20u \
"This removes index and unused package files by running conda clean --all. \
Only useful if pkgs_dirs is set in a .condarc file."
IntOp $5 $5 + 20

IntOp $5 $5 + 5
${NSD_CreateLabel} 0 "$5u" 100% 10u \
"These options are not recommended if multiple conda installations exist on the same system."
IntOp $5 $5 + 10
Pop $R0
SetCtlColors $R0 ff0000 transparent

nsDialogs::Show
FunctionEnd

Function un.UninstRemoveCondarcs_User_OnClick
Pop $0
${NSD_GetState} $0 $UninstRemoveCondarcs_User_State
FunctionEnd

Function un.UninstRemoveCondarcs_System_OnClick
Pop $0
${NSD_GetState} $0 $UninstRemoveCondarcs_System_State
FunctionEnd

Function un.UninstRemoveCaches_OnClick
Pop $0
${NSD_GetState} $0 $UninstRemoveCaches_State
FunctionEnd

Function un.UninstCondaClean_OnClick
Pop $0
${NSD_GetState} $0 $UninstCondaClean_State
FunctionEnd
90 changes: 76 additions & 14 deletions constructor/nsis/main.nsi.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ var /global StdOutHandleSet

!include "Utils.nsh"

#if uninstall_with_conda_exe is True
!include "StandaloneUninstallerOptions.nsh"
#endif

!define NAME __NAME__
!define VERSION __VERSION__
!define COMPANY __COMPANY__
Expand Down Expand Up @@ -110,6 +114,11 @@ var /global ARGV_NoScripts
var /global ARGV_NoShortcuts
var /global ARGV_CheckPathLength
var /global ARGV_QuietMode
#if uninstall_with_conda_exe is True
var /global ARGV_Uninst_RemoveCondaRcs
var /global ARGV_Uninst_RemoveCaches
var /global ARGV_Uninst_CondaClean
#endif

var /global IsDomainUser
var /global CheckPathLength
Expand Down Expand Up @@ -203,6 +212,9 @@ Page Custom mui_AnaCustomOptions_Show
!insertmacro MUI_UNPAGE_WELCOME
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE un.OnDirectoryLeave
!insertmacro MUI_UNPAGE_CONFIRM
#if uninstall_with_conda_exe is True
UninstPage Custom un.UninstCustomOptions_Show
#endif
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_UNPAGE_FINISH

Expand Down Expand Up @@ -742,7 +754,7 @@ Function .onInit
Pop $0
FunctionEnd

Function un.onInit
!macro un.ParseCommandLineArgs
ClearErrors
${GetParameters} $ARGV
${GetOptions} $ARGV "/?" $ARGV_Help
Expand All @@ -762,6 +774,11 @@ Function un.onInit
/? (show this help message)$\n\
/S (run in CLI/headless mode)$\n\
/Q (quiet mode, do not print output to console)$\n\
#if uninstall_with_conda_exe is True
/RemoveCondaRcs=[none|users|system|all] [default: none]$\n\
/RemoveCaches=[0|1] [default: 0]$\n\
/CondaClean=[0|1] [default: 0]$\n\
#endif
/_?=[installation directory] (must be last parameter)$\n\
$\n\
EXAMPLES$\n\
Expand All @@ -773,8 +790,7 @@ Function un.onInit
Closing in 10s..."
# Give it some time so users can read it the pop-up console
# The pop-up console happens because the uninstaller copies itself to
# a temporary location because actually running, so we can't get the parent
# console handle
# a temporary location, so we can't get the parent console handle
Sleep 10000
Abort
${EndIf}
Expand All @@ -784,6 +800,59 @@ Function un.onInit
${IfNot} ${Errors}
StrCpy $QuietMode "1"
${EndIf}
#if uninstall_with_conda_exe is True
ClearErrors
${GetOptions} $ARGV "/RemoveCondaRcs=" $ARGV_Uninst_RemoveCondaRcs
${IfNot} ${Errors}
${IfNot} ${UAC_IsAdmin}
${If} $ARGV_Uninst_RemoveCondaRcs == "all"
${OrIf} $ARGV_Uninst_RemoveCondaRcs == "system"
MessageBox MB_ICONSTOP "Removing system .condarc files requires an elevated prompt."
Abort
${EndIf}
${EndIf}
${If} $ARGV_Uninst_RemoveCondaRcs == "user"
StrCpy $UninstRemoveCondaRcs_User_State ${BST_CHECKED}
StrCpy $UninstRemoveCondaRcs_System_State ${BST_UNCHECKED}
${ElseIf} $ARGV_Uninst_RemoveCondaRcs == "system"
StrCpy $UninstRemoveCondaRcs_User_State ${BST_UNCHECKED}
StrCpy $UninstRemoveCondaRcs_System_State ${BST_CHECKED}
${ElseIf} $ARGV_Uninst_RemoveCondaRcs == "all"
StrCpy $UninstRemoveCondaRcs_User_State ${BST_CHECKED}
StrCpy $UninstRemoveCondaRcs_System_State ${BST_CHECKED}
${Else}
StrCpy $UninstRemoveCondaRcs_User_State ${BST_UNCHECKED}
StrCpy $UninstRemoveCondaRcs_System_State ${BST_UNCHECKED}
${EndIf}
${EndIf}

ClearErrors
${GetOptions} $ARGV "/RemoveCaches=" $ARGV_Uninst_RemoveCaches
${IfNot} ${Errors}
${If} $ARGV_Uninst_RemoveCaches = "1"
StrCpy $UninstRemoveCaches_State ${BST_CHECKED}
${ElseIf} $ARGV_Uninst_RemoveCaches = "0"
StrCpy $UninstRemoveCaches_State ${BST_UNCHECKED}
${EndIf}
${EndIf}

ClearErrors
${GetOptions} $ARGV "/CondaClean=" $ARGV_Uninst_CondaClean
${IfNot} ${Errors}
${If} $ARGV_Uninst_CondaClean = "1"
StrCpy $UninstCondaClean_State ${BST_CHECKED}
${ElseIf} $ARGV_Uninst_CondaClean = "0"
StrCpy $UninstCondaClean_State ${BST_UNCHECKED}
${EndIf}
${EndIf}
#endif
!macroend

Function un.onInit

#if uninstall_with_conda_exe is True
Call un.UninstCustomOptions_InitDefaults
#endif

Push $0
Push $1
Expand Down Expand Up @@ -1410,10 +1479,11 @@ SectionEnd

Section "Uninstall"
${LogSet} on
${If} ${Silent}
!insertmacro un.ParseCommandLineArgs
${EndIf}

# Remove menu items, path entries
System::Call 'kernel32::SetEnvironmentVariable(t,t)i("CONDA_ROOT_PREFIX", "$INSTDIR")".r0'
@UNINSTALL_MENUS@

# ensure that MSVC runtime DLLs are on PATH during uninstallation
ReadEnvStr $0 PATH
Expand Down Expand Up @@ -1463,15 +1533,7 @@ Section "Uninstall"
System::Call 'kernel32::SetEnvironmentVariable(t,t)i("INSTALLER_UNATTENDED", "0").r0'
${EndIf}

!insertmacro AbortRetryNSExecWaitLibNsisCmd "pre_uninstall"
!insertmacro AbortRetryNSExecWaitLibNsisCmd "rmpath"
!insertmacro AbortRetryNSExecWaitLibNsisCmd "rmreg"

${Print} "Removing files and folders..."
nsExec::Exec 'cmd.exe /D /C RMDIR /Q /S "$INSTDIR"'

# In case the last command fails, run the slow method to remove leftover
RMDir /r /REBOOTOK "$INSTDIR"
@UNINSTALL_COMMANDS@

${If} $INSTALLER_NAME_FULL != ""
DeleteRegKey SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$INSTALLER_NAME_FULL"
Expand Down
Loading
Loading