Merge pull request #8 from Husafan/context
Fix test failure and restructure the BuildContext execution.
This commit is contained in:
commit
455444073b
170
anvil/context.py
170
anvil/context.py
|
@ -116,6 +116,8 @@ class BuildContext(object):
|
||||||
self.stop_on_error = stop_on_error
|
self.stop_on_error = stop_on_error
|
||||||
self.raise_on_error = raise_on_error
|
self.raise_on_error = raise_on_error
|
||||||
|
|
||||||
|
self.error_encountered = False
|
||||||
|
|
||||||
# Build the rule graph
|
# Build the rule graph
|
||||||
self.rule_graph = graph.RuleGraph(self.project)
|
self.rule_graph = graph.RuleGraph(self.project)
|
||||||
|
|
||||||
|
@ -154,9 +156,9 @@ class BuildContext(object):
|
||||||
d = self.execute_async(target_rule_names)
|
d = self.execute_async(target_rule_names)
|
||||||
self.wait(d)
|
self.wait(d)
|
||||||
result = [None]
|
result = [None]
|
||||||
def _callback():
|
def _callback(*args, **kwargs):
|
||||||
result[0] = True
|
result[0] = True
|
||||||
def _errback():
|
def _errback(*args, **kwargs):
|
||||||
result[0] = False
|
result[0] = False
|
||||||
d.add_callback_fn(_callback)
|
d.add_callback_fn(_callback)
|
||||||
d.add_errback_fn(_errback)
|
d.add_errback_fn(_errback)
|
||||||
|
@ -188,126 +190,88 @@ class BuildContext(object):
|
||||||
|
|
||||||
# Calculate the sequence of rules to execute
|
# Calculate the sequence of rules to execute
|
||||||
rule_sequence = self.rule_graph.calculate_rule_sequence(target_rule_names)
|
rule_sequence = self.rule_graph.calculate_rule_sequence(target_rule_names)
|
||||||
|
|
||||||
any_failed = [False]
|
|
||||||
main_deferred = Deferred()
|
|
||||||
remaining_rules = rule_sequence[:]
|
remaining_rules = rule_sequence[:]
|
||||||
in_flight_rules = []
|
|
||||||
pumping = [False]
|
|
||||||
|
|
||||||
def _issue_rule(rule):
|
def _issue_rule(rule, deferred=None):
|
||||||
"""Issues a single rule into the current execution context.
|
"""Issues a single rule into the current execution context.
|
||||||
Updates the in_flight_rules list and pumps when the rule completes.
|
Updates the in_flight_rules list and pumps when the rule completes.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
rule: Rule to issue.
|
rule: Rule to issue.
|
||||||
|
deferred: Deferred to wait on before executing the rule.
|
||||||
"""
|
"""
|
||||||
def _rule_callback(*args, **kwargs):
|
def _rule_callback(*args, **kwargs):
|
||||||
in_flight_rules.remove(rule)
|
remaining_rules.remove(rule)
|
||||||
_pump(previous_succeeded=True)
|
|
||||||
|
|
||||||
def _rule_errback(exception=None, *args, **kwargs):
|
def _rule_errback(exception=None, *args, **kwargs):
|
||||||
in_flight_rules.remove(rule)
|
remaining_rules.remove(rule)
|
||||||
|
if self.stop_on_error:
|
||||||
|
self.error_encountered = True
|
||||||
# TODO(benvanik): log result/exception/etc?
|
# TODO(benvanik): log result/exception/etc?
|
||||||
if exception: # pragma: no cover
|
if exception: # pragma: no cover
|
||||||
print exception
|
print exception
|
||||||
any_failed[0] = True
|
|
||||||
_pump(previous_succeeded=False)
|
|
||||||
|
|
||||||
in_flight_rules.append(rule)
|
# All RuleContexts should be created by the time this method is called.
|
||||||
rule_deferred = self._execute_rule(rule)
|
assert self.rule_contexts[rule.path]
|
||||||
|
rule_deferred = self.rule_contexts[rule.path].deferred
|
||||||
rule_deferred.add_callback_fn(_rule_callback)
|
rule_deferred.add_callback_fn(_rule_callback)
|
||||||
rule_deferred.add_errback_fn(_rule_errback)
|
rule_deferred.add_errback_fn(_rule_errback)
|
||||||
|
|
||||||
|
def _execute(*args, **kwargs):
|
||||||
|
self._execute_rule(rule)
|
||||||
|
def _on_failure(*args, **kwards):
|
||||||
|
self._execute_rule(rule)
|
||||||
|
|
||||||
|
if deferred:
|
||||||
|
deferred.add_callback_fn(_execute)
|
||||||
|
deferred.add_errback_fn(_on_failure)
|
||||||
|
else:
|
||||||
|
_execute()
|
||||||
|
|
||||||
return rule_deferred
|
return rule_deferred
|
||||||
|
|
||||||
def _pump(previous_succeeded=True):
|
def _chain_rule_execution(target_rules):
|
||||||
"""Attempts to run another rule and signals the main_deferred if done.
|
"""Given a list of target rules, build them and all dependencies.
|
||||||
|
|
||||||
|
This method builds the passed in target rules and all dependencies. It
|
||||||
|
first assembles a list of the dependencies to target rules orded as:
|
||||||
|
[dependencies -> target_rules]
|
||||||
|
It then traverses the list, issuing execute commands for all rules that
|
||||||
|
do not have dependencies within the list. For all rules that do have
|
||||||
|
dependencies within the list, a deferred is used to trigger the rule's
|
||||||
|
exeution once all dependencies have completed executing.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
previous_succeeded: Whether the previous rule succeeded.
|
target_rules: A list of rules to be executed.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A deferred that resolves once all target_rules have either executed
|
||||||
|
successfully or failed.
|
||||||
"""
|
"""
|
||||||
# If we're already done, gracefully exit
|
issued_rules = []
|
||||||
if main_deferred.is_done():
|
all_deferreds = []
|
||||||
return
|
for rule in target_rules:
|
||||||
|
# Create the RuleContexts here so that failures can cascade and the
|
||||||
|
# deferred is accessible by any rules that depend on this one.
|
||||||
|
rule_ctx = rule.create_context(self)
|
||||||
|
self.rule_contexts[rule.path] = rule_ctx
|
||||||
|
|
||||||
# If we failed and we are supposed to stop, gracefully stop by
|
# Make the execution of the current rule dependent on the execution
|
||||||
# killing all future rules
|
# of all rules it depends on.
|
||||||
# This is better than terminating immediately, as it allows legit tasks
|
dependent_deferreds = []
|
||||||
# to finish
|
for executable_rule in issued_rules:
|
||||||
if any_failed[0] and self.stop_on_error:
|
if self.rule_graph.has_dependency(rule.path, executable_rule.path):
|
||||||
remaining_rules[:] = []
|
executable_ctx = self.rule_contexts[executable_rule.path]
|
||||||
# TODO(benvanik): better error message
|
dependent_deferreds.append(executable_ctx.deferred)
|
||||||
main_deferred.errback()
|
if dependent_deferreds:
|
||||||
return
|
dependent_deferred = async.gather_deferreds(
|
||||||
|
dependent_deferreds, errback_if_any_fail=True)
|
||||||
if pumping[0]:
|
all_deferreds.append(_issue_rule(rule, dependent_deferred))
|
||||||
return
|
|
||||||
pumping[0] = True
|
|
||||||
|
|
||||||
# Scan through all remaining rules - if any are unblocked, issue them
|
|
||||||
to_issue = []
|
|
||||||
for i in range(0, len(remaining_rules)):
|
|
||||||
next_rule = remaining_rules[i]
|
|
||||||
|
|
||||||
# Ignore if any dependency on any rule before it in the list
|
|
||||||
skip_rule = False
|
|
||||||
if i:
|
|
||||||
for old_rule in remaining_rules[:i]:
|
|
||||||
if self.rule_graph.has_dependency(next_rule.path, old_rule.path):
|
|
||||||
# Blocked on previous rule
|
|
||||||
skip_rule = True
|
|
||||||
break
|
|
||||||
if skip_rule:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Ignore if any dependency on an in-flight rule
|
|
||||||
for in_flight_rule in in_flight_rules:
|
|
||||||
if self.rule_graph.has_dependency(next_rule.path,
|
|
||||||
in_flight_rule.path):
|
|
||||||
# Blocked on a previous rule, so pass and wait for the next pump
|
|
||||||
skip_rule = True
|
|
||||||
break
|
|
||||||
if skip_rule:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# If here then we found no conflicting rules, queue for running
|
|
||||||
to_issue.append(next_rule)
|
|
||||||
|
|
||||||
# Run all rules that we can
|
|
||||||
for rule in to_issue:
|
|
||||||
remaining_rules.remove(rule)
|
|
||||||
for rule in to_issue:
|
|
||||||
_issue_rule(rule)
|
|
||||||
|
|
||||||
if (not len(remaining_rules) and
|
|
||||||
not len(in_flight_rules) and
|
|
||||||
not main_deferred.is_done()):
|
|
||||||
assert not len(remaining_rules)
|
|
||||||
|
|
||||||
# Done!
|
|
||||||
# TODO(benvanik): better errbacks? some kind of BuildResults?
|
|
||||||
if not any_failed[0]:
|
|
||||||
# Only save the cache when we have succeeded
|
|
||||||
# This causes some stuff to be rebuilt in failure cases, but prevents
|
|
||||||
# a lot of weirdness when things are partially broken
|
|
||||||
self.cache.save()
|
|
||||||
|
|
||||||
main_deferred.callback()
|
|
||||||
else:
|
else:
|
||||||
main_deferred.errback()
|
all_deferreds.append(_issue_rule(rule))
|
||||||
|
return async.gather_deferreds(all_deferreds, errback_if_any_fail=True)
|
||||||
|
|
||||||
pumping[0] = False
|
return _chain_rule_execution(rule_sequence)
|
||||||
|
|
||||||
# Keep the queue pumping
|
|
||||||
if not len(in_flight_rules) and len(remaining_rules):
|
|
||||||
_pump()
|
|
||||||
|
|
||||||
# Kick off execution (once for each rule as a heuristic for filling the
|
|
||||||
# pipeline)
|
|
||||||
for rule in rule_sequence:
|
|
||||||
_pump()
|
|
||||||
|
|
||||||
return main_deferred
|
|
||||||
|
|
||||||
def wait(self, deferreds):
|
def wait(self, deferreds):
|
||||||
"""Blocks waiting on a list of deferreds until they all complete.
|
"""Blocks waiting on a list of deferreds until they all complete.
|
||||||
|
@ -330,10 +294,10 @@ class BuildContext(object):
|
||||||
Returns:
|
Returns:
|
||||||
A Deferred that will callback when the rule has completed executing.
|
A Deferred that will callback when the rule has completed executing.
|
||||||
"""
|
"""
|
||||||
assert not self.rule_contexts.has_key(rule.path)
|
assert self.rule_contexts.has_key(rule.path)
|
||||||
rule_ctx = rule.create_context(self)
|
rule_ctx = self.rule_contexts[rule.path]
|
||||||
self.rule_contexts[rule.path] = rule_ctx
|
if (rule_ctx.check_predecessor_failures() or
|
||||||
if rule_ctx.check_predecessor_failures():
|
self.stop_on_error and self.error_encountered):
|
||||||
return rule_ctx.cascade_failure()
|
return rule_ctx.cascade_failure()
|
||||||
else:
|
else:
|
||||||
rule_ctx.begin()
|
rule_ctx.begin()
|
||||||
|
@ -647,7 +611,7 @@ class RuleContext(object):
|
||||||
"""Checks all dependencies for failure.
|
"""Checks all dependencies for failure.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
True if any dependency has failed.
|
True if any dependency has failed or been interrupted.
|
||||||
"""
|
"""
|
||||||
for dep in self.rule.get_dependent_paths():
|
for dep in self.rule.get_dependent_paths():
|
||||||
if util.is_rule_path(dep):
|
if util.is_rule_path(dep):
|
||||||
|
@ -655,7 +619,7 @@ class RuleContext(object):
|
||||||
dep, requesting_module=self.rule.parent_module)
|
dep, requesting_module=self.rule.parent_module)
|
||||||
other_rule_ctx = self.build_context.rule_contexts.get(
|
other_rule_ctx = self.build_context.rule_contexts.get(
|
||||||
other_rule.path, None)
|
other_rule.path, None)
|
||||||
if other_rule_ctx.status == Status.FAILED:
|
if (other_rule_ctx.status == Status.FAILED):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
@ -153,19 +153,31 @@ class BuildContextTest(FixtureTestCase):
|
||||||
results = ctx.get_rule_results('m:b')
|
results = ctx.get_rule_results('m:b')
|
||||||
self.assertEqual(results[0], Status.FAILED)
|
self.assertEqual(results[0], Status.FAILED)
|
||||||
|
|
||||||
|
print '*******************************************************'
|
||||||
project = Project(modules=[Module('m', rules=[
|
project = Project(modules=[Module('m', rules=[
|
||||||
FailRule('a'),
|
FailRule('a'),
|
||||||
SucceedRule('b', deps=[':a'])])])
|
SucceedRule('b', deps=[':a']),
|
||||||
|
SucceedRule('c'),
|
||||||
|
SucceedRule('d', deps=[':c']),
|
||||||
|
SucceedRule('e', deps=[':c']),
|
||||||
|
SucceedRule('f', deps=[':d', ':e'])])])
|
||||||
with BuildContext(self.build_env, project, stop_on_error=True) as ctx:
|
with BuildContext(self.build_env, project, stop_on_error=True) as ctx:
|
||||||
d = ctx.execute_async(['m:b'])
|
d = ctx.execute_async(['m:b', 'm:f'])
|
||||||
ctx.wait(d)
|
ctx.wait(d)
|
||||||
self.assertErrback(d)
|
self.assertErrback(d)
|
||||||
results = ctx.get_rule_results('m:a')
|
results = ctx.get_rule_results('m:a')
|
||||||
self.assertEqual(results[0], Status.FAILED)
|
self.assertEqual(results[0], Status.FAILED)
|
||||||
results = ctx.get_rule_results('m:b')
|
results = ctx.get_rule_results('m:b')
|
||||||
self.assertEqual(results[0], Status.FAILED)
|
self.assertEqual(results[0], Status.FAILED)
|
||||||
|
# Because m:a failed and stop_on_error is true, even though m:c is a
|
||||||
|
# succed rule, m:d, m:e and m:f should all be FAILED as well.
|
||||||
|
results = ctx.get_rule_results('m:d')
|
||||||
|
self.assertEqual(results[0], Status.FAILED)
|
||||||
|
results = ctx.get_rule_results('m:e')
|
||||||
|
self.assertEqual(results[0], Status.FAILED)
|
||||||
|
results = ctx.get_rule_results('m:f')
|
||||||
|
self.assertEqual(results[0], Status.FAILED)
|
||||||
|
|
||||||
# TODO(benvanik): test stop_on_error
|
|
||||||
# TODO(benvanik): test raise_on_error
|
# TODO(benvanik): test raise_on_error
|
||||||
|
|
||||||
def testCaching(self):
|
def testCaching(self):
|
||||||
|
@ -338,26 +350,29 @@ class RuleContextTest(FixtureTestCase):
|
||||||
project = Project(module_resolver=FileModuleResolver(self.root_path))
|
project = Project(module_resolver=FileModuleResolver(self.root_path))
|
||||||
build_ctx = BuildContext(self.build_env, project)
|
build_ctx = BuildContext(self.build_env, project)
|
||||||
|
|
||||||
rule = project.resolve_rule(':file_input')
|
rule = ':file_input'
|
||||||
d = build_ctx._execute_rule(rule)
|
resolved = project.resolve_rule(rule)
|
||||||
self.assertTrue(d.is_done())
|
success = build_ctx.execute_sync([rule])
|
||||||
rule_outputs = build_ctx.get_rule_outputs(rule)
|
self.assertTrue(success)
|
||||||
|
rule_outputs = build_ctx.get_rule_outputs(resolved)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
set([os.path.basename(f) for f in rule_outputs]),
|
set([os.path.basename(f) for f in rule_outputs]),
|
||||||
set(['a.txt']))
|
set(['a.txt']))
|
||||||
|
|
||||||
rule = project.resolve_rule(':local_txt')
|
rule = ':local_txt'
|
||||||
d = build_ctx._execute_rule(rule)
|
resolved = project.resolve_rule(rule)
|
||||||
self.assertTrue(d.is_done())
|
success = build_ctx.execute_sync([rule])
|
||||||
rule_outputs = build_ctx.get_rule_outputs(rule)
|
self.assertTrue(success)
|
||||||
|
rule_outputs = build_ctx.get_rule_outputs(resolved)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
set([os.path.basename(f) for f in rule_outputs]),
|
set([os.path.basename(f) for f in rule_outputs]),
|
||||||
set(['a.txt', 'b.txt', 'c.txt']))
|
set(['a.txt', 'b.txt', 'c.txt']))
|
||||||
|
|
||||||
rule = project.resolve_rule(':recursive_txt')
|
rule = ':recursive_txt'
|
||||||
d = build_ctx._execute_rule(rule)
|
resolved = project.resolve_rule(rule)
|
||||||
self.assertTrue(d.is_done())
|
success = build_ctx.execute_sync([rule])
|
||||||
rule_outputs = build_ctx.get_rule_outputs(rule)
|
self.assertTrue(success)
|
||||||
|
rule_outputs = build_ctx.get_rule_outputs(resolved)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
set([os.path.basename(f) for f in rule_outputs]),
|
set([os.path.basename(f) for f in rule_outputs]),
|
||||||
set(['a.txt', 'b.txt', 'c.txt', 'd.txt', 'e.txt']))
|
set(['a.txt', 'b.txt', 'c.txt', 'd.txt', 'e.txt']))
|
||||||
|
@ -366,63 +381,67 @@ class RuleContextTest(FixtureTestCase):
|
||||||
project = Project(module_resolver=FileModuleResolver(self.root_path))
|
project = Project(module_resolver=FileModuleResolver(self.root_path))
|
||||||
build_ctx = BuildContext(self.build_env, project)
|
build_ctx = BuildContext(self.build_env, project)
|
||||||
|
|
||||||
rule = project.resolve_rule(':missing_txt')
|
rule = ':missing_txt'
|
||||||
with self.assertRaises(OSError):
|
with self.assertRaises(OSError):
|
||||||
build_ctx._execute_rule(rule)
|
build_ctx.execute_sync([rule])
|
||||||
|
|
||||||
rule = project.resolve_rule(':missing_glob_txt')
|
rule = ':missing_glob_txt'
|
||||||
d = build_ctx._execute_rule(rule)
|
resolved = project.resolve_rule(rule)
|
||||||
self.assertTrue(d.is_done())
|
success = build_ctx.execute_sync([rule])
|
||||||
rule_outputs = build_ctx.get_rule_outputs(rule)
|
self.assertTrue(success)
|
||||||
|
rule_outputs = build_ctx.get_rule_outputs(resolved)
|
||||||
self.assertEqual(len(rule_outputs), 0)
|
self.assertEqual(len(rule_outputs), 0)
|
||||||
|
|
||||||
rule = project.resolve_rule(':local_txt_filter')
|
rule = ':local_txt_filter'
|
||||||
d = build_ctx._execute_rule(rule)
|
resolved = project.resolve_rule(rule)
|
||||||
self.assertTrue(d.is_done())
|
success = build_ctx.execute_sync([rule])
|
||||||
rule_outputs = build_ctx.get_rule_outputs(rule)
|
self.assertTrue(success)
|
||||||
|
rule_outputs = build_ctx.get_rule_outputs(resolved)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
set([os.path.basename(f) for f in rule_outputs]),
|
set([os.path.basename(f) for f in rule_outputs]),
|
||||||
set(['a.txt', 'b.txt', 'c.txt']))
|
set(['a.txt', 'b.txt', 'c.txt']))
|
||||||
|
|
||||||
rule = project.resolve_rule(':recursive_txt_filter')
|
rule = ':recursive_txt_filter'
|
||||||
d = build_ctx._execute_rule(rule)
|
resolved = project.resolve_rule(rule)
|
||||||
self.assertTrue(d.is_done())
|
success = build_ctx.execute_sync([rule])
|
||||||
rule_outputs = build_ctx.get_rule_outputs(rule)
|
self.assertTrue(success)
|
||||||
|
rule_outputs = build_ctx.get_rule_outputs(resolved)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
set([os.path.basename(f) for f in rule_outputs]),
|
set([os.path.basename(f) for f in rule_outputs]),
|
||||||
set(['a.txt', 'b.txt', 'c.txt', 'd.txt', 'e.txt']))
|
set(['a.txt', 'b.txt', 'c.txt', 'd.txt', 'e.txt']))
|
||||||
|
|
||||||
rule = project.resolve_rule(':exclude_txt_filter')
|
rule = ':exclude_txt_filter'
|
||||||
d = build_ctx._execute_rule(rule)
|
resolved = project.resolve_rule(rule)
|
||||||
self.assertTrue(d.is_done())
|
success = build_ctx.execute_sync([rule])
|
||||||
rule_outputs = build_ctx.get_rule_outputs(rule)
|
self.assertTrue(success)
|
||||||
|
rule_outputs = build_ctx.get_rule_outputs(resolved)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
set([os.path.basename(f) for f in rule_outputs]),
|
set([os.path.basename(f) for f in rule_outputs]),
|
||||||
set(['dir_2', 'a.txt-a', 'b.txt-b', 'c.txt-c', 'g.not-txt', 'BUILD']))
|
set(['dir_2', 'a.txt-a', 'b.txt-b', 'c.txt-c', 'g.not-txt', 'BUILD']))
|
||||||
|
|
||||||
rule = project.resolve_rule(':include_exclude_filter')
|
rule = ':include_exclude_filter'
|
||||||
d = build_ctx._execute_rule(rule)
|
resolved = project.resolve_rule(rule)
|
||||||
self.assertTrue(d.is_done())
|
success = build_ctx.execute_sync([rule])
|
||||||
rule_outputs = build_ctx.get_rule_outputs(rule)
|
self.assertTrue(success)
|
||||||
|
rule_outputs = build_ctx.get_rule_outputs(resolved)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
set([os.path.basename(f) for f in rule_outputs]),
|
set([os.path.basename(f) for f in rule_outputs]),
|
||||||
set(['a.txt-a', 'b.txt-b']))
|
set(['a.txt-a', 'b.txt-b']))
|
||||||
|
|
||||||
rule = project.resolve_rule(':multi_exts')
|
rule = ':only_a'
|
||||||
build_ctx._execute_rule(rule)
|
resolved = project.resolve_rule(rule)
|
||||||
|
success = build_ctx.execute_sync([rule])
|
||||||
rule = project.resolve_rule(':only_a')
|
self.assertTrue(success)
|
||||||
d = build_ctx._execute_rule(rule)
|
rule_outputs = build_ctx.get_rule_outputs(resolved)
|
||||||
self.assertTrue(d.is_done())
|
|
||||||
rule_outputs = build_ctx.get_rule_outputs(rule)
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
set([os.path.basename(f) for f in rule_outputs]),
|
set([os.path.basename(f) for f in rule_outputs]),
|
||||||
set(['a.txt-a']))
|
set(['a.txt-a']))
|
||||||
|
|
||||||
rule = project.resolve_rule(':only_ab')
|
rule = ':only_ab'
|
||||||
d = build_ctx._execute_rule(rule)
|
resolved = project.resolve_rule(rule)
|
||||||
self.assertTrue(d.is_done())
|
success = build_ctx.execute_sync([rule])
|
||||||
rule_outputs = build_ctx.get_rule_outputs(rule)
|
self.assertTrue(success)
|
||||||
|
rule_outputs = build_ctx.get_rule_outputs(resolved)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
set([os.path.basename(f) for f in rule_outputs]),
|
set([os.path.basename(f) for f in rule_outputs]),
|
||||||
set(['a.txt-a', 'b.txt-b']))
|
set(['a.txt-a', 'b.txt-b']))
|
||||||
|
@ -431,36 +450,33 @@ class RuleContextTest(FixtureTestCase):
|
||||||
project = Project(module_resolver=FileModuleResolver(self.root_path))
|
project = Project(module_resolver=FileModuleResolver(self.root_path))
|
||||||
build_ctx = BuildContext(self.build_env, project)
|
build_ctx = BuildContext(self.build_env, project)
|
||||||
|
|
||||||
rule = project.resolve_rule(':file_input')
|
rule = ':file_input'
|
||||||
d = build_ctx._execute_rule(rule)
|
resolved = project.resolve_rule(rule)
|
||||||
self.assertTrue(d.is_done())
|
success = build_ctx.execute_sync([rule])
|
||||||
|
self.assertTrue(success)
|
||||||
rule_outputs = build_ctx.get_rule_outputs(rule)
|
rule_outputs = build_ctx.get_rule_outputs(rule)
|
||||||
self.assertNotEqual(len(rule_outputs), 0)
|
self.assertNotEqual(len(rule_outputs), 0)
|
||||||
|
|
||||||
rule = project.resolve_rule(':rule_input')
|
rule = ':rule_input'
|
||||||
d = build_ctx._execute_rule(rule)
|
resolved = project.resolve_rule(rule)
|
||||||
self.assertTrue(d.is_done())
|
success = build_ctx.execute_sync([rule])
|
||||||
|
self.assertTrue(success)
|
||||||
rule_outputs = build_ctx.get_rule_outputs(rule)
|
rule_outputs = build_ctx.get_rule_outputs(rule)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
set([os.path.basename(f) for f in rule_outputs]),
|
set([os.path.basename(f) for f in rule_outputs]),
|
||||||
set(['a.txt']))
|
set(['a.txt']))
|
||||||
|
|
||||||
rule = project.resolve_rule(':mixed_input')
|
rule = ':mixed_input'
|
||||||
d = build_ctx._execute_rule(rule)
|
resolved = project.resolve_rule(rule)
|
||||||
self.assertTrue(d.is_done())
|
success = build_ctx.execute_sync([rule])
|
||||||
|
self.assertTrue(success)
|
||||||
rule_outputs = build_ctx.get_rule_outputs(rule)
|
rule_outputs = build_ctx.get_rule_outputs(rule)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
set([os.path.basename(f) for f in rule_outputs]),
|
set([os.path.basename(f) for f in rule_outputs]),
|
||||||
set(['a.txt', 'b.txt']))
|
set(['a.txt', 'b.txt']))
|
||||||
|
|
||||||
rule = project.resolve_rule(':missing_input')
|
|
||||||
with self.assertRaises(KeyError):
|
with self.assertRaises(KeyError):
|
||||||
build_ctx._execute_rule(rule)
|
build_ctx.execute_sync([':missing_input'])
|
||||||
|
|
||||||
build_ctx = BuildContext(self.build_env, project)
|
|
||||||
rule = project.resolve_rule(':rule_input')
|
|
||||||
with self.assertRaises(RuntimeError):
|
|
||||||
build_ctx._execute_rule(rule)
|
|
||||||
|
|
||||||
def _compare_path(self, result, expected):
|
def _compare_path(self, result, expected):
|
||||||
result = os.path.relpath(result, self.root_path)
|
result = os.path.relpath(result, self.root_path)
|
||||||
|
|
Loading…
Reference in New Issue