holoscan 2.6.0__cp312-cp312-manylinux_2_35_aarch64.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.
Files changed (126) hide show
  1. holoscan-2.6.0.data/purelib/holoscan/__init__.py +133 -0
  2. holoscan-2.6.0.data/purelib/holoscan/cli/__init__.py +32 -0
  3. holoscan-2.6.0.data/purelib/holoscan/cli/__main__.py +159 -0
  4. holoscan-2.6.0.data/purelib/holoscan/cli/common/argparse_types.py +153 -0
  5. holoscan-2.6.0.data/purelib/holoscan/cli/common/artifact_sources.py +149 -0
  6. holoscan-2.6.0.data/purelib/holoscan/cli/common/constants.py +119 -0
  7. holoscan-2.6.0.data/purelib/holoscan/cli/common/dockerutils.py +509 -0
  8. holoscan-2.6.0.data/purelib/holoscan/cli/common/enum_types.py +52 -0
  9. holoscan-2.6.0.data/purelib/holoscan/cli/common/exceptions.py +130 -0
  10. holoscan-2.6.0.data/purelib/holoscan/cli/common/sdk_utils.py +180 -0
  11. holoscan-2.6.0.data/purelib/holoscan/cli/common/utils.py +130 -0
  12. holoscan-2.6.0.data/purelib/holoscan/cli/logging.json +37 -0
  13. holoscan-2.6.0.data/purelib/holoscan/cli/nics/__init__.py +18 -0
  14. holoscan-2.6.0.data/purelib/holoscan/cli/nics/nics.py +34 -0
  15. holoscan-2.6.0.data/purelib/holoscan/cli/packager/__init__.py +18 -0
  16. holoscan-2.6.0.data/purelib/holoscan/cli/packager/arguments.py +137 -0
  17. holoscan-2.6.0.data/purelib/holoscan/cli/packager/config_reader.py +181 -0
  18. holoscan-2.6.0.data/purelib/holoscan/cli/packager/container_builder.py +368 -0
  19. holoscan-2.6.0.data/purelib/holoscan/cli/packager/manifest_files.py +220 -0
  20. holoscan-2.6.0.data/purelib/holoscan/cli/packager/models.py +93 -0
  21. holoscan-2.6.0.data/purelib/holoscan/cli/packager/package_command.py +189 -0
  22. holoscan-2.6.0.data/purelib/holoscan/cli/packager/packager.py +122 -0
  23. holoscan-2.6.0.data/purelib/holoscan/cli/packager/parameters.py +558 -0
  24. holoscan-2.6.0.data/purelib/holoscan/cli/packager/platforms.py +402 -0
  25. holoscan-2.6.0.data/purelib/holoscan/cli/packager/templates/Dockerfile.jinja2 +470 -0
  26. holoscan-2.6.0.data/purelib/holoscan/cli/packager/templates/dockerignore +93 -0
  27. holoscan-2.6.0.data/purelib/holoscan/cli/packager/templates/tools.sh +416 -0
  28. holoscan-2.6.0.data/purelib/holoscan/cli/py.typed +0 -0
  29. holoscan-2.6.0.data/purelib/holoscan/cli/runner/__init__.py +18 -0
  30. holoscan-2.6.0.data/purelib/holoscan/cli/runner/resources.py +174 -0
  31. holoscan-2.6.0.data/purelib/holoscan/cli/runner/run_command.py +203 -0
  32. holoscan-2.6.0.data/purelib/holoscan/cli/runner/runner.py +306 -0
  33. holoscan-2.6.0.data/purelib/holoscan/cli/version/__init__.py +18 -0
  34. holoscan-2.6.0.data/purelib/holoscan/cli/version/version.py +50 -0
  35. holoscan-2.6.0.data/purelib/holoscan/conditions/__init__.py +57 -0
  36. holoscan-2.6.0.data/purelib/holoscan/core/__init__.py +430 -0
  37. holoscan-2.6.0.data/purelib/holoscan/decorator.py +592 -0
  38. holoscan-2.6.0.data/purelib/holoscan/executors/__init__.py +26 -0
  39. holoscan-2.6.0.data/purelib/holoscan/graphs/__init__.py +32 -0
  40. holoscan-2.6.0.data/purelib/holoscan/gxf/__init__.py +57 -0
  41. holoscan-2.6.0.data/purelib/holoscan/lib/gxf_extensions/libgxf_holoscan_wrapper.so +0 -0
  42. holoscan-2.6.0.data/purelib/holoscan/lib/gxf_extensions/libgxf_holoscan_wrapper_lib.so +0 -0
  43. holoscan-2.6.0.data/purelib/holoscan/lib/gxf_extensions/libgxf_ucx_holoscan.so +0 -0
  44. holoscan-2.6.0.data/purelib/holoscan/lib/gxf_extensions/libgxf_ucx_holoscan_lib.so +0 -0
  45. holoscan-2.6.0.data/purelib/holoscan/lib/libgxf_app.so +0 -0
  46. holoscan-2.6.0.data/purelib/holoscan/lib/libgxf_core.so +0 -0
  47. holoscan-2.6.0.data/purelib/holoscan/lib/libgxf_cuda.so +0 -0
  48. holoscan-2.6.0.data/purelib/holoscan/lib/libgxf_logger.so +0 -0
  49. holoscan-2.6.0.data/purelib/holoscan/lib/libgxf_multimedia.so +0 -0
  50. holoscan-2.6.0.data/purelib/holoscan/lib/libgxf_rmm.so +0 -0
  51. holoscan-2.6.0.data/purelib/holoscan/lib/libgxf_sample.so +0 -0
  52. holoscan-2.6.0.data/purelib/holoscan/lib/libgxf_serialization.so +0 -0
  53. holoscan-2.6.0.data/purelib/holoscan/lib/libgxf_std.so +0 -0
  54. holoscan-2.6.0.data/purelib/holoscan/lib/libgxf_ucx.so +0 -0
  55. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_core.so.2.6.0 +0 -0
  56. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_infer.so.2.6.0 +0 -0
  57. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_infer_onnx_runtime.so.2.6.0 +0 -0
  58. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_infer_torch.so.2.6.0 +0 -0
  59. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_infer_utils.so.2.6.0 +0 -0
  60. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_logger.so.2.6.0 +0 -0
  61. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_aja.so.2.6.0 +0 -0
  62. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_async_ping_rx.so.2.6.0 +0 -0
  63. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_async_ping_tx.so.2.6.0 +0 -0
  64. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_bayer_demosaic.so.2.6.0 +0 -0
  65. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_format_converter.so.2.6.0 +0 -0
  66. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_gxf_codelet.so.2.6.0 +0 -0
  67. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_holoviz.so.2.6.0 +0 -0
  68. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_inference.so.2.6.0 +0 -0
  69. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_inference_processor.so.2.6.0 +0 -0
  70. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_ping_rx.so.2.6.0 +0 -0
  71. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_ping_tensor_rx.so.2.6.0 +0 -0
  72. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_ping_tensor_tx.so.2.6.0 +0 -0
  73. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_ping_tx.so.2.6.0 +0 -0
  74. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_segmentation_postprocessor.so.2.6.0 +0 -0
  75. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_v4l2.so.2.6.0 +0 -0
  76. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_video_stream_recorder.so.2.6.0 +0 -0
  77. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_video_stream_replayer.so.2.6.0 +0 -0
  78. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_profiler.so.2.6.0 +0 -0
  79. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_spdlog_logger.so.2.6.0 +0 -0
  80. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_viz.so.2.6.0 +0 -0
  81. holoscan-2.6.0.data/purelib/holoscan/lib/libucm.so.0.0.0 +0 -0
  82. holoscan-2.6.0.data/purelib/holoscan/lib/libucp.so.0.0.0 +0 -0
  83. holoscan-2.6.0.data/purelib/holoscan/lib/libucs.so.0.0.0 +0 -0
  84. holoscan-2.6.0.data/purelib/holoscan/lib/libucs_signal.so.0.0.0 +0 -0
  85. holoscan-2.6.0.data/purelib/holoscan/lib/libuct.so.0.0.0 +0 -0
  86. holoscan-2.6.0.data/purelib/holoscan/lib/libyaml-cpp.so.0.7.0 +0 -0
  87. holoscan-2.6.0.data/purelib/holoscan/lib/ucx/libucm_cuda.so.0.0.0 +0 -0
  88. holoscan-2.6.0.data/purelib/holoscan/lib/ucx/libucs_fuse.so.0.0.0 +0 -0
  89. holoscan-2.6.0.data/purelib/holoscan/lib/ucx/libuct_cma.so.0.0.0 +0 -0
  90. holoscan-2.6.0.data/purelib/holoscan/lib/ucx/libuct_cuda.so.0.0.0 +0 -0
  91. holoscan-2.6.0.data/purelib/holoscan/lib/ucx/libuct_cuda_gdrcopy.so.0.0.0 +0 -0
  92. holoscan-2.6.0.data/purelib/holoscan/lib/ucx/libuct_ib.so.0.0.0 +0 -0
  93. holoscan-2.6.0.data/purelib/holoscan/lib/ucx/libuct_rdmacm.so.0.0.0 +0 -0
  94. holoscan-2.6.0.data/purelib/holoscan/lib/ucx/libuct_xpmem.so.0.0.0 +0 -0
  95. holoscan-2.6.0.data/purelib/holoscan/lib/ucx/libucx_perftest_cuda.so.0.0.0 +0 -0
  96. holoscan-2.6.0.data/purelib/holoscan/logger/__init__.py +37 -0
  97. holoscan-2.6.0.data/purelib/holoscan/network_contexts/__init__.py +28 -0
  98. holoscan-2.6.0.data/purelib/holoscan/operators/__init__.py +97 -0
  99. holoscan-2.6.0.data/purelib/holoscan/operators/aja_source/__init__.py +22 -0
  100. holoscan-2.6.0.data/purelib/holoscan/operators/bayer_demosaic/__init__.py +24 -0
  101. holoscan-2.6.0.data/purelib/holoscan/operators/format_converter/__init__.py +23 -0
  102. holoscan-2.6.0.data/purelib/holoscan/operators/gxf_codelet/__init__.py +67 -0
  103. holoscan-2.6.0.data/purelib/holoscan/operators/holoviz/__init__.py +424 -0
  104. holoscan-2.6.0.data/purelib/holoscan/operators/inference/__init__.py +23 -0
  105. holoscan-2.6.0.data/purelib/holoscan/operators/inference_processor/__init__.py +23 -0
  106. holoscan-2.6.0.data/purelib/holoscan/operators/ping_rx/__init__.py +45 -0
  107. holoscan-2.6.0.data/purelib/holoscan/operators/ping_tensor_rx/__init__.py +22 -0
  108. holoscan-2.6.0.data/purelib/holoscan/operators/ping_tensor_tx/__init__.py +22 -0
  109. holoscan-2.6.0.data/purelib/holoscan/operators/ping_tx/__init__.py +46 -0
  110. holoscan-2.6.0.data/purelib/holoscan/operators/segmentation_postprocessor/__init__.py +23 -0
  111. holoscan-2.6.0.data/purelib/holoscan/operators/v4l2_video_capture/__init__.py +23 -0
  112. holoscan-2.6.0.data/purelib/holoscan/operators/video_stream_recorder/__init__.py +22 -0
  113. holoscan-2.6.0.data/purelib/holoscan/operators/video_stream_replayer/__init__.py +22 -0
  114. holoscan-2.6.0.data/purelib/holoscan/resources/__init__.py +147 -0
  115. holoscan-2.6.0.data/purelib/holoscan/schedulers/__init__.py +32 -0
  116. holoscan-2.6.0.data/purelib/holoscan-2.6.0.pth +1 -0
  117. holoscan-2.6.0.dist-info/LICENSE.txt +202 -0
  118. holoscan-2.6.0.dist-info/METADATA +125 -0
  119. holoscan-2.6.0.dist-info/NOTICE.txt +174 -0
  120. holoscan-2.6.0.dist-info/NVIDIA-AI-PRODUCT-EULA.txt +243 -0
  121. holoscan-2.6.0.dist-info/RECORD +126 -0
  122. holoscan-2.6.0.dist-info/WHEEL +5 -0
  123. holoscan-2.6.0.dist-info/axle.lck +0 -0
  124. holoscan-2.6.0.dist-info/entry_points.txt +3 -0
  125. holoscan-2.6.0.dist-info/symlinks.txt +82 -0
  126. holoscan-2.6.0.dist-info/top_level.txt +3 -0
@@ -0,0 +1,181 @@
1
+ """
2
+ SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3
+ SPDX-License-Identifier: Apache-2.0
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ """ # noqa: E501
17
+
18
+ import os
19
+ from pathlib import Path
20
+ from typing import Any
21
+
22
+ import yaml
23
+
24
+ from ..common.constants import DefaultValues, EnvironmentVariables
25
+ from ..common.exceptions import InvalidApplicationConfigurationError
26
+ from .manifest_files import ApplicationManifest, PackageManifest
27
+ from .parameters import PackageBuildParameters
28
+
29
+
30
+ class ApplicationConfiguration:
31
+ def __init__(self) -> None:
32
+ self._config = None
33
+
34
+ def read(self, path: Path):
35
+ """Reads application configuration file
36
+
37
+ Args:
38
+ path (Path): path to the app configuration file
39
+
40
+ Raises:
41
+ FileNotFoundError: when file does not exists or is not a file
42
+ InvalidApplicationConfigurationError: error reading file
43
+ """
44
+ if not path.exists() or not path.is_file():
45
+ raise FileNotFoundError(
46
+ f"Specified application configuration file cannot be found: {path}"
47
+ )
48
+
49
+ try:
50
+ with open(path) as app_manifest_file:
51
+ self._config = yaml.load(app_manifest_file, yaml.SafeLoader)
52
+ except Exception as ex:
53
+ raise InvalidApplicationConfigurationError(
54
+ f"Error reading application configuration file from '{path}'. Please check that "
55
+ "the file is accessible and is a valid YAML file.",
56
+ ex,
57
+ ) from ex
58
+
59
+ self._config_file_path = path
60
+ self._validate()
61
+
62
+ def _validate(self):
63
+ if self._config is None:
64
+ raise InvalidApplicationConfigurationError(
65
+ f"Error reading application configuration: {self._config_file_path}"
66
+ )
67
+
68
+ if "application" not in self._config:
69
+ raise InvalidApplicationConfigurationError(
70
+ "Application ('application') configuration cannot be found in "
71
+ f"{self._config_file_path}"
72
+ )
73
+ if "resources" not in self._config:
74
+ raise InvalidApplicationConfigurationError(
75
+ "Resources ('resources') configuration cannot be found in "
76
+ f"{self._config_file_path}"
77
+ )
78
+ if (
79
+ "title" not in self._config["application"]
80
+ or len(self._config["application"]["title"]) <= 0
81
+ ):
82
+ raise InvalidApplicationConfigurationError(
83
+ "Application configuration key/value ('application>title') "
84
+ f"cannot be found or is empty in {self._config_file_path}"
85
+ )
86
+ self._application_object = self._config["application"]
87
+ self._resource_object = self._config["resources"]
88
+
89
+ def title(self) -> str:
90
+ return self._application_object["title"]
91
+
92
+ def pip_packages(self) -> Any:
93
+ if "pip-packages" in self._application_object:
94
+ return self._application_object["pip-packages"]
95
+ return None
96
+
97
+ def populate_app_manifest(
98
+ self, build_parameters: PackageBuildParameters
99
+ ) -> ApplicationManifest:
100
+ application_manifest = ApplicationManifest()
101
+ application_manifest.api_version = DefaultValues.API_VERSION
102
+ application_manifest.command = build_parameters.command
103
+
104
+ application_manifest.environment = {}
105
+ application_manifest.environment[EnvironmentVariables.HOLOSCAN_APPLICATION] = str(
106
+ build_parameters.app_dir
107
+ )
108
+ application_manifest.environment[EnvironmentVariables.HOLOSCAN_INPUT_PATH] = str(
109
+ build_parameters.input_dir
110
+ )
111
+ application_manifest.environment[EnvironmentVariables.HOLOSCAN_OUTPUT_PATH] = str(
112
+ build_parameters.output_dir
113
+ )
114
+ application_manifest.environment[EnvironmentVariables.HOLOSCAN_WORKDIR] = str(
115
+ build_parameters.working_dir
116
+ )
117
+ application_manifest.environment[EnvironmentVariables.HOLOSCAN_MODEL_PATH] = str(
118
+ build_parameters.models_dir
119
+ )
120
+ application_manifest.environment[EnvironmentVariables.HOLOSCAN_CONFIG_PATH] = str(
121
+ build_parameters.config_file_path
122
+ )
123
+ application_manifest.environment[EnvironmentVariables.HOLOSCAN_APP_MANIFEST_PATH] = str(
124
+ build_parameters.app_manifest_path
125
+ )
126
+ application_manifest.environment[EnvironmentVariables.HOLOSCAN_PKG_MANIFEST_PATH] = str(
127
+ build_parameters.package_manifest_path
128
+ )
129
+ application_manifest.environment[EnvironmentVariables.HOLOSCAN_DOCS_PATH] = str(
130
+ build_parameters.docs_dir
131
+ )
132
+ application_manifest.environment[EnvironmentVariables.HOLOSCAN_LOGS_PATH] = str(
133
+ build_parameters.logs_dir
134
+ )
135
+
136
+ application_manifest.input = {
137
+ "path": build_parameters.input_dir,
138
+ "formats": self._application_object.get("input-formats", None),
139
+ }
140
+
141
+ application_manifest.output = {
142
+ "path": build_parameters.output_dir,
143
+ "formats": self._application_object.get("output-formats", None),
144
+ }
145
+
146
+ application_manifest.readiness = None
147
+ application_manifest.liveness = None
148
+ application_manifest.timeout = build_parameters.timeout
149
+ application_manifest.version = self._get_version(build_parameters)
150
+ application_manifest.working_directory = str(build_parameters.working_dir)
151
+
152
+ return application_manifest
153
+
154
+ def populate_package_manifest(
155
+ self, build_parameters: PackageBuildParameters
156
+ ) -> PackageManifest:
157
+ package_manifest = PackageManifest()
158
+ package_manifest.api_version = DefaultValues.API_VERSION
159
+ package_manifest.application_root = str(build_parameters.app_dir)
160
+ package_manifest.model_root = str(build_parameters.models_dir)
161
+
162
+ package_manifest.models = {}
163
+ if build_parameters.models is not None:
164
+ for model in build_parameters.models:
165
+ package_manifest.models[model] = os.path.join(package_manifest.model_root, model)
166
+ package_manifest.resources = self._resource_object
167
+ package_manifest.version = self._get_version(build_parameters)
168
+
169
+ return package_manifest
170
+
171
+ def _get_version(self, build_parameters: PackageBuildParameters) -> str:
172
+ if build_parameters.version is None:
173
+ if "version" not in self._application_object:
174
+ raise InvalidApplicationConfigurationError(
175
+ "Application configuration key/value ('application>version') "
176
+ f"cannot be found or is empty in {self._config_file_path}"
177
+ )
178
+
179
+ return self._application_object["version"]
180
+
181
+ return build_parameters.version
@@ -0,0 +1,368 @@
1
+ """
2
+ SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3
+ SPDX-License-Identifier: Apache-2.0
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ """ # noqa: E501
17
+
18
+ import logging
19
+ import os
20
+ import pprint
21
+ import shutil
22
+ from pathlib import Path
23
+ from typing import Optional
24
+
25
+ from jinja2 import Environment, FileSystemLoader, StrictUndefined
26
+
27
+ from ..common.constants import Constants, DefaultValues
28
+ from ..common.dockerutils import build_docker_image, create_and_get_builder, docker_export_tarball
29
+ from ..common.exceptions import WrongApplicationPathError
30
+ from .parameters import PackageBuildParameters, PlatformBuildResults, PlatformParameters
31
+
32
+
33
+ class BuilderBase:
34
+ """
35
+ Docker container image builder base class.
36
+ Prepares files for building the docker image and calls Docker API to build the container image.
37
+ """
38
+
39
+ def __init__(
40
+ self,
41
+ build_parameters: PackageBuildParameters,
42
+ temp_dir: str,
43
+ ) -> None:
44
+ """
45
+ Copy the application, model files, and user documentations here in __init__ since they
46
+ won't change when building different platforms.
47
+
48
+ Args:
49
+ build_parameters (PackageBuildParameters): general build parameters
50
+ temp_dir (str): temporary directory to store files required for build
51
+
52
+ """
53
+ self._logger = logging.getLogger("packager.builder")
54
+ self._build_parameters = build_parameters
55
+ self._temp_dir = temp_dir
56
+ self._copy_application()
57
+ self._copy_model_files()
58
+ self._copy_docs()
59
+ _ = self._write_dockerignore()
60
+ _ = self._copy_script()
61
+
62
+ def build(self, platform_parameters: PlatformParameters) -> PlatformBuildResults:
63
+ """Build a new container image for a specific platform.
64
+ Copy supporting files, such as redistributables and generate Dockerfile for the build.
65
+
66
+ Args:
67
+ platform_parameters (PlatformParameters): platform parameters
68
+
69
+ Returns:
70
+ PlatformBuildResults: build results
71
+ """
72
+ self._copy_supporting_files(platform_parameters)
73
+ docker_file_path = self._write_dockerfile(platform_parameters)
74
+
75
+ return self._build_internal(docker_file_path, platform_parameters)
76
+
77
+ def _build_internal(
78
+ self, dockerfile: str, platform_parameters: PlatformParameters
79
+ ) -> PlatformBuildResults:
80
+ """Prepare parameters for Docker buildx build
81
+
82
+ Args:
83
+ dockerfile (str): Path to Dockerfile to be built
84
+ platform_parameters (PlatformParameters): platform parameters
85
+
86
+ Returns:
87
+ PlatformBuildResults: build results
88
+ """
89
+ self.print_build_info(platform_parameters)
90
+ builder = create_and_get_builder(Constants.LOCAL_BUILDX_BUILDER_NAME)
91
+
92
+ build_result = PlatformBuildResults(platform_parameters)
93
+
94
+ cache_to = {"type": "local", "dest": self._build_parameters.build_cache}
95
+ cache_from = [{"type": "local", "src": self._build_parameters.build_cache}]
96
+ if platform_parameters.base_image is not None:
97
+ cache_from.append({"type": "registry", "ref": platform_parameters.base_image})
98
+ if platform_parameters.build_image is not None:
99
+ cache_from.append({"type": "registry", "ref": platform_parameters.build_image})
100
+
101
+ builds = {
102
+ "builder": builder,
103
+ "cache": not self._build_parameters.no_cache,
104
+ "cache_from": None if self._build_parameters.no_cache else cache_from,
105
+ "cache_to": None if self._build_parameters.no_cache else cache_to,
106
+ "context_path": self._temp_dir,
107
+ "file": dockerfile,
108
+ "platforms": [platform_parameters.docker_arch],
109
+ "progress": "plain" if self._logger.root.level == logging.DEBUG else "auto",
110
+ "pull": True,
111
+ "tags": [platform_parameters.tag],
112
+ }
113
+
114
+ export_to_tar_ball = False
115
+ if self._build_parameters.tarball_output is not None:
116
+ build_result.tarball_filenaem = str(
117
+ self._build_parameters.tarball_output
118
+ / f"{platform_parameters.tag}{Constants.TARBALL_FILE_EXTENSION}"
119
+ ).replace(":", "-")
120
+
121
+ # Make result image available on 'docker image' only if arch matches
122
+ if platform_parameters.same_arch_as_system:
123
+ builds["load"] = True
124
+ build_result.docker_tag = platform_parameters.tag
125
+ export_to_tar_ball = self._build_parameters.tarball_output is not None
126
+ else:
127
+ if self._build_parameters.tarball_output is not None:
128
+ builds["output"] = {
129
+ # type=oci cannot be loaded by docker: https://github.com/docker/buildx/issues/59
130
+ "type": "docker",
131
+ "dest": build_result.tarball_filenaem,
132
+ }
133
+ else:
134
+ build_result.succeeded = False
135
+ build_result.error = (
136
+ "Skipped due to incompatible system architecture. "
137
+ "Use '--output' to write image to disk."
138
+ )
139
+ return build_result
140
+
141
+ builds["build_args"] = {
142
+ "UID": self._build_parameters.uid,
143
+ "GID": self._build_parameters.gid,
144
+ "UNAME": self._build_parameters.username,
145
+ "GPU_TYPE": platform_parameters.platform_config.value,
146
+ }
147
+
148
+ self._logger.debug(f"Building Holoscan Application Package: tag={platform_parameters.tag}")
149
+
150
+ try:
151
+ build_docker_image(**builds)
152
+ build_result.succeeded = True
153
+ if export_to_tar_ball:
154
+ try:
155
+ self._logger.info(
156
+ f"Saving {platform_parameters.tag} to {build_result.tarball_filenaem}..."
157
+ )
158
+ docker_export_tarball(build_result.tarball_filenaem, platform_parameters.tag)
159
+ except Exception as ex:
160
+ build_result.error = f"Error saving tarball: {ex}"
161
+ build_result.succeeded = False
162
+ except Exception:
163
+ build_result.succeeded = False
164
+ build_result.error = "Error building image: see Docker output for additional details."
165
+
166
+ return build_result
167
+
168
+ def print_build_info(self, platform_parameters):
169
+ """Print build information for the platform."""
170
+ self._logger.info(
171
+ f"""
172
+ ===============================================================================
173
+ Building image for: {platform_parameters.platform.value}
174
+ Architecture: {platform_parameters.platform_arch.value}
175
+ Base Image: {platform_parameters.base_image}
176
+ Build Image: {platform_parameters.build_image if platform_parameters.build_image is not None else "N/A"}
177
+ Cache: {'Disabled' if self._build_parameters.no_cache else 'Enabled'}
178
+ Configuration: {platform_parameters.platform_config.value}
179
+ Holoscan SDK Package: {platform_parameters.holoscan_sdk_file if platform_parameters.holoscan_sdk_file is not None else "N/A"}
180
+ MONAI Deploy App SDK Package: {platform_parameters.monai_deploy_sdk_file if platform_parameters.monai_deploy_sdk_file is not None else "N/A"}
181
+ gRPC Health Probe: {platform_parameters.health_probe if platform_parameters.health_probe is not None else "N/A"}
182
+ SDK Version: {self._build_parameters.holoscan_sdk_version}
183
+ SDK: {self._build_parameters.sdk.value}
184
+ Tag: {platform_parameters.tag}
185
+ Included features/dependencies: {", ".join(self._build_parameters.includes) if self._build_parameters.includes else "N/A"}
186
+ """ # noqa: E501
187
+ )
188
+
189
+ def _write_dockerignore(self):
190
+ """Copy .dockerignore file to temporary location."""
191
+ # Write out .dockerignore file
192
+ dockerignore_source_file_path = Path(__file__).parent / "templates" / "dockerignore"
193
+ dockerignore_dest_file_path = os.path.join(self._temp_dir, ".dockerignore")
194
+ shutil.copyfile(dockerignore_source_file_path, dockerignore_dest_file_path)
195
+ return dockerignore_dest_file_path
196
+
197
+ def _copy_script(self):
198
+ """Copy HAP/MAP tools.sh script to temporary directory"""
199
+ # Copy the tools script
200
+ tools_script_file_path = Path(__file__).parent / "templates" / "tools.sh"
201
+ tools_script_dest_file_path = os.path.join(self._temp_dir, "tools")
202
+ shutil.copyfile(tools_script_file_path, tools_script_dest_file_path)
203
+ return tools_script_dest_file_path
204
+
205
+ def _write_dockerfile(self, platform_parameters: PlatformParameters):
206
+ """Write Dockerfile temporary location"""
207
+ docker_template_string = self._get_template(platform_parameters)
208
+ self._logger.debug(
209
+ f"""
210
+ ========== Begin Dockerfile ==========
211
+ {docker_template_string}
212
+ =========== End Dockerfile ===========
213
+ """
214
+ )
215
+
216
+ docker_file_path = os.path.join(self._temp_dir, DefaultValues.DOCKER_FILE_NAME)
217
+ with open(docker_file_path, "w") as docker_file:
218
+ docker_file.write(docker_template_string)
219
+
220
+ return os.path.abspath(docker_file_path)
221
+
222
+ def _copy_application(self):
223
+ """Copy application to temporary location"""
224
+ # Copy application files to temp directory (under 'app' folder)
225
+ target_application_path = Path(os.path.join(self._temp_dir, "app"))
226
+ if os.path.exists(target_application_path):
227
+ shutil.rmtree(target_application_path)
228
+
229
+ if not os.path.exists(self._build_parameters.application):
230
+ raise WrongApplicationPathError(
231
+ f'Directory "{self._build_parameters.application}" not found.'
232
+ )
233
+
234
+ if os.path.isfile(self._build_parameters.application):
235
+ shutil.copytree(self._build_parameters.application.parent, target_application_path)
236
+ else:
237
+ shutil.copytree(self._build_parameters.application, target_application_path)
238
+
239
+ target_config_file_path = Path(os.path.join(self._temp_dir, "app.config"))
240
+ shutil.copyfile(self._build_parameters.app_config_file_path, target_config_file_path)
241
+
242
+ def _copy_model_files(self):
243
+ """Copy models to temporary location"""
244
+ if self._build_parameters.models:
245
+ target_models_root_path = os.path.join(self._temp_dir, "models")
246
+ os.makedirs(target_models_root_path, exist_ok=True)
247
+
248
+ for model in self._build_parameters.models:
249
+ target_model_path = os.path.join(target_models_root_path, model)
250
+ if self._build_parameters.models[model].is_dir():
251
+ shutil.copytree(self._build_parameters.models[model], target_model_path)
252
+ elif self._build_parameters.models[model].is_file():
253
+ os.makedirs(target_model_path, exist_ok=True)
254
+ target_model_path = os.path.join(
255
+ target_model_path, self._build_parameters.models[model].name
256
+ )
257
+ shutil.copy(self._build_parameters.models[model], target_model_path)
258
+
259
+ def _copy_docs(self):
260
+ """Copy user documentations to temporary location"""
261
+ if self._build_parameters.docs is not None:
262
+ target_path = os.path.join(self._temp_dir, "docs")
263
+ shutil.copytree(self._build_parameters.docs, target_path)
264
+
265
+ def _get_template(self, platform_parameters: PlatformParameters):
266
+ """Generate Dockerfile using Jinja2 engine"""
267
+ jinja_env = Environment(
268
+ loader=FileSystemLoader(Path(__file__).parent / "templates"),
269
+ undefined=StrictUndefined,
270
+ trim_blocks=True,
271
+ lstrip_blocks=True,
272
+ )
273
+ self._logger.debug(
274
+ f"""
275
+ ========== Begin Build Parameters ==========
276
+ {pprint.pformat(self._build_parameters.to_jinja)}
277
+ =========== End Build Parameters ===========
278
+ """
279
+ )
280
+ self._logger.debug(
281
+ f"""
282
+ ========== Begin Platform Parameters ==========
283
+ {pprint.pformat(platform_parameters.to_jinja)}
284
+ =========== End Platform Parameters ===========
285
+ """
286
+ )
287
+
288
+ jinja_template = jinja_env.get_template("Dockerfile.jinja2")
289
+ return jinja_template.render(
290
+ {
291
+ **self._build_parameters.to_jinja,
292
+ **platform_parameters.to_jinja,
293
+ }
294
+ )
295
+
296
+ def _copy_supporting_files(self, platform_parameters: PlatformParameters):
297
+ """Abstract base function to copy supporting files"""
298
+ return NotImplemented
299
+
300
+ def __init_subclass__(cls):
301
+ if cls._copy_supporting_files is BuilderBase._copy_supporting_files:
302
+ raise NotImplementedError("{cls} has not overwritten method {_copy_supporting_files}!")
303
+
304
+
305
+ class PythonAppBuilder(BuilderBase):
306
+ """A subclass of BuilderBase for Python-based applications.
307
+ Copioes PyPI package and requirement.txt file
308
+ """
309
+
310
+ def __init__(
311
+ self,
312
+ build_parameters: PackageBuildParameters,
313
+ temp_dir: str,
314
+ ) -> None:
315
+ BuilderBase.__init__(self, build_parameters, temp_dir)
316
+
317
+ def _copy_supporting_files(self, platform_parameters: PlatformParameters):
318
+ self._copy_sdk_file(platform_parameters.holoscan_sdk_file)
319
+ self._copy_sdk_file(platform_parameters.monai_deploy_sdk_file)
320
+ self._copy_pip_requirements()
321
+
322
+ def _copy_pip_requirements(self):
323
+ pip_folder = os.path.join(self._temp_dir, "pip")
324
+ os.makedirs(pip_folder, exist_ok=True)
325
+ pip_requirements_path = os.path.join(pip_folder, "requirements.txt")
326
+ with open(pip_requirements_path, "w") as requirements_file:
327
+ # Use local requirements.txt packages if provided, otherwise use sdk provided packages
328
+ if self._build_parameters.requirements_file_path is not None:
329
+ with open(self._build_parameters.requirements_file_path) as lr:
330
+ for line in lr:
331
+ requirements_file.write(line)
332
+ requirements_file.writelines("\n")
333
+
334
+ if self._build_parameters.pip_packages:
335
+ requirements_file.writelines("\n".join(self._build_parameters.pip_packages))
336
+
337
+ def _copy_sdk_file(self, sdk_file: Optional[Path]):
338
+ if sdk_file is not None and os.path.isfile(sdk_file):
339
+ dest = os.path.join(self._temp_dir, sdk_file.name)
340
+ if os.path.exists(dest):
341
+ os.remove(dest)
342
+ shutil.copyfile(sdk_file, dest)
343
+
344
+
345
+ class CppAppBuilder(BuilderBase):
346
+ """A subclass of BuilderBase for C++ applications.
347
+ Copies Debian.
348
+ """
349
+
350
+ def __init__(
351
+ self,
352
+ build_parameters: PackageBuildParameters,
353
+ temp_dir: str,
354
+ ) -> None:
355
+ BuilderBase.__init__(self, build_parameters, temp_dir)
356
+
357
+ def _copy_supporting_files(self, platform_parameters: PlatformParameters):
358
+ """Copies the SDK file to the temporary directory"""
359
+ if platform_parameters.holoscan_sdk_file is not None and os.path.isfile(
360
+ platform_parameters.holoscan_sdk_file
361
+ ):
362
+ dest = os.path.join(self._temp_dir, platform_parameters.holoscan_sdk_file.name)
363
+ if os.path.exists(dest):
364
+ os.remove(dest)
365
+ shutil.copyfile(
366
+ platform_parameters.holoscan_sdk_file,
367
+ dest,
368
+ )