Created
June 29, 2015 03:43
-
-
Save mgsloan/d944011a659e31616ab3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/yesod-bin/BuildProgram.hs b/yesod-bin/BuildProgram.hs | |
new file mode 100644 | |
index 0000000..2bdf11b | |
--- /dev/null | |
+++ b/yesod-bin/BuildProgram.hs | |
@@ -0,0 +1,50 @@ | |
+module BuildProgram where | |
+ | |
+import System.Exit (ExitCode (..), exitWith) | |
+import System.Process (ProcessHandle, createProcess, getProcessExitCode, proc) | |
+import Control.Concurrent (threadDelay) | |
+ | |
+data BuildProgram | |
+ = CabalLike String -- ^ String indicates which cabal-like program to use (cabal or cabal-dev) | |
+ | Stack FilePath -- ^ The FilePath indicates which directory has 'stack.yaml' | |
+ deriving (Show, Eq) | |
+ | |
+buildProgramName :: BuildProgram -> String | |
+buildProgramName (CabalLike program) = program | |
+buildProgramName (Stack _) = "stack" | |
+ | |
+runConfigure :: BuildProgram -> IO () | |
+runConfigure (Stack fp) = putStrLn "No need to configure with stack." | |
+runConfigure (CabalLike program) = exitOnFailure =<< runProcess' program ["configure"] | |
+ | |
+runTest :: BuildProgram -> IO () | |
+runTest (Stack fp) = fail "FIXME" | |
+runTest (CabalLike program) = do | |
+ exitOnFailure =<< runProcess' program ["configure", "--enable-tests", "-flibrary-only"] | |
+ exitOnFailure =<< runProcess' program ["build"] | |
+ exitOnFailure =<< runProcess' program ["test"] | |
+ | |
+runBuild :: BuildProgram -> Bool -> [String] -> IO ExitCode | |
+runBuild (Stack fp) silent args = | |
+ runProcess' "stack" ((if silent then ["--verbosity", "silent", "build"] else ["build"]) ++ args) | |
+runBuild (CabalLike program) silent args = | |
+ runProcess' program ((if silent then ["build", "-v0"] else ["build"]) ++ args) | |
+ | |
+runProcess' :: FilePath -> [String] -> IO ExitCode | |
+runProcess' program args = do | |
+ (_,_,_,ph) <- createProcess (proc program args) | |
+ waitForProcess' ph | |
+ | |
+exitOnFailure :: ExitCode -> IO () | |
+exitOnFailure ExitSuccess = return () | |
+exitOnFailure code = exitWith code | |
+ | |
+-- | nonblocking version of @waitForProcess@ | |
+waitForProcess' :: ProcessHandle -> IO ExitCode | |
+waitForProcess' pid = go | |
+ where | |
+ go = do | |
+ mec <- getProcessExitCode pid | |
+ case mec of | |
+ Just ec -> return ec | |
+ Nothing -> threadDelay 100000 >> go | |
diff --git a/yesod-bin/Devel.hs b/yesod-bin/Devel.hs | |
index 0552e0c..2a4f5f0 100644 | |
--- a/yesod-bin/Devel.hs | |
+++ b/yesod-bin/Devel.hs | |
@@ -53,7 +53,6 @@ import System.PosixCompat.Files (getFileStatus, | |
modificationTime) | |
import System.Process (ProcessHandle, | |
createProcess, env, | |
- getProcessExitCode, | |
proc, readProcess, | |
system, | |
terminateProcess) | |
@@ -63,6 +62,9 @@ import Build (getDeps, isNewerThan, | |
recompDeps) | |
import GhcBuild (buildPackage, | |
getBuildFlags, getPackageArgs) | |
+import BuildProgram (BuildProgram(..), buildProgramName, | |
+ runBuild, waitForProcess', | |
+ runProcess') | |
import qualified Config as GHC | |
import Data.Streaming.Network (bindPortTCP) | |
@@ -103,7 +105,7 @@ data DevelTermOpt = TerminateOnEnter | TerminateOnlyInterrupt | |
deriving (Show, Eq) | |
data DevelOpts = DevelOpts | |
- { isCabalDev :: Bool | |
+ { buildProgram :: BuildProgram | |
, forceCabal :: Bool | |
, verbose :: Bool | |
, eventTimeout :: Int -- negative value for no timeout | |
@@ -122,7 +124,7 @@ getBuildDir opts = fromMaybe "dist" (buildDir opts) | |
defaultDevelOpts :: DevelOpts | |
defaultDevelOpts = DevelOpts | |
- { isCabalDev = False | |
+ { buildProgram = CabalLike "cabal" | |
, forceCabal = False | |
, verbose = False | |
, eventTimeout = -1 | |
@@ -136,11 +138,6 @@ defaultDevelOpts = DevelOpts | |
, terminateWith = TerminateOnEnter | |
} | |
-cabalProgram :: DevelOpts -> FilePath | |
-cabalProgram opts | |
- | isCabalDev opts = "cabal-dev" | |
- | otherwise = "cabal" | |
- | |
-- | Run a reverse proxy from port 3000 to 3001. If there is no response on | |
-- 3001, give an appropriate message to the user. | |
reverseProxy :: DevelOpts -> I.IORef Int -> IO () | |
@@ -263,8 +260,10 @@ devel opts passThroughArgs = withSocketsDo $ withManager $ \manager -> do | |
ldar <- liftIO lookupLdAr | |
(hsSourceDirs, _) <- liftIO $ checkCabalFile gpd | |
liftIO $ removeFileIfExists (bd </> "setup-config") | |
- c <- liftIO $ configure opts passThroughArgs | |
- if c then do | |
+ ec <- case buildProgram opts of | |
+ Stack _ -> return ExitSuccess | |
+ CabalLike program -> liftIO $ cabalConfigure program passThroughArgs | |
+ if ec == ExitSuccess then do | |
-- these files contain the wrong data after the configure step, | |
-- remove them to force a cabal build first | |
liftIO $ mapM_ removeFileIfExists [ "yesod-devel/ghcargs.txt" | |
@@ -340,21 +339,20 @@ runBuildHook Nothing = return () | |
{- | |
run `cabal configure' with our wrappers | |
-} | |
-configure :: DevelOpts -> [String] -> IO Bool | |
-configure opts extraArgs = | |
- checkExit =<< createProcess (proc (cabalProgram opts) $ | |
- [ "configure" | |
- , "-flibrary-only" | |
- , "--disable-tests" | |
- , "--disable-benchmarks" | |
- , "-fdevel" | |
- , "--disable-library-profiling" | |
- , "--with-ld=yesod-ld-wrapper" | |
- , "--with-ghc=yesod-ghc-wrapper" | |
- , "--with-ar=yesod-ar-wrapper" | |
- , "--with-hc-pkg=ghc-pkg" | |
- ] ++ extraArgs | |
- ) | |
+cabalConfigure :: FilePath -> [String] -> IO ExitCode | |
+cabalConfigure program extraArgs = | |
+ runProcess' program $ | |
+ [ "configure" | |
+ , "-flibrary-only" | |
+ , "--disable-tests" | |
+ , "--disable-benchmarks" | |
+ , "-fdevel" | |
+ , "--disable-library-profiling" | |
+ , "--with-ld=yesod-ld-wrapper" | |
+ , "--with-ghc=yesod-ghc-wrapper" | |
+ , "--with-ar=yesod-ar-wrapper" | |
+ , "--with-hc-pkg=ghc-pkg" | |
+ ] ++ extraArgs | |
removeFileIfExists :: FilePath -> IO () | |
removeFileIfExists file = removeFile file `Ex.catch` handler | |
@@ -386,11 +384,8 @@ rebuildGhc bf ld ar = do | |
rebuildCabal :: DevelOpts -> IO Bool | |
rebuildCabal opts = do | |
- putStrLn $ "Rebuilding application... (using " ++ cabalProgram opts ++ ")" | |
- checkExit =<< createProcess (proc (cabalProgram opts) args) | |
- where | |
- args | verbose opts = [ "build" ] | |
- | otherwise = [ "build", "-v0" ] | |
+ putStrLn $ "Rebuilding application... (using " ++ buildProgramName (buildProgram opts) ++ ")" | |
+ (==ExitSuccess) <$> runBuild (buildProgram opts) (not (verbose opts)) [] | |
try_ :: forall a. IO a -> IO () | |
try_ x = void (Ex.try x :: IO (Either Ex.SomeException a)) | |
@@ -519,17 +514,3 @@ lookupLdAr' = do | |
return $ (,) <$> look D.ldProgram pgmc' <*> look D.arProgram pgmc' | |
where | |
look pgm pdb = fmap D.programPath (D.lookupProgram pgm pdb) | |
- | |
--- | nonblocking version of @waitForProcess@ | |
-waitForProcess' :: ProcessHandle -> IO ExitCode | |
-waitForProcess' pid = go | |
- where | |
- go = do | |
- mec <- getProcessExitCode pid | |
- case mec of | |
- Just ec -> return ec | |
- Nothing -> threadDelay 100000 >> go | |
- | |
--- | wait for process started by @createProcess@, return True for ExitSuccess | |
-checkExit :: (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> IO Bool | |
-checkExit (_,_,_,h) = (==ExitSuccess) <$> waitForProcess' h | |
diff --git a/yesod-bin/main.hs b/yesod-bin/main.hs | |
index 6cd65ec..1ac2bfd 100755 | |
--- a/yesod-bin/main.hs | |
+++ b/yesod-bin/main.hs | |
@@ -9,6 +9,7 @@ import System.Exit (ExitCode (ExitSuccess), exitWith) | |
import System.Process (rawSystem) | |
import AddHandler (addHandler) | |
+import BuildProgram (BuildProgram(..), runConfigure, runBuild, runTest, exitOnFailure) | |
import Devel (DevelOpts (..), devel, DevelTermOpt(..)) | |
import Keter (keter) | |
import Options (injectDefaults) | |
@@ -32,15 +33,20 @@ windowsWarning :: String | |
windowsWarning = " (does not work on Windows)" | |
#endif | |
-data CabalPgm = Cabal | CabalDev deriving (Show, Eq) | |
- | |
data Options = Options | |
- { optCabalPgm :: CabalPgm | |
- , optVerbose :: Bool | |
- , optCommand :: Command | |
+ { optCabalDev :: Bool | |
+ , optStackPath :: Maybe FilePath | |
+ , optVerbose :: Bool | |
+ , optCommand :: Command | |
} | |
deriving (Show, Eq) | |
+optBuildProgram :: Options -> BuildProgram | |
+optBuildProgram opts | |
+ | Just path <- optStackPath opts = Stack path | |
+ | optCabalDev opts = CabalLike "cabal-dev" | |
+ | otherwise = CabalLike "cabal" | |
+ | |
data Command = Init { _initBare :: Bool, _initName :: Maybe String, _initDatabase :: Maybe String } | |
| HsFiles | |
| Configure | |
@@ -72,12 +78,6 @@ data Command = Init { _initBare :: Bool, _initName :: Maybe String, _initDatabas | |
| Version | |
deriving (Show, Eq) | |
-cabalCommand :: Options -> String | |
-cabalCommand mopt | |
- | optCabalPgm mopt == CabalDev = "cabal-dev" | |
- | otherwise = "cabal" | |
- | |
- | |
main :: IO () | |
main = do | |
o <- execParser =<< injectDefaults "yesod" | |
@@ -97,19 +97,19 @@ main = do | |
c -> c | |
}) | |
] optParser' | |
- let cabal = rawSystem' (cabalCommand o) | |
case optCommand o of | |
Init{..} -> scaffold _initBare _initName _initDatabase | |
HsFiles -> mkHsFile | |
- Configure -> cabal ["configure"] | |
- Build es -> touch' >> cabal ("build":es) | |
+ Configure -> runConfigure (optBuildProgram o) | |
+ Build es -> do touch' | |
+ exitOnFailure =<< runBuild (optBuildProgram o) False es | |
Touch -> touch' | |
- Keter{..} -> keter (cabalCommand o) _keterNoRebuild _keterNoCopyTo | |
+ -- Keter{..} -> keter (cabalCommand o) _keterNoRebuild _keterNoCopyTo | |
Version -> putStrLn ("yesod-bin version: " ++ showVersion Paths_yesod_bin.version) | |
AddHandler{..} -> addHandler addHandlerRoute addHandlerPattern addHandlerMethods | |
- Test -> cabalTest cabal | |
+ Test -> touch' >> runTest (optBuildProgram o) | |
Devel{..} -> let develOpts = DevelOpts | |
- { isCabalDev = optCabalPgm o == CabalDev | |
+ { buildProgram = optBuildProgram o | |
, forceCabal = _develDisableApi | |
, verbose = optVerbose o | |
, eventTimeout = _develRescan | |
@@ -123,19 +123,15 @@ main = do | |
, terminateWith = if _interruptOnly then TerminateOnlyInterrupt else TerminateOnEnter | |
} | |
in devel develOpts develExtraArgs | |
- where | |
- cabalTest cabal = do touch' | |
- _ <- cabal ["configure", "--enable-tests", "-flibrary-only"] | |
- _ <- cabal ["build"] | |
- cabal ["test"] | |
optParser' :: ParserInfo Options | |
optParser' = info (helper <*> optParser) ( fullDesc <> header "Yesod Web Framework command line utility" ) | |
optParser :: Parser Options | |
optParser = Options | |
- <$> flag Cabal CabalDev ( long "dev" <> short 'd' <> help "use cabal-dev" ) | |
- <*> switch ( long "verbose" <> short 'v' <> help "More verbose output" ) | |
+ <$> switch ( long "dev" <> short 'd' <> help "use cabal-dev" ) | |
+ <*> optStr ( long "stack" <> short 's' <> help "use stack" ) | |
+ <*> switch ( long "verbose" <> short 'v' <> help "More verbose output" ) | |
<*> subparser ( command "init" (info initOptions | |
(progDesc "Scaffold a new site")) | |
<> command "hsfiles" (info (pure HsFiles) | |
@@ -205,7 +201,7 @@ develOptions = Devel <$> switch ( long "disable-api" <> short 'd' | |
extraCabalArgs :: Parser [String] | |
extraCabalArgs = many (strOption ( long "extra-cabal-arg" <> short 'e' <> metavar "ARG" | |
- <> help "pass extra argument ARG to cabal") | |
+ <> help "pass extra argument ARG to build program") | |
) | |
addHandlerOptions :: Parser Command |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment