1use std::{collections::BTreeSet, process::exit};23use clap::Parser;4use jrsonnet_cli::MiscOpts;5use jrsonnet_evaluator::{FileImportResolver, ImportResolver};6use jrsonnet_ir::{IStr, Source, SourcePath, visit::Visitor};7use jrsonnet_ir_parser::ParserSettings;89#[derive(Parser)]10struct Opts {11 12 input: String,13 #[clap(flatten)]14 misc: MiscOpts,15}1617struct FoundImports(Vec<(IStr, bool)>);18impl Visitor for FoundImports {19 fn visit_import(&mut self, expression: bool, value: IStr) {20 self.0.push((value, expression));21 }22}2324fn collect_deps(25 resolver: &FileImportResolver,26 source: &SourcePath,27 deps: &mut BTreeSet<String>,28) -> Result<(), String> {29 let contents = resolver30 .load_file_contents(source)31 .map_err(|e| format!("{e}"))?;32 let code = std::str::from_utf8(&contents).map_err(|e| format!("{source}: {e}"))?;33 let code: IStr = code.into();34 let parsed = jrsonnet_ir_parser::parse(35 &code,36 &ParserSettings {37 source: Source::new(source.clone(), code.clone()),38 },39 )40 .map_err(|e| format!("{source}: {e}"))?;4142 let mut imports = FoundImports(vec![]);43 imports.visit_expr(&parsed);4445 for (path, expression) in imports.0 {46 let resolved = resolver47 .resolve_from(source, &&*path)48 .map_err(|e| format!("{e}"))?;49 let path_str = format!("{resolved}");50 if deps.insert(path_str) && expression {51 collect_deps(resolver, &resolved, deps)?;52 }53 }5455 Ok(())56}5758fn main() {59 let opts = Opts::parse();60 let resolver = opts.misc.import_resolver();6162 let source = resolver63 .resolve_from_default(&opts.input.as_str())64 .unwrap_or_else(|e| {65 eprintln!("{e}");66 exit(1);67 });6869 let mut deps = BTreeSet::new();70 if let Err(e) = collect_deps(&resolver, &source, &mut deps) {71 eprintln!("{e}");72 exit(1);73 }7475 for dep in &deps {76 println!("{dep}");77 }78}