view mercurial/packagescan.py @ 4095:6fa7a2d0fc2e

hgweb: catch util.Abort raised by addchangegroup Right now, if a pretxnchangegroup hook fails, we send some HTML error message to the client and the transaction is not rolled back (issue499). Catching util.Abort allows us to send a decent message to the client and for some reason makes the rollback complete. This patch is not perfect since it doesn't fix the reason why the transaction wasn't rolled back (maybe some circular references?). Also, the transaction is aborted only after we've sent the response back to the client and the "transaction aborted" message ends up in the logs of the web server.
author Alexis S. L. Carvalho <alexis@cecm.usp.br>
date Fri, 16 Feb 2007 05:10:43 -0200
parents eb0b4a2d70a9
children
line wrap: on
line source

# packagescan.py - Helper module for identifing used modules.
# Used for the py2exe distutil.
# This module must be the first mercurial module imported in setup.py
#
# Copyright 2005, 2006 Volker Kleinfeld <Volker.Kleinfeld@gmx.de>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
import glob
import os
import sys
import ihooks
import types
import string

# Install this module as fake demandload module
sys.modules['mercurial.demandload'] = sys.modules[__name__]

# Requiredmodules contains the modules imported by demandload.
# Please note that demandload can be invoked before the
# mercurial.packagescan.scan method is invoked in case a mercurial
# module is imported.
requiredmodules = {}
def demandload(scope, modules):
    """ fake demandload function that collects the required modules
        foo            import foo
        foo bar        import foo, bar
        foo.bar        import foo.bar
        foo@bar        import foo as bar
        foo:bar        from foo import bar
        foo:bar,quux   from foo import bar, quux
        foo.bar:quux   from foo.bar import quux"""

    for m in modules.split():
        mod = None
        try:
            module, fromlist = m.split(':')
            fromlist = fromlist.split(',')
        except:
            module = m
            fromlist = []
        as_ = None
        if '@' in module:
            module, as_ = module.split('@')
        mod = __import__(module, scope, scope, fromlist)
        if fromlist == []:
            # mod is only the top package, but we need all packages
            comp = module.split('.')
            i = 1
            mn = comp[0]
            while True:
                # mn and mod.__name__ might not be the same
                if not as_:
                    as_ = mn
                scope[as_] = mod
                requiredmodules[mod.__name__] = 1
                if len(comp) == i: break
                mod = getattr(mod, comp[i])
                mn = string.join(comp[:i+1],'.')
                i += 1
        else:
            # mod is the last package in the component list
            requiredmodules[mod.__name__] = 1
            for f in fromlist:
                scope[f] = getattr(mod, f)
                if type(scope[f]) == types.ModuleType:
                    requiredmodules[scope[f].__name__] = 1

class SkipPackage(Exception):
    def __init__(self, reason):
        self.reason = reason

scan_in_progress = False

def scan(libpath, packagename):
    """ helper for finding all required modules of package <packagename> """
    global scan_in_progress
    scan_in_progress = True
    # Use the package in the build directory
    libpath = os.path.abspath(libpath)
    sys.path.insert(0, libpath)
    packdir = os.path.join(libpath, packagename.replace('.', '/'))
    # A normal import would not find the package in
    # the build directory. ihook is used to force the import.
    # After the package is imported the import scope for
    # the following imports is settled.
    p = importfrom(packdir)
    globals()[packagename] = p
    sys.modules[packagename] = p
    # Fetch the python modules in the package
    cwd = os.getcwd()
    os.chdir(packdir)
    pymodulefiles = glob.glob('*.py')
    extmodulefiles = glob.glob('*.pyd')
    os.chdir(cwd)
    # Import all python modules and by that run the fake demandload
    for m in pymodulefiles:
        if m == '__init__.py': continue
        tmp = {}
        mname, ext = os.path.splitext(m)
        fullname = packagename+'.'+mname
        try:
            __import__(fullname, tmp, tmp)
        except SkipPackage, inst:
            print >> sys.stderr, 'skipping %s: %s' % (fullname, inst.reason)
            continue
        requiredmodules[fullname] = 1
    # Import all extension modules and by that run the fake demandload
    for m in extmodulefiles:
        tmp = {}
        mname, ext = os.path.splitext(m)
        fullname = packagename+'.'+mname
        __import__(fullname, tmp, tmp)
        requiredmodules[fullname] = 1

def getmodules():
    return requiredmodules.keys()

def importfrom(filename):
    """
    import module/package from a named file and returns the module.
    It does not check on sys.modules or includes the module in the scope.
    """
    loader = ihooks.BasicModuleLoader()
    path, file = os.path.split(filename)
    name, ext  = os.path.splitext(file)
    m = loader.find_module_in_dir(name, path)
    if not m:
        raise ImportError, name
    m = loader.load_module(name, m)
    return m