blob: b93978c223fb09ced424c0e1e7d6965f8e0f625c [file] [log] [blame]
// Copyright 2022 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.
//! A tool to:
//! - acquire and display product bundle information (metadata)
//! - acquire related data files, such as disk partition images (data)
use {
anyhow::{Context, Result},
ffx_core::ffx_plugin,
ffx_product_args::{CreateCommand, GetCommand, ListCommand, ProductCommand, SubCommand},
fidl_fuchsia_developer_ffx::RepositoryRegistryProxy,
fidl_fuchsia_developer_ffx_ext::{RepositoryError, RepositorySpec},
pbms::{get_product_data, is_pb_ready, product_bundle_urls, update_metadata},
std::{
convert::TryInto,
io::{stdout, Write},
},
};
mod create;
/// Provide functionality to show product-bundle metadata, fetch metadata, and
/// pull images and related data.
#[ffx_plugin("product.experimental", RepositoryRegistryProxy = "daemon::protocol")]
pub async fn product(cmd: ProductCommand, repos: RepositoryRegistryProxy) -> Result<()> {
product_plugin_impl(cmd, &mut stdout(), repos).await
}
/// Dispatch to a sub-command.
pub async fn product_plugin_impl<W>(
command: ProductCommand,
writer: &mut W,
repos: RepositoryRegistryProxy,
) -> Result<()>
where
W: Write + Sync,
{
match &command.sub {
SubCommand::List(cmd) => pb_list(writer, &cmd).await?,
SubCommand::Get(cmd) => pb_get(writer, &cmd, repos).await?,
SubCommand::Create(cmd) => pb_create(&cmd).await?,
}
Ok(())
}
/// `ffx product list` sub-command.
async fn pb_list<W: Write + Sync>(writer: &mut W, cmd: &ListCommand) -> Result<()> {
if !cmd.cached {
update_metadata(/*verbose=*/ false, writer).await?;
}
let mut entries = product_bundle_urls().await.context("list pbms")?;
entries.sort();
writeln!(writer, "")?;
for entry in entries {
let ready = if is_pb_ready(&entry).await? { "*" } else { "" };
writeln!(writer, "{}{}", entry, ready)?;
}
writeln!(
writer,
"\
\n*No need to fetch with `ffx product get ...`. \
The '*' is not part of the name.\
\n"
)?;
Ok(())
}
/// `ffx product get` sub-command.
async fn pb_get<W: Write + Sync>(
writer: &mut W,
cmd: &GetCommand,
repos: RepositoryRegistryProxy,
) -> Result<()> {
if !cmd.cached {
update_metadata(cmd.verbose, writer).await?;
}
let product_url = pbms::select_product_bundle(&cmd.product_bundle_name).await?;
get_product_data(&product_url, cmd.verbose, writer).await?;
// Register a repository with the daemon if we downloaded any packaging artifacts.
if let Some(product_name) = product_url.fragment() {
if let Ok(repo_path) = pbms::get_packages_dir(&product_url).await {
if repo_path.exists() {
let repo_path = repo_path
.canonicalize()
.with_context(|| format!("canonicalizing {:?}", repo_path))?;
let repo_spec = RepositorySpec::Pm { path: repo_path.try_into()? };
repos
.add_repository(&product_name, &mut repo_spec.into())
.await
.context("communicating with ffx daemon")?
.map_err(RepositoryError::from)
.with_context(|| format!("registering repository {}", product_name))?;
writeln!(writer, "Created repository named '{}'", product_name)?;
}
}
}
Ok(())
}
/// `ffx product create` sub-command.
async fn pb_create(cmd: &CreateCommand) -> Result<()> {
create::create_product_bundle(cmd).await
}
#[cfg(test)]
mod test {}