hgext/pager.py
author Gregory Szorc <gregory.szorc@gmail.com>
Sun, 13 Aug 2017 10:58:48 -0700
changeset 33800 f257943e47ab
parent 31406 e83302d43748
child 34495 6d1b0970f80c
permissions -rw-r--r--
repository: formalize peer interface with abstract base class There are various interfaces for interacting with repositories and peers. They form a contract for how one should interact with a repo or peer object. The contracts today aren't very well-defined or enforced. There have been several bugs over the years where peers or repo types have forgotten to implement certain methods. In addition, the inheritance of some classes is wonky. For example, localrepository doesn't inherit from an interface and the god-object nature of that class means the repository interface isn't well-defined. Other repository types inherit from localrepository then stub out methods that don't make sense (e.g. statichttprepository re-defining locking methods to fail fast). Not having well-defined interfaces makes implementing alternate storage backends, wire protocol transports, and repository types difficult because it isn't clear what exactly needs to be implemented. This patch starts the process of attempting to establish more order to the type system around repositories and peers. Our first patch starts with a problem space that already has a partial solution: peers. The peer.peerrepository class already somewhat defines a peer interface. But it is missing a few things and the total interface isn't well-defined because it is combined with wireproto.wirepeer. Our newly-established basepeer class uses the abc module to declare an abstract base class with the properties and methods that a generic peer must implement. We create a new class that inherits from it. This class will hold our other future abstract base classes / interfaces so we can expose a unified base class/interface. We don't yet use the new interface because subsequent additions will break existing code without some refactoring first. A new module (repository.py) was created to hold the interfaces. I could have put things in peer.py. However, I have plans to eventually add interfaces to define repository and storage types. These almost certainly require a new module. And I figured having all the interfaces live in one module makes sense. So I created repository.py to be that future home. Differential Revision: https://phab.mercurial-scm.org/D332

# pager.py - display output using a pager
#
# Copyright 2008 David Soria Parra <dsp@php.net>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
#
# To load the extension, add it to your configuration file:
#
#   [extension]
#   pager =
#
# Run 'hg help pager' to get info on configuration.

'''browse command output with an external pager (DEPRECATED)

Forcibly enable paging for individual commands that don't typically
request pagination with the attend-<command> option. This setting
takes precedence over ignore options and defaults::

  [pager]
  attend-cat = false
'''
from __future__ import absolute_import

from mercurial import (
    cmdutil,
    commands,
    dispatch,
    extensions,
    )

# Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
# be specifying the version(s) of Mercurial they are tested with, or
# leave the attribute unspecified.
testedwith = 'ships-with-hg-core'

def uisetup(ui):

    def pagecmd(orig, ui, options, cmd, cmdfunc):
        auto = options['pager'] == 'auto'
        if auto and not ui.pageractive:
            usepager = False
            attend = ui.configlist('pager', 'attend', attended)
            ignore = ui.configlist('pager', 'ignore')
            cmds, _ = cmdutil.findcmd(cmd, commands.table)

            for cmd in cmds:
                var = 'attend-%s' % cmd
                if ui.config('pager', var):
                    usepager = ui.configbool('pager', var)
                    break
                if (cmd in attend or
                     (cmd not in ignore and not attend)):
                    usepager = True
                    break

            if usepager:
                # Slight hack: the attend list is supposed to override
                # the ignore list for the pager extension, but the
                # core code doesn't know about attend, so we have to
                # lobotomize the ignore list so that the extension's
                # behavior is preserved.
                ui.setconfig('pager', 'ignore', '', 'pager')
                ui.pager('extension-via-attend-' + cmd)
            else:
                ui.disablepager()
        return orig(ui, options, cmd, cmdfunc)

    extensions.wrapfunction(dispatch, '_runcommand', pagecmd)

attended = ['annotate', 'cat', 'diff', 'export', 'glog', 'log', 'qdiff']