Skip to content

Commit cb489bd

Browse files
committed
Refactored linting code to fix issues and make it more future proof
Almost a complete rewrite. It had a few issues: - Finding user defined bodies / bundles / promise types did not work when specifying file instead of folder. - Code paths for linting arg, vs file, vs folder, vs snippet were getting complicated and confusing. - Linting rules (node checks) and state changes were getting complicated. I wanted to simplify these before we add more rules. - Probably some other issues I cannot remember. Fixing the issues was not trivial, so I decided to refactor and fix at the same time. Signed-off-by: Ole Herman Schumacher Elgesem <ole@northern.tech>
1 parent fb6a57c commit cb489bd

File tree

3 files changed

+816
-364
lines changed

3 files changed

+816
-364
lines changed

src/cfengine_cli/commands.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import json
55
from cfengine_cli.profile import profile_cfengine, generate_callstack
66
from cfengine_cli.dev import dispatch_dev_subcommand
7-
from cfengine_cli.lint import lint_folder, lint_single_arg
7+
from cfengine_cli.lint import lint_args
88
from cfengine_cli.shell import user_command
99
from cfengine_cli.paths import bin
1010
from cfengine_cli.version import cfengine_cli_version_string
@@ -96,20 +96,16 @@ def format(names, line_length) -> int:
9696

9797
def _lint(files, strict) -> int:
9898
if not files:
99-
return lint_folder(".", strict)
100-
101-
errors = 0
102-
103-
for file in files:
104-
errors += lint_single_arg(file, strict)
105-
106-
return errors
99+
return lint_args(["."], strict)
100+
return lint_args(files, strict)
107101

108102

109103
def lint(files, strict) -> int:
110104
errors = _lint(files, strict)
111105
if errors == 0:
112106
print("Success, no errors found.")
107+
elif errors == 1:
108+
print("Failure, 1 error in total.")
113109
else:
114110
print(f"Failure, {errors} errors in total.")
115111
return errors

src/cfengine_cli/docs.py

Lines changed: 59 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
from cfbs.pretty import pretty_file
1717
from cfbs.utils import find
1818

19-
from cfengine_cli.lint import lint_folder, lint_policy_file
19+
from cfengine_cli.format import format_policy_file
20+
from cfengine_cli.lint import lint_args, lint_policy_file_snippet
2021
from cfengine_cli.utils import UserError
2122

2223
IGNORED_DIRS = [".git"]
@@ -127,7 +128,7 @@ def fn_check_syntax(
127128
first_line,
128129
_last_line,
129130
snippet_number,
130-
prefix=None,
131+
prefix,
131132
):
132133
snippet_abs_path = os.path.abspath(snippet_path)
133134

@@ -138,8 +139,13 @@ def fn_check_syntax(
138139

139140
match language:
140141
case "cf":
141-
r = lint_policy_file(
142-
snippet_abs_path, origin_path, first_line + 1, snippet_number, prefix
142+
r = lint_policy_file_snippet(
143+
snippet_abs_path,
144+
origin_path,
145+
first_line + 1,
146+
snippet_number,
147+
prefix,
148+
strict=False,
143149
)
144150
if r != 0:
145151
raise UserError(f"Error when checking '{origin_path}'")
@@ -189,6 +195,7 @@ def fn_replace(origin_path, snippet_path, _language, first_line, last_line, inde
189195

190196

191197
def fn_autoformat(_origin_path, snippet_path, language, _first_line, _last_line):
198+
assert language in ("cf", "json")
192199
match language:
193200
case "json":
194201
try:
@@ -203,6 +210,9 @@ def fn_autoformat(_origin_path, snippet_path, language, _first_line, _last_line)
203210
raise UserError(f"Couldn't open '{snippet_path}'")
204211
except json.decoder.JSONDecodeError:
205212
raise UserError(f"Invalid json in '{snippet_path}'")
213+
case "cf":
214+
# Note: Dead code - Not used for CFEngine policy yet
215+
format_policy_file(snippet_path, 80)
206216

207217

208218
def _translate_language(x):
@@ -241,10 +251,23 @@ def _process_markdown_code_blocks(
241251
origin_paths = sorted(parsed_markdowns["files"].keys())
242252
origin_paths_len = len(origin_paths)
243253

254+
if origin_paths_len == 0:
255+
print("No markdown files found.")
256+
return
257+
258+
if syntax_check:
259+
# We currently only print the filenames during linting, not formatting
260+
print(
261+
f"Processing code blocks (snippets) inside {origin_paths_len} markdown files:"
262+
)
244263
for origin_paths_i, origin_path in enumerate(origin_paths):
245264
percentage = int(100 * (origin_paths_i + 1) / origin_paths_len)
246-
prefix = f"[{origin_paths_i + 1}/{origin_paths_len} ({percentage}%)] "
265+
spaces = " " * (4 - len(str(percentage)))
266+
prefix = f"[{origin_paths_i + 1}/{origin_paths_len}{spaces}({percentage}%)] "
247267
offset = 0
268+
if syntax_check and not parsed_markdowns["files"][origin_path]["code-blocks"]:
269+
print(f"{prefix}SKIP: No code blocks in '{origin_path}'")
270+
continue
248271
for i, code_block in enumerate(
249272
parsed_markdowns["files"][origin_path]["code-blocks"]
250273
):
@@ -259,33 +282,44 @@ def _process_markdown_code_blocks(
259282
snippet_path = f"{origin_path}.snippet-{snippet_number}.{language}"
260283

261284
flags = code_block["flags"]
285+
first_line = code_block["first_line"]
286+
last_line = code_block["last_line"]
262287
if "noextract" in flags or "skip" in flags:
263288
# code block was marked to be skipped
289+
if syntax_check:
290+
print(
291+
f"{prefix}SKIP: Snippet {snippet_number} at '{origin_path}:{first_line}' ({language} {' '.join(flags)})"
292+
)
264293
continue
265294
if extract:
266295
fn_extract(
267296
origin_path,
268297
snippet_path,
269298
language,
270-
code_block["first_line"],
271-
code_block["last_line"],
299+
first_line,
300+
last_line,
272301
)
273302

274-
if syntax_check and "novalidate" not in flags:
275-
try:
276-
fn_check_syntax(
277-
origin_path,
278-
snippet_path,
279-
language,
280-
code_block["first_line"],
281-
code_block["last_line"],
282-
snippet_number,
283-
prefix,
303+
if syntax_check:
304+
if "novalidate" in flags:
305+
print(
306+
f"{prefix}SKIP: Snippet {snippet_number} at '{origin_path}:{first_line}' ({language} {' '.join(flags)})"
284307
)
285-
except Exception as e:
286-
if cleanup:
287-
os.remove(snippet_path)
288-
raise e
308+
else:
309+
try:
310+
fn_check_syntax(
311+
origin_path,
312+
snippet_path,
313+
language,
314+
first_line,
315+
last_line,
316+
snippet_number,
317+
prefix,
318+
)
319+
except Exception as e:
320+
if cleanup:
321+
os.remove(snippet_path)
322+
raise e
289323

290324
if output_check and "noexecute" not in flags:
291325
fn_check_output()
@@ -295,16 +329,16 @@ def _process_markdown_code_blocks(
295329
origin_path,
296330
snippet_path,
297331
language,
298-
code_block["first_line"],
299-
code_block["last_line"],
332+
first_line,
333+
last_line,
300334
)
301335

302336
if replace and "noreplace" not in flags:
303337
offset = fn_replace(
304338
origin_path,
305339
snippet_path,
306340
language,
307-
code_block["first_line"],
341+
first_line,
308342
code_block["last_line"],
309343
code_block["indent"],
310344
)
@@ -409,7 +443,7 @@ def check_docs() -> int:
409443
410444
Run by the command:
411445
cfengine dev lint-docs"""
412-
r = lint_folder(".", strict=False)
446+
r = lint_args(["."], strict=False)
413447
if r != 0:
414448
return r
415449
_process_markdown_code_blocks(

0 commit comments

Comments
 (0)