def new_commit(orig_commit, ui, repo, *pats, **opts): if opts['message'] or opts['logfile']: # don't act if user already specified a message return orig_commit(ui, repo, *pats, **opts) # check if changelog changed logname = ui.config('changelog', 'filename', 'CHANGES') if pats: match = cmdutil.match(repo, pats, opts) if logname not in match: # changelog is not mentioned return orig_commit(ui, repo, *pats, **opts) logmatch = cmdutil.match(repo, [logname], {}) logmatch.bad = lambda f, msg: None # don't complain if file is missing # get diff of changelog log = [] for chunk in patch.diff(repo, None, None, match=logmatch): for line in chunk.splitlines(): # naive: all added lines are the changelog if line.startswith('+') and not line.startswith('+++'): log.append(line[1:].rstrip().expandtabs()) log = normalize_log(log) # always let the user edit the message opts['force_editor'] = True opts['message'] = log return orig_commit(ui, repo, *pats, **opts)
def perfwalk(ui, repo, *pats): try: m = cmdutil.match(repo, pats, {}) timer(lambda: len(list(repo.dirstate.walk(m, True, False)))) except: try: m = cmdutil.match(repo, pats, {}) timer(lambda: len([b for a,b,c in repo.dirstate.statwalk([], m)])) except: timer(lambda: len(list(cmdutil.walk(repo, pats, {}))))
def perfwalk(ui, repo, *pats): try: m = cmdutil.match(repo, pats, {}) timer(lambda: len(list(repo.dirstate.walk(m, [], True, False)))) except: try: m = cmdutil.match(repo, pats, {}) timer(lambda: len([b for a, b, c in repo.dirstate.statwalk([], m)])) except: timer(lambda: len(list(cmdutil.walk(repo, pats, {}))))
def add(self, filepaths, dry_run=False, subrepo=None): "add the specified files on the next commit" m = match(self.repo, filepaths) prefix = "" uio = self.repo.ui rejected = cmdutil.add(uio, self.repo, m, dry_run, subrepo, prefix) return rejected
def cleanup(self, repo, pats, opts): '''removes all changes from the working copy and makes it so there isn't a patch applied''' # find added files in the user's chosen set m = cmdutil.match(repo, pats, opts) added = repo.status(match=m)[1] revertopts = { 'include': opts.get('include'), 'exclude': opts.get('exclude'), 'date': None, 'all': True, 'rev': '.', 'no_backup': True, } self.ui.pushbuffer() # silence revert try: commands.revert(self.ui, repo, *pats, **revertopts) # finish the job of reverting added files (safe because they are # saved in the attic patch) for fn in added: self.ui.status(_('removing %s\n') % fn) util.unlink(fn) finally: self.ui.popbuffer() self.applied = '' self.persiststate()
def search_thread(self, q, tgts, copy): hglib.invalidaterepo(self.repo) srcs = [] audit_path = util.path_auditor(self.repo.root) m = cmdutil.match(self.repo) for abs in self.repo.walk(m): target = self.repo.wjoin(abs) good = True try: audit_path(abs) except: good = False status = self.repo.dirstate[abs] if (not good or not os.path.lexists(target) or (os.path.isdir(target) and not os.path.islink(target))): srcs.append(abs) elif copy and status == 'n': # looking for copies, so any revisioned file is a # potential source (yes, this will be expensive) # Added and removed files are not considered as copy # sources. srcs.append(abs) if copy: simularity = 1.0 else: simularity = self.adjustment.get_value() / 100.0; gen = similar.findrenames(self.repo, tgts, srcs, simularity) for old, new, score in gen: q.put( [old, new, '%d%%' % (score*100)] )
def _casecollide(ui, repo, *pats, **opts): '''check the case of the given file against the repository. Return True on collisions and (optionally) print a list of problem-files.''' reserved = False colliding = False casefold = False override = opts['override'] or ui.configbool('caseguard', 'override') nowinchk = opts['nowincheck'] or ui.configbool('caseguard', 'nowincheck') if len(set(s.lower() for s in pats)) != len(pats): colliding = True ui.note(_('file list contains a possible case-fold collision\n')) added = repo.status()[1] + repo.status()[3] exclst = [item[0] for item in repo['.'].manifest().iteritems()] + added chklst = [item.lower() for item in exclst] mtch = dict(zip(chklst, exclst)) m = cmdutil.match(repo, pats, opts) for f in repo.walk(m): flwr = f.lower() reserved = _wincheck(ui, f) or _charcheck(ui, f) or reserved if f not in repo.dirstate and f not in exclst and flwr in mtch: colliding = True ui.note(_('adding %s may cause a case-fold collision with %s\n') % (f, mtch[flwr])) mtch[flwr] = f casefold = not override and ((reserved and not nowinchk) or colliding) return casefold, colliding, reserved and not nowinchk
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 impl_hg_tree(repo, cid, path, names, *args): m = cmdutil.match(repo, pats=[path], default=path) data = {} for name in names: rev_iter = cmdutil.walkchangerevs(repo, m, {'rev': cid}, lambda c,f: None) data[name] = rev_iter.next().hex() return data
def add(self, filepaths, dry_run=False, subrepo=None): "add the specified files on the next commit" m = match(self.repo, filepaths) prefix = "" uio = self.repo.ui rejected = cmdutil.add(uio, self.repo, m, dry_run, subrepo, prefix) return rejected
def _get_history_1_4(self, repo, pats, opts, limit): matcher = cmdutil.match(repo, pats, opts) if self.isfile: fncache = {} def prep(ctx, fns): if self.isfile: fncache[ctx.rev()] = fns[0] else: def prep(ctx, fns): pass # keep one lookahead entry so that we can detect renames path = self.path entry = None count = 1 for ctx in cmdutil.walkchangerevs(repo, matcher, opts, prep): if self.isfile and entry: path = fncache[ctx.rev()] if path != entry[0]: entry = entry[0:2] + (Changeset.COPY,) if entry: count += 1 yield entry entry = (path, self.repos.hg_display(ctx.node()), Changeset.EDIT) if entry: if count < limit: entry = entry[0:2] + (Changeset.ADD,) yield entry
def createpatch(self, repo, name, msg, user, date, pats=[], opts={}): """creates a patch from the current state of the working copy""" fp = self.opener(name, 'w') ctx = repo[None] fp.write('# HG changeset patch\n') if user: fp.write('# User %s\n' % user) if date: fp.write('# Date %d %d\n' % date) parents = [p.node() for p in ctx.parents() if p] if parents and parents[0]: fp.write('# Parent %s\n' % hex(parents[0])) if msg: if not isinstance(msg, str): msg = '\n'.join(msg) if msg and msg[-1] != '\n': msg += '\n' fp.write(msg) m = cmdutil.match(repo, pats, opts) chunks = patch.diff(repo, match = m, opts = self.diffopts(opts)) for chunk in chunks: fp.write(chunk) fp.close() self.currentpatch=name self.persiststate()
def createpatch(self, repo, name, msg, user, date, pats=[], opts={}): """creates a patch from the current state of the working copy""" fp = self.opener(name, 'w') ctx = repo[None] fp.write('# HG changeset patch\n') if user: fp.write('# User %s\n' % user) if date: fp.write('# Date %d %d\n' % date) parents = [p.node() for p in ctx.parents() if p] if parents and parents[0]: fp.write('# Parent %s\n' % hex(parents[0])) if msg: if not isinstance(msg, str): msg = '\n'.join(msg) if msg and msg[-1] != '\n': msg += '\n' fp.write(msg) m = cmdutil.match(repo, pats, opts) chunks = patch.diff(repo, match=m, opts=self.diffopts(opts)) for chunk in chunks: fp.write(chunk) fp.close() self.currentpatch = name self.persiststate()
def _casecollide(ui, repo, *pats, **opts): '''check the case of the given file against the repository. Return True on collisions and (optionally) print a list of problem-files.''' reserved = False colliding = False casefold = False override = opts['override'] or ui.configbool('caseguard', 'override') nowinchk = opts['nowincheck'] or ui.configbool('caseguard', 'nowincheck') if len(set(s.lower() for s in pats)) != len(pats): colliding = True ui.note(_('file list contains a possible case-fold collision\n')) added = repo.status()[1] + repo.status()[3] exclst = [item[0] for item in repo['.'].manifest().iteritems()] + added chklst = [item.lower() for item in exclst] mtch = dict(zip(chklst, exclst)) m = cmdutil.match(repo, pats, opts) for f in repo.walk(m): flwr = f.lower() reserved = _wincheck(ui, f) or _charcheck(ui, f) or reserved if f not in repo.dirstate and f not in exclst and flwr in mtch: colliding = True ui.note( _('adding %s may cause a case-fold collision with %s\n') % (f, mtch[flwr])) mtch[flwr] = f casefold = not override and ((reserved and not nowinchk) or colliding) return casefold, colliding, reserved and not nowinchk
def cleanup(self, repo, pats, opts): '''removes all changes from the working copy and makes it so there isn't a patch applied''' # find added files in the user's chosen set m = cmdutil.match(repo, pats, opts) added = repo.status(match=m)[1] revertopts = { 'include': opts.get('include'), 'exclude': opts.get('exclude'), 'date': None, 'all': True, 'rev': '.', 'no_backup': True, } self.ui.pushbuffer() # silence revert try: commands.revert(self.ui, repo, *pats, **revertopts) # finish the job of reverting added files (safe because they are # saved in the attic patch) for fn in added: self.ui.status(_('removing %s\n') % fn) util.unlink(fn) finally: self.ui.popbuffer() self.applied = '' self.persiststate()
def _modified_regions(repo, patterns, **kwargs): opt_all = kwargs.get('all', False) opt_no_ignore = kwargs.get('no_ignore', False) # Import the match (repository file name matching helper) # function. Different versions of Mercurial keep it in different # modules and implement them differently. try: from mercurial import scmutil m = scmutil.match(repo[None], patterns, kwargs) except ImportError: from mercurial import cmdutil m = cmdutil.match(repo, patterns, kwargs) modified, added, removed, deleted, unknown, ignore, clean = \ repo.status(match=m, clean=opt_all) if not opt_all: try: wctx = repo.workingctx() except: from mercurial import context wctx = context.workingctx(repo) files = [ (fn, all_regions) for fn in added ] + \ [ (fn, modregions(wctx, fn)) for fn in modified ] else: files = [ (fn, all_regions) for fn in added + modified + clean ] for fname, mod_regions in files: if opt_no_ignore or not check_ignores(fname): yield fname, mod_regions
def cacherepo(self, root, pats=[], filetypes="CI?"): status = ([],) * 7 try: repo = hg.repository(ui.ui(), path=root) matcher = cmdutil.match(repo, pats) st = repo.status(match=matcher, clean="C" in filetypes, ignored="I" in filetypes, unknown="?" in filetypes) except IOError: pass filelist = [] # concatenate status output into a single list, then sort on filename for l, s in ((st[0], "M"), (st[1], "A"), (st[2], "R"), (st[3], "!"), (st[4], "?"), (st[5], "I"), (st[6], "C")): for m in l: filelist.append([m, s]) filelist.sort() # Build tree data structure modelroot = dirnode() for name, filestatus in filelist: dirs, basename = self.split(name) curdir = modelroot for dir in dirs: if dir not in curdir.subdirs: curdir.addsubdir(dir) curdir.addstatus(filestatus) curdir = curdir.subdirs[dir] curdir.addfile(name, filestatus) self.cachedmodel = modelroot self.cachedroot = root self.cachedrepo = repo
def qrefresh_wrapper(self, repo, *pats, **opts): mqmessage = opts.pop('mqmessage', None) mqcommit, q, r = mqcommit_info(self, repo, opts) diffstat = "" if mqcommit and mqmessage: if mqmessage.find("%s") != -1: buffer = StringIO.StringIO() m = cmdutil.match(repo, None, {}) diffopts = mdiff.diffopts() cmdutil.diffordiffstat(self, repo, diffopts, repo.dirstate.parents()[0], None, m, stat=True, fp = buffer) diffstat = buffer.getvalue() buffer.close() mq.refresh(self, repo, *pats, **opts) if mqcommit and len(q.applied) > 0: patch = q.applied[-1].name if r is None: raise util.Abort("no patch repository found when using -Q option") mqmessage = mqmessage.replace("%p", patch) mqmessage = mqmessage.replace("%a", 'UPDATE') mqmessage = mqmessage.replace("%s", diffstat) commands.commit(r.ui, r, message=mqmessage)
def _casecollide(ui, repo, *pats, **opts): '''check the case of the given file against the repository. Return True on collisions and (optionally) print a list of problem-files.''' override = opts['override'] or ui.configbool('caseguard', 'override') nowinchk = opts['nowincheck'] or ui.configbool('caseguard', 'nowincheck') loglevel = _defaultloglevel(ui, not override) if len(set(s.lower() for s in pats)) != len(pats): colliding = True ui.note(_('file list contains a possible case-fold collision\n')) added = repo.status()[1] + repo.status()[3] exclst = [item[0] for item in repo['.'].manifest().iteritems()] + added chklst = [item.lower() for item in exclst] mtch = dict(zip(chklst, exclst)) m = cmdutil.match(repo, pats, opts) for f in repo.walk(m): flwr = f.lower() _wincheck(ui, f, loglevel) _charcheck(ui, f, loglevel) if f not in repo.dirstate and f not in exclst and flwr in mtch: loglevel(_('possible case-folding collision for %s') % f) mtch[flwr] = f
def casecheck(ui, repo, *pats, **opts): if not repo.local(): ui.note(_('Only local repositories can be checked')) return '''check an existing local repository for filename issues (caseguard)''' try: # Mercurial >= 1.9 m = scmutil.match(repo[0], pats, opts) except ImportError: # Mercurial <= 1.8 m = cmdutil.match(repo, pats, opts) seen = dict() def dostatus(msg): ui.status('%s\n' % msg) for f in repo.walk(m): if f in repo.dirstate: badname = _wincheck(ui, f, dostatus) or \ _charcheck(ui, f, dostatus) if f.lower() in seen: dostatus(_('%s collides with %s') % (f, seen[f.lower()])) else: seen[f.lower()] = f if not badname: ui.note(_('\t[OK] %s\n') % f)
def _modified_regions(repo, patterns, **kwargs): opt_all = kwargs.get('all', False) opt_no_ignore = kwargs.get('no_ignore', False) # Import the match (repository file name matching helper) # function. Different versions of Mercurial keep it in different # modules and implement them differently. try: from mercurial import scmutil m = scmutil.match(repo[None], patterns, kwargs) except ImportError: from mercurial import cmdutil m = cmdutil.match(repo, patterns, kwargs) modified, added, removed, deleted, unknown, ignore, clean = \ repo.status(match=m, clean=opt_all) if not opt_all: try: wctx = repo.workingctx() except: from mercurial import context wctx = context.workingctx(repo) files = [ (fn, all_regions) for fn in added ] + \ [ (fn, modregions(wctx, fn)) for fn in modified ] else: files = [(fn, all_regions) for fn in added + modified + clean] for fname, mod_regions in files: if opt_no_ignore or not check_ignores(fname): yield fname, mod_regions
def get_matcher(repo, pats=[], opts={}, showbad=True): '''Wrapper around cmdutil.match() that adds showbad: if false, neuter the match object\'s bad() method so it does not print any warnings about missing files or directories.''' match = cmdutil.match(repo, pats, opts) if not showbad: match.bad = lambda f, msg: None return match
def impl_hg_tree(repo, cid, path, names, *args): m = cmdutil.match(repo, pats=[path], default=path) data = {} for name in names: rev_iter = cmdutil.walkchangerevs( repo, m, {'rev': cid}, lambda c, f: None) data[name] = rev_iter.next().hex() return data
def get_matcher(repo, pats=[], opts={}, showbad=True): '''Wrapper around cmdutil.match() that adds showbad: if false, neuter the match object\'s bad() method so it does not print any warnings about missing files or directories.''' match = cmdutil.match(repo, pats, opts) if not showbad: match.bad = lambda f, msg: None return match
def _status(ui, repo, kwt, *pats, **opts): '''Bails out if [keyword] configuration is not active. Returns status of working directory.''' if kwt: return repo.status(match=cmdutil.match(repo, pats, opts), clean=True, unknown=opts.get('unknown') or opts.get('all')) if ui.configitems('keyword'): raise util.Abort(_('[keyword] patterns cannot match')) raise util.Abort(_('no [keyword] patterns configured'))
def commit(self, filepaths, message): "commit the specified files or all outstanding changes" oldid = self.repo[self.repo.lookup('.')] user = date = None m = match(self.repo, filepaths) node = self.repo.commit(message, user, date, m) if self.repo[self.repo.lookup('.')] == oldid: return None # no changes return True # sucess
def _status(ui, repo, kwt, unknown, *pats, **opts): '''Bails out if [keyword] configuration is not active. Returns status of working directory.''' if kwt: match = cmdutil.match(repo, pats, opts) return repo.status(match=match, unknown=unknown, clean=True) if ui.configitems('keyword'): raise util.Abort(_('[keyword] patterns cannot match')) raise util.Abort(_('no [keyword] patterns configured'))
def changedlines(ui, repo, ctx1, ctx2, fns): lines = 0 fmatch = cmdutil.match(repo, pats=fns) diff = ''.join(patch.diff(repo, ctx1.node(), ctx2.node(), fmatch)) for l in diff.split('\n'): if (l.startswith("+") and not l.startswith("+++ ") or l.startswith("-") and not l.startswith("--- ")): lines += 1 return lines
def commit(self, filepaths, message): "commit the specified files or all outstanding changes" oldid = self.repo[self.repo.lookup('.')] user = date = None m = match(self.repo, filepaths) node = self.repo.commit(message, user, date, m) if self.repo[self.repo.lookup('.')] == oldid: return None # no changes return True # sucess
def countrate(ui, repo, amap, *pats, **opts): """Calculate stats""" if opts.get('dateformat'): def getkey(ctx): t, tz = ctx.date() date = datetime.datetime(*time.gmtime(float(t) - tz)[:6]) return date.strftime(opts['dateformat']) else: tmpl = opts.get('template', '{author|email}') tmpl = maketemplater(ui, repo, tmpl) def getkey(ctx): ui.pushbuffer() tmpl.show(ctx) return ui.popbuffer() state = {'count': 0, 'pct': 0} rate = {} df = False if opts.get('date'): df = util.matchdate(opts['date']) m = cmdutil.match(repo, pats, opts) def prep(ctx, fns): rev = ctx.rev() if df and not df(ctx.date()[0]): # doesn't match date format return key = getkey(ctx) key = amap.get(key, key) # alias remap if opts.get('changesets'): rate[key] = (rate.get(key, (0,))[0] + 1, 0) else: parents = ctx.parents() if len(parents) > 1: ui.note(_('Revision %d is a merge, ignoring...\n') % (rev,)) return ctx1 = parents[0] lines = changedlines(ui, repo, ctx1, ctx, fns) rate[key] = [r + l for r, l in zip(rate.get(key, (0, 0)), lines)] if opts.get('progress'): state['count'] += 1 newpct = int(100.0 * state['count'] / max(len(repo), 1)) if state['pct'] < newpct: state['pct'] = newpct ui.write("\r" + _("generating stats: %d%%") % state['pct']) sys.stdout.flush() for ctx in cmdutil.walkchangerevs(repo, m, opts, prep): continue if opts.get('progress'): ui.write("\r") sys.stdout.flush() return rate
def cat(self, file1, revision=None): "return the current or given revision of a file" ctx = revsingle(self.repo, revision) m = match(self.repo, (file1, )) for abs in ctx.walk(m): data = ctx[abs].data() if self.decode: data = self.repo.wwritedata(abs, data) return data
def cat(self, file1, revision=None): "return the current or given revision of a file" ctx = revsingle(self.repo, revision) m = match(self.repo, (file1,)) for abs in ctx.walk(m): data = ctx[abs].data() if self.decode: data = self.repo.wwritedata(abs, data) return data
def changedlines(ui, repo, ctx1, ctx2, fns): lines = 0 fmatch = cmdutil.match(repo, pats=fns) diff = ''.join(patch.diff(repo, ctx1.node(), ctx2.node(), fmatch)) for l in diff.split('\n'): if (l.startswith("+") and not l.startswith("+++ ") or l.startswith("-") and not l.startswith("--- ")): lines += 1 return lines
def difftree(ui, repo, node1=None, node2=None, *files, **opts): """diff trees from two commits""" def __difftree(repo, node1, node2, files=[]): assert node2 is not None mmap = repo[node1].manifest() mmap2 = repo[node2].manifest() m = cmdutil.match(repo, files) modified, added, removed = repo.status(node1, node2, m)[:3] empty = short(nullid) for f in modified: # TODO get file permissions ui.write(":100664 100664 %s %s M\t%s\t%s\n" % (short(mmap[f]), short(mmap2[f]), f, f)) for f in added: ui.write(":000000 100664 %s %s N\t%s\t%s\n" % (empty, short(mmap2[f]), f, f)) for f in removed: ui.write(":100664 000000 %s %s D\t%s\t%s\n" % (short(mmap[f]), empty, f, f)) ## while True: if opts['stdin']: try: line = raw_input().split(' ') node1 = line[0] if len(line) > 1: node2 = line[1] else: node2 = None except EOFError: break node1 = repo.lookup(node1) if node2: node2 = repo.lookup(node2) else: node2 = node1 node1 = repo.changelog.parents(node1)[0] if opts['patch']: if opts['pretty']: catcommit(ui, repo, node2, "") m = cmdutil.match(repo, files) chunks = patch.diff(repo, node1, node2, match=m, opts=patch.diffopts(ui, {'git': True})) for chunk in chunks: ui.write(chunk) else: __difftree(repo, node1, node2, files=files) if not opts['stdin']: break
def countrate(ui, repo, amap, *pats, **opts): """Calculate stats""" if opts.get('dateformat'): def getkey(ctx): t, tz = ctx.date() date = datetime.datetime(*time.gmtime(float(t) - tz)[:6]) return date.strftime(opts['dateformat']) else: tmpl = opts.get('template', '{author|email}') tmpl = maketemplater(ui, repo, tmpl) def getkey(ctx): ui.pushbuffer() tmpl.show(ctx) return ui.popbuffer() state = {'count': 0} rate = {} df = False if opts.get('date'): df = util.matchdate(opts['date']) m = cmdutil.match(repo, pats, opts) def prep(ctx, fns): rev = ctx.rev() if df and not df(ctx.date()[0]): # doesn't match date format return key = getkey(ctx) key = amap.get(key, key) # alias remap key = key.strip() # ignore leading and trailing spaces if opts.get('changesets'): rate[key] = (rate.get(key, (0,))[0] + 1, 0) else: parents = ctx.parents() if len(parents) > 1: ui.note(_('Revision %d is a merge, ignoring...\n') % (rev,)) return ctx1 = parents[0] lines = changedlines(ui, repo, ctx1, ctx, fns) rate[key] = [r + l for r, l in zip(rate.get(key, (0, 0)), lines)] state['count'] += 1 ui.progress(_('analyzing'), state['count'], total=len(repo)) for ctx in cmdutil.walkchangerevs(repo, m, opts, prep): continue ui.progress(_('analyzing'), None) return rate
def difftree(ui, repo, node1=None, node2=None, *files, **opts): """diff trees from two commits""" def __difftree(repo, node1, node2, files=[]): assert node2 is not None mmap = repo[node1].manifest() mmap2 = repo[node2].manifest() m = cmdutil.match(repo, files) modified, added, removed = repo.status(node1, node2, m)[:3] empty = short(nullid) for f in modified: # TODO get file permissions ui.write(":100664 100664 %s %s M\t%s\t%s\n" % (short(mmap[f]), short(mmap2[f]), f, f)) for f in added: ui.write(":000000 100664 %s %s N\t%s\t%s\n" % (empty, short(mmap2[f]), f, f)) for f in removed: ui.write(":100664 000000 %s %s D\t%s\t%s\n" % (short(mmap[f]), empty, f, f)) ## while True: if opts['stdin']: try: line = raw_input().split(' ') node1 = line[0] if len(line) > 1: node2 = line[1] else: node2 = None except EOFError: break node1 = repo.lookup(node1) if node2: node2 = repo.lookup(node2) else: node2 = node1 node1 = repo.changelog.parents(node1)[0] if opts['patch']: if opts['pretty']: catcommit(ui, repo, node2, "") m = cmdutil.match(repo, files) chunks = patch.diff(repo, node1, node2, match=m, opts=patch.diffopts(ui, {'git': True})) for chunk in chunks: ui.write(chunk) else: __difftree(repo, node1, node2, files=files) if not opts['stdin']: break
def find_files_with_lib(dirname): """ Use the Mercurial library to recursively find versioned files in dirname. """ try: try: repo = hg.repository(ui.ui(), path=dirname) except RepoError: return # tuple of (modified, added, removed, deleted, unknown, ignored, clean) modified, added, removed, deleted, unknown = repo.status()[:5] # exclude all files that hg knows about, but haven't been added, # or have been deleted, removed, or have an unknown status excluded = removed + deleted + unknown if version in OLD_VERSIONS: from mercurial import util node = None for src, abs, rel, exact in cmdutil.walk(repo, [], {}, node=node, badmatch=util.always, default='relglob'): if src == 'b': continue if not node and abs not in repo.dirstate: continue if abs in excluded: continue yield abs else: rev = None try: match = cmdutil.match(repo, [], {}, default='relglob') except: # Probably mercurial 1.8+ from mercurial import scmutil match = scmutil.match(repo[None], [], {}, default='relglob') match.bad = lambda x, y: False for abs in repo[rev].walk(match): if not rev and abs not in repo.dirstate: continue if abs in excluded: continue yield abs except Exception: if log: log.warn("Error in setuptools_hg: %s" % sys.exc_info()[1]) # try calling hg command as a last resort find_files_with_cmd(dirname)
def find_files_with_lib(dirname): """ Use the Mercurial library to recursively find versioned files in dirname. """ try: try: repo = hg.repository(ui.ui(), path=dirname) except RepoError: return # tuple of (modified, added, removed, deleted, unknown, ignored, clean) modified, added, removed, deleted, unknown = repo.status()[:5] # exclude all files that hg knows about, but haven't been added, # or have been deleted, removed, or have an unknown status excluded = removed + deleted + unknown if version in OLD_VERSIONS: from mercurial import util node = None for src, abs, rel, exact in cmdutil.walk(repo, [], {}, node=node, badmatch=util.always, default="relglob"): if src == "b": continue if not node and abs not in repo.dirstate: continue if abs in excluded: continue yield abs else: rev = None try: match = cmdutil.match(repo, [], {}, default="relglob") except: # Probably mercurial 1.8+ from mercurial import scmutil match = scmutil.match(repo[None], [], {}, default="relglob") match.bad = lambda x, y: False for abs in repo[rev].walk(match): if not rev and abs not in repo.dirstate: continue if abs in excluded: continue yield abs except Exception, e: if log: log.warn("Error in setuptools_hg: %s" % e) # try calling hg command as a last resort find_files_with_cmd(dirname)
def getmatcher(repo, pats=[], opts={}, showbad=True): """Wrapper around scmutil.match() that adds showbad: if false, neuter the match object\'s bad() method so it does not print any warnings about missing files or directories.""" try: # Mercurial >= 1.9 match = scmutil.match(repo[None], pats, opts) except ImportError: # Mercurial <= 1.8 match = cmdutil.match(repo, pats, opts) if not showbad: match.bad = lambda f, msg: None return match
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 override_forget(orig, ui, repo, *pats, **opts): wctx = repo[None].manifest() oldmatch = cmdutil.match def override_match(repo, pats=[], opts={}, globbed=False, default='relpath'): match = oldmatch(repo, pats, opts, globbed, default) m = copy.copy(match) notbfile = lambda f: not bfutil.is_standin(f) and bfutil.standin(f) not in wctx m._files = [f for f in m._files if notbfile(f)] m._fmap = set(m._files) orig_matchfn = m.matchfn m.matchfn = lambda f: orig_matchfn(f) and notbfile(f) return m cmdutil.match = override_match orig(ui, repo, *pats, **opts) cmdutil.match = oldmatch m = cmdutil.match(repo, pats, opts) try: repo.bfstatus = True s = repo.status(match=m, clean=True) finally: repo.bfstatus = False forget = sorted(s[0] + s[1] + s[3] + s[6]) forget = [f for f in forget if bfutil.standin(f) in wctx] for f in forget: if bfutil.standin(f) not in repo.dirstate and not os.path.isdir(m.rel(bfutil.standin(f))): ui.warn(_('not removing %s: file is already untracked\n') % m.rel(f)) for f in forget: if ui.verbose or not m.exact(f): ui.status(_('removing %s\n') % m.rel(f)) # Need to lock because standin files are deleted then removed from the repository # and we could race inbetween. wlock = repo.wlock() try: bfdirstate = bfutil.open_bfdirstate(ui, repo) for f in forget: bfdirstate.remove(bfutil.unixpath(f)) bfdirstate.write() bfutil.repo_remove(repo, [bfutil.standin(f) for f in forget], unlink=True) finally: wlock.release()
def pdiff(self, pats, opts, parent=None): 'Return diffs relative to PARENT, as best as we can make out' parent = self.parent(parent) act = self.active(parent) # # act.localtip maybe nil, in the case of uncommitted local # changes. # if not act.revs: return matchfunc = cmdutil.match(self.repo, pats, opts) opts = patch.diffopts(self.ui, opts) return self.diff(act.parenttip.node(), act.localtip.node(), match=matchfunc, opts=opts)
def __difftree(repo, node1, node2, files=[]): assert node2 is not None mmap = repo[node1].manifest() mmap2 = repo[node2].manifest() m = cmdutil.match(repo, files) modified, added, removed = repo.status(node1, node2, m)[:3] empty = short(nullid) for f in modified: # TODO get file permissions ui.write(":100664 100664 %s %s M\t%s\t%s\n" % (short(mmap[f]), short(mmap2[f]), f, f)) for f in added: ui.write(":000000 100664 %s %s N\t%s\t%s\n" % (empty, short(mmap2[f]), f, f)) for f in removed: ui.write(":100664 000000 %s %s D\t%s\t%s\n" % (short(mmap[f]), empty, f, f))
def __difftree(repo, node1, node2, files=[]): assert node2 is not None mmap = repo[node1].manifest() mmap2 = repo[node2].manifest() m = cmdutil.match(repo, files) modified, added, removed = repo.status(node1, node2, m)[:3] empty = short(nullid) for f in modified: # TODO get file permissions ui.write(":100664 100664 %s %s M\t%s\t%s\n" % (short(mmap[f]), short(mmap2[f]), f, f)) for f in added: ui.write(":000000 100664 %s %s N\t%s\t%s\n" % (empty, short(mmap2[f]), f, f)) for f in removed: ui.write(":100664 000000 %s %s D\t%s\t%s\n" % (short(mmap[f]), empty, f, f))
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 casecheck(ui, repo, *pats, **opts): if not repo.local(): ui.note(_('Only local repositories can be checked')) return '''check an existing local repository for filename issues (caseguard)''' m = cmdutil.match(repo, pats, opts) seen = dict() for f in repo.walk(m): if f in repo.dirstate: badname = _wincheck(ui, f, ui.status) or \ _charcheck(ui, f, ui.status) if f.lower() in seen: ui.status(_('%s collides with %s\n') % (f, seen[f.lower()])) else: seen[f.lower()] = f if not badname: ui.note(_('\t[OK] %s\n') % f)
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 casecheck(ui, repo, *pats, **opts): if not repo.local(): ui.note(_('Only local repositories can be checked')) return '''check an existing local repository for filename issues (caseguard)''' m = cmdutil.match(repo, pats, opts) seen = dict() for f in repo.walk(m): if f in repo.dirstate: badname = _wincheck(ui, f, ui.status) or \ _charcheck(ui, f, ui.status) if f.lower() in seen: ui.status(_('%s collides with %s\n') % (f, seen[f.lower()])) else: seen[f.lower()] = f if not badname: ui.note(_('\t[OK] %s\n') % f)
def get_hg_file(repo, file_name, rev, tmp_file_name, dump_to_file = False): """ INTERNAL: read a file from the hg repo. If dump_to_file, the data is written into tmp_file_name. Otherwise, the data is returned and tmp_file_name is deleted. """ #print "get_hg_file -- ", file_name, rev file_name = os.path.join(repo.root, file_name) ctx = repo[rev] bytes = None err = True matches = cmdutil.match(repo, (file_name,)) for abs_ in ctx.walk(matches): assert err # Wacky. Why are we looping again? # REDFLAG: ripped out decode code. Will I need that on windows? file_ptr = None # Hmmmm starting to look like crappy Java code :-( in_file = None try: file_ptr = cmdutil.make_file(repo, tmp_file_name, ctx.node(), pathname=abs_) file_ptr.write(ctx[abs_].data()) file_ptr.close() file_ptr = None if not dump_to_file: in_file = open(tmp_file_name) bytes = in_file.read() finally: if file_ptr: file_ptr.close() if in_file: in_file.close() if not dump_to_file and os.path.exists(tmp_file_name): os.remove(tmp_file_name) err = False if err: raise KeyError("File: %s doesn't exist in version: %s" \ % (file_name, rev)) if dump_to_file: return "The data was written into: %s" % tmp_file_name return bytes
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 matcher(self, pats=None, opts=None, files=None): '''Return a match object suitable for Mercurial based on specified criteria. If files is specified it is a list of pathnames relative to the repository root to be matched precisely. If pats and/or opts are specified, these are as to cmdutil.match''' of_patterns = pats is not None or opts is not None of_files = files is not None opts = opts or {} # must be a dict assert not (of_patterns and of_files) if of_patterns: return cmdutil.match(self.repo, pats, opts) elif of_files: return cmdutil.matchfiles(self.repo, files) else: return cmdutil.matchall(self.repo)
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 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 rdiff(ui, repo, url, lrev=None, rrev=None, *pats, **opts): def rui(): try: return hg.remoteui(repo, opts) except AttributeError: # pre 1.6 return cmdutil.remoteui(repo, opts) try: other = getpeer(rui(), {}, url) except AttributeError: # pre-1.3 other = hg.repository(ui, url) cmdutil.setremoteconfig(ui, opts) ui.status(_('comparing with %s\n') % url) if rrev: if capable(other, 'lookup'): rrev = other.lookup(rrev) else: error = _( "Other repository doesn't support revision lookup, so a rev cannot be specified." ) raise util.Abort(error) incoming = findincomingfn(repo)(other, heads=rrev and [rrev] or []) if not incoming: # remote is a subset of local if not rrev: if capable(other, 'lookup'): rrev = other.lookup('tip') else: raise util.Abort(_('cannot determine remote tip')) other = repo bundle = None try: if incoming: # create a bundle (uncompressed if other repo is not local) if not rrev: cg = other.changegroup(incoming, "incoming") else: if not capable(other, 'changegroupsubset'): raise util.Abort( _("Partial incoming cannot be done because other repository doesn't support changegroupsubset." )) cg = other.changegroupsubset(incoming, rrev and [rrev] or [], 'incoming') bundle = changegroup.writebundle(cg, '', 'HG10UN') other = hg.repository(ui, bundle) if lrev: lrev = repo.changectx(lrev).node() rrev = other.changectx(rrev or 'tip').node() if opts['reverse']: lrev, rrev = rrev, lrev if not lrev: # bundle dirstate removed prior to hg 1.1 lrev = repo.dirstate.parents()[0] try: try: # scmutil.match expects a context not a repo m = scmutil.match(repo[None], pats, opts) except (ImportError, AttributeError): m = cmdutil.match(repo, pats, opts) chunks = patch.diff(other, lrev, rrev, match=m, opts=patch.diffopts(ui, opts)) for chunk in chunks: ui.write(chunk) except AttributeError: # 1.0 compatibility fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) patch.diff(other, lrev, rrev, fns, match=matchfn, opts=patch.diffopts(ui, opts)) finally: if hasattr(other, 'close'): other.close() if bundle: os.unlink(bundle)
def purge(ui, repo, *dirs, **opts): '''removes files not tracked by Mercurial Delete files not known to Mercurial. This is useful to test local and uncommitted changes in an otherwise-clean source tree. This means that purge will delete: - Unknown files: files marked with "?" by "hg status" - Empty directories: in fact Mercurial ignores directories unless they contain files under source control management But it will leave untouched: - Modified and unmodified tracked files - Ignored files (unless --all is specified) - New files added to the repository (with "hg add") If directories are given on the command line, only files in these directories are considered. Be careful with purge, as you could irreversibly delete some files you forgot to add to the repository. If you only want to print the list of files that this program would delete, use the --print option. ''' act = not opts['print'] eol = '\n' if opts['print0']: eol = '\0' act = False # --print0 implies --print def remove(remove_func, name): if act: try: remove_func(repo.wjoin(name)) except OSError: m = _('%s cannot be removed') % name if opts['abort_on_err']: raise util.Abort(m) ui.warn(_('warning: %s\n') % m) else: ui.write('%s%s' % (name, eol)) def removefile(path): try: os.remove(path) except OSError: # read-only files cannot be unlinked under Windows s = os.stat(path) if (s.st_mode & stat.S_IWRITE) != 0: raise os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE) os.remove(path) directories = [] match = cmdutil.match(repo, dirs, opts) match.dir = directories.append status = repo.status(match=match, ignored=opts['all'], unknown=True) for f in sorted(status[4] + status[5]): ui.note(_('Removing file %s\n') % f) remove(removefile, f) for f in sorted(directories, reverse=True): if match(f) and not os.listdir(repo.wjoin(f)): ui.note(_('Removing directory %s\n') % f) remove(os.rmdir, f)
def impl_hg_node(repo, cid, path, *args): m = cmdutil.match(repo, pats=[path], default=path) rev_iter = cmdutil.walkchangerevs(repo, m, {'rev': cid}, lambda c, f: None) return rev_iter.next().hex()
def haschanges(self, repo, pats=[], opts={}): """checks if repository has changes or not""" return list( patch.diff(repo, match=cmdutil.match(repo, pats, opts), opts=self.diffopts(opts))) != []
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)