Merge branch 'master' of github.com:Microsoft/DevSkim-Sublime-Plugin

This commit is contained in:
Michael Scovetta 2017-05-15 17:08:18 -07:00
Родитель 16b3391b7b 1f66948180
Коммит 32512fb222
2 изменённых файлов: 119 добавлений и 9 удалений

Просмотреть файл

@ -12,6 +12,8 @@ import logging
import re import re
import time import time
import os import os
import shlex
import subprocess
import traceback import traceback
import webbrowser import webbrowser
@ -213,6 +215,7 @@ class DevSkimEventListener(sublime_plugin.EventListener):
# Open a regular URL in the user's web browser # Open a regular URL in the user's web browser
if re.match("^https?://", command, re.IGNORECASE): if re.match("^https?://", command, re.IGNORECASE):
webbrowser.open_new(command) webbrowser.open_new(command)
return
# Special commands, intercept and perform the fix # Special commands, intercept and perform the fix
if command.startswith('#fixit'): if command.startswith('#fixit'):
@ -341,6 +344,7 @@ class DevSkimEventListener(sublime_plugin.EventListener):
self.analyze_current_view(view, show_popup=False, single_line=True) self.analyze_current_view(view, show_popup=False, single_line=True)
except Exception as msg: except Exception as msg:
logger.warning("Error analyzing current view: %s", msg) logger.warning("Error analyzing current view: %s", msg)
traceback.print_exc()
def on_load_async(self, view): def on_load_async(self, view):
"""Handle asynchronous loading event.""" """Handle asynchronous loading event."""
@ -352,6 +356,7 @@ class DevSkimEventListener(sublime_plugin.EventListener):
self.analyze_current_view(view, show_popup=False) self.analyze_current_view(view, show_popup=False)
except Exception as msg: except Exception as msg:
logger.warning("Error analyzing current view: %s", msg) logger.warning("Error analyzing current view: %s", msg)
traceback.print_exc()
def on_post_save_async(self, view): def on_post_save_async(self, view):
"""Handle post-save events.""" """Handle post-save events."""
@ -365,6 +370,7 @@ class DevSkimEventListener(sublime_plugin.EventListener):
self.analyze_current_view(view) self.analyze_current_view(view)
except Exception as msg: except Exception as msg:
logger.warning("Error analyzing current view: %s", msg) logger.warning("Error analyzing current view: %s", msg)
traceback.print_exc()
def analyze_current_view(self, view, show_popup=True, single_line=False): def analyze_current_view(self, view, show_popup=True, single_line=False):
"""Kick off the analysis.""" """Kick off the analysis."""
@ -375,7 +381,19 @@ class DevSkimEventListener(sublime_plugin.EventListener):
return return
window = view.window() window = view.window()
if not single_line:
self.clear_regions(view)
# TRY
_v = window.extract_variables()
filename = _v.get('file', '').replace('\\', '/')
if filename:
if self.is_file_ignored(filename):
logger.info("File is ignored.")
return
# DONE
self.lazy_initialize() self.lazy_initialize()
logger.debug("analyze_current_view()") logger.debug("analyze_current_view()")
@ -638,8 +656,8 @@ class DevSkimEventListener(sublime_plugin.EventListener):
logger.warning("Error suppressing rules for %s: %s" % logger.warning("Error suppressing rules for %s: %s" %
(rule_id, msg)) (rule_id, msg))
# Only include active rules -- if 'active' is not specified, assume True # Only include non-disabled rules -- if 'disabled' is not specified, assume False
rules = list(filter(lambda x: x.get('active', True), rules)) rules = list(filter(lambda x: not x.get('disabled', False), rules))
# Filter by tags, if specified, convert all to lowercase # Filter by tags, if specified, convert all to lowercase
show_only_tags = set([k.lower().strip() show_only_tags = set([k.lower().strip()
@ -847,7 +865,15 @@ class DevSkimEventListener(sublime_plugin.EventListener):
if self.is_suppressed(rule, line_list): if self.is_suppressed(rule, line_list):
continue # Don't add the result to the list continue # Don't add the result to the list
result_list.append({ # If there are conditions, run them now
context = {
'filename': filename,
'file_contents': file_contents,
'rule': rule,
'pattern': pattern_dict
}
result_details = {
'rule': rule, 'rule': rule,
'match_content': match.group(), 'match_content': match.group(),
'match_region': sublime.Region(start + offset, end + offset), 'match_region': sublime.Region(start + offset, end + offset),
@ -855,13 +881,65 @@ class DevSkimEventListener(sublime_plugin.EventListener):
'match_end': end + offset, 'match_end': end + offset,
'pattern': orig_pattern_str, 'pattern': orig_pattern_str,
'scope_list': scope_list 'scope_list': scope_list
}) }
if self.meets_conditions(context, result_details):
result_list.append(result_details)
else: else:
logger.debug("Not running rule check [force={0}, rule_applies={1}, syntax={2}, ext={3},]".format( logger.debug("Not running rule check [force={0}, rule_applies={1}, syntax={2}, ext={3},]".format(
force_analyze, rule_applies_to, set(rule_applies_to) & set(syntax_types), extension)) force_analyze, rule_applies_to, set(rule_applies_to) & set(syntax_types), extension))
return result_list return result_list
def meets_conditions(self, context, result):
"""Checks to see if a finding meets specified conditions from the rule."""
logger.debug(context)
pattern = context.get('pattern')
if not pattern:
return True # No pattern means same thing as them all passing.
conditions = pattern.get('conditions')
if not conditions:
return True # No conditions means same as them all passing.
match_start = result.get('match_start')
line = self.view.substr(self.view.line(match_start))
if not line:
logger.error('No line was found in meets_conditions')
return True # No line means something is broken
def _line_match_all(line, targets):
logger.debug('_line_match_all({0}, {1})'.format(line, targets))
line = line.lower()
return all([t.lower() in line for t in targets])
def _line_match_any(line, targets):
line = line.lower()
return any([t.lower() in line for t in targets])
logger.debug('Found {0} conditions'.format(len(conditions)))
result = True
for condition in conditions:
name = condition.get('name')
value = condition.get('value')
invert = condition.get('invert', False)
if name == 'line-match-all':
r = _line_match_all(line, value)
result &= not r if invert else r
elif name == 'line-match-any':
r = _line_match_any(line, value)
result &= not r if invert else r
else:
logger.warning('Invalid condition name: {0}'.format(name))
return result
def severity_abbreviation(self, severity): def severity_abbreviation(self, severity):
"""Convert a severity name into an abbreviation.""" """Convert a severity name into an abbreviation."""
if severity is None: if severity is None:
@ -959,9 +1037,34 @@ class DevSkimEventListener(sublime_plugin.EventListener):
max_width=max_width, max_width=max_width,
max_height=max_height, max_height=max_height,
on_navigate=on_navigate, on_navigate=on_navigate,
on_hide=on_hide), repeat_duration_ms) on_hide=on_hide), repeat_duration_ms)
def is_file_ignored(self, filename):
"""Check to see if a file (by filename) is ignored from analysis."""
global user_settings
if not filename:
return False
if not user_settings.get('ignore_from_gitignore', True):
return False
for ignore_pattern in user_settings.get('ignore_files', []):
logger.warning("Checking {0}".format(ignore_pattern))
if re.match(ignore_pattern, filename, re.IGNORECASE):
return True
try:
cwd = os.path.dirname(filename)
filename = shlex.quote(filename)
output = subprocess.check_output("git check-ignore --no-index {0}; exit 0;".format(filename),
cwd=cwd, stderr=subprocess.STDOUT, shell=True)
return filename in output.decode('utf-8')
except Exception as msg:
logger.warning("Error checking if file is ignored: {0}".format(msg))
return False
class ReplaceTextCommand(sublime_plugin.TextCommand): class ReplaceTextCommand(sublime_plugin.TextCommand):
"""Simple function to route text changes to view.""" """Simple function to route text changes to view."""
@ -991,6 +1094,7 @@ class DevSkimAnalyzeCommand(sublime_plugin.TextCommand):
devskim_event_listener.analyze_current_view(self.view) devskim_event_listener.analyze_current_view(self.view)
except Exception as msg: except Exception as msg:
logger.warning("Error analyzing current view: %s" % msg) logger.warning("Error analyzing current view: %s" % msg)
traceback.print_exc()
class DevSkimReloadRulesCommand(sublime_plugin.TextCommand): class DevSkimReloadRulesCommand(sublime_plugin.TextCommand):
@ -1002,10 +1106,10 @@ class DevSkimReloadRulesCommand(sublime_plugin.TextCommand):
rules = [] rules = []
stylesheet_content = "" stylesheet_content = ""
def plugin_loaded(): def plugin_loaded():
"""Handle the plugin_loaded event from ST3.""" """Handle the plugin_loaded event from ST3."""
logger.info('DevSkim plugin_loaded(), Sublime Text v%s' % sublime.version()) logger.info('DevSkim plugin_loaded(), Sublime Text v%s' % sublime.version())
def plugin_unloaded(): def plugin_unloaded():

Просмотреть файл

@ -24,6 +24,13 @@
/* Sort results by either "severity" or "line_number" */ /* Sort results by either "severity" or "line_number" */
"sort_results_by": "line_number", "sort_results_by": "line_number",
/* Ignore files specified in .gitignore */
"ignore_from_gitignore": true,
/* Ignore additional files, each is a regular expression, escaped for JSON */
"ignore_files": [
],
/* Run analysis as soon as a file is opened. */ /* Run analysis as soon as a file is opened. */
"show_highlights_on_load": true, "show_highlights_on_load": true,
@ -52,5 +59,4 @@
/* Globally suppress these rules (list of rule IDs, like "DS123456") */ /* Globally suppress these rules (list of rule IDs, like "DS123456") */
"suppress_rules": [ "suppress_rules": [
] ]
} }