From 4488f2ee63fa73a20a3499f145277dec8cb2f0c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C5=82omkowski?= Date: Thu, 20 Jul 2017 22:20:48 +0200 Subject: [PATCH] Add support for variable marks ${ and }. Fixes #4 --- README.md | 1 + nginxfmt.py | 31 ++++++++++++++++++++++++++++--- test_nginxfmt.py | 38 +++++++++++++++++++++++++++++++++++++- 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a092d1d..bd5c260 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ way, described below: * neighbouring empty lines are collapsed to at most two empty lines * curly braces placement follows Java convention * whitespaces are collapsed, except in comments an quotation marks +* whitespaces in variable designators are removed: `${ my_variable }` is collapsed to `${my_variable}` ## Installation diff --git a/nginxfmt.py b/nginxfmt.py index 1e7849e..0fbd797 100755 --- a/nginxfmt.py +++ b/nginxfmt.py @@ -1,7 +1,10 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -"""Script formats nginx configuration file.""" +"""This Python script formats nginx configuration files in consistent way. + +Originally published under https://github.com/1connect/nginx-config-formatter +""" import argparse import codecs @@ -10,9 +13,13 @@ import re __author__ = "Michał Słomkowski" __license__ = "Apache 2.0" +__version__ = "1.0.1" INDENTATION = ' ' * 4 +TEMPLATE_VARIABLE_OPENING_TAG = '___TEMPLATE_VARIABLE_OPENING_TAG___' +TEMPLATE_VARIABLE_CLOSING_TAG = '___TEMPLATE_VARIABLE_CLOSING_TAG___' + def strip_line(single_line): """Strips the line and replaces neighbouring whitespaces with single space (except when within quotation marks).""" @@ -31,19 +38,37 @@ def strip_line(single_line): return '"'.join(parts) +def apply_variable_template_tags(line: str) -> str: + """Replaces variable indicators ${ and } with tags, so subsequent formatting is easier.""" + return re.sub(r'\${\s*(\w+)\s*}', + TEMPLATE_VARIABLE_OPENING_TAG + r"\1" + TEMPLATE_VARIABLE_CLOSING_TAG, + line, + flags=re.UNICODE) + + +def strip_variable_template_tags(line: str) -> str: + """Replaces tags back with ${ and } respectively.""" + return re.sub(TEMPLATE_VARIABLE_OPENING_TAG + r'\s*(\w+)\s*' + TEMPLATE_VARIABLE_CLOSING_TAG, + r'${\1}', + line, + flags=re.UNICODE) + + def clean_lines(orig_lines): """Strips the lines and splits them if they contain curly brackets.""" cleaned_lines = [] for line in orig_lines: line = strip_line(line) + line = apply_variable_template_tags(line) if line == "": cleaned_lines.append("") continue else: if line.startswith("#"): - cleaned_lines.append(line) + cleaned_lines.append(strip_variable_template_tags(line)) else: - cleaned_lines.extend([l.strip() for l in re.split("([\\{\\}])", line) if l != ""]) + cleaned_lines.extend( + [strip_variable_template_tags(l).strip() for l in re.split(r"([{\\}])", line) if l != ""]) return cleaned_lines diff --git a/test_nginxfmt.py b/test_nginxfmt.py index 3c8da8e..4daa13e 100644 --- a/test_nginxfmt.py +++ b/test_nginxfmt.py @@ -14,9 +14,12 @@ __license__ = "Apache 2.0" class TestFormatter(unittest.TestCase): - def _check_formatting(self, original_text, formatted_text): + def _check_formatting(self, original_text: str, formatted_text: str): self.assertMultiLineEqual(formatted_text, format_config_contents(original_text)) + def _check_variable_tags_symmetry(self, text): + self.assertMultiLineEqual(text, strip_variable_template_tags(apply_variable_template_tags(text))) + def test_join_opening_parenthesis(self): self.assertEqual(["foo", "bar {", "johan {", "tee", "ka", "}"], join_opening_bracket(("foo", "bar {", "johan", "{", "tee", "ka", "}"))) @@ -75,6 +78,12 @@ class TestFormatter(unittest.TestCase): self.assertEqual('lorem ipsum " foo bar zip " or " dd aa " mi', strip_line(' lorem ipsum " foo bar zip " or \t " dd aa " mi')) + def test_variable_template_tags(self): + self.assertEqual("foo bar ___TEMPLATE_VARIABLE_OPENING_TAG___myvar___TEMPLATE_VARIABLE_CLOSING_TAG___", + apply_variable_template_tags("foo bar ${myvar}")) + self._check_variable_tags_symmetry("lorem ipsum ${dolor} $amet") + self._check_variable_tags_symmetry("lorem ipsum ${dolor} $amet\nother $var and ${var_name2}") + def test_umlaut_in_string(self): self._check_formatting( "# Statusseite für Monitoring freigeben \n" + @@ -125,6 +134,33 @@ class TestFormatter(unittest.TestCase): " }\n" + "}\n") + def test_template_variables_with_dollars(self): + self._check_formatting('server {\n' + + ' # commented ${line} should not be touched\n' + + 'listen 80 default_server;\n' + + 'server_name localhost;\n' + + 'location / {\n' + + 'proxy_set_header X-User-Auth "In ${cookie_access_token} ${ other}";\n' + + 'proxy_set_header X-User-Other "foo ${bar}";\n' + + '}\n' + + '}', + 'server {\n' + + ' # commented ${line} should not be touched\n' + + ' listen 80 default_server;\n' + + ' server_name localhost;\n' + + ' location / {\n' + + ' proxy_set_header X-User-Auth "In ${cookie_access_token} ${other}";\n' + + ' proxy_set_header X-User-Other "foo ${bar}";\n' + + ' }\n' + + '}\n') + + self._check_formatting(' some_tag { with_templates "my ${var} and other ${ variable_name } "; }\n' + + '# in my line\n', + 'some_tag {\n' + + ' with_templates "my ${var} and other ${variable_name} ";\n' + + '}\n' + + '# in my line\n') + def test_loading_utf8_file(self): tmp_file = tempfile.mkstemp('utf-8')[1] shutil.copy('test-files/umlaut-utf8.conf', tmp_file)