reg_index/
list.rs

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
10/// List entries in the index.
11///
12/// This will list all entries for a particular package in the index. If the
13/// version is not specified, all versions are returned. The version supports
14/// semver requirement syntax.
15pub 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
32/// List all entries for all packages in the index.
33///
34/// If `pkg_name` is set, only list the given package.
35/// If `version_req` is set, filters with the given semver requirement.
36/// The given callback will be called for each version.
37pub 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}