164 lines
5.2 KiB
Rust
164 lines
5.2 KiB
Rust
use std::path::{Path, PathBuf};
|
|
|
|
use anyhow::{Context, Result, bail};
|
|
use serde::Serialize;
|
|
|
|
use crate::{
|
|
cli::CaptureCliGoldensArgs,
|
|
workspace::{
|
|
capture_stdout_lines, default_binary_path, load_workspace_metadata, utc_now_rfc3339,
|
|
write_utf8_lines, write_utf8_text,
|
|
},
|
|
};
|
|
|
|
#[derive(Debug, Serialize)]
|
|
/// JSON manifest written beside captured CLI compatibility goldens.
|
|
struct CompatManifest {
|
|
/// UTC generation timestamp for the manifest.
|
|
generated_at_utc: String,
|
|
/// Relative paths captured by the workflow.
|
|
captured: Vec<&'static str>,
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
/// Human-readable JSON summary printed after capture.
|
|
struct CompatSummary {
|
|
#[serde(rename = "Captured")]
|
|
/// Relative paths captured by the workflow.
|
|
captured: Vec<&'static str>,
|
|
}
|
|
|
|
/// Captures upstream and Rust CLI help/version output as compatibility goldens.
|
|
pub fn run_capture_cli_goldens(args: &CaptureCliGoldensArgs) -> Result<()> {
|
|
let metadata = load_workspace_metadata()?;
|
|
let host_triple = crate::workspace::host_triple()?;
|
|
let upstream_binary = args
|
|
.upstream_binary
|
|
.clone()
|
|
.unwrap_or_else(default_upstream_binary);
|
|
let rust_binary = args
|
|
.rust_binary
|
|
.clone()
|
|
.unwrap_or_else(|| default_binary_path(&metadata, &host_triple, &host_triple));
|
|
let output_root = args.output_root.clone().unwrap_or_else(|| {
|
|
metadata
|
|
.workspace_root
|
|
.join("docs/compatibility/goldens/cli")
|
|
});
|
|
|
|
ensure_path_exists(&upstream_binary, "upstream binary")?;
|
|
ensure_path_exists(&rust_binary, "rust binary")?;
|
|
|
|
let upstream_dir = output_root.join("upstream");
|
|
let rust_dir = output_root.join("rust");
|
|
std::fs::create_dir_all(&upstream_dir)
|
|
.with_context(|| format!("failed to create {}", upstream_dir.display()))?;
|
|
std::fs::create_dir_all(&rust_dir)
|
|
.with_context(|| format!("failed to create {}", rust_dir.display()))?;
|
|
|
|
let upstream_version = capture_stdout_lines(&upstream_binary, &["-v"])?;
|
|
let upstream_help =
|
|
redact_windows_home_paths(capture_stdout_lines(&upstream_binary, &["--help=#all"])?);
|
|
let rust_version = capture_stdout_lines(&rust_binary, &["--version"])?;
|
|
let rust_help =
|
|
redact_windows_home_paths(capture_stdout_lines(&rust_binary, &["--help=#all"])?);
|
|
|
|
write_utf8_lines(&upstream_dir.join("version.txt"), &upstream_version)?;
|
|
write_utf8_lines(&upstream_dir.join("help-all.txt"), &upstream_help)?;
|
|
write_utf8_lines(&rust_dir.join("version.txt"), &rust_version)?;
|
|
write_utf8_lines(&rust_dir.join("help-all.txt"), &rust_help)?;
|
|
|
|
let captured = captured_paths();
|
|
let manifest = CompatManifest {
|
|
generated_at_utc: utc_now_rfc3339()?,
|
|
captured: captured.to_vec(),
|
|
};
|
|
let manifest_text = serde_json::to_string_pretty(&manifest)
|
|
.context("failed to serialize compatibility manifest")?;
|
|
write_utf8_text(&output_root.join("manifest.json"), &(manifest_text + "\n"))?;
|
|
|
|
let summary = CompatSummary {
|
|
captured: summary_paths().to_vec(),
|
|
};
|
|
println!(
|
|
"{}",
|
|
serde_json::to_string_pretty(&summary)
|
|
.context("failed to serialize compatibility summary")?
|
|
);
|
|
Ok(())
|
|
}
|
|
|
|
/// Returns the repository-local default upstream aria2 binary path.
|
|
fn default_upstream_binary() -> PathBuf {
|
|
crate::workspace::repo_root()
|
|
.join("dist")
|
|
.join("upstream")
|
|
.join("aria2-1.37.0-win-64bit-build1")
|
|
.join("aria2-1.37.0-win-64bit-build1")
|
|
.join("aria2c.exe")
|
|
}
|
|
|
|
/// Ensures an expected binary path exists.
|
|
fn ensure_path_exists(path: &Path, label: &str) -> Result<()> {
|
|
if path.is_file() {
|
|
Ok(())
|
|
} else {
|
|
bail!("{label} not found: {}", path.display())
|
|
}
|
|
}
|
|
|
|
/// Replaces a Windows account name embedded in captured CLI help text.
|
|
fn redact_windows_home_paths(lines: Vec<String>) -> Vec<String> {
|
|
lines
|
|
.into_iter()
|
|
.map(|line| redact_windows_home_path(&line))
|
|
.collect()
|
|
}
|
|
|
|
/// Replaces the first Windows home-directory account name in a line.
|
|
fn redact_windows_home_path(line: &str) -> String {
|
|
const PREFIX: &str = "C:/Users/";
|
|
|
|
let Some((leading, remainder)) = line.split_once(PREFIX) else {
|
|
return line.to_owned();
|
|
};
|
|
let Some((_, trailing)) = remainder.split_once('/') else {
|
|
return line.to_owned();
|
|
};
|
|
format!("{leading}{PREFIX}<user>/{trailing}")
|
|
}
|
|
|
|
/// Returns the golden files produced by the capture workflow.
|
|
const fn captured_paths() -> &'static [&'static str] {
|
|
&[
|
|
"upstream/version.txt",
|
|
"upstream/help-all.txt",
|
|
"rust/version.txt",
|
|
"rust/help-all.txt",
|
|
]
|
|
}
|
|
|
|
/// Returns all paths reported in the workflow summary.
|
|
const fn summary_paths() -> &'static [&'static str] {
|
|
&[
|
|
"upstream/version.txt",
|
|
"upstream/help-all.txt",
|
|
"rust/version.txt",
|
|
"rust/help-all.txt",
|
|
"manifest.json",
|
|
]
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::redact_windows_home_path;
|
|
|
|
#[test]
|
|
fn redacts_a_windows_home_path_in_captured_help() {
|
|
assert_eq!(
|
|
redact_windows_home_path("Default: C:/Users/alice/.netrc"),
|
|
"Default: C:/Users/<user>/.netrc"
|
|
);
|
|
}
|
|
}
|