packages feed

HsSVN-0.1: Subversion/FileSystem.hsc

{- -*- haskell -*- -}

-- #prune

-- |An interface to the Subversion filesystem.

#include "HsSVN.h"

module Subversion.FileSystem
    ( -- * Type
      FileSystem
    , SVN_FS_T -- private

    , wrapFS -- private
    , withFSPtr -- private
    , touchFS -- private

      -- * Information of the libsvn_fs itself
    , fsVersion

      -- * Filesystem creation, opening and destruction
    , createFileSystem
    , fsConfigFSType
    , fsTypeBDB
    , fsTypeFSFS

    , openFileSystem
    , deleteFileSystem
    , hotCopyFileSystem

      -- * Accessors
    , getFileSystemType
    , getFileSystemPath

    , getYoungestRev
    )
    where

import           Control.Monad
import           Foreign.C.String
import           Foreign.ForeignPtr
import           Foreign.Ptr
import           Foreign.Marshal.Alloc
import           Foreign.Storable
import           GHC.ForeignPtr   as GF
import           Subversion.Error
import           Subversion.Hash
import           Subversion.Pool
import           Subversion.Types

-- |@'FileSystem'@ is an opaque object representing a Subversion
-- filesystem.
newtype FileSystem = FileSystem (ForeignPtr SVN_FS_T)
data SVN_FS_T

foreign import ccall "svn_fs_version"
        _version :: IO (Ptr SVN_VERSION_T)

foreign import ccall "svn_fs_create"
        _create :: Ptr (Ptr SVN_FS_T) -> CString -> Ptr APR_HASH_T -> Ptr APR_POOL_T -> IO (Ptr SVN_ERROR_T)

foreign import ccall "svn_fs_open"
        _open :: Ptr (Ptr SVN_FS_T) -> CString -> Ptr APR_HASH_T -> Ptr APR_POOL_T -> IO (Ptr SVN_ERROR_T)

foreign import ccall "svn_fs_delete_fs"
        _delete_fs :: CString -> Ptr APR_POOL_T -> IO (Ptr SVN_ERROR_T)

foreign import ccall "svn_fs_hotcopy"
        _hotcopy :: CString -> CString -> SVN_BOOLEAN_T -> Ptr APR_POOL_T -> IO (Ptr SVN_ERROR_T)

foreign import ccall "svn_fs_type"
        _type :: Ptr CString -> CString -> Ptr APR_POOL_T -> IO (Ptr SVN_ERROR_T)

foreign import ccall "svn_fs_path"
        _path :: Ptr SVN_FS_T -> Ptr APR_POOL_T -> IO CString

foreign import ccall "svn_fs_youngest_rev"
        _youngest_rev :: Ptr SVN_REVNUM_T -> Ptr SVN_FS_T -> Ptr APR_POOL_T -> IO (Ptr SVN_ERROR_T)


wrapFS :: IO () -> Ptr SVN_FS_T -> IO FileSystem
wrapFS finalizer fsPtr
    = do fs <- newForeignPtr_ fsPtr
         GF.addForeignPtrConcFinalizer fs finalizer
         return $ FileSystem fs


withFSPtr :: FileSystem -> (Ptr SVN_FS_T -> IO a) -> IO a
withFSPtr (FileSystem fs) = withForeignPtr fs


touchFS :: FileSystem -> IO ()
touchFS (FileSystem fs) = touchForeignPtr fs

-- |@fsVersion@ returns a version information of the libsvn_fs.
fsVersion :: IO Version
fsVersion = _version >>= peekVersion


-- |@'fsConfigFSType'@ is a config key to specify the filesystem
-- back-end.
fsConfigFSType :: String
fsConfigFSType = (#const_str SVN_FS_CONFIG_FS_TYPE)

-- |@'fsTypeBDB'@ is a config value representing the Berkeley-DB
-- back-end.
fsTypeBDB :: String
fsTypeBDB = (#const_str SVN_FS_TYPE_BDB)

-- |@'fsTypeFSFS'@ is a config value representing the
-- Native-filesystem back-end.
fsTypeFSFS :: String
fsTypeFSFS = (#const_str SVN_FS_TYPE_FSFS)

-- |@'createFileSystem'@ creates a new, empty Subversion
-- filesystem. Note that creating a raw filesystem is different from
-- creating a repository. If you want a new repository, use
-- 'Subversion.Repository.createRepository' instead.
createFileSystem
    :: FilePath           -- ^ Where to create the filesystem. The
                          --   path most not currently exist, but its
                          --   parent must exist.
    -> [(String, String)] -- ^ A list of @(key, value)@ tuples which
                          --   modifies the behavior of the
                          --   filesystem. The interpretation of it is
                          --   specific to the filesystem back-end.
                          -- 
                          --   If the list contains a value for
                          --   'fsConfigFSType', that value determines
                          --   the filesystem type for the new
                          --   filesystem. Currently defined values
                          --   are:
                          --
                          --   ['fsTypeBDB'] Berkeley-DB implementation
                          --
                          --   ['fsTypeFSFS'] Native-filesystem
                          --   implementation
                          --
                          --   If the list does not contain a value
                          --   for 'fsConfigFSType' then the default
                          --   filesystem type will be used. This will
                          --   typically be BDB for version 1.1 and
                          --   FSFS for later versions, though the
                          --   caller should not rely upon any
                          --   particular default if they wish to
                          --   ensure that a filesystem of specific
                          --   type is created.
    -> IO FileSystem      -- ^ The new filesystem.
createFileSystem path configPairs
    = do pool <- newPool
         alloca $ \ fsPtrPtr ->
             withCString path $ \ pathPtr ->
             withPoolPtr pool $ \ poolPtr ->
                 do config <- pairsToHash configPairs
                    svnErr $ _create fsPtrPtr pathPtr (unsafeHashToPtr config) poolPtr

                    fs <- wrapFS (touchPool pool) =<< peek fsPtrPtr

                    -- config には fs が死ぬまでは生きてゐて慾しい。
                    GF.addForeignPtrConcFinalizer (case fs of FileSystem x -> x)
                          $ touchHash config

                    return fs

-- |@'openFileSystem'@ opens a Subversion filesystem. Note that you
-- probably don't want to use this directly. Take a look at
-- 'Subversion.Repository.openRepository' instead.
openFileSystem
    :: FilePath           -- ^ Where the filesystem located on.
    -> [(String, String)] -- ^ A list of @(key, value)@ tuples which
                          --   modifies the behavior of the
                          --   filesystem. The interpretation of it is
                          --   specific to the filesystem back-end.
    -> IO FileSystem
openFileSystem path configPairs
    = do pool <- newPool
         alloca $ \ fsPtrPtr ->
             withCString path $ \ pathPtr ->
             withPoolPtr pool $ \ poolPtr ->
             do config <- pairsToHash configPairs
                svnErr $ _open fsPtrPtr pathPtr (unsafeHashToPtr config) poolPtr

                fs <- wrapFS (touchPool pool) =<< peek fsPtrPtr

                -- config には fs が死ぬまでは生きてゐて慾しい。
                GF.addForeignPtrConcFinalizer (case fs of FileSystem x -> x)
                      $ touchHash config

                return fs

-- |@'deleteFileSystem'@ deletes a Subversion filesystem. Note that
-- you probably don't want to use this directly. Take a look at
-- 'Subversion.Repository.deleteRepository' instead.
deleteFileSystem :: FilePath -> IO ()
deleteFileSystem path
    = do pool <- newPool
         withCString path $ \ pathPtr ->
             withPoolPtr pool $ \ poolPtr ->
             svnErr $ _delete_fs pathPtr poolPtr

-- |@'hotCopyFileSystem'@ copies a possibly live Subversion filesystem
-- from one location to another.
hotCopyFileSystem :: FilePath -- ^ Source
                  -> FilePath -- ^ Destination
                  -> Bool     -- ^ If this is true,
                              --   @'hotCopyFileSystem'@ performs
                              --   cleanup on the source filesystem as
                              --   part of the copy opeation;
                              --   currently, this means deleting
                              --   copied, unused logfiles for a
                              --   Berkeley DB source filesystem.
                  -> IO ()
hotCopyFileSystem src dest clean
    = do pool <- newPool
         withCString src $ \ srcPath ->
             withCString dest $ \ destPath ->
             withPoolPtr pool $ \ poolPtr  ->
             svnErr $ _hotcopy srcPath destPath (marshalBool clean) poolPtr

-- |@'getFileSystemPath' fsPath@ returns a string identifying the
-- back-end type of the Subversion filesystem located on @fsPath@. The
-- string should be equal to one of the @fsType*@ defined constants,
-- unless the filesystem is a new back-end type added in a later
-- version of Subversion.
--
-- In general, the type should make no difference in the filesystem's
-- semantics, but there are a few situations (such as backups) where
-- it might matter.
getFileSystemType :: FilePath -> IO String
getFileSystemType path
    = do pool <- newPool
         alloca $ \ typePtrPtr ->
             withCString path $ \ pathPtr ->
             withPoolPtr pool $ \ poolPtr ->
             do svnErr $ _type typePtrPtr pathPtr poolPtr
                t <- peekCString =<< peek typePtrPtr
                return t

-- |@'getFileSystemPath' fs@ returns the path to @fs@'s
-- repository. Note that this is what was passed to 'createFileSystem'
-- or 'openFileSystem'; might be absolute, might not.
getFileSystemPath :: FileSystem -> IO FilePath
getFileSystemPath fs
    = do pool <- newPool
         withFSPtr fs $ \ fsPtr ->
             withPoolPtr pool $ \ poolPtr ->
             do path <- peekCString =<< _path fsPtr poolPtr
                touchPool pool
                return path

-- |@'getYoungestRev' fs@ returns the number of the youngest revision
-- in filesystem @fs@. The oldest revision in any filesystem is
-- numbered zero.
getYoungestRev :: FileSystem -> IO RevNum
getYoungestRev fs
    = do pool <- newPool
         alloca $ \ revNumPtr ->
             withFSPtr   fs   $ \ fsPtr   ->
             withPoolPtr pool $ \ poolPtr ->
             do svnErr $ _youngest_rev revNumPtr fsPtr poolPtr
                return . fromIntegral =<< peek revNumPtr