Enhance nix-shell shebang handling in flake.nix by supporting multiple interpreters and improving package resolution for Python scripts. Introduced logic to create proper Python wrappers and separate system packages from Python packages for better environment management.

This commit is contained in:
Danilo Reyes
2025-12-20 18:11:36 -06:00
parent 3d86a2b288
commit e3395daced

View File

@@ -58,31 +58,82 @@
}; };
packages.x86_64-linux = packages.x86_64-linux =
let let
# Handle nix-shell shebangs by extracting packages and using writeShellApplication # Handle nix-shell shebangs by extracting packages and interpreter
scriptBin = path: name: scriptBin = path: name:
let let
content = builtins.readFile path; content = builtins.readFile path;
# Match the nix-shell package line: #! nix-shell -i bash -p package1 package2 ... # Match the nix-shell line: #! nix-shell -i interpreter -p package1 package2 ...
nixShellMatch = builtins.match ".*#! nix-shell -i [^ ]+ -p ([^\n]+).*" content; nixShellMatch = builtins.match ".*#! nix-shell -i ([^ ]+) -p ([^\n]+).*" content;
in in
if nixShellMatch != null then if nixShellMatch != null then
let let
packagesStr = builtins.head nixShellMatch; interpreter = builtins.head nixShellMatch;
packagesStr = builtins.elemAt nixShellMatch 1;
# Split by spaces and filter empty strings # Split by spaces and filter empty strings
packages = builtins.filter (s: s != "") (pkgs.lib.splitString " " packagesStr); packages = builtins.filter (s: s != "") (pkgs.lib.splitString " " packagesStr);
# Resolve package references - handle python3Packages.* and regular packages
resolvePackage = pkgName:
if pkgs.lib.hasPrefix "python3Packages." pkgName then
let
pythonPkgName = pkgs.lib.removePrefix "python3Packages." pkgName;
in
pkgs.python3Packages.${pythonPkgName}
else if pkgName == "python3" then
pkgs.python3
else
pkgs.${pkgName};
# Get package references from pkgs # Get package references from pkgs
runtimeInputs = builtins.map (pkgName: pkgs.${pkgName}) packages; runtimeInputs = builtins.map resolvePackage packages;
# Remove the nix-shell shebang lines # Remove the nix-shell shebang lines
scriptContent = builtins.replaceStrings scriptContent = builtins.replaceStrings
[ "#!/usr/bin/env nix-shell\n" "#! nix-shell -i bash -p ${packagesStr}\n" ] [ "#!/usr/bin/env nix-shell\n" "#! nix-shell -i ${interpreter} -p ${packagesStr}\n" ]
[ "" "" ] [ "" "" ]
content; content;
in in
pkgs.writeShellApplication { if interpreter == "python3" then
inherit name; # For Python scripts, create a proper wrapper with Python shebang
runtimeInputs = runtimeInputs; let
text = scriptContent; # Separate Python packages from system packages
} pythonPkgNames = builtins.filter (pkg: pkgs.lib.hasPrefix "python3Packages." pkg) packages;
systemPkgNames = builtins.filter (pkg: !(pkgs.lib.hasPrefix "python3Packages." pkg) && pkg != "python3") packages;
# Resolve Python packages for python3.withPackages
pythonPkgs = builtins.map (pkgName:
let pythonPkgName = pkgs.lib.removePrefix "python3Packages." pkgName;
in pkgs.python3Packages.${pythonPkgName}
) pythonPkgNames;
# Create Python environment with required packages
pythonEnv = if pythonPkgs != [] then
pkgs.python3.withPackages (ps: pythonPkgs)
else
pkgs.python3;
# Resolve system packages for PATH
systemRuntimeInputs = builtins.map resolvePackage systemPkgNames;
scriptFile = pkgs.writeText "${name}.py" ''
#!${pythonEnv}/bin/python3
${scriptContent}
'';
in
pkgs.stdenv.mkDerivation {
inherit name;
buildInputs = [ pkgs.makeWrapper ];
dontUnpack = true;
installPhase = ''
mkdir -p $out/bin
cp ${scriptFile} $out/bin/${name}
chmod +x $out/bin/${name}
${pkgs.lib.optionalString (systemRuntimeInputs != []) ''
wrapProgram $out/bin/${name} \
--prefix PATH : ${pkgs.lib.makeBinPath systemRuntimeInputs}
''}
'';
}
else
# For shell scripts, use writeShellApplication
pkgs.writeShellApplication {
inherit name;
runtimeInputs = runtimeInputs;
text = scriptContent;
}
else else
pkgs.writeScriptBin name content; pkgs.writeScriptBin name content;
pkgsBin = pkgsBin =