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.Package as Pkg
45import qualified Json.Encode as E
46import qualified Parse.Module as Parse
47import qualified Reporting
48import qualified Reporting.Annotation as A
49import qualified Reporting.Error as Error
50import qualified Reporting.Error.Syntax as Syntax
51import qualified Reporting.Error.Import as Import
52import qualified Reporting.Exit as Exit
62 { _key :: Reporting.BKey
65 , _srcDirs :: [FilePath]
66 , _locals :: Map.Map ModuleName.Raw Details.Local
67 , _foreigns :: Map.Map ModuleName.Raw Details.Foreign
71makeEnv :: Reporting.BKey -> FilePath -> Details.Details -> Env
72makeEnv key root (Details.Details _ validOutline locals foreigns _) =
74 Details.ValidApp srcDirs ->
75 Env key root Pkg.dummyName (NE.toList srcDirs) locals foreigns
77 Details.ValidPkg pkg _ ->
78 Env key root pkg ["src"] locals foreigns
85fork :: IO a -> IO (MVar a)
87 do mvar <- newEmptyMVar
88 _ <- forkIO $ putMVar mvar =<< work
92{-# INLINE forkWithKey #-}
93forkWithKey :: (k -> a -> IO b) -> Map.Map k a -> IO (Map.Map k (MVar b))
94forkWithKey func dict =
95 Map.traverseWithKey (\k v -> fork (func k v)) dict
102fromExposed :: Reporting.Style -> FilePath -> Details.Details -> DocsGoal docs -> NE.List ModuleName.Raw -> IO (Either Exit.BuildProblem docs)
103fromExposed style root details docsGoal exposed@(NE.List e es) =
104 Reporting.trackBuild style $ \key ->
105 do let env = makeEnv key root details
106 dmvar <- Details.loadInterfaces root details
110 let docsNeed = toDocsNeed docsGoal
111 roots <- Map.fromKeysA (fork . crawlModule env mvar docsNeed) (e:es)
114 statuses <- traverse readMVar =<< readMVar mvar
117 midpoint <- checkExposedMidpoint dmvar statuses
120 return (Left (Exit.BuildProjectProblem problem))
123 do rmvar <- newEmptyMVar
124 resultMVars <- forkWithKey (checkModule env foreigns rmvar) statuses
125 putMVar rmvar resultMVars
126 results <- traverse readMVar resultMVars
127 writeDetails root details results
128 finalizeExposed docsGoal exposed results
138 , _deps :: Dependencies
139 , _mains :: NE.List Main
140 , _modules :: [Module]
145 = Fresh ModuleName.Raw I.Interface Opt.LocalGraph
146 | Cached ModuleName.Raw Bool (MVar CachedInterface)
150 Map.Map ModuleName.Canonical I.DependencyInterface
153fromMains :: Reporting.Style -> FilePath -> Details.Details -> NE.List FilePath -> IO (Either Exit.BuildProblem Artifacts)
154fromMains style root details paths =
155 Reporting.trackBuild style $ \key ->
156 do let env = makeEnv key root details
158 elmains <- findMains env paths
161 return (Left (Exit.BuildProjectProblem problem))
165 dmvar <- Details.loadInterfaces root details
166 smvar <- newMVar Map.empty
167 smainMVars <- traverse (fork . crawlMain env smvar) lmains
168 smains <- traverse readMVar smainMVars
169 statuses <- traverse readMVar =<< readMVar smvar
171 midpoint <- checkMainsMidpoint dmvar statuses smains
174 return (Left (Exit.BuildProjectProblem problem))
178 rmvar <- newEmptyMVar
179 resultsMVars <- forkWithKey (checkModule env foreigns rmvar) statuses
180 putMVar rmvar resultsMVars
181 rmainMVars <- traverse (fork . checkMain env resultsMVars) smains
182 results <- traverse readMVar resultsMVars
183 writeDetails root details results
184 toArtifacts env foreigns results <$> traverse readMVar rmainMVars
192 Map.Map ModuleName.Raw (MVar Status)
196 = SCached Details.Local
197 | SChanged Details.Local B.ByteString Src.Module DocsNeed
198 | SBadImport Import.Problem
199 | SBadSyntax FilePath File.Time B.ByteString Syntax.Error
204crawlDeps :: Env -> MVar StatusDict -> [ModuleName.Raw] -> a -> IO a
205crawlDeps env mvar deps blockedValue =
206 do statusDict <- takeMVar mvar
207 let depsDict = Map.fromKeys (\_ -> ()) deps
208 let newsDict = Map.difference depsDict statusDict
209 statuses <- Map.traverseWithKey crawlNew newsDict
210 putMVar mvar (Map.union statuses statusDict)
211 mapM_ readMVar statuses
214 crawlNew name () = fork (crawlModule env mvar (DocsNeed False) name)
217crawlModule :: Env -> MVar StatusDict -> DocsNeed -> ModuleName.Raw -> IO Status
218crawlModule env@(Env _ root pkg srcDirs locals foreigns) mvar docsNeed name =
219 do let fileName = ModuleName.toFilePath name <.> "elm"
220 let inRoot path = File.exists (root </> path)
222 paths <- filterM inRoot (map (</> fileName) srcDirs)
226 case Map.lookup name foreigns of
227 Just (Details.Foreign dep deps) ->
228 return $ SBadImport $ Import.Ambiguous path [] dep deps
231 case Map.lookup name locals of
233 crawlFile env mvar docsNeed name path
235 Just local@(Details.Local oldPath oldTime deps _) ->
237 then crawlFile env mvar docsNeed name path
239 do newTime <- File.getTime path
240 if oldTime < newTime || needsDocs docsNeed
241 then crawlFile env mvar docsNeed name path
242 else crawlDeps env mvar deps (SCached local)
245 return $ SBadImport $ Import.AmbiguousLocal p1 p2 ps
248 case Map.lookup name foreigns of
249 Just (Details.Foreign dep deps) ->
252 return $ SForeign dep
255 return $ SBadImport $ Import.AmbiguousForeign dep d ds
258 if Name.isKernel name && Pkg.isKernel pkg then
259 do exists <- File.exists ("src" </> ModuleName.toFilePath name <.> "js")
260 return $ if exists then SKernel else SBadImport Import.NotFound
262 return $ SBadImport Import.NotFound
265crawlFile :: Env -> MVar StatusDict -> DocsNeed -> ModuleName.Raw -> FilePath -> IO Status
266crawlFile env@(Env _ root pkg _ _ _) mvar docsNeed expectedName path =
267 do time <- File.getTime path
268 source <- File.readUtf8 (root </> path)
270 case Parse.fromByteString pkg source of
272 return $ SBadSyntax path time source err
274 Right modul@(Src.Module maybeActualName _ _ imports values _ _ _ _) ->
275 case maybeActualName of
277 return $ SBadSyntax path time source (Syntax.ModuleNameUnspecified expectedName)
279 Just name@(A.At _ actualName) ->
280 if expectedName == actualName then
282 deps = map Src.getImportName imports
283 local = Details.Local path time deps (any isMain values)
285 crawlDeps env mvar deps (SChanged local source modul docsNeed)
287 return $ SBadSyntax path time source (Syntax.ModuleNameMismatch expectedName name)
290isMain :: A.Located Src.Value -> Bool
291isMain (A.At _ (Src.Value (A.At _ name) _ _ _)) =
300 Map.Map ModuleName.Raw (MVar Result)
304 = RNew !Details.Local !I.Interface !Opt.LocalGraph !(Maybe Docs.Module)
305 | RSame !Details.Local !I.Interface !Opt.LocalGraph !(Maybe Docs.Module)
306 | RCached Bool (MVar CachedInterface)
307 | RNotFound Import.Problem
308 | RProblem Error.Module
310 | RForeign I.Interface
320checkModule :: Env -> Dependencies -> MVar ResultDict -> ModuleName.Raw -> Status -> IO Result
321checkModule env@(Env _ root pkg _ _ _) foreigns resultsMVar name status =
323 SCached local@(Details.Local path time deps hasMain) ->
324 do results <- readMVar resultsMVar
325 depsStatus <- checkDeps root results deps
328 do source <- File.readUtf8 path
329 case Parse.fromByteString pkg source of
330 Right modul -> compile env (DocsNeed False) local source ifaces modul
333 Error.Module name path time source (Error.BadSyntax err)
336 do mvar <- newMVar Unneeded
337 return (RCached hasMain mvar)
342 DepsNotFound problems ->
343 do source <- File.readUtf8 path
344 return $ RProblem $ Error.Module name path time source $
345 case Parse.fromByteString pkg source of
346 Right (Src.Module _ _ _ imports _ _ _ _ _) ->
347 Error.BadImports (toImportErrors env results imports problems)
352 SChanged local@(Details.Local path time deps _) source modul@(Src.Module _ _ _ imports _ _ _ _ _) docsNeed ->
353 do results <- readMVar resultsMVar
354 depsStatus <- checkDeps root results deps
357 compile env docsNeed local source ifaces modul
359 DepsSame same cached ->
360 do maybeLoaded <- checkCachedInterfaces root cached
366 do let ifaces = Map.union loaded (Map.fromList same)
367 compile env docsNeed local source ifaces modul
372 DepsNotFound problems ->
373 return $ RProblem $ Error.Module name path time source $
374 Error.BadImports (toImportErrors env results imports problems)
376 SBadImport importProblem ->
377 return (RNotFound importProblem)
379 SBadSyntax path time source err ->
380 return $ RProblem $ Error.Module name path time source $
384 case foreigns ! ModuleName.Canonical home name of
385 I.Public iface -> return (RForeign iface)
386 I.Private _ _ _ -> error "loading private interface in Build"
397 = DepsChange (Map.Map ModuleName.Raw I.Interface)
398 | DepsSame [Dep] [CDep]
400 | DepsNotFound (NE.List (ModuleName.Raw, Import.Problem))
403checkDeps :: FilePath -> ResultDict -> [ModuleName.Raw] -> IO DepsStatus
404checkDeps root results deps =
405 checkDepsHelp root results deps [] [] [] [] False
408type Dep = (ModuleName.Raw, I.Interface)
409type CDep = (ModuleName.Raw, MVar CachedInterface)
412checkDepsHelp :: FilePath -> ResultDict -> [ModuleName.Raw] -> [Dep] -> [Dep] -> [CDep] -> [(ModuleName.Raw,Import.Problem)] -> Bool -> IO DepsStatus
413checkDepsHelp root results deps new same cached importProblems isBlocked =
416 do result <- readMVar (results ! dep)
418 RNew _ iface _ _ -> checkDepsHelp root results otherDeps ((dep,iface) : new) same cached importProblems isBlocked
419 RSame _ iface _ _ -> checkDepsHelp root results otherDeps new ((dep,iface) : same) cached importProblems isBlocked
420 RCached _ mvar -> checkDepsHelp root results otherDeps new same ((dep,mvar) : cached) importProblems isBlocked
421 RNotFound prob -> checkDepsHelp root results otherDeps new same cached ((dep,prob) : importProblems) True
422 RProblem _ -> checkDepsHelp root results otherDeps new same cached importProblems True
423 RBlocked -> checkDepsHelp root results otherDeps new same cached importProblems True
424 RForeign iface -> checkDepsHelp root results otherDeps new ((dep,iface) : same) cached importProblems isBlocked
425 RKernel -> checkDepsHelp root results otherDeps new same cached importProblems isBlocked
428 case importProblems of
430 return $ DepsNotFound (NE.List p ps)
436 else if null new then
437 return $ DepsSame same cached
440 do maybeLoaded <- checkCachedInterfaces root cached
446 return $ DepsChange $
447 Map.union loaded (Map.union (Map.fromList new) (Map.fromList same))
454toImportErrors :: Env -> ResultDict -> [Src.Import] -> NE.List (ModuleName.Raw, Import.Problem) -> NE.List Import.Error
455toImportErrors (Env _ _ _ _ locals foreigns) results imports problems =
459 [ Map.keysSet foreigns
461 , Map.keysSet results
465 Set.difference knownModules (Set.fromList (map Src.getImportName imports))
468 Map.fromList (map (\(Src.Import (A.At region name) _ _) -> (name, region)) imports)
470 toError (name, problem) =
471 Import.Error (regionDict ! name) name unimportedModules problem
473 fmap toError problems
480checkCachedInterfaces :: FilePath -> [(ModuleName.Raw, MVar CachedInterface)] -> IO (Maybe (Map.Map ModuleName.Raw I.Interface))
481checkCachedInterfaces root deps =
482 do loading <- traverse (fork . checkCache root) deps
483 loaded <- traverse readMVar loading
484 return $ Map.fromList <$> sequence loaded
487checkCache :: FilePath -> (ModuleName.Raw, MVar CachedInterface) -> IO (Maybe Dep)
488checkCache root (name, ciMvar) =
489 do cachedInterface <- takeMVar ciMvar
490 case cachedInterface of
492 do putMVar ciMvar cachedInterface
496 do putMVar ciMvar cachedInterface
497 return (Just (name, iface))
500 do maybeIface <- File.readBinary (Stuff.elmi root name)
503 do putMVar ciMvar Corrupted
507 do putMVar ciMvar (Loaded iface)
508 return (Just (name, iface))
515checkExposedMidpoint :: MVar (Maybe Dependencies) -> Map.Map ModuleName.Raw Status -> IO (Either Exit.BuildProjectProblem Dependencies)
516checkExposedMidpoint dmvar statuses =
517 case checkForCycles statuses of
519 do maybeForeigns <- readMVar dmvar
520 case maybeForeigns of
521 Nothing -> return (Left Exit.BP_CannotLoadDependencies)
522 Just fs -> return (Right fs)
524 Just (NE.List name names) ->
525 do _ <- readMVar dmvar
526 return (Left (Exit.BP_Cycle name names))
529checkMainsMidpoint :: MVar (Maybe Dependencies) -> Map.Map ModuleName.Raw Status -> NE.List MainStatus -> IO (Either Exit.BuildProjectProblem Dependencies)
530checkMainsMidpoint dmvar statuses smains =
531 case checkForCycles statuses of
533 case checkUniqueMains statuses smains of
535 do maybeForeigns <- readMVar dmvar
536 case maybeForeigns of
537 Nothing -> return (Left Exit.BP_CannotLoadDependencies)
538 Just fs -> return (Right fs)
541 do _ <- readMVar dmvar
542 return (Left problem)
544 Just (NE.List name names) ->
545 do _ <- readMVar dmvar
546 return (Left (Exit.BP_Cycle name names))
553checkForCycles :: Map.Map ModuleName.Raw Status -> Maybe (NE.List ModuleName.Raw)
554checkForCycles modules =
556 !graph = Map.foldrWithKey addToGraph [] modules
557 !sccs = Graph.stronglyConnComp graph
559 checkForCyclesHelp sccs
562checkForCyclesHelp :: [Graph.SCC ModuleName.Raw] -> Maybe (NE.List ModuleName.Raw)
563checkForCyclesHelp sccs =
570 Graph.AcyclicSCC _ -> checkForCyclesHelp otherSccs
571 Graph.CyclicSCC [] -> checkForCyclesHelp otherSccs
572 Graph.CyclicSCC (m:ms) -> Just (NE.List m ms)
576 ( ModuleName.Raw, ModuleName.Raw, [ModuleName.Raw] )
579addToGraph :: ModuleName.Raw -> Status -> [Node] -> [Node]
580addToGraph name status graph =
584 SCached (Details.Local _ _ deps _) -> deps
585 SChanged (Details.Local _ _ deps _) _ _ _ -> deps
587 SBadSyntax _ _ _ _ -> []
591 (name, name, dependencies) : graph
598checkUniqueMains :: Map.Map ModuleName.Raw Status -> NE.List MainStatus -> Maybe Exit.BuildProjectProblem
599checkUniqueMains insides smains =
602 Map.fromListWith OneOrMore.more (Maybe.mapMaybe mainStatusToNamePathPair (NE.toList smains))
604 case Map.traverseWithKey checkOutside outsidesDict of
609 case sequence_ (Map.intersectionWithKey checkInside outsides insides) of
611 Left problem -> Just problem
614mainStatusToNamePathPair :: MainStatus -> Maybe (ModuleName.Raw, OneOrMore.OneOrMore FilePath)
615mainStatusToNamePathPair smain =
618 SOutsideOk (Details.Local path _ _ _) _ modul -> Just (Src.getName modul, OneOrMore.one path)
619 SOutsideErr _ -> Nothing
622checkOutside :: ModuleName.Raw -> OneOrMore.OneOrMore FilePath -> Either Exit.BuildProjectProblem FilePath
623checkOutside name paths =
624 case OneOrMore.destruct NE.List paths of
625 NE.List p [] -> Right p
626 NE.List p1 (p2:_) -> Left (Exit.BP_MainNameDuplicate name p1 p2)
629checkInside :: ModuleName.Raw -> FilePath -> Status -> Either Exit.BuildProjectProblem ()
630checkInside name p1 status =
632 SCached (Details.Local p2 _ _ _) -> Left (Exit.BP_MainNameDuplicate name p1 p2)
633 SChanged (Details.Local p2 _ _ _) _ _ _ -> Left (Exit.BP_MainNameDuplicate name p1 p2)
634 SBadImport _ -> Right ()
635 SBadSyntax _ _ _ _ -> Right ()
636 SForeign _ -> Right ()
644compile :: Env -> DocsNeed -> Details.Local -> B.ByteString -> Map.Map ModuleName.Raw I.Interface -> Src.Module -> IO Result
645compile (Env key root pkg _ _ _) docsNeed local@(Details.Local path time _ _) source ifaces modul =
646 case Compile.compile pkg ifaces modul of
647 Right (Compile.Artifacts canonical annotations objects) ->
648 do let name = Src.getName modul
649 let iface = I.fromModule pkg canonical annotations
650 let docs = makeDocs docsNeed canonical
651 File.writeBinary (Stuff.elmo root name) objects
652 maybeOldi <- File.readBinary (Stuff.elmi root name)
654 Just oldi | oldi == iface ->
655 do -- iface should be fully forced by equality check
656 Reporting.report key Reporting.BDone
657 return (RSame local iface objects docs)
660 do -- iface may be lazy still
661 -- TODO try adding forkIO here
662 File.writeBinary (Stuff.elmi root name) iface
663 Reporting.report key Reporting.BDone
664 return (RNew local iface objects docs)
667 do Reporting.report key Reporting.BDone
669 Error.Module (Src.getName modul) path time source err
676writeDetails :: FilePath -> Details.Details -> Map.Map ModuleName.Raw Result -> IO ()
677writeDetails root (Details.Details time outline locals foreigns extras) results =
678 File.writeBinary (Stuff.details root) $
679 Details.Details time outline (Map.foldrWithKey addNewLocal locals results) foreigns extras
682addNewLocal :: ModuleName.Raw -> Result -> Map.Map ModuleName.Raw Details.Local -> Map.Map ModuleName.Raw Details.Local
683addNewLocal name result locals =
685 RNew local _ _ _ -> Map.insert name local locals
686 RSame local _ _ _ -> Map.insert name local locals
687 RCached _ _ -> locals
688 RNotFound _ -> locals
699finalizeExposed :: DocsGoal docs -> NE.List ModuleName.Raw -> Map.Map ModuleName.Raw Result -> IO (Either Exit.BuildProblem docs)
700finalizeExposed docsGoal exposed results =
701 case foldr (addImportProblems results) [] (NE.toList exposed) of
703 return $ Left $ Exit.BuildProjectProblem (Exit.BP_MissingExposed (NE.List p ps))
706 case Map.foldr addErrors [] results of
707 [] -> Right <$> finalizeDocs docsGoal results
708 e:es -> return $ Left $ Exit.BuildModuleProblems e es
711addErrors :: Result -> [Error.Module] -> [Error.Module]
712addErrors result errors =
714 RNew _ _ _ _ -> errors
715 RSame _ _ _ _ -> errors
716 RCached _ _ -> errors
717 RNotFound _ -> errors
718 RProblem e -> e:errors
724addImportProblems :: Map.Map ModuleName.Raw Result -> ModuleName.Raw -> [(ModuleName.Raw, Import.Problem)] -> [(ModuleName.Raw, Import.Problem)]
725addImportProblems results name problems =
726 case results ! name of
727 RNew _ _ _ _ -> problems
728 RSame _ _ _ _ -> problems
729 RCached _ _ -> problems
730 RNotFound p -> (name, p) : problems
731 RProblem _ -> problems
733 RForeign _ -> problems
742 KeepDocs :: DocsGoal Docs.Documentation
743 WriteDocs :: FilePath -> DocsGoal ()
744 IgnoreDocs :: DocsGoal ()
748 DocsNeed { needsDocs :: Bool }
751toDocsNeed :: DocsGoal a -> DocsNeed
754 IgnoreDocs -> DocsNeed False
755 WriteDocs _ -> DocsNeed True
756 KeepDocs -> DocsNeed True
759makeDocs :: DocsNeed -> Can.Module -> Maybe Docs.Module
760makeDocs (DocsNeed isNeeded) modul =
762 case Docs.fromModule modul of
763 Right docs -> Just docs
769finalizeDocs :: DocsGoal docs -> Map.Map ModuleName.Raw Result -> IO docs
770finalizeDocs goal results =
773 return $ Map.mapMaybe toDocs results
776 E.writeUgly path $ Docs.encode $ Map.mapMaybe toDocs results
782toDocs :: Result -> Maybe Docs.Module
787 RCached _ _ -> Nothing
788 RNotFound _ -> Nothing
789 RProblem _ -> Nothing
791 RForeign _ -> Nothing
796--------------------------------------------------------------------------------
797--------------------------------------------------------------------------------
798------ AFTER THIS, EVERYTHING IS ABOUT HANDLING MODULES GIVEN BY FILEPATH ------
799--------------------------------------------------------------------------------
800--------------------------------------------------------------------------------
808 = LInside ModuleName.Raw
812findMains :: Env -> NE.List FilePath -> IO (Either Exit.BuildProjectProblem (NE.List MainLocation))
814 do mvars <- traverse (fork . findLocation env) paths
815 elocs <- traverse readMVar mvars
816 return $ checkLocations =<< sequence elocs
819checkLocations :: NE.List Location -> Either Exit.BuildProjectProblem (NE.List MainLocation)
820checkLocations locations =
822 toOneOrMore loc@(Location absolute _ _) =
823 (absolute, OneOrMore.one loc)
825 fromOneOrMore loc locs =
828 loc2:_ -> Left (Exit.BP_MainPathDuplicate (_relative loc) (_relative loc2))
830 fmap (\_ -> fmap _location locations) $
831 traverse (OneOrMore.destruct fromOneOrMore) $
832 Map.fromListWith OneOrMore.more $ map toOneOrMore (NE.toList locations)
841 { _absolute :: FilePath
842 , _relative :: FilePath
843 , _location :: MainLocation
847findLocation :: Env -> FilePath -> IO (Either Exit.BuildProjectProblem Location)
848findLocation env path =
849 do exists <- File.exists path
851 then isInsideSrcDirs env path <$> Dir.canonicalizePath path
852 else return (Left (Exit.BP_PathUnknown path))
855isInsideSrcDirs :: Env -> FilePath -> FilePath -> Either Exit.BuildProjectProblem Location
856isInsideSrcDirs (Env _ root _ srcDirs _ _) path absolutePath =
858 (dirs, file) = FP.splitFileName absolutePath
859 (final, ext) = break (=='.') file
862 then Left (Exit.BP_WithBadExtension path)
865 roots = FP.splitDirectories root
866 segments = FP.splitDirectories dirs ++ [final]
868 case dropPrefix roots segments of
870 Right (Location absolutePath path (LOutside path))
872 Just relativeSegments ->
875 Either.partitionEithers (map (isInsideSrcDirsHelp relativeSegments) srcDirs)
877 -- TODO make sure this is all correct
878 case (exits, Maybe.catMaybes maybes) of
879 (_, [(_,name)]) -> Right (Location absolutePath path (LInside name))
880 ([], []) -> Right (Location absolutePath path (LOutside path))
881 (_, (s1,_):(s2,_):_) -> Left (Exit.BP_WithAmbiguousSrcDir s1 s2)
882 (exit:_, _) -> Left exit
885isInsideSrcDirsHelp :: [String] -> FilePath -> Either Exit.BuildProjectProblem (Maybe (FilePath, ModuleName.Raw))
886isInsideSrcDirsHelp segments srcDir =
887 case dropPrefix (FP.splitDirectories srcDir) segments of
892 if all isGoodName names
893 then Right (Just (srcDir, Name.fromChars (List.intercalate "." names)))
894 else Left (error "Exit.MakeWithInvalidModuleName" srcDir segments)
897isGoodName :: [Char] -> Bool
904 Char.isUpper char && all (\c -> Char.isAlphaNum c || c == '_') chars
907dropPrefix :: [FilePath] -> [FilePath] -> Maybe [FilePath]
908dropPrefix roots paths =
916 p:ps -> if r == p then dropPrefix rs ps else Nothing
924 = SInside ModuleName.Raw
925 | SOutsideOk Details.Local B.ByteString Src.Module
926 | SOutsideErr Error.Module
929crawlMain :: Env -> MVar StatusDict -> MainLocation -> IO MainStatus
930crawlMain env@(Env _ _ pkg _ _ _) mvar given =
933 do statusMVar <- newEmptyMVar
934 statusDict <- takeMVar mvar
935 putMVar mvar (Map.insert name statusMVar statusDict)
936 putMVar statusMVar =<< crawlModule env mvar (DocsNeed False) name
937 return (SInside name)
940 do time <- File.getTime path
941 source <- File.readUtf8 path
942 case Parse.fromByteString pkg source of
943 Right modul@(Src.Module _ _ _ imports values _ _ _ _) ->
944 do let deps = map Src.getImportName imports
945 let local = Details.Local path time deps (any isMain values)
946 crawlDeps env mvar deps (SOutsideOk local source modul)
949 return $ SOutsideErr $
950 Error.Module "???" path time source (Error.BadSyntax syntaxError)
958 = RInside ModuleName.Raw
959 | ROutsideOk ModuleName.Raw I.Interface Opt.LocalGraph
960 | ROutsideErr Error.Module
964checkMain :: Env -> ResultDict -> MainStatus -> IO MainResult
965checkMain env@(Env _ root _ _ _ _) results pendingMain =
968 return (RInside name)
971 return (ROutsideErr err)
973 SOutsideOk local@(Details.Local path time deps _) source modul@(Src.Module _ _ _ imports _ _ _ _ _) ->
974 do depsStatus <- checkDeps root results deps
977 return $ compileOutside env local source ifaces modul
979 DepsSame same cached ->
980 do maybeLoaded <- checkCachedInterfaces root cached
983 return ROutsideBlocked
986 do let ifaces = Map.union loaded (Map.fromList same)
987 return $ compileOutside env local source ifaces modul
990 return ROutsideBlocked
992 DepsNotFound problems ->
993 return $ ROutsideErr $ Error.Module (Src.getName modul) path time source $
994 Error.BadImports (toImportErrors env results imports problems)
997compileOutside :: Env -> Details.Local -> B.ByteString -> Map.Map ModuleName.Raw I.Interface -> Src.Module -> MainResult
998compileOutside (Env _ _ pkg _ _ _) (Details.Local path time _ _) source ifaces modul =
1000 name = Src.getName modul
1002 case Compile.compile pkg ifaces modul of
1003 Right (Compile.Artifacts canonical annotations objects) ->
1004 ROutsideOk name (I.fromModule pkg canonical annotations) objects
1008 Error.Module name path time source errors
1016 = Inside ModuleName.Raw
1017 | Outside ModuleName.Raw I.Interface Opt.LocalGraph
1020toArtifacts :: Env -> Dependencies -> Map.Map ModuleName.Raw Result -> NE.List MainResult -> Either Exit.BuildProblem Artifacts
1021toArtifacts (Env _ _ pkg _ _ _) foreigns results mainResults =
1022 case gatherProblemsOrMains results mainResults of
1023 Left (NE.List e es) ->
1024 Left (Exit.BuildModuleProblems e es)
1027 Right $ Artifacts pkg foreigns mains $
1028 Map.foldrWithKey addInside (foldr addOutside [] mainResults) results
1031gatherProblemsOrMains :: Map.Map ModuleName.Raw Result -> NE.List MainResult -> Either (NE.List Error.Module) (NE.List Main)
1032gatherProblemsOrMains results (NE.List mainResult mainResults) =
1034 sortMain result (es, mains) =
1036 RInside n -> ( es, Inside n : mains)
1037 ROutsideOk n i o -> ( es, Outside n i o : mains)
1038 ROutsideErr e -> (e:es, mains)
1039 ROutsideBlocked -> ( es, mains)
1041 errors = Map.foldr addErrors [] results
1043 case (mainResult, foldr sortMain (errors, []) mainResults) of
1044 (RInside n , ( [], ms)) -> Right (NE.List (Inside n) ms)
1045 (RInside _ , (e:es, _ )) -> Left (NE.List e es)
1046 (ROutsideOk n i o, ( [], ms)) -> Right (NE.List (Outside n i o) ms)
1047 (ROutsideOk _ _ _, (e:es, _ )) -> Left (NE.List e es)
1048 (ROutsideErr e , ( es, _ )) -> Left (NE.List e es)
1049 (ROutsideBlocked , ( [], _ )) -> error "seems like elm-stuff/ is corrupted"
1050 (ROutsideBlocked , (e:es, _ )) -> Left (NE.List e es)
1053addInside :: ModuleName.Raw -> Result -> [Module] -> [Module]
1054addInside name result modules =
1056 RNew _ iface objs _ -> Fresh name iface objs : modules
1057 RSame _ iface objs _ -> Fresh name iface objs : modules
1058 RCached main mvar -> Cached name main mvar : modules
1059 RNotFound _ -> error (badInside name)
1060 RProblem _ -> error (badInside name)
1061 RBlocked -> error (badInside name)
1062 RForeign _ -> modules
1066badInside :: ModuleName.Raw -> [Char]
1068 "Error from `" ++ Name.toChars name ++ "` should have been reported already."
1071addOutside :: MainResult -> [Module] -> [Module]
1072addOutside main modules =
1074 RInside _ -> modules
1075 ROutsideOk name iface objs -> Fresh name iface objs : modules
1076 ROutsideErr _ -> modules
1077 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