def read()

in esrally/track/loader.py [0:0]


    def read(self, track_name, track_spec_file, mapping_dir):
        """
        Reads a track file, verifies it against the JSON schema and if valid, creates a track.

        :param track_name: The name of the track.
        :param track_spec_file: The complete path to the track specification file.
        :param mapping_dir: The directory where the mapping files for this track are stored locally.
        :return: A corresponding track instance if the track file is valid.
        """

        self.logger.info("Reading track specification file [%s].", track_spec_file)
        # render the track to a temporary file instead of dumping it into the logs. It is easier to check for error messages
        # involving lines numbers and it also does not bloat Rally's log file so much.
        with tempfile.NamedTemporaryFile(delete=False, suffix=".json") as tmp:
            try:
                rendered = render_template_from_file(
                    track_spec_file,
                    self.track_params,
                    complete_track_params=self.complete_track_params,
                    build_flavor=self.build_flavor,
                    serverless_operator=self.serverless_operator,
                )
                with open(tmp.name, "w", encoding="utf-8") as f:
                    f.write(rendered)
                self.logger.info("Final rendered track for '%s' has been written to '%s'.", track_spec_file, tmp.name)
                track_spec = json.loads(rendered)
            except jinja2.exceptions.TemplateSyntaxError as te:
                self.logger.exception("Could not load [%s] due to Jinja Syntax Exception.", track_spec_file)
                msg = f"Could not load '{track_spec_file}' due to Jinja Syntax Exception. "
                msg += f"The track file ({tmp.name}) likely hasn't been written."
                raise TrackSyntaxError(msg, te)
            except jinja2.exceptions.TemplateNotFound:
                self.logger.exception("Could not load [%s]", track_spec_file)
                raise exceptions.SystemSetupError(f"Track {track_name} does not exist")
            except json.JSONDecodeError as e:
                self.logger.exception("Could not load [%s].", track_spec_file)
                msg = f"Could not load '{track_spec_file}': {str(e)}."
                if e.doc and e.lineno > 0 and e.colno > 0:
                    line_idx = e.lineno - 1
                    lines = e.doc.split("\n")
                    ctx_line_count = 3
                    ctx_start = max(0, line_idx - ctx_line_count)
                    ctx_end = min(line_idx + ctx_line_count, len(lines))
                    erroneous_lines = lines[ctx_start:ctx_end]
                    erroneous_lines.insert(line_idx - ctx_start + 1, "-" * (e.colno - 1) + "^ Error is here")
                    msg += " Lines containing the error:\n\n{}\n\n".format("\n".join(erroneous_lines))
                msg += f"The complete track has been written to '{tmp.name}' for diagnosis."
                raise TrackSyntaxError(msg)
            except Exception as e:
                self.logger.exception("Could not load [%s].", track_spec_file)
                msg = f"Could not load '{track_spec_file}'. The complete track has been written to '{tmp.name}' for diagnosis."
                raise TrackSyntaxError(msg, e)

        # check the track version before even attempting to validate the JSON format to avoid bogus errors.
        raw_version = track_spec.get("version", TrackFileReader.MAXIMUM_SUPPORTED_TRACK_VERSION)
        try:
            track_version = int(raw_version)
        except ValueError:
            raise exceptions.InvalidSyntax("version identifier for track %s must be numeric but was [%s]" % (track_name, str(raw_version)))

        if TrackFileReader.MINIMUM_SUPPORTED_TRACK_VERSION > track_version:
            raise exceptions.RallyError(
                "Track {} is on version {} but needs to be updated at least to version {} to work with the "
                "current version of Rally.".format(track_name, track_version, TrackFileReader.MINIMUM_SUPPORTED_TRACK_VERSION)
            )
        if TrackFileReader.MAXIMUM_SUPPORTED_TRACK_VERSION < track_version:
            raise exceptions.RallyError(
                "Track {} requires a newer version of Rally. Please upgrade Rally (supported track version: {}, "
                "required track version: {}).".format(track_name, TrackFileReader.MAXIMUM_SUPPORTED_TRACK_VERSION, track_version)
            )

        try:
            jsonschema.validate(track_spec, self.track_schema)
        except jsonschema.exceptions.ValidationError as ve:
            raise TrackSyntaxError(
                "Track '{}' is invalid.\n\nError details: {}\nInstance: {}\nPath: {}\nSchema path: {}".format(
                    track_name, ve.message, json.dumps(ve.instance, indent=4, sort_keys=True), ve.absolute_path, ve.absolute_schema_path
                )
            )

        current_track = self.read_track(track_name, track_spec, mapping_dir, track_spec_file)

        internal_user_defined_track_params = self.complete_track_params.internal_user_defined_track_params()
        if len(internal_user_defined_track_params) > 0:
            params_list = ",".join(opts.double_quoted_list_of(sorted(internal_user_defined_track_params)))
            err_msg = f"Some of your track parameter(s) {params_list} are defined by Rally and cannot be modified.\n"

            self.logger.critical(err_msg)
            # also dump the message on the console
            console.println(err_msg)
            raise exceptions.TrackConfigError(f"Reserved track parameters {sorted(internal_user_defined_track_params)}.")

        unused_user_defined_track_params = self.complete_track_params.unused_user_defined_track_params()
        if len(unused_user_defined_track_params) > 0:
            err_msg = (
                "Some of your track parameter(s) {} are not used by this track; perhaps you intend to use {} instead.\n\n"
                "All track parameters you provided are:\n"
                "{}\n\n"
                "All parameters exposed by this track:\n"
                "{}".format(
                    ",".join(opts.double_quoted_list_of(sorted(unused_user_defined_track_params))),
                    ",".join(
                        opts.double_quoted_list_of(
                            sorted(
                                opts.make_list_of_close_matches(
                                    unused_user_defined_track_params, self.complete_track_params.track_defined_params
                                )
                            )
                        )
                    ),
                    "\n".join(opts.bulleted_list_of(sorted(list(self.track_params.keys())))),
                    "\n".join(opts.bulleted_list_of(self.complete_track_params.sorted_track_defined_params)),
                )
            )

            self.logger.critical(err_msg)
            # also dump the message on the console
            console.println(err_msg)
            raise exceptions.TrackConfigError(f"Unused track parameters {sorted(unused_user_defined_track_params)}.")
        return current_track