libwally/
package_source.rs

1mod in_memory;
2mod registry;
3mod test_registry;
4
5pub use self::in_memory::InMemoryRegistry;
6use self::in_memory::InMemoryRegistrySource;
7pub use self::registry::Registry;
8pub use self::test_registry::TestRegistry;
9
10use std::collections::HashMap;
11use std::path::PathBuf;
12
13use serde::Serialize;
14
15use crate::manifest::Manifest;
16use crate::package_contents::PackageContents;
17use crate::package_id::PackageId;
18use crate::package_req::PackageReq;
19
20#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
21pub enum PackageSourceId {
22    DefaultRegistry,
23    Git(String),
24    Path(PathBuf),
25}
26
27#[derive(Clone)]
28pub struct PackageSourceMap {
29    sources: HashMap<PackageSourceId, Box<PackageSource>>,
30    source_order: Vec<PackageSourceId>,
31}
32
33impl PackageSourceMap {
34    pub fn new(default_registry: Box<PackageSource>) -> Self {
35        let mut sources = HashMap::new();
36        sources.insert(PackageSourceId::DefaultRegistry, default_registry);
37
38        Self {
39            sources,
40            source_order: vec![PackageSourceId::DefaultRegistry],
41        }
42    }
43
44    pub fn get(&self, id: &PackageSourceId) -> Option<&PackageSource> {
45        self.sources.get(id).map(|source| source.as_ref())
46    }
47
48    pub fn source_order(&self) -> &Vec<PackageSourceId> {
49        &self.source_order
50    }
51
52    /// Searches the current list of sources for fallbacks and adds any not yet in the list, producing
53    /// a complete tree of reachable sources for packages.
54    /// Sources are searched breadth-first to ensure correct fallback priority.
55    pub fn add_fallbacks(&mut self) -> anyhow::Result<()> {
56        let mut source_index = 0;
57
58        while source_index < self.source_order.len() {
59            let registry = self.sources.get(&self.source_order[source_index]).unwrap();
60
61            for fallback in registry.fallback_sources()? {
62                // Prevent circular references by only adding new sources
63                if !self.source_order.contains(&fallback) {
64                    let source: Box<PackageSource> = match &fallback {
65                        PackageSourceId::Git(url) => {
66                            Box::new(PackageSource::Registry(Registry::from_registry_spec(url)?))
67                        }
68                        PackageSourceId::Path(path) => {
69                            Box::new(PackageSource::TestRegistry(TestRegistry::new(path.clone())))
70                        }
71                        PackageSourceId::DefaultRegistry => {
72                            panic!("Default registry should never be added as a fallback source!")
73                        }
74                    };
75
76                    self.sources.insert(fallback.clone(), source);
77                    self.source_order.push(fallback);
78                }
79            }
80
81            source_index += 1;
82        }
83
84        Ok(())
85    }
86}
87
88pub trait PackageSourceProvider: Sync + Send + Clone {
89    /// Update this package source, if it has state that needs to be updated.
90    fn update(&self) -> anyhow::Result<()>;
91
92    /// Query this package source for all of the packages that match this
93    /// `PackageReq`.
94    fn query(&self, package_req: &PackageReq) -> anyhow::Result<Vec<Manifest>>;
95
96    /// Downloads the contents of a package given its fully-qualified
97    /// `PackageId`.
98    fn download_package(&self, package_id: &PackageId) -> anyhow::Result<PackageContents>;
99
100    /// Provide a list of fallback sources to search if this source can't provide a package
101    fn fallback_sources(&self) -> anyhow::Result<Vec<PackageSourceId>>;
102}
103
104#[derive(Clone)]
105pub enum PackageSource {
106    InMemory(InMemoryRegistrySource),
107    Registry(Registry),
108    TestRegistry(TestRegistry),
109}
110
111impl PackageSourceProvider for PackageSource {
112    fn update(&self) -> anyhow::Result<()> {
113        match self {
114            PackageSource::InMemory(source) => source.update(),
115            PackageSource::Registry(source) => source.update(),
116            PackageSource::TestRegistry(source) => source.update(),
117        }
118    }
119
120    fn query(&self, package_req: &PackageReq) -> anyhow::Result<Vec<Manifest>> {
121        match self {
122            PackageSource::InMemory(source) => source.query(package_req),
123            PackageSource::Registry(source) => source.query(package_req),
124            PackageSource::TestRegistry(source) => source.query(package_req),
125        }
126    }
127
128    fn download_package(&self, package_id: &PackageId) -> anyhow::Result<PackageContents> {
129        match self {
130            PackageSource::InMemory(source) => source.download_package(package_id),
131            PackageSource::Registry(source) => source.download_package(package_id),
132            PackageSource::TestRegistry(source) => source.download_package(package_id),
133        }
134    }
135
136    fn fallback_sources(&self) -> anyhow::Result<Vec<PackageSourceId>> {
137        match self {
138            PackageSource::InMemory(source) => source.fallback_sources(),
139            PackageSource::Registry(source) => source.fallback_sources(),
140            PackageSource::TestRegistry(source) => source.fallback_sources(),
141        }
142    }
143}