// SPDX-FileCopyrightText: 2025 Ruby Iris Juric // // SPDX-License-Identifier: 0BSD use std::{fs, path::Path}; use miette::{Context, IntoDiagnostic, Result, miette}; use crate::gleam_toml::{self, GleamToml}; pub struct AppSpec { pub name: String, pub contents: String, } fn get_applications(otp_dependencies: &[String], gleam_toml: &GleamToml) -> Vec { let extra_applications = gleam_toml .erlang .as_ref() .and_then(|e| e.extra_applications.clone()) .unwrap_or_default(); let mut applications = [otp_dependencies, &extra_applications].concat(); applications.sort(); applications.dedup(); applications } fn get_modules(out_dir: &str) -> Result> { std::fs::read_dir(out_dir) .into_diagnostic()? .collect::, _>>() .into_diagnostic() .wrap_err(format!("While getting files in \"{out_dir}\":"))? .iter() .filter(|path| { path.path() .extension() .map(|ext| ext == "beam") .unwrap_or(false) }) .map(|path| { path.path() .file_stem() .and_then(|p| p.to_str()) .map(|p| p.to_string()) .ok_or(miette!("Non UTF-8 filename in directory")) }) .collect::, _>>() } fn generate_app_spec(otp_dependencies: &[String], out_dir: &str) -> Result { let gleam_toml = gleam_toml::parse("gleam.toml")?; let applications = get_applications(otp_dependencies, &gleam_toml).join(","); let modules = get_modules(out_dir)?.join(","); let start_module = gleam_toml .erlang .and_then(|e| e.application_start_module) .map(|module| format!("{{mod, {{'{module}', []}}}},\n")) .unwrap_or_default(); Ok(AppSpec { name: format!("{}.app", gleam_toml.name), contents: format!( r#"{{application, {0}, [ {{vsn, "{1}"}}, {start_module}{{applications, [{applications}]}}, {{description, "{2}"}}, {{modules, [{modules}]}}, {{registered, []}} ]}}."#, gleam_toml.name, gleam_toml.version, gleam_toml.description.unwrap_or_default() ), }) } pub fn generate_app_file(args: &[String]) -> Result<()> { let (out_path, otp_dependencies) = args .split_first() .ok_or(miette!("No output path specified"))?; let app_spec = generate_app_spec(otp_dependencies, &out_path)?; fs::write(Path::new(&out_path).join(&app_spec.name), app_spec.contents).into_diagnostic()?; println!("Successfully generated {}", app_spec.name); Ok(()) }