blob: 7721d1973175ae15fcfea969906d5ddddf9c2dcd [file] [log] [blame]
// Copyright 2023 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 anyhow::{Context, Result};
use camino::{Utf8Path, Utf8PathBuf};
use component_id_index::Index;
use fidl::persist;
use fidl_fuchsia_component_internal::ComponentIdIndex;
/// A builder that constructs component id indices.
#[derive(Default)]
pub struct ComponentIdIndexBuilder {
indices: Vec<Utf8PathBuf>,
}
impl ComponentIdIndexBuilder {
/// Add a product-provided index.
pub fn index(&mut self, index: impl AsRef<Utf8Path>) -> &mut Self {
self.indices.push(index.as_ref().into());
self
}
/// Build the final index by merging all the indices from the product and
/// optionally the core component id index.
pub fn build(self, outdir: impl AsRef<Utf8Path>) -> Result<Utf8PathBuf> {
let merged_index =
Index::merged_from_json5_files(&self.indices).context("merging index files")?;
let merged_index_fidl: ComponentIdIndex =
merged_index.try_into().context("converting index into fidl")?;
let bytes = persist(&merged_index_fidl).context("Could not fidl-encode index")?;
let path = outdir.as_ref().join("component_id_index.fidlbin");
std::fs::write(&path, bytes)
.context("Could not write merged FIDL-encoded index to file")?;
Ok(path)
}
}
#[cfg(test)]
mod tests {
use super::*;
use component_id_index::InstanceId;
use moniker::Moniker;
use pretty_assertions::assert_eq;
use std::io::Write;
fn gen_index(start: u32, end: u32) -> Index {
let mut index = Index::default();
for i in start..end {
let moniker = Moniker::parse_str(&format!("/a/b/c/{i}")).unwrap();
let instance_id =
format!("00000000000000000000000000000000000000000000000000000000000000{:02x}", i)
.parse::<InstanceId>()
.unwrap();
index.insert(moniker, instance_id).unwrap();
}
index
}
#[test]
fn build_empty() {
let outdir = tempfile::TempDir::new().unwrap();
let outdir_path = Utf8PathBuf::from_path_buf(outdir.path().to_path_buf()).unwrap();
let builder = ComponentIdIndexBuilder::default();
let path = builder.build(&outdir_path).unwrap();
assert_eq!(path, outdir_path.join("component_id_index.fidlbin"));
}
#[test]
fn build_multiple_indices() {
let mut tmp_input_index1 = tempfile::NamedTempFile::new().unwrap();
let mut tmp_input_index2 = tempfile::NamedTempFile::new().unwrap();
// write the first index file
let index1 = gen_index(0, 2);
let index1_path =
Utf8PathBuf::from_path_buf(tmp_input_index1.path().to_path_buf()).unwrap();
tmp_input_index1.write_all(serde_json5::to_string(&index1).unwrap().as_bytes()).unwrap();
// write the second index file
let index2 = gen_index(2, 4);
let index2_path =
Utf8PathBuf::from_path_buf(tmp_input_index2.path().to_path_buf()).unwrap();
tmp_input_index2.write_all(serde_json5::to_string(&index2).unwrap().as_bytes()).unwrap();
let outdir = tempfile::TempDir::new().unwrap();
let outdir_path = Utf8PathBuf::from_path_buf(outdir.path().to_path_buf()).unwrap();
let mut builder = ComponentIdIndexBuilder::default();
builder.index(&index1_path);
builder.index(&index2_path);
let path = builder.build(&outdir_path).unwrap();
assert_eq!(path, outdir_path.join("component_id_index.fidlbin"));
let index = component_id_index::Index::from_fidl_file(&path).unwrap();
for i in 0..4 {
let mon = Moniker::parse_str(&format!("/a/b/c/{}", i)).unwrap();
let instance = index.id_for_moniker(&mon).unwrap();
let expected =
format!("00000000000000000000000000000000000000000000000000000000000000{:02x}", i)
.parse::<InstanceId>()
.unwrap();
assert!(index.contains_id(&expected));
assert_eq!(&expected, instance);
}
}
}