packages feed

hpack 0.33.0.1 → 0.33.1

raw patch · 10 files changed

+265/−144 lines, 10 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

+ Hpack: ForceHash :: GenerateHashStrategy
+ Hpack: ForceNoHash :: GenerateHashStrategy
+ Hpack: PreferHash :: GenerateHashStrategy
+ Hpack: PreferNoHash :: GenerateHashStrategy
+ Hpack: [optionsGenerateHashStrategy] :: Options -> GenerateHashStrategy
+ Hpack: data GenerateHashStrategy
+ Hpack: instance GHC.Classes.Eq Hpack.GenerateHashStrategy
+ Hpack: instance GHC.Show.Show Hpack.GenerateHashStrategy
+ Hpack.Config: DependencyInfo :: [String] -> DependencyVersion -> DependencyInfo
+ Hpack.Config: [dependencyInfoMixins] :: DependencyInfo -> [String]
+ Hpack.Config: [dependencyInfoVersion] :: DependencyInfo -> DependencyVersion
+ Hpack.Config: data DependencyInfo
- Hpack: Options :: DecodeOptions -> Force -> Bool -> Options
+ Hpack: Options :: DecodeOptions -> Force -> GenerateHashStrategy -> Bool -> Options

Files

hpack.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 55dc38c5a69ab1a5dc744c1e8322a562cf343c8f4f84380100024f10784994b6+-- hash: 3543542c356a8147c78f7d1b3e633d834653cf0d5132754f0751b712e275cc88  name:           hpack-version:        0.33.0.1+version:        0.33.1 synopsis:       A modern 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 ViewPatterns #-} {-# LANGUAGE RecordWildCards #-} module Hpack ( -- | /__NOTE:__/ This module is exposed to allow integration of Hpack into@@ -32,10 +33,12 @@ , Verbose(..) , Options(..) , Force(..)+, GenerateHashStrategy(..)  #ifdef TEST , hpackResultWithVersion , header+, renderCabalFile #endif ) where @@ -47,8 +50,9 @@ import           System.Exit import           System.IO (stderr) import           Data.Aeson (Value)+import           Data.Maybe -import           Paths_hpack ()+import           Paths_hpack (version) import           Hpack.Options import           Hpack.Config import           Hpack.Render@@ -56,34 +60,35 @@ import           Hpack.Utf8 as Utf8 import           Hpack.CabalFile -version :: Version-version = makeVersion [0,33,0]--programVersion :: Version -> String-programVersion v = "hpack version " ++ Version.showVersion v+programVersion :: Maybe Version -> String+programVersion Nothing = "hpack"+programVersion (Just v) = "hpack version " ++ Version.showVersion v -header :: FilePath -> Version -> Hash -> String-header p v hash = unlines [+header :: FilePath -> Maybe Version -> (Maybe Hash) -> [String]+header p v hash = [     "-- This file has been generated from " ++ takeFileName p ++ " by " ++ programVersion v ++ "."   , "--"   , "-- see: https://github.com/sol/hpack"-  , "--"-  , "-- hash: " ++ hash-  , ""-  ]+  ] ++ case hash of+    Just h -> ["--" , "-- hash: " ++ h, ""]+    Nothing -> [""]  data Options = Options {   optionsDecodeOptions :: DecodeOptions , optionsForce :: Force+, optionsGenerateHashStrategy :: GenerateHashStrategy , optionsToStdout :: Bool } +data GenerateHashStrategy = ForceHash | ForceNoHash | PreferHash | PreferNoHash+  deriving (Eq, Show)+ getOptions :: FilePath -> [String] -> IO (Maybe (Verbose, Options)) getOptions defaultPackageConfig args = do   result <- parseOptions defaultPackageConfig args   case result of     PrintVersion -> do-      putStrLn (programVersion version)+      putStrLn (programVersion $ Just version)       return Nothing     PrintNumericVersion -> do       putStrLn (Version.showVersion version)@@ -91,9 +96,12 @@     Help -> do       printHelp       return Nothing-    Run options -> case options of-      ParseOptions verbose force toStdout file -> do-        return $ Just (verbose, Options defaultDecodeOptions {decodeOptionsTarget = file} force toStdout)+    Run (ParseOptions verbose force hash toStdout file) -> do+      let generateHash = case hash of+            Just True -> ForceHash+            Just False -> ForceNoHash+            Nothing -> PreferHash+      return $ Just (verbose, Options defaultDecodeOptions {decodeOptionsTarget = file} force generateHash toStdout)     ParseError -> do       printHelp       exitFailure@@ -102,7 +110,7 @@ printHelp = do   name <- getProgName   Utf8.hPutStrLn stderr $ unlines [-      "Usage: " ++ name ++ " [ --silent ] [ --force | -f ] [ PATH ] [ - ]"+      "Usage: " ++ name ++ " [ --silent ] [ --force | -f ] [ --[no-]hash ] [ PATH ] [ - ]"     , "       " ++ name ++ " --version"     , "       " ++ name ++ " --numeric-version"     , "       " ++ name ++ " --help"@@ -112,7 +120,7 @@ hpack verbose options = hpackResult options >>= printResult verbose  defaultOptions :: Options-defaultOptions = Options defaultDecodeOptions NoForce False+defaultOptions = Options defaultDecodeOptions NoForce PreferHash False  setTarget :: FilePath -> Options -> Options setTarget target options@Options{..} =@@ -157,41 +165,76 @@ printWarnings :: [String] -> IO () printWarnings = mapM_ $ Utf8.hPutStrLn stderr . ("WARNING: " ++) -mkStatus :: [String] -> Version -> CabalFile -> Status-mkStatus new v (CabalFile mOldVersion mHash old) = case (mOldVersion, mHash) of-  (_, _) | old == new -> OutputUnchanged-  (Nothing, _) -> ExistingCabalFileWasModifiedManually-  (Just oldVersion, _) | oldVersion < makeVersion [0, 20, 0] -> Generated-  (_, Nothing) -> ExistingCabalFileWasModifiedManually-  (Just oldVersion, Just hash)-    | v < oldVersion -> AlreadyGeneratedByNewerHpack-    | sha256 (unlines old) /= hash -> ExistingCabalFileWasModifiedManually-    | otherwise -> Generated+mkStatus :: CabalFile -> CabalFile -> Status+mkStatus new@(CabalFile _ mNewVersion mNewHash _) existing@(CabalFile _ mExistingVersion _ _)+  | new `hasSameContent` existing = OutputUnchanged+  | otherwise = case mExistingVersion of+      Nothing -> ExistingCabalFileWasModifiedManually+      Just _+        | mNewVersion < mExistingVersion -> AlreadyGeneratedByNewerHpack+        | isJust mNewHash && hashMismatch existing -> ExistingCabalFileWasModifiedManually+        | otherwise -> Generated +hasSameContent :: CabalFile -> CabalFile -> Bool+hasSameContent (CabalFile cabalVersionA _ _ a) (CabalFile cabalVersionB _ _ b) = cabalVersionA == cabalVersionB && a == b++hashMismatch :: CabalFile -> Bool+hashMismatch cabalFile = case cabalFileHash cabalFile of+  Nothing -> False+  Just hash -> hash /= calculateHash cabalFile++calculateHash :: CabalFile -> Hash+calculateHash (CabalFile cabalVersion _ _ body) = sha256 (unlines $ cabalVersion ++ body)+ hpackResult :: Options -> IO Result hpackResult = hpackResultWithVersion version  hpackResultWithVersion :: Version -> Options -> IO Result-hpackResultWithVersion v (Options options force toStdout) = do-  DecodeResult pkg cabalVersion cabalFile warnings <- readPackageConfig options >>= either die return-  oldCabalFile <- readCabalFile cabalFile-  let-    body = renderPackage (maybe [] cabalFileContents oldCabalFile) pkg-    withoutHeader = cabalVersion ++ body+hpackResultWithVersion v (Options options force generateHashStrategy toStdout) = do+  DecodeResult pkg (lines -> cabalVersion) cabalFileName warnings <- readPackageConfig options >>= either die return+  mExistingCabalFile <- readCabalFile cabalFileName   let+    newCabalFile = makeCabalFile generateHashStrategy mExistingCabalFile cabalVersion v pkg+     status = case force of       Force -> Generated-      NoForce -> maybe Generated (mkStatus (lines withoutHeader) v) oldCabalFile+      NoForce -> maybe Generated (mkStatus newCabalFile) mExistingCabalFile+   case status of-    Generated -> do-      let hash = sha256 withoutHeader-          out  = cabalVersion ++ header (decodeOptionsTarget options) v hash ++ body-      if toStdout-        then Utf8.putStr out-        else Utf8.writeFile cabalFile out+    Generated -> writeCabalFile options toStdout cabalFileName newCabalFile     _ -> return ()+   return Result {-      resultWarnings = warnings-    , resultCabalFile = cabalFile-    , resultStatus = status-    }+    resultWarnings = warnings+  , resultCabalFile = cabalFileName+  , resultStatus = status+  }++writeCabalFile :: DecodeOptions -> Bool -> FilePath -> CabalFile -> IO ()+writeCabalFile options toStdout name cabalFile = do+  write . unlines $ renderCabalFile (decodeOptionsTarget options) cabalFile+  where+    write = if toStdout then Utf8.putStr else Utf8.writeFile name++makeCabalFile :: GenerateHashStrategy -> Maybe CabalFile -> [String] -> Version -> Package -> CabalFile+makeCabalFile strategy mExistingCabalFile cabalVersion v pkg = cabalFile+  where+    cabalFile = CabalFile cabalVersion (Just v) hash body++    hash+      | shouldGenerateHash mExistingCabalFile strategy = Just $ calculateHash cabalFile+      | otherwise = Nothing++    body = lines $ renderPackage (maybe [] cabalFileContents mExistingCabalFile) pkg++shouldGenerateHash :: Maybe CabalFile -> GenerateHashStrategy -> Bool+shouldGenerateHash mExistingCabalFile strategy = case (strategy, mExistingCabalFile) of+  (ForceHash, _) -> True+  (ForceNoHash, _) -> False+  (PreferHash, Nothing) -> True+  (PreferNoHash, Nothing) -> False+  (_, Just CabalFile {cabalFileHash = Nothing}) -> False+  (_, Just CabalFile {cabalFileHash = Just _}) -> True++renderCabalFile :: FilePath -> CabalFile -> [String]+renderCabalFile file (CabalFile cabalVersion hpackVersion hash body) = cabalVersion ++ header file hpackVersion hash ++ body
src/Hpack/CabalFile.hs view
@@ -16,7 +16,8 @@ makeVersion v = Version v []  data CabalFile = CabalFile {-  cabalFileHpackVersion :: Maybe Version+  cabalFileCabalVersion :: [String]+, cabalFileHpackVersion :: Maybe Version , cabalFileHash :: Maybe Hash , cabalFileContents :: [String] } deriving (Eq, Show)@@ -25,13 +26,13 @@ readCabalFile cabalFile = fmap parse <$> tryReadFile cabalFile   where     parse :: String -> CabalFile-    parse (splitHeader -> (h, c)) = CabalFile (extractVersion h) (extractHash h) c+    parse (splitHeader -> (cabalVersion, h, c)) = CabalFile cabalVersion (extractVersion h) (extractHash h) c -    splitHeader :: String -> ([String], [String])+    splitHeader :: String -> ([String], [String], [String])     splitHeader (removeGitConflictMarkers . lines -> c) =       case span (not . isComment) c of         (cabalVersion, xs) -> case span isComment xs of-          (header, body) -> (header, cabalVersion ++ dropWhile null body)+          (header, body) -> (cabalVersion, header, dropWhile null body)      isComment = ("--" `isPrefixOf`) 
src/Hpack/Config.hs view
@@ -39,6 +39,7 @@ , section , Package(..) , Dependencies(..)+, DependencyInfo(..) , VersionConstraint(..) , DependencyVersion(..) , SourceDependency(..)
src/Hpack/Options.hs view
@@ -1,6 +1,9 @@ {-# LANGUAGE LambdaCase #-} module Hpack.Options where +import           Control.Applicative+import           Control.Monad+import           Data.Maybe import           System.FilePath import           System.Directory @@ -16,6 +19,7 @@ data ParseOptions = ParseOptions {   parseOptionsVerbose :: Verbose , parseOptionsForce :: Force+, parseOptionsHash :: Maybe Bool , parseOptionsToStdout :: Bool , parseOptionsTarget :: FilePath } deriving (Eq, Show)@@ -30,18 +34,30 @@       file <- expandTarget defaultTarget target       let         options-          | toStdout = ParseOptions NoVerbose Force toStdout file-          | otherwise = ParseOptions verbose force toStdout file+          | toStdout = ParseOptions NoVerbose Force hash toStdout file+          | otherwise = ParseOptions verbose force hash toStdout file       return (Run options)     Left err -> return err     where       silentFlag = "--silent"       forceFlags = ["--force", "-f"]+      hashFlag = "--hash"+      noHashFlag = "--no-hash" -      flags = silentFlag : forceFlags+      flags = hashFlag : noHashFlag : silentFlag : forceFlags +      verbose :: Verbose       verbose = if silentFlag `elem` args then NoVerbose else Verbose++      force :: Force       force = if any (`elem` args) forceFlags then Force else NoForce++      hash :: Maybe Bool+      hash = listToMaybe . reverse $ mapMaybe parse args+        where+          parse :: String -> Maybe Bool+          parse t = True <$ guard (t == hashFlag) <|> False <$ guard (t == noHashFlag)+       ys = filter (`notElem` flags) args        targets :: Either ParseResult (Maybe FilePath, Bool)
src/Hpack/Render.hs view
@@ -45,7 +45,6 @@ import           Hpack.Config import           Hpack.Render.Hints import           Hpack.Render.Dsl-import           Hpack.Syntax.Dependencies  renderPackage :: [String] -> Package -> String renderPackage oldCabalFile = renderPackageWith settings alignment formattingHintsFieldOrder formattingHintsSectionsFieldOrder
test/Hpack/CabalFileSpec.hs view
@@ -9,9 +9,15 @@  import           Paths_hpack (version) +import           Hpack.Util (Hash)+import           Data.Version (Version) import           Hpack (header)+ import           Hpack.CabalFile +mkHeader :: FilePath -> Version -> Hash -> String+mkHeader p v hash = unlines $ header p (Just v) (Just hash)+ spec :: Spec spec = do   describe "readCabalFile" $ do@@ -21,13 +27,13 @@      it "includes hash" $ do       inTempDirectory $ do-        writeFile file $ header "package.yaml" version hash-        readCabalFile file `shouldReturn` Just (CabalFile (Just version) (Just hash) [])+        writeFile file $ mkHeader "package.yaml" version hash+        readCabalFile file `shouldReturn` Just (CabalFile [] (Just version) (Just hash) [])      it "accepts cabal-version at the beginning of the file" $ do       inTempDirectory $ do-        writeFile file $ ("cabal-version: 2.2\n" ++ header "package.yaml" version hash)-        readCabalFile file `shouldReturn` Just (CabalFile (Just version) (Just hash) ["cabal-version: 2.2"])+        writeFile file $ ("cabal-version: 2.2\n" ++ mkHeader "package.yaml" version hash)+        readCabalFile file `shouldReturn` Just (CabalFile ["cabal-version: 2.2"] (Just version) (Just hash) [])    describe "extractVersion" $ do     it "extracts Hpack version from a cabal file" $ do
test/Hpack/OptionsSpec.hs view
@@ -18,10 +18,10 @@      context "by default" $ do       it "returns Run" $ do-        parseOptions defaultTarget [] `shouldReturn` Run (ParseOptions Verbose NoForce False defaultTarget)+        parseOptions defaultTarget [] `shouldReturn` Run (ParseOptions Verbose NoForce Nothing False defaultTarget)        it "includes target" $ do-        parseOptions defaultTarget ["foo.yaml"] `shouldReturn` Run (ParseOptions Verbose NoForce False "foo.yaml")+        parseOptions defaultTarget ["foo.yaml"] `shouldReturn` Run (ParseOptions Verbose NoForce Nothing False "foo.yaml")        context "with superfluous arguments" $ do         it "returns ParseError" $ do@@ -29,19 +29,31 @@        context "with --silent" $ do         it "sets optionsVerbose to NoVerbose" $ do-          parseOptions defaultTarget ["--silent"] `shouldReturn` Run (ParseOptions NoVerbose NoForce False defaultTarget)+          parseOptions defaultTarget ["--silent"] `shouldReturn` Run (ParseOptions NoVerbose NoForce Nothing False defaultTarget)        context "with --force" $ do         it "sets optionsForce to Force" $ do-          parseOptions defaultTarget ["--force"] `shouldReturn` Run (ParseOptions Verbose Force False defaultTarget)+          parseOptions defaultTarget ["--force"] `shouldReturn` Run (ParseOptions Verbose Force Nothing False defaultTarget)        context "with -f" $ do         it "sets optionsForce to Force" $ do-          parseOptions defaultTarget ["-f"] `shouldReturn` Run (ParseOptions Verbose Force False defaultTarget)+          parseOptions defaultTarget ["-f"] `shouldReturn` Run (ParseOptions Verbose Force Nothing False defaultTarget) +      context "when determining parseOptionsHash" $ do++        it "assumes True on --hash" $ do+          parseOptions defaultTarget ["--hash"] `shouldReturn` Run (ParseOptions Verbose NoForce (Just True) False defaultTarget)++        it "assumes False on --no-hash" $ do+          parseOptions defaultTarget ["--no-hash"] `shouldReturn` Run (ParseOptions Verbose NoForce (Just False) False defaultTarget)++        it "gives last occurrence precedence" $ do+          parseOptions defaultTarget ["--no-hash", "--hash"] `shouldReturn` Run (ParseOptions Verbose NoForce (Just True) False defaultTarget)+          parseOptions defaultTarget ["--hash", "--no-hash"] `shouldReturn` Run (ParseOptions Verbose NoForce (Just False) False defaultTarget)+       context "with -" $ do         it "sets optionsToStdout to True, implies Force and NoVerbose" $ do-          parseOptions defaultTarget ["-"] `shouldReturn` Run (ParseOptions NoVerbose Force True defaultTarget)+          parseOptions defaultTarget ["-"] `shouldReturn` Run (ParseOptions NoVerbose Force Nothing True defaultTarget)          it "rejects - for target" $ do           parseOptions defaultTarget ["-", "-"] `shouldReturn` ParseError
test/Hpack/RenderSpec.hs view
@@ -10,7 +10,6 @@ import           Hpack.Config hiding (package) import           Hpack.Render.Dsl import           Hpack.Render-import           Hpack.Syntax.Dependencies  library :: Library library = Library Nothing [] [] [] [] []
test/HpackSpec.hs view
@@ -6,7 +6,6 @@ import qualified Prelude as Prelude  import           Control.DeepSeq-import           Data.List  import           Hpack.Config import           Hpack.CabalFile@@ -17,94 +16,139 @@  spec :: Spec spec = do-  describe "hpackResult" $ do-    context "with existing cabal file" $ around_ inTempDirectory $ before_ (writeFile packageConfig "name: foo") $ do-      let-        file = "foo.cabal"+  describe "header" $ do+    it "generates header" $ do+      header "foo.yaml" Nothing Nothing `shouldBe` [+          "-- This file has been generated from foo.yaml by hpack."+        , "--"+        , "-- see: https://github.com/sol/hpack"+        , ""+        ] -        hpackWithVersion v = hpackResultWithVersion v defaultOptions-        hpack = hpackResult defaultOptions-        hpackForce = hpackResult defaultOptions {optionsForce = Force}+    context "with hpack version" $ do+      it "includes hpack version" $ do+        header "foo.yaml" (Just $ makeVersion [0,34,0]) Nothing `shouldBe` [+            "-- This file has been generated from foo.yaml by hpack version 0.34.0."+          , "--"+          , "-- see: https://github.com/sol/hpack"+          , ""+          ] -        generated = Result [] file Generated-        modifiedManually = Result [] file ExistingCabalFileWasModifiedManually-        outputUnchanged = Result [] file OutputUnchanged-        alreadyGeneratedByNewerHpack = Result [] file AlreadyGeneratedByNewerHpack+    context "with hash" $ do+      it "includes hash" $ do+        header "foo.yaml" Nothing (Just "some-hash") `shouldBe` [+            "-- This file has been generated from foo.yaml by hpack."+          , "--"+          , "-- see: https://github.com/sol/hpack"+          , "--"+          , "-- hash: some-hash"+          , ""+          ] -      context "when cabal file was created manually" $ do-        it "does not overwrite existing cabal file" $ do-          let existing = "some existing cabal file"-          writeFile file existing-          hpack `shouldReturn` modifiedManually+  describe "renderCabalFile" $ do+    it "is inverse to readCabalFile" $ do+      expected <- lines <$> readFile "hpack.cabal"+      Just c <- readCabalFile "hpack.cabal"+      renderCabalFile "package.yaml" c `shouldBe` expected++  describe "hpackResult" $ around_ inTempDirectory $ before_ (writeFile packageConfig "name: foo") $ do+    let+      file = "foo.cabal"++      hpackWithVersion v = hpackResultWithVersion (makeVersion v) defaultOptions+      hpackWithStrategy strategy = hpackResult defaultOptions { optionsGenerateHashStrategy = strategy }+      hpackForce = hpackResult defaultOptions {optionsForce = Force}++      generated = Result [] file Generated+      modifiedManually = Result [] file ExistingCabalFileWasModifiedManually+      outputUnchanged = Result [] file OutputUnchanged+      alreadyGeneratedByNewerHpack = Result [] file AlreadyGeneratedByNewerHpack++      modifyPackageConfig = writeFile packageConfig $ unlines [+          "name: foo"+        , "version: 0.1.0"+        ]++      modifyCabalFile = do+        xs <- readFile file+        writeFile file $ xs ++ "foo\n"++      manuallyCreateCabalFile = do+        writeFile file "some existing cabal file"++      doesNotGenerateHash :: HasCallStack => GenerateHashStrategy -> Spec+      doesNotGenerateHash strategy = do+        it "does not generate hash" $ do+          hpackWithStrategy strategy `shouldReturn` generated+          readFile file >>= (`shouldNotContain` "hash")++      generatesHash :: HasCallStack => GenerateHashStrategy -> Spec+      generatesHash strategy = do+        it "generates hash" $ do+          hpackWithStrategy strategy `shouldReturn` generated+          readFile file >>= (`shouldContain` "hash")++      doesNotOverwrite :: HasCallStack => GenerateHashStrategy -> Spec+      doesNotOverwrite strategy = do+        it "does not overwrite cabal file" $ do+          existing <- readFile file+          hpackWithStrategy strategy `shouldReturn` modifiedManually           readFile file `shouldReturn` existing -        context "with --force" $ do-          it "overwrites existing cabal file" $ do-            _ <- hpack-            expected <- readFile file-            writeFile file "some existing cabal file"-            hpackForce `shouldReturn` generated-            readFile file `shouldReturn` expected+      with strategy item = context ("with " ++ show strategy) $ item strategy -      context "when cabal file was created with hpack < 0.20.0" $ do-        it "overwrites existing cabal file" $ do-          _ <- hpack-          expected <- readFile file-          writeFile file "-- This file has been generated from package.yaml by hpack version 0.19.3."-          hpack `shouldReturn` generated-          readFile file `shouldReturn` expected+    context "without an existing cabal file" $ do+      with ForceHash generatesHash+      with PreferHash generatesHash+      with ForceNoHash doesNotGenerateHash+      with PreferNoHash doesNotGenerateHash -      context "when cabal file was created with hpack >= 0.20.0" $ do-        context "when hash is missing" $ do-          it "does not overwrite existing cabal file" $ do-            let existing = "-- This file has been generated from package.yaml by hpack version 0.20.0."-            writeFile file existing-            hpack `shouldReturn` modifiedManually-            readFile file `shouldReturn` existing+    context "with an existing cabal file" $ do+      context "without a hash" $ before_ (hpackWithStrategy ForceNoHash >> modifyPackageConfig) $ do+        with ForceHash generatesHash+        with PreferHash doesNotGenerateHash+        with ForceNoHash doesNotGenerateHash+        with PreferNoHash doesNotGenerateHash -          context "when only the the cabal file header changed" $ do-            it "does not complain if it's newer" $ do-              hpack `shouldReturn` generated-              let removeHash = unlines . filter (not . isInfixOf "hash") . lines-              readFile file >>= writeFile file . removeHash-              hpack `shouldReturn` outputUnchanged+      context "with a hash" $ before_ (hpackWithStrategy ForceHash >> modifyPackageConfig) $ do+        with ForceHash generatesHash+        with PreferHash generatesHash+        with ForceNoHash doesNotGenerateHash+        with PreferNoHash generatesHash -        context "when hash is present" $ do-          context "when exsting cabal file was generated with a newer version of hpack" $ do-            it "does not overwrite existing cabal file" $ do-              writeFile packageConfig $ unlines [-                  "name: foo"-                , "version: 0.1.0"-                ]-              _ <- hpackWithVersion (makeVersion [0,22,0])-              old <- readFile file+        context "with manual modifications" $ before_ modifyCabalFile $ do+          with ForceHash doesNotOverwrite+          with PreferHash doesNotOverwrite+          with ForceNoHash doesNotGenerateHash+          with PreferNoHash doesNotOverwrite -              writeFile packageConfig $ unlines [-                  "name: foo"-                , "version: 0.2.0"-                ]+      context "when created manually" $ before_ manuallyCreateCabalFile $ do+        with ForceHash doesNotOverwrite+        with PreferHash doesNotOverwrite+        with ForceNoHash doesNotOverwrite+        with PreferNoHash doesNotOverwrite -              hpackWithVersion (makeVersion [0,20,0]) `shouldReturn` alreadyGeneratedByNewerHpack-              readFile file `shouldReturn` old+        context "with --force" $ do+          it "overwrites cabal file" $ do+            hpackForce `shouldReturn` generated -          context "when cabal file was modified manually" $ do-            it "does not overwrite existing cabal file" $ do-              _ <- hpack-              old <- readFile file-              let modified = old ++ "foo\n"-              writeFile file modified-              _ <- hpack-              readFile file `shouldReturn` modified+      context "when generated with a newer version of hpack" $ do+        it "does not overwrite cabal file" $ do+          _ <- hpackWithVersion [0,22,0]+          old <- readFile file+          modifyPackageConfig+          hpackWithVersion [0,20,0] `shouldReturn` alreadyGeneratedByNewerHpack+          readFile file `shouldReturn` old -          context "when only the hpack version in the cabal file header changed" $ do-            it "does not overwrite existing cabal file" $ do-              _ <- hpackWithVersion (makeVersion [0,20,0])-              old <- readFile file-              hpack `shouldReturn` outputUnchanged-              readFile file `shouldReturn` old+      context "when only the hpack version in the cabal file header changed" $ do+        it "does not overwrite cabal file" $ do+          _ <- hpackWithVersion [0,22,0]+          old <- readFile file+          hpackWithVersion [0,30,0] `shouldReturn` outputUnchanged+          readFile file `shouldReturn` old -            it "does not complain if it's newer" $ do-              _ <- hpackWithVersion (makeVersion [999,999,0])-              old <- readFile file-              hpack `shouldReturn` outputUnchanged-              readFile file `shouldReturn` old+        it "does not complain if it's newer" $ do+          _ <- hpackWithVersion [0,22,0]+          old <- readFile file+          hpackWithVersion [0,20,0] `shouldReturn` outputUnchanged+          readFile file `shouldReturn` old