332 lines
9.8 KiB
Python
Executable file
332 lines
9.8 KiB
Python
Executable file
#!/usr/bin/python3
|
|
|
|
# This file is part of Elixir, a source code cross-referencer.
|
|
#
|
|
# Copyright (C) 2017 Mikaël Bouillot
|
|
# <mikael.bouillot@free-electrons.com>
|
|
#
|
|
# Elixir is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# Elixir is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with Elixir. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
from io import StringIO
|
|
|
|
realprint = print
|
|
outputBuffer = StringIO()
|
|
|
|
def print (arg, end='\n'):
|
|
global outputBuffer
|
|
outputBuffer.write (arg + end)
|
|
|
|
# enable debugging
|
|
import cgitb
|
|
cgitb.enable()
|
|
|
|
import cgi
|
|
import os
|
|
from re import search, sub
|
|
from collections import OrderedDict
|
|
|
|
ident = ''
|
|
status = 200
|
|
|
|
m = search ('^/([^/]*)/([^/]*)/([^/]*)(.*)$', os.environ['SCRIPT_URL'])
|
|
if m:
|
|
project = m.group (1)
|
|
version = m.group (2)
|
|
cmd = m.group (3)
|
|
arg = m.group (4)
|
|
if not (project and search ('^[A-Za-z0-9-]+$', project)) \
|
|
or not (version and search ('^[A-Za-z0-9._-]+$', version)):
|
|
status = 302
|
|
location = '/linux/latest/'+cmd+arg
|
|
cmd = ''
|
|
if cmd == 'source':
|
|
path = arg
|
|
if len (path) > 0 and path[-1] == '/':
|
|
path = path[:-1]
|
|
status = 301
|
|
location = '/'+project+'/'+version+'/source'+path
|
|
else:
|
|
mode = 'source'
|
|
if not search ('^[A-Za-z0-9_/.,+-]*$', path):
|
|
path = 'INVALID'
|
|
url = 'source'+path
|
|
elif cmd == 'ident':
|
|
ident = arg[1:]
|
|
form = cgi.FieldStorage()
|
|
ident2 = form.getvalue ('i')
|
|
if ident == '' and ident2:
|
|
status = 302
|
|
location = '/'+project+'/'+version+'/ident/'+ident2
|
|
else:
|
|
mode = 'ident'
|
|
if not (ident and search ('^[A-Za-z0-9_-]*$', ident)):
|
|
ident = ''
|
|
url = 'ident/'+ident
|
|
else:
|
|
status = 404
|
|
|
|
if status == 301:
|
|
realprint ('Status: 301 Moved Permanently')
|
|
realprint ('Location: '+location+'\n')
|
|
exit()
|
|
elif status == 302:
|
|
realprint ('Status: 302 Found')
|
|
realprint ('Location: '+location+'\n')
|
|
exit()
|
|
elif status == 404:
|
|
realprint ('Status: 404 Not Found\n')
|
|
exit()
|
|
|
|
basedir = os.environ['LXR_PROJ_DIR']
|
|
os.environ['LXR_DATA_DIR'] = basedir + '/' + project + '/data';
|
|
os.environ['LXR_REPO_DIR'] = basedir + '/' + project + '/repo';
|
|
|
|
projects = []
|
|
for (dirpath, dirnames, filenames) in os.walk (basedir):
|
|
projects.extend (dirnames)
|
|
break
|
|
|
|
import sys
|
|
sys.path = [ sys.path[0] + '/..' ] + sys.path
|
|
import query
|
|
|
|
def do_query (*args):
|
|
cwd = os.getcwd()
|
|
os.chdir ('..')
|
|
a = query.query (*args)
|
|
os.chdir (cwd)
|
|
|
|
# decode('ascii') fails on special chars
|
|
# FIXME: major hack until we handle everything as bytestrings
|
|
try:
|
|
a = a.decode ('utf-8')
|
|
except UnicodeDecodeError:
|
|
a = a.decode ('iso-8859-1')
|
|
a = a.split ('\n')
|
|
del a[-1]
|
|
return a
|
|
|
|
if version == 'latest':
|
|
tag = do_query ('latest')[0]
|
|
else:
|
|
tag = version
|
|
|
|
data = {
|
|
'baseurl': 'http://' + os.environ['HTTP_HOST'] + '/' + project + '/',
|
|
'tag': tag,
|
|
'version': version,
|
|
'url': url,
|
|
'projects': projects,
|
|
}
|
|
|
|
lines = do_query ('versions')
|
|
va = OrderedDict()
|
|
for l in lines:
|
|
m = search ('^([^ ]*) ([^ ]*) ([^ ]*)$', l)
|
|
if not m:
|
|
continue
|
|
m1 = m.group(1)
|
|
m2 = m.group(2)
|
|
l = m.group(3)
|
|
|
|
if m1 not in va:
|
|
va[m1] = OrderedDict()
|
|
if m2 not in va[m1]:
|
|
va[m1][m2] = []
|
|
va[m1][m2].append (l)
|
|
|
|
v = ''
|
|
b = 1
|
|
for v1k in va:
|
|
v1v = va[v1k]
|
|
v += '<li>\n'
|
|
v += '\t<span>'+v1k+'</span>\n'
|
|
v += '\t<ul>\n'
|
|
b += 1
|
|
for v2k in v1v:
|
|
v2v = v1v[v2k]
|
|
if v2k == v2v[0]:
|
|
if v2k == tag: v += '\t\t<li class="li-link active"><a href="'+v2k+'/'+url+'">'+v2k+'</a></li>\n'
|
|
else: v += '\t\t<li class="li-link"><a href="'+v2k+'/'+url+'">'+v2k+'</a></li>\n'
|
|
else:
|
|
v += '\t\t<li>\n'
|
|
v += '\t\t\t<span>'+v2k+'</span>\n'
|
|
v += '\t\t\t<ul>\n'
|
|
for v3 in v2v:
|
|
if v3 == tag: v += '\t\t\t\t<li class="li-link active"><a href="'+v3+'/'+url+'">'+v3+'</a></li>\n'
|
|
else: v += '\t\t\t\t<li class="li-link"><a href="'+v3+'/'+url+'">'+v3+'</a></li>\n'
|
|
v += '\t\t\t</ul></li>\n'
|
|
v += '\t</ul></li>\n'
|
|
|
|
data['versions'] = v
|
|
|
|
if mode == 'source':
|
|
breadcrumb = '<a href="'+version+'/source">'+project+'</a>'
|
|
p2 = ''
|
|
p3 = path.split ('/') [1:]
|
|
for p in p3:
|
|
p2 += '/'+p
|
|
breadcrumb += '/<a href="'+version+'/source'+p2+'">'+p+'</a>'
|
|
|
|
data['breadcrumb'] = breadcrumb
|
|
data['ident'] = ident
|
|
data['title'] = project+path+' - Elixir - Free Electrons'
|
|
|
|
lines = ['null - -']
|
|
|
|
type = do_query ('type', tag, path)
|
|
if len (type) == 1:
|
|
type = type[0]
|
|
if type == 'tree':
|
|
lines += do_query ('dir', tag, path)
|
|
elif type == 'blob':
|
|
lines += do_query ('file', tag, path)
|
|
else:
|
|
print ('<br><b>This file does not exist.</b>')
|
|
status = 404
|
|
|
|
if type == 'tree':
|
|
if path != '':
|
|
lines[0] = 'back - -'
|
|
|
|
print ('<table>\n')
|
|
for l in lines:
|
|
type, name, size = l.split (' ')
|
|
|
|
if type == 'null':
|
|
continue
|
|
elif type == 'tree':
|
|
icon = 'folder.gif'
|
|
size = ''
|
|
path2 = path+'/'+name
|
|
name = name
|
|
elif type == 'blob':
|
|
icon = 'text.gif'
|
|
size = size+' bytes'
|
|
path2 = path+'/'+name
|
|
elif type == 'back':
|
|
icon = 'back.gif'
|
|
size = ''
|
|
path2 = os.path.dirname (path[:-1])
|
|
if path2 == '/': path2 = ''
|
|
name = 'Parent directory'
|
|
|
|
print (' <tr>')
|
|
print (' <td><a href="'+version+'/source'+path2+'"><img src="/icons/'+icon+'" width="20" height="22" border="0" alt="'+icon+'"/></a></td>')
|
|
print (' <td><a href="'+version+'/source'+path2+'">'+name+'</a></td>')
|
|
print (' <td>'+size+'</td>')
|
|
|
|
print (' </tr>\n')
|
|
|
|
print ('</table>', end='')
|
|
|
|
elif type == 'blob':
|
|
del (lines[0])
|
|
|
|
print ('<div id="lxrcode">')
|
|
print ('<table><tr><td><pre>')
|
|
|
|
width1 = len (str (len (lines)))
|
|
num = 1
|
|
width2 = len (str (num))
|
|
space = ' ' * (width1 - width2)
|
|
for l in lines:
|
|
print (' '+space+'<a name="L'+str(num)+'" href="'+version+'/source'+path+'#L'+str(num)+'">'+str(num)+'</a> ')
|
|
num += 1
|
|
width2 = len (str (num))
|
|
space = ' ' * (width1 - width2)
|
|
|
|
print ('</pre></td><td><pre>')
|
|
|
|
for l in lines:
|
|
l = cgi.escape (l)
|
|
l = sub ('"', '"', l)
|
|
l = sub ('\033\[31m(.*?)\033\[0m', '<a href="'+version+'/ident/\\1">\\1</a>', l)
|
|
l = sub ('\033\[32m', '', l)
|
|
l = sub ('\033\[33m', '', l)
|
|
l = sub ('\033\[0m', '', l)
|
|
print (l)
|
|
|
|
print ('</pre></td></tr></table>')
|
|
print ('</div>', end='')
|
|
|
|
|
|
elif mode == 'ident':
|
|
field = '</h1>\n<form method="get" action="'+version+'/ident">\nIdentifier: <input type="text" name="i" value="'+ident+'"size="60"/>\n<input type="submit" value="Go get it"/>\n</form>\n<h1>' + ident
|
|
data['breadcrumb'] = field
|
|
data['title'] = ident+' - Elixir - Free Electrons'
|
|
|
|
lines = do_query ('ident', tag, ident)
|
|
lines = iter (lines)
|
|
|
|
m = search ('Defined in (\d*) file', next (lines))
|
|
if m:
|
|
num = int (m.group(1))
|
|
if num == 0:
|
|
status = 404
|
|
|
|
print ('Defined in '+str(num)+' files:')
|
|
print ('<ul>')
|
|
for i in range (0, num):
|
|
l = next (lines)
|
|
m = search ('^(.*): (\d*) \((.*)\)$', l)
|
|
f, n, t = m.groups()
|
|
print ('<li><a href="'+version+'/source/'+f+'#L'+n+'">'+f+', line '+n+' (as a '+t+')</a>', end='')
|
|
print ('</ul>')
|
|
|
|
next (lines)
|
|
|
|
m = search ('Referenced in (\d*) file', next (lines))
|
|
num = int (m.group(1))
|
|
|
|
print ('Referenced in '+str(num)+' files:')
|
|
print ('<ul>')
|
|
for i in range (0, num):
|
|
l = next (lines)
|
|
m = search ('^(.*): (.*)$', l)
|
|
f = m.group (1)
|
|
ln = m.group (2).split (',')
|
|
if len (ln) == 1:
|
|
n = ln[0]
|
|
print ('<li><a href="'+version+'/source/'+f+'#L'+str(n)+'">'+f+', line '+str(n)+'</a>', end='')
|
|
else:
|
|
if num > 100: # Concise display
|
|
n = len (ln)
|
|
print ('<li><a href="'+version+'/source/'+f+'">'+f+'</a>, '+str(n)+' times')
|
|
else: # Verbose display
|
|
print ('<li>'+f)
|
|
print ('<ul>')
|
|
for n in ln:
|
|
print ('<li><a href="'+version+'/source/'+f+'#L'+str(n)+'">line '+str(n)+'</a>')
|
|
print ('</ul>')
|
|
print ('</ul>')
|
|
else:
|
|
if ident != '':
|
|
print ('<br><b>Not used</b>')
|
|
status = 404
|
|
|
|
else:
|
|
print ('Invalid request')
|
|
|
|
if status == 404:
|
|
realprint ('Status: 404 Not Found')
|
|
|
|
import jinja2
|
|
loader = jinja2.FileSystemLoader (os.path.join (os.path.dirname (__file__), '../templates/'))
|
|
environment = jinja2.Environment (loader=loader)
|
|
template = environment.get_template ('layout.html')
|
|
|
|
realprint ('Content-Type: text/html;charset=utf-8\n')
|
|
data['main'] = outputBuffer.getvalue()
|
|
realprint (template.render(data), end='')
|