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