Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce stack run command line option #3952

Merged
merged 14 commits into from Jun 24, 2018
@@ -22,6 +22,9 @@ Other enhancements:
`extra-deps` of `stack.yaml`
* `stack build` suggests trying another GHC version should the build
plan end up requiring unattainable `base` version.
* A new sub command `run` has been introduced to build and run a specified executable
similar to `cabal run`. If no executable is provided as the first argument, it
defaults to the first available executable in the project.
* `stack build` missing dependency suggestions (on failure to construct a valid
build plan because of missing deps) are now printed with their latest
cabal file revision hash. See
@@ -22,6 +22,7 @@ execOptsParser mcmd =
txt = case mcmd of
Nothing -> normalTxt
Just ExecCmd{} -> normalTxt
Just ExecRun -> "-- ARGS (e.g. stack run -- file.txt)"
Just ExecGhc -> "-- ARGS (e.g. stack runghc -- X.hs -o x)"
Just ExecRunGhc -> "-- ARGS (e.g. stack runghc -- X.hs)"
normalTxt = "-- ARGS (e.g. stack exec -- ghc-pkg describe base)"
@@ -404,6 +404,7 @@ data ExecOpts = ExecOpts

data SpecialExecCmd
= ExecCmd String
| ExecRun
| ExecGhc
| ExecRunGhc
deriving (Show, Eq)
@@ -28,6 +28,7 @@ import qualified Data.ByteString.Lazy as L
import Data.IORef.RunOnce (runOnce)
import Data.List
import qualified Data.Map.Strict as Map
import qualified Data.Set as Set
import qualified Data.Text as T
import Data.Version (showVersion)
import RIO.Process
@@ -97,6 +98,7 @@ import Stack.Solver (solveExtraDeps)
import Stack.Types.Version
import Stack.Types.Config
import Stack.Types.Compiler
import Stack.Types.NamedComponent
import Stack.Types.Nix
import Stack.Types.Runner
import Stack.Upgrade
@@ -369,6 +371,10 @@ commandLineHandler currentDir progName isInterpreter = complicatedOptions
"Execute a command"
execCmd
(execOptsParser Nothing)
addCommand' "run"
"Build and run an executable. Defaults to the first available executable if none is provided as the first argument."
execCmd
(execOptsParser $ Just ExecRun)
addGhciCommand' "ghci"
"Run ghci in the context of package(s) (experimental)"
ghciCmd
@@ -791,10 +797,6 @@ execCmd :: ExecOpts -> GlobalOpts -> IO ()
execCmd ExecOpts {..} go@GlobalOpts{..} =
case eoExtra of
ExecOptsPlain -> do
(cmd, args) <- case (eoCmd, eoArgs) of
(ExecCmd cmd, args) -> return (cmd, args)
(ExecGhc, args) -> return ("ghc", args)
(ExecRunGhc, args) -> return ("runghc", args)
loadConfigWithOpts go $ \lc ->
withUserFileLock go (view stackRootL lc) $ \lk -> do
let getCompilerVersion = loadCompilerVersion go lc
@@ -803,14 +805,17 @@ execCmd ExecOpts {..} go@GlobalOpts{..} =
(lcProjectRoot lc)
-- Unlock before transferring control away, whether using docker or not:
(Just $ munlockFile lk)
(runRIO (lcConfig lc) $ do
(withBuildConfigAndLock go $ \buildLock -> do
config <- view configL
menv <- liftIO $ configProcessContextSettings config plainEnvSettings
withProcessContext menv $ Nix.reexecWithOptionalShell
(lcProjectRoot lc)
getCompilerVersion
(runRIO (lcConfig lc) $
exec cmd args))
withProcessContext menv $ do
(cmd, args) <- case (eoCmd, eoArgs) of
(ExecCmd cmd, args) -> return (cmd, args)
(ExecRun, args) -> getRunCmd args
(ExecGhc, args) -> return ("ghc", args)
(ExecRunGhc, args) -> return ("runghc", args)
munlockFile buildLock
Nix.reexecWithOptionalShell (lcProjectRoot lc) getCompilerVersion (runRIO (lcConfig lc) $ exec cmd args))
Nothing
Nothing -- Unlocked already above.
ExecOptsEmbellished {..} ->
@@ -830,6 +835,7 @@ execCmd ExecOpts {..} go@GlobalOpts{..} =
else args ++ ["+RTS"] ++ eoRtsOptions ++ ["-RTS"]
(cmd, args) <- case (eoCmd, argsWithRts eoArgs) of
(ExecCmd cmd, args) -> return (cmd, args)
(ExecRun, args) -> getRunCmd args
(ExecGhc, args) -> getGhcCmd "" eoPackages args
-- NOTE: this won't currently work for GHCJS, because it doesn't have
-- a runghcjs binary. It probably will someday, though.
@@ -852,6 +858,24 @@ execCmd ExecOpts {..} go@GlobalOpts{..} =
getPkgOpts wc pkgs =
map ("-package-id=" ++) <$> mapM (getPkgId wc) pkgs

getRunCmd args = do
pkgComponents <- liftM (map lpvComponents . Map.elems . lpProject) getLocalPackages
let executables = filter isCExe $ concatMap Set.toList pkgComponents
let (exe, args') = case args of
[] -> (firstExe, args)
x:xs -> case find (\y -> y == (CExe $ T.pack x)) executables of
Nothing -> (firstExe, args)
argExe -> (argExe, xs)
where
firstExe = listToMaybe executables
case exe of
Just (CExe exe') -> do
Stack.Build.build (const (return ())) Nothing defaultBuildOptsCLI{boptsCLITargets = [T.cons ':' exe']}
return (T.unpack exe', args')
_ -> do
logError "No executables found."
liftIO exitFailure

getGhcCmd prefix pkgs args = do
wc <- view $ actualCompilerVersionL.whichCompilerL
pkgopts <- getPkgOpts wc pkgs