1use core::str;
54use inline_colorization::*;
55use std::{
56 path::{Component, PathBuf},
57 process::Command,
58};
59
60#[macro_export]
61macro_rules! build_react_under {
62 ($s:expr) => {
63 ($crate::build_my_react_js($s, env!("CARGO_MANIFEST_DIR")))
64 };
65}
66
67pub fn build_my_react_js(path: &str, outer_env: &str) {
70 match build_my_react_js_fallible(path, outer_env, false) {
71 Ok(_) => (),
72 Err(err_msg) => panic!("{err_msg}"),
73 }
74}
75
76pub fn build_my_react_js_silent(path: &str, outer_env: &str) {
78 match build_my_react_js_fallible(path, outer_env, true) {
79 Ok(_) => (),
80 Err(err_msg) => panic!("{err_msg}"),
81 }
82}
83
84pub fn build_my_react_js_fallible(path: &str, outer_env: &str, silent: bool) -> Result<(), String> {
98 let mut d = PathBuf::from(outer_env);
99 d.push(format!("{path}/build/index.html"));
100 if d.components().any(|z| {
101 z == Component::ParentDir
102 || z.as_os_str()
103 .as_encoded_bytes()
104 .iter()
105 .find(|&c| *c == b'*')
106 != None
107 }) {
108 return Err(format!("{style_bold}{color_bright_red}ReactJS Frontend build error:{color_reset}{style_reset} Invalid separator provided, '{path}'"));
109 }
110 match std::fs::exists(PathBuf::from(d)) {
111 Ok(defined) => {
112 if defined {
113 let mut d = PathBuf::from(outer_env);
114 d.push(format!("{path}/src/"));
115 println!("cargo::rerun-if-changed={}", d.to_string_lossy());
116
117 let mut d = PathBuf::from(outer_env);
118 d.push(format!("{path}/package.json"));
119 println!("cargo::rerun-if-changed={}", d.to_string_lossy());
120 } else {
121 let mut d = PathBuf::from(outer_env);
122 d.push(format!("{path}/"));
123 if let Ok(output) = Command::new("npm").arg("ping").output() {
124 if !output.status.success() {
125 print_warning(
126 format!("Unable to locate npm, cannot complete build."),
127 silent,
128 );
129
130 print_warning(
131 format!("Failed with: {}", str::from_utf8(&output.stdout).unwrap()),
132 silent,
133 );
134 return Err(format!("{style_bold}{color_bright_red}ReactJS Frontend build error:{color_reset}{style_reset}NPM unavailable"));
135 } else {
136 print_warning(format!("Located NPM for frontend build."), silent);
137 }
138 } else {
139 return Err(format!("{style_bold}{color_bright_red}ReactJS Frontend build error:{color_reset}{style_reset} Node Package Manager not found, or npm registry unreachable! Ensure the system is configured with npm."));
140 }
141
142 let mut d = PathBuf::from(outer_env);
143 d.push(format!("{path}/"));
144 if let Ok(output) = Command::new("npm")
145 .current_dir(d)
146 .arg(format!("install"))
147 .output()
148 {
149 if !output.status.success() {
150 print_warning(format!("NPM build failed."), silent);
151 print_warning(
152 format!(
153 "NPM build reported:{}",
154 str::from_utf8(&output.stdout).unwrap()
155 ),
156 silent,
157 );
158 return Err(format!("{style_bold}{color_bright_red}ReactJS Frontend build error:{color_reset}{style_reset} NPM unavailable"));
159 } else {
160 print_warning(format!("Installed **node_modules**"), silent);
161 }
162 } else {
163 return Err(format!("{style_bold}{color_bright_red}ReactJS Frontend build error:{color_reset}{style_reset} Node Package Manager error! Check system logs."));
164 }
165 }
166 }
167 Err(e) => return Err(e.to_string()),
168 }
169
170 let mut d = PathBuf::from(outer_env);
171 d.push(format!("{path}/"));
172 if let Ok(output) = Command::new("npm").arg("ping").output() {
173 if !output.status.success() {
174 print_warning(
175 format!("Unable to locate npm, cannot complete build."),
176 silent,
177 );
178 print_warning(
179 format!("Failed with: {}", str::from_utf8(&output.stdout).unwrap()),
180 silent,
181 );
182 return Err(format!("{style_bold}{color_bright_red}ReactJS Frontend build error:{color_reset}{style_reset} NPM unavailable"));
183 } else {
184 print_warning(format!("Located NPM for frontend build."), silent);
185 }
186 } else {
187 return Err(
188 format!("{style_bold}{color_bright_red}ReactJS Frontend build error:{color_reset}{style_reset} Node Package Manager not found! Ensure the system is configured with npm."),
189 );
190 }
191
192 let mut d = PathBuf::from(outer_env);
193 d.push(format!("{path}/"));
194 if let Ok(output) = Command::new("npm")
195 .current_dir(d)
196 .arg("run")
197 .arg("build")
198 .output()
199 {
200 if !output.status.success() {
201 print_warning(format!("NPM build failed."), silent);
202 print_warning(
203 format!(
204 "NPM build reported:{}",
205 str::from_utf8(&output.stdout).unwrap()
206 ),
207 silent,
208 );
209 return Err(format!("{style_bold}{color_bright_red}ReactJS Frontend build error:{color_reset}{style_reset} NPM unavailable"));
210 } else {
211 print_warning(format!("Frontend build completed successfully!"), silent);
212 }
213 } else {
214 return Err(format!("{style_bold}{color_bright_red}ReactJS Frontend build error:{color_reset}{style_reset} Node Package Manager error! Check system logs."));
215 }
216
217 Ok(())
218}
219
220#[doc(hidden)]
221fn print_warning(s: String, silent: bool) {
222 if !silent {
223 println!("cargo::warning={}", s);
224 }
225}