blob: 4485ba27d2521dabfc9b4a9bb1ba9cbc86dc8e1f [file] [log] [blame]
// Copyright 2018 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.
#![feature(async_await, await_macro, futures_api)]
#![deny(warnings)]
use failure::{Error, ResultExt};
use fidl_fuchsia_io::{MAX_BUF, DirectoryProxy};
use fidl_fuchsia_pkg::{PackageResolverMarker, UpdatePolicy};
use fuchsia_app::client::Launcher;
use fuchsia_async as fasync;
use fuchsia_zircon as zx;
use std::mem;
use structopt::StructOpt;
#[derive(StructOpt)]
#[structopt(name = "pkgctl")]
struct Options {
#[structopt(
long = "pkg-resolver-uri",
help = "Package URI of the package resolver",
default_value = "fuchsia-pkg://fuchsia.com/pkg_resolver#meta/pkg_resolver.cmx"
)]
pkg_resolver_uri: String,
#[structopt(subcommand)]
cmd: Command,
}
#[derive(StructOpt)]
enum Command {
#[structopt(name = "resolve", about = "resolve a package")]
Resolve {
#[structopt(help = "URI of package to cache")]
pkg_uri: String,
#[structopt(help = "Package selectors")]
selectors: Vec<String>,
},
}
fn main() -> Result<(), Error> {
let mut executor = fasync::Executor::new().context("Error creating executor")?;
let Options {
pkg_resolver_uri,
cmd,
} = Options::from_args();
// Launch the server and connect to the resolver service.
let launcher = Launcher::new().context("Failed to open launcher service")?;
let app = launcher
.launch(pkg_resolver_uri, None)
.context("Failed to launch resolver service")?;
let resolver = app
.connect_to_service(PackageResolverMarker)
.context("Failed to connect to resolver service")?;
let fut = async {
match cmd {
Command::Resolve { pkg_uri, selectors } => {
println!("resolving {} with the selectors {:?}", pkg_uri, selectors);
let (dir, dir_server_end) = fidl::endpoints::create_proxy()?;
let res = await!(resolver.resolve(
&pkg_uri,
&mut selectors.iter().map(|s| s.as_str()),
&mut UpdatePolicy {
fetch_if_absent: true,
allow_old_versions: true,
},
dir_server_end,
))?;
zx::Status::ok(res)?;
let entries = await!(readdir(dir))?;
println!("package resolved");
for entry in entries {
println!("package directory: {:?}", entry);
}
Ok(())
}
}
};
executor.run_singlethreaded(fut)
}
async fn readdir(dir: DirectoryProxy) -> Result<Vec<String>, Error> {
#[repr(packed)]
struct Dirent {
_ino: u64,
size: u8,
_type: u8,
}
let mut entries = vec![];
loop {
let (status, buf) = await!(dir.read_dirents(MAX_BUF))?;
zx::Status::ok(status)?;
if buf.is_empty() {
break;
}
// The buffer contains an arbitrary number of dirents.
let mut slice = buf.as_slice();
while !slice.is_empty() {
// Read the dirent, and figure out how long the name is.
let (head, rest) = slice.split_at(mem::size_of::<Dirent>());
// Cast the dirent bytes into a `Dirent`, and extract out the size of the name.
let size = unsafe {
let dirent: *const Dirent = mem::transmute(head.as_ptr());
(*dirent).size as usize
};
// Package resolver paths are always utf8.
entries.push(String::from_utf8(rest[..size].to_vec())?);
// Finally, skip over the name.
slice = &rest[size..];
}
}
Ok(entries)
}