From 2f0399a214ca0d026387a0aa6796c1fcd53df23d Mon Sep 17 00:00:00 2001 From: Yue Fei Date: Sun, 22 Sep 2024 08:53:15 +0800 Subject: [PATCH] replace `winreg` dependency --- Cargo.lock | 37 +++-- Cargo.toml | 3 +- src/cli/self_update/windows.rs | 279 +++++++++++++-------------------- tests/suite/cli_paths.rs | 49 +++--- tests/suite/cli_self_upd.rs | 8 +- 5 files changed, 164 insertions(+), 212 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 631a36efae..19b52117c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1984,7 +1984,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "windows-registry", + "windows-registry 0.2.0", ] [[package]] @@ -2184,8 +2184,9 @@ dependencies = [ "url", "wait-timeout", "walkdir", + "windows-registry 0.3.0", + "windows-result", "windows-sys 0.59.0", - "winreg", "xz2", "zstd", ] @@ -3182,7 +3183,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" dependencies = [ "windows-result", - "windows-strings", + "windows-strings 0.1.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-registry" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bafa604f2104cf5ae2cc2db1dee84b7e6a5d11b05f737b60def0ffdc398cbc0a" +dependencies = [ + "windows-result", + "windows-strings 0.2.0", "windows-targets 0.52.6", ] @@ -3205,6 +3217,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-strings" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978d65aedf914c664c510d9de43c8fd85ca745eaff1ed53edf409b479e441663" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -3362,16 +3383,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "winreg" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" -dependencies = [ - "cfg-if 1.0.0", - "windows-sys 0.48.0", -] - [[package]] name = "xattr" version = "1.3.1" diff --git a/Cargo.toml b/Cargo.toml index a8fb69a92b..9743ed11a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -95,7 +95,8 @@ zstd = "0.13" [target."cfg(windows)".dependencies] cc = "1" -winreg = "0.52" +windows-registry = "0.3.0" +windows-result = "0.2.0" [target."cfg(windows)".dependencies.windows-sys] features = [ diff --git a/src/cli/self_update/windows.rs b/src/cli/self_update/windows.rs index 7c1f37ede0..45a44062bb 100644 --- a/src/cli/self_update/windows.rs +++ b/src/cli/self_update/windows.rs @@ -1,10 +1,8 @@ use std::env::{consts::EXE_SUFFIX, split_paths}; use std::ffi::{OsStr, OsString}; use std::fmt; -#[cfg(any(test, feature = "test"))] -use std::io; use std::io::Write; -use std::os::windows::ffi::{OsStrExt, OsStringExt}; +use std::os::windows::ffi::OsStrExt; use std::path::Path; use std::process::Command; use std::sync::{Arc, Mutex}; @@ -13,10 +11,11 @@ use std::sync::{LockResult, MutexGuard}; use anyhow::{anyhow, Context, Result}; use tracing::{info, warn}; -use winreg::enums::{RegType, HKEY_CURRENT_USER, KEY_READ, KEY_WRITE}; #[cfg(any(test, feature = "test"))] -use winreg::types::{FromRegValue, ToRegValue}; -use winreg::{RegKey, RegValue}; +use windows_registry::Value; +use windows_registry::{Key, CURRENT_USER, HSTRING}; +use windows_result::HRESULT; +use windows_sys::Win32::Foundation::{ERROR_FILE_NOT_FOUND, ERROR_INVALID_DATA}; use super::super::errors::*; use super::common; @@ -465,7 +464,7 @@ pub(crate) fn do_add_to_path(process: &Process) -> Result<()> { do_add_to_programs(process) } -fn _apply_new_path(new_path: Option>) -> Result<()> { +fn _apply_new_path(new_path: Option) -> Result<()> { use std::ptr; use windows_sys::Win32::Foundation::*; use windows_sys::Win32::UI::WindowsAndMessaging::{ @@ -477,17 +476,12 @@ fn _apply_new_path(new_path: Option>) -> Result<()> { None => return Ok(()), // No need to set the path }; - let root = RegKey::predef(HKEY_CURRENT_USER); - let environment = root.open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)?; + let environment = CURRENT_USER.create("Environment")?; if new_path.is_empty() { - environment.delete_value("PATH")?; + environment.remove_value("PATH")?; } else { - let reg_value = RegValue { - bytes: to_winreg_bytes(new_path), - vtype: RegType::REG_EXPAND_SZ, - }; - environment.set_raw_value("PATH", ®_value)?; + environment.set_expand_hstring("PATH", &new_path)?; } // Tell other processes to update their environment @@ -510,55 +504,49 @@ fn _apply_new_path(new_path: Option>) -> Result<()> { // Get the windows PATH variable out of the registry as a String. If // this returns None then the PATH variable is not a string and we // should not mess with it. -fn get_windows_path_var() -> Result>> { - use std::io; - - let root = RegKey::predef(HKEY_CURRENT_USER); - let environment = root - .open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE) +fn get_windows_path_var() -> Result> { + let environment = CURRENT_USER + .create("Environment") .context("Failed opening Environment key")?; - let reg_value = environment.get_raw_value("PATH"); + let reg_value = environment.get_hstring("PATH"); match reg_value { - Ok(val) => { - if let Some(s) = from_winreg_value(&val) { - Ok(Some(s)) - } else { - warn!( - "the registry key HKEY_CURRENT_USER\\Environment\\PATH is not a string. \ - Not modifying the PATH variable" - ); - Ok(None) - } + Ok(val) => Ok(Some(val)), + Err(e) if e.code() == HRESULT::from_win32(ERROR_INVALID_DATA) => { + warn!( + "the registry key HKEY_CURRENT_USER\\Environment\\PATH is not a string. \ + Not modifying the PATH variable" + ); + Ok(None) } - Err(ref e) if e.kind() == io::ErrorKind::NotFound => Ok(Some(Vec::new())), + Err(e) if e.code() == HRESULT::from_win32(ERROR_FILE_NOT_FOUND) => Ok(Some(HSTRING::new())), Err(e) => Err(e).context(CLIError::WindowsUninstallMadness), } } // Returns None if the existing old_path does not need changing, otherwise // prepends the path_str to old_path, handling empty old_path appropriately. -fn _add_to_path(old_path: Vec, path_str: Vec) -> Option> { +fn _add_to_path(old_path: HSTRING, path_str: HSTRING) -> Option { if old_path.is_empty() { Some(path_str) } else if old_path .windows(path_str.len()) - .any(|path| path == path_str) + .any(|path| *path == *path_str) { None } else { - let mut new_path = path_str; - new_path.push(b';' as u16); - new_path.extend_from_slice(&old_path); - Some(new_path) + let mut new_path = path_str.to_os_string(); + new_path.push(";"); + new_path.push(old_path.to_os_string()); + Some(HSTRING::from(new_path)) } } // Returns None if the existing old_path does not need changing -fn _remove_from_path(old_path: Vec, path_str: Vec) -> Option> { +fn _remove_from_path(old_path: HSTRING, path_str: HSTRING) -> Option { let idx = old_path .windows(path_str.len()) - .position(|path| path == path_str)?; + .position(|path| *path == *path_str)?; // If there's a trailing semicolon (likely, since we probably added one // during install), include that in the substring to remove. We don't search // for that to find the string, because if it's the last string in the path, @@ -575,18 +563,17 @@ fn _remove_from_path(old_path: Vec, path_str: Vec) -> Option> if new_path.last() == Some(&(b';' as u16)) { new_path.pop(); } - Some(new_path) + Some(HSTRING::from_wide(&new_path)) } -fn _with_path_cargo_home_bin(f: F, process: &Process) -> Result>> +fn _with_path_cargo_home_bin(f: F, process: &Process) -> Result> where - F: FnOnce(Vec, Vec) -> Option>, + F: FnOnce(HSTRING, HSTRING) -> Option, { let windows_path = get_windows_path_var()?; let mut path_str = process.cargo_home()?; path_str.push("bin"); - Ok(windows_path - .and_then(|old_path| f(old_path, OsString::from(path_str).encode_wide().collect()))) + Ok(windows_path.and_then(|old_path| f(old_path, HSTRING::from(path_str.as_path())))) } pub(crate) fn do_remove_from_path(process: &Process) -> Result<()> { @@ -597,16 +584,15 @@ pub(crate) fn do_remove_from_path(process: &Process) -> Result<()> { const RUSTUP_UNINSTALL_ENTRY: &str = r"Software\Microsoft\Windows\CurrentVersion\Uninstall\Rustup"; -fn rustup_uninstall_reg_key() -> Result { - Ok(RegKey::predef(HKEY_CURRENT_USER) - .create_subkey(RUSTUP_UNINSTALL_ENTRY) - .context("Failed creating uninstall key")? - .0) +fn rustup_uninstall_reg_key() -> Result { + CURRENT_USER + .create(RUSTUP_UNINSTALL_ENTRY) + .context("Failed creating uninstall key") } pub(crate) fn do_update_programs_display_version(version: &str) -> Result<()> { rustup_uninstall_reg_key()? - .set_value("DisplayVersion", &version) + .set_string("DisplayVersion", version) .context("Failed to set `DisplayVersion`") } @@ -616,11 +602,9 @@ pub(crate) fn do_add_to_programs(process: &Process) -> Result<()> { let key = rustup_uninstall_reg_key()?; // Don't overwrite registry if Rustup is already installed - let prev = key - .get_raw_value("UninstallString") - .map(|val| from_winreg_value(&val)); - if let Ok(Some(s)) = prev { - let mut path = PathBuf::from(OsString::from_wide(&s)); + let prev = key.get_hstring("UninstallString"); + if let Ok(s) = prev { + let mut path = PathBuf::from(s.to_os_string()); path.pop(); if path.exists() { return Ok(()); @@ -633,14 +617,9 @@ pub(crate) fn do_add_to_programs(process: &Process) -> Result<()> { uninstall_cmd.push(path); uninstall_cmd.push("\" self uninstall"); - let reg_value = RegValue { - bytes: to_winreg_bytes(uninstall_cmd.encode_wide().collect()), - vtype: RegType::REG_SZ, - }; - - key.set_raw_value("UninstallString", ®_value) + key.set_hstring("UninstallString", &HSTRING::from(uninstall_cmd)) .context("Failed to set `UninstallString`")?; - key.set_value("DisplayName", &"Rustup: the Rust toolchain installer") + key.set_string("DisplayName", "Rustup: the Rust toolchain installer") .context("Failed to set `DisplayName`")?; do_update_programs_display_version(env!("CARGO_PKG_VERSION"))?; @@ -648,42 +627,13 @@ pub(crate) fn do_add_to_programs(process: &Process) -> Result<()> { } pub(crate) fn do_remove_from_programs() -> Result<()> { - match RegKey::predef(HKEY_CURRENT_USER).delete_subkey_all(RUSTUP_UNINSTALL_ENTRY) { + match CURRENT_USER.remove_tree(RUSTUP_UNINSTALL_ENTRY) { Ok(()) => Ok(()), - Err(ref e) if e.kind() == std::io::ErrorKind::NotFound => Ok(()), + Err(e) if e.code() == HRESULT::from_win32(ERROR_FILE_NOT_FOUND) => Ok(()), Err(e) => Err(anyhow!(e)), } } -/// Convert a vector UCS-2 chars to a null-terminated UCS-2 string in bytes -pub(crate) fn to_winreg_bytes(mut v: Vec) -> Vec { - v.push(0); - unsafe { std::slice::from_raw_parts(v.as_ptr().cast::(), v.len() * 2).to_vec() } -} - -/// This is used to decode the value of HKCU\Environment\PATH. If that key is -/// not REG_SZ | REG_EXPAND_SZ then this returns None. The winreg library itself -/// does a lossy unicode conversion. -pub(crate) fn from_winreg_value(val: &winreg::RegValue) -> Option> { - use std::slice; - - match val.vtype { - RegType::REG_SZ | RegType::REG_EXPAND_SZ => { - // Copied from winreg - let mut words = unsafe { - #[allow(clippy::cast_ptr_alignment)] - slice::from_raw_parts(val.bytes.as_ptr().cast::(), val.bytes.len() / 2) - .to_owned() - }; - while words.last() == Some(&0) { - words.pop(); - } - Some(words) - } - _ => None, - } -} - pub(crate) fn run_update(setup_path: &Path) -> Result { Command::new(setup_path) .arg("--self-replace") @@ -813,7 +763,7 @@ pub(crate) fn delete_rustup_and_cargo_home(process: &Process) -> Result<()> { } #[cfg(any(test, feature = "test"))] -pub fn get_path() -> io::Result> { +pub fn get_path() -> Result> { USER_PATH.get() } @@ -821,12 +771,12 @@ pub fn get_path() -> io::Result> { pub struct RegistryGuard<'a> { _locked: LockResult>, id: &'static RegistryValueId, - prev: Option, + prev: Option, } #[cfg(any(test, feature = "test"))] impl<'a> RegistryGuard<'a> { - pub fn new(id: &'static RegistryValueId) -> io::Result { + pub fn new(id: &'static RegistryValueId) -> Result { Ok(Self { _locked: REGISTRY_LOCK.lock(), id, @@ -859,50 +809,48 @@ pub struct RegistryValueId { #[cfg(any(test, feature = "test"))] impl RegistryValueId { - pub fn get_value(&self) -> io::Result> { - self.get()?.map(|v| T::from_reg_value(&v)).transpose() + pub fn get_value(&self) -> Result> { + self.get() } - fn get(&self) -> io::Result> { - let sub_key = RegKey::predef(HKEY_CURRENT_USER) - .open_subkey_with_flags(self.sub_key, KEY_READ | KEY_WRITE)?; - match sub_key.get_raw_value(self.value_name) { + fn get(&self) -> Result> { + let sub_key = CURRENT_USER.create(self.sub_key)?; + match sub_key.get_value(self.value_name) { Ok(val) => Ok(Some(val)), - Err(ref e) if e.kind() == io::ErrorKind::NotFound => Ok(None), - Err(e) => Err(e), + Err(e) if e.code() == HRESULT::from_win32(ERROR_FILE_NOT_FOUND) => Ok(None), + Err(e) => Err(e.into()), } } - pub fn set_value(&self, new: Option) -> io::Result<()> { - self.set(new.map(|s| s.to_reg_value()).as_ref()) + pub fn set_value(&self, new: Option<&Value>) -> Result<()> { + self.set(new) } - fn set(&self, new: Option<&RegValue>) -> io::Result<()> { - let sub_key = RegKey::predef(HKEY_CURRENT_USER) - .open_subkey_with_flags(self.sub_key, KEY_READ | KEY_WRITE)?; + fn set(&self, new: Option<&Value>) -> Result<()> { + let sub_key = CURRENT_USER.create(self.sub_key)?; match new { - Some(new) => sub_key.set_raw_value(self.value_name, new), - None => sub_key.delete_value(self.value_name), + Some(new) => Ok(sub_key.set_value(self.value_name, new)?), + None => Ok(sub_key.remove_value(self.value_name)?), } } } #[cfg(test)] mod tests { + use std::os::windows::ffi::OsStringExt; + + use windows_registry::Type; + use super::*; use crate::process::TestProcess; - fn wide(str: &str) -> Vec { - OsString::from(str).encode_wide().collect() - } - #[test] fn windows_install_does_not_add_path_twice() { assert_eq!( None, super::_add_to_path( - wide(r"c:\users\example\.cargo\bin;foo"), - wide(r"c:\users\example\.cargo\bin") + HSTRING::from(r"c:\users\example\.cargo\bin;foo"), + HSTRING::from(r"c:\users\example\.cargo\bin") ) ); } @@ -914,16 +862,19 @@ mod tests { 0x0101, // bogus trailing surrogate 0x0000, // null ]; - let cargo_home = wide(r"c:\users\example\.cargo\bin"); - let final_path = [&cargo_home, &[b';' as u16][..], &initial_path].join(&[][..]); + let cargo_home = r"c:\users\example\.cargo\bin"; + let mut final_path = OsString::from(cargo_home); + final_path.push(";"); + final_path.push(OsString::from_wide(&initial_path)); assert_eq!( - &final_path, - &super::_add_to_path(initial_path.clone(), cargo_home.clone(),).unwrap() + final_path, + super::_add_to_path(HSTRING::from_wide(&initial_path), HSTRING::from(cargo_home)) + .unwrap() ); assert_eq!( - &initial_path, - &super::_remove_from_path(final_path, cargo_home,).unwrap() + HSTRING::from_wide(&initial_path), + super::_remove_from_path(HSTRING::from(final_path), HSTRING::from(cargo_home)).unwrap() ); } @@ -931,56 +882,44 @@ mod tests { fn windows_path_regkey_type() { // per issue #261, setting PATH should use REG_EXPAND_SZ. let _guard = RegistryGuard::new(&USER_PATH); - let root = RegKey::predef(HKEY_CURRENT_USER); - let environment = root - .open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE) - .unwrap(); - environment.delete_value("PATH").unwrap(); + let environment = CURRENT_USER.create("Environment").unwrap(); + environment.remove_value("PATH").unwrap(); { // Can't compare the Results as Eq isn't derived; thanks error-chain. #![allow(clippy::unit_cmp)] - assert_eq!((), super::_apply_new_path(Some(wide("foo"))).unwrap()); + assert_eq!( + (), + super::_apply_new_path(Some(HSTRING::from("foo"))).unwrap() + ); } - let root = RegKey::predef(HKEY_CURRENT_USER); - let environment = root - .open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE) - .unwrap(); - let path = environment.get_raw_value("PATH").unwrap(); - assert_eq!(path.vtype, RegType::REG_EXPAND_SZ); - assert_eq!(super::to_winreg_bytes(wide("foo")), &path.bytes[..]); + let environment = CURRENT_USER.create("Environment").unwrap(); + let path = environment.get_value("PATH").unwrap(); + let path_hstring = environment.get_hstring("PATH").unwrap(); + assert_eq!(path.ty(), Type::ExpandString); + assert_eq!(HSTRING::from("foo"), path_hstring); } #[test] fn windows_path_delete_key_when_empty() { - use std::io; // during uninstall the PATH key may end up empty; if so we should // delete it. let _guard = RegistryGuard::new(&USER_PATH); - let root = RegKey::predef(HKEY_CURRENT_USER); - let environment = root - .open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE) - .unwrap(); + let environment = CURRENT_USER.create("Environment").unwrap(); environment - .set_raw_value( - "PATH", - &RegValue { - bytes: super::to_winreg_bytes(wide("foo")), - vtype: RegType::REG_EXPAND_SZ, - }, - ) + .set_expand_hstring("PATH", &HSTRING::from("foo")) .unwrap(); { // Can't compare the Results as Eq isn't derived; thanks error-chain. #![allow(clippy::unit_cmp)] - assert_eq!((), super::_apply_new_path(Some(Vec::new())).unwrap()); + assert_eq!((), super::_apply_new_path(Some(HSTRING::new())).unwrap()); } - let reg_value = environment.get_raw_value("PATH"); + let reg_value = environment.get_value("PATH"); match reg_value { Ok(_) => panic!("key not deleted"), - Err(ref e) if e.kind() == io::ErrorKind::NotFound => {} - Err(ref e) => panic!("error {e}"), + Err(e) if e.code() == HRESULT::from_win32(ERROR_FILE_NOT_FOUND) => {} + Err(e) => panic!("error {e}"), } } @@ -995,15 +934,10 @@ mod tests { ); let _guard = RegistryGuard::new(&USER_PATH); - let root = RegKey::predef(HKEY_CURRENT_USER); - let environment = root - .open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE) + let environment = CURRENT_USER.create("Environment").unwrap(); + environment + .set_bytes("PATH", Type::Bytes, &[0x12, 0x34]) .unwrap(); - let reg_value = RegValue { - bytes: vec![0x12, 0x34], - vtype: RegType::REG_BINARY, - }; - environment.set_raw_value("PATH", ®_value).unwrap(); // Ok(None) signals no change to the PATH setting layer assert_eq!( None, @@ -1021,22 +955,19 @@ mod tests { fn windows_treat_missing_path_as_empty() { // during install the PATH key may be missing; treat it as empty let _guard = RegistryGuard::new(&USER_PATH); - let root = RegKey::predef(HKEY_CURRENT_USER); - let environment = root - .open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE) - .unwrap(); - environment.delete_value("PATH").unwrap(); + let environment = CURRENT_USER.create("Environment").unwrap(); + environment.remove_value("PATH").unwrap(); - assert_eq!(Some(Vec::new()), super::get_windows_path_var().unwrap()); + assert_eq!(Some(HSTRING::new()), super::get_windows_path_var().unwrap()); } #[test] fn windows_uninstall_removes_semicolon_from_path_prefix() { assert_eq!( - wide("foo"), + HSTRING::from("foo"), super::_remove_from_path( - wide(r"c:\users\example\.cargo\bin;foo"), - wide(r"c:\users\example\.cargo\bin"), + HSTRING::from(r"c:\users\example\.cargo\bin;foo"), + HSTRING::from(r"c:\users\example\.cargo\bin"), ) .unwrap() ) @@ -1045,10 +976,10 @@ mod tests { #[test] fn windows_uninstall_removes_semicolon_from_path_suffix() { assert_eq!( - wide("foo"), + HSTRING::from("foo"), super::_remove_from_path( - wide(r"foo;c:\users\example\.cargo\bin"), - wide(r"c:\users\example\.cargo\bin"), + HSTRING::from(r"foo;c:\users\example\.cargo\bin"), + HSTRING::from(r"c:\users\example\.cargo\bin"), ) .unwrap() ) diff --git a/tests/suite/cli_paths.rs b/tests/suite/cli_paths.rs index c88a7e6120..56cd62d1bc 100644 --- a/tests/suite/cli_paths.rs +++ b/tests/suite/cli_paths.rs @@ -383,13 +383,19 @@ mod windows { use rustup::test::mock::clitools::{CliTestContext, Scenario}; use rustup::test::{get_path, RegistryGuard, USER_PATH}; + use windows_registry::{Value, HSTRING}; + #[tokio::test] /// Smoke test for end-to-end code connectivity of the installer path mgmt on windows. async fn install_uninstall_affect_path() { let mut cx = CliTestContext::new(Scenario::Empty).await; let _guard = RegistryGuard::new(&USER_PATH).unwrap(); let cfg_path = cx.config.cargodir.join("bin").display().to_string(); - let get_path_ = || get_path().unwrap().unwrap().to_string(); + let get_path_ = || { + HSTRING::try_from(get_path().unwrap().unwrap()) + .unwrap() + .to_string() + }; cx.config.expect_ok(&INIT_NONE).await; assert!( @@ -408,38 +414,39 @@ mod windows { #[tokio::test] /// Smoke test for end-to-end code connectivity of the installer path mgmt on windows. async fn install_uninstall_affect_path_with_non_unicode() { - use std::ffi::OsString; use std::os::windows::ffi::OsStrExt; - use winreg::enums::{RegType, HKEY_CURRENT_USER, KEY_READ, KEY_WRITE}; - use winreg::{RegKey, RegValue}; + + use windows_registry::{Type, CURRENT_USER}; let mut cx = CliTestContext::new(Scenario::Empty).await; let _guard = RegistryGuard::new(&USER_PATH).unwrap(); // Set up a non unicode PATH - let reg_value = RegValue { - bytes: vec![ - 0x00, 0xD8, // leading surrogate - 0x01, 0x01, // bogus trailing surrogate - 0x00, 0x00, // null - ], - vtype: RegType::REG_EXPAND_SZ, - }; - RegKey::predef(HKEY_CURRENT_USER) - .open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE) + let mut reg_value = Value::from([ + 0x00, 0xD8, // leading surrogate + 0x01, 0x01, // bogus trailing surrogate + 0x00, 0x00, // null + ]); + reg_value.set_ty(Type::ExpandString); + CURRENT_USER + .create("Environment") .unwrap() - .set_raw_value("PATH", ®_value) + .set_value("PATH", ®_value) .unwrap(); // compute expected path after installation - let expected = RegValue { - bytes: OsString::from(cx.config.cargodir.join("bin")) + let mut expected = Value::from( + cx.config + .cargodir + .join("bin") + .as_os_str() .encode_wide() .flat_map(|v| vec![v as u8, (v >> 8) as u8]) .chain(vec![b';', 0]) - .chain(reg_value.bytes.iter().copied()) - .collect(), - vtype: RegType::REG_EXPAND_SZ, - }; + .chain(reg_value.iter().copied()) + .collect::>() + .as_slice(), + ); + expected.set_ty(Type::ExpandString); cx.config.expect_ok(&INIT_NONE).await; assert_eq!(get_path().unwrap().unwrap(), expected); diff --git a/tests/suite/cli_self_upd.rs b/tests/suite/cli_self_upd.rs index 3ec6eb588d..d79d44691a 100644 --- a/tests/suite/cli_self_upd.rs +++ b/tests/suite/cli_self_upd.rs @@ -23,6 +23,8 @@ use rustup::test::{ use rustup::test::{RegistryGuard, RegistryValueId, USER_PATH}; use rustup::utils::{raw, utils}; use rustup::{for_host, DUP_TOOLS, TOOLS}; +#[cfg(windows)] +use windows_registry::Value; const TEST_VERSION: &str = "1.1.1"; @@ -350,12 +352,12 @@ async fn update_overwrites_programs_display_version() { .await; USER_RUSTUP_VERSION - .set_value(Some(PLACEHOLDER_VERSION)) + .set_value(Some(&Value::from(PLACEHOLDER_VERSION))) .unwrap(); cx.config.expect_ok(&["rustup", "self", "update"]).await; assert_eq!( - USER_RUSTUP_VERSION.get_value::().unwrap().unwrap(), - version, + USER_RUSTUP_VERSION.get_value().unwrap().unwrap(), + Value::from(version) ); }