forked from commercialhaskell/stack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathVersionTagged.hs
More file actions
77 lines (73 loc) · 2.89 KB
/
VersionTagged.hs
File metadata and controls
77 lines (73 loc) · 2.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
-- | Tag a Store instance with structural version info to ensure we're
-- reading a compatible format.
module Data.Store.VersionTagged
( taggedDecodeOrLoad
, taggedEncodeFile
, decodeFileMaybe
) where
import Control.Applicative
import Control.Exception.Lifted (catch, IOException, assert)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Control.Monad.Logger
import Control.Monad.Trans.Control (MonadBaseControl)
import qualified Data.ByteString as BS
import Data.Monoid ((<>))
import Data.Store
import Data.Store.TypeHash
import qualified Data.Text as T
import Path
import Path.IO (ensureDir)
import Prelude
-- | Write to the given file, with a binary-tagged tag.
taggedEncodeFile :: (Store a, HasTypeHash a, MonadIO m, MonadLogger m, Eq a)
=> Path Abs File
-> a
-> m ()
taggedEncodeFile fp x = do
let fpt = T.pack (toFilePath fp)
$logDebug $ "Encoding " <> fpt
ensureDir (parent fp)
let encoded = encode (Tagged x)
assert (decodeEx encoded == Tagged x) $ liftIO $ BS.writeFile (toFilePath fp) encoded
$logDebug $ "Finished writing " <> fpt
-- | Read from the given file. If the read fails, run the given action and
-- write that back to the file. Always starts the file off with the
-- version tag.
taggedDecodeOrLoad :: (Store a, HasTypeHash a, Eq a, MonadIO m, MonadLogger m, MonadBaseControl IO m)
=> Path Abs File
-> m a
-> m a
taggedDecodeOrLoad fp mx = do
let fpt = T.pack (toFilePath fp)
$logDebug $ "Trying to decode " <> fpt
mres <- decodeFileMaybe fp
case mres of
Nothing -> do
$logDebug $ "Failure decoding " <> fpt
x <- mx
taggedEncodeFile fp x
return x
Just x -> do
$logDebug $ "Success decoding " <> fpt
return x
decodeFileMaybe :: (Store a, HasTypeHash a, MonadIO m, MonadLogger m, MonadBaseControl IO m)
=> Path loc File
-> m (Maybe a)
decodeFileMaybe fp = do
mbs <- liftIO (Just <$> BS.readFile (toFilePath fp)) `catch` \(err :: IOException) -> do
$logDebug ("Exception ignored when attempting to load " <> T.pack (toFilePath fp) <> ": " <> T.pack (show err))
return Nothing
case mbs of
Nothing -> return Nothing
Just bs ->
liftIO (do (Tagged res) <- decodeIO bs
return (Just res)) `catch` \(err :: PeekException) -> do
let fpt = T.pack (toFilePath fp)
$logDebug ("Error while decoding " <> fpt <> ": " <> T.pack (show err) <> " (this might not be an error, when switching between stack versions)")
return Nothing