Skip to content

Commit 4aa99b2

Browse files
authored
fix: create separte workdir per variant (#4934)
1 parent 91d302a commit 4aa99b2

File tree

5 files changed

+90
-0
lines changed

5 files changed

+90
-0
lines changed

crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@workspace_variants.snap

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,20 @@ expression: project_model
3131
"url": null,
3232
"license": null
3333
}
34+
},
35+
"python": {
36+
"binary": {
37+
"version": "*",
38+
"build": null,
39+
"buildNumber": null,
40+
"fileName": null,
41+
"channel": null,
42+
"subdir": null,
43+
"md5": null,
44+
"sha256": null,
45+
"url": null,
46+
"license": null
47+
}
3448
}
3549
},
3650
"buildDependencies": {},

crates/pixi_command_dispatcher/src/build/work_dir_key.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! See [`WorkDirKey`] for more information.
22
33
use std::{
4+
collections::BTreeMap,
45
ffi::OsStr,
56
hash::{Hash, Hasher},
67
};
@@ -71,4 +72,13 @@ impl WorkDirKey {
7172
None => unique_key,
7273
}
7374
}
75+
76+
pub fn variant_key(variant_key: &BTreeMap<String, String>) -> String {
77+
let mut hasher = Xxh3::new();
78+
for (key, value) in variant_key {
79+
key.hash(&mut hasher);
80+
value.hash(&mut hasher);
81+
}
82+
URL_SAFE_NO_PAD.encode(hasher.finish().to_ne_bytes())
83+
}
7484
}

crates/pixi_command_dispatcher/src/source_build/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,18 @@ impl SourceBuildSpec {
543543
})
544544
})?;
545545

546+
// Create a variant-specific work directory by including the actual variant values
547+
// in the work directory key.
548+
// This ensures different variants get separate work directories,
549+
// preventing files like .pyc accumulation across builds (when using multiple python variants).
550+
let variant_work_dir_hash = WorkDirKey::variant_key(&output.metadata.variant);
551+
552+
// not using set_file_name as it requires &mut self
553+
let work_directory = PathBuf::from(format!(
554+
"{}-{variant_work_dir_hash}",
555+
work_directory.to_string_lossy()
556+
));
557+
546558
// Determine final directories for everything.
547559
let directories = Directories::new(&work_directory, host_platform);
548560

docs/source_files/pixi_workspaces/pixi_build/workspace_variants/pixi.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,12 @@ version = "0.1.0"
3737
[package.build]
3838
backend = { name = "pixi-build-python", version = "==0.4.0" }
3939

40+
[package.build.config]
41+
noarch = false
42+
4043
[package.host-dependencies]
4144
hatchling = "==1.26.3"
45+
python = "*"
4246

4347
[package.run-dependencies]
4448
cpp_math = { path = "packages/cpp_math" }
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import shutil
2+
from pathlib import Path
3+
4+
import pytest
5+
6+
from .common import repo_root, verify_cli_command
7+
8+
9+
@pytest.mark.extra_slow
10+
def test_workspace_variants_separate_work_directories(
11+
pixi: Path,
12+
tmp_pixi_workspace: Path,
13+
) -> None:
14+
"""Test that building with multiple Python variants creates separate work directories.
15+
16+
This test verifies the fix for issue #4878 where .pyc files from different
17+
Python versions would accumulate in the same work directory, causing package
18+
sizes to grow progressively.
19+
20+
The fix ensures that each variant combination gets its own work directory by
21+
including variants in the work directory key hash.
22+
"""
23+
# Find the workspace_variants project
24+
workspace_variants_project = repo_root().joinpath(
25+
"docs/source_files/pixi_workspaces/pixi_build/workspace_variants"
26+
)
27+
28+
# Remove existing .pixi folders
29+
shutil.rmtree(workspace_variants_project.joinpath(".pixi"), ignore_errors=True)
30+
31+
# Copy to workspace
32+
shutil.copytree(workspace_variants_project, tmp_pixi_workspace, dirs_exist_ok=True)
33+
34+
# Build the packages for all variants
35+
verify_cli_command(
36+
[pixi, "build", "--path", tmp_pixi_workspace, "--output-dir", str(tmp_pixi_workspace)],
37+
)
38+
39+
# Check that work directories exist and are separate for each variant
40+
work_dir = tmp_pixi_workspace / ".pixi" / "build" / "work"
41+
assert work_dir.exists(), "Work directory should exist"
42+
43+
# Get all work directories (should be different for py311 and py312)
44+
work_dirs = list(work_dir.glob("python_rich-*"))
45+
46+
# Should have at least 2 work directories (one per Python variant)
47+
assert len(work_dirs) >= 2, (
48+
f"Expected at least 2 work directories for different Python variants, "
49+
f"found {len(work_dirs)}: {[d.name for d in work_dirs]}"
50+
)

0 commit comments

Comments
 (0)