blob: 2acd80dfa4262545f4d20964c62f0e794d64c9ee [file] [log] [blame] [edit]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use alchemist::dependency::package::PackageAtom;
use alchemist::ebuild::PackageDetails;
use alchemist::{analyze::dependency::analyze_dependencies, bash::vars::BashValue};
use anyhow::{Context, Result};
use colored::Colorize;
use itertools::Itertools;
use std::sync::Arc;
use crate::alchemist::TargetData;
#[derive(clap::Args, Clone, Debug)]
pub struct Args {
/// Additionally dump the environment for the package.
#[arg(short = 'e', long)]
env: bool,
/// Package names.
packages: Vec<String>,
}
fn dump_deps(dep_type: &str, deps: &Vec<Arc<PackageDetails>>) {
println!("{dep_type}:");
for dep in deps {
println!(" {}-{}::{}", dep.package_name, dep.version, dep.repo_name);
}
}
pub fn dump_package_main(
host: Option<&TargetData>,
target: Option<&TargetData>,
args: Args,
) -> Result<()> {
let atoms = args
.packages
.iter()
.map(|raw| raw.parse::<PackageAtom>())
.collect::<Result<Vec<_>>>()?;
let resolver = target
.or(host)
.map(|data| &data.resolver)
.context("Expected a target or host resolver")?;
let cross_compile = if let Some(host) = host {
if let Some(target) = target {
let cbuild = host
.config
.env()
.get("CHOST")
.context("host is missing CHOST")?;
let chost = target
.config
.env()
.get("CHOST")
.context("target is missing CHOST")?;
cbuild != chost
} else {
false
}
} else {
true
};
for atom in atoms {
let mut packages = resolver.find_packages(&atom)?;
let default = resolver.find_best_package_in(&packages)?;
packages.sort_by(|a, b| a.version.cmp(&b.version));
packages.reverse();
println!("=======\t{}", atom);
for (i, details) in packages.into_iter().enumerate() {
if i > 0 {
println!();
}
let is_default = match &default {
Some(default) => default.ebuild_path == details.ebuild_path,
None => false,
};
println!("Path:\t\t{}", &details.ebuild_path.to_string_lossy());
println!("Package:\t{}", &details.package_name);
println!(
"Version:\t{}{}",
&details.version,
if is_default { " (Default)" } else { "" }
);
println!("Slot:\t\t{}", &details.slot);
println!("Accepted:\t{:?}", details.accepted);
println!("Stable:\t\t{:?}", details.stable);
println!("Masked:\t\t{}", details.masked);
println!(
"USE:\t\t{}",
details
.use_map
.iter()
.sorted()
.map(|(name, value)| {
let label = format!("{}{}", if *value { "+" } else { "-" }, name);
label.color(if *value { "red" } else { "blue" })
})
.join(" ")
);
let deps = analyze_dependencies(
&details,
cross_compile,
host.map(|data| &data.resolver),
resolver,
)?;
dump_deps("BDEPEND", &deps.build_host_deps);
dump_deps("IDEPEND", &deps.install_host_deps);
dump_deps("DEPEND", &deps.build_deps);
dump_deps("RDEPEND", &deps.runtime_deps);
dump_deps("PDEPEND", &deps.post_deps);
if args.env {
println!("Env: ");
let map = details.vars.hash_map();
for key in map.keys().sorted() {
println!(
" \"{}\": {}",
key,
match map.get(key).unwrap() {
BashValue::Scalar(val) => format!("\"{}\"", val),
BashValue::IndexedArray(vec) => format!("{:#?}", vec)
.lines()
.map(|line| format!(" {line}"))
.join("\n"),
BashValue::AssociativeArray(map) => format!("{:#?}", map)
.lines()
.map(|line| format!(" {line}"))
.join("\n"),
}
);
}
}
}
}
Ok(())
}