changeset 2574:78c2903fcabe

merge with mpm.
author Vadim Gelfer <vadim.gelfer@gmail.com>
date Thu, 06 Jul 2006 15:04:10 -0700
parents b13a98bd078e (diff) 82e3b2966862 (current diff)
children 7289d20b18cd
files mercurial/commands.py
diffstat 11 files changed, 151 insertions(+), 53 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/commands.py	Thu Jul 06 14:15:24 2006 -0500
+++ b/mercurial/commands.py	Thu Jul 06 15:04:10 2006 -0700
@@ -2649,7 +2649,7 @@
 
     if opts['pid_file']:
         fp = open(opts['pid_file'], 'w')
-        fp.write(str(os.getpid()))
+        fp.write(str(os.getpid()) + '\n')
         fp.close()
 
     if opts['daemon_pipefds']:
@@ -3371,12 +3371,12 @@
 def findext(name):
     '''return module with given extension name'''
     try:
-        return external[name]
+        return sys.modules[external[name]]
     except KeyError:
         dotname = '.' + name
         for k, v in external.iteritems():
-            if k.endswith('.' + name) or v.__name__ == name:
-                return v
+            if k.endswith('.' + name) or v == name:
+                return sys.modules[v]
         raise KeyError(name)
     
 def dispatch(args):
@@ -3390,14 +3390,14 @@
         sys.stderr.write(_("abort: %s\n") % inst)
         return -1
 
-    for x in u.extensions():
+    for ext_name, load_from_name in u.extensions():
         try:
-            if x[1]:
+            if load_from_name:
                 # the module will be loaded in sys.modules
                 # choose an unique name so that it doesn't
                 # conflicts with other modules
-                module_name = "hgext_%s" % x[0].replace('.', '_')
-                mod = imp.load_source(module_name, x[1])
+                module_name = "hgext_%s" % ext_name.replace('.', '_')
+                mod = imp.load_source(module_name, load_from_name)
             else:
                 def importh(name):
                     mod = __import__(name)
@@ -3406,12 +3406,10 @@
                         mod = getattr(mod, comp)
                     return mod
                 try:
-                    name = 'hgext.' + x[0]
-                    mod = importh(name)
+                    mod = importh("hgext.%s" % ext_name)
                 except ImportError:
-                    name = x[0]
-                    mod = importh(name)
-            external[name] = mod
+                    mod = importh(ext_name)
+            external[ext_name] = mod.__name__
         except (util.SignalInterrupt, KeyboardInterrupt):
             raise
         except Exception, inst:
@@ -3419,14 +3417,15 @@
             if u.print_exc():
                 return 1
 
-    for x in external.itervalues():
-        uisetup = getattr(x, 'uisetup', None)
+    for name in external.itervalues():
+        mod = sys.modules[name]
+        uisetup = getattr(mod, 'uisetup', None)
         if uisetup:
             uisetup(u)
-        cmdtable = getattr(x, 'cmdtable', {})
+        cmdtable = getattr(mod, 'cmdtable', {})
         for t in cmdtable:
             if t in table:
-                u.warn(_("module %s overrides %s\n") % (x.__name__, t))
+                u.warn(_("module %s overrides %s\n") % (name, t))
         table.update(cmdtable)
 
     try:
@@ -3475,9 +3474,10 @@
                     if not repo:
                         repo = hg.repository(u, path=path)
                     u = repo.ui
-                    for x in external.itervalues():
-                        if hasattr(x, 'reposetup'):
-                            x.reposetup(u, repo)
+                    for name in external.itervalues():
+                        mod = sys.modules[name]
+                        if hasattr(mod, 'reposetup'):
+                            mod.reposetup(u, repo)
                 except hg.RepoError:
                     if cmd not in optionalrepo.split():
                         raise
--- a/mercurial/httprepo.py	Thu Jul 06 14:15:24 2006 -0500
+++ b/mercurial/httprepo.py	Thu Jul 06 15:04:10 2006 -0700
@@ -87,25 +87,31 @@
             for chunk in util.filechunkiter(data):
                 keepalive.HTTPConnection.send(self, chunk)
 
-class httphandler(keepalive.HTTPHandler):
+class basehttphandler(keepalive.HTTPHandler):
     def http_open(self, req):
         return self.do_open(httpconnection, req)
 
-class httpsconnection(httplib.HTTPSConnection):
-    # must be able to send big bundle as stream.
+has_https = hasattr(urllib2, 'HTTPSHandler')
+if has_https:
+    class httpsconnection(httplib.HTTPSConnection):
+        response_class = keepalive.HTTPResponse
+        # must be able to send big bundle as stream.
 
-    def send(self, data):
-        if isinstance(data, str):
-            httplib.HTTPSConnection.send(self, data)
-        else:
-            # if auth required, some data sent twice, so rewind here
-            data.seek(0)
-            for chunk in util.filechunkiter(data):
-                httplib.HTTPSConnection.send(self, chunk)
+        def send(self, data):
+            if isinstance(data, str):
+                httplib.HTTPSConnection.send(self, data)
+            else:
+                # if auth required, some data sent twice, so rewind here
+                data.seek(0)
+                for chunk in util.filechunkiter(data):
+                    httplib.HTTPSConnection.send(self, chunk)
 
-class httpshandler(urllib2.HTTPSHandler):
-    def https_open(self, req):
-        return self.do_open(httpsconnection, req)
+    class httphandler(basehttphandler, urllib2.HTTPSHandler):
+        def https_open(self, req):
+            return self.do_open(httpsconnection, req)
+else:
+    class httphandler(basehttphandler):
+        pass
 
 class httprepository(remoterepository):
     def __init__(self, ui, path):
@@ -176,7 +182,6 @@
 
         opener = urllib2.build_opener(
             handler,
-            httpshandler(),
             urllib2.HTTPBasicAuthHandler(passmgr),
             urllib2.HTTPDigestAuthHandler(passmgr))
 
@@ -322,4 +327,8 @@
             os.unlink(tempname)
 
 class httpsrepository(httprepository):
-    pass
+    def __init__(self, ui, path):
+        if not has_https:
+            raise util.Abort(_('Python support for SSL and HTTPS '
+                               'is not installed'))
+        httprepository.__init__(self, ui, path)
--- a/tests/run-tests.py	Thu Jul 06 14:15:24 2006 -0500
+++ b/tests/run-tests.py	Thu Jul 06 15:04:10 2006 -0700
@@ -7,23 +7,32 @@
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
 
-import os, sys, shutil, re
+import difflib
+import errno
+import optparse
+import os
+import popen2
+import re
+import shutil
+import signal
+import sys
 import tempfile
-import difflib
-import popen2
-from optparse import OptionParser
+import time
 
 required_tools = ["python", "diff", "grep", "unzip", "gunzip", "bunzip2", "sed"]
 
-parser = OptionParser("%prog [options] [tests]")
+parser = optparse.OptionParser("%prog [options] [tests]")
 parser.add_option("-v", "--verbose", action="store_true",
     help="output verbose messages")
+parser.add_option("-t", "--timeout", type="int",
+    help="output verbose messages")
 parser.add_option("-c", "--cover", action="store_true",
     help="print a test coverage report")
 parser.add_option("-s", "--cover_stdlib", action="store_true",
     help="print a test coverage report inc. standard libraries")
 parser.add_option("-C", "--annotate", action="store_true",
     help="output files annotated with coverage")
+parser.set_defaults(timeout=30)
 (options, args) = parser.parse_args()
 verbose = options.verbose
 coverage = options.cover or options.cover_stdlib or options.annotate
@@ -79,6 +88,23 @@
         print "# Cleaning up HGTMP", HGTMP
     shutil.rmtree(HGTMP, True)
 
+def use_correct_python():
+    # some tests run python interpreter. they must use same
+    # interpreter we use or bad things will happen.
+    exedir, exename = os.path.split(sys.executable)
+    if exename == 'python':
+        path = find_program('python')
+        if os.path.dirname(path) == exedir:
+            return
+    vlog('# Making python executable in test path use correct Python')
+    my_python = os.path.join(BINDIR, 'python')
+    try:
+        os.symlink(sys.executable, my_python)
+    except AttributeError:
+        # windows fallback
+        shutil.copyfile(sys.executable, my_python)
+        shutil.copymode(sys.executable, my_python)
+            
 def install_hg():
     vlog("# Performing temporary installation of HG")
     installerrs = os.path.join("tests", "install.err")
@@ -102,6 +128,8 @@
     os.environ["PATH"] = "%s%s%s" % (BINDIR, os.pathsep, os.environ["PATH"])
     os.environ["PYTHONPATH"] = PYTHONDIR
 
+    use_correct_python()
+
     if coverage:
         vlog("# Installing coverage wrapper")
         os.environ['COVERAGE_FILE'] = COVERAGE_FILE
@@ -140,6 +168,12 @@
         vlog("# Running: "+cmd)
         os.system(cmd)
 
+class Timeout(Exception):
+    pass
+
+def alarmed(signum, frame):
+    raise Timeout
+
 def run(cmd):
     """Run command in a sub-process, capturing the output (stdout and stderr).
     Return the exist code, and output."""
@@ -153,9 +187,17 @@
             ret = 0
     else:
         proc = popen2.Popen4(cmd)
-        proc.tochild.close()
-        output = proc.fromchild.read()
-        ret = proc.wait()
+        try:
+            output = ''
+            proc.tochild.close()
+            output = proc.fromchild.read()
+            ret = proc.wait()
+        except Timeout:
+            vlog('# Process %d timed out - killing it' % proc.pid)
+            os.kill(proc.pid, signal.SIGTERM)
+            ret = proc.wait()
+            if ret == 0:
+                ret = signal.SIGTERM << 8
     return ret, splitnewlines(output)
 
 def run_one(test):
@@ -185,10 +227,16 @@
     if os.name == 'nt' and test.endswith(".bat"):
         cmd = 'cmd /c call "%s"' % (os.path.join(TESTDIR, test))
 
+    if options.timeout > 0:
+        signal.alarm(options.timeout)
+
     vlog("# Running", cmd)
     ret, out = run(cmd)
     vlog("# Ret was:", ret)
 
+    if options.timeout > 0:
+        signal.alarm(0)
+
     diffret = 0
     # If reference output file exists, check test output against it
     if os.path.exists(ref):
@@ -212,6 +260,30 @@
             f.write(line)
         f.close()
 
+    # Kill off any leftover daemon processes
+    try:
+        fp = file(DAEMON_PIDS)
+        for line in fp:
+            try:
+                pid = int(line)
+            except ValueError:
+                continue
+            try:
+                os.kill(pid, 0)
+                vlog('# Killing daemon process %d' % pid)
+                os.kill(pid, signal.SIGTERM)
+                time.sleep(0.25)
+                os.kill(pid, 0)
+                vlog('# Daemon process %d is stuck - really killing it' % pid)
+                os.kill(pid, signal.SIGKILL)
+            except OSError, err:
+                if err.errno != errno.ESRCH:
+                    raise
+        fp.close()
+        os.unlink(DAEMON_PIDS)
+    except IOError:
+        pass
+
     os.chdir(TESTDIR)
     shutil.rmtree(tmpd, True)
     return ret == 0
@@ -233,6 +305,8 @@
 
 TESTDIR = os.environ["TESTDIR"] = os.getcwd()
 HGTMP   = os.environ["HGTMP"]   = tempfile.mkdtemp("", "hgtests.")
+DAEMON_PIDS = os.environ["DAEMON_PIDS"] = os.path.join(HGTMP, 'daemon.pids')
+
 vlog("# Using TESTDIR", TESTDIR)
 vlog("# Using HGTMP", HGTMP)
 
@@ -245,6 +319,15 @@
     try:
         install_hg()
 
+        if options.timeout > 0:
+            try:
+                signal.signal(signal.SIGALRM, alarmed)
+                vlog('# Running tests with %d-second timeout' %
+                     options.timeout)
+            except AttributeError:
+                print 'WARNING: cannot run tests with timeouts'
+                options.timeout = 0
+
         tests = 0
         failed = 0
 
--- a/tests/test-archive	Thu Jul 06 14:15:24 2006 -0500
+++ b/tests/test-archive	Thu Jul 06 15:04:10 2006 -0700
@@ -17,6 +17,7 @@
 echo "name = test-archive" >> .hg/hgrc
 echo "allow_archive = gz bz2, zip" >> .hg/hgrc
 hg serve -p 20059 -d --pid-file=hg.pid
+cat hg.pid >> $DAEMON_PIDS
 
 TIP=`hg id -v | cut -f1 -d' '`
 QTIP=`hg id -q`
@@ -32,9 +33,6 @@
 http_proxy= python getarchive.py "$TIP" zip > archive.zip
 unzip -t archive.zip | sed "s/$QTIP/TIP/"
 
-kill `cat hg.pid`
-sleep 1 # wait for server to scream and die
-
 hg archive -t tar test.tar
 tar tf test.tar
 
--- a/tests/test-bad-pull	Thu Jul 06 14:15:24 2006 -0500
+++ b/tests/test-bad-pull	Thu Jul 06 15:04:10 2006 -0700
@@ -18,6 +18,7 @@
 EOF
 
 python dumb.py 2>/dev/null &
+echo $! >> $DAEMON_PIDS
 
 http_proxy= hg clone http://localhost:20059/foo copy2 2>&1 | \
     sed -e 's/404.*/404/' -e 's/Date:.*/Date:/'
--- a/tests/test-http-proxy	Thu Jul 06 14:15:24 2006 -0500
+++ b/tests/test-http-proxy	Thu Jul 06 15:04:10 2006 -0700
@@ -5,10 +5,12 @@
 echo a > a
 hg ci -Ama -d '1123456789 0'
 hg serve -p 20059 -d --pid-file=hg.pid
+cat hg.pid >> $DAEMON_PIDS
 
 cd ..
-("$TESTDIR/tinyproxy.py" 20060 localhost >/dev/null 2>&1 </dev/null &
+("$TESTDIR/tinyproxy.py" 20060 localhost >proxy.log 2>&1 </dev/null &
 echo $! > proxy.pid)
+cat proxy.pid >> $DAEMON_PIDS
 sleep 2
 
 echo %% url for proxy
@@ -26,5 +28,4 @@
 echo %% bad host:port for proxy
 http_proxy=localhost:20061 hg clone --config http_proxy.always=True http://localhost:20059/ f
 
-kill `cat proxy.pid a/hg.pid`
 exit 0
--- a/tests/test-incoming-outgoing	Thu Jul 06 14:15:24 2006 -0500
+++ b/tests/test-incoming-outgoing	Thu Jul 06 15:04:10 2006 -0700
@@ -9,6 +9,7 @@
 done
 hg verify
 hg serve -p 20059 -d --pid-file=hg.pid
+cat hg.pid >> $DAEMON_PIDS
 cd ..
 
 hg init new
@@ -45,5 +46,3 @@
 hg -R test-dev outgoing test
 http_proxy= hg -R test-dev outgoing http://localhost:20059/
 http_proxy= hg -R test-dev outgoing -r 11 http://localhost:20059/
-
-kill `cat test/hg.pid`
--- a/tests/test-pull	Thu Jul 06 14:15:24 2006 -0500
+++ b/tests/test-pull	Thu Jul 06 15:04:10 2006 -0700
@@ -8,6 +8,7 @@
 hg commit -m 1
 hg verify
 hg serve -p 20059 -d --pid-file=hg.pid
+cat hg.pid >> $DAEMON_PIDS
 cd ..
 
 http_proxy= hg clone http://localhost:20059/ copy
@@ -17,5 +18,3 @@
 cat foo
 hg manifest
 hg pull
-
-kill `cat ../test/hg.pid`
--- a/tests/test-push-http	Thu Jul 06 14:15:24 2006 -0500
+++ b/tests/test-push-http	Thu Jul 06 15:04:10 2006 -0700
@@ -15,6 +15,7 @@
 
 echo % expect ssl error
 hg serve -p 20059 -d --pid-file=hg.pid
+cat hg.pid >> $DAEMON_PIDS
 hg --cwd ../test2 push http://localhost:20059/
 kill `cat hg.pid`
 
@@ -22,18 +23,21 @@
 echo '[web]' > .hg/hgrc
 echo 'push_ssl = false' >> .hg/hgrc
 hg serve -p 20059 -d --pid-file=hg.pid
+cat hg.pid >> $DAEMON_PIDS
 hg --cwd ../test2 push http://localhost:20059/
 kill `cat hg.pid`
 
 echo % expect authorization error: must have authorized user
 echo 'allow_push = unperson' >> .hg/hgrc
 hg serve -p 20059 -d --pid-file=hg.pid
+cat hg.pid >> $DAEMON_PIDS
 hg --cwd ../test2 push http://localhost:20059/
 kill `cat hg.pid`
 
 echo % expect success
 echo 'allow_push = *' >> .hg/hgrc
 hg serve -p 20059 -d --pid-file=hg.pid
+cat hg.pid >> $DAEMON_PIDS
 hg --cwd ../test2 push http://localhost:20059/
 kill `cat hg.pid`
 hg rollback
@@ -41,11 +45,13 @@
 echo % expect authorization error: all users denied
 echo 'deny_push = *' >> .hg/hgrc
 hg serve -p 20059 -d --pid-file=hg.pid
+cat hg.pid >> $DAEMON_PIDS
 hg --cwd ../test2 push http://localhost:20059/
 kill `cat hg.pid`
 
 echo % expect authorization error: some users denied, users must be authenticated
 echo 'deny_push = unperson' >> .hg/hgrc
 hg serve -p 20059 -d --pid-file=hg.pid
+cat hg.pid >> $DAEMON_PIDS
 hg --cwd ../test2 push http://localhost:20059/
 kill `cat hg.pid`
--- a/tests/test-static-http	Thu Jul 06 14:15:24 2006 -0500
+++ b/tests/test-static-http	Thu Jul 06 15:04:10 2006 -0700
@@ -20,6 +20,7 @@
 EOF
 
 python dumb.py 2>/dev/null &
+echo $! >> $DAEMON_PIDS
 
 mkdir remote
 cd remote
--- a/tests/test-webraw	Thu Jul 06 14:15:24 2006 -0500
+++ b/tests/test-webraw	Thu Jul 06 15:04:10 2006 -0700
@@ -11,6 +11,7 @@
 hg add sometext.txt
 hg commit -d "1 0" -m "Just some text"
 hg serve -p 20059 -A access.log -E error.log -d --pid-file=hg.pid
+cat hg.pid >> $DAEMON_PIDS
 ("$TESTDIR/get-with-headers.py" localhost:20059 '/?f=f165dc289438;file=sometext.txt;style=raw' content-type content-length content-disposition) >getoutput.txt &
 
 sleep 5