Skip to content

Commit fc33f46

Browse files
committed
Finish install sdk operation screen
1 parent 6bd3285 commit fc33f46

File tree

8 files changed

+285
-77
lines changed

8 files changed

+285
-77
lines changed

src-tauri/src/builder/sdk.rs

Lines changed: 155 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,44 @@ use std::fs;
66
use std::os::unix::fs::symlink;
77
use std::path::{Component, Path, PathBuf};
88
use std::process::Command;
9-
use tauri::{AppHandle, Manager};
9+
use tauri::{AppHandle, Manager, Window};
1010

1111
use crate::builder::swift::{swift_bin, validate_toolchain};
12+
use crate::operation::Operation;
1213

1314
const DARWIN_TOOLS_VERSION: &str = "1.0.1";
1415

1516
#[tauri::command]
1617
pub async fn install_sdk_operation(
1718
app: AppHandle,
19+
window: Window,
1820
xcode_path: String,
1921
toolchain_path: String,
2022
) -> Result<(), String> {
23+
let op = Operation::new("install_sdk".to_string(), &window);
2124
let work_dir = std::env::temp_dir().join("DarwinSDKBuild");
22-
let res = install_sdk_internal(app, xcode_path, toolchain_path, work_dir.clone()).await;
25+
let res = install_sdk_internal(app, xcode_path, toolchain_path, work_dir.clone(), &op).await;
26+
op.start("cleanup")?;
2327
let cleanup_result = if work_dir.exists() {
2428
fs::remove_dir_all(&work_dir)
2529
} else {
2630
Ok(())
2731
};
28-
match (res, cleanup_result) {
32+
33+
let cleanup_result_for_match = cleanup_result
34+
.as_ref()
35+
.map(|_| ())
36+
.map_err(|e| format!("{}", e));
37+
38+
let cleanup_result = op.fail_if_err_map("cleanup", cleanup_result, |e| {
39+
format!("Failed to remove temp dir: {}", e)
40+
});
41+
42+
if cleanup_result.is_ok() {
43+
op.complete("cleanup")?;
44+
}
45+
46+
match (res, cleanup_result_for_match) {
2947
(Err(main_err), Err(cleanup_err)) => Err(format!(
3048
"{main_err} (additionally, failed to clean up temp dir: {cleanup_err})"
3149
)),
@@ -41,7 +59,19 @@ async fn install_sdk_internal(
4159
xcode_path: String,
4260
toolchain_path: String,
4361
work_dir: PathBuf,
62+
op: &Operation<'_>,
4463
) -> Result<(), String> {
64+
op.start("create_stage")?;
65+
if xcode_path.is_empty() || !xcode_path.ends_with(".xip") {
66+
return op.fail("create_stage", "Xcode not found".to_string());
67+
}
68+
if toolchain_path.is_empty() {
69+
return op.fail("create_stage", "Toolchain not found".to_string());
70+
}
71+
if !validate_toolchain(&toolchain_path) {
72+
return op.fail("create_stage", "Invalid toolchain path".to_string());
73+
}
74+
4575
let swift_bin = swift_bin(&toolchain_path)?;
4676
let output = std::process::Command::new(swift_bin)
4777
.arg("sdk")
@@ -50,32 +80,31 @@ async fn install_sdk_internal(
5080
.output();
5181
if let Ok(output) = output {
5282
if !output.status.success() && output.status.code() != Some(1) {
53-
return Err(format!(
54-
"Failed to remove existing darwin SDK: {}",
55-
String::from_utf8_lossy(&output.stderr)
56-
));
83+
return op.fail(
84+
"create_stage",
85+
format!(
86+
"Failed to remove existing darwin SDK: {}",
87+
String::from_utf8_lossy(&output.stderr)
88+
),
89+
);
5790
}
5891
}
59-
if xcode_path.is_empty() || !xcode_path.ends_with(".xip") {
60-
return Err("Xcode not found".to_string());
61-
}
62-
if toolchain_path.is_empty() {
63-
return Err("Toolchain not found".to_string());
64-
}
65-
if !validate_toolchain(&toolchain_path) {
66-
return Err("Invalid toolchain path".to_string());
67-
}
92+
6893
let output_dir = work_dir.join("darwin.artifactbundle");
6994
if output_dir.exists() {
70-
fs::remove_dir_all(&output_dir)
71-
.map_err(|e| format!("Failed to remove existing output directory: {}", e))?;
95+
op.fail_if_err_map("create_stage", fs::remove_dir_all(&output_dir), |e| {
96+
format!("Failed to remove existing output directory: {}", e)
97+
})?;
7298
}
73-
fs::create_dir_all(&output_dir)
74-
.map_err(|e| format!("Failed to create output directory: {}", e))?;
75-
76-
install_toolset(&output_dir).await?;
99+
op.fail_if_err_map("create_stage", fs::create_dir_all(&output_dir), |e| {
100+
format!("Failed to create output directory: {}", e)
101+
})?;
77102

78-
let dev = install_developer(&app, &output_dir, &xcode_path).await?;
103+
op.move_on("create_stage", "install_toolset")?;
104+
op.fail_if_err("install_toolset", install_toolset(&output_dir).await)?;
105+
op.complete("install_toolset")?;
106+
let dev = install_developer(&app, &output_dir, &xcode_path, op).await?;
107+
op.start("write_metadata")?;
79108

80109
let iphone_os_sdk = sdk(&dev, "iPhoneOS")?;
81110
let mac_os_sdk = sdk(&dev, "MacOSX")?;
@@ -98,8 +127,11 @@ async fn install_sdk_internal(
98127
}
99128
}
100129
";
101-
fs::write(output_dir.join("info.json"), info)
102-
.map_err(|e| format!("Failed to write info.json: {}", e))?;
130+
op.fail_if_err_map(
131+
"write_metadata",
132+
fs::write(output_dir.join("info.json"), info),
133+
|e| format!("Failed to write info.json: {}", e),
134+
)?;
103135

104136
let toolset = "
105137
{
@@ -115,8 +147,11 @@ async fn install_sdk_internal(
115147
}
116148
}
117149
";
118-
fs::write(output_dir.join("toolset.json"), toolset)
119-
.map_err(|e| format!("Failed to write toolset.json: {}", e))?;
150+
op.fail_if_err_map(
151+
"write_metadata",
152+
fs::write(output_dir.join("toolset.json"), toolset),
153+
|e| format!("Failed to write toolset.json: {}", e),
154+
)?;
120155

121156
let sdk_def = SDKDefinition {
122157
schema_version: "4.0".to_string(),
@@ -145,35 +180,56 @@ async fn install_sdk_internal(
145180
};
146181

147182
let sdk_def_path = output_dir.join("swift-sdk.json");
148-
fs::write(
149-
sdk_def_path,
150-
serde_json::to_string_pretty(&sdk_def)
151-
.map_err(|e| format!("Failed to serialize SDKDefinition: {}", e))?,
152-
)
153-
.map_err(|e| format!("Failed to write swift-sdk.json: {}", e))?;
183+
op.fail_if_err_map(
184+
"write_metadata",
185+
fs::write(
186+
sdk_def_path,
187+
op.fail_if_err_map(
188+
"write_metadata",
189+
serde_json::to_string_pretty(&sdk_def),
190+
|e| format!("Failed to serialize SDKDefinition: {}", e),
191+
)?,
192+
),
193+
|e| format!("Failed to write swift-sdk.json: {}", e),
194+
)?;
195+
154196
let sdk_version_path = output_dir.join("darwin-sdk-version.txt");
155-
fs::write(&sdk_version_path, "develop")
156-
.map_err(|e| format!("Failed to write darwin-sdk-version.txt: {}", e))?;
197+
op.fail_if_err_map(
198+
"write_metadata",
199+
fs::write(&sdk_version_path, "develop"),
200+
|e| format!("Failed to write darwin-sdk-version.txt: {}", e),
201+
)?;
202+
op.move_on("write_metadata", "install_sdk")?;
157203

158204
let path = PathBuf::from(toolchain_path);
159205
let swift_path = path.join("usr").join("bin").join("swift");
160206
if !swift_path.exists() || !swift_path.is_file() {
161-
return Err("Swift binary not found in toolchain".to_string());
207+
return op.fail(
208+
"install_sdk",
209+
"Swift binary not found in toolchain".to_string(),
210+
);
162211
}
163212

164-
let output = std::process::Command::new(swift_path)
165-
.arg("sdk")
166-
.arg("install")
167-
.arg(output_dir.to_string_lossy().to_string())
168-
.output()
169-
.map_err(|e| format!("Failed to execute swift command: {}", e))?;
213+
let output = op.fail_if_err_map(
214+
"install_sdk",
215+
std::process::Command::new(swift_path)
216+
.arg("sdk")
217+
.arg("install")
218+
.arg(output_dir.to_string_lossy().to_string())
219+
.output(),
220+
|e| format!("Failed to execute swift command: {}", e),
221+
)?;
170222

171223
if !output.status.success() {
172-
return Err(format!(
173-
"Swift command failed: {}",
174-
String::from_utf8_lossy(&output.stderr)
175-
));
224+
return op.fail(
225+
"install_sdk",
226+
format!(
227+
"Swift command failed: {}",
228+
String::from_utf8_lossy(&output.stderr)
229+
),
230+
);
176231
}
232+
op.complete("install_sdk")?;
177233

178234
Ok(())
179235
}
@@ -236,51 +292,79 @@ async fn install_developer(
236292
app: &AppHandle,
237293
output_path: &PathBuf,
238294
xcode_path: &str,
295+
op: &Operation<'_>,
239296
) -> Result<PathBuf, String> {
297+
op.start("extract_xip")?;
240298
let dev_stage = output_path.join("DeveloperStage");
241-
fs::create_dir_all(&dev_stage)
242-
.map_err(|e| format!("Failed to create DeveloperStage directory: {}", e))?;
299+
op.fail_if_err_map("extract_xip", fs::create_dir_all(&dev_stage), |e| {
300+
format!("Failed to create DeveloperStage directory: {}", e)
301+
})?;
243302

244-
let unxip_path = app
245-
.path()
246-
.resolve("unxip", tauri::path::BaseDirectory::Resource)
247-
.map_err(|e| format!("Failed to resolve unxip path: {}", e))?;
303+
let unxip_path = op.fail_if_err_map(
304+
"extract_xip",
305+
app.path()
306+
.resolve("unxip", tauri::path::BaseDirectory::Resource),
307+
|e| format!("Failed to resolve unxip path: {}", e),
308+
)?;
248309

249310
let status = Command::new(unxip_path)
250311
.current_dir(&dev_stage)
251312
.arg(xcode_path)
252-
.status();
313+
.output();
253314
if let Err(e) = status {
254-
return Err(format!("Failed to run unxip: {}", e));
315+
return op.fail("extract_xip", format!("Failed to run unxip: {}", e));
255316
}
256-
if !status.unwrap().success() {
257-
return Err("Failed to unxip Xcode".to_string());
317+
let status = status.unwrap();
318+
if !status.status.success() {
319+
return op.fail(
320+
"extract_xip",
321+
format!(
322+
"{}\nProcess exited with code {}",
323+
String::from_utf8_lossy(&status.stderr.trim_ascii()),
324+
status.status.code().unwrap_or(0)
325+
),
326+
);
258327
}
259328

260-
let app_dirs = fs::read_dir(&dev_stage)
261-
.map_err(|e| format!("Failed to read DeveloperStage directory: {}", e))?
329+
let app_dirs = op
330+
.fail_if_err_map("extract_xip", fs::read_dir(&dev_stage), |e| {
331+
format!("Failed to read DeveloperStage directory: {}", e)
332+
})?
262333
.filter_map(Result::ok)
263334
.filter(|entry| entry.path().extension().map_or(false, |ext| ext == "app"))
264335
.collect::<Vec<_>>();
265336
if app_dirs.len() != 1 {
266-
return Err(format!(
267-
"Expected one .app in DeveloperStage, found {}",
268-
app_dirs.len()
269-
));
337+
return op.fail(
338+
"extract_xip",
339+
format!(
340+
"Expected one .app in DeveloperStage, found {}",
341+
app_dirs.len()
342+
),
343+
);
270344
}
271345

346+
op.move_on("extract_xip", "copy_files")?;
272347
let app_path = app_dirs[0].path();
273348
let dev = output_path.join("Developer");
274-
fs::create_dir_all(&dev).map_err(|e| format!("Failed to create Developer directory: {}", e))?;
349+
op.fail_if_err_map("copy_files", fs::create_dir_all(&dev), |e| {
350+
format!("Failed to create Developer directory: {}", e)
351+
})?;
275352

276353
let contents_developer = app_path.join("Contents/Developer");
277354
if !contents_developer.exists() {
278-
return Err("Contents/Developer not found in .app".to_string());
355+
return op.fail(
356+
"copy_files",
357+
"Contents/Developer not found in .app".to_string(),
358+
);
279359
}
280-
copy_developer(&contents_developer, &dev, Path::new("Contents/Developer"))
281-
.map_err(|e| format!("Failed to copy Developer: {}", e))?;
282-
fs::remove_dir_all(&dev_stage)
283-
.map_err(|e| format!("Failed to remove DeveloperStage directory: {}", e))?;
360+
361+
op.fail_if_err(
362+
"copy_files",
363+
copy_developer(&contents_developer, &dev, Path::new("Contents/Developer")),
364+
)?;
365+
op.fail_if_err_map("copy_files", fs::remove_dir_all(&dev_stage), |e| {
366+
format!("Failed to remove DeveloperStage directory: {}", e)
367+
})?;
284368

285369
for platform in ["iPhoneOS", "MacOSX", "iPhoneSimulator"] {
286370
let lib = "../../../../../Library";
@@ -310,7 +394,7 @@ async fn install_developer(
310394

311395
for (name, target) in &links {
312396
let link_path = dest.join(name);
313-
symlink(target, &link_path).map_err(|e| {
397+
op.fail_if_err_map("copy_files", symlink(target, &link_path), |e| {
314398
format!(
315399
"Failed to create symlink {:?} -> {:?}: {}",
316400
link_path, target, e
@@ -319,6 +403,8 @@ async fn install_developer(
319403
}
320404
}
321405

406+
op.complete("copy_files")?;
407+
322408
Ok(dev)
323409
}
324410

src-tauri/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ mod templates;
99
mod windows;
1010
#[macro_use]
1111
mod builder;
12+
mod operation;
1213
mod sideloader;
1314

1415
use device::refresh_idevice;

0 commit comments

Comments
 (0)