-- | 'recompile force', recompile @~\/.xmonad\/xmonad.hs@ when any of the
-- following apply:
--
--      * force is 'True'
--
--      * the xmonad executable does not exist
--
--      * the xmonad executable is older than xmonad.hs or any file in
--        ~\/.xmonad\/lib
--
-- The -i flag is used to restrict recompilation to the xmonad.hs file only,
-- and any files in the ~\/.xmonad\/lib directory.
--
-- Compilation errors (if any) are logged to ~\/.xmonad\/xmonad.errors.  If
-- GHC indicates failure with a non-zero exit code, an xmessage displaying
-- that file is spawned.
--
-- 'False' is returned if there are compilation errors.
--
recompile :: MonadIO m => Bool -> m Bool
recompile force = io $ do
    dir <- getXMonadDir
    let binn = "xmonad-"++arch++"-"++os
        bin  = dir </> binn
        base = dir </> "xmonad"
        err  = base ++ ".errors"
        src  = base ++ ".hs"
        lib  = dir </> "lib"
    libTs <- mapM getModTime . Prelude.filter isSource =<< allFiles lib
    srcT <- getModTime src
    binT <- getModTime bin
    if force || any (binT <) (srcT : libTs)
      then do
        -- temporarily disable SIGCHLD ignoring:
        uninstallSignalHandlers
        status <- bracket (openFile err WriteMode) hClose $ \h ->
            waitForProcess =<< runProcess "ghc" ["--make", "xmonad.hs", "-i", "-ilib", "-fforce-recomp", "-v0", "-o",binn] (Just dir)
                                    Nothing Nothing Nothing (Just h)

        -- re-enable SIGCHLD:
        installSignalHandlers

        -- now, if it fails, run xmessage to let the user know:
        when (status /= ExitSuccess) $ do
            ghcErr <- readFile err
            let msg = unlines $
                    ["Error detected while loading xmonad configuration file: " ++ src]
                    ++ lines (if null ghcErr then show status else ghcErr)
                    ++ ["","Please check the file for errors."]
            -- nb, the ordering of printing, then forking, is crucial due to
            -- lazy evaluation
            hPutStrLn stderr msg
            forkProcess $ executeFile "xmessage" True ["-default", "okay", msg] Nothing
            return ()
        return (status == ExitSuccess)
      else return True
 where getModTime f = catch (Just <$> getModificationTime f) (\(SomeException _) -> return Nothing)
       isSource = flip elem [".hs",".lhs",".hsc"]
       allFiles t = do
            let prep = map (t</>) . Prelude.filter (`notElem` [".",".."])
            cs <- prep <$> catch (getDirectoryContents t) (\(SomeException _) -> return [])
            ds <- filterM doesDirectoryExist cs
            concat . ((cs \\ ds):) <$> mapM allFiles ds

-- | Conditionally run an action, using a @Maybe a@ to decide.
recompile :: MonadIO m => Bool -> m Bool
recompile force = io $ do
    dir <- getXMonadDir
    let binn = "xmonad-"++arch++"-"++os
        bin  = dir </> binn
        base = dir </> "xmonad"
        err  = base ++ ".errors"
        src  = base ++ ".hs"
        lib  = dir </> "lib"
    libTs <- mapM getModTime . Prelude.filter isSource =<< allFiles lib
    srcT <- getModTime src
    binT <- getModTime bin
    if force || any (binT <) (srcT : libTs)
      then do
        -- temporarily disable SIGCHLD ignoring:
        uninstallSignalHandlers
        status <- bracket (openFile err WriteMode) hClose $ \h ->
            waitForProcess =<< runProcess "ghc" ["--make", "xmonad.hs", "-i", "-ilib", "-fforce-recomp", "-v0", "-o",binn] (Just dir)
                                    Nothing Nothing Nothing (Just h)

        -- re-enable SIGCHLD:
        installSignalHandlers

        -- now, if it fails, run xmessage to let the user know:
        when (status /= ExitSuccess) $ do
            ghcErr <- readFile err
            let msg = unlines $
                    ["Error detected while loading xmonad configuration file: " ++ src]
                    ++ lines (if null ghcErr then show status else ghcErr)
                    ++ ["","Please check the file for errors."]
            -- nb, the ordering of printing, then forking, is crucial due to
            -- lazy evaluation
            hPutStrLn stderr msg
            forkProcess $ executeFile "xmessage" True ["-default", "okay", msg] Nothing
            return ()
        return (status == ExitSuccess)
      else return True
 where getModTime f = catch (Just <$> getModificationTime f) (\(SomeException _) -> return Nothing)
       isSource = flip elem [".hs",".lhs",".hsc"]
       allFiles t = do
            let prep = map (t</>) . Prelude.filter (`notElem` [".",".."])
            cs <- prep <$> catch (getDirectoryContents t) (\(SomeException _) -> return [])
            ds <- filterM doesDirectoryExist cs
            concat . ((cs \\ ds):) <$> mapM allFiles ds

-- | Conditionally run an action, using a @Maybe a@ to decide.
recompile force = io $ do
    dir <- getXMonadDir
    let binn = "xmonad-"++arch++"-"++os
        bin  = dir </> binn
        base = dir </> "xmonad"
        err  = base ++ ".errors"
        src  = base ++ ".hs"
        lib  = dir </> "lib"
    libTs <- mapM getModTime . Prelude.filter isSource =<< allFiles lib
    srcT <- getModTime src
    binT <- getModTime bin
    if force || any (binT <) (srcT : libTs)
      then do
        -- temporarily disable SIGCHLD ignoring:
        uninstallSignalHandlers
        status <- bracket (openFile err WriteMode) hClose $ \h ->
            waitForProcess =<< runProcess "ghc" ["--make", "xmonad.hs", "-i", "-ilib", "-fforce-recomp", "-v0", "-o",binn] (Just dir)
                                    Nothing Nothing Nothing (Just h)

        -- re-enable SIGCHLD:
        installSignalHandlers

        -- now, if it fails, run xmessage to let the user know:
        when (status /= ExitSuccess) $ do
            ghcErr <- readFile err
            let msg = unlines $
                    ["Error detected while loading xmonad configuration file: " ++ src]
                    ++ lines (if null ghcErr then show status else ghcErr)
                    ++ ["","Please check the file for errors."]
            -- nb, the ordering of printing, then forking, is crucial due to
            -- lazy evaluation
            hPutStrLn stderr msg
            forkProcess $ executeFile "xmessage" True ["-default", "okay", msg] Nothing
            return ()
        return (status == ExitSuccess)
      else return True
 where getModTime f = catch (Just <$> getModificationTime f) (\(SomeException _) -> return Nothing)
       isSource = flip elem [".hs",".lhs",".hsc"]
       allFiles t = do
            let prep = map (t</>) . Prelude.filter (`notElem` [".",".."])
            cs <- prep <$> catch (getDirectoryContents t) (\(SomeException _) -> return [])
            ds <- filterM doesDirectoryExist cs
            concat . ((cs \\ ds):) <$> mapM allFiles ds

-- | Conditionally run an action, using a @Maybe a@ to decide.