1
0
Fork 0

Merging upstream version 2.13.0.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-09 21:28:21 +01:00
parent c2d1f037e4
commit 1e2278d3de
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
27 changed files with 1249 additions and 80 deletions

View file

@ -1,6 +1,6 @@
repos: repos:
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.4.0 rev: v4.0.1
hooks: hooks:
- id: trailing-whitespace - id: trailing-whitespace
- id: end-of-file-fixer - id: end-of-file-fixer
@ -12,25 +12,25 @@ repos:
- id: requirements-txt-fixer - id: requirements-txt-fixer
- id: double-quote-string-fixer - id: double-quote-string-fixer
- repo: https://github.com/PyCQA/flake8 - repo: https://github.com/PyCQA/flake8
rev: 3.9.0 rev: 3.9.2
hooks: hooks:
- id: flake8 - id: flake8
additional_dependencies: [flake8-typing-imports==1.10.0] additional_dependencies: [flake8-typing-imports==1.10.0]
- repo: https://github.com/pre-commit/mirrors-autopep8 - repo: https://github.com/pre-commit/mirrors-autopep8
rev: v1.5.6 rev: v1.5.7
hooks: hooks:
- id: autopep8 - id: autopep8
- repo: https://github.com/pre-commit/pre-commit - repo: https://github.com/pre-commit/pre-commit
rev: v2.12.1 rev: v2.13.0
hooks: hooks:
- id: validate_manifest - id: validate_manifest
- repo: https://github.com/asottile/pyupgrade - repo: https://github.com/asottile/pyupgrade
rev: v2.12.0 rev: v2.16.0
hooks: hooks:
- id: pyupgrade - id: pyupgrade
args: [--py36-plus] args: [--py36-plus]
- repo: https://github.com/asottile/reorder_python_imports - repo: https://github.com/asottile/reorder_python_imports
rev: v2.4.0 rev: v2.5.0
hooks: hooks:
- id: reorder-python-imports - id: reorder-python-imports
args: [--py3-plus] args: [--py3-plus]

View file

@ -1,3 +1,26 @@
2.13.0 - 2021-05-21
===================
### Features
- Setting `SKIP=...` skips installation as well.
- #1875 PR by @asottile.
- pre-commit-ci/issues#53 issue by @TylerYep.
- Attempt to mount from host with docker-in-docker.
- #1888 PR by @okainov.
- #1387 issue by @okainov.
- Enable `repo: local` for `r` hooks.
- #1878 PR by @lorenzwalthert.
- Upgrade `ruby-build` and `rbenv`.
- #1913 PR by @jalessio.
### Fixes
- Better detect `r` packages.
- #1898 PR by @lorenzwalthert.
- Avoid warnings with mismatched `renv` versions.
- #1841 PR by @lorenzwalthert.
- Reproducibly produce ruby tar resources.
- #1915 PR by @asottile.
2.12.1 - 2021-04-16 2.12.1 - 2021-04-16
=================== ===================
@ -1444,7 +1467,7 @@ that have helped us get this far!
0.13.1 - 2017-02-16 0.13.1 - 2017-02-16
=================== ===================
- Fix dummy gem for ruby local hooks - Fix placeholder gem for ruby local hooks
0.13.0 - 2017-02-16 0.13.0 - 2017-02-16
=================== ===================

View file

@ -271,11 +271,11 @@ def _get_diff() -> bytes:
def _run_hooks( def _run_hooks(
config: Dict[str, Any], config: Dict[str, Any],
hooks: Sequence[Hook], hooks: Sequence[Hook],
skips: Set[str],
args: argparse.Namespace, args: argparse.Namespace,
environ: MutableMapping[str, str], environ: MutableMapping[str, str],
) -> int: ) -> int:
"""Actually run the hooks.""" """Actually run the hooks."""
skips = _get_skips(environ)
cols = _compute_cols(hooks) cols = _compute_cols(hooks)
classifier = Classifier.from_config( classifier = Classifier.from_config(
_all_filenames(args), config['files'], config['exclude'], _all_filenames(args), config['files'], config['exclude'],
@ -403,9 +403,11 @@ def run(
) )
return 1 return 1
install_hook_envs(hooks, store) skips = _get_skips(environ)
to_install = [hook for hook in hooks if hook.id not in skips]
install_hook_envs(to_install, store)
return _run_hooks(config, hooks, args, environ) return _run_hooks(config, hooks, skips, args, environ)
# https://github.com/python/mypy/issues/7726 # https://github.com/python/mypy/issues/7726
raise AssertionError('unreachable') raise AssertionError('unreachable')

View file

@ -1,5 +1,7 @@
import hashlib import hashlib
import json
import os import os
import socket
from typing import Sequence from typing import Sequence
from typing import Tuple from typing import Tuple
@ -8,6 +10,7 @@ from pre_commit.hook import Hook
from pre_commit.languages import helpers from pre_commit.languages import helpers
from pre_commit.prefix import Prefix from pre_commit.prefix import Prefix
from pre_commit.util import clean_path_on_failure from pre_commit.util import clean_path_on_failure
from pre_commit.util import cmd_output_b
ENVIRONMENT_DIR = 'docker' ENVIRONMENT_DIR = 'docker'
PRE_COMMIT_LABEL = 'PRE_COMMIT' PRE_COMMIT_LABEL = 'PRE_COMMIT'
@ -15,6 +18,34 @@ get_default_version = helpers.basic_get_default_version
healthy = helpers.basic_healthy healthy = helpers.basic_healthy
def _is_in_docker() -> bool:
try:
with open('/proc/1/cgroup', 'rb') as f:
return b'docker' in f.read()
except FileNotFoundError:
return False
def _get_docker_path(path: str) -> str:
if not _is_in_docker():
return path
hostname = socket.gethostname()
_, out, _ = cmd_output_b('docker', 'inspect', hostname)
container, = json.loads(out)
for mount in container['Mounts']:
src_path = mount['Source']
to_path = mount['Destination']
if os.path.commonpath((path, to_path)) == to_path:
# So there is something in common,
# and we can proceed remapping it
return path.replace(to_path, src_path)
# we're in Docker, but the path is not mounted, cannot really do anything,
# so fall back to original path
return path
def md5(s: str) -> str: # pragma: win32 no cover def md5(s: str) -> str: # pragma: win32 no cover
return hashlib.md5(s.encode()).hexdigest() return hashlib.md5(s.encode()).hexdigest()
@ -73,7 +104,7 @@ def docker_cmd() -> Tuple[str, ...]: # pragma: win32 no cover
# https://docs.docker.com/engine/reference/commandline/run/#mount-volumes-from-container-volumes-from # https://docs.docker.com/engine/reference/commandline/run/#mount-volumes-from-container-volumes-from
# The `Z` option tells Docker to label the content with a private # The `Z` option tells Docker to label the content with a private
# unshared label. Only the current container can use a private volume. # unshared label. Only the current container can use a private volume.
'-v', f'{os.getcwd()}:/src:rw,Z', '-v', f'{_get_docker_path(os.getcwd())}:/src:rw,Z',
'--workdir', '/src', '--workdir', '/src',
) )

View file

@ -15,6 +15,7 @@ from pre_commit.util import clean_path_on_failure
from pre_commit.util import cmd_output_b from pre_commit.util import cmd_output_b
ENVIRONMENT_DIR = 'renv' ENVIRONMENT_DIR = 'renv'
RSCRIPT_OPTS = ('--no-save', '--no-restore', '--no-site-file', '--no-environ')
get_default_version = helpers.basic_get_default_version get_default_version = helpers.basic_get_default_version
healthy = helpers.basic_healthy healthy = helpers.basic_healthy
@ -39,14 +40,19 @@ def _get_env_dir(prefix: Prefix, version: str) -> str:
return prefix.path(helpers.environment_dir(ENVIRONMENT_DIR, version)) return prefix.path(helpers.environment_dir(ENVIRONMENT_DIR, version))
def _prefix_if_file_entry( def _prefix_if_non_local_file_entry(
entry: Sequence[str], entry: Sequence[str],
prefix: Prefix, prefix: Prefix,
src: str,
) -> Sequence[str]: ) -> Sequence[str]:
if entry[1] == '-e': if entry[1] == '-e':
return entry[1:] return entry[1:]
else: else:
return (prefix.path(entry[1]),) if src == 'local':
path = entry[1]
else:
path = prefix.path(entry[1])
return (path,)
def _entry_validate(entry: Sequence[str]) -> None: def _entry_validate(entry: Sequence[str]) -> None:
@ -69,13 +75,12 @@ def _entry_validate(entry: Sequence[str]) -> None:
def _cmd_from_hook(hook: Hook) -> Tuple[str, ...]: def _cmd_from_hook(hook: Hook) -> Tuple[str, ...]:
opts = ('--no-save', '--no-restore', '--no-site-file', '--no-environ')
entry = shlex.split(hook.entry) entry = shlex.split(hook.entry)
_entry_validate(entry) _entry_validate(entry)
return ( return (
*entry[:1], *opts, *entry[:1], *RSCRIPT_OPTS,
*_prefix_if_file_entry(entry, hook.prefix), *_prefix_if_non_local_file_entry(entry, hook.prefix, hook.src),
*hook.args, *hook.args,
) )
@ -89,29 +94,32 @@ def install_environment(
with clean_path_on_failure(env_dir): with clean_path_on_failure(env_dir):
os.makedirs(env_dir, exist_ok=True) os.makedirs(env_dir, exist_ok=True)
shutil.copy(prefix.path('renv.lock'), env_dir) shutil.copy(prefix.path('renv.lock'), env_dir)
shutil.copytree(prefix.path('renv'), os.path.join(env_dir, 'renv'))
cmd_output_b( cmd_output_b(
'Rscript', '--vanilla', '-e', 'Rscript', '--vanilla', '-e',
f"""\ f"""\
prefix_dir <- {prefix.prefix_dir!r} prefix_dir <- {prefix.prefix_dir!r}
missing_pkgs <- setdiff(
"renv", unname(installed.packages()[, "Package"])
)
options( options(
repos = c(CRAN = "https://cran.rstudio.com"), repos = c(CRAN = "https://cran.rstudio.com"),
renv.consent = TRUE renv.consent = TRUE
) )
install.packages(missing_pkgs) source("renv/activate.R")
renv::activate()
renv::restore() renv::restore()
activate_statement <- paste0( activate_statement <- paste0(
'renv::activate("', file.path(getwd()), '"); ' 'suppressWarnings({{',
'old <- setwd("', getwd(), '"); ',
'source("renv/activate.R"); ',
'setwd(old); ',
'renv::load("', getwd(), '");}})'
) )
writeLines(activate_statement, 'activate.R') writeLines(activate_statement, 'activate.R')
is_package <- tryCatch({{ is_package <- tryCatch(
content_desc <- read.dcf(file.path(prefix_dir, 'DESCRIPTION')) {{
suppressWarnings(unname(content_desc[,'Type']) == "Package") path_desc <- file.path(prefix_dir, 'DESCRIPTION')
}}, suppressWarnings(desc <- read.dcf(path_desc))
error = function(...) FALSE "Package" %in% colnames(desc)
}},
error = function(...) FALSE
) )
if (is_package) {{ if (is_package) {{
renv::install(prefix_dir) renv::install(prefix_dir)
@ -120,12 +128,13 @@ def install_environment(
cwd=env_dir, cwd=env_dir,
) )
if additional_dependencies: if additional_dependencies:
cmd_output_b( with in_env(prefix, version):
'Rscript', '-e', cmd_output_b(
'renv::install(commandArgs(trailingOnly = TRUE))', 'Rscript', *RSCRIPT_OPTS, '-e',
*additional_dependencies, 'renv::install(commandArgs(trailingOnly = TRUE))',
cwd=env_dir, *additional_dependencies,
) cwd=env_dir,
)
def run_hook( def run_hook(

View file

@ -0,0 +1,7 @@
Copyright 2021 RStudio, PBC
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1,6 +1,6 @@
use ExtUtils::MakeMaker; use ExtUtils::MakeMaker;
WriteMakefile( WriteMakefile(
NAME => "PreCommitDummy", NAME => "PreCommitPlaceholder",
VERSION => "0.0.1", VERSION => "0.0.1",
); );

View file

@ -0,0 +1,440 @@
local({
# the requested version of renv
version <- "0.12.5"
# the project directory
project <- getwd()
# avoid recursion
if (!is.na(Sys.getenv("RENV_R_INITIALIZING", unset = NA)))
return(invisible(TRUE))
# signal that we're loading renv during R startup
Sys.setenv("RENV_R_INITIALIZING" = "true")
on.exit(Sys.unsetenv("RENV_R_INITIALIZING"), add = TRUE)
# signal that we've consented to use renv
options(renv.consent = TRUE)
# load the 'utils' package eagerly -- this ensures that renv shims, which
# mask 'utils' packages, will come first on the search path
library(utils, lib.loc = .Library)
# check to see if renv has already been loaded
if ("renv" %in% loadedNamespaces()) {
# if renv has already been loaded, and it's the requested version of renv,
# nothing to do
spec <- .getNamespaceInfo(.getNamespace("renv"), "spec")
if (identical(spec[["version"]], version))
return(invisible(TRUE))
# otherwise, unload and attempt to load the correct version of renv
unloadNamespace("renv")
}
# load bootstrap tools
bootstrap <- function(version, library) {
# attempt to download renv
tarball <- tryCatch(renv_bootstrap_download(version), error = identity)
if (inherits(tarball, "error"))
stop("failed to download renv ", version)
# now attempt to install
status <- tryCatch(renv_bootstrap_install(version, tarball, library), error = identity)
if (inherits(status, "error"))
stop("failed to install renv ", version)
}
renv_bootstrap_tests_running <- function() {
getOption("renv.tests.running", default = FALSE)
}
renv_bootstrap_repos <- function() {
# check for repos override
repos <- Sys.getenv("RENV_CONFIG_REPOS_OVERRIDE", unset = NA)
if (!is.na(repos))
return(repos)
# if we're testing, re-use the test repositories
if (renv_bootstrap_tests_running())
return(getOption("renv.tests.repos"))
# retrieve current repos
repos <- getOption("repos")
# ensure @CRAN@ entries are resolved
repos[repos == "@CRAN@"] <- "https://cloud.r-project.org"
# add in renv.bootstrap.repos if set
default <- c(CRAN = "https://cloud.r-project.org")
extra <- getOption("renv.bootstrap.repos", default = default)
repos <- c(repos, extra)
# remove duplicates that might've snuck in
dupes <- duplicated(repos) | duplicated(names(repos))
repos[!dupes]
}
renv_bootstrap_download <- function(version) {
# if the renv version number has 4 components, assume it must
# be retrieved via github
nv <- numeric_version(version)
components <- unclass(nv)[[1]]
methods <- if (length(components) == 4L) {
list(
renv_bootstrap_download_github
)
} else {
list(
renv_bootstrap_download_cran_latest,
renv_bootstrap_download_cran_archive
)
}
for (method in methods) {
path <- tryCatch(method(version), error = identity)
if (is.character(path) && file.exists(path))
return(path)
}
stop("failed to download renv ", version)
}
renv_bootstrap_download_impl <- function(url, destfile) {
mode <- "wb"
# https://bugs.r-project.org/bugzilla/show_bug.cgi?id=17715
fixup <-
Sys.info()[["sysname"]] == "Windows" &&
substring(url, 1L, 5L) == "file:"
if (fixup)
mode <- "w+b"
utils::download.file(
url = url,
destfile = destfile,
mode = mode,
quiet = TRUE
)
}
renv_bootstrap_download_cran_latest <- function(version) {
repos <- renv_bootstrap_download_cran_latest_find(version)
message("* Downloading renv ", version, " from CRAN ... ", appendLF = FALSE)
info <- tryCatch(
utils::download.packages(
pkgs = "renv",
repos = repos,
destdir = tempdir(),
quiet = TRUE
),
condition = identity
)
if (inherits(info, "condition")) {
message("FAILED")
return(FALSE)
}
message("OK")
info[1, 2]
}
renv_bootstrap_download_cran_latest_find <- function(version) {
all <- renv_bootstrap_repos()
for (repos in all) {
db <- tryCatch(
as.data.frame(
x = utils::available.packages(repos = repos),
stringsAsFactors = FALSE
),
error = identity
)
if (inherits(db, "error"))
next
entry <- db[db$Package %in% "renv" & db$Version %in% version, ]
if (nrow(entry) == 0)
next
return(repos)
}
fmt <- "renv %s is not available from your declared package repositories"
stop(sprintf(fmt, version))
}
renv_bootstrap_download_cran_archive <- function(version) {
name <- sprintf("renv_%s.tar.gz", version)
repos <- renv_bootstrap_repos()
urls <- file.path(repos, "src/contrib/Archive/renv", name)
destfile <- file.path(tempdir(), name)
message("* Downloading renv ", version, " from CRAN archive ... ", appendLF = FALSE)
for (url in urls) {
status <- tryCatch(
renv_bootstrap_download_impl(url, destfile),
condition = identity
)
if (identical(status, 0L)) {
message("OK")
return(destfile)
}
}
message("FAILED")
return(FALSE)
}
renv_bootstrap_download_github <- function(version) {
enabled <- Sys.getenv("RENV_BOOTSTRAP_FROM_GITHUB", unset = "TRUE")
if (!identical(enabled, "TRUE"))
return(FALSE)
# prepare download options
pat <- Sys.getenv("GITHUB_PAT")
if (nzchar(Sys.which("curl")) && nzchar(pat)) {
fmt <- "--location --fail --header \"Authorization: token %s\""
extra <- sprintf(fmt, pat)
saved <- options("download.file.method", "download.file.extra")
options(download.file.method = "curl", download.file.extra = extra)
on.exit(do.call(base::options, saved), add = TRUE)
} else if (nzchar(Sys.which("wget")) && nzchar(pat)) {
fmt <- "--header=\"Authorization: token %s\""
extra <- sprintf(fmt, pat)
saved <- options("download.file.method", "download.file.extra")
options(download.file.method = "wget", download.file.extra = extra)
on.exit(do.call(base::options, saved), add = TRUE)
}
message("* Downloading renv ", version, " from GitHub ... ", appendLF = FALSE)
url <- file.path("https://api.github.com/repos/rstudio/renv/tarball", version)
name <- sprintf("renv_%s.tar.gz", version)
destfile <- file.path(tempdir(), name)
status <- tryCatch(
renv_bootstrap_download_impl(url, destfile),
condition = identity
)
if (!identical(status, 0L)) {
message("FAILED")
return(FALSE)
}
message("OK")
return(destfile)
}
renv_bootstrap_install <- function(version, tarball, library) {
# attempt to install it into project library
message("* Installing renv ", version, " ... ", appendLF = FALSE)
dir.create(library, showWarnings = FALSE, recursive = TRUE)
# invoke using system2 so we can capture and report output
bin <- R.home("bin")
exe <- if (Sys.info()[["sysname"]] == "Windows") "R.exe" else "R"
r <- file.path(bin, exe)
args <- c("--vanilla", "CMD", "INSTALL", "-l", shQuote(library), shQuote(tarball))
output <- system2(r, args, stdout = TRUE, stderr = TRUE)
message("Done!")
# check for successful install
status <- attr(output, "status")
if (is.numeric(status) && !identical(status, 0L)) {
header <- "Error installing renv:"
lines <- paste(rep.int("=", nchar(header)), collapse = "")
text <- c(header, lines, output)
writeLines(text, con = stderr())
}
status
}
renv_bootstrap_prefix <- function() {
# construct version prefix
version <- paste(R.version$major, R.version$minor, sep = ".")
prefix <- paste("R", numeric_version(version)[1, 1:2], sep = "-")
# include SVN revision for development versions of R
# (to avoid sharing platform-specific artefacts with released versions of R)
devel <-
identical(R.version[["status"]], "Under development (unstable)") ||
identical(R.version[["nickname"]], "Unsuffered Consequences")
if (devel)
prefix <- paste(prefix, R.version[["svn rev"]], sep = "-r")
# build list of path components
components <- c(prefix, R.version$platform)
# include prefix if provided by user
prefix <- Sys.getenv("RENV_PATHS_PREFIX")
if (nzchar(prefix))
components <- c(prefix, components)
# build prefix
paste(components, collapse = "/")
}
renv_bootstrap_library_root_name <- function(project) {
# use project name as-is if requested
asis <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT_ASIS", unset = "FALSE")
if (asis)
return(basename(project))
# otherwise, disambiguate based on project's path
id <- substring(renv_bootstrap_hash_text(project), 1L, 8L)
paste(basename(project), id, sep = "-")
}
renv_bootstrap_library_root <- function(project) {
path <- Sys.getenv("RENV_PATHS_LIBRARY", unset = NA)
if (!is.na(path))
return(path)
path <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT", unset = NA)
if (!is.na(path)) {
name <- renv_bootstrap_library_root_name(project)
return(file.path(path, name))
}
file.path(project, "renv/library")
}
renv_bootstrap_validate_version <- function(version) {
loadedversion <- utils::packageDescription("renv", fields = "Version")
if (version == loadedversion)
return(TRUE)
# assume four-component versions are from GitHub; three-component
# versions are from CRAN
components <- strsplit(loadedversion, "[.-]")[[1]]
remote <- if (length(components) == 4L)
paste("rstudio/renv", loadedversion, sep = "@")
else
paste("renv", loadedversion, sep = "@")
fmt <- paste(
"renv %1$s was loaded from project library, but this project is configured to use renv %2$s.",
"Use `renv::record(\"%3$s\")` to record renv %1$s in the lockfile.",
"Use `renv::restore(packages = \"renv\")` to install renv %2$s into the project library.",
sep = "\n"
)
msg <- sprintf(fmt, loadedversion, version, remote)
warning(msg, call. = FALSE)
FALSE
}
renv_bootstrap_hash_text <- function(text) {
hashfile <- tempfile("renv-hash-")
on.exit(unlink(hashfile), add = TRUE)
writeLines(text, con = hashfile)
tools::md5sum(hashfile)
}
renv_bootstrap_load <- function(project, libpath, version) {
# try to load renv from the project library
if (!requireNamespace("renv", lib.loc = libpath, quietly = TRUE))
return(FALSE)
# warn if the version of renv loaded does not match
renv_bootstrap_validate_version(version)
# load the project
renv::load(project)
TRUE
}
# construct path to library root
root <- renv_bootstrap_library_root(project)
# construct library prefix for platform
prefix <- renv_bootstrap_prefix()
# construct full libpath
libpath <- file.path(root, prefix)
# attempt to load
if (renv_bootstrap_load(project, libpath, version))
return(TRUE)
# load failed; inform user we're about to bootstrap
prefix <- paste("# Bootstrapping renv", version)
postfix <- paste(rep.int("-", 77L - nchar(prefix)), collapse = "")
header <- paste(prefix, postfix)
message(header)
# perform bootstrap
bootstrap(version, libpath)
# exit early if we're just testing bootstrap
if (!is.na(Sys.getenv("RENV_BOOTSTRAP_INSTALL_ONLY", unset = NA)))
return(TRUE)
# try again to load
if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) {
message("* Successfully installed and loaded renv ", version, ".")
return(renv::load())
}
# failed to download or load renv; warn the user
msg <- c(
"Failed to find an renv installation: the project will not be loaded.",
"Use `renv::activate()` to re-initialize the project."
)
warning(paste(msg, collapse = "\n"), call. = FALSE)
})

View file

@ -1 +1 @@
module pre-commit-dummy-empty-module module pre-commit-placeholder-empty-module

View file

@ -1,4 +1,4 @@
{ {
"name": "pre_commit_dummy_package", "name": "pre_commit_placeholder_package",
"version": "0.0.0" "version": "0.0.0"
} }

View file

@ -1,6 +0,0 @@
Gem::Specification.new do |s|
s.name = 'pre_commit_dummy_package'
s.version = '0.0.0'
s.summary = 'dummy gem for pre-commit hooks'
s.authors = ['Anthony Sottile']
end

View file

@ -0,0 +1,6 @@
Gem::Specification.new do |s|
s.name = 'pre_commit_placeholder_package'
s.version = '0.0.0'
s.summary = 'placeholder gem for pre-commit hooks'
s.authors = ['Anthony Sottile']
end

View file

@ -1,4 +1,4 @@
from setuptools import setup from setuptools import setup
setup(name='pre-commit-dummy-package', version='0.0.0') setup(name='pre-commit-placeholder-package', version='0.0.0')

Binary file not shown.

View file

@ -188,15 +188,20 @@ class Store:
LOCAL_RESOURCES = ( LOCAL_RESOURCES = (
'Cargo.toml', 'main.go', 'go.mod', 'main.rs', '.npmignore', 'Cargo.toml', 'main.go', 'go.mod', 'main.rs', '.npmignore',
'package.json', 'pre_commit_dummy_package.gemspec', 'setup.py', 'package.json', 'pre_commit_placeholder_package.gemspec', 'setup.py',
'environment.yml', 'Makefile.PL', 'renv.lock', 'environment.yml', 'Makefile.PL',
'renv.lock', 'renv/activate.R', 'renv/LICENSE.renv',
) )
def make_local(self, deps: Sequence[str]) -> str: def make_local(self, deps: Sequence[str]) -> str:
def make_local_strategy(directory: str) -> None: def make_local_strategy(directory: str) -> None:
for resource in self.LOCAL_RESOURCES: for resource in self.LOCAL_RESOURCES:
contents = resource_text(f'empty_template_{resource}') resource_dirname, resource_basename = os.path.split(resource)
with open(os.path.join(directory, resource), 'w') as f: 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) f.write(contents)
env = git.no_git_env() env = git.no_git_env()

View file

@ -1,6 +1,6 @@
[metadata] [metadata]
name = pre_commit name = pre_commit
version = 2.12.1 version = 2.13.0
description = A framework for managing and maintaining multi-language pre-commit hooks. description = A framework for managing and maintaining multi-language pre-commit hooks.
long_description = file: README.md long_description = file: README.md
long_description_content_type = text/markdown long_description_content_type = text/markdown

View file

@ -1,5 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import argparse import argparse
import gzip
import os.path import os.path
import shutil import shutil
import subprocess import subprocess
@ -14,25 +15,24 @@ from typing import Sequence
REPOS = ( REPOS = (
('rbenv', 'git://github.com/rbenv/rbenv', '0843745'), ('rbenv', 'https://github.com/rbenv/rbenv', '585ed84'),
('ruby-build', 'git://github.com/rbenv/ruby-build', '500863c'), ('ruby-build', 'https://github.com/rbenv/ruby-build', 'e9fa4bf'),
( (
'ruby-download', 'ruby-download',
'git://github.com/garnieretienne/rvm-download', 'https://github.com/garnieretienne/rvm-download',
'09bd7c6', '09bd7c6',
), ),
) )
def make_archive(name: str, repo: str, ref: str, destdir: str) -> str: def reset(tarinfo: tarfile.TarInfo) -> tarfile.TarInfo:
"""Makes an archive of a repository in the given destdir. tarinfo.uid = tarinfo.gid = 0
tarinfo.uname = tarinfo.gname = 'root'
tarinfo.mtime = 0
return tarinfo
:param text name: Name to give the archive. For instance foo. The file
that is created will be called foo.tar.gz. def make_archive(name: str, repo: str, ref: str, destdir: str) -> str:
:param text repo: Repository to clone.
:param text ref: Tag/SHA/branch to check out.
:param text destdir: Directory to place archives in.
"""
output_path = os.path.join(destdir, f'{name}.tar.gz') output_path = os.path.join(destdir, f'{name}.tar.gz')
with tempfile.TemporaryDirectory() as tmpdir: with tempfile.TemporaryDirectory() as tmpdir:
# this ensures that the root directory has umask permissions # this ensures that the root directory has umask permissions
@ -47,8 +47,24 @@ def make_archive(name: str, repo: str, ref: str, destdir: str) -> str:
# runtime # runtime
shutil.rmtree(os.path.join(gitdir, '.git')) shutil.rmtree(os.path.join(gitdir, '.git'))
with tarfile.open(output_path, 'w|gz') as tf: arcs = [(name, gitdir)]
tf.add(gitdir, name) for root, dirs, filenames in os.walk(gitdir):
for filename in dirs + filenames:
abspath = os.path.abspath(os.path.join(root, filename))
relpath = os.path.relpath(abspath, gitdir)
arcs.append((os.path.join(name, relpath), abspath))
arcs.sort()
with gzip.GzipFile(output_path, 'wb', mtime=0) as gzipf:
# https://github.com/python/typeshed/issues/5491
with tarfile.open(fileobj=gzipf, mode='w') as tf: # type: ignore
for arcname, abspath in arcs:
tf.add(
abspath,
arcname=arcname,
recursive=False,
filter=reset,
)
return output_path return output_path

View file

@ -0,0 +1,7 @@
Copyright 2021 RStudio, PBC
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,440 @@
local({
# the requested version of renv
version <- "0.12.5"
# the project directory
project <- getwd()
# avoid recursion
if (!is.na(Sys.getenv("RENV_R_INITIALIZING", unset = NA)))
return(invisible(TRUE))
# signal that we're loading renv during R startup
Sys.setenv("RENV_R_INITIALIZING" = "true")
on.exit(Sys.unsetenv("RENV_R_INITIALIZING"), add = TRUE)
# signal that we've consented to use renv
options(renv.consent = TRUE)
# load the 'utils' package eagerly -- this ensures that renv shims, which
# mask 'utils' packages, will come first on the search path
library(utils, lib.loc = .Library)
# check to see if renv has already been loaded
if ("renv" %in% loadedNamespaces()) {
# if renv has already been loaded, and it's the requested version of renv,
# nothing to do
spec <- .getNamespaceInfo(.getNamespace("renv"), "spec")
if (identical(spec[["version"]], version))
return(invisible(TRUE))
# otherwise, unload and attempt to load the correct version of renv
unloadNamespace("renv")
}
# load bootstrap tools
bootstrap <- function(version, library) {
# attempt to download renv
tarball <- tryCatch(renv_bootstrap_download(version), error = identity)
if (inherits(tarball, "error"))
stop("failed to download renv ", version)
# now attempt to install
status <- tryCatch(renv_bootstrap_install(version, tarball, library), error = identity)
if (inherits(status, "error"))
stop("failed to install renv ", version)
}
renv_bootstrap_tests_running <- function() {
getOption("renv.tests.running", default = FALSE)
}
renv_bootstrap_repos <- function() {
# check for repos override
repos <- Sys.getenv("RENV_CONFIG_REPOS_OVERRIDE", unset = NA)
if (!is.na(repos))
return(repos)
# if we're testing, re-use the test repositories
if (renv_bootstrap_tests_running())
return(getOption("renv.tests.repos"))
# retrieve current repos
repos <- getOption("repos")
# ensure @CRAN@ entries are resolved
repos[repos == "@CRAN@"] <- "https://cloud.r-project.org"
# add in renv.bootstrap.repos if set
default <- c(CRAN = "https://cloud.r-project.org")
extra <- getOption("renv.bootstrap.repos", default = default)
repos <- c(repos, extra)
# remove duplicates that might've snuck in
dupes <- duplicated(repos) | duplicated(names(repos))
repos[!dupes]
}
renv_bootstrap_download <- function(version) {
# if the renv version number has 4 components, assume it must
# be retrieved via github
nv <- numeric_version(version)
components <- unclass(nv)[[1]]
methods <- if (length(components) == 4L) {
list(
renv_bootstrap_download_github
)
} else {
list(
renv_bootstrap_download_cran_latest,
renv_bootstrap_download_cran_archive
)
}
for (method in methods) {
path <- tryCatch(method(version), error = identity)
if (is.character(path) && file.exists(path))
return(path)
}
stop("failed to download renv ", version)
}
renv_bootstrap_download_impl <- function(url, destfile) {
mode <- "wb"
# https://bugs.r-project.org/bugzilla/show_bug.cgi?id=17715
fixup <-
Sys.info()[["sysname"]] == "Windows" &&
substring(url, 1L, 5L) == "file:"
if (fixup)
mode <- "w+b"
utils::download.file(
url = url,
destfile = destfile,
mode = mode,
quiet = TRUE
)
}
renv_bootstrap_download_cran_latest <- function(version) {
repos <- renv_bootstrap_download_cran_latest_find(version)
message("* Downloading renv ", version, " from CRAN ... ", appendLF = FALSE)
info <- tryCatch(
utils::download.packages(
pkgs = "renv",
repos = repos,
destdir = tempdir(),
quiet = TRUE
),
condition = identity
)
if (inherits(info, "condition")) {
message("FAILED")
return(FALSE)
}
message("OK")
info[1, 2]
}
renv_bootstrap_download_cran_latest_find <- function(version) {
all <- renv_bootstrap_repos()
for (repos in all) {
db <- tryCatch(
as.data.frame(
x = utils::available.packages(repos = repos),
stringsAsFactors = FALSE
),
error = identity
)
if (inherits(db, "error"))
next
entry <- db[db$Package %in% "renv" & db$Version %in% version, ]
if (nrow(entry) == 0)
next
return(repos)
}
fmt <- "renv %s is not available from your declared package repositories"
stop(sprintf(fmt, version))
}
renv_bootstrap_download_cran_archive <- function(version) {
name <- sprintf("renv_%s.tar.gz", version)
repos <- renv_bootstrap_repos()
urls <- file.path(repos, "src/contrib/Archive/renv", name)
destfile <- file.path(tempdir(), name)
message("* Downloading renv ", version, " from CRAN archive ... ", appendLF = FALSE)
for (url in urls) {
status <- tryCatch(
renv_bootstrap_download_impl(url, destfile),
condition = identity
)
if (identical(status, 0L)) {
message("OK")
return(destfile)
}
}
message("FAILED")
return(FALSE)
}
renv_bootstrap_download_github <- function(version) {
enabled <- Sys.getenv("RENV_BOOTSTRAP_FROM_GITHUB", unset = "TRUE")
if (!identical(enabled, "TRUE"))
return(FALSE)
# prepare download options
pat <- Sys.getenv("GITHUB_PAT")
if (nzchar(Sys.which("curl")) && nzchar(pat)) {
fmt <- "--location --fail --header \"Authorization: token %s\""
extra <- sprintf(fmt, pat)
saved <- options("download.file.method", "download.file.extra")
options(download.file.method = "curl", download.file.extra = extra)
on.exit(do.call(base::options, saved), add = TRUE)
} else if (nzchar(Sys.which("wget")) && nzchar(pat)) {
fmt <- "--header=\"Authorization: token %s\""
extra <- sprintf(fmt, pat)
saved <- options("download.file.method", "download.file.extra")
options(download.file.method = "wget", download.file.extra = extra)
on.exit(do.call(base::options, saved), add = TRUE)
}
message("* Downloading renv ", version, " from GitHub ... ", appendLF = FALSE)
url <- file.path("https://api.github.com/repos/rstudio/renv/tarball", version)
name <- sprintf("renv_%s.tar.gz", version)
destfile <- file.path(tempdir(), name)
status <- tryCatch(
renv_bootstrap_download_impl(url, destfile),
condition = identity
)
if (!identical(status, 0L)) {
message("FAILED")
return(FALSE)
}
message("OK")
return(destfile)
}
renv_bootstrap_install <- function(version, tarball, library) {
# attempt to install it into project library
message("* Installing renv ", version, " ... ", appendLF = FALSE)
dir.create(library, showWarnings = FALSE, recursive = TRUE)
# invoke using system2 so we can capture and report output
bin <- R.home("bin")
exe <- if (Sys.info()[["sysname"]] == "Windows") "R.exe" else "R"
r <- file.path(bin, exe)
args <- c("--vanilla", "CMD", "INSTALL", "-l", shQuote(library), shQuote(tarball))
output <- system2(r, args, stdout = TRUE, stderr = TRUE)
message("Done!")
# check for successful install
status <- attr(output, "status")
if (is.numeric(status) && !identical(status, 0L)) {
header <- "Error installing renv:"
lines <- paste(rep.int("=", nchar(header)), collapse = "")
text <- c(header, lines, output)
writeLines(text, con = stderr())
}
status
}
renv_bootstrap_prefix <- function() {
# construct version prefix
version <- paste(R.version$major, R.version$minor, sep = ".")
prefix <- paste("R", numeric_version(version)[1, 1:2], sep = "-")
# include SVN revision for development versions of R
# (to avoid sharing platform-specific artefacts with released versions of R)
devel <-
identical(R.version[["status"]], "Under development (unstable)") ||
identical(R.version[["nickname"]], "Unsuffered Consequences")
if (devel)
prefix <- paste(prefix, R.version[["svn rev"]], sep = "-r")
# build list of path components
components <- c(prefix, R.version$platform)
# include prefix if provided by user
prefix <- Sys.getenv("RENV_PATHS_PREFIX")
if (nzchar(prefix))
components <- c(prefix, components)
# build prefix
paste(components, collapse = "/")
}
renv_bootstrap_library_root_name <- function(project) {
# use project name as-is if requested
asis <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT_ASIS", unset = "FALSE")
if (asis)
return(basename(project))
# otherwise, disambiguate based on project's path
id <- substring(renv_bootstrap_hash_text(project), 1L, 8L)
paste(basename(project), id, sep = "-")
}
renv_bootstrap_library_root <- function(project) {
path <- Sys.getenv("RENV_PATHS_LIBRARY", unset = NA)
if (!is.na(path))
return(path)
path <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT", unset = NA)
if (!is.na(path)) {
name <- renv_bootstrap_library_root_name(project)
return(file.path(path, name))
}
file.path(project, "renv/library")
}
renv_bootstrap_validate_version <- function(version) {
loadedversion <- utils::packageDescription("renv", fields = "Version")
if (version == loadedversion)
return(TRUE)
# assume four-component versions are from GitHub; three-component
# versions are from CRAN
components <- strsplit(loadedversion, "[.-]")[[1]]
remote <- if (length(components) == 4L)
paste("rstudio/renv", loadedversion, sep = "@")
else
paste("renv", loadedversion, sep = "@")
fmt <- paste(
"renv %1$s was loaded from project library, but this project is configured to use renv %2$s.",
"Use `renv::record(\"%3$s\")` to record renv %1$s in the lockfile.",
"Use `renv::restore(packages = \"renv\")` to install renv %2$s into the project library.",
sep = "\n"
)
msg <- sprintf(fmt, loadedversion, version, remote)
warning(msg, call. = FALSE)
FALSE
}
renv_bootstrap_hash_text <- function(text) {
hashfile <- tempfile("renv-hash-")
on.exit(unlink(hashfile), add = TRUE)
writeLines(text, con = hashfile)
tools::md5sum(hashfile)
}
renv_bootstrap_load <- function(project, libpath, version) {
# try to load renv from the project library
if (!requireNamespace("renv", lib.loc = libpath, quietly = TRUE))
return(FALSE)
# warn if the version of renv loaded does not match
renv_bootstrap_validate_version(version)
# load the project
renv::load(project)
TRUE
}
# construct path to library root
root <- renv_bootstrap_library_root(project)
# construct library prefix for platform
prefix <- renv_bootstrap_prefix()
# construct full libpath
libpath <- file.path(root, prefix)
# attempt to load
if (renv_bootstrap_load(project, libpath, version))
return(TRUE)
# load failed; inform user we're about to bootstrap
prefix <- paste("# Bootstrapping renv", version)
postfix <- paste(rep.int("-", 77L - nchar(prefix)), collapse = "")
header <- paste(prefix, postfix)
message(header)
# perform bootstrap
bootstrap(version, libpath)
# exit early if we're just testing bootstrap
if (!is.na(Sys.getenv("RENV_BOOTSTRAP_INSTALL_ONLY", unset = NA)))
return(TRUE)
# try again to load
if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) {
message("* Successfully installed and loaded renv ", version, ".")
return(renv::load())
}
# failed to download or load renv; warn the user
msg <- c(
"Failed to find an renv installation: the project will not be loaded.",
"Use `renv::activate()` to re-initialize the project."
)
warning(paste(msg, collapse = "\n"), call. = FALSE)
})

View file

@ -526,9 +526,9 @@ def test_merge_conflict(cap_out, store, in_merge_conflict):
def test_merge_conflict_modified(cap_out, store, in_merge_conflict): def test_merge_conflict_modified(cap_out, store, in_merge_conflict):
# Touch another file so we have unstaged non-conflicting things # Touch another file so we have unstaged non-conflicting things
assert os.path.exists('dummy') assert os.path.exists('placeholder')
with open('dummy', 'w') as dummy_file: with open('placeholder', 'w') as placeholder_file:
dummy_file.write('bar\nbaz\n') placeholder_file.write('bar\nbaz\n')
ret, printed = _do_run(cap_out, store, in_merge_conflict, run_opts()) ret, printed = _do_run(cap_out, store, in_merge_conflict, run_opts())
assert ret == 1 assert ret == 1
@ -600,6 +600,29 @@ def test_skip_aliased_hook(cap_out, store, aliased_repo):
assert printed.count(msg) == 1 assert printed.count(msg) == 1
def test_skip_bypasses_installation(cap_out, store, repo_with_passing_hook):
config = {
'repo': 'local',
'hooks': [
{
'id': 'skipme',
'name': 'skipme',
'entry': 'skipme',
'language': 'python',
'additional_dependencies': ['/pre-commit-does-not-exist'],
},
],
}
add_config_to_repo(repo_with_passing_hook, config)
ret, printed = _do_run(
cap_out, store, repo_with_passing_hook,
run_opts(all_files=True),
{'SKIP': 'skipme'},
)
assert ret == 0
def test_hook_id_not_in_non_verbose_output( def test_hook_id_not_in_non_verbose_output(
cap_out, store, repo_with_passing_hook, cap_out, store, repo_with_passing_hook,
): ):
@ -808,9 +831,9 @@ def test_local_hook_passes(cap_out, store, repo_with_passing_hook):
} }
add_config_to_repo(repo_with_passing_hook, config) add_config_to_repo(repo_with_passing_hook, config)
with open('dummy.py', 'w') as staged_file: with open('placeholder.py', 'w') as staged_file:
staged_file.write('"""TODO: something"""\n') staged_file.write('"""TODO: something"""\n')
cmd_output('git', 'add', 'dummy.py') cmd_output('git', 'add', 'placeholder.py')
_test_run( _test_run(
cap_out, cap_out,
@ -835,9 +858,9 @@ def test_local_hook_fails(cap_out, store, repo_with_passing_hook):
} }
add_config_to_repo(repo_with_passing_hook, config) add_config_to_repo(repo_with_passing_hook, config)
with open('dummy.py', 'w') as staged_file: with open('placeholder.py', 'w') as staged_file:
staged_file.write('"""TODO: something"""\n') staged_file.write('"""TODO: something"""\n')
cmd_output('git', 'add', 'dummy.py') cmd_output('git', 'add', 'placeholder.py')
_test_run( _test_run(
cap_out, cap_out,

View file

@ -90,8 +90,8 @@ def _make_conflict():
@pytest.fixture @pytest.fixture
def in_merge_conflict(tempdir_factory): def in_merge_conflict(tempdir_factory):
path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') path = make_consuming_repo(tempdir_factory, 'script_hooks_repo')
open(os.path.join(path, 'dummy'), 'a').close() open(os.path.join(path, 'placeholder'), 'a').close()
cmd_output('git', 'add', 'dummy', cwd=path) cmd_output('git', 'add', 'placeholder', cwd=path)
git_commit(msg=in_merge_conflict.__name__, cwd=path) git_commit(msg=in_merge_conflict.__name__, cwd=path)
conflict_path = tempdir_factory.get() conflict_path = tempdir_factory.get()

View file

@ -1,14 +1,155 @@
import builtins
import json
import ntpath
import os.path
import posixpath
from unittest import mock from unittest import mock
import pytest
from pre_commit.languages import docker from pre_commit.languages import docker
def test_docker_fallback_user(): def test_docker_fallback_user():
def invalid_attribute(): def invalid_attribute():
raise AttributeError raise AttributeError
with mock.patch.multiple( with mock.patch.multiple(
'os', create=True, 'os', create=True,
getuid=invalid_attribute, getuid=invalid_attribute,
getgid=invalid_attribute, getgid=invalid_attribute,
): ):
assert docker.get_docker_user() == () assert docker.get_docker_user() == ()
def test_in_docker_no_file():
with mock.patch.object(builtins, 'open', side_effect=FileNotFoundError):
assert docker._is_in_docker() is False
def _mock_open(data):
return mock.patch.object(
builtins,
'open',
new_callable=mock.mock_open,
read_data=data,
)
def test_in_docker_docker_in_file():
docker_cgroup_example = b'''\
12:hugetlb:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
11:blkio:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
10:freezer:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
9:cpu,cpuacct:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
8:pids:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
7:rdma:/
6:net_cls,net_prio:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
5:cpuset:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
4:devices:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
3:memory:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
2:perf_event:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
1:name=systemd:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
0::/system.slice/containerd.service
''' # noqa: E501
with _mock_open(docker_cgroup_example):
assert docker._is_in_docker() is True
def test_in_docker_docker_not_in_file():
non_docker_cgroup_example = b'''\
12:perf_event:/
11:hugetlb:/
10:devices:/
9:blkio:/
8:rdma:/
7:cpuset:/
6:cpu,cpuacct:/
5:freezer:/
4:memory:/
3:pids:/
2:net_cls,net_prio:/
1:name=systemd:/init.scope
0::/init.scope
'''
with _mock_open(non_docker_cgroup_example):
assert docker._is_in_docker() is False
def test_get_docker_path_not_in_docker_returns_same():
with mock.patch.object(docker, '_is_in_docker', return_value=False):
assert docker._get_docker_path('abc') == 'abc'
@pytest.fixture
def in_docker():
with mock.patch.object(docker, '_is_in_docker', return_value=True):
yield
def _linux_commonpath():
return mock.patch.object(os.path, 'commonpath', posixpath.commonpath)
def _nt_commonpath():
return mock.patch.object(os.path, 'commonpath', ntpath.commonpath)
def _docker_output(out):
ret = (0, out, b'')
return mock.patch.object(docker, 'cmd_output_b', return_value=ret)
def test_get_docker_path_in_docker_no_binds_same_path(in_docker):
docker_out = json.dumps([{'Mounts': []}]).encode()
with _docker_output(docker_out):
assert docker._get_docker_path('abc') == 'abc'
def test_get_docker_path_in_docker_binds_path_equal(in_docker):
binds_list = [{'Source': '/opt/my_code', 'Destination': '/project'}]
docker_out = json.dumps([{'Mounts': binds_list}]).encode()
with _linux_commonpath(), _docker_output(docker_out):
assert docker._get_docker_path('/project') == '/opt/my_code'
def test_get_docker_path_in_docker_binds_path_complex(in_docker):
binds_list = [{'Source': '/opt/my_code', 'Destination': '/project'}]
docker_out = json.dumps([{'Mounts': binds_list}]).encode()
with _linux_commonpath(), _docker_output(docker_out):
path = '/project/test/something'
assert docker._get_docker_path(path) == '/opt/my_code/test/something'
def test_get_docker_path_in_docker_no_substring(in_docker):
binds_list = [{'Source': '/opt/my_code', 'Destination': '/project'}]
docker_out = json.dumps([{'Mounts': binds_list}]).encode()
with _linux_commonpath(), _docker_output(docker_out):
path = '/projectSuffix/test/something'
assert docker._get_docker_path(path) == path
def test_get_docker_path_in_docker_binds_path_many_binds(in_docker):
binds_list = [
{'Source': '/something_random', 'Destination': '/not-related'},
{'Source': '/opt/my_code', 'Destination': '/project'},
{'Source': '/something-random-2', 'Destination': '/not-related-2'},
]
docker_out = json.dumps([{'Mounts': binds_list}]).encode()
with _linux_commonpath(), _docker_output(docker_out):
assert docker._get_docker_path('/project') == '/opt/my_code'
def test_get_docker_path_in_docker_windows(in_docker):
binds_list = [{'Source': r'c:\users\user', 'Destination': r'c:\folder'}]
docker_out = json.dumps([{'Mounts': binds_list}]).encode()
with _nt_commonpath(), _docker_output(docker_out):
path = r'c:\folder\test\something'
expected = r'c:\users\user\test\something'
assert docker._get_docker_path(path) == expected

View file

@ -14,10 +14,12 @@ def _test_r_parsing(
hook_id, hook_id,
expected_hook_expr={}, expected_hook_expr={},
expected_args={}, expected_args={},
config={},
expect_path_prefix=True,
): ):
repo_path = 'r_hooks_repo' repo_path = 'r_hooks_repo'
path = make_repo(tempdir_factory, repo_path) path = make_repo(tempdir_factory, repo_path)
config = make_config_from_repo(path) config = config or make_config_from_repo(path)
hook = _get_hook_no_install(config, store, hook_id) hook = _get_hook_no_install(config, store, hook_id)
ret = r._cmd_from_hook(hook) ret = r._cmd_from_hook(hook)
expected_cmd = 'Rscript' expected_cmd = 'Rscript'
@ -25,7 +27,8 @@ def _test_r_parsing(
'--no-save', '--no-restore', '--no-site-file', '--no-environ', '--no-save', '--no-restore', '--no-site-file', '--no-environ',
) )
expected_path = os.path.join( expected_path = os.path.join(
hook.prefix.prefix_dir, '.'.join([hook_id, 'R']), hook.prefix.prefix_dir if expect_path_prefix else '',
f'{hook_id}.R',
) )
expected = ( expected = (
expected_cmd, expected_cmd,
@ -102,3 +105,25 @@ def test_r_parsing_expr_non_Rscirpt(tempdir_factory, store):
msg = execinfo.value.args msg = execinfo.value.args
assert msg == ('entry must start with `Rscript`.',) assert msg == ('entry must start with `Rscript`.',)
def test_r_parsing_file_local(tempdir_factory, store):
path = 'path/to/script.R'
hook_id = 'local-r'
config = {
'repo': 'local',
'hooks': [{
'id': hook_id,
'name': 'local-r',
'entry': f'Rscript {path}',
'language': 'r',
}],
}
_test_r_parsing(
tempdir_factory,
store,
hook_id=hook_id,
expected_hook_expr=(path,),
config=config,
expect_path_prefix=False,
)

View file

@ -36,13 +36,13 @@ def test_uses_system_if_both_gem_and_ruby_are_available(find_exe_mck):
def fake_gem_prefix(tmpdir): def fake_gem_prefix(tmpdir):
gemspec = '''\ gemspec = '''\
Gem::Specification.new do |s| Gem::Specification.new do |s|
s.name = 'pre_commit_dummy_package' s.name = 'pre_commit_placeholder_package'
s.version = '0.0.0' s.version = '0.0.0'
s.summary = 'dummy gem for pre-commit hooks' s.summary = 'placeholder gem for pre-commit hooks'
s.authors = ['Anthony Sottile'] s.authors = ['Anthony Sottile']
end end
''' '''
tmpdir.join('dummy_gem.gemspec').write(gemspec) tmpdir.join('placeholder_gem.gemspec').write(gemspec)
yield Prefix(tmpdir) yield Prefix(tmpdir)
@ -53,7 +53,7 @@ def test_install_ruby_system(fake_gem_prefix):
# Should be able to activate and use rbenv install # Should be able to activate and use rbenv install
with ruby.in_env(fake_gem_prefix, 'system'): with ruby.in_env(fake_gem_prefix, 'system'):
_, out, _ = cmd_output('gem', 'list') _, out, _ = cmd_output('gem', 'list')
assert 'pre_commit_dummy_package' in out assert 'pre_commit_placeholder_package' in out
@xfailif_windows # pragma: win32 no cover @xfailif_windows # pragma: win32 no cover

View file

@ -186,7 +186,7 @@ def test_local_resources_reflects_reality():
for res in os.listdir('pre_commit/resources') for res in os.listdir('pre_commit/resources')
if res.startswith('empty_template_') if res.startswith('empty_template_')
} }
assert on_disk == set(Store.LOCAL_RESOURCES) assert on_disk == {os.path.basename(x) for x in Store.LOCAL_RESOURCES}
def test_mark_config_as_used(store, tmpdir): def test_mark_config_as_used(store, tmpdir):