/* * Copyright 2026 Flix Authors * * Use of this source code is governed by the Apache 2.0 license * that can be found in the LICENSE.md file. */////// Effect for finding files matching a glob pattern, and its functions.///pubmod Fs.Glob {use Fs.FileSystemuse Fs.FsLayer.{logPre, logPost}////// Effect for finding files matching a glob pattern.///pubeffGlob {////// Returns a list of paths under `base` that match the given glob `pattern`.///defglob(base: String, pattern: String): Result[IoError, List[String]] }////// Handles the `Glob` effect of the given function `f`.////// In other words, re-interprets the `Glob` effect using the `IO` effect.///pubdefhandle(f: a -> b \ ef): a -> b \ (ef - Glob) + IO = x ->run { f(x) } withhandlerGlob {defglob(base, pattern, k) = k(Fs.FsLayer.glob(base, pattern)) }////// Runs the `Glob` effect of the given function `f`.////// In other words, re-interprets the `Glob` effect using the `IO` effect.///@DefaultHandlerpubdefrunWithIO(f: Unit -> a \ ef): a \ (ef - Glob) + IO = handle(f)()////// Handles the `Glob` effect of the given function `f` using the `FileSystem` effect.///pubdefrunWithFileSystem(f: Unit -> a \ ef): a \ (ef - Glob) + FileSystem =run { f() } withhandlerGlob {defglob(base, pattern, k) = k(Fs.FileSystem.glob(base, pattern)) }////// Middleware that intercepts the `Glob` effect, logging each operation/// and its result via the `Logger` effect.////// Successful operations are logged at `Debug` level; errors at `Warn`.///pubdefwithLogging(f: Unit -> a \ ef): a \ (ef - Glob) + { Glob, Logger } =run { f() } withhandlerGlob {defglob(base, pattern, k) = {logPre("glob", base);letresult = Glob.glob(base, pattern);logPost("glob", base, ls -> "${List.length(ls)} matches", result);k(result) } }////// Middleware that intercepts the `Glob` effect, resolving all file paths/// relative to the given `baseDir` using Java's `Path.resolve` semantics.////// Absolute paths are passed through unchanged.///pubdefwithBaseDir(baseDir: String, f: Unit -> a \ ef): a \ (ef - Glob) + Glob =letr = p -> Fs.FsLayer.resolve(baseDir, p);run { f() } withhandlerGlob {defglob(base, pattern, k) = k(Glob.glob(r(base), pattern)) }////// Middleware that intercepts the `Glob` effect, validating that all base paths/// resolve within the given `chrootDir`. Rejects paths that escape the chroot with/// a `PermissionDenied` error.///pubdefwithChroot(chrootDir: String, f: Unit -> a \ ef): a \ (ef - Glob) + Glob =letc = p -> Fs.FsLayer.chroot(chrootDir, p);run { f() } withhandlerGlob {defglob(base, pattern, k) = k(Result.flatMap(p -> Glob.glob(p, pattern), c(base))) }////// Middleware that intercepts the `Glob` effect, validating that all base paths/// resolve within one of the given `allowedDirs`. Rejects paths outside the/// allow list with a `PermissionDenied` error.///pubdefwithAllowList(allowedDirs: Nel[String], f: Unit -> a \ ef): a \ (ef - Glob) + Glob =letc = p -> Fs.FsLayer.allowList(allowedDirs, p);run { f() } withhandlerGlob {defglob(base, pattern, k) = k(Result.flatMap(p -> Glob.glob(p, pattern), c(base))) }////// Middleware that intercepts the `Glob` effect, validating that all base paths/// do not resolve within any of the given `deniedDirs`. Rejects paths inside a/// denied directory with a `PermissionDenied` error.///pubdefwithDenyList(deniedDirs: Nel[String], f: Unit -> a \ ef): a \ (ef - Glob) + Glob =letc = p -> Fs.FsLayer.denyList(deniedDirs, p);run { f() } withhandlerGlob {defglob(base, pattern, k) = k(Result.flatMap(p -> Glob.glob(p, pattern), c(base))) }////// Middleware that intercepts the `Glob` effect, validating that all base paths/// match at least one of the given glob `patterns`. Rejects paths that do not match/// with a `PermissionDenied` error.///pubdefwithAllowGlob(patterns: Nel[String], f: Unit -> a \ ef): a \ (ef - Glob) + Glob =letc = p -> Fs.FsLayer.allowGlob(patterns, p);run { f() } withhandlerGlob {defglob(base, pattern, k) = k(Result.flatMap(p -> Glob.glob(p, pattern), c(base))) }////// Middleware that intercepts the `Glob` effect, validating that all base paths/// do not match any of the given glob `patterns`. Rejects paths that match a denied/// pattern with a `PermissionDenied` error.///pubdefwithDenyGlob(patterns: Nel[String], f: Unit -> a \ ef): a \ (ef - Glob) + Glob =letc = p -> Fs.FsLayer.denyGlob(patterns, p);run { f() } withhandlerGlob {defglob(base, pattern, k) = k(Result.flatMap(p -> Glob.glob(p, pattern), c(base))) }////// Middleware that intercepts the `Glob` effect, resolving all base paths/// to their real filesystem targets by following symlinks.///pubdefwithFollowLinks(f: Unit -> a \ ef): a \ (ef - Glob) + Glob =letresolve = p -> Fs.FsLayer.resolveRealPathOrSelf(p);run { f() } withhandlerGlob {defglob(base, pattern, k) = k(Glob.glob(resolve(base), pattern)) }}