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

Skip to content

Commit 7bb7f4a

Browse files
committed
Initial commit.
0 parents  commit 7bb7f4a

10 files changed

Lines changed: 329 additions & 0 deletions

File tree

.coveragerc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[report]
2+
exclude_lines =
3+
# Don't complain about defensive assertions
4+
raise NotImplementedError
5+
raise AssertionError
6+
7+
# Don't complain about non-runnable code
8+
if __name__ == .__main__.:
9+
10+
omit =
11+
/usr/*
12+
py_env/*
13+
*/__init__.py
14+
15+
# Ignore test coverage
16+
tests/*
17+
18+
# Don't complain about our pre-commit file
19+
pre-commit.py

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
*.pyc
2+
.pydevproject
3+
.project
4+
.coverage
5+
/py_env
6+
*.db
7+
.idea
8+
build
9+
dist
10+
*.egg-info

.travis.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
language: python
2+
3+
python:
4+
- 2.6
5+
- 2.7
6+
7+
install: pip install virtualenv
8+
script: make

Makefile

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
2+
TEST_TARGETS =
3+
ITEST_TARGETS = -m integration
4+
UTEST_TARGETS = -m "not(integration)"
5+
6+
all: _tests
7+
8+
integration:
9+
$(eval TEST_TARGETS := $(ITEST_TARGETS))
10+
11+
unit:
12+
$(eval TEST_TARGETS := $(UTEST_TARGETS))
13+
14+
utests: test
15+
utest: test
16+
tests: test
17+
test: unit _tests
18+
itests: itest
19+
itest: integration _tests
20+
21+
_tests: py_env
22+
bash -c 'source py_env/bin/activate && py.test tests $(TEST_TARGETS)'
23+
24+
ucoverage: unit coverage
25+
icoverage: integration coverage
26+
27+
coverage: py_env
28+
bash -c 'source py_env/bin/activate && \
29+
coverage erase && \
30+
coverage run `which py.test` tests $(TEST_TARGETS) && \
31+
coverage report -m'
32+
33+
py_env: requirements.txt
34+
rm -rf py_env
35+
virtualenv py_env
36+
bash -c 'source py_env/bin/activate && \
37+
pip install -r requirements.txt'
38+
39+
clean:
40+
rm -rf py_env

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pre-commit
2+
==========
3+
4+
A framework for managing and maintaining multi-language pre-commit hooks.
5+

pre-commit.py

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
#!/usr/bin/env python
2+
3+
import collections
4+
import optparse
5+
import os
6+
import os.path
7+
import shutil
8+
import subprocess
9+
import sys
10+
11+
def __backport_check_output():
12+
def check_output(*popenargs, **kwargs):
13+
r"""Run command with arguments and return its output as a byte string.
14+
15+
Backported from Python 2.7 as it's implemented as pure python on stdlib.
16+
17+
>>> check_output(['/usr/bin/python', '--version'])
18+
Python 2.6.2
19+
"""
20+
process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs)
21+
output, unused_err = process.communicate()
22+
retcode = process.poll()
23+
if retcode:
24+
cmd = kwargs.get("args")
25+
if cmd is None:
26+
cmd = popenargs[0]
27+
error = subprocess.CalledProcessError(retcode, cmd)
28+
error.output = output
29+
raise error
30+
return output
31+
32+
if not hasattr(subprocess, 'check_output'):
33+
setattr(subprocess, 'check_output', check_output)
34+
35+
__backport_check_output()
36+
del __backport_check_output
37+
38+
39+
FILE_LIST = 'git ls-files | egrep "\.%s$"'
40+
41+
ALL_FILES = FILE_LIST % '(php|sql|py|js|htm|c|cpp|h|sh|css)'
42+
JS_FILES = FILE_LIST % 'js'
43+
PY_FILES = FILE_LIST % 'py'
44+
CPP_FILES = FILE_LIST % '(cc|cpp|h)'
45+
C_FILES = FILE_LIST % '(c|h)'
46+
C_LIKE_FILES = FILE_LIST % '(c|cc|cpp|h)'
47+
HEADER_FILES = FILE_LIST % 'h'
48+
49+
RED = '\033[41m'
50+
GREEN = '\033[42m'
51+
NORMAL = '\033[0m'
52+
COLS = int(subprocess.check_output(['tput', 'cols']))
53+
54+
Test = collections.namedtuple('Test', ['command', 'name', 'nonzero', 'config'])
55+
56+
TESTS = [
57+
Test(
58+
"%s | xargs pyflakes" % PY_FILES,
59+
'Py - Pyflakes',
60+
False, 'testpyflakes',
61+
),
62+
Test(
63+
"%s | xargs grep 'import\sipdb'" % PY_FILES,
64+
'Py - ipdb',
65+
True, 'testipdb',
66+
),
67+
Test(
68+
"%s | grep 'tests' | grep -v '_test.py$' | grep -v '__init__.py' | grep -v '/conftest.py'" % PY_FILES,
69+
'Py - Test files should end in _test.py',
70+
True, 'testtestnames',
71+
),
72+
Test(
73+
"%s | xargs egrep 'split\(.\\\\n.\)'" % PY_FILES,
74+
'Py - Use s.splitlines over s.split',
75+
True, 'testsplitlines',
76+
),
77+
Test(
78+
"%s | xargs grep -H -n -P '\t'" % ALL_FILES,
79+
"All - No tabs",
80+
True, 'testtabs',
81+
),
82+
Test(
83+
"make test",
84+
"Py - Tests",
85+
False, 'testtests',
86+
),
87+
]
88+
89+
def get_git_config(config_name):
90+
config_result = ''
91+
try:
92+
config_result = subprocess.check_output([
93+
'git', 'config', config_name
94+
])
95+
except subprocess.CalledProcessError: pass
96+
97+
return config_result.strip()
98+
99+
def get_pre_commit_path():
100+
git_top = subprocess.check_output(
101+
['git', 'rev-parse', '--show-toplevel']
102+
).strip()
103+
return os.path.join(git_top, '.git/hooks/pre-commit')
104+
105+
class FixAllBase(object):
106+
name = None
107+
matching_files_command = None
108+
109+
def get_all_files(self):
110+
try:
111+
files = subprocess.check_output(
112+
self.matching_files_command,
113+
shell=True,
114+
)
115+
files_split = files.splitlines()
116+
return [file.strip() for file in files_split]
117+
except subprocess.CalledProcessError:
118+
return []
119+
120+
def fix_file(self, file):
121+
'''Implement to fix the file.'''
122+
raise NotImplementedError
123+
124+
def run(self):
125+
'''Runs the process to fix the files. Returns True if nothign to fix.'''
126+
print '%s...' % self.name
127+
all_files = self.get_all_files()
128+
for file in all_files:
129+
print 'Fixing %s' % file
130+
self.fix_file(file)
131+
return not all_files
132+
133+
class FixTrailingWhitespace(FixAllBase):
134+
name = 'Trimming trailing whitespace'
135+
matching_files_command = '%s | xargs egrep -l "[[:space:]]$"' % ALL_FILES
136+
137+
def fix_file(self, file):
138+
subprocess.check_call(['sed', '-i', '-e', 's/[[:space:]]*$//', file])
139+
140+
class FixLineEndings(FixAllBase):
141+
name = 'Fixing line endings'
142+
matching_files_command = "%s | xargs egrep -l $'\\r'\\$" % ALL_FILES
143+
144+
def fix_file(self, file):
145+
subprocess.check_call(['dos2unix', file])
146+
subprocess.check_call(['mac2unix', file])
147+
148+
FIXERS = [
149+
FixTrailingWhitespace,
150+
FixLineEndings,
151+
]
152+
153+
def run_tests():
154+
passed = True
155+
for test in TESTS:
156+
run_test = get_git_config('hooks.%s' % test.config)
157+
if run_test == 'false':
158+
print 'Skipping "%s" due to git config.' % test.name
159+
continue
160+
161+
try:
162+
retcode = 0
163+
output = subprocess.check_output(
164+
test.command, shell=True, stderr=subprocess.STDOUT
165+
)
166+
except subprocess.CalledProcessError as e:
167+
retcode = e.returncode
168+
output = e.output
169+
170+
pass_fail = '%sSuccess%s' % (GREEN, NORMAL)
171+
failed_test = False
172+
if (retcode and not test.nonzero) or (not retcode and test.nonzero):
173+
pass_fail = '%sFailure(%s)%s' % (RED, retcode, NORMAL)
174+
failed_test = True
175+
176+
dots = COLS - len(pass_fail) - len(test.name)
177+
print '%s%s%s' % (test.name, '.' * dots, pass_fail)
178+
179+
if failed_test:
180+
print
181+
print output
182+
passed = False
183+
184+
return passed
185+
186+
if __name__ == '__main__':
187+
parser = optparse.OptionParser()
188+
parser.add_option(
189+
'-u', '--uninstall',
190+
action='store_true', dest='uninstall', default=False,
191+
help='Uninstall pre-commit script.'
192+
)
193+
parser.add_option(
194+
'-i', '--install',
195+
action='store_true', dest='install', default=False,
196+
help='Install pre-commit script.'
197+
)
198+
opts, args = parser.parse_args()
199+
200+
if opts.install:
201+
pre_commit_path = get_pre_commit_path()
202+
shutil.copyfile(__file__, pre_commit_path)
203+
os.chmod(pre_commit_path, 0755)
204+
print 'Installed pre commit to %s' % pre_commit_path
205+
sys.exit(0)
206+
elif opts.uninstall:
207+
pre_commit_path = get_pre_commit_path()
208+
if os.path.exists(pre_commit_path):
209+
os.remove(pre_commit_path)
210+
print 'Removed pre-commit scripts.'
211+
212+
passed = True
213+
for fixer in FIXERS:
214+
passed &= fixer().run()
215+
passed &= run_tests()
216+
217+
if not passed:
218+
print '%sFailures / Fixes detected.%s' % (RED, NORMAL)
219+
print 'Please fix and commit again.'
220+
print "You could also pass --no-verify, but you probably shouldn't."
221+
print
222+
print "Here's git status for convenience: "
223+
print
224+
os.system('git status')
225+
sys.exit(-1)

pre_commit/__init__.py

Whitespace-only changes.

requirements.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
argparse
2+
pyyaml
3+
simplejson
4+
5+
# Testing requirements
6+
coverage
7+
ipdb
8+
mock
9+
pyflakes
10+
pytest

setup.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from setuptools import find_packages
2+
from setuptools import setup
3+
4+
setup(
5+
name='pre_commit',
6+
version='0.3.4',
7+
packages=find_packages('.', exclude=('tests*', 'testing*')),
8+
install_requires=[
9+
'argparse',
10+
'simplejson',
11+
],
12+
)

tests/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)