Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 55 additions & 1 deletion main/licence_headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,43 @@ def _header_line_matches(actual, expected):
return actual == expected


def _is_region_directive(line):
return bool(re.match(r'^#region(?:\s|$)', line.strip()))


def _is_end_region_directive(line):
return bool(re.match(r'^#endregion(?:\s|$)', line.strip()))


def _find_leading_region_block(lines):
for idx, line in enumerate(lines):
stripped = line.strip()
if not stripped:
continue
if not _is_region_directive(stripped):
return None
depth = 0
for region_idx in range(idx, len(lines)):
region_line = lines[region_idx].strip()
if _is_region_directive(region_line):
depth += 1
elif _is_end_region_directive(region_line):
depth -= 1
if depth == 0:
return idx, region_idx
return None
return None


def _strip_leading_region_wrapper(text):
lines = text.splitlines()
region_block = _find_leading_region_block(lines)
if region_block is None:
return lines
idx, region_end = region_block
return lines[idx + 1:region_end]


def _known_header_prefix_end(text, offset, expected):
actual_lines = []
position = offset
Expand Down Expand Up @@ -187,6 +224,8 @@ def _damaged_full_header_end(text, offset, style):

def _existing_header_end(text, offset, style, expected):
lines = text[offset:].splitlines(keepends=True)
if lines and _is_region_directive(lines[0].strip()):
return offset
if lines and LEGACY_HEADER_PATTERN.match(lines[0]):
if len(lines) > 1 and lines[1].strip() == '':
return offset + len(lines[0]) + len(lines[1])
Expand All @@ -201,7 +240,10 @@ def _has_valid_header(text, offset, expected):
'''Check if text starting at offset contains a valid compliant header (accepting any valid year).'''
if text.startswith(expected, offset):
return True
actual_lines = [line.strip() for line in text[offset:].splitlines()]

body_lines = text[offset:].splitlines()
stripped_body = _strip_leading_region_wrapper('\n'.join(body_lines))
actual_lines = [line.strip() for line in stripped_body]
Comment thread
layfield-ccdc marked this conversation as resolved.
expected_lines = [line.strip() for line in expected.splitlines()]
if len(actual_lines) < len(expected_lines):
return False
Expand Down Expand Up @@ -242,6 +284,18 @@ def fix_content(filename, data, year=None):
if _has_valid_header(text, offset, expected):
return data

lines = text.splitlines(keepends=True)
region_block = _find_leading_region_block(lines)
if region_block is not None:
region_start, region_end = region_block
inner = ''.join(lines[region_start + 1:region_end])
if _has_valid_header(inner, 0, expected):
return data
header_end = _existing_header_end(inner, 0, style, expected)
fixed_inner = expected + inner[header_end:]
fixed = ''.join(lines[:region_start + 1]) + fixed_inner + ''.join(lines[region_end:])
return fixed.encode(encoding) if encoding else fixed

header_end = _existing_header_end(text, offset, style, expected)
prefix = text[:offset]
if prefix and not prefix.endswith(('\n', '\r')):
Expand Down
25 changes: 25 additions & 0 deletions test/test_licence_headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,31 @@ def test_existing_file_with_earlier_year_passes_and_is_not_modified():
assert 'Copyright (C) 2020' in fixed


def test_header_inside_leading_region_wrapper_passes_without_duplication():
header = licence_headers._render_header('hash', year=2026)
content = '#region Licence\n' + header + '#endregion\nprint("ok")\n'
assert licence_headers.check_content('example.py', content, 2026) is None
fixed = licence_headers.fix_content('example.py', content, 2026)
assert fixed == content


def test_regional_keyword_is_not_treated_as_region_directive():
header = licence_headers._render_header('hash', year=2026)
content = '#regional\n' + header + 'print("ok")\n'
assert licence_headers.check_content('example.py', content, 2026) is not None
fixed = licence_headers.fix_content('example.py', content, 2026)
assert fixed.startswith(header)


def test_wrapped_header_is_repaired_in_place_without_double_insert():
header = licence_headers._render_header('hash', year=2026)
broken = header.replace('# copied, except in accordance with a valid licence agreement with CCDC and\n', '')
content = '#region Licence\n' + broken + '#endregion\nprint("ok")\n'
fixed = licence_headers.fix_content('example.py', content, 2026)
assert fixed == '#region Licence\n' + header + '#endregion\nprint("ok")\n'
assert licence_headers.check_content('example.py', fixed, 2026) is None


def test_literal_year_token_fails():
header = licence_headers._render_header('hash', year=2026).replace('2026', '{{ .Year }}')
assert licence_headers.check_content('example.py', header, 2026) is not None
Expand Down
Loading