Files

Glob

Files found by glob patterns like docs/**/*.md, with patterns to leave out, and paths tested against patterns.

Version 1.0.0 · 3 functions · 2 crates

#files#folders#search

Functions

What use glob.qwer gives a program, with the types Quillo sees. To take only some, or under other names: use glob_files, glob_match from glob (Quillo 0.6).

glob_files(base: str, patterns: list, exclude: list) → listor an error

The files under the folder base matching any of patterns, and none of exclude, as paths relative to base, sorted. * stays within a folder, ** crosses folders, ? is one character, {a,b} either, [abc] one of them. Links are not followed; at most 100,000 results.

glob_match(pattern: str, path: str) → boolor an error

Whether path matches the glob pattern, with the same rules: "src/**/*.rs" matches "src/a/b.rs" and "src/b.rs".

glob_filter(paths: list, patterns: list) → listor an error

The paths (any text: names from a database, keys in a bucket) that match any of patterns, in their order.

Get it

$ quillo install glob               # glob.qwer into this folder$ quillo install glob --example     # and its example, glob.qwe

Or with curl:

$ curl -O https://quillolang.org/plugins/files/glob.qwer$ curl -O https://quillolang.org/plugins/files/glob.qwe

Then, in your program, all of it or only what you call:

main.qwe
use glob.qweruse glob_files, glob_match from glob      // Quillo 0.6: only these

It uses these crates, which cargo fetches the first time the plugin is built:

[dependencies]
globset = "0.4"walkdir = "2"

Example

glob.qwe
// A docs site that finds its pages by pattern, and an asset list filtered the same way.////   quillo run glob.qwe      then open http://localhost:8080/pagesuse "glob.qwer"fn seed() {    write_file("data/site/docs/index.md", "# Docs")    write_file("data/site/docs/guide/routes.md", "# Routes")    write_file("data/site/docs/guide/drafts/next.md", "# Soon")    write_file("data/site/docs/logo.png", "png")    write_file("data/site/blog/hello.md", "# Hello")}route GET /pages {    seed()    glob_files("data/site", ["docs/**/*.md", "blog/*.md"], ["**/drafts/**"])}route GET /match = {    nested: glob_match("docs/**/*.md", "docs/guide/routes.md")?,    one_level: glob_match("docs/*.md", "docs/guide/routes.md")?,    images: glob_filter(["a.jpg", "b.PNG", "c.png", "notes.txt"], ["*.{jpg,png}"])?,}
$ quillo run glob.qwe$ curl 'localhost:8080/pages'$ curl 'localhost:8080/match'

Source

glob.qwer
//! Files found by glob patterns such as "docs/**/*.md" or "*.{jpg,png}", with patterns to leave out, and paths tested against patterns.//! version: 1.0.0//!//! [dependencies]//! globset = "0.4"//! walkdir = "2"const MAX_RESULTS: usize = 100_000;const MAX_SEEN: usize = 1_000_000;fn set(patterns: &[String]) -> Result<globset::GlobSet, String> {    let mut b = globset::GlobSetBuilder::new();    for p in patterns {        let g = globset::GlobBuilder::new(p.trim_start_matches("./")).literal_separator(true).backslash_escape(true).build().map_err(|e| format!("`{}`: {}", p, e))?;        b.add(g);    }    b.build().map_err(|e| e.to_string())}/// The files under the folder `base` matching any of `patterns`, and none of `exclude`, as paths relative to `base`, sorted./// `*` stays within a folder, `**` crosses folders, `?` is one character, `{a,b}` either, `[abc]` one of them. Links are not followed; at most 100,000 results.pub fn glob_files(base: &str, patterns: Vec<String>, exclude: Vec<String>) -> Result<Vec<String>, String> {    let root = std::path::Path::new(if base.is_empty() { "." } else { base });    if !root.is_dir() {        return Err(format!("{}: not a folder", base));    }    let want = set(&patterns)?;    let skip = set(&exclude)?;    let mut out = vec![];    for (seen, e) in walkdir::WalkDir::new(root).min_depth(1).follow_links(false).into_iter().filter_map(Result::ok).enumerate() {        if seen > MAX_SEEN || out.len() >= MAX_RESULTS {            break;        }        if !e.file_type().is_file() {            continue;        }        let rel = e.path().strip_prefix(root).unwrap_or(e.path()).to_string_lossy().replace('\\', "/");        if want.is_match(&rel) && !skip.is_match(&rel) {            out.push(rel);        }    }    out.sort();    Ok(out)}/// Whether `path` matches the glob `pattern`, with the same rules: "src/**/*.rs" matches "src/a/b.rs" and "src/b.rs".pub fn glob_match(pattern: &str, path: &str) -> Result<bool, String> {    Ok(set(&[pattern.to_string()])?.is_match(path.trim_start_matches("./")))}/// The `paths` (any text: names from a database, keys in a bucket) that match any of `patterns`, in their order.pub fn glob_filter(paths: Vec<String>, patterns: Vec<String>) -> Result<Vec<String>, String> {    let s = set(&patterns)?;    Ok(paths.into_iter().filter(|p| s.is_match(p.trim_start_matches("./"))).collect())}
Thread
77Useful? Like it, or add to its thread below.

Thread 0 posts

On Glob: questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.