# HG changeset patch # User David M. Carr # Date 2012-01-18 00:10:59 # Node ID 2bd54ffaa27e6d40f619643338c9aff9416acc86 # Parent c654eac03452bf4e80ba4b7ed427a51a6541d67e forget: fix subrepo recursion for explicit path handling When support for handling explicit paths in subrepos was added to the forget command (95174c381525), subrepo recursion wasn't taken into account. This change fixes that by pulling the majority of the logic of commands.forget into cmdutil.forget, which can then be called from both there and subrepo.forget. diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py --- a/mercurial/cmdutil.py +++ b/mercurial/cmdutil.py @@ -1201,6 +1201,48 @@ def add(ui, repo, match, dryrun, listsub bad.extend(f for f in rejected if f in match.files()) return bad +def forget(ui, repo, match, prefix, explicitonly): + join = lambda f: os.path.join(prefix, f) + bad = [] + oldbad = match.bad + match.bad = lambda x, y: bad.append(x) or oldbad(x, y) + wctx = repo[None] + forgot = [] + s = repo.status(match=match, clean=True) + forget = sorted(s[0] + s[1] + s[3] + s[6]) + if explicitonly: + forget = [f for f in forget if match.exact(f)] + + for subpath in wctx.substate: + sub = wctx.sub(subpath) + try: + submatch = matchmod.narrowmatcher(subpath, match) + subbad, subforgot = sub.forget(ui, submatch, prefix) + bad.extend([subpath + '/' + f for f in subbad]) + forgot.extend([subpath + '/' + f for f in subforgot]) + except error.LookupError: + ui.status(_("skipping missing subrepository: %s\n") + % join(subpath)) + + for f in match.files(): + if match.exact(f) or not explicitonly: + if f not in repo.dirstate and not os.path.isdir(match.rel(join(f))): + if f not in forgot: + if os.path.exists(match.rel(join(f))): + ui.warn(_('not removing %s: ' + 'file is already untracked\n') + % match.rel(join(f))) + bad.append(f) + + for f in forget: + if ui.verbose or not match.exact(f): + ui.status(_('removing %s\n') % match.rel(join(f))) + + rejected = wctx.forget(forget, prefix) + bad.extend(f for f in rejected if f in match.files()) + forgot.extend(forget) + return bad, forgot + def duplicatecopies(repo, rev, p1): "Reproduce copies found in the source revision in the dirstate for grafts" for dst, src in copies.pathcopies(repo[p1], repo[rev]).iteritems(): diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -13,7 +13,6 @@ import hg, scmutil, util, revlog, extens import patch, help, url, encoding, templatekw, discovery import archival, changegroup, cmdutil, hbisect import sshserver, hgweb, hgweb.server, commandserver -import match as matchmod import merge as mergemod import minirst, revset, fileset import dagparser, context, simplemerge @@ -2449,46 +2448,9 @@ def forget(ui, repo, *pats, **opts): if not pats: raise util.Abort(_('no files specified')) - wctx = repo[None] - m = scmutil.match(wctx, pats, opts) - s = repo.status(match=m, clean=True) - forget = sorted(s[0] + s[1] + s[3] + s[6]) - subforget = {} - errs = 0 - - for subpath in wctx.substate: - sub = wctx.sub(subpath) - try: - submatch = matchmod.narrowmatcher(subpath, m) - for fsub in sub.walk(submatch): - if submatch.exact(fsub): - subforget[subpath + '/' + fsub] = (fsub, sub) - except error.LookupError: - ui.status(_("skipping missing subrepository: %s\n") % subpath) - - for f in m.files(): - if f not in repo.dirstate and not os.path.isdir(m.rel(f)): - if f not in subforget: - if os.path.exists(m.rel(f)): - ui.warn(_('not removing %s: file is already untracked\n') - % m.rel(f)) - errs = 1 - - for f in forget: - if ui.verbose or not m.exact(f): - ui.status(_('removing %s\n') % m.rel(f)) - - if ui.verbose: - for f in sorted(subforget.keys()): - ui.status(_('removing %s\n') % m.rel(f)) - - wctx.forget(forget) - - for f in sorted(subforget.keys()): - fsub, sub = subforget[f] - sub.forget([fsub]) - - return errs + m = scmutil.match(repo[None], pats, opts) + rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0] + return rejected and 1 or 0 @command( 'graft', diff --git a/mercurial/context.py b/mercurial/context.py --- a/mercurial/context.py +++ b/mercurial/context.py @@ -900,16 +900,20 @@ class workingctx(changectx): finally: wlock.release() - def forget(self, files): + def forget(self, files, prefix=""): + join = lambda f: os.path.join(prefix, f) wlock = self._repo.wlock() try: + rejected = [] for f in files: if self._repo.dirstate[f] != 'a': self._repo.dirstate.remove(f) elif f not in self._repo.dirstate: - self._repo.ui.warn(_("%s not tracked!\n") % f) + self._repo.ui.warn(_("%s not tracked!\n") % join(f)) + rejected.append(f) else: self._repo.dirstate.drop(f) + return rejected finally: wlock.release() diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py --- a/mercurial/subrepo.py +++ b/mercurial/subrepo.py @@ -360,8 +360,8 @@ class abstractsubrepo(object): ''' pass - def forget(self, files): - pass + def forget(self, ui, match, prefix): + return [] class hgsubrepo(abstractsubrepo): def __init__(self, ctx, path, state): @@ -561,9 +561,9 @@ class hgsubrepo(abstractsubrepo): ctx = self._repo[None] return ctx.walk(match) - def forget(self, files): - ctx = self._repo[None] - ctx.forget(files) + def forget(self, ui, match, prefix): + return cmdutil.forget(ui, self._repo, match, + os.path.join(prefix, self._path), True) class svnsubrepo(abstractsubrepo): def __init__(self, ctx, path, state): diff --git a/tests/test-subrepo-recursion.t b/tests/test-subrepo-recursion.t --- a/tests/test-subrepo-recursion.t +++ b/tests/test-subrepo-recursion.t @@ -197,12 +197,6 @@ Test explicit path commands within subre A foo/bar/z2.txt This is expected to forget the file, but is currently broken $ hg forget foo/bar/z2.txt - not removing foo/bar/z2.txt: file is already untracked - [1] - $ hg status -S - A foo/bar/z2.txt -When fixed, remove the next two commands - $ hg forget -R foo/bar foo/bar/z2.txt $ hg status -S ? foo/bar/z2.txt $ rm foo/bar/z2.txt