naersk/default.nix

299 lines
10 KiB
Nix
Raw Normal View History

2019-06-18 14:55:38 +00:00
with rec
{ sources = import ./nix/sources.nix;
_pkgs = import sources.nixpkgs {};
};
2019-06-13 11:26:19 +00:00
2019-06-18 14:55:38 +00:00
{ lib ? _pkgs.lib
, runCommand ? _pkgs.runCommand
, symlinkJoin ? _pkgs.symlinkJoin
, stdenv ? _pkgs.stdenv
, writeText ? _pkgs.writeText
, llvmPackages ? _pkgs.llvmPackages
, darwin ? _pkgs.darwin
2019-06-13 11:26:19 +00:00
, rustPackages ?
with sources;
2019-06-18 14:55:38 +00:00
(_pkgs.callPackage rust-nightly {}).rust {inherit (rust-nightly) date; }
2019-06-13 11:26:19 +00:00
}:
# Crate building
with rec
{ # creates an attrset from package name to package version + sha256
2019-06-18 10:58:08 +00:00
# (note: this includes the package's dependencies)
2019-06-18 13:40:44 +00:00
mkVersions = packageName: cargolock:
2019-06-18 15:23:32 +00:00
if builtins.hasAttr "metadata" cargolock then
# TODO: this should nub by <pkg-name>-<pkg-version>
(lib.concatMap (x:
with { mdk = mkMetadataKey x.name x.version; };
( lib.optional (builtins.hasAttr mdk cargolock.metadata)
{ inherit (x) version name;
sha256 = cargolock.metadata.${mkMetadataKey x.name x.version};
}
) ++ (lib.concatMap (parseDependency cargolock) (x.dependencies or []))
)
(builtins.filter (v: v.name != packageName) cargolock.package))
else [];
2019-06-13 11:26:19 +00:00
2019-06-18 13:40:44 +00:00
# Turns "lib-name lib-ver (registry+...)" to [ { name = "lib-name", etc } ]
# iff the package is present in the Cargo.lock (otherwise returns [])
2019-06-18 10:58:08 +00:00
parseDependency = cargolock: str:
with rec
2019-06-18 14:55:38 +00:00
{ components = lib.splitString " " str;
name = lib.elemAt components 0;
version = lib.elemAt components 1;
2019-06-18 13:40:44 +00:00
mdk = mkMetadataKey name version;
2019-06-18 10:58:08 +00:00
};
2019-06-18 14:55:38 +00:00
( lib.optional (builtins.hasAttr mdk cargolock.metadata)
2019-06-18 13:40:44 +00:00
(
with
{ sha256 = cargolock.metadata.${mkMetadataKey name version};
};
{ inherit name version sha256; }
));
2019-06-18 10:58:08 +00:00
2019-06-13 11:26:19 +00:00
# crafts the key used to look up the sha256 in the cargo lock; no
# robustness guarantee
mkMetadataKey = name: version:
"checksum ${name} ${version} (registry+https://github.com/rust-lang/crates.io-index)";
# XXX: the actual crate format is not documented but in practice is a
# gzipped tar; we simply unpack it and introduce a ".cargo-checksum.json"
# file that cargo itself uses to double check the sha256
unpackCrate = name: version: sha256:
with
{ src = builtins.fetchurl
{ url = "https://crates.io/api/v1/crates/${name}/${version}/download";
inherit sha256;
};
};
2019-06-18 14:55:38 +00:00
runCommand "unpack-${name}-${version}" {}
2019-06-13 11:26:19 +00:00
''
mkdir -p $out
tar -xvzf ${src} -C $out
echo '{"package":"${sha256}","files":{}}' > $out/${name}-${version}/.cargo-checksum.json
'';
# creates a forest of symlinks of all the dependencies XXX: this is very
# basic and means that we have very little incrementality; e.g. when
# anything changes all the deps will be rebuilt. The rustc compiler is
# pretty fast so this is not too bad. In the future we'll want to pre-build
# the crates and give cargo a pre-populated ./target directory.
2019-06-18 14:47:13 +00:00
# TODO: this should most likely take more than one packageName
2019-06-18 13:40:44 +00:00
mkSnapshotForest = patchCrate: packageName: cargolock:
2019-06-18 14:55:38 +00:00
symlinkJoin
2019-06-13 11:26:19 +00:00
{ name = "crates-io";
paths =
2019-06-18 10:58:08 +00:00
map
(v: patchCrate v.name v (unpackCrate v.name v.version v.sha256))
2019-06-18 13:40:44 +00:00
(mkVersions packageName cargolock);
2019-06-13 11:26:19 +00:00
};
buildPackage =
src:
{ cargoCommands ? [ "cargo build" ]
2019-06-18 13:40:44 +00:00
, patchCrate ? (_: _: x: x)
, name ? null
2019-06-18 14:47:13 +00:00
, rustc ? rustPackages
, cargo ? rustPackages
, override ? null
2019-06-18 13:40:44 +00:00
}:
2019-06-13 11:26:19 +00:00
with rec
{
readTOML = f: builtins.fromTOML (builtins.readFile f);
cargolock = readTOML "${src}/Cargo.lock";
2019-06-18 14:47:13 +00:00
# The top-level Cargo.toml
2019-06-13 11:26:19 +00:00
cargotoml = readTOML "${src}/Cargo.toml";
2019-06-18 14:47:13 +00:00
# All the Cargo.tomls, including the top-level one
cargotomls =
2019-06-18 13:40:44 +00:00
with rec
2019-06-18 14:47:13 +00:00
{ workspaceMembers = cargotoml.workspace.members or [];
2019-06-18 13:40:44 +00:00
};
2019-06-18 14:47:13 +00:00
[cargotoml] ++ (
map (member: (builtins.fromTOML (builtins.readFile
2019-06-18 15:23:32 +00:00
"${src}/${member}/Cargo.toml")))
2019-06-18 14:47:13 +00:00
workspaceMembers);
crateNames = builtins.filter (pname: ! isNull pname) (
map (ctoml: ctoml.package.name or null) cargotomls);
# The list of potential binaries
# TODO: is this even worth it or shall we simply copy all the
# executables to bin/?
bins = crateNames ++
map (bin: bin.name) (
2019-06-18 14:55:38 +00:00
lib.concatMap (ctoml: ctoml.bin or []) cargotomls);
2019-06-18 14:47:13 +00:00
2019-06-18 14:55:38 +00:00
cargoconfig = writeText "cargo-config"
2019-06-18 11:00:55 +00:00
''
[source.crates-io]
replace-with = 'nix-sources'
[source.nix-sources]
2019-06-18 14:55:38 +00:00
directory = '${mkSnapshotForest patchCrate (lib.head crateNames) cargolock}'
2019-06-18 11:00:55 +00:00
'';
2019-06-18 14:55:38 +00:00
drv = stdenv.mkDerivation
2019-06-18 14:47:13 +00:00
{ inherit src;
name =
if ! isNull name then
name
2019-06-18 14:55:38 +00:00
else if lib.length crateNames == 0 then
2019-06-18 14:47:13 +00:00
abort "No crate names"
2019-06-18 14:55:38 +00:00
else if lib.length crateNames == 1 then
lib.head crateNames
2019-06-18 14:47:13 +00:00
else
2019-06-18 14:55:38 +00:00
lib.head crateNames + "-et-al";
2019-06-18 14:47:13 +00:00
buildInputs =
[ cargo
# needed for "dsymutil"
2019-06-18 14:55:38 +00:00
llvmPackages.stdenv.cc.bintools
2019-06-18 14:47:13 +00:00
# needed for "cc"
2019-06-18 14:55:38 +00:00
llvmPackages.stdenv.cc
2019-06-18 14:47:13 +00:00
2019-06-18 14:55:38 +00:00
] ++ (stdenv.lib.optionals stdenv.isDarwin
[ darwin.Security
darwin.apple_sdk.frameworks.CoreServices
darwin.cf-private
2019-06-18 14:47:13 +00:00
]);
2019-06-18 14:55:38 +00:00
LIBCLANG_PATH="${llvmPackages.libclang.lib}/lib";
2019-06-18 14:47:13 +00:00
CXX="clang++";
RUSTC="${rustc}/bin/rustc";
2019-06-18 14:55:38 +00:00
cargoCommands = lib.concatStringsSep "\n" cargoCommands;
crateNames = lib.concatStringsSep "\n" crateNames;
bins = lib.concatStringsSep "\n" bins;
2019-06-18 14:47:13 +00:00
buildPhase =
''
runHook preBuild
## registry setup
export CARGO_HOME="$PWD/.cargo-home"
mkdir -p $CARGO_HOME
mkdir -p .cargo
cp ${cargoconfig} .cargo/config
## Build commands
echo "$cargoCommands" | \
while IFS= read -r c
do
echo "Runnig cargo command: $c"
$c
done
runHook postBuild
'';
installPhase =
# TODO: this should also copy <foo> for every src/bin/<foo.rs>
''
runHook preInstall
mkdir -p $out/bin
echo "$bins" | \
while IFS= read -r c
do
echo "Installing executable: $c"
cp "target/debug/$c" $out/bin \
|| echo "No executable $c to install"
done
runHook postInstall
'';
};
};
if isNull override then drv else drv.overrideAttrs override;
2019-06-13 11:26:19 +00:00
};
2019-06-18 10:58:08 +00:00
# lib-like helpers
2019-06-18 12:42:26 +00:00
# These come in handy when cargo manifests must be patched
with rec
{ # Enables the cargo feature "edition" in the cargo manifest
fixupEdition = name: v: src: fixupFeatures name v src ["edition"];
# Generates a sed expression that enables the given features
fixupFeaturesSed = feats:
with
2019-06-18 14:55:38 +00:00
{ features = ''["'' + lib.concatStringsSep ''","'' feats + ''"]'';
2019-06-18 12:42:26 +00:00
};
''/\[package\]/i cargo-features = ${features}'';
# Patches the cargo manifest to enable the list of features
fixupFeatures = name: v: src: feats:
2019-06-18 14:55:38 +00:00
runCommand "fixup-editions-${name}" {}
2019-06-18 10:58:08 +00:00
''
mkdir -p $out
cp -r --no-preserve=mode ${src}/* $out
2019-06-18 12:42:26 +00:00
sed -i '${fixupFeaturesSed feats}' \
$out/${name}-${v.version}/Cargo.toml
2019-06-18 10:58:08 +00:00
'';
};
2019-06-20 09:04:08 +00:00
with
{ crates =
{ lorri = buildPackage sources.lorri
{ override = _oldAttrs:
{ BUILD_REV_COUNT = 1;
RUN_TIME_CLOSURE = "${sources.lorri}/nix/runtime.nix";
};
};
2019-06-18 14:55:38 +00:00
2019-06-20 09:04:08 +00:00
ripgrep-all = buildPackage sources.ripgrep-all {};
rustfmt = buildPackage sources.rustfmt {};
};
};
{ inherit buildPackage fixupEdition fixupFeatures fixupFeaturesSed crates;
test_lorri = runCommand "lorri" { buildInputs = [ crates.lorri ]; }
"lorri --help && touch $out";
2019-06-18 12:42:26 +00:00
test_talent-plan-1 = buildPackage "${sources.talent-plan}/rust/projects/project-1" {};
test_talent-plan-2 = buildPackage "${sources.talent-plan}/rust/projects/project-2" {};
test_talent-plan-3 = buildPackage "${sources.talent-plan}/rust/projects/project-3" {};
# TODO: support for git deps
#test_talent-plan-4 = buildPackage "${sources.talent-plan}/rust/projects/project-4" {};
#test_talent-plan-5 = buildPackage "${sources.talent-plan}/rust/projects/project-5" {};
2019-06-18 13:40:44 +00:00
# TODO: figure out executables from src/bin/*.rs
2019-06-20 09:04:08 +00:00
test_ripgrep-all = runCommand "ripgrep-all"
{ buildInputs = [ crates.ripgrep-all ]; }
"touch $out";
2019-06-18 12:42:26 +00:00
# TODO: Nix error:
# error: while parsing a TOML string at default.nix:80:25:
# Bare key 'cfg(all(target_env = "musl", target_pointer_width = "64"))'
# cannot contain whitespace at line 64
# and this is the culprit:
# https://github.com/BurntSushi/ripgrep/blob/d1389db2e39802d5e04dc7b902fd2b1f9f615b01/Cargo.toml#L64
#test_ripgrep = buildPackage sources.ripgrep {};
# TODO: (workspace)
2019-06-18 13:40:44 +00:00
# error: while parsing a TOML string at ...:115:25:
# Bare key 'cfg(any(all(target_arch = "wasm32", not(target_os = "emscripten")), all(target_vendor = "fortanix", target_env = "sgx")))'
# cannot contain whitespace at line 53
2019-06-18 12:42:26 +00:00
#test_rust = buildPackage sources.rust {};
2019-06-18 13:40:44 +00:00
# Unable to update https://github.com/...
2019-06-18 12:42:26 +00:00
#test_noria = buildPackage sources.noria {};
2019-06-18 13:40:44 +00:00
# No submodules
#test_lucet = buildPackage sources.lucet {};
test_rustlings = buildPackage sources.rustlings {};
2019-06-18 14:47:13 +00:00
# TODO: walk through bins
2019-06-18 14:55:38 +00:00
test_rustfmt = runCommand "rust-fmt"
2019-06-20 09:04:08 +00:00
{ buildInputs = [ crates.rustfmt ]; }
2019-06-18 14:47:13 +00:00
''
rustfmt --help
cargo-fmt --help
touch $out
'';
2019-06-18 12:42:26 +00:00
}