summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2022-01-11 01:16:17 -0500
committerJesse Luehrs <doy@tozt.net>2022-01-11 01:16:17 -0500
commit6f2f4e779671bbd26b2afc203210295e32f97f86 (patch)
tree7a88d2610068f520bc6dea1b4478aff597b9ccb0
parent798b412537fd2e93e86c2c305be9405b79d2dcb4 (diff)
downloadnbsh-6f2f4e779671bbd26b2afc203210295e32f97f86.tar.gz
nbsh-6f2f4e779671bbd26b2afc203210295e32f97f86.zip
move home directory expansion from cd to eval
-rw-r--r--src/parse/ast.rs49
-rw-r--r--src/runner/builtins/mod.rs61
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<String> {
+ 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<std::path::PathBuf> {
+ 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<command::Child> {
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<std::path::PathBuf> {
- 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())
-}