Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build kinds support #285

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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")?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.context("Target shouuld have kind")?
.context("Target should 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
Comment on lines +111 to +113
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your PR rust-lang/cargo#11847 got closed due to inactivity. Do you still intend to resume this?

requiredFeatures = [ {% for feature in bin.required_features %}{{feature}} {% endfor %}];
}
{%- endfor %}
Expand Down
147 changes: 26 additions & 121 deletions crate2nix/templates/nix/crate2nix/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -89,112 +89,28 @@ 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) isExample isTest isBench;
in
builtins.any (k: isBench k || isExample k || isTest k) buildKinds;

buildRustCrateForPkgsFuncOverriden =
if buildRustCrateForPkgsFunc != null
then buildRustCrateForPkgsFunc
Expand All @@ -207,31 +123,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 +142,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 +181,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 +255,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 +377,7 @@ rec {
, featuresByPackageId ? { }
, target
# Adds devDependencies to the crate with rootPackageId.
, runTests ? false
, isDevBuild ? false
, ...
} @ args:
assert (builtins.isAttrs crateConfigs);
Expand All @@ -482,7 +387,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 +422,7 @@ rec {
mergePackageFeatures {
features = combinedFeatures;
featuresByPackageId = cache;
inherit crateConfigs packageId target runTests rootPackageId;
inherit crateConfigs packageId target isDevBuild rootPackageId;
}
);
cacheWithSelf =
Expand All @@ -533,7 +438,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": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👀

"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": "ba1f86f0f8c155b1d10fa306cdd321cd91c73bba",
"sha256": "070bcm65fl086f96hw7f4wy5n3f3xc6clriiqmciq6rc692a5lxx",
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs/archive/0c4800d579af4ed98ecc47d464a5e7b0870c4b1f.tar.gz",
"url": "https://github.com/jordanisaacs/nixpkgs/archive/ba1f86f0f8c155b1d10fa306cdd321cd91c73bba.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"nixpkgs-mozilla": {
Expand Down
Loading