mirror of
https://github.com/certbot/certbot.git
synced 2026-04-23 15:17:48 -04:00
Now handles some conf files in whitespace-preserving mode
(but not all of them)
This commit is contained in:
parent
44edbecba0
commit
8147c671e4
3 changed files with 53 additions and 114 deletions
|
|
@ -18,8 +18,7 @@ class RawNginxParser(object):
|
|||
left_bracket = Literal("{").suppress()
|
||||
right_bracket = Literal("}").suppress()
|
||||
semicolon = Literal(";").suppress()
|
||||
space = White().suppress()
|
||||
keepSpace = Optional(White())
|
||||
space = Optional(White())
|
||||
key = Word(alphanums + "_/+-.")
|
||||
# Matches anything that is not a special character AND any chars in single
|
||||
# or double quotes
|
||||
|
|
@ -29,21 +28,23 @@ class RawNginxParser(object):
|
|||
modifier = Literal("=") | Literal("~*") | Literal("~") | Literal("^~")
|
||||
|
||||
# rules
|
||||
comment = Literal('#') + restOfLine()
|
||||
comment = space + Literal('#') + restOfLine()
|
||||
|
||||
assignment = keepSpace + key + Optional(space + value, default=None) + semicolon
|
||||
location_statement = Optional(space + modifier) + Optional(space + location)
|
||||
if_statement = Literal("if") + space + Regex(r"\(.+\)") + space
|
||||
map_statement = Literal("map") + space + Regex(r"\S+") + space + Regex(r"\$\S+") + space
|
||||
assignment = space + key + Optional(space + value, default=None) + semicolon
|
||||
location_statement = space + Optional(modifier) + Optional(space + location)
|
||||
if_statement = space + Literal("if") + space + Regex(r"\(.+\)") + space
|
||||
map_statement = space + Literal("map") + space + Regex(r"\S+") + space + Regex(r"\$\S+") + space
|
||||
block = Forward()
|
||||
|
||||
block << Group(
|
||||
# XXX could this "key" be Literal("location")?
|
||||
(Group(key + location_statement) ^ Group(if_statement) ^ Group(map_statement)) +
|
||||
left_bracket +
|
||||
Group(ZeroOrMore(Group(comment | assignment) | block)) +
|
||||
right_bracket)
|
||||
|
||||
script = OneOrMore(Group(comment | assignment) ^ block) + stringEnd
|
||||
script.parseWithTabs()
|
||||
|
||||
def __init__(self, source):
|
||||
self.source = source
|
||||
|
|
@ -56,51 +57,6 @@ class RawNginxParser(object):
|
|||
"""Returns the parsed tree as a list."""
|
||||
return self.parse().asList()
|
||||
|
||||
class OldRawNginxParser(object):
|
||||
# pylint: disable=expression-not-assigned
|
||||
"""A class that parses nginx configuration with pyparsing."""
|
||||
|
||||
# constants
|
||||
left_bracket = Literal("{").suppress()
|
||||
right_bracket = Literal("}").suppress()
|
||||
semicolon = Literal(";").suppress()
|
||||
space = White().suppress()
|
||||
key = Word(alphanums + "_/+-.")
|
||||
# Matches anything that is not a special character AND any chars in single
|
||||
# or double quotes
|
||||
value = Regex(r"((\".*\")?(\'.*\')?[^\{\};,]?)+")
|
||||
location = CharsNotIn("{};," + string.whitespace)
|
||||
# modifier for location uri [ = | ~ | ~* | ^~ ]
|
||||
modifier = Literal("=") | Literal("~*") | Literal("~") | Literal("^~")
|
||||
|
||||
# rules
|
||||
comment = Literal("#") + restOfLine()
|
||||
assignment = (key + Optional(space + value, default=None) + semicolon)
|
||||
location_statement = Optional(space + modifier) + Optional(space + location)
|
||||
if_statement = Literal("if") + space + Regex(r"\(.+\)") + space
|
||||
map_statement = Literal("map") + space + Regex(r"\S+") + space + Regex(r"\$\S+") + space
|
||||
block = Forward()
|
||||
|
||||
block << Group(
|
||||
(Group(key + location_statement) ^ Group(if_statement) ^ Group(map_statement)) +
|
||||
left_bracket +
|
||||
Group(ZeroOrMore(Group(comment | assignment) | block)) +
|
||||
right_bracket)
|
||||
|
||||
script = OneOrMore(Group(comment | assignment) ^ block) + stringEnd
|
||||
|
||||
def __init__(self, source):
|
||||
self.source = source
|
||||
|
||||
def parse(self):
|
||||
"""Returns the parsed tree."""
|
||||
return self.script.parseString(self.source)
|
||||
|
||||
def as_list(self):
|
||||
"""Returns the parsed tree as a list."""
|
||||
return self.parse().asList()
|
||||
|
||||
|
||||
class RawNginxDumper(object):
|
||||
# pylint: disable=too-few-public-methods
|
||||
"""A class that dumps nginx configuration from the provided tree."""
|
||||
|
|
@ -108,35 +64,41 @@ class RawNginxDumper(object):
|
|||
self.blocks = blocks
|
||||
self.indentation = indentation
|
||||
|
||||
def __iter__(self, blocks=None, spacer=' '):
|
||||
def __iter__(self, blocks=None):
|
||||
"""Iterates the dumped nginx content."""
|
||||
blocks = blocks or self.blocks
|
||||
print "iterating", blocks
|
||||
for b in blocks:
|
||||
b0 = b
|
||||
b = copy.deepcopy(b)
|
||||
indentation = ""
|
||||
if spacey(b[0]):
|
||||
indentation = b.pop(0)
|
||||
indentation = indentation.replace("\n", "", 1)
|
||||
key = b.pop(0)
|
||||
values = b.pop(0)
|
||||
|
||||
values = b
|
||||
if isinstance(key, list):
|
||||
yield indentation + spacer.join(key) + ' {'
|
||||
yield indentation + "".join(key) + '{'
|
||||
for parameter in values:
|
||||
dumped = self.__iter__([parameter])
|
||||
for line in dumped:
|
||||
yield line
|
||||
|
||||
yield '}'
|
||||
else:
|
||||
#yield b
|
||||
if isinstance(key, str) and key.strip() == '#':
|
||||
yield indentation + key + values
|
||||
else:
|
||||
gap = ""
|
||||
# Sometimes the parser has stuck some gap whitespace in here;
|
||||
# if so rotate it into gap
|
||||
if spacey(values):
|
||||
gap = values
|
||||
values = b.pop(0)
|
||||
if values is None:
|
||||
yield indentation + key + ';'
|
||||
yield indentation + key + gap + ';'
|
||||
else:
|
||||
yield indentation + key + spacer + values + ';'
|
||||
yield indentation + key + gap + values + ';'
|
||||
|
||||
def __str__(self):
|
||||
"""Return the parsed block as a string."""
|
||||
|
|
@ -146,42 +108,6 @@ class RawNginxDumper(object):
|
|||
|
||||
|
||||
|
||||
class OldRawNginxDumper(object):
|
||||
# pylint: disable=too-few-public-methods
|
||||
"""A class that dumps nginx configuration from the provided tree."""
|
||||
def __init__(self, blocks, indentation=4):
|
||||
self.blocks = blocks
|
||||
self.indentation = indentation
|
||||
|
||||
def __iter__(self, blocks=None, current_indent=0, spacer=' '):
|
||||
"""Iterates the dumped nginx content."""
|
||||
blocks = blocks or self.blocks
|
||||
for key, values in blocks:
|
||||
indentation = spacer * current_indent
|
||||
if isinstance(key, list):
|
||||
if current_indent:
|
||||
yield ''
|
||||
yield indentation + spacer.join(key) + ' {'
|
||||
|
||||
for parameter in values:
|
||||
dumped = self.__iter__([parameter], current_indent + self.indentation)
|
||||
for line in dumped:
|
||||
yield line
|
||||
|
||||
yield indentation + '}'
|
||||
else:
|
||||
if key == '#':
|
||||
yield spacer * current_indent + key + values
|
||||
else:
|
||||
if values is None:
|
||||
yield spacer * current_indent + key + ';'
|
||||
else:
|
||||
yield spacer * current_indent + key + spacer + values + ';'
|
||||
|
||||
def __str__(self):
|
||||
"""Return the parsed block as a string."""
|
||||
return '\n'.join(self) + '\n'
|
||||
|
||||
|
||||
# Shortcut functions to respect Python's serialization interface
|
||||
# (like pyyaml, picker or json)
|
||||
|
|
@ -194,10 +120,6 @@ def loads(source):
|
|||
:rtype: list
|
||||
|
||||
"""
|
||||
old = OldRawNginxParser(source).as_list()
|
||||
print "Old:"
|
||||
for entry in old:
|
||||
print len(entry), " ",
|
||||
new = UnspacedList(RawNginxParser(source).as_list())
|
||||
print "\nNew:"
|
||||
print new
|
||||
|
|
@ -207,14 +129,6 @@ def loads(source):
|
|||
for entry in new.spaced:
|
||||
print str(len(entry))+ " ",
|
||||
print "\ngo"
|
||||
if old != new:
|
||||
print "NON-MATCH"
|
||||
for a, b in zip(old, new):
|
||||
if a != b:
|
||||
print "Entry", a, "!=", b
|
||||
import sys
|
||||
else:
|
||||
print "Parallel"
|
||||
return new
|
||||
|
||||
|
||||
|
|
@ -229,7 +143,7 @@ def load(_file):
|
|||
return loads(_file.read())
|
||||
|
||||
|
||||
def dumps(blocks, indentation=4):
|
||||
def dumps(blocks):
|
||||
"""Dump to a string.
|
||||
|
||||
:param UnspacedList block: The parsed tree
|
||||
|
|
@ -237,10 +151,10 @@ def dumps(blocks, indentation=4):
|
|||
:rtype: str
|
||||
|
||||
"""
|
||||
return str(RawNginxDumper(blocks, indentation))
|
||||
return str(RawNginxDumper(blocks))
|
||||
|
||||
|
||||
def dump(blocks, _file, indentation=4):
|
||||
def dump(blocks, _file):
|
||||
"""Dump to a file.
|
||||
|
||||
:param UnspacedList block: The parsed tree
|
||||
|
|
@ -249,7 +163,7 @@ def dump(blocks, _file, indentation=4):
|
|||
:rtype: NoneType
|
||||
|
||||
"""
|
||||
return _file.write(dumps(blocks, indentation))
|
||||
return _file.write(dumps(blocks))
|
||||
|
||||
|
||||
spacey = lambda x: isinstance(x, str) and x.isspace()
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import logging
|
|||
import os
|
||||
import pyparsing
|
||||
import re
|
||||
import sys
|
||||
|
||||
from certbot import errors
|
||||
|
||||
|
|
@ -213,9 +214,26 @@ class NginxParser(object):
|
|||
if ext:
|
||||
filename = filename + os.path.extsep + ext
|
||||
try:
|
||||
logger.debug('Dumping to %s:\n%s', filename, nginxparser.dumps(tree))
|
||||
out = nginxparser.dumps(tree)
|
||||
logger.debug('Dumping to %s:\n%s', filename, out)
|
||||
with open(filename, 'w') as _file:
|
||||
nginxparser.dump(tree, _file)
|
||||
_file.write(out)
|
||||
|
||||
if "owncloud" in filename:
|
||||
print "Outputting", filename
|
||||
print out
|
||||
a = open("/tmp/nginx/sites-enabled/owncloud.conf").read()
|
||||
b = open(filename).read()
|
||||
for linea, lineb in zip(a.split('\n'), b.split('\n')):
|
||||
if linea != lineb:
|
||||
print "a", repr(linea)
|
||||
print "b", repr(lineb)
|
||||
if a != b:
|
||||
print "Mismatch!"
|
||||
if a != out:
|
||||
print "Double mismatch", len(a), len(out)
|
||||
else:
|
||||
print "Match!"
|
||||
except IOError:
|
||||
logger.error("Could not open file for writing: %s", filename)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import itertools
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
from certbot import errors
|
||||
from certbot.plugins import common
|
||||
|
|
@ -123,7 +124,13 @@ class NginxTlsSni01(common.TLSSNI01):
|
|||
True, self.challenge_conf)
|
||||
|
||||
with open(self.challenge_conf, "w") as new_conf:
|
||||
nginxparser.dump(config, new_conf)
|
||||
if "mime" in self.challenge_conf:
|
||||
print "Weird"
|
||||
out = nginxparser.dumps(config)
|
||||
print out
|
||||
#sys.exit(1)
|
||||
#nginxparser.dump(config, new_conf)
|
||||
new_conf.write(out)
|
||||
|
||||
def _make_server_block(self, achall, addrs):
|
||||
"""Creates a server block for a challenge.
|
||||
|
|
|
|||
Loading…
Reference in a new issue