Skip to content

Commit 94ef81e

Browse files
committed
Support @latest
Closes #1160
1 parent 8d288f0 commit 94ef81e

File tree

7 files changed

+86
-35
lines changed

7 files changed

+86
-35
lines changed

.github/workflows/ci.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,11 @@ jobs:
180180
- name: --shebang test 2
181181
run: test $(pkgx -q! echo fail hi) = hi
182182

183+
- name: '@latest'
184+
run: |
185+
pkgx semverator eq $(pkgx krampus=0.2 --version) 0.2.0
186+
pkgx semverator gt $(pkgx krampus@latest --version) 0.2
187+
183188
- uses: coverallsapp/github-action@v2
184189
with:
185190
path-to-lcov: lcov.info

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/cli/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "pkgx"
33
description = "Run anything"
44
authors = ["Max Howell <mxcl@me.com>", "Jacob Heider <jacob@pkgx.dev>"]
55
license = "Apache-2.0"
6-
version = "2.5.0"
6+
version = "2.6.0"
77
edition = "2021"
88
repository = "https://github.com/pkgxdev/pkgx"
99

@@ -14,7 +14,7 @@ regex = "1.11.1"
1414
indicatif = "0.17.9"
1515
nix = { version = "0.29.0", features = ["process"] }
1616
serde_json = "1.0.135"
17-
libpkgx = { version = "0.5.0", path = "../lib" }
17+
libpkgx = { version = "0.6.0", path = "../lib" }
1818
console = { version = "0.15", default-features = false, features = [
1919
"ansi-parsing",
2020
] }

crates/cli/src/resolve.rs

Lines changed: 67 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use libpkgx::{
44
install_multi::install_multi,
55
pantry_db, sync,
66
types::{Installation, PackageReq},
7+
VersionRange,
78
};
89
use 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+
}

crates/lib/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "libpkgx"
33
description = "Install and run `pkgx` packages"
44
authors = ["Max Howell <mxcl@me.com>", "Jacob Heider <jacob@pkgx.dev>"]
55
license = "Apache-2.0"
6-
version = "0.5.0"
6+
version = "0.6.0"
77
edition = "2021"
88
repository = "https://github.com/pkgxdev/pkgx"
99

crates/lib/src/inventory.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ impl Error for DownloadError {}
2626

2727
// Select function to pick a version
2828
pub async fn select(rq: &PackageReq, config: &Config) -> Result<Option<Version>, Box<dyn Error>> {
29-
let versions = ls(rq, config).await?;
29+
let versions = ls(&rq.project, config).await?;
3030

3131
Ok(versions
3232
.iter()
@@ -36,13 +36,13 @@ pub async fn select(rq: &PackageReq, config: &Config) -> Result<Option<Version>,
3636
}
3737

3838
// Get function to fetch available versions
39-
pub async fn ls(rq: &PackageReq, config: &Config) -> Result<Vec<Version>, Box<dyn Error>> {
39+
pub async fn ls(project: &String, config: &Config) -> Result<Vec<Version>, Box<dyn Error>> {
4040
let base_url = config.dist_url.clone();
4141

4242
let (platform, arch) = host();
4343
let url = Url::parse(&format!(
4444
"{}/{}/{}/{}/versions.txt",
45-
base_url, rq.project, platform, arch
45+
base_url, project, platform, arch
4646
))?;
4747

4848
let rsp = build_client()?.get(url.clone()).send().await?;
@@ -64,11 +64,11 @@ pub async fn ls(rq: &PackageReq, config: &Config) -> Result<Vec<Version>, Box<dy
6464
if versions.is_empty() {
6565
return Err(Box::new(std::io::Error::new(
6666
std::io::ErrorKind::Other,
67-
format!("No versions for {}", rq.project),
67+
format!("No versions for {}", project),
6868
)));
6969
}
7070

71-
if rq.project == "openssl.org" {
71+
if project == "openssl.org" {
7272
// Workaround: Remove specific version
7373
let excluded_version = Version::parse("1.1.118")?;
7474
versions.retain(|x| x != &excluded_version);

crates/lib/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@ pub mod env;
55
pub mod hydrate;
66
mod install;
77
pub mod install_multi;
8-
mod inventory;
8+
pub mod inventory;
99
mod pantry;
1010
pub mod pantry_db;
1111
pub mod platform_case_aware_env_key;
1212
pub mod resolve;
1313
pub mod sync;
1414
pub mod types;
1515
pub mod utils;
16+
17+
pub type Version = libsemverator::semver::Semver;
18+
pub type VersionRange = libsemverator::range::Range;

0 commit comments

Comments
 (0)