Compare commits

..

No commits in common. "e3b593d62870bd3d4369dbed1ced1f4f7a39011e" and "a45a619cf3508d085d20b6402ab61dfe582762b7" have entirely different histories.

6 changed files with 5 additions and 173 deletions

View file

@ -1,6 +0,0 @@
``wuttamess.postfix``
=====================
.. automodule:: wuttamess.postfix
:members:

View file

@ -31,5 +31,4 @@ project.
api/wuttamess api/wuttamess
api/wuttamess.apt api/wuttamess.apt
api/wuttamess.postfix
api/wuttamess.sync api/wuttamess.sync

View file

@ -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)

View file

@ -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):

View file

@ -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'")

View file

@ -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):