--- a/mercurial/cmdutil.py Fri May 13 14:06:28 2011 -0500
+++ b/mercurial/cmdutil.py Fri May 13 14:07:16 2011 -0500
@@ -8,16 +8,16 @@
from node import hex, nullid, nullrev, short
from i18n import _
import os, sys, errno, re, tempfile
-import util, scmutil, templater, patch, error, templatekw, wdutil
+import util, scmutil, templater, patch, error, templatekw
import match as matchmod
import subrepo
-expandpats = wdutil.expandpats
-match = wdutil.match
-matchall = wdutil.matchall
-matchfiles = wdutil.matchfiles
-addremove = wdutil.addremove
-dirstatecopy = wdutil.dirstatecopy
+expandpats = scmutil.expandpats
+match = scmutil.match
+matchall = scmutil.matchall
+matchfiles = scmutil.matchfiles
+addremove = scmutil.addremove
+dirstatecopy = scmutil.dirstatecopy
def parsealiases(cmd):
return cmd.lstrip("^").split("|")
--- a/mercurial/scmutil.py Fri May 13 14:06:28 2011 -0500
+++ b/mercurial/scmutil.py Fri May 13 14:07:16 2011 -0500
@@ -6,8 +6,9 @@
# GNU General Public License version 2 or any later version.
from i18n import _
-import util, error, osutil, revset
-import os, errno, stat, sys
+import util, error, osutil, revset, similar
+import match as matchmod
+import os, errno, stat, sys, glob
def checkfilename(f):
'''Check that the filename f is an acceptable filename for a tracked file'''
@@ -536,3 +537,154 @@
seen.update(l)
return l
+
+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 = 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)
--- a/mercurial/wdutil.py Fri May 13 14:06:28 2011 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,162 +0,0 @@
-# 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)