mercurial/patch.py
changeset 2874 4ec58b157265
parent 2868 9a2a481ec3ea
child 2875 3d6efcbbd1c9
equal deleted inserted replaced
2873:5dd6631c8238 2874:4ec58b157265
     5 # This software may be used and distributed according to the terms
     5 # This software may be used and distributed according to the terms
     6 # of the GNU General Public License, incorporated herein by reference.
     6 # of the GNU General Public License, incorporated herein by reference.
     7 
     7 
     8 from demandload import demandload
     8 from demandload import demandload
     9 from i18n import gettext as _
     9 from i18n import gettext as _
    10 demandload(globals(), "util")
    10 from node import *
    11 demandload(globals(), "cStringIO email.Parser os re shutil tempfile")
    11 demandload(globals(), "cmdutil mdiff util")
       
    12 demandload(globals(), "cStringIO email.Parser os re shutil sys tempfile")
    12 
    13 
    13 def extract(ui, fileobj):
    14 def extract(ui, fileobj):
    14     '''extract patch from data read from fileobj.
    15     '''extract patch from data read from fileobj.
    15 
    16 
    16     patch can be normal patch or contained in email message.
    17     patch can be normal patch or contained in email message.
   247 
   248 
   248     for gp in gitpatches:
   249     for gp in gitpatches:
   249         files[gp.path] = (gp.op, gp)
   250         files[gp.path] = (gp.op, gp)
   250 
   251 
   251     return files
   252     return files
       
   253 
       
   254 def diff(repo, node1=None, node2=None, files=None, match=util.always,
       
   255          fp=None, changes=None, opts=None):
       
   256     '''print diff of changes to files between two nodes, or node and
       
   257     working directory.
       
   258 
       
   259     if node1 is None, use first dirstate parent instead.
       
   260     if node2 is None, compare node1 with working directory.'''
       
   261 
       
   262     if opts is None:
       
   263         opts = mdiff.defaultopts
       
   264     if fp is None:
       
   265         fp = repo.ui
       
   266 
       
   267     if not node1:
       
   268         node1 = repo.dirstate.parents()[0]
       
   269     # reading the data for node1 early allows it to play nicely
       
   270     # with repo.changes and the revlog cache.
       
   271     change = repo.changelog.read(node1)
       
   272     mmap = repo.manifest.read(change[0])
       
   273     date1 = util.datestr(change[2])
       
   274 
       
   275     if not changes:
       
   276         changes = repo.changes(node1, node2, files, match=match)
       
   277     modified, added, removed, deleted, unknown = changes
       
   278     if files:
       
   279         def filterfiles(filters):
       
   280             l = [x for x in files if x in filters]
       
   281 
       
   282             for t in filters:
       
   283                 if t and t[-1] != "/":
       
   284                     t += "/"
       
   285                 l += [x for x in files if x.startswith(t)]
       
   286             return l
       
   287 
       
   288         modified, added, removed = map(lambda x: filterfiles(x),
       
   289                                        (modified, added, removed))
       
   290 
       
   291     if not modified and not added and not removed:
       
   292         return
       
   293 
       
   294     if node2:
       
   295         change = repo.changelog.read(node2)
       
   296         mmap2 = repo.manifest.read(change[0])
       
   297         _date2 = util.datestr(change[2])
       
   298         def date2(f):
       
   299             return _date2
       
   300         def read(f):
       
   301             return repo.file(f).read(mmap2[f])
       
   302     else:
       
   303         tz = util.makedate()[1]
       
   304         _date2 = util.datestr()
       
   305         def date2(f):
       
   306             try:
       
   307                 return util.datestr((os.lstat(repo.wjoin(f)).st_mtime, tz))
       
   308             except OSError, err:
       
   309                 if err.errno != errno.ENOENT: raise
       
   310                 return _date2
       
   311         def read(f):
       
   312             return repo.wread(f)
       
   313 
       
   314     if repo.ui.quiet:
       
   315         r = None
       
   316     else:
       
   317         hexfunc = repo.ui.verbose and hex or short
       
   318         r = [hexfunc(node) for node in [node1, node2] if node]
       
   319 
       
   320     all = modified + added + removed
       
   321     all.sort()
       
   322     for f in all:
       
   323         to = None
       
   324         tn = None
       
   325         if f in mmap:
       
   326             to = repo.file(f).read(mmap[f])
       
   327         if f not in removed:
       
   328             tn = read(f)
       
   329         fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, opts=opts))
       
   330 
       
   331 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
       
   332            opts=None):
       
   333     '''export changesets as hg patches.'''
       
   334 
       
   335     total = len(revs)
       
   336     revwidth = max(map(len, revs))
       
   337 
       
   338     def single(node, seqno, fp):
       
   339         parents = [p for p in repo.changelog.parents(node) if p != nullid]
       
   340         if switch_parent:
       
   341             parents.reverse()
       
   342         prev = (parents and parents[0]) or nullid
       
   343         change = repo.changelog.read(node)
       
   344 
       
   345         if not fp:
       
   346             fp = cmdutil.make_file(repo, template, node, total=total,
       
   347                                    seqno=seqno, revwidth=revwidth)
       
   348         if fp not in (sys.stdout, repo.ui):
       
   349             repo.ui.note("%s\n" % fp.name)
       
   350 
       
   351         fp.write("# HG changeset patch\n")
       
   352         fp.write("# User %s\n" % change[1])
       
   353         fp.write("# Date %d %d\n" % change[2])
       
   354         fp.write("# Node ID %s\n" % hex(node))
       
   355         fp.write("# Parent  %s\n" % hex(prev))
       
   356         if len(parents) > 1:
       
   357             fp.write("# Parent  %s\n" % hex(parents[1]))
       
   358         fp.write(change[4].rstrip())
       
   359         fp.write("\n\n")
       
   360 
       
   361         diff(repo, prev, node, fp=fp, opts=opts)
       
   362         if fp not in (sys.stdout, repo.ui):
       
   363             fp.close()
       
   364 
       
   365     for seqno, cset in enumerate(revs):
       
   366         single(cset, seqno, fp)