Compare commits
No commits in common. "e3b593d62870bd3d4369dbed1ced1f4f7a39011e" and "a45a619cf3508d085d20b6402ab61dfe582762b7" have entirely different histories.
e3b593d628
...
a45a619cf3
|
@ -1,6 +0,0 @@
|
||||||
|
|
||||||
``wuttamess.postfix``
|
|
||||||
=====================
|
|
||||||
|
|
||||||
.. automodule:: wuttamess.postfix
|
|
||||||
:members:
|
|
|
@ -31,5 +31,4 @@ project.
|
||||||
|
|
||||||
api/wuttamess
|
api/wuttamess
|
||||||
api/wuttamess.apt
|
api/wuttamess.apt
|
||||||
api/wuttamess.postfix
|
|
||||||
api/wuttamess.sync
|
api/wuttamess.sync
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
# -*- coding: utf-8; -*-
|
|
||||||
################################################################################
|
|
||||||
#
|
|
||||||
# WuttaMess -- Fabric Automation Helpers
|
|
||||||
# Copyright © 2024 Lance Edgar
|
|
||||||
#
|
|
||||||
# This file is part of Wutta Framework.
|
|
||||||
#
|
|
||||||
# Wutta Framework 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, either version 3 of the License, or (at your option) any
|
|
||||||
# later version.
|
|
||||||
#
|
|
||||||
# Wutta Framework 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
|
|
||||||
# Wutta Framework. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
################################################################################
|
|
||||||
"""
|
|
||||||
Postfix mail service
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def set_config(c, setting, value):
|
|
||||||
"""
|
|
||||||
Configure the given setting with the given value.
|
|
||||||
"""
|
|
||||||
c.run(f"postconf -e '{setting}={value}'")
|
|
||||||
|
|
||||||
|
|
||||||
def set_myhostname(c, hostname):
|
|
||||||
"""
|
|
||||||
Configure the ``myhostname`` setting with the given string.
|
|
||||||
"""
|
|
||||||
set_config(c, 'myhostname', hostname)
|
|
||||||
|
|
||||||
|
|
||||||
def set_myorigin(c, origin):
|
|
||||||
"""
|
|
||||||
Configure the ``myorigin`` setting with the given string.
|
|
||||||
"""
|
|
||||||
set_config(c, 'myorigin', origin)
|
|
||||||
|
|
||||||
|
|
||||||
def set_mydestination(c, *destinations):
|
|
||||||
"""
|
|
||||||
Configure the ``mydestinations`` setting with the given strings.
|
|
||||||
"""
|
|
||||||
set_config(c, 'mydestination', ', '.join(destinations))
|
|
||||||
|
|
||||||
|
|
||||||
def set_mynetworks(c, *networks):
|
|
||||||
"""
|
|
||||||
Configure the ``mynetworks`` setting with the given strings.
|
|
||||||
"""
|
|
||||||
set_config(c, 'mynetworks', ' '.join(networks))
|
|
||||||
|
|
||||||
|
|
||||||
def set_relayhost(c, relayhost):
|
|
||||||
"""
|
|
||||||
Configure the ``relayhost`` setting with the given string
|
|
||||||
"""
|
|
||||||
set_config(c, 'relayhost', relayhost)
|
|
|
@ -44,41 +44,20 @@ def make_root(path, dest='/'):
|
||||||
return fabsync.load(path, dest)
|
return fabsync.load(path, dest)
|
||||||
|
|
||||||
|
|
||||||
def make_selector(subpath=None, **kwargs):
|
def isync(c, root, selector=None, echo=True, **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.
|
Sync files, yielding the result for each as it goes.
|
||||||
|
|
||||||
This is a convenience wrapper around
|
This is a convenience wrapper around
|
||||||
:func:`fabsync:fabsync.isync()`.
|
:func:`fabsync:fabsync.isync()`.
|
||||||
|
|
||||||
:param c: Fabric connection.
|
:param c: Connection object.
|
||||||
|
|
||||||
:param root: File tree "root" object as obtained from
|
:param root: File tree "root" object as obtained from
|
||||||
:func:`make_root()`.
|
:func:`make_root()`.
|
||||||
|
|
||||||
:param selector: This can be a simple "subpath" string, indicating
|
:param selector: This can be a simple "subpath" string, indicating
|
||||||
a section of the file tree (e.g. ``'etc/postfix'``). Or can be
|
a section of the file tree. For instance: ``'etc/postfix'``
|
||||||
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
|
:param echo: Flag indicating whether the path for each file synced
|
||||||
should be echoed to stdout. Generally thought to be useful but
|
should be echoed to stdout. Generally thought to be useful but
|
||||||
|
@ -89,10 +68,7 @@ def isync(c, root, selector=None, tags=None, echo=True, **kwargs):
|
||||||
"""
|
"""
|
||||||
if selector:
|
if selector:
|
||||||
if not isinstance(selector, fabsync.ItemSelector):
|
if not isinstance(selector, fabsync.ItemSelector):
|
||||||
kw = {}
|
selector = fabsync.ItemSelector.new(selector)
|
||||||
if tags:
|
|
||||||
kw['tags'] = tags
|
|
||||||
selector = make_selector(selector, **kw)
|
|
||||||
kwargs['selector'] = selector
|
kwargs['selector'] = selector
|
||||||
|
|
||||||
for result in fabsync.isync(c, root, **kwargs):
|
for result in fabsync.isync(c, root, **kwargs):
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
# -*- coding: utf-8; -*-
|
|
||||||
|
|
||||||
from unittest import TestCase
|
|
||||||
from unittest.mock import MagicMock
|
|
||||||
|
|
||||||
from wuttamess import postfix as mod
|
|
||||||
|
|
||||||
|
|
||||||
class TestSetConfig(TestCase):
|
|
||||||
|
|
||||||
def test_basic(self):
|
|
||||||
c = MagicMock()
|
|
||||||
mod.set_config(c, 'foo', 'bar')
|
|
||||||
c.run.assert_called_once_with("postconf -e 'foo=bar'")
|
|
||||||
|
|
||||||
|
|
||||||
class TestSetMyhostname(TestCase):
|
|
||||||
|
|
||||||
def test_basic(self):
|
|
||||||
c = MagicMock()
|
|
||||||
mod.set_myhostname(c, 'test.example.com')
|
|
||||||
c.run.assert_called_once_with("postconf -e 'myhostname=test.example.com'")
|
|
||||||
|
|
||||||
|
|
||||||
class TestSetMyorigin(TestCase):
|
|
||||||
|
|
||||||
def test_basic(self):
|
|
||||||
c = MagicMock()
|
|
||||||
mod.set_myorigin(c, 'example.com')
|
|
||||||
c.run.assert_called_once_with("postconf -e 'myorigin=example.com'")
|
|
||||||
|
|
||||||
|
|
||||||
class TestSetMydestination(TestCase):
|
|
||||||
|
|
||||||
def test_basic(self):
|
|
||||||
c = MagicMock()
|
|
||||||
mod.set_mydestination(c, 'example.com', 'test.example.com', 'localhost')
|
|
||||||
c.run.assert_called_once_with("postconf -e 'mydestination=example.com, test.example.com, localhost'")
|
|
||||||
|
|
||||||
|
|
||||||
class TestSetMynetworks(TestCase):
|
|
||||||
|
|
||||||
def test_basic(self):
|
|
||||||
c = MagicMock()
|
|
||||||
mod.set_mynetworks(c, '127.0.0.0/8', '[::1]/128')
|
|
||||||
c.run.assert_called_once_with("postconf -e 'mynetworks=127.0.0.0/8 [::1]/128'")
|
|
||||||
|
|
||||||
|
|
||||||
class TestSetRelayhost(TestCase):
|
|
||||||
|
|
||||||
def test_basic(self):
|
|
||||||
c = MagicMock()
|
|
||||||
mod.set_relayhost(c, 'mail.example.com')
|
|
||||||
c.run.assert_called_once_with("postconf -e 'relayhost=mail.example.com'")
|
|
|
@ -18,14 +18,6 @@ class TestMakeRoot(TestCase):
|
||||||
self.assertEqual(root.dest, Path('/'))
|
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):
|
class TestIsync(TestCase):
|
||||||
|
|
||||||
def test_basic(self):
|
def test_basic(self):
|
||||||
|
@ -48,7 +40,7 @@ class TestIsync(TestCase):
|
||||||
self.assertEqual(results, [result])
|
self.assertEqual(results, [result])
|
||||||
fabsync.isync.assert_called_once_with(c, root)
|
fabsync.isync.assert_called_once_with(c, root)
|
||||||
|
|
||||||
# sync with selector (subpath)
|
# sync with selector
|
||||||
fabsync.isync.reset_mock()
|
fabsync.isync.reset_mock()
|
||||||
result = MagicMock(path='/foo', modified=True)
|
result = MagicMock(path='/foo', modified=True)
|
||||||
fabsync.isync.return_value = [result]
|
fabsync.isync.return_value = [result]
|
||||||
|
@ -56,14 +48,6 @@ class TestIsync(TestCase):
|
||||||
self.assertEqual(results, [result])
|
self.assertEqual(results, [result])
|
||||||
fabsync.isync.assert_called_once_with(c, root, selector=fabsync.ItemSelector.new('foo'))
|
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):
|
class TestCheckIsync(TestCase):
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue