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