From 751f436aae6b2ab0fddf0763ab205846a4bbd154 Mon Sep 17 00:00:00 2001 From: hverlin Date: Sat, 7 Dec 2024 07:48:43 +0100 Subject: [PATCH 1/2] feat: Add --json-extended option to mise env --- docs/cli/env.md | 4 +++ e2e/cli/test_env_json | 23 +++++++++++++ mise.usage.kdl | 1 + src/backend/mod.rs | 3 +- src/cli/env.rs | 62 +++++++++++++++++++++++++++++++++++ src/cli/settings/ls.rs | 2 +- src/config/config_file/mod.rs | 3 +- src/github.rs | 3 +- src/toolset/mod.rs | 21 ++++++++---- xtasks/fig/src/mise.ts | 7 ++++ 10 files changed, 116 insertions(+), 13 deletions(-) diff --git a/docs/cli/env.md b/docs/cli/env.md index 441a8d52d8..2bd6875262 100644 --- a/docs/cli/env.md +++ b/docs/cli/env.md @@ -21,6 +21,10 @@ Tool(s) to use Output in JSON format +### `--json-extended` + +Output in JSON format with additional information (source, tool) + ### `-D --dotenv` Output in dotenv format diff --git a/e2e/cli/test_env_json b/e2e/cli/test_env_json index a298cc38a1..3a9bae3d99 100644 --- a/e2e/cli/test_env_json +++ b/e2e/cli/test_env_json @@ -1,9 +1,32 @@ #!/usr/bin/env bash require_cmd jq +cat >/tmp/.env-test <.mise.toml <" { diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 1f59901295..c27baff48a 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -21,8 +21,7 @@ use crate::ui::progress_report::SingleReport; use crate::{dirs, env, file, hash, lock_file, plugins, versions_host}; use backend_type::BackendType; use console::style; -use eyre::Result; -use eyre::{bail, eyre, WrapErr}; +use eyre::{bail, eyre, Result, WrapErr}; use indexmap::IndexSet; use itertools::Itertools; use once_cell::sync::Lazy; diff --git a/src/cli/env.rs b/src/cli/env.rs index 0834897ca6..71df187115 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -1,4 +1,5 @@ use eyre::Result; +use std::collections::BTreeMap; use crate::cli::args::ToolArg; use crate::config::Config; @@ -20,6 +21,10 @@ pub struct Env { #[clap(long, short = 'J', overrides_with = "shell")] json: bool, + /// Output in JSON format with additional information (source, tool) + #[clap(long, overrides_with = "shell")] + json_extended: bool, + /// Output in dotenv format #[clap(long, short = 'D', overrides_with = "shell")] dotenv: bool, @@ -38,6 +43,8 @@ impl Env { if self.json { self.output_json(&config, ts) + } else if self.json_extended { + self.output_extended_json(&config, ts) } else if self.dotenv { self.output_dotenv(&config, ts) } else { @@ -51,6 +58,61 @@ impl Env { Ok(()) } + fn output_extended_json(&self, config: &Config, ts: Toolset) -> Result<()> { + let mut res = BTreeMap::new(); + + ts.env_with_path(config)?.iter().for_each(|(k, v)| { + res.insert(k.to_string(), BTreeMap::from([("value", v.to_string())])); + }); + + config.env_with_sources()?.iter().for_each(|(k, v)| { + res.insert( + k.to_string(), + BTreeMap::from([ + ("value", v.0.to_string()), + ("source", v.1.to_string_lossy().into_owned()), + ]), + ); + }); + + let tool_map: BTreeMap = ts + .list_all_versions()? + .into_iter() + .map(|(b, tv)| { + ( + b.id().into(), + tv.request + .source() + .path() + .map(|p| p.to_string_lossy().into_owned()) + .unwrap_or_else(|| "".to_string()), + ) + }) + .collect(); + + ts.env_from_tools(config) + .iter() + .for_each(|(name, value, tool_id)| { + res.insert( + name.to_string(), + BTreeMap::from([ + ("value", value.to_string()), + ("tool", tool_id.to_string()), + ( + "source", + tool_map + .get(tool_id) + .cloned() + .unwrap_or_else(|| "unknown_source".to_string()), + ), + ]), + ); + }); + + miseprintln!("{}", serde_json::to_string_pretty(&res)?); + Ok(()) + } + fn output_shell(&self, config: &Config, ts: Toolset) -> Result<()> { let default_shell = get_shell(Some(ShellType::Bash)).unwrap(); let shell = get_shell(self.shell).unwrap_or(default_shell); diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index 9ab827698e..7408e605ad 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -116,7 +116,7 @@ impl SettingsLs { toml_value_to_json_value(row.toml_value), ); if let Some(source) = row.source { - entry.insert("source".to_string(), display_path(&source).into()); + entry.insert("source".to_string(), source.to_string_lossy().into()); } if let Some((key, subkey)) = row.key.split_once('.') { let subtable = table diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 08de39db86..c2e30dd4ce 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -5,8 +5,7 @@ use std::hash::Hash; use std::path::{Path, PathBuf}; use std::sync::{Mutex, Once}; -use eyre::eyre; -use eyre::Result; +use eyre::{eyre, Result}; use idiomatic_version::IdiomaticVersionFile; use indexmap::IndexMap; use once_cell::sync::Lazy; diff --git a/src/github.rs b/src/github.rs index a63b41a349..bf1e1a9aac 100644 --- a/src/github.rs +++ b/src/github.rs @@ -7,8 +7,7 @@ use reqwest::header::HeaderMap; use serde_derive::{Deserialize, Serialize}; use std::collections::HashMap; use std::path::PathBuf; -use std::sync::RwLock; -use std::sync::RwLockReadGuard; +use std::sync::{RwLock, RwLockReadGuard}; use xx::regex; #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index e7dc26e285..ed0b18aba1 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -519,20 +519,29 @@ impl Toolset { env.insert(PATH_KEY.to_string(), path_env.to_string()); Ok(env) } - pub fn env(&self, config: &Config) -> Result> { - time!("env start"); - let entries = self - .list_current_installed_versions() + pub fn env_from_tools(&self, config: &Config) -> Vec<(String, String, String)> { + self.list_current_installed_versions() .into_par_iter() .filter(|(_, tv)| !matches!(tv.request, ToolRequest::System { .. })) .flat_map(|(p, tv)| match p.exec_env(config, self, &tv) { - Ok(env) => env.into_iter().collect(), + Ok(env) => env + .into_iter() + .map(|(k, v)| (k, v, p.id().into())) + .collect(), Err(e) => { warn!("Error running exec-env: {:#}", e); Vec::new() } }) - .filter(|(k, _)| k.to_uppercase() != "PATH") + .filter(|(_, k, _)| k.to_uppercase() != "PATH") + .collect::>() + } + pub fn env(&self, config: &Config) -> Result> { + time!("env start"); + let entries = self + .env_from_tools(config) + .into_iter() + .map(|(k, v, _)| (k, v)) .collect::>(); let add_paths = entries .iter() diff --git a/xtasks/fig/src/mise.ts b/xtasks/fig/src/mise.ts index 8befe4ad44..7f4506c13d 100644 --- a/xtasks/fig/src/mise.ts +++ b/xtasks/fig/src/mise.ts @@ -888,6 +888,13 @@ const completionSpec: Fig.Spec = { "description": "Output in JSON format", "isRepeatable": false }, + { + "name": [ + "--json-extended" + ], + "description": "Output in JSON format with additional information (source, tool)", + "isRepeatable": false + }, { "name": [ "-D", From 22e3b42f8e38b305de963b4a4afd8bf63167ea72 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 7 Dec 2024 06:31:00 -0600 Subject: [PATCH 2/2] test: fix settings_ls --- e2e/cli/test_settings_ls | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/e2e/cli/test_settings_ls b/e2e/cli/test_settings_ls index f328893139..f474e5c7eb 100644 --- a/e2e/cli/test_settings_ls +++ b/e2e/cli/test_settings_ls @@ -17,19 +17,19 @@ assert_contains "mise settings --json" '{ assert_contains "mise settings --toml" 'all_compile = false disable_backends = ["rust", "java"]' -assert_contains "mise settings --json-extended" '{ - "all_compile": { - "source": "~/workdir/mise.toml", - "value": false +assert_contains "mise settings --json-extended" "{ + \"all_compile\": { + \"source\": \"$HOME/workdir/mise.toml\", + \"value\": false }, - "disable_backends": { - "source": "~/workdir/mise.toml", - "value": [ - "rust", - "java" + \"disable_backends\": { + \"source\": \"$HOME/workdir/mise.toml\", + \"value\": [ + \"rust\", + \"java\" ] } -}' +}" assert_contains "mise settings ls -T" "all_compile = false" echo "settings.python.venv_auto_create = false" >>mise.toml