Make Windows update find PowerShell hosts
ci / test (push) Canceled after 0s
ci / fuzz-smoke (push) Canceled after 0s
ci / macos-client (macos-aarch64, macos-14) (push) Canceled after 0s
ci / macos-client (macos-x86_64, macos-13) (push) Canceled after 0s
ci / windows-client (push) Canceled after 0s
ci / package-release (linux-x86_64, ubuntu-latest, , , ) (push) Canceled after 0s
ci / package-release (macos-aarch64, macos-14, , , ) (push) Canceled after 0s
ci / package-release (macos-x86_64, macos-13, , , ) (push) Canceled after 0s
ci / package-release (windows-aarch64, windows-latest, aarch64, windows, aarch64-pc-windows-msvc) (push) Canceled after 0s
ci / package-release (windows-x86_64, windows-latest, , , ) (push) Canceled after 0s
ci / remote-bench (push) Canceled after 0s
ci / publish-gitea-release (push) Canceled after 0s

This commit is contained in:
DuProcess
2026-07-16 21:02:58 -04:00
parent 4dc57400f4
commit 729358ebb9
+87 -31
View File
@@ -4407,15 +4407,8 @@ fn latest_release_tag(repo: &str) -> Result<Option<String>> {
}
let latest_url = format!("{web}/releases/latest");
let output = if cfg!(windows) {
Command::new("powershell.exe")
.arg("-NoProfile")
.arg("-ExecutionPolicy")
.arg("Bypass")
.arg("-Command")
.arg(windows_effective_url_script(&latest_url))
.stdin(Stdio::null())
.output()
.with_context(|| format!("resolve latest release for {web}"))?
let script = windows_effective_url_script(&latest_url);
windows_powershell_output(&script, &format!("resolve latest release for {web}"))?
} else {
Command::new("curl")
.arg("-fsSL")
@@ -4449,17 +4442,8 @@ fn release_tag_download_url(repo: &str, tag: &str, artifact: &str) -> Option<Str
fn url_reachable(url: &str) -> Result<bool> {
let status = if cfg!(windows) {
Command::new("powershell.exe")
.arg("-NoProfile")
.arg("-ExecutionPolicy")
.arg("Bypass")
.arg("-Command")
.arg(windows_url_reachable_script(url))
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.with_context(|| format!("check {url}"))?
let script = windows_url_reachable_script(url);
windows_powershell_status(&script, &format!("check {url}"))?
} else {
Command::new("curl")
.arg("-fsIL")
@@ -4591,15 +4575,7 @@ fn run_update_installer(
binary_version,
);
let script = windows_deferred_update_script(std::process::id(), &script);
Command::new("powershell.exe")
.arg("-NoProfile")
.arg("-ExecutionPolicy")
.arg("Bypass")
.arg("-Command")
.arg(script)
.stdin(Stdio::null())
.spawn()
.context("start deferred dosh update installer")?;
windows_powershell_spawn(&script, "start deferred dosh update installer")?;
println!("dosh update started; the installer will run after this process exits");
return Ok(());
}
@@ -4790,6 +4766,77 @@ fn windows_deferred_update_script(parent_pid: u32, installer_script: &str) -> St
)
}
fn windows_powershell_command_candidates() -> &'static [&'static str] {
&["powershell.exe", "powershell", "pwsh.exe", "pwsh"]
}
fn windows_powershell_command(candidate: &str, script: &str) -> Command {
let mut command = Command::new(candidate);
command
.arg("-NoProfile")
.arg("-ExecutionPolicy")
.arg("Bypass")
.arg("-Command")
.arg(script)
.stdin(Stdio::null());
command
}
fn windows_powershell_output(script: &str, context: &str) -> Result<std::process::Output> {
let mut missing = Vec::new();
for candidate in windows_powershell_command_candidates() {
match windows_powershell_command(candidate, script).output() {
Ok(output) => return Ok(output),
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
missing.push(*candidate);
}
Err(err) => return Err(err).with_context(|| format!("{context} using {candidate}")),
}
}
Err(anyhow!(
"{context}: no PowerShell executable found; tried {}",
missing.join(", ")
))
}
fn windows_powershell_status(script: &str, context: &str) -> Result<std::process::ExitStatus> {
let mut missing = Vec::new();
for candidate in windows_powershell_command_candidates() {
match windows_powershell_command(candidate, script)
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
{
Ok(status) => return Ok(status),
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
missing.push(*candidate);
}
Err(err) => return Err(err).with_context(|| format!("{context} using {candidate}")),
}
}
Err(anyhow!(
"{context}: no PowerShell executable found; tried {}",
missing.join(", ")
))
}
fn windows_powershell_spawn(script: &str, context: &str) -> Result<Child> {
let mut missing = Vec::new();
for candidate in windows_powershell_command_candidates() {
match windows_powershell_command(candidate, script).spawn() {
Ok(child) => return Ok(child),
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
missing.push(*candidate);
}
Err(err) => return Err(err).with_context(|| format!("{context} using {candidate}")),
}
}
Err(anyhow!(
"{context}: no PowerShell executable found; tried {}",
missing.join(", ")
))
}
fn powershell_string(value: &str) -> String {
format!("'{}'", value.replace('\'', "''"))
}
@@ -10588,8 +10635,9 @@ mod tests {
update_binary_version_for_installer, update_installer_url, update_version_status,
upsert_managed_block, valid_forward_host, vscode_command_candidates, vscode_safe_alias,
wake_repaint_retry_deadline, windows_command_word, windows_deferred_update_script,
windows_effective_url_script, windows_mode_from_readonly, windows_readonly_from_mode,
windows_update_script, windows_url_reachable_script, windows_vt_output_mode,
windows_effective_url_script, windows_mode_from_readonly,
windows_powershell_command_candidates, windows_readonly_from_mode, windows_update_script,
windows_url_reachable_script, windows_vt_output_mode,
};
use dosh::config::{ClientConfig, CommandExtension, HostConfig};
use dosh::native::EnvVar;
@@ -12978,6 +13026,14 @@ mod tests {
assert!(!reachable.contains("curl"));
}
#[test]
fn windows_update_tries_classic_and_core_powershell_hosts() {
assert_eq!(
windows_powershell_command_candidates(),
&["powershell.exe", "powershell", "pwsh.exe", "pwsh"]
);
}
#[test]
fn update_uses_local_tag_when_release_latest_is_older() {
assert_eq!(