Enhanced Windows support, see #70

* Use easier way to convert path components
* Fix failing tests on Windows
This commit is contained in:
David Peter 2017-10-07 09:40:44 +02:00 committed by GitHub
parent a84536a173
commit 4731dc670c
4 changed files with 24 additions and 19 deletions

View File

@ -1,4 +1,5 @@
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::io;
/// Get a relative path with respect to a certain base path. /// Get a relative path with respect to a certain base path.
/// See: https://stackoverflow.com/a/39343127/704831 /// See: https://stackoverflow.com/a/39343127/704831
@ -41,3 +42,12 @@ pub fn path_relative_from(path: &Path, base: &Path) -> Option<PathBuf> {
Some(comps.iter().map(|c| c.as_os_str()).collect()) Some(comps.iter().map(|c| c.as_os_str()).collect())
} }
} }
pub fn absolute_path(path: &Path) -> io::Result<PathBuf> {
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)
}

View File

@ -10,14 +10,13 @@ pub mod lscolors;
pub mod fshelper; pub mod fshelper;
mod app; mod app;
use std::borrow::Cow;
use std::env; use std::env;
use std::error::Error; use std::error::Error;
use std::io::Write; use std::io::Write;
use std::ops::Deref; use std::ops::Deref;
#[cfg(target_family = "unix")] #[cfg(unix)]
use std::os::unix::fs::PermissionsExt; use std::os::unix::fs::PermissionsExt;
use std::path::{Component, Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process; use std::process;
use std::sync::Arc; use std::sync::Arc;
use std::sync::mpsc::channel; use std::sync::mpsc::channel;
@ -111,10 +110,11 @@ enum ReceiverMode {
} }
/// Root directory /// Root directory
#[cfg(unix)]
static ROOT_DIR: &'static str = "/"; static ROOT_DIR: &'static str = "/";
/// Parent directory #[cfg(windows)]
static PARENT_DIR: &'static str = ".."; static ROOT_DIR: &'static str = "";
/// Print a search result to the console. /// Print a search result to the console.
fn print_entry(base: &Path, entry: &PathBuf, config: &FdOptions) { 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(); let path_str = entry.to_string_lossy();
#[cfg(target_family = "unix")] #[cfg(unix)]
let is_executable = |p: Option<&std::fs::Metadata>| { let is_executable = |p: Option<&std::fs::Metadata>| {
p.map(|f| f.permissions().mode() & 0o111 != 0) p.map(|f| f.permissions().mode() & 0o111 != 0)
.unwrap_or(false) .unwrap_or(false)
}; };
#[cfg(not(target_family = "unix"))] #[cfg(windows)]
let is_executable = |_: Option<&std::fs::Metadata>| false; let is_executable = |_: Option<&std::fs::Metadata>| false;
let stdout = std::io::stdout(); 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 // Traverse the path and colorize each component
for component in entry.components() { for component in entry.components() {
let comp_str = match component { let comp_str = component.as_os_str().to_string_lossy();
Component::Normal(p) => p.to_string_lossy(),
Component::ParentDir => Cow::from(PARENT_DIR),
_ => error("Error: unexpected path component.")
};
component_path.push(Path::new(comp_str.deref())); component_path.push(Path::new(comp_str.deref()));
@ -373,7 +369,7 @@ fn main() {
root_dir_is_absolute = path.is_absolute(); 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)) |_| error(&format!("Error: could not find directory '{}'.", rd))
) )
} else { } else {

View File

@ -47,6 +47,8 @@ fn create_working_directory() -> Result<TempDir, io::Error> {
#[cfg(unix)] #[cfg(unix)]
unix::fs::symlink(root.join("one/two"), root.join("symlink"))?; 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)] #[cfg(windows)]
windows::fs::symlink_dir(root.join("one/two"), root.join("symlink"))?; windows::fs::symlink_dir(root.join("one/two"), root.join("symlink"))?;

View File

@ -1,7 +1,5 @@
//! Integration tests for the CLI interface of fd. //! Integration tests for the CLI interface of fd.
#![allow(dead_code, unused_imports)]
mod testenv; mod testenv;
use testenv::TestEnv; use testenv::TestEnv;
@ -39,8 +37,6 @@ fn test_simple() {
} }
/// Explicit root path /// Explicit root path
// TODO: Fails on windows
#[cfg_attr(windows, ignore)]
#[test] #[test]
fn test_explicit_root_path() { fn test_explicit_root_path() {
let te = TestEnv::new(); let te = TestEnv::new();
@ -239,8 +235,6 @@ fn test_max_depth() {
} }
/// Absolute paths (--absolute-path) /// Absolute paths (--absolute-path)
// TODO: fails on windows
#[cfg_attr(windows, ignore)]
#[test] #[test]
fn test_absolute_path() { fn test_absolute_path() {
let te = TestEnv::new(); let te = TestEnv::new();
@ -250,6 +244,9 @@ fn test_absolute_path() {
.to_str().expect("string") .to_str().expect("string")
.to_string(); .to_string();
#[cfg(windows)]
let abs_path = abs_path.trim_left_matches(r"\\?\");
te.assert_output( te.assert_output(
&["--absolute-path", "foo"], &["--absolute-path", "foo"],
&format!( &format!(