From 0e69212f2badee13975ebdfa1e1d91bee32e681d Mon Sep 17 00:00:00 2001 From: Farid Akhmedov Date: Sat, 12 Nov 2022 01:59:25 +0700 Subject: [PATCH 1/4] Add more options to format action Add "align" and "spacious" for pretty-printing. Add "write" for write in-place --- crossplane/__main__.py | 18 ++++++++++++++---- crossplane/builder.py | 14 ++++++++++++-- crossplane/formatter.py | 5 +++-- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/crossplane/__main__.py b/crossplane/__main__.py index 0ac64f6..0c408f5 100644 --- a/crossplane/__main__.py +++ b/crossplane/__main__.py @@ -152,9 +152,15 @@ def write_block(block): o.close() -def format(filename, out, indent=4, tabs=False): - output = format_file(filename, indent=indent, tabs=tabs) - o = sys.stdout if out is None else io.open(out, 'w', encoding='utf-8') +def format(filename, out, indent=4, tabs=False, align=False, spacious=False, write=False): + output = format_file(filename, indent=indent, tabs=tabs, align=align, spacious=spacious) + + o = sys.stdout + if write: + o = io.open(filename, 'w', encoding='utf-8') + elif out is not None: + o = io.open(out, 'w', encoding='utf-8') + try: o.write(output + u'\n') finally: @@ -226,7 +232,11 @@ def create_subparser(function, help): p = create_subparser(format, 'formats an nginx config file') p.add_argument('filename', help='the nginx config file') - p.add_argument('-o', '--out', type=str, help='write output to a file') + p.add_argument('--align', action='store_true', help='align directives within blocks') + p.add_argument('--spacious', action='store_true', help="add line breaks after blocks") + g = p.add_mutually_exclusive_group() + g.add_argument('-o', '--out', type=str, help='write output to a file') + g.add_argument('-w', '--write', action='store_true', help='write output to a source file') g = p.add_mutually_exclusive_group() g.add_argument('-i', '--indent', type=int, metavar='NUM', help='number of spaces to indent output', default=4) g.add_argument('-t', '--tabs', action='store_true', help='indent with tabs instead of spaces') diff --git a/crossplane/builder.py b/crossplane/builder.py index 049d224..fc35661 100644 --- a/crossplane/builder.py +++ b/crossplane/builder.py @@ -71,7 +71,7 @@ def _enquote(arg): return arg -def build(payload, indent=4, tabs=False, header=False): +def build(payload, indent=4, tabs=False, header=False, align=False, spacious=False): padding = '\t' if tabs else ' ' * indent head = '' @@ -83,11 +83,18 @@ def build(payload, indent=4, tabs=False, header=False): def _build_block(output, block, depth, last_line): margin = padding * depth + max_directive_length = max(len(stmt['directive']) for stmt in block) for stmt in block: directive = _enquote(stmt['directive']) line = stmt.get('line', 0) + directive_padding = ( + (max_directive_length + 1 - len(directive)) * ' ' + if align and stmt.get('block') is None + else ' ' + ) + if directive == '#' and line == last_line: output += ' #' + stmt['comment'] continue @@ -102,7 +109,7 @@ def _build_block(output, block, depth, last_line): if directive == 'if': built = 'if (' + ' '.join(args) + ')' elif args: - built = directive + ' ' + ' '.join(args) + built = directive + directive_padding + ' '.join(args) else: built = directive @@ -113,6 +120,9 @@ def _build_block(output, block, depth, last_line): built = _build_block(built, stmt['block'], depth+1, line) built += '\n' + margin + '}' + if spacious and stmt.get('block') is not None and line - 1 != last_line: + output += '\n' + output += ('\n' if output else '') + margin + built last_line = line diff --git a/crossplane/formatter.py b/crossplane/formatter.py index 80c3b21..8428861 100644 --- a/crossplane/formatter.py +++ b/crossplane/formatter.py @@ -4,7 +4,7 @@ from .parser import parse -def format(filename, indent=4, tabs=False): +def format(filename, indent=4, tabs=False, align=False, spacious=False): payload = parse( filename, comments=True, @@ -18,5 +18,6 @@ def format(filename, indent=4, tabs=False): raise NgxParserBaseException(e['error'], e['file'], e['line']) parsed = payload['config'][0]['parsed'] - output = build(parsed, indent=indent, tabs=tabs) + output = build(parsed, indent=indent, tabs=tabs, + align=align, spacious=spacious) return output From eb64c2a33cff6ccabf78f9b0c030ac776ee0da2b Mon Sep 17 00:00:00 2001 From: Farid Akhmedov Date: Sat, 12 Nov 2022 02:03:29 +0700 Subject: [PATCH 2/4] Fix error with formatting when there is no statements in block --- crossplane/builder.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crossplane/builder.py b/crossplane/builder.py index fc35661..f9a9196 100644 --- a/crossplane/builder.py +++ b/crossplane/builder.py @@ -83,7 +83,9 @@ def build(payload, indent=4, tabs=False, header=False, align=False, spacious=Fal def _build_block(output, block, depth, last_line): margin = padding * depth - max_directive_length = max(len(stmt['directive']) for stmt in block) + + if len(block) > 0: + max_directive_length = max(len(stmt['directive']) for stmt in block) for stmt in block: directive = _enquote(stmt['directive']) From 6446f15ad080f0decfc1f2024914cc75992d69cc Mon Sep 17 00:00:00 2001 From: Farid Akhmedov Date: Sat, 12 Nov 2022 02:26:17 +0700 Subject: [PATCH 3/4] Add tests for formatting options --- tests/configs/many-directives/nginx.conf | 10 ++++ .../configs/many-directives/with-blocks.conf | 11 ++++ tests/test_format.py | 60 +++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 tests/configs/many-directives/nginx.conf create mode 100644 tests/configs/many-directives/with-blocks.conf diff --git a/tests/configs/many-directives/nginx.conf b/tests/configs/many-directives/nginx.conf new file mode 100644 index 0000000..4170184 --- /dev/null +++ b/tests/configs/many-directives/nginx.conf @@ -0,0 +1,10 @@ +server { + listen 443 ssl; + ssl_certificate fullchain.pem; + ssl_certificate_key privite.pem; + server_name _; + index index.html; + root /public; + charset utf-8; + expires $expires; +} \ No newline at end of file diff --git a/tests/configs/many-directives/with-blocks.conf b/tests/configs/many-directives/with-blocks.conf new file mode 100644 index 0000000..a2dc934 --- /dev/null +++ b/tests/configs/many-directives/with-blocks.conf @@ -0,0 +1,11 @@ +server { + location ~ \d { + image_filter_buffer 5M; + image_filter_interlace on; + image_filter_jpeg_quality 75; + } location ~ \d { + image_filter_buffer 5M; + image_filter_interlace on; + image_filter_jpeg_quality 75; + } +} \ No newline at end of file diff --git a/tests/test_format.py b/tests/test_format.py index d116572..f84e0e9 100644 --- a/tests/test_format.py +++ b/tests/test_format.py @@ -66,6 +66,66 @@ def test_format_not_main_file(): ]) +def test_format_align_option(): + dirname = os.path.join(here, 'configs', 'many-directives') + config = os.path.join(dirname, 'nginx.conf') + output = crossplane.format(config, align=True) + assert output == '\n'.join([ + 'server {', + ' listen 443 ssl;', + ' ssl_certificate fullchain.pem;', + ' ssl_certificate_key privite.pem;', + ' server_name _;', + ' index index.html;', + ' root /public;', + ' charset utf-8;', + ' expires $expires;', + '}', + ]) + + +def test_format_just_spacious_option(): + dirname = os.path.join(here, 'configs', 'many-directives') + config = os.path.join(dirname, 'with-blocks.conf') + output = crossplane.format(config, spacious=True) + assert output == '\n'.join([ + 'server {', + ' location ~ \d {', + ' image_filter_buffer 5M;', + ' image_filter_interlace on;', + ' image_filter_jpeg_quality 75;', + ' }', + '', + ' location ~ \d {', + ' image_filter_buffer 5M;', + ' image_filter_interlace on;', + ' image_filter_jpeg_quality 75;', + ' }', + '}', + ]) + + +def test_format_spacious_option_with_align(): + dirname = os.path.join(here, 'configs', 'many-directives') + config = os.path.join(dirname, 'with-blocks.conf') + output = crossplane.format(config, align=True, spacious=True) + assert output == '\n'.join([ + 'server {', + ' location ~ \d {', + ' image_filter_buffer 5M;', + ' image_filter_interlace on;', + ' image_filter_jpeg_quality 75;', + ' }', + '', + ' location ~ \d {', + ' image_filter_buffer 5M;', + ' image_filter_interlace on;', + ' image_filter_jpeg_quality 75;', + ' }', + '}', + ]) + + def test_format_args_not_analyzed(): dirname = os.path.join(here, 'configs', 'bad-args') config = os.path.join(dirname, 'nginx.conf') From 7f28ebbef8ad8e9b806c57e1764f7f8e3c718156 Mon Sep 17 00:00:00 2001 From: Farid Akhmedov Date: Sat, 12 Nov 2022 02:28:56 +0700 Subject: [PATCH 4/4] Add documentation for "align" and "spacious" format options --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dd889b4..be2c1d6 100644 --- a/README.md +++ b/README.md @@ -431,16 +431,19 @@ formatting tool. If that is what you are looking for, then you may want to look writing your own using crossplane's Python API. ``` -usage: crossplane format [-h] [-o OUT] [-i NUM | -t] filename +usage: crossplane format [-h] [--align] [--spacious] [-o OUT | -w] [-i NUM | -t] filename formats an nginx config file positional arguments: filename the nginx config file -optional arguments: +options: -h, --help show this help message and exit + --align align directives within blocks + --spacious add line breaks after blocks -o OUT, --out OUT write output to a file + -w, --write write output to a source file -i NUM, --indent NUM number of spaces to indent output -t, --tabs indent with tabs instead of spaces ```