Menu
AkurAI-Build
publicLatest change fe39ce51fc9c202d5411f39fd9a8a2feeca4a85e - Harden test suite: 16→179 hermetic tests, race-free integration harness by Ólafur Búi Ólafsson
use std::{
fs,
path::{Path, PathBuf},
process::Command,
};
use anyhow::{Context, Result, ensure};
use crate::config;
pub fn repository_path(root: &Path, name: &str) -> Result<PathBuf> {
config::validate_repo_name(name)?;
Ok(root.join("hosted").join(format!("{name}.git")))
}
pub fn host(root: &Path, name: &str, source: &Path) -> Result<PathBuf> {
let source = source
.canonicalize()
.with_context(|| format!("source repository does not exist: {}", source.display()))?;
let destination = repository_path(root, name)?;
ensure!(
!destination.exists(),
"hosted repository already exists: {name}"
);
let parent = destination
.parent()
.context("hosted repository has no parent")?;
fs::create_dir_all(parent)?;
run(
Command::new("git")
.args(["clone", "--mirror"])
.arg(&source)
.arg(&destination),
"git mirror clone",
)?;
if let Err(error) = run(
Command::new("git").arg("-C").arg(&destination).args([
"config",
"http.receivepack",
"true",
]),
"enable Git Smart HTTP writes",
) {
let _ = fs::remove_dir_all(&destination);
return Err(error);
}
Ok(destination)
}
pub fn sync(root: &Path, name: &str, source: &Path) -> Result<PathBuf> {
let source = source
.canonicalize()
.with_context(|| format!("source repository does not exist: {}", source.display()))?;
let destination = repository_path(root, name)?;
ensure!(destination.is_dir(), "unknown hosted repository: {name}");
run(
Command::new("git")
.arg("-C")
.arg(&destination)
.args(["fetch", "--prune"])
.arg(&source)
.arg("+refs/*:refs/*"),
"sync Git mirror",
)?;
Ok(destination)
}
fn run(command: &mut Command, operation: &str) -> Result<()> {
let output = command
.output()
.with_context(|| format!("failed to start {operation}"))?;
ensure!(
output.status.success(),
"{operation} failed: {}",
String::from_utf8_lossy(&output.stderr).trim()
);
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
use tempfile::tempdir;
fn init_source(work: &Path) -> Result<PathBuf> {
let source = work.join("source");
fs::create_dir(&source)?;
git(&source, &["init", "-b", "main"])?;
git(&source, &["config", "user.name", "AkurAI Build"])?;
git(&source, &["config", "user.email", "build@localhost"])?;
Ok(source)
}
fn commit(repository: &Path, message: &str) -> Result<()> {
fs::write(repository.join("README.md"), format!("{message}\n"))?;
git(repository, &["add", "."])?;
git(repository, &["commit", "-m", message])
}
fn head(repository: &Path) -> Result<String> {
let output = Command::new("git")
.arg("-C")
.arg(repository)
.args(["rev-parse", "refs/heads/main"])
.output()?;
ensure!(output.status.success(), "read hosted head failed");
Ok(String::from_utf8(output.stdout)?.trim().to_owned())
}
fn git(repository: &Path, arguments: &[&str]) -> Result<()> {
run(
Command::new("git")
.arg("-C")
.arg(repository)
.args(arguments),
&format!("git {}", arguments.join(" ")),
)
}
fn has_config(repository: &Path, key: &str, expected: &str) -> bool {
let output = Command::new("git")
.arg("-C")
.arg(repository)
.args(["config", key])
.output();
output
.ok()
.filter(|out| out.status.success())
.and_then(|out| String::from_utf8(out.stdout).ok())
.is_some_and(|v| v.trim() == expected)
}
#[test]
fn host_creates_bare_mirror_with_matching_head() -> Result<()> {
let work = tempdir()?;
let source = init_source(work.path())?;
commit(&source, "initial")?;
let source_head = head(&source)?;
let root = work.path().join("data");
let hosted = host(&root, "app", &source)?;
let hosted_head = head(&hosted)?;
assert_eq!(
source_head, hosted_head,
"mirror HEAD must equal source HEAD"
);
assert!(
hosted.join("HEAD").is_file(),
"bare mirror must have a HEAD file"
);
assert!(
!hosted.join("index").exists(),
"bare mirror should not have a working-tree index"
);
assert!(
has_config(&hosted, "http.receivepack", "true"),
"mirror must have Smart-HTTP receive enabled"
);
Ok(())
}
#[test]
fn sync_propagates_new_commits_branches_and_tags() -> Result<()> {
let work = tempdir()?;
let source = init_source(work.path())?;
commit(&source, "first")?;
git(&source, &["tag", "-a", "v1.0", "-m", "first release"])?;
let root = work.path().join("data");
let hosted = host(&root, "app", &source)?;
commit(&source, "second")?;
git(&source, &["branch", "feature"])?;
git(&source, &["tag", "-a", "v2.0", "-m", "second release"])?;
sync(&root, "app", &source)?;
let mirror_head = head(&hosted)?;
let source_head = head(&source)?;
assert_eq!(
mirror_head, source_head,
"mirror HEAD should reflect new commits"
);
let branches = Command::new("git")
.arg("-C")
.arg(&hosted)
.args(["branch", "--list", "feature"])
.output()?;
assert!(
branches.status.success()
&& !String::from_utf8_lossy(&branches.stdout).trim().is_empty(),
"feature branch must be present in mirror"
);
let tags = Command::new("git")
.arg("-C")
.arg(&hosted)
.args(["tag", "--list"])
.output()?;
let tag_list = String::from_utf8_lossy(&tags.stdout);
assert!(
tag_list.contains("v1.0") && tag_list.contains("v2.0"),
"both tags must be present in mirror: {tag_list}"
);
Ok(())
}
#[test]
fn repository_name_rejects_traversal() {
for name in ["", "../escape", "repo/hack", "has space", "\x00null"] {
let result = repository_path(Path::new("root"), name);
assert!(
result.is_err(),
"repository name {name:?} should be rejected"
);
}
}
#[test]
fn repository_name_accepts_valid() -> Result<()> {
for name in ["app", "my-repo", "repo_v2", "test.repo", "a"] {
let path = repository_path(Path::new("root"), name)?;
assert!(
path.ends_with(format!("{name}.git")),
"valid name {name:?} should produce {name}.git suffix"
);
}
Ok(())
}
#[test]
fn sync_unknown_repository_errors() -> Result<()> {
let work = tempdir()?;
let source = init_source(work.path())?;
commit(&source, "first")?;
let root = work.path().join("data");
let result = sync(&root, "nonexistent", &source);
assert!(result.is_err(), "sync of unknown repo should error");
Ok(())
}
#[test]
fn host_missing_source_errors() {
let work = tempdir().expect("create temp dir");
let missing = work.path().join("does-not-exist");
let root = work.path().join("data");
let result = host(&root, "app", &missing);
assert!(result.is_err(), "host of missing source should error");
}
#[test]
fn rehost_existing_name_errors() -> Result<()> {
let work = tempdir()?;
let source = init_source(work.path())?;
commit(&source, "first")?;
let root = work.path().join("data");
host(&root, "app", &source)?;
let result = host(&root, "app", &source);
assert!(result.is_err(), "re-hosting existing name should error");
Ok(())
}
#[test]
fn host_mirror_is_bare() -> Result<()> {
let work = tempdir()?;
let source = init_source(work.path())?;
commit(&source, "first")?;
let root = work.path().join("data");
let hosted = host(&root, "app", &source)?;
let is_bare = Command::new("git")
.arg("-C")
.arg(&hosted)
.args(["rev-parse", "--is-bare-repository"])
.output()
.map(|out| String::from_utf8_lossy(&out.stdout).trim() == "true")
.unwrap_or(false);
assert!(is_bare, "hosted mirror must be a bare repository");
Ok(())
}
}