packages feed

shake 0.18.5 → 0.19

raw patch · 103 files changed

+936/−870 lines, 103 filesdep ~basedep ~extra

Dependency ranges changed: base, extra

Files

CHANGES.txt view
@@ -1,5 +1,19 @@ Changelog for Shake (* = breaking change) +0.19, released 2020-05-23+    #738, improve the help text+    #679, allow Ninja to depend on a directory+*   #748, close stdin by default in cmd+    #748, add NoProcessGroup and InheritStdin to cmd+    Delete stuff deprecated since 2014 - **>, ?>>, *>>, *>, |*>, &*>+    Mark askOracleWith and deprioritize as DEPRECATED+    #753, fix timing information for batch+    #746, optimise file modification times on Linux+    #746, add an instance for CmdArgument ()+    Allow getting FSATrace ByteString as a result+*   Make the FSATrace type polymorphic over the FilePath+    Speed up FSATrace parsing+    Require extra-1.6.19 0.18.5, released 2020-02-02     Use uninterruptibleMask_ to ensure all cleanup happens robustly     #742, make the Chrome profile only include the last run
shake.cabal view
@@ -1,7 +1,7 @@ cabal-version:      >= 1.18 build-type:         Simple name:               shake-version:            0.18.5+version:            0.19 license:            BSD3 license-file:       LICENSE category:           Development, Shake@@ -30,7 +30,7 @@     (e.g. compiler version). homepage:           https://shakebuild.com bug-reports:        https://github.com/ndmitchell/shake/issues-tested-with:        GHC==8.8.1, GHC==8.6.5, GHC==8.4.4, GHC==8.2.2, GHC==8.0.2, GHC==7.10.3+tested-with:        GHC==8.10.1, GHC==8.8.3, GHC==8.6.5, GHC==8.4.4, GHC==8.2.2, GHC==8.0.2 extra-doc-files:     CHANGES.txt     README.md@@ -90,7 +90,7 @@         bytestring,         deepseq >= 1.1,         directory >= 1.2.7.0,-        extra >= 1.6.14,+        extra >= 1.6.19,         filepath,         filepattern,         hashable >= 1.1.2.3,@@ -216,7 +216,7 @@         bytestring,         deepseq >= 1.1,         directory,-        extra >= 1.6.14,+        extra >= 1.6.19,         filepath,         filepattern,         file-embed >= 0.0.11,@@ -337,7 +337,7 @@         bytestring,         deepseq >= 1.1,         directory,-        extra >= 1.6.14,+        extra >= 1.6.19,         filepath,         filepattern,         hashable >= 1.1.2.3,
src/Development/Ninja/All.hs view
@@ -38,9 +38,9 @@ runNinja _ file args (Just "compdb") = do     dir <- getCurrentDirectory     Ninja{..} <- parse file =<< newEnv-    rules <- return $ Map.fromList [r | r <- rules, BS.unpack (fst r) `elem` args]+    rules<- pure $ Map.fromList [r | r <- rules, BS.unpack (fst r) `elem` args]     -- the build items are generated in reverse order, hence the reverse-    let xs = [(a,b,file,rule) | (a,b@Build{..}) <- reverse $ multiples ++ map (first return) singles+    let xs = [(a,b,file,rule) | (a,b@Build{..}) <- reverse $ multiples ++ map (first pure) singles                               , Just rule <- [Map.lookup ruleName rules], file:_ <- [depsNormal]]     xs <- forM xs $ \(out,Build{..},file,Rule{..}) -> do         -- the order of adding new environment variables matters@@ -51,29 +51,29 @@         forM_ buildBind $ \(a,b) -> addEnv env a b         addBinds env ruleBind         commandline <- fmap BS.unpack $ askVar env $ BS.pack "command"-        return $ CompDb dir commandline $ BS.unpack file+        pure $ CompDb dir commandline $ BS.unpack file     putStr $ printCompDb xs-    return Nothing+    pure Nothing  runNinja _ _ _ (Just x) = errorIO $ "Unknown tool argument, expected 'compdb', got " ++ x  runNinja restart file args Nothing = do     addTiming "Ninja parse"     ninja@Ninja{..} <- parse file =<< newEnv-    return $ Just $ do-        phonys <- return $ Map.fromList phonys-        needDeps <- return $ needDeps ninja phonys -- partial application-        singles <- return $ Map.fromList $ map (first filepathNormalise) singles-        multiples <- return $ Map.fromList [(x,(xs,b)) | (xs,b) <- map (first $ map filepathNormalise) multiples, x <- xs]-        rules <- return $ Map.fromList rules+    pure $ Just $ do+        phonys<- pure $ Map.fromList phonys+        needDeps<- pure $ needDeps ninja phonys -- partial application+        singles<- pure $ Map.fromList $ map (first filepathNormalise) singles+        multiples<- pure $ Map.fromList [(x,(xs,b)) | (xs,b) <- map (first $ map filepathNormalise) multiples, x <- xs]+        rules<- pure $ Map.fromList rules         pools <- fmap Map.fromList $ forM ((BS.pack "console",1):pools) $ \(name,depth) ->             (name,) <$> newResource (BS.unpack name) depth          action $ do             -- build the .ninja files, if they change, restart the build-            before <- liftIO $ mapM (getFileInfo . fileNameFromString) sources+            before <- liftIO $ mapM (getFileInfo False . fileNameFromString) sources             need sources-            after <- liftIO $ mapM (getFileInfo . fileNameFromString) sources+            after <- liftIO $ mapM (getFileInfo False . fileNameFromString) sources             if before /= after then                 runAfter restart              else@@ -156,13 +156,13 @@         neededBS xs         -- now try and statically validate needed will never fail         -- first find which dependencies are generated files-        xs <- return $ filter (`Map.member` builds) xs+        xs<- pure $ filter (`Map.member` builds) xs         -- now try and find them as dependencies         -- performance note: allDependencies generates lazily, and difference consumes lazily,         -- with the property that in the common case it won't generate much of the list at all         let bad = xs `difference` allDependencies build         case bad of-            [] -> return ()+            [] -> pure ()             xs -> throwM $ errorStructured                 ("Lint checking error - " ++                     (if length xs == 1 then "file in deps is" else "files in deps are") ++@@ -252,7 +252,7 @@         -- Using the "cmd" program adds overhead (I measure 7ms), and a limit of 8191 characters,         -- but is the most robust, requiring no additional escaping.         ([Shell], s, [])-    | (cmd,s) <- word1 s, map toUpper cmd `elem` ["CMD","CMD.EXE"], ("/c",s) <- word1 s =+    | (cmd,s) <- word1 s, upper cmd `elem` ["CMD","CMD.EXE"], ("/c",s) <- word1 s =         -- Given "cmd.exe /c <something>" we translate to Shell, which adds cmd.exe         -- (looked up on the current path) and /c to the front. CMake uses this rule a lot.         -- Adding quotes around pieces are /c goes very wrong.@@ -260,7 +260,7 @@     | otherwise =         -- It's a long command line which doesn't call "cmd /c". We reverse the escaping         -- Haskell applies, but each argument will still gain quotes around it.-        let xs = splitArgs s in ([], head $ xs ++ [""], drop 1 xs)+        let xs = splitArgs s in ([], headDef "" xs, drop1 xs)   data State
src/Development/Ninja/Env.hs view
@@ -16,11 +16,11 @@   newEnv :: IO (Env k v)-newEnv = do ref <- newIORef Map.empty; return $ Env ref Nothing+newEnv = do ref <- newIORef Map.empty; pure $ Env ref Nothing   scopeEnv :: Env k v -> IO (Env k v)-scopeEnv e = do ref <- newIORef Map.empty; return $ Env ref $ Just e+scopeEnv e = do ref <- newIORef Map.empty; pure $ Env ref $ Just e   addEnv :: (Eq k, Hashable k) => Env k v -> k -> v -> IO ()@@ -31,9 +31,9 @@ askEnv (Env ref e) k = do     mp <- readIORef ref     case Map.lookup k mp of-        Just v -> return $ Just v+        Just v -> pure $ Just v         Nothing | Just e <- e -> askEnv e k-        _ -> return Nothing+        _ -> pure Nothing  fromEnv :: Env k v -> IO (Map.HashMap k v) fromEnv (Env ref _) = readIORef ref
src/Development/Ninja/Lexer.hs view
@@ -45,7 +45,7 @@         i = unsafePerformIO $ BS.unsafeUseAsCString bs $ \ptr -> do             let start = castPtr ptr :: S             let end = go start-            return $! Ptr end `minusPtr` start+            pure $! Ptr end `minusPtr` start          go s@(Ptr a) | c == '\0' || f c = a                      | otherwise = go (next s)@@ -59,7 +59,7 @@         i = unsafePerformIO $ BS.unsafeUseAsCString bs $ \ptr -> do             let start = castPtr ptr :: S             let end = go start-            return $! Ptr end `minusPtr` start+            pure $! Ptr end `minusPtr` start          go s@(Ptr a) | f c = a                      | otherwise = go (next s)
src/Development/Ninja/Parse.hs view
@@ -35,18 +35,18 @@         binds <- mapM (\(a,b) -> (a,) <$> askExpr env b) binds         let (normal,implicit,orderOnly) = splitDeps deps         let build = Build rule env normal implicit orderOnly binds-        return $+        pure $             if rule == BS.pack "phony" then ninja{phonys = [(x, normal ++ implicit ++ orderOnly) | x <- outputs] ++ phonys}             else if length outputs == 1 then ninja{singles = (head outputs, build) : singles}             else ninja{multiples = (outputs, build) : multiples}     LexRule name ->-        return ninja{rules = (name, Rule binds) : rules}+        pure ninja{rules = (name, Rule binds) : rules}     LexDefault xs -> do         xs <- mapM (askExpr env) xs-        return ninja{defaults = xs ++ defaults}+        pure ninja{defaults = xs ++ defaults}     LexPool name -> do         depth <- getDepth env binds-        return ninja{pools = (name, depth) : pools}+        pure ninja{pools = (name, depth) : pools}     LexInclude expr -> do         file <- askExpr env expr         parseFile (BS.unpack file) env ninja@@ -56,7 +56,7 @@         parseFile (BS.unpack file) e ninja     LexDefine a b -> do         addBind env a b-        return ninja+        pure ninja     LexBind a _ ->         error $ "Unexpected binding defining " ++ BS.unpack a @@ -71,9 +71,9 @@  getDepth :: Env Str Str -> [(Str, Expr)] -> IO Int getDepth env xs = case lookup (BS.pack "depth") xs of-    Nothing -> return 1+    Nothing -> pure 1     Just x -> do         x <- askExpr env x         case BS.readInt x of-            Just (i, n) | BS.null n -> return i+            Just (i, n) | BS.null n -> pure i             _ -> error $ "Could not parse depth field in pool, got: " ++ BS.unpack x
src/Development/Ninja/Type.hs view
@@ -25,7 +25,7 @@ askExpr :: Env Str Str -> Expr -> IO Str askExpr e = f     where f (Exprs xs) = BS.concat <$> mapM f xs-          f (Lit x) = return x+          f (Lit x) = pure x           f (Var x) = askVar e x  askVar :: Env Str Str -> Str -> IO Str
src/Development/Shake.hs view
@@ -110,16 +110,12 @@     batch,     reschedule,     -- * Deprecated-    (*>), (|*>), (&*>),-    (**>), (*>>), (?>>),     askOracleWith,     deprioritize,     pattern Quiet, pattern Normal, pattern Loud, pattern Chatty,     putLoud, putNormal, putQuiet     ) where -import Prelude(Maybe, FilePath, Double, String) -- Since GHC 7.10 duplicates *>- -- I would love to use module export in the above export list, but alas Haddock -- then shows all the things that are hidden in the docs, which is terrible. import Control.Monad.IO.Class@@ -221,53 +217,11 @@   ------------------------------------------------------------------------ DEPRECATED SINCE 0.13, MAY 2014--infix 1 **>, ?>>, *>>---{-# DEPRECATED (**>) "Use |%> instead" #-}--- | /Deprecated:/ Alias for '|%>'.-(**>) :: [FilePattern] -> (FilePath -> Action ()) -> Rules ()-(**>) = (|%>)--{-# DEPRECATED (?>>) "Use &?> instead" #-}--- | /Deprecated:/ Alias for '&?>'.-(?>>) :: (FilePath -> Maybe [FilePath]) -> ([FilePath] -> Action ()) -> Rules ()-(?>>) = (&?>)--{-# DEPRECATED (*>>) "Use &%> instead" #-}--- | /Deprecated:/ Alias for '&%>'.-(*>>) :: [FilePattern] -> ([FilePath] -> Action ()) -> Rules ()-(*>>) = (&%>)--------------------------------------------------------------------------- DEPRECATED SINCE 0.14, MAY 2014--infix 1 *>, |*>, &*>--{-# DEPRECATED (*>) "Use %> instead" #-}--- | /Deprecated:/ Alias for '%>'. Note that @*>@ clashes with a Prelude operator in GHC 7.10.-(*>) :: FilePattern -> (FilePath -> Action ()) -> Rules ()-(*>) = (%>)--{-# DEPRECATED (|*>) "Use |%> instead" #-}--- | /Deprecated:/ Alias for '|%>'.-(|*>) :: [FilePattern] -> (FilePath -> Action ()) -> Rules ()-(|*>) = (|%>)--{-# DEPRECATED (&*>) "Use &%> instead" #-}--- | /Deprecated:/ Alias for '&%>'.-(&*>) :: [FilePattern] -> ([FilePath] -> Action ()) -> Rules ()-(&*>) = (&%>)------------------------------------------------------------------------ -- DEPRECATED SINCE 0.16.1, NOV 2017  -- | /Deprecated:/ Replace @'askOracleWith' q a@ by @'askOracle' q@ --   since the 'RuleResult' type family now fixes the result type.+{-# DEPRECATED askOracleWith "Use 'askOracle q' instead of 'askOracleWith q a', the result value is now unnecessary" #-} askOracleWith :: (RuleResult q ~ a, ShakeValue q, ShakeValue a) => q -> a -> Action a askOracleWith question _ = askOracle question @@ -275,6 +229,7 @@ -- DEPRECATED SINCE 0.18.4, JUL 2019  -- | /Deprecated:/ Alias for 'reschedule'.+{-# DEPRECATED deprioritize "Use 'reschedule' instead" #-} deprioritize :: Double -> Action () deprioritize = reschedule 
src/Development/Shake/Command.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE FlexibleInstances, TypeOperators, ScopedTypeVariables, NamedFieldPuns #-} {-# LANGUAGE GADTs, GeneralizedNewtypeDeriving, DeriveDataTypeable, RecordWildCards #-} @@ -39,6 +41,7 @@ import System.IO.Unsafe(unsafeInterleaveIO) import qualified Data.ByteString.Char8 as BS import qualified Data.ByteString.Lazy.Char8 as LBS+import qualified Data.ByteString.UTF8 as UTF8 import General.Extra import General.Process import Prelude@@ -69,7 +72,7 @@ addPath pre post = do     args <- liftIO getEnvironment     let (path,other) = partition ((== "PATH") . (if isWindows then upper else id) . fst) args-    return $ Env $+    pure $ Env $         [("PATH",intercalate [searchPathSeparator] $ pre ++ post) | null path] ++         [(a,intercalate [searchPathSeparator] $ pre ++ [b | b /= ""] ++ post) | (a,b) <- path] ++         other@@ -88,7 +91,7 @@ addEnv :: MonadIO m => [(String, String)] -> m CmdOption addEnv extra = do     args <- liftIO getEnvironment-    return $ Env $ extra ++ filter (\(a,_) -> a `notElem` map fst extra) args+    pure $ Env $ extra ++ filter (\(a,_) -> a `notElem` map fst extra) args   data Str = Str String | BS BS.ByteString | LBS LBS.ByteString | Unit deriving (Eq,Show)@@ -112,7 +115,8 @@     | ResultTime Double     | ResultLine String     | ResultProcess PID-    | ResultFSATrace [FSATrace]+    | ResultFSATrace [FSATrace FilePath]+    | ResultFSATraceBS [FSATrace BS.ByteString]       deriving (Eq,Show)  data PID = PID0 | PID ProcessHandle@@ -127,9 +131,15 @@     ,args :: [String]     } deriving Show -class MonadIO m => MonadTempDir m where runWithTempDir :: (FilePath -> m a) -> m a-instance MonadTempDir IO where runWithTempDir = IO.withTempDir-instance MonadTempDir Action where runWithTempDir = withTempDir+class MonadIO m => MonadTempDir m where+    runWithTempDir :: (FilePath -> m a) -> m a+    runWithTempFile :: (FilePath -> m a) -> m a+instance MonadTempDir IO where+    runWithTempDir = IO.withTempDir+    runWithTempFile = IO.withTempFile+instance MonadTempDir Action where+    runWithTempDir = withTempDir+    runWithTempFile = withTempFile  --------------------------------------------------------------------- -- DEAL WITH Shell@@ -143,9 +153,9 @@     | Shell `elem` opts = do         -- put our UserCommand first, as the last one wins, and ours is lowest priority         let userCmdline = unwords $ prog : args-        params <- return params{opts = UserCommand userCmdline : filter (/= Shell) opts}+        params <- pure params{opts = UserCommand userCmdline : filter (/= Shell) opts} -        prog <- liftIO $ if isFSATrace params then copyFSABinary prog else return prog+        prog <- liftIO $ if isFSATrace params then copyFSABinary prog else pure prog         let realCmdline = unwords $ prog : args         if not isWindows then             call params{prog = "/bin/sh", args = ["-c",realCmdline]}@@ -162,12 +172,12 @@ -- DEAL WITH FSATrace  isFSATrace :: Params -> Bool-isFSATrace Params{..} = ResultFSATrace [] `elem` results || any isFSAOptions opts+isFSATrace Params{..} = any isResultFSATrace  results || any isFSAOptions opts  -- Mac disables tracing on system binaries, so we copy them over, yurk copyFSABinary :: FilePath -> IO FilePath copyFSABinary prog-    | not isMac = return prog+    | not isMac = pure prog     | otherwise = do         progFull <- findExecutable prog         case progFull of@@ -179,8 +189,8 @@                 unlessM (doesFileExist fake) $ do                     createDirectoryRecursive $ takeDirectory fake                     copyFile x fake-                return fake-            _ -> return prog+                pure fake+            _ -> pure prog  removeOptionFSATrace     :: MonadTempDir m@@ -192,26 +202,31 @@     | ResultProcess PID0 `elem` results =         -- This is a bad state to get into, you could technically just ignore the tracing, but that's a bit dangerous         liftIO $ errorIO "Asyncronous process execution combined with FSATrace is not support"-    | otherwise = runWithTempDir $ \dir -> do-        let file = dir </> "fsatrace.txt"+    | otherwise = runWithTempFile $ \file -> do         liftIO $ writeFile file "" -- ensures even if we fail before fsatrace opens the file, we can still read it         params <- liftIO $ fsaParams file params         res <- call params{opts = UserCommand (showCommandForUser2 prog args) : filter (not . isFSAOptions) opts}-        cwd <- liftIO getCurrentDirectory-        fsaRes <- liftIO $ parseFSA <$> readFileUTF8' file-        return $ replace [ResultFSATrace []] [ResultFSATrace fsaRes] res+        fsaResBS <- liftIO $ parseFSA <$> BS.readFile file+        let fsaRes = map (fmap UTF8.toString) fsaResBS+        pure $ flip map res $ \case+            ResultFSATrace [] -> ResultFSATrace fsaRes+            ResultFSATraceBS [] -> ResultFSATraceBS fsaResBS+            x -> x     where-        fsaFlags = fromMaybe "rwmdqt" fsaOptions-        fsaOptions = last $ Nothing : [Just x | FSAOptions x <- opts]+        fsaFlags = lastDef "rwmdqt" [x | FSAOptions x <- opts]          fsaParams file Params{..} = do             prog <- copyFSABinary prog-            return params{prog = "fsatrace", args = fsaFlags : file : "--" : prog : args }+            pure params{prog = "fsatrace", args = fsaFlags : file : "--" : prog : args }   isFSAOptions FSAOptions{} = True isFSAOptions _ = False +isResultFSATrace ResultFSATrace{} = True+isResultFSATrace ResultFSATraceBS{} = True+isResultFSATrace _ = False+ addFSAOptions :: String -> [CmdOption] -> [CmdOption] addFSAOptions x opts | any isFSAOptions opts = map f opts     where f (FSAOptions y) = FSAOptions $ nubOrd $ y ++ x@@ -222,34 +237,46 @@ -- | The results produced by @fsatrace@. All files will be absolute paths. --   You can get the results for a 'cmd' by requesting a value of type --   @['FSATrace']@.-data FSATrace+data FSATrace a     = -- | Writing to a file-      FSAWrite FilePath+      FSAWrite a     | -- | Reading from a file-      FSARead FilePath+      FSARead a     | -- | Deleting a file-      FSADelete FilePath+      FSADelete a     | -- | Moving, arguments destination, then source-      FSAMove FilePath FilePath+      FSAMove a a     | -- | Querying\/stat on a file-      FSAQuery FilePath+      FSAQuery a     | -- | Touching a file-      FSATouch FilePath-      deriving (Show,Eq,Ord,Data,Typeable)+      FSATouch a+      deriving (Show,Eq,Ord,Data,Typeable,Functor)   -- | Parse the 'FSATrace' entries, ignoring anything you don't understand.-parseFSA :: String -> [FSATrace]-parseFSA = mapMaybe f . lines-    where f ('w':'|':xs) = Just $ FSAWrite xs-          f ('r':'|':xs) = Just $ FSARead xs-          f ('d':'|':xs) = Just $ FSADelete xs-          f ('m':'|':xs) | (xs,'|':ys) <- break (== '|') xs = Just $ FSAMove xs ys-          f ('q':'|':xs) = Just $ FSAQuery xs-          f ('t':'|':xs) = Just $ FSATouch xs-          f _ = Nothing+parseFSA :: BS.ByteString -> [FSATrace BS.ByteString]+parseFSA = mapMaybe (f . dropR) . BS.lines+    where+        -- deal with CRLF on Windows+        dropR x = case BS.unsnoc x of+            Just (x, '\r') -> x+            _ -> x +        f x+            | Just (k, x) <- BS.uncons x+            , Just ('|', x) <- BS.uncons x =+                case k of+                    'w' -> Just $ FSAWrite x+                    'r' -> Just $ FSARead  x+                    'd' -> Just $ FSADelete x+                    'm' | (xs, ys) <- BS.break (== '|') x, Just ('|',ys) <- BS.uncons ys ->+                        Just $ FSAMove xs ys+                    'q' -> Just $ FSAQuery x+                    't' -> Just $ FSATouch x+                    _ -> Nothing+            | otherwise = Nothing + --------------------------------------------------------------------- -- ACTION EXPLICIT OPERATION @@ -257,9 +284,9 @@ commandExplicitAction :: Partial => Params -> Action [Result] commandExplicitAction oparams = do     ShakeOptions{shakeCommandOptions,shakeRunCommands,shakeLint,shakeLintInside} <- getShakeOptions-    params@Params{..} <- return $ oparams{opts = shakeCommandOptions ++ opts oparams}+    params@Params{..}<- pure $ oparams{opts = shakeCommandOptions ++ opts oparams} -    let skipper act = if null results && not shakeRunCommands then return [] else act+    let skipper act = if null results && not shakeRunCommands then pure [] else act      let verboser act = do             let cwd = listToMaybe $ reverse [x | Cwd x <- opts]@@ -272,7 +299,7 @@      let tracer act = do             -- note: use the oparams - find a good tracing before munging it for shell stuff-            let msg = last $ defaultTraced oparams : [x | Traced x <- opts]+            let msg = lastDef (defaultTraced oparams) [x | Traced x <- opts]             if msg == "" then liftIO act else traced msg act      let async = ResultProcess PID0 `elem` results@@ -286,13 +313,12 @@             xs <- liftIO $ filterM doesFileExist [x | FSARead x <- pxs]             cwd <- liftIO getCurrentDirectory             temp <- fixPaths cwd xs-            liftIO $ print ("AutoDeps", pxs, cwd, xs, temp) -- DEBUGGING             unsafeAllowApply $ need temp-            return res+            pure res          fixPaths cwd xs = liftIO $ do-            xs <- return $ map toStandard xs-            xs <- return $ filter (\x -> any (`isPrefixOf` x) shakeLintInside) xs+            xs<- pure $ map toStandard xs+            xs<- pure $ filter (\x -> any (`isPrefixOf` x) shakeLintInside) xs             mapM (\x -> fromMaybe x <$> makeRelativeEx cwd x) xs          fsalint act = do@@ -303,7 +329,7 @@             cwd <- liftIO getCurrentDirectory             trackRead  =<< fixPaths cwd =<< existing reader xs             trackWrite =<< fixPaths cwd =<< existing writer xs-            return res+            pure res      skipper $ tracker $ \params -> verboser $ tracer $ commandExplicitIO params @@ -318,7 +344,7 @@ -- | Given a very explicit set of CmdOption, translate them to a General.Process structure commandExplicitIO :: Partial => Params -> IO [Result] commandExplicitIO params = removeOptionShell params $ \params -> removeOptionFSATrace params $ \Params{..} -> do-    let (grabStdout, grabStderr) = both or $ unzip $ flip map results $ \r -> case r of+    let (grabStdout, grabStderr) = both or $ unzip $ flip map results $ \case             ResultStdout{} -> (True, False)             ResultStderr{} -> (False, True)             ResultStdouterr{} -> (True, True)@@ -326,40 +352,43 @@      optEnv <- resolveEnv opts     let optCwd = mergeCwd [x | Cwd x <- opts]-    let optStdin = flip mapMaybe opts $ \x -> case x of+    let optStdin = flip mapMaybe opts $ \case             Stdin x -> Just $ SrcString x             StdinBS x -> Just $ SrcBytes x             FileStdin x -> Just $ SrcFile x+            InheritStdin -> Just SrcInherit             _ -> Nothing     let optBinary = BinaryPipes `elem` opts     let optAsync = ResultProcess PID0 `elem` results     let optTimeout = listToMaybe $ reverse [x | Timeout x <- opts]-    let optWithStdout = last $ False : [x | WithStdout x <- opts]-    let optWithStderr = last $ True : [x | WithStderr x <- opts]+    let optWithStdout = lastDef False [x | WithStdout x <- opts]+    let optWithStderr = lastDef True [x | WithStderr x <- opts]     let optFileStdout = [x | FileStdout x <- opts]     let optFileStderr = [x | FileStderr x <- opts]-    let optEchoStdout = last $ (not grabStdout && null optFileStdout) : [x | EchoStdout x <- opts]-    let optEchoStderr = last $ (not grabStderr && null optFileStderr) : [x | EchoStderr x <- opts]+    let optEchoStdout = lastDef (not grabStdout && null optFileStdout) [x | EchoStdout x <- opts]+    let optEchoStderr = lastDef (not grabStderr && null optFileStderr) [x | EchoStderr x <- opts]     let optRealCommand = showCommandForUser2 prog args-    let optUserCommand = last $ optRealCommand : [x | UserCommand x <- opts]+    let optUserCommand = lastDef optRealCommand [x | UserCommand x <- opts]     let optCloseFds = CloseFileHandles `elem` opts+    let optProcessGroup = NoProcessGroup `notElem` opts -    let bufLBS f = do (a,b) <- buf $ LBS LBS.empty; return (a, (\(LBS x) -> f x) <$> b)+    let bufLBS f = do (a,b) <- buf $ LBS LBS.empty; pure (a, (\(LBS x) -> f x) <$> b)         buf Str{} | optBinary = bufLBS (Str . LBS.unpack)-        buf Str{} = do x <- newBuffer; return ([DestString x | not optAsync], Str . concat <$> readBuffer x)-        buf LBS{} = do x <- newBuffer; return ([DestBytes x | not optAsync], LBS . LBS.fromChunks <$> readBuffer x)+        buf Str{} = do x <- newBuffer; pure ([DestString x | not optAsync], Str . concat <$> readBuffer x)+        buf LBS{} = do x <- newBuffer; pure ([DestBytes x | not optAsync], LBS . LBS.fromChunks <$> readBuffer x)         buf BS {} = bufLBS (BS . BS.concat . LBS.toChunks)-        buf Unit  = return ([], return Unit)+        buf Unit  = pure ([], pure Unit)     (dStdout, dStderr, resultBuild) :: ([[Destination]], [[Destination]], [Double -> ProcessHandle -> ExitCode -> IO Result]) <--        fmap unzip3 $ forM results $ \r -> case r of-            ResultCode _ -> return ([], [], \_ _ ex -> return $ ResultCode ex)-            ResultTime _ -> return ([], [], \dur _ _ -> return $ ResultTime dur)-            ResultLine _ -> return ([], [], \_ _ _ -> return $ ResultLine optUserCommand)-            ResultProcess _ -> return ([], [], \_ pid _ -> return $ ResultProcess $ PID pid)-            ResultStdout    s -> do (a,b) <- buf s; return (a , [], \_ _ _ -> fmap ResultStdout b)-            ResultStderr    s -> do (a,b) <- buf s; return ([], a , \_ _ _ -> fmap ResultStderr b)-            ResultStdouterr s -> do (a,b) <- buf s; return (a , a , \_ _ _ -> fmap ResultStdouterr b)-            ResultFSATrace _ -> return ([], [], \_ _ _ -> return $ ResultFSATrace []) -- filled in elsewhere+        fmap unzip3 $ forM results $ \case+            ResultCode _ -> pure ([], [], \_ _ ex -> pure $ ResultCode ex)+            ResultTime _ -> pure ([], [], \dur _ _ -> pure $ ResultTime dur)+            ResultLine _ -> pure ([], [], \_ _ _ -> pure $ ResultLine optUserCommand)+            ResultProcess _ -> pure ([], [], \_ pid _ -> pure $ ResultProcess $ PID pid)+            ResultStdout    s -> do (a,b) <- buf s; pure (a , [], \_ _ _ -> fmap ResultStdout b)+            ResultStderr    s -> do (a,b) <- buf s; pure ([], a , \_ _ _ -> fmap ResultStderr b)+            ResultStdouterr s -> do (a,b) <- buf s; pure (a , a , \_ _ _ -> fmap ResultStdouterr b)+            ResultFSATrace _ -> pure ([], [], \_ _ _ -> pure $ ResultFSATrace []) -- filled in elsewhere+            ResultFSATraceBS _ -> pure ([], [], \_ _ _ -> pure $ ResultFSATraceBS []) -- filled in elsewhere      exceptionBuffer <- newBuffer     po <- resolvePath ProcessOpts@@ -370,6 +399,7 @@         ,poStderr = [DestEcho | optEchoStderr] ++ map DestFile optFileStderr ++ [DestString exceptionBuffer | optWithStderr && not optAsync] ++ concat dStderr         ,poAsync = optAsync         ,poCloseFds = optCloseFds+        ,poGroup = optProcessGroup         }     (dur,(pid,exit)) <- duration $ process po     if exit == ExitSuccess || ResultCode ExitSuccess `elem` results then@@ -378,12 +408,11 @@         exceptionBuffer <- readBuffer exceptionBuffer         let captured = ["Stderr" | optWithStderr] ++ ["Stdout" | optWithStdout]         cwd <- case optCwd of-            Nothing -> return ""+            Nothing -> pure ""             Just v -> do-                v <- canonicalizePath v `catchIO` const (return v)-                return $ "Current directory: " ++ v ++ "\n"-        -- FIXME: switch to errorIO once extra-1.6.18 is available everywhere-        liftIO $ error $+                v <- canonicalizePath v `catchIO` const (pure v)+                pure $ "Current directory: " ++ v ++ "\n"+        liftIO $ errorIO $             "Development.Shake." ++ funcName ++ ", system command failed\n" ++             "Command line: " ++ optRealCommand ++ "\n" ++             (if optRealCommand /= optUserCommand then "Original command line: " ++ optUserCommand ++ "\n" else "") ++@@ -401,9 +430,9 @@ -- | Apply all environment operations, to produce a new environment to use. resolveEnv :: [CmdOption] -> IO (Maybe [(String, String)]) resolveEnv opts-    | null env, null addEnv, null addPath, null remEnv = return Nothing+    | null env, null addEnv, null addPath, null remEnv = pure Nothing     | otherwise = Just . unique . tweakPath . (++ addEnv) . filter (flip notElem remEnv . fst) <$>-                  if null env then getEnvironment else return (concat env)+                  if null env then getEnvironment else pure (concat env)     where         env = [x | Env x <- opts]         addEnv = [(x,y) | AddEnv x y <- opts]@@ -434,24 +463,24 @@     new <- unsafeInterleaveIO $ findExecutableWith (splitSearchPath path) progExe     old2 <- unsafeInterleaveIO $ findExecutableWith (splitSearchPath pathOld) progExe -    switch <- return $ case () of+    switch<- pure $ case () of         _ | path == pathOld -> False -- The state I can see hasn't changed           | Nothing <- new -> False -- I have nothing to offer           | Nothing <- old -> True -- I failed last time, so this must be an improvement           | Just old <- old, Just new <- new, equalFilePath old new -> False -- no different           | Just old <- old, Just old2 <- old2, equalFilePath old old2 -> True -- I could predict last time           | otherwise -> False-    return $ case new of+    pure $ case new of         Just new | switch -> po{poCommand = RawCommand new args}         _ -> po-resolvePath po = return po+resolvePath po = pure po   -- | Given a list of directories, and a file name, return the complete path if you can find it. --   Like findExecutable, but with a custom PATH. findExecutableWith :: [FilePath] -> String -> IO (Maybe FilePath) findExecutableWith path x = flip firstJustM (map (</> x) path) $ \s ->-    ifM (doesFileExist s) (return $ Just s) (return Nothing)+    ifM (doesFileExist s) (pure $ Just s) (pure Nothing)   ---------------------------------------------------------------------@@ -496,7 +525,7 @@ -- timer act = do --     ('CmdTime' t, 'CmdLine' x, r) <- act --     liftIO $ putStrLn $ \"Command \" ++ x ++ \" took \" ++ show t ++ \" seconds\"---     return r+--     pure r -- -- run :: IO () -- run = timer $ 'cmd' \"ghc --version\"@@ -545,9 +574,12 @@ instance CmdResult CmdTime where     cmdResult = ([ResultTime 0], \[ResultTime x] -> CmdTime x) -instance CmdResult [FSATrace] where+instance CmdResult [FSATrace FilePath] where     cmdResult = ([ResultFSATrace []], \[ResultFSATrace x] -> x) +instance CmdResult [FSATrace BS.ByteString] where+    cmdResult = ([ResultFSATraceBS []], \[ResultFSATraceBS x] -> x)+ instance CmdString a => CmdResult (Stdout a) where     cmdResult = let (a,b) = cmdString in ([ResultStdout a], \[ResultStdout x] -> Stdout $ b x) @@ -705,9 +737,10 @@ class IsCmdArgument a where     -- | Conversion to a CmdArgument     toCmdArgument :: a -> CmdArgument+instance IsCmdArgument () where toCmdArgument = mempty instance IsCmdArgument String where toCmdArgument = CmdArgument . map Right . words instance IsCmdArgument [String] where toCmdArgument = CmdArgument . map Right-instance IsCmdArgument CmdOption where toCmdArgument = CmdArgument . return . Left+instance IsCmdArgument CmdOption where toCmdArgument = CmdArgument . pure . Left instance IsCmdArgument [CmdOption] where toCmdArgument = CmdArgument . map Left instance IsCmdArgument CmdArgument where toCmdArgument = id instance IsCmdArgument a => IsCmdArgument (Maybe a) where toCmdArgument = maybe mempty toCmdArgument
src/Development/Shake/Config.hs view
@@ -51,7 +51,7 @@     mapM_ (uncurry (Ninja.addEnv env) . (UTF8.fromString *** UTF8.fromString)) vars     Ninja.parse file env     mp <- Ninja.fromEnv env-    return $ Map.fromList $ map (UTF8.toString *** UTF8.toString) $ Map.toList mp+    pure $ Map.fromList $ map (UTF8.toString *** UTF8.toString) $ Map.toList mp   newtype Config = Config String deriving (Show,Typeable,Eq,Hashable,Binary,NFData)@@ -70,7 +70,7 @@         liftIO $ readConfigFile file     addOracle $ \(Config x) -> Map.lookup x <$> mp ()     addOracle $ \(ConfigKeys ()) -> sort . Map.keys <$> mp ()-    return ()+    pure ()   -- | Specify the values to use with 'getConfig', generally prefer@@ -78,9 +78,9 @@ --   of variables outside 'Action'. usingConfig :: Map.HashMap String String -> Rules () usingConfig mp = do-    addOracle $ \(Config x) -> return $ Map.lookup x mp-    addOracle $ \(ConfigKeys ()) -> return $ sort $ Map.keys mp-    return ()+    addOracle $ \(Config x) -> pure $ Map.lookup x mp+    addOracle $ \(ConfigKeys ()) -> pure $ sort $ Map.keys mp+    pure ()   -- | Obtain the value of a configuration variable, returns 'Nothing' to indicate the variable
src/Development/Shake/Database.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE RecordWildCards #-}  -- | Lower-level primitives to drive Shake, which are wrapped into the@@ -62,28 +63,28 @@             withOpen use "shakeOpenDatabase" id $ \_ ->                 ShakeDatabase use <$> open cleanup opts (rules >> defaultRules)     let free = do-            modifyVar_ use $ \x -> case x of+            modifyVar_ use $ \case                     Using s -> throwM $ errorStructured "Error when calling shakeOpenDatabase close function, currently running" [("Existing call", Just s)] ""-                    _ -> return Closed+                    _ -> pure Closed             clean-    return (alloc, free)+    pure (alloc, free)  withOpen :: Var UseState -> String -> (UseState -> UseState) -> (UseState -> IO a) -> IO a withOpen var name final act = mask $ \restore -> do-    o <- modifyVar var $ \x -> case x of+    o <- modifyVar var $ \case         Using s -> throwM $ errorStructured ("Error when calling " ++ name ++ ", currently running") [("Existing call", Just s)] ""         Closed -> throwM $ errorStructured ("Error when calling " ++ name ++ ", already closed") [] ""-        o@Open{} -> return (Using name, o)+        o@Open{} -> pure (Using name, o)     let clean = writeVar var $ final o     res <- restore (act o) `onException` clean     clean-    return res+    pure res  -- | Declare that a just-openned database will be used to call 'shakeRunDatabase' at most once. --   If so, an optimisation can be applied to retain less memory. shakeOneShotDatabase :: ShakeDatabase -> IO () shakeOneShotDatabase (ShakeDatabase use _) =-    withOpen use "shakeOneShotDatabase" (\o -> o{openOneShot=True}) $ \_ -> return ()+    withOpen use "shakeOneShotDatabase" (\o -> o{openOneShot=True}) $ \_ -> pure ()  -- | Given some options and rules, create a 'ShakeDatabase' that can be used to run --   executions.@@ -142,9 +143,9 @@             reset s         (refs, as) <- fmap unzip $ forM as $ \a -> do             ref <- newIORef Nothing-            return (ref, liftIO . writeIORef ref . Just =<< a)+            pure (ref, liftIO . writeIORef ref . Just =<< a)         after <- run s openOneShot $ map void as         results <- mapM readIORef refs         case sequence results of-            Just result -> return (result, after)+            Just result -> pure (result, after)             Nothing -> throwM $ errorInternal "Expected all results were written, but some where not"
src/Development/Shake/FilePath.hs view
@@ -14,6 +14,7 @@  import System.Directory (canonicalizePath) import System.Info.Extra+import Data.List.Extra import qualified System.FilePath as Native  import System.FilePath hiding@@ -34,7 +35,7 @@ -- > dropDirectory1 "aaa" == "" -- > dropDirectory1 "" == "" dropDirectory1 :: FilePath -> FilePath-dropDirectory1 = drop 1 . dropWhile (not . isPathSeparator)+dropDirectory1 = drop1 . dropWhile (not . isPathSeparator)   -- | Take the first component of a 'FilePath'. Should only be used on@@ -76,12 +77,12 @@ makeRelativeEx :: FilePath -> FilePath -> IO (Maybe FilePath) makeRelativeEx pathA pathB     | isRelative makeRelativePathAPathB =-        return (Just makeRelativePathAPathB)+        pure (Just makeRelativePathAPathB)     | otherwise = do         a' <- canonicalizePath pathA         b' <- canonicalizePath pathB         if takeDrive a' /= takeDrive b'-            then return Nothing+            then pure Nothing             else Just <$> makeRelativeEx' a' b'     where         makeRelativePathAPathB = makeRelative pathA pathB@@ -91,11 +92,11 @@             let rel = makeRelative a b                 parent = takeDirectory a             if isRelative rel-                then return rel+                then pure rel                 else if a /= parent                     then do                         parentToB <- makeRelativeEx' parent b-                        return (".." </> parentToB)+                        pure (".." </> parentToB)                      -- Impossible: makeRelative should have succeeded in finding                     -- a relative path once `a == "/"`.
src/Development/Shake/Forward.hs view
@@ -55,7 +55,7 @@ import Development.Shake.Command import Development.Shake.Classes import Development.Shake.FilePath-import Data.IORef+import Data.IORef.Extra import Data.Either import Data.Typeable import Data.List.Extra@@ -89,7 +89,7 @@ encode' = BS.concat . LBS.toChunks . encode  decode' :: Binary a => BS.ByteString -> a-decode' = decode . LBS.fromChunks . return+decode' = decode . LBS.fromChunks . pure  type instance RuleResult Forward = Forward @@ -112,14 +112,14 @@         fail "When running in forward mode you must set shakeLintInside to specify where to detect dependencies"     addBuiltinRule noLint noIdentity $ \k old mode ->         case old of-            Just old | mode == RunDependenciesSame -> return $ RunResult ChangedNothing old (decode' old)+            Just old | mode == RunDependenciesSame -> pure $ RunResult ChangedNothing old (decode' old)             _ -> do                 res <- liftIO $ atomicModifyIORef forwards $ \mp -> (Map.delete k mp, Map.lookup k mp)                 case res of                     Nothing -> liftIO $ errorIO $ "Failed to find action name, " ++ show k                     Just act -> do                         new <- act-                        return $ RunResult ChangedRecomputeSame (encode' new) new+                        pure $ RunResult ChangedRecomputeSame (encode' new) new     action act  -- | Given a 'ShakeOptions', set the options necessary to execute in forward mode.@@ -133,10 +133,10 @@ --   (e.g. the action is a closure), you should call 'cacheActionWith' being explicit about what is captured. cacheAction :: (Typeable a, Binary a, Show a, Typeable b, Binary b, Show b) => a -> Action b -> Action b cacheAction (mkForward -> key) (action :: Action b) = do-    liftIO $ atomicModifyIORef forwards $ \mp -> (Map.insert key (mkForward <$> action) mp, ())+    liftIO $ atomicModifyIORef_ forwards $ Map.insert key (mkForward <$> action)     res <- apply1 key-    liftIO $ atomicModifyIORef forwards $ \mp -> (Map.delete key mp, ())-    return $ unForward res+    liftIO $ atomicModifyIORef_ forwards $ Map.delete key+    pure $ unForward res  newtype With a = With a     deriving (Typeable, Binary, Show)@@ -147,7 +147,7 @@ cacheActionWith key argument action = do     cacheAction (With argument) $ do         alwaysRerun-        return argument+        pure argument     cacheAction key $ do         apply1 $ mkForward $ With argument         action@@ -163,7 +163,7 @@ cache cmd = do     let CmdArgument args = cmd     let isDull ['-',_] = True; isDull _ = False-    let name = head $ filter (not . isDull) (drop 1 $ rights args) ++ ["unknown"]+    let name = headDef "unknown" $ filter (not . isDull) $ drop1 $ rights args     cacheAction (Command $ toStandard name ++ " #" ++ upper (showHex (abs $ hash $ show args) "")) cmd  newtype Command = Command String
src/Development/Shake/Internal/Args.hs view
@@ -29,7 +29,7 @@ import Control.Exception.Extra import Control.Monad import Data.Either-import Data.List+import Data.List.Extra import Data.Maybe import System.Directory.Extra import System.Environment@@ -80,7 +80,7 @@ -- * @main _make/henry.txt@ will not build @neil.txt@ or @emily.txt@, but will instead build @henry.txt@. shakeArgs :: ShakeOptions -> Rules () -> IO () shakeArgs opts rules = shakeArgsWith opts [] f-    where f _ files = return $ Just $ if null files then rules else want files >> withoutActions rules+    where f _ files = pure $ Just $ if null files then rules else want files >> withoutActions rules   -- | A version of 'shakeArgs' with more flexible handling of command line arguments.@@ -115,7 +115,7 @@ -- data Flags = DistCC deriving Eq -- flags = [Option \"\" [\"distcc\"] (NoArg $ Right DistCC) \"Run distributed.\"] ----- main = 'shakeArgsWith' 'shakeOptions' flags $ \\flags targets -> return $ Just $ do+-- main = 'shakeArgsWith' 'shakeOptions' flags $ \\flags targets -> pure $ Just $ do --     let compiler = if DistCC \`elem\` flags then \"distcc\" else \"gcc\" --     let rules = do --         \"*.o\" '%>' \\out -> do@@ -146,7 +146,7 @@         progressReplays = [x | ProgressReplay x <- flagsExtra]         progressRecords = [x | ProgressRecord x <- flagsExtra]         changeDirectory = listToMaybe [x | ChangeDirectory x <- flagsExtra]-        printDirectory = last $ False : [x | PrintDirectory x <- flagsExtra]+        printDirectory = lastDef False [x | PrintDirectory x <- flagsExtra]         shareRemoves = [x | ShareRemove x <- flagsExtra]         oshakeOpts = foldl' (flip ($)) baseOpts flagsShake     lintInside <- mapM canonicalizePath $ shakeLintInside oshakeOpts@@ -160,8 +160,8 @@     let putWhenLn v msg = putWhen v $ msg ++ "\n"     let showHelp long = do             progName <- getProgName-            (targets, helpSuffix) <- if not long then return ([], []) else-                handleSynchronous (\e -> do putWhenLn Info $ "Failure to collect targets: " ++ show e; return ([], [])) $ do+            (targets, helpSuffix) <- if not long then pure ([], []) else+                handleSynchronous (\e -> do putWhenLn Info $ "Failure to collect targets: " ++ show e; pure ([], [])) $ do                     -- run the rules as simply as we can                     rs <- rules shakeOpts [] []                     case rs of@@ -169,8 +169,8 @@                             xs <- getTargets shakeOpts rs                             helpSuffix <- getHelpSuffix shakeOpts rs                             evaluate $ force (["  - " ++ a ++ maybe "" (" - " ++) b | (a,b) <- xs], helpSuffix)-                        _ -> return ([], [])-            changes <- return $+                        _ -> pure ([], [])+            changes<- pure $                 let as = shakeOptionsFields baseOpts                     bs = shakeOptionsFields oshakeOpts                 in ["  - " ++ lbl ++ ": " ++ v1 ++ " => " ++ v2 | long, ((lbl, v1), (_, v2)) <- zip as bs, v1 /= v2]@@ -199,7 +199,7 @@      else if not $ null progressReplays then do         dat <- forM progressReplays $ \file -> do             src <- readFile file-            return (file, map read $ lines src)+            pure (file, map read $ lines src)         forM_ (if null $ shakeReport shakeOpts then ["-"] else shakeReport shakeOpts) $ \file -> do             putWhenLn Info $ "Writing report to " ++ file             writeProgressReport file dat@@ -208,30 +208,30 @@         start <- offsetTime         initDataDirectory -- must be done before we start changing directory         let redir = maybe id withCurrentDirectory changeDirectory-        shakeOpts <- if null progressRecords then return shakeOpts else do+        shakeOpts <- if null progressRecords then pure shakeOpts else do             t <- offsetTime-            return shakeOpts{shakeProgress = \p ->+            pure shakeOpts{shakeProgress = \p ->                 void $ withThreadsBoth (shakeProgress shakeOpts p) $-                    progressDisplay 1 (const $ return ()) $ do+                    progressDisplay 1 (const $ pure ()) $ do                         p <- p                         t <- t                         forM_ progressRecords $ \file ->                             appendFile file $ show (t,p) ++ "\n"-                        return p+                        pure p             }         (ran,shakeOpts,res) <- redir $ do             when printDirectory $ do                 curdir <- getCurrentDirectory                 putWhenLn Info $ "shake: In directory `" ++ curdir ++ "'"             (shakeOpts, ui) <- do-                let compact = last $ No : [x | Compact x <- flagsExtra]-                use <- if compact == Auto then checkEscCodes else return $ compact == Yes+                let compact = lastDef No [x | Compact x <- flagsExtra]+                use <- if compact == Auto then checkEscCodes else pure $ compact == Yes                 if use                     then second withThreadSlave <$> compactUI shakeOpts-                    else return (shakeOpts, id)+                    else pure (shakeOpts, id)             rules <- rules shakeOpts user files             ui $ case rules of-                Nothing -> return (False, shakeOpts, Right ())+                Nothing -> pure (False, shakeOpts, Right ())                 Just (shakeOpts, rules) -> do                     res <- try_ $ shake shakeOpts $                         if NoBuild `elem` flagsExtra then@@ -249,10 +249,10 @@                             withoutActions rules                         else                             rules-                    return (True, shakeOpts, res)+                    pure (True, shakeOpts, res)          if not ran || shakeVerbosity shakeOpts < Info || NoTime `elem` flagsExtra then-            either throwIO return res+            either throwIO pure res          else             let esc = if shakeColor shakeOpts then escape else flip const             in case res of@@ -338,8 +338,8 @@     ,opts $ Option "m" ["metadata"] (reqArg "PREFIX" $ \x s -> s{shakeFiles=x}) "Prefix for storing metadata files."     ,extr $ Option ""  ["numeric-version"] (noArg [NumericVersion]) "Print just the version number and exit."     ,opts $ Option ""  ["skip-commands"] (noArg $ \s -> s{shakeRunCommands=False}) "Try and avoid running external programs."-    ,opts $ Option "B" ["rebuild"] (optArg "PATTERN" $ \x s -> s{shakeRebuild=shakeRebuild s ++ [(RebuildNow, fromMaybe "**" x)]}) "Rebuild matching files."-    ,opts $ Option ""  ["no-rebuild"] (optArg "PATTERN" $ \x s -> s{shakeRebuild=shakeRebuild s ++ [(RebuildNormal, fromMaybe "**" x)]}) "Rebuild matching files if necessary (default)."+    ,opts $ Option "B" ["rebuild"] (optArg "PATTERN" $ \x s -> s{shakeRebuild=shakeRebuild s ++ [(RebuildNow, fromMaybe "**" x)]}) "If required, these files will rebuild even if nothing has changed."+    ,opts $ Option ""  ["no-rebuild"] (optArg "PATTERN" $ \x s -> s{shakeRebuild=shakeRebuild s ++ [(RebuildNormal, fromMaybe "**" x)]}) "If required, these files will rebuild only if things have changed (default)."     ,opts $ Option ""  ["skip"] (optArg "PATTERN" $ \x s -> s{shakeRebuild=shakeRebuild s ++ [(RebuildLater, fromMaybe "**" x)]}) "Don't rebuild matching files this run." --    ,yes $ Option ""  ["skip-forever"] (OptArg (\x -> Right ([], \s -> s{shakeRebuild=shakeRebuild s ++ [(RebuildNever, fromMaybe "**" x)]})) "PATTERN") "Don't rebuild matching files until they change."     ,opts $ Option "r" ["report","profile"] (optArg "FILE" $ \x s -> s{shakeReport=shakeReport s ++ [fromMaybe "report.html" x]}) "Write out profiling information [to report.html]."@@ -357,7 +357,7 @@     ,opts $ Option "S" ["no-keep-going","stop"] (noArg $ \s -> s{shakeStaunch=False}) "Turns off -k."     ,opts $ Option ""  ["storage"] (noArg $ \s -> s{shakeStorageLog=True}) "Write a storage log."     ,both $ Option "p" ["progress"] (progress $ optArgInt 1 "progress" "N" $ \i s -> s{shakeProgress=prog $ fromMaybe 5 i}) "Show progress messages [every N secs, default 5]."-    ,opts $ Option ""  ["no-progress"] (noArg $ \s -> s{shakeProgress=const $ return ()}) "Don't show progress messages."+    ,opts $ Option ""  ["no-progress"] (noArg $ \s -> s{shakeProgress=const $ pure ()}) "Don't show progress messages."     ,opts $ Option "q" ["quiet"] (noArg $ \s -> s{shakeVerbosity=move (shakeVerbosity s) pred}) "Print less (pass repeatedly for even less)."     ,extr $ Option ""  ["no-time"] (noArg [NoTime]) "Don't print build time."     ,opts $ Option ""  ["timings"] (noArg $ \s -> s{shakeTimings=True}) "Print phase timings."
src/Development/Shake/Internal/CmdOption.hs view
@@ -29,4 +29,6 @@     | UserCommand String -- ^ The command the user thinks about, before any munging. Defaults to the actual command.     | FSAOptions String -- ^ Options to @fsatrace@, a list of strings with characters such as @\"r\"@ (reads) @\"w\"@ (writes). Defaults to @\"rwmdqt\"@ if the output of @fsatrace@ is required.     | CloseFileHandles -- ^ Before starting the command in the child process, close all file handles except stdin, stdout, stderr in the child process. Uses @close_fds@ from package process and comes with the same caveats, i.e. runtime is linear with the maximum number of open file handles (@RLIMIT_NOFILE@, see @man 2 getrlimit@ on Linux).+    | NoProcessGroup -- ^ Don't run the process in its own group. Required when running @docker@. Will mean that process timeouts and asyncronous exceptions may not properly clean up child processes.+    | InheritStdin -- ^ Cause the stdin from the parent to be inherited. Might also require NoProcessGroup on Linux. Ignored if you explicitly pass a stdin.       deriving (Eq,Ord,Show,Data,Typeable)
src/Development/Shake/Internal/CompactUI.hs view
@@ -13,7 +13,7 @@ import Control.Exception import General.Thread import General.EscCodes-import Data.IORef+import Data.IORef.Extra import Control.Monad.Extra  @@ -64,9 +64,9 @@     unlessM checkEscCodes $         putStrLn "Your terminal does not appear to support escape codes, --compact mode may not work"     ref <- newIORef emptyS-    let tweak f = atomicModifyIORef ref $ \s -> (f s, ())+    let tweak = atomicModifyIORef_ ref     time <- offsetTime-    opts <- return $ opts+    opts <- pure $ opts         {shakeTrace = \a b c -> do t <- time; tweak (addTrace a b c t)         ,shakeOutput = \a b -> tweak (addOutput a b)         ,shakeProgress = \x -> void $ progressDisplay 1 (tweak . addProgress) x `withThreadsBoth` shakeProgress opts x@@ -74,4 +74,4 @@         ,shakeVerbosity = Error         }     let tick = do t <- time; mask_ $ putStr =<< atomicModifyIORef ref (display t)-    return (opts, forever (tick >> sleep 0.4) `finally` tick)+    pure (opts, forever (tick >> sleep 0.4) `finally` tick)
src/Development/Shake/Internal/Core/Action.hs view
@@ -28,10 +28,11 @@ import System.Directory import System.FilePattern import System.FilePattern.Directory+import System.Time.Extra import Control.Concurrent.Extra import Data.Maybe import Data.Tuple.Extra-import Data.IORef+import Data.IORef.Extra import Data.List.Extra import Numeric.Extra import General.Extra@@ -67,7 +68,7 @@     putRW s2     res <- fromAction m     modifyRW undo-    return res+    pure res   ---------------------------------------------------------------------@@ -78,12 +79,12 @@ --   then do nothing with it. shakeException :: Global -> Stack -> SomeException -> IO ShakeException shakeException Global{globalOptions=ShakeOptions{..},..} stk e = case fromException e of-    Just (e :: ShakeException) -> return e+    Just (e :: ShakeException) -> pure e     Nothing -> do-        e <- return $ exceptionStack stk e+        e<- pure $ exceptionStack stk e         when (shakeStaunch && shakeVerbosity >= Error) $             globalOutput Error $ show e ++ "Continuing due to staunch mode"-        return e+        pure e   actionBracketEx :: Bool -> IO a -> (a -> IO b) -> (a -> Action c) -> Action c@@ -92,18 +93,18 @@     (v, key) <- liftIO $ mask_ $ do         v <- alloc         key <- liftIO $ register globalCleanup $ void $ free v-        return (v, key)+        pure (v, key)     res <- Action $ catchRAW (fromAction $ act v) $ \e -> liftIO (release key) >> throwRAW e     liftIO $ if runOnSuccess then release key else unprotect key-    return res+    pure res  -- | If an exception is raised by the 'Action', perform some 'IO' then reraise the exception. actionOnException :: Action a -> IO b -> Action a-actionOnException act free = actionBracketEx False (return ()) (const free) (const act)+actionOnException act free = actionBracketEx False (pure ()) (const free) (const act)  -- | After an 'Action', perform some 'IO', even if there is an exception. actionFinally :: Action a -> IO b -> Action a-actionFinally act free = actionBracket (return ()) (const free) (const act)+actionFinally act free = actionBracket (pure ()) (const free) (const act)  -- | Like `bracket`, but where the inner operation is of type 'Action'. Usually used as --   @'actionBracket' alloc free use@.@@ -152,7 +153,7 @@ runAfter :: IO () -> Action () runAfter op = do     Global{..} <- Action getRO-    liftIO $ atomicModifyIORef globalAfter $ \ops -> (op:ops, ())+    liftIO $ atomicModifyIORef_ globalAfter (op:)   ---------------------------------------------------------------------@@ -257,7 +258,7 @@     let trace = newTrace msg start stop     liftIO $ evaluate $ rnf trace     Action $ modifyRW $ \s -> s{localTraces = trace : localTraces s}-    return res+    pure res   ---------------------------------------------------------------------@@ -320,7 +321,7 @@         let used = Set.filter (not . ignore) $ Set.fromList localTrackRead          -- check Read 4a-        bad <- return $ Set.toList $ used `Set.difference` Set.fromList deps+        bad<- pure $ Set.toList $ used `Set.difference` Set.fromList deps         unless (null bad) $ do             let n = length bad             throwM $ errorStructured@@ -338,9 +339,9 @@                 ""          -- check Write 3-        bad <- return $ filter (not . ignore) $ Set.toList $ Set.fromList localTrackWrite+        bad<- pure $ filter (not . ignore) $ Set.toList $ Set.fromList localTrackWrite         unless (null bad) $-            liftIO $ atomicModifyIORef globalTrackAbsent $ \old -> ([(fromMaybe k top, k) | k <- bad] ++ old, ())+            liftIO $ atomicModifyIORef_ globalTrackAbsent ([(fromMaybe k top, k) | k <- bad] ++)   -- | Allow any matching key recorded with 'lintTrackRead' or 'lintTrackWrite' in this action,@@ -366,12 +367,12 @@         ""  lintWatch :: [FilePattern] -> IO (String -> IO ())-lintWatch [] = return $ const $ return ()+lintWatch [] = pure $ const $ pure () lintWatch pats = do     let op = getDirectoryFiles "." pats -- cache parsing of the pats-    let record = do xs <- op; forM xs $ \x -> (x,) <$> getFileInfo (fileNameFromString x)+    let record = do xs <- op; forM xs $ \x -> (x,) <$> getFileInfo False (fileNameFromString x)     old <- record-    return $ \msg -> do+    pure $ \msg -> do         now <- record         when (old /= now) $ throwIO $ errorStructured             "Lint checking error - watched files have changed"@@ -391,7 +392,7 @@ lookupDependencies :: Database -> Key -> IO [Depends] lookupDependencies db k = do     Just (Ready r) <- getValueFromKey db k-    return $ depends r+    pure $ depends r   -- | This rule should not be cached or recorded in the history because it makes use of untracked dependencies@@ -425,7 +426,7 @@     Local{localDepends=pre} <- getRW     res <- fromAction act     modifyRW $ \s -> s{localDepends=pre}-    return res+    pure res   ---------------------------------------------------------------------@@ -436,15 +437,15 @@ newCacheIO :: (Eq k, Hashable k) => (k -> Action v) -> IO (k -> Action v) newCacheIO (act :: k -> Action v) = do     var :: Var (Map.HashMap k (Fence IO (Either SomeException ([Depends],v)))) <- newVar Map.empty-    return $ \key ->+    pure $ \key ->         join $ liftIO $ modifyVar var $ \mp -> case Map.lookup key mp of-            Just bar -> return $ (,) mp $ do+            Just bar -> pure $ (,) mp $ do                 (offset, (deps, v)) <- actionFenceRequeue bar                 Action $ modifyRW $ \s -> addDiscount offset $ s{localDepends = deps ++ localDepends s}-                return v+                pure v             Nothing -> do                 bar <- newFence-                return $ (Map.insert key bar mp,) $ do+                pure $ (Map.insert key bar mp,) $ do                     Local{localDepends=pre} <- Action getRW                     res <- Action $ tryRAW $ fromAction $ act key                     case res of@@ -455,7 +456,7 @@                             Local{localDepends=post} <- Action getRW                             let deps = dropEnd (length pre) post                             liftIO $ signalFence bar $ Right (deps, v)-                            return v+                            pure v   -- | Run an action without counting to the thread limit, typically used for actions that execute@@ -473,14 +474,14 @@     -- we start a new thread, giving up ours, to ensure the thread count goes down     (wait, res) <- actionAlwaysRequeue res     Action $ modifyRW $ addDiscount wait-    return res+    pure res   -- | Execute a list of actions in parallel. In most cases 'need' will be more appropriate to benefit from parallelism. parallel :: [Action a] -> Action [a] -- Note: There is no parallel_ unlike sequence_ because there is no stack benefit to doing so-parallel [] = return []-parallel [x] = return <$> x+parallel [] = pure []+parallel [x] = pure <$> x parallel acts = do     Global{..} <- Action getRO @@ -492,12 +493,12 @@             Action $ modifyRW localClearMutable             res <- act             old <- Action getRW-            return (old, res)+            pure (old, res)     (wait, res) <- actionFenceSteal =<< liftIO (exceptFence waits)     liftIO $ atomicWriteIORef done True     let (waits, locals, results) = unzip3 $ map (\(a,(b,c)) -> (a,b,c)) res     Action $ modifyRW $ \root -> addDiscount (wait - sum waits) $ localMergeMutable root locals-    return results+    pure results   -- | Batch different outputs into a single 'Action', typically useful when a command has a high@@ -516,7 +517,7 @@ -- -- @ -- 'batch' 3 (\"*.out\" 'Development.Shake.%>')---     (\\out -> do 'Development.Shake.need' [out '-<.>' \"in\"]; return out)+--     (\\out -> do 'Development.Shake.need' [out '-<.>' \"in\"]; pure out) --     (\\outs -> 'Development.Shake.cmd' "build-multiple" [out '-<.>' \"in\" | out \<- outs]) -- @ --@@ -537,7 +538,7 @@     | mx <= 0 = error $ "Can't call batchable with <= 0, you used " ++ show mx     | mx == 1 = pred $ \a -> do b <- one a; many [b]     | otherwise = do-        todo :: IORef (Int, [(b, Local, Fence IO (Either SomeException Local))]) <- liftIO $ newIORef (0, [])+        todo :: IORef (Int, [(b, Local, Fence IO (Either SomeException (Seconds, Local)))]) <- liftIO $ newIORef (0, [])         pred $ \a -> do             b <- one a             fence <- liftIO newFence@@ -545,15 +546,15 @@             local <- Action getRW             count <- liftIO $ atomicModifyIORef todo $ \(count, bs) -> let i = count+1 in ((i, (b,local,fence):bs), i)             requeue todo (==) count-            (wait, local2) <- actionFenceRequeue fence-            Action $ modifyRW $ \root -> addDiscount wait $ localMergeMutable root [local2]+            (wait, (cost, local2)) <- actionFenceRequeue fence+            Action $ modifyRW $ \root -> addDiscount (wait - cost) $ localMergeMutable root [local2]     where         -- When changing by one, only trigger on (==) so we don't have lots of waiting pool entries         -- When changing by many, trigger on (>=) because we don't hit all edges         requeue todo trigger count             | count `trigger` mx = addPoolWait_ PoolResume $ go todo             | count `trigger` 1  = addPoolWait_ PoolBatch  $ go todo-            | otherwise = return ()+            | otherwise = pure ()          go todo = do             -- delete at most mx from the batch@@ -568,9 +569,17 @@                     -- make sure we are using one of the local's that we are computing                     -- we things like stack, blockApply etc. work as expected                     modifyRW $ const $ localClearMutable $ snd3 $ head now+                    start <- liftIO offsetTime                     fromAction $ many $ map fst3 now-                    res <- getRW-                    return res{localDiscount = localDiscount res / intToDouble (length now)} -- divide the batch fairly+                    end <- liftIO start++                    -- accounting for time is tricky, we spend time T, over N jobs+                    -- so want to charge everyone for T / N time+                    -- but that also means we need to subtract localDiscount so we don't apply that to all+                    rw <- getRW+                    let t = end - localDiscount rw+                    let n = intToDouble (length now)+                    pure (t / n, rw{localDiscount = 0})                 liftIO $ mapM_ (flip signalFence res . thd3) now  @@ -580,7 +589,7 @@ --   Only useful if the results are being interactively reported or consumed. reschedule :: Double -> Action () reschedule x = do-    (wait, _) <- actionAlwaysRequeuePriority (PoolDeprioritize $ negate x) $ return ()+    (wait, _) <- actionAlwaysRequeuePriority (PoolDeprioritize $ negate x) $ pure ()     Action $ modifyRW $ addDiscount wait  
src/Development/Shake/Internal/Core/Build.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE RecordWildCards, PatternGuards, ScopedTypeVariables, NamedFieldPuns, GADTs #-} {-# LANGUAGE Rank2Types, ConstraintKinds, TupleSections, ViewPatterns #-} @@ -49,7 +50,7 @@         let changeValue = case v of                 Ready r -> Just $ "    = " ++ showBracket (result r) ++ " " ++ (if built r == changed r then "(changed)" else "(unchanged)")                 _ -> Nothing-        return $ changeStatus ++ maybe "" ("\n" ++) changeValue+        pure $ changeStatus ++ maybe "" ("\n" ++) changeValue     setMem db i k v  @@ -64,7 +65,7 @@ getDatabaseValueGeneric k = do     Global{..} <- Action getRO     Just status <- liftIO $ getValueFromKey globalDatabase k-    return $ getResult status+    pure $ getResult status   ---------------------------------------------------------------------@@ -97,7 +98,7 @@ buildOne global@Global{..} stack database i k r = case addStack i k stack of     Left e -> do         quickly $ setIdKeyStatus global database i k $ mkError e-        return $ Left e+        pure $ Left e     Right stack -> Later $ \continue -> do         setIdKeyStatus global database i k (Running (NoShow continue) r)         let go = buildRunMode global stack database r@@ -107,7 +108,7 @@                     let val = fmap runValue res                     res <- liftIO $ getKeyValueFromId database i                     w <- case res of-                        Just (_, Running (NoShow w) _) -> return w+                        Just (_, Running (NoShow w) _) -> pure w                         -- We used to be able to hit here, but we fixed it by ensuring the thread pool workers are all                         -- dead _before_ any exception bubbles up                         _ -> throwM $ errorInternal $ "expected Waiting but got " ++ maybe "nothing" (statusType . snd) res ++ ", key " ++ show k@@ -115,7 +116,7 @@                     w val                 case res of                     Right RunResult{..} | runChanged /= ChangedNothing -> setDisk database i k $ Loaded runValue{result=runStore}-                    _ -> return ()+                    _ -> pure ()     where         mkError e = Failed e $ if globalOneShot then Nothing else r @@ -124,9 +125,9 @@ buildRunMode :: Global -> Stack -> Database -> Maybe (Result a) -> Wait Locked RunMode buildRunMode global stack database me = do     changed <- case me of-        Nothing -> return True+        Nothing -> pure True         Just me -> buildRunDependenciesChanged global stack database me-    return $ if changed then RunDependenciesChanged else RunDependenciesSame+    pure $ if changed then RunDependenciesChanged else RunDependenciesSame   -- | Have the dependencies changed@@ -151,7 +152,7 @@     Local{localStack, localBlockApply} <- Action getRW     let stack = addCallStack callStack localStack -    let tk = typeKey $ head $ ks ++ [newKey ()] -- always called at non-empty so never see () key+    let tk = typeKey $ headDef (newKey ()) ks -- always called at non-empty so never see () key     whenJust localBlockApply $ throwM . errorNoApply tk (show <$> listToMaybe ks)      let database = globalDatabase@@ -160,13 +161,13 @@         wait <- runWait $ do             x <- firstJustWaitUnordered (fmap (either Just (const Nothing)) . lookupOne global stack database) $ nubOrd is             case x of-                Just e -> return $ Left e+                Just e -> pure $ Left e                 Nothing -> quickly $ Right <$> mapM (fmap (\(Just (_, Ready r)) -> fst $ result r) . liftIO . getKeyValueFromId database) is-        return (is, wait)+        pure (is, wait)     Action $ modifyRW $ \s -> s{localDepends = Depends is : localDepends s}      case wait of-        Now vs -> either throwM return vs+        Now vs -> either throwM pure vs         _ -> do             offset <- liftIO offsetTime             vs <- Action $ captureRAW $ \continue ->@@ -174,7 +175,7 @@                     liftIO $ addPool (if isLeft x then PoolException else PoolResume) globalPool $ continue x             offset <- liftIO offset             Action $ modifyRW $ addDiscount offset-            return vs+            pure vs   runKey@@ -189,7 +190,7 @@     let tk = typeKey k     BuiltinRule{..} <- case Map.lookup tk globalRules of         Nothing -> throwM $ errorNoRuleToBuildType tk (Just $ show k) Nothing-        Just r -> return r+        Just r -> pure r      let s = (newLocal stack shakeVerbosity){localBuiltinVersion = builtinVersion}     time <- offsetTime@@ -203,7 +204,7 @@             globalRuleFinished k             producesCheck -        Action $ fmap (res,) getRW) $ \x -> case x of+        Action $ fmap (res,) getRW) $ \case             Left e ->                 continue . Left . toException =<< shakeException global stack e             Right (RunResult{..}, Local{..})@@ -232,7 +233,7 @@ apply :: (Partial, RuleResult key ~ value, ShakeValue key, Typeable value) => [key] -> Action [value] apply [] =     -- if they do [] then we don't test localBlockApply, but unclear if that should be an error or not-    return []+    pure [] apply ks =     fmap (map fromValue) $ Action $ stepRAW (callStackFull, map newKey ks) @@ -240,7 +241,7 @@ -- | Apply a single rule, equivalent to calling 'apply' with a singleton list. Where possible, --   use 'apply' to allow parallelism. apply1 :: (Partial, RuleResult key ~ value, ShakeValue key, Typeable value) => key -> Action value-apply1 = withFrozenCallStack $ fmap head . apply . return+apply1 = withFrozenCallStack $ fmap head . apply . pure   @@ -256,7 +257,7 @@ historyLoad (Ver -> ver) = do     global@Global{..} <- Action getRO     Local{localStack, localBuiltinVersion} <- Action getRW-    if isNothing globalShared && isNothing globalCloud then return Nothing else do+    if isNothing globalShared && isNothing globalCloud then pure Nothing else do         key <- liftIO $ evaluate $ fromMaybe (error "Can't call historyLoad outside a rule") $ topStack localStack         let database = globalDatabase         res <- liftIO $ runLocked database $ runWait $ do@@ -265,19 +266,19 @@                     let identify = runIdentify globalRules k . fst . result                     either (const Nothing) identify <$> lookupOne global localStack database i             x <- case globalShared of-                Nothing -> return Nothing+                Nothing -> pure Nothing                 Just shared -> lookupShared shared ask key localBuiltinVersion ver             x <- case x of-                Just res -> return $ Just res+                Just res -> pure $ Just res                 Nothing -> case globalCloud of-                    Nothing -> return Nothing+                    Nothing -> pure Nothing                     Just cloud -> lookupCloud cloud ask key localBuiltinVersion ver             case x of-                Nothing -> return Nothing+                Nothing -> pure Nothing                 Just (a,b,c) -> quickly $ Just . (a,,c) <$> mapM (mapM $ mkId database) b         -- FIXME: If running with cloud and shared, and you got a hit in cloud, should also add it to shared         res <- case res of-            Now x -> return x+            Now x -> pure x             _ -> do                 offset <- liftIO offsetTime                 res <- Action $ captureRAW $ \continue ->@@ -285,14 +286,14 @@                         liftIO $ addPool PoolResume globalPool $ continue $ Right x                 offset <- liftIO offset                 Action $ modifyRW $ addDiscount offset-                return res+                pure res         case res of-            Nothing -> return Nothing+            Nothing -> pure Nothing             Just (res, deps, restore) -> do-                liftIO $ globalDiagnostic $ return $ "History hit for " ++ show key+                liftIO $ globalDiagnostic $ pure $ "History hit for " ++ show key                 liftIO restore                 Action $ modifyRW $ \s -> s{localDepends = reverse $ map Depends deps}-                return (Just res)+                pure (Just res)   -- | Is the history enabled, returns 'True' if you have a 'shakeShare' or 'shakeCloud',@@ -301,7 +302,7 @@ historyIsEnabled = Action $ do     Global{..} <- getRO     Local{localHistory} <- getRW-    return $ localHistory && (isJust globalShared || isJust globalCloud)+    pure $ localHistory && (isJust globalShared || isJust globalCloud)   -- | Save a value to the history. Record the version of any user rule@@ -326,14 +327,14 @@             -- can do this without the DB lock, since it reads things that are stable             forNothingM (reverse localDepends) $ \(Depends is) -> forNothingM is $ \i -> do                 Just (k, Ready r) <- getKeyValueFromId globalDatabase i-                return $ (k,) <$> runIdentify globalRules k (fst $ result r)+                pure $ (k,) <$> runIdentify globalRules k (fst $ result r)         let k = topStack localStack         case deps of-            Nothing -> liftIO $ globalDiagnostic $ return $ "Dependency with no identity for " ++ show k+            Nothing -> liftIO $ globalDiagnostic $ pure $ "Dependency with no identity for " ++ show k             Just deps -> do                 whenJust globalShared $ \shared -> addShared shared key localBuiltinVersion ver deps store produced                 whenJust globalCloud  $ \cloud  -> addCloud  cloud  key localBuiltinVersion ver deps store produced-                liftIO $ globalDiagnostic $ return $ "History saved for " ++ show k+                liftIO $ globalDiagnostic $ pure $ "History saved for " ++ show k   runIdentify :: Map.HashMap TypeRep BuiltinRule -> Key -> Value -> Maybe BS.ByteString
src/Development/Shake/Internal/Core/Database.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP #-} {-# LANGUAGE GeneralizedNewtypeDeriving, RecordWildCards #-}  module Development.Shake.Internal.Core.Database(@@ -18,18 +17,12 @@ import Control.Concurrent.Extra import Control.Monad.IO.Class import qualified General.Ids as Ids--#if __GLASGOW_HASKELL__ >= 800 && __GLASGOW_HASKELL__ < 808 import Control.Monad.Fail-#endif+import Prelude   newtype Locked a = Locked (IO a)-    deriving (Functor, Applicative, Monad, MonadIO-#if __GLASGOW_HASKELL__ >= 800-             ,MonadFail-#endif-        )+    deriving (Functor, Applicative, Monad, MonadIO, MonadFail)  runLocked :: DatabasePoly k v -> Locked b -> IO b runLocked db (Locked act) = withLock (lock db) act@@ -58,7 +51,7 @@     xs <- Ids.toList status     intern <- newIORef $ Intern.fromList [(k, i) | (i, (k,_)) <- xs]     lock <- newLock-    return Database{..}+    pure Database{..}   ---------------------------------------------------------------------@@ -68,7 +61,7 @@ getValueFromKey Database{..} k = do     is <- readIORef intern     case Intern.lookup k is of-        Nothing -> return Nothing+        Nothing -> pure Nothing         Just i -> fmap snd <$> Ids.lookup status i  -- Returns Nothing only if the Id was serialised previously but then the Id disappeared@@ -84,7 +77,7 @@ getIdFromKey :: (Eq k, Hashable k) => DatabasePoly k v -> IO (k -> Maybe Id) getIdFromKey Database{..} = do     is <- readIORef intern-    return $ flip Intern.lookup is+    pure $ flip Intern.lookup is   ---------------------------------------------------------------------@@ -95,13 +88,13 @@ mkId Database{..} k = liftIO $ do     is <- readIORef intern     case Intern.lookup k is of-        Just i -> return i+        Just i -> pure i         Nothing -> do-            (is, i) <- return $ Intern.add k is+            (is, i)<- pure $ Intern.add k is             -- make sure to write it into Status first to maintain Database invariants             Ids.insert status i (k, vDefault)             writeIORef' intern is-            return i+            pure i   setMem :: DatabasePoly k v -> Id -> k -> v -> Locked ()
src/Development/Shake/Internal/Core/Monad.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE GADTs, ScopedTypeVariables, TupleSections, GeneralizedNewtypeDeriving #-}  module Development.Shake.Internal.Core.Monad(@@ -16,11 +16,8 @@ import Control.Monad import System.IO import Data.Semigroup-import Prelude--#if __GLASGOW_HASKELL__ >= 800 && __GLASGOW_HASKELL__ < 808 import Control.Monad.Fail-#endif+import Prelude   data RAW k v ro rw a where@@ -54,14 +51,8 @@ instance MonadIO (RAW k v ro rw) where     liftIO = LiftIO -#if __GLASGOW_HASKELL__ >= 800 && __GLASGOW_HASKELL__ < 808 instance MonadFail (RAW k v ro rw) where     fail = liftIO . Control.Monad.Fail.fail-#endif-#if __GLASGOW_HASKELL__ >= 808-instance MonadFail (RAW k v ro rw) where-    fail = liftIO . Prelude.fail-#endif  instance Semigroup a => Semigroup (RAW k v ro rw a) where     (<>) a b = (<>) <$> a <*> b@@ -81,10 +72,10 @@  assertOnce :: MonadIO m => String -> (a -> m b) -> IO (a -> m b) assertOnce msg k-    | not assertOnceCheck = return k+    | not assertOnceCheck = pure k     | otherwise = do         ref <- liftIO $ newIORef False-        return $ \v -> do+        pure $ \v -> do             liftIO $ join $ atomicModifyIORef ref $ \old -> (True,) $ when old $ do                 hPutStrLn stderr "FATAL ERROR: assertOnce failed"                 Prelude.fail $ "assertOnce failed: " ++ msg@@ -136,10 +127,10 @@             Bind a b -> go a $ \a -> sio a $ \a -> go (b a) k             LiftIO act -> flush $ do v <- act; k $ pure v -            GetRO -> k $ return ro-            GetRW -> flush $ k . return =<< readIORef rw-            PutRW x -> flush $ writeIORef rw x >> k (return ())-            ModifyRW f -> flush $ modifyIORef' rw f >> k (return ())+            GetRO -> k $ pure ro+            GetRW -> flush $ k . pure =<< readIORef rw+            PutRW x -> flush $ writeIORef rw x >> k (pure ())+            ModifyRW f -> flush $ modifyIORef' rw f >> k (pure ())              CatchRAW m hdl -> flush $ do                 hdl <- assertOnce "CatchRAW" hdl@@ -154,11 +145,11 @@                 f <- assertOnce "CaptureRAW" f                 old <- readIORef handler                 writeIORef handler throwIO-                f $ \x -> case x of+                f $ \case                     Left e -> old e                     Right v -> do                         writeIORef handler old-                        k (return v) `catch_` \e -> do unflush; ($ e) =<< readIORef handler+                        k (pure v) `catch_` \e -> do unflush; ($ e) =<< readIORef handler   newtype SIO a = SIO (IO a)@@ -174,7 +165,7 @@ addStep (Steps ref) k = do     out <- newIORef $ throwImpure $ errorInternal "Monad, addStep not flushed"     modifyIORef ref ((k,out):)-    return $ SIO $ readIORef out+    pure $ SIO $ readIORef out  unflushSteps :: Steps k v -> IO () unflushSteps (Steps ref) = writeIORef ref []@@ -183,10 +174,10 @@ flushSteps (Steps ref) = do     v <- reverse <$> readIORef ref     case v of-        [] -> return Nothing+        [] -> pure Nothing         xs -> do             writeIORef ref []-            return $ Just $ \step -> do+            pure $ Just $ \step -> do                 vs <- step $ map fst xs                 liftIO $ zipWithM_ writeIORef (map snd xs) vs @@ -215,7 +206,7 @@ catchRAW = CatchRAW  tryRAW :: RAW k v ro rw a -> RAW k v ro rw (Either SomeException a)-tryRAW m = catchRAW (fmap Right m) (return . Left)+tryRAW m = catchRAW (fmap Right m) (pure . Left)  throwRAW :: Exception e => e -> RAW k v ro rw a -- Note that while we could directly pass this to the handler@@ -226,7 +217,7 @@ finallyRAW a undo = do     r <- catchRAW a (\e -> undo >> throwRAW e)     undo-    return r+    pure r   ---------------------------------------------------------------------
src/Development/Shake/Internal/Core/Pool.hs view
@@ -28,9 +28,9 @@     rw <- Action getRW     liftIO $ do         fence <- newFence-        let act2 = do offset <- liftIO offsetTime; res <- act; offset <- liftIO offset; return (offset, res)+        let act2 = do offset <- liftIO offsetTime; res <- act; offset <- liftIO offset; pure (offset, res)         addPool pri globalPool $ runAction ro rw act2 $ signalFence fence-        return fence+        pure fence  -- | Like 'addPoolWait' but doesn't provide a fence to wait for it - a fire and forget version. --   Warning: If Action throws an exception, it would be lost, so must be executed with try. Seconds are not tracked.@@ -38,7 +38,7 @@ addPoolWait_ pri act = do     ro@Global{..} <- Action getRO     rw <- Action getRW-    liftIO $ addPool pri globalPool $ runAction ro rw act $ \_ -> return ()+    liftIO $ addPool pri globalPool $ runAction ro rw act $ \_ -> pure ()   actionFenceSteal :: Fence IO (Either SomeException a) -> Action (Seconds, a)@@ -46,7 +46,7 @@     res <- liftIO $ testFence fence     case res of         Just (Left e) -> Action $ throwRAW e-        Just (Right v) -> return (0, v)+        Just (Right v) -> pure (0, v)         Nothing -> Action $ captureRAW $ \continue -> do             offset <- offsetTime             waitFence fence $ \v -> do@@ -62,7 +62,7 @@     res <- liftIO $ testFence fence     case fmap op res of         Just (Left e) -> throwRAW e-        Just (Right v) -> return (0, v)+        Just (Right v) -> pure (0, v)         Nothing -> do             Global{..} <- getRO             offset <- liftIO offsetTime
src/Development/Shake/Internal/Core/Rules.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP #-} {-# LANGUAGE RecordWildCards, ScopedTypeVariables #-} {-# LANGUAGE GeneralizedNewtypeDeriving, ConstraintKinds, NamedFieldPuns #-} {-# LANGUAGE ExistentialQuantification, RankNTypes #-}@@ -40,11 +39,8 @@ import Data.Binary.Put import Data.Binary.Get import General.ListBuilder-import Prelude--#if __GLASGOW_HASKELL__ >= 800 && __GLASGOW_HASKELL__ < 808 import Control.Monad.Fail-#endif+import Prelude  import Development.Shake.Internal.Core.Types import Development.Shake.Internal.Core.Monad@@ -69,9 +65,9 @@     Global{..} <- Action getRO     let UserRuleVersioned versioned rules = fromMaybe mempty $ TMap.lookup globalUserRules     let ver = if versioned then Nothing else Just $ Ver 0-    let items = head $ (map snd $ reverse $ groupSort $ f (Ver 0) Nothing rules) ++ [[]]+    let items = headDef [] $ map snd $ reverse $ groupSort $ f (Ver 0) Nothing rules     let err = errorMultipleRulesMatch (typeOf key) (show key) (map snd3 items)-    return (ver, map (\(Ver v,_,x) -> (v,x)) items, err)+    pure (ver, map (\(Ver v,_,x) -> (v,x)) items, err)     where         f :: Ver -> Maybe Double -> UserRule a -> [(Double,(Ver,Maybe String,b))]         f v p (UserRule x) = [(fromMaybe 1 p, (v,disp x,x2)) | Just x2 <- [test x]]@@ -98,8 +94,8 @@ getUserRuleMaybe key disp test = do     (_, xs, err) <- getUserRuleInternal key disp test     case xs of-        [] -> return Nothing-        [x] -> return $ Just x+        [] -> pure Nothing+        [x] -> pure $ Just x         _ -> throwM err  -- | A version of 'getUserRuleList' that fails if there is not exactly one result@@ -108,7 +104,7 @@ getUserRuleOne key disp test = do     (_, xs, err) <- getUserRuleInternal key disp test     case xs of-        [x] -> return x+        [x] -> pure x         _ -> throwM err  @@ -116,11 +112,7 @@ --   Rules are combined with either the 'Monoid' instance, or (more commonly) the 'Monad' instance and @do@ notation. --   To define your own custom types of rule, see "Development.Shake.Rule". newtype Rules a = Rules (ReaderT (ShakeOptions, IORef (SRules ListBuilder)) IO a) -- All IO must be associative/commutative (e.g. creating IORef/MVars)-    deriving (Functor, Applicative, Monad, MonadIO, MonadFix-#if __GLASGOW_HASKELL__ >= 800-             ,MonadFail-#endif-        )+    deriving (Functor, Applicative, Monad, MonadIO, MonadFix, Control.Monad.Fail.MonadFail)  newRules :: SRules ListBuilder -> Rules () newRules x = Rules $ liftIO . flip modifyIORef' (<> x) =<< asks snd@@ -133,14 +125,14 @@         res <- runReaderT r (opts, refNew)         rules <- readIORef refNew         modifyIORef' refOld (<> f rules)-        return res+        pure res  runRules :: ShakeOptions -> Rules () -> IO (SRules []) runRules opts (Rules r) = do     ref <- newIORef mempty     runReaderT r (opts, ref)     SRules{..} <- readIORef ref-    return $ SRules (runListBuilder actions) builtinRules userRules (runListBuilder targets) (runListBuilder helpSuffix)+    pure $ SRules (runListBuilder actions) builtinRules userRules (runListBuilder targets) (runListBuilder helpSuffix)  -- | Get all targets registered in the given rules. The names in --   'Development.Shake.phony' and 'Development.Shake.~>' as well as the file patterns@@ -150,12 +142,12 @@ getTargets :: ShakeOptions -> Rules () -> IO [(String, Maybe String)] getTargets opts rs = do     SRules{targets} <- runRules opts rs-    return [(target, documentation) | Target{..} <- targets]+    pure [(target, documentation) | Target{..} <- targets]  getHelpSuffix :: ShakeOptions -> Rules () -> IO [String] getHelpSuffix opts rs = do     SRules{helpSuffix} <- runRules opts rs-    return helpSuffix+    pure helpSuffix  data Target = Target     {target :: !String@@ -182,7 +174,7 @@     (<>) = liftA2 (<>)  instance (Semigroup a, Monoid a) => Monoid (Rules a) where-    mempty = return mempty+    mempty = pure mempty     mappend = (<>)  @@ -215,7 +207,7 @@  -- | A suitable 'BuiltinLint' that always succeeds. noLint :: BuiltinLint key value-noLint _ _ = return Nothing+noLint _ _ = pure Nothing  -- | A suitable 'BuiltinIdentity' that always fails with a runtime error, incompatible with 'shakeShare'. --   Use this function if you don't care about 'shakeShare', or if your rule provides a dependency that can@@ -239,7 +231,7 @@     => BuiltinLint key value -> BuiltinIdentity key value -> BuiltinRun key value -> Rules () addBuiltinRule = withFrozenCallStack $ addBuiltinRuleInternal $ BinaryOp     (putEx . Bin.toLazyByteString . execPut . put)-    (runGet get . LBS.fromChunks . return)+    (runGet get . LBS.fromChunks . pure)  addBuiltinRuleEx     :: (RuleResult key ~ value, ShakeValue key, BinaryEx key, Typeable value, NFData value, Show value, Partial)
src/Development/Shake/Internal/Core/Run.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE RecordWildCards, ScopedTypeVariables, PatternGuards #-} {-# LANGUAGE ConstraintKinds, TupleSections, ViewPatterns #-} {-# LANGUAGE TypeFamilies, NamedFieldPuns #-}@@ -33,7 +34,7 @@ import qualified Data.HashSet as Set import Data.Dynamic import Data.Maybe-import Data.IORef+import Data.IORef.Extra import System.Directory import System.Time.Extra import qualified Data.ByteString as BS@@ -72,20 +73,20 @@  open :: Cleanup -> ShakeOptions -> Rules () -> IO RunState open cleanup opts rs = withInit opts $ \opts@ShakeOptions{..} diagnostic _ -> do-    diagnostic $ return "Starting run"+    diagnostic $ pure "Starting run"     SRules{actions, builtinRules, userRules} <- runRules opts rs -    diagnostic $ return $ "Number of actions = " ++ show (length actions)-    diagnostic $ return $ "Number of builtin rules = " ++ show (Map.size builtinRules) ++ " " ++ show (Map.keys builtinRules)-    diagnostic $ return $ "Number of user rule types = " ++ show (TMap.size userRules)-    diagnostic $ return $ "Number of user rules = " ++ show (sum (TMap.toList (userRuleSize . userRuleContents) userRules))+    diagnostic $ pure $ "Number of actions = " ++ show (length actions)+    diagnostic $ pure $ "Number of builtin rules = " ++ show (Map.size builtinRules) ++ " " ++ show (Map.keys builtinRules)+    diagnostic $ pure $ "Number of user rule types = " ++ show (TMap.size userRules)+    diagnostic $ pure $ "Number of user rules = " ++ show (sum (TMap.toList (userRuleSize . userRuleContents) userRules))      checkShakeExtra shakeExtra     curdir <- getCurrentDirectory      database <- usingDatabase cleanup opts diagnostic builtinRules     (shared, cloud) <- loadSharedCloud database opts builtinRules-    return RunState{..}+    pure RunState{..}   -- Prepare for a fresh run by changing Result to Loaded@@ -145,11 +146,11 @@                 -- give each action a stack to start with!                 forM_ (actions ++ map (emptyStack,) actions2) $ \(stack, act) -> do                     let local = newLocal stack shakeVerbosity-                    addPool PoolStart pool $ runAction global local (act >> getLocal) $ \x -> case x of+                    addPool PoolStart pool $ runAction global local (act >> getLocal) $ \case                         Left e -> raiseError =<< shakeException global stack e-                        Right local -> atomicModifyIORef locals $ \rest -> (local:rest, ())+                        Right local -> atomicModifyIORef_ locals (local:) -            maybe (return ()) (throwIO . snd) =<< readIORef except+            whenJustM (readIORef except) (throwIO . snd)             assertFinishedDatabase database             let putWhen lvl msg = when (shakeVerbosity >= lvl) $ output lvl msg @@ -172,7 +173,7 @@                     writeProfile file database             when (shakeLiveFiles /= []) $ do                 addTiming "Listing live"-                diagnostic $ return "Listing live keys"+                diagnostic $ pure "Listing live keys"                 xs <- liveFiles database                 forM_ shakeLiveFiles $ \file -> do                     putWhen Info $ "Writing live list to " ++ file@@ -180,21 +181,21 @@              res <- readIORef after             addTiming "Cleanup"-            return res+            pure res          whenJustM (readIORef timingsToShow) $             putStr . unlines-        return res+        pure res   -- | Run a set of IO actions, treated as \"after\" actions, typically returned from --   'Development.Shake.Database.shakeRunDatabase'. The actions will be run with diagnostics --   etc as specified in the 'ShakeOptions'. shakeRunAfter :: ShakeOptions -> [IO ()] -> IO ()-shakeRunAfter _ [] = return ()+shakeRunAfter _ [] = pure () shakeRunAfter opts after = withInit opts $ \ShakeOptions{..} diagnostic _ -> do     let n = show $ length after-    diagnostic $ return $ "Running " ++ n ++ " after actions"+    diagnostic $ pure $ "Running " ++ n ++ " after actions"     (time, _) <- duration $ sequence_ $ reverse after     when (shakeTimings && shakeVerbosity >= Info) $         putStrLn $ "(+ running " ++ show n ++ " after actions in " ++ showDuration time ++ ")"@@ -210,17 +211,17 @@  usingShakeOptions :: Cleanup -> ShakeOptions -> IO ShakeOptions usingShakeOptions cleanup opts = do-    opts@ShakeOptions{..} <- if shakeThreads opts /= 0 then return opts else do p <- getProcessorCount; return opts{shakeThreads=p}+    opts@ShakeOptions{..} <- if shakeThreads opts /= 0 then pure opts else do p <- getProcessorCount; pure opts{shakeThreads=p}     when shakeLineBuffering $ usingLineBuffering cleanup     usingNumCapabilities cleanup shakeThreads-    return opts+    pure opts  outputFunctions :: ShakeOptions -> Lock -> (IO String -> IO (), Verbosity -> String -> IO ()) outputFunctions opts@ShakeOptions{..} outputLock = (diagnostic, output)     where         outputLocked v msg = withLock outputLock $ shakeOutput v msg -        diagnostic | shakeVerbosity < Diagnostic = const $ return ()+        diagnostic | shakeVerbosity < Diagnostic = const $ pure ()                    | otherwise = \act -> do v <- act; outputLocked Diagnostic $ "% " ++ v         output v = outputLocked v . shakeAbbreviationsApply opts @@ -230,9 +231,9 @@     let getProgress = do             failure <- getFailure             stats <- progress database step-            return stats{isFailure=failure}+            pure stats{isFailure=failure}     allocateThread cleanup $ shakeProgress getProgress-    return getProgress+    pure getProgress  checkShakeExtra :: Map.HashMap TypeRep Dynamic -> IO () checkShakeExtra mp = do@@ -241,12 +242,12 @@         (k,t):xs -> throwIO $ errorStructured "Invalid Map in shakeExtra"             [("Key",Just $ show k),("Value type",Just $ show t)]             (if null xs then "" else "Plus " ++ show (length xs) ++ " other keys")-        _ -> return ()+        _ -> pure ()   runLint :: Map.HashMap TypeRep BuiltinRule -> Key -> Value -> IO (Maybe String) runLint mp k v = case Map.lookup (typeKey k) mp of-    Nothing -> return Nothing+    Nothing -> pure Nothing     Just BuiltinRule{..} -> builtinLint k v  @@ -269,27 +270,27 @@ liveFiles database = do     status <- getKeyValues database     let specialIsFileKey t = show (fst $ splitTyConApp t) == "FileQ"-    return [show k | (k, Ready{}) <- status, specialIsFileKey $ typeKey k]+    pure [show k | (k, Ready{}) <- status, specialIsFileKey $ typeKey k]  errorsState :: RunState -> IO [(String, SomeException)] errorsState RunState{..} = do     status <- getKeyValues database-    return [(show k, e) | (k, Failed e _) <- status]+    pure [(show k, e) | (k, Failed e _) <- status]   checkValid :: (IO String -> IO ()) -> Database -> (Key -> Value -> IO (Maybe String)) -> [(Key, Key)] -> IO () checkValid diagnostic db check absent = do     status <- getKeyValues db-    diagnostic $ return "Starting validity/lint checking"+    diagnostic $ pure "Starting validity/lint checking"      -- TEST 1: Have values changed since being depended on     -- Do not use a forM here as you use too much stack space     bad <- (\f -> foldM f [] status) $ \seen v -> case v of         (key, Ready Result{..}) -> do             good <- check key $ fst result-            diagnostic $ return $ "Checking if " ++ show key ++ " is " ++ show result ++ ", " ++ if isNothing good then "passed" else "FAILED"-            return $ [(key, result, now) | Just now <- [good]] ++ seen-        _ -> return seen+            diagnostic $ pure $ "Checking if " ++ show key ++ " is " ++ show result ++ ", " ++ if isNothing good then "passed" else "FAILED"+            pure $ [(key, result, now) | Just now <- [good]] ++ seen+        _ -> pure seen     unless (null bad) $ do         let n = length bad         throwM $ errorStructured@@ -300,7 +301,7 @@      -- TEST 2: Is anything from lintTrackWrite which promised not to exist actually been created     exists <- getIdFromKey db-    bad <- return [(parent,key) | (parent, key) <- Set.toList $ Set.fromList absent, isJust $ exists key]+    bad <- pure [(parent,key) | (parent, key) <- Set.toList $ Set.fromList absent, isJust $ exists key]     unless (null bad) $ do         let n = length bad         throwM $ errorStructured@@ -308,7 +309,7 @@             (intercalate [("",Just "")] [ [("Rule", Just $ show parent), ("Created", Just $ show key)] | (parent,key) <- bad])             "" -    diagnostic $ return "Validity/lint check passed"+    diagnostic $ pure "Validity/lint check passed"   ---------------------------------------------------------------------@@ -318,11 +319,11 @@ usingDatabase cleanup opts diagnostic owitness = do     let step = (typeRep (Proxy :: Proxy StepKey), (Ver 0, BinaryOp (const mempty) (const stepKey)))     let root = (typeRep (Proxy :: Proxy Root), (Ver 0, BinaryOp (const mempty) (const rootKey)))-    witness <- return $ Map.fromList+    witness<- pure $ Map.fromList         [ (QTypeRep t, (version, BinaryOp (putDatabase putOp) (getDatabase getOp)))         | (t,(version, BinaryOp{..})) <- step : root : Map.toList (Map.map (\BuiltinRule{..} -> (builtinVersion, builtinKey)) owitness)]     (status, journal) <- usingStorage cleanup opts diagnostic witness-    journal <- return $ \i k v -> journal (QTypeRep $ typeKey k) i (k, v)+    journal<- pure $ \i k v -> journal (QTypeRep $ typeKey k) i (k, v)     createDatabase status journal Missing  @@ -330,13 +331,13 @@ incrementStep db = runLocked db $ do     stepId <- mkId db stepKey     v <- liftIO $ getKeyValueFromId db stepId-    step <- return $ case v of+    step<- pure $ case v of         Just (_, Loaded r) -> incStep $ fromStepResult r         _ -> Step 1     let stepRes = toStepResult step     setMem db stepId stepKey $ Ready stepRes     liftIO $ setDisk db stepId stepKey $ Loaded $ fmap snd stepRes-    return step+    pure step  toStepResult :: Step -> Result (Value, BS_Store) toStepResult i = Result (newValue i, runBuilder $ putEx i) i i [] 0 []@@ -369,13 +370,13 @@     let ver = makeVer $ shakeVersion opts      shared <- case shakeShare opts of-        Nothing -> return Nothing+        Nothing -> pure Nothing         Just x -> Just <$> newShared (shakeSymlink opts) wit2 ver x     cloud <- case newCloud (runLocked var) (Map.map builtinKey owitness) ver keyVers $ shakeCloud opts of-        _ | null $ shakeCloud opts -> return Nothing+        _ | null $ shakeCloud opts -> pure Nothing         Nothing -> fail "shakeCloud set but Shake not compiled for cloud operation"         Just res -> Just <$> res-    return (shared, cloud)+    pure (shared, cloud)   putDatabase :: (Key -> Builder) -> ((Key, Status) -> Builder)
src/Development/Shake/Internal/Core/Storage.hs view
@@ -56,7 +56,7 @@ messageCorrupt :: FilePath -> SomeException -> IO [String] messageCorrupt dbfile err = do     msg <- showException err-    return $+    pure $         ("Error when reading Shake database " ++ dbfile) :         map ("  "++) (lines msg) ++         ["All files will be rebuilt"]@@ -97,15 +97,15 @@     -> Map.HashMap k (Ver, BinaryOp v)                 -- ^ Witnesses     -> IO (Ids.Ids v, k -> Id -> v -> IO ()) usingStorage _ ShakeOptions{..} diagnostic _ | shakeFiles == "/dev/null" = do-    diagnostic $ return "Using in-memory database"+    diagnostic $ pure "Using in-memory database"     ids <- Ids.empty-    return (ids, \_ _ _ -> return ())+    pure (ids, \_ _ _ -> pure ())  usingStorage cleanup ShakeOptions{..} diagnostic witness = do     let lockFile = shakeFiles </> ".shake.lock"-    diagnostic $ return $ "Before usingLockFile on " ++ lockFile+    diagnostic $ pure $ "Before usingLockFile on " ++ lockFile     usingLockFile cleanup lockFile-    diagnostic $ return "After usingLockFile"+    diagnostic $ pure "After usingLockFile"      let dbfile = shakeFiles </> ".shake.database"     createDirectoryRecursive shakeFiles@@ -113,7 +113,7 @@     -- complete a partially failed compress     whenM (restoreChunksBackup dbfile) $ do         unexpected "Backup file exists, restoring over the previous file\n"-        diagnostic $ return "Backup file move to original"+        diagnostic $ pure "Backup file move to original"      addTiming "Database read"     h <- usingChunks cleanup dbfile shakeFlush@@ -137,11 +137,11 @@     ids <- case witnessOld of         Left _ -> do             resetChunksCorrupt Nothing h-            return Nothing+            pure Nothing         Right witnessOld ->  handleBool (not . isAsyncException) (\err -> do             outputErr =<< messageCorrupt dbfile err             corrupt-            return Nothing) $ do+            pure Nothing) $ do              (!missing, !load) <- evaluate $ loadWitness witness witnessOld             when (missing /= []) $ outputErr $ messageMissingTypes dbfile missing@@ -154,8 +154,8 @@                         Left e -> do                             let slop = fromIntegral $ BS.length e                             when (slop > 0) $ unexpected $ "Last " ++ show slop ++ " bytes do not form a whole record\n"-                            diagnostic $ return $ "Read " ++ show i ++ " chunks, plus " ++ show slop ++ " slop"-                            return i+                            diagnostic $ pure $ "Read " ++ show i ++ " chunks, plus " ++ show slop ++ " slop"+                            pure i                         Right bs | (id, Just (k,v)) <- load bs -> do                             evaluate $ rnf k                             evaluate $ rnf v@@ -164,14 +164,14 @@                                 let pretty (Left x) = "FAILURE: " ++ show x                                     pretty (Right x) = x                                 x2 <- try_ $ evaluate $ let s = show v in rnf s `seq` s-                                return $ "Chunk " ++ show i ++ " " ++ raw bs ++ " " ++ show id ++ " = " ++ pretty x2+                                pure $ "Chunk " ++ show i ++ " " ++ raw bs ++ " " ++ show id ++ " = " ++ pretty x2                             go $ i+1                         Right bs -> do-                            diagnostic $ return $ "Chunk " ++ show i ++ " " ++ raw bs ++ " UNKNOWN WITNESS"+                            diagnostic $ pure $ "Chunk " ++ show i ++ " " ++ raw bs ++ " UNKNOWN WITNESS"                             go i             countItems <- go 0             countDistinct <- Ids.sizeUpperBound ids-            diagnostic $ return $ "Found at most " ++ show countDistinct ++ " distinct entries out of " ++ show countItems+            diagnostic $ pure $ "Found at most " ++ show countDistinct ++ " distinct entries out of " ++ show countItems              when (countItems > countDistinct*2 || not verEq || witnessOld /= witnessNew) $ do                 addTiming "Database compression"@@ -182,7 +182,7 @@             Just <$> Ids.forCopy ids snd      ids <- case ids of-        Just ids -> return ids+        Just ids -> pure ids         Nothing -> do             writeChunk h $ putEx ver             writeChunk h $ putEx witnessNew@@ -190,7 +190,7 @@      addTiming "With database"     out <- usingWriteChunks cleanup h-    return (ids, \k i v -> out $ save k i v)+    pure (ids, \k i v -> out $ save k i v)     where         unexpected x = when shakeStorageLog $ do             t <- getCurrentTime
src/Development/Shake/Internal/Core/Types.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP #-} {-# LANGUAGE GeneralizedNewtypeDeriving, ScopedTypeVariables, DeriveDataTypeable, ViewPatterns #-} {-# LANGUAGE ExistentialQuantification, DeriveFunctor, RecordWildCards, FlexibleInstances #-} @@ -47,11 +46,8 @@ import Development.Shake.Classes import Data.Semigroup import General.Cleanup-import Prelude--#if __GLASGOW_HASKELL__ >= 800 && __GLASGOW_HASKELL__ < 808 import Control.Monad.Fail-#endif+import Prelude   ---------------------------------------------------------------------@@ -61,11 +57,7 @@ --   Action values are used by 'addUserRule' and 'action'. The 'Action' monad tracks the dependencies of a rule. --   To raise an exception call 'error', 'fail' or @'liftIO' . 'throwIO'@. newtype Action a = Action {fromAction :: RAW ([String],[Key]) [Value] Global Local a}-    deriving (Functor, Applicative, Monad, MonadIO, Typeable, Semigroup, Monoid-#if __GLASGOW_HASKELL__ >= 800-             ,MonadFail-#endif-        )+    deriving (Functor, Applicative, Monad, MonadIO, Typeable, Semigroup, Monoid, MonadFail)  runAction :: Global -> Local -> Action a -> Capture (Either SomeException a) runAction g l (Action x) = runRAW (fromAction . build) g l x@@ -73,7 +65,7 @@         -- first argument is a list of call stacks, since build only takes one we use the first         -- they are very probably all identical...         build :: [([String], [Key])] -> Action [[Value]]-        build [] = return []+        build [] = pure []         build ks@((callstack,_):_) = do             let kss = map snd ks             unconcat kss <$> globalBuild g callstack (concat kss)@@ -296,7 +288,7 @@ -- -- > run key oldStore mode = do -- >     ...--- >     return $ RunResult change newStore newValue+-- >     pure $ RunResult change newStore newValue -- --   Where you have: --
src/Development/Shake/Internal/Demo.hs view
@@ -7,8 +7,7 @@  import Control.Exception.Extra import Control.Monad-import Data.Char-import Data.List+import Data.List.Extra import Data.Maybe import System.Directory import System.Exit@@ -42,7 +41,7 @@     dir <- if empty then getCurrentDirectory else do         home <- getHomeDirectory         dir <- getDirectoryContents home-        return $ home </> head (map ("shake-demo" ++) ("":map show [2..]) \\ dir)+        pure $ home </> head (map ("shake-demo" ++) ("":map show [2..]) \\ dir)      putStrLn "% The Shake demo uses an empty directory, OK to use:"     putStrLn $ "%     " ++ dir@@ -100,21 +99,21 @@ yesNo :: Bool -> IO Bool yesNo auto = do     putStr "% [Y/N] (then ENTER): "-    x <- if auto then putLine "y" else fmap (map toLower) getLine+    x <- if auto then putLine "y" else lower <$> getLine     if "y" `isPrefixOf` x then-        return True+        pure True      else if "n" `isPrefixOf` x then-        return False+        pure False      else         yesNo auto  putLine :: String -> IO String-putLine x = putStrLn x >> return x+putLine x = putStrLn x >> pure x   -- | Replace exceptions with 'False'. wrap :: IO Bool -> IO Bool-wrap act = act `catch_` const (return False)+wrap act = act `catch_` const (pure False)   -- | Require a condition to be true, or exit with a message.
src/Development/Shake/Internal/Derived.hs view
@@ -54,7 +54,7 @@ getHashedShakeVersion :: [FilePath] -> IO String getHashedShakeVersion files = do     hashes <- mapM (fmap (hashWithSalt 0) . BS.readFile) files-    return $ "hash-" ++ show (hashWithSalt 0 hashes)+    pure $ "hash-" ++ show (hashWithSalt 0 hashes)   -- | Get an item from 'shakeExtra', using the requested type as the key. Fails@@ -70,13 +70,13 @@ lookupShakeExtra mp =     case Map.lookup want mp of         Just dyn-            | Just x <- fromDynamic dyn -> return $ Just x+            | Just x <- fromDynamic dyn -> pure $ Just x             | otherwise -> throwM $ errorStructured                 "shakeExtra value is malformed, all keys and values must agree"                 [("Key", Just $ show want)                 ,("Value", Just $ show $ dynTypeRep dyn)]                 "Use addShakeExtra to ensure shakeExtra is well-formed"-        Nothing -> return Nothing+        Nothing -> pure Nothing     where want = typeRep (Proxy :: Proxy a)  -- | Add a properly structued value to 'shakeExtra' which can be retrieved with 'getShakeExtra'.@@ -145,7 +145,7 @@         -- semantics on Windows         b <- withFile name ReadMode $ \h -> do             src <- hGetContents h-            return $! src /= x+            pure $! src /= x         when b $ do             removeFile_ name -- symlink safety             writeFile name x@@ -252,7 +252,7 @@ -- @ -- google <- 'Development.Shake.newThrottle' \"Google\" 1 5 -- \"*.url\" 'Development.Shake.%>' \\out -> do---     'Development.Shake.withResource' google 1 $ return ()+--     'Development.Shake.withResource' google 1 $ pure () --     'Development.Shake.cmd' \"wget\" [\"https:\/\/google.com?q=\" ++ 'Development.Shake.FilePath.takeBaseName' out] \"-O\" [out] -- @ --@@ -290,7 +290,7 @@ -- @ -- digits \<- 'newCache' $ \\file -> do --     src \<- readFile\' file---     return $ length $ filter isDigit src+--     pure $ length $ filter isDigit src -- \"*.digits\" 'Development.Shake.%>' \\x -> do --     v1 \<- digits ('dropExtension' x) --     v2 \<- digits ('dropExtension' x)
src/Development/Shake/Internal/FileInfo.hs view
@@ -6,12 +6,21 @@     getFileHash, getFileInfo     ) where +#ifndef MIN_VERSION_unix+#define MIN_VERSION_unix(a,b,c) 0+#endif++#ifndef MIN_VERSION_time+#define MIN_VERSION_time(a,b,c) 0+#endif++ import Data.Hashable import Control.Exception.Extra import Development.Shake.Classes import Development.Shake.Internal.FileName import qualified Data.ByteString.Lazy.Internal as LBS (defaultChunkSize)-import Data.Char+import Data.List.Extra import Data.Word import Numeric import System.IO@@ -27,8 +36,15 @@ import Control.Monad import qualified Data.ByteString.Char8 as BS import Foreign.C.String+import Data.Char  #else++#if MIN_VERSION_time(1,9,1)+import Data.Time.Clock+import Data.Fixed+#endif+ import Development.Shake.Internal.Errors import GHC.IO.Exception import System.IO.Error@@ -52,7 +68,7 @@     show (FileInfo x)         | x == 0 = "EQ"         | x == 1 = "NEQ"-        | otherwise = "0x" ++ map toUpper (showHex (x-2) "")+        | otherwise = "0x" ++ upper (showHex (x-2) "")  instance Eq (FileInfo a) where     FileInfo a == FileInfo b@@ -73,7 +89,7 @@         go h ptr salt = do             n <- hGetBufSome h ptr LBS.defaultChunkSize             if n == 0 then-                return $! fileInfo $ fromIntegral salt+                pure $! fileInfo $ fromIntegral salt             else                 go h ptr =<< hashPtrWithSalt ptr n salt @@ -87,14 +103,15 @@ result x y = do     x <- evaluate $ fileInfo x     y <- evaluate $ fileInfo y-    return $ Just (x, y)+    pure $ Just (x, y)  -getFileInfo :: FileName -> IO (Maybe (ModTime, FileSize))+-- | True = allow directory, False = disallow+getFileInfo :: Bool -> FileName -> IO (Maybe (ModTime, FileSize))  #if defined(PORTABLE) -- Portable fallback-getFileInfo x = handleBool isDoesNotExistError (const $ return Nothing) $ do+getFileInfo allowDir x = handleBool isDoesNotExistError (const $ pure Nothing) $ do     let file = fileNameToString x     time <- getModificationTime file     size <- withFile file ReadMode hFileSize@@ -106,12 +123,12 @@  #elif defined(mingw32_HOST_OS) -- Directly against the Win32 API, twice as fast as the portable version-getFileInfo x = BS.useAsCString (fileNameToByteString x) $ \file ->+getFileInfo allowDir x = BS.useAsCString (fileNameToByteString x) $ \file ->     alloca_WIN32_FILE_ATTRIBUTE_DATA $ \fad -> do         res <- c_GetFileAttributesExA file 0 fad         let peek = do                 code <- peekFileAttributes fad-                if testBit code 4 then+                if not allowDir && testBit code 4 then                     throwIO $ errorDirectoryNotFile $ fileNameToString x                  else                     join $ liftM2 result (peekLastWriteTimeLow fad) (peekFileSizeLow fad)@@ -119,9 +136,9 @@             peek          else if BS.any (>= chr 0x80) (fileNameToByteString x) then withCWString (fileNameToString x) $ \file -> do             res <- c_GetFileAttributesExW file 0 fad-            if res then peek else return Nothing+            if res then peek else pure Nothing          else-            return Nothing+            pure Nothing  #ifdef x86_64_HOST_ARCH #define CALLCONV ccall@@ -153,9 +170,9 @@  #else -- Unix version-getFileInfo x = handleBool isDoesNotExistError' (const $ return Nothing) $ do+getFileInfo allowDir x = handleBool isDoesNotExistError' (const $ pure Nothing) $ do     s <- getFileStatus $ fileNameToByteString x-    if isDirectory s then+    if not allowDir && isDirectory s then         throwM $ errorDirectoryNotFile $ fileNameToString x      else         result (extractFileTime s) (fromIntegral $ fileSize s)@@ -164,11 +181,12 @@             isDoesNotExistError e || ioeGetErrorType e == InappropriateType  extractFileTime :: FileStatus -> Word32-#ifndef MIN_VERSION_unix-#define MIN_VERSION_unix(a,b,c) 0-#endif #if MIN_VERSION_unix(2,6,0)-extractFileTime x = ceiling $ modificationTimeHiRes x * 1e4 -- precision of 0.1ms+#if MIN_VERSION_time(1,9,1)+extractFileTime = fromInteger . (\(MkFixed x) -> x) . nominalDiffTimeToSeconds . modificationTimeHiRes+#else+extractFileTime x = ceiling $ modificationTimeHiRes x * 1e4+#endif #else extractFileTime x = fromIntegral $ fromEnum $ modificationTime x #endif
src/Development/Shake/Internal/FilePattern.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE PatternGuards, ViewPatterns, TupleSections #-}  module Development.Shake.Internal.FilePattern(@@ -84,7 +85,7 @@     where         -- str = I have ever seen a Str go past (equivalent to "can I be satisfied by no paths")         -- slash = I am either at the start, or my previous character was Slash-        f str slash = \x -> case x of+        f str slash = \case             [] -> [Lit "" | slash]             Str "**":xs -> Skip : f True False xs             Str x:xs -> parseLit x : f True False xs
src/Development/Shake/Internal/History/Cloud.hs view
@@ -36,13 +36,13 @@     forkFinally (timeout maxTime act) $ \res -> relock $ signalFence fence $ case res of         Right (Just v) -> v         _ -> def-    return fence+    pure fence  laterFence :: MonadIO m => Fence m a -> Wait m a laterFence fence = do     res <- liftIO $ testFence fence     case res of-        Just v -> return v+        Just v -> pure v         Nothing -> Later $ waitFence fence  @@ -52,8 +52,8 @@     server <- newServer conn binop globalVer     fence <- newLaterFence relock 10 Map.empty $ do         xs <- serverAllKeys server ruleVer-        return $ Map.fromList [(k,(v,ds,test)) | (k,v,ds,test) <- xs]-    return $ Cloud server relock fence+        pure $ Map.fromList [(k,(v,ds,test)) | (k,v,ds,test) <- xs]+    pure $ Cloud server relock fence   addCloud :: Cloud -> Key -> Ver -> Ver -> [[(Key, BS_Identity)]] -> BS_Store -> [FilePath] -> IO ()@@ -63,7 +63,7 @@ lookupCloud :: Cloud -> (Key -> Wait Locked (Maybe BS_Identity)) -> Key -> Ver -> Ver -> Wait Locked (Maybe (BS_Store, [[Key]], IO ())) lookupCloud (Cloud server relock initial) ask key builtinVer userVer = runMaybeT $ do     mp <- lift $ laterFence initial-    Just (ver, deps, bloom) <- return $ Map.lookup key mp+    Just (ver, deps, bloom)<- pure $ Map.lookup key mp     unless (ver == userVer) $ fail ""     Right vs <- lift $ firstLeftWaitUnordered (fmap (maybeToEither ()) . ask) deps     unless (bloomTest bloom vs) $ fail ""@@ -72,8 +72,8 @@     f [deps] tree     where         f :: [[Key]] -> BuildTree Key -> MaybeT (Wait Locked) (BS_Store, [[Key]], IO ())-        f ks (Done store xs) = return (store, reverse ks, serverDownloadFiles server key xs)+        f ks (Done store xs) = pure (store, reverse ks, serverDownloadFiles server key xs)         f ks (Depend deps trees) = do             Right vs <- lift $ firstLeftWaitUnordered (fmap (maybeToEither ()) . ask) deps-            Just tree <- return $ lookup vs trees+            Just tree<- pure $ lookup vs trees             f (deps:ks) tree
src/Development/Shake/Internal/History/Network.hs view
@@ -28,7 +28,7 @@  #else -connect x = Just $ return $ Conn $ x ++ ['/' | not $ "/" `isSuffixOf` x]+connect x = Just $ pure $ Conn $ x ++ ['/' | not $ "/" `isSuffixOf` x]  post (Conn prefix) url send = do     let request = Request@@ -40,7 +40,7 @@     case response of         Left e -> fail $ "Network.post, failed: " ++ show e         Right v | rspCode v /= (2,0,0) -> fail $ "Network.post, failed: " ++ show (rspCode v)-                | otherwise -> return $ rspBody v+                | otherwise -> pure $ rspBody v   parseURI_ :: String -> URI
src/Development/Shake/Internal/History/Serialise.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE FlexibleInstances, DeriveFunctor, DeriveFoldable, DeriveTraversable #-}+{-# LANGUAGE FlexibleInstances, DeriveTraversable #-}  -- | The endpoints on the cloud server module Development.Shake.Internal.History.Serialise(
src/Development/Shake/Internal/History/Server.hs view
@@ -24,16 +24,16 @@ data Server = Server Conn (Map.HashMap TypeRep (BinaryOp Key)) Ver  newServer :: Conn -> Map.HashMap TypeRep (BinaryOp Key) -> Ver -> IO Server-newServer a b c = return $ Server a b c+newServer a b c = pure $ Server a b c  serverAllKeys :: Server -> [(TypeRep, Ver)] -> IO [(Key, Ver, [Key], Bloom [BS_Identity])] serverAllKeys (Server conn key ver) typs = do     res <- post conn "allkeys/v1" $ LBS.fromChunks [runBuilder $ putEx $ withTypeReps $ SendAllKeys ver typs]     let RecvAllKeys ans = withoutKeys key $ getEx $ BS.concat $ LBS.toChunks res-    return ans+    pure ans  serverOneKey :: Server -> Key -> Ver -> Ver -> [(Key, BS_Identity)] -> IO (BuildTree Key)-serverOneKey _ _ _ _ _ = return $ Depend [] []+serverOneKey _ _ _ _ _ = pure $ Depend [] []   serverDownloadFiles :: Server -> Key -> [(FilePath, FileSize, FileHash)] -> IO ()
src/Development/Shake/Internal/History/Shared.hs view
@@ -39,7 +39,7 @@     }  newShared :: Bool -> BinaryOp Key -> Ver -> FilePath -> IO Shared-newShared useSymlink keyOp globalVersion sharedRoot = return Shared{..}+newShared useSymlink keyOp globalVersion sharedRoot = pure Shared{..}   data Entry = Entry@@ -94,7 +94,7 @@ sharedFileKeys :: FilePath -> IO [FilePath] sharedFileKeys dir = do     b <- doesDirectoryExist_ $ dir </> "_key"-    if not b then return [] else listFiles $ dir </> "_key"+    if not b then pure [] else listFiles $ dir </> "_key"  loadSharedEntry :: Shared -> Key -> Ver -> Ver -> IO [IO (Maybe Entry)] loadSharedEntry shared@Shared{..} key builtinVersion userVersion =@@ -103,7 +103,7 @@         f file = do             e@Entry{..} <- getEntry keyOp <$> BS.readFile file             let valid = entryKey == key && entryGlobalVersion == globalVersion && entryBuiltinVersion == builtinVersion && entryUserVersion == userVersion-            return $ if valid then Just e else Nothing+            pure $ if valid then Just e else Nothing   -- | Given a way to get the identity, see if you can find a stored cloud version@@ -113,7 +113,7 @@     flip firstJustWaitUnordered ents $ \act -> do         me <- liftIO act         case me of-            Nothing -> return Nothing+            Nothing -> pure Nothing             Just Entry{..} -> do                 -- use Nothing to indicate success, Just () to bail out early on mismatch                 let result x = if isJust x then Nothing else Just $ (entryResult, map (map fst) entryDepends, ) $ do@@ -151,10 +151,10 @@     deleted <- forM dirs $ \dir -> do         files <- sharedFileKeys dir         -- if any key matches, clean them all out-        b <- flip anyM files $ \file -> handleSynchronous (\e -> putStrLn ("Warning: " ++ show e) >> return False) $+        b <- flip anyM files $ \file -> handleSynchronous (\e -> putStrLn ("Warning: " ++ show e) >> pure False) $             evaluate . test . entryKey . getEntry keyOp =<< BS.readFile file         when b $ removePathForcibly dir-        return b+        pure b     liftIO $ putStrLn $ "Deleted " ++ show (length (filter id deleted)) ++ " entries"  listShared :: Shared -> IO ()
src/Development/Shake/Internal/History/Symlink.hs view
@@ -32,11 +32,11 @@  createLinkMaybe from to = withCWString from $ \cfrom -> withCWString to $ \cto -> do     res <- c_CreateHardLinkW cto cfrom nullPtr-    return $ if res then Nothing else Just "CreateHardLink failed."+    pure $ if res then Nothing else Just "CreateHardLink failed."  #else -createLinkMaybe from to = handleIO (return . Just . show) $ createLink from to >> return Nothing+createLinkMaybe from to = handleIO (pure . Just . show) $ createLink from to >> pure Nothing  #endif 
src/Development/Shake/Internal/Options.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP, DeriveDataTypeable, PatternGuards #-}+{-# LANGUAGE DeriveDataTypeable, PatternGuards #-}  -- | Types exposed to the user module Development.Shake.Internal.Options(@@ -210,6 +210,9 @@         --   If this setting is @True@ (even if symlinks are not available) then files will be         --   made read-only to avoid inadvertantly poisoning the shared cache.         --   Note the links are actually hard links, not symlinks.+    ,shakeNeedDirectory :: Bool+        -- ^ Defaults to @False@. Is depending on a directory an error (default), or it is permitted with+        --   undefined results. Provided for compatibility with @ninja@.     ,shakeProgress :: IO Progress -> IO ()         -- ^ Defaults to no action. A function called when the build starts, allowing progress to be reported.         --   The function is called on a separate thread, and that thread is killed when the build completes.@@ -234,10 +237,10 @@ shakeOptions :: ShakeOptions shakeOptions = ShakeOptions     ".shake" 1 "1" Info False [] Nothing [] [] [] [] (Just 10) [] [] False True False-    True ChangeModtime True [] False False Nothing [] False-    (const $ return ())+    True ChangeModtime True [] False False Nothing [] False False+    (const $ pure ())     (const $ BS.putStrLn . UTF8.fromString) -- try and output atomically using BS-    (\_ _ _ -> return ())+    (\_ _ _ -> pure ())     Map.empty  fieldsShakeOptions =@@ -246,19 +249,20 @@     ,"shakeFlush", "shakeRebuild", "shakeAbbreviations", "shakeStorageLog"     ,"shakeLineBuffering", "shakeTimings", "shakeRunCommands", "shakeChange", "shakeCreationCheck"     ,"shakeLiveFiles", "shakeVersionIgnore", "shakeColor", "shakeShare", "shakeCloud", "shakeSymlink"+    ,"shakeNeedDirectory"     ,"shakeProgress", "shakeOutput", "shakeTrace", "shakeExtra"] tyShakeOptions = mkDataType "Development.Shake.Types.ShakeOptions" [conShakeOptions] conShakeOptions = mkConstr tyShakeOptions "ShakeOptions" fieldsShakeOptions Prefix-unhide x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13 x14 x15 x16 x17 x18 x19 x20 x21 x22 x23 x24 x25 x26 y1 y2 y3 y4 =-    ShakeOptions x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13 x14 x15 x16 x17 x18 x19 x20 x21 x22 x23 x24 x25 x26+unhide x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13 x14 x15 x16 x17 x18 x19 x20 x21 x22 x23 x24 x25 x26 x27 y1 y2 y3 y4 =+    ShakeOptions x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13 x14 x15 x16 x17 x18 x19 x20 x21 x22 x23 x24 x25 x26 x27         (fromHidden y1) (fromHidden y2) (fromHidden y3) (fromHidden y4)  instance Data ShakeOptions where-    gfoldl k z (ShakeOptions x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13 x14 x15 x16 x17 x18 x19 x20 x21 x22 x23 x24 x25 x26 y1 y2 y3 y4) =+    gfoldl k z (ShakeOptions x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13 x14 x15 x16 x17 x18 x19 x20 x21 x22 x23 x24 x25 x26 x27 y1 y2 y3 y4) =         z unhide `k` x1 `k` x2 `k` x3 `k` x4 `k` x5 `k` x6 `k` x7 `k` x8 `k` x9 `k` x10 `k` x11 `k`-        x12 `k` x13 `k` x14 `k` x15 `k` x16 `k` x17 `k` x18 `k` x19 `k` x20 `k` x21 `k` x22 `k` x23 `k` x24 `k` x25 `k` x26 `k`+        x12 `k` x13 `k` x14 `k` x15 `k` x16 `k` x17 `k` x18 `k` x19 `k` x20 `k` x21 `k` x22 `k` x23 `k` x24 `k` x25 `k` x26 `k` x27 `k`         Hidden y1 `k` Hidden y2 `k` Hidden y3 `k` Hidden y4-    gunfold k z _ = k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ z unhide+    gunfold k z _ = k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ k $ z unhide     toConstr ShakeOptions{} = conShakeOptions     dataTypeOf _ = tyShakeOptions 
src/Development/Shake/Internal/Paths.hs view
@@ -36,7 +36,7 @@ #ifdef FILE_EMBED  initDataDirectory :: IO ()-initDataDirectory = return ()+initDataDirectory = pure ()  htmlDataFiles :: [(FilePath, BS.ByteString)] htmlDataFiles =@@ -49,13 +49,13 @@ readDataFileHTML file = do     case lookup file htmlDataFiles of       Nothing -> fail $ "Could not find data file " ++ file ++ " in embedded data files!"-      Just x  -> return (LBS.fromStrict x)+      Just x  -> pure (LBS.fromStrict x)  manualDirData :: [(FilePath, BS.ByteString)] manualDirData = $(embedDir "docs/manual")  hasManualData :: IO Bool-hasManualData = return True+hasManualData = pure True  copyManualData :: FilePath -> IO () copyManualData dest = do@@ -70,9 +70,9 @@ dataDirs :: [String] dataDirs = unsafePerformIO $ do     datdir <- getDataDir-    exedir <- takeDirectory <$> getExecutablePath `catchIO` \_ -> return ""+    exedir <- takeDirectory <$> getExecutablePath `catchIO` \_ -> pure ""     curdir <- getCurrentDirectory-    return $ [datdir] ++ [exedir | exedir /= ""] ++ [curdir]+    pure $ [datdir] ++ [exedir | exedir /= ""] ++ [curdir]  -- The data files may be located relative to the current directory, if so cache it in advance initDataDirectory :: IO ()@@ -84,7 +84,7 @@     res <- filterM doesFileExist_ poss     case res of         [] -> fail $ unlines $ ("Could not find data file " ++ file ++ ", looked in:") : map ("  " ++) poss-        x:_ -> return x+        x:_ -> pure x  hasDataFile :: FilePath -> IO Bool hasDataFile file = anyM (\dir -> doesFileExist_ $ dir </> file) dataDirs
src/Development/Shake/Internal/Profile.hs view
@@ -85,7 +85,7 @@             }             where fromStep i = fromJust $ Map.lookup i steps                   fromTrace (Trace a b c) = ProfileTrace (BS.unpack a) (floatToDouble b) (floatToDouble c)-    return [maybe (throwImpure $ errorInternal "toReport") f $ Map.lookup i status | i <- order]+    pure [maybe (throwImpure $ errorInternal "toReport") f $ Map.lookup i status | i <- order]   data ProfileEntry = ProfileEntry@@ -131,7 +131,7 @@ generateHTML :: [ProfileEntry] -> IO LBS.ByteString generateHTML xs = do     report <- readDataFileHTML "profile.html"-    let f "data/profile-data.js" = return $ LBS.pack $ "var profile =\n" ++ generateJSON xs+    let f "data/profile-data.js" = pure $ LBS.pack $ "var profile =\n" ++ generateJSON xs     runTemplate f report  
src/Development/Shake/Internal/Progress.hs view
@@ -53,7 +53,7 @@ progress :: Database -> Step -> IO Progress progress db step = do     xs <- getKeyValues db-    return $! foldl' f mempty $ map snd xs+    pure $! foldl' f mempty $ map snd xs     where         g = floatToDouble @@ -217,7 +217,7 @@             sleep sample             p <- prog             t <- time-            ((secs,perc,_debug), mealy) <- return $ runMealy mealy (t, p)+            ((secs,perc,_debug), mealy)<- pure $ runMealy mealy (t, p)             -- putStrLn _debug             let done = countSkipped p + countBuilt p             let todo = done + countUnknown p + countTodo p@@ -270,7 +270,7 @@ generateHTML :: [(FilePath, [ProgressEntry])] -> IO LBS.ByteString generateHTML xs = do     report <- readDataFileHTML "progress.html"-    let f "data/progress-data.js" = return $ LBS.pack $ "var progress =\n" ++ generateJSON xs+    let f "data/progress-data.js" = pure $ LBS.pack $ "var progress =\n" ++ generateJSON xs     runTemplate f report  generateJSON :: [(FilePath, [ProgressEntry])] -> String@@ -299,7 +299,7 @@ #ifdef mingw32_HOST_OS         win = withCWString x c_setConsoleTitleW #else-        win = return False+        win = pure False #endif          lin = whenM checkEscCodes $ BS.putStr $ BS.pack $ escWindowTitle x@@ -323,10 +323,10 @@ progressProgram = do     exe <- findExecutable "shake-progress"     case exe of-        Nothing -> return $ const $ return ()+        Nothing -> pure $ const $ pure ()         Just exe -> do             lastArgs <- newIORef Nothing -- the arguments we passed to shake-progress last time-            return $ \msg -> do+            pure $ \msg -> do                 let failure = " Failure! " `isInfixOf` msg                 let perc = let (a,b) = break (== '%') msg                            in if null b then "" else reverse $ takeWhile isDigit $ reverse a
src/Development/Shake/Internal/Resource.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE RecordWildCards, ViewPatterns #-}  module Development.Shake.Internal.Resource(@@ -26,7 +27,7 @@ resourceId :: IO Int resourceId = unsafePerformIO $ do     ref <- newIORef 0-    return $ atomicModifyIORef' ref $ \i -> let j = i + 1 in (j, j)+    pure $ atomicModifyIORef' ref $ \i -> let j = i + 1 in (j, j)   -- | Run an action which uses part of a finite resource. For more details see 'Resource'.@@ -34,17 +35,17 @@ withResource :: Resource -> Int -> Action a -> Action a withResource r i act = do     Global{..} <- Action getRO-    liftIO $ globalDiagnostic $ return $ show r ++ " waiting to acquire " ++ show i+    liftIO $ globalDiagnostic $ pure $ show r ++ " waiting to acquire " ++ show i      fence <- liftIO $ acquireResource r globalPool i     whenJust fence $ \fence -> do         (offset, ()) <- actionFenceRequeueBy Right fence         Action $ modifyRW $ addDiscount offset -    liftIO $ globalDiagnostic $ return $ show r ++ " running with " ++ show i+    liftIO $ globalDiagnostic $ pure $ show r ++ " running with " ++ show i     Action $ fromAction (blockApply ("Within withResource using " ++ show r) act) `finallyRAW` do         liftIO $ releaseResource r globalPool i-        liftIO $ globalDiagnostic $ return $ show r ++ " released " ++ show i+        liftIO $ globalDiagnostic $ pure $ show r ++ " released " ++ show i   @@ -98,7 +99,7 @@         errorIO $ "You cannot create a resource named " ++ name ++ " with a negative quantity, you used " ++ show mx     key <- resourceId     var <- newVar $ Finite mx mempty-    return $ Resource (negate key) shw (acquire var) (release var)+    pure $ Resource (negate key) shw (acquire var) (release var)     where         shw = "Resource " ++ name @@ -108,18 +109,18 @@             | want > mx = errorIO $ "You cannot acquire more than " ++ show mx ++ " of " ++ shw ++ ", requested " ++ show want             | otherwise = modifyVar var $ \x@Finite{..} ->                 if want <= finiteAvailable then-                    return (x{finiteAvailable = finiteAvailable - want}, Nothing)+                    pure (x{finiteAvailable = finiteAvailable - want}, Nothing)                 else do                     fence <- newFence-                    return (x{finiteWaiting = finiteWaiting `snoc` (want, fence)}, Just fence)+                    pure (x{finiteWaiting = finiteWaiting `snoc` (want, fence)}, Just fence)          release :: Var Finite -> Pool -> Int -> IO ()-        release var _ i = join $ modifyVar var $ \x -> return $ f x{finiteAvailable = finiteAvailable x + i}+        release var _ i = join $ modifyVar var $ \x -> pure $ f x{finiteAvailable = finiteAvailable x + i}             where                 f (Finite i (uncons -> Just ((wi,wa),ws)))                     | wi <= i = second (signalFence wa () >>) $ f $ Finite (i-wi) ws                     | otherwise = first (add (wi,wa)) $ f $ Finite i ws-                f (Finite i _) = (Finite i mempty, return ())+                f (Finite i _) = (Finite i mempty, pure ())                 add a s = s{finiteWaiting = a `cons` finiteWaiting s}  @@ -149,7 +150,7 @@         errorIO $ "You cannot create a throttle named " ++ name ++ " with a negative quantity, you used " ++ show count     key <- resourceId     var <- newVar $ ThrottleAvailable count-    return $ Resource key shw (acquire var) (release var)+    pure $ Resource key shw (acquire var) (release var)     where         shw = "Throttle " ++ name @@ -157,23 +158,23 @@         acquire var pool want             | want < 0 = errorIO $ "You cannot acquire a negative quantity of " ++ shw ++ ", requested " ++ show want             | want > count = errorIO $ "You cannot acquire more than " ++ show count ++ " of " ++ shw ++ ", requested " ++ show want-            | otherwise = modifyVar var $ \x -> case x of+            | otherwise = modifyVar var $ \case                 ThrottleAvailable i-                    | i >= want -> return (ThrottleAvailable $ i - want, Nothing)+                    | i >= want -> pure (ThrottleAvailable $ i - want, Nothing)                     | otherwise -> do                         stop <- keepAlivePool pool                         fence <- newFence-                        return (ThrottleWaiting stop $ (want - i, fence) `cons` mempty, Just fence)+                        pure (ThrottleWaiting stop $ (want - i, fence) `cons` mempty, Just fence)                 ThrottleWaiting stop xs -> do                     fence <- newFence-                    return (ThrottleWaiting stop $ xs `snoc` (want, fence), Just fence)+                    pure (ThrottleWaiting stop $ xs `snoc` (want, fence), Just fence)          release :: Var Throttle -> Pool -> Int -> IO ()-        release var _ n = waiter period $ join $ modifyVar var $ \x -> return $ case x of-                ThrottleAvailable i -> (ThrottleAvailable $ i+n, return ())+        release var _ n = waiter period $ join $ modifyVar var $ \x -> pure $ case x of+                ThrottleAvailable i -> (ThrottleAvailable $ i+n, pure ())                 ThrottleWaiting stop xs -> f stop n xs             where                 f stop i (uncons -> Just ((wi,wa),ws))                     | i >= wi = second (signalFence wa () >>) $ f stop (i-wi) ws-                    | otherwise = (ThrottleWaiting stop $ (wi-i,wa) `cons` ws, return ())+                    | otherwise = (ThrottleWaiting stop $ (wi-i,wa) `cons` ws, pure ())                 f stop i _ = (ThrottleAvailable i, stop)
src/Development/Shake/Internal/Rules/Directory.hs view
@@ -121,12 +121,12 @@ queryRule witness query = addBuiltinRuleEx     (\k old -> do         new <- query k-        return $ if old == new then Nothing else Just $ show new)+        pure $ if old == new then Nothing else Just $ show new)     (\_ v -> Just $ runBuilder $ putEx $ witness v)     (\k old _ -> liftIO $ do         new <- query k         let wnew = witness new-        return $ case old of+        pure $ case old of             Just old | wnew == getEx old -> RunResult ChangedNothing old new             _ -> RunResult ChangedRecomputeDiff (runBuilder $ putEx wnew) new) @@ -276,7 +276,7 @@         f dir (WalkTo (files, dirs)) = do             files <- filterM (IO.doesFileExist . (root </>)) $ map (dir </>) files             dirs <- concatMapM (uncurry f) =<< filterM (IO.doesDirectoryExist . (root </>) . fst) (map (first (dir </>)) dirs)-            return $ files ++ dirs+            pure $ files ++ dirs   ---------------------------------------------------------------------
src/Development/Shake/Internal/Rules/File.hs view
@@ -146,14 +146,14 @@       deriving (Eq,Ord,Show,Read,Typeable,Enum,Bounded)  fileStoredValue :: ShakeOptions -> FileQ -> IO (Maybe FileA)-fileStoredValue ShakeOptions{shakeChange=c} (FileQ x) = do-    res <- getFileInfo x+fileStoredValue ShakeOptions{shakeChange=c, shakeNeedDirectory=allowDir} (FileQ x) = do+    res <- getFileInfo allowDir x     case res of-        Nothing -> return Nothing-        Just (time,size) | c == ChangeModtime -> return $ Just $ FileA time size noFileHash+        Nothing -> pure Nothing+        Just (time,size) | c == ChangeModtime -> pure $ Just $ FileA time size noFileHash         Just (time,size) -> do             hash <- unsafeInterleaveIO $ getFileHash x-            return $ Just $ FileA time size hash+            pure $ Just $ FileA time size hash   fileEqualValue :: ShakeOptions -> FileA -> FileA -> EqualCost@@ -173,7 +173,7 @@ storedValueError opts False msg x | False && not (shakeOutputCheck opts) = do     when (shakeCreationCheck opts) $ do         whenM (isNothing <$> (storedValue opts x :: IO (Maybe FileA))) $ error $ msg ++ "\n  " ++ unpackU (fromFileQ x)-    return $ FileA fileInfoEq fileInfoEq fileInfoEq+    pure $ FileA fileInfoEq fileInfoEq fileInfoEq -} storedValueError opts input msg x = maybe def Just <$> fileStoredValue opts2 x     where def = if shakeCreationCheck opts || input then error err else Nothing@@ -193,11 +193,11 @@ ruleLint :: ShakeOptions -> BuiltinLint FileQ FileR ruleLint opts k (FileR (Just v) True) = do     now <- fileStoredValue opts k-    return $ case now of+    pure $ case now of         Nothing -> Just "<missing>"         Just now | fileEqualValue opts v now == EqualCheap -> Nothing                  | otherwise -> Just $ show now-ruleLint _ _ _ = return Nothing+ruleLint _ _ _ = pure Nothing  ruleIdentity :: ShakeOptions -> BuiltinIdentity FileQ FileR ruleIdentity opts | shakeChange opts == ChangeModtime = throwImpure errorNoHash@@ -268,10 +268,10 @@         unLint (RunResult a b c) = RunResult a b c{useLint = False}          retNew :: RunChanged -> Answer -> Action (RunResult FileR)-        retNew c v = return $ RunResult c (runBuilder $ putEx v) $ fileR v+        retNew c v = pure $ RunResult c (runBuilder $ putEx v) $ fileR v          retOld :: RunChanged -> Action (RunResult FileR)-        retOld c = return $ RunResult c (fromJust oldBin) $ fileR (fromJust old)+        retOld c = pure $ RunResult c (fromJust oldBin) $ fileR (fromJust old)          -- actually run the rebuild         rebuildWith act = do@@ -315,7 +315,7 @@                                     res <- answer (AnswerDirect $ Ver ver) new                                     historySave ver $ runBuilder $                                         if isNoFileHash fileHash then throwImpure errorNoHash else putExStorable fileHash-                                    return res+                                    pure res                 Just (_, ModePhony act) -> do                     -- See #523 and #524                     -- Shake runs the dependencies first, but stops when one has changed.@@ -338,16 +338,16 @@ resultHasChanged file = do     let filename = FileQ $ fileNameFromString file     res <- getDatabaseValue filename-    old <- return $ case result <$> res of+    old<- pure $ case result <$> res of         Nothing -> Nothing         Just (Left bs) -> fromAnswer $ getEx bs         Just (Right v) -> answer v     case old of-        Nothing -> return True+        Nothing -> pure True         Just old -> do             opts <- getShakeOptions             new <- liftIO $ fileStoredValue opts filename-            return $ case new of+            pure $ case new of                 Nothing -> True                 Just new -> fileEqualValue opts old new == NotEqual @@ -403,13 +403,13 @@     apply_ fileNameFromString paths     self <- getCurrentKey     selfVal <- case self of-        Nothing -> return Nothing+        Nothing -> pure Nothing         Just self -> getDatabaseValueGeneric self     case selfVal of-        Nothing -> return paths -- never build before or not a key, so everything has changed+        Nothing -> pure paths -- never build before or not a key, so everything has changed         Just selfVal -> flip filterM paths $ \path -> do             pathVal <- getDatabaseValue (FileQ $ fileNameFromString path)-            return $ case pathVal of+            pure $ case pathVal of                 Just pathVal | changed pathVal > built selfVal -> True                 _ -> False @@ -439,7 +439,7 @@     let bad = [ (x, if isJust a then "File change" else "File created")               | (x, a, FileR (Just b) _) <- zip3 xs pre post, maybe NotEqual (\a -> fileEqualValue opts a b) a == NotEqual]     case bad of-        [] -> return ()+        [] -> pure ()         (file,msg):_ -> throwM $ errorStructured             "Lint checking error - 'needed' file required rebuilding"             [("File", Just $ fileNameToString file)@@ -502,7 +502,7 @@ --   This function is defined in terms of 'action' and 'need', use 'action' if you need more complex --   targets than 'want' allows. want :: Partial => [FilePath] -> Rules ()-want [] = return ()+want [] = pure () want xs = withFrozenCallStack $ action $ need xs  @@ -574,7 +574,7 @@     mapM_ addTarget pats     let (simp,other) = partition simple pats     case map toStandard simp of-        [] -> return ()+        [] -> pure ()         [p] -> root help (\x -> toStandard x == p) act         ps -> let set = Set.fromList ps in root help (flip Set.member set . toStandard) act     unless (null other) $
src/Development/Shake/Internal/Rules/Files.hs view
@@ -73,10 +73,10 @@     addBuiltinRuleEx (ruleLint opts) (ruleIdentity opts) (ruleRun opts $ shakeRebuildApply opts)  ruleLint :: ShakeOptions -> BuiltinLint FilesQ FilesA-ruleLint _ _ (FilesA []) = return Nothing -- in the case of disabling lint+ruleLint _ _ (FilesA []) = pure Nothing -- in the case of disabling lint ruleLint opts k v = do     now <- filesStoredValue opts k-    return $ case now of+    pure $ case now of         Nothing -> Just "<missing>"         Just now | filesEqualValue opts v now == EqualCheap -> Nothing                  | otherwise -> Just $ show now@@ -107,20 +107,20 @@             Just _ ->                 -- ignoring the currently stored value, which may trigger lint has changed                 -- so disable lint on this file-                return $ RunResult ChangedNothing (fromJust o) $ FilesA []+                pure $ RunResult ChangedNothing (fromJust o) $ FilesA []             Nothing -> do                 -- i don't have a previous value, so assume this is a source node, and mark rebuild in future                 now <- liftIO $ filesStoredValue opts k                 case now of                     Nothing -> rebuild-                    Just now -> do alwaysRerun; return $ RunResult ChangedStore (runBuilder $ putEx $ Result (Ver 0) now) now+                    Just now -> do alwaysRerun; pure $ RunResult ChangedStore (runBuilder $ putEx $ Result (Ver 0) now) now         Just (Result ver old) | mode == RunDependenciesSame, verEq ver -> do             v <- liftIO $ filesStoredValue opts k             case v of                 Just v -> case filesEqualValue opts old v of                     NotEqual -> rebuild-                    EqualCheap -> return $ RunResult ChangedNothing (fromJust o) v-                    EqualExpensive -> return $ RunResult ChangedStore (runBuilder $ putEx $ Result ver v) v+                    EqualCheap -> pure $ RunResult ChangedNothing (fromJust o) v+                    EqualExpensive -> pure $ RunResult ChangedStore (runBuilder $ putEx $ Result ver v) v                 Nothing -> rebuild         _ -> rebuild     where@@ -130,16 +130,16 @@                 Just res ->                     fmap FilesA $ forM (zipExact (getExList res) (fromFilesQ k)) $ \(bin, file) -> do                         Just (FileA mod size _) <- liftIO $ fileStoredValue opts file-                        return $ FileA mod size $ getExStorable bin+                        pure $ FileA mod size $ getExStorable bin                 Nothing -> do                     FilesA v <- act                     producesUnchecked $ map (fileNameToString . fromFileQ) $ fromFilesQ k                     historySave ver $ runBuilder $ putExList                         [if isNoFileHash hash then throwImpure errorNoHash else putExStorable hash | FileA _ _ hash <- v]-                    return $ FilesA v+                    pure $ FilesA v             let c | Just (Result _ old) <- old, filesEqualValue opts old v /= NotEqual = ChangedRecomputeSame                   | otherwise = ChangedRecomputeDiff-            return $ RunResult c (runBuilder $ putEx $ Result (Ver ver) v) v+            pure $ RunResult c (runBuilder $ putEx $ Result (Ver ver) v) v   @@ -159,7 +159,7 @@ --   have the same sequence of @\/\/@ and @*@ wildcards in the same order. --   This function will create directories for the result files, if necessary. (&%>) :: Located => [FilePattern] -> ([FilePath] -> Action ()) -> Rules ()-[p] &%> act = withFrozenCallStack $ p %> act . return+[p] &%> act = withFrozenCallStack $ p %> act . pure ps &%> act     | not $ compatible ps = error $ unlines $         "All patterns to &%> must have the same number and position of ** and * wildcards" :@@ -169,7 +169,7 @@             (if simple p then id else priority 0.5) $                 fileForward (show ps ++ " &%> at " ++ callStackTop) $ let op = (p ?==) in \file -> if not $ op file then Nothing else Just $ do                     FilesA res <- apply1 $ FilesQ $ map (FileQ . fileNameFromString . substitute (extract p file)) ps-                    return $ if null res then Nothing else Just $ res !! i+                    pure $ if null res then Nothing else Just $ res !! i         (if all simple ps then id else priority 0.5) $ do             mapM_ addTarget ps             addUserRule $ FilesRule (show ps ++ " &%> " ++ callStackTop) $ \(FilesQ xs_) -> let xs = map (fileNameToString . fromFileQ) xs_ in@@ -208,7 +208,7 @@     let checkedTest x = case normTest x of             Nothing -> Nothing             Just ys | x `notElem` ys -> error $ unlines $-                "Invariant broken in &?>, did not return the input (after normalisation)." :+                "Invariant broken in &?>, did not pure the input (after normalisation)." :                 inputOutput "" x ys             Just ys | bad:_ <- filter ((/= Just ys) . normTest) ys -> error $ unlines $                 ["Invariant broken in &?>, not equalValue for all arguments (after normalisation)."] ++@@ -220,7 +220,7 @@         Nothing -> Nothing         Just ys -> Just $ do             FilesA res <- apply1 $ FilesQ $ map (FileQ . fileNameFromString) ys-            return $ if null res then Nothing else Just $ res !! fromJust (elemIndex x ys)+            pure $ if null res then Nothing else Just $ res !! fromJust (elemIndex x ys)      addUserRule $ FilesRule ("&?> " ++ callStackTop) $ \(FilesQ xs_) -> let xs@(x:_) = map (fileNameToString . fromFileQ) xs_ in         case checkedTest x of@@ -238,8 +238,8 @@     let opts2 = if shakeChange opts == ChangeModtimeAndDigestInput then opts{shakeChange=ChangeModtime} else opts     ys <- liftIO $ mapM (fileStoredValue opts2) xs     case sequence ys of-        Just ys -> return $ FilesA ys-        Nothing | not $ shakeCreationCheck opts -> return $ FilesA []+        Just ys -> pure $ FilesA ys+        Nothing | not $ shakeCreationCheck opts -> pure $ FilesA []         Nothing -> do             let missing = length $ filter isNothing ys             error $ "Error, " ++ name ++ " rule failed to produce " ++ show missing ++
src/Development/Shake/Internal/Rules/Oracle.hs view
@@ -41,28 +41,28 @@          addBuiltinRule noLint (\_ v -> Just $ runBuilder $ putEx $ hash v) $ \(OracleQ q) old mode -> case old of             Just old | (flavor /= Hash && skip) || (flavor == Cache && mode == RunDependenciesSame) ->-                return $ RunResult ChangedNothing old $ decode' old+                pure $ RunResult ChangedNothing old $ decode' old             _ -> do                 -- can only use cmpHash if flavor == Hash                 let cmpValue new = if fmap decode' old == Just new then ChangedRecomputeSame else ChangedRecomputeDiff                 let cmpHash newHash = if old == Just newHash then ChangedRecomputeSame else ChangedRecomputeDiff -                cache <- if flavor == Cache then historyLoad 0 else return Nothing+                cache <- if flavor == Cache then historyLoad 0 else pure Nothing                 case cache of                     Just newEncode -> do                         let new = decode' newEncode-                        return $ RunResult (cmpValue new) newEncode new+                        pure $ RunResult (cmpValue new) newEncode new                     Nothing -> do                         new <- OracleA <$> act q                         let newHash = encodeHash new                         let newEncode = encode' new                         when (flavor == Cache) $                             historySave 0 newEncode-                        return $+                        pure $                             if flavor == Hash                                 then RunResult (cmpHash newHash) newHash new                                 else RunResult (cmpValue new) newEncode new-        return askOracle+        pure askOracle     where         encodeHash :: Hashable a => a -> BS.ByteString         encodeHash = runBuilder . putEx . hash@@ -71,7 +71,7 @@         encode' = BS.concat . LBS.toChunks . encode          decode' :: Binary a => BS.ByteString -> a-        decode' = decode . LBS.fromChunks . return+        decode' = decode . LBS.fromChunks . pure   -- | Add extra information which rules can depend on.@@ -112,11 +112,11 @@ -- rules = do --     getPkgList \<- 'addOracle' $ \\GhcPkgList{} -> do --         Stdout out <- 'Development.Shake.cmd' \"ghc-pkg list --simple-output\"---         return [(reverse b, reverse a) | x <- words out, let (a,_:b) = break (== \'-\') $ reverse x]+--         pure [(reverse b, reverse a) | x <- words out, let (a,_:b) = break (== \'-\') $ reverse x] -- --     getPkgVersion \<- 'addOracle' $ \\(GhcPkgVersion pkg) -> do --         pkgs <- getPkgList $ GhcPkgList ()---         return $ lookup pkg pkgs+--         pure $ lookup pkg pkgs -- --     \"myrule\" %> \\_ -> do --         getPkgVersion $ GhcPkgVersion \"shake\"
src/Development/Shake/Internal/Rules/Rerun.hs view
@@ -43,4 +43,4 @@ defaultRuleRerun :: Rules () defaultRuleRerun =     addBuiltinRuleEx noLint noIdentity $-        \AlwaysRerunQ{} _ _ -> return $ RunResult ChangedRecomputeDiff BS.empty ()+        \AlwaysRerunQ{} _ _ -> pure $ RunResult ChangedRecomputeDiff BS.empty ()
src/Development/Shake/Rule.hs view
@@ -109,7 +109,7 @@ --   exercise our build system with: -- -- > example = do--- >     fileRule "a.txt" $ return ()+-- >     fileRule "a.txt" $ pure () -- >     fileRule "b.txt" $ do -- >         fileNeed "a.txt" -- >         liftIO $ writeFile "b.txt" . reverse =<< readFile "a.txt"@@ -122,18 +122,18 @@ -- > addBuiltinFileRule :: Rules () -- > addBuiltinFileRule = addBuiltinRule noLint noIdentity run -- >     where--- >         fileContents (File x) = do b <- IO.doesFileExist x; if b then IO.readFile' x else return ""+-- >         fileContents (File x) = do b <- IO.doesFileExist x; if b then IO.readFile' x else pure "" -- > -- >         run :: BuiltinRun File () -- >         run key old mode = do -- >             now <- liftIO $ fileContents key -- >             if mode == RunDependenciesSame && fmap BS.unpack old == Just now then--- >                 return $ RunResult ChangedNothing (BS.pack now) ()+-- >                 pure $ RunResult ChangedNothing (BS.pack now) () -- >             else do -- >                 (_, act) <- getUserRuleOne key (const Nothing) $ \(FileRule k act) -> if k == key then Just act else Nothing -- >                 act -- >                 now <- liftIO $ fileContents key--- >                 return $ RunResult ChangedRecomputeDiff (BS.pack now) ()+-- >                 pure $ RunResult ChangedRecomputeDiff (BS.pack now) () -- --   We define a wrapper @addBuiltinFileRule@ that calls @addBuiltinRule@, opting out of linting and cached storage. --   The only thing we provide is a 'BuiltinRun' function which gets the previous state, and whether any dependency has changed,
src/Development/Shake/Util.hs view
@@ -50,7 +50,7 @@ -- data Flags = Flags {distCC :: Bool} deriving Eq -- flags = [Option \"\" [\"distcc\"] (NoArg $ Right $ \\x -> x{distCC=True}) \"Run distributed.\"] ----- main = 'shakeArgsAccumulate' 'shakeOptions' flags (Flags False) $ \\flags targets -> return $ Just $ do+-- main = 'shakeArgsAccumulate' 'shakeOptions' flags (Flags False) $ \\flags targets -> pure $ Just $ do --     if null targets then 'want' [\"result.exe\"] else 'want' targets --     let compiler = if distCC flags then \"distcc\" else \"gcc\" --     \"*.o\" '%>' \\out -> do@@ -68,7 +68,7 @@ --   the second argument is called with a list of the files that the build checked were up-to-date. shakeArgsPrune :: ShakeOptions -> ([FilePath] -> IO ()) -> Rules () -> IO () shakeArgsPrune opts prune rules = shakeArgsPruneWith opts prune [] f-    where f _ files = return $ Just $ if null files then rules else want files >> withoutActions rules+    where f _ files = pure $ Just $ if null files then rules else want files >> withoutActions rules   -- | A version of 'shakeArgsPrune' that also takes a list of extra options to use.@@ -80,7 +80,7 @@         case sequence opts of             Nothing -> do                 writeIORef pruning True-                return Nothing+                pure Nothing             Just opts -> act opts args     whenM (readIORef pruning) $         IO.withTempFile $ \file -> do
src/General/Binary.hs view
@@ -79,7 +79,7 @@     (Builder x1 x2) <> (Builder y1 y2) = Builder (x1+y1) $ \p i -> do x2 p i; y2 p $ i+x1  instance Monoid Builder where-    mempty = Builder 0 $ \_ _ -> return ()+    mempty = Builder 0 $ \_ _ -> pure ()     mappend = (<>)  -- | Methods for Binary serialisation that go directly between strict ByteString values.@@ -97,13 +97,13 @@  instance BinaryEx LBS.ByteString where     putEx x = Builder (fromIntegral $ LBS.length x) $ \ptr i -> do-        let go _ [] = return ()+        let go _ [] = pure ()             go i (x:xs) = do                 let n = BS.length x                 BS.useAsCString x $ \bs -> BS.memcpy (ptr `plusPtr` i) (castPtr bs) (fromIntegral n)                 go (i+n) xs         go i $ LBS.toChunks x-    getEx = LBS.fromChunks . return+    getEx = LBS.fromChunks . pure  instance BinaryEx [BS.ByteString] where     -- Format:@@ -113,7 +113,7 @@     putEx xs = Builder (4 + (n * 4) + sum ns) $ \p i -> do         pokeByteOff p i (fromIntegral n :: Word32)         for2M_ [4+i,8+i..] ns $ \i x -> pokeByteOff p i (fromIntegral x :: Word32)-        p <- return $ p `plusPtr` (i + 4 + (n * 4))+        p<- pure $ p `plusPtr` (i + 4 + (n * 4))         for2M_ (scanl (+) 0 ns) xs $ \i x -> BS.useAsCStringLen x $ \(bs, n) ->             BS.memcpy (p `plusPtr` i) (castPtr bs) (fromIntegral n)         where ns = map BS.length xs@@ -122,7 +122,7 @@     getEx bs = unsafePerformIO $ BS.useAsCString bs $ \p -> do         n <- fromIntegral <$> (peekByteOff p 0 :: IO Word32)         ns :: [Word32] <- forM [1..fromIntegral n] $ \i -> peekByteOff p (i * 4)-        return $ snd $ mapAccumL (\bs i -> swap $ BS.splitAt (fromIntegral i) bs) (BS.drop (4 + (n * 4)) bs) ns+        pure $ snd $ mapAccumL (\bs i -> swap $ BS.splitAt (fromIntegral i) bs) (BS.drop (4 + (n * 4)) bs) ns  instance BinaryEx () where     putEx () = mempty@@ -197,7 +197,7 @@ --     BS putExList :: [Builder] -> Builder putExList xs = Builder (sum $ map (\b -> sizeBuilder b + 4) xs) $ \p i -> do-    let go _ [] = return ()+    let go _ [] = pure ()         go i (Builder n b:xs) = do             pokeByteOff p i (fromIntegral n :: Word32)             b p (i+4)
src/General/Chunks.hs view
@@ -44,12 +44,12 @@ readChunkDirect h mx = do     let slop x = do             unless (BS.null x) $ hSetFileSize h . subtract (toInteger $ BS.length x) =<< hFileSize h-            return $ Left x+            pure $ Left x     n <- BS.hGet h 4     if BS.length n < 4 then slop n else do         let count = fromIntegral $ min mx $ fst $ unsafeBinarySplit n         v <- BS.hGet h count-        if BS.length v < count then slop (n `BS.append` v) else return $ Right v+        if BS.length v < count then slop (n `BS.append` v) else pure $ Right v  writeChunkDirect :: Handle -> Builder -> IO () writeChunkDirect h x = bs `seq` BS.hPut h bs@@ -72,18 +72,18 @@             takeMVar kick             sleep flush             tryTakeMVar kick-            writeChan chan $ hFlush h >> return True+            writeChan chan $ hFlush h >> pure True      -- pump the thread while we are running     -- once we abort, let everything finish flushing first     -- the mask_ is very important - we don't want to abort until everything finishes     allocateThread cleanup $ mask_ $ whileM $ join $ readChan chan     -- this cleanup will run before we attempt to kill the thread-    register cleanup $ writeChan chan $ return False+    register cleanup $ writeChan chan $ pure False -    return $ \s -> do+    pure $ \s -> do         out <- evaluate $ writeChunkDirect h s -- ensure exceptions occur on this thread-        writeChan chan $ out >> tryPutMVar kick () >> return True+        writeChan chan $ out >> tryPutMVar kick () >> pure True   writeChunk :: Chunks -> Builder -> IO ()@@ -99,10 +99,10 @@ restoreChunksBackup file = do     -- complete a partially failed compress     b <- doesFileExist $ backup file-    if not b then return False else do+    if not b then pure False else do         removeFile_ file         renameFile (backup file) file-        return True+        pure True   usingChunks :: Cleanup -> FilePath -> Maybe Seconds -> IO Chunks@@ -111,7 +111,7 @@     allocate cleanup         (putMVar h =<< openFile file ReadWriteMode)         (const $ hClose =<< takeMVar h)-    return $ Chunks file flush h+    pure $ Chunks file flush h   -- | The file is being compacted, if the process fails, use a backup.@@ -128,7 +128,7 @@         res <- act $ writeChunkDirect h         hFlush h         removeFile $ backup chunksFileName-        return res+        pure res   -- | The file got corrupted, return a new version.@@ -136,7 +136,7 @@ resetChunksCorrupt copy Chunks{..} = mask $ \restore -> do     h <- takeMVar chunksHandle     case copy of-        Nothing -> return h+        Nothing -> pure h         Just copy -> do             flip onException (putMVar chunksHandle h) $ restore $ do                 hClose h
src/General/Cleanup.hs view
@@ -40,7 +40,7 @@     let clean = uninterruptibleMask_ $ do             items <- atomicModifyIORef' ref $ \s -> (s{items=Map.empty}, items s)             mapM_ snd $ sortOn (negate . fst) $ Map.toList items-    return (Cleanup ref, clean)+    pure (Cleanup ref, clean)   register :: Cleanup -> IO () -> IO ReleaseKey@@ -53,11 +53,11 @@ release :: ReleaseKey -> IO () release (ReleaseKey ref i) = uninterruptibleMask_ $ do     undo <- atomicModifyIORef' ref $ \s -> (s{items = Map.delete i $ items s}, Map.lookup i $ items s)-    fromMaybe (return ()) undo+    fromMaybe (pure ()) undo  allocate :: Cleanup -> IO a -> (a -> IO ()) -> IO a allocate cleanup acquire release =     mask_ $ do         v <- acquire         register cleanup $ release v-        return v+        pure v
src/General/EscCodes.hs view
@@ -13,6 +13,7 @@     ) where  import Data.Char+import Data.List.Extra import System.IO import System.Environment import System.IO.Unsafe@@ -26,18 +27,18 @@ #endif  checkEscCodes :: IO Bool-checkEscCodes = return checkEscCodesOnce+checkEscCodes = pure checkEscCodesOnce  {-# NOINLINE checkEscCodesOnce #-} checkEscCodesOnce :: Bool checkEscCodesOnce = unsafePerformIO $ do     hdl <- hIsTerminalDevice stdout     env <- maybe False (/= "dumb") <$> lookupEnv "TERM"-    if hdl && env then return True else+    if hdl && env then pure True else #ifdef mingw32_HOST_OS         checkEscCodesWindows #else-        return False+        pure False #endif  #ifdef mingw32_HOST_OS@@ -64,17 +65,17 @@     -- might return INVALID_HANDLE_VALUE, but then the next step will happily fail     mode <- alloca $ \v -> do         b <- c_GetConsoleModule h v-        if b then Just <$> peek v else return Nothing+        if b then Just <$> peek v else pure Nothing     case mode of-        Nothing -> return False+        Nothing -> pure False         Just mode -> do             let modeNew = mode .|. c_ENABLE_VIRTUAL_TERMINAL_PROCESSING-            if mode == modeNew then return True else do+            if mode == modeNew then pure True else do                 c_SetConsoleMode h modeNew #endif  removeEscCodes :: String -> String-removeEscCodes ('\ESC':'[':xs) = removeEscCodes $ drop 1 $ dropWhile (not . isAlpha) xs+removeEscCodes ('\ESC':'[':xs) = removeEscCodes $ drop1 $ dropWhile (not . isAlpha) xs removeEscCodes (x:xs) = x : removeEscCodes xs removeEscCodes [] = [] 
src/General/Extra.hs view
@@ -1,5 +1,4 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE ScopedTypeVariables, ConstraintKinds, RecordWildCards, GeneralizedNewtypeDeriving, ViewPatterns, Rank2Types #-}+{-# LANGUAGE ScopedTypeVariables, ConstraintKinds, GeneralizedNewtypeDeriving, ViewPatterns #-}  module General.Extra(     getProcessorCount,@@ -50,9 +49,7 @@ import Control.Monad import Control.Monad.ST import GHC.Conc(getNumProcessors)-#if __GLASGOW_HASKELL__ >= 800 import GHC.Stack-#endif   ---------------------------------------------------------------------@@ -122,7 +119,7 @@ {-# NOINLINE getProcessorCount #-} getProcessorCount :: IO Int -- unsafePefromIO so we cache the result and only compute it once-getProcessorCount = let res = unsafePerformIO act in return res+getProcessorCount = let res = unsafePerformIO act in pure res     where         act =             if rtsSupportsBoundThreads then@@ -130,10 +127,10 @@             else do                 env <- lookupEnv "NUMBER_OF_PROCESSORS"                 case env of-                    Just s | [(i,"")] <- reads s -> return i+                    Just s | [(i,"")] <- reads s -> pure i                     _ -> do-                        src <- readFile' "/proc/cpuinfo" `catchIO` \_ -> return ""-                        return $! max 1 $ length [() | x <- lines src, "processor" `isPrefixOf` x]+                        src <- readFile' "/proc/cpuinfo" `catchIO` \_ -> pure ""+                        pure $! max 1 $ length [() | x <- lines src, "processor" `isPrefixOf` x]   -- Can you find a GCC executable? return a Bool, and optionally something to add to $PATH to run it@@ -147,9 +144,9 @@                 Just ghc -> do                     let gcc = takeDirectory (takeDirectory ghc) </> "mingw/bin/gcc.exe"                     b <- doesFileExist_ gcc-                    return $ if b then (True, Just $ takeDirectory gcc) else (False, Nothing)-                _ -> return (False, Nothing)-        _ -> return (isJust v, Nothing)+                    pure $ if b then (True, Just $ takeDirectory gcc) else (False, Nothing)+                _ -> pure (False, Nothing)+        _ -> pure (isJust v, Nothing)   @@ -160,7 +157,7 @@ randomElem xs = do     when (null xs) $ fail "General.Extra.randomElem called with empty list, can't pick a random element"     i <- randomRIO (0, length xs - 1)-    return $ xs !! i+    pure $ xs !! i   ---------------------------------------------------------------------@@ -190,11 +187,11 @@ withs (f:fs) act = f $ \a -> withs fs $ \as -> act $ a:as  forNothingM :: Monad m => [a] -> (a -> m (Maybe b)) -> m (Maybe [b])-forNothingM [] f = return $ Just []+forNothingM [] f = pure $ Just [] forNothingM (x:xs) f = do     v <- f x     case v of-        Nothing -> return Nothing+        Nothing -> pure Nothing         Just v -> liftM (v:) `liftM` forNothingM xs f  @@ -235,16 +232,16 @@ -- System.Directory  doesFileExist_ :: FilePath -> IO Bool-doesFileExist_ x = doesFileExist x `catchIO` \_ -> return False+doesFileExist_ x = doesFileExist x `catchIO` \_ -> pure False  doesDirectoryExist_ :: FilePath -> IO Bool-doesDirectoryExist_ x = doesDirectoryExist x `catchIO` \_ -> return False+doesDirectoryExist_ x = doesDirectoryExist x `catchIO` \_ -> pure False  -- | Remove a file, but don't worry if it fails removeFile_ :: FilePath -> IO () removeFile_ x =     removeFile x `catchIO` \e ->-        when (isPermissionError e) $ handleIO (\_ -> return ()) $ do+        when (isPermissionError e) $ handleIO (\_ -> pure ()) $ do             perms <- getPermissions x             setPermissions x perms{readable = True, searchable = True, writable = True}             removeFile x@@ -271,14 +268,12 @@ type Located = Partial  callStackTop :: Partial => String-callStackTop = withFrozenCallStack $ head $ callStackFull ++ ["unknown location"]+callStackTop = withFrozenCallStack $ headDef "unknown location" callStackFull  callStackFull :: Partial => [String] callStackFromException :: SomeException -> ([String], SomeException)  -#if __GLASGOW_HASKELL__ >= 800- -- | Invert 'prettyCallStack', which GHC pre-applies in certain cases parseCallStack = reverse . map trimStart . drop 1 . lines @@ -287,14 +282,6 @@ callStackFromException (fromException -> Just (ErrorCallWithLocation msg loc)) = (parseCallStack loc, toException $ ErrorCall msg) callStackFromException e = ([], e) -#else--callStackFull = []-callStackFromException e = ([], e)--withFrozenCallStack :: a -> a-withFrozenCallStack = id-#endif  --------------------------------------------------------------------- -- Data.Version
src/General/Fence.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE LambdaCase #-}  module General.Fence(     Fence, newFence, signalFence, waitFence, testFence,@@ -21,20 +22,20 @@ instance Show (Fence m a) where show _ = "Fence"  newFence :: MonadIO m => IO (Fence m a)-newFence = Fence <$> newIORef (Left $ const $ return ())+newFence = Fence <$> newIORef (Left $ const $ pure ())  signalFence :: (Partial, MonadIO m) => Fence m a -> a -> m ()-signalFence (Fence ref) v = join $ liftIO $ atomicModifyIORef' ref $ \x -> case x of+signalFence (Fence ref) v = join $ liftIO $ atomicModifyIORef' ref $ \case     Left queue -> (Right v, queue v)     Right _ -> throwImpure $ errorInternal "signalFence called twice on one Fence"  waitFence :: MonadIO m => Fence m a -> (a -> m ()) -> m ()-waitFence (Fence ref) call = join $ liftIO $ atomicModifyIORef' ref $ \x -> case x of-    Left queue -> (Left (\a -> queue a >> call a), return ())+waitFence (Fence ref) call = join $ liftIO $ atomicModifyIORef' ref $ \case+    Left queue -> (Left (\a -> queue a >> call a), pure ())     Right v -> (Right v, call v)  testFence :: Fence m a -> IO (Maybe a)-testFence (Fence x) = either (const Nothing) Just <$> readIORef x+testFence (Fence x) = eitherToMaybe <$> readIORef x   ---------------------------------------------------------------------@@ -50,5 +51,5 @@         join $ liftIO $ atomicModifyIORef' todo $ \i -> case res of             Left e | i >= 0 -> (-1, signalFence fence $ Left e)             _ | i == 1 -> (-1, signalFence fence . Right =<< liftIO (mapM (fmap (fromRight' . fromJust) . testFence) xs))-              | otherwise -> (i-1, return ())-    return fence+              | otherwise -> (i-1, pure ())+    pure fence
src/General/GetOpt.hs view
@@ -58,7 +58,7 @@ mergeOptDescr xs ys = map (fmapFmapOptDescr Left) xs ++ map (fmapFmapOptDescr Right) ys  optionsEnum :: (Enum a, Bounded a, Show a) => [OptDescr (Either String a)]-optionsEnum = optionsEnumDesc [(x, "Flag " ++ lower (show x) ++ ".") | x <- [minBound..maxBound]]+optionsEnum = optionsEnumDesc [(x, "Flag " ++ lower (show x) ++ ".") | x <- enumerate]  optionsEnumDesc :: Show a => [(a, String)] -> [OptDescr (Either String a)] optionsEnumDesc xs = [Option "" [lower $ show x] (NoArg $ Right x) d | (x,d) <- xs]
src/General/Ids.hs view
@@ -51,14 +51,14 @@ sizeUpperBound :: Ids a -> IO Int sizeUpperBound (Ids ref) = do     S{..} <- readIORef ref-    return used+    pure used   size :: Ids a -> IO Int size (Ids ref) = do     S{..} <- readIORef ref     let go !acc i-            | i < 0 = return acc+            | i < 0 = pure acc             | otherwise = do                 v <- readArray values i                 if isJust v then go (acc+1) (i-1) else go acc (i-1)@@ -68,12 +68,12 @@ toMap :: Ids a -> IO (Map.HashMap Id a) toMap ids = do     mp <- Map.fromList <$> toListUnsafe ids-    return $! mp+    pure $! mp  forWithKeyM_ :: Ids a -> (Id -> a -> IO ()) -> IO () forWithKeyM_ (Ids ref) f = do     S{..} <- readIORef ref-    let go !i | i >= used = return ()+    let go !i | i >= used = pure ()               | otherwise = do                 v <- readArray values i                 whenJust v $ f $ Id $ fromIntegral i@@ -84,7 +84,7 @@ forCopy (Ids ref) f = do     S{..} <- readIORef ref     values2 <- newArray capacity Nothing-    let go !i | i >= used = return ()+    let go !i | i >= used = pure ()               | otherwise = do                 v <- readArray values i                 whenJust v $ \v -> writeArray values2 i $ Just $ f v@@ -96,7 +96,7 @@ forMutate :: Ids a -> (a -> a) -> IO () forMutate (Ids ref) f = do     S{..} <- readIORef ref-    let go !i | i >= used = return ()+    let go !i | i >= used = pure ()               | otherwise = do                 v <- readArray values i                 whenJust v $ \v -> writeArray values i $ Just $ f v@@ -124,7 +124,7 @@     let demand (_:xs) = demand xs         demand [] = ()     evaluate $ demand xs-    return xs+    pure xs  elems :: Ids a -> IO [a] elems ids = map snd <$> toList ids@@ -141,7 +141,7 @@         writeArray values ii $ Just v         when (ii >= used) $ writeIORef' ref S{used=ii+1,..}      else do-        c2 <- return $ max (capacity * 2) (ii + 10000)+        c2<- pure $ max (capacity * 2) (ii + 10000)         v2 <- newArray c2 Nothing         copyMutableArray v2 0 values 0 capacity         writeArray v2 ii $ Just v@@ -154,4 +154,4 @@     if ii < used then         readArray values ii      else-        return Nothing+        pure Nothing
src/General/Pool.hs view
@@ -52,11 +52,11 @@  emptyS :: Int -> Bool -> IO S emptyS n deterministic = do-    rand <- if not deterministic then return randomIO else do+    rand <- if not deterministic then pure randomIO else do         ref <- newIORef 0         -- no need to be thread-safe - if two threads race they were basically the same time anyway-        return $ do i <- readIORef ref; writeIORef' ref (i+1); return i-    return $ S True Set.empty n 0 0 0 rand Heap.empty+        pure $ do i <- readIORef ref; writeIORef' ref (i+1); pure i+    pure $ S True Set.empty n 0 0 0 rand Heap.empty   data Pool = Pool@@ -66,15 +66,15 @@  withPool :: Pool -> (S -> IO (S, IO ())) -> IO () withPool (Pool var _) f = join $ modifyVar var $ \s ->-    if alive s then f s else return (s, return ())+    if alive s then f s else pure (s, pure ())  withPool_ :: Pool -> (S -> IO S) -> IO ()-withPool_ pool act = withPool pool $ fmap (, return()) . act+withPool_ pool act = withPool pool $ fmap (, pure()) . act   worker :: Pool -> IO ()-worker pool = withPool pool $ \s -> return $ case Heap.uncons $ todo s of-    Nothing -> (s, return ())+worker pool = withPool pool $ \s -> pure $ case Heap.uncons $ todo s of+    Nothing -> (s, pure ())     Just (Heap.Entry _ now, todo2) -> (s{todo = todo2}, now >> worker pool)  -- | Given a pool, and a function that breaks the S invariants, restore them.@@ -90,14 +90,14 @@             t <- newThreadFinally (now >> worker pool) $ \t res -> case res of                 Left e -> withPool_ pool $ \s -> do                     signalBarrier done $ Left e-                    return (remThread t s){alive = False}+                    pure (remThread t s){alive = False}                 Right _ ->-                    step pool $ return . remThread t-            return (addThread t s){todo = todo2}+                    step pool $ pure . remThread t+            pure (addThread t s){todo = todo2}         Nothing | threadsCount s == 0 -> do             signalBarrier done $ Right s-            return s{alive = False}-        _ -> return s+            pure s{alive = False}+        _ -> pure s     where         addThread t s = s{threads = Set.insert t $ threads s, threadsCount = threadsCount s + 1                          ,threadsSum = threadsSum s + 1, threadsMax = threadsMax s `max` (threadsCount s + 1)}@@ -109,7 +109,7 @@ addPool :: PoolPriority -> Pool -> IO a -> IO () addPool priority pool act = step pool $ \s -> do     i <- rand s-    return s{todo = Heap.insert (Heap.Entry (priority, i) $ void act) $ todo s}+    pure s{todo = Heap.insert (Heap.Entry (priority, i) $ void act) $ todo s}   data PoolPriority@@ -124,8 +124,8 @@ --   After calling cleanup you should requeue onto a new thread. increasePool :: Pool -> IO (IO ()) increasePool pool = do-    step pool $ \s -> return s{threadsLimit = threadsLimit s + 1}-    return $ step pool $ \s -> return s{threadsLimit = threadsLimit s - 1}+    step pool $ \s -> pure s{threadsLimit = threadsLimit s + 1}+    pure $ step pool $ \s -> pure s{threadsLimit = threadsLimit s - 1}   -- | Make sure the pool cannot run out of tasks (and thus everything finishes) until after the cancel is called.@@ -137,7 +137,7 @@         cancel <- increasePool pool         waitBarrier bar         cancel-    return $ signalBarrier bar ()+    pure $ signalBarrier bar ()   -- | Run all the tasks in the pool on the given number of works.@@ -149,7 +149,7 @@     let pool = Pool s done      -- if someone kills our thread, make sure we kill our child threads-    let cleanup = join $ modifyVar s $ \s -> return (s{alive=False}, stopThreads $ Set.toList $ threads s)+    let cleanup = join $ modifyVar s $ \s -> pure (s{alive=False}, stopThreads $ Set.toList $ threads s)      let ghc10793 = do             -- if this thread dies because it is blocked on an MVar there's a chance we have
src/General/Process.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE RecordWildCards #-}  -- | A wrapping of createProcess to provide a more flexible interface.@@ -19,7 +20,7 @@ import System.Process import System.Time.Extra import Data.Unique-import Data.IORef+import Data.IORef.Extra import qualified Data.ByteString.Char8 as BS import qualified Data.ByteString.Lazy as LBS import General.Extra@@ -38,7 +39,7 @@ newBuffer = liftM2 Buffer newUnique (newIORef [])  addBuffer :: Buffer a -> a -> IO ()-addBuffer (Buffer _ ref) x = atomicModifyIORef ref $ \xs -> (x:xs, ())+addBuffer (Buffer _ ref) x = atomicModifyIORef_ ref (x:)  readBuffer :: Buffer a -> IO [a] readBuffer (Buffer _ ref) = reverse <$> readIORef ref@@ -51,6 +52,7 @@     = SrcFile FilePath     | SrcString String     | SrcBytes LBS.ByteString+    | SrcInherit  data Destination     = DestEcho@@ -72,6 +74,7 @@     ,poStderr :: [Destination]     ,poAsync :: Bool     ,poCloseFds :: Bool+    ,poGroup :: Bool     }  @@ -80,7 +83,7 @@  -- | If two buffers can be replaced by one and a copy, do that (only if they start empty) optimiseBuffers :: ProcessOpts -> IO (ProcessOpts, IO ())-optimiseBuffers po@ProcessOpts{..} = return (po{poStdout = nubOrd poStdout, poStderr = nubOrd poStderr}, return ())+optimiseBuffers po@ProcessOpts{..} = pure (po{poStdout = nubOrd poStdout, poStderr = nubOrd poStderr}, pure ())  stdStream :: (FilePath -> Handle) -> [Destination] -> [Destination] -> StdStream stdStream _ [DestEcho] _ = Inherit@@ -89,19 +92,20 @@   stdIn :: (FilePath -> Handle) -> [Source] -> (StdStream, Handle -> IO ())-stdIn _ [] = (Inherit, const $ return ())-stdIn file [SrcFile x] = (UseHandle $ file x, const $ return ())+stdIn _ [SrcInherit] = (Inherit, const $ pure ())+stdIn file [SrcFile x] = (UseHandle $ file x, const $ pure ()) stdIn file src = (,) CreatePipe $ \h -> ignoreSigPipe $ do-    forM_ src $ \x -> case x of+    forM_ src $ \case         SrcString x -> hPutStr h x         SrcBytes x -> LBS.hPutStr h x         SrcFile x -> LBS.hPutStr h =<< LBS.hGetContents (file x)+        SrcInherit -> pure () -- Can't both inherit and set it     hClose h   ignoreSigPipe :: IO () -> IO () ignoreSigPipe = handleIO $ \e -> case e of-    IOError {ioe_type=ResourceVanished, ioe_errno=Just ioe} | Errno ioe == ePIPE -> return ()+    IOError {ioe_type=ResourceVanished, ioe_errno=Just ioe} | Errno ioe == ePIPE -> pure ()     _ -> throwIO e  @@ -113,7 +117,7 @@         unmask (waitBarrier bar) `onException` do             forkIO stop             waitBarrier bar-    either throwIO return v+    either throwIO pure v   withTimeout :: Maybe Double -> IO () -> IO a -> IO a@@ -131,16 +135,17 @@ forkWait a = do     res <- newEmptyMVar     _ <- mask $ \restore -> forkIO $ try_ (restore a) >>= putMVar res-    return $ takeMVar res >>= either throwIO return+    pure $ takeMVar res >>= either throwIO pure  -abort :: ProcessHandle -> IO ()-abort pid = do-    interruptProcessGroupOf pid-    sleep 3 -- give the process a few seconds grace period to die nicely-    -- seems to happen with some GHC 7.2 compiled binaries with FFI etc+abort :: Bool -> ProcessHandle -> IO ()+abort poGroup pid = do+    when poGroup $ do+        interruptProcessGroupOf pid+        sleep 3 -- give the process a few seconds grace period to die nicely     terminateProcess pid + withFiles :: IOMode -> [FilePath] -> ((FilePath -> Handle) -> IO a) -> IO a withFiles mode files act = withs (map (`withFile` mode) files) $ \handles ->     act $ \x -> fromJust $ lookup x $ zipExact files handles@@ -153,11 +158,11 @@     let outFiles = nubOrd [x | DestFile x <- poStdout ++ poStderr]     let inFiles = nubOrd [x | SrcFile x <- poStdin]     withFiles WriteMode outFiles $ \outHandle -> withFiles ReadMode inFiles $ \inHandle -> do-        let cp = (cmdSpec poCommand){cwd = poCwd, env = poEnv, create_group = True, close_fds = poCloseFds+        let cp = (cmdSpec poCommand){cwd = poCwd, env = poEnv, create_group = poGroup, close_fds = poCloseFds                  ,std_in = fst $ stdIn inHandle poStdin                  ,std_out = stdStream outHandle poStdout poStderr, std_err = stdStream outHandle poStderr poStdout}         withCreateProcessCompat cp $ \inh outh errh pid ->-            withExceptions (abort pid) $ withTimeout poTimeout (abort pid) $ do+            withTimeout poTimeout (abort poGroup pid) $ withExceptions (abort poGroup pid) $ do                  let streams = [(outh, stdout, poStdout) | Just outh <- [outh], CreatePipe <- [std_out cp]] ++                               [(errh, stderr, poStderr) | Just errh <- [errh], CreatePipe <- [std_err cp]]@@ -169,12 +174,12 @@                     when (DestEcho `elem` dest) $ do                         buf <- hGetBuffering hh                         case buf of-                            BlockBuffering{} -> return ()+                            BlockBuffering{} -> pure ()                             _ -> hSetBuffering h buf                      if isBinary then do                         hSetBinaryMode h True-                        dest <- return $ flip map dest $ \d -> case d of+                        dest<- pure $ flip map dest $ \case                             DestEcho -> BS.hPut hh                             DestFile x -> BS.hPut (outHandle x)                             DestString x -> addBuffer x . (if isWindows then replace "\r\n" "\n" else id) . BS.unpack@@ -184,36 +189,36 @@                             mapM_ ($ src) dest                             notM $ hIsEOF h                      else if isTied then do-                        dest <- return $ flip map dest $ \d -> case d of+                        dest<- pure $ flip map dest $ \case                             DestEcho -> hPutStrLn hh                             DestFile x -> hPutStrLn (outHandle x)                             DestString x -> addBuffer x . (++ "\n")                             DestBytes{} -> throwImpure $ errorInternal "Not reachable due to isBinary condition"                         forkWait $ whileM $-                            ifM (hIsEOF h) (return False) $ do+                            ifM (hIsEOF h) (pure False) $ do                                 src <- hGetLine h                                 mapM_ ($ src) dest-                                return True+                                pure True                      else do                         src <- hGetContents h                         wait1 <- forkWait $ C.evaluate $ rnf src-                        waits <- forM dest $ \d -> case d of+                        waits <- forM dest $ \case                             DestEcho -> forkWait $ hPutStr hh src                             DestFile x -> forkWait $ hPutStr (outHandle x) src-                            DestString x -> do addBuffer x src; return $ return ()+                            DestString x -> do addBuffer x src; pure $ pure ()                             DestBytes{} -> throwImpure $ errorInternal "Not reachable due to isBinary condition"-                        return $ sequence_ $ wait1 : waits+                        pure $ sequence_ $ wait1 : waits                  whenJust inh $ snd $ stdIn inHandle poStdin                 if poAsync then-                    return (pid, ExitSuccess)+                    pure (pid, ExitSuccess)                  else do                     sequence_ wait                     flushBuffers                     res <- waitForProcess pid                     whenJust outh hClose                     whenJust errh hClose-                    return (pid, res)+                    pure (pid, res)   ---------------------------------------------------------------------
src/General/Template.hs view
@@ -27,7 +27,7 @@  -- Very hard to abstract over TH, so we do it with CPP #ifdef FILE_EMBED-#define FILE(x) (return (LBS.fromStrict $(embedFile =<< runIO (x))))+#define FILE(x) (pure (LBS.fromStrict $(embedFile =<< runIO (x)))) #else #define FILE(x) (LBS.readFile =<< (x)) #endif@@ -52,9 +52,9 @@         link = LBS.pack "<link href=\""         script = LBS.pack "<script src=\"" -        f x | Just file <- lbsStripPrefix script y = do res <- grab file; return $ LBS.pack "<script>\n" `LBS.append` res `LBS.append` LBS.pack "\n</script>"-            | Just file <- lbsStripPrefix link y = do res <- grab file; return $ LBS.pack "<style type=\"text/css\">\n" `LBS.append` res `LBS.append` LBS.pack "\n</style>"-            | otherwise = return x+        f x | Just file <- lbsStripPrefix script y = do res <- grab file; pure $ LBS.pack "<script>\n" `LBS.append` res `LBS.append` LBS.pack "\n</script>"+            | Just file <- lbsStripPrefix link y = do res <- grab file; pure $ LBS.pack "<style type=\"text/css\">\n" `LBS.append` res `LBS.append` LBS.pack "\n</style>"+            | otherwise = pure x             where                 y = LBS.dropWhile isSpace x                 grab = asker . takeWhile (/= '\"') . LBS.unpack@@ -67,7 +67,7 @@         asker "shake.js" = readDataFileHTML "shake.js"         asker "data/metadata.js" = do             time <- getCurrentTime-            return $ LBS.pack $+            pure $ LBS.pack $                 "var version = " ++ show shakeVersionString ++                 "\nvar generated = " ++ show (formatTime defaultTimeLocale (iso8601DateFormat (Just "%H:%M:%S")) time)         asker x = ask x@@ -78,7 +78,7 @@ -- before it starts producing the lazy result, killing streaming and having more stack usage. -- The real solution (albeit with too many dependencies for something small) is a streaming library, -- but a little bit of unsafePerformIO does the trick too.-lbsMapLinesIO f = return . LBS.unlines . map (unsafePerformIO . f) . LBS.lines+lbsMapLinesIO f = pure . LBS.unlines . map (unsafePerformIO . f) . LBS.lines   ---------------------------------------------------------------------
src/General/Thread.hs view
@@ -32,13 +32,13 @@         res <- try $ unmask act         me <- myThreadId         cleanup (Thread me bar) res-    return $ Thread t bar+    pure $ Thread t bar   stopThreads :: [Thread] -> IO () stopThreads threads = do     -- if a thread is in a masked action, killing it may take some time, so kill them in parallel-    bars <- sequence [do forkIO $ killThread t; return bar | Thread t bar <- threads]+    bars <- sequence [do forkIO $ killThread t; pure bar | Thread t bar <- threads]     mapM_ waitBarrier bars  @@ -63,13 +63,13 @@         res :: Either SomeException (a,b) <- try $ unmask $ do             Right v1 <- waitBarrier bar1             Right v2 <- waitBarrier bar2-            return (v1,v2)+            pure (v1,v2)         writeVar ignore True         killThread t1         forkIO $ killThread t2         waitBarrier bar1         waitBarrier bar2-        either throwIO return res+        either throwIO pure res   -- | Run an action in a separate thread.
src/General/Timing.hs view
@@ -1,9 +1,10 @@  module General.Timing(resetTimings, addTiming, getTimings) where -import Data.IORef+import Data.IORef.Extra import System.IO.Unsafe import Data.Tuple.Extra+import Data.List.Extra import Numeric.Extra import General.Extra import System.Time.Extra@@ -30,13 +31,13 @@ getTimings = do     now <- timer     old <- atomicModifyIORef timings dupe-    return $ showTimings now $ reverse old+    pure $ showTimings now $ reverse old   addTiming :: String -> IO () addTiming msg = do     now <- timer-    atomicModifyIORef timings $ \ts -> ((now,msg):ts, ())+    atomicModifyIORef_ timings ((now,msg):)   showTimings :: Seconds -> [(Seconds, String)] -> [String]@@ -51,7 +52,7 @@         mx = maximum $ map snd xs         sm = sum $ map snd xs         xs = [ (name, stop - start)-             | ((start, name), stop) <- zipExact times $ map fst (drop 1 times) ++ [stop]]+             | ((start, name), stop) <- zipExact times $ map fst (drop1 times) ++ [stop]]   showGap :: [(String,String)] -> [String]
src/General/Wait.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE DeriveFunctor, CPP #-}+{-# LANGUAGE DeriveFunctor #-}  -- | A bit like 'Fence', but not thread safe and optimised for avoiding taking the fence module General.Wait(@@ -12,15 +12,13 @@ import Data.List.Extra import Data.Primitive.Array import GHC.Exts(RealWorld)--#if __GLASGOW_HASKELL__ >= 800 && __GLASGOW_HASKELL__ < 808 import Control.Monad.Fail-#endif+import Prelude   runWait :: Monad m => Wait m a -> m (Wait m a) runWait (Lift x) = runWait =<< x-runWait x = return x+runWait x = pure x  fromLater :: Monad m => Wait m a -> (a -> m ()) -> m () fromLater (Lift x) f = do x <- x; fromLater x f@@ -41,14 +39,14 @@     Lift x <*> y = Lift $ (<*> y) <$> x     Later x <*> Now y = Later $ \c -> x $ \x -> c $ x y     -- Note: We pull the Lift from the right BEFORE the Later, to enable parallelism-    Later x <*> Lift y = Lift $ do y <- y; return $ Later x <*> y+    Later x <*> Lift y = Lift $ do y <- y; pure $ Later x <*> y     Later x <*> Later y = Later $ \c -> x $ \x -> y $ \y -> c $ x y  instance (Monad m, Applicative m) => Monad (Wait m) where     return = pure     (>>) = (*>)     Now x >>= f = f x-    Lift x >>= f = Lift $ do x <- x; return $ x >>= f+    Lift x >>= f = Lift $ do x <- x; pure $ x >>= f     Later x >>= f = Later $ \c -> x $ \x -> do         x <- runWait $ f x         case x of@@ -58,16 +56,9 @@ instance (MonadIO m,  Applicative m) => MonadIO (Wait m) where     liftIO = Lift . liftIO . fmap Now -#if __GLASGOW_HASKELL__ >= 800 && __GLASGOW_HASKELL__ < 808 instance MonadFail m => MonadFail (Wait m) where     fail = Lift . Control.Monad.Fail.fail-#endif-#if __GLASGOW_HASKELL__ >= 808-instance MonadFail m => MonadFail (Wait m) where-    fail = Lift . Prelude.fail-#endif - firstJustWaitUnordered :: MonadIO m => (a -> Wait m (Maybe b)) -> [a] -> Wait m (Maybe b) firstJustWaitUnordered f = go [] . map f     where@@ -79,7 +70,7 @@             Later l -> go (l:later) xs             Lift x -> Lift $ do                 x <- x-                return $ go later (x:xs)+                pure $ go later (x:xs)         go [] [] = Now Nothing         go [l] [] = Later l         go ls [] = Later $ \callback -> do@@ -101,7 +92,7 @@         mut <- liftIO $ newArray n undefined         res <- go mut [] $ zipFrom 0 $ map f xs         case res of-            Just e -> return $ Left e+            Just e -> pure $ Left e             Nothing -> liftIO $ Right <$> mapM (readArray mut) [0..n-1]     where         -- keep a list of those things we might visit later, and ask for each we see in turn@@ -114,7 +105,7 @@             Later l -> go mut ((i,l):later) xs             Lift x -> Lift $ do                 x <- x-                return $ go mut later ((i,x):xs)+                pure $ go mut later ((i,x):xs)         go _ [] [] = Now Nothing         go mut ls [] = Later $ \callback -> do             ref <- liftIO $ newIORef $ length ls
src/Paths.hs view
@@ -6,7 +6,7 @@  -- If Shake can't find files in the data directory it tries relative to the executable getDataDir :: IO FilePath-getDataDir = return "random_path_that_cannot_possibly_exist"+getDataDir = pure "random_path_that_cannot_possibly_exist"  version :: Version version = makeVersion [0,0]
src/Run.hs view
@@ -25,19 +25,20 @@         ,"Shakefile.hs","Shakefile.lhs"]     case hsExe of         Just file -> do-            (prog,args) <- return $+            (prog,args)<- pure $                 if takeExtension file `elem` [".hs",".lhs"] then ("runhaskell", file:args) else (toNative file, args)             e <- rawSystem prog args             when (e /= ExitSuccess) $ exitWith e         Nothing -> do-            let go = shakeArgsWith shakeOptions{shakeThreads=0,shakeCreationCheck=False} flags $ \opts targets -> do+            let opts = shakeOptions{shakeThreads=0,shakeCreationCheck=False,shakeNeedDirectory=True}+            let go = shakeArgsWith opts flags $ \opts targets -> do                         let tool = listToMaybe [x | Tool x <- opts]                         makefile <- case reverse [x | UseMakefile x <- opts] of-                            x:_ -> return x+                            x:_ -> pure x                             _ -> do                                 res <- findFile ["build.ninja"]                                 case res of-                                    Just x -> return x+                                    Just x -> pure x                                     Nothing -> errorIO "Could not find `build.ninja'"                         runNinja go makefile targets tool             withArgs ("--no-time":args) go
src/Test.hs view
@@ -4,6 +4,7 @@ import Control.Exception.Extra import Control.Monad.Extra import Data.Maybe+import Data.List.Extra import System.Directory import System.Environment import General.Timing@@ -153,14 +154,14 @@ makefile :: IO () -> IO () makefile _ = do     args <- getArgs-    withArgs (drop 1 args) Run.main+    withArgs (drop1 args) Run.main   filetime :: IO () -> IO () filetime _ = do     args <- getArgs     addTiming "Reading files"-    files <- fmap concat $ forM (drop 1 args) $ \file ->+    files <- concatForM (drop1 args) $ \file ->         BS.lines . BS.filter (/= '\r') <$> BS.readFile file     let n = length files     evaluate n@@ -169,7 +170,7 @@     let (b,cd) = splitAt (n `div` 4) bcd     let (c,d) = splitAt (n `div` 4) cd     vars <- forM [a,b,c,d] $ \xs ->-        onceFork $ mapM_ (getFileInfo . fileNameFromByteString) xs+        onceFork $ mapM_ (getFileInfo False . fileNameFromByteString) xs     sequence_ vars  @@ -181,4 +182,4 @@ test yield = do     args <- getArgs     flip onException (putStrLn "TESTS FAILED") $-        sequence_ [withArgs (name:"test":drop 1 args) $ test yield | (name,test) <- mains, name /= "random"]+        sequence_ [withArgs (name:"test":drop1 args) $ test yield | (name,test) <- mains, name /= "random"]
src/Test/Basic.hs view
@@ -53,8 +53,8 @@         x <- getShakeOptions         writeFile' "threads.txt" $ show $ shakeThreads x -    phony ("slash" </> "platform") $ return ()-    phony "slash/forward" $ return ()+    phony ("slash" </> "platform") $ pure ()+    phony "slash/forward" $ pure ()      phony "options" $ do         opts <- getShakeOptions@@ -78,7 +78,7 @@     ["sep" </> "3.txt", "sep" </> "4.txt", "sep" </> "5.*", "sep/6.txt"] |%> \out -> writeFile' out ""     ["sep" </> "7.txt"] |%> \out -> writeFile' out "" -    "ids/source" %> \_ -> return ()+    "ids/source" %> \_ -> pure ()     "ids/out" %> \out -> do need =<< readFileLines "ids/source"; writeFile' out ""     "ids/*" %> \out -> do alwaysRerun; trace (takeFileName out); writeFile' out $ takeFileName out 
src/Test/Batch.hs view
@@ -4,6 +4,7 @@ import Development.Shake import Development.Shake.FilePath import System.Directory+import Data.List import General.Extra import Test.Type import Control.Monad@@ -12,7 +13,7 @@ main = testBuild test $ do     let inp x = x -<.> "in"     file <- newResource "log.txt" 1-    batch 3 ("*.out" %>) (\out -> do need [inp out]; return out) $ \outs -> do+    batch 3 ("*.out" %>) (\out -> do need [inp out]; pure out) $ \outs -> do         liftIO $ assertBool (length outs <= 3) "length outs <= 3"         withResource file 1 $ liftIO $ appendFile "log.txt" $ show (length outs) ++ "\n"         putInfo $ "Building batch: " ++ unwords outs@@ -35,14 +36,20 @@         o <- resultHasChanged out         writeFileLines out $ xs ++ ["On" | o] -    batch maxBound ("batch_max.*" %>) return $ \outs ->+    batch maxBound ("batch_max.*" %>) pure $ \outs ->         forM_ outs $ \out -> writeFile' out $ show $ length outs +    phony "sleep2" $ liftIO $ sleep 2+    batch 2 ("batch_profile.*" %>) (\x -> when ("1" `isSuffixOf` x) (liftIO $ sleep 1) >> pure x) $ \outs -> do+        liftIO $ sleep 2+        need ["sleep2"]+        forM_ outs $ \out -> writeFile' out "" + test build = do     forM_ [1..6] $ \i -> writeFile (show i <.> "in") $ show i     build ["--sleep","-j2"]-    assertBoolIO (do src <- readFile "log.txt"; return $ length (lines src) < 6) "some batching"+    assertBoolIO (do src <- readFile "log.txt"; pure $ length (lines src) < 6) "some batching"     writeFile "log.txt" ""     writeFile "2.in" "22"     writeFile "5.in" "55"@@ -96,3 +103,7 @@      build ["batch_max." ++ show i | i <- [1..100]]     assertContents "batch_max.72" "100"++    let names = ["batch_profile." ++ show i | i <- [1..2]]+    build names+    assertTimings build $ ("sleep2",2) : zip names [2,1]
src/Test/Benchmark.hs view
@@ -5,6 +5,7 @@ import Development.Shake import Test.Type import Text.Read+import Data.List.Extra import Development.Shake.FilePath  @@ -14,8 +15,8 @@  -- | Given a breadth and depth come up with a set of build files main = testBuildArgs test opts $ \opts -> do-    let depth   = last $ 75 : [x | Depth   x <- opts]-    let breadth = last $ 75 : [x | Breadth x <- opts]+    let depth   = lastDef 75 [x | Depth   x <- opts]+    let breadth = lastDef 75 [x | Breadth x <- opts]      want ["0." ++ show i | i <- [1..breadth]]     "*" %> \out -> do
src/Test/Builtin.hs view
@@ -24,18 +24,18 @@ addBuiltinFileRule :: Rules () addBuiltinFileRule = addBuiltinRule noLint noIdentity run     where-        fileContents (File x) = do b <- IO.doesFileExist x; if b then IO.readFile' x else return ""+        fileContents (File x) = do b <- IO.doesFileExist x; if b then IO.readFile' x else pure ""          run :: BuiltinRun File ()         run key old mode = do             now <- liftIO $ fileContents key             if mode == RunDependenciesSame && fmap BS.unpack old == Just now then-                return $ RunResult ChangedNothing (BS.pack now) ()+                pure $ RunResult ChangedNothing (BS.pack now) ()             else do                 (_, act) <- getUserRuleOne key (const Nothing) $ \(FileRule k act) -> if k == key then Just act else Nothing                 act                 now <- liftIO $ fileContents key-                return $ RunResult ChangedRecomputeDiff (BS.pack now) ()+                pure $ RunResult ChangedRecomputeDiff (BS.pack now) ()  fileRule :: FilePath -> Action () -> Rules () fileRule file act = addUserRule $ FileRule (File file) act@@ -47,7 +47,7 @@ main = testBuild test $ do     addBuiltinFileRule -    fileRule "a.txt" $ return ()+    fileRule "a.txt" $ pure ()     fileRule "b.txt" $ do         fileNeed "a.txt"         liftIO $ appendFile "log.txt" "X"
src/Test/C.hs view
@@ -25,4 +25,4 @@ cIncludes :: FilePath -> Action [FilePath] cIncludes x = do     Stdout stdout <- cmd "gcc" ["-MM",x]-    return $ drop 2 $ words stdout+    pure $ drop 2 $ words stdout
src/Test/Cache.hs view
@@ -12,7 +12,7 @@     vowels <- newCache $ \file -> do         src <- readFile' file         liftIO $ appendFile "trace.txt" "1"-        return $ length $ filter isDigit src+        pure $ length $ filter isDigit src     "*.out*" %> \x ->         writeFile' x . show =<< vowels (dropExtension x <.> "txt") 
src/Test/Cleanup.hs view
@@ -15,7 +15,7 @@ main = testSimple $ do     do -- survives releasing bottom         x <- newIORef (0 :: Int)-        handle (\(_ :: SomeException) -> return ()) $ withCleanup $ \cleanup -> do+        handle (\(_ :: SomeException) -> pure ()) $ withCleanup $ \cleanup -> do             _ <- register cleanup $ modifyIORef x (+1)             release undefined         (=== 1) =<< readIORef x@@ -47,7 +47,7 @@         Left Dummy <- try $ withCleanup $ \cleanup -> do             register cleanup (checkMasked "exception")             throwIO Dummy-        return ()+        pure ()   data Dummy = Dummy
src/Test/CloseFileHandles.hs view
@@ -51,7 +51,7 @@             \file -> actionBracket (openFile file AppendMode) hClose $                 \h -> do fd <- liftIO $ handleToFd h                          (Exit c, Stdout _, Stderr _) <- cmdWithOpts helper (show fd) :: Action (Exit, Stdout String, Stderr String)-                         return c+                         pure c      "defaultbehaviour" !> do         c <- callWithOpenFile cmd
src/Test/Command.hs view
@@ -98,12 +98,14 @@      "timeout2" !> do checkTimeout $ liftIO $ timeout 2 $ cmd_ helper "w20" -    -- commented out beause on Windows when you abort a Shell process you get a-    -- Do you want to terminate the batch file (Y/N)-    when False $ "timeout3" !> do checkTimeout $ liftIO $ timeout 2 $ cmd_ Shell helper "w20"+    -- disabled on Windows because when you abort a Shell process you get a+    -- "Do you want to terminate the batch file (Y/N)"+    unless isWindows $ "timeout3" !> do checkTimeout $ liftIO $ timeout 2 $ cmd_ Shell helper "w20"      "timeout4" !> do checkTimeout $ liftIO $ timeout 2 $ cmd_ helper "sw20" +    "timeout5" !> do checkTimeout $ liftIO $ timeout 2 $ cmd_ helper "i w20"+     "env" !> do         -- use liftIO since it blows away PATH which makes lint-tracker stop working         Stdout out <- liftIO $ cmd (Env [("FOO","HELLO SHAKE")]) Shell helper "vFOO"@@ -147,7 +149,7 @@         liftIO $ (===) (str, bs) $ second BS.pack $ dupe $ if isWindows then "foo\r\n" else "foo\n"         (Stdout str, Stdout bs) <- cmd helper "ofoo"         liftIO $ (str, bs) === ("foo\n", BS.pack $ if isWindows then "foo\r\n" else "foo\n")-        return ()+        pure ()      "large" !> do         (Stdout (_ :: String), CmdTime t1) <- cmd helper "r10000000"@@ -184,7 +186,7 @@ timer act = do     (CmdTime t, CmdLine x, r) <- act     liftIO $ putStrLn $ "Command " ++ x ++ " took " ++ show t ++ " seconds"-    return r+    pure r  waits :: (String -> IO ()) -> IO () waits op = f 0
src/Test/Config.hs view
@@ -5,7 +5,7 @@ import Development.Shake.FilePath import Development.Shake.Config import Test.Type-import Data.Char+import Data.List.Extra import qualified Data.HashMap.Strict as Map import Data.Maybe @@ -14,7 +14,7 @@     want ["hsflags.var","cflags.var","none.var","keys"]     usingConfigFile "config"     "*.var" %> \out -> do-        cfg <- getConfig $ map toUpper $ takeBaseName out+        cfg <- getConfig $ upper $ takeBaseName out         liftIO $ appendFile (out -<.> "times") "X"         writeFile' out $ fromMaybe "" cfg     "keys" %> \out -> do
src/Test/Database.hs view
@@ -33,7 +33,7 @@     (open, close) <- shakeOpenDatabase opts rules     db <- open -    ([12], after) <- shakeRunDatabase db [need ["a.out"] >> return 12]+    ([12], after) <- shakeRunDatabase db [need ["a.out"] >> pure 12]     assertContents "log.txt" "x"      writeFile "a.in" "A"@@ -41,7 +41,7 @@     assertContents "a.out" "A"     assertContents "log.txt" "xxx" -    ([13,14], _) <- shakeRunDatabase db [need ["a.out"] >> return 13, return 14]+    ([13,14], _) <- shakeRunDatabase db [need ["a.out"] >> pure 13, pure 14]     assertContents "log.txt" "xxx"      live <- shakeLiveFilesDatabase db@@ -77,10 +77,10 @@      -- check the progress thread gets killed properly on normal cleanup     ref <- newIORef 0-    opts <- return opts{shakeProgress = const $ bracket_ (modifyIORef ref succ) (modifyIORef ref succ) $ sleep 100}+    opts <- pure opts{shakeProgress = const $ bracket_ (modifyIORef ref succ) (modifyIORef ref succ) $ sleep 100}     (open, close) <- shakeOpenDatabase opts rules     db <- open-    ([12], after) <- shakeRunDatabase db [need ["a.out"] >> liftIO (modifyIORef ref succ) >> return 12]+    ([12], after) <- shakeRunDatabase db [need ["a.out"] >> liftIO (modifyIORef ref succ) >> pure 12]     (=== 3) =<< readIORef ref -- success if it all shuts down cleanly      -- and on an exception@@ -91,7 +91,7 @@     -- and on an external exception     writeIORef ref 0     bar <- newBarrier; bar2 <- newBarrier-    t <- flip forkFinally (signalBarrier bar2)  $ void $ shakeRunDatabase db $ return $ do+    t <- flip forkFinally (signalBarrier bar2)  $ void $ shakeRunDatabase db $ pure $ do         liftIO $ modifyIORef ref succ         liftIO $ signalBarrier bar ()         need ["sleep"]
src/Test/Digest.hs view
@@ -23,7 +23,7 @@         writeFile' out1 "X"         writeFile' out2 "Y" -    "leaf" ~> return ()+    "leaf" ~> pure ()     "node1.txt" %> \file -> do need ["leaf"]; writeFile' file "x"     "node2.txt" %> \file -> do need ["node1.txt"]; liftIO $ appendFile file "x" 
src/Test/Docs.hs view
@@ -10,7 +10,6 @@ import Control.Monad import Data.Char import Data.List.Extra-import Data.Maybe import System.Info import Data.Version.Extra @@ -87,6 +86,7 @@             ,"import Control.Concurrent"             ,"import Control.Exception"             ,"import Control.Monad"+            ,"import Control.Monad.Trans.Reader"             ,"import Data.ByteString(ByteString, pack, unpack)"             ,"import qualified Data.ByteString.Char8 as BS"             ,"import qualified System.Directory.Extra as IO"@@ -143,7 +143,7 @@             ,"instance Eq (OptDescr a)"             ,"(foo,bar,baz) = undefined"             ,"(p1,p2) = (0.0, 0.0)"-            ,"(r1,r2) = (return () :: Rules(), return () :: Rules())"+            ,"(r1,r2) = (pure () :: Rules(), pure () :: Rules())"             ,"xs = []"             ,"ys = []"             ,"os = [\"file.o\"]"@@ -171,11 +171,11 @@             ["Part_" ++ takeBaseName x ++ "_md" | x <- filesMd,                 takeBaseName x `notElem` ["Developing","Model","Architecture"]] -    let needModules = do mods <- readFileLines "Files.lst"; need [m <.> "hs" | m <- mods]; return mods+    let needModules = do mods <- readFileLines "Files.lst"; need [m <.> "hs" | m <- mods]; pure mods      "Main.hs" %> \out -> do         mods <- needModules-        writeFileLines out $ ["module Main(main) where"] ++ ["import " ++ m ++ "()" | m <- mods] ++ ["main = return ()"]+        writeFileLines out $ ["module Main(main) where"] ++ ["import " ++ m ++ "()" | m <- mods] ++ ["main = pure ()"]      "Success.txt" %> \out -> do         putInfo . ("Checking documentation for:\n" ++) =<< readFile' "Files.lst"@@ -212,7 +212,7 @@     in Code (dropWhileEnd isBlank $ unindent a) : findCodeMarkdown b     where         indented x = length (takeWhile isSpace x) >= 4-findCodeMarkdown (x:xs) = map (Code . return) (evens $ splitOn "`" x) ++ findCodeMarkdown xs+findCodeMarkdown (x:xs) = map (Code . pure) (evens $ splitOn "`" x) ++ findCodeMarkdown xs     where         evens (_:x:xs) = x : evens xs         evens _ = []@@ -223,7 +223,7 @@ -- RENDER THE CODE  showCode :: [Code] -> [String]-showCode = concat . zipWith f [1..] . nubOrd+showCode = concat . zipWithFrom f 1 . nubOrd     where         f i (Code x) | "#" `isPrefixOf` concat x = []                      | all whitelist x = []@@ -232,7 +232,7 @@  fixCmd :: [String] -> [String] fixCmd xs-    | all ("cmd_ " `isPrefixOf`) xs = xs ++ ["return () :: IO () "]+    | all ("cmd_ " `isPrefixOf`) xs = xs ++ ["pure () :: IO () "]     | otherwise = map (replace "Stdout out" "Stdout (out :: String)" . replace "Stderr err" "Stderr (err :: String)") xs  -- | Replace ... with undefined (don't use undefined with cmd; two ...'s should become one replacement)@@ -248,7 +248,7 @@ showStmt i [x] | filter isAlpha (fst $ word1 x) `elem` types = ["type Code_" ++ show i ++ " = " ++ x] showStmt i [x] | length (words x) <= 2 = ["code_" ++ show i ++ " = (" ++ x ++ ")"] -- deal with operators and sections showStmt i xs | all isPredicate xs, length xs > 1 =-    zipWith (\j x -> "code_" ++ show i ++ "_" ++ show j ++ " = " ++ x) [1..] xs+    zipWithFrom (\j x -> "code_" ++ show i ++ "_" ++ show j ++ " = " ++ x) 1 xs showStmt i xs = ("code_" ++ show i ++ " = do") : map ("  " ++) xs ++ ["  undefined" | isBindStmt $ last xs]  isPredicate :: String -> Bool@@ -282,11 +282,11 @@  -- | Find all pieces of text inside a given tag insideTag :: String -> String -> [String]-insideTag tag = map (fst . breakOn ("</" ++ tag ++ ">")) . drop 1 . splitOn ("<" ++ tag ++ ">")+insideTag tag = map (fst . breakOn ("</" ++ tag ++ ">")) . drop1 . splitOn ("<" ++ tag ++ ">")  -- | Given some HTML, find the raw text innerText :: String -> String-innerText ('<':xs) = innerText $ drop 1 $ dropWhile (/= '>') xs+innerText ('<':xs) = innerText $ drop1 $ dropWhile (/= '>') xs innerText ('&':xs)     | Just xs <- stripPrefix "quot;" xs = '\"' : innerText xs     | Just xs <- stripPrefix "lt;" xs = '<' : innerText xs@@ -307,7 +307,7 @@ -- | Identifiers that indicate the fragment is a type types :: [String] types = words $-    "MVar IO String FilePath Maybe [String] FSATrace Char ExitCode Change " +++    "MVar IO String FilePath Maybe [String] FSATrace Char ExitCode ReaderT Change " ++     "Action Resource Rebuild FilePattern Development.Shake.FilePattern " ++     "Lint Verbosity Rules CmdOption Int Double " ++     "NFData Binary Hashable Eq Typeable Show Applicative " ++@@ -332,7 +332,7 @@     where (a,b) = span (== '-') x  isCmdFlags :: String -> Bool-isCmdFlags = all (\x -> let y = fromMaybe x $ stripSuffix "," x in isCmdFlag y || isArg y) . words+isCmdFlags = all (\x -> let y = dropSuffix "," x in isCmdFlag y || isArg y) . words     where isArg = all (\x -> isUpper x || x == '=')  isEnvVar :: String -> Bool@@ -343,7 +343,7 @@  isProgram :: String -> Bool isProgram (words -> x:xs) = x `elem` programs && all (\x -> isCmdFlag x || isFilePath x || all isAlpha x || x == "&&") xs-    where programs = words "excel gcc cl make ghc ghci cabal distcc npm build tar git fsatrace ninja touch pwd runhaskell rot13 main shake stack rm cat sed sh apt-get build-multiple"+    where programs = words "excel gcc docker cl make ghc ghci cabal distcc npm build tar git fsatrace ninja touch pwd runhaskell rot13 main shake stack rm cat sed sh apt-get build-multiple" isProgram _ = False  -- | Should a fragment be whitelisted and not checked
src/Test/Errors.hs view
@@ -26,14 +26,14 @@ type instance RuleResult BadBinary = BadBinary instance Binary BadBinary where     put (BadBinary x) = put x-    get = do x <- get; if x == "bad" then error "get: BadBinary \"bad\"" else return $ BadBinary x+    get = do x <- get; if x == "bad" then error "get: BadBinary \"bad\"" else pure $ BadBinary x  main = testBuildArgs test optionsEnum $ \args -> do     "norule" %> \_ ->         need ["norule_isavailable"]      "failcreate" %> \_ ->-        return ()+        pure ()      ["failcreates", "failcreates2"] &%> \_ ->         writeFile' "failcreates" ""@@ -60,12 +60,12 @@             writeFile' out "0"             op $ do src <- IO.readFile' out; writeFile out $ show (read src + 1 :: Int)     catcher "finally1" $ actionFinally $ fail "die"-    catcher "finally2" $ actionFinally $ return ()+    catcher "finally2" $ actionFinally $ pure ()     catcher "finally3" $ actionFinally $ liftIO $ sleep 10     catcher "finally4" $ actionFinally $ need ["wait"]     "wait" ~> do liftIO $ sleep 10     catcher "exception1" $ actionOnException $ fail "die"-    catcher "exception2" $ actionOnException $ return ()+    catcher "exception2" $ actionOnException $ pure ()      "retry*" %> \out -> do         ref <- liftIO $ newIORef 3@@ -93,7 +93,7 @@     "tempfile" %> \out -> do         file <- withTempFile $ \file -> do             liftIO $ assertExists file-            return file+            pure file         liftIO $ assertMissing file         withTempFile $ \file -> do             liftIO $ assertExists file@@ -106,7 +106,7 @@             liftIO $ writeFile (dir </> "foo.txt") ""                 -- will throw if the directory does not exist             writeFile' out ""-            return file+            pure file         liftIO $ assertMissing file      phony "fail1" $ fail "die1"@@ -141,7 +141,7 @@         liftIO $ sleep 20         writeFile' out "" -    addOracle $ \(BadBinary x) -> return $ BadBinary $ 'b':x+    addOracle $ \(BadBinary x) -> pure $ BadBinary $ 'b':x     "badinput" %> \out -> do         askOracle $ BadBinary "bad"         liftIO $ appendFile out "x"
src/Test/Existence.hs view
@@ -11,17 +11,17 @@     cwd <- getCurrentDirectory     someFiles <- getDirectoryFilesIO cwd ["*"]     let someFile = head someFiles-    assertIsJust . getFileInfo $ fileNameFromString someFile+    assertIsJust $ getFileInfo False $ fileNameFromString someFile      let fileThatCantExist = someFile </> "fileThatCantExist"-    assertIsNothing . getFileInfo $ fileNameFromString fileThatCantExist+    assertIsNothing $ getFileInfo False $ fileNameFromString fileThatCantExist  assertIsJust :: IO (Maybe a) -> IO () assertIsJust action = do     Just _ <- action-    return ()+    pure ()  assertIsNothing :: IO (Maybe a) -> IO () assertIsNothing action = do     Nothing <- action-    return ()+    pure ()
src/Test/FilePath.hs view
@@ -7,7 +7,7 @@ import Test.Type import Test.QuickCheck import Control.Monad-import Data.List+import Data.List.Extra import qualified Data.ByteString.Char8 as BS import qualified Development.Shake.Internal.FileName as BS import System.Info.Extra@@ -18,7 +18,7 @@ newtype File = File String deriving Show  instance Arbitrary File where-    arbitrary = fmap File $ listOf $ oneof $ map return "a /\\:."+    arbitrary = fmap File $ listOf $ oneof $ map pure "a /\\:."     shrink (File x) = map File $ shrink x  @@ -66,7 +66,7 @@     Success{} <- quickCheckWithResult stdArgs{maxSuccess=1000} $ \(File x) ->         let y = norm x             sep = Native.isPathSeparator-            noDrive = if isWindows then drop 1 else id+            noDrive = if isWindows then drop1 else id             ps = [y /= ""                  ,null x || (sep (head x) == sep (head y) && sep (last x) == sep (last y))                  ,not $ "/./" `isInfixOf` y
src/Test/FilePattern.hs view
@@ -180,27 +180,27 @@     substitute  ["foo/bar/","test"] "//*a.txt" === "foo/bar/testa.txt"     substitute  ["foo/bar/","test"] "**/*a.txt" === "foo/bar/testa.txt" -    (False, Walk _) <- return $ walk ["*.xml"]-    (False, Walk _) <- return $ walk ["//*.xml"]-    (False, Walk _) <- return $ walk ["**/*.xml"]-    (False, WalkTo ([], [("foo",Walk _)])) <- return $ walk ["foo//*.xml"]-    (False, WalkTo ([], [("foo",Walk _)])) <- return $ walk ["foo/**/*.xml"]-    (False, WalkTo ([], [("foo",WalkTo ([],[("bar",Walk _)]))])) <- return $ walk ["foo/bar/*.xml"]-    (False, WalkTo (["a"],[("b",WalkTo (["c"],[]))])) <- return $ walk ["a","b/c"]-    ([], [("foo",WalkTo ([],[("bar",Walk _)]))]) <- let (False, Walk f) = walk ["*/bar/*.xml"] in return $ f ["foo"]-    (False, WalkTo ([],[("bar",Walk _),("baz",Walk _)])) <- return $ walk ["bar/*.xml","baz//*.c"]-    (False, WalkTo ([],[("bar",Walk _),("baz",Walk _)])) <- return $ walk ["bar/*.xml","baz/**/*.c"]-    (False, WalkTo ([], [])) <- return $ walk []-    (True, Walk _) <- return $ walk ["//"]-    (True, Walk _) <- return $ walk ["**"]-    (True, WalkTo _) <- return $ walk [""]+    (False, Walk _) <- pure $ walk ["*.xml"]+    (False, Walk _) <- pure $ walk ["//*.xml"]+    (False, Walk _) <- pure $ walk ["**/*.xml"]+    (False, WalkTo ([], [("foo",Walk _)])) <- pure $ walk ["foo//*.xml"]+    (False, WalkTo ([], [("foo",Walk _)])) <- pure $ walk ["foo/**/*.xml"]+    (False, WalkTo ([], [("foo",WalkTo ([],[("bar",Walk _)]))])) <- pure $ walk ["foo/bar/*.xml"]+    (False, WalkTo (["a"],[("b",WalkTo (["c"],[]))])) <- pure $ walk ["a","b/c"]+    ([], [("foo",WalkTo ([],[("bar",Walk _)]))]) <- let (False, Walk f) = walk ["*/bar/*.xml"] in pure $ f ["foo"]+    (False, WalkTo ([],[("bar",Walk _),("baz",Walk _)])) <- pure $ walk ["bar/*.xml","baz//*.c"]+    (False, WalkTo ([],[("bar",Walk _),("baz",Walk _)])) <- pure $ walk ["bar/*.xml","baz/**/*.c"]+    (False, WalkTo ([], [])) <- pure $ walk []+    (True, Walk _) <- pure $ walk ["//"]+    (True, Walk _) <- pure $ walk ["**"]+    (True, WalkTo _) <- pure $ walk [""]      Success{} <- quickCheckWithResult stdArgs{maxSuccess=1000} $ \(Pattern p) (Path x) ->         let label _ = property in             -- Ignore label to workaround QuickCheck space-leak             -- See #450 and https://github.com/nick8325/quickcheck/pull/93-        let b = p ?== x in (if b then property else label "No match") $ unsafePerformIO $ do f b p x; return True-    return ()+        let b = p ?== x in (if b then property else label "No match") $ unsafePerformIO $ do f b p x; pure True+    pure ()   walker :: FilePattern -> FilePath -> Bool
src/Test/Forward.hs view
@@ -16,7 +16,7 @@     os <- forP cs $ \c -> do         let o = c <.> "o"         cache $ cmd "gcc -c" [c] "-o" [o]-        return o+        pure o     cache $ cmd "gcc -o" ["Main" <.> exe] os     cache $ cmd ["." </> "Main" <.> exe] (FileStdout "output.txt") 
src/Test/History.hs view
@@ -19,7 +19,7 @@     let die :: a -> a         die x = if Die `elem` args then error "Die" else x -    phony "Phony" $ return ()+    phony "Phony" $ pure ()     "Phony.txt" %> \out -> do         need ["Phony"]         copyFile' "In.txt" out
src/Test/Lint.hs view
@@ -20,7 +20,7 @@     addOracle $ \Zero{} -> do         liftIO $ createDirectoryRecursive "dir"         liftIO $ setCurrentDirectory "dir"-        return $ Zero ()+        pure $ Zero ()      "changedir" %> \out -> do         Zero () <- askOracle $ Zero ()
src/Test/Monad.hs view
@@ -8,7 +8,7 @@ import Data.IORef import Control.Concurrent import Control.Exception-import Control.Monad+import Control.Monad.Extra import Control.Monad.IO.Class  @@ -17,8 +17,8 @@ run :: ro -> rw -> RAW () () ro rw a -> IO a run ro rw m = do     res <- newEmptyMVar-    runRAW return ro rw m $ void . tryPutMVar res-    either throwIO return =<< readMVar res+    runRAW pure ro rw m $ void . tryPutMVar res+    eitherM throwIO pure (readMVar res)   main = testSimple $ do@@ -34,7 +34,7 @@             dump "more"             modifyRW (++ "x")             dump "morex"-            return 100+            pure 100         liftIO $ conv res === Right 100         dump "morex"         putRW "new"@@ -45,7 +45,7 @@             dump "newz"             throwRAW Overflow             error "Should not have reached here"-            return 9+            pure 9         liftIO $ conv res === Left (Just Overflow)         dump "newz"         catchRAW (catchRAW (throwRAW Overflow) $ \_ -> modifyRW (++ "x")) $@@ -71,10 +71,10 @@     res === Left Overflow     res <- try $ run 1 "test" $ do         captureRAW $ \_ -> throwIO Overflow-        return "x"+        pure "x"     res === Left Overflow     -- test for GHC bug 11555-    runRAW return 1 "test" (throw Overflow :: RAW () () Int String ()) $ \res ->+    runRAW pure 1 "test" (throw Overflow :: RAW () () Int String ()) $ \res ->         mapLeft fromException res === Left (Just Overflow)      -- catch works properly if continuation called multiple times@@ -92,7 +92,7 @@      -- what if we throw an exception inside the continuation of run     ref <- newIORef 0-    res <- try $ runRAW return 1 "test" (return 1) $ \_ -> do+    res <- try $ runRAW pure 1 "test" (pure 1) $ \_ -> do         modifyIORef ref (+1)         throwIO Overflow     res === Left Overflow
src/Test/Ninja.hs view
@@ -9,7 +9,7 @@ import General.Extra import Test.Type import qualified Data.HashMap.Strict as Map-import Data.List+import Data.List.Extra import System.IO.Extra import qualified Run import System.Environment@@ -17,9 +17,13 @@  opts = Option "" ["arg"] (ReqArg Right "") "" +-- | Set to True to test with real Ninja+--   On Windows doesn't work because echo foo > 1 isn't supported+real_ninja = False+ main = testBuildArgs test [opts] $ \opts -> do     let real = "real" `elem` opts-    action $ if real+    action $ if real || real_ninja         then cmd "ninja" opts         else liftIO $ withArgs ("--lint":"--report=report.html":opts) Run.main @@ -75,7 +79,7 @@     run "-f../../src/Test/Ninja/lint.ninja good --lint"     runFail "-f../../src/Test/Ninja/lint.ninja bad --lint" "not a pre-dependency" -    res <- fmap (drop 1 . lines . fst) $ captureOutput $ runEx "-f../../src/Test/Ninja/compdb.ninja -t compdb cxx" "--quiet"+    res <- fmap (drop1 . lines . fst) $ captureOutput $ runEx "-f../../src/Test/Ninja/compdb.ninja -t compdb cxx" "--quiet"     want <- lines <$> readFile "../../src/Test/Ninja/compdb.output"     let eq a b | (a1,'*':a2) <- break (== '*') a = unless (a1 `isPrefixOf` b && a2 `isSuffixOf` b) $ a === b                | otherwise = a === b@@ -111,6 +115,10 @@     copyFile "../../src/Test/Ninja/restart.ninja" "restart.ninja"     runEx "-frestart.ninja" "--sleep"     assertExists "restart.txt"++    createDirectoryRecursive "directory1"+    createDirectoryRecursive "directory2"+    run "-f../../src/Test/Ninja/allow_directory.ninja"      when False $ do         -- currently fails because Shake doesn't match Ninja here
+ src/Test/Ninja/allow_directory.ninja view
@@ -0,0 +1,6 @@+rule create+    command = echo 1 > $out++build root: phony || allow_directory.txt directory1+build allow_directory.txt: create | directory2+default root
src/Test/Oracle.hs view
@@ -37,14 +37,14 @@ opt = [Option "" ["def"] (ReqArg (Right . uncurry Define . second tail . breakOn "=") "type=value") ""]  main = testBuildArgs test opt $ \args -> do-    addOracle $ \(T.RandomType _) -> return 42-    addOracle $ \(RandomType _) -> return (-42)+    addOracle $ \(T.RandomType _) -> pure 42+    addOracle $ \(RandomType _) -> pure (-42)     "randomtype.txt" %> \out -> do         a <- askOracle $ T.RandomType $ BinarySentinel ()         b <- askOracle $ RandomType $ BinarySentinel ()         writeFile' out $ show (a,b) -    addOracle $ \b -> return $ not b+    addOracle $ \b -> pure $ not b     "true.txt" %> \out -> writeFile' out . show =<< askOracle False      let add :: forall a . (ShakeValue a, RuleResult a ~ String) => String -> a -> Rules ()@@ -53,7 +53,7 @@                 liftIO $ appendFile ".log" "."                 writeFile' out =<< askOracle key             forM_ [val | Define nam val <- args, nam == name] $ \val ->-                addOracle $ \(_ :: a) -> return val+                addOracle $ \(_ :: a) -> pure val     add "string" ""     add "unit" ()     add "int" (0 :: Int)
src/Test/Parallel.hs view
@@ -29,8 +29,8 @@     phony "papplicative" $ do         need ["papplicative_1"]         need ["papplicative_2"]-        let ensureReturn = return ()-        ensureReturn -- should work even though we have a return+        let ensureReturn = pure ()+        ensureReturn -- should work even though we have a pure         need ["papplicative_3"]      "pseparate_*" %> \out -> do@@ -41,7 +41,7 @@      phony "pseparate" $ do         need ["pseparate_1"]-        liftIO $ return ()+        liftIO $ pure ()         need ["pseparate_2"]      sem <- liftIO $ newQSemN 0@@ -77,10 +77,13 @@         writeFile' "parallel" $ show peak      "parallels" %> \out -> do-        xs <- parallel $ replicate 5 $ parallel $ map return [1..5]+        xs <- parallel $ replicate 5 $ parallel $ map pure [1..5]         writeFile' out $ show xs +    phony "timings" $+        void $ parallel $ map (liftIO . sleep) [1, 2, 0, 1] + test build = do     build ["clean"]     writeFile "A.txt" "AAA"@@ -106,3 +109,8 @@     assertContents "pseparate.log" "[][]"     build ["papplicative","-j3"]     build ["ptraverse","-j8"]++    build ["timings","-j6"]+    assertTimings build [("timings",4)]+    build ["timings","-j1"]+    assertTimings build [("timings",4)]
src/Test/Pool.hs view
@@ -7,7 +7,9 @@ import Control.Concurrent.Extra import Control.Exception.Extra import Control.Monad+import System.Time.Extra import Data.Either.Extra+import General.Timing   main = testSimple $ do@@ -23,10 +25,10 @@             runPool deterministic n $ \pool ->                 replicateM_ 5 $                     add pool $ do-                        modifyVar_ var $ \(mx,now) -> return (max (now+1) mx, now+1)+                        modifyVar_ var $ \(mx,now) -> pure (max (now+1) mx, now+1)                         -- requires that all tasks get spawned within 0.1s                         sleep 0.1-                        modifyVar_ var $ \(mx,now) -> return (mx,now-1)+                        modifyVar_ var $ \(mx,now) -> pure (mx,now-1)             res <- readVar var             res === (min n 5, 0) @@ -42,7 +44,7 @@                     flip finally (signalBarrier stopped ()) $ do                         signalBarrier started ()                         sleep 10-                        modifyVar_ good $ const $ return False+                        modifyVar_ good $ const $ pure False         -- note that the pool finishing means we started killing our threads         -- not that they have actually died         mapLeft fromException res === Left (Just Underflow)@@ -60,7 +62,7 @@         -- check high priority stuff runs first         res <- newVar ""         runPool deterministic 1 $ \pool -> do-            let note c = modifyVar_ res $ return . (c:)+            let note c = modifyVar_ res $ pure . (c:)             -- deliberately in a random order             addPool PoolBatch pool $ note 'b'             addPool PoolException pool $ note 'e'@@ -92,3 +94,12 @@             add pool $ try_ $ (do signalBarrier started (); sleep 10) `finally` (do sleep 1; writeVar var True)             add pool $ do waitBarrier started; throw Overflow         (=== True) =<< readVar var++    -- benchmark for testing thread performance, see https://github.com/ndmitchell/shake/pull/751+    when False $ do+        resetTimings+        withNumCapabilities 4 $ do+            (d, _) <- duration $ runPool False 4 $ \pool ->+                replicateM_ 200000 $ addPool PoolStart pool $ return ()+            print d+            print =<< getTimings
src/Test/Progress.hs view
@@ -7,7 +7,7 @@ import System.FilePath  -main = testBuild test $ return ()+main = testBuild test $ pure ()   -- | Given a list of todo times, get out a list of how long is predicted@@ -19,7 +19,7 @@     let resolution = 10000 -- Use resolution to get extra detail on the numbers     let done = scanl (+) 0 $ map (min mxDone . max 0) $ zipWith (-) todo (tail todo)     let res = progressReplay $ zip (map (*resolution) [1..]) $ tail $ zipWith (\t d -> mempty{timeBuilt=d*resolution,timeTodo=(t*resolution,0)}) todo done-    return $ (0/0) : map ((/ resolution) . actualSecs) res+    pure $ (0/0) : map ((/ resolution) . actualSecs) res   test build = do
src/Test/Random.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE PatternGuards #-}  module Test.Random(main) where@@ -41,7 +42,7 @@             i <- randomRIO (0, 25)             sleep $ intToDouble i / 100 -    forM_ (map read $ filter (isNothing . asDuration) args) $ \x -> case x of+    forM_ (map read $ filter (isNothing . asDuration) args) $ \case         Want xs -> want $ map (toFile . Output) xs         Logic out srcs -> toFile (Output out) %> \out -> do             res <- fmap (show . Multiple) $ forM srcs $ \src -> do@@ -64,7 +65,7 @@         args <- getArgs         let bound = listToMaybe $ reverse $ mapMaybe asDuration args         time <- offsetTime-        return $ when (isJust bound) $ do+        pure $ when (isJust bound) $ do             now <- time             when (now > fromJust bound) exitSuccess @@ -88,9 +89,9 @@         res <- try_ $ build $ "--exception" : ("-j" ++ show j) : map ((++) "--arg=" . show) (logicBang ++ [Want [i | Logic i _ <- logicBang]])         case res of             Left err-                | "BANG" `isInfixOf` show err -> return () -- error I expected+                | "BANG" `isInfixOf` show err -> pure () -- error I expected                 | otherwise -> error $ "UNEXPECTED ERROR: " ++ show err-            _ -> return () -- occasionally we only put BANG in places with no dependenies that don't get rebuilt+            _ -> pure () -- occasionally we only put BANG in places with no dependenies that don't get rebuilt         runLogic [] $ logic ++ [Want [i | Logic i _ <- logic]]         where             runLogic :: [Int] -> [Logic] -> IO ()@@ -106,7 +107,7 @@                  let value i =                         let ys = head [ys | Logic j ys <- xs, j == i]-                        in Multiple $ flip map ys $ map $ \i -> case i of+                        in Multiple $ flip map ys $ map $ \case                             Input i -> Single $ if i `elem` negated then negate i else i                             Output i -> value i                             Bang -> error "BANG"@@ -122,13 +123,13 @@     i <- randomRIO (0, length xs - 1)     let (before,now:after) = splitAt i xs     now <- f now-    return $ before ++ now : after+    pure $ before ++ now : after     where         f (Logic log xs) = do             i <- randomRIO (0, length xs)             let (before,after) = splitAt i xs-            return $ Logic log $ before ++ [Bang] : after-        f x = return x+            pure $ Logic log $ before ++ [Bang] : after+        f x = pure x   randomLogic :: IO [Logic] -- only Logic constructors@@ -136,7 +137,7 @@     rules <- randomRIO (1,100)     f rules $ map Input inputRange     where-        f 0 _ = return []+        f 0 _ = pure []         f i avail = do             needs <- randomRIO (0,3)             xs <- replicateM needs $ do
src/Test/Rebuild.hs view
@@ -4,6 +4,7 @@ import Development.Shake import Test.Type import Text.Read+import Data.List.Extra import Control.Monad import General.GetOpt @@ -14,7 +15,7 @@  main = testBuildArgs test opts $ \args -> do     let timestamp = concat [x | Timestamp x <- args]-    let p = last $ PatWildcard : [x | Pattern x <- args]+    let p = lastDef PatWildcard [x | Pattern x <- args]     want ["a.txt"]     pat p "a.txt" $ \out -> do         src <- readFile' "b.txt"
src/Test/Resources.hs view
@@ -3,7 +3,7 @@  import Development.Shake import Test.Type-import Data.List+import Data.List.Extra import System.FilePath import Control.Exception.Extra import System.Time.Extra@@ -56,7 +56,7 @@         res <- newThrottle "throttle" 2 0.4         phony "throttle" $ need ["t_file1.1","t_file2.1","t_file3.2","t_file4.1","t_file5.2"]         "t_*.*" %> \out -> do-            withResource res (read $ drop 1 $ takeExtension out) $+            withResource res (read $ drop1 $ takeExtension out) $                 when (takeBaseName out == "t_file3") $ liftIO $ sleep 0.2             writeFile' out "" 
src/Test/Self.hs view
@@ -29,7 +29,7 @@      ghcPkg <- addOracleHash $ \GhcPkg{} -> do         Stdout out <- quietly $ cmd "ghc-pkg list --simple-output"-        return $ words out+        pure $ words out      ghcFlags <- addOracleHash $ \GhcFlags{} ->         map ("-package=" ++) <$> readFileLines ".pkgs"
src/Test/SelfMake.hs view
@@ -25,7 +25,7 @@      ghcPkg <- addOracleHash $ \GhcPkg{} -> do         Stdout out <- quietly $ cmd "ghc-pkg list --simple-output"-        return $ words out+        pure $ words out      ghcFlags <- addOracleHash $ \GhcFlags{} ->         map ("-package=" ++) <$> readFileLines ".pkgs"
src/Test/Targets.hs view
@@ -13,22 +13,22 @@  rules :: Rules () rules = do-    withTargetDocs "A phony target" $ phony "phony1" $ return ()+    withTargetDocs "A phony target" $ phony "phony1" $ pure () -    "file1" %> \_ -> return ()-    ["file2", "file3"] |%> \_ -> return ()-    ["file4", "file5"] &%> \_ -> return ()+    "file1" %> \_ -> pure ()+    ["file2", "file3"] |%> \_ -> pure ()+    ["file4", "file5"] &%> \_ -> pure () -    "file6" %> \_ -> return ()-    ["file7", "file8"] |%> \_ -> return ()-    ["file9", "file10"] &%> \_ -> return ()+    "file6" %> \_ -> pure ()+    ["file7", "file8"] |%> \_ -> pure ()+    ["file9", "file10"] &%> \_ -> pure () -    withTargetDocs "Builds something really good" $ phony "phony2" $ return ()+    withTargetDocs "Builds something really good" $ phony "phony2" $ pure ()     withTargetDocs "bad docs" $ do-        withTargetDocs "a great file" $ "file11" %> \_ -> return ()-        withTargetDocs "awesome files" $ ["file12", "file13"] &%> \_ -> return ()-        phony "Foo" $ return ()-        withoutTargets $ phony "Bar" $ return ()+        withTargetDocs "a great file" $ "file11" %> \_ -> pure ()+        withTargetDocs "awesome files" $ ["file12", "file13"] &%> \_ -> pure ()+        phony "Foo" $ pure ()+        withoutTargets $ phony "Bar" $ pure ()      addHelpSuffix "Don't Panic"     addHelpSuffix "Know where your towel is"
src/Test/Thread.hs view
@@ -33,14 +33,14 @@     isAnswer 1 $ withCleanup $ \cleanup -> do         allocateThread cleanup finish         sleep 0.1-        return 1+        pure 1     finished 1      putStrLn "## allocateThread, main finishes first"     isAnswer 1 $ withCleanup $ \cleanup -> do         allocateThread cleanup $ (unpause >> sleep 100) `finally` finish         pause-        return 1+        pure 1     finished 1      putStrLn "## allocateThread, spawned throws an exception"@@ -54,16 +54,16 @@         allocateThread cleanup $ (unpause >> sleep 100) `finally` finish         pause         throw Overflow-        return 1+        pure 1     finished 1      putStrLn "## withThreadsBoth, both succeed"-    isAnswer (2,3) $ withThreadsBoth (return 2) (return 3)+    isAnswer (2,3) $ withThreadsBoth (pure 2) (pure 3)      putStrLn "## withThreadsBoth, left fails"-    isException Overflow $ withThreadsBoth (pause >> throw Overflow >> return 1) ((unpause >> return 3) `finally` finish)+    isException Overflow $ withThreadsBoth (pause >> throw Overflow >> pure 1) ((unpause >> pure 3) `finally` finish)     finished 1      putStrLn "## withThreadsBoth, right fails"-    isException Overflow $ withThreadsBoth ((unpause >> return 3) `finally` finish) (pause >> throw Overflow >> return 1)+    isException Overflow $ withThreadsBoth ((unpause >> pure 3) `finally` finish) (pause >> throw Overflow >> pure 1)     finished 1
src/Test/Tup.hs view
@@ -22,7 +22,7 @@                     | takeExtension x == ".a" = takeBaseName x </> "lib" ++ x                     | otherwise = error $ "Unknown extension, " ++ x             x <- fromMaybe (error $ "Missing config key, " ++ key) <$> getConfig key-            return $ map f $ words x+            pure $ map f $ words x      (\x -> x -<.> exe == x) ?> \out -> do         os <- objects "" $ takeBaseName out <.> "exe"
src/Test/Type.hs view
@@ -10,6 +10,7 @@     assertBool, assertBoolIO, assertException, assertExceptionAfter,     assertContents, assertContentsUnordered, assertContentsWords, assertContentsInfix,     assertExists, assertMissing,+    assertTimings,     (===),     (&?%>),     Pat(PatWildcard), pat,@@ -27,7 +28,8 @@  import Control.Exception.Extra import Control.Monad.Extra-import Data.List+import Data.List.Extra+import Text.Read(readMaybe) import Data.Maybe import Data.Either import Data.Typeable@@ -56,10 +58,10 @@ testBuild f g = testBuildArgs f [] (const g)  testSimple :: IO () -> IO () -> IO ()-testSimple act = testBuild (const act) (return ())+testSimple act = testBuild (const act) (pure ())  testNone :: IO () -> IO ()-testNone _ = return ()+testNone _ = pure ()  shakenEx     :: Bool@@ -74,7 +76,7 @@     name:args <- getArgs     putStrLn $ "## BUILD " ++ unwords (name:args)     let forward = "--forward" `elem` args-    args <- return $ delete "--forward" args+    args <- pure $ delete "--forward" args     let out = "output/" ++ name ++ "/"     let change = if not reenter then withCurrentDirectory out else id     let clean = do@@ -103,9 +105,9 @@          args -> change $ do             t <- tracker-            opts <- return shakeOptions{shakeFiles = "."}+            opts <- pure shakeOptions{shakeFiles = "."}             cwd <- getCurrentDirectory-            opts <- return $ if forward then forwardOptions opts{shakeLintInside=[""]} else opts+            opts <- pure $ if forward then forwardOptions opts{shakeLintInside=[""]} else opts                 {shakeLint = Just t                 ,shakeLintInside = [cwd </> ".." </> ".."]                 ,shakeLintIgnore = [".cabal-sandbox/**",".stack-work/**","../../.stack-work/**"]}@@ -118,13 +120,13 @@                     let (extra1, extra2) = partitionEithers extra                     when (Clean `elem` extra1) clean                     when (Sleep `elem` extra1) sleeper-                    so <- return $ if UsePredicate `notElem` extra1 then so else+                    so <- pure $ if UsePredicate `notElem` extra1 then so else                         so{shakeExtra = addShakeExtra UsePredicateYes $ shakeExtra so}                     if "clean" `elem` files then-                        clean >> return Nothing-                    else return $ Just $ (,) so $ do+                        clean >> pure Nothing+                    else pure $ Just $ (,) so $ do                         -- if you have passed sleep, suppress the "no actions" warning-                        when (Sleep `elem` extra1) $ action $ return ()+                        when (Sleep `elem` extra1) $ action $ pure ()                         rules extra2 files  data Flags@@ -149,12 +151,12 @@ tracker :: IO Lint tracker = do     fsatrace <- findExecutable $ "fsatrace" <.> exe-    return $ if isJust fsatrace then LintFSATrace else LintBasic+    pure $ if isJust fsatrace then LintFSATrace else LintBasic  hasTracker :: IO Bool hasTracker = do     t <- tracker-    return $ t == LintFSATrace+    pure $ t == LintFSATrace  assertFail :: String -> IO a assertFail msg = error $ "ASSERTION FAILED: " ++ msg@@ -186,7 +188,7 @@     t <- timeout n act     case t of         Nothing -> assertFail $ "Expected to complete within " ++ show n ++ " seconds, but did not"-        Just v -> return v+        Just v -> pure v  assertContents :: FilePath -> String -> IO () assertContents file want = do@@ -221,6 +223,23 @@ assertException :: [String] -> IO a -> IO () assertException = assertExceptionAfter id +assertTimings :: ([String] -> IO ()) -> [(String, Seconds)] -> IO ()+assertTimings build expect = do+    build ["--report=report.json","--no-build"]+    src <- IO.readFile' "report.json"+    let f ('[':'\"':xs)+            | (name,_:',':xs) <- break (== '\"') xs+            , num <- takeWhile (`notElem` ",]") xs+            , Just num <- readMaybe num+            = (name, num :: Double)+        f x = error $ "Failed to parse JSON output in assertTimings, " ++ show x+    let got = [f x | x <- map drop1 $ lines src, x /= ""]+    forM_ expect $ \(name, val) ->+        case lookup name got of+            Nothing -> assertFail $ "Couldn't find key " ++ show name ++ " in profiling output"+            Just v -> assertBool (v >= val && v < (val + 1)) $ "Unexpected value, got " ++ show v ++ ", hoping for " ++ show val ++ " (+ 1 sec)"++ defaultTest :: ([String] -> IO ()) -> IO () defaultTest build = do     build ["--abbrev=output=$OUT","-j3","--report"]@@ -241,14 +260,14 @@     mtimes <- forM [1..2] $ \i -> fmap fst $ duration $ do         writeFile file $ show i         let time = fmap (fst . fromMaybe (error "File missing during sleepFileTimeCalibrate")) $-                        getFileInfo $ fileNameFromString file+                        getFileInfo False $ fileNameFromString file         t1 <- time         flip loopM 0 $ \j -> do             writeFile file $ show (i,j)             t2 <- time-            return $ if t1 == t2 then Left $ j+1 else Right ()+            pure $ if t1 == t2 then Left $ j+1 else Right ()     putStrLn $ "Longest file modification time lag was " ++ show (ceiling (maximum' mtimes * 1000)) ++ "ms"-    return $ sleep $ min 1 $ maximum' mtimes * 2+    pure $ sleep $ min 1 $ maximum' mtimes * 2   removeFilesRandom :: FilePath -> IO Int@@ -257,7 +276,7 @@     n <- randomRIO (0,length files)     rs <- replicateM (length files) (randomIO :: IO Double)     mapM_ (removeFile . snd) $ sort $ zip rs files-    return n+    pure n   getDirectoryContentsRecursive :: FilePath -> IO [FilePath]@@ -265,7 +284,7 @@     xs <- IO.getDirectoryContents dir     (dirs,files) <- partitionM IO.doesDirectoryExist [dir </> x | x <- xs, not $ "." `isPrefixOf` x]     rest <- concatMapM getDirectoryContentsRecursive dirs-    return $ files++rest+    pure $ files++rest   copyDirectoryChanged :: FilePath -> FilePath -> IO ()@@ -309,7 +328,7 @@     get = do         x <- get         let want = show (typeRep (Proxy :: Proxy a))-        if x == want then return $ BinarySentinel () else+        if x == want then pure $ BinarySentinel () else             error $ "BinarySentinel failed, got " ++ show x ++ " but wanted " ++ show want  newtype RandomType = RandomType (BinarySentinel ())
src/Test/Unicode.hs view
@@ -4,6 +4,7 @@ import Development.Shake import Development.Shake.FilePath import Test.Type+import Data.List.Extra import General.GetOpt import Control.Monad import GHC.IO.Encoding@@ -23,7 +24,7 @@     ,Option "" ["want"] (ReqArg (Right . Want) "") ""]  main = testBuildArgs test opts $ \xs -> do-    let pre = last $ "" : [decode x | Prefix x <- xs :: [Arg]]+    let pre = lastDef "" [decode x | Prefix x <- xs :: [Arg]]     want [decode x | Want x <- xs]      pre ++ "dir/*" %> \out -> do
src/Test/Verbosity.hs view
@@ -19,7 +19,7 @@             b <- getVerbosity             c <- quietly getVerbosity             d <- fmap shakeVerbosity getShakeOptions-            return [a,b,c,d]+            pure [a,b,c,d]         z <- getVerbosity         writeFile' out $ unwords $ map show $ [x] ++ ys ++ [z] 
src/Test/Version.hs view
@@ -5,6 +5,7 @@ import Development.Shake import Development.Shake.Classes import General.GetOpt+import Data.List.Extra import Text.Read import Test.Type @@ -21,12 +22,12 @@      "foo.txt" %> \file -> liftIO $ appendFile file "x" -    let ver = head $ [x | Ver x <- opts] ++ [0]+    let ver = headDef 0 [x | Ver x <- opts]     versioned ver $ "ver.txt" %> \out -> liftIO $ appendFile out $ show ver      versioned ver $ addOracleCache $ \(Oracle ()) -> do         liftIO $ appendFile "oracle.in" $ show ver-        return $ ver `mod` 2+        pure $ ver `mod` 2     "oracle.txt" %> \out -> do         v <- askOracle $ Oracle ()         liftIO $ appendFile out $ show v