def project_changed(self, new_project: ExistingProjectParameter): try: self.is_processing = True self.project = Project(new_project.value) self.name.update(self.project.project_name) self.current_kernel = TemplateParameter( None, options=sorted( { t for t in self.conductor.resolve_templates( self.project.templates['kernel'].as_query()) }, key=lambda v: Version(v.version), reverse=True)) self.current_templates = [ TemplateParameter( None, options=sorted( { t for t in self.conductor.resolve_templates( t.as_query()) }, key=lambda v: Version(v.version), reverse=True)) for t in self.project.templates.values() if t.name != 'kernel' ] self.new_templates = [] self.is_processing = False except BaseException as e: ui.logger(__name__).exception(e)
def run(self) -> P: _push_renderer(self) self.thread = current_thread() self.alive = True while self.alive: self.render(self.app) if not self.alive: break line = self.get_line() if not self.alive or not line or line.isspace(): continue try: value = json.loads(line) if 'uuid' in value and 'event' in value: Observable.notify(value['uuid'], value['event'], *value.get('args', []), **value.get('kwargs', {})) except json.JSONDecodeError as e: ui.logger(__name__).exception(e) except BaseException as e: ui.logger(__name__).exception(e) break self.stop_sem.release() self.stop() return self.run_rv
def execute(self): if len(self.actions) == 0: ui.logger(__name__).warning('No actions necessary.') return location = self.project.location tfd, tfn = tempfile.mkstemp(prefix='pros-project-', suffix=f'-{self.project.name}.zip', text='w+b') with os.fdopen(tfd, 'w+b') as tf: with zipfile.ZipFile(tf, mode='w') as zf: files, length = it.tee(location.glob('**/*'), 2) length = len(list(length)) with ui.progressbar(files, length=length, label=f'Backing up {self.project.name} to {tfn}') as pb: for file in pb: zf.write(file, arcname=file.relative_to(location)) try: with ui.Notification(): for action in self.actions: ui.logger(__name__).debug(action.describe(self.conductor, self.project)) rv = action.execute(self.conductor, self.project) ui.logger(__name__).debug(f'{action} returned {rv}') if rv is not None and not rv: raise ValueError('Action did not complete successfully') ui.echo('All actions performed successfully') except Exception as e: ui.logger(__name__).warning(f'Failed to perform transaction, restoring project to previous state') with zipfile.ZipFile(tfn) as zf: with ui.progressbar(zf.namelist(), label=f'Restoring {self.project.name} from {tfn}') as pb: for file in pb: zf.extract(file, path=location) ui.logger(__name__).exception(e) finally: ui.echo(f'Removing {tfn}') os.remove(tfn)
def project_changed(self, new_project: ExistingProjectParameter): try: self.project = Project(new_project.value) assert self.project is not None if self.project.target == 'v5': self.advanced_options = { 'name': parameters.Parameter( self.project.upload_options.get( 'remote_name', self.project.name)), 'description': parameters.Parameter( self.project.upload_options.get( 'description', 'Created with PROS')), 'compress_bin': parameters.BooleanParameter( self.project.upload_options.get('compress_bin', True)) } self.update_slots() else: self.advanced_options = {} self.update_comports() self.redraw() except BaseException as e: ui.logger(__name__).exception(e)
def execute(self, conductor: c.Conductor, project: c.Project): try: conductor.remove_template(project, self.template, **self.remove_kwargs) except ValueError as e: if not self.suppress_not_removable: raise e else: ui.logger(__name__).warning(str(e))
def wake_me(self): """ Hack to wake up input thread to know to shut down """ ui.logger(__name__).debug(f'Broadcasting WAKEME for {self.app}') if ui.ismachineoutput(): ui._machineoutput({'type': 'wakeme'}) else: ui.echo('Wake up the renderer!')
def execute(self, conductor: c.Conductor, project: c.Project): try: conductor.apply_template(project, self.template, **self.apply_kwargs) except InvalidTemplateException as e: if e.reason != TemplateAction.AlreadyInstalled or not self.suppress_already_installed: raise e else: ui.logger(__name__).warning(str(e)) return None
def _add_template(self): options = self.conductor.resolve_templates( identifier=BaseTemplate(target=self.project.target), unique=True) ui.logger(__name__).debug(options) p = TemplateParameter(None, options) @p.on('removed') def remove_template(): self.new_templates.remove(p) self.new_templates.append(p)
def update_comports(self): list_all_comports.cache_clear() if isinstance(self.project, Project): options = {} if self.project.target == 'v5': options = {p.device for p in find_v5_ports('system')} elif self.project.target == 'cortex': options = [p.device for p in find_cortex_ports()] if options != {*self.port.options}: self.port.options = list(options) if self.port.value not in options: self.port.update(self.port.options[0] if len( self.port.options) > 0 else 'No ports found') ui.logger(__name__).debug('Updating ports') if self.project and self.project.target == 'v5': self.update_slots() self.redraw()
def prompt_to_send(event: Dict[str, Any], hint: Optional[Dict[str, Any]]) -> Optional[Dict[str, Any]]: """ Asks the user for permission to send data to Sentry """ global cli_config with ui.Notification(): if cli_config is None or (cli_config.offer_sentry is not None and not cli_config.offer_sentry): return if 'extra' in event and not event['extra'].get('sentry', True): ui.logger(__name__).debug('Not sending candidate event because event was tagged with extra.sentry = False') return if 'exc_info' in hint and (not getattr(hint['exc_info'][1], 'sentry', True) or any(isinstance(hint['exc_info'][1], t) for t in SUPPRESSED_EXCEPTIONS)): ui.logger(__name__).debug('Not sending candidate event because exception was tagged with sentry = False') return if not event['tags']: event['tags'] = dict() extra_text = '' if 'message' in event: extra_text += event['message'] + '\n' if 'culprit' in event: extra_text += event['culprit'] + '\n' if 'logentry' in event and 'message' in event['logentry']: extra_text += event['logentry']['message'] + '\n' if 'exc_info' in hint: import traceback extra_text += ''.join(traceback.format_exception(*hint['exc_info'], limit=4)) event['tags']['confirmed'] = ui.confirm('We detected something went wrong! Do you want to send a report?', log=extra_text) if event['tags']['confirmed']: ui.echo('Sending bug report.') ui.echo(f'Want to get updates? Visit https://pros.cs.purdue.edu/report.html?event={event["event_id"]}') return event else: ui.echo('Not sending bug report.')
def stop(self): ui.logger(__name__).debug(f'Stopping {self.app}') self.alive = False if current_thread() != self.thread: ui.logger(__name__).debug( f'Interrupting render thread of {self.app}') while not self.stop_sem.acquire(timeout=0.1): self.wake_me() ui.logger(__name__).debug(f'Broadcasting stop {self.app}') self._output({'uuid': self.app.uuid, 'should_exit': True}) _remove_renderer(self) top_renderer = _current_renderer() if top_renderer: top_renderer.wake_me()
def upgrade(force_check, no_install): """ Check for updates to the PROS CLI """ from pros.upgrade import UpgradeManager manager = UpgradeManager() manifest = manager.get_manifest(force_check) ui.logger(__name__).debug(repr(manifest)) if manager.has_stale_manifest: ui.logger(__name__).error( 'Failed to get latest upgrade information. ' 'Try running with --debug for more information') return -1 if not manager.needs_upgrade: ui.finalize('upgradeInfo', 'PROS CLI is up to date') else: ui.finalize('upgradeInfo', manifest) if not no_install: if not manager.can_perform_upgrade: ui.logger(__name__).error( f'This manifest cannot perform the upgrade.') return -3 ui.finalize('upgradeComplete', manager.perform_upgrade())