def info_project(project: c.Project, ls_upgrades): """ Display information about a PROS project Visit https://pros.cs.purdue.edu/v5/cli/conductor to learn more """ class ProjectReport(object): def __init__(self, project: c.Project): self.project = { "target": project.target, "location": os.path.abspath(project.location), "name": project.name, "templates": [{ "name": t.name, "version": t.version, "origin": t.origin } for t in project.templates.values()] } def __str__(self): import tabulate s = f'PROS Project for {self.project["target"]} at: {self.project["location"]}' \ f' ({self.project["name"]})' if self.project["name"] else '' s += '\n' rows = [t.values() for t in self.project["templates"]] headers = [ h.capitalize() for h in self.project["templates"][0].keys() ] s += tabulate.tabulate(rows, headers=headers) return s def __getstate__(self): return self.__dict__ report = ProjectReport(project) _conductor = c.Conductor() if ls_upgrades: for template in report.project['templates']: import semantic_version as semver templates = _conductor.resolve_templates( c.BaseTemplate.create_query(name=template["name"], version=f'>{template["version"]}', target=project.target)) template["upgrades"] = sorted({t.version for t in templates}, key=lambda v: semver.Version(v), reverse=True) ui.finalize('project-report', report)
def confirm(self, *args, **kwargs): assert self.can_confirm self.exit() project = self.conductor.new_project( path=self.directory.value, target=self.targets.value, version=self.kernel_versions.value, no_default_libs=not self.install_default_libraries.value, project_name=self.project_name.value) from pros.conductor.project import ProjectReport report = ProjectReport(project) ui.finalize('project-report', report) with ui.Notification(): ui.echo('Building project...') project.compile([])
def write_program(self, file: typing.BinaryIO, **kwargs): action_string = '' if hasattr(file, 'name'): action_string += f' {Path(file.name).name}' action_string += f' to Cortex on {self.port}' ui.echo(f'Uploading {action_string}') logger(__name__).info('Writing program to Cortex') status = self.query_system() logger(__name__).info(status) if not status.flags | self.SystemStatusFlags.TETH_USB and not status.flags | self.SystemStatusFlags.DL_MODE: self.send_to_download_channel() bootloader = self.expose_bootloader() rv = bootloader.write_program(file, **kwargs) ui.finalize('upload', f'Finished uploading {action_string}') return rv
def ls_usb(target): """ List plugged in VEX Devices """ from pros.serial.devices.vex import find_v5_ports, find_cortex_ports class PortReport(object): def __init__(self, header: str, ports: List[Any], machine_header: Optional[str] = None): self.header = header self.ports = [{ 'device': p.device, 'desc': p.description } for p in ports] self.machine_header = machine_header or header def __getstate__(self): return {'device_type': self.machine_header, 'devices': self.ports} def __str__(self): if len(self.ports) == 0: return f'There are no connected {self.header}' else: port_str = "\n".join( [f"{p['device']} - {p['desc']}" for p in self.ports]) return f'{self.header}:\n{port_str}' result = [] if target == 'v5' or target is None: ports = find_v5_ports('system') result.append(PortReport('VEX EDR V5 System Ports', ports, 'v5/system')) ports = find_v5_ports('User') result.append(PortReport('VEX EDR V5 User ports', ports, 'v5/user')) if target == 'cortex' or target is None: ports = find_cortex_ports() result.append( PortReport('VEX EDR Cortex Microcontroller Ports', ports, 'cortex')) ui.finalize('lsusb', result)
def test(): ui.echo('Hello World!') with ui.Notification(): ui.echo('Hello from another box') ui.echo('Back on the other one', nl=False) ui.echo('Whoops I missed a newline') with ui.Notification(): ui.echo('Yet another box') with ui.progressbar(range(20)) as bar: for _ in bar: time.sleep(0.1) ui.echo('more below the ', nl=False) ui.echo('progressbar') ui.echo('Back in the other notification') logger(__name__).warning('Hello') try: raise Exception('Hey') except Exception as e: logger(__name__).exception(e) ui.finalize('test', {'hello': 'world'}, human_prefix='Created ')
def query_templates(ctx, query: c.BaseTemplate, allow_offline: bool, allow_online: bool, force_refresh: bool, limit: int): """ Query local and remote templates based on a spec Visit https://pros.cs.purdue.edu/v5/cli/conductor.html to learn more """ if limit < 0: limit = 15 templates = c.Conductor().resolve_templates( query, allow_offline=allow_offline, allow_online=allow_online, force_refresh=force_refresh)[:limit] render_templates = {} for template in templates: key = (template.identifier, template.origin) if key in render_templates: if isinstance(template, c.LocalTemplate): render_templates[key]['local'] = True else: render_templates[key] = { 'name': template.name, 'version': template.version, 'location': template.origin, 'target': template.target, 'local': isinstance(template, c.LocalTemplate) } import semantic_version as semver render_templates = sorted(render_templates.values(), key=lambda k: k['local']) # tertiary key render_templates = sorted(render_templates, key=lambda k: semver.Version(k['version']), reverse=True) # secondary key render_templates = sorted(render_templates, key=lambda k: k['name']) # primary key ui.finalize('template-query', render_templates)
def info_project(project: c.Project, ls_upgrades): """ Display information about a PROS project Visit https://pros.cs.purdue.edu/v5/cli/conductor.html to learn more """ from pros.conductor.project import ProjectReport report = ProjectReport(project) _conductor = c.Conductor() if ls_upgrades: for template in report.project['templates']: import semantic_version as semver templates = _conductor.resolve_templates( c.BaseTemplate.create_query(name=template["name"], version=f'>{template["version"]}', target=project.target)) template["upgrades"] = sorted({t.version for t in templates}, key=lambda v: semver.Version(v), reverse=True) ui.finalize('project-report', report)
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())
def upload(path: str, project: Optional[c.Project], port: str, **kwargs): """ Upload a binary to a microcontroller. [PATH] may be a directory or file. If a directory, finds a PROS project root and uploads the binary for the correct target automatically. If a file, then the file is uploaded. Note that --target must be specified in this case. [PORT] may be any valid communication port file, such as COM1 or /dev/ttyACM0. If left blank, then a port is automatically detected based on the target (or as supplied by the PROS project) """ import pros.serial.devices.vex as vex from pros.serial.ports import DirectPort args = [] if path is None or os.path.isdir(path): if project is None: project_path = c.Project.find_project(path or os.getcwd()) if project_path is None: raise click.UsageError( 'Specify a file to upload or set the cwd inside a PROS project' ) project = c.Project(project_path) path = os.path.join(project.location, project.output) if project.target == 'v5' and not kwargs['name']: kwargs['name'] = project.name # apply upload_options as a template options = dict(**project.upload_options) options.update(kwargs) kwargs = options kwargs[ 'target'] = project.target # enforce target because uploading to the wrong uC is VERY bad if 'program-version' in kwargs: kwargs['version'] = kwargs['program-version'] if 'name' not in kwargs: kwargs['name'] = project.name if 'target' not in kwargs: logger(__name__).debug( f'Target not specified. Arguments provided: {kwargs}') raise click.UsageError( 'Target not specified. specify a project (using the file argument) or target manually' ) if kwargs['target'] == 'v5': port = resolve_v5_port(port, 'system') elif kwargs['target'] == 'cortex': port = resolve_cortex_port(port) else: logger(__name__).debug(f"Invalid target provided: {kwargs['target']}") logger(__name__).debug('Target should be one of ("v5" or "cortex").') if not port: return -1 if kwargs['target'] == 'v5': if kwargs['name'] is None: kwargs['name'] = os.path.splitext(os.path.basename(path))[0] args.append(kwargs.pop('name').replace('@', '_')) kwargs['slot'] -= 1 if kwargs['run_after'] and kwargs['run_screen']: kwargs['run_after'] = vex.V5Device.FTCompleteOptions.RUN_SCREEN elif kwargs['run_after'] and not kwargs['run_screen']: kwargs[ 'run_after'] = vex.V5Device.FTCompleteOptions.RUN_IMMEDIATELY else: kwargs['run_after'] = vex.V5Device.FTCompleteOptions.DONT_RUN elif kwargs['target'] == 'cortex': pass # print what was decided ui.echo('Uploading {} to {} device on {}'.format(path, kwargs['target'], port), nl=False) if kwargs['target'] == 'v5': ui.echo(f' as {args[0]} to slot {kwargs["slot"] + 1}', nl=False) ui.echo('') logger(__name__).debug('Arguments: {}'.format(str(kwargs))) if not os.path.isfile(path) and path is not '-': logger(__name__).error( '{} is not a valid file! Make sure it exists (e.g. by building your project)' .format(path)) return -1 # Do the actual uploading! try: ser = DirectPort(port) device = None if kwargs['target'] == 'v5': device = vex.V5Device(ser) elif kwargs['target'] == 'cortex': device = vex.CortexDevice(ser).get_connected_device() with click.open_file(path, mode='rb') as pf: device.write_program(pf, *args, **kwargs) except Exception as e: logger(__name__).exception(e, exc_info=True) exit(1) ui.finalize('upload', f'Finished uploading {path} to {kwargs["target"]} on {port}')
def query_system(self) -> SystemStatus: logger(__name__).info('Querying system information') rx = self._txrx_simple_struct(0x21, "<8B2x") status = CortexDevice.SystemStatus(rx) ui.finalize('cortex-status', status) return status