1use super::IndexPackage;
2use crate::{
3 lock::Lock,
4 util::{crate_walker, pkg_path},
5};
6use anyhow::{Context, Error};
7use semver::VersionReq;
8use std::{fs, path::Path};
9
10pub fn list(
16 index: impl AsRef<Path>,
17 pkg_name: &str,
18 version_req: Option<&str>,
19) -> Result<Vec<IndexPackage>, Error> {
20 let index = index.as_ref();
21 let lock = Lock::new_shared(index)?;
22 let version_req = if let Some(version) = version_req {
23 Some(VersionReq::parse(version)?)
24 } else {
25 None
26 };
27 let res = _list(index, pkg_name, version_req.as_ref())?;
28 drop(lock);
29 Ok(res)
30}
31
32pub fn list_all(
38 index: impl AsRef<Path>,
39 pkg_name: Option<&str>,
40 version_req: Option<&str>,
41 mut cb: impl FnMut(Vec<IndexPackage>),
42) -> Result<(), Error> {
43 let index = index.as_ref();
44 let lock = Lock::new_shared(index)?;
45 let version_req = if let Some(version_req) = version_req {
46 Some(VersionReq::parse(version_req)?)
47 } else {
48 None
49 };
50 if let Some(pkg_name) = pkg_name {
51 let entries = _list(index, pkg_name, version_req.as_ref())?;
52 cb(entries);
53 } else {
54 for entry in crate_walker(index) {
55 let entry = entry?;
56 let pkg_name = entry.file_name().to_str().unwrap();
57 let entries = _list(index, pkg_name, version_req.as_ref())?;
58 cb(entries);
59 }
60 };
61 drop(lock);
62 Ok(())
63}
64
65pub(crate) fn _list(
66 index: &Path,
67 pkg_name: &str,
68 version_req: Option<&VersionReq>,
69) -> Result<Vec<IndexPackage>, Error> {
70 let repo_path = pkg_path(pkg_name);
71 let path = index.join(repo_path);
72 if !path.exists() {
73 return Ok(vec![]);
74 }
75 let contents = fs::read_to_string(&path)
76 .with_context(|| format!("Failed to read `{}`.", path.display()))?;
77 contents
78 .lines()
79 .map(|line| {
80 Ok(serde_json::from_str(line).with_context(|| {
81 format!("Could not deserialize `{}` line:\n{}", path.display(), line)
82 })?)
83 })
84 .filter(|index_pkg: &Result<IndexPackage, Error>| -> bool {
85 if let Some(version_req) = &version_req {
86 if let Ok(index_pkg) = index_pkg {
87 version_req.matches(&index_pkg.vers)
88 } else {
89 true
90 }
91 } else {
92 true
93 }
94 })
95 .collect::<Result<Vec<IndexPackage>, Error>>()
96}