Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,11 @@ jobs:
- name: --shebang test 2
run: test $(pkgx -q! echo fail hi) = hi

- name: '@latest'
run: |
pkgx semverator eq $(pkgx krampus=0.2.0 --version) 0.2.0
pkgx semverator gt $(pkgx krampus@latest --version) 0.2.0

- uses: coverallsapp/github-action@v2
with:
path-to-lcov: lcov.info
Expand Down
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "pkgx"
description = "Run anything"
authors = ["Max Howell <mxcl@me.com>", "Jacob Heider <jacob@pkgx.dev>"]
license = "Apache-2.0"
version = "2.5.0"
version = "2.6.0"
edition = "2021"
repository = "https://github.com/pkgxdev/pkgx"

Expand All @@ -14,7 +14,7 @@ regex = "1.11.1"
indicatif = "0.17.9"
nix = { version = "0.29.0", features = ["process"] }
serde_json = "1.0.135"
libpkgx = { version = "0.5.0", path = "../lib" }
libpkgx = { version = "0.6.0", path = "../lib" }
console = { version = "0.15", default-features = false, features = [
"ansi-parsing",
] }
Expand Down
91 changes: 67 additions & 24 deletions crates/cli/src/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use libpkgx::{
install_multi::install_multi,
pantry_db, sync,
types::{Installation, PackageReq},
VersionRange,
};
use rusqlite::Connection;

Expand All @@ -23,34 +24,24 @@ pub async fn resolve(
let mut pkgs = vec![];

for pkgspec in plus {
let PackageReq {
project: project_or_cmd,
constraint,
} = PackageReq::parse(pkgspec)?;
if config
let mut pkgspec = parse_pkgspec(pkgspec)?;

if !config
.pantry_dir
.join("projects")
.join(project_or_cmd.clone())
.join(pkgspec.project())
.is_dir()
{
pkgs.push(PackageReq {
project: project_or_cmd,
constraint,
});
} else {
let project = which::which(&project_or_cmd, conn, &pkgs).await?;
pkgs.push(PackageReq {
project,
constraint,
});
let project = which::which(&pkgspec.project(), conn, &pkgs).await?;
pkgspec.set_project(project);
}

pkgs.push(pkgspec.pkgreq(config).await);
}

if find_program {
let PackageReq {
constraint,
project: cmd,
} = PackageReq::parse(&args[0])?;
let mut pkgspec = parse_pkgspec(&args[0])?;
let cmd = pkgspec.project();

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

Expand All @@ -69,10 +60,9 @@ pub async fn resolve(
Ok(project) => Ok(project),
}?;

pkgs.push(PackageReq {
project,
constraint,
});
pkgspec.set_project(project.clone());

pkgs.push(pkgspec.pkgreq(config).await);
}

let companions = pantry_db::companions_for_projects(
Expand All @@ -97,3 +87,56 @@ pub async fn resolve(

Ok((installations, graph))
}

enum Pkgspec {
Req(PackageReq),
Latest(String),
}

impl Pkgspec {
fn project(&self) -> String {
match self {
Pkgspec::Req(req) => req.project.clone(),
Pkgspec::Latest(project) => project.clone(),
}
}

fn set_project(&mut self, project: String) {
match self {
Pkgspec::Req(req) => req.project = project,
Pkgspec::Latest(_) => *self = Pkgspec::Latest(project),
}
}

async fn constraint(&self, config: &Config) -> VersionRange {
match self {
Pkgspec::Req(req) => req.constraint.clone(),
Pkgspec::Latest(project) => match libpkgx::inventory::ls(project, config).await {
Ok(versions) if !versions.is_empty() => {
let vmax = versions.iter().max();
VersionRange::parse(&format!("={}", vmax.unwrap()))
}
_ => VersionRange::parse("*"),
}
.unwrap(),
}
}

async fn pkgreq(&self, config: &Config) -> PackageReq {
let project = self.project();
let constraint = self.constraint(config).await;
PackageReq {
project,
constraint,
}
}
}

fn parse_pkgspec(pkgspec: &str) -> Result<Pkgspec, Box<dyn std::error::Error>> {
if let Some(project) = pkgspec.strip_suffix("@latest") {
Ok(Pkgspec::Latest(project.to_string()))
} else {
let pkgspec = PackageReq::parse(pkgspec)?;
Ok(Pkgspec::Req(pkgspec))
}
}
2 changes: 1 addition & 1 deletion crates/cli/src/x.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ pub async fn exec(
);

env.insert(
"PKGX_VERSION".to_string(),
construct_platform_case_aware_env_key("PKGX_VERSION".to_string()),
env!("CARGO_PKG_VERSION").to_string(),
);

Expand Down
2 changes: 1 addition & 1 deletion crates/lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "libpkgx"
description = "Install and run `pkgx` packages"
authors = ["Max Howell <mxcl@me.com>", "Jacob Heider <jacob@pkgx.dev>"]
license = "Apache-2.0"
version = "0.5.0"
version = "0.6.0"
edition = "2021"
repository = "https://github.com/pkgxdev/pkgx"

Expand Down
10 changes: 5 additions & 5 deletions crates/lib/src/inventory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ impl Error for DownloadError {}

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

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

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

let (platform, arch) = host();
let url = Url::parse(&format!(
"{}/{}/{}/{}/versions.txt",
base_url, rq.project, platform, arch
base_url, project, platform, arch
))?;

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

if rq.project == "openssl.org" {
if project == "openssl.org" {
// Workaround: Remove specific version
let excluded_version = Version::parse("1.1.118")?;
versions.retain(|x| x != &excluded_version);
Expand Down
5 changes: 4 additions & 1 deletion crates/lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ pub mod env;
pub mod hydrate;
mod install;
pub mod install_multi;
mod inventory;
pub mod inventory;
mod pantry;
pub mod pantry_db;
pub mod platform_case_aware_env_key;
pub mod resolve;
pub mod sync;
pub mod types;
pub mod utils;

pub type Version = libsemverator::semver::Semver;
pub type VersionRange = libsemverator::range::Range;
Loading