def diff(orig, ui, repo, *args, **opts): """show a diff of the most recent revision against its parent from svn """ if not opts.get('svn', False) or opts.get('change', None): return orig(ui, repo, *args, **opts) meta = repo.svnmeta() hashes = meta.revmap.hashes() if not opts.get('rev', None): parent = repo.parents()[0] o_r = util.outgoing_revisions(repo, hashes, parent.node()) if o_r: parent = repo[o_r[-1]].parents()[0] opts['rev'] = ['%s:.' % node.hex(parent.node()), ] node1, node2 = cmdutil.revpair(repo, opts['rev']) baserev, _junk = hashes.get(node1, (-1, 'junk')) newrev, _junk = hashes.get(node2, (-1, 'junk')) it = patch.diff(repo, node1, node2, opts=patch.diffopts(ui, opts={'git': True, 'show_function': False, 'ignore_all_space': False, 'ignore_space_change': False, 'ignore_blank_lines': False, 'unified': True, 'text': False, })) ui.write(util.filterdiff(''.join(it), baserev, newrev))
def autodiff(ui, repo, *pats, **opts): diffopts = patch.diffopts(ui, opts) git = opts.get('git', 'no') brokenfiles = set() losedatafn = None if git in ('yes', 'no'): diffopts.git = git == 'yes' diffopts.upgrade = False elif git == 'auto': diffopts.git = False diffopts.upgrade = True elif git == 'warn': diffopts.git = False diffopts.upgrade = True def losedatafn(fn=None, **kwargs): brokenfiles.add(fn) return True elif git == 'abort': diffopts.git = False diffopts.upgrade = True def losedatafn(fn=None, **kwargs): raise util.Abort('losing data for %s' % fn) else: raise util.Abort('--git must be yes, no or auto') node1, node2 = cmdutil.revpair(repo, []) m = cmdutil.match(repo, pats, opts) it = patch.diff(repo, node1, node2, match=m, opts=diffopts, losedatafn=losedatafn) for chunk in it: ui.write(chunk) for fn in sorted(brokenfiles): ui.write('data lost for: %s\n' % fn)
def diff(orig, ui, repo, *args, **opts): """show a diff of the most recent revision against its parent from svn """ if not opts.get('svn', False) or opts.get('change', None): return orig(ui, repo, *args, **opts) meta = repo.svnmeta() hashes = meta.revmap.hashes() if not opts.get('rev', None): parent = repo.parents()[0] o_r = util.outgoing_revisions(repo, hashes, parent.node()) if o_r: parent = repo[o_r[-1]].parents()[0] opts['rev'] = [ '%s:.' % node.hex(parent.node()), ] node1, node2 = cmdutil.revpair(repo, opts['rev']) baserev, _junk = hashes.get(node1, (-1, 'junk')) newrev, _junk = hashes.get(node2, (-1, 'junk')) it = patch.diff(repo, node1, node2, opts=patch.diffopts(ui, opts={ 'git': True, 'show_function': False, 'ignore_all_space': False, 'ignore_space_change': False, 'ignore_blank_lines': False, 'unified': True, 'text': False, })) ui.write(util.filterdiff(''.join(it), baserev, newrev))
def _do_reload_status(self): """Clear out the existing ListStore model and reload it from the repository status. Also recheck and reselect files that remain in the list. """ self.repo.dirstate.invalidate() self.repo.invalidate() # The following code was copied from the status function in mercurial\commands.py # and modified slightly to work here # node2 is None (the working dir) when 0 or 1 rev is specificed self._node1, self._node2 = cmdutil.revpair(self.repo, self.opts.get('rev')) files, matchfn, anypats = cmdutil.matchpats(self.repo, self.pats, self.opts) cwd = (self.pats and self.repo.getcwd()) or '' modified, added, removed, deleted, unknown, ignored, clean = [ n for n in self.repo.status(node1=self._node1, node2=self._node2, files=files, match=matchfn, list_ignored=self.test_opt('ignored'), list_clean=self.test_opt('clean'))] changetypes = (('modified', 'M', modified), ('added', 'A', added), ('removed', 'R', removed), ('deleted', '!', deleted), ('unknown', '?', unknown), ('ignored', 'I', ignored)) explicit_changetypes = changetypes + (('clean', 'C', clean),) # List of the currently checked and selected files to pass on to the new data recheck = [entry[2] for entry in self.model if entry[0]] reselect = [self.model[iter][2] for iter in self.tree.get_selection().get_selected_rows()[1]] # Load the new data into the tree's model self.tree.hide() self.model.clear() for opt, char, changes in ([ct for ct in explicit_changetypes if self.test_opt(ct[0])] or changetypes) : for file in changes: file = util.localpath(file) self.model.append([file in recheck, char, toutf(file), file]) self._update_check_count() selection = self.tree.get_selection() selected = False for row in self.model: if row[2] in reselect: selection.select_iter(row.iter) selected = True if not selected: selection.select_path((0,)) self.tree.show() self.tree.grab_focus() return True
def view_file_rev(self, menuitem): 'User selected view file revision from the file list context menu' if not self.curfile: return rev = self.currev parents = [x.rev() for x in self.repo[rev].parents()] if len(parents) == 0: parent = rev-1 else: parent = parents[0] pair = '%u:%u' % (parent, rev) self._node1, self._node2 = cmdutil.revpair(self.repo, [pair]) self._view_files([self.curfile], False)
def _view_file_rev(self, menuitem): '''User selected view file revision from the file list context menu''' if not self.curfile: # ignore view events for the [Description] row return rev = self.currev parents = self.parents if len(parents) == 0: parent = rev-1 else: parent = parents[0] pair = '%u:%u' % (parent, rev) self._node1, self._node2 = cmdutil.revpair(self.repo, [pair]) self._view_file('M', self.curfile, force_left=False)
def _get_diffs(self, repository=None, filepath=None): diffs = [] for repo, root in self.repositories: if repository and root != repository: continue #commands.pull(thisui, user_repo) # The hg diff command returns the entire set of diffs as one big # chunk. The following code is lifted from the source (version # 1.2) as the method for getting the individual diffs. As such, # this is prone to break in the case of internal changes. We # should try and get an external method to do the same thing. node1, node2 = cmdutil.revpair(repo, None) match = cmdutil.match(repo, (), {}) repodiffs = [] for diff in patch.diff(repo, node1, node2, match=match, opts=patch.diffopts(self.ui)): diffheader = diff.split('\n')[0] filename = DIFF_FILE.match(diffheader).groups()[0] if filepath and filepath == filename: return {'repository':root, 'filename':filename, 'diff': highlight(diff, DiffLexer(), HtmlFormatter())} # Should I instantiate a single lexer and formatter and share them? repodiffs.append({'repository':root, 'filename':filename, 'diff': highlight(diff, DiffLexer(), HtmlFormatter())}) # At the repo level, we want to go through all found files and look # for related issues try: issues = yamltrak.issues([repo.root])[root] except KeyError: # There is no issue database, or maybe just no open issues... issues = {} for diff in repodiffs: relatedissues = yamltrak.relatedissues(repo.root, filename=diff['filename'], ids=issues.keys()) related = {} for issue in relatedissues: related[issue] = {'repo':root, 'title':issues[issue]['title']} diff['relatedissues'] = related diffs += repodiffs # Done collecting the diffs if filepath: # User wanted a specific diff, and we didn't find it. This # probably isn't the best exception, but it will have to do... raise LookupError return diffs
def get_repo_status(): # Create a new repo object repo = hg.repository(self.ui, path=self.repo.root) self.newrepo = repo self.subrepos = [] try: if self.mqmode and self.mode != 'status': # when a patch is applied, show diffs to parent of top patch qtip = repo['.'] n1 = qtip.parents()[0].node() n2 = None else: # node2 is None (working dir) when 0 or 1 rev is specified n1, n2 = cmdutil.revpair(repo, self.opts.get('rev')) except (util.Abort, error.RepoError), e: self.status_error = str(e) return
def status(self, path=None): "show changed files in the working directory" revs = None node1, node2 = revpair(self.repo, revs) cwd = (path and self.repo.getcwd()) or '' copy = {} states = 'modified added removed deleted unknown ignored clean'.split() show = states stat = self.repo.status(node1, node2, match(self.repo, path), 'ignored' in show, 'clean' in show, 'unknown' in show, ) changestates = zip(states, 'MAR!?IC', stat) for state, char, files in changestates: for f in files: yield f, state
def commits(ui, repo, *pats, **opts): node1, node2 = cmdutil.revpair(repo, opts.get('rev')) matcher = cmdutil.match(repo, pats, opts) cwd = (pats and repo.getcwd()) or '' modified, added, removed, deleted, unknown, ignored, clean = \ repo.status(node1=node1, node2=node2, match=matcher, unknown=True) changetypes = (('modified', 'M', modified), ('added', 'A', added), ('removed', 'R', removed), ('deleted', '!', deleted), ('unknown', '?', unknown), ) end = '\n' status_lines = [end] status_lines.append("%s %s%s" % (_pfx_root, repo.root, end)) for opt, char, changes in changetypes: format = "%s %s %%s%s" % (_pfx, char, end) for f in changes: status_lines.append(format % repo.pathto(f, cwd)) contents = cmdutil.logmessage(opts) if not contents: contents = ui.edit("".join(status_lines), opts['user']) sets = parse_changesets(contents) if sets is None: sys.exit(1) for i, (message, files) in enumerate(sets): print 'Committing set %d' % (i+1) print message for fn in files: print fn print m = match.match(repo.root, '', files, exact=True) if not opts['dry_run']: repo.commit(match=m, text=message, user=opts['user'], date=opts['date'], force=util.always)
def status(self, path=None): "show changed files in the working directory" revs = None node1, node2 = revpair(self.repo, revs) cwd = (path and self.repo.getcwd()) or '' copy = {} states = 'modified added removed deleted unknown ignored clean'.split() show = states stat = self.repo.status( node1, node2, match(self.repo, path), 'ignored' in show, 'clean' in show, 'unknown' in show, ) changestates = zip(states, 'MAR!?IC', stat) for state, char, files in changestates: for f in files: yield f, state
def prepare_display(self): self.currow = None self.graphview = None self.glog_parent = None node0, node1 = cmdutil.revpair(self.repo, self.opts.get('rev')) self.load_details(self.repo.changelog.rev(node0))
def dodiff(ui, repo, diffcmd, diffopts, pats, opts): '''Do the actuall diff: - copy to a temp structure if diffing 2 internal revisions - copy to a temp structure if diffing working revision with another one and more than 1 file is changed - just invoke the diff for a single file in the working dir ''' revs = opts.get('rev') change = opts.get('change') if revs and change: msg = _('cannot specify --rev and --change at the same time') raise util.Abort(msg) elif change: node2 = repo.lookup(change) node1 = repo[node2].parents()[0].node() else: node1, node2 = cmdutil.revpair(repo, revs) matcher = cmdutil.match(repo, pats, opts) modified, added, removed = repo.status(node1, node2, matcher)[:3] if not (modified or added or removed): return 0 tmproot = tempfile.mkdtemp(prefix='extdiff.') dir2root = '' try: # Always make a copy of node1 dir1 = snapshot(ui, repo, modified + removed, node1, tmproot)[0] changes = len(modified) + len(removed) + len(added) # If node2 in not the wc or there is >1 change, copy it if node2 or changes > 1: dir2, fns_and_mtime = snapshot(ui, repo, modified + added, node2, tmproot) else: # This lets the diff tool open the changed file directly dir2 = '' dir2root = repo.root fns_and_mtime = [] # If only one change, diff the files instead of the directories if changes == 1: if len(modified): dir1 = os.path.join(dir1, util.localpath(modified[0])) dir2 = os.path.join(dir2root, dir2, util.localpath(modified[0])) elif len(removed): dir1 = os.path.join(dir1, util.localpath(removed[0])) dir2 = os.devnull else: dir1 = os.devnull dir2 = os.path.join(dir2root, dir2, util.localpath(added[0])) cmdline = ('%s %s %s %s' % (util.shellquote(diffcmd), ' '.join(diffopts), util.shellquote(dir1), util.shellquote(dir2))) ui.debug(_('running %r in %s\n') % (cmdline, tmproot)) util.system(cmdline, cwd=tmproot) for copy_fn, working_fn, mtime in fns_and_mtime: if os.path.getmtime(copy_fn) != mtime: ui.debug( _('file changed while diffing. ' 'Overwriting: %s (src: %s)\n') % (working_fn, copy_fn)) util.copyfile(copy_fn, working_fn) return 1 finally: ui.note(_('cleaning up temp directory\n')) shutil.rmtree(tmproot)
def dodiff(ui, repo, diffcmd, diffopts, pats, opts): '''Do the actuall diff: - copy to a temp structure if diffing 2 internal revisions - copy to a temp structure if diffing working revision with another one and more than 1 file is changed - just invoke the diff for a single file in the working dir ''' revs = opts.get('rev') change = opts.get('change') args = ' '.join(diffopts) do3way = '$parent2' in args if revs and change: msg = _('cannot specify --rev and --change at the same time') raise util.Abort(msg) elif change: node2 = repo.lookup(change) node1a, node1b = repo.changelog.parents(node2) else: node1a, node2 = cmdutil.revpair(repo, revs) if not revs: node1b = repo.dirstate.parents()[1] else: node1b = nullid # Disable 3-way merge if there is only one parent if do3way: if node1b == nullid: do3way = False matcher = cmdutil.match(repo, pats, opts) mod_a, add_a, rem_a = map(set, repo.status(node1a, node2, matcher)[:3]) if do3way: mod_b, add_b, rem_b = map(set, repo.status(node1b, node2, matcher)[:3]) else: mod_b, add_b, rem_b = set(), set(), set() modadd = mod_a | add_a | mod_b | add_b common = modadd | rem_a | rem_b if not common: return 0 tmproot = tempfile.mkdtemp(prefix='extdiff.') try: # Always make a copy of node1a (and node1b, if applicable) dir1a_files = mod_a | rem_a | ((mod_b | add_b) - add_a) dir1a = snapshot(ui, repo, dir1a_files, node1a, tmproot)[0] if do3way: dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b) dir1b = snapshot(ui, repo, dir1b_files, node1b, tmproot)[0] else: dir1b = None fns_and_mtime = [] # If node2 in not the wc or there is >1 change, copy it dir2root = '' if node2: dir2 = snapshot(ui, repo, modadd, node2, tmproot)[0] elif len(common) > 1: #we only actually need to get the files to copy back to #the working dir in this case (because the other cases #are: diffing 2 revisions or single file -- in which case #the file is already directly passed to the diff tool). dir2, fns_and_mtime = snapshot(ui, repo, modadd, None, tmproot) else: # This lets the diff tool open the changed file directly dir2 = '' dir2root = repo.root # If only one change, diff the files instead of the directories # Handle bogus modifies correctly by checking if the files exist if len(common) == 1: common_file = util.localpath(common.pop()) dir1a = os.path.join(dir1a, common_file) if not os.path.isfile(os.path.join(tmproot, dir1a)): dir1a = os.devnull if do3way: dir1b = os.path.join(dir1b, common_file) if not os.path.isfile(os.path.join(tmproot, dir1b)): dir1b = os.devnull dir2 = os.path.join(dir2root, dir2, common_file) # Function to quote file/dir names in the argument string. # When not operating in 3-way mode, an empty string is # returned for parent2 replace = dict(parent=dir1a, parent1=dir1a, parent2=dir1b, child=dir2) def quote(match): key = match.group()[1:] if not do3way and key == 'parent2': return '' return util.shellquote(replace[key]) # Match parent2 first, so 'parent1?' will match both parent1 and parent regex = '\$(parent2|parent1?|child)' if not do3way and not re.search(regex, args): args += ' $parent1 $child' args = re.sub(regex, quote, args) cmdline = util.shellquote(diffcmd) + ' ' + args ui.debug('running %r in %s\n' % (cmdline, tmproot)) util.system(cmdline, cwd=tmproot) for copy_fn, working_fn, mtime in fns_and_mtime: if os.path.getmtime(copy_fn) != mtime: ui.debug('file changed while diffing. ' 'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn)) util.copyfile(copy_fn, working_fn) return 1 finally: ui.note(_('cleaning up temp directory\n')) shutil.rmtree(tmproot)
def dodiff(ui, repo, diffcmd, diffopts, pats, opts): '''Do the actuall diff: - copy to a temp structure if diffing 2 internal revisions - copy to a temp structure if diffing working revision with another one and more than 1 file is changed - just invoke the diff for a single file in the working dir ''' node1, node2 = cmdutil.revpair(repo, opts['rev']) files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) modified, added, removed, deleted, unknown = repo.status( node1, node2, files, match=matchfn)[:5] if not (modified or added or removed): return 0 tmproot = tempfile.mkdtemp(prefix='extdiff.') dir2root = '' try: # Always make a copy of node1 dir1 = snapshot_node(ui, repo, modified + removed, node1, tmproot) changes = len(modified) + len(removed) + len(added) fns_and_mtime = [] # If node2 in not the wc or there is >1 change, copy it if node2: dir2 = snapshot_node(ui, repo, modified + added, node2, tmproot) elif changes > 1: #we only actually need to get the files to copy back to the working #dir in this case (because the other cases are: diffing 2 revisions #or single file -- in which case the file is already directly passed #to the diff tool). dir2, fns_and_mtime = snapshot_wdir(ui, repo, modified + added, tmproot) else: # This lets the diff tool open the changed file directly dir2 = '' dir2root = repo.root # If only one change, diff the files instead of the directories if changes == 1 : if len(modified): dir1 = os.path.join(dir1, util.localpath(modified[0])) dir2 = os.path.join(dir2root, dir2, util.localpath(modified[0])) elif len(removed) : dir1 = os.path.join(dir1, util.localpath(removed[0])) dir2 = os.devnull else: dir1 = os.devnull dir2 = os.path.join(dir2root, dir2, util.localpath(added[0])) cmdline = ('%s %s %s %s' % (util.shellquote(diffcmd), ' '.join(diffopts), util.shellquote(dir1), util.shellquote(dir2))) ui.debug('running %r in %s\n' % (cmdline, tmproot)) util.system(cmdline, cwd=tmproot) for copy_fn, working_fn, mtime in fns_and_mtime: if os.path.getmtime(copy_fn) != mtime: ui.debug('File changed while diffing. ' 'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn)) util.copyfile(copy_fn, working_fn) return 1 finally: ui.note(_('cleaning up temp directory\n')) shutil.rmtree(tmproot)
def visualdiff(ui, repo, pats, opts): revs = opts.get('rev') change = opts.get('change') try: ctx1b = None if change: ctx2 = repo[change] p = ctx2.parents() if len(p) > 1: ctx1a, ctx1b = p else: ctx1a = p[0] else: n1, n2 = cmdutil.revpair(repo, revs) ctx1a, ctx2 = repo[n1], repo[n2] p = ctx2.parents() if not revs and len(p) > 1: ctx1b = p[1] except (error.LookupError, error.RepoError): gdialog.Prompt(_('Unable to find changeset'), _('You likely need to refresh this application'), None).run() return None pats = cmdutil.expandpats(pats) m = match.match(repo.root, '', pats, None, None, 'relpath') n2 = ctx2.node() mod_a, add_a, rem_a = map(set, repo.status(ctx1a.node(), n2, m)[:3]) if ctx1b: mod_b, add_b, rem_b = map(set, repo.status(ctx1b.node(), n2, m)[:3]) cpy = copies.copies(repo, ctx1a, ctx1b, ctx1a.ancestor(ctx1b))[0] else: cpy = copies.copies(repo, ctx1a, ctx2, repo[-1])[0] mod_b, add_b, rem_b = set(), set(), set() MA = mod_a | add_a | mod_b | add_b MAR = MA | rem_a | rem_b if not MAR: gdialog.Prompt(_('No file changes'), _('There are no file changes to view'), None).run() return None detectedtools = hglib.difftools(repo.ui) if not detectedtools: gdialog.Prompt(_('No diff tool found'), _('No visual diff tools were detected'), None).run() return None preferred = besttool(repo.ui, detectedtools) # Build tool list based on diff-patterns matches toollist = set() patterns = repo.ui.configitems('diff-patterns') patterns = [(p, t) for p,t in patterns if t in detectedtools] for path in MAR: for pat, tool in patterns: mf = match.match(repo.root, '', [pat]) if mf(path): toollist.add(tool) break else: toollist.add(preferred) cto = cpy.keys() for path in MAR: if path in cto: hascopies = True break else: hascopies = False force = repo.ui.configbool('tortoisehg', 'forcevdiffwin') if len(toollist) > 1 or (hascopies and len(MAR) > 1) or force: usewin = True else: preferred = toollist.pop() dirdiff = repo.ui.configbool('merge-tools', preferred + '.dirdiff') dir3diff = repo.ui.configbool('merge-tools', preferred + '.dir3diff') usewin = repo.ui.configbool('merge-tools', preferred + '.usewin') if not usewin and len(MAR) > 1: if ctx1b is not None: usewin = not dir3diff else: usewin = not dirdiff if usewin: # Multiple required tools, or tool does not support directory diffs sa = [mod_a, add_a, rem_a] sb = [mod_b, add_b, rem_b] dlg = FileSelectionDialog(repo, pats, ctx1a, sa, ctx1b, sb, ctx2, cpy) return dlg # We can directly use the selected tool, without a visual diff window diffcmd, diffopts, mergeopts = detectedtools[preferred] # Disable 3-way merge if there is only one parent or no tool support do3way = False if ctx1b: if mergeopts: do3way = True args = mergeopts else: args = diffopts if str(ctx1b.rev()) in revs: ctx1a = ctx1b else: args = diffopts def dodiff(tmproot): assert not (hascopies and len(MAR) > 1), \ 'dodiff cannot handle copies when diffing dirs' sa = [mod_a, add_a, rem_a] sb = [mod_b, add_b, rem_b] ctxs = [ctx1a, ctx1b, ctx2] # If more than one file, diff on working dir copy. copyworkingdir = len(MAR) > 1 dirs, labels, fns_and_mtimes = snapshotset(repo, ctxs, sa, sb, cpy, tmproot, copyworkingdir) dir1a, dir1b, dir2 = dirs label1a, label1b, label2 = labels fns_and_mtime = fns_and_mtimes[2] if len(MAR) > 1 and label2 == '': label2 = 'working files' def getfile(fname, dir, label): file = os.path.join(tmproot, dir, fname) if os.path.isfile(file): return fname+label, file nullfile = os.path.join(tmproot, 'empty') fp = open(nullfile, 'w') fp.close() return _nonexistant+label, nullfile # If only one change, diff the files instead of the directories # Handle bogus modifies correctly by checking if the files exist if len(MAR) == 1: file2 = util.localpath(MAR.pop()) if file2 in cto: file1 = util.localpath(cpy[file2]) else: file1 = file2 label1a, dir1a = getfile(file1, dir1a, label1a) if do3way: label1b, dir1b = getfile(file1, dir1b, label1b) label2, dir2 = getfile(file2, dir2, label2) if do3way: label1a += '[local]' label1b += '[other]' label2 += '[merged]' replace = dict(parent=dir1a, parent1=dir1a, parent2=dir1b, plabel1=label1a, plabel2=label1b, phash1=str(ctx1a), phash2=str(ctx1b), repo=hglib.get_reponame(repo), clabel=label2, child=dir2, chash=str(ctx2)) launchtool(diffcmd, args, replace, True) # detect if changes were made to mirrored working files for copy_fn, working_fn, mtime in fns_and_mtime: if os.path.getmtime(copy_fn) != mtime: ui.debug('file changed while diffing. ' 'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn)) util.copyfile(copy_fn, working_fn) def dodiffwrapper(): try: dodiff(tmproot) finally: ui.note(_('cleaning up temp directory\n')) try: shutil.rmtree(tmproot) except (IOError, OSError), e: # Leaking temporary files, fix your diff tool config ui.note(_('unable to clean temp directory: %s\n'), str(e))
def dodiff(ui, repo, diffcmd, diffopts, pats, opts): '''Do the actuall diff: - copy to a temp structure if diffing 2 internal revisions - copy to a temp structure if diffing working revision with another one and more than 1 file is changed - just invoke the diff for a single file in the working dir ''' revs = opts.get('rev') change = opts.get('change') if revs and change: msg = _('cannot specify --rev and --change at the same time') raise util.Abort(msg) elif change: node2 = repo.lookup(change) node1 = repo[node2].parents()[0].node() else: node1, node2 = cmdutil.revpair(repo, revs) matcher = cmdutil.match(repo, pats, opts) modified, added, removed = repo.status(node1, node2, matcher)[:3] if not (modified or added or removed): return 0 tmproot = tempfile.mkdtemp(prefix='extdiff.') dir2root = '' try: # Always make a copy of node1 dir1 = snapshot(ui, repo, modified + removed, node1, tmproot)[0] changes = len(modified) + len(removed) + len(added) # If node2 in not the wc or there is >1 change, copy it if node2 or changes > 1: dir2, fns_and_mtime = snapshot(ui, repo, modified + added, node2, tmproot) else: # This lets the diff tool open the changed file directly dir2 = '' dir2root = repo.root fns_and_mtime = [] # If only one change, diff the files instead of the directories if changes == 1 : if len(modified): dir1 = os.path.join(dir1, util.localpath(modified[0])) dir2 = os.path.join(dir2root, dir2, util.localpath(modified[0])) elif len(removed) : dir1 = os.path.join(dir1, util.localpath(removed[0])) dir2 = os.devnull else: dir1 = os.devnull dir2 = os.path.join(dir2root, dir2, util.localpath(added[0])) cmdline = ('%s %s %s %s' % (util.shellquote(diffcmd), ' '.join(diffopts), util.shellquote(dir1), util.shellquote(dir2))) ui.debug(_('running %r in %s\n') % (cmdline, tmproot)) util.system(cmdline, cwd=tmproot) for copy_fn, working_fn, mtime in fns_and_mtime: if os.path.getmtime(copy_fn) != mtime: ui.debug(_('file changed while diffing. ' 'Overwriting: %s (src: %s)\n') % (working_fn, copy_fn)) util.copyfile(copy_fn, working_fn) return 1 finally: ui.note(_('cleaning up temp directory\n')) shutil.rmtree(tmproot)