blob: d28d193769c2f1a40c1f82cb8bafeed5dbe672c3 [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::model::{Resolver, ResolverError},
cm_fidl_translator::translate,
fidl::endpoints::ClientEnd,
fidl_fuchsia_sys2 as fsys,
fuchsia_uri::boot_uri::BootUri,
futures::future::FutureObj,
std::path::PathBuf,
};
pub static SCHEME: &str = "fuchsia-boot";
/// Resolves component URLs with the "fuchsia-boot" scheme.
///
/// URL syntax:
/// - fuchsia-boot:///directory#meta/component.cm
pub struct FuchsiaBootResolver {}
impl FuchsiaBootResolver {
pub fn new() -> FuchsiaBootResolver {
FuchsiaBootResolver {}
}
async fn resolve_async<'a>(
&'a self,
component_url: &'a str,
) -> Result<fsys::Component, ResolverError> {
// Parse URL.
let url = BootUri::parse(component_url)
.map_err(|e| ResolverError::component_not_available(component_url, e))?;
let res = url.resource().ok_or(ResolverError::url_missing_resource_error(component_url))?;
let res_path = PathBuf::from(url.path()).join(PathBuf::from(res));
let res_path_str =
res_path.to_str().ok_or(ResolverError::url_missing_resource_error(component_url))?;
// Read component manifest from resource into a component decl.
let cm_file = io_util::open_file_in_namespace(&res_path_str)
.map_err(|e| ResolverError::component_not_available(component_url, e))?;
let cm_str = await!(io_util::read_file(&cm_file))
.map_err(|e| ResolverError::component_not_available(component_url, e))?;
let component_decl = translate(&cm_str)
.map_err(|e| ResolverError::component_not_available(component_url, e))?;
// Set up the fuchsia-boot path as the component's "package" namespace.
let package_path = url.path();
let path_proxy = io_util::open_directory_in_namespace(&package_path)
.map_err(|e| ResolverError::component_not_available(component_url, e))?;
let package = fsys::Package {
package_url: Some(url.root_uri().to_string()),
package_dir: Some(ClientEnd::new(path_proxy.into_channel().unwrap().into_zx_channel())),
};
Ok(fsys::Component {
resolved_url: Some(component_url.to_string()),
decl: Some(component_decl),
package: Some(package),
})
}
}
impl Resolver for FuchsiaBootResolver {
fn resolve<'a>(
&'a self,
component_url: &'a str,
) -> FutureObj<'a, Result<fsys::Component, ResolverError>> {
FutureObj::new(Box::new(self.resolve_async(component_url)))
}
}
#[cfg(test)]
mod tests {
use {
super::*, fidl_fuchsia_data as fdata, fidl_fuchsia_sys2::ComponentDecl,
fuchsia_async as fasync,
};
#[test]
fn hello_world_test() {
let mut executor = fasync::Executor::new().unwrap();
executor.run_singlethreaded(async {
let resolver = FuchsiaBootResolver::new();
let component = await!(resolver
.resolve_async("fuchsia-boot:///pkg#meta/component_manager_tests_hello_world.cm"))
.unwrap();
assert_eq!(
"fuchsia-boot:///pkg#meta/component_manager_tests_hello_world.cm",
component.resolved_url.unwrap()
);
let program = fdata::Dictionary {
entries: vec![fdata::Entry {
key: "binary".to_string(),
value: Some(Box::new(fdata::Value::Str("bin/hello_world".to_string()))),
}],
};
let component_decl = ComponentDecl {
program: Some(program),
uses: None,
exposes: None,
offers: None,
facets: None,
children: None,
collections: None,
storage: None,
};
assert_eq!(component_decl, component.decl.unwrap());
assert_eq!("fuchsia-boot:///pkg", component.package.unwrap().package_url.unwrap());
});
}
}