This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / knot2 / crates / knot-fixtures / src / lib.rs
4.0 kB 133 lines
1use std::io::Write; 2use std::path::Path; 3use std::process::{Command, Output, Stdio}; 4 5pub const AUTHOR_NAME: &str = "nel"; 6pub const AUTHOR_EMAIL: &str = "nel@oyster.cafe"; 7pub const PINNED_DATE: &str = "2026-01-01T00:00:00 +0000"; 8 9pub fn command(cwd: &Path) -> Command { 10 let mut command = Command::new("git"); 11 command 12 .current_dir(cwd) 13 .env("GIT_CONFIG_GLOBAL", "/dev/null") 14 .env("GIT_CONFIG_SYSTEM", "/dev/null") 15 .env("GIT_TERMINAL_PROMPT", "0") 16 .env("GIT_ASKPASS", "true") 17 .env("GIT_AUTHOR_NAME", AUTHOR_NAME) 18 .env("GIT_AUTHOR_EMAIL", AUTHOR_EMAIL) 19 .env("GIT_COMMITTER_NAME", AUTHOR_NAME) 20 .env("GIT_COMMITTER_EMAIL", AUTHOR_EMAIL); 21 command 22} 23 24pub fn command_at(cwd: &Path, stamp: &str) -> Command { 25 let mut command = command(cwd); 26 command 27 .env("GIT_AUTHOR_DATE", stamp) 28 .env("GIT_COMMITTER_DATE", stamp); 29 command 30} 31 32pub fn available() -> bool { 33 Command::new("git") 34 .arg("--version") 35 .output() 36 .map(|out| out.status.success()) 37 .unwrap_or(false) 38} 39 40fn combined(out: &Output) -> String { 41 format!( 42 "{}{}", 43 String::from_utf8_lossy(&out.stdout), 44 String::from_utf8_lossy(&out.stderr) 45 ) 46} 47 48pub fn run(cwd: &Path, args: &[&str]) -> (bool, String) { 49 let out = command_at(cwd, PINNED_DATE) 50 .args(args) 51 .output() 52 .expect("git is available"); 53 (out.status.success(), combined(&out)) 54} 55 56pub fn must(cwd: &Path, args: &[&str]) -> String { 57 let out = command_at(cwd, PINNED_DATE) 58 .args(args) 59 .output() 60 .expect("git is available"); 61 assert!(out.status.success(), "git {args:?}:\n{}", combined(&out)); 62 String::from_utf8_lossy(&out.stdout).trim().to_string() 63} 64 65pub fn feed(cwd: &Path, args: &[&str], stdin: &[u8]) -> (bool, String) { 66 let mut child = command_at(cwd, PINNED_DATE) 67 .args(args) 68 .stdin(Stdio::piped()) 69 .stdout(Stdio::piped()) 70 .stderr(Stdio::piped()) 71 .spawn() 72 .expect("git is available"); 73 child 74 .stdin 75 .take() 76 .expect("stdin was piped") 77 .write_all(stdin) 78 .expect("the write to git's stdin succeeds"); 79 let out = child.wait_with_output().expect("git exits"); 80 (out.status.success(), combined(&out)) 81} 82 83pub fn fsck(bare: &Path) -> Result<(), String> { 84 match run( 85 bare, 86 &["fsck", "--no-dangling", "--no-reflogs", "--no-progress"], 87 ) { 88 (true, _) => Ok(()), 89 (false, report) => Err(report), 90 } 91} 92 93pub fn commit(work: &Path, file: &str, contents: &str, message: &str) { 94 std::fs::write(work.join(file), contents).expect("fixture file is writable"); 95 must(work, &["add", "-A"]); 96 must(work, &["commit", "-q", "-m", message]); 97} 98 99pub fn contains(haystack: &[u8], needle: &[u8]) -> bool { 100 haystack 101 .windows(needle.len()) 102 .any(|window| window == needle) 103} 104 105#[cfg(test)] 106mod tests { 107 use super::*; 108 109 #[test] 110 fn every_helper_pins_its_dates_so_the_same_sequence_yields_the_same_oid() { 111 if !available() { 112 return; 113 } 114 let oids = || { 115 let dir = tempfile::tempdir().unwrap(); 116 must(dir.path(), &["init", "-q", "-b", "main"]); 117 commit(dir.path(), "README.md", "kelp\n", "initial"); 118 let tree = must(dir.path(), &["hash-object", "-t", "tree", "-w", "--stdin"]); 119 let (ok, from_stdin) = feed(dir.path(), &["commit-tree", &tree, "-F", "-"], b"empty\n"); 120 assert!(ok, "{from_stdin}"); 121 ( 122 must(dir.path(), &["rev-parse", "HEAD"]), 123 from_stdin.trim().to_string(), 124 ) 125 }; 126 assert_eq!( 127 oids(), 128 oids(), 129 "an unpinned committer date would make every differential run disagree, \ 130 so a fixture writing through stdin pins the same dates as one that doesn't" 131 ); 132 } 133}