haskdeep-0.1.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 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
rule = ignoreRule 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
if ignore fpt rule
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
ignore :: T.Text -> Maybe T.Text -> Bool
ignore fpt (Just rule) = fpt =~ rule
ignore _ Nothing = False