{ bash, callPackage, coreutils, fetchurl, findutils, nix, runCommand, stdenv , substituteAll, wget, writeText }: /* autonix is a collection of tools to automate packaging large collections * of software, particularly KDE. It consists of three components: * 1. a script (manifest) to download and hash the packages * 2. a dependency scanner (autonix-deps) written in Haskell that examines * the package sources and tries to guess their dependencies * 3. a library of Nix routines (generateCollection) to generate Nix * expressions from the output of the previous steps. */ with stdenv.lib; let /* Download the packages into the Nix store, compute their hashes, * and generate a package manifest in ./manifest.nix. */ manifest = let script = substituteAll { src = ./manifest.sh; inherit bash coreutils findutils nix wget; }; in runCommand "autonix-manifest" {} '' cp ${script} $out chmod +x $out ''; /* Convert a manifest.nix file to XML to be read by autonix-deps. */ writeManifestXML = filename: let generateStores = mapAttrs (n: pkg: pkg.store); manifest = importManifest filename { mirror = ""; }; stores = generateStores manifest; in writeText "manifest.xml" (builtins.toXML stores); /* Generate a set of Nix expressions for the collection, given a * manifest.nix, dependencies.nix, and renames.nix in the same directory. */ generateCollection = dir: # path to directory { mirror # mirror to download packages from , mkDerivation ? mkDerivation , preResolve ? id # modify package set before dependency resolution , postResolve ? id # modify package set after dependency resolution , renames ? {} , scope ? {} }: let fix = f: let x = f x; in x; resolvePkg = name: mapAttrs (attr: if isDepAttr attr then resolveDeps scope else id); resolve = mapAttrs resolvePkg; derive = mapAttrs (name: mkDerivation); renames_ = if renames == {} then (import (dir + "/renames.nix") {}) else renames; packages = importPackages dir renames_ { inherit mirror; }; in derive (postResolve (resolve (preResolve packages))); pkgAttrName = pkg: (builtins.parseDrvName pkg.name).name; pkgVersion = pkg: (builtins.parseDrvName pkg.name).version; depAttrNames = [ "buildInputs" "nativeBuildInputs" "propagatedBuildInputs" "propagatedNativeBuildInputs" "propagatedUserEnvPkgs" ]; isDepAttr = name: builtins.elem name depAttrNames; removePkgDeps = deps: let removeDepsIfDepAttr = attr: value: if isDepAttr attr then fold remove value deps else value; in mapAttrs removeDepsIfDepAttr; hasDep = dep: pkg: let depAttrs = attrValues (filterAttrs (n: v: isDepAttr n) pkg); allDeps = concatLists depAttrs; in elem dep allDeps; importManifest = path: { mirror }: let uniqueNames = manifest: unique (map pkgAttrName manifest); versionsOf = manifest: name: filter (pkg: pkgAttrName pkg == name) manifest; bestVersions = manifest: let best = versions: let strictlyLess = a: b: builtins.compareVersions (pkgVersion a) (pkgVersion b) > 0; sorted = sort strictlyLess versions; in head sorted; in map (name: best (versionsOf manifest name)) (uniqueNames manifest); withNames = manifest: builtins.listToAttrs (map (p: nameValuePair (toLower (pkgAttrName p)) p) manifest); orig = import path { inherit stdenv fetchurl mirror; }; in fold (f: x: f x) orig [ withNames bestVersions ]; importPackages = path: renames: manifestScope: let # Do not allow any package to depend on itself. breakRecursion = let removeSelfDep = pkg: mapAttrs (n: if isDepAttr n then filter (dep: dep != pkg && renamed dep != pkg) else id); in mapAttrs removeSelfDep; renamed = dep: renames."${dep}" or dep; manifest = importManifest (path + "/manifest.nix") manifestScope; deps = import (path + "/dependencies.nix") {}; mkPkg = name: manifest: { inherit (manifest) name src; inherit (deps."${name}") buildInputs nativeBuildInputs propagatedBuildInputs propagatedNativeBuildInputs propagatedUserEnvPkgs; }; in breakRecursion (mapAttrs mkPkg manifest); mkDerivation = drv: stdenv.mkDerivation (drv // { src = fetchurl drv.src; }); resolveDeps = scope: let resolveDeps_go = dep: let res = scope."${dep}" or []; in if isList res then res else [res]; in concatMap resolveDeps_go; userEnvPkg = dep: mapAttrs (name: pkg: pkg // { propagatedUserEnvPkgs = (pkg.propagatedUserEnvPkgs or []) ++ optional (hasDep dep pkg) dep; }); in { inherit generateCollection; inherit importManifest; inherit isDepAttr; inherit manifest; inherit removePkgDeps; inherit resolveDeps; inherit userEnvPkg; inherit writeManifestXML; blacklist = names: pkgs: let removeDeps = deps: mapAttrs (name: removePkgDeps deps); removePkgs = names: pkgs: builtins.removeAttrs pkgs names; in removeDeps names (removePkgs names pkgs); }