Skip to content

Commit f8f166a

Browse files
committed
Support for --project-file and --dist-dir flags.
These flags allow users to configure the location of cabal.project and dist-newstyle, respectively. Primary motivation is for the test suite, to allow non-clobbering inplace testing. Bikeshed points: - GlobalFlags or InstallFlags? I picked GlobalFlags as it seemed more appropriate from a semantic perspective, but the downside is that you must now specify the flag before new-build, i.e., cabal --dist-dir=... new-build. However, if we ever support a Nix-style command that doesn't take the full complement of InstallFlags, GlobalFlags is the only place it could go. - Flag names? I think --project-file is good but perhaps someone has a better idea for --dist-dir. - Is this in duplication with globalConfigFile? I have no idea what that parameter does, so I don't think so. It's not too easy to make the value of 'dist-dir' saveable to the cabal.project file, as we'd prefer to load directly from the cache if cabal.project is not updated. Signed-off-by: Edward Z. Yang <[email protected]>
1 parent b8aca4d commit f8f166a

12 files changed

+132
-54
lines changed

Cabal/doc/nix-local-build.rst

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1697,5 +1697,35 @@ Most users generally won't need these.
16971697
The command line variant of this field is
16981698
``--cabal-lib-version=1.24.0.1``.
16991699

1700+
Top-level configuration flags
1701+
-----------------------------
1702+
1703+
These top-level flags must be passed before the subcommand (e.g.,
1704+
``cabal --dist-dir=dist-newstyle.mine new-build``) and cannot be
1705+
saved to the ``cabal.project`` file (as they affect how we find
1706+
the ``cabal.project`` file and its cache.)
1707+
1708+
.. option:: --project-file=FILE
1709+
1710+
Specifies the name of the project file used to specify the
1711+
rest of the top-level configuration; defaults to ``cabal.project``.
1712+
This name not only specifies the name of the main project file,
1713+
but also the auxiliary project files ``cabal.project.freeze``
1714+
and ``cabal.project.local``; for example, if you specify
1715+
``--project-file=my.project``, then the other files that will
1716+
be probed are ``my.project.freeze`` and ``my.project.local``.
1717+
1718+
If the specified project file is a relative path, we will
1719+
look for the file relative to the current working directory,
1720+
and then for the parent directory, until the project file is
1721+
found or we have hit the top of the user's home directory.
1722+
1723+
.. option:: --dist-dir=DIR
1724+
1725+
Specifies the name of the directory where build products for
1726+
build will be stored; defaults to ``dist-newstyle``. If a
1727+
relative name is specified, this directory is resolved relative
1728+
to the root of the project (i.e., where the ``cabal.project``
1729+
file lives.)
17001730

17011731
.. include:: references.inc

cabal-install/Distribution/Client/CmdConfigure.hs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ configureCommand = Client.installCommand {
3131
commandUsage = usageAlternatives "new-configure" [ "[FLAGS]" ],
3232
commandDescription = Just $ \_ -> wrapText $
3333
"Configures a Nix-local build project, downloading source from"
34-
++ " the network and writing out a cabal.project.local file which"
35-
++ " saves any FLAGS, to be reapplied on subsequent invocations to "
36-
++ "new-build.",
34+
++ " the network and writing out a cabal.project.local file"
35+
++ " (or $project_file.local, if --project-file is specified)"
36+
++ " which saves any FLAGS, to be reapplied on subsequent invocations to"
37+
++ " new-build.",
3738
commandNotes = Just $ \pname ->
3839
"Examples:\n"
3940
++ " " ++ pname ++ " new-configure "
@@ -65,7 +66,7 @@ configureAction (configFlags, configExFlags, installFlags, haddockFlags)
6566
hookPrePlanning = \rootDir _ cliConfig ->
6667
-- Write out the @cabal.project.local@ so it gets picked up by the
6768
-- planning phase.
68-
writeProjectLocalExtraConfig rootDir cliConfig,
69+
writeProjectLocalExtraConfig globalFlags rootDir cliConfig,
6970

7071
hookSelectPlanSubset = \buildSettings' elaboratedPlan -> do
7172
-- Select the same subset of targets as 'CmdBuild' would

cabal-install/Distribution/Client/CmdFreeze.hs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import Distribution.Client.ProjectPlanning
1111
import Distribution.Client.ProjectConfig
1212
( ProjectConfig(..), ProjectConfigShared(..)
1313
, commandLineFlagsToProjectConfig, writeProjectLocalFreezeConfig
14-
, findProjectRoot )
14+
, findProjectRoot, getProjectFileName )
1515
import Distribution.Client.Targets
1616
( UserConstraint(..) )
1717
import Distribution.Solver.Types.ConstraintSource
@@ -60,6 +60,7 @@ freezeCommand = Client.installCommand {
6060
commandDescription = Just $ \_ -> wrapText $
6161
"Performs dependency solving on a Nix-local build project, and"
6262
++ " then writes out the precise dependency configuration to cabal.project.freeze"
63+
++ " (or $project_file.freeze if --project-file is specified)"
6364
++ " so that the plan is always used in subsequent builds.",
6465
commandNotes = Just $ \pname ->
6566
"Examples:\n"
@@ -86,23 +87,23 @@ freezeAction (configFlags, configExFlags, installFlags, haddockFlags)
8687
cabalDir <- defaultCabalDir
8788
let cabalDirLayout = defaultCabalDirLayout cabalDir
8889

89-
projectRootDir <- findProjectRoot
90-
let distDirLayout = defaultDistDirLayout projectRootDir
90+
projectRootDir <- findProjectRoot globalFlags
91+
let distDirLayout = defaultDistDirLayout globalFlags projectRootDir
9192

9293
let cliConfig = commandLineFlagsToProjectConfig
9394
globalFlags configFlags configExFlags
9495
installFlags haddockFlags
9596

9697

9798
(_, elaboratedPlan, _, _) <-
98-
rebuildInstallPlan verbosity
99+
rebuildInstallPlan verbosity globalFlags
99100
projectRootDir distDirLayout cabalDirLayout
100101
cliConfig
101102

102103
let freezeConfig = projectFreezeConfig elaboratedPlan
103-
writeProjectLocalFreezeConfig projectRootDir freezeConfig
104+
writeProjectLocalFreezeConfig globalFlags projectRootDir freezeConfig
104105
notice verbosity $
105-
"Wrote freeze file: " ++ projectRootDir </> "cabal.project.freeze"
106+
"Wrote freeze file: " ++ projectRootDir </> getProjectFileName globalFlags <.> "freeze"
106107

107108
where
108109
verbosity = fromFlagOrDefault normal (configVerbosity configFlags)

cabal-install/Distribution/Client/Config.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,9 @@ instance Semigroup SavedConfig where
227227
globalRequireSandbox = combine globalRequireSandbox,
228228
globalIgnoreSandbox = combine globalIgnoreSandbox,
229229
globalIgnoreExpiry = combine globalIgnoreExpiry,
230-
globalHttpTransport = combine globalHttpTransport
230+
globalHttpTransport = combine globalHttpTransport,
231+
globalDistDirName = combine globalDistDirName,
232+
globalProjectFileName = combine globalProjectFileName
231233
}
232234
where
233235
combine = combine' savedGlobalFlags

cabal-install/Distribution/Client/DistDirLayout.hs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ module Distribution.Client.DistDirLayout (
1717
) where
1818

1919
import System.FilePath
20+
import Distribution.Client.GlobalFlags
21+
import Distribution.Simple.Setup (fromFlagOrDefault)
2022
import Distribution.Package
2123
( PackageId, ComponentId, UnitId )
2224
import Distribution.Compiler
@@ -106,12 +108,18 @@ data CabalDirLayout = CabalDirLayout {
106108
cabalWorldFile :: FilePath
107109
}
108110

109-
110-
defaultDistDirLayout :: FilePath -> DistDirLayout
111-
defaultDistDirLayout projectRootDirectory =
111+
-- | Given the path to the dist directory (defaults to
112+
-- @$project_root/dist-newstyle@), create the 'DistDirLayout'
113+
-- associated with it.
114+
--
115+
-- NB: This used to accept just @project_root@, but to let the
116+
-- dist directory be configurable we changed it.
117+
defaultDistDirLayout :: GlobalFlags -> FilePath -> DistDirLayout
118+
defaultDistDirLayout globalFlags projectRootDirectory =
112119
DistDirLayout {..}
113120
where
114-
distDirectory = projectRootDirectory </> "dist-newstyle"
121+
distDirName = fromFlagOrDefault "dist-newstyle" (globalDistDirName globalFlags)
122+
distDirectory = projectRootDirectory </> distDirName
115123
--TODO: switch to just dist at some point, or some other new name
116124

117125
distBuildRootDirectory = distDirectory </> "build"

cabal-install/Distribution/Client/GlobalFlags.hs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,19 @@ data GlobalFlags = GlobalFlags {
6767
globalRequireSandbox :: Flag Bool,
6868
globalIgnoreSandbox :: Flag Bool,
6969
globalIgnoreExpiry :: Flag Bool, -- ^ Ignore security expiry dates
70-
globalHttpTransport :: Flag String
70+
globalHttpTransport :: Flag String,
71+
-- | Project-wide dist directory. Defaults to @dist-newstyle@.
72+
-- Assumed to be relative to the root of the project (as indicated
73+
-- by @cabal.project@).
74+
globalDistDirName :: Flag FilePath,
75+
-- | The cabal project file name; defaults to @cabal.project@.
76+
-- Th name itself denotes the cabal project file name, but it also
77+
-- is the base of auxiliary project files, such as
78+
-- @cabal.project.local@ and @cabal.project.freeze@ which are also
79+
-- read and written out in some cases. If the path is not found
80+
-- in the current working directory, we will successively probe
81+
-- relative to parent directories until this name is found.
82+
globalProjectFileName :: Flag FilePath
7183
} deriving Generic
7284

7385
defaultGlobalFlags :: GlobalFlags
@@ -85,7 +97,9 @@ defaultGlobalFlags = GlobalFlags {
8597
globalRequireSandbox = Flag False,
8698
globalIgnoreSandbox = Flag False,
8799
globalIgnoreExpiry = Flag False,
88-
globalHttpTransport = mempty
100+
globalHttpTransport = mempty,
101+
globalDistDirName = mempty,
102+
globalProjectFileName = mempty
89103
}
90104

91105
instance Monoid GlobalFlags where

cabal-install/Distribution/Client/ProjectConfig.hs

Lines changed: 37 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ module Distribution.Client.ProjectConfig (
3737
resolveSolverSettings,
3838
BuildTimeSettings(..),
3939
resolveBuildTimeSettings,
40+
getProjectFileName,
4041

4142
-- * Checking configuration
4243
checkBadPerPackageCompilerPaths,
@@ -46,6 +47,7 @@ module Distribution.Client.ProjectConfig (
4647
import Prelude ()
4748
import Distribution.Client.Compat.Prelude
4849

50+
import Distribution.Client.GlobalFlags
4951
import Distribution.Client.ProjectConfig.Types
5052
import Distribution.Client.ProjectConfig.Legacy
5153
import Distribution.Client.RebuildMonad
@@ -55,8 +57,6 @@ import Distribution.Client.Glob
5557
import Distribution.Client.Types
5658
import Distribution.Client.DistDirLayout
5759
( CabalDirLayout(..) )
58-
import Distribution.Client.GlobalFlags
59-
( RepoContext(..), withRepoContext' )
6060
import Distribution.Client.BuildReports.Types
6161
( ReportLevel(..) )
6262
import Distribution.Client.Config
@@ -338,14 +338,20 @@ resolveBuildTimeSettings verbosity
338338
-- Reading and writing project config files
339339
--
340340

341+
getProjectFileName :: GlobalFlags -> FilePath
342+
getProjectFileName globalFlags =
343+
fromFlagOrDefault "cabal.project" (globalProjectFileName globalFlags)
344+
341345
-- | Find the root of this project.
342346
--
343347
-- Searches for an explicit @cabal.project@ file, in the current directory or
344348
-- parent directories. If no project file is found then the current dir is the
345349
-- project root (and the project will use an implicit config).
346350
--
347-
findProjectRoot :: IO FilePath
348-
findProjectRoot = do
351+
findProjectRoot :: GlobalFlags -> IO FilePath
352+
findProjectRoot globalFlags = do
353+
354+
let projectFileName = getProjectFileName globalFlags
349355

350356
curdir <- getCurrentDirectory
351357
homedir <- getHomeDirectory
@@ -355,7 +361,7 @@ findProjectRoot = do
355361
let probe dir | isDrive dir || dir == homedir
356362
= return curdir -- implicit project root
357363
probe dir = do
358-
exists <- doesFileExist (dir </> "cabal.project")
364+
exists <- doesFileExist (dir </> projectFileName)
359365
if exists
360366
then return dir -- explicit project root
361367
else probe (takeDirectory dir)
@@ -367,20 +373,20 @@ findProjectRoot = do
367373
-- | Read all the config relevant for a project. This includes the project
368374
-- file if any, plus other global config.
369375
--
370-
readProjectConfig :: Verbosity -> FilePath -> Rebuild ProjectConfig
371-
readProjectConfig verbosity projectRootDir = do
372-
global <- readGlobalConfig verbosity
373-
local <- readProjectLocalConfig verbosity projectRootDir
374-
freeze <- readProjectLocalFreezeConfig verbosity projectRootDir
375-
extra <- readProjectLocalExtraConfig verbosity projectRootDir
376+
readProjectConfig :: Verbosity -> GlobalFlags -> FilePath -> Rebuild ProjectConfig
377+
readProjectConfig verbosity globalFlags projectRootDir = do
378+
global <- readGlobalConfig verbosity
379+
local <- readProjectLocalConfig verbosity globalFlags projectRootDir
380+
freeze <- readProjectLocalFreezeConfig verbosity globalFlags projectRootDir
381+
extra <- readProjectLocalExtraConfig verbosity globalFlags projectRootDir
376382
return (global <> local <> freeze <> extra)
377383

378384

379385
-- | Reads an explicit @cabal.project@ file in the given project root dir,
380386
-- or returns the default project config for an implicitly defined project.
381387
--
382-
readProjectLocalConfig :: Verbosity -> FilePath -> Rebuild ProjectConfig
383-
readProjectLocalConfig verbosity projectRootDir = do
388+
readProjectLocalConfig :: Verbosity -> GlobalFlags -> FilePath -> Rebuild ProjectConfig
389+
readProjectLocalConfig verbosity globalFlags projectRootDir = do
384390
usesExplicitProjectRoot <- liftIO $ doesFileExist projectFile
385391
if usesExplicitProjectRoot
386392
then do
@@ -391,7 +397,7 @@ readProjectLocalConfig verbosity projectRootDir = do
391397
return defaultImplicitProjectConfig
392398

393399
where
394-
projectFile = projectRootDir </> "cabal.project"
400+
projectFile = projectRootDir </> getProjectFileName globalFlags
395401
readProjectFile =
396402
reportParseResult verbosity "project file" projectFile
397403
. parseProjectConfig
@@ -419,25 +425,25 @@ readProjectLocalConfig verbosity projectRootDir = do
419425
-- or returns empty. This file gets written by @cabal configure@, or in
420426
-- principle can be edited manually or by other tools.
421427
--
422-
readProjectLocalExtraConfig :: Verbosity -> FilePath -> Rebuild ProjectConfig
423-
readProjectLocalExtraConfig verbosity =
424-
readProjectExtensionFile verbosity "local"
428+
readProjectLocalExtraConfig :: Verbosity -> GlobalFlags -> FilePath -> Rebuild ProjectConfig
429+
readProjectLocalExtraConfig verbosity globalFlags =
430+
readProjectExtensionFile verbosity globalFlags "local"
425431
"project local configuration file"
426432

427433
-- | Reads a @cabal.project.freeze@ file in the given project root dir,
428434
-- or returns empty. This file gets written by @cabal freeze@, or in
429435
-- principle can be edited manually or by other tools.
430436
--
431-
readProjectLocalFreezeConfig :: Verbosity -> FilePath -> Rebuild ProjectConfig
432-
readProjectLocalFreezeConfig verbosity =
433-
readProjectExtensionFile verbosity "freeze"
437+
readProjectLocalFreezeConfig :: Verbosity -> GlobalFlags -> FilePath -> Rebuild ProjectConfig
438+
readProjectLocalFreezeConfig verbosity globalFlags =
439+
readProjectExtensionFile verbosity globalFlags "freeze"
434440
"project freeze file"
435441

436442
-- | Reads a named config file in the given project root dir, or returns empty.
437443
--
438-
readProjectExtensionFile :: Verbosity -> String -> FilePath
444+
readProjectExtensionFile :: Verbosity -> GlobalFlags -> String -> FilePath
439445
-> FilePath -> Rebuild ProjectConfig
440-
readProjectExtensionFile verbosity extensionName extensionDescription
446+
readProjectExtensionFile verbosity globalFlags extensionName extensionDescription
441447
projectRootDir = do
442448
exists <- liftIO $ doesFileExist extensionFile
443449
if exists
@@ -446,7 +452,9 @@ readProjectExtensionFile verbosity extensionName extensionDescription
446452
else do monitorFiles [monitorNonExistentFile extensionFile]
447453
return mempty
448454
where
449-
extensionFile = projectRootDir </> "cabal.project" <.> extensionName
455+
extensionFile = projectRootDir </> projectFileName <.> extensionName
456+
457+
projectFileName = getProjectFileName globalFlags
450458

451459
readExtensionFile =
452460
reportParseResult verbosity extensionDescription extensionFile
@@ -477,20 +485,20 @@ showProjectConfig =
477485

478486
-- | Write a @cabal.project.local@ file in the given project root dir.
479487
--
480-
writeProjectLocalExtraConfig :: FilePath -> ProjectConfig -> IO ()
481-
writeProjectLocalExtraConfig projectRootDir =
488+
writeProjectLocalExtraConfig :: GlobalFlags -> FilePath -> ProjectConfig -> IO ()
489+
writeProjectLocalExtraConfig globalFlags projectRootDir =
482490
writeProjectConfigFile projectExtraConfigFile
483491
where
484-
projectExtraConfigFile = projectRootDir </> "cabal.project.local"
492+
projectExtraConfigFile = projectRootDir </> getProjectFileName globalFlags <.> "local"
485493

486494

487495
-- | Write a @cabal.project.freeze@ file in the given project root dir.
488496
--
489-
writeProjectLocalFreezeConfig :: FilePath -> ProjectConfig -> IO ()
490-
writeProjectLocalFreezeConfig projectRootDir =
497+
writeProjectLocalFreezeConfig :: GlobalFlags -> FilePath -> ProjectConfig -> IO ()
498+
writeProjectLocalFreezeConfig globalFlags projectRootDir =
491499
writeProjectConfigFile projectFreezeConfigFile
492500
where
493-
projectFreezeConfigFile = projectRootDir </> "cabal.project.freeze"
501+
projectFreezeConfigFile = projectRootDir </> getProjectFileName globalFlags <.> "freeze"
494502

495503

496504
-- | Write in the @cabal.project@ format to the given file.

cabal-install/Distribution/Client/ProjectConfig/Legacy.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,9 @@ convertToLegacySharedConfig
472472
globalRequireSandbox = mempty,
473473
globalIgnoreSandbox = mempty,
474474
globalIgnoreExpiry = projectConfigIgnoreExpiry,
475-
globalHttpTransport = projectConfigHttpTransport
475+
globalHttpTransport = projectConfigHttpTransport,
476+
globalProjectFileName = mempty,
477+
globalDistDirName = mempty
476478
}
477479

478480
configFlags = mempty {

cabal-install/Distribution/Client/ProjectOrchestration.hs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,8 @@ runProjectPreBuildPhase
172172
cabalDir <- defaultCabalDir
173173
let cabalDirLayout = defaultCabalDirLayout cabalDir
174174

175-
projectRootDir <- findProjectRoot
176-
let distDirLayout = defaultDistDirLayout projectRootDir
175+
projectRootDir <- findProjectRoot globalFlags
176+
let distDirLayout = defaultDistDirLayout globalFlags projectRootDir
177177

178178
let cliConfig = commandLineFlagsToProjectConfig
179179
globalFlags configFlags configExFlags
@@ -189,7 +189,7 @@ runProjectPreBuildPhase
189189
-- the user has asked for.
190190
--
191191
(elaboratedPlan, _, elaboratedShared, projectConfig) <-
192-
rebuildInstallPlan verbosity
192+
rebuildInstallPlan verbosity globalFlags
193193
projectRootDir distDirLayout cabalDirLayout
194194
cliConfig
195195

0 commit comments

Comments
 (0)