Skip to content

feat(config): add exclude-newer - #7385

Merged
lucascolley merged 62 commits into
mainfrom
default-exclude-newer
Nov 2, 2026
Merged

lucascolley merged 62 commits into
mainfrom
default-exclude-newer

Conversation

@pavelzw

@pavelzw pavelzw commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

Description

Stacked on #7384.

Fixes #5810.

Adds exclude-newer to the pixi configuration, with the same shape as exclude-newer in a manifest:

# config.toml
exclude-newer = "7d"
# or
exclude-newer = { cutoff = "7d", exemptions = { ruff = "*" } }

As settled in #5810, it is the starting point for new manifests and for pixi exec, and never applies implicitly to an existing workspace, so a lock file doesn't depend on the configuration of whoever runs pixi:

  • pixi init writes it into the exclude-newer of the new workspace (pixi.toml, pyproject.toml and from an environment file). The cutoff is written as configured, e.g. 7d.
  • pixi global writes it into the exclude-newer of a new, empty global manifest. A global manifest created from an existing installation doesn't get it, as those environments were installed without a cutoff.
  • pixi exec solves its environments with it. The cached exec environment is keyed by the configured value (a relative cutoff stays 7d, like in fix: reuse the build backend environment with a relative exclude-newer #7384), and only when it is set, so existing exec environments keep their names.

The key is part of the configuration shared by all rattler-based tools (conda/rattler#3020), so it can also be set in a rattler config file and rattler-build can use it as well. rattler_config keeps the cutoff and exemptions as written; pixi parses them with the manifest's own exclude-newer parser via the new ExcludeNewerConfig::from_toml_value, so they have the same syntax and errors.

Note

The rattler crates point to the commit of conda/rattler#3020 on a fork for now. This will be replaced with the released version of rattler_config before merging. pixi config set exclude-newer 7d sets a cutoff, and a table is given as JSON like the other complex config values.

Per-channel cutoffs for default-channels (the other idea in #5810) are not part of this, as default-channels only takes channel names.

How Has This Been Tested?

  • Unit tests for parsing both forms from the config and for pixi config set/unset.
  • Unit test that the exec environment hash depends on the configured value.
  • Integration tests: pixi init writes the configured cutoff and exemptions; pixi exec fails with a cutoff before every package of the test channel and succeeds once the package is exempted; pixi global install writes the default into the new global manifest and applies the cutoff to packages that are not exempted.

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

Checklist:

  • I have performed a self-review of my own code
  • I have made corresponding changes to the documentation
  • I have added sufficient tests to cover my changes.
  • I have verified that changes that would impact the JSON schema have been made in schema/model.py.

Comment thread docs/reference/pixi_configuration.md Resolved
@pavelzw
pavelzw marked this pull request as ready for review October 28, 2026 01:55
@pavelzw
pavelzw requested a review from lucascolley October 28, 2026 01:56
@wolfv

wolfv commented Oct 28, 2026

Copy link
Copy Markdown
Member

Shouldn't or couldn't this go to the rattler configuration so that we can use it in rattler-build as well?

@pavelzw

pavelzw commented Oct 28, 2026

Copy link
Copy Markdown
Collaborator Author

yes you are right. was too late for me yesterday night i guess...

@pavelzw

pavelzw commented Oct 28, 2026

Copy link
Copy Markdown
Collaborator Author

conda/rattler#3020

@pavelzw pavelzw changed the title feat: add default-exclude-newer to the pixi configuration feat: add exclude-newer to the pixi configuration Oct 28, 2026
@pavelzw
pavelzw force-pushed the default-exclude-newer branch 2 times, most recently from 4ddbda6 to 4335319 Compare October 28, 2026 14:26
@lucascolley
lucascolley force-pushed the default-exclude-newer branch from 4335319 to fae97ce Compare October 28, 2026 14:58
Base automatically changed from backend-env-relative-exclude-newer to main October 28, 2026 15:38
`pixi init` on a `pyproject.toml` that already has a pixi table prints
"Nothing to do here", but it still writes the configured `exclude-newer`
into it, overwriting the workspace's own cutoff and making its lock
file stale. This documents the problem where it happens, and adds a
test that fails until it is fixed.
An invalid `exclude-newer` in the configuration only failed after
`pixi init` had written the manifest. The workspace was left without a
cutoff, and re-running `pixi init` failed because the manifest already
existed. The value is now parsed before anything is written.
`pixi global` created an empty manifest before parsing the configured
`exclude-newer`. If parsing failed, the empty manifest was left behind,
and once the configuration was fixed it was treated as existing, so the
cutoff never got written. The new manifest is now built in memory and
only written once the value has been parsed.
@pavelzw

pavelzw commented Oct 30, 2026

Copy link
Copy Markdown
Collaborator Author

depends on prefix-dev/rattler-build#2914

@lucascolley

Copy link
Copy Markdown
Member

I found a few more things that we might want to change in rattler, so no rush on that release... nothing hugely blocking but seems like we would still have some workarounds on the Pixi side

A configured exemption that combines a package archive `url` with
fields such as `version` is accepted by `rattler_config`, but pixi's
manifest rejects it, so `pixi init` and `pixi global` write a manifest
that doesn't parse. Rejecting it belongs in `rattler_config`, where it
would apply whenever the configuration loads, rather than in pixi's
conversion only.
`pixi config unset` falls back to an empty configuration when the file
doesn't load, so it can remove an invalid value. For a key inside
`exclude-newer`, the empty value was then written back over the whole
`exclude-newer`, silently dropping its cutoff and every other
exemption. This is the very command the parse error suggests for
repairing the file.

When the file doesn't load, such a key is now removed from the document
like any other key.
Unsetting a key inside `exclude-newer` that isn't there, such as an
exemption of a package that isn't exempted, succeeded and printed
"Updated config". It now fails like unsetting any other missing key.
The `exclude-newer` part of the name of a cached `pixi exec`
environment was hashed with `DefaultHasher`, whose algorithm can change
between Rust releases. A toolchain update could then rename every
cached environment and solve again, picking up newer packages for a
relative cutoff. The configured value is now hashed with xxh3 like the
rest of the name.
`pixi init --script` ignored the `exclude-newer` of the configuration,
although a script's workspace accepts one. A new PEP 723 or
conda-script block now gets it under `[tool.pixi.workspace]`, like a
new workspace does.

The configuration is loaded from the script's directory, as when the
script is run, and checked against the manifest before anything is
written.
Comment thread crates/pixi_cli/src/config.rs Resolved
pavelzw and others added 7 commits November 2, 2026 11:00
The pinned rattler adds conda/rattler#3082 on top of the previous rev:
`rattler_config` now rejects an exemption that combines a `url` with
fields other than `md5` and `sha256`, so a configuration that pixi
writes into a manifest as a url spec can no longer lose fields.
`pixi config set/unset exclude-newer.*` wrote back the whole value,
dropping the comments and layout inside it, e.g. turning a
`[exclude-newer.exemptions]` table into an inline table. Only the
edited key is now written, with `write_exclude_newer_edit` of
`rattler_config`. An exemption keeps its name as written in the file
when it is edited under a differently cased name.
The pinned rattler moves to bf11b568b3 of conda/rattler#3082, which
does the whole `exclude-newer` edit in `set_exclude_newer` and
`set_exclude_newer_in_document`. That replaces the throwaway
`ConfigBase` in `Config::set` and the before/after comparison in
`pixi config`, and nothing is written when an edit changes nothing.

Removing the last exemption now keeps a `[exclude-newer]` table and
its comments, which the layout test covers. A `url` exemption with
other fields fails with rattler's shorter message.

The branch is based on a newer rattler release, so `rattler_cache`,
`rattler_config`, `rattler_repodata_gateway` and
`rattler_virtual_package_detectors` move to their next versions, along
with the `rattler_build_*` crates that require them.
`rattler_config` accepts an exclude-newer exemption such as
`{ url = "…/libbaz-1-0.conda", flags = [] }`, as empty `flags` and
`track-features` select nothing. `pixi init`, `pixi global` and
`pixi init --script` write the configured exemption as written, so the
new manifest failed to parse with "`flags` cannot be used with `url`".
pixi now ignores empty `flags` and `track-features` next to an archive
too, rather than rattler rejecting them.
`rattler_config` writes the source of an invalid value into its own
message and also reports it as the source, so `pixi config set` and
`pixi config unset` of an `exclude-newer` key printed the reason
twice. pixi now keeps only the source, under its own message.
`pixi workspace exclude-newer unexempt` and its `pixi global`
counterpart turned a `[exclude-newer]` table without exemptions into a
bare cutoff, dropping the comments in and above it. Only an inline
table is now collapsed, like `rattler_config` does for
`pixi config unset`.
The rattler crates come from their release in conda/rattler#3084,
which includes conda/rattler#3082 and conda/rattler#3085, instead of
a git revision.

The `rattler_build_*` crates on crates.io require `rattler_config`
0.11, so they come from prefix-dev/rattler-build#2920 until it is
released.
@lucascolley lucascolley changed the title feat: add exclude-newer to the pixi configuration feat(config): add exclude-newer Nov 2, 2026
@lucascolley lucascolley added the configuration Configuration of workspace or global behavior label Nov 2, 2026
rattler_build_core 0.2.24 builds with rattler_config 0.12, so the git
patch on prefix-dev/rattler-build#2920 can go.

@lucascolley lucascolley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

thank you for working through this, Pavel!

@lucascolley
lucascolley enabled stacked auto-merge (squash) November 2, 2026 16:52
stacked auto-merge was automatically disabled November 2, 2026 17:10

Auto-merge was disabled for another pull request in the stack

# Conflicts:
#	crates/pixi_manifest/src/exclude_newer.rs
@lucascolley
lucascolley enabled stacked auto-merge (squash) November 2, 2026 18:05
@lucascolley
lucascolley merged commit 3d194bf into main Nov 2, 2026
38 checks passed
@lucascolley
lucascolley deleted the default-exclude-newer branch November 2, 2026 18:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

configuration Configuration of workspace or global behavior enhancement New features exclude-newer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(config): add default-exclude-newer key

3 participants