hgext/extdiff.py
changeset 8066 aece3c9e62f1
parent 8026 683d8ebcf434
parent 8065 66d0a03d3afc
child 8076 5ec526c1a32f
equal deleted inserted replaced
8060:84d0fe34427b 8066:aece3c9e62f1
    48 from mercurial.i18n import _
    48 from mercurial.i18n import _
    49 from mercurial.node import short
    49 from mercurial.node import short
    50 from mercurial import cmdutil, util, commands
    50 from mercurial import cmdutil, util, commands
    51 import os, shlex, shutil, tempfile
    51 import os, shlex, shutil, tempfile
    52 
    52 
    53 def snapshot_node(ui, repo, files, node, tmproot):
    53 def snapshot(ui, repo, files, node, tmproot):
    54     '''snapshot files as of some revision'''
    54     '''snapshot files as of some revision
       
    55     if not using snapshot, -I/-X does not work and recursive diff
       
    56     in tools like kdiff3 and meld displays too many files.'''
    55     dirname = os.path.basename(repo.root)
    57     dirname = os.path.basename(repo.root)
    56     if dirname == "":
    58     if dirname == "":
    57         dirname = "root"
    59         dirname = "root"
    58     dirname = '%s.%s' % (dirname, short(node))
    60     if node is not None:
       
    61         dirname = '%s.%s' % (dirname, short(node))
    59     base = os.path.join(tmproot, dirname)
    62     base = os.path.join(tmproot, dirname)
    60     os.mkdir(base)
    63     os.mkdir(base)
    61     ui.note(_('making snapshot of %d files from rev %s\n') %
    64     if node is not None:
    62             (len(files), short(node)))
    65         ui.note(_('making snapshot of %d files from rev %s\n') %
       
    66                 (len(files), short(node)))
       
    67     else:
       
    68         ui.note(_('making snapshot of %d files from working directory\n') %
       
    69             (len(files)))
       
    70     wopener = util.opener(base)
       
    71     fns_and_mtime = []
    63     ctx = repo[node]
    72     ctx = repo[node]
    64     for fn in files:
    73     for fn in files:
    65         wfn = util.pconvert(fn)
    74         wfn = util.pconvert(fn)
    66         if not wfn in ctx:
    75         if not wfn in ctx:
    67             # skipping new file after a merge ?
    76             # skipping new file after a merge ?
    68             continue
    77             continue
    69         ui.note('  %s\n' % wfn)
    78         ui.note('  %s\n' % wfn)
    70         dest = os.path.join(base, wfn)
    79         dest = os.path.join(base, wfn)
    71         destdir = os.path.dirname(dest)
    80         fctx = ctx[wfn]
    72         if not os.path.isdir(destdir):
    81         data = repo.wwritedata(wfn, fctx.data())
    73             os.makedirs(destdir)
    82         if 'l' in fctx.flags():
    74         data = repo.wwritedata(wfn, ctx[wfn].data())
    83             wopener.symlink(data, wfn)
    75         open(dest, 'wb').write(data)
    84         else:
    76     return dirname
    85             wopener(wfn, 'w').write(data)
    77 
    86             if 'x' in fctx.flags():
    78 
    87                 util.set_flags(dest, False, True)
    79 def snapshot_wdir(ui, repo, files, tmproot):
    88         if node is None:
    80     '''snapshot files from working directory.
    89             fns_and_mtime.append((dest, repo.wjoin(fn), os.path.getmtime(dest)))
    81     if not using snapshot, -I/-X does not work and recursive diff
       
    82     in tools like kdiff3 and meld displays too many files.'''
       
    83     dirname = os.path.basename(repo.root)
       
    84     if dirname == "":
       
    85         dirname = "root"
       
    86     base = os.path.join(tmproot, dirname)
       
    87     os.mkdir(base)
       
    88     ui.note(_('making snapshot of %d files from working directory\n') %
       
    89             (len(files)))
       
    90 
       
    91     fns_and_mtime = []
       
    92 
       
    93     for fn in files:
       
    94         wfn = util.pconvert(fn)
       
    95         ui.note('  %s\n' % wfn)
       
    96         dest = os.path.join(base, wfn)
       
    97         destdir = os.path.dirname(dest)
       
    98         if not os.path.isdir(destdir):
       
    99             os.makedirs(destdir)
       
   100 
       
   101         fp = open(dest, 'wb')
       
   102         for chunk in util.filechunkiter(repo.wopener(wfn)):
       
   103             fp.write(chunk)
       
   104         fp.close()
       
   105 
       
   106         fns_and_mtime.append((dest, repo.wjoin(fn), os.path.getmtime(dest)))
       
   107 
       
   108 
       
   109     return dirname, fns_and_mtime
    90     return dirname, fns_and_mtime
   110 
       
   111 
    91 
   112 def dodiff(ui, repo, diffcmd, diffopts, pats, opts):
    92 def dodiff(ui, repo, diffcmd, diffopts, pats, opts):
   113     '''Do the actuall diff:
    93     '''Do the actuall diff:
   114 
    94 
   115     - copy to a temp structure if diffing 2 internal revisions
    95     - copy to a temp structure if diffing 2 internal revisions
   137 
   117 
   138     tmproot = tempfile.mkdtemp(prefix='extdiff.')
   118     tmproot = tempfile.mkdtemp(prefix='extdiff.')
   139     dir2root = ''
   119     dir2root = ''
   140     try:
   120     try:
   141         # Always make a copy of node1
   121         # Always make a copy of node1
   142         dir1 = snapshot_node(ui, repo, modified + removed, node1, tmproot)
   122         dir1 = snapshot(ui, repo, modified + removed, node1, tmproot)[0]
   143         changes = len(modified) + len(removed) + len(added)
   123         changes = len(modified) + len(removed) + len(added)
   144 
   124 
   145         fns_and_mtime = []
       
   146 
       
   147         # If node2 in not the wc or there is >1 change, copy it
   125         # If node2 in not the wc or there is >1 change, copy it
   148         if node2:
   126         if node2 or changes > 1:
   149             dir2 = snapshot_node(ui, repo, modified + added, node2, tmproot)
   127             dir2, fns_and_mtime = snapshot(ui, repo, modified + added, node2, tmproot)
   150         elif changes > 1:
       
   151             #we only actually need to get the files to copy back to the working
       
   152             #dir in this case (because the other cases are: diffing 2 revisions
       
   153             #or single file -- in which case the file is already directly passed
       
   154             #to the diff tool).
       
   155             dir2, fns_and_mtime = snapshot_wdir(ui, repo, modified + added, tmproot)
       
   156         else:
   128         else:
   157             # This lets the diff tool open the changed file directly
   129             # This lets the diff tool open the changed file directly
   158             dir2 = ''
   130             dir2 = ''
   159             dir2root = repo.root
   131             dir2root = repo.root
       
   132             fns_and_mtime = []
   160 
   133 
   161         # If only one change, diff the files instead of the directories
   134         # If only one change, diff the files instead of the directories
   162         if changes == 1 :
   135         if changes == 1 :
   163             if len(modified):
   136             if len(modified):
   164                 dir1 = os.path.join(dir1, util.localpath(modified[0]))
   137                 dir1 = os.path.join(dir1, util.localpath(modified[0]))