darcsden-1.1: src/DarcsDen/Handler/Repository/Forks.hs
{-# LANGUAGE ScopedTypeVariables, TypeFamilies, CPP #-}
module DarcsDen.Handler.Repository.Forks where
import Darcs.Patch.PatchInfoAnd (hopefully, info)
import Darcs.Patch.Depends (findUncommon)
import Darcs.Patch.Info (makeFilename)
import Darcs.Patch (getdeps)
import Darcs.Patch.Permutations
import Darcs.Repository
( RepoJob(..)
, applyToWorking
, finalizeRepositoryChanges
, identifyRepositoryFor
, invalidateIndex
, readRepo
, tentativelyMergePatches
#ifdef DARCS28
, withGutsOf
#endif
, withRepoLock
)
import qualified Darcs.Repository as R (Repository)
#ifdef DARCS28
import Darcs.Utils (withCurrentDirectory)
import Darcs.CommandsAux (checkPaths)
import Darcs.Flags as DUF (DarcsFlag(SkipConflicts))
import Darcs.SelectChanges (filterOutConflicts)
import Darcs.Witnesses.Ordered
import Darcs.Witnesses.Sealed
#else
import Darcs.Util.File (withCurrentDirectory)
import Darcs.Patch.Witnesses.Ordered ((:\/:)(..), (:>)(..), lengthFL, reverseFL, mapRL)
import Darcs.Patch.Witnesses.Sealed
import Darcs.UI.CommandsAux (checkPaths)
import qualified Darcs.Repository.Flags as DRF
import Darcs.Repository.State (filterOutConflicts)
#endif
import DarcsDen.Handler.Repository.Changes
import DarcsDen.State.Repository
import DarcsDen.State.Session
import DarcsDen.State.Util
data Fork =
Fork
{ fRepo :: Repository
, fPatches :: [PatchLog]
} deriving (Show)
getUpstreamChanges :: Repository -> IO (Maybe Fork)
getUpstreamChanges r = withParent (getForkChanges r) r
getDownstreamChanges :: Repository -> IO (Maybe Fork)
getDownstreamChanges r = withParent (flip getForkChanges r) r
-- Get patches that are in rOther but not r
getForkChanges :: Repository -> Repository -> IO Fork
getForkChanges rOther r = do
let pdir = repoDir (rOwner rOther) (rName rOther)
cdir = repoDir (rOwner r) (rName r)
#ifdef DARCS28
withCurrentDirectory pdir $ withRepoLock [] $ RepoJob $ \(pr :: R.Repository p wR wU wR) -> do
cr <- identifyRepositoryFor pr cdir
#else
withCurrentDirectory pdir $ withRepoLock DRF.NoDryRun DRF.YesUseCache DRF.YesUpdateWorking DRF.NoUMask $ RepoJob $ \(pr :: R.Repository p wR wU wR) -> do
cr <- identifyRepositoryFor pr DRF.YesUseCache cdir
#endif
pps <- readRepo pr
cps <- readRepo cr
let cs = case findUncommon pps cps of
_ :\/: them ->
let depends = map (\(p, ds) -> (makeFilename p, ds)) (findAllDeps (reverseFL them))
in mapRL
(\p ->
let l = toLog (info p, getdeps (hopefully p))
in case lookup (makeFilename (info p)) depends of
Just ds -> l{pDepends = map (take 20 . makeFilename) ds}
Nothing -> l)
(reverseFL them)
changes <- findUsers cs
return $ Fork r changes
mergePatches :: Repository -> Repository -> [String] -> Session -> IO Bool
mergePatches rDest r ps s = do
#ifdef DARCS28
withCurrentDirectory (origin rDest) $ withRepoLock [] $ RepoJob $ \(pr :: R.Repository p wR wU wR) -> do
cr <- identifyRepositoryFor pr fork
#else
withCurrentDirectory (origin rDest) $ withRepoLock DRF.NoDryRun DRF.YesUseCache DRF.YesUpdateWorking DRF.NoUMask $ RepoJob $ \(pr :: R.Repository p wR wU wR) -> do
cr <- identifyRepositoryFor pr DRF.YesUseCache fork
#endif
pps <- readRepo pr
cps <- readRepo cr
case findUncommon pps cps of
us :\/: them ->
case partitionFL ((`elem` ps) . take 20 . makeFilename . info) them of
chosen :> _ -> do
#ifdef DARCS28
(conflicts, Sealed merge) <- filterOutConflicts [DUF.SkipConflicts] (reverseFL us) pr chosen
#else
(conflicts, Sealed merge) <- filterOutConflicts (reverseFL us) pr chosen
#endif
if conflicts || lengthFL merge < length ps
then do
flip warn s . unwords $
[ "Patches for fork"
, "\"" ++ rOwner r ++ "/" ++ rName r ++ "\""
, "could not be applied cleanly and have been skipped."
]
return False
else do
checkPaths [] merge
#ifdef DARCS28
Sealed pw <- tentativelyMergePatches pr "pull" [] us merge
#else
Sealed pw <- tentativelyMergePatches pr "pull" DRF.NoAllowConflicts DRF.YesUpdateWorking DRF.NoExternalMerge DRF.NoWantGuiPause DRF.GzipCompression DRF.NormalVerbosity (DRF.UseIndex, DRF.ScanKnown) us merge
#endif
invalidateIndex pr
#ifdef DARCS28
withGutsOf pr $ do
finalizeRepositoryChanges pr
applyToWorking pr [] pw
return ()
#else
finalizeRepositoryChanges pr DRF.YesUpdateWorking DRF.GzipCompression
applyToWorking pr DRF.NormalVerbosity pw
#endif
return True
where
origin p = repoDir (rOwner p) (rName p)
fork = repoDir (rOwner r) (rName r)
canView :: Maybe String -> Repository -> Bool
canView _ Repository{rIsPrivate=False} = True
canView (Just user) r | user == rOwner r || user `elem` rMembers r = True
canView _ _ = False
canMerge :: Maybe String -> Repository -> Bool
canMerge Nothing _ = False
canMerge (Just user) r = user == rOwner r || user `elem` rMembers r