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

Stack init and solver finish up and doc update #1674

Merged
merged 25 commits into from Jan 27, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
16faae1
Create show instances for build plan check results
harendra-kumar Jan 7, 2016
c1b1bb4
Implement Ord and Eq instances for BuildPlanCheck
harendra-kumar Jan 14, 2016
f9449e6
stack init: ignore resolver incompatible packages
harendra-kumar Jan 14, 2016
b2162af
Provide detailed messages when ignoring packages
harendra-kumar Jan 14, 2016
fcfebe0
init - summarise warnings before writing config
harendra-kumar Jan 14, 2016
58eb46c
init: add ignored packages as commented in config
harendra-kumar Jan 15, 2016
93debc6
init - add a user warning message to stack.yaml
harendra-kumar Jan 15, 2016
925952b
Solver: remove one package in conflict and retry
harendra-kumar Jan 15, 2016
b7c535f
Solver: resolve conflict by ignoring packages
harendra-kumar Jan 16, 2016
3e6508d
init - ignore duplicated package names
harendra-kumar Jan 17, 2016
91bb0bb
stack init: add --omit-packages CLI option
harendra-kumar Jan 17, 2016
592cdb0
Choose a resolver which builds max user packages
harendra-kumar Jan 17, 2016
5d7b66d
init: try all major lts snapshot versions
harendra-kumar Jan 17, 2016
f569a16
init: use global --resolver option
harendra-kumar Jan 17, 2016
b6e0cb4
Use simpler syntax in pattern matching
harendra-kumar Jan 18, 2016
9bf8dca
init: fix duplicate package detection
harendra-kumar Jan 18, 2016
1d2343c
init: error out if packages do not have a name
harendra-kumar Jan 18, 2016
0c14ec4
Solver: choose to reject packages in deeper dirs
harendra-kumar Jan 18, 2016
8a415d1
Update stack init documentation in the user guide
harendra-kumar Jan 19, 2016
b4f8fc4
Update stack solver user guide doc
harendra-kumar Jan 19, 2016
ddd3960
Add user-message in yaml configuration user doc
harendra-kumar Jan 19, 2016
0149ba5
Add --install-ghc in stack init doc guide
harendra-kumar Jan 19, 2016
63c7f48
init: check pkg name and .cabal file name match
harendra-kumar Jan 19, 2016
da82ce9
init: allow global --resolver in subcommand
harendra-kumar Jan 19, 2016
4842d88
Add and fix haddocks for stack init and solver
harendra-kumar Jan 19, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
483 changes: 339 additions & 144 deletions doc/GUIDE.md

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions doc/yaml_configuration.md
Expand Up @@ -128,6 +128,28 @@ You can also specify `entrypoints`. By default all your executables are placed
in `/usr/local/bin`, but you can specify a list using `executables` to only add
some.

### user-message

A user-message is inserted by `stack init` when it omits packages or adds
external dependencies. For example:

```yaml
user-message: ! 'Warning: Some packages were found to be incompatible with the resolver
and have been left commented out in the packages section.

Warning: Specified resolver could not satisfy all dependencies. Some external packages
have been added as dependencies.

You can suppress this message by removing it from stack.yaml

'
```

This messages is displayed every time the config is loaded by stack and serves
as a reminder for the user to review the configuration and make any changes if
needed. The user can delete this message if the generated configuration is
acceptable.

## Non-project config

Non-project config options may go in the global config (`/etc/stack/config.yaml`) or the user config (`~/.stack/config.yaml`).
Expand Down
105 changes: 69 additions & 36 deletions src/Stack/BuildPlan.hs
Expand Up @@ -10,10 +10,14 @@
-- snapshot.

module Stack.BuildPlan
( gpdPackages
, BuildPlanException (..)
( BuildPlanException (..)
, BuildPlanCheck (..)
, checkSnapBuildPlan
, DepError(..)
, DepErrors
, gpdPackageDeps
, gpdPackages
, gpdPackageName
, MiniBuildPlan(..)
, MiniPackageInfo(..)
, loadMiniBuildPlan
Expand All @@ -23,8 +27,7 @@ module Stack.BuildPlan
, ToolMap
, getToolMap
, shadowMiniBuildPlan
, showCompilerErrors
, showDepErrors
, showItems
, parseCustomMiniBuildPlan
) where

Expand Down Expand Up @@ -652,6 +655,36 @@ data BuildPlanCheck =
| BuildPlanCheckFail (Map PackageName (Map FlagName Bool)) DepErrors
CompilerVersion

-- Greater means a better plan
instance Ord BuildPlanCheck where
BuildPlanCheckPartial _ e1 `compare` BuildPlanCheckPartial _ e2 =
compare (Map.size e1) (Map.size e2)

BuildPlanCheckFail _ e1 _ `compare` BuildPlanCheckFail _ e2 _ =
let numUserPkgs e = Map.size $ Map.unions (Map.elems (fmap deNeededBy e))
in compare (numUserPkgs e1) (numUserPkgs e2)

BuildPlanCheckOk {} `compare` BuildPlanCheckOk {} = EQ
BuildPlanCheckOk {} `compare` BuildPlanCheckPartial {} = GT
BuildPlanCheckOk {} `compare` BuildPlanCheckFail {} = GT
BuildPlanCheckPartial {} `compare` BuildPlanCheckFail {} = GT
_ `compare` _ = LT

instance Eq BuildPlanCheck where
BuildPlanCheckOk {} == BuildPlanCheckOk {} = True
BuildPlanCheckPartial _ e1 == BuildPlanCheckPartial _ e2 =
Map.size e1 == Map.size e2
BuildPlanCheckFail _ e1 _ == BuildPlanCheckFail _ e2 _ =
let numUserPkgs e = Map.size $ Map.unions (Map.elems (fmap deNeededBy e))
in numUserPkgs e1 == numUserPkgs e2

_ == _ = False

instance Show BuildPlanCheck where
show BuildPlanCheckOk {} = ""
show (BuildPlanCheckPartial f e) = T.unpack $ showDepErrors f e
show (BuildPlanCheckFail f e c) = T.unpack $ showCompilerErrors f e c

-- | Check a set of 'GenericPackageDescription's and a set of flags against a
-- given snapshot. Returns how well the snapshot satisfies the dependencies of
-- the packages.
Expand Down Expand Up @@ -697,67 +730,67 @@ selectBestSnapshot
, MonadBaseControl IO m)
=> [GenericPackageDescription]
-> [SnapName]
-> m (Maybe SnapName)
-> m (SnapName, BuildPlanCheck)
selectBestSnapshot gpds snaps = do
$logInfo $ "Selecting the best among "
<> T.pack (show (length snaps))
<> " snapshots...\n"
loop Nothing snaps
where
loop Nothing [] = return Nothing
loop (Just (snap, _)) [] = return $ Just snap
loop Nothing [] = error "Bug: in best snapshot selection"
loop (Just pair) [] = return pair
loop bestYet (snap:rest) = do
result <- checkSnapBuildPlan gpds Nothing snap
reportResult result snap
let new = (snap, result)
case result of
BuildPlanCheckFail _ _ _ -> loop bestYet rest
BuildPlanCheckOk _ -> return $ Just snap
BuildPlanCheckPartial _ e -> do
case bestYet of
Nothing -> loop (Just (snap, e)) rest
Just prev ->
loop (Just (betterSnap prev (snap, e))) rest

betterSnap (s1, e1) (s2, e2)
| (Map.size e1) <= (Map.size e2) = (s1, e1)
| otherwise = (s2, e2)

reportResult (BuildPlanCheckOk _) snap = do
$logInfo $ "* Selected " <> renderSnapName snap
BuildPlanCheckOk {} -> return new
_ -> case bestYet of
Nothing -> loop (Just new) rest
Just old -> loop (Just (betterSnap old new)) rest

betterSnap (s1, r1) (s2, r2)
| r1 <= r2 = (s1, r1)
| otherwise = (s2, r2)

reportResult BuildPlanCheckOk {} snap = do
$logInfo $ "* Matches " <> renderSnapName snap
$logInfo ""

reportResult (BuildPlanCheckPartial f errs) snap = do
reportResult r@BuildPlanCheckPartial {} snap = do
$logWarn $ "* Partially matches " <> renderSnapName snap
$logWarn $ indent $ showDepErrors f errs
$logWarn $ indent $ T.pack $ show r

reportResult (BuildPlanCheckFail f errs compiler) snap = do
reportResult r@BuildPlanCheckFail {} snap = do
$logWarn $ "* Rejected " <> renderSnapName snap
$logWarn $ indent $ showCompilerErrors f errs compiler
$logWarn $ indent $ T.pack $ show r

indent t = T.unlines $ fmap (" " <>) (T.lines t)

showItems :: Show a => [a] -> Text
showItems items = T.concat (map formatItem items)
where
formatItem item = T.concat
[ " - "
, T.pack $ show item
, "\n"
]

showMapPackages :: Map PackageName a -> Text
showMapPackages mp = showItems $ Map.keys mp

showCompilerErrors
:: Map PackageName (Map FlagName Bool)
-> DepErrors
-> CompilerVersion
-> Text
showCompilerErrors flags errs compiler =
-- TODO print the package filename to enable quick mapping for the user
T.concat
[ compilerVersionText compiler
, " cannot be used for these packages:\n"
, T.concat (map formatError (Map.toList errs))
, showMapPackages $ Map.unions (Map.elems (fmap deNeededBy errs))
, showDepErrors flags errs -- TODO only in debug mode
]
where
formatError (_, DepError _ neededBy) = T.concat $
map formatItem (Map.toList neededBy)

formatItem (user, _) = T.concat
[ " - "
, T.pack $ packageNameString user
, "\n"
]

showDepErrors :: Map PackageName (Map FlagName Bool) -> DepErrors -> Text
showDepErrors flags errs =
Expand Down
8 changes: 7 additions & 1 deletion src/Stack/Config.hs
Expand Up @@ -374,6 +374,11 @@ loadConfig configArgs mstackYaml mresolver = do
(configMonoidDockerOpts c) {dockerMonoidDefaultEnable = False}})
extraConfigs0
mproject <- loadProjectConfig mstackYaml

let printUserMessage (p, _, _) =
maybe (return ()) ($logWarn . T.pack) (projectUserMsg p)
maybe (return ()) printUserMessage mproject

let mproject' = (\(project, stackYaml, _) -> (project, stackYaml)) <$> mproject
config <- configFromConfigMonoid stackRoot userConfigPath mresolver mproject' $ mconcat $
case mproject of
Expand Down Expand Up @@ -435,7 +440,8 @@ loadBuildConfig mproject config mresolver mcompiler = do
$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
{ projectUserMsg = Nothing
, projectPackages = mempty
, projectExtraDeps = mempty
, projectFlags = mempty
, projectResolver = r
Expand Down