Skip to content

Commit

Permalink
add buildbot.util.pathmatch
Browse files Browse the repository at this point in the history
  • Loading branch information
djmitche committed May 8, 2012
1 parent af77e7b commit 67487d5
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 0 deletions.
60 changes: 60 additions & 0 deletions master/buildbot/test/unit/test_util_pathmatch.py
@@ -0,0 +1,60 @@
# This file is part of Buildbot. Buildbot is free software: you can
# redistribute it and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation, version 2.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright Buildbot Team Members

from twisted.trial import unittest
from buildbot.util import pathmatch

class Matcher(unittest.TestCase):

def setUp(self):
self.m = pathmatch.Matcher()

def test_dupe_path(self):
def set():
self.m[('abc,')] = 1
set()
self.assertRaises(AssertionError, set)

def test_empty(self):
self.assertRaises(KeyError, lambda : self.m[('abc',)])

def test_diff_length(self):
self.m[('abc', 'def')] = 2
self.m[('ab', 'cd', 'ef')] = 3
self.assertEqual(self.m[('abc', 'def')], (2, {}))

def test_same_length(self):
self.m[('abc', 'def')] = 2
self.m[('abc', 'efg')] = 3
self.assertEqual(self.m[('abc', 'efg')], (3, {}))

def test_pattern_variables(self):
self.m[('A', ':a', 'B', ':b')] = 'AB'
self.assertEqual(self.m[('A', 'a', 'B', 'b')],
('AB', dict(a='a', b='b')))

def test_prefix_matching(self):
self.m[('A', ':a')] = 'A'
self.m[('A', ':a', 'B', ':b')] = 'AB'
self.assertEqual(
(self.m[('A', 'a1', 'B', 'b')], self.m['A', 'a2']),
(('AB', dict(a='a1', b='b')), ('A', dict(a='a2'))))

def test_dirty_again(self):
self.m[('abc', 'def')] = 2
self.assertEqual(self.m[('abc', 'def')], (2, {}))
self.m[('abc', 'efg')] = 3
self.assertEqual(self.m[('abc', 'def')], (2, {}))
self.assertEqual(self.m[('abc', 'efg')], (3, {}))
50 changes: 50 additions & 0 deletions master/buildbot/util/pathmatch.py
@@ -0,0 +1,50 @@
# This file is part of Buildbot. Buildbot is free software: you can
# redistribute it and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation, version 2.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright Buildbot Team Members

class Matcher(object):

def __init__(self):
self._patterns = {}
self._dirty = True

def __setitem__(self, path, value):
assert path not in self._patterns, "duplicate path"
self._patterns[path] = value
self._dirty = True

def __getitem__(self, path):
if self._dirty:
self._compile()

patterns = self._by_length.get(len(path), {})
for pattern in patterns:
kwargs = {}
for ptrn, pth in zip(pattern, path):
if ptrn[0] == ':':
kwargs[ptrn[1:]] = pth
else:
if ptrn != pth:
break
else:
# complete match
return patterns[pattern], kwargs
else:
raise KeyError, 'No match for %r' % (path,)

def _compile(self):
self._by_length = {}
for k, v in self._patterns.iteritems():
l = len(k)
self._by_length.setdefault(l, {})[k] = v
22 changes: 22 additions & 0 deletions master/docs/developer/utils.rst
Expand Up @@ -511,6 +511,28 @@ This module contains a few utilities that are not included with SQLAlchemy.
versions that did not have a ``__version__`` attribute are represented by
``(0,0,0)``.

buildbot.util.pathmatcher
~~~~~~~~~~~~~~~~~~~~~~~~~

.. py:module:: buildbot.util.pathmatcher
.. py:class:: Matcher
This class implements the path-matching algorithm used by the data API.

Patterns are tuples of strings, with strings beginning with a colon (``:``) denoting variables.
A tuple of strings matches a pattern if the lengths are identical, and if every non-variable pattern element matches exactly.

A matcher object takes patterns using dictionary-assignment syntax::

matcher[('change', ':changeid')] = Change()

and performs matching using the dictionary-lookup syntax::

changeEndpoint, kwargs = matcher[('change', '13')]

where the result is a tuple of the original assigned object (the ``Change`` instance in this case) and the values of any variables in the path.

buildbot.util.subscription
~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down

0 comments on commit 67487d5

Please sign in to comment.