packages feed

darcs-cabalized-2.0.2: src/Darcs/Repository/Pristine.lhs

%  Copyright (C) 2002-2005 David Roundy
%  Copyright (C) 2004 Juliusz Chroboczek
%
%  This program is free software; you can redistribute it and/or modify
%  it under the terms of the GNU General Public License as published by
%  the Free Software Foundation; either version 2, or (at your option)
%  any later version.
%
%  This program is distributed in the hope that it will be useful,
%  but WITHOUT ANY WARRANTY; without even the implied warranty of
%  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%  GNU General Public License for more details.
%
%  You should have received a copy of the GNU General Public License
%  along with this program; see the file COPYING.  If not, write to
%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
%  Boston, MA 02110-1301, USA.


\begin{code}
{-# OPTIONS_GHC -cpp #-}
#include "gadts.h"
module Darcs.Repository.Pristine ( Pristine, flagsToPristine, nopristine,
                 createPristine, removePristine, identifyPristine,
                 checkPristine, slurpPristine,
                 applyPristine, createPristineFromWorking,
                 syncPristine, replacePristine, getPristinePop,
                 pristineDirectory, pristineToFlagString,
                 easyCreatePristineDirectoryTree,
                 easyCreatePartialsPristineDirectoryTree
               ) where

import Data.Maybe ( isJust )
import Control.Monad ( when, liftM )
import System.Directory ( createDirectory, doesDirectoryExist, doesFileExist,
                   renameDirectory, removeFile )
import Darcs.Lock ( rm_recursive, writeBinFile )
import Darcs.Diff ( cmp, sync )
import Workaround ( getCurrentDirectory )
import Darcs.SlurpDirectory ( Slurpy,  mmap_slurp, co_slurp )
import Darcs.Utils ( catchall )

import Darcs.PopulationData ( Population, getPopFrom )
import Darcs.Flags ( DarcsFlag( PristinePlain, PristineNone, UseHashedInventory, UseFormat2 ) )
import Darcs.IO ( WriteableDirectory(mWithCurrentDirectory) )
import Darcs.Patch ( Patchy, apply )
import Darcs.Patch.Info ( PatchInfo )
import FileName ( fp2fn )
import FastPackedString ( nilPS )
import SHA1 ( sha1PS )
import Darcs.External ( cloneTree, cloneTreeExcept, clonePartialsTree )
import Darcs.Repository.InternalTypes ( Pristine(..) )
import Darcs.Global ( darcsdir )
#include "impossible.h"

nopristine :: Pristine
nopristine = NoPristine "aack?"

pristineName :: String
pristineName = "pristine"

identifyPristine :: IO (Pristine)
identifyPristine = do mp <- reallyIdentifyPristine
                      case mp of
                          Nothing -> fail "Pristine tree doesn't exist."
                          Just pristine -> return pristine

reallyIdentifyPristine :: IO (Maybe Pristine)
reallyIdentifyPristine = 
    do dir <- findpristine doesDirectoryExist ""
       none <- findpristine doesFileExist ".none"
       hashinv <- doesFileExist $ darcsdir++"/hashed_inventory"
       hashpris <- doesDirectoryExist hashedPristineDirectory
       case (dir, none, hashinv && hashpris) of
           (Nothing, Nothing, False) -> return Nothing
           (Just n, Nothing, False) ->
               return (Just (PlainPristine n))
           (Nothing, Just n, False) ->
               return (Just (NoPristine n))
           (Nothing, Nothing, True) ->
               return (Just HashedPristine)
           _ -> fail "Multiple pristine trees."
    where findpristine fn ext =
              do e1 <- fn n1
                 e2 <- fn n2
                 case (e1, e2) of
                     (False, False) -> return Nothing
                     (True, False) -> return (Just n1)
                     (False, True) -> return (Just n2)
                     (True, True) -> fail "Multiple pristine trees."
              where  n1 = darcsdir++"/pristine" ++ ext
                     n2 = darcsdir++"/current" ++ ext

flagsToPristine :: [DarcsFlag] -> Pristine
flagsToPristine fs | UseFormat2 `elem` fs || UseHashedInventory `elem` fs = HashedPristine
flagsToPristine (PristineNone : _) = NoPristine (darcsdir++"/" ++ pristineName ++ ".none")
flagsToPristine (PristinePlain : _) = PlainPristine (darcsdir++"/" ++ pristineName)
flagsToPristine (_ : t) = flagsToPristine t
flagsToPristine [] = flagsToPristine [PristinePlain]

createPristine :: Pristine -> IO Pristine
createPristine p = 
    do oldpristine <- reallyIdentifyPristine
       when (isJust oldpristine) $ fail "Pristine tree already exists."
       case p of
           NoPristine n -> writeBinFile n "Do not delete this file.\n"
           PlainPristine n -> createDirectory n
           HashedPristine -> do createDirectory hashedPristineDirectory
                                writeFile (hashedPristineDirectory++"/"++sha1PS nilPS) ""
       return p

hashedPristineDirectory :: String
hashedPristineDirectory = darcsdir++"/pristine.hashed"

removePristine :: Pristine -> IO ()
removePristine (NoPristine n) = removeFile n
removePristine (PlainPristine n) = rm_recursive n
removePristine HashedPristine = rm_recursive hashedPristineDirectory

checkPristine :: FilePath -> Pristine -> IO Bool
checkPristine _ (NoPristine _) = return True
checkPristine path (PlainPristine n) = do cwd <- getCurrentDirectory
                                          cmp (cwd ++ "/" ++ n) path
checkPristine _ HashedPristine = 
    bug "HashedPristine is not implemented yet."

slurpPristine :: Pristine -> IO (Maybe Slurpy)
slurpPristine (PlainPristine n) = do cwd <- getCurrentDirectory
                                     slurpy <- mmap_slurp (cwd ++ "/" ++ n)
                                     return (Just slurpy)
slurpPristine (NoPristine _) = return Nothing
slurpPristine HashedPristine =
    bug "HashedPristine is not implemented yet."

applyPristine :: Patchy p => Pristine -> p C(x y) -> IO ()
applyPristine (NoPristine _) _ = return ()
-- We don't need flags for now, since we don't care about
-- SetScriptsExecutable for the pristine cache.
applyPristine (PlainPristine n) p =
    mWithCurrentDirectory (fp2fn n) $ apply [] p
applyPristine HashedPristine _ =
    bug "3 HashedPristine is not implemented yet."

createPristineFromWorking :: Pristine -> IO ()
createPristineFromWorking (NoPristine _) = return ()
createPristineFromWorking (PlainPristine n) = cloneTreeExcept [darcsdir] "." n
createPristineFromWorking HashedPristine =
    bug "HashedPristine is not implemented yet."

syncPristine :: Pristine -> IO ()
syncPristine (NoPristine _) = return ()
syncPristine (PlainPristine n) =
    do ocur <- mmap_slurp n
       owork <- co_slurp ocur "."
       sync n ocur owork
syncPristine HashedPristine = return () -- FIXME this should be implemented!

replacePristine :: FilePath -> Pristine -> IO ()
replacePristine _ (NoPristine _) = return ()
replacePristine newcur (PlainPristine n) =
    do rm_recursive nold
           `catchall` return ()
       renameDirectory n nold
       renameDirectory newcur n
       return ()
           where nold = darcsdir ++ "/" ++ pristineName ++ "-old"
replacePristine _ HashedPristine =
    bug "HashedPristine is not implemented yet."

getPristinePop :: PatchInfo -> Pristine -> IO (Maybe Population)
getPristinePop pinfo (PlainPristine n) =
    Just `liftM` getPopFrom n pinfo
getPristinePop _ _ = return Nothing

pristineDirectory :: Pristine -> Maybe String
pristineDirectory (PlainPristine n) = Just n
pristineDirectory _ = Nothing

pristineToFlagString :: Pristine -> String
pristineToFlagString (NoPristine _) = "--no-pristine-tree"
pristineToFlagString (PlainPristine _) = "--plain-pristine-tree"
pristineToFlagString HashedPristine =
    bug "HashedPristine is not implemented yet."

easyCreatePristineDirectoryTree :: Pristine -> FilePath -> IO Bool
easyCreatePristineDirectoryTree (NoPristine _) _ = return False
easyCreatePristineDirectoryTree (PlainPristine n) p
 = cloneTree n p >> return True
easyCreatePristineDirectoryTree HashedPristine _ =
    bug "HashedPristine is not implemented yet."

easyCreatePartialsPristineDirectoryTree :: [FilePath] -> Pristine -> FilePath
                                        -> IO Bool
easyCreatePartialsPristineDirectoryTree _ (NoPristine _) _ = return False
easyCreatePartialsPristineDirectoryTree prefs (PlainPristine n) p
 = clonePartialsTree n p prefs >> return True
easyCreatePartialsPristineDirectoryTree _ HashedPristine _ =
    bug "HashedPristine is not implemented yet."
\end{code}