Blame pagure/perfrepo.py

Patrick Uiterwijk 571575
# -*- coding: utf-8 -*-
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
"""
Patrick Uiterwijk 571575
 (c) 2017 - Copyright Red Hat Inc
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
 Authors:
Patrick Uiterwijk 571575
   Patrick Uiterwijk <puiterwijk@redhat.com></puiterwijk@redhat.com>
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
"""
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
import pprint
Patrick Uiterwijk 571575
import os
Patrick Uiterwijk 571575
import traceback
Patrick Uiterwijk 571575
import types
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
import pygit2
Patrick Uiterwijk 571575
import _pygit2
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
real_pygit2_repository = pygit2.Repository
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
TOTALS = {'walks': 0,
Patrick Uiterwijk 571575
          'steps': 0}
Patrick Uiterwijk 571575
REQUESTS = []
Patrick Uiterwijk 571575
STATS = {}
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
class PerfRepoMeta(type):
Patrick Uiterwijk 571575
    def __new__(cls, name, parents, dct):
Patrick Uiterwijk 571575
        # create a class_id if it's not specified
Patrick Uiterwijk 571575
        if 'class_id' not in dct:
Patrick Uiterwijk 571575
            dct['class_id'] = name.lower()
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
        # we need to call type.__new__ to complete the initialization
Patrick Uiterwijk 571575
        return super(PerfRepoMeta, cls).__new__(cls, name, parents, dct)
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
    def __getattr__(cls, attr):
Patrick Uiterwijk 571575
        real = getattr(real_pygit2_repository, attr)
Patrick Uiterwijk 571575
        if type(real).__name__ in ['function', 'builtin_function_or_method']:
Patrick Uiterwijk 571575
            def fake(*args, **kwargs):
Patrick Uiterwijk 571575
                return real(*args, **kwargs)
Patrick Uiterwijk 571575
            return fake
Patrick Uiterwijk 571575
        else:
Patrick Uiterwijk 571575
            return real
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
class FakeWalker(object):
Patrick Uiterwijk 571575
    def __init__(self, parent):
Patrick Uiterwijk 571575
        self.parent = parent
Patrick Uiterwijk 571575
        self.wid = STATS['counters']['walks']
Patrick Uiterwijk 571575
        STATS['counters']['walks'] += 1
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
        STATS['walks'][self.wid] = {
Patrick Uiterwijk 571575
            'steps': 0,
Patrick Uiterwijk 571575
            'type': 'walker',
Patrick Uiterwijk 571575
            'init': traceback.extract_stack(limit=3)[0],
Patrick Uiterwijk 571575
            'iter': None}
Patrick Uiterwijk 571575
        TOTALS['walks'] += 1
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
    def __getattr__(self, attr):
Patrick Uiterwijk 571575
        return getattr(self.parent, attr)
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
    def __iter__(self):
Patrick Uiterwijk 571575
        STATS['walks'][self.wid]['iter'] = traceback.extract_stack(limit=2)[0]
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
        return self
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
    def next(self):
Patrick Uiterwijk 571575
        STATS['walks'][self.wid]['steps'] += 1
Patrick Uiterwijk 571575
        TOTALS['steps'] += 1
Patrick Uiterwijk 571575
        resp = self.parent.next()
Patrick Uiterwijk 571575
        return resp
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
class FakeDiffHunk(object):
Patrick Uiterwijk 571575
    def __init__(self, parent):
Patrick Uiterwijk 571575
        self.parent = parent
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
    def __getattr__(self, attr):
Patrick Uiterwijk 571575
        print 'Getting Fake Hunk %s' % attr
Patrick Uiterwijk 571575
        resp = getattr(self.parent, attr)
Patrick Uiterwijk 571575
        print 'Response: %s' % resp
Patrick Uiterwijk 571575
        return resp
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
class FakeDiffPatch(object):
Patrick Uiterwijk 571575
    def __init__(self, parent):
Patrick Uiterwijk 571575
        self.parent = parent
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
    def __getattr__(self, attr):
Patrick Uiterwijk 571575
        if attr == 'hunks':
Patrick Uiterwijk 571575
            return [FakeDiffHunk(h) for h in self.parent.hunks]
Patrick Uiterwijk 571575
        return getattr(self.parent, attr)
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
class FakeDiffer(object):
Patrick Uiterwijk 571575
    def __init__(self, parent):
Patrick Uiterwijk 571575
        self.parent = parent
Patrick Uiterwijk 571575
        self.iter = None
Patrick Uiterwijk 571575
        self.did = STATS['counters']['diffs']
Patrick Uiterwijk 571575
        STATS['counters']['diffs'] += 1
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
        STATS['diffs'][self.did] = {
Patrick Uiterwijk 571575
            'init': traceback.extract_stack(limit=3)[0],
Patrick Uiterwijk 571575
            'steps': 0,
Patrick Uiterwijk 571575
            'iter': None}
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
    def __getattr__(self, attr):
Patrick Uiterwijk 571575
        return getattr(self.parent, attr)
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
    def __dir__(self):
Patrick Uiterwijk 571575
        return dir(self.parent)
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
    def __iter__(self):
Patrick Uiterwijk 571575
        STATS['diffs'][self.did]['iter'] = traceback.extract_stack(limit=2)[0]
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
        self.iter = self.parent.__iter__()
Patrick Uiterwijk 571575
        return self
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
    def next(self):
Patrick Uiterwijk 571575
        STATS['diffs'][self.did]['steps'] += 1
Patrick Uiterwijk 571575
        resp = self.iter.next()
Patrick Uiterwijk 571575
        if isinstance(resp, _pygit2.Patch):
Patrick Uiterwijk 571575
            resp = FakeDiffPatch(resp)
Patrick Uiterwijk 571575
        else:
Patrick Uiterwijk 571575
            raise Exception('Unexpected %s returned from differ' % resp)
Patrick Uiterwijk 571575
        return resp
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
    def __len__(self):
Patrick Uiterwijk 571575
        return len(self.parent)
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
class PerfRepo(object):
Patrick Uiterwijk 571575
    """ An utility class allowing to go around pygit2's inability to be
Patrick Uiterwijk 571575
    stable.
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
    """
Patrick Uiterwijk 571575
    __metaclass__ = PerfRepoMeta
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
    def __init__(self, path):
Patrick Uiterwijk 571575
        STATS['repo_inits'].append((path, traceback.extract_stack(limit=2)[0]))
Patrick Uiterwijk 571575
        STATS['counters']['inits'] += 1
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
        self.repo = real_pygit2_repository(path)
Patrick Uiterwijk 571575
        self.iter = None
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
    def __getattr__(self, attr):
Patrick Uiterwijk 571575
        real = getattr(self.repo, attr)
Patrick Uiterwijk 571575
        if type(real) in [types.FunctionType,
Patrick Uiterwijk 571575
                          types.BuiltinFunctionType,
Patrick Uiterwijk 571575
                          types.BuiltinMethodType]:
Patrick Uiterwijk 571575
            def fake(*args, **kwargs):
Patrick Uiterwijk 571575
                resp = real(*args, **kwargs)
Patrick Uiterwijk 571575
                if isinstance(resp, _pygit2.Walker):
Patrick Uiterwijk 571575
                    resp = FakeWalker(resp)
Patrick Uiterwijk 571575
                elif isinstance(resp, _pygit2.Diff):
Patrick Uiterwijk 571575
                    resp = FakeDiffer(resp)
Patrick Uiterwijk 571575
                return resp
Patrick Uiterwijk 571575
            return fake
Patrick Uiterwijk 571575
        elif isinstance(real, dict):
Patrick Uiterwijk 571575
            real_getitem = real.__getitem__
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
            def fake_getitem(self, item):
Patrick Uiterwijk 571575
                return real_getitem(item)
Patrick Uiterwijk 571575
            real.__getitem__ = fake_getitem
Patrick Uiterwijk 571575
            return real
Patrick Uiterwijk 571575
        else:
Patrick Uiterwijk 571575
            return real
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
    def __getitem__(self, item):
Patrick Uiterwijk 571575
        return self.repo.__getitem__(item)
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
    def __contains__(self, item):
Patrick Uiterwijk 571575
        return self.repo.__contains__(item)
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
    def __iter__(self):
Patrick Uiterwijk 571575
        self.wid = STATS['counters']['walks']
Patrick Uiterwijk 571575
        STATS['counters']['walks'] += 1
Patrick Uiterwijk 571575
        STATS['walks'][self.wid] = {
Patrick Uiterwijk 571575
            'steps': 0,
Patrick Uiterwijk 571575
            'type': 'iter',
Patrick Uiterwijk 571575
            'iter': traceback.extract_stack(limit=3)[0]}
Patrick Uiterwijk 571575
        TOTALS['walks'] += 1
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
        self.iter = self.repo.__iter__()
Patrick Uiterwijk 571575
        return self
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
    def next(self):
Patrick Uiterwijk 571575
        STATS['walks'][self.wid]['steps'] += 1
Patrick Uiterwijk 571575
        TOTALS['steps'] += 1
Patrick Uiterwijk 571575
        return self.iter.next()
Patrick Uiterwijk 571575
Pierre-Yves Chibon 79825b
Patrick Uiterwijk 571575
pygit2.Repository = PerfRepo
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
def reset_stats():
Patrick Uiterwijk 571575
    """Resets STATS to be clear for the next request."""
Patrick Uiterwijk 571575
    global STATS
Patrick Uiterwijk 571575
    STATS = {'walks': {},
Patrick Uiterwijk 571575
             'diffs': {},
Patrick Uiterwijk 571575
             'repo_inits': [],
Patrick Uiterwijk 571575
             'counters': {'walks': 0,
Patrick Uiterwijk 571575
                          'diffs': 0,
Patrick Uiterwijk 571575
                          'inits': 0}}
Patrick Uiterwijk 571575
Pierre-Yves Chibon a34537
Patrick Uiterwijk 571575
# Make sure we start blank
Patrick Uiterwijk 571575
reset_stats()
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
def print_stats(response):
Patrick Uiterwijk 571575
    """Finalizes stats for the current request, and prints them possibly."""
Patrick Uiterwijk 571575
    REQUESTS.append(STATS)
Patrick Uiterwijk 571575
    if not os.environ.get('PAGURE_PERFREPO_VERBOSE'):
Patrick Uiterwijk 571575
        return response
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
    print 'Statistics:'
Patrick Uiterwijk 571575
    pprint.pprint(STATS)
Patrick Uiterwijk 571575
Patrick Uiterwijk 571575
    return response