Dont use YAML for the changelog

No point having an extra dependency just to parse the changelog, which
doesnt have a ot of structured information, anyway.
This commit is contained in:
Kovid Goyal 2020-10-29 10:36:40 +05:30
parent b7bb73e40e
commit 49af5de171
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
5 changed files with 21543 additions and 22484 deletions

20065
Changelog.old.txt Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1309
Changelog.txt Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

169
setup/changelog.py Normal file
View File

@ -0,0 +1,169 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from datetime import date
def parse(raw):
entries = []
current_entry = None
current_section = 'new features'
def normal(linenum, line, stripped_line):
nonlocal current_entry, current_section
if not stripped_line:
return normal
if stripped_line.startswith('{' '{' '{'):
parts = line.split()[1:]
if len(parts) != 2:
raise ValueError(f'The entry start line is malformed: {line}')
if current_entry is not None:
raise ValueError(f'Start of entry while previous entry is still active at line: {linenum}')
version, draw = parts
d = date(*map(int, draw.split('-')))
current_entry = {'version': version, 'date': d, 'new features': [], 'bug fixes': [], 'improved recipes': [], 'new recipes': []}
current_section = 'new features'
return in_entry
raise ValueError(f'Invalid content at line {linenum}: {line}')
def in_entry(linenum, line, stripped_line):
nonlocal current_section, current_entry
if stripped_line == '}' '}' '}':
if current_entry is None:
raise ValueError(f'Entry terminator without active entry at line: {linenum}')
entries.append(current_entry)
current_entry = None
return normal
if line.startswith(':: '):
current_section = line[3:].strip()
if current_section not in ('new features', 'bug fixes', 'new recipes', 'improved recipes'):
raise ValueError(f'Unknown section: {current_section}')
return in_entry
if line.startswith('-'):
return start_item(linenum, line, stripped_line)
if not stripped_line:
return in_entry
raise ValueError(f'Invalid content at line {linenum}: {line}')
def start_item(linenum, line, stripped_line):
line = line[1:].lstrip()
items = current_entry[current_section]
if current_section == 'improved recipes':
items.append(line.rstrip())
return in_entry
if current_section == 'new recipes':
idx = line.rfind('by ')
if idx == -1:
items.append({'title': line.strip()})
else:
items.append({'title': line[:idx].strip(), 'author': line[idx + 3:].strip()})
return in_entry
item = {}
if line.startswith('['):
idx = line.find(']')
if idx == -1:
raise ValueError(f'No closing ] found in line: {linenum}')
for x in line[1:idx].split():
if x == 'major':
item['type'] = x
continue
num = int(x)
item.setdefault('tickets', []).append(num)
item['title'] = line[idx+1:].strip()
else:
item['title'] = line.strip()
items.append(item)
return in_item
def finalize_item(item):
if 'description' in item and not item['description']:
del item['description']
return item
def in_item(linenum, line, stripped_line):
item = current_entry[current_section][-1]
if line.startswith('::'):
finalize_item(item)
return in_entry(linenum, line, stripped_line)
if line.startswith('-'):
finalize_item(item)
return start_item(linenum, line, stripped_line)
if line.startswith('}' '}' '}'):
return in_entry(linenum, line, stripped_line)
if not stripped_line:
if 'description' not in item:
item['description'] = ''
return in_item
if 'description' in item:
item['description'] += stripped_line
else:
item['title'] += stripped_line
return in_item
state = normal
for i, line in enumerate(raw.splitlines()):
if line.startswith('#'):
continue
stripped_line = line.strip()
state = state(i + 1, line, stripped_line)
return entries
def migrate():
from yaml import safe_load
def output_item(item, lines):
meta = []
if item.get('type') == 'major':
meta.append(item['type'])
for x in item.get('tickets', ()):
meta.append(str(x))
title = item['title']
if meta:
meta = ' '.join(meta)
title = f'[{meta}] {title}'
lines.append(f'- {title}')
d = item.get('description')
if d:
lines.append(''), lines.append(d)
lines.append('')
for name in ('Changelog.yaml', 'Changelog.old.yaml'):
entries = safe_load(open(name).read())
lines = []
for entry in entries:
lines.append('')
lines.append('{' '{' '{' f' {entry["version"]} {entry["date"]}')
for w in ('new features', 'bug fixes'):
nf = entry.get(w)
if nf:
lines.append(f':: {w}'), lines.append('')
for x in nf:
output_item(x, lines)
lines.append('')
nr = entry.get('new recipes')
if nr:
lines.append(':: new recipes'), lines.append('')
for r in nr:
aut = r.get('author') or r.get('authors')
title = r['title']
if title:
if aut:
lines.append(f'- {title} by {aut}')
else:
lines.append(f'- {title}')
lines.append('')
ir = entry.get('improved recipes')
if ir:
lines.append(':: improved recipes'), lines.append('')
for r in ir:
lines.append(f'- {r}')
lines.append('')
with open(name.replace('yaml', 'txt'), 'w') as f:
f.write('\n'.join(lines))
lines.append(''), lines.append('}' '}' '}'), lines.append('')
if __name__ == '__main__':
migrate()