Пример #1
0
def add_arguments_to_parser(parser):
    """
    Add the subcommand's arguments to the given argparse.ArgumentParser.
    """

    parser.add_argument('input',
                        type=str,
                        nargs='*',
                        metavar='file/folder',
                        default=os.path.join(util.get_default_workspace(),
                                             'reports'),
                        help="The analysis result files and/or folders "
                             "containing analysis results which should be "
                             "parsed and printed.")

    parser.add_argument('-t', '--type', '--input-format',
                        dest="input_format",
                        required=False,
                        choices=['plist'],
                        default='plist',
                        help="Specify the format the analysis results were "
                             "created as.")

    parser.add_argument('--suppress',
                        type=str,
                        dest="suppress",
                        default=argparse.SUPPRESS,
                        required=False,
                        help="Path of the suppress file to use. Records in "
                             "the suppress file are used to suppress the "
                             "display of certain results when parsing the "
                             "analyses' report. (Reports to an analysis "
                             "result can also be suppressed in the source "
                             "code -- please consult the manual on how to "
                             "do so.) NOTE: The suppress file relies on the "
                             "\"bug identifier\" generated by the analyzers "
                             "which is experimental, take care when relying "
                             "on it.")

    parser.add_argument('--export-source-suppress',
                        dest="create_suppress",
                        action="store_true",
                        required=False,
                        default=argparse.SUPPRESS,
                        help="Write suppress data from the suppression "
                             "annotations found in the source files that were "
                             "analyzed earlier that created the results. "
                             "The suppression information will be written "
                             "to the parameter of '--suppress'.")

    parser.add_argument('--print-steps',
                        dest="print_steps",
                        action="store_true",
                        required=False,
                        default=argparse.SUPPRESS,
                        help="Print the steps the analyzers took in finding "
                             "the reported defect.")

    add_verbose_arguments(parser)
    parser.set_defaults(func=main)
Пример #2
0
    def from_cmdline_args(args, migration_root, env=None):
        """
        Normally only this method is called form outside of this module in
        order to instance the proper server implementation.

        Parameters:
            args: the command line arguments from CodeChecker.py
            migration_root: path to the database migration scripts
            env: a run environment dictionary.
        """

        if not host_check.check_sql_driver(args.postgresql):
            LOG.error("The selected SQL driver is not available.")
            sys.exit(1)

        if args.postgresql:
            LOG.debug("Using PostgreSQLServer")
            if 'workspace' in args:
                data_url = os.path.join(args.workspace, 'pgsql_data')
            else:
                # TODO: This will be refactored eventually so that
                # CodeChecker is no longer bringing up a postgres database...
                # It is an external dependency, it is an external
                # responbitility. Until then, use the default folder now
                # for the new commands who no longer define workspace.
                if 'dbdatadir' in args:
                    workspace = args.dbdatadir
                else:
                    workspace = util.get_default_workspace()
                data_url = os.path.join(workspace, 'pgsql_data')
            return PostgreSQLServer(data_url,
                                    migration_root,
                                    args.dbaddress,
                                    args.dbport,
                                    args.dbusername,
                                    args.dbname,
                                    run_env=env)
        else:
            LOG.debug("Using SQLiteDatabase")
            if 'workspace' in args:
                data_file = os.path.join(args.workspace, 'codechecker.sqlite')
            else:
                data_file = args.sqlite
            return SQLiteDatabase(data_file, migration_root, run_env=env)
Пример #3
0
def add_arguments_to_parser(parser):
    """
    Add the subcommand's arguments to the given argparse.ArgumentParser.
    """

    parser.add_argument('logfile',
                        type=str,
                        nargs='+',
                        help="Path to the JSON compilation command database "
                             "files which were created during the build. "
                             "The analyzers will check only the files "
                             "registered in these build databases.")

    parser.add_argument('-j', '--jobs',
                        type=int,
                        dest="jobs",
                        required=False,
                        default=1,
                        help="Number of threads to use in analysis. More "
                             "threads mean faster analysis at the cost of "
                             "using more memory.")

    parser.add_argument('-i', '--ignore', '--skip',
                        dest="skipfile",
                        required=False,
                        default=argparse.SUPPRESS,
                        help="Path to the Skipfile dictating which project "
                             "files should be omitted from analysis. Please "
                             "consult the User guide on how a Skipfile "
                             "should be laid out.")

    parser.add_argument('-o', '--output',
                        dest="output_path",
                        required=False,
                        default=os.path.join(util.get_default_workspace(),
                                             'reports'),
                        help="Store the analysis output in the given folder.")

    parser.add_argument('-t', '--type', '--output-format',
                        dest="output_format",
                        required=False,
                        choices=['plist'],
                        default='plist',
                        help="Specify the format the analysis results should "
                             "use.")

    parser.add_argument('-n', '--name',
                        dest="name",
                        required=False,
                        default=argparse.SUPPRESS,
                        help="Annotate the ran analysis with a custom name in "
                             "the created metadata file.")

    analyzer_opts = parser.add_argument_group("analyzer arguments")

    analyzer_opts.add_argument('--analyzers',
                               nargs='+',
                               dest='analyzers',
                               metavar='ANALYZER',
                               required=False,
                               choices=analyzer_types.supported_analyzers,
                               default=argparse.SUPPRESS,
                               help="Run analysis only with the analyzers "
                                    "specified. Currently supported analyzers "
                                    "are: " +
                                    ', '.join(analyzer_types.
                                              supported_analyzers) + ".")

    analyzer_opts.add_argument('--add-compiler-defaults',
                               action='store_true',
                               default=False,
                               required=False,
                               help="Retrieve compiler-specific configuration "
                                    "from the compilers themselves, and use "
                                    "them with Clang. This is used when the "
                                    "compiler on the system is special, e.g. "
                                    "when doing cross-compilation.")

    analyzer_opts.add_argument('--saargs',
                               dest="clangsa_args_cfg_file",
                               required=False,
                               default=argparse.SUPPRESS,
                               help="File containing argument which will be "
                                    "forwarded verbatim for the Clang Static "
                                    "Analyzer.")

    analyzer_opts.add_argument('--tidyargs',
                               dest="tidy_args_cfg_file",
                               required=False,
                               default=argparse.SUPPRESS,
                               help="File containing argument which will be "
                                    "forwarded verbatim for Clang-Tidy.")

    checkers_opts = parser.add_argument_group(
        "checker configuration",
        "See 'codechecker-checkers' for the list of available checkers. "
        "You can fine-tune which checkers to use in the analysis by setting "
        "the enabled and disabled flags starting from the bigger groups "
        "and going inwards, e.g. '-e core -d core.uninitialized -e "
        "core.uninitialized.Assign' will enable every 'core' checker, but "
        "only 'core.uninitialized.Assign' from the 'core.uninitialized' "
        "group. Please consult the manual for details. Disabling certain "
        "checkers - such as the 'core' group - is unsupported by the LLVM/"
        "Clang community, and thus discouraged.")

    checkers_opts.add_argument('-e', '--enable',
                               dest="enable",
                               metavar='checker/checker-group',
                               default=argparse.SUPPRESS,
                               action=OrderedCheckersAction,
                               help="Set a checker (or checker group) "
                                    "to BE USED in the analysis.")

    checkers_opts.add_argument('-d', '--disable',
                               dest="disable",
                               metavar='checker/checker-group',
                               default=argparse.SUPPRESS,
                               action=OrderedCheckersAction,
                               help="Set a checker (or checker group) "
                                    "to BE PROHIBITED from use in the "
                                    "analysis.")

    checkers_opts.add_argument('--enable-all',
                               dest="enable_all",
                               action='store_true',
                               required=False,
                               default=argparse.SUPPRESS,
                               help="Force the running analyzers to use "
                                    "almost every checker available. The "
                                    "checker groups 'alpha.', 'debug.' and "
                                    "'osx.' (on Linux) are NOT enabled "
                                    "automatically and must be EXPLICITLY "
                                    "specified. WARNING! Enabling all "
                                    "checkers might result in the analysis "
                                    "losing precision and stability, and "
                                    "could even result in a total failure of "
                                    "the analysis. USE WISELY AND AT YOUR "
                                    "OWN RISK!")

    add_verbose_arguments(parser)
    parser.set_defaults(func=main)
Пример #4
0
def add_arguments_to_parser(parser):
    """
    Add the subcommand's arguments to the given argparse.ArgumentParser.
    """

    # TODO: --workspace is an outdated concept in 'store'. Later on,
    # it shall be deprecated, as changes to db_handler commence.
    parser.add_argument('-w', '--workspace',
                        type=str,
                        dest="workspace",
                        default=util.get_default_workspace(),
                        required=False,
                        help="Directory where CodeChecker can store analysis "
                             "result related data, such as the database. "
                             "(Cannot be specified at the same time with "
                             "'--sqlite' or '--config-directory'.)")

    parser.add_argument('-f', '--config-directory',
                        type=str,
                        dest="config_directory",
                        default=util.get_default_workspace(),
                        required=False,
                        help="Directory where CodeChecker server should read "
                             "server-specific configuration (such as "
                             "authentication settings, SSL certificate"
                             " (cert.pem) and key (key.pem)) from.")

    parser.add_argument('--host',
                        type=str,
                        dest="listen_address",
                        default="localhost",
                        required=False,
                        help="The IP address or hostname of the server on "
                             "which it should listen for connections.")

    # TODO: -v/--view-port is too verbose. The server's -p/--port is used
    # symmetrically in 'CodeChecker cmd' anyways.
    parser.add_argument('-v', '--view-port',  # TODO: <- Deprecate and remove.
                        '-p', '--port',
                        type=int,
                        dest="view_port",
                        metavar='PORT',
                        default=8001,
                        required=False,
                        help="The port which will be used as listen port for "
                             "the server.")

    # TODO: This should be removed later on, in favour of --host.
    parser.add_argument('--not-host-only',
                        dest="not_host_only",
                        action="store_true",
                        required=False,
                        help="If specified, storing and viewing the results "
                             "will be possible not only by browsers and "
                             "clients running locally, but to everyone, who "
                             "can access the server over the Internet. "
                             "(Equivalent to specifying '--host \"\"'.)")

    parser.add_argument('--skip-db-cleanup',
                        dest="skip_db_cleanup",
                        action='store_true',
                        default=False,
                        required=False,
                        help="Skip performing cleanup jobs on the database "
                             "like removing unused files.")

    dbmodes = parser.add_argument_group("configuration database arguments")

    dbmodes = dbmodes.add_mutually_exclusive_group(required=False)

    dbmodes.add_argument('--sqlite',
                         type=str,
                         dest="sqlite",
                         metavar='SQLITE_FILE',
                         default=os.path.join(
                             '<CONFIG_DIRECTORY>',
                             "config.sqlite"),
                         required=False,
                         help="Path of the SQLite database file to use.")

    dbmodes.add_argument('--postgresql',
                         dest="postgresql",
                         action='store_true',
                         required=False,
                         default=argparse.SUPPRESS,
                         help="Specifies that a PostgreSQL database is to be "
                              "used instead of SQLite. See the \"PostgreSQL "
                              "arguments\" section on how to configure the "
                              "database connection.")

    pgsql = parser.add_argument_group("PostgreSQL arguments",
                                      "Values of these arguments are ignored, "
                                      "unless '--postgresql' is specified!")

    # TODO: --dbSOMETHING arguments are kept to not break interface from
    # old command. Database using commands such as "CodeChecker store" no
    # longer supports these --- it would be ideal to break and remove args
    # with this style and only keep --db-SOMETHING.
    pgsql.add_argument('--dbaddress', '--db-host',
                       type=str,
                       dest="dbaddress",
                       default="localhost",
                       required=False,
                       help="Database server address.")

    pgsql.add_argument('--dbport', '--db-port',
                       type=int,
                       dest="dbport",
                       default=5432,
                       required=False,
                       help="Database server port.")

    pgsql.add_argument('--dbusername', '--db-username',
                       type=str,
                       dest="dbusername",
                       default='codechecker',
                       required=False,
                       help="Username to use for connection.")

    pgsql.add_argument('--dbname', '--db-name',
                       type=str,
                       dest="dbname",
                       default="config",
                       required=False,
                       help="Name of the database to use.")

    root_account = parser.add_argument_group(
        "root account arguments",
        "Servers automatically create a root user to access the server's "
        "configuration via the clients. This user is created at first start "
        "and saved in the CONFIG_DIRECTORY, and the credentials are printed "
        "to the server's standard output. The plaintext credentials are "
        "NEVER accessible again.")

    root_account.add_argument('--reset-root',
                              dest="reset_root",
                              action='store_true',
                              default=argparse.SUPPRESS,
                              required=False,
                              help="Force the server to recreate the master "
                                   "superuser (root) account name and "
                                   "password. The previous credentials will "
                                   "be invalidated, and the new ones will be "
                                   "printed to the standard output.")

    root_account.add_argument('--force-authentication',
                              dest="force_auth",
                              action='store_true',
                              default=argparse.SUPPRESS,
                              required=False,
                              help="Force the server to run in "
                                   "authentication requiring mode, despite "
                                   "the configuration value in "
                                   "'server_config.json'. This is needed "
                                   "if you need to edit the product "
                                   "configuration of a server that would not "
                                   "require authentication otherwise.")

    instance_mgmnt = parser.add_argument_group("running server management")

    instance_mgmnt = instance_mgmnt. \
        add_mutually_exclusive_group(required=False)

    instance_mgmnt.add_argument('-l', '--list',
                                dest="list",
                                action='store_true',
                                default=argparse.SUPPRESS,
                                required=False,
                                help="List the servers that has been started "
                                     "by you.")

    instance_mgmnt.add_argument('-r', '--reload',
                                dest="reload",
                                action='store_true',
                                default=argparse.SUPPRESS,
                                required=False,
                                help="Sends the CodeChecker server process a "
                                     "SIGHUP signal, causing it to reread "
                                     "it's configuration files.")

    # TODO: '-s' was removed from 'quickcheck', it shouldn't be here either?
    instance_mgmnt.add_argument('-s', '--stop',
                                dest="stop",
                                action='store_true',
                                default=argparse.SUPPRESS,
                                required=False,
                                help="Stops the server associated with "
                                     "the given view-port and workspace.")

    instance_mgmnt.add_argument('--stop-all',
                                dest="stop_all",
                                action='store_true',
                                default=argparse.SUPPRESS,
                                required=False,
                                help="Stops all of your running CodeChecker "
                                     "server instances.")

    database_mgmnt = parser.add_argument_group(
            "Database management arguments.",
            """WARNING these commands needs to be called with the same
            workspace and configuration arguments as the server so the
            configuration database will be found which is required for the
            schema migration. Migration can be done without a running server
            but pay attention to use the same arguments which will be used to
            start the server.
            NOTE:
            Before migration it is advised to create a full a backup of
            the product databases.
            """)

    database_mgmnt = database_mgmnt. \
        add_mutually_exclusive_group(required=False)

    database_mgmnt.add_argument('--db-status',
                                type=str,
                                dest="status",
                                action='store',
                                default=argparse.SUPPRESS,
                                required=False,
                                help="Name of the product to get "
                                     "the database status for. "
                                     "Use 'all' to list the database "
                                     "statuses for all of the products.")

    database_mgmnt.add_argument('--db-upgrade-schema',
                                type=str,
                                dest='product_to_upgrade',
                                action='store',
                                default=argparse.SUPPRESS,
                                required=False,
                                help="Name of the product to upgrade to the "
                                     "latest database schema available in "
                                     "the package. Use 'all' to upgrade all "
                                     "of the products. "
                                     "NOTE: Before migration it is advised"
                                     " to create a full backup of "
                                     "the product databases.")

    database_mgmnt.add_argument('--db-force-upgrade',
                                dest='force_upgrade',
                                action='store_true',
                                default=argparse.SUPPRESS,
                                required=False,
                                help="Force the server to do database "
                                     "migration without user interaction. "
                                     "NOTE: Please use with caution and "
                                     "before automatic migration it is "
                                     "advised to create a full backup of the "
                                     "product databases.")

    logger.add_verbose_arguments(parser)

    def __handle(args):
        """Custom handler for 'server' so custom error messages can be
        printed without having to capture 'parser' in main."""

        def arg_match(options):
            return util.arg_match(options, sys.argv[1:])

        # See if there is a "PostgreSQL argument" specified in the invocation
        # without '--postgresql' being there. There is no way to distinguish
        # a default argument and a deliberately specified argument without
        # inspecting sys.argv.
        options = ['--dbaddress', '--dbport', '--dbusername', '--dbname',
                   '--db-host', '--db-port', '--db-username', '--db-name']
        psql_args_matching = arg_match(options)
        if any(psql_args_matching) and\
                'postgresql' not in args:
            first_matching_arg = next(iter([match for match
                                            in psql_args_matching]))
            parser.error("argument {0}: not allowed without "
                         "argument --postgresql".format(first_matching_arg))
            # parser.error() terminates with return code 2.

        # --not-host-only is a "shortcut", actually a to-be-deprecated
        # call which means '--host ""'.
        # TODO: Actually deprecate --not-host-only later on.
        options = ['--not-host-only', '--host']
        if set(arg_match(options)) == set(options):
            parser.error("argument --not-host-only: not allowed with "
                         "argument --host, as it is a shortcut to --host "
                         "\"\"")
        else:
            # Apply the shortcut.
            if len(arg_match(['--not-host-only'])) > 0:
                args.listen_address = ""  # Listen on every interface.

            # --not-host-only is just a shortcut optstring, no actual use
            # is intended later on.
            delattr(args, 'not_host_only')

        # --workspace and --sqlite cannot be specified either, as
        # both point to a database location.
        options = ['--sqlite', '--workspace']
        options_short = ['--sqlite', '-w']
        if set(arg_match(options)) == set(options) or \
                set(arg_match(options_short)) == set(options_short):
            parser.error("argument --sqlite: not allowed with "
                         "argument --workspace")

        # --workspace and --config-directory also aren't allowed together now,
        # the latter one is expected to replace the earlier.
        options = ['--config-directory', '--workspace']
        options_short = ['--config-directory', '-w']
        if set(arg_match(options)) == set(options) or \
                set(arg_match(options_short)) == set(options_short):
            parser.error("argument --config-directory: not allowed with "
                         "argument --workspace")

        # If workspace is specified, sqlite is workspace/config.sqlite
        # and config_directory is the workspace directory.
        if len(arg_match(['--workspace', '-w'])) > 0:
            args.config_directory = args.workspace
            args.sqlite = os.path.join(args.workspace,
                                       'config.sqlite')
            setattr(args, 'dbdatadir', os.path.join(args.workspace,
                                                    'pgsql_data'))

        # Workspace should not exist as a Namespace key.
        delattr(args, 'workspace')

        if '<CONFIG_DIRECTORY>' in args.sqlite:
            # Replace the placeholder variable with the actual value.
            args.sqlite = args.sqlite.replace('<CONFIG_DIRECTORY>',
                                              args.config_directory)

        if 'postgresql' not in args:
            # Later called database modules need the argument to be actually
            # present, even though the default is suppressed in the optstring.
            setattr(args, 'postgresql', False)

            # This is not needed by the database starter as we are
            # running SQLite.
            if 'dbdatadir' in args:
                delattr(args, 'dbdatadir')
        else:
            # If --postgresql is given, --sqlite is useless.
            delattr(args, 'sqlite')

        # If everything is fine, do call the handler for the subcommand.
        main(args)

    parser.set_defaults(func=__handle)
Пример #5
0
def add_arguments_to_parser(parser):
    """
    Add the subcommand's arguments to the given argparse.ArgumentParser.
    """

    parser.add_argument('input',
                        type=str,
                        nargs='*',
                        metavar='file/folder',
                        default=os.path.join(util.get_default_workspace(),
                                             'reports'),
                        help="The analysis result files and/or folders "
                        "containing analysis results which should be "
                        "parsed and printed.")

    parser.add_argument('-t',
                        '--type',
                        '--input-format',
                        dest="input_format",
                        required=False,
                        choices=['plist'],
                        default='plist',
                        help="Specify the format the analysis results were "
                        "created as.")

    parser.add_argument('-n',
                        '--name',
                        type=str,
                        dest="name",
                        required=False,
                        default=argparse.SUPPRESS,
                        help="The name of the analysis run to use in storing "
                        "the reports to the database. If not specified, "
                        "the '--name' parameter given to 'codechecker-"
                        "analyze' will be used, if exists.")

    parser.add_argument('--tag',
                        type=str,
                        dest="tag",
                        required=False,
                        default=argparse.SUPPRESS,
                        help="A uniques identifier for this individual store "
                        "of results in the run's history.")

    parser.add_argument('--trim-path-prefix',
                        type=str,
                        nargs='*',
                        dest="trim_path_prefix",
                        required=False,
                        default=argparse.SUPPRESS,
                        help="Removes leading path from files which will be "
                        "stored. So if you have /a/b/c/x.cpp and "
                        "/a/b/c/y.cpp then by removing \"/a/b/\" prefix "
                        "will store files like c/x.cpp and c/y.cpp. "
                        "If multiple prefix is given, the longest match "
                        "will be removed.")

    parser.add_argument('-f',
                        '--force',
                        dest="force",
                        default=argparse.SUPPRESS,
                        action='store_true',
                        required=False,
                        help="Delete analysis results stored in the database "
                        "for the current analysis run's name and store "
                        "only the results reported in the 'input' files. "
                        "(By default, CodeChecker would keep reports "
                        "that were coming from files not affected by the "
                        "analysis, and only incrementally update defect "
                        "reports for source files that were analysed.)")

    server_args = parser.add_argument_group(
        "server arguments",
        "Specifies a 'CodeChecker server' instance which will be used to "
        "store the results. This server must be running and listening, and "
        "the given product must exist prior to the 'store' command being ran.")

    server_args.add_argument('--url',
                             type=str,
                             metavar='PRODUCT_URL',
                             dest="product_url",
                             default="localhost:8001/Default",
                             required=False,
                             help="The URL of the product to store the "
                             "results for, in the format of "
                             "'[http[s]://]host:port/Endpoint'.")

    logger.add_verbose_arguments(parser)
    parser.set_defaults(func=main)
Пример #6
0
def add_arguments_to_parser(parser):
    """
    Add the subcommand's arguments to the given argparse.ArgumentParser.
    """

    parser.add_argument('input',
                        type=str,
                        nargs='*',
                        metavar='file/folder',
                        default=os.path.join(util.get_default_workspace(),
                                             'reports'),
                        help="The analysis result files and/or folders "
                        "containing analysis results which should be "
                        "parsed and printed.")

    parser.add_argument('-t',
                        '--type',
                        '--input-format',
                        dest="input_format",
                        required=False,
                        choices=['plist'],
                        default='plist',
                        help="Specify the format the analysis results were "
                        "created as.")

    output_opts = parser.add_argument_group("export arguments")
    output_opts.add_argument('-e',
                             '--export',
                             dest="export",
                             required=False,
                             choices=['html'],
                             help="Specify extra output format type.")

    output_opts.add_argument('-o',
                             '--output',
                             dest="output_path",
                             help="Store the output in the given folder.")

    output_opts.add_argument('-c',
                             '--clean',
                             dest="clean",
                             required=False,
                             action='store_true',
                             default=argparse.SUPPRESS,
                             help="Delete output results stored in the output "
                             "directory. (By default, it would keep "
                             "output files and overwrites only those "
                             "that belongs to a plist file given by the "
                             "input argument.")

    parser.add_argument('--suppress',
                        type=str,
                        dest="suppress",
                        default=argparse.SUPPRESS,
                        required=False,
                        help="Path of the suppress file to use. Records in "
                        "the suppress file are used to suppress the "
                        "display of certain results when parsing the "
                        "analyses' report. (Reports to an analysis "
                        "result can also be suppressed in the source "
                        "code -- please consult the manual on how to "
                        "do so.) NOTE: The suppress file relies on the "
                        "\"bug identifier\" generated by the analyzers "
                        "which is experimental, take care when relying "
                        "on it.")

    parser.add_argument('--export-source-suppress',
                        dest="create_suppress",
                        action="store_true",
                        required=False,
                        default=argparse.SUPPRESS,
                        help="Write suppress data from the suppression "
                        "annotations found in the source files that were "
                        "analyzed earlier that created the results. "
                        "The suppression information will be written "
                        "to the parameter of '--suppress'.")

    parser.add_argument('--print-steps',
                        dest="print_steps",
                        action="store_true",
                        required=False,
                        default=argparse.SUPPRESS,
                        help="Print the steps the analyzers took in finding "
                        "the reported defect.")

    parser.add_argument('-i',
                        '--ignore',
                        '--skip',
                        dest="skipfile",
                        required=False,
                        default=argparse.SUPPRESS,
                        help="Path to the Skipfile dictating which project "
                        "files should be omitted from analysis. Please "
                        "consult the User guide on how a Skipfile "
                        "should be laid out.")

    logger.add_verbose_arguments(parser)

    def __handle(args):
        """Custom handler for 'parser' so custom error messages can be
        printed without having to capture 'parser' in main."""
        def arg_match(options):
            return util.arg_match(options, sys.argv[1:])

        # --export cannot be specified without --output.
        export = ['-e', '--export']
        output = ['-o', '--output']
        if any(arg_match(export)) and not any(arg_match(output)):
            parser.error("argument --export: not allowed without "
                         "argument --output")

        # If everything is fine, do call the handler for the subcommand.
        main(args)

    parser.set_defaults(func=__handle)
Пример #7
0
def add_arguments_to_parser(parser):
    """
    Add the subcommand's arguments to the given argparse.ArgumentParser.
    """

    # Some arguments were deprecated already in 'CodeChecker check'.
    parser.add_argument('--keep-tmp', action=DeprecatedOptionAction)

    parser.add_argument('-c', '--clean', action=DeprecatedOptionAction)

    parser.add_argument('--update', action=DeprecatedOptionAction)

    # In 'store', --name is not a required argument by argparse, as 'analyze'
    # can prepare a name, which is read after 'store' is started.
    # If the name is missing, the user is explicitly warned.
    # TODO: This should be an optional argument here too.
    parser.add_argument('-n',
                        '--name',
                        type=str,
                        dest="name",
                        required=True,
                        default=argparse.SUPPRESS,
                        help="The name of the analysis run to use in storing "
                        "the reports to the database. If not specified, "
                        "the '--name' parameter given to 'codechecker-"
                        "analyze' will be used, if exists.")

    # TODO: Workspace is no longer a concept in the new subcommands.
    parser.add_argument('-w',
                        '--workspace',
                        type=str,
                        default=util.get_default_workspace(),
                        dest="workspace",
                        help="Directory where CodeChecker can store analysis "
                        "related data, such as intermediate result files "
                        "and the database.")

    parser.add_argument('-f',
                        '--force',
                        dest="force",
                        default=False,
                        action='store_true',
                        required=False,
                        help="Delete analysis results stored in the database "
                        "for the current analysis run's name and store "
                        "only the results reported in the 'input' files. "
                        "(By default, CodeChecker would keep reports "
                        "that were coming from files not affected by the "
                        "analysis, and only incrementally update defect "
                        "reports for source files that were analysed.)")

    log_args = parser.add_argument_group(
        "log arguments",
        "Specify how the build information database should be obtained. You "
        "need to specify either an already existing log file, or a build "
        "command which will be used to generate a log file on the fly.")

    log_args.add_argument('-q',
                          '--quiet-build',
                          dest="quiet_build",
                          action='store_true',
                          default=False,
                          required=False,
                          help="Do not print the output of the build tool "
                          "into the output of this command.")

    log_args = log_args.add_mutually_exclusive_group(required=True)

    log_args.add_argument('-b',
                          '--build',
                          type=str,
                          dest="command",
                          default=argparse.SUPPRESS,
                          required=False,
                          help="Execute and record a build command. Build "
                          "commands can be simple calls to 'g++' or "
                          "'clang++' or 'make', but a more complex "
                          "command, or the call of a custom script file "
                          "is also supported.")

    log_args.add_argument('-l',
                          '--logfile',
                          type=str,
                          dest="logfile",
                          help="Use an already existing JSON compilation "
                          "command database file specified at this path.")

    analyzer_opts = parser.add_argument_group("analyzer arguments")
    analyzer_opts.add_argument('-j',
                               '--jobs',
                               type=int,
                               dest="jobs",
                               required=False,
                               default=1,
                               help="Number of threads to use in analysis. "
                               "More threads mean faster analysis at "
                               "the cost of using more memory.")

    # TODO: Analyze knows '--ignore' also for this.
    analyzer_opts.add_argument('-i',
                               '--skip',
                               dest="skipfile",
                               required=False,
                               default=argparse.SUPPRESS,
                               help="Path to the Skipfile dictating which "
                               "project files should be omitted from "
                               "analysis. Please consult the User guide "
                               "on how a Skipfile should be laid out.")

    analyzer_opts.add_argument(
        '--analyzers',
        nargs='+',
        dest='analyzers',
        metavar='ANALYZER',
        required=False,
        choices=analyzer_types.supported_analyzers,
        default=argparse.SUPPRESS,
        help="Run analysis only with the analyzers "
        "specified. Currently supported analyzers "
        "are: " + ', '.join(analyzer_types.supported_analyzers) + ".")

    analyzer_opts.add_argument('--add-compiler-defaults',
                               action='store_true',
                               default=False,
                               required=False,
                               help="Retrieve compiler-specific configuration "
                               "from the compilers themselves, and use "
                               "them with Clang. This is used when the "
                               "compiler on the system is special, e.g. "
                               "when doing cross-compilation.")

    analyzer_opts.add_argument('--saargs',
                               dest="clangsa_args_cfg_file",
                               required=False,
                               default=argparse.SUPPRESS,
                               help="File containing argument which will be "
                               "forwarded verbatim for the Clang Static "
                               "analyzer.")

    analyzer_opts.add_argument('--tidyargs',
                               dest="tidy_args_cfg_file",
                               required=False,
                               default=argparse.SUPPRESS,
                               help="File containing argument which will be "
                               "forwarded verbatim for the Clang-Tidy "
                               "analyzer.")

    checkers_opts = parser.add_argument_group(
        "checker configuration",
        "See 'codechecker-checkers' for the list of available checkers. "
        "You can fine-tune which checkers to use in the analysis by setting "
        "the enabled and disabled flags starting from the bigger groups "
        "and going inwards, e.g. '-e core -d core.uninitialized -e "
        "core.uninitialized.Assign' will enable every 'core' checker, but "
        "only 'core.uninitialized.Assign' from the 'core.uninitialized' "
        "group. Please consult the manual for details. Disabling certain "
        "checkers - such as the 'core' group - is unsupported by the LLVM/"
        "Clang community, and thus discouraged.")

    checkers_opts.add_argument('-e',
                               '--enable',
                               dest="enable",
                               metavar='checker/checker-group',
                               default=argparse.SUPPRESS,
                               action=OrderedCheckersAction,
                               help="Set a checker (or checker group) "
                               "to BE USED in the analysis.")

    checkers_opts.add_argument('-d',
                               '--disable',
                               dest="disable",
                               metavar='checker/checker-group',
                               default=argparse.SUPPRESS,
                               action=OrderedCheckersAction,
                               help="Set a checker (or checker group) "
                               "to BE PROHIBITED from use in the "
                               "analysis.")

    # TODO: Analyze does not know '-u', only '--suppress'
    parser.add_argument('-u',
                        '--suppress',
                        type=str,
                        dest="suppress",
                        default=argparse.SUPPRESS,
                        required=False,
                        help="Path of the suppress file to use. Records in "
                        "the suppress file are used to suppress the "
                        "storage of certain results when parsing the "
                        "analyses' report. (Reports to an analysis "
                        "result can also be suppressed in the source "
                        "code -- please consult the manual on how to do "
                        "so.) NOTE: The suppress file relies on the "
                        "\"bug identifier\" generated by the analyzers "
                        "which is experimental, take care when relying "
                        "on it.")

    dbmodes = parser.add_argument_group("database arguments")

    dbmodes = dbmodes.add_mutually_exclusive_group(required=False)

    # SQLite is the default, and for 'check', it was deprecated.
    # TODO: In 'store', --sqlite has been replaced as an option to specify the
    # .sqlite file, essentially replacing the concept of 'workspace'.
    dbmodes.add_argument('--sqlite', action=DeprecatedOptionAction)

    dbmodes.add_argument('--postgresql',
                         dest="postgresql",
                         action='store_true',
                         required=False,
                         default=argparse.SUPPRESS,
                         help="Specifies that a PostgreSQL database is to be "
                         "used instead of SQLite. See the \"PostgreSQL "
                         "arguments\" section on how to configure the "
                         "database connection.")

    pgsql = parser.add_argument_group(
        "PostgreSQL arguments", "Values of these arguments are ignored, "
        "unless '--postgresql' is specified!")

    # WARNING: '--dbaddress' default value influences workspace creation
    # in SQLite.
    # TODO: These are '--db-something' in 'store', not '--dbsomething'.
    pgsql.add_argument('--dbaddress',
                       type=str,
                       dest="dbaddress",
                       default="localhost",
                       required=False,
                       help="Database server address.")

    pgsql.add_argument('--dbport',
                       type=int,
                       dest="dbport",
                       default=5432,
                       required=False,
                       help="Database server port.")

    pgsql.add_argument('--dbusername',
                       type=str,
                       dest="dbusername",
                       default='codechecker',
                       required=False,
                       help="Username to use for connection.")

    pgsql.add_argument('--dbname',
                       type=str,
                       dest="dbname",
                       default="codechecker",
                       required=False,
                       help="Name of the database to use.")

    add_verbose_arguments(parser)
    parser.set_defaults(func=main)
Пример #8
0
def add_arguments_to_parser(parser):
    """
    Add the subcommand's arguments to the given argparse.ArgumentParser.
    """

    # TODO: --name does not exist in 'parse'.
    # In 'store', --name is not a required argument by argparse, as 'analyze'
    # can prepare a name, which is read after 'store' is started.
    # If the name is missing, the user is explicitly warned.
    # TODO: This should be an optional argument here too. Also it doesn't make
    # sense to require --name if --stdout ('parse'-mode) is set.
    parser.add_argument('-n',
                        '--name',
                        type=str,
                        dest="name",
                        required=True,
                        default=argparse.SUPPRESS,
                        help="The name of the analysis run to use in storing "
                        "the reports to the database. If not specified, "
                        "the '--name' parameter given to 'codechecker-"
                        "analyze' will be used, if exists.")

    # TODO: This argument is without an opt-string in 'store' and 'parse'.
    parser.add_argument('-d',
                        '--directory',
                        type=str,
                        dest="directory",
                        required=True,
                        help="Path of the directory where the plist files "
                        "to be used are found.")

    # TODO: Workspace is no longer a concept in the new subcommands.
    parser.add_argument('-w',
                        '--workspace',
                        type=str,
                        default=util.get_default_workspace(),
                        dest="workspace",
                        help="Directory where CodeChecker can store analysis "
                        "related data, such as the database.")

    parser.add_argument('-f',
                        '--force',
                        dest="force",
                        default=False,
                        action='store_true',
                        required=False,
                        help="Delete analysis results stored in the database "
                        "for the current analysis run's name and store "
                        "only the results reported in the 'input' files. "
                        "(By default, CodeChecker would keep reports "
                        "that were coming from files not affected by the "
                        "analysis, and only incrementally update defect "
                        "reports for source files that were analysed.)")

    parser.add_argument('-j',
                        '--jobs',
                        type=int,
                        dest="jobs",
                        required=False,
                        default=1,
                        help="Number of threads to use in parsing and storing "
                        "of results. More threads mean faster analysis "
                        "at the cost of using more memory.")

    # TODO: Parse does not know '-s' or '--steps' for this.
    parser.add_argument('-s',
                        '--steps',
                        '--print-steps',
                        dest="print_steps",
                        action="store_true",
                        required=False,
                        help="Print the steps the analyzers took in finding "
                        "the reported defect.")

    parser.add_argument('--stdout',
                        dest="stdout",
                        action='store_true',
                        required=False,
                        default=False,
                        help="Print the analysis results to the standard "
                        "output instead of storing to the database.")

    dbmodes = parser.add_argument_group("database arguments")

    dbmodes = dbmodes.add_mutually_exclusive_group(required=False)

    # SQLite is the default, and for 'check', it was deprecated.
    # TODO: In 'store', --sqlite has been replaced as an option to specify the
    # .sqlite file, essentially replacing the concept of 'workspace'.
    dbmodes.add_argument('--sqlite', action=DeprecatedOptionAction)

    dbmodes.add_argument('--postgresql',
                         dest="postgresql",
                         action='store_true',
                         required=False,
                         default=argparse.SUPPRESS,
                         help="Specifies that a PostgreSQL database is to be "
                         "used instead of SQLite. See the \"PostgreSQL "
                         "arguments\" section on how to configure the "
                         "database connection.")

    pgsql = parser.add_argument_group(
        "PostgreSQL arguments", "Values of these arguments are ignored, "
        "unless '--postgresql' is specified!")

    # WARNING: '--dbaddress' default value influences workspace creation
    # in SQLite.
    # TODO: These are '--db-something' in 'store', not '--dbsomething'.
    pgsql.add_argument('--dbaddress',
                       type=str,
                       dest="dbaddress",
                       default="localhost",
                       required=False,
                       help="Database server address.")

    pgsql.add_argument('--dbport',
                       type=int,
                       dest="dbport",
                       default=5432,
                       required=False,
                       help="Database server port.")

    pgsql.add_argument('--dbusername',
                       type=str,
                       dest="dbusername",
                       default='codechecker',
                       required=False,
                       help="Username to use for connection.")

    pgsql.add_argument('--dbname',
                       type=str,
                       dest="dbname",
                       default="codechecker",
                       required=False,
                       help="Name of the database to use.")

    add_verbose_arguments(parser)
    parser.set_defaults(func=main)
Пример #9
0
def main():
    """
    CodeChecker main command line.
    """

    def signal_handler(sig, frame):
        """
        Without this handler the PostgreSQL
        server does not terminate at signal.
        """
        sys.exit(1)

    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)

    try:
        parser = argparse.ArgumentParser(
            prog='CodeChecker',
            formatter_class=argparse.RawDescriptionHelpFormatter,
            description='''
Run the CodeChecker source analyzer framework.
See the subcommands for specific features.''',
            epilog='''
Example usage:
--------------
Analyzing a project with default settings:
CodeChecker check -b "cd ~/myproject && make" -n myproject

Start the viewer to see the results:
CodeChecker server

See the results in a web browser: localhost:8001
See results in  the command line: CodeChecker cmd results -p 8001 -n myproject

To analyze a small project quickcheck feature can be used.
The results will be printed only to the standard output.
(No database will be used)

CodeChecker quickcheck -b "cd ~/myproject && make"
''')

        subparsers = parser.add_subparsers(help='commands')

        workspace_help_msg = 'Directory where the CodeChecker can' \
            ' store analysis related data.'

        name_help_msg = 'Name of the analysis.'

        jobs_help_msg = 'Number of jobs. ' \
            'Start multiple processes for faster analysis.'

        log_argument_help_msg = """Path to the log file which is created
         during the build. \nIf there is an already generated log file
         with the compilation commands\ngenerated by \'CodeChecker log\' or
         \'cmake -DCMAKE_EXPORT_COMPILE_COMMANDS\' \n CodeChecker check can
         use it for the analysis in that case running the original build
         will \nbe left out from the analysis process (no log is needed)."""

        suppress_help_msg = """Path to suppress file.\nSuppress file can be used
         to suppress analysis results during the analysis.\nIt is based on the
         bug identifier generated by the compiler which is experimental.\nDo
         not depend too much on this file because identifier or file format
         can be changed.\nFor other in source suppress features see the user
         guide."""

        # --------------------------------------
        # check commands
        check_parser = subparsers.add_parser('check',
                                             formatter_class=ADHF,
                                             help=''' \
Run the supported source code analyzers on a project.''')

        check_parser.add_argument('-w', '--workspace', type=str,
                                  default=util.get_default_workspace(),
                                  dest="workspace",
                                  help=workspace_help_msg)

        check_parser.add_argument('-n', '--name', type=str,
                                  dest="name", required=True,
                                  default=argparse.SUPPRESS,
                                  help=name_help_msg)

        checkgroup = check_parser.add_mutually_exclusive_group(required=True)

        checkgroup.add_argument('-b', '--build', type=str, dest="command",
                                default=argparse.SUPPRESS,
                                required=False, help='''\
Build command which is used to build the project.''')

        checkgroup.add_argument('-l', '--log', type=str, dest="logfile",
                                default=argparse.SUPPRESS,
                                required=False,
                                help=log_argument_help_msg)

        check_parser.add_argument('-j', '--jobs', type=int, dest="jobs",
                                  default=1, required=False,
                                  help=jobs_help_msg)

        check_parser.add_argument('-u', '--suppress', type=str,
                                  dest="suppress",
                                  default=argparse.SUPPRESS,
                                  required=False,
                                  help=suppress_help_msg)
        check_parser.add_argument('-c', '--clean',
                                  default=argparse.SUPPRESS,
                                  action=DeprecatedOptionAction)

        check_parser.add_argument('--update', action=DeprecatedOptionAction,
                                  dest="update", default=False, required=False,
                                  help="Incremental parsing, update the "
                                       "results of a previous run. "
                                       "Only the files changed since the last "
                                       "build will be reanalyzed. Depends on"
                                       " the build system.")

        check_parser.add_argument('--force', action="store_true",
                                  dest="force", default=False, required=False,
                                  help="Delete analysis results form the "
                                       "database if a run with the "
                                       "given name already exists.")

        check_parser.add_argument('-s', '--skip', type=str, dest="skipfile",
                                  default=argparse.SUPPRESS,
                                  required=False, help='Path to skip file.')

        check_parser.add_argument('--quiet-build',
                                  action='store_true',
                                  default=False,
                                  required=False,
                                  help='Do not print out the output of the '
                                       'original build.')

        check_parser.add_argument('--add-compiler-defaults',
                                  action='store_true',
                                  default=False,
                                  required=False,
                                  help='Fetch built in compiler include '
                                       'paths and defines '
                                       'and pass them to Clang. This is '
                                       'useful when you do cross-compilation.')

        add_analyzer_arguments(check_parser)
        add_database_arguments(check_parser)
        logger.add_verbose_arguments(check_parser)
        check_parser.set_defaults(func=arg_handler.handle_check)

        # --------------------------------------
        # QuickCheck commands.
        qcheck_parser = subparsers.add_parser('quickcheck',
                                              formatter_class=ADHF,
                                              help='Run CodeChecker for a '
                                                   'project without database.')

        qcheckgroup = qcheck_parser.add_mutually_exclusive_group(required=True)

        qcheckgroup.add_argument('-b', '--build', type=str, dest="command",
                                 default=argparse.SUPPRESS,
                                 required=False, help='Build command.')

        qcheckgroup.add_argument('-l', '--log', type=str, dest="logfile",
                                 required=False,
                                 default=argparse.SUPPRESS,
                                 help=log_argument_help_msg)

        qcheck_parser.add_argument('-s', '--steps', action="store_true",
                                   dest="print_steps", help='Print steps.')

        qcheck_parser.add_argument('--quiet-build',
                                   action='store_true',
                                   default=False,
                                   required=False,
                                   help='Do not print out the output of the '
                                        'original build.')
        qcheck_parser.add_argument('-i', '--skip', type=str, dest="skipfile",
                                   default=argparse.SUPPRESS,
                                   required=False, help='Path to skip file.')
        qcheck_parser.add_argument('-j', '--jobs', type=int, dest="jobs",
                                   default=1, required=False,
                                   help=jobs_help_msg)
        qcheck_parser.add_argument('-u', '--suppress', type=str,
                                   dest="suppress",
                                   default=argparse.SUPPRESS,
                                   required=False,
                                   help=suppress_help_msg)
        qcheck_parser.add_argument('--add-compiler-defaults',
                                   action='store_true',
                                   default=False,
                                   required=False,
                                   help='Fetch built in compiler include paths'
                                        ' and defines and pass them to Clang. '
                                        'This is useful when you'
                                        'do cross-compilation.')
        add_analyzer_arguments(qcheck_parser)
        logger.add_verbose_arguments(qcheck_parser)
        qcheck_parser.set_defaults(func=arg_handler.handle_quickcheck)

        # --------------------------------------
        # Log commands.
        logging_p = subparsers.add_parser('log',
                                          formatter_class=ADHF,
                                          help='Runs the given build '
                                               'command. During the '
                                               'build the compilation '
                                               'commands are collected '
                                               'and stored into a '
                                               'compilation command '
                                               'json file '
                                               '(no analysis is done '
                                               'during the build).')

        logging_p.add_argument('-o', '--output', type=str, dest="logfile",
                               default=argparse.SUPPRESS,
                               required=True,
                               help='Path to the log file.')

        logging_p.add_argument('-b', '--build', type=str, dest="command",
                               default=argparse.SUPPRESS,
                               required=True, help='Build command.')

        logger.add_verbose_arguments(logging_p)
        logging_p.set_defaults(func=arg_handler.handle_log)

        # --------------------------------------
        # Checkers parser.
        checker_p = subparsers.add_parser('checkers',
                                          formatter_class=ADHF,
                                          help='List the available checkers '
                                               'for the supported analyzers '
                                               'and show their default status '
                                               '(+ for being enabled, '
                                               '- for being disabled by '
                                               'default).')

        checker_p.add_argument('--analyzers', nargs='+',
                               dest="analyzers", required=False,
                               help='Select which analyzer checkers '
                               'should be listed.\nCurrently supported '
                               'analyzers:\n' + analyzers)

        logger.add_verbose_arguments(checker_p)
        checker_p.set_defaults(func=arg_handler.handle_list_checkers)

        # --------------------------------------
        # Server.
        server_parser = subparsers.add_parser('server',
                                              formatter_class=ADHF,
                                              help='Start and manage the '
                                                   'CodeChecker web server.')
        server_parser.add_argument('-w', '--workspace', type=str,
                                   dest="workspace",
                                   default=util.get_default_workspace(),
                                   help=workspace_help_msg)

        server_parser.add_argument('-l', '--list',
                                   action='store_true',
                                   dest="list",
                                   required=False,
                                   help='List servers started by your user.')

        server_parser.add_argument('-s', '--stop',
                                   action='store_true',
                                   dest="stop",
                                   required=False,
                                   help='Stops the server associated with '
                                        'the given view-port and workspace.')

        server_parser.add_argument('--stop-all',
                                   action='store_true',
                                   dest="stop_all",
                                   required=False,
                                   help='Stops all of your running '
                                        'CodeChecker instances.')

        server_parser.add_argument('-v', '--view-port', type=int,
                                   dest="view_port",
                                   default=8001, required=False,
                                   help='Port used for viewing.')

        server_parser.add_argument('-u', '--suppress', type=str,
                                   dest="suppress",
                                   required=False,
                                   help='Path to suppress file.')

        server_parser.add_argument('--not-host-only', action="store_true",
                                   dest="not_host_only",
                                   help='Viewing the results is possible not '
                                        'only by browsers or clients '
                                        'started locally.')

        server_parser.add_argument('--check-port', type=int, dest="check_port",
                                   default=None, required=False,
                                   help='Port used for checking.')

        server_parser.add_argument('--check-address', type=str,
                                   dest="check_address", default="localhost",
                                   required=False, help='Server address.')

        add_database_arguments(server_parser)
        logger.add_verbose_arguments(server_parser)
        server_parser.set_defaults(func=arg_handler.handle_server)

        # --------------------------------------
        # Cmd_line.
        cmd_line_parser = subparsers.add_parser('cmd',
                                                help='Command line client')
        cmd_line_client.register_client_command_line(cmd_line_parser)

        # --------------------------------------
        # Debug parser.
        debug_parser = subparsers.add_parser('debug',
                                             formatter_class=ADHF,
                                             help='Generate gdb debug dump '
                                                  'files for all the failed '
                                                  'compilation commands in '
                                                  'the last analyzer run.\n'
                                                  'Requires a database with '
                                                  'the failed compilation '
                                                  'commands.')

        debug_parser.add_argument('-w', '--workspace', type=str,
                                  dest="workspace",
                                  default=util.get_default_workspace(),
                                  help=workspace_help_msg)

        debug_parser.add_argument('-f', '--force', action="store_true",
                                  dest="force", required=False, default=False,
                                  help='Overwrite already generated files.')

        add_database_arguments(debug_parser)
        logger.add_verbose_arguments(debug_parser)
        debug_parser.set_defaults(func=arg_handler.handle_debug)

        # --------------------------------------
        # Plist parser.
        plist_parser = subparsers.add_parser('plist',
                                             formatter_class=ADHF,
                                             help='Parse plist files in '
                                                  'the given directory and '
                                                  'store them to the database '
                                                  'or print to the standard '
                                                  'output.')

        plist_parser.add_argument('-w', '--workspace', type=str,
                                  dest="workspace",
                                  default=util.get_default_workspace(),
                                  help=workspace_help_msg)

        plist_parser.add_argument('-n', '--name', type=str,
                                  dest="name", required=True,
                                  default=argparse.SUPPRESS,
                                  help=name_help_msg)

        plist_parser.add_argument('-d', '--directory', type=str,
                                  dest="directory", required=True,
                                  help='Path of a directory containing plist '
                                  'files to parse.')

        plist_parser.add_argument('-j', '--jobs', type=int, dest="jobs",
                                  default=1, required=False,
                                  help=jobs_help_msg)

        plist_parser.add_argument('-s', '--steps', action="store_true",
                                  dest="print_steps", help='Print steps.')

        plist_parser.add_argument('--stdout', action="store_true",
                                  dest="stdout",
                                  required=False, default=False,
                                  help='Print results to stdout instead of '
                                       'storing to the database.')

        plist_parser.add_argument('--force', action="store_true",
                                  dest="force", default=False, required=False,
                                  help='Delete analysis results form the '
                                       'database if a run with the given '
                                       'name already exists.')

        add_database_arguments(plist_parser)
        logger.add_verbose_arguments(plist_parser)
        plist_parser.set_defaults(func=arg_handler.handle_plist)

        # --------------------------------------
        # Package version info.
        version_parser = subparsers.add_parser('version',
                                               help='Print package version '
                                                    'information.')
        version_parser.set_defaults(func=arg_handler.handle_version_info)
        logger.add_verbose_arguments(version_parser)

        args = parser.parse_args()
        LoggerFactory.set_log_level(args.verbose)
        args.func(args)

    except KeyboardInterrupt as kb_err:
        LOG.info(str(kb_err))
        LOG.info("Interrupted by user...")
        sys.exit(1)

    except shared.ttypes.RequestFailed as thrift_ex:
        LOG.info("Server error.")
        LOG.info("Error code: " + str(thrift_ex.error_code))
        LOG.info("Error message: " + str(thrift_ex.message))
        sys.exit(1)

    # Handle all exception, but print stacktrace. It is needed for atexit.
    # atexit does not work correctly when an unhandled exception occurred.
    # So in this case, the servers left running when the script exited.
    except Exception:
        import traceback
        traceback.print_exc(file=sys.stdout)
        sys.exit(2)
Пример #10
0
def add_arguments_to_parser(parser):
    """
    Add the subcommand's arguments to the given argparse.ArgumentParser.
    """

    # TODO: --name does not exist in 'parse'.
    # In 'store', --name is not a required argument by argparse, as 'analyze'
    # can prepare a name, which is read after 'store' is started.
    # If the name is missing, the user is explicitly warned.
    # TODO: This should be an optional argument here too. Also it doesn't make
    # sense to require --name if --stdout ('parse'-mode) is set.
    parser.add_argument('-n',
                        '--name',
                        type=str,
                        dest="name",
                        required=True,
                        default=argparse.SUPPRESS,
                        help="The name of the analysis run to use in storing "
                        "the reports to the database. If not specified, "
                        "the '--name' parameter given to 'codechecker-"
                        "analyze' will be used, if exists.")

    # TODO: This argument is without an opt-string in 'store' and 'parse'.
    parser.add_argument('-d',
                        '--directory',
                        type=str,
                        dest="directory",
                        required=True,
                        help="Path of the directory where the plist files "
                        "to be used are found.")

    # TODO: Workspace is no longer a concept in the new subcommands.
    parser.add_argument('-w',
                        '--workspace',
                        type=str,
                        default=util.get_default_workspace(),
                        dest="workspace",
                        help="Directory where CodeChecker can store analysis "
                        "related data, such as the database.")

    parser.add_argument('-f',
                        '--force',
                        dest="force",
                        default=False,
                        action='store_true',
                        required=False,
                        help="Delete analysis results stored in the database "
                        "for the current analysis run's name and store "
                        "only the results reported in the 'input' files. "
                        "(By default, CodeChecker would keep reports "
                        "that were coming from files not affected by the "
                        "analysis, and only incrementally update defect "
                        "reports for source files that were analysed.)")

    parser.add_argument('-j',
                        '--jobs',
                        type=int,
                        dest="jobs",
                        required=False,
                        default=1,
                        help="Number of threads to use in parsing and storing "
                        "of results. More threads mean faster analysis "
                        "at the cost of using more memory.")

    # TODO: Parse does not know '-s' or '--steps' for this.
    parser.add_argument('-s',
                        '--steps',
                        '--print-steps',
                        dest="print_steps",
                        action="store_true",
                        required=False,
                        help="Print the steps the analyzers took in finding "
                        "the reported defect.")

    parser.add_argument('--stdout',
                        dest="stdout",
                        action='store_true',
                        required=False,
                        default=False,
                        help="Print the analysis results to the standard "
                        "output instead of storing to the database.")

    server_args = parser.add_argument_group(
        "server arguments",
        "Specifies a 'CodeChecker server' instance which will be used to "
        "store the results. This server must be running and listening prior "
        "to the 'store' command being ran.")

    server_args.add_argument('--host',
                             type=str,
                             dest="host",
                             required=False,
                             default="localhost",
                             help="The IP address or hostname of the "
                             "CodeChecker server.")

    server_args.add_argument('-p',
                             '--port',
                             type=int,
                             dest="port",
                             required=False,
                             default=8001,
                             help="The port of the server to use for storing.")

    # TODO: These arguments have been retroactively removed from 'store'
    # and are deprecated here. They should be completely removed.
    dbmodes = parser.add_argument_group("database arguments")
    dbmodes = dbmodes.add_mutually_exclusive_group(required=False)
    db_deprec = "Database connectivity has been removed from 'check'. " \
                "Please specify a CodeChecker server address via --host " \
                "and --port instead!"

    # SQLite is the default, and for 'check', it was deprecated.
    # TODO: In 'store', --sqlite has been replaced as an option to specify the
    # .sqlite file, essentially replacing the concept of 'workspace'.
    dbmodes.add_argument('--sqlite',
                         kill_if_used=True,
                         error_string=db_deprec,
                         action=DeprecatedOptionAction)

    dbmodes.add_argument('--postgresql',
                         kill_if_used=True,
                         error_string=db_deprec,
                         action=DeprecatedOptionAction)

    pgsql = parser.add_argument_group(
        "PostgreSQL arguments", "Values of these arguments are ignored, "
        "unless '--postgresql' is specified!")

    # WARNING: '--dbaddress' default value influences workspace creation
    # in SQLite.
    # TODO: These are '--db-something' in 'store', not '--dbsomething'.
    pgsql.add_argument('--dbaddress',
                       nargs=1,
                       kill_if_used=True,
                       error_string=db_deprec,
                       action=DeprecatedOptionAction)

    pgsql.add_argument('--dbport',
                       nargs=1,
                       kill_if_used=True,
                       error_string=db_deprec,
                       action=DeprecatedOptionAction)

    pgsql.add_argument('--dbusername',
                       nargs=1,
                       kill_if_used=True,
                       error_string=db_deprec,
                       action=DeprecatedOptionAction)

    pgsql.add_argument('--dbname',
                       nargs=1,
                       kill_if_used=True,
                       error_string=db_deprec,
                       action=DeprecatedOptionAction)

    add_verbose_arguments(parser)

    def __kill_deprec(args):
        if '_deprecated' in args:
            LOG.warning("A deprecated argument was passed to the "
                        "commandline. This argument has no effect anymore, "
                        "and the behaviour has changed.")
            LOG.error("Execution halted: CodeChecker would work in an "
                      "unexpected way with this argument passed.")
            sys.exit(2)  # argparse kills with error code 2.

        # Call the main process if everything matches.
        main(args)

    parser.set_defaults(func=__kill_deprec)
Пример #11
0
def add_arguments_to_parser(parser):
    """
    Add the subcommand's arguments to the given argparse.ArgumentParser.
    """
    def is_ctu_capable():
        """ Detects if the current clang is CTU compatible. """

        context = generic_package_context.get_context()
        ctu_func_map_cmd = context.ctu_func_map_cmd
        try:
            version = subprocess.check_output([ctu_func_map_cmd, '-version'])
        except (subprocess.CalledProcessError, OSError):
            version = 'ERROR'
        return version != 'ERROR'

    parser.add_argument('logfile',
                        type=str,
                        nargs='+',
                        help="Path to the JSON compilation command database "
                        "files which were created during the build. "
                        "The analyzers will check only the files "
                        "registered in these build databases.")

    parser.add_argument('-j',
                        '--jobs',
                        type=int,
                        dest="jobs",
                        required=False,
                        default=1,
                        help="Number of threads to use in analysis. More "
                        "threads mean faster analysis at the cost of "
                        "using more memory.")

    parser.add_argument('-i',
                        '--ignore',
                        '--skip',
                        dest="skipfile",
                        required=False,
                        default=argparse.SUPPRESS,
                        help="Path to the Skipfile dictating which project "
                        "files should be omitted from analysis. Please "
                        "consult the User guide on how a Skipfile "
                        "should be laid out.")

    parser.add_argument('-o',
                        '--output',
                        dest="output_path",
                        required=False,
                        default=os.path.join(util.get_default_workspace(),
                                             'reports'),
                        help="Store the analysis output in the given folder.")

    parser.add_argument('-t',
                        '--type',
                        '--output-format',
                        dest="output_format",
                        required=False,
                        choices=['plist'],
                        default='plist',
                        help="Specify the format the analysis results should "
                        "use.")

    parser.add_argument('-n',
                        '--name',
                        dest="name",
                        required=False,
                        default=argparse.SUPPRESS,
                        help="Annotate the ran analysis with a custom name in "
                        "the created metadata file.")

    analyzer_opts = parser.add_argument_group("analyzer arguments")

    analyzer_opts.add_argument(
        '--analyzers',
        nargs='+',
        dest='analyzers',
        metavar='ANALYZER',
        required=False,
        choices=analyzer_types.supported_analyzers,
        default=argparse.SUPPRESS,
        help="Run analysis only with the analyzers "
        "specified. Currently supported analyzers "
        "are: " + ', '.join(analyzer_types.supported_analyzers) + ".")

    analyzer_opts.add_argument('--add-compiler-defaults',
                               action='store_true',
                               default=False,
                               required=False,
                               help="Retrieve compiler-specific configuration "
                               "from the compilers themselves, and use "
                               "them with Clang. This is used when the "
                               "compiler on the system is special, e.g. "
                               "when doing cross-compilation.")

    analyzer_opts.add_argument('--capture-analysis-output',
                               dest='capture_analysis_output',
                               action='store_true',
                               default=argparse.SUPPRESS,
                               required=False,
                               help="Store standard output and standard error "
                               "of successful analyzer invocations "
                               "into the '<OUTPUT_DIR>/success' "
                               "directory.")

    analyzer_opts.add_argument('--saargs',
                               dest="clangsa_args_cfg_file",
                               required=False,
                               default=argparse.SUPPRESS,
                               help="File containing argument which will be "
                               "forwarded verbatim for the Clang Static "
                               "Analyzer.")

    analyzer_opts.add_argument('--tidyargs',
                               dest="tidy_args_cfg_file",
                               required=False,
                               default=argparse.SUPPRESS,
                               help="File containing argument which will be "
                               "forwarded verbatim for Clang-Tidy.")

    if is_ctu_capable():
        ctu_opts = parser.add_argument_group(
            "cross translation unit analysis arguments",
            "These arguments are only available if the Clang Static Analyzer "
            "supports Cross-TU analysis. By default, no CTU analysis is ran "
            "when 'CodeChecker analyze' is called.")

        ctu_modes = ctu_opts.add_mutually_exclusive_group()

        ctu_modes.add_argument('--ctu',
                               '--ctu-all',
                               action='store_const',
                               const=[True, True],
                               dest='ctu_phases',
                               default=argparse.SUPPRESS,
                               help="Perform Cross Translation Unit (CTU) "
                               "analysis, both 'collect' and 'analyze' "
                               "phases. In this mode, the extra files "
                               "created by 'collect' are cleaned up "
                               "after the analysis.")

        ctu_modes.add_argument('--ctu-collect',
                               action='store_const',
                               const=[True, False],
                               dest='ctu_phases',
                               default=argparse.SUPPRESS,
                               help="Perform the first, 'collect' phase of "
                               "Cross-TU analysis. This phase generates "
                               "extra files needed by CTU analysis, and "
                               "puts them into '<OUTPUT_DIR>/ctu-dir'. "
                               "NOTE: If this argument is present, "
                               "CodeChecker will NOT execute the "
                               "analyzers!")

        ctu_modes.add_argument('--ctu-analyze',
                               action='store_const',
                               const=[False, True],
                               dest='ctu_phases',
                               default=argparse.SUPPRESS,
                               help="Perform the second, 'analyze' phase of "
                               "Cross-TU analysis, using already "
                               "available extra files in "
                               "'<OUTPUT_DIR>/ctu-dir'. (These files "
                               "will not be cleaned up in this mode.)")

        ctu_opts.add_argument('--ctu-on-the-fly',
                              action='store_true',
                              dest='ctu_in_memory',
                              default=False,
                              help="If specified, the 'collect' phase will "
                              "not create the extra AST dumps, but "
                              "rather analysis will be ran with an "
                              "in-memory recompilation of the source "
                              "files.")

    checkers_opts = parser.add_argument_group(
        "checker configuration",
        "See 'codechecker-checkers' for the list of available checkers. "
        "You can fine-tune which checkers to use in the analysis by setting "
        "the enabled and disabled flags starting from the bigger groups "
        "and going inwards, e.g. '-e core -d core.uninitialized -e "
        "core.uninitialized.Assign' will enable every 'core' checker, but "
        "only 'core.uninitialized.Assign' from the 'core.uninitialized' "
        "group. Please consult the manual for details. Disabling certain "
        "checkers - such as the 'core' group - is unsupported by the LLVM/"
        "Clang community, and thus discouraged.")

    checkers_opts.add_argument('-e',
                               '--enable',
                               dest="enable",
                               metavar='checker/checker-group',
                               default=argparse.SUPPRESS,
                               action=OrderedCheckersAction,
                               help="Set a checker (or checker group) "
                               "to BE USED in the analysis.")

    checkers_opts.add_argument('-d',
                               '--disable',
                               dest="disable",
                               metavar='checker/checker-group',
                               default=argparse.SUPPRESS,
                               action=OrderedCheckersAction,
                               help="Set a checker (or checker group) "
                               "to BE PROHIBITED from use in the "
                               "analysis.")

    checkers_opts.add_argument('--enable-all',
                               dest="enable_all",
                               action='store_true',
                               required=False,
                               default=argparse.SUPPRESS,
                               help="Force the running analyzers to use "
                               "almost every checker available. The "
                               "checker groups 'alpha.', 'debug.' and "
                               "'osx.' (on Linux) are NOT enabled "
                               "automatically and must be EXPLICITLY "
                               "specified. WARNING! Enabling all "
                               "checkers might result in the analysis "
                               "losing precision and stability, and "
                               "could even result in a total failure of "
                               "the analysis. USE WISELY AND AT YOUR "
                               "OWN RISK!")

    add_verbose_arguments(parser)
    parser.set_defaults(func=main)
Пример #12
0
def add_arguments_to_parser(parser):
    """
    Add the subcommand's arguments to the given argparse.ArgumentParser.
    """

    parser.add_argument('input',
                        type=str,
                        nargs='*',
                        metavar='file/folder',
                        default=os.path.join(util.get_default_workspace(),
                                             'reports'),
                        help="The analysis result files and/or folders "
                        "containing analysis results which should be "
                        "parsed and printed.")

    parser.add_argument('-t',
                        '--type',
                        '--input-format',
                        dest="input_format",
                        required=False,
                        choices=['plist'],
                        default='plist',
                        help="Specify the format the analysis results were "
                        "created as.")

    parser.add_argument('-j',
                        '--jobs',
                        type=int,
                        dest="jobs",
                        required=False,
                        default=1,
                        help="Number of threads to use in storing results. "
                        "More threads mean faster operation at the cost "
                        "of using more memory.")

    parser.add_argument('-n',
                        '--name',
                        type=str,
                        dest="name",
                        required=False,
                        default=argparse.SUPPRESS,
                        help="The name of the analysis run to use in storing "
                        "the reports to the database. If not specified, "
                        "the '--name' parameter given to 'codechecker-"
                        "analyze' will be used, if exists.")

    # Upcoming feature planned for v6.0. Argument name and help RESERVED.
    # parser.add_argument('--group', '--group-name',
    #                    type=str,
    #                    dest="group_name",
    #                    required=False,
    #                    default=argparse.SUPPRESS,
    #                    help="Specify the \"analysis group\" the results "
    #                         "stored will belong to. An analysis group "
    #                         "consists of multiple analyses whose reports "
    #                         "are showed together in a common view -- e.g. "
    #                         "a project's view for every subproject analysed "
    #                         "separately, or all analyses of a user or a "
    #                         "team.")

    parser.add_argument('--suppress',
                        type=str,
                        dest="suppress",
                        default=argparse.SUPPRESS,
                        required=False,
                        help="Path of the suppress file to use. Records in "
                        "the suppress file are used to mark certain "
                        "stored analysis results as 'suppressed'. "
                        "(Reports to an analysis result can also be "
                        "suppressed in the source code -- please "
                        "consult the manual on how to do so.) NOTE: The "
                        "suppress file relies on the \"bug identifier\" "
                        "generated by the analyzers which is "
                        "experimental, take care when relying on it.")

    parser.add_argument('-f',
                        '--force',
                        dest="force",
                        default=False,
                        action='store_true',
                        required=False,
                        help="Delete analysis results stored in the database "
                        "for the current analysis run's name and store "
                        "only the results reported in the 'input' files. "
                        "(By default, CodeChecker would keep reports "
                        "that were coming from files not affected by the "
                        "analysis, and only incrementally update defect "
                        "reports for source files that were analysed.)")

    dbmodes = parser.add_argument_group("database arguments")

    dbmodes = dbmodes.add_mutually_exclusive_group(required=False)

    dbmodes.add_argument('--sqlite',
                         type=str,
                         dest="sqlite",
                         metavar='SQLITE_FILE',
                         default=os.path.join(util.get_default_workspace(),
                                              "codechecker.sqlite"),
                         required=False,
                         help="Path of the SQLite database file to use.")

    dbmodes.add_argument('--postgresql',
                         dest="postgresql",
                         action='store_true',
                         required=False,
                         default=argparse.SUPPRESS,
                         help="Specifies that a PostgreSQL database is to be "
                         "used instead of SQLite. See the \"PostgreSQL "
                         "arguments\" section on how to configure the "
                         "database connection.")

    pgsql = parser.add_argument_group(
        "PostgreSQL arguments", "Values of these arguments are ignored, "
        "unless '--postgresql' is specified!")

    # WARNING: '--dbaddress' default value influences workspace creation
    # in SQLite.
    pgsql.add_argument('--db-host',
                       type=str,
                       dest="dbaddress",
                       default="localhost",
                       required=False,
                       help="Database server address.")

    pgsql.add_argument('--db-port',
                       type=int,
                       dest="dbport",
                       default=5432,
                       required=False,
                       help="Database server port.")

    pgsql.add_argument('--db-username',
                       type=str,
                       dest="dbusername",
                       default='codechecker',
                       required=False,
                       help="Username to use for connection.")

    pgsql.add_argument('--db-name',
                       type=str,
                       dest="dbname",
                       default="codechecker",
                       required=False,
                       help="Name of the database to use.")

    add_verbose_arguments(parser)

    def __handle(args):
        """Custom handler for 'store' so custom error messages can be
        printed without having to capture 'parser' in main."""
        def arg_match(options):
            """Checks and selects the option string specified in 'options'
            that are present in the invocation argv."""
            matched_args = []
            for option in options:
                if any([
                        arg if option.startswith(arg) else None
                        for arg in sys.argv[1:]
                ]):
                    matched_args.append(option)
                    continue

            return matched_args

        # See if there is a "PostgreSQL argument" specified in the invocation
        # without '--postgresql' being there. There is no way to distinguish
        # a default argument and a deliberately specified argument without
        # inspecting sys.argv.
        options = ['--db-host', '--db-port', '--db-username', '--db-name']
        psql_args_matching = arg_match(options)
        if any(psql_args_matching) and \
                'postgresql' not in args:
            first_matching_arg = next(
                iter([match for match in psql_args_matching]))
            parser.error("argument {0}: not allowed without "
                         "argument --postgresql".format(first_matching_arg))
            # parser.error() terminates with return code 2.

        if 'postgresql' not in args:
            # Later called database modules need the argument to be actually
            # present, even though the default is suppressed in the optstring.
            setattr(args, 'postgresql', False)
        else:
            # If --postgresql is given, --sqlite is useless.
            delattr(args, 'sqlite')

        # If everything is fine, do call the handler for the subcommand.
        main(args)

    parser.set_defaults(func=__handle)
Пример #13
0
def main(subcommands=None):
    """
    CodeChecker main command line.
    """

    def signal_handler(sig, frame):
        """
        Without this handler the PostgreSQL
        server does not terminate at signal.
        """
        sys.exit(1)

    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)

    try:
        parser = argparse.ArgumentParser(
            prog='CodeChecker',
            formatter_class=argparse.RawDescriptionHelpFormatter,
            description='''
Run the CodeChecker source analyzer framework.
See the subcommands for specific features.''',
            epilog='''
Example usage:
--------------
Analyzing a project with default settings:
CodeChecker check -b "cd ~/myproject && make" -n myproject

Start the viewer to see the results:
CodeChecker server

See the results in a web browser: localhost:8001
See results in  the command line: CodeChecker cmd results -p 8001 -n myproject

To analyze a small project quickcheck feature can be used.
The results will be printed only to the standard output.
(No database will be used)

CodeChecker quickcheck -b "cd ~/myproject && make"
''')

        subparsers = parser.add_subparsers(help='commands')

        # TODO: Delete these once a later version rolls.
        old_subcommands = []

        def _warn_deprecated_command(cmd_name):
            # Write to stderr so the output is not captured by pipes, e.g.
            # with the "checkers" command, the "-" in the new command's name
            # would mess up pipe usage.
            err_msg = "[WARNING] The called command 'CodeChecker {0}' is " \
                      "DEPRECATED since version A.B. A new version is "    \
                      "available as 'codechecker-{0}'.\nThe DEPRECATED "   \
                      "command will be REPLACED when version X.Y is "      \
                      "released.\nPlease see 'codechecker-{0} --help' on " \
                      "details how to run the new version.\n".format(cmd_name)

            # This warning is implemented for showing later on, once old
            # behaviour commands are deprecated. We don't warn between 5.8 and
            # 6.0 for now.
            # sys.stderr.write(err_msg)

        workspace_help_msg = 'Directory where the CodeChecker can' \
            ' store analysis related data.'

        # --------------------------------------
        # Checkers parser.
        checker_p = subparsers.add_parser('checkers',
                                          formatter_class=ADHF,
                                          help='List the available checkers '
                                               'for the supported analyzers '
                                               'and show their default status '
                                               '(+ for being enabled, '
                                               '- for being disabled by '
                                               'default).')
        old_subcommands.append('checkers')

        checker_p.add_argument('--analyzers', nargs='+',
                               dest="analyzers", required=False,
                               help='Select which analyzer checkers '
                               'should be listed.\nCurrently supported '
                               'analyzers:\n' + analyzers)

        logger.add_verbose_arguments(checker_p)
        checker_p.set_defaults(func=arg_handler.handle_list_checkers)

        # --------------------------------------
        # Server.
        server_parser = subparsers.add_parser('server',
                                              formatter_class=ADHF,
                                              help='Start and manage the '
                                                   'CodeChecker web server.')
        old_subcommands.append('server')

        server_parser.add_argument('-w', '--workspace', type=str,
                                   dest="workspace",
                                   default=util.get_default_workspace(),
                                   help=workspace_help_msg)

        server_parser.add_argument('-l', '--list',
                                   action='store_true',
                                   dest="list",
                                   required=False,
                                   help='List servers started by your user.')

        server_parser.add_argument('-s', '--stop',
                                   action='store_true',
                                   dest="stop",
                                   required=False,
                                   help='Stops the server associated with '
                                        'the given view-port and workspace.')

        server_parser.add_argument('--stop-all',
                                   action='store_true',
                                   dest="stop_all",
                                   required=False,
                                   help='Stops all of your running '
                                        'CodeChecker instances.')

        server_parser.add_argument('-v', '--view-port', type=int,
                                   dest="view_port",
                                   default=8001, required=False,
                                   help='Port used for viewing.')

        server_parser.add_argument('-u', '--suppress', type=str,
                                   dest="suppress",
                                   required=False,
                                   help='Path to suppress file.')

        server_parser.add_argument('--not-host-only', action="store_true",
                                   dest="not_host_only",
                                   help='Viewing the results is possible not '
                                        'only by browsers or clients '
                                        'started locally.')

        server_parser.add_argument('--check-port', type=int, dest="check_port",
                                   default=None, required=False,
                                   help='Port used for checking.')

        server_parser.add_argument('--check-address', type=str,
                                   dest="check_address", default="localhost",
                                   required=False, help='Server address.')

        add_database_arguments(server_parser)
        logger.add_verbose_arguments(server_parser)
        server_parser.set_defaults(func=arg_handler.handle_server)

        # --------------------------------------
        # Cmd_line.
        cmd_line_parser = subparsers.add_parser('cmd',
                                                help='Command line client')
        old_subcommands.append('cmd')
        cmd_line_client.register_client_command_line(cmd_line_parser)

        # --------------------------------------
        # Debug parser.
        debug_parser = subparsers.add_parser('debug',
                                             formatter_class=ADHF,
                                             help='Generate gdb debug dump '
                                                  'files for all the failed '
                                                  'compilation commands in '
                                                  'the last analyzer run.\n'
                                                  'Requires a database with '
                                                  'the failed compilation '
                                                  'commands.')
        old_subcommands.append('debug')

        debug_parser.add_argument('-w', '--workspace', type=str,
                                  dest="workspace",
                                  default=util.get_default_workspace(),
                                  help=workspace_help_msg)

        debug_parser.add_argument('-f', '--force', action="store_true",
                                  dest="force", required=False, default=False,
                                  help='Overwrite already generated files.')

        add_database_arguments(debug_parser)
        logger.add_verbose_arguments(debug_parser)
        debug_parser.set_defaults(func=arg_handler.handle_debug)

        if subcommands:
            # Load the 'libcodechecker' module and acquire its path.
            file, path, descr = imp.find_module("libcodechecker")
            libcc_path = imp.load_module("libcodechecker",
                                         file, path, descr).__path__[0]

            # Try to check if the user has already given us a subcommand to
            # execute. If so, don't load every available parts of CodeChecker
            # to ensure a more optimised run.
            if len(sys.argv) > 1:
                first_command = sys.argv[1]
                if first_command in subcommands:
                    LOG.debug("Supplied an existing, valid subcommand: " +
                              first_command)

                    if 'CC_FROM_LEGACY_INVOKE' not in os.environ:
                        # Consider only the given command as an available one.
                        subcommands = [first_command]
                    else:
                        if first_command in old_subcommands:
                            # Certain commands as of now have a 'new' and an
                            # 'old' invocation and execution. In case of an
                            # 'old' invocation is passed ('CodeChecker
                            # command'), do NOT load the 'new' argument parser
                            # and executed method.
                            #
                            # TODO: Delete this once the new commands are
                            # fleshed out and old are deprecated later on.
                            _warn_deprecated_command(first_command)
                            subcommands = []

            for subcommand in subcommands:
                if 'CC_FROM_LEGACY_INVOKE' in os.environ and \
                        subcommand in old_subcommands:
                    # Make sure 'old' commands have a priority in the listing
                    # when '--help' is queried.
                    continue

                LOG.debug("Creating arg parser for subcommand " + subcommand)

                try:
                    # Even though command verbs and nouns are joined by a
                    # hyphen, the Python files contain underscores.
                    command_file = os.path.join(libcc_path,
                                                subcommand.replace('-', '_') +
                                                ".py")

                    # Load the module's source code, located under
                    # libcodechecker/sub_command.py.
                    # We can't use find_module() and load_module() here as both
                    # a file AND a package exists with the same name, and
                    # find_module() would find
                    # libcodechecker/sub_command/__init__.py first.
                    # Thus, manual source-code reading is required.
                    # NOTE: load_source() loads the compiled .pyc, if such
                    # exists.
                    command_module = imp.load_source(subcommand, command_file)

                    # Now that the module is loaded, construct an
                    # ArgumentParser for it.
                    sc_parser = subparsers.add_parser(
                        subcommand, **command_module.get_argparser_ctor_args())

                    command_module.add_arguments_to_parser(sc_parser)

                except (IOError, ImportError):
                    LOG.warning("Couldn't import module for subcommand '" +
                                subcommand + "'... ignoring.")
                    import traceback
                    traceback.print_exc(file=sys.stdout)

        args = parser.parse_args()
        if 'verbose' in args:
            LoggerFactory.set_log_level(args.verbose)
        args.func(args)

        if 'CC_FROM_LEGACY_INVOKE' in os.environ and \
                first_command and first_command in old_subcommands:
            _warn_deprecated_command(first_command)

    except KeyboardInterrupt as kb_err:
        LOG.info(str(kb_err))
        LOG.info("Interrupted by user...")
        sys.exit(1)

    except shared.ttypes.RequestFailed as thrift_ex:
        LOG.info("Server error.")
        LOG.info("Error code: " + str(thrift_ex.error_code))
        LOG.info("Error message: " + str(thrift_ex.message))
        sys.exit(1)

    # Handle all exception, but print stacktrace. It is needed for atexit.
    # atexit does not work correctly when an unhandled exception occurred.
    # So in this case, the servers left running when the script exited.
    except Exception:
        import traceback
        traceback.print_exc(file=sys.stdout)
        sys.exit(1)
Пример #14
0
def add_arguments_to_parser(parser):
    """
    Add the subcommand's arguments to the given argparse.ArgumentParser.
    """

    parser.add_argument('-o',
                        '--output',
                        dest="output_dir",
                        required=False,
                        default=os.path.join(get_default_workspace(),
                                             'reports'),
                        help="Store the analysis output in the given folder.")

    parser.add_argument('-q',
                        '--quiet',
                        dest="quiet",
                        action='store_true',
                        required=False,
                        default=argparse.SUPPRESS,
                        help="If specified, the build tool's and the "
                        "analyzers' output will not be printed to the "
                        "standard output.")

    parser.add_argument('-f',
                        '--force',
                        dest="force",
                        default=argparse.SUPPRESS,
                        action='store_true',
                        required=False,
                        help="Delete analysis results stored in the database "
                        "for the current analysis run's name and store "
                        "only the results reported in the 'input' files. "
                        "(By default, CodeChecker would keep reports "
                        "that were coming from files not affected by the "
                        "analysis, and only incrementally update defect "
                        "reports for source files that were analysed.)")

    log_args = parser.add_argument_group(
        "log arguments",
        "Specify how the build information database should be obtained. You "
        "need to specify either an already existing log file, or a build "
        "command which will be used to generate a log file on the fly.")

    log_args = log_args.add_mutually_exclusive_group(required=True)

    log_args.add_argument('-b',
                          '--build',
                          type=str,
                          dest="command",
                          default=argparse.SUPPRESS,
                          help="Execute and record a build command. Build "
                          "commands can be simple calls to 'g++' or "
                          "'clang++' or 'make', but a more complex "
                          "command, or the call of a custom script file "
                          "is also supported.")

    log_args.add_argument('-l',
                          '--logfile',
                          type=str,
                          dest="logfile",
                          default=argparse.SUPPRESS,
                          help="Use an already existing JSON compilation "
                          "command database file specified at this path.")

    analyzer_opts = parser.add_argument_group("analyzer arguments")
    analyzer_opts.add_argument('-j',
                               '--jobs',
                               type=int,
                               dest="jobs",
                               required=False,
                               default=1,
                               help="Number of threads to use in analysis. "
                               "More threads mean faster analysis at "
                               "the cost of using more memory.")

    analyzer_opts.add_argument('-i',
                               '--ignore',
                               '--skip',
                               dest="skipfile",
                               required=False,
                               default=argparse.SUPPRESS,
                               help="Path to the Skipfile dictating which "
                               "project files should be omitted from "
                               "analysis. Please consult the User guide "
                               "on how a Skipfile should be laid out.")

    analyzer_opts.add_argument(
        '--analyzers',
        nargs='+',
        dest='analyzers',
        metavar='ANALYZER',
        required=False,
        choices=analyzer_types.supported_analyzers,
        default=argparse.SUPPRESS,
        help="Run analysis only with the analyzers "
        "specified. Currently supported analyzers "
        "are: " + ', '.join(analyzer_types.supported_analyzers) + ".")

    analyzer_opts.add_argument('--add-compiler-defaults',
                               action='store_true',
                               required=False,
                               default=argparse.SUPPRESS,
                               help="Retrieve compiler-specific configuration "
                               "from the analyzers themselves, and use "
                               "them with Clang. This is used when the "
                               "compiler on the system is special, e.g. "
                               "when doing cross-compilation.")

    # TODO: One day, get rid of these. See Issue #36, #427.
    analyzer_opts.add_argument('--saargs',
                               dest="clangsa_args_cfg_file",
                               required=False,
                               default=argparse.SUPPRESS,
                               help="File containing argument which will be "
                               "forwarded verbatim for the Clang Static "
                               "analyzer.")

    analyzer_opts.add_argument('--tidyargs',
                               dest="tidy_args_cfg_file",
                               required=False,
                               default=argparse.SUPPRESS,
                               help="File containing argument which will be "
                               "forwarded verbatim for the Clang-Tidy "
                               "analyzer.")

    checkers_opts = parser.add_argument_group(
        "checker configuration",
        "See 'codechecker-checkers' for the list of available checkers. "
        "You can fine-tune which checkers to use in the analysis by setting "
        "the enabled and disabled flags starting from the bigger groups "
        "and going inwards, e.g. '-e core -d core.uninitialized -e "
        "core.uninitialized.Assign' will enable every 'core' checker, but "
        "only 'core.uninitialized.Assign' from the 'core.uninitialized' "
        "group. Please consult the manual for details. Disabling certain "
        "checkers - such as the 'core' group - is unsupported by the LLVM/"
        "Clang community, and thus discouraged.")

    checkers_opts.add_argument('-e',
                               '--enable',
                               dest="enable",
                               metavar='checker/checker-group',
                               default=argparse.SUPPRESS,
                               action=OrderedCheckersAction,
                               help="Set a checker (or checker group) "
                               "to BE USED in the analysis.")

    checkers_opts.add_argument('-d',
                               '--disable',
                               dest="disable",
                               metavar='checker/checker-group',
                               default=argparse.SUPPRESS,
                               action=OrderedCheckersAction,
                               help="Set a checker (or checker group) "
                               "to BE PROHIBITED from use in the "
                               "analysis.")

    output_opts = parser.add_argument_group("output arguments")

    output_opts.add_argument('--print-steps',
                             dest="print_steps",
                             action="store_true",
                             required=False,
                             default=argparse.SUPPRESS,
                             help="Print the steps the analyzers took in "
                             "finding the reported defect.")

    add_verbose_arguments(parser)
    parser.set_defaults(func=main)