Skip to content

new-exec #4722

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

Merged
merged 37 commits into from
Sep 26, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
b41505a
enviroment -> environment
dmwit Feb 3, 2017
599120e
disable GHC environment files in another way
dmwit Feb 3, 2017
585fe3a
bare-bones new-exec support
dmwit Feb 4, 2017
c5f0052
factor out the logic for choosing a directory for binaries
dmwit Feb 7, 2017
effe36b
PATH modifications for new-exec
dmwit Feb 7, 2017
43893e4
use the ProgramDb in new-exec
dmwit Feb 8, 2017
1d4533e
write help text for new-exec
dmwit Feb 9, 2017
603897f
backwards compatibility
dmwit Feb 9, 2017
44af73e
use the install plan to modify PATH in new-exec
dmwit Feb 13, 2017
e49880b
comment on a tricky line of code
dmwit Feb 13, 2017
a6df3e8
accept all new-build flags in new-exec
dmwit Feb 13, 2017
108ab93
allow new-exec'ing of executables built inplace
dmwit Feb 15, 2017
b13bcbf
Make new-bench actually run the benchmarks
fgaz Jul 20, 2017
ae9ae09
Add brief description of mew-bench in docs
fgaz Jul 22, 2017
f7c2b18
Add new-bench to changelog
fgaz Jul 22, 2017
b7f726c
Merge branch 'master' of github.com:dmwit/cabal into new-exec/1
fgaz Jul 23, 2017
57763ca
Adapt new-exec to the new new-build structure
fgaz Aug 11, 2017
b57f9bd
Merge branch 'master' into new-exec/1
fgaz Aug 11, 2017
ce2518d
Fix some warnings
fgaz Aug 11, 2017
4ee6da9
Re-enable .ghc.env temp directory for new-exec
fgaz Aug 22, 2017
33a8b51
Add args fallback when we can't use .ghc.env files
fgaz Aug 23, 2017
e923107
Add basic test for new-exec
fgaz Aug 23, 2017
5e454c6
Add global package env to new-exec ghc invocations
fgaz Aug 23, 2017
194453e
Reorder things a bit
fgaz Aug 23, 2017
6b9d462
Check if the compiler is supported in the buildCtx
fgaz Aug 23, 2017
e0b085e
Don't use ghc env files if they aren't supported
fgaz Aug 23, 2017
9298ad8
Exec args are defaults, not overrides
fgaz Aug 23, 2017
8e050a6
Make withTempEnvFile its own function
fgaz Aug 23, 2017
5fd32dc
Add test: new-exec can run an exe
fgaz Aug 24, 2017
d0ba72d
Remove useless comment
fgaz Aug 24, 2017
630634a
Match the configured compiler in new-exec
fgaz Aug 29, 2017
f99f169
Use void instead of _ <-
fgaz Sep 26, 2017
ca31578
Fix comment
fgaz Sep 26, 2017
8945ebd
Don't base execCommand on installCommand
fgaz Sep 26, 2017
cb9a355
Add new-exec to changelog
fgaz Sep 26, 2017
442bb91
Add new-exec to the docs
fgaz Sep 26, 2017
28c9fd8
Merge branch 'master' into new-exec/1
fgaz Sep 26, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions Cabal/Distribution/Simple/GHC/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -520,13 +520,15 @@ simpleGhcEnvironmentFile packageDBs pkgids =
--
-- The 'Platform' and GHC 'Version' are needed as part of the file name.
--
-- Returns the name of the file written.
writeGhcEnvironmentFile :: FilePath -- ^ directory in which to put it
-> Platform -- ^ the GHC target platform
-> Version -- ^ the GHC version
-> [GhcEnvironmentFileEntry] -- ^ the content
-> NoCallStackIO ()
writeGhcEnvironmentFile directory platform ghcversion =
writeFileAtomic envfile . BS.pack . renderGhcEnvironmentFile
-> NoCallStackIO FilePath
writeGhcEnvironmentFile directory platform ghcversion entries = do
writeFileAtomic envfile . BS.pack . renderGhcEnvironmentFile $ entries
return envfile
where
envfile = directory </> ghcEnvironmentFileName platform ghcversion

Expand Down
2 changes: 2 additions & 0 deletions Cabal/Distribution/Simple/Program/GHC.hs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ module Distribution.Simple.Program.GHC (

runGHC,

packageDbArgsDb,

) where

import Prelude ()
Expand Down
12 changes: 7 additions & 5 deletions Cabal/doc/nix-local-build.rst
Original file line number Diff line number Diff line change
Expand Up @@ -421,16 +421,18 @@ cabal new-haddock
``cabal new-haddock [FLAGS] TARGET`` builds Haddock documentation for
the specified packages within the project.

cabal new-exec
---------------

``cabal new-exec [FLAGS] [--] COMMAND [--] [ARGS]`` runs the specified command
using the project's environment. That is, passing the right flags to compiler
invocations and bringing the project's executables into scope.

Unsupported commands
--------------------

The following commands are not currently supported:

``cabal new-exec`` (:issue:`4722`)
Workaround: if you wanted to execute GHCi, consider using
``cabal new-repl`` instead. Otherwise, use ``-v`` to find the list
of flags GHC is being invoked with and pass it manually.

``cabal new-install`` (:issue:`3737` and :issue:`3332`)
Workaround: no good workaround at the moment. (But note that you no
longer need to install libraries before building!)
Expand Down
259 changes: 259 additions & 0 deletions cabal-install/Distribution/Client/CmdExec.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
-------------------------------------------------------------------------------
-- |
-- Module : Distribution.Client.Exec
-- Maintainer : [email protected]
-- Portability : portable
--
-- Implementation of the 'new-exec' command for running an arbitrary executable
-- in an environment suited to the part of the store built for a project.
-------------------------------------------------------------------------------

{-# LANGUAGE RecordWildCards #-}
module Distribution.Client.CmdExec
( execAction
, execCommand
) where

import Distribution.Client.DistDirLayout
( DistDirLayout(..)
)
import Distribution.Client.InstallPlan
( GenericPlanPackage(..)
, toGraph
)
import Distribution.Client.Setup
( ConfigExFlags
, ConfigFlags(configVerbosity)
, GlobalFlags
, InstallFlags
)
import Distribution.Client.ProjectOrchestration
( ProjectBuildContext(..)
, runProjectPreBuildPhase
, establishProjectBaseContext
, distDirLayout
, commandLineFlagsToProjectConfig
, ProjectBaseContext(..)
)
import Distribution.Client.ProjectPlanOutput
( updatePostBuildProjectStatus
, createPackageEnvironment
, argsEquivalentOfGhcEnvironmentFile
, PostBuildProjectStatus
)
import qualified Distribution.Client.ProjectPlanning as Planning
import Distribution.Client.ProjectPlanning
( ElaboratedInstallPlan
, ElaboratedSharedConfig(..)
)
import Distribution.Simple.Command
( CommandUI(..)
)
import Distribution.Simple.Program.Db
( modifyProgramSearchPath
, requireProgram
, configuredPrograms
)
import Distribution.Simple.Program.Find
( ProgramSearchPathEntry(..)
)
import Distribution.Simple.Program.Run
( programInvocation
, runProgramInvocation
)
import Distribution.Simple.Program.Types
( programOverrideEnv
, programDefaultArgs
, programPath
, simpleProgram
, ConfiguredProgram
)
import Distribution.Simple.GHC
( getImplInfo
, GhcImplInfo(supportsPkgEnvFiles) )
import Distribution.Simple.Setup
( HaddockFlags
, fromFlagOrDefault
)
import Distribution.Simple.Utils
( die'
, info
, withTempDirectory
, wrapText
)
import Distribution.Verbosity
( Verbosity
, normal
)

import qualified Distribution.Client.CmdBuild as CmdBuild

import Prelude ()
import Distribution.Client.Compat.Prelude

import Data.Set (Set)
import qualified Data.Set as S
import qualified Data.Map as M

execCommand :: CommandUI (ConfigFlags, ConfigExFlags, InstallFlags, HaddockFlags)
execCommand = CommandUI
{ commandName = "new-exec"
, commandSynopsis = "Give a command access to the store."
, commandUsage = \pname ->
"Usage: " ++ pname ++ " new-exec [FLAGS] [--] COMMAND [--] [ARGS]\n"
, commandDescription = Just $ \pname -> wrapText $
"During development it is often useful to run build tasks and perform"
++ " one-off program executions to experiment with the behavior of build"
++ " tools. It is convenient to run these tools in the same way " ++ pname
++ " itself would. The `" ++ pname ++ " new-exec` command provides a way to"
++ " do so.\n"
++ "\n"
++ "Compiler tools will be configured to see the same subset of the store"
++ " that builds would see. The PATH is modified to make all executables in"
++ " the dependency tree available (provided they have been built already)."
++ " Commands are also rewritten in the way cabal itself would. For"
++ " example, `" ++ pname ++ " new-exec ghc` will consult the configuration"
++ " to choose an appropriate version of ghc and to include any"
++ " ghc-specific flags requested."
, commandNotes = Nothing
, commandOptions = commandOptions CmdBuild.buildCommand
, commandDefaultFlags = commandDefaultFlags CmdBuild.buildCommand
}

execAction :: (ConfigFlags, ConfigExFlags, InstallFlags, HaddockFlags)
-> [String] -> GlobalFlags -> IO ()
execAction (configFlags, configExFlags, installFlags, haddockFlags)
extraArgs globalFlags = do

baseCtx <- establishProjectBaseContext verbosity cliConfig

-- To set up the environment, we'd like to select the libraries in our
-- dependency tree that we've already built. So first we set up an install
-- plan, but we walk the dependency tree without first executing the plan.
buildCtx <- runProjectPreBuildPhase
verbosity
baseCtx
(\plan -> return (plan, M.empty))

-- We use the build status below to decide what libraries to include in the
-- compiler environment, but we don't want to actually build anything. So we
-- pass mempty to indicate that nothing happened and we just want the current
-- status.
buildStatus <- updatePostBuildProjectStatus
verbosity
(distDirLayout baseCtx)
(elaboratedPlanOriginal buildCtx)
(pkgsBuildStatus buildCtx)
mempty

-- Some dependencies may have executables. Let's put those on the PATH.
extraPaths <- pathAdditions verbosity baseCtx buildCtx
let programDb = modifyProgramSearchPath
(map ProgramSearchPathDir extraPaths ++)
. pkgConfigCompilerProgs
. elaboratedShared
$ buildCtx

-- Now that we have the packages, set up the environment. We accomplish this
-- by creating an environment file that selects the databases and packages we
-- computed in the previous step, and setting an environment variable to
-- point at the file.
-- In case ghc is too old to support environment files,
-- we pass the same info as arguments
let compiler = pkgConfigCompiler $ elaboratedShared buildCtx
envFilesSupported = supportsPkgEnvFiles (getImplInfo compiler)
case extraArgs of
[] -> die' verbosity "Please specify an executable to run"
exe:args -> do
(program, _) <- requireProgram verbosity (simpleProgram exe) programDb
let argOverrides =
argsEquivalentOfGhcEnvironmentFile
compiler
(distDirLayout baseCtx)
(elaboratedPlanOriginal buildCtx)
buildStatus
programIsConfiguredCompiler = matchCompilerPath
(elaboratedShared buildCtx)
program
argOverrides' =
if envFilesSupported
|| not programIsConfiguredCompiler
then []
else argOverrides

(if envFilesSupported
then withTempEnvFile verbosity baseCtx buildCtx buildStatus
else \f -> f []) $ \envOverrides -> do
let program' = withOverrides
envOverrides
argOverrides'
program
invocation = programInvocation program' args
runProgramInvocation verbosity invocation
where
verbosity = fromFlagOrDefault normal (configVerbosity configFlags)
cliConfig = commandLineFlagsToProjectConfig
globalFlags configFlags configExFlags
installFlags haddockFlags
withOverrides env args program = program
{ programOverrideEnv = programOverrideEnv program ++ env
, programDefaultArgs = programDefaultArgs program ++ args}

matchCompilerPath :: ElaboratedSharedConfig -> ConfiguredProgram -> Bool
matchCompilerPath elaboratedShared program =
programPath program
`elem`
(programPath <$> configuredCompilers)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should i canonicalize those paths?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not 100% sure, probably not. Aren't the configured progs paths already absolute?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No idea. They seem absolute but maybe it's only the general case. I'll probably leave it like this and add a comment about it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. I think they should be absolute after the configure progs step.

where
configuredCompilers = configuredPrograms $ pkgConfigCompilerProgs elaboratedShared

-- | Execute an action with a temporary .ghc.environment file reflecting the
-- current environment. The action takes an environment containing the env
-- variable which points ghc to the file.
withTempEnvFile :: Verbosity
-> ProjectBaseContext
-> ProjectBuildContext
-> PostBuildProjectStatus
-> ([(String, Maybe String)] -> IO a)
-> IO a
withTempEnvFile verbosity
baseCtx
buildCtx
buildStatus
action =
withTempDirectory
verbosity
(distTempDirectory (distDirLayout baseCtx))
"environment."
(\tmpDir -> do
envOverrides <- createPackageEnvironment
verbosity
tmpDir
(elaboratedPlanToExecute buildCtx)
(elaboratedShared buildCtx)
buildStatus
action envOverrides)

pathAdditions :: Verbosity -> ProjectBaseContext -> ProjectBuildContext -> IO [FilePath]
pathAdditions verbosity ProjectBaseContext{..}ProjectBuildContext{..} = do
info verbosity . unlines $ "Including the following directories in PATH:"
: paths
return paths
where
paths = S.toList
$ binDirectories distDirLayout elaboratedShared elaboratedPlanToExecute

binDirectories
:: DistDirLayout
-> ElaboratedSharedConfig
-> ElaboratedInstallPlan
-> Set FilePath
binDirectories layout config = fromElaboratedInstallPlan where
fromElaboratedInstallPlan = fromGraph . toGraph
fromGraph = foldMap fromPlan
fromSrcPkg = S.fromList . Planning.binDirectories layout config

fromPlan (PreExisting _) = mempty
fromPlan (Configured pkg) = fromSrcPkg pkg
fromPlan (Installed pkg) = fromSrcPkg pkg

10 changes: 6 additions & 4 deletions cabal-install/Distribution/Client/ProjectOrchestration.hs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ import Data.Map (Map)
import Data.List
import Data.Maybe
import Data.Either
import Control.Monad (void)
import Control.Exception (Exception(..), throwIO, assert)
import System.Exit (ExitCode(..), exitFailure)
#ifdef MIN_VERSION_unix
Expand Down Expand Up @@ -349,10 +350,11 @@ runProjectPostBuildPhase verbosity
pkgsBuildStatus
buildOutcomes

writePlanGhcEnvironment distDirLayout
elaboratedPlanOriginal
elaboratedShared
postBuildStatus
void $ writePlanGhcEnvironment (distProjectRootDirectory
distDirLayout)
elaboratedPlanOriginal
elaboratedShared
postBuildStatus

-- Finally if there were any build failures then report them and throw
-- an exception to terminate the program
Expand Down
Loading