use crate::store::Store;
use std::path::Path;
use std::process::Command;
fn git_sha(repo: &Path, rev: &str) -> Option<String> {
let out = Command::new("git")
.args(["rev-parse", rev])
.current_dir(repo)
.output()
.ok()?;
if !out.status.success() {
return None;
}
let sha = String::from_utf8_lossy(&out.stdout).trim().to_string();
crate::tick::is_40_lower_hex(&sha).then_some(sha)
}
pub fn resolve(repo: &Path, store: &Store, policy: &str, offline: bool) -> Option<String> {
if offline {
return store.read_origin_sha();
}
match policy {
"none" => None,
"local-head" => git_sha(repo, "HEAD"),
_ => {
let sha = git_sha(repo, "@{upstream}");
match &sha {
Some(s) => {
let _ = store.write_origin_sha(s);
}
None => eprintln!(
"warning: cannot resolve the live-origin staleness reference (no upstream?) — sha-staleness skipped"
),
}
sha
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::store::Store;
fn git_store() -> (std::path::PathBuf, Store, String) {
use std::sync::atomic::{AtomicU64, Ordering};
static N: AtomicU64 = AtomicU64::new(0);
let p = std::env::temp_dir().join(format!(
"ev-staleness-{}-{}",
std::process::id(),
N.fetch_add(1, Ordering::Relaxed)
));
let _ = std::fs::remove_dir_all(&p);
std::fs::create_dir_all(&p).unwrap();
for args in [
["init"].as_slice(),
["config", "user.email", "t@e.st"].as_slice(),
["config", "user.name", "Tester"].as_slice(),
["commit", "--allow-empty", "-m", "init"].as_slice(),
] {
Command::new("git")
.args(args)
.current_dir(&p)
.output()
.unwrap();
}
let head = String::from_utf8(
Command::new("git")
.args(["rev-parse", "HEAD"])
.current_dir(&p)
.output()
.unwrap()
.stdout,
)
.unwrap()
.trim()
.to_string();
let s = Store::at(&p);
s.init().unwrap();
(p, s, head)
}
#[test]
fn git_sha_should_return_the_head_when_run_in_a_git_repo() {
let (p, _s, head) = git_store();
let sha = git_sha(&p, "HEAD");
assert_eq!(sha.as_deref(), Some(head.as_str()));
}
#[test]
fn resolve_should_be_none_when_the_policy_is_none() {
let (p, s, _head) = git_store();
let sha = resolve(&p, &s, "none", false);
assert!(sha.is_none());
}
#[test]
fn resolve_should_be_the_local_head_when_the_policy_is_local_head() {
let (p, s, head) = git_store();
let sha = resolve(&p, &s, "local-head", false);
assert_eq!(sha.as_deref(), Some(head.as_str()));
}
#[test]
fn resolve_should_use_the_cached_origin_when_offline() {
let (p, s, _head) = git_store();
std::fs::write(
s.root.join("results").join("origin-sha"),
"d308afac1b2c3d4e5f60718293a4b5c6d7e8f901",
)
.unwrap();
let sha = resolve(&p, &s, "live-origin", true);
assert_eq!(
sha.as_deref(),
Some("d308afac1b2c3d4e5f60718293a4b5c6d7e8f901")
);
}
}