Skip to content

Commit

Permalink
Rename config files and clarify their purposes (#969)
Browse files Browse the repository at this point in the history
* Rename `~/.stack/stack.yaml` to `~/.stack/config.yaml`
* Rename `~/.stack/global` to `~/.stack/global-project`
* Rename `/etc/stack/config` to `/etc/stack/config.yaml`
* Support old locations of the renamed paths, with deprecation warnings
* Clarify wording of some messages
* Write comment to top of new `~/.stack/config.yaml` describing its purpose
* Write comment to top of new `~/.stack/global-project/stack.yaml` describing its purpose
* Write `~/.stack/global-project/README` describing the purpose of the directory
  • Loading branch information
borsboom committed Sep 26, 2015
1 parent 42bb3b3 commit d3c8b6c
Show file tree
Hide file tree
Showing 13 changed files with 197 additions and 62 deletions.
7 changes: 6 additions & 1 deletion ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

Major changes:

* "stack setup" now supports building and booting GHCJS from source tarball.
* "stack setup" now supports building and booting GHCJS from source tarball
* Rename config files and clarify their purposes (#969)
* `~/.stack/stack.yaml` --> `~/.stack/config.yaml`
* `~/.stack/global` --> `~/.stack/global-project`
* `/etc/stack/config` --> `/etc/stack/config.yaml`
* Old locations still supported, with deprecation warnings

## 0.1.5.0

Expand Down
10 changes: 5 additions & 5 deletions doc/GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ Downloading template "new-template" to create project "helloworld" in helloworld
Using the following authorship configuration:
author-email: example@example.com
author-name: Example Author Name
Copy these to /home/michael/.stack/stack.yaml and edit to use different values.
Copy these to /home/michael/.stack/config.yaml and edit to use different values.
Writing default config file to: /home/michael/helloworld/stack.yaml
Basing on cabal files:
- /home/michael/helloworld/helloworld.cabal
Expand Down Expand Up @@ -1321,7 +1321,7 @@ follows the Unix convention of `--` to separate these, e.g.:
```
michael@d30748af6d3d:~$ stack exec --package stm -- echo I installed the stm package via --package stm
Run from outside a project, using implicit global config
Run from outside a project, using implicit global project config
Using latest snapshot resolver: lts-3.2
Writing global (non-project-specific) config file to: /home/michael/.stack/global/stack.yaml
Note: You can change the snapshot via the resolver field there.
Expand Down Expand Up @@ -1368,14 +1368,14 @@ import Turtle
main = echo "Hello World!"
michael@d30748af6d3d:~$ chmod +x turtle.hs
michael@d30748af6d3d:~$ ./turtle.hs
Run from outside a project, using implicit global config
Run from outside a project, using implicit global project config
Using resolver: lts-3.2 specified on command line
hashable-1.2.3.3: configure
# installs some more dependencies
Completed all 22 actions.
Hello World!
michael@d30748af6d3d:~$ ./turtle.hs
Run from outside a project, using implicit global config
Run from outside a project, using implicit global project config
Using resolver: lts-3.2 specified on command line
Hello World!
```
Expand Down Expand Up @@ -1545,7 +1545,7 @@ Downloading template "yesod-simple" to create project "my-yesod-project" in my-y
Using the following authorship configuration:
author-email: example@example.com
author-name: Example Author Name
Copy these to /home/michael/.stack/stack.yaml and edit to use different values.
Copy these to /home/michael/.stack/config.yaml and edit to use different values.
Writing default config file to: /home/michael/my-yesod-project/stack.yaml
Basing on cabal files:
- /home/michael/my-yesod-project/my-yesod-project.cabal
Expand Down
2 changes: 1 addition & 1 deletion doc/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ stack has two layers of configuration: project and non-project. All of these
are stored in stack.yaml files, but the former has extra fields (resolver,
packages, extra-deps, and flags). The latter can be monoidally combined so that
a system config file provides defaults, which a user can override with
~/.stack/stack.yaml, and a project can further customize. In addition,
`~/.stack/config.yaml`, and a project can further customize. In addition,
environment variables STACK\_ROOT and STACK\_YAML can be used to tweak where
stack gets its configuration from.

Expand Down
6 changes: 3 additions & 3 deletions doc/yaml_configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ The stack.yaml configuration options break down into [project specific](#project

and [non-project specific](#non-project-config) options in:

- `/etc/stack/config` -- for system global non-project default options
- `~/.stack/stack.yaml` -- for user non-project default options
- `/etc/stack/config.yaml` -- for system global non-project default options
- `~/.stack/config.yaml` -- for user non-project default options
- The project file itself may also contain non-project specific options

*Note:* When stack is invoked outside a stack project it will source project specific options from `~/.stack/global/stack.yaml`. Options in this file will be ignored for a project with its own `<project dir>/stack.yaml`.
Expand Down Expand Up @@ -115,7 +115,7 @@ image:

## Non-project config

Non-project config options may go in the global config (`/etc/stack/config`) or the user config (`~/.stack/stack.yaml`).
Non-project config options may go in the global config (`/etc/stack/config.yaml`) or the user config (`~/.stack/config.yaml`).

### docker

Expand Down
2 changes: 1 addition & 1 deletion src/Stack/Build/Target.hs
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ data NeedTargets

parseTargets :: (MonadThrow m, MonadIO m)
=> NeedTargets -- ^ need at least one target
-> Bool -- ^ using implicit global?
-> Bool -- ^ using implicit global project?
-> Map PackageName Version -- ^ snapshot
-> Map PackageName Version -- ^ extra deps
-> Map PackageName LocalPackageView
Expand Down
97 changes: 76 additions & 21 deletions src/Stack/Config.hs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ module Stack.Config
,loadMiniConfig
,packagesParser
,resolvePackageEntry
,getImplicitGlobalProjectDir
) where

import qualified Codec.Archive.Tar as Tar
Expand All @@ -41,6 +42,7 @@ import Control.Monad.Reader (MonadReader, ask, runReaderT)
import Control.Monad.Trans.Control (MonadBaseControl)
import qualified Crypto.Hash.SHA256 as SHA256
import Data.Aeson.Extended
import qualified Data.ByteString as S
import qualified Data.ByteString.Base16 as B16
import qualified Data.ByteString.Lazy as L
import qualified Data.IntMap as IntMap
Expand Down Expand Up @@ -89,18 +91,15 @@ getLatestResolver = do
Just lts -> lts
return (ResolverSnapshot snap)

-- | Note that this will be @Nothing@ on Windows, which is by design.
defaultStackGlobalConfig :: Maybe (Path Abs File)
defaultStackGlobalConfig = parseAbsFile "/etc/stack/config"

-- Interprets ConfigMonoid options.
configFromConfigMonoid
:: (MonadLogger m, MonadIO m, MonadCatch m, MonadReader env m, HasHttpManager env)
=> Path Abs Dir -- ^ stack root, e.g. ~/.stack
-> Path Abs File -- ^ user config file path, e.g. ~/.stack/config.yaml
-> Maybe Project
-> ConfigMonoid
-> m Config
configFromConfigMonoid configStackRoot mproject configMonoid@ConfigMonoid{..} = do
configFromConfigMonoid configStackRoot configUserConfigPath mproject configMonoid@ConfigMonoid{..} = do
let configDocker = Docker.dockerOptsFromMonoid mproject configStackRoot configMonoidDockerOpts
configConnectionCount = fromMaybe 8 configMonoidConnectionCount
configHideTHLoading = fromMaybe True configMonoidHideTHLoading
Expand Down Expand Up @@ -257,17 +256,18 @@ loadConfig :: (MonadLogger m,MonadIO m,MonadCatch m,MonadThrow m,MonadBaseContro
-> m (LoadConfig m)
loadConfig configArgs mstackYaml = do
stackRoot <- determineStackRoot
extraConfigs <- getExtraConfigs stackRoot >>= mapM loadYaml
userConfigPath <- getDefaultUserConfigPath stackRoot
extraConfigs <- getExtraConfigs userConfigPath >>= mapM loadYaml
mproject <- loadProjectConfig mstackYaml
config <- configFromConfigMonoid stackRoot (fmap (\(proj, _, _) -> proj) mproject) $ mconcat $
config <- configFromConfigMonoid stackRoot userConfigPath (fmap (\(proj, _, _) -> proj) mproject) $ mconcat $
case mproject of
Nothing -> configArgs : extraConfigs
Just (_, _, projectConfig) -> configArgs : projectConfig : extraConfigs
unless (fromCabalVersion Meta.version `withinRange` configRequireStackVersion config)
(throwM (BadStackVersionException (configRequireStackVersion config)))
return $ LoadConfig
{ lcConfig = config
, lcLoadBuildConfig = loadBuildConfig mproject config stackRoot
, lcLoadBuildConfig = loadBuildConfig mproject config
, lcProjectRoot = fmap (\(_, fp, _) -> parent fp) mproject
}

Expand All @@ -276,20 +276,19 @@ loadConfig configArgs mstackYaml = do
loadBuildConfig :: (MonadLogger m, MonadIO m, MonadCatch m, MonadReader env m, HasHttpManager env, MonadBaseControl IO m, HasTerminal env)
=> Maybe (Project, Path Abs File, ConfigMonoid)
-> Config
-> Path Abs Dir
-> Maybe AbstractResolver -- override resolver
-> m BuildConfig
loadBuildConfig mproject config stackRoot mresolver = do
loadBuildConfig mproject config mresolver = do
env <- ask
miniConfig <- loadMiniConfig config

(project', stackYamlFP) <- case mproject of
Just (project, fp, _) -> return (project, fp)
Nothing -> do
$logInfo "Run from outside a project, using implicit global config"
$logInfo "Run from outside a project, using implicit global project config"
destDir <- getImplicitGlobalProjectDir config
let dest :: Path Abs File
dest = destDir </> stackDotYaml
destDir = implicitGlobalDir stackRoot
dest' :: FilePath
dest' = toFilePath dest
createTree destDir
Expand All @@ -301,7 +300,7 @@ loadBuildConfig mproject config stackRoot mresolver = do
case mresolver of
Nothing ->
$logInfo ("Using resolver: " <> resolverName (projectResolver project) <>
" from global config file: " <> T.pack dest')
" from implicit global project's config file: " <> T.pack dest')
Just aresolver -> do
let name =
case aresolver of
Expand All @@ -316,15 +315,28 @@ loadBuildConfig mproject config stackRoot mresolver = do
else do
r <- runReaderT getLatestResolver miniConfig
$logInfo ("Using latest snapshot resolver: " <> resolverName r)
$logInfo ("Writing global (non-project-specific) config file to: " <> T.pack dest')
$logInfo ("Writing implicit global project config file to: " <> T.pack dest')
$logInfo "Note: You can change the snapshot via the resolver field there."
let p = Project
{ projectPackages = mempty
, projectExtraDeps = mempty
, projectFlags = mempty
, projectResolver = r
}
liftIO $ Yaml.encodeFile dest' p
liftIO $ do
S.writeFile dest'
("# This is the implicit global project's config file, which is only used when\n" <>
"# 'stack' is run outside of a real project. Settings here do _not_ act as\n" <>
"# defaults for all projects. To change stack's default settings, edit\n" <>
"# '" <> encodeUtf8 (T.pack $ toFilePath $ configUserConfigPath config) <> "' instead.\n" <>
"#\n" <>
"# For more information about stack's configuration, see\n" <>
"# https://github.com/commercialhaskell/stack/blob/release/doc/yaml_configuration.md\n" <>
"#\n" <>
Yaml.encode p)
S.writeFile (toFilePath $ parent dest </> $(mkRelFile "README.txt")) $
"This is the implicit global project, which is used only when 'stack' is run\n" <>
"outside of a real project.\n"
return (p, dest)
resolver <-
case mresolver of
Expand Down Expand Up @@ -372,7 +384,7 @@ resolvePackageEntry menv projRoot pe = do
subs -> mapM (resolveDir entryRoot) subs
case peValidWanted pe of
Nothing -> return ()
Just _ -> $logWarn "Warning: you are using the deprecated valid-wanted field. You should instead use extra-dep. See: https://github.com/commercialhaskell/stack/blob/master/doc/yaml_configuration.md#packages"
Just _ -> $logWarn "Warning: you are using the deprecated valid-wanted field. You should instead use extra-dep. See: https://github.com/commercialhaskell/stack/blob/release/doc/yaml_configuration.md#packages"
return $ map (, not $ peExtraDep pe) paths

-- | Resolve a PackageLocation into a path, downloading and cloning as
Expand Down Expand Up @@ -460,10 +472,12 @@ determineStackRoot = do
-- | Determine the extra config file locations which exist.
--
-- Returns most local first
getExtraConfigs :: MonadIO m
=> Path Abs Dir -- ^ stack root
getExtraConfigs :: (MonadIO m, MonadLogger m)
=> Path Abs File -- ^ use config path
-> m [Path Abs File]
getExtraConfigs stackRoot = liftIO $ do
getExtraConfigs userConfigPath = do
defaultStackGlobalConfigPath <- getDefaultGlobalConfigPath
liftIO $ do
env <- getEnvironment
mstackConfig <-
maybe (return Nothing) (fmap Just . parseAbsFile)
Expand All @@ -472,8 +486,8 @@ getExtraConfigs stackRoot = liftIO $ do
maybe (return Nothing) (fmap Just . parseAbsFile)
$ lookup "STACK_GLOBAL_CONFIG" env
filterM fileExists
$ fromMaybe (stackRoot </> stackDotYaml) mstackConfig
: maybe [] return (mstackGlobalConfig <|> defaultStackGlobalConfig)
$ fromMaybe userConfigPath mstackConfig
: maybe [] return (mstackGlobalConfig <|> defaultStackGlobalConfigPath)

-- | Load and parse YAML from the given file.
loadYaml :: (FromJSON (a, [JSONWarning]), MonadIO m, MonadLogger m) => Path Abs File -> m a
Expand Down Expand Up @@ -542,5 +556,46 @@ loadProjectConfig mstackYaml = do
ProjectAndConfigMonoid project config <- loadYaml fp
return $ Just (project, fp, config)

-- | Get the location of the default stack configuration file.
-- If a file already exists at the deprecated location, its location is returned.
-- Otherwise, the new location is returned.
getDefaultGlobalConfigPath
:: (MonadIO m, MonadLogger m)
=> m (Maybe (Path Abs File))
getDefaultGlobalConfigPath =
case (defaultGlobalConfigPath, defaultGlobalConfigPathDeprecated) of
(Just new,Just old) ->
(Just . fst ) <$>
tryDeprecatedPath
(Just "non-project global configuration file")
fileExists
new
old
(Just new,Nothing) -> return (Just new)
_ -> return Nothing

-- | Get the location of the default user configuration file.
-- If a file already exists at the deprecated location, its location is returned.
-- Otherwise, the new location is returned.
getDefaultUserConfigPath
:: (MonadIO m, MonadLogger m)
=> Path Abs Dir -> m (Path Abs File)
getDefaultUserConfigPath stackRoot = do
(path, exists) <- tryDeprecatedPath
(Just "non-project configuration file")
fileExists
(defaultUserConfigPath stackRoot)
(defaultUserConfigPathDeprecated stackRoot)
unless exists $ do
createTree (parent path)
liftIO $ S.writeFile (toFilePath path) $
"# This file contains default non-project-specific settings for 'stack', used\n" <>
"# in all projects. For more information about stack's configuration, see\n" <>
"# https://github.com/commercialhaskell/stack/blob/release/doc/yaml_configuration.md\n" <>
"#\n" <>
Yaml.encode (mempty :: Object)
return path


packagesParser :: Parser [String]
packagesParser = many (strOption (long "package" <> help "Additional packages that must be installed"))
46 changes: 37 additions & 9 deletions src/Stack/Constants.hs
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,17 @@ module Stack.Constants
,stackProgName
,wiredInPackages
,cabalPackageName
,implicitGlobalDir
,implicitGlobalProjectDirDeprecated
,implicitGlobalProjectDir
,hpcRelativeDir
,hpcDirFromDir
,dotHpc
,objectInterfaceDir
,templatesDir
,globalConfigPath
,defaultUserConfigPathDeprecated
,defaultUserConfigPath
,defaultGlobalConfigPathDeprecated
,defaultGlobalConfigPath
)
where

Expand Down Expand Up @@ -285,17 +289,41 @@ cabalPackageName :: PackageName
cabalPackageName =
$(mkPackageName "Cabal")

-- | Implicit global directory used when outside of a project.
implicitGlobalDir :: Path Abs Dir -- ^ Stack root.
-> Path Abs Dir
implicitGlobalDir p =
-- | Deprecated implicit global project directory used when outside of a project.
implicitGlobalProjectDirDeprecated :: Path Abs Dir -- ^ Stack root.
-> Path Abs Dir
implicitGlobalProjectDirDeprecated p =
p </>
$(mkRelDir "global")

-- | Implicit global project directory used when outside of a project.
-- Normally, @getImplicitGlobalProjectDir@ should be used instead.
implicitGlobalProjectDir :: Path Abs Dir -- ^ Stack root.
-> Path Abs Dir
implicitGlobalProjectDir p =
p </>
$(mkRelDir "global-project")

-- | Where .mix files go.
dotHpc :: Path Rel Dir
dotHpc = $(mkRelDir ".hpc")

-- | Global config path.
globalConfigPath :: Config -> Path Abs File
globalConfigPath = (</> $(mkRelFile "stack.yaml")) . configStackRoot
-- | Deprecated default global config path.
defaultUserConfigPathDeprecated :: Path Abs Dir -> Path Abs File
defaultUserConfigPathDeprecated = (</> $(mkRelFile "stack.yaml"))

-- | Default global config path.
-- Normally, @getDefaultUserConfigPath@ should be used instead.
defaultUserConfigPath :: Path Abs Dir -> Path Abs File
defaultUserConfigPath = (</> $(mkRelFile "config.yaml"))

-- | Deprecated default global config path.
-- Note that this will be @Nothing@ on Windows, which is by design.
defaultGlobalConfigPathDeprecated :: Maybe (Path Abs File)
defaultGlobalConfigPathDeprecated = parseAbsFile "/etc/stack/config"

-- | Default global config path.
-- Normally, @getDefaultGlobalConfigPath@ should be used instead.
-- Note that this will be @Nothing@ on Windows, which is by design.
defaultGlobalConfigPath :: Maybe (Path Abs File)
defaultGlobalConfigPath = parseAbsFile "/etc/stack/config.yaml"
Loading

0 comments on commit d3c8b6c

Please sign in to comment.