-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Revert "Rename cargo-metest to cargo-maelstrom."
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
Showing
36 changed files
with
6,955 additions
and
54 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()) | ||
} |
Oops, something went wrong.