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

beebox / crossover   deb

Repository URL to install this package:

Version: 18.5.0-1 

/ opt / cxoffice / lib / python / bottlemanagement.py

# (c) Copyright 2009-2015. CodeWeavers, Inc.

import os
import cxproduct
import shutil
import distversion

import cxutils
import cxobjc
import cxlog
import cxmenu
import bottlequery

class BottleManagement(cxobjc.Proxy):
    pass


def _bottle_tool():
    return os.path.join(cxutils.CX_ROOT, "bin", "cxbottle")


@cxobjc.method(BottleManagement, 'createBottle_fromTemplate_')
def create_bottle(bottlename, template="winxp", env=None, appid=None):
    """Creates the specified bottle and returns a (success, err_msg) tuple.
    """
    args = [_bottle_tool(), "--bottle", bottlename,
            "--create", "--template", template, "--install"]
    if appid is not None:
        s = "EnvironmentVariables:CX_BOTTLE_CREATOR_APPID=%s" % appid
        args.append("--param")
        args.append(s)
    retcode, _out, err = cxutils.run(args, env=env, stderr=cxutils.GRAB)
    return (retcode == 0), err


@cxobjc.method(BottleManagement, 'duplicateBottle_fromBottle_')
def copy_bottle(bottlename, bottleToCopy):
    """Copies the specified bottle and returns a (success, err_msg) tuple.
    """
    args = [_bottle_tool(), "--bottle", bottlename,
            "--copy", bottleToCopy, "--install"]
    retcode, _out, err = cxutils.run(args, stderr=cxutils.GRAB)
    return (retcode == 0), err


def publish_bottle(bottlename, bottleToCopy):
    """Publishes the specified bottle and returns a (success, err_msg) tuple.
    """


    if cxproduct.is_root_install():
        cxsu = os.path.join(cxutils.CX_ROOT, "bin", "cxsu")
        cxsu_args = [cxsu, '--ignore-home']
    else:
        cxsu_args = []

    prefix = bottlequery.get_prefix_for_bottle(bottleToCopy)
    args = cxsu_args + [_bottle_tool(), "--bottle", bottlename,
                        "--copy", prefix, "--install", "--scope", "managed"]
    retcode, _out, err = cxutils.run(args, stderr=cxutils.GRAB)
    return (retcode == 0), err


@cxobjc.method(BottleManagement, 'restoreBottle_fromArchive_')
def restore_bottle(bottlename, archiveFile):
    """Restores the specified archive to the specified bottle name and
    returns a (success, err_msg) tuple.
    """
    args = [_bottle_tool(), "--bottle", bottlename,
            "--restore", archiveFile, "--install"]
    env = None
    if distversion.IS_MACOSX and 'LANG' not in os.environ and \
            'LC_CTYPE' not in os.environ and 'LC_ALL' not in os.environ:
        env = os.environ.copy()
        env['LC_CTYPE'] = 'UTF-8'
    retcode, _out, err = cxutils.run(args, stderr=cxutils.GRAB, env=env)
    return (retcode == 0), err

def migration_info_for_games_bottle(gamesbottlename):
    """Returns the information necessary for the front-end to migrate (move or
       copy) a Games bottle.
    """

    fullBottleLocation = os.path.join(cxproduct.get_games_bottle_path(), gamesbottlename)
    newBottleName = bottlequery.unique_bottle_name(gamesbottlename)
    fullNewBottleLocation = os.path.join(cxproduct.get_bottle_path(), newBottleName)
    return fullBottleLocation, newBottleName, fullNewBottleLocation

def post_migrate_games_bottle(newBottleName):
    """Finishes the migration of a Games bottle into this product's bottle
       directory.

       It will clean up and reinstall the new bottle.
    """

    fullNewBottleLocation = os.path.join(cxproduct.get_bottle_path(), newBottleName)

    if distversion.IS_MACOSX:
        desktopdata = os.path.join(fullNewBottleLocation, "desktopdata")
        try:
            os.unlink(os.path.join(desktopdata, "cxmenu", "cxmenu_macosx.plist"))
        except OSError:
            pass
        try:
            os.unlink(os.path.join(desktopdata, "cxassoc", "cxassoc_macosx.plist"))
        except OSError:
            pass

    cxconfig = cxproduct.get_config()
    menu_root = cxconfig['BottleDefaults'].get('MenuRoot', '/Windows Applications')
    # At this point we know the bottle's menus are not installed yet so there
    # is no need to update them
    cxmenu.set_menuroot(newBottleName, menu_root, update=False)

    args = [_bottle_tool(), "--bottle", newBottleName, "--restored", "--install"]
    retcode, _out, err = cxutils.run(args, stderr=cxutils.GRAB)
    if retcode != 0:
        cxlog.log("Failed to install menus for migrated bottle: %s." % cxlog.to_str(err))

    if retcode != 0:
        return err
    return None

def migrate_games_bottle(gamesbottlename):
    """Pulls a bottle out of the old cxgames bottle prefix and
       moves it into the modern bottle directory.

       It will move, and reinstall. Uninstall, if necessary, must be done
       before calling.
    """

    fullBottleLocation, newBottleName, fullNewBottleLocation = migration_info_for_games_bottle(gamesbottlename)
    shutil.move(fullBottleLocation, fullNewBottleLocation)
    err = post_migrate_games_bottle(newBottleName)
    if err is None:
        return True, newBottleName
    return False, err

def copy_games_bottle(gamesbottlename):
    """Copy a bottle out of the old cxgames bottle prefix and
       into the modern bottle directory.

       It will copy and reinstall.
    """

    fullBottleLocation, newBottleName, fullNewBottleLocation = migration_info_for_games_bottle(gamesbottlename)

    shutil.copytree(fullBottleLocation, fullNewBottleLocation, symlinks=True)

    err = post_migrate_games_bottle(newBottleName)
    if err is None:
        return True, newBottleName
    return False, err



@cxobjc.method(BottleManagement, 'renameBottle_to_')
def rename_bottle(bottlename, newBottleName):
    """Renames the specified bottle and returns a (success, err_msg) tuple."""
    oldPrefix = bottlequery.get_prefix_for_bottle(bottlename)
    newPrefix = os.path.join(os.path.dirname(oldPrefix), newBottleName)
    wasDefault = (bottlequery.get_default_bottle() == bottlename)

    if os.path.exists(newPrefix):
        err = "Cannot rename; that bottle already exists."
        return (False, err)

    args = [_bottle_tool(), "--bottle", bottlename,
            "--removeall"]
    retcode, _out, err = cxutils.run(args, stderr=cxutils.GRAB)
    if retcode != 0:
        errstr = "Failed to uninstall the old bottle name: %s" % err
        return (False, errstr)

    os.rename(oldPrefix, newPrefix)

    args = [_bottle_tool(), "--bottle", newBottleName,
            "--new-uuid", "--install"]
    if wasDefault:
        args.append("--default")
    retcode, _out, err = cxutils.run(args, stderr=cxutils.GRAB)
    if retcode != 0:
        errstr = "Failed to install the new bottle name: %s" % err
        return (False, errstr)

    return (True, "")


def delete_bottle(bottlename, isManaged=False):
    """Deletes the specified bottle and returns a (success, err_msg) tuple.
    """

    if isManaged:
        if cxproduct.is_root_install():
            cxsu = os.path.join(cxutils.CX_ROOT, "bin", "cxsu")
            cxsu_args = [cxsu, '--ignore-home']
        else:
            cxsu_args = []
        args = cxsu_args + [_bottle_tool(), "--bottle", bottlename,
                            "--removeall", "--delete", "--force"]
        retcode, _out, err = cxutils.run(args, stderr=cxutils.GRAB)

        if retcode != 0:
            cxlog.log("Failed to delete %s." % cxlog.to_str(bottlename))

        # Delete the stub, if it's there.
        args = [_bottle_tool(), "--bottle", bottlename,
                "--removeall", "--delete", "--force", "--scope", "private"]
        retcode, _out, err = cxutils.run(args, stderr=cxutils.GRAB)

        if retcode != 0:
            cxlog.log("Failed to delete the stub for %s." % cxlog.to_str(bottlename))

        return (retcode == 0), err

    else:
        args = [_bottle_tool(), "--bottle", bottlename,
                "--removeall", "--delete", "--force", "--scope", "private"]
        retcode, _out, err = cxutils.run(args, stderr=cxutils.GRAB)
        return (retcode == 0), err


@cxobjc.method(BottleManagement, 'deleteBottle_')
def _deleteBottle_(bottlename):
    return delete_bottle(bottlename, False)


@cxobjc.method(BottleManagement, 'setBottle_isDefault_')
def set_default_bottle(bottlename, inState):
    """Makes or unmakes the bottle the default bottle and returns a
    (success, err_msg) tuple.
    """
    if inState:
        cmd = "--default"
    else:
        cmd = "--undefault"
    args = [_bottle_tool(), "--bottle", bottlename, cmd]
    retcode, _out, err = cxutils.run(args, stderr=cxutils.GRAB)
    return (retcode == 0), err

def package_bottle(bottlename, packagetype, release, productid, packager, outdir):
    args = [_bottle_tool(), "--%s" % packagetype, "--release", release, "--bottle", bottlename, "--productid", productid, "--packager", packager]

    retcode, _out, err = cxutils.run(args, cwd=outdir, stderr=cxutils.GRAB)
    return (retcode == 0), err



@cxobjc.method(BottleManagement, 'setBottle_description_')
def set_bottle_description(bottlename, inDescription):
    """Sets the bottle's description and returns a (success, err_msg)
    tuple.
    """
    args = [_bottle_tool(), "--bottle", bottlename,
            "--description", inDescription]
    retcode, _out, err = cxutils.run(args, stderr=cxutils.GRAB)
    return (retcode == 0), err


@cxobjc.method(BottleManagement, 'archiveBottle_toPath_')
def archive_bottle(bottlename, inArchivePath):
    """Archives the bottle to the specified file and returns a
    (success, err_msg) tuple.
    """
    args = [_bottle_tool(), "--bottle", bottlename,
            "--tar", inArchivePath]
    env = None
    if distversion.IS_MACOSX and 'LANG' not in os.environ and \
            'LC_CTYPE' not in os.environ and 'LC_ALL' not in os.environ:
        env = os.environ.copy()
        env['LC_CTYPE'] = 'UTF-8'
    retcode, _out, err = cxutils.run(args, stderr=cxutils.GRAB, env=env)
    return (retcode == 0), err


@cxobjc.method(BottleManagement, 'templates')
def template_list():
    templateList = []
    templateDir = os.path.join(cxutils.CX_ROOT, "share", "crossover", "bottle_templates")
    is_64bit = cxproduct.is_64bit_install()
    for dentry in os.listdir(templateDir):
        if not is_64bit and dentry.endswith('_64'):
            continue
        if os.path.exists(os.path.join(templateDir, dentry, "setup")):
            templateList.append(dentry)
    return templateList

_TEMPLATE_PROPERTIES = {
    # pylint: disable=C0326
    'win98':       (0, 'Windows 98',    None),
    'win2000':     (1, 'Windows 2000',  None),
    'winxp':       (2, 'Windows XP',    None),
    'winxp_64':    (3, 'Windows XP 64-bit', None),
    'winvista':    (4, 'Windows Vista', None),
    'winvista_64': (5, 'Windows Vista 64-bit', None),
    'win7':        (6, 'Windows 7',     None),
    'win7_64':     (7, 'Windows 7 64-bit',     None),
    'win8':        (8, 'Windows 8',     None),
    'win8_64':     (9, 'Windows 8 64-bit',     None),
    'win10':       (10, 'Windows 10',     None),
    'win10_64':    (11, 'Windows 10 64-bit',     None),
    }

@cxobjc.method(BottleManagement, 'sortKeyForTemplate_')
def get_template_key(template):
    prop = _TEMPLATE_PROPERTIES.get(template)
    if prop is None:
        return (99, 'zzz', template)
    return (prop[0], prop[1], template)

@cxobjc.method(BottleManagement, 'displayNameForTemplate_')
def get_template_name(template, recommend=False):
    if template not in _TEMPLATE_PROPERTIES:
        return template
    prop = _TEMPLATE_PROPERTIES[template]
    if not recommend or prop[2] is None:
        return prop[1]
    return '%s (%s)' % (prop[1], prop[2])

@cxobjc.method(BottleManagement, 'isBottleRunning_')
def is_running(bottlename):

    args = [os.path.join(cxutils.CX_ROOT, "bin", "wine"),
            "--bottle", bottlename, "--no-update",
            "--ux-app", "wineserver", "-k0"]
    retcode = cxutils.system(args)
    return retcode == 0


@cxobjc.method(BottleManagement, 'quitBottle_')
def quit_bottle(bottlename):
    """Return True if shutdown succeeded, False if failed or canceled."""

    if not is_running(bottlename):
        return True

    args = [os.path.join(cxutils.CX_ROOT, "bin", "wine"),
            "--bottle", bottlename, "--no-update",
            "--wl-app", "wineboot.exe", "--", "--end-session",
            "--shutdown", "--force", "--kill"]
    retcode, _out, _err = cxutils.run(args, stdout=cxutils.GRAB)
    return retcode == 0


@cxobjc.method(BottleManagement, 'bottleIsUpToDate_')
def get_up_to_date(bottlename, scope="private"):
    args = [_bottle_tool(), "--bottle", bottlename, "--status", "--scope", scope]
    retcode, out, _err = cxutils.run(args, stdout=cxutils.GRAB)
    if retcode == 0 and "Status=uptodate" in out:
        return True
    return False


@cxobjc.method(BottleManagement, 'killBottle_')
def kill_bottle(bottlename):
    if not is_running(bottlename):
        return True

    args = [os.path.join(cxutils.CX_ROOT, "bin", "wine"),
            "--bottle", bottlename, "--no-update",
            "--ux-app", "wineserver", "-k"]
    retcode = cxutils.system(args)
    return retcode == 0


@cxobjc.method(BottleManagement, 'wineEjectForBottle_')
def wine_eject(bottlename):
    args = [os.path.join(cxutils.CX_ROOT, "bin", "wine"),
            "--bottle", bottlename,
            "--wl-app", "eject.exe", "-a"]
    retcode = cxutils.system(args)
    return retcode == 0