@@ -0,0 +1,379 @@
1+{-# LANGUAGE BangPatterns, OverloadedStrings #-}
26+import Control.Concurrent
27+import Control.Monad (when)
28+import qualified Data.ByteString.Builder as B
29+import qualified Data.NonEmptyList as NE
30+import qualified System.Exit as Exit
31+import qualified System.Info as Info
32+import System.IO (hFlush, hPutStr, stderr, stdout)
34+import qualified Elm.ModuleName as ModuleName
35+import qualified Elm.Package as Pkg
36+import qualified Elm.Version as V
37+import qualified Json.Encode as Encode
38+import Reporting.Doc ((<+>), (<>))
39+import qualified Reporting.Doc as D
40+import qualified Reporting.Exit as Exit
41+import qualified Reporting.Exit.Help as Help
60+ Terminal <$> newMVar ()
67+attempt :: Style -> IO (Either Help.Report a) -> IO a
72+ Left ex -> exit style ex
75+exit :: Style -> Help.Report -> IO a
79+ do B.hPutBuilder stderr (Encode.encodeUgly (Exit.toJson rep))
94+ D.green $ if isWindows then "+" else "●"
99+ D.red $ if isWindows then "X" else "✗"
102+_waitingMark :: D.Doc
104+ D.dullyellow $ if isWindows then "-" else "→"
109+ Info.os == "mingw32"
116+newtype Key msg = Key (msg -> IO ())
119+report :: Key msg -> msg -> IO ()
120+report (Key send) msg =
131+trackDetails :: Style -> (DKey -> IO a) -> IO a
132+trackDetails style callback =
135+ callback (Key (\_ -> return ()))
142+ detailsLoop chan (DState 0 0 0 0 0 0 0)
145+ answer <- callback (Key (writeChan chan . Just))
146+ writeChan chan Nothing
150+detailsLoop :: Chan (Maybe DMsg) -> DState -> IO ()
151+detailsLoop chan state@(DState total _ _ _ _ built _) =
152+ do msg <- readChan chan
155+ detailsLoop chan =<< detailsStep dmsg state
158+ putStrLn $ clear (toBuildProgress total total) $
160+ then "Dependencies ready!"
161+ else "Dependency problem!"
168+ , _requested :: !Int
180+ | DReceived Pkg.Name V.Version
181+ | DFailed Pkg.Name V.Version
186+detailsStep :: DMsg -> DState -> IO DState
187+detailsStep msg (DState total cached rqst rcvd failed built broken) =
189+ DStart numDependencies ->
190+ return (DState numDependencies 0 0 0 0 0 0)
193+ putTransition (DState total (cached + 1) rqst rcvd failed built broken)
196+ do when (rqst == 0) (putStrLn "Starting downloads...\n")
197+ return (DState total cached (rqst + 1) rcvd failed built broken)
199+ DReceived pkg vsn ->
200+ do putDownload goodMark pkg vsn
201+ putTransition (DState total cached rqst (rcvd + 1) failed built broken)
204+ do putDownload badMark pkg vsn
205+ putTransition (DState total cached rqst rcvd (failed + 1) built broken)
208+ putBuilt (DState total cached rqst rcvd failed (built + 1) broken)
211+ putBuilt (DState total cached rqst rcvd failed built (broken + 1))
214+putDownload :: D.Doc -> Pkg.Name -> V.Version -> IO ()
215+putDownload mark pkg vsn =
216+ Help.toStdout $ D.indent 2 $
218+ <+> D.fromUtf8 (Pkg.toString pkg)
219+ <+> D.fromUtf8 (V.toString vsn)
223+putTransition :: DState -> IO DState
224+putTransition state@(DState total cached _ rcvd failed built broken) =
225+ if cached + rcvd + failed < total then
229+ do let char = if rcvd + failed == 0 then '\r' else '\n'
230+ putStrFlush (char : toBuildProgress (built + broken + failed) total)
234+putBuilt :: DState -> IO DState
235+putBuilt state@(DState total cached _ rcvd failed built broken) =
236+ do when (total == cached + rcvd + failed) $
237+ putStrFlush $ '\r' : toBuildProgress (built + broken + failed) total
241+toBuildProgress :: Int -> Int -> [Char]
242+toBuildProgress built total =
243+ "Verifying dependencies (" ++ show built ++ "/" ++ show total ++ ")"
246+clear :: [Char] -> [Char] -> [Char]
248+ '\r' : replicate (length before) ' ' ++ '\r' : after
257+type BResult a = Either Exit.BuildProblem a
260+trackBuild :: Style -> (BKey -> IO (BResult a)) -> IO (BResult a)
261+trackBuild style callback =
264+ callback (Key (\_ -> return ()))
271+ putStrFlush "Compiling ..."
275+ result <- callback (Key (writeChan chan . Left))
276+ writeChan chan (Right result)
284+buildLoop :: Chan (Either BMsg (BResult a)) -> Int -> IO ()
285+buildLoop chan done =
286+ do msg <- readChan chan
289+ do let !done1 = done + 1
290+ putStrFlush $ "\rCompiling (" ++ show done1 ++ ")"
291+ buildLoop chan done1
295+ !message = toFinalMessage done result
296+ !width = 12 + length (show done)
299+ if length message < width
300+ then '\r' : replicate width ' ' ++ '\r' : message
304+toFinalMessage :: Int -> BResult a -> [Char]
305+toFinalMessage done result =
310+ 1 -> "Success! Compiled 1 module."
311+ n -> "Success! Compiled " ++ show n ++ " modules."
315+ Exit.BuildModuleProblems _ [] ->
316+ "Detected problems in 1 module."
318+ Exit.BuildModuleProblems _ (_:ps) ->
319+ "Detected problems in " ++ show (2 + length ps) ++ " modules."
321+ Exit.BuildProjectProblem _ ->
322+ "Detected a problem."
329+reportGenerate :: Style -> NE.List ModuleName.Raw -> FilePath -> IO ()
330+reportGenerate style names output =
337+ let cnames = fmap ModuleName.toChars names
338+ putStrLn ('\n' : toGenDiagram cnames output)
341+toGenDiagram :: NE.List [Char] -> FilePath -> [Char]
342+toGenDiagram (NE.List name names) output =
344+ width = 3 + foldr (max . length) (length name) names
348+ toGenLine width name ('>' : ' ' : output ++ "\n")
352+ toGenLine width name (vtop : hbar : hbar : '>' : ' ' : output)
353+ : reverse (zipWith (toGenLine width) (reverse names) ([vbottom] : repeat [vmiddle]))
356+toGenLine :: Int -> [Char] -> [Char] -> [Char]
357+toGenLine width name end =
358+ " " ++ name ++ ' ' : replicate (width - length name) hbar ++ end
362+hbar = if isWindows then '-' else '─'
365+vtop = if isWindows then '+' else '┬'
368+vmiddle = if isWindows then '+' else '┤'
371+vbottom = if isWindows then '+' else '┘'
377+putStrFlush :: String -> IO ()
379+ hPutStr stdout str >> hFlush stdout