Skip to content

Commit 19a457b

Browse files
authored
Enhance Holohub CLI Environment Handling (#1256)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Unified environment and path-mapping across build, run, and install flows; consolidated workdir resolution and local vs container branching. * **New Features** * Verbose path-mapping output and two-stage placeholder resolution for paths and env vars. * New env-update behavior supporting prepend/append semantics and templated replacements. * Exposed configurable CLI prefix for path resolution. * **Bug Fixes** * Improved env precedence, language-aware defaults, and clearer build/run/install messaging. * **Tests** * Expanded tests for placeholder replacement, mode env precedence, and isolated environment handling. * **Documentation** * Expanded CLI docs with modes, examples, env precedence, and migration guidance. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: B Hashemian <[email protected]>
1 parent a59bd3f commit 19a457b

File tree

4 files changed

+688
-185
lines changed

4 files changed

+688
-185
lines changed

utilities/cli/README.md

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ As of June 2025, HoloHub has been refactored from bash-based CLI scripts (`./run
77
## Key Benefits of the Refactoring
88

99
### **Simplified Workflows**
10+
1011
Transform complex multi-command workflows into single, intuitive commands:
1112

1213
```bash
@@ -27,12 +28,14 @@ Transform complex multi-command workflows into single, intuitive commands:
2728
```
2829

2930
### **Enhanced Developer Experience**
31+
3032
- **Unified Interface**: One tool for both local and containerized development instead of juggling `./run` and `./dev_container`
3133
- **Intelligent Defaults**: Container-first development for consistency and reproducibility
3234
- **Better Error Messages**: Helpful suggestions when commands or project names don't match
3335
- **Modern Python Implementation**: More reliable, maintainable, and extensible
3436

3537
### **Quick Command Reference**
38+
3639
| Workflow | Old Commands | New Command |
3740
|----------|-------------|-------------|
3841
| **Container Build & Run** | `./dev_container build_and_run` | `./holohub run` |
@@ -45,6 +48,7 @@ Transform complex multi-command workflows into single, intuitive commands:
4548
## Migration Examples
4649

4750
### **Build & Run**
51+
4852
```bash
4953
# Build locally with optional operators and build type
5054
# previous ./run build myapp --type debug --with "op1;op2"
@@ -72,6 +76,7 @@ Transform complex multi-command workflows into single, intuitive commands:
7276
```
7377

7478
### **Container Operations**
79+
7580
```bash
7681
# Container build
7782
# previous ./dev_container build --docker_file <path/to/myapp/Dockerfile> --img holohub:myapp
@@ -102,7 +107,7 @@ Use `-h` or `--help` to view a complete list of commands or subcommand options.
102107
./holohub build myapp --benchmark
103108
```
104109

105-
### **Development Environment**
110+
### **Development Environment**
106111

107112
Development commands remain familiar:
108113

@@ -122,6 +127,7 @@ Development commands remain familiar:
122127
## New Capabilities & Enhancements
123128

124129
### **Project Creation and Testing**
130+
125131
The new CLI introduces development lifecycle features:
126132

127133
```bash
@@ -142,10 +148,13 @@ The new CLI introduces development lifecycle features:
142148
```
143149

144150
### Application Modes
151+
145152
HoloHub applications with a 'modes' field in their `metadata.json` now support multiple **modes** - pre-configured setups for different use cases, hardware configurations, or deployment scenarios. This eliminates the need to remember complex command-line arguments for different use cases.
146153

147154
#### **Understanding Modes**
155+
148156
Modes potentially provide typical configurations for:
157+
149158
- **Different hardware**
150159
- **Deployment scenarios** (e.g. development vs. production vs. cloud inference)
151160
- **Data sources** (e.g. live video vs. recorded files vs. distributed streaming)
@@ -181,6 +190,7 @@ CLI parameters can be used in addition to modes. When provided, CLI parameters w
181190

182191
**Mode Priority Rules:**
183192
When CLI parameters are **not** provided, mode settings are used:
193+
184194
- If mode defines `run.docker_run_args` and no `--docker-opts` → Mode's docker options are used
185195
- If mode defines `build.depends` and no `--build-with` → Mode's dependencies are used
186196
- If mode defines `build.docker_build_args` and no `--build-args` → Mode's build args are used
@@ -189,9 +199,11 @@ When CLI parameters are **not** provided, mode settings are used:
189199
When CLI parameters **are** provided, they always override mode settings.
190200

191201
#### **For Application Developers**
202+
192203
Applications can define modes in their `metadata.json`. Here's the complete field reference:
193204

194205
##### **Mode Structure**
206+
195207
Each mode is defined as a named object under the `modes` key:
196208

197209
```json
@@ -208,16 +220,20 @@ Each mode is defined as a named object under the `modes` key:
208220
```
209221

210222
##### **Application-Level Fields**
223+
211224
**Optional Fields:**
225+
212226
- **`default_mode`** *(string)*: Specifies which mode to use when no mode is explicitly provided. Only needed when there are multiple modes (2 or more).
213227

214228
##### **Supported Fields for Each Mode**
215229

216230
**Required Fields:**
231+
217232
- **`description`** *(string)*: Human-readable description of what this mode does
218233
- **`run`** *(object)*: Run configuration (see run command fields below)
219234

220235
**Optional Fields:**
236+
221237
- **`requirements`** *(array of strings)*: List of dependency IDs required for this mode
222238
- **`build`** *(object)*: Build configuration (see build configuration fields below)
223239
- **`env`** *(object)*: Environment variables to set for both build and run operations
@@ -226,6 +242,7 @@ Each mode is defined as a named object under the `modes` key:
226242
- Example: `{"CUDA_VISIBLE_DEVICES": "0", "BUILD_ENV": "production"}`
227243

228244
##### **Build Configuration Fields (`build` object):**
245+
229246
- **`depends`** *(array of strings)*: List of operators/dependencies to build with this mode
230247
- **`docker_build_args`** *(string or array)*: Docker **build** arguments (equivalent to CLI `--build-args`)
231248
- Can be a single string: `"--build-arg CUSTOM=value"`
@@ -237,6 +254,7 @@ Each mode is defined as a named object under the `modes` key:
237254
- **Note**: For environment variables needed during both build and run, use the top-level `env` field instead
238255

239256
##### **Run Command Fields (`run` object):**
257+
240258
- **`command`** *(string)*: Complete command to execute including all arguments
241259
- **`workdir`** *(string)*: Working directory for command execution
242260
- **`docker_run_args`** *(string or array)*: Docker **run** arguments used for both build and application containers (equivalent to CLI `--docker-opts`)
@@ -344,6 +362,7 @@ For cases where build and run containers need different Docker configurations, y
344362
```
345363

346364
**Usage:**
365+
347366
```bash
348367
# Phase 1: Build with network access
349368
./holohub build myapp production_build
@@ -355,13 +374,33 @@ For cases where build and run containers need different Docker configurations, y
355374
Both modes automatically share the same Docker image name (`holohub:myapp`), so the run mode can use the image built by the build mode.
356375

357376
##### **Key Points for Mode Development**
377+
358378
- **`default_mode`** is required only if your project defines two or more modes; with a single mode, it is selected automatically. The default mode is used when no mode is explicitly specified on the command line.
359379
- **Mode names** must match pattern `^[a-zA-Z_][a-zA-Z0-9_]*$` (alphanumeric + underscore, can't start with number)
360380
- **Environment variables** can be specified at two levels:
361-
- Top-level `env`: Environment variables for **both build and run** operations
362-
- Can affect CLI behavior (e.g., `HOLOHUB_BUILD_LOCAL` to force local builds)
363-
- `run.env`: Environment variables **only for runtime** (local runs only)
364-
- When both are specified, they are merged with `run.env` taking precedence
381+
- Top-level `env`: Environment variables for **both build and run**
382+
- `mode_name.build.env`: Set environment variables **only for build and install**
383+
- `mode_name.run.env`: Set environment variables **only for run**
384+
- They can affect CLI behavior (e.g., `HOLOHUB_BUILD_LOCAL` to force local builds)
385+
- You can append to the existing environment variables by using `:`, like
386+
387+
```json
388+
"modes": {
389+
"mode_name": {
390+
"run": {
391+
"env": {
392+
"PATH": "<PATH>:<holohub_app_bin>/bin" # append to the updated PATH by mode_name.env
393+
"CMAKE_BUILD_TYPE": "Release" # override the existing CMAKE_BUILD_TYPE
394+
}
395+
},
396+
"env": {
397+
"PATH": "<holohub_bin>/bin:<PATH>" # prepend to the existing PATH in the environment
398+
}
399+
}
400+
}
401+
```
402+
403+
- The inner `env` object takes the precedence over the top-level `env` object, and the top-level `env` object takes precedence over the CLI environment variables.
365404
- **Docker arguments** can be specified in two places for different purposes:
366405
- `build.docker_build_args`: Docker **build** arguments for container image building (equivalent to CLI `--build-args`)
367406
- `run.docker_run_args`: Docker **run** arguments for both build and application containers (equivalent to CLI `--docker-opts`)
@@ -375,19 +414,21 @@ Both modes automatically share the same Docker image name (`holohub:myapp`), so
375414
- **Requirements** reference dependency IDs defined elsewhere in the metadata
376415
- **Modes provide complete control** over both build and runtime behavior for different deployment scenarios
377416

378-
379417
### **Granular Build Control**
418+
380419
The new architecture provides precise control over your development workflow.
381420

382421
**Default Behavior:**
383422
By default, `./holohub run` operates in a 'containerized mode', which means it will:
423+
384424
1. Build the container image (unless skipped, e.g. using `--no-docker-build`)
385425
2. Build the application inside the container
386426
3. Run the application inside the container
387427

388428
This container-first approach ensures consistency and reproducibility across different development environments.
389429

390430
**Command-line Options:**
431+
391432
- **`--local`**: Explicit local development mode
392433
- **`--no-local-build`**: Skip application rebuild for faster iteration
393434
- **`--no-docker-build`**: Use existing container images
@@ -398,11 +439,13 @@ This container-first approach ensures consistency and reproducibility across dif
398439
The CLI supports the following environment variables for customization:
399440

400441
**Build and Execution Control:**
442+
401443
- **`HOLOHUB_BUILD_LOCAL`**: Forces local mode (equivalent to `--local`), skips the container build steps and runs on the host directly.
402444
- **`HOLOHUB_ALWAYS_BUILD`**: Set to `false` to skip builds with `--no-local-build` and `--no-docker-build`.
403445
- **`HOLOHUB_ENABLE_SCCACHE`**: Defaults to `false`. Set to `true` to enable rapids-sccache for the build. You can configure sccache with `SCCACHE_*` environment variables per the [sccache documentation](https://github.com/rapidsai/sccache/tree/rapids/docs).
404446

405447
**Paths and Directories:**
448+
406449
- **`HOLOHUB_ROOT`**: HoloHub repository root directory, used to resolve relative paths for components, build artifacts, data, and other resources.
407450
- **`HOLOHUB_BUILD_PARENT_DIR`**: Root directory for all builds (default: `<HOLOHUB_ROOT>/build`).
408451
- **`HOLOHUB_DATA_DIR`**: Root data (such as models, datasets downloading during component building) directory (default: `<HOLOHUB_ROOT>/data`).
@@ -412,6 +455,7 @@ The CLI supports the following environment variables for customization:
412455
- **`HOLOSCAN_SDK_ROOT`**: Path to local Holoscan SDK root directory (source or build tree), used for mounting local Holoscan SDK development trees into containers.
413456

414457
**Container Configuration:**
458+
415459
- **`HOLOHUB_REPO_PREFIX`**: Repository prefix for naming defaults (default: `holohub`). Used as the default value for container-related variables below.
416460
- **`HOLOHUB_CONTAINER_PREFIX`**: Docker container name prefix (default: `HOLOHUB_REPO_PREFIX`).
417461
- **`HOLOHUB_WORKSPACE_NAME`**: Workspace directory name in container (default: `HOLOHUB_REPO_PREFIX`). The `<HOLOHUB_ROOT>` directory is mounted in the container as `/workspace/<HOLOHUB_WORKSPACE_NAME>`.
@@ -421,6 +465,7 @@ The CLI supports the following environment variables for customization:
421465
**Docker Images:**
422466

423467
By default, the Dockerfile used to build a container image for your project is chosen in that order:
468+
424469
1. Specified in your project's `metadata.json` file.
425470
2. `<app_source>/Dockerfile`
426471
3. `<app_source>/<language>/Dockerfile`
@@ -430,6 +475,7 @@ By default, the Dockerfile used to build a container image for your project is c
430475
This can be overridden by the `--docker-file` option.
431476

432477
If the selected Dockerfile has `ARG BASE_IMAGE`, the value of `BASE_IMAGE` will be automatically populated by the `./holohub build-container`, defaulting to `{base_image}:v{sdk_version}-{cuda_tag}` where:
478+
433479
- `{base_image}` defaults to `nvcr.io/nvidia/clara-holoscan/holoscan` and can be overridden by the **`HOLOHUB_BASE_IMAGE`** env variable.
434480
- `{sdk_version}` defaults to the latest available Holoscan SDK version (e.g. `3.8.0`) and can be overridden by the **`HOLOHUB_BASE_SDK_VERSION`** env variable.
435481
- `{cuda_tag}` is the Holoscan SDK container cuda tag. For Holoscan 3.7+, the default cuda major version is based on your host driver version, and can be overridden with the `--cuda <major_version>` option.
@@ -438,6 +484,7 @@ If the selected Dockerfile has `ARG BASE_IMAGE`, the value of `BASE_IMAGE` will
438484
The whole base image (`<repo:tag>`) can be overridden by the `--base-img` option.
439485

440486
The name of the output image generated by `./holohub build-container [project]` varies based on the following factors:
487+
441488
- Legacy tags:
442489
- If the project is using the default Dockerfile, the name will default to `{container_prefix}:ngc-v{sdk_version}-{cuda_tag}` where:
443490
- `{container_prefix}` defaults to **`HOLOHUB_REPO_PREFIX`** and can be overridden by the **`HOLOHUB_CONTAINER_PREFIX`** env variable.
@@ -456,20 +503,22 @@ The name of the output image generated by `./holohub build-container [project]`
456503
These output tags can be overridden by the `--img` option.
457504

458505
**Docker Runtime:**
506+
459507
- **`HOLOHUB_DEFAULT_DOCKER_BUILD_ARGS`**: Additional default arguments passed to `docker build` commands. Typically used to set global build arguments for all applications in the codebase, applications and commands can override these arguments.
460508
- **`HOLOHUB_DEFAULT_DOCKER_RUN_ARGS`**: Additional default arguments passed to `docker run` commands. Typically used to set global runtime arguments for all applications in the codebase, applications and commands can override these arguments.
461509
- **`HOLOHUB_BENCHMARKING_SUBDIR`**: Benchmarking subdirectory (default: `benchmarks/holoscan_flow_benchmarking`).
462510

463511
**Testing:**
512+
464513
- **`HOLOHUB_CTEST_SCRIPT`**: CTest script path used by `./holohub test` command (default: `<HOLOHUB_ROOT>/utilities/testing/holohub.container.ctest`).
465514

466515
**Other:**
516+
467517
- **`HOLOHUB_CMD_NAME`**: Command name displayed in help messages (default: `./holohub`). Allows customizing the command name for external codebases.
468518
- **`HOLOHUB_CLI_DOCS_URL`**: CLI documentation URL. Allows customizing the documentation URL for external codebases.
469519
- **`CMAKE_BUILD_TYPE`**: Default CMake build type (`debug`, `release`, or `relwithdebinfo`) when not specified in build commands.
470520
- **`CMAKE_BUILD_PARALLEL_LEVEL`**: Number of parallel CMake build jobs.
471521

472-
473522
## Getting Help
474523

475524
```bash
@@ -479,7 +528,6 @@ These output tags can be overridden by the `--img` option.
479528
./holohub list # Check available projects
480529
```
481530

482-
483531
## Bash Autocompletion
484532

485533
The autocompletion is automatically installed during setup and provides:
@@ -489,14 +537,17 @@ The autocompletion is automatically installed during setup and provides:
489537
- **Dynamic discovery**: Automatically finds new projects without manual configuration
490538

491539
### **Usage**
540+
492541
```bash
493542
./holohub <TAB><TAB> # Show all available options
494543
./holohub run ultra<TAB> # Complete to "ultrasound_segmentation"
495544
./holohub build vid<TAB> # Complete to "video_deidentification"
496545
```
497546

498547
### **Manual Installation**
548+
499549
If autocompletion isn't working, you can manually enable it:
550+
500551
```bash
501552
# Copy the autocomplete script
502553
sudo cp utilities/holohub_autocomplete /etc/bash_completion.d/
@@ -511,6 +562,7 @@ The autocompletion uses `./holohub autocompletion_list` command internally.
511562
## Useful Commands
512563

513564
- When adding option that looks like an argument, use `=` instead of whitespace ` ` (because of [Python argparse design choice](https://github.com/python/cpython/issues/53580)):
565+
514566
```bash
515567
--run-args="--verbose" # instead of --run-args "--verbose"
516568
```

0 commit comments

Comments
 (0)