| 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); |
| } |