From 6f2f4e779671bbd26b2afc203210295e32f97f86 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Tue, 11 Jan 2022 01:16:17 -0500 Subject: move home directory expansion from cd to eval --- src/parse/ast.rs | 49 +++++++++++++++++++++++++++++++++++++ src/runner/builtins/mod.rs | 61 +++++++++------------------------------------- 2 files changed, 60 insertions(+), 50 deletions(-) diff --git a/src/parse/ast.rs b/src/parse/ast.rs index 6a3ab8e..207a786 100644 --- a/src/parse/ast.rs +++ b/src/parse/ast.rs @@ -227,6 +227,9 @@ impl Word { let mut s = String::new(); let mut pat = String::new(); let mut is_glob = false; + let initial_bareword = word + .get(0) + .map_or(false, |part| matches!(part, WordPart::Bareword(_))); for part in word { match part { WordPart::Alternation(_) => unreachable!(), @@ -247,6 +250,10 @@ impl Word { } } } + if initial_bareword { + s = expand_home(&s)?; + pat = expand_home(&pat)?; + } if is_glob { let mut found = false; for file in glob::glob_with(&pat, opts)? { @@ -464,6 +471,48 @@ fn parse_fd(s: &str) -> std::os::unix::io::RawFd { } } +fn expand_home(dir: &str) -> anyhow::Result { + if dir.starts_with('~') { + let path: std::path::PathBuf = dir.into(); + if let std::path::Component::Normal(prefix) = + path.components().next().unwrap() + { + let prefix_bytes = prefix.as_bytes(); + let name = if prefix_bytes == b"~" { + None + } else { + Some(std::ffi::OsStr::from_bytes(&prefix_bytes[1..])) + }; + if let Some(home) = home(name) { + Ok(home + .join(path.strip_prefix(prefix).unwrap()) + .to_str() + .unwrap() + .to_string()) + } else { + anyhow::bail!( + "no such user: {}", + name.map(std::ffi::OsStr::to_string_lossy) + .as_ref() + .unwrap_or(&std::borrow::Cow::Borrowed("(deleted)")) + ); + } + } else { + unreachable!() + } + } else { + Ok(dir.to_string()) + } +} + +fn home(user: Option<&std::ffi::OsStr>) -> Option { + let user = user.map_or_else( + || users::get_user_by_uid(users::get_current_uid()), + users::get_user_by_name, + ); + user.map(|user| user.home_dir().to_path_buf()) +} + #[cfg(test)] #[path = "test_ast.rs"] mod test; diff --git a/src/runner/builtins/mod.rs b/src/runner/builtins/mod.rs index 47d2f45..ff03499 100644 --- a/src/runner/builtins/mod.rs +++ b/src/runner/builtins/mod.rs @@ -60,55 +60,24 @@ fn cd( ) -> anyhow::Result { async fn async_cd( exe: crate::parse::Exe, - _env: &Env, + env: &Env, cfg: command::Cfg, ) -> std::process::ExitStatus { - let dir = exe.args().get(0).map_or("", String::as_str); - let dir = if dir.is_empty() { - if let Some(dir) = home(None) { - dir - } else { - bail!(cfg, exe, "couldn't find current user"); - } - } else if dir.starts_with('~') { - let path: std::path::PathBuf = dir.into(); - if let std::path::Component::Normal(prefix) = - path.components().next().unwrap() - { - let prefix_bytes = prefix.as_bytes(); - let name = if prefix_bytes == b"~" { - None - } else { - Some(std::ffi::OsStr::from_bytes(&prefix_bytes[1..])) - }; - if let Some(home) = home(name) { - home.join(path.strip_prefix(prefix).unwrap()) - } else { - bail!( - cfg, - exe, - "no such user: {}", - name.map(std::ffi::OsStr::to_string_lossy) - .as_ref() - .unwrap_or(&std::borrow::Cow::Borrowed( - "(deleted)" - )) - ); - } + let dir = if let Some(dir) = exe.args().get(0) { + if dir.is_empty() { + ".".to_string() } else { - unreachable!() + dir.into() } } else { - dir.into() + let dir = env.var("HOME"); + if dir.is_empty() { + bail!(cfg, exe, "could not find home directory"); + } + dir }; if let Err(e) = std::env::set_current_dir(&dir) { - bail!( - cfg, - exe, - "{}: {}", - crate::format::io_error(&e), - dir.display() - ); + bail!(cfg, exe, "{}: {}", crate::format::io_error(&e), dir); } async_std::process::ExitStatus::from_raw(0) } @@ -308,11 +277,3 @@ fn builtin( cfg.setup_command(&mut cmd); Ok(command::Child::new_wrapped(cmd.spawn(env)?)) } - -fn home(user: Option<&std::ffi::OsStr>) -> Option { - let user = user.map_or_else( - || users::get_user_by_uid(users::get_current_uid()), - users::get_user_by_name, - ); - user.map(|user| user.home_dir().to_path_buf()) -} -- cgit v1.2.3-54-g00ecf