Skip to content

Commit de68daf

Browse files
authored
Merge pull request #59 from nginxinc/fix-build-starting-with-comment
Refactored and fixed crossplane.build
2 parents 07f2ab8 + 6a77f36 commit de68daf

File tree

3 files changed

+61
-70
lines changed

3 files changed

+61
-70
lines changed

crossplane/builder.py

Lines changed: 42 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -74,75 +74,54 @@ def _enquote(arg):
7474

7575
def build(payload, indent=4, tabs=False, header=False):
7676
padding = '\t' if tabs else ' ' * indent
77-
state = {
78-
'prev_obj': None,
79-
'depth': -1
80-
}
8177

82-
def _put_line(line, obj):
83-
margin = padding * state['depth']
84-
85-
# don't need put \n on first line and after comment
86-
if state['prev_obj'] is None:
87-
return margin + line
88-
89-
# trailing comments have to be without \n
90-
if obj['directive'] == '#' and obj['line'] == state['prev_obj']['line']:
91-
return ' ' + line
92-
93-
return '\n' + margin + line
78+
head = ''
79+
if header:
80+
head += '# This config was built from JSON using NGINX crossplane.\n'
81+
head += '# If you encounter any bugs please report them here:\n'
82+
head += '# https://github.com/nginxinc/crossplane/issues\n'
83+
head += '\n'
9484

95-
def _build_lines(objs):
96-
state['depth'] = state['depth'] + 1
85+
def _build_block(output, block, depth, last_line):
86+
margin = padding * depth
9787

98-
for obj in objs:
99-
directive = _enquote(obj['directive'])
88+
for stmt in block:
89+
directive = _enquote(stmt['directive'])
90+
line = stmt.get('line', 0)
10091

101-
if directive in EXTERNAL_BUILDERS:
102-
external_builder = EXTERNAL_BUILDERS[directive]
103-
built = external_builder(obj, padding, state, indent, tabs)
104-
yield _put_line(built, obj)
92+
if directive == '#' and line == last_line:
93+
output += ' #' + stmt['comment']
10594
continue
106-
107-
if directive == '#':
108-
yield _put_line('#' + obj['comment'], obj)
109-
continue
110-
111-
args = [_enquote(arg) for arg in obj['args']]
112-
113-
if directive == 'if':
114-
line = 'if (' + ' '.join(args) + ')'
115-
elif args:
116-
line = directive + ' ' + ' '.join(args)
117-
else:
118-
line = directive
119-
120-
if obj.get('block') is None:
121-
yield _put_line(line + ';', obj)
95+
elif directive == '#':
96+
built = '#' + stmt['comment']
97+
elif directive in EXTERNAL_BUILDERS:
98+
external_builder = EXTERNAL_BUILDERS[directive]
99+
built = external_builder(stmt, padding, indent, tabs)
122100
else:
123-
yield _put_line(line + ' {', obj)
124-
125-
# set prev_obj to propper indentation in block
126-
state['prev_obj'] = obj
127-
for line in _build_lines(obj['block']):
128-
yield line
129-
yield _put_line('}', obj)
130-
131-
state['prev_obj'] = obj
132-
state['depth'] = state['depth'] - 1
133-
134-
if header:
135-
lines = [
136-
'# This config was built from JSON using NGINX crossplane.\n',
137-
'# If you encounter any bugs please report them here:\n',
138-
'# https://github.com/nginxinc/crossplane/issues\n',
139-
'\n'
140-
]
141-
else:
142-
lines = []
143-
144-
lines += _build_lines(payload)
145-
return ''.join(lines)
101+
args = [_enquote(arg) for arg in stmt['args']]
102+
103+
if directive == 'if':
104+
built = 'if (' + ' '.join(args) + ')'
105+
elif args:
106+
built = directive + ' ' + ' '.join(args)
107+
else:
108+
built = directive
109+
110+
if stmt.get('block') is None:
111+
built += ';'
112+
else:
113+
built += ' {'
114+
built = _build_block(built, stmt['block'], depth+1, line)
115+
built += '\n' + margin + '}'
116+
117+
output += ('\n' if output else '') + margin + built
118+
last_line = line
119+
120+
return output
121+
122+
body = ''
123+
body = _build_block(body, payload, 0, 0)
124+
return head + body
146125

147126

148127
def build_files(payload, dirname=None, indent=4, tabs=False, header=False):

crossplane/ext/lua.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def lex(self, char_iterator, directive):
9292
def parse(self, stmt, parsing, tokens, ctx=(), consume=False):
9393
pass
9494

95-
def build(self, stmt, padding, state, indent=4, tabs=False):
95+
def build(self, stmt, padding, indent=4, tabs=False):
9696
built = stmt['directive']
9797
if built == 'set_by_lua_block':
9898
block = stmt['args'][1]

tests/test_build.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,7 @@ def test_build_nested_and_multiple_args():
4848
]
4949
}
5050
]
51-
5251
built = crossplane.build(payload, indent=4, tabs=False)
53-
5452
assert built == '\n'.join([
5553
'events {',
5654
' worker_connections 1024;',
@@ -148,9 +146,7 @@ def test_build_with_comments():
148146
]
149147
}
150148
]
151-
152149
built = crossplane.build(payload, indent=4, tabs=False)
153-
154150
assert built == '\n'.join([
155151
'events {',
156152
' worker_connections 1024;',
@@ -170,6 +166,24 @@ def test_build_with_comments():
170166
])
171167

172168

169+
def test_build_starts_with_comments():
170+
payload = [
171+
{
172+
"directive": "#",
173+
"line": 1,
174+
"args": [],
175+
"comment": " foo"
176+
},
177+
{
178+
"directive": "user",
179+
"line": 5,
180+
"args": ["root"]
181+
}
182+
]
183+
built = crossplane.build(payload, indent=4, tabs=False)
184+
assert built == '# foo\nuser root;'
185+
186+
173187
def test_build_with_quoted_unicode():
174188
payload = [
175189
{
@@ -178,9 +192,7 @@ def test_build_with_quoted_unicode():
178192
"args": ["русский текст"],
179193
}
180194
]
181-
182195
built = crossplane.build(payload, indent=4, tabs=False)
183-
184196
assert built == u"env 'русский текст';"
185197

186198

0 commit comments

Comments
 (0)