Skip to content

Commit e05a46e

Browse files
committed
Implement OS-dependent line endings. #31
1 parent 485617f commit e05a46e

File tree

4 files changed

+52
-20
lines changed

4 files changed

+52
-20
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,5 @@ dmypy.json
139139

140140
examples/
141141
deploy*.sh
142+
143+
poetry.lock

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# *nginx* config file formatter/beautifier
22

3-
*nginx* config file formatter/beautifier written in Python with no additional dependencies. It can be used as library or standalone script. It formats *nginx* configuration files in consistent way, described below:
3+
*nginx* config file formatter/beautifier written in Python with no additional dependencies.
4+
It can be used as library or standalone script.
5+
It formats *nginx* configuration files in consistent way, described below:
46

57
* All lines are indented in uniform manner, with 4 spaces per level. Number of spaces is customizable.
68
* Neighbouring empty lines are collapsed to at most two empty lines.
@@ -19,8 +21,7 @@ pip3 install nginxfmt
1921

2022
### Manual installation
2123

22-
The simplest form of installation would be copying `nginxfmt.py` to
23-
your scripts' directory. It has no 3-rd party dependencies.
24+
The simplest form of installation would be copying `nginxfmt.py` to your scripts' directory. It has no third party dependencies.
2425

2526
You can also clone the repository and symlink the executable:
2627

@@ -97,7 +98,7 @@ Please create issue under https://github.com/slomkowski/nginx-config-formatter/i
9798
reproduce the issue, preferably:
9899

99100
* snippet do be formatted
100-
* actual result with invalid formatting
101+
* actual result with the invalid formatting
101102
* desired result
102103

103104

nginxfmt.py

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,23 @@
88
"""
99

1010
import argparse
11-
import codecs
1211
import contextlib
1312
import io
1413
import logging
14+
import os
1515
import pathlib
1616
import re
1717
import sys
1818

1919
__author__ = "Michał Słomkowski"
2020
__license__ = "Apache 2.0"
21-
__version__ = "1.2.3"
21+
__version__ = "1.3.0"
2222

2323

2424
class FormatterOptions:
2525
"""Class holds the formatting options. For now, only indentation supported."""
2626
indentation = 4
27+
line_endings = os.linesep
2728

2829

2930
class Formatter:
@@ -43,19 +44,24 @@ def __init__(self,
4344
def format_string(self,
4445
contents: str) -> str:
4546
"""Accepts the string containing nginx configuration and returns formatted one. Adds newline at the end."""
47+
ls = self.options.line_endings
4648
lines = contents.splitlines()
4749
lines = self._apply_bracket_template_tags(lines)
4850
lines = self._clean_lines(lines)
4951
lines = self._join_opening_bracket(lines)
5052
lines = self._perform_indentation(lines)
5153

52-
text = '\n'.join(lines)
54+
text = ls.join(lines)
5355
text = self._strip_bracket_template_tags(text)
5456

55-
for pattern, substitute in ((r'\n{3,}', '\n\n\n'), (r'^\n', ''), (r'\n$', '')):
56-
text = re.sub(pattern, substitute, text, re.MULTILINE)
57+
for pattern, substitute in (
58+
(r'%s{3,}' % ls, '%s%s%s' % (ls, ls, ls)),
59+
(r'^%s' % ls, ''),
60+
(r'%s$' % ls, '')
61+
):
62+
text = re.sub(pattern, substitute, text)
5763

58-
return text + '\n'
64+
return text + ls
5965

6066
def get_formatted_string_from_file(self,
6167
file_path: pathlib.Path) -> str:
@@ -74,13 +80,13 @@ def format_file(self,
7480

7581
chosen_encoding, original_file_content = self._load_file_content(file_path)
7682

77-
with codecs.open(file_path, 'w', encoding=chosen_encoding) as wfp:
83+
with file_path.open('w', encoding=chosen_encoding) as wfp:
7884
wfp.write(self.format_string(original_file_content))
7985

8086
self.logger.info("Formatted content written to original file.")
8187

8288
if original_backup_file_path:
83-
with codecs.open(original_backup_file_path, 'w', encoding=chosen_encoding) as wfp:
89+
with original_backup_file_path.open('w', encoding=chosen_encoding) as wfp:
8490
wfp.write(original_file_content)
8591
self.logger.info("Original content saved to '%s'.", original_backup_file_path)
8692

@@ -96,7 +102,7 @@ def _load_file_content(self,
96102

97103
for enc in encodings:
98104
try:
99-
with codecs.open(file_path, 'r', encoding=enc) as rfp:
105+
with file_path.open('r', encoding=enc) as rfp:
100106
original_file_content = rfp.read()
101107
chosen_encoding = enc
102108
break
@@ -165,8 +171,7 @@ def _count_multi_semicolon(single_line):
165171
c += 1
166172
return q, c
167173

168-
@staticmethod
169-
def _multi_semicolon(single_line):
174+
def _multi_semicolon(self, single_line):
170175
"""Break multi semicolon into multiline (except when within quotation marks)."""
171176
single_line = single_line.strip()
172177
if single_line.startswith('#'):
@@ -186,7 +191,7 @@ def _multi_semicolon(single_line):
186191
quote_char = char
187192
result.append(char)
188193
elif not within_quotes and char == ';':
189-
result.append(";\n")
194+
result.append(";%s" % self.options.line_endings)
190195
else:
191196
result.append(char)
192197
return ''.join(result)
@@ -349,8 +354,21 @@ def _standalone_run(program_arguments):
349354
help="configuration files to format")
350355

351356
formatter_options_group = arg_parser.add_argument_group("formatting options")
352-
formatter_options_group.add_argument("-i", "--indent", action="store", default=4, type=int,
357+
formatter_options_group.add_argument("-i",
358+
"--indent",
359+
action="store",
360+
default=4,
361+
type=int,
353362
help="specify number of spaces for indentation")
363+
formatter_options_group.add_argument(
364+
"--line-endings",
365+
choices=["auto", "unix", "windows", "crlf", "lf"],
366+
default="auto",
367+
help=(
368+
"specify line ending style: 'unix' or 'lf' for \\n, "
369+
"'windows' or 'crlf' for \\r\\n. When not provided, system-default is used"
370+
)
371+
)
354372

355373
with _redirect_stdout_to_stderr():
356374
args = arg_parser.parse_args(program_arguments)
@@ -373,17 +391,25 @@ def _standalone_run(program_arguments):
373391

374392
format_options = FormatterOptions()
375393
format_options.indentation = args.indent
394+
395+
if args.line_endings in ["unix", "lf"]:
396+
format_options.line_endings = '\n'
397+
elif args.line_endings in ["windows", "crlf"]:
398+
format_options.line_endings = '\r\n'
399+
else:
400+
format_options.line_endings = os.linesep
401+
376402
formatter = Formatter(format_options)
377403

378404
if args.pipe:
379405
original_content = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8')
380406
print(formatter.format_string(original_content.read()))
381407
elif args.print_result:
382-
print(formatter.get_formatted_string_from_file(args.config_files[0]))
408+
print(formatter.get_formatted_string_from_file(pathlib.Path(args.config_files[0])))
383409
else:
384410
for config_file_path in args.config_files:
385-
backup_file_path = config_file_path + '~' if args.backup_original else None
386-
formatter.format_file(config_file_path, backup_file_path)
411+
backup_file_path = pathlib.Path(config_file_path + '~') if args.backup_original else None
412+
formatter.format_file(pathlib.Path(config_file_path), backup_file_path)
387413

388414

389415
def main():

test_nginxfmt.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,9 @@ def test_custom_indentation(self):
375375
"}\n"))
376376

377377

378+
#todo tests for unix and windows line endings
379+
380+
378381
class TestStandaloneRun(unittest.TestCase):
379382

380383
@contextlib.contextmanager

0 commit comments

Comments
 (0)