blob: d4cac4d8d6d996c92c50687b950a9e3b02dfc66f [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::{
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))
}