use std::io::{BufRead, BufReader, Write};
use std::net::TcpListener;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::OnceLock;
pub fn archon_bin() -> &'static str {
env!("CARGO_BIN_EXE_archon")
}
fn arch_os_release_path() -> &'static Path {
static PATH: OnceLock<PathBuf> = OnceLock::new();
PATH.get_or_init(|| {
let path = std::env::temp_dir().join(format!("archon-test-os-release-{}", std::process::id()));
std::fs::write(&path, "ID=arch\n").expect("write fixture os-release");
path
})
}
pub struct FixturePkg {
pub name: &'static str,
pub version: &'static str,
pub depends: &'static [&'static str],
}
pub fn fixture_sync_dir(pkgs: &[FixturePkg]) -> (tempfile::TempDir, PathBuf) {
let dir = tempfile::tempdir().expect("create temp dir");
let db_path = dir.path().join("core.db");
let mut builder = tar::Builder::new(Vec::new());
for pkg in pkgs {
let mut desc = format!("%NAME%\n{}\n\n%VERSION%\n{}\n\n", pkg.name, pkg.version);
if !pkg.depends.is_empty() {
desc.push_str("%DEPENDS%\n");
for d in pkg.depends {
desc.push_str(d);
desc.push('\n');
}
desc.push('\n');
}
let mut header = tar::Header::new_ustar();
header.set_size(desc.len() as u64);
header.set_mode(0o644);
header.set_cksum();
builder
.append_data(&mut header, format!("{}-{}/desc", pkg.name, pkg.version), desc.as_bytes())
.expect("append fixture package");
}
let bytes = builder.into_inner().expect("finish tar");
std::fs::write(&db_path, bytes).expect("write fixture db");
let path = dir.path().to_path_buf();
(dir, path)
}
pub fn empty_aur_server() -> String {
let listener = TcpListener::bind("127.0.0.1:0").expect("bind mock AUR server");
let addr = listener.local_addr().unwrap();
std::thread::spawn(move || {
for stream in listener.incoming() {
let Ok(mut stream) = stream else { break };
let mut reader = BufReader::new(stream.try_clone().unwrap());
let mut request_line = String::new();
let _ = reader.read_line(&mut request_line);
loop {
let mut line = String::new();
if reader.read_line(&mut line).is_err() || line == "\r\n" || line.is_empty() {
break;
}
}
let body = r#"{"type":"multiinfo","resultcount":0,"results":[],"version":5}"#;
let resp = format!(
"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{}",
body.len(),
body
);
let _ = stream.write_all(resp.as_bytes());
}
});
format!("http://{addr}")
}
pub struct Output {
pub status: std::process::ExitStatus,
pub stdout: String,
pub stderr: String,
}
pub fn run_archon(args: &[&str], envs: &[(&str, &str)]) -> Output {
let mut cmd = Command::new(archon_bin());
cmd.args(args).stdin(std::process::Stdio::null());
cmd.env("ARCHON_OS_RELEASE", arch_os_release_path());
for (k, v) in envs {
cmd.env(k, v);
}
let output = cmd.output().expect("failed to execute archon binary");
Output {
status: output.status,
stdout: String::from_utf8_lossy(&output.stdout).into_owned(),
stderr: String::from_utf8_lossy(&output.stderr).into_owned(),
}
}
pub fn empty_local_dir() -> (tempfile::TempDir, PathBuf) {
let dir = tempfile::tempdir().expect("create temp dir");
let path = dir.path().to_path_buf();
(dir, path)
}
pub fn fixture_local_dir(pkgs: &[FixturePkg]) -> (tempfile::TempDir, PathBuf) {
let dir = tempfile::tempdir().expect("create temp dir");
for pkg in pkgs {
let pkg_dir = dir.path().join(format!("{}-{}", pkg.name, pkg.version));
std::fs::create_dir_all(&pkg_dir).expect("create fixture pkg dir");
std::fs::write(
pkg_dir.join("desc"),
format!("%NAME%\n{}\n\n%VERSION%\n{}\n\n%BASE%\n{}\n", pkg.name, pkg.version, pkg.name),
)
.expect("write fixture desc");
}
let path = dir.path().to_path_buf();
(dir, path)
}
pub fn empty_cache_dir() -> (tempfile::TempDir, PathBuf) {
let dir = tempfile::tempdir().expect("create temp dir");
let path = dir.path().to_path_buf();
(dir, path)
}
pub const UNREACHABLE_AUR_URL: &str = "http://127.0.0.1:1";
pub fn fixture_os_release(content: &str) -> (tempfile::TempDir, PathBuf) {
let dir = tempfile::tempdir().expect("create temp dir");
let path = dir.path().join("os-release");
std::fs::write(&path, content).expect("write fixture os-release");
(dir, path)
}