| // 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::{ |
| sdk::{ |
| amber_path, 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( |
| verbose: bool, |
| fuchsia_config: &FuchsiaConfig, |
| cmx_path: &Path, |
| ) -> Result<(), Error> { |
| if verbose { |
| println!("validate_cmx_file: cmx_path = {:#?}", cmx_path); |
| } |
| |
| 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( |
| verbose: bool, |
| target_options: &TargetOptions<'_, '_>, |
| target: &Path, |
| binary_path: &Path, |
| package_path: &Path, |
| cmx_path: &Path, |
| package_name: &str, |
| app_name: &str, |
| ) -> Result<(), Error> { |
| if verbose { |
| println!("write_manifest_file: target = {:#?}", target); |
| } |
| let mut manifest = File::create(&target)?; |
| let zircon_build = zircon_build_path(&target_options.config)?; |
| let libc_path = format!( |
| "{}/user-{}-clang.shlib/obj/system/ulib/c/libc.so", |
| zircon_build.to_string_lossy(), |
| target_options.config.fuchsia_arch |
| ); |
| let fdio_path = format!( |
| "{}/user-{}-clang.shlib/obj/system/ulib/fdio/libfdio.so", |
| zircon_build.to_string_lossy(), |
| target_options.config.fuchsia_arch |
| ); |
| let libsyslog_path = format!( |
| "{}/user-{}-clang.shlib/obj/system/ulib/syslog/libsyslog.so", |
| zircon_build.to_string_lossy(), |
| target_options.config.fuchsia_arch |
| ); |
| writeln!( |
| manifest, |
| r#"bin/{}={} |
| lib/ld.so.1={} |
| lib/libfdio.so={} |
| lib/libsyslog.so={} |
| meta/package={} |
| meta/{}.cmx={} |
| "#, |
| app_name, |
| binary_path.to_string_lossy(), |
| libc_path, |
| fdio_path, |
| libsyslog_path, |
| package_path.to_string_lossy(), |
| package_name, |
| cmx_path.to_string_lossy(), |
| )?; |
| Ok(()) |
| } |
| |
| fn write_package_file(verbose: bool, target: &Path, package_name: &str) -> Result<(), Error> { |
| let mut package = File::create(&target)?; |
| let package_contents = json!({ |
| "name": package_name, |
| "version": "0" |
| }); |
| if verbose { |
| println!("write_package_file: target = {:#?}", target); |
| println!("write_package_file: package_contents = {:#?}", package_contents); |
| } |
| writeln!(package, "{}", package_contents.to_string())?; |
| Ok(()) |
| } |
| |
| fn pm_build( |
| verbose: bool, |
| 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"); |
| if verbose { |
| println!("pm_build: package_manager_path = {:#?}", pm); |
| println!("pm_build: fuchsia_dir = {:#?}", fuchsia_dir); |
| println!("pm_build: dev_key_path = {:#?}", dev_key_path); |
| println!("pm_build: manifest_path = {:#?}", manifest_path); |
| println!("pm_build: output_path = {:#?}", output_path); |
| } |
| 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( |
| verbose: bool, |
| target_options: &TargetOptions<'_, '_>, |
| output_path: &Path, |
| manifest_path: &Path, |
| ) -> Result<(), Error> { |
| if verbose { |
| println!("pm_archive: output_path = {:#?}", output_path); |
| println!("pm_archive: manifest_path = {:#?}", manifest_path); |
| } |
| 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 `pm_archive` to build an archive")?; |
| |
| if !output.status.success() { |
| bail!("pm returned error: {}", String::from_utf8_lossy(&output.stderr)); |
| } |
| |
| Ok(()) |
| } |
| |
| fn pm_publish( |
| verbose: bool, |
| target_options: &TargetOptions<'_, '_>, |
| output_path: &Path, |
| ) -> Result<(), Error> { |
| let pm = package_manager_path(target_options.config)?; |
| let tuf_root = amber_path(target_options.config)?; |
| if verbose { |
| println!("pm_publish: output_path = {:#?}", output_path); |
| println!("pm_publish: tuf_root = {:#?}", tuf_root); |
| } |
| 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 `publish` to publish package")?; |
| |
| if !output.status.success() { |
| bail!("pm returned error: {}", String::from_utf8_lossy(&output.stderr)); |
| } |
| |
| Ok(()) |
| } |
| |
| pub fn make_package( |
| verbose: bool, |
| target_options: &TargetOptions<'_, '_>, |
| binary_path: &Path, |
| cmx_path: &Path, |
| app_name: &str, |
| ) -> 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"); |
| if verbose { |
| println!("make_package: package_name = {:#?}", package_name); |
| } |
| let output_path = binary_parent.join(&package_name); |
| if verbose { |
| println!("make_package: output_path = {:#?}", output_path); |
| } |
| create_dir_all(&output_path).context("create_dir_all failed")?; |
| let stripped_binary_path = strip_binary(binary_path)?; |
| validate_cmx_file(verbose, &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(verbose, &package_path, &package_name)?; |
| let manifest_path = PathBuf::from("/tmp/manifest"); |
| write_manifest_file( |
| verbose, |
| &target_options, |
| &manifest_path, |
| &stripped_binary_path, |
| &package_path, |
| &formatted_path, |
| &package_name, |
| app_name, |
| )?; |
| pm_build(verbose, &target_options, &manifest_path, &output_path).context("pm_build failed")?; |
| pm_archive(verbose, &target_options, &output_path, &manifest_path) |
| .context("pm_archive failed")?; |
| pm_publish(verbose, &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)) |
| } |