mirror of
https://github.com/sharkdp/fd
synced 2024-10-14 19:54:37 +00:00
Enhanced Windows support, see #70
* Use easier way to convert path components * Fix failing tests on Windows
This commit is contained in:
parent
a84536a173
commit
4731dc670c
|
@ -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)
|
||||||
|
}
|
||||||
|
|
22
src/main.rs
22
src/main.rs
|
@ -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 {
|
||||||
|
|
|
@ -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"))?;
|
||||||
|
|
||||||
|
|
|
@ -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!(
|
||||||
|
|
Loading…
Reference in a new issue