Mercurial > hg > mercurial-crew-with-dirclash
comparison mercurial/patch.py @ 2873:4ec58b157265
refactor text diff/patch code.
rename commands.dodiff to patch.diff.
rename commands.doexport to patch.export.
move some functions from commands to new mercurial.cmdutil module.
turn list of diff options into mdiff.diffopts class.
patch.diff and patch.export now has clean api for call from 3rd party
python code.
author | Vadim Gelfer <vadim.gelfer@gmail.com> |
---|---|
date | Sat, 12 Aug 2006 16:13:27 -0700 |
parents | 9a2a481ec3ea |
children | 3d6efcbbd1c9 |
comparison
equal
deleted
inserted
replaced
2872:5dd6631c8238 | 2873: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) |