]> jfr.im git - yt-dlp.git/blob - devscripts/prepare_manpage.py
[cleanup,build] Cleanup some build-related code
[yt-dlp.git] / devscripts / prepare_manpage.py
1 #!/usr/bin/env python3
2 import optparse
3 import os.path
4 import re
5
6 ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
7 README_FILE = os.path.join(ROOT_DIR, 'README.md')
8
9 PREFIX = r'''%yt-dlp(1)
10
11 # NAME
12
13 yt\-dlp \- A youtube-dl fork with additional features and patches
14
15 # SYNOPSIS
16
17 **yt-dlp** \[OPTIONS\] URL [URL...]
18
19 # DESCRIPTION
20
21 '''
22
23
24 def main():
25 parser = optparse.OptionParser(usage='%prog OUTFILE.md')
26 options, args = parser.parse_args()
27 if len(args) != 1:
28 parser.error('Expected an output filename')
29
30 outfile, = args
31
32 with open(README_FILE, encoding='utf-8') as f:
33 readme = f.read()
34
35 readme = filter_excluded_sections(readme)
36 readme = move_sections(readme)
37 readme = filter_options(readme)
38
39 with open(outfile, 'w', encoding='utf-8') as outf:
40 outf.write(PREFIX + readme)
41
42
43 def filter_excluded_sections(readme):
44 EXCLUDED_SECTION_BEGIN_STRING = re.escape('<!-- MANPAGE: BEGIN EXCLUDED SECTION -->')
45 EXCLUDED_SECTION_END_STRING = re.escape('<!-- MANPAGE: END EXCLUDED SECTION -->')
46 return re.sub(
47 rf'(?s){EXCLUDED_SECTION_BEGIN_STRING}.+?{EXCLUDED_SECTION_END_STRING}\n',
48 '', readme)
49
50
51 def move_sections(readme):
52 MOVE_TAG_TEMPLATE = '<!-- MANPAGE: MOVE "%s" SECTION HERE -->'
53 sections = re.findall(r'(?m)^%s$' % (
54 re.escape(MOVE_TAG_TEMPLATE).replace(r'\%', '%') % '(.+)'), readme)
55
56 for section_name in sections:
57 move_tag = MOVE_TAG_TEMPLATE % section_name
58 if readme.count(move_tag) > 1:
59 raise Exception(f'There is more than one occurrence of "{move_tag}". This is unexpected')
60
61 sections = re.findall(rf'(?sm)(^# {re.escape(section_name)}.+?)(?=^# )', readme)
62 if len(sections) < 1:
63 raise Exception(f'The section {section_name} does not exist')
64 elif len(sections) > 1:
65 raise Exception(f'There are multiple occurrences of section {section_name}, this is unhandled')
66
67 readme = readme.replace(sections[0], '', 1).replace(move_tag, sections[0], 1)
68 return readme
69
70
71 def filter_options(readme):
72 section = re.search(r'(?sm)^# USAGE AND OPTIONS\n.+?(?=^# )', readme).group(0)
73 options = '# OPTIONS\n'
74 for line in section.split('\n')[1:]:
75 mobj = re.fullmatch(r'''(?x)
76 \s{4}(?P<opt>-(?:,\s|[^\s])+)
77 (?:\s(?P<meta>(?:[^\s]|\s(?!\s))+))?
78 (\s{2,}(?P<desc>.+))?
79 ''', line)
80 if not mobj:
81 options += f'{line.lstrip()}\n'
82 continue
83 option, metavar, description = mobj.group('opt', 'meta', 'desc')
84
85 # Pandoc's definition_lists. See http://pandoc.org/README.html
86 option = f'{option} *{metavar}*' if metavar else option
87 description = f'{description}\n' if description else ''
88 options += f'\n{option}\n: {description}'
89 continue
90
91 return readme.replace(section, options, 1)
92
93
94 if __name__ == '__main__':
95 main()