forked from kovidgoyal/calibre
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcheck.py
120 lines (98 loc) · 4.01 KB
/
check.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#!/usr/bin/env python2
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import with_statement
__license__ = 'GPL v3'
__copyright__ = '2009, Kovid Goyal <[email protected]>'
__docformat__ = 'restructuredtext en'
import os, json, subprocess, errno, hashlib
from setup import Command, build_cache_dir, edit_file, dump_json
class Message:
def __init__(self, filename, lineno, msg):
self.filename, self.lineno, self.msg = filename, lineno, msg
def __str__(self):
return '%s:%s: %s' % (self.filename, self.lineno, self.msg)
class Check(Command):
description = 'Check for errors in the calibre source code'
CACHE = 'check.json'
def get_files(self):
for dname in ('odf', 'calibre'):
for x in os.walk(self.j(self.SRC, dname)):
for f in x[-1]:
y = self.j(x[0], f)
if (f.endswith('.py') and f not in (
'dict_data.py', 'unicodepoints.py', 'krcodepoints.py',
'jacodepoints.py', 'vncodepoints.py', 'zhcodepoints.py') and
'prs500/driver.py' not in y) and not f.endswith('_ui.py'):
yield y
for x in os.walk(self.j(self.d(self.SRC), 'recipes')):
for f in x[-1]:
f = self.j(x[0], f)
if f.endswith('.recipe'):
yield f
for x in os.walk(self.j(self.SRC, 'pyj')):
for f in x[-1]:
f = self.j(x[0], f)
if f.endswith('.pyj'):
yield f
if self.has_changelog_check:
yield self.j(self.d(self.SRC), 'Changelog.yaml')
def read_file(self, f):
with open(f, 'rb') as f:
return f.read()
def file_hash(self, f):
try:
return self.fhash_cache[f]
except KeyError:
self.fhash_cache[f] = ans = hashlib.sha1(self.read_file(f)).hexdigest()
return ans
def is_cache_valid(self, f, cache):
return cache.get(f) == self.file_hash(f)
@property
def cache_file(self):
return self.j(build_cache_dir(), self.CACHE)
def save_cache(self, cache):
dump_json(cache, self.cache_file)
def file_has_errors(self, f):
ext = os.path.splitext(f)[1]
if ext in {'.py', '.recipe'}:
p1 = subprocess.Popen(['flake8-python2', '--filename', '*.py,*.recipe', f])
p2 = subprocess.Popen(['flake8', '--filename', '*.py,*.recipe', f])
codes = p1.wait(), p2.wait()
return codes != (0, 0)
if ext == '.pyj':
p = subprocess.Popen(['rapydscript', 'lint', f])
return p.wait() != 0
if ext == '.yaml':
p = subprocess.Popen(['python', self.j(self.wn_path, 'whats_new.py'), f])
return p.wait() != 0
def run(self, opts):
self.fhash_cache = {}
cache = {}
self.wn_path = os.path.expanduser('~/work/srv/main/static')
self.has_changelog_check = os.path.exists(self.wn_path)
try:
cache = json.load(open(self.cache_file, 'rb'))
except EnvironmentError as err:
if err.errno != errno.ENOENT:
raise
dirty_files = tuple(f for f in self.get_files() if not self.is_cache_valid(f, cache))
try:
for i, f in enumerate(dirty_files):
self.info('\tChecking', f)
if self.file_has_errors(f):
self.info('%d files left to check' % (len(dirty_files) - i - 1))
edit_file(f)
if self.file_has_errors(f):
raise SystemExit(1)
cache[f] = self.file_hash(f)
finally:
self.save_cache(cache)
def report_errors(self, errors):
for err in errors:
self.info('\t\t', str(err))
def clean(self):
try:
os.remove(self.cache_file)
except EnvironmentError as err:
if err.errno != errno.ENOENT:
raise