blob: c9e28ea862d90cac13c8a9a10ebfceeebd97c010 [file] [log] [blame]
Aurimas Liutikas0383fc22016-12-14 19:09:31 -08001# Copyright 2013-2014 Sebastian Kreft
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14"""Common function used across modules."""
15
16import io
17import os
18import re
19
20
21def filter_lines(lines, filter_regex, groups=None):
22 """Filters out the lines not matching the pattern.
23
24 Args:
25 lines: list[string]: lines to filter.
26 pattern: string: regular expression to filter out lines.
27
28 Returns: list[string]: the list of filtered lines.
29 """
30 pattern = re.compile(filter_regex)
31 for line in lines:
32 match = pattern.search(line)
33 if match:
34 if groups is None:
35 yield line
36 elif len(groups) == 1:
37 yield match.group(groups[0])
38 else:
39 matched_groups = match.groupdict()
40 yield tuple(matched_groups.get(group) for group in groups)
41
42
43# TODO(skreft): add test
44def which(program):
45 """Returns a list of paths where the program is found."""
46 if (os.path.isabs(program) and os.path.isfile(program) and
47 os.access(program, os.X_OK)):
48 return [program]
49
50 candidates = []
51 locations = os.environ.get("PATH").split(os.pathsep)
52 for location in locations:
53 candidate = os.path.join(location, program)
54 if os.path.isfile(candidate) and os.access(candidate, os.X_OK):
55 candidates.append(candidate)
56 return candidates
57
58
59def programs_not_in_path(programs):
60 """Returns all the programs that are not found in the PATH."""
61 return [program for program in programs if not which(program)]
62
63
64def _open_for_write(filename):
65 """Opens filename for writing, creating the directories if needed."""
66 dirname = os.path.dirname(filename)
67 if not os.path.exists(dirname):
68 os.makedirs(dirname)
69
70 return io.open(filename, 'w')
71
72
73def _get_cache_filename(name, filename):
74 """Returns the cache location for filename and linter name."""
75 filename = os.path.abspath(filename)[1:]
76 home_folder = os.path.expanduser('~')
77 base_cache_dir = os.path.join(home_folder, '.git-lint', 'cache')
78
79 return os.path.join(base_cache_dir, name, filename)
80
81
82def get_output_from_cache(name, filename):
83 """Returns the output from the cache if still valid.
84
85 It checks that the cache file is defined and that its modification time is
86 after the modification time of the original file.
87
88 Args:
89 name: string: name of the linter.
90 filename: string: path of the filename for which we are retrieving the
91 output.
92
93 Returns: a string with the output, if it is still valid, or None otherwise.
94 """
95 cache_filename = _get_cache_filename(name, filename)
96 if (os.path.exists(cache_filename) and
97 os.path.getmtime(filename) < os.path.getmtime(cache_filename)):
98 with io.open(cache_filename) as f:
99 return f.read()
100
101 return None
102
103
104def save_output_in_cache(name, filename, output):
105 """Saves output in the cache location.
106
107 Args:
108 name: string: name of the linter.
109 filename: string: path of the filename for which we are saving the output.
110 output: string: full output (not yet filetered) of the lint command.
111 """
112 cache_filename = _get_cache_filename(name, filename)
113 with _open_for_write(cache_filename) as f:
114 f.write(output)