Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 19bc0dc

Browse files
committed
Merge pull request #355 from pre-commit/env_context
Factor out bash and activate files
2 parents 495e21b + f8c82f9 commit 19bc0dc

27 files changed

Lines changed: 733 additions & 272 deletions

Makefile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
REBUILD_FLAG =
32

43
.PHONY: all
@@ -21,7 +20,7 @@ test: .venv.touch
2120

2221
.PHONY: clean
2322
clean:
24-
find . -iname '*.pyc' | xargs rm -f
23+
find . -name '*.pyc' -delete
2524
rm -rf .tox
2625
rm -rf ./venv-*
2726
rm -f .venv.touch

pre_commit/commands/install_uninstall.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
import logging
66
import os
77
import os.path
8-
import stat
98
import sys
109

1110
from pre_commit.logging_handler import LoggingHandler
11+
from pre_commit.util import make_executable
1212
from pre_commit.util import mkdirp
1313
from pre_commit.util import resource_filename
1414

@@ -42,14 +42,6 @@ def is_previous_pre_commit(filename):
4242
return any(hash in contents for hash in PREVIOUS_IDENTIFYING_HASHES)
4343

4444

45-
def make_executable(filename):
46-
original_mode = os.stat(filename).st_mode
47-
os.chmod(
48-
filename,
49-
original_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH,
50-
)
51-
52-
5345
def install(runner, overwrite=False, hooks=False, hook_type='pre-commit'):
5446
"""Install the pre-commit hooks."""
5547
hook_path = runner.get_hook_path(hook_type)

pre_commit/commands/run.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def _run_single_hook(hook, repo, args, write, skips=frozenset()):
8686
sys.stdout.flush()
8787

8888
diff_before = cmd_output('git', 'diff', retcode=None, encoding=None)
89-
retcode, stdout, stderr = repo.run_hook(hook, filenames)
89+
retcode, stdout, stderr = repo.run_hook(hook, tuple(filenames))
9090
diff_after = cmd_output('git', 'diff', retcode=None, encoding=None)
9191

9292
file_modifications = diff_before != diff_after

pre_commit/envcontext.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
from __future__ import absolute_import
2+
from __future__ import unicode_literals
3+
4+
import collections
5+
import contextlib
6+
import os
7+
8+
from pre_commit import five
9+
10+
11+
UNSET = collections.namedtuple('UNSET', ())()
12+
13+
14+
Var = collections.namedtuple('Var', ('name', 'default'))
15+
setattr(Var.__new__, five.defaults_attr, ('',))
16+
17+
18+
def format_env(parts, env):
19+
return ''.join(
20+
env.get(part.name, part.default)
21+
if isinstance(part, Var)
22+
else part
23+
for part in parts
24+
)
25+
26+
27+
@contextlib.contextmanager
28+
def envcontext(patch, _env=None):
29+
"""In this context, `os.environ` is modified according to `patch`.
30+
31+
`patch` is an iterable of 2-tuples (key, value):
32+
`key`: string
33+
`value`:
34+
- string: `environ[key] == value` inside the context.
35+
- UNSET: `key not in environ` inside the context.
36+
- template: A template is a tuple of strings and Var which will be
37+
replaced with the previous environment
38+
"""
39+
env = os.environ if _env is None else _env
40+
before = env.copy()
41+
42+
for k, v in patch:
43+
if v is UNSET:
44+
env.pop(k, None)
45+
elif isinstance(v, tuple):
46+
env[k] = format_env(v, before)
47+
else:
48+
env[k] = v
49+
50+
try:
51+
yield
52+
finally:
53+
env.clear()
54+
env.update(before)

pre_commit/five.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ def n(s):
1212
return s
1313
else:
1414
return s.encode('UTF-8')
15+
16+
defaults_attr = 'func_defaults'
1517
else: # pragma: no cover (PY3 only)
1618
text = str
1719

@@ -21,6 +23,8 @@ def n(s):
2123
else:
2224
return s.decode('UTF-8')
2325

26+
defaults_attr = '__defaults__'
27+
2428

2529
def to_text(s):
2630
return s if isinstance(s, text) else s.decode('UTF-8')

pre_commit/languages/all.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# def install_environment(
1616
# repo_cmd_runner,
1717
# version='default',
18-
# additional_dependencies=None,
18+
# additional_dependencies=(),
1919
# ):
2020
# """Installs a repository in the given repository. Note that the current
2121
# working directory will already be inside the repository.

pre_commit/languages/helpers.py

Lines changed: 5 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,14 @@
11
from __future__ import unicode_literals
22

3-
import pipes
3+
from pre_commit.util import cmd_output
4+
5+
6+
def run_setup_cmd(runner, cmd):
7+
cmd_output(*cmd, cwd=runner.prefix_dir, encoding=None)
48

59

610
def environment_dir(ENVIRONMENT_DIR, language_version):
711
if ENVIRONMENT_DIR is None:
812
return None
913
else:
1014
return '{0}-{1}'.format(ENVIRONMENT_DIR, language_version)
11-
12-
13-
def file_args_to_stdin(file_args):
14-
return '\0'.join(list(file_args) + [''])
15-
16-
17-
def run_hook(env, hook, file_args):
18-
quoted_args = [pipes.quote(arg) for arg in hook['args']]
19-
return env.run(
20-
# Use -s 4000 (slightly less than posix mandated minimum)
21-
# This is to prevent "xargs: ... Bad file number" on windows
22-
' '.join(['xargs', '-0', '-s4000', hook['entry']] + quoted_args),
23-
stdin=file_args_to_stdin(file_args),
24-
retcode=None,
25-
encoding=None,
26-
)
27-
28-
29-
class Environment(object):
30-
def __init__(self, repo_cmd_runner, language_version):
31-
self.repo_cmd_runner = repo_cmd_runner
32-
self.language_version = language_version
33-
34-
@property
35-
def env_prefix(self):
36-
"""env_prefix is a value that is prefixed to the command that is run.
37-
38-
Usually this is to source a virtualenv, etc.
39-
40-
Commands basically end up looking like:
41-
42-
bash -c '{env_prefix} {cmd}'
43-
44-
so you'll often want to end your prefix with &&
45-
"""
46-
raise NotImplementedError
47-
48-
def run(self, cmd, **kwargs):
49-
"""Returns (returncode, stdout, stderr)."""
50-
return self.repo_cmd_runner.run(
51-
['bash', '-c', ' '.join([self.env_prefix, cmd])], **kwargs
52-
)

pre_commit/languages/node.py

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,45 @@
11
from __future__ import unicode_literals
22

33
import contextlib
4+
import os
45
import sys
56

7+
from pre_commit.envcontext import envcontext
8+
from pre_commit.envcontext import Var
69
from pre_commit.languages import helpers
710
from pre_commit.util import clean_path_on_failure
8-
from pre_commit.util import shell_escape
11+
from pre_commit.xargs import xargs
912

1013

1114
ENVIRONMENT_DIR = 'node_env'
1215

1316

14-
class NodeEnv(helpers.Environment):
15-
@property
16-
def env_prefix(self):
17-
return ". '{{prefix}}{0}/bin/activate' &&".format(
18-
helpers.environment_dir(ENVIRONMENT_DIR, self.language_version),
19-
)
17+
def get_env_patch(venv):
18+
return (
19+
('NODE_VIRTUAL_ENV', venv),
20+
('NPM_CONFIG_PREFIX', venv),
21+
('npm_config_prefix', venv),
22+
('NODE_PATH', os.path.join(venv, 'lib', 'node_modules')),
23+
('PATH', (os.path.join(venv, 'bin'), os.pathsep, Var('PATH'))),
24+
)
2025

2126

2227
@contextlib.contextmanager
2328
def in_env(repo_cmd_runner, language_version):
24-
yield NodeEnv(repo_cmd_runner, language_version)
29+
envdir = os.path.join(
30+
repo_cmd_runner.prefix_dir,
31+
helpers.environment_dir(ENVIRONMENT_DIR, language_version),
32+
)
33+
with envcontext(get_env_patch(envdir)):
34+
yield
2535

2636

2737
def install_environment(
2838
repo_cmd_runner,
2939
version='default',
30-
additional_dependencies=None,
40+
additional_dependencies=(),
3141
):
42+
additional_dependencies = tuple(additional_dependencies)
3243
assert repo_cmd_runner.exists('package.json')
3344
directory = helpers.environment_dir(ENVIRONMENT_DIR, version)
3445

@@ -44,18 +55,13 @@ def install_environment(
4455

4556
repo_cmd_runner.run(cmd)
4657

47-
with in_env(repo_cmd_runner, version) as node_env:
48-
node_env.run("cd '{prefix}' && npm install -g", encoding=None)
49-
if additional_dependencies:
50-
node_env.run(
51-
"cd '{prefix}' && npm install -g " +
52-
' '.join(
53-
shell_escape(dep) for dep in additional_dependencies
54-
),
55-
encoding=None,
56-
)
58+
with in_env(repo_cmd_runner, version):
59+
helpers.run_setup_cmd(
60+
repo_cmd_runner,
61+
('npm', 'install', '-g', '.') + additional_dependencies,
62+
)
5763

5864

5965
def run_hook(repo_cmd_runner, hook, file_args):
60-
with in_env(repo_cmd_runner, hook['language_version']) as env:
61-
return helpers.run_hook(env, hook, file_args)
66+
with in_env(repo_cmd_runner, hook['language_version']):
67+
return xargs((hook['entry'],) + tuple(hook['args']), file_args)

pre_commit/languages/pcre.py

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22

33
from sys import platform
44

5-
from pre_commit.languages.helpers import file_args_to_stdin
6-
from pre_commit.util import shell_escape
5+
from pre_commit.xargs import xargs
76

87

98
ENVIRONMENT_DIR = None
@@ -12,29 +11,19 @@
1211
def install_environment(
1312
repo_cmd_runner,
1413
version='default',
15-
additional_dependencies=None,
14+
additional_dependencies=(),
1615
):
1716
"""Installation for pcre type is a noop."""
1817
raise AssertionError('Cannot install pcre repo.')
1918

2019

2120
def run_hook(repo_cmd_runner, hook, file_args):
22-
grep_command = 'grep -H -n -P'
23-
if platform == 'darwin': # pragma: no cover (osx)
24-
grep_command = 'ggrep -H -n -P'
25-
2621
# For PCRE the entry is the regular expression to match
27-
return repo_cmd_runner.run(
28-
[
29-
'xargs', '-0', 'sh', '-c',
30-
# Grep usually returns 0 for matches, and nonzero for non-matches
31-
# so we flip it here.
32-
'! {0} {1} {2} $@'.format(
33-
grep_command, ' '.join(hook['args']),
34-
shell_escape(hook['entry'])),
35-
'--',
36-
],
37-
stdin=file_args_to_stdin(file_args),
38-
retcode=None,
39-
encoding=None,
40-
)
22+
cmd = (
23+
'ggrep' if platform == 'darwin' else 'grep',
24+
'-H', '-n', '-P',
25+
) + tuple(hook['args']) + (hook['entry'],)
26+
27+
# Grep usually returns 0 for matches, and nonzero for non-matches so we
28+
# negate it here.
29+
return xargs(cmd, file_args, negate=True)

0 commit comments

Comments
 (0)