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
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ jobs:
- run: pkgx +git
- run: pkgx +git --json
- run: pkgx +git --json=v1
- run: pkgx +git --json=v2
- run: pkgx git --version
- run: pkgx --silent +git
- run: pkgx --quiet +git
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ regex = "1.11.1"
indicatif = "0.17.9"
nix = { version = "0.29.0", features = ["process"] }
serde_json = "1.0.135"
serde = { version = "1.0", features = ["derive"] }
libpkgx = { version = "0.6.0", path = "../lib" }
console = { version = "0.15", default-features = false, features = [
"ansi-parsing",
Expand Down
19 changes: 11 additions & 8 deletions crates/cli/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub enum Mode {
pub struct Flags {
pub quiet: bool,
pub silent: bool,
pub json: bool,
pub json: Option<isize>,
pub version_n_continue: bool,
pub shebang: bool,
pub sync: bool,
Expand All @@ -30,12 +30,13 @@ pub fn parse() -> Args {
let mut args = Vec::new();
let mut silent: bool = false;
let mut quiet: bool = false;
let mut json: bool = false;
let mut json = None;
let mut find_program = false;
let mut collecting_args = false;
let mut version_n_continue = false;
let mut shebang = false;
let mut sync = false;
let json_latest_v: isize = 2;

for arg in std::env::args().skip(1) {
if collecting_args {
Expand All @@ -47,17 +48,19 @@ pub fn parse() -> Args {
collecting_args = true;
} else if arg.starts_with("--") {
match arg.as_str() {
"--shebang" => shebang = true,
"--json" => {
if !silent {
eprintln!(
"{} use --json=v1",
style("warning: --json is not stable").yellow()
"{} use --json={}",
style("warning: --json is not stable").yellow(),
json_latest_v
);
}
json = true
json = Some(2);
}
"--shebang" => shebang = true,
"--json=v1" => json = true,
"--json=v1" => json = Some(1),
"--json=v2" => json = Some(2),
"--silent" => silent = true,
"--help" => mode = Mode::Help,
"--version" => mode = Mode::Version,
Expand Down Expand Up @@ -98,7 +101,7 @@ pub fn parse() -> Args {
}
'h' => mode = Mode::Help,
's' => silent = true,
'j' => json = true,
'j' => json = Some(json_latest_v),
'v' => version_n_continue = true,
'!' => shebang = true,
'Q' => mode = Mode::Query,
Expand Down
92 changes: 74 additions & 18 deletions crates/cli/src/dump.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,73 @@
use std::collections::HashMap;
use std::{collections::HashMap, path::PathBuf, vec};

use libpkgx::{
env::expand_moustaches, pantry_db,
platform_case_aware_env_key::construct_platform_case_aware_env_key, types::Installation,
};
use serde::Serialize;
use serde_json::json;

pub fn dump(
conn: rusqlite::Connection,
installations: Vec<Installation>,
env: HashMap<String, Vec<String>>,
flags: &crate::args::Flags,
) -> Result<(), Box<dyn std::error::Error>> {
if !flags.json {
if let Some(v) = flags.json {
if v < 2 {
let env = libpkgx::env::map(&installations);
let mut runtime_env = HashMap::new();
for pkg in installations.clone() {
let pkg_runtime_env =
libpkgx::pantry_db::runtime_env_for_project(&pkg.pkg.project, &conn)?;
if !pkg_runtime_env.is_empty() {
runtime_env.insert(pkg.pkg.project, pkg_runtime_env);
}
}
let json = json!({
"pkgs": installations,
"env": env,
"runtime_env": runtime_env
});
println!("{}", json);
} else {
let mut pkgs: HashMap<String, JsonV2Pkg> = HashMap::new();
for installation in installations.clone() {
let env = libpkgx::env::map(&vec![installation.clone()]);
let project = installation.pkg.project.clone();

let mut runtime_env = libpkgx::pantry_db::runtime_env_for_project(&project, &conn)?;

for (installation_key, installation_value) in runtime_env.clone() {
let installation_value =
expand_moustaches(&installation_value, &installation, &installations);
runtime_env.insert(installation_key, installation_value);
}

let programs = pantry_db::programs_for_project(&project, &conn)?;
let companions = pantry_db::companions_for_projects(&[project.clone()], &conn)?
.iter()
.map(|c| c.to_string())
.collect::<Vec<String>>();

let pkg = JsonV2Pkg {
path: installation.path,
project,
version: installation.pkg.version,
env,
runtime_env,
programs,
companions,
};
pkgs.insert(pkg.project.clone(), pkg);
}

let json = json!({
"pkgs": pkgs, "env": libpkgx::env::map(&installations)
});
println!("{}", json);
}
} else {
let env = libpkgx::env::map(&installations);
let env = env
.iter()
.map(|(k, v)| {
Expand All @@ -29,21 +85,21 @@ pub fn dump(
value.replace(&format!(":${}", key), &format!("${{{}:+:${}}}", key, key))
);
}
} else {
let mut runtime_env = HashMap::new();
for pkg in installations.clone() {
let pkg_runtime_env =
libpkgx::pantry_db::runtime_env_for_project(&pkg.pkg.project, &conn)?;
if !pkg_runtime_env.is_empty() {
runtime_env.insert(pkg.pkg.project, pkg_runtime_env);
}
}
let json = json!({
"pkgs": installations,
"env": env,
"runtime_env": runtime_env
});
println!("{}", json);
}
Ok(())
}

#[derive(Serialize)]
struct JsonV2Pkg {
project: String,
version: libpkgx::Version,
#[serde(skip_serializing_if = "HashMap::is_empty")]
env: HashMap<String, Vec<String>>,
#[serde(skip_serializing_if = "HashMap::is_empty")]
runtime_env: HashMap<String, String>,
path: PathBuf,
#[serde(skip_serializing_if = "Vec::is_empty")]
programs: Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
companions: Vec<String>,
}
2 changes: 2 additions & 0 deletions crates/cli/src/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ flags:
-q, --quiet # suppress brief informational messages
-qq, --silent # no chat. no errors. just execute.
-v # print version and continue
--sync # sync first (note: rarely if ever needed)
-j,--json=v2 # output JSON (if sensible)

more:
$ OPEN https://docs.pkgx.sh
Expand Down
4 changes: 2 additions & 2 deletions crates/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,17 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
&mut spinner,
)
.await?;
let env = libpkgx::env::map(&installations);

if !args.is_empty() {
let env = libpkgx::env::map(&installations);
let (cmd, args, env) =
x::exec(find_program, args, installations, env, flags, conn, graph).await?;
spinner.finish_and_clear();
execve(cmd, args, env)?;
Ok(())
} else if !plus.is_empty() {
spinner.finish_and_clear();
dump::dump(conn, installations, env, &flags)?;
dump::dump(conn, installations, &flags)?;
Ok(())
} else if flags.version_n_continue || flags.sync {
Ok(())
Expand Down
13 changes: 13 additions & 0 deletions crates/lib/src/pantry_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,16 @@ pub fn companions_for_projects(
// Collect results into a Vec<PackageReq>, propagating errors
Ok(companions.collect::<Result<Vec<_>, _>>()?)
}

pub fn programs_for_project(
project: &String,
conn: &Connection,
) -> Result<Vec<String>, rusqlite::Error> {
let mut stmt = conn.prepare("SELECT program FROM provides WHERE project = ?1")?;
let mut rv = Vec::new();
let mut rows = stmt.query(params![project])?;
while let Some(row) = rows.next()? {
rv.push(row.get(0)?);
}
Ok(rv)
}
Loading