Skip to content

Commit

Permalink
"external xtasks" pattern; wire up cargo xtask releng (#5783)
Browse files Browse the repository at this point in the history
  • Loading branch information
iliana authored May 20, 2024
1 parent c2f51e2 commit a5213df
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 4 deletions.
2 changes: 1 addition & 1 deletion .github/buildomat/jobs/tuf-repo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,4 @@ esac
pfexec zfs create -p "rpool/images/$USER/host"
pfexec zfs create -p "rpool/images/$USER/recovery"

cargo run --release --bin omicron-releng -- --output-dir /work
cargo xtask releng --output-dir /work
3 changes: 2 additions & 1 deletion dev-tools/releng/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,15 @@ static WORKSPACE_DIR: Lazy<Utf8PathBuf> = Lazy::new(|| {
dir
});

#[derive(Parser)]
/// Run the Oxide release engineering process and produce a TUF repo that can be
/// used to update a rack.
///
/// For more information, see `docs/releng.adoc` in the Omicron repository.
///
/// Note that `--host-dataset` and `--recovery-dataset` must be set to different
/// values to build the two OS images in parallel. This is strongly recommended.
#[derive(Parser)]
#[command(name = "cargo xtask releng", bin_name = "cargo xtask releng")]
struct Args {
/// ZFS dataset to use for `helios-build` when building the host image
#[clap(long, default_value_t = Self::default_dataset("host"))]
Expand Down
72 changes: 72 additions & 0 deletions dev-tools/xtask/src/external.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

//! External xtasks. (extasks?)
use std::ffi::{OsStr, OsString};
use std::os::unix::process::CommandExt;
use std::process::Command;

use anyhow::{Context, Result};
use clap::Parser;

/// Argument parser for external xtasks.
///
/// In general we want all developer tasks to be discoverable simply by running
/// `cargo xtask`, but some development tools end up with a particularly
/// large dependency tree. It's not ideal to have to pay the cost of building
/// our release engineering tooling if all the user wants to do is check for
/// workspace dependency issues.
///
/// `External` provides a pattern for creating xtasks that live in other crates.
/// An external xtask is defined on `crate::Cmds` as a tuple variant containing
/// `External`, which captures all arguments and options (even `--help`) as
/// a `Vec<OsString>`. The main function then calls `External::exec` with the
/// appropriate bin target name and any additional Cargo arguments.
#[derive(Parser)]
#[clap(
disable_help_flag(true),
disable_help_subcommand(true),
disable_version_flag(true)
)]
pub struct External {
#[clap(trailing_var_arg(true), allow_hyphen_values(true))]
args: Vec<OsString>,

// This stores an in-progress Command builder. `cargo_args` appends args
// to it, and `exec` consumes it. Clap does not treat this as a command
// (`skip`), but fills in this field by calling `new_command`.
#[clap(skip = new_command())]
command: Command,
}

impl External {
/// Add additional arguments to `cargo run` (for instance, to run the
/// external xtask in release mode).
pub fn cargo_args(
mut self,
args: impl IntoIterator<Item = impl AsRef<OsStr>>,
) -> External {
self.command.args(args);
self
}

pub fn exec(mut self, bin_target: impl AsRef<OsStr>) -> Result<()> {
let error = self
.command
.arg("--bin")
.arg(bin_target)
.arg("--")
.args(self.args)
.exec();
Err(error).context("failed to exec `cargo run`")
}
}

fn new_command() -> Command {
let cargo = std::env::var_os("CARGO").unwrap_or_else(|| "cargo".into());
let mut command = Command::new(cargo);
command.arg("run");
command
}
20 changes: 18 additions & 2 deletions dev-tools/xtask/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,20 @@ use clap::{Parser, Subcommand};

mod check_workspace_deps;
mod clippy;
#[cfg_attr(not(target_os = "illumos"), allow(dead_code))]
mod external;

#[cfg(target_os = "illumos")]
mod verify_libraries;
#[cfg(target_os = "illumos")]
mod virtual_hardware;

#[derive(Parser)]
#[command(name = "cargo xtask", about = "Workspace-related developer tools")]
#[command(
name = "cargo xtask",
bin_name = "cargo xtask",
about = "Workspace-related developer tools"
)]
struct Args {
#[command(subcommand)]
cmd: Cmds,
Expand All @@ -33,6 +39,9 @@ enum Cmds {
/// Run configured clippy checks
Clippy(clippy::ClippyArgs),

#[cfg(target_os = "illumos")]
/// Build a TUF repo
Releng(external::External),
/// Verify we are not leaking library bindings outside of intended
/// crates
#[cfg(target_os = "illumos")]
Expand All @@ -41,6 +50,9 @@ enum Cmds {
#[cfg(target_os = "illumos")]
VirtualHardware(virtual_hardware::Args),

/// (this command is only available on illumos)
#[cfg(not(target_os = "illumos"))]
Releng,
/// (this command is only available on illumos)
#[cfg(not(target_os = "illumos"))]
VerifyLibraries,
Expand All @@ -55,13 +67,17 @@ fn main() -> Result<()> {
Cmds::Clippy(args) => clippy::run_cmd(args),
Cmds::CheckWorkspaceDeps => check_workspace_deps::run_cmd(),

#[cfg(target_os = "illumos")]
Cmds::Releng(external) => {
external.cargo_args(["--release"]).exec("omicron-releng")
}
#[cfg(target_os = "illumos")]
Cmds::VerifyLibraries(args) => verify_libraries::run_cmd(args),
#[cfg(target_os = "illumos")]
Cmds::VirtualHardware(args) => virtual_hardware::run_cmd(args),

#[cfg(not(target_os = "illumos"))]
Cmds::VerifyLibraries | Cmds::VirtualHardware => {
Cmds::Releng | Cmds::VerifyLibraries | Cmds::VirtualHardware => {
anyhow::bail!("this command is only available on illumos");
}
}
Expand Down

0 comments on commit a5213df

Please sign in to comment.