# (c) Copyright 2009-2010, 2014. CodeWeavers, Inc.
import os.path
import re
import cxutils
import distversion
import bottlemanagement
import cxaiebase
# for localization
from cxutils import cxgettext as _
#####
#
# Fixing cxdiag issues
#
#####
class AIECXFixes(cxaiebase.AIETask):
def __init__(self, engine):
cxaiebase.AIETask.__init__(self, engine, _("Preparing the system for this application"))
def __unicode__(self):
return "%s(%s)" % (self.__class__.__name__, self.scheduler.installtask.bottlename)
def main(self):
import cxfixes
engine = self.scheduler
cxfixes.clear_errors()
for key, (level, title, _description) in engine.installtask.get_cxdiag_messages().iteritems():
cxfixes.add_error(key, title)
cxfixes.fix_errors()
# Fixing the first set of errors might have uncovered new ones: this may
# be the case if some critical 32 bit libraries were still missing and
# the particular application being installed *requires* non-critical
# libraries to be installed (e.g. libldap_r). So recheck from scratch
# and only report the 'mustfix' errors.
cxfixes.clear_errors()
for key, (level, title, _description) in engine.installtask.get_cxdiag_messages().iteritems():
if level == 'Require':
cxfixes.add_error(key, title)
cxfixes.report_errors()
return True
#####
#
# Bottle initialization tasks
#
#####
class AIECreateBottle(cxaiebase.AIETask):
def __init__(self, engine):
cxaiebase.AIETask.__init__(self, engine, _("Creating the %s bottle") % engine.installtask.bottlename)
def __unicode__(self):
return "%s(%s)" % (self.__class__.__name__, self.scheduler.installtask.bottlename)
def createsBottle(self):
return True
def main(self):
engine = self.scheduler
success, err = bottlemanagement.create_bottle(
engine.installtask.bottlename,
engine.installtask.GetNewBottleTemplate(),
env=engine.state['environ'],
appid=engine.installtask.profile.appid)
if success:
return True
self.error = err
return False
class AIEPreAssoc(cxaiebase.AIETask):
"""This task ensures that cxassoc.conf is up to date before we start
installing applications.
The reason is that if it is out of date, then we may think that
pre-existing associations were created by the installer and then try to
export them to the desktop environment.
"""
def __init__(self, engine):
cxaiebase.AIETask.__init__(self, engine, "")
def __unicode__(self):
return self.__class__.__name__ + "()"
def main(self):
engine = self.scheduler
if engine.state['skipassoc']:
return True
cmd = [os.path.join(cxutils.CX_ROOT, "bin", "cxassoc"),
"--bottle", engine.installtask.bottlename,
"--sync"]
retcode, _out, err = cxutils.run(cmd, env=engine.state['environ'],
stderr=cxutils.GRAB)
if retcode:
self.error = err
return False
return True
class AIEPreNSPlugin(cxaiebase.AIETask):
"""Some installers open a web page using their newly installed plugin.
So we have to 'export' these before running the installer or the user
would see an error message on that page and think the installation failed.
Here we export all the plugins at once, and rely on the post-installation
'cxnsplugin --sync' to delete all those that did not actually get created
for whatever reason.
"""
def __init__(self, engine):
cxaiebase.AIETask.__init__(self, engine, "")
def __unicode__(self):
return self.__class__.__name__ + "()"
def main(self):
engine = self.scheduler
if engine.state['installnsplugins'] and engine.state['pre_nsplugins']:
cmd = [os.path.join(cxutils.CX_ROOT, "bin", "cxnsplugin"),
"--bottle", engine.installtask.bottlename,
'--create', '--install', '--filter',
':'.join(engine.state['pre_nsplugins'])]
retcode, _out, err = cxutils.run(cmd, env=engine.state['environ'],
stderr=cxutils.GRAB)
if retcode:
self.error = err
return False
return True
def get_bottle_init_task(engine):
"""Returns a task (or task group) with all that needs to be done before we
can start installation tasks that use the bottle.
"""
if engine.installtask.GetCreateNewBottle():
create_bottle = AIECreateBottle(engine)
else:
create_bottle = None
group = cxaiebase.AIETaskGroup(engine, "PreInstall", first=create_bottle)
group.insert(AIEPreAssoc(engine))
if distversion.HAS_PLUGIN:
group.insert(AIEPreNSPlugin(engine))
if engine.installtask.get_apply_cxfixes():
cxfixes = AIECXFixes(engine)
engine.add(cxfixes)
group.add_dependency(cxfixes)
return group
#####
#
# Post-installation tasks
#
#####
class AIESyncMenu(cxaiebase.AIETask):
def __init__(self, engine):
cxaiebase.AIETask.__init__(self, engine, _("Refreshing the menus"))
def __unicode__(self):
return self.__class__.__name__ + "()"
def main(self):
"""Refreshes the desktop environment's menus to reflect the changes
that occurred in the bottle.
"""
engine = self.scheduler
cmd = [os.path.join(cxutils.CX_ROOT, "bin", "cxmenu"),
"--bottle", engine.installtask.bottlename,
"--sync", "--mode", "install"]
retcode, _out, err = cxutils.run(cmd, env=engine.state['environ'],
stderr=cxutils.GRAB)
if retcode:
self.error = err
return False
return True
class AIESyncAssoc(cxaiebase.AIETask):
def __init__(self, engine):
cxaiebase.AIETask.__init__(self, engine, _("Refreshing the associations"))
def __unicode__(self):
return self.__class__.__name__ + "()"
def main(self):
"""Refreshes the desktop environment's associations to reflect the
changes that occurred in the bottle.
"""
engine = self.scheduler
if distversion.IS_MACOSX:
mode_spec = ['alternative']
else:
mode_spec = ['mime']
# Note that cxassoc's --mode option expects a list of regular
# expressions matching the eassocids while the C4P files contain plain
# eassocids. So we escape escape them so the dots and stuff don't get
# interpreted.
default_eassocs = engine.state['defaulteassocs']
if default_eassocs:
mode_spec.append("default=" + ":".join(re.escape(x) for x in default_eassocs))
alt_eassocs = engine.state['alteassocs'] - default_eassocs
if alt_eassocs:
# We must add these even if the default mode is 'alternative'
# because it won't force a change in the mode of existing
# associations.
mode_spec.append("alternative=" + ":".join(re.escape(x) for x in alt_eassocs))
# --sync-mode tells cxassoc to change the mode of existing
# associations that match the --mode option.
cmd = [os.path.join(cxutils.CX_ROOT, "bin", "cxassoc"),
"--bottle", engine.installtask.bottlename,
'--sync', '--sync-mode', '--mode',
";".join(mode_spec)]
retcode, _out, err = cxutils.run(cmd, env=engine.state['environ'],
stderr=cxutils.GRAB)
if retcode:
self.error = err
return False
return True
class AIESyncNSPlugin(cxaiebase.AIETask):
def __init__(self, engine):
cxaiebase.AIETask.__init__(self, engine, _("Refreshing the netscape plugins"))
def __unicode__(self):
return self.__class__.__name__ + "()"
def main(self):
"""Refreshes the desktop environment's netscape plugins to reflect the
changes that occurred in the bottle.
"""
engine = self.scheduler
if engine.state['installnsplugins']:
mode_spec = ["install"]
if engine.state['ignore_nsplugins']:
mode_spec.append("ignore=" + ":".join(engine.state['ignore_nsplugins']))
else:
mode_spec = ["ignore"]
cmd = [os.path.join(cxutils.CX_ROOT, "bin", "cxnsplugin"),
"--bottle", engine.installtask.bottlename,
'--sync', '--mode', ';'.join(mode_spec)]
retcode, _out, err = cxutils.run(cmd, env=engine.state['environ'],
stderr=cxutils.GRAB)
if retcode:
self.error = err
return False
return True
def get_postinstall_task(engine):
"""Returns a task (or task group) with all that needs to be done after the
application and all its dependencies have been installed.
"""
group = cxaiebase.AIETaskGroup(engine, "PostInstall")
if not engine.state['skipassoc']:
group.insert(AIESyncAssoc(engine))
if not engine.state['skipmenu']:
group.insert(AIESyncMenu(engine))
if distversion.HAS_PLUGIN:
group.insert(AIESyncNSPlugin(engine))
return group