Commit ad328975 authored by Dom Sekotill's avatar Dom Sekotill
Browse files

Fix & optimise .next_if_* rules

Fixed setting .next_if_* rules when multiple files are loaded: if
already set, do not change. This prevents loss of all exclude rules
after an inverted rule in a file and vice-versa.
parent 55e949e1
Loading
Loading
Loading
Loading
+9 −8
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@ class GitLoader(loaders.Loader):
		super(GitLoader, self).__init__(project_root, target_path)
		pattern = patterns.FileMatchPattern('.git')
		self.rules = rules.Rule(project_root, '', pattern, with_path=False)
		self.rules.set_next(rules.ExcludeRule(), None)
		self.__rules = [None, self.rules], [None]

		git_dir = environ['GIT_DIR']
@@ -114,26 +115,26 @@ class GitLoader(loaders.Loader):

		excl_rules = [rules.IncludeRule()]
		incl_rules = [rules.ExcludeRule()]
		last_excl = excl_rules[-1]
		last_incl = incl_rules[-1]
		for inverted, rule in reversed(rule_list):
			if inverted:
				rule.next_if_match = excl_rules[-1]
				rule.next_if_fail = incl_rules[-1]
				rule.set_next(last_excl, last_incl)
				incl_rules.append(rule)
				last_incl = rule
			else:
				rule.next_if_match = incl_rules[-1]
				rule.next_if_fail = excl_rules[-1]
				rule.set_next(last_incl, last_excl)
				excl_rules.append(rule)
				last_excl = rule


		all_excl_rules, all_incl_rules = self.__rules
		try:
			all_excl_rules[1].next_if_match = incl_rules[-1]
			all_excl_rules[1].next_if_fail = excl_rules[-1]
			all_excl_rules[1].set_next(last_incl, last_excl)
		except IndexError:
			pass
		try:
			all_incl_rules[1].next_if_match = excl_rules[-1]
			all_incl_rules[1].next_if_fail = incl_rules[-1]
			all_incl_rules[1].set_next(last_excl, last_incl)
		except IndexError:
			pass

+26 −9
Original line number Diff line number Diff line
@@ -3,6 +3,8 @@ from warnings import warn


TOP_NAMES = {'', '.'}
MATCH = True
NO_MATCH = False


def add_attr(attrs, obj, name):
@@ -27,12 +29,8 @@ class Rule(object):
		self.with_path = with_path
		self.directory_only = directory_only

		if invert:
			self.next_if_match = IncludeRule()
			self.next_if_fail = ExcludeRule()
		else:
			self.next_if_match = ExcludeRule()
			self.next_if_fail = IncludeRule()
		self.invert = invert
		self.next_if_match = self.next_if_fail = None

	def __repr__(self):
		attrs = [self.__class__.__name__]
@@ -41,16 +39,35 @@ class Rule(object):
		add_attr(attrs, self, 'directory_only')
		return ('<{0}>'.format(' '.join(attrs)))


	def set_next(self, on_match, on_fail):
		assert on_match is None or isinstance(on_match, Rule)
		assert on_fail is None or isinstance(on_fail, Rule)
		if on_match is not None and self.next_if_match is None:
			self.next_if_match = on_match
		if on_fail is not None and self.next_if_fail is None:
			self.next_if_fail = on_fail

	def get_next(self, match):
		if match and self.next_if_match is not None:
			return self.next_if_match
		elif match:
			return IncludeRule() if self.invert else ExcludeRule()
		elif self.next_if_fail is not None:
			return self.next_if_fail
		else:
			return ExcludeRule() if self.invert else IncludeRule()

	def check_path(self, testpath, testname=None):
		if testpath in TOP_NAMES:
			return IncludeRule()

		if not testpath.startswith(self.pattern_root):
			return self.next_if_fail
			return self.get_next(NO_MATCH)

		fullpath = path.join(self.project_root, testpath)
		if self.directory_only and not path.isdir(fullpath):
			return self.next_if_fail
			return self.get_next(NO_MATCH)

		# strip off pattern_root
		testpath = testpath[len(self.pattern_root):]
@@ -63,7 +80,7 @@ class Rule(object):
			check_path = testname

		match = self.pattern.match(check_path)
		return self.next_if_match if match else self.next_if_fail
		return self.get_next(match)


def run_rules(rules_head, testpath, testname=None):