Ejemplo n.º 1
0
Archivo: api.py Proyecto: Lucaszw/mpm
def installed_plugins(only_conda=False):
    '''
    .. versionadded:: 0.20

    Parameters
    ----------
    only_conda : bool, optional
        Only consider plugins that are installed **as Conda packages**.

        .. versionadded:: 0.22

    Returns
    -------
    list
        List of properties corresponding to each available plugin that is
        **installed**.

        .. versionchanged:: 0.22

            If :data:`only_conda` is ``False``, a plugin is assumed to be
            *installed* if it is present in the
            ``share/microdrop/plugins/available`` directory **and** is a
            **real** directory (i.e., not a link).

            If :data:`only_conda` is ``True``, only properties for plugins that
            are installed **as Conda packages** are returned.
    '''
    available_path = MICRODROP_CONDA_SHARE.joinpath('plugins', 'available')
    if not available_path.isdir():
        return []
    installed_plugins_ = []
    for plugin_path_i in available_path.dirs():
        # Only process plugin directory if it is *not a link*.
        if not _islinklike(plugin_path_i):
            # Read plugin package info from `properties.yml` file.
            try:
                with plugin_path_i.joinpath('properties.yml').open('r') as input_:
                    properties_i = yaml.load(input_.read())
            except:
                logger.info('[warning] Could not read package info: `%s`',
                            plugin_path_i.joinpath('properties.yml'),
                            exc_info=True)
            else:
                properties_i['path'] = plugin_path_i.realpath()
                installed_plugins_.append(properties_i)

    if only_conda:
        # Only consider plugins that are installed **as Conda packages**.
        try:
            package_names = [plugin_i['package_name']
                             for plugin_i in installed_plugins_]
            conda_package_infos = ch.package_version(package_names,
                                                     verbose=False)
        except ch.PackageNotFound, exception:
            # At least one specified plugin package name did not correspond to an
            # installed Conda package.
            logger.warning(str(exception))
            conda_package_infos = exception.available
        # Extract name from each Conda plugin package.
        installed_package_names = set([package_i['name']
                                       for package_i in conda_package_infos])
        return [plugin_i for plugin_i in installed_plugins_
                if plugin_i['package_name'] in installed_package_names]
Ejemplo n.º 2
0
Archivo: api.py Proyecto: Lucaszw/mpm
def enabled_plugins(installed_only=True):
    '''
    .. versionadded:: 0.21

    Parameters
    ----------
    installed_only : bool, optional
        Only consider enabled plugins that are installed in the Conda
        environment.

    Returns
    -------
    list
        List of properties corresponding to each plugin that is **enabled**.

        If :data:`installed_only` is True``, only consider plugins:

         1. Present in the ``etc/microdrop/plugins/enabled`` directory as a
            link/junction to a **real** directory (i.e., not a link) in the
            ``share/microdrop/plugins/available`` directory.
         2. Matching the name of a package in the Conda environment.

        If :data:`installed_only` is ``False``, consider all plugins present in
        the ``etc/microdrop/plugins/enabled`` directory as either a *real*
        directory or a link/junction.

    '''
    enabled_path = MICRODROP_CONDA_PLUGINS.joinpath('enabled')
    if not enabled_path.isdir():
        return []

    # Construct list of property dictionaries, one per enabled plugin
    # directory.
    enabled_plugins_ = []
    for plugin_path_i in enabled_path.dirs():
        if not installed_only or _islinklike(plugin_path_i):
            # Enabled plugin path is either **a link to an installed plugin**
            # or call explicitly specifies that plugins that are not installed
            # should still be considered.

            # Read plugin package info from `properties.yml` file.
            try:
                with plugin_path_i.joinpath('properties.yml').open('r') as input_:
                    properties_i = yaml.load(input_.read())
            except:
                logger.info('[warning] Could not read package info: `%s`',
                            plugin_path_i.joinpath('properties.yml'),
                            exc_info=True)
                continue
            else:
                properties_i['path'] = plugin_path_i.realpath()
                enabled_plugins_.append(properties_i)

    if installed_only:
        # Only consider enabled plugins that are installed in the Conda
        # environment.
        try:
            # Attempt to look up installed Conda package info for each enabled
            # plugin.
            package_names = [properties_i['package_name']
                             for properties_i in enabled_plugins_]
            installed_info = ch.package_version(package_names, verbose=False)
        except ch.PackageNotFound, exception:
            # Failed to find a corresponding installed Conda package for at
            # least one enabled plugin.
            logger.warning(str(exception))
            available_names = set([package_i['name']
                                   for package_i in exception.available])
            # Only return list of enabled plugins that have a corresponding
            # Conda package installed.
            return [properties_i for properties_i in enabled_plugins_
                    if properties_i['package_name'] in available_names]
Ejemplo n.º 3
0
def conda_version_info(package_name):
    '''
    .. versionadded:: 0.2.post5

    .. versionchanged:: 0.3.post2
        Add support for running in Conda environments.

    .. versionchanged:: 0.7.3
        Use :func:`conda_helpers.conda_exec` to search for available MicroDrop
        Conda packages.

        Add ``sci-bots`` Anaconda channel to Conda package search.

    .. versionchanged:: 0.7.8
        Fall back to using ``conda list`` to search for the installed version
        of MicroDrop if the version cannot be determined using ``conda
        search``.

    Parameters
    ----------
    package_name : str
        Conda package name.

    Returns
    -------
    dict
        Version information:

         - ``latest``: Latest available version.
         - ``installed``: Conda package description dictionary for installed
           version (`None` if not installed).

    Raises
    ------
    IOError
        If Conda executable not found.
    subprocess.CalledProcessError
        If `conda search` command fails.

        This happens, for example, if no internet connection is available.
    '''
    # Use `-f` flag to search for package, but *no other packages that have
    # `<package_name>` in the name).
    json_output = ch.conda_exec('search',
                                '-c',
                                'sci-bots',
                                '-c',
                                'wheeler-microfluidics',
                                '-f',
                                'microdrop',
                                '--json',
                                verbose=False)
    versions = json.loads(json_output)['microdrop']
    installed_versions = [v_i for v_i in versions if v_i['installed']]
    installed_version = installed_versions[0] if installed_versions else None

    if installed_version is None:
        # If not able to find installed version from `microdrop` Conda package
        # search, use `conda list ...` to try determine the installed version of
        # MicroDrop.
        try:
            installed_version = ch.package_version('microdrop', verbose=False)
        except NameError:
            # Installed MicroDrop Conda package not found (perhaps this is a
            # development environment?)
            pass

    return {'installed': installed_version, 'versions': versions}
Ejemplo n.º 4
0
    ------
    IOError
        If Conda update server cannot be reached, e.g., if there is no network
        connection available.

    See also
    --------
    _update_plugin_ui
    '''
    try:
        update_json_log = plugin_install(package_name)
    except RuntimeError, exception:
        if 'CondaHTTPError' in str(exception):
            raise IOError('Error accessing update server.')
        else:
            raise

    if update_json_log.get('success'):
        if 'actions' in update_json_log:
            # Plugin was updated successfully.
            # Display prompt indicating previous version
            # and new version.
            actions = update_json_log['actions']
            update_json_log['old_versions'] = actions.get('UNLINK', [])
            update_json_log['new_versions'] = actions.get('LINK', [])
        else:
            # No update available.
            version_dict = ch.package_version(package_name)
            update_json_log.update(version_dict)
        return update_json_log
Ejemplo n.º 5
0
def update_plugin_dialog(package_name=None, update_args=None,
                         update_kwargs=None, ignore_not_installed=True):
    '''
    Launch dialog to track status of update of specified plugin package.

    .. versionadded:: 0.19

    .. versionchanged:: 0.20
        Add support for updating multiple packages (update all **installed**
        plugins by default).

        Add :data:`update_args` and :data:`update_kwargs` arguments.

    .. versionchanged:: 0.20.1
        Disable "OK" button until update has completed.

        Add "Cancel" button.

    .. versionchanged:: 0.20.3
        Fix typo in handling of attempt to update plugin packages that are not
        installed.

    .. versionchanged:: 0.23
        Add :data:`ignore_not_installed` parameter.

    .. versionchanged:: 0.23.1
        Fix bug in status message markup syntax when no packages are unlinked
        **or** linked.

    Parameters
    ----------
    package_name : str or list, optional
        Conda MicroDrop plugin package name, e.g., `microdrop.mr-box-plugin`.

        Multiple plugin package names may be provided as a list.

        If no package name(s) specified, update **all installed** plugin
        packages.
    update_args : list or tuple, optional
        Extra arguments to pass to :func:`mpm.api.update` call.
    update_kwargs : dict, optional
        Extra keyword arguments to pass to :func:`mpm.api.update` call.
    ignore_not_installed : bool, optional
        If ``True`` (*default*), ignore plugin packages that are not installed
        as Conda packages.

        Otherwise, a :class:`conda_heplers.PackageNotFound` exception will be
        raised for plugins that are not installed as Conda packages.

    Returns
    -------
    dict or None
        Conda install log.

        If dialog is closed or cancelled, ``None`` is returned.

    Notes
    -----
    This function launches two threads; one to pulse the progress bar
    periodically, and one to run the actual update attempt.
    '''
    thread_context = {}

    if package_name is None:
        # No plugin package specified.  Update all plugins which are installed
        # as Conda packages.
        installed_plugins_ = installed_plugins(only_conda=True)
        installed_package_names = [plugin_i['package_name']
                                   for plugin_i in installed_plugins_]
        package_name = installed_package_names
        logger.info('Update all plugins installed as Conda packages.')
    else:
        # At least one plugin package name was explicitly specified.
        if isinstance(package_name, types.StringTypes):
            package_name = [package_name]

        # Only update plugins that are installed as Conda packages.
        try:
            conda_package_infos = ch.package_version(package_name, verbose=False)
        except ch.PackageNotFound, exception:
            # At least one specified plugin package name did not correspond to an
            # installed Conda package.
            if not ignore_not_installed:
                # Raise error indicating at least one plugin is not installed
                # as a Conda package.
                raise
            logger.warning(str(exception))
            conda_package_infos = exception.available
        # Extract name from each Conda plugin package.
        package_name = [package_i['name'] for package_i in conda_package_infos]
        logger.info('Update the following plugins: %s',
                    ', '.join('`{}`'.format(name_i)
                              for name_i in package_name))
Ejemplo n.º 6
0
                                      'no network connection.')
                return
        install_log_json = _strip_conda_menuinst_messages(install_log_json)
        install_log_json = _strip_progress_messages(install_log_json)
        try:
            install_response = json.loads(install_log_json)
        except ValueError:
            # Error decoding JSON response.
            # XXX Assume install succeeded.
            print >> sys.stderr, ('Warning: could not decode '
                                  '`microdrop-launcher` install log:')
            print >> sys.stderr, install_log_json
            return
        unlinked, linked = ch.install_info(install_response)
        print 'Uninstall:'
        print '\n'.join(' - `{} (from {})`'.format(package_i, channel_i)
                        for package_i, channel_i in unlinked)
        print ''
        print 'Install:'
        print '\n'.join(' - `{} (from {})`'.format(package_i, channel_i)
                        for package_i, channel_i in linked)
    else:
        # No new version of the launcher is available for installation.
        print('Up to date: {}'.format(
            ch.package_version('microdrop-launcher',
                               verbose=False).get('dist_name')))


if __name__ == '__main__':
    main()
Ejemplo n.º 7
0
def check_version_cache_for_upgrade():
    '''
    Prompt user to offer to upgrade if cached latest MicroDrop version is newer
    than currently installed version.

    .. versionadded:: 0.7.8
    '''
    # Get currently installed `microdrop` package information.
    #
    # Example `installed_info`:
    #
    #     {u'base_url': None,
    #      u'build_number': 0,
    #      u'build_string': u'0',
    #      u'channel': u'sci-bots',
    #      u'dist_name': u'microdrop-2.10.2-0',
    #      u'name': u'microdrop',
    #      u'platform': None,
    #      u'version': u'2.10.2',
    #      u'with_features_depends': None}
    try:
        installed_info = ch.package_version('microdrop', verbose=False)
    except NameError:
        # Installed MicroDrop Conda package not found (perhaps this is a
        # development environment?)
        return

    cached_path, cached_info = load_cached_version()
    latest_version = cached_info.get('version')
    installed_version = installed_info.get('version')

    # If cached latest MicroDrop version is more recent than the currently
    # installed version, prompt user to offer to upgrade.
    if all([GUI_AVAILABLE, not cached_info.get('ignore'),
            latest_version is not None]):
        if (pkg_resources.parse_version(latest_version) <=
            pkg_resources.parse_version(installed_version)):
            return
        # Display dialog.
        dialog = gtk.MessageDialog(type=gtk.MESSAGE_QUESTION)
        dialog.set_icon_from_file(ICON_PATH)
        dialog.set_title('Upgrade to MicroDrop v{}'.format(latest_version))
        dialog.add_buttons(gtk.STOCK_YES, gtk.RESPONSE_YES,
                           "Not now", gtk.RESPONSE_NO,
                           "Never", gtk.RESPONSE_CANCEL)
        dialog.set_markup('A new version of MicroDrop is available.\n\n'
                          'Would you like to upgrade to MicroDrop v{} (current'
                          ' version: v{})?'.format(latest_version,
                                                   installed_version))
        response = dialog.run()
        dialog.destroy()

        if response == gtk.RESPONSE_CANCEL:
            # Ignore this specific version from now on.
            try:
                with cached_path.open('w') as output:
                    cached_info = {'version': latest_version, 'ignore': True}
                    yaml.dump(cached_info, stream=output)
                print ('new version available: MicroDrop v{} (not installing '
                       'now)'.format(latest_version))
            except:
                logger.error('Error caching latest version.', exc_info=True)
        elif response == gtk.RESPONSE_YES:
            # User selected `Yes`, so upgrade MicroDrop, but restrict upgrade
            # to within the same major version.
            try:
                major_version = int(cre_version.match(installed_version)
                                    .group('major'))
                install_log_json = ch.conda_exec('install', '--json',
                                                 'microdrop >={}, <{}'
                                                 .format(major_version,
                                                         major_version + 1))
                install_response = json.loads(install_log_json)
                unlinked, linked = ch.install_info(install_response)
                print ch.format_install_info(unlinked, linked)
                try:
                    # Remove stale cached MicroDrop version data.
                    cached_path.remove()
                except:
                    pass
            except:
                logger.error('Error upgrading MicroDrop.', exc_info=True)