pixi-ros 0.3.0__py3-none-any.whl → 0.4.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.
- pixi_ros/cli.py +42 -29
- pixi_ros/data/conda-forge.yaml +4 -0
- pixi_ros/init.py +324 -198
- pixi_ros/mappings.py +39 -30
- pixi_ros/validator.py +245 -0
- {pixi_ros-0.3.0.dist-info → pixi_ros-0.4.0.dist-info}/METADATA +83 -26
- pixi_ros-0.4.0.dist-info/RECORD +17 -0
- pixi_ros-0.3.0.dist-info/RECORD +0 -16
- {pixi_ros-0.3.0.dist-info → pixi_ros-0.4.0.dist-info}/WHEEL +0 -0
- {pixi_ros-0.3.0.dist-info → pixi_ros-0.4.0.dist-info}/entry_points.txt +0 -0
- {pixi_ros-0.3.0.dist-info → pixi_ros-0.4.0.dist-info}/licenses/LICENSE +0 -0
pixi_ros/mappings.py
CHANGED
|
@@ -103,7 +103,11 @@ def reload_mappings():
|
|
|
103
103
|
|
|
104
104
|
|
|
105
105
|
def map_ros_to_conda(
|
|
106
|
-
ros_package: str,
|
|
106
|
+
ros_package: str,
|
|
107
|
+
distro: str = "humble",
|
|
108
|
+
platform_override: str | None = None,
|
|
109
|
+
validator=None,
|
|
110
|
+
workspace_packages: set[str] | None = None,
|
|
107
111
|
) -> list[str]:
|
|
108
112
|
"""
|
|
109
113
|
Map a ROS package name to its conda package names.
|
|
@@ -116,6 +120,8 @@ def map_ros_to_conda(
|
|
|
116
120
|
ros_package: The ROS package name (e.g., "rclcpp", "udev", "opengl")
|
|
117
121
|
distro: The ROS distribution (e.g., "humble", "iron", "jazzy")
|
|
118
122
|
platform_override: Override platform detection (for testing)
|
|
123
|
+
validator: Optional RosDistroValidator instance for validation
|
|
124
|
+
workspace_packages: Optional set of workspace package names
|
|
119
125
|
|
|
120
126
|
Returns:
|
|
121
127
|
List of conda package names, which may include placeholder strings
|
|
@@ -130,6 +136,30 @@ def map_ros_to_conda(
|
|
|
130
136
|
>>> map_ros_to_conda("opengl", "humble") # doctest: +SKIP
|
|
131
137
|
['REQUIRE_OPENGL'] # placeholder from mapping file
|
|
132
138
|
"""
|
|
139
|
+
# If validator is provided, use full validation logic
|
|
140
|
+
if validator is not None:
|
|
141
|
+
mappings = get_mappings()
|
|
142
|
+
ws_packages = workspace_packages or set()
|
|
143
|
+
|
|
144
|
+
# Determine the platform to use for validation
|
|
145
|
+
if platform_override:
|
|
146
|
+
# Convert mapping platform to pixi platform for validator
|
|
147
|
+
mapping_to_pixi = {
|
|
148
|
+
"linux": "linux-64",
|
|
149
|
+
"osx": "osx-64",
|
|
150
|
+
"win64": "win-64",
|
|
151
|
+
}
|
|
152
|
+
platform = mapping_to_pixi.get(platform_override, "linux-64")
|
|
153
|
+
else:
|
|
154
|
+
# Use current platform
|
|
155
|
+
platform = str(Platform.current())
|
|
156
|
+
|
|
157
|
+
result = validator.validate_package(
|
|
158
|
+
ros_package, ws_packages, mappings, platform
|
|
159
|
+
)
|
|
160
|
+
return result.conda_packages
|
|
161
|
+
|
|
162
|
+
# Legacy behavior (backward compatibility)
|
|
133
163
|
mappings = get_mappings()
|
|
134
164
|
current_platform = platform_override or _detect_platform()
|
|
135
165
|
|
|
@@ -257,46 +287,25 @@ def is_system_package(package_name: str) -> bool:
|
|
|
257
287
|
|
|
258
288
|
def get_platforms() -> list[str]:
|
|
259
289
|
"""
|
|
260
|
-
Get list of supported pixi platforms
|
|
261
|
-
|
|
262
|
-
Extracts platform names from the mapping data and converts them to
|
|
263
|
-
standard pixi platform names.
|
|
264
|
-
|
|
265
|
-
Mapping files use: linux, osx, win64
|
|
266
|
-
Pixi uses: linux-64, osx-64, osx-arm64, win-64
|
|
290
|
+
Get list of supported pixi platforms, including current platform.
|
|
267
291
|
|
|
268
292
|
Returns:
|
|
269
293
|
List of pixi platform names
|
|
270
294
|
"""
|
|
271
|
-
mappings = get_mappings()
|
|
272
|
-
mapping_platforms = set()
|
|
273
295
|
|
|
274
|
-
#
|
|
275
|
-
|
|
276
|
-
for channel_mapping in package_mappings.values():
|
|
277
|
-
if isinstance(channel_mapping, dict):
|
|
278
|
-
# This is a platform-specific mapping
|
|
279
|
-
mapping_platforms.update(channel_mapping.keys())
|
|
296
|
+
# Hardcoded supported platforms, as a hint for the user.
|
|
297
|
+
pixi_platforms = ["linux-64", "linux-aarch64", "osx-64", "osx-arm64", "win-64"]
|
|
280
298
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
pixi_platforms.append("linux-64")
|
|
285
|
-
if "osx" in mapping_platforms:
|
|
286
|
-
pixi_platforms.extend(["osx-64", "osx-arm64"])
|
|
287
|
-
if "win64" in mapping_platforms or "win" in mapping_platforms:
|
|
288
|
-
pixi_platforms.append("win-64")
|
|
299
|
+
platform_str = str(Platform.current())
|
|
300
|
+
if not any(platform_str in p for p in pixi_platforms):
|
|
301
|
+
pixi_platforms.append(platform_str)
|
|
289
302
|
|
|
290
|
-
return
|
|
291
|
-
pixi_platforms
|
|
292
|
-
if pixi_platforms
|
|
293
|
-
else ["linux-64", "osx-64", "osx-arm64", "win-64"]
|
|
294
|
-
)
|
|
303
|
+
return pixi_platforms
|
|
295
304
|
|
|
296
305
|
|
|
297
306
|
def get_ros_distros() -> list[str]:
|
|
298
307
|
"""
|
|
299
|
-
Get list of
|
|
308
|
+
Get list of known ROS distributions.
|
|
300
309
|
|
|
301
310
|
Returns:
|
|
302
311
|
List of ROS distro names
|
pixi_ros/validator.py
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
"""ROS package validation logic."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from enum import Enum
|
|
6
|
+
|
|
7
|
+
from rattler import Channel, Gateway, Platform
|
|
8
|
+
from rosdistro import get_cached_distribution, get_index, get_index_url
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class PackageSource(Enum):
|
|
12
|
+
"""Source of a package."""
|
|
13
|
+
|
|
14
|
+
WORKSPACE = "workspace"
|
|
15
|
+
MAPPING = "mapping"
|
|
16
|
+
ROS_DISTRO = "ros_distro"
|
|
17
|
+
CONDA_FORGE = "conda_forge"
|
|
18
|
+
NOT_FOUND = "not_found"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class PackageValidationResult:
|
|
23
|
+
"""Result of package validation."""
|
|
24
|
+
|
|
25
|
+
package_name: str
|
|
26
|
+
source: PackageSource
|
|
27
|
+
conda_packages: list[str]
|
|
28
|
+
error: str | None = None
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class RosDistroValidator:
|
|
32
|
+
"""Validator for ROS packages using rosdistro."""
|
|
33
|
+
|
|
34
|
+
def __init__(self, distro_name: str):
|
|
35
|
+
"""
|
|
36
|
+
Initialize validator with ROS distribution.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
distro_name: ROS distribution name (e.g., "humble", "jazzy")
|
|
40
|
+
"""
|
|
41
|
+
self.distro_name = distro_name
|
|
42
|
+
self._distro = None
|
|
43
|
+
self._init_error = None
|
|
44
|
+
self._conda_forge_cache = {}
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
index = get_index(get_index_url())
|
|
48
|
+
self._distro = get_cached_distribution(index, distro_name)
|
|
49
|
+
except Exception as e:
|
|
50
|
+
self._init_error = str(e)
|
|
51
|
+
|
|
52
|
+
def has_package(self, package_name: str) -> bool:
|
|
53
|
+
"""
|
|
54
|
+
Check if package exists in ROS distribution.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
package_name: ROS package name
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
True if package exists in distribution
|
|
61
|
+
"""
|
|
62
|
+
if self._distro is None:
|
|
63
|
+
return False
|
|
64
|
+
return package_name in self._distro.release_packages
|
|
65
|
+
|
|
66
|
+
def check_package_availability(
|
|
67
|
+
self, package_name: str, platform: str, channel_url: str
|
|
68
|
+
) -> bool:
|
|
69
|
+
"""
|
|
70
|
+
Check if package is available in the specified channel.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
package_name: Conda package name
|
|
74
|
+
platform: Platform string (e.g., "linux-64", "osx-arm64")
|
|
75
|
+
channel_url: Channel URL to check (e.g., "https://prefix.dev/conda-forge")
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
True if package is available in the channel
|
|
79
|
+
"""
|
|
80
|
+
# Check cache first
|
|
81
|
+
cache_key = (package_name, platform, channel_url)
|
|
82
|
+
if cache_key in self._conda_forge_cache:
|
|
83
|
+
return self._conda_forge_cache[cache_key]
|
|
84
|
+
|
|
85
|
+
try:
|
|
86
|
+
gateway = Gateway()
|
|
87
|
+
channel = Channel(channel_url)
|
|
88
|
+
platform_obj = Platform(platform)
|
|
89
|
+
noarch_obj = Platform("noarch")
|
|
90
|
+
|
|
91
|
+
# Query with 10 second timeout, check both platform and noarch
|
|
92
|
+
repo_data = asyncio.wait_for(
|
|
93
|
+
gateway.query(
|
|
94
|
+
[channel],
|
|
95
|
+
[platform_obj, noarch_obj],
|
|
96
|
+
specs=[package_name],
|
|
97
|
+
recursive=False,
|
|
98
|
+
),
|
|
99
|
+
timeout=10.0,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Check if any records match
|
|
103
|
+
results = asyncio.run(repo_data)
|
|
104
|
+
for channel_records in results:
|
|
105
|
+
for record in channel_records:
|
|
106
|
+
if record.name.normalized == package_name.lower():
|
|
107
|
+
self._conda_forge_cache[cache_key] = True
|
|
108
|
+
return True
|
|
109
|
+
|
|
110
|
+
self._conda_forge_cache[cache_key] = False
|
|
111
|
+
return False
|
|
112
|
+
except (asyncio.TimeoutError, Exception):
|
|
113
|
+
# On error or timeout, assume not available
|
|
114
|
+
self._conda_forge_cache[cache_key] = False
|
|
115
|
+
return False
|
|
116
|
+
|
|
117
|
+
def check_conda_forge_availability(self, package_name: str, platform: str) -> bool:
|
|
118
|
+
"""
|
|
119
|
+
Check if package is available on conda-forge.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
package_name: Conda package name
|
|
123
|
+
platform: Platform string (e.g., "linux-64", "osx-arm64")
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
True if package is available on conda-forge
|
|
127
|
+
"""
|
|
128
|
+
return self.check_package_availability(
|
|
129
|
+
package_name, platform, "https://prefix.dev/conda-forge"
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
def validate_package(
|
|
133
|
+
self,
|
|
134
|
+
package_name: str,
|
|
135
|
+
workspace_packages: set[str],
|
|
136
|
+
mappings: dict[str, dict[str, list[str] | dict[str, list[str]]]],
|
|
137
|
+
platform: str = "linux-64",
|
|
138
|
+
) -> PackageValidationResult:
|
|
139
|
+
"""
|
|
140
|
+
Validate a ROS package and determine its source.
|
|
141
|
+
|
|
142
|
+
Process:
|
|
143
|
+
1. Determine source (workspace/mapping/ros_distro/conda_forge/not_found)
|
|
144
|
+
2. Validate that packages actually exist in their expected channels
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
package_name: ROS package name
|
|
148
|
+
workspace_packages: Set of package names in the workspace
|
|
149
|
+
mappings: Package mappings from mapping files
|
|
150
|
+
platform: Target platform (default: "linux-64")
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
PackageValidationResult with source and conda package names
|
|
154
|
+
"""
|
|
155
|
+
# Step 1: Determine source without validation
|
|
156
|
+
source = None
|
|
157
|
+
conda_packages = []
|
|
158
|
+
|
|
159
|
+
# 1. Check if it's a workspace package
|
|
160
|
+
if package_name in workspace_packages:
|
|
161
|
+
return PackageValidationResult(
|
|
162
|
+
package_name=package_name,
|
|
163
|
+
source=PackageSource.WORKSPACE,
|
|
164
|
+
conda_packages=[],
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
# 2. Check if it's in the mapping file
|
|
168
|
+
if package_name in mappings:
|
|
169
|
+
channels = mappings[package_name]
|
|
170
|
+
if channels:
|
|
171
|
+
channel_mapping = next(iter(channels.values()))
|
|
172
|
+
if isinstance(channel_mapping, dict):
|
|
173
|
+
# Platform-specific mapping
|
|
174
|
+
pixi_to_mapping = {
|
|
175
|
+
"linux-64": "linux",
|
|
176
|
+
"linux-aarch64": "linux",
|
|
177
|
+
"osx-64": "osx",
|
|
178
|
+
"osx-arm64": "osx",
|
|
179
|
+
"win-64": "win64",
|
|
180
|
+
}
|
|
181
|
+
mapping_platform = pixi_to_mapping.get(platform, "linux")
|
|
182
|
+
packages = channel_mapping.get(mapping_platform, [])
|
|
183
|
+
source = PackageSource.MAPPING
|
|
184
|
+
conda_packages = packages if packages else []
|
|
185
|
+
elif isinstance(channel_mapping, list):
|
|
186
|
+
source = PackageSource.MAPPING
|
|
187
|
+
conda_packages = channel_mapping
|
|
188
|
+
|
|
189
|
+
# 3. Check if it's in ROS distro
|
|
190
|
+
if source is None and self.has_package(package_name):
|
|
191
|
+
conda_name = package_name.replace("_", "-")
|
|
192
|
+
source = PackageSource.ROS_DISTRO
|
|
193
|
+
conda_packages = [f"ros-{self.distro_name}-{conda_name}"]
|
|
194
|
+
|
|
195
|
+
# 4. Check if it's available on conda-forge (without ros-distro prefix)
|
|
196
|
+
if source is None:
|
|
197
|
+
conda_name = package_name.replace("_", "-")
|
|
198
|
+
if self.check_conda_forge_availability(conda_name, platform):
|
|
199
|
+
source = PackageSource.CONDA_FORGE
|
|
200
|
+
conda_packages = [conda_name]
|
|
201
|
+
|
|
202
|
+
# 5. Not found
|
|
203
|
+
if source is None:
|
|
204
|
+
print(
|
|
205
|
+
f"Package '{package_name}' not found in workspace, mappings, "
|
|
206
|
+
f"ROS distro, or conda-forge."
|
|
207
|
+
)
|
|
208
|
+
return PackageValidationResult(
|
|
209
|
+
package_name=package_name,
|
|
210
|
+
source=PackageSource.NOT_FOUND,
|
|
211
|
+
conda_packages=[],
|
|
212
|
+
error=f"Package '{package_name}' not found in any source",
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
# Step 2: Validate packages exist in their expected channels
|
|
216
|
+
# Note: We don't validate mapped packages - we trust the mappings
|
|
217
|
+
if source == PackageSource.ROS_DISTRO:
|
|
218
|
+
# Validate ROS package exists in robostack channel
|
|
219
|
+
robostack_channel = f"https://prefix.dev/robostack-{self.distro_name}"
|
|
220
|
+
ros_conda_name = conda_packages[0]
|
|
221
|
+
|
|
222
|
+
if not self.check_package_availability(
|
|
223
|
+
ros_conda_name, platform, robostack_channel
|
|
224
|
+
):
|
|
225
|
+
print(
|
|
226
|
+
f"Package '{package_name}' found in ROS {self.distro_name} "
|
|
227
|
+
f"distro index but '{ros_conda_name}' not available in "
|
|
228
|
+
f"robostack-{self.distro_name}."
|
|
229
|
+
)
|
|
230
|
+
# Keep the conda package name so we can show it in NOT_FOUND
|
|
231
|
+
return PackageValidationResult(
|
|
232
|
+
package_name=package_name,
|
|
233
|
+
source=PackageSource.NOT_FOUND,
|
|
234
|
+
conda_packages=[ros_conda_name],
|
|
235
|
+
error=(
|
|
236
|
+
f"ROS package not available in robostack-{self.distro_name}"
|
|
237
|
+
),
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
# Source determined and validated
|
|
241
|
+
return PackageValidationResult(
|
|
242
|
+
package_name=package_name,
|
|
243
|
+
source=source,
|
|
244
|
+
conda_packages=conda_packages,
|
|
245
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pixi-ros
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Pixi extension for ROS package management
|
|
5
5
|
Project-URL: Homepage, https://github.com/ruben-arts/pixi-ros
|
|
6
6
|
Project-URL: Repository, https://github.com/ruben-arts/pixi-ros
|
|
@@ -13,6 +13,7 @@ Requires-Dist: pathspec>=0.11.0
|
|
|
13
13
|
Requires-Dist: py-rattler>=0.6.0
|
|
14
14
|
Requires-Dist: pyyaml>=6.0
|
|
15
15
|
Requires-Dist: rich>=13.0.0
|
|
16
|
+
Requires-Dist: rosdistro>=0.9.0
|
|
16
17
|
Requires-Dist: tomlkit>=0.12.0
|
|
17
18
|
Requires-Dist: typer>=0.12.0
|
|
18
19
|
Description-Content-Type: text/markdown
|
|
@@ -63,10 +64,16 @@ pixi-ros init --distro humble
|
|
|
63
64
|
This will:
|
|
64
65
|
1. Discover all ROS packages in your workspace (by finding `package.xml` files)
|
|
65
66
|
2. Read dependencies from each `package.xml`
|
|
66
|
-
3.
|
|
67
|
+
3. **Validate and resolve** each dependency using the priority system:
|
|
68
|
+
- Skip workspace packages (built locally)
|
|
69
|
+
- Use custom mappings from YAML files
|
|
70
|
+
- Query ROS distro index for ROS packages
|
|
71
|
+
- Auto-detect packages on conda-forge
|
|
72
|
+
- Flag packages that can't be found
|
|
67
73
|
4. Generate/update `pixi.toml` with proper channels and dependencies
|
|
68
|
-
5. Check package availability
|
|
74
|
+
5. Check package availability in conda channels for each platform
|
|
69
75
|
6. Create helpful build/test/clean tasks
|
|
76
|
+
7. Display detailed validation results with source information
|
|
70
77
|
|
|
71
78
|
### Install and Build
|
|
72
79
|
|
|
@@ -88,26 +95,66 @@ pixi shell
|
|
|
88
95
|
|
|
89
96
|
## How It Works
|
|
90
97
|
|
|
91
|
-
### Dependency Mapping
|
|
98
|
+
### Dependency Mapping & Validation
|
|
92
99
|
|
|
93
|
-
`pixi-ros` reads all dependency types from `package.xml` files
|
|
94
|
-
It then does a best effort mapping of ROS package names to conda packages.
|
|
100
|
+
`pixi-ros` reads all dependency types from `package.xml` files and intelligently resolves them to conda packages using a **priority-based validation system**.
|
|
95
101
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
102
|
+
#### Validation Priority Order
|
|
103
|
+
|
|
104
|
+
When resolving a ROS package dependency, `pixi-ros` checks sources in this order:
|
|
105
|
+
|
|
106
|
+
1. **Workspace packages** (local source) → Skipped, won't be added to dependencies
|
|
107
|
+
2. **Mapping files** → Use custom conda package mappings from the embedded mapping.
|
|
108
|
+
3. **ROS distribution** → Query the official ROS distro index for `ros-{distro}-{package}` packages
|
|
109
|
+
4. **conda-forge** (auto-detection) → Search conda-forge for packages without ros-distro prefix
|
|
110
|
+
5. **NOT FOUND** → Mark as unavailable and comment out in `pixi.toml`
|
|
111
|
+
|
|
112
|
+
#### Package Sources
|
|
113
|
+
|
|
114
|
+
The dependency tables show where each package comes from:
|
|
115
|
+
|
|
116
|
+
- **ROS {distro}**: Official ROS distribution packages from robostack (e.g., `ros-humble-rclcpp`)
|
|
117
|
+
- **Mapping**: Custom mappings from YAML files (e.g., `cmake` → `cmake`, `udev` → `libusb + libudev`)
|
|
118
|
+
- **conda-forge**: Auto-detected packages available directly on conda-forge
|
|
119
|
+
- **Workspace**: Local packages in your workspace (skipped from dependencies)
|
|
120
|
+
- **NOT FOUND**: Packages that couldn't be resolved (commented out in `pixi.toml`)
|
|
99
121
|
|
|
100
122
|
The mapping rules are defined in YAML files (see `src/pixi_ros/data/conda-forge.yaml`) and can be customized by placing your own mapping files in `pixi-ros/*.yaml` or `~/.pixi-ros/*.yaml`.
|
|
101
123
|
|
|
102
|
-
After
|
|
124
|
+
After dependency resolution, `pixi-ros` validates package availability in the configured channels for each target platform by connecting to `https://prefix.dev`.
|
|
125
|
+
|
|
126
|
+
### Example Output
|
|
127
|
+
|
|
128
|
+
When you run `pixi-ros init --distro humble`, you'll see validation results:
|
|
103
129
|
|
|
104
|
-
|
|
130
|
+
```
|
|
131
|
+
Found 2 package(s): my_package, other_package
|
|
132
|
+
Initializing ROS humble distribution validator...
|
|
133
|
+
|
|
134
|
+
╭─────────────────── Package: my_package ───────────────────╮
|
|
135
|
+
│ ROS Dependency │ Type │ Conda Packages │ Source │
|
|
136
|
+
├────────────────┼─────────┼─────────────────────────┼──────────────┤
|
|
137
|
+
│ rclcpp │ Build │ ros-humble-rclcpp │ ROS humble │
|
|
138
|
+
│ std_msgs │ Runtime │ ros-humble-std-msgs │ ROS humble │
|
|
139
|
+
│ cmake │ Build │ cmake │ Mapping │
|
|
140
|
+
│ eigen │ Build │ eigen │ conda-forge │
|
|
141
|
+
╰────────────────┴─────────┴─────────────────────────┴──────────────╯
|
|
142
|
+
|
|
143
|
+
Validation Summary:
|
|
144
|
+
✓ 2 workspace packages (skipped)
|
|
145
|
+
✓ 1 packages from mappings
|
|
146
|
+
✓ 5 packages from ROS humble distro
|
|
147
|
+
✓ 1 packages from conda-forge (auto-detected)
|
|
148
|
+
|
|
149
|
+
Total external dependencies: 7
|
|
150
|
+
```
|
|
105
151
|
|
|
106
152
|
Given a `package.xml` with:
|
|
107
153
|
|
|
108
154
|
```xml
|
|
109
155
|
<depend>rclcpp</depend>
|
|
110
156
|
<build_depend>ament_cmake</build_depend>
|
|
157
|
+
<build_depend>cmake</build_depend>
|
|
111
158
|
<exec_depend>std_msgs</exec_depend>
|
|
112
159
|
```
|
|
113
160
|
|
|
@@ -115,9 +162,21 @@ Given a `package.xml` with:
|
|
|
115
162
|
|
|
116
163
|
```toml
|
|
117
164
|
[dependencies]
|
|
118
|
-
|
|
119
|
-
ros-humble-
|
|
120
|
-
|
|
165
|
+
# Base ROS dependencies
|
|
166
|
+
ros-humble-ros-base = "*"
|
|
167
|
+
pkg-config = "*"
|
|
168
|
+
compilers = "*"
|
|
169
|
+
make = "*"
|
|
170
|
+
ninja = "*"
|
|
171
|
+
|
|
172
|
+
# Build tools
|
|
173
|
+
colcon-common-extensions = "*"
|
|
174
|
+
|
|
175
|
+
# Workspace dependencies
|
|
176
|
+
cmake = "*" # From mapping
|
|
177
|
+
ros-humble-ament-cmake = "*" # From ROS humble
|
|
178
|
+
ros-humble-rclcpp = "*" # From ROS humble
|
|
179
|
+
ros-humble-std-msgs = "*" # From ROS humble
|
|
121
180
|
```
|
|
122
181
|
|
|
123
182
|
### Version Constraints
|
|
@@ -155,13 +214,6 @@ eigen = ">=3.3.0,<4.0.0"
|
|
|
155
214
|
boost = "==1.2.3"
|
|
156
215
|
```
|
|
157
216
|
|
|
158
|
-
## Supported ROS Distributions
|
|
159
|
-
|
|
160
|
-
- ROS 2 Humble: https://prefix.dev/robostack-humble
|
|
161
|
-
- ROS 2 Iron: https://prefix.dev/robostack-iron
|
|
162
|
-
- ROS 2 Jazzy: https://prefix.dev/robostack-jazzy
|
|
163
|
-
- ROS 2 Rolling: https://prefix.dev/robostack-rolling
|
|
164
|
-
|
|
165
217
|
## Command Reference
|
|
166
218
|
|
|
167
219
|
### `pixi-ros init`
|
|
@@ -183,6 +235,7 @@ pixi-ros init
|
|
|
183
235
|
**What it does:**
|
|
184
236
|
- Scans workspace for `package.xml` files
|
|
185
237
|
- Reads all dependency types (build, exec, test) and version constraints
|
|
238
|
+
- **Validates dependencies** using the priority-based system (workspace → mapping → ROS distro → conda-forge)
|
|
186
239
|
- Maps ROS dependencies to conda packages for each platform
|
|
187
240
|
- Applies version constraints from package.xml to pixi.toml dependencies
|
|
188
241
|
- Configures robostack channels
|
|
@@ -190,6 +243,7 @@ pixi-ros init
|
|
|
190
243
|
- Creates build tasks using colcon
|
|
191
244
|
- Generates helpful `README_PIXI.md`
|
|
192
245
|
- Sets up platform-specific dependencies in `pixi.toml`
|
|
246
|
+
- **Displays validation results** showing where each dependency was found
|
|
193
247
|
|
|
194
248
|
**Running multiple times:**
|
|
195
249
|
The command is idempotent - you can run it multiple times to update dependencies as your workspace changes.
|
|
@@ -297,12 +351,15 @@ workspace/
|
|
|
297
351
|
|
|
298
352
|
### Package Not Found
|
|
299
353
|
|
|
300
|
-
If pixi-ros marks packages as "NOT FOUND":
|
|
354
|
+
If pixi-ros marks packages as "NOT FOUND" (shown in red in the validation output):
|
|
355
|
+
|
|
356
|
+
1. **Check the ROS distro**: Verify the package exists in robostack: https://prefix.dev/channels/robostack-{distro}
|
|
357
|
+
2. **Check for typos**: Review your `package.xml` for spelling errors
|
|
358
|
+
3. **Check conda-forge**: Some packages may be available directly on conda-forge without the `ros-distro-` prefix
|
|
359
|
+
4. **Create a mapping**: Add a custom mapping in `pixi-ros/*.yaml` if the package has a different conda name
|
|
360
|
+
5. **Add to workspace**: Consider including the package source in your workspace instead of depending on it
|
|
301
361
|
|
|
302
|
-
|
|
303
|
-
2. Check for typos in `package.xml`
|
|
304
|
-
3. Some packages may have different names - check mapping files
|
|
305
|
-
4. Consider adding the package to your workspace instead of depending on it
|
|
362
|
+
The validation table shows exactly where each dependency was checked, making it easier to diagnose issues.
|
|
306
363
|
|
|
307
364
|
### Different Package Names
|
|
308
365
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
pixi_ros/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
pixi_ros/cli.py,sha256=erbuzfPtDxE7q0iIgTGzndsT4xN8GjBxJ4x-WvoEE7A,4938
|
|
3
|
+
pixi_ros/config.py,sha256=JevtFXh96UJj7aMUWp18J1xcPeQPoLzh3hdiu5uPR0s,834
|
|
4
|
+
pixi_ros/init.py,sha256=1x1v3xcyJq2oLjA4KQinOgFPjLEtMQMFivi0cWE2ZGI,36804
|
|
5
|
+
pixi_ros/mappings.py,sha256=uTNGNEMUmTYpXeCFi6jJnqMNwoocyMc5p59UcKOH61I,10690
|
|
6
|
+
pixi_ros/package_xml.py,sha256=XnDkKuccSar1ndmvACZMZ7c2yUNXz7CcfQRwluZolqQ,8815
|
|
7
|
+
pixi_ros/utils.py,sha256=uGgB8CYiM_3KfBtqvUKqkEXXTffv8FkkaIC230peHUY,2026
|
|
8
|
+
pixi_ros/validator.py,sha256=ZMIvwHgR7-4l9r_xVMXgLGTQXgCIMKVMR7qDcnU6bLI,8714
|
|
9
|
+
pixi_ros/workspace.py,sha256=N5Aqcl77J8aLrEDr4T-XR9V5fBjZ1KQHXd4dkbgX8HU,6838
|
|
10
|
+
pixi_ros/data/README.md,sha256=Tdc2sTUuvoyEaHYlmM_C1pf3qr0o0P5Lu2ZUQ88tUjI,1602
|
|
11
|
+
pixi_ros/data/README_PIXI.md.template,sha256=q7g65oHmrEqKTtqOT7lgX6l9RI69w64B0DCLwhf8ocM,3076
|
|
12
|
+
pixi_ros/data/conda-forge.yaml,sha256=AisPkGWbr2WqpNOE3cRUMbYp10AnjaKgH0lJDwCOSJA,19003
|
|
13
|
+
pixi_ros-0.4.0.dist-info/METADATA,sha256=lPcZ0GQJEZMy8uvuiLhyhEkbAC0IVvITFT1uO92dXeE,13877
|
|
14
|
+
pixi_ros-0.4.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
15
|
+
pixi_ros-0.4.0.dist-info/entry_points.txt,sha256=DpBwU4Djcej8gT42q8Ccuv-R9pdmGHyFV5p57_ogqfQ,47
|
|
16
|
+
pixi_ros-0.4.0.dist-info/licenses/LICENSE,sha256=pAZXnNE2dxxwXFIduGyn1gpvPefJtUYOYZOi3yeGG94,1068
|
|
17
|
+
pixi_ros-0.4.0.dist-info/RECORD,,
|
pixi_ros-0.3.0.dist-info/RECORD
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
pixi_ros/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
pixi_ros/cli.py,sha256=85lRSSsnSWAxqhkwjT0OiObYdTu84YBJXO576k0fOlY,4351
|
|
3
|
-
pixi_ros/config.py,sha256=JevtFXh96UJj7aMUWp18J1xcPeQPoLzh3hdiu5uPR0s,834
|
|
4
|
-
pixi_ros/init.py,sha256=wX7VqJFuh0q3OGNZ7_BLVM3BYyTdbI7_BhzHJfJJLIw,30835
|
|
5
|
-
pixi_ros/mappings.py,sha256=AlXT_VsPV7KeEQxHkbBrnc79LXwizrCk7oG9-fYX5MI,10376
|
|
6
|
-
pixi_ros/package_xml.py,sha256=XnDkKuccSar1ndmvACZMZ7c2yUNXz7CcfQRwluZolqQ,8815
|
|
7
|
-
pixi_ros/utils.py,sha256=uGgB8CYiM_3KfBtqvUKqkEXXTffv8FkkaIC230peHUY,2026
|
|
8
|
-
pixi_ros/workspace.py,sha256=N5Aqcl77J8aLrEDr4T-XR9V5fBjZ1KQHXd4dkbgX8HU,6838
|
|
9
|
-
pixi_ros/data/README.md,sha256=Tdc2sTUuvoyEaHYlmM_C1pf3qr0o0P5Lu2ZUQ88tUjI,1602
|
|
10
|
-
pixi_ros/data/README_PIXI.md.template,sha256=q7g65oHmrEqKTtqOT7lgX6l9RI69w64B0DCLwhf8ocM,3076
|
|
11
|
-
pixi_ros/data/conda-forge.yaml,sha256=DeMfdzEuFCFXLmceV6ENmGpSBo6tMZh-Gx-ZkEAakT8,18941
|
|
12
|
-
pixi_ros-0.3.0.dist-info/METADATA,sha256=fDBOMPyY5DSt4N87s-pugMV0JVCmOOdDU76x8HyND0M,10714
|
|
13
|
-
pixi_ros-0.3.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
14
|
-
pixi_ros-0.3.0.dist-info/entry_points.txt,sha256=DpBwU4Djcej8gT42q8Ccuv-R9pdmGHyFV5p57_ogqfQ,47
|
|
15
|
-
pixi_ros-0.3.0.dist-info/licenses/LICENSE,sha256=pAZXnNE2dxxwXFIduGyn1gpvPefJtUYOYZOi3yeGG94,1068
|
|
16
|
-
pixi_ros-0.3.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|