pixi-ros 0.1.2__tar.gz → 0.2.0__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.
Files changed (50) hide show
  1. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/.github/workflows/ci.yml +2 -0
  2. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/PKG-INFO +86 -6
  3. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/README.md +85 -5
  4. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/pyproject.toml +1 -1
  5. pixi_ros-0.2.0/src/pixi_ros/cli.py +134 -0
  6. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/src/pixi_ros/init.py +273 -66
  7. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/src/pixi_ros/mappings.py +35 -0
  8. pixi_ros-0.2.0/tests/test_init.py +366 -0
  9. pixi_ros-0.1.2/src/pixi_ros/cli.py +0 -77
  10. pixi_ros-0.1.2/tests/test_init.py +0 -144
  11. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/.gitattributes +0 -0
  12. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/.github/workflows/publish-pypi.yml +0 -0
  13. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/.gitignore +0 -0
  14. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/LICENSE +0 -0
  15. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/pixi.lock +0 -0
  16. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/pixi.toml +0 -0
  17. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/src/pixi_ros/__init__.py +0 -0
  18. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/src/pixi_ros/config.py +0 -0
  19. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/src/pixi_ros/data/README.md +0 -0
  20. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/src/pixi_ros/data/README_PIXI.md.template +0 -0
  21. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/src/pixi_ros/data/conda-forge.yaml +0 -0
  22. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/src/pixi_ros/package_xml.py +0 -0
  23. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/src/pixi_ros/utils.py +0 -0
  24. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/src/pixi_ros/workspace.py +0 -0
  25. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/examples/ws1/pixi.lock +0 -0
  26. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/examples/ws1/pixi.toml +0 -0
  27. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/examples/ws1/src/package-a/CMakeLists.txt +0 -0
  28. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/examples/ws1/src/package-a/LICENSE +0 -0
  29. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/examples/ws1/src/package-a/package.xml +0 -0
  30. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/examples/ws1/src/package-b/package-b/__init__.py +0 -0
  31. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/examples/ws1/src/package-b/package.xml +0 -0
  32. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/examples/ws1/src/package-b/setup.cfg +0 -0
  33. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/examples/ws1/src/package-b/setup.py +0 -0
  34. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/examples/ws1/src/package-b/test/test_copyright.py +0 -0
  35. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/examples/ws1/src/package-b/test/test_flake8.py +0 -0
  36. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/examples/ws1/src/package-b/test/test_pep257.py +0 -0
  37. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/fixtures/mock_workspace/README.md +0 -0
  38. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/fixtures/mock_workspace/src/legacy_pkg/package.xml +0 -0
  39. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/fixtures/mock_workspace/src/my_cpp_pkg/CMakeLists.txt +0 -0
  40. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/fixtures/mock_workspace/src/my_cpp_pkg/package.xml +0 -0
  41. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/fixtures/mock_workspace/src/my_mixed_pkg/package.xml +0 -0
  42. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/fixtures/mock_workspace/src/my_python_pkg/package.xml +0 -0
  43. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/fixtures/mock_workspace/src/my_python_pkg/setup.py +0 -0
  44. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/test_cli.py +0 -0
  45. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/test_config.py +0 -0
  46. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/test_gateway_availability.py +0 -0
  47. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/test_mappings.py +0 -0
  48. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/test_package_xml.py +0 -0
  49. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/test_utils.py +0 -0
  50. {pixi_ros-0.1.2 → pixi_ros-0.2.0}/tests/test_workspace.py +0 -0
@@ -1,3 +1,5 @@
1
+ name: CI
2
+
1
3
  on:
2
4
  push:
3
5
  pull_request:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pixi-ros
3
- Version: 0.1.2
3
+ Version: 0.2.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
@@ -90,13 +90,16 @@ pixi shell
90
90
 
91
91
  ### Dependency Mapping
92
92
 
93
- `pixi-ros` reads all dependency types from `package.xml` files.
93
+ `pixi-ros` reads all dependency types from `package.xml` files.
94
94
  It then does a best effort mapping of ROS package names to conda packages.
95
95
 
96
96
  - **ROS packages**: `ros-{distro}-{package}` from robostack channels (e.g., `ros-humble-rclcpp`)
97
97
  - **System packages**: Mapped to conda-forge equivalents (e.g., `cmake`, `eigen`)
98
+ - **Platform-specific packages**: Different mappings per platform (e.g., OpenGL → `libgl-devel` on Linux, X11 packages on macOS)
98
99
 
99
- After the mapping, it validates package availability in the configured channels. This starts a connection with `https://prefix.dev` to check if packages exist.
100
+ 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
+
102
+ After the mapping, it validates package availability in the configured channels for each target platform. This starts a connection with `https://prefix.dev` to check if packages exist.
100
103
 
101
104
  ### Example
102
105
 
@@ -132,24 +135,101 @@ Initialize or update a ROS workspace's `pixi.toml`.
132
135
 
133
136
  ```bash
134
137
  pixi-ros init --distro <ros_distro>
138
+ pixi-ros init --distro humble --platform linux-64 --platform osx-arm64
135
139
  pixi-ros init
136
140
  ```
137
141
 
138
142
  **Options:**
139
- - `--distro`, `-d`: ROS distribution (optional)
143
+ - `--distro`, `-d`: ROS distribution (optional, will prompt if not provided)
144
+ - `--platform`, `-p`: Target platforms (optional, can be specified multiple times, will prompt if not provided)
145
+ - Available: `linux-64`, `osx-64`, `osx-arm64`, `win-64`
146
+ - Platforms come from the mapping files and determine which dependencies are available
140
147
 
141
148
  **What it does:**
142
149
  - Scans workspace for `package.xml` files
143
150
  - Reads all dependency types (build, exec, test)
144
- - Maps ROS dependencies to conda packages
151
+ - Maps ROS dependencies to conda packages for each platform
145
152
  - Configures robostack channels
146
- - Checks package availability
153
+ - Checks package availability per platform
147
154
  - Creates build tasks using colcon
148
155
  - Generates helpful `README_PIXI.md`
156
+ - Sets up platform-specific dependencies in `pixi.toml`
149
157
 
150
158
  **Running multiple times:**
151
159
  The command is idempotent - you can run it multiple times to update dependencies as your workspace changes.
152
160
 
161
+ ## Multi-Platform Support
162
+
163
+ `pixi-ros` supports generating cross-platform configurations. When you specify multiple platforms, it:
164
+
165
+ 1. **Analyzes dependencies per platform**: Some packages have platform-specific mappings (e.g., OpenGL requirements differ between Linux and macOS)
166
+
167
+ 2. **Organizes dependencies intelligently**:
168
+ - **Common dependencies** (available on all platforms) → `[dependencies]`
169
+ - **Unix dependencies** (available on Linux and macOS, but not Windows) → `[target.unix.dependencies]`
170
+ - **Platform-specific dependencies** → `[target.linux.dependencies]`, `[target.osx.dependencies]`, etc.
171
+
172
+ 3. **Sets up correct platform list**: The `[workspace]` section gets the appropriate pixi platform names
173
+
174
+ ### Platform Naming
175
+
176
+ pixi-ros uses standard pixi platform names:
177
+ - `linux-64` - Linux x86_64
178
+ - `osx-64` - macOS Intel
179
+ - `osx-arm64` - macOS Apple Silicon (M1/M2/M3)
180
+ - `win-64` - Windows x86_64
181
+
182
+ Internally, mapping files use a simplified format (`linux`, `osx`, `win64`), but this is transparent to users. When you specify `osx-64` and `osx-arm64`, they both use the same `osx` mapping rules since package availability is typically the same for both architectures.
183
+
184
+ ### Example: Multi-Platform Setup
185
+
186
+ ```bash
187
+ pixi-ros init --distro humble --platform linux-64 --platform osx-arm64
188
+ ```
189
+
190
+ Generates:
191
+
192
+ ```toml
193
+ [workspace]
194
+ name = "my_workspace"
195
+ channels = [
196
+ "https://prefix.dev/robostack-humble",
197
+ "https://prefix.dev/conda-forge",
198
+ ]
199
+ platforms = ["linux-64", "osx-arm64"]
200
+
201
+ [dependencies]
202
+ # Common dependencies (available on all platforms)
203
+ ros-humble-rclcpp = "*"
204
+ ros-humble-std-msgs = "*"
205
+
206
+ [target.unix.dependencies]
207
+ # Unix-specific dependencies (Linux and macOS)
208
+ xorg-libx11 = "*"
209
+ xorg-libxext = "*"
210
+
211
+ [target.linux.dependencies]
212
+ # Linux-specific dependencies
213
+ libgl-devel = "*"
214
+ libopengl-devel = "*"
215
+ ```
216
+
217
+ ### Interactive Platform Selection
218
+
219
+ If you don't specify platforms, you'll be prompted:
220
+
221
+ ```bash
222
+ $ pixi-ros init --distro humble
223
+
224
+ Available target platforms:
225
+ 1. linux-64
226
+ 2. osx-64
227
+ 3. osx-arm64
228
+ 4. win-64
229
+
230
+ Select platforms (enter numbers or names, comma or space separated): 1 3
231
+ ```
232
+
153
233
  ## Philosophy
154
234
 
155
235
  `pixi-ros` aims to be a quick **gateway drug**. It:
@@ -71,13 +71,16 @@ pixi shell
71
71
 
72
72
  ### Dependency Mapping
73
73
 
74
- `pixi-ros` reads all dependency types from `package.xml` files.
74
+ `pixi-ros` reads all dependency types from `package.xml` files.
75
75
  It then does a best effort mapping of ROS package names to conda packages.
76
76
 
77
77
  - **ROS packages**: `ros-{distro}-{package}` from robostack channels (e.g., `ros-humble-rclcpp`)
78
78
  - **System packages**: Mapped to conda-forge equivalents (e.g., `cmake`, `eigen`)
79
+ - **Platform-specific packages**: Different mappings per platform (e.g., OpenGL → `libgl-devel` on Linux, X11 packages on macOS)
79
80
 
80
- After the mapping, it validates package availability in the configured channels. This starts a connection with `https://prefix.dev` to check if packages exist.
81
+ 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`.
82
+
83
+ After the mapping, it validates package availability in the configured channels for each target platform. This starts a connection with `https://prefix.dev` to check if packages exist.
81
84
 
82
85
  ### Example
83
86
 
@@ -113,24 +116,101 @@ Initialize or update a ROS workspace's `pixi.toml`.
113
116
 
114
117
  ```bash
115
118
  pixi-ros init --distro <ros_distro>
119
+ pixi-ros init --distro humble --platform linux-64 --platform osx-arm64
116
120
  pixi-ros init
117
121
  ```
118
122
 
119
123
  **Options:**
120
- - `--distro`, `-d`: ROS distribution (optional)
124
+ - `--distro`, `-d`: ROS distribution (optional, will prompt if not provided)
125
+ - `--platform`, `-p`: Target platforms (optional, can be specified multiple times, will prompt if not provided)
126
+ - Available: `linux-64`, `osx-64`, `osx-arm64`, `win-64`
127
+ - Platforms come from the mapping files and determine which dependencies are available
121
128
 
122
129
  **What it does:**
123
130
  - Scans workspace for `package.xml` files
124
131
  - Reads all dependency types (build, exec, test)
125
- - Maps ROS dependencies to conda packages
132
+ - Maps ROS dependencies to conda packages for each platform
126
133
  - Configures robostack channels
127
- - Checks package availability
134
+ - Checks package availability per platform
128
135
  - Creates build tasks using colcon
129
136
  - Generates helpful `README_PIXI.md`
137
+ - Sets up platform-specific dependencies in `pixi.toml`
130
138
 
131
139
  **Running multiple times:**
132
140
  The command is idempotent - you can run it multiple times to update dependencies as your workspace changes.
133
141
 
142
+ ## Multi-Platform Support
143
+
144
+ `pixi-ros` supports generating cross-platform configurations. When you specify multiple platforms, it:
145
+
146
+ 1. **Analyzes dependencies per platform**: Some packages have platform-specific mappings (e.g., OpenGL requirements differ between Linux and macOS)
147
+
148
+ 2. **Organizes dependencies intelligently**:
149
+ - **Common dependencies** (available on all platforms) → `[dependencies]`
150
+ - **Unix dependencies** (available on Linux and macOS, but not Windows) → `[target.unix.dependencies]`
151
+ - **Platform-specific dependencies** → `[target.linux.dependencies]`, `[target.osx.dependencies]`, etc.
152
+
153
+ 3. **Sets up correct platform list**: The `[workspace]` section gets the appropriate pixi platform names
154
+
155
+ ### Platform Naming
156
+
157
+ pixi-ros uses standard pixi platform names:
158
+ - `linux-64` - Linux x86_64
159
+ - `osx-64` - macOS Intel
160
+ - `osx-arm64` - macOS Apple Silicon (M1/M2/M3)
161
+ - `win-64` - Windows x86_64
162
+
163
+ Internally, mapping files use a simplified format (`linux`, `osx`, `win64`), but this is transparent to users. When you specify `osx-64` and `osx-arm64`, they both use the same `osx` mapping rules since package availability is typically the same for both architectures.
164
+
165
+ ### Example: Multi-Platform Setup
166
+
167
+ ```bash
168
+ pixi-ros init --distro humble --platform linux-64 --platform osx-arm64
169
+ ```
170
+
171
+ Generates:
172
+
173
+ ```toml
174
+ [workspace]
175
+ name = "my_workspace"
176
+ channels = [
177
+ "https://prefix.dev/robostack-humble",
178
+ "https://prefix.dev/conda-forge",
179
+ ]
180
+ platforms = ["linux-64", "osx-arm64"]
181
+
182
+ [dependencies]
183
+ # Common dependencies (available on all platforms)
184
+ ros-humble-rclcpp = "*"
185
+ ros-humble-std-msgs = "*"
186
+
187
+ [target.unix.dependencies]
188
+ # Unix-specific dependencies (Linux and macOS)
189
+ xorg-libx11 = "*"
190
+ xorg-libxext = "*"
191
+
192
+ [target.linux.dependencies]
193
+ # Linux-specific dependencies
194
+ libgl-devel = "*"
195
+ libopengl-devel = "*"
196
+ ```
197
+
198
+ ### Interactive Platform Selection
199
+
200
+ If you don't specify platforms, you'll be prompted:
201
+
202
+ ```bash
203
+ $ pixi-ros init --distro humble
204
+
205
+ Available target platforms:
206
+ 1. linux-64
207
+ 2. osx-64
208
+ 3. osx-arm64
209
+ 4. win-64
210
+
211
+ Select platforms (enter numbers or names, comma or space separated): 1 3
212
+ ```
213
+
134
214
  ## Philosophy
135
215
 
136
216
  `pixi-ros` aims to be a quick **gateway drug**. It:
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pixi-ros"
7
- version = "0.1.2"
7
+ version = "0.2.0"
8
8
  description = "Pixi extension for ROS package management"
9
9
  authors = [
10
10
  { name = "Ruben Arts", email = "ruben@prefix.dev" }
@@ -0,0 +1,134 @@
1
+ """Main CLI entry point for pixi-ros."""
2
+
3
+ from typing import Annotated
4
+
5
+ import typer
6
+
7
+ from pixi_ros.init import init_workspace
8
+ from pixi_ros.mappings import get_platforms, get_ros_distros
9
+
10
+ app = typer.Typer(
11
+ name="pixi-ros",
12
+ help="Pixi extension for ROS package management",
13
+ no_args_is_help=True,
14
+ )
15
+
16
+ pkg_app = typer.Typer(help="Manage ROS packages")
17
+ app.add_typer(pkg_app, name="pkg")
18
+
19
+
20
+ @app.command()
21
+ def init(
22
+ distro: Annotated[
23
+ str | None,
24
+ typer.Option(
25
+ "--distro",
26
+ "-d",
27
+ help="ROS distribution (e.g., humble, iron, jazzy)",
28
+ ),
29
+ ] = None,
30
+ platforms: Annotated[
31
+ list[str] | None,
32
+ typer.Option(
33
+ "--platform",
34
+ "-p",
35
+ help="Target platforms (e.g., linux-64, osx-arm64, win-64). Can be specified multiple times.",
36
+ ),
37
+ ] = None,
38
+ ):
39
+ """Initialize pixi.toml for a ROS workspace."""
40
+ # If distro not provided, prompt user to select one
41
+ if distro is None:
42
+ available_distros = get_ros_distros()
43
+ typer.echo("Available ROS distributions:")
44
+ for i, d in enumerate(available_distros, 1):
45
+ typer.echo(f" {i}. {d}")
46
+
47
+ # Prompt for selection
48
+ selection = typer.prompt(
49
+ "\nSelect a distribution (enter number or name)",
50
+ type=str,
51
+ )
52
+
53
+ # Parse selection (either number or name)
54
+ try:
55
+ selection_num = int(selection)
56
+ dist_count = len(available_distros)
57
+ if 1 <= selection_num <= dist_count:
58
+ distro = available_distros[selection_num - 1]
59
+ else:
60
+ typer.echo(
61
+ f"Error: Invalid selection. Please choose 1-{dist_count}",
62
+ err=True,
63
+ )
64
+ raise typer.Exit(code=1)
65
+ except ValueError as err:
66
+ # User entered a name instead of number
67
+ if selection in available_distros:
68
+ distro = selection
69
+ else:
70
+ typer.echo(
71
+ f"Error: '{selection}' is not a valid ROS distribution", err=True
72
+ )
73
+ typer.echo(f"Available: {', '.join(available_distros)}", err=True)
74
+ raise typer.Exit(code=1) from err
75
+
76
+ # If platforms not provided, prompt user to select
77
+ if platforms is None or len(platforms) == 0:
78
+ available_platforms = get_platforms()
79
+ typer.echo("\nAvailable target platforms:")
80
+ for i, p in enumerate(available_platforms, 1):
81
+ typer.echo(f" {i}. {p}")
82
+
83
+ # Prompt for selection (can be comma-separated or space-separated)
84
+ selection = typer.prompt(
85
+ "\nSelect platforms (enter numbers or names, comma or space separated)",
86
+ type=str,
87
+ )
88
+
89
+ # Parse selection (can be numbers or names, comma or space separated)
90
+ platforms = []
91
+ # Split by comma or space
92
+ selections = selection.replace(",", " ").split()
93
+
94
+ for sel in selections:
95
+ sel = sel.strip()
96
+ if not sel:
97
+ continue
98
+
99
+ try:
100
+ # Try parsing as number
101
+ sel_num = int(sel)
102
+ if 1 <= sel_num <= len(available_platforms):
103
+ platforms.append(available_platforms[sel_num - 1])
104
+ else:
105
+ typer.echo(
106
+ f"Error: Invalid selection {sel_num}. Please choose 1-{len(available_platforms)}",
107
+ err=True,
108
+ )
109
+ raise typer.Exit(code=1)
110
+ except ValueError:
111
+ # User entered a name instead of number
112
+ if sel in available_platforms:
113
+ platforms.append(sel)
114
+ else:
115
+ typer.echo(
116
+ f"Error: '{sel}' is not a valid platform", err=True
117
+ )
118
+ typer.echo(f"Available: {', '.join(available_platforms)}", err=True)
119
+ raise typer.Exit(code=1)
120
+
121
+ if not platforms:
122
+ typer.echo("Error: No platforms selected", err=True)
123
+ raise typer.Exit(code=1)
124
+
125
+ init_workspace(distro, platforms=platforms)
126
+
127
+
128
+ def main():
129
+ """Entry point for the CLI."""
130
+ app()
131
+
132
+
133
+ if __name__ == "__main__":
134
+ main()