Skip to content

Commit ee0f381

Browse files
committed
feat: shell support custom env file via cli
1 parent 513fd00 commit ee0f381

File tree

2 files changed

+60
-54
lines changed

2 files changed

+60
-54
lines changed

src/command/shell.rs

Lines changed: 33 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use dialoguer::{Select, theme::ColorfulTheme};
1414
use semver::VersionReq;
1515

1616
use crate::{
17-
command::utils::InstallOptions,
17+
command::utils::{InstallOptions, KeyValuePair},
1818
consts::GOUP_GO_VERSION,
1919
dir::Dir,
2020
registries::{go_index::GoIndex, registry::Registry},
@@ -36,6 +36,9 @@ pub struct Shell {
3636
/// skip autodetect go.work/go.mod.
3737
#[arg(long)]
3838
skip_autodetect: bool,
39+
/// custom env vars
40+
#[arg(short, long)]
41+
envs: Vec<KeyValuePair>,
3942
/// env file path
4043
#[arg(short, long)]
4144
filename: Option<PathBuf>,
@@ -45,22 +48,26 @@ pub struct Shell {
4548

4649
impl Run for Shell {
4750
fn run(&self) -> Result<(), anyhow::Error> {
48-
let envs = if let Some(ref filename) = self.filename {
51+
let filter_keys = ["GOROOT", GOUP_GO_VERSION];
52+
53+
let mut envs = if let Some(ref filename) = self.filename {
4954
dotenvy::from_filename_iter(filename)?
5055
.filter_map(|v| {
5156
v.ok().and_then(|(k, v)| {
5257
// 过滤 GOROOT 和 GOUP_GO_VERSION
53-
if k == "GOROOT" || k == GOUP_GO_VERSION {
54-
None
55-
} else {
56-
Some((k, v))
57-
}
58+
(!filter_keys.contains(&k.as_str())).then_some((k, v))
5859
})
5960
})
6061
.collect()
6162
} else {
6263
HashMap::new()
6364
};
65+
// 合并命令行的 -e KEY=VALUE
66+
for kv in &self.envs {
67+
if !filter_keys.contains(&kv.key.as_str()) {
68+
envs.insert(kv.key.clone(), kv.value.clone());
69+
}
70+
}
6471

6572
let local_versions = Version::list_go_version()?;
6673
let target_go_version = self.get_target_version(&local_versions)?;
@@ -88,16 +95,27 @@ impl Run for Shell {
8895
});
8996
let parent_env_path = env::var("PATH").unwrap_or_default();
9097

91-
let extra_path = envs.get("path").map(|v| v.as_ref());
9298
let child_env_go_root = go_root_path.to_string_lossy();
9399
let child_go_root_bin = go_root_bin_path.to_string_lossy();
94-
let child_env_path = Self::merger_env_path_as_child_path(
95-
&parent_env_path,
96-
extra_path,
97-
parent_go_root_bin.as_deref(),
98-
&child_go_root_bin,
99-
env_separator,
100-
);
100+
let child_env_path = {
101+
let mut seen = HashSet::new();
102+
envs.get("path")
103+
.map(|v| v.split(env_separator))
104+
.into_iter()
105+
.flatten()
106+
.chain(std::iter::once(child_go_root_bin.as_ref()))
107+
.chain(parent_env_path.split(env_separator).filter(|v| {
108+
if let Some(parent_bin) = parent_go_root_bin.as_deref()
109+
&& *v == parent_bin
110+
{
111+
return false;
112+
}
113+
true
114+
}))
115+
.filter(|v| seen.insert(*v)) // 去重,保持顺序
116+
.collect::<Vec<_>>()
117+
.join(env_separator)
118+
};
101119

102120
log::info!("Enter new shell session with Go {target_go_version}");
103121
let mut command = Command::new(shell.to_string());
@@ -126,45 +144,6 @@ impl Run for Shell {
126144
}
127145

128146
impl Shell {
129-
fn merger_env_path_as_child_path(
130-
parent_env_path: &str,
131-
extra_path: Option<&str>,
132-
parent_go_root_bin: Option<&str>,
133-
child_go_root_bin: &str,
134-
env_separator: &str,
135-
) -> String {
136-
// parent_env_path
137-
// .split(env_separator)
138-
// .filter(|v| {
139-
// if let Some(parent_bin) = parent_go_root_bin
140-
// && *v == parent_bin
141-
// {
142-
// return false;
143-
// }
144-
// true
145-
// })
146-
// .chain(std::iter::once(child_go_root_bin))
147-
// .collect::<Vec<_>>()
148-
// .join(env_separator)
149-
let mut seen = HashSet::new();
150-
extra_path
151-
.map(|v| v.split(env_separator))
152-
.into_iter()
153-
.flatten()
154-
.chain(std::iter::once(child_go_root_bin))
155-
.chain(parent_env_path.split(env_separator).filter(|v| {
156-
if let Some(parent_bin) = parent_go_root_bin
157-
&& *v == parent_bin
158-
{
159-
return false;
160-
}
161-
true
162-
}))
163-
.filter(|v| seen.insert(*v)) // 去重,保持顺序
164-
.collect::<Vec<_>>()
165-
.join(env_separator)
166-
}
167-
168147
fn get_target_version(&self, local_versions: &[Version]) -> Result<String, anyhow::Error> {
169148
if let Some(version) = &self.version {
170149
// 指定了版本号,直接使用该版本

src/command/utils.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::str::FromStr;
2+
13
use clap::Args;
24

35
use crate::{consts, registries::registry_index::RegistryIndexType};
@@ -16,3 +18,28 @@ pub struct InstallOptions {
1618
#[arg(long, default_value_t = consts::GO_REGISTRY.to_owned(), env = consts::GOUP_GO_REGISTRY)]
1719
pub registry: String,
1820
}
21+
22+
#[derive(Debug, Clone, PartialEq)]
23+
pub struct KeyValuePair {
24+
pub key: String,
25+
pub value: String,
26+
}
27+
28+
impl FromStr for KeyValuePair {
29+
type Err = anyhow::Error;
30+
31+
fn from_str(s: &str) -> Result<Self, Self::Err> {
32+
let mut parts = s.splitn(2, '=');
33+
let k = parts
34+
.next()
35+
.filter(|v| !v.is_empty())
36+
.ok_or_else(|| anyhow::anyhow!("expected KEY=VALUE, empty key, got `{}`", s))?;
37+
let v = parts
38+
.next()
39+
.ok_or_else(|| anyhow::anyhow!("expected KEY=VALUE, got `{}`", s))?;
40+
Ok(KeyValuePair {
41+
key: k.to_string(),
42+
value: v.to_string(),
43+
})
44+
}
45+
}

0 commit comments

Comments
 (0)