haskdeep-0.2.0.0: src/HaskDeep/Computation.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DoAndIfThenElse #-}
-- |
-- Module : HaskDeep.Computation
-- Copyright : Mauro Taraborelli 2012
-- License : BSD3
--
-- Maintainer : maurotaraborelli@gmail.com
-- Stability : experimental
-- Portability : unknown
--
-- Computes hashes traversing recursively through a directory structure.
-- Uses a list of known hashes to audit a set of files.
--
-- Internal module.
module HaskDeep.Computation
(
-- * Computation
compute -- Hash ctx a => HaskDeepConfiguration -> ComputationMode a -> IO HashSet
)
where
import Control.Monad (liftM)
import Data.Maybe (fromJust)
import Prelude hiding (FilePath)
import Crypto.Classes (Hash)
import qualified Crypto.Conduit as CC
import Data.Conduit (($$))
import qualified Data.Conduit as C
import qualified Data.Conduit.Filesystem as CF
import qualified Data.Conduit.List as CL
import qualified Data.Text as T
import Data.Time (UTCTime)
import qualified Filesystem as FS
import Filesystem.Path.CurrentOS (FilePath)
import qualified Filesystem.Path.CurrentOS as FSC
import Text.Regex.TDFA ((=~))
import Text.Regex.TDFA.Text ()
import HaskDeep.Configuration
import HaskDeep.ComputationMode
import HaskDeep.HashSet (HashInfo(..), HashSet)
import qualified HaskDeep.HashSet as HS
-- | Compute @HashSet@ traversing recursively through the directory structure.
compute :: Hash ctx a => HaskDeepConfiguration
-> ComputationMode a
-> IO HashSet
compute conf cm = CF.traverse False root $$ CL.foldM insert_hash empty_with_symbol
where
root = rootDirectory conf
regex = excludeRegex conf
mod_from = includeModFrom conf
mod_upto = includeModUpTo conf
empty_with_symbol = HS.setSymbol (symbol cm) HS.empty
insert_hash :: HashSet -> FilePath -> IO HashSet
insert_hash hs fp = do let fpt = fpToText $ relativize root fp
fmt <- FS.getModified fp
if (excRegex fpt regex) || (excMod fmt mod_from mod_upto)
then return hs
else do s <- FS.getSize fp
h <- liftM (runComputation cm) $ C.runResourceT
$ CF.sourceFile fp $$ CC.sinkHash
return $ HS.insert (HashInfo fpt s h) hs
relativize :: FilePath -> FilePath -> FilePath
relativize root fp = fromJust $ FSC.stripPrefix root fp
fpToText :: FilePath -> T.Text
fpToText = either id id . FSC.toText
excRegex :: T.Text -> Maybe T.Text -> Bool
excRegex fpt (Just rule) = fpt =~ rule
excRegex _ Nothing = False
excMod :: UTCTime -> Maybe UTCTime -> Maybe UTCTime -> Bool
excMod fmt (Just modFrom) (Just modUpTo) = (fmt < modFrom) || (fmt > modUpTo)
excMod fmt (Just modFrom) Nothing = fmt < modFrom
excMod fmt Nothing (Just modUpTo) = fmt > modUpTo
excMod _ Nothing Nothing = False