Skip to content

Commit

Permalink
feat: Add $LIMMAT_ARTIFACTS
Browse files Browse the repository at this point in the history
This is the first step - just enough to give you a place to drop data even if
you can't make much use of this.
  • Loading branch information
bjackman committed Dec 12, 2024
1 parent b473b60 commit ea014f3
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 10 deletions.
18 changes: 15 additions & 3 deletions src/database.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::{
fs::{create_dir_all, File, OpenOptions},
fs::{create_dir, create_dir_all, File, OpenOptions},
io::ErrorKind::AlreadyExists,
path::{Path, PathBuf},
};

Expand All @@ -12,6 +13,7 @@ use crate::{
flock::{ExclusiveFlock, SharedFlock},
git::Hash,
test::{ConfigHash, TestCase, TestJobOutput, TestName, TestResult},
util::IoResultExt as _,
};

// Result database similar to the design described in
Expand Down Expand Up @@ -162,7 +164,8 @@ impl DatabaseEntry {
// Output for an individual test job, stored into the database. Includes an exclusive lock on
// the database entry, nobody can read the result or run the test case until you drop this object.
pub struct DatabaseOutput {
base_dir: PathBuf, // Must exist.
base_dir: PathBuf, // Must exist.
artifacts_dir: PathBuf, // This too.
stdout_opened: bool,
stderr_opened: bool,
status_written: bool,
Expand All @@ -172,12 +175,17 @@ pub struct DatabaseOutput {

impl DatabaseOutput {
pub fn new(
base_dir: PathBuf,
base_dir: PathBuf, // Must exist.
config_hash: ConfigHash,
json_flock: ExclusiveFlock,
) -> anyhow::Result<Self> {
debug!("Creating database entry at {base_dir:?}");
let artifacts_dir = base_dir.join("artifacts").to_owned();
create_dir(&artifacts_dir)
.ignore(AlreadyExists)
.context("creating artifacts dir")?;
Ok(Self {
artifacts_dir,
base_dir,
stdout_opened: false,
stderr_opened: false,
Expand Down Expand Up @@ -217,6 +225,10 @@ impl TestJobOutput for DatabaseOutput {
.set_content(&serde_json::to_vec(&entry).expect("failed to serialize TestStatus"))
.context("writing JSON result")
}

fn artifacts_dir(&mut self) -> &Path {
&self.artifacts_dir
}
}

#[cfg(test)]
Expand Down
19 changes: 14 additions & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use std::collections::HashMap;
use std::ffi::OsString;
use std::fmt::Display;
use std::io::{stdout, Stdout};
use std::path::{absolute, PathBuf};
use std::path::{absolute, Path, PathBuf};
use std::pin::pin;
use std::process::Stdio;
use std::sync::Arc;
Expand Down Expand Up @@ -370,7 +370,9 @@ async fn ensure_job_success(
Ok(())
}

struct OneshotOutput {}
struct OneshotOutput {
artifacts_dir: PathBuf,
}

impl TestJobOutput for OneshotOutput {
type Stream = Stdio;
Expand All @@ -385,6 +387,9 @@ impl TestJobOutput for OneshotOutput {
eprintln!("Job result: {result:?}");
Ok(())
}
fn artifacts_dir(&mut self) -> &Path {
&self.artifacts_dir
}
}

// Run a set of tests at a given version, in worktrees, in parallel, unless
Expand Down Expand Up @@ -527,9 +532,13 @@ async fn test(
// Doesn't need a worktree, it's gonna do it live and direct in the main tree.
needs_resources.remove(&ResourceKey::Worktree);
let resources = env.config.resource_pools.get(needs_resources).await;
let result = job
.run_with(env.repo.path(), &resources, OneshotOutput {})
.await?;
let artifacts_dir = TempDir::with_prefix("limmat-artifacts-")?.into_path();
eprintln!(
"Test artifacts will be stored under {}",
artifacts_dir.display()
);
let output = OneshotOutput { artifacts_dir };
let result = job.run_with(env.repo.path(), &resources, output).await?;
eprintln!("Finished: {}", result);
Ok(())
}
Expand Down
7 changes: 5 additions & 2 deletions src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,8 @@ pub trait TestJobOutput {
fn stdout(&mut self) -> anyhow::Result<Self::Stream>;
// Panics if called more than once.
fn set_result(&mut self, result: &TestResult) -> anyhow::Result<()>;
// Extant directory for the job to put artifacts into.
fn artifacts_dir(&mut self) -> &Path;
}

// This is not really a proper type, it doesn't really mean anything except as an implementation
Expand Down Expand Up @@ -711,8 +713,9 @@ impl<'a> TestJob {
Ok(())
}

fn set_env(&self, cmd: &mut Command, resources: &Resources<'a>) {
fn set_env(&self, cmd: &mut Command, resources: &Resources<'a>, artifacts_dir: &Path) {
cmd.env("LIMMAT_COMMIT", &self.test_case.commit_hash);
cmd.env("LIMMAT_ARTIFACTS", artifacts_dir);
for (k, v) in self.base_env.iter() {
cmd.env(k, v);
}
Expand Down Expand Up @@ -745,7 +748,7 @@ impl<'a> TestJob {
cmd.current_dir(current_dir)
.stdout(output.stdout().context("no stdout handle available")?)
.stderr(output.stderr().context("no stdout handle available")?);
self.set_env(&mut cmd, resources);
self.set_env(&mut cmd, resources, output.artifacts_dir());
// It would be really confusing and annoying if we exited this function
// without ensuring the child is dead. So we wrap it in this sketchy
// drop guard thing.
Expand Down
20 changes: 20 additions & 0 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use core::fmt;
use std::{
fmt::{Display, Formatter},
future::Future,
io,
ops::Deref,
path::PathBuf,
str::FromStr,
Expand Down Expand Up @@ -110,3 +111,22 @@ pub struct Rect {
pub cols: usize,
pub rows: usize,
}

pub trait IoResultExt {
fn ignore(self, kind: io::ErrorKind) -> Self;
}

impl IoResultExt for io::Result<()> {
fn ignore(self, kind: io::ErrorKind) -> io::Result<()> {
match self {
Err(e) => {
if e.kind() == kind {
Ok(())
} else {
Err(e)
}
}
Ok(()) => Ok(()),
}
}
}

0 comments on commit ea014f3

Please sign in to comment.