changeset 547:4fc63e22b1fe

Merge with TAH -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Merge with TAH manifest hash: 1742d7ba2093dc643b57e45167cb2d794212cbb9 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.0 (GNU/Linux) iD8DBQFCxPCQywK+sNU5EO8RAkr0AJ9qut/31lCLQ/xY3FWaF3c21RhS7wCfW1eV 3WexPDsJldMAr3V5vc9eowA= =pJYu -----END PGP SIGNATURE-----
author mpm@selenic.com
date Thu, 30 Jun 2005 23:28:16 -0800
parents 53872e2be33a (diff) c8ae964109c1 (current diff)
children e2e963e255fd 2204311609a0
files TODO hgeditor hgmerge mercurial/commands.py mercurial/hg.py mercurial/hgweb.py mercurial/revlog.py templates/map tests/fish-merge tests/run-tests tests/test-bad-pull tests/test-bad-pull.out tests/test-basic tests/test-conflict tests/test-copy tests/test-help tests/test-pull tests/test-rawcommit1.out tests/test-simple-update tests/test-tags tests/test-undo tests/test-up-local-change tests/test-up-local-change.out
diffstat 10 files changed, 248 insertions(+), 82 deletions(-) [+]
line wrap: on
line diff
--- a/TODO	Fri Jul 01 07:40:32 2005 +0100
+++ b/TODO	Thu Jun 30 23:28:16 2005 -0800
@@ -20,7 +20,6 @@
 - make showing removed files (in history etc.) faster.
 
 Commands:
-- hg diff Makefile should avoid walking the tree
 - hg add <directory> should work
 - hg status <filename>: file rev, changeset rev, changed, added,
   deleted, sha-1
@@ -43,4 +42,3 @@
 - some web servers think hgweb.cgi.[di] is a CGI script with old-http://
   (use quoting (see foo.d in Core) or document server configurations?)
 - link children in hgweb
-- search field searching in descriptions, file names, what else?
--- a/mercurial/commands.py	Fri Jul 01 07:40:32 2005 +0100
+++ b/mercurial/commands.py	Thu Jun 30 23:28:16 2005 -0800
@@ -32,19 +32,24 @@
         return [ util.pconvert(os.path.normpath(os.path.join(p, x))) for x in args ]
     return args
 
-def dodiff(ui, repo, path, files = None, node1 = None, node2 = None):
+def dodiff(ui, repo, files = None, node1 = None, node2 = None):
     def date(c):
         return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
 
+    (c, a, d, u) = repo.changes(None, node1, files)
+    if files:
+        c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
+
+    if not c and not a and not d:
+        return
+
     if node2:
         change = repo.changelog.read(node2)
         mmap2 = repo.manifest.read(change[0])
-        (c, a, d) = repo.diffrevs(node1, node2)
         def read(f): return repo.file(f).read(mmap2[f])
         date2 = date(change)
     else:
         date2 = time.asctime()
-        (c, a, d, u) = repo.diffdir(path, node1)
         if not node1:
             node1 = repo.dirstate.parents()[0]
         def read(f): return repo.wfile(f).read()
@@ -59,9 +64,6 @@
     mmap = repo.manifest.read(change[0])
     date1 = date(change)
 
-    if files:
-        c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
-
     for f in c:
         to = None
         if f in mmap:
@@ -124,7 +126,7 @@
     ui.status("date:        %s\n" % time.asctime(
         time.localtime(float(changes[2].split(' ')[0]))))
     if ui.debugflag:
-        files = repo.diffrevs(changelog.parents(changenode)[0], changenode)
+        files = repo.changes(changelog.parents(changenode)[0], changenode)
         for key, value in zip(["files:", "files+:", "files-:"], files):
             if value:
                 ui.note("%-12s %s\n" % (key, " ".join(value)))
@@ -214,7 +216,7 @@
             elif s not in 'nmai' and isfile:
                 u.append(f)
     else:
-        (c, a, d, u) = repo.diffdir(repo.root)
+        (c, a, d, u) = repo.changes(None, None)
     repo.add(u)
     repo.remove(d)
 
@@ -413,7 +415,7 @@
     else:
         files = relpath(repo, [""])
 
-    dodiff(ui, repo, os.getcwd(), files, *revs)
+    dodiff(ui, repo, files, *revs)
 
 def export(ui, repo, changeset):
     """dump the changeset header and diffs for a revision"""
@@ -430,7 +432,7 @@
     print change[4].rstrip()
     print
 
-    dodiff(ui, repo, "", None, prev, node)
+    dodiff(ui, repo, None, prev, node)
 
 def forget(ui, repo, file, *files):
     """don't add the specified files on the next commit"""
@@ -449,7 +451,7 @@
         return
 
     hexfunc = ui.verbose and hg.hex or hg.short
-    (c, a, d, u) = repo.diffdir(repo.root)
+    (c, a, d, u) = repo.changes(None, None)
     output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
                         (c or a or d) and "+" or "")]
 
@@ -647,7 +649,7 @@
     R = removed
     ? = not tracked'''
 
-    (c, a, d, u) = repo.diffdir(os.getcwd())
+    (c, a, d, u) = repo.changes(None, None)
     (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
 
     for f in c: print "C", f
@@ -662,7 +664,7 @@
 	ui.warn("abort: 'tip' is a reserved name!\n")
 	return -1
 
-    (c, a, d, u) = repo.diffdir(repo.root)
+    (c, a, d, u) = repo.changes(None, None)
     for x in (c, a, d, u):
 	if ".hgtags" in x:
 	    ui.warn("abort: working copy of .hgtags is changed!\n")
--- a/mercurial/hg.py	Fri Jul 01 07:40:32 2005 +0100
+++ b/mercurial/hg.py	Thu Jun 30 23:28:16 2005 -0800
@@ -288,9 +288,57 @@
             st.write(e + f)
         self.dirty = 0
 
-    def dup(self):
+    def changes(self, files, ignore):
         self.read()
-        return self.map.copy()
+        dc = self.map.copy()
+        lookup, changed, added, unknown = [], [], [], []
+
+        # compare all files by default
+        if not files: files = [self.root]
+
+        def uniq(g):
+            seen = {}
+            for f in g:
+                if f not in seen:
+                    seen[f] = 1
+                    yield f
+
+        # recursive generator of all files listed
+        def walk(files):
+            for f in uniq(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 ".hg" in subdirs: subdirs.remove(".hg")
+                        for fn in fl:
+                            fn = util.pconvert(os.path.join(d, fn))
+                            yield fn
+                else:
+                    yield f[len(self.root) + 1:]
+
+        for fn in uniq(walk(files)):
+            try: s = os.stat(os.path.join(self.root, fn))
+            except: continue
+
+            if fn in dc:
+                c = dc[fn]
+                del dc[fn]
+
+                if c[0] == 'm':
+                    changed.append(fn)
+                elif c[0] == 'a':
+                    added.append(fn)
+                elif c[0] == 'r':
+                    unknown.append(fn)
+                elif c[2] != s.st_size or (c[1] ^ s.st_mode) & 0100:
+                    changed.append(fn)
+                elif c[1] != s.st_mode or c[3] != s.st_mtime:
+                    lookup.append(fn)
+            else:
+                if not ignore(fn): unknown.append(fn)
+
+        return (lookup, changed, added, dc.keys(), unknown)
 
 # used to avoid circular references so destructors work
 def opener(base):
@@ -568,7 +616,7 @@
                 else:
                     self.ui.warn("%s not tracked!\n" % f)
         else:
-            (c, a, d, u) = self.diffdir(self.root)
+            (c, a, d, u) = self.changes(None, None)
             commit = c + a
             remove = d
 
@@ -644,81 +692,60 @@
         self.dirstate.update(new, "n")
         self.dirstate.forget(remove)
 
-    def diffdir(self, path, changeset = None):
-        changed = []
-        added = []
-        unknown = []
-        mf = {}
+    def changes(self, node1, node2, files=None):
+        # changed, added, deleted, unknown
+        c, a, d, u, mf1 = [], [], [], [], None
 
-        if changeset:
-            change = self.changelog.read(changeset)
-            mf = self.manifest.read(change[0])
-            dc = dict.fromkeys(mf)
-        else:
-            changeset = self.dirstate.parents()[0]
-            change = self.changelog.read(changeset)
-            mf = self.manifest.read(change[0])
-            dc = self.dirstate.dup()
-
-        def fcmp(fn):
+        def fcmp(fn, mf):
             t1 = self.wfile(fn).read()
             t2 = self.file(fn).revision(mf[fn])
             return cmp(t1, t2)
 
-        for dir, subdirs, files in os.walk(path):
-            d = dir[len(self.root)+1:]
-            if ".hg" in subdirs: subdirs.remove(".hg")
+        # are we comparing the working directory?
+        if not node1:
+            l, c, a, d, u = self.dirstate.changes(files, self.ignore)
+
+            # are we comparing working dir against its parent?
+            if not node2:
+                if l:
+                    # do a full compare of any files that might have changed
+                    change = self.changelog.read(self.dirstate.parents()[0])
+                    mf1 = self.manifest.read(change[0])
+                    for f in lookup:
+                        if fcmp(f, mf):
+                            c.append(f)
+                return (c, a, d, u)
 
-            for f in files:
-                fn = util.pconvert(os.path.join(d, f))
-                try: s = os.stat(os.path.join(self.root, fn))
-                except: continue
-                if fn in dc:
-                    c = dc[fn]
-                    del dc[fn]
-                    if not c:
-                        if fcmp(fn):
-                            changed.append(fn)
-                    elif c[0] == 'm':
-                        changed.append(fn)
-                    elif c[0] == 'a':
-                        added.append(fn)
-                    elif c[0] == 'r':
-                        unknown.append(fn)
-                    elif c[2] != s.st_size or (c[1] ^ s.st_mode) & 0100:
-                        changed.append(fn)
-                    elif c[1] != s.st_mode or c[3] != s.st_mtime:
-                        if fcmp(fn):
-                            changed.append(fn)
-                else:
-                    if self.ignore(fn): continue
-                    unknown.append(fn)
+        # are we comparing working dir against non-tip?
+        # generate a pseudo-manifest for the working dir
+        if not node1:
+            if not mf1:
+                change = self.changelog.read(self.dirstate.parents()[0])
+                mf1 = self.manifest.read(change[0])
+            for f in a + c + l:
+                mf1[f] = ""
+            for f in d:
+                if f in mf1: del mf1[f]
+        else:
+            change = self.changelog.read(node1)
+            mf1 = self.manifest.read(change[0])
 
-        deleted = dc.keys()
-        deleted.sort()
-
-        return (changed, added, deleted, unknown)
-
-    def diffrevs(self, node1, node2):
-        changed, added = [], []
-
-        change = self.changelog.read(node1)
-        mf1 = self.manifest.read(change[0])
         change = self.changelog.read(node2)
         mf2 = self.manifest.read(change[0])
 
         for fn in mf2:
             if mf1.has_key(fn):
                 if mf1[fn] != mf2[fn]:
-                    changed.append(fn)
+                    if mf1[fn] != "" or fcmp(fn, mf2):
+                        c.append(fn)
                 del mf1[fn]
             else:
-                added.append(fn)
+                a.append(fn)
 
-        deleted = mf1.keys()
-        deleted.sort()
+        d = mf1.keys()
+        d.sort()
 
-        return (changed, added, deleted)
+        return (c, a, d, u)
 
     def add(self, list):
         for f in list:
@@ -1044,7 +1071,7 @@
         ma = self.manifest.read(man)
         mfa = self.manifest.readflags(man)
 
-        (c, a, d, u) = self.diffdir(self.root)
+        (c, a, d, u) = self.changes(None, None)
 
         # is this a jump, or a merge?  i.e. is there a linear path
         # from p1 to p2?
--- a/mercurial/hgweb.py	Fri Jul 01 07:40:32 2005 +0100
+++ b/mercurial/hgweb.py	Thu Jun 30 23:28:16 2005 -0800
@@ -194,7 +194,7 @@
         date1 = self.date(change1)
         date2 = self.date(change2)
 
-        c, a, d = r.diffrevs(node1, node2)
+        c, a, d, u = r.changes(node1, node2)
         c, a, d = map(lambda x: filterfiles(x, files), (c, a, d))
 
         for f in c:
@@ -286,6 +286,68 @@
                      manifest = hex(mf),
                      rev = pos, changesets = count, entries = changelist)
 
+    def search(self, query):
+
+        def changelist():
+            cl = self.repo.changelog
+            count = 0
+            qw = query.lower().split()
+
+            def revgen():
+                for i in range(cl.count() - 1, 0, -100):
+                    l = []
+                    for j in range(max(0, i - 100), i):
+                        n = cl.node(j)
+                        changes = cl.read(n)
+                        l.insert(0, (n, j, changes))
+                    for e in l:
+                        yield e
+
+            for n, i, changes in revgen():
+                miss = 0
+                for q in qw:
+                    if not (q in changes[1].lower() or
+                            q in changes[4].lower() or
+                            q in " ".join(changes[3][:20]).lower()):
+                        miss = 1
+                        break
+                if miss: continue
+
+                count += 1
+                hn = hex(n)
+                p1, p2 = cl.parents(n)
+                t = float(changes[2].split(' ')[0])
+
+                yield self.t(
+                    'searchentry',
+                    parity = count & 1,
+                    author = changes[1],
+                    parent1 = self.parent("changelogparent",
+                                          hex(p1), cl.rev(p1)),
+                    parent2 = self.parent("changelogparent",
+                                          hex(p2), cl.rev(p2)),
+                    p1 = hex(p1), p2 = hex(p2),
+                    p1rev = cl.rev(p1), p2rev = cl.rev(p2),
+                    manifest = hex(changes[0]),
+                    desc = changes[4],
+                    date = t,
+                    files = self.listfilediffs(changes[3], n),
+                    rev = i,
+                    node = hn)
+
+                if count >= self.maxchanges: break
+
+        cl = self.repo.changelog
+        mf = cl.read(cl.tip())[0]
+
+        yield self.t('search',
+                     header = self.header(),
+                     footer = self.footer(),
+                     query = query,
+                     repo = self.reponame,
+                     manifest = hex(mf),
+                     entries = changelist)
+
     def changeset(self, nodeid):
         n = bin(nodeid)
         cl = self.repo.changelog
@@ -586,13 +648,16 @@
         self.t = templater(m, self.filters)
 
         if not args.has_key('cmd') or args['cmd'][0] == 'changelog':
-            hi = self.repo.changelog.count() - 1
+            c = self.repo.changelog.count() - 1
+            hi = c
             if args.has_key('rev'):
                 hi = args['rev'][0]
                 try:
                     hi = self.repo.changelog.rev(self.repo.lookup(hi))
-                except KeyError: pass
-
+                except KeyError:
+                    write(self.search(hi))
+                    return
+                
             write(self.changelog(hi))
 
         elif args['cmd'][0] == 'changeset':
--- a/templates/map	Fri Jul 01 07:40:32 2005 +0100
+++ b/templates/map	Thu Jun 30 23:28:16 2005 -0800
@@ -1,11 +1,13 @@
 header = header.tmpl
 footer = footer.tmpl
+search = search.tmpl
 changelog = changelog.tmpl
 naventry = "<a href="?cmd=changelog;rev=#rev#">#label#</a> "
 filedifflink = "<a href="?cmd=filediff;node=#node#;file=#file#">#file#</a> "
 filenodelink = "<a href="?cmd=file;filenode=#filenode#;file=#file#">#file#</a> "
 fileellipses = "..."
 changelogentry = changelogentry.tmpl
+searchentry = searchentry.tmpl
 changeset = changeset.tmpl
 manifest = manifest.tmpl
 manifestdirentry = "<tr class="parity#parity#"><td><tt>drwxr-xr-x</tt>&nbsp;<td><a href="?cmd=manifest;manifest=#manifest#;path=#path#">#basename#/</a>"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/search.tmpl	Thu Jun 30 23:28:16 2005 -0800
@@ -0,0 +1,28 @@
+#header#
+<title>#repo|escape#: searching for #query|escape#</title>
+</head>
+<body>
+
+<div class="buttons">
+<a href="?cmd=changelog;rev=#rev#">changelog</a>
+<a href="?cmd=tags">tags</a>
+<a href="?cmd=manifest;manifest=#manifest#;path=/">manifest</a>
+</div>
+
+<h2>searching for #query|escape#</h2>
+
+<form>
+search:
+<input type="hidden" name="cmd" value="changelog">
+<input name="rev" type="text" width="30" value="#query|escape#">
+</form>
+
+#entries#
+
+<form>
+search:
+<input type="hidden" name="cmd" value="changelog">
+<input name="rev" type="text" width="30">
+</form>
+
+#footer#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/searchentry.tmpl	Thu Jun 30 23:28:16 2005 -0800
@@ -0,0 +1,22 @@
+<div class="parity#parity#">
+<table width="100%" cellpadding="0" cellspacing="0">
+<tr>
+ <td align="right" width="15%"><b>#date|age# ago:&nbsp;</b></td>
+ <td><b>#desc|firstline|escape#</b></td></tr>
+<tr>
+ <td align="right">changeset #rev#:&nbsp;</td>
+ <td><a href="?cmd=changeset;node=#node#">#node|short#</a></td></tr>
+#parent1#
+#parent2#
+<tr>
+ <td align="right">author:&nbsp;</td>
+ <td>#author|obfuscate#</td></tr>
+<tr>
+ <td align="right">date:&nbsp;</td>
+ <td>#date|date#</td></tr>
+<tr>
+ <td align="right" valign="top"><a href="?cmd=manifest;manifest=#manifest#;path=/">files</a>:&nbsp;</td>
+ <td>#files#</td></tr>
+</table>
+</div>
+
--- a/tests/test-bad-pull.out	Fri Jul 01 07:40:32 2005 +0100
+++ b/tests/test-bad-pull.out	Thu Jun 30 23:28:16 2005 -0800
@@ -9,8 +9,8 @@
 + ls copy
 ls: copy: No such file or directory
 + cat
++ python dumb.py
 + sleep 2
-+ python dumb.py
 + hg clone http://localhost:20059/foo copy2
 requesting all changes
 adding changesets
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-diffdir	Thu Jun 30 23:28:16 2005 -0800
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+hg init
+touch a
+hg add a
+hg ci -t "a" -u test -d "0 0"
+
+echo 123 > b
+hg add b
+hg diff | sed "s/\(\(---\|+++\).*\)\t.*/\1/"
+
+hg diff -r tip | sed "s/\(\(---\|+++\).*\)\t.*/\1/"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-diffdir.out	Thu Jun 30 23:28:16 2005 -0800
@@ -0,0 +1,10 @@
+diff -r 3903775176ed b
+--- /dev/null
++++ b/b
+@@ -0,0 +1,1 @@
++123
+diff -r 3903775176ed b
+--- /dev/null
++++ b/b
+@@ -0,0 +1,1 @@
++123