darcs-2.18.5: src/Darcs/Patch/Set.hs
-- Copyright (C) 2003 David Roundy
--
-- 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.
module Darcs.Patch.Set
( PatchSet(..)
, Tagged(..)
, SealedPatchSet
, Origin
, progressPatchSet
, patchSetInventoryHashes
, patchSetTags
, emptyPatchSet
, appendPSFL
, patchSet2RL
, patchSet2FL
, inOrderTags
, patchSetSnoc
, patchSetSplit
, patchSetDrop
) where
import Darcs.Prelude
import Data.Maybe ( catMaybes )
import qualified Data.Set as S
import Darcs.Patch.Ident ( Ident(..), PatchId )
import Darcs.Patch.Info ( PatchInfo, piTag )
import Darcs.Patch.PatchInfoAnd ( PatchInfoAnd, info )
import Darcs.Patch.Witnesses.Sealed ( Sealed(..) )
import Darcs.Patch.Witnesses.Ordered
( FL, RL(..), (+<+), (+<<+), (:>)(..), reverseRL,
mapRL_RL, concatRL, mapRL )
import Darcs.Patch.Witnesses.Show ( Show1, Show2 )
import Darcs.Util.Progress ( progress )
import Darcs.Util.ValidHash ( InventoryHash )
-- |'Origin' is a type used to represent the initial context of a repo.
data Origin
type SealedPatchSet p wStart = Sealed ((PatchSet p) wStart)
-- |The patches in a repository are stored in chunks broken up at \"clean\"
-- tags. A tag is clean if the only patches before it in the current
-- repository ordering are ones that the tag depends on (either directly
-- or indirectly). Each chunk is stored in a separate inventory file on disk.
--
-- A 'PatchSet' represents a repo's history as the list of patches since the
-- last clean tag, and then a list of patch lists each delimited by clean tags.
--
-- Because the invariants about clean tags can only be maintained if a
-- 'PatchSet' contains the whole history, the first witness is always forced
-- to be 'Origin'. The type still has two witnesses so it can easily be used
-- with combinators like ':>' and 'Fork'.
--
-- The history is lazily loaded from disk so does not normally need to be all
-- kept in memory.
data PatchSet p wStart wY where
PatchSet :: RL (Tagged p) Origin wX -> RL (PatchInfoAnd p) wX wY
-> PatchSet p Origin wY
deriving instance Show2 p => Show (PatchSet p wStart wY)
instance Show2 p => Show1 (PatchSet p wStart)
instance Show2 p => Show2 (PatchSet p)
type instance PatchId (PatchSet p) = S.Set PatchInfo
instance Ident (PatchSet p) where
ident = S.fromList . mapRL ident . patchSet2RL
emptyPatchSet :: PatchSet p Origin Origin
emptyPatchSet = PatchSet NilRL NilRL
-- |A 'Tagged' is a single chunk of a 'PatchSet'.
-- It has a 'PatchInfo' representing a clean tag,
-- the hash of the previous inventory (if it exists),
-- and the list of patches since that previous inventory.
data Tagged p wX wZ where
Tagged :: RL (PatchInfoAnd p) wX wY -> PatchInfoAnd p wY wZ -> Maybe InventoryHash
-> Tagged p wX wZ
deriving instance Show2 p => Show (Tagged p wX wZ)
instance Show2 p => Show1 (Tagged p wX)
instance Show2 p => Show2 (Tagged p)
-- |'patchSet2RL' takes a 'PatchSet' and returns an equivalent, linear 'RL' of
-- patches.
patchSet2RL :: PatchSet p wStart wX -> RL (PatchInfoAnd p) wStart wX
patchSet2RL (PatchSet ts ps) = concatRL (mapRL_RL ts2rl ts) +<+ ps
where
ts2rl :: Tagged p wY wZ -> RL (PatchInfoAnd p) wY wZ
ts2rl (Tagged ps2 t _) = ps2 :<: t
-- |'patchSet2FL' takes a 'PatchSet' and returns an equivalent, linear 'FL' of
-- patches.
patchSet2FL :: PatchSet p wStart wX -> FL (PatchInfoAnd p) wStart wX
patchSet2FL = reverseRL . patchSet2RL
-- |'appendPSFL' takes a 'PatchSet' and a 'FL' of patches that "follow" the
-- PatchSet, and concatenates the patches into the PatchSet.
appendPSFL :: PatchSet p wStart wX -> FL (PatchInfoAnd p) wX wY
-> PatchSet p wStart wY
appendPSFL (PatchSet ts ps) newps = PatchSet ts (ps +<<+ newps)
-- |Runs a progress action for each tag and patch in a given PatchSet, using
-- the passed progress message. Does not alter the PatchSet.
progressPatchSet :: String -> PatchSet p wStart wX -> PatchSet p wStart wX
progressPatchSet k (PatchSet ts ps) =
PatchSet (mapRL_RL progressTagged ts) (mapRL_RL prog ps)
where
prog = progress k
progressTagged :: Tagged p wY wZ -> Tagged p wY wZ
progressTagged (Tagged tps t h) = Tagged (mapRL_RL prog tps) (prog t) h
patchSetInventoryHashes :: PatchSet p wX wY -> [Maybe InventoryHash]
patchSetInventoryHashes (PatchSet ts _) = mapRL (\(Tagged _ _ mh) -> mh) ts
-- | The tag names of /all/ tags of a given 'PatchSet'.
patchSetTags :: PatchSet p wX wY -> [String]
patchSetTags = catMaybes . mapRL (piTag . info) . patchSet2RL
inOrderTags :: PatchSet p wS wX -> [PatchInfo]
inOrderTags (PatchSet ts _) = go ts
where go :: RL(Tagged t1) wT wY -> [PatchInfo]
go (ts' :<: Tagged _ t _) = info t : go ts'
go NilRL = []
patchSetSnoc :: PatchSet p wX wY -> PatchInfoAnd p wY wZ -> PatchSet p wX wZ
patchSetSnoc (PatchSet ts ps) p = PatchSet ts (ps :<: p)
-- | Split a 'PatchSet' /before/ the latest known clean tag. The left part
-- is what comes before the tag, the right part is the tag and its
-- non-dependencies.
patchSetSplit :: PatchSet p wX wY
-> (PatchSet p :> RL (PatchInfoAnd p)) wX wY
patchSetSplit (PatchSet (ts :<: Tagged ps' t _) ps) =
PatchSet ts ps' :> ((NilRL :<: t) +<+ ps)
patchSetSplit (PatchSet NilRL ps) = PatchSet NilRL NilRL :> ps
-- | Drop the last @n@ patches from the given 'PatchSet'.
patchSetDrop :: Int
-> PatchSet p wStart wX
-> SealedPatchSet p wStart
patchSetDrop n ps | n <= 0 = Sealed ps
patchSetDrop n (PatchSet (ts :<: Tagged ps t _) NilRL) =
patchSetDrop n $ PatchSet ts (ps :<: t)
patchSetDrop _ (PatchSet NilRL NilRL) = Sealed $ PatchSet NilRL NilRL
patchSetDrop n (PatchSet ts (ps :<: _)) = patchSetDrop (n - 1) $ PatchSet ts ps