-- Copyright (C) 2009 Petr Rockai---- Permission is hereby granted, free of charge, to any person-- obtaining a copy of this software and associated documentation-- files (the "Software"), to deal in the Software without-- restriction, including without limitation the rights to use, copy,-- modify, merge, publish, distribute, sublicense, and/or sell copies-- of the Software, and to permit persons to whom the Software is-- furnished to do so, subject to the following conditions:---- The above copyright notice and this permission notice shall be-- included in all copies or substantial portions of the Software.---- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND-- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS-- BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN-- ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN-- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE-- SOFTWARE.-- |-- Module : Darcs.Diff-- Copyright : 2009 Petr Rockai-- License : MIT-- Maintainer : darcs-devel@darcs.net-- Stability : experimental-- Portability : portablemoduleDarcs.Diff(treeDiff)whereimportqualifiedData.ByteString.Lazy.Char8asBLCimportqualifiedData.ByteStringasBSimportqualifiedData.ByteString.LazyasBLimportData.List(sortBy)importStorage.Hashed.Tree(diffTrees,zipTrees,TreeItem(..),Tree,readBlob,emptyBlob)importStorage.Hashed.AnchoredPath(AnchoredPath,anchorPath)importByteStringUtils(isFunky)importDarcs.Patch(PrimPatch,hunk,canonize,binary,addfile,rmfile,adddir,rmdir,invert)importDarcs.Repository.Prefs(FileType(..))importDarcs.Witnesses.Ordered(FL(..),(+>+))importDarcs.Witnesses.Sealed(Gap(..))#include "gadts.h"#include "impossible.h"dataDiffm=Added(TreeItemm)|Removed(TreeItemm)|Changed(TreeItemm)(TreeItemm)getDiff::AnchoredPath->Maybe(TreeItemm)->Maybe(TreeItemm)->(AnchoredPath,Diffm)getDiffpNothing(Justt)=(p,Addedt)getDiffp(Justfrom)(Justto)=(p,Changedfromto)getDiffp(Justt)Nothing=(p,Removedt)getDiff_NothingNothing=impossible-- zipTrees should never return thistreeDiff::forallmwprim.(Functorm,Monadm,Gapw,PrimPatchprim)=>(FilePath->FileType)->Treem->Treem->m(w(FLprim))treeDiffftt1t2=do(from,to)<-diffTreest1t2diffs<-mapM(uncurrydiff)$sortByorganise$zipTreesgetDifffromtoreturn$foldr(joinGap(+>+))(emptyGapNilFL)diffswhere-- sort into removes, changes, adds, with removes in reverse-path order-- and everything else in forward orderorganise::(AnchoredPath,Diffm)->(AnchoredPath,Diffm)->Orderingorganise(p1,Changed__)(p2,Changed__)=comparep1p2organise(p1,Added_)(p2,Added_)=comparep1p2organise(p1,Removed_)(p2,Removed_)=comparep2p1organise(_,Removed_)_=LTorganise_(_,Removed_)=GTorganise(_,Changed__)_=LTorganise_(_,Changed__)=GTdiff::AnchoredPath->Diffm->m(w(FLprim))diff_(Changed(SubTree_)(SubTree_))=return(emptyGapNilFL)diffp(Removed(SubTree_))=return$freeGap(rmdir(anchorPath""p):>:NilFL)diffp(Added(SubTree_))=return$freeGap(adddir(anchorPath""p):>:NilFL)diffp(Addedb'@(File_))=dodiff'<-diffp(Changed(FileemptyBlob)b')return$joinGap(:>:)(freeGap(addfile(anchorPath""p)))diff'diffp(Removeda'@(File_))=dodiff'<-diffp(Changeda'(FileemptyBlob))return$joinGap(+>+)diff'(freeGap(rmfile(anchorPath""p):>:NilFL))diffp(Changed(Filea')(Fileb'))=doa<-readBloba'b<-readBlobb'letpath=anchorPath""pcaseftpathofTextFile|no_bina&&no_binb->return$text_diffpathab_->return$ifa/=bthenfreeGap(binarypath(stricta)(strictb):>:NilFL)elseemptyGapNilFLdiffp_=fail$"Missing case at path "++showptext_diffpab|BL.nulla&&BL.nullb=emptyGapNilFL|BL.nulla=freeGap(diff_from_emptypb)|BL.nullb=freeGap(diff_to_emptypa)|otherwise=freeGap(line_diffp(linesBa)(linesBb))line_diffpab=canonize(hunkp1ab)diff_to_emptypx|BLC.lastx=='\n'=line_diffp(init$linesBx)[]|otherwise=line_diffp(linesBx)[BS.empty]diff_from_emptypx=invert(diff_to_emptypx)no_bin=not.isFunky.strict.BL.take4096linesB=mapstrict.BLC.split'\n'strict=BS.concat.BL.toChunks