1 --   Copyright (C) 2003-2004 Jan Scheffczyk and David Roundy
    2 --
    3 --   This program is free software; you can redistribute it and/or modify
    4 --   it under the terms of the GNU General Public License as published by
    5 --   the Free Software Foundation; either version 2, or (at your option)
    6 --   any later version.
    7 --
    8 --   This program is distributed in the hope that it will be useful,
    9 --   but WITHOUT ANY WARRANTY; without even the implied warranty of
   10 --   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   11 --   GNU General Public License for more details.
   12 --
   13 --   You should have received a copy of the GNU General Public License
   14 --   along with this program; see the file COPYING.  If not, write to
   15 --   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   16 --   Boston, MA 02110-1301, USA.
   17 
   18 module Darcs.PopulationData ( Population(..), PopTree(..), Info(..),
   19                         setPopState, notModified, setState,
   20                         DirMark(..), getPopFrom
   21                       ) where
   22 import Darcs.Patch.Info
   23 import Darcs.Utils ( withCurrentDirectory )
   24 import System.Directory ( doesDirectoryExist, getDirectoryContents )
   25 import qualified Data.ByteString.Char8 as BC
   26 import qualified Data.ByteString       as B (ByteString)
   27 
   28 -- | the population of a darcs repository (simpler Slurpy)
   29 data Population = Pop { popState :: PatchInfo -- ^ the state when last modified
   30                       , popTree  :: PopTree   -- ^ the directory listing
   31                       }
   32  deriving (Show, Eq)
   33 
   34 setPopState :: PatchInfo -> Population -> Population
   35 setPopState i (Pop _ tr) = Pop i tr
   36 
   37 -- | directory listing
   38 data PopTree = PopDir !Info ![PopTree]
   39              | PopFile !Info
   40  deriving ( Ord, Eq )
   41 
   42 -- | info of a directory member
   43 data DirMark = AddedFile | RemovedFile | MovedFile String
   44              | ModifiedFile | DullFile
   45              | AddedDir | RemovedDir | MovedDir !String | DullDir
   46                deriving ( Ord, Eq )
   47 data Info = Info {nameI :: !B.ByteString, -- ^ name of the element
   48                   modifiedByI :: !PatchInfo, -- ^ last patch modifying this element
   49                   modifiedHowI :: !DirMark, -- ^ how was it modified
   50                   createdByI :: !(Maybe PatchInfo), -- ^ this can be unknown when restored backwards!
   51                   creationNameI :: !(Maybe B.ByteString) -- ^ the original name of the element
   52                  }
   53  deriving ( Ord, Eq )
   54 
   55 -- | was an Info record not modified?
   56 notModified :: Info -> Bool
   57 notModified i = (modifiedHowI i == DullFile) || (modifiedHowI i == DullDir)
   58 
   59 -- | set the modifier for an Info record
   60 setState :: Info -> PatchInfo -> Info
   61 setState i pinfo = i { modifiedByI = pinfo }
   62 
   63 instance Show PopTree where
   64  show s = showPop "" s
   65 
   66 showPop :: String -> PopTree -> String
   67 showPop indent (PopDir i fs)
   68  = indent ++ show i ++ "\n" ++
   69    unlines (map (showPop (' ':indent)) fs)
   70 showPop indent (PopFile i)
   71  = indent ++ show i
   72 
   73 instance Show Info where
   74  show i = show (nameI i) ++ " " ++ show (modifiedHowI i) ++
   75           " at state " ++ show (modifiedByI i)
   76 
   77 instance Show DirMark where
   78  show AddedFile = "File added"
   79  show RemovedFile = "File removed"
   80  show (MovedFile s) = "File moved to " ++ s
   81  show ModifiedFile = "File modified"
   82  show DullFile = "File old"
   83  show AddedDir = "Dir added"
   84  show RemovedDir = "Dir removed"
   85  show (MovedDir s) = "Dir moved from " ++ s
   86  show DullDir = "Dir old"
   87 
   88 -- | read the population from a given directory @dirname@
   89 --   all folders and documents get the given time @t@
   90 --
   91 --  This needs to be here in order to avoid a circular dependency
   92 --  between Population and Pristine.
   93 getPopFrom :: FilePath -> PatchInfo -> IO Population
   94 getPopFrom the_directory pinfo =
   95     withCurrentDirectory the_directory $
   96        do popT <- getPopFrom_helper "."
   97           return (Pop pinfo popT)
   98  where getPopFrom_helper :: FilePath -> IO PopTree
   99        getPopFrom_helper dirname = do
  100         isdir <- doesDirectoryExist dirname
  101         let n = BC.pack dirname
  102         if isdir
  103           then do
  104            fnames <- getDirectoryContents dirname
  105            sl <- withCurrentDirectory dirname
  106                  (sequence $ map getPopFrom_helper $ filter not_hidden fnames)
  107            let i = Info {nameI = n,
  108                          modifiedByI = pinfo,
  109                          modifiedHowI = DullDir,
  110                          createdByI = Just pinfo,
  111                          creationNameI = Just n}
  112            return $ PopDir i sl
  113           else do let i = Info {nameI = n,
  114                                 modifiedByI = pinfo,
  115                                 modifiedHowI = DullFile,
  116                                 createdByI = Just pinfo,
  117                                 creationNameI = Just n}
  118                   return $ PopFile i
  119 
  120 not_hidden :: FilePath -> Bool
  121 not_hidden ('.':_) = False
  122 not_hidden ('_':_) = False
  123 not_hidden _ = True