implement `expand_path`

pull/120/head
Takayuki Maeda 3 years ago
parent 2d43c705a9
commit 855935708c

@ -245,7 +245,9 @@ impl Connection {
DatabaseType::Sqlite => {
let path = self.path.as_ref().map_or(
Err(anyhow::anyhow!("type sqlite needs the path field")),
|path| expand_tilde(path).ok_or(anyhow::anyhow!("cannot expand file path")),
|path| {
expand_path(path).ok_or_else(|| anyhow::anyhow!("cannot expand file path"))
},
)?;
Ok(format!("sqlite://{path}", path = path.to_str().unwrap()))
@ -275,40 +277,85 @@ pub fn get_app_config_path() -> anyhow::Result<std::path::PathBuf> {
Ok(path)
}
fn expand_tilde<P: AsRef<Path>>(path_user_input: P) -> Option<PathBuf> {
let p = path_user_input.as_ref();
if !p.starts_with("~") {
return Some(p.to_path_buf());
fn expand_path(path: &Path) -> Option<PathBuf> {
let mut expanded_path = PathBuf::new();
let mut path_iter = path.iter();
if path.starts_with("~") {
path_iter.next()?;
expanded_path = expanded_path.join(dirs_next::home_dir()?);
}
if p == Path::new("~") {
return dirs_next::home_dir();
}
dirs_next::home_dir().map(|mut h| {
if h == Path::new("/") {
p.strip_prefix("~").unwrap().to_path_buf()
for path in path_iter {
let path = path.to_str()?;
expanded_path = if cfg!(unix) && path.starts_with('$') {
expanded_path.join(std::env::var(path.strip_prefix('$')?).unwrap_or_default())
} else if cfg!(winddows) && path.starts_with('%') && path.ends_with('%') {
expanded_path
.join(std::env::var(path.strip_prefix('%')?.strip_suffix('%')?).unwrap_or_default())
} else {
h.push(p.strip_prefix("~/").unwrap());
h
expanded_path.join(path)
}
})
}
Some(expanded_path)
}
#[cfg(test)]
mod test {
use super::{expand_tilde, PathBuf};
use super::{expand_path, Path, PathBuf};
use std::env;
#[test]
fn test_expand_tilde() {
#[cfg(unix)]
let home = std::env::var("HOME").unwrap();
#[cfg(windows)]
#[cfg(unix)]
fn test_expand_path() {
let home = env::var("HOME").unwrap();
let test_env = "baz";
env::set_var("TEST", test_env);
assert_eq!(
expand_path(&Path::new("$HOME/foo")),
Some(PathBuf::from(&home).join("foo"))
);
assert_eq!(
expand_path(&Path::new("$HOME/foo/$TEST/bar")),
Some(PathBuf::from(&home).join("foo").join(test_env).join("bar"))
);
assert_eq!(
expand_path(&Path::new("~/foo")),
Some(PathBuf::from(&home).join("foo"))
);
assert_eq!(
expand_path(&Path::new("~/foo/~/bar")),
Some(PathBuf::from(&home).join("foo").join("~").join("bar"))
);
}
#[test]
#[cfg(windows)]
fn test_expand_path() {
let home = std::env::var("APPDATA").unwrap();
let projects = PathBuf::from(home).join("Projects");
assert_eq!(expand_tilde("~/Projects"), Some(projects));
assert_eq!(expand_tilde("/foo/bar"), Some("/foo/bar".into()));
let test_env = "baz";
env::set_var("TEST", test_env);
assert_eq!(
expand_path(Path::new("%APPDATA%/foo").to_path_buf()),
Some(PathBuf::from(home).join("foo"))
);
assert_eq!(
expand_path(Path::new("%APPDATA%/foo/%TEST%/bar").to_path_buf()),
Some(PathBuf::from(&home).join("foo").join(test_env).join("bar"))
);
assert_eq!(
expand_path(Path::new("~/foo").to_path_buf()),
Some(PathBuf::from(&home).join("foo"))
);
assert_eq!(
expand_tilde("~alice/projects"),
Some("~alice/projects".into())
expand_path(Path::new("~/foo/~/bar").to_path_buf()),
Some(PathBuf::from(&home).join("foo").join("~").join("bar"))
);
}
}

Loading…
Cancel
Save