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

Example code to skip hidden files breaks WalkDir::new(".") #154

Open
kpcyrd opened this issue Sep 7, 2021 · 1 comment
Open

Example code to skip hidden files breaks WalkDir::new(".") #154

kpcyrd opened this issue Sep 7, 2021 · 1 comment

Comments

@kpcyrd
Copy link

kpcyrd commented Sep 7, 2021

This is currently recommended to skip hidden directories in the docs:

use walkdir::{DirEntry, WalkDir};

fn is_hidden(entry: &DirEntry) -> bool {
    entry.file_name()
         .to_str()
         .map(|s| s.starts_with("."))
         .unwrap_or(false)
}

for entry in WalkDir::new("foo")
                     .into_iter()
                     .filter_entry(|e| !is_hidden(e)) {
    println!("{}", entry?.path().display());
}

This works well for foo, but breaks if . is provided instead (playground):

use walkdir::{WalkDir, DirEntry}; // 2.3.2

fn matches(entry: &DirEntry) -> bool {
    let hidden = entry.file_name()
         .to_str()
         .map(|s| s.starts_with("."))
         .unwrap_or(false);

    if hidden {
        println!("Skipping because hidden: {:?}", entry);
    }

    !hidden
}

fn walk(path: &str) {
    println!("Walking: {:?}", path);
    let walker = WalkDir::new(path).into_iter();
    for entry in walker.filter_entry(matches) {
        println!("{:?}", entry);
    }
}

fn main() {
    walk(".");
    walk("/etc");
}

Output:

Walking: "."
Skipping because hidden: DirEntry(".")
Walking: "/etc"
Ok(DirEntry("/etc"))
Ok(DirEntry("/etc/issue.net"))
Ok(DirEntry("/etc/bindresvport.blacklist"))
Ok(DirEntry("/etc/rc1.d"))
Ok(DirEntry("/etc/hostname"))
Ok(DirEntry("/etc/xattr.conf"))
Ok(DirEntry("/etc/resolv.conf"))
Ok(DirEntry("/etc/pam.conf"))
Ok(DirEntry("/etc/mke2fs.conf"))
Ok(DirEntry("/etc/e2scrub.conf"))
Ok(DirEntry("/etc/update-motd.d"))
Ok(DirEntry("/etc/update-motd.d/50-motd-news"))
Ok(DirEntry("/etc/update-motd.d/10-help-text"))
Ok(DirEntry("/etc/update-motd.d/00-header"))
Ok(DirEntry("/etc/update-motd.d/60-unminimize"))
Ok(DirEntry("/etc/terminfo"))
Ok(DirEntry("/etc/terminfo/README"))
Ok(DirEntry("/etc/alternatives"))
Ok(DirEntry("/etc/alternatives/w"))
Ok(DirEntry("/etc/alternatives/README"))
Ok(DirEntry("/etc/alternatives/pager"))
Ok(DirEntry("/etc/alternatives/awk"))
Ok(DirEntry("/etc/alternatives/nawk"))
Ok(DirEntry("/etc/alternatives/rmt"))
Ok(DirEntry("/etc/alternatives/lzma"))
Ok(DirEntry("/etc/alternatives/rsh"))
Ok(DirEntry("/etc/alternatives/cpp"))
Ok(DirEntry("/etc/alternatives/fakeroot"))
Ok(DirEntry("/etc/alternatives/lzfgrep"))
Ok(DirEntry("/etc/alternatives/cc"))
Ok(DirEntry("/etc/alternatives/lzcat"))
Ok(DirEntry("/etc/alternatives/c++"))
Ok(DirEntry("/etc/alternatives/lzegrep"))
Ok(DirEntry("/etc/alternatives/c99"))
Ok(DirEntry("/etc/alternatives/lzgrep"))
Ok(DirEntry("/etc/alternatives/unlzma"))
Ok(DirEntry("/etc/alternatives/lzmore"))
Ok(DirEntry("/etc/alternatives/lzless"))
Ok(DirEntry("/etc/alternatives/lzdiff"))
Ok(DirEntry("/etc/alternatives/rcp"))
Ok(DirEntry("/etc/alternatives/c89"))
Ok(DirEntry("/etc/alternatives/rlogin"))
Ok(DirEntry("/etc/alternatives/lzcmp"))
Ok(DirEntry("/etc/alternatives/pinentry"))
Ok(DirEntry("/etc/ld.so.cache"))
Ok(DirEntry("/etc/networks"))
Ok(DirEntry("/etc/profile"))
Ok(DirEntry("/etc/debconf.conf"))
Ok(DirEntry("/etc/security"))
Ok(DirEntry("/etc/security/limits.conf"))
Ok(DirEntry("/etc/security/access.conf"))
Ok(DirEntry("/etc/security/sepermit.conf"))
Ok(DirEntry("/etc/security/faillock.conf"))
Ok(DirEntry("/etc/security/opasswd"))
Ok(DirEntry("/etc/security/namespace.init"))
Ok(DirEntry("/etc/security/namespace.d"))
Ok(DirEntry("/etc/security/limits.d"))
Ok(DirEntry("/etc/security/pam_env.conf"))
Ok(DirEntry("/etc/security/group.conf"))
Ok(DirEntry("/etc/security/time.conf"))
Ok(DirEntry("/etc/security/namespace.conf"))
Skipping because hidden: DirEntry("/etc/.pwd.lock")
Ok(DirEntry("/etc/gai.conf"))
Ok(DirEntry("/etc/dpkg"))
Ok(DirEntry("/etc/dpkg/dpkg.cfg"))
Ok(DirEntry("/etc/dpkg/origins"))
Ok(DirEntry("/etc/dpkg/origins/ubuntu"))
Ok(DirEntry("/etc/dpkg/origins/default"))
Ok(DirEntry("/etc/dpkg/origins/debian"))
Ok(DirEntry("/etc/dpkg/dpkg.cfg.d"))
Ok(DirEntry("/etc/dpkg/dpkg.cfg.d/excludes"))
Ok(DirEntry("/etc/dpkg/dpkg.cfg.d/docker-apt-speedup"))
Ok(DirEntry("/etc/dpkg/dpkg.cfg.d/pkg-config-hook-config"))
Ok(DirEntry("/etc/dpkg/shlibs.override"))
Ok(DirEntry("/etc/dpkg/shlibs.default"))
Ok(DirEntry("/etc/rc3.d"))
Ok(DirEntry("/etc/fstab"))
Ok(DirEntry("/etc/gshadow"))
Ok(DirEntry("/etc/sysctl.conf"))
Ok(DirEntry("/etc/rc2.d"))
Ok(DirEntry("/etc/selinux"))
Ok(DirEntry("/etc/selinux/semanage.conf"))
Ok(DirEntry("/etc/ld.so.conf.d"))
Ok(DirEntry("/etc/ld.so.conf.d/libc.conf"))
Ok(DirEntry("/etc/ld.so.conf.d/x86_64-linux-gnu.conf"))
Ok(DirEntry("/etc/ld.so.conf.d/fakeroot-x86_64-linux-gnu.conf"))
Ok(DirEntry("/etc/os-release"))
Ok(DirEntry("/etc/libaudit.conf"))
Ok(DirEntry("/etc/login.defs"))
Ok(DirEntry("/etc/skel"))
Skipping because hidden: DirEntry("/etc/skel/.bash_logout")
Skipping because hidden: DirEntry("/etc/skel/.profile")
Skipping because hidden: DirEntry("/etc/skel/.bashrc")
Ok(DirEntry("/etc/shells"))
Ok(DirEntry("/etc/rc4.d"))
Ok(DirEntry("/etc/cron.d"))
[...]

I'm wondering if walkdir::FilterEntry could be extended with a method to make the initial path skip the filter. Alternatively is_hidden could be enhanced to check for . and .. since filter_entry should never try these unless the path was the initial folder.

The example code in the docs should be updated to include this change.

Thanks!

@gifnksm
Copy link

gifnksm commented Aug 27, 2022

For reference, using entry.path().file_name() instead of entry.file_name() seems to work.

fn is_hidden(entry: &walkdir::DirEntry) -> bool {
    entry
        .path()
        .file_name()
        .and_then(|file_name| file_name.to_str().map(|s| s.starts_with('.')))
        .unwrap_or(false)
}

Path::new(".").file_name() and Path::new("..").file_name() return None.

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=264e8981f52264894f80691bbb0969d4

In this case, walkdir::DirEntry::file_name returns the entire path, which is incorrectly determined to be a hidden file.

walkdir/src/dent.rs

Lines 166 to 168 in abf3a15

pub fn file_name(&self) -> &OsStr {
self.path.file_name().unwrap_or_else(|| self.path.as_os_str())
}

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

2 participants