Skip to content

Commit

Permalink
refactor to build specific bins and features
Browse files Browse the repository at this point in the history
  • Loading branch information
iliana committed Jun 21, 2024
1 parent fd864a6 commit 7851944
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 68 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ workspace = true
[dependencies]
anyhow.workspace = true
camino.workspace = true
cargo_metadata.workspace = true
clap.workspace = true
futures.workspace = true
hex.workspace = true
illumos-utils.workspace = true
indicatif.workspace = true
omicron-workspace-hack.workspace = true
omicron-zone-package.workspace = true
petgraph.workspace = true
rayon.workspace = true
Expand All @@ -30,13 +32,11 @@ slog-bunyan.workspace = true
slog-term.workspace = true
smf.workspace = true
strum.workspace = true
swrite.workspace = true
tar.workspace = true
thiserror.workspace = true
tokio = { workspace = true, features = [ "full" ] }
toml.workspace = true
walkdir.workspace = true
omicron-workspace-hack.workspace = true

[dev-dependencies]
expectorate.workspace = true
Expand Down
155 changes: 90 additions & 65 deletions package/src/bin/omicron-package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,13 @@ use slog::o;
use slog::Drain;
use slog::Logger;
use slog::{info, warn};
use std::collections::BTreeMap;
use std::collections::{BTreeMap, BTreeSet};
use std::env;
use std::fs::create_dir_all;
use std::io::Write;
use std::str::FromStr;
use std::sync::{Arc, OnceLock};
use std::time::Duration;
use swrite::{swrite, SWrite};
use tokio::io::{AsyncReadExt, AsyncWriteExt, BufReader};
use tokio::process::Command;

Expand Down Expand Up @@ -106,81 +105,107 @@ struct Args {
subcommand: SubCommand,
}

async fn run_cargo_on_packages<I, S>(
subcmd: &str,
packages: I,
#[derive(Debug, Default)]
struct CargoPlan<'a> {
command: &'a str,
bins: BTreeSet<&'a String>,
features: BTreeSet<&'a String>,
release: bool,
features: &str,
) -> Result<()>
where
I: IntoIterator<Item = S>,
S: AsRef<std::ffi::OsStr>,
{
let mut cmd = Command::new("cargo");
// We rely on the rust-toolchain.toml file for toolchain information,
// rather than specifying one within the packaging tool.
cmd.arg(subcmd);
for package in packages {
cmd.arg("-p").arg(package);
}
cmd.arg("--features").arg(features);
if release {
cmd.arg("--release");
}
let status = cmd
.status()
.await
.context(format!("Failed to run command: ({:?})", cmd))?;
if !status.success() {
bail!("Failed to build packages");
}
}

Ok(())
impl<'a> CargoPlan<'a> {
async fn run(&self, log: &Logger) -> Result<()> {
if self.bins.is_empty() {
return Ok(());
}

let mut cmd = Command::new("cargo");
// We rely on the rust-toolchain.toml file for toolchain information,
// rather than specifying one within the packaging tool.
cmd.arg(self.command);
for bin in &self.bins {
cmd.arg("--bin").arg(bin);
}
if !self.features.is_empty() {
cmd.arg("--features").arg(self.features.iter().fold(
String::new(),
|mut acc, s| {
if !acc.is_empty() {
acc.push(' ');
}
acc.push_str(s);
acc
},
));
}
if self.release {
cmd.arg("--release");
}
info!(log, "running: {:?}", cmd.as_std());
let status = cmd
.status()
.await
.context(format!("Failed to run command: ({:?})", cmd))?;
if !status.success() {
bail!("Failed to build packages");
}

Ok(())
}
}

async fn do_for_all_rust_packages(
config: &Config,
command: &str,
) -> Result<()> {
// First, filter out all Rust packages from the configuration that should be
// built, and partition them into "release" and "debug" categories.
let (release_pkgs, debug_pkgs): (Vec<_>, _) = config
.packages_to_build()
.0
// Collect a map of all of the workspace packages
let workspace = cargo_metadata::MetadataCommand::new().exec()?;
let workspace_pkgs = workspace
.packages
.into_iter()
.filter_map(|(name, pkg)| match &pkg.source {
PackageSource::Local { rust: Some(rust_pkg), .. } => {
Some((name, rust_pkg.release))
}
_ => None,
.filter_map(|package| {
workspace
.workspace_members
.contains(&package.id)
.then_some((package.name.clone(), package))
})
.partition(|(_, release)| *release);
.collect::<BTreeMap<_, _>>();

let features =
config.target.0.iter().fold(String::new(), |mut acc, (name, value)| {
swrite!(acc, "{}-{} ", name, value);
acc
});

// Execute all the release / debug packages at the same time.
if !release_pkgs.is_empty() {
run_cargo_on_packages(
command,
release_pkgs.iter().map(|(name, _)| name),
true,
&features,
)
.await?;
}
if !debug_pkgs.is_empty() {
run_cargo_on_packages(
command,
debug_pkgs.iter().map(|(name, _)| name),
false,
&features,
)
.await?;
// Generate a list of all features we might want to request
let features = config
.target
.0
.iter()
.map(|(name, value)| format!("{name}-{value}"))
.collect::<BTreeSet<_>>();

// We split the packages to be built into "release" and "debug" lists
let mut release =
CargoPlan { command, release: true, ..Default::default() };
let mut debug = CargoPlan { command, release: false, ..Default::default() };

for (name, pkg) in config.packages_to_build().0 {
// If this is a Rust package...
if let PackageSource::Local { rust: Some(rust_pkg), .. } = &pkg.source {
let plan = if rust_pkg.release { &mut release } else { &mut debug };
// Add the binaries we want to build to the plan
plan.bins.extend(&rust_pkg.binary_names);
// Get the package metadata
let metadata = workspace_pkgs.get(name).with_context(|| {
format!("package '{name}' is not a workspace package")
})?;
// Add all features we want to request to the plan
plan.features.extend(
metadata
.features
.keys()
.filter(|feature| features.contains(*feature)),
);
}
}

release.run(&config.log).await?;
debug.run(&config.log).await?;
Ok(())
}

Expand Down

0 comments on commit 7851944

Please sign in to comment.