Expand tilde and environment variables in path field (#120)

* expand tlide in path field

* join path

* implement `expand_path`

* fix compile error on Windows

* fix typo

* use HOMEPATH

* fix home dir

* use HOME env
pull/125/head
Takayuki Maeda 3 years ago committed by GitHub
parent 78d1297452
commit 7a202aa8b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -26,4 +26,4 @@ database = "dvdrental"
[[conn]]
type = "sqlite"
path = "/Users/tako8ki/Downloads/chinook.db"
path = "$HOME/Downloads/chinook.db"

@ -4,6 +4,7 @@ use serde::Deserialize;
use std::fmt;
use std::fs::File;
use std::io::{BufReader, Read};
use std::path::{Path, PathBuf};
use structopt::StructOpt;
#[derive(StructOpt, Debug)]
@ -244,10 +245,12 @@ impl Connection {
DatabaseType::Sqlite => {
let path = self.path.as_ref().map_or(
Err(anyhow::anyhow!("type sqlite needs the path field")),
|path| Ok(path.to_str().unwrap()),
|path| {
expand_path(path).ok_or_else(|| anyhow::anyhow!("cannot expand file path"))
},
)?;
Ok(format!("sqlite://{path}", path = path))
Ok(format!("sqlite://{path}", path = path.to_str().unwrap()))
}
}
}
@ -273,3 +276,91 @@ pub fn get_app_config_path() -> anyhow::Result<std::path::PathBuf> {
std::fs::create_dir_all(&path)?;
Ok(path)
}
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()?);
}
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!(windows) && path.starts_with('%') && path.ends_with('%') {
expanded_path
.join(std::env::var(path.strip_prefix('%')?.strip_suffix('%')?).unwrap_or_default())
} else {
expanded_path.join(path)
}
}
Some(expanded_path)
}
#[cfg(test)]
mod test {
use super::{expand_path, Path, PathBuf};
use std::env;
#[test]
#[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_patha() {
let home = std::env::var("HOMEPATH").unwrap();
let test_env = "baz";
env::set_var("TEST", test_env);
assert_eq!(
expand_path(&Path::new("%HOMEPATH%/foo")),
Some(PathBuf::from(&home).join("foo"))
);
assert_eq!(
expand_path(&Path::new("%HOMEPATH%/foo/%TEST%/bar")),
Some(PathBuf::from(&home).join("foo").join(test_env).join("bar"))
);
assert_eq!(
expand_path(&Path::new("~/foo")),
Some(PathBuf::from(&dirs_next::home_dir().unwrap()).join("foo"))
);
assert_eq!(
expand_path(&Path::new("~/foo/~/bar")),
Some(
PathBuf::from(&dirs_next::home_dir().unwrap())
.join("foo")
.join("~")
.join("bar")
)
);
}
}

Loading…
Cancel
Save