1use std::collections::BTreeMap;
6use std::path::{Path, PathBuf};
7
8use yog_ids::Format;
9use yog_script_build::{JvmBuild, build_jar};
10
11use crate::diagnostics;
12use crate::project::manifest::{SOURCES_DIR, YogToml};
13
14const PACKAGE_ROOT: &str = "yogscript";
16const WORK_DIR: &str = "scripts";
18const JAVAC: &str = "javac";
22const JDK_BIN: &str = "bin";
24
25pub fn jars(
27 root: &Path,
28 meta: &YogToml,
29 build_dir: &Path,
30) -> Result<Vec<(String, Vec<u8>)>, String> {
31 let sources = sources(root)?;
32 if sources.is_empty() {
33 return Ok(Vec::new());
34 }
35 let home = yog_home::Home::locate()?;
36 let resolver = yog_home::targets::Resolver::new(&home)?;
37 let api = resolver.java_api_jar().ok_or(
38 "Yog Script needs the loader SDK's java-api jar: `./build.sh build api` in the SDK",
39 )?;
40 let package = format!("{PACKAGE_ROOT}.{}", yog_ids::mod_lib_name(&meta.id));
41 let mut out = Vec::new();
42 for (mc, java) in versions(&resolver)? {
43 let javac = resolver.jdk(java).map_or_else(
44 || PathBuf::from(JAVAC),
45 |jdk| {
46 jdk.join(JDK_BIN)
47 .join(format!("{JAVAC}{}", std::env::consts::EXE_SUFFIX))
48 },
49 );
50 let work = build_dir.join(WORK_DIR).join(&mc);
51 let jar = build_dir
52 .join(WORK_DIR)
53 .join(format!("{mc}-{}.jar", meta.id));
54 let b = JvmBuild {
55 javac: &javac,
56 release: java,
57 classpath: std::slice::from_ref(&api),
58 package: &package,
59 work: &work,
60 to_server: meta.to_server,
61 };
62 if let Err(problems) = build_jar(&sources, &b, &jar) {
63 diagnostics::report_all(&problems);
64 problems.iter().for_each(|d| yog_logging::error!("{d}"));
65 return Err(format!("the Yog Script didn't build for {mc}"));
66 }
67 let bytes = std::fs::read(&jar).map_err(|e| format!("{}: {e}", jar.display()))?;
68 out.push((
69 format!("{}/{mc}/{}.jar", yog_ids::archive::SCRIPTS, meta.id),
70 bytes,
71 ));
72 yog_logging::info!("scripts for {mc} (Java {java})");
73 }
74 Ok(out)
75}
76
77fn sources(root: &Path) -> Result<Vec<(String, String)>, String> {
80 crate::files::of(&root.join(SOURCES_DIR), Format::Script)
81 .into_iter()
82 .map(|f| {
83 let text = std::fs::read_to_string(&f).map_err(|e| format!("{}: {e}", f.display()))?;
84 Ok((crate::shown_path(root, &f), text))
85 })
86 .collect()
87}
88
89fn versions(resolver: &yog_home::targets::Resolver) -> Result<BTreeMap<String, u32>, String> {
91 let mut out = BTreeMap::new();
92 for t in resolver.targets()? {
93 if let (Some(mc), Some(java)) = (t.variant.clone(), t.java()) {
94 out.insert(mc, java);
95 }
96 }
97 if out.is_empty() {
98 return Err("no game version to build the Yog Script for: no loader SDK".into());
99 }
100 Ok(out)
101}