windows: Implement shell environment loading for git operations (#39019)

Fixes the "failed to get working directory environment for repository"
error on Windows by implementing proper shell environment variable
capture.

Release Notes:

- Fixed failed to get working directory environment for repository

---------

Signed-off-by: Xiaobo Liu <cppcoffee@gmail.com>
This commit is contained in:
Xiaobo Liu
2025-09-27 17:10:06 +02:00
committed by GitHub
parent 72948e14ee
commit 682cf023ca
2 changed files with 61 additions and 3 deletions
+20 -3
View File
@@ -227,14 +227,31 @@ async fn load_shell_environment(
#[cfg(all(target_os = "windows", not(any(test, feature = "test-support"))))]
async fn load_shell_environment(
_dir: &Path,
dir: &Path,
_load_direnv: &DirenvSettings,
) -> (
Option<HashMap<String, String>>,
Option<EnvironmentErrorMessage>,
) {
// TODO the current code works with Unix $SHELL only, implement environment loading on windows
(None, None)
use util::shell_env;
let envs = match shell_env::capture(dir).await {
Ok(envs) => envs,
Err(err) => {
util::log_err(&err);
return (
None,
Some(EnvironmentErrorMessage(format!(
"Failed to load environment variables: {}",
err
))),
);
}
};
// Note: direnv is not available on Windows, so we skip direnv processing
// and just return the shell environment
(Some(envs), None)
}
#[cfg(not(any(target_os = "windows", test, feature = "test-support")))]
+41
View File
@@ -99,6 +99,47 @@ async fn spawn_and_read_fd(
Ok((buffer, process.output().await?))
}
/// Capture all environment variables from the shell on Windows.
#[cfg(windows)]
pub async fn capture(directory: &std::path::Path) -> Result<collections::HashMap<String, String>> {
use std::process::Stdio;
let zed_path =
std::env::current_exe().context("Failed to determine current zed executable path.")?;
// Use PowerShell to get environment variables in the directory context
let mut command = std::process::Command::new(crate::get_windows_system_shell());
command
.arg("-NonInteractive")
.arg("-NoProfile")
.arg("-Command")
.arg(format!(
"Set-Location '{}'; & '{}' --printenv",
directory.display(),
zed_path.display()
))
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::piped());
let output = smol::process::Command::from(command).output().await?;
anyhow::ensure!(
output.status.success(),
"PowerShell command failed with {}. stdout: {:?}, stderr: {:?}",
output.status,
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr),
);
let env_output = String::from_utf8_lossy(&output.stdout);
// Parse the JSON output from zed --printenv
let env_map: collections::HashMap<String, String> = serde_json::from_str(&env_output)
.with_context(|| "Failed to deserialize environment variables from json")?;
Ok(env_map)
}
pub fn print_env() {
let env_vars: HashMap<String, String> = std::env::vars().collect();
let json = serde_json::to_string_pretty(&env_vars).unwrap_or_else(|err| {