Skip to content

Commit 74f6056

Browse files
marcoestersjaimergplrandersson
authored
Convert script and directory _nsis.py subcommands into NSIS code (conda#1069)
* Port mkdirs subcommand into NSIS * Convert cmd.exe executable into global variable * Run pre-uninstall script inside NSIS * Execute post-install script in NSIS * Add news * NSIS_SCRIPTS_RAISE_ERRORS * Convert finding cmd.exe into a macro * Remove unneeded rmreg command * Apply suggestions from code review Co-authored-by: Robin <[email protected]> * Replace rmreg with conda command * Add --user and --system options to init reverse command --------- Co-authored-by: jaimergp <[email protected]> Co-authored-by: Robin <[email protected]>
1 parent 71b368b commit 74f6056

File tree

5 files changed

+83
-151
lines changed

5 files changed

+83
-151
lines changed

.github/workflows/main.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ jobs:
107107
&& files+=(--file "tests/extra-requirements-${{ runner.os }}.txt")
108108
conda install ${files[@]} -y
109109
echo "NSIS_USING_LOG_BUILD=1" >> $GITHUB_ENV
110-
echo "NSIS_SCRIPTS_RAISE_ERRORS=1" >> $GITHUB_ENV
111110
pip install -e . --no-deps --no-build-isolation
112111
- name: Set up conda executable
113112
run: |

constructor/nsis/_nsis.py

Lines changed: 2 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,8 @@
88
# be tested in an installation.
99

1010
import os
11-
import re
1211
import sys
13-
from os.path import exists, isfile, join
14-
15-
try:
16-
import winreg
17-
except ImportError:
18-
import _winreg as winreg
12+
from os.path import exists, join
1913

2014
ROOT_PREFIX = sys.prefix
2115

@@ -57,96 +51,6 @@ def err(x):
5751
OutputDebugString('_nsis.py: Error: ' + x)
5852

5953

60-
class NSISReg:
61-
def __init__(self, reg_path):
62-
self.reg_path = reg_path
63-
if exists(join(ROOT_PREFIX, '.nonadmin')):
64-
self.main_key = winreg.HKEY_CURRENT_USER
65-
else:
66-
self.main_key = winreg.HKEY_LOCAL_MACHINE
67-
68-
def set(self, name, value):
69-
try:
70-
winreg.CreateKey(self.main_key, self.reg_path)
71-
registry_key = winreg.OpenKey(self.main_key, self.reg_path, 0,
72-
winreg.KEY_WRITE)
73-
winreg.SetValueEx(registry_key, name, 0, winreg.REG_SZ, value)
74-
winreg.CloseKey(registry_key)
75-
return True
76-
except WindowsError:
77-
return False
78-
79-
def get(self, name):
80-
try:
81-
registry_key = winreg.OpenKey(self.main_key, self.reg_path, 0,
82-
winreg.KEY_READ)
83-
value, regtype = winreg.QueryValueEx(registry_key, name)
84-
winreg.CloseKey(registry_key)
85-
return value
86-
except WindowsError:
87-
return None
88-
89-
90-
def mk_dirs():
91-
envs_dir = join(ROOT_PREFIX, 'envs')
92-
if not exists(envs_dir):
93-
os.mkdir(envs_dir)
94-
95-
96-
def run_post_install():
97-
"""
98-
call the post install script, if the file exists
99-
"""
100-
path = join(ROOT_PREFIX, 'pkgs', 'post_install.bat')
101-
if not isfile(path):
102-
return
103-
env = os.environ.copy()
104-
env.setdefault('PREFIX', str(ROOT_PREFIX))
105-
cmd_exe = os.path.join(os.environ['SystemRoot'], 'System32', 'cmd.exe')
106-
if not os.path.isfile(cmd_exe):
107-
cmd_exe = os.path.join(os.environ['windir'], 'System32', 'cmd.exe')
108-
if not os.path.isfile(cmd_exe):
109-
err("Error: running %s failed. cmd.exe could not be found. "
110-
"Looked in SystemRoot and windir env vars.\n" % path)
111-
if os.environ.get("NSIS_SCRIPTS_RAISE_ERRORS"):
112-
sys.exit(1)
113-
args = [cmd_exe, '/d', '/c', path]
114-
import subprocess
115-
try:
116-
subprocess.check_call(args, env=env)
117-
except subprocess.CalledProcessError:
118-
err("Error: running %s failed\n" % path)
119-
if os.environ.get("NSIS_SCRIPTS_RAISE_ERRORS"):
120-
sys.exit(1)
121-
122-
123-
def run_pre_uninstall():
124-
"""
125-
call the pre uninstall script, if the file exists
126-
"""
127-
path = join(ROOT_PREFIX, 'pre_uninstall.bat')
128-
if not isfile(path):
129-
return
130-
env = os.environ.copy()
131-
env.setdefault('PREFIX', str(ROOT_PREFIX))
132-
cmd_exe = os.path.join(os.environ['SystemRoot'], 'System32', 'cmd.exe')
133-
if not os.path.isfile(cmd_exe):
134-
cmd_exe = os.path.join(os.environ['windir'], 'System32', 'cmd.exe')
135-
if not os.path.isfile(cmd_exe):
136-
err("Error: running %s failed. cmd.exe could not be found. "
137-
"Looked in SystemRoot and windir env vars.\n" % path)
138-
if os.environ.get("NSIS_SCRIPTS_RAISE_ERRORS"):
139-
sys.exit(1)
140-
args = [cmd_exe, '/d', '/c', path]
141-
import subprocess
142-
try:
143-
subprocess.check_call(args, env=env)
144-
except subprocess.CalledProcessError:
145-
err("Error: running %s failed\n" % path)
146-
if os.environ.get("NSIS_SCRIPTS_RAISE_ERRORS"):
147-
sys.exit(1)
148-
149-
15054
allusers = (not exists(join(ROOT_PREFIX, '.nonadmin')))
15155
# out('allusers is %s\n' % allusers)
15256

@@ -217,29 +121,9 @@ def add_condabin_to_path():
217121
broadcast_environment_settings_change()
218122

219123

220-
def rm_regkeys():
221-
cmdproc_reg_entry = NSISReg(r'Software\Microsoft\Command Processor')
222-
cmdproc_autorun_val = cmdproc_reg_entry.get('AutoRun')
223-
conda_hook_regex_pat = r'((\s+&\s+)?(if +exist)?(\s*?\"[^\"]*?conda[-_]hook\.bat\"))'
224-
if join(ROOT_PREFIX, 'condabin') in (cmdproc_autorun_val or ''):
225-
cmdproc_autorun_newval = re.sub(conda_hook_regex_pat, '',
226-
cmdproc_autorun_val)
227-
try:
228-
cmdproc_reg_entry.set('AutoRun', cmdproc_autorun_newval)
229-
except Exception:
230-
# Hey, at least we made an attempt to cleanup
231-
pass
232-
233-
234124
def main():
235125
cmd = sys.argv[1].strip()
236-
if cmd == 'post_install':
237-
run_post_install()
238-
elif cmd == 'rmreg':
239-
rm_regkeys()
240-
elif cmd == 'mkdirs':
241-
mk_dirs()
242-
elif cmd == 'addpath':
126+
if cmd == 'addpath':
243127
# These checks are probably overkill, but could be useful
244128
# if I forget to update something that uses this code.
245129
if len(sys.argv) > 2:
@@ -257,8 +141,6 @@ def main():
257141
add_condabin_to_path()
258142
elif cmd == 'rmpath':
259143
remove_from_path()
260-
elif cmd == 'pre_uninstall':
261-
run_pre_uninstall()
262144
else:
263145
sys.exit("ERROR: did not expect %r" % cmd)
264146

constructor/nsis/main.nsi.tmpl

Lines changed: 62 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,22 @@ var /global InstMode # 0 = Just Me, 1 = All Users.
132132
!define JUST_ME 0
133133
!define ALL_USERS 1
134134

135+
var /global CMD_EXE
136+
137+
!macro FindCmdExe
138+
# Find cmd.exe
139+
ReadEnvStr $R0 SystemRoot
140+
ReadEnvStr $R1 windir
141+
${If} ${FileExists} "$R0"
142+
StrCpy $CMD_EXE "$R0\System32\cmd.exe"
143+
${ElseIf} ${FileExists} "$R1"
144+
StrCpy $CMD_EXE "$R1\System32\cmd.exe"
145+
${Else}
146+
# Cross our fingers CMD is in PATH
147+
StrCpy $CMD_EXE "cmd.exe"
148+
${EndIf}
149+
!macroend
150+
135151
# Include this one after our defines
136152
!include "OptionsDialog.nsh"
137153

@@ -1226,6 +1242,8 @@ Section "Install"
12261242
call OnDirectoryLeave
12271243
${EndIf}
12281244

1245+
!insertmacro FindCmdExe
1246+
12291247
SetOutPath "$INSTDIR\Lib"
12301248
File "{{ NSIS_DIR }}\_nsis.py"
12311249
File "{{ NSIS_DIR }}\_system_path.py"
@@ -1353,17 +1371,7 @@ Section "Install"
13531371

13541372
IfFileExists "$INSTDIR\pkgs\pre_install.bat" 0 NoPreInstall
13551373
${Print} "Running pre_install scripts..."
1356-
ReadEnvStr $5 SystemRoot
1357-
ReadEnvStr $6 windir
1358-
# This 'FileExists' also returns True for directories
1359-
${If} ${FileExists} "$5"
1360-
push '"$5\System32\cmd.exe" /D /C "$INSTDIR\pkgs\pre_install.bat"'
1361-
${ElseIf} ${FileExists} "$6"
1362-
push '"$6\System32\cmd.exe" /D /C "$INSTDIR\pkgs\pre_install.bat"'
1363-
${Else}
1364-
# Cross our fingers CMD is in PATH
1365-
push 'cmd.exe /D /C "$INSTDIR\pkgs\pre_install.bat"'
1366-
${EndIf}
1374+
push '"$CMD_EXE" /D /C "$INSTDIR\pkgs\pre_install.bat"'
13671375
push "Failed to run pre_install"
13681376
push 'WithLog'
13691377
call AbortRetryNSExecWait
@@ -1415,19 +1423,20 @@ Section "Install"
14151423
AddSize {{ SIZE }}
14161424

14171425
{%- if has_conda %}
1418-
${Print} "Initializing conda directories..."
1419-
push '"$INSTDIR\pythonw.exe" -E -s "$INSTDIR\Lib\_nsis.py" mkdirs'
1420-
push 'Failed to initialize conda directories'
1421-
push 'WithLog'
1422-
call AbortRetryNSExecWait
1426+
StrCpy $R0 "$INSTDIR\envs"
1427+
${IfNot} ${FileExists} "$R0"
1428+
CreateDirectory "$R0"
1429+
${EndIf}
14231430
{%- endif %}
14241431

1425-
${If} $Ana_PostInstall_State = ${BST_CHECKED}
1426-
${Print} "Running post install..."
1427-
push '"$INSTDIR\pythonw.exe" -E -s "$INSTDIR\Lib\_nsis.py" post_install'
1428-
push 'Failed to run post install script'
1429-
push 'WithLog'
1430-
call AbortRetryNSExecWait
1432+
${If} ${FileExists} "$INSTDIR\pkgs\post_install.bat"
1433+
${If} $Ana_PostInstall_State = ${BST_CHECKED}
1434+
${Print} "Running post install..."
1435+
push '"$CMD_EXE" /D /C "$INSTDIR\pkgs\post_install.bat"'
1436+
push "Failed to run post_install"
1437+
push 'WithLog'
1438+
call AbortRetryNSExecWait
1439+
${EndIf}
14311440
${EndIf}
14321441

14331442
${If} $Ana_ClearPkgCache_State = ${BST_CHECKED}
@@ -1544,6 +1553,8 @@ Section "Uninstall"
15441553
!insertmacro un.ParseCommandLineArgs
15451554
${EndIf}
15461555

1556+
!insertmacro FindCmdExe
1557+
15471558
System::Call 'kernel32::SetEnvironmentVariable(t,t)i("CONDA_ROOT_PREFIX", "$INSTDIR")".r0'
15481559
15491560
# ensure that MSVC runtime DLLs are on PATH during uninstallation
@@ -1599,9 +1610,14 @@ Section "Uninstall"
15991610
${EndIf}
16001611

16011612
{%- if uninstall_with_conda_exe %}
1602-
!insertmacro AbortRetryNSExecWaitLibNsisCmd "pre_uninstall"
1613+
${If} ${FileExists} "$INSTDIR\pkgs\pre_uninstall.bat"
1614+
${Print} "Running pre_uninstall scripts..."
1615+
push '"$CMD_EXE" /D /C "$INSTDIR\pkgs\pre_uninstall.bat"'
1616+
push "Failed to run pre_uninstall"
1617+
push 'WithLog'
1618+
call un.AbortRetryNSExecWait
1619+
${EndIf}
16031620
!insertmacro AbortRetryNSExecWaitLibNsisCmd "rmpath"
1604-
!insertmacro AbortRetryNSExecWaitLibNsisCmd "rmreg"
16051621

16061622
# Parse arguments
16071623
StrCpy $R0 ""
@@ -1649,9 +1665,29 @@ Section "Uninstall"
16491665
call un.AbortRetryNSExecWait
16501666
SetDetailsPrint both
16511667
{%- endfor %}
1652-
!insertmacro AbortRetryNSExecWaitLibNsisCmd "pre_uninstall"
1668+
${If} ${FileExists} "$INSTDIR\pkgs\pre_uninstall.bat"
1669+
${Print} "Running pre_uninstall scripts..."
1670+
push '"$CMD_EXE" /D /C "$INSTDIR\pkgs\pre_uninstall.bat"'
1671+
push "Failed to run pre_uninstall"
1672+
push 'WithLog'
1673+
call un.AbortRetryNSExecWait
1674+
${EndIf}
16531675
!insertmacro AbortRetryNSExecWaitLibNsisCmd "rmpath"
1654-
!insertmacro AbortRetryNSExecWaitLibNsisCmd "rmreg"
1676+
{%- if has_conda %}
1677+
${If} ${FileExists} "$INSTDIR\.nonadmin"
1678+
StrCpy $R0 "user"
1679+
${Else}
1680+
StrCpy $R0 "system"
1681+
${EndIf}
1682+
# When running conda.bat directly, there is a non-fatal error
1683+
# that DOSKEY (called by conda_hook.bat) is not a valid command.
1684+
# While the operation still succeeds, this error is confusing.
1685+
# Calling via cmd.exe fixes that.
1686+
push '"$CMD_EXE" /D /C "$INSTDIR\condabin\conda.bat" init cmd.exe --reverse --$R0'
1687+
push 'Failed to clean AutoRun'
1688+
push 'WithLog'
1689+
call un.AbortRetryNSExecWait
1690+
{%- endif %}
16551691

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

news/1069-port-nsispy-cmds-nsis

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
### Enhancements
2+
3+
* Port script execution, AutoRun manipulation, and directory creation functions from `_nsis.py` to NSIS. (#1069)
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>

scripts/run_examples.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,6 @@ def run_examples(keep_artifacts=None, conda_exe=None, debug=False):
118118
if os.path.exists(os.path.join(fpath, "construct.yaml")):
119119
example_paths.append(fpath)
120120

121-
# NSIS won't error out when running scripts unless
122-
# we set this custom environment variable
123-
os.environ["NSIS_SCRIPTS_RAISE_ERRORS"] = "1"
124-
125121
parent_output = tempfile.mkdtemp()
126122
tested_files = set()
127123
which_errored = {}

0 commit comments

Comments
 (0)