1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
use std::collections::BTreeMap;
use std::path::PathBuf;
use std::path::Path;
use anyhow::Result;
use anyhow::Context;
use resiter::Map;
use crate::package::Package;
use crate::package::PackageName;
use crate::package::PackageVersion;
use crate::package::PackageVersionConstraint;
/// A repository represents a collection of packages
pub struct Repository {
inner: BTreeMap<(PackageName, PackageVersion), Package>,
}
impl Repository {
pub fn load(path: &Path) -> Result<Self> {
fn all_subdirs(p: &Path) -> Result<Vec<PathBuf>> {
let mut v = Vec::new();
for de in p.read_dir()? {
let de = de?;
if de.file_type()?.is_dir() {
v.push(de.path());
}
}
return Ok(v)
}
fn load_recursive(path: &Path, mut config: config::Config) -> Result<Vec<Result<Package>>> {
let pkg_file = path.join("pkg.toml");
if pkg_file.is_file() {
let buf = std::fs::read_to_string(&pkg_file)
.with_context(|| format!("Reading {}", pkg_file.display()))?;
config.merge(config::File::from_str(&buf, config::FileFormat::Toml))
.with_context(|| format!("Loading contents of {}", pkg_file.display()))?;
}
let subdirs = all_subdirs(path).with_context(|| format!("Finding subdirs for {}", pkg_file.display()))?;
if subdirs.is_empty() {
let package = config
.deserialize()
.with_context(|| format!("Failed to parse {} into package", path.display()));
Ok(vec![package])
} else {
subdirs
.into_iter()
.fold(Ok(Vec::new()), |vec, dir| {
vec.and_then(|mut v| {
let mut loaded = load_recursive(&dir, config.clone())
.with_context(|| format!("Recursing for {}", pkg_file.display()))?;
v.append(&mut loaded);
Ok(v)
})
})
}
}
let inner = load_recursive(path, config::Config::default())
.with_context(|| format!("Recursing for {}", path.display()))?
.into_iter()
.map_ok(|p| ((p.name().clone(), p.version().clone()), p))
.collect::<Result<_>>()?;
Ok(Repository { inner })
}
pub fn find_by_name<'a>(&'a self, name: &PackageName) -> Vec<&'a Package> {
self.inner
.iter()
.filter(|((n, _), _)| name == n)
.map(|(_, pack)| pack)
.collect()
}
pub fn find<'a>(&'a self, name: &PackageName, version: &PackageVersion) -> Option<&'a Package> {
self.inner
.iter()
.find(|((n, v), _)| n == name && v == version)
.map(|(_, p)| p)
}
pub fn find_with_version_contraint<'a>(&'a self, name: &PackageName, vc: &PackageVersionConstraint) -> Vec<&'a Package> {
self.inner
.iter()
.filter(|((n, v), _)| {
n == name && vc.matches(v).map(|mtch| !mtch.is_false()).unwrap_or(false)
})
.map(|(_, p)| p)
.collect()
}
}
|