summaryrefslogtreecommitdiff
path: root/bin/spack.bat
blob: 2c2947ac0f8ca112dac6e1677fec6db1363467de (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
:: Copyright 2013-2023 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

:: we cannot allow batch "for" loop to directly process CL args
:: a number of batch reserved characters are commonly passed to
:: spack and allowing batch's "for" method to process the raw inputs
:: results in a large number of formatting issues
:: instead, treat the entire CLI as one string
:: and split by space manually
:: capture cl args in variable named cl_args
set cl_args=%*
:process_cl_args
:: tokens=1* returns the first processed token produced
:: by tokenizing the input string cl_args on spaces into
:: the named variable %%g
:: While this make look like a for loop, it only
:: executes a single time for each of the cl args
:: the actual iterative loop is performed by the
:: goto process_cl_args stanza
:: we are simply leveraging the "for" method's string
:: tokenization
for /f "tokens=1*" %%g in ("%cl_args%") do (
    set t=%%~g
    :: remainder of string is composed into %%h
    :: these are the cl args yet to be processed
    :: assign cl_args var to only the args to be processed
    :: effectively discarding the current arg %%g
    :: this will be nul when we have no further tokens to process
    set cl_args=%%h
    :: process the first space delineated cl arg
    :: of this iteration
    if "!t:~0,1!" == "-" (
        if defined _sp_subcommand (
            :: 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!"
                shift
            ) else (
                set "_sp_flags=!_sp_flags! !t!"
                shift
            )
        )
    ) else if not defined _sp_subcommand (
        set "_sp_subcommand=!t!"
        shift
    ) else (
        if not defined _sp_args (
            set "_sp_args=!t!"
            shift
        ) else (
            set "_sp_args=!_sp_args! !t!"
            shift
        )
    )
)
:: if this is not nil, we have more tokens to process
:: 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 args contain --sh, --csh, or -h/--help: just execute.
if defined _sp_args (
    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
    )
)

for /f "tokens=* USEBACKQ" %%I in (
    `python "%spack%" %_sp_flags% %_sp_subcommand% --bat %_sp_args%`) do %%I

goto :end_switch

:case_unload
goto :case_load

: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%