Skip to content
Closed
35 changes: 34 additions & 1 deletion crates/cargo-wdk/src/actions/build/build_task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use std::path::{Path, PathBuf};
use anyhow::Result;
use cargo_metadata::Message;
use clap_cargo::Features;
use mockall::automock;
use mockall_double::double;
use tracing::debug;
use wdk_build::CpuArchitecture;
Expand All @@ -24,6 +25,7 @@ use crate::{
};

/// Parameters for constructing a [`BuildTask`].
#[derive(Clone, Copy)]
pub struct BuildTaskParams<'a> {
/// The name of the package to build
pub package_name: &'a str,
Expand All @@ -41,6 +43,32 @@ pub struct BuildTaskParams<'a> {
pub verbosity_level: clap_verbosity_flag::Verbosity,
}

#[derive(Debug, Default)]
#[cfg_attr(test, allow(dead_code))]
pub struct BuildTaskRunner {}

#[automock]
#[allow(clippy::unused_self, clippy::elidable_lifetime_names)]
#[cfg_attr(test, allow(dead_code))]
impl BuildTaskRunner {
// Returns `Box<dyn Iterator<...>>` rather than `impl Iterator<...>` because
// this method is `#[automock]`ed. mockall must be able to *name* the return
// type to generate the mock's expectation storage, and it cannot mock an
// opaque `impl Trait` return. Boxing into a trait object gives mockall a
// concrete, nameable type while still forwarding `BuildTask::run`'s lazy
// message stream, so consumers like `get_target_dir_from_output` can
// short-circuit instead of parsing/allocating every cargo message up front.
pub fn run<'a>(
&self,
params: &BuildTaskParams<'a>,
command_exec: &CommandExec,
) -> Result<Box<dyn Iterator<Item = Result<Message, std::io::Error>>>, BuildTaskError> {
BuildTask::new(*params, command_exec).run().map(|messages| {
Box::new(messages) as Box<dyn Iterator<Item = Result<Message, std::io::Error>>>
})
}
}

/// Builds specified package by running `cargo build`
pub struct BuildTask<'a> {
params: BuildTaskParams<'a>,
Expand Down Expand Up @@ -90,9 +118,14 @@ impl<'a> BuildTask<'a> {
/// not a valid unicode
/// * `BuildTaskError::CargoBuild` - If there is an error running the `cargo
/// build` command
// `+ use<>` opts this RPIT out of capturing the `&self` lifetime (edition
// 2024 captures in-scope lifetimes by default). The returned iterator owns
// its buffer (`Cursor<Vec<u8>>`), so it is effectively `'static`; opting out
// of the capture lets `BuildTaskRunner::run` move it out of the temporary
// `BuildTask` and box it as a `'static` trait object.
pub fn run(
&self,
) -> Result<impl Iterator<Item = Result<Message, std::io::Error>>, BuildTaskError> {
) -> Result<impl Iterator<Item = Result<Message, std::io::Error>> + use<>, BuildTaskError> {
debug!("Running cargo build");
let mut args = vec!["build".to_string()];
args.push("--message-format=json-render-diagnostics".to_string());
Expand Down
46 changes: 36 additions & 10 deletions crates/cargo-wdk/src/actions/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,17 @@ use std::{
};

use anyhow::Result;
use build_task::{BuildTask, BuildTaskParams};
use build_task::BuildTaskParams;
#[double]
use build_task::BuildTaskRunner;
use cargo_metadata::{CrateType, Message, Metadata as CargoMetadata, Package, TargetKind};
use clap_cargo::Features;
use error::BuildActionError;
use mockall_double::double;
use package_task::PackageTaskParams;
#[double]
use package_task::PackageTaskRunner;
pub use package_task::SignMode;
use package_task::{PackageTask, PackageTaskParams};
use tracing::{debug, error as err, info, trace, warn};
use wdk_build::{
CpuArchitecture,
Expand Down Expand Up @@ -63,6 +67,8 @@ pub struct BuildAction<'a> {
command_exec: &'a CommandExec,
fs: &'a Fs,
metadata: &'a Metadata,
build_task_runner: BuildTaskRunner,
package_task_runner: PackageTaskRunner,
}

impl<'a> BuildAction<'a> {
Expand All @@ -89,6 +95,26 @@ impl<'a> BuildAction<'a> {
command_exec: &'a CommandExec,
fs: &'a Fs,
metadata: &'a Metadata,
) -> Result<Self> {
Self::new_with_runners(
params,
wdk_build,
command_exec,
fs,
metadata,
BuildTaskRunner::default(),
PackageTaskRunner::default(),
)
}

fn new_with_runners(
params: &BuildActionParams<'a>,
wdk_build: &'a WdkBuild,
command_exec: &'a CommandExec,
fs: &'a Fs,
metadata: &'a Metadata,
build_task_runner: BuildTaskRunner,
package_task_runner: PackageTaskRunner,
) -> Result<Self> {
// TODO: validate params
anyhow::ensure!(
Expand All @@ -108,6 +134,8 @@ impl<'a> BuildAction<'a> {
command_exec,
fs,
metadata,
build_task_runner,
package_task_runner,
})
}

Expand Down Expand Up @@ -345,8 +373,8 @@ impl<'a> BuildAction<'a> {
let package_name = package.name.as_str();
info!("Building package {package_name}");

let build_task = BuildTask::new(
BuildTaskParams {
let output_message_iter = self.build_task_runner.run(
&BuildTaskParams {
package_name,
working_dir,
profile: self.profile,
Expand All @@ -356,8 +384,7 @@ impl<'a> BuildAction<'a> {
verbosity_level: self.verbosity_level,
},
self.command_exec,
);
let output_message_iter = build_task.run()?;
)?;

let wdk_metadata = if let Ok(wdk_metadata) = wdk_metadata {
debug!("Found wdk metadata in package: {}", package_name);
Expand Down Expand Up @@ -398,8 +425,8 @@ impl<'a> BuildAction<'a> {
target_dir.display()
);

PackageTask::new(
PackageTaskParams {
self.package_task_runner.run(
&PackageTaskParams {
package_name,
working_dir,
target_dir: &target_dir,
Expand All @@ -411,8 +438,7 @@ impl<'a> BuildAction<'a> {
self.wdk_build,
self.command_exec,
self.fs,
)
.run()?;
)?;

info!("Finished building {package_name}");
Ok(())
Expand Down
Loading