blob: 3fc6d781ca99ff6f86218b28f823f3cc5b7b34c0 [file] [log] [blame]
// Copyright 2024 The Fuchsia Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::Error;
use argh::FromArgs;
use std::collections::BTreeSet;
use std::fs::File;
use std::io::{BufRead, BufReader, Write};
use std::path::PathBuf;
use std::process::Command;
/// Tool that run the aidl tool
/// Arguments for aidl_wrapper.
#[derive(Debug, FromArgs)]
pub struct AidlWrapperArgs {
/// path to the aidl tool
#[argh(option)]
pub aidl_path: PathBuf,
/// base paths for the library
#[argh(option)]
pub base: Vec<PathBuf>,
/// directory into which the tool will generate the dependencies and package files
#[argh(option)]
dependency_dir: PathBuf,
/// dependency dir of dependencies
#[argh(option)]
deps: Vec<PathBuf>,
/// arguments of the aidl command
#[argh(option)]
pub args: Vec<String>,
/// file containing the input of the aidl command
#[argh(option)]
pub inputs_path: PathBuf,
/// the version of the interface and parcelable
#[argh(option)]
version: Option<String>,
}
fn read_file<T>(filename: PathBuf) -> Result<T, Error>
where
T: FromIterator<String>,
{
// Open the file in read-only mode.
let file = File::open(filename)?;
// Read the file line by line.
Ok(BufReader::new(file).lines().collect::<Result<T, _>>()?)
}
fn read_path_bufs(filename: PathBuf) -> Result<BTreeSet<PathBuf>, Error> {
Ok(read_file::<BTreeSet<String>>(filename)?.iter().map(PathBuf::from).collect())
}
fn write_file<'a, T>(filename: PathBuf, content: impl Iterator<Item = T>) -> Result<(), Error>
where
String: From<T>,
{
std::fs::OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.open(filename)?
.write_all(content.map(String::from).collect::<Vec<_>>().join("\n").as_bytes())?;
Ok(())
}
const DEPS_FILE: &'static str = "deps.d";
const PACKAGE_FILE: &'static str = "aidl_package";
const BASES_FILE: &'static str = "aidl_bases";
const RUST_GLUE_ARGS: &'static str = "aidl_rust_glue_args";
const HASH_FILE: &'static str = ".hash";
fn main() -> Result<(), Error> {
let opt: AidlWrapperArgs = argh::from_env();
let mut packages = BTreeSet::<String>::new();
let mut dependencies = BTreeSet::<PathBuf>::new();
for base in &opt.base {
dependencies.insert(base.clone());
}
let mut glue_args = vec![];
for deps in opt.deps {
for package in read_file::<BTreeSet<String>>(deps.join(PACKAGE_FILE))? {
glue_args.push("-I".to_owned());
glue_args.push(package.replace(".", "_").to_owned());
}
for base in read_file::<BTreeSet<String>>(deps.join(BASES_FILE))? {
dependencies.insert(base.into());
}
}
for path in read_path_bufs(opt.inputs_path)? {
let mut hash = None;
for base in &opt.base {
if path.starts_with(base) {
let package = pathdiff::diff_paths(&path, &base)
.unwrap()
.parent()
.unwrap()
.to_string_lossy()
.replace("/", ".");
packages.insert(package);
if opt.version.is_some() {
let mut hashes = read_file::<Vec<String>>(base.join(HASH_FILE))?;
hash = hashes.pop();
}
}
}
let mut command = Command::new(&opt.aidl_path);
// Make aidl generate a dependencies file.
command.arg("-a");
for dep in &dependencies {
command.arg("-I").arg(dep);
}
if let Some(version) = &opt.version {
command.arg(format!("--version={version}"));
}
if let Some(hash) = hash {
command.arg(format!("--hash={hash}"));
}
for arg in &opt.args {
command.arg(arg);
}
command.arg(path);
let output = command.output()?;
if !output.status.success() {
anyhow::bail!("aidl failed: {output:?}");
}
}
// Find dependency files, aggregate it and delete the individual dependencies.
let mut aggregated_dependency_file = vec![];
for entry in walkdir::WalkDir::new(&opt.dependency_dir).into_iter() {
let entry = entry?;
let f_name = entry.file_name().to_string_lossy();
if f_name.ends_with(".d") {
let file = File::open(entry.path())?;
aggregated_dependency_file
.append(&mut BufReader::new(file).lines().collect::<Result<Vec<_>, _>>()?);
std::fs::remove_file(entry.path())?;
}
}
write_file(opt.dependency_dir.join(PACKAGE_FILE), packages.into_iter())?;
write_file(opt.dependency_dir.join(RUST_GLUE_ARGS), glue_args.iter().map(|x| x.as_str()))?;
write_file(opt.dependency_dir.join(DEPS_FILE), aggregated_dependency_file.into_iter())?;
write_file(
opt.dependency_dir.join(BASES_FILE),
dependencies.iter().map(|x| x.to_string_lossy()),
)?;
Ok(())
}