Skip to content

Commit

Permalink
fix(libscoop): added portability on non-windows
Browse files Browse the repository at this point in the history
Note: although this is for unix, we are not going to add non-windows
support. The reason of adding the adaptor is to support build docs
on linux...

Signed-off-by: Chawye Hsu <[email protected]>
  • Loading branch information
chawyehsu committed Aug 9, 2023
1 parent 183cfd8 commit 3d1ffee
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 41 deletions.
6 changes: 4 additions & 2 deletions crates/libscoop/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ dirs = "5.0.1"
flume = "0.10"
futures = { version = "0.3", features = ["thread-pool"] }
git2 = "0.17.2"
junction = "1.0.0"
log = "0.4"
once_cell = "1.18.0"
rayon = "1.7.0"
Expand All @@ -28,12 +27,15 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
sysinfo = "0.29"
thiserror = "1.0"
winreg = "0.50"

[dependencies.scoop-hash]
version = "0.1.0-beta.3"
path = "../scoop_hash"

[target.'cfg(windows)'.dependencies]
junction = "1.0.0"
winreg = "0.50"

[features]
default = []
rustcrypto-hash = ["scoop-hash/rustcrypto"]
Expand Down
117 changes: 78 additions & 39 deletions crates/libscoop/src/internal/env.rs
Original file line number Diff line number Diff line change
@@ -1,44 +1,83 @@
use once_cell::sync::Lazy;
use std::ffi::OsString;
use std::path::Path;
use winreg::enums::HKEY_CURRENT_USER;
use winreg::RegKey;

use crate::error::Fallible;

/// `HKEY_CURRENT_USER` registry key handle.
static HKCU: Lazy<RegKey> = Lazy::new(|| RegKey::predef(HKEY_CURRENT_USER));

/// Get the value of an environment variable.
/// Returns an empty string if the variable is not set.
pub fn get(key: &str) -> Fallible<OsString> {
let path = Path::new("Environment");
let env = HKCU.open_subkey(path)?;
Ok(env.get_value(key)?)
}
#[cfg(unix)]
pub use unix::{get, get_env_path_list, set};
#[cfg(windows)]
pub use windows::{get, get_env_path_list, set};

#[cfg(windows)]
mod windows {
use once_cell::sync::Lazy;
use std::ffi::OsString;
use std::path::Path;
use winreg::enums::HKEY_CURRENT_USER;
use winreg::RegKey;

use crate::error::Fallible;

/// `HKEY_CURRENT_USER` registry key handle.
static HKCU: Lazy<RegKey> = Lazy::new(|| RegKey::predef(HKEY_CURRENT_USER));

/// Get the value of an environment variable.
/// Returns an empty string if the variable is not set.
pub fn get(key: &str) -> Fallible<OsString> {
let path = Path::new("Environment");
let env = HKCU.open_subkey(path)?;
Ok(env.get_value(key)?)
}

/// Set the value of an environment variable.
/// If the value is an empty string, the variable is deleted.
pub fn set(key: &str, value: &str) -> Fallible<()> {
let path = Path::new("Environment");
let (env, _) = HKCU.create_subkey(path)?;

if value.is_empty() {
// ignore error of deleting non-existent value
let _ = env.delete_value(key);
} else {
env.set_value(key, &value)?;
}
Ok(())
}

/// Set the value of an environment variable.
/// If the value is an empty string, the variable is deleted.
pub fn set(key: &str, value: &str) -> Fallible<()> {
let path = Path::new("Environment");
let (env, _) = HKCU.create_subkey(path)?;

if value.is_empty() {
// ignore error of deleting non-existent value
let _ = env.delete_value(key);
} else {
env.set_value(key, &value)?;
/// Get the value of the `PATH` environment variable as a list of paths.
pub fn get_env_path_list() -> Fallible<Vec<String>> {
let env_path = get("PATH")?;
Ok(env_path
.into_string()
.unwrap()
.split(';')
.map(|s| s.to_owned())
.collect())
}
Ok(())
}

/// Get the value of the `PATH` environment variable as a list of paths.
pub fn get_env_path_list() -> Fallible<Vec<String>> {
let env_path = get("PATH")?;
Ok(env_path
.into_string()
.unwrap()
.split(';')
.map(|s| s.to_owned())
.collect())
#[cfg(unix)]
mod unix {
use std::ffi::OsString;

use crate::error::Fallible;

/// Get the value of an environment variable.
/// Returns an empty string if the variable is not set.
pub fn get(key: &str) -> Fallible<OsString> {
Ok(std::env::var_os(key).unwrap_or_default())
}

/// Set the value of an environment variable.
/// If the value is an empty string, the variable is deleted.
pub fn set(key: &str, value: &str) -> Fallible<()> {
// no-op
Ok(())
}

/// Get the value of the `PATH` environment variable as a list of paths.
pub fn get_env_path_list() -> Fallible<Vec<String>> {
let env_path = get("PATH")?;
Ok(env_path
.into_string()
.unwrap()
.split(':')
.map(|s| s.to_owned())
.collect())
}
}
15 changes: 15 additions & 0 deletions crates/libscoop/src/internal/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ where
}

/// Remove a symlink at `lnk`.
#[cfg(windows)]
pub fn remove_symlink<P: AsRef<Path>>(lnk: P) -> io::Result<()> {
let lnk = lnk.as_ref();
let metadata = lnk.symlink_metadata()?;
Expand All @@ -94,6 +95,7 @@ pub fn remove_symlink<P: AsRef<Path>>(lnk: P) -> io::Result<()> {
// Remove possible readonly flag on the symlink added by `attrib +R` command
if permissions.readonly() {
// Remove readonly flag
#[allow(clippy::permissions_set_readonly_false)]
permissions.set_readonly(false);
std::fs::set_permissions(lnk, permissions)?;
}
Expand All @@ -112,7 +114,14 @@ pub fn remove_symlink<P: AsRef<Path>>(lnk: P) -> io::Result<()> {
}
}

/// Remove a symlink at `lnk`.
#[cfg(unix)]
pub fn remove_symlink<P: AsRef<Path>>(lnk: P) -> io::Result<()> {
std::fs::remove_file(lnk)
}

/// Create a directory symlink at `lnk` pointing to `src`.
#[cfg(windows)]
pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(src: P, lnk: Q) -> io::Result<()> {
// It is possible to create a symlink on Windows, but one of the following
// conditions must be met:
Expand All @@ -133,3 +142,9 @@ pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(src: P, lnk: Q) -> io::Result
Ok(())
}
}

/// Create a directory symlink at `lnk` pointing to `src`.
#[cfg(unix)]
pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(src: P, lnk: Q) -> io::Result<()> {
std::os::unix::fs::symlink(src.as_ref(), lnk.as_ref())
}

0 comments on commit 3d1ffee

Please sign in to comment.