Example #1
0
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([])
Example #3
0
    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
Example #4
0
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)
Example #5
0
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 ')
Example #6
0
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)
Example #7
0
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)
Example #8
0
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())
Example #9
0
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}')
Example #10
0
 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