Skip to content

Commit

Permalink
build kinds
Browse files Browse the repository at this point in the history
  • Loading branch information
jordanisaacs committed Mar 20, 2023
1 parent f549328 commit bfbc55f
Show file tree
Hide file tree
Showing 15 changed files with 422 additions and 630 deletions.
227 changes: 106 additions & 121 deletions crate2nix/Cargo.nix

Large diffs are not rendered by default.

19 changes: 17 additions & 2 deletions crate2nix/src/resolve.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Resolve dependencies and other data for CrateDerivation.
use anyhow::format_err;
use anyhow::Context;
use anyhow::Error;
use cargo_metadata::Node;
use cargo_metadata::Package;
Expand Down Expand Up @@ -141,11 +141,16 @@ impl CrateDerivation {
.iter()
.any(|t| t.kind.iter().any(|k| k == "proc-macro"));

// Binaries have one kind:
// https://github.com/rust-lang/cargo/blob/94394ebf2a6b6f1c1d6c160b48865a06e54d5f30/src/cargo/core/manifest.rs#L126
let binaries = package
.targets
.iter()
.filter_map(|t| {
if t.kind.iter().any(|k| k == "bin") {
if t.kind
.iter()
.any(|k| k == "bin" || k == "example" || k == "bench" || k == "test")
{
BuildTarget::new(&t, &package_path).ok()
} else {
None
Expand Down Expand Up @@ -333,23 +338,33 @@ pub fn double_crate_with_rename() {
pub struct BuildTarget {
/// The name of the build target.
pub name: String,
/// The kind of the build target.
pub kind: String,
/// The relative path of the target source file.
pub src_path: PathBuf,
/// The crate's features that need to be enabled for this target to be compiled.
/// Otherwise, this target is ignored.
pub required_features: Vec<String>,
/// Whether to test this binary
pub test: bool,
}

impl BuildTarget {
pub fn new(target: &Target, package_path: impl AsRef<Path>) -> Result<BuildTarget, Error> {
Ok(BuildTarget {
name: target.name.clone(),
kind: target
.kind
.first()
.context("Target shouuld have kind")?
.to_string(),
src_path: target
.src_path
.canonicalize()?
.strip_prefix(&package_path)?
.to_path_buf(),
required_features: target.required_features.clone(),
test: target.test,
})
}
}
Expand Down
5 changes: 5 additions & 0 deletions crate2nix/templates/Cargo.nix.tera
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ rec {
{
name = {{ bin.name }};
path = {{ bin.src_path }};
kind = {{ bin.kind }};
test = {{ bin.test }};
# TODO (when cargo merges metadata):
# harness
# bench
requiredFeatures = [ {% for feature in bin.required_features %}{{feature}} {% endfor %}];
}
{%- endfor %}
Expand Down
153 changes: 32 additions & 121 deletions crate2nix/templates/nix/crate2nix/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -89,112 +89,34 @@ rec {
|| baseName == "tests.nix"
);

/* Returns a crate which depends on successful test execution
of crate given as the second argument.
testCrateFlags: list of flags to pass to the test exectuable
testInputs: list of packages that should be available during test execution
*/
crateWithTest = { crate, testCrate, testCrateFlags, testInputs, testPreRun, testPostRun }:
assert builtins.typeOf testCrateFlags == "list";
assert builtins.typeOf testInputs == "list";
assert builtins.typeOf testPreRun == "string";
assert builtins.typeOf testPostRun == "string";
let
# override the `crate` so that it will build and execute tests instead of
# building the actual lib and bin targets We just have to pass `--test`
# to rustc and it will do the right thing. We execute the tests and copy
# their log and the test executables to $out for later inspection.
test =
let
drv = testCrate.override
(
_: {
buildTests = true;
}
);
# If the user hasn't set any pre/post commands, we don't want to
# insert empty lines. This means that any existing users of crate2nix
# don't get a spurious rebuild unless they set these explicitly.
testCommand = pkgs.lib.concatStringsSep "\n"
(pkgs.lib.filter (s: s != "") [
testPreRun
"$f $testCrateFlags 2>&1 | tee -a $out"
testPostRun
]);
in
pkgs.runCommand "run-tests-${testCrate.name}"
{
inherit testCrateFlags;
buildInputs = testInputs;
} ''
set -ex
export RUST_BACKTRACE=1
# recreate a file hierarchy as when running tests with cargo
# the source for test data
${pkgs.xorg.lndir}/bin/lndir ${crate.src}
# build outputs
testRoot=target/debug
mkdir -p $testRoot
# executables of the crate
# we copy to prevent std::env::current_exe() to resolve to a store location
for i in ${crate}/bin/*; do
cp "$i" "$testRoot"
done
chmod +w -R .
# test harness executables are suffixed with a hash, like cargo does
# this allows to prevent name collision with the main
# executables of the crate
hash=$(basename $out)
for file in ${drv}/tests/*; do
f=$testRoot/$(basename $file)-$hash
cp $file $f
${testCommand}
done
'';
in
pkgs.runCommand "${crate.name}-linked"
{
inherit (crate) outputs crateName;
passthru = (crate.passthru or { }) // {
inherit test;
};
} ''
echo tested by ${test}
${lib.concatMapStringsSep "\n" (output: "ln -s ${crate.${output}} ${"$"}${output}") crate.outputs}
'';

/* A restricted overridable version of builtRustCratesWithFeatures. */
buildRustCrateWithFeatures =
{ packageId
, features ? rootFeatures
, crateOverrides ? defaultCrateOverrides
, buildRustCrateForPkgsFunc ? null
, runTests ? false
, testCrateFlags ? [ ]
, testInputs ? [ ]
# Any command to run immediatelly before a test is executed.
, testPreRun ? ""
# Any command run immediatelly after a test is executed.
, testPostRun ? ""
# Available: [ "lib" "bin" ] or ["test" "bench" "example"]
, buildKinds ? [ "lib" "bin" ]
}:
lib.makeOverridable
(
{ features
, crateOverrides
, runTests
, testCrateFlags
, testInputs
, testPreRun
, testPostRun
, buildKinds
}:
let
isDevBuild =
let
inherit (pkgs.buildRustCrateHelpers.kinds) isLib isBin isExample isTest isBench;

notDev = builtins.any (k: isLib k || isBin k) buildKinds;
isDev = builtins.any (k: isBench k || isExample k || isTest k) buildKinds;
in
assert (buildKinds != [ ]);
# Can't have build dev and non dev kinds
assert (notDev != isDev);
isDev;

buildRustCrateForPkgsFuncOverriden =
if buildRustCrateForPkgsFunc != null
then buildRustCrateForPkgsFunc
Expand All @@ -207,31 +129,16 @@ rec {
defaultCrateOverrides = crateOverrides;
}
);

builtRustCrates = builtRustCratesWithFeatures {
inherit packageId features;
inherit packageId features buildKinds isDevBuild;
buildRustCrateForPkgsFunc = buildRustCrateForPkgsFuncOverriden;
runTests = false;
};
builtTestRustCrates = builtRustCratesWithFeatures {
inherit packageId features;
buildRustCrateForPkgsFunc = buildRustCrateForPkgsFuncOverriden;
runTests = true;
};
drv = builtRustCrates.crates.${packageId};
testDrv = builtTestRustCrates.crates.${packageId};
derivation =
if runTests then
crateWithTest
{
crate = drv;
testCrate = testDrv;
inherit testCrateFlags testInputs testPreRun testPostRun;
}
else drv;

in
derivation
builtRustCrates.crates.${packageId}
)
{ inherit features crateOverrides runTests testCrateFlags testInputs testPreRun testPostRun; };
{ inherit features crateOverrides buildKinds; };

/* Returns an attr set with packageId mapped to the result of buildRustCrateForPkgsFunc
for the corresponding crate.
Expand All @@ -241,21 +148,24 @@ rec {
, features
, crateConfigs ? crates
, buildRustCrateForPkgsFunc
, runTests
, buildKinds
, isDevBuild
, makeTarget ? makeDefaultTarget
} @ args:
assert (builtins.isAttrs crateConfigs);
assert (builtins.isString packageId);
assert (builtins.isList features);
assert (builtins.isAttrs (makeTarget stdenv.hostPlatform));
assert (builtins.isBool runTests);
assert (builtins.isBool isDevBuild);
assert (builtins.isList buildKinds);
let
rootPackageId = packageId;
mergedFeatures = mergePackageFeatures
(
args // {
inherit rootPackageId;
target = makeTarget stdenv.hostPlatform // { test = runTests; };
# What does test do for target?
target = makeTarget stdenv.hostPlatform // { test = false; };
}
);
# Memoize built packages so that reappearing packages are only built once.
Expand All @@ -277,7 +187,7 @@ rec {
builtins.removeAttrs crateConfig' [ "resolvedDefaultFeatures" "devDependencies" ];
devDependencies =
lib.optionals
(runTests && packageId == rootPackageId)
(isDevBuild && packageId == rootPackageId)
(crateConfig'.devDependencies or [ ]);
dependencies =
dependencyDerivations {
Expand Down Expand Up @@ -351,6 +261,7 @@ rec {
}
);
extraRustcOpts = lib.lists.optional (targetFeatures != [ ]) "-C target-feature=${lib.concatMapStringsSep "," (x: "+${x}") targetFeatures}";
buildKinds = if (packageId == rootPackageId) then buildKinds else [ "lib" ];
inherit features dependencies buildDependencies crateRenames release;
}
);
Expand Down Expand Up @@ -472,7 +383,7 @@ rec {
, featuresByPackageId ? { }
, target
# Adds devDependencies to the crate with rootPackageId.
, runTests ? false
, isDevBuild ? false
, ...
} @ args:
assert (builtins.isAttrs crateConfigs);
Expand All @@ -482,7 +393,7 @@ rec {
assert (builtins.isList dependencyPath);
assert (builtins.isAttrs featuresByPackageId);
assert (builtins.isAttrs target);
assert (builtins.isBool runTests);
assert (builtins.isBool isDevBuild);
let
crateConfig = crateConfigs."${packageId}" or (builtins.throw "Package not found: ${packageId}");
expandedFeatures = expandFeatures (crateConfig.features or { }) features;
Expand Down Expand Up @@ -517,7 +428,7 @@ rec {
mergePackageFeatures {
features = combinedFeatures;
featuresByPackageId = cache;
inherit crateConfigs packageId target runTests rootPackageId;
inherit crateConfigs packageId target isDevBuild rootPackageId;
}
);
cacheWithSelf =
Expand All @@ -533,7 +444,7 @@ rec {
(
crateConfig.dependencies or [ ]
++ lib.optionals
(runTests && packageId == rootPackageId)
(isDevBuild && packageId == rootPackageId)
(crateConfig.devDependencies or [ ])
);
cacheWithAll =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ let
crate2nix.mergePackageFeatures
{
target = crate2nix.makeDefaultTarget (stdenv.hostPlatform);
runTests = false;
rootPackageId = packageId;
inherit crateConfigs packageId features;
};
Expand Down
3 changes: 0 additions & 3 deletions default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ let
in
!(baseName == "templates" && type == "directory");
crate2nix = cargoNix.rootCrate.build.override {
testCrateFlags = [
"--skip nix_integration_tests"
];
crateOverrides = defaultCrateOverrides // {
crate2nix = { src, ... }: {
src =
Expand Down
14 changes: 7 additions & 7 deletions nix/sources.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,15 @@
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"nixpkgs": {
"branch": "nixos-unstable",
"description": "A read-only mirror of NixOS/nixpkgs tracking the released channels. Send issues and PRs to",
"homepage": "https://github.com/NixOS/nixpkgs",
"owner": "NixOS",
"branch": "brc-kinds",
"description": "Nix Packages collection",
"homepage": "",
"owner": "jordanisaacs",
"repo": "nixpkgs",
"rev": "0c4800d579af4ed98ecc47d464a5e7b0870c4b1f",
"sha256": "00gx09447gzgxlzwih4hdj51sdg62xanikkgr4bv4y7fpm98qirq",
"rev": "812079dcb5dbbe5f89a02f107b840704f7bcb441",
"sha256": "16p1mh1xvvdnsrfr8ha1310zxvh6yfg0n1yhxs19rvax6c2xw9wv",
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs/archive/0c4800d579af4ed98ecc47d464a5e7b0870c4b1f.tar.gz",
"url": "https://github.com/jordanisaacs/nixpkgs/archive/812079dcb5dbbe5f89a02f107b840704f7bcb441.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"nixpkgs-mozilla": {
Expand Down
Loading

0 comments on commit bfbc55f

Please sign in to comment.