module Keydir (mapEntriesToKeydir, getValueFromKeydir, buildKeyDir, listKeysFromKeydir) where import Caskfile (listCaskFiles, readEntries, readEntryFromPos) import qualified Data.ByteString.Lazy as B import qualified Data.Map as Map import Entry (Entry (..), FieldSize, Key, Timestamp, Value, matchChecksum) import System.FilePath ((</>)) data KeydirEntry = KeydirEntry FilePath FieldSize Int Timestamp deriving (Int -> KeydirEntry -> ShowS [KeydirEntry] -> ShowS KeydirEntry -> String (Int -> KeydirEntry -> ShowS) -> (KeydirEntry -> String) -> ([KeydirEntry] -> ShowS) -> Show KeydirEntry forall a. (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a $cshowsPrec :: Int -> KeydirEntry -> ShowS showsPrec :: Int -> KeydirEntry -> ShowS $cshow :: KeydirEntry -> String show :: KeydirEntry -> String $cshowList :: [KeydirEntry] -> ShowS showList :: [KeydirEntry] -> ShowS Show, KeydirEntry -> KeydirEntry -> Bool (KeydirEntry -> KeydirEntry -> Bool) -> (KeydirEntry -> KeydirEntry -> Bool) -> Eq KeydirEntry forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a $c== :: KeydirEntry -> KeydirEntry -> Bool == :: KeydirEntry -> KeydirEntry -> Bool $c/= :: KeydirEntry -> KeydirEntry -> Bool /= :: KeydirEntry -> KeydirEntry -> Bool Eq) type Keydir = Map.Map Key KeydirEntry mapEntriesToKeydir :: FilePath -> [(Int, Entry)] -> Keydir mapEntriesToKeydir :: String -> [(Int, Entry)] -> Keydir mapEntriesToKeydir String _ [] = Keydir forall k a. Map k a Map.empty mapEntriesToKeydir String filepath ((Int offset, Entry Checksum _ Timestamp timestamp Timestamp ksize Timestamp vsize Key key Key _) : [(Int, Entry)] entries) = let ksize' :: Int ksize' = Timestamp -> Int forall a b. (Integral a, Num b) => a -> b fromIntegral Timestamp ksize in let entry :: KeydirEntry entry = String -> Timestamp -> Int -> Timestamp -> KeydirEntry KeydirEntry String filepath Timestamp vsize (Int ksize' Int -> Int -> Int forall a. Num a => a -> a -> a + Int 4 Int -> Int -> Int forall a. Num a => a -> a -> a + Int 8 Int -> Int -> Int forall a. Num a => a -> a -> a + Int 8 Int -> Int -> Int forall a. Num a => a -> a -> a + Int 8 Int -> Int -> Int forall a. Num a => a -> a -> a + Int offset) Timestamp timestamp in Key -> KeydirEntry -> Keydir -> Keydir forall k a. Ord k => k -> a -> Map k a -> Map k a Map.insert Key key KeydirEntry entry (Keydir -> Keydir) -> Keydir -> Keydir forall a b. (a -> b) -> a -> b $ String -> [(Int, Entry)] -> Keydir mapEntriesToKeydir String filepath [(Int, Entry)] entries getValueFromKeydir :: Keydir -> Key -> IO (Maybe Value) getValueFromKeydir :: Keydir -> Key -> IO (Maybe Key) getValueFromKeydir Keydir keydir Key key = do let keydir' :: Maybe KeydirEntry keydir' = Key -> Keydir -> Maybe KeydirEntry forall k a. Ord k => k -> Map k a -> Maybe a Map.lookup Key key Keydir keydir case Maybe KeydirEntry keydir' of Just (KeydirEntry String filepath Timestamp vsize Int offset Timestamp _) -> do entry :: Entry entry@(Entry Checksum _ Timestamp _ Timestamp _ Timestamp _ Key _ Key value) <- String -> Timestamp -> Timestamp -> Timestamp -> IO Entry readEntryFromPos String filepath (Key -> Timestamp B.length Key key) Timestamp vsize (Timestamp -> IO Entry) -> Timestamp -> IO Entry forall a b. (a -> b) -> a -> b $ Int -> Timestamp forall a b. (Integral a, Num b) => a -> b fromIntegral Int offset Maybe Key -> IO (Maybe Key) forall a. a -> IO a forall (f :: * -> *) a. Applicative f => a -> f a pure (Maybe Key -> IO (Maybe Key)) -> Maybe Key -> IO (Maybe Key) forall a b. (a -> b) -> a -> b $ if Entry -> Bool matchChecksum Entry entry then Key -> Maybe Key forall a. a -> Maybe a Just Key value else Maybe Key forall a. Maybe a Nothing Maybe KeydirEntry Nothing -> Maybe Key -> IO (Maybe Key) forall a. a -> IO a forall (f :: * -> *) a. Applicative f => a -> f a pure Maybe Key forall a. Maybe a Nothing compareByTimestamp :: KeydirEntry -> KeydirEntry -> KeydirEntry compareByTimestamp :: KeydirEntry -> KeydirEntry -> KeydirEntry compareByTimestamp left :: KeydirEntry left@(KeydirEntry String _ Timestamp _ Int _ Timestamp timestamp) right :: KeydirEntry right@(KeydirEntry String _ Timestamp _ Int _ Timestamp timestamp') = if Timestamp timestamp Timestamp -> Timestamp -> Bool forall a. Ord a => a -> a -> Bool > Timestamp timestamp' then KeydirEntry left else KeydirEntry right buildKeyDir :: FilePath -> IO Keydir buildKeyDir :: String -> IO Keydir buildKeyDir String dirpath = do [String] caskfiles <- String -> IO [String] listCaskFiles String dirpath [Keydir] keydirs <- (String -> IO Keydir) -> [String] -> IO [Keydir] forall (t :: * -> *) (m :: * -> *) a b. (Traversable t, Monad m) => (a -> m b) -> t a -> m (t b) forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b] mapM ( \String caskfile -> do let caskpath :: String caskpath = String dirpath String -> ShowS </> String caskfile [(Int, Entry)] entries <- String -> IO [(Int, Entry)] readEntries String caskpath Keydir -> IO Keydir forall a. a -> IO a forall (f :: * -> *) a. Applicative f => a -> f a pure (Keydir -> IO Keydir) -> Keydir -> IO Keydir forall a b. (a -> b) -> a -> b $ String -> [(Int, Entry)] -> Keydir mapEntriesToKeydir String caskpath [(Int, Entry)] entries ) [String] caskfiles Keydir -> IO Keydir forall a. a -> IO a forall (f :: * -> *) a. Applicative f => a -> f a pure (Keydir -> IO Keydir) -> Keydir -> IO Keydir forall a b. (a -> b) -> a -> b $ (KeydirEntry -> KeydirEntry -> KeydirEntry) -> [Keydir] -> Keydir forall (f :: * -> *) k a. (Foldable f, Ord k) => (a -> a -> a) -> f (Map k a) -> Map k a Map.unionsWith KeydirEntry -> KeydirEntry -> KeydirEntry compareByTimestamp [Keydir] keydirs listKeysFromKeydir :: Keydir -> [Key] listKeysFromKeydir :: Keydir -> [Key] listKeysFromKeydir = Keydir -> [Key] forall k a. Map k a -> [k] Map.keys