[ffx][component][list] Remove unused code.
`ffx component list` is now using cs's code since after the CL
fxr/479162. So the unused code can be removed.
Bug: 66157
Change-Id: I7b4d00f474b54ade36e4ee8f322eb3695cb90fbe
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/486640
Commit-Queue: Ingrid Feng <ingridlol@google.com>
Reviewed-by: Andrew Davies <awdavies@google.com>
diff --git a/src/developer/ffx/plugins/component/list/BUILD.gn b/src/developer/ffx/plugins/component/list/BUILD.gn
index 2f2e3ea..8d45451 100644
--- a/src/developer/ffx/plugins/component/list/BUILD.gn
+++ b/src/developer/ffx/plugins/component/list/BUILD.gn
@@ -10,22 +10,12 @@
with_unit_tests = true
deps = [
"//sdk/fidl/fuchsia.io:fuchsia.io-rustc",
- "//src/lib/fidl/rust/fidl",
- "//src/lib/fuchsia-async",
- "//src/lib/network/packet",
- "//src/lib/zerocopy",
"//src/lib/zircon/rust:fuchsia-zircon-status",
"//src/sys/tools/cs:lib",
- "//third_party/rust_crates:async-std",
- "//third_party/rust_crates:async-trait",
- "//third_party/rust_crates:byteorder",
- "//third_party/rust_crates:futures",
]
sources = [
"src/args.rs",
- "src/component.rs",
- "src/io.rs",
"src/lib.rs",
]
}
diff --git a/src/developer/ffx/plugins/component/list/src/component.rs b/src/developer/ffx/plugins/component/list/src/component.rs
deleted file mode 100644
index 587cfcf..0000000
--- a/src/developer/ffx/plugins/component/list/src/component.rs
+++ /dev/null
@@ -1,264 +0,0 @@
-// Copyright 2020 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 std::fmt::{Debug, Display};
-
-#[derive(Debug)]
-pub enum Component {
- V1(Realm), // In this topography the root will always be a realm.
- V2(ComponentVersion2),
-}
-
-#[derive(Debug)]
-pub struct Realm {
- pub id: u32,
- pub name: String,
- pub realms: Vec<Self>,
- pub components: Vec<ComponentVersion1>,
-}
-
-#[derive(Debug)]
-pub struct ComponentVersion1 {
- pub url: String,
- pub name: String,
- pub id: u32,
- pub merkleroot: Option<String>,
- pub children: Vec<Self>,
-}
-
-#[derive(Debug)]
-pub struct ComponentVersion2 {
- pub url: String,
- pub id: String,
- pub component_type: String,
- pub children: Vec<Component>,
-}
-
-const INDENT_INCREMENT: usize = 2;
-
-pub trait TreeFormatter {
- fn tree_formatter<'a>(&'a self, indent: usize) -> Box<dyn Display + 'a>;
-}
-
-struct ComponentTreeFormatterV2<'a> {
- inner: &'a ComponentVersion2,
- indent: usize,
-}
-
-struct ComponentTreeFormatterRealm<'a> {
- inner: &'a Realm,
- indent: usize,
-}
-
-struct ComponentTreeFormatterV1<'a> {
- inner: &'a ComponentVersion1,
- indent: usize,
-}
-
-impl TreeFormatter for Component {
- fn tree_formatter<'a>(&'a self, indent: usize) -> Box<dyn Display + 'a> {
- match self {
- Component::V2(c) => c.tree_formatter(indent),
- Component::V1(c) => c.tree_formatter(indent),
- }
- }
-}
-
-impl TreeFormatter for ComponentVersion1 {
- fn tree_formatter<'a>(&'a self, indent: usize) -> Box<dyn Display + 'a> {
- Box::new(ComponentTreeFormatterV1 { inner: self, indent })
- }
-}
-
-impl TreeFormatter for ComponentVersion2 {
- fn tree_formatter<'a>(&'a self, indent: usize) -> Box<dyn Display + 'a> {
- Box::new(ComponentTreeFormatterV2 { inner: self, indent })
- }
-}
-
-impl TreeFormatter for Realm {
- fn tree_formatter<'a>(&'a self, indent: usize) -> Box<dyn Display + 'a> {
- Box::new(ComponentTreeFormatterRealm { inner: self, indent })
- }
-}
-
-fn pad(amount: usize, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- // I tried several different formatting strings, and none appeared to
- // work, so here's the next best thing.
- (0..amount).try_for_each(|_| write!(f, " "))
-}
-
-impl Display for ComponentTreeFormatterV2<'_> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- pad(self.indent, f)?;
- write!(
- f,
- "{}\n",
- self.inner
- .url
- .split("/")
- .last()
- .ok_or(std::fmt::Error {})?
- .split(".")
- .next()
- .ok_or(std::fmt::Error {})?
- )?;
- self.inner
- .children
- .iter()
- .try_for_each(|c| write!(f, "{}", c.tree_formatter(self.indent + INDENT_INCREMENT)))
- }
-}
-
-impl Display for ComponentTreeFormatterRealm<'_> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- pad(self.indent, f)?;
- write!(f, "{} (realm)\n", self.inner.name)?;
- self.inner
- .components
- .iter()
- .try_for_each(|c| write!(f, "{}", c.tree_formatter(self.indent + INDENT_INCREMENT)))?;
- self.inner
- .realms
- .iter()
- .try_for_each(|r| write!(f, "{}", r.tree_formatter(self.indent + INDENT_INCREMENT)))
- }
-}
-
-impl Display for ComponentTreeFormatterV1<'_> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- pad(self.indent, f)?;
- write!(f, "{}\n", self.inner.url.split("/").last().ok_or(std::fmt::Error {})?)?;
- self.inner
- .children
- .iter()
- .try_for_each(|c| write!(f, "{}", c.tree_formatter(self.indent + INDENT_INCREMENT)))
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
-
- fn test_tree() -> ComponentVersion2 {
- ComponentVersion2 {
- url: "/root.cm".to_owned(),
- id: "0".to_owned(),
- component_type: "static".to_owned(),
- children: vec![
- Component::V2(ComponentVersion2 {
- url: "/bootstrap.cm".to_owned(),
- id: "0".to_owned(),
- component_type: "static".to_owned(),
- children: vec![
- Component::V2(ComponentVersion2 {
- url: "/console.cm".to_owned(),
- id: "0".to_owned(),
- component_type: "static".to_owned(),
- children: vec![],
- }),
- Component::V2(ComponentVersion2 {
- url: "/driver_manager.cm".to_owned(),
- id: "0".to_owned(),
- component_type: "static".to_owned(),
- children: vec![],
- }),
- Component::V2(ComponentVersion2 {
- url: "/fshost.cm".to_owned(),
- id: "0".to_owned(),
- component_type: "static".to_owned(),
- children: vec![],
- }),
- ],
- }),
- Component::V2(ComponentVersion2 {
- url: "/core.cm".to_owned(),
- id: "0".to_owned(),
- component_type: "static".to_owned(),
- children: vec![
- Component::V2(ComponentVersion2 {
- url: "/appmgr.cm".to_owned(),
- id: "0".to_owned(),
- component_type: "static".to_owned(),
- children: vec![Component::V1(Realm {
- id: 16606,
- name: "app".to_owned(),
- realms: vec![Realm {
- id: 16607,
- name: "sys".to_owned(),
- realms: vec![],
- components: vec![
- ComponentVersion1 {
- url: "/pkg-resolver.cmx".to_owned(),
- name: "pkg-resolver.cmx".to_owned(),
- id: 17339,
- merkleroot: Some("foobar".to_owned()),
- children: vec![],
- },
- ComponentVersion1 {
- url: "/something.cmx".to_owned(),
- name: "something.cmx".to_owned(),
- id: 12345,
- merkleroot: Some("bazmumble".to_owned()),
- children: vec![ComponentVersion1 {
- url: "/somechild.cmx".to_owned(),
- name: "somechild.cmx".to_owned(),
- id: 12346,
- merkleroot: None,
- children: vec![],
- }],
- },
- ],
- }],
- components: vec![ComponentVersion1 {
- url: "/sysmgr.cmx".to_owned(),
- name: "sysmgr.cmx".to_owned(),
- id: 9999,
- merkleroot: Some("florp".to_owned()),
- children: vec![],
- }],
- })],
- }),
- Component::V2(ComponentVersion2 {
- url: "/archivist.cm".to_owned(),
- id: "0".to_owned(),
- component_type: "static".to_owned(),
- children: vec![],
- }),
- Component::V2(ComponentVersion2 {
- url: "/fonts.cm".to_owned(),
- id: "0".to_owned(),
- component_type: "static".to_owned(),
- children: vec![],
- }),
- ],
- }),
- ],
- }
- }
-
- #[test]
- fn test_tree_formatter_mixed_components() {
- let tree = test_tree();
- let tree_str = format!("{}", tree.tree_formatter(0));
- #[rustfmt::skip]
- assert_eq!(tree_str,
-r"root
- bootstrap
- console
- driver_manager
- fshost
- core
- appmgr
- app (realm)
- sysmgr.cmx
- sys (realm)
- pkg-resolver.cmx
- something.cmx
- somechild.cmx
- archivist
- fonts
-");
- }
-}
diff --git a/src/developer/ffx/plugins/component/list/src/io.rs b/src/developer/ffx/plugins/component/list/src/io.rs
deleted file mode 100644
index 70ebffa..0000000
--- a/src/developer/ffx/plugins/component/list/src/io.rs
+++ /dev/null
@@ -1,707 +0,0 @@
-// Copyright 2020 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.
-
-//! Simple Rust utilities for file I/O that are usable on the host (via overnet
-//! FIDL usage) as well as on a Fuchsia target.
-//!
-//! For now all utilities in here are implemented as read-only.
-
-use {
- anyhow::{anyhow, Context, Result},
- async_trait::async_trait,
- byteorder::NetworkEndian,
- fidl_fuchsia_io as fio,
- fuchsia_zircon_status::Status,
- futures::Future,
- packet::BufferView,
- std::convert::{TryFrom, TryInto},
- std::fmt::Debug,
- zerocopy::ByteSlice,
-};
-
-/// Applies a predicate to all children. If all children are known to be of
-/// a certain type in advance, this function can be run much simpler. For
-/// example, this trait is implemented for `MapChildren<DirectoryProxy, _, _>`,
-/// which will automatically open each child in the directory as a directory.
-#[async_trait]
-pub trait MapChildren<T, E, F>
-where
- F: Future<Output = Result<E>>,
-{
- /// Attempts to apply the predicate to all children, using the flags for
- /// opening each child.
- async fn map_children(self, flags: u32, f: fn(T) -> F) -> Result<Vec<E>>;
-}
-
-#[async_trait]
-impl<E, F> MapChildren<fio::DirectoryProxy, E, F> for fio::DirectoryProxy
-where
- F: Future<Output = Result<E>> + 'static + Send,
- E: 'static + Send,
-{
- async fn map_children(self, flags: u32, func: fn(fio::DirectoryProxy) -> F) -> Result<Vec<E>> {
- // TODO(awdavies): Run this in parallel with some kind of barrier to
- // prevent overspawning channels.
- let mut res = Vec::new();
- for child in self.dirents().await? {
- let child_root = child.to_dir_proxy(&self, flags)?;
- res.push(func(child_root).await?);
- }
- Ok(res)
- }
-}
-
-#[async_trait]
-trait DirectoryProxyExtPrivate {
- async fn dirent_bytes(&self) -> Result<Vec<u8>>;
-}
-
-#[async_trait]
-impl DirectoryProxyExtPrivate for fio::DirectoryProxy {
- async fn dirent_bytes(&self) -> Result<Vec<u8>> {
- let (status, buf) = self.read_dirents(fio::MAX_BUF).await.context("read_dirents")?;
- Status::ok(status).context("dirents result")?;
- Ok(buf)
- }
-}
-
-#[async_trait]
-pub trait DirectoryProxyExt {
- /// Reads all raw dirents, returning a vector of dirents.
- /// Each dirent can be potentially converted into either a file or
- /// directory proxy.
- async fn dirents(&self) -> Result<Vec<Dirent>>;
-
- /// Attempts to find a dirent in this directory, returning `None` if it
- /// cannot be found.
- async fn dirent(&self, name: &str) -> Result<Option<Dirent>>;
-
- /// Attempts to open a directory at the given path.
- fn open_dir(&self, path: &str, flags: u32) -> Result<fio::DirectoryProxy>;
-
- /// Attempts to open a file at the given path.
- fn open_file(&self, path: &str, flags: u32) -> Result<fio::FileProxy>;
-
- /// Similar to `open_dir` but returns `None` if the file doesn't exist inside
- /// this directory (so avoid using names referring to files under one or more
- /// directories).
- async fn open_dir_checked(&self, name: &str, flags: u32)
- -> Result<Option<fio::DirectoryProxy>>;
-
- /// Attempts to read the max buffer size of a file for a given path.
- async fn read_file(&self, path: &str) -> Result<String>;
-}
-
-#[async_trait]
-impl DirectoryProxyExt for fio::DirectoryProxy {
- fn open_dir(&self, path: &str, flags: u32) -> Result<fio::DirectoryProxy> {
- let (dir_client, dir_server) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>()
- .context("creating fidl proxy")?;
- self.open(
- fio::OPEN_FLAG_DIRECTORY | flags,
- fio::MODE_TYPE_DIRECTORY,
- path,
- fidl::endpoints::ServerEnd::new(dir_server.into_channel()),
- )?;
- Ok(dir_client)
- }
-
- fn open_file(&self, path: &str, flags: u32) -> Result<fio::FileProxy> {
- let (file_client, file_server) =
- fidl::endpoints::create_proxy::<fio::FileMarker>().context("creating fidl proxy")?;
- self.open(
- fio::OPEN_FLAG_NOT_DIRECTORY | flags,
- fio::MODE_TYPE_FILE,
- path,
- fidl::endpoints::ServerEnd::new(file_server.into_channel()),
- )?;
- Ok(file_client)
- }
-
- async fn open_dir_checked(
- &self,
- path: &str,
- flags: u32,
- ) -> Result<Option<fio::DirectoryProxy>> {
- if let Some(_) = self.dirent(path).await? {
- Ok(Some(self.open_dir(path, flags)?))
- } else {
- Ok(None)
- }
- }
-
- async fn read_file(&self, path: &str) -> Result<String> {
- Ok(std::str::from_utf8(
- self.open_file(path, fio::OPEN_RIGHT_READABLE)
- .context(format!("reading file from path: {}", path))?
- .read_max_bytes()
- .await
- .context(format!("reading max buf from file: {}", path))?
- .as_ref(),
- )?
- .to_owned())
- }
-
- async fn dirents(&self) -> Result<Vec<Dirent>> {
- let mut res = Vec::new();
- loop {
- let buf = self.dirent_bytes().await?;
- if buf.is_empty() {
- break;
- }
- let mut bref: &[u8] = buf.as_ref();
- let mut bref_ref = &mut bref;
- loop {
- let dirent_raw = Dirent::parse::<&[u8], &mut &[u8]>(&mut bref_ref)?;
- if dirent_raw.name != "." {
- res.push(dirent_raw);
- }
- if is_empty::<&[u8], &mut &[u8]>(&mut bref_ref) {
- break;
- }
- }
- }
- Ok(res)
- }
-
- async fn dirent(&self, name: &str) -> Result<Option<Dirent>> {
- Ok(self.dirents().await?.iter().find(|d| d.name == name).map(|d| d.clone()))
- }
-}
-
-#[async_trait]
-pub trait FileProxyExt {
- /// Attempts to read the max bytes for a given file, returning a u8 buffer.
- async fn read_max_bytes(&self) -> Result<Vec<u8>>;
-}
-
-#[async_trait]
-impl FileProxyExt for fio::FileProxy {
- async fn read_max_bytes(&self) -> Result<Vec<u8>> {
- let (status, buf) = self.read(fio::MAX_BUF).await?;
- Status::ok(status).context("read file")?;
- Ok(buf)
- }
-}
-
-type U64 = zerocopy::U64<NetworkEndian>;
-
-#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Clone, Copy)]
-pub enum DirentType {
- Unknown(u8),
- Directory,
- BlockDevice,
- File,
- Socket,
- Service,
-}
-
-impl TryFrom<DirentType> for u32 {
- type Error = anyhow::Error;
-
- fn try_from(d: DirentType) -> Result<u32> {
- Ok(match d {
- DirentType::Unknown(t) => return Err(anyhow!("unknown type: {}", t)),
- DirentType::Directory => fio::MODE_TYPE_DIRECTORY,
- DirentType::BlockDevice => fio::MODE_TYPE_BLOCK_DEVICE,
- DirentType::File => fio::MODE_TYPE_FILE,
- DirentType::Socket => fio::MODE_TYPE_SOCKET,
- DirentType::Service => fio::MODE_TYPE_SERVICE,
- })
- }
-}
-
-impl From<u8> for DirentType {
- fn from(dirent_type: u8) -> Self {
- match dirent_type {
- fio::DIRENT_TYPE_DIRECTORY => DirentType::Directory,
- fio::DIRENT_TYPE_BLOCK_DEVICE => DirentType::BlockDevice,
- fio::DIRENT_TYPE_FILE => DirentType::File,
- fio::DIRENT_TYPE_SOCKET => DirentType::Socket,
- fio::DIRENT_TYPE_SERVICE => DirentType::Service,
- _ => DirentType::Unknown(dirent_type),
- }
- }
-}
-
-trait ToDirProxy {
- /// Attempts to use the root `DirectoryProxy`'s `open` command to open a `DirectoryProxy`.
- ///
- /// Passes `OPEN_FLAG_DIRECTORY` bitwise or'd with `flags` to the `open` command.
- fn to_dir_proxy(&self, root: &fio::DirectoryProxy, flags: u32) -> Result<fio::DirectoryProxy>;
-}
-
-trait ToFileProxy {
- /// Attempts to use the root `DirectoryProxy`'s `open` command to open a `FileProxy`.
- ///
- /// Passes `OPEN_FLAG_NOT_DIRECTORY` bitwise or'd with `flags` to the `open` command.
- fn to_file_proxy(&self, root: &fio::DirectoryProxy, flags: u32) -> Result<fio::FileProxy>;
-}
-
-#[derive(Debug, Eq, PartialEq, Clone)]
-pub struct Dirent {
- pub ino: u64,
- pub size: u8,
- pub dirent_type: DirentType,
- pub name: String,
-}
-
-impl ToDirProxy for Dirent {
- fn to_dir_proxy(&self, root: &fio::DirectoryProxy, flags: u32) -> Result<fio::DirectoryProxy> {
- match self.dirent_type {
- DirentType::Directory => {
- let (dir_client, dir_server) =
- fidl::endpoints::create_proxy::<fio::DirectoryMarker>()
- .context("creating fidl proxy")?;
- root.open(
- fio::OPEN_FLAG_DIRECTORY | flags,
- self.dirent_type.try_into()?,
- &self.name,
- fidl::endpoints::ServerEnd::new(dir_server.into_channel()),
- )?;
-
- Ok(dir_client)
- }
- _ => Err(anyhow!("wrong type for dir proxy: {:?}", self.dirent_type)),
- }
- }
-}
-
-impl ToFileProxy for Dirent {
- fn to_file_proxy(&self, root: &fio::DirectoryProxy, flags: u32) -> Result<fio::FileProxy> {
- match self.dirent_type {
- DirentType::Directory | DirentType::Unknown(_) => {
- Err(anyhow!("wrong type for file proxy: {:?}", self.dirent_type))
- }
- _ => {
- let (file_client, file_server) = fidl::endpoints::create_proxy::<fio::FileMarker>()
- .context("creating fidl proxy")?;
- root.open(
- fio::OPEN_FLAG_NOT_DIRECTORY | flags,
- self.dirent_type.try_into()?,
- &self.name,
- fidl::endpoints::ServerEnd::new(file_server.into_channel()),
- )?;
- Ok(file_client)
- }
- }
- }
-}
-
-impl Dirent {
- fn parse<B: ByteSlice, BV: BufferView<B>>(buffer: &mut BV) -> Result<Self> {
- let ino = buffer.take_obj_front::<U64>().context("reading ino")?;
- let size = buffer.take_byte_front().context("reading size")?;
- let dirent_type: DirentType = buffer.take_byte_front().context("reading type")?.into();
- let name = std::str::from_utf8(&buffer.take_front(size.into()).context("reading name")?)
- .context("dirent utf8 parsing")?
- .to_owned();
- Ok(Self { ino: ino.get(), size, dirent_type, name })
- }
-}
-
-// This is just here to satisfy the trait constraints, otherwise the compiler
-// will complain that it doesn't know <B> (if done outside of this function).
-// This is sort of the limitation of type inference where it's a pointer to
-// a pointer to a pointer.
-#[inline]
-pub fn is_empty<B: ByteSlice, BV: BufferView<B>>(buffer: &mut BV) -> bool {
- buffer.len() == 0
-}
-
-/// Contains some fake directories and test harness utilities for constructing
-/// unit tests on a fake read-only file system.
-#[cfg(test)]
-pub mod testing {
- use {
- fidl_fuchsia_io as fio, fuchsia_zircon_status::Status, futures::TryStreamExt,
- std::collections::HashMap,
- };
-
- const DIRENT_HEADER_SIZE: usize = 10;
-
- /// The type of a fake dirent.
- #[derive(Clone, PartialEq, Debug, Eq)]
- pub enum TestDirentTreeType {
- /// The file variation of a dirent.
- File,
- /// The directory variation of a dirent.
- Dir,
- }
-
- impl From<&TestDirentTreeType> for u8 {
- fn from(t: &TestDirentTreeType) -> Self {
- match t {
- TestDirentTreeType::Dir => fio::DIRENT_TYPE_DIRECTORY,
- TestDirentTreeType::File => fio::DIRENT_TYPE_FILE,
- }
- }
- }
-
- /// Represents a whole faked file system.
- #[derive(Clone, Debug)]
- pub struct TestDirentTree {
- /// The name fo the entity.
- pub name: String,
- /// The dirent type of this entity.
- pub ttype: TestDirentTreeType,
- /// If this is a file, the contents of the file.
- pub contents: String,
- /// If this is a directory, the children of this directory.
- pub children: Option<HashMap<String, Self>>,
- }
-
- /// A builder trait for adding files to a faked file tree.
- pub trait TreeBuilder {
- /// Adds a file while returning an instance of the builder, allowing
- /// for this function to be chained.
- fn add_file(self, name: &str, contents: &str) -> Self;
- }
-
- impl TreeBuilder for TestDirentTree {
- fn add_file(mut self, name: &str, contents: &str) -> Self {
- (&mut self).add_file(name, contents);
- self
- }
- }
-
- impl TreeBuilder for &mut TestDirentTree {
- fn add_file(self, name: &str, contents: &str) -> Self {
- let name = name.to_owned();
- let contents = contents.to_owned();
- self.children.as_mut().unwrap().insert(
- name.clone(),
- TestDirentTree { name, ttype: TestDirentTreeType::File, contents, children: None },
- );
- self
- }
- }
-
- impl TestDirentTree {
- /// Creates a root directory with no name and no children.
- pub fn root() -> Self {
- Self {
- name: "".to_string(),
- ttype: TestDirentTreeType::Dir,
- contents: "".to_string(),
- children: Some(HashMap::new()),
- }
- }
-
- /// Adds a directory to the tree, and then returns an instance of `Self`
- /// so that subsequent commands can be chained to this tree.
- pub fn add_dir<'a>(&'a mut self, name: &str) -> &'a mut Self {
- let name = name.to_owned();
- self.children.as_mut().unwrap().insert(
- name.clone(),
- TestDirentTree {
- name: name.clone(),
- ttype: TestDirentTreeType::Dir,
- contents: "".to_owned(),
- children: Some(HashMap::new()),
- },
- );
-
- self.children.as_mut().unwrap().get_mut(&name).unwrap()
- }
- }
-
- fn launch_fake_file(
- entity: TestDirentTree,
- server: fidl::endpoints::ServerEnd<fio::FileMarker>,
- ) {
- fuchsia_async::Task::local(async move {
- let mut stream =
- server.into_stream().expect("converting fake file server proxy to stream");
- while let Ok(Some(req)) = stream.try_next().await {
- match req {
- fio::FileRequest::Read { count: _, responder } => {
- responder
- .send(Status::OK.into_raw(), entity.contents.clone().as_ref())
- .expect("writing file test response");
- }
- _ => panic!("not supported"),
- }
- }
- })
- .detach();
- }
-
- fn launch_fake_directory(
- root: TestDirentTree,
- server: fidl::endpoints::ServerEnd<fio::DirectoryMarker>,
- ) {
- fuchsia_async::Task::local(async move {
- let mut finished_reading_dirents = false;
- let mut stream =
- server.into_stream().expect("converting fake dir server proxy to stream");
- 'stream_loop: while let Ok(Some(req)) = stream.try_next().await {
- match req {
- fio::DirectoryRequest::Open {
- flags: _,
- mode,
- path,
- object,
- control_handle: _,
- } => {
- let mut iter = path.split("/");
- let mut child =
- match root.children.as_ref().unwrap().get(iter.next().unwrap()) {
- Some(child) => child.clone(),
- None => {
- object.close_with_epitaph(Status::NOT_FOUND).unwrap();
- continue;
- }
- };
- for entry in iter {
- child = match child.children.as_ref().unwrap().get(entry) {
- Some(child) => child.clone(),
- None => {
- object.close_with_epitaph(Status::NOT_FOUND).unwrap();
- continue 'stream_loop;
- }
- }
- }
- match child.ttype {
- TestDirentTreeType::Dir => {
- assert_eq!(mode, fio::MODE_TYPE_DIRECTORY);
- launch_fake_directory(
- child,
- fidl::endpoints::ServerEnd::new(object.into_channel()),
- );
- }
- TestDirentTreeType::File => {
- assert_eq!(mode, fio::MODE_TYPE_FILE);
- launch_fake_file(
- child,
- fidl::endpoints::ServerEnd::new(object.into_channel()),
- );
- }
- }
- }
- fio::DirectoryRequest::ReadDirents { max_bytes: _, responder } => {
- let res = if !finished_reading_dirents {
- let children = root.children.as_ref().unwrap();
- children.values().fold(Vec::with_capacity(256), |mut acc, child| {
- let mut buf =
- Vec::with_capacity(DIRENT_HEADER_SIZE + child.name.len() + 100);
- buf.append(&mut vec![0, 0, 0, 0, 0, 0, 0, 0]);
- buf.push(child.name.len() as u8);
- buf.push(u8::from(&child.ttype));
- // unsafe: this is a test, plus the UTF-8 value is checked later.
- buf.append(unsafe { child.name.clone().as_mut_vec() });
- acc.append(&mut buf);
- acc
- })
- } else {
- vec![]
- };
- finished_reading_dirents = !finished_reading_dirents;
- responder
- .send(Status::OK.into_raw(), res.as_ref())
- .expect("dirents read test response");
- }
- _ => panic!("unsupported"),
- }
- }
- })
- .detach();
- }
-
- /// Launches a fake file system based off of the passed tree.
- ///
- /// Currently the file system is intended to be read-only.
- pub fn setup_fake_directory(root: TestDirentTree) -> fio::DirectoryProxy {
- let (proxy, server) =
- fidl::endpoints::create_proxy::<fio::DirectoryMarker>().expect("making fake dir proxy");
- launch_fake_directory(root, server);
- proxy
- }
-}
-
-#[cfg(test)]
-pub mod test {
- use super::testing::*;
- use super::*;
-
- impl Dirent {
- /// Creates a default (everything zeroed out) file with the given name.
- fn anonymous_file(name: &str) -> Self {
- Self { ino: 0, size: 0, dirent_type: DirentType::File, name: name.to_owned() }
- }
-
- /// Creates a default (everything zeroed out) directory with the given name.
- fn anonymous_dir(name: &str) -> Self {
- Self { ino: 0, size: 0, dirent_type: DirentType::Directory, name: name.to_owned() }
- }
- }
-
- fn take_byte<B: ByteSlice, BV: BufferView<B>>(buffer: &mut BV) {
- let _ = buffer.take_byte_front().unwrap();
- }
-
- #[test]
- fn test_buffer_is_empty() {
- let buf: [u8; 1] = [2];
- let mut bref = &buf[..];
- let mut bref_ref = &mut bref;
- assert!(!is_empty::<&[u8], &mut &[u8]>(&mut bref_ref));
- take_byte::<&[u8], &mut &[u8]>(&mut bref_ref);
- assert!(is_empty::<&[u8], &mut &[u8]>(&mut bref_ref));
- }
-
- #[test]
- fn test_dirent_to_mode_type() {
- let dtype = DirentType::Unknown(252u8);
- assert!(u32::try_from(dtype).is_err());
-
- struct Test {
- dtype: DirentType,
- expected: u32,
- }
- for test in vec![
- Test { dtype: DirentType::Directory, expected: fio::MODE_TYPE_DIRECTORY },
- Test { dtype: DirentType::BlockDevice, expected: fio::MODE_TYPE_BLOCK_DEVICE },
- Test { dtype: DirentType::File, expected: fio::MODE_TYPE_FILE },
- Test { dtype: DirentType::Socket, expected: fio::MODE_TYPE_SOCKET },
- Test { dtype: DirentType::Service, expected: fio::MODE_TYPE_SERVICE },
- ]
- .iter()
- {
- assert_eq!(u32::try_from(test.dtype).unwrap(), test.expected);
- }
- }
-
- #[test]
- fn test_dirent_u8_to_dirent_type() {
- struct Test {
- u8type: u8,
- expected: DirentType,
- }
- for test in vec![
- Test { u8type: fio::DIRENT_TYPE_DIRECTORY, expected: DirentType::Directory },
- Test { u8type: fio::DIRENT_TYPE_BLOCK_DEVICE, expected: DirentType::BlockDevice },
- Test { u8type: fio::DIRENT_TYPE_FILE, expected: DirentType::File },
- Test { u8type: fio::DIRENT_TYPE_SOCKET, expected: DirentType::Socket },
- Test { u8type: fio::DIRENT_TYPE_SERVICE, expected: DirentType::Service },
- Test { u8type: 253u8, expected: DirentType::Unknown(253u8) },
- ]
- .iter()
- {
- assert_eq!(DirentType::from(test.u8type), test.expected);
- }
- }
-
- #[test]
- fn test_parse_dirent_raw() -> Result<()> {
- #[rustfmt::skip]
- let buf = [
- // ino
- 42, 0, 0, 0, 0, 0, 0, 0,
- // name length
- 4,
- // type
- fio::DIRENT_TYPE_FILE,
- // name
- 't' as u8, 'e' as u8, 's' as u8, 't' as u8,
- // ino
- 41, 0, 0, 0, 0, 0, 0, 1,
- // name length
- 5,
- // type
- fio::DIRENT_TYPE_SERVICE,
- // name
- 'f' as u8, 'o' as u8, 'o' as u8, 'o' as u8, 'o' as u8,
- ];
-
- let mut bref = &buf[..];
- let mut bref_ref = &mut bref;
- let dirent_raw = Dirent::parse::<&[u8], &mut &[u8]>(&mut bref_ref)?;
- assert_eq!(dirent_raw.size, 4);
- assert_eq!(dirent_raw.ino, 0x2a00000000000000);
- assert_eq!(dirent_raw.dirent_type, DirentType::File);
- assert_eq!(dirent_raw.name, "test".to_owned());
- let dirent_raw = Dirent::parse::<&[u8], &mut &[u8]>(&mut bref_ref)?;
- assert_eq!(dirent_raw.size, 5);
- assert_eq!(dirent_raw.ino, 0x2900000000000001);
- assert_eq!(dirent_raw.dirent_type, DirentType::Service);
- assert_eq!(dirent_raw.name, "foooo".to_owned());
- Ok(())
- }
-
- #[test]
- fn test_parse_dirent_raw_malformed() {
- #[rustfmt::skip]
- let buf = [
- // ino
- 1, 0, 0, 0, 0, 0, 0, 0,
- // name length
- 12,
- // type
- fio::DIRENT_TYPE_FILE,
- // name
- 'w' as u8, 'o' as u8, 'o' as u8, 'p' as u8, 's' as u8,
- ];
-
- let mut bref = &buf[..];
- let mut bref_ref = &mut bref;
- assert!(Dirent::parse::<&[u8], &mut &[u8]>(&mut bref_ref).is_err());
-
- let buf = [1, 2, 3, 4];
- let mut bref = &buf[..];
- let mut bref_ref = &mut bref;
- assert!(Dirent::parse::<&[u8], &mut &[u8]>(&mut bref_ref).is_err());
- }
-
- #[test]
- fn test_to_proxy_fails() {
- let (root, _dir_server) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>()
- .expect("creating fake root proxy");
- let dirent = Dirent::anonymous_dir("foo");
- assert!(dirent.to_file_proxy(&root, fio::OPEN_RIGHT_READABLE).is_err());
- let dirent = Dirent::anonymous_file("foo");
- assert!(dirent.to_dir_proxy(&root, fio::OPEN_RIGHT_READABLE).is_err());
- }
-
- #[fuchsia_async::run_singlethreaded(test)]
- async fn test_read_file_from_str() {
- let mut root = TestDirentTree::root().add_file("foo", "test").add_file("bar", "other_test");
- root.add_dir("baz").add_file("mumble", "testarossa");
- let root = setup_fake_directory(root);
-
- let buf = root
- .open_file("foo", fio::OPEN_RIGHT_READABLE)
- .unwrap()
- .read_max_bytes()
- .await
- .unwrap();
- assert_eq!("test", std::str::from_utf8(&buf[..]).unwrap());
- let buf = root
- .open_file("bar", fio::OPEN_RIGHT_READABLE)
- .unwrap()
- .read_max_bytes()
- .await
- .unwrap();
- assert_eq!("other_test", std::str::from_utf8(&buf[..]).unwrap());
- let buf = root
- .open_file("baz/mumble", fio::OPEN_RIGHT_READABLE)
- .unwrap()
- .read_max_bytes()
- .await
- .unwrap();
- assert_eq!("testarossa", std::str::from_utf8(&buf[..]).unwrap());
- assert!(root
- .open_file("blorp", fio::OPEN_RIGHT_READABLE)
- .unwrap()
- .read_max_bytes()
- .await
- .is_err());
- assert!(root
- .open_file("blorp/blip/bloop", fio::OPEN_RIGHT_READABLE)
- .unwrap()
- .read_max_bytes()
- .await
- .is_err());
- }
-}
diff --git a/src/developer/ffx/plugins/component/list/src/lib.rs b/src/developer/ffx/plugins/component/list/src/lib.rs
index ff8c125..9a1ebc7 100644
--- a/src/developer/ffx/plugins/component/list/src/lib.rs
+++ b/src/developer/ffx/plugins/component/list/src/lib.rs
@@ -3,21 +3,14 @@
// found in the LICENSE file.
use {
- crate::component::*,
- crate::io::{DirectoryProxyExt, MapChildren},
anyhow::{Context, Result},
- async_trait::async_trait,
cs::{io::Directory, v2::V2Component},
ffx_component_list_args::ComponentListCommand,
ffx_core::ffx_plugin,
fidl_fuchsia_developer_remotecontrol as rc, fidl_fuchsia_io as fio,
fuchsia_zircon_status::Status,
- futures::future::ready,
};
-mod component;
-mod io;
-
#[ffx_plugin()]
pub async fn list(rcs_proxy: rc::RemoteControlProxy, cmd: ComponentListCommand) -> Result<()> {
list_impl(rcs_proxy, cmd).await
@@ -36,291 +29,3 @@
component.print_tree();
Ok(())
}
-
-pub const V1_ROOT_COMPONENT: &'static str = "fuchsia-pkg://fuchsia.com/appmgr#meta/appmgr.cm";
-
-pub const V1_HUB_PATH: &'static str = "exec/out/hub";
-
-#[async_trait]
-pub trait DirectoryProxyComponentExt {
- async fn to_component_v2(self) -> Result<ComponentVersion2>;
-
- async fn to_component_v1(self) -> Result<ComponentVersion1>;
-
- async fn component_v1_children(&self) -> Result<Vec<ComponentVersion1>>;
-
- async fn to_realm(self) -> Result<Realm>;
-}
-
-#[async_trait]
-impl DirectoryProxyComponentExt for fio::DirectoryProxy {
- async fn to_component_v2(self) -> Result<ComponentVersion2> {
- let (url, id, component_type) = futures::try_join!(
- self.read_file("url"),
- self.read_file("id"),
- self.read_file("component_type")
- )?;
-
- let children = match url.as_ref() {
- V1_ROOT_COMPONENT => vec![Component::V1(
- self.open_dir(V1_HUB_PATH, fio::OPEN_RIGHT_READABLE)?.to_realm().await?,
- )],
- _ => self
- .open_dir("children", fio::OPEN_RIGHT_READABLE)?
- .map_children(fio::OPEN_RIGHT_READABLE, |c| c.to_component_v2())
- .await?
- .drain(..)
- .map(|c| Component::V2(c))
- .collect(),
- };
- Ok(ComponentVersion2 { url, id, component_type, children })
- }
-
- async fn to_component_v1(self) -> Result<ComponentVersion1> {
- let (id, name, url, merkleroot, children) = futures::join!(
- self.read_file("job-id"),
- self.read_file("name"),
- self.read_file("url"),
- self.read_file("in/pkg/meta"),
- self.component_v1_children(),
- );
- let (id, name, url, merkleroot, children) =
- (id?.parse::<u32>()?, name?, url?, merkleroot.ok(), children?);
- Ok(ComponentVersion1 { id, url, name, merkleroot, children })
- }
-
- async fn to_realm(self) -> Result<Realm> {
- let (id, name, mut realms_stacked, components) = futures::try_join!(
- self.read_file("job-id"),
- self.read_file("name"),
- self.open_dir("r", fio::OPEN_RIGHT_READABLE)?.map_children(
- fio::OPEN_RIGHT_READABLE,
- |realm_name| {
- realm_name.map_children(fio::OPEN_RIGHT_READABLE, |realm_instance| {
- realm_instance.to_realm()
- })
- }
- ),
- self.component_v1_children(),
- )?;
- let id = id.parse::<u32>()?;
- let realms = realms_stacked.drain(..).flatten().collect();
- Ok(Realm { id, name, realms, components })
- }
-
- async fn component_v1_children(&self) -> Result<Vec<ComponentVersion1>> {
- Ok(self
- .open_dir_checked("c", fio::OPEN_RIGHT_READABLE)
- .await?
- .map(|c| {
- c.map_children(fio::OPEN_RIGHT_READABLE, |child_name| {
- child_name.map_children(fio::OPEN_RIGHT_READABLE, |child_instance| {
- child_instance.to_component_v1()
- })
- })
- })
- .unwrap_or(Box::pin(ready(Ok(vec![]))))
- .await?
- .drain(..)
- .flatten()
- .collect())
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
- use crate::io::testing::{self as io_test, TreeBuilder};
-
- trait ComponentExt {
- fn as_v2<'a>(&'a self) -> Option<&'a ComponentVersion2>;
-
- fn as_v1<'a>(&'a self) -> Option<&'a Realm>;
- }
-
- impl ComponentExt for Component {
- fn as_v2<'a>(&'a self) -> Option<&'a ComponentVersion2> {
- match self {
- Component::V2(c) => Some(c),
- _ => None,
- }
- }
-
- fn as_v1<'a>(&'a self) -> Option<&'a Realm> {
- match self {
- Component::V1(c) => Some(c),
- _ => None,
- }
- }
- }
-
- #[fuchsia_async::run_singlethreaded(test)]
- async fn test_flat_hub() {
- let mut root = io_test::TestDirentTree::root()
- .add_file("url", "fuchsia-boot:///#meta/root.cm")
- .add_file("id", "1")
- .add_file("component_type", "excellent");
- root.add_dir("children");
- let root = io_test::setup_fake_directory(root);
- let component = root.to_component_v2().await.unwrap();
- assert_eq!(component.url, "fuchsia-boot:///#meta/root.cm");
- assert_eq!(component.id, "1");
- assert_eq!(component.component_type, "excellent");
- assert_eq!(component.children.len(), 0);
- }
-
- trait ComponentBuilder {
- /// Add's a "leaf" component, meaning subsequent builder chains will append to whatever
- /// directory this component is in.
- fn add_v1_component_leaf(self, name: &str, job_id: &str, merkleroot: Option<&str>) -> Self;
-
- /// Add's a "leaf" component, meaning subsequent builder chains will append to whatever
- /// directory this component is in.
- fn add_v2_component_leaf(self, name: &str, id: &str, component_type: &str) -> Self;
-
- fn add_v2_component_chain(self, name: &str, id: &str, component_type: &str) -> Self;
- }
-
- impl ComponentBuilder for &mut io_test::TestDirentTree {
- fn add_v1_component_leaf(self, name: &str, job_id: &str, merkleroot: Option<&str>) -> Self {
- let base_dir = self
- .add_dir(name.clone())
- .add_dir(job_id.clone())
- .add_file("job-id", job_id.clone())
- .add_file("url", format!("{}.cmx", name).as_ref())
- .add_file("name", name.clone());
- if let Some(merkleroot) = merkleroot {
- base_dir.add_dir("in").add_dir("pkg").add_file("meta", merkleroot);
- }
- self
- }
-
- fn add_v2_component_leaf(self, name: &str, id: &str, component_type: &str) -> Self {
- self.add_v2_component_chain(name, id, component_type);
- self
- }
-
- fn add_v2_component_chain(self, name: &str, id: &str, component_type: &str) -> Self {
- self.add_dir(name.clone())
- .add_file("url", format!("{}.cm", name).as_ref())
- .add_file("id", id)
- .add_file("component_type", component_type)
- .add_dir("children")
- }
- }
-
- fn make_v1_hub_tree(root: &mut io_test::TestDirentTree) {
- root.add_file("job-id", "999")
- .add_file("name", "app")
- .add_dir("c")
- .add_v1_component_leaf("sysmgr", "123", Some("12345"))
- .add_v1_component_leaf("tiles", "1234", None);
-
- let realm = root.add_dir("r").add_dir("realm").add_dir("456");
- realm.add_dir("r");
- realm
- .add_file("name", "realm")
- .add_file("job-id", "456")
- .add_dir("c")
- .add_v1_component_leaf("foo", "4567", None);
- }
-
- // Root is special as it has no self-named directory.
- fn hub_root_setup(root: &mut io_test::TestDirentTree) -> &mut io_test::TestDirentTree {
- root.add_file("url", "root.cm").add_file("id", "1").add_file("component_type", "fun");
- root.add_dir("children")
- }
-
- #[fuchsia_async::run_singlethreaded(test)]
- async fn test_hub_tree() {
- // Intended hub topo:
- //
- // root -|
- // |
- // |-----> bootstrap ---> appmgr --------|----> sysmgr.cmx (m)
- // | |
- // | |----> tiles.cmx
- // | |
- // | |----> realm ---> foo.cmx
- // |-----> console ----> driver_manager
- //
- let mut root = io_test::TestDirentTree::root();
- let root_component = hub_root_setup(&mut root);
- #[rustfmt::skip]
- root_component
- .add_v2_component_chain("console", "3", "fabulous")
- .add_v2_component_leaf("driver_manager", "7", "crunchy");
- let appmgr =
- root_component.add_v2_component_chain("bootstrap", "2", "spicy").add_dir("appmgr");
-
- // Appmgr is a little special for its setup.
- appmgr.add_dir("children");
- appmgr
- .add_file("id", "8")
- .add_file("url", V1_ROOT_COMPONENT)
- .add_file("component_type", "extra_special");
- let v1_hub_root = appmgr.add_dir("exec").add_dir("out").add_dir("hub");
- make_v1_hub_tree(v1_hub_root);
-
- let root = io_test::setup_fake_directory(root).to_component_v2().await.unwrap();
- assert_eq!(root.url, "root.cm");
- assert_eq!(root.id, "1");
- assert_eq!(root.component_type, "fun");
- assert_eq!(root.children.len(), 2);
- let bootstrap = root
- .children
- .iter()
- .find(|c| c.as_v2().unwrap().url == "bootstrap.cm")
- .unwrap()
- .as_v2()
- .unwrap();
- assert_eq!(bootstrap.id, "2");
- assert_eq!(bootstrap.component_type, "spicy");
- assert_eq!(bootstrap.children.len(), 1);
- let appmgr = bootstrap.children[0].as_v2().unwrap();
- assert_eq!(appmgr.id, "8");
- assert_eq!(appmgr.url, V1_ROOT_COMPONENT);
- assert_eq!(appmgr.component_type, "extra_special");
- assert_eq!(appmgr.children.len(), 1);
- let app_realm = appmgr.children[0].as_v1().unwrap();
- assert_eq!(app_realm.id, 999);
- assert_eq!(app_realm.name, "app");
- assert_eq!(app_realm.components.len(), 2);
- assert_eq!(app_realm.realms.len(), 1);
- let sysmgr = app_realm.components.iter().find(|c| c.name == "sysmgr").unwrap();
- assert_eq!(sysmgr.url, "sysmgr.cmx");
- assert_eq!(sysmgr.id, 123);
- assert_eq!(sysmgr.merkleroot, Some("12345".to_owned()));
- assert_eq!(sysmgr.children.len(), 0);
- let tiles = app_realm.components.iter().find(|c| c.name == "tiles").unwrap();
- assert_eq!(tiles.url, "tiles.cmx");
- assert_eq!(tiles.id, 1234);
- assert_eq!(tiles.merkleroot, None);
- assert_eq!(tiles.children.len(), 0);
- let subrealm = &app_realm.realms[0];
- assert_eq!(subrealm.name, "realm");
- assert_eq!(subrealm.id, 456);
- assert_eq!(subrealm.realms.len(), 0);
- assert_eq!(subrealm.components.len(), 1);
- let foo = &subrealm.components[0];
- assert_eq!(foo.name, "foo");
- assert_eq!(foo.url, "foo.cmx");
- assert_eq!(foo.id, 4567);
- assert_eq!(foo.merkleroot, None);
- assert_eq!(foo.children.len(), 0);
- let console = root
- .children
- .iter()
- .find(|c| c.as_v2().unwrap().url == "console.cm")
- .unwrap()
- .as_v2()
- .unwrap();
- assert_eq!(console.id, "3");
- assert_eq!(console.component_type, "fabulous");
- assert_eq!(console.children.len(), 1);
- let driver_manager = console.children[0].as_v2().unwrap();
- assert_eq!(driver_manager.id, "7");
- assert_eq!(driver_manager.url, "driver_manager.cm");
- assert_eq!(driver_manager.component_type, "crunchy");
- }
-}