diff --git a/gitlint/linters.py b/gitlint/linters.py index 7b1cae1..8feeb4d 100644 --- a/gitlint/linters.py +++ b/gitlint/linters.py @@ -55,7 +55,7 @@ def missing_requirements_command(missing_programs, installation_string, # TODO(skreft): add test case for result already in cache. -def lint_command(name, program, arguments, filter_regex, filename, lines): +def lint_command(program, arguments, filter_regex, filename, lines): """Executes a lint program and filter the output. Executes the lint tool 'program' with arguments 'arguments' over the file @@ -63,7 +63,6 @@ def lint_command(name, program, arguments, filter_regex, filename, lines): 'filter_regex'. Args: - name: string: the name of the linter. program: string: lint program. arguments: list[string]: extra arguments for the program. filter_regex: string: regular expression to filter lines. @@ -73,7 +72,8 @@ def lint_command(name, program, arguments, filter_regex, filename, lines): Returns: dict: a dict with the extracted info from the message. """ - output = utils.get_output_from_cache(name, filename) + linter_hash = utils.calculate_hash(program, arguments) + output = utils.get_output_from_cache(linter_hash, filename) if output is None: call_arguments = [program] + arguments + [filename] @@ -91,7 +91,7 @@ def lint_command(name, program, arguments, filter_regex, filename, lines): } } output = output.decode('utf-8') - utils.save_output_in_cache(name, filename, output) + utils.save_output_in_cache(linter_hash, filename, output) output_lines = output.split(os.linesep) @@ -137,7 +137,7 @@ def parse_yaml_config(yaml_config, repo_home): 'REPO_HOME': repo_home, } - for name, data in yaml_config.items(): + for _, data in yaml_config.items(): command = _replace_variables([data['command']], variables)[0] requirements = _replace_variables( data.get('requirements', []), variables) @@ -149,7 +149,7 @@ def parse_yaml_config(yaml_config, repo_home): linter_command = Partial(missing_requirements_command, not_found_programs, data['installation']) else: - linter_command = Partial(lint_command, name, command, arguments, + linter_command = Partial(lint_command, command, arguments, data['filter']) for extension in data['extensions']: config[extension].append(linter_command) diff --git a/gitlint/utils.py b/gitlint/utils.py index 71c74f7..3a5cff3 100644 --- a/gitlint/utils.py +++ b/gitlint/utils.py @@ -13,6 +13,7 @@ # limitations under the License. """Common function used across modules.""" +import hashlib import io import os import re @@ -72,29 +73,45 @@ def _open_for_write(filename): return io.open(filename, 'w') -def _get_cache_filename(name, filename): - """Returns the cache location for filename and linter name.""" +def _get_cache_filename(linter_hash, filename): + """Returns the cache location for filename and linter hash.""" filename = os.path.abspath(filename)[1:] home_folder = os.path.expanduser('~') base_cache_dir = os.path.join(home_folder, '.git-lint', 'cache') - return os.path.join(base_cache_dir, name, filename) + return os.path.join(base_cache_dir, linter_hash, filename) -def get_output_from_cache(name, filename): +def calculate_hash(program, arguments): + """Calculate sha256 hash as hex string over program and arguments. + + Args: + program: string: lint program. + arguments: list[string]: extra arguments for the program. + + Returns: string: a string with the calculated sha256 hex value. + """ + h = hashlib.sha256() + h.update(program) + for argument in arguments: + h.update(argument) + return h.hexdigest() + + +def get_output_from_cache(linter_hash, filename): """Returns the output from the cache if still valid. It checks that the cache file is defined and that its modification time is after the modification time of the original file. Args: - name: string: name of the linter. + linter_hash: string: hash representing linter binary and arguments. filename: string: path of the filename for which we are retrieving the output. Returns: a string with the output, if it is still valid, or None otherwise. """ - cache_filename = _get_cache_filename(name, filename) + cache_filename = _get_cache_filename(linter_hash, filename) if (os.path.exists(cache_filename) and os.path.getmtime(filename) < os.path.getmtime(cache_filename)): with io.open(cache_filename) as f: @@ -103,14 +120,14 @@ def get_output_from_cache(name, filename): return None -def save_output_in_cache(name, filename, output): +def save_output_in_cache(linter_hash, filename, output): """Saves output in the cache location. Args: - name: string: name of the linter. + linter_hash: string: hash representing linter binary and arguments. filename: string: path of the filename for which we are saving the output. output: string: full output (not yet filetered) of the lint command. """ - cache_filename = _get_cache_filename(name, filename) + cache_filename = _get_cache_filename(linter_hash, filename) with _open_for_write(cache_filename) as f: f.write(output)