Skip to content

Commit

Permalink
Detect invalid flag specifications #617
Browse files Browse the repository at this point in the history
  • Loading branch information
snoyberg committed Jul 22, 2015
1 parent 57ac913 commit 5c9f03c
Show file tree
Hide file tree
Showing 18 changed files with 149 additions and 0 deletions.
1 change: 1 addition & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* Don't require cabal-install to upload [#313](https://github.com/commercialhaskell/stack/issues/313)
* Generate indexes for all deps and all installed snapshot packages [#143](https://github.com/fpco/commercialhaskell/issues/143)
* Provide `--resolver global` option [#645](https://github.com/commercialhaskell/stack/issues/645)
* Make `stack build --flag` error when flag or package is unknown [#617](https://github.com/commercialhaskell/stack/issues/617)

Bug fixes:

Expand Down
29 changes: 29 additions & 0 deletions src/Stack/Build/Source.hs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ module Stack.Build.Source
) where

import Control.Applicative ((<|>), (<$>), (<*>))
import Control.Arrow ((&&&))
import Control.Exception (catch)
import Control.Monad
import Control.Monad.Catch (MonadCatch)
Expand Down Expand Up @@ -247,6 +248,34 @@ loadLocals bopts latestVersion = do
let known = Set.fromList $ map (packageName . lpPackage) lps
unknown = Set.difference (Map.keysSet names) known

-- Check if flags specified in stack.yaml and the command line are
-- used, see https://github.com/commercialhaskell/stack/issues/617
flags = map (, FSCommandLine) [(k, v) | (Just k, v) <- Map.toList $ boptsFlags bopts]
++ map (, FSStackYaml) (Map.toList $ bcFlags bconfig)

localNameMap = Map.fromList $ map (packageName . lpPackage &&& lpPackage) lps
checkFlagUsed ((name, userFlags), source) =
case Map.lookup name localNameMap of
-- Package is not available locally
Nothing ->
case Map.lookup name $ bcExtraDeps bconfig of
-- Also not in extra-deps, it's an error
Nothing -> Just $ UFNoPackage source name
-- We don't check for flag presence for extra deps
Just _ -> Nothing
-- Package exists locally, let's check if the flags are defined
Just pkg ->
let unused = Set.difference (Map.keysSet userFlags) (packageDefinedFlags pkg)
in if Set.null unused
-- All flags are defined, nothing to do
then Nothing
-- Error about the undefined flags
else Just $ UFFlagsNotDefined source name unused

unusedFlags = mapMaybe checkFlagUsed flags

unless (null unusedFlags) $ throwM $ InvalidFlagSpecification $ Set.fromList unusedFlags

return (lps, unknown, idents)
where
-- Attempt to parse a TargetSpec based on its textual form and on
Expand Down
33 changes: 33 additions & 0 deletions src/Stack/Build/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

module Stack.Build.Types
(StackBuildException(..)
,FlagSource(..)
,UnusedFlags(..)
,InstallLocation(..)
,ModTime
,modTime
Expand Down Expand Up @@ -95,8 +97,16 @@ data StackBuildException
Version -- local version
Version -- version specified on command line
| NoSetupHsFound (Path Abs Dir)
| InvalidFlagSpecification (Set UnusedFlags)
deriving Typeable

data FlagSource = FSCommandLine | FSStackYaml
deriving (Show, Eq, Ord)

data UnusedFlags = UFNoPackage FlagSource PackageName
| UFFlagsNotDefined FlagSource PackageName (Set FlagName)
deriving (Show, Eq, Ord)

instance Show StackBuildException where
show (Couldn'tFindPkgId name) =
("After installing " <> packageNameString name <>
Expand Down Expand Up @@ -224,6 +234,29 @@ instance Show StackBuildException where
]
show (NoSetupHsFound dir) =
"No Setup.hs or Setup.lhs file found in " ++ toFilePath dir
show (InvalidFlagSpecification unused) = unlines
$ "Invalid flag specification:"
: map go (Set.toList unused)
where
goS :: FlagSource -> String
goS FSCommandLine = " (specified on command line)"
goS FSStackYaml = " (specified in stack.yaml)"

go :: UnusedFlags -> String
go (UFNoPackage src name) = concat
[ "- Package '"
, packageNameString name
, "' not found"
, goS src
]
go (UFFlagsNotDefined src name flags) = concat
[ "- Package '"
, packageNameString name
, "' does not define the following flags"
, goS src
, ": "
, intercalate ", " $ map flagNameString $ Set.toList flags
]

instance Exception StackBuildException

Expand Down
2 changes: 2 additions & 0 deletions src/Stack/Package.hs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ data Package =
,packageOpts :: !GetPackageOpts -- ^ Args to pass to GHC.
,packageHasExposedModules :: !Bool -- ^ Does the package have exposed modules?
,packageSimpleType :: !Bool -- ^ Does the package of build-type: Simple
,packageDefinedFlags :: !(Set FlagName) -- ^ All flags defined in the .cabal file
}
deriving (Show,Typeable)

Expand Down Expand Up @@ -259,6 +260,7 @@ resolvePackage packageConfig gpkg = Package
generatePkgDescOpts locals cabalfp pkg
, packageHasExposedModules = maybe False (not . null . exposedModules) (library pkg)
, packageSimpleType = buildType (packageDescription gpkg) == Just Simple
, packageDefinedFlags = S.fromList $ map (fromCabalFlagName . flagName) $ genPackageFlags gpkg
}

where
Expand Down
4 changes: 4 additions & 0 deletions test/integration/tests/617-extra-dep-flag/Main.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import StackTest

main :: IO ()
main = stack ["build"]
7 changes: 7 additions & 0 deletions test/integration/tests/617-extra-dep-flag/files/stack.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
resolver: ghc-7.8
flags:
text:
integer-simple: false
extra-deps:
- text-1.2.0.3
packages: []
8 changes: 8 additions & 0 deletions test/integration/tests/617-unused-flag-cli/Main.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import StackTest

main :: IO ()
main = do
stack ["build"]
stackErr ["build", "--flag", "foo:bar"]
stackErr ["build", "--flag", "files:bar"]
stack ["build", "--flag", "*:bar"]
10 changes: 10 additions & 0 deletions test/integration/tests/617-unused-flag-cli/files/files.cabal
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
name: files
version: 0.1.0.0
build-type: Simple
cabal-version: >=1.10

library
hs-source-dirs: src
exposed-modules: Lib
build-depends: base >= 4.7 && < 5
default-language: Haskell2010
6 changes: 6 additions & 0 deletions test/integration/tests/617-unused-flag-cli/files/src/Lib.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Lib
( someFunc
) where

someFunc :: IO ()
someFunc = putStrLn "someFunc"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
resolver: ghc-7.8
4 changes: 4 additions & 0 deletions test/integration/tests/617-unused-flag-name-yaml/Main.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import StackTest

main :: IO ()
main = stackErr ["build"]
10 changes: 10 additions & 0 deletions test/integration/tests/617-unused-flag-name-yaml/files/files.cabal
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
name: files
version: 0.1.0.0
build-type: Simple
cabal-version: >=1.10

library
hs-source-dirs: src
exposed-modules: Lib
build-depends: base >= 4.7 && < 5
default-language: Haskell2010
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Lib
( someFunc
) where

someFunc :: IO ()
someFunc = putStrLn "someFunc"
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
resolver: ghc-7.8
flags:
files:
does-not-exist: false
4 changes: 4 additions & 0 deletions test/integration/tests/617-unused-flag-yaml/Main.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import StackTest

main :: IO ()
main = stackErr ["build"]
10 changes: 10 additions & 0 deletions test/integration/tests/617-unused-flag-yaml/files/files.cabal
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
name: files
version: 0.1.0.0
build-type: Simple
cabal-version: >=1.10

library
hs-source-dirs: src
exposed-modules: Lib
build-depends: base >= 4.7 && < 5
default-language: Haskell2010
6 changes: 6 additions & 0 deletions test/integration/tests/617-unused-flag-yaml/files/src/Lib.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Lib
( someFunc
) where

someFunc :: IO ()
someFunc = putStrLn "someFunc"
4 changes: 4 additions & 0 deletions test/integration/tests/617-unused-flag-yaml/files/stack.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
resolver: ghc-7.8
flags:
does-not-exist:
foo: false

0 comments on commit 5c9f03c

Please sign in to comment.