From 10fecabe3a56c1961a3951ce757a6c253339d588 Mon Sep 17 00:00:00 2001 From: DavHau Date: Tue, 12 Jul 2022 18:54:35 +0200 Subject: [PATCH] add devShell outputs for nodejs ad python (#186) * add devShell outputs for nodejs ad python * nodejs devShell improvements - do not export NODE_PATH - create node_modules directory - add .bin directories of direct dependencies to PATH * nodejs: revise devShell logic - fix namespaced modules symlinking to ./node_modules - add all transitive exectables to ./node_modules/.bin - add ./node_modules/.bin to PATH * set nodejs version in eslint example * nodejs: improve error message on failed node_modules symlink in devShell * readme: add nodejs version setting to example --- README.md | 1 + examples/eslint/flake.nix | 1 + .../nodejs/builders/granular/default.nix | 73 ++++++++++++++++++- .../builders/simple-builder/default.nix | 13 ++++ 4 files changed, 86 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8859db35..ec1c3913 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,7 @@ Extensive Example `flake.nix`: { filter = project: project.translator == "package-json"; subsystemInfo.npmArgs = "--legacy-peer-deps"; + subsystemInfo.nodejs = 18; } ]; diff --git a/examples/eslint/flake.nix b/examples/eslint/flake.nix index e7e43d61..e2d7aa4a 100644 --- a/examples/eslint/flake.nix +++ b/examples/eslint/flake.nix @@ -17,6 +17,7 @@ settings = [ { subsystemInfo.noDev = true; + subsystemInfo.nodejs = 18; } ]; }) diff --git a/src/subsystems/nodejs/builders/granular/default.nix b/src/subsystems/nodejs/builders/granular/default.nix index 5f1ce42c..8d82a8d8 100644 --- a/src/subsystems/nodejs/builders/granular/default.nix +++ b/src/subsystems/nodejs/builders/granular/default.nix @@ -62,7 +62,7 @@ makePackage name version)) packageVersions; - outputs = { + outputs = rec { # select only the packages listed in dreamLock as main packages packages = b.foldl' @@ -73,6 +73,16 @@ "${name}"."${version}" = allPackages."${name}"."${version}"; }) args.packages); + + devShell = devShells.default; + + devShells = + {default = devShells.${defaultPackageName};} + // ( + l.mapAttrs + (name: version: allPackages.${name}.${version}.devShell) + args.packages + ); }; # This is only executed for electron based packages. @@ -148,6 +158,8 @@ # Generates a derivation for a specific package name + version makePackage = name: version: let + pname = lib.replaceStrings ["@" "/"] ["__at__" "__slash__"] name; + deps = getDependencies name version; nodeDeps = @@ -155,6 +167,35 @@ deps (dep: allPackages."${dep.name}"."${dep.version}"); + # Derivation building the ./node_modules directory in isolation. + # This is used for the devShell of the current package. + # We do not want to build the full package for the devShell. + nodeModulesDir = pkgs.runCommand "node_modules-${pname}" {} '' + # symlink direct dependencies to ./node_modules + mkdir $out + ${l.concatStringsSep "\n" ( + l.forEach nodeDeps + (pkg: '' + for dir in $(ls ${pkg}/lib/node_modules/); do + if [[ $dir == @* ]]; then + mkdir -p $out/$dir + ln -s ${pkg}/lib/node_modules/$dir/* $out/$dir/ + else + ln -s ${pkg}/lib/node_modules/$dir $out/ + fi + done + '') + )} + + # symlink transitive executables to ./node_modules/.bin + mkdir $out/.bin + for dep in ${l.toString nodeDeps}; do + for binDir in $(ls -d $dep/lib/node_modules/.bin 2>/dev/null ||:); do + ln -sf $binDir/* $out/.bin/ + done + done + ''; + passthruDeps = l.listToAttrs (l.forEach deps @@ -198,10 +239,27 @@ packageName = name; - pname = lib.replaceStrings ["@" "/"] ["__at__" "__slash__"] name; + inherit pname; passthru.dependencies = passthruDeps; + passthru.devShell = pkgs.mkShell { + buildInputs = [ + nodejs + ]; + shellHook = '' + # create the ./node_modules directory + if [ -e ./node_modules ] && [ ! -L ./node_modules ]; then + echo -e "\nFailed creating the ./node_modules symlink to ${nodeModulesDir}" + echo -e "\n./node_modules already exists and is a directory, which means it is managed by another program. Please delete ./node_modules first and re-enter the dev shell." + else + rm -f ./node_modules + ln -s ${nodeModulesDir} ./node_modules + export PATH="$PATH:$(realpath ./node_modules)/.bin" + fi + ''; + }; + installMethod = "symlink"; electronAppDir = "."; @@ -421,6 +479,17 @@ ln -s $nodeModules/.bin $out/bin fi + echo "Symlinking transitive executables to $nodeModules/.bin" + echo "node deps: ${l.toString nodeDeps}" + for dep in ${l.toString nodeDeps}; do + echo "bin dirs: $(ls -d $dep/lib/node_modules/.bin 2>/dev/null ||:)" + for binDir in $(ls -d $dep/lib/node_modules/.bin 2>/dev/null ||:); do + echo binDir $binDir + mkdir -p $nodeModules/.bin + ln -sf $binDir/* $nodeModules/.bin/ + done + done + echo "Symlinking manual pages" if [ -d "$nodeModules/$packageName/man" ] then diff --git a/src/subsystems/python/builders/simple-builder/default.nix b/src/subsystems/python/builders/simple-builder/default.nix index 14402e84..056b5d1a 100644 --- a/src/subsystems/python/builders/simple-builder/default.nix +++ b/src/subsystems/python/builders/simple-builder/default.nix @@ -66,7 +66,20 @@ $pipInstallFlags ''; }); + + devShell = pkgs.mkShell { + buildInputs = [ + # a drv with all dependencies without the main package + (package.overrideAttrs (old: { + src = "."; + dontUnpack = true; + buildPhase = old.preBuild; + })) + ]; + }; in { packages.${defaultPackageName}.${defaultPackageVersion} = package; + devShells.${defaultPackageName} = devShell; + inherit devShell; }; }