changeset 836:1fe3b14c7044

Merge with TAH
author mpm@selenic.com
date Thu, 04 Aug 2005 13:27:41 -0800
parents a61728b58dc0 (diff) 9de3535caae8 (current diff)
children 9c918287d10b
files doc/hg.1.txt hgeditor hgmerge mercurial/bdiff.c mercurial/commands.py mercurial/hg.py mercurial/hgweb.py mercurial/util.py tests/run-tests tests/test-clone tests/test-clone-failure tests/test-merge-revert tests/test-merge-revert.out tests/test-merge-revert2 tests/test-merge-revert2.out tests/test-merge5.out
diffstat 7 files changed, 90 insertions(+), 43 deletions(-) [+]
line wrap: on
line diff
--- a/doc/hg.1.txt	Thu Aug 04 18:23:07 2005 +0100
+++ b/doc/hg.1.txt	Thu Aug 04 13:27:41 2005 -0800
@@ -330,6 +330,7 @@
     -p, --port <n>           port to use (default: 8000)
     -n, --name <name>        name to show in web pages (default: working dir)
     -t, --templatedir <path> web templates to use
+    -6, --ipv6               use IPv6 in addition to IPv4
 
 status [options] [files]::
     Show changed files in the working directory.  If no names are
--- a/mercurial/bdiff.c	Thu Aug 04 18:23:07 2005 +0100
+++ b/mercurial/bdiff.c	Thu Aug 04 13:27:41 2005 -0800
@@ -229,7 +229,8 @@
 	/* allocate and fill arrays */
 	t = equatelines(a, an, b, bn);
 	pos = calloc(bn, sizeof(struct pos));
-	l.head = l.base = malloc(sizeof(struct hunk) * ((an + bn) / 4 + 2));
+	/* we can't have more matches than lines in the shorter file */
+	l.head = l.base = malloc(sizeof(struct hunk) * ((an<bn ? an:bn) + 1));
 
 	if (pos && l.base && t) {
 		/* generate the matching block list */
--- a/mercurial/commands.py	Thu Aug 04 18:23:07 2005 +0100
+++ b/mercurial/commands.py	Thu Aug 04 13:27:41 2005 -0800
@@ -40,16 +40,24 @@
     return args
 
 def matchpats(cwd, pats = [], opts = {}, head = ''):
-    return util.matcher(cwd, pats, opts.get('include'),
+    return util.matcher(cwd, pats or ['.'], opts.get('include'),
                         opts.get('exclude'), head)
 
+def pathto(n1, n2):
+    '''return the relative path from one place to another'''
+    if not n1: return n2
+    a, b = n1.split(os.sep), n2.split(os.sep)
+    a.reverse(), b.reverse()
+    while a and b and a[-1] == b[-1]:
+        a.pop(), b.pop()
+    b.reverse()
+    return os.sep.join((['..'] * len(a)) + b)
+
 def walk(repo, pats, opts, head = ''):
     cwd = repo.getcwd()
-    c = 0
-    if cwd: c = len(cwd) + 1
     files, matchfn = matchpats(cwd, pats, opts, head)
     for src, fn in repo.walk(files = files, match = matchfn):
-        yield src, fn, fn[c:]
+        yield src, fn, pathto(cwd, fn)
 
 revrangesep = ':'
 
@@ -565,6 +573,11 @@
             ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
     ui.write("}\n")
 
+def debugwalk(ui, repo, *pats, **opts):
+    items = list(walk(repo, pats, opts))
+    fmt = '%%s  %%-%ds  %%s' % max([len(abs) for (src, abs, rel) in items])
+    for i in items: print fmt % i
+
 def diff(ui, repo, *pats, **opts):
     """diff working directory (or selected files)"""
     revs = []
@@ -690,7 +703,7 @@
             message = "%s\n" % '\n'.join(message)
         ui.debug('message:\n%s\n' % message)
 
-        f = os.popen("patch -p%d < %s" % (strip, pf))
+        f = os.popen("patch -p%d < '%s'" % (strip, pf))
         files = []
         for l in f.read().splitlines():
             l.rstrip('\r\n');
@@ -989,7 +1002,7 @@
             return default
 
     httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
-                                opts["address"], opts["port"],
+                                opts["address"], opts["port"], opts["ipv6"],
                                 openlog('accesslog', sys.stdout),
                                 openlog('errorlog', sys.stderr))
     if ui.verbose:
@@ -1015,9 +1028,10 @@
     R = removed
     ? = not tracked'''
 
-    files, matchfn = matchpats(repo.getcwd(), pats, opts)
-    (c, a, d, u) = repo.changes(files = files, match = matchfn)
-    (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
+    cwd = repo.getcwd()
+    files, matchfn = matchpats(cwd, pats, opts)
+    (c, a, d, u) = [[pathto(cwd, x) for x in n]
+                    for n in repo.changes(files=files, match=matchfn)]
 
     for f in c:
         ui.write("M ", f, "\n")
@@ -1160,6 +1174,10 @@
     "debugstate": (debugstate, [], 'debugstate'),
     "debugindex": (debugindex, [], 'debugindex FILE'),
     "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
+    "debugwalk": (debugwalk,
+                  [('I', 'include', [], 'include path in search'),
+                   ('X', 'exclude', [], 'exclude path from search')],
+                  'debugwalk [OPTIONS]... [FILE]...'),
     "^diff":
         (diff,
          [('r', 'rev', [], 'revision'),
@@ -1233,7 +1251,8 @@
           ('a', 'address', '', 'interface address'),
           ('n', 'name', os.getcwd(), 'repository name'),
           ('', 'stdio', None, 'for remote clients'),
-          ('t', 'templates', "", 'template map')],
+          ('t', 'templates', "", 'template map'),
+          ('6', 'ipv6', None, 'use IPv6 in addition to IPv4')],
          "hg serve [OPTION]..."),
     "^status": (status,
                 [('I', 'include', [], 'include path in search'),
--- a/mercurial/hg.py	Thu Aug 04 18:23:07 2005 +0100
+++ b/mercurial/hg.py	Thu Aug 04 13:27:41 2005 -0800
@@ -440,32 +440,43 @@
         dc = self.map.copy()
         # walk all files by default
         if not files: files = [self.root]
+        known = {'.hg': 1}
+        def seen(fn):
+            if fn in known: return True
+            known[fn] = 1
         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':
+                        nd = os.path.normpath(d)
+                        if seen(nd):
                             subdirs[:] = []
                             continue
                         for sd in subdirs:
-                            ds = os.path.join(d, sd +'/')
+                            ds = os.path.join(nd, sd +'/')
                             if self.ignore(ds) or not match(ds):
                                 subdirs.remove(sd)
+                        subdirs.sort()
+                        fl.sort()
                         for fn in fl:
                             fn = util.pconvert(os.path.join(d, fn))
                             yield 'f', fn
                 else:
                     yield 'f', f[len(self.root) + 1:]
 
-            for k in dc.keys():
+            ks = dc.keys()
+            ks.sort()
+            for k in ks:
                 yield 'm', k
 
         # yield only files that match: all in dirstate, others only if
         # not in .hgignore
 
         for src, fn in util.unique(traverse()):
+            fn = os.path.normpath(fn)
+            if seen(fn): continue
             if fn in dc:
                 del dc[fn]
             elif self.ignore(fn):
@@ -868,7 +879,7 @@
     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
+                if match(fn): yield 'm', fn
         else:
             for src, fn in self.dirstate.walk(files, match):
                 yield src, fn
--- a/mercurial/hgweb.py	Thu Aug 04 18:23:07 2005 +0100
+++ b/mercurial/hgweb.py	Thu Aug 04 13:27:41 2005 -0800
@@ -6,7 +6,7 @@
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
 
-import os, cgi, time, re, difflib, sys, zlib
+import os, cgi, time, re, difflib, socket, sys, zlib
 from mercurial.hg import *
 from mercurial.ui import *
 
@@ -699,11 +699,14 @@
         else:
             write(self.t("error"))
 
-def create_server(path, name, templates, address, port,
+def create_server(path, name, templates, address, port, use_ipv6 = False,
                   accesslog = sys.stdout, errorlog = sys.stderr):
 
     import BaseHTTPServer
 
+    class IPv6HTTPServer(BaseHTTPServer.HTTPServer):
+        address_family = socket.AF_INET6
+
     class hgwebhandler(BaseHTTPServer.BaseHTTPRequestHandler):
         def log_error(self, format, *args):
             errorlog.write("%s - - [%s] %s\n" % (self.address_string(),
@@ -774,10 +777,13 @@
                 sys.argv, sys.stdin, sys.stdout, sys.stderr = save
 
     hg = hgweb(path, name, templates)
-    return BaseHTTPServer.HTTPServer((address, port), hgwebhandler)
+    if use_ipv6:
+        return IPv6HTTPServer((address, port), hgwebhandler)
+    else:
+        return BaseHTTPServer.HTTPServer((address, port), hgwebhandler)
 
-def server(path, name, templates, address, port,
+def server(path, name, templates, address, port, use_ipv6 = False,
            accesslog = sys.stdout, errorlog = sys.stderr):
-    httpd = create_server(path, name, templates, address, port,
+    httpd = create_server(path, name, templates, address, port, use_ipv6,
                           accesslog, errorlog)
     httpd.serve_forever()
--- a/mercurial/util.py	Thu Aug 04 18:23:07 2005 +0100
+++ b/mercurial/util.py	Thu Aug 04 13:27:41 2005 -0800
@@ -69,24 +69,27 @@
 _globchars = {'[': 1, '{': 1, '*': 1, '?': 1}
 
 def matcher(cwd, names, inc, exc, head = ''):
-    def patlike(name):
+    def patkind(name):
         for prefix in 're:', 'glob:', 'path:':
-            if name.startswith(prefix): return True
+            if name.startswith(prefix): return name.split(':', 1)
         for c in name:
-            if c in _globchars: return True
+            if c in _globchars: return 'glob', name
+        return 'relpath', name
+
+    cwdsep = cwd + os.sep
 
     def regex(name, tail):
         '''convert a pattern into a regular expression'''
-        if name.startswith('re:'):
-            return name[3:]
-        elif name.startswith('path:'):
-            return '^' + re.escape(name[5:]) + '$'
-        elif name.startswith('glob:'):
-            return head + globre(name[5:], '', tail)
+        kind, name = patkind(name)
+        if kind == 're':
+            return name
+        elif kind == 'path':
+            return '^' + re.escape(name) + '$'
+        if cwd: name = os.path.join(cwdsep, name)
+        name = os.path.normpath(name)
+        if name == '.': name = '**'
         return head + globre(name, '', tail)
 
-    cwdsep = cwd + os.sep
-
     def under(fn):
         """check if fn is under our cwd"""
         return not cwd or fn.startswith(cwdsep)
@@ -95,22 +98,28 @@
         """build a matching function from a set of patterns"""
         if pats:
             pat = '(?:%s)' % '|'.join([regex(p, tail) for p in pats])
-            if cwd:
-                pat = re.escape(cwdsep) + pat
             return re.compile(pat).match
 
-    pats = filter(patlike, names)
-    files = [n for n in names if not patlike(n)]
-    if pats: plain = []
-    elif cwd: plain = [cwdsep + f for f in files]
-    else: plain = files
+    def globprefix(pat):
+        '''return the non-glob prefix of a path, e.g. foo/* -> foo'''
+        root = []
+        for p in pat.split(os.sep):
+            if patkind(p)[0] == 'glob': break
+            root.append(p)
+        return os.sep.join(root)
+
+    patkinds = map(patkind, names)
+    pats = [name for (kind, name) in patkinds if kind != 'relpath']
+    files = [name for (kind, name) in patkinds if kind == 'relpath']
+    roots = filter(None, map(globprefix, pats)) + files
+    if cwd: roots = [cwdsep + r for r in roots]
         
-    patmatch = matchfn(pats, '$')
-    filematch = matchfn(files, '(?:/|$)')
-    incmatch = matchfn(inc, '(?:/|$)') or under
+    patmatch = matchfn(pats, '$') or always
+    filematch = matchfn(files, '(?:/|$)') or always
+    incmatch = matchfn(inc, '(?:/|$)') or always
     excmatch = matchfn(exc, '(?:/|$)') or (lambda fn: False)
 
-    return plain, lambda fn: (incmatch(fn) and not excmatch(fn) and
+    return roots, lambda fn: (incmatch(fn) and not excmatch(fn) and
                               (fn.endswith('/') or
                                (not pats and not files) or
                                (pats and patmatch(fn)) or
--- a/tests/test-merge5.out	Thu Aug 04 18:23:07 2005 +0100
+++ b/tests/test-merge5.out	Thu Aug 04 13:27:41 2005 -0800
@@ -9,4 +9,4 @@
 this update spans a branch affecting the following files:
  b
 aborting update spanning branches!
-(use update -m to perform a branch merge)
+(use update -m to merge across branches or -C to lose changes)