blob: bdbb0d185ce00cbd8bca29285843fb1e1a2b6250 [file]
use std::collections::{BTreeMap, BTreeSet, HashMap};
use std::fs::read_to_string;
use std::path::PathBuf;
use cargo_toml::Manifest;
use clap::Parser;
use handlebars::Handlebars;
use serde::{Deserialize, Serialize};
#[derive(Debug, Parser)]
struct Args {
#[arg(long, required(true))]
config: PathBuf,
#[arg(required(true))]
manifest: Vec<PathBuf>,
}
#[derive(Deserialize)]
struct Mapping {
constraint: String,
path: String,
}
#[derive(Deserialize)]
struct Config {
mappings: HashMap<String, Mapping>,
}
#[derive(Serialize)]
struct Alias {
pub name: String,
// Using BTreeSet and BTreeMap here for a stable output order.
pub target_compatible_with: BTreeSet<String>,
pub actual: BTreeMap<String, String>,
}
fn main() {
let args = Args::parse();
let config_str = read_to_string(args.config).expect("config file exists");
let config: Config = toml::from_str(&config_str).expect("config file parses");
// Using BTreeMap here for a stable output order.
let mut aliases: BTreeMap<String, Alias> = BTreeMap::new();
for manifest_path in args.manifest {
let manifest = Manifest::from_path(manifest_path).expect("manifest parses");
let package_name = &manifest.package().name;
let Some(mapping) = config.mappings.get(package_name) else {
panic!("No mapping for {package_name} in config.");
};
for dep_name in manifest.dependencies.keys() {
let alias = aliases.entry(dep_name.clone()).or_insert(Alias {
name: dep_name.clone(),
target_compatible_with: BTreeSet::new(),
actual: BTreeMap::new(),
});
alias
.target_compatible_with
.insert(mapping.constraint.clone());
alias.actual.insert(
mapping.constraint.clone(),
format!("{}:{dep_name}", mapping.path),
);
}
}
// Create a wrapper struct so that we expose `aliases` as a single element
// in the template's global namespace.
#[derive(Serialize)]
struct TemplateData<'a> {
aliases: &'a BTreeMap<String, Alias>,
}
let template = r#"
# Auto-generated by //create_aliases. See //README.md for information on
# updating
def make_crate_aliases():
{{#each aliases}}
native.alias (
name = "{{this.name}}",
target_compatible_with = select({
{{#each this.target_compatible_with}}
"{{this}}": [],
{{/each}}
"//conditions:default": ["@platforms//:incompatible"],
}),
actual = select({
{{#each this.actual}}
"{{@key}}": "{{this}}",
{{/each}}
}),
visibility = ["//visibility:public"],
)
{{/each}}
"#
.trim();
let output = Handlebars::new()
.render_template(template, &TemplateData { aliases: &aliases })
.expect("Template renders");
print!("{}", output);
}