Compare commits
6 Commits
require_is
...
test-apach
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9749f64d8 | ||
|
|
c0633ec3ac | ||
|
|
c9edb49267 | ||
|
|
9cc15da90f | ||
|
|
69bb92d698 | ||
|
|
bafa9e2eb0 |
@@ -1,5 +1,9 @@
|
|||||||
""" apacheconfig implementation of the ParserNode interfaces """
|
""" apacheconfig implementation of the ParserNode interfaces """
|
||||||
|
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
|
from certbot import errors
|
||||||
|
|
||||||
from certbot_apache._internal import assertions
|
from certbot_apache._internal import assertions
|
||||||
from certbot_apache._internal import interfaces
|
from certbot_apache._internal import interfaces
|
||||||
from certbot_apache._internal import parsernode_util as util
|
from certbot_apache._internal import parsernode_util as util
|
||||||
@@ -78,12 +82,60 @@ class ApacheDirectiveNode(ApacheParserNode):
|
|||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def _parameters_from_string(text):
|
||||||
|
text = text.strip()
|
||||||
|
words = []
|
||||||
|
word = ""
|
||||||
|
quote = None
|
||||||
|
escape = False
|
||||||
|
for c in text:
|
||||||
|
if c.isspace() and not quote:
|
||||||
|
if word:
|
||||||
|
words.append(word)
|
||||||
|
word = ""
|
||||||
|
else:
|
||||||
|
word += c
|
||||||
|
if not escape:
|
||||||
|
if not quote and c in "\"\'":
|
||||||
|
quote = c
|
||||||
|
elif c == quote:
|
||||||
|
words.append(word[1:-1])
|
||||||
|
word = ""
|
||||||
|
quote = None
|
||||||
|
escape = c == "\\"
|
||||||
|
if word:
|
||||||
|
words.append(word)
|
||||||
|
return tuple(words)
|
||||||
|
|
||||||
|
|
||||||
class ApacheBlockNode(ApacheDirectiveNode):
|
class ApacheBlockNode(ApacheDirectiveNode):
|
||||||
""" apacheconfig implementation of BlockNode interface """
|
""" apacheconfig implementation of BlockNode interface """
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super(ApacheBlockNode, self).__init__(**kwargs)
|
super(ApacheBlockNode, self).__init__(**kwargs)
|
||||||
self.children = ()
|
self._raw_children = self._raw
|
||||||
|
children = []
|
||||||
|
for raw_node in self._raw_children:
|
||||||
|
metadata = self.metadata.copy()
|
||||||
|
metadata['ac_ast'] = raw_node
|
||||||
|
if raw_node.typestring == "comment":
|
||||||
|
node = ApacheCommentNode(comment=raw_node.name[2:],
|
||||||
|
metadata=metadata, ancestor=self,
|
||||||
|
filepath=self.filepath)
|
||||||
|
elif raw_node.typestring == "block":
|
||||||
|
parameters = _parameters_from_string(raw_node.arguments)
|
||||||
|
node = ApacheBlockNode(name=raw_node.tag, parameters=parameters,
|
||||||
|
metadata=metadata, ancestor=self,
|
||||||
|
filepath=self.filepath, enabled=self.enabled)
|
||||||
|
else:
|
||||||
|
parameters = ()
|
||||||
|
if raw_node.value:
|
||||||
|
parameters = _parameters_from_string(raw_node.value)
|
||||||
|
node = ApacheDirectiveNode(name=raw_node.name, parameters=parameters,
|
||||||
|
metadata=metadata, ancestor=self,
|
||||||
|
filepath=self.filepath, enabled=self.enabled)
|
||||||
|
children.append(node)
|
||||||
|
self.children = tuple(children)
|
||||||
|
|
||||||
def __eq__(self, other): # pragma: no cover
|
def __eq__(self, other): # pragma: no cover
|
||||||
if isinstance(other, self.__class__):
|
if isinstance(other, self.__class__):
|
||||||
@@ -97,36 +149,44 @@ class ApacheBlockNode(ApacheDirectiveNode):
|
|||||||
self.metadata == other.metadata)
|
self.metadata == other.metadata)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def add_child_block(self, name, parameters=None, position=None): # pylint: disable=unused-argument
|
def _add_child_thing(self, raw_string, partial_node, position):
|
||||||
|
position = len(self._raw_children) if not position else position
|
||||||
|
# Cap position to length to mimic AugeasNode behavior. TODO: document that this happens
|
||||||
|
position = min(len(self._raw_children), position)
|
||||||
|
raw_ast = self._raw_children.add(position, raw_string)
|
||||||
|
metadata = self.metadata.copy()
|
||||||
|
metadata['ac_ast'] = raw_ast
|
||||||
|
new_node = partial_node(ancestor=self, metadata=metadata, filepath=self.filepath)
|
||||||
|
|
||||||
|
# Update metadata
|
||||||
|
children = list(self.children)
|
||||||
|
children.insert(position, new_node)
|
||||||
|
self.children = tuple(children)
|
||||||
|
return new_node
|
||||||
|
|
||||||
|
def add_child_block(self, name, parameters=None, position=None):
|
||||||
"""Adds a new BlockNode to the sequence of children"""
|
"""Adds a new BlockNode to the sequence of children"""
|
||||||
new_block = ApacheBlockNode(name=assertions.PASS,
|
parameters_str = " " + " ".join(parameters) if parameters else ""
|
||||||
parameters=assertions.PASS,
|
if not parameters:
|
||||||
ancestor=self,
|
parameters = []
|
||||||
filepath=assertions.PASS,
|
partial_block = partial(ApacheBlockNode, name=name,
|
||||||
metadata=self.metadata)
|
parameters=tuple(parameters), enabled=self.enabled)
|
||||||
self.children += (new_block,)
|
return self._add_child_thing("\n<%s%s>\n</%s>" % (name, parameters_str, name),
|
||||||
return new_block
|
partial_block, position)
|
||||||
|
|
||||||
def add_child_directive(self, name, parameters=None, position=None): # pylint: disable=unused-argument
|
def add_child_directive(self, name, parameters=None, position=None):
|
||||||
"""Adds a new DirectiveNode to the sequence of children"""
|
"""Adds a new DirectiveNode to the sequence of children"""
|
||||||
new_dir = ApacheDirectiveNode(name=assertions.PASS,
|
parameters_str = " " + " ".join(parameters) if parameters else ""
|
||||||
parameters=assertions.PASS,
|
if not parameters: # TODO (mona): test
|
||||||
ancestor=self,
|
parameters = [] # pragma: no cover
|
||||||
filepath=assertions.PASS,
|
partial_block = partial(ApacheDirectiveNode, name=name,
|
||||||
metadata=self.metadata)
|
parameters=tuple(parameters), enabled=self.enabled)
|
||||||
self.children += (new_dir,)
|
return self._add_child_thing("\n%s%s" % (name, parameters_str), partial_block, position)
|
||||||
return new_dir
|
|
||||||
|
|
||||||
# pylint: disable=unused-argument
|
|
||||||
def add_child_comment(self, comment="", position=None): # pragma: no cover
|
|
||||||
|
|
||||||
|
def add_child_comment(self, comment="", position=None):
|
||||||
"""Adds a new CommentNode to the sequence of children"""
|
"""Adds a new CommentNode to the sequence of children"""
|
||||||
new_comment = ApacheCommentNode(comment=assertions.PASS,
|
partial_comment = partial(ApacheCommentNode, comment=comment)
|
||||||
ancestor=self,
|
return self._add_child_thing(comment, partial_comment, position)
|
||||||
filepath=assertions.PASS,
|
|
||||||
metadata=self.metadata)
|
|
||||||
self.children += (new_comment,)
|
|
||||||
return new_comment
|
|
||||||
|
|
||||||
def find_blocks(self, name, exclude=True): # pylint: disable=unused-argument
|
def find_blocks(self, name, exclude=True): # pylint: disable=unused-argument
|
||||||
"""Recursive search of BlockNodes from the sequence of children"""
|
"""Recursive search of BlockNodes from the sequence of children"""
|
||||||
@@ -151,9 +211,22 @@ class ApacheBlockNode(ApacheDirectiveNode):
|
|||||||
filepath=assertions.PASS,
|
filepath=assertions.PASS,
|
||||||
metadata=self.metadata)]
|
metadata=self.metadata)]
|
||||||
|
|
||||||
|
# TODO (mona): test
|
||||||
def delete_child(self, child): # pragma: no cover
|
def delete_child(self, child): # pragma: no cover
|
||||||
"""Deletes a ParserNode from the sequence of children"""
|
"""Deletes a ParserNode from the sequence of children"""
|
||||||
return
|
index = -1
|
||||||
|
i = None
|
||||||
|
for i, elem in enumerate(self.children):
|
||||||
|
if elem == child:
|
||||||
|
index = i
|
||||||
|
break
|
||||||
|
if index < 0:
|
||||||
|
raise errors.PluginError("Could not find child node to delete")
|
||||||
|
children_list = list(self.children)
|
||||||
|
thing = children_list.pop(i)
|
||||||
|
self.children = tuple(children_list)
|
||||||
|
self._raw_children.remove(i)
|
||||||
|
return thing
|
||||||
|
|
||||||
def unsaved_files(self): # pragma: no cover
|
def unsaved_files(self): # pragma: no cover
|
||||||
"""Returns a list of unsaved filepaths"""
|
"""Returns a list of unsaved filepaths"""
|
||||||
|
|||||||
@@ -12,6 +12,11 @@ import pkg_resources
|
|||||||
import six
|
import six
|
||||||
import zope.component
|
import zope.component
|
||||||
import zope.interface
|
import zope.interface
|
||||||
|
try:
|
||||||
|
import apacheconfig
|
||||||
|
HAS_APACHECONFIG = True
|
||||||
|
except ImportError: # pragma: no cover
|
||||||
|
HAS_APACHECONFIG = False
|
||||||
|
|
||||||
from acme import challenges
|
from acme import challenges
|
||||||
from acme.magic_typing import DefaultDict # pylint: disable=unused-import, no-name-in-module
|
from acme.magic_typing import DefaultDict # pylint: disable=unused-import, no-name-in-module
|
||||||
@@ -261,7 +266,7 @@ class ApacheConfigurator(common.Installer):
|
|||||||
pn_meta = {"augeasparser": self.parser,
|
pn_meta = {"augeasparser": self.parser,
|
||||||
"augeaspath": self.parser.get_root_augpath(),
|
"augeaspath": self.parser.get_root_augpath(),
|
||||||
"ac_ast": None}
|
"ac_ast": None}
|
||||||
if self.USE_PARSERNODE:
|
if self.USE_PARSERNODE and HAS_APACHECONFIG:
|
||||||
self.parser_root = self.get_parsernode_root(pn_meta)
|
self.parser_root = self.get_parsernode_root(pn_meta)
|
||||||
self.parsed_paths = self.parser_root.parsed_paths()
|
self.parsed_paths = self.parser_root.parsed_paths()
|
||||||
|
|
||||||
@@ -369,6 +374,11 @@ class ApacheConfigurator(common.Installer):
|
|||||||
apache_vars["modules"] = apache_util.parse_modules(self.option("ctl"))
|
apache_vars["modules"] = apache_util.parse_modules(self.option("ctl"))
|
||||||
metadata["apache_vars"] = apache_vars
|
metadata["apache_vars"] = apache_vars
|
||||||
|
|
||||||
|
with open(self.parser.loc["root"]) as f:
|
||||||
|
with apacheconfig.make_loader(writable=True,
|
||||||
|
**apacheconfig.flavors.NATIVE_APACHE) as loader:
|
||||||
|
metadata["ac_ast"] = loader.loads(f.read())
|
||||||
|
|
||||||
return dualparser.DualBlockNode(
|
return dualparser.DualBlockNode(
|
||||||
name=assertions.PASS,
|
name=assertions.PASS,
|
||||||
ancestor=None,
|
ancestor=None,
|
||||||
@@ -907,7 +917,7 @@ class ApacheConfigurator(common.Installer):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
v1_vhosts = self.get_virtual_hosts_v1()
|
v1_vhosts = self.get_virtual_hosts_v1()
|
||||||
if self.USE_PARSERNODE:
|
if self.USE_PARSERNODE and HAS_APACHECONFIG:
|
||||||
v2_vhosts = self.get_virtual_hosts_v2()
|
v2_vhosts = self.get_virtual_hosts_v2()
|
||||||
|
|
||||||
for v1_vh in v1_vhosts:
|
for v1_vh in v1_vhosts:
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ install_requires = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
dev_extras = [
|
dev_extras = [
|
||||||
'apacheconfig>=0.3.1',
|
'apacheconfig>=0.3.2',
|
||||||
]
|
]
|
||||||
|
|
||||||
class PyTest(TestCommand):
|
class PyTest(TestCommand):
|
||||||
|
|||||||
@@ -1,8 +1,15 @@
|
|||||||
"""Tests for AugeasParserNode classes"""
|
"""Tests for AugeasParserNode classes"""
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
|
import unittest
|
||||||
import util
|
import util
|
||||||
|
|
||||||
|
try:
|
||||||
|
import apacheconfig # pylint: disable=import-error,unused-import
|
||||||
|
HAS_APACHECONFIG = True
|
||||||
|
except ImportError: # pragma: no cover
|
||||||
|
HAS_APACHECONFIG = False
|
||||||
|
|
||||||
from acme.magic_typing import List # pylint: disable=unused-import, no-name-in-module
|
from acme.magic_typing import List # pylint: disable=unused-import, no-name-in-module
|
||||||
from certbot import errors
|
from certbot import errors
|
||||||
|
|
||||||
@@ -10,6 +17,7 @@ from certbot_apache._internal import assertions
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipIf(not HAS_APACHECONFIG, reason='Tests require apacheconfig dependency')
|
||||||
class AugeasParserNodeTest(util.ApacheTest): # pylint: disable=too-many-public-methods
|
class AugeasParserNodeTest(util.ApacheTest): # pylint: disable=too-many-public-methods
|
||||||
"""Test AugeasParserNode using available test configurations"""
|
"""Test AugeasParserNode using available test configurations"""
|
||||||
|
|
||||||
@@ -146,7 +154,7 @@ class AugeasParserNodeTest(util.ApacheTest): # pylint: disable=too-many-public-
|
|||||||
self.assertTrue(found)
|
self.assertTrue(found)
|
||||||
|
|
||||||
def test_add_child_comment(self):
|
def test_add_child_comment(self):
|
||||||
newc = self.config.parser_root.primary.add_child_comment("The content")
|
newc = self.config.parser_root.add_child_comment("The content")
|
||||||
comments = self.config.parser_root.find_comments("The content")
|
comments = self.config.parser_root.find_comments("The content")
|
||||||
self.assertEqual(len(comments), 1)
|
self.assertEqual(len(comments), 1)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ class DualParserNodeTest(unittest.TestCase): # pylint: disable=too-many-public-
|
|||||||
parser_mock = mock.MagicMock()
|
parser_mock = mock.MagicMock()
|
||||||
parser_mock.aug.match.return_value = []
|
parser_mock.aug.match.return_value = []
|
||||||
parser_mock.get_arg.return_value = []
|
parser_mock.get_arg.return_value = []
|
||||||
self.metadata = {"augeasparser": parser_mock, "augeaspath": "/invalid", "ac_ast": None}
|
ast_mock = mock.MagicMock()
|
||||||
|
self.metadata = {"augeasparser": parser_mock, "augeaspath": "/invalid", "ac_ast": ast_mock}
|
||||||
self.block = dualparser.DualBlockNode(name="block",
|
self.block = dualparser.DualBlockNode(name="block",
|
||||||
ancestor=None,
|
ancestor=None,
|
||||||
filepath="/tmp/something",
|
filepath="/tmp/something",
|
||||||
|
|||||||
@@ -5,7 +5,14 @@ import mock
|
|||||||
|
|
||||||
import util
|
import util
|
||||||
|
|
||||||
|
try:
|
||||||
|
import apacheconfig
|
||||||
|
HAS_APACHECONFIG = True
|
||||||
|
except ImportError: # pragma: no cover
|
||||||
|
HAS_APACHECONFIG = False
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipIf(not HAS_APACHECONFIG, reason='Tests require apacheconfig dependency')
|
||||||
class ConfiguratorParserNodeTest(util.ApacheTest): # pylint: disable=too-many-public-methods
|
class ConfiguratorParserNodeTest(util.ApacheTest): # pylint: disable=too-many-public-methods
|
||||||
"""Test AugeasParserNode using available test configurations"""
|
"""Test AugeasParserNode using available test configurations"""
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
# Some dev package versions specified here may be overridden by higher level constraints
|
# Some dev package versions specified here may be overridden by higher level constraints
|
||||||
# files during tests (eg. letsencrypt-auto-source/pieces/dependency-requirements.txt).
|
# files during tests (eg. letsencrypt-auto-source/pieces/dependency-requirements.txt).
|
||||||
alabaster==0.7.10
|
alabaster==0.7.10
|
||||||
apacheconfig==0.3.1
|
apacheconfig==0.3.2
|
||||||
apipkg==1.4
|
apipkg==1.4
|
||||||
appnope==0.1.0
|
appnope==0.1.0
|
||||||
asn1crypto==0.22.0
|
asn1crypto==0.22.0
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ pytz==2012rc0
|
|||||||
google-api-python-client==1.5.5
|
google-api-python-client==1.5.5
|
||||||
|
|
||||||
# Our setup.py constraints
|
# Our setup.py constraints
|
||||||
apacheconfig==0.3.1
|
apacheconfig==0.3.2
|
||||||
cloudflare==1.5.1
|
cloudflare==1.5.1
|
||||||
cryptography==1.2.3
|
cryptography==1.2.3
|
||||||
parsedatetime==1.3
|
parsedatetime==1.3
|
||||||
|
|||||||
2
tox.ini
2
tox.ini
@@ -119,12 +119,14 @@ setenv =
|
|||||||
basepython = python2.7
|
basepython = python2.7
|
||||||
commands =
|
commands =
|
||||||
{[base]install_packages}
|
{[base]install_packages}
|
||||||
|
{[base]pip_install} certbot-apache[dev]
|
||||||
python tox.cover.py
|
python tox.cover.py
|
||||||
|
|
||||||
[testenv:py37-cover]
|
[testenv:py37-cover]
|
||||||
basepython = python3.7
|
basepython = python3.7
|
||||||
commands =
|
commands =
|
||||||
{[base]install_packages}
|
{[base]install_packages}
|
||||||
|
{[base]pip_install} certbot-apache[dev]
|
||||||
python tox.cover.py
|
python tox.cover.py
|
||||||
|
|
||||||
[testenv:lint]
|
[testenv:lint]
|
||||||
|
|||||||
Reference in New Issue
Block a user