predicates-rs icon indicating copy to clipboard operation
predicates-rs copied to clipboard

predicates::path::missing() should handle broken symlinks

Open gibfahn opened this issue 3 years ago • 2 comments

The docs for predicates::path::missing() say:

Creates a new Predicate that ensures the path doesn’t exist.

However, if the path is a symlink pointing to nothing, then it will be treated as not existing, when in fact the symlink is a file that exists.

Open to the idea that a broken link should count as not existing, but either way it would be useful for the function's docs to cover this.

It also gets complicated as a symlink may start to exist or not exist based on changes to other parts of the filesystem.

I tried this code:

use predicates::prelude::*;
use std::{fs, os::unix, path::Path};

fn main() {
    let _ = fs::remove_file("symlink-to-non-existent-path");
    unix::fs::symlink("non-existent-path", "symlink-to-non-existent-path").unwrap();

    let predicate_fn = predicate::path::missing();
    // Shouldn't be missing as symlink is a real file.
    assert_eq!(false, predicate_fn.eval(Path::new("non-existent-file.foo")));
}

I expected the assert to pass, but it failed.

Meta

predicates-rs version: 2.1.0 rustc --version: 1.57.0

I think instead of:

    fn eval(&self, path: &path::Path) -> bool {
        path.exists() == self.exists
    }
    fn eval(&self, path: &path::Path) -> bool {
        ( path.exists() || path.symlink_metadata().is_ok() ) == self.exists
    }

gibfahn avatar Dec 29 '21 22:12 gibfahn

Happy to raise a PR for this.

gibfahn avatar Dec 30 '21 07:12 gibfahn

Thanks for creating this issue!

I feel like matching path.exists() will most meet people's expectations and I worry changing it will break someone and would rather not break compatibility.

I can see us exposing an API with more specific checks (is_file, is_dir, is_symlink) and the corresponding predicate struct could have a follow_symlinks(false) function to customize it, like we do with utf8 on other predicates.

The main question is ow to expose this. Some ideas:

  • is_file, is_dir, is_symlink
  • file_type(FileType::File)
  • file_type(FileType::FILE | FileType::DIR).

epage avatar Dec 30 '21 20:12 epage