Esempio n. 1
0
def do_action(params):
    f = Forcheck(params["files"],
                 fortran_standard=params["standard"],
                 emulate_compiler=params["emulation"],
                 free_format=params["free_format"],
                 extra_opts=params["extra_opts"])

    if params["pretend"]:
        print " ".join(f.get_command())
        sys.exit(0)

    # run forcheck
    f.run()
    forcheck_output = f.get_tmp_filename()  # file deleted by f.__del__()

    # parse
    parser = ForcheckParser(forcheck_output, ignore_list=params["ignore_list"])

    # result state
    state = parser.state
    state.run_data = f.get_run_data()

    # generate output
    writer = ResultWriter(parser.state, params["outdir"])
    writer.run()

    p_info("\nAll done. View '%s/index.html' for results." % params["outdir"])
Esempio n. 2
0
    def run(self):
        p_info("\nWriting HTML output to '%s'" % self.outdir)
        if self.outdir and not os.path.isdir(self.outdir):
            os.makedirs(self.outdir)

        self._gen_assets()
        self._gen_event_pages()
        self._gen_source_pages()
        self._gen_index()
Esempio n. 3
0
    def _gen_index(self):
        outfile = os.path.join(self.outdir, "index.html")
        p_info(" - Generating %s" % outfile)

        ctx = self.default_context.copy()
        ctx["event_summary"] = self.events
        ctx["FCKDIR"] = os.environ["FCKDIR"]
        ctx["FCKCNF"] = os.environ["FCKCNF"]
        ctx["FCKPWD"] = os.environ["FCKPWD"]
        if hasattr(self.state, "run_data"):
            ctx.update(self.state.run_data)

        with open(outfile, 'w') as f:
            f.write(render("index.html", ctx))
Esempio n. 4
0
    def _gen_source_pages(self):
        p_info(" - Generating marked-up source files")
        ctx = self.default_context.copy()
        for filename, event_instances in self.state.file_events.iteritems():
            ctx["code_block"], subpath, depth = self._format_source(filename)
            outfile = os.path.join(self.outdir, subpath)
            p_verbose("   -- %s" % outfile)

            ctx["to_root"] = "../" * depth
            ctx["filename"] = filename
            outdir = os.path.dirname(outfile)
            if outdir and not os.path.isdir(outdir):
                os.makedirs(outdir)

            with open(outfile, 'w') as f:
                f.write(render("code_source.html", ctx).encode('utf-8'))
Esempio n. 5
0
    def _gen_event_pages(self):
        depth = 1
        eventdir = os.path.join(self.outdir, "event")
        p_info(" - Generating event summaries")

        if not os.path.isdir(eventdir):
            os.makedirs(eventdir)

        ctx = self.default_context.copy()
        ctx["to_root"] = "../" * depth
        for e in self.events:
            outfile = "%s/%s.html" % (eventdir, e.code.replace(' ', '_'))
            ctx["event"] = e
            ctx["event_instances"] = self.state.event_instances[e.code]
            with open(outfile, 'w') as f:
                f.write(render("event.html", ctx))
Esempio n. 6
0
    def __init__(self, input_files,
                 fortran_standard="95",
                 emulate_compiler="gfortran",
                 free_format=False, extra_opts=None):
        self.rc = None
        self.input_files = input_files
        self.extra_opts = extra_opts

        # create tempfile file for use as staging area for forcheck .lst file
        tmp_fd, self.tmpfile = mkstemp(suffix=".lst")
        os.close(tmp_fd)

        # The following are set by call to self._locate_forcheck()
        self.supported_emulators = []
        self.cnfdir = None
        self.forcheck_exe = None
        self.forcheck_version = None
        self._locate_forcheck()

        # we support only version 14.2 and above
        ver = self.get_version()

        # store layout format and language standard
        self.free_format = free_format
        if fortran_standard not in SUPPORTED_STANDARDS:
            raise CheckfortException("Unsupported Fortran standard. "
                                     "Possible options: "
                                     + ", ".join(SUPPORTED_STANDARDS.keys()))
        self.fortran_standard = fortran_standard

        # select compiler emulation
        if emulate_compiler not in self.supported_emulators:
            raise CheckfortException("Unsuppoted compiler emulation. "
                                     "Possible options: "
                                     + ", ".join(self.supported_emulators))
        self.emulate_compiler = emulate_compiler
        os.environ["FCKCNF"] = os.path.join(self.cnfdir,
                                            "%s.cnf" % emulate_compiler)
        p_info(" - compiler emilation: %s" % emulate_compiler)
Esempio n. 7
0
 def run(self):
     out = "forcheck.log"
     p_info("\nRunning forcheck (stdout written to %s)" % out)
     with open(out, "w") as fout:
         # use pexpect.spawn instead of subprocess.Popen so we can get
         # real-time output from forcheck (Popen is subject to stdout being
         # buffered when redirected to PIPE).
         cmd = self.get_command()
         child = pexpect.spawn(cmd[0], args=cmd[1:], logfile=fout)
         self._store_prev = ("", "")
         while True:
             try:
                 child.expect('\n')
                 self._report_runtime_message(child.before)
             except pexpect.EOF:
                 break
         child.close()
         self.rc = child.exitstatus
     try:
         p_info("\nDONE. (rc=%d, %s)" % (self.rc, EXIT_CODES[self.rc]))
     except KeyError:
         p_error("FAILED (rc=%d). See %s for details" % (self.rc, out))
Esempio n. 8
0
    def _report_runtime_message(self, line):
        """Selectively print content from forcheck runtime output"""
        line = line.strip()

        if line.startswith("-- "):
            if line.startswith("-- file: "):
                p_verbose("    - %s" % line.split(None, 2)[2])
            elif not line.startswith("-- commandline") and \
                    not line.startswith("-- messages presented"):
                p_verbose(line)
            if not verbose_enabled():
                p_info(".", "")

        elif line.startswith("FCK-- "):
            err = line.split(None, 1)[1]
            culprit, filename = self._store_prev
            if not filename.startswith("("):
                filename = ""  # not specified
            p_warn("%s - %s %s\n" % (err, culprit, filename))

        elif not verbose_enabled() and line.startswith("- file"):
            p_info(".", "")

        self._store_prev = (line, self._store_prev[0])
Esempio n. 9
0
    def _parse(self):
        p_info("\nParsing forcheck listfile")
        if self.state.ignore_list:
            p_info("(ignoring the following forcheck events: "
                   "%s)" % ", ".join(str(x) for x in self.state.ignore_list))

        stages = iter((
            {"name": "file events",
             "end_marker": "global program analysis:",
             "parser": FileEvent(self.state)},
            {"name": "global events",
             "end_marker": "program_units and procedures analysed:",
             "parser": GlobalEvent(self.state)},
            {"name": "program units",
             # "end_marker": "*END OF ANALYSIS*"  # no longer appear in >14.3
             "end_marker": "messages presented:",
             "parser": None},
            {"name": "forcheck summary",
             "end_marker": None,
             "parser": SummaryEvent(self.state)},
        ))

        lines = ("", "", "")  # (current, previous, previous-1)
        stage = stages.next()
        p_info(" - Parsing %s" % stage["name"])

        def forward_to_content(file_iterator):
            """
            Forwards file iterator the the actual content, then returns
            the source file addressed by forcheck output page
            """
            # each new page starts with a header
            line = next(file_iterator)
            assert line.startswith("FORCHECK"), "Unexpected listfile format"

            # this is followed by "(options...) target_file" if the output is
            # file specific
            line = next(file_iterator)
            if line.strip():
                target_file = line.rsplit(None, 1)[-1]
                line = next(file_iterator)  # following line should be blank
                assert not line.strip(), "Unexpected listfile format"
            else:
                target_file = None
            return target_file

        with open(self.listfile) as f:
            target_file = forward_to_content(f)
            for L in f:
                if L.startswith("\f"):  # new page. forward to content
                    target_file = forward_to_content(f)
                    continue
                lines = (L.strip(), lines[0], lines[1])  # shift
                if lines[0] == stage["end_marker"]:
                    stage = stages.next()
                    p_info(" - Parsing %s" % stage["name"])
                elif stage["parser"]:  # if event has a parser
                    stage["parser"].slurp(target_file, *lines)

        if self.state.debug_required:
            import shutil
            listfile_out = "forcheck_listfile.debug"
            shutil.copy(self.listfile, listfile_out)
            p_debug(
                "There appears to be a problem in the parsing. \n"
                " Forcheck results written to %s. \n"
                " Please send the file and the checkfort version info\n"
                "    to the checkfort devs for further investigation"
                % (listfile_out, ))
        else:
            p_verbose("Parse successful")
Esempio n. 10
0
    def _locate_forcheck(self):
        """
        Detect required environment variables (FCKDIR, FCKCNF).

        From those values, locate forchk binary and detects list of supported
        compiler emulators.

        sets self.cnfdir, self.forcheck_exe and self.supported_emulators
        """
        p_info("\nLocating forcheck")

        if "FCKPWD" not in os.environ:
            raise CheckfortException("FCKPWD environment var not set")

        try:
            fdir = os.environ["FCKDIR"]
        except KeyError:
            raise CheckfortException("FCKDIR environment var not set")

        # locate exe
        candidates = map(lambda x: os.path.join(fdir, x, "forchk"),
                            ("bin", "."))
        try:
            found = (x for x in candidates if os.path.isfile(x)).next()
        except StopIteration:
            raise CheckfortException("Could not find 'forchk' binary")
        self.forcheck_exe = os.path.realpath(os.path.join(fdir, found))

        # locate g95.cnf and assume all cnf files are in the same dir
        candidates = map(lambda x: os.path.join(fdir, x, "g95.cnf"),
                            ("share/forcheck", "."))
        try:
            found = (x for x in candidates if os.path.isfile(x)).next()
        except StopIteration:
            raise CheckfortException("Could not find '*.cnf' files")
        self.cnfdir = os.path.dirname(os.path.join(fdir, found))

        # detect list of supported emulators
        self.supported_emulators = [x[:-4] for x in sieve(self.cnfdir,
                                                          "*.cnf")]

        # guess version number by doing a trial run of forchk
        try:
            child = subprocess.Popen([self.forcheck_exe, "-batch"],
                                        stdout=subprocess.PIPE,
                                        stderr=subprocess.PIPE)
        except:
            raise CheckfortException("Could not run " + self.forcheck_exe)

        # extract version string from output header
        first_line = child.communicate()[0].split("\n", 1)[0]
        last_col = first_line.rsplit(None, 1)[1]
        try:
            ver = re.match(r"V(\d+)\.(\d+)\.(\d+)", last_col).groups()
            self.forcheck_version = map(int, ver)
        except AttributeError:
            raise CheckfortException(
                self.forcheck_exe + " not producing expected output")

        p_info(" - install dir: %s" % fdir)
        p_info(" - executable: %s" % self.forcheck_exe)
        p_info(" - version: %s" % ".".join(str(v)
                                                 for v in self.get_version()))

        # compare min version
        min_ver = tuple(int(x) for x in MIN_VESION.split("."))
        if tuple(self.forcheck_version[:2]) < min_ver[:2]:
            p_error("Unsupported Forcheck version "
                    "(version >=%s expected)." % MIN_VESION)
Esempio n. 11
0
 def _gen_assets(self):
     outfile = os.path.join(self.outdir, "style.css")
     p_info(" - Generating %s" % outfile)
     with open(outfile, 'w') as f:
         f.write(render("style.css"))
         f.write(HtmlFormatter(**self.fmt_args).get_style_defs())
Esempio n. 12
0
def main():
    o, a = parse_options()

    cleaned = {}  # store validated input options
    cleaned["outdir"] = o.outdir
    cleaned["pretend"] = bool(o.pretend)
    cleaned["extra_opts"] = shlex.split(o.extra_opts or "")

    # --compiler-emulation can only be checked once Forcheck is found.
    # Accept anything for now
    cleaned["emulation"] = o.emulation

    # Set log level
    if o.quiet or cleaned["pretend"]:
        set_silent_mode()
    elif o.verbose:
        set_verbose_mode()
    if o.debug:
        set_debug_mode()

    # Once output verbosity set, we can print the output header
    p_info("%s" % header)

    # check allowed standards
    if o.standard not in supported_standards:
        p_error("Unsupported fortran standard (%s). Options: %s"
                % (o.standard, ", ".join(supported_standards)))
    else:
        cleaned["standard"] = o.standard

    # deal with optional --free-form
    if o.free_form:
        if cleaned["standard"] == '77':
            p_warn("Fortran 77 does not support free format. Ignoring "
                   "--free-form (-f) option.")
            o.free_form = False
    cleaned["free_format"] = bool(o.free_form)

    # check --ignore-err-codes (must be comma separated numeric codes)
    try:
        cleaned["ignore_list"] = list(set(int(x) for x in o.ignore.split(",")
                                                     if x.strip()))
    except ValueError:
        p_error("Invalid value for --ignore-err-codes (-i). "
                "Expecting comma-separated list of numeric values")

    # read target files form positional args and --input-file option
    targets = a[:]  # get targets from arguments
    if o.input_file:  # get targets from file specified with --input-file
        try:
            targets.extend(InputFileReader(o.input_file).get_entries())
        except IOError:
            p_error("Input file not readable: %s" % o.input_file)
    if not targets:
        p_error("No inputs provided.")

    # file extensions to search for
    if o.extensions:
        ext_list = [x.strip() for x in o.extensions.split(",")]
    else:
        ext_list = default_extensions

    # search and validate target files
    if any(os.path.isdir(x) for x in targets):
        p_info("Searching directories for files with the following "
                  "extensions : %s" % " ".join("*.%s" % x for x in ext_list))
    try:
        filelist = FileList(targets,  ext_list)
    except CheckfortException, e:
        p_error(e)