#! /usr/bin/env python from __future__ import print_function import optparse import os.path import re import sys class GeneratorBase(object): def gen(self, recipe, recipe_dir, common_dir): self.common_dir = common_dir for ingredient in recipe: path = self._get_path(ingredient, recipe_dir) self._add(path) self._print_output() def _get_path(self, ingredient, recipe_dir): m = re.match(r"(common|local)/(.*)", ingredient) if not m: raise RuntimeError( "Error while parsing:\n\t{0}".format(ingredient)) if m.group(1) == "local": path = os.path.join(recipe_dir, m.group(2)) elif m.group(1) == "common": path = os.path.join(self.common_dir, m.group(2)) return path class DirListGenerator(GeneratorBase): def __init__(self): self.output = [] def _add(self, ingredient): self.output.append(ingredient) def _print_output(self): for line in self.output: print(line) class TextFileGenerator(GeneratorBase): def __init__(self): self.output = [] def _add(self, ingredient): self.output.extend(open(ingredient).readlines()) def _print_output(self): for line in self.output: print(line, end='') class KconfigGenerator(GeneratorBase): class ConfigLine(object): def __init__(self, line): self.line = line self.symbol = None self.overwritten = False def _parse_config_line(self, line): config_line = KconfigGenerator.ConfigLine(line) m = re.match(r"(?P\w+)=.*$", line) if not m: m = re.match(r"# (?P\w+) is not set$", line) if m: config_line.symbol = m.group("symbol") return config_line def _add_symbol(self, new_config_line): found = False for (i, config_line) in enumerate(self.config): if config_line.symbol == new_config_line.symbol: found = True break if found: if self.config[i].overwritten: raise RuntimeError( "Multiple overwrite of symbol {0}.".format( self.config[i].symbol)) self.config[i] = new_config_line self.config[i].overwritten = True else: self.config.append(new_config_line) def _add_config_part(self, config_part): for line in open(config_part).readlines(): config_line = self._parse_config_line(line) if config_line.symbol: self._add_symbol(config_line) else: self.config.append(config_line) def __init__(self): self.config = [] def _add(self, ingredient): self._add_config_part(ingredient) def _print_output(self): for config_line in self.config: print(config_line.line, end='') def get_recipe(desc, gen): recipe = [] found = False for line in open(desc).readlines(): if line[0].isspace(): if not target: raise RuntimeError( "Error while parsing line:\n\t\{0}".format(line)) if found: line = line.strip() if line: recipe.append(line.strip()) else: if found: break else: target = line.strip() if target == gen: found = True if found: return recipe else: return None def main(args): usage="Generate from a description." parser = optparse.OptionParser(usage=usage) parser.add_option("", "--desc-file", type="string", dest="desc", help="description file") parser.add_option("", "--common-dir", type="string", dest="common_dir", help="common directory") parser.add_option("", "--gen", type="string", dest="gen", help="what to generate") parser.add_option("", "--list-gen", action="store_true", dest="list_gen", help="list possible values for --gen") (options, args) = parser.parse_args() generators = { "busybox.config": KconfigGenerator, "defconfig": KconfigGenerator, "device_table.txt": TextFileGenerator, "linux26.config": KconfigGenerator, "target_skeleton": DirListGenerator } if options.list_gen: for generator in sorted(generators.keys()): print(generator) return if (not options.desc) or (not options.common_dir) or (not options.gen): parser.print_help() return if options.gen in generators: generator = generators[options.gen]() else: raise RuntimeError("Don't know how to generate \"{0}\"".format( options.gen)) recipe = get_recipe(options.desc, options.gen) if not recipe: raise RuntimeError( "Cannot find recipe to generate \"{0}\"".format(options.gen)) generator.gen(recipe, os.path.dirname(options.desc), options.common_dir) if __name__ == "__main__": main(sys.argv)