def install_environment( prefix: Prefix, version: str, additional_dependencies: Sequence[str], ) -> None: additional_dependencies = tuple(additional_dependencies) assert prefix.exists('package.json') envdir = _envdir(prefix, version) # https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx?f=255&MSPPError=-2147217396#maxpath if sys.platform == 'win32': # pragma: no cover envdir = fr'\\?\{os.path.normpath(envdir)}' with clean_path_on_failure(envdir): cmd = [ sys.executable, '-mnodeenv', '--prebuilt', '--clean-src', envdir, ] if version != C.DEFAULT: cmd.extend(['-n', version]) cmd_output_b(*cmd) with in_env(prefix, version): # https://npm.community/t/npm-install-g-git-vs-git-clone-cd-npm-install-g/5449 # install as if we installed from git helpers.run_setup_cmd(prefix, ('npm', 'install')) helpers.run_setup_cmd( prefix, ('npm', 'install', '-g', '.', *additional_dependencies), )
def install_environment( prefix: Prefix, version: str, additional_dependencies: Sequence[str], ) -> None: helpers.assert_version_default("conda", version) directory = helpers.environment_dir(ENVIRONMENT_DIR, version) env_dir = prefix.path(directory) with clean_path_on_failure(env_dir): cmd_output_b( "conda", "env", "create", "-p", env_dir, "--file", "environment.yml", cwd=prefix.prefix_dir, ) if additional_dependencies: cmd_output_b( "conda", "install", "-p", env_dir, *additional_dependencies, cwd=prefix.prefix_dir, )
def install_environment(prefix, version, additional_dependencies): helpers.assert_version_default('golang', version) directory = prefix.path( helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT), ) with clean_path_on_failure(directory): remote = git.get_remote_url(prefix.prefix_dir) repo_src_dir = os.path.join(directory, 'src', guess_go_dir(remote)) # Clone into the goenv we'll create helpers.run_setup_cmd(prefix, ('git', 'clone', '.', repo_src_dir)) if sys.platform == 'cygwin': # pragma: no cover _, gopath, _ = cmd_output('cygpath', '-w', directory) gopath = gopath.strip() else: gopath = directory env = dict(os.environ, GOPATH=gopath) env.pop('GOBIN', None) cmd_output_b('go', 'get', './...', cwd=repo_src_dir, env=env) for dependency in additional_dependencies: cmd_output_b('go', 'get', dependency, cwd=repo_src_dir, env=env) # Same some disk space, we don't need these after installation rmtree(prefix.path(directory, 'src')) pkgdir = prefix.path(directory, 'pkg') if os.path.exists(pkgdir): # pragma: no cover (go<1.10) rmtree(pkgdir)
def commit(repo: str = '.') -> None: 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 cmd = ('git', 'commit', '--no-edit', '--no-gpg-sign', '-n', '-minit') cmd_output_b(*cmd, cwd=repo, env=env)
def docker_is_running() -> bool: # pragma: win32 no cover try: cmd_output_b("docker", "ps") except CalledProcessError: return False else: return True
def commit(repo: str = ".") -> None: 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 cmd = ("git", "commit", "--no-edit", "--no-gpg-sign", "-n", "-minit") cmd_output_b(*cmd, cwd=repo, env=env)
def install_environment( prefix: Prefix, version: str, additional_dependencies: Sequence[str], ) -> None: helpers.assert_version_default("golang", version) directory = prefix.path( helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT), ) with clean_path_on_failure(directory): remote = git.get_remote_url(prefix.prefix_dir) repo_src_dir = os.path.join(directory, "src", guess_go_dir(remote)) # Clone into the goenv we'll create helpers.run_setup_cmd(prefix, ("git", "clone", ".", repo_src_dir)) if sys.platform == "cygwin": # pragma: no cover _, gopath, _ = cmd_output("cygpath", "-w", directory) gopath = gopath.strip() else: gopath = directory env = dict(os.environ, GOPATH=gopath) env.pop("GOBIN", None) cmd_output_b("go", "get", "./...", cwd=repo_src_dir, env=env) for dependency in additional_dependencies: cmd_output_b("go", "get", dependency, cwd=repo_src_dir, env=env) # Same some disk space, we don't need these after installation rmtree(prefix.path(directory, "src")) pkgdir = prefix.path(directory, "pkg") if os.path.exists(pkgdir): # pragma: no cover (go<1.10) rmtree(pkgdir)
def greppable_files(tmpdir): with tmpdir.as_cwd(): cmd_output_b('git', 'init', '.') tmpdir.join('f1').write_binary(b"hello'hi\nworld\n") tmpdir.join('f2').write_binary(b'foo\nbar\nbaz\n') tmpdir.join('f3').write_binary(b'[WARN] hi\n') yield tmpdir
def init_repo(path: str, remote: str) -> None: if os.path.isdir(remote): remote = os.path.abspath(remote) env = no_git_env() cmd_output_b('git', 'init', path, env=env) cmd_output_b('git', 'remote', 'add', 'origin', remote, cwd=path, env=env)
def _git_apply(patch: str) -> None: args = ('apply', '--whitespace=nowarn', patch) try: cmd_output_b('git', *args) except CalledProcessError: # Retry with autocrlf=false -- see #570 cmd_output_b('git', '-c', 'core.autocrlf=false', *args)
def _git_apply(patch: str) -> None: args = ("apply", "--whitespace=nowarn", patch) try: cmd_output_b("git", *args) except CalledProcessError: # Retry with autocrlf=false -- see #570 cmd_output_b("git", "-c", "core.autocrlf=false", *args)
def docker_is_running() -> bool: # pragma: win32 no cover try: cmd_output_b('docker', 'ps') except CalledProcessError: # pragma: no cover return False else: return True
def update(self, tags_only: bool, freeze: bool) -> RevInfo: git_cmd = ('git', *git.NO_FS_MONITOR) if tags_only: tag_cmd = ( *git_cmd, 'describe', 'FETCH_HEAD', '--tags', '--abbrev=0', ) else: tag_cmd = ( *git_cmd, 'describe', 'FETCH_HEAD', '--tags', '--exact', ) with tmpdir() as tmp: git.init_repo(tmp, self.repo) cmd_output_b( *git_cmd, 'fetch', 'origin', 'HEAD', '--tags', cwd=tmp, ) try: rev = cmd_output(*tag_cmd, cwd=tmp)[1].strip() except CalledProcessError: cmd = (*git_cmd, 'rev-parse', 'FETCH_HEAD') rev = cmd_output(*cmd, cwd=tmp)[1].strip() frozen = None if freeze: exact_rev_cmd = (*git_cmd, 'rev-parse', rev) exact = cmd_output(*exact_rev_cmd, cwd=tmp)[1].strip() if exact != rev: rev, frozen = exact, rev return self._replace(rev=rev, frozen=frozen)
def install_environment( prefix: Prefix, version: str, additional_dependencies: Sequence[str], ) -> None: helpers.assert_version_default('conda', version) directory = helpers.environment_dir(ENVIRONMENT_DIR, version) conda_exe = _conda_exe() env_dir = prefix.path(directory) with clean_path_on_failure(env_dir): cmd_output_b( conda_exe, 'env', 'create', '-p', env_dir, '--file', 'environment.yml', cwd=prefix.prefix_dir, ) if additional_dependencies: cmd_output_b( conda_exe, 'install', '-p', env_dir, *additional_dependencies, cwd=prefix.prefix_dir, )
def init_repo(path: str, remote: str) -> None: if os.path.isdir(remote): remote = os.path.abspath(remote) env = no_git_env() # avoid the user's template so that hooks do not recurse cmd_output_b("git", "init", "--template=", path, env=env) cmd_output_b("git", "remote", "add", "origin", remote, cwd=path, env=env)
def init_repo(path: str, remote: str) -> None: if os.path.isdir(remote): remote = os.path.abspath(remote) env = no_git_env() # avoid the user's template so that hooks do not recurse cmd_output_b('git', 'init', '--template=', path, env=env) cmd_output_b('git', 'remote', 'add', 'origin', remote, cwd=path, env=env)
def test_really_long_file_paths(tempdir_factory, store): base_path = tempdir_factory.get() really_long_path = os.path.join(base_path, 'really_long' * 10) cmd_output_b('git', 'init', really_long_path) path = make_repo(tempdir_factory, 'python_hooks_repo') config = make_config_from_repo(path) with cwd(really_long_path): _get_hook(config, store, 'foo')
def install_environment( prefix: Prefix, version: str, additional_dependencies: Sequence[str], ) -> None: env_dir = _get_env_dir(prefix, version) with clean_path_on_failure(env_dir): os.makedirs(env_dir, exist_ok=True) shutil.copy(prefix.path('renv.lock'), env_dir) shutil.copytree(prefix.path('renv'), os.path.join(env_dir, 'renv')) cmd_output_b( _rscript_exec(), '--vanilla', '-e', f"""\ prefix_dir <- {prefix.prefix_dir!r} options( repos = c(CRAN = "https://cran.rstudio.com"), renv.consent = TRUE ) source("renv/activate.R") renv::restore() activate_statement <- paste0( 'suppressWarnings({{', 'old <- setwd("', getwd(), '"); ', 'source("renv/activate.R"); ', 'setwd(old); ', 'renv::load("', getwd(), '");}})' ) writeLines(activate_statement, 'activate.R') is_package <- tryCatch( {{ path_desc <- file.path(prefix_dir, 'DESCRIPTION') suppressWarnings(desc <- read.dcf(path_desc)) "Package" %in% colnames(desc) }}, error = function(...) FALSE ) if (is_package) {{ renv::install(prefix_dir) }} """, cwd=env_dir, ) if additional_dependencies: with in_env(prefix, version): cmd_output_b( _rscript_exec(), *RSCRIPT_OPTS, '-e', 'renv::install(commandArgs(trailingOnly = TRUE))', *additional_dependencies, cwd=env_dir, )
def install_environment( prefix: Prefix, version: str, additional_dependencies: Sequence[str], ) -> None: env_dir = _get_env_dir(prefix, version) with clean_path_on_failure(env_dir): os.makedirs(env_dir, exist_ok=True) path_desc_source = prefix.path('DESCRIPTION') if os.path.exists(path_desc_source): shutil.copy(path_desc_source, env_dir) shutil.copy(prefix.path('renv.lock'), env_dir) cmd_output_b( 'Rscript', '--vanilla', '-e', """\ missing_pkgs <- setdiff( "renv", unname(installed.packages()[, "Package"]) ) options( repos = c(CRAN = "https://cran.rstudio.com"), renv.consent = TRUE ) install.packages(missing_pkgs) renv::activate() renv::restore() activate_statement <- paste0( 'renv::activate("', file.path(getwd()), '"); ' ) writeLines(activate_statement, 'activate.R') is_package <- tryCatch( suppressWarnings( unname(read.dcf('DESCRIPTION')[,'Type'] == "Package") ), error = function(...) FALSE ) if (is_package) { renv::install(normalizePath('.')) } """, cwd=env_dir, ) if additional_dependencies: cmd_output_b( 'Rscript', '-e', 'renv::install(commandArgs(trailingOnly = TRUE))', *additional_dependencies, cwd=env_dir, )
def install_environment( prefix: Prefix, version: str, additional_dependencies: Sequence[str], ) -> None: envdir = prefix.path(helpers.environment_dir(ENVIRONMENT_DIR, version)) python = norm_version(version) venv_cmd = (sys.executable, '-mvirtualenv', envdir, '-p', python) install_cmd = ('python', '-mpip', 'install', '.', *additional_dependencies) with clean_path_on_failure(envdir): cmd_output_b(*venv_cmd, cwd='/') with in_env(prefix, version): helpers.run_setup_cmd(prefix, install_cmd)
def _unstaged_changes_cleared(patch_dir: str) -> Generator[None, None, None]: tree = cmd_output('git', 'write-tree')[1].strip() retcode, diff_stdout_binary, _ = cmd_output_b( 'git', 'diff-index', '--ignore-submodules', '--binary', '--exit-code', '--no-color', '--no-ext-diff', tree, '--', retcode=None, ) if retcode and diff_stdout_binary.strip(): patch_filename = f'patch{int(time.time())}-{os.getpid()}' patch_filename = os.path.join(patch_dir, patch_filename) logger.warning('Unstaged files detected.') logger.info(f'Stashing unstaged files to {patch_filename}.') # Save the current unstaged changes as a patch os.makedirs(patch_dir, exist_ok=True) with open(patch_filename, 'wb') as patch_file: patch_file.write(diff_stdout_binary) # prevent recursive post-checkout hooks (#1418) no_checkout_env = dict(os.environ, _PRE_COMMIT_SKIP_POST_CHECKOUT='1') try: cmd_output_b(*_CHECKOUT_CMD, env=no_checkout_env) yield finally: # Try to apply the patch we saved try: _git_apply(patch_filename) except CalledProcessError: logger.warning( 'Stashed changes conflicted with hook auto-fixes... ' 'Rolling back fixes...', ) # We failed to apply the patch, presumably due to fixes made # by hooks. # Roll back the changes made by hooks. cmd_output_b(*_CHECKOUT_CMD, env=no_checkout_env) _git_apply(patch_filename) logger.info(f'Restored changes from {patch_filename}.') else: # There weren't any staged files so we don't need to do anything # special yield
def install_environment( prefix: Prefix, version: str, additional_dependencies: Sequence[str], ) -> None: additional_dependencies = tuple(additional_dependencies) assert prefix.exists('package.json') envdir = _envdir(prefix, version) # https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx?f=255&MSPPError=-2147217396#maxpath if sys.platform == 'win32': # pragma: no cover envdir = fr'\\?\{os.path.normpath(envdir)}' with clean_path_on_failure(envdir): cmd = [ sys.executable, '-mnodeenv', '--prebuilt', '--clean-src', envdir, ] if version != C.DEFAULT: cmd.extend(['-n', version]) cmd_output_b(*cmd) with in_env(prefix, version): # https://npm.community/t/npm-install-g-git-vs-git-clone-cd-npm-install-g/5449 # install as if we installed from git local_install_cmd = ( 'npm', 'install', '--dev', '--prod', '--ignore-prepublish', '--no-progress', '--no-save', ) helpers.run_setup_cmd(prefix, local_install_cmd) _, pkg, _ = cmd_output('npm', 'pack', cwd=prefix.prefix_dir) pkg = prefix.path(pkg.strip()) install = ('npm', 'install', '-g', pkg, *additional_dependencies) helpers.run_setup_cmd(prefix, install) # clean these up after installation if prefix.exists('node_modules'): # pragma: win32 no cover rmtree(prefix.path('node_modules')) os.remove(pkg)
def _unstaged_changes_cleared(patch_dir: str) -> Generator[None, None, None]: tree = cmd_output("git", "write-tree")[1].strip() retcode, diff_stdout_binary, _ = cmd_output_b( "git", "diff-index", "--ignore-submodules", "--binary", "--exit-code", "--no-color", "--no-ext-diff", tree, "--", retcode=None, ) if retcode and diff_stdout_binary.strip(): patch_filename = f"patch{int(time.time())}" patch_filename = os.path.join(patch_dir, patch_filename) logger.warning("Unstaged files detected.") logger.info(f"Stashing unstaged files to {patch_filename}.") # Save the current unstaged changes as a patch os.makedirs(patch_dir, exist_ok=True) with open(patch_filename, "wb") as patch_file: patch_file.write(diff_stdout_binary) # prevent recursive post-checkout hooks (#1418) no_checkout_env = dict(os.environ, _PRE_COMMIT_SKIP_POST_CHECKOUT="1") cmd_output_b("git", "checkout", "--", ".", env=no_checkout_env) try: yield finally: # Try to apply the patch we saved try: _git_apply(patch_filename) except CalledProcessError: logger.warning( "Stashed changes conflicted with hook auto-fixes... " "Rolling back fixes...", ) # We failed to apply the patch, presumably due to fixes made # by hooks. # Roll back the changes made by hooks. cmd_output_b("git", "checkout", "--", ".", env=no_checkout_env) _git_apply(patch_filename) logger.info(f"Restored changes from {patch_filename}.") else: # There weren't any staged files so we don't need to do anything # special yield
def install_environment( prefix: Prefix, version: str, additional_dependencies: Sequence[str], ) -> None: helpers.assert_version_default("rust", version) directory = prefix.path( helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT), ) # There are two cases where we might want to specify more dependencies: # as dependencies for the library being built, and as binary packages # to be `cargo install`'d. # # Unlike e.g. Python, if we just `cargo install` a library, it won't be # used for compilation. And if we add a crate providing a binary to the # `Cargo.toml`, the binary won't be built. # # Because of this, we allow specifying "cli" dependencies by prefixing # with 'cli:'. cli_deps = { dep for dep in additional_dependencies if dep.startswith("cli:") } lib_deps = set(additional_dependencies) - cli_deps if len(lib_deps) > 0: _add_dependencies(prefix.path("Cargo.toml"), lib_deps) with clean_path_on_failure(directory): packages_to_install: Set[Tuple[str, ...]] = {("--path", ".")} for cli_dep in cli_deps: cli_dep = cli_dep[len("cli:"):] package, _, version = cli_dep.partition(":") if version != "": packages_to_install.add((package, "--version", version)) else: packages_to_install.add((package, )) for args in packages_to_install: cmd_output_b( "cargo", "install", "--bins", "--root", directory, *args, cwd=prefix.prefix_dir, )
def health_check(prefix: Prefix, language_version: str) -> str | None: with in_env(prefix, language_version): retcode, _, _ = cmd_output_b('node', '--version', retcode=None) if retcode != 0: # pragma: win32 no cover return f'`node --version` returned {retcode}' else: return None
def _has_unstaged_config(config_file: str) -> bool: retcode, _, _ = cmd_output_b( 'git', 'diff', '--no-ext-diff', '--exit-code', config_file, retcode=None, ) # be explicit, other git errors don't mean it has an unstaged config. return retcode == 1
def _norm_pwd(path): # Under windows bash's temp and windows temp is different. # This normalizes to the bash /tmp return cmd_output_b( 'bash', '-c', f"cd '{path}' && pwd", )[1].strip()
def _update_repo(repo_config, store, tags_only): """Updates a repository to the tip of `master`. If the repository cannot be updated because a hook that is configured does not exist in `master`, this raises a RepositoryCannotBeUpdatedError Args: repo_config - A config for a repository """ with tmpdir() as repo_path: git.init_repo(repo_path, repo_config['repo']) cmd_output_b('git', 'fetch', 'origin', 'HEAD', '--tags', cwd=repo_path) tag_cmd = ('git', 'describe', 'FETCH_HEAD', '--tags') if tags_only: tag_cmd += ('--abbrev=0', ) else: tag_cmd += ('--exact', ) try: rev = cmd_output(*tag_cmd, cwd=repo_path)[1].strip() except CalledProcessError: tag_cmd = ('git', 'rev-parse', 'FETCH_HEAD') rev = cmd_output(*tag_cmd, cwd=repo_path)[1].strip() # Don't bother trying to update if our rev is the same if rev == repo_config['rev']: return repo_config try: path = store.clone(repo_config['repo'], rev) manifest = load_manifest(os.path.join(path, C.MANIFEST_FILE)) except InvalidManifestError as e: raise RepositoryCannotBeUpdatedError(six.text_type(e)) # See if any of our hooks were deleted with the new commits hooks = {hook['id'] for hook in repo_config['hooks']} hooks_missing = hooks - {hook['id'] for hook in manifest} if hooks_missing: raise RepositoryCannotBeUpdatedError( 'Cannot update because the tip of master is missing these hooks:\n' '{}'.format(', '.join(sorted(hooks_missing))), ) # Construct a new config with the head rev new_config = repo_config.copy() new_config['rev'] = rev return new_config
def install_environment( prefix, version, additional_dependencies, ): # pragma: windows no cover helpers.assert_version_default('swift', version) helpers.assert_no_additional_deps('swift', additional_dependencies) directory = prefix.path( helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT), ) # Build the swift package with clean_path_on_failure(directory): os.mkdir(directory) cmd_output_b( 'swift', 'build', '-C', prefix.prefix_dir, '-c', BUILD_CONFIG, '--build-path', os.path.join(directory, BUILD_DIR), )
def _get_diff() -> bytes: _, out, _ = cmd_output_b( 'git', 'diff', '--no-ext-diff', '--ignore-submodules', retcode=None, ) return out