|
1 | 1 | use std::{
|
2 | 2 | collections::BTreeMap,
|
3 |
| - io::{Read, Seek}, |
4 |
| - path::Path, |
| 3 | + io::{Read, Seek, Write}, |
| 4 | + path::{Path, PathBuf}, |
5 | 5 | str::FromStr as _,
|
6 | 6 | sync::LazyLock,
|
7 | 7 | };
|
8 | 8 | use tangram_client as tg;
|
9 | 9 |
|
| 10 | +use crate::CLOSEST_ARTIFACT_PATH; |
| 11 | + |
10 | 12 | /// The magic number used to indicate an executable has a manifest.
|
11 | 13 | pub const MAGIC_NUMBER: &[u8] = b"tangram\0";
|
12 | 14 |
|
@@ -300,49 +302,70 @@ impl Manifest {
|
300 | 302 | .as_ref()
|
301 | 303 | .ok_or_else(|| tg::error!("expected a wrap binary"))?;
|
302 | 304 |
|
| 305 | + tg::cache::cache(tg, tg::cache::Arg { |
| 306 | + artifacts: vec![file.id().into(), stub.id().into(), wrap.id().into()] |
| 307 | + }) |
| 308 | + .await |
| 309 | + .map_err(|source| tg::error!(!source, "failed to cache artifacts"))?; |
| 310 | + |
| 311 | + // Get their paths on disk. |
| 312 | + let path: PathBuf = CLOSEST_ARTIFACT_PATH.clone().into(); |
| 313 | + let file = path.join(file.id().to_string()); |
| 314 | + let stub = path.join(stub.id().to_string()); |
| 315 | + let wrap = path.join(wrap.id().to_string()); |
| 316 | + |
| 317 | + // Create a temp file for the manifest. |
| 318 | + let mut manifest = tempfile::NamedTempFile::new().map_err(|source| tg::error!(!source, "failed to get temp file"))?; |
| 319 | + let output = "/tmp/__wrap_output__"; |
| 320 | + |
303 | 321 | // Create the manifest file. TODO: asyncify.
|
304 |
| - let contents = tangram_serialize::to_vec(self) |
| 322 | + let contents = serde_json::to_vec(self) |
305 | 323 | .map_err(|source| tg::error!(!source, "failed to serialize manifest"))?;
|
306 |
| - let contents = std::io::Cursor::new(contents); |
307 |
| - let blob = tg::Blob::with_reader(tg, contents) |
308 |
| - .await |
309 |
| - .map_err(|source| tg::error!(!source, "failed to create blob"))?; |
310 |
| - let manifest = tg::File::with_contents(blob); |
311 |
| - manifest |
312 |
| - .store(tg) |
313 |
| - .await |
314 |
| - .map_err(|source| tg::error!(!source, "failed to store manifest file"))?; |
315 |
| - |
316 |
| - let host = std::env::var("TANGRAM_HOST").map_err(|_| tg::error!("expected TANGRAM_HOST to be set"))?; |
317 |
| - |
318 |
| - // Run the build. |
319 |
| - let output = tg::build::build( |
320 |
| - tg, |
321 |
| - tg::build::Arg { |
322 |
| - executable: Some(tg::command::Executable::Artifact( |
323 |
| - tg::command::ArtifactExecutable { |
324 |
| - artifact: wrap.clone().into(), |
325 |
| - path: None, |
326 |
| - }, |
327 |
| - )), |
328 |
| - args: vec![ |
329 |
| - tg::Template::with_components(vec![file.clone().into()]).into(), |
330 |
| - tg::Template::with_components(vec![manifest.into()]).into(), |
331 |
| - tg::Template::with_components(vec![stub.clone().into()]).into(), |
332 |
| - ], |
333 |
| - host: Some(host), |
334 |
| - ..tg::build::Arg::default() |
335 |
| - }, |
336 |
| - ) |
337 |
| - .await |
338 |
| - .map_err(|source| tg::error!(!source, "failed to embed wrapper")) |
339 |
| - .inspect_err(|error| eprintln!("{error:#?}"))? |
340 |
| - .try_unwrap_object() |
341 |
| - .map_err(|_| tg::error!("expected an object"))? |
342 |
| - .try_unwrap_file() |
343 |
| - .map_err(|_| tg::error!("expected a file"))?; |
344 |
| - |
345 |
| - Ok(output) |
| 324 | + manifest.as_file_mut().write_all(&contents).map_err(|source| tg::error!(!source, "failed to write manifest"))?; |
| 325 | + |
| 326 | + // Run the command. |
| 327 | + let success = std::process::Command::new(wrap) |
| 328 | + .arg(file) |
| 329 | + .arg(manifest.path()) |
| 330 | + .arg(stub) |
| 331 | + .arg(output) |
| 332 | + .stdout(std::process::Stdio::inherit()) |
| 333 | + .stderr(std::process::Stdio::inherit()) |
| 334 | + .output() |
| 335 | + .map_err(|source| tg::error!(!source, "failed to wrap the binary"))? |
| 336 | + .status |
| 337 | + .success(); |
| 338 | + if !success { |
| 339 | + return Err(tg::error!("failed to run the command")); |
| 340 | + } |
| 341 | + |
| 342 | + let bytes = std::fs::read(output).map_err(|source| tg::error!(!source, "failed to read the output"))?; |
| 343 | + let cursor = std::io::Cursor::new(bytes); |
| 344 | + let blob = tg::Blob::with_reader(tg, cursor).await.map_err(|source| tg::error!(!source, "failed to create blob"))?; |
| 345 | + |
| 346 | + // Obtain the dependencies from the manifest to add to the file. |
| 347 | + // NOTE: We know the wrapper file has no dependencies, so there is no need to merge. |
| 348 | + let dependencies = self.dependencies(); |
| 349 | + let dependencies = if dependencies.is_empty() { |
| 350 | + None |
| 351 | + } else { |
| 352 | + Some(dependencies) |
| 353 | + }; |
| 354 | + |
| 355 | + // Create a file with the new blob and references. |
| 356 | + let mut output_file = tg::File::builder(blob).executable(true); |
| 357 | + if let Some(dependencies) = dependencies { |
| 358 | + output_file = output_file.dependencies(dependencies); |
| 359 | + } |
| 360 | + let output_file = output_file.build(); |
| 361 | + |
| 362 | + #[cfg(feature = "tracing")] |
| 363 | + { |
| 364 | + let file_id = output_file.id(); |
| 365 | + tracing::trace!(?file_id, "created wrapper file"); |
| 366 | + } |
| 367 | + |
| 368 | + Ok(output_file) |
346 | 369 | }
|
347 | 370 |
|
348 | 371 | /// Create a new wrapper from a manifest. Will locate the wrapper file from the `TANGRAM_WRAPPER_ID` environment variable.
|
|
0 commit comments