1use std::collections::BTreeSet;2use std::process::exit;34use clap::Parser;5use jrsonnet_evaluator::{FileImportResolver, ImportResolver};6use jrsonnet_ir::{visit::Visitor, IStr, Source, SourcePath};7use jrsonnet_ir_parser::ParserSettings;89use jrsonnet_cli::MiscOpts;1011#[derive(Parser)]12struct Opts {13 14 input: String,15 #[clap(flatten)]16 misc: MiscOpts,17}1819struct FoundImports(Vec<(IStr, bool)>);20impl Visitor for FoundImports {21 fn visit_import(&mut self, expression: bool, value: IStr) {22 self.0.push((value, expression));23 }24}2526fn collect_deps(27 resolver: &FileImportResolver,28 source: &SourcePath,29 deps: &mut BTreeSet<String>,30) -> Result<(), String> {31 let contents = resolver32 .load_file_contents(source)33 .map_err(|e| format!("{e}"))?;34 let code = std::str::from_utf8(&contents).map_err(|e| format!("{source}: {e}"))?;35 let code: IStr = code.into();36 let parsed = jrsonnet_ir_parser::parse(37 &code,38 &ParserSettings {39 source: Source::new(source.clone(), code.clone()),40 },41 )42 .map_err(|e| format!("{source}: {e}"))?;4344 let mut imports = FoundImports(vec![]);45 imports.visit_expr(&parsed);4647 for (path, expression) in imports.0 {48 let resolved = resolver49 .resolve_from(source, &&*path)50 .map_err(|e| format!("{e}"))?;51 let path_str = format!("{resolved}");52 if deps.insert(path_str) && expression {53 collect_deps(resolver, &resolved, deps)?;54 }55 }5657 Ok(())58}5960fn main() {61 let opts = Opts::parse();62 let resolver = opts.misc.import_resolver();6364 let source = resolver65 .resolve_from_default(&opts.input.as_str())66 .unwrap_or_else(|e| {67 eprintln!("{e}");68 exit(1);69 });7071 let mut deps = BTreeSet::new();72 if let Err(e) = collect_deps(&resolver, &source, &mut deps) {73 eprintln!("{e}");74 exit(1);75 }7677 for dep in &deps {78 println!("{dep}");79 }80}