Bug 1063414 - Add infrastructure to follow what the current file being processed is in a Context. r=gps

This commit is contained in:
Mike Hommey 2014-10-02 09:14:07 +09:00
parent 2ff412e6fe
commit 8844c6aea2
2 changed files with 154 additions and 4 deletions

View File

@ -78,18 +78,63 @@ class Context(KeyedDefaultDict):
def __init__(self, allowed_variables={}, config=None):
self._allowed_variables = allowed_variables
self.main_path = None
self.all_paths = set()
self.current_path = None
# There aren't going to be enough paths for the performance of scanning
# a list to be a problem.
self._all_paths = []
self.config = config
self.executed_time = 0
KeyedDefaultDict.__init__(self, self._factory)
def push_source(self, path):
"""Adds the given path as source of the data from this context and make
it the current path for the context."""
assert os.path.isabs(path)
if not self.main_path:
self.main_path = path
else:
# Callers shouldn't push after main_path has been popped.
assert self.current_path
self.current_path = path
# The same file can be pushed twice, so don't remove any previous
# occurrence.
self._all_paths.append(path)
def pop_source(self):
"""Get back to the previous current path for the context."""
assert self.main_path
assert self.current_path
last = self._all_paths.pop()
# Keep the popped path in the list of all paths, but before the main
# path so that it's not popped again.
self._all_paths.insert(0, last)
if last == self.main_path:
self.current_path = None
else:
self.current_path = self._all_paths[-1]
return last
def add_source(self, path):
"""Adds the given path as source of the data from this context."""
assert os.path.isabs(path)
if not self.main_path:
self.main_path = path
self.all_paths.add(path)
self.main_path = self.current_path = path
# Insert at the beginning of the list so that it's always before the
# main path.
if path not in self._all_paths:
self._all_paths.insert(0, path)
@property
def all_paths(self):
"""Returns all paths ever added to the context."""
return set(self._all_paths)
@property
def source_stack(self):
"""Returns the current stack of pushed sources."""
if not self.current_path:
return []
return self._all_paths[self._all_paths.index(self.main_path):]
@memoized_property
def objdir(self):

View File

@ -2,6 +2,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import os
import unittest
from mozunit import main
@ -95,6 +96,110 @@ class TestContext(unittest.TestCase):
self.assertEqual(test['foo'], 42)
self.assertEqual(test['baz'], { 'c': 3, 'd': 4 })
def test_paths(self):
test = Context()
# Newly created context has no paths.
self.assertIsNone(test.main_path)
self.assertIsNone(test.current_path)
self.assertEqual(test.all_paths, set())
self.assertEqual(test.source_stack, [])
foo = os.path.abspath('foo')
test.add_source(foo)
# Adding the first source makes it the main and current path.
self.assertEqual(test.main_path, foo)
self.assertEqual(test.current_path, foo)
self.assertEqual(test.all_paths, set([foo]))
self.assertEqual(test.source_stack, [foo])
bar = os.path.abspath('bar')
test.add_source(bar)
# Adding the second source makes leaves main and current paths alone.
self.assertEqual(test.main_path, foo)
self.assertEqual(test.current_path, foo)
self.assertEqual(test.all_paths, set([bar, foo]))
self.assertEqual(test.source_stack, [foo])
qux = os.path.abspath('qux')
test.push_source(qux)
# Pushing a source makes it the current path
self.assertEqual(test.main_path, foo)
self.assertEqual(test.current_path, qux)
self.assertEqual(test.all_paths, set([bar, foo, qux]))
self.assertEqual(test.source_stack, [foo, qux])
hoge = os.path.abspath('hoge')
test.push_source(hoge)
self.assertEqual(test.main_path, foo)
self.assertEqual(test.current_path, hoge)
self.assertEqual(test.all_paths, set([bar, foo, hoge, qux]))
self.assertEqual(test.source_stack, [foo, qux, hoge])
fuga = os.path.abspath('fuga')
# Adding a source after pushing doesn't change the source stack
test.add_source(fuga)
self.assertEqual(test.main_path, foo)
self.assertEqual(test.current_path, hoge)
self.assertEqual(test.all_paths, set([bar, foo, fuga, hoge, qux]))
self.assertEqual(test.source_stack, [foo, qux, hoge])
# Adding a source twice doesn't change anything
test.add_source(qux)
self.assertEqual(test.main_path, foo)
self.assertEqual(test.current_path, hoge)
self.assertEqual(test.all_paths, set([bar, foo, fuga, hoge, qux]))
self.assertEqual(test.source_stack, [foo, qux, hoge])
last = test.pop_source()
# Popping a source returns the last pushed one, not the last added one.
self.assertEqual(last, hoge)
self.assertEqual(test.main_path, foo)
self.assertEqual(test.current_path, qux)
self.assertEqual(test.all_paths, set([bar, foo, fuga, hoge, qux]))
self.assertEqual(test.source_stack, [foo, qux])
last = test.pop_source()
self.assertEqual(last, qux)
self.assertEqual(test.main_path, foo)
self.assertEqual(test.current_path, foo)
self.assertEqual(test.all_paths, set([bar, foo, fuga, hoge, qux]))
self.assertEqual(test.source_stack, [foo])
# Popping the main path is allowed.
last = test.pop_source()
self.assertEqual(last, foo)
self.assertEqual(test.main_path, foo)
self.assertIsNone(test.current_path)
self.assertEqual(test.all_paths, set([bar, foo, fuga, hoge, qux]))
self.assertEqual(test.source_stack, [])
# Popping past the main path asserts.
with self.assertRaises(AssertionError):
test.pop_source()
# Pushing after the main path was popped asserts.
with self.assertRaises(AssertionError):
test.push_source(foo)
test = Context()
test.push_source(foo)
test.push_source(bar)
# Pushing the same file twice is allowed.
test.push_source(bar)
test.push_source(foo)
self.assertEqual(last, foo)
self.assertEqual(test.main_path, foo)
self.assertEqual(test.current_path, foo)
self.assertEqual(test.all_paths, set([bar, foo]))
self.assertEqual(test.source_stack, [foo, bar, bar, foo])
class TestSymbols(unittest.TestCase):
def _verify_doc(self, doc):