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) |