packages feed

shake-0.15: src/Run.hs

module Run(main) where

import Development.Make.All
import Development.Ninja.All
import System.Environment
import Development.Shake
import Development.Shake.FilePath
import General.Timing
import Data.List.Extra
import Control.Monad.Extra
import Control.Exception.Extra
import Data.Maybe
import qualified System.Directory as IO
import System.Console.GetOpt
import System.Process
import System.Exit
import General.Extra


main :: IO ()
main = do
    resetTimings
    args <- getArgs
    withArgs ("--no-time":args) $
        shakeArgsWith shakeOptions{shakeCreationCheck=False} flags $ \opts targets -> do
            let tool = listToMaybe [x | Tool x <- opts]
            (mode, makefile) <- case reverse [x | UseMakefile x <- opts] of
                x:_ -> return (modeMakefile x, x)
                _ -> findMakefile
            case mode of
                Ninja -> runNinja makefile targets tool
                _ | isJust tool -> error "--tool flag is not supported without a .ninja Makefile"
                Exe -> do exitOnFailure =<< rawSystem (toNative makefile) args; return Nothing
                Haskell -> do exitOnFailure =<< rawSystem "runhaskell" (makefile:args); return Nothing
                Make -> fmap Just $ runMakefile makefile targets

exitOnFailure :: ExitCode -> IO ()
exitOnFailure x = when (x /= ExitSuccess) $ exitWith x


data Flag = UseMakefile FilePath
          | Tool String

flags = [Option "f" ["file","makefile"] (ReqArg (Right . UseMakefile) "FILE") "Read FILE as a makefile."
        ,Option "t" ["tool"] (ReqArg (Right . Tool) "TOOL") "Ninja-compatible tools."
        ]

data Mode = Make | Ninja | Haskell | Exe

modeMakefile :: FilePath -> Mode
modeMakefile x | takeExtension x == ".ninja" = Ninja
               | takeExtension x `elem` [".hs",".lhs"] = Haskell
               | otherwise = Make


findMakefile :: IO (Mode, FilePath)
findMakefile = do
    let files = [(Exe,".shake" </> "shake" <.> exe)
                ,(Haskell,"Shakefile.hs"),(Haskell,"Shakefile.lhs")
                ,(Make,"makefile"),(Make,"Makefile")
                ,(Ninja,"build.ninja")]
    res <- findM (fmap (either (const False) id) . try_ . IO.doesFileExist . snd) files
    case res of
        Just x -> return x
        Nothing -> do
            let Just (p1,p2) = unsnoc ["`" ++ x ++ "'" | (_,x) <- files]
            errorIO $ "Could not find " ++ intercalate ", " p1 ++ " or " ++ p2