packages feed

hpack 0.1.2 → 0.2.0

raw patch · 6 files changed

+304/−133 lines, 6 filesdep +textdep ~base

Dependencies added: text

Dependency ranges changed: base

Files

driver/Main.hs view
@@ -4,6 +4,7 @@ import           Prelude.Compat import           Control.Monad.Compat import           Control.Exception+import           System.IO import           System.IO.Error import           Data.List.Compat import           Data.Version (showVersion)@@ -12,8 +13,8 @@ import           Paths_hpack (version) import           Run -header :: String-header = unlines [+header :: String -> String+header configFile = unlines [     "-- This file has been generated from " ++ configFile ++ " by hpack version " ++ showVersion version ++ "."   , "--"   , "-- see: https://github.com/sol/hpack"@@ -22,9 +23,10 @@  main :: IO () main = do-  (name, new) <- run+  (configFile, warnings, name, new) <- run+  forM_ warnings $ \warning -> hPutStrLn stderr ("WARNING: " ++ warning)   old <- force . either (const Nothing) (Just . stripHeader) <$> tryJust (guard . isDoesNotExistError) (readFile name)-  unless (old == Just (lines new)) (writeFile name $ header ++ new)+  unless (old == Just (lines new)) (writeFile name $ header configFile ++ new)   where     stripHeader :: String -> [String]     stripHeader = dropWhile null . dropWhile ("--" `isPrefixOf`) . lines
hpack.cabal view
@@ -1,9 +1,9 @@--- This file has been generated from package.yaml by hpack version 0.1.1.+-- This file has been generated from package.yml by hpack version 0.2.0. -- -- see: https://github.com/sol/hpack  name:           hpack-version:        0.1.2+version:        0.2.0 synopsis:       An alternative format for Haskell packages homepage:       https://github.com/sol/hpack#readme bug-reports:    https://github.com/sol/hpack/issues@@ -18,8 +18,12 @@   location: https://github.com/sol/hpack  executable hpack-  hs-source-dirs: driver, src+  hs-source-dirs: src, driver   main-is: Main.hs+  other-modules:+      Config+      Run+      Util   build-depends:       aeson >= 0.8     , base == 4.*@@ -27,6 +31,7 @@     , deepseq     , directory     , filepath+    , text     , unordered-containers     , yaml   ghc-options: -Wall@@ -34,16 +39,16 @@  test-suite spec   type: exitcode-stdio-1.0-  hs-source-dirs: test, src+  hs-source-dirs: src, test   main-is: Spec.hs   other-modules:+      Config+      Run+      Util       ConfigSpec       Helper       RunSpec       UtilSpec-      Config-      Run-      Util   build-depends:       aeson >= 0.8     , base == 4.*@@ -51,6 +56,7 @@     , deepseq     , directory     , filepath+    , text     , unordered-containers     , yaml 
src/Config.hs view
@@ -1,4 +1,8 @@-{-# LANGUAGE DeriveGeneric, RecordWildCards #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-} module Config (   readPackageConfig , Package(..)@@ -12,18 +16,47 @@ import           Prelude.Compat import           Control.Applicative import           Control.Monad.Compat-import           Data.List ((\\))+import           Data.List (nub, sort, (\\)) import           Data.String import           Data.Maybe import           Data.Yaml import           GHC.Generics import           Data.HashMap.Lazy (HashMap) import qualified Data.HashMap.Lazy as Map+import qualified Data.Text as T import           System.FilePath import           System.Directory+import           Data.Data+import           Data.Aeson.Types  import           Util +genericParseJSON_ :: forall a. (Typeable a, Generic a, GFromJSON (Rep a)) => Value -> Parser a+genericParseJSON_ = genericParseJSON defaultOptions {fieldLabelModifier = hyphenize name}+  where+    name = (tyConName . typeRepTyCon . typeRep) (Proxy :: Proxy a)++hyphenize :: String -> String -> String+hyphenize name = camelTo '-' . drop (length name)++data CaptureUnknownFields a = CaptureUnknownFields {+  captureUnknownFieldsFields :: [String]+, captureUnknownFieldsValue :: a+} deriving (Eq, Show, Generic, Data, Typeable)++instance (Data a, FromJSON a) => FromJSON (CaptureUnknownFields a) where+  parseJSON v = captureUnknownFields <$> parseJSON v+    where+      captureUnknownFields a = case v of+        Object o -> CaptureUnknownFields unknown a+          where+            unknown = keys \\ fields+            keys = map T.unpack (Map.keys o)+            constr = toConstr a+            name = showConstr constr+            fields = map (hyphenize name) (constrFields constr)+        _ -> CaptureUnknownFields [] a+ data LibrarySection = LibrarySection {   librarySectionSourceDirs :: Maybe (List FilePath) , librarySectionExposedModules :: Maybe (List String)@@ -31,10 +64,10 @@ , librarySectionDependencies :: Maybe (List Dependency) , librarySectionDefaultExtensions :: Maybe (List String) , librarySectionGhcOptions :: Maybe (List GhcOption)-} deriving (Eq, Show, Generic)+} deriving (Eq, Show, Generic, Data, Typeable)  instance FromJSON LibrarySection where-  parseJSON = genericParseJSON_ "LibrarySection"+  parseJSON = genericParseJSON_  data ExecutableSection = ExecutableSection {   executableSectionMain :: FilePath@@ -43,10 +76,10 @@ , executableSectionDependencies :: Maybe (List Dependency) , executableSectionDefaultExtensions :: Maybe (List String) , executableSectionGhcOptions :: Maybe (List GhcOption)-} deriving (Eq, Show, Generic)+} deriving (Eq, Show, Generic, Data, Typeable)  instance FromJSON ExecutableSection where-  parseJSON = genericParseJSON_ "ExecutableSection"+  parseJSON = genericParseJSON_  data PackageConfig = PackageConfig {   packageConfigName :: Maybe String@@ -67,13 +100,13 @@ , packageConfigDependencies :: Maybe (List Dependency) , packageConfigDefaultExtensions :: Maybe (List String) , packageConfigGhcOptions :: Maybe (List GhcOption)-, packageConfigLibrary :: Maybe LibrarySection-, packageConfigExecutables :: Maybe (HashMap String ExecutableSection)-, packageConfigTests :: Maybe (HashMap String ExecutableSection)-} deriving (Eq, Show, Generic)+, packageConfigLibrary :: Maybe (CaptureUnknownFields LibrarySection)+, packageConfigExecutables :: Maybe (HashMap String (CaptureUnknownFields ExecutableSection))+, packageConfigTests :: Maybe (HashMap String (CaptureUnknownFields ExecutableSection))+} deriving (Eq, Show, Generic, Data, Typeable)  instance FromJSON PackageConfig where-  parseJSON value = handleNullValues <$> genericParseJSON_ "PackageConfig" value+  parseJSON value = handleNullValues <$> genericParseJSON_ value     where       handleNullValues :: PackageConfig -> PackageConfig       handleNullValues =@@ -92,14 +125,16 @@   where     p = parseJSON >=> (.: fromString name) -readPackageConfig :: FilePath -> IO (Either String Package)+readPackageConfig :: FilePath -> IO (Either String ([String], Package)) readPackageConfig file = do   config <- decodeFileEither file   either (return . Left . errToString) (fmap Right . mkPackage) config   where     errToString err = file ++ case err of       AesonException e -> ": " ++ e-      InvalidYaml (Just e) -> let loc = yamlProblemMark e in ":" ++ show (yamlLine loc) ++ ":" ++ show (yamlColumn loc) ++ ": " ++ yamlProblem e ++ " " ++ yamlContext e+      InvalidYaml (Just (YamlException s)) -> ": " ++ s+      InvalidYaml (Just (YamlParseException{..})) -> ":" ++ show yamlLine ++ ":" ++ show yamlColumn ++ ": " ++ yamlProblem ++ " " ++ yamlContext+        where YamlMark{..} = yamlProblemMark       _ -> ": " ++ show err  type Dependency = String@@ -145,20 +180,28 @@ , executableGhcOptions :: [GhcOption] } deriving (Eq, Show) -mkPackage :: PackageConfig -> IO Package-mkPackage PackageConfig{..} = do+mkPackage :: (CaptureUnknownFields PackageConfig) -> IO ([String], Package)+mkPackage (CaptureUnknownFields unknownFields PackageConfig{..}) = do   let dependencies = fromMaybeList packageConfigDependencies-  let sourceDirs = fromMaybeList packageConfigSourceDirs-  let defaultExtensions = fromMaybeList packageConfigDefaultExtensions-  let ghcOptions = fromMaybeList packageConfigGhcOptions-  mLibrary <- mapM (mkLibrary sourceDirs dependencies defaultExtensions ghcOptions) packageConfigLibrary-  executables <- toExecutables sourceDirs dependencies defaultExtensions ghcOptions packageConfigExecutables-  tests <- toExecutables sourceDirs dependencies defaultExtensions ghcOptions packageConfigTests+      sourceDirs = fromMaybeList packageConfigSourceDirs+      defaultExtensions = fromMaybeList packageConfigDefaultExtensions+      ghcOptions = fromMaybeList packageConfigGhcOptions+      convert f = f sourceDirs dependencies defaultExtensions ghcOptions +  mLibrary <- mapM (convert toLibrary) mLibrarySection+  executables <- convert toExecutables mExecutableSections+  tests <- convert toExecutables mTestSections+   name <- maybe (takeBaseName <$> getCurrentDirectory) return packageConfigName    licenseFileExists <- doesFileExist "LICENSE" +  missingSourceDirs <- nub . sort <$> filterM (fmap not <$> doesDirectoryExist) (+       maybe [] librarySourceDirs mLibrary+    ++ concatMap executableSourceDirs executables+    ++ concatMap executableSourceDirs tests+    )+   let package = Package {         packageName = name       , packageVersion = fromMaybe "0.0.0" packageConfigVersion@@ -179,8 +222,38 @@       , packageExecutables = executables       , packageTests = tests       }-  return package++      warnings =+           formatUnknownFields "package description" unknownFields+        ++ maybe [] (formatUnknownFields "library section") (captureUnknownFieldsFields <$> packageConfigLibrary)+        ++ formatUnknownSectionFields "executable" packageConfigExecutables+        ++ formatUnknownSectionFields "test" packageConfigTests+        ++ formatMissingSourceDirs missingSourceDirs++  return (warnings, package)   where+    mLibrarySection :: Maybe LibrarySection+    mLibrarySection = captureUnknownFieldsValue <$> packageConfigLibrary++    mExecutableSections :: Maybe (HashMap String ExecutableSection)+    mExecutableSections = fmap captureUnknownFieldsValue <$> packageConfigExecutables++    mTestSections :: Maybe (HashMap String ExecutableSection)+    mTestSections = fmap captureUnknownFieldsValue <$> packageConfigTests++    formatUnknownFields name = map f . sort+      where+        f field = "Ignoring unknown field " ++ show field ++ " in " ++ name++    formatUnknownSectionFields sectionType = maybe [] (concatMap f . Map.toList . fmap captureUnknownFieldsFields)+      where+        f :: (String, [String]) -> [String]+        f (section, fields) = formatUnknownFields (sectionType ++ " section " ++ show section) fields++    formatMissingSourceDirs = map f+      where+        f name = "Specified source-dir " ++ show name ++ " does not exist"+     github = ("https://github.com/" ++) <$> packageConfigGithub      homepage :: Maybe String@@ -197,8 +270,8 @@       where         fromGithub = ((++ "/issues") <$> github) -mkLibrary :: [FilePath] -> [Dependency] -> [String] -> [GhcOption] -> LibrarySection -> IO Library-mkLibrary globalSourceDirs globalDependencies globalDefaultExtensions globalGhcOptions LibrarySection{..} = do+toLibrary :: [FilePath] -> [Dependency] -> [String] -> [GhcOption] -> LibrarySection -> IO Library+toLibrary globalSourceDirs globalDependencies globalDefaultExtensions globalGhcOptions LibrarySection{..} = do   modules <- concat <$> mapM getModules sourceDirs    let (exposedModules, otherModules) = determineModules modules librarySectionExposedModules librarySectionOtherModules
src/Run.hs view
@@ -1,7 +1,6 @@ {-# LANGUAGE QuasiQuotes, RecordWildCards #-} module Run (   run-, configFile -- exported for testing , renderPackage ) where@@ -16,20 +15,20 @@ import           Config  configFile :: FilePath-configFile = "package.yaml"+configFile = "package.yml" -run :: IO (FilePath, String)+run :: IO (FilePath, [String], FilePath, String) run = do   mPackage <- readPackageConfig configFile   case mPackage of-    Right package -> do+    Right (warnings, package) -> do       let cabalFile = packageName package ++ ".cabal"        old <- tryReadFile cabalFile        let alignment = fromMaybe 16 (old >>= sniffAlignment)           output = renderPackage alignment (maybe [] extractFieldOrderHint old) package-      return (cabalFile, output)+      return (configFile, warnings, cabalFile, output)     Left err -> die err  renderPackage :: Int -> [String] -> Package -> String
src/Util.hs view
@@ -1,8 +1,7 @@-{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE DeriveDataTypeable #-} module Util (   List(..) , toModule-, genericParseJSON_ , getFilesRecursive , tryReadFile , sniffAlignment@@ -21,15 +20,12 @@ import           Data.List import           System.Directory import           System.FilePath+import           Data.Data -import           GHC.Generics import           Data.Aeson.Types -genericParseJSON_ :: (Generic a, GFromJSON (Rep a)) => String -> Value -> Parser a-genericParseJSON_ name = genericParseJSON defaultOptions {fieldLabelModifier = camelTo '-' . drop (length name)}- newtype List a = List {fromList :: [a]}-  deriving (Eq, Show)+  deriving (Eq, Show, Data, Typeable)  instance FromJSON a => FromJSON (List a) where   parseJSON v = List <$> (parseJSON v <|> (return <$> parseJSON v))
test/ConfigSpec.hs view
@@ -29,233 +29,279 @@ spec :: Spec spec = around_ (inTempDirectoryNamed "foo") $ do   describe "readPackageConfig" $ do+    it "warns on unknown fields" $ do+      writeFile "package.yml" [i|+        bar: 23+        baz: 42+        |]+      fmap fst <$> readPackageConfig "package.yml" `shouldReturn` Right [+          "Ignoring unknown field \"bar\" in package description"+        , "Ignoring unknown field \"baz\" in package description"+        ]+     it "accepts name" $ do-      writeFile "package.yaml" [i|+      writeFile "package.yml" [i|         name: bar         |]-      readPackageConfig "package.yaml" `shouldReturn` Right package {packageName = "bar"}+      Right (_, c) <- readPackageConfig "package.yml"+      c `shouldBe` package {packageName = "bar"}      it "accepts version" $ do-      writeFile "package.yaml" [i|+      writeFile "package.yml" [i|         version: 0.1.0         |]-      readPackageConfig "package.yaml" `shouldReturn` Right package {packageVersion = "0.1.0"}+      Right (_, c) <- readPackageConfig "package.yml"+      c `shouldBe` package {packageVersion = "0.1.0"}      it "accepts synopsis" $ do-      writeFile "package.yaml" [i|+      writeFile "package.yml" [i|         synopsis: some synopsis         |]-      readPackageConfig "package.yaml" `shouldReturn` Right package {packageSynopsis = Just "some synopsis"}+      Right (_, c) <- readPackageConfig "package.yml"+      c `shouldBe` package {packageSynopsis = Just "some synopsis"}      it "accepts description" $ do-      writeFile "package.yaml" [i|+      writeFile "package.yml" [i|         description: some description         |]-      readPackageConfig "package.yaml" `shouldReturn` Right package {packageDescription = Just "some description"}+      Right (_, c) <- readPackageConfig "package.yml"+      c `shouldBe` package {packageDescription = Just "some description"}      it "accepts category" $ do-      writeFile "package.yaml" [i|+      writeFile "package.yml" [i|         category: Data         |]-      readPackageConfig "package.yaml" `shouldReturn` Right package {packageCategory = Just "Data"}+      Right (_, c) <- readPackageConfig "package.yml"+      c `shouldBe` package {packageCategory = Just "Data"}      it "accepts author" $ do-      writeFile "package.yaml" [i|+      writeFile "package.yml" [i|         author: John Doe         |]-      readPackageConfig "package.yaml" `shouldReturn` Right package {packageAuthor = ["John Doe"]}+      Right (_, c) <- readPackageConfig "package.yml"+      c `shouldBe` package {packageAuthor = ["John Doe"]}      it "accepts maintainer" $ do-      writeFile "package.yaml" [i|+      writeFile "package.yml" [i|         maintainer: John Doe <john.doe@example.com>         |]-      readPackageConfig "package.yaml" `shouldReturn` Right package {packageMaintainer = ["John Doe <john.doe@example.com>"]}+      Right (_, c) <- readPackageConfig "package.yml"+      c `shouldBe` package {packageMaintainer = ["John Doe <john.doe@example.com>"]}      it "accepts copyright" $ do-      writeFile "package.yaml" [i|+      writeFile "package.yml" [i|         copyright: (c) 2015 John Doe         |]-      readPackageConfig "package.yaml" `shouldReturn` Right package {packageCopyright = ["(c) 2015 John Doe"]}+      Right (_, c) <- readPackageConfig "package.yml"+      c `shouldBe` package {packageCopyright = ["(c) 2015 John Doe"]}      it "accepts stability" $ do-      writeFile "package.yaml" [i|+      writeFile "package.yml" [i|         stability: experimental         |]-      Right c <- readPackageConfig "package.yaml"+      Right (_, c) <- readPackageConfig "package.yml"       packageStability c `shouldBe` Just "experimental"      it "accepts homepage URL" $ do-      writeFile "package.yaml" [i|+      writeFile "package.yml" [i|         github: hspec/hspec         homepage: https://example.com/         |]-      Right c <- readPackageConfig "package.yaml"+      Right (_, c) <- readPackageConfig "package.yml"       packageHomepage c `shouldBe` Just "https://example.com/"      it "infers homepage URL from github" $ do-      writeFile "package.yaml" [i|+      writeFile "package.yml" [i|         github: hspec/hspec         |]-      Right c <- readPackageConfig "package.yaml"+      Right (_, c) <- readPackageConfig "package.yml"       packageHomepage c `shouldBe` Just "https://github.com/hspec/hspec#readme"      it "omits homepage URL if it is null" $ do-      writeFile "package.yaml" [i|+      writeFile "package.yml" [i|         github: hspec/hspec         homepage: null         |]-      Right c <- readPackageConfig "package.yaml"+      Right (_, c) <- readPackageConfig "package.yml"       packageHomepage c `shouldBe` Nothing      it "accepts bug-reports URL" $ do-      writeFile "package.yaml" [i|+      writeFile "package.yml" [i|         github: hspec/hspec         bug-reports: https://example.com/issues         |]-      Right c <- readPackageConfig "package.yaml"+      Right (_, c) <- readPackageConfig "package.yml"       packageBugReports c `shouldBe` Just "https://example.com/issues"      it "infers bug-reports URL from github" $ do-      writeFile "package.yaml" [i|+      writeFile "package.yml" [i|         github: hspec/hspec         |]-      Right c <- readPackageConfig "package.yaml"+      Right (_, c) <- readPackageConfig "package.yml"       packageBugReports c `shouldBe` Just "https://github.com/hspec/hspec/issues"      it "omits bug-reports URL if it is null" $ do-      writeFile "package.yaml" [i|+      writeFile "package.yml" [i|         github: hspec/hspec         bug-reports: null         |]-      Right c <- readPackageConfig "package.yaml"+      Right (_, c) <- readPackageConfig "package.yml"       packageBugReports c `shouldBe` Nothing      it "accepts license" $ do-      writeFile "package.yaml" [i|+      writeFile "package.yml" [i|         license: MIT         |]-      readPackageConfig "package.yaml" `shouldReturn` Right package {packageLicense = Just "MIT"}+      Right (_, c) <- readPackageConfig "package.yml"+      c `shouldBe` package {packageLicense = Just "MIT"}      it "infers license file" $ do-      writeFile "package.yaml" [i|+      writeFile "package.yml" [i|         name: foo         |]       touch "LICENSE"-      readPackageConfig "package.yaml" `shouldReturn` Right package {packageLicenseFile = Just "LICENSE"}+      Right (_, c) <- readPackageConfig "package.yml"+      c `shouldBe` package {packageLicenseFile = Just "LICENSE"}      it "accepts extra-source-files" $ do-      writeFile "package.yaml" [i|+      writeFile "package.yml" [i|         extra-source-files:           - CHANGES.markdown           - README.markdown         |]-      Right c <- readPackageConfig "package.yaml"+      Right (_, c) <- readPackageConfig "package.yml"       packageExtraSourceFiles c `shouldBe` ["CHANGES.markdown", "README.markdown"]      it "accepts github" $ do-      writeFile "package.yaml" [i|+      writeFile "package.yml" [i|         github: hspec/hspec         |]-      Right c <- readPackageConfig "package.yaml"+      Right (_, c) <- readPackageConfig "package.yml"       packageSourceRepository c `shouldBe` Just "https://github.com/hspec/hspec"      context "when reading library section" $ do+      it "warns on unknown fields" $ do+        writeFile "package.yml" [i|+          library:+            bar: 23+            baz: 42+          |]++        fmap fst <$> readPackageConfig "package.yml" `shouldReturn` Right [+            "Ignoring unknown field \"bar\" in library section"+          , "Ignoring unknown field \"baz\" in library section"+          ]+       it "accepts source-dirs" $ do-        writeFile "package.yaml" [i|+        writeFile "package.yml" [i|           library:             source-dirs:               - foo               - bar           |]-        Right c <- readPackageConfig "package.yaml"+        Right (_, c) <- readPackageConfig "package.yml"         packageLibrary c `shouldBe` Just library {librarySourceDirs = ["foo", "bar"]}        it "accepts default-extensions" $ do-        writeFile "package.yaml" [i|+        writeFile "package.yml" [i|           library:             default-extensions:               - Foo               - Bar           |]-        Right c <- readPackageConfig "package.yaml"+        Right (_, c) <- readPackageConfig "package.yml"         packageLibrary c `shouldBe` Just library {libraryDefaultExtensions = ["Foo", "Bar"]}        it "accepts global default-extensions" $ do-        writeFile "package.yaml" [i|+        writeFile "package.yml" [i|           default-extensions:             - Foo             - Bar           library: {}           |]-        Right c <- readPackageConfig "package.yaml"+        Right (_, c) <- readPackageConfig "package.yml"         packageLibrary c `shouldBe` Just library {libraryDefaultExtensions = ["Foo", "Bar"]}        it "accepts global source-dirs" $ do-        writeFile "package.yaml" [i|+        writeFile "package.yml" [i|           source-dirs:             - foo             - bar           library: {}           |]-        Right c <- readPackageConfig "package.yaml"+        Right (_, c) <- readPackageConfig "package.yml"         packageLibrary c `shouldBe` Just library {librarySourceDirs = ["foo", "bar"]}        it "allows to specify exposed-modules" $ do-        writeFile "package.yaml" [i|+        writeFile "package.yml" [i|           library:             source-dirs: src             exposed-modules: Foo           |]         touch "src/Foo.hs"         touch "src/Bar.hs"-        Right c <- readPackageConfig "package.yaml"+        Right (_, c) <- readPackageConfig "package.yml"         packageLibrary c `shouldBe` Just library {librarySourceDirs = ["src"], libraryExposedModules = ["Foo"], libraryOtherModules = ["Bar"]}        it "allows to specify other-modules" $ do-        writeFile "package.yaml" [i|+        writeFile "package.yml" [i|           library:             source-dirs: src             other-modules: Bar           |]         touch "src/Foo.hs"         touch "src/Bar.hs"-        Right c <- readPackageConfig "package.yaml"+        Right (_, c) <- readPackageConfig "package.yml"         packageLibrary c `shouldBe` Just library {librarySourceDirs = ["src"], libraryExposedModules = ["Foo"], libraryOtherModules = ["Bar"]}        it "allows to specify both exposed-modules and other-modules" $ do-        writeFile "package.yaml" [i|+        writeFile "package.yml" [i|           library:             source-dirs: src             exposed-modules: Foo             other-modules: Bar           |]         touch "src/Baz.hs"-        Right c <- readPackageConfig "package.yaml"+        Right (_, c) <- readPackageConfig "package.yml"         packageLibrary c `shouldBe` Just library {librarySourceDirs = ["src"], libraryExposedModules = ["Foo"], libraryOtherModules = ["Bar"]}        context "when neither exposed-module nor other-module are specified" $ do         it "exposes all modules" $ do-          writeFile "package.yaml" [i|+          writeFile "package.yml" [i|             library:               source-dirs: src             |]           touch "src/Foo.hs"           touch "src/Bar.hs"-          Right c <- readPackageConfig "package.yaml"+          Right (_, c) <- readPackageConfig "package.yml"           packageLibrary c `shouldBe` Just library {librarySourceDirs = ["src"], libraryExposedModules = ["Bar", "Foo"]}      context "when reading executable section" $ do+      it "warns on unknown fields" $ do+        writeFile "package.yml" [i|+          executables:+            foo:+              main: Main.hs+              bar: 42+              baz: 23+          |]++        fmap fst <$> readPackageConfig "package.yml" `shouldReturn` Right [+            "Ignoring unknown field \"bar\" in executable section \"foo\""+          , "Ignoring unknown field \"baz\" in executable section \"foo\""+          ]+       it "reads executable section" $ do-        writeFile "package.yaml" [i|+        writeFile "package.yml" [i|           executables:             foo:               main: driver/Main.hs           |]-        Right c <- readPackageConfig "package.yaml"+        Right (_, c) <- readPackageConfig "package.yml"         packageExecutables c `shouldBe` [executable "foo" "driver/Main.hs"]        it "accepts source-dirs" $ do-        writeFile "package.yaml" [i|+        writeFile "package.yml" [i|           executables:             foo:               main: Main.hs@@ -263,11 +309,11 @@                 - foo                 - bar           |]-        Right c <- readPackageConfig "package.yaml"+        Right (_, c) <- readPackageConfig "package.yml"         packageExecutables c `shouldBe` [(executable "foo" "Main.hs") {executableSourceDirs = ["foo", "bar"]}]        it "accepts global source-dirs" $ do-        writeFile "package.yaml" [i|+        writeFile "package.yml" [i|           source-dirs:             - foo             - bar@@ -275,7 +321,7 @@             foo:               main: Main.hs           |]-        Right c <- readPackageConfig "package.yaml"+        Right (_, c) <- readPackageConfig "package.yml"         packageExecutables c `shouldBe` [(executable "foo" "Main.hs") {executableSourceDirs = ["foo", "bar"]}]        it "infers other-modules" $ do@@ -283,30 +329,30 @@         touch "src/Foo.hs"         touch "src/Bar.hs"         touch "src/Baz.lhs"-        writeFile "package.yaml" [i|+        writeFile "package.yml" [i|           executables:             foo:               main: Main.hs               source-dirs: src           |]-        Right [r] <- fmap packageExecutables <$> readPackageConfig "package.yaml"+        Right (_, [r]) <- (fmap . fmap) packageExecutables <$> readPackageConfig "package.yml"         executableOtherModules r `shouldBe` ["Bar", "Baz", "Foo"]        it "allows to specify other-modules" $ do         touch "src/Foo.hs"         touch "src/Bar.hs"-        writeFile "package.yaml" [i|+        writeFile "package.yml" [i|           executables:             foo:               main: Main.hs               source-dirs: src               other-modules: Baz           |]-        Right [r] <- fmap packageExecutables <$> readPackageConfig "package.yaml"+        Right (_, [r]) <- (fmap . fmap) packageExecutables <$> readPackageConfig "package.yml"         executableOtherModules r `shouldBe` ["Baz"]        it "accepts default-extensions" $ do-        writeFile "package.yaml" [i|+        writeFile "package.yml" [i|           executables:             foo:               main: driver/Main.hs@@ -314,11 +360,11 @@                 - Foo                 - Bar           |]-        Right c <- readPackageConfig "package.yaml"+        Right (_, c) <- readPackageConfig "package.yml"         packageExecutables c `shouldBe` [(executable "foo" "driver/Main.hs") {executableDefaultExtensions = ["Foo", "Bar"]}]        it "accepts global default-extensions" $ do-        writeFile "package.yaml" [i|+        writeFile "package.yml" [i|           default-extensions:             - Foo             - Bar@@ -326,47 +372,65 @@             foo:               main: driver/Main.hs           |]-        Right c <- readPackageConfig "package.yaml"+        Right (_, c) <- readPackageConfig "package.yml"         packageExecutables c `shouldBe` [(executable "foo" "driver/Main.hs") {executableDefaultExtensions = ["Foo", "Bar"]}]        it "accepts GHC options" $ do-        writeFile "package.yaml" [i|+        writeFile "package.yml" [i|           executables:             foo:               main: driver/Main.hs               ghc-options: -Wall           |]-        readPackageConfig "package.yaml" `shouldReturn` Right package {packageExecutables = [(executable "foo" "driver/Main.hs") {executableGhcOptions = ["-Wall"]}]}+        Right (_, c) <- readPackageConfig "package.yml"+        c `shouldBe` package {packageExecutables = [(executable "foo" "driver/Main.hs") {executableGhcOptions = ["-Wall"]}]}        it "accepts global GHC options" $ do-        writeFile "package.yaml" [i|+        writeFile "package.yml" [i|           ghc-options: -Wall           executables:             foo:               main: driver/Main.hs           |]-        readPackageConfig "package.yaml" `shouldReturn` Right package {packageExecutables = [(executable "foo" "driver/Main.hs") {executableGhcOptions = ["-Wall"]}]}+        Right (_, c) <- readPackageConfig "package.yml"+        c `shouldBe` package {packageExecutables = [(executable "foo" "driver/Main.hs") {executableGhcOptions = ["-Wall"]}]}      context "when reading test section" $ do+      it "warns on unknown fields" $ do+        writeFile "package.yml" [i|+          tests:+            foo:+              main: Main.hs+              bar: 42+              baz: 23+          |]++        fmap fst <$> readPackageConfig "package.yml" `shouldReturn` Right [+            "Ignoring unknown field \"bar\" in test section \"foo\""+          , "Ignoring unknown field \"baz\" in test section \"foo\""+          ]+       it "reads test section" $ do-        writeFile "package.yaml" [i|+        writeFile "package.yml" [i|           tests:             spec:               main: test/Spec.hs           |]-        readPackageConfig "package.yaml" `shouldReturn` Right package {packageTests = [executable "spec" "test/Spec.hs"]}+        Right (_, c) <- readPackageConfig "package.yml"+        c `shouldBe` package {packageTests = [executable "spec" "test/Spec.hs"]}        it "accepts single dependency" $ do-        writeFile "package.yaml" [i|+        writeFile "package.yml" [i|           tests:             spec:               main: test/Spec.hs               dependencies: hspec           |]-        readPackageConfig "package.yaml" `shouldReturn` Right package {packageTests = [(executable "spec" "test/Spec.hs") {executableDependencies = [["hspec"]]}]}+        Right (_, c) <- readPackageConfig "package.yml"+        c `shouldBe` package {packageTests = [(executable "spec" "test/Spec.hs") {executableDependencies = [["hspec"]]}]}        it "accepts list of dependencies" $ do-        writeFile "package.yaml" [i|+        writeFile "package.yml" [i|           tests:             spec:               main: test/Spec.hs@@ -374,11 +438,12 @@                 - hspec                 - QuickCheck           |]-        readPackageConfig "package.yaml" `shouldReturn` Right package {packageTests = [(executable "spec" "test/Spec.hs") {executableDependencies = [["hspec", "QuickCheck"]]}]}+        Right (_, c) <- readPackageConfig "package.yml"+        c `shouldBe` package {packageTests = [(executable "spec" "test/Spec.hs") {executableDependencies = [["hspec", "QuickCheck"]]}]}        context "when both top-level and section specific dependencies are specified" $ do         it "combines dependencies" $ do-          writeFile "package.yaml" [i|+          writeFile "package.yml" [i|             dependencies:               - base @@ -387,21 +452,51 @@                 main: test/Spec.hs                 dependencies: hspec             |]-          readPackageConfig "package.yaml" `shouldReturn` Right package {packageTests = [(executable "spec" "test/Spec.hs") {executableDependencies = [["base"], ["hspec"]]}]}+          Right (_, c) <- readPackageConfig "package.yml"+          c `shouldBe` package {packageTests = [(executable "spec" "test/Spec.hs") {executableDependencies = [["base"], ["hspec"]]}]} -    context "when package.yaml can not be parsed" $ do+    context "when a specified source directory does not exist" $ do+      it "warns" $ do+        writeFile "package.yml" [i|+          source-dirs:+            - some-dir+            - some-existing-dir+          library:+            source-dirs: some-lib-dir+          executables:+            main:+              main: Main.hs+              source-dirs: some-exec-dir+          tests:+            spec:+              main: Main.hs+              source-dirs: some-test-dir+          |]+        touch "some-existing-dir/foo"+        fmap fst <$> readPackageConfig "package.yml" `shouldReturn` Right [+            "Specified source-dir " ++ show "some-dir" ++ " does not exist"+          , "Specified source-dir " ++ show "some-exec-dir" ++ " does not exist"+          , "Specified source-dir " ++ show "some-lib-dir" ++ " does not exist"+          , "Specified source-dir " ++ show "some-test-dir" ++ " does not exist"+          ]++    context "when package.yml can not be parsed" $ do       it "returns an error" $ do-        writeFile "package.yaml" [i|+        writeFile "package.yml" [i|           foo: bar           foo baz           |]-        readPackageConfig "package.yaml" `shouldReturn` Left "package.yaml:3:10: could not find expected ':' while scanning a simple key"+        readPackageConfig "package.yml" `shouldReturn` Left "package.yml:3:10: could not find expected ':' while scanning a simple key" -    context "when package.yaml is invalid" $ do+    context "when package.yml is invalid" $ do       it "returns an error" $ do-        writeFile "package.yaml" [i|+        writeFile "package.yml" [i|           executables:             foo:               ain: driver/Main.hs           |]-        readPackageConfig "package.yaml" `shouldReturn` Left "package.yaml: The key \"main\" was not found"+        readPackageConfig "package.yml" `shouldReturn` Left "package.yml: The key \"main\" was not found"++    context "when package.yml does not exist" $ do+      it "returns an error" $+        readPackageConfig "package.yml" `shouldReturn` Left "package.yml: Yaml file not found: package.yml"