fix: add sync.make_selector() convenience function

wraps `fabsync.ItemSelector.new()`
This commit is contained in:
Lance Edgar 2024-09-10 20:10:15 -05:00
parent 2a83142d95
commit e3b593d628
2 changed files with 45 additions and 5 deletions

View file

@ -44,20 +44,41 @@ def make_root(path, dest='/'):
return fabsync.load(path, dest)
def isync(c, root, selector=None, echo=True, **kwargs):
def make_selector(subpath=None, **kwargs):
"""
Make and return an "item selector" for use with a sync call.
This is a convenience wrapper around
:meth:`fabsync:fabsync.ItemSelector.new()`.
:param subpath: (Optional) Relative subpath of the file tree to
sync, e.g. ``'etc/postfix'``.
:param tags: Optional iterable of tags to include; excluding any
files which are not so tagged. E.g. ``{'foo'}``
"""
return fabsync.ItemSelector.new(subpath, **kwargs)
def isync(c, root, selector=None, tags=None, echo=True, **kwargs):
"""
Sync files, yielding the result for each as it goes.
This is a convenience wrapper around
:func:`fabsync:fabsync.isync()`.
:param c: Connection object.
:param c: Fabric connection.
:param root: File tree "root" object as obtained from
:func:`make_root()`.
:param selector: This can be a simple "subpath" string, indicating
a section of the file tree. For instance: ``'etc/postfix'``
a section of the file tree (e.g. ``'etc/postfix'``). Or can be
a :class:`fabsync.ItemSelector` instance.
:param tags: Optional iterable of tags to select. If ``selector``
is a subpath string, and you specify ``tags`` then they will be
included when creating the actual selector.
:param echo: Flag indicating whether the path for each file synced
should be echoed to stdout. Generally thought to be useful but
@ -68,7 +89,10 @@ def isync(c, root, selector=None, echo=True, **kwargs):
"""
if selector:
if not isinstance(selector, fabsync.ItemSelector):
selector = fabsync.ItemSelector.new(selector)
kw = {}
if tags:
kw['tags'] = tags
selector = make_selector(selector, **kw)
kwargs['selector'] = selector
for result in fabsync.isync(c, root, **kwargs):

View file

@ -18,6 +18,14 @@ class TestMakeRoot(TestCase):
self.assertEqual(root.dest, Path('/'))
class TestMakeSelector(TestCase):
def test_basic(self):
selector = mod.make_selector('etc/postfix')
self.assertIsInstance(selector, ItemSelector)
self.assertEqual(selector.subpath, Path('etc/postfix'))
class TestIsync(TestCase):
def test_basic(self):
@ -40,7 +48,7 @@ class TestIsync(TestCase):
self.assertEqual(results, [result])
fabsync.isync.assert_called_once_with(c, root)
# sync with selector
# sync with selector (subpath)
fabsync.isync.reset_mock()
result = MagicMock(path='/foo', modified=True)
fabsync.isync.return_value = [result]
@ -48,6 +56,14 @@ class TestIsync(TestCase):
self.assertEqual(results, [result])
fabsync.isync.assert_called_once_with(c, root, selector=fabsync.ItemSelector.new('foo'))
# sync with selector (subpath + tags)
fabsync.isync.reset_mock()
result = MagicMock(path='/foo', modified=True)
fabsync.isync.return_value = [result]
results = list(mod.isync(c, root, 'foo', tags={'bar'}))
self.assertEqual(results, [result])
fabsync.isync.assert_called_once_with(c, root, selector=fabsync.ItemSelector.new('foo', tags={'bar'}))
class TestCheckIsync(TestCase):