Skip to content

Instantly share code, notes, and snippets.

@voidlizard
Created August 2, 2024 15:50
Show Gist options
  • Select an option

  • Save voidlizard/9d2254cd5787fc6e218b149588da18f3 to your computer and use it in GitHub Desktop.

Select an option

Save voidlizard/9d2254cd5787fc6e218b149588da18f3 to your computer and use it in GitHub Desktop.

Revisions

  1. voidlizard created this gist Aug 2, 2024.
    38 changes: 38 additions & 0 deletions glob.hs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,38 @@
    glob :: forall m . MonadIO m
    => [FilePattern] -- ^ search patterns
    -> [FilePattern] -- ^ ignore patterns
    -> FilePath -- ^ directory
    -> (FilePath -> m Bool) -- ^ file action
    -> m ()

    glob pat ignore dir action = do
    q <- newTQueueIO
    void $ liftIO (async $ go q dir >> atomically (writeTQueue q Nothing))
    fix $ \next -> do
    atomically (readTQueue q) >>= \case
    Nothing -> pure ()
    Just x -> do
    r <- action x
    when r next

    where

    matches p f = or [ i ?== f | i <- p ]
    skip p = or [ i ?== p | i <- ignore ]

    go q f = do

    isD <- doesDirectoryExist f

    if not isD then do
    isF <- doesFileExist f
    when (isF && matches pat f) do
    atomically $ writeTQueue q (Just f)
    else do
    co' <- (try @_ @IOError $ listDirectory f)
    <&> fromRight mempty

    let co = [ normalise (f </> x) | x <- co' ]
    & filter (not . skip)

    forConcurrently_ co (go q)