{-# LANGUAGE DeriveGeneric #-}

{- |
   Maintainer:  simons@cryp.to
   Stability:   provisional
   Portability: portable

   Types and class instances for parsing the @package.json@ files found in a
   @01-index.tar@ tarball from Hackage with "Data.Aeson". These parsers mirror
   the exact structure of those files, but only a small part of it is actually
   of interest to anyone other than implementors of @cabal-install@. Everyone
   else will most likely prefer the functions oferred by
   "Distribution.Hackage.DB.Parsed".
 -}

module Distribution.Hackage.DB.MetaData where

import Distribution.Hackage.DB.Errors

import Control.Exception
import Data.Aeson
import Data.ByteString.Lazy.UTF8 as BS
import Data.Map as Map
import GHC.Generics ( Generic )

-- | Parse the @package.json@ file found in a @01-index.tar@ tarball from
-- Hackage with "Data.Aeson". This function is a convenience wrapper around
-- 'eitherDecode' that throws an 'InvalidMetaFile' exception to signal failure.
--
-- >>> :set -XOverloadedStrings
-- >>> parseMetaData "{\"signatures\":[],\"signed\":{\"_type\":\"Targets\",\"expires\":null,\"targets\":{\"<repo>/package/jailbreak-cabal-1.3.2.tar.gz\":{\"hashes\":{\"md5\":\"ba42b3e68323ccbeb3ac900cd68f9e90\",\"sha256\":\"212a8bbc3dfc748c4063282414a2726709d651322f3984c9989179d2352950f4\"},\"length\":2269}},\"version\":0}}"
-- MetaData {signed = SignedMetaData {version = 0, expires = Nothing, _type = "Targets", targets = fromList [("<repo>/package/jailbreak-cabal-1.3.2.tar.gz",TargetData {length = 2269, hashes = fromList [("md5","ba42b3e68323ccbeb3ac900cd68f9e90"),("sha256","212a8bbc3dfc748c4063282414a2726709d651322f3984c9989179d2352950f4")]})]}, signatures = []}

parseMetaData :: ByteString -> MetaData
parseMetaData :: ByteString -> MetaData
parseMetaData = (String -> MetaData)
-> (MetaData -> MetaData) -> Either String MetaData -> MetaData
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (InvalidMetaFile -> MetaData
forall a e. Exception e => e -> a
throw (InvalidMetaFile -> MetaData)
-> (String -> InvalidMetaFile) -> String -> MetaData
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> InvalidMetaFile
InvalidMetaFile) MetaData -> MetaData
forall a. a -> a
id (Either String MetaData -> MetaData)
-> (ByteString -> Either String MetaData) -> ByteString -> MetaData
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either String MetaData
forall a. FromJSON a => ByteString -> Either String a
eitherDecode

data MetaData = MetaData { MetaData -> SignedMetaData
signed :: SignedMetaData
                         , MetaData -> [String]
signatures :: [String]
                         }
  deriving (Int -> MetaData -> ShowS
[MetaData] -> ShowS
MetaData -> String
(Int -> MetaData -> ShowS)
-> (MetaData -> String) -> ([MetaData] -> ShowS) -> Show MetaData
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [MetaData] -> ShowS
$cshowList :: [MetaData] -> ShowS
show :: MetaData -> String
$cshow :: MetaData -> String
showsPrec :: Int -> MetaData -> ShowS
$cshowsPrec :: Int -> MetaData -> ShowS
Show, (forall x. MetaData -> Rep MetaData x)
-> (forall x. Rep MetaData x -> MetaData) -> Generic MetaData
forall x. Rep MetaData x -> MetaData
forall x. MetaData -> Rep MetaData x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep MetaData x -> MetaData
$cfrom :: forall x. MetaData -> Rep MetaData x
Generic)

instance FromJSON MetaData

data SignedMetaData = SignedMetaData { SignedMetaData -> Int
version :: Int
                                     , SignedMetaData -> Maybe String
expires :: Maybe String
                                     , SignedMetaData -> String
_type   :: String
                                     , SignedMetaData -> Map String TargetData
targets :: Map String TargetData
                                     }
  deriving (Int -> SignedMetaData -> ShowS
[SignedMetaData] -> ShowS
SignedMetaData -> String
(Int -> SignedMetaData -> ShowS)
-> (SignedMetaData -> String)
-> ([SignedMetaData] -> ShowS)
-> Show SignedMetaData
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SignedMetaData] -> ShowS
$cshowList :: [SignedMetaData] -> ShowS
show :: SignedMetaData -> String
$cshow :: SignedMetaData -> String
showsPrec :: Int -> SignedMetaData -> ShowS
$cshowsPrec :: Int -> SignedMetaData -> ShowS
Show, (forall x. SignedMetaData -> Rep SignedMetaData x)
-> (forall x. Rep SignedMetaData x -> SignedMetaData)
-> Generic SignedMetaData
forall x. Rep SignedMetaData x -> SignedMetaData
forall x. SignedMetaData -> Rep SignedMetaData x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep SignedMetaData x -> SignedMetaData
$cfrom :: forall x. SignedMetaData -> Rep SignedMetaData x
Generic)

instance FromJSON SignedMetaData

data TargetData = TargetData { TargetData -> Int
length :: Int
                             , TargetData -> Map String String
hashes :: Map String String
                             }
  deriving (Int -> TargetData -> ShowS
[TargetData] -> ShowS
TargetData -> String
(Int -> TargetData -> ShowS)
-> (TargetData -> String)
-> ([TargetData] -> ShowS)
-> Show TargetData
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TargetData] -> ShowS
$cshowList :: [TargetData] -> ShowS
show :: TargetData -> String
$cshow :: TargetData -> String
showsPrec :: Int -> TargetData -> ShowS
$cshowsPrec :: Int -> TargetData -> ShowS
Show, (forall x. TargetData -> Rep TargetData x)
-> (forall x. Rep TargetData x -> TargetData) -> Generic TargetData
forall x. Rep TargetData x -> TargetData
forall x. TargetData -> Rep TargetData x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep TargetData x -> TargetData
$cfrom :: forall x. TargetData -> Rep TargetData x
Generic)

instance FromJSON TargetData