Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add --json-extended option to mise env #3389

Merged
merged 2 commits into from
Dec 7, 2024
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
4 changes: 4 additions & 0 deletions docs/cli/env.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
23 changes: 23 additions & 0 deletions e2e/cli/test_env_json
Original file line number Diff line number Diff line change
@@ -1,9 +1,32 @@
#!/usr/bin/env bash
require_cmd jq

cat >/tmp/.env-test <<EOF
AAA=bbb
EOF

cat >.mise.toml <<EOF
[tools]
deno = "2"

[env]
_.file = '/tmp/.env-test'
FOO = "bar"
EOF

assert "mise env --json dummy@latest | jq -r .FOO" "bar"

assert "mise env --json-extended dummy@latest | jq -r '.FOO.value'" "bar"
assert_contains "mise env --json-extended dummy@latest | jq -r '.FOO.source'" ".mise.toml"

assert "mise env --json-extended dummy@latest | jq -r '.AAA.value'" "bbb"
assert "mise env --json-extended dummy@latest | jq -r '.AAA.source'" "/tmp/.env-test"

mise i
assert "mise env --json-extended | jq -r '.DENO_INSTALL_ROOT.tool'" "deno"
assert_contains "mise env --json-extended | jq -r '.DENO_INSTALL_ROOT.value'" ".deno"
assert_contains "mise env --json-extended | jq -r '.DENO_INSTALL_ROOT.source'" ".mise.toml"

assert_contains "mise env --json-extended go@1.23.4 | jq -r '.GOBIN.value'" "go/1.23.4/bin"
assert_contains "mise env --json-extended go@1.23.4 | jq -r '.GOBIN.tool'" "go"
assert_contains "mise env --json-extended go@1.23.4 | jq -r '.GOBIN.source'" ""
20 changes: 10 additions & 10 deletions e2e/cli/test_settings_ls
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions mise.usage.kdl
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ use this if you have `mise activate` in your shell rc file."
$ execx($(mise env -s xonsh))
"#
flag "-J --json" help="Output in JSON format"
flag "--json-extended" help="Output in JSON format with additional information (source, tool)"
flag "-D --dotenv" help="Output in dotenv format"
flag "-s --shell" help="Shell type to generate environment variables for" {
arg "<SHELL>" {
Expand Down
3 changes: 1 addition & 2 deletions src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
62 changes: 62 additions & 0 deletions src/cli/env.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use eyre::Result;
use std::collections::BTreeMap;

use crate::cli::args::ToolArg;
use crate::config::Config;
Expand All @@ -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,
Expand All @@ -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 {
Expand All @@ -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)| {
hverlin marked this conversation as resolved.
Show resolved Hide resolved
res.insert(
k.to_string(),
BTreeMap::from([
("value", v.0.to_string()),
("source", v.1.to_string_lossy().into_owned()),
]),
);
});

let tool_map: BTreeMap<String, String> = 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);
Expand Down
2 changes: 1 addition & 1 deletion src/cli/settings/ls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions src/config/config_file/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 1 addition & 2 deletions src/github.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
21 changes: 15 additions & 6 deletions src/toolset/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<BTreeMap<String, String>> {
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::<Vec<(String, String, String)>>()
}
pub fn env(&self, config: &Config) -> Result<BTreeMap<String, String>> {
time!("env start");
let entries = self
.env_from_tools(config)
.into_iter()
.map(|(k, v, _)| (k, v))
.collect::<Vec<(String, String)>>();
let add_paths = entries
.iter()
Expand Down
7 changes: 7 additions & 0 deletions xtasks/fig/src/mise.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Loading