changeset 1780:8a1f2eae2832

Merge with jeffpc
author Matt Mackall <mpm@selenic.com>
date Tue, 21 Feb 2006 17:36:27 -0600
parents 0762feff3043 (diff) a1e6e02e9d05 (current diff)
children 35a05f177267 88f0345d82e9
files mercurial/hgweb.py
diffstat 23 files changed, 307 insertions(+), 160 deletions(-) [+]
line wrap: on
line diff
--- a/contrib/hbisect.py	Sat Feb 18 22:24:42 2006 -0500
+++ b/contrib/hbisect.py	Tue Feb 21 17:36:27 2006 -0600
@@ -187,7 +187,7 @@
         check_clean(self.ui, self.repo)
         rev = self.next()
         self.ui.write("Now testing %s\n" % hg.hex(rev))
-        return self.repo.update(rev, allow=True, force=True)
+        return self.repo.update(rev, force=True)
 
     def good(self, rev):
         self.goodrevs.append(rev)
@@ -232,7 +232,7 @@
             b.good(new_rev)
             ui.write("it is good\n")
         anc = b.ancestors()
-        repo.update(new_rev, allow=True, force=True)
+        repo.update(new_rev, force=True)
     for v in anc:
         if v != rev:
             ui.warn("fail to found cset! :(\n")
--- a/doc/hg.1.txt	Sat Feb 18 22:24:42 2006 -0500
+++ b/doc/hg.1.txt	Tue Feb 21 17:36:27 2006 -0600
@@ -376,6 +376,11 @@
     options:
     -I, --include <pat>   include names matching the given patterns
     -X, --exclude <pat>   exclude names matching the given patterns
+    -b, --branch          show branches
+    -k, --keyword <str>   search for keywords
+    -l, --limit <num>     print no more than this many changes
+    -M, --no-merges       do not show merges
+    -m, --only-merges     only show merges
     -r, --rev <A>         show the specified revision or range
     -p, --patch           show patch
 
@@ -543,10 +548,12 @@
 
     options:
     -A, --accesslog <file>   name of access log file to write to
+    -d, --daemon             run server in background, as a daemon
     -E, --errorlog <file>    name of error log file to write to
     -a, --address <addr>     address to use
     -p, --port <n>           port to use (default: 8000)
     -n, --name <name>        name to show in web pages (default: working dir)
+    --pid-file <file>        write server process ID to given file
     -t, --templatedir <path> web templates to use
     -6, --ipv6               use IPv6 in addition to IPv4
 
--- a/hgmerge	Sat Feb 18 22:24:42 2006 -0500
+++ b/hgmerge	Tue Feb 21 17:36:27 2006 -0600
@@ -17,31 +17,35 @@
 
 # find decent versions of our utilities, insisting on the GNU versions where we
 # need to
-MERGE=merge
-DIFF3=gdiff3
-DIFF=gdiff
-PATCH=gpatch
+MERGE="merge"
+DIFF3="gdiff3"
+DIFF="gdiff"
+PATCH="gpatch"
 
-type $MERGE >/dev/null 2>&1 || MERGE=
-type $DIFF3 >/dev/null 2>&1 || DIFF3=diff3
-type $DIFF  >/dev/null 2>&1 || DIFF=diff
-type $PATCH >/dev/null 2>&1 || PATCH=patch
+type "$MERGE" >/dev/null 2>&1 || MERGE=
+type "$DIFF3" >/dev/null 2>&1 || DIFF3="diff3"
 $DIFF3 --version >/dev/null 2>&1 || DIFF3=
+type "$DIFF"  >/dev/null 2>&1 || DIFF="diff"
+type "$DIFF"  >/dev/null 2>&1 || DIFF=
+type "$PATCH" >/dev/null 2>&1 || PATCH="patch"
+type "$PATCH" >/dev/null 2>&1 || PATCH=
 
 # find optional visual utilities
-FILEMERGE='/Developer/Applications/Utilities/FileMerge.app/Contents/MacOS/FileMerge'
-KDIFF3=kdiff3
-TKDIFF=tkdiff
+FILEMERGE="/Developer/Applications/Utilities/FileMerge.app/Contents/MacOS/FileMerge"
+KDIFF3="kdiff3"
+TKDIFF="tkdiff"
+MELD="meld"
 
-type $FILEMERGE >/dev/null 2>&1 || FILEMERGE=
-type $KDIFF3    >/dev/null 2>&1 || KDIFF3=
-type $TKDIFF    >/dev/null 2>&1 || TKDIFF=
+type "$FILEMERGE" >/dev/null 2>&1 || FILEMERGE=
+type "$KDIFF3"    >/dev/null 2>&1 || KDIFF3=
+type "$TKDIFF"    >/dev/null 2>&1 || TKDIFF=
+type "$MELD"      >/dev/null 2>&1 || MELD=
 
 # random part of names
-RAND="$RANDOM.$RANDOM.$RANDOM.$$"
+RAND="$RANDOM$RANDOM"
 
 # temporary directory for diff+patch merge
-HGTMP="${TMPDIR-/tmp}/hgmerge.$RAND"
+HGTMP="${TMPDIR-'/tmp'}/hgmerge.$RAND"
 
 # backup file
 BACKUP="$LOCAL.orig.$RAND"
@@ -68,6 +72,18 @@
     exit 1
 }
 
+# Ask if the merge was successful
+ask_if_merged() {
+    while 1; do
+        echo "$LOCAL seems unchanged. Was the merge successful? [y/n]"
+        read answer
+        case answer in
+            y*|Y*) success;;
+            n*|N*) failure;;
+        esac
+    done
+}
+
 # Clean up when interrupted
 trap "failure" 1 2 3 6 15 # HUP INT QUIT ABRT TERM
 
@@ -76,18 +92,16 @@
 cp "$BACKUP" "$LOCAL"
 
 # Attempt to do a non-interactive merge
-if [ -n "$MERGE" ]; then
-    $MERGE "$LOCAL" "$BASE" "$OTHER" 2> /dev/null && success
-    cp "$BACKUP" "$LOCAL"
-elif [ -n "$DIFF3" ]; then
-    echo $DIFF3 -m "$BACKUP" "$BASE" "$OTHER"
-    $DIFF3 -m "$BACKUP" "$BASE" "$OTHER" > "$LOCAL" && success
-    if [ $? -eq 2 ]; then
-        echo "$DIFF3 failed! Exiting." 1>&2
-        cp "$BACKUP" "$LOCAL"
+if [ -n "$MERGE" -o -n "$DIFF3" ]; then
+    if [ -n "$MERGE" ]; then
+        $MERGE "$LOCAL" "$BASE" "$OTHER" 2> /dev/null && success
+    elif [ -n "$DIFF3" ]; then
+        $DIFF3 -m "$BACKUP" "$BASE" "$OTHER" > "$LOCAL" && success
+    fi
+    if [ $? -gt 1 ]; then
+        echo "automatic merge failed! Exiting." 1>&2
         failure
     fi
-    cp "$BACKUP" "$LOCAL"
 fi
 
 # on MacOS X try FileMerge.app, shipped with Apple's developer tools
@@ -97,71 +111,66 @@
     # filemerge prefers the right by default
     $FILEMERGE -left "$OTHER" -right "$LOCAL" -ancestor "$BASE" -merge "$LOCAL"
     [ $? -ne 0 ] && echo "FileMerge failed to launch" && failure
-    if test "$LOCAL" -nt "$CHGTEST"
-    then
-        success
-    else
-        echo "$LOCAL seems unchanged. Was the merge successful?"
-        select answer in yes no
-        do
-            test "$answer" == "yes" && success || failure
-        done
-    fi
-    failure
+    test "$LOCAL" -nt "$CHGTEST" && success || ask_if_merged
 fi
 
 if [ -n "$DISPLAY" ]; then
     # try using kdiff3, which is fairly nice
     if [ -n "$KDIFF3" ]; then
-	$KDIFF3 --auto "$BASE" "$LOCAL" "$OTHER" -o "$LOCAL" || failure
-	success
+        $KDIFF3 --auto "$BASE" "$LOCAL" "$OTHER" -o "$LOCAL" || failure
+        success
     fi
 
     # try using tkdiff, which is a bit less sophisticated
     if [ -n "$TKDIFF" ]; then
-	$TKDIFF "$LOCAL" "$OTHER" -a "$BASE" -o "$LOCAL" || failure
-	success
+        $TKDIFF "$LOCAL" "$OTHER" -a "$BASE" -o "$LOCAL" || failure
+        success
+    fi
+
+    if [ -n "$MELD" ]; then
+        cp "$BACKUP" "$CHGTEST"
+        # protect our feet - meld allows us to save to the left file
+        cp "$BACKUP" "$LOCAL.tmp.$RAND"
+        # Meld doesn't have automatic merging, so to reduce intervention
+        # use the file with conflicts
+        $MELD "$LOCAL.tmp.$RAND" "$LOCAL" "$OTHER" || failure
+        # Also it doesn't return good error code
+        test "$LOCAL" -nt "$CHGTEST" && success || ask_if_merged
     fi
 fi
 
 # Attempt to do a merge with $EDITOR
-if [ -n "$MERGE" ]; then
-    echo "conflicts detected in $LOCAL"
-    $MERGE "$LOCAL" "$BASE" "$OTHER" 2>/dev/null || $EDITOR "$LOCAL"
-    success
-fi
-
-if [ -n "$DIFF3" ]; then
+if [ -n "$MERGE" -o -n "$DIFF3" ]; then
     echo "conflicts detected in $LOCAL"
-    $DIFF3 -m "$BACKUP" "$BASE" "$OTHER" > "$LOCAL" || {
-        case $? in
-            1)
-                $EDITOR "$LOCAL" ;;
-            2)  echo "$DIFF3 failed! Exiting." 1>&2
-                cp "$BACKUP" "$LOCAL"
-                failure ;;
-        esac
-        success
-    }
+    cp "$BACKUP" "$CHGTEST"
+    $EDITOR "$LOCAL" || failure
+    # Some editors do not return meaningful error codes
+    # Do not take any chances
+    test "$LOCAL" -nt "$CHGTEST" && success || ask_if_merged
 fi
 
 # attempt to manually merge with diff and patch
 if [ -n "$DIFF" -a -n "$PATCH" ]; then
 
     (umask 077 && mkdir "$HGTMP") || {
-	echo "Could not create temporary directory $HGTMP" 1>&2
-	failure
+        echo "Could not create temporary directory $HGTMP" 1>&2
+        failure
     }
 
     $DIFF -u "$BASE" "$OTHER" > "$HGTMP/diff" || :
     if $PATCH "$LOCAL" < "$HGTMP/diff"; then
-	success
+        success
     else
-	# If rejects are empty after using the editor, merge was ok
-	$EDITOR "$LOCAL" "$LOCAL.rej" && test -s "$LOCAL.rej" || success
+        # If rejects are empty after using the editor, merge was ok
+        $EDITOR "$LOCAL" "$LOCAL.rej" || failure
+        test -s "$LOCAL.rej" || success
     fi
     failure
 fi
 
-echo "hgmerge: unable to find merge, tkdiff, kdiff3, or diff+patch!"
+echo
+echo "hgmerge: unable to find any merge utility!"
+echo "supported programs:"
+echo "merge, FileMerge, tkdiff, kdiff3, meld, diff+patch"
+echo
 failure
--- a/mercurial/bdiff.c	Sat Feb 18 22:24:42 2006 -0500
+++ b/mercurial/bdiff.c	Tue Feb 21 17:36:27 2006 -0600
@@ -17,6 +17,10 @@
 #define inline
 #endif
 
+#ifdef __SUNPRO_C
+# define inline
+#endif 
+
 #ifdef _WIN32
 #ifdef _MSC_VER
 #define inline __inline
--- a/mercurial/commands.py	Sat Feb 18 22:24:42 2006 -0500
+++ b/mercurial/commands.py	Tue Feb 21 17:36:27 2006 -0600
@@ -115,8 +115,8 @@
                     yield rev
 
         minrev, maxrev = min(revs), max(revs)
-        for file in files:
-            filelog = repo.file(file)
+        for file_ in files:
+            filelog = repo.file(file_)
             # A zero count may be a directory or deleted file, so
             # try to find matching entries on the slow path.
             if filelog.count() == 0:
@@ -127,7 +127,7 @@
                     if rev < minrev:
                         break
                     fncache.setdefault(rev, [])
-                    fncache[rev].append(file)
+                    fncache[rev].append(file_)
                     wanted[rev] = 1
     if slowpath:
         # The slow path checks files modified in every changeset.
@@ -447,7 +447,6 @@
             f = f.lstrip("^")
             if not ui.debugflag and f.startswith("debug"):
                 continue
-            d = ""
             doc = e[0].__doc__
             if not doc:
                 doc = _("(No help text available)")
@@ -725,8 +724,8 @@
             # can end up with extra data in the cloned revlogs that's
             # not pointed to by changesets, thus causing verify to
             # fail
-            l1 = lock.lock(os.path.join(source, ".hg", "lock"))
-        except OSError:
+            l1 = other.lock()
+        except lock.LockException:
             copy = False
 
     if copy:
@@ -818,14 +817,19 @@
         reasons = {'?': _('is not managed'),
                    'a': _('has been marked for add'),
                    'r': _('has been marked for remove')}
-        reason = reasons.get(repo.dirstate.state(abs))
+        state = repo.dirstate.state(abs)
+        reason = reasons.get(state)
         if reason:
+            if state == 'a':
+                origsrc = repo.dirstate.copied(abs)
+                if origsrc is not None:
+                    return origsrc
             if exact:
                 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
         else:
-            return True
-
-    def copy(abssrc, relsrc, target, exact):
+            return abs
+
+    def copy(origsrc, abssrc, relsrc, target, exact):
         abstarget = util.canonpath(repo.root, cwd, target)
         reltarget = util.pathto(cwd, abstarget)
         prevsrc = targets.get(abstarget)
@@ -864,7 +868,7 @@
         if ui.verbose or not exact:
             ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
         targets[abstarget] = abssrc
-        repo.copy(abssrc, abstarget)
+        repo.copy(origsrc, abstarget)
         copied.append((abssrc, relsrc, exact))
 
     def targetpathfn(pat, dest, srcs):
@@ -938,8 +942,9 @@
     for pat in pats:
         srcs = []
         for tag, abssrc, relsrc, exact in walk(repo, [pat], opts):
-            if okaytocopy(abssrc, relsrc, exact):
-                srcs.append((abssrc, relsrc, exact))
+            origsrc = okaytocopy(abssrc, relsrc, exact)
+            if origsrc:
+                srcs.append((origsrc, abssrc, relsrc, exact))
         if not srcs:
             continue
         copylist.append((tfn(pat, dest, srcs), srcs))
@@ -947,8 +952,8 @@
         raise util.Abort(_('no files to copy'))
 
     for targetpath, srcs in copylist:
-        for abssrc, relsrc, exact in srcs:
-            copy(abssrc, relsrc, targetpath(abssrc), exact)
+        for origsrc, abssrc, relsrc, exact in srcs:
+            copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
 
     if errors:
         ui.warn(_('(consider using --after)\n'))
@@ -980,6 +985,18 @@
     a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
     ui.write("%d:%s\n" % (r.rev(a), hex(a)))
 
+def debugrebuildstate(ui, repo, rev=None):
+    """rebuild the dirstate as it would look like for the given revision"""
+    if not rev:
+        rev = repo.changelog.tip()
+    else:
+        rev = repo.lookup(rev)
+    change = repo.changelog.read(rev)
+    n = change[0]
+    files = repo.manifest.readflags(n)
+    wlock = repo.wlock()
+    repo.dirstate.rebuild(rev, files.iteritems())
+
 def debugcheckstate(ui, repo):
     """validate the correctness of the current dirstate"""
     parent1, parent2 = repo.dirstate.parents()
@@ -1284,6 +1301,7 @@
             s = linestate(line, lnum, cstart, cend)
             m[s] = s
 
+    # FIXME: prev isn't used, why ?
     prev = {}
     ucache = {}
     def display(fn, rev, states, prevstates):
@@ -1593,7 +1611,19 @@
                 self.write(*args)
         def __getattr__(self, key):
             return getattr(self.ui, key)
+
     changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
+
+    if opts['limit']:
+        try:
+            limit = int(opts['limit'])
+        except ValueError:
+            raise util.Abort(_('limit must be a positive integer'))
+        if limit <= 0: raise util.Abort(_('limit must be positive'))
+    else:
+        limit = sys.maxint
+    count = 0
+
     for st, rev, fns in changeiter:
         if st == 'window':
             du = dui(ui)
@@ -1607,7 +1637,6 @@
             if opts['only_merges'] and len(parents) != 2:
                 continue
 
-            br = None
             if opts['keyword']:
                 changes = getchange(rev)
                 miss = 0
@@ -1620,7 +1649,8 @@
                 if miss:
                     continue
 
-            if opts['branch']:
+            br = None
+            if opts['branches']:
                 br = repo.branchlookup([repo.changelog.node(rev)])
 
             show_changeset(du, repo, rev, brinfo=br)
@@ -1629,8 +1659,11 @@
                 dodiff(du, du, repo, prev, changenode, match=matchfn)
                 du.write("\n\n")
         elif st == 'iter':
-            for args in du.hunk[rev]:
-                ui.write(*args)
+            if count == limit: break
+            if du.hunk[rev]:
+                count += 1
+                for args in du.hunk[rev]:
+                    ui.write(*args)
 
 def manifest(ui, repo, rev=None):
     """output the latest or given revision of the project manifest
@@ -1681,7 +1714,7 @@
             dodiff(ui, ui, repo, prev, n)
             ui.write("\n")
 
-def parents(ui, repo, rev=None, branch=None):
+def parents(ui, repo, rev=None, branches=None):
     """show the parents of the working dir or revision
 
     Print the working directory's parent revisions.
@@ -1692,7 +1725,7 @@
         p = repo.dirstate.parents()
 
     br = None
-    if branch is not None:
+    if branches is not None:
         br = repo.branchlookup(p)
     for n in p:
         if n != nullid:
@@ -2022,6 +2055,16 @@
         if opts[o]:
             ui.setconfig("web", o, opts[o])
 
+    if opts['daemon'] and not opts['daemon_pipefds']:
+        rfd, wfd = os.pipe()
+        args = sys.argv[:]
+        args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
+        pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
+                         args[0], args)
+        os.close(wfd)
+        os.read(rfd, 1)
+        os._exit(0)
+
     try:
         httpd = hgweb.create_server(repo)
     except socket.error, inst:
@@ -2040,6 +2083,25 @@
             ui.status(_('listening at http://%s:%d/\n') % (addr, port))
         else:
             ui.status(_('listening at http://%s/\n') % addr)
+
+    if opts['pid_file']:
+        fp = open(opts['pid_file'], 'w')
+        fp.write(str(os.getpid()))
+        fp.close()
+
+    if opts['daemon_pipefds']:
+        rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
+        os.close(rfd)
+        os.write(wfd, 'y')
+        os.close(wfd)
+        sys.stdout.flush()
+        sys.stderr.flush()
+        fd = os.open(util.nulldev, os.O_RDWR)
+        if fd != 0: os.dup2(fd, 0)
+        if fd != 1: os.dup2(fd, 1)
+        if fd != 2: os.dup2(fd, 2)
+        if fd not in (0, 1, 2): os.close(fd)
+
     httpd.serve_forever()
 
 def status(ui, repo, *pats, **opts):
@@ -2164,7 +2226,10 @@
     Show the tip revision.
     """
     n = repo.changelog.tip()
-    show_changeset(ui, repo, changenode=n)
+    br = None
+    if opts['branches']:
+        br = repo.branchlookup([n])
+    show_changeset(ui, repo, changenode=n, brinfo=br)
     if opts['patch']:
         dodiff(ui, ui, repo, repo.changelog.parents(n)[0], n)
 
@@ -2324,6 +2389,10 @@
            _('forcibly copy over an existing managed file'))],
          _('hg copy [OPTION]... [SOURCE]... DEST')),
     "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
+    "debugrebuildstate":
+        (debugrebuildstate,
+         [('r', 'rev', "", _("revision to rebuild to"))],
+         _('debugrebuildstate [-r REV] [REV]')),
     "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
     "debugconfig": (debugconfig, [], _('debugconfig')),
     "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
@@ -2375,7 +2444,7 @@
          _('hg grep [OPTION]... PATTERN [FILE]...')),
     "heads":
         (heads,
-         [('b', 'branches', None, _('find branch info')),
+         [('b', 'branches', None, _('show branches')),
           ('r', 'rev', '', _('show only heads which are descendants of rev'))],
          _('hg heads [-b] [-r <rev>]')),
     "help": (help_, [], _('hg help [COMMAND]')),
@@ -2409,8 +2478,9 @@
         (log,
          [('I', 'include', [], _('include names matching the given patterns')),
           ('X', 'exclude', [], _('exclude names matching the given patterns')),
-          ('b', 'branch', None, _('show branches')),
+          ('b', 'branches', None, _('show branches')),
           ('k', 'keyword', [], _('search for a keyword')),
+          ('l', 'limit', '', _('limit number of changes displayed')),
           ('r', 'rev', [], _('show the specified revision or range')),
           ('M', 'no-merges', None, _('do not show merges')),
           ('m', 'only-merges', None, _('show only merges')),
@@ -2424,7 +2494,7 @@
          _('hg outgoing [-p] [-n] [-M] [DEST]')),
     "^parents":
         (parents,
-         [('b', 'branch', None, _('show branches'))],
+         [('b', 'branches', None, _('show branches'))],
          _('hg parents [-b] [REV]')),
     "paths": (paths, [], _('hg paths [NAME]')),
     "^pull":
@@ -2476,11 +2546,14 @@
     "^serve":
         (serve,
          [('A', 'accesslog', '', _('name of access log file to write to')),
+          ('d', 'daemon', None, _('run server in background')),
+          ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
           ('E', 'errorlog', '', _('name of error log file to write to')),
           ('p', 'port', 0, _('port to use (default: 8000)')),
           ('a', 'address', '', _('address to use')),
           ('n', 'name', '',
            _('name to show in web pages (default: working dir)')),
+          ('', 'pid-file', '', _('name of file to write process ID to')),
           ('', 'stdio', None, _('for remote clients')),
           ('t', 'templates', '', _('web templates to use')),
           ('', 'style', '', _('template style to use')),
@@ -2508,7 +2581,11 @@
           ('r', 'rev', '', _('revision to tag'))],
          _('hg tag [-r REV] [OPTION]... NAME')),
     "tags": (tags, [], _('hg tags')),
-    "tip": (tip, [('p', 'patch', None, _('show patch'))], _('hg tip')),
+    "tip":
+        (tip,
+         [('b', 'branches', None, _('show branches')),
+          ('p', 'patch', None, _('show patch'))],
+         _('hg [-b] [-p] tip')),
     "unbundle":
         (unbundle,
          [('u', 'update', None,
--- a/mercurial/dirstate.py	Sat Feb 18 22:24:42 2006 -0500
+++ b/mercurial/dirstate.py	Tue Feb 21 17:36:27 2006 -0600
@@ -197,6 +197,19 @@
 
     def clear(self):
         self.map = {}
+        self.copies = {}
+        self.markdirty()
+
+    def rebuild(self, parent, files):
+        self.clear()
+        umask = os.umask(0)
+        os.umask(umask)
+        for f, mode in files:
+            if mode:
+                self.map[f] = ('n', ~umask, -1, 0)
+            else:
+                self.map[f] = ('n', ~umask & 0666, -1, 0)
+        self.pl = (parent, nullid)
         self.markdirty()
 
     def write(self):
@@ -270,11 +283,11 @@
         elif not dc:
             dc = self.filterfiles(files)
 
-        def statmatch(file, stat):
-            file = util.pconvert(file)
-            if file not in dc and self.ignore(file):
+        def statmatch(file_, stat):
+            file_ = util.pconvert(file_)
+            if file_ not in dc and self.ignore(file_):
                 return False
-            return match(file)
+            return match(file_)
 
         return self.walkhelper(files=files, statmatch=statmatch, dc=dc)
 
@@ -350,9 +363,9 @@
                 continue
             if stat.S_ISDIR(st.st_mode):
                 cmp1 = (lambda x, y: cmp(x[1], y[1]))
-                sorted = [ x for x in findfiles(f) ]
-                sorted.sort(cmp1)
-                for e in sorted:
+                sorted_ = [ x for x in findfiles(f) ]
+                sorted_.sort(cmp1)
+                for e in sorted_:
                     yield e
             else:
                 ff = util.normpath(ff)
@@ -380,7 +393,7 @@
 
         for src, fn, st in self.statwalk(files, match):
             try:
-                type, mode, size, time = self[fn]
+                type_, mode, size, time = self[fn]
             except KeyError:
                 unknown.append(fn)
                 continue
@@ -399,22 +412,23 @@
                         nonexistent = False
                 # XXX: what to do with file no longer present in the fs
                 # who are not removed in the dirstate ?
-                if nonexistent and type in "nm":
+                if nonexistent and type_ in "nm":
                     deleted.append(fn)
                     continue
             # check the common case first
-            if type == 'n':
+            if type_ == 'n':
                 if not st:
                     st = os.stat(fn)
-                if size != st.st_size or (mode ^ st.st_mode) & 0100:
+                if size >= 0 and (size != st.st_size
+                                  or (mode ^ st.st_mode) & 0100):
                     modified.append(fn)
                 elif time != st.st_mtime:
                     lookup.append(fn)
-            elif type == 'm':
+            elif type_ == 'm':
                 modified.append(fn)
-            elif type == 'a':
+            elif type_ == 'a':
                 added.append(fn)
-            elif type == 'r':
+            elif type_ == 'r':
                 removed.append(fn)
 
         return (lookup, modified, added, removed, deleted, unknown)
--- a/mercurial/hgweb.py	Sat Feb 18 22:24:42 2006 -0500
+++ b/mercurial/hgweb.py	Tue Feb 21 17:36:27 2006 -0600
@@ -661,9 +661,10 @@
         i = self.repo.tagslist()
         i.reverse()
 
-        def entries(**map):
+        def entries(notip=False, **map):
             parity = 0
             for k,n in i:
+                if notip and k == "tip": continue
                 yield {"parity": parity,
                        "tag": k,
                        "tagmanifest": hex(cl.read(n)[0]),
@@ -673,7 +674,8 @@
 
         yield self.t("tags",
                      manifest=hex(mf),
-                     entries=entries)
+                     entries=lambda **x: entries(False, **x),
+                     entriesnotip=lambda **x: entries(True, **x))
 
     def summary(self):
         cl = self.repo.changelog
--- a/mercurial/localrepo.py	Sat Feb 18 22:24:42 2006 -0500
+++ b/mercurial/localrepo.py	Tue Feb 21 17:36:27 2006 -0600
@@ -231,7 +231,7 @@
                                        self.join("journal"), after)
 
     def recover(self):
-        lock = self.lock()
+        l = self.lock()
         if os.path.exists(self.join("journal")):
             self.ui.status(_("rolling back interrupted transaction\n"))
             transaction.rollback(self.opener, self.join("journal"))
@@ -245,7 +245,7 @@
     def undo(self, wlock=None):
         if not wlock:
             wlock = self.wlock()
-        lock = self.lock()
+        l = self.lock()
         if os.path.exists(self.join("undo")):
             self.ui.status(_("rolling back last transaction\n"))
             transaction.rollback(self.opener, self.join("undo"))
@@ -254,25 +254,25 @@
         else:
             self.ui.warn(_("no undo information available\n"))
 
-    def lock(self, wait=1):
+    def do_lock(self, lockname, wait, releasefn=None, acquirefn=None):
         try:
-            return lock.lock(self.join("lock"), 0)
-        except lock.LockHeld, inst:
-            if wait:
-                self.ui.warn(_("waiting for lock held by %s\n") % inst.args[0])
-                return lock.lock(self.join("lock"), wait)
-            raise inst
-
-    def wlock(self, wait=1):
-        try:
-            wlock = lock.lock(self.join("wlock"), 0, self.dirstate.write)
+            l = lock.lock(self.join(lockname), 0, releasefn)
         except lock.LockHeld, inst:
             if not wait:
                 raise inst
             self.ui.warn(_("waiting for lock held by %s\n") % inst.args[0])
-            wlock = lock.lock(self.join("wlock"), wait, self.dirstate.write)
-        self.dirstate.read()
-        return wlock
+            l = lock.lock(self.join(lockname), wait, releasefn)
+        if acquirefn:
+            acquirefn()
+        return l
+
+    def lock(self, wait=1):
+        return self.do_lock("lock", wait)
+
+    def wlock(self, wait=1):
+        return self.do_lock("wlock", wait,
+                            self.dirstate.write,
+                            self.dirstate.read)
 
     def checkfilemerge(self, filename, text, filelog, manifest1, manifest2):
         "determine whether a new filenode is needed"
@@ -311,7 +311,7 @@
 
         if not wlock:
             wlock = self.wlock()
-        lock = self.lock()
+        l = self.lock()
         tr = self.transaction()
         mm = m1.copy()
         mfm = mf1.copy()
@@ -388,7 +388,7 @@
 
         if not wlock:
             wlock = self.wlock()
-        lock = self.lock()
+        l = self.lock()
         tr = self.transaction()
 
         # check in files
@@ -508,7 +508,7 @@
             if not wlock:
                 try:
                     wlock = self.wlock(wait=0)
-                except lock.LockHeld:
+                except lock.LockException:
                     wlock = None
             lookup, modified, added, removed, deleted, unknown = (
                 self.dirstate.changes(files, match))
@@ -597,7 +597,6 @@
             if os.path.exists(p):
                 self.ui.warn(_("%s still exists!\n") % f)
             elif self.dirstate.state(f) == 'a':
-                self.ui.warn(_("%s never committed!\n") % f)
                 self.dirstate.forget([f])
             elif f not in self.dirstate:
                 self.ui.warn(_("%s not tracked!\n") % f)
@@ -932,7 +931,7 @@
         return subset
 
     def pull(self, remote, heads=None):
-        lock = self.lock()
+        l = self.lock()
 
         # if we have an empty repo, fetch everything
         if self.changelog.tip() == nullid:
@@ -952,7 +951,7 @@
         return self.addchangegroup(cg)
 
     def push(self, remote, force=False):
-        lock = remote.lock()
+        l = remote.lock()
 
         base = {}
         heads = remote.heads()
--- a/mercurial/lock.py	Sat Feb 18 22:24:42 2006 -0500
+++ b/mercurial/lock.py	Tue Feb 21 17:36:27 2006 -0600
@@ -5,10 +5,14 @@
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
 
-import os, time
+import errno, os, time
 import util
 
-class LockHeld(Exception):
+class LockException(Exception):
+    pass
+class LockHeld(LockException):
+    pass
+class LockUnavailable(LockException):
     pass
 
 class lock(object):
@@ -38,8 +42,11 @@
         try:
             util.makelock(str(pid), self.f)
             self.held = 1
-        except (OSError, IOError):
-            raise LockHeld(util.readlock(self.f))
+        except (OSError, IOError), why:
+            if why.errno == errno.EEXIST:
+                raise LockHeld(util.readlock(self.f))
+            else:
+                raise LockUnavailable(why)
 
     def release(self):
         if self.held:
--- a/mercurial/mpatch.c	Sat Feb 18 22:24:42 2006 -0500
+++ b/mercurial/mpatch.c	Tue Feb 21 17:36:27 2006 -0600
@@ -66,7 +66,7 @@
 			a = NULL;
 		} else
 			a->head = a->tail = a->base;
-			return a;
+		return a;
 	}
 	if (!PyErr_Occurred())
 		PyErr_NoMemory();
--- a/mercurial/revlog.py	Sat Feb 18 22:24:42 2006 -0500
+++ b/mercurial/revlog.py	Tue Feb 21 17:36:27 2006 -0600
@@ -624,12 +624,10 @@
             # we store negative distances because heap returns smallest member
             h = [(-dist[node], node)]
             seen = {}
-            earliest = self.count()
             while h:
                 d, n = heapq.heappop(h)
                 if n not in seen:
                     seen[n] = 1
-                    r = self.rev(n)
                     yield (-d, n)
                     for p in self.parents(n):
                         heapq.heappush(h, (-dist[p], p))
@@ -690,11 +688,6 @@
         p = self.parents(self.node(revs[0]))[0]
         revs.insert(0, self.rev(p))
 
-        # helper to reconstruct intermediate versions
-        def construct(text, base, rev):
-            bins = [self.chunk(r) for r in xrange(base + 1, rev + 1)]
-            return mdiff.patches(text, bins)
-
         # build deltas
         for d in xrange(0, len(revs) - 1):
             a, b = revs[d], revs[d + 1]
@@ -738,10 +731,10 @@
         base = prev = -1
         start = end = measure = 0
         if r:
-            start = self.start(self.base(t))
+            base = self.base(t)
+            start = self.start(base)
             end = self.end(t)
-            measure = self.length(self.base(t))
-            base = self.base(t)
+            measure = self.length(base)
             prev = self.tip()
 
         transaction.add(self.datafile, end)
@@ -793,14 +786,15 @@
                     raise RevlogError(_("consistency error adding group"))
                 measure = len(text)
             else:
-                e = (end, len(cdelta), self.base(t), link, p1, p2, node)
+                e = (end, len(cdelta), base, link, p1, p2, node)
                 self.index.append(e)
                 self.nodemap[node] = r
                 dfh.write(cdelta)
                 ifh.write(struct.pack(indexformat, *e))
 
             t, r, chain, prev = r, r + 1, node, node
-            start = self.start(self.base(t))
+            base = self.base(t)
+            start = self.start(base)
             end = self.end(t)
 
         dfh.close()
--- a/templates/map-rss	Sat Feb 18 22:24:42 2006 -0500
+++ b/templates/map-rss	Tue Feb 21 17:36:27 2006 -0600
@@ -4,3 +4,5 @@
 changelogentry = changelogentry-rss.tmpl
 filelog = filelog-rss.tmpl
 filelogentry = filelogentry-rss.tmpl
+tags = tags-rss.tmpl
+tagentry = tagentry-rss.tmpl
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/tagentry-rss.tmpl	Tue Feb 21 17:36:27 2006 -0600
@@ -0,0 +1,6 @@
+<item>
+    <title>#tag|escape#</title>
+    <link>#url#?cs=#node|short#</link>
+    <description><![CDATA[#tag|strip|escape|addbreaks#]]></description>
+    <pubDate>#date|rfc822date#</pubDate>
+</item>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/tags-rss.tmpl	Tue Feb 21 17:36:27 2006 -0600
@@ -0,0 +1,6 @@
+#header#
+    <title>#repo|escape#: tags </title>
+    <description>#repo|escape# tag history</description>
+    #entriesnotip%tagentry#
+  </channel>
+</rss>
--- a/templates/tags.tmpl	Sat Feb 18 22:24:42 2006 -0500
+++ b/templates/tags.tmpl	Tue Feb 21 17:36:27 2006 -0600
@@ -1,11 +1,14 @@
 #header#
 <title>#repo|escape#: tags</title>
+<link rel="alternate" type="application/rss+xml"
+   href="?cmd=tags;style=rss" title="RSS feed for #repo|escape#: tags">
 </head>
 <body>
 
 <div class="buttons">
 <a href="?cl=tip">changelog</a>
 <a href="?mf=#manifest|short#;path=/">manifest</a>
+<a type="application/rss+xml" href="?cmd=tags;style=rss">rss</a>
 </div>
 
 <h2>tags:</h2>
--- a/tests/test-archive	Sat Feb 18 22:24:42 2006 -0500
+++ b/tests/test-archive	Tue Feb 21 17:36:27 2006 -0600
@@ -18,8 +18,8 @@
 echo "allowzip = true" >> .hg/hgrc
 echo "allowgz = true" >> .hg/hgrc
 echo "allowbz2 = true" >> .hg/hgrc
-hg serve -p 20059 > /dev/null &
-sleep 1 # wait for server to be started
+serverpid=`mktemp`
+hg serve -p 20059 -d --pid-file=$serverpid
 
 TIP=`hg id -v | cut -f1 -d' '`
 QTIP=`hg id -q`
@@ -35,4 +35,5 @@
 http_proxy= python getarchive.py "$TIP" zip > archive.zip
 unzip -t archive.zip | sed "s/$QTIP/TIP/"
 
-kill $!
+kill `cat $serverpid`
+rm $serverpid
--- a/tests/test-archive.out	Sat Feb 18 22:24:42 2006 -0500
+++ b/tests/test-archive.out	Tue Feb 21 17:36:27 2006 -0600
@@ -12,4 +12,3 @@
     testing: test-archive-TIP/baz/bletch   OK
     testing: test-archive-TIP/foo   OK
 No errors detected in compressed data of archive.zip.
-killed!
--- a/tests/test-merge3.out	Sat Feb 18 22:24:42 2006 -0500
+++ b/tests/test-merge3.out	Tue Feb 21 17:36:27 2006 -0600
@@ -1,3 +1,2 @@
 removing b
-b never committed!
 nothing changed
--- a/tests/test-pull	Sat Feb 18 22:24:42 2006 -0500
+++ b/tests/test-pull	Tue Feb 21 17:36:27 2006 -0600
@@ -7,8 +7,8 @@
 hg addremove
 hg commit -m 1
 hg verify
-hg serve -p 20059 > /dev/null &
-sleep 1 # wait for server to be started
+serverpid=`mktemp`
+hg serve -p 20059 -d --pid-file=$serverpid
 cd ..
 
 hg clone http://localhost:20059/ copy
@@ -19,4 +19,5 @@
 hg manifest
 hg pull
 
-kill $!
+kill `cat $serverpid`
+rm $serverpid
--- a/tests/test-pull-permission	Sat Feb 18 22:24:42 2006 -0500
+++ b/tests/test-pull-permission	Tue Feb 21 17:36:27 2006 -0600
@@ -12,9 +12,8 @@
 cd ..
 
 hg clone a b
+
+chmod +w a/.hg # let test clean up
+
 cd b
 hg verify
-
-cd ..
-
-chmod +w a/.hg # let test clean up
--- a/tests/test-pull.out	Sat Feb 18 22:24:42 2006 -0500
+++ b/tests/test-pull.out	Tue Feb 21 17:36:27 2006 -0600
@@ -19,4 +19,3 @@
 pulling from http://localhost:20059/
 searching for changes
 no changes found
-killed!
--- a/tests/test-rename	Sat Feb 18 22:24:42 2006 -0500
+++ b/tests/test-rename	Tue Feb 21 17:36:27 2006 -0600
@@ -158,3 +158,16 @@
 hg rename d1 d3
 hg status
 hg update -C
+
+echo "# transitive rename"
+hg rename d1/b d1/bb
+hg rename d1/bb d1/bc
+hg status
+hg update -C
+
+echo "# transitive rename --after"
+hg rename d1/b d1/bb
+mv d1/bb d1/bc
+hg rename --after d1/bb d1/bc
+hg status
+hg update -C
--- a/tests/test-rename.out	Sat Feb 18 22:24:42 2006 -0500
+++ b/tests/test-rename.out	Tue Feb 21 17:36:27 2006 -0600
@@ -246,3 +246,9 @@
 R d1/b
 R d1/ba
 R d1/d11/a1
+# transitive rename
+A d1/bc
+R d1/b
+# transitive rename --after
+A d1/bc
+R d1/b