Mercurial > public > mercurial-scm > hg
view mercurial/wdutil.py @ 14259:df9ccd39828c
patch: move updatedir() from cmdutil into patch
Also, create an artificial wdutil.py to avoid import cycles between patch.py
and cmdutil.py.
author | Patrick Mezard <pmezard@gmail.com> |
---|---|
date | Sun, 08 May 2011 17:48:30 +0200 |
parents | |
children |
line wrap: on
line source
# wdutil.py - working dir utilities # # Copyright 2011 Patrick Mezard <pmezard@gmail.com> # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. import glob, os import util, similar, scmutil import match as matchmod from i18n import _ def expandpats(pats): if not util.expandglobs: return list(pats) ret = [] for p in pats: kind, name = matchmod._patsplit(p, None) if kind is None: try: globbed = glob.glob(name) except re.error: globbed = [name] if globbed: ret.extend(globbed) continue ret.append(p) return ret def match(repo, pats=[], opts={}, globbed=False, default='relpath'): if pats == ("",): pats = [] if not globbed and default == 'relpath': pats = expandpats(pats or []) m = matchmod.match(repo.root, repo.getcwd(), pats, opts.get('include'), opts.get('exclude'), default, auditor=repo.auditor) def badfn(f, msg): repo.ui.warn("%s: %s\n" % (m.rel(f), msg)) m.bad = badfn return m def matchall(repo): return matchmod.always(repo.root, repo.getcwd()) def matchfiles(repo, files): return matchmod.exact(repo.root, repo.getcwd(), files) def addremove(repo, pats=[], opts={}, dry_run=None, similarity=None): if dry_run is None: dry_run = opts.get('dry_run') if similarity is None: similarity = float(opts.get('similarity') or 0) # we'd use status here, except handling of symlinks and ignore is tricky added, unknown, deleted, removed = [], [], [], [] audit_path = scmutil.pathauditor(repo.root) m = match(repo, pats, opts) for abs in repo.walk(m): target = repo.wjoin(abs) good = True try: audit_path(abs) except (OSError, util.Abort): good = False rel = m.rel(abs) exact = m.exact(abs) if good and abs not in repo.dirstate: unknown.append(abs) if repo.ui.verbose or not exact: repo.ui.status(_('adding %s\n') % ((pats and rel) or abs)) elif repo.dirstate[abs] != 'r' and (not good or not os.path.lexists(target) or (os.path.isdir(target) and not os.path.islink(target))): deleted.append(abs) if repo.ui.verbose or not exact: repo.ui.status(_('removing %s\n') % ((pats and rel) or abs)) # for finding renames elif repo.dirstate[abs] == 'r': removed.append(abs) elif repo.dirstate[abs] == 'a': added.append(abs) copies = {} if similarity > 0: for old, new, score in similar.findrenames(repo, added + unknown, removed + deleted, similarity): if repo.ui.verbose or not m.exact(old) or not m.exact(new): repo.ui.status(_('recording removal of %s as rename to %s ' '(%d%% similar)\n') % (m.rel(old), m.rel(new), score * 100)) copies[new] = old if not dry_run: wctx = repo[None] wlock = repo.wlock() try: wctx.remove(deleted) wctx.add(unknown) for new, old in copies.iteritems(): wctx.copy(old, new) finally: wlock.release() def updatedir(ui, repo, patches, similarity=0): '''Update dirstate after patch application according to metadata''' if not patches: return [] copies = [] removes = set() cfiles = patches.keys() cwd = repo.getcwd() if cwd: cfiles = [util.pathto(repo.root, cwd, f) for f in patches.keys()] for f in patches: gp = patches[f] if not gp: continue if gp.op == 'RENAME': copies.append((gp.oldpath, gp.path)) removes.add(gp.oldpath) elif gp.op == 'COPY': copies.append((gp.oldpath, gp.path)) elif gp.op == 'DELETE': removes.add(gp.path) wctx = repo[None] for src, dst in copies: dirstatecopy(ui, repo, wctx, src, dst, cwd=cwd) if (not similarity) and removes: wctx.remove(sorted(removes), True) for f in patches: gp = patches[f] if gp and gp.mode: islink, isexec = gp.mode dst = repo.wjoin(gp.path) # patch won't create empty files if gp.op == 'ADD' and not os.path.lexists(dst): flags = (isexec and 'x' or '') + (islink and 'l' or '') repo.wwrite(gp.path, '', flags) util.setflags(dst, islink, isexec) addremove(repo, cfiles, similarity=similarity) files = patches.keys() files.extend([r for r in removes if r not in files]) return sorted(files) def dirstatecopy(ui, repo, wctx, src, dst, dryrun=False, cwd=None): """Update the dirstate to reflect the intent of copying src to dst. For different reasons it might not end with dst being marked as copied from src. """ origsrc = repo.dirstate.copied(src) or src if dst == origsrc: # copying back a copy? if repo.dirstate[dst] not in 'mn' and not dryrun: repo.dirstate.normallookup(dst) else: if repo.dirstate[origsrc] == 'a' and origsrc == src: if not ui.quiet: ui.warn(_("%s has not been committed yet, so no copy " "data will be stored for %s.\n") % (repo.pathto(origsrc, cwd), repo.pathto(dst, cwd))) if repo.dirstate[dst] in '?r' and not dryrun: wctx.add([dst]) elif not dryrun: wctx.copy(origsrc, dst)