2015-01-19 17:13:18 +00:00
|
|
|
{ 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);
|
2015-02-21 16:58:37 +00:00
|
|
|
manifest = importManifest filename { mirror = ""; };
|
|
|
|
stores = generateStores manifest;
|
2015-01-19 17:13:18 +00:00
|
|
|
in
|
2015-02-21 16:58:37 +00:00
|
|
|
writeText "manifest.xml" (builtins.toXML stores);
|
2015-01-19 17:13:18 +00:00
|
|
|
|
|
|
|
/* 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
|
2015-01-25 18:47:17 +00:00
|
|
|
, renames ? {}
|
2015-01-19 17:13:18 +00:00
|
|
|
, 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);
|
|
|
|
|
2015-01-25 18:47:17 +00:00
|
|
|
renames_ =
|
|
|
|
if renames == {} then (import (dir + "/renames.nix") {}) else renames;
|
|
|
|
|
|
|
|
packages = importPackages dir renames_ { inherit mirror; };
|
2015-01-19 17:13:18 +00:00
|
|
|
|
|
|
|
in derive (postResolve (resolve (preResolve packages)));
|
|
|
|
|
2015-02-21 16:58:37 +00:00
|
|
|
pkgAttrName = pkg: (builtins.parseDrvName pkg.name).name;
|
|
|
|
pkgVersion = pkg: (builtins.parseDrvName pkg.name).version;
|
2015-01-19 17:13:18 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2015-02-21 16:58:37 +00:00
|
|
|
orig = import path { inherit stdenv fetchurl mirror; };
|
2015-01-19 17:13:18 +00:00
|
|
|
in
|
|
|
|
fold (f: x: f x) orig [ withNames bestVersions ];
|
|
|
|
|
2015-01-25 18:47:17 +00:00
|
|
|
importPackages = path: renames: manifestScope:
|
2015-01-19 17:13:18 +00:00
|
|
|
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") {};
|
|
|
|
|
2015-02-21 16:58:37 +00:00
|
|
|
mkPkg = name: manifest:
|
2015-01-19 17:13:18 +00:00
|
|
|
{
|
2015-02-21 16:58:37 +00:00
|
|
|
inherit (manifest) name src;
|
|
|
|
inherit (deps."${name}")
|
2015-01-19 17:13:18 +00:00
|
|
|
buildInputs nativeBuildInputs propagatedBuildInputs
|
|
|
|
propagatedNativeBuildInputs propagatedUserEnvPkgs;
|
|
|
|
};
|
|
|
|
|
|
|
|
in breakRecursion (mapAttrs mkPkg manifest);
|
|
|
|
|
|
|
|
mkDerivation = drv: stdenv.mkDerivation (drv // { src = fetchurl drv.src; });
|
|
|
|
|
2015-06-15 16:50:39 +01:00
|
|
|
resolveDeps = scope: deps:
|
|
|
|
let resolve = dep:
|
2015-03-08 22:28:44 +00:00
|
|
|
let res = scope."${dep}" or [];
|
2015-06-15 16:50:39 +01:00
|
|
|
in if lib.isList res then res else [res];
|
|
|
|
in lib.concatMap resolve deps;
|
2015-01-19 17:13:18 +00:00
|
|
|
|
|
|
|
userEnvPkg = dep:
|
|
|
|
mapAttrs
|
|
|
|
(name: pkg: pkg // {
|
|
|
|
propagatedUserEnvPkgs =
|
|
|
|
(pkg.propagatedUserEnvPkgs or [])
|
|
|
|
++ optional (hasDep dep pkg) dep;
|
|
|
|
});
|
|
|
|
|
|
|
|
in
|
|
|
|
{
|
|
|
|
inherit generateCollection;
|
2015-02-07 18:52:01 +00:00
|
|
|
inherit importManifest;
|
2015-01-19 17:13:18 +00:00
|
|
|
inherit isDepAttr;
|
|
|
|
inherit manifest;
|
2015-02-01 16:25:19 +00:00
|
|
|
inherit removePkgDeps;
|
2015-01-19 17:13:18 +00:00
|
|
|
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);
|
2015-06-15 16:50:39 +01:00
|
|
|
|
|
|
|
lib = rec {
|
|
|
|
mkPackage = callPackage: defaultOverride: name: pkg: let drv =
|
|
|
|
{ mkDerivation, fetchurl, scope }:
|
|
|
|
|
|
|
|
mkDerivation (defaultOverride {
|
|
|
|
inherit (pkg) name;
|
|
|
|
|
|
|
|
src = fetchurl pkg.src;
|
|
|
|
|
|
|
|
buildInputs = resolveDeps scope pkg.buildInputs;
|
|
|
|
nativeBuildInputs = resolveDeps scope pkg.nativeBuildInputs;
|
|
|
|
propagatedBuildInputs = resolveDeps scope pkg.propagatedBuildInputs;
|
|
|
|
propagatedNativeBuildInputs =
|
|
|
|
resolveDeps scope pkg.propagatedNativeBuildInputs;
|
|
|
|
propagatedUserEnvPkgs = resolveDeps scope pkg.propagatedUserEnvPkgs;
|
|
|
|
|
|
|
|
enableParallelBuilding = true;
|
|
|
|
});
|
|
|
|
in callPackage drv {};
|
|
|
|
|
|
|
|
renameDeps = renames: lib.mapAttrs (name: pkg:
|
|
|
|
let breakCycles = lib.filter (dep: dep != name);
|
|
|
|
rename = dep: renames."${dep}" or dep;
|
|
|
|
in pkg // {
|
|
|
|
buildInputs = breakCycles (map rename pkg.buildInputs);
|
|
|
|
nativeBuildInputs = breakCycles (map rename pkg.nativeBuildInputs);
|
|
|
|
propagatedBuildInputs = breakCycles (map rename pkg.propagatedBuildInputs);
|
|
|
|
propagatedNativeBuildInputs = breakCycles (map rename pkg.propagatedNativeBuildInputs);
|
|
|
|
propagatedUserEnvPkgs = breakCycles (map rename pkg.propagatedUserEnvPkgs);
|
|
|
|
});
|
|
|
|
|
|
|
|
propagateDeps = propagated: lib.mapAttrs (name: pkg:
|
|
|
|
let isPropagated = dep: lib.elem dep propagated;
|
|
|
|
isNotPropagated = dep: !(isPropagated dep);
|
|
|
|
in pkg // {
|
|
|
|
buildInputs = lib.filter isNotPropagated pkg.buildInputs;
|
|
|
|
nativeBuildInputs = lib.filter isNotPropagated pkg.nativeBuildInputs;
|
|
|
|
propagatedBuildInputs =
|
|
|
|
pkg.propagatedBuildInputs
|
|
|
|
++ lib.filter isPropagated pkg.buildInputs;
|
|
|
|
propagatedNativeBuildInputs =
|
|
|
|
pkg.propagatedNativeBuildInputs
|
|
|
|
++ lib.filter isPropagated pkg.nativeBuildInputs;
|
|
|
|
});
|
|
|
|
|
|
|
|
nativeDeps = native: lib.mapAttrs (name: pkg:
|
|
|
|
let isNative = dep: lib.elem dep native;
|
|
|
|
isNotNative = dep: !(isNative dep);
|
|
|
|
in pkg // {
|
|
|
|
buildInputs = lib.filter isNotNative pkg.buildInputs;
|
|
|
|
nativeBuildInputs =
|
|
|
|
pkg.nativeBuildInputs
|
|
|
|
++ lib.filter isNative pkg.buildInputs;
|
|
|
|
propagatedBuildInputs = lib.filter isNotNative pkg.propagatedBuildInputs;
|
|
|
|
propagatedNativeBuildInputs =
|
|
|
|
pkg.propagatedNativeBuildInputs
|
|
|
|
++ lib.filter isNative pkg.propagatedBuildInputs;
|
|
|
|
});
|
|
|
|
|
|
|
|
userEnvDeps = user: lib.mapAttrs (name: pkg:
|
|
|
|
let allDeps = with pkg; lib.concatLists [
|
|
|
|
buildInputs
|
|
|
|
nativeBuildInputs
|
|
|
|
propagatedBuildInputs
|
|
|
|
propagatedNativeBuildInputs
|
|
|
|
];
|
|
|
|
in assert (lib.isList allDeps); pkg // {
|
|
|
|
propagatedUserEnvPkgs = lib.filter (dep: lib.elem dep user) allDeps;
|
|
|
|
});
|
|
|
|
|
|
|
|
overrideDerivation = pkg: f: pkg.override (super: super // {
|
|
|
|
mkDerivation = drv: super.mkDerivation (drv // f drv);
|
|
|
|
});
|
|
|
|
|
|
|
|
extendDerivation = pkg: attrs:
|
|
|
|
let mergeAttrBy = lib.mergeAttrBy // {
|
|
|
|
propagatedNativeBuildInputs = a: b: a ++ b;
|
|
|
|
NIX_CFLAGS_COMPILE = a: b: "${a} ${b}";
|
|
|
|
cmakeFlags = a: b: a ++ b;
|
|
|
|
};
|
|
|
|
mergeAttrsByFunc = sets:
|
|
|
|
let merged = lib.foldl lib.mergeAttrByFunc { inherit mergeAttrBy; } sets;
|
|
|
|
in builtins.removeAttrs merged ["mergeAttrBy"];
|
|
|
|
in overrideDerivation pkg (drv: mergeAttrsByFunc [ drv attrs ]);
|
|
|
|
|
|
|
|
overrideScope = pkg: fnOrSet: pkg.override (super: super // {
|
|
|
|
scope = if builtins.isFunction fnOrSet
|
|
|
|
then super.scope // fnOrSet super.scope
|
|
|
|
else super.scope // fnOrSet;
|
|
|
|
});
|
|
|
|
};
|
2015-01-19 17:13:18 +00:00
|
|
|
}
|