[Apache v2] Implement parsed_files (#7562)

* Implement parsed_files

* Add parsed_files stub to ApacheParserNodes and fix assertions

* Update certbot-apache/certbot_apache/interfaces.py

Co-Authored-By: ohemorange <ebportnoy@gmail.com>

* Add more descriptive comments

* Update certbot-apache/certbot_apache/augeasparser.py

Co-Authored-By: ohemorange <ebportnoy@gmail.com>

* Update certbot-apache/certbot_apache/dualparser.py

Co-Authored-By: ohemorange <ebportnoy@gmail.com>

* Update certbot-apache/certbot_apache/interfaces.py

Co-Authored-By: ohemorange <ebportnoy@gmail.com>
This commit is contained in:
Joona Hoikkala
2019-12-10 13:20:00 -05:00
committed by ohemorange
co-authored by ohemorange
parent 6148e5c355
commit 5c588a6f8d
7 changed files with 86 additions and 2 deletions
@@ -159,6 +159,10 @@ class ApacheBlockNode(ApacheDirectiveNode):
"""Returns a list of unsaved filepaths"""
return [assertions.PASS]
def parsed_paths(self): # pragma: no cover
"""Returns a list of parsed configuration file paths"""
return [assertions.PASS]
interfaces.CommentNode.register(ApacheCommentNode)
interfaces.DirectiveNode.register(ApacheDirectiveNode)
@@ -1,4 +1,6 @@
"""Dual parser node assertions"""
import fnmatch
from certbot_apache import interfaces
@@ -102,3 +104,17 @@ def assertEqualSimple(first, second):
""" Simple assertion """
if not isPass(first) and not isPass(second):
assert first == second
def assertEqualPathsList(first, second): # pragma: no cover
"""
Checks that the two lists of file paths match. This assertion allows for wildcard
paths.
"""
if any([isPass(path) for path in first]):
return
if any([isPass(path) for path in second]):
return
for fpath in first:
assert any([fnmatch.fnmatch(fpath, spath) for spath in second])
for spath in second:
assert any([fnmatch.fnmatch(fpath, spath) for fpath in first])
@@ -383,6 +383,20 @@ class AugeasBlockNode(AugeasDirectiveNode):
"""Returns a list of unsaved filepaths"""
return self.parser.unsaved_files()
def parsed_paths(self):
"""
Returns a list of file paths that have currently been parsed into the parser
tree. The returned list may include paths with wildcard characters, for
example: ['/etc/apache2/conf.d/*.load']
This is typically called on the root node of the ParserNode tree.
:returns: list of file paths of files that have been parsed
"""
parsed_paths = self.parser.aug.match("/augeas/load/Httpd/incl")
return [self.parser.aug.get(path) for path in parsed_paths]
def _create_commentnode(self, path):
"""Helper function to create a CommentNode from Augeas path"""
+17 -2
View File
@@ -54,7 +54,7 @@ class DualNodeBase(object):
if pass_primary and pass_secondary:
# Both unimplemented
new_nodes.append(nodeclass(primary=primary_res[0],
secondary=secondary_res[0])) # pragma: no cover
secondary=secondary_res[0])) # pragma: no cover
elif pass_primary:
for c in secondary_res:
new_nodes.append(nodeclass(primary=primary_res[0],
@@ -272,7 +272,6 @@ class DualBlockNode(DualNodeBase):
return self._find_helper(DualCommentNode, "find_comments", comment)
def delete_child(self, child):
"""Deletes a child from the ParserNode implementations. The actual
ParserNode implementations are used here directly in order to be able
@@ -289,3 +288,19 @@ class DualBlockNode(DualNodeBase):
assertions.assertEqualSimple(primary_files, secondary_files)
return primary_files
def parsed_paths(self):
"""
Returns a list of file paths that have currently been parsed into the parser
tree. The returned list may include paths with wildcard characters, for
example: ['/etc/apache2/conf.d/*.load']
This is typically called on the root node of the ParserNode tree.
:returns: list of file paths of files that have been parsed
"""
primary_paths = self.primary.parsed_paths()
secondary_paths = self.secondary.parsed_paths()
assertions.assertEqualPathsList(primary_paths, secondary_paths)
return primary_paths
@@ -502,3 +502,15 @@ class BlockNode(DirectiveNode):
:returns: list of file paths of files that have been changed but not yet
saved to disk.
"""
@abc.abstractmethod
def parsed_paths(self):
"""
Returns a list of file paths that have currently been parsed into the parser
tree. The returned list may include paths with wildcard characters, for
example: ['/etc/apache2/conf.d/*.load']
This is typically called on the root node of the ParserNode tree.
:returns: list of file paths of files that have been parsed
"""
@@ -292,6 +292,10 @@ class AugeasParserNodeTest(util.ApacheTest): # pylint: disable=too-many-public-
"ThisRaisesErrorBecauseMissingParameters"
)
def test_parsed_paths(self):
paths = self.config.parser_root.parsed_paths()
self.assertEqual(len(paths), 6)
def test_find_ancestors(self):
vhsblocks = self.config.parser_root.find_blocks("VirtualHost")
macro_test = False
@@ -413,6 +413,25 @@ class DualParserNodeTest(unittest.TestCase): # pylint: disable=too-many-public-
self.assertFalse(self.directive == ne_directive)
self.assertFalse(self.comment == ne_comment)
def test_parsed_paths(self):
mock_p = mock.MagicMock(return_value=['/path/file.conf',
'/another/path',
'/path/other.conf'])
mock_s = mock.MagicMock(return_value=['/path/*.conf', '/another/path'])
self.block.primary.parsed_paths = mock_p
self.block.secondary.parsed_paths = mock_s
self.block.parsed_paths()
self.assertTrue(mock_p.called)
self.assertTrue(mock_s.called)
def test_parsed_paths_error(self):
mock_p = mock.MagicMock(return_value=['/path/file.conf'])
mock_s = mock.MagicMock(return_value=['/path/*.conf', '/another/path'])
self.block.primary.parsed_paths = mock_p
self.block.secondary.parsed_paths = mock_s
with self.assertRaises(AssertionError):
self.block.parsed_paths()
def test_find_ancestors(self):
primarymock = mock.MagicMock(return_value=[])
secondarymock = mock.MagicMock(return_value=[])