Exemplo n.º 1
0
def _run_hooks(config, hooks, args, environ):
    """Actually run the hooks."""
    skips = _get_skips(environ)
    cols = _compute_cols(hooks, args.verbose)
    filenames = _all_filenames(args)
    filenames = filter_by_include_exclude(filenames, '', config['exclude'])
    classifier = Classifier(filenames)
    retval = 0
    for hook in hooks:
        retval |= _run_single_hook(classifier, hook, args, skips, cols)
        if retval and config['fail_fast']:
            break
    if retval and args.show_diff_on_failure and git.has_diff():
        if args.all_files:
            output.write_line(
                'pre-commit hook(s) made changes.\n'
                'If you are seeing this message in CI, '
                'reproduce locally with: `pre-commit run --all-files`.\n'
                'To run `pre-commit` as part of git workflow, use '
                '`pre-commit install`.',
            )
        output.write_line('All changes made by hooks:')
        # args.color is a boolean.
        # See user_color function in color.py
        subprocess.call((
            'git', '--no-pager', 'diff', '--no-ext-diff',
            '--color={}'.format({True: 'always', False: 'never'}[args.color]),
        ))

    return retval
Exemplo n.º 2
0
def clean(store):
    legacy_path = os.path.expanduser('~/.pre-commit')
    for directory in (store.directory, legacy_path):
        if os.path.exists(directory):
            rmtree(directory)
            output.write_line('Cleaned {}.'.format(directory))
    return 0
Exemplo n.º 3
0
def install(
        config_file, store,
        overwrite=False, hooks=False, hook_type='pre-commit',
        skip_on_missing_conf=False,
):
    """Install the pre-commit hooks."""
    if cmd_output('git', 'config', 'core.hooksPath', retcode=None)[1].strip():
        logger.error(
            'Cowardly refusing to install hooks with `core.hooksPath` set.\n'
            'hint: `git config --unset-all core.hooksPath`',
        )
        return 1

    hook_path, legacy_path = _hook_paths(hook_type)

    mkdirp(os.path.dirname(hook_path))

    # If we have an existing hook, move it to pre-commit.legacy
    if os.path.lexists(hook_path) and not is_our_script(hook_path):
        shutil.move(hook_path, legacy_path)

    # If we specify overwrite, we simply delete the legacy file
    if overwrite and os.path.exists(legacy_path):
        os.remove(legacy_path)
    elif os.path.exists(legacy_path):
        output.write_line(
            'Running in migration mode with existing hooks at {}\n'
            'Use -f to use only pre-commit.'.format(legacy_path),
        )

    params = {
        'CONFIG': config_file,
        'HOOK_TYPE': hook_type,
        'INSTALL_PYTHON': sys.executable,
        'SKIP_ON_MISSING_CONFIG': skip_on_missing_conf,
    }

    with io.open(hook_path, 'w') as hook_file:
        contents = resource_text('hook-tmpl')
        before, rest = contents.split(TEMPLATE_START)
        to_template, after = rest.split(TEMPLATE_END)

        before = before.replace('#!/usr/bin/env python3', shebang())

        hook_file.write(before + TEMPLATE_START)
        for line in to_template.splitlines():
            var = line.split()[0]
            hook_file.write('{} = {!r}\n'.format(var, params[var]))
        hook_file.write(TEMPLATE_END + after)
    make_executable(hook_path)

    output.write_line('pre-commit installed at {}'.format(hook_path))

    # If they requested we install all of the hooks, do so.
    if hooks:
        install_hooks(config_file, store)

    return 0
Exemplo n.º 4
0
def main(argv=None):
    parser = argparse.ArgumentParser()
    parser.add_argument('--dest', default='pre_commit/resources')
    args = parser.parse_args(argv)
    for archive_name, repo, ref in REPOS:
        output.write_line(
            'Making {}.tar.gz for {}@{}'.format(archive_name, repo, ref),
        )
        make_archive(archive_name, repo, ref, args.dest)
Exemplo n.º 5
0
def _process_filename_by_line(pattern, filename):
    retv = 0
    with open(filename, 'rb') as f:
        for line_no, line in enumerate(f, start=1):
            if pattern.search(line):
                retv = 1
                output.write('{}:{}:'.format(filename, line_no))
                output.write_line(line.rstrip(b'\r\n'))
    return retv
Exemplo n.º 6
0
def install(
        runner, overwrite=False, hooks=False, hook_type='pre-commit',
        skip_on_missing_conf=False,
):
    """Install the pre-commit hooks."""
    hook_path = runner.get_hook_path(hook_type)
    legacy_path = hook_path + '.legacy'

    mkdirp(os.path.dirname(hook_path))

    # If we have an existing hook, move it to pre-commit.legacy
    if os.path.lexists(hook_path) and not is_our_script(hook_path):
        os.rename(hook_path, legacy_path)

    # If we specify overwrite, we simply delete the legacy file
    if overwrite and os.path.exists(legacy_path):
        os.remove(legacy_path)
    elif os.path.exists(legacy_path):
        output.write_line(
            'Running in migration mode with existing hooks at {}\n'
            'Use -f to use only pre-commit.'.format(
                legacy_path,
            ),
        )

    with io.open(hook_path, 'w') as pre_commit_file_obj:
        if hook_type == 'pre-push':
            with io.open(resource_filename('pre-push-tmpl')) as f:
                hook_specific_contents = f.read()
        elif hook_type == 'commit-msg':
            with io.open(resource_filename('commit-msg-tmpl')) as f:
                hook_specific_contents = f.read()
        elif hook_type == 'pre-commit':
            hook_specific_contents = ''
        else:
            raise AssertionError('Unknown hook type: {}'.format(hook_type))

        skip_on_missing_conf = 'true' if skip_on_missing_conf else 'false'
        contents = io.open(resource_filename('hook-tmpl')).read().format(
            sys_executable=pipes.quote(sys.executable),
            hook_type=hook_type,
            hook_specific=hook_specific_contents,
            config_file=runner.config_file,
            skip_on_missing_conf=skip_on_missing_conf,
        )
        pre_commit_file_obj.write(contents)
    make_executable(hook_path)

    output.write_line('pre-commit installed at {}'.format(hook_path))

    # If they requested we install all of the hooks, do so.
    if hooks:
        install_hooks(runner)

    return 0
Exemplo n.º 7
0
def run(runner, args, environ=os.environ):
    no_stash = args.no_stash or args.all_files or bool(args.files)

    # Check if we have unresolved merge conflict files and fail fast.
    if _has_unmerged_paths(runner):
        logger.error('Unmerged files.  Resolve before committing.')
        return 1
    if bool(args.source) != bool(args.origin):
        logger.error('Specify both --origin and --source.')
        return 1
    if _has_unstaged_config(runner) and not no_stash:
        if args.allow_unstaged_config:
            logger.warn(
                'You have an unstaged config file and have specified the '
                '--allow-unstaged-config option.\n'
                'Note that your config will be stashed before the config is '
                'parsed unless --no-stash is specified.',
            )
        else:
            logger.error(
                'Your .pre-commit-config.yaml is unstaged.\n'
                '`git add .pre-commit-config.yaml` to fix this.\n'
                'Run pre-commit with --allow-unstaged-config to silence this.'
            )
            return 1

    # Expose origin / source as environment variables for hooks to consume
    if args.origin and args.source:
        environ['PRE_COMMIT_ORIGIN'] = args.origin
        environ['PRE_COMMIT_SOURCE'] = args.source

    if no_stash:
        ctx = noop_context()
    else:
        ctx = staged_files_only(runner.cmd_runner)

    with ctx:
        repo_hooks = list(get_repo_hooks(runner))

        if args.hook:
            repo_hooks = [
                (repo, hook) for repo, hook in repo_hooks
                if hook['id'] == args.hook
            ]
            if not repo_hooks:
                output.write_line('No hook with id `{}`'.format(args.hook))
                return 1

        # Filter hooks for stages
        repo_hooks = [
            (repo, hook) for repo, hook in repo_hooks
            if not hook['stages'] or args.hook_stage in hook['stages']
        ]

        return _run_hooks(repo_hooks, args, environ)
Exemplo n.º 8
0
 def emit(self, record):
     output.write_line(
         '{}{}'.format(
             color.format_color(
                 '[{}]'.format(record.levelname),
                 LOG_LEVEL_COLORS[record.levelname],
                 self.use_color,
             ) + ' ',
             record.getMessage(),
         ),
     )
Exemplo n.º 9
0
def _log_and_exit(msg, exc, formatted):
    error_msg = b''.join((
        five.to_bytes(msg), b': ',
        five.to_bytes(type(exc).__name__), b': ',
        _to_bytes(exc), b'\n',
    ))
    output.write(error_msg)
    store = Store()
    log_path = os.path.join(store.directory, 'pre-commit.log')
    output.write_line('Check the log at {}'.format(log_path))
    with open(log_path, 'wb') as log:
        output.write(error_msg, stream=log)
        output.write_line(formatted, stream=log)
    raise SystemExit(1)
Exemplo n.º 10
0
def try_repo(args):
    with tmpdir() as tempdir:
        repo, ref = _repo_ref(tempdir, args.repo, args.ref)

        store = Store(tempdir)
        if args.hook:
            hooks = [{'id': args.hook}]
        else:
            repo_path = store.clone(repo, ref)
            manifest = load_manifest(os.path.join(repo_path, C.MANIFEST_FILE))
            manifest = sorted(manifest, key=lambda hook: hook['id'])
            hooks = [{'id': hook['id']} for hook in manifest]

        items = (('repo', repo), ('rev', ref), ('hooks', hooks))
        config = {'repos': [collections.OrderedDict(items)]}
        config_s = ordered_dump(config, **C.YAML_DUMP_KWARGS)

        config_filename = os.path.join(tempdir, C.CONFIG_FILE)
        with open(config_filename, 'w') as cfg:
            cfg.write(config_s)

        output.write_line('=' * 79)
        output.write_line('Using config:')
        output.write_line('=' * 79)
        output.write(config_s)
        output.write_line('=' * 79)

        return run(config_filename, store, args)
Exemplo n.º 11
0
def _log_and_exit(msg, exc, formatted):
    error_msg = b''.join((
        five.to_bytes(msg), b': ',
        five.to_bytes(type(exc).__name__), b': ',
        _to_bytes(exc), b'\n',
    ))
    output.write(error_msg)
    output.write_line('Check the log at ~/.pre-commit/pre-commit.log')
    store = Store()
    store.require_created()
    with io.open(os.path.join(store.directory, 'pre-commit.log'), 'wb') as log:
        output.write(error_msg, stream=log)
        output.write_line(formatted, stream=log)
    raise PreCommitSystemExit(1)
Exemplo n.º 12
0
def _process_filename_at_once(pattern, filename):
    retv = 0
    with open(filename, 'rb') as f:
        contents = f.read()
        match = pattern.search(contents)
        if match:
            retv = 1
            line_no = contents[:match.start()].count(b'\n')
            output.write('{}:{}:'.format(filename, line_no + 1))

            matched_lines = match.group().split(b'\n')
            matched_lines[0] = contents.split(b'\n')[line_no]

            output.write_line(b'\n'.join(matched_lines))
    return retv
Exemplo n.º 13
0
def uninstall(runner, hook_type='pre-commit'):
    """Uninstall the pre-commit hooks."""
    hook_path = runner.get_hook_path(hook_type)
    legacy_path = hook_path + '.legacy'
    # If our file doesn't exist or it isn't ours, gtfo.
    if not os.path.exists(hook_path) or not is_our_script(hook_path):
        return 0

    os.remove(hook_path)
    output.write_line('{} uninstalled'.format(hook_type))

    if os.path.exists(legacy_path):
        os.rename(legacy_path, hook_path)
        output.write_line('Restored previous hooks to {}'.format(hook_path))

    return 0
Exemplo n.º 14
0
def run(runner, args, environ=os.environ):
    no_stash = args.all_files or bool(args.files)

    # Check if we have unresolved merge conflict files and fail fast.
    if _has_unmerged_paths():
        logger.error('Unmerged files.  Resolve before committing.')
        return 1
    if bool(args.source) != bool(args.origin):
        logger.error('Specify both --origin and --source.')
        return 1
    if _has_unstaged_config(runner) and not no_stash:
        logger.error(
            'Your .pre-commit-config.yaml is unstaged.\n'
            '`git add .pre-commit-config.yaml` to fix this.',
        )
        return 1

    # Expose origin / source as environment variables for hooks to consume
    if args.origin and args.source:
        environ['PRE_COMMIT_ORIGIN'] = args.origin
        environ['PRE_COMMIT_SOURCE'] = args.source

    if no_stash:
        ctx = noop_context()
    else:
        ctx = staged_files_only(runner.store.directory)

    with ctx:
        repo_hooks = list(get_repo_hooks(runner))

        if args.hook:
            repo_hooks = [
                (repo, hook) for repo, hook in repo_hooks
                if hook['id'] == args.hook
            ]
            if not repo_hooks:
                output.write_line('No hook with id `{}`'.format(args.hook))
                return 1

        # Filter hooks for stages
        repo_hooks = [
            (repo, hook) for repo, hook in repo_hooks
            if not hook['stages'] or args.hook_stage in hook['stages']
        ]

        return _run_hooks(runner.config, repo_hooks, args, environ)
Exemplo n.º 15
0
def run(config_file, store, args, environ=os.environ):
    no_stash = args.all_files or bool(args.files)

    # Check if we have unresolved merge conflict files and fail fast.
    if _has_unmerged_paths():
        logger.error('Unmerged files.  Resolve before committing.')
        return 1
    if bool(args.source) != bool(args.origin):
        logger.error('Specify both --origin and --source.')
        return 1
    if _has_unstaged_config(config_file) and not no_stash:
        logger.error(
            'Your pre-commit configuration is unstaged.\n'
            '`git add {}` to fix this.'.format(config_file),
        )
        return 1

    # Expose origin / source as environment variables for hooks to consume
    if args.origin and args.source:
        environ['PRE_COMMIT_ORIGIN'] = args.origin
        environ['PRE_COMMIT_SOURCE'] = args.source

    if no_stash:
        ctx = noop_context()
    else:
        ctx = staged_files_only(store.directory)

    with ctx:
        config = load_config(config_file)
        hooks = [
            hook
            for hook in all_hooks(config, store)
            if not args.hook or hook.id == args.hook or hook.alias == args.hook
            if args.hook_stage in hook.stages
        ]

        if args.hook and not hooks:
            output.write_line('No hook with id `{}`'.format(args.hook))
            return 1

        install_hook_envs(hooks, store)

        return _run_hooks(config, hooks, args, environ)
Exemplo n.º 16
0
    def run(argv=None):
        parser = argparse.ArgumentParser()
        parser.add_argument('filenames', nargs='*', help=filenames_help)
        parser.add_argument(
            '-V', '--version',
            action='version',
            version='%(prog)s {}'.format(
                pkg_resources.get_distribution('pre-commit').version
            )
        )

        args = parser.parse_args(argv)

        retval = 0
        for filename in args.filenames:
            try:
                validate_strategy(filename)
            except exception_cls as e:
                output.write_line(e.args[0])
                retval = 1
        return retval
Exemplo n.º 17
0
def autoupdate(config_file, store, tags_only, repos=()):
    """Auto-update the pre-commit config to the latest versions of repos."""
    migrate_config(config_file, quiet=True)
    retv = 0
    output_repos = []
    changed = False

    input_config = load_config(config_file)

    for repo_config in input_config['repos']:
        if (
            repo_config['repo'] in {LOCAL, META} or
            # Skip updating any repo_configs that aren't for the specified repo
            repos and repo_config['repo'] not in repos
        ):
            output_repos.append(repo_config)
            continue
        output.write('Updating {}...'.format(repo_config['repo']))
        try:
            new_repo_config = _update_repo(repo_config, store, tags_only)
        except RepositoryCannotBeUpdatedError as error:
            output.write_line(error.args[0])
            output_repos.append(repo_config)
            retv = 1
            continue

        if new_repo_config['rev'] != repo_config['rev']:
            changed = True
            output.write_line(
                'updating {} -> {}.'.format(
                    repo_config['rev'], new_repo_config['rev'],
                ),
            )
            output_repos.append(new_repo_config)
        else:
            output.write_line('already up to date.')
            output_repos.append(repo_config)

    if changed:
        output_config = input_config.copy()
        output_config['repos'] = output_repos
        _write_new_config_file(config_file, output_config)

    return retv
Exemplo n.º 18
0
def autoupdate(runner):
    """Auto-update the pre-commit config to the latest versions of repos."""
    retv = 0
    output_configs = []
    changed = False

    input_configs = load_config(
        runner.config_file_path,
        load_strategy=ordered_load,
    )

    for repo_config in input_configs:
        if is_local_hooks(repo_config):
            output_configs.append(repo_config)
            continue
        output.write('Updating {}...'.format(repo_config['repo']))
        try:
            new_repo_config = _update_repository(repo_config, runner)
        except RepositoryCannotBeUpdatedError as error:
            output.write_line(error.args[0])
            output_configs.append(repo_config)
            retv = 1
            continue

        if new_repo_config['sha'] != repo_config['sha']:
            changed = True
            output.write_line('updating {} -> {}.'.format(
                repo_config['sha'], new_repo_config['sha'],
            ))
            output_configs.append(new_repo_config)
        else:
            output.write_line('already up to date.')
            output_configs.append(repo_config)

    if changed:
        with open(runner.config_file_path, 'w') as config_file:
            config_file.write(
                ordered_dump(
                    remove_defaults(output_configs, CONFIG_JSON_SCHEMA),
                    **C.YAML_DUMP_KWARGS
                )
            )

    return retv
Exemplo n.º 19
0
def autoupdate(runner, tags_only):
    """Auto-update the pre-commit config to the latest versions of repos."""
    migrate_config(runner, quiet=True)
    retv = 0
    output_repos = []
    changed = False

    input_config = load_config(runner.config_file_path)

    for repo_config in input_config['repos']:
        if is_local_repo(repo_config):
            output_repos.append(repo_config)
            continue
        output.write('Updating {}...'.format(repo_config['repo']))
        try:
            new_repo_config = _update_repo(repo_config, runner, tags_only)
        except RepositoryCannotBeUpdatedError as error:
            output.write_line(error.args[0])
            output_repos.append(repo_config)
            retv = 1
            continue

        if new_repo_config['sha'] != repo_config['sha']:
            changed = True
            output.write_line('updating {} -> {}.'.format(
                repo_config['sha'], new_repo_config['sha'],
            ))
            output_repos.append(new_repo_config)
        else:
            output.write_line('already up to date.')
            output_repos.append(repo_config)

    if changed:
        output_config = input_config.copy()
        output_config['repos'] = output_repos
        _write_new_config_file(runner.config_file_path, output_config)

    return retv
Exemplo n.º 20
0
def _run_single_hook(filenames, hook, repo, args, skips, cols):
    include, exclude = hook['files'], hook['exclude']
    filenames = _filter_by_include_exclude(filenames, include, exclude)
    types, exclude_types = hook['types'], hook['exclude_types']
    filenames = _filter_by_types(filenames, types, exclude_types)
    if hook['id'] in skips:
        output.write(
            get_hook_message(
                _hook_msg_start(hook, args.verbose),
                end_msg=SKIPPED,
                end_color=color.YELLOW,
                use_color=args.color,
                cols=cols,
            ))
        return 0
    elif not filenames and not hook['always_run']:
        output.write(
            get_hook_message(
                _hook_msg_start(hook, args.verbose),
                postfix=NO_FILES,
                end_msg=SKIPPED,
                end_color=color.TURQUOISE,
                use_color=args.color,
                cols=cols,
            ))
        return 0

    # Print the hook and the dots first in case the hook takes hella long to
    # run.
    output.write(
        get_hook_message(
            _hook_msg_start(hook, args.verbose),
            end_len=6,
            cols=cols,
        ))
    sys.stdout.flush()

    diff_before = cmd_output(
        'git',
        'diff',
        '--no-ext-diff',
        retcode=None,
        encoding=None,
    )
    retcode, stdout, stderr = repo.run_hook(
        hook,
        tuple(filenames) if hook['pass_filenames'] else (),
    )
    diff_after = cmd_output(
        'git',
        'diff',
        '--no-ext-diff',
        retcode=None,
        encoding=None,
    )

    file_modifications = diff_before != diff_after

    # If the hook makes changes, fail the commit
    if file_modifications:
        retcode = 1

    if retcode:
        retcode = 1
        print_color = color.RED
        pass_fail = 'Failed'
    else:
        retcode = 0
        print_color = color.GREEN
        pass_fail = 'Passed'

    output.write_line(color.format_color(pass_fail, print_color, args.color))

    if (stdout or stderr or file_modifications) and (retcode or args.verbose):
        output.write_line('hookid: {}\n'.format(hook['id']))

        # Print a message if failing due to file modifications
        if file_modifications:
            output.write('Files were modified by this hook.')

            if stdout or stderr:
                output.write_line(' Additional output:')

            output.write_line()

        for out in (stdout, stderr):
            assert type(out) is bytes, type(out)
            if out.strip():
                output.write_line(out.strip(), logfile_name=hook['log_file'])
        output.write_line()

    return retcode
Exemplo n.º 21
0
def main():
    for archive_name, repo, ref in REPOS:
        output.write_line('Making {}.tar.gz for {}@{}'.format(
            archive_name, repo, ref,
        ))
        make_archive(archive_name, repo, ref, RESOURCES_DIR)
Exemplo n.º 22
0
def gc(store):
    with store.exclusive_lock():
        repos_removed = _gc_repos(store)
    output.write_line('{} repo(s) removed.'.format(repos_removed))
    return 0
from pre_commit.output import write_line

write_line("msg1")
print("msg2")
Exemplo n.º 24
0
 def _log_line(*s):  # type: (*str) -> None
     output.write_line(*s, stream=log)
            # skip html stuff
            elif re.match(r"({% (extends|block)|<!--).*", line):
                continue
            else:
                h_lines.append(line)

            if len(h_lines) == 3:
                break
    return h_lines


if __name__ == "__main__":
    retv = 0
    for filename in sys.argv[1:]:
        filepath = Path(filename)
        if not filepath.is_file():
            continue

        header_lines = get_header_lines(filepath)
        if len(header_lines) < 3:
            retv |= 1
            output.write_line(f"{filename}: (not enough lines)")
        else:
            header = "".join(header_lines)
            if header != EXPECTED_HEADER:
                retv |= 1
                output.write(f"{filename}:\n  {'  '.join(header_lines)}")
            else:
                retv |= 0
    sys.exit(retv)
Exemplo n.º 26
0
def _run_single_hook(classifier, hook, args, skips, cols):
    filenames = classifier.filenames_for_hook(hook)

    if hook.language == 'pcre':
        logger.warning(
            '`{}` (from {}) uses the deprecated pcre language.\n'
            'The pcre language is scheduled for removal in pre-commit 2.x.\n'
            'The pygrep language is a more portable (and usually drop-in) '
            'replacement.'.format(hook.id, hook.src),
        )

    if hook.id in skips or hook.alias in skips:
        output.write(
            get_hook_message(
                _hook_msg_start(hook, args.verbose),
                end_msg=SKIPPED,
                end_color=color.YELLOW,
                use_color=args.color,
                cols=cols,
            ),
        )
        return 0
    elif not filenames and not hook.always_run:
        output.write(
            get_hook_message(
                _hook_msg_start(hook, args.verbose),
                postfix=NO_FILES,
                end_msg=SKIPPED,
                end_color=color.TURQUOISE,
                use_color=args.color,
                cols=cols,
            ),
        )
        return 0

    # Print the hook and the dots first in case the hook takes hella long to
    # run.
    output.write(
        get_hook_message(
            _hook_msg_start(hook, args.verbose), end_len=6, cols=cols,
        ),
    )
    sys.stdout.flush()

    diff_before = cmd_output(
        'git', 'diff', '--no-ext-diff', retcode=None, encoding=None,
    )
    retcode, stdout, stderr = hook.run(
        tuple(filenames) if hook.pass_filenames else (),
    )
    diff_after = cmd_output(
        'git', 'diff', '--no-ext-diff', retcode=None, encoding=None,
    )

    file_modifications = diff_before != diff_after

    # If the hook makes changes, fail the commit
    if file_modifications:
        retcode = 1

    if retcode:
        retcode = 1
        print_color = color.RED
        pass_fail = 'Failed'
    else:
        retcode = 0
        print_color = color.GREEN
        pass_fail = 'Passed'

    output.write_line(color.format_color(pass_fail, print_color, args.color))

    if (
            (stdout or stderr or file_modifications) and
            (retcode or args.verbose or hook.verbose)
    ):
        output.write_line('hookid: {}\n'.format(hook.id))

        # Print a message if failing due to file modifications
        if file_modifications:
            output.write('Files were modified by this hook.')

            if stdout or stderr:
                output.write_line(' Additional output:')

            output.write_line()

        for out in (stdout, stderr):
            assert type(out) is bytes, type(out)
            if out.strip():
                output.write_line(out.strip(), logfile_name=hook.log_file)
        output.write_line()

    return retcode
Exemplo n.º 27
0
def _run_single_hook(classifier, hook, args, skips, cols):
    filenames = classifier.filenames_for_hook(hook)

    if hook.language == 'pcre':
        logger.warning(
            '`{}` (from {}) uses the deprecated pcre language.\n'
            'The pcre language is scheduled for removal in pre-commit 2.x.\n'
            'The pygrep language is a more portable (and usually drop-in) '
            'replacement.'.format(hook.id, hook.src),
        )

    if hook.id in skips or hook.alias in skips:
        output.write(get_hook_message(
            _hook_msg_start(hook, args.verbose),
            end_msg=SKIPPED,
            end_color=color.YELLOW,
            use_color=args.color,
            cols=cols,
        ))
        return 0
    elif not filenames and not hook.always_run:
        output.write(get_hook_message(
            _hook_msg_start(hook, args.verbose),
            postfix=NO_FILES,
            end_msg=SKIPPED,
            end_color=color.TURQUOISE,
            use_color=args.color,
            cols=cols,
        ))
        return 0

    # Print the hook and the dots first in case the hook takes hella long to
    # run.
    output.write(get_hook_message(
        _hook_msg_start(hook, args.verbose), end_len=6, cols=cols,
    ))
    sys.stdout.flush()

    diff_before = cmd_output(
        'git', 'diff', '--no-ext-diff', retcode=None, encoding=None,
    )
    retcode, stdout, stderr = hook.run(
        tuple(filenames) if hook.pass_filenames else (),
    )
    diff_after = cmd_output(
        'git', 'diff', '--no-ext-diff', retcode=None, encoding=None,
    )

    file_modifications = diff_before != diff_after

    # If the hook makes changes, fail the commit
    if file_modifications:
        retcode = 1

    if retcode:
        retcode = 1
        print_color = color.RED
        pass_fail = 'Failed'
    else:
        retcode = 0
        print_color = color.GREEN
        pass_fail = 'Passed'

    output.write_line(color.format_color(pass_fail, print_color, args.color))

    if (
            (stdout or stderr or file_modifications) and
            (retcode or args.verbose or hook.verbose)
    ):
        output.write_line('hookid: {}\n'.format(hook.id))

        # Print a message if failing due to file modifications
        if file_modifications:
            output.write('Files were modified by this hook.')

            if stdout or stderr:
                output.write_line(' Additional output:')

            output.write_line()

        for out in (stdout, stderr):
            assert type(out) is bytes, type(out)
            if out.strip():
                output.write_line(out.strip(), logfile_name=hook.log_file)
        output.write_line()

    return retcode
Exemplo n.º 28
0
def _run_single_hook(hook, repo, args, skips, cols):
    filenames = get_filenames(args, hook.get('files', '^$'), hook['exclude'])
    if hook['id'] in skips:
        output.write(get_hook_message(
            _hook_msg_start(hook, args.verbose),
            end_msg=SKIPPED,
            end_color=color.YELLOW,
            use_color=args.color,
            cols=cols,
        ))
        return 0
    elif not filenames and not hook['always_run']:
        output.write(get_hook_message(
            _hook_msg_start(hook, args.verbose),
            postfix=NO_FILES,
            end_msg=SKIPPED,
            end_color=color.TURQUOISE,
            use_color=args.color,
            cols=cols,
        ))
        return 0

    # Print the hook and the dots first in case the hook takes hella long to
    # run.
    output.write(get_hook_message(
        _hook_msg_start(hook, args.verbose), end_len=6, cols=cols,
    ))
    sys.stdout.flush()

    diff_before = cmd_output(
        'git', 'diff', '--no-ext-diff', retcode=None, encoding=None,
    )
    retcode, stdout, stderr = repo.run_hook(
        hook,
        tuple(filenames) if hook['pass_filenames'] else (),
    )
    diff_after = cmd_output(
        'git', 'diff', '--no-ext-diff', retcode=None, encoding=None,
    )

    file_modifications = diff_before != diff_after

    # If the hook makes changes, fail the commit
    if file_modifications:
        retcode = 1

    if retcode:
        retcode = 1
        print_color = color.RED
        pass_fail = 'Failed'
    else:
        retcode = 0
        print_color = color.GREEN
        pass_fail = 'Passed'

    output.write_line(color.format_color(pass_fail, print_color, args.color))

    if (stdout or stderr or file_modifications) and (retcode or args.verbose):
        output.write_line('hookid: {}\n'.format(hook['id']))

        # Print a message if failing due to file modifications
        if file_modifications:
            output.write('Files were modified by this hook.')

            if stdout or stderr:
                output.write_line(' Additional output:')

            output.write_line()

        for out in (stdout, stderr):
            assert type(out) is bytes, type(out)
            if out.strip():
                output.write_line(out.strip(), logfile_name=hook['log_file'])
        output.write_line()

    return retcode
Exemplo n.º 29
0
def main(argv=None):
    argv = argv if argv is not None else sys.argv[1:]
    for arg in argv:
        output.write_line(arg)
Exemplo n.º 30
0
def main(argv: Optional[Sequence[str]] = None) -> int:
    argv = argv if argv is not None else sys.argv[1:]
    for arg in argv:
        output.write_line(arg)
    return 0
Exemplo n.º 31
0
def _run_single_hook(
        classifier: Classifier,
        hook: Hook,
        skips: Set[str],
        cols: int,
        diff_before: bytes,
        verbose: bool,
        use_color: bool,
) -> Tuple[bool, bytes]:
    filenames = classifier.filenames_for_hook(hook)

    if hook.id in skips or hook.alias in skips:
        output.write(
            _full_msg(
                start=hook.name,
                end_msg=SKIPPED,
                end_color=color.YELLOW,
                use_color=use_color,
                cols=cols,
            ),
        )
        duration = None
        retcode = 0
        diff_after = diff_before
        files_modified = False
        out = b''
    elif not filenames and not hook.always_run:
        output.write(
            _full_msg(
                start=hook.name,
                postfix=NO_FILES,
                end_msg=SKIPPED,
                end_color=color.TURQUOISE,
                use_color=use_color,
                cols=cols,
            ),
        )
        duration = None
        retcode = 0
        diff_after = diff_before
        files_modified = False
        out = b''
    else:
        # print hook and dots first in case the hook takes a while to run
        output.write(_start_msg(start=hook.name, end_len=6, cols=cols))

        if not hook.pass_filenames:
            filenames = ()
        time_before = time.time()
        language = languages[hook.language]
        retcode, out = language.run_hook(hook, filenames, use_color)
        duration = round(time.time() - time_before, 2) or 0
        diff_after = _get_diff()

        # if the hook makes changes, fail the commit
        files_modified = diff_before != diff_after

        if retcode or files_modified:
            print_color = color.RED
            status = 'Failed'
        else:
            print_color = color.GREEN
            status = 'Passed'

        output.write_line(color.format_color(status, print_color, use_color))

    if verbose or hook.verbose or retcode or files_modified:
        _subtle_line(f'- hook id: {hook.id}', use_color)

        if (verbose or hook.verbose) and duration is not None:
            _subtle_line(f'- duration: {duration}s', use_color)

        if retcode:
            _subtle_line(f'- exit code: {retcode}', use_color)

        # Print a message if failing due to file modifications
        if files_modified:
            _subtle_line('- files were modified by this hook', use_color)

        if out.strip():
            output.write_line()
            output.write_line_b(out.strip(), logfile_name=hook.log_file)
            output.write_line()

    return files_modified or bool(retcode), diff_after
Exemplo n.º 32
0
def run(
        config_file: str,
        store: Store,
        args: argparse.Namespace,
        environ: MutableMapping[str, str] = os.environ,
) -> int:
    stash = not args.all_files and not args.files

    # Check if we have unresolved merge conflict files and fail fast.
    if _has_unmerged_paths():
        logger.error('Unmerged files.  Resolve before committing.')
        return 1
    if bool(args.from_ref) != bool(args.to_ref):
        logger.error('Specify both --from-ref and --to-ref.')
        return 1
    if stash and _has_unstaged_config(config_file):
        logger.error(
            f'Your pre-commit configuration is unstaged.\n'
            f'`git add {config_file}` to fix this.',
        )
        return 1
    if (
            args.hook_stage in {'prepare-commit-msg', 'commit-msg'} and
            not args.commit_msg_filename
    ):
        logger.error(
            f'`--commit-msg-filename` is required for '
            f'`--hook-stage {args.hook_stage}`',
        )
        return 1
    # prevent recursive post-checkout hooks (#1418)
    if (
            args.hook_stage == 'post-checkout' and
            environ.get('_PRE_COMMIT_SKIP_POST_CHECKOUT')
    ):
        return 0

    # Expose from-ref / to-ref as environment variables for hooks to consume
    if args.from_ref and args.to_ref:
        # legacy names
        environ['PRE_COMMIT_ORIGIN'] = args.from_ref
        environ['PRE_COMMIT_SOURCE'] = args.to_ref
        # new names
        environ['PRE_COMMIT_FROM_REF'] = args.from_ref
        environ['PRE_COMMIT_TO_REF'] = args.to_ref

    if args.remote_name and args.remote_url and args.remote_branch:
        environ['PRE_COMMIT_REMOTE_BRANCH'] = args.remote_branch
        environ['PRE_COMMIT_REMOTE_NAME'] = args.remote_name
        environ['PRE_COMMIT_REMOTE_URL'] = args.remote_url

    if args.checkout_type:
        environ['PRE_COMMIT_CHECKOUT_TYPE'] = args.checkout_type

    if args.is_squash_merge:
        environ['PRE_COMMIT_IS_SQUASH_MERGE'] = args.is_squash_merge

    # Set pre_commit flag
    environ['PRE_COMMIT'] = '1'

    with contextlib.ExitStack() as exit_stack:
        if stash:
            exit_stack.enter_context(staged_files_only(store.directory))

        config = load_config(config_file)
        hooks = [
            hook
            for hook in all_hooks(config, store)
            if not args.hook or hook.id == args.hook or hook.alias == args.hook
            if args.hook_stage in hook.stages
        ]

        if args.hook and not hooks:
            output.write_line(
                f'No hook with id `{args.hook}` in stage `{args.hook_stage}`',
            )
            return 1

        install_hook_envs(hooks, store)

        return _run_hooks(config, hooks, args, environ)

    # https://github.com/python/mypy/issues/7726
    raise AssertionError('unreachable')
Exemplo n.º 33
0
def _subtle_line(s: str, use_color: bool) -> None:
    output.write_line(color.format_color(s, color.SUBTLE, use_color))
Exemplo n.º 34
0
def gc(store: Store) -> int:
    with store.exclusive_lock():
        repos_removed = _gc_repos(store)
    output.write_line(f'{repos_removed} repo(s) removed.')
    return 0
Exemplo n.º 35
0
def clean(runner):
    if os.path.exists(runner.store.directory):
        rmtree(runner.store.directory)
        output.write_line('Cleaned {}.'.format(runner.store.directory))
    return 0
Exemplo n.º 36
0
def run(
    config_file: str,
    store: Store,
    args: argparse.Namespace,
    environ: EnvironT = os.environ,
) -> int:
    stash = not args.all_files and not args.files

    # Check if we have unresolved merge conflict files and fail fast.
    if _has_unmerged_paths():
        logger.error("Unmerged files.  Resolve before committing.")
        return 1
    if bool(args.from_ref) != bool(args.to_ref):
        logger.error("Specify both --from-ref and --to-ref.")
        return 1
    if stash and _has_unstaged_config(config_file):
        logger.error(
            f"Your pre-commit configuration is unstaged.\n"
            f"`git add {config_file}` to fix this.",
        )
        return 1
    if (
        args.hook_stage in {"prepare-commit-msg", "commit-msg"}
        and not args.commit_msg_filename
    ):
        logger.error(
            f"`--commit-msg-filename` is required for "
            f"`--hook-stage {args.hook_stage}`",
        )
        return 1
    # prevent recursive post-checkout hooks (#1418)
    if args.hook_stage == "post-checkout" and environ.get(
        "_PRE_COMMIT_SKIP_POST_CHECKOUT"
    ):
        return 0

    # Expose from-ref / to-ref as environment variables for hooks to consume
    if args.from_ref and args.to_ref:
        # legacy names
        environ["PRE_COMMIT_ORIGIN"] = args.from_ref
        environ["PRE_COMMIT_SOURCE"] = args.to_ref
        # new names
        environ["PRE_COMMIT_FROM_REF"] = args.from_ref
        environ["PRE_COMMIT_TO_REF"] = args.to_ref

    if args.remote_name and args.remote_url:
        environ["PRE_COMMIT_REMOTE_NAME"] = args.remote_name
        environ["PRE_COMMIT_REMOTE_URL"] = args.remote_url

    if args.checkout_type:
        environ["PRE_COMMIT_CHECKOUT_TYPE"] = args.checkout_type

    # Set pre_commit flag
    environ["PRE_COMMIT"] = "1"

    with contextlib.ExitStack() as exit_stack:
        if stash:
            exit_stack.enter_context(staged_files_only(store.directory))

        config = load_config(config_file)
        hooks = [
            hook
            for hook in all_hooks(config, store)
            if not args.hook or hook.id == args.hook or hook.alias == args.hook
            if args.hook_stage in hook.stages
        ]

        if args.hook and not hooks:
            output.write_line(
                f"No hook with id `{args.hook}` in stage `{args.hook_stage}`",
            )
            return 1

        install_hook_envs(hooks, store)

        return _run_hooks(config, hooks, args, environ)

    # https://github.com/python/mypy/issues/7726
    raise AssertionError("unreachable")