1#![deny(missing_docs)]
4
5use anyhow::Result;
6use indexmap::IndexMap;
7use miette::{GraphicalReportHandler, GraphicalTheme, NamedSource, Report};
8use std::{
9 collections::HashMap,
10 io::IsTerminal,
11 path::{Path, PathBuf},
12};
13use wac_parser::Document;
14use wac_resolver::{packages, Error, FileSystemPackageResolver};
15use wac_types::BorrowedPackageKey;
16
17pub mod commands;
18
19#[cfg(feature = "registry")]
20mod progress;
21
22fn fmt_err(e: impl Into<Report>, path: &Path, source: &str) -> anyhow::Error {
23 let mut s = String::new();
24 let e = e.into();
25 GraphicalReportHandler::new()
26 .with_cause_chain()
27 .with_theme(if std::io::stderr().is_terminal() {
28 GraphicalTheme::unicode()
29 } else {
30 GraphicalTheme::unicode_nocolor()
31 })
32 .render_report(
33 &mut s,
34 e.with_source_code(NamedSource::new(path.to_string_lossy(), source.to_string()))
35 .as_ref(),
36 )
37 .expect("failed to render diagnostic");
38 anyhow::Error::msg(s)
39}
40
41pub struct PackageResolver {
48 fs: FileSystemPackageResolver,
49 #[cfg(feature = "registry")]
50 registry: Option<wac_resolver::RegistryPackageResolver>,
51}
52
53impl PackageResolver {
54 pub async fn new(
56 dir: impl Into<PathBuf>,
57 overrides: HashMap<String, PathBuf>,
58 #[cfg(feature = "registry")] registry: Option<&str>,
59 ) -> Result<Self> {
60 Ok(Self {
61 fs: FileSystemPackageResolver::new(dir, overrides, false),
62 #[cfg(feature = "registry")]
63 registry: if registry.is_some() {
64 Some(
65 wac_resolver::RegistryPackageResolver::new(
66 registry,
67 Some(Box::new(progress::ProgressBar::new())),
68 )
69 .await?,
70 )
71 } else {
72 None
73 },
74 })
75 }
76
77 pub async fn resolve<'a>(
79 &mut self,
80 document: &'a Document<'a>,
81 ) -> Result<IndexMap<BorrowedPackageKey<'a>, Vec<u8>>, Error> {
82 let mut keys = packages(document)?;
83
84 #[allow(unused_mut)]
87 let mut packages = self.fs.resolve(&keys)?;
88 keys.retain(|key, _| !packages.contains_key(key));
89
90 #[cfg(feature = "registry")]
93 if !keys.is_empty() {
94 if self.registry.is_none() {
95 self.registry = Some(
96 wac_resolver::RegistryPackageResolver::new(
97 None,
98 Some(Box::new(progress::ProgressBar::new())),
99 )
100 .await
101 .map_err(Error::RegistryClientFailed)?,
102 );
103 }
104 let reg_packages = self.registry.as_ref().unwrap().resolve(&keys).await?;
105 keys.retain(|key, _| !reg_packages.contains_key(key));
106 packages.extend(reg_packages);
107 }
108
109 if let Some((key, span)) = keys.first() {
111 return Err(Error::UnknownPackage {
112 name: key.name.to_string(),
113 span: *span,
114 });
115 }
116
117 Ok(packages)
118 }
119}