def cmd_dump_project(args):
    if len(mainlist.projects) == 0:
        putter.error('No projects available.')
        return

    apply_define_args(args)

    if args.project is None:
        with putter.group('Projects'):
            for name in mainlist.projects:
                path = resolve_project_path(name, do_not_crash=True)
                if path is None:
                    putter.warning(
                        f'No path allowed by conditions for {cf.bold(name)}.')
                    continue
                try:
                    data = read_project(path)
                    dump_project(data)
                except (ValueError, AssertionError):
                    putter.error('Could not parse file.')
                except FileNotFoundError:
                    putter.error(f'File not found: {cf.underlined(path)}.')
        return

    try:
        data = read_project(resolve_project_path(args.project))
        dump_project(data)
    except (ValueError, AssertionError):
        putter.error('Could not parse file.')
        raise
    except FileNotFoundError:
        putter.error(f'File not found: {cf.underlined(path)}.')
        raise
def resolve_project_path(name, do_not_crash=False):
    proj = mainlist.projects[name]

    # TODO(maximsmol): shortcircuit path search if not debugging
    path = None
    for p in proj.paths:
        if 'cond' not in p:
            if path is not None:
                putter.die(
                    f'Multiple paths apply: {cf.bold(path)} and {cf.bold(p.path)}.'
                )
            path = p.path
            continue

        if eval_cond(p.cond):
            if path is not None:
                putter.die(
                    f'Multiple paths apply: {cf.bold(path)} and {cf.bold(p.path)}.'
                )
            path = p.path
    if path is None:
        if do_not_crash:
            return None

        # TODO(maximsmol): display why each condition failed
        err_dump_macro_state()
        putter.newline()
        putter.error(f'Found no applicable paths after trying the following:')
        with putter.indent():
            for p in proj.paths:
                putter.error(f'{cf.italic(p.path)}{cond_suffix(p)}')
        putter.newline()

    return Path(path)
def cmd_build(args):
    if args.group is None:
        putter.error('Specify a group to build.')
        print()
        with putter.group('Available groups'):
            print(putter.render_list(mainlist.groups.keys()))
        return

    apply_define_args(args)
    build_project('client')
def cmd_dump_group(args):
    if len(mainlist.groups) == 0:
        putter.error('No groups available.')
        return

    if args.group is None:
        with putter.group('Groups'):
            for name in mainlist.groups:
                dump_group(name)
        return

    dump_group(args.group)
def cmd_dump_project_manifest(args):
    if len(mainlist.projects) == 0:
        putter.error('No projects available.')
        return

    apply_define_args(args)

    if args.project is None:
        with putter.group('Projects'):
            for name in mainlist.projects:
                dump_project_manifest(name)
        return

    dump_project_manifest(args.project)
def err_dump_macro_state():
    have_non_bool_macros = False
    bool_macro_strs = []
    for k, v in macro_state.items():
        if not isinstance(v, bool):
            have_non_bool_macros = True
            continue
        if v is True:
            bool_macro_strs.append(f'${k}')
        else:
            bool_macro_strs.append(f'!${k}')

    if not have_non_bool_macros:
        putter.error('Macros: ' + putter.render_list(bool_macro_strs))
    else:
        putter.error('Macros:')

    with putter.indent():
        for k, v in macro_state.items():
            if v is True:
                continue
            putter.error(f'{cf.bold("$"+k)} = {render_macro_value(v)}')
def build_project(name):
    project_data = Namespace(configuration=Namespace(compiler=Namespace()))

    root_path = None

    def build_data(path):
        data = read_project(path)
        for inst in data.instructions:
            if inst.type == 'conditional':
                val = expand_macros_in_string(inst.value)
                if 'cond' not in inst or eval_cond(inst.cond):
                    if val == '1':
                        val = True
                    if val == '0':
                        val = False

                    if val in no_strings or val in yes_strings:
                        putter.warning(
                            f'Found yes/no string but refusing to convert it: {render_macro_value(val)}'
                        )

                    print(
                        f'{cf.magenta("Set conditional")} {cf.bold("$"+inst.name)} = {render_macro_value(val)}{cond_suffix(inst)}'
                    )
                    if inst.name in macro_state and val != macro_state[
                            inst.name]:
                        with putter.indent():
                            putter.warning(
                                f'Overriding old value of {render_macro_value(macro_state[inst.name])}'
                            )
                    macro_state[inst.name] = val
                else:
                    print(
                        f'Not setting conditional {cf.bold("$"+inst.name)} = {render_macro_value(val)}{cond_suffix(inst)} due to the false condition'
                    )
            elif inst.type == 'macro':
                val = expand_macros_in_string(inst.value)
                if 'cond' not in inst or eval_cond(inst.cond):
                    if val == '1':
                        val = True
                    if val == '0':
                        val = False

                    if val in no_strings or val in yes_strings:
                        putter.warning(
                            f'Found yes/no stringbut refusing to convert it: {render_macro_value(val)}'
                        )

                    print(
                        f'{cf.magenta("Set")} {cf.bold("$"+inst.name)} = {render_macro_value(val)}{cond_suffix(inst)}'
                    )
                    if inst.name in macro_state and val != macro_state[
                            inst.name]:
                        with putter.indent():
                            putter.warning(
                                f'Overriding old value of {render_macro_value(macro_state[inst.name])}'
                            )
                    macro_state[inst.name] = val
                else:
                    print(
                        f'Not setting {cf.bold("$"+inst.name)} = {render_macro_value(val)}{cond_suffix(inst)} due to the false condition'
                    )
            elif inst.type == 'include':
                if 'cond' not in inst or eval_cond(inst.cond):
                    print(
                        f'{cf.magenta("Including")} {cf.italic(inst.path)}{cond_suffix(inst)}'
                    )
                    with putter.indent():
                        include_path = expand_macros_in_string(inst.path)
                        resolved_path = Path(
                            ntpath.normpath(
                                str(root_path.parent / include_path)))
                        print(
                            f'{cf.magenta("Resolved to")} {cf.italic(resolved_path)}'
                        )
                        build_data(resolved_path)
                else:
                    print(
                        f'Not including {cf.italic(Path(inst.path).name)}{cond_suffix(inst)} due to the false condition'
                    )
            elif inst.type == 'configuration':

                def print_generic_dict(x_name):
                    x_key = vpc.configuration_commands[x_name].pythonized
                    if x_key not in inst:
                        return

                    # TODO(maximsmol): print the merging process
                    merged = Namespace()
                    for x in inst[x_key]:
                        if 'cond' not in x or eval_cond(x.cond):
                            merge_command_data(merged, x)

                    with putter.group(x_name):
                        for k, v in merged.items():
                            print(f'{cf.bold(k)} = {cf.bold(v)}')

                suffix = ''
                if 'name' in inst:
                    suffix = f' "{inst.name}"'
                with putter.group(f'Configuration{suffix}'):
                    for generic_group in vpc.configuration_commands:
                        print_generic_dict(generic_group)
            elif inst.type == 'macro_required':
                invalid_value = macro_state.get(
                    inst.name) == '' and not inst.allow_empty
                if inst.name not in macro_state or invalid_value:
                    if 'default' not in inst:
                        if inst.name not in macro_state:
                            die(f'Macro {cf.bold("$"+inst.name)} is required, but not defined.'
                                )
                        if not inst.allow_empty:
                            die(f'Macro {cf.bold("$"+inst.name)} is required, but is set to an empty string.'
                                )
                    with putter.indent():
                        print(
                            f'{cf.magenta("Defaulted")} {cf.bold("$"+inst.name)} = {render_macro_value(inst.default)}'
                        )
                        macro_state[inst.name] = inst.default
                else:
                    print(
                        f'{cf.magenta("Found required")} {cf.bold("$"+inst.name)}'
                    )
            else:
                putter.warning(f'Skipped instruction {cf.bold(inst.type)}.')

    root_path = resolve_project_path(name)
    print(f'Resolved project to {cf.italic(root_path)}')
    print()
    try:
        build_data(root_path)
    except (ValueError, AssertionError):
        putter.newline()
        putter.error(f'Root path is: {cf.italic(root_path)}')
        die('Could not parse file.', linefeed_before=False)
        raise
    except FileNotFoundError as e:
        putter.newline()
        putter.error(f'Root path is: {cf.italic(root_path)}')
        die(f'File not found: {cf.italic(e.filename)}.', linefeed_before=False)
        raise
Exemple #8
0
 def die(self, msg, *args, **kwargs):
   p = Path(self.file.name)
   # putter.error(f'{cf.bold(str(self.line_cache[0])+":")} {self.lines[self.line_cache[0]-1].strip()}')
   putter.error(self.line_cache[1].rstrip()) # righthand whitespace will not be visible anyway
   putter.die(f'{cf.italic(p.name)}:{str(self.line_cache[0]+1)+":"} {msg}', *args, **kwargs)