Skip to content

Instantly share code, notes, and snippets.

@taktoa
Last active January 8, 2018 12:57
Show Gist options
  • Save taktoa/894ff2ba18bdde7142177f2c3ddcbaea to your computer and use it in GitHub Desktop.
Save taktoa/894ff2ba18bdde7142177f2c3ddcbaea to your computer and use it in GitHub Desktop.
Build the profunctors library incrementally using Nix.
with builtins;
rec {
pkgs = import <nixpkgs> {};
testGHC = pkgs.haskellPackages.ghcWithPackages (p: with p; [
base base-orphans bifunctors comonad contravariant distributive
tagged transformers
]);
testInputs = [ testGHC pkgs.findutils pkgs.parallel ];
extractSrc = drv: { patches ? [] }: pkgs.stdenv.mkDerivation {
name = "${drv.name}-src";
src = drv.src;
phases = [ "unpackPhase" "patchPhase" "installPhase" ];
inherit patches;
installPhase = ''
mkdir -p $out/
cp -Rv ./* $out/
'';
};
testCBs = inputs: {
build = self: { command, dependencies }: (
pkgs.stdenv.mkDerivation {
name = "intermediate-build";
src = pkgs.buildEnv {
name = "intermediate-build-env";
paths = dependencies;
};
inherit command;
buildInputs = inputs;
phases = ["unpackPhase" "buildPhase" "installPhase"];
unpackPhase = ''
cp -Lsrv "$src" .
cd "$(basename "$src")"
chmod -Rv u+w .
'';
buildPhase = ''
eval "$command"
'';
installPhase = ''
mkdir -p "$out"
function helper () {
FILE="$1"
if test -e "$FILE"; then
echo "helper: processing $FILE"
if test -d "$FILE"; then
echo "helper: $FILE is a directory, so we should make it"
mkdir -pv "$out/$FILE"
elif test -h "$FILE"; then
echo "helper: $FILE is symlink, so we should symlink the original"
cp -sv "$(readlink -f "$FILE")" "$out/$(dirname "$FILE")"
else
echo "helper: $FILE is a regular file, so we should copy it"
cp -v "$FILE" "$out/$(dirname "$FILE")"
fi
else
echo "helper: error: $FILE does not exist"
fi
}
export -f helper
find . | parallel "helper {}"
'';
});
phony = self: dependencies: pkgs.buildEnv {
name = "intermediate-phony";
paths = dependencies;
};
leaf = self: path: (
with rec {
file = readFile (toPath "${self.src}/${path}");
drv = toFile "interned-leaf" file;
};
pkgs.runCommand "intermediate-leaf" {} ''
mkdir -p "$out/$(dirname ${path})"
cp -v "${drv}" "$out/$(dirname ${path})/$(basename ${path})"
'');
};
exampleSrc = extractSrc pkgs.haskellPackages.profunctors {
patches = [];
#patches = [ ./example.patch ];
};
dynamize = data: { build, phony, leaf }: self: (
with rec {
convertBuild = node: build self { inherit (node) command dependencies; };
convertPhony = node: phony self node.dependencies;
convertLeaf = node: leaf self node.path;
convertNode = node: (
if node.type == "build" then convertBuild node
else if node.type == "phony" then convertPhony node
else if node.type == "leaf" then convertLeaf node
else abort ("invalid node type in build graph: " + node.type));
};
{
inherit (data) src defaults;
graph = pkgs.lib.attrsets.mapAttrs (key: val: convertNode val) data.graph;
});
resolver = cb: { build, phony, leaf }: (
cb {
build = self: { command, dependencies }: (build self {
inherit command;
dependencies = map (x: self.graph.${x}) dependencies;
});
phony = self: dependencies: (
phony self (map (x: self.graph.${x}) dependencies));
inherit leaf;
});
ninjaJSON = fromJSON (readFile ./ninja.json);
exampleNinjaData = ninjaJSON // { src = toPath "${exampleSrc}/src"; };
exampleNinja = dynamize exampleNinjaData;
combineDefault = ({ defaults, graph, ... }:
pkgs.buildEnv {
name = "default";
paths = (map (x: graph.${x}) defaults);
});
buildNinja = ninja: cbs: combineDefault (pkgs.lib.fix (resolver ninja cbs));
test = buildNinja exampleNinja (testCBs testInputs);
}
{
"defaults": [
"all"
],
"graph": {
"Data/Profunctor.hi": {
"dependencies": [
"Data/Profunctor.o"
],
"type": "phony"
},
"Data/Profunctor.hs": {
"path": "Data/Profunctor.hs",
"type": "leaf"
},
"Data/Profunctor.o": {
"command": "/bin/sh -c \"ghc -c Data/Profunctor.hs\"",
"dependencies": [
"Data/Profunctor.hs",
"Data/Profunctor/Closed.hi",
"Data/Profunctor/Strong.hi",
"Data/Profunctor/Types.hi",
"Data/Profunctor/Choice.hi",
"Data/Profunctor/Mapping.hi"
],
"type": "build"
},
"Data/Profunctor/Adjunction.hi": {
"dependencies": [
"Data/Profunctor/Adjunction.o"
],
"type": "phony"
},
"Data/Profunctor/Adjunction.hs": {
"path": "Data/Profunctor/Adjunction.hs",
"type": "leaf"
},
"Data/Profunctor/Adjunction.o": {
"command": "/bin/sh -c \"ghc -c Data/Profunctor/Adjunction.hs\"",
"dependencies": [
"Data/Profunctor/Adjunction.hs",
"Data/Profunctor/Monad.hi",
"Data/Profunctor/Types.hi"
],
"type": "build"
},
"Data/Profunctor/Cayley.hi": {
"dependencies": [
"Data/Profunctor/Cayley.o"
],
"type": "phony"
},
"Data/Profunctor/Cayley.hs": {
"path": "Data/Profunctor/Cayley.hs",
"type": "leaf"
},
"Data/Profunctor/Cayley.o": {
"command": "/bin/sh -c \"ghc -c Data/Profunctor/Cayley.hs\"",
"dependencies": [
"Data/Profunctor/Cayley.hs",
"Data/Profunctor/Unsafe.hi",
"Data/Profunctor/Monad.hi",
"Data/Profunctor.hi"
],
"type": "build"
},
"Data/Profunctor/Choice.hi": {
"dependencies": [
"Data/Profunctor/Choice.o"
],
"type": "phony"
},
"Data/Profunctor/Choice.hs": {
"path": "Data/Profunctor/Choice.hs",
"type": "leaf"
},
"Data/Profunctor/Choice.o": {
"command": "/bin/sh -c \"ghc -c Data/Profunctor/Choice.hs\"",
"dependencies": [
"Data/Profunctor/Choice.hs",
"Data/Profunctor/Monad.hi",
"Data/Profunctor/Unsafe.hi",
"Data/Profunctor/Strong.hi",
"Data/Profunctor/Types.hi",
"Data/Profunctor/Adjunction.hi"
],
"type": "build"
},
"Data/Profunctor/Closed.hi": {
"dependencies": [
"Data/Profunctor/Closed.o"
],
"type": "phony"
},
"Data/Profunctor/Closed.hs": {
"path": "Data/Profunctor/Closed.hs",
"type": "leaf"
},
"Data/Profunctor/Closed.o": {
"command": "/bin/sh -c \"ghc -c Data/Profunctor/Closed.hs\"",
"dependencies": [
"Data/Profunctor/Closed.hs",
"Data/Profunctor/Monad.hi",
"Data/Profunctor/Unsafe.hi",
"Data/Profunctor/Strong.hi",
"Data/Profunctor/Types.hi",
"Data/Profunctor/Adjunction.hi"
],
"type": "build"
},
"Data/Profunctor/Composition.hi": {
"dependencies": [
"Data/Profunctor/Composition.o"
],
"type": "phony"
},
"Data/Profunctor/Composition.hs": {
"path": "Data/Profunctor/Composition.hs",
"type": "leaf"
},
"Data/Profunctor/Composition.o": {
"command": "/bin/sh -c \"ghc -c Data/Profunctor/Composition.hs\"",
"dependencies": [
"Data/Profunctor/Composition.hs",
"Data/Profunctor/Unsafe.hi",
"Data/Profunctor/Sieve.hi",
"Data/Profunctor/Rep.hi",
"Data/Profunctor/Monad.hi",
"Data/Profunctor/Adjunction.hi",
"Data/Profunctor.hi"
],
"type": "build"
},
"Data/Profunctor/Mapping.hi": {
"dependencies": [
"Data/Profunctor/Mapping.o"
],
"type": "phony"
},
"Data/Profunctor/Mapping.hs": {
"path": "Data/Profunctor/Mapping.hs",
"type": "leaf"
},
"Data/Profunctor/Mapping.o": {
"command": "/bin/sh -c \"ghc -c Data/Profunctor/Mapping.hs\"",
"dependencies": [
"Data/Profunctor/Mapping.hs",
"Data/Profunctor/Monad.hi",
"Data/Profunctor/Unsafe.hi",
"Data/Profunctor/Closed.hi",
"Data/Profunctor/Strong.hi",
"Data/Profunctor/Types.hi",
"Data/Profunctor/Traversing.hi",
"Data/Profunctor/Choice.hi"
],
"type": "build"
},
"Data/Profunctor/Monad.hi": {
"dependencies": [
"Data/Profunctor/Monad.o"
],
"type": "phony"
},
"Data/Profunctor/Monad.hs": {
"path": "Data/Profunctor/Monad.hs",
"type": "leaf"
},
"Data/Profunctor/Monad.o": {
"command": "/bin/sh -c \"ghc -c Data/Profunctor/Monad.hs\"",
"dependencies": [
"Data/Profunctor/Monad.hs",
"Data/Profunctor/Types.hi"
],
"type": "build"
},
"Data/Profunctor/Ran.hi": {
"dependencies": [
"Data/Profunctor/Ran.o"
],
"type": "phony"
},
"Data/Profunctor/Ran.hs": {
"path": "Data/Profunctor/Ran.hs",
"type": "leaf"
},
"Data/Profunctor/Ran.o": {
"command": "/bin/sh -c \"ghc -c Data/Profunctor/Ran.hs\"",
"dependencies": [
"Data/Profunctor/Ran.hs",
"Data/Profunctor/Unsafe.hi",
"Data/Profunctor/Monad.hi",
"Data/Profunctor/Composition.hi",
"Data/Profunctor.hi"
],
"type": "build"
},
"Data/Profunctor/Rep.hi": {
"dependencies": [
"Data/Profunctor/Rep.o"
],
"type": "phony"
},
"Data/Profunctor/Rep.hs": {
"path": "Data/Profunctor/Rep.hs",
"type": "leaf"
},
"Data/Profunctor/Rep.o": {
"command": "/bin/sh -c \"ghc -c Data/Profunctor/Rep.hs\"",
"dependencies": [
"Data/Profunctor/Rep.hs",
"Data/Profunctor/Sieve.hi",
"Data/Profunctor.hi"
],
"type": "build"
},
"Data/Profunctor/Sieve.hi": {
"dependencies": [
"Data/Profunctor/Sieve.o"
],
"type": "phony"
},
"Data/Profunctor/Sieve.hs": {
"path": "Data/Profunctor/Sieve.hs",
"type": "leaf"
},
"Data/Profunctor/Sieve.o": {
"command": "/bin/sh -c \"ghc -c Data/Profunctor/Sieve.hs\"",
"dependencies": [
"Data/Profunctor/Sieve.hs",
"Data/Profunctor.hi"
],
"type": "build"
},
"Data/Profunctor/Strong.hi": {
"dependencies": [
"Data/Profunctor/Strong.o"
],
"type": "phony"
},
"Data/Profunctor/Strong.hs": {
"path": "Data/Profunctor/Strong.hs",
"type": "leaf"
},
"Data/Profunctor/Strong.o": {
"command": "/bin/sh -c \"ghc -c Data/Profunctor/Strong.hs\"",
"dependencies": [
"Data/Profunctor/Strong.hs",
"Data/Profunctor/Monad.hi",
"Data/Profunctor/Unsafe.hi",
"Data/Profunctor/Types.hi",
"Data/Profunctor/Adjunction.hi"
],
"type": "build"
},
"Data/Profunctor/Traversing.hi": {
"dependencies": [
"Data/Profunctor/Traversing.o"
],
"type": "phony"
},
"Data/Profunctor/Traversing.hs": {
"path": "Data/Profunctor/Traversing.hs",
"type": "leaf"
},
"Data/Profunctor/Traversing.o": {
"command": "/bin/sh -c \"ghc -c Data/Profunctor/Traversing.hs\"",
"dependencies": [
"Data/Profunctor/Traversing.hs",
"Data/Profunctor/Monad.hi",
"Data/Profunctor/Unsafe.hi",
"Data/Profunctor/Strong.hi",
"Data/Profunctor/Types.hi",
"Data/Profunctor/Choice.hi"
],
"type": "build"
},
"Data/Profunctor/Types.hi": {
"dependencies": [
"Data/Profunctor/Types.o"
],
"type": "phony"
},
"Data/Profunctor/Types.hs": {
"path": "Data/Profunctor/Types.hs",
"type": "leaf"
},
"Data/Profunctor/Types.o": {
"command": "/bin/sh -c \"ghc -c Data/Profunctor/Types.hs\"",
"dependencies": [
"Data/Profunctor/Types.hs",
"Data/Profunctor/Unsafe.hi"
],
"type": "build"
},
"Data/Profunctor/Unsafe.hi": {
"dependencies": [
"Data/Profunctor/Unsafe.o"
],
"type": "phony"
},
"Data/Profunctor/Unsafe.hs": {
"path": "Data/Profunctor/Unsafe.hs",
"type": "leaf"
},
"Data/Profunctor/Unsafe.o": {
"command": "/bin/sh -c \"ghc -c Data/Profunctor/Unsafe.hs\"",
"dependencies": [
"Data/Profunctor/Unsafe.hs"
],
"type": "build"
},
"all": {
"dependencies": [
"Data/Profunctor.o",
"Data/Profunctor/Adjunction.o",
"Data/Profunctor/Cayley.o",
"Data/Profunctor/Choice.o",
"Data/Profunctor/Closed.o",
"Data/Profunctor/Composition.o",
"Data/Profunctor/Mapping.o",
"Data/Profunctor/Monad.o",
"Data/Profunctor/Ran.o",
"Data/Profunctor/Rep.o",
"Data/Profunctor/Sieve.o",
"Data/Profunctor/Strong.o",
"Data/Profunctor/Traversing.o",
"Data/Profunctor/Types.o",
"Data/Profunctor/Unsafe.o"
],
"type": "phony"
}
}
}
@vaibhavsagar
Copy link

This is cool! It also looks like you've reimplemented Make in Nix 😃

@taktoa
Copy link
Author

taktoa commented Jun 3, 2017

@vaibhavsagar Yes, the intention here is to eventually create a ninja2nix tool that will convert any Ninja file to a Nix derivation. Then I will convert the output of ghc -M to Ninja file, which can be done with kati.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment