Skip to content

Commit

Permalink
refactor: Replace shellexpand with dirs + path_from()
Browse files Browse the repository at this point in the history
It turned out shellexpand has some limitations that bugged me
(netvl/shellexpand#22).

I opted to use the more low-level and popular "dirs" crate, which
allowed me to write a quite elegant abstraction in form of a new
path_from() function.
  • Loading branch information
randoragon committed Feb 21, 2024
1 parent 4251ae3 commit 5964103
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 20 deletions.
11 changes: 1 addition & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ edition = "2021"
anyhow = "1.0.80"
camino = "1.1.6"
clap = { version = "4.5.1", features = ["derive"] }
dirs = "5.0.1"
id3 = "1.12.0"
log = "0.4.20"
shellexpand = "3.1.0"
stderrlog = "0.6.0"
28 changes: 21 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,34 @@ use anyhow::{anyhow, Result};
use camino::{Utf8Path, Utf8PathBuf};
use log::warn;
use std::fs;
use std::path::PathBuf;
use std::sync::OnceLock;

/// Returns the path to the music directory.
pub fn dirname() -> &'static Utf8Path {
static MUSIC_DIR: OnceLock<Utf8PathBuf> = OnceLock::new();
MUSIC_DIR.get_or_init(|| shellexpand_or_panic("~/Music"))
MUSIC_DIR.get_or_init(|| path_from(dirs::home_dir, "Music"))
}

/// Expands a path. Panics on any error encountered, including undefined variables.
fn shellexpand_or_panic(path: &str) -> Utf8PathBuf {
match shellexpand::full(path) {
Ok(cow) => Utf8PathBuf::from(cow.as_ref()),
Err(e) => panic!("Failed to expand path '{}': {}", path, e),
}
/// Constructs a path by concatenating a `dirs::*` function output and an arbitrary relative path.
///
/// # Examples
/// ```
/// assert_eq!(path_from(dirs::home_dir, "my_file.txt"), "/home/user/my_file.txt");
/// ```
pub fn path_from<T: AsRef<Utf8Path>>(base_dir: fn() -> Option<PathBuf>, rel_path: T) -> Utf8PathBuf {
assert!(rel_path.as_ref().is_relative(), "rel_path must be relative");
let path = match base_dir() {
Some(path) => path,
None => panic!("Failed to locate home directory"),
};
assert!(path.is_absolute(), "base_dir must yield an absolute path");
let mut path = match path.to_str() {
Some(str) => Utf8PathBuf::from(str),
None => panic!("Failed to convert home path to UTF-8 (other encodings not supported)"),
};
path.push(rel_path);
path
}

/// Returns an iterator over directory files, with a filtering function.
Expand Down
2 changes: 1 addition & 1 deletion src/playcount/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ impl Playcount {
/// Returns the path to the playcount directory.
fn dirname() -> &'static Utf8Path {
static PLAYCOUNTS_DIR: OnceLock<Utf8PathBuf> = OnceLock::new();
PLAYCOUNTS_DIR.get_or_init(|| crate::shellexpand_or_panic("~/Music/.playcount"))
PLAYCOUNTS_DIR.get_or_init(|| crate::path_from(dirs::home_dir, "Music/.playcount"))
}

/// Returns an iterator over all playcount file paths.
Expand Down
2 changes: 1 addition & 1 deletion src/playlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ impl Playlist {
/// Returns the path to the playlists directory.
fn dirname() -> &'static Utf8Path {
static PLAYLISTS_DIR: OnceLock<Utf8PathBuf> = OnceLock::new();
PLAYLISTS_DIR.get_or_init(|| crate::shellexpand_or_panic("~/Music/Playlists"))
PLAYLISTS_DIR.get_or_init(|| crate::path_from(dirs::home_dir, "Music/Playlists"))
}

/// Returns an iterator over all playlist file paths.
Expand Down

0 comments on commit 5964103

Please sign in to comment.