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
holoscan_cli/__init__.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
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
|
+
"""
|
|
16
|
+
.. autosummary::
|
|
17
|
+
:toctree: _autosummary
|
|
18
|
+
|
|
19
|
+
common
|
|
20
|
+
packager
|
|
21
|
+
runner
|
|
22
|
+
version
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import importlib.metadata
|
|
26
|
+
import os
|
|
27
|
+
import sys
|
|
28
|
+
|
|
29
|
+
__title__ = "holoscan_cli"
|
|
30
|
+
_current_dir = os.path.abspath(os.path.dirname(__file__))
|
|
31
|
+
if sys.path and os.path.abspath(sys.path[0]) != _current_dir:
|
|
32
|
+
sys.path.insert(0, _current_dir)
|
|
33
|
+
del _current_dir
|
|
34
|
+
|
|
35
|
+
__version__ = importlib.metadata.version("holoscan-cli")
|
holoscan_cli/__main__.py
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
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 argparse
|
|
16
|
+
import json
|
|
17
|
+
import logging
|
|
18
|
+
import logging.config
|
|
19
|
+
import os
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from typing import Optional, Union
|
|
22
|
+
|
|
23
|
+
from .common.enum_types import Platform, PlatformConfiguration
|
|
24
|
+
|
|
25
|
+
logging.getLogger("docker.api.build").setLevel(logging.WARNING)
|
|
26
|
+
logging.getLogger("docker.auth").setLevel(logging.WARNING)
|
|
27
|
+
logging.getLogger("docker.utils.config").setLevel(logging.WARNING)
|
|
28
|
+
logging.getLogger("urllib3.connectionpool").setLevel(logging.WARNING)
|
|
29
|
+
logging.getLogger("urllib3").setLevel(logging.WARNING)
|
|
30
|
+
|
|
31
|
+
LOG_CONFIG_FILENAME = "logging.json"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def parse_args(argv: Optional[list[str]] = None) -> argparse.Namespace:
|
|
35
|
+
from .packager.package_command import create_package_parser
|
|
36
|
+
from .runner.run_command import create_run_parser
|
|
37
|
+
|
|
38
|
+
if argv is None:
|
|
39
|
+
import sys
|
|
40
|
+
|
|
41
|
+
argv = sys.argv
|
|
42
|
+
argv = list(argv) # copy argv for manipulation to avoid side-effects
|
|
43
|
+
|
|
44
|
+
# We have intentionally not set the default using `default="INFO"` here so that the default
|
|
45
|
+
# value from here doesn't override the value in `LOG_CONFIG_FILENAME` unless the user indends
|
|
46
|
+
# to do so. If the user doesn't use this flag to set log level, this argument is set to "None"
|
|
47
|
+
# and the logging level specified in `LOG_CONFIG_FILENAME` is used.
|
|
48
|
+
|
|
49
|
+
command_name = os.path.basename(argv[0])
|
|
50
|
+
program_name = "holoscan" if command_name == "__main__.py" else command_name
|
|
51
|
+
parent_parser = argparse.ArgumentParser()
|
|
52
|
+
|
|
53
|
+
parent_parser.add_argument(
|
|
54
|
+
"-l",
|
|
55
|
+
"--log-level",
|
|
56
|
+
dest="log_level",
|
|
57
|
+
type=str.upper,
|
|
58
|
+
choices=["DEBUG", "INFO", "WARN", "ERROR", "CRITICAL"],
|
|
59
|
+
help="set the logging level (default: INFO)",
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
parser = argparse.ArgumentParser(
|
|
63
|
+
parents=[parent_parser],
|
|
64
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
65
|
+
add_help=False,
|
|
66
|
+
prog=program_name,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
subparser = parser.add_subparsers(dest="command")
|
|
70
|
+
|
|
71
|
+
# Parser for `package` command
|
|
72
|
+
create_package_parser(subparser, "package", parents=[parent_parser])
|
|
73
|
+
|
|
74
|
+
# Parser for `run` command
|
|
75
|
+
create_run_parser(subparser, "run", parents=[parent_parser])
|
|
76
|
+
|
|
77
|
+
# Parser for `version` command
|
|
78
|
+
subparser.add_parser(
|
|
79
|
+
"version",
|
|
80
|
+
formatter_class=argparse.HelpFormatter,
|
|
81
|
+
parents=[parent_parser],
|
|
82
|
+
add_help=False,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# Parser for `nics` command
|
|
86
|
+
subparser.add_parser(
|
|
87
|
+
"nics",
|
|
88
|
+
formatter_class=argparse.HelpFormatter,
|
|
89
|
+
parents=[parent_parser],
|
|
90
|
+
add_help=False,
|
|
91
|
+
)
|
|
92
|
+
args = parser.parse_args(argv[1:])
|
|
93
|
+
args.argv = argv # save argv for later use in runpy
|
|
94
|
+
|
|
95
|
+
# Print help if no command is specified
|
|
96
|
+
if args.command is None:
|
|
97
|
+
parser.print_help()
|
|
98
|
+
parser.exit()
|
|
99
|
+
|
|
100
|
+
if args.command == "package":
|
|
101
|
+
if args.platform[0] == Platform.X64Workstation:
|
|
102
|
+
args.platform_config = PlatformConfiguration.dGPU
|
|
103
|
+
elif args.platform_config is None:
|
|
104
|
+
parser.error(
|
|
105
|
+
f"'--platform-config' is required for '{args.platform[0].value}'"
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
return args
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def set_up_logging(
|
|
112
|
+
level: Optional[str], config_path: Union[str, Path] = LOG_CONFIG_FILENAME
|
|
113
|
+
):
|
|
114
|
+
"""Initializes the logger and sets up logging level.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
level (str): A logging level (DEBUG, INFO, WARN, ERROR, CRITICAL).
|
|
118
|
+
log_config_path (str): A path to logging config file.
|
|
119
|
+
"""
|
|
120
|
+
# Default log config path
|
|
121
|
+
log_config_path = Path(__file__).absolute().parent / LOG_CONFIG_FILENAME
|
|
122
|
+
|
|
123
|
+
config_path = Path(config_path)
|
|
124
|
+
|
|
125
|
+
# If a logging config file that is specified by `log_config_path` exists in the current folder,
|
|
126
|
+
# it overrides the default one
|
|
127
|
+
if config_path.exists():
|
|
128
|
+
log_config_path = config_path
|
|
129
|
+
|
|
130
|
+
config_dict = json.loads(log_config_path.read_bytes())
|
|
131
|
+
|
|
132
|
+
if level is not None and "root" in config_dict:
|
|
133
|
+
config_dict["root"]["level"] = level
|
|
134
|
+
logging.config.dictConfig(config_dict)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def main(argv: Optional[list[str]] = None):
|
|
138
|
+
args = parse_args(argv)
|
|
139
|
+
|
|
140
|
+
set_up_logging(args.log_level)
|
|
141
|
+
|
|
142
|
+
if args.command == "package":
|
|
143
|
+
from .packager.packager import execute_package_command
|
|
144
|
+
|
|
145
|
+
execute_package_command(args)
|
|
146
|
+
|
|
147
|
+
elif args.command == "run":
|
|
148
|
+
from .runner.runner import execute_run_command
|
|
149
|
+
|
|
150
|
+
execute_run_command(args)
|
|
151
|
+
|
|
152
|
+
elif args.command == "version":
|
|
153
|
+
from .version.version import execute_version_command
|
|
154
|
+
|
|
155
|
+
execute_version_command(args)
|
|
156
|
+
|
|
157
|
+
elif args.command == "nics":
|
|
158
|
+
from .nics.nics import execute_nics_command
|
|
159
|
+
|
|
160
|
+
execute_nics_command(args)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
if __name__ == "__main__":
|
|
164
|
+
main()
|
|
@@ -0,0 +1,156 @@
|
|
|
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 argparse
|
|
16
|
+
import os
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
from .constants import SDK
|
|
20
|
+
from .enum_types import Platform, PlatformConfiguration, SdkType
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def valid_dir_path(path: str, create_if_not_exists: bool = True) -> Path:
|
|
24
|
+
"""Helper type checking and type converting method for ArgumentParser.add_argument
|
|
25
|
+
to convert string input to pathlib.Path if the given path exists and it is a directory path.
|
|
26
|
+
If directory does not exist, create the directory and convert string input to pathlib.Path.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
path: string input path
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
If path exists and is a directory, return absolute path as a pathlib.Path object.
|
|
33
|
+
|
|
34
|
+
If path exists and is not a directory, raises argparse.ArgumentTypeError.
|
|
35
|
+
|
|
36
|
+
If path doesn't exist, create the directory and return absolute path as a pathlib.Path
|
|
37
|
+
object.
|
|
38
|
+
"""
|
|
39
|
+
path = os.path.expanduser(path)
|
|
40
|
+
dir_path = Path(path).absolute()
|
|
41
|
+
if dir_path.exists():
|
|
42
|
+
if dir_path.is_dir():
|
|
43
|
+
return dir_path
|
|
44
|
+
else:
|
|
45
|
+
raise argparse.ArgumentTypeError(
|
|
46
|
+
f"Expected directory path: '{dir_path}' is not a directory"
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
if create_if_not_exists:
|
|
50
|
+
# create directory
|
|
51
|
+
dir_path.mkdir(parents=True)
|
|
52
|
+
return dir_path
|
|
53
|
+
|
|
54
|
+
raise argparse.ArgumentTypeError(f"No such directory: '{dir_path}'")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def valid_existing_dir_path(path: str) -> Path:
|
|
58
|
+
"""Helper type checking and type converting method for ArgumentParser.add_argument
|
|
59
|
+
to convert string input to pathlib.Path if the given path exists and it is a directory path.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
path: string input path
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
If path exists and is a directory, return absolute path as a pathlib.Path object.
|
|
66
|
+
|
|
67
|
+
If path doesn't exist or it is not a directory, raises argparse.ArgumentTypeError.
|
|
68
|
+
"""
|
|
69
|
+
return valid_dir_path(path, False)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def valid_existing_path(path: str) -> Path:
|
|
73
|
+
"""Helper type checking and type converting method for ArgumentParser.add_argument
|
|
74
|
+
to convert string input to pathlib.Path if the given file/folder path exists.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
path: string input path
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
If path exists, return absolute path as a pathlib.Path object.
|
|
81
|
+
|
|
82
|
+
If path doesn't exist, raises argparse.ArgumentTypeError.
|
|
83
|
+
"""
|
|
84
|
+
path = os.path.expanduser(path)
|
|
85
|
+
file_path = Path(path).absolute()
|
|
86
|
+
if file_path.exists():
|
|
87
|
+
if file_path.is_dir():
|
|
88
|
+
if any(os.scandir(file_path)):
|
|
89
|
+
return file_path
|
|
90
|
+
raise argparse.ArgumentTypeError(f"Directory is empty: '{file_path}'")
|
|
91
|
+
return file_path
|
|
92
|
+
raise argparse.ArgumentTypeError(f"No such file/folder: '{file_path}'")
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def valid_platforms(platforms_str: str) -> list[Platform]:
|
|
96
|
+
"""Helper type checking and type converting method for ArgumentParser.add_argument
|
|
97
|
+
to convert platform strings to Platform enum if values are valid.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
platforms_str: string comma separated platforms values
|
|
101
|
+
Returns:
|
|
102
|
+
If all values are valid, convert all values to Platform enum.
|
|
103
|
+
|
|
104
|
+
Otherwise, raises argparse.ArgumentTypeError.
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
platforms = platforms_str.lower().split(",")
|
|
108
|
+
platform_enums = []
|
|
109
|
+
for platform in platforms:
|
|
110
|
+
if platform not in SDK.PLATFORMS:
|
|
111
|
+
raise argparse.ArgumentTypeError(
|
|
112
|
+
f"{platform} is not a valid option for --platforms."
|
|
113
|
+
)
|
|
114
|
+
platform_enums.append(Platform(platform))
|
|
115
|
+
|
|
116
|
+
return platform_enums
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def valid_platform_config(platform_config_str: str) -> PlatformConfiguration:
|
|
120
|
+
"""Helper type checking and type converting method for ArgumentParser.add_argument
|
|
121
|
+
to convert platform configuration string to PlatformConfigurations enum if value is valid.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
platform_config_str: a platforms configuration value
|
|
125
|
+
Returns:
|
|
126
|
+
If the value is valid, convert the value to PlatformConfigurations enum.
|
|
127
|
+
|
|
128
|
+
Otherwise, raises argparse.ArgumentTypeError.
|
|
129
|
+
"""
|
|
130
|
+
|
|
131
|
+
platform_config_str = platform_config_str.lower()
|
|
132
|
+
if platform_config_str not in SDK.PLATFORM_CONFIGS:
|
|
133
|
+
raise argparse.ArgumentTypeError(
|
|
134
|
+
f"{platform_config_str} is not a valid option for --platform-config."
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
return PlatformConfiguration(platform_config_str)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def valid_sdk_type(sdk_str: str) -> SdkType:
|
|
141
|
+
"""Helper type checking and type converting method for ArgumentParser.add_argument
|
|
142
|
+
to convert sdk string to SdkType enum if value is valid.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
sdk_str: sdk string
|
|
146
|
+
Returns:
|
|
147
|
+
If the value is valid, convert the value to SdkType enum.
|
|
148
|
+
|
|
149
|
+
Otherwise, raises argparse.ArgumentTypeError.
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
sdk_str = sdk_str.lower()
|
|
153
|
+
if sdk_str not in SDK.SDKS:
|
|
154
|
+
raise argparse.ArgumentTypeError(f"{sdk_str} is not a valid option for --sdk.")
|
|
155
|
+
|
|
156
|
+
return SdkType(sdk_str)
|
|
@@ -0,0 +1,160 @@
|
|
|
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 json
|
|
16
|
+
import logging
|
|
17
|
+
from typing import Any, Optional
|
|
18
|
+
|
|
19
|
+
import requests
|
|
20
|
+
|
|
21
|
+
from holoscan_cli import __version__
|
|
22
|
+
from packaging.version import InvalidVersion, Version
|
|
23
|
+
|
|
24
|
+
from .enum_types import PlatformConfiguration, SdkType
|
|
25
|
+
from .exceptions import InvalidSourceFileError, ManifestDownloadError
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ArtifactSources:
|
|
29
|
+
"""Provides default artifact source URLs with the ability to override."""
|
|
30
|
+
|
|
31
|
+
SectionWheelVersion = "wheel-version"
|
|
32
|
+
SectionDebianVersion = "debian-version"
|
|
33
|
+
SectionBaseImages = "base-images"
|
|
34
|
+
SectionBuildImages = "build-images"
|
|
35
|
+
SectionHealthProbe = "health-probes"
|
|
36
|
+
HoloscanVersion = None
|
|
37
|
+
ManifestFileUrl = None
|
|
38
|
+
|
|
39
|
+
def __init__(self) -> None:
|
|
40
|
+
self._logger = logging.getLogger("common")
|
|
41
|
+
try:
|
|
42
|
+
ArtifactSources.HoloscanVersion = ".".join(
|
|
43
|
+
str(i) for i in Version(__version__).release[0:3]
|
|
44
|
+
)
|
|
45
|
+
except InvalidVersion as ex:
|
|
46
|
+
raise RuntimeError(
|
|
47
|
+
"Unable to detect Holoscan version. Use --sdk-version to specify "
|
|
48
|
+
"a Holoscan SDK version to use."
|
|
49
|
+
) from ex
|
|
50
|
+
|
|
51
|
+
ArtifactSources.ManifestFileUrl = f"https://raw.githubusercontent.com/nvidia-holoscan/holoscan-cli/refs/heads/main/releases/{ArtifactSources.HoloscanVersion}/artifacts.json" # noqa: E501
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def holoscan_versions(self) -> list[str]:
|
|
55
|
+
# logic to dynamically fetch the supported versions
|
|
56
|
+
return self._data.keys()
|
|
57
|
+
|
|
58
|
+
def base_image(self, version) -> str:
|
|
59
|
+
return self._data[version][SdkType.Holoscan.value][
|
|
60
|
+
ArtifactSources.SectionBaseImages
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
def build_images(self, version) -> dict[Any, str]:
|
|
64
|
+
return self._data[version][SdkType.Holoscan.value][
|
|
65
|
+
ArtifactSources.SectionBuildImages
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
def health_probe(self, version) -> dict[Any, str]:
|
|
69
|
+
return self._data[version][ArtifactSources.SectionHealthProbe]
|
|
70
|
+
|
|
71
|
+
def load(self, uri: str):
|
|
72
|
+
"""Overrides the default values from a given JSON file.
|
|
73
|
+
Validates top-level attributes to ensure the file is valid
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
file (Path): Path to JSON file
|
|
77
|
+
"""
|
|
78
|
+
if uri.startswith("https"):
|
|
79
|
+
self._download_manifest_internal(uri)
|
|
80
|
+
elif uri.startswith("http"):
|
|
81
|
+
raise ManifestDownloadError(
|
|
82
|
+
"Downloading manifest files from non-HTTPS servers is not supported."
|
|
83
|
+
)
|
|
84
|
+
else:
|
|
85
|
+
self._logger.info(f"Using CLI manifest file from {uri}...")
|
|
86
|
+
with open(uri) as file:
|
|
87
|
+
temp = json.load(file)
|
|
88
|
+
|
|
89
|
+
try:
|
|
90
|
+
self.validate(temp)
|
|
91
|
+
self._data = temp
|
|
92
|
+
except Exception as ex:
|
|
93
|
+
raise InvalidSourceFileError(
|
|
94
|
+
f"{uri} is missing required data: {ex}"
|
|
95
|
+
) from ex
|
|
96
|
+
|
|
97
|
+
def validate(self, data: Any):
|
|
98
|
+
self._logger.debug("Validating CLI manifest file...")
|
|
99
|
+
|
|
100
|
+
for key in data:
|
|
101
|
+
item = data[key]
|
|
102
|
+
assert SdkType.Holoscan.value in item
|
|
103
|
+
holoscan = item[SdkType.Holoscan.value]
|
|
104
|
+
|
|
105
|
+
assert ArtifactSources.SectionWheelVersion in holoscan
|
|
106
|
+
assert ArtifactSources.SectionDebianVersion in holoscan
|
|
107
|
+
assert ArtifactSources.SectionBaseImages in holoscan
|
|
108
|
+
assert ArtifactSources.SectionBuildImages in holoscan
|
|
109
|
+
|
|
110
|
+
for config in PlatformConfiguration:
|
|
111
|
+
assert config.value in holoscan[ArtifactSources.SectionBuildImages]
|
|
112
|
+
|
|
113
|
+
def download_manifest(self):
|
|
114
|
+
self._download_manifest_internal(
|
|
115
|
+
ArtifactSources.ManifestFileUrl,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
def _download_manifest_internal(self, url, headers=None):
|
|
119
|
+
self._logger.info("Downloading CLI manifest file...")
|
|
120
|
+
manifest = requests.get(url, headers=headers)
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
manifest.raise_for_status()
|
|
124
|
+
except Exception as ex:
|
|
125
|
+
raise ManifestDownloadError(
|
|
126
|
+
f"Error downloading manifest file from {url}: {manifest.reason}"
|
|
127
|
+
) from ex
|
|
128
|
+
else:
|
|
129
|
+
self._data = manifest.json()
|
|
130
|
+
self.validate(self._data)
|
|
131
|
+
|
|
132
|
+
def debian_package_version(self, version: str) -> Optional[str]:
|
|
133
|
+
"""Gets the version of the Debian package based on the version of Holoscan.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
version (str): version of Holoscan
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
Optional[str]: Debian package version
|
|
140
|
+
"""
|
|
141
|
+
return (
|
|
142
|
+
self._data[version][SdkType.Holoscan.value][
|
|
143
|
+
ArtifactSources.SectionDebianVersion
|
|
144
|
+
]
|
|
145
|
+
if version in self._data
|
|
146
|
+
else None
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
def wheel_package_version(self, version: str) -> Optional[str]:
|
|
150
|
+
"""Gets the version of the PyPI package based on the version of Holoscan.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
version (str): version of Holoscan
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
Optional[str]: PyPI package version
|
|
157
|
+
"""
|
|
158
|
+
return self._data[version][SdkType.Holoscan.value][
|
|
159
|
+
ArtifactSources.SectionWheelVersion
|
|
160
|
+
]
|
|
@@ -0,0 +1,119 @@
|
|
|
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 pathlib import Path
|
|
16
|
+
|
|
17
|
+
from .enum_types import Arch, Platform, PlatformConfiguration, SdkType
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class DefaultValues:
|
|
21
|
+
"""
|
|
22
|
+
This class contains default values for various parameters.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
API_VERSION = "1.0.0" # MAP/HAP version number
|
|
26
|
+
DOCKER_FILE_NAME = "Dockerfile" # Filename of the generated Dockerfile
|
|
27
|
+
TIMEOUT = 0 # Default application timeout
|
|
28
|
+
USERNAME = "holoscan" # Default user to be created in the container
|
|
29
|
+
BUILD_CACHE_DIR = Path(
|
|
30
|
+
"~/.holoscan_build_cache"
|
|
31
|
+
) # A local directory used for storing Docker build cache
|
|
32
|
+
|
|
33
|
+
HOLOSCAN_APP_DIR = Path("/opt/holoscan/app") # Path to user's application
|
|
34
|
+
HOLOSCAN_LIB_DIR = Path("/opt/holoscan/lib") # Path to user's application
|
|
35
|
+
HOLOSCAN_CONFIG_PATH = Path(
|
|
36
|
+
"/var/holoscan/app.yaml"
|
|
37
|
+
) # Path to the application config file
|
|
38
|
+
HOLOSCAN_DOCS_DIR = Path("/opt/holoscan/docs") # Path to documentation
|
|
39
|
+
HOLOSCAN_LOGS_DIR = Path("/var/holoscan/logs") # Path to application logs
|
|
40
|
+
INPUT_DIR = "input/" # Relative path to application input data
|
|
41
|
+
MODELS_DIR = Path("/opt/holoscan/models/") # Path to user provided model(s)
|
|
42
|
+
OUTPUT_DIR = "output/" # Relative path to application generated results
|
|
43
|
+
WORK_DIR = Path("/var/holoscan/") # Default working directory
|
|
44
|
+
APP_MANIFEST_PATH = "/etc/holoscan/app.json" # Path to app.json manifest file
|
|
45
|
+
PKG_MANIFEST_PATH = "/etc/holoscan/pkg.json" # Path to pkg.json manifest file
|
|
46
|
+
|
|
47
|
+
DEFAULT_SHM_SIZE = 1073741824
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class Constants:
|
|
51
|
+
CPP_CMAKELIST_FILE = "CMakeLists.txt"
|
|
52
|
+
PYTHON_EXECUTABLE = "python3"
|
|
53
|
+
PYTHON_MAIN_FILE = "__main__.py"
|
|
54
|
+
|
|
55
|
+
TARBALL_FILE_EXTENSION = ".tar"
|
|
56
|
+
|
|
57
|
+
DEBIAN_FILE_EXTENSION = ".deb"
|
|
58
|
+
PYPI_WHEEL_FILE_EXTENSION = ".whl"
|
|
59
|
+
PYPI_TARGZ_FILE_EXTENSION = ".gz"
|
|
60
|
+
PYTHON_FILE_EXTENSION = ".py"
|
|
61
|
+
|
|
62
|
+
PYPI_FILE_EXTENSIONS = [PYPI_WHEEL_FILE_EXTENSION, PYPI_TARGZ_FILE_EXTENSION]
|
|
63
|
+
|
|
64
|
+
LOCAL_BUILDX_BUILDER_NAME = "holoscan_app_builder"
|
|
65
|
+
LOCAL_DOCKER_REGISTRY_NAME = "holoscan_build_registry"
|
|
66
|
+
LOCAL_REGISTRY_IMAGE_NAME = "registry:2"
|
|
67
|
+
LOCAL_REGISTRY_HOST = "localhost"
|
|
68
|
+
LOCAL_REGISTRY_INTERNAL_PORT = "5000/tcp"
|
|
69
|
+
|
|
70
|
+
RESOURCE_SHARED_MEMORY_KEY = "sharedMemory"
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class SDK:
|
|
74
|
+
"""
|
|
75
|
+
This class contains lookup tables for various platform and SDK settings.
|
|
76
|
+
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
# Platform to architecture mappings
|
|
80
|
+
PLATFORM_MAPPINGS = {
|
|
81
|
+
Platform.IGXOrinDevIt: Arch.arm64,
|
|
82
|
+
Platform.JetsonAgxOrinDevKit: Arch.arm64,
|
|
83
|
+
Platform.SBSA: Arch.arm64,
|
|
84
|
+
Platform.X64Workstation: Arch.amd64,
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
# Values of all platforms supported by the Packager
|
|
88
|
+
PLATFORMS = [
|
|
89
|
+
Platform.IGXOrinDevIt.value,
|
|
90
|
+
Platform.JetsonAgxOrinDevKit.value,
|
|
91
|
+
Platform.SBSA.value,
|
|
92
|
+
Platform.X64Workstation.value,
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
# Values of all platform configurations supported by the Packager
|
|
96
|
+
PLATFORM_CONFIGS = [
|
|
97
|
+
PlatformConfiguration.iGPU.value,
|
|
98
|
+
PlatformConfiguration.dGPU.value,
|
|
99
|
+
]
|
|
100
|
+
|
|
101
|
+
# Values of SDKs supported by the Packager
|
|
102
|
+
SDKS = [SdkType.Holoscan.value, SdkType.MonaiDeploy.value]
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class EnvironmentVariables:
|
|
106
|
+
"""
|
|
107
|
+
This class includes all environment variables set in
|
|
108
|
+
the container and in the app.json manifest file."""
|
|
109
|
+
|
|
110
|
+
HOLOSCAN_APPLICATION = "HOLOSCAN_APPLICATION"
|
|
111
|
+
HOLOSCAN_INPUT_PATH = "HOLOSCAN_INPUT_PATH"
|
|
112
|
+
HOLOSCAN_OUTPUT_PATH = "HOLOSCAN_OUTPUT_PATH"
|
|
113
|
+
HOLOSCAN_WORKDIR = "HOLOSCAN_WORKDIR"
|
|
114
|
+
HOLOSCAN_MODEL_PATH = "HOLOSCAN_MODEL_PATH"
|
|
115
|
+
HOLOSCAN_CONFIG_PATH = "HOLOSCAN_CONFIG_PATH"
|
|
116
|
+
HOLOSCAN_APP_MANIFEST_PATH = "HOLOSCAN_APP_MANIFEST_PATH"
|
|
117
|
+
HOLOSCAN_PKG_MANIFEST_PATH = "HOLOSCAN_PKG_MANIFEST_PATH"
|
|
118
|
+
HOLOSCAN_DOCS_PATH = "HOLOSCAN_DOCS_PATH"
|
|
119
|
+
HOLOSCAN_LOGS_PATH = "HOLOSCAN_LOGS_PATH"
|