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
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)