Skip to content

Add automatic lcov and cargo-fuzz installation to restore packages workflow #1592

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

Draft
wants to merge 3 commits into
base: main
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
109 changes: 109 additions & 0 deletions flowey/flowey_lib_common/src/install_lcov.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

//! Globally install lcov and ensure it is available on the user's $PATH

use flowey::node::prelude::*;

new_flow_node!(struct Node);

flowey_request! {
pub enum Request {
/// Ensure that lcov was installed and is available on $PATH
EnsureInstalled(WriteVar<SideEffect>),

/// Automatically install lcov
LocalOnlyAutoInstall(bool),
}
}

impl FlowNode for Node {
type Request = Request;

fn imports(dep: &mut ImportCtx<'_>) {
dep.import::<crate::check_needs_relaunch::Node>();
dep.import::<crate::install_dist_pkg::Node>();
}

fn emit(requests: Vec<Self::Request>, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
let mut ensure_installed = Vec::new();
let mut auto_install = None;

for req in requests {
match req {
Request::EnsureInstalled(v) => ensure_installed.push(v),
Request::LocalOnlyAutoInstall(v) => {
same_across_all_reqs("LocalOnlyAutoInstall", &mut auto_install, v)?
}
}
}

let ensure_installed = ensure_installed;
let auto_install = auto_install.ok_or(anyhow::anyhow!(
"Missing essential request: LocalOnlyAutoInstall",
))?;

// -- end of req processing -- //

if ensure_installed.is_empty() {
return Ok(());
}

if auto_install {
let (read_bin, write_bin) = ctx.new_var();
ctx.req(crate::check_needs_relaunch::Params {
check: read_bin,
done: ensure_installed,
});

let lcov_installed = ctx.reqv(|v| crate::install_dist_pkg::Request::Install {
package_names: vec!["lcov".into()],
done: v,
});

ctx.emit_rust_step("install lcov", |ctx| {
let write_bin = write_bin.claim(ctx);
lcov_installed.claim(ctx);

|rt: &mut RustRuntimeServices<'_>| {
match rt.platform() {
FlowPlatform::Linux(_) => {
rt.write(write_bin, &Some(crate::check_needs_relaunch::BinOrEnv::Bin("lcov".to_string())));
Ok(())
},
FlowPlatform::MacOs => {
// On macOS, try to install via homebrew if available
if which::which("brew").is_ok() {
let sh = xshell::Shell::new()?;
xshell::cmd!(sh, "brew install lcov").run()?;
} else {
log::warn!("lcov installation on macOS requires homebrew. Please install homebrew and run 'brew install lcov'");
}
rt.write(write_bin, &Some(crate::check_needs_relaunch::BinOrEnv::Bin("lcov".to_string())));
Ok(())
},
FlowPlatform::Windows => {
log::warn!("lcov is not typically available on Windows. Consider using Windows Subsystem for Linux (WSL) for coverage reports.");
rt.write(write_bin, &None);
Ok(())
},
platform => anyhow::bail!("unsupported platform {platform}"),
}
}
});
} else {
ctx.emit_rust_step("ensure lcov is installed", |ctx| {
ensure_installed.claim(ctx);
|_rt| {
if which::which("lcov").is_err() {
anyhow::bail!("Please install lcov to continue (e.g., 'apt install lcov' on Ubuntu, 'brew install lcov' on macOS).");
}

Ok(())
}
});
}

Ok(())
}
}
1 change: 1 addition & 0 deletions flowey/flowey_lib_common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub mod install_azure_cli;
pub mod install_cargo_nextest;
pub mod install_dist_pkg;
pub mod install_git;
pub mod install_lcov;
pub mod install_nodejs;
pub mod install_nuget_azure_credential_provider;
pub mod install_rust;
Expand Down
4 changes: 4 additions & 0 deletions flowey/flowey_lib_hvlite/src/_jobs/cfg_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ impl SimpleFlowNode for Node {
ctx.import::<flowey_lib_common::install_dist_pkg::Node>();
ctx.import::<flowey_lib_common::install_azure_cli::Node>();
ctx.import::<flowey_lib_common::install_git::Node>();
ctx.import::<flowey_lib_common::install_lcov::Node>();
ctx.import::<flowey_lib_common::install_nodejs::Node>();
ctx.import::<flowey_lib_common::install_nuget_azure_credential_provider::Node>();
ctx.import::<flowey_lib_common::install_rust::Node>();
Expand Down Expand Up @@ -154,6 +155,9 @@ impl SimpleFlowNode for Node {
ctx.req(
flowey_lib_common::install_git::Request::LocalOnlyAutoInstall(auto_install),
);
ctx.req(
flowey_lib_common::install_lcov::Request::LocalOnlyAutoInstall(auto_install),
);
}

//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,19 @@ impl SimpleFlowNode for Node {
ctx.import::<crate::init_openvmm_magicpath_openhcl_sysroot::Node>();
ctx.import::<crate::init_openvmm_magicpath_protoc::Node>();
ctx.import::<crate::init_openvmm_magicpath_uefi_mu_msvm::Node>();
ctx.import::<flowey_lib_common::download_cargo_fuzz::Node>();
ctx.import::<flowey_lib_common::install_lcov::Node>();
}

fn process_request(request: Self::Request, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
let Request { arch, done } = request;

let mut deps = vec![ctx.reqv(crate::init_openvmm_magicpath_protoc::Request)];

// Install tools for fuzzing
deps.push(ctx.reqv(|done| flowey_lib_common::install_lcov::Request::EnsureInstalled(done)));
deps.push(ctx.reqv(flowey_lib_common::download_cargo_fuzz::Request::InstallWithCargo));

match arch {
CommonArch::X86_64 => {
if matches!(ctx.platform(), FlowPlatform::Linux(_)) {
Expand Down
2 changes: 1 addition & 1 deletion xtask/src/tasks/fuzz/html_coverage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ pub(super) fn generate_html_coverage_report(

if which::which("lcov").is_err() {
anyhow::bail!(
"could not find `lcov` on your $PATH! make sure it's installed (e.g: `apt install lcov`)"
"could not find `lcov` on your $PATH! Run `xflowey restore` to auto-install it, or install manually (e.g: `apt install lcov`)"
)
}

Expand Down