<commit_before># -*- coding: utf-8 -*-
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

import json
import os
import shutil
import subprocess

from cli_common.command import run_check
from cli_common.log import get_logger
from static_analysis_bot import COVERITY
from static_analysis_bot import AnalysisException
from static_analysis_bot import DefaultAnalyzer
from static_analysis_bot import Issue
from static_analysis_bot import stats
from static_analysis_bot.config import settings
from static_analysis_bot.revisions import Revision

logger = get_logger(__name__)

ISSUE_MARKDOWN = '''
## coverity error

- **Message**: {message}
- **Location**: {location}
- **In patch**: {in_patch}
- **Coverity check**: {check}
- **Publishable **: {publishable}
- **Is new**: {is_new}

```
{body}
```
'''

ISSUE_ELEMENT_IN_STACK = '''
- //{file_path}:{line_number}//:
-- `{path_type}: {description}`.
'''

ISSUE_RELATION = '''
The path that leads to this defect is:
'''


class Coverity(DefaultAnalyzer):
    '''
    Coverity runner
    '''
    def __init__(self, validate_checks=True):
        # Ensure that we have all what we need into settings
        assert settings.cov_package_name, 'Missing secret COVERITY_CONFIG:package_name'
        assert settings.cov_package_ver, 'Missing secret COVERITY_CONFIG:package_ver'

        self.cov_state_path = os.path.join(os.environ['MOZBUILD_STATE_PATH'],
                                           'coverity')
        self.cov_path = os.path.join(self.cov_state_path,
                                     settings.cov_package_name)
        self.cov_run_desktop = os.path.join(self.cov_path, 'bin', 'cov-run-desktop')
        self.cov_translate = os.path.join(self.cov_path, 'bin', 'cov-translate')
        self.cov_configure = os.path.join(self.cov_path, 'bin', 'cov-configure')
        self.cov_work_path = os.path.join(self.cov_state_path, 'data-coverity')
        self.cov_idir_path = os.path.join(self.cov_work_path, settings.cov_package_ver, 'idir')

        assert os.path.exists(self.cov_path), \
            'Missing Coverity in {}'.format(self.cov_path)

    def get_files_with_commands(self):
        '''
        Returns an array of dictionaries having file_path with build command
        '''

        compile_db = json.load(open(self.compile_commands_path, 'r'))

        commands_list = []

        for rev_file in self.revision.files:
            # It must be a C/C++ file
            _, ext = os.path.splitext(rev_file)

            if ext.lower() not in settings.cpp_extensions:
                continue
            file_with_abspath = os.path.join(settings.repo_dir, rev_file)
            for f in compile_db:
                # Found for a file that we are looking
                if file_with_abspath == f['file']:
                    commands_list.append(f)

        return commands_list

    @stats.api.timed('runtime.coverity')
    def run(self, revision):
        '''
        Run coverity
        '''
        assert isinstance(revision, Revision)
        self.revision = revision

        # Based on our previous configs we should already have generated compile_commands.json
        self.compile_commands_path = os.path.join(settings.repo_dir, 'obj-x86_64-pc-linux-gnu', 'compile_commands.json')

        assert os.path.exists(self.compile_commands_path), \
            'Missing Coverity in {}'.format(self.compile_commands_path)

        logger.info('Building command files from compile_commands.json')

        # Retrieve the revision files with build commands associated
        commands_list = self.get_files_with_commands()
        assert commands_list is not [], 'Commands List is empty'
        logger.info('Built commands for {} files'.format(len(commands_list)))

        cmd = ['gecko-env', self.cov_run_desktop, '--setup']
        logger.info('Running Coverity Setup', cmd=cmd)
        try:
            run_check(cmd, cwd=self.cov_path)
        except subprocess.CalledProcessError as e:
            raise AnalysisException('coverity', 'Coverity Setup failed: {}'.format(e.output))

        cmd = ['gecko-env', self.cov_configure, '--clang']
        logger.info('Running Coverity Configure', cmd=cmd)
        try:
            run_check(cmd, cwd=self.cov_path)
        except subprocess.CalledProcessError as e:
            raise AnalysisException('coverity', 'Coverity Configure failed: {}'.format(e.output))

        # For each element in commands_list run `cov-translate`<commit_msg>staticanalysis/bot: If there are no compilation units abort the Coverity Analysis. (#1879)<commit_after># -*- coding: utf-8 -*-
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

import json
import os
import shutil
import subprocess

from cli_common.command import run_check
from cli_common.log import get_logger
from static_analysis_bot import COVERITY
from static_analysis_bot import AnalysisException
from static_analysis_bot import DefaultAnalyzer
from static_analysis_bot import Issue
from static_analysis_bot import stats
from static_analysis_bot.config import settings
from static_analysis_bot.revisions import Revision

logger = get_logger(__name__)

ISSUE_MARKDOWN = '''
## coverity error

- **Message**: {message}
- **Location**: {location}
- **In patch**: {in_patch}
- **Coverity check**: {check}
- **Publishable **: {publishable}
- **Is new**: {is_new}

```
{body}
```
'''

ISSUE_ELEMENT_IN_STACK = '''
- //{file_path}:{line_number}//:
-- `{path_type}: {description}`.
'''

ISSUE_RELATION = '''
The path that leads to this defect is:
'''


class Coverity(DefaultAnalyzer):
    '''
    Coverity runner
    '''
    def __init__(self, validate_checks=True):
        # Ensure that we have all what we need into settings
        assert settings.cov_package_name, 'Missing secret COVERITY_CONFIG:package_name'
        assert settings.cov_package_ver, 'Missing secret COVERITY_CONFIG:package_ver'

        self.cov_state_path = os.path.join(os.environ['MOZBUILD_STATE_PATH'],
                                           'coverity')
        self.cov_path = os.path.join(self.cov_state_path,
                                     settings.cov_package_name)
        self.cov_run_desktop = os.path.join(self.cov_path, 'bin', 'cov-run-desktop')
        self.cov_translate = os.path.join(self.cov_path, 'bin', 'cov-translate')
        self.cov_configure = os.path.join(self.cov_path, 'bin', 'cov-configure')
        self.cov_work_path = os.path.join(self.cov_state_path, 'data-coverity')
        self.cov_idir_path = os.path.join(self.cov_work_path, settings.cov_package_ver, 'idir')

        assert os.path.exists(self.cov_path), \
            'Missing Coverity in {}'.format(self.cov_path)

    def get_files_with_commands(self):
        '''
        Returns an array of dictionaries having file_path with build command
        '''

        compile_db = json.load(open(self.compile_commands_path, 'r'))

        commands_list = []

        for rev_file in self.revision.files:
            # It must be a C/C++ file
            _, ext = os.path.splitext(rev_file)

            if ext.lower() not in settings.cpp_extensions:
                continue
            file_with_abspath = os.path.join(settings.repo_dir, rev_file)
            for f in compile_db:
                # Found for a file that we are looking
                if file_with_abspath == f['file']:
                    commands_list.append(f)

        return commands_list

    @stats.api.timed('runtime.coverity')
    def run(self, revision):
        '''
        Run coverity
        '''
        assert isinstance(revision, Revision)
        self.revision = revision

        # Based on our previous configs we should already have generated compile_commands.json
        self.compile_commands_path = os.path.join(settings.repo_dir, 'obj-x86_64-pc-linux-gnu', 'compile_commands.json')

        assert os.path.exists(self.compile_commands_path), \
            'Missing Coverity in {}'.format(self.compile_commands_path)

        logger.info('Building command files from compile_commands.json')

        # Retrieve the revision files with build commands associated
        commands_list = self.get_files_with_commands()
        assert commands_list is not [], 'Commands List is empty'
        logger.info('Built commands for {} files'.format(len(commands_list)))

        if len(commands_list) == 0:
            logger.info('Coverity didn\'t find any compilation units to use.')
            return []

        cmd = ['gecko-env', self.cov_run_desktop, '--setup']
        logger.info('Running Coverity Setup', cmd=cmd)
        try:
            run_check(cmd, cwd=self.cov_path)
        except subprocess.CalledProcessError as e:
            raise AnalysisException('coverity', 'Coverity Setup failed: {}'.format(e.output))

        cmd = ['gecko-env', self.cov_configure, '--clang']
        logger.info('Running Coverity Configure', cmd=cmd)
        try:
            run_check(cmd, cwd=self.cov_path)
        except subprocess.CalledProcessError as e:
            raise AnalysisException('coverity', 'Coverity Configure failed: {}'.format(e.output))

        # For each element in commands_list run `cov-translate`
{'fraction_non_alphanumeric': 0.10811671087533156, 'fraction_numerical': 0.002440318302387268, 'mean_word_length': 2.8726376335250614, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4669335', 'n_tokens_mistral': 2824, 'n_tokens_neox': 2736, 'n_words': 694}