/* This is the library of nix builders. Some rules to follow: - Keep this code as minimal as possible. I'd rather write Haskell than Nix, wouldn't you? - Try to reuse as much upstream Nix as possible. - Path-like args such as 'srcs' should always be absolute paths. */ { srcs ? "" # list of all source files, as a space-separated string , main # the entrypoint or main module (not a path) , root # path to git root , packageSet # name mapped to private.${packageSet}, e.g. 'ghcWith' , langdeps ? null # list of deps (as a string), split and passed to packageSet , sysdeps ? null , name # exe name , compileLine ? "" # Target.compiler <> Target.compilerFlags }: with import (/. + root + "/Biz/Bild.nix") {}; with builtins; let srcs_ = (lib.strings.splitString " " srcs) ++ [main]; skip = ["_" ".direnv"]; filter = file: type: if elem (baseNameOf file) skip then false # TODO: this means any new directory will cause a rebuild. this bad. i # should recurse into the directory and match against the srcs. for now I # just use postUnpack to delete empty dirs else if type == "directory" then true else if type == "regular" then (builtins.elem file srcs_) else false; # clean up empty dirs postUnpack = "find . -type d -empty -delete"; src = lib.sources.cleanSourceWith {inherit filter; src = lib.sources.cleanSource root;}; langdeps_ = pkgset: if langdeps == null || langdeps == [] then [] else private.selectAttrs (lib.strings.splitString " " langdeps) pkgset; sysdeps_ = if sysdeps == null || sysdeps == [] then [] else private.selectAttrs (lib.strings.splitString " " sysdeps) private.nixpkgs.pkgs; BIZ_ROOT = "."; in { base = stdenv.mkDerivation rec { inherit name src BIZ_ROOT postUnpack; buildInputs = [ (private.${packageSet} langdeps_) ] ++ sysdeps_; installPhase = "install -D ${name} $out/bin/${name}"; buildPhase = compileLine; }; python = buildPythonApplication rec { inherit name src BIZ_ROOT postUnpack; propagatedBuildInputs = [ (private.${packageSet} langdeps_) ] ++ sysdeps_; buildInputs = sysdeps_; checkInputs = [(private.pythonWith (p: with p; [black mypy pylint]))]; checkPhase = '' black --quiet --exclude 'setup\.py$' --check . pylint --errors-only . mypy --strict --no-error-summary --exclude 'setup\.py$' . python -m ${main} test ''; preBuild = '' # initialize possibly-empty subdirectories as python modules find . -type d -exec touch {}/__init__.py \; # generate a minimal setup.py cat > setup.py << EOF from setuptools import setup, find_packages setup( name='${name}', entry_points={'console_scripts':['${name} = ${main}:main']}, version='0.0.0', url='git://simatime.com/biz.git', author='dev', author_email='dev@simatime.com', description='nil', packages=find_packages(), install_requires=[], ) EOF ''; pythonImportsCheck = [main]; # sanity check }; }