-
Notifications
You must be signed in to change notification settings - Fork 0
/
renderdeps.py
131 lines (104 loc) · 3.91 KB
/
renderdeps.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# -*- coding: utf8 -*-
import logging
from bs4 import BeautifulSoup
from pelican import signals
from pelican.generators import ArticlesGenerator, PagesGenerator, TemplatePagesGenerator
import threading
import queue
MAX_THREADS = 1
RENDERDEPS_USE_SOUP_DEFAULT = False
def makeStrmatches(args, kwargs):
tagmatch = f"<{args[0]} " if len(args) > 0 else ""
class_args = kwargs.get('class_', [])
if isinstance(class_args, str):
class_args = [class_args]
classmatches = [f'class="{v}"' for v in class_args]
if classmatches:
return [
f"{tagmatch}{c}"
for c in classmatches
]
else:
return [tagmatch]
def process_dependencies(article, generator=None):
"""
Pelican callback
"""
# TODO: This is far too slow.
if article._content is None:
logging.warning(f"{article.title} is empty!")
return
settings = article.settings
dependencies = settings.get("RENDER_DEPS", [])
use_soup = settings.get("RENDERDEPS_USE_SOUP", RENDERDEPS_USE_SOUP_DEFAULT)
dirty = False
for (args, kwargs, *strmatches_), dep in dependencies:
# logging.debug(f"Checking for '{args} {kwargs}'")
if use_soup:
soup = BeautifulSoup(article._content, 'html.parser')
if match := soup.find(*args, **kwargs):
logging.info("Inserting dependency " + repr(dep) + " into " + repr(article.slug) + " matching" + repr(match))
soup.append(BeautifulSoup(dep, 'html.parser'))
dirty = True
else:
strmatches = strmatches_ or makeStrmatches(args, kwargs)
if any(s in article._content for s in strmatches):
logging.debug(f"Matched '{strmatches}'")
article._content += dep
# just chuck it in
if use_soup and dirty:
article._content = str(soup)
else:
# logging.debug("No dependencies in " + repr(article.slug))
pass
return
TYPES_TO_PROCESS = [
"articles", "pages", "drafts",
"hidden_pages", "hidden_articles",
"translations", "hidden_translations", "draft_translations", "drafts_translations"
]
def link_source_files(generator):
"""
Processes each article/page object and formulates copy from and copy
to destinations, as well as adding a source file URL as an attribute.
"""
# Get all attributes from the generator that are articles or pages
def add_deps(generators):
# Process the articles and pages
THREADED = MAX_THREADS > 1
if THREADED:
q = queue.Queue()
class Worker(threading.Thread):
def __init__(self, fn, *args, **kwargs):
self.fn = fn
super().__init__(*args, **kwargs)
def run(self):
while True:
try:
work = q.get(timeout=3) # 3s timeout
except queue.Empty:
return
self.fn(*work)
q.task_done()
document_generators = [ArticlesGenerator, PagesGenerator, TemplatePagesGenerator]
for generator in generators:
if any(isinstance(generator, t) for t in document_generators):
documents = sum([
getattr(generator, attr, None)
for attr in TYPES_TO_PROCESS
if getattr(generator, attr, None)
], [])
for document in documents:
if THREADED:
work = (document, generator)
q.put_nowait(work)
else:
process_dependencies(document, generator)
else:
logging.debug(f"Renderdeps: Unhandled generator {generator}")
if THREADED:
for _ in range(MAX_THREADS):
Worker(process_dependencies).start()
q.join() # blocks until the queue is empty.
def register():
signals.all_generators_finalized.connect(add_deps)