--- a/mercurial/hg.py Wed Jul 20 11:40:27 2005 -0500
+++ b/mercurial/hg.py Wed Jul 20 20:00:29 2005 -0500
@@ -277,6 +277,36 @@
self.map = None
self.pl = None
self.copies = {}
+ self.ignorefunc = None
+
+ def wjoin(self, f):
+ return os.path.join(self.root, f)
+
+ def ignore(self, f):
+ if not self.ignorefunc:
+ bigpat = []
+ try:
+ l = file(self.wjoin(".hgignore"))
+ for pat in l:
+ if pat != "\n":
+ p = util.pconvert(pat[:-1])
+ try:
+ r = re.compile(p)
+ except:
+ self.ui.warn("ignoring invalid ignore"
+ + " regular expression '%s'\n" % p)
+ else:
+ bigpat.append(util.pconvert(pat[:-1]))
+ except IOError: pass
+
+ if bigpat:
+ s = "(?:%s)" % (")|(?:".join(bigpat))
+ r = re.compile(s)
+ self.ignorefunc = r.search
+ else:
+ self.ignorefunc = util.never
+
+ return self.ignorefunc(f)
def __del__(self):
if self.dirty:
@@ -298,8 +328,12 @@
self.read()
return self.pl
+ def markdirty(self):
+ if not self.dirty:
+ self.dirty = 1
+
def setparents(self, p1, p2 = nullid):
- self.dirty = 1
+ self.markdirty()
self.pl = p1, p2
def state(self, key):
@@ -334,7 +368,7 @@
def copy(self, source, dest):
self.read()
- self.dirty = 1
+ self.markdirty()
self.copies[dest] = source
def copied(self, file):
@@ -349,7 +383,7 @@
if not files: return
self.read()
- self.dirty = 1
+ self.markdirty()
for f in files:
if state == "r":
self.map[f] = ('r', 0, 0, 0)
@@ -360,7 +394,7 @@
def forget(self, files):
if not files: return
self.read()
- self.dirty = 1
+ self.markdirty()
for f in files:
try:
del self.map[f]
@@ -370,7 +404,7 @@
def clear(self):
self.map = {}
- self.dirty = 1
+ self.markdirty()
def write(self):
st = self.opener("dirstate", "w")
@@ -383,34 +417,50 @@
st.write(e + f)
self.dirty = 0
- def changes(self, files, ignore):
+ def walk(self, files = None, match = util.always):
self.read()
dc = self.map.copy()
- lookup, changed, added, unknown = [], [], [], []
-
- # compare all files by default
+ # walk all files by default
if not files: files = [self.root]
-
- # recursive generator of all files listed
- def walk(files):
+ def traverse():
for f in util.unique(files):
f = os.path.join(self.root, f)
if os.path.isdir(f):
for dir, subdirs, fl in os.walk(f):
d = dir[len(self.root) + 1:]
+ if d == '.hg':
+ subdirs[:] = []
+ continue
for sd in subdirs:
- if ignore(os.path.join(d, sd +'/')):
+ ds = os.path.join(d, sd +'/')
+ if self.ignore(ds) or not match(ds):
subdirs.remove(sd)
for fn in fl:
fn = util.pconvert(os.path.join(d, fn))
- yield fn
+ yield 'f', fn
else:
- yield f[len(self.root) + 1:]
+ yield 'f', f[len(self.root) + 1:]
for k in dc.keys():
- yield k
+ yield 'm', k
+
+ # yield only files that match: all in dirstate, others only if
+ # not in .hgignore
- for fn in util.unique(walk(files)):
+ for src, fn in util.unique(traverse()):
+ if fn in dc:
+ del dc[fn]
+ elif self.ignore(fn):
+ continue
+ if match(fn):
+ yield src, fn
+
+ def changes(self, files = None, match = util.always):
+ self.read()
+ dc = self.map.copy()
+ lookup, changed, added, unknown = [], [], [], []
+
+ for src, fn in self.walk(files, match):
try: s = os.stat(os.path.join(self.root, fn))
except: continue
@@ -429,9 +479,9 @@
elif c[1] != s.st_mode or c[3] != s.st_mtime:
lookup.append(fn)
else:
- if not ignore(fn): unknown.append(fn)
+ if match(fn): unknown.append(fn)
- return (lookup, changed, added, dc.keys(), unknown)
+ return (lookup, changed, added, filter(match, dc.keys()), unknown)
# used to avoid circular references so destructors work
def opener(base):
@@ -493,7 +543,6 @@
self.wopener = opener(self.root)
self.manifest = manifest(self.opener)
self.changelog = changelog(self.opener)
- self.ignorefunc = None
self.tagscache = None
self.nodetagscache = None
@@ -503,29 +552,6 @@
self.ui.readconfig(self.opener("hgrc"))
except IOError: pass
- def ignore(self, f):
- if not self.ignorefunc:
- bigpat = ["^.hg/$"]
- try:
- l = file(self.wjoin(".hgignore"))
- for pat in l:
- if pat != "\n":
- p = util.pconvert(pat[:-1])
- try:
- r = re.compile(p)
- except:
- self.ui.warn("ignoring invalid ignore"
- + " regular expression '%s'\n" % p)
- else:
- bigpat.append(util.pconvert(pat[:-1]))
- except IOError: pass
-
- s = "(?:%s)" % (")|(?:".join(bigpat))
- r = re.compile(s)
- self.ignorefunc = r.search
-
- return self.ignorefunc(f)
-
def hook(self, name, **args):
s = self.ui.config("hooks", name)
if s:
@@ -738,7 +764,7 @@
else:
self.ui.warn("%s not tracked!\n" % f)
else:
- (c, a, d, u) = self.changes(None, None)
+ (c, a, d, u) = self.changes()
commit = c + a
remove = d
@@ -815,7 +841,16 @@
if not self.hook("commit", node=hex(n)):
return 1
- def changes(self, node1, node2, files=None):
+ def walk(self, node = None, files = [], match = util.always):
+ if node:
+ for fn in self.manifest.read(self.changelog.read(node)[0]):
+ yield 'm', fn
+ else:
+ for src, fn in self.dirstate.walk(files, match):
+ yield src, fn
+
+ def changes(self, node1 = None, node2 = None, files = [],
+ match = util.always):
mf2, u = None, []
def fcmp(fn, mf):
@@ -823,16 +858,23 @@
t2 = self.file(fn).revision(mf[fn])
return cmp(t1, t2)
+ def mfmatches(node):
+ mf = dict(self.manifest.read(node))
+ for fn in mf.keys():
+ if not match(fn):
+ del mf[fn]
+ return mf
+
# are we comparing the working directory?
if not node2:
- l, c, a, d, u = self.dirstate.changes(files, self.ignore)
+ l, c, a, d, u = self.dirstate.changes(files, match)
# are we comparing working dir against its parent?
if not node1:
if l:
# do a full compare of any files that might have changed
change = self.changelog.read(self.dirstate.parents()[0])
- mf2 = self.manifest.read(change[0])
+ mf2 = mfmatches(change[0])
for f in l:
if fcmp(f, mf2):
c.append(f)
@@ -847,20 +889,20 @@
if not node2:
if not mf2:
change = self.changelog.read(self.dirstate.parents()[0])
- mf2 = self.manifest.read(change[0]).copy()
+ mf2 = mfmatches(change[0])
for f in a + c + l:
mf2[f] = ""
for f in d:
if f in mf2: del mf2[f]
else:
change = self.changelog.read(node2)
- mf2 = self.manifest.read(change[0])
+ mf2 = mfmatches(change[0])
# flush lists from dirstate before comparing manifests
c, a = [], []
change = self.changelog.read(node1)
- mf1 = self.manifest.read(change[0]).copy()
+ mf1 = mfmatches(change[0])
for fn in mf2:
if mf1.has_key(fn):
@@ -885,7 +927,7 @@
self.ui.warn("%s does not exist!\n" % f)
elif not os.path.isfile(p):
self.ui.warn("%s not added: mercurial only supports files currently\n" % f)
- elif self.dirstate.state(f) == 'n':
+ elif self.dirstate.state(f) in 'an':
self.ui.warn("%s already tracked!\n" % f)
else:
self.dirstate.update([f], "a")
@@ -1268,7 +1310,7 @@
ma = self.manifest.read(man)
mfa = self.manifest.readflags(man)
- (c, a, d, u) = self.changes(None, None)
+ (c, a, d, u) = self.changes()
# is this a jump, or a merge? i.e. is there a linear path
# from p1 to p2?