add complement wrapper xtask script

This commit is contained in:
Benjamin Lee 2024-06-20 19:06:57 -07:00
parent 3f89bc4a7c
commit ef6eb27b9b
No known key found for this signature in database
GPG key ID: FB9624E2885D55A4
10 changed files with 292 additions and 0 deletions

14
xtask/Cargo.toml Normal file
View file

@ -0,0 +1,14 @@
[package]
name = "xtask"
version = "0.1.0"
edition = "2021"
license.workspace = true
rust-version.workspace = true
[dependencies]
clap.workspace = true
miette.workspace = true
xshell.workspace = true
[lints]
workspace = true

32
xtask/src/complement.rs Normal file
View file

@ -0,0 +1,32 @@
use std::path::PathBuf;
use miette::{IntoDiagnostic, Result, WrapErr};
use xshell::{cmd, Shell};
mod docker;
mod test2json;
use self::{docker::load_docker_image, test2json::run_complement};
#[derive(clap::Args)]
pub(crate) struct Args;
#[allow(clippy::needless_pass_by_value)]
pub(crate) fn main(_args: Args) -> Result<()> {
let sh = Shell::new().unwrap();
let toplevel = get_toplevel_path(&sh)
.wrap_err("failed to determine repository root directory")?;
let docker_image = load_docker_image(&sh, &toplevel).wrap_err(
"failed to build and load complement-grapevine docker image",
)?;
run_complement(&sh, &docker_image)
.wrap_err("failed to run complement tests")?;
Ok(())
}
/// Returns the path to the repository root
fn get_toplevel_path(sh: &Shell) -> Result<PathBuf> {
let path =
cmd!(sh, "git rev-parse --show-toplevel").read().into_diagnostic()?;
Ok(path.into())
}

View file

@ -0,0 +1,58 @@
//! Functions for working with docker images and containers.
use std::path::Path;
use miette::{miette, IntoDiagnostic, LabeledSpan, Result, WrapErr};
use xshell::{cmd, Shell};
/// Build the 'grapevine-complement' OCI image and load it into the docker
/// daemon.
pub(crate) fn load_docker_image(sh: &Shell, toplevel: &Path) -> Result<String> {
// > i would Not trust that parser as far as i can throw it
// - @jade_:matrix.org, 2024-06-19
//
// So we're not even gonna try to escape the arbitrary top level path
// correctly for a flake installable reference. Instead we're just gonna cd
// into toplevel before running nix commands.
let _pushd_guard = sh.push_dir(toplevel);
let installable = ".#complement-grapevine-oci-image";
cmd!(sh, "nix-build-and-cache just {installable} -- --no-link")
.run()
.into_diagnostic()
.wrap_err("error building complement-grapevine-oci-image")?;
let oci_image_path = cmd!(sh, "nix path-info {installable}")
.read()
.into_diagnostic()
.wrap_err(
"error getting nix store path for complement-grapevine-oci-image",
)?;
// Instead of building the image with a fixed tag, we let nix choose the tag
// based on the input hash, and then determine the image/tag it used by
// parsing the 'docker load' output. This is to avoid a race condition
// between multiple concurrent 'xtask complement' invocations, which might
// otherwise assign the same tag to different images.
let load_output = cmd!(sh, "docker image load --input {oci_image_path}")
.read()
.into_diagnostic()
.wrap_err("error loading complement-grapevine docker image")?;
let expected_prefix = "Loaded image: ";
let docker_image = load_output
.strip_prefix(expected_prefix)
.ok_or_else(|| {
// Miette doesn't support inclusive ranges.
// <https://github.com/zkat/miette/pull/385>
#[allow(clippy::range_plus_one)]
let span = 0..(expected_prefix.len().min(load_output.len()) + 1);
let label =
LabeledSpan::at(span, format!("Expected {expected_prefix:?}"));
miette!(
labels = vec![label],
"failed to parse 'docker image load' output"
)
.with_source_code(load_output.clone())
})?
.to_owned();
Ok(docker_image)
}

View file

@ -0,0 +1,19 @@
//! Functions for working with the go [`test2json`][test2json] tool.
//!
//! [test2json]: https://pkg.go.dev/cmd/test2json@go1.22.4
use miette::{IntoDiagnostic, Result};
use xshell::{cmd, Shell};
/// Runs complement test suite
pub(crate) fn run_complement(sh: &Shell, docker_image: &str) -> Result<()> {
// TODO: handle SIG{INT,TERM}
// TODO: XTASK_PATH variable, so that we don't need to pollute devshell with
// go
cmd!(sh, "go tool test2json complement.test -test.v=test2json")
.env("COMPLEMENT_BASE_IMAGE", docker_image)
.env("COMPLEMENT_SPAWN_HS_TIMEOUT", "5")
.env("COMPLEMENT_ALWAYS_PRINT_SERVER_LOGS", "1")
.run()
.into_diagnostic()
}

30
xtask/src/main.rs Normal file
View file

@ -0,0 +1,30 @@
mod complement;
use std::process::ExitCode;
use clap::{Parser, Subcommand};
#[derive(Parser)]
struct Args {
#[clap(subcommand)]
command: Command,
}
#[derive(Subcommand)]
enum Command {
Complement(complement::Args),
}
fn main() -> ExitCode {
let args = Args::parse();
let result = match args.command {
Command::Complement(args) => complement::main(args),
};
let Err(e) = result else {
return ExitCode::SUCCESS;
};
// Include a leading newline because sometimes an error will occur in
// the middle of displaying a progress indicator.
eprintln!("\n{e:?}");
ExitCode::FAILURE
}