pub fn get_cached_canonical_orca_rom() -> Result<(std::path::PathBuf, std::path::PathBuf), String> {
use uxn_tal_common::hash_url;
use uxn_tal_defined::consts::CANONICAL_ORCA;
let url = CANONICAL_ORCA;
let roms_dir =
crate::paths::uxntal_roms_get_path().ok_or("Failed to get uxntal roms directory")?;
let cache_dir = roms_dir.join(format!("{}", hash_url(url)));
let orca_rom = cache_dir.join("orca.rom");
if !orca_rom.exists() {
return Err(format!(
"orca.rom not found in cache dir: {}",
orca_rom.display()
));
}
let metadata =
std::fs::metadata(&orca_rom).map_err(|e| format!("orca.rom metadata error: {e}"))?;
if metadata.len() == 0 {
return Err(format!(
"orca.rom is empty in cache dir: {}",
orca_rom.display()
));
}
Ok((orca_rom, cache_dir))
}
pub fn get_workspace_canonical_orca_rom() -> Result<(std::path::PathBuf, std::path::PathBuf), String>
{
let roms_dir = std::path::PathBuf::from("roms");
let orca_rom = roms_dir.join("orca.rom");
if !orca_rom.exists() {
return Err(format!(
"orca.rom not found in workspace roms dir: {}",
orca_rom.display()
));
}
let metadata =
std::fs::metadata(&orca_rom).map_err(|e| format!("orca.rom metadata error: {e}"))?;
if metadata.len() == 0 {
return Err(format!(
"orca.rom is empty in workspace roms dir: {}",
orca_rom.display()
));
}
Ok((orca_rom, roms_dir))
}
pub fn resolve_canonical_orca_rom() -> Result<(std::path::PathBuf, std::path::PathBuf), String> {
if let Ok(pair) = get_cached_canonical_orca_rom() {
return Ok(pair);
}
use uxn_tal_common::cache::RomEntryResolver;
use uxn_tal_defined::consts::CANONICAL_ORCA;
let entry_resolver = crate::util::RealRomEntryResolver;
let (tal_path, cache_dir) = entry_resolver
.resolve_entry_and_cache_dir(CANONICAL_ORCA)
.map_err(|e| format!("Failed to resolve canonical orca: {e}"))?;
let orca_rom = cache_dir.join("orca.rom");
if !orca_rom.exists() {
let prev_dir =
std::env::current_dir().map_err(|e| format!("Failed to get current dir: {e}"))?;
let set_dir = std::env::set_current_dir(&cache_dir);
let rom_bytes = match set_dir {
Ok(_) => {
let result = crate::assemble_file(&tal_path)
.map_err(|e| format!("Failed to assemble canonical orca.tal: {e}"));
let _ = std::env::set_current_dir(&prev_dir);
result?
}
Err(e) => {
return Err(format!("Failed to set current dir to cache dir: {e}"));
}
};
std::fs::write(&orca_rom, &rom_bytes)
.map_err(|e| format!("Failed to write canonical orca.rom: {e}"))?;
}
let metadata =
std::fs::metadata(&orca_rom).map_err(|e| format!("orca.rom metadata error: {e}"))?;
if metadata.len() == 0 {
return Err(format!(
"orca.rom is empty in cache dir: {}",
orca_rom.display()
));
}
Ok((orca_rom, cache_dir))
}
use uxn_tal_common::cache::RomEntryResolver;
pub struct RealRomEntryResolver;
impl RomEntryResolver for RealRomEntryResolver {
fn resolve_entry_and_cache_dir(
&self,
url: &str,
) -> Result<(std::path::PathBuf, std::path::PathBuf), String> {
crate::fetch::downloader::resolve_and_fetch_entry(url).map_err(|e| format!("{e}"))
}
}
use crate::assemble_file;
use std::io::IsTerminal;
pub fn pause_on_error() {
if !std::io::stderr().is_terminal() && !std::io::stdout().is_terminal() {
return;
}
use std::{thread, time};
eprintln!("\n---\nKeeping window open for 15 seconds so you can read the above. Press Enter to continue...");
use std::sync::mpsc;
let (tx, rx) = mpsc::channel();
#[cfg(not(target_arch = "wasm32"))]
thread::spawn(move || {
let mut _buf = String::new();
let _ = std::io::stdin().read_line(&mut _buf);
let _ = tx.send(());
});
let _ = rx.recv_timeout(time::Duration::from_secs(15));
}
pub fn pause_for_windows() {
#[cfg(target_os = "windows")]
{
if std::io::stdout().is_terminal() || std::io::stderr().is_terminal() {
use std::io::Write;
print!("Press Enter to continue...");
let _ = std::io::stdout().flush();
let mut _buf = String::new();
let _ = std::io::stdin().read_line(&mut _buf);
}
}
}
use std::path::{Path, PathBuf};
pub struct RealRomCache;
impl uxn_tal_common::cache::RomCache for RealRomCache {
fn get_or_write_cached_rom(&self, url: &str, out_path: &Path) -> Result<PathBuf, String> {
let (entry_path, cache_dir) = crate::fetch::downloader::resolve_and_fetch_entry(url)
.map_err(|e| format!("resolve_and_fetch_entry failed: {e}"))?;
let rom_path = cache_dir.join(
out_path
.file_name()
.unwrap_or_else(|| std::ffi::OsStr::new("out.rom")),
);
if rom_path.exists() {
return Ok(rom_path);
}
if let Some(ext) = entry_path.extension() {
if ext == "rom" {
std::fs::copy(&entry_path, &rom_path)
.map_err(|e| format!("Failed to copy ROM: {e}"))?;
return Ok(rom_path);
}
}
let tal_path = entry_path;
let rom_bytes = assemble_file(&tal_path).map_err(|e| format!("Assembler error: {e}"))?;
std::fs::write(&rom_path, &rom_bytes).map_err(|e| format!("Failed to write ROM: {e}"))?;
Ok(rom_path)
}
}