hpack 0.34.2 → 0.34.3
raw patch · 18 files changed
+623/−274 lines, 18 filesdep ~directoryPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: directory
API changes (from Hackage documentation)
+ Hpack.Config: CondBool :: Bool -> Cond
+ Hpack.Config: CondExpression :: String -> Cond
+ Hpack.Config: Module :: String -> Module
+ Hpack.Config: [unModule] :: Module -> String
+ Hpack.Config: data Cond
+ Hpack.Config: newtype Module
- Hpack.Config: Conditional :: String -> a -> Maybe a -> Conditional a
+ Hpack.Config: Conditional :: Cond -> a -> Maybe a -> Conditional a
- Hpack.Config: Executable :: Maybe FilePath -> [String] -> [String] -> Executable
+ Hpack.Config: Executable :: Maybe FilePath -> [Module] -> [Module] -> Executable
- Hpack.Config: Library :: Maybe Bool -> Maybe String -> [String] -> [String] -> [String] -> [String] -> [String] -> Library
+ Hpack.Config: Library :: Maybe Bool -> Maybe String -> [Module] -> [Module] -> [Module] -> [String] -> [String] -> Library
- Hpack.Config: Package :: String -> String -> Maybe String -> Maybe String -> Maybe String -> Maybe String -> Maybe String -> Maybe String -> [String] -> [String] -> [String] -> BuildType -> Maybe String -> [FilePath] -> Maybe String -> [Flag] -> [Path] -> [Path] -> [Path] -> Maybe FilePath -> Maybe SourceRepository -> Maybe CustomSetup -> Maybe (Section Library) -> Map String (Section Library) -> Map String (Section Executable) -> Map String (Section Executable) -> Map String (Section Executable) -> [Verbatim] -> Package
+ Hpack.Config: Package :: String -> String -> Maybe String -> Maybe String -> Maybe String -> Maybe String -> Maybe String -> Maybe String -> [String] -> [String] -> [String] -> BuildType -> Maybe String -> [FilePath] -> [String] -> [Flag] -> [Path] -> [Path] -> [Path] -> Maybe FilePath -> Maybe SourceRepository -> Maybe CustomSetup -> Maybe (Section Library) -> Map String (Section Library) -> Map String (Section Executable) -> Map String (Section Executable) -> Map String (Section Executable) -> [Verbatim] -> Package
- Hpack.Config: [conditionalCondition] :: Conditional a -> String
+ Hpack.Config: [conditionalCondition] :: Conditional a -> Cond
- Hpack.Config: [executableGeneratedModules] :: Executable -> [String]
+ Hpack.Config: [executableGeneratedModules] :: Executable -> [Module]
- Hpack.Config: [executableOtherModules] :: Executable -> [String]
+ Hpack.Config: [executableOtherModules] :: Executable -> [Module]
- Hpack.Config: [libraryExposedModules] :: Library -> [String]
+ Hpack.Config: [libraryExposedModules] :: Library -> [Module]
- Hpack.Config: [libraryGeneratedModules] :: Library -> [String]
+ Hpack.Config: [libraryGeneratedModules] :: Library -> [Module]
- Hpack.Config: [libraryOtherModules] :: Library -> [String]
+ Hpack.Config: [libraryOtherModules] :: Library -> [Module]
- Hpack.Config: [packageTestedWith] :: Package -> Maybe String
+ Hpack.Config: [packageTestedWith] :: Package -> [String]
Files
- CHANGELOG.md +14/−0
- hpack.cabal +9/−4
- src/Hpack/Config.hs +114/−72
- src/Hpack/Haskell.hs +4/−3
- src/Hpack/Module.hs +114/−0
- src/Hpack/Render.hs +16/−10
- src/Hpack/Render/Hints.hs +6/−2
- src/Hpack/Syntax/Dependencies.hs +1/−1
- src/Hpack/Syntax/DependencyVersion.hs +3/−3
- src/Hpack/Util.hs +21/−35
- src/Path.hs +25/−0
- test/EndToEndSpec.hs +214/−84
- test/Helper.hs +7/−0
- test/Hpack/ConfigSpec.hs +3/−22
- test/Hpack/ModuleSpec.hs +58/−0
- test/Hpack/Render/HintsSpec.hs +13/−2
- test/Hpack/RenderSpec.hs +1/−1
- test/Hpack/UtilSpec.hs +0/−35
CHANGELOG.md view
@@ -1,3 +1,17 @@+## Changes in 0.34.3+ - Ignore duplicate source directories (see #356)+ - Do not infer duplicate modules (see #408, #406, #353)+ - Reject empty `then` / `else` sections (see #362)+ - Omit conditionals that are always `false` from generated `.cabal` file+ (see #404)+ - Infer correct `cabal-version` when `Path_` is used with `RebindableSyntax`+ and `OverloadedStrings` or `OverloadedLists` (see #400)+ - Do not use indentation from any existing `.cabal` file if it is invalid+ (e.g. `0`) (fixes #252)+ - Accept lists for `tested-with` (see #407)+ - Render current directory as `./` instead of `./.` for forward compatibility+ with future version of Cabal+ ## Changes in 0.34.2 - Accept subcomponents as dependencies (close #382)
hpack.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: hpack-version: 0.34.2+version: 0.34.3 synopsis: A modern format for Haskell packages description: See README at <https://github.com/sol/hpack#readme> category: Development@@ -36,7 +36,7 @@ , containers , cryptonite , deepseq- , directory+ , directory >=1.2.5.0 , filepath , http-client , http-client-tls@@ -63,6 +63,7 @@ Hpack.Defaults Hpack.Haskell Hpack.License+ Hpack.Module Hpack.Options Hpack.Render.Dsl Hpack.Render.Hints@@ -74,6 +75,7 @@ Hpack.Syntax.ParseDependencies Hpack.Utf8 Hpack.Util+ Path Paths_hpack default-language: Haskell2010 @@ -92,7 +94,7 @@ , containers , cryptonite , deepseq- , directory+ , directory >=1.2.5.0 , filepath , hpack , http-client@@ -130,7 +132,7 @@ , containers , cryptonite , deepseq- , directory+ , directory >=1.2.5.0 , filepath , hspec ==2.* , http-client@@ -161,6 +163,7 @@ Hpack.DefaultsSpec Hpack.HaskellSpec Hpack.LicenseSpec+ Hpack.ModuleSpec Hpack.OptionsSpec Hpack.Render.DslSpec Hpack.Render.HintsSpec@@ -182,6 +185,7 @@ Hpack.Defaults Hpack.Haskell Hpack.License+ Hpack.Module Hpack.Options Hpack.Render Hpack.Render.Dsl@@ -195,5 +199,6 @@ Hpack.Utf8 Hpack.Util Hpack.Yaml+ Path Paths_hpack default-language: Haskell2010
src/Hpack/Config.hs view
@@ -56,6 +56,7 @@ , Library(..) , Executable(..) , Conditional(..)+, Cond(..) , Flag(..) , SourceRepository(..) , BuildType(..)@@ -65,12 +66,11 @@ , CcOption , LdOption , Path(..)+, Module(..) #ifdef TEST , renameDependencies , Empty(..)-, getModules , pathsModuleFromPackageName-, Cond(..) , LibrarySection(..) , fromLibrarySectionInConditional@@ -89,13 +89,14 @@ import Data.Map.Lazy (Map) import qualified Data.Map.Lazy as Map import qualified Data.HashMap.Lazy as HashMap-import Data.List (nub, (\\), sortBy, intercalate)+import Data.List ((\\), sortBy, intercalate) import Data.Maybe import Data.Semigroup (Semigroup(..)) import Data.Ord import Data.String import Data.Text (Text) import qualified Data.Text as T+import Data.Text.Encoding (decodeUtf8) import Data.Scientific (Scientific) import System.Directory import System.FilePath@@ -108,6 +109,8 @@ import Distribution.Pretty (prettyShow) import qualified Distribution.SPDX.License as SPDX +import qualified Data.Yaml.Pretty as Yaml+import Data.Aeson (object, (.=)) import Data.Aeson.Config.Types import Data.Aeson.Config.FromValue hiding (decodeValue) import qualified Data.Aeson.Config.FromValue as Config@@ -122,7 +125,10 @@ import Hpack.Syntax.BuildTools import Hpack.License import Hpack.CabalFile (parseVersion)+import Hpack.Module +import qualified Path+ import qualified Paths_hpack as Hpack (version) package :: String -> String -> Package@@ -141,7 +147,7 @@ , packageBuildType = Simple , packageLicense = Nothing , packageLicenseFile = []- , packageTestedWith = Nothing+ , packageTestedWith = [] , packageFlags = [] , packageExtraSourceFiles = [] , packageExtraDocFiles = []@@ -197,10 +203,10 @@ data LibrarySection = LibrarySection { librarySectionExposed :: Maybe Bool , librarySectionVisibility :: Maybe String-, librarySectionExposedModules :: Maybe (List String)-, librarySectionGeneratedExposedModules :: Maybe (List String)-, librarySectionOtherModules :: Maybe (List String)-, librarySectionGeneratedOtherModules :: Maybe (List String)+, librarySectionExposedModules :: Maybe (List Module)+, librarySectionGeneratedExposedModules :: Maybe (List Module)+, librarySectionOtherModules :: Maybe (List Module)+, librarySectionGeneratedOtherModules :: Maybe (List Module) , librarySectionReexportedModules :: Maybe (List String) , librarySectionSignatures :: Maybe (List String) } deriving (Eq, Show, Generic, FromValue)@@ -223,8 +229,8 @@ data ExecutableSection = ExecutableSection { executableSectionMain :: Maybe FilePath-, executableSectionOtherModules :: Maybe (List String)-, executableSectionGeneratedOtherModules :: Maybe (List String)+, executableSectionOtherModules :: Maybe (List Module)+, executableSectionGeneratedOtherModules :: Maybe (List Module) } deriving (Eq, Show, Generic, FromValue) instance Monoid ExecutableSection where@@ -424,25 +430,54 @@ instance FromValue a => FromValue (ParseConditionalSection a) where fromValue v- | hasKey "then" v || hasKey "else" v = ThenElseConditional <$> fromValue v+ | hasKey "then" v || hasKey "else" v = ThenElseConditional <$> fromValue v <* giveHint | otherwise = FlatConditional <$> fromValue v+ where+ giveHint = case v of+ Object o -> case (,,) <$> HashMap.lookup "then" o <*> HashMap.lookup "else" o <*> HashMap.lookup "condition" o of+ Just (Object then_, Object else_, String condition) -> do+ when (HashMap.null then_) $ "then" `emptyTryInstead` flatElse+ when (HashMap.null else_) $ "else" `emptyTryInstead` flatThen+ where+ flatThen = flatConditional condition then_+ flatElse = flatConditional (negate_ condition) else_+ _ -> return ()+ _ -> return () + negate_ condition = "!(" <> condition <> ")"++ flatConditional condition sect = object [("when" .= HashMap.insert "condition" (String condition) sect)]++ emptyTryInstead :: String -> Value -> Parser ()+ emptyTryInstead name sect = do+ fail $ "an empty " <> show name <> " section is not allowed, try the following instead:\n\n" ++ encodePretty sect++ encodePretty = T.unpack . decodeUtf8 . Yaml.encodePretty c+ where+ c :: Yaml.Config+ c = Yaml.setConfCompare f Yaml.defConfig+ where+ f a b = case (a, b) of+ ("condition", "condition") -> EQ+ ("condition", _) -> LT+ (_, "condition") -> GT+ _ -> compare a b+ hasKey :: Text -> Value -> Bool hasKey key (Object o) = HashMap.member key o hasKey _ _ = False newtype Condition = Condition {- _conditionCondition :: Cond+ conditionCondition :: Cond } deriving (Eq, Show, Generic, FromValue) -newtype Cond = Cond String+data Cond = CondBool Bool | CondExpression String deriving (Eq, Show) instance FromValue Cond where fromValue v = case v of- String s -> return (Cond $ T.unpack s)- Bool True -> return (Cond "true")- Bool False -> return (Cond "false")+ String c -> return (CondExpression $ T.unpack c)+ Bool c -> return (CondBool c) _ -> typeMismatch "Boolean or String" v data ThenElse cSources cxxSources jsSources a = ThenElse {@@ -528,7 +563,7 @@ , packageConfigBuildType :: Maybe BuildType , packageConfigLicense :: Maybe (Maybe String) , packageConfigLicenseFile :: Maybe (List String)-, packageConfigTestedWith :: Maybe String+, packageConfigTestedWith :: Maybe (List String) , packageConfigFlags :: Maybe (Map String FlagSection) , packageConfigExtraSourceFiles :: Maybe (List FilePath) , packageConfigExtraDocFiles :: Maybe (List FilePath)@@ -710,7 +745,7 @@ , makeVersion [2,0] <$ guard (has librarySignatures) , makeVersion [2,0] <$ guard (has libraryGeneratedModules) , makeVersion [3,0] <$ guard (has libraryVisibility)- , sectionCabalVersion sect+ , sectionCabalVersion (concatMap getLibraryModules) sect ] where has field = any (not . null . field) sect@@ -728,20 +763,29 @@ executableCabalVersion :: Section Executable -> Maybe Version executableCabalVersion sect = maximum [ makeVersion [2,0] <$ guard (executableHasGeneratedModules sect)- , sectionCabalVersion sect+ , sectionCabalVersion (concatMap getExecutableModules) sect ] executableHasGeneratedModules :: Section Executable -> Bool executableHasGeneratedModules = any (not . null . executableGeneratedModules) - sectionCabalVersion :: Section a -> Maybe Version- sectionCabalVersion sect = maximum $ [+ sectionCabalVersion :: (Section a -> [Module]) -> Section a -> Maybe Version+ sectionCabalVersion getMentionedModules sect = maximum $ [ makeVersion [2,2] <$ guard (sectionSatisfies (not . null . sectionCxxSources) sect) , makeVersion [2,2] <$ guard (sectionSatisfies (not . null . sectionCxxOptions) sect) , makeVersion [2,0] <$ guard (sectionSatisfies (any hasMixins . unDependencies . sectionDependencies) sect) , makeVersion [3,0] <$ guard (sectionSatisfies (any hasSubcomponents . Map.keys . unDependencies . sectionDependencies) sect)+ , makeVersion [2,2] <$ guard (+ uses "RebindableSyntax"+ && (uses "OverloadedStrings" || uses "OverloadedLists")+ && pathsModule `elem` getMentionedModules sect) ] ++ map versionFromSystemBuildTool systemBuildTools where+ defaultExtensions = sectionAll sectionDefaultExtensions sect+ uses = (`elem` defaultExtensions)++ pathsModule = pathsModuleFromPackageName packageName+ versionFromSystemBuildTool name | name `elem` known_1_10 = Nothing | name `elem` known_1_14 = Just (makeVersion [1,14])@@ -793,8 +837,6 @@ p sect , any (any (sectionSatisfies p)) (sectionConditionals sect) ]- sectionAll :: (Semigroup b, Monoid b) => (Section a -> b) -> Section a -> b- sectionAll f sect = f sect <> foldMap (foldMap $ sectionAll f) (sectionConditionals sect) hasMixins :: DependencyInfo -> Bool hasMixins (DependencyInfo mixins _) = not (null mixins)@@ -802,6 +844,9 @@ hasSubcomponents :: String -> Bool hasSubcomponents = elem ':' +sectionAll :: (Semigroup b, Monoid b) => (Section a -> b) -> Section a -> b+sectionAll f sect = f sect <> foldMap (foldMap $ sectionAll f) (sectionConditionals sect)+ decodeValue :: FromValue a => ProgramName -> FilePath -> Value -> Warnings (Errors IO) a decodeValue (ProgramName programName) file value = do (r, unknown) <- lift . ExceptT . return $ first (prefix ++) (Config.decodeValue value)@@ -849,7 +894,7 @@ , packageBuildType :: BuildType , packageLicense :: Maybe String , packageLicenseFile :: [FilePath]-, packageTestedWith :: Maybe String+, packageTestedWith :: [String] , packageFlags :: [Flag] , packageExtraSourceFiles :: [Path] , packageExtraDocFiles :: [Path]@@ -872,17 +917,17 @@ data Library = Library { libraryExposed :: Maybe Bool , libraryVisibility :: Maybe String-, libraryExposedModules :: [String]-, libraryOtherModules :: [String]-, libraryGeneratedModules :: [String]+, libraryExposedModules :: [Module]+, libraryOtherModules :: [Module]+, libraryGeneratedModules :: [Module] , libraryReexportedModules :: [String] , librarySignatures :: [String] } deriving (Eq, Show) data Executable = Executable { executableMain :: Maybe FilePath-, executableOtherModules :: [String]-, executableGeneratedModules :: [String]+, executableOtherModules :: [Module]+, executableGeneratedModules :: [Module] } deriving (Eq, Show) data BuildTool = BuildTool String String | LocalBuildTool String@@ -919,7 +964,7 @@ } deriving (Eq, Show, Functor, Foldable, Traversable) data Conditional a = Conditional {- conditionalCondition :: String+ conditionalCondition :: Cond , conditionalThen :: a , conditionalElse :: Maybe a } deriving (Eq, Show, Functor, Foldable, Traversable)@@ -1063,12 +1108,15 @@ toSect :: (Monad m, Monoid a) => WithCommonOptions CSources CxxSources JsSources a -> Warnings m (Section a) toSect = toSection packageName_ executableNames . first ((mempty <$ globalOptions) <>) - toLib = toSect >=> liftIO . toLibrary dir packageName_- toExecutables = maybe (return mempty) (traverse $ toSect >=> liftIO . toExecutable dir packageName_)+ toSections :: (Monad m, Monoid a) => Maybe (Map String (WithCommonOptions CSources CxxSources JsSources a)) -> Warnings m (Map String (Section a))+ toSections = maybe (return mempty) (traverse toSect) - mLibrary <- traverse toLib packageConfigLibrary- internalLibraries <- maybe (return mempty) (traverse toLib) packageConfigInternalLibraries+ toLib = liftIO . toLibrary dir packageName_+ toExecutables = toSections >=> traverse (liftIO . toExecutable dir packageName_) + mLibrary <- traverse (toSect >=> toLib) packageConfigLibrary+ internalLibraries <- toSections packageConfigInternalLibraries >>= traverse toLib+ executables <- toExecutables executableMap tests <- toExecutables packageConfigTests benchmarks <- toExecutables packageConfigBenchmarks@@ -1124,7 +1172,7 @@ , packageBuildType = fromMaybe defaultBuildType packageConfigBuildType , packageLicense = join packageConfigLicense , packageLicenseFile = licenseFiles- , packageTestedWith = packageConfigTestedWith+ , packageTestedWith = fromMaybeList packageConfigTestedWith , packageFlags = flags , packageExtraSourceFiles = extraSourceFiles , packageExtraDocFiles = extraDocFiles@@ -1234,23 +1282,36 @@ where traverseConditionals = traverse . traverse . traverseSectionAndConditionals fConditionals fConditionals -getMentionedLibraryModules :: LibrarySection -> [String]+getMentionedLibraryModules :: LibrarySection -> [Module] getMentionedLibraryModules (LibrarySection _ _ exposedModules generatedExposedModules otherModules generatedOtherModules _ _) = fromMaybeList (exposedModules <> generatedExposedModules <> otherModules <> generatedOtherModules) -listModules :: FilePath -> Section a -> IO [String]+getLibraryModules :: Library -> [Module]+getLibraryModules Library{..} = libraryExposedModules ++ libraryOtherModules++getExecutableModules :: Executable -> [Module]+getExecutableModules Executable{..} = executableOtherModules++listModules :: FilePath -> Section a -> IO [Module] listModules dir Section{..} = concat <$> mapM (getModules dir) sectionSourceDirs +removeConditionalsThatAreAlwaysFalse :: Section a -> Section a+removeConditionalsThatAreAlwaysFalse sect = sect {+ sectionConditionals = filter p $ sectionConditionals sect+ }+ where+ p = (/= CondBool False) . conditionalCondition+ inferModules :: FilePath -> String- -> (a -> [String])- -> (b -> [String])- -> ([String] -> [String] -> a -> b)- -> ([String] -> a -> b)+ -> (a -> [Module])+ -> (b -> [Module])+ -> ([Module] -> [Module] -> a -> b)+ -> ([Module] -> a -> b) -> Section a -> IO (Section b)-inferModules dir packageName_ getMentionedModules getInferredModules fromData fromConditionals = traverseSectionAndConditionals+inferModules dir packageName_ getMentionedModules getInferredModules fromData fromConditionals = fmap removeConditionalsThatAreAlwaysFalse . traverseSectionAndConditionals (fromConfigSection fromData [pathsModuleFromPackageName packageName_]) (fromConfigSection (\ [] -> fromConditionals) []) []@@ -1268,9 +1329,7 @@ toLibrary dir name = inferModules dir name getMentionedLibraryModules getLibraryModules fromLibrarySectionTopLevel fromLibrarySectionInConditional where- getLibraryModules :: Library -> [String]- getLibraryModules Library{..} = libraryExposedModules ++ libraryOtherModules-+ fromLibrarySectionTopLevel :: [Module] -> [Module] -> LibrarySection -> Library fromLibrarySectionTopLevel pathsModule inferableModules LibrarySection{..} = Library librarySectionExposed librarySectionVisibility exposedModules otherModules generatedModules reexportedModules signatures where@@ -1279,7 +1338,7 @@ reexportedModules = fromMaybeList librarySectionReexportedModules signatures = fromMaybeList librarySectionSignatures -determineModules :: [String] -> [String] -> Maybe (List String) -> Maybe (List String) -> Maybe (List String) -> Maybe (List String) -> ([String], [String], [String])+determineModules :: [Module] -> [Module] -> Maybe (List Module) -> Maybe (List Module) -> Maybe (List Module) -> Maybe (List Module) -> ([Module], [Module], [Module]) determineModules pathsModule inferable mExposed mGeneratedExposed mOther mGeneratedOther = (exposed, others, generated) where@@ -1287,7 +1346,7 @@ exposed = maybe inferable fromList mExposed ++ fromMaybeList mGeneratedExposed others = maybe ((inferable \\ exposed) ++ pathsModule) fromList mOther ++ fromMaybeList mGeneratedOther -fromLibrarySectionInConditional :: [String] -> LibrarySection -> Library+fromLibrarySectionInConditional :: [Module] -> LibrarySection -> Library fromLibrarySectionInConditional inferableModules lib@(LibrarySection _ _ exposedModules _ otherModules _ _ _) = case (exposedModules, otherModules) of (Nothing, Nothing) -> addToOtherModules inferableModules (fromLibrarySectionPlain lib)@@ -1306,16 +1365,16 @@ , librarySignatures = fromMaybeList librarySectionSignatures } -getMentionedExecutableModules :: ExecutableSection -> [String]+getMentionedExecutableModules :: ExecutableSection -> [Module] getMentionedExecutableModules (ExecutableSection main otherModules generatedModules)=- maybe id (:) (main >>= toModule . splitDirectories) $ fromMaybeList (otherModules <> generatedModules)+ maybe id (:) (toModule . Path.fromFilePath <$> main) $ fromMaybeList (otherModules <> generatedModules) toExecutable :: FilePath -> String -> Section ExecutableSection -> IO (Section Executable) toExecutable dir packageName_ =- inferModules dir packageName_ getMentionedExecutableModules executableOtherModules fromExecutableSection (fromExecutableSection [])+ inferModules dir packageName_ getMentionedExecutableModules getExecutableModules fromExecutableSection (fromExecutableSection []) . expandMain where- fromExecutableSection :: [String] -> [String] -> ExecutableSection -> Executable+ fromExecutableSection :: [Module] -> [Module] -> ExecutableSection -> Executable fromExecutableSection pathsModule inferableModules ExecutableSection{..} = (Executable executableSectionMain (otherModules ++ generatedModules) generatedModules) where@@ -1350,7 +1409,7 @@ conditionals <- mapM toConditional (fromMaybeList commonOptionsWhen) return Section { sectionData = a- , sectionSourceDirs = fromMaybeList commonOptionsSourceDirs+ , sectionSourceDirs = nub $ fromMaybeList commonOptionsSourceDirs , sectionDefaultExtensions = fromMaybeList commonOptionsDefaultExtensions , sectionOtherExtensions = fromMaybeList commonOptionsOtherExtensions , sectionGhcOptions = fromMaybeList commonOptionsGhcOptions@@ -1390,7 +1449,7 @@ ThenElseConditional (Product (ThenElse then_ else_) c) -> conditional c <$> (go then_) <*> (Just <$> go else_) FlatConditional (Product sect c) -> conditional c <$> (go sect) <*> pure Nothing where- conditional (Condition (Cond c)) = Conditional c+ conditional = Conditional . conditionCondition type SystemBuildTool = (String, VersionConstraint) @@ -1439,25 +1498,8 @@ warnLegacyTool pkg name = tell ["Usage of the unqualified build-tool name " ++ show name ++ " is deprecated! Please use the qualified name \"" ++ pkg ++ ":" ++ name ++ "\" instead!"] warnLegacySystemTool name = tell ["Listing " ++ show name ++ " under build-tools is deperecated! Please list system executables under system-build-tools instead!"] -pathsModuleFromPackageName :: String -> String-pathsModuleFromPackageName name = "Paths_" ++ map f name+pathsModuleFromPackageName :: String -> Module+pathsModuleFromPackageName name = Module ("Paths_" ++ map f name) where f '-' = '_' f x = x--getModules :: FilePath -> FilePath -> IO [String]-getModules dir src_ = sort <$> do- exists <- doesDirectoryExist (dir </> src_)- if exists- then do- src <- canonicalizePath (dir </> src_)- removeSetup src . toModules <$> getModuleFilesRecursive src- else return []- where- toModules :: [[FilePath]] -> [String]- toModules = catMaybes . map toModule-- removeSetup :: FilePath -> [String] -> [String]- removeSetup src- | src == dir = filter (/= "Setup")- | otherwise = id
src/Hpack/Haskell.hs view
@@ -1,5 +1,6 @@ module Hpack.Haskell ( isModule+, isModuleNameComponent , isQualifiedIdentifier , isIdentifier ) where@@ -7,10 +8,10 @@ import Data.Char isModule :: [String] -> Bool-isModule name = (not . null) name && all isModuleName name+isModule name = (not . null) name && all isModuleNameComponent name -isModuleName :: String -> Bool-isModuleName name = case name of+isModuleNameComponent :: String -> Bool+isModuleNameComponent name = case name of x : xs -> isUpper x && all isIdChar xs _ -> False
+ src/Hpack/Module.hs view
@@ -0,0 +1,114 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE CPP #-}+module Hpack.Module (+ Module(..)+, toModule+, getModules+#ifdef TEST+, getModuleFilesRecursive+#endif+) where++import Data.String+import System.FilePath+import qualified System.Directory as Directory+import Control.Monad+import Data.List hiding (nub, sort)++import Data.Aeson.Config.FromValue+import Hpack.Util+import Hpack.Haskell++import Path (Path(..), PathComponent(..))+import qualified Path++newtype Module = Module {unModule :: String}+ deriving (Eq, Ord)++instance Show Module where+ show = show . unModule++instance IsString Module where+ fromString = Module++instance FromValue Module where+ fromValue = fmap Module . fromValue++toModule :: Path -> Module+toModule path = case reverse $ Path.components path of+ [] -> Module ""+ file : dirs -> Module . intercalate "." . reverse $ dropExtension file : dirs++getModules :: FilePath -> FilePath -> IO [Module]+getModules dir literalSrc = sortModules <$> do+ exists <- Directory.doesDirectoryExist (dir </> literalSrc)+ if exists+ then do+ canonicalSrc <- Directory.canonicalizePath (dir </> literalSrc)++ let+ srcIsProjectRoot :: Bool+ srcIsProjectRoot = canonicalSrc == dir++ toModules :: [Path] -> [Module]+ toModules = removeSetup . nub . map toModule++ removeSetup :: [Module] -> [Module]+ removeSetup+ | srcIsProjectRoot = filter (/= "Setup")+ | otherwise = id++ toModules <$> getModuleFilesRecursive canonicalSrc+ else return []++sortModules :: [Module] -> [Module]+sortModules = map Module . sort . map unModule++isSourceFile :: PathComponent -> Bool+isSourceFile (splitExtension . unPathComponent -> (name, ext)) = ext `elem` extensions && isModuleNameComponent name+ where+ extensions :: [String]+ extensions = [+ ".hs"+ , ".lhs"+ , ".chs"+ , ".hsc"+ , ".y"+ , ".ly"+ , ".x"+ ]++isModuleComponent :: PathComponent -> Bool+isModuleComponent = isModuleNameComponent . unPathComponent++getModuleFilesRecursive :: FilePath -> IO [Path]+getModuleFilesRecursive baseDir = go (Path [])+ where+ addBaseDir :: Path -> FilePath+ addBaseDir = (baseDir </>) . Path.toFilePath++ listDirectory :: Path -> IO [PathComponent]+ listDirectory = fmap (map PathComponent) . Directory.listDirectory . addBaseDir++ doesFileExist :: Path -> IO Bool+ doesFileExist = Directory.doesFileExist . addBaseDir++ doesDirectoryExist :: Path -> IO Bool+ doesDirectoryExist = Directory.doesDirectoryExist . addBaseDir++ go :: Path -> IO [Path]+ go dir = do+ entries <- listDirectory dir++ files <- filterWith doesFileExist (filter isSourceFile entries)+ directories <- filterWith doesDirectoryExist (filter isModuleComponent entries)++ subdirsFiles <- concat <$> mapM go directories+ return (files ++ subdirsFiles)+ where+ filterWith :: (Path -> IO Bool) -> [PathComponent] -> IO [Path]+ filterWith p = filterM p . map addDir++ addDir :: PathComponent -> Path+ addDir entry = Path (unPath dir ++ [entry])
src/Hpack/Render.hs view
@@ -65,7 +65,8 @@ packageFields :: [Element] packageFields = addVerbatim packageVerbatim . sortFieldsBy existingFieldOrder $ headerFields ++ [- Field "extra-source-files" (renderPaths packageExtraSourceFiles)+ Field "tested-with" $ CommaSeparatedList packageTestedWith+ , Field "extra-source-files" (renderPaths packageExtraSourceFiles) , Field "extra-doc-files" (renderPaths packageExtraDocFiles) , Field "data-files" (renderPaths packageDataFiles) ] ++ maybe [] (return . Field "data-dir" . Literal) packageDataDir@@ -108,7 +109,6 @@ , case packageLicenseFile of [file] -> ("license-file", Just file) files -> ("license-files", formatList files)- , ("tested-with", packageTestedWith) , ("build-type", Just (show packageBuildType)) ] @@ -286,8 +286,14 @@ Nothing -> if_ Just else_ -> Group if_ (Stanza "else" $ renderSection renderSectionData [] [] else_) where- if_ = Stanza ("if " ++ condition) (renderSection renderSectionData [] [] sect)+ if_ = Stanza ("if " ++ renderCond condition) (renderSection renderSectionData [] [] sect) +renderCond :: Cond -> String+renderCond = \ case+ CondExpression c -> c+ CondBool True -> "true"+ CondBool False -> "false"+ defaultLanguage :: Element defaultLanguage = Field "default-language" "Haskell2010" @@ -296,17 +302,17 @@ where replaceDots = map replaceDot replaceDot xs = case xs of- "." -> "./."+ "." -> "./" _ -> xs -renderExposedModules :: [String] -> Element-renderExposedModules = Field "exposed-modules" . LineSeparatedList+renderExposedModules :: [Module] -> Element+renderExposedModules = Field "exposed-modules" . LineSeparatedList . map unModule -renderOtherModules :: [String] -> Element-renderOtherModules = Field "other-modules" . LineSeparatedList+renderOtherModules :: [Module] -> Element+renderOtherModules = Field "other-modules" . LineSeparatedList . map unModule -renderGeneratedModules :: [String] -> Element-renderGeneratedModules = Field "autogen-modules" . LineSeparatedList+renderGeneratedModules :: [Module] -> Element+renderGeneratedModules = Field "autogen-modules" . LineSeparatedList . map unModule renderReexportedModules :: [String] -> Element renderReexportedModules = Field "reexported-modules" . CommaSeparatedList
src/Hpack/Render/Hints.hs view
@@ -4,6 +4,7 @@ FormattingHints (..) , sniffFormattingHints #ifdef TEST+, sniffRenderSettings , extractFieldOrder , extractSectionsFieldOrder , sanitize@@ -17,10 +18,11 @@ import Data.Char import Data.Maybe-import Data.List+import Data.List hiding (nub) import Control.Applicative import Hpack.Render.Dsl+import Hpack.Util data FormattingHints = FormattingHints { formattingHintsFieldOrder :: [String]@@ -109,6 +111,8 @@ sniffRenderSettings :: [String] -> RenderSettings sniffRenderSettings input = RenderSettings indentation fieldAlignment commaStyle where- indentation = fromMaybe (renderSettingsIndentation defaultRenderSettings) (sniffIndentation input)+ indentation = max def $ fromMaybe def (sniffIndentation input)+ where def = renderSettingsIndentation defaultRenderSettings+ fieldAlignment = renderSettingsFieldAlignment defaultRenderSettings commaStyle = fromMaybe (renderSettingsCommaStyle defaultRenderSettings) (sniffCommaStyle input)
src/Hpack/Syntax/Dependencies.hs view
@@ -50,7 +50,7 @@ data DependencyInfo = DependencyInfo { dependencyInfoMixins :: [String] , dependencyInfoVersion :: DependencyVersion-} deriving (Eq, Show)+} deriving (Eq, Ord, Show) addMixins :: Object -> DependencyVersion -> Parser DependencyInfo addMixins o version = do
src/Hpack/Syntax/DependencyVersion.hs view
@@ -48,7 +48,7 @@ type GitRef = String data VersionConstraint = AnyVersion | VersionRange String- deriving (Eq, Show)+ deriving (Eq, Ord, Show) instance FromValue VersionConstraint where fromValue = versionConstraint@@ -67,7 +67,7 @@ versionRange = DependencyVersion Nothing . VersionRange data DependencyVersion = DependencyVersion (Maybe SourceDependency) VersionConstraint- deriving (Eq, Show)+ deriving (Eq, Ord, Show) withDependencyVersion :: (DependencyVersion -> a)@@ -85,7 +85,7 @@ dependencyVersion = withDependencyVersion id (const return) data SourceDependency = GitRef GitUrl GitRef (Maybe FilePath) | Local FilePath- deriving (Eq, Show)+ deriving (Eq, Ord, Show) objectDependency :: Object -> Parser DependencyVersion objectDependency o = let
src/Hpack/Util.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE LambdaCase #-} module Hpack.Util ( GhcOption , GhcProfOption@@ -7,22 +8,25 @@ , CxxOption , LdOption , parseMain-, toModule-, getModuleFilesRecursive+ , tryReadFile , expandGlobs , sort , lexicographically , Hash , sha256++, nub+, nubOn ) where import Control.Exception import Control.Monad import Data.Char import Data.Bifunctor-import Data.List hiding (sort)+import Data.List hiding (nub, sort) import Data.Ord+import qualified Data.Set as Set import System.IO.Error import System.Directory import System.FilePath@@ -62,38 +66,6 @@ (ys, "") -> [ys] (ys, _:zs) -> ys : go zs -toModule :: [FilePath] -> Maybe String-toModule path = case reverse path of- [] -> Nothing- x : xs -> do- m <- msum $ map (`stripSuffix` x) [- ".hs"- , ".lhs"- , ".chs"- , ".hsc"- , ".y"- , ".ly"- , ".x"- ]- let name = reverse (m : xs)- guard (isModule name) >> return (intercalate "." name)- where- stripSuffix :: String -> String -> Maybe String- stripSuffix suffix x = reverse <$> stripPrefix (reverse suffix) (reverse x)--getModuleFilesRecursive :: FilePath -> IO [[String]]-getModuleFilesRecursive baseDir = go []- where- go :: [FilePath] -> IO [[FilePath]]- go dir = do- c <- map ((dir ++) . return) . filter (`notElem` [".", ".."]) <$> getDirectoryContents (pathTo dir)- subdirsFiles <- filterM (doesDirectoryExist . pathTo) c >>= mapM go . filter isModule- files <- filterM (doesFileExist . pathTo) c- return (files ++ concat subdirsFiles)- where- pathTo :: [FilePath] -> FilePath- pathTo p = baseDir </> joinPath p- tryReadFile :: FilePath -> IO (Maybe String) tryReadFile file = do r <- tryJust (guard . isDoesNotExistError) (Utf8.readFile file)@@ -158,3 +130,17 @@ sha256 :: String -> Hash sha256 c = show (hash (Utf8.encodeUtf8 c) :: Digest SHA256)++nub :: Ord a => [a] -> [a]+nub = nubOn id++nubOn :: Ord b => (a -> b) -> [a] -> [a]+nubOn f = go mempty+ where+ go seen = \ case+ [] -> []+ a : as+ | b `Set.member` seen -> go seen as+ | otherwise -> a : go (Set.insert b seen) as+ where+ b = f a
+ src/Path.hs view
@@ -0,0 +1,25 @@+module Path where++import System.FilePath+import Data.String++fromFilePath :: FilePath -> Path+fromFilePath = Path . map PathComponent . splitDirectories++toFilePath :: Path -> FilePath+toFilePath = joinPath . components++components :: Path -> [String]+components = map unPathComponent . unPath++newtype Path = Path {unPath :: [PathComponent]}+ deriving Eq++instance Show Path where+ show = show . toFilePath++instance IsString Path where+ fromString = fromFilePath++newtype PathComponent = PathComponent {unPathComponent :: String}+ deriving Eq
test/EndToEndSpec.hs view
@@ -40,6 +40,28 @@ Paths_foo |] + describe "tested-with" $ do+ it "accepts a string" $ do+ [i|+ tested-with: GHC == 7.0.4+ |] `shouldRenderTo` package [i|+ tested-with:+ GHC == 7.0.4+ |]++ it "accepts a list" $ do+ [i|+ tested-with:+ - GHC == 7.0.4+ - GHC == 7.2.2+ - GHC == 7.4.2+ |] `shouldRenderTo` package [i|+ tested-with:+ GHC == 7.0.4+ , GHC == 7.2.2+ , GHC == 7.4.2+ |]+ it "warns on duplicate fields" $ do [i| name: foo@@ -48,6 +70,48 @@ "package.yaml: Duplicate field $.name" ] + describe "handling of Paths_ module" $ do+ it "adds Paths_ to other-modules" $ do+ [i|+ library: {}+ |] `shouldRenderTo` library [i|+ other-modules:+ Paths_foo+ |]++ context "when Paths_ is mentioned in a conditional that is always false" $ do+ it "does not add Paths_" $ do+ [i|+ library:+ when:+ - condition: false+ other-modules: Paths_foo+ |] `shouldRenderTo` library [i|+ |]++ context "with RebindableSyntax and OverloadedStrings or OverloadedStrings" $ do+ it "infers cabal-version 2.2" $ do+ [i|+ default-extensions: [RebindableSyntax, OverloadedStrings]+ library: {}+ |] `shouldRenderTo` (library [i|+ default-extensions: RebindableSyntax OverloadedStrings+ other-modules:+ Paths_foo+ |]) {packageCabalVersion = "2.2"}++ context "when Paths_ is mentioned in a conditional that is always false" $ do+ it "does not infer cabal-version 2.2" $ do+ [i|+ default-extensions: [RebindableSyntax, OverloadedStrings]+ library:+ when:+ - condition: false+ other-modules: Paths_foo+ |] `shouldRenderTo` (library [i|+ default-extensions: RebindableSyntax OverloadedStrings+ |])+ describe "spec-version" $ do it "accepts spec-version" $ do [i|@@ -922,7 +986,98 @@ Foo |] - context "when inferring modules" $ do+ context "with mixins" $ do+ it "infers cabal-version 2.0" $ do+ [i|+ library:+ dependencies:+ foo:+ mixin:+ - (Blah as Etc)+ |] `shouldRenderTo` (library [i|+ other-modules:+ Paths_foo+ build-depends:+ foo+ mixins:+ foo (Blah as Etc)+ |]) {packageCabalVersion = "2.0"}++ describe "internal-libraries" $ do+ it "accepts internal-libraries" $ do+ touch "src/Foo.hs"+ [i|+ internal-libraries:+ bar:+ source-dirs: src+ |] `shouldRenderTo` internalLibrary "bar" [i|+ exposed-modules:+ Foo+ other-modules:+ Paths_foo+ hs-source-dirs:+ src+ |]++ it "warns on unknown fields" $ do+ [i|+ name: foo+ internal-libraries:+ bar:+ baz: 42+ |] `shouldWarn` pure "package.yaml: Ignoring unrecognized field $.internal-libraries.bar.baz"++ it "warns on missing source-dirs" $ do+ [i|+ name: foo+ internal-libraries:+ bar:+ source-dirs: src+ |] `shouldWarn` pure "Specified source-dir \"src\" does not exist"++ it "accepts visibility" $ do+ [i|+ internal-libraries:+ bar:+ visibility: public+ |] `shouldRenderTo` (internalLibrary "bar" [i|+ visibility: public+ other-modules:+ Paths_foo+ |]) {packageCabalVersion = "3.0"}++ context "when inferring modules" $ do+ context "with a library" $ do+ it "ignores duplicate source directories" $ do+ touch "src/Foo.hs"+ [i|+ source-dirs: src+ library:+ source-dirs: src+ |] `shouldRenderTo` library [i|+ hs-source-dirs:+ src+ exposed-modules:+ Foo+ other-modules:+ Paths_foo+ |]++ it "ignores duplicate modules" $ do+ touch "src/Foo.hs"+ touch "src/Foo.x"+ [i|+ library:+ source-dirs: src+ |] `shouldRenderTo` library [i|+ hs-source-dirs:+ src+ exposed-modules:+ Foo+ other-modules:+ Paths_foo+ |]+ context "with exposed-modules" $ do it "infers other-modules" $ do touch "src/Foo.hs"@@ -1123,86 +1278,7 @@ Exposed |]) {packageCabalVersion = "2.0"} - context "mixins" $ do- it "sets cabal-version to 2.0 if mixins are used" $ do- [i|- library:- dependencies:- foo:- mixin:- - (Blah as Etc)- |] `shouldRenderTo` (library [i|- other-modules:- Paths_foo- build-depends:- foo- mixins:- foo (Blah as Etc)- |]) {packageCabalVersion = "2.0"}-- describe "internal-libraries" $ do- it "accepts internal-libraries" $ do- touch "src/Foo.hs"- [i|- internal-libraries:- bar:- source-dirs: src- |] `shouldRenderTo` internalLibrary "bar" [i|- exposed-modules:- Foo- other-modules:- Paths_foo- hs-source-dirs:- src- |]-- it "warns on unknown fields" $ do- [i|- name: foo- internal-libraries:- bar:- baz: 42- |] `shouldWarn` pure "package.yaml: Ignoring unrecognized field $.internal-libraries.bar.baz"-- it "warns on missing source-dirs" $ do- [i|- name: foo- internal-libraries:- bar:- source-dirs: src- |] `shouldWarn` pure "Specified source-dir \"src\" does not exist"-- it "accepts visibility" $ do- [i|- internal-libraries:- bar:- visibility: public- |] `shouldRenderTo` (internalLibrary "bar" [i|- visibility: public- other-modules:- Paths_foo- |]) {packageCabalVersion = "3.0"}-- describe "executables" $ do- it "accepts arbitrary entry points as main" $ do- touch "src/Foo.hs"- touch "src/Bar.hs"- [i|- executables:- foo:- source-dirs: src- main: Foo- |] `shouldRenderTo` executable "foo" [i|- main-is: Foo.hs- ghc-options: -main-is Foo- hs-source-dirs:- src- other-modules:- Bar- Paths_foo- |]-- context "when inferring modules" $ do+ context "with an executable" $ do it "infers other-modules" $ do touch "src/Main.hs" touch "src/Foo.hs"@@ -1256,7 +1332,7 @@ Foo |]) {packageCabalVersion = "2.0"} - context "with conditional" $ do+ context "with a conditional" $ do it "doesn't infer any modules mentioned in that conditional" $ do touch "src/Foo.hs" touch "src/Bar.hs"@@ -1301,7 +1377,26 @@ windows |] - context "with conditional" $ do+ describe "executables" $ do+ it "accepts arbitrary entry points as main" $ do+ touch "src/Foo.hs"+ touch "src/Bar.hs"+ [i|+ executables:+ foo:+ source-dirs: src+ main: Foo+ |] `shouldRenderTo` executable "foo" [i|+ main-is: Foo.hs+ ghc-options: -main-is Foo+ hs-source-dirs:+ src+ other-modules:+ Bar+ Paths_foo+ |]++ context "with a conditional" $ do it "does not apply global options" $ do -- related bug: https://github.com/sol/hpack/issues/214 [i|@@ -1380,6 +1475,40 @@ unix |] + context "with empty then-branch" $ do+ it "provides a hint" $ do+ [i|+ when:+ condition: os(windows)+ then: {}+ else:+ dependencies: unix+ executable: {}+ |] `shouldFailWith` unlines [+ "package.yaml: Error while parsing $.when - an empty \"then\" section is not allowed, try the following instead:"+ , ""+ , "when:"+ , " condition: '!(os(windows))'"+ , " dependencies: unix"+ ]++ context "with empty else-branch" $ do+ it "provides a hint" $ do+ [i|+ when:+ condition: os(windows)+ then:+ dependencies: Win32+ else: {}+ executable: {}+ |] `shouldFailWith` unlines [+ "package.yaml: Error while parsing $.when - an empty \"else\" section is not allowed, try the following instead:"+ , ""+ , "when:"+ , " condition: os(windows)"+ , " dependencies: Win32"+ ]+ it "rejects invalid conditionals" $ do [i| when:@@ -1407,7 +1536,8 @@ else: when: condition: os(windows)- then: {}+ then:+ dependencies: foo else: baz: null |] `shouldWarn` [
test/Helper.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ConstraintKinds #-}+{-# OPTIONS_GHC -fno-warn-orphans #-} module Helper ( module Test.Hspec , module Test.Mockery.Directory@@ -13,6 +14,7 @@ import Test.Hspec import Test.Mockery.Directory+import Data.String import Control.Monad import Control.Applicative import System.Directory (getCurrentDirectory, setCurrentDirectory, canonicalizePath)@@ -22,6 +24,11 @@ import Data.Yaml.TH (yamlQQ) import Language.Haskell.TH.Quote (QuasiQuoter)++import Hpack.Config++instance IsString Cond where+ fromString = CondExpression withCurrentDirectory :: FilePath -> IO a -> IO a withCurrentDirectory dir action = do
test/Hpack/ConfigSpec.hs view
@@ -148,25 +148,6 @@ } renameDependencies "bar" "baz" (sectionWithConditional ["foo", "bar"]) `shouldBe` sectionWithConditional ["foo", "baz"] - describe "getModules" $ around withTempDirectory $ do- it "returns Haskell modules in specified source directory" $ \dir -> do- touch (dir </> "src/Foo.hs")- touch (dir </> "src/Bar/Baz.hs")- touch (dir </> "src/Setup.hs")- getModules dir "src" >>= (`shouldMatchList` ["Foo", "Bar.Baz", "Setup"])-- context "when source directory is '.'" $ do- it "ignores Setup" $ \dir -> do- touch (dir </> "Foo.hs")- touch (dir </> "Setup.hs")- getModules dir "." `shouldReturn` ["Foo"]-- context "when source directory is './.'" $ do- it "ignores Setup" $ \dir -> do- touch (dir </> "Foo.hs")- touch (dir </> "Setup.hs")- getModules dir "./." `shouldReturn` ["Foo"]- describe "toBuildTool" $ do let toBuildTool_ name = runWriter $ toBuildTool "my-package" ["foo"] (name, anyVersion) context "with an UnqualifiedBuildTool" $ do@@ -662,17 +643,17 @@ it "accepts Strings" $ do [yaml| os(windows)- |] `shouldDecodeTo_` Cond "os(windows)"+ |] `shouldDecodeTo_` CondExpression "os(windows)" it "accepts True" $ do [yaml| yes- |] `shouldDecodeTo_` Cond "true"+ |] `shouldDecodeTo_` CondBool True it "accepts False" $ do [yaml| no- |] `shouldDecodeTo_` Cond "false"+ |] `shouldDecodeTo_` CondBool False it "rejects other values" $ do [yaml|
+ test/Hpack/ModuleSpec.hs view
@@ -0,0 +1,58 @@+{-# LANGUAGE OverloadedStrings #-}+module Hpack.ModuleSpec (spec) where++import Helper++import Hpack.Module++spec :: Spec+spec = do+ describe "getModules" $ around withTempDirectory $ do+ it "returns Haskell modules in specified source directory" $ \dir -> do+ touch (dir </> "src/Foo.hs")+ touch (dir </> "src/Bar/Baz.hs")+ touch (dir </> "src/Setup.hs")+ getModules dir "src" >>= (`shouldMatchList` ["Foo", "Bar.Baz", "Setup"])++ context "when source directory is '.'" $ do+ it "ignores Setup" $ \dir -> do+ touch (dir </> "Foo.hs")+ touch (dir </> "Setup.hs")+ getModules dir "." `shouldReturn` ["Foo"]++ context "when source directory is './.'" $ do+ it "ignores Setup" $ \dir -> do+ touch (dir </> "Foo.hs")+ touch (dir </> "Setup.hs")+ getModules dir "./." `shouldReturn` ["Foo"]++ describe "toModule" $ do+ it "maps a Path to a Module" $ do+ toModule "Foo/Bar/Baz.hs" `shouldBe` "Foo.Bar.Baz"++ describe "getModuleFilesRecursive" $ do+ it "gets all Haskell source files from given directory" $ do+ inTempDirectory $ do+ touch "foo/Bar.hs"+ touch "foo/Baz.chs"+ actual <- getModuleFilesRecursive "foo"+ actual `shouldMatchList` [+ "Bar.hs"+ , "Baz.chs"+ ]++ it "ignores other files" $ do+ inTempDirectory $ do+ touch "foo/Bar.js"+ getModuleFilesRecursive "foo" `shouldReturn` []++ it "descends into subdirectories" $ do+ inTempDirectory $ do+ touch "foo/Bar/Baz.hs"+ getModuleFilesRecursive "foo" `shouldReturn` ["Bar/Baz.hs"]++ context "when a subdirectory is not a valid module name" $ do+ it "does not descend" $ do+ inTempDirectory $ do+ touch "foo/bar/Baz.hs"+ getModuleFilesRecursive "foo" `shouldReturn` empty
test/Hpack/Render/HintsSpec.hs view
@@ -7,6 +7,17 @@ spec :: Spec spec = do+ describe "sniffRenderSettings" $ do+ context "when sniffed indentation is < default" $ do+ it "uses default instead" $ do+ let input = [+ "library"+ , "exposed-modules:"+ , " Foo"+ ]+ sniffIndentation input `shouldBe` Just 0+ renderSettingsIndentation (sniffRenderSettings input) `shouldBe` 2+ describe "extractFieldOrder" $ do it "extracts field order hints" $ do let input = [@@ -109,7 +120,7 @@ splitField "foo bar" `shouldBe` Nothing describe "sniffIndentation" $ do- it "sniff alignment from executable section" $ do+ it "sniffs indentation from executable section" $ do let input = [ "name: foo" , "version: 0.0.0"@@ -119,7 +130,7 @@ ] sniffIndentation input `shouldBe` Just 4 - it "sniff alignment from library section" $ do+ it "sniffs indentation from library section" $ do let input = [ "name: foo" , "version: 0.0.0"
test/Hpack/RenderSpec.hs view
@@ -342,7 +342,7 @@ (render defaultRenderSettings 0 $ renderDirectories "name" ["."]) `shouldBe` [ "name:"- , " ./."+ , " ./" ] describe "renderDependencies" $ do
test/Hpack/UtilSpec.hs view
@@ -30,41 +30,6 @@ it "accepts qualified identifier" $ do parseMain "Foo.bar" `shouldBe` ("Foo.hs", ["-main-is Foo.bar"]) - describe "toModule" $ do- it "maps .hs paths to module names" $ do- toModule ["Foo", "Bar", "Baz.hs"] `shouldBe` Just "Foo.Bar.Baz"-- it "maps .lhs paths to module names" $ do- toModule ["Foo", "Bar", "Baz.lhs"] `shouldBe` Just "Foo.Bar.Baz"-- it "maps .hsc paths to module names" $ do- toModule ["Foo", "Bar", "Baz.hsc"] `shouldBe` Just "Foo.Bar.Baz"-- it "rejects invalid module names" $ do- toModule ["resources", "hello.hs"] `shouldBe` Nothing-- describe "getModuleFilesRecursive" $ do- it "gets all files from given directory" $ do- inTempDirectory $ do- touch "foo/bar"- touch "foo/baz"- actual <- getModuleFilesRecursive "foo"- actual `shouldMatchList` [- ["bar"]- , ["baz"]- ]-- it "descends into subdirectories" $ do- inTempDirectory $ do- touch "foo/Bar/baz"- getModuleFilesRecursive "foo" `shouldReturn` [["Bar", "baz"]]-- context "when a subdirectory is not a valid module name" $ do- it "does not descend" $ do- inTempDirectory $ do- touch "foo/bar/baz"- getModuleFilesRecursive "foo" `shouldReturn` empty- describe "tryReadFile" $ do it "reads file" $ do inTempDirectory $ do