Repository URL to install this package:
|
Version:
18.5.0-1 ▾
|
# (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))