2015-11-10 08:15:11 +00:00
|
|
|
import codecs
|
2016-04-25 04:42:46 +00:00
|
|
|
from collections import defaultdict
|
2016-04-03 11:30:29 +00:00
|
|
|
from docutils import io
|
2016-03-06 06:23:19 +00:00
|
|
|
from docutils.core import (
|
2016-04-03 11:30:29 +00:00
|
|
|
Publisher,
|
2016-03-06 06:23:19 +00:00
|
|
|
publish_doctree,
|
|
|
|
publish_from_doctree,
|
|
|
|
publish_parts,
|
|
|
|
)
|
2016-04-03 11:30:29 +00:00
|
|
|
from docutils.readers.doctree import Reader
|
2015-11-10 08:15:11 +00:00
|
|
|
from flask import (
|
|
|
|
abort,
|
|
|
|
g,
|
|
|
|
make_response,
|
|
|
|
redirect,
|
|
|
|
render_template,
|
|
|
|
render_template_string,
|
|
|
|
request,
|
|
|
|
safe_join,
|
|
|
|
url_for,
|
|
|
|
)
|
|
|
|
import os.path
|
|
|
|
|
2016-04-03 11:30:29 +00:00
|
|
|
from i2p2www import PROPOSAL_DIR, SPEC_DIR
|
2015-11-10 08:15:11 +00:00
|
|
|
from i2p2www import helpers
|
|
|
|
|
|
|
|
|
|
|
|
SPEC_METATAGS = {
|
|
|
|
'accuratefor': None,
|
2016-04-01 23:28:07 +00:00
|
|
|
'category': '',
|
2015-11-10 08:15:11 +00:00
|
|
|
'lastupdated': None,
|
|
|
|
}
|
|
|
|
SPEC_LIST_METATAGS = [
|
|
|
|
]
|
2016-04-25 04:42:46 +00:00
|
|
|
SPEC_CATEGORY_SORT = defaultdict(lambda: 999, {
|
2016-04-01 23:28:07 +00:00
|
|
|
'Design': 1,
|
|
|
|
'Transports': 2,
|
|
|
|
'Protocols': 3,
|
2022-01-28 10:57:52 -05:00
|
|
|
'Formats': 4,
|
2016-04-25 04:42:46 +00:00
|
|
|
})
|
2015-11-10 08:15:11 +00:00
|
|
|
|
2016-04-03 11:30:29 +00:00
|
|
|
PROPOSAL_METATAGS = {
|
|
|
|
'author': u'I2P devs',
|
|
|
|
'created': None,
|
2017-04-07 10:34:35 +00:00
|
|
|
'editor': None,
|
2016-04-25 04:42:46 +00:00
|
|
|
'implementedin': None,
|
2016-04-03 11:30:29 +00:00
|
|
|
'lastupdated': None,
|
|
|
|
'status': u'Draft',
|
2016-04-10 07:17:19 +00:00
|
|
|
'supercededby': None,
|
|
|
|
'supercedes': None,
|
2016-04-25 04:42:46 +00:00
|
|
|
'target': None,
|
2016-04-03 11:30:29 +00:00
|
|
|
'thread': None,
|
|
|
|
}
|
|
|
|
PROPOSAL_LIST_METATAGS = [
|
2016-04-10 07:17:19 +00:00
|
|
|
'supercedes',
|
2016-04-03 11:30:29 +00:00
|
|
|
]
|
2016-04-25 04:42:46 +00:00
|
|
|
PROPOSAL_STATUS_SORT = defaultdict(lambda: 999, {
|
|
|
|
'Open': 1,
|
|
|
|
'Accepted': 2,
|
|
|
|
'Finished': 3,
|
|
|
|
'Closed': 90,
|
2016-04-04 12:50:16 +00:00
|
|
|
'Rejected': 100,
|
2016-04-25 04:42:46 +00:00
|
|
|
'Draft': 10,
|
|
|
|
'Needs-Revision': 11,
|
|
|
|
'Dead': 20,
|
|
|
|
'Needs-Research': 15,
|
|
|
|
'Meta': 0,
|
|
|
|
'Reserve': 50,
|
|
|
|
'Informational': 80,
|
|
|
|
})
|
2015-11-10 08:15:11 +00:00
|
|
|
|
2016-04-03 11:30:29 +00:00
|
|
|
METATAG_LABELS = {
|
|
|
|
'accuratefor': u'Accurate for',
|
|
|
|
'author': u'Author',
|
|
|
|
'category': u'Category',
|
|
|
|
'created': u'Created',
|
2017-04-07 10:34:35 +00:00
|
|
|
'editor': u'Editor',
|
2016-04-25 04:42:46 +00:00
|
|
|
'implementedin': u'Implemented in',
|
2016-04-03 11:30:29 +00:00
|
|
|
'lastupdated': u'Last updated',
|
|
|
|
'status': u'Status',
|
2016-04-10 07:17:19 +00:00
|
|
|
'supercededby': u'Superceded by',
|
2016-04-10 07:20:55 +00:00
|
|
|
'supercedes': u'Supercedes',
|
2016-04-25 04:42:46 +00:00
|
|
|
'target': u'Target',
|
2016-04-03 11:30:29 +00:00
|
|
|
'thread': u'Thread',
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
def get_rsts(directory, meta_parser):
|
|
|
|
rsts = []
|
|
|
|
for f in os.listdir(directory):
|
2015-11-10 08:15:11 +00:00
|
|
|
if f.endswith('.rst'):
|
2016-04-03 11:30:29 +00:00
|
|
|
path = safe_join(directory, f)
|
2015-11-25 01:45:01 +00:00
|
|
|
# read file header
|
|
|
|
header = ''
|
2015-11-10 08:15:11 +00:00
|
|
|
with codecs.open(path, encoding='utf-8') as fd:
|
2015-11-25 01:45:01 +00:00
|
|
|
for line in fd:
|
|
|
|
header += line
|
|
|
|
if not line.strip():
|
|
|
|
break
|
2016-04-03 11:30:29 +00:00
|
|
|
parts = publish_parts(source=header, source_path=directory, writer_name="html")
|
|
|
|
meta = meta_parser(parts['meta'])
|
2015-11-10 08:15:11 +00:00
|
|
|
|
2016-04-03 11:30:29 +00:00
|
|
|
rst = {
|
2015-11-10 08:15:11 +00:00
|
|
|
'name': f[:-4],
|
|
|
|
'title': parts['title'],
|
|
|
|
}
|
2016-04-03 11:30:29 +00:00
|
|
|
rst.update(meta)
|
|
|
|
rsts.append(rst)
|
|
|
|
return rsts
|
2015-11-10 08:15:11 +00:00
|
|
|
|
2016-04-03 11:30:29 +00:00
|
|
|
def spec_index():
|
|
|
|
specs = get_rsts(SPEC_DIR, spec_meta)
|
2016-04-01 23:28:07 +00:00
|
|
|
specs.sort(key=lambda s: (SPEC_CATEGORY_SORT[s['category']], s['title']))
|
2015-11-10 08:15:11 +00:00
|
|
|
return render_template('spec/index.html', specs=specs)
|
|
|
|
|
2016-04-03 11:30:29 +00:00
|
|
|
def proposal_index():
|
|
|
|
proposals = get_rsts(PROPOSAL_DIR, proposal_meta)
|
|
|
|
for i in range(0, len(proposals)):
|
|
|
|
proposals[i]['num'] = int(proposals[i]['name'][:3])
|
|
|
|
proposals.sort(key=lambda s: (PROPOSAL_STATUS_SORT[s['status']], s['num']))
|
|
|
|
return render_template('spec/proposal-index.html', proposals=proposals)
|
|
|
|
|
2018-03-03 14:45:34 +00:00
|
|
|
def proposal_number(number):
|
|
|
|
proposals = get_rsts(PROPOSAL_DIR, proposal_meta)
|
|
|
|
for proposal in proposals:
|
|
|
|
if int(proposal['name'][:3]) == number:
|
|
|
|
return proposal_show(proposal['name'])
|
|
|
|
else:
|
|
|
|
abort(404)
|
|
|
|
|
2016-04-03 11:30:29 +00:00
|
|
|
def render_rst(directory, name, meta_parser, template):
|
2015-11-10 08:15:11 +00:00
|
|
|
# check if that file actually exists
|
2016-04-03 11:30:29 +00:00
|
|
|
path = safe_join(directory, name + '.rst')
|
2015-11-10 08:15:11 +00:00
|
|
|
if not os.path.exists(path):
|
|
|
|
abort(404)
|
|
|
|
|
|
|
|
# read file
|
|
|
|
with codecs.open(path, encoding='utf-8') as fd:
|
|
|
|
content = fd.read()
|
|
|
|
|
2016-04-03 11:30:29 +00:00
|
|
|
if not template:
|
2015-11-10 08:15:11 +00:00
|
|
|
# Strip out RST
|
|
|
|
content = content.replace('.. meta::\n', '')
|
2016-03-06 06:23:19 +00:00
|
|
|
content = content.replace('.. contents::\n\n', '')
|
2015-11-10 08:15:11 +00:00
|
|
|
content = content.replace('.. raw:: html\n\n', '')
|
|
|
|
content = content.replace('\n.. [', '\n[')
|
2015-11-14 20:41:05 +00:00
|
|
|
content = content.replace(']_.', '].')
|
2016-04-25 04:42:46 +00:00
|
|
|
content = content.replace(']_,', '],')
|
2015-11-14 00:07:25 +00:00
|
|
|
content = content.replace(']_', '] ')
|
2015-11-10 08:15:11 +00:00
|
|
|
# Change highlight formatter
|
|
|
|
content = content.replace('{% highlight', "{% highlight formatter='textspec'")
|
2016-04-03 11:30:29 +00:00
|
|
|
# Metatags
|
|
|
|
for (metatag, label) in METATAG_LABELS.items():
|
|
|
|
content = content.replace(' :%s' % metatag, label)
|
2015-11-10 08:15:11 +00:00
|
|
|
|
|
|
|
# render the post with Jinja2 to handle URLs etc.
|
|
|
|
rendered_content = render_template_string(content)
|
|
|
|
rendered_content = rendered_content.replace('</pre></div>', ' </pre></div>')
|
|
|
|
|
2016-04-03 11:30:29 +00:00
|
|
|
if not template:
|
2015-11-10 08:15:11 +00:00
|
|
|
# Send response
|
|
|
|
r = make_response(rendered_content)
|
|
|
|
r.mimetype = 'text/plain'
|
|
|
|
return r
|
|
|
|
|
2016-03-06 06:23:19 +00:00
|
|
|
# Render the ToC
|
|
|
|
doctree = publish_doctree(source=rendered_content)
|
|
|
|
bullet_list = doctree[1][1]
|
|
|
|
doctree.clear()
|
|
|
|
doctree.append(bullet_list)
|
2016-04-03 11:30:29 +00:00
|
|
|
reader = Reader(parser_name='null')
|
|
|
|
pub = Publisher(reader, None, None,
|
|
|
|
source=io.DocTreeInput(doctree),
|
|
|
|
destination_class=io.StringOutput)
|
|
|
|
pub.set_writer('html')
|
|
|
|
pub.publish()
|
|
|
|
toc = pub.writer.parts['fragment']
|
2016-03-06 06:23:19 +00:00
|
|
|
|
|
|
|
# Remove the ToC from the main document
|
|
|
|
rendered_content = rendered_content.replace('.. contents::\n', '')
|
|
|
|
|
|
|
|
# publish the spec with docutils
|
2016-04-03 11:30:29 +00:00
|
|
|
parts = publish_parts(source=rendered_content, source_path=directory, writer_name="html")
|
|
|
|
meta = meta_parser(parts['meta'])
|
2016-04-10 06:49:27 +00:00
|
|
|
|
|
|
|
if (directory == PROPOSAL_DIR):
|
|
|
|
meta['num'] = int(name[:3])
|
2015-11-10 08:15:11 +00:00
|
|
|
|
2016-04-03 11:30:29 +00:00
|
|
|
return render_template(template, title=parts['title'], toc=toc, body=parts['fragment'], name=name, meta=meta)
|
|
|
|
|
|
|
|
def spec_show(name):
|
|
|
|
return render_rst(SPEC_DIR, name, spec_meta, 'spec/show.html')
|
2015-11-10 08:15:11 +00:00
|
|
|
|
|
|
|
def spec_show_txt(name):
|
2016-04-03 11:30:29 +00:00
|
|
|
return render_rst(SPEC_DIR, name, spec_meta, None)
|
|
|
|
|
|
|
|
def proposal_show(name):
|
|
|
|
return render_rst(PROPOSAL_DIR, name, proposal_meta, 'spec/proposal-show.html')
|
2015-11-10 08:15:11 +00:00
|
|
|
|
2016-04-03 11:30:29 +00:00
|
|
|
def proposal_show_txt(name):
|
|
|
|
return render_rst(PROPOSAL_DIR, name, proposal_meta, None)
|
|
|
|
|
|
|
|
def spec_meta(meta):
|
2015-11-10 08:15:11 +00:00
|
|
|
return helpers.get_metadata_from_meta(meta, SPEC_METATAGS, SPEC_LIST_METATAGS)
|
2016-04-03 11:30:29 +00:00
|
|
|
|
|
|
|
def proposal_meta(meta):
|
|
|
|
return helpers.get_metadata_from_meta(meta, PROPOSAL_METATAGS, PROPOSAL_LIST_METATAGS)
|