fix tree graft-in bug

When adding a tree like a/b/c/d when a/b already exists, fixes the bug that
the tree that got created was a/b/a/b/c/d

Just need to flatten out the top N directories of the tree that's being
grafted in, so we get the c/d part. This was complicated by the Tree
data type being a rose tree rather than a regular tree.

This commit was sponsored by Nick Daly on Patreon.
This commit is contained in:
Joey Hess 2016-10-11 15:36:40 -04:00
parent 66ebf1a8f9
commit 3f25317ad5
No known key found for this signature in database
GPG key ID: C910D9222512E3C7
2 changed files with 23 additions and 11 deletions

View file

@ -143,6 +143,16 @@ treeItemsToTree = go M.empty
where where
parent = takeDirectory d parent = takeDirectory d
{- Flattens the top N levels of a Tree. -}
flattenTree :: Int -> Tree -> Tree
flattenTree 0 t = t
flattenTree n (Tree l) = Tree (concatMap (go n) l)
where
go 0 c = [c]
go _ b@(TreeBlob _ _ _) = [b]
go n' (RecordedSubTree _ _ l') = concatMap (go (n'-1)) l'
go n' (NewSubTree _ l') = concatMap (go (n'-1)) l'
{- Applies an adjustment to items in a tree. {- Applies an adjustment to items in a tree.
- -
- While less flexible than using getTree and recordTree, - While less flexible than using getTree and recordTree,
@ -163,42 +173,42 @@ adjustTree
adjustTree adjusttreeitem addtreeitems removefiles r repo = adjustTree adjusttreeitem addtreeitems removefiles r repo =
withMkTreeHandle repo $ \h -> do withMkTreeHandle repo $ \h -> do
(l, cleanup) <- liftIO $ lsTreeWithObjects r repo (l, cleanup) <- liftIO $ lsTreeWithObjects r repo
(l', _, _) <- go h False [] inTopTree l (l', _, _) <- go h False [] 1 inTopTree l
l'' <- adjustlist h inTopTree (const True) l' l'' <- adjustlist h 0 inTopTree (const True) l'
sha <- liftIO $ mkTree h l'' sha <- liftIO $ mkTree h l''
void $ liftIO cleanup void $ liftIO cleanup
return sha return sha
where where
go _ wasmodified c _ [] = return (c, wasmodified, []) go _ wasmodified c _ _ [] = return (c, wasmodified, [])
go h wasmodified c intree (i:is) go h wasmodified c depth intree (i:is)
| intree i = case readObjectType (LsTree.typeobj i) of | intree i = case readObjectType (LsTree.typeobj i) of
Just BlobObject -> do Just BlobObject -> do
let ti = TreeItem (LsTree.file i) (LsTree.mode i) (LsTree.sha i) let ti = TreeItem (LsTree.file i) (LsTree.mode i) (LsTree.sha i)
v <- adjusttreeitem ti v <- adjusttreeitem ti
case v of case v of
Nothing -> go h True c intree is Nothing -> go h True c depth intree is
Just ti'@(TreeItem f m s) -> Just ti'@(TreeItem f m s) ->
let !modified = wasmodified || ti' /= ti let !modified = wasmodified || ti' /= ti
blob = TreeBlob f m s blob = TreeBlob f m s
in go h modified (blob:c) intree is in go h modified (blob:c) depth intree is
Just TreeObject -> do Just TreeObject -> do
(sl, modified, is') <- go h False [] (beneathSubTree i) is (sl, modified, is') <- go h False [] (depth+1) (beneathSubTree i) is
sl' <- adjustlist h (inTree i) (beneathSubTree i) sl sl' <- adjustlist h depth (inTree i) (beneathSubTree i) sl
let slmodified = sl' /= sl let slmodified = sl' /= sl
subtree <- if modified || slmodified subtree <- if modified || slmodified
then liftIO $ recordSubTree h $ NewSubTree (LsTree.file i) sl' then liftIO $ recordSubTree h $ NewSubTree (LsTree.file i) sl'
else return $ RecordedSubTree (LsTree.file i) (LsTree.sha i) [] else return $ RecordedSubTree (LsTree.file i) (LsTree.sha i) []
let !modified' = modified || slmodified || wasmodified let !modified' = modified || slmodified || wasmodified
go h modified' (subtree : c) intree is' go h modified' (subtree : c) depth intree is'
_ -> error ("unexpected object type \"" ++ LsTree.typeobj i ++ "\"") _ -> error ("unexpected object type \"" ++ LsTree.typeobj i ++ "\"")
| otherwise = return (c, wasmodified, i:is) | otherwise = return (c, wasmodified, i:is)
adjustlist h ishere underhere l = do adjustlist h depth ishere underhere l = do
let (addhere, rest) = partition ishere addtreeitems let (addhere, rest) = partition ishere addtreeitems
let l' = filter (not . removed) $ let l' = filter (not . removed) $
map treeItemToTreeContent addhere ++ l map treeItemToTreeContent addhere ++ l
let inl i = any (\t -> beneathSubTree t i) l' let inl i = any (\t -> beneathSubTree t i) l'
let (Tree addunderhere) = treeItemsToTree $ let (Tree addunderhere) = flattenTree depth $ treeItemsToTree $
filter (\i -> underhere i && not (inl i)) rest filter (\i -> underhere i && not (inl i)) rest
addunderhere' <- liftIO $ mapM (recordSubTree h) addunderhere addunderhere' <- liftIO $ mapM (recordSubTree h) addunderhere
return (addunderhere'++l') return (addunderhere'++l')

View file

@ -86,3 +86,5 @@ the adjusted branch that adds the file back, but the file doesn't reach
the master branch in this scenario. the master branch in this scenario.
--[[Joey]] --[[Joey]]
Both bugs fixed now. [[done]] --[[Joey]]