Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
crossover / opt / cxoffice / lib / python / cxtiemain.py
Size: Mime:
# (c) Copyright 2010-2015. CodeWeavers, Inc.

import os
import sys

import c4parser
import c4profiles
import cxproduct
import cxlog
import cxutils


TIE_VERSION = 2


#
# Association installation / uninstallation
#

def install():
    cxassoc = os.path.join(cxutils.CX_ROOT, 'bin', 'cxassoc')
    if cxutils.system((cxassoc, '--tie', '--removeall', '--install')):
        return 1
    return 0


def uninstall():
    cxassoc = os.path.join(cxutils.CX_ROOT, 'bin', 'cxassoc')
    if cxutils.system((cxassoc, '--tie', '--removeall')):
        return 1
    return 0


#
# Product registration / unregistration
#

def _get_product_key(config, cxroot):
    """Figures out which entry contains the current product's information."""
    for key, section in config.iteritems():
        if section.get('Root', None) == cxroot:
            return key
    return None


def _get_best_tie(config, product_key=None):
    """Picks (one of) the product(s) with the highest TieVersion."""
    best_version = 0
    best_key = None
    best_is_current = False
    for key, section in config.iteritems():
        try:
            version = int(section.get('TieVersion', '0'), 10)
            # Pick the currently installed tie handler in case of a version tie!
            # And pick product_key as the second best
            installed = section.get('TieInstalled', 'false') == 'true'
            if version > best_version or \
                    (version == best_version and installed) or \
                    (version == best_version and key.lower() == product_key and not best_is_current):
                best_version = version
                best_key = key
                best_is_current = installed
        except TypeError:
            pass
    return best_key


def _get_current_tie(config):
    """Returns the key of the currently installed tie handler."""
    for key, section in config.iteritems():
        if section.get('TieInstalled', 'false') == 'true':
            return key
    return None


def _run_action(section, action):
    environ = os.environ.copy()
    environ['CX_ROOT'] = section['Root']

    # Split the command and only then expand the individual args to avoid
    # trouble with quoting.
    argv = []
    for arg in cxutils.cmdlinetoargv(section[action]):
        argv.append(cxutils.expand_unix_string(environ, arg))
    if cxutils.system(argv):
        return 1
    return 0


def register(cxroot):
    """Adds a product to the list of registered products.

    Also installs its .tie file handler, uninstalling that of another product
    if appropriate."""
    if cxroot is None:
        cxroot = cxutils.CX_ROOT
    else:
        cxroot = os.path.abspath(cxroot)

    if cxroot == cxutils.CX_ROOT:
        product = cxproduct.this_product()
        product_tie_version = TIE_VERSION
    else:
        product = cxproduct.product_info_from_cxroot(cxroot)
        if product is None:
            cxlog.err("'%s' does not contain a CrossOver product with a version >= 9.x" % cxroot)
            return 1
        try:
            if int(product['productversion'].split('.', 1)[0]) >= 10:
                # This is not a legacy version, so call its cxtie.
                cxtie = os.path.join(cxroot, 'bin', 'cxtie')
                if cxutils.system((cxtie, '--register')) == 0:
                    return 0
        except TypeError:
            pass
        product_tie_version = 0

    config = cxproduct.get_cross_product_config()
    wconfig = config.get_save_config()
    wconfig.lock_file()

    # Pick a unique key for the current product
    product_key = _get_product_key(config, cxroot)
    if product_key is None:
        i = 1
        while True:
            product_key = 'Product-%d-%d' % (os.geteuid(), i)
            if product_key not in config:
                break
            i += 1
    product_key = product_key.lower()

    # Register the product in the shared configuration file
    section = wconfig[product_key]
    section['Root'] = product['root']
    section['Name'] = product['name']
    section['PublicVersion'] = product['publicversion']
    old_version = section.get('ProductVersion', '')
    section['ProductVersion'] = product['productversion']
    section['ProductID'] = product['productid']
    section['TieVersion'] = "%d" % product_tie_version
    if cxroot == cxutils.CX_ROOT:
        section['TieInstall'] = '"${CX_ROOT}/bin/%s" --install' % cxlog.name0()
        section['TieUninstall'] = '"${CX_ROOT}/bin/%s" --uninstall' % cxlog.name0()
    else:
        section['TieInstall'] = 'false'
        section['TieUninstall'] = 'true'

    # Then check if we should install our trampoline
    if cxroot == cxutils.CX_ROOT and \
            (section.get('TieInstalled', 'false') != 'true' or \
                 cxutils.cmp_versions(old_version, "12.5.0") <= 0):
        best_tie = _get_best_tie(config, product_key)
        # Don't try to set ourselves as the default handler if we cannot
        # uninstall the current one (typically because it belongs to root)
        current_tie = _get_current_tie(config)
        if best_tie == product_key and \
                (current_tie is None or current_tie in wconfig):
            if current_tie is not None and current_tie != product_key and \
                    'TieUninstall' in wconfig[current_tie]:
                _run_action(config[current_tie], 'TieUninstall')
                del wconfig[current_tie]['TieInstalled']
            install()
            section['TieInstalled'] = 'true'

    # Unlock the file last to avoid races in the install/uninstall steps
    wconfig.save_and_unlock_file()
    return 0


def unregister(cxroot):
    """Removes a product from the list of registered products.

    Also uninstalls its .tie file handler and installs that of another product
    if appropriate."""
    if cxroot is None:
        cxroot = cxutils.CX_ROOT
    else:
        cxroot = os.path.abspath(cxroot)

    config = cxproduct.get_cross_product_config()

    if cxroot != cxutils.CX_ROOT:
        # Try cxtie first, if this looks like a non-legacy version
        product_key = _get_product_key(config, cxroot)
        if product_key is not None and \
                config[product_key].get('TieVersion', '0') != '0':
            cxtie = os.path.join(cxroot, 'bin', 'cxtie')
            if cxutils.system((cxtie, '--unregister')) == 0:
                return 0

    wconfig = config.get_save_config()
    wconfig.lock_file()

    product_key = _get_product_key(config, cxroot)
    if product_key is None:
        cxlog.warn('this product has already been unregistered')
        return 0
    installed = config[product_key].get('TieInstalled', 'false') == 'true'
    del wconfig[product_key]

    if cxroot == cxutils.CX_ROOT and installed:
        uninstall()
        best_tie = _get_best_tie(config)
        if best_tie and best_tie in wconfig:
            if _run_action(config[best_tie], 'TieInstall') == 0:
                wconfig[best_tie]['TieInstalled'] = 'true'

    # Unlock the file last to avoid races in the install/uninstall steps
    wconfig.save_and_unlock_file(True)
    return 0


#
# Tie file handling
#


def _get_appname(c4pfile):
    autorun = c4pfile.get_autorun_id()
    for profile in c4pfile.profiles:
        if profile.appid == autorun:
            return profile.name
    return "'%s'" % c4pfile.filename

def open_file(filename):
    # pylint: disable=W0404
    try:
        c4pfile = c4parser.C4PFile(filename, False, c4profiles.download)
    except Exception:
        e = sys.exc_info()[1]
        # FIXME: C4PFile.__init__ doesn't actually raise an exception when
        # parsing fails for any reason, so we can't present a proper error to
        # the user.
        import cxtieui
        return cxtieui.show_invalid_file_error(filename, e)

    if c4pfile is None or not c4pfile.profiles:
        import cxtieui
        return cxtieui.show_invalid_file_error(filename, None)

    if c4pfile.malware_appid:
        import cxtieui
        return cxtieui.show_malware_dialog(c4pfile)

    products = c4pfile.find_products()

    if not products:
        import cxtieui
        products = c4pfile.get_supported_product_ids()
        if not products:
            return cxtieui.show_invalid_file_error(filename, None)
        return cxtieui.show_otherproduct_dialog(products, filename,
                                                _get_appname(c4pfile))
    elif len(products) == 1:
        product = products[0]
        cxinstaller = os.path.join(product['root'], 'bin', 'cxinstaller')
        os.execl(cxinstaller, cxinstaller, '--c4pfile', filename)
        # Unreachable code
        return 13
    import cxtieui
    return cxtieui.run(products, filename, _get_appname(c4pfile))