Skip to content

Commit

Permalink
Initial import
Browse files Browse the repository at this point in the history
  • Loading branch information
vitkyrka committed May 10, 2017
0 parents commit 02f99ca
Show file tree
Hide file tree
Showing 11 changed files with 570 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
@@ -0,0 +1,5 @@
*.pyc
*.swp
*.egg-info
.tox
*.sqlite
58 changes: 58 additions & 0 deletions README.rst
@@ -0,0 +1,58 @@
.. -*- rst -*-
opengrokfs
==========

opengrokfs implement a FUSE filesystem backed by the OpenGrok web interface. A
cscope-clone which uses the OpenGrok web interface as the backend is also
included.

Install with pip::

pip3 install opengrokfs

Run ``opengrokfs`` with the URL of the OpenGrok start page and the local
directory where the filesystem should be mounted::


mkdir -p mnt
opengrokfs http://androidxref.com/7.1.1_r6/ mnt

Now you can access the files::

$ ls mnt/
Android.bp bootable bionic development external
art bootstrap.bash dalvik device frameworks
...

Use ``oggrep`` to search using OpenGrok's "Full Search"::

$ cd mnt/bionic/
mnt/bionic$ oggrep O_LARGEFILE
libc/kernel/uapi/asm-arm/asm/fcntl.h:#define O_LARGEFILE 0400000
libc/kernel/uapi/asm-arm64/asm/fcntl.h:#define O_LARGEFILE 0400000
libc/bionic/lfs64_support.cpp:// are already 64-bit ready. In particular, we don't have non-O_LARGEFILE
libc/bionic/open.cpp: return flags | O_LARGEFILE;
libc/kernel/uapi/asm-mips/asm/fcntl.h:#define O_LARGEFILE 0x2000
libc/kernel/uapi/asm-generic/fcntl.h:#ifndef O_LARGEFILE
libc/kernel/uapi/asm-generic/fcntl.h:#define O_LARGEFILE 00100000
tests/stdlib_test.cpp: ASSERT_EQ(O_LARGEFILE, fcntl(tf.fd, F_GETFL) & O_LARGEFILE);

``ogcscope`` emulates cscope's line-oriented interface but uses OpenGrok as the
backend::

mnt/bionic$ ogcscope -dl
>> 1CLONE_CHILD_SETTID
cscope: 1 lines
libc/kernel/uapi/linux/sched.h <unknown> 41 #define CLONE_CHILD_SETTID 0x01000000
>> 0CLONE_CHILD_SETTID
cscope: 5 lines
libc/bionic/clone.cpp <unknown> 53 if ((flags & (CLONE_PARENT_SETTID|CLONE_SETTLS|CLONE_CHILD_SETTID|CLONE_CHILD_CLEARTID)) != 0) {
libc/bionic/clone.cpp <unknown> 56 if ((flags & (CLONE_SETTLS|CLONE_CHILD_SETTID|CLONE_CHILD_CLEARTID)) != 0) {
libc/bionic/clone.cpp <unknown> 59 if ((flags & (CLONE_CHILD_SETTID|CLONE_CHILD_CLEARTID)) != 0) {
libc/bionic/fork.cpp <unknown> 34 #define FORK_FLAGS (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD)
libc/kernel/uapi/linux/sched.h <unknown> 41 #define CLONE_CHILD_SETTID 0x01000000

``ogcscope`` can be used from within any editor which supports cscope. For example, for ``vim``::

mnt/bionic$ vim -c 'set cscopeprg=ogcscope' -c 'cs add .opengrokfs'
Empty file added opengrokfs/__init__.py
Empty file.
83 changes: 83 additions & 0 deletions opengrokfs/cscope.py
@@ -0,0 +1,83 @@
#!/usr/bin/env python3
import argparse
import cmd
import logging
import sys

from opengrokfs.opengrok import OpenGrok


class OpenGrokCscope(cmd.Cmd):
prompt = '>> '

def __init__(self, opengrok):
super().__init__()
self.opengrok = opengrok

def do_q(self, arg):
return True

def default(self, line):
try:
field = int(line[0])
except ValueError:
print("cscope: unknown command '%s'" % line)
return

q = line[1:]

if field == 0:
params = {'refs': q}
elif field == 1:
params = {'defs': q}
elif field == 4:
params = {'q': q}
elif field == 7:
params = {'path': q}
else:
params = None

results = []
if params:
results = self.opengrok.search(params)

print('cscope: %d lines' % len(results))

for r in results:
function = r.function if r.function else '<unknown>'
line = r.line if r.line else 1
text = r.text if r.text else '<unknown>'

print('%s %s %d %s' % (r.path, function, line, text))


def main():
parser = argparse.ArgumentParser()

parser.add_argument('--debug', action='store_true')
parser.add_argument('--url')
parser.add_argument('--project', action='append')
parser.add_argument('--strip')

# Ignored, for compatibility with cscope
parser.add_argument('-d')
parser.add_argument('-f')
parser.add_argument('-l')

try:
with open('.opengrokfs') as f:
argv = [l.rstrip() for l in f.readlines()]
except FileNotFoundError:
argv = []

args = parser.parse_args(argv + sys.argv[1:])

if args.debug:
logging.basicConfig(level=logging.DEBUG)

og = OpenGrok(args.url, projects=args.project, strip=args.strip)
OpenGrokCscope(og).cmdloop()


if __name__ == '__main__':
main()
44 changes: 44 additions & 0 deletions opengrokfs/grep.py
@@ -0,0 +1,44 @@
#!/usr/bin/env python3
import argparse
import logging
import sys

from opengrokfs.opengrok import OpenGrok


def main():
parser = argparse.ArgumentParser()

parser.add_argument('--debug', action='store_true')
parser.add_argument('--url', required=True)
parser.add_argument('--project', action='append')
parser.add_argument('--strip')

parser.add_argument('-n', '--line-number', action='store_true')
parser.add_argument('pattern')

try:
with open('.opengrokfs') as f:
argv = [l.rstrip() for l in f.readlines()]
except FileNotFoundError:
argv = []

args = parser.parse_args(argv + sys.argv[1:])

if args.debug:
logging.basicConfig(level=logging.DEBUG)

og = OpenGrok(args.url, projects=args.project, strip=args.strip)
results = og.search({'q': args.pattern})

for r in results:
if args.line_number:
print('%s:%d:%s' % (r.path, r.line, r.text))
else:
print('%s:%s' % (r.path, r.text))

sys.exit(0 if results else 1)


if __name__ == '__main__':
main()
133 changes: 133 additions & 0 deletions opengrokfs/opengrok.py
@@ -0,0 +1,133 @@
import urllib.parse

import requests
import dateparser
import attr
from lxml import etree


@attr.s
class File(object):
name = attr.ib()
date = attr.ib()
size = attr.ib()
dir = attr.ib(False)


@attr.s
class Result(object):
path = attr.ib()
function = attr.ib(None)
line = attr.ib(0)
text = attr.ib(None)


class OpenGrok(object):
def __init__(self, url, projects=None, strip=None):
if not url.endswith('/'):
url += '/'
self.url = url
self.base = urllib.parse.urlparse(self.url).path
self.htmlparser = etree.HTMLParser()

self.params = {'n': 10000}
self.projects = projects
if projects:
self.params['project'] = projects

self.strip = strip

def single_project(self):
return self.projects and len(self.projects) == 1 and self.projects[0]

def _text(self, item):
return ''.join(item.itertext())

def search(self, query):
params = dict(self.params)
params.update(query)

page = requests.get(self.url + '/search', params)

tree = etree.fromstring(page.text.encode('utf-8'), self.htmlparser)

if '<title>Search Error</title>' in page.text:
msgp = tree.find('.//div[@id="results"]/p')
msg = msgp.text if msgp is not None else 'Search Error'
raise Exception(msg)

results = []
for tr in tree.findall('.//div[@id="results"]//tr'):
if tr.get('class') == 'dir':
continue

href = tr.find('./td[@class="f"]/a').get('href')
path = href.replace(self.base, '').replace('xref', '')

if self.strip and path.startswith(self.strip):
path = path[len(self.strip):]

anchors = tr.findall('./td/tt/a[@class="s"]')
for a in anchors:
line = int(a[0].text)
text = ''.join(a.itertext())
text = text.replace('%d ' % line, '')

results.append(Result(path=path, line=line, text=text))

if not anchors:
results.append(Result(path=path))

return results

def get(self, path):
page = requests.get(self.url + '/raw/' + path)
return page.text

def parse_size(self, sizetext):
size = float(sizetext.split(' ')[0])
if 'KiB' in sizetext:
# Precision has been lost due to rounding, so just try to
# increase the size and hope nothing breaks
size += 0.1
size *= 1024

return int(size)

def list(self, path='/'):
page = requests.get(self.url + '/xref/' + path + '/')
tree = etree.fromstring(page.text.encode('utf-8'), self.htmlparser)

tbl = tree.find('.//table[@id="dirlist"]')
colmap = dict([(col.text, i)
for i, col
in enumerate(tbl.findall('.//th'))
if col.text])

files = []
for tr in tbl.findall('./tbody/tr'):
tds = tr.findall('./td')

name = self._text(tds[colmap['Name']])
if name.endswith('/'):
name = name[:-1]
directory = True
elif name == '..':
directory = True
else:
directory = False

# Empty directories are folded in newer versions
name = name.split('/')[0]

date = dateparser.parse(self._text(tds[colmap['Date']]))
date = date.replace(hour=0, minute=0, second=0, microsecond=0)

sizetext = self._text(tds[colmap['Size']])
# &nbsp; seems to be converted to \xa0
sizetext = sizetext.replace(',', '.').replace('\xa0', '')
size = self.parse_size(sizetext)

files.append(File(name=name, date=date, size=size, dir=directory))

return files

0 comments on commit 02f99ca

Please sign in to comment.