holoscan-cli 2.9.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- holoscan_cli/__init__.py +35 -0
- holoscan_cli/__main__.py +164 -0
- holoscan_cli/common/argparse_types.py +156 -0
- holoscan_cli/common/artifact_sources.py +160 -0
- holoscan_cli/common/constants.py +119 -0
- holoscan_cli/common/dockerutils.py +521 -0
- holoscan_cli/common/enum_types.py +49 -0
- holoscan_cli/common/exceptions.py +126 -0
- holoscan_cli/common/sdk_utils.py +195 -0
- holoscan_cli/common/utils.py +137 -0
- holoscan_cli/logging.json +37 -0
- holoscan_cli/nics/__init__.py +15 -0
- holoscan_cli/nics/nics.py +33 -0
- holoscan_cli/package-source.json +32 -0
- holoscan_cli/packager/__init__.py +15 -0
- holoscan_cli/packager/arguments.py +148 -0
- holoscan_cli/packager/config_reader.py +180 -0
- holoscan_cli/packager/container_builder.py +426 -0
- holoscan_cli/packager/manifest_files.py +217 -0
- holoscan_cli/packager/models.py +90 -0
- holoscan_cli/packager/package_command.py +197 -0
- holoscan_cli/packager/packager.py +124 -0
- holoscan_cli/packager/parameters.py +603 -0
- holoscan_cli/packager/platforms.py +426 -0
- holoscan_cli/packager/templates/Dockerfile.jinja2 +479 -0
- holoscan_cli/packager/templates/dockerignore +92 -0
- holoscan_cli/packager/templates/tools.sh +414 -0
- holoscan_cli/py.typed +14 -0
- holoscan_cli/runner/__init__.py +15 -0
- holoscan_cli/runner/resources.py +185 -0
- holoscan_cli/runner/run_command.py +207 -0
- holoscan_cli/runner/runner.py +340 -0
- holoscan_cli/version/__init__.py +15 -0
- holoscan_cli/version/version.py +53 -0
- holoscan_cli-2.9.0.dist-info/LICENSE +201 -0
- holoscan_cli-2.9.0.dist-info/METADATA +102 -0
- holoscan_cli-2.9.0.dist-info/RECORD +39 -0
- holoscan_cli-2.9.0.dist-info/WHEEL +4 -0
- holoscan_cli-2.9.0.dist-info/entry_points.txt +4 -0
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
4
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
#===============================================================================
|
|
18
|
+
# Default values for environment variables.
|
|
19
|
+
#===============================================================================
|
|
20
|
+
|
|
21
|
+
init_globals() {
|
|
22
|
+
if [ "$0" != "/bin/bash" ] && [ "$0" != "bash" ]; then
|
|
23
|
+
SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
|
|
24
|
+
export RUN_SCRIPT_FILE="$(readlink -f "$0")"
|
|
25
|
+
else
|
|
26
|
+
export RUN_SCRIPT_FILE="$(readlink -f "${BASH_SOURCE[0]}")"
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
export TOP=$(dirname "${RUN_SCRIPT_FILE}")
|
|
30
|
+
|
|
31
|
+
export HOLOSCAN_APPLICATION="${HOLOSCAN_APPLICATION:=/opt/holoscan/app}"
|
|
32
|
+
export HOLOSCAN_INPUT_PATH="${HOLOSCAN_INPUT_PATH:=/var/holoscan/input}"
|
|
33
|
+
export HOLOSCAN_OUTPUT_PATH="${HOLOSCAN_OUTPUT_PATH:=/var/holoscan/output}"
|
|
34
|
+
export HOLOSCAN_WORKDIR="${HOLOSCAN_WORKDIR:=/var/holoscan/}"
|
|
35
|
+
export HOLOSCAN_MODEL_PATH="${HOLOSCAN_MODEL_PATH:=/opt/holoscan/models/}"
|
|
36
|
+
export HOLOSCAN_DOCS="${HOLOSCAN_DOCS:=/opt/holoscan/docs/}"
|
|
37
|
+
export HOLOSCAN_CONFIG_PATH="${HOLOSCAN_CONFIG_PATH:=/var/holoscan/app.config}"
|
|
38
|
+
export HOLOSCAN_APP_MANIFEST_PATH="${HOLOSCAN_APP_MANIFEST_PATH:=/etc/holoscan/app.json}"
|
|
39
|
+
export HOLOSCAN_PKG_MANIFEST_PATH="${HOLOSCAN_PKG_MANIFEST_PATH:=/etc/holoscan/pkg.json}"
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
################################################################################
|
|
43
|
+
# Utility functions
|
|
44
|
+
################################################################################
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
c_str() {
|
|
48
|
+
local old_color=39
|
|
49
|
+
local old_attr=0
|
|
50
|
+
local color=39
|
|
51
|
+
local attr=0
|
|
52
|
+
local text=""
|
|
53
|
+
local mode="color"
|
|
54
|
+
if [ "${1:-}" = "color" ]; then
|
|
55
|
+
mode="color"
|
|
56
|
+
shift
|
|
57
|
+
elif [ "${1:-}" = "nocolor" ]; then
|
|
58
|
+
mode="nocolor"
|
|
59
|
+
shift
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
for i in "$@"; do
|
|
63
|
+
case "$i" in
|
|
64
|
+
r|R)
|
|
65
|
+
color=31
|
|
66
|
+
;;
|
|
67
|
+
g|G)
|
|
68
|
+
color=32
|
|
69
|
+
;;
|
|
70
|
+
y|Y)
|
|
71
|
+
color=33
|
|
72
|
+
;;
|
|
73
|
+
b|B)
|
|
74
|
+
color=34
|
|
75
|
+
;;
|
|
76
|
+
p|P)
|
|
77
|
+
color=35
|
|
78
|
+
;;
|
|
79
|
+
c|C)
|
|
80
|
+
color=36
|
|
81
|
+
;;
|
|
82
|
+
w|W)
|
|
83
|
+
color=37
|
|
84
|
+
;;
|
|
85
|
+
|
|
86
|
+
z|Z)
|
|
87
|
+
color=0
|
|
88
|
+
;;
|
|
89
|
+
esac
|
|
90
|
+
case "$i" in
|
|
91
|
+
l|L|R|G|Y|B|P|C|W)
|
|
92
|
+
attr=1
|
|
93
|
+
;;
|
|
94
|
+
n|N|r|g|y|b|p|c|w)
|
|
95
|
+
attr=0
|
|
96
|
+
;;
|
|
97
|
+
z|Z)
|
|
98
|
+
attr=0
|
|
99
|
+
;;
|
|
100
|
+
*)
|
|
101
|
+
text="${text}$i"
|
|
102
|
+
esac
|
|
103
|
+
if [ "${mode}" = "color" ]; then
|
|
104
|
+
if [ ${old_color} -ne ${color} ] || [ ${old_attr} -ne ${attr} ]; then
|
|
105
|
+
text="${text}\033[${attr};${color}m"
|
|
106
|
+
old_color=$color
|
|
107
|
+
old_attr=$attr
|
|
108
|
+
fi
|
|
109
|
+
fi
|
|
110
|
+
done
|
|
111
|
+
/bin/echo -en "$text"
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
c_echo() {
|
|
115
|
+
# Select color/nocolor based on the first argument
|
|
116
|
+
local mode="color"
|
|
117
|
+
if [ "${1:-}" = "color" ]; then
|
|
118
|
+
mode="color"
|
|
119
|
+
shift
|
|
120
|
+
elif [ "${1:-}" = "nocolor" ]; then
|
|
121
|
+
mode="nocolor"
|
|
122
|
+
shift
|
|
123
|
+
else
|
|
124
|
+
if [ ! -t 1 ]; then
|
|
125
|
+
mode="nocolor"
|
|
126
|
+
fi
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
local old_opt="$(shopt -op xtrace)" # save old xtrace option
|
|
130
|
+
set +x # unset xtrace
|
|
131
|
+
|
|
132
|
+
if [ "${mode}" = "color" ]; then
|
|
133
|
+
local text="$(c_str color "$@")"
|
|
134
|
+
/bin/echo -e "$text\033[0m"
|
|
135
|
+
else
|
|
136
|
+
local text="$(c_str nocolor "$@")"
|
|
137
|
+
/bin/echo -e "$text"
|
|
138
|
+
fi
|
|
139
|
+
eval "${old_opt}" # restore old xtrace option
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
echo_err() {
|
|
143
|
+
>&2 echo "$@"
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
c_echo_err() {
|
|
147
|
+
>&2 c_echo "$@"
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
newline() {
|
|
151
|
+
echo
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
info() {
|
|
155
|
+
c_echo_err W "$(date -u '+%Y-%m-%d %H:%M:%S') [INFO] " Z "$@"
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
error() {
|
|
159
|
+
c_echo_err R "$(date -u '+%Y-%m-%d %H:%M:%S') [ERROR] " Z "$@"
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
fatal() {
|
|
163
|
+
if [ -n "$*" ]; then
|
|
164
|
+
c_echo_err R "$(date -u '+%Y-%m-%d %H:%M:%S') [FATAL] " Z "$@"
|
|
165
|
+
echo_err
|
|
166
|
+
fi
|
|
167
|
+
if [ -n "${SCRIPT_DIR}" ]; then
|
|
168
|
+
exit 1
|
|
169
|
+
else
|
|
170
|
+
kill -INT $$ # kill the current process instead of exit in shell environment.
|
|
171
|
+
fi
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
run_command() {
|
|
175
|
+
local status=0
|
|
176
|
+
local cmd="$*"
|
|
177
|
+
|
|
178
|
+
[ "$(echo -n "$@")" = "" ] && return 1 # return 1 if there is no command available
|
|
179
|
+
|
|
180
|
+
if [ "${DO_DRY_RUN}" != "true" ]; then
|
|
181
|
+
"$@"
|
|
182
|
+
status=$?
|
|
183
|
+
fi
|
|
184
|
+
|
|
185
|
+
return $status
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
#===============================================================================
|
|
190
|
+
# Section: Show
|
|
191
|
+
#===============================================================================
|
|
192
|
+
|
|
193
|
+
print() {
|
|
194
|
+
# Parse CLI arguments next
|
|
195
|
+
ARGS=("$@")
|
|
196
|
+
if [ "$ARGS" = "" ]; then
|
|
197
|
+
ARGS=*
|
|
198
|
+
fi
|
|
199
|
+
|
|
200
|
+
local i
|
|
201
|
+
local arg
|
|
202
|
+
for i in "${!ARGS[@]}"; do
|
|
203
|
+
arg="${ARGS[i]}"
|
|
204
|
+
if [[ "$arg" = "*" || "$arg" = "" ]]; then
|
|
205
|
+
opt=all
|
|
206
|
+
fi
|
|
207
|
+
if [ "$arg" = "app" ]; then
|
|
208
|
+
opt=app
|
|
209
|
+
fi
|
|
210
|
+
if [ "$arg" = "pkg" ]; then
|
|
211
|
+
opt=pkg
|
|
212
|
+
fi
|
|
213
|
+
done
|
|
214
|
+
newline
|
|
215
|
+
if [[ "$opt" = "all" || "$opt" = "app" ]]; then
|
|
216
|
+
if [ -f "${HOLOSCAN_APP_MANIFEST_PATH}" ]; then
|
|
217
|
+
c_echo "============================== app.json =============================="
|
|
218
|
+
run_command cat ${HOLOSCAN_APP_MANIFEST_PATH} | jq
|
|
219
|
+
else
|
|
220
|
+
c_echo_err "${HOLOSCAN_APP_MANIFEST_PATH} does not exists!"
|
|
221
|
+
fi
|
|
222
|
+
fi
|
|
223
|
+
newline
|
|
224
|
+
if [[ "$opt" = "all" || "$opt" = "pkg" ]]; then
|
|
225
|
+
if [ -f "${HOLOSCAN_PKG_MANIFEST_PATH}" ]; then
|
|
226
|
+
c_echo "============================== pkg.json =============================="
|
|
227
|
+
run_command cat ${HOLOSCAN_PKG_MANIFEST_PATH} | jq
|
|
228
|
+
else
|
|
229
|
+
c_echo_err "${HOLOSCAN_PKG_MANIFEST_PATH} does not exists!"
|
|
230
|
+
fi
|
|
231
|
+
fi
|
|
232
|
+
newline
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
print_env() {
|
|
236
|
+
run_command env -0 | sort -z | tr '\0' '\n'
|
|
237
|
+
}
|
|
238
|
+
#===============================================================================
|
|
239
|
+
# Section: Export
|
|
240
|
+
#===============================================================================
|
|
241
|
+
|
|
242
|
+
copy_app() {
|
|
243
|
+
info "Copying application from ${HOLOSCAN_APPLICATION} to ${EXPORT_ROOT}/app"
|
|
244
|
+
if [ -d "${HOLOSCAN_APPLICATION}" ]; then
|
|
245
|
+
run_command cp -r ${HOLOSCAN_APPLICATION} ${EXPORT_ROOT}/app
|
|
246
|
+
else
|
|
247
|
+
info "'${HOLOSCAN_APPLICATION}' cannot be found."
|
|
248
|
+
fi
|
|
249
|
+
newline
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
copy_configs() {
|
|
253
|
+
if [ ! -d "${EXPORT_ROOT}/config/" ]
|
|
254
|
+
then
|
|
255
|
+
mkdir -p ${EXPORT_ROOT}/config/
|
|
256
|
+
fi
|
|
257
|
+
|
|
258
|
+
info "Copying application manifest file from ${HOLOSCAN_APP_MANIFEST_PATH} to ${EXPORT_ROOT}/config/app.json"
|
|
259
|
+
if [ -f "${HOLOSCAN_APP_MANIFEST_PATH}" ]; then
|
|
260
|
+
run_command cp ${HOLOSCAN_APP_MANIFEST_PATH} ${EXPORT_ROOT}/config/app.json
|
|
261
|
+
else
|
|
262
|
+
info "application manifest file '${HOLOSCAN_APP_MANIFEST_PATH}' cannot be found."
|
|
263
|
+
fi
|
|
264
|
+
|
|
265
|
+
info "Copying pkg manifest file from ${HOLOSCAN_PKG_MANIFEST_PATH} to ${EXPORT_ROOT}/config/pkg.json"
|
|
266
|
+
if [ -f "${HOLOSCAN_PKG_MANIFEST_PATH}" ]; then
|
|
267
|
+
run_command cp ${HOLOSCAN_PKG_MANIFEST_PATH} ${EXPORT_ROOT}/config/pkg.json
|
|
268
|
+
else
|
|
269
|
+
info "package manifest file '${HOLOSCAN_PKG_MANIFEST_PATH}' cannot be found."
|
|
270
|
+
fi
|
|
271
|
+
|
|
272
|
+
local CONFIG_FILE_NAME=$(basename ${HOLOSCAN_CONFIG_PATH})
|
|
273
|
+
info "Copying application configuration from ${HOLOSCAN_CONFIG_PATH} to ${EXPORT_ROOT}/config/$CONFIG_FILE_NAME"
|
|
274
|
+
if [ -f "${HOLOSCAN_CONFIG_PATH}" ]; then
|
|
275
|
+
run_command cp ${HOLOSCAN_CONFIG_PATH} ${EXPORT_ROOT}/config/$CONFIG_FILE_NAME
|
|
276
|
+
else
|
|
277
|
+
info "Application configuration'${HOLOSCAN_CONFIG_PATH}' cannot be found."
|
|
278
|
+
fi
|
|
279
|
+
newline
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
copy_models() {
|
|
283
|
+
info "Copying models from ${HOLOSCAN_MODEL_PATH} to ${EXPORT_ROOT}/models"
|
|
284
|
+
if [ -d "${HOLOSCAN_MODEL_PATH}" ]; then
|
|
285
|
+
run_command cp -r ${HOLOSCAN_MODEL_PATH} ${EXPORT_ROOT}/models
|
|
286
|
+
else
|
|
287
|
+
info "'${HOLOSCAN_MODEL_PATH}' cannot be found."
|
|
288
|
+
fi
|
|
289
|
+
newline
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
copy_docs() {
|
|
293
|
+
info "Copying documentation from ${HOLOSCAN_DOCS} to ${EXPORT_ROOT}/docs"
|
|
294
|
+
if [ -d "${HOLOSCAN_DOCS}" ]; then
|
|
295
|
+
run_command cp -r ${HOLOSCAN_DOCS} ${EXPORT_ROOT}/docs
|
|
296
|
+
else
|
|
297
|
+
info "'${HOLOSCAN_DOCS}' cannot be found."
|
|
298
|
+
fi
|
|
299
|
+
newline
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
check_permission(){
|
|
303
|
+
test -w $@
|
|
304
|
+
if [ $? -ne 0 ]; then
|
|
305
|
+
fatal "Permission error: ensure the directory is created on the host first before using the 'extract' command."
|
|
306
|
+
fi
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
copy() {
|
|
311
|
+
EXPORT_ROOT=/var/run/holoscan/export
|
|
312
|
+
|
|
313
|
+
if [ -d "${EXPORT_ROOT}" ]
|
|
314
|
+
then
|
|
315
|
+
if [ -d "${EXPORT_ROOT}/app" ]; then
|
|
316
|
+
check_permission "${EXPORT_ROOT}/app"
|
|
317
|
+
copy_app
|
|
318
|
+
elif [ -d "${EXPORT_ROOT}/config" ]; then
|
|
319
|
+
check_permission "${EXPORT_ROOT}/config"
|
|
320
|
+
copy_configs
|
|
321
|
+
elif [ -d "${EXPORT_ROOT}/models" ]; then
|
|
322
|
+
check_permission "${EXPORT_ROOT}/models"
|
|
323
|
+
copy_models
|
|
324
|
+
elif [ -d "${EXPORT_ROOT}/docs" ]; then
|
|
325
|
+
copy_docs "${EXPORT_ROOT}/docs"
|
|
326
|
+
else
|
|
327
|
+
check_permission "${EXPORT_ROOT}"
|
|
328
|
+
copy_app
|
|
329
|
+
copy_configs
|
|
330
|
+
copy_models
|
|
331
|
+
copy_docs
|
|
332
|
+
fi
|
|
333
|
+
else
|
|
334
|
+
fatal "No volume mount found ${EXPORT_ROOT}."
|
|
335
|
+
fi
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
#===============================================================================
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
print_usage() {
|
|
342
|
+
local YELLOW='\033[0;93m' # YELLOW
|
|
343
|
+
local RED='\033[0;91m' # YELLOW
|
|
344
|
+
local NC='\033[0m' # No Color
|
|
345
|
+
c_echo "USAGE: /var/holoscan/tools [command] [arguments]..."
|
|
346
|
+
c_echo " Command List"
|
|
347
|
+
c_echo " ${YELLOW}extract${NC} --------------------------- Extract data based on mounted volume paths."
|
|
348
|
+
c_echo " /var/run/holoscan/export/app extract the application"
|
|
349
|
+
c_echo " /var/run/holoscan/export/config extract app.json and pkg.json manifest files and application YAML."
|
|
350
|
+
c_echo " /var/run/holoscan/export/models extract models"
|
|
351
|
+
c_echo " /var/run/holoscan/export/docs extract documentation files"
|
|
352
|
+
c_echo " /var/run/holoscan/export extract all of the above"
|
|
353
|
+
c_echo " ${RED}IMPORTANT${NC}: ensure the directory to be mounted for data extraction is created first on the host system"
|
|
354
|
+
c_echo " and has the correct permissions. If the directory had been created by the container previously"
|
|
355
|
+
c_echo " with the user and group being root, please delete it and manually create it again."
|
|
356
|
+
c_echo " ${YELLOW}show${NC} ----------------------------- Print manifest file(s): [app|pkg] to the terminal."
|
|
357
|
+
c_echo " ${YELLOW}app${NC} print app.json"
|
|
358
|
+
c_echo " ${YELLOW}pkg${NC} print pkg.json"
|
|
359
|
+
c_echo " ${YELLOW}env${NC} ------------------------- Print all environment variables to the terminal."
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
main() {
|
|
364
|
+
if [ "$1" = "show" ]; then
|
|
365
|
+
shift
|
|
366
|
+
print "$@"
|
|
367
|
+
elif [ "$1" = "env" ]; then
|
|
368
|
+
shift
|
|
369
|
+
print_env
|
|
370
|
+
elif [ "$1" = "extract" ]; then
|
|
371
|
+
shift
|
|
372
|
+
copy
|
|
373
|
+
elif [ "$1" = "help" ]; then
|
|
374
|
+
shift
|
|
375
|
+
print_usage
|
|
376
|
+
else # all other commands will launch the application
|
|
377
|
+
local command=$(jq -r '.command | fromjson | join(" ")' ${HOLOSCAN_APP_MANIFEST_PATH} 2>/dev/null)
|
|
378
|
+
if [ -n "${command}" ]; then
|
|
379
|
+
args=$(printf " %s" "${@}")
|
|
380
|
+
info "Launching application ${command} ${args:1}..."
|
|
381
|
+
eval ${command} "$@"
|
|
382
|
+
exit_code=$?
|
|
383
|
+
if [ $exit_code -ne 0 ] && [ -f /.dockerenv ] && [ "$HOLOSCAN_HOSTING_SERVICE" != "HOLOSCAN_RUN" ]; then
|
|
384
|
+
newline
|
|
385
|
+
c_echo "================================================================================================"
|
|
386
|
+
c_echo "Application exited with ${exit_code}."
|
|
387
|
+
newline
|
|
388
|
+
newline
|
|
389
|
+
c_echo nocolor "When running inside docker, ensure that the runtime is set to nvidia with required arguments."
|
|
390
|
+
newline
|
|
391
|
+
c_echo nocolor "For example:"
|
|
392
|
+
c_echo nocolor "docker run --runtime nvidia \\"
|
|
393
|
+
c_echo nocolor " --gpus all \\"
|
|
394
|
+
c_echo nocolor " -it \\"
|
|
395
|
+
c_echo nocolor " -e NVIDIA_DRIVER_CAPABILITIES=all \\"
|
|
396
|
+
c_echo nocolor " -e DISPLAY=\$DISPLAY \\"
|
|
397
|
+
c_echo nocolor " -v /tmp/.X11-unix:/tmp/.X11-unix \\"
|
|
398
|
+
c_echo nocolor " -v \${MY-INPUT-DATA}:/var/holoscan/input \\"
|
|
399
|
+
c_echo nocolor " my-container-image[:tag]"
|
|
400
|
+
newline
|
|
401
|
+
c_echo "================================================================================================"
|
|
402
|
+
newline
|
|
403
|
+
fi
|
|
404
|
+
else
|
|
405
|
+
fatal "Failed to launch application; failed to read/parse command from ${HOLOSCAN_APP_MANIFEST_PATH}."
|
|
406
|
+
fi
|
|
407
|
+
fi
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
init_globals
|
|
411
|
+
|
|
412
|
+
if [ -n "${SCRIPT_DIR}" ]; then
|
|
413
|
+
main "$@"
|
|
414
|
+
fi
|
holoscan_cli/py.typed
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
from .runner import execute_run_command # noqa: F401
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
import logging
|
|
16
|
+
import re
|
|
17
|
+
from typing import Optional, Union
|
|
18
|
+
|
|
19
|
+
from ..common.constants import Constants, DefaultValues
|
|
20
|
+
from ..common.exceptions import InvalidSharedMemoryValueError
|
|
21
|
+
|
|
22
|
+
logger = logging.getLogger("runner")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def get_shared_memory_size(
|
|
26
|
+
pkg_info: dict,
|
|
27
|
+
worker: bool,
|
|
28
|
+
driver: bool,
|
|
29
|
+
fragments: str,
|
|
30
|
+
user_shm_size: Optional[str],
|
|
31
|
+
) -> Optional[float]:
|
|
32
|
+
"""Queries the pkg.json file for shared memory requirement of the application
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
pkg_info (dict): package manifest
|
|
36
|
+
worker (bool): start the application as App Worker
|
|
37
|
+
driver (bool): start the application as App Driver
|
|
38
|
+
fragments (str): comma-separated list of fragments
|
|
39
|
+
user_shm_size (Optional[str]): user provided share memory size
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
float: shared memory value in bytes
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
if user_shm_size == "config":
|
|
46
|
+
return _read_shm_size_from_config(pkg_info, worker, driver, fragments)
|
|
47
|
+
elif user_shm_size is not None:
|
|
48
|
+
return _convert_to_bytes(user_shm_size)
|
|
49
|
+
else:
|
|
50
|
+
return None
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _read_shm_size_from_config(
|
|
54
|
+
pkg_info: dict, worker: bool, driver: bool, fragments: str
|
|
55
|
+
) -> float:
|
|
56
|
+
"""Queries the pkg.json file for shared memory requirement of the application
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
pkg_info (dict): package manifest
|
|
60
|
+
worker (bool): start the application as App Worker
|
|
61
|
+
driver (bool): start the application as App Driver
|
|
62
|
+
fragments (str): comma-separated list of fragments
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
float: shared memory value in bytes
|
|
66
|
+
"""
|
|
67
|
+
resources = pkg_info.get("resources") if pkg_info is not None else None
|
|
68
|
+
|
|
69
|
+
if resources is None:
|
|
70
|
+
return DefaultValues.DEFAULT_SHM_SIZE
|
|
71
|
+
|
|
72
|
+
max_value: float = 0
|
|
73
|
+
global_shared_memory_size = _convert_to_bytes(
|
|
74
|
+
resources.get(
|
|
75
|
+
Constants.RESOURCE_SHARED_MEMORY_KEY, DefaultValues.DEFAULT_SHM_SIZE
|
|
76
|
+
)
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
resources_fragments = resources.get("fragments", {})
|
|
80
|
+
if worker:
|
|
81
|
+
if fragments is None or fragments.lower() == "all":
|
|
82
|
+
max_value = _find_maximum_shared_memory_value_from_all_fragments(
|
|
83
|
+
resources_fragments
|
|
84
|
+
)
|
|
85
|
+
else:
|
|
86
|
+
max_value = _find_maximum_shared_memory_value_from_matching_fragments(
|
|
87
|
+
resources_fragments, fragments
|
|
88
|
+
)
|
|
89
|
+
max_value = max(max_value, global_shared_memory_size)
|
|
90
|
+
else:
|
|
91
|
+
if driver:
|
|
92
|
+
max_value = global_shared_memory_size
|
|
93
|
+
else:
|
|
94
|
+
max_value = _find_maximum_shared_memory_value_from_all_fragments(
|
|
95
|
+
resources_fragments
|
|
96
|
+
)
|
|
97
|
+
max_value = max(max_value, global_shared_memory_size)
|
|
98
|
+
|
|
99
|
+
return max_value
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _find_maximum_shared_memory_value_from_matching_fragments(
|
|
103
|
+
resources_fragments: dict, fragments: str
|
|
104
|
+
) -> Optional[float]:
|
|
105
|
+
"""Scan matching fragments for the maximum shared memory value.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
resources_fragments (Dict): fragment resources; resources->fragments
|
|
109
|
+
fragments (str): comma-separated list of fragments to match
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Optional[float]: maximum shred memory value or zero if no fragments found.
|
|
113
|
+
"""
|
|
114
|
+
user_fragments = fragments.split(",")
|
|
115
|
+
fragment_values = [
|
|
116
|
+
_convert_to_bytes(val[Constants.RESOURCE_SHARED_MEMORY_KEY])
|
|
117
|
+
for key, val in resources_fragments.items()
|
|
118
|
+
if Constants.RESOURCE_SHARED_MEMORY_KEY in val and key in user_fragments
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
if fragment_values:
|
|
122
|
+
return max(fragment_values)
|
|
123
|
+
else:
|
|
124
|
+
return 0
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _find_maximum_shared_memory_value_from_all_fragments(
|
|
128
|
+
resources_fragments: dict,
|
|
129
|
+
) -> Optional[float]:
|
|
130
|
+
"""Scan all fragments for the maximum shared memory value.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
resources_fragments (Dict): fragment resources; resources->fragments
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
Optional[float]: maximum shred memory value or zero if no fragments found.
|
|
137
|
+
"""
|
|
138
|
+
fragment_values = [
|
|
139
|
+
_convert_to_bytes(val[Constants.RESOURCE_SHARED_MEMORY_KEY])
|
|
140
|
+
for _, val in resources_fragments.items()
|
|
141
|
+
if Constants.RESOURCE_SHARED_MEMORY_KEY in val
|
|
142
|
+
]
|
|
143
|
+
|
|
144
|
+
if fragment_values:
|
|
145
|
+
return max(fragment_values)
|
|
146
|
+
else:
|
|
147
|
+
return 0
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _convert_to_bytes(raw_value: Union[str, float, int]) -> float:
|
|
151
|
+
"""Converts data measurements in string to float.
|
|
152
|
+
|
|
153
|
+
Supported units are Mi|MiB (mebibytes), Gi|GiB (gibibytes), MB|m (megabytes) and
|
|
154
|
+
GB|g (gigabytes)
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
raw_value (str): data measurement with a number and a supporting unit.
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
float: number of bytes
|
|
161
|
+
"""
|
|
162
|
+
|
|
163
|
+
if type(raw_value) in [float, int]:
|
|
164
|
+
return raw_value
|
|
165
|
+
|
|
166
|
+
result = re.search(r"([.\d]+)\s*(Mi|MiB|Gi|GiB|MB|GB|m|g)", raw_value)
|
|
167
|
+
|
|
168
|
+
if result is not None:
|
|
169
|
+
value = float(result.group(1))
|
|
170
|
+
if result.group(2) in ["Mi", "MiB"]:
|
|
171
|
+
return value * 1048576
|
|
172
|
+
if result.group(2) in ["Gi", "GiB"]:
|
|
173
|
+
return value * 1073741824
|
|
174
|
+
if result.group(2) == "MB":
|
|
175
|
+
return value * 1000000
|
|
176
|
+
if result.group(2) == "GB":
|
|
177
|
+
return value * 1000000000
|
|
178
|
+
if result.group(2) == "m":
|
|
179
|
+
return value * 1000000
|
|
180
|
+
if result.group(2) == "g":
|
|
181
|
+
return value * 1000000000
|
|
182
|
+
|
|
183
|
+
raise InvalidSharedMemoryValueError(
|
|
184
|
+
f"Invalid/unsupported shared memory value: {raw_value}. "
|
|
185
|
+
)
|