use std::{fs, path::PathBuf};
use clap::{Parser, ValueEnum};
use factorio_exporter::{load_api, FactorioExporter, FactorioExporterError, Result};
use indoc::printdoc;
use serde_json::Value;
use tracing::{debug, info};
#[derive(Parser, Debug)]
#[command(version)]
struct Args {
#[arg(long)]
factorio_dir: Option<PathBuf>,
#[arg(long)]
factorio_api_spec: Option<PathBuf>,
#[arg(long)]
factorio_binary: Option<PathBuf>,
#[arg(long, short)]
destination: Option<PathBuf>,
#[arg(long, short, default_value = "json")]
format: OutputFormat,
#[arg(long, short)]
icons: bool,
mods: Vec<PathBuf>,
}
#[derive(Clone, Debug, ValueEnum)]
#[clap(rename_all = "kebab_case")]
enum OutputFormat {
Json,
Yaml,
}
const RUNTIME_API_DEFINITION: &str = "doc-html/runtime-api.json";
#[cfg(windows)]
const FACTORIO_BINPATH: &str = "bin/x64/factorio.exe";
#[cfg(not(windows))]
const FACTORIO_BINPATH: &str = "bin/x64/factorio";
fn main() -> Result<()> {
let args = Args::parse();
debug!("Parsed arguments: {:?}", args);
let api_spec = std::fs::canonicalize(
args.factorio_api_spec
.or_else(|| {
args.factorio_dir
.as_ref()
.map(|d| d.join(RUNTIME_API_DEFINITION))
})
.ok_or_else(|| {
FactorioExporterError::InvocationError(
"One of --factorio-api-spec or --factorio-dir must be specified".into(),
)
})?,
)?;
let binary = std::fs::canonicalize(
args.factorio_binary
.or_else(|| args.factorio_dir.as_ref().map(|d| d.join(FACTORIO_BINPATH)))
.ok_or_else(|| {
FactorioExporterError::InvocationError(
"One of --factorio-binary or --factorio-dir must be specified".into(),
)
})?,
)?;
let api = load_api(&api_spec)?;
let exporter = FactorioExporter::new(&binary, &api, "en", args.icons)?;
exporter.install_mods(&args.mods)?;
match exporter.export() {
Ok(prototypes) => {
let parsed: Value = serde_yaml::from_value(prototypes)?;
let output = match args.format {
OutputFormat::Json => serde_json::to_string_pretty(&parsed)?,
OutputFormat::Yaml => serde_yaml::to_string(&parsed)?,
};
info!("write output");
match args.destination {
Some(path) => fs::write(path, output)?,
None => println!("{}", output),
}
}
Err(FactorioExporterError::FactorioExecutionError { stdout, stderr }) => {
printdoc! {r"
Failed to execute Factorio:
=== STDOUT
{}
=== STDERR
{}
", stdout, stderr};
}
Err(e) => return Err(e),
}
info!("done");
Ok(())
}