Пример #1
0
class ShellCheckBear:  # pragma nt: no cover
    """
    Check bash/shell scripts for syntactical problems (with understandable
    messages), semantical problems as well as subtle caveats and pitfalls.

    A gallery of bad code that can be detected is available at
    <https://github.com/koalaman/shellcheck/blob/master/README.md>.
    """

    LANGUAGES = {'sh', 'bash', 'ksh', 'dash'}
    REQUIREMENTS = {AnyOneOfRequirements(
            [CabalRequirement('ShellCheck', '0.4.1'),
             DistributionRequirement('shellcheck')
             ]
        ),
    }
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Syntax', 'Security', 'Undefined Element', 'Unused Code'}

    @staticmethod
    def create_arguments(filename, file, config_file, shell: str = 'sh',
                         shellcheck_ignore: list = None,
                         ):
        """
        :param shell: Target shell being used.
        :param shellcheck_ignore: List of linting rules that should be ignored.
        """
        args = ('--f', 'gcc', '-s', shell, filename)
        if shellcheck_ignore:
            args += ('-e', ','.join(shellcheck_ignore))

        return args
Пример #2
0
class GhcModBear:  # pragma nt: no cover
    """
    Syntax checking with ``ghc`` for Haskell files.

    See <https://hackage.haskell.org/package/ghc-mod> for more information!
    """

    LANGUAGES = {'Haskell'}
    REQUIREMENTS = {
        AnyOneOfRequirements(
            [CabalRequirement('ghc-mod', '5.6.0.0'),
             DistributionRequirement('ghc-mod')
             ]
        ),
    }
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    ASCIINEMA_URL = 'https://asciinema.org/a/98873'
    CAN_DETECT = {'Syntax'}

    @staticmethod
    def create_arguments(filename, file, config_file):
        # -b '. ' is the argument given for ghc-mod for seperation of messages
        return '-b', '. ', 'check', filename
class HaskellLintBear:
    """
    Check Haskell code for possible problems. This bear can propose patches for
    using alternative functions, simplifying code and removing redundancies.

    See <http://community.haskell.org/~ndm/darcs/hlint/hlint.htm> for more
    information.
    """

    LANGUAGES = {'Haskell'}
    REQUIREMENTS = {
        AnyOneOfRequirements([
            CabalRequirement(package='hlint', version='1.9.27'),
            DistributionRequirement(apt_get='hlint'),
        ], ),
    }
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Duplication'}
    CAN_FIX = {'Unused Code', 'Code Simplification'}

    severity_map = {
        'Error': RESULT_SEVERITY.MAJOR,
        'Warning': RESULT_SEVERITY.NORMAL,
        'Suggestion': RESULT_SEVERITY.INFO
    }

    @staticmethod
    def create_arguments(filename, file, config_file):
        return '--json', filename

    def process_output(self, output, filename, file):
        output = json.loads(output)

        for issue in output:
            diff = Diff(file)
            from_lines = issue['from'].splitlines()
            to_lines = issue['to'].splitlines()
            assert len(from_lines) == len(to_lines)
            for other_lines in range(1, len(from_lines)):
                assert from_lines[other_lines] == to_lines[other_lines]
            line_nr = issue['startLine']
            line_to_change = file[line_nr - 1]
            newline = line_to_change.replace(from_lines[0], to_lines[0])
            diff.change_line(line_nr, line_to_change, newline)

            yield Result.from_values(
                origin=self,
                message=issue['hint'],
                file=filename,
                severity=self.severity_map[issue['severity']],
                line=issue['startLine'],
                column=issue['startColumn'],
                end_line=issue['endLine'],
                end_column=issue['endColumn'],
                diffs={filename: diff})
class RubySyntaxBear:
    """
    Checks the code with ``ruby -wc`` on each file separately.
    """
    LANGUAGES = {'Ruby'}
    REQUIREMENTS = {
        AnyOneOfRequirements(
            [DistributionRequirement('ruby'),
             CondaRequirement('ruby', '2.2.3', 'bioconda'),
             ],
        ),
    }
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Syntax'}

    @staticmethod
    def create_arguments(filename, file, config_file):
        return '-wc', filename
Пример #5
0
class PHPMessDetectorBear:
    """
    The bear takes a given PHP source code base and looks for several
    potential problems within that source. These problems can be things like:

    - Possible bugs
    - Suboptimal code
    - Overcomplicated expressions
    - Unused parameters, methods, properties
    """

    LANGUAGES = {'PHP'}
    REQUIREMENTS = {
        AnyOneOfRequirements([
            DistributionRequirement(
                apt_get='phpmd',
                dnf='php-phpmd-PHP-PMD',
            ),
            ComposerRequirement('phpmd/phpmd'),
        ], ),
    }
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {
        'Formatting', 'Complexity', 'Unused Code', 'Redundancy',
        'Variable Misuse'
    }
    SEE_MORE = 'https://phpmd.org/about.html'

    @staticmethod
    def create_arguments(filename, file, config_file,
                         phpmd_rulesets: typed_list(str)):
        """
        :param phpmd_rulesets:
            A list of rulesets to use for analysis.
            Available rulesets: cleancode, codesize, controversial, design,
            naming, unusedcode.
        """
        return filename, 'text', ','.join(phpmd_rulesets)
class PHPCodeSnifferBear:
    """
    Ensures that your PHP, JavaScript or CSS code remains clean and consistent.

    See <https://github.com/squizlabs/PHP_CodeSniffer> for more information.
    """

    LANGUAGES = {'PHP', 'JavaScript', 'CSS'}
    REQUIREMENTS = {
        AnyOneOfRequirements([
            DistributionRequirement(
                apt_get='php-codesniffer',
                zypper='php-pear-php_codesniffer',
            ),
            ComposerRequirement('squizlabs/php_codesniffer'),
        ], ),
    }
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {
        'Formatting', 'Syntax', 'Documentation', 'Code Simplification'
    }
    ASCIINEMA_URL = 'https://asciinema.org/a/efawv96vdalck73tc3hwcabov'

    @staticmethod
    def create_arguments(filename, file, config_file):
        return '--report=emacs', '--standard=' + config_file, filename

    @staticmethod
    def generate_config(filename,
                        file,
                        max_line_length: int = 79,
                        line_ending_character: str = '\\n',
                        indent_size: int = SpacingHelper.DEFAULT_TAB_WIDTH,
                        use_spaces: bool = True,
                        allow_multiple_statements_per_line: bool = False,
                        force_lower_case_keywords: bool = True,
                        force_lower_case_constants: bool = True,
                        blank_line_after_namespace_declaration: bool = True,
                        check_use_blocks: bool = True,
                        check_class_declaration: bool = True,
                        check_property_declaration: bool = True,
                        force_scope_modifier_on_method: bool = True,
                        function_declaration_argument_spacing: int = 1,
                        allow_multiline_function_declaration: bool = True):
        """
        :param max_line_length:
            Maximum number of characters for a line.
        :param line_ending_character:
            Checks that end of line characters correspond to the one provided.
        :param indent_size:
            Number of spaces per indentation level.
        :param use_spaces:
            True if spaces are to be used instead of tabs.
        :param allow_multiple_statements_per_line:
            Allows having multiple statements on one line.
        :param force_lower_case_keyword:
            Checks that ``PHP`` keywords are lowercase.
        :param force_lower_case_constant:
            Checks that all uses of ``true``, ``false`` and ``null`` are
            lowercase.
        :param blank_line_after_namespace_declaration:
            Ensures that there is a blank line after a namespace declaration.
        :param check_use_blocks:
            Ensures that there is one blank line after a ``use`` block,
            that there is only one use block per line, and that all ``use``
            declaration are done after namespaces declaration.
        :param check_class_declaration:
            Ensures that ``extends`` and ``implements`` keywords are declared
            on the same line as the class name, that the opening brace for a
            class is on the next line, and that the closing brace for a class
            is on the next line after the body. Allows splitting implements
            list accross multiple lines.
        :param check_property_declaration:
            Ensures that visibility is declared on all properties, that the
            ``var`` keyword is not used to declare a property, that there is
            not more that one property declared on a line, that properties are
            not prefixed with an underscore.
        :param force_scope_modifier_on_method:
            Verifies that class methods have scope modifiers.
        :param function_declaration_argument_spacing:
            Number of spaces between arguments in function declaration.
        :param allow_multiline_function_declaration:
            Allows argument lists to be split accross multiple lines correctly
            indented.
        """
        rules_map = {
            'Generic.WhiteSpace.DisallowTabIndent':
            use_spaces,
            'Generic.Formatting.DisallowMultipleStatements':
            not allow_multiple_statements_per_line,
            'Generic.PHP.LowerCaseKeyword':
            force_lower_case_keywords,
            'Generic.PHP.LowerCaseConstant':
            force_lower_case_constants,
            'PSR2.Namespaces.UseDeclaration':
            check_use_blocks,
            'PSR2.Namespaces.NamespaceDeclaration':
            blank_line_after_namespace_declaration,
            'PSR2.Classes.ClassDeclaration':
            check_class_declaration,
            'PSR2.Classes.PropertyDeclaration':
            check_property_declaration,
            'Squiz.Scope.MethodScope':
            force_scope_modifier_on_method,
            'Squiz.Functions.MultiLineFunctionDeclaration':
            allow_multiline_function_declaration
        }
        rules = ''
        for k, v in rules_map.items():
            rules += '<rule ref="{}"/>\n'.format(k) if v else ''
        configs = '''<?xml version="1.0"?>
<ruleset name="Custom Standard">
 <description>A custom coding standard</description>
 <!-- Include the whole PSR-1 standard -->
 <rule ref="PSR1"/>
 <rule ref="Generic.Files.LineLength">
  <properties>
   <property name="lineLimit" value="{max_line_length}"/>
   <property name="absoluteLineLimit" value="{absolute_line_length}"/>
  </properties>
 </rule>
 <rule ref="Generic.Files.LineEndings">
  <properties>
   <property name="eolChar" value="{line_ending_character}"/>
  </properties>
 </rule>
 <rule ref="Generic.WhiteSpace.ScopeIndent">
  <properties>
   <property name="ignoreIndentationTokens" type="array"
   value="T_COMMENT,T_DOC_COMMENT_OPEN_TAG"/>
  </properties>
  <properties>
   <property name="indent" value="{indent_size}"/>
  </properties>
  <properties>
   <property name="exact" value="true"/>
  </properties>
 </rule>
 {some_rules}
 <rule ref="Squiz.WhiteSpace.ScopeKeywordSpacing"/>
 <rule ref="Squiz.Functions.FunctionDeclarationArgumentSpacing">
  <properties>
   <property name="equalsSpacing"
   value="{function_declaration_argument_spacing}"/>
  </properties>
 </rule>
 <rule
 ref="Squiz.Functions.FunctionDeclarationArgumentSpacing.SpacingAfterHint">
  <severity>0</severity>
 </rule>
</ruleset>
'''.format(max_line_length=max_line_length,
           absolute_line_length=0,
           line_ending_character=line_ending_character,
           indent_size=indent_size,
           some_rules=rules,
           function_declaration_argument_spacing=(
               function_declaration_argument_spacing))
        return configs
Пример #7
0
class FormatRBear:
    """
    Check and correct formatting of R Code using known formatR utility.
    """
    LANGUAGES = {'R'}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    REQUIREMENTS = {
        AnyOneOfRequirements(
            [DistributionRequirement(
                apt_get='r-cran-formatr',
                zypper='R-formatR',
             ),
             RscriptRequirement('formatR'),
             ]
        )
    }
    LICENSE = 'AGPL-3.0'
    ASCIINEMA_URL = 'https://asciinema.org/a/0y0oxtak18v492jdyfqwpw1n4'
    CAN_FIX = {'Formatting'}

    @staticmethod
    @deprecate_settings(indent_size='tab_width')
    def create_arguments(filename, file, config_file,
                         r_keep_comments: bool = True,
                         r_keep_blank_lines: bool = True,
                         r_braces_on_next_line: bool = None,
                         r_use_arrows: bool = None,
                         indent_size:
                             int = SpacingHelper.DEFAULT_TAB_WIDTH,
                         r_max_expression_length: int = 0,
                         ):
        """
        :param r_keep_comments:
            Determines whether comments are kept or not.
        :param r_keep_blank_lines:
            Determines whether blank lines are kept or not.
        :param r_braces_on_next_line:
            Determines whether a brace should be placed on the next line.

            Example:
            If ``True``::

                if (...) {

            changes to::

                if (...)
                {

            If ``False`` the brace is placed on the same line.
        :param r_use_arrows:
            Determines whether the assignment operator ``=`` should be replaced
            by an arrow ``<-`` or not.

            Example: If  ``True``, ``x = 1`` changes to ``x <- 1``.
        :param indent_size:
            Number of spaces per indentation level.
        :param r_max_expression_length:
            Maximum number of characters for an expression.

            Example: If ``20`` then::

                1 + 1 + 1 + 1 + 1 + 1 + 1

            changes to::

                1 + 1 + 1 + 1 + 1 + 1 +
                    1
        """
        options = {'source="' + escape(filename, '"\\') + '"',
                   'blank=' + _map_to_r_bool(r_keep_blank_lines),
                   'comment=' + _map_to_r_bool(r_keep_comments),
                   'indent=' + str(indent_size)}
        if r_max_expression_length:
            options.add('width.cutoff=' + str(r_max_expression_length))
        if r_braces_on_next_line is not None:
            options.add('brace.newline=' +
                        _map_to_r_bool(r_braces_on_next_line))
        if r_use_arrows is not None:
            options.add('arrow=' + _map_to_r_bool(r_use_arrows))

        rcode = 'library(formatR);formatR::tidy_source({})'.format(
            ','.join(options))
        return '-e', rcode
Пример #8
0
class CPDBear(GlobalBear):

    language_dict = {
        'C#': 'cs',
        'CPP': 'cpp',
        'JavaScript': 'ecmascript',
        'Fortran': 'fortran',
        'Go': 'go',
        'Java': 'java',
        'JSP': 'jsp',
        'Matlab': 'matlab',
        'Octave': 'matlab',
        'Objective-C': 'objectivec',
        'PHP': 'php',
        'PLSQL': 'plsql',
        'Python': 'python',
        'Python 2': 'python',
        'Python 3': 'python',
        'Ruby': 'ruby',
        'Scala': 'scala',
        'Swift': 'swift'
    }

    LANGUAGES = set(language_dict.keys())
    REQUIREMENTS = {
        AnyOneOfRequirements([
            ExecutableRequirement('cpd'),
            ExecutableRequirement('run.sh'),
        ]),
    }
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Duplication'}

    def run(
        self,
        language: language,
        minimum_tokens: int = 20,
        ignore_annotations: bool = False,
        ignore_identifiers: bool = True,
        ignore_literals: bool = False,
        ignore_usings: bool = False,
        skip_duplicate_files: bool = True,
    ):
        """
        Checks for similar code that looks as it could be replaced to reduce
        redundancy.

        For more details see:
        <https://pmd.github.io/pmd-6.4.0/pmd_userdocs_cpd.html>

        :param language:
            One of the supported languages of this bear.
        :param minimum_tokens:
            The minimum token length which should be reported as a duplicate.
        :param ignore_annotations:
            Ignore language annotations when comparing text.
        :param ignore_identifiers:
            Ignore constant and variable names when comparing text.
        :param ignore_literals:
            Ignore number values and string contents when comparing text.
        :param ignore_usings:
            Ignore ``using`` directives in C#.
        :param skip_duplicate_files:
            Ignore multiple copies of files of the same name and length in
            comparison.
        """
        for supported_lang in self.language_dict:
            if supported_lang in language:
                cpd_language = self.language_dict[supported_lang]
                break
        else:
            self.err('This bear does not support files with the extension '
                     "'{}'.".format(language))
            return

        options = {
            '--ignore-annotations': ignore_annotations,
            '--ignore-identifiers': ignore_identifiers,
            '--ignore-literals': ignore_literals,
            '--ignore-usings': ignore_usings,
            '--skip-duplicate-files': skip_duplicate_files
        }

        files = ','.join(self.file_dict.keys())
        executable = which('cpd') or which('run.sh')
        executable = tuple([executable] if not executable.endswith('run.sh')
                           else [executable, 'cpd'])

        arguments = ('--skip-lexical-errors', '--minimum-tokens',
                     str(minimum_tokens), '--language', cpd_language,
                     '--files', files, '--format', 'xml')

        arguments += tuple(option for option, enable in options.items()
                           if enable is True)

        arguments = executable + arguments
        stdout_output, _ = run_shell_command(arguments)

        if stdout_output:
            root = ElementTree.fromstring(stdout_output)

            for duplication in root.findall('duplication'):
                length = int(duplication.attrib['lines'])
                affected_code = list()

                for xml_file in duplication.findall('file'):
                    filename = xml_file.attrib['path']
                    start_line = int(xml_file.attrib['line'])
                    end_line = min(start_line + length - 1,
                                   len(self.file_dict[filename]))

                    affected_code.append(
                        SourceRange.from_values(filename,
                                                start_line=start_line,
                                                end_line=end_line))

                yield Result(
                    self,
                    'Duplicate code found.',
                    affected_code,
                    additional_info=(
                        'Duplicate code is an indicator '
                        'that you have more code than you need. Consider'
                        ' refactor your code to remove one of the'
                        ' occurrences. For more information go here:'
                        'http://tinyurl.com/coala-clone'))
Пример #9
0
class DistributionRequirement(PackageRequirement):
    """
    This class is a subclass of ``PackageRequirement``. It specifies the
    proper type automatically.
    """
    """
    List of supported package manager with their command respectively
    """
    SUPPORTED_PACKAGE_MANAGERS = {
        'apt_get': 'apt-get',
        'brew': 'brew',
        'dnf': 'dnf',
        'pacman': 'pacman',
        'portage': 'emerge',
        'xbps': 'xbps-install',
        'yum': 'yum',
        'zypper': 'zypper',
    }
    _available_managers = None

    REQUIREMENTS = {
        AnyOneOfRequirements(
            list(
                ExecutableRequirement(name)
                for name in SUPPORTED_PACKAGE_MANAGERS.values())),
        ExecutableRequirement('grep'),
    }
    """
    List of commands that can be used to verify if the package is installed.
    """
    CHECKER_COMMANDS = {
        'apt_get': 'dpkg-query -l {}',
        'brew': 'brew list {}',
        'dnf': 'rpm -qa | grep "^{}"',
        'pacman': 'pacman -Qs {}',
        'portage': 'equery list {}',
        'xbps': 'xbps-query {}',
        'yum': 'rpm -qa | grep "^{}"',
        'zypper': 'rpm -qa | grep "^{}"',
    }
    """
    List of commands that can be used to install a package.
    """
    _INSTALL_COMMANDS = {
        'apt_get': ('apt-get', 'install', '--yes'),
        'brew': ('brew', 'install'),
        'dnf': ('dnf', 'install', '--assumeyes'),
        'pacman': ('pacman', ),
        'portage': ('emerge', ),
        'xbps': ('xbps-install', '--yes'),
        'yum': ('yum', 'install', '--assumeyes'),
        'zypper': ('zypper', '--non-interactive', 'install'),
    }

    def __init__(self,
                 package: str = None,
                 version='',
                 repo='',
                 **package_overrides):
        """
        Constructs a new ``DistributionRequirement``, using the
        ``PackageRequirement`` constructor.

        When a ``package`` name is provided, it is used as the
        package attribute, even when override package names are
        provided for specific package managers.

        >>> dr = DistributionRequirement(package='clang',
        ...                              apt_get='libclang',
        ...                              dnf='libclangg')
        >>> dr.package
        'clang'
        >>> dr.packages['apt_get']
        'libclang'
        >>> dr.packages['dnf']
        'libclangg'

        When no ``package`` name is provided, the override package name
        for the local host's package manager is used if possible,
        otherwise the most common override is used.

        >>> dr = DistributionRequirement(unknown1='libclangg',
        ...                              unknown2='libclang',
        ...                              unknown3='libclang')
        >>> dr.package
        'libclang'
        >>> dr.packages['unknown1']
        'libclangg'
        >>> dr.packages['unknown2']
        'libclang'
        >>> dr.packages['unknown3']
        'libclang'

        >>> from pprint import pprint
        >>> len(dr.REQUIREMENTS)
        2
        >>> not_grep_req = [dep for dep in dr.REQUIREMENTS
        ...                 if str(dep) != 'grep'][0]
        >>> pprint(str(not_grep_req))
        ('ExecutableRequirement(apt-get) ExecutableRequirement(brew) '
         'ExecutableRequirement(dnf) ExecutableRequirement(emerge) '
         'ExecutableRequirement(pacman) ExecutableRequirement(xbps-install) '
         'ExecutableRequirement(yum) ExecutableRequirement(zypper)')

        :param package: A string with the name of the package to be installed.
        :param version: A version string.  Unused.
        :param repo:    The repository from which the package is to be
                        installed.  Unused.
        :param kwargs: Override package names for supported package managers.
        """
        self._managers = None
        self._manager = None
        self.packages = package_overrides

        if not package and not package_overrides:
            raise NoArgsNotImplementedError('No package managers specified')

        if package:
            defaults = {(pm, package)
                        for pm in self.SUPPORTED_PACKAGE_MANAGERS.keys()
                        if pm not in package_overrides}
            self.packages.update(defaults)

        else:
            package = self._get_best_package_name()

        PackageRequirement.__init__(self, 'distribution', package, version)

    def _get_best_package_name(self):
        package_names = Counter(self.packages.values())

        if len(package_names) == 1:
            return package_names.most_common()[0][0]

        try:
            return self.packages[self.get_available_package_manager()]
        except NotImplementedError:
            return package_names.most_common()[0][0]

    def get_available_package_manager(self):
        """
        Returns the available package manager that can be used to satisfy
        the requirement.

        Raises NotImplementedError if there's no supported package manager.

        :return: Supported package manager key
        """
        if not self._manager:
            self._manager = next(self.get_package_managers())
        return self._manager

    def get_package_managers(self):
        """
        Yield package managers that can satisfy requirement.

        :raises NotImplementedError:
             There are no package managers for requirement.
        """
        found = False
        available_managers = self.available_package_managers
        supported_managers = self.SUPPORTED_PACKAGE_MANAGERS.keys()
        for manager in self.packages.keys():
            if manager in available_managers:
                found = True
                yield manager
            elif manager not in supported_managers:
                raise NotImplementedError(
                    "{} is not supported".format(manager))
        if found:
            return

        raise NotImplementedError("This platform doesn't have any of the "
                                  'specified package manager(s): '
                                  '{}'.format(','.join(self.packages.keys())))

    @property
    def package_managers(self):
        """
        Return package managers that can satisfy requirement.

        :raises NotImplementedError:
             There are no package managers for requirement.
        """
        if self._managers is None:
            self._managers = list(self.get_package_managers())
        return self._managers

    @property
    def available_package_managers(self):
        """
        Return all available package managers.

        :raises NotImplementedError:
             There are no package managers for requirement.
        """
        if self._available_managers is None:
            self._available_managers = list(
                self.get_all_available_package_managers())
        return self._available_managers

    @classmethod
    def get_all_available_package_managers(self):
        """
        Yield the available package managers.

        :raises NotImplementedError:
            There are no supported package managers.
        """
        found = False
        for manager, exe in self.SUPPORTED_PACKAGE_MANAGERS.items():
            if is_executable_exists(exe):
                found = True
                yield manager
        if found:
            return

        raise NotImplementedError(
            "This platform doesn't have any of the supported package "
            'manager(s): {}'.format(', '.join(
                self.SUPPORTED_PACKAGE_MANAGERS)))

    def is_installed(self):
        """
        Check if the requirement is satisfied by calling various package
        managers that are mentioned.

        Raises NotImplementedError if executable is not defined when
        there's no supported package manager.

        :return: True if the dependency is installed, false otherwise
        """

        package_manager = self.get_available_package_manager()
        command = self.CHECKER_COMMANDS[package_manager]
        package = self.packages[package_manager]
        return not run(command.format(package),
                       stdout=Capture(),
                       stderr=Capture()).returncode

    def install_command(self):
        """
        Creates the installation command for the instance of the class.

        >>> DistributionRequirement('indent').install_command()[-1]
        'indent'

        :param return: A list with the installation command.
        """
        package_manager = self.get_available_package_manager()
        package = self.packages[package_manager]

        command = list(self._INSTALL_COMMANDS[package_manager])

        command.append(package)

        return command