fixup/improve python translator and builder

- translator: ensure setup requirements from pyproject.toml are respected
- builder: ensure setup requirements are installed first before the package is built
- simplify the python translator
- dont depend on mach-nix for dependency extraction
- use only pip download to extract dependencies
- allow impure pip translator to cache downloads
- fix dream-lock.json. location was missing
This commit is contained in:
DavHau 2022-06-19 10:20:55 +02:00
parent 1ba9555ecf
commit 78b14674cd
5 changed files with 63 additions and 73 deletions

21
examples/python/flake.nix Normal file
View File

@ -0,0 +1,21 @@
{
inputs = {
dream2nix.url = "github:nix-community/dream2nix";
src.url = "https://files.pythonhosted.org/packages/5a/86/5f63de7a202550269a617a5d57859a2961f3396ecd1739a70b92224766bc/aiohttp-3.8.1.tar.gz";
src.flake = false;
};
outputs = {
self,
dream2nix,
src,
} @ inp:
(dream2nix.lib.makeFlakeOutputs {
systems = ["x86_64-linux"];
config.projectRoot = ./.;
source = src;
})
// {
checks.x86_64-linux.aiohttp = self.packages.x86_64-linux.aiohttp;
};
}

View File

@ -146,25 +146,6 @@
}; };
}); });
pre-commit-check = forAllSystems (
system: pkgs:
pre-commit-hooks.lib.${system}.run {
src = ./.;
hooks = {
treefmt = {
enable = true;
name = "treefmt";
pass_filenames = true;
entry = l.toString (pkgs.writeScript "treefmt" ''
#!${pkgs.bash}/bin/bash
export PATH="$PATH:${alejandra.defaultPackage.${system}}/bin"
${pkgs.treefmt}/bin/treefmt --fail-on-change "$@"
'');
};
};
}
);
docsCli = forAllSystems ( docsCli = forAllSystems (
system: pkgs: system: pkgs:
pkgs.callPackage ./src/docs-cli.nix { pkgs.callPackage ./src/docs-cli.nix {
@ -332,6 +313,17 @@
${pkgs.treefmt}/bin/treefmt --clear-cache --fail-on-change ${pkgs.treefmt}/bin/treefmt --clear-cache --fail-on-change
''); '');
}; };
is-cleaned = {
enable = true;
name = "is-cleaned";
entry = l.toString (pkgs.writeScript "is-cleaned" ''
#!${pkgs.bash}/bin/bash
if find ./examples | grep -q 'flake.lock\|dream2nix-packages'; then
echo "./examples should not contain any flake.lock files or dream2nix-packages directories" >&2
exit 1
fi
'');
};
}; };
}; };
}); });

View File

@ -34,7 +34,7 @@
l.flatten l.flatten
(l.mapAttrsToList (l.mapAttrsToList
(name: versions: (name: versions:
if name == defaultPackageName if l.elem name [defaultPackageName "setuptools" "pip"]
then [] then []
else l.map (ver: getSource name ver) versions) else l.map (ver: getSource name ver) versions)
packageVersions); packageVersions);
@ -51,6 +51,7 @@
buildInputs = pkgs.pythonManylinuxPackages.manylinux1; buildInputs = pkgs.pythonManylinuxPackages.manylinux1;
nativeBuildInputs = [pkgs.autoPatchelfHook]; nativeBuildInputs = [pkgs.autoPatchelfHook];
doCheck = false; doCheck = false;
dontStrip = true;
preBuild = '' preBuild = ''
mkdir dist mkdir dist
for file in ${builtins.toString allDependencySources}; do for file in ${builtins.toString allDependencySources}; do
@ -59,9 +60,6 @@
fname=$(stripHash $fname) fname=$(stripHash $fname)
cp $file dist/$fname cp $file dist/$fname
done done
'';
installPhase = ''
runHook preInstall
mkdir -p "$out/${python.sitePackages}" mkdir -p "$out/${python.sitePackages}"
export PYTHONPATH="$out/${python.sitePackages}:$PYTHONPATH" export PYTHONPATH="$out/${python.sitePackages}:$PYTHONPATH"
${python}/bin/python -m pip install \ ${python}/bin/python -m pip install \
@ -71,7 +69,6 @@
--prefix="$out" \ --prefix="$out" \
--no-cache \ --no-cache \
$pipInstallFlags $pipInstallFlags
runHook postInstall
''; '';
}; };
in { in {

View File

@ -10,7 +10,6 @@ in {
# the input format is specified in /specifications/translator-call-example.json # the input format is specified in /specifications/translator-call-example.json
# this script receives a json file including the input paths and extraArgs # this script receives a json file including the input paths and extraArgs
translateBin = { translateBin = {
# dream2nix
externalSources, externalSources,
utils, utils,
bash, bash,
@ -18,84 +17,64 @@ in {
jq, jq,
nix, nix,
python3, python3,
toml2json,
writeScriptBin, writeScriptBin,
... ...
}: let }:
machNixExtractor = "${externalSources.mach-nix}/lib/extractor/default.nix";
setuptools_shim = ''
import sys, setuptools, tokenize, os; sys.argv[0] = 'setup.py'; __file__='setup.py';
f=getattr(tokenize, 'open', open)(__file__);
code=f.read().replace('\r\n', '\n');
f.close();
exec(compile(code, __file__, 'exec'))
'';
in
utils.writePureShellScript utils.writePureShellScript
[ [
bash bash
coreutils coreutils
jq jq
nix nix
toml2json
] ]
'' ''
# accroding to the spec, the translator reads the input from a json file # accroding to the spec, the translator reads the input from a json file
jsonInput=$1 jsonInput=$1
# read the json input # read the json input
outputFile=$WORKDIR/$(${jq}/bin/jq '.outputFile' -c -r $jsonInput) outputFile=$WORKDIR/$(jq '.outputFile' -c -r $jsonInput)
source="$(${jq}/bin/jq '.source' -c -r $jsonInput)/$(${jq}/bin/jq '.project.relPath' -c -r $jsonInput)" source="$(jq '.source' -c -r $jsonInput)/$(jq '.project.relPath' -c -r $jsonInput)"
pythonAttr=$(${jq}/bin/jq '.project.subsystemInfo.pythonAttr' -c -r $jsonInput) pythonAttr=$(jq '.project.subsystemInfo.pythonAttr' -c -r $jsonInput)
# build python and pip executables # build python and pip executables
tmpBuild=$(mktemp -d) tmpBuild=$(mktemp -d)
nix build --show-trace --impure --expr \ nix build \
" --impure \
(import ${machNixExtractor} {}).mkPy --expr "(import <nixpkgs> {}).$pythonAttr.withPackages (ps: [ps.pip ps.setuptools])" \
(import <nixpkgs> {}).$pythonAttr -o $tmpBuild/pip
" \
-o $tmpBuild/python
nix build --impure --expr "(import <nixpkgs> {}).$pythonAttr.withPackages (ps: [ps.pip ps.setuptools])" -o $tmpBuild/pip
python=$tmpBuild/python/bin/python
pip=$tmpBuild/pip/bin/pip pip=$tmpBuild/pip/bin/pip
python=$tmpBuild/pip/bin/python
# prepare temporary directory # prepare temporary directory
tmp=$(mktemp -d) tmp=$(mktemp -d)
# extract python requirements from setup.py # prepare source
cp -r $source $tmpBuild/src cp -r $source ./source
chmod -R +w $tmpBuild/src chmod +w -R ./source
cd $tmpBuild/src
chmod +x setup.py || true
echo "extracting dependencies"
out_file=$tmpBuild/python.json \
dump_setup_attrs=y \
PYTHONIOENCODING=utf8 \
LANG=C.utf8 \
$python -c "${setuptools_shim}" install &> $tmpBuild/python.log || true
# extract requirements from json result # download setup dependencies from pyproject.toml
$python -c " toml2json ./source/pyproject.toml | jq '."build-system".requires[]' -r > __setup_reqs.txt \
import json && $tmpBuild/pip/bin/pip download \
result = json.load(open('$tmpBuild/python.json')) --dest $tmp \
for key in ('install_requires', 'setup_requires'): --progress-bar off \
if key in result: -r __setup_reqs.txt \
print('\n'.join(result[key])) || :
" > $tmpBuild/computed_requirements
# download files according to requirements # download files according to requirements
$tmpBuild/pip/bin/pip download \ $tmpBuild/pip/bin/pip download \
--no-cache \
--dest $tmp \ --dest $tmp \
--progress-bar off \ --progress-bar off \
-r $tmpBuild/computed_requirements -r __setup_reqs.txt \
# -r ''${inputFiles/$'\n'/$' -r '} ./source
cd $WORKDIR
# generate the dream lock from the downloaded list of files # generate the dream lock from the downloaded list of files
NAME=$(${jq}/bin/jq '.name' -c -r $tmpBuild/python.json) \ cd ./source
VERSION=$(${jq}/bin/jq '.version' -c -r $tmpBuild/python.json) \ export NAME=$($python ./setup.py --name 2>/dev/null)
$tmpBuild/python/bin/python ${./generate-dream-lock.py} $tmp $jsonInput export VERSION=$($python ./setup.py --version 2>/dev/null)
cd $WORKDIR
$python ${./generate-dream-lock.py} $tmp $jsonInput
rm -rf $tmp $tmpBuild rm -rf $tmp $tmpBuild
''; '';

View File

@ -65,6 +65,7 @@ def main():
os.environ.get('NAME'): os.environ.get('VERSION'), os.environ.get('NAME'): os.environ.get('VERSION'),
}, },
"sourcesAggregatedHash": None, "sourcesAggregatedHash": None,
"location": "",
}, },
_subsystem={ _subsystem={
"application": jsonInput.get('application', False), "application": jsonInput.get('application', False),