feat: oxidize the emitter
Metadata
Current evaluation
Merged #411 reimplemented Craft CLI's emitter in Rust with PyO3/Maturin, removed global emit, and switched the build backend.
Resolution: closed resolved
Reason: canonical/craft-cli#411 was merged, completing the Rust emitter implementation and its associated packaging changes.
Evaluated by: mr-cal-bot
No scores available.
Issue body
- [ ] Have you followed the guidelines for contributing?
- [ ] Have you signed the [CLA](http://www.ubuntu.com/legal/contributors/)?
- [ ] Have you successfully run `make lint && make test`?
---
Oxidizes the emitter class. The [PyO3 docs](https://pyo3.rs/v0.27.2/index.html) and [Maturin docs](https://www.maturin.rs/) may help with reviewing. So far, the only intended breaking change is the removal of the global `emit`. Rust, reasonably so, does not play nicely with globally mutable state or partially initialized variables. If anything else is breaking, it's either because it's not yet implemented or I didn't mean to break it, so definitely ask if you spot anything!
Remaining work:
- Streaming brief
- `Emitter.open_stream`
- External log handling (from `logging`)
- Devise testing strategy
- Incremental progress bars
- Fix project versioning (see below)
Overall structure
---
In order to build with Maturin, the build backend just needed to be switched. This was mostly simple, but Maturin has an unfortunate limitation in that it completely lacks anything like `tool.setuptools_scm` for configuring tag-based dynamic versioning. This can be _mostly_ achieved via environment variables, but for local development builds with uv (`maturin develop --uv`), a version _must_ be present in `pyproject.toml`. For now, the version is hard-coded to `0.0.0+dev`.
The field in `pyproject` setting the module name just makes the compiled `.so` appear with that import path. Otherwise, it would overwrite the Python portion of Craft CLI. This new submodule was named `_rs`.
To test what has been done so far, clone this, update your venv, and then run `uv run maturin develop --uv`. This builds to a `.so`, then installs it as an editable wheel.
Comments will be made on code in this PR for any other higher level design choices.
CRAFT-4970
Evaluation history
| Date | Model | Scores | Action | Summary |
|---|---|---|---|---|
| stealth/space-bunny-alpha | — | closed resolved | Merged #411 reimplemented Craft CLI's emitter in Rust with PyO3/Maturin, removed global emit, and switched the build backend. | |
| stealth/space-bunny-alpha | — | closed resolved | Merged #411: replaced the Python emitter with a Rust extension using PyO3/Maturin, removed global emit, and switched the build backend. | |
| qwen/qwen3.6-35b-a3b | — | — | Merged. The emitter class was oxidized to Rust using PyO3 and Maturin, removing the global emit function. The PR updated the build backend, required Rust 1.80+, and was merged after addressing CI failures and review feedback. |
Update history
No update history recorded yet.
Related issues
| Issue | Project | State | Summary | Similarity |
|---|---|---|---|---|
| #416 feat: oxidize open_stream | craft-cli | merged | Merged PR #416 restored Rust-backed Emitter.open_stream(), refactoring Printer to static state and adding Emitter.init_logger(). It built on prerequisite emitter oxidation in #411. | |
| #419 feat: oxidize streaming_brief feature | craft-cli | merged | Merged in canonical/craft-cli#419, restoring streaming_brief output and prefixing messages piped through Emitter.open_stream. | |
| #432 feat: rust error emitting | craft-cli | merged | Merged in canonical/craft-cli#432, restoring error() and report_error() to the Rust Emitter. |