Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extracting the relative path #204

Open
konstin opened this issue Nov 14, 2024 · 0 comments
Open

Extracting the relative path #204

konstin opened this issue Nov 14, 2024 · 0 comments

Comments

@konstin
Copy link

konstin commented Nov 14, 2024

I know this has been already discussed in #5, but it's been 8 years so i hope you don't mind me bringing this up again.

In many, if not most cases, where i'm using walkdir, i need the path relative to the root. For example, below is a naive recursive directory copy implementation, but this also applies to anything that needs to do includes or excludes with non-absolute matchers.

Currently, entry.path() does not seem to guarantee that the path starts with the walkdir root (or at least i didn't see that in the docs), the the unwrap could potentially fail, even if i know that i should be able to write code that never fails here.

From an API-perspective, it would be nice to have an infallible .relative_path(). Currently, there are usually two let relative = entry.path().strip_prefix(source_tree).expect("walkdir starts with root"); invocations when i call walkdir, one for filter_entry and one in the for loop body. This API would expose the infallible operation as such and could slim multi-line .filter_entry calls to a single line of .filter_entry(|entry| matches_directory(entry.relative_path()).

use std::error::Error;
use std::io::ErrorKind;
use std::path::Path;
use std::{fs, io};
use walkdir::WalkDir;

fn copy_dir_recursive(source: &Path, target: &Path) -> Result<(), Box<dyn Error>> {
    for entry in WalkDir::new(source) {
        let entry = entry?;
        let path = entry.path();

        let relative = path
            .strip_prefix(&source)
            .expect("walkdir starts with root");
        let out_path = target.join(relative);

        if entry.file_type().is_dir() {
            fs::create_dir_all(&out_path)?;
        } else if entry.file_type().is_file() {
            fs::copy(entry.path(), &out_path)?;
        } else {
            return Err(io::Error::new(
                ErrorKind::Other,
                format!(
                    "Unknown type {:?}: {}",
                    entry.file_type(),
                    entry.path().display()
                ),
            )
            .into());
        }
    }

    Ok(())
}

fn main() -> Result<(), Box<dyn Error>> {
    let source = Path::new("foo");
    let target = Path::new("/root/bar");

    copy_dir_recursive(&source, target)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant