Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
install.py816 linesDownload Raw Back to isapi
1"""Installation utilities for Python ISAPI filters and extensions."""2 3# this code adapted from "Tomcat JK2 ISAPI redirector", part of Apache4# Created July 2004, Mark Hammond.5import imp6import os7import shutil8import stat9import sys10import traceback11 12import pythoncom13import win32api14import winerror15from win32com.client import Dispatch, GetObject16from win32com.client.gencache import EnsureDispatch, EnsureModule17 18_APP_INPROC = 019_APP_OUTPROC = 120_APP_POOLED = 221_IIS_OBJECT = "IIS://LocalHost/W3SVC"22_IIS_SERVER = "IIsWebServer"23_IIS_WEBDIR = "IIsWebDirectory"24_IIS_WEBVIRTUALDIR = "IIsWebVirtualDir"25_IIS_FILTERS = "IIsFilters"26_IIS_FILTER = "IIsFilter"27 28_DEFAULT_SERVER_NAME = "Default Web Site"29_DEFAULT_HEADERS = "X-Powered-By: Python"30_DEFAULT_PROTECTION = _APP_POOLED31 32# Default is for 'execute' only access - ie, only the extension33# can be used.  This can be overridden via your install script.34_DEFAULT_ACCESS_EXECUTE = True35_DEFAULT_ACCESS_READ = False36_DEFAULT_ACCESS_WRITE = False37_DEFAULT_ACCESS_SCRIPT = False38_DEFAULT_CONTENT_INDEXED = False39_DEFAULT_ENABLE_DIR_BROWSING = False40_DEFAULT_ENABLE_DEFAULT_DOC = False41 42_extensions = [ext for ext, _, _ in imp.get_suffixes()]43is_debug_build = "_d.pyd" in _extensions44 45this_dir = os.path.abspath(os.path.dirname(__file__))46 47 48class FilterParameters:49    Name = None50    Description = None51    Path = None52    Server = None53    # Params that control if/how AddExtensionFile is called.54    AddExtensionFile = True55    AddExtensionFile_Enabled = True56    AddExtensionFile_GroupID = None  # defaults to Name57    AddExtensionFile_CanDelete = True58    AddExtensionFile_Description = None  # defaults to Description.59 60    def __init__(self, **kw):61        self.__dict__.update(kw)62 63 64class VirtualDirParameters:65    Name = None  # Must be provided.66    Description = None  # defaults to Name67    AppProtection = _DEFAULT_PROTECTION68    Headers = _DEFAULT_HEADERS69    Path = None  # defaults to WWW root.70    Type = _IIS_WEBVIRTUALDIR71    AccessExecute = _DEFAULT_ACCESS_EXECUTE72    AccessRead = _DEFAULT_ACCESS_READ73    AccessWrite = _DEFAULT_ACCESS_WRITE74    AccessScript = _DEFAULT_ACCESS_SCRIPT75    ContentIndexed = _DEFAULT_CONTENT_INDEXED76    EnableDirBrowsing = _DEFAULT_ENABLE_DIR_BROWSING77    EnableDefaultDoc = _DEFAULT_ENABLE_DEFAULT_DOC78    DefaultDoc = None  # Only set in IIS if not None79    ScriptMaps = []80    ScriptMapUpdate = "end"  # can be 'start', 'end', 'replace'81    Server = None82 83    def __init__(self, **kw):84        self.__dict__.update(kw)85 86    def is_root(self):87        "This virtual directory is a root directory if parent and name are blank"88        parent, name = self.split_path()89        return not parent and not name90 91    def split_path(self):92        return split_path(self.Name)93 94 95class ScriptMapParams:96    Extension = None97    Module = None98    Flags = 599    Verbs = ""100    # Params that control if/how AddExtensionFile is called.101    AddExtensionFile = True102    AddExtensionFile_Enabled = True103    AddExtensionFile_GroupID = None  # defaults to Name104    AddExtensionFile_CanDelete = True105    AddExtensionFile_Description = None  # defaults to Description.106 107    def __init__(self, **kw):108        self.__dict__.update(kw)109 110    def __str__(self):111        "Format this parameter suitable for IIS"112        items = [self.Extension, self.Module, self.Flags]113        # IIS gets upset if there is a trailing verb comma, but no verbs114        if self.Verbs:115            items.append(self.Verbs)116        items = [str(item) for item in items]117        return ",".join(items)118 119 120class ISAPIParameters:121    ServerName = _DEFAULT_SERVER_NAME122    # Description = None123    Filters = []124    VirtualDirs = []125 126    def __init__(self, **kw):127        self.__dict__.update(kw)128 129 130verbose = 1  # The level - 0 is quiet.131 132 133def log(level, what):134    if verbose >= level:135        print(what)136 137 138# Convert an ADSI COM exception to the Win32 error code embedded in it.139def _GetWin32ErrorCode(com_exc):140    hr = com_exc.hresult141    # If we have more details in the 'excepinfo' struct, use it.142    if com_exc.excepinfo:143        hr = com_exc.excepinfo[-1]144    if winerror.HRESULT_FACILITY(hr) != winerror.FACILITY_WIN32:145        raise146    return winerror.SCODE_CODE(hr)147 148 149class InstallationError(Exception):150    pass151 152 153class ItemNotFound(InstallationError):154    pass155 156 157class ConfigurationError(InstallationError):158    pass159 160 161def FindPath(options, server, name):162    if name.lower().startswith("iis://"):163        return name164    else:165        if name and name[0] != "/":166            name = "/" + name167        return FindWebServer(options, server) + "/ROOT" + name168 169 170def LocateWebServerPath(description):171    """172    Find an IIS web server whose name or comment matches the provided173    description (case-insensitive).174 175    >>> LocateWebServerPath('Default Web Site') # doctest: +SKIP176 177    or178 179    >>> LocateWebServerPath('1') #doctest: +SKIP180    """181    assert len(description) >= 1, "Server name or comment is required"182    iis = GetObject(_IIS_OBJECT)183    description = description.lower().strip()184    for site in iis:185        # Name is generally a number, but no need to assume that.186        site_attributes = [187            getattr(site, attr, "").lower().strip()188            for attr in ("Name", "ServerComment")189        ]190        if description in site_attributes:191            return site.AdsPath192    msg = "No web sites match the description '%s'" % description193    raise ItemNotFound(msg)194 195 196def GetWebServer(description=None):197    """198    Load the web server instance (COM object) for a given instance199    or description.200    If None is specified, the default website is retrieved (indicated201    by the identifier 1.202    """203    description = description or "1"204    path = LocateWebServerPath(description)205    server = LoadWebServer(path)206    return server207 208 209def LoadWebServer(path):210    try:211        server = GetObject(path)212    except pythoncom.com_error as details:213        msg = details.strerror214        if exc.excepinfo and exc.excepinfo[2]:215            msg = exc.excepinfo[2]216        msg = "WebServer %s: %s" % (path, msg)217        raise ItemNotFound(msg)218    return server219 220 221def FindWebServer(options, server_desc):222    """223    Legacy function to allow options to define a .server property224    to override the other parameter.  Use GetWebServer instead.225    """226    # options takes precedence227    server_desc = options.server or server_desc228    # make sure server_desc is unicode (could be mbcs if passed in229    #  sys.argv).230    if server_desc and not isinstance(server_desc, str):231        server_desc = server_desc.decode("mbcs")232 233    # get the server (if server_desc is None, the default site is acquired)234    server = GetWebServer(server_desc)235    return server.adsPath236 237 238def split_path(path):239    """240    Get the parent path and basename.241 242    >>> split_path('/')243    ['', '']244 245    >>> split_path('')246    ['', '']247 248    >>> split_path('foo')249    ['', 'foo']250 251    >>> split_path('/foo')252    ['', 'foo']253 254    >>> split_path('/foo/bar')255    ['/foo', 'bar']256 257    >>> split_path('foo/bar')258    ['/foo', 'bar']259    """260 261    if not path.startswith("/"):262        path = "/" + path263    return path.rsplit("/", 1)264 265 266def _CreateDirectory(iis_dir, name, params):267    # We used to go to lengths to keep an existing virtual directory268    # in place.  However, in some cases the existing directories got269    # into a bad state, and an update failed to get them working.270    # So we nuke it first.  If this is a problem, we could consider adding271    # a --keep-existing option.272    try:273        # Also seen the Class change to a generic IISObject - so nuke274        # *any* existing object, regardless of Class275        assert name.strip("/"), "mustn't delete the root!"276        iis_dir.Delete("", name)277        log(2, "Deleted old directory '%s'" % (name,))278    except pythoncom.com_error:279        pass280 281    newDir = iis_dir.Create(params.Type, name)282    log(2, "Creating new directory '%s' in %s..." % (name, iis_dir.Name))283 284    friendly = params.Description or params.Name285    newDir.AppFriendlyName = friendly286 287    # Note that the new directory won't be visible in the IIS UI288    # unless the directory exists on the filesystem.289    try:290        path = params.Path or iis_dir.Path291        newDir.Path = path292    except AttributeError:293        # If params.Type is IIS_WEBDIRECTORY, an exception is thrown294        pass295    newDir.AppCreate2(params.AppProtection)296    # XXX - note that these Headers only work in IIS6 and earlier.  IIS7297    # only supports them on the w3svc node - not even on individial sites,298    # let alone individual extensions in the site!299    if params.Headers:300        newDir.HttpCustomHeaders = params.Headers301 302    log(2, "Setting directory options...")303    newDir.AccessExecute = params.AccessExecute304    newDir.AccessRead = params.AccessRead305    newDir.AccessWrite = params.AccessWrite306    newDir.AccessScript = params.AccessScript307    newDir.ContentIndexed = params.ContentIndexed308    newDir.EnableDirBrowsing = params.EnableDirBrowsing309    newDir.EnableDefaultDoc = params.EnableDefaultDoc310    if params.DefaultDoc is not None:311        newDir.DefaultDoc = params.DefaultDoc312    newDir.SetInfo()313    return newDir314 315 316def CreateDirectory(params, options):317    _CallHook(params, "PreInstall", options)318    if not params.Name:319        raise ConfigurationError("No Name param")320    parent, name = params.split_path()321    target_dir = GetObject(FindPath(options, params.Server, parent))322 323    if not params.is_root():324        target_dir = _CreateDirectory(target_dir, name, params)325 326    AssignScriptMaps(params.ScriptMaps, target_dir, params.ScriptMapUpdate)327 328    _CallHook(params, "PostInstall", options, target_dir)329    log(1, "Configured Virtual Directory: %s" % (params.Name,))330    return target_dir331 332 333def AssignScriptMaps(script_maps, target, update="replace"):334    """Updates IIS with the supplied script map information.335 336    script_maps is a list of ScriptMapParameter objects337 338    target is an IIS Virtual Directory to assign the script maps to339 340    update is a string indicating how to update the maps, one of  ('start',341    'end', or 'replace')342    """343    # determine which function to use to assign script maps344    script_map_func = "_AssignScriptMaps" + update.capitalize()345    try:346        script_map_func = eval(script_map_func)347    except NameError:348        msg = "Unknown ScriptMapUpdate option '%s'" % update349        raise ConfigurationError(msg)350    # use the str method to format the script maps for IIS351    script_maps = [str(s) for s in script_maps]352    # call the correct function353    script_map_func(target, script_maps)354    target.SetInfo()355 356 357def get_unique_items(sequence, reference):358    "Return items in sequence that can't be found in reference."359    return tuple([item for item in sequence if item not in reference])360 361 362def _AssignScriptMapsReplace(target, script_maps):363    target.ScriptMaps = script_maps364 365 366def _AssignScriptMapsEnd(target, script_maps):367    unique_new_maps = get_unique_items(script_maps, target.ScriptMaps)368    target.ScriptMaps = target.ScriptMaps + unique_new_maps369 370 371def _AssignScriptMapsStart(target, script_maps):372    unique_new_maps = get_unique_items(script_maps, target.ScriptMaps)373    target.ScriptMaps = unique_new_maps + target.ScriptMaps374 375 376def CreateISAPIFilter(filterParams, options):377    server = FindWebServer(options, filterParams.Server)378    _CallHook(filterParams, "PreInstall", options)379    try:380        filters = GetObject(server + "/Filters")381    except pythoncom.com_error as exc:382        # Brand new sites don't have the '/Filters' collection - create it.383        # Any errors other than 'not found' we shouldn't ignore.384        if (385            winerror.HRESULT_FACILITY(exc.hresult) != winerror.FACILITY_WIN32386            or winerror.HRESULT_CODE(exc.hresult) != winerror.ERROR_PATH_NOT_FOUND387        ):388            raise389        server_ob = GetObject(server)390        filters = server_ob.Create(_IIS_FILTERS, "Filters")391        filters.FilterLoadOrder = ""392        filters.SetInfo()393 394    # As for VirtualDir, delete an existing one.395    assert filterParams.Name.strip("/"), "mustn't delete the root!"396    try:397        filters.Delete(_IIS_FILTER, filterParams.Name)398        log(2, "Deleted old filter '%s'" % (filterParams.Name,))399    except pythoncom.com_error:400        pass401    newFilter = filters.Create(_IIS_FILTER, filterParams.Name)402    log(2, "Created new ISAPI filter...")403    assert os.path.isfile(filterParams.Path)404    newFilter.FilterPath = filterParams.Path405    newFilter.FilterDescription = filterParams.Description406    newFilter.SetInfo()407    load_order = [b.strip() for b in filters.FilterLoadOrder.split(",") if b]408    if filterParams.Name not in load_order:409        load_order.append(filterParams.Name)410        filters.FilterLoadOrder = ",".join(load_order)411        filters.SetInfo()412    _CallHook(filterParams, "PostInstall", options, newFilter)413    log(1, "Configured Filter: %s" % (filterParams.Name,))414    return newFilter415 416 417def DeleteISAPIFilter(filterParams, options):418    _CallHook(filterParams, "PreRemove", options)419    server = FindWebServer(options, filterParams.Server)420    ob_path = server + "/Filters"421    try:422        filters = GetObject(ob_path)423    except pythoncom.com_error as details:424        # failure to open the filters just means a totally clean IIS install425        # (IIS5 at least has no 'Filters' key when freshly installed).426        log(2, "ISAPI filter path '%s' did not exist." % (ob_path,))427        return428    try:429        assert filterParams.Name.strip("/"), "mustn't delete the root!"430        filters.Delete(_IIS_FILTER, filterParams.Name)431        log(2, "Deleted ISAPI filter '%s'" % (filterParams.Name,))432    except pythoncom.com_error as details:433        rc = _GetWin32ErrorCode(details)434        if rc != winerror.ERROR_PATH_NOT_FOUND:435            raise436        log(2, "ISAPI filter '%s' did not exist." % (filterParams.Name,))437    # Remove from the load order438    load_order = [b.strip() for b in filters.FilterLoadOrder.split(",") if b]439    if filterParams.Name in load_order:440        load_order.remove(filterParams.Name)441        filters.FilterLoadOrder = ",".join(load_order)442        filters.SetInfo()443    _CallHook(filterParams, "PostRemove", options)444    log(1, "Deleted Filter: %s" % (filterParams.Name,))445 446 447def _AddExtensionFile(module, def_groupid, def_desc, params, options):448    group_id = params.AddExtensionFile_GroupID or def_groupid449    desc = params.AddExtensionFile_Description or def_desc450    try:451        ob = GetObject(_IIS_OBJECT)452        ob.AddExtensionFile(453            module,454            params.AddExtensionFile_Enabled,455            group_id,456            params.AddExtensionFile_CanDelete,457            desc,458        )459        log(2, "Added extension file '%s' (%s)" % (module, desc))460    except (pythoncom.com_error, AttributeError) as details:461        # IIS5 always fails.  Probably should upgrade this to462        # complain more loudly if IIS6 fails.463        log(2, "Failed to add extension file '%s': %s" % (module, details))464 465 466def AddExtensionFiles(params, options):467    """Register the modules used by the filters/extensions as a trusted468    'extension module' - required by the default IIS6 security settings."""469    # Add each module only once.470    added = {}471    for vd in params.VirtualDirs:472        for smp in vd.ScriptMaps:473            if smp.Module not in added and smp.AddExtensionFile:474                _AddExtensionFile(smp.Module, vd.Name, vd.Description, smp, options)475                added[smp.Module] = True476 477    for fd in params.Filters:478        if fd.Path not in added and fd.AddExtensionFile:479            _AddExtensionFile(fd.Path, fd.Name, fd.Description, fd, options)480            added[fd.Path] = True481 482 483def _DeleteExtensionFileRecord(module, options):484    try:485        ob = GetObject(_IIS_OBJECT)486        ob.DeleteExtensionFileRecord(module)487        log(2, "Deleted extension file record for '%s'" % module)488    except (pythoncom.com_error, AttributeError) as details:489        log(2, "Failed to remove extension file '%s': %s" % (module, details))490 491 492def DeleteExtensionFileRecords(params, options):493    deleted = {}  # only remove each .dll once.494    for vd in params.VirtualDirs:495        for smp in vd.ScriptMaps:496            if smp.Module not in deleted and smp.AddExtensionFile:497                _DeleteExtensionFileRecord(smp.Module, options)498                deleted[smp.Module] = True499 500    for filter_def in params.Filters:501        if filter_def.Path not in deleted and filter_def.AddExtensionFile:502            _DeleteExtensionFileRecord(filter_def.Path, options)503            deleted[filter_def.Path] = True504 505 506def CheckLoaderModule(dll_name):507    suffix = ""508    if is_debug_build:509        suffix = "_d"510    template = os.path.join(this_dir, "PyISAPI_loader" + suffix + ".dll")511    if not os.path.isfile(template):512        raise ConfigurationError("Template loader '%s' does not exist" % (template,))513    # We can't do a simple "is newer" check, as the DLL is specific to the514    # Python version.  So we check the date-time and size are identical,515    # and skip the copy in that case.516    src_stat = os.stat(template)517    try:518        dest_stat = os.stat(dll_name)519    except os.error:520        same = 0521    else:522        same = (523            src_stat[stat.ST_SIZE] == dest_stat[stat.ST_SIZE]524            and src_stat[stat.ST_MTIME] == dest_stat[stat.ST_MTIME]525        )526    if not same:527        log(2, "Updating %s->%s" % (template, dll_name))528        shutil.copyfile(template, dll_name)529        shutil.copystat(template, dll_name)530    else:531        log(2, "%s is up to date." % (dll_name,))532 533 534def _CallHook(ob, hook_name, options, *extra_args):535    func = getattr(ob, hook_name, None)536    if func is not None:537        args = (ob, options) + extra_args538        func(*args)539 540 541def Install(params, options):542    _CallHook(params, "PreInstall", options)543    for vd in params.VirtualDirs:544        CreateDirectory(vd, options)545 546    for filter_def in params.Filters:547        CreateISAPIFilter(filter_def, options)548 549    AddExtensionFiles(params, options)550 551    _CallHook(params, "PostInstall", options)552 553 554def RemoveDirectory(params, options):555    if params.is_root():556        return557    try:558        directory = GetObject(FindPath(options, params.Server, params.Name))559    except pythoncom.com_error as details:560        rc = _GetWin32ErrorCode(details)561        if rc != winerror.ERROR_PATH_NOT_FOUND:562            raise563        log(2, "VirtualDirectory '%s' did not exist" % params.Name)564        directory = None565    if directory is not None:566        # Be robust should IIS get upset about unloading.567        try:568            directory.AppUnLoad()569        except:570            exc_val = sys.exc_info()[1]571            log(2, "AppUnLoad() for %s failed: %s" % (params.Name, exc_val))572        # Continue trying to delete it.573        try:574            parent = GetObject(directory.Parent)575            parent.Delete(directory.Class, directory.Name)576            log(1, "Deleted Virtual Directory: %s" % (params.Name,))577        except:578            exc_val = sys.exc_info()[1]579            log(1, "Failed to remove directory %s: %s" % (params.Name, exc_val))580 581 582def RemoveScriptMaps(vd_params, options):583    "Remove script maps from the already installed virtual directory"584    parent, name = vd_params.split_path()585    target_dir = GetObject(FindPath(options, vd_params.Server, parent))586    installed_maps = list(target_dir.ScriptMaps)587    for _map in map(str, vd_params.ScriptMaps):588        if _map in installed_maps:589            installed_maps.remove(_map)590    target_dir.ScriptMaps = installed_maps591    target_dir.SetInfo()592 593 594def Uninstall(params, options):595    _CallHook(params, "PreRemove", options)596 597    DeleteExtensionFileRecords(params, options)598 599    for vd in params.VirtualDirs:600        _CallHook(vd, "PreRemove", options)601 602        RemoveDirectory(vd, options)603        if vd.is_root():604            # if this is installed to the root virtual directory, we can't delete it605            #  so remove the script maps.606            RemoveScriptMaps(vd, options)607 608        _CallHook(vd, "PostRemove", options)609 610    for filter_def in params.Filters:611        DeleteISAPIFilter(filter_def, options)612    _CallHook(params, "PostRemove", options)613 614 615# Patch up any missing module names in the params, replacing them with616# the DLL name that hosts this extension/filter.617def _PatchParamsModule(params, dll_name, file_must_exist=True):618    if file_must_exist:619        if not os.path.isfile(dll_name):620            raise ConfigurationError("%s does not exist" % (dll_name,))621 622    # Patch up all references to the DLL.623    for f in params.Filters:624        if f.Path is None:625            f.Path = dll_name626    for d in params.VirtualDirs:627        for sm in d.ScriptMaps:628            if sm.Module is None:629                sm.Module = dll_name630 631 632def GetLoaderModuleName(mod_name, check_module=None):633    # find the name of the DLL hosting us.634    # By default, this is "_{module_base_name}.dll"635    if hasattr(sys, "frozen"):636        # What to do?  The .dll knows its name, but this is likely to be637        # executed via a .exe, which does not know.638        base, ext = os.path.splitext(mod_name)639        path, base = os.path.split(base)640        # handle the common case of 'foo.exe'/'foow.exe'641        if base.endswith("w"):642            base = base[:-1]643        # For py2exe, we have '_foo.dll' as the standard pyisapi loader - but644        # 'foo.dll' is what we use (it just delegates).645        # So no leading '_' on the installed name.646        dll_name = os.path.abspath(os.path.join(path, base + ".dll"))647    else:648        base, ext = os.path.splitext(mod_name)649        path, base = os.path.split(base)650        dll_name = os.path.abspath(os.path.join(path, "_" + base + ".dll"))651    # Check we actually have it.652    if check_module is None:653        check_module = not hasattr(sys, "frozen")654    if check_module:655        CheckLoaderModule(dll_name)656    return dll_name657 658 659# Note the 'log' params to these 'builtin' args - old versions of pywin32660# didn't log at all in this function (by intent; anyone calling this was661# responsible). So existing code that calls this function with the old662# signature (ie, without a 'log' param) still gets the same behaviour as663# before...664 665 666def InstallModule(conf_module_name, params, options, log=lambda *args: None):667    "Install the extension"668    if not hasattr(sys, "frozen"):669        conf_module_name = os.path.abspath(conf_module_name)670        if not os.path.isfile(conf_module_name):671            raise ConfigurationError("%s does not exist" % (conf_module_name,))672 673    loader_dll = GetLoaderModuleName(conf_module_name)674    _PatchParamsModule(params, loader_dll)675    Install(params, options)676    log(1, "Installation complete.")677 678 679def UninstallModule(conf_module_name, params, options, log=lambda *args: None):680    "Remove the extension"681    loader_dll = GetLoaderModuleName(conf_module_name, False)682    _PatchParamsModule(params, loader_dll, False)683    Uninstall(params, options)684    log(1, "Uninstallation complete.")685 686 687standard_arguments = {688    "install": InstallModule,689    "remove": UninstallModule,690}691 692 693def build_usage(handler_map):694    docstrings = [handler.__doc__ for handler in handler_map.values()]695    all_args = dict(zip(iter(handler_map.keys()), docstrings))696    arg_names = "|".join(iter(all_args.keys()))697    usage_string = "%prog [options] [" + arg_names + "]\n"698    usage_string += "commands:\n"699    for arg, desc in all_args.items():700        usage_string += " %-10s: %s" % (arg, desc) + "\n"701    return usage_string[:-1]702 703 704def MergeStandardOptions(options, params):705    """706    Take an options object generated by the command line and merge707    the values into the IISParameters object.708    """709    pass710 711 712# We support 2 ways of extending our command-line/install support.713# * Many of the installation items allow you to specify "PreInstall",714#   "PostInstall", "PreRemove" and "PostRemove" hooks715#   All hooks are called with the 'params' object being operated on, and716#   the 'optparser' options for this session (ie, the command-line options)717#   PostInstall for VirtualDirectories and Filters both have an additional718#   param - the ADSI object just created.719# * You can pass your own option parser for us to use, and/or define a map720#   with your own custom arg handlers.  It is a map of 'arg'->function.721#   The function is called with (options, log_fn, arg).  The function's722#   docstring is used in the usage output.723def HandleCommandLine(724    params,725    argv=None,726    conf_module_name=None,727    default_arg="install",728    opt_parser=None,729    custom_arg_handlers={},730):731    """Perform installation or removal of an ISAPI filter or extension.732 733    This module handles standard command-line options and configuration734    information, and installs, removes or updates the configuration of an735    ISAPI filter or extension.736 737    You must pass your configuration information in params - all other738    arguments are optional, and allow you to configure the installation739    process.740    """741    global verbose742    from optparse import OptionParser743 744    argv = argv or sys.argv745    if not conf_module_name:746        conf_module_name = sys.argv[0]747        # convert to a long name so that if we were somehow registered with748        # the "short" version but unregistered with the "long" version we749        # still work (that will depend on exactly how the installer was750        # started)751        try:752            conf_module_name = win32api.GetLongPathName(conf_module_name)753        except win32api.error as exc:754            log(755                2,756                "Couldn't determine the long name for %r: %s" % (conf_module_name, exc),757            )758 759    if opt_parser is None:760        # Build our own parser.761        parser = OptionParser(usage="")762    else:763        # The caller is providing their own filter, presumably with their764        # own options all setup.765        parser = opt_parser766 767    # build a usage string if we don't have one.768    if not parser.get_usage():769        all_handlers = standard_arguments.copy()770        all_handlers.update(custom_arg_handlers)771        parser.set_usage(build_usage(all_handlers))772 773    # allow the user to use uninstall as a synonym for remove if it wasn't774    #  defined by the custom arg handlers.775    all_handlers.setdefault("uninstall", all_handlers["remove"])776 777    parser.add_option(778        "-q",779        "--quiet",780        action="store_false",781        dest="verbose",782        default=True,783        help="don't print status messages to stdout",784    )785    parser.add_option(786        "-v",787        "--verbosity",788        action="count",789        dest="verbose",790        default=1,791        help="increase the verbosity of status messages",792    )793    parser.add_option(794        "",795        "--server",796        action="store",797        help="Specifies the IIS server to install/uninstall on."798        " Default is '%s/1'" % (_IIS_OBJECT,),799    )800 801    (options, args) = parser.parse_args(argv[1:])802    MergeStandardOptions(options, params)803    verbose = options.verbose804    if not args:805        args = [default_arg]806    try:807        for arg in args:808            handler = all_handlers[arg]809            handler(conf_module_name, params, options, log)810    except (ItemNotFound, InstallationError) as details:811        if options.verbose > 1:812            traceback.print_exc()813        print("%s: %s" % (details.__class__.__name__, details))814    except KeyError:815        parser.error("Invalid arg '%s'" % arg)816 
codekingpro/portable-devtools · Team Ai