Hello community,

here is the log from the commit of package ghc-hackage-security for 
openSUSE:Factory checked in at 2016-07-21 08:12:16
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ghc-hackage-security (Old)
 and      /work/SRC/openSUSE:Factory/.ghc-hackage-security.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "ghc-hackage-security"

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/ghc-hackage-security/ghc-hackage-security.changes    
    2016-06-07 23:47:25.000000000 +0200
+++ 
/work/SRC/openSUSE:Factory/.ghc-hackage-security.new/ghc-hackage-security.changes
   2016-07-21 08:12:21.000000000 +0200
@@ -1,0 +2,5 @@
+Sun Jul 10 17:19:31 UTC 2016 - [email protected]
+
+- Update to version 0.5.2.1 revision 0 with cabal2obs.
+
+-------------------------------------------------------------------

Old:
----
  hackage-security-0.5.1.0.tar.gz

New:
----
  hackage-security-0.5.2.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ ghc-hackage-security.spec ++++++
--- /var/tmp/diff_new_pack.2adW7J/_old  2016-07-21 08:12:23.000000000 +0200
+++ /var/tmp/diff_new_pack.2adW7J/_new  2016-07-21 08:12:23.000000000 +0200
@@ -15,23 +15,18 @@
 # Please submit bugfixes or comments via http://bugs.opensuse.org/
 #
 
-%global pkg_name hackage-security
 
+%global pkg_name hackage-security
 %bcond_with tests
-
 Name:           ghc-%{pkg_name}
-Version:        0.5.1.0
+Version:        0.5.2.1
 Release:        0
 Summary:        Hackage security library
-Group:          System/Libraries
-
 License:        BSD-3-Clause
+Group:          System/Libraries
 Url:            https://hackage.haskell.org/package/%{pkg_name}
 Source0:        
https://hackage.haskell.org/package/%{pkg_name}-%{version}/%{pkg_name}-%{version}.tar.gz
-BuildRoot:      %{_tmppath}/%{name}-%{version}-build
-
 BuildRequires:  ghc-Cabal-devel
-BuildRequires:  ghc-rpm-macros
 # Begin cabal-rpm deps:
 BuildRequires:  ghc-base16-bytestring-devel
 BuildRequires:  ghc-base64-bytestring-devel
@@ -46,11 +41,13 @@
 BuildRequires:  ghc-network-uri-devel
 BuildRequires:  ghc-parsec-devel
 BuildRequires:  ghc-pretty-devel
+BuildRequires:  ghc-rpm-macros
 BuildRequires:  ghc-tar-devel
 BuildRequires:  ghc-template-haskell-devel
 BuildRequires:  ghc-time-devel
 BuildRequires:  ghc-transformers-devel
 BuildRequires:  ghc-zlib-devel
+BuildRoot:      %{_tmppath}/%{name}-%{version}-build
 %if %{with tests}
 BuildRequires:  ghc-HUnit-devel
 BuildRequires:  ghc-QuickCheck-devel
@@ -78,22 +75,18 @@
 "Hackage.Security.Server" is the main entry point for servers (the typical
 example being 'hackage-server').
 
-This is a beta release.
-
-
 %package devel
 Summary:        Haskell %{pkg_name} library development files
 Group:          Development/Libraries/Other
+Requires:       %{name} = %{version}-%{release}
 Requires:       ghc-compiler = %{ghc_version}
 Requires(post): ghc-compiler = %{ghc_version}
 Requires(postun): ghc-compiler = %{ghc_version}
-Requires:       %{name} = %{version}-%{release}
 
 %description devel
 This package provides the Haskell %{pkg_name} library development
 files.
 
-
 %prep
 %setup -q -n %{pkg_name}-%{version}
 
@@ -108,25 +101,22 @@
 
 %check
 %if %{with tests}
-%cabal test
+%{cabal} test
 %endif
 
 
 %post devel
 %ghc_pkg_recache
 
-
 %postun devel
 %ghc_pkg_recache
 
-
 %files -f %{name}.files
 %defattr(-,root,root,-)
 %doc LICENSE
 
-
 %files devel -f %{name}-devel.files
 %defattr(-,root,root,-)
-
+%doc ChangeLog.md
 
 %changelog

++++++ hackage-security-0.5.1.0.tar.gz -> hackage-security-0.5.2.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hackage-security-0.5.1.0/ChangeLog.md 
new/hackage-security-0.5.2.1/ChangeLog.md
--- old/hackage-security-0.5.1.0/ChangeLog.md   2016-04-23 05:48:47.000000000 
+0200
+++ new/hackage-security-0.5.2.1/ChangeLog.md   2016-06-07 23:44:49.000000000 
+0200
@@ -1,3 +1,20 @@
+0.5.2.1
+-------
+
+* Fix accidental breakage with GHC 8
+
+0.5.2.0
+-------
+
+* Change path handling to work on Windows (#162).
+* Add new MD5 hash type (#163). This is not for security (only SHA256 is
+  used for verification) but to provide as metadata to help with other
+  services like mirroring (e.g. HTTP & S3 use MD5 checksum headers).
+* Adjust reading of JSON maps to ignore unknown keys. This allows adding
+  e.g. new hash types in future without breaking existing clients.
+* Fix build warnings on GHC 8
+
+
 0.5.1.0
 -------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hackage-security-0.5.1.0/hackage-security.cabal 
new/hackage-security-0.5.2.1/hackage-security.cabal
--- old/hackage-security-0.5.1.0/hackage-security.cabal 2016-04-23 
05:48:47.000000000 +0200
+++ new/hackage-security-0.5.2.1/hackage-security.cabal 2016-06-07 
23:44:49.000000000 +0200
@@ -1,5 +1,5 @@
 name:                hackage-security
-version:             0.5.1.0
+version:             0.5.2.1
 synopsis:            Hackage security library
 description:         The hackage security library provides both server and
                      client utilities for securing the Hackage package server
@@ -18,13 +18,11 @@
                      clients (the typical example being @cabal@), and
                      "Hackage.Security.Server" is the main entry point for
                      servers (the typical example being @hackage-server@).
-                     .
-                     This is a beta release.
 license:             BSD3
 license-file:        LICENSE
 author:              Edsko de Vries
 maintainer:          [email protected]
-copyright:           Copyright 2015 Well-Typed LLP
+copyright:           Copyright 2015-2016 Well-Typed LLP
 category:            Distribution
 homepage:            https://github.com/well-typed/hackage-security
 bug-reports:         https://github.com/well-typed/hackage-security/issues
@@ -214,9 +212,11 @@
 test-suite TestSuite
   type:                exitcode-stdio-1.0
   main-is:             TestSuite.hs
-  other-modules:       TestSuite.InMemCache
+  other-modules:       TestSuite.HttpMem
+                       TestSuite.InMemCache
                        TestSuite.InMemRepo
                        TestSuite.InMemRepository
+                       TestSuite.JSON
                        TestSuite.PrivateKeys
                        TestSuite.Util.StrictMVar
   build-depends:       base,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hackage-security-0.5.1.0/src/Hackage/Security/Client/Repository/Cache.hs 
new/hackage-security-0.5.2.1/src/Hackage/Security/Client/Repository/Cache.hs
--- 
old/hackage-security-0.5.1.0/src/Hackage/Security/Client/Repository/Cache.hs    
    2016-04-23 05:48:47.000000000 +0200
+++ 
new/hackage-security-0.5.2.1/src/Hackage/Security/Client/Repository/Cache.hs    
    2016-06-07 23:44:49.000000000 +0200
@@ -62,7 +62,7 @@
     -- update the uncompressed index incrementally (assuming the local files
     -- have not been corrupted).
     -- NOTE: This assumes we already updated the compressed file.
-    unzipIndex :: typ ~ Binary => IO ()
+    unzipIndex :: IO ()
     unzipIndex = do
         createDirectoryIfMissing True (takeDirectory indexUn)
         shouldTryIncremenal <- cachedIndexProbablyValid
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hackage-security-0.5.1.0/src/Hackage/Security/Client/Repository/Remote.hs 
new/hackage-security-0.5.2.1/src/Hackage/Security/Client/Repository/Remote.hs
--- 
old/hackage-security-0.5.1.0/src/Hackage/Security/Client/Repository/Remote.hs   
    2016-04-23 05:48:47.000000000 +0200
+++ 
new/hackage-security-0.5.2.1/src/Hackage/Security/Client/Repository/Remote.hs   
    2016-06-07 23:44:49.000000000 +0200
@@ -299,24 +299,25 @@
 
 -- | Download method (downloading or updating)
 data DownloadMethod :: * -> * -> * where
-    -- | Download this file (we never attempt to update this type of file)
+    -- Download this file (we never attempt to update this type of file)
     NeverUpdated :: {
         neverUpdatedFormat :: HasFormat fs f
       } -> DownloadMethod fs typ
 
-    -- | Download this file (we cannot update this file right now)
+    -- Download this file (we cannot update this file right now)
     CannotUpdate :: {
         cannotUpdateFormat :: HasFormat fs f
       , cannotUpdateReason :: UpdateFailure
       } -> DownloadMethod fs Binary
 
-    -- | Attempt an (incremental) update of this file
+    -- Attempt an (incremental) update of this file
     Update :: {
         updateFormat :: HasFormat fs f
       , updateInfo   :: Trusted FileInfo
       , updateLocal  :: Path Absolute
       , updateTail   :: Int54
       } -> DownloadMethod fs Binary
+--TODO: ^^ older haddock doesn't support GADT doc comments :-(
 
 pickDownloadMethod :: forall fs typ. RemoteConfig
                    -> AttemptNr
@@ -362,8 +363,7 @@
 getFile cfg@RemoteConfig{..} attemptNr remoteFile method =
     go method
   where
-    go :: Throws SomeRemoteError
-       => DownloadMethod fs typ -> Verify (Some (HasFormat fs), RemoteTemp typ)
+    go :: DownloadMethod fs typ -> Verify (Some (HasFormat fs), RemoteTemp typ)
     go NeverUpdated{..} = do
         cfgLogger $ LogDownloading remoteFile
         download neverUpdatedFormat
@@ -379,8 +379,7 @@
     headers = httpRequestHeaders cfg attemptNr
 
     -- Get any file from the server, without using incremental updates
-    download :: Throws SomeRemoteError => HasFormat fs f
-             -> Verify (Some (HasFormat fs), RemoteTemp typ)
+    download :: HasFormat fs f -> Verify (Some (HasFormat fs), RemoteTemp typ)
     download format = do
         (tempPath, h) <- openTempFile (Cache.cacheRoot cfgCache) (uriTemplate 
uri)
         liftIO $ do
@@ -598,15 +597,16 @@
         wholeTemp :: Path Absolute
       } -> RemoteTemp a
 
-    -- | If we download only the delta, we record both the path to where the
+    -- If we download only the delta, we record both the path to where the
     -- "old" file is stored and the path to the temp file containing the delta.
     -- Then:
     --
-    -- * When we verify the file, we need both of these paths if we compute
+    --   When we verify the file, we need both of these paths if we compute
     --   the hash from scratch, or only the path to the delta if we attempt
     --   to compute the hash incrementally (TODO: incremental verification
     --   not currently implemented).
-    -- * When we copy a file over, we are additionally given a destination
+    --
+    --   When we copy a file over, we are additionally given a destination
     --   path. In this case, we expect that destination path to be equal to
     --   the path to the old file (and assert this to be the case).
     DownloadedDelta :: {
@@ -614,6 +614,8 @@
       , deltaExisting :: Path Absolute
       , deltaSeek     :: Int54       -- ^ How much of the existing file to keep
       } -> RemoteTemp Binary
+--TODO: ^^ older haddock doesn't support GADT doc comments :-(
+--      and add the '*' bullet points back in
 
 instance Pretty (RemoteTemp typ) where
     pretty DownloadedWhole{..} = intercalate " " $ [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hackage-security-0.5.1.0/src/Hackage/Security/Client/Repository.hs 
new/hackage-security-0.5.2.1/src/Hackage/Security/Client/Repository.hs
--- old/hackage-security-0.5.1.0/src/Hackage/Security/Client/Repository.hs      
2016-04-23 05:48:47.000000000 +0200
+++ new/hackage-security-0.5.2.1/src/Hackage/Security/Client/Repository.hs      
2016-06-07 23:44:49.000000000 +0200
@@ -403,17 +403,17 @@
 
 -- | Is a particular remote file cached?
 data IsCached :: * -> * where
-    -- | This remote file should be cached, and we ask for it by name
+    -- This remote file should be cached, and we ask for it by name
     CacheAs :: CachedFile -> IsCached Metadata
 
-    -- | We don't cache this remote file
+    -- We don't cache this remote file
     --
     -- This doesn't mean a Repository should not feel free to cache the file
     -- if desired, but it does mean the generic algorithms will never ask for
     -- this file from the cache.
     DontCache :: IsCached Binary
 
-    -- | The index is somewhat special: it should be cached, but we never
+    -- The index is somewhat special: it should be cached, but we never
     -- ask for it directly.
     --
     -- Instead, we will ask the Repository for files _from_ the index, which it
@@ -422,6 +422,7 @@
     -- keep an index tarball index for quick access, others may scan the 
tarball
     -- linearly, etc.
     CacheIndex :: IsCached Binary
+--TODO: ^^ older haddock doesn't support GADT doc comments :-(
 
 deriving instance Eq   (IsCached typ)
 deriving instance Show (IsCached typ)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hackage-security-0.5.1.0/src/Hackage/Security/Client.hs 
new/hackage-security-0.5.2.1/src/Hackage/Security/Client.hs
--- old/hackage-security-0.5.1.0/src/Hackage/Security/Client.hs 2016-04-23 
05:48:47.000000000 +0200
+++ new/hackage-security-0.5.2.1/src/Hackage/Security/Client.hs 2016-06-07 
23:44:49.000000000 +0200
@@ -110,8 +110,7 @@
     -- root information and start over. However, in order to prevent DoS 
attacks
     -- we limit how often we go round this loop.
     -- See als <https://github.com/theupdateframework/tuf/issues/287>.
-    limitIterations :: (Throws VerificationError, Throws SomeRemoteError)
-                    => VerificationHistory -> IO HasUpdates
+    limitIterations :: VerificationHistory -> IO HasUpdates
     limitIterations history | length history >= maxNumIterations =
         throwChecked $ VerificationErrorLoop (reverse history)
     limitIterations history = do
@@ -802,7 +801,9 @@
         }
   where
     indexPath :: Tar.Entry -> IndexPath
-    indexPath = rootPath . fromUnrootedFilePath . Tar.entryPath
+    indexPath = rootPath . fromUnrootedFilePath
+              . Tar.fromTarPathToPosixPath
+              . Tar.entryTarPath
 
     indexFile :: IndexPath -> Maybe (Some IndexFile)
     indexFile = indexFileFromPath repIndexLayout
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hackage-security-0.5.1.0/src/Hackage/Security/Key.hs 
new/hackage-security-0.5.2.1/src/Hackage/Security/Key.hs
--- old/hackage-security-0.5.1.0/src/Hackage/Security/Key.hs    2016-04-23 
05:48:47.000000000 +0200
+++ new/hackage-security-0.5.2.1/src/Hackage/Security/Key.hs    2016-06-07 
23:44:49.000000000 +0200
@@ -153,7 +153,7 @@
   toObjectKey = return . keyIdString
 
 instance Monad m => FromObjectKey m KeyId where
-  fromObjectKey = return . KeyId
+  fromObjectKey = return . Just . KeyId
 
 -- | Compute the key ID of a key
 class HasKeyId key where
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hackage-security-0.5.1.0/src/Hackage/Security/TUF/FileInfo.hs 
new/hackage-security-0.5.2.1/src/Hackage/Security/TUF/FileInfo.hs
--- old/hackage-security-0.5.1.0/src/Hackage/Security/TUF/FileInfo.hs   
2016-04-23 05:48:47.000000000 +0200
+++ new/hackage-security-0.5.2.1/src/Hackage/Security/TUF/FileInfo.hs   
2016-06-07 23:44:49.000000000 +0200
@@ -29,6 +29,7 @@
 
-------------------------------------------------------------------------------}
 
 data HashFn = HashFnSHA256
+            | HashFnMD5
   deriving (Show, Eq, Ord)
 
 -- | File information
@@ -87,10 +88,12 @@
 
 instance Monad m => ToObjectKey m HashFn where
   toObjectKey HashFnSHA256 = return "sha256"
+  toObjectKey HashFnMD5    = return "md5"
 
 instance ReportSchemaErrors m => FromObjectKey m HashFn where
-  fromObjectKey "sha256" = return HashFnSHA256
-  fromObjectKey str      = expected "valid hash function" (Just str)
+  fromObjectKey "sha256" = return (Just HashFnSHA256)
+  fromObjectKey "md5"    = return (Just HashFnMD5)
+  fromObjectKey _        = return Nothing
 
 instance Monad m => ToJSON m FileInfo where
   toJSON FileInfo{..} = mkObject [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hackage-security-0.5.1.0/src/Hackage/Security/TUF/FileMap.hs 
new/hackage-security-0.5.2.1/src/Hackage/Security/TUF/FileMap.hs
--- old/hackage-security-0.5.1.0/src/Hackage/Security/TUF/FileMap.hs    
2016-04-23 05:48:47.000000000 +0200
+++ new/hackage-security-0.5.2.1/src/Hackage/Security/TUF/FileMap.hs    
2016-06-07 23:44:49.000000000 +0200
@@ -127,8 +127,7 @@
 
 instance ReportSchemaErrors m => FromObjectKey m TargetPath where
   fromObjectKey ('<':'r':'e':'p':'o':'>':'/':path) =
-    return . TargetPathRepo  . rootPath . fromUnrootedFilePath $ path
+    return . Just . TargetPathRepo  . rootPath . fromUnrootedFilePath $ path
   fromObjectKey ('<':'i':'n':'d':'e':'x':'>':'/':path) =
-    return . TargetPathIndex . rootPath . fromUnrootedFilePath $ path
-  fromObjectKey str =
-    expected "target path" (Just str)
+    return . Just . TargetPathIndex . rootPath . fromUnrootedFilePath $ path
+  fromObjectKey _str = return Nothing
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hackage-security-0.5.1.0/src/Hackage/Security/TUF/Layout/Index.hs 
new/hackage-security-0.5.2.1/src/Hackage/Security/TUF/Layout/Index.hs
--- old/hackage-security-0.5.1.0/src/Hackage/Security/TUF/Layout/Index.hs       
2016-04-23 05:48:47.000000000 +0200
+++ new/hackage-security-0.5.2.1/src/Hackage/Security/TUF/Layout/Index.hs       
2016-06-07 23:44:49.000000000 +0200
@@ -9,8 +9,6 @@
   , indexLayoutPkgPrefs
   ) where
 
-import qualified System.FilePath as FP
-
 import Distribution.Package
 import Distribution.Text
 
@@ -45,14 +43,15 @@
 -- the global preferred-versions file. But supporting legacy Hackage will
 -- probably require more work anyway..
 data IndexFile :: * -> * where
-    -- | Package-specific metadata (@targets.json@)
+    -- Package-specific metadata (@targets.json@)
     IndexPkgMetadata :: PackageIdentifier -> IndexFile (Signed Targets)
 
-    -- | Cabal file for a package
+    -- Cabal file for a package
     IndexPkgCabal :: PackageIdentifier -> IndexFile ()
 
-    -- | Preferred versions a package
+    -- Preferred versions a package
     IndexPkgPrefs :: PackageName -> IndexFile ()
+--TODO: ^^ older haddock doesn't support GADT doc comments :-(
 
 deriving instance Show (IndexFile dec)
 
@@ -68,7 +67,7 @@
 hackageIndexLayout :: IndexLayout
 hackageIndexLayout = IndexLayout {
       indexFileToPath   = toPath
-    , indexFileFromPath = fromPath . toUnrootedFilePath . unrootPath
+    , indexFileFromPath = fromPath
     }
   where
     toPath :: IndexFile dec -> IndexPath
@@ -90,16 +89,16 @@
     fromFragments :: [String] -> IndexPath
     fromFragments = rootPath . joinFragments
 
-    fromPath :: FilePath -> Maybe (Some IndexFile)
-    fromPath fp = case FP.splitPath fp of
-      [pkg, version, file] -> do
-        pkgId <- simpleParse (init pkg ++ "-" ++ init version)
-        case FP.takeExtension file of
+    fromPath :: IndexPath -> Maybe (Some IndexFile)
+    fromPath fp = case splitFragments (unrootPath fp) of
+      [pkg, version, _file] -> do
+        pkgId <- simpleParse (pkg ++ "-" ++ version)
+        case takeExtension fp of
           ".cabal"   -> return $ Some $ IndexPkgCabal    pkgId
           ".json"    -> return $ Some $ IndexPkgMetadata pkgId
           _otherwise -> Nothing
       [pkg, "preferred-versions"] ->
-        Some . IndexPkgPrefs <$> simpleParse (init pkg)
+        Some . IndexPkgPrefs <$> simpleParse pkg
       _otherwise -> Nothing
 
 
{-------------------------------------------------------------------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hackage-security-0.5.1.0/src/Hackage/Security/TUF/Paths.hs 
new/hackage-security-0.5.2.1/src/Hackage/Security/TUF/Paths.hs
--- old/hackage-security-0.5.1.0/src/Hackage/Security/TUF/Paths.hs      
2016-04-23 05:48:47.000000000 +0200
+++ new/hackage-security-0.5.2.1/src/Hackage/Security/TUF/Paths.hs      
2016-06-07 23:44:49.000000000 +0200
@@ -37,7 +37,7 @@
 instance Pretty (Path RepoRoot) where
   pretty (Path fp) = "<repo>/" ++ fp
 
-anchorRepoPathLocally :: FsRoot root => Path root -> RepoPath -> Path root
+anchorRepoPathLocally :: Path root -> RepoPath -> Path root
 anchorRepoPathLocally localRoot repoPath = localRoot </> unrootPath repoPath
 
 anchorRepoPathRemotely :: Path Web -> RepoPath -> Path Web
@@ -68,5 +68,5 @@
     pretty (Path fp) = "<cache>/" ++ fp
 
 -- | Anchor a cache path to the location of the cache
-anchorCachePath :: FsRoot root => Path root -> CachePath -> Path root
+anchorCachePath :: Path root -> CachePath -> Path root
 anchorCachePath cacheRoot cachePath = cacheRoot </> unrootPath cachePath
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hackage-security-0.5.1.0/src/Hackage/Security/TUF/Patterns.hs 
new/hackage-security-0.5.2.1/src/Hackage/Security/TUF/Patterns.hs
--- old/hackage-security-0.5.1.0/src/Hackage/Security/TUF/Patterns.hs   
2016-04-23 05:48:47.000000000 +0200
+++ new/hackage-security-0.5.2.1/src/Hackage/Security/TUF/Patterns.hs   
2016-06-07 23:44:49.000000000 +0200
@@ -27,7 +27,7 @@
 
 import Control.Monad.Except
 import Language.Haskell.TH (Q, Exp)
-import System.FilePath
+import System.FilePath.Posix
 import qualified Language.Haskell.TH.Syntax as TH
 
 import Hackage.Security.JSON
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hackage-security-0.5.1.0/src/Hackage/Security/Util/Checked.hs 
new/hackage-security-0.5.2.1/src/Hackage/Security/Util/Checked.hs
--- old/hackage-security-0.5.1.0/src/Hackage/Security/Util/Checked.hs   
2016-04-23 05:48:47.000000000 +0200
+++ new/hackage-security-0.5.2.1/src/Hackage/Security/Util/Checked.hs   
2016-06-07 23:44:49.000000000 +0200
@@ -1,5 +1,8 @@
 {-# LANGUAGE CPP #-}
 {-# OPTIONS_GHC -fno-warn-unused-binds #-}
+#if __GLASGOW_HASKELL__ >= 800
+{-# OPTIONS_GHC -Wno-redundant-constraints #-}
+#endif
 
 #if __GLASGOW_HASKELL__ >= 708
 {-# LANGUAGE RoleAnnotations     #-}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hackage-security-0.5.1.0/src/Hackage/Security/Util/JSON.hs 
new/hackage-security-0.5.2.1/src/Hackage/Security/Util/JSON.hs
--- old/hackage-security-0.5.1.0/src/Hackage/Security/Util/JSON.hs      
2016-04-23 05:48:47.000000000 +0200
+++ new/hackage-security-0.5.2.1/src/Hackage/Security/Util/JSON.hs      
2016-06-07 23:44:49.000000000 +0200
@@ -24,6 +24,7 @@
   ) where
 
 import Control.Monad (liftM)
+import Data.Maybe (catMaybes)
 import Data.Map (Map)
 import Data.Time
 import Text.JSON.Canonical
@@ -54,7 +55,7 @@
 
 -- | Used in the 'FromJSON' instance for 'Map'
 class FromObjectKey m a where
-  fromObjectKey :: String -> m a
+  fromObjectKey :: String -> m (Maybe a)
 
 -- | Monads in which we can report schema errors
 class (Applicative m, Monad m) => ReportSchemaErrors m where
@@ -85,13 +86,13 @@
   toObjectKey = return
 
 instance Monad m => FromObjectKey m String where
-  fromObjectKey = return
+  fromObjectKey = return . Just
 
 instance Monad m => ToObjectKey m (Path root) where
   toObjectKey (Path fp) = return fp
 
 instance Monad m => FromObjectKey m (Path root) where
-  fromObjectKey = liftM Path . fromObjectKey
+  fromObjectKey = liftM (fmap Path) . fromObjectKey
 
 
{-------------------------------------------------------------------------------
   ToJSON and FromJSON instances
@@ -162,10 +163,13 @@
          ) => FromJSON m (Map k a) where
   fromJSON enc = do
       obj <- fromJSObject enc
-      Map.fromList <$> mapM aux obj
+      Map.fromList . catMaybes <$> mapM aux obj
     where
-      aux :: (String, JSValue) -> m (k, a)
-      aux (k, a) = (,) <$> fromObjectKey k <*> fromJSON a
+      aux :: (String, JSValue) -> m (Maybe (k, a))
+      aux (k, a) = knownKeys <$> fromObjectKey k <*> fromJSON a
+      knownKeys :: Maybe k -> a -> Maybe (k, a)
+      knownKeys Nothing  _ = Nothing
+      knownKeys (Just k) a = Just (k, a)
 
 instance Monad m => ToJSON m URI where
   toJSON = toJSON . show
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hackage-security-0.5.1.0/src/Hackage/Security/Util/Path.hs 
new/hackage-security-0.5.2.1/src/Hackage/Security/Util/Path.hs
--- old/hackage-security-0.5.1.0/src/Hackage/Security/Util/Path.hs      
2016-04-23 05:48:47.000000000 +0200
+++ new/hackage-security-0.5.2.1/src/Hackage/Security/Util/Path.hs      
2016-06-07 23:44:49.000000000 +0200
@@ -17,6 +17,7 @@
   , takeFileName
   , (<.>)
   , splitExtension
+  , takeExtension
     -- * Unrooted paths
   , Unrooted
   , (</>)
@@ -26,6 +27,7 @@
   , fromUnrootedFilePath
   , fragment
   , joinFragments
+  , splitFragments
   , isPathPrefixOf
     -- * File-system paths
   , Relative
@@ -92,7 +94,8 @@
 #endif
 import qualified Data.ByteString         as BS
 import qualified Data.ByteString.Lazy    as BS.L
-import qualified System.FilePath         as FP
+import qualified System.FilePath         as FP.Native
+import qualified System.FilePath.Posix   as FP.Posix
 import qualified System.IO               as IO
 import qualified System.Directory        as Dir
 import qualified Codec.Archive.Tar       as Tar
@@ -115,9 +118,21 @@
 -- make sense to append two absolute paths together; instead, we can only 
append
 -- an unrooted path to another path. It also means we avoid bugs where we use
 -- one kind of path where we expect another.
-newtype Path a = Path { unPath :: FilePath }
+newtype Path a = Path FilePath -- always a Posix style path internally
   deriving (Show, Eq, Ord)
 
+mkPathNative :: FilePath -> Path a
+mkPathNative = Path . FP.Posix.joinPath . FP.Native.splitDirectories
+
+unPathNative :: Path a -> FilePath
+unPathNative (Path fp) = FP.Native.joinPath . FP.Posix.splitDirectories $ fp
+
+mkPathPosix :: FilePath -> Path a
+mkPathPosix = Path
+
+unPathPosix :: Path a -> FilePath
+unPathPosix (Path fp) = fp
+
 -- | Reinterpret the root of a path
 --
 -- This literally just changes the type-level tag; use with caution!
@@ -129,18 +144,21 @@
 
-------------------------------------------------------------------------------}
 
 takeDirectory :: Path a -> Path a
-takeDirectory = liftFP FP.takeDirectory
+takeDirectory = liftFP FP.Posix.takeDirectory
 
 takeFileName :: Path a -> String
-takeFileName = liftFromFP FP.takeFileName
+takeFileName = liftFromFP FP.Posix.takeFileName
 
 (<.>) :: Path a -> String -> Path a
-fp <.> ext = liftFP (FP.<.> ext) fp
+fp <.> ext = liftFP (FP.Posix.<.> ext) fp
 
 splitExtension :: Path a -> (Path a, String)
 splitExtension (Path fp) = (Path fp', ext)
   where
-    (fp', ext) = FP.splitExtension fp
+    (fp', ext) = FP.Posix.splitExtension fp
+
+takeExtension :: Path a -> String
+takeExtension (Path fp) = FP.Posix.takeExtension fp
 
 
{-------------------------------------------------------------------------------
   Unrooted paths
@@ -155,7 +173,7 @@
   pretty (Path fp) = fp
 
 (</>) :: Path a -> Path Unrooted -> Path a
-(</>) = liftFP2 (FP.</>)
+(</>) = liftFP2 (FP.Posix.</>)
 
 -- | Reinterpret an unrooted path
 --
@@ -169,18 +187,29 @@
 unrootPath :: Path root -> Path Unrooted
 unrootPath (Path fp) = Path fp
 
+-- | Convert a relative\/unrooted Path to a FilePath (using POSIX style
+-- directory separators).
+--
+-- See also 'toAbsoluteFilePath'
+--
 toUnrootedFilePath :: Path Unrooted -> FilePath
-toUnrootedFilePath = unPath
+toUnrootedFilePath = unPathPosix
 
+-- | Convert from a relative\/unrooted FilePath (using POSIX style directory
+-- separators).
+--
 fromUnrootedFilePath :: FilePath -> Path Unrooted
-fromUnrootedFilePath = Path
+fromUnrootedFilePath = mkPathPosix
 
 -- | A path fragment (like a single directory or filename)
 fragment :: String -> Path Unrooted
-fragment = fromUnrootedFilePath
+fragment = Path
 
 joinFragments :: [String] -> Path Unrooted
-joinFragments = liftToFP FP.joinPath
+joinFragments = liftToFP FP.Posix.joinPath
+
+splitFragments :: Path Unrooted -> [String]
+splitFragments (Path fp) = FP.Posix.splitDirectories fp
 
 isPathPrefixOf :: Path Unrooted -> Path Unrooted -> Bool
 isPathPrefixOf = liftFromFP2 isPrefixOf
@@ -204,30 +233,34 @@
 
 -- | A file system root can be interpreted as an (absolute) FilePath
 class FsRoot root where
+  -- | Convert a Path to an absolute FilePath (using native style directory 
separators).
+  --
   toAbsoluteFilePath :: Path root -> IO FilePath
 
 instance FsRoot Relative where
-    toAbsoluteFilePath (Path fp) = go fp
+    toAbsoluteFilePath p = go (unPathNative p)
       where
         go :: FilePath -> IO FilePath
 #if MIN_VERSION_directory(1,2,2)
         go = Dir.makeAbsolute
 #else
         -- copied implementation from the directory package
-        go = (FP.normalise <$>) . absolutize
+        go = (FP.Native.normalise <$>) . absolutize
         absolutize path -- avoid the call to `getCurrentDirectory` if we can
-          | FP.isRelative path = (FP.</> path) . FP.addTrailingPathSeparator 
<$>
-                                 Dir.getCurrentDirectory
-          | otherwise          = return path
+          | FP.Native.isRelative path
+                      = (FP.Native.</> path)
+                      . FP.Native.addTrailingPathSeparator <$>
+                        Dir.getCurrentDirectory
+          | otherwise = return path
 #endif
 
 instance FsRoot Absolute where
-    toAbsoluteFilePath (Path fp) = return fp
+    toAbsoluteFilePath = return . unPathNative
 
 instance FsRoot HomeDir where
-    toAbsoluteFilePath (Path fp) = do
+    toAbsoluteFilePath p = do
       home <- Dir.getHomeDirectory
-      return $ home FP.</> fp
+      return $ home FP.Native.</> unPathNative p
 
 -- | Abstract over a file system root
 --
@@ -239,29 +272,29 @@
 
-------------------------------------------------------------------------------}
 
 toFilePath :: Path Absolute -> FilePath
-toFilePath (Path fp) = fp
+toFilePath = unPathNative
 
 fromFilePath :: FilePath -> FsPath
 fromFilePath fp
-    | FP.isAbsolute      fp = FsPath (Path fp  :: Path Absolute)
-    | Just fp' <- atHome fp = FsPath (Path fp' :: Path HomeDir)
-    | otherwise             = FsPath (Path fp  :: Path Relative)
+    | FP.Native.isAbsolute fp = FsPath (mkPathNative fp  :: Path Absolute)
+    | Just fp' <- atHome fp   = FsPath (mkPathNative fp' :: Path HomeDir)
+    | otherwise               = FsPath (mkPathNative fp  :: Path Relative)
   where
     -- TODO: I don't know if there a standard way that Windows users refer to
     -- their home directory. For now, we'll only interpret '~'. Everybody else
     -- can specify an absolute path if this doesn't work.
     atHome :: FilePath -> Maybe FilePath
     atHome "~" = Just ""
-    atHome ('~':sep:fp') | FP.isPathSeparator sep = Just fp'
+    atHome ('~':sep:fp') | FP.Native.isPathSeparator sep = Just fp'
     atHome _otherwise = Nothing
 
 makeAbsolute :: FsPath -> IO (Path Absolute)
-makeAbsolute (FsPath p) = Path <$> toAbsoluteFilePath p
+makeAbsolute (FsPath p) = mkPathNative <$> toAbsoluteFilePath p
 
 fromAbsoluteFilePath :: FilePath -> Path Absolute
 fromAbsoluteFilePath fp
-  | FP.isAbsolute fp = Path fp
-  | otherwise        = error "fromAbsoluteFilePath: not an absolute path"
+  | FP.Native.isAbsolute fp = mkPathNative fp
+  | otherwise               = error "fromAbsoluteFilePath: not an absolute 
path"
 
 
{-------------------------------------------------------------------------------
   Wrappers around System.IO
@@ -363,7 +396,7 @@
     fragments <$> Dir.getDirectoryContents filePath
   where
     fragments :: [String] -> [Path Unrooted]
-    fragments = map fromUnrootedFilePath . filter (not . skip)
+    fragments = map fragment . filter (not . skip)
 
     skip :: String -> Bool
     skip "."  = True
@@ -389,7 +422,7 @@
                        else return [path]
 
     emptyPath :: Path Unrooted
-    emptyPath = Path (FP.joinPath [])
+    emptyPath = joinFragments []
 
 renameFile :: (FsRoot root, FsRoot root')
            => Path root  -- ^ Old
@@ -431,7 +464,7 @@
     Tar.append tarFile' baseDir' contents'
   where
     contents' :: [FilePath]
-    contents' = map (toUnrootedFilePath . unrootPath) contents
+    contents' = map (unPathNative . unrootPath) contents
 
 
{-------------------------------------------------------------------------------
   Wrappers around Network.URI
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hackage-security-0.5.1.0/tests/TestSuite/HttpMem.hs 
new/hackage-security-0.5.2.1/tests/TestSuite/HttpMem.hs
--- old/hackage-security-0.5.1.0/tests/TestSuite/HttpMem.hs     1970-01-01 
01:00:00.000000000 +0100
+++ new/hackage-security-0.5.2.1/tests/TestSuite/HttpMem.hs     2016-06-07 
23:44:49.000000000 +0200
@@ -0,0 +1,70 @@
+-- | HttpLib bridge to the in-memory repository
+module TestSuite.HttpMem (
+    httpMem
+  ) where
+
+-- stdlib
+import Network.URI (URI)
+import qualified Data.ByteString.Lazy as BS.L
+
+-- hackage-security
+import Hackage.Security.Client
+import Hackage.Security.Client.Repository.HttpLib
+import Hackage.Security.Util.Checked
+import Hackage.Security.Util.Path
+import Hackage.Security.Util.Some
+
+-- TestSuite
+import TestSuite.InMemRepo
+
+httpMem :: InMemRepo -> HttpLib
+httpMem inMemRepo = HttpLib {
+      httpGet      = get      inMemRepo
+    , httpGetRange = getRange inMemRepo
+    }
+
+{-------------------------------------------------------------------------------
+  Individual methods
+-------------------------------------------------------------------------------}
+
+-- | Download a file
+--
+-- Since we don't (yet?) make any attempt to simulate a cache, we ignore
+-- caching headers.
+get :: forall a. Throws SomeRemoteError
+    => InMemRepo
+    -> [HttpRequestHeader]
+    -> URI
+    -> ([HttpResponseHeader] -> BodyReader -> IO a)
+    -> IO a
+get InMemRepo{..} _requestHeaders uri callback = do
+    Some inMemFile <- inMemRepoGetPath $ castRoot (uriPath uri)
+    br <- bodyReaderFromBS $ inMemFileRender inMemFile
+    callback [HttpResponseAcceptRangesBytes] br
+
+-- | Download a byte range
+--
+-- Range is starting and (exclusive) end offset in bytes.
+--
+-- We ignore requests for compression; different servers deal with compression
+-- for byte range requests differently; in particular, Apache returns the range
+-- of the _compressed_ file, which is pretty useless for our purposes. For now
+-- we ignore this issue completely here.
+getRange :: forall a. Throws SomeRemoteError
+         => InMemRepo
+         -> [HttpRequestHeader]
+         -> URI
+         -> (Int, Int)
+         -> (HttpStatus -> [HttpResponseHeader] -> BodyReader -> IO a)
+         -> IO a
+getRange InMemRepo{..} _requestHeaders uri (fr, to) callback = do
+    Some inMemFile <- inMemRepoGetPath $ castRoot (uriPath uri)
+    br <- bodyReaderFromBS $ substr (inMemFileRender inMemFile)
+
+    let responseHeaders = concat [
+            [ HttpResponseAcceptRangesBytes ]
+          ]
+    callback HttpStatus206PartialContent responseHeaders br
+  where
+    substr :: BS.L.ByteString -> BS.L.ByteString
+    substr = BS.L.take (fromIntegral (to - fr)) . BS.L.drop (fromIntegral fr)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hackage-security-0.5.1.0/tests/TestSuite/InMemCache.hs 
new/hackage-security-0.5.2.1/tests/TestSuite/InMemCache.hs
--- old/hackage-security-0.5.1.0/tests/TestSuite/InMemCache.hs  2016-04-23 
05:48:47.000000000 +0200
+++ new/hackage-security-0.5.2.1/tests/TestSuite/InMemCache.hs  2016-06-07 
23:44:49.000000000 +0200
@@ -8,8 +8,13 @@
 import qualified Codec.Compression.GZip as GZip
 import qualified Data.ByteString.Lazy   as BS.L
 
+-- tar
+import qualified Codec.Archive.Tar       as Tar
+import qualified Codec.Archive.Tar.Index as TarIndex
+import           Codec.Archive.Tar.Index   (TarIndex)
+
 -- hackage-security
-import Hackage.Security.Client
+import Hackage.Security.Client hiding (withIndex)
 import Hackage.Security.Client.Formats
 import Hackage.Security.Client.Repository
 import Hackage.Security.JSON
@@ -20,20 +25,25 @@
 import TestSuite.InMemRepo
 
 data InMemCache = InMemCache {
-      inMemCacheGet     :: CachedFile -> IO (Maybe (Path Absolute))
-    , inMemCacheGetRoot :: IO (Path Absolute)
-    , inMemCacheClear   :: IO ()
-    , inMemCachePut     :: forall f typ. InMemFile typ -> Format f -> IsCached 
typ -> IO ()
+      inMemCacheGet         :: CachedFile -> IO (Maybe (Path Absolute))
+    , inMemCacheGetRoot     :: IO (Path Absolute)
+    , inMemCacheWithIndex   :: forall a. (Handle -> IO a) -> IO a
+    , inMemCacheGetIndexIdx :: IO TarIndex
+    , inMemCacheClear       :: IO ()
+    , inMemCachePut         :: forall f typ. InMemFile typ -> Format f
+                                          -> IsCached  typ -> IO ()
     }
 
 newInMemCache :: Path Absolute -> RepoLayout -> IO InMemCache
 newInMemCache tempDir layout = do
     state <- newMVar $ initLocalState layout
     return InMemCache {
-        inMemCacheGet     = get     state tempDir
-      , inMemCacheGetRoot = getRoot state tempDir
-      , inMemCacheClear   = clear   state
-      , inMemCachePut     = put     state
+        inMemCacheGet         = get         state tempDir
+      , inMemCacheGetRoot     = getRoot     state tempDir
+      , inMemCacheWithIndex   = withIndex   state tempDir
+      , inMemCacheGetIndexIdx = getIndexIdx state
+      , inMemCacheClear       = clear       state
+      , inMemCachePut         = put         state
       }
 
 
{-------------------------------------------------------------------------------
@@ -106,6 +116,26 @@
 getRoot state cacheTempDir =
     needRoot `fmap` get state cacheTempDir CachedRoot
 
+withIndex :: MVar LocalState -> Path Absolute -> (Handle -> IO a) -> IO a
+withIndex state cacheTempDir action = do
+    st <- readMVar state
+    case cachedIndex st of
+      Nothing -> error "InMemCache.withIndex: Could not read index."
+      Just bs -> do
+        (_, h) <- openTempFile' cacheTempDir "01-index.tar"
+        BS.L.hPut h bs
+        hSeek  h AbsoluteSeek 0
+        x <- action h
+        hClose h
+        return x
+
+getIndexIdx :: MVar LocalState -> IO TarIndex
+getIndexIdx state = do
+    st <- readMVar state
+    case cachedIndex st of
+      Nothing    -> error "InMemCache.getIndexIdx: Could not read index."
+      Just index -> either throwIO return . TarIndex.build . Tar.read $ index
+
 -- | Clear all cached data
 clear :: MVar LocalState -> IO ()
 clear state = modifyMVar_ state $ \st -> return st {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hackage-security-0.5.1.0/tests/TestSuite/InMemRepo.hs 
new/hackage-security-0.5.2.1/tests/TestSuite/InMemRepo.hs
--- old/hackage-security-0.5.1.0/tests/TestSuite/InMemRepo.hs   2016-04-23 
05:48:47.000000000 +0200
+++ new/hackage-security-0.5.2.1/tests/TestSuite/InMemRepo.hs   2016-06-07 
23:44:49.000000000 +0200
@@ -72,6 +72,9 @@
 
     -- | Rollover the timestamp and snapshot keys
   , inMemRepoKeyRollover :: UTCTime -> IO ()
+
+    -- | Set the content of the repo tar index and resign
+  , inMemRepoSetIndex :: UTCTime -> [Tar.Entry] -> IO ()
   }
 
 newInMemRepo :: RepoLayout
@@ -86,6 +89,7 @@
       , inMemRepoGetPath     = getPath     state
       , inMemRepoCron        = cron        state
       , inMemRepoKeyRollover = keyRollover state
+      , inMemRepoSetIndex    = setIndex    state
       }
 
 
{-------------------------------------------------------------------------------
@@ -215,6 +219,41 @@
       , remoteSnapshot  = signedSnapshot
       }
 
+setIndex :: MVar RemoteState -> UTCTime -> [Tar.Entry] -> IO ()
+setIndex state now entries = modifyMVar_ state $ \st@RemoteState{..} -> do
+    let snapshot, snapshot' :: Snapshot
+        snapshot  = signed remoteSnapshot
+        snapshot' = snapshot {
+            snapshotVersion   = versionIncrement $ snapshotVersion snapshot
+          , snapshotExpires   = expiresInDays now 3
+          , snapshotInfoTarGz = fileInfo $ newTarGz
+          , snapshotInfoTar   = Just $ fileInfo newTar
+          }
+
+        newTar :: BS.L.ByteString
+        newTar = Tar.write entries
+
+        newTarGz :: BS.L.ByteString
+        newTarGz = GZip.compress newTar
+
+        timestamp, timestamp' :: Timestamp
+        timestamp  = signed remoteTimestamp
+        timestamp' = Timestamp {
+            timestampVersion      = versionIncrement $ timestampVersion 
timestamp
+          , timestampExpires      = expiresInDays now 3
+          , timestampInfoSnapshot = fileInfo $ renderJSON remoteLayout 
signedSnapshot
+          }
+
+        signedTimestamp = withSignatures remoteLayout [privateTimestamp 
remoteKeys] timestamp'
+        signedSnapshot  = withSignatures remoteLayout [privateSnapshot  
remoteKeys] snapshot'
+
+    return st {
+        remoteTimestamp = signedTimestamp
+      , remoteSnapshot  = signedSnapshot
+      , remoteTar       = newTar
+      , remoteTarGz     = newTarGz
+      }
+
 keyRollover :: MVar RemoteState -> UTCTime -> IO ()
 keyRollover state now = modifyMVar_ state $ \st@RemoteState{..} -> do
     newKeySnapshot  <- createKey' KeyTypeEd25519
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hackage-security-0.5.1.0/tests/TestSuite/InMemRepository.hs 
new/hackage-security-0.5.2.1/tests/TestSuite/InMemRepository.hs
--- old/hackage-security-0.5.1.0/tests/TestSuite/InMemRepository.hs     
2016-04-23 05:48:47.000000000 +0200
+++ new/hackage-security-0.5.2.1/tests/TestSuite/InMemRepository.hs     
2016-06-07 23:44:49.000000000 +0200
@@ -31,8 +31,8 @@
       , repGetCachedRoot = inMemCacheGetRoot  cache
       , repClearCache    = inMemCacheClear    cache
       , repLockCache     = withMVar cacheLock . const
-      , repWithIndex     = error "newInMemRepository: repWithIndex TODO"
-      , repGetIndexIdx   = error "newInMemRepository: repGetIndexIdx TODO"
+      , repWithIndex     = inMemCacheWithIndex   cache
+      , repGetIndexIdx   = inMemCacheGetIndexIdx cache
       , repWithMirror    = withMirror
       , repLog           = logger
       , repLayout        = layout
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hackage-security-0.5.1.0/tests/TestSuite/JSON.hs 
new/hackage-security-0.5.2.1/tests/TestSuite/JSON.hs
--- old/hackage-security-0.5.1.0/tests/TestSuite/JSON.hs        1970-01-01 
01:00:00.000000000 +0100
+++ new/hackage-security-0.5.2.1/tests/TestSuite/JSON.hs        2016-06-07 
23:44:49.000000000 +0200
@@ -0,0 +1,77 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+module TestSuite.JSON (
+    prop_roundtrip_canonical,
+    prop_roundtrip_pretty,
+    prop_canonical_pretty,
+  ) where
+
+-- stdlib
+import Data.Int
+import Data.List (sortBy, nubBy)
+import Data.Function (on)
+import Control.Applicative
+import qualified Data.ByteString.Lazy.Char8 as BS
+import Test.QuickCheck
+
+-- hackage-security
+import Text.JSON.Canonical
+
+
+prop_roundtrip_canonical, prop_roundtrip_pretty, prop_canonical_pretty
+  :: JSValue -> Bool
+
+prop_roundtrip_canonical jsval =
+    parseCanonicalJSON (renderCanonicalJSON jsval) == Right (canonicalise 
jsval)
+
+prop_roundtrip_pretty jsval =
+    parseCanonicalJSON (BS.pack (prettyCanonicalJSON jsval)) == Right jsval
+
+prop_canonical_pretty jsval =
+    parseCanonicalJSON (renderCanonicalJSON jsval) ==
+    fmap canonicalise (parseCanonicalJSON (BS.pack (prettyCanonicalJSON 
jsval)))
+
+canonicalise :: JSValue -> JSValue
+canonicalise v@JSNull        = v
+canonicalise v@(JSBool    _) = v
+canonicalise v@(JSNum     _) = v
+canonicalise v@(JSString  _) = v
+canonicalise   (JSArray  vs) = JSArray  [ canonicalise v | v <- vs]
+canonicalise   (JSObject vs) = JSObject [ (k, canonicalise v)
+                                        | (k,v) <- sortBy (compare `on` fst) 
vs ]
+
+instance Arbitrary JSValue where
+  arbitrary =
+    sized $ \sz ->
+    frequency
+      [ (1, pure JSNull)
+      , (1, JSBool   <$> arbitrary)
+      , (2, JSNum    <$> arbitrary)
+      , (2, JSString <$> arbitrary)
+      , (3, JSArray                <$> resize (sz `div` 2) arbitrary)
+      , (3, JSObject . noDupFields <$> resize (sz `div` 2) arbitrary)
+      ]
+    where
+      noDupFields = nubBy (\(x,_) (y,_) -> x==y)
+
+  shrink JSNull        = []
+  shrink (JSBool    _) = []
+  shrink (JSNum     n) = [ JSNum    n' | n' <- shrink n ]
+  shrink (JSString  s) = [ JSString s' | s' <- shrink s ]
+  shrink (JSArray  vs) = [ JSArray vs' | vs' <- shrink vs ]
+  shrink (JSObject vs) = [ JSObject vs' | vs' <- shrinkList shrinkSnd vs ]
+    where
+      shrinkSnd (a,b) = [ (a,b') | b' <- shrink b ]
+
+
+instance Arbitrary Int54 where
+  arbitrary = fromIntegral <$>
+              frequency [ (1, pure lowerbound)
+                        , (1, pure upperbound)
+                        , (8, choose (lowerbound, upperbound))
+                        ]
+    where
+      upperbound, lowerbound :: Int64
+      upperbound =   999999999999999  -- 15 decimal digits
+      lowerbound = (-999999999999999)
+  shrink = shrinkIntegral
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hackage-security-0.5.1.0/tests/TestSuite.hs 
new/hackage-security-0.5.2.1/tests/TestSuite.hs
--- old/hackage-security-0.5.1.0/tests/TestSuite.hs     2016-04-23 
05:48:47.000000000 +0200
+++ new/hackage-security-0.5.2.1/tests/TestSuite.hs     2016-06-07 
23:44:49.000000000 +0200
@@ -1,3 +1,4 @@
+{-# LANGUAGE RecordWildCards, GADTs #-}
 module Main (main) where
 
 -- stdlib
@@ -8,8 +9,13 @@
 import Network.URI (URI, parseURI)
 import Test.Tasty
 import Test.Tasty.HUnit
-import Test.Tasty.QuickCheck
+import Test.Tasty.QuickCheck hiding (label)
 import System.IO.Temp (withSystemTempDirectory)
+import qualified Codec.Archive.Tar.Entry    as Tar
+import qualified Data.ByteString.Lazy.Char8 as BS
+
+-- Cabal
+import Distribution.Package (PackageName(..))
 
 -- hackage-security
 import Hackage.Security.Client
@@ -17,6 +23,7 @@
 import Hackage.Security.JSON (DeserializationError(..))
 import Hackage.Security.Util.Checked
 import Hackage.Security.Util.Path
+import Hackage.Security.Util.Some
 import Hackage.Security.Util.Pretty
 import qualified Hackage.Security.Client.Repository.Remote as Remote
 import qualified Hackage.Security.Client.Repository.Cache  as Cache
@@ -45,6 +52,7 @@
         , testCase "testInMemUpdatesAfterCron"     testInMemUpdatesAfterCron
         , testCase "testInMemKeyRollover"          testInMemKeyRollover
         , testCase "testInMemOutdatedTimestamp"    testInMemOutdatedTimestamp
+        , testCase "testInMemIndex"                testInMemIndex
         ]
     , testGroup "HttpMem" [
           testCase "testHttpMemInitialHasForUpdates" 
testHttpMemInitialHasUpdates
@@ -52,6 +60,7 @@
         , testCase "testHttpMemUpdatesAfterCron"     
testHttpMemUpdatesAfterCron
         , testCase "testHttpMemKeyRollover"          testHttpMemKeyRollover
         , testCase "testHttpMemOutdatedTimestamp"    
testHttpMemOutdatedTimestamp
+        , testCase "testHttpMemIndex"                testHttpMemIndex
         ]
     , testGroup "Canonical JSON" [
           testProperty "prop_roundtrip_canonical" JSON.prop_roundtrip_canonical
@@ -131,6 +140,10 @@
       withAssertLog "C" logMsgs [] $ do
         assertEqual "C.1" HasUpdates =<< checkForUpdates repo fourDaysLater
 
+testInMemIndex :: Assertion
+testInMemIndex = inMemTest $ \inMemRepo _logMsgs repo ->
+    testRepoIndex inMemRepo repo
+
 
{-------------------------------------------------------------------------------
   Same tests, but going through the "real" Remote repository and Cache, though
   still using an in-memory repository (with a HttpLib bridge)
@@ -202,6 +215,57 @@
       withAssertLog "C" logMsgs [] $ do
         assertEqual "C.1" HasUpdates =<< checkForUpdates repo fourDaysLater
 
+testHttpMemIndex :: Assertion
+testHttpMemIndex = httpMemTest $ \inMemRepo _logMsgs repo ->
+    testRepoIndex inMemRepo repo
+
+{-------------------------------------------------------------------------------
+  Identical tests between the two variants
+-------------------------------------------------------------------------------}
+
+testRepoIndex :: (Throws SomeRemoteError, Throws VerificationError)
+              => InMemRepo -> Repository down -> IO ()
+testRepoIndex inMemRepo repo = do
+    assertEqual "A" HasUpdates =<< checkForUpdates repo =<< checkExpiry
+    dir1 <- getDirectory repo
+    directoryFirst dir1  @?= DirectoryEntry 0
+    directoryNext  dir1  @?= DirectoryEntry 0
+    length (directoryEntries dir1) @?= 0
+
+    now <- getCurrentTime
+    inMemRepoSetIndex inMemRepo now [testEntry1]
+
+    assertEqual "B" HasUpdates =<< checkForUpdates repo =<< checkExpiry
+    dir2 <- getDirectory repo
+    directoryFirst dir2  @?= DirectoryEntry 0
+    directoryNext  dir2  @?= DirectoryEntry 2
+    length (directoryEntries dir2) @?= 1
+    directoryLookup dir2 testEntryIndexFile @?= Just (DirectoryEntry 0)
+    withIndex repo $ \IndexCallbacks{..} -> do
+      (sentry, next) <- indexLookupEntry (DirectoryEntry 0)
+      next @?= Nothing
+      case sentry of Some entry -> checkIndexEntry entry
+  where
+    checkIndexEntry :: IndexEntry dec -> Assertion
+    checkIndexEntry entry = do
+       toUnrootedFilePath (unrootPath (indexEntryPath entry))
+         @?= "foo/preferred-versions"
+       indexEntryContent entry @?= testEntrycontent
+       case indexEntryPathParsed entry of
+         Just (IndexPkgPrefs pkgname) -> do
+           pkgname @?= PackageName "foo"
+           case indexEntryContentParsed entry of
+             Right () -> return ()
+             _        -> fail "unexpected index entry content"
+         _ -> fail "unexpected index path"
+
+    testEntry1 = Tar.fileEntry path testEntrycontent
+      where
+        Right path = Tar.toTarPath False "foo/preferred-versions"
+    testEntrycontent   = BS.pack "foo >= 1"
+    testEntryIndexFile = IndexPkgPrefs (PackageName "foo")
+
+
 
{-------------------------------------------------------------------------------
   Log messages we expect when using the Remote repository
 
-------------------------------------------------------------------------------}


Reply via email to