2019-02-11 14:32:13 +01:00
|
|
|
from pathlib import Path
|
2019-02-27 10:23:58 +01:00
|
|
|
import re
|
2019-02-11 14:32:13 +01:00
|
|
|
import sys
|
|
|
|
|
|
|
|
errors = []
|
|
|
|
|
|
|
|
|
|
|
|
def find_all(a_str, sub):
|
2019-02-27 18:32:47 +01:00
|
|
|
for i, line in enumerate(a_str.splitlines()):
|
2019-02-11 14:32:13 +01:00
|
|
|
column = 0
|
|
|
|
while True:
|
|
|
|
column = line.find(sub, column)
|
|
|
|
if column == -1:
|
|
|
|
break
|
|
|
|
yield i, column
|
|
|
|
column += len(sub)
|
|
|
|
|
|
|
|
|
2021-03-07 19:29:02 +01:00
|
|
|
section_regex = re.compile(r"^(=+|-+|\*+|~+)$")
|
|
|
|
directive_regex = re.compile(r"^(\s*)\.\. (.*)::.*$")
|
|
|
|
directive_arg_regex = re.compile(r"^(\s+):.*:\s*.*$")
|
|
|
|
esphome_io_regex = re.compile(r"https://esphome.io/")
|
2019-02-27 10:23:58 +01:00
|
|
|
|
|
|
|
|
2021-03-07 19:29:02 +01:00
|
|
|
for f in sorted(Path(".").glob("**/*.rst")):
|
2019-02-11 14:32:13 +01:00
|
|
|
try:
|
2021-03-07 19:29:02 +01:00
|
|
|
content = f.read_text("utf-8")
|
2019-02-11 14:32:13 +01:00
|
|
|
except UnicodeDecodeError:
|
2021-03-07 19:29:02 +01:00
|
|
|
errors.append(
|
|
|
|
"File {} is not readable as UTF-8. Please set your editor to UTF-8 mode."
|
|
|
|
"".format(f)
|
|
|
|
)
|
2019-02-27 18:32:47 +01:00
|
|
|
continue
|
|
|
|
|
2021-03-07 19:29:02 +01:00
|
|
|
if not content.endswith("\n"):
|
|
|
|
errors.append(
|
|
|
|
"Newline at end of file missing. Please insert an empty line at end "
|
|
|
|
"of file {}".format(f)
|
|
|
|
)
|
2019-02-27 18:32:47 +01:00
|
|
|
|
|
|
|
# Check tab character
|
2021-03-07 19:29:02 +01:00
|
|
|
for line, col in find_all(content, "\t"):
|
|
|
|
errors.append(
|
|
|
|
"File {} contains tab character on line {}:{}. "
|
|
|
|
"Please convert tabs to spaces.".format(f, line + 1, col)
|
|
|
|
)
|
2019-02-27 18:32:47 +01:00
|
|
|
# Check windows newline
|
2021-03-07 19:29:02 +01:00
|
|
|
for line, col in find_all(content, "\r"):
|
|
|
|
errors.append(
|
|
|
|
"File {} contains windows newline on line {}:{}. "
|
|
|
|
"Please set your editor to unix newline mode.".format(f, line + 1, col)
|
|
|
|
)
|
2019-02-11 14:32:13 +01:00
|
|
|
|
2019-02-27 10:23:58 +01:00
|
|
|
lines = content.splitlines(keepends=False)
|
2019-02-27 18:32:47 +01:00
|
|
|
|
2020-01-12 16:36:02 +01:00
|
|
|
# for i, line in enumerate(lines):
|
|
|
|
# if i == 0:
|
|
|
|
# continue
|
|
|
|
#
|
|
|
|
# if not section_regex.match(line):
|
|
|
|
# continue
|
|
|
|
# line_above = lines[i - 1]
|
|
|
|
# if len(line_above) != len(line):
|
|
|
|
# errors.append("The title length must match the bar length below it. See {}:{}"
|
|
|
|
# "".format(f, i+1))
|
|
|
|
# if i + 1 < len(lines) and lines[i + 1]:
|
|
|
|
# errors.append("Empty line after heading is missing. Please insert an "
|
|
|
|
# "empty line. See {}:{}".format(f, i+1))
|
2019-02-27 18:32:47 +01:00
|
|
|
|
|
|
|
for i, line in enumerate(lines):
|
|
|
|
m = directive_regex.match(line)
|
|
|
|
if m is None:
|
|
|
|
continue
|
|
|
|
base_indentation = len(m.group(1))
|
|
|
|
directive_name = m.group(2)
|
2021-03-07 19:29:02 +01:00
|
|
|
if directive_name.startswith("|") or directive_name == "seo":
|
2019-02-27 18:32:47 +01:00
|
|
|
continue
|
|
|
|
# Match directive args
|
|
|
|
for j in range(i + 1, len(lines)):
|
|
|
|
if not directive_arg_regex.match(lines[j]):
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
# Reached end of file
|
|
|
|
continue
|
|
|
|
|
|
|
|
# Empty line must follow
|
|
|
|
if lines[j]:
|
2021-03-07 19:29:02 +01:00
|
|
|
errors.append(
|
|
|
|
"Directive '{}' is not followed by an empty line. Please insert an "
|
|
|
|
"empty line after {}:{}".format(directive_name, f, j)
|
|
|
|
)
|
2019-02-27 18:32:47 +01:00
|
|
|
continue
|
|
|
|
|
|
|
|
k = j + 1
|
|
|
|
for j in range(k, len(lines)):
|
|
|
|
if not lines[j]:
|
|
|
|
# Ignore Empty lines
|
|
|
|
continue
|
|
|
|
|
|
|
|
num_spaces = len(lines[j]) - len(lines[j].lstrip())
|
|
|
|
if num_spaces <= base_indentation:
|
|
|
|
# Finished with this directive
|
|
|
|
break
|
|
|
|
num_indent = num_spaces - base_indentation
|
|
|
|
if j == k and num_indent != 4:
|
2021-03-07 19:29:02 +01:00
|
|
|
errors.append(
|
|
|
|
"Directive '{}' must be indented with 4 spaces, not {}. See "
|
|
|
|
"{}:{}".format(directive_name, num_indent, f, j + 1)
|
|
|
|
)
|
2019-02-27 18:32:47 +01:00
|
|
|
break
|
|
|
|
|
|
|
|
for i, line in enumerate(lines):
|
|
|
|
if esphome_io_regex.search(line):
|
2021-03-07 19:29:02 +01:00
|
|
|
if "privacy.rst" in str(f) or "web_server.rst" in str(f):
|
2019-02-27 18:32:47 +01:00
|
|
|
continue
|
2021-03-07 19:29:02 +01:00
|
|
|
errors.append(
|
|
|
|
"All links to esphome.io should be relative, please remove esphome.io "
|
|
|
|
"from URL. See {}:{}".format(f, i + 1)
|
|
|
|
)
|
2019-02-27 10:23:58 +01:00
|
|
|
|
|
|
|
|
2019-02-11 14:32:13 +01:00
|
|
|
for error in errors:
|
|
|
|
print(error)
|
|
|
|
|
|
|
|
sys.exit(len(errors))
|