mod build_utils;
use std::env;
use std::fs;
use std::io::Write;
use std::path::Path;
use thag_proc_macros::{safe_eprintln, safe_println};
#[allow(clippy::doc_markdown, clippy::too_many_lines)]
fn main() {
safe_println!("cargo:rerun-if-changed=themes/built_in");
safe_println!("cargo:rerun-if-changed=src/bin");
let out_dir = env::var("OUT_DIR").expect("OUT_DIR not set");
safe_eprintln!("OUT_DIR={out_dir}");
fs::create_dir_all(&out_dir).expect("Failed to create destination directory");
let out_dir_path = &Path::new(&out_dir);
let dest_path = out_dir_path.join("generated_tests.rs");
let mut file = fs::File::create(dest_path).expect("Failed to create generated_tests.rs");
let subdir_names = vec!["demo"];
for subdir_name in &subdir_names {
let source_dir = Path::new(subdir_name);
safe_eprintln!(
"source_path = source_dir = {:#?}",
source_dir.canonicalize()
);
assert!(
source_dir.exists() && source_dir.is_dir(),
"source directory {} does not exist",
source_dir.display()
);
let dest_dir = &out_dir_path.join(subdir_name);
fs::create_dir_all(dest_dir)
.unwrap_or_else(|_| panic!("Failed to create directory {}", dest_dir.display()));
let skip_scripts_on_windows = [
"crossbeam_channel_stopwatch.rs",
"factorial_main_rug.rs",
"factorial_main_rug_product.rs",
"fib_4784969_cpp_rug.rs",
"fib_big_clap_rug.rs",
"fib_doubling_iterative_purge_rug.rs",
"fib_fac_rug.rs",
"fib_matrix_rug.rs",
"rug_arbitrary_precision_nums.rs",
];
let multimain = [
"flume_async.rs",
"flume_async_profile.rs",
"flume_select.rs",
"thag_async_benchmark.rs",
];
let stable_only = [
"duration_main.rs",
"duration_snippet.rs",
"displayable_nightly.rs",
"displayable_nightly1.rs",
];
for entry in fs::read_dir(source_dir)
.unwrap_or_else(|_| panic!("Failed to read directory {}", source_dir.display()))
{
let entry = entry.expect("Failed to get directory entry");
let path = entry.path();
if path.extension().and_then(|s| s.to_str()) == Some("rs") {
let source_name = path
.file_name()
.and_then(|s| s.to_str())
.expect("Failed to get source file name");
if cfg!(target_os = "windows") && skip_scripts_on_windows.contains(&source_name) {
continue;
}
if cfg!(not(feature = "nightly")) && stable_only.contains(&source_name) {
safe_eprintln!("Skipping nightly-only test {source_name}");
continue;
}
let test_name = source_name.replace('.', "_");
#[allow(clippy::literal_string_with_formatting_args)]
writeln!(
file,
r#"
#[test]
fn check_{subdir_name}_{test_name}() {{
{{
use std::process::Command;
use thag_proc_macros::{{/*safe_eprintln,*/ safe_osc}};
// Reset terminal state at start
safe_osc!("\x1B[0m\x1B[?1049l"); // Reset all attributes and exit alternate screen
set_up();
// Use precompiled binary instead of cargo run for much faster tests
// Construct path to built binary
let target_dir = std::env::var("CARGO_TARGET_DIR")
.unwrap_or_else(|_| "target".to_string());
let profile = std::env::var("PROFILE")
.unwrap_or_else(|_| "debug".to_string());
#[cfg(windows)]
let thag_bin = format!("{{}}/{{}}/thag.exe", target_dir, profile);
#[cfg(not(windows))]
let thag_bin = format!("{{}}/{{}}/thag", target_dir, profile);
let output = Command::new(&thag_bin)
// Suppress invoking termbg and supports_color on shared terminal.
// This should already be passed by default after call to set_up(), but just making sure.
.env("TEST_ENV", "1")
.arg("-c{more_options}")
.arg({source_path:?})
.output()
.expect("Failed to execute command");
let err_str = std::str::from_utf8(&output.stderr).expect("Can't parse stderr to &str");
if !output.status.success() || err_str.contains("Build failed") {{
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
panic!(
"Failed to build file: {source_name}\nstdout: {{stdout}}\nstderr: {{stderr}}"
);
}}
// safe_eprintln!("{{output:?}}");
// safe_eprintln!("stdout={{}}", String::from_utf8_lossy(&output.stdout));
// safe_eprintln!("stderr={{}}", String::from_utf8_lossy(&output.stderr));
// safe_eprintln!("... finished {source_name}, starting cargo clean");
// Get the file stem
let file_stem = {source_name:?}.trim_end_matches(".rs");
// Construct the destination directory path
let mut dest_dir = env::temp_dir();
dest_dir.push("thag_rs");
dest_dir.push(file_stem);
// Note: With shared target implementation, per-script target directories no longer exist.
// Build artifacts are in $TMPDIR/thag_rs_shared_target/ and executables in $TMPDIR/thag_rs_bins/.
// The old cleanup code that removed $TMPDIR/thag_rs/<script>/target/debug is no longer needed.
// Reset terminal state after
safe_osc!("\x1B[0m\x1B[?1049l");
}}
}}
"#,
source_path = &path.to_str().expect("Failed to get source path"),
more_options = if multimain.contains(&source_name) {
"mq"
} else if source_name == "hyper_hello_server.rs" || source_name == "just_a_test_expression.rs" {
"v"
} else {
"q"
}
)
.expect("Failed to write test function");
}
}
}
}