pythonCatchConflictsHook: improve and add tests
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
{ pythonOnBuildForHost, runCommand, writeShellScript, coreutils, gnugrep }: let
|
||||
|
||||
pythonPkgs = pythonOnBuildForHost.pkgs;
|
||||
|
||||
### UTILITIES
|
||||
|
||||
# customize a package so that its store paths differs
|
||||
customize = pkg: pkg.overrideAttrs { some_modification = true; };
|
||||
|
||||
# generates minimal pyproject.toml
|
||||
pyprojectToml = pname: builtins.toFile "pyproject.toml" ''
|
||||
[project]
|
||||
name = "${pname}"
|
||||
version = "1.0.0"
|
||||
'';
|
||||
|
||||
# generates source for a python project
|
||||
projectSource = pname: runCommand "my-project-source" {} ''
|
||||
mkdir -p $out/src
|
||||
cp ${pyprojectToml pname} $out/pyproject.toml
|
||||
touch $out/src/__init__.py
|
||||
'';
|
||||
|
||||
# helper to reduce boilerplate
|
||||
generatePythonPackage = args: pythonPkgs.buildPythonPackage (
|
||||
{
|
||||
version = "1.0.0";
|
||||
src = runCommand "my-project-source" {} ''
|
||||
mkdir -p $out/src
|
||||
cp ${pyprojectToml args.pname} $out/pyproject.toml
|
||||
touch $out/src/__init__.py
|
||||
'';
|
||||
pyproject = true;
|
||||
catchConflicts = true;
|
||||
buildInputs = [ pythonPkgs.setuptools ];
|
||||
}
|
||||
// args
|
||||
);
|
||||
|
||||
# in order to test for a failing build, wrap it in a shell script
|
||||
expectFailure = build: errorMsg: build.overrideDerivation (old: {
|
||||
builder = writeShellScript "test-for-failure" ''
|
||||
export PATH=${coreutils}/bin:${gnugrep}/bin:$PATH
|
||||
${old.builder} "$@" > ./log 2>&1
|
||||
status=$?
|
||||
cat ./log
|
||||
if [ $status -eq 0 ] || ! grep -q "${errorMsg}" ./log; then
|
||||
echo "The build should have failed with '${errorMsg}', but it didn't"
|
||||
exit 1
|
||||
else
|
||||
echo "The build failed as expected with: ${errorMsg}"
|
||||
mkdir -p $out
|
||||
fi
|
||||
'';
|
||||
});
|
||||
in {
|
||||
|
||||
### TEST CASES
|
||||
|
||||
# Test case which must not trigger any conflicts.
|
||||
# This derivation has runtime dependencies on custom versions of multiple build tools.
|
||||
# This scenario is relevant for lang2nix tools which do not override the nixpkgs fix-point.
|
||||
# see https://github.com/NixOS/nixpkgs/issues/283695
|
||||
ignores-build-time-deps =
|
||||
generatePythonPackage {
|
||||
pname = "ignores-build-time-deps";
|
||||
buildInputs = [
|
||||
pythonPkgs.build
|
||||
pythonPkgs.packaging
|
||||
pythonPkgs.setuptools
|
||||
pythonPkgs.wheel
|
||||
];
|
||||
propagatedBuildInputs = [
|
||||
# Add customized versions of build tools as runtime deps
|
||||
(customize pythonPkgs.packaging)
|
||||
(customize pythonPkgs.setuptools)
|
||||
(customize pythonPkgs.wheel)
|
||||
];
|
||||
};
|
||||
|
||||
# Simplest test case that should trigger a conflict
|
||||
catches-simple-conflict = let
|
||||
# this build must fail due to conflicts
|
||||
package = pythonPkgs.buildPythonPackage rec {
|
||||
pname = "catches-simple-conflict";
|
||||
version = "0.0.0";
|
||||
src = projectSource pname;
|
||||
pyproject = true;
|
||||
catchConflicts = true;
|
||||
buildInputs = [
|
||||
pythonPkgs.setuptools
|
||||
];
|
||||
# depend on two different versions of packaging
|
||||
# (an actual runtime dependency conflict)
|
||||
propagatedBuildInputs = [
|
||||
pythonPkgs.packaging
|
||||
(customize pythonPkgs.packaging)
|
||||
];
|
||||
};
|
||||
in
|
||||
expectFailure package "Found duplicated packages in closure for dependency 'packaging'";
|
||||
|
||||
|
||||
/*
|
||||
More complex test case with a transitive conflict
|
||||
|
||||
Test sets up this dependency tree:
|
||||
|
||||
toplevel
|
||||
├── dep1
|
||||
│ └── leaf
|
||||
└── dep2
|
||||
└── leaf (customized version -> conflicting)
|
||||
*/
|
||||
catches-transitive-conflict = let
|
||||
# package depending on both dependency1 and dependency2
|
||||
toplevel = generatePythonPackage {
|
||||
pname = "catches-transitive-conflict";
|
||||
propagatedBuildInputs = [ dep1 dep2 ];
|
||||
};
|
||||
# dep1 package depending on leaf
|
||||
dep1 = generatePythonPackage {
|
||||
pname = "dependency1";
|
||||
propagatedBuildInputs = [ leaf ];
|
||||
};
|
||||
# dep2 package depending on conflicting version of leaf
|
||||
dep2 = generatePythonPackage {
|
||||
pname = "dependency2";
|
||||
propagatedBuildInputs = [ (customize leaf) ];
|
||||
};
|
||||
# some leaf package
|
||||
leaf = generatePythonPackage {
|
||||
pname = "leaf";
|
||||
};
|
||||
in
|
||||
expectFailure toplevel "Found duplicated packages in closure for dependency 'leaf'";
|
||||
}
|
||||
Reference in New Issue
Block a user