• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pkgxdev / pkgx / 14221314421

02 Apr 2025 01:49PM UTC coverage: 89.48% (+0.06%) from 89.425%
14221314421

push

github

mxcl
bump libsemverator

1 of 3 new or added lines in 2 files covered. (33.33%)

1463 of 1635 relevant lines covered (89.48%)

17075858.1 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.32
/crates/cli/src/resolve.rs
1
use libpkgx::{
2
    config::Config,
3
    hydrate::hydrate,
4
    install_multi::install_multi,
5
    pantry_db, sync,
6
    types::{Installation, PackageReq},
7
    VersionRange,
8
};
9
use rusqlite::Connection;
10

11
use crate::{spinner::Spinner, which};
12

13
pub async fn resolve(
28✔
14
    args: &mut [String],
28✔
15
    plus: &[String],
28✔
16
    find_program: bool,
28✔
17
    config: &Config,
28✔
18
    conn: &mut Connection,
28✔
19
    did_sync: bool,
28✔
20
    spinner: &mut Spinner,
28✔
21
) -> std::result::Result<(Vec<Installation>, Vec<PackageReq>), Box<dyn std::error::Error>> {
28✔
22
    spinner.set_message("resolving pkg graph…");
28✔
23

28✔
24
    let mut pkgs = vec![];
28✔
25

26
    for pkgspec in plus {
52✔
27
        let mut pkgspec = parse_pkgspec(pkgspec)?;
24✔
28

29
        if !config
24✔
30
            .pantry_dir
24✔
31
            .join("projects")
24✔
32
            .join(pkgspec.project())
24✔
33
            .is_dir()
24✔
34
        {
35
            let project = which::which(&pkgspec.project(), conn, &pkgs).await?;
16✔
36
            pkgspec.set_project(project);
16✔
37
        }
8✔
38

39
        pkgs.push(pkgspec.pkgreq(config).await);
24✔
40
    }
41

42
    if find_program {
28✔
43
        let mut pkgspec = parse_pkgspec(&args[0])?;
2✔
44
        let cmd = pkgspec.project();
2✔
45

2✔
46
        args[0] = cmd.clone(); // invoke eg. `node` rather than eg. `node@20`
2✔
47

48
        let project = match which::which(&cmd, conn, &pkgs).await {
2✔
49
            Err(which::WhichError::CmdNotFound(cmd)) => {
×
50
                if !did_sync {
×
51
                    spinner.set_message(&format!("{} not found, syncing…", cmd));
×
52
                    sync::update(config, conn).await?; // cmd not found ∴ sync in case it is new
×
53
                    spinner.set_message("resolving pkg graph…");
×
54
                    which::which(&cmd, conn, &pkgs).await
×
55
                } else {
56
                    Err(which::WhichError::CmdNotFound(cmd))
×
57
                }
58
            }
59
            Err(err) => Err(err),
2✔
60
            Ok(project) => Ok(project),
×
61
        }?;
2✔
62

63
        pkgspec.set_project(project.clone());
×
64

65
        pkgs.push(pkgspec.pkgreq(config).await);
×
66
    }
26✔
67

68
    let companions = pantry_db::companions_for_projects(
26✔
69
        &pkgs
26✔
70
            .iter()
26✔
71
            .map(|project| project.project.clone())
26✔
72
            .collect::<Vec<_>>(),
26✔
73
        conn,
26✔
74
    )?;
26✔
75

76
    pkgs.extend(companions);
26✔
77

78
    let graph = hydrate(&pkgs, |project| pantry_db::deps_for_project(&project, conn)).await?;
216✔
79

80
    let resolution = libpkgx::resolve::resolve(&graph, config).await?;
26✔
81

82
    let mut installations = resolution.installed;
26✔
83
    if !resolution.pending.is_empty() {
26✔
84
        let installed = install_multi(&resolution.pending, config, spinner.arc()).await?;
6✔
85
        installations.extend(installed);
6✔
86
    }
20✔
87

88
    Ok((installations, graph))
26✔
89
}
28✔
90

91
enum Pkgspec {
92
    Req(PackageReq),
93
    Latest(String),
94
}
95

96
impl Pkgspec {
97
    fn project(&self) -> String {
66✔
98
        match self {
66✔
99
            Pkgspec::Req(req) => req.project.clone(),
66✔
100
            Pkgspec::Latest(project) => project.clone(),
×
101
        }
102
    }
66✔
103

104
    fn set_project(&mut self, project: String) {
16✔
105
        match self {
16✔
106
            Pkgspec::Req(req) => req.project = project,
16✔
107
            Pkgspec::Latest(_) => *self = Pkgspec::Latest(project),
×
108
        }
109
    }
16✔
110

111
    async fn constraint(&self, config: &Config) -> VersionRange {
24✔
112
        match self {
24✔
113
            Pkgspec::Req(req) => req.constraint.clone(),
24✔
114
            Pkgspec::Latest(project) => match libpkgx::inventory::ls(project, config).await {
×
115
                Ok(versions) if !versions.is_empty() => {
×
NEW
116
                    VersionRange::from_semver(versions.iter().max().unwrap()).unwrap()
×
117
                }
NEW
118
                _ => VersionRange::any(),
×
119
            },
120
        }
121
    }
24✔
122

123
    async fn pkgreq(&self, config: &Config) -> PackageReq {
24✔
124
        let project = self.project();
24✔
125
        let constraint = self.constraint(config).await;
24✔
126
        PackageReq {
24✔
127
            project,
24✔
128
            constraint,
24✔
129
        }
24✔
130
    }
24✔
131
}
132

133
fn parse_pkgspec(pkgspec: &str) -> Result<Pkgspec, Box<dyn std::error::Error>> {
26✔
134
    if let Some(project) = pkgspec.strip_suffix("@latest") {
26✔
135
        Ok(Pkgspec::Latest(project.to_string()))
×
136
    } else {
137
        let pkgspec = PackageReq::parse(pkgspec)?;
26✔
138
        Ok(Pkgspec::Req(pkgspec))
26✔
139
    }
140
}
26✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc