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

Include only files matching a glob #81

Open
ajeetdsouza opened this issue May 13, 2022 · 5 comments
Open

Include only files matching a glob #81

ajeetdsouza opened this issue May 13, 2022 · 5 comments

Comments

@ajeetdsouza
Copy link

It would be great if we could include just the files matching a particular glob. This is similar to #13, but I think a glob design would be far easier to use.

@Michael-F-Bryan
Copy link
Owner

Michael-F-Bryan commented May 15, 2022

Do you have an idea of what this might look like from a consumer's point of view?

@ajeetdsouza
Copy link
Author

I'd think that ideally, it would be inspired by the gitignore syntax.

include_dir!(
  "$CARGO_MANIFEST_DIR/assets/*", # include all files in assets folder
  "!$CARGO_MANIFEST_DIR/assets/.cache" # except .cache folder
  "$CARGO_MANIFEST_DIR/images/*.png" # include PNG images from here
);

@ModProg
Copy link

ModProg commented Jun 21, 2022

I have a similar requirement, I actually just need to include files matching a glob as a Vec of Strings.

@demurgos
Copy link

demurgos commented Sep 25, 2022

Do you have an idea of what this might look like from a consumer's point of view?

After having encountered this problem of picking a subtree from a directory multiple times, there are two things I'd recommend for a good API.

  1. The directory acting as the root must be explicit and unambiguous. You need to know 100% where is the boundary.
  2. The filters should be defined relative to the inclusion root. This allows better composability and symmetry with .find. For example, it allows easy merging / virtual overlay FS setups.

Let's take an example. The code below prints all the Rust files in the current project:

static PROJECT_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR");

for entry in PROJECT_DIR.find("**/*.rs").unwrap() {
    println!("Found {}", entry.path().display());
}

This is a prime candidate to apply filtering at inclusion time. Following the points above, I'd recommend the following API with an optional filter / match / find / whatever argument:

static PROJECT_DIR_ONLY_RUST: Dir = include_dir!("$CARGO_MANIFEST_DIR", filter = "**/*.rs");

// This `find` is only a simple traversal of what's embedded, no filtering occurs at runtime
for entry in PROJECT_DIR_ONLY_RUST.find("**/*").unwrap() {
    println!("Found {}", entry.path().display()); // Same output as the previous program
}

Notice how the code above is close to the original. You can simply think of it as moving the runtime glob matching to compile time. Further extensions may allow an array as the list of filters, but for the moment I'd recommend to start simply with a single pattern and make sure it works fine.

Adding support for a list of multiple patterns requires a bit of care. In general I agree that the best semantics should be to follow how .gitignore matches files: you can mix positive and negative filters in any order and they act as set operators on the list of files. There are some patterns that can't be expressed if you use two lists (one positive, one negative) instead of a singled mixed list of both positive and negative rules.

@kylecarow
Copy link

I use this crate for packaging serialized 'resource' files in various formats, so being able to include only the applicable formats (as controlled by my crate's features) would be excellent!

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

5 participants