Mercurial > public > mercurial-scm > hg
comparison hgext/extdiff.py @ 45126:48c38018bd77
extdiff: refactor logic which does diff of patches
The current extdiff code is hard to understand on first look. Took me few hours
to grasp the code. Before adding more things, decided to do some refactoring.
Differential Revision: https://phab.mercurial-scm.org/D8686
author | Pulkit Goyal <7895pulkit@gmail.com> |
---|---|
date | Tue, 07 Jul 2020 12:42:39 +0530 |
parents | 8e8fd938ca07 |
children | da2e69a278df |
comparison
equal
deleted
inserted
replaced
45125:f55099982bc5 | 45126:48c38018bd77 |
---|---|
348 with ui.timeblockedsection(b'extdiff'): | 348 with ui.timeblockedsection(b'extdiff'): |
349 for proc in waitprocs: | 349 for proc in waitprocs: |
350 proc.wait() | 350 proc.wait() |
351 | 351 |
352 | 352 |
353 def diffpatch(ui, repo, node1a, node2, tmproot, matcher, cmdline, do3way): | |
354 template = b'hg-%h.patch' | |
355 with formatter.nullformatter(ui, b'extdiff', {}) as fm: | |
356 cmdutil.export( | |
357 repo, | |
358 [repo[node1a].rev(), repo[node2].rev()], | |
359 fm, | |
360 fntemplate=repo.vfs.reljoin(tmproot, template), | |
361 match=matcher, | |
362 ) | |
363 label1a = cmdutil.makefilename(repo[node1a], template) | |
364 label2 = cmdutil.makefilename(repo[node2], template) | |
365 dir1a = repo.vfs.reljoin(tmproot, label1a) | |
366 dir2 = repo.vfs.reljoin(tmproot, label2) | |
367 dir1b = None | |
368 label1b = None | |
369 cmdline = formatcmdline( | |
370 cmdline, | |
371 repo.root, | |
372 do3way=do3way, | |
373 parent1=dir1a, | |
374 plabel1=label1a, | |
375 parent2=dir1b, | |
376 plabel2=label1b, | |
377 child=dir2, | |
378 clabel=label2, | |
379 ) | |
380 ui.debug(b'running %r in %s\n' % (pycompat.bytestr(cmdline), tmproot)) | |
381 ui.system(cmdline, cwd=tmproot, blockedtag=b'extdiff') | |
382 return 1 | |
383 | |
384 | |
353 def dodiff(ui, repo, cmdline, pats, opts, guitool=False): | 385 def dodiff(ui, repo, cmdline, pats, opts, guitool=False): |
354 '''Do the actual diff: | 386 '''Do the actual diff: |
355 | 387 |
356 - copy to a temp structure if diffing 2 internal revisions | 388 - copy to a temp structure if diffing 2 internal revisions |
357 - copy to a temp structure if diffing working revision with | 389 - copy to a temp structure if diffing working revision with |
414 if not common: | 446 if not common: |
415 return 0 | 447 return 0 |
416 | 448 |
417 tmproot = pycompat.mkdtemp(prefix=b'extdiff.') | 449 tmproot = pycompat.mkdtemp(prefix=b'extdiff.') |
418 try: | 450 try: |
419 if not opts.get(b'patch'): | 451 if opts.get(b'patch'): |
420 # Always make a copy of node1a (and node1b, if applicable) | 452 return diffpatch( |
421 dir1a_files = mod_a | rem_a | ((mod_b | add_b) - add_a) | 453 ui, repo, node1a, node2, tmproot, matcher, cmdline, do3way |
422 dir1a = snapshot(ui, repo, dir1a_files, node1a, tmproot, subrepos)[ | 454 ) |
455 | |
456 # Always make a copy of node1a (and node1b, if applicable) | |
457 dir1a_files = mod_a | rem_a | ((mod_b | add_b) - add_a) | |
458 dir1a = snapshot(ui, repo, dir1a_files, node1a, tmproot, subrepos)[0] | |
459 rev1a = b'@%d' % repo[node1a].rev() | |
460 if do3way: | |
461 dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b) | |
462 dir1b = snapshot(ui, repo, dir1b_files, node1b, tmproot, subrepos)[ | |
423 0 | 463 0 |
424 ] | 464 ] |
425 rev1a = b'@%d' % repo[node1a].rev() | 465 rev1b = b'@%d' % repo[node1b].rev() |
466 else: | |
467 dir1b = None | |
468 rev1b = b'' | |
469 | |
470 fnsandstat = [] | |
471 | |
472 # If node2 in not the wc or there is >1 change, copy it | |
473 dir2root = b'' | |
474 rev2 = b'' | |
475 if node2: | |
476 dir2 = snapshot(ui, repo, modadd, node2, tmproot, subrepos)[0] | |
477 rev2 = b'@%d' % repo[node2].rev() | |
478 elif len(common) > 1: | |
479 # we only actually need to get the files to copy back to | |
480 # the working dir in this case (because the other cases | |
481 # are: diffing 2 revisions or single file -- in which case | |
482 # the file is already directly passed to the diff tool). | |
483 dir2, fnsandstat = snapshot( | |
484 ui, repo, modadd, None, tmproot, subrepos | |
485 ) | |
486 else: | |
487 # This lets the diff tool open the changed file directly | |
488 dir2 = b'' | |
489 dir2root = repo.root | |
490 | |
491 label1a = rev1a | |
492 label1b = rev1b | |
493 label2 = rev2 | |
494 | |
495 # If only one change, diff the files instead of the directories | |
496 # Handle bogus modifies correctly by checking if the files exist | |
497 if len(common) == 1: | |
498 common_file = util.localpath(common.pop()) | |
499 dir1a = os.path.join(tmproot, dir1a, common_file) | |
500 label1a = common_file + rev1a | |
501 if not os.path.isfile(dir1a): | |
502 dir1a = pycompat.osdevnull | |
426 if do3way: | 503 if do3way: |
427 dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b) | 504 dir1b = os.path.join(tmproot, dir1b, common_file) |
428 dir1b = snapshot( | 505 label1b = common_file + rev1b |
429 ui, repo, dir1b_files, node1b, tmproot, subrepos | 506 if not os.path.isfile(dir1b): |
430 )[0] | 507 dir1b = pycompat.osdevnull |
431 rev1b = b'@%d' % repo[node1b].rev() | 508 dir2 = os.path.join(dir2root, dir2, common_file) |
432 else: | 509 label2 = common_file + rev2 |
433 dir1b = None | |
434 rev1b = b'' | |
435 | |
436 fnsandstat = [] | |
437 | |
438 # If node2 in not the wc or there is >1 change, copy it | |
439 dir2root = b'' | |
440 rev2 = b'' | |
441 if node2: | |
442 dir2 = snapshot(ui, repo, modadd, node2, tmproot, subrepos)[0] | |
443 rev2 = b'@%d' % repo[node2].rev() | |
444 elif len(common) > 1: | |
445 # we only actually need to get the files to copy back to | |
446 # the working dir in this case (because the other cases | |
447 # are: diffing 2 revisions or single file -- in which case | |
448 # the file is already directly passed to the diff tool). | |
449 dir2, fnsandstat = snapshot( | |
450 ui, repo, modadd, None, tmproot, subrepos | |
451 ) | |
452 else: | |
453 # This lets the diff tool open the changed file directly | |
454 dir2 = b'' | |
455 dir2root = repo.root | |
456 | |
457 label1a = rev1a | |
458 label1b = rev1b | |
459 label2 = rev2 | |
460 | |
461 # If only one change, diff the files instead of the directories | |
462 # Handle bogus modifies correctly by checking if the files exist | |
463 if len(common) == 1: | |
464 common_file = util.localpath(common.pop()) | |
465 dir1a = os.path.join(tmproot, dir1a, common_file) | |
466 label1a = common_file + rev1a | |
467 if not os.path.isfile(dir1a): | |
468 dir1a = pycompat.osdevnull | |
469 if do3way: | |
470 dir1b = os.path.join(tmproot, dir1b, common_file) | |
471 label1b = common_file + rev1b | |
472 if not os.path.isfile(dir1b): | |
473 dir1b = pycompat.osdevnull | |
474 dir2 = os.path.join(dir2root, dir2, common_file) | |
475 label2 = common_file + rev2 | |
476 else: | |
477 template = b'hg-%h.patch' | |
478 with formatter.nullformatter(ui, b'extdiff', {}) as fm: | |
479 cmdutil.export( | |
480 repo, | |
481 [repo[node1a].rev(), repo[node2].rev()], | |
482 fm, | |
483 fntemplate=repo.vfs.reljoin(tmproot, template), | |
484 match=matcher, | |
485 ) | |
486 label1a = cmdutil.makefilename(repo[node1a], template) | |
487 label2 = cmdutil.makefilename(repo[node2], template) | |
488 dir1a = repo.vfs.reljoin(tmproot, label1a) | |
489 dir2 = repo.vfs.reljoin(tmproot, label2) | |
490 dir1b = None | |
491 label1b = None | |
492 fnsandstat = [] | |
493 | 510 |
494 if not perfile: | 511 if not perfile: |
495 # Run the external tool on the 2 temp directories or the patches | 512 # Run the external tool on the 2 temp directories or the patches |
496 cmdline = formatcmdline( | 513 cmdline = formatcmdline( |
497 cmdline, | 514 cmdline, |