1{-# OPTIONS_GHC -Wno-unused-do-bind #-}
2{-# LANGUAGE BangPatterns, GADTs, OverloadedStrings #-}
18import Control.Concurrent (forkIO)
19import Control.Concurrent.MVar
20import Control.Monad (filterM, mapM_, sequence_)
21import qualified Data.ByteString as B
22import qualified Data.Char as Char
23import qualified Data.Graph as Graph
24import qualified Data.List as List
25import qualified Data.Map.Utils as Map
26import qualified Data.Map.Strict as Map
27import Data.Map.Strict ((!))
28import qualified Data.Maybe as Maybe
29import qualified Data.Name as Name
30import qualified Data.NonEmptyList as NE
31import qualified Data.OneOrMore as OneOrMore
32import qualified Data.Set as Set
33import qualified System.Directory as Dir
34import qualified System.FilePath as FP
35import System.FilePath ((</>), (<.>))
37import qualified AST.Canonical as Can
38import qualified AST.Source as Src
39import qualified AST.Optimized as Opt
40import qualified Compile
41import qualified Elm.Details as Details
42import qualified Elm.Docs as Docs
43import qualified Elm.Interface as I
44import qualified Elm.ModuleName as ModuleName
45import qualified Elm.Outline as Outline
46import qualified Elm.Package as Pkg
48import qualified Json.Encode as E
49import qualified Parse.Module as Parse
50import qualified Reporting
51import qualified Reporting.Annotation as A
52import qualified Reporting.Error as Error
53import qualified Reporting.Error.Docs as EDocs
54import qualified Reporting.Error.Syntax as Syntax
55import qualified Reporting.Error.Import as Import
56import qualified Reporting.Exit as Exit
57import qualified Reporting.Render.Type.Localizer as L
67 { _key :: Reporting.BKey
69 , _project :: Parse.ProjectType
70 , _srcDirs :: [AbsoluteSrcDir]
71 , _buildID :: Details.BuildID
72 , _locals :: Map.Map ModuleName.Raw Details.Local
73 , _foreigns :: Map.Map ModuleName.Raw Details.Foreign
77makeEnv :: Reporting.BKey -> FilePath -> Details.Details -> IO Env
78makeEnv key root (Details.Details _ validOutline buildID locals foreigns _) =
80 Details.ValidApp givenSrcDirs ->
81 do srcDirs <- traverse (toAbsoluteSrcDir root) (NE.toList givenSrcDirs)
82 return $ Env key root Parse.Application srcDirs buildID locals foreigns
84 Details.ValidPkg pkg _ _ ->
85 do srcDir <- toAbsoluteSrcDir root (Outline.RelativeSrcDir "src")
86 return $ Env key root (Parse.Package pkg) [srcDir] buildID locals foreigns
93newtype AbsoluteSrcDir =
94 AbsoluteSrcDir FilePath
97toAbsoluteSrcDir :: FilePath -> Outline.SrcDir -> IO AbsoluteSrcDir
98toAbsoluteSrcDir root srcDir =
99 AbsoluteSrcDir <$> Dir.canonicalizePath
102 Outline.AbsoluteSrcDir dir -> dir
103 Outline.RelativeSrcDir dir -> root </> dir
107addRelative :: AbsoluteSrcDir -> FilePath -> FilePath
108addRelative (AbsoluteSrcDir srcDir) path =
116-- PERF try using IORef semephore on file crawl phase?
117-- described in Chapter 13 of Parallel and Concurrent Programming in Haskell by Simon Marlow
118-- https://www.oreilly.com/library/view/parallel-and-concurrent/9781449335939/ch13.html#sec_conc-par-overhead
120fork :: IO a -> IO (MVar a)
122 do mvar <- newEmptyMVar
123 _ <- forkIO $ putMVar mvar =<< work
127{-# INLINE forkWithKey #-}
128forkWithKey :: (k -> a -> IO b) -> Map.Map k a -> IO (Map.Map k (MVar b))
129forkWithKey func dict =
130 Map.traverseWithKey (\k v -> fork (func k v)) dict
137fromExposed :: Reporting.Style -> FilePath -> Details.Details -> DocsGoal docs -> NE.List ModuleName.Raw -> IO (Either Exit.BuildProblem docs)
138fromExposed style root details docsGoal exposed@(NE.List e es) =
139 Reporting.trackBuild style $ \key ->
140 do env <- makeEnv key root details
141 dmvar <- Details.loadInterfaces root details
145 let docsNeed = toDocsNeed docsGoal
146 roots <- Map.fromKeysA (fork . crawlModule env mvar docsNeed) (e:es)
149 statuses <- traverse readMVar =<< readMVar mvar
152 midpoint <- checkMidpoint dmvar statuses
155 return (Left (Exit.BuildProjectProblem problem))
158 do rmvar <- newEmptyMVar
159 resultMVars <- forkWithKey (checkModule env foreigns rmvar) statuses
160 putMVar rmvar resultMVars
161 results <- traverse readMVar resultMVars
162 writeDetails root details results
163 finalizeExposed root docsGoal exposed results
173 , _deps :: Dependencies
174 , _roots :: NE.List Root
175 , _modules :: [Module]
180 = Fresh ModuleName.Raw I.Interface Opt.LocalGraph
181 | Cached ModuleName.Raw Bool (MVar CachedInterface)
185 Map.Map ModuleName.Canonical I.DependencyInterface
188fromPaths :: Reporting.Style -> FilePath -> Details.Details -> NE.List FilePath -> IO (Either Exit.BuildProblem Artifacts)
189fromPaths style root details paths =
190 Reporting.trackBuild style $ \key ->
191 do env <- makeEnv key root details
193 elroots <- findRoots env paths
196 return (Left (Exit.BuildProjectProblem problem))
200 dmvar <- Details.loadInterfaces root details
201 smvar <- newMVar Map.empty
202 srootMVars <- traverse (fork . crawlRoot env smvar) lroots
203 sroots <- traverse readMVar srootMVars
204 statuses <- traverse readMVar =<< readMVar smvar
206 midpoint <- checkMidpointAndRoots dmvar statuses sroots
209 return (Left (Exit.BuildProjectProblem problem))
213 rmvar <- newEmptyMVar
214 resultsMVars <- forkWithKey (checkModule env foreigns rmvar) statuses
215 putMVar rmvar resultsMVars
216 rrootMVars <- traverse (fork . checkRoot env resultsMVars) sroots
217 results <- traverse readMVar resultsMVars
218 writeDetails root details results
219 toArtifacts env foreigns results <$> traverse readMVar rrootMVars
226getRootNames :: Artifacts -> NE.List ModuleName.Raw
227getRootNames (Artifacts _ _ roots _) =
228 fmap getRootName roots
231getRootName :: Root -> ModuleName.Raw
235 Outside name _ _ -> name
243 Map.Map ModuleName.Raw (MVar Status)
247 = SCached Details.Local
248 | SChanged Details.Local B.ByteString Src.Module DocsNeed
249 | SBadImport Import.Problem
250 | SBadSyntax FilePath File.Time B.ByteString Syntax.Error
255crawlDeps :: Env -> MVar StatusDict -> [ModuleName.Raw] -> a -> IO a
256crawlDeps env mvar deps blockedValue =
257 do statusDict <- takeMVar mvar
258 let depsDict = Map.fromKeys (\_ -> ()) deps
259 let newsDict = Map.difference depsDict statusDict
260 statuses <- Map.traverseWithKey crawlNew newsDict
261 putMVar mvar (Map.union statuses statusDict)
262 mapM_ readMVar statuses
265 crawlNew name () = fork (crawlModule env mvar (DocsNeed False) name)
268crawlModule :: Env -> MVar StatusDict -> DocsNeed -> ModuleName.Raw -> IO Status
269crawlModule env@(Env _ root projectType srcDirs buildID locals foreigns) mvar docsNeed name =
270 do let fileName = ModuleName.toFilePath name <.> "elm"
272 paths <- filterM File.exists (map (`addRelative` fileName) srcDirs)
276 case Map.lookup name foreigns of
277 Just (Details.Foreign dep deps) ->
278 return $ SBadImport $ Import.Ambiguous path [] dep deps
281 do newTime <- File.getTime path
282 case Map.lookup name locals of
284 crawlFile env mvar docsNeed name path newTime buildID
286 Just local@(Details.Local oldPath oldTime deps _ lastChange _) ->
287 if path /= oldPath || oldTime /= newTime || needsDocs docsNeed
288 then crawlFile env mvar docsNeed name path newTime lastChange
289 else crawlDeps env mvar deps (SCached local)
292 return $ SBadImport $ Import.AmbiguousLocal (FP.makeRelative root p1) (FP.makeRelative root p2) (map (FP.makeRelative root) ps)
295 case Map.lookup name foreigns of
296 Just (Details.Foreign dep deps) ->
299 return $ SForeign dep
302 return $ SBadImport $ Import.AmbiguousForeign dep d ds
305 if Name.isKernel name && Parse.isKernel projectType then
306 do exists <- File.exists ("src" </> ModuleName.toFilePath name <.> "js")
307 return $ if exists then SKernel else SBadImport Import.NotFound
309 return $ SBadImport Import.NotFound
312crawlFile :: Env -> MVar StatusDict -> DocsNeed -> ModuleName.Raw -> FilePath -> File.Time -> Details.BuildID -> IO Status
313crawlFile env@(Env _ root projectType _ buildID _ _) mvar docsNeed expectedName path time lastChange =
314 do source <- File.readUtf8 (root </> path)
316 case Parse.fromByteString projectType source of
318 return $ SBadSyntax path time source err
320 Right modul@(Src.Module maybeActualName _ _ imports values _ _ _ _) ->
321 case maybeActualName of
323 return $ SBadSyntax path time source (Syntax.ModuleNameUnspecified expectedName)
325 Just name@(A.At _ actualName) ->
326 if expectedName == actualName then
328 deps = map Src.getImportName imports
329 local = Details.Local path time deps (any isMain values) lastChange buildID
331 crawlDeps env mvar deps (SChanged local source modul docsNeed)
333 return $ SBadSyntax path time source (Syntax.ModuleNameMismatch expectedName name)
336isMain :: A.Located Src.Value -> Bool
337isMain (A.At _ (Src.Value (A.At _ name) _ _ _)) =
346 Map.Map ModuleName.Raw (MVar Result)
350 = RNew !Details.Local !I.Interface !Opt.LocalGraph !(Maybe Docs.Module)
351 | RSame !Details.Local !I.Interface !Opt.LocalGraph !(Maybe Docs.Module)
352 | RCached Bool Details.BuildID (MVar CachedInterface)
353 | RNotFound Import.Problem
354 | RProblem Error.Module
356 | RForeign I.Interface
366checkModule :: Env -> Dependencies -> MVar ResultDict -> ModuleName.Raw -> Status -> IO Result
367checkModule env@(Env _ root projectType _ _ _ _) foreigns resultsMVar name status =
369 SCached local@(Details.Local path time deps hasMain lastChange lastCompile) ->
370 do results <- readMVar resultsMVar
371 depsStatus <- checkDeps root results deps lastCompile
374 do source <- File.readUtf8 path
375 case Parse.fromByteString projectType source of
376 Right modul -> compile env (DocsNeed False) local source ifaces modul
379 Error.Module name path time source (Error.BadSyntax err)
382 do mvar <- newMVar Unneeded
383 return (RCached hasMain lastChange mvar)
388 DepsNotFound problems ->
389 do source <- File.readUtf8 path
390 return $ RProblem $ Error.Module name path time source $
391 case Parse.fromByteString projectType source of
392 Right (Src.Module _ _ _ imports _ _ _ _ _) ->
393 Error.BadImports (toImportErrors env results imports problems)
398 SChanged local@(Details.Local path time deps _ _ lastCompile) source modul@(Src.Module _ _ _ imports _ _ _ _ _) docsNeed ->
399 do results <- readMVar resultsMVar
400 depsStatus <- checkDeps root results deps lastCompile
403 compile env docsNeed local source ifaces modul
405 DepsSame same cached ->
406 do maybeLoaded <- loadInterfaces root same cached
408 Nothing -> return RBlocked
409 Just ifaces -> compile env docsNeed local source ifaces modul
414 DepsNotFound problems ->
415 return $ RProblem $ Error.Module name path time source $
416 Error.BadImports (toImportErrors env results imports problems)
418 SBadImport importProblem ->
419 return (RNotFound importProblem)
421 SBadSyntax path time source err ->
422 return $ RProblem $ Error.Module name path time source $
426 case foreigns ! ModuleName.Canonical home name of
427 I.Public iface -> return (RForeign iface)
428 I.Private _ _ _ -> error $ "mistakenly seeing private interface for " ++ Pkg.toChars home ++ " " ++ ModuleName.toChars name
439 = DepsChange (Map.Map ModuleName.Raw I.Interface)
440 | DepsSame [Dep] [CDep]
442 | DepsNotFound (NE.List (ModuleName.Raw, Import.Problem))
445checkDeps :: FilePath -> ResultDict -> [ModuleName.Raw] -> Details.BuildID -> IO DepsStatus
446checkDeps root results deps lastCompile =
447 checkDepsHelp root results deps [] [] [] [] False 0 lastCompile
450type Dep = (ModuleName.Raw, I.Interface)
451type CDep = (ModuleName.Raw, MVar CachedInterface)
454checkDepsHelp :: FilePath -> ResultDict -> [ModuleName.Raw] -> [Dep] -> [Dep] -> [CDep] -> [(ModuleName.Raw,Import.Problem)] -> Bool -> Details.BuildID -> Details.BuildID -> IO DepsStatus
455checkDepsHelp root results deps new same cached importProblems isBlocked lastDepChange lastCompile =
458 do result <- readMVar (results ! dep)
460 RNew (Details.Local _ _ _ _ lastChange _) iface _ _ ->
461 checkDepsHelp root results otherDeps ((dep,iface) : new) same cached importProblems isBlocked (max lastChange lastDepChange) lastCompile
463 RSame (Details.Local _ _ _ _ lastChange _) iface _ _ ->
464 checkDepsHelp root results otherDeps new ((dep,iface) : same) cached importProblems isBlocked (max lastChange lastDepChange) lastCompile
466 RCached _ lastChange mvar ->
467 checkDepsHelp root results otherDeps new same ((dep,mvar) : cached) importProblems isBlocked (max lastChange lastDepChange) lastCompile
470 checkDepsHelp root results otherDeps new same cached ((dep,prob) : importProblems) True lastDepChange lastCompile
473 checkDepsHelp root results otherDeps new same cached importProblems True lastDepChange lastCompile
476 checkDepsHelp root results otherDeps new same cached importProblems True lastDepChange lastCompile
479 checkDepsHelp root results otherDeps new ((dep,iface) : same) cached importProblems isBlocked lastDepChange lastCompile
482 checkDepsHelp root results otherDeps new same cached importProblems isBlocked lastDepChange lastCompile
486 case reverse importProblems of
488 return $ DepsNotFound (NE.List p ps)
494 else if null new && lastDepChange <= lastCompile then
495 return $ DepsSame same cached
498 do maybeLoaded <- loadInterfaces root same cached
500 Nothing -> return DepsBlock
501 Just ifaces -> return $ DepsChange $ Map.union (Map.fromList new) ifaces
508toImportErrors :: Env -> ResultDict -> [Src.Import] -> NE.List (ModuleName.Raw, Import.Problem) -> NE.List Import.Error
509toImportErrors (Env _ _ _ _ _ locals foreigns) results imports problems =
513 [ Map.keysSet foreigns
515 , Map.keysSet results
519 Set.difference knownModules (Set.fromList (map Src.getImportName imports))
522 Map.fromList (map (\(Src.Import (A.At region name) _ _) -> (name, region)) imports)
524 toError (name, problem) =
525 Import.Error (regionDict ! name) name unimportedModules problem
527 fmap toError problems
531-- LOAD CACHED INTERFACES
534loadInterfaces :: FilePath -> [Dep] -> [CDep] -> IO (Maybe (Map.Map ModuleName.Raw I.Interface))
535loadInterfaces root same cached =
536 do loading <- traverse (fork . loadInterface root) cached
537 maybeLoaded <- traverse readMVar loading
538 case sequence maybeLoaded of
543 return $ Just $ Map.union (Map.fromList loaded) (Map.fromList same)
546loadInterface :: FilePath -> CDep -> IO (Maybe Dep)
547loadInterface root (name, ciMvar) =
548 do cachedInterface <- takeMVar ciMvar
549 case cachedInterface of
551 do putMVar ciMvar cachedInterface
555 do putMVar ciMvar cachedInterface
556 return (Just (name, iface))
559 do maybeIface <- File.readBinary (Stuff.elmi root name)
562 do putMVar ciMvar Corrupted
566 do putMVar ciMvar (Loaded iface)
567 return (Just (name, iface))
574checkMidpoint :: MVar (Maybe Dependencies) -> Map.Map ModuleName.Raw Status -> IO (Either Exit.BuildProjectProblem Dependencies)
575checkMidpoint dmvar statuses =
576 case checkForCycles statuses of
578 do maybeForeigns <- readMVar dmvar
579 case maybeForeigns of
580 Nothing -> return (Left Exit.BP_CannotLoadDependencies)
581 Just fs -> return (Right fs)
583 Just (NE.List name names) ->
584 do _ <- readMVar dmvar
585 return (Left (Exit.BP_Cycle name names))
588checkMidpointAndRoots :: MVar (Maybe Dependencies) -> Map.Map ModuleName.Raw Status -> NE.List RootStatus -> IO (Either Exit.BuildProjectProblem Dependencies)
589checkMidpointAndRoots dmvar statuses sroots =
590 case checkForCycles statuses of
592 case checkUniqueRoots statuses sroots of
594 do maybeForeigns <- readMVar dmvar
595 case maybeForeigns of
596 Nothing -> return (Left Exit.BP_CannotLoadDependencies)
597 Just fs -> return (Right fs)
600 do _ <- readMVar dmvar
601 return (Left problem)
603 Just (NE.List name names) ->
604 do _ <- readMVar dmvar
605 return (Left (Exit.BP_Cycle name names))
612checkForCycles :: Map.Map ModuleName.Raw Status -> Maybe (NE.List ModuleName.Raw)
613checkForCycles modules =
615 !graph = Map.foldrWithKey addToGraph [] modules
616 !sccs = Graph.stronglyConnComp graph
618 checkForCyclesHelp sccs
621checkForCyclesHelp :: [Graph.SCC ModuleName.Raw] -> Maybe (NE.List ModuleName.Raw)
622checkForCyclesHelp sccs =
629 Graph.AcyclicSCC _ -> checkForCyclesHelp otherSccs
630 Graph.CyclicSCC [] -> checkForCyclesHelp otherSccs
631 Graph.CyclicSCC (m:ms) -> Just (NE.List m ms)
635 ( ModuleName.Raw, ModuleName.Raw, [ModuleName.Raw] )
638addToGraph :: ModuleName.Raw -> Status -> [Node] -> [Node]
639addToGraph name status graph =
643 SCached (Details.Local _ _ deps _ _ _) -> deps
644 SChanged (Details.Local _ _ deps _ _ _) _ _ _ -> deps
646 SBadSyntax _ _ _ _ -> []
650 (name, name, dependencies) : graph
657checkUniqueRoots :: Map.Map ModuleName.Raw Status -> NE.List RootStatus -> Maybe Exit.BuildProjectProblem
658checkUniqueRoots insides sroots =
661 Map.fromListWith OneOrMore.more (Maybe.mapMaybe rootStatusToNamePathPair (NE.toList sroots))
663 case Map.traverseWithKey checkOutside outsidesDict of
668 case sequence_ (Map.intersectionWithKey checkInside outsides insides) of
670 Left problem -> Just problem
673rootStatusToNamePathPair :: RootStatus -> Maybe (ModuleName.Raw, OneOrMore.OneOrMore FilePath)
674rootStatusToNamePathPair sroot =
677 SOutsideOk (Details.Local path _ _ _ _ _) _ modul -> Just (Src.getName modul, OneOrMore.one path)
678 SOutsideErr _ -> Nothing
681checkOutside :: ModuleName.Raw -> OneOrMore.OneOrMore FilePath -> Either Exit.BuildProjectProblem FilePath
682checkOutside name paths =
683 case OneOrMore.destruct NE.List paths of
684 NE.List p [] -> Right p
685 NE.List p1 (p2:_) -> Left (Exit.BP_RootNameDuplicate name p1 p2)
688checkInside :: ModuleName.Raw -> FilePath -> Status -> Either Exit.BuildProjectProblem ()
689checkInside name p1 status =
691 SCached (Details.Local p2 _ _ _ _ _) -> Left (Exit.BP_RootNameDuplicate name p1 p2)
692 SChanged (Details.Local p2 _ _ _ _ _) _ _ _ -> Left (Exit.BP_RootNameDuplicate name p1 p2)
693 SBadImport _ -> Right ()
694 SBadSyntax _ _ _ _ -> Right ()
695 SForeign _ -> Right ()
703compile :: Env -> DocsNeed -> Details.Local -> B.ByteString -> Map.Map ModuleName.Raw I.Interface -> Src.Module -> IO Result
704compile (Env key root projectType _ buildID _ _) docsNeed (Details.Local path time deps main lastChange _) source ifaces modul =
706 pkg = projectTypeToPkg projectType
708 case Compile.compile pkg ifaces modul of
709 Right (Compile.Artifacts canonical annotations objects) ->
710 case makeDocs docsNeed canonical of
713 Error.Module (Src.getName modul) path time source (Error.BadDocs err)
716 do let name = Src.getName modul
717 let iface = I.fromModule pkg canonical annotations
718 let elmi = Stuff.elmi root name
719 File.writeBinary (Stuff.elmo root name) objects
720 maybeOldi <- File.readBinary elmi
722 Just oldi | oldi == iface ->
723 do -- iface should be fully forced by equality check
724 Reporting.report key Reporting.BDone
725 let local = Details.Local path time deps main lastChange buildID
726 return (RSame local iface objects docs)
729 do -- iface may be lazy still
730 File.writeBinary elmi iface
731 Reporting.report key Reporting.BDone
732 let local = Details.Local path time deps main buildID buildID
733 return (RNew local iface objects docs)
737 Error.Module (Src.getName modul) path time source err
740projectTypeToPkg :: Parse.ProjectType -> Pkg.Name
741projectTypeToPkg projectType =
743 Parse.Package pkg -> pkg
744 Parse.Application -> Pkg.dummyName
751writeDetails :: FilePath -> Details.Details -> Map.Map ModuleName.Raw Result -> IO ()
752writeDetails root (Details.Details time outline buildID locals foreigns extras) results =
753 File.writeBinary (Stuff.details root) $
754 Details.Details time outline buildID (Map.foldrWithKey addNewLocal locals results) foreigns extras
757addNewLocal :: ModuleName.Raw -> Result -> Map.Map ModuleName.Raw Details.Local -> Map.Map ModuleName.Raw Details.Local
758addNewLocal name result locals =
760 RNew local _ _ _ -> Map.insert name local locals
761 RSame local _ _ _ -> Map.insert name local locals
762 RCached _ _ _ -> locals
763 RNotFound _ -> locals
774finalizeExposed :: FilePath -> DocsGoal docs -> NE.List ModuleName.Raw -> Map.Map ModuleName.Raw Result -> IO (Either Exit.BuildProblem docs)
775finalizeExposed root docsGoal exposed results =
776 case foldr (addImportProblems results) [] (NE.toList exposed) of
778 return $ Left $ Exit.BuildProjectProblem (Exit.BP_MissingExposed (NE.List p ps))
781 case Map.foldr addErrors [] results of
782 [] -> Right <$> finalizeDocs docsGoal results
783 e:es -> return $ Left $ Exit.BuildBadModules root e es
786addErrors :: Result -> [Error.Module] -> [Error.Module]
787addErrors result errors =
789 RNew _ _ _ _ -> errors
790 RSame _ _ _ _ -> errors
791 RCached _ _ _ -> errors
792 RNotFound _ -> errors
793 RProblem e -> e:errors
799addImportProblems :: Map.Map ModuleName.Raw Result -> ModuleName.Raw -> [(ModuleName.Raw, Import.Problem)] -> [(ModuleName.Raw, Import.Problem)]
800addImportProblems results name problems =
801 case results ! name of
802 RNew _ _ _ _ -> problems
803 RSame _ _ _ _ -> problems
804 RCached _ _ _ -> problems
805 RNotFound p -> (name, p) : problems
806 RProblem _ -> problems
808 RForeign _ -> problems
817 KeepDocs :: DocsGoal Docs.Documentation
818 WriteDocs :: FilePath -> DocsGoal ()
819 IgnoreDocs :: DocsGoal ()
823 DocsNeed { needsDocs :: Bool }
826toDocsNeed :: DocsGoal a -> DocsNeed
829 IgnoreDocs -> DocsNeed False
830 WriteDocs _ -> DocsNeed True
831 KeepDocs -> DocsNeed True
834makeDocs :: DocsNeed -> Can.Module -> Either EDocs.Error (Maybe Docs.Module)
835makeDocs (DocsNeed isNeeded) modul =
837 case Docs.fromModule modul of
838 Right docs -> Right (Just docs)
844finalizeDocs :: DocsGoal docs -> Map.Map ModuleName.Raw Result -> IO docs
845finalizeDocs goal results =
848 return $ Map.mapMaybe toDocs results
851 E.writeUgly path $ Docs.encode $ Map.mapMaybe toDocs results
857toDocs :: Result -> Maybe Docs.Module
862 RCached _ _ _ -> Nothing
863 RNotFound _ -> Nothing
864 RProblem _ -> Nothing
866 RForeign _ -> Nothing
871--------------------------------------------------------------------------------
872------ NOW FOR SOME REPL STUFF -------------------------------------------------
873--------------------------------------------------------------------------------
881 { _repl_home :: ModuleName.Canonical
882 , _repl_modules :: [Module]
883 , _repl_localizer :: L.Localizer
884 , _repl_annotations :: Map.Map Name.Name Can.Annotation
888fromRepl :: FilePath -> Details.Details -> B.ByteString -> IO (Either Exit.Repl ReplArtifacts)
889fromRepl root details source =
890 do env@(Env _ _ projectType _ _ _ _) <- makeEnv Reporting.ignorer root details
891 case Parse.fromByteString projectType source of
893 return $ Left $ Exit.ReplBadInput source $ Error.BadSyntax syntaxError
895 Right modul@(Src.Module _ _ _ imports _ _ _ _ _) ->
896 do dmvar <- Details.loadInterfaces root details
898 let deps = map Src.getImportName imports
899 mvar <- newMVar Map.empty
900 crawlDeps env mvar deps ()
902 statuses <- traverse readMVar =<< readMVar mvar
903 midpoint <- checkMidpoint dmvar statuses
907 return $ Left $ Exit.ReplProjectProblem problem
910 do rmvar <- newEmptyMVar
911 resultMVars <- forkWithKey (checkModule env foreigns rmvar) statuses
912 putMVar rmvar resultMVars
913 results <- traverse readMVar resultMVars
914 writeDetails root details results
915 depsStatus <- checkDeps root resultMVars deps 0
916 finalizeReplArtifacts env source modul depsStatus resultMVars results
919finalizeReplArtifacts :: Env -> B.ByteString -> Src.Module -> DepsStatus -> ResultDict -> Map.Map ModuleName.Raw Result -> IO (Either Exit.Repl ReplArtifacts)
920finalizeReplArtifacts env@(Env _ root projectType _ _ _ _) source modul@(Src.Module _ _ _ imports _ _ _ _ _) depsStatus resultMVars results =
923 projectTypeToPkg projectType
925 compileInput ifaces =
926 case Compile.compile pkg ifaces modul of
927 Right (Compile.Artifacts canonical annotations objects) ->
929 h = Can._name canonical
930 m = Fresh (Src.getName modul) (I.fromModule pkg canonical annotations) objects
931 ms = Map.foldrWithKey addInside [] results
933 return $ Right $ ReplArtifacts h (m:ms) (L.fromModule modul) annotations
936 return $ Left $ Exit.ReplBadInput source errors
942 DepsSame same cached ->
943 do maybeLoaded <- loadInterfaces root same cached
945 Just ifaces -> compileInput ifaces
946 Nothing -> return $ Left $ Exit.ReplBadCache
949 case Map.foldr addErrors [] results of
950 [] -> return $ Left $ Exit.ReplBlocked
951 e:es -> return $ Left $ Exit.ReplBadLocalDeps root e es
953 DepsNotFound problems ->
954 return $ Left $ Exit.ReplBadInput source $ Error.BadImports $
955 toImportErrors env resultMVars imports problems
959--------------------------------------------------------------------------------
960--------------------------------------------------------------------------------
961------ AFTER THIS, EVERYTHING IS ABOUT HANDLING MODULES GIVEN BY FILEPATH ------
962--------------------------------------------------------------------------------
963--------------------------------------------------------------------------------
971 = LInside ModuleName.Raw
975findRoots :: Env -> NE.List FilePath -> IO (Either Exit.BuildProjectProblem (NE.List RootLocation))
977 do mvars <- traverse (fork . getRootInfo env) paths
978 einfos <- traverse readMVar mvars
979 return $ checkRoots =<< sequence einfos
982checkRoots :: NE.List RootInfo -> Either Exit.BuildProjectProblem (NE.List RootLocation)
985 toOneOrMore loc@(RootInfo absolute _ _) =
986 (absolute, OneOrMore.one loc)
988 fromOneOrMore loc locs =
991 loc2:_ -> Left (Exit.BP_MainPathDuplicate (_relative loc) (_relative loc2))
993 fmap (\_ -> fmap _location infos) $
994 traverse (OneOrMore.destruct fromOneOrMore) $
995 Map.fromListWith OneOrMore.more $ map toOneOrMore (NE.toList infos)
1004 { _absolute :: FilePath
1005 , _relative :: FilePath
1006 , _location :: RootLocation
1010getRootInfo :: Env -> FilePath -> IO (Either Exit.BuildProjectProblem RootInfo)
1011getRootInfo env path =
1012 do exists <- File.exists path
1014 then getRootInfoHelp env path =<< Dir.canonicalizePath path
1015 else return (Left (Exit.BP_PathUnknown path))
1018getRootInfoHelp :: Env -> FilePath -> FilePath -> IO (Either Exit.BuildProjectProblem RootInfo)
1019getRootInfoHelp (Env _ _ _ srcDirs _ _ _) path absolutePath =
1021 (dirs, file) = FP.splitFileName absolutePath
1022 (final, ext) = FP.splitExtension file
1026 return $ Left $ Exit.BP_WithBadExtension path
1029 absoluteSegments = FP.splitDirectories dirs ++ [final]
1031 case Maybe.mapMaybe (isInsideSrcDirByPath absoluteSegments) srcDirs of
1033 return $ Right $ RootInfo absolutePath path (LOutside path)
1035 [(_, Right names)] ->
1036 do let name = Name.fromChars (List.intercalate "." names)
1037 matchingDirs <- filterM (isInsideSrcDirByName names) srcDirs
1038 case matchingDirs of
1040 do let p1 = addRelative d1 (FP.joinPath names <.> "elm")
1041 let p2 = addRelative d2 (FP.joinPath names <.> "elm")
1042 return $ Left $ Exit.BP_RootNameDuplicate name p1 p2
1045 return $ Right $ RootInfo absolutePath path (LInside name)
1047 [(s, Left names)] ->
1048 return $ Left $ Exit.BP_RootNameInvalid path s names
1051 return $ Left $ Exit.BP_WithAmbiguousSrcDir path s1 s2
1055isInsideSrcDirByName :: [String] -> AbsoluteSrcDir -> IO Bool
1056isInsideSrcDirByName names srcDir =
1057 File.exists (addRelative srcDir (FP.joinPath names <.> "elm"))
1060isInsideSrcDirByPath :: [String] -> AbsoluteSrcDir -> Maybe (FilePath, Either [String] [String])
1061isInsideSrcDirByPath segments (AbsoluteSrcDir srcDir) =
1062 case dropPrefix (FP.splitDirectories srcDir) segments of
1067 if all isGoodName names
1068 then Just (srcDir, Right names)
1069 else Just (srcDir, Left names)
1072isGoodName :: [Char] -> Bool
1079 Char.isUpper char && all (\c -> Char.isAlphaNum c || c == '_') chars
1082-- INVARIANT: Dir.canonicalizePath has been run on both inputs
1084dropPrefix :: [FilePath] -> [FilePath] -> Maybe [FilePath]
1085dropPrefix roots paths =
1093 p:ps -> if r == p then dropPrefix rs ps else Nothing
1101 = SInside ModuleName.Raw
1102 | SOutsideOk Details.Local B.ByteString Src.Module
1103 | SOutsideErr Error.Module
1106crawlRoot :: Env -> MVar StatusDict -> RootLocation -> IO RootStatus
1107crawlRoot env@(Env _ _ projectType _ buildID _ _) mvar root =
1110 do statusMVar <- newEmptyMVar
1111 statusDict <- takeMVar mvar
1112 putMVar mvar (Map.insert name statusMVar statusDict)
1113 putMVar statusMVar =<< crawlModule env mvar (DocsNeed False) name
1114 return (SInside name)
1117 do time <- File.getTime path
1118 source <- File.readUtf8 path
1119 case Parse.fromByteString projectType source of
1120 Right modul@(Src.Module _ _ _ imports values _ _ _ _) ->
1121 do let deps = map Src.getImportName imports
1122 let local = Details.Local path time deps (any isMain values) buildID buildID
1123 crawlDeps env mvar deps (SOutsideOk local source modul)
1126 return $ SOutsideErr $
1127 Error.Module "???" path time source (Error.BadSyntax syntaxError)
1135 = RInside ModuleName.Raw
1136 | ROutsideOk ModuleName.Raw I.Interface Opt.LocalGraph
1137 | ROutsideErr Error.Module
1141checkRoot :: Env -> ResultDict -> RootStatus -> IO RootResult
1142checkRoot env@(Env _ root _ _ _ _ _) results rootStatus =
1145 return (RInside name)
1148 return (ROutsideErr err)
1150 SOutsideOk local@(Details.Local path time deps _ _ lastCompile) source modul@(Src.Module _ _ _ imports _ _ _ _ _) ->
1151 do depsStatus <- checkDeps root results deps lastCompile
1153 DepsChange ifaces ->
1154 compileOutside env local source ifaces modul
1156 DepsSame same cached ->
1157 do maybeLoaded <- loadInterfaces root same cached
1159 Nothing -> return ROutsideBlocked
1160 Just ifaces -> compileOutside env local source ifaces modul
1163 return ROutsideBlocked
1165 DepsNotFound problems ->
1166 return $ ROutsideErr $ Error.Module (Src.getName modul) path time source $
1167 Error.BadImports (toImportErrors env results imports problems)
1170compileOutside :: Env -> Details.Local -> B.ByteString -> Map.Map ModuleName.Raw I.Interface -> Src.Module -> IO RootResult
1171compileOutside (Env key _ projectType _ _ _ _) (Details.Local path time _ _ _ _) source ifaces modul =
1173 pkg = projectTypeToPkg projectType
1174 name = Src.getName modul
1176 case Compile.compile pkg ifaces modul of
1177 Right (Compile.Artifacts canonical annotations objects) ->
1178 do Reporting.report key Reporting.BDone
1179 return $ ROutsideOk name (I.fromModule pkg canonical annotations) objects
1182 return $ ROutsideErr $ Error.Module name path time source errors
1190 = Inside ModuleName.Raw
1191 | Outside ModuleName.Raw I.Interface Opt.LocalGraph
1194toArtifacts :: Env -> Dependencies -> Map.Map ModuleName.Raw Result -> NE.List RootResult -> Either Exit.BuildProblem Artifacts
1195toArtifacts (Env _ root projectType _ _ _ _) foreigns results rootResults =
1196 case gatherProblemsOrMains results rootResults of
1197 Left (NE.List e es) ->
1198 Left (Exit.BuildBadModules root e es)
1201 Right $ Artifacts (projectTypeToPkg projectType) foreigns roots $
1202 Map.foldrWithKey addInside (foldr addOutside [] rootResults) results
1205gatherProblemsOrMains :: Map.Map ModuleName.Raw Result -> NE.List RootResult -> Either (NE.List Error.Module) (NE.List Root)
1206gatherProblemsOrMains results (NE.List rootResult rootResults) =
1208 addResult result (es, roots) =
1210 RInside n -> ( es, Inside n : roots)
1211 ROutsideOk n i o -> ( es, Outside n i o : roots)
1212 ROutsideErr e -> (e:es, roots)
1213 ROutsideBlocked -> ( es, roots)
1215 errors = Map.foldr addErrors [] results
1217 case (rootResult, foldr addResult (errors, []) rootResults) of
1218 (RInside n , ( [], ms)) -> Right (NE.List (Inside n) ms)
1219 (RInside _ , (e:es, _ )) -> Left (NE.List e es)
1220 (ROutsideOk n i o, ( [], ms)) -> Right (NE.List (Outside n i o) ms)
1221 (ROutsideOk _ _ _, (e:es, _ )) -> Left (NE.List e es)
1222 (ROutsideErr e , ( es, _ )) -> Left (NE.List e es)
1223 (ROutsideBlocked , ( [], _ )) -> error "seems like elm-stuff/ is corrupted"
1224 (ROutsideBlocked , (e:es, _ )) -> Left (NE.List e es)
1227addInside :: ModuleName.Raw -> Result -> [Module] -> [Module]
1228addInside name result modules =
1230 RNew _ iface objs _ -> Fresh name iface objs : modules
1231 RSame _ iface objs _ -> Fresh name iface objs : modules
1232 RCached main _ mvar -> Cached name main mvar : modules
1233 RNotFound _ -> error (badInside name)
1234 RProblem _ -> error (badInside name)
1235 RBlocked -> error (badInside name)
1236 RForeign _ -> modules
1240badInside :: ModuleName.Raw -> [Char]
1242 "Error from `" ++ Name.toChars name ++ "` should have been reported already."
1245addOutside :: RootResult -> [Module] -> [Module]
1246addOutside root modules =
1248 RInside _ -> modules
1249 ROutsideOk name iface objs -> Fresh name iface objs : modules
1250 ROutsideErr _ -> modules
1251 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