def install( config_file, store, overwrite=False, hooks=False, hook_type='pre-commit', skip_on_missing_config=False, git_dir=None, ): """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, git_dir=git_dir) 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_config, } 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
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
def _install_hook_script( config_file: str, hook_type: str, overwrite: bool = False, skip_on_missing_config: bool = False, git_dir: Optional[str] = None, ) -> None: hook_path, legacy_path = _hook_paths(hook_type, git_dir=git_dir) os.makedirs(os.path.dirname(hook_path), exist_ok=True) # 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( f'Running in migration mode with existing hooks at {legacy_path}\n' f'Use -f to use only pre-commit.', ) args = ['hook-impl', f'--config={config_file}', f'--hook-type={hook_type}'] if skip_on_missing_config: args.append('--skip-on-missing-config') with open(hook_path, 'w') as hook_file: contents = resource_text('hook-tmpl') before, rest = contents.split(TEMPLATE_START) _, after = rest.split(TEMPLATE_END) # on windows always use `/bin/sh` since `bash` might not be on PATH # though we use bash-specific features `sh` on windows is actually # bash in "POSIXLY_CORRECT" mode which still supports the features we # use: subshells / arrays if sys.platform == 'win32': # pragma: win32 cover hook_file.write('#!/bin/sh\n') hook_file.write(before + TEMPLATE_START) hook_file.write(f'INSTALL_PYTHON={shlex.quote(sys.executable)}\n') # TODO: python3.8+: shlex.join args_s = ' '.join(shlex.quote(part) for part in args) hook_file.write(f'ARGS=({args_s})\n') hook_file.write(TEMPLATE_END + after) make_executable(hook_path) output.write_line(f'pre-commit installed at {hook_path}')
def make_local_strategy(directory): for resource in self.LOCAL_RESOURCES: contents = resource_text('empty_template_{}'.format(resource)) with io.open(os.path.join(directory, resource), 'w') as f: f.write(contents) env = git.no_git_env() # initialize the git repository so it looks more like cloned repos def _git_cmd(*args): cmd_output_b('git', *args, cwd=directory, env=env) git.init_repo(directory, '<<unknown>>') _git_cmd('add', '.') git.commit(repo=directory)
def make_local_strategy(directory: str) -> None: for resource in self.LOCAL_RESOURCES: contents = resource_text(f"empty_template_{resource}") with open(os.path.join(directory, resource), "w") as f: f.write(contents) env = git.no_git_env() # initialize the git repository so it looks more like cloned repos def _git_cmd(*args: str) -> None: cmd_output_b("git", *args, cwd=directory, env=env) git.init_repo(directory, "<<unknown>>") _git_cmd("add", ".") git.commit(repo=directory)
def make_local_strategy(directory): for resource in self.LOCAL_RESOURCES: contents = resource_text('empty_template_{}'.format(resource)) with io.open(os.path.join(directory, resource), 'w') as f: f.write(contents) env = git.no_git_env() # initialize the git repository so it looks more like cloned repos def _git_cmd(*args): cmd_output('git', *args, cwd=directory, env=env) _git_cmd('init', '.') _git_cmd('config', 'remote.origin.url', '<<unknown>>') _git_cmd('add', '.') git.commit(repo=directory)
def _install_hook_script( config_file: str, hook_type: str, overwrite: bool = False, skip_on_missing_config: bool = False, git_dir: Optional[str] = None, ) -> None: hook_path, legacy_path = _hook_paths(hook_type, git_dir=git_dir) os.makedirs(os.path.dirname(hook_path), exist_ok=True) # 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( f'Running in migration mode with existing hooks at {legacy_path}\n' f'Use -f to use only pre-commit.', ) params = { 'CONFIG': config_file, 'HOOK_TYPE': hook_type, 'INSTALL_PYTHON': sys.executable, 'SKIP_ON_MISSING_CONFIG': skip_on_missing_config, } with 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(f'{var} = {params[var]!r}\n') hook_file.write(TEMPLATE_END + after) make_executable(hook_path) output.write_line(f'pre-commit installed at {hook_path}')
def _install_hook_script( config_file: str, hook_type: str, overwrite: bool = False, skip_on_missing_config: bool = False, git_dir: Optional[str] = None, ) -> None: hook_path, legacy_path = _hook_paths(hook_type, git_dir=git_dir) os.makedirs(os.path.dirname(hook_path), exist_ok=True) # 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( f"Running in migration mode with existing hooks at {legacy_path}\n" f"Use -f to use only pre-commit.", ) args = ["hook-impl", f"--config={config_file}", f"--hook-type={hook_type}"] if skip_on_missing_config: args.append("--skip-on-missing-config") params = {"INSTALL_PYTHON": sys.executable, "ARGS": args} with 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(f"{var} = {params[var]!r}\n") hook_file.write(TEMPLATE_END + after) make_executable(hook_path) output.write_line(f"pre-commit installed at {hook_path}")
def make_local_strategy(directory): for resource in self.LOCAL_RESOURCES: contents = resource_text('empty_template_{}'.format(resource)) with io.open(os.path.join(directory, resource), 'w') as f: f.write(contents) env = no_git_env() name, email = 'pre-commit', '*****@*****.**' env['GIT_AUTHOR_NAME'] = env['GIT_COMMITTER_NAME'] = name env['GIT_AUTHOR_EMAIL'] = env['GIT_COMMITTER_EMAIL'] = email # initialize the git repository so it looks more like cloned repos def _git_cmd(*args): cmd_output('git', *args, cwd=directory, env=env) _git_cmd('init', '.') _git_cmd('config', 'remote.origin.url', '<<unknown>>') _git_cmd('add', '.') _git_cmd('commit', '--no-edit', '--no-gpg-sign', '-n', '-minit')
def make_local_strategy(directory: str) -> None: for resource in self.LOCAL_RESOURCES: resource_dirname, resource_basename = os.path.split(resource) contents = resource_text(f'empty_template_{resource_basename}') target_dir = os.path.join(directory, resource_dirname) target_file = os.path.join(target_dir, resource_basename) os.makedirs(target_dir, exist_ok=True) with open(target_file, 'w') as f: f.write(contents) env = git.no_git_env() # initialize the git repository so it looks more like cloned repos def _git_cmd(*args: str) -> None: cmd_output_b('git', *args, cwd=directory, env=env) git.init_repo(directory, '<<unknown>>') _git_cmd('add', '.') git.commit(repo=directory)
def _install_hook_script( config_file: str, hook_type: str, overwrite: bool = False, skip_on_missing_config: bool = False, git_dir: Optional[str] = None, ) -> None: hook_path, legacy_path = _hook_paths(hook_type, git_dir=git_dir) os.makedirs(os.path.dirname(hook_path), exist_ok=True) # 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( f'Running in migration mode with existing hooks at {legacy_path}\n' f'Use -f to use only pre-commit.', ) args = ['hook-impl', f'--config={config_file}', f'--hook-type={hook_type}'] if skip_on_missing_config: args.append('--skip-on-missing-config') with open(hook_path, 'w') as hook_file: contents = resource_text('hook-tmpl') before, rest = contents.split(TEMPLATE_START) _, after = rest.split(TEMPLATE_END) hook_file.write(before + TEMPLATE_START) hook_file.write(f'INSTALL_PYTHON={shlex.quote(sys.executable)}\n') # TODO: python3.8+: shlex.join args_s = ' '.join(shlex.quote(part) for part in args) hook_file.write(f'ARGS=({args_s})\n') hook_file.write(TEMPLATE_END + after) make_executable(hook_path) output.write_line(f'pre-commit installed at {hook_path}')
def test_replace_old_commit_script(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): # Install a script that looks like our old script pre_commit_contents = resource_text('hook-tmpl') new_contents = pre_commit_contents.replace( CURRENT_HASH.decode(), PRIOR_HASHES[-1].decode(), ) os.makedirs(os.path.join(path, '.git/hooks'), exist_ok=True) with open(os.path.join(path, '.git/hooks/pre-commit'), 'w') as f: f.write(new_contents) make_executable(f.name) # Install normally assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0 ret, output = _get_commit_output(tempdir_factory) assert ret == 0 NORMAL_PRE_COMMIT_RUN.assert_matches(output)
def test_replace_old_commit_script(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): # Install a script that looks like our old script pre_commit_contents = resource_text('hook-tmpl') new_contents = pre_commit_contents.replace( CURRENT_HASH, PRIOR_HASHES[-1], ) mkdirp(os.path.join(path, '.git/hooks')) with io.open(os.path.join(path, '.git/hooks/pre-commit'), 'w') as f: f.write(new_contents) make_executable(f.name) # Install normally assert install(C.CONFIG_FILE, store) == 0 ret, output = _get_commit_output(tempdir_factory) assert ret == 0 assert NORMAL_PRE_COMMIT_RUN.match(output)
def test_replace_old_commit_script(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): runner = Runner(path, C.CONFIG_FILE) # Install a script that looks like our old script pre_commit_contents = resource_text('hook-tmpl') new_contents = pre_commit_contents.replace( CURRENT_HASH, PRIOR_HASHES[-1], ) mkdirp(os.path.join(path, '.git/hooks')) with io.open(os.path.join(path, '.git/hooks/pre-commit'), 'w') as f: f.write(new_contents) make_executable(f.name) # Install normally assert install(runner, store) == 0 ret, output = _get_commit_output(tempdir_factory) assert ret == 0 assert NORMAL_PRE_COMMIT_RUN.match(output)