<commit_before>__author__ = 'kevin'

import argparse

from attacksurfacemeter import CallGraph
from loaders import CflowLoader, GprofLoader
from formatters import TxtFormatter, XmlFormatter, JsonFormatter, HtmlFormatter


def main():

    formatters = {
        'txt': TxtFormatter,
        'xml': XmlFormatter,
        'json': JsonFormatter,
        'html': HtmlFormatter
    }

    loaders = {
        'cflow': CflowLoader,
        'gprof': GprofLoader
    }

    args = parse_args()

    if args.tool == "all":
        # TODO: Maybe it would be useful to have some sort of factory method here because
        # of different constructor signatures for different loaders. I.e. gprof doesn't
        # support a reverse option so its not necessary to send it as a parameter.
        cflow_loader = loaders['cflow'](args.cflowfile, args.reverse)
        gprof_loader = loaders['gprof'](args.gproffile, args.reverse)

        call_graph = CallGraph.from_merge(CallGraph.from_loader(cflow_loader),
                                          CallGraph.from_loader(gprof_loader))
    else:
        if_not_none = lambda arg: arg if arg is not None else args.source

        input_file = {
            'cflow': if_not_none(args.cflowfile),
            'gprof': if_not_none(args.gproffile)
        }

        loader = loaders[args.tool](input_file[args.tool], args.reverse)

        call_graph = CallGraph.from_loader(loader)

    formatter = formatters[args.format](call_graph)

    if args.summary:
        print(formatter.write_summary())
    else:
        print(formatter.write_output())


def parse_args():
    """
        Provides a command line interface for the attack surface meter.

        Defines all the positional and optional arguments along with their respective valid values
        for the command line interface and returns all the received arguments as an object.

        Returns:
            An object that contains all the provided command line arguments.
    """
    parser = argparse.ArgumentParser(
        description="Analyzes a software's source code and reports various metrics related to it's attack surface.")

    parser.add_argument("-src", "--source",
                        help="Can be either the root directory of the source code to analyze or the text file that "
                             "contains the raw call graph information. Use this when specifying only one call graph "
                             "generation tool with the -t (--tool) option.")
    parser.add_argument("-cf", "--cflowfile",
                        help="The file containing cflow's output.")
    parser.add_argument("-gf", "--gproffile",
                        help="The file containing gprof's output")
    parser.add_argument("-t", "--tool", choices=["cflow", "gprof", "all"], default="cflow",
                        help="The call graph generation software to use. Choose both to use both tools.")
    parser.add_argument("-r", "--reverse", action="store_true",
                        help="When using cflow for call graph generation, use the reverse algorithm.")
    parser.add_argument("-f", "--format", choices=["txt", "html", "xml", "json"], default="txt",
                        help="Output format of the calculated metrics report.")
    parser.add_argument("-s", "--summary", action="store_true",
                        help="Print only a summary of the report.")

    return parser.parse_args()


if __name__ == '__main__':
    main()<commit_msg>Added a -e command line argument to show the parsing errors list along with the attack surface report.<commit_after>__author__ = 'kevin'

import argparse

from attacksurfacemeter import CallGraph
from loaders import CflowLoader, GprofLoader
from formatters import TxtFormatter, XmlFormatter, JsonFormatter, HtmlFormatter


def main():

    formatters = {
        'txt': TxtFormatter,
        'xml': XmlFormatter,
        'json': JsonFormatter,
        'html': HtmlFormatter
    }

    loaders = {
        'cflow': CflowLoader,
        'gprof': GprofLoader
    }

    args = parse_args()

    if args.tool == "all":
        # TODO: Maybe it would be useful to have some sort of factory method here because
        # of different constructor signatures for different loaders. I.e. gprof doesn't
        # support a reverse option so its not necessary to send it as a parameter.
        cflow_loader = loaders['cflow'](args.cflowfile, args.reverse)
        gprof_loader = loaders['gprof'](args.gproffile, args.reverse)

        call_graph = CallGraph.from_merge(CallGraph.from_loader(cflow_loader),
                                          CallGraph.from_loader(gprof_loader))
    else:
        if_not_none = lambda arg: arg if arg is not None else args.source

        input_file = {
            'cflow': if_not_none(args.cflowfile),
            'gprof': if_not_none(args.gproffile)
        }

        loader = loaders[args.tool](input_file[args.tool], args.reverse)

        call_graph = CallGraph.from_loader(loader)

    formatter = formatters[args.format](call_graph)

    if args.summary:
        print(formatter.write_summary())
    else:
        print(formatter.write_output())

    if args.show_errors:
        for m in call_graph.errors:
            print(m)


def parse_args():
    """
        Provides a command line interface for the attack surface meter.

        Defines all the positional and optional arguments along with their respective valid values
        for the command line interface and returns all the received arguments as an object.

        Returns:
            An object that contains all the provided command line arguments.
    """
    parser = argparse.ArgumentParser(
        description="Analyzes a software's source code and reports various metrics related to it's attack surface.")

    parser.add_argument("-src", "--source",
                        help="Can be either the root directory of the source code to analyze or the text file that "
                             "contains the raw call graph information. Use this when specifying only one call graph "
                             "generation tool with the -t (--tool) option.")
    parser.add_argument("-cf", "--cflowfile",
                        help="The file containing cflow's output.")
    parser.add_argument("-gf", "--gproffile",
                        help="The file containing gprof's output")
    parser.add_argument("-t", "--tool", choices=["cflow", "gprof", "all"], default="cflow",
                        help="The call graph generation software to use. Choose both to use both tools.")
    parser.add_argument("-r", "--reverse", action="store_true",
                        help="When using cflow for call graph generation, use the reverse algorithm.")
    parser.add_argument("-f", "--format", choices=["txt", "html", "xml", "json"], default="txt",
                        help="Output format of the calculated metrics report.")
    parser.add_argument("-s", "--summary", action="store_true",
                        help="Print only a summary of the report.")
    parser.add_argument("-e", "--show_errors", action="store_true",
                        help="Print all parsing error messages at the end of the report")

    return parser.parse_args()


if __name__ == '__main__':
    main()
{'fraction_non_alphanumeric': 0.09851607584501236, 'fraction_numerical': 0.0, 'mean_word_length': 2.459600760456274, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3913278', 'n_tokens_mistral': 1916, 'n_tokens_neox': 1846, 'n_words': 639}