hpack 0.22.0 → 0.23.0
raw patch · 14 files changed
+366/−202 lines, 14 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Hpack: RunOptions :: Maybe FilePath -> FilePath -> (FilePath -> IO (Either String Value)) -> RunOptions
+ Hpack: [runOptionsConfigDir] :: RunOptions -> Maybe FilePath
+ Hpack: [runOptionsConfigFile] :: RunOptions -> FilePath
+ Hpack: [runOptionsDecode] :: RunOptions -> FilePath -> IO (Either String Value)
+ Hpack: data RunOptions
+ Hpack: defaultRunOptions :: RunOptions
+ Hpack: mainWith :: FilePath -> (FilePath -> IO (Either String Value)) -> IO ()
+ Hpack.Config: [executableGeneratedModules] :: Executable -> [String]
+ Hpack.Config: [libraryGeneratedModules] :: Library -> [String]
+ Hpack.Config: readPackageConfigWith :: (FilePath -> IO (Either String Value)) -> FilePath -> FilePath -> IO (Either String (Package, [String]))
+ Hpack.Run: RunOptions :: Maybe FilePath -> FilePath -> (FilePath -> IO (Either String Value)) -> RunOptions
+ Hpack.Run: [runOptionsConfigDir] :: RunOptions -> Maybe FilePath
+ Hpack.Run: [runOptionsConfigFile] :: RunOptions -> FilePath
+ Hpack.Run: [runOptionsDecode] :: RunOptions -> FilePath -> IO (Either String Value)
+ Hpack.Run: data RunOptions
+ Hpack.Run: defaultRunOptions :: RunOptions
- Hpack: hpack :: Maybe FilePath -> Verbose -> Force -> IO ()
+ Hpack: hpack :: RunOptions -> Verbose -> Force -> IO ()
- Hpack: hpackResult :: Maybe FilePath -> Force -> IO Result
+ Hpack: hpackResult :: RunOptions -> Force -> IO Result
- Hpack.Config: Executable :: Maybe FilePath -> [String] -> Executable
+ Hpack.Config: Executable :: Maybe FilePath -> [String] -> [String] -> Executable
- Hpack.Config: Library :: Maybe Bool -> [String] -> [String] -> [String] -> [String] -> Library
+ Hpack.Config: Library :: Maybe Bool -> [String] -> [String] -> [String] -> [String] -> [String] -> Library
- Hpack.Run: run :: Maybe FilePath -> FilePath -> IO ([String], FilePath, String)
+ Hpack.Run: run :: RunOptions -> IO ([String], FilePath, String)
Files
- CHANGELOG.md +8/−1
- hpack.cabal +3/−3
- src/Hpack.hs +28/−35
- src/Hpack/CabalFile.hs +4/−2
- src/Hpack/Config.hs +40/−27
- src/Hpack/Options.hs +30/−9
- src/Hpack/Run.hs +42/−10
- src/Hpack/Util.hs +4/−0
- test/EndToEndSpec.hs +131/−39
- test/Hpack/CabalFileSpec.hs +4/−0
- test/Hpack/ConfigSpec.hs +8/−16
- test/Hpack/OptionsSpec.hs +50/−10
- test/Hpack/RunSpec.hs +11/−9
- test/HpackSpec.hs +3/−41
CHANGELOG.md view
@@ -1,4 +1,11 @@-## next+## Changes in 0.23.0+ - Add support for custom decoders to allow for alternate syntax (e.g. Dhall)+ - `generated-exposed-modules` and `generated-other-modules`, for populating+ the `autogen-modules` field (#207).+ - Corrected `cabal-version` setting for `reexported-modules` inside+ a conditional.++## Changes in 0.22.0 - Add support for `defaults` - Add `--numeric-version` - Add support for `signatures`
hpack.cabal view
@@ -1,11 +1,11 @@--- This file has been generated from package.yaml by hpack version 0.21.2.+-- This file has been generated from package.yaml by hpack version 0.22.0. -- -- see: https://github.com/sol/hpack ----- hash: ed684f1c6e2ea1bdc1674463da6eeef99a1dd9a3fac6bf2ce309d3d675879539+-- hash: a810403afb86b045741c0bad9d0d0d278cd4582751e39f0912edd62038c29692 name: hpack-version: 0.22.0+version: 0.23.0 synopsis: An alternative format for Haskell packages description: See README at <https://github.com/sol/hpack#readme> category: Development
src/Hpack.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE RecordWildCards #-} module Hpack ( hpack , hpackResult@@ -8,10 +9,12 @@ , Force(..) , version , main+, mainWith+, RunOptions(..)+, defaultRunOptions #ifdef TEST , header , hpackWithVersionResult-, splitDirectory #endif ) where @@ -21,8 +24,7 @@ import System.Environment import System.Exit import System.IO (stderr)-import System.FilePath-import System.Directory+import Data.Aeson (Value) import Paths_hpack (version) import Hpack.Options@@ -31,6 +33,7 @@ import Hpack.Util import Hpack.Utf8 as Utf8 import Hpack.CabalFile+import Hpack.Yaml programVersion :: Version -> String programVersion v = "hpack version " ++ Version.showVersion v@@ -46,15 +49,18 @@ ] main :: IO ()-main = do- args <- getArgs- case parseOptions args of+main = mainWith packageConfig decodeYaml++mainWith :: FilePath -> (FilePath -> IO (Either String Value)) -> IO ()+mainWith configFile decode = do+ result <- getArgs >>= parseOptions configFile+ case result of PrintVersion -> putStrLn (programVersion version) PrintNumericVersion -> putStrLn (Version.showVersion version) Help -> printHelp Run options -> case options of- Options _verbose _force True dir -> hpackStdOut dir- Options verbose force False dir -> hpack dir verbose force+ Options _verbose _force True dir file -> hpackStdOut (RunOptions dir file decode)+ Options verbose force False dir file -> hpack (RunOptions dir file decode) verbose force ParseError -> do printHelp exitFailure@@ -67,10 +73,10 @@ , " hpack --help" ] -hpack :: Maybe FilePath -> Verbose -> Force -> IO ()+hpack :: RunOptions -> Verbose -> Force -> IO () hpack = hpackWithVersion version -hpackResult :: Maybe FilePath -> Force -> IO Result+hpackResult :: RunOptions -> Force -> IO Result hpackResult = hpackWithVersionResult version data Result = Result {@@ -86,9 +92,9 @@ | OutputUnchanged deriving (Eq, Show) -hpackWithVersion :: Version -> Maybe FilePath -> Verbose -> Force -> IO ()-hpackWithVersion v p verbose force = do- r <- hpackWithVersionResult v p force+hpackWithVersion :: Version -> RunOptions -> Verbose -> Force -> IO ()+hpackWithVersion v options verbose force = do+ r <- hpackWithVersionResult v options force printWarnings (resultWarnings r) when (verbose == Verbose) $ putStrLn $ case resultStatus r of@@ -101,17 +107,6 @@ printWarnings warnings = do forM_ warnings $ \warning -> Utf8.hPutStrLn stderr ("WARNING: " ++ warning) -splitDirectory :: Maybe FilePath -> IO (Maybe FilePath, FilePath)-splitDirectory Nothing = return (Nothing, packageConfig)-splitDirectory (Just p) = do- isDirectory <- doesDirectoryExist p- return $ if isDirectory- then (Just p, packageConfig)- else let- file = takeFileName p- dir = takeDirectory p- in (guard (p /= file) >> Just dir, if null file then packageConfig else file)- mkStatus :: [String] -> Version -> CabalFile -> Status mkStatus new v (CabalFile mOldVersion mHash old) = case (mOldVersion, mHash) of (Nothing, _) -> ExistingCabalFileWasModifiedManually@@ -123,10 +118,9 @@ | old == new -> OutputUnchanged | otherwise -> Generated -hpackWithVersionResult :: Version -> Maybe FilePath -> Force -> IO Result-hpackWithVersionResult v p force = do- (dir, file) <- splitDirectory p- (warnings, cabalFile, new) <- run dir file+hpackWithVersionResult :: Version -> RunOptions -> Force -> IO Result+hpackWithVersionResult v options@RunOptions{..} force = do+ (warnings, cabalFile, new) <- run options oldCabalFile <- readCabalFile cabalFile let status = case force of@@ -135,17 +129,16 @@ case status of Generated -> do let hash = sha256 new- Utf8.writeFile cabalFile (header file v hash ++ new)+ Utf8.writeFile cabalFile (header runOptionsConfigFile v hash ++ new) _ -> return ()- return Result- { resultWarnings = warnings+ return Result {+ resultWarnings = warnings , resultCabalFile = cabalFile , resultStatus = status } -hpackStdOut :: Maybe FilePath -> IO ()-hpackStdOut p = do- (dir, file) <- splitDirectory p- (warnings, _cabalFile, new) <- run dir file+hpackStdOut :: RunOptions -> IO ()+hpackStdOut options = do+ (warnings, _cabalFile, new) <- run options Utf8.putStr new printWarnings warnings
src/Hpack/CabalFile.hs view
@@ -34,9 +34,11 @@ extractHash = extract "-- hash: " Just extractVersion :: [String] -> Maybe Version-extractVersion = extract prefix (parseVersion . safeInit)+extractVersion = extract prefix (stripFileName >=> parseVersion . safeInit) where- prefix = "-- This file has been generated from package.yaml by hpack version "+ prefix = "-- This file has been generated from "+ stripFileName :: String -> Maybe String+ stripFileName = listToMaybe . mapMaybe (stripPrefix " by hpack version ") . tails extract :: String -> (String -> Maybe a) -> [String] -> Maybe a extract prefix parse = listToMaybe . mapMaybe (stripPrefix prefix >=> parse)
src/Hpack/Config.hs view
@@ -14,6 +14,7 @@ module Hpack.Config ( packageConfig , readPackageConfig+, readPackageConfigWith , renamePackage , packageDependencies , package@@ -37,7 +38,6 @@ , Empty(..) , getModules , pathsModuleFromPackageName-, determineModules , BuildType(..) , Cond(..) @@ -155,17 +155,21 @@ data LibrarySection = LibrarySection { librarySectionExposed :: Maybe Bool , librarySectionExposedModules :: Maybe (List String)+, librarySectionGeneratedExposedModules :: Maybe (List String) , librarySectionOtherModules :: Maybe (List String)+, librarySectionGeneratedOtherModules :: Maybe (List String) , librarySectionReexportedModules :: Maybe (List String) , librarySectionSignatures :: Maybe (List String) } deriving (Eq, Show, Generic) instance Monoid LibrarySection where- mempty = LibrarySection Nothing Nothing Nothing Nothing Nothing+ mempty = LibrarySection Nothing Nothing Nothing Nothing Nothing Nothing Nothing mappend a b = LibrarySection { librarySectionExposed = librarySectionExposed b <|> librarySectionExposed a , librarySectionExposedModules = librarySectionExposedModules a <> librarySectionExposedModules b+ , librarySectionGeneratedExposedModules = librarySectionGeneratedExposedModules a <> librarySectionGeneratedExposedModules b , librarySectionOtherModules = librarySectionOtherModules a <> librarySectionOtherModules b+ , librarySectionGeneratedOtherModules = librarySectionGeneratedOtherModules a <> librarySectionGeneratedOtherModules b , librarySectionReexportedModules = librarySectionReexportedModules a <> librarySectionReexportedModules b , librarySectionSignatures = librarySectionSignatures a <> librarySectionSignatures b }@@ -178,13 +182,15 @@ data ExecutableSection = ExecutableSection { executableSectionMain :: Maybe FilePath , executableSectionOtherModules :: Maybe (List String)+, executableSectionGeneratedOtherModules :: Maybe (List String) } deriving (Eq, Show, Generic) instance Monoid ExecutableSection where- mempty = ExecutableSection Nothing Nothing+ mempty = ExecutableSection Nothing Nothing Nothing mappend a b = ExecutableSection { executableSectionMain = executableSectionMain b <|> executableSectionMain a , executableSectionOtherModules = executableSectionOtherModules a <> executableSectionOtherModules b+ , executableSectionGeneratedOtherModules = executableSectionGeneratedOtherModules a <> executableSectionGeneratedOtherModules b } instance HasFieldNames ExecutableSection@@ -558,8 +564,12 @@ decodeYaml = lift . ExceptT . Yaml.decodeYaml readPackageConfig :: FilePath -> FilePath -> IO (Either String (Package, [String]))-readPackageConfig userDataDir file = runExceptT $ runWriterT $ do- config <- decodeYaml file+readPackageConfig = readPackageConfigWith Yaml.decodeYaml++readPackageConfigWith :: (FilePath -> IO (Either String Value)) -> FilePath -> FilePath -> IO (Either String (Package, [String]))+readPackageConfigWith readValue userDataDir file = runExceptT $ runWriterT $ do+ value <- lift . ExceptT $ readValue file+ config <- lift . ExceptT . return $ first ((file ++ ": ") ++) (parseEither parseJSON value) dir <- liftIO $ takeDirectory <$> canonicalizePath file toPackage userDataDir dir config @@ -600,6 +610,7 @@ libraryExposed :: Maybe Bool , libraryExposedModules :: [String] , libraryOtherModules :: [String]+, libraryGeneratedModules :: [String] , libraryReexportedModules :: [String] , librarySignatures :: [String] } deriving (Eq, Show)@@ -607,6 +618,7 @@ data Executable = Executable { executableMain :: Maybe FilePath , executableOtherModules :: [String]+, executableGeneratedModules :: [String] } deriving (Eq, Show) data Section a = Section {@@ -987,8 +999,8 @@ traverseConditionals = traverse . traverse . traverseSectionAndConditionals fConditionals fConditionals getMentionedLibraryModules :: LibrarySection -> [String]-getMentionedLibraryModules LibrarySection{..} =- fromMaybeList librarySectionExposedModules ++ fromMaybeList librarySectionOtherModules+getMentionedLibraryModules (LibrarySection _ exposedModules generatedExposedModules otherModules generatedOtherModules _ _)+ = fromMaybeList (exposedModules <> generatedExposedModules <> otherModules <> generatedOtherModules) listModules :: FilePath -> Section a -> IO [String] listModules dir Section{..} = concat <$> mapM (getModules dir) sectionSourceDirs@@ -1025,32 +1037,35 @@ getLibraryModules Library{..} = libraryExposedModules ++ libraryOtherModules fromLibrarySectionTopLevel pathsModule inferableModules LibrarySection{..} =- Library librarySectionExposed exposedModules otherModules reexportedModules signatures+ Library librarySectionExposed exposedModules otherModules generatedModules reexportedModules signatures where- (exposedModules, otherModules) =- determineModules pathsModule inferableModules librarySectionExposedModules librarySectionOtherModules+ (exposedModules, otherModules, generatedModules) =+ determineModules pathsModule inferableModules librarySectionExposedModules librarySectionGeneratedExposedModules librarySectionOtherModules librarySectionGeneratedOtherModules reexportedModules = fromMaybeList librarySectionReexportedModules signatures = fromMaybeList librarySectionSignatures -determineModules :: [String] -> [String] -> Maybe (List String) -> Maybe (List String) -> ([String], [String])-determineModules pathsModule inferableModules mExposedModules mOtherModules = case (mExposedModules, mOtherModules) of- (Nothing, Nothing) -> (inferableModules, pathsModule)- _ -> (exposedModules, otherModules)- where- exposedModules = maybe (inferableModules \\ otherModules) fromList mExposedModules- otherModules = maybe ((inferableModules ++ pathsModule) \\ exposedModules) fromList mOtherModules+determineModules :: [String] -> [String] -> Maybe (List String) -> Maybe (List String) -> Maybe (List String) -> Maybe (List String) -> ([String], [String], [String])+determineModules pathsModule inferable mExposed mGeneratedExposed mOther mGeneratedOther =+ (exposed, others, generated)+ where+ generated = fromMaybeList (mGeneratedExposed <> mGeneratedOther)+ exposed = maybe inferable fromList mExposed ++ fromMaybeList mGeneratedExposed+ others = maybe ((inferable \\ exposed) ++ pathsModule) fromList mOther ++ fromMaybeList mGeneratedOther fromLibrarySectionInConditional :: [String] -> LibrarySection -> Library-fromLibrarySectionInConditional inferableModules lib@(LibrarySection _ exposedModules otherModules _ _) = do+fromLibrarySectionInConditional inferableModules lib@(LibrarySection _ exposedModules _ otherModules _ _ _) = case (exposedModules, otherModules) of- (Nothing, Nothing) -> (fromLibrarySectionPlain lib) {libraryOtherModules = inferableModules}+ (Nothing, Nothing) -> addToOtherModules inferableModules (fromLibrarySectionPlain lib) _ -> fromLibrarySectionPlain lib+ where+ addToOtherModules xs r = r {libraryOtherModules = xs ++ libraryOtherModules r} fromLibrarySectionPlain :: LibrarySection -> Library fromLibrarySectionPlain LibrarySection{..} = Library { libraryExposed = librarySectionExposed- , libraryExposedModules = fromMaybeList librarySectionExposedModules- , libraryOtherModules = fromMaybeList librarySectionOtherModules+ , libraryExposedModules = fromMaybeList (librarySectionExposedModules <> librarySectionGeneratedExposedModules)+ , libraryOtherModules = fromMaybeList (librarySectionOtherModules <> librarySectionGeneratedOtherModules)+ , libraryGeneratedModules = fromMaybeList (librarySectionGeneratedOtherModules <> librarySectionGeneratedExposedModules) , libraryReexportedModules = fromMaybeList librarySectionReexportedModules , librarySignatures = fromMaybeList librarySectionSignatures }@@ -1062,8 +1077,8 @@ toExecutables dir packageName_ globalOptions = traverse (toExecutable dir packageName_ globalOptions) . fromMaybe mempty getMentionedExecutableModules :: ExecutableSection -> [String]-getMentionedExecutableModules ExecutableSection{..} =- fromMaybeList executableSectionOtherModules ++ maybe [] return (executableSectionMain >>= toModule . splitDirectories)+getMentionedExecutableModules (ExecutableSection main otherModules generatedModules)=+ maybe id (:) (main >>= toModule . splitDirectories) $ fromMaybeList (otherModules <> generatedModules) toExecutable :: FilePath -> String -> GlobalOptions -> SectionConfig Identity CSources JsSources ExecutableSection -> IO (Section Executable) toExecutable dir packageName_ globalOptions =@@ -1073,9 +1088,10 @@ where fromExecutableSection :: [String] -> [String] -> ExecutableSection -> Executable fromExecutableSection pathsModule inferableModules ExecutableSection{..} =- (Executable executableSectionMain otherModules)+ (Executable executableSectionMain (otherModules ++ generatedModules) generatedModules) where otherModules = maybe (inferableModules ++ pathsModule) fromList executableSectionOtherModules+ generatedModules = maybe [] fromList executableSectionGeneratedOtherModules expandMain :: Section ExecutableSection -> Section ExecutableSection expandMain = flatten . expand@@ -1163,6 +1179,3 @@ removeSetup src | src == dir = filter (/= "Setup") | otherwise = id--fromMaybeList :: Maybe (List a) -> [a]-fromMaybeList = maybe [] fromList
src/Hpack/Options.hs view
@@ -1,5 +1,10 @@+{-# LANGUAGE LambdaCase #-} module Hpack.Options where +import Control.Monad+import System.FilePath+import System.Directory+ data ParseResult = Help | PrintVersion | PrintNumericVersion | Run Options | ParseError deriving (Eq, Show) @@ -13,22 +18,26 @@ optionsVerbose :: Verbose , optionsForce :: Force , optionsToStdout :: Bool-, optionsTarget :: Maybe FilePath+, optionsConfigDir :: Maybe FilePath+, optionsConfigFile :: FilePath } deriving (Eq, Show) -parseOptions :: [String] -> ParseResult-parseOptions xs = case xs of- ["--version"] -> PrintVersion- ["--numeric-version"] -> PrintNumericVersion- ["--help"] -> Help+parseOptions :: FilePath -> [String] -> IO ParseResult+parseOptions defaultConfigFile xs = case xs of+ ["--version"] -> return PrintVersion+ ["--numeric-version"] -> return PrintNumericVersion+ ["--help"] -> return Help _ -> case targets of- Just (target, toStdout) -> Run (Options verbose force toStdout target)- Nothing -> ParseError+ Just (target, toStdout) -> do+ (dir, file) <- splitDirectory defaultConfigFile target+ return $ Run (Options verbose force toStdout dir file)+ Nothing -> return ParseError where silentFlag = "--silent" forceFlags = ["--force", "-f"] - flags = [silentFlag] ++ forceFlags+ flags = silentFlag : forceFlags+ verbose = if silentFlag `elem` xs then NoVerbose else Verbose force = if any (`elem` xs) forceFlags then Force else NoForce ys = filter (`notElem` flags) xs@@ -40,3 +49,15 @@ [dir, "-"] -> Just (Just dir, True) [] -> Just (Nothing, False) _ -> Nothing++splitDirectory :: FilePath -> Maybe FilePath -> IO (Maybe FilePath, FilePath)+splitDirectory defaultFileName = \ case+ Nothing -> return (Nothing, defaultFileName)+ (Just p) -> do+ isDirectory <- doesDirectoryExist p+ return $ if isDirectory+ then (Just p, defaultFileName)+ else let+ file = takeFileName p+ dir = takeDirectory p+ in (guard (p /= file) >> Just dir, if null file then defaultFileName else file)
src/Hpack/Run.hs view
@@ -4,7 +4,9 @@ {-# LANGUAGE ViewPatterns #-} {-# LANGUAGE CPP #-} module Hpack.Run (- run+ RunOptions(..)+, defaultRunOptions+, run , renderPackage , RenderSettings(..) , Alignment(..)@@ -31,17 +33,28 @@ import Data.Version import Data.Map.Lazy (Map) import qualified Data.Map.Lazy as Map+import qualified Data.Aeson as Aeson import Hpack.Util import Hpack.Config import Hpack.Render import Hpack.FormattingHints+import Hpack.Yaml -run :: Maybe FilePath -> FilePath -> IO ([String], FilePath, String)-run mDir c = do+data RunOptions = RunOptions {+ runOptionsConfigDir :: Maybe FilePath+, runOptionsConfigFile :: FilePath+, runOptionsDecode :: FilePath -> IO (Either String Aeson.Value)+}++defaultRunOptions :: RunOptions+defaultRunOptions = RunOptions Nothing packageConfig decodeYaml++run :: RunOptions -> IO ([String], FilePath, String)+run (RunOptions mDir c decode) = do let dir = fromMaybe "" mDir userDataDir <- getAppUserDataDirectory "hpack"- mPackage <- readPackageConfig userDataDir (dir </> c)+ mPackage <- readPackageConfigWith decode userDataDir (dir </> c) case mPackage of Right (pkg, warnings) -> do let cabalFile = dir </> (packageName pkg ++ ".cabal")@@ -132,8 +145,11 @@ cabalVersion = (">= " ++) . showVersion <$> maximum [ Just (makeVersion [1,10]) , packageCabalVersion- , packageLibrary >>= libraryCabalVersion . sectionData+ , packageLibrary >>= libraryCabalVersion , internalLibsCabalVersion packageInternalLibraries+ , executablesCabalVersion packageExecutables+ , executablesCabalVersion packageTests+ , executablesCabalVersion packageBenchmarks ] where packageCabalVersion :: Maybe Version@@ -143,18 +159,29 @@ , makeVersion [1,18] <$ guard (not (null packageExtraDocFiles)) ] - libraryCabalVersion :: Library -> Maybe Version- libraryCabalVersion Library{..} = maximum [+ libraryCabalVersion :: Section Library -> Maybe Version+ libraryCabalVersion sect = maximum [ makeVersion [1,22] <$ guard hasReexportedModules , makeVersion [2,0] <$ guard hasSignatures+ , makeVersion [2,0] <$ guard hasGeneratedModules ] where- hasReexportedModules = (not . null) libraryReexportedModules- hasSignatures = (not . null) librarySignatures+ hasReexportedModules = any (not . null . libraryReexportedModules) sect+ hasSignatures = any (not . null . librarySignatures) sect+ hasGeneratedModules = any (not . null . libraryGeneratedModules) sect internalLibsCabalVersion :: Map String (Section Library) -> Maybe Version internalLibsCabalVersion internalLibraries = makeVersion [2,0] <$ guard (not (Map.null internalLibraries)) + executablesCabalVersion :: Map String (Section Executable) -> Maybe Version+ executablesCabalVersion = foldr max Nothing . map executableCabalVersion . Map.elems++ executableCabalVersion :: Section Executable -> Maybe Version+ executableCabalVersion sect = makeVersion [2,0] <$ guard (executableHasGeneratedModules sect)++ executableHasGeneratedModules :: Section Executable -> Bool+ executableHasGeneratedModules = any (not . null . executableGeneratedModules)+ sortSectionFields :: [(String, [String])] -> [Element] -> [Element] sortSectionFields sectionsFieldOrder = go where@@ -226,10 +253,11 @@ renderExecutableSection sect = renderSection renderExecutableFields sect ++ [defaultLanguage] renderExecutableFields :: Executable -> [Element]-renderExecutableFields Executable{..} = mainIs ++ [otherModules]+renderExecutableFields Executable{..} = mainIs ++ [otherModules, generatedModules] where mainIs = maybe [] (return . Field "main-is" . Literal) executableMain otherModules = renderOtherModules executableOtherModules+ generatedModules = renderGeneratedModules executableGeneratedModules renderCustomSetup :: CustomSetup -> Element renderCustomSetup CustomSetup{..} =@@ -246,6 +274,7 @@ maybe [] (return . renderExposed) libraryExposed ++ [ renderExposedModules libraryExposedModules , renderOtherModules libraryOtherModules+ , renderGeneratedModules libraryGeneratedModules , renderReexportedModules libraryReexportedModules , renderSignatures librarySignatures ]@@ -303,6 +332,9 @@ renderOtherModules :: [String] -> Element renderOtherModules = Field "other-modules" . LineSeparatedList++renderGeneratedModules :: [String] -> Element+renderGeneratedModules = Field "autogen-modules" . LineSeparatedList renderReexportedModules :: [String] -> Element renderReexportedModules = Field "reexported-modules" . LineSeparatedList
src/Hpack/Util.hs view
@@ -5,6 +5,7 @@ {-# LANGUAGE GeneralizedNewtypeDeriving #-} module Hpack.Util ( List(..)+, fromMaybeList , GhcOption , GhcProfOption , GhcjsOption@@ -51,6 +52,9 @@ parseJSON v = List <$> case v of Array _ -> parseJSON v _ -> return <$> parseJSON v++fromMaybeList :: Maybe (List a) -> [a]+fromMaybeList = maybe [] fromList type GhcOption = String type GhcProfOption = String
test/EndToEndSpec.hs view
@@ -27,7 +27,7 @@ spec :: Spec spec = around_ (inTempDirectoryNamed "foo") $ do describe "hpack" $ do- context "with defaults" $ do+ describe "defaults" $ do it "accepts global defaults" $ do writeFile "defaults/sol/hpack-template/2017/defaults.yaml" [i| default-extensions:@@ -41,9 +41,7 @@ path: defaults.yaml ref: "2017" library: {}- |] `shouldRenderTo` library [i|- other-modules:- Paths_foo+ |] `shouldRenderTo` library_ [i| default-extensions: RecordWildCards DeriveFunctor |] @@ -73,9 +71,7 @@ - foo/bar@v1 - foo/bar@v2 library: {}- |] `shouldRenderTo` library [i|- other-modules:- Paths_foo+ |] `shouldRenderTo` library_ [i| default-extensions: RecordWildCards DeriveFunctor |] @@ -85,9 +81,7 @@ [i| defaults: foo/bar@v1 library: {}- |] `shouldRenderTo` library [i|- other-modules:- Paths_foo+ |] `shouldRenderTo` library_ [i| default-extensions: DeriveFunctor |] @@ -345,24 +339,11 @@ |] `shouldWarn` pure "Specified pattern \"foo/*.c\" for c-sources does not match any files" context "with library" $ do- it "accepts signatures" $ do- [i|- library:- signatures: Foo- |] `shouldRenderTo` (library [i|- other-modules:- Paths_foo- signatures:- Foo- |]) {packageCabalVersion = ">= 2.0"}- it "accepts global c-sources" $ do [i| c-sources: cbits/*.c library: {}- |] `shouldRenderTo` library [i|- other-modules:- Paths_foo+ |] `shouldRenderTo` library_ [i| c-sources: cbits/bar.c cbits/foo.c@@ -372,9 +353,7 @@ [i| library: c-sources: cbits/*.c- |] `shouldRenderTo` library [i|- other-modules:- Paths_foo+ |] `shouldRenderTo` library_ [i| c-sources: cbits/bar.c cbits/foo.c@@ -386,9 +365,7 @@ when: condition: os(windows) c-sources: cbits/*.c- |] `shouldRenderTo` library [i|- other-modules:- Paths_foo+ |] `shouldRenderTo` library_ [i| if os(windows) c-sources: cbits/bar.c@@ -418,7 +395,7 @@ cbits/foo.c |] - context "with custom-setup" $ do+ describe "custom-setup" $ do it "warns on unknown fields" $ do [i| name: foo@@ -451,18 +428,39 @@ base |]) {packageBuildType = "Make"} - context "with library" $ do+ describe "library" $ do it "accepts reexported-modules" $ do [i| library: reexported-modules: Baz- |] `shouldRenderTo` (library [i|- reexported-modules:- Baz- other-modules:- Paths_foo+ |] `shouldRenderTo` (library_ [i|+ reexported-modules:+ Baz |]) {packageCabalVersion = ">= 1.22"} + it "accepts signatures" $ do+ [i|+ library:+ signatures: Foo+ |] `shouldRenderTo` (library_ [i|+ signatures:+ Foo+ |]) {packageCabalVersion = ">= 2.0"}++ context "when package.yaml contains duplicate modules" $ do+ it "generates a cabal file with duplicate modules" $ do+ -- garbage in, garbage out+ [i|+ library:+ exposed-modules: Foo+ other-modules: Foo+ |] `shouldRenderTo` library [i|+ exposed-modules:+ Foo+ other-modules:+ Foo+ |]+ context "when inferring modules" $ do context "with exposed-modules" $ do it "infers other-modules" $ do@@ -601,7 +599,70 @@ unix/ |] - context "with internal-libraries" $ do+ context "with generated modules" $ do+ it "includes generated modules in autogen-modules" $ do+ [i|+ library:+ generated-exposed-modules: Foo+ generated-other-modules: Bar+ |] `shouldRenderTo` (library [i|+ exposed-modules:+ Foo+ other-modules:+ Paths_foo+ Bar+ autogen-modules:+ Foo+ Bar+ |]) {packageCabalVersion = ">= 2.0"}++ it "does not infer any mentioned generated modules" $ do+ touch "src/Exposed.hs"+ touch "src/Other.hs"+ [i|+ library:+ source-dirs: src+ generated-exposed-modules: Exposed+ generated-other-modules: Other+ |] `shouldRenderTo` (library [i|+ hs-source-dirs:+ src+ exposed-modules:+ Exposed+ other-modules:+ Paths_foo+ Other+ autogen-modules:+ Exposed+ Other+ |]) {packageCabalVersion = ">= 2.0"}++ it "does not infer any generated modules mentioned inside conditionals" $ do+ touch "src/Exposed.hs"+ touch "src/Other.hs"+ [i|+ library:+ source-dirs: src+ when:+ condition: os(windows)+ generated-exposed-modules: Exposed+ generated-other-modules: Other+ |] `shouldRenderTo` (library [i|+ other-modules:+ Paths_foo+ hs-source-dirs:+ src+ if os(windows)+ exposed-modules:+ Exposed+ other-modules:+ Other+ autogen-modules:+ Other+ Exposed+ |]) {packageCabalVersion = ">= 2.0"}++ describe "internal-libraries" $ do it "accepts internal-libraries" $ do touch "src/Foo.hs" [i|@@ -633,7 +694,7 @@ source-dirs: src |] `shouldWarn` pure "Specified source-dir \"src\" does not exist" - context "with executables" $ do+ describe "executables" $ do it "accepts arbitrary entry points as main" $ do touch "src/Foo.hs" touch "src/Bar.hs"@@ -686,6 +747,26 @@ other-modules: Baz |]++ it "does not infer any mentioned generated modules" $ do+ touch "src/Foo.hs"+ [i|+ executables:+ foo:+ main: Main.hs+ source-dirs: src+ generated-other-modules: Foo+ |] `shouldRenderTo` (executable "foo" [i|+ main-is: Main.hs+ hs-source-dirs:+ src+ other-modules:+ Paths_foo+ Foo+ autogen-modules:+ Foo+ |]) {packageCabalVersion = ">= 2.0"}+ context "with conditional" $ do it "doesn't infer any modules mentioned in that conditional" $ do touch "src/Foo.hs"@@ -888,6 +969,17 @@ content = [i| custom-setup #{indentBy 2 $ unindent a}+|]++library_ :: String -> Package+library_ l = package content+ where+ content = [i|+library+ other-modules:+ Paths_foo+#{indentBy 2 $ unindent l}+ default-language: Haskell2010 |] library :: String -> Package
test/Hpack/CabalFileSpec.hs view
@@ -26,6 +26,10 @@ let cabalFile = ["-- This file has been generated from package.yaml by hpack version 0.10.0."] extractVersion cabalFile `shouldBe` Just (makeVersion [0, 10, 0]) + it "is agnostic to file name" $ do+ let cabalFile = ["-- This file has been generated from some random file by hpack version 0.10.0."]+ extractVersion cabalFile `shouldBe` Just (makeVersion [0, 10, 0])+ it "is total" $ do let cabalFile = ["-- This file has been generated from package.yaml by hpack version "] extractVersion cabalFile `shouldBe` Nothing
test/Hpack/ConfigSpec.hs view
@@ -3,6 +3,7 @@ {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE MultiParamTypeClasses #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Hpack.ConfigSpec ( spec@@ -12,11 +13,10 @@ ) where import Helper- import Data.Aeson.Types import Data.String.Interpolate.IsString import Control.Arrow-import GHC.Exts+import qualified GHC.Exts as Exts import System.Directory (createDirectory) import Data.Either import qualified Data.Map.Lazy as Map@@ -26,7 +26,7 @@ import Hpack.Config hiding (package) import qualified Hpack.Config as Config -instance IsList (Maybe (List a)) where+instance Exts.IsList (Maybe (List a)) where type Item (Maybe (List a)) = a fromList = Just . List toList = undefined@@ -38,10 +38,10 @@ package = Config.package "foo" "0.0.0" executable :: String -> Executable-executable main_ = Executable (Just main_) ["Paths_foo"]+executable main_ = Executable (Just main_) ["Paths_foo"] [] library :: Library-library = Library Nothing [] ["Paths_foo"] [] []+library = Library Nothing [] ["Paths_foo"] [] [] [] withPackage :: String -> IO () -> ((Package, [String]) -> Expectation) -> Expectation withPackage content beforeAction expectation = withTempDirectory $ \dir_ -> do@@ -70,23 +70,14 @@ it "replaces dashes with underscores in package name" $ do pathsModuleFromPackageName "foo-bar" `shouldBe` "Paths_foo_bar" - describe "determineModules" $ do- it "adds the Paths_* module to the other-modules" $ do- determineModules ["Paths_foo"] [] ["Foo"] Nothing `shouldBe` (["Foo"], ["Paths_foo"])-- it "adds the Paths_* module to the other-modules when no modules are specified" $ do- determineModules ["Paths_foo"] [] Nothing Nothing `shouldBe` ([], ["Paths_foo"])-- context "when the Paths_* module is part of the exposed-modules" $ do- it "does not add the Paths_* module to the other-modules" $ do- determineModules ["Paths_foo"] [] ["Foo", "Paths_foo"] Nothing `shouldBe` (["Foo", "Paths_foo"], [])- describe "fromLibrarySectionInConditional" $ do let sect = LibrarySection { librarySectionExposed = Nothing , librarySectionExposedModules = Nothing+ , librarySectionGeneratedExposedModules = Nothing , librarySectionOtherModules = Nothing+ , librarySectionGeneratedOtherModules = Nothing , librarySectionReexportedModules = Nothing , librarySectionSignatures = Nothing }@@ -94,6 +85,7 @@ libraryExposed = Nothing , libraryExposedModules = [] , libraryOtherModules = []+ , libraryGeneratedModules = [] , libraryReexportedModules = [] , librarySignatures = [] }
test/Hpack/OptionsSpec.hs view
@@ -7,40 +7,80 @@ spec :: Spec spec = do describe "parseOptions" $ do+ let configFile = "package.yaml" context "with --help" $ do it "returns Help" $ do- parseOptions ["--help"] `shouldBe` Help+ parseOptions configFile ["--help"] `shouldReturn` Help context "with --version" $ do it "returns PrintVersion" $ do- parseOptions ["--version"] `shouldBe` PrintVersion+ parseOptions configFile ["--version"] `shouldReturn` PrintVersion context "by default" $ do it "returns Run" $ do- parseOptions [] `shouldBe` Run (Options Verbose NoForce False Nothing)+ parseOptions configFile [] `shouldReturn` Run (Options Verbose NoForce False Nothing configFile) it "includes target" $ do- parseOptions ["foo"] `shouldBe` Run (Options Verbose NoForce False (Just "foo"))+ parseOptions configFile ["foo.yaml"] `shouldReturn` Run (Options Verbose NoForce False Nothing "foo.yaml") context "with superfluous arguments" $ do it "returns ParseError" $ do- parseOptions ["foo", "bar"] `shouldBe` ParseError+ parseOptions configFile ["foo", "bar"] `shouldReturn` ParseError context "with --silent" $ do it "sets optionsVerbose to NoVerbose" $ do- parseOptions ["--silent"] `shouldBe` Run (Options NoVerbose NoForce False Nothing)+ parseOptions configFile ["--silent"] `shouldReturn` Run (Options NoVerbose NoForce False Nothing configFile) context "with --force" $ do it "sets optionsForce to Force" $ do- parseOptions ["--force"] `shouldBe` Run (Options Verbose Force False Nothing)+ parseOptions configFile ["--force"] `shouldReturn` Run (Options Verbose Force False Nothing configFile) context "with -f" $ do it "sets optionsForce to Force" $ do- parseOptions ["-f"] `shouldBe` Run (Options Verbose Force False Nothing)+ parseOptions configFile ["-f"] `shouldReturn` Run (Options Verbose Force False Nothing configFile) context "with -" $ do it "sets optionsToStdout to True" $ do- parseOptions ["-"] `shouldBe` Run (Options Verbose NoForce True Nothing)+ parseOptions configFile ["-"] `shouldReturn` Run (Options Verbose NoForce True Nothing configFile) it "rejects - for target" $ do- parseOptions ["-", "-"] `shouldBe` ParseError+ parseOptions configFile ["-", "-"] `shouldReturn` ParseError++ describe "splitDirectory" $ do+ let packageConfig = "package.yaml"+ context "when given Nothing" $ do+ it "defaults file name to package.yaml" $ do+ splitDirectory packageConfig Nothing `shouldReturn` (Nothing, "package.yaml")++ context "when given a directory" $ do+ it "defaults file name to package.yaml" $ do+ withTempDirectory $ \dir -> do+ splitDirectory packageConfig (Just dir) `shouldReturn` (Just dir, "package.yaml")++ context "when given a file name" $ do+ it "defaults directory to Nothing" $ do+ inTempDirectory $ do+ touch "foo.yaml"+ splitDirectory packageConfig (Just "foo.yaml") `shouldReturn` (Nothing, "foo.yaml")++ context "when given a path to a file" $ do+ it "splits directory from file name" $ do+ withTempDirectory $ \dir -> do+ let file = dir </> "foo.yaml"+ touch file+ splitDirectory packageConfig (Just file) `shouldReturn` (Just dir, "foo.yaml")++ context "when path does not exist" $ do+ it "splits path into directory and file name" $ do+ inTempDirectory $ do+ splitDirectory packageConfig (Just "test/foo.yaml") `shouldReturn` (Just "test", "foo.yaml")++ context "when file does not exist" $ do+ it "defaults directory to Nothing" $ do+ inTempDirectory $ do+ splitDirectory packageConfig (Just "test") `shouldReturn` (Nothing, "test")++ context "when directory does not exist" $ do+ it "defaults file name to package.yaml" $ do+ inTempDirectory $ do+ splitDirectory packageConfig (Just "test/") `shouldReturn` (Just "test", "package.yaml")
test/Hpack/RunSpec.hs view
@@ -1,9 +1,9 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE OverloadedLists #-} module Hpack.RunSpec (spec) where import Helper import Data.List-import qualified Data.Map.Lazy as Map import Hpack.ConfigSpec hiding (spec) import Hpack.Config hiding (package)@@ -11,8 +11,11 @@ import Hpack.Run library :: Library-library = Library Nothing [] [] [] []+library = Library Nothing [] [] [] [] [] +executable :: Section Executable+executable = section (Executable (Just "Main.hs") [] [])+ renderEmptySection :: Empty -> [Element] renderEmptySection Empty = [] @@ -159,7 +162,7 @@ ] it "retains section field order" $ do- renderPackage defaultRenderSettings 0 [] [("executable foo", ["default-language", "main-is", "ghc-options"])] package {packageExecutables = Map.fromList [("foo", (section $ Executable (Just "Main.hs") []) {sectionGhcOptions = ["-Wall", "-Werror"]})]} `shouldBe` unlines [+ renderPackage defaultRenderSettings 0 [] [("executable foo", ["default-language", "main-is", "ghc-options"])] package {packageExecutables = [("foo", executable {sectionGhcOptions = ["-Wall", "-Werror"]})]} `shouldBe` unlines [ "name: foo" , "version: 0.0.0" , "build-type: Simple"@@ -171,10 +174,9 @@ , " ghc-options: -Wall -Werror" ] - context "when rendering executable section" $ do it "includes dependencies" $ do- renderPackage_ package {packageExecutables = Map.fromList [("foo", (section $ Executable (Just "Main.hs") []) {sectionDependencies = Dependencies $ Map.fromList+ renderPackage_ package {packageExecutables = [("foo", executable {sectionDependencies = Dependencies [("foo", VersionRange "== 0.1.0"), ("bar", AnyVersion)]})]} `shouldBe` unlines [ "name: foo" , "version: 0.0.0"@@ -190,7 +192,7 @@ ] it "includes GHC options" $ do- renderPackage_ package {packageExecutables = Map.fromList [("foo", (section $ Executable (Just "Main.hs") []) {sectionGhcOptions = ["-Wall", "-Werror"]})]} `shouldBe` unlines [+ renderPackage_ package {packageExecutables = [("foo", executable {sectionGhcOptions = ["-Wall", "-Werror"]})]} `shouldBe` unlines [ "name: foo" , "version: 0.0.0" , "build-type: Simple"@@ -203,7 +205,7 @@ ] it "includes frameworks" $ do- renderPackage_ package {packageExecutables = Map.fromList [("foo", (section $ Executable (Just "Main.hs") []) {sectionFrameworks = ["foo", "bar"]})]} `shouldBe` unlines [+ renderPackage_ package {packageExecutables = [("foo", executable {sectionFrameworks = ["foo", "bar"]})]} `shouldBe` unlines [ "name: foo" , "version: 0.0.0" , "build-type: Simple"@@ -218,7 +220,7 @@ ] it "includes extra-framework-dirs" $ do- renderPackage_ package {packageExecutables = Map.fromList [("foo", (section $ Executable (Just "Main.hs") []) {sectionExtraFrameworksDirs = ["foo", "bar"]})]} `shouldBe` unlines [+ renderPackage_ package {packageExecutables = [("foo", executable {sectionExtraFrameworksDirs = ["foo", "bar"]})]} `shouldBe` unlines [ "name: foo" , "version: 0.0.0" , "build-type: Simple"@@ -233,7 +235,7 @@ ] it "includes GHC profiling options" $ do- renderPackage_ package {packageExecutables = Map.fromList [("foo", (section $ Executable (Just "Main.hs") []) {sectionGhcProfOptions = ["-fprof-auto", "-rtsopts"]})]} `shouldBe` unlines [+ renderPackage_ package {packageExecutables = [("foo", executable {sectionGhcProfOptions = ["-fprof-auto", "-rtsopts"]})]} `shouldBe` unlines [ "name: foo" , "version: 0.0.0" , "build-type: Simple"
test/HpackSpec.hs view
@@ -21,9 +21,9 @@ let file = "foo.cabal" - hpackWithVersion v = hpackWithVersionResult v Nothing NoForce- hpack = hpackWithVersionResult version Nothing NoForce- hpackForce = hpackWithVersionResult version Nothing Force+ hpackWithVersion v = hpackWithVersionResult v defaultRunOptions NoForce+ hpack = hpackWithVersionResult version defaultRunOptions NoForce+ hpackForce = hpackWithVersionResult version defaultRunOptions Force generated = Result [] file Generated modifiedManually = Result [] file ExistingCabalFileWasModifiedManually@@ -94,41 +94,3 @@ old <- readFile file hpack `shouldReturn` outputUnchanged readFile file `shouldReturn` old-- describe "splitDirectory" $ do- context "when given Nothing" $ do- it "defaults file name to package.yaml" $ do- splitDirectory Nothing `shouldReturn` (Nothing, "package.yaml")-- context "when given a directory" $ do- it "defaults file name to package.yaml" $ do- withTempDirectory $ \dir -> do- splitDirectory (Just dir) `shouldReturn` (Just dir, "package.yaml")-- context "when given a file name" $ do- it "defaults directory to Nothing" $ do- inTempDirectory $ do- touch "foo.yaml"- splitDirectory (Just "foo.yaml") `shouldReturn` (Nothing, "foo.yaml")-- context "when given a path to a file" $ do- it "splits directory from file name" $ do- withTempDirectory $ \dir -> do- let file = dir </> "foo.yaml"- touch file- splitDirectory (Just file) `shouldReturn` (Just dir, "foo.yaml")-- context "when path does not exist" $ do- it "defaults directory to Nothing" $ do- inTempDirectory $ do- splitDirectory (Just "test/foo.yaml") `shouldReturn` (Just "test", "foo.yaml")-- context "when file does not exist" $ do- it "defaults directory to Nothing" $ do- inTempDirectory $ do- splitDirectory (Just "test") `shouldReturn` (Nothing, "test")-- context "when directory does not exist" $ do- it "defaults directory to Nothing" $ do- inTempDirectory $ do- splitDirectory (Just "test/") `shouldReturn` (Just "test", "package.yaml")