Merging upstream version 2.13.0.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
c2d1f037e4
commit
1e2278d3de
27 changed files with 1249 additions and 80 deletions
|
@ -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]
|
||||||
|
|
25
CHANGELOG.md
25
CHANGELOG.md
|
@ -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
|
||||||
===================
|
===================
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -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(
|
||||||
|
|
7
pre_commit/resources/empty_template_LICENSE.renv
Normal file
7
pre_commit/resources/empty_template_LICENSE.renv
Normal 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.
|
|
@ -1,6 +1,6 @@
|
||||||
use ExtUtils::MakeMaker;
|
use ExtUtils::MakeMaker;
|
||||||
|
|
||||||
WriteMakefile(
|
WriteMakefile(
|
||||||
NAME => "PreCommitDummy",
|
NAME => "PreCommitPlaceholder",
|
||||||
VERSION => "0.0.1",
|
VERSION => "0.0.1",
|
||||||
);
|
);
|
||||||
|
|
440
pre_commit/resources/empty_template_activate.R
Normal file
440
pre_commit/resources/empty_template_activate.R
Normal 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)
|
||||||
|
|
||||||
|
})
|
|
@ -1 +1 @@
|
||||||
module pre-commit-dummy-empty-module
|
module pre-commit-placeholder-empty-module
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{
|
{
|
||||||
"name": "pre_commit_dummy_package",
|
"name": "pre_commit_placeholder_package",
|
||||||
"version": "0.0.0"
|
"version": "0.0.0"
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
@ -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.
Binary file not shown.
Binary file not shown.
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
7
testing/resources/r_hooks_repo/renv/LICENSE
Normal file
7
testing/resources/r_hooks_repo/renv/LICENSE
Normal 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.
|
440
testing/resources/r_hooks_repo/renv/activate.R
Normal file
440
testing/resources/r_hooks_repo/renv/activate.R
Normal 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)
|
||||||
|
|
||||||
|
})
|
|
@ -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,
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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):
|
||||||
|
|
Loading…
Add table
Reference in a new issue