Exemple #1
0
    def setup(self, out_dir):
        """Run setup actions for the external dependency"""
        self.out_dir = out_dir

        # Build the contents of the cache file.  This must include enough information to verify
        # the reproducibility of the actions, so it contains all input parameters to the
        # dependency.
        cache_file_contents = [
            "***Delete this file to re-run dependency setup***",
            "name={}".format(self.name), "out_dir={}".format(self.out_dir)
        ]
        for a in self.actions:
            cache_file_contents.append("action {} {}".format(
                a.ACTION_TYPE, a.arg))

        if _SetupBeginAction(cache_file_contents).run(self):
            Log.I("{} up to date".format(self.name))
            return
        else:
            Log.I("Setting up {}".format(self.name))
        inputs = []
        for a in self.actions:
            inputs = a.run(self, inputs)
            Log.D("    => {}".format(inputs))
        _SetupCompleteAction(cache_file_contents).run(self)
Exemple #2
0
 def generate(self, definitions, out_dir):
     """Generate a settings file"""
     args = dict(DEFINITIONS=definitions,
                 OUT_DIR=out_dir,
                 OUT_FILE=self.filename,
                 PARAM_TYPE=DefTree.PARAM_TYPE,
                 g_print=lambda msg: Log.I("        {}".format(str(msg))),
                 g_debug=lambda msg: Log.D("        {}".format(str(msg))),
                 g_err=lambda msg: Log.E(msg, stackframe=3))
     runpy.run_path(self.formatter,
                    init_globals=args,
                    run_name="<globifest>")
Exemple #3
0
def extract_zipfile(zip_filename, out_dir, prefix=None, do_test=True):
    """
        Extract an archive using zipfile

        If prefix is provided then only files with the prefix are used, and
        the prefix is removed from the output path
    """
    with zipfile.ZipFile(zip_filename, mode="r") as zip_fh:
        if do_test:
            bad_file = zip_fh.testzip()
            if bad_file:
                Log.E("Corrupt archive at: {}".format(bad_file))
            else:
                Log.D("  Archive tested OK")
        # Check if doing path replacement, if so, normalize paths
        if prefix:
            Log.D("  Using prefix '{}'".format(prefix))
        Log.D("  Extracting to: {}".format(out_dir))
        for file in zip_fh.infolist():
            if prefix:
                if not file.filename.startswith(prefix):
                    continue
                orig_fn = file.filename
                start_idx = len(prefix)
                try:
                    while file.filename[start_idx] in ["/", "\\"]:
                        # This is a directory; fix up for the user so it does not
                        # extract to the root of the host's filesystem.
                        start_idx += 1
                except IndexError:
                    # Just the prefix, possibly with trailing slashes; just skip.
                    continue
                file.filename = file.filename[start_idx:]
                Log.D("    {} => {}".format(orig_fn, file.filename))
            else:
                Log.D("    {}".format(file.filename))
            zip_fh.extract(file, path=out_dir)
Exemple #4
0
 def log_debug(self, text):
     """Log a debug message pertinent to the action"""
     Log.D("  {}: {}".format(self.ACTION_TYPE, text))
Exemple #5
0
def build_project(in_fname, out_dir, settings, callbacks=Util.Container()):
    """
      Build a project with the given settings
    """
    project, prj_dir, out_dir = read_project(in_fname, out_dir)
    Log.I("Project: {}".format(project.get_name()))
    Log.I("PrjDir: {}".format(prj_dir))
    Log.I("OutDir: {}".format(out_dir))

    os.makedirs(out_dir, exist_ok=True)

    # Check external project dependencies
    for dep_name, dependency in project.get_dependencies():
        Log.I("Checking dependency {}...".format(dep_name))
        dep_out_dir = os.path.join(out_dir, dep_name)
        os.makedirs(dep_out_dir, exist_ok=True)
        dependency.setup(dep_out_dir)

    # Set up build configuration
    Log.I("Build configuration:")
    setting_re = re.compile("([^=]+)=(.+)")
    cfg_container = Util.Container()  # Unordered, for tracking purposes
    for cfg_entry in settings:
        m = Matcher.new(cfg_entry)
        if not m.is_fullmatch(setting_re):
            Log.E("Malformed setting: {}".format(cfg_entry))
        if cfg_container.get(m[1]):
            Log.E("Conflicting/Duplicate setting: {}".format(cfg_entry))
        Log.I("  {}: {}".format(m[1], m[2]))
        variant = project.get_target(m[1], m[2])
        # Update the filename with the absolute path
        variant.filename = Util.get_abs_path(variant.filename, prj_dir)
        cfg_container[m[1]] = variant

    # Validate that all layers are specified
    for layer in project.get_layer_names():
        variant = cfg_container.get(layer)
        if variant is None:
            variant_names = project.get_variant_names(layer)
            if len(variant_names) == 1:
                # None specified, but there is only one
                variant = project.get_target(layer, variant_names[0])
                Log.D("  **Default selected for layer {}**".format(layer))
                Log.I("  {}: {}".format(layer, variant.name))
                variant.filename = Util.get_abs_path(variant.filename, prj_dir)
                cfg_container[layer] = variant
            else:
                Log.E("Must specify variant for layer {}".format(layer))

    Log.I("Generating settings in layer order:")
    effective_settings = Settings.new()
    for layer in project.get_layer_names():
        variant = cfg_container.get(layer)
        Log.I("  {}: {}".format(layer, variant.filename))
        layer_config = build_config(variant.filename)
        effective_settings.extend(layer_config.get_settings())

    # Generate a metadata object to communicate information back to the caller
    metadata = Util.Container(prj_dir=prj_dir,
                              out_dir=out_dir,
                              settings=effective_settings)

    #### PREBUILD CALLBACK ####
    if callbacks.get("prebuild"):
        callbacks.prebuild(callbacks.get("arg"), metadata)

    # Prepare storage for package processing
    for pub_key in ManifestParser.PUBLIC_LABELS:
        metadata[pub_key] = []
    all_manifests = []

    Log.I("Processing packages...")
    for pkg in project.get_packages():
        pkg_file = get_pkg_file(project, pkg, prj_dir, out_dir)
        if pkg_file is None:
            Log.I("Unknown file root {}".format(str(pkg.file_root)))
        pkg_root = get_pkg_root(project, pkg, pkg_file, out_dir)
        if pkg_root is None:
            Log.I("Unknown package root {}".format(str(pkg.file_root)))
        Log.I("  {}".format(pkg_file))
        manifest = build_manifest(pkg_file, effective_settings, pkg_root)
        all_manifests.append(manifest)
        pkg_dir = os.path.dirname(pkg_file)
        manifest_out = manifest.get_output()
        # Replace all file paths with absolute paths
        for k in ManifestParser.FILE_LABELS:
            manifest_out[k] = [
                Util.get_abs_path(x, pkg_dir) for x in manifest_out[k]
            ]
        # Aggregate all public labels
        for pub_key in ManifestParser.PUBLIC_LABELS:
            metadata[pub_key] += manifest_out[pub_key]
        # Dump all the files on extreme mode
        if Log.Logger.has_level(Log.LEVEL.EXTREME):
            for k, v in manifest_out:
                Log.X("    {}:".format(k))
                for f in v:
                    Log.X("      {}".format(f))
        for cfg in manifest.get_configs():
            Log.I("    Post-processing {}".format(cfg.definition_abs))
            defs = cfg.def_tree.get_relevant_params(effective_settings)
            for gen in cfg.generators:
                gen_file = Util.get_abs_path(gen.get_filename(), pkg_dir)
                gen_file = os.path.relpath(gen_file, start=pkg_dir)
                gen_file = os.path.normpath(gen_file)
                gen_file = os.path.join(out_dir, gen_file)
                # Update the filename in the generator
                gen.filename = gen_file
                Log.I("      Generating {}".format(gen_file))
                if gen.get_formatter():
                    formatter_filename = Util.get_abs_path(
                        gen.get_formatter(), pkg_dir)
                    Log.I("      Executing {}".format(formatter_filename))
                #### GENERATOR CALLBACK ####
                if callbacks.get("generator"):
                    # Let the build script intercept the generator without any filesystem changes
                    callbacks.generator(callbacks.get("arg", None), metadata,
                                        defs, gen)
                else:
                    os.makedirs(os.path.dirname(gen_file), exist_ok=True)
                    gen.generate(defs, out_dir)

    #### POSTPROCESS CALLBACK ####
    if callbacks.get("postprocess"):
        callbacks.postprocess(callbacks.get("arg"), metadata)

    # Add public data into each manifest and build
    if callbacks.get("target"):
        for manifest in all_manifests:
            tables = Util.Container()
            manifest_out = manifest.get_output()
            for k, v in manifest_out:
                if not k in ManifestParser.PUBLIC_LABELS:
                    tables[k] = v
            manifest_name = os.path.relpath(manifest.get_filename(),
                                            start=prj_dir)
            manifest_name = os.path.normpath(manifest_name)
            manifest_name = os.path.splitext(manifest_name)[0]

            #### BUILD TARGET CALLBACK ####
            callbacks.target(callbacks.get("arg", None), metadata,
                             manifest_name, tables)

    #### POSTBUILD CALLBACK ####
    if callbacks.get("postbuild"):
        callbacks.postbuild(callbacks.get("arg", None), metadata)