90 lines
2.9 KiB
Python
90 lines
2.9 KiB
Python
|
import glob
|
||
|
|
||
|
class WikiArticle:
|
||
|
def __init__(self, filename):
|
||
|
def tags(content):
|
||
|
for line in content:
|
||
|
if line.startswith('#+FILETAGS:'):
|
||
|
tags = line.replace(' ', '').strip().split(":")[1:]
|
||
|
tags = list(filter(identity, tags))
|
||
|
return tags
|
||
|
raise Exception(f'no tags in {filename}')
|
||
|
|
||
|
def title(content):
|
||
|
for line in content:
|
||
|
if line.startswith('#+TITLE:'):
|
||
|
res = line.strip().replace(' ', '', 1).split(':')
|
||
|
if len(res) > 2: raise Exception(f'Invalid title in {filename}')
|
||
|
return res[-1]
|
||
|
raise Exception(f'No title in {filename}')
|
||
|
|
||
|
with open(filename, 'r') as f:
|
||
|
content = f.readlines()
|
||
|
self.content = [c.strip() for c in content]
|
||
|
self.title = title(content)
|
||
|
self.tags = tags(content)
|
||
|
self.filename = filename
|
||
|
|
||
|
def __repr__(self):
|
||
|
return f'{type(self).__name__}({self.title}, {self.filename}, {self.tags})'
|
||
|
|
||
|
class ContentArticle(WikiArticle): pass
|
||
|
class MetaPage(WikiArticle):
|
||
|
def __init__(self, filename):
|
||
|
self.header = '** Pages in this category'
|
||
|
super().__init__(filename)
|
||
|
if len(self.tags) > 1:
|
||
|
raise Exception(f'Multiple tags in metapage: {self.filename}')
|
||
|
self.meta = self.tags[0]
|
||
|
|
||
|
correct_section = list(filter(lambda l: l == self.header, self.content))
|
||
|
if len(correct_section) != 1:
|
||
|
raise Exception(f'Invalid meta section in {filename}')
|
||
|
|
||
|
def replace_content(self, wikiarticles):
|
||
|
content = map(identity, self.content)
|
||
|
def rep():
|
||
|
for line in content:
|
||
|
if line == self.header: break
|
||
|
else: yield line
|
||
|
yield self.header
|
||
|
for w in wikiarticles:
|
||
|
yield f'- [[../{w.filename}][{w.title}]]'
|
||
|
return rep()
|
||
|
|
||
|
|
||
|
identity = lambda x: x
|
||
|
def merge(d1, d2):
|
||
|
d1.update(d2)
|
||
|
return d1
|
||
|
|
||
|
def files():
|
||
|
return filter(lambda f: f not in {'todo.org'}, glob.glob('*.org'))
|
||
|
|
||
|
def metafiles():
|
||
|
return glob.glob('meta/*.org')
|
||
|
|
||
|
|
||
|
def invert_map(map_: list[WikiArticle]):
|
||
|
'''from {a: [1, 2], b: [2, 3]} to {1: [a], 2: [a, b], 3: [b]}'''
|
||
|
keys = set(i for e in map_ for i in e.tags)
|
||
|
res = dict()
|
||
|
for k in keys:
|
||
|
res[k] = res.get(k, []) + [w for w in map_ if k in w.tags]
|
||
|
return res
|
||
|
|
||
|
def write_meta_page(m: MetaPage, content: list[str]):
|
||
|
with open(m.filename, 'w') as f:
|
||
|
f.writelines(map(lambda l: l+'\n', content))
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
files = [ContentArticle(f) for f in files()]
|
||
|
meta = [MetaPage(f) for f in metafiles()]
|
||
|
meta = {m.meta: m for m in meta}
|
||
|
print(meta)
|
||
|
tags = invert_map(files)
|
||
|
for t, articles in tags.items():
|
||
|
if t in meta:
|
||
|
newcontent = meta[t].replace_content(articles)
|
||
|
write_meta_page(meta[t], newcontent)
|