From 0fc658139d5dd2cf2bd2b190a506516236e19e18 Mon Sep 17 00:00:00 2001 From: Orion Kindel Date: Mon, 17 Jun 2024 15:22:48 -0500 Subject: [PATCH 1/7] fix: gitignoringGlob stack safety + perf --- src/Spago/Glob.js | 2 +- src/Spago/Glob.purs | 89 ++++++++++++++++++++------------------------ test/Spago/Glob.purs | 35 +++++++++++------ 3 files changed, 66 insertions(+), 60 deletions(-) diff --git a/src/Spago/Glob.js b/src/Spago/Glob.js index 7ba9a6c83..c140130d1 100644 --- a/src/Spago/Glob.js +++ b/src/Spago/Glob.js @@ -1,7 +1,7 @@ import mm from 'micromatch'; import * as fsWalk from '@nodelib/fs.walk'; -export const micromatch = options => patterns => mm.matcher(patterns, options); +export const micromatch = options => mm.matcher(options.include, options); export const fsWalkImpl = Left => Right => respond => options => path => () => { const entryFilter = entry => options.entryFilter(entry)(); diff --git a/src/Spago/Glob.purs b/src/Spago/Glob.purs index 1165c2ed4..3789c1e7f 100644 --- a/src/Spago/Glob.purs +++ b/src/Spago/Glob.purs @@ -2,9 +2,12 @@ module Spago.Glob (gitignoringGlob) where import Spago.Prelude +import Control.Alternative (guard) +import Control.Monad.Maybe.Trans (MaybeT(..), runMaybeT) +import Control.Monad.Trans.Class (lift) import Data.Array as Array import Data.Filterable (filter) -import Data.Foldable (any) +import Data.Foldable (any, fold) import Data.String as String import Data.String.CodePoints as String.CodePoint import Effect.Aff as Aff @@ -14,9 +17,12 @@ import Node.Path as Path import Record as Record import Type.Proxy (Proxy(..)) -type MicroMatchOptions = { ignore :: Array String } +type MicroMatchOptions = { ignore :: Array String, include :: Array String } -foreign import micromatch :: MicroMatchOptions -> Array String -> String -> Boolean +foreign import micromatch :: MicroMatchOptions -> String -> Boolean + +splitMicromatch :: MicroMatchOptions -> Array MicroMatchOptions +splitMicromatch {ignore, include} = (\a -> {ignore, include: [a]}) <$> include type Entry = { name :: String, path :: String, dirent :: DirEnt } type FsWalkOptions = { entryFilter :: Entry -> Effect Boolean, deepFilter :: Entry -> Effect Boolean } @@ -31,19 +37,20 @@ foreign import fsWalkImpl -> String -> Effect Unit -gitignoreToMicromatchPatterns :: String -> String -> { ignore :: Array String, patterns :: Array String } +gitignoreToMicromatchPatterns :: String -> String -> { ignore :: Array String, include :: Array String } gitignoreToMicromatchPatterns base = String.split (String.Pattern "\n") >>> map String.trim >>> Array.filter (not <<< or [ String.null, isComment ]) >>> partitionMap ( \line -> do - let negated = isJust $ String.stripPrefix (String.Pattern "!") line - let pattern = Path.concat [ base, gitignorePatternToMicromatch line ] - if negated then Left pattern else Right pattern + let pattern a = Path.concat [ base, gitignorePatternToMicromatch a ] + case String.stripPrefix (String.Pattern "!") line of + Just negated -> Left $ pattern negated + Nothing -> Right $ pattern line ) >>> Record.rename (Proxy :: Proxy "left") (Proxy :: Proxy "ignore") - >>> Record.rename (Proxy :: Proxy "right") (Proxy :: Proxy "patterns") + >>> Record.rename (Proxy :: Proxy "right") (Proxy :: Proxy "include") where isComment = isJust <<< String.stripPrefix (String.Pattern "#") @@ -51,66 +58,52 @@ gitignoreToMicromatchPatterns base = dropPrefixSlash str = fromMaybe str $ String.stripPrefix (String.Pattern "/") str leadingSlash str = String.codePointAt 0 str == Just (String.CodePoint.codePointFromChar '/') - trailingSlash str = String.codePointAt (String.length str - 1) str == Just (String.CodePoint.codePointFromChar '/') gitignorePatternToMicromatch :: String -> String gitignorePatternToMicromatch pattern - | trailingSlash pattern = gitignorePatternToMicromatch $ dropSuffixSlash pattern | leadingSlash pattern = dropPrefixSlash pattern <> "/**" - | otherwise = "**/" <> pattern <> "/**" + | otherwise = "**/" <> dropSuffixSlash pattern <> "/**" fsWalk :: String -> Array String -> Array String -> Aff (Array Entry) fsWalk cwd ignorePatterns includePatterns = Aff.makeAff \cb -> do - let includeMatcher = micromatch { ignore: [] } includePatterns -- The Stuff we are globbing for. + let includeMatcher = micromatch { ignore: [], include: includePatterns } -- Pattern for directories which can be outright ignored. -- This will be updated whenver a .gitignore is found. - ignoreMatcherRef <- Ref.new $ micromatch { ignore: [] } ignorePatterns + ignoreMatcherRef <- Ref.new { ignore: [], include: ignorePatterns } -- If this Ref contains `true` because this Aff has been canceled, then deepFilter will always return false. canceled <- Ref.new false let + entryGitignore :: Entry -> Effect Unit + entryGitignore entry = void $ runMaybeT do + gitignore <- MaybeT $ hush <$> try (SyncFS.readTextFile UTF8 entry.path) + let + base = Path.relative cwd $ Path.dirname entry.path + gitignored = splitMicromatch $ gitignoreToMicromatchPatterns base gitignore + allowsSearch = not <<< flip any includePatterns + newIgnorePatterns = filter (allowsSearch <<< micromatch) gitignored + void + $ lift + $ Ref.modify (_ <> fold newIgnorePatterns) + $ ignoreMatcherRef + -- Should `fsWalk` recurse into this directory? deepFilter :: Entry -> Effect Boolean - deepFilter entry = Ref.read canceled >>= - if _ then - -- The Aff has been canceled, don't recurse into any further directories! - pure false - else do - matcher <- Ref.read ignoreMatcherRef - pure $ not $ matcher (Path.relative cwd entry.path) + deepFilter entry = fromMaybe false <$> runMaybeT do + isCanceled <- lift $ Ref.read canceled + guard $ not isCanceled + shouldIgnore <- lift $ micromatch <$> Ref.read ignoreMatcherRef + pure $ not $ shouldIgnore $ Path.relative cwd entry.path -- Should `fsWalk` retain this entry for the result array? entryFilter :: Entry -> Effect Boolean entryFilter entry = do - when (isFile entry.dirent && entry.name == ".gitignore") do -- A .gitignore was encountered - let gitignorePath = entry.path - - -- directory of this .gitignore relative to the directory being globbed - let base = Path.relative cwd (Path.dirname gitignorePath) - - try (SyncFS.readTextFile UTF8 gitignorePath) >>= case _ of - Left _ -> pure unit - Right gitignore -> do - let { ignore, patterns } = gitignoreToMicromatchPatterns base gitignore - let gitignored = (micromatch { ignore } <<< pure) <$> patterns - let wouldConflictWithSearch m = any m includePatterns - - -- Do not add `.gitignore` patterns that explicitly ignore the files - -- we're searching for; - -- - -- ex. if `includePatterns` is [".spago/p/aff-1.0.0/**/*.purs"], - -- and `gitignored` is ["node_modules", ".spago"], - -- then add "node_modules" to `ignoreMatcher` but not ".spago" - for_ (filter (not <<< wouldConflictWithSearch) gitignored) \pat -> do - -- Instead of composing the matcher functions, we could also keep a growing array of - -- patterns and regenerate the matcher on every append. I don't know which option is - -- more performant, but composing functions is more convenient. - let addMatcher currentMatcher = or [ currentMatcher, pat ] - void $ Ref.modify addMatcher ignoreMatcherRef - - ignoreMatcher <- Ref.read ignoreMatcherRef - let path = withForwardSlashes $ Path.relative cwd entry.path + when (isFile entry.dirent && entry.name == ".gitignore") (entryGitignore entry) + ignorePat <- Ref.read ignoreMatcherRef + let + ignoreMatcher = micromatch ignorePat + path = withForwardSlashes $ Path.relative cwd entry.path pure $ includeMatcher path && not (ignoreMatcher path) options = { entryFilter, deepFilter } diff --git a/test/Spago/Glob.purs b/test/Spago/Glob.purs index a7a8bc47d..e9d5f99e8 100644 --- a/test/Spago/Glob.purs +++ b/test/Spago/Glob.purs @@ -2,10 +2,13 @@ module Test.Spago.Glob where import Test.Prelude +import Data.Foldable (intercalate) +import Data.String.Gen (genAlphaLowercaseString) import Effect.Aff as Aff import Node.Path as Path import Spago.FS as FS import Spago.Glob as Glob +import Test.QuickCheck.Gen (randomSample', resize) import Test.Spec (Spec) import Test.Spec as Spec import Test.Spec.Assertions as Assert @@ -26,11 +29,13 @@ globTmpDir m = Aff.bracket make cleanup m base dir "fruits" - [touch "apple", touch "orange", touch "banana"] - base - dir - "sports" - [touch "baseball", touch "scrabble"] + [ touch "apple" + , touch "orange" + , touch "banana" + , dir "special" + [ touch "apple" + ] + ] base dir "src" @@ -45,17 +50,19 @@ spec = Spec.around globTmpDir do Spec.describe "glob" do Spec.describe "gitignoringGlob" do Spec.it "when no .gitignore, yields all matches" \p -> do - a <- Glob.gitignoringGlob p ["**/fruits/apple/**"] - a `Assert.shouldEqual` ["fruits/apple", "src/fruits/apple"] - - b <- Glob.gitignoringGlob p ["sports/**"] - b `Assert.shouldEqual` ["sports", "sports/baseball", "sports/scrabble"] + a <- Glob.gitignoringGlob p ["**/apple"] + a `Assert.shouldEqual` ["fruits/apple", "fruits/special/apple", "src/fruits/apple"] Spec.it "respects a .gitignore pattern that doesn't conflict with search" \p -> do FS.writeTextFile (Path.concat [p, ".gitignore"]) "/fruits" - a <- Glob.gitignoringGlob p ["src/fruits/apple/**"] + a <- Glob.gitignoringGlob p ["**/apple"] a `Assert.shouldEqual` ["src/fruits/apple"] + Spec.it "respects a negated .gitignore pattern" \p -> do + FS.writeTextFile (Path.concat [p, ".gitignore"]) "!/fruits/special/apple\n/fruits/apple" + a <- Glob.gitignoringGlob p ["**/apple"] + a `Assert.shouldEqual` ["fruits/special/apple", "src/fruits/apple"] + Spec.it "does not respect a .gitignore pattern that conflicts with search" \p -> do for_ ["/fruits", "fruits", "fruits/", "**/fruits", "fruits/**", "**/fruits/**"] \gitignore -> do FS.writeTextFile (Path.concat [p, ".gitignore"]) gitignore @@ -66,3 +73,9 @@ spec = Spec.around globTmpDir do FS.writeTextFile (Path.concat [p, ".gitignore"]) """/fruits\n/src""" a <- Glob.gitignoringGlob p ["fruits/apple/**"] a `Assert.shouldEqual` ["fruits/apple"] + + Spec.it "is stacksafe" \p -> do + hugeGitignore <- liftEffect $ intercalate "\n" <$> randomSample' 10000 (resize 4 $ genAlphaLowercaseString) + FS.writeTextFile (Path.concat [p, ".gitignore"]) hugeGitignore + a <- Glob.gitignoringGlob p ["fruits/apple/**"] + a `Assert.shouldEqual` ["fruits/apple"] From bdeb14d1960910ac6749a48f3082f7a067b00b50 Mon Sep 17 00:00:00 2001 From: Orion Kindel Date: Mon, 17 Jun 2024 15:36:38 -0500 Subject: [PATCH 2/7] fix: formatting --- src/Spago/Glob.purs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/Spago/Glob.purs b/src/Spago/Glob.purs index 3789c1e7f..8bea3f7f5 100644 --- a/src/Spago/Glob.purs +++ b/src/Spago/Glob.purs @@ -10,6 +10,7 @@ import Data.Filterable (filter) import Data.Foldable (any, fold) import Data.String as String import Data.String.CodePoints as String.CodePoint +import Data.Traversable (traverse_) import Effect.Aff as Aff import Effect.Ref as Ref import Node.FS.Sync as SyncFS @@ -22,7 +23,7 @@ type MicroMatchOptions = { ignore :: Array String, include :: Array String } foreign import micromatch :: MicroMatchOptions -> String -> Boolean splitMicromatch :: MicroMatchOptions -> Array MicroMatchOptions -splitMicromatch {ignore, include} = (\a -> {ignore, include: [a]}) <$> include +splitMicromatch { ignore, include } = (\a -> { ignore, include: [ a ] }) <$> include type Entry = { name :: String, path :: String, dirent :: DirEnt } type FsWalkOptions = { entryFilter :: Entry -> Effect Boolean, deepFilter :: Entry -> Effect Boolean } @@ -76,17 +77,18 @@ fsWalk cwd ignorePatterns includePatterns = Aff.makeAff \cb -> do canceled <- Ref.new false let entryGitignore :: Entry -> Effect Unit - entryGitignore entry = void $ runMaybeT do - gitignore <- MaybeT $ hush <$> try (SyncFS.readTextFile UTF8 entry.path) - let - base = Path.relative cwd $ Path.dirname entry.path - gitignored = splitMicromatch $ gitignoreToMicromatchPatterns base gitignore - allowsSearch = not <<< flip any includePatterns - newIgnorePatterns = filter (allowsSearch <<< micromatch) gitignored - void - $ lift - $ Ref.modify (_ <> fold newIgnorePatterns) - $ ignoreMatcherRef + entryGitignore entry = + try (SyncFS.readTextFile UTF8 entry.path) + >>= traverse_ \gitignore -> + let + base = Path.relative cwd $ Path.dirname entry.path + gitignored = splitMicromatch $ gitignoreToMicromatchPatterns base gitignore + canIgnore = not <<< flip any includePatterns + newIgnores = filter (canIgnore <<< micromatch) gitignored + in + void + $ Ref.modify (_ <> fold newIgnores) + $ ignoreMatcherRef -- Should `fsWalk` recurse into this directory? deepFilter :: Entry -> Effect Boolean From 425157685f5940ac63b202d68d4e84726a23555c Mon Sep 17 00:00:00 2001 From: Orion Kindel Date: Mon, 17 Jun 2024 15:44:47 -0500 Subject: [PATCH 3/7] fix: unused import --- src/Spago/Glob.purs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Spago/Glob.purs b/src/Spago/Glob.purs index 8bea3f7f5..6543e7a71 100644 --- a/src/Spago/Glob.purs +++ b/src/Spago/Glob.purs @@ -3,7 +3,7 @@ module Spago.Glob (gitignoringGlob) where import Spago.Prelude import Control.Alternative (guard) -import Control.Monad.Maybe.Trans (MaybeT(..), runMaybeT) +import Control.Monad.Maybe.Trans (runMaybeT) import Control.Monad.Trans.Class (lift) import Data.Array as Array import Data.Filterable (filter) From 0b098be9edb2ec98c2e1262c362d5051a1eb38d8 Mon Sep 17 00:00:00 2001 From: Orion Kindel Date: Sun, 23 Jun 2024 21:02:41 -0500 Subject: [PATCH 4/7] fix: restore this old behavior, maybe it broke windows --- src/Spago/Glob.js | 2 +- src/Spago/Glob.purs | 78 +++++++++++++++++++++++++++----------------- test/Spago/Glob.purs | 12 ++++--- 3 files changed, 56 insertions(+), 36 deletions(-) diff --git a/src/Spago/Glob.js b/src/Spago/Glob.js index c140130d1..b053202ba 100644 --- a/src/Spago/Glob.js +++ b/src/Spago/Glob.js @@ -1,7 +1,7 @@ import mm from 'micromatch'; import * as fsWalk from '@nodelib/fs.walk'; -export const micromatch = options => mm.matcher(options.include, options); +export const testGlob = glob => mm.matcher(glob.include, {ignore: glob.ignore}); export const fsWalkImpl = Left => Right => respond => options => path => () => { const entryFilter = entry => options.entryFilter(entry)(); diff --git a/src/Spago/Glob.purs b/src/Spago/Glob.purs index 6543e7a71..93b15f4ef 100644 --- a/src/Spago/Glob.purs +++ b/src/Spago/Glob.purs @@ -8,8 +8,8 @@ import Control.Monad.Trans.Class (lift) import Data.Array as Array import Data.Filterable (filter) import Data.Foldable (any, fold) +import Data.Newtype (wrap) import Data.String as String -import Data.String.CodePoints as String.CodePoint import Data.Traversable (traverse_) import Effect.Aff as Aff import Effect.Ref as Ref @@ -18,12 +18,15 @@ import Node.Path as Path import Record as Record import Type.Proxy (Proxy(..)) -type MicroMatchOptions = { ignore :: Array String, include :: Array String } +type Glob = + { ignore :: Array String + , include :: Array String + } -foreign import micromatch :: MicroMatchOptions -> String -> Boolean +foreign import testGlob :: Glob -> String -> Boolean -splitMicromatch :: MicroMatchOptions -> Array MicroMatchOptions -splitMicromatch { ignore, include } = (\a -> { ignore, include: [ a ] }) <$> include +splitGlob :: Glob -> Array Glob +splitGlob { ignore, include } = (\a -> { ignore, include: [ a ] }) <$> include type Entry = { name :: String, path :: String, dirent :: DirEnt } type FsWalkOptions = { entryFilter :: Entry -> Effect Boolean, deepFilter :: Entry -> Effect Boolean } @@ -38,40 +41,41 @@ foreign import fsWalkImpl -> String -> Effect Unit -gitignoreToMicromatchPatterns :: String -> String -> { ignore :: Array String, include :: Array String } -gitignoreToMicromatchPatterns base = +gitignoreGlob :: String -> String -> Glob +gitignoreGlob base = String.split (String.Pattern "\n") >>> map String.trim >>> Array.filter (not <<< or [ String.null, isComment ]) >>> partitionMap ( \line -> do - let pattern a = Path.concat [ base, gitignorePatternToMicromatch a ] + let + resolve a = Path.concat [ base, a ] + pat a = resolve $ unpackPattern a case String.stripPrefix (String.Pattern "!") line of - Just negated -> Left $ pattern negated - Nothing -> Right $ pattern line + Just negated -> Left $ pat negated + Nothing -> Right $ pat line ) - >>> Record.rename (Proxy :: Proxy "left") (Proxy :: Proxy "ignore") - >>> Record.rename (Proxy :: Proxy "right") (Proxy :: Proxy "include") + >>> Record.rename (Proxy @"left") (Proxy @"ignore") + >>> Record.rename (Proxy @"right") (Proxy @"include") where - isComment = isJust <<< String.stripPrefix (String.Pattern "#") - dropSuffixSlash str = fromMaybe str $ String.stripSuffix (String.Pattern "/") str - dropPrefixSlash str = fromMaybe str $ String.stripPrefix (String.Pattern "/") str - - leadingSlash str = String.codePointAt 0 str == Just (String.CodePoint.codePointFromChar '/') + isComment = isJust <<< String.stripPrefix (String.Pattern "#") + leadingSlash = String.stripPrefix (String.Pattern "/") + trailingSlash = String.stripSuffix (String.Pattern "/") - gitignorePatternToMicromatch :: String -> String - gitignorePatternToMicromatch pattern - | leadingSlash pattern = dropPrefixSlash pattern <> "/**" - | otherwise = "**/" <> dropSuffixSlash pattern <> "/**" + unpackPattern :: String -> String + unpackPattern pattern + | Just a <- trailingSlash pattern = unpackPattern a + | Just a <- leadingSlash pattern = a <> "/**" + | otherwise = "**/" <> pattern <> "/**" fsWalk :: String -> Array String -> Array String -> Aff (Array Entry) fsWalk cwd ignorePatterns includePatterns = Aff.makeAff \cb -> do - let includeMatcher = micromatch { ignore: [], include: includePatterns } + let includeMatcher = testGlob { ignore: [], include: includePatterns } -- Pattern for directories which can be outright ignored. -- This will be updated whenver a .gitignore is found. - ignoreMatcherRef <- Ref.new { ignore: [], include: ignorePatterns } + ignoreMatcherRef :: Ref Glob <- Ref.new { ignore: [], include: ignorePatterns } -- If this Ref contains `true` because this Aff has been canceled, then deepFilter will always return false. canceled <- Ref.new false @@ -81,13 +85,27 @@ fsWalk cwd ignorePatterns includePatterns = Aff.makeAff \cb -> do try (SyncFS.readTextFile UTF8 entry.path) >>= traverse_ \gitignore -> let + naivePatIntersectsWith a b = + let + globsExpanded = + String.replaceAll (wrap "*") (wrap "foo") + $ String.replaceAll (wrap "**") (wrap "a/b/c") + $ b + globsCollapsed = + String.replaceAll (wrap "*") (wrap "foo") + $ String.replaceAll (wrap "**/") (wrap "") + $ b + test = testGlob {include: [a], ignore: []} + in + test globsExpanded || test globsCollapsed base = Path.relative cwd $ Path.dirname entry.path - gitignored = splitMicromatch $ gitignoreToMicromatchPatterns base gitignore - canIgnore = not <<< flip any includePatterns - newIgnores = filter (canIgnore <<< micromatch) gitignored - in + pats = splitGlob $ gitignoreGlob base gitignore + patIsOk {include: [p0]} = not $ any (naivePatIntersectsWith p0) includePatterns + patIsOk _ = false + newPats = filter (patIsOk) pats + in do void - $ Ref.modify (_ <> fold newIgnores) + $ Ref.modify (_ <> fold newPats) $ ignoreMatcherRef -- Should `fsWalk` recurse into this directory? @@ -95,7 +113,7 @@ fsWalk cwd ignorePatterns includePatterns = Aff.makeAff \cb -> do deepFilter entry = fromMaybe false <$> runMaybeT do isCanceled <- lift $ Ref.read canceled guard $ not isCanceled - shouldIgnore <- lift $ micromatch <$> Ref.read ignoreMatcherRef + shouldIgnore <- lift $ testGlob <$> Ref.read ignoreMatcherRef pure $ not $ shouldIgnore $ Path.relative cwd entry.path -- Should `fsWalk` retain this entry for the result array? @@ -104,7 +122,7 @@ fsWalk cwd ignorePatterns includePatterns = Aff.makeAff \cb -> do when (isFile entry.dirent && entry.name == ".gitignore") (entryGitignore entry) ignorePat <- Ref.read ignoreMatcherRef let - ignoreMatcher = micromatch ignorePat + ignoreMatcher = testGlob ignorePat path = withForwardSlashes $ Path.relative cwd entry.path pure $ includeMatcher path && not (ignoreMatcher path) diff --git a/test/Spago/Glob.purs b/test/Spago/Glob.purs index e9d5f99e8..0cadf8385 100644 --- a/test/Spago/Glob.purs +++ b/test/Spago/Glob.purs @@ -63,11 +63,13 @@ spec = Spec.around globTmpDir do a <- Glob.gitignoringGlob p ["**/apple"] a `Assert.shouldEqual` ["fruits/special/apple", "src/fruits/apple"] - Spec.it "does not respect a .gitignore pattern that conflicts with search" \p -> do - for_ ["/fruits", "fruits", "fruits/", "**/fruits", "fruits/**", "**/fruits/**"] \gitignore -> do - FS.writeTextFile (Path.concat [p, ".gitignore"]) gitignore - a <- Glob.gitignoringGlob p ["fruits/apple/**"] - a `Assert.shouldEqual` ["fruits/apple"] + for_ ["/fruits", "fruits", "fruits/", "**/fruits", "fruits/**", "**/fruits/**"] \gitignore -> do + Spec.focus $ Spec.it + ("does not respect a .gitignore pattern that conflicts with search: " <> gitignore) + \p -> do + FS.writeTextFile (Path.concat [p, ".gitignore"]) gitignore + a <- Glob.gitignoringGlob p ["fruits/apple/**"] + a `Assert.shouldEqual` ["fruits/apple"] Spec.it "respects some .gitignore patterns" \p -> do FS.writeTextFile (Path.concat [p, ".gitignore"]) """/fruits\n/src""" From d7e5583af3d65462c63438388e0a875f5c4b0b25 Mon Sep 17 00:00:00 2001 From: Orion Kindel Date: Sun, 23 Jun 2024 21:06:41 -0500 Subject: [PATCH 5/7] fix: unnecessary complexity --- src/Spago/Glob.purs | 17 +---------------- test/Spago.purs | 34 +++++++++++++++++----------------- 2 files changed, 18 insertions(+), 33 deletions(-) diff --git a/src/Spago/Glob.purs b/src/Spago/Glob.purs index 93b15f4ef..4de4ab376 100644 --- a/src/Spago/Glob.purs +++ b/src/Spago/Glob.purs @@ -8,7 +8,6 @@ import Control.Monad.Trans.Class (lift) import Data.Array as Array import Data.Filterable (filter) import Data.Foldable (any, fold) -import Data.Newtype (wrap) import Data.String as String import Data.Traversable (traverse_) import Effect.Aff as Aff @@ -85,23 +84,9 @@ fsWalk cwd ignorePatterns includePatterns = Aff.makeAff \cb -> do try (SyncFS.readTextFile UTF8 entry.path) >>= traverse_ \gitignore -> let - naivePatIntersectsWith a b = - let - globsExpanded = - String.replaceAll (wrap "*") (wrap "foo") - $ String.replaceAll (wrap "**") (wrap "a/b/c") - $ b - globsCollapsed = - String.replaceAll (wrap "*") (wrap "foo") - $ String.replaceAll (wrap "**/") (wrap "") - $ b - test = testGlob {include: [a], ignore: []} - in - test globsExpanded || test globsCollapsed base = Path.relative cwd $ Path.dirname entry.path pats = splitGlob $ gitignoreGlob base gitignore - patIsOk {include: [p0]} = not $ any (naivePatIntersectsWith p0) includePatterns - patIsOk _ = false + patIsOk g = not $ any (testGlob g) includePatterns newPats = filter (patIsOk) pats in do void diff --git a/test/Spago.purs b/test/Spago.purs index ea5fc830f..4a0202309 100644 --- a/test/Spago.purs +++ b/test/Spago.purs @@ -41,22 +41,22 @@ main :: Effect Unit main = Aff.launchAff_ $ void $ un Identity $ Spec.Runner.runSpecT testConfig [ Spec.Reporter.consoleReporter ] do Spec.describe "spago" do -- TODO: script - Init.spec - Sources.spec - Install.spec - Uninstall.spec - Ls.spec - Build.spec - Run.spec - Test.spec - Bundle.spec - Registry.spec - Docs.spec - Upgrade.spec - Publish.spec - Graph.spec + -- Init.spec + -- Sources.spec + -- Install.spec + -- Uninstall.spec + -- Ls.spec + -- Build.spec + -- Run.spec + -- Test.spec + -- Bundle.spec + -- Registry.spec + -- Docs.spec + -- Upgrade.spec + -- Publish.spec + -- Graph.spec Spec.describe "miscellaneous" do - Lock.spec - Unit.spec + -- Lock.spec + -- Unit.spec Glob.spec - Errors.spec + -- Errors.spec From e5c3d3b34047c97104435f1d7e546559f6dec94c Mon Sep 17 00:00:00 2001 From: Orion Kindel Date: Sun, 23 Jun 2024 21:07:40 -0500 Subject: [PATCH 6/7] fix: fmt --- src/Spago/Glob.purs | 25 +++++++++++++------------ test/Spago.purs | 34 +++++++++++++++++----------------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/Spago/Glob.purs b/src/Spago/Glob.purs index 4de4ab376..f72f7e27a 100644 --- a/src/Spago/Glob.purs +++ b/src/Spago/Glob.purs @@ -58,15 +58,15 @@ gitignoreGlob base = >>> Record.rename (Proxy @"right") (Proxy @"include") where - isComment = isJust <<< String.stripPrefix (String.Pattern "#") - leadingSlash = String.stripPrefix (String.Pattern "/") - trailingSlash = String.stripSuffix (String.Pattern "/") + isComment = isJust <<< String.stripPrefix (String.Pattern "#") + leadingSlash = String.stripPrefix (String.Pattern "/") + trailingSlash = String.stripSuffix (String.Pattern "/") - unpackPattern :: String -> String - unpackPattern pattern - | Just a <- trailingSlash pattern = unpackPattern a - | Just a <- leadingSlash pattern = a <> "/**" - | otherwise = "**/" <> pattern <> "/**" + unpackPattern :: String -> String + unpackPattern pattern + | Just a <- trailingSlash pattern = unpackPattern a + | Just a <- leadingSlash pattern = a <> "/**" + | otherwise = "**/" <> pattern <> "/**" fsWalk :: String -> Array String -> Array String -> Aff (Array Entry) fsWalk cwd ignorePatterns includePatterns = Aff.makeAff \cb -> do @@ -88,10 +88,11 @@ fsWalk cwd ignorePatterns includePatterns = Aff.makeAff \cb -> do pats = splitGlob $ gitignoreGlob base gitignore patIsOk g = not $ any (testGlob g) includePatterns newPats = filter (patIsOk) pats - in do - void - $ Ref.modify (_ <> fold newPats) - $ ignoreMatcherRef + in + do + void + $ Ref.modify (_ <> fold newPats) + $ ignoreMatcherRef -- Should `fsWalk` recurse into this directory? deepFilter :: Entry -> Effect Boolean diff --git a/test/Spago.purs b/test/Spago.purs index 4a0202309..ea5fc830f 100644 --- a/test/Spago.purs +++ b/test/Spago.purs @@ -41,22 +41,22 @@ main :: Effect Unit main = Aff.launchAff_ $ void $ un Identity $ Spec.Runner.runSpecT testConfig [ Spec.Reporter.consoleReporter ] do Spec.describe "spago" do -- TODO: script - -- Init.spec - -- Sources.spec - -- Install.spec - -- Uninstall.spec - -- Ls.spec - -- Build.spec - -- Run.spec - -- Test.spec - -- Bundle.spec - -- Registry.spec - -- Docs.spec - -- Upgrade.spec - -- Publish.spec - -- Graph.spec + Init.spec + Sources.spec + Install.spec + Uninstall.spec + Ls.spec + Build.spec + Run.spec + Test.spec + Bundle.spec + Registry.spec + Docs.spec + Upgrade.spec + Publish.spec + Graph.spec Spec.describe "miscellaneous" do - -- Lock.spec - -- Unit.spec + Lock.spec + Unit.spec Glob.spec - -- Errors.spec + Errors.spec From c6ec57420274e16ae4e349d4eb47bf44982c8675 Mon Sep 17 00:00:00 2001 From: Orion Kindel Date: Sun, 23 Jun 2024 21:08:45 -0500 Subject: [PATCH 7/7] fix: unnecessary do --- src/Spago/Glob.purs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Spago/Glob.purs b/src/Spago/Glob.purs index f72f7e27a..ceeb0d764 100644 --- a/src/Spago/Glob.purs +++ b/src/Spago/Glob.purs @@ -89,10 +89,7 @@ fsWalk cwd ignorePatterns includePatterns = Aff.makeAff \cb -> do patIsOk g = not $ any (testGlob g) includePatterns newPats = filter (patIsOk) pats in - do - void - $ Ref.modify (_ <> fold newPats) - $ ignoreMatcherRef + void $ Ref.modify (_ <> fold newPats) $ ignoreMatcherRef -- Should `fsWalk` recurse into this directory? deepFilter :: Entry -> Effect Boolean