use std::path::{Path, PathBuf};
use tempfile::TempDir;
use super::git_helpers;
pub struct PlaygroundHarness {
pub _temp: TempDir,
pub workspace_root: PathBuf,
pub remotes_dir: PathBuf,
pub repo_names: Vec<String>,
}
impl PlaygroundHarness {
pub fn new(repo_names: &[&str]) -> Self {
let temp = TempDir::new().expect("failed to create temp dir");
let workspace_root = temp.path().join("playground");
let remotes_dir = temp.path().join("remotes");
std::fs::create_dir_all(&workspace_root).expect("failed to create workspace root");
std::fs::create_dir_all(&remotes_dir).expect("failed to create remotes dir");
for repo_name in repo_names {
let bare_path = remotes_dir.join(format!("{}.git", repo_name));
let staging = temp.path().join(format!("staging-{}", repo_name));
let repo_path = workspace_root.join(repo_name);
git_helpers::init_bare_repo(&bare_path);
git_helpers::init_repo(&staging);
git_helpers::commit_file(
&staging,
"README.md",
&format!("# {}\n", repo_name),
"Initial commit",
);
let remote_url = format!("file://{}", bare_path.display());
git_helpers::add_remote(&staging, "origin", &remote_url);
git_helpers::push_upstream(&staging, "origin", "main");
git_helpers::clone_repo(&remote_url, &repo_path);
}
Self {
_temp: temp,
workspace_root,
remotes_dir,
repo_names: repo_names.iter().map(|name| (*name).to_string()).collect(),
}
}
pub fn repo_path(&self, name: &str) -> PathBuf {
self.workspace_root.join(name)
}
pub fn remote_url(&self, name: &str) -> String {
format!(
"file://{}",
self.remotes_dir.join(format!("{}.git", name)).display()
)
}
pub fn init_from_dirs(&self) {
self.run_from_manifest_dir([
"init",
"--from-dirs",
"-p",
self.workspace_root
.to_str()
.expect("workspace path should be utf-8"),
]);
self.ensure_repo_identities();
}
pub fn run_in_workspace<I, S>(&self, args: I)
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
self.run(args, &self.workspace_root);
}
pub fn run_from_manifest_dir<I, S>(&self, args: I)
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
self.run(args, Path::new(env!("CARGO_MANIFEST_DIR")));
}
pub fn run_in_workspace_output<I, S>(&self, args: I) -> std::process::Output
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
self.run_output(args, &self.workspace_root)
}
pub fn ensure_repo_identities(&self) {
for repo_name in &self.repo_names {
let repo_path = self.repo_path(repo_name);
if repo_path.join(".git").exists() {
git_helpers::configure_identity(&repo_path);
}
}
}
fn run<I, S>(&self, args: I, current_dir: &Path)
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
let args_vec: Vec<String> = args.into_iter().map(|s| s.as_ref().to_string()).collect();
let output = self.run_output(args_vec.iter().map(String::as_str), current_dir);
assert!(
output.status.success(),
"gr {:?} failed in {}:\nstdout:\n{}\nstderr:\n{}",
args_vec,
current_dir.display(),
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
}
fn run_output<I, S>(&self, args: I, current_dir: &Path) -> std::process::Output
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
let args_vec: Vec<String> = args.into_iter().map(|s| s.as_ref().to_string()).collect();
let mut cmd = std::process::Command::new(assert_cmd::cargo::cargo_bin!("gr"));
cmd.current_dir(current_dir)
.args(args_vec.iter().map(String::as_str));
cmd.output().expect("failed to run gr binary")
}
}