Support Termux (#10013)

This commit is contained in:
Skyler Hawthorne 2023-08-28 02:53:25 -04:00 committed by GitHub
parent 487f1a97ea
commit 38f454d5ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 69 additions and 52 deletions

View File

@ -16,5 +16,5 @@ dirs-next = "2.0"
[target.'cfg(windows)'.dependencies]
omnipath = "0.1"
[target.'cfg(all(unix, not(target_os = "macos")))'.dependencies]
[target.'cfg(all(unix, not(target_os = "macos"), not(target_os = "android")))'.dependencies]
pwd = "1.3"

View File

@ -1,7 +1,22 @@
#[cfg(all(unix, not(target_os = "macos")))]
#[cfg(all(unix, not(target_os = "macos"), not(target_os = "android")))]
use pwd::Passwd;
use std::path::{Path, PathBuf};
#[cfg(target_os = "macos")]
const FALLBACK_USER_HOME_BASE_DIR: &str = "/Users";
#[cfg(target_os = "windows")]
const FALLBACK_USER_HOME_BASE_DIR: &str = "C:\\Users\\";
#[cfg(all(unix, not(target_os = "macos"), not(target_os = "android")))]
const FALLBACK_USER_HOME_BASE_DIR: &str = "/home";
#[cfg(all(unix, target_os = "android"))]
const FALLBACK_USER_HOME_BASE_DIR: &str = "/data";
#[cfg(target_os = "android")]
const TERMUX_HOME: &str = "/data/data/com.termux/files/home";
fn expand_tilde_with_home(path: impl AsRef<Path>, home: Option<PathBuf>) -> PathBuf {
let path = path.as_ref();
@ -45,77 +60,61 @@ fn expand_tilde_with_home(path: impl AsRef<Path>, home: Option<PathBuf>) -> Path
}
}
#[cfg(all(unix, not(target_os = "macos")))]
fn fallback_home_dir(username: &str) -> PathBuf {
PathBuf::from_iter([FALLBACK_USER_HOME_BASE_DIR, username])
}
#[cfg(all(unix, not(target_os = "macos"), not(target_os = "android")))]
fn user_home_dir(username: &str) -> PathBuf {
let passwd = Passwd::from_name(username);
match &passwd.ok() {
Some(Some(dir)) => PathBuf::from(&dir.dir),
_ => {
let mut file = String::from("/home/");
file.push_str(username);
PathBuf::from(file)
_ => fallback_home_dir(username),
}
}
// PathBuf::from(concat!("/home/", username)),
// Returns home dir of user.
}
#[cfg(target_os = "macos")]
#[cfg(any(target_os = "android", target_os = "windows", target_os = "macos"))]
fn user_home_dir(username: &str) -> PathBuf {
use std::path::Component;
match dirs_next::home_dir() {
None => {
let mut expected_path = String::from("/Users/");
expected_path.push_str(username);
let path = Path::new(&expected_path);
let mut home = PathBuf::new();
home.push(path);
home
// Termux always has the same home directory
#[cfg(target_os = "android")]
if is_termux() {
return PathBuf::from(TERMUX_HOME);
}
fallback_home_dir(username)
}
Some(user) => {
let mut expected_path = user;
if !cfg!(target_os = "android")
&& expected_path
.components()
.last()
.map(|last| last != Component::Normal(username.as_ref()))
.unwrap_or(false)
{
expected_path.pop();
expected_path.push(Path::new(username));
}
if expected_path.is_dir() {
expected_path
} else {
let mut expected_path_as_string = String::from("/Users/");
expected_path_as_string.push_str(username);
let path = Path::new(&expected_path_as_string);
let mut home = PathBuf::new();
home.push(path);
home
fallback_home_dir(username)
}
}
}
}
#[cfg(target_os = "windows")]
fn user_home_dir(username: &str) -> PathBuf {
match dirs_next::home_dir() {
None => {
let mut expected_path = String::from("C:\\Users\\");
expected_path.push_str(username);
let path = Path::new(&expected_path);
let mut home = PathBuf::new();
home.push(path);
home
}
Some(user) => {
let mut expected_path = user;
expected_path.pop();
expected_path.push(Path::new(username));
if expected_path.is_dir() {
expected_path
} else {
let mut expected_path_as_string = String::from("C:\\Users\\");
expected_path_as_string.push_str(username);
let path = Path::new(&expected_path_as_string);
let mut home = PathBuf::new();
home.push(path);
home
}
}
}
/// Returns true if the shell is running inside the Termux terminal emulator
/// app.
#[cfg(target_os = "android")]
fn is_termux() -> bool {
std::env::var("TERMUX_VERSION").is_ok()
}
fn expand_tilde_with_another_user_home(path: &Path) -> PathBuf {
@ -211,4 +210,22 @@ mod tests {
fn string_with_double_tilde_backslash() {
check_expanded("~\\\\test\\test2/test3");
}
// [TODO] Figure out how to reliably test with real users.
#[test]
fn user_home_dir_fallback() {
let user = "nonexistent";
let expected_home = PathBuf::from_iter([FALLBACK_USER_HOME_BASE_DIR, user]);
#[cfg(target_os = "android")]
let expected_home = if is_termux() {
PathBuf::from(TERMUX_HOME)
} else {
expected_home
};
let actual_home = super::user_home_dir(user);
assert_eq!(expected_home, actual_home, "wrong home");
}
}