1{-# OPTIONS_GHC -Wno-unused-do-bind #-}
2{-# LANGUAGE BangPatterns, GADTs, OverloadedStrings #-}
15import Control.Concurrent (forkIO)
16import Control.Concurrent.MVar
17import Control.Monad (filterM, mapM_, sequence_)
18import qualified Data.ByteString as B
19import qualified Data.Char as Char
20import qualified Data.Either as Either
21import qualified Data.Graph as Graph
22import qualified Data.List as List
23import qualified Data.Map.Utils as Map
24import qualified Data.Map.Strict as Map
25import Data.Map.Strict ((!))
26import qualified Data.Maybe as Maybe
27import qualified Data.Name as Name
28import qualified Data.NonEmptyList as NE
29import qualified Data.OneOrMore as OneOrMore
30import qualified Data.Set as Set
31import qualified System.Directory as Dir
32import qualified System.FilePath as FP
33import System.FilePath ((</>), (<.>))
35import qualified AST.Canonical as Can
36import qualified AST.Source as Src
37import qualified AST.Optimized as Opt
38import qualified Compile
39import qualified Elm.Details as Details
40import qualified Elm.Docs as Docs
41import qualified Elm.Interface as I
42import qualified Elm.ModuleName as ModuleName
43import qualified Elm.Outline as Outline
44import qualified Elm.Package as Pkg
46import qualified Json.Encode as E
47import qualified Parse.Module as Parse
48import qualified Reporting
49import qualified Reporting.Annotation as A
50import qualified Reporting.Error as Error
51import qualified Reporting.Error.Syntax as Syntax
52import qualified Reporting.Error.Import as Import
53import qualified Reporting.Exit as Exit
63 { _key :: Reporting.BKey
66 , _srcDirs :: [FilePath]
67 , _locals :: Map.Map ModuleName.Raw Details.Local
68 , _foreigns :: Map.Map ModuleName.Raw Details.Foreign
72makeEnv :: Reporting.BKey -> FilePath -> Details.Details -> Env
73makeEnv key root (Details.Details _ validOutline locals foreigns _) =
75 Details.ValidApp srcDirs ->
76 Env key root Pkg.dummyName (NE.toList srcDirs) locals foreigns
78 Details.ValidPkg pkg _ ->
79 Env key root pkg ["src"] locals foreigns
86fork :: IO a -> IO (MVar a)
88 do mvar <- newEmptyMVar
89 _ <- forkIO $ putMVar mvar =<< work
93{-# INLINE forkWithKey #-}
94forkWithKey :: (k -> a -> IO b) -> Map.Map k a -> IO (Map.Map k (MVar b))
95forkWithKey func dict =
96 Map.traverseWithKey (\k v -> fork (func k v)) dict
103fromExposed :: Reporting.Style -> FilePath -> Details.Details -> DocsGoal docs -> NE.List ModuleName.Raw -> IO (Either Exit.BuildProblem docs)
104fromExposed style root details docsGoal exposed@(NE.List e es) =
105 Reporting.trackBuild style $ \key ->
106 do let env = makeEnv key root details
107 dmvar <- Details.loadInterfaces root details
111 let docsNeed = toDocsNeed docsGoal
112 roots <- Map.fromKeysA (fork . crawlModule env mvar docsNeed) (e:es)
115 statuses <- traverse readMVar =<< readMVar mvar
118 midpoint <- checkExposedMidpoint dmvar statuses
121 return (Left (Exit.BuildProjectProblem problem))
124 do rmvar <- newEmptyMVar
125 resultMVars <- forkWithKey (checkModule env foreigns rmvar) statuses
126 putMVar rmvar resultMVars
127 results <- traverse readMVar resultMVars
128 writeDetails root details results
129 finalizeExposed docsGoal exposed results
139 , _deps :: Dependencies
140 , _mains :: NE.List Main
141 , _modules :: [Module]
146 = Fresh ModuleName.Raw I.Interface Opt.LocalGraph
147 | Cached ModuleName.Raw Bool (MVar CachedInterface)
151 Map.Map ModuleName.Canonical I.DependencyInterface
154fromMains :: Reporting.Style -> FilePath -> Details.Details -> NE.List FilePath -> IO (Either Exit.BuildProblem Artifacts)
155fromMains style root details paths =
156 Reporting.trackBuild style $ \key ->
157 do let env = makeEnv key root details
159 elmains <- findMains env paths
162 return (Left (Exit.BuildProjectProblem problem))
166 dmvar <- Details.loadInterfaces root details
167 smvar <- newMVar Map.empty
168 smainMVars <- traverse (fork . crawlMain env smvar) lmains
169 smains <- traverse readMVar smainMVars
170 statuses <- traverse readMVar =<< readMVar smvar
172 midpoint <- checkMainsMidpoint dmvar statuses smains
175 return (Left (Exit.BuildProjectProblem problem))
179 rmvar <- newEmptyMVar
180 resultsMVars <- forkWithKey (checkModule env foreigns rmvar) statuses
181 putMVar rmvar resultsMVars
182 rmainMVars <- traverse (fork . checkMain env resultsMVars) smains
183 results <- traverse readMVar resultsMVars
184 writeDetails root details results
185 toArtifacts env foreigns results <$> traverse readMVar rmainMVars
193 Map.Map ModuleName.Raw (MVar Status)
197 = SCached Details.Local
198 | SChanged Details.Local B.ByteString Src.Module DocsNeed
199 | SBadImport Import.Problem
200 | SBadSyntax FilePath File.Time B.ByteString Syntax.Error
205crawlDeps :: Env -> MVar StatusDict -> [ModuleName.Raw] -> a -> IO a
206crawlDeps env mvar deps blockedValue =
207 do statusDict <- takeMVar mvar
208 let depsDict = Map.fromKeys (\_ -> ()) deps
209 let newsDict = Map.difference depsDict statusDict
210 statuses <- Map.traverseWithKey crawlNew newsDict
211 putMVar mvar (Map.union statuses statusDict)
212 mapM_ readMVar statuses
215 crawlNew name () = fork (crawlModule env mvar (DocsNeed False) name)
218crawlModule :: Env -> MVar StatusDict -> DocsNeed -> ModuleName.Raw -> IO Status
219crawlModule env@(Env _ root pkg srcDirs locals foreigns) mvar docsNeed name =
220 do let fileName = ModuleName.toFilePath name <.> "elm"
221 let inRoot path = File.exists (root </> path)
223 paths <- filterM inRoot (map (</> fileName) srcDirs)
227 case Map.lookup name foreigns of
228 Just (Details.Foreign dep deps) ->
229 return $ SBadImport $ Import.Ambiguous path [] dep deps
232 case Map.lookup name locals of
234 crawlFile env mvar docsNeed name path
236 Just local@(Details.Local oldPath oldTime deps _) ->
238 then crawlFile env mvar docsNeed name path
240 do newTime <- File.getTime path
241 if oldTime < newTime || needsDocs docsNeed
242 then crawlFile env mvar docsNeed name path
243 else crawlDeps env mvar deps (SCached local)
246 return $ SBadImport $ Import.AmbiguousLocal p1 p2 ps
249 case Map.lookup name foreigns of
250 Just (Details.Foreign dep deps) ->
253 return $ SForeign dep
256 return $ SBadImport $ Import.AmbiguousForeign dep d ds
259 if Name.isKernel name && Pkg.isKernel pkg then
260 do exists <- File.exists ("src" </> ModuleName.toFilePath name <.> "js")
261 return $ if exists then SKernel else SBadImport Import.NotFound
263 return $ SBadImport Import.NotFound
266crawlFile :: Env -> MVar StatusDict -> DocsNeed -> ModuleName.Raw -> FilePath -> IO Status
267crawlFile env@(Env _ root pkg _ _ _) mvar docsNeed expectedName path =
268 do time <- File.getTime path
269 source <- File.readUtf8 (root </> path)
271 case Parse.fromByteString pkg source of
273 return $ SBadSyntax path time source err
275 Right modul@(Src.Module maybeActualName _ _ imports values _ _ _ _) ->
276 case maybeActualName of
278 return $ SBadSyntax path time source (Syntax.ModuleNameUnspecified expectedName)
280 Just name@(A.At _ actualName) ->
281 if expectedName == actualName then
283 deps = map Src.getImportName imports
284 local = Details.Local path time deps (any isMain values)
286 crawlDeps env mvar deps (SChanged local source modul docsNeed)
288 return $ SBadSyntax path time source (Syntax.ModuleNameMismatch expectedName name)
291isMain :: A.Located Src.Value -> Bool
292isMain (A.At _ (Src.Value (A.At _ name) _ _ _)) =
301 Map.Map ModuleName.Raw (MVar Result)
305 = RNew !Details.Local !I.Interface !Opt.LocalGraph !(Maybe Docs.Module)
306 | RSame !Details.Local !I.Interface !Opt.LocalGraph !(Maybe Docs.Module)
307 | RCached Bool (MVar CachedInterface)
308 | RNotFound Import.Problem
309 | RProblem Error.Module
311 | RForeign I.Interface
321checkModule :: Env -> Dependencies -> MVar ResultDict -> ModuleName.Raw -> Status -> IO Result
322checkModule env@(Env _ root pkg _ _ _) foreigns resultsMVar name status =
324 SCached local@(Details.Local path time deps hasMain) ->
325 do results <- readMVar resultsMVar
326 depsStatus <- checkDeps root results deps
329 do source <- File.readUtf8 path
330 case Parse.fromByteString pkg source of
331 Right modul -> compile env (DocsNeed False) local source ifaces modul
334 Error.Module name path time source (Error.BadSyntax err)
337 do mvar <- newMVar Unneeded
338 return (RCached hasMain mvar)
343 DepsNotFound problems ->
344 do source <- File.readUtf8 path
345 return $ RProblem $ Error.Module name path time source $
346 case Parse.fromByteString pkg source of
347 Right (Src.Module _ _ _ imports _ _ _ _ _) ->
348 Error.BadImports (toImportErrors env results imports problems)
353 SChanged local@(Details.Local path time deps _) source modul@(Src.Module _ _ _ imports _ _ _ _ _) docsNeed ->
354 do results <- readMVar resultsMVar
355 depsStatus <- checkDeps root results deps
358 compile env docsNeed local source ifaces modul
360 DepsSame same cached ->
361 do maybeLoaded <- checkCachedInterfaces root cached
367 do let ifaces = Map.union loaded (Map.fromList same)
368 compile env docsNeed local source ifaces modul
373 DepsNotFound problems ->
374 return $ RProblem $ Error.Module name path time source $
375 Error.BadImports (toImportErrors env results imports problems)
377 SBadImport importProblem ->
378 return (RNotFound importProblem)
380 SBadSyntax path time source err ->
381 return $ RProblem $ Error.Module name path time source $
385 case foreigns ! ModuleName.Canonical home name of
386 I.Public iface -> return (RForeign iface)
387 I.Private _ _ _ -> error "loading private interface in Build"
398 = DepsChange (Map.Map ModuleName.Raw I.Interface)
399 | DepsSame [Dep] [CDep]
401 | DepsNotFound (NE.List (ModuleName.Raw, Import.Problem))
404checkDeps :: FilePath -> ResultDict -> [ModuleName.Raw] -> IO DepsStatus
405checkDeps root results deps =
406 checkDepsHelp root results deps [] [] [] [] False
409type Dep = (ModuleName.Raw, I.Interface)
410type CDep = (ModuleName.Raw, MVar CachedInterface)
413checkDepsHelp :: FilePath -> ResultDict -> [ModuleName.Raw] -> [Dep] -> [Dep] -> [CDep] -> [(ModuleName.Raw,Import.Problem)] -> Bool -> IO DepsStatus
414checkDepsHelp root results deps new same cached importProblems isBlocked =
417 do result <- readMVar (results ! dep)
419 RNew _ iface _ _ -> checkDepsHelp root results otherDeps ((dep,iface) : new) same cached importProblems isBlocked
420 RSame _ iface _ _ -> checkDepsHelp root results otherDeps new ((dep,iface) : same) cached importProblems isBlocked
421 RCached _ mvar -> checkDepsHelp root results otherDeps new same ((dep,mvar) : cached) importProblems isBlocked
422 RNotFound prob -> checkDepsHelp root results otherDeps new same cached ((dep,prob) : importProblems) True
423 RProblem _ -> checkDepsHelp root results otherDeps new same cached importProblems True
424 RBlocked -> checkDepsHelp root results otherDeps new same cached importProblems True
425 RForeign iface -> checkDepsHelp root results otherDeps new ((dep,iface) : same) cached importProblems isBlocked
426 RKernel -> checkDepsHelp root results otherDeps new same cached importProblems isBlocked
429 case importProblems of
431 return $ DepsNotFound (NE.List p ps)
437 else if null new then
438 return $ DepsSame same cached
441 do maybeLoaded <- checkCachedInterfaces root cached
447 return $ DepsChange $
448 Map.union loaded (Map.union (Map.fromList new) (Map.fromList same))
455toImportErrors :: Env -> ResultDict -> [Src.Import] -> NE.List (ModuleName.Raw, Import.Problem) -> NE.List Import.Error
456toImportErrors (Env _ _ _ _ locals foreigns) results imports problems =
460 [ Map.keysSet foreigns
462 , Map.keysSet results
466 Set.difference knownModules (Set.fromList (map Src.getImportName imports))
469 Map.fromList (map (\(Src.Import (A.At region name) _ _) -> (name, region)) imports)
471 toError (name, problem) =
472 Import.Error (regionDict ! name) name unimportedModules problem
474 fmap toError problems
481checkCachedInterfaces :: FilePath -> [(ModuleName.Raw, MVar CachedInterface)] -> IO (Maybe (Map.Map ModuleName.Raw I.Interface))
482checkCachedInterfaces root deps =
483 do loading <- traverse (fork . checkCache root) deps
484 loaded <- traverse readMVar loading
485 return $ Map.fromList <$> sequence loaded
488checkCache :: FilePath -> (ModuleName.Raw, MVar CachedInterface) -> IO (Maybe Dep)
489checkCache root (name, ciMvar) =
490 do cachedInterface <- takeMVar ciMvar
491 case cachedInterface of
493 do putMVar ciMvar cachedInterface
497 do putMVar ciMvar cachedInterface
498 return (Just (name, iface))
501 do maybeIface <- File.readBinary (Stuff.elmi root name)
504 do putMVar ciMvar Corrupted
508 do putMVar ciMvar (Loaded iface)
509 return (Just (name, iface))
516checkExposedMidpoint :: MVar (Maybe Dependencies) -> Map.Map ModuleName.Raw Status -> IO (Either Exit.BuildProjectProblem Dependencies)
517checkExposedMidpoint dmvar statuses =
518 case checkForCycles statuses of
520 do maybeForeigns <- readMVar dmvar
521 case maybeForeigns of
522 Nothing -> return (Left Exit.BP_CannotLoadDependencies)
523 Just fs -> return (Right fs)
525 Just (NE.List name names) ->
526 do _ <- readMVar dmvar
527 return (Left (Exit.BP_Cycle name names))
530checkMainsMidpoint :: MVar (Maybe Dependencies) -> Map.Map ModuleName.Raw Status -> NE.List MainStatus -> IO (Either Exit.BuildProjectProblem Dependencies)
531checkMainsMidpoint dmvar statuses smains =
532 case checkForCycles statuses of
534 case checkUniqueMains statuses smains of
536 do maybeForeigns <- readMVar dmvar
537 case maybeForeigns of
538 Nothing -> return (Left Exit.BP_CannotLoadDependencies)
539 Just fs -> return (Right fs)
542 do _ <- readMVar dmvar
543 return (Left problem)
545 Just (NE.List name names) ->
546 do _ <- readMVar dmvar
547 return (Left (Exit.BP_Cycle name names))
554checkForCycles :: Map.Map ModuleName.Raw Status -> Maybe (NE.List ModuleName.Raw)
555checkForCycles modules =
557 !graph = Map.foldrWithKey addToGraph [] modules
558 !sccs = Graph.stronglyConnComp graph
560 checkForCyclesHelp sccs
563checkForCyclesHelp :: [Graph.SCC ModuleName.Raw] -> Maybe (NE.List ModuleName.Raw)
564checkForCyclesHelp sccs =
571 Graph.AcyclicSCC _ -> checkForCyclesHelp otherSccs
572 Graph.CyclicSCC [] -> checkForCyclesHelp otherSccs
573 Graph.CyclicSCC (m:ms) -> Just (NE.List m ms)
577 ( ModuleName.Raw, ModuleName.Raw, [ModuleName.Raw] )
580addToGraph :: ModuleName.Raw -> Status -> [Node] -> [Node]
581addToGraph name status graph =
585 SCached (Details.Local _ _ deps _) -> deps
586 SChanged (Details.Local _ _ deps _) _ _ _ -> deps
588 SBadSyntax _ _ _ _ -> []
592 (name, name, dependencies) : graph
599checkUniqueMains :: Map.Map ModuleName.Raw Status -> NE.List MainStatus -> Maybe Exit.BuildProjectProblem
600checkUniqueMains insides smains =
603 Map.fromListWith OneOrMore.more (Maybe.mapMaybe mainStatusToNamePathPair (NE.toList smains))
605 case Map.traverseWithKey checkOutside outsidesDict of
610 case sequence_ (Map.intersectionWithKey checkInside outsides insides) of
612 Left problem -> Just problem
615mainStatusToNamePathPair :: MainStatus -> Maybe (ModuleName.Raw, OneOrMore.OneOrMore FilePath)
616mainStatusToNamePathPair smain =
619 SOutsideOk (Details.Local path _ _ _) _ modul -> Just (Src.getName modul, OneOrMore.one path)
620 SOutsideErr _ -> Nothing
623checkOutside :: ModuleName.Raw -> OneOrMore.OneOrMore FilePath -> Either Exit.BuildProjectProblem FilePath
624checkOutside name paths =
625 case OneOrMore.destruct NE.List paths of
626 NE.List p [] -> Right p
627 NE.List p1 (p2:_) -> Left (Exit.BP_MainNameDuplicate name p1 p2)
630checkInside :: ModuleName.Raw -> FilePath -> Status -> Either Exit.BuildProjectProblem ()
631checkInside name p1 status =
633 SCached (Details.Local p2 _ _ _) -> Left (Exit.BP_MainNameDuplicate name p1 p2)
634 SChanged (Details.Local p2 _ _ _) _ _ _ -> Left (Exit.BP_MainNameDuplicate name p1 p2)
635 SBadImport _ -> Right ()
636 SBadSyntax _ _ _ _ -> Right ()
637 SForeign _ -> Right ()
645compile :: Env -> DocsNeed -> Details.Local -> B.ByteString -> Map.Map ModuleName.Raw I.Interface -> Src.Module -> IO Result
646compile (Env key root pkg _ _ _) docsNeed local@(Details.Local path time _ _) source ifaces modul =
647 case Compile.compile pkg ifaces modul of
648 Right (Compile.Artifacts canonical annotations objects) ->
649 do let name = Src.getName modul
650 let iface = I.fromModule pkg canonical annotations
651 let docs = makeDocs docsNeed canonical
652 File.writeBinary (Stuff.elmo root name) objects
653 maybeOldi <- File.readBinary (Stuff.elmi root name)
655 Just oldi | oldi == iface ->
656 do -- iface should be fully forced by equality check
657 Reporting.report key Reporting.BDone
658 return (RSame local iface objects docs)
661 do -- iface may be lazy still
662 -- TODO try adding forkIO here
663 File.writeBinary (Stuff.elmi root name) iface
664 Reporting.report key Reporting.BDone
665 return (RNew local iface objects docs)
668 do Reporting.report key Reporting.BDone
670 Error.Module (Src.getName modul) path time source err
677writeDetails :: FilePath -> Details.Details -> Map.Map ModuleName.Raw Result -> IO ()
678writeDetails root (Details.Details time outline locals foreigns extras) results =
679 File.writeBinary (Stuff.details root) $
680 Details.Details time outline (Map.foldrWithKey addNewLocal locals results) foreigns extras
683addNewLocal :: ModuleName.Raw -> Result -> Map.Map ModuleName.Raw Details.Local -> Map.Map ModuleName.Raw Details.Local
684addNewLocal name result locals =
686 RNew local _ _ _ -> Map.insert name local locals
687 RSame local _ _ _ -> Map.insert name local locals
688 RCached _ _ -> locals
689 RNotFound _ -> locals
700finalizeExposed :: DocsGoal docs -> NE.List ModuleName.Raw -> Map.Map ModuleName.Raw Result -> IO (Either Exit.BuildProblem docs)
701finalizeExposed docsGoal exposed results =
702 case foldr (addImportProblems results) [] (NE.toList exposed) of
704 return $ Left $ Exit.BuildProjectProblem (Exit.BP_MissingExposed (NE.List p ps))
707 case Map.foldr addErrors [] results of
708 [] -> Right <$> finalizeDocs docsGoal results
709 e:es -> return $ Left $ Exit.BuildModuleProblems e es
712addErrors :: Result -> [Error.Module] -> [Error.Module]
713addErrors result errors =
715 RNew _ _ _ _ -> errors
716 RSame _ _ _ _ -> errors
717 RCached _ _ -> errors
718 RNotFound _ -> errors
719 RProblem e -> e:errors
725addImportProblems :: Map.Map ModuleName.Raw Result -> ModuleName.Raw -> [(ModuleName.Raw, Import.Problem)] -> [(ModuleName.Raw, Import.Problem)]
726addImportProblems results name problems =
727 case results ! name of
728 RNew _ _ _ _ -> problems
729 RSame _ _ _ _ -> problems
730 RCached _ _ -> problems
731 RNotFound p -> (name, p) : problems
732 RProblem _ -> problems
734 RForeign _ -> problems
743 KeepDocs :: DocsGoal Docs.Documentation
744 WriteDocs :: FilePath -> DocsGoal ()
745 IgnoreDocs :: DocsGoal ()
749 DocsNeed { needsDocs :: Bool }
752toDocsNeed :: DocsGoal a -> DocsNeed
755 IgnoreDocs -> DocsNeed False
756 WriteDocs _ -> DocsNeed True
757 KeepDocs -> DocsNeed True
760makeDocs :: DocsNeed -> Can.Module -> Maybe Docs.Module
761makeDocs (DocsNeed isNeeded) modul =
763 case Docs.fromModule modul of
764 Right docs -> Just docs
770finalizeDocs :: DocsGoal docs -> Map.Map ModuleName.Raw Result -> IO docs
771finalizeDocs goal results =
774 return $ Map.mapMaybe toDocs results
777 E.writeUgly path $ Docs.encode $ Map.mapMaybe toDocs results
783toDocs :: Result -> Maybe Docs.Module
788 RCached _ _ -> Nothing
789 RNotFound _ -> Nothing
790 RProblem _ -> Nothing
792 RForeign _ -> Nothing
797--------------------------------------------------------------------------------
798--------------------------------------------------------------------------------
799------ AFTER THIS, EVERYTHING IS ABOUT HANDLING MODULES GIVEN BY FILEPATH ------
800--------------------------------------------------------------------------------
801--------------------------------------------------------------------------------
809 = LInside ModuleName.Raw
813findMains :: Env -> NE.List FilePath -> IO (Either Exit.BuildProjectProblem (NE.List MainLocation))
815 do mvars <- traverse (fork . findLocation env) paths
816 elocs <- traverse readMVar mvars
817 return $ checkLocations =<< sequence elocs
820checkLocations :: NE.List Location -> Either Exit.BuildProjectProblem (NE.List MainLocation)
821checkLocations locations =
823 toOneOrMore loc@(Location absolute _ _) =
824 (absolute, OneOrMore.one loc)
826 fromOneOrMore loc locs =
829 loc2:_ -> Left (Exit.BP_MainPathDuplicate (_relative loc) (_relative loc2))
831 fmap (\_ -> fmap _location locations) $
832 traverse (OneOrMore.destruct fromOneOrMore) $
833 Map.fromListWith OneOrMore.more $ map toOneOrMore (NE.toList locations)
842 { _absolute :: FilePath
843 , _relative :: FilePath
844 , _location :: MainLocation
848findLocation :: Env -> FilePath -> IO (Either Exit.BuildProjectProblem Location)
849findLocation env path =
850 do exists <- File.exists path
852 then isInsideSrcDirs env path <$> Dir.canonicalizePath path
853 else return (Left (Exit.BP_PathUnknown path))
856isInsideSrcDirs :: Env -> FilePath -> FilePath -> Either Exit.BuildProjectProblem Location
857isInsideSrcDirs (Env _ root _ srcDirs _ _) path absolutePath =
859 (dirs, file) = FP.splitFileName absolutePath
860 (final, ext) = break (=='.') file
863 then Left (Exit.BP_WithBadExtension path)
866 roots = FP.splitDirectories root
867 segments = FP.splitDirectories dirs ++ [final]
869 case dropPrefix roots segments of
871 Right (Location absolutePath path (LOutside path))
873 Just relativeSegments ->
876 Either.partitionEithers (map (isInsideSrcDirsHelp relativeSegments) srcDirs)
878 -- TODO make sure this is all correct
879 case (exits, Maybe.catMaybes maybes) of
880 (_, [(_,name)]) -> Right (Location absolutePath path (LInside name))
881 ([], []) -> Right (Location absolutePath path (LOutside path))
882 (_, (s1,_):(s2,_):_) -> Left (Exit.BP_WithAmbiguousSrcDir s1 s2)
883 (exit:_, _) -> Left exit
886isInsideSrcDirsHelp :: [String] -> FilePath -> Either Exit.BuildProjectProblem (Maybe (FilePath, ModuleName.Raw))
887isInsideSrcDirsHelp segments srcDir =
888 case dropPrefix (FP.splitDirectories srcDir) segments of
893 if all isGoodName names
894 then Right (Just (srcDir, Name.fromChars (List.intercalate "." names)))
895 else Left (error "Exit.MakeWithInvalidModuleName" srcDir segments)
898isGoodName :: [Char] -> Bool
905 Char.isUpper char && all (\c -> Char.isAlphaNum c || c == '_') chars
908dropPrefix :: [FilePath] -> [FilePath] -> Maybe [FilePath]
909dropPrefix roots paths =
917 p:ps -> if r == p then dropPrefix rs ps else Nothing
925 = SInside ModuleName.Raw
926 | SOutsideOk Details.Local B.ByteString Src.Module
927 | SOutsideErr Error.Module
930crawlMain :: Env -> MVar StatusDict -> MainLocation -> IO MainStatus
931crawlMain env@(Env _ _ pkg _ _ _) mvar given =
934 do statusMVar <- newEmptyMVar
935 statusDict <- takeMVar mvar
936 putMVar mvar (Map.insert name statusMVar statusDict)
937 putMVar statusMVar =<< crawlModule env mvar (DocsNeed False) name
938 return (SInside name)
941 do time <- File.getTime path
942 source <- File.readUtf8 path
943 case Parse.fromByteString pkg source of
944 Right modul@(Src.Module _ _ _ imports values _ _ _ _) ->
945 do let deps = map Src.getImportName imports
946 let local = Details.Local path time deps (any isMain values)
947 crawlDeps env mvar deps (SOutsideOk local source modul)
950 return $ SOutsideErr $
951 Error.Module "???" path time source (Error.BadSyntax syntaxError)
959 = RInside ModuleName.Raw
960 | ROutsideOk ModuleName.Raw I.Interface Opt.LocalGraph
961 | ROutsideErr Error.Module
965checkMain :: Env -> ResultDict -> MainStatus -> IO MainResult
966checkMain env@(Env _ root _ _ _ _) results pendingMain =
969 return (RInside name)
972 return (ROutsideErr err)
974 SOutsideOk local@(Details.Local path time deps _) source modul@(Src.Module _ _ _ imports _ _ _ _ _) ->
975 do depsStatus <- checkDeps root results deps
978 return $ compileOutside env local source ifaces modul
980 DepsSame same cached ->
981 do maybeLoaded <- checkCachedInterfaces root cached
984 return ROutsideBlocked
987 do let ifaces = Map.union loaded (Map.fromList same)
988 return $ compileOutside env local source ifaces modul
991 return ROutsideBlocked
993 DepsNotFound problems ->
994 return $ ROutsideErr $ Error.Module (Src.getName modul) path time source $
995 Error.BadImports (toImportErrors env results imports problems)
998compileOutside :: Env -> Details.Local -> B.ByteString -> Map.Map ModuleName.Raw I.Interface -> Src.Module -> MainResult
999compileOutside (Env _ _ pkg _ _ _) (Details.Local path time _ _) source ifaces modul =
1001 name = Src.getName modul
1003 case Compile.compile pkg ifaces modul of
1004 Right (Compile.Artifacts canonical annotations objects) ->
1005 ROutsideOk name (I.fromModule pkg canonical annotations) objects
1009 Error.Module name path time source errors
1017 = Inside ModuleName.Raw
1018 | Outside ModuleName.Raw I.Interface Opt.LocalGraph
1021toArtifacts :: Env -> Dependencies -> Map.Map ModuleName.Raw Result -> NE.List MainResult -> Either Exit.BuildProblem Artifacts
1022toArtifacts (Env _ _ pkg _ _ _) foreigns results mainResults =
1023 case gatherProblemsOrMains results mainResults of
1024 Left (NE.List e es) ->
1025 Left (Exit.BuildModuleProblems e es)
1028 Right $ Artifacts pkg foreigns mains $
1029 Map.foldrWithKey addInside (foldr addOutside [] mainResults) results
1032gatherProblemsOrMains :: Map.Map ModuleName.Raw Result -> NE.List MainResult -> Either (NE.List Error.Module) (NE.List Main)
1033gatherProblemsOrMains results (NE.List mainResult mainResults) =
1035 sortMain result (es, mains) =
1037 RInside n -> ( es, Inside n : mains)
1038 ROutsideOk n i o -> ( es, Outside n i o : mains)
1039 ROutsideErr e -> (e:es, mains)
1040 ROutsideBlocked -> ( es, mains)
1042 errors = Map.foldr addErrors [] results
1044 case (mainResult, foldr sortMain (errors, []) mainResults) of
1045 (RInside n , ( [], ms)) -> Right (NE.List (Inside n) ms)
1046 (RInside _ , (e:es, _ )) -> Left (NE.List e es)
1047 (ROutsideOk n i o, ( [], ms)) -> Right (NE.List (Outside n i o) ms)
1048 (ROutsideOk _ _ _, (e:es, _ )) -> Left (NE.List e es)
1049 (ROutsideErr e , ( es, _ )) -> Left (NE.List e es)
1050 (ROutsideBlocked , ( [], _ )) -> error "seems like elm-stuff/ is corrupted"
1051 (ROutsideBlocked , (e:es, _ )) -> Left (NE.List e es)
1054addInside :: ModuleName.Raw -> Result -> [Module] -> [Module]
1055addInside name result modules =
1057 RNew _ iface objs _ -> Fresh name iface objs : modules
1058 RSame _ iface objs _ -> Fresh name iface objs : modules
1059 RCached main mvar -> Cached name main mvar : modules
1060 RNotFound _ -> error (badInside name)
1061 RProblem _ -> error (badInside name)
1062 RBlocked -> error (badInside name)
1063 RForeign _ -> modules
1067badInside :: ModuleName.Raw -> [Char]
1069 "Error from `" ++ Name.toChars name ++ "` should have been reported already."
1072addOutside :: MainResult -> [Module] -> [Module]
1073addOutside main modules =
1075 RInside _ -> modules
1076 ROutsideOk name iface objs -> Fresh name iface objs : modules
1077 ROutsideErr _ -> modules
1078 ROutsideBlocked -> modules
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list