Fix the following on Windows: * `spack load --list` (this printed 0 packages even if packages were loaded) * `spack unload <package>` (this said that the package is not loaded even if it was) Update unit tests for `spack load` to also run on Windows (specifically for ".bat"). This involved refactoring a few tests to parameterize based on whether the unit tests are being run on a Windows system (and to account for batch syntax).
		
			
				
	
	
		
			251 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			Batchfile
		
	
	
	
	
	
			
		
		
	
	
			251 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			Batchfile
		
	
	
	
	
	
:: Copyright 2013-2024 Lawrence Livermore National Security, LLC and other
 | 
						|
:: Spack Project Developers. See the top-level COPYRIGHT file for details.
 | 
						|
::
 | 
						|
:: SPDX-License-Identifier: (Apache-2.0 OR MIT)
 | 
						|
::#######################################################################
 | 
						|
::
 | 
						|
:: This file is part of Spack and sets up the spack environment for batch,
 | 
						|
:: This includes environment modules and lmod support,
 | 
						|
:: and it also puts spack in your path. The script also checks that at least
 | 
						|
:: module support exists, and provides suggestions if it doesn't. Source
 | 
						|
:: it like this:
 | 
						|
::
 | 
						|
::    . /path/to/spack/install/spack_cmd.bat
 | 
						|
::
 | 
						|
@echo off
 | 
						|
 | 
						|
set spack="%SPACK_ROOT%"\bin\spack
 | 
						|
 | 
						|
::#######################################################################
 | 
						|
:: This is a wrapper around the spack command that forwards calls to
 | 
						|
:: 'spack load' and 'spack unload' to shell functions.  This in turn
 | 
						|
:: allows them to be used to invoke environment modules functions.
 | 
						|
::
 | 
						|
:: 'spack load' is smarter than just 'load' because it converts its
 | 
						|
:: arguments into a unique Spack spec that is then passed to module
 | 
						|
:: commands.  This allows the user to use packages without knowing all
 | 
						|
:: their installation details.
 | 
						|
::
 | 
						|
:: e.g., rather than requiring a full spec for libelf, the user can type:
 | 
						|
::
 | 
						|
::     spack load libelf
 | 
						|
::
 | 
						|
:: This will first find the available libelf module file and use a
 | 
						|
:: matching one.  If there are two versions of libelf, the user would
 | 
						|
:: need to be more specific, e.g.:
 | 
						|
::
 | 
						|
::     spack load libelf@0.8.13
 | 
						|
::
 | 
						|
:: This is very similar to how regular spack commands work and it
 | 
						|
:: avoids the need to come up with a user-friendly naming scheme for
 | 
						|
:: spack module files.
 | 
						|
::#######################################################################
 | 
						|
 | 
						|
:_sp_shell_wrapper
 | 
						|
set "_sp_flags="
 | 
						|
set "_sp_args="
 | 
						|
set "_sp_subcommand="
 | 
						|
setlocal enabledelayedexpansion
 | 
						|
:: commands have the form '[flags] [subcommand] [args]'
 | 
						|
:: flags will always start with '-', e.g. --help or -V
 | 
						|
:: subcommands will never start with '-'
 | 
						|
:: everything after the subcommand is an arg
 | 
						|
 | 
						|
 | 
						|
:process_cl_args
 | 
						|
rem Set first cl argument (denoted by %1) to be processed
 | 
						|
set t=%1
 | 
						|
rem shift moves all cl positional arguments left by one
 | 
						|
rem meaning %2 is now %1, this allows us to iterate over each
 | 
						|
rem argument
 | 
						|
shift
 | 
						|
rem assign next "first" cl argument to cl_args, will be null when
 | 
						|
rem there are now further arguments to process
 | 
						|
set cl_args=%1
 | 
						|
if "!t:~0,1!" == "-" (
 | 
						|
    if defined _sp_subcommand (
 | 
						|
        rem  We already have a subcommand, processing args now
 | 
						|
        if not defined _sp_args (
 | 
						|
            set "_sp_args=!t!"
 | 
						|
        ) else (
 | 
						|
            set "_sp_args=!_sp_args! !t!"
 | 
						|
        )
 | 
						|
    ) else (
 | 
						|
        if not defined _sp_flags (
 | 
						|
            set "_sp_flags=!t!"
 | 
						|
        ) else (
 | 
						|
            set "_sp_flags=!_sp_flags! !t!"
 | 
						|
        )
 | 
						|
    )
 | 
						|
) else if not defined _sp_subcommand (
 | 
						|
    set "_sp_subcommand=!t!"
 | 
						|
) else (
 | 
						|
    if not defined _sp_args (
 | 
						|
        set "_sp_args=!t!"
 | 
						|
    ) else (
 | 
						|
        set "_sp_args=!_sp_args! !t!"
 | 
						|
    )
 | 
						|
)
 | 
						|
 | 
						|
rem  if this is not nu;ll, we have more tokens to process
 | 
						|
rem  start above process again with remaining unprocessed cl args
 | 
						|
if defined cl_args goto :process_cl_args
 | 
						|
 | 
						|
 | 
						|
:: --help, -h and -V flags don't require further output parsing.
 | 
						|
:: If we encounter, execute and exit
 | 
						|
if defined _sp_flags (
 | 
						|
    if NOT "%_sp_flags%"=="%_sp_flags:-h=%" (
 | 
						|
        python "%spack%" %_sp_flags%
 | 
						|
        exit /B 0
 | 
						|
    ) else if NOT "%_sp_flags%"=="%_sp_flags:--help=%" (
 | 
						|
        python "%spack%" %_sp_flags%
 | 
						|
        exit /B 0
 | 
						|
    ) else if NOT "%_sp_flags%"=="%_sp_flags:-V=%" (
 | 
						|
        python "%spack%" %_sp_flags%
 | 
						|
        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
 | 
						|
:: this because delayedexpansion can only be set by setlocal
 | 
						|
endlocal & (
 | 
						|
    set "_sp_flags=%_sp_flags%"
 | 
						|
    set "_sp_args=%_sp_args%"
 | 
						|
    set "_sp_subcommand=%_sp_subcommand%"
 | 
						|
)
 | 
						|
 | 
						|
 | 
						|
:: Filter out some commands. For any others, just run the command.
 | 
						|
if "%_sp_subcommand%" == "cd" (
 | 
						|
    goto :case_cd
 | 
						|
) else if "%_sp_subcommand%" == "env" (
 | 
						|
    goto :case_env
 | 
						|
) else if "%_sp_subcommand%" == "load" (
 | 
						|
    goto :case_load
 | 
						|
) else if "%_sp_subcommand%" == "unload" (
 | 
						|
    goto :case_load
 | 
						|
) else (
 | 
						|
    goto :default_case
 | 
						|
)
 | 
						|
 | 
						|
::#######################################################################
 | 
						|
 | 
						|
:case_cd
 | 
						|
:: Check for --help or -h
 | 
						|
:: TODO: This is not exactly the same as setup-env.
 | 
						|
:: In setup-env, '--help' or '-h' must follow the cd
 | 
						|
:: Here, they may be anywhere in the args
 | 
						|
if defined _sp_args (
 | 
						|
    if NOT "%_sp_args%"=="%_sp_args:--help=%" (
 | 
						|
        python "%spack%" cd -h
 | 
						|
        goto :end_switch
 | 
						|
    ) else if NOT "%_sp_args%"=="%_sp_args:-h=%" (
 | 
						|
        python "%spack%" cd -h
 | 
						|
        goto :end_switch
 | 
						|
    )
 | 
						|
)
 | 
						|
 | 
						|
for /F "tokens=* USEBACKQ" %%F in (
 | 
						|
  `python "%spack%" location %_sp_args%`) do (
 | 
						|
    set "LOC=%%F"
 | 
						|
)
 | 
						|
for %%Z in ("%LOC%") do if EXIST %%~sZ\NUL (cd /d "%LOC%")
 | 
						|
goto :end_switch
 | 
						|
 | 
						|
:case_env
 | 
						|
:: If no args or args contain --bat or -h/--help: just execute.
 | 
						|
if NOT defined _sp_args (
 | 
						|
    goto :default_case
 | 
						|
)
 | 
						|
 | 
						|
if NOT "%_sp_args%"=="%_sp_args:--help=%" (
 | 
						|
    goto :default_case
 | 
						|
) else if NOT "%_sp_args%"=="%_sp_args: -h=%" (
 | 
						|
    goto :default_case
 | 
						|
) else if NOT "%_sp_args%"=="%_sp_args:--bat=%" (
 | 
						|
    goto :default_case
 | 
						|
) else if NOT "%_sp_args%"=="%_sp_args:deactivate=%" (
 | 
						|
    for /f "tokens=* USEBACKQ" %%I in (
 | 
						|
        `call python %spack% %_sp_flags% env deactivate --bat %_sp_args:deactivate=%`
 | 
						|
    ) do %%I
 | 
						|
) else if NOT "%_sp_args%"=="%_sp_args:activate=%" (
 | 
						|
    for /f "tokens=* USEBACKQ" %%I in (
 | 
						|
        `python %spack% %_sp_flags% env activate --bat %_sp_args:activate=%`
 | 
						|
    ) do %%I
 | 
						|
) else (
 | 
						|
    goto :default_case
 | 
						|
)
 | 
						|
goto :end_switch
 | 
						|
 | 
						|
:case_load
 | 
						|
if NOT defined _sp_args (
 | 
						|
   exit /B 0
 | 
						|
)
 | 
						|
 | 
						|
:: If args contain --bat, or -h/--help: just execute.
 | 
						|
if NOT "%_sp_args%"=="%_sp_args:--help=%" (
 | 
						|
    goto :default_case
 | 
						|
) else if NOT "%_sp_args%"=="%_sp_args:-h=%" (
 | 
						|
    goto :default_case
 | 
						|
) else if NOT "%_sp_args%"=="%_sp_args:--bat=%" (
 | 
						|
    goto :default_case
 | 
						|
) else if NOT "%_sp_args%"=="%_sp_args:--list=%" (
 | 
						|
    goto :default_case
 | 
						|
)
 | 
						|
 | 
						|
for /f "tokens=* USEBACKQ" %%I in (
 | 
						|
    `python "%spack%" %_sp_flags% %_sp_subcommand% --bat %_sp_args%`
 | 
						|
    ) do %%I
 | 
						|
 | 
						|
goto :end_switch
 | 
						|
 | 
						|
:default_case
 | 
						|
python "%spack%" %_sp_flags% %_sp_subcommand% %_sp_args%
 | 
						|
goto :end_switch
 | 
						|
 | 
						|
:end_switch
 | 
						|
exit /B %ERRORLEVEL%
 | 
						|
 | 
						|
 | 
						|
::########################################################################
 | 
						|
:: Prepends directories to path, if they exist.
 | 
						|
::      pathadd /path/to/dir            # add to PATH
 | 
						|
:: or   pathadd OTHERPATH /path/to/dir  # add to OTHERPATH
 | 
						|
::########################################################################
 | 
						|
 | 
						|
:_spack_pathadd
 | 
						|
set "_pa_varname=PATH"
 | 
						|
set "_pa_new_path=%~1"
 | 
						|
if NOT "%~2" == "" (
 | 
						|
    set "_pa_varname=%~1"
 | 
						|
    set "_pa_new_path=%~2"
 | 
						|
    )
 | 
						|
set "_pa_oldvalue=%_pa_varname%"
 | 
						|
for %%Z in ("%_pa_new_path%") do if EXIST %%~sZ\NUL (
 | 
						|
    if defined %_pa_oldvalue% (
 | 
						|
        set "_pa_varname=%_pa_new_path%:%_pa_oldvalue%"
 | 
						|
    ) else (
 | 
						|
        set "_pa_varname=%_pa_new_path%"
 | 
						|
    )
 | 
						|
)
 | 
						|
exit /b 0
 | 
						|
 | 
						|
:: set module system roots
 | 
						|
:_sp_multi_pathadd
 | 
						|
for %%I in (%~2) do (
 | 
						|
    for %%Z in (%_sp_compatible_sys_types%) do (
 | 
						|
        :pathadd "%~1" "%%I\%%Z"
 | 
						|
    )
 | 
						|
)
 | 
						|
exit /B %ERRORLEVEL%
 |