blob: 810ca4ca9d9eb477d91373a24cb9b04dcb2f1823 [file] [log] [blame]
// 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))
}