-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
discussionenhancementNew feature or requestNew feature or requestfeaturehelp wantedExtra attention is neededExtra attention is needed
Description
Summary
Add optional shellexpand feature for automatic Unix shell-style path expansion in soft_canonicalize().
Motivation
Users frequently pass shell-style paths from configs, CLI args, and user input. Currently requires manual expansion before calling soft_canonicalize.
Proposed API
[dependencies]
soft-canonicalize = { version = "0.4", features = ["shellexpand"] }// With feature enabled, automatic expansion:
let path = soft_canonicalize("~/Documents/$PROJECT/file.txt")?;
// → /home/user/Documents/my-project/file.txt
// Without feature: tilde treated as literal path componentSupported Expansions (Unix only)
~→/home/user~/path→/home/user/path~user/path→/home/user/path$VAR,${VAR}→ environment variables~+→$PWD~-→$OLDPWD
Critical Design Question: Non-Existing Users
Our library works with non-existing filesystem paths. Should it work with non-existing users?
soft_canonicalize("~alice/file.txt")
// What if user "alice" doesn't exist in /etc/passwd?Options
Option 1: Error on unknown users ❌
- Contradicts "works with non-existing paths" philosophy
- Less useful for planning future multi-user systems
Option 2: Silent literal fallback
~alice→./~alice/file.txtif user doesn't exist- Too magical, hard to debug
Option 3: Current user only 😐
- Expand
~but not~alice - Inconsistent, feels incomplete
Option 4: Best-effort with heuristics ✅ Recommended
- Existing user → authoritative lookup
- Non-existing user → platform convention (
/home/aliceor/Users/alice) - Aligns with library philosophy: path may not exist, that's OK
- Clear documented behavior
Option 5: Configurable policy 🔧
- Add
ExpansionPolicyenum - Maximum flexibility, more complex API
Option 6: Don't implement 🚫
- Users compose with
shellexpandcrate themselves - Maintains clear separation of concerns
Implementation Notes (Option 4)
fn expand_tilde_user(username: &str, rest: &str) -> io::Result<PathBuf> {
// Try system lookup first
if let Some(home) = lookup_user_home(username) {
return Ok(home.join(rest)); // Authoritative
}
// Fallback: platform conventions
#[cfg(target_os = "macos")]
let home = PathBuf::from("/Users").join(username);
#[cfg(not(target_os = "macos"))]
let home = PathBuf::from("/home").join(username);
Ok(home.join(rest))
}Dependencies
With feature enabled:
shellexpand(~20KB) - may need fork/patch for best-effort behaviordirs- home directory detectionbstr- byte string utilities
Total: ~3 small, well-maintained crates
Questions for Discussion
- Which option for non-existing users? (Recommendation: Option 4)
- Is best-effort expansion acceptable? Will
/home/aliceassumption work? - Implementation approach: DIY, fork shellexpand, or use as-is?
- Environment variables: Same policy as users or stricter?
- Windows: Feature doesn't compile on Windows (cfg-gated)?
- Should this be in the library at all? Or keep as separate concern?
Feedback needed: The non-existing user dilemma is critical. Which approach makes most sense for this library's philosophy?
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
discussionenhancementNew feature or requestNew feature or requestfeaturehelp wantedExtra attention is neededExtra attention is needed