module Subversion.Dump
( RevDate
, Revision(..)
, OpKind(..)
, OpAction(..)
, Operation(..)
, readSvnDump
) where
import Control.Applicative hiding (many)
import Data.ByteString as B hiding (map)
import qualified Data.ByteString.Char8 as BC hiding (map)
import qualified Data.ByteString.Lazy as BL hiding (map)
import qualified Data.List as L
import Data.Text (Text)
import qualified Data.Text.Encoding as E
import Data.Maybe
import Subversion.Dump.Raw
import Prelude hiding (getContents)
default (ByteString)
type RevDate = Text
data Revision = Revision { revNumber :: Int
, revDate :: RevDate
, revAuthor :: Maybe Text
, revComment :: Maybe Text
, revOperations :: [Operation] }
deriving Show
data OpKind = File | Directory deriving (Show, Enum, Eq)
data OpAction = Add | Change | Replace | Delete deriving (Show, Enum, Eq)
data Operation = Operation { opKind :: OpKind
, opAction :: OpAction
, opPathname :: FilePath
, opContents :: BL.ByteString
, opContentLength :: Int
, opChecksumMD5 :: Maybe Text
, opChecksumSHA1 :: Maybe Text
, opCopyFromRev :: Maybe Int
, opCopyFromPath :: Maybe FilePath }
deriving Show
readSvnDump :: BL.ByteString -> [Revision]
readSvnDump dump = map processRevs $ L.groupBy sameRev $ readSvnDumpRaw dump
where sameRev _ y = isNothing $
L.lookup "Revision-number" (entryTags y)
getField f n x = L.lookup n (f x)
getField' f n x = fromMaybe "" (getField f n x)
tagM = getField entryTags
propM = getField entryProps
tag = getField' entryTags
prop = getField' entryProps
processRevs [] = error "Unexpected"
processRevs (rev:ops) =
Revision {
revNumber = readInt $ tag "Revision-number" rev
, revDate = parseDate $ prop "svn:date" rev
, revAuthor = E.decodeUtf8 <$> propM "svn:author" rev
, revComment = E.decodeUtf8 <$> propM "svn:log" rev
, revOperations = map processOp ops }
processOp op =
Operation {
opKind = getOpKind $ tag "Node-kind" op
, opAction = getOpAction $ tag "Node-action" op
, opPathname = BC.unpack $ tag "Node-path" op
, opContents = entryBody op
, opContentLength = readInt $ tag "Text-content-length" op
, opCopyFromRev = readInt <$>
tagM "Node-copyfrom-rev" op
, opCopyFromPath = BC.unpack <$> tagM "Node-copyfrom-path" op
, opChecksumMD5 = E.decodeUtf8 <$> tagM "Text-content-md5" op
, opChecksumSHA1 = E.decodeUtf8 <$> tagM "Text-content-sha1" op }
getOpKind kind = case kind of
"file" -> File
"dir" -> Directory
_ -> error "Unexpected"
getOpAction kind = case kind of
"add" -> Add
"delete" -> Delete
"change" -> Change
"replace" -> Replace
_ -> error "Unexpected"
parseDate :: ByteString -> RevDate
parseDate = E.decodeUtf8