nginxparser.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import string
  2. from pyparsing import (
  3. Literal, White, Word, alphanums, CharsNotIn, Forward, Group, SkipTo,
  4. Optional, OneOrMore, ZeroOrMore, pythonStyleComment)
  5. class NginxParser(object):
  6. """
  7. A class that parses nginx configuration with pyparsing
  8. """
  9. # constants
  10. left_bracket = Literal("{").suppress()
  11. right_bracket = Literal("}").suppress()
  12. semicolon = Literal(";").suppress()
  13. space = White().suppress()
  14. key = Word(alphanums + "_/")
  15. value = CharsNotIn("{};")
  16. value2 = CharsNotIn(";")
  17. location = CharsNotIn("{};," + string.whitespace)
  18. ifword = Literal("if")
  19. setword = Literal("set")
  20. # modifier for location uri [ = | ~ | ~* | ^~ ]
  21. modifier = Literal("=") | Literal("~*") | Literal("~") | Literal("^~")
  22. # rules
  23. assignment = (key + Optional(space + value) + semicolon)
  24. setblock = (setword + OneOrMore(space + value2) + semicolon)
  25. block = Forward()
  26. ifblock = Forward()
  27. subblock = Forward()
  28. ifblock << (
  29. Group(ifword + Optional(space) + Optional(value) + SkipTo('{'))
  30. + left_bracket
  31. + Group(subblock)
  32. + right_bracket)
  33. subblock << ZeroOrMore(
  34. Group(assignment) | block | Group(ifblock) | setblock
  35. )
  36. block << Group(
  37. Group(key + Optional(space + modifier) + Optional(space + location))
  38. + left_bracket
  39. + Group(subblock)
  40. + right_bracket
  41. )
  42. script = OneOrMore(Group(assignment) | block).ignore(pythonStyleComment)
  43. def __init__(self, source):
  44. self.source = source
  45. def parse(self):
  46. """
  47. Returns the parsed tree.
  48. """
  49. return self.script.parseString(self.source)
  50. def as_list(self):
  51. """
  52. Returns the list of tree.
  53. """
  54. return self.parse().asList()
  55. class NginxDumper(object):
  56. """
  57. A class that dumps nginx configuration from the provided tree.
  58. """
  59. def __init__(self, blocks, indentation=4):
  60. self.blocks = blocks
  61. self.indentation = indentation
  62. def __iter__(self, blocks=None, current_indent=0, spacer=' '):
  63. """
  64. Iterates the dumped nginx content.
  65. """
  66. blocks = blocks or self.blocks
  67. for key, values in blocks:
  68. if current_indent:
  69. yield spacer
  70. indentation = spacer * current_indent
  71. if isinstance(key, list):
  72. yield indentation + spacer.join(key) + ' {'
  73. for parameter in values:
  74. if isinstance(parameter[0], list):
  75. dumped = self.__iter__(
  76. [parameter],
  77. current_indent + self.indentation)
  78. for line in dumped:
  79. yield line
  80. else:
  81. dumped = spacer.join(parameter) + ';'
  82. yield spacer * (
  83. current_indent + self.indentation) + dumped
  84. yield indentation + '}'
  85. else:
  86. yield spacer * current_indent + key + spacer + values + ';'
  87. def as_string(self):
  88. return '\n'.join(self)
  89. def to_file(self, out):
  90. for line in self:
  91. out.write(line+"\n")
  92. out.close()
  93. return out
  94. # Shortcut functions to respect Python's serialization interface
  95. # (like pyyaml, picker or json)
  96. def loads(source):
  97. return NginxParser(source).as_list()
  98. def load(_file):
  99. return loads(_file.read())
  100. def dumps(blocks, indentation=4):
  101. return NginxDumper(blocks, indentation).as_string()
  102. def dump(blocks, _file, indentation=4):
  103. return NginxDumper(blocks, indentation).to_file(_file)