Windows: Fix spack.bat handling of env commands (#35143)

This PR enables the successful execution of the spack binary cache
tutorial on Windows. It assumes gnupg and file are available (they
can be installed with choco).

* Fix handling of args with quotes in spack.bat
* `file` utility can be installed on Windows (e.g. with choco): update
  error message accordingly
This commit is contained in:
Dan Lipsa 2023-02-07 14:04:14 -05:00 committed by GitHub
parent 8358f430a4
commit 1648968514
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 37 additions and 27 deletions

View file

@ -83,6 +83,16 @@ if defined _sp_flags (
exit /B 0 exit /B 0
) )
) )
if not defined _sp_subcommand (
if not defined _sp_args (
if not defined _sp_flags (
python "%spack%" --help
exit /B 0
)
)
)
:: pass parsed variables outside of local scope. Need to do :: pass parsed variables outside of local scope. Need to do
:: this because delayedexpansion can only be set by setlocal :: this because delayedexpansion can only be set by setlocal
echo %_sp_flags%>flags echo %_sp_flags%>flags
@ -92,24 +102,24 @@ endlocal
set /p _sp_subcommand=<subcmd set /p _sp_subcommand=<subcmd
set /p _sp_flags=<flags set /p _sp_flags=<flags
set /p _sp_args=<args set /p _sp_args=<args
set str_subcommand=%_sp_subcommand:"='% if "%_sp_subcommand%"=="ECHO is off." (set "_sp_subcommand=")
set str_flags=%_sp_flags:"='% if "%_sp_subcommand%"=="ECHO is on." (set "_sp_subcommand=")
set str_args=%_sp_args:"='% if "%_sp_flags%"=="ECHO is off." (set "_sp_flags=")
if "%str_subcommand%"=="ECHO is off." (set "_sp_subcommand=") if "%_sp_flags%"=="ECHO is on." (set "_sp_flags=")
if "%str_flags%"=="ECHO is off." (set "_sp_flags=") if "%_sp_args%"=="ECHO is off." (set "_sp_args=")
if "%str_args%"=="ECHO is off." (set "_sp_args=") if "%_sp_args%"=="ECHO is on." (set "_sp_args=")
del subcmd del subcmd
del flags del flags
del args del args
:: Filter out some commands. For any others, just run the command. :: Filter out some commands. For any others, just run the command.
if "%_sp_subcommand%" == "cd" ( if %_sp_subcommand% == "cd" (
goto :case_cd goto :case_cd
) else if "%_sp_subcommand%" == "env" ( ) else if %_sp_subcommand% == "env" (
goto :case_env goto :case_env
) else if "%_sp_subcommand%" == "load" ( ) else if %_sp_subcommand% == "load" (
goto :case_load goto :case_load
) else if "%_sp_subcommand%" == "unload" ( ) else if %_sp_subcommand% == "unload" (
goto :case_load goto :case_load
) else ( ) else (
goto :default_case goto :default_case
@ -143,19 +153,21 @@ goto :end_switch
:: If no args or args contain --bat or -h/--help: just execute. :: If no args or args contain --bat or -h/--help: just execute.
if NOT defined _sp_args ( if NOT defined _sp_args (
goto :default_case goto :default_case
)else if NOT "%_sp_args%"=="%_sp_args:--help=%" ( )
set args_no_quote=%_sp_args:"=%
if NOT "%args_no_quote%"=="%args_no_quote:--help=%" (
goto :default_case goto :default_case
) else if NOT "%_sp_args%"=="%_sp_args: -h=%" ( ) else if NOT "%args_no_quote%"=="%args_no_quote: -h=%" (
goto :default_case goto :default_case
) else if NOT "%_sp_args%"=="%_sp_args:--bat=%" ( ) else if NOT "%args_no_quote%"=="%args_no_quote:--bat=%" (
goto :default_case goto :default_case
) else if NOT "%_sp_args%"=="%_sp_args:deactivate=%" ( ) else if NOT "%args_no_quote%"=="%args_no_quote:deactivate=%" (
for /f "tokens=* USEBACKQ" %%I in ( for /f "tokens=* USEBACKQ" %%I in (
`call python "%spack%" %_sp_flags% env deactivate --bat %_sp_args:deactivate=%` `call python %spack% %_sp_flags% env deactivate --bat %args_no_quote:deactivate=%`
) do %%I ) do %%I
) else if NOT "%_sp_args%"=="%_sp_args:activate=%" ( ) else if NOT "%args_no_quote%"=="%args_no_quote:activate=%" (
for /f "tokens=* USEBACKQ" %%I in ( for /f "tokens=* USEBACKQ" %%I in (
`call python "%spack%" %_sp_flags% env activate --bat %_sp_args:activate=%` `python %spack% %_sp_flags% env activate --bat %args_no_quote:activate=%`
) do %%I ) do %%I
) else ( ) else (
goto :default_case goto :default_case
@ -220,4 +232,4 @@ for %%I in (%~2) do (
:pathadd "%~1" "%%I\%%Z" :pathadd "%~1" "%%I\%%Z"
) )
) )
exit /B %ERRORLEVEL% exit /B %ERRORLEVEL%

View file

@ -23,7 +23,7 @@
from llnl.util.lang import dedupe, memoized from llnl.util.lang import dedupe, memoized
from llnl.util.symlink import islink, symlink from llnl.util.symlink import islink, symlink
from spack.util.executable import CommandNotFoundError, Executable, which from spack.util.executable import Executable, which
from spack.util.path import path_to_os_path, system_path_filter from spack.util.path import path_to_os_path, system_path_filter
is_windows = _platform == "win32" is_windows = _platform == "win32"
@ -117,13 +117,7 @@ def path_contains_subdirectory(path, root):
@memoized @memoized
def file_command(*args): def file_command(*args):
"""Creates entry point to `file` system command with provided arguments""" """Creates entry point to `file` system command with provided arguments"""
try: file_cmd = which("file", required=True)
file_cmd = which("file", required=True)
except CommandNotFoundError as e:
if is_windows:
raise CommandNotFoundError("`file` utility is not available on Windows")
else:
raise e
for arg in args: for arg in args:
file_cmd.add_default_arg(arg) file_cmd.add_default_arg(arg)
return file_cmd return file_cmd
@ -134,7 +128,11 @@ def _get_mime_type():
"""Generate method to call `file` system command to aquire mime type """Generate method to call `file` system command to aquire mime type
for a specified path for a specified path
""" """
return file_command("-b", "-h", "--mime-type") if is_windows:
# -h option (no-dereference) does not exist in Windows
return file_command("-b", "--mime-type")
else:
return file_command("-b", "-h", "--mime-type")
@memoized @memoized