Skip to content

Commit f3b45f2

Browse files
committed
Use guard type to replace with_saved_path()
1 parent 61cadf9 commit f3b45f2

File tree

7 files changed

+243
-235
lines changed

7 files changed

+243
-235
lines changed

src/cli/self_update/test.rs

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
//! Support for functional tests.
22
33
#[cfg(windows)]
4-
use std::{io, sync::Mutex};
4+
use std::{
5+
io,
6+
sync::{LockResult, Mutex, MutexGuard},
7+
};
58

69
#[cfg(windows)]
710
use winreg::{
@@ -11,37 +14,40 @@ use winreg::{
1114
};
1215

1316
#[cfg(windows)]
14-
pub fn with_saved_path(f: &mut dyn FnMut()) {
15-
with_saved_reg_value(&USER_PATH, f)
17+
pub fn get_path() -> io::Result<Option<RegValue>> {
18+
USER_PATH.get()
1619
}
1720

18-
#[cfg(unix)]
19-
pub fn with_saved_path(f: &mut dyn FnMut()) {
20-
f()
21+
#[cfg(windows)]
22+
pub struct RegistryGuard<'a> {
23+
_locked: LockResult<MutexGuard<'a, ()>>,
24+
id: &'static RegistryValueId,
25+
prev: Option<RegValue>,
2126
}
2227

2328
#[cfg(windows)]
24-
pub fn get_path() -> io::Result<Option<RegValue>> {
25-
USER_PATH.get()
29+
impl<'a> RegistryGuard<'a> {
30+
pub fn new(id: &'static RegistryValueId) -> io::Result<Self> {
31+
Ok(Self {
32+
_locked: REGISTRY_LOCK.lock(),
33+
id,
34+
prev: id.get()?,
35+
})
36+
}
2637
}
2738

2839
#[cfg(windows)]
29-
pub fn with_saved_reg_value(id: &RegistryValueId, f: &mut dyn FnMut()) {
30-
// Lock protects concurrent mutation of registry
31-
static LOCK: Mutex<()> = Mutex::new(());
32-
let _g = LOCK.lock();
33-
34-
// Save and restore the global state here to keep from trashing things.
35-
let saved_state = id
36-
.get()
37-
.expect("Error getting global state: Better abort to avoid trashing it");
38-
let _g = scopeguard::guard(saved_state, |p| id.set(p.as_ref()).unwrap());
39-
40-
f();
40+
impl<'a> Drop for RegistryGuard<'a> {
41+
fn drop(&mut self) {
42+
self.id.set(self.prev.as_ref()).unwrap();
43+
}
4144
}
4245

4346
#[cfg(windows)]
44-
const USER_PATH: RegistryValueId = RegistryValueId {
47+
static REGISTRY_LOCK: Mutex<()> = Mutex::new(());
48+
49+
#[cfg(windows)]
50+
pub const USER_PATH: RegistryValueId = RegistryValueId {
4551
sub_key: "Environment",
4652
value_name: "PATH",
4753
};

src/cli/self_update/windows.rs

Lines changed: 71 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -816,7 +816,7 @@ mod tests {
816816
use winreg::{RegKey, RegValue};
817817

818818
use crate::currentprocess::TestProcess;
819-
use crate::test::with_saved_path;
819+
use crate::test::{RegistryGuard, USER_PATH};
820820

821821
fn wide(str: &str) -> Vec<u16> {
822822
OsString::from(str).encode_wide().collect()
@@ -856,60 +856,58 @@ mod tests {
856856
#[test]
857857
fn windows_path_regkey_type() {
858858
// per issue #261, setting PATH should use REG_EXPAND_SZ.
859-
with_saved_path(&mut || {
860-
let root = RegKey::predef(HKEY_CURRENT_USER);
861-
let environment = root
862-
.open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
863-
.unwrap();
864-
environment.delete_value("PATH").unwrap();
865-
866-
{
867-
// Can't compare the Results as Eq isn't derived; thanks error-chain.
868-
#![allow(clippy::unit_cmp)]
869-
assert_eq!((), super::_apply_new_path(Some(wide("foo"))).unwrap());
870-
}
871-
let root = RegKey::predef(HKEY_CURRENT_USER);
872-
let environment = root
873-
.open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
874-
.unwrap();
875-
let path = environment.get_raw_value("PATH").unwrap();
876-
assert_eq!(path.vtype, RegType::REG_EXPAND_SZ);
877-
assert_eq!(super::to_winreg_bytes(wide("foo")), &path.bytes[..]);
878-
});
859+
let _guard = RegistryGuard::new(&USER_PATH);
860+
let root = RegKey::predef(HKEY_CURRENT_USER);
861+
let environment = root
862+
.open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
863+
.unwrap();
864+
environment.delete_value("PATH").unwrap();
865+
866+
{
867+
// Can't compare the Results as Eq isn't derived; thanks error-chain.
868+
#![allow(clippy::unit_cmp)]
869+
assert_eq!((), super::_apply_new_path(Some(wide("foo"))).unwrap());
870+
}
871+
let root = RegKey::predef(HKEY_CURRENT_USER);
872+
let environment = root
873+
.open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
874+
.unwrap();
875+
let path = environment.get_raw_value("PATH").unwrap();
876+
assert_eq!(path.vtype, RegType::REG_EXPAND_SZ);
877+
assert_eq!(super::to_winreg_bytes(wide("foo")), &path.bytes[..]);
879878
}
880879

881880
#[test]
882881
fn windows_path_delete_key_when_empty() {
883882
use std::io;
884883
// during uninstall the PATH key may end up empty; if so we should
885884
// delete it.
886-
with_saved_path(&mut || {
887-
let root = RegKey::predef(HKEY_CURRENT_USER);
888-
let environment = root
889-
.open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
890-
.unwrap();
891-
environment
892-
.set_raw_value(
893-
"PATH",
894-
&RegValue {
895-
bytes: super::to_winreg_bytes(wide("foo")),
896-
vtype: RegType::REG_EXPAND_SZ,
897-
},
898-
)
899-
.unwrap();
900-
901-
{
902-
// Can't compare the Results as Eq isn't derived; thanks error-chain.
903-
#![allow(clippy::unit_cmp)]
904-
assert_eq!((), super::_apply_new_path(Some(Vec::new())).unwrap());
905-
}
906-
let reg_value = environment.get_raw_value("PATH");
907-
match reg_value {
908-
Ok(_) => panic!("key not deleted"),
909-
Err(ref e) if e.kind() == io::ErrorKind::NotFound => {}
910-
Err(ref e) => panic!("error {e}"),
911-
}
912-
});
885+
let _guard = RegistryGuard::new(&USER_PATH);
886+
let root = RegKey::predef(HKEY_CURRENT_USER);
887+
let environment = root
888+
.open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
889+
.unwrap();
890+
environment
891+
.set_raw_value(
892+
"PATH",
893+
&RegValue {
894+
bytes: super::to_winreg_bytes(wide("foo")),
895+
vtype: RegType::REG_EXPAND_SZ,
896+
},
897+
)
898+
.unwrap();
899+
900+
{
901+
// Can't compare the Results as Eq isn't derived; thanks error-chain.
902+
#![allow(clippy::unit_cmp)]
903+
assert_eq!((), super::_apply_new_path(Some(Vec::new())).unwrap());
904+
}
905+
let reg_value = environment.get_raw_value("PATH");
906+
match reg_value {
907+
Ok(_) => panic!("key not deleted"),
908+
Err(ref e) if e.kind() == io::ErrorKind::NotFound => {}
909+
Err(ref e) => panic!("error {e}"),
910+
}
913911
}
914912

915913
#[test]
@@ -921,22 +919,23 @@ mod tests {
921919
.cloned()
922920
.collect(),
923921
);
924-
with_saved_path(&mut || {
925-
let root = RegKey::predef(HKEY_CURRENT_USER);
926-
let environment = root
927-
.open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
928-
.unwrap();
929-
let reg_value = RegValue {
930-
bytes: vec![0x12, 0x34],
931-
vtype: RegType::REG_BINARY,
932-
};
933-
environment.set_raw_value("PATH", &reg_value).unwrap();
934-
// Ok(None) signals no change to the PATH setting layer
935-
assert_eq!(
936-
None,
937-
super::_with_path_cargo_home_bin(|_, _| panic!("called"), &tp.process).unwrap()
938-
);
939-
});
922+
923+
let _guard = RegistryGuard::new(&USER_PATH);
924+
let root = RegKey::predef(HKEY_CURRENT_USER);
925+
let environment = root
926+
.open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
927+
.unwrap();
928+
let reg_value = RegValue {
929+
bytes: vec![0x12, 0x34],
930+
vtype: RegType::REG_BINARY,
931+
};
932+
environment.set_raw_value("PATH", &reg_value).unwrap();
933+
// Ok(None) signals no change to the PATH setting layer
934+
assert_eq!(
935+
None,
936+
super::_with_path_cargo_home_bin(|_, _| panic!("called"), &tp.process).unwrap()
937+
);
938+
940939
assert_eq!(
941940
r"warn: the registry key HKEY_CURRENT_USER\Environment\PATH is not a string. Not modifying the PATH variable
942941
",
@@ -947,15 +946,14 @@ mod tests {
947946
#[test]
948947
fn windows_treat_missing_path_as_empty() {
949948
// during install the PATH key may be missing; treat it as empty
950-
with_saved_path(&mut || {
951-
let root = RegKey::predef(HKEY_CURRENT_USER);
952-
let environment = root
953-
.open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
954-
.unwrap();
955-
environment.delete_value("PATH").unwrap();
956-
957-
assert_eq!(Some(Vec::new()), super::get_windows_path_var().unwrap());
958-
});
949+
let _guard = RegistryGuard::new(&USER_PATH);
950+
let root = RegKey::predef(HKEY_CURRENT_USER);
951+
let environment = root
952+
.open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
953+
.unwrap();
954+
environment.delete_value("PATH").unwrap();
955+
956+
assert_eq!(Some(Vec::new()), super::get_windows_path_var().unwrap());
959957
}
960958

961959
#[test]

src/env_var.rs

Lines changed: 35 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,10 @@ mod tests {
4747
use std::ffi::{OsStr, OsString};
4848

4949
use super::*;
50+
#[cfg(windows)]
51+
use crate::cli::self_update::test::{RegistryGuard, USER_PATH};
5052
use crate::currentprocess::TestProcess;
51-
use crate::test::{with_saved_path, Env};
53+
use crate::test::Env;
5254

5355
#[test]
5456
fn prepend_unique_path() {
@@ -58,43 +60,43 @@ mod tests {
5860
env::join_paths(["/home/a/.cargo/bin", "/home/b/.cargo/bin"].iter()).unwrap(),
5961
);
6062
let tp = TestProcess::with_vars(vars);
61-
with_saved_path(&mut || {
62-
let mut path_entries = vec![];
63-
let mut cmd = Command::new("test");
63+
#[cfg(windows)]
64+
let _path_guard = RegistryGuard::new(&USER_PATH).unwrap();
65+
let mut path_entries = vec![];
66+
let mut cmd = Command::new("test");
6467

65-
let a = OsString::from("/home/a/.cargo/bin");
66-
let path_a = PathBuf::from(a);
67-
path_entries.push(path_a);
68+
let a = OsString::from("/home/a/.cargo/bin");
69+
let path_a = PathBuf::from(a);
70+
path_entries.push(path_a);
6871

69-
let _a = OsString::from("/home/a/.cargo/bin");
70-
let _path_a = PathBuf::from(_a);
71-
path_entries.push(_path_a);
72+
let _a = OsString::from("/home/a/.cargo/bin");
73+
let _path_a = PathBuf::from(_a);
74+
path_entries.push(_path_a);
7275

73-
let z = OsString::from("/home/z/.cargo/bin");
74-
let path_z = PathBuf::from(z);
75-
path_entries.push(path_z);
76+
let z = OsString::from("/home/z/.cargo/bin");
77+
let path_z = PathBuf::from(z);
78+
path_entries.push(path_z);
7679

77-
prepend_path("PATH", path_entries, &mut cmd, &tp.process);
78-
let envs: Vec<_> = cmd.get_envs().collect();
80+
prepend_path("PATH", path_entries, &mut cmd, &tp.process);
81+
let envs: Vec<_> = cmd.get_envs().collect();
7982

80-
assert_eq!(
81-
envs,
82-
&[(
83-
OsStr::new("PATH"),
84-
Some(
85-
env::join_paths(
86-
[
87-
"/home/z/.cargo/bin",
88-
"/home/a/.cargo/bin",
89-
"/home/b/.cargo/bin"
90-
]
91-
.iter()
92-
)
93-
.unwrap()
94-
.as_os_str()
83+
assert_eq!(
84+
envs,
85+
&[(
86+
OsStr::new("PATH"),
87+
Some(
88+
env::join_paths(
89+
[
90+
"/home/z/.cargo/bin",
91+
"/home/a/.cargo/bin",
92+
"/home/b/.cargo/bin"
93+
]
94+
.iter()
9595
)
96-
),]
97-
);
98-
});
96+
.unwrap()
97+
.as_os_str()
98+
)
99+
),]
100+
);
99101
}
100102
}

src/test.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,11 @@ use std::process::Command;
1515
#[cfg(test)]
1616
use anyhow::Result;
1717

18-
pub use crate::cli::self_update::test::with_saved_path;
1918
use crate::currentprocess::TestProcess;
2019
use crate::dist::TargetTriple;
2120

2221
#[cfg(windows)]
23-
pub use crate::cli::self_update::test::{get_path, with_saved_reg_value, RegistryValueId};
22+
pub use crate::cli::self_update::test::{get_path, RegistryGuard, RegistryValueId, USER_PATH};
2423

2524
// Things that can have environment variables applied to them.
2625
pub trait Env {

0 commit comments

Comments
 (0)