pow-cli 0.1.1__tar.gz → 0.2.0rc2__tar.gz
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.
- pow_cli-0.2.0rc2/CHANGELOG.md +170 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/PKG-INFO +1 -1
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/cli/asset.py +0 -1
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/cli/init.py +44 -28
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/cli/lint.py +0 -2
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/cli/main.py +14 -3
- pow_cli-0.2.0rc2/pow_cli/cli/ros.py +155 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/cli/run.py +0 -2
- pow_cli-0.2.0rc2/pow_cli/cli/sim.py +67 -0
- pow_cli-0.2.0rc2/pow_cli/common/prompt.py +136 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/core/models/pow_config.py +104 -4
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/core/ros_manager.py +142 -128
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/core/runner.py +113 -13
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/data/pow.template.toml +3 -6
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/docker/Dockerfile.simros_jazzy +99 -13
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pyproject.toml +6 -1
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/tests/test_config.py +108 -5
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/tests/test_init_cmd.py +30 -7
- pow_cli-0.2.0rc2/tests/test_prompt.py +198 -0
- pow_cli-0.2.0rc2/tests/test_ros_cmd.py +154 -0
- pow_cli-0.2.0rc2/tests/test_ros_manager.py +268 -0
- pow_cli-0.2.0rc2/tests/test_runner.py +299 -0
- pow_cli-0.2.0rc2/tests/test_sim_cmd.py +71 -0
- pow_cli-0.2.0rc2/tests/test_version.py +11 -0
- pow_cli-0.1.1/CHANGELOG.md +0 -126
- pow_cli-0.1.1/pow_cli/cli/ros.py +0 -42
- pow_cli-0.1.1/pow_cli/docker/Dockerfile.simros_humble +0 -200
- pow_cli-0.1.1/tests/test_runner.py +0 -88
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/.gitignore +0 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/LICENSE +0 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/NOTICE +0 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/README.md +0 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/__init__.py +0 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/cli/__init__.py +0 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/cli/check.py +0 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/cli/python.py +0 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/common/__init__.py +0 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/common/utils.py +0 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/core/__init__.py +0 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/core/asset_manager.py +0 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/core/initializer.py +0 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/core/linter.py +0 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/core/models/asset_profile.py +0 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/core/models/system_config.py +0 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/data/asset-registry/isaacsim_assets_5_1_0.toml +0 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/data/asset-registry/omniverse_assets.toml +0 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/data/example/asset-profile.example.toml +0 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/data/gitignore.template +0 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/data/system.template.toml +0 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/pow_cli/main.py +0 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/scripts/check_assets_urls.py +0 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/tests/test_check_cmd.py +0 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/tests/test_initializer.py +0 -0
- {pow_cli-0.1.1 → pow_cli-0.2.0rc2}/tests/test_verify_isaacsim.py +0 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the `pow-cli` package will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [0.2.0-rc.2] - 2026-07-28
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **`pow sim`** — run Isaac Sim from any directory, with no project required: no `pyproject.toml` check and `pow.toml` is never read. Launches the default version (`5.1.0`, override with `-v/--version`) and forwards raw arguments straight to `isaac-sim.sh` (`pow sim -- --no-window`). The ROS 2 bridge environment is loaded by default (`--ros jazzy`); pass `--no-ros` to launch with the inherited environment instead
|
|
10
|
+
- **`pow ros build`** — build the custom image from `ros_dockerfile` without re-running `pow init`; builds the `pow_simros_jazzy` base image first if it is missing, and supports `--no-cache`. `pow ros` is now a command group (bare `pow ros [args...]` usage is unchanged; `pow ros launch` is the explicit form)
|
|
11
|
+
- **`ros_bridge` config in `pow.toml`** — choose which Isaac Sim internal ROS 2 bridge libs to load (`jazzy` or `humble`, default `jazzy`), i.e. which `exts/isaacsim.ros2.bridge/<distro>/lib` is added to `LD_LIBRARY_PATH` when `enable_ros = true`. Overridable per profile. Previously the bridge was inferred from the host Ubuntu version with no way to override it; an unsupported value is now rejected with a clear error
|
|
12
|
+
- **Tab completion for the `pow init` ROS workspace path** — step 6's "Path to clone IsaacSim-ros_workspaces" prompt now completes filesystem paths on <kbd>Tab</kbd> like a shell: unique directories complete inline (no stray trailing space, so the next segment can be typed straight away), ambiguous prefixes list candidates, and `~` is kept in the stored path. Trailing separators and whitespace are trimmed before the value is written to `pow.toml`
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- **Breaking (vs 0.2.0-rc.1):** the `ros_container_name` config key was renamed to `ros_docker_image`. The container name is no longer configured directly — it is derived from the image name (`/` and `:` replaced with `_`), so default setups now get a container named `pow_simros_jazzy` instead of `pow_simros`
|
|
17
|
+
- **Breaking (vs 0.2.0-rc.1):** ROS 2 Humble support was removed — the ROS workspace and docker integration now support Jazzy only (`Dockerfile.simros_humble` deleted). Isaac Sim itself still runs on Ubuntu 22.04 and 24.04; Jazzy workspaces build on both
|
|
18
|
+
- **`pow init` no longer builds the Isaac Sim ROS workspace.** Step 6 only clones `IsaacSim-ros_workspaces`; the ROS 2 bridge comes from Isaac Sim's own prebuilt libs (selected by `ros_bridge`), so init is much faster and no longer runs a Docker build for the workspace. It reports the bridge distro in use instead of a build result
|
|
19
|
+
- `pow init` no longer creates the `scripts/`, `.assets/`, and `standalone/` project folders (only `exts/`, `.modules/`, `usda/`). A manually created `scripts/` folder is still mounted into the ROS container when present
|
|
20
|
+
- The `pow_simros_jazzy` image now resolves workspace dependencies with `rosdep install` at build time instead of building the workspace, and source-only packages (`topic_based_ros2_control`) are staged in `/opt/pow/extra_src` and copied into `/jazzy_ws/src` at container start, so the runtime volume mount no longer shadows them
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- **`rosdep install` failed inside the Jazzy container** — three causes, all fixed (requires rebuilding the image): the Ubuntu 24.04 base image's stock `ubuntu` user took UID 1000 and collided with the mapped host user, so `HOME` pointed at `/home/ubuntu` while the host `~/.ros` was mounted at `/home/hostuser/.ros`; the per-user rosdep cache was empty because `rosdep update` had run as root at build time, giving "your rosdep installation has not been initialized"; and `ros-jazzy-ros-testing` was missing from the image
|
|
25
|
+
- **`cpu_performance_mode` asked for the sudo password on every launch** — `pow run` / `pow python` now read the current CPU governor from `/sys/devices/system/cpu/cpu*/cpufreq/scaling_governor` first and run no `sudo` at all when it is already `performance`, so the password is normally needed once instead of every launch. When sudo credentials are still cached the governor is set without the "requires sudo" notice, and hosts without `cpupower` or without cpufreq support now report and skip rather than prompting for a password to no purpose. The interactive prompt itself is unchanged when the governor really has to be switched
|
|
26
|
+
- **`ros2` tab completion inside the `pow_simros` container** — the entrypoint sourced ROS before exec'ing bash, which carried environment variables but not bash completion functions. Interactive shells now re-source `/opt/ros/jazzy/setup.bash` and the workspace overlay via `/etc/bash.bashrc`, so `ros2` / `colcon` autocomplete works without manually sourcing `setup.bash` (requires rebuilding the image)
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## [0.2.0-rc.1] - 2026-06-14
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- **Custom ROS Dockerfile (`pow init`)**
|
|
35
|
+
- New `ros_dockerfile` config in `pow.toml` — point to a project-local Dockerfile that layers on top of the bundled `pow_simros_<distro>` base image
|
|
36
|
+
- New `ros_container_name` config in `pow.toml` — set a custom container/image name (defaults to `pow_simros`)
|
|
37
|
+
- `pow init` now builds the custom image automatically after the base image when `ros_dockerfile` is set
|
|
38
|
+
- `pow ros` launches the custom image when configured, otherwise falls back to the base image
|
|
39
|
+
- **Version flag (`pow --version` / `pow -v`)** — quickly check the installed `pow-cli` version from the command line
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
|
|
43
|
+
- Updated CLI description to *"Manage Isaac Sim projects and simplify the development workflow"*
|
|
44
|
+
- Renamed status messages from *"Isaac ROS workspace"* to *"Isaac Sim ROS workspace"* for clarity
|
|
45
|
+
- Container name is now read from `ros_container_name` config instead of being hard-coded
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## [0.1.1] - 2026-06-14
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
|
|
53
|
+
- **ROS Docker container: `colcon build` fails for new packages** — The container
|
|
54
|
+
entrypoint now detects stale build artifacts (left from a host-path build) and
|
|
55
|
+
cleans `build/`, `install/`, and `log/` automatically before rebuilding.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## [0.1.0] - 2026-06-05
|
|
60
|
+
|
|
61
|
+
First stable release of `pow-cli`, promoted from `0.1.0-rc.1` with documentation improvements.
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
### Fixed
|
|
65
|
+
|
|
66
|
+
- Installation guide referenced incorrect `pow-cli` version
|
|
67
|
+
|
|
68
|
+
### Changed
|
|
69
|
+
|
|
70
|
+
- Improved README wording, tagline, and Profiles section
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## [0.1.0-rc.1] - 2026-05-11
|
|
75
|
+
|
|
76
|
+
### Added
|
|
77
|
+
|
|
78
|
+
- **Asset Management (`pow asset`)**
|
|
79
|
+
- `pow asset list` — list available Isaac Sim & Omniverse assets
|
|
80
|
+
- `pow asset add` — download and register assets into the local asset folder (only support `isaacsim_5_1_0` for now)
|
|
81
|
+
- `pow asset set / unset` — set/unset target local asset folder
|
|
82
|
+
- `pow asset info` — display current local asset folder information
|
|
83
|
+
- **Linter (`pow lint`)**
|
|
84
|
+
- New `pow lint` and `pow lint --fix` commands for `.usda` files
|
|
85
|
+
- Detects absolute/relative local asset paths and rewrites them with correct aliases or asset urls (`user-home`, `pow-assets`)
|
|
86
|
+
- Rule for validating `simros_ws` relative paths
|
|
87
|
+
- **ROS Integration (`pow ros`)**
|
|
88
|
+
- `pow ros` command to build, launch, and attach to ROS 2 Docker containers
|
|
89
|
+
- Verbose mode (`--verbose`) for runtime diagnostics
|
|
90
|
+
- Separate Dockerfiles for ROS Humble and Jazzy distributions
|
|
91
|
+
- Project `scripts/` directory mounted into the container
|
|
92
|
+
- PyTorch with CUDA support available inside the container
|
|
93
|
+
- `isaacsim_ros_ws` working directory configurable in `pow.toml`
|
|
94
|
+
- **Runner Improvements**
|
|
95
|
+
- (experimental) `pow run --open <file>` option to open a USD stage on launch
|
|
96
|
+
- Non-existent `ext_folders` entries are now silently skipped instead of auto-created
|
|
97
|
+
- **Other**
|
|
98
|
+
- `pow python` command with `--profile` flag for running standalone app under specified version of Isaac Sim's Python
|
|
99
|
+
- `user-home` aliases automatically configured during `pow init`
|
|
100
|
+
- `usda/` folder added to default project structure
|
|
101
|
+
- `extends` support in `pow.toml` for profile-based configuration
|
|
102
|
+
|
|
103
|
+
### Fixed
|
|
104
|
+
|
|
105
|
+
- ROS Jazzy container build failure on Ubuntu 24.04
|
|
106
|
+
- CUDA version pinned to 12.1 for deterministic ROS builds
|
|
107
|
+
- `.ros` / `.ros2` mount and permission issues in the SimROS container
|
|
108
|
+
- SimROS entrypoint no longer warns when host-user directory already exists
|
|
109
|
+
- `pow run` no longer calls `open_stage` when no path is provided
|
|
110
|
+
- `pow asset unset` no longer accidentally removes `user-home` alias
|
|
111
|
+
- Duplicate and deprecated keys in generated `.vscode/settings.json`
|
|
112
|
+
- `pow init` now respects existing `isaacsim_ros_ws` value in existing `pow.toml`
|
|
113
|
+
- `pow ros` correctly attaches to an already-running container
|
|
114
|
+
|
|
115
|
+
### Changed
|
|
116
|
+
|
|
117
|
+
- Rewrite and refactor all core functionality of pow-cli
|
|
118
|
+
- Move commands under group `pow sim` to root `pow` command instead
|
|
119
|
+
- Remove pow-foxglove from repository
|
|
120
|
+
- ROS-related logic extracted into dedicated `ros_manager.py` module
|
|
121
|
+
- CLI and core layers refactored for clearer separation of concerns
|
|
122
|
+
|
|
123
|
+
## [0.1.0a3] - 2026-01-27
|
|
124
|
+
|
|
125
|
+
### Fixed
|
|
126
|
+
|
|
127
|
+
- Fixed incorrect Ubuntu base Docker image version in `pow sim init` ROS workspace setup. Now correctly uses Ubuntu 22.04 for ROS Humble and Ubuntu 24.04 for ROS Jazzy (previously hardcoded to 22.04 for both).
|
|
128
|
+
|
|
129
|
+
## [0.1.0a2] - 2025-12-25
|
|
130
|
+
|
|
131
|
+
### Fixed
|
|
132
|
+
|
|
133
|
+
- `pow sim init` now allows overwriting existing VS Code settings to resolve Pylance `reportMissingImports` errors for Isaac Sim packages.
|
|
134
|
+
- Fixed an issue where the `ros_enable` flag did not correctly disable ROS workspace sourcing when set to `false` in an existing `pow.toml`.
|
|
135
|
+
|
|
136
|
+
## [0.1.0a1] - 2025-12-23
|
|
137
|
+
|
|
138
|
+
### Added
|
|
139
|
+
|
|
140
|
+
- Initial alpha release of Isaac Powerpack CLI (`pow`)
|
|
141
|
+
- **Core CLI Structure**
|
|
142
|
+
- Main entry point with Click-based command group architecture
|
|
143
|
+
- Hierarchical command organization under `pow sim` namespace
|
|
144
|
+
|
|
145
|
+
- **Simulation Commands (`pow sim`)**
|
|
146
|
+
- `pow sim run` - Run Isaac Sim applications with automatic environment setup
|
|
147
|
+
- Auto-discovery of project root via `pow.toml` configuration
|
|
148
|
+
- ROS 2 workspace sourcing support
|
|
149
|
+
- Isaac Sim setup file sourcing
|
|
150
|
+
- Configurable app path and extension loading
|
|
151
|
+
- `pow sim init` - Initialize Isaac Sim development environment
|
|
152
|
+
- VS Code settings generation for Isaac Sim development
|
|
153
|
+
- Asset browser cache fix utility
|
|
154
|
+
- Project configuration scaffolding
|
|
155
|
+
- `pow sim check` - Run Isaac Sim compatibility checker
|
|
156
|
+
- Validates system compatibility with Isaac Sim requirements
|
|
157
|
+
- `pow sim info` - Display Isaac Sim configuration information
|
|
158
|
+
- Show local assets path configuration (`-l, --local-assets` flag)
|
|
159
|
+
|
|
160
|
+
- **Resource Management (`pow sim add`)**
|
|
161
|
+
- `pow sim add local-assets` - Configure local Isaac Sim assets
|
|
162
|
+
- Updates `isaacsim.exp.base.kit` with local asset paths
|
|
163
|
+
- Configures asset browser and content browser folders
|
|
164
|
+
- Supports versioned asset directories
|
|
165
|
+
|
|
166
|
+
### Dependencies
|
|
167
|
+
|
|
168
|
+
- `click>=8.1.7` - Command line interface framework
|
|
169
|
+
- `toml>=0.10.2` - TOML configuration file parsing
|
|
170
|
+
- Python 3.10+ required
|
|
@@ -6,11 +6,10 @@ from pathlib import Path
|
|
|
6
6
|
import click
|
|
7
7
|
from rich.panel import Panel
|
|
8
8
|
from rich.progress import BarColumn, Progress, SpinnerColumn, TextColumn
|
|
9
|
-
from rich.prompt import Confirm
|
|
10
|
-
from rich.text import Text
|
|
9
|
+
from rich.prompt import Confirm
|
|
11
10
|
|
|
11
|
+
from ..common.prompt import ask_path
|
|
12
12
|
from ..common.utils import console
|
|
13
|
-
from ..core.models.pow_config import PowConfig
|
|
14
13
|
from ..core.initializer import Initializer
|
|
15
14
|
from ..core.ros_manager import RosManager
|
|
16
15
|
|
|
@@ -63,7 +62,7 @@ def _step1_check_config(global_dir_name: str) -> bool:
|
|
|
63
62
|
"""Print config header and verify pyproject.toml exists. Return False to abort."""
|
|
64
63
|
if not Path("pyproject.toml").exists():
|
|
65
64
|
console.print(
|
|
66
|
-
"\n[bold red][1/
|
|
65
|
+
"\n[bold red][1/10] ❌ Error:[/bold red] pyproject.toml not found. "
|
|
67
66
|
"Please run this command in a valid project directory."
|
|
68
67
|
)
|
|
69
68
|
return False
|
|
@@ -260,7 +259,7 @@ def _step6_ros_integration(
|
|
|
260
259
|
ws_path = forced_ws
|
|
261
260
|
console.print(f" Using existing workspace path from pow.toml: [bold green]{ws_path}[/bold green]")
|
|
262
261
|
else:
|
|
263
|
-
ws_path =
|
|
262
|
+
ws_path = ask_path(
|
|
264
263
|
" Path to clone IsaacSim-ros_workspaces",
|
|
265
264
|
default=default_ws,
|
|
266
265
|
)
|
|
@@ -277,28 +276,19 @@ def _step6_ros_integration(
|
|
|
277
276
|
console.print(f" [dim]Workspace path:[/dim] {display_path}")
|
|
278
277
|
|
|
279
278
|
ros_cloned = False
|
|
280
|
-
ros_already_built = False
|
|
281
279
|
|
|
282
280
|
def ros_status_callback(state):
|
|
283
|
-
nonlocal ros_cloned
|
|
281
|
+
nonlocal ros_cloned
|
|
284
282
|
if state == "cloning":
|
|
285
283
|
ros_cloned = True
|
|
286
|
-
status.update("[bold green]Cloning Isaac ROS workspace...")
|
|
284
|
+
status.update("[bold green]Cloning Isaac Sim ROS workspace...")
|
|
287
285
|
elif state == "existed":
|
|
288
|
-
status.update("[bold yellow]Isaac ROS workspace already exists.
|
|
289
|
-
elif state == "built":
|
|
290
|
-
ros_already_built = True
|
|
291
|
-
status.update("[bold yellow]Docker build already complete.")
|
|
292
|
-
elif state == "building":
|
|
293
|
-
status.update("[bold green]Docker build: Isaac ROS workspace...")
|
|
294
|
-
elif state.startswith("building:"):
|
|
295
|
-
line = state[len("building:"):]
|
|
296
|
-
status.update(f"[bold green]Docker build:[/bold green] [dim]{line[:80]}[/dim]")
|
|
286
|
+
status.update("[bold yellow]Isaac Sim ROS workspace already exists.")
|
|
297
287
|
|
|
298
288
|
# Resolve the tilde path for actual filesystem operations
|
|
299
289
|
resolved_ws = Path(ws_path).expanduser()
|
|
300
290
|
|
|
301
|
-
|
|
291
|
+
ros_setup_failed = False
|
|
302
292
|
|
|
303
293
|
with console.status("Preparing ROS workspace...") as status:
|
|
304
294
|
try:
|
|
@@ -307,11 +297,11 @@ def _step6_ros_integration(
|
|
|
307
297
|
ws_path=resolved_ws,
|
|
308
298
|
)
|
|
309
299
|
except Exception as e:
|
|
310
|
-
|
|
300
|
+
ros_setup_failed = True
|
|
311
301
|
console.print(f" [bold red]❌ ROS Setup Error:[/bold red] {e}")
|
|
312
302
|
|
|
313
|
-
if
|
|
314
|
-
console.print(" [yellow]⊖[/yellow] Skipping remaining steps due to ROS
|
|
303
|
+
if ros_setup_failed:
|
|
304
|
+
console.print(" [yellow]⊖[/yellow] Skipping remaining steps due to ROS setup error.")
|
|
315
305
|
raise SystemExit(1)
|
|
316
306
|
|
|
317
307
|
if ros_cloned:
|
|
@@ -319,11 +309,12 @@ def _step6_ros_integration(
|
|
|
319
309
|
else:
|
|
320
310
|
console.print(f" [yellow]✔[/yellow] IsaacSim-ros_workspaces already available in [dim]{display_path}[/dim]")
|
|
321
311
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
312
|
+
bridge_distro = ros_mgr.config.ros_bridge
|
|
313
|
+
console.print(
|
|
314
|
+
f" [green]✔[/green] ROS bridge: [bold]{bridge_distro}[/bold] "
|
|
315
|
+
f"(ros_bridge in pow.toml, host Ubuntu {ros_res['ubuntu_version']}) "
|
|
316
|
+
f"via Isaac Sim internal libs."
|
|
317
|
+
)
|
|
327
318
|
|
|
328
319
|
# Build pow_simros Docker image
|
|
329
320
|
simros_already_built = False
|
|
@@ -341,7 +332,7 @@ def _step6_ros_integration(
|
|
|
341
332
|
|
|
342
333
|
with console.status("Building pow_simros image...") as simros_status:
|
|
343
334
|
try:
|
|
344
|
-
|
|
335
|
+
ros_mgr.build_simros_image(
|
|
345
336
|
status_callback=simros_status_callback,
|
|
346
337
|
ws_path=resolved_ws,
|
|
347
338
|
)
|
|
@@ -356,13 +347,38 @@ def _step6_ros_integration(
|
|
|
356
347
|
else:
|
|
357
348
|
console.print(f" [green]✔[/green] Docker image {simros_label} built successfully.")
|
|
358
349
|
|
|
350
|
+
# Build custom ROS image layered on top of pow_simros_<distro>
|
|
351
|
+
custom_dockerfile = ros_mgr.config.ros_dockerfile
|
|
352
|
+
if custom_dockerfile:
|
|
353
|
+
custom_image = ros_mgr.config.ros_docker_image
|
|
354
|
+
|
|
355
|
+
def custom_status_callback(state):
|
|
356
|
+
if state == "custom_building":
|
|
357
|
+
custom_status.update(f"[bold green]Building custom image '{custom_image}'...")
|
|
358
|
+
elif state.startswith("custom_building:"):
|
|
359
|
+
line = state[len("custom_building:"):]
|
|
360
|
+
custom_status.update(f"[bold green]custom build:[/bold green] [dim]{line[:80]}[/dim]")
|
|
361
|
+
|
|
362
|
+
with console.status(f"Building custom image '{custom_image}'...") as custom_status:
|
|
363
|
+
try:
|
|
364
|
+
ros_mgr.build_custom_ros_image(status_callback=custom_status_callback)
|
|
365
|
+
except Exception as e:
|
|
366
|
+
console.print(f" [bold red]❌ Custom ROS Build Error:[/bold red] {e}")
|
|
367
|
+
console.print(" [yellow]⊖[/yellow] Skipping remaining steps due to build error.")
|
|
368
|
+
raise SystemExit(1)
|
|
369
|
+
|
|
370
|
+
console.print(
|
|
371
|
+
f" [green]✔[/green] Custom Docker image [bold]{custom_image}[/bold] "
|
|
372
|
+
f"built from [dim]{custom_dockerfile}[/dim]."
|
|
373
|
+
)
|
|
374
|
+
|
|
359
375
|
return True, display_path
|
|
360
376
|
|
|
361
377
|
|
|
362
378
|
def _step7_project_structure(initializer: Initializer):
|
|
363
379
|
"""Create local project folders and .gitignore."""
|
|
364
380
|
console.print("[bold blue][7/10] 🏗️ Project Structure:[/bold blue] Creating local folders...")
|
|
365
|
-
local_folders = ["exts", "
|
|
381
|
+
local_folders = ["exts", ".modules", "usda"]
|
|
366
382
|
|
|
367
383
|
with Progress(
|
|
368
384
|
SpinnerColumn(),
|
|
@@ -5,8 +5,6 @@ from pathlib import Path
|
|
|
5
5
|
import click
|
|
6
6
|
from rich.markup import escape
|
|
7
7
|
from rich.panel import Panel
|
|
8
|
-
from rich.table import Table
|
|
9
|
-
from rich.text import Text
|
|
10
8
|
|
|
11
9
|
from ..common.utils import console
|
|
12
10
|
from ..core.linter import AliasConfig, lint_file, fix_file, scan_directory
|
|
@@ -7,14 +7,24 @@ from .init import init_cmd
|
|
|
7
7
|
from .check import check_cmd
|
|
8
8
|
from .lint import lint_group
|
|
9
9
|
from .run import run_cmd
|
|
10
|
-
from .
|
|
10
|
+
from .sim import sim_cmd
|
|
11
|
+
from .ros import ros_group
|
|
11
12
|
from .python import python_cmd
|
|
12
13
|
from .asset import asset_group
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
@click.group()
|
|
17
|
+
@click.version_option(
|
|
18
|
+
None,
|
|
19
|
+
"-v",
|
|
20
|
+
"--version",
|
|
21
|
+
package_name="pow-cli",
|
|
22
|
+
prog_name="pow",
|
|
23
|
+
message="%(prog)s %(version)s",
|
|
24
|
+
help="Show the pow CLI version.",
|
|
25
|
+
)
|
|
16
26
|
def pow_group():
|
|
17
|
-
"""Isaac
|
|
27
|
+
"""Manage Isaac Sim projects and simplify the development workflow."""
|
|
18
28
|
pass
|
|
19
29
|
|
|
20
30
|
|
|
@@ -23,6 +33,7 @@ pow_group.add_command(init_cmd)
|
|
|
23
33
|
pow_group.add_command(check_cmd)
|
|
24
34
|
pow_group.add_command(lint_group)
|
|
25
35
|
pow_group.add_command(run_cmd)
|
|
26
|
-
pow_group.add_command(
|
|
36
|
+
pow_group.add_command(sim_cmd)
|
|
37
|
+
pow_group.add_command(ros_group)
|
|
27
38
|
pow_group.add_command(python_cmd)
|
|
28
39
|
pow_group.add_command(asset_group)
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""Ros command implementation."""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
from rich.panel import Panel
|
|
5
|
+
from ..common.utils import console
|
|
6
|
+
from ..core.ros_manager import RosManager
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _launch_container(extra_args, verbose: bool):
|
|
10
|
+
"""Launch or attach to the ROS container, rendering errors as panels."""
|
|
11
|
+
try:
|
|
12
|
+
RosManager.run_simros_container(extra_args=extra_args, verbose=verbose)
|
|
13
|
+
except click.ClickException:
|
|
14
|
+
raise
|
|
15
|
+
except Exception as e:
|
|
16
|
+
console.print(
|
|
17
|
+
Panel(
|
|
18
|
+
f"[bold red]✘[/bold red] {e}",
|
|
19
|
+
title="[bold red]ROS Error[/bold red]",
|
|
20
|
+
border_style="red",
|
|
21
|
+
)
|
|
22
|
+
)
|
|
23
|
+
raise SystemExit(1)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class RosGroup(click.Group):
|
|
27
|
+
"""Group that falls through to `launch` for unrecognized arguments."""
|
|
28
|
+
|
|
29
|
+
def resolve_command(self, ctx, args):
|
|
30
|
+
if args and self.get_command(ctx, args[0]) is not None:
|
|
31
|
+
return super().resolve_command(ctx, args)
|
|
32
|
+
launch = self.get_command(ctx, "launch")
|
|
33
|
+
return launch.name, launch, args
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@click.group(
|
|
37
|
+
name="ros",
|
|
38
|
+
cls=RosGroup,
|
|
39
|
+
invoke_without_command=True,
|
|
40
|
+
context_settings={"ignore_unknown_options": True},
|
|
41
|
+
)
|
|
42
|
+
@click.pass_context
|
|
43
|
+
def ros_group(ctx: click.Context):
|
|
44
|
+
"""Launch or manage the ROS docker container.
|
|
45
|
+
|
|
46
|
+
Without a subcommand, launches an interactive session in the container
|
|
47
|
+
running the image from `ros_docker_image` in pow.toml (or attaches to it
|
|
48
|
+
if it is already running). Unrecognized arguments are forwarded as the
|
|
49
|
+
container command (default: /bin/bash), e.g. `pow ros ros2 topic list`.
|
|
50
|
+
|
|
51
|
+
\b
|
|
52
|
+
Subcommands:
|
|
53
|
+
launch Explicitly launch the container (same as bare `pow ros`).
|
|
54
|
+
build Build the custom image from `ros_dockerfile`.
|
|
55
|
+
|
|
56
|
+
\b
|
|
57
|
+
Requires:
|
|
58
|
+
- ROS integration enabled in pow.toml (enable_ros = true).
|
|
59
|
+
- The pow_simros Docker image built via `pow init`.
|
|
60
|
+
"""
|
|
61
|
+
if ctx.invoked_subcommand is None:
|
|
62
|
+
_launch_container(None, False)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@ros_group.command(
|
|
66
|
+
name="launch",
|
|
67
|
+
context_settings={"ignore_unknown_options": True, "allow_extra_args": True},
|
|
68
|
+
)
|
|
69
|
+
@click.option("--verbose", "-v", is_flag=True, default=False, help="Show detailed feedback during container launch.")
|
|
70
|
+
@click.pass_context
|
|
71
|
+
def launch_cmd(ctx: click.Context, verbose: bool):
|
|
72
|
+
"""Launch the ROS container, forwarding extra args as the container command."""
|
|
73
|
+
_launch_container(ctx.args or None, verbose)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@ros_group.command(name="build")
|
|
77
|
+
@click.option("--no-cache", is_flag=True, default=False, help="Build without using the Docker layer cache.")
|
|
78
|
+
def build_cmd(no_cache: bool):
|
|
79
|
+
"""Build the custom ROS image from `ros_dockerfile` in pow.toml."""
|
|
80
|
+
ros_mgr = RosManager()
|
|
81
|
+
config = ros_mgr.config
|
|
82
|
+
|
|
83
|
+
if config.project_root is None:
|
|
84
|
+
raise click.ClickException("Not initialized. Run `pow init` first.")
|
|
85
|
+
|
|
86
|
+
if not config.ros_dockerfile:
|
|
87
|
+
console.print(
|
|
88
|
+
"[yellow]No `ros_dockerfile` set in pow.toml; nothing to build.[/yellow]\n"
|
|
89
|
+
f"The bundled [bold]pow_simros_{config.ros_distro}[/bold] image is built by `pow init`."
|
|
90
|
+
)
|
|
91
|
+
return
|
|
92
|
+
|
|
93
|
+
base_image = f"pow_simros_{config.ros_distro}"
|
|
94
|
+
if not RosManager.image_exists(base_image):
|
|
95
|
+
distro_ws = config.ros_ws_path / f"{config.ros_distro}_ws"
|
|
96
|
+
if not distro_ws.exists():
|
|
97
|
+
raise click.ClickException(
|
|
98
|
+
f"Base image '{base_image}' not found and the ROS workspace "
|
|
99
|
+
f"'{distro_ws}' does not exist.\n"
|
|
100
|
+
"Run `pow init` first to set up the ROS workspace."
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
console.print(f"[yellow]Base image '{base_image}' not found — building it first.[/yellow]")
|
|
104
|
+
|
|
105
|
+
def simros_status_callback(state):
|
|
106
|
+
if state == "simros_building":
|
|
107
|
+
base_status.update(f"[bold green]Building base image '{base_image}'...")
|
|
108
|
+
elif state.startswith("simros_building:"):
|
|
109
|
+
line = state[len("simros_building:"):]
|
|
110
|
+
base_status.update(f"[bold green]{base_image} build:[/bold green] [dim]{line[:80]}[/dim]")
|
|
111
|
+
|
|
112
|
+
with console.status(f"Building base image '{base_image}'...") as base_status:
|
|
113
|
+
try:
|
|
114
|
+
ros_mgr.build_simros_image(status_callback=simros_status_callback)
|
|
115
|
+
except Exception as e:
|
|
116
|
+
console.print(
|
|
117
|
+
Panel(
|
|
118
|
+
f"[bold red]✘[/bold red] {e}",
|
|
119
|
+
title="[bold red]ROS Build Error[/bold red]",
|
|
120
|
+
border_style="red",
|
|
121
|
+
)
|
|
122
|
+
)
|
|
123
|
+
raise SystemExit(1)
|
|
124
|
+
|
|
125
|
+
console.print(f"[green]✔[/green] Base Docker image [bold]{base_image}[/bold] built successfully.")
|
|
126
|
+
|
|
127
|
+
custom_image = config.ros_docker_image
|
|
128
|
+
|
|
129
|
+
def custom_status_callback(state):
|
|
130
|
+
if state == "custom_building":
|
|
131
|
+
custom_status.update(f"[bold green]Building custom image '{custom_image}'...")
|
|
132
|
+
elif state.startswith("custom_building:"):
|
|
133
|
+
line = state[len("custom_building:"):]
|
|
134
|
+
custom_status.update(f"[bold green]custom build:[/bold green] [dim]{line[:80]}[/dim]")
|
|
135
|
+
|
|
136
|
+
with console.status(f"Building custom image '{custom_image}'...") as custom_status:
|
|
137
|
+
try:
|
|
138
|
+
ros_mgr.build_custom_ros_image(
|
|
139
|
+
status_callback=custom_status_callback,
|
|
140
|
+
no_cache=no_cache,
|
|
141
|
+
)
|
|
142
|
+
except Exception as e:
|
|
143
|
+
console.print(
|
|
144
|
+
Panel(
|
|
145
|
+
f"[bold red]✘[/bold red] {e}",
|
|
146
|
+
title="[bold red]ROS Build Error[/bold red]",
|
|
147
|
+
border_style="red",
|
|
148
|
+
)
|
|
149
|
+
)
|
|
150
|
+
raise SystemExit(1)
|
|
151
|
+
|
|
152
|
+
console.print(
|
|
153
|
+
f"[green]✔[/green] Custom Docker image [bold]{custom_image}[/bold] "
|
|
154
|
+
f"built from [dim]{config.ros_dockerfile}[/dim]."
|
|
155
|
+
)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Sim command implementation."""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
from rich.panel import Panel
|
|
5
|
+
from ..common.utils import console
|
|
6
|
+
from ..core.models.pow_config import PowConfig
|
|
7
|
+
from ..core.runner import Runner
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@click.command(
|
|
11
|
+
name="sim",
|
|
12
|
+
context_settings={"ignore_unknown_options": True, "allow_extra_args": True},
|
|
13
|
+
)
|
|
14
|
+
@click.option(
|
|
15
|
+
"-v",
|
|
16
|
+
"--version",
|
|
17
|
+
"sim_version",
|
|
18
|
+
default=PowConfig.ISAACSIM_VERSION,
|
|
19
|
+
show_default=True,
|
|
20
|
+
help="Isaac Sim version to run.",
|
|
21
|
+
)
|
|
22
|
+
@click.option(
|
|
23
|
+
"--ros",
|
|
24
|
+
"ros_bridge",
|
|
25
|
+
type=click.Choice(PowConfig.SUPPORTED_ROS_BRIDGES),
|
|
26
|
+
default=PowConfig.ROS_BRIDGE,
|
|
27
|
+
show_default=True,
|
|
28
|
+
help="ROS 2 bridge distro to load into the environment.",
|
|
29
|
+
)
|
|
30
|
+
@click.option(
|
|
31
|
+
"--no-ros",
|
|
32
|
+
is_flag=True,
|
|
33
|
+
default=False,
|
|
34
|
+
help="Launch without the ROS 2 bridge environment.",
|
|
35
|
+
)
|
|
36
|
+
@click.pass_context
|
|
37
|
+
def sim_cmd(ctx: click.Context, sim_version: str, ros_bridge: str, no_ros: bool):
|
|
38
|
+
"""Run Isaac Sim from any directory, ignoring pow.toml.
|
|
39
|
+
|
|
40
|
+
\b
|
|
41
|
+
Unlike `pow run` this needs no project: no pyproject.toml is required and
|
|
42
|
+
pow.toml is never read. Every unrecognized argument is forwarded verbatim
|
|
43
|
+
to .pow/isaacsim/<version>/isaac-sim.sh.
|
|
44
|
+
|
|
45
|
+
\b
|
|
46
|
+
Examples:
|
|
47
|
+
pow sim
|
|
48
|
+
pow sim --no-ros
|
|
49
|
+
pow sim -- --no-window --/renderer/enabled=gpu
|
|
50
|
+
"""
|
|
51
|
+
try:
|
|
52
|
+
Runner.run_sim(
|
|
53
|
+
version=sim_version,
|
|
54
|
+
ros_bridge=None if no_ros else ros_bridge,
|
|
55
|
+
extra_args=ctx.args,
|
|
56
|
+
)
|
|
57
|
+
except click.ClickException:
|
|
58
|
+
raise
|
|
59
|
+
except Exception as e:
|
|
60
|
+
console.print(
|
|
61
|
+
Panel(
|
|
62
|
+
f"[bold red]✘[/bold red] {e}",
|
|
63
|
+
title="[bold red]Sim Error[/bold red]",
|
|
64
|
+
border_style="red",
|
|
65
|
+
)
|
|
66
|
+
)
|
|
67
|
+
raise SystemExit(1)
|