summaryrefslogtreecommitdiff
path: root/lib/CheckDir.hs
blob: 1ca71eb9697af85454d9e655755044a1625e9ffe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
{-# LANGUAGE DeriveAnyClass    #-}
{-# LANGUAGE DeriveGeneric     #-}
{-# LANGUAGE LambdaCase        #-}
{-# LANGUAGE OverloadedStrings #-}

-- | Module that contains high-level checking for an entire directory
module CheckDir (recursiveCheckDir)  where

import           CheckMap     (MapResult, loadAndLintMap, mapresultDepends)
import           Data.Aeson   (ToJSON)
import           Data.Map     (Map)
import qualified Data.Map     as M
import           Data.Text    (Text)
import qualified Data.Text    as T
import           GHC.Generics (Generic)
import           Paths        (normalise)
import           Types        (Dep (LocalMap))
import           Util         (PrettyPrint (prettyprint))


data DirResult = DirResult
  { dirresultMaps :: [MapResult]
  , dirresultDeps :: [Text]
  } deriving (Generic, ToJSON)


instance PrettyPrint DirResult where
  prettyprint res = "Here's a result:" <> T.concat (map prettyprint $ dirresultMaps res)

-- based on the startling observation that Data.Map has lower complexity
-- for difference than Data.Set, but the same complexity for fromList
type Set a = Map a ()


instance Semigroup DirResult where
  a <> b = DirResult
    { dirresultMaps = dirresultMaps a <> dirresultMaps b
    , dirresultDeps = dirresultDeps a <> dirresultDeps b
    }

instance Monoid DirResult where
  mempty = DirResult
    { dirresultMaps = []
    , dirresultDeps = []
    }


-- TODO: options?
recursiveCheckDir :: FilePath -> IO DirResult
recursiveCheckDir root = recursiveCheckDir' [root] mempty mempty


recursiveCheckDir' :: [FilePath] -> Set FilePath -> DirResult -> IO DirResult
recursiveCheckDir' paths done acc = do
  putStrLn $ "linting " <> show paths
  -- lint all maps in paths
  lints <- mapM  loadAndLintMap paths
  -- get new deps
  let deps = concatMap mapresultDepends lints
  -- filter deps for map dependencies
  let mapdeps =
        map (\(LocalMap path) -> normalise path)
        . filter (\case { LocalMap _ -> True; _ -> False })
        $ deps
  -- build a Map FilePath () containing all map dependencies
  let mapmapdeps = M.fromList $ zip mapdeps (repeat ())
  -- take difference of that with what's already done (O(m+n))
  let unknowns = map fst . M.toList $ M.difference mapmapdeps done
  let known = M.union done . M.fromList . zip paths $ repeat ()

  let acc' = acc <> DirResult
                { dirresultMaps = lints
                , dirresultDeps = [] }
  case unknowns of
    [] -> pure acc'
    _  -> recursiveCheckDir' unknowns known acc'