From 4731dc670c1b2050e1d8b1c33fae47551eb2b990 Mon Sep 17 00:00:00 2001 From: David Peter Date: Sat, 7 Oct 2017 09:40:44 +0200 Subject: [PATCH] Enhanced Windows support, see #70 * Use easier way to convert path components * Fix failing tests on Windows --- src/fshelper/mod.rs | 10 ++++++++++ src/main.rs | 22 +++++++++------------- tests/testenv/mod.rs | 2 ++ tests/tests.rs | 9 +++------ 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/fshelper/mod.rs b/src/fshelper/mod.rs index c088ccb..72eabc1 100644 --- a/src/fshelper/mod.rs +++ b/src/fshelper/mod.rs @@ -1,4 +1,5 @@ use std::path::{Path, PathBuf}; +use std::io; /// Get a relative path with respect to a certain base path. /// See: https://stackoverflow.com/a/39343127/704831 @@ -41,3 +42,12 @@ pub fn path_relative_from(path: &Path, base: &Path) -> Option { Some(comps.iter().map(|c| c.as_os_str()).collect()) } } + +pub fn absolute_path(path: &Path) -> io::Result { + let path_buf = path.canonicalize()?; + + #[cfg(windows)] + let path_buf = Path::new(path_buf.as_path().to_string_lossy().trim_left_matches(r"\\?\")).to_path_buf(); + + Ok(path_buf) +} diff --git a/src/main.rs b/src/main.rs index 3dc03f6..16a8e98 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,14 +10,13 @@ pub mod lscolors; pub mod fshelper; mod app; -use std::borrow::Cow; use std::env; use std::error::Error; use std::io::Write; use std::ops::Deref; -#[cfg(target_family = "unix")] +#[cfg(unix)] use std::os::unix::fs::PermissionsExt; -use std::path::{Component, Path, PathBuf}; +use std::path::{Path, PathBuf}; use std::process; use std::sync::Arc; use std::sync::mpsc::channel; @@ -111,10 +110,11 @@ enum ReceiverMode { } /// Root directory +#[cfg(unix)] static ROOT_DIR: &'static str = "/"; -/// Parent directory -static PARENT_DIR: &'static str = ".."; +#[cfg(windows)] +static ROOT_DIR: &'static str = ""; /// Print a search result to the console. fn print_entry(base: &Path, entry: &PathBuf, config: &FdOptions) { @@ -122,13 +122,13 @@ fn print_entry(base: &Path, entry: &PathBuf, config: &FdOptions) { let path_str = entry.to_string_lossy(); - #[cfg(target_family = "unix")] + #[cfg(unix)] let is_executable = |p: Option<&std::fs::Metadata>| { p.map(|f| f.permissions().mode() & 0o111 != 0) .unwrap_or(false) }; - #[cfg(not(target_family = "unix"))] + #[cfg(windows)] let is_executable = |_: Option<&std::fs::Metadata>| false; let stdout = std::io::stdout(); @@ -145,11 +145,7 @@ fn print_entry(base: &Path, entry: &PathBuf, config: &FdOptions) { // Traverse the path and colorize each component for component in entry.components() { - let comp_str = match component { - Component::Normal(p) => p.to_string_lossy(), - Component::ParentDir => Cow::from(PARENT_DIR), - _ => error("Error: unexpected path component.") - }; + let comp_str = component.as_os_str().to_string_lossy(); component_path.push(Path::new(comp_str.deref())); @@ -373,7 +369,7 @@ fn main() { root_dir_is_absolute = path.is_absolute(); - path.canonicalize().unwrap_or_else( + fshelper::absolute_path(path).unwrap_or_else( |_| error(&format!("Error: could not find directory '{}'.", rd)) ) } else { diff --git a/tests/testenv/mod.rs b/tests/testenv/mod.rs index 418bf13..f1d90ed 100644 --- a/tests/testenv/mod.rs +++ b/tests/testenv/mod.rs @@ -47,6 +47,8 @@ fn create_working_directory() -> Result { #[cfg(unix)] unix::fs::symlink(root.join("one/two"), root.join("symlink"))?; + // Note: creating symlinks on Windows requires the `SeCreateSymbolicLinkPrivilege` which + // is by default only granted for administrators. #[cfg(windows)] windows::fs::symlink_dir(root.join("one/two"), root.join("symlink"))?; diff --git a/tests/tests.rs b/tests/tests.rs index 86550e2..327c0bd 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1,7 +1,5 @@ //! Integration tests for the CLI interface of fd. -#![allow(dead_code, unused_imports)] - mod testenv; use testenv::TestEnv; @@ -39,8 +37,6 @@ fn test_simple() { } /// Explicit root path -// TODO: Fails on windows -#[cfg_attr(windows, ignore)] #[test] fn test_explicit_root_path() { let te = TestEnv::new(); @@ -239,8 +235,6 @@ fn test_max_depth() { } /// Absolute paths (--absolute-path) -// TODO: fails on windows -#[cfg_attr(windows, ignore)] #[test] fn test_absolute_path() { let te = TestEnv::new(); @@ -250,6 +244,9 @@ fn test_absolute_path() { .to_str().expect("string") .to_string(); + #[cfg(windows)] + let abs_path = abs_path.trim_left_matches(r"\\?\"); + te.assert_output( &["--absolute-path", "foo"], &format!(