Skip to content

Commit 860b4f7

Browse files
committed
Fix #6606 Distinguish global and project-level configuration files
Also refactors where: * 'project' is used to refer to a file or directory that may not be within a project directory but within the Stack root; * `stackYaml` is used to refer to a configuration file that may be a user-specific global one as well as a project-level one; or * `userConfigPath` or `stackGlobalConfig` refers to the user-specific global configuration file (`userGlobalConfigFile`). Also refactors descriptions in `stack path` to use the terminology of user-specific global configuration file or project-level configuration file (`stack.yaml`, by default).
1 parent 9b07d28 commit 860b4f7

File tree

25 files changed

+250
-180
lines changed

25 files changed

+250
-180
lines changed

.stan.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,14 @@
8383

8484
# Anti-pattern: Data.ByteString.Char8.pack
8585
[[ignore]]
86-
id = "OBS-STAN-0203-tuE+RG-234:21"
86+
id = "OBS-STAN-0203-tuE+RG-234:24"
8787
# ✦ Description: Usage of 'pack' function that doesn't handle Unicode characters
8888
# ✦ Category: #AntiPattern
8989
# ✦ File: src\Stack\Build\ExecutePackage.hs
9090
#
9191
# 233 ┃
92-
# 234 ┃ newProjectRoot <- S8.pack . toFilePath <$> view projectRootL
93-
# 235 ┃ ^^^^^^^
92+
# 234 ┃ newConfigFileRoot <- S8.pack . toFilePath <$> view configFileRootL
93+
# 235 ┃ ^^^^^^^
9494

9595
# Anti-pattern: Data.ByteString.Char8.pack
9696
[[ignore]]

ChangeLog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ Bug fixes:
7878
specified at the command line.
7979
* Fix a regression, introduced in Stack 2.11.1, that caused the `script` command
8080
to parse an (otherwise ignored) project-level configuration file.
81+
* Stack no longer makes recommendations about a project-level configuration file
82+
when only a global configuration file is in use.
8183

8284
## v2.15.7 - 2024-05-12
8385

doc/maintainers/stack_errors.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,7 @@ to take stock of the errors that Stack itself can raise, by reference to the
422422
[S-5470] | DuplicateLocalPackageNames [(PackageName, [PackageLocation])]
423423
[S-6854] | BadMsysEnvironment MsysEnvironment Arch
424424
[S-5006] | NoDefaultMsysEnvironmentBug
425+
[S-8398] | ConfigFileNotProjectLevelBug
425426
~~~
426427

427428
- `Stack.Types.Config.ParseAbsolutePathException`

src/Stack/Build.hs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ module Stack.Build
1515
) where
1616

1717
import Data.Attoparsec.Args ( EscapingMode (Escaping), parseArgs )
18+
import qualified Data.Either.Extra as EE
1819
import Data.List ( (\\) )
1920
import Data.List.Extra ( groupSort )
2021
import qualified Data.Map as Map
@@ -41,7 +42,7 @@ import Stack.Types.Build
4142
)
4243
import Stack.Types.Build.Exception
4344
( BuildException (..), BuildPrettyException (..) )
44-
import Stack.Types.BuildConfig ( HasBuildConfig, stackYamlL )
45+
import Stack.Types.BuildConfig ( HasBuildConfig, configFileL )
4546
import Stack.Types.BuildOpts ( BuildOpts (..) )
4647
import Stack.Types.BuildOptsCLI
4748
( BuildCommand (..), BuildOptsCLI (..), FileWatchOpts (..) )
@@ -153,11 +154,13 @@ build msetLocalFiles = do
153154
sourceMap <- view $ envConfigL . to (.sourceMap)
154155
locals <- projectLocalPackages
155156
depsLocals <- localDependencies
156-
let allLocals = locals <> depsLocals
157-
158157
boptsCli <- view $ envConfigL . to (.buildOptsCLI)
159158
-- Set local files, necessary for file watching
160-
stackYaml <- view stackYamlL
159+
configFile <- view configFileL
160+
let allLocals = locals <> depsLocals
161+
-- We are indifferent as to whether the configuration file is a
162+
-- user-specifc global or a project-level one.
163+
eitherConfigFile = EE.fromEither configFile
161164
for_ msetLocalFiles $ \setLocalFiles -> do
162165
files <-
163166
if boptsCli.watchAll
@@ -171,7 +174,7 @@ build msetLocalFiles = do
171174
lpFiles lp
172175
Just (TargetComps components) ->
173176
lpFilesForComponents components lp
174-
liftIO $ setLocalFiles $ Set.insert stackYaml $ Set.unions files
177+
liftIO $ setLocalFiles $ Set.insert eitherConfigFile $ Set.unions files
175178

176179
checkComponentsBuildable allLocals
177180

src/Stack/Build/ConstructPlan.hs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ import Stack.Types.Build.Exception
5151
, BuildPrettyException (..), ConstructPlanException (..)
5252
)
5353
import Stack.Types.BuildConfig
54-
( BuildConfig (..), HasBuildConfig (..), stackYamlL )
54+
( BuildConfig (..), HasBuildConfig (..), configFileL )
5555
import Stack.Types.BuildOpts ( BuildOpts (..) )
5656
import Stack.Types.BuildOptsCLI
5757
( BuildOptsCLI (..), BuildSubset (..) )
@@ -187,13 +187,13 @@ constructPlan
187187
else Map.empty
188188
}
189189
else do
190-
stackYaml <- view stackYamlL
190+
configFile <- view configFileL
191191
stackRoot <- view stackRootL
192192
isImplicitGlobal <-
193193
view $ configL . to (isPCGlobalProject . (.project))
194194
prettyThrowM $ ConstructPlanFailed
195195
errs
196-
stackYaml
196+
configFile
197197
stackRoot
198198
isImplicitGlobal
199199
parents

src/Stack/Build/ExecutePackage.hs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ import qualified Stack.Types.Build as ConfigCache ( ConfigCache (..) )
9090
import Stack.Types.Build.Exception
9191
( BuildException (..), BuildPrettyException (..) )
9292
import Stack.Types.BuildConfig
93-
( BuildConfig (..), HasBuildConfig (..), projectRootL )
93+
( BuildConfig (..), HasBuildConfig (..), configFileRootL )
9494
import Stack.Types.BuildOpts
9595
( BenchmarkOpts (..), BuildOpts (..), HaddockOpts (..)
9696
, TestOpts (..)
@@ -231,7 +231,7 @@ ensureConfig newConfigCache pkgDir buildOpts announce cabal cabalFP task = do
231231
(guard . isDoesNotExistError)
232232
(getFileStatus (toFilePath setupConfigfp))
233233
newSetupConfigMod <- getNewSetupConfigMod
234-
newProjectRoot <- S8.pack . toFilePath <$> view projectRootL
234+
newConfigFileRoot <- S8.pack . toFilePath <$> view configFileRootL
235235
-- See https://github.com/commercialhaskell/stack/issues/3554. This can be
236236
-- dropped when Stack drops support for GHC < 8.4.
237237
taskAnyMissingHackEnabled <-
@@ -271,7 +271,7 @@ ensureConfig newConfigCache pkgDir buildOpts announce cabal cabalFP task = do
271271
/= Just (ignoreComponents newConfigCache)
272272
|| mOldCabalMod /= Just newCabalMod
273273
|| mOldSetupConfigMod /= newSetupConfigMod
274-
|| mOldProjectRoot /= Just newProjectRoot
274+
|| mOldProjectRoot /= Just newConfigFileRoot
275275

276276
when task.buildTypeConfig $
277277
-- When build-type is Configure, we need to have a configure script in the
@@ -312,7 +312,7 @@ ensureConfig newConfigCache pkgDir buildOpts announce cabal cabalFP task = do
312312
-- our config mod file is newer than the file above, but this seems
313313
-- reasonable too.
314314
getNewSetupConfigMod >>= writeSetupConfigMod pkgDir
315-
writePackageProjectRoot pkgDir newProjectRoot
315+
writePackageProjectRoot pkgDir newConfigFileRoot
316316
pure needConfig
317317

318318
-- | Make a padded prefix for log messages

src/Stack/Clean.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import Stack.Constants.Config ( rootDistDirFromDir, workDirFromDir )
1818
import Stack.Prelude
1919
import Stack.Runners ( ShouldReexec (..), withConfig )
2020
import Stack.Types.BuildConfig
21-
( BuildConfig (..), HasBuildConfig (..), getProjectWorkDir )
21+
( BuildConfig (..), HasBuildConfig (..), getWorkDir )
2222
import Stack.Types.Config ( Config )
2323
import Stack.Types.Runner ( Runner )
2424
import Stack.Types.SourceMap ( SMWanted (..), ppRoot )
@@ -94,5 +94,5 @@ dirsToDelete cleanOpts = do
9494
xs -> throwM (NonLocalPackages xs)
9595
CleanFull -> do
9696
pkgWorkDirs <- mapM (workDirFromDir . ppRoot) $ Map.elems packages
97-
projectWorkDir <- getProjectWorkDir
97+
projectWorkDir <- getWorkDir
9898
pure (projectWorkDir : pkgWorkDirs)

src/Stack/Config.hs

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import Data.Array.IArray ( (!), (//) )
4242
import qualified Data.ByteString as S
4343
import Data.ByteString.Builder ( byteString )
4444
import Data.Coerce ( coerce )
45+
import qualified Data.Either.Extra as EE
4546
import qualified Data.IntMap as IntMap
4647
import qualified Data.Map as Map
4748
import qualified Data.Map.Merge.Strict as MS
@@ -272,15 +273,16 @@ getLatestSnapshot = do
272273
configFromConfigMonoid ::
273274
(HasRunner env, HasTerm env)
274275
=> Path Abs Dir -- ^ Stack root, e.g. ~/.stack
275-
-> Path Abs File -- ^ user config file path, e.g. ~/.stack/config.yaml
276+
-> Path Abs File
277+
-- ^ User-specific global configuration file.
276278
-> Maybe AbstractSnapshot
277279
-> ProjectConfig (Project, Path Abs File)
278280
-> ConfigMonoid
279281
-> (Config -> RIO env a)
280282
-> RIO env a
281283
configFromConfigMonoid
282284
stackRoot
283-
userConfigPath
285+
userGlobalConfigFile
284286
snapshot
285287
project
286288
configMonoid
@@ -565,7 +567,7 @@ configFromConfigMonoid
565567
(stackRoot </> relFileStorage)
566568
( \userStorage -> inner Config
567569
{ workDir
568-
, userConfigPath
570+
, userGlobalConfigFile
569571
, build
570572
, docker
571573
, nix
@@ -771,16 +773,16 @@ withBuildConfig inner = do
771773
<> " specified on command line"
772774
makeConcreteSnapshot aSnapshot
773775

774-
(project', stackYaml) <- case config.project of
776+
(project', configFile) <- case config.project of
775777
PCProject (project, fp) -> do
776778
forM_ project.userMsg prettyWarnS
777-
pure (project, fp)
779+
pure (project, Right fp)
778780
PCNoProject extraDeps -> do
779781
p <-
780782
case mSnapshot of
781783
Nothing -> throwIO NoSnapshotWhenUsingNoProject
782784
Just _ -> getEmptyProject mSnapshot extraDeps
783-
pure (p, config.userConfigPath)
785+
pure (p, Left config.userGlobalConfigFile)
784786
PCGlobalProject -> do
785787
logDebug "Run from outside a project, using implicit global project config"
786788
destDir <- getImplicitGlobalProjectDir config
@@ -803,7 +805,7 @@ withBuildConfig inner = do
803805
<> " from implicit global project's config file: "
804806
<> fromString dest'
805807
Just _ -> pure ()
806-
pure (project, dest)
808+
pure (project, Right dest)
807809
else do
808810
prettyInfoL
809811
[ flow "Writing the configuration file for the implicit \
@@ -816,10 +818,10 @@ withBuildConfig inner = do
816818
p <- getEmptyProject mSnapshot []
817819
liftIO $ do
818820
writeBinaryFileAtomic dest $ byteString $ S.concat
819-
[ "# This is the implicit global project's config file, which is only used when\n"
820-
, "# 'stack' is run outside of a real project. Settings here do _not_ act as\n"
821+
[ "# This is the implicit global project's configuration file, which is only used\n"
822+
, "# when 'stack' is run outside of a real project. Settings here do _not_ act as\n"
821823
, "# defaults for all projects. To change Stack's default settings, edit\n"
822-
, "# '", encodeUtf8 (T.pack $ toFilePath config.userConfigPath), "' instead.\n"
824+
, "# '", encodeUtf8 (T.pack $ toFilePath config.userGlobalConfigFile), "' instead.\n"
823825
, "#\n"
824826
, "# For more information about Stack's configuration, see\n"
825827
, "# http://docs.haskellstack.org/en/stable/yaml_configuration/\n"
@@ -829,29 +831,31 @@ withBuildConfig inner = do
829831
"This is the implicit global project, which is " <>
830832
"used only when 'stack' is run\noutside of a " <>
831833
"real project.\n"
832-
pure (p, dest)
834+
pure (p, Right dest)
833835
mcompiler <- view $ globalOptsL . to (.compiler)
834836
let project :: Project
835837
project = project'
836838
{ Project.compiler = mcompiler <|> project'.compiler
837839
, Project.snapshot = fromMaybe project'.snapshot mSnapshot
838840
}
841+
-- We are indifferent as to whether the configuration file is a
842+
-- user-specific global or a project-level one.
843+
eitherConfigFile = EE.fromEither configFile
839844
extraPackageDBs <- mapM resolveDir' project.extraPackageDBs
840845

841-
smWanted <- lockCachedWanted stackYaml project.snapshot $
842-
fillProjectWanted stackYaml config project
846+
smWanted <- lockCachedWanted eitherConfigFile project.snapshot $
847+
fillProjectWanted eitherConfigFile config project
843848

844-
-- Unfortunately redoes getProjectWorkDir, since we don't have a BuildConfig
845-
-- yet
849+
-- Unfortunately redoes getWorkDir, since we don't have a BuildConfig yet
846850
workDir <- view workDirL
847-
let projectStorageFile = parent stackYaml </> workDir </> relFileStorage
851+
let projectStorageFile = parent eitherConfigFile </> workDir </> relFileStorage
848852

849853
initProjectStorage projectStorageFile $ \projectStorage -> do
850854
let bc = BuildConfig
851855
{ config
852856
, smWanted
853857
, extraPackageDBs
854-
, stackYaml
858+
, configFile
855859
, curator = project.curator
856860
, projectStorage
857861
}
@@ -891,18 +895,20 @@ withBuildConfig inner = do
891895

892896
fillProjectWanted ::
893897
(HasLogFunc env, HasPantryConfig env, HasProcessContext env)
894-
=> Path Abs t
898+
=> Path Abs File
899+
-- ^ Location of the configuration file, which may be either a
900+
-- user-specific global or a project-level one.
895901
-> Config
896902
-> Project
897903
-> Map RawPackageLocationImmutable PackageLocationImmutable
898904
-> WantedCompiler
899905
-> Map PackageName (Bool -> RIO env DepPackage)
900906
-> RIO env (SMWanted, [CompletedPLI])
901-
fillProjectWanted stackYamlFP config project locCache snapCompiler snapPackages = do
907+
fillProjectWanted configFile config project locCache snapCompiler snapPackages = do
902908
let bopts = config.build
903909

904910
packages0 <- for project.packages $ \fp@(RelFilePath t) -> do
905-
abs' <- resolveDir (parent stackYamlFP) (T.unpack t)
911+
abs' <- resolveDir (parent configFile) (T.unpack t)
906912
let resolved = ResolvedPath fp abs'
907913
pp <- mkProjectPackage YesPrintWarnings resolved bopts.buildHaddocks
908914
pure (pp.projectCommon.name, pp)

src/Stack/ConfigCmd.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ cfgCmdSet cmd = do
105105
fmap (</> stackDotYaml) (getImplicitGlobalProjectDir conf)
106106
PCNoProject _extraDeps -> throwIO NoProjectConfigAvailable
107107
-- maybe modify the ~/.stack/config.yaml file instead?
108-
CommandScopeGlobal -> pure conf.userConfigPath
108+
CommandScopeGlobal -> pure conf.userGlobalConfigFile
109109
rawConfig <- liftIO (readFileUtf8 (toFilePath configFilePath))
110110
config <- either throwM pure (Yaml.decodeEither' $ encodeUtf8 rawConfig)
111111
newValue <- cfgCmdSetValue (parent configFilePath) cmd

src/Stack/Constants/Config.hs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ module Stack.Constants.Config
2626
import Path ( (</>), mkRelDir, mkRelFile, parseRelDir )
2727
import Stack.Constants ( relDirDist, relDirGhci, relDirHpc )
2828
import Stack.Prelude
29-
import Stack.Types.BuildConfig ( HasBuildConfig, projectRootL )
29+
import Stack.Types.BuildConfig ( HasBuildConfig, configFileRootL )
3030
import Stack.Types.Compiler ( compilerVersionString )
3131
import Stack.Types.CompilerPaths ( compilerVersionL )
3232
import Stack.Types.Config ( Config, HasConfig, stackRootL, workDirL )
@@ -37,15 +37,15 @@ import Stack.Types.EnvConfig
3737
objectInterfaceDirL :: HasBuildConfig env => Getting r env (Path Abs Dir)
3838
objectInterfaceDirL = to $ \env -> -- FIXME is this idiomatic lens code?
3939
let workDir = view workDirL env
40-
root = view projectRootL env
41-
in root </> workDir </> $(mkRelDir "odir/")
40+
configFileRoot = view configFileRootL env
41+
in configFileRoot </> workDir </> $(mkRelDir "odir/")
4242

4343
-- | GHCi files directory.
4444
ghciDirL :: HasBuildConfig env => Getting r env (Path Abs Dir)
4545
ghciDirL = to $ \env -> -- FIXME is this idiomatic lens code?
4646
let workDir = view workDirL env
47-
root = view projectRootL env
48-
in root </> workDir </> relDirGhci
47+
configFileRoot = view configFileRootL env
48+
in configFileRoot </> workDir </> relDirGhci
4949

5050
-- | The directory containing the files used for dirtiness check of source
5151
-- files.

0 commit comments

Comments
 (0)