def check_device_name_and_version(self):
        """
        Check to see if:

         a) The connected device is a OpenDrop
         b) The device firmware matches the host driver API version

        In the case where the device firmware version does not match, display a
        dialog offering to flash the device with the firmware version that
        matches the host driver API version.
        """
        try:
            self.connect()
            name = self.control_board.properties['package_name']
            if name != self.control_board.host_package_name:
                raise Exception("Device is not a DropBot DX")

            host_software_version = self.control_board.host_software_version
            remote_software_version = self.control_board.remote_software_version

            # Reflash the firmware if it is not the right version.
            if host_software_version != remote_software_version:
                response = yesno(
                    "The DropBot DX firmware version (%s) "
                    "does not match the driver version (%s). "
                    "Update firmware?" %
                    (remote_software_version, host_software_version))
                if response == gtk.RESPONSE_YES:
                    self.on_flash_firmware()
        except Exception, why:
            logger.warning("%s" % why)
 def on_app_exit(self):
     app = get_app()
     if self.modified:
         result = yesno('Protocol %s has unsaved changes.  Save now?'\
                 % app.protocol.name)
         if result == gtk.RESPONSE_YES:
             self.save_protocol()
    def check_device_name_and_version(self):
        '''
        Check to see if:

         a) The connected device is a OpenDrop
         b) The device firmware matches the host driver API version

        In the case where the device firmware version does not match, display a
        dialog offering to flash the device with the firmware version that
        matches the host driver API version.
        '''
        try:
            self.connect()
            name = self.control_board.name()
            if name != "open_drop":
                raise Exception("Device is not an OpenDrop")

            host_software_version = self.control_board.host_software_version()
            remote_software_version = self.control_board.software_version()

            # Reflash the firmware if it is not the right version.
            if host_software_version != remote_software_version:
                response = yesno("The control board firmware version (%s) "
                                 "does not match the driver version (%s). "
                                 "Update firmware?" % (remote_software_version,
                                                       host_software_version))
                if response == gtk.RESPONSE_YES:
                    self.on_flash_firmware()
        except Exception, why:
            logger.warning("%s" % why)
    def update_plugin(self, plugin_controller, verbose=False, force=False):
        app = get_app()
        server_url = app.get_app_value('server_url')
        plugin_metadata = plugin_controller.get_plugin_info()
        package_name = plugin_metadata.package_name
        plugin_name = plugin_metadata.plugin_name

        p = PluginRepository(server_url)
        latest_version = Version(**p.latest_version(package_name,
                                                    app_version={'major': 1,
                                                                 'minor': 0,
                                                                 'micro': 0}))

        # Check the plugin tag versus the tag of latest version from the
        # update respository. If they are different, it's a sign that they
        # the currently installed plugin may be incompatible.
        if plugin_controller.version.tags != latest_version.tags:
            if yesno('The currently installed plugin (%s-%s) is from a '
                     'different branch and may not be compatible with '
                     'this version of Microdrop. Would you like to download '
                     'a compatible version?' % (plugin_name,
                                                plugin_controller.version)
                     ) == gtk.RESPONSE_YES:
                return self.download_and_install_plugin(package_name,
                                                        force=force)
        elif plugin_controller.version < latest_version:
            return self.download_and_install_plugin(package_name, force=force)
        else:
            message = 'Plugin %s is up to date (version %s)' % (
                plugin_name, plugin_controller.version)
            if verbose:
                logging.warning(message)
            logging.info(message)
            return False
Beispiel #5
0
    def update_plugin(self, plugin_controller, verbose=False, force=False):
        app = get_app()
        server_url = app.get_app_value('server_url')
        plugin_metadata = plugin_controller.get_plugin_info()
        package_name = plugin_metadata.package_name
        plugin_name = plugin_metadata.plugin_name

        plugin_repo = PluginRepository(server_url)
        latest_version = Version(**plugin_repo
                                 .latest_version(package_name,
                                                 app_version=APP_VERSION))

        # Check the plugin tag versus the tag of latest version from the
        # update respository. If they are different, it's a sign that they
        # the currently installed plugin may be incompatible.
        if plugin_controller.version.tags != latest_version.tags:
            if yesno('The currently installed plugin (%s-%s) is from a '
                     'different branch and may not be compatible with '
                     'this version of MicroDrop. Would you like to download '
                     'a compatible version?' % (plugin_name,
                                                plugin_controller.version)
                     ) == gtk.RESPONSE_YES:
                return self.download_and_install_plugin(package_name,
                                                        force=force)
        elif plugin_controller.version < latest_version:
            return self.download_and_install_plugin(package_name, force=force)
        else:
            message = 'Plugin %s is up to date (version %s)' % (
                plugin_name, plugin_controller.version)
            if verbose:
                logging.warning(message)
            logging.info(message)
            return False
 def save_check(self):
     app = get_app()
     if self.modified:
         result = yesno('Device %s has unsaved changes.  Save now?' %
                        app.dmf_device.name)
         if result == gtk.RESPONSE_YES:
             self.save_dmf_device()
Beispiel #7
0
 def save_check(self):
     app = get_app()
     if self.modified:
         result = yesno('Device %s has unsaved changes.  Save now?' %
                        app.dmf_device.name)
         if result == gtk.RESPONSE_YES:
             self.save_dmf_device()
Beispiel #8
0
 def import_device(self, input_device_path):
     input_device_path = ph.path(input_device_path).realpath()
     output_device_path = (input_device_path.parent
                           .joinpath(input_device_path.namebase + '.svg'))
     overwrite = False
     if output_device_path.isfile():
         result = yesno('Output file exists.  Overwrite?')
         if not result == gtk.RESPONSE_YES:
             return
         overwrite = True
     convert_device_to_svg(input_device_path, output_device_path,
                           use_svg_path=True, detect_connections=True,
                           extend_mm=.5, overwrite=overwrite)
     self.load_device(output_device_path)
 def import_device(self, input_device_path):
     input_device_path = ph.path(input_device_path).realpath()
     output_device_path = (input_device_path.parent
                           .joinpath(input_device_path.namebase + '.svg'))
     overwrite = False
     if output_device_path.isfile():
         result = yesno('Output file exists.  Overwrite?')
         if not result == gtk.RESPONSE_YES:
             return
         overwrite = True
     convert_device_to_svg(input_device_path, output_device_path,
                           use_svg_path=True, detect_connections=True,
                           extend_mm=.5, overwrite=overwrite)
     self.load_device(output_device_path)
    def apply_device_dir(self, device_directory):
        '''
        .. versionchanged:: 2.21
            Use :func:`path_helpers.resource_copytree` to support when copying
            from a module stored in a ``.zip`` archive or ``.egg`` file.
        '''
        app = get_app()

        # if the device directory is empty or None, set a default
        if not device_directory:
            device_directory = (ph.path(app.config.data['data_dir'])
                                .joinpath('devices'))
            self.set_app_values({'device_directory': device_directory})

        if self.previous_device_dir and (device_directory ==
                                         self.previous_device_dir):
            # If the data directory hasn't changed, we do nothing
            return False

        device_directory = ph.path(device_directory)
        if self.previous_device_dir:
            device_directory.makedirs_p()
            if device_directory.listdir():
                result = yesno('Merge?', '''\
Target directory [%s] is not empty.  Merge contents with
current devices [%s] (overwriting common paths in the target
directory)?''' % (device_directory, self.previous_device_dir))
                if not result == gtk.RESPONSE_YES:
                    return False

            original_directory = ph.path(self.previous_device_dir)
            for d in original_directory.dirs():
                copytree(d, device_directory.joinpath(d.name))
            for f in original_directory.files():
                f.copyfile(device_directory.joinpath(f.name))
            original_directory.rmtree()
        elif not device_directory.isdir():
            # if the device directory doesn't exist, copy the skeleton dir
            if device_directory.parent:
                device_directory.parent.makedirs_p()
            # XXX Use `path_helpers.resource_copytree` to support when copying
            # from a module stored in a `.zip` archive or `.egg` file.
            ph.resource_copytree('microdrop', 'devices', device_directory)
        self.previous_device_dir = device_directory
        return True
    def on_button_uninstall_clicked(self, widget, data=None):
        package_name = self.get_plugin_package_name()
        response = yesno('Uninstall plugin %s?' % package_name)
        if response == gtk.RESPONSE_YES:
            # remove the plugin from he enabled list
            app = get_app()
            if package_name in app.config["plugins"]["enabled"]:
                app.config["plugins"]["enabled"].remove(package_name)

            plugin_path = self.get_plugin_path()
            if plugin_path.isdir():
                self.controller.uninstall_plugin(plugin_path)
                self.controller.restart_required = True
                self.controller.update()
                app.main_window_controller.info('%s plugin successfully '
                                                'removed.' % package_name,
                                                'Uninstall plugin')
                self.controller.dialog.update()
Beispiel #12
0
    def on_button_uninstall_clicked(self, widget, data=None):
        package_name = self.get_plugin_package_name()
        response = yesno('Uninstall plugin %s?' % package_name)
        if response == gtk.RESPONSE_YES:
            # remove the plugin from he enabled list
            app = get_app()
            if package_name in app.config["plugins"]["enabled"]:
                app.config["plugins"]["enabled"].remove(package_name)

            plugin_path = self.get_plugin_path()
            if plugin_path.isdir():
                self.controller.uninstall_plugin(plugin_path)
                self.controller.restart_required = True
                self.controller.update()
                app.main_window_controller.info('%s plugin successfully '
                                                'removed.' % package_name,
                                                'Uninstall plugin')
                self.controller.dialog.update()
Beispiel #13
0
 def _firmware_check():
     # Offer to reflash the firmware if the major and minor versions
     # are not not identical. If micro versions are different, the
     # firmware is assumed to be compatible. See [1]
     #
     # [1]: https://github.com/wheeler-microfluidics/base-node-rpc/issues/8
     if any([
             host_software_version.major !=
             remote_software_version.major,
             host_software_version.minor !=
             remote_software_version.minor
     ]):
         response = yesno(
             "The DropBot firmware version (%s) does "
             "not match the driver version (%s). "
             "Update firmware?" %
             (remote_software_version, host_software_version))
         if response == gtk.RESPONSE_YES:
             self.on_flash_firmware()
Beispiel #14
0
    def update_check(self):
        if self._update_setting() not in ('auto-update',
                                          'check for updates, but ask before '
                                          'installing'):
            return

        app_update_server_url = self.config.data.get(self.name, {}).get(
                'server_url', 'http://microfluidics.utoronto.ca/update')
        logger.debug('[APP UPDATE SERVER] server url: %s' % app_update_server_url)
        app_repository = AppRepository(app_update_server_url)
        current_version = Version.fromstring(self.version)
        try:
            latest_version = Version(**app_repository.latest_version('microdrop'))
        except (JSONRPCException, JSONDecodeException, IOError):
            logger.warning('Could not connect to application update server: '
                           '%s', app_update_server_url)
            return
        if current_version < latest_version:
            logger.info('Current version: %s. There is a new version '
                        'available: %s %s' % (current_version, latest_version,
                                               app_repository.server_url +
                                               app_repository
                                               .latest_package_url(
                                                   'microdrop')))
            response = yesno('''
There is a new version of Microdrop available (%s, current version: %s).

Would you like to download the latest version in your browser?''' %
                             (latest_version, current_version))
            if response == gtk.RESPONSE_YES:
                latest_full_url = (app_repository.server_url + app_repository
                                   .latest_package_url('microdrop'))
                if webbrowser.open_new_tab(latest_full_url):
                    logger.info('Closing app after opening browser to latest '
                                'version (%s).' % latest_version)
                    try:
                        self.main_window_controller.on_destroy(None)
                    except AttributeError:
                        raise SystemExit, 'Closing app to allow upgrade installation'
        else:
            logger.info('[SUCCESS] software is up-to-date.\n (installed '
                        'version: %s, server version: %s)' % (current_version,
                                                              latest_version))
Beispiel #15
0
    def apply_device_dir(self, device_directory):
        app = get_app()

        # if the device directory is empty or None, set a default
        if not device_directory:
            device_directory = (ph.path(
                app.config.data['data_dir']).joinpath('devices'))
            self.set_app_values({'device_directory': device_directory})

        if self.previous_device_dir and (device_directory
                                         == self.previous_device_dir):
            # If the data directory hasn't changed, we do nothing
            return False

        device_directory = ph.path(device_directory)
        if self.previous_device_dir:
            device_directory.makedirs_p()
            if device_directory.listdir():
                result = yesno(
                    'Merge?', '''\
Target directory [%s] is not empty.  Merge contents with
current devices [%s] (overwriting common paths in the target
directory)?''' % (device_directory, self.previous_device_dir))
                if not result == gtk.RESPONSE_YES:
                    return False

            original_directory = ph.path(self.previous_device_dir)
            for d in original_directory.dirs():
                copytree(d, device_directory.joinpath(d.name))
            for f in original_directory.files():
                f.copyfile(device_directory.joinpath(f.name))
            original_directory.rmtree()
        elif not device_directory.isdir():
            # if the device directory doesn't exist, copy the skeleton dir
            if device_directory.parent:
                device_directory.parent.makedirs_p()
            base_path().joinpath('devices').copytree(device_directory)
        self.previous_device_dir = device_directory
        return True
    def apply_device_dir(self, device_directory):
        app = get_app()

        # if the device directory is empty or None, set a default
        if not device_directory:
            device_directory = (ph.path(app.config.data['data_dir'])
                                .joinpath('devices'))
            self.set_app_values({'device_directory': device_directory})

        if self.previous_device_dir and (device_directory ==
                                         self.previous_device_dir):
            # If the data directory hasn't changed, we do nothing
            return False

        device_directory = ph.path(device_directory)
        if self.previous_device_dir:
            device_directory.makedirs_p()
            if device_directory.listdir():
                result = yesno('Merge?', '''\
Target directory [%s] is not empty.  Merge contents with
current devices [%s] (overwriting common paths in the target
directory)?''' % (device_directory, self.previous_device_dir))
                if not result == gtk.RESPONSE_YES:
                    return False

            original_directory = ph.path(self.previous_device_dir)
            for d in original_directory.dirs():
                copytree(d, device_directory.joinpath(d.name))
            for f in original_directory.files():
                f.copyfile(device_directory.joinpath(f.name))
            original_directory.rmtree()
        elif not device_directory.isdir():
            # if the device directory doesn't exist, copy the skeleton dir
            if device_directory.parent:
                device_directory.parent.makedirs_p()
            base_path().joinpath('devices').copytree(device_directory)
        self.previous_device_dir = device_directory
        return True
    def verify_and_install_new_plugin(self, plugin_root, force=False):
        plugin_metadata = get_plugin_info(plugin_root)
        if plugin_metadata is None:
            logging.error('%s does not contain a valid plugin.' % plugin_root)
            return False
        logging.info('Installing: %s' % (plugin_metadata, ))

        app = get_app()
        installed_plugin_path = (path(app.config.data['plugins']['directory'])
                                 .joinpath(plugin_metadata.package_name))
        installed_metadata = get_plugin_info(installed_plugin_path)

        if installed_metadata:
            logging.info('Currently installed: %s' % (installed_metadata,))
            if installed_metadata.version.tags == \
                    plugin_metadata.version.tags and \
                    installed_metadata.version >= plugin_metadata.version:
                # Installed version is up-to-date
                message = ('Plugin %s is up-to-date (version %s).  Skipping '
                           'installation.' % (installed_metadata.plugin_name,
                           installed_metadata.version))
                logging.info(message)
                return
            else:
                message = ('A newer version (%s) of the %s plugin is available'
                           ' (current version=%s).' % (plugin_metadata.version,
                                                       plugin_metadata
                                                       .plugin_name,
                                                       installed_metadata
                                                       .version))
                logging.info(message)
                if not force:
                    response = yesno('''%s Would you like to upgrade?''' %
                                     message)
                    if response == gtk.RESPONSE_YES:
                        force = True
                    else:
                        return False
                if force:
                    try:
                        self.uninstall_plugin(installed_plugin_path)
                        count = 1
                        target_path = installed_plugin_path
                        while installed_plugin_path.exists():
                            installed_plugin_path = path(
                                '%s%d' % (installed_plugin_path, count))
                        if target_path != installed_plugin_path:
                            self.rename_queue.append((installed_plugin_path,
                                                      target_path))
                    except:
                        raise
                        return False
        else:
            # There is no valid version of this plugin currently installed.
            logging.info('%s is not currently installed' %
                         plugin_metadata.plugin_name)

            # enable new plugins by default
            app.config["plugins"]["enabled"].append(plugin_metadata
                                                    .package_name)
        try:
            self.install_plugin(plugin_root, installed_plugin_path)
            logging.info('%s installed successfully' %
                         plugin_metadata.plugin_name)
        except Exception, why:
            logging.error('Error installing plugin. %s.', why)
Beispiel #18
0
    def verify_and_install_new_plugin(self, plugin_root, force=False):
        plugin_metadata = get_plugin_info(plugin_root)
        if plugin_metadata is None:
            logging.error('%s does not contain a valid plugin.' % plugin_root)
            return False
        logging.info('Installing: %s' % (plugin_metadata, ))

        app = get_app()
        installed_plugin_path = (path(app.config.data['plugins']['directory'])
                                 .joinpath(plugin_metadata.package_name))
        installed_metadata = get_plugin_info(installed_plugin_path)

        if installed_metadata:
            logging.info('Currently installed: %s' % (installed_metadata,))
            if installed_metadata.version.tags == \
                    plugin_metadata.version.tags and \
                    installed_metadata.version >= plugin_metadata.version:
                # Installed version is up-to-date
                message = ('Plugin %s is up-to-date (version %s).  Skipping '
                           'installation.' % (installed_metadata.plugin_name,
                           installed_metadata.version))
                logging.info(message)
                return
            else:
                message = ('A newer version (%s) of the %s plugin is available'
                           ' (current version=%s).' % (plugin_metadata.version,
                                                       plugin_metadata
                                                       .plugin_name,
                                                       installed_metadata
                                                       .version))
                logging.info(message)
                if not force:
                    response = yesno('''%s Would you like to upgrade?''' %
                                     message)
                    if response == gtk.RESPONSE_YES:
                        force = True
                    else:
                        return False
                if force:
                    try:
                        self.uninstall_plugin(installed_plugin_path)
                        count = 1
                        target_path = installed_plugin_path
                        while installed_plugin_path.exists():
                            installed_plugin_path = path(
                                '%s%d' % (installed_plugin_path, count))
                        if target_path != installed_plugin_path:
                            self.rename_queue.append((installed_plugin_path,
                                                      target_path))
                    except:
                        raise
                        return False
        else:
            # There is no valid version of this plugin currently installed.
            logging.info('%s is not currently installed' %
                         plugin_metadata.plugin_name)

            # enable new plugins by default
            app.config["plugins"]["enabled"].append(plugin_metadata
                                                    .package_name)
        try:
            self.install_plugin(plugin_root, installed_plugin_path)
            logging.info('%s installed successfully' %
                         plugin_metadata.plugin_name)
        except Exception, why:
            logging.error('Error installing plugin. %s.', why)
     get_service_names('microdrop')
 missing_plugins = []
 for k, v in p.plugin_data.items():
     if k not in enabled_plugins and k not in missing_plugins:
         missing_plugins.append(k)
 for i in range(len(p)):
     for k, v in p[i].plugin_data.items():
         if k not in enabled_plugins and k not in missing_plugins:
             missing_plugins.append(k)
 if missing_plugins:
     logging.info('load protocol(%s): missing plugins: %s' %
                  (filename, ", ".join(missing_plugins)))
     result = yesno('Some data in the protocol "%s" requires '
                    'plugins that are not currently installed:'
                    '\n\t%s\nThis data will be ignored unless you '
                    'install and enable these plugins. Would you'
                    'like to permanently clear this data from the '
                    'protocol?' % (p.name,
                                 ",\n\t".join(missing_plugins)))
     if result == gtk.RESPONSE_YES:
         logging.info('Deleting protocol data for missing items')
         for k, v in p.plugin_data.items():
             if k in missing_plugins:
                 del p.plugin_data[k]
         for i in range(len(p)):
             for k, v in p[i].plugin_data.items():
                 if k in missing_plugins:
                     del p[i].plugin_data[k]
         self.save_protocol()
 self.modified = False
 emit_signal("on_protocol_swapped", [app.protocol, p])
Beispiel #20
0
    def _export_protocol(self):
        app = get_app()

        filter_ = gtk.FileFilter()
        filter_.set_name(' MicroDrop protocols (*.json)')
        filter_.add_pattern("*.json")

        dialog = gtk.FileChooserDialog(
            title="Export protocol",
            action=gtk.FILE_CHOOSER_ACTION_SAVE,
            buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE,
                     gtk.RESPONSE_OK))
        dialog.add_filter(filter_)
        dialog.set_default_response(gtk.RESPONSE_OK)
        dialog.set_current_name(app.protocol.name)
        dialog.set_current_folder(
            os.path.join(app.get_device_directory(), app.dmf_device.name,
                         "protocols"))
        response = dialog.run()
        try:
            if response == gtk.RESPONSE_OK:
                filename = ph.path(dialog.get_filename())
                if filename.ext.lower() != '.json':
                    filename = filename + '.json'
                logger = _L()  # use logger with method context
                try:
                    with open(filename, 'w') as output:
                        protocol_dict_to_json(upgrade_protocol(app.protocol),
                                              ostream=output,
                                              validate=False,
                                              json_kwargs={'indent': 2})
                except md.protocol.SerializationError, exception:
                    plugin_exception_counts = Counter(
                        [e['plugin'] for e in exception.exceptions])
                    logger.info('%s: `%s`', exception, exception.exceptions)
                    result = yesno(
                        'Error exporting data for the following '
                        'plugins: `%s`\n\n'
                        'Would you like to exclude this data and '
                        'export anyway?' %
                        ', '.join(sorted(plugin_exception_counts.keys())))
                    if result == gtk.RESPONSE_YES:
                        # Delete plugin data that is causing serialization
                        # errors.
                        protocol = copy.deepcopy(app.protocol)
                        protocol.remove_exceptions(exception.exceptions,
                                                   inplace=True)
                        with open(filename, 'w') as output:
                            protocol_dict_to_json(upgrade_protocol(
                                app.protocol),
                                                  ostream=output,
                                                  validate=False,
                                                  json_kwargs={'indent': 2})
                    else:
                        # Abort export.
                        logger.warn('Export cancelled.')
                        return
                logger.info('exported protocol to %s', filename)
                app = get_app()
                parent_window = app.main_window_controller.view
                message = 'Exported protocol to:\n\n%s' % filename
                ok_dialog = gtk.MessageDialog(parent=parent_window,
                                              message_format=message,
                                              type=gtk.MESSAGE_OTHER,
                                              buttons=gtk.BUTTONS_OK)
                # Increase default dialog size.
                ok_dialog.set_size_request(450, 150)
                ok_dialog.props.title = 'Export complete'
                ok_dialog.props.use_markup = True
                ok_dialog.run()
                ok_dialog.destroy()
        finally:
            dialog.destroy()