@@ -4,6 +4,7 @@ use libpkgx::{
44 install_multi:: install_multi,
55 pantry_db, sync,
66 types:: { Installation , PackageReq } ,
7+ VersionRange ,
78} ;
89use rusqlite:: Connection ;
910
@@ -23,34 +24,24 @@ pub async fn resolve(
2324 let mut pkgs = vec ! [ ] ;
2425
2526 for pkgspec in plus {
26- let PackageReq {
27- project : project_or_cmd,
28- constraint,
29- } = PackageReq :: parse ( pkgspec) ?;
30- if config
27+ let mut pkgspec = parse_pkgspec ( pkgspec) ?;
28+
29+ if !config
3130 . pantry_dir
3231 . join ( "projects" )
33- . join ( project_or_cmd . clone ( ) )
32+ . join ( pkgspec . project ( ) )
3433 . is_dir ( )
3534 {
36- pkgs. push ( PackageReq {
37- project : project_or_cmd,
38- constraint,
39- } ) ;
40- } else {
41- let project = which:: which ( & project_or_cmd, conn, & pkgs) . await ?;
42- pkgs. push ( PackageReq {
43- project,
44- constraint,
45- } ) ;
35+ let project = which:: which ( & pkgspec. project ( ) , conn, & pkgs) . await ?;
36+ pkgspec. set_project ( project) ;
4637 }
38+
39+ pkgs. push ( pkgspec. pkgreq ( config) . await ) ;
4740 }
4841
4942 if find_program {
50- let PackageReq {
51- constraint,
52- project : cmd,
53- } = PackageReq :: parse ( & args[ 0 ] ) ?;
43+ let mut pkgspec = parse_pkgspec ( & args[ 0 ] ) ?;
44+ let cmd = pkgspec. project ( ) ;
5445
5546 args[ 0 ] = cmd. clone ( ) ; // invoke eg. `node` rather than eg. `node@20`
5647
@@ -69,10 +60,9 @@ pub async fn resolve(
6960 Ok ( project) => Ok ( project) ,
7061 } ?;
7162
72- pkgs. push ( PackageReq {
73- project,
74- constraint,
75- } ) ;
63+ pkgspec. set_project ( project. clone ( ) ) ;
64+
65+ pkgs. push ( pkgspec. pkgreq ( config) . await ) ;
7666 }
7767
7868 let companions = pantry_db:: companions_for_projects (
@@ -97,3 +87,56 @@ pub async fn resolve(
9787
9888 Ok ( ( installations, graph) )
9989}
90+
91+ enum Pkgspec {
92+ Req ( PackageReq ) ,
93+ Latest ( String ) ,
94+ }
95+
96+ impl Pkgspec {
97+ fn project ( & self ) -> String {
98+ match self {
99+ Pkgspec :: Req ( req) => req. project . clone ( ) ,
100+ Pkgspec :: Latest ( project) => project. clone ( ) ,
101+ }
102+ }
103+
104+ fn set_project ( & mut self , project : String ) {
105+ match self {
106+ Pkgspec :: Req ( req) => req. project = project,
107+ Pkgspec :: Latest ( _) => * self = Pkgspec :: Latest ( project) ,
108+ }
109+ }
110+
111+ async fn constraint ( & self , config : & Config ) -> VersionRange {
112+ match self {
113+ Pkgspec :: Req ( req) => req. constraint . clone ( ) ,
114+ Pkgspec :: Latest ( project) => match libpkgx:: inventory:: ls ( project, config) . await {
115+ Ok ( versions) if !versions. is_empty ( ) => {
116+ let vmax = versions. iter ( ) . max ( ) ;
117+ VersionRange :: parse ( & format ! ( "={}" , vmax. unwrap( ) ) )
118+ }
119+ _ => VersionRange :: parse ( "*" ) ,
120+ }
121+ . unwrap ( ) ,
122+ }
123+ }
124+
125+ async fn pkgreq ( & self , config : & Config ) -> PackageReq {
126+ let project = self . project ( ) ;
127+ let constraint = self . constraint ( config) . await ;
128+ PackageReq {
129+ project,
130+ constraint,
131+ }
132+ }
133+ }
134+
135+ fn parse_pkgspec ( pkgspec : & str ) -> Result < Pkgspec , Box < dyn std:: error:: Error > > {
136+ if let Some ( project) = pkgspec. strip_suffix ( "@latest" ) {
137+ Ok ( Pkgspec :: Latest ( project. to_string ( ) ) )
138+ } else {
139+ let pkgspec = PackageReq :: parse ( pkgspec) ?;
140+ Ok ( Pkgspec :: Req ( pkgspec) )
141+ }
142+ }
0 commit comments