1# 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) 115