Skip to content
Open
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
53 changes: 50 additions & 3 deletions src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub struct BuildBuilder<'a> {
krate: &'a Crate,
sandbox: SandboxBuilder,
patches: Vec<CratePatch>,
extra_cargo_args: Vec<String>,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

let's follow the pattern we have in cmd::Command

Suggested change
extra_cargo_args: Vec<String>,
extra_cargo_args: Vec<OsString>,

}

/// Output of a completed build together with build-level statistics.
Expand Down Expand Up @@ -131,6 +132,36 @@ impl BuildBuilder<'_> {
self
}

/// Add extra arguments passed to cargo commands during the prepare phase
/// (manifest validation, lockfile generation, dependency fetching).
///
/// This is useful for passing unstable cargo flags (e.g. `-Zbindeps`) that
/// are required for cargo to parse the crate's manifest.
///
/// # Example
///
/// ```no_run
/// # use rustwide::{WorkspaceBuilder, Toolchain, Crate, cmd::SandboxBuilder};
/// # use std::error::Error;
/// # fn main() -> anyhow::Result<(), Box<dyn Error>> {
/// # let workspace = WorkspaceBuilder::new("".as_ref(), "").init()?;
/// # let toolchain = Toolchain::dist("");
/// # let krate = Crate::local("".as_ref());
/// # let sandbox = SandboxBuilder::new();
/// let mut build_dir = workspace.build_dir("foo");
/// build_dir.build(&toolchain, &krate, sandbox)
/// .extra_cargo_args(vec!["-Zbindeps".into()])
/// .run(|build| {
/// build.cargo().args(&["test", "--all"]).run()?;
/// Ok(())
/// })?;
/// # Ok(())
/// # }
pub fn extra_cargo_args(mut self, args: Vec<String>) -> Self {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

same here, the pattern from Command::args()

    pub fn extra_cargo_args<S: Into<OsString>>(
        mut self,
        args: impl IntoIterator<Item = S>,
    ) -> Self {
        self.extra_cargo_args
            .extend(args.into_iter().map(Into::into));

        self
    }

self.extra_cargo_args = args;
self
}

/// Run a sandboxed build of the provided crate with the provided toolchain. The closure will
/// be provided an instance of [`Build`](struct.Build.html) that allows spawning new processes
/// inside the sandbox.
Expand Down Expand Up @@ -162,8 +193,14 @@ impl BuildBuilder<'_> {
self,
f: F,
) -> anyhow::Result<BuildResult<R>> {
self.build_dir
.run(self.toolchain, self.krate, self.sandbox, self.patches, f)
self.build_dir.run(
self.toolchain,
self.krate,
self.sandbox,
self.patches,
self.extra_cargo_args,
f,
)
}
}

Expand Down Expand Up @@ -208,6 +245,7 @@ impl BuildDirectory {
krate,
sandbox,
patches: Vec::new(),
extra_cargo_args: Vec::new(),
}
}

Expand All @@ -229,14 +267,22 @@ impl BuildDirectory {
krate: &Crate,
sandbox: SandboxBuilder,
patches: Vec<CratePatch>,
extra_cargo_args: Vec<String>,
f: F,
) -> anyhow::Result<BuildResult<R>> {
let source_dir = self.source_dir();
if source_dir.exists() {
crate::utils::remove_dir_all(&source_dir)?;
}

let mut prepare = Prepare::new(&self.workspace, toolchain, krate, &source_dir, patches);
let mut prepare = Prepare::new(
&self.workspace,
toolchain,
krate,
&source_dir,
patches,
extra_cargo_args,
);
prepare.prepare().map_err(|err| {
if err.downcast_ref::<PrepareError>().is_none() {
err.context(PrepareError::Uncategorized)
Expand Down Expand Up @@ -407,6 +453,7 @@ impl<'ws> Build<'ws> {
self.toolchain,
&self.host_source_dir(),
targets,
&[],
)
}
}
22 changes: 16 additions & 6 deletions src/prepare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub(crate) struct Prepare<'a> {
krate: &'a Crate,
source_dir: &'a Path,
patches: Vec<CratePatch>,
extra_cargo_args: Vec<String>,
}

impl<'a> Prepare<'a> {
Expand All @@ -23,13 +24,15 @@ impl<'a> Prepare<'a> {
krate: &'a Crate,
source_dir: &'a Path,
patches: Vec<CratePatch>,
extra_cargo_args: Vec<String>,
) -> Self {
Self {
workspace,
toolchain,
krate,
source_dir,
patches,
extra_cargo_args,
}
}

Expand Down Expand Up @@ -70,6 +73,7 @@ impl<'a> Prepare<'a> {

let res = Command::new(self.workspace, self.toolchain.cargo())
.args(["metadata", "--manifest-path", "Cargo.toml", "--no-deps"])
.args(&self.extra_cargo_args)
.current_directory(self.source_dir)
.log_output(false)
.run();
Expand Down Expand Up @@ -117,11 +121,9 @@ impl<'a> Prepare<'a> {
return Ok(());
}

let mut cmd = Command::new(self.workspace, self.toolchain.cargo()).args([
"generate-lockfile",
"--manifest-path",
"Cargo.toml",
]);
let mut cmd = Command::new(self.workspace, self.toolchain.cargo())
.args(["generate-lockfile", "--manifest-path", "Cargo.toml"])
.args(&self.extra_cargo_args);
if !self.workspace.fetch_registry_index_during_builds() {
cmd = cmd
.args(["-Zno-index-update"])
Expand All @@ -133,7 +135,13 @@ impl<'a> Prepare<'a> {

#[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
fn fetch_deps(&mut self) -> anyhow::Result<()> {
fetch_deps(self.workspace, self.toolchain, self.source_dir, &[])
fetch_deps(
self.workspace,
self.toolchain,
self.source_dir,
&[],
&self.extra_cargo_args,
)
}
}

Expand All @@ -153,9 +161,11 @@ pub(crate) fn fetch_deps(
toolchain: &Toolchain,
source_dir: &Path,
fetch_build_std_targets: &[&str],
extra_cargo_args: &[String],
) -> anyhow::Result<()> {
let mut cmd = Command::new(workspace, toolchain.cargo())
.args(["fetch", "--manifest-path", "Cargo.toml"])
.args(extra_cargo_args)
.current_directory(source_dir);
// Pass `-Zbuild-std` in case a build in the sandbox wants to use it;
// build-std has to have the source for libstd's dependencies available.
Expand Down
31 changes: 31 additions & 0 deletions tests/buildtest/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,37 @@ fn test_cargo_workspace() {
});
}

#[test]
fn test_extra_cargo_args() {
runner::run("hello-world", |run| {
run.build(SandboxBuilder::new().enable_networking(false), |builder| {
builder
.extra_cargo_args(vec!["--quiet".into()])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

can we somehow assert that this cargo arg is actually working?

Like, checking stdout for the output that this suppresses?

.run(|build| {
build.cargo().args(&["run"]).run()?;
Ok(())
})
})?;
Ok(())
});
}

#[test]
fn test_extra_cargo_args_invalid() {
runner::run("hello-world", |run| {
let res = run.build(SandboxBuilder::new().enable_networking(false), |builder| {
builder
.extra_cargo_args(vec!["--invalid-flag-that-does-not-exist".into()])
.run(|_build| Ok(()))
});
assert!(
res.is_err(),
"expected extra cargo args to cause a prepare failure"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

can we assert something that ensures that the invalid flag is the actual error? perhaps just reading stdout and checking what's in it?

);
Ok(())
});
}

test_prepare_error!(
test_missing_cargotoml,
"missing-cargotoml",
Expand Down
Loading