Compare commits
	
		
			2 commits
		
	
	
		
			a45a619cf3
			...
			e3b593d628
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
							 | 
						e3b593d628 | ||
| 
							 | 
						2a83142d95 | 
					 6 changed files with 173 additions and 5 deletions
				
			
		
							
								
								
									
										6
									
								
								docs/api/wuttamess.postfix.rst
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								docs/api/wuttamess.postfix.rst
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
 | 
			
		||||
``wuttamess.postfix``
 | 
			
		||||
=====================
 | 
			
		||||
 | 
			
		||||
.. automodule:: wuttamess.postfix
 | 
			
		||||
   :members:
 | 
			
		||||
| 
						 | 
				
			
			@ -31,4 +31,5 @@ project.
 | 
			
		|||
 | 
			
		||||
   api/wuttamess
 | 
			
		||||
   api/wuttamess.apt
 | 
			
		||||
   api/wuttamess.postfix
 | 
			
		||||
   api/wuttamess.sync
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										67
									
								
								src/wuttamess/postfix.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								src/wuttamess/postfix.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,67 @@
 | 
			
		|||
# -*- 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,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):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										54
									
								
								tests/test_postfix.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								tests/test_postfix.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,54 @@
 | 
			
		|||
# -*- 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,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):
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue