1# Copyright 2013 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import optparse 6import re 7 8from telemetry.internal.util import command_line 9 10 11class _StoryMatcher(object): 12 def __init__(self, pattern): 13 self._regex = None 14 self.has_compile_error = False 15 if pattern: 16 try: 17 self._regex = re.compile(pattern) 18 except re.error: 19 self.has_compile_error = True 20 21 def __nonzero__(self): 22 return self._regex is not None 23 24 def HasMatch(self, story): 25 return self and bool( 26 self._regex.search(story.display_name) or 27 (story.name and self._regex.search(story.name))) 28 29 30class _StoryLabelMatcher(object): 31 def __init__(self, labels_str): 32 self._labels = labels_str.split(',') if labels_str else None 33 34 def __nonzero__(self): 35 return self._labels is not None 36 37 def HasLabelIn(self, story): 38 return self and bool(story.labels.intersection(self._labels)) 39 40 41class StoryFilter(command_line.ArgumentHandlerMixIn): 42 """Filters stories in the story set based on command-line flags.""" 43 44 @classmethod 45 def AddCommandLineArgs(cls, parser): 46 group = optparse.OptionGroup(parser, 'User story filtering options') 47 group.add_option('--story-filter', 48 help='Use only stories whose names match the given filter regexp.') 49 group.add_option('--story-filter-exclude', 50 help='Exclude stories whose names match the given filter regexp.') 51 group.add_option('--story-label-filter', 52 help='Use only stories that have any of these labels') 53 group.add_option('--story-label-filter-exclude', 54 help='Exclude stories that have any of these labels') 55 parser.add_option_group(group) 56 57 @classmethod 58 def ProcessCommandLineArgs(cls, parser, args): 59 cls._include_regex = _StoryMatcher(args.story_filter) 60 cls._exclude_regex = _StoryMatcher(args.story_filter_exclude) 61 cls._include_labels = _StoryLabelMatcher(args.story_label_filter) 62 cls._exclude_labels = _StoryLabelMatcher(args.story_label_filter_exclude) 63 64 if cls._include_regex.has_compile_error: 65 raise parser.error('--story-filter: Invalid regex.') 66 if cls._exclude_regex.has_compile_error: 67 raise parser.error('--story-filter-exclude: Invalid regex.') 68 69 @classmethod 70 def IsSelected(cls, story): 71 # Exclude filters take priority. 72 if cls._exclude_labels.HasLabelIn(story): 73 return False 74 if cls._exclude_regex.HasMatch(story): 75 return False 76 77 if cls._include_labels and not cls._include_labels.HasLabelIn(story): 78 return False 79 if cls._include_regex and not cls._include_regex.HasMatch(story): 80 return False 81 return True 82