def develop_unlink(options, info):
    '''
    Prepare development environment.

    Perform the following steps:

     - Unlink working ``.pioenvs`` directory into Conda ``Library`` directory.
     - Unlink ``dmf_control_board_firmware`` Python package from site packages
       directory.

    See Also
    --------
    :func:`develop_link`
    '''
    project_dir = ph.path(__file__).realpath().parent

    # Unlink working ``.pioenvs`` directory into Conda ``Library`` directory.
    info('Unlink working firmware directories from Conda environment.')
    pio_bin_dir = pioh.conda_bin_path()
    fw_bin_dir = pio_bin_dir.joinpath('dmf-control-board-firmware')

    if fw_bin_dir.exists():
        fw_config_ini = fw_bin_dir.joinpath('platformio.ini')
        if fw_config_ini.exists():
            fw_config_ini.unlink()
        fw_bin_dir.unlink()

    # Remove link to ``dmf_control_board_firmware`` Python package in
    # `conda.pth` in site packages directory.
    info('Unlink working Python directory from Conda environment...')
    ch.conda_exec('develop', '-u', project_dir, verbose=True)
    info(72 * '-' + '\nFinished')
Пример #2
0
Файл: api.py Проект: Lucaszw/mpm
def rollback(*args, **kwargs):
    '''
    Restore previous revision of Conda environment according to most recent
    action in :attr:`MICRODROP_CONDA_ACTIONS`.

    .. versionchanged:: 0.18
        Add support for action revision files compressed using ``bz2``.

    .. versionchanged:: 0.24
        Remove channels argument.  Use Conda channels as configured in Conda
        environment.

        Note that channels can still be explicitly set through :data:`*args`.

    Parameters
    ----------
    *args
        Extra arguments to pass to Conda ``install`` roll-back command.

    Returns
    -------
    int, dict
        Revision after roll back and Conda installation log object (from JSON
        Conda install output).

    See also
    --------

    `wheeler-microfluidics/microdrop#200 <https://github.com/wheeler-microfluidics/microdrop/issues/200>`
    '''
    action_files = MICRODROP_CONDA_ACTIONS.files()
    if not action_files:
        # No action files, return current revision.
        logger.debug('No rollback actions have been recorded.')
        revisions_js = ch.conda_exec('list', '--revisions', '--json',
                                     verbose=False)
        revisions = json.loads(revisions_js)
        return revisions[-1]['rev']
    # Get file associated with most recent action.
    cre_rev = re.compile(r'rev(?P<rev>\d+)')
    action_file = sorted([(int(cre_rev.match(file_i.namebase).group('rev')),
                           file_i) for file_i in
                          action_files if cre_rev.match(file_i.namebase)],
                         reverse=True)[0]
    # Do rollback (i.e., install state of previous revision).
    if action_file.ext.lower() == '.bz2':
        # Assume file is compressed using bz2.
        with bz2.BZ2File(action_file, mode='r') as input_:
            action = json.load(input_)
    else:
        # Assume it is raw JSON.
        with action_file.open('r') as input_:
            action = json.load(input_)
    rollback_revision = action['revisions'][-2]
    conda_args = (['install', '--json'] + list(args) +
                  ['--revision', str(rollback_revision)])
    install_log_js = ch.conda_exec(*conda_args, verbose=False)
    install_log = json.loads(install_log_js.split('\x00')[-1])
    logger.debug('Rolled back to revision %s', rollback_revision)
    return rollback_revision, install_log
Пример #3
0
Файл: api.py Проект: Lucaszw/mpm
def _save_action(extra_context=None):
    '''
    Save list of revisions revisions for active Conda environment.

    .. versionchanged:: 0.18
        Compress action revision files using ``bz2`` to save disk space.

    Parameters
    ----------
    extra_context : dict, optional
        Extra content to store in stored action revision.

    Returns
    -------
    path_helpers.path, dict
        Path to which action was written and action object, including list of
        revisions for active Conda environment.
    '''
    # Get list of revisions to Conda environment since creation.
    revisions_js = ch.conda_exec('list', '--revisions', '--json',
                                 verbose=False)
    revisions = json.loads(revisions_js)
    # Save list of revisions to `/etc/microdrop/plugins/actions/rev<rev>.json`
    # See [wheeler-microfluidics/microdrop#200][i200].
    #
    # [i200]: https://github.com/wheeler-microfluidics/microdrop/issues/200
    action = extra_context.copy() if extra_context else {}
    action['revisions'] = revisions
    action_path = (MICRODROP_CONDA_ACTIONS
                   .joinpath('rev{}.json.bz2'.format(revisions[-1]['rev'])))
    action_path.parent.makedirs_p()
    # Compress action file using bz2 to save disk space.
    with bz2.BZ2File(action_path, mode='w') as output:
        json.dump(action, output, indent=2)
    return action_path, action
Пример #4
0
def main():
    '''
    .. versionadded:: 0.1.post62

    .. versionchanged:: 0.7.5
        Use Conda install dry-run to check for new version.

    .. versionchanged:: 0.7.6
        Fix displayed package name during upgrade.

        Fail gracefully with warning on JSON decode error.

    .. versionchanged:: 0.7.7
        Strip progress messages from Conda install output log to prevent JSON
        decoding errors.
    '''
    # Upgrade `microdrop-launcher` package if there is a new version available.
    print 'Checking for `microdrop-launcher` updates',
    try:
        # Check if new version of `microdrop-launcher` would be installed.
        dry_run_response = json.loads(
            ch.conda_exec('install',
                          '--dry-run',
                          '--json',
                          'microdrop-launcher',
                          verbose=False))
    except RuntimeError, exception:
        if 'CondaHTTPError' in str(exception):
            print 'Error checking for updates - no network connection'
            return
        else:
            print 'Error checking for updates.\n{}'.format(exception)
            return
Пример #5
0
Файл: api.py Проект: Lucaszw/mpm
def available_packages(*args, **kwargs):
    '''
    Query available plugin packages based on specified Conda channels.

    Parameters
    ----------
    *args
        Extra arguments to pass to Conda ``search`` command.

    Returns
    -------
    dict
        .. versionchanged:: 0.24
            All Conda packages beginning with ``microdrop.`` prefix from all
            configured channels.

        Each *key* corresponds to a package name.

        Each *value* corresponds to a ``list`` of dictionaries, each
        corresponding to an available version of the respective package.

        For example:

            {
              "microdrop.dmf-device-ui-plugin": [
                ...
                {
                  ...
                  "build_number": 0,
                  "channel": "microdrop-plugins",
                  "installed": true,
                  "license": "BSD",
                  "name": "microdrop.dmf-device-ui-plugin",
                  "size": 62973,
                  "version": "2.1.post2",
                  ...
                },
                ...],
                ...
            }
    '''
    # Get list of available MicroDrop plugins, i.e., Conda packages that start
    # with the prefix `microdrop.`.
    try:
        plugin_packages_info_json = ch.conda_exec('search', '--json',
                                                  '^microdrop\.', verbose=False)
        return json.loads(plugin_packages_info_json)
    except RuntimeError, exception:
        if 'CondaHTTPError' in str(exception):
            logger.warning('Could not connect to Conda server.')
        else:
            logger.warning('Error querying available MicroDrop plugins.',
                           exc_info=True)
def develop_link(options, info):
    '''
    Prepare development environment.

    Perform the following steps:

     - Uninstall ``dmf_control_board_firmware`` if installed as Conda package.
     - Install build and run-time Conda dependencies.
     - Link working ``.pioenvs`` directory into Conda ``Library`` directory to
       make development versions of compiled firmware binaries available to
       Python API.
     - Link ``dmf_control_board_firmware`` Python package into site packages
       directory.

    See Also
    --------
    :func:`develop_unlink`
    '''
    project_dir = ph.path(__file__).realpath().parent

    # Uninstall ``dmf_control_board_firmware`` if installed as Conda package.
    info('Check if Conda package is installed...')
    version_info = ch.conda_version_info('dmf-control-board-firmware')
    if version_info.get('installed') is not None:
        info('Uninstall `dmf-control-board-firmware` package...')
        ch.conda_exec('uninstall',
                      '-y',
                      'dmf-control-board-firmware',
                      verbose=True)
    else:
        info('`dmf-control-board-firmware` package is not installed.')

    # Install build and run-time Conda dependencies.
    info('Install build and run-time Conda dependencies...')
    recipe_dir = project_dir.joinpath('.conda-recipe').realpath()
    ch.conda_exec('install', '-y', '-n', 'root', 'conda-build', verbose=True)
    ch.development_setup(recipe_dir, verbose=True)

    # Link working ``.pioenvs`` directory into Conda ``Library`` directory.
    info('Link working firmware directories into Conda environment.')
    pio_bin_dir = pioh.conda_bin_path()

    fw_bin_dir = pio_bin_dir.joinpath('dmf-control-board-firmware')

    if not fw_bin_dir.exists():
        project_dir.joinpath('.pioenvs').junction(fw_bin_dir)

    fw_config_ini = fw_bin_dir.joinpath('platformio.ini')
    if not fw_config_ini.exists():
        project_dir.joinpath('platformio.ini').link(fw_config_ini)

    # Link ``dmf_control_board_firmware`` Python package `conda.pth` in site
    # packages directory.
    info('Link working Python directory into Conda environment...')
    ch.conda_exec('develop', project_dir, verbose=True)
    info(72 * '-' + '\nFinished')
Пример #7
0
Файл: api.py Проект: Lucaszw/mpm
def uninstall(plugin_name, *args):
    '''
    Uninstall plugin packages.

    Plugin packages must have a directory with the same name as the package in
    the following directory:

        <conda prefix>/share/microdrop/plugins/available/

    Parameters
    ----------
    plugin_name : str or list
        Plugin package(s) to uninstall.
    *args
        Extra arguments to pass to Conda ``uninstall`` command.

    Returns
    -------
    dict
        Conda uninstallation log object (from JSON Conda uninstall output).
    '''
    if isinstance(plugin_name, types.StringTypes):
        plugin_name = [plugin_name]

    available_path = MICRODROP_CONDA_SHARE.joinpath('plugins', 'available')
    for name_i in plugin_name:
        plugin_module_i = name_i.split('.')[-1].replace('-', '_')
        plugin_path_i = available_path.joinpath(plugin_module_i)
        if not _islinklike(plugin_path_i) and not plugin_path_i.isdir():
            raise IOError('Plugin `{}` not found in `{}`'
                          .format(name_i, available_path))
        else:
            logging.debug('[uninstall] Found plugin `%s`', plugin_path_i)

    # Perform uninstall operation.
    conda_args = ['uninstall', '--json', '-y'] + list(args) + plugin_name
    uninstall_log_js = ch.conda_exec(*conda_args, verbose=False)
    # Remove broken links in `<conda prefix>/etc/microdrop/plugins/enabled/`,
    # since uninstall may have made one or more packages unavailable.
    _remove_broken_links()
    logger.debug('Uninstalled plugins: ```%s```', plugin_name)
    return json.loads(uninstall_log_js.split('\x00')[-1])
Пример #8
0
Файл: api.py Проект: Lucaszw/mpm
def install(plugin_name, *args, **kwargs):
    '''
    Install plugin packages based on specified Conda channels.

    .. versionchanged:: 0.19.1
        Do not save rollback info on dry-run.

    .. versionchanged:: 0.24
        Remove channels argument.  Use Conda channels as configured in Conda
        environment.

        Note that channels can still be explicitly set through :data:`*args`.

    Parameters
    ----------
    plugin_name : str or list
        Plugin package(s) to install.

        Version specifiers are also supported, e.g., ``package >=1.0.5``.
    *args
        Extra arguments to pass to Conda ``install`` command.

    Returns
    -------
    dict
        Conda installation log object (from JSON Conda install output).
    '''
    if isinstance(plugin_name, types.StringTypes):
        plugin_name = [plugin_name]

    # Perform installation
    conda_args = (['install', '-y', '--json'] + list(args) + plugin_name)
    install_log_js = ch.conda_exec(*conda_args, verbose=False)
    install_log = json.loads(install_log_js.split('\x00')[-1])
    if 'actions' in install_log and not install_log.get('dry_run'):
        # Install command modified Conda environment.
        _save_action({'conda_args': conda_args, 'install_log': install_log})
        logger.debug('Installed plugin(s): ```%s```', install_log['actions'])
    return install_log
Пример #9
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}
Пример #10
0
    dry_run_unlinked, dry_run_linked = ch.install_info(dry_run_response,
                                                       split_version=True)

    # Try to find package specifier for new version of `midrodrop-launcher`.
    # **N.B.**, `dry_run_linked` will be `None` if there is no new version.
    launcher_packages = [
        package_i for package_i, version_i, channel_i in (dry_run_linked or [])
        if 'microdrop-launcher' == package_i
    ]
    if dry_run_linked and launcher_packages:
        # A new version of the launcher is available for installation.
        print 'Upgrading to:', launcher_packages[0]
        try:
            install_log_json = ch.conda_exec('install',
                                             '--json',
                                             'microdrop-launcher',
                                             '--quiet',
                                             verbose=False)
        except RuntimeError, exception:
            if 'CondaHTTPError' in str(exception):
                print >> sys.stderr, ('Error upgrading `microdrop-launcher` - '
                                      '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 '
Пример #11
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)