diff --git a/ghp/commands/import_upstream.py b/ghp/commands/import_upstream.py index 5a9f4c7..d15ddf1 100644 --- a/ghp/commands/import_upstream.py +++ b/ghp/commands/import_upstream.py @@ -15,13 +15,13 @@ # limitations under the License. from ghp.errors import HpgitError +from ghp.log import LogDedentMixin from ghp import subcommand, log from git import Repo, GitCommandError import inspect import os -import textwrap class ImportUpstreamError(HpgitError): @@ -29,7 +29,7 @@ class ImportUpstreamError(HpgitError): pass -class ImportUpstream(object): +class ImportUpstream(LogDedentMixin): """ Import code from an upstream project and merge in additional branches to create a new branch unto which changes that are not upstream but are @@ -46,6 +46,10 @@ class ImportUpstream(object): self._repo = Repo(os.environ.get('GIT_WORK_TREE', os.path.curdir)) self._git = self.repo.git + # make sure to correctly initialise inherited objects before performing + # any computation + super(ImportUpstream, self).__init__() + if self.repo.bare: raise ImportUpstreamError("Cannot perform imports in bare repos") @@ -142,10 +146,10 @@ class ImportUpstream(object): "from '%s' (%s)", self.import_branch, self.upstream, commit) self.log.info( - textwrap.dedent("""\ - Checking if import branch '%s' already exists: - git branch --list %s - """), self.import_branch, self.import_branch) + """\ + Checking if import branch '%s' already exists: + git branch --list %s + """, self.import_branch, self.import_branch) if self.git.show_ref("refs/heads/" + self.import_branch, verify=True, with_exceptions=False) and not force: msg = "Import branch '%s' already exists, use force to replace" @@ -154,11 +158,10 @@ class ImportUpstream(object): if self.repo.active_branch == self.import_branch: self.log.info( - textwrap.dedent( - """\ - Resetting import branch '%s' to specified commit '%s' - git reset --hard %s - """), self.import_branch, commit, commit) + """\ + Resetting import branch '%s' to specified commit '%s' + git reset --hard %s + """, self.import_branch, commit, commit) self.git.reset(commit, hard=True) elif checkout: checkout_args = dict(b=True) @@ -166,30 +169,27 @@ class ImportUpstream(object): checkout_args = dict(B=True) self.log.info( - textwrap.dedent( - """\ - Checking out import branch '%s' using specified commit '%s' - git checkout %s %s %s - """), self.import_branch, commit, checkout_args, + """\ + Checking out import branch '%s' using specified commit '%s' + git checkout %s %s %s + """, self.import_branch, commit, checkout_args, self.import_branch, commit) self.git.checkout(self.import_branch, commit, **checkout_args) else: self.log.info( - textwrap.dedent( - """\ - Creating import branch '%s' from specified commit '%s' - git branch --force %s %s - """), self.import_branch, commit, self.import_branch, commit) + """\ + Creating import branch '%s' from specified commit '%s' + git branch --force %s %s + """, self.import_branch, commit, self.import_branch, commit) self.git.branch(self.import_branch, commit, force=force) if self.extra_branches: self.log.info( - textwrap.dedent( - """\ - Merging additional branch(es) '%s' into import branch '%s' - git checkout %s - git merge %s - """), ", ".join(self.extra_branches), self.import_branch, + """\ + Merging additional branch(es) '%s' into import branch '%s' + git checkout %s + git merge %s + """, ", ".join(self.extra_branches), self.import_branch, self.import_branch, " ".join(self.extra_branches)) self.git.checkout(self.import_branch) self.git.merge(*self.extra_branches) diff --git a/ghp/log.py b/ghp/log.py index 097e0c2..44fb754 100644 --- a/ghp/log.py +++ b/ghp/log.py @@ -24,6 +24,8 @@ for logging output to the console. """ import logging +from functools import wraps +import textwrap # Add new NOTICE logging level @@ -87,3 +89,63 @@ class LevelFilterIgnoreBelow(logging.Filter): def filter(self, record): return record.levelno >= self.level + + +class DedentLoggerMeta(type): + """ + Meta class to wrap all level functions in logging interface with dedent + + Classes created from this should be derived from the logging.Logger class + as otherwise they will not contain the correct methods to be wrapped and + trying to pass them as the default class to create Loggers from will fail. + """ + + def __new__(cls, name, bases, dict): + # provide a more intelligent error instead of waiting for setattr/getattr + # adding of a wrapper function to fail + if logging.Logger not in bases: + raise TypeError("%s not derived from logging.Logger" % name) + + obj = super(DedentLoggerMeta, cls).__new__(cls, name, bases, dict) + for level in _levels: + setattr(obj, level, cls.wrap_level(getattr(obj, level))) + setattr(obj, 'log', cls.wrap(getattr(obj, 'log'))) + return obj + + @staticmethod + def wrap(func): + def _dedent_log(self, level, msg, *args, **kwargs): + dedent = kwargs.pop('dedent', True) + if dedent: + msg = textwrap.dedent(msg) + func(self, level, msg, *args, **kwargs) + return wraps(func)(_dedent_log) + + @staticmethod + def wrap_level(func): + def _dedent_log(self, msg, *args, **kwargs): + dedent = kwargs.pop('dedent', True) + if dedent: + msg = textwrap.dedent(msg) + func(self, msg, *args, **kwargs) + return wraps(func)(_dedent_log) + + +class DedentLogger(logging.Logger): + __metaclass__ = DedentLoggerMeta + + +# override default logger class for everything that imports this module +logging.setLoggerClass(DedentLogger) + + +class LogDedentMixin(object): + + def __init__(self, *args, **kwargs): + self.__log = getLogger('%s.%s' % (__name__, self.__class__.__name__)) + + super(LogDedentMixin, self).__init__(*args, **kwargs) + + @property + def log(self): + return self.__log