writeHTML.py (9204B)
1 #!/usr/bin/python3 2 # Copyright 2003-2008, Nick Mathewson. See LICENSE for licensing info. 3 # Copyright 2018, 2019 ng0 <ng0@n0.is> 4 5 """ 6 Generate indices by author, topic, date, and BibTeX key. 7 """ 8 9 from future.utils import raise_with_traceback 10 from io import BytesIO ## for Python 3 11 import sys 12 import re 13 import os 14 import json 15 import BibTeX 16 import config 17 18 19 assert sys.version_info[:3] >= (2, 2, 0) 20 os.umask(0o22) 21 22 def getTemplate(name): 23 template_file = open(name) 24 template = template_file.read() 25 template_file.close() 26 template_s, template_e = template.split("%(entries)s") 27 return template_s, template_e 28 29 def pathLength(s): 30 n = 0 31 while s: 32 parent, leaf = os.path.split(s) 33 if leaf != '' and leaf != '.': 34 n += 1 35 s = parent 36 return n 37 38 def writeBody(target_file, sections, section_urls, cache_path, base_url): 39 """ 40 target_file: an open file 41 sections: list of (sectionname, [list of BibTeXEntry]) 42 section_urls: map from sectionname to external url 43 """ 44 for s, entries in sections: 45 u = section_urls.get(s) 46 sDisp = re.sub(r'\s+', ' ', s.strip()) 47 sDisp = sDisp.replace(" ", " ") 48 print("<section class='item-preview'>", file=target_file) 49 if u: 50 print(('<h3><a name="%s"></a><a href="%s">%s</a></h3>' 51 %((BibTeX.url_untranslate(s), u, sDisp))), 52 file=target_file) 53 else: 54 print(('<h3><a name="%s">%s</a></h3>' 55 %(BibTeX.url_untranslate(s), sDisp)), 56 file=target_file) 57 #print("<section class='item-preview'>", file=target_file) 58 for e in entries: 59 print(e.to_html(cache_path=cache_path, base_url=base_url), 60 file=target_file) 61 print("</section>", file=target_file) 62 63 def writeHTML(f, sections, sectionType, fieldName, choices, 64 tag, config, cache_url_path, section_urls={}): 65 """ 66 sections: list of (sectionname, [list of BibTeXEntry])''' 67 sectionType: str 68 fieldName: str 69 choices: list of (choice, url) 70 """ 71 72 title = config.TAG_TITLES[tag] 73 short_title = config.TAG_SHORT_TITLES[tag] 74 # what used to be the sidebar: 75 secStr = [] 76 for s, _ in sections: 77 hts = re.sub(r'\s+', ' ', s.strip()) 78 hts = s.replace(" ", " ") 79 secStr.append("<li class='bar-item'><a class='bar-link' href='#%s'>%s</a></li>\n"% 80 ((BibTeX.url_untranslate(s), hts))) 81 secStr = "".join(secStr) 82 83 # 84 tagListStr = [] 85 st = list(config.TAG_SHORT_TITLES.keys()) 86 st.sort() 87 root = "../"*pathLength(config.TAG_DIRECTORIES[tag]) 88 if root == "": root = "." 89 for t in st: 90 name = config.TAG_SHORT_TITLES[t] 91 if t == tag: 92 tagListStr.append(name) 93 else: 94 url = BibTeX.smartJoin(root, config.TAG_DIRECTORIES[t], "date.html") 95 tagListStr.append("<a href='%s'>%s</a>"%(url, name)) 96 tagListStr = " | ".join(tagListStr) 97 98 # 99 choiceStr = [] 100 for choice, url in choices: 101 if url: 102 choiceStr.append("<a href='%s'>%s</a>"%(url, choice)) 103 else: 104 choiceStr.append(choice) 105 106 choiceStr = (" | ".join(choiceStr)) 107 108 fields = {'command_line' : "", 109 'sectiontypes' : sectionType, 110 'choices' : choiceStr, 111 'field': fieldName, 112 'sections' : secStr, 113 'otherbibs' : tagListStr, 114 'title': title, 115 'short_title': short_title, 116 "root" : root,} 117 118 header, footer = getTemplate(config.TEMPLATE_FILE) 119 print(header%fields, file=f) 120 writeBody(f, sections, section_urls, cache_path=cache_url_path, 121 base_url=root) 122 print(footer%fields, file=f) 123 124 def jsonDumper(obj): 125 if isinstance(obj, BibTeX.BibTeXEntry): 126 e = obj.entries.copy() 127 e['key'] = obj.key 128 return e 129 else: 130 raise_with_traceback(TypeError("Do not know how to serialize %s"%(obj.__class,))) 131 132 def writePageSet(config, bib, tag): 133 if tag: 134 bib_entries = [b for b in bib.entries 135 if tag in b.get('www_tags', "").split()] 136 else: 137 bib_entries = bib.entries[:] 138 139 if not bib_entries: 140 print("No entries with tag %r; skipping"%tag, file=sys.stderr) 141 return 142 143 tagdir = config.TAG_DIRECTORIES[tag] 144 outdir = os.path.join(config.OUTPUT_DIR, tagdir) 145 cache_url_path = BibTeX.smartJoin("../"*pathLength(tagdir), 146 config.CACHE_DIR) 147 if not os.path.exists(outdir): 148 os.makedirs(outdir, 0o755) 149 ##### Sorted views: 150 151 ## By topic. 152 153 entries = BibTeX.sortEntriesBy(bib_entries, "www_section", "ZZZZZZZZZZZZZZ") 154 entries = BibTeX.splitSortedEntriesBy(entries, "www_section") 155 if entries[-1][0].startswith("<span class='bad'>"): 156 entries[-1] = ("Miscellaneous", entries[-1][1]) 157 158 entries = [(s, BibTeX.sortEntriesByDate(ents)) 159 for s, ents in entries] 160 161 f = open(os.path.join(outdir, "topic.html"), 'w') 162 writeHTML(f, entries, "Topics", "topic", 163 (("By topic", None), 164 ("By date", "./date.html"), 165 ("By author", "./author.html")), 166 tag=tag, config=config, 167 cache_url_path=cache_url_path) 168 f.close() 169 170 ## By date. 171 172 entries = BibTeX.sortEntriesByDate(bib_entries) 173 entries = BibTeX.splitSortedEntriesBy(entries, 'year') 174 for idx in -1, -2: 175 try: 176 if entries[idx][0].startswith("<span class='bad'>"): 177 entries[idx] = ("Unknown", entries[idx][1]) 178 elif entries[idx][0].startswith("forthcoming"): 179 entries[idx] = ("Forthcoming", entries[idx][1]) 180 except IndexError: 181 continue 182 sections = [ent[0] for ent in entries] 183 184 first_year = int(entries[0][1][0]['year']) 185 try: 186 last_year = int(entries[-1][1][0].get('year')) 187 except ValueError: 188 last_year = int(entries[-2][1][0].get('year')) 189 190 years = list(map(str, list(range(first_year, last_year+1)))) 191 if entries[-1][0] == 'Unknown': 192 years.append("Unknown") 193 194 date_file = open(os.path.join(outdir, "date.html"), 'w') 195 writeHTML(date_file, entries, "Years", "date", 196 (("By topic", "./topic.html"), 197 ("By date", None), 198 ("By author", "./author.html")), 199 tag=tag, config=config, 200 cache_url_path=cache_url_path) 201 date_file.close() 202 203 ## By author 204 entries, url_map = BibTeX.splitEntriesByAuthor(bib_entries) 205 206 author_file = open(os.path.join(outdir, "author.html"), 'w') 207 writeHTML(author_file, entries, "Authors", "author", 208 (("By topic", "./topic.html"), 209 ("By date", "./date.html"), 210 ("By author", None),), 211 tag=tag, config=config, 212 cache_url_path=cache_url_path, 213 section_urls=url_map) 214 author_file.close() 215 216 ## The big BibTeX file 217 218 entries = bib_entries[:] 219 entries = [(ent.key, ent) for ent in entries] 220 entries.sort() 221 entries = [ent[1] for ent in entries] 222 223 ## Finding the root directory is done by writeHTML(), but 224 ## the BibTeX file doesn't use that, so repeat the code here 225 root = "../"*pathLength(config.TAG_DIRECTORIES[tag]) 226 if root == "": 227 root = "." 228 229 header, footer = getTemplate(config.BIBTEX_TEMPLATE_FILE) 230 bibtex_file = open(os.path.join(outdir, "bibtex.html"), 'w') 231 print(header%{'command_line' : "", 232 'title': config.TAG_TITLES[tag], 233 'root': root}, 234 file=bibtex_file) 235 for ent in entries: 236 print((("<tr><td class='bibtex'><a name='%s'>%s</a>" 237 "<pre class='bibtex'>%s</pre></td></tr>") 238 % (BibTeX.url_untranslate(ent.key), 239 ent.key, 240 ent.format(90, 8, 1))), 241 file=bibtex_file) 242 print(footer, file=bibtex_file) 243 bibtex_file.close() 244 245 bibtex_json_file = open(os.path.join(outdir, "bibtex.json"), 'w') 246 json.dump(entries, bibtex_json_file, default=jsonDumper) 247 bibtex_json_file.close() 248 249 # Produce NAME with EXTENSION 'bib' as a FILE holding one 250 # bib record. 251 bibdir = config.BIB_DIRECTORY 252 biboutdir = os.path.join(config.OUTPUT_DIR, bibdir) 253 for ent in entries: 254 bib_file_dir = os.path.join(biboutdir, ent.key) 255 if not os.path.exists(bib_file_dir): 256 os.makedirs(bib_file_dir, 0o755) 257 single_bib_file = open(os.path.join(bib_file_dir, 258 "record.bib"), 259 'w') 260 print("%s" % ent.format(90, 8, 1), file=single_bib_file) 261 single_bib_file.close() 262 263 if __name__ == '__main__': 264 if len(sys.argv) == 2: 265 print("Loading from %s"%sys.argv[1]) 266 else: 267 print("Expected a single configuration file as an argument", 268 file=sys.stderr) 269 sys.exit(1) 270 config.load(sys.argv[1]) 271 272 bib = BibTeX.parseFile(config.MASTER_BIB) 273 274 for tag in list(config.TAG_DIRECTORIES.keys()): 275 writePageSet(config, bib, tag)