| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| use crate::{ |
| get_target_triple, |
| sdk::{ |
| amber_path, clang_resource_dir, cmc_path, fuchsia_dir, package_manager_path, |
| zircon_build_path, FuchsiaConfig, TargetOptions, |
| }, |
| utils::strip_binary, |
| }; |
| use failure::{bail, format_err, Error, ResultExt}; |
| use serde_json::json; |
| use std::{ |
| fs::{create_dir_all, File}, |
| io::Write, |
| path::{Path, PathBuf}, |
| process::Command, |
| }; |
| |
| fn validate_cmx_file(fuchsia_config: &FuchsiaConfig, cmx_path: &Path) -> Result<(), Error> { |
| let cmc = cmc_path(fuchsia_config)?; |
| |
| let output = Command::new(cmc) |
| .arg("validate") |
| .arg(cmx_path) |
| .output() |
| .context("Running `cmc` to validate cmx file")?; |
| |
| if !output.status.success() { |
| bail!("cmc returned error: {}", String::from_utf8_lossy(&output.stderr)); |
| } |
| |
| Ok(()) |
| } |
| |
| fn format_cmx_file(fuchsia_config: &FuchsiaConfig, cmx_path: &Path) -> Result<PathBuf, Error> { |
| let destination_path = format!( |
| "/tmp/{}", |
| cmx_path |
| .file_name() |
| .ok_or(format_err!("file_name failed on {:#?}", cmx_path))? |
| .to_string_lossy() |
| ); |
| |
| let cmc = cmc_path(fuchsia_config)?; |
| |
| let output = Command::new(cmc) |
| .arg("format") |
| .arg(cmx_path) |
| .arg("-o") |
| .arg(&destination_path) |
| .output() |
| .context("Running `cmc` to format cmx file")?; |
| |
| if !output.status.success() { |
| bail!("cmc returned error: {}", String::from_utf8_lossy(&output.stderr)); |
| } |
| |
| Ok(PathBuf::from(destination_path)) |
| } |
| |
| fn write_manifest_file( |
| target_options: &TargetOptions<'_, '_>, |
| target: &Path, |
| binary_path: &Path, |
| package_path: &Path, |
| cmx_path: &Path, |
| package_name: &str, |
| ) -> Result<(), Error> { |
| let mut manifest = File::create(&target)?; |
| let zircon_build = zircon_build_path(&target_options.config)?; |
| let libc_path = format!( |
| "{}/user-{}-gcc.shlib/obj/system/ulib/c/libc.so", |
| zircon_build.to_string_lossy(), |
| target_options.config.fuchsia_arch |
| ); |
| let fdio_path = format!( |
| "{}/user-{}-gcc.shlib/obj/system/ulib/fdio/libfdio.so", |
| zircon_build.to_string_lossy(), |
| target_options.config.fuchsia_arch |
| ); |
| let target_triple = get_target_triple(target_options); |
| let clang_resource_lib = clang_resource_dir(&target_triple)?.join(&target_triple).join("lib"); |
| let libsyslog_path = format!( |
| "{}/user-{}-gcc.shlib/obj/system/ulib/syslog/libsyslog.so", |
| zircon_build.to_string_lossy(), |
| target_options.config.fuchsia_arch |
| ); |
| writeln!( |
| manifest, |
| r#"bin/app={} |
| lib/ld.so.1={} |
| lib/libfdio.so={} |
| lib/libunwind.so.1={}/libunwind.so.1 |
| lib/libsyslog.so={} |
| meta/package={} |
| meta/{}.cmx={} |
| "#, |
| binary_path.to_string_lossy(), |
| libc_path, |
| fdio_path, |
| clang_resource_lib.to_string_lossy(), |
| libsyslog_path, |
| package_path.to_string_lossy(), |
| package_name, |
| cmx_path.to_string_lossy(), |
| )?; |
| Ok(()) |
| } |
| |
| fn write_package_file(target: &Path, package_name: &str) -> Result<(), Error> { |
| let mut package = File::create(&target)?; |
| let package_contents = json!({ |
| "name": package_name, |
| "version": "0" |
| }); |
| writeln!(package, "{}", package_contents.to_string())?; |
| Ok(()) |
| } |
| |
| fn pm_build( |
| target_options: &TargetOptions<'_, '_>, |
| manifest_path: &Path, |
| output_path: &Path, |
| ) -> Result<(), Error> { |
| let pm = package_manager_path(target_options.config)?; |
| |
| let fuchsia_dir = fuchsia_dir()?; |
| let dev_key_path = fuchsia_dir.join("build/development.key"); |
| let output = Command::new(pm) |
| .arg("-k") |
| .arg(dev_key_path) |
| .arg("-o") |
| .arg(&output_path) |
| .arg("-m") |
| .arg(&manifest_path) |
| .arg("build") |
| .arg("-depfile") |
| .arg("-blobsfile") |
| .arg("-blobs-manifest") |
| .output() |
| .context("Running `cmc` to format cmx file")?; |
| |
| if !output.status.success() { |
| bail!("pm returned error: {}", String::from_utf8_lossy(&output.stderr)); |
| } |
| |
| Ok(()) |
| } |
| |
| fn pm_archive( |
| target_options: &TargetOptions<'_, '_>, |
| output_path: &Path, |
| manifest_path: &Path, |
| ) -> Result<(), Error> { |
| let pm = package_manager_path(target_options.config)?; |
| |
| let output = Command::new(pm) |
| .arg("-o") |
| .arg(&output_path) |
| .arg("-m") |
| .arg(&manifest_path) |
| .arg("archive") |
| .output() |
| .context("Running `cmc` to format cmx file")?; |
| |
| if !output.status.success() { |
| bail!("pm returned error: {}", String::from_utf8_lossy(&output.stderr)); |
| } |
| |
| Ok(()) |
| } |
| |
| fn pm_publish(target_options: &TargetOptions<'_, '_>, output_path: &Path) -> Result<(), Error> { |
| let pm = package_manager_path(target_options.config)?; |
| let tuf_root = amber_path(target_options.config)?; |
| let output = Command::new(pm) |
| .arg("publish") |
| .arg("-a") |
| .arg("-f") |
| .arg(output_path) |
| .arg("-r") |
| .arg(tuf_root) |
| .arg("-vt") |
| .arg("-v") |
| .output() |
| .context("Running `cmc` to format cmx file")?; |
| |
| if !output.status.success() { |
| bail!("pm returned error: {}", String::from_utf8_lossy(&output.stderr)); |
| } |
| |
| Ok(()) |
| } |
| |
| pub fn make_package( |
| target_options: &TargetOptions<'_, '_>, |
| binary_path: &Path, |
| cmx_path: &Path, |
| ) -> Result<String, Error> { |
| let binary_parent = |
| binary_path.parent().expect(&format!("Can't get parent of {:#?}", binary_path)); |
| let mut package_name = binary_path |
| .file_name() |
| .expect("file_name failed on binary_path") |
| .to_string_lossy() |
| .to_string(); |
| package_name.push_str("_fargo"); |
| let output_path = binary_parent.join(&package_name); |
| create_dir_all(&output_path).context("create_dir_all failed")?; |
| let stripped_binary_path = strip_binary(binary_path)?; |
| validate_cmx_file(&target_options.config, cmx_path)?; |
| let formatted_path = format_cmx_file(&target_options.config, cmx_path)?; |
| let package_path = PathBuf::from("/tmp/package"); |
| write_package_file(&package_path, &package_name)?; |
| let manifest_path = PathBuf::from("/tmp/manifest"); |
| write_manifest_file( |
| &target_options, |
| &manifest_path, |
| &stripped_binary_path, |
| &package_path, |
| &formatted_path, |
| &package_name, |
| )?; |
| pm_build(&target_options, &manifest_path, &output_path).context("pm_build failed")?; |
| pm_archive(&target_options, &output_path, &manifest_path).context("pm_archive failed")?; |
| pm_publish(&target_options, &output_path.join(format!("{}-0.far", package_name))) |
| .context("pm_publish failed")?; |
| Ok(format!("fuchsia-pkg://fuchsia.com/{}#meta/{}.cmx", package_name, package_name)) |
| } |