From 355a50811807413bceccafd8f2a453e7e9e7a18e Mon Sep 17 00:00:00 2001 From: Robin Date: Tue, 11 Nov 2025 16:43:46 -0500 Subject: [PATCH 01/14] Fix inconsistency in options --- constructor/nsis/OptionsDialog.nsh | 118 +++++++++--- constructor/nsis/main.nsi.tmpl | 175 ++++++++++-------- constructor/winexe.py | 2 - examples/custom_nsis_template/custom.nsi.tmpl | 2 - news/1105-improve-handling-of-certain-options | 20 ++ 5 files changed, 210 insertions(+), 107 deletions(-) create mode 100644 news/1105-improve-handling-of-certain-options diff --git a/constructor/nsis/OptionsDialog.nsh b/constructor/nsis/OptionsDialog.nsh index 0b5f15c6d..2b687962f 100644 --- a/constructor/nsis/OptionsDialog.nsh +++ b/constructor/nsis/OptionsDialog.nsh @@ -14,8 +14,6 @@ Var mui_AnaCustomOptions.ClearPkgCache Var mui_AnaCustomOptions.CreateShortcuts # These are the checkbox states, to be used by the installer -Var Ana_AddToPath_State -Var Ana_RegisterSystemPython_State Var Ana_PostInstall_State Var Ana_PreInstall_State Var Ana_ClearPkgCache_State @@ -28,9 +26,18 @@ Var Ana_PostInstall_Label Var Ana_PreInstall_Label Function mui_AnaCustomOptions_InitDefaults - # Initialize defaults - ${If} $Ana_AddToPath_State == "" - StrCpy $Ana_AddToPath_State ${BST_UNCHECKED} + # AddToPath / conda init default + !if ${INIT_CONDA_OPTION} == 1 + # Ensure we initialize from compile-time default value + StrCpy $INIT_CONDA ${INIT_CONDA_DEFAULT_VALUE} + !else + StrCpy $INIT_CONDA 0 + !endif + + # Register Python default + !if ${REGISTER_PYTHON_OPTION} == 1 + # Ensure we initialize from compile-time default value + StrCpy $REG_PY ${REGISTER_PYTHON_DEFAULT_VALUE} # Default whether to register as system python as: # Enabled - if no system python is registered, OR # a system python which does not exist is registered. @@ -38,11 +45,13 @@ Function mui_AnaCustomOptions_InitDefaults ReadRegStr $2 SHCTX "Software\Python\PythonCore\${PY_VER}\InstallPath" "" ${If} "$2" != "" ${AndIf} ${FileExists} "$2\Python.exe" - StrCpy $Ana_RegisterSystemPython_State ${BST_UNCHECKED} - ${Else} - StrCpy $Ana_RegisterSystemPython_State ${BST_CHECKED} + StrCpy $REG_PY 0 ${EndIf} - ${EndIf} + !else + StrCpy $REG_PY 0 + !endif + + # Shortcuts defaults ${If} $Ana_CreateShortcuts_State == "" ${If} "${ENABLE_SHORTCUTS}" == "yes" StrCpy $Ana_CreateShortcuts_State ${BST_CHECKED} @@ -57,7 +66,7 @@ FunctionEnd Function mui_AnaCustomOptions_Show ; Enforce that the defaults were initialized - ${If} $Ana_AddToPath_State == "" + ${If} $INIT_CONDA == "" Abort ${EndIf} @@ -84,7 +93,7 @@ Function mui_AnaCustomOptions_Show ${NSD_OnClick} $mui_AnaCustomOptions.CreateShortcuts CreateShortcuts_OnClick ${EndIf} - ${If} "${SHOW_ADD_TO_PATH}" != "no" + !if ${INIT_CONDA_OPTION} == 1 # AddToPath is only an option for JustMe installations; it is disabled for AllUsers # installations. (Addresses CVE-2022-26526) ${If} $InstMode = ${JUST_ME} @@ -92,9 +101,18 @@ Function mui_AnaCustomOptions_Show environment variable" IntOp $5 $5 + 11 Pop $mui_AnaCustomOptions.AddToPath - ${NSD_SetState} $mui_AnaCustomOptions.AddToPath $Ana_AddToPath_State + + # Set state of check-box + ${If} $INIT_CONDA == 1 + ${NSD_Check} $mui_AnaCustomOptions.AddToPath + ${Else} + ${NSD_Uncheck} $mui_AnaCustomOptions.AddToPath + ${EndIf} + ${NSD_OnClick} $mui_AnaCustomOptions.AddToPath AddToPath_OnClick - ${If} "${SHOW_ADD_TO_PATH}" == "condabin" + + # Account for the conda mode + ${If} "${INIT_CONDA_MODE}" == "condabin" ${NSD_CreateLabel} 5% "$5u" 90% 20u \ "Adds condabin/, which only contains the 'conda' executables, to PATH. \ Does not require special shortcuts but activation needs \ @@ -107,26 +125,54 @@ Function mui_AnaCustomOptions_Show ${EndIf} IntOp $5 $5 + 20 Pop $Ana_AddToPath_Label + + # Color the label if needed; even if the user has not interacted with the checkbox yet + ${If} $INIT_CONDA = 1 + ${If} "${INIT_CONDA_MODE}" == "classic" + SetCtlColors $Ana_AddToPath_Label ff0000 transparent + ${Else} + # Here INIT_CONDA_MODE equals condabin + SetCtlColors $Ana_AddToPath_Label 000000 transparent + ${EndIf} + ${Else} + SetCtlColors $Ana_AddToPath_Label 000000 transparent + ${EndIf} ${EndIf} - ${EndIf} + !endif - ${If} "${SHOW_REGISTER_PYTHON}" == "yes" + !if ${REGISTER_PYTHON_OPTION} == 1 ${If} $InstMode = ${JUST_ME} StrCpy $1 "my default" ${Else} StrCpy $1 "the system" ${EndIf} + ${NSD_CreateCheckbox} 0 "$5u" 100% 11u "&Register ${NAME} as $1 Python ${PY_VER}" IntOp $5 $5 + 11 Pop $mui_AnaCustomOptions.RegisterSystemPython - ${NSD_SetState} $mui_AnaCustomOptions.RegisterSystemPython $Ana_RegisterSystemPython_State + + # Set state of check-box + ${If} $REG_PY == 1 + ${NSD_Check} $mui_AnaCustomOptions.RegisterSystemPython + ${Else} + ${NSD_Uncheck} $mui_AnaCustomOptions.RegisterSystemPython + ${EndIf} + ${NSD_OnClick} $mui_AnaCustomOptions.RegisterSystemPython RegisterSystemPython_OnClick + ${NSD_CreateLabel} 5% "$5u" 90% 20u \ "Allows other programs, such as VSCode, PyCharm, etc. to automatically \ detect ${NAME} as the primary Python ${PY_VER} on the system." IntOp $5 $5 + 20 Pop $Ana_RegisterSystemPython_Label - ${EndIf} + + # Color the label if needed; even if the user has not interacted with the checkbox yet + ${If} $REG_PY = 1 + SetCtlColors $Ana_RegisterSystemPython_Label ff0000 transparent + ${Else} + SetCtlColors $Ana_RegisterSystemPython_Label 000000 transparent + ${EndIf} + !endif ${NSD_CreateCheckbox} 0 "$5u" 100% 11u "Clear the package cache upon completion" @@ -167,15 +213,22 @@ FunctionEnd Function AddToPath_OnClick Pop $0 - ShowWindow $Ana_AddToPath_Label ${SW_HIDE} - ${NSD_GetState} $0 $Ana_AddToPath_State - ${If} $Ana_AddToPath_State == ${BST_UNCHECKED} + # Sync UI with variable + ${NSD_GetState} $0 $1 + ${If} $1 == ${BST_CHECKED} + StrCpy $INIT_CONDA 1 ${Else} - ${If} "${SHOW_ADD_TO_PATH}" == "condabin" - SetCtlColors $Ana_AddToPath_Label 000000 transparent - ${Else} + StrCpy $INIT_CONDA 0 + ${EndIf} + + ShowWindow $Ana_AddToPath_Label ${SW_HIDE} + # Only color it red if it's classic + ${If} $INIT_CONDA == 1 + ${If} "${INIT_CONDA_MODE}" == "classic" SetCtlColors $Ana_AddToPath_Label ff0000 transparent ${EndIf} + ${Else} + SetCtlColors $Ana_AddToPath_Label 000000 transparent ${EndIf} ShowWindow $Ana_AddToPath_Label ${SW_SHOW} FunctionEnd @@ -183,9 +236,16 @@ FunctionEnd Function RegisterSystemPython_OnClick Pop $0 + # Sync UI with variable + ${NSD_GetState} $0 $1 + ${If} $1 == ${BST_CHECKED} + StrCpy $REG_PY 1 + ${Else} + StrCpy $REG_PY 0 + ${EndIf} + ShowWindow $Ana_RegisterSystemPython_Label ${SW_HIDE} - ${NSD_GetState} $0 $Ana_RegisterSystemPython_State - ${If} $Ana_RegisterSystemPython_State == ${BST_UNCHECKED} + ${If} $REG_PY == 1 SetCtlColors $Ana_RegisterSystemPython_Label ff0000 transparent ${Else} SetCtlColors $Ana_RegisterSystemPython_Label 000000 transparent @@ -194,7 +254,7 @@ Function RegisterSystemPython_OnClick # If the button was checked, make sure we're not conflicting # with another system installed Python - ${If} $Ana_RegisterSystemPython_State == ${BST_CHECKED} + ${If} $REG_PY == 1 # Check if a Python of the version we're installing # already exists, in which case warn the user before # proceeding. @@ -213,8 +273,10 @@ Function RegisterSystemPython_OnClick directory manually." \ IDOK KeepSettingLabel # If they don't click OK, uncheck it - StrCpy $Ana_RegisterSystemPython_State ${BST_UNCHECKED} - ${NSD_SetState} $0 $Ana_RegisterSystemPython_State + StrCpy $REG_PY 0 + ${NSD_Uncheck} $0 + # Change color back to black again otherwise it will be red after user presses cancel + SetCtlColors $Ana_RegisterSystemPython_Label 000000 transparent KeepSettingLabel: ${EndIf} diff --git a/constructor/nsis/main.nsi.tmpl b/constructor/nsis/main.nsi.tmpl index 371eff0f7..9ceb718aa 100644 --- a/constructor/nsis/main.nsi.tmpl +++ b/constructor/nsis/main.nsi.tmpl @@ -73,30 +73,36 @@ ${Using:StrFunc} StrStr !include "StandaloneUninstallerOptions.nsh" {%- endif %} -!define NAME {{ installer_name }} -!define VERSION {{ installer_version }} -!define COMPANY {{ company }} -!define ARCH {{ arch }} -!define PLATFORM {{ installer_platform }} -!define CONSTRUCTOR_VERSION {{ constructor_version }} +!define NAME {{ installer_name }} +!define VERSION {{ installer_version }} +!define COMPANY {{ company }} +!define ARCH {{ arch }} +!define PLATFORM {{ installer_platform }} +!define CONSTRUCTOR_VERSION {{ constructor_version }} {%- if has_python %} -!define PY_VER {{ pyver_components[:2] | join(".") }} -!define PYVERSION_JUSTDIGITS {{ pyver_components | join("") }} -!define PYVERSION {{ pyver_components | join(".") }} -!define PYVERSION_MAJOR {{ pyver_components[0] }} -{%- endif %} -!define DEFAULT_PREFIX {{ default_prefix }} -!define DEFAULT_PREFIX_DOMAIN_USER {{ default_prefix_domain_user }} -!define DEFAULT_PREFIX_ALL_USERS {{ default_prefix_all_users }} -!define PRE_INSTALL_DESC {{ pre_install_desc }} -!define POST_INSTALL_DESC {{ post_install_desc }} -!define ENABLE_SHORTCUTS {{ enable_shortcuts }} -!define SHOW_REGISTER_PYTHON {{ show_register_python }} -!define SHOW_ADD_TO_PATH {{ show_add_to_path }} -!define PRODUCT_NAME "${NAME} ${VERSION} (${ARCH})" -!define UNINSTALL_NAME "{{ UNINSTALL_NAME }}" -!define UNINSTREG "SOFTWARE\Microsoft\Windows\CurrentVersion\ - \Uninstall\${UNINSTALL_NAME}" +!define PY_VER {{ pyver_components[:2] | join(".") }} +!define PYVERSION_JUSTDIGITS {{ pyver_components | join("") }} +!define PYVERSION {{ pyver_components | join(".") }} +!define PYVERSION_MAJOR {{ pyver_components[0] }} +{% endif } +!define DEFAULT_PREFIX {{ default_prefix }} +!define DEFAULT_PREFIX_DOMAIN_USER {{ default_prefix_domain_user }} +!define DEFAULT_PREFIX_ALL_USERS {{ default_prefix_all_users }} +!define PRE_INSTALL_DESC {{ pre_install_desc }} +!define POST_INSTALL_DESC {{ post_install_desc }} +!define ENABLE_SHORTCUTS {{ enable_shortcuts }} +!define REGISTER_PYTHON_OPTION {{ '1' if register_python else '0' }} +!define REGISTER_PYTHON_DEFAULT_VALUE {{ '1' if register_python_default else '0' }} +!define INIT_CONDA_OPTION {{ '1' if initialize_conda else '0' }} +!define INIT_CONDA_MODE "{{ 'condabin' if initialize_conda == 'condabin' else 'classic' }}" +!define INIT_CONDA_DEFAULT_VALUE {{ '1' if initialize_by_default else '0' }} +!define PRODUCT_NAME "${NAME} ${VERSION} (${ARCH})" +!define UNINSTALL_NAME "{{ UNINSTALL_NAME }}" +!define UNINSTREG "SOFTWARE\Microsoft\Windows\CurrentVersion\ + \Uninstall\${UNINSTALL_NAME}" + +var /global INIT_CONDA +var /global REG_PY var /global INSTDIR_JUSTME var /global INSTALLER_VERSION @@ -304,11 +310,13 @@ FunctionEnd -------$\n\ $\n\ /InstallationType=AllUsers [default: JustMe]$\n\ +{% if initialize_conda %} /AddToPath=[0|1] [default: 0]$\n\ +{% endif %} /KeepPkgCache=[0|1] [default: {{ 1 if keep_pkgs else 0 }}]$\n\ -{%- if has_python %} - /RegisterPython=[0|1] [default: AllUsers: 1, JustMe: 0]$\n\ -{%- endif %} +{% if has_python and register_python %} + /RegisterPython=[0|1] [default: 0]$\n\ +{% endif %} /NoRegistry=[0|1] [default: AllUsers: 0, JustMe: 0]$\n\ /NoScripts=[0|1] [default: 0]$\n\ /NoShortcuts=[0|1] [default: 0]$\n\ @@ -327,14 +335,16 @@ FunctionEnd Install for all users, but don't add to PATH env var:$\n\ > $EXEFILE /InstallationType=AllUsers$\n\ $\n\ -{%- if has_python %} - Install for just me, add to PATH and register as system Python:$\n\ - > $EXEFILE /RegisterPython=1 /AddToPath=1$\n\ +{%- if has_python and register_python %} + Install for just me, and register as system Python:$\n\ + > $EXEFILE /RegisterPython=1$\n\ $\n\ {%- endif %} +{% if initialize_conda %} Install for just me and add to PATH:$\n\ > $EXEFILE /AddToPath=1$\n\ $\n\ +{% endif %} Install for just me, with no registry modification (for CI):$\n\ > $EXEFILE /NoRegistry=1$\n\ $\n\ @@ -358,16 +368,18 @@ FunctionEnd ${EndIf} ClearErrors -{%- if has_python %} - ${GetOptions} $ARGV "/RegisterPython=" $ARGV_RegisterPython - ${IfNot} ${Errors} - ${If} $ARGV_RegisterPython = "1" - StrCpy $Ana_RegisterSystemPython_State ${BST_CHECKED} - ${ElseIf} $ARGV_RegisterPython = "0" - StrCpy $Ana_RegisterSystemPython_State ${BST_UNCHECKED} + !if ${REGISTER_PYTHON_OPTION} == 1 + ${GetOptions} $ARGV "/RegisterPython=" $ARGV_RegisterPython + ${IfNot} ${Errors} + ${If} $ARGV_RegisterPython == "1" + StrCpy $REG_PY 1 + ${ElseIf} $ARGV_RegisterPython == "0" + StrCpy $REG_PY 0 + ${EndIf} ${EndIf} - ${EndIf} -{%- endif %} + !else + StrCpy $REG_PY 0 + !endif ClearErrors ${GetOptions} $ARGV "/KeepPkgCache=" $ARGV_KeepPkgCache @@ -429,23 +441,28 @@ Function OnInit_Release # Parsing the AddToPath option here (and not in ParseCommandLineArgs) to prevent the MessageBox from showing twice. # For more context, see https://github.com/conda/constructor/pull/584#issuecomment-1347688020 - ClearErrors - ${GetOptions} $ARGV "/AddToPath=" $ARGV_AddToPath - ${IfNot} ${Errors} - ${If} $ARGV_AddToPath = "1" - ${If} $InstMode == ${ALL_USERS} + !if ${INIT_CONDA_OPTION} == 1 + ClearErrors + ${GetOptions} $ARGV "/AddToPath=" $ARGV_AddToPath + ${IfNot} ${Errors} + ${If} $ARGV_AddToPath = "1" # To address CVE-2022-26526. # In AllUsers install mode, do not allow AddToPath as an option. - MessageBox MB_OK|MB_ICONEXCLAMATION "/AddToPath=1 is disabled and ignored in 'All Users' installations" /SD IDOK - ${Print} "/AddToPath=1 is disabled and ignored in 'All Users' installations" - StrCpy $Ana_AddToPath_State ${BST_UNCHECKED} - ${Else} - StrCpy $Ana_AddToPath_State ${BST_CHECKED} + ${If} $InstMode == ${ALL_USERS} + MessageBox MB_OK|MB_ICONEXCLAMATION \ + "/AddToPath=1 is disabled and ignored in 'All Users' installations" /SD IDOK + ${Print} "/AddToPath=1 is disabled and ignored in 'All Users' installations" + StrCpy $INIT_CONDA 0 + ${Else} + StrCpy $INIT_CONDA 1 + ${EndIf} + ${ElseIf} $ARGV_AddToPath = "0" + StrCpy $INIT_CONDA 0 ${EndIf} - ${ElseIf} $ARGV_AddToPath = "0" - StrCpy $Ana_AddToPath_State ${BST_UNCHECKED} ${EndIf} - ${EndIf} + !else + StrCpy $INIT_CONDA 0 + !endif FunctionEnd Function InstModePage_RadioButton_OnClick @@ -589,6 +606,19 @@ Function .onInit Push $R1 Push $R2 + # Assign the runtime variables + !if ${INIT_CONDA_OPTION} == 1 + StrCpy $INIT_CONDA ${INIT_CONDA_DEFAULT_VALUE} + !else + StrCpy $INIT_CONDA 0 + !endif + + !if ${REGISTER_PYTHON_OPTION} == 1 + StrCpy $REG_PY ${REGISTER_PYTHON_DEFAULT_VALUE} + !else + StrCpy $REG_PY 0 + !endif + InitPluginsDir {%- if TEMP_EXTRA_FILES | length != 0 %} SetOutPath $PLUGINSDIR @@ -733,25 +763,9 @@ Function .onInit StrCpy $CheckPathLength "1" ${EndIf} - # Initialize the default settings for the anaconda custom options + # Initialize the custom options Call mui_AnaCustomOptions_InitDefaults - # Override custom options with explicitly given values from construct.yaml. - # If initialize_by_default / register_python_default - # are None, do nothing. Note that these variables exist even when the construct.yaml - # settings are disabled, and the installer will respect them later! -{%- if initialize_conda %} - {%- if initialize_by_default %} - ${If} $InstMode == ${JUST_ME} - StrCpy $Ana_AddToPath_State ${BST_CHECKED} - ${EndIf} - {%- else %} - StrCpy $Ana_AddToPath_State ${BST_UNCHECKED} - {%- endif %} -{%- endif %} -{%- if register_python %} - StrCpy $Ana_RegisterSystemPython_State {{ '${BST_CHECKED}' if register_python_default else '${BST_UNCHECKED}' }} -{%- endif %} StrCpy $CheckPathLength "{{ 1 if check_path_length else 0 }}" StrCpy $Ana_ClearPkgCache_State {{ '${BST_UNCHECKED}' if keep_pkgs else '${BST_CHECKED}' }} StrCpy $Ana_PreInstall_State {{ '${BST_CHECKED}' if pre_install_exists else '${BST_UNCHECKED}' }} @@ -1591,19 +1605,30 @@ Section "Install" call AbortRetryNSExecWait ${EndIf} -{% if initialize_conda %} - ${If} ${FileExists} "$INSTDIR\.nonadmin" - ${If} $Ana_AddToPath_State = ${BST_CHECKED} - !insertmacro AddRemovePath "add" "" + !if ${INIT_CONDA_OPTION} == 1 + # For consistency with other code, only for "Just Me" installation + ${If} ${FileExists} "$INSTDIR\.nonadmin" + ${If} $INIT_CONDA = 1 + !insertmacro AddRemovePath "add" "" + ${If} "${INIT_CONDA_MODE}" == "condabin" + ${Print} "Adding $INSTDIR\condabin to PATH..." + push '"$INSTDIR\pythonw.exe" -E -s "$INSTDIR\Lib\_nsis.py" addcondabinpath' + ${Else} + ${Print} "Adding $INSTDIR\Scripts & Library\bin to PATH..." + push '"$INSTDIR\pythonw.exe" -E -s "$INSTDIR\Lib\_nsis.py" addpath ${PYVERSION} ${NAME} ${VERSION} ${ARCH}' + ${EndIf} + push 'Failed to add ${NAME} to PATH' + push 'WithLog' + call AbortRetryNSExecWait + ${EndIf} ${EndIf} - ${EndIf} -{%- endif %} + !endif {%- if has_python %} # Create registry entries saying this is the system Python # (for this version) !define PYREG "Software\Python\PythonCore\${PY_VER}" - ${If} $Ana_RegisterSystemPython_State == ${BST_CHECKED} + ${If} $REG_PY == 1 WriteRegStr SHCTX "${PYREG}\Help\Main Python Documentation" \ "Main Python Documentation" \ "$INSTDIR\Doc\python${PYVERSION_JUSTDIGITS}.chm" diff --git a/constructor/winexe.py b/constructor/winexe.py index 1af81dfc3..d225182af 100644 --- a/constructor/winexe.py +++ b/constructor/winexe.py @@ -166,8 +166,6 @@ def make_nsi( "pre_install_desc": info["pre_install_desc"], "post_install_desc": info["post_install_desc"], "enable_shortcuts": "yes" if info["_enable_shortcuts"] is True else "no", - "show_register_python": "yes" if info.get("register_python", True) else "no", - "show_add_to_path": info.get("initialize_conda", "classic") or "no", "outfile": info["_outpath"], "vipv": make_VIProductVersion(info["version"]), "constructor_version": info["CONSTRUCTOR_VERSION"], diff --git a/examples/custom_nsis_template/custom.nsi.tmpl b/examples/custom_nsis_template/custom.nsi.tmpl index ff6526fc9..1ed5b41f3 100644 --- a/examples/custom_nsis_template/custom.nsi.tmpl +++ b/examples/custom_nsis_template/custom.nsi.tmpl @@ -55,8 +55,6 @@ Unicode "true" # OptionsDialog.nsh plug-in constructor uses !define PRE_INSTALL_DESC __PRE_INSTALL_DESC__ !define POST_INSTALL_DESC __POST_INSTALL_DESC__ -!define SHOW_REGISTER_PYTHON __SHOW_REGISTER_PYTHON__ -!define SHOW_ADD_TO_PATH __SHOW_ADD_TO_PATH__ !define PRODUCT_NAME "${NAME} Uninstaller Patch" !define UNINSTREG "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" diff --git a/news/1105-improve-handling-of-certain-options b/news/1105-improve-handling-of-certain-options new file mode 100644 index 000000000..df152eada --- /dev/null +++ b/news/1105-improve-handling-of-certain-options @@ -0,0 +1,20 @@ +### Enhancements + +* EXE: Improve handling of options `initialize_conda`, `register_python` with their corresponding default values. The behavior of these options + with respect to `initialize_conda_default` and `register_python_default` is now consistent with `.sh` and `.pkg` installers. (#1003, #1004 via #1105) + +### Bug fixes + +* + +### Deprecations + +* + +### Docs + +* + +### Other + +* From e8af3582374138fdc2b9676e300c993cbf6e8ec9 Mon Sep 17 00:00:00 2001 From: Robin Date: Wed, 12 Nov 2025 08:10:27 -0500 Subject: [PATCH 02/14] Add missing % --- constructor/nsis/main.nsi.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/constructor/nsis/main.nsi.tmpl b/constructor/nsis/main.nsi.tmpl index 9ceb718aa..d7950617f 100644 --- a/constructor/nsis/main.nsi.tmpl +++ b/constructor/nsis/main.nsi.tmpl @@ -84,7 +84,7 @@ ${Using:StrFunc} StrStr !define PYVERSION_JUSTDIGITS {{ pyver_components | join("") }} !define PYVERSION {{ pyver_components | join(".") }} !define PYVERSION_MAJOR {{ pyver_components[0] }} -{% endif } +{% endif %} !define DEFAULT_PREFIX {{ default_prefix }} !define DEFAULT_PREFIX_DOMAIN_USER {{ default_prefix_domain_user }} !define DEFAULT_PREFIX_ALL_USERS {{ default_prefix_all_users }} From 44c9f5fefd23d7502121e66e27d67fc9845d608a Mon Sep 17 00:00:00 2001 From: Robin Date: Wed, 12 Nov 2025 08:58:04 -0500 Subject: [PATCH 03/14] Ensure potential empty rows are trimmed --- constructor/nsis/main.nsi.tmpl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/constructor/nsis/main.nsi.tmpl b/constructor/nsis/main.nsi.tmpl index d7950617f..b83158d47 100644 --- a/constructor/nsis/main.nsi.tmpl +++ b/constructor/nsis/main.nsi.tmpl @@ -310,13 +310,13 @@ FunctionEnd -------$\n\ $\n\ /InstallationType=AllUsers [default: JustMe]$\n\ -{% if initialize_conda %} +{%- if initialize_conda %} /AddToPath=[0|1] [default: 0]$\n\ -{% endif %} +{%- endif %} /KeepPkgCache=[0|1] [default: {{ 1 if keep_pkgs else 0 }}]$\n\ -{% if has_python and register_python %} +{%- if has_python and register_python %} /RegisterPython=[0|1] [default: 0]$\n\ -{% endif %} +{%- endif %} /NoRegistry=[0|1] [default: AllUsers: 0, JustMe: 0]$\n\ /NoScripts=[0|1] [default: 0]$\n\ /NoShortcuts=[0|1] [default: 0]$\n\ @@ -340,11 +340,11 @@ FunctionEnd > $EXEFILE /RegisterPython=1$\n\ $\n\ {%- endif %} -{% if initialize_conda %} +{%- if initialize_conda %} Install for just me and add to PATH:$\n\ > $EXEFILE /AddToPath=1$\n\ $\n\ -{% endif %} +{%- endif %} Install for just me, with no registry modification (for CI):$\n\ > $EXEFILE /NoRegistry=1$\n\ $\n\ From c9f9320e10e0b773ce85c251dd98790cc24d25fb Mon Sep 17 00:00:00 2001 From: Robin Date: Wed, 12 Nov 2025 10:30:37 -0500 Subject: [PATCH 04/14] Fixed another merge conflict --- constructor/nsis/main.nsi.tmpl | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/constructor/nsis/main.nsi.tmpl b/constructor/nsis/main.nsi.tmpl index b83158d47..48a11def7 100644 --- a/constructor/nsis/main.nsi.tmpl +++ b/constructor/nsis/main.nsi.tmpl @@ -1606,20 +1606,9 @@ Section "Install" ${EndIf} !if ${INIT_CONDA_OPTION} == 1 - # For consistency with other code, only for "Just Me" installation ${If} ${FileExists} "$INSTDIR\.nonadmin" ${If} $INIT_CONDA = 1 !insertmacro AddRemovePath "add" "" - ${If} "${INIT_CONDA_MODE}" == "condabin" - ${Print} "Adding $INSTDIR\condabin to PATH..." - push '"$INSTDIR\pythonw.exe" -E -s "$INSTDIR\Lib\_nsis.py" addcondabinpath' - ${Else} - ${Print} "Adding $INSTDIR\Scripts & Library\bin to PATH..." - push '"$INSTDIR\pythonw.exe" -E -s "$INSTDIR\Lib\_nsis.py" addpath ${PYVERSION} ${NAME} ${VERSION} ${ARCH}' - ${EndIf} - push 'Failed to add ${NAME} to PATH' - push 'WithLog' - call AbortRetryNSExecWait ${EndIf} ${EndIf} !endif From 77f8c5ec84f7e0e8ffb48acd30d4cb1fad1ad7e6 Mon Sep 17 00:00:00 2001 From: Robin Date: Fri, 14 Nov 2025 12:34:00 -0500 Subject: [PATCH 05/14] Add clarity regarding default of REG_PY --- constructor/nsis/main.nsi.tmpl | 8 +++++--- docs/source/cli-options.md | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/constructor/nsis/main.nsi.tmpl b/constructor/nsis/main.nsi.tmpl index 48a11def7..86d3b56d0 100644 --- a/constructor/nsis/main.nsi.tmpl +++ b/constructor/nsis/main.nsi.tmpl @@ -367,8 +367,12 @@ FunctionEnd ${EndIf} ${EndIf} - ClearErrors + + # Default: don't register Python + StrCpy $REG_PY 0 + !if ${REGISTER_PYTHON_OPTION} == 1 + ClearErrors ${GetOptions} $ARGV "/RegisterPython=" $ARGV_RegisterPython ${IfNot} ${Errors} ${If} $ARGV_RegisterPython == "1" @@ -377,8 +381,6 @@ FunctionEnd StrCpy $REG_PY 0 ${EndIf} ${EndIf} - !else - StrCpy $REG_PY 0 !endif ClearErrors diff --git a/docs/source/cli-options.md b/docs/source/cli-options.md index 97bd1ea8b..cad946d87 100644 --- a/docs/source/cli-options.md +++ b/docs/source/cli-options.md @@ -72,7 +72,7 @@ Windows installers have the following CLI options available: - `/NoShortcuts=[0|1]`: If set to `1`, the installer will not create any shortcuts. Defaults to `0`. - `/RegisterPython=[0|1]`: Whether to register Python as default in the Windows registry. Defaults - to `1`. This is preferred to `AddToPath`. + to `0`. This is preferred to `AddToPath`. - `/D` (directory): sets the default installation directory. Note that even if the path contains spaces, it must be the last parameter used in the command line and must not contain any quotes. Only absolute paths are supported. From bc6a315803e4ceb0aa3d9763689347e1fd5d7713 Mon Sep 17 00:00:00 2001 From: Robin Date: Fri, 14 Nov 2025 12:37:07 -0500 Subject: [PATCH 06/14] Account for has_python --- constructor/nsis/main.nsi.tmpl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/constructor/nsis/main.nsi.tmpl b/constructor/nsis/main.nsi.tmpl index 86d3b56d0..62de3427d 100644 --- a/constructor/nsis/main.nsi.tmpl +++ b/constructor/nsis/main.nsi.tmpl @@ -91,7 +91,7 @@ ${Using:StrFunc} StrStr !define PRE_INSTALL_DESC {{ pre_install_desc }} !define POST_INSTALL_DESC {{ post_install_desc }} !define ENABLE_SHORTCUTS {{ enable_shortcuts }} -!define REGISTER_PYTHON_OPTION {{ '1' if register_python else '0' }} +!define REGISTER_PYTHON_OPTION {{ '1' if register_python and has_python else '0' }} !define REGISTER_PYTHON_DEFAULT_VALUE {{ '1' if register_python_default else '0' }} !define INIT_CONDA_OPTION {{ '1' if initialize_conda else '0' }} !define INIT_CONDA_MODE "{{ 'condabin' if initialize_conda == 'condabin' else 'classic' }}" @@ -370,7 +370,6 @@ FunctionEnd # Default: don't register Python StrCpy $REG_PY 0 - !if ${REGISTER_PYTHON_OPTION} == 1 ClearErrors ${GetOptions} $ARGV "/RegisterPython=" $ARGV_RegisterPython From db68a7c3cdeaeaf53a0d832b100eb3bd666ca424 Mon Sep 17 00:00:00 2001 From: Robin Date: Fri, 14 Nov 2025 12:48:58 -0500 Subject: [PATCH 07/14] Update release notes --- news/1105-improve-handling-of-certain-options | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/news/1105-improve-handling-of-certain-options b/news/1105-improve-handling-of-certain-options index df152eada..65b8002b0 100644 --- a/news/1105-improve-handling-of-certain-options +++ b/news/1105-improve-handling-of-certain-options @@ -1,7 +1,9 @@ ### Enhancements * EXE: Improve handling of options `initialize_conda`, `register_python` with their corresponding default values. The behavior of these options - with respect to `initialize_conda_default` and `register_python_default` is now consistent with `.sh` and `.pkg` installers. (#1003, #1004 via #1105) + with respect to `initialize_by_default` and `register_python_default` is now consistent with `.sh` and `.pkg` installers. + The options `initialize_by_default` and `register_python_default` only applies for interactive installations. + Note that when installing via the command-line, the corresponding options `AddToPath` and `RegisterPython` are by default set to `0`. (#1003, #1004 via #1105) ### Bug fixes From 666c2e353eab27612ccbf3cc9eac8d4c505ef2d4 Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 17 Nov 2025 13:26:38 -0500 Subject: [PATCH 08/14] Additional review fixes --- constructor/data/construct.schema.json | 4 ++-- constructor/nsis/main.nsi.tmpl | 2 ++ constructor/winexe.py | 2 +- news/1105-improve-handling-of-certain-options | 3 +-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/constructor/data/construct.schema.json b/constructor/data/construct.schema.json index 78f371941..fbae86794 100644 --- a/constructor/data/construct.schema.json +++ b/constructor/data/construct.schema.json @@ -750,7 +750,7 @@ } ], "default": null, - "description": "Default value for the option added by `initialize_conda`. The default is true for GUI installers (EXE, PKG) and false for shell installers. The user is able to change the default during interactive installation. NOTE: For Windows, `AddToPath` is disabled when `InstallationType=AllUsers`.\nOnly applies if `initialize_conda` is not false.", + "description": "Default value for the option added by `initialize_conda`. The default is true for PKG installers, and false for EXE (GUI and CLI installations) and shell installers. The user is able to change the default during interactive installation. NOTE: For Windows, `AddToPath` is disabled when `InstallationType=AllUsers`.\nOnly applies if `initialize_conda` is not false.", "title": "Initialize By Default" }, "initialize_conda": { @@ -1076,7 +1076,7 @@ }, "register_python": { "default": true, - "description": "Whether to offer the user an option to register the installed Python instance as the system's default Python. (Windows only)", + "description": "If the installer bundles a Python instance, offer the user an option to register the installed Python instance as the system's default Python. (Windows only)", "title": "Register Python", "type": "boolean" }, diff --git a/constructor/nsis/main.nsi.tmpl b/constructor/nsis/main.nsi.tmpl index 62de3427d..56dd5006a 100644 --- a/constructor/nsis/main.nsi.tmpl +++ b/constructor/nsis/main.nsi.tmpl @@ -440,6 +440,8 @@ Function OnInit_Release ${LogSet} on !insertmacro ParseCommandLineArgs + # Default: don't initialize conda + StrCpy $INIT_CONDA 0 # Parsing the AddToPath option here (and not in ParseCommandLineArgs) to prevent the MessageBox from showing twice. # For more context, see https://github.com/conda/constructor/pull/584#issuecomment-1347688020 !if ${INIT_CONDA_OPTION} == 1 diff --git a/constructor/winexe.py b/constructor/winexe.py index d225182af..52896ac23 100644 --- a/constructor/winexe.py +++ b/constructor/winexe.py @@ -243,7 +243,7 @@ def make_nsi( variables.update(ns_platform(info["_platform"])) variables["initialize_conda"] = info.get("initialize_conda", "classic") - variables["initialize_by_default"] = info.get("initialize_by_default", None) + variables["initialize_by_default"] = info.get("initialize_by_default", False) variables["check_path_length"] = info.get("check_path_length", False) variables["check_path_spaces"] = info.get("check_path_spaces", True) variables["keep_pkgs"] = info.get("keep_pkgs") or False diff --git a/news/1105-improve-handling-of-certain-options b/news/1105-improve-handling-of-certain-options index 65b8002b0..10501af44 100644 --- a/news/1105-improve-handling-of-certain-options +++ b/news/1105-improve-handling-of-certain-options @@ -2,8 +2,7 @@ * EXE: Improve handling of options `initialize_conda`, `register_python` with their corresponding default values. The behavior of these options with respect to `initialize_by_default` and `register_python_default` is now consistent with `.sh` and `.pkg` installers. - The options `initialize_by_default` and `register_python_default` only applies for interactive installations. - Note that when installing via the command-line, the corresponding options `AddToPath` and `RegisterPython` are by default set to `0`. (#1003, #1004 via #1105) + Windows CLI installations now don't add `conda` to `PATH` or register Python by default. (#1003, #1004 via #1105) ### Bug fixes From bf24d45b2aadbf0010e26118f5b89a380a107d34 Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 17 Nov 2025 13:42:56 -0500 Subject: [PATCH 09/14] Docs updates --- CONSTRUCT.md | 6 +++--- constructor/_schema.py | 8 ++++---- constructor/data/construct.schema.json | 4 ++-- docs/source/construct-yaml.md | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/CONSTRUCT.md b/CONSTRUCT.md index 77155d3e9..0ffd57766 100644 --- a/CONSTRUCT.md +++ b/CONSTRUCT.md @@ -525,8 +525,8 @@ See also `initialize_by_default`. ### `initialize_by_default` -Default value for the option added by `initialize_conda`. The default -is true for GUI installers (EXE, PKG) and false for shell installers. The user +Default value for the option added by `initialize_conda`. The default is +true for PKG installers, and false for EXE (GUI and CLI installations) and shell installers. The user is able to change the default during interactive installation. NOTE: For Windows, `AddToPath` is disabled when `InstallationType=AllUsers`. @@ -534,7 +534,7 @@ Only applies if `initialize_conda` is not false. ### `register_python` -Whether to offer the user an option to register the installed Python instance as the +If the installer installs a Python instance, offer the user an option to register the installed Python instance as the system's default Python. (Windows only) ### `register_python_default` diff --git a/constructor/_schema.py b/constructor/_schema.py index 2e1785b13..a4855b402 100644 --- a/constructor/_schema.py +++ b/constructor/_schema.py @@ -690,10 +690,10 @@ class ConstructorConfiguration(BaseModel): See also `initialize_by_default`. """ - initialize_by_default: bool | None = None + initialize_by_default: bool | None = False """ - Default value for the option added by `initialize_conda`. The default - is true for GUI installers (EXE, PKG) and false for shell installers. The user + Default value for the option added by `initialize_conda`. The default is + true for PKG installers, and false for EXE (GUI and CLI installations) and shell installers. The user is able to change the default during interactive installation. NOTE: For Windows, `AddToPath` is disabled when `InstallationType=AllUsers`. @@ -701,7 +701,7 @@ class ConstructorConfiguration(BaseModel): """ register_python: bool = True """ - Whether to offer the user an option to register the installed Python instance as the + If the installer installs a Python instance, offer the user an option to register the installed Python instance as the system's default Python. (Windows only) """ register_python_default: bool | None = False diff --git a/constructor/data/construct.schema.json b/constructor/data/construct.schema.json index fbae86794..b2f8b1c67 100644 --- a/constructor/data/construct.schema.json +++ b/constructor/data/construct.schema.json @@ -749,7 +749,7 @@ "type": "null" } ], - "default": null, + "default": false, "description": "Default value for the option added by `initialize_conda`. The default is true for PKG installers, and false for EXE (GUI and CLI installations) and shell installers. The user is able to change the default during interactive installation. NOTE: For Windows, `AddToPath` is disabled when `InstallationType=AllUsers`.\nOnly applies if `initialize_conda` is not false.", "title": "Initialize By Default" }, @@ -1076,7 +1076,7 @@ }, "register_python": { "default": true, - "description": "If the installer bundles a Python instance, offer the user an option to register the installed Python instance as the system's default Python. (Windows only)", + "description": "If the installer installs a Python instance, offer the user an option to register the installed Python instance as the system's default Python. (Windows only)", "title": "Register Python", "type": "boolean" }, diff --git a/docs/source/construct-yaml.md b/docs/source/construct-yaml.md index 77155d3e9..0ffd57766 100644 --- a/docs/source/construct-yaml.md +++ b/docs/source/construct-yaml.md @@ -525,8 +525,8 @@ See also `initialize_by_default`. ### `initialize_by_default` -Default value for the option added by `initialize_conda`. The default -is true for GUI installers (EXE, PKG) and false for shell installers. The user +Default value for the option added by `initialize_conda`. The default is +true for PKG installers, and false for EXE (GUI and CLI installations) and shell installers. The user is able to change the default during interactive installation. NOTE: For Windows, `AddToPath` is disabled when `InstallationType=AllUsers`. @@ -534,7 +534,7 @@ Only applies if `initialize_conda` is not false. ### `register_python` -Whether to offer the user an option to register the installed Python instance as the +If the installer installs a Python instance, offer the user an option to register the installed Python instance as the system's default Python. (Windows only) ### `register_python_default` From 83ed89a904589d62a245530357d7452dfb230ffb Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 17 Nov 2025 15:11:51 -0500 Subject: [PATCH 10/14] Adjust setting of default values --- constructor/nsis/main.nsi.tmpl | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/constructor/nsis/main.nsi.tmpl b/constructor/nsis/main.nsi.tmpl index 56dd5006a..ec857649d 100644 --- a/constructor/nsis/main.nsi.tmpl +++ b/constructor/nsis/main.nsi.tmpl @@ -368,8 +368,6 @@ FunctionEnd ${EndIf} - # Default: don't register Python - StrCpy $REG_PY 0 !if ${REGISTER_PYTHON_OPTION} == 1 ClearErrors ${GetOptions} $ARGV "/RegisterPython=" $ARGV_RegisterPython @@ -440,8 +438,6 @@ Function OnInit_Release ${LogSet} on !insertmacro ParseCommandLineArgs - # Default: don't initialize conda - StrCpy $INIT_CONDA 0 # Parsing the AddToPath option here (and not in ParseCommandLineArgs) to prevent the MessageBox from showing twice. # For more context, see https://github.com/conda/constructor/pull/584#issuecomment-1347688020 !if ${INIT_CONDA_OPTION} == 1 @@ -609,7 +605,8 @@ Function .onInit Push $R1 Push $R2 - # Assign the runtime variables + # Initialize INIT_CONDA and REG_PY, note that they to default 0 if the installer + # is not configured to prompt the user with a choice. !if ${INIT_CONDA_OPTION} == 1 StrCpy $INIT_CONDA ${INIT_CONDA_DEFAULT_VALUE} !else From 16ffe6e7fd468e7a7f6b365293ba64bc5f046984 Mon Sep 17 00:00:00 2001 From: Robin Date: Tue, 18 Nov 2025 08:18:47 -0500 Subject: [PATCH 11/14] Changed back the default value --- constructor/_schema.py | 2 +- constructor/data/construct.schema.json | 2 +- constructor/winexe.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/constructor/_schema.py b/constructor/_schema.py index a4855b402..daf4711d6 100644 --- a/constructor/_schema.py +++ b/constructor/_schema.py @@ -690,7 +690,7 @@ class ConstructorConfiguration(BaseModel): See also `initialize_by_default`. """ - initialize_by_default: bool | None = False + initialize_by_default: bool | None = None """ Default value for the option added by `initialize_conda`. The default is true for PKG installers, and false for EXE (GUI and CLI installations) and shell installers. The user diff --git a/constructor/data/construct.schema.json b/constructor/data/construct.schema.json index b2f8b1c67..cd267bcf3 100644 --- a/constructor/data/construct.schema.json +++ b/constructor/data/construct.schema.json @@ -749,7 +749,7 @@ "type": "null" } ], - "default": false, + "default": null, "description": "Default value for the option added by `initialize_conda`. The default is true for PKG installers, and false for EXE (GUI and CLI installations) and shell installers. The user is able to change the default during interactive installation. NOTE: For Windows, `AddToPath` is disabled when `InstallationType=AllUsers`.\nOnly applies if `initialize_conda` is not false.", "title": "Initialize By Default" }, diff --git a/constructor/winexe.py b/constructor/winexe.py index 52896ac23..d225182af 100644 --- a/constructor/winexe.py +++ b/constructor/winexe.py @@ -243,7 +243,7 @@ def make_nsi( variables.update(ns_platform(info["_platform"])) variables["initialize_conda"] = info.get("initialize_conda", "classic") - variables["initialize_by_default"] = info.get("initialize_by_default", False) + variables["initialize_by_default"] = info.get("initialize_by_default", None) variables["check_path_length"] = info.get("check_path_length", False) variables["check_path_spaces"] = info.get("check_path_spaces", True) variables["keep_pkgs"] = info.get("keep_pkgs") or False From a913928ddcce235a745d2bbab7033966d6000dde Mon Sep 17 00:00:00 2001 From: Robin Date: Tue, 18 Nov 2025 14:25:29 -0500 Subject: [PATCH 12/14] More fixes and lock dependency in test --- constructor/nsis/OptionsDialog.nsh | 109 +++++++++--------- constructor/nsis/main.nsi.tmpl | 86 ++++++-------- examples/extra_envs/construct.yaml | 2 +- news/1105-improve-handling-of-certain-options | 3 +- 4 files changed, 96 insertions(+), 104 deletions(-) diff --git a/constructor/nsis/OptionsDialog.nsh b/constructor/nsis/OptionsDialog.nsh index 2b687962f..11c94e5a3 100644 --- a/constructor/nsis/OptionsDialog.nsh +++ b/constructor/nsis/OptionsDialog.nsh @@ -7,7 +7,6 @@ Var mui_AnaCustomOptions Var mui_AnaCustomOptions.AddToPath -Var mui_AnaCustomOptions.RegisterSystemPython Var mui_AnaCustomOptions.PostInstall Var mui_AnaCustomOptions.PreInstall Var mui_AnaCustomOptions.ClearPkgCache @@ -20,11 +19,65 @@ Var Ana_ClearPkgCache_State Var Ana_CreateShortcuts_State Var Ana_AddToPath_Label -Var Ana_RegisterSystemPython_Label Var Ana_ClearPkgCache_Label Var Ana_PostInstall_Label Var Ana_PreInstall_Label + +!if ${REGISTER_PYTHON_OPTION} == 1 + Var mui_AnaCustomOptions.RegisterSystemPython + Var Ana_RegisterSystemPython_Label + + Function RegisterSystemPython_OnClick + Pop $0 + + # Sync UI with variable + ${NSD_GetState} $0 $1 + ${If} $1 == ${BST_CHECKED} + StrCpy $REG_PY 1 + ${Else} + StrCpy $REG_PY 0 + ${EndIf} + + ShowWindow $Ana_RegisterSystemPython_Label ${SW_HIDE} + ${If} $REG_PY == 1 + SetCtlColors $Ana_RegisterSystemPython_Label ff0000 transparent + ${Else} + SetCtlColors $Ana_RegisterSystemPython_Label 000000 transparent + ${EndIf} + ShowWindow $Ana_RegisterSystemPython_Label ${SW_SHOW} + + # If the button was checked, make sure we're not conflicting + # with another system installed Python + ${If} $REG_PY == 1 + # Check if a Python of the version we're installing + # already exists, in which case warn the user before + # proceeding. + ReadRegStr $2 SHCTX "Software\Python\PythonCore\${PY_VER}\InstallPath" "" + ${If} "$2" != "" + ${AndIf} ${FileExists} "$2\Python.exe" + MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION|MB_DEFBUTTON2 \ + "A version of Python ${PY_VER} (${ARCH}) is already at$\n\ + $2$\n\ + We recommend that if you want ${NAME} registered as your $\n\ + system Python, you unregister this Python first. If you really$\n\ + know this is what you want, click OK, otherwise$\n\ + click cancel to continue.$\n$\n\ + NOTE: Anaconda 1.3 and earlier lacked an uninstall, if$\n\ + you are upgrading an old Anaconda, please delete the$\n\ + directory manually." \ + IDOK KeepSettingLabel + # If they don't click OK, uncheck it + StrCpy $REG_PY 0 + ${NSD_Uncheck} $0 + + KeepSettingLabel: + + ${EndIf} + ${EndIf} + FunctionEnd +!endif + Function mui_AnaCustomOptions_InitDefaults # AddToPath / conda init default !if ${INIT_CONDA_OPTION} == 1 @@ -34,7 +87,7 @@ Function mui_AnaCustomOptions_InitDefaults StrCpy $INIT_CONDA 0 !endif - # Register Python default + # Register Python default while accounting for existing installations !if ${REGISTER_PYTHON_OPTION} == 1 # Ensure we initialize from compile-time default value StrCpy $REG_PY ${REGISTER_PYTHON_DEFAULT_VALUE} @@ -233,56 +286,6 @@ Function AddToPath_OnClick ShowWindow $Ana_AddToPath_Label ${SW_SHOW} FunctionEnd -Function RegisterSystemPython_OnClick - Pop $0 - - # Sync UI with variable - ${NSD_GetState} $0 $1 - ${If} $1 == ${BST_CHECKED} - StrCpy $REG_PY 1 - ${Else} - StrCpy $REG_PY 0 - ${EndIf} - - ShowWindow $Ana_RegisterSystemPython_Label ${SW_HIDE} - ${If} $REG_PY == 1 - SetCtlColors $Ana_RegisterSystemPython_Label ff0000 transparent - ${Else} - SetCtlColors $Ana_RegisterSystemPython_Label 000000 transparent - ${EndIf} - ShowWindow $Ana_RegisterSystemPython_Label ${SW_SHOW} - - # If the button was checked, make sure we're not conflicting - # with another system installed Python - ${If} $REG_PY == 1 - # Check if a Python of the version we're installing - # already exists, in which case warn the user before - # proceeding. - ReadRegStr $2 SHCTX "Software\Python\PythonCore\${PY_VER}\InstallPath" "" - ${If} "$2" != "" - ${AndIf} ${FileExists} "$2\Python.exe" - MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION|MB_DEFBUTTON2 \ - "A version of Python ${PY_VER} (${ARCH}) is already at$\n\ - $2$\n\ - We recommend that if you want ${NAME} registered as your $\n\ - system Python, you unregister this Python first. If you really$\n\ - know this is what you want, click OK, otherwise$\n\ - click cancel to continue.$\n$\n\ - NOTE: Anaconda 1.3 and earlier lacked an uninstall, if$\n\ - you are upgrading an old Anaconda, please delete the$\n\ - directory manually." \ - IDOK KeepSettingLabel - # If they don't click OK, uncheck it - StrCpy $REG_PY 0 - ${NSD_Uncheck} $0 - # Change color back to black again otherwise it will be red after user presses cancel - SetCtlColors $Ana_RegisterSystemPython_Label 000000 transparent -KeepSettingLabel: - - ${EndIf} - ${EndIf} -FunctionEnd - Function PostInstall_OnClick Pop $0 diff --git a/constructor/nsis/main.nsi.tmpl b/constructor/nsis/main.nsi.tmpl index ec857649d..28af9991e 100644 --- a/constructor/nsis/main.nsi.tmpl +++ b/constructor/nsis/main.nsi.tmpl @@ -118,7 +118,9 @@ var /global ARGV_Help var /global ARGV_InstallationType var /global ARGV_AddToPath var /global ARGV_KeepPkgCache +{%- if has_python %} var /global ARGV_RegisterPython +{%- endif %} var /global ARGV_NoRegistry var /global ARGV_NoScripts var /global ARGV_NoShortcuts @@ -309,7 +311,7 @@ FunctionEnd OPTIONS$\n\ -------$\n\ $\n\ - /InstallationType=AllUsers [default: JustMe]$\n\ + /InstallationType=[AllUsers|JustMe] [default: JustMe]$\n\ {%- if initialize_conda %} /AddToPath=[0|1] [default: 0]$\n\ {%- endif %} @@ -377,6 +379,34 @@ FunctionEnd ${ElseIf} $ARGV_RegisterPython == "0" StrCpy $REG_PY 0 ${EndIf} + ${Else} + # If we have Errors, i.e. the option is not explicitly set by the user + StrCpy $REG_PY 0 + ${EndIf} + + !endif + + !if ${INIT_CONDA_OPTION} == 1 + ClearErrors + ${GetOptions} $ARGV "/AddToPath=" $ARGV_AddToPath + ${IfNot} ${Errors} + ${If} $ARGV_AddToPath = "1" + # To address CVE-2022-26526. + # In AllUsers install mode, do not allow AddToPath as an option. + ${If} $InstMode == ${ALL_USERS} + MessageBox MB_OK|MB_ICONEXCLAMATION \ + "/AddToPath=1 is disabled and ignored in 'All Users' installations" /SD IDOK + ${Print} "/AddToPath=1 is disabled and ignored in 'All Users' installations" + StrCpy $INIT_CONDA 0 + ${Else} + StrCpy $INIT_CONDA 1 + ${EndIf} + ${ElseIf} $ARGV_AddToPath = "0" + StrCpy $INIT_CONDA 0 + ${EndIf} + ${Else} + # If we have Errors, i.e. the option is not explicitly set by the user + StrCpy $INIT_CONDA 0 ${EndIf} !endif @@ -434,36 +464,6 @@ FunctionEnd !macroend -Function OnInit_Release - ${LogSet} on - !insertmacro ParseCommandLineArgs - - # Parsing the AddToPath option here (and not in ParseCommandLineArgs) to prevent the MessageBox from showing twice. - # For more context, see https://github.com/conda/constructor/pull/584#issuecomment-1347688020 - !if ${INIT_CONDA_OPTION} == 1 - ClearErrors - ${GetOptions} $ARGV "/AddToPath=" $ARGV_AddToPath - ${IfNot} ${Errors} - ${If} $ARGV_AddToPath = "1" - # To address CVE-2022-26526. - # In AllUsers install mode, do not allow AddToPath as an option. - ${If} $InstMode == ${ALL_USERS} - MessageBox MB_OK|MB_ICONEXCLAMATION \ - "/AddToPath=1 is disabled and ignored in 'All Users' installations" /SD IDOK - ${Print} "/AddToPath=1 is disabled and ignored in 'All Users' installations" - StrCpy $INIT_CONDA 0 - ${Else} - StrCpy $INIT_CONDA 1 - ${EndIf} - ${ElseIf} $ARGV_AddToPath = "0" - StrCpy $INIT_CONDA 0 - ${EndIf} - ${EndIf} - !else - StrCpy $INIT_CONDA 0 - !endif -FunctionEnd - Function InstModePage_RadioButton_OnClick ${LogSet} on Exch $0 @@ -605,19 +605,13 @@ Function .onInit Push $R1 Push $R2 - # Initialize INIT_CONDA and REG_PY, note that they to default 0 if the installer - # is not configured to prompt the user with a choice. - !if ${INIT_CONDA_OPTION} == 1 - StrCpy $INIT_CONDA ${INIT_CONDA_DEFAULT_VALUE} - !else - StrCpy $INIT_CONDA 0 - !endif + # 1. Initialize core options default values + Call mui_AnaCustomOptions_InitDefaults - !if ${REGISTER_PYTHON_OPTION} == 1 - StrCpy $REG_PY ${REGISTER_PYTHON_DEFAULT_VALUE} - !else - StrCpy $REG_PY 0 - !endif + # 2. Account finally for CLI to potentially override core default values + ${If} ${Silent} + !insertmacro ParseCommandLineArgs + ${EndIf} InitPluginsDir {%- if TEMP_EXTRA_FILES | length != 0 %} @@ -626,7 +620,6 @@ Function .onInit File "{{ file }}" {%- endfor %} {%- endif %} - !insertmacro ParseCommandLineArgs # Select the correct registry to look at, depending # on whether it's a 32-bit or 64-bit installer @@ -763,16 +756,11 @@ Function .onInit StrCpy $CheckPathLength "1" ${EndIf} - # Initialize the custom options - Call mui_AnaCustomOptions_InitDefaults - StrCpy $CheckPathLength "{{ 1 if check_path_length else 0 }}" StrCpy $Ana_ClearPkgCache_State {{ '${BST_UNCHECKED}' if keep_pkgs else '${BST_CHECKED}' }} StrCpy $Ana_PreInstall_State {{ '${BST_CHECKED}' if pre_install_exists else '${BST_UNCHECKED}' }} StrCpy $Ana_PostInstall_State {{ '${BST_CHECKED}' if post_install_exists else '${BST_UNCHECKED}' }} - Call OnInit_Release - ${Print} "Welcome to ${NAME} ${VERSION}$\n" Pop $R2 diff --git a/examples/extra_envs/construct.yaml b/examples/extra_envs/construct.yaml index aedaf28ff..ef09adfcd 100644 --- a/examples/extra_envs/construct.yaml +++ b/examples/extra_envs/construct.yaml @@ -9,7 +9,7 @@ channels: specs: - python=3.9 - conda # conda is required for extra_envs - - miniforge_console_shortcut # [win] + - miniforge_console_shortcut 1.* # [win] exclude: # [unix] - tk # [unix] extra_envs: diff --git a/news/1105-improve-handling-of-certain-options b/news/1105-improve-handling-of-certain-options index 10501af44..4e499e249 100644 --- a/news/1105-improve-handling-of-certain-options +++ b/news/1105-improve-handling-of-certain-options @@ -2,7 +2,8 @@ * EXE: Improve handling of options `initialize_conda`, `register_python` with their corresponding default values. The behavior of these options with respect to `initialize_by_default` and `register_python_default` is now consistent with `.sh` and `.pkg` installers. - Windows CLI installations now don't add `conda` to `PATH` or register Python by default. (#1003, #1004 via #1105) + Windows CLI installations now don't add `conda` to `PATH` or register Python by default, and, command-line arguments are + only parsed when installing in silent mode (enabled with the flag `/S`).(#1003, #1004 via #1105) ### Bug fixes From cf93b7a7c4346606f9542f766f8c1bd2aa865344 Mon Sep 17 00:00:00 2001 From: Robin Date: Wed, 19 Nov 2025 09:11:22 -0500 Subject: [PATCH 13/14] Review fixes --- constructor/_schema.py | 10 ++++++---- constructor/nsis/main.nsi.tmpl | 4 ++-- news/1105-improve-handling-of-certain-options | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/constructor/_schema.py b/constructor/_schema.py index daf4711d6..d50cac46a 100644 --- a/constructor/_schema.py +++ b/constructor/_schema.py @@ -693,16 +693,18 @@ class ConstructorConfiguration(BaseModel): initialize_by_default: bool | None = None """ Default value for the option added by `initialize_conda`. The default is - true for PKG installers, and false for EXE (GUI and CLI installations) and shell installers. The user - is able to change the default during interactive installation. NOTE: For Windows, - `AddToPath` is disabled when `InstallationType=AllUsers`. + true for PKG installers, and false for EXE and SH shell installers. + The user is able to change the default during interactive installations. + Non-interactive installations are not affected by this value: users must explicitly request + to add to `PATH` via CLI options. + NOTE: For Windows, `/AddToPath` is disabled when `/InstallationType=AllUsers`. Only applies if `initialize_conda` is not false. """ register_python: bool = True """ If the installer installs a Python instance, offer the user an option to register the installed Python instance as the - system's default Python. (Windows only) + system's default Python. Defaults to `true` for GUI and `false` for CLI installations. (Windows only) """ register_python_default: bool | None = False """ diff --git a/constructor/nsis/main.nsi.tmpl b/constructor/nsis/main.nsi.tmpl index 28af9991e..fb93badb6 100644 --- a/constructor/nsis/main.nsi.tmpl +++ b/constructor/nsis/main.nsi.tmpl @@ -380,7 +380,7 @@ FunctionEnd StrCpy $REG_PY 0 ${EndIf} ${Else} - # If we have Errors, i.e. the option is not explicitly set by the user + # If we have Errors, the option is not explicitly set by the user StrCpy $REG_PY 0 ${EndIf} @@ -405,7 +405,7 @@ FunctionEnd StrCpy $INIT_CONDA 0 ${EndIf} ${Else} - # If we have Errors, i.e. the option is not explicitly set by the user + # If we have Errors, the option is not explicitly set by the user StrCpy $INIT_CONDA 0 ${EndIf} !endif diff --git a/news/1105-improve-handling-of-certain-options b/news/1105-improve-handling-of-certain-options index 4e499e249..171008d30 100644 --- a/news/1105-improve-handling-of-certain-options +++ b/news/1105-improve-handling-of-certain-options @@ -2,8 +2,8 @@ * EXE: Improve handling of options `initialize_conda`, `register_python` with their corresponding default values. The behavior of these options with respect to `initialize_by_default` and `register_python_default` is now consistent with `.sh` and `.pkg` installers. - Windows CLI installations now don't add `conda` to `PATH` or register Python by default, and, command-line arguments are - only parsed when installing in silent mode (enabled with the flag `/S`).(#1003, #1004 via #1105) + Windows CLI installations now don't add `conda` to `PATH` or register Python by default, and command-line arguments are + only parsed when installing in silent mode (enabled with the flag `/S`). (#1003, #1004 via #1105) ### Bug fixes From d6236a0d99cad7dd37fa10a9af5d403ee03d04f4 Mon Sep 17 00:00:00 2001 From: Robin Date: Wed, 19 Nov 2025 09:36:26 -0500 Subject: [PATCH 14/14] Doc updates (_schema.py and make_docs) --- CONSTRUCT.md | 10 ++++++---- constructor/data/construct.schema.json | 4 ++-- docs/source/construct-yaml.md | 10 ++++++---- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/CONSTRUCT.md b/CONSTRUCT.md index 0ffd57766..210cc88e9 100644 --- a/CONSTRUCT.md +++ b/CONSTRUCT.md @@ -526,16 +526,18 @@ See also `initialize_by_default`. ### `initialize_by_default` Default value for the option added by `initialize_conda`. The default is -true for PKG installers, and false for EXE (GUI and CLI installations) and shell installers. The user -is able to change the default during interactive installation. NOTE: For Windows, -`AddToPath` is disabled when `InstallationType=AllUsers`. +true for PKG installers, and false for EXE and SH shell installers. +The user is able to change the default during interactive installations. +Non-interactive installations are not affected by this value: users must explicitly request +to add to `PATH` via CLI options. +NOTE: For Windows, `/AddToPath` is disabled when `/InstallationType=AllUsers`. Only applies if `initialize_conda` is not false. ### `register_python` If the installer installs a Python instance, offer the user an option to register the installed Python instance as the -system's default Python. (Windows only) +system's default Python. Defaults to `true` for GUI and `false` for CLI installations. (Windows only) ### `register_python_default` diff --git a/constructor/data/construct.schema.json b/constructor/data/construct.schema.json index cd267bcf3..228b82946 100644 --- a/constructor/data/construct.schema.json +++ b/constructor/data/construct.schema.json @@ -750,7 +750,7 @@ } ], "default": null, - "description": "Default value for the option added by `initialize_conda`. The default is true for PKG installers, and false for EXE (GUI and CLI installations) and shell installers. The user is able to change the default during interactive installation. NOTE: For Windows, `AddToPath` is disabled when `InstallationType=AllUsers`.\nOnly applies if `initialize_conda` is not false.", + "description": "Default value for the option added by `initialize_conda`. The default is true for PKG installers, and false for EXE and SH shell installers. The user is able to change the default during interactive installations. Non-interactive installations are not affected by this value: users must explicitly request to add to `PATH` via CLI options. NOTE: For Windows, `/AddToPath` is disabled when `/InstallationType=AllUsers`.\nOnly applies if `initialize_conda` is not false.", "title": "Initialize By Default" }, "initialize_conda": { @@ -1076,7 +1076,7 @@ }, "register_python": { "default": true, - "description": "If the installer installs a Python instance, offer the user an option to register the installed Python instance as the system's default Python. (Windows only)", + "description": "If the installer installs a Python instance, offer the user an option to register the installed Python instance as the system's default Python. Defaults to `true` for GUI and `false` for CLI installations. (Windows only)", "title": "Register Python", "type": "boolean" }, diff --git a/docs/source/construct-yaml.md b/docs/source/construct-yaml.md index 0ffd57766..210cc88e9 100644 --- a/docs/source/construct-yaml.md +++ b/docs/source/construct-yaml.md @@ -526,16 +526,18 @@ See also `initialize_by_default`. ### `initialize_by_default` Default value for the option added by `initialize_conda`. The default is -true for PKG installers, and false for EXE (GUI and CLI installations) and shell installers. The user -is able to change the default during interactive installation. NOTE: For Windows, -`AddToPath` is disabled when `InstallationType=AllUsers`. +true for PKG installers, and false for EXE and SH shell installers. +The user is able to change the default during interactive installations. +Non-interactive installations are not affected by this value: users must explicitly request +to add to `PATH` via CLI options. +NOTE: For Windows, `/AddToPath` is disabled when `/InstallationType=AllUsers`. Only applies if `initialize_conda` is not false. ### `register_python` If the installer installs a Python instance, offer the user an option to register the installed Python instance as the -system's default Python. (Windows only) +system's default Python. Defaults to `true` for GUI and `false` for CLI installations. (Windows only) ### `register_python_default`