6213e7c183
* stable-2.16: FakeGroupAuditService: Make auditEvents final ErrorProne: Increase severity of MutableConstantField to ERROR ConfigUpdatedEvent: Use immutable type in field declaration Add missing slf4j dependencies in BUILD file JGitMetricModule: fix WindowCache miss ration which wasn't reported Revert "JGitMetricModule: Replace anonymous Supplier instances with method references" Suppress generic logging on docker start for ElasticSearch container Replace deprecated OptionParser with ArgumentParser Change-Id: I36a7ce5c043bd43d90fb415fcec67440db2b5c84
315 lines
9.4 KiB
Python
Executable File
315 lines
9.4 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# coding=utf-8
|
|
# Copyright (C) 2013 The Android Open Source Project
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import argparse
|
|
import re
|
|
import sys
|
|
|
|
PAT_GERRIT = re.compile(r'^GERRIT')
|
|
PAT_INCLUDE = re.compile(r'^(include::.*)(\[\])$')
|
|
PAT_GET = re.compile(r'^get::([^ \t\n]*)')
|
|
PAT_TITLE = re.compile(r'^\.(.*)')
|
|
PAT_STARS = re.compile(r'^\*\*\*\*')
|
|
PAT_SEARCHBOX = re.compile(r'^SEARCHBOX')
|
|
|
|
GERRIT_UPLINK = """
|
|
|
|
++++
|
|
<hr style=\"
|
|
height: 2px;
|
|
color: silver;
|
|
margin-top: 1.2em;
|
|
margin-bottom: 0.5em;
|
|
\">
|
|
++++
|
|
|
|
"""
|
|
|
|
GET_TITLE = '<div class="title">%s</div>'
|
|
|
|
GET_MACRO = """
|
|
|
|
++++
|
|
<div class="listingblock">
|
|
%s
|
|
<div class="content">
|
|
<a id=\"{0}\" onmousedown="javascript:
|
|
var i = document.URL.lastIndexOf(\'/Documentation/\');
|
|
var url = document.URL.substring(0, i) + \'{0}\';
|
|
document.getElementById(\'{0}\').href = url;">
|
|
GET {0} HTTP/1.0
|
|
</a>
|
|
</div>
|
|
</div>
|
|
++++
|
|
|
|
"""
|
|
|
|
SEARCH_BOX = """
|
|
|
|
++++
|
|
<div style="
|
|
position:fixed;
|
|
top:0px;
|
|
right:0px;
|
|
text-align:
|
|
right;
|
|
padding-top:2px;
|
|
padding-right:0.5em;
|
|
padding-bottom:2px;">
|
|
<input size="40"
|
|
style="line-height: 0.75em;font-size: 0.75em;"
|
|
id="docSearch"
|
|
type="text">
|
|
<button style="
|
|
background:none!important;
|
|
border:none;
|
|
padding:0!important;
|
|
vertical-align:bottom;
|
|
font-family:'Open Sans','DejaVu Sans',sans-serif;
|
|
font-size:0.8em;
|
|
color:#1d4b8f;
|
|
text-decoration:none;"
|
|
type="button"
|
|
id="searchBox">
|
|
Search
|
|
</button>
|
|
%s
|
|
</div>
|
|
++++
|
|
"""
|
|
|
|
BUILTIN_SEARCH = """
|
|
<script type="text/javascript">
|
|
var f = function() {
|
|
window.location = '../#/Documentation/q/' +
|
|
encodeURIComponent(document.getElementById("docSearch").value);
|
|
}
|
|
document.getElementById("searchBox").onclick = f;
|
|
document.getElementById("docSearch").onkeypress = function(e) {
|
|
if (13 == (e.keyCode ? e.keyCode : e.which)) {
|
|
f();
|
|
}
|
|
}
|
|
</script>
|
|
"""
|
|
|
|
GOOGLE_SITE_SEARCH = """
|
|
<script type="text/javascript">
|
|
var f = function() {
|
|
window.location = 'https://www.google.com/search?q=' +
|
|
encodeURIComponent(document.getElementById("docSearch").value +
|
|
' site:@SITE@');
|
|
}
|
|
document.getElementById("searchBox").onclick = f;
|
|
document.getElementById("docSearch").onkeypress = function(e) {
|
|
if (13 == (e.keyCode ? e.keyCode : e.which)) {
|
|
f();
|
|
}
|
|
}
|
|
</script>
|
|
"""
|
|
|
|
|
|
LINK_SCRIPT = """
|
|
|
|
++++
|
|
<script type="text/javascript">
|
|
decorate(document.getElementsByTagName('h1'));
|
|
decorate(document.getElementsByTagName('h2'));
|
|
decorate(document.getElementsByTagName('h3'));
|
|
decorate(document.getElementsByTagName('h4'));
|
|
|
|
var divs = document.getElementsByTagName('div');
|
|
var arr = new Array();
|
|
var excluded = getExcludedIds();
|
|
for(var i = 0; i < divs.length; i++) {
|
|
var d = divs[i];
|
|
var id = d.getAttribute('id');
|
|
if (id != null && !(id in excluded)) {
|
|
arr[arr.length] = d;
|
|
}
|
|
}
|
|
decorate(arr);
|
|
|
|
var anchors = document.getElementsByTagName('a');
|
|
arr = new Array();
|
|
for(var i = 0; i < anchors.length; i++) {
|
|
var a = anchors[i];
|
|
// if the anchor has no id there is no target to
|
|
// which we can link
|
|
if (a.getAttribute('id') != null) {
|
|
// if the anchor is empty there is no content which
|
|
// can receive the mouseover event, an empty anchor
|
|
// applies to the element that follows, move the
|
|
// element that follows into the anchor so that there
|
|
// is content which can receive the mouseover event
|
|
if (a.firstChild == null) {
|
|
var next = a.nextSibling;
|
|
if (next != null) {
|
|
next.parentNode.removeChild(next);
|
|
a.appendChild(next);
|
|
}
|
|
}
|
|
arr[arr.length] = a;
|
|
}
|
|
}
|
|
decorate(arr);
|
|
|
|
function decorate(e) {
|
|
for(var i = 0; i < e.length; i++) {
|
|
e[i].onmouseover = function (evt) {
|
|
var element = this;
|
|
// do nothing if the link icon is currently showing
|
|
var a = element.firstChild;
|
|
if (a != null && a instanceof Element
|
|
&& a.getAttribute('id') == 'LINK') {
|
|
return;
|
|
}
|
|
|
|
// if there is no id there is no target to link to
|
|
var id = element.getAttribute('id');
|
|
if (id == null) {
|
|
return;
|
|
}
|
|
|
|
// create and show a link icon that links to this element
|
|
a = document.createElement('a');
|
|
a.setAttribute('id', 'LINK');
|
|
a.setAttribute('href', '#' + id);
|
|
a.setAttribute('style', 'position: absolute;'
|
|
+ ' left: ' + (element.offsetLeft - 16 - 2 * 4) + 'px;'
|
|
+ ' padding-left: 4px; padding-right: 4px;');
|
|
var span = document.createElement('span');
|
|
span.setAttribute('style', 'height: ' + element.offsetHeight + 'px;'
|
|
+ ' display: inline-block; vertical-align: baseline;'
|
|
+ ' font-size: 16px; text-decoration: none; color: grey;');
|
|
a.appendChild(span);
|
|
var link = document.createTextNode('🔗');
|
|
span.appendChild(link);
|
|
element.insertBefore(a, element.firstChild);
|
|
|
|
// remove the link icon when the mouse is moved away,
|
|
// but keep it shown if the mouse is over the element, the link or
|
|
// the icon
|
|
hide = function(evt) {
|
|
if (document.elementFromPoint(evt.clientX, evt.clientY) != element
|
|
&& document.elementFromPoint(evt.clientX, evt.clientY) != a
|
|
&& document.elementFromPoint(evt.clientX, evt.clientY) != span
|
|
&& document.elementFromPoint(evt.clientX, evt.clientY) != link
|
|
&& element.contains(a)) {
|
|
element.removeChild(a);
|
|
}
|
|
}
|
|
element.onmouseout = hide;
|
|
a.onmouseout = hide;
|
|
span.onmouseout = hide;
|
|
link.onmouseout = hide;
|
|
}
|
|
}
|
|
}
|
|
|
|
function getExcludedIds() {
|
|
var excluded = {};
|
|
excluded['header'] = true;
|
|
excluded['toc'] = true;
|
|
excluded['toctitle'] = true;
|
|
excluded['content'] = true;
|
|
excluded['preamble'] = true;
|
|
excluded['footer'] = true;
|
|
excluded['footer-text'] = true;
|
|
return excluded;
|
|
}
|
|
</script>
|
|
|
|
++++
|
|
|
|
"""
|
|
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('-o', '--out', help='output file')
|
|
parser.add_argument('-s', '--src', help='source file')
|
|
parser.add_argument('-x', '--suffix', help='suffix for included filenames')
|
|
parser.add_argument('-b', '--searchbox', action="store_true", default=True,
|
|
help="generate the search boxes")
|
|
parser.add_argument('--no-searchbox', action="store_false", dest='searchbox',
|
|
help="don't generate the search boxes")
|
|
parser.add_argument('--site-search', action="store", metavar="SITE",
|
|
help=("generate the search box using google. SITE should " +
|
|
"point to the domain/path of the site, eg. " +
|
|
"gerrit-review.googlesource.com/Documentation"))
|
|
args = parser.parse_args()
|
|
|
|
if args.site_search:
|
|
SEARCH_BOX = (SEARCH_BOX %
|
|
GOOGLE_SITE_SEARCH.replace("@SITE@", args.site_search))
|
|
else:
|
|
SEARCH_BOX = SEARCH_BOX % BUILTIN_SEARCH
|
|
|
|
|
|
try:
|
|
try:
|
|
out_file = open(args.out, 'w', errors='ignore')
|
|
src_file = open(args.src, 'r', errors='ignore')
|
|
except TypeError:
|
|
out_file = open(args.out, 'w')
|
|
src_file = open(args.src, 'r')
|
|
last_line = ''
|
|
ignore_next_line = False
|
|
last_title = ''
|
|
for line in src_file:
|
|
if PAT_GERRIT.match(last_line):
|
|
# Case of "GERRIT\n------" at the footer
|
|
out_file.write(GERRIT_UPLINK)
|
|
last_line = ''
|
|
elif PAT_SEARCHBOX.match(last_line):
|
|
# Case of 'SEARCHBOX\n---------'
|
|
if args.searchbox:
|
|
out_file.write(SEARCH_BOX)
|
|
last_line = ''
|
|
elif PAT_INCLUDE.match(line):
|
|
# Case of 'include::<filename>'
|
|
match = PAT_INCLUDE.match(line)
|
|
out_file.write(last_line)
|
|
last_line = match.group(1) + args.suffix + match.group(2) + '\n'
|
|
elif PAT_STARS.match(line):
|
|
if PAT_TITLE.match(last_line):
|
|
# Case of the title in '.<title>\n****\nget::<url>\n****'
|
|
match = PAT_TITLE.match(last_line)
|
|
last_title = GET_TITLE % match.group(1)
|
|
else:
|
|
out_file.write(last_line)
|
|
last_title = ''
|
|
elif PAT_GET.match(line):
|
|
# Case of '****\nget::<url>\n****' in rest api
|
|
url = PAT_GET.match(line).group(1)
|
|
out_file.write(GET_MACRO.format(url) % last_title)
|
|
ignore_next_line = True
|
|
elif ignore_next_line:
|
|
# Handle the trailing '****' of the 'get::' case
|
|
last_line = ''
|
|
ignore_next_line = False
|
|
else:
|
|
out_file.write(last_line)
|
|
last_line = line
|
|
out_file.write(last_line)
|
|
out_file.write(LINK_SCRIPT)
|
|
out_file.close()
|
|
except IOError as err:
|
|
sys.stderr.write(
|
|
"error while expanding %s to %s: %s" % (args.src, args.out, err))
|
|
exit(1)
|