Skip to content

feat: add tool-specific config extension and default config discovery#2636

Merged
wolfv merged 6 commits into
mainfrom
claude/rattler-shared-config-design-m8d2gb
Jul 10, 2026
Merged

feat: add tool-specific config extension and default config discovery#2636
wolfv merged 6 commits into
mainfrom
claude/rattler-shared-config-design-m8d2gb

Conversation

@wolfv

@wolfv wolfv commented Jul 5, 2026

Copy link
Copy Markdown
Member

Description

Part of the effort to make rattler, rattler-build and pixi share one configuration (see conda/rattler#2557, now released as rattler_config 0.6.0). rattler-build already consumed rattler_config, but only as ConfigBase<()> (no extension point) and only when --config-file was passed explicitly — without it, no configuration was loaded at all.

Two changes, plus a dependency bump:

  1. Tool-specific extension point. New src/config.rs defines RattlerBuildConfig — an (empty for now) extension struct implementing the rattler_config::config::Config trait (in 0.6 that's just merge_config) — and the alias Config = ConfigBase<RattlerBuildConfig>, used everywhere ConfigBase<()> was (opt.rs, main.rs, debug.rs, Python bindings). Future rattler-build-only configuration keys go into this struct; all shared keys (default channels, mirrors, S3 options, concurrency, …) keep coming from rattler_config.

  2. Default config discovery via the shared locations helper. When --config-file is not given, rattler-build now discovers and merges configuration from the standard locations (only files that exist, later overriding earlier) using rattler_config::locations::config_search_paths(&["pixi", "rattler-build"]) — the shared discovery shipped in 0.6. This replaces ~80 lines of hand-rolled path logic that previously duplicated pixi's. Precedence (lowest first): all system-wide files (/etc/pixi/config.toml, /etc/rattler-build/config.toml; C:\ProgramData\… on Windows), then all per-user files (platform config dir, then $PIXI_HOME/$RATTLER_BUILD_HOME or ~/.pixi / ~/.rattler-build) — pixi first, then rattler-build, so a user's existing pixi config (mirrors, S3, channels) applies out of the box and rattler-build's own config wins. --config-file still bypasses discovery entirely (loads only that file), and when no file exists the loader returns "no config" exactly as before.

    Note: this newly searches a system-wide /etc/rattler-build/config.toml, and the ordering is now system-before-user across both tools (previously it was all-pixi-then-all-rattler-build) — a deliberate consequence of using the shared helper.

Dependency bump

All rattler crates bumped to the released set that includes rattler_config 0.6: rattler 0.46→0.47, rattler_conda_types 0.47→0.48, rattler_config 0.5.2→0.6, rattler_repodata_gateway 0.29→0.30, and the rest (cache, index, menuinst, networking, package_streaming, shell, solve, upload, virtual_packages) to their current releases. Non-config fallout from the bump, all behavior-preserving:

  • Gateway::query now returns RepoDataQueryOutput (repodata_gateway 0.30) — solver.rs reads result.repodata.
  • Shared ConfigBase keys moved behind .common (Deref) — one access in the Python bindings adjusted.
  • Channel::from_directory was deprecated in conda_types 0.48 — 3 call sites migrated to try_from_directory(..), preserving the prior panic-on-invalid-path behavior.

cargo tree confirms a single rattler_conda_types 0.48.0 and rattler_config 0.6.0, both from crates.io. docs/config.md and the CLI reference were updated.

This PR unblocks pixi. pixi (prefix-dev/pixi#6531) consumes rattler_build_core as a library and currently can't move to the released rattler 0.6 line because the published rattler_build_core (0.2.8) still pins rattler 0.46 / rattler_config 0.5.2. Merging and publishing a rattler_build_core release built on this branch is what lets pixi drop its temporary git patch and switch to the crates.io versions.

Testing

  • cargo check --workspace --all-targets clean (zero warnings); cargo check -p py-rattler-build clean.
  • Config module tests pass (cargo test -p rattler-build --lib), including the discovery/ordering tests (rewritten to assert per-group precedence via the shared locations helpers, using temp dirs / env overrides, not the real home dir).
  • cargo fmt --check and cargo clippy (-D warnings) clean on both workspaces.

AI Disclosure

  • This PR contains AI-generated content.
    • I have tested any AI-generated content in my PR.
    • I take responsibility for any AI-generated content in my PR.

Tools: Claude Code

🤖 Generated with Claude Code

https://claude.ai/code/session_01EzYs4p6XJDj9QBcNB4ipR7

rattler-build now actually shares configuration with pixi and the other
rattler based tools instead of only reading a file when --config-file is
passed explicitly:

- Introduce a new `config` module with `RattlerBuildConfig`, an (empty for
  now) extension struct implementing `rattler_config::config::Config`, and
  the alias `Config = ConfigBase<RattlerBuildConfig>`. This is the extension
  point for configuration keys that only make sense for rattler-build, while
  all shared keys (default channels, mirrors, S3 options, ...) keep coming
  from `rattler_config`'s `ConfigBase`. All previous uses of
  `ConfigBase<()>` (opt.rs, main.rs, debug.rs and the Python bindings) now
  use this alias.

- When no --config-file is given, discover and merge configuration from the
  standard locations (only files that exist), later files overriding
  earlier ones:
    1. system-wide pixi config: /etc/pixi/config.toml
       (Windows: C:\ProgramData\pixi\config.toml)
    2. pixi's global config: $XDG_CONFIG_HOME/pixi/config.toml (or the
       platform config dir) and $PIXI_HOME/config.toml (~/.pixi/config.toml)
    3. rattler-build's own config: $XDG_CONFIG_HOME/rattler-build/config.toml
       and $RATTLER_BUILD_HOME/config.toml (~/.rattler-build/config.toml)
  The path logic mirrors pixi's `config_path_system`/`config_path_global`
  so settings configured for pixi are picked up automatically, and can be
  overridden by rattler-build specific files. Passing --config-file keeps
  today's behavior of loading only the given file.

Prompt: make rattler-build share configuration with pixi and rattler, add a
tool-specific extension type for rattler-build-only keys, and load config
from the standard pixi/rattler-build locations when no --config-file is
given.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EzYs4p6XJDj9QBcNB4ipR7
The rattler crates are now published to crates.io, so switch from the
pre-release versions to the released ones and adapt to the redesigned
rattler_config 0.6 API.

Version bumps (workspace + py-rattler-build):
- rattler 0.46 -> 0.47
- rattler_cache 0.10.0 -> 0.10.2
- rattler_conda_types 0.47.2 -> 0.48
- rattler_config 0.5.2 -> 0.6
- rattler_index 0.30.5 -> 0.30.8
- rattler_menuinst 0.2.67 -> 0.2.69
- rattler_networking 0.30.0 -> 0.30.1
- rattler_package_streaming 0.26.5 -> 0.26.7
- rattler_repodata_gateway 0.29.6 -> 0.30
- rattler_shell 0.27.7 -> 0.27.9
- rattler_solve 7.1.4 -> 7.2
- rattler_upload 0.8.0 -> 0.8.3
- rattler_virtual_packages 3.0.2 -> 3.0.3

rattler_config 0.6 API adaptation (src/config.rs):
- The `Config` trait now has a single required method `merge_config`;
  `get_extension_name` was removed and `validate`/`keys`/`is_default`
  gained default impls, so `RattlerBuildConfig` only implements
  `merge_config`.
- Replace the hand-rolled ~80 lines of config-path discovery with a thin
  wrapper over the new shared `rattler_config::locations::config_search_paths`
  helper (`&["pixi", "rattler-build"]`). Discovery now also searches
  `/etc/rattler-build/config.toml`. Precedence, lowest first: all
  system-wide files, then all per-user files; within each group
  rattler-build overrides pixi. `load_default_config` still returns
  `Ok(None)` when no file exists. Unit tests and docs updated to match.

Fallout from the conda_types 0.48 / repodata_gateway 0.30 bumps:
- `Gateway::query` now returns `RepoDataQueryOutput` (records plus
  non-fatal warnings); take its `.repodata` field.
- `ConfigBase` now stores the shared keys behind a `common` field
  (accessed via `Deref`); move `channel_config` out of `config.common`.
- Migrate the deprecated `Channel::from_directory` call sites to
  `Channel::try_from_directory(..).expect(..)`, preserving the previous
  panic-on-invalid-path behavior.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EzYs4p6XJDj9QBcNB4ipR7
@wolfv wolfv force-pushed the claude/rattler-shared-config-design-m8d2gb branch from 79f6af4 to a7c3da2 Compare July 10, 2026 05:40
claude added 2 commits July 10, 2026 06:17
Two CI fixes after the rattler 0.47 bump:
- cargo-fmt: reflow the Channel::try_from_directory call in
  rattler_build_core/src/types/mod.rs to rustfmt's preferred layout.
- generate-cli-docs: rattler 0.47 renamed `auth status --verbose` to
  `--details` (conda/rattler#2551); regenerate the CLI reference to match.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EzYs4p6XJDj9QBcNB4ipR7
Make configuration resolution traceable and pin down the loading contract:

- On startup the CLI now logs `rattler-build <version>` and the exact
  config files it loaded ("Loaded configuration from: …", or "No
  configuration file loaded"), at the default log level. `-v` additionally
  logs the full candidate search path so users can see why a file was or
  wasn't picked up.
- Document (module docs + docs/config.md) that automatic discovery happens
  ONLY in the CLI. Programmatic/library consumers (pixi via
  rattler_build_core, the Python bindings) never load config implicitly —
  they construct and pass their own Config. `load_default_config` is the
  CLI-only discovery entry point and is not called by any library path.
- Document the behavior change (discovery when no --config-file is given)
  and the new search locations in docs/config.md.

No functional change to library code paths; verified rattler_build_core
does no config-from-disk loading and the Python bindings use Config::default().

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EzYs4p6XJDj9QBcNB4ipR7
@wolfv wolfv marked this pull request as ready for review July 10, 2026 08:57
.unwrap();

Ok(result)
// `query` now returns a `RepoDataQueryOutput` (records plus non-fatal

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we emit the warnings here? Or elsewhere? That would be a nice improvement.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it would be good to add them for sure! Now they are silently dropped.

@wolfv wolfv left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, some comments

Comment thread docs/config.md

Alternatively, a single configuration file can be specified explicitly with `--config-file` (e.g. `--config-file ~/.pixi/config.toml`), which disables the automatic discovery and loads only that file.

!!! note "Behavior change"

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add a mode in which rattler-build doesn't load any configuration so users can preserve the old behavior?

Comment thread Cargo.toml
Comment on lines +138 to 169
rattler_conda_types = { version = "0.48", default-features = false }
rattler_digest = { version = "1.3.1", default-features = false, features = [
"serde",
] }
rattler_networking = { version = "0.30.0", default-features = false }
rattler_package_streaming = { version = "0.26.5", default-features = false }
rattler_shell = { version = "0.27.7", default-features = false, features = [
rattler_networking = { version = "0.30.1", default-features = false }
rattler_package_streaming = { version = "0.26.7", default-features = false }
rattler_shell = { version = "0.27.9", default-features = false, features = [
"sysinfo",
] }
rattler_git = { version = "0.1.3" }
rattler_prefix_guard = { version = "0.1.1" }

rattler_config = { version = "0.5.2" }
rattler = { version = "0.46.0", default-features = false, features = [
rattler_config = { version = "0.6" }
rattler = { version = "0.47", default-features = false, features = [
"cli-tools",
"indicatif",
] }
rattler_cache = { version = "0.10.0", default-features = false }
rattler_index = { version = "0.30.5", default-features = false }
rattler_upload = { version = "0.8.0", default-features = false }
rattler_cache = { version = "0.10.2", default-features = false }
rattler_index = { version = "0.30.8", default-features = false }
rattler_upload = { version = "0.8.3", default-features = false }
rattler_s3 = { version = "0.2.5" }
rattler_redaction = { version = "0.2.1", default-features = false }
rattler_repodata_gateway = { version = "0.29.6", default-features = false, features = [
rattler_repodata_gateway = { version = "0.30", default-features = false, features = [
"gateway",
] }
rattler_solve = { version = "7.1.4", default-features = false, features = [
rattler_solve = { version = "7.2", default-features = false, features = [
"resolvo",
"serde",
] }
rattler_virtual_packages = { version = "3.0.2", default-features = false }
rattler_menuinst = "0.2.67"
rattler_virtual_packages = { version = "3.0.3", default-features = false }
rattler_menuinst = "0.2.69"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be better to only bump minor patches and leave patch bumps in the lockfile only.

claude added 2 commits July 10, 2026 09:15
Addresses review feedback on #2636:

- Emit non-fatal gateway warnings instead of silently dropping them.
  `Gateway::query` returns a `RepoDataQueryOutput` whose `warnings` were
  discarded at both call sites; now logged via `tracing::warn!` in
  render/solver.rs and publish.rs.
- Add a `--no-config` flag that disables all configuration loading and
  discovery (built-in defaults + CLI args only), restoring the pre-discovery
  behavior. Mutually exclusive with `--config-file`. Documented in
  docs/config.md and the regenerated CLI reference.
- Cargo.toml: express rattler dependency requirements at minor level
  (e.g. 0.30 rather than 0.30.1); the exact patch versions stay pinned in
  Cargo.lock only. No lockfile version changes.
- Remove an unused `dirs` dependency (workspace + rattler-build crate) left
  over from an earlier config-discovery iteration; discovery is handled
  entirely by rattler_config's locations helper.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EzYs4p6XJDj9QBcNB4ipR7
The Python bindings are a separate cargo workspace with their own
Cargo.lock. Removing the unused `dirs` dependency from the rattler-build
crate left that lockfile carrying a stale `dirs` edge, which the pre-commit
`git diff --exit-code` check flagged. Regenerate it (drops only the edge;
no version changes).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EzYs4p6XJDj9QBcNB4ipR7
@wolfv wolfv merged commit 1e69a76 into main Jul 10, 2026
15 checks passed
@wolfv wolfv deleted the claude/rattler-shared-config-design-m8d2gb branch July 10, 2026 09:50
wolfv pushed a commit to prefix-dev/pixi that referenced this pull request Jul 10, 2026
Now that rattler-build's config PR (prefix-dev/rattler-build#2636) is merged,
align pixi's rattler/rattler-build sources so the shared rattler_config /
rattler_conda_types types unify:

- Drop the conda/rattler [patch.crates-io] block. It pinned the pre-release
  rattler_config 0.5.2 / rattler 0.46 branch, which conflicts with
  rattler-build main (built against the released rattler_config 0.6 /
  rattler 0.47). rattler_config 0.6 is now released, so the patch is obsolete.
- Bump rattler requirements to the released set: rattler 0.47,
  rattler_conda_types 0.48, rattler_config 0.6, rattler_repodata_gateway 0.30.
- Patch all rattler-build crates in the tree to prefix-dev/rattler-build main
  (the merged config update); the crates.io rattler_build_core 0.2.8 still
  pins the old rattler 0.46 and is unusable until a new release is published.

Lockfile re-resolved: a single copy of each shared crate from crates.io,
rattler-build crates from git main, no leftover conda/rattler refs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EzYs4p6XJDj9QBcNB4ipR7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants