Skip to content

Commit

Permalink
Revert "Rename cargo-metest to cargo-maelstrom."
Browse files Browse the repository at this point in the history
This reverts commit 717c442.

This commit meant to rename cargo-metest, but instead it ended up
accidentally deleting it. I'm reverting it so we can try again.
  • Loading branch information
bobbobbio committed Jan 14, 2024
1 parent 717c442 commit df673a4
Show file tree
Hide file tree
Showing 36 changed files with 6,955 additions and 54 deletions.
14 changes: 7 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### `cargo-maelstrom`
### `cargo-metest`

#### Added
- The `--include` and `--exclude` long option names for `-i` and `-x`.
Expand All @@ -30,7 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
flags. `list` also takes an optional positional argument to indicate what
type of artifact to list. The `-v`, `-h`, and `-b` flags remain at the top
level. The `quiet` configuration option also has moved into a new sub-section
for the run command in `cargo-maelstrom.toml`.
for the run command in `cargo-metest.toml`.
[Issue #118](https://github.com/meticulous-software/meticulous/issues/118)

#### Fixed
Expand All @@ -51,7 +51,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Ability to create a build environment using [`nix`](https://nixos.org).
- Renamed `maelstrom-client` binary to `maelstrom-client-cli`.

### `cargo-maelstrom`
### `cargo-metest`

#### Added

Expand All @@ -77,7 +77,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
#### Changed

- The JSON language used to specify jobs. This now has all of the features of
the language used by `cargo-maelstrom`, including specifying parts of an image
the language used by `cargo-metest`, including specifying parts of an image
to use.
[Issue #103](https://github.com/meticulous-software/meticulous/issues/103)

Expand All @@ -99,7 +99,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
`maelstrom-client`.
[Issue #70](https://github.com/meticulous-software/meticulous/issues/70).

### `cargo-maelstrom`
### `cargo-metest`

#### Added

Expand All @@ -119,7 +119,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
worked on. There is an new, "pop-up", status bar when tar files are being
generated. Plus other small improvements.
- Initial progress bar accuracy by remembering how many tests there were the
last time `cargo-maelstrom` was run.
last time `cargo-metest` was run.

#### Changed

Expand All @@ -137,7 +137,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Binaries for the clustered job runner: `maelstrom-worker`,
`maelstrom-broker`, and `maelstrom-client`.
- Client library for communicating with the broker: `maelstrom-client`.
- A Rust test runner that uses the clustered job runner: `cargo-maelstrom`.
- A Rust test runner that uses the clustered job runner: `cargo-metest`.
- A bunch of other library packages that are used internally.

[unreleased]: https://github.com/meticulous-software/meticulous/compare/v0.3.0...HEAD
Expand Down
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.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ this repository and use `cargo install`.
Something like this should work:

```sh
for i in meticulous-{broker,worker,client} cargo-maelstrom; do
for i in meticulous-{broker,worker,client} cargo-metest; do
cargo install --git https://github.com/meticulous-software/meticulous.git $i
done
```
41 changes: 41 additions & 0 deletions crates/cargo-metest/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
[package]
name = "cargo-metest"
version.workspace = true
edition.workspace = true

[dependencies]
anyhow.workspace = true
cargo_metadata.workspace = true
clap.workspace = true
colored.workspace = true
combine.workspace = true
console.workspace = true
derive_more.workspace = true
enumset.workspace = true
figment.workspace = true
globset.workspace = true
indicatif.workspace = true
lddtree.workspace = true
maelstrom-base.workspace = true
maelstrom-client.workspace = true
maelstrom-util.workspace = true
regex.workspace = true
regex-macro.workspace = true
serde.workspace = true
serde_json.workspace = true
serde_repr.workspace = true
serde_with.workspace = true
tar.workspace = true
toml.workspace = true
unicode-truncate.workspace = true
unicode-width.workspace = true

[dev-dependencies]
assert_matches.workspace = true
bincode.workspace = true
enum-map.workspace = true
serde.workspace = true
tempfile.workspace = true
maelstrom-broker.workspace = true
maelstrom-test.workspace = true
maelstrom-worker.workspace = true
29 changes: 29 additions & 0 deletions crates/cargo-metest/examples/cargo-metest.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Example config for cargo metest.
#
# Save this as <workspace-root>/.cache/cargo-metest.toml or wherever you
# specify the config file using the --config-file or -c option.

# The host and port of the broker.
#
# Can also be specified via the `--broker` or `-b` command-line options, or via
# the CARGO_METEST_BROKER environment variable.
#
# There is no default. This option must be specified.
#
# Examples:
# broker = "localhost:1234"
# broker = "127.0.0.1:1234"
broker = "[::1]:1234"

# Options that apply to the `run` subcommand go in this section.
[run]

# Whether the output should be "quiet". If this is true, then only a single
# status bar will be output.
#
# Can also be specified via the `--quiet` or `-q` command-line options, or via
# the CARGO_METEST_RUN environment variable like this: CARGO_METEST_RUN={quiet = true}
#
# Default: false
# Examples:
# quiet = true
149 changes: 149 additions & 0 deletions crates/cargo-metest/src/artifacts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
use crate::progress::ProgressIndicator;
use anyhow::Result;
use indicatif::ProgressBar;
use maelstrom_base::Sha256Digest;
use maelstrom_client::Client;
use maelstrom_util::fs::Fs;
use std::{
collections::{BTreeSet, HashMap},
path::{Path, PathBuf},
sync::Mutex,
};
use tar::Header;

fn create_artifact_for_binary(binary_path: &Path, prog: Option<ProgressBar>) -> Result<PathBuf> {
let prog = prog.unwrap_or_else(ProgressBar::hidden);

let fs = Fs::new();
let binary = fs.open_file(binary_path)?;

let mut tar_path = PathBuf::from(binary_path);
assert!(tar_path.set_extension("tar"));

if fs.exists(&tar_path) {
let binary_mtime = binary.metadata()?.modified()?;
let tar_mtime = fs.metadata(&tar_path)?.modified()?;
if binary_mtime < tar_mtime {
return Ok(tar_path);
}
}

let tar_file = fs.create_file(&tar_path)?;
let mut a = tar::Builder::new(tar_file);

let binary_path_in_tar = Path::new("./").join(binary_path.file_name().unwrap());
let mut header = Header::new_gnu();
let meta = binary.metadata()?;
prog.set_length(meta.len());
header.set_metadata(&meta.into_inner());
a.append_data(&mut header, binary_path_in_tar, prog.wrap_read(binary))?;
a.finish()?;

Ok(tar_path)
}

fn create_artifact_for_binary_deps(
binary_path: &Path,
prog: Option<ProgressBar>,
) -> Result<PathBuf> {
let prog = prog.unwrap_or_else(ProgressBar::hidden);
let fs = Fs::new();

let mut tar_path = PathBuf::from(binary_path);
assert!(tar_path.set_extension("deps.tar"));

if fs.exists(&tar_path) {
let binary_mtime = fs.metadata(binary_path)?.modified()?;
let tar_mtime = fs.metadata(&tar_path)?.modified()?;

if binary_mtime < tar_mtime {
return Ok(tar_path);
}
}

let dep_tree = lddtree::DependencyAnalyzer::new("/".into());
let deps = dep_tree.analyze(binary_path)?;

let mut paths = BTreeSet::new();
if let Some(p) = deps.interpreter {
if let Some(lib) = deps.libraries.get(&p) {
paths.insert(lib.path.clone());
}
}

fn walk_deps(
deps: &[String],
libraries: &HashMap<String, lddtree::Library>,
paths: &mut BTreeSet<PathBuf>,
) {
for dep in deps {
if let Some(lib) = libraries.get(dep) {
paths.insert(lib.path.clone());
}
if let Some(lib) = libraries.get(dep) {
walk_deps(&lib.needed, libraries, paths);
}
}
}
walk_deps(&deps.needed, &deps.libraries, &mut paths);

fn remove_root(path: &Path) -> PathBuf {
path.components().skip(1).collect()
}

let tar_file = fs.create_file(&tar_path)?;
let mut a = tar::Builder::new(tar_file);

let files = paths
.iter()
.map(|p| fs.open_file(p))
.collect::<Result<Vec<_>>>()?;

let metas = files
.iter()
.map(|f| f.metadata())
.collect::<Result<Vec<_>>>()?;

let total_size = metas.iter().map(|m| m.len()).sum();
prog.set_length(total_size);

for ((path, file), meta) in paths
.into_iter()
.zip(files.into_iter())
.zip(metas.into_iter())
{
let mut header = Header::new_gnu();
header.set_metadata(&meta.into_inner());
a.append_data(&mut header, &remove_root(&path), prog.wrap_read(file))?;
}

a.finish()?;

Ok(tar_path)
}

pub struct GeneratedArtifacts {
pub binary: Sha256Digest,
pub deps: Sha256Digest,
}

pub fn add_generated_artifacts(
client: &Mutex<Client>,
binary_path: &Path,
ind: &impl ProgressIndicator,
) -> Result<GeneratedArtifacts> {
let prog = ind.new_side_progress("tar");
let binary_artifact = client
.lock()
.unwrap()
.add_artifact(&create_artifact_for_binary(binary_path, prog)?)?;
let prog = ind.new_side_progress("tar");
let deps_artifact = client
.lock()
.unwrap()
.add_artifact(&create_artifact_for_binary_deps(binary_path, prog)?)?;
Ok(GeneratedArtifacts {
binary: binary_artifact,
deps: deps_artifact,
})
}
94 changes: 94 additions & 0 deletions crates/cargo-metest/src/cargo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use anyhow::{Error, Result};
use cargo_metadata::{
Artifact as CargoArtifact, Message as CargoMessage, MessageIter as CargoMessageIter,
};
use regex::Regex;
use std::{
io,
io::BufReader,
path::Path,
process::{Child, ChildStdout, Command, Stdio},
str,
};

pub struct CargoBuild {
child: Child,
}

impl CargoBuild {
pub fn new(program: &str, color: bool, packages: Vec<String>) -> Result<Self> {
let mut cmd = Command::new(program);
cmd.arg("test")
.arg("--no-run")
.arg("--message-format=json-render-diagnostics")
.arg(&format!(
"--color={}",
if color { "always" } else { "never" }
))
.stdout(Stdio::piped())
.stderr(Stdio::piped());

for package in packages {
cmd.arg("--package").arg(package);
}

let child = cmd.spawn()?;

Ok(Self { child })
}

pub fn artifact_stream(&mut self) -> TestArtifactStream {
TestArtifactStream {
stream: Some(CargoMessage::parse_stream(BufReader::new(
self.child.stdout.take().unwrap(),
))),
}
}

pub fn check_status(mut self, mut stderr: impl io::Write) -> Result<()> {
let exit_status = self.child.wait()?;
if !exit_status.success() {
std::io::copy(self.child.stderr.as_mut().unwrap(), &mut stderr)?;
return Err(Error::msg("build failure".to_string()));
}

Ok(())
}
}

#[derive(Default)]
pub struct TestArtifactStream {
stream: Option<CargoMessageIter<BufReader<ChildStdout>>>,
}

impl Iterator for TestArtifactStream {
type Item = Result<CargoArtifact>;

fn next(&mut self) -> Option<Self::Item> {
while let Some(stream) = &mut self.stream {
match stream.next()? {
Err(e) => return Some(Err(e.into())),
Ok(CargoMessage::CompilerArtifact(artifact)) => {
if artifact.executable.is_some() && artifact.profile.test {
return Some(Ok(artifact));
}
}
_ => continue,
}
}
None
}
}

pub fn get_cases_from_binary(binary: &Path, filter: &Option<String>) -> Result<Vec<String>> {
let mut cmd = Command::new(binary);
cmd.arg("--list").arg("--format").arg("terse");
if let Some(filter) = filter {
cmd.arg(filter);
}
let output = cmd.output()?;
Ok(Regex::new(r"\b([^ ]*): test")?
.captures_iter(str::from_utf8(&output.stdout)?)
.map(|capture| capture.get(1).unwrap().as_str().trim().to_string())
.collect())
}
Loading

0 comments on commit df673a4

Please sign in to comment.