4 from difflib import SequenceMatcher
5 from typing import List
7 from termcolor import cprint # python3-termcolor
9 from pywikibot import input_yn
11 from wrpylib.mwapi import WikiSite
12 from wrpylib.wrmwmarkup import create_sledrun_wiki
15 def _format_range_unified(start: int, stop: int) -> str:
16 """Copied from difflib._format_range_unified"""
17 beginning = start + 1 # lines start numbering with one
22 beginning -= 1 # empty ranges begin at line just before the range
23 return f'{beginning},{length}'
26 def unified_diff(a: str, b: str, context: int = 3):
27 a_lines = a.splitlines()
28 b_lines = b.splitlines()
29 for group in SequenceMatcher(None, a_lines, b_lines).get_grouped_opcodes(context):
30 first, last = group[0], group[-1]
31 file1_range = _format_range_unified(first[1], last[2])
32 file2_range = _format_range_unified(first[3], last[4])
33 cprint(f'@@ -{file1_range} +{file2_range} @@', 'magenta')
35 for tag, i1, i2, j1, j2 in group:
37 for line in a_lines[i1:i2]:
40 if tag in {'replace', 'delete'}:
41 for line in a_lines[i1:i2]:
42 cprint(f'- {line}', 'red')
43 if tag in {'replace', 'insert'}:
44 for line in b_lines[j1:j2]:
45 cprint(f'+ {line}', 'green')
48 def update_sledrun(site: WikiSite, wiki_page: dict, json_page: dict, map_page: dict, impression_page: dict):
49 json_page_main_slot = json_page['revisions'][0]['slots']['main']
50 assert json_page_main_slot['contentmodel'] == 'json'
51 sledrun_json = json.loads(json_page_main_slot['content'])
52 jsonschema.validate(instance=sledrun_json, schema=site.sledrun_schema())
54 if 'missing' in map_page:
57 map_page_main_slot = map_page['revisions'][0]['slots']['main']
58 assert map_page_main_slot['contentmodel'] == 'json'
59 map_json = json.loads(map_page_main_slot['content'])
61 if 'missing' in impression_page:
62 impression_title = None
64 impression_title = impression_page['title']
66 new_text = create_sledrun_wiki(sledrun_json, map_json, impression_title).strip()
68 previous_text = wiki_page['revisions'][0]['slots']['main']['content'].strip()
69 if new_text == previous_text:
72 cprint(wiki_page['title'], 'green')
73 unified_diff(previous_text, new_text)
74 yn = input_yn('Do you accept the changes?', True)
80 pageid=wiki_page['pageid'],
82 summary='Rodelbahnbeschreibung aus JSON Daten aktualisiert.',
85 baserevid=wiki_page['revisions'][0]['revid'],
91 def update_sledrun_wikitext(ini_files: List[str], update_all: bool):
92 site = WikiSite(ini_files)
94 for wikitext_result in site.query(list='categorymembers', cmtitle='Kategorie:Rodelbahn', cmlimit=cm_limit):
95 wikitext_title_list = [page["title"] for page in wikitext_result['categorymembers']]
96 json_title_list = [f'{title}/Rodelbahn.json' for title in wikitext_title_list]
98 wikitext_result = query_revisions(site, wikitext_title_list, [])
99 json_result = query_revisions(site, json_title_list, [])
101 update_wikitext_title_list = []
102 update_json_title_list = []
103 for wikitext_page, json_page in zip(wikitext_result, json_result):
104 assert wikitext_page['title'] + '/Rodelbahn.json' == json_page['title']
105 if 'missing' in json_page:
107 if wikitext_page['revisions'][0]['timestamp'] < json_page['revisions'][0]['timestamp']:
108 update_wikitext_title_list.append(wikitext_page['title'])
109 update_json_title_list.append(json_page['title'])
111 if len(update_wikitext_title_list) == 0:
114 update_map_title_list = [f'{title}/Landkarte.json' for title in update_wikitext_title_list]
115 update_impression_title_list = [f'{title}/Impressionen' for title in update_wikitext_title_list]
117 update_wikitext_result = query_revisions(site, update_wikitext_title_list, ['content'])
118 update_json_result = query_revisions(site, update_json_title_list, ['content'])
119 update_map_result = query_revisions(site, update_map_title_list, ['content'])
120 update_impression_result = query_revisions(site, update_impression_title_list, ['content'])
122 for wikitext_page, json_page, map_page, impression_page in \
123 zip(update_wikitext_result, update_json_result, update_map_result, update_impression_result):
124 assert wikitext_page['title'] + '/Rodelbahn.json' == json_page['title']
125 update_sledrun(site, wikitext_page, json_page, map_page, impression_page)
128 def query_revisions(site: WikiSite, title_list: List[str], extra_rv_prop: List[str]) -> List[dict]:
129 rv_prop = ['timestamp', 'ids'] + extra_rv_prop
130 pages = next(site.query(prop='revisions', titles=title_list, rvslots='*', rvprop=rv_prop))['pages']
131 pages = sorted(pages, key=lambda p: title_list.index(p['title']))
132 assert len(title_list) == len(pages)
137 parser = argparse.ArgumentParser(description='Update sledrun wikitext from JSON')
138 parser.add_argument('--all', action='store_true',
139 help='update all sledruns regardless of modification date differences')
140 parser.add_argument('inifile', nargs='+', help='inifile.ini, see: https://www.winterrodeln.org/trac/wiki/ConfigIni')
141 args = parser.parse_args()
142 update_sledrun_wikitext(args.inifile, args.all)
145 if __name__ == '__main__':