2015-11-10 00:24:13 +03:00
|
|
|
# phabstatus.py
|
|
|
|
#
|
|
|
|
# Copyright 2015 Facebook, Inc.
|
|
|
|
#
|
|
|
|
# This software may be used and distributed according to the terms of the
|
|
|
|
# GNU General Public License version 2 or any later version.
|
|
|
|
|
2017-07-19 22:34:46 +03:00
|
|
|
from mercurial import cmdutil, extensions, registrar
|
2015-11-10 00:24:13 +03:00
|
|
|
from mercurial import util as hgutil
|
2016-01-14 21:45:47 +03:00
|
|
|
from mercurial.i18n import _
|
2017-07-08 06:54:19 +03:00
|
|
|
from mercurial import obsutil
|
2017-12-14 21:28:30 +03:00
|
|
|
import os
|
2015-11-10 00:24:13 +03:00
|
|
|
|
2018-01-24 23:30:25 +03:00
|
|
|
from .extlib.phabricator import (
|
2016-04-27 19:50:13 +03:00
|
|
|
arcconfig,
|
|
|
|
diffprops,
|
2017-12-14 21:28:30 +03:00
|
|
|
graphql,
|
2016-04-27 19:50:13 +03:00
|
|
|
)
|
2016-04-27 19:27:56 +03:00
|
|
|
|
2015-11-17 18:13:12 +03:00
|
|
|
def memoize(f):
|
2016-01-11 21:30:13 +03:00
|
|
|
"""
|
|
|
|
NOTE: This is a hack
|
|
|
|
if f args are like (a, b1, b2, b3) and returns [o1, o2, o3] where
|
|
|
|
o1, o2, o3 are output of f respectively for (a, b1), (a, b2) and
|
|
|
|
(a, b3) then we memoize f(a, b1, b2, b3)'s result but also
|
|
|
|
f(a, b1) => o1 , f(a, b2) => o2 and f(a, b3) => o3.
|
|
|
|
Example:
|
|
|
|
|
|
|
|
>>> partialsum = lambda a, *b: [a + bn for bn in b]
|
|
|
|
>>> partialsum = memoize(partialsum)
|
|
|
|
|
|
|
|
Create a class that wraps the integer '3', otherwise we cannot add
|
|
|
|
_phabstatuscache to it for the test
|
|
|
|
>>> class IntWrapperClass(int):
|
|
|
|
... def __new__(cls, *args, **kwargs):
|
|
|
|
... return super(IntWrapperClass, cls).__new__(cls, 3)
|
|
|
|
|
|
|
|
>>> three = IntWrapperClass()
|
|
|
|
>>> partialsum(three, 1, 2, 3)
|
|
|
|
[4, 5, 6]
|
|
|
|
|
|
|
|
As expected, we have 4 entries in the cache for a call like f(a, b, c, d)
|
|
|
|
>>> pp(three._phabstatuscache)
|
|
|
|
{(3, 1): [4], (3, 1, 2, 3): [4, 5, 6], (3, 2): [5], (3, 3): [6]}
|
|
|
|
"""
|
2015-11-17 18:13:12 +03:00
|
|
|
def helper(*args):
|
|
|
|
repo = args[0]
|
|
|
|
if not hgutil.safehasattr(repo, '_phabstatuscache'):
|
|
|
|
repo._phabstatuscache = {}
|
|
|
|
if args not in repo._phabstatuscache:
|
2016-01-11 21:30:13 +03:00
|
|
|
u = f(*args)
|
|
|
|
repo._phabstatuscache[args] = u
|
|
|
|
if isinstance(u, list):
|
|
|
|
revs = args[1:]
|
|
|
|
for x, r in enumerate(revs):
|
|
|
|
repo._phabstatuscache[(repo, r)] = [u[x]]
|
2015-11-17 18:13:12 +03:00
|
|
|
return repo._phabstatuscache[args]
|
|
|
|
return helper
|
|
|
|
|
2016-04-06 22:49:43 +03:00
|
|
|
def _fail(repo, diffids, *msgs):
|
|
|
|
for msg in msgs:
|
|
|
|
repo.ui.warn(msg)
|
|
|
|
return ["Error"] * len(diffids)
|
|
|
|
|
2015-11-17 18:13:12 +03:00
|
|
|
@memoize
|
2016-01-11 21:30:13 +03:00
|
|
|
def getdiffstatus(repo, *diffid):
|
2016-04-27 19:27:56 +03:00
|
|
|
"""Perform a Conduit API call to get the diff status
|
2015-11-10 00:24:13 +03:00
|
|
|
|
|
|
|
Returns status of the diff"""
|
|
|
|
|
2016-04-06 22:49:43 +03:00
|
|
|
if not diffid:
|
|
|
|
return []
|
|
|
|
timeout = repo.ui.configint('ssl', 'timeout', 5)
|
2017-10-19 16:03:48 +03:00
|
|
|
ca_certs = repo.ui.configpath('web', 'cacerts')
|
2016-04-27 19:27:56 +03:00
|
|
|
|
2015-11-10 00:24:13 +03:00
|
|
|
try:
|
2017-12-14 21:28:30 +03:00
|
|
|
client = graphql.Client(
|
|
|
|
repodir=os.getcwd(), ca_bundle=ca_certs, repo=repo)
|
|
|
|
statuses = client.getrevisioninfo(timeout, diffid)
|
2016-04-06 22:49:43 +03:00
|
|
|
|
2017-12-14 21:28:30 +03:00
|
|
|
except graphql.ClientError as ex:
|
2016-04-06 22:49:43 +03:00
|
|
|
msg = _('Error talking to phabricator. No diff information can be '
|
2016-01-14 21:45:47 +03:00
|
|
|
'provided.\n')
|
phabstatus: fail gracefully if necessary arcrc settings are missing
Summary:
If the user does not have necesary credentials defined in their arc
configuration, catch the KeyError and convert it into an ArcConfigError.
The existing call sites in the phabstatus and arcdiff extensions catch and
handle ArcConfigError, but not generic KeyErrors.
This also fixes the phabstatus warning messages to end with a newline.
Test Plan: Added a unit test.
Reviewers: #sourcecontrol, quark, simonfar, wez, rmcelroy
Reviewed By: wez, rmcelroy
Subscribers: rmcelroy, net-systems-diffs@fb.com, yogeshwer, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D4800977
Tasks: 17002914
Signature: t1:4800977:1490847078:e18bba042e3ff57100e0a7b25c610b5cad17fa2e
2017-03-30 21:55:39 +03:00
|
|
|
hint = _("Error info: %s\n") % str(ex)
|
2017-12-14 21:28:30 +03:00
|
|
|
ret = _fail(repo, diffid, msg, hint)
|
|
|
|
return ret
|
2016-04-27 19:27:56 +03:00
|
|
|
except arcconfig.ArcConfigError as ex:
|
|
|
|
msg = _('arcconfig configuration problem. No diff information can be '
|
|
|
|
'provided.\n')
|
phabstatus: fail gracefully if necessary arcrc settings are missing
Summary:
If the user does not have necesary credentials defined in their arc
configuration, catch the KeyError and convert it into an ArcConfigError.
The existing call sites in the phabstatus and arcdiff extensions catch and
handle ArcConfigError, but not generic KeyErrors.
This also fixes the phabstatus warning messages to end with a newline.
Test Plan: Added a unit test.
Reviewers: #sourcecontrol, quark, simonfar, wez, rmcelroy
Reviewed By: wez, rmcelroy
Subscribers: rmcelroy, net-systems-diffs@fb.com, yogeshwer, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D4800977
Tasks: 17002914
Signature: t1:4800977:1490847078:e18bba042e3ff57100e0a7b25c610b5cad17fa2e
2017-03-30 21:55:39 +03:00
|
|
|
hint = _("Error info: %s\n") % str(ex)
|
2017-12-14 21:28:30 +03:00
|
|
|
ret = _fail(repo, diffid, msg, hint)
|
|
|
|
return ret
|
2016-04-06 22:49:43 +03:00
|
|
|
|
2017-12-14 21:28:30 +03:00
|
|
|
# This makes the code more robust in case we don't learn about any
|
|
|
|
# particular revision
|
2016-04-06 22:49:43 +03:00
|
|
|
result = []
|
|
|
|
for diff in diffid:
|
2017-12-14 21:28:30 +03:00
|
|
|
matchingresponse = statuses.get(str(diff))
|
2016-04-06 22:49:43 +03:00
|
|
|
if not matchingresponse:
|
|
|
|
result.append("Error")
|
|
|
|
else:
|
2016-08-05 21:33:36 +03:00
|
|
|
result.append(matchingresponse)
|
2016-04-06 22:49:43 +03:00
|
|
|
return result
|
2015-11-10 00:24:13 +03:00
|
|
|
|
2017-07-19 22:34:46 +03:00
|
|
|
def populateresponseforphab(repo, diffnum):
|
2016-08-05 21:33:36 +03:00
|
|
|
""":populateresponse: Runs the memoization function
|
|
|
|
for use of phabstatus and sync status
|
2015-12-08 22:28:38 +03:00
|
|
|
"""
|
2017-07-19 22:34:46 +03:00
|
|
|
if not hgutil.safehasattr(repo, '_phabstatusrevs'):
|
|
|
|
return
|
|
|
|
|
|
|
|
if (hgutil.safehasattr(repo, '_phabstatuscache') and
|
|
|
|
(repo, diffnum) in repo._phabstatuscache):
|
|
|
|
# We already have cached data for this diff
|
|
|
|
return
|
|
|
|
|
|
|
|
next_revs = repo._phabstatusrevs.peekahead()
|
|
|
|
if repo._phabstatusrevs.done:
|
|
|
|
# repo._phabstatusrevs doesn't have anything else to process.
|
|
|
|
# Remove it so we will bail out earlier next time.
|
|
|
|
del repo._phabstatusrevs
|
|
|
|
|
|
|
|
alldiffnumbers = [getdiffnum(repo, repo[rev])
|
|
|
|
for rev in next_revs]
|
|
|
|
okdiffnumbers = set(d for d in alldiffnumbers if d is not None)
|
|
|
|
# Make sure we always include the requested diff number
|
|
|
|
okdiffnumbers.add(diffnum)
|
|
|
|
# To populate the cache, the result will be used by the templater
|
|
|
|
getdiffstatus(repo, *okdiffnumbers)
|
2016-01-11 21:30:13 +03:00
|
|
|
|
templates: fix help messages for template keywords
Summary:
Many of the template keywords in our extensions were being registered
incorrectly, causing their help output to be rendered incorrectly in the
"hg help templates" output. The ones in smartlog.py were particularly bad, as
most of them showed only their description, without displaying the name of the
template. In smartlog.py only singlepublicsuccessor was being displayed
correctly, because it's docstring explicitly included it's own name at the
start.
This fixes all of our extensions to consistently use the
registrar.templatekeyword() decorator to register the keywords. This decorator
automatically prefixes the help message with the keyword name. The
mercurial/extensions.py code will explicitly check to see if an extension
contains an "templatekeyword" attribute, and if so it will register any
keywords contained in this registry after calling extsetup().
Test Plan:
Added new unit tests to check the output of "hg help templates" for the
affected keywords.
Reviewers: #sourcecontrol, kulshrax, ikostia, rmcelroy
Reviewed By: rmcelroy
Subscribers: rmcelroy, net-systems-diffs@, yogeshwer, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D4427729
Signature: t1:4427729:1484831476:17b478a5e867dfc3f85402588c381bf8b1831107
2017-01-19 23:52:54 +03:00
|
|
|
templatekeyword = registrar.templatekeyword()
|
|
|
|
|
|
|
|
@templatekeyword('phabstatus')
|
2016-08-05 21:33:36 +03:00
|
|
|
def showphabstatus(repo, ctx, templ, **args):
|
templates: fix help messages for template keywords
Summary:
Many of the template keywords in our extensions were being registered
incorrectly, causing their help output to be rendered incorrectly in the
"hg help templates" output. The ones in smartlog.py were particularly bad, as
most of them showed only their description, without displaying the name of the
template. In smartlog.py only singlepublicsuccessor was being displayed
correctly, because it's docstring explicitly included it's own name at the
start.
This fixes all of our extensions to consistently use the
registrar.templatekeyword() decorator to register the keywords. This decorator
automatically prefixes the help message with the keyword name. The
mercurial/extensions.py code will explicitly check to see if an extension
contains an "templatekeyword" attribute, and if so it will register any
keywords contained in this registry after calling extsetup().
Test Plan:
Added new unit tests to check the output of "hg help templates" for the
affected keywords.
Reviewers: #sourcecontrol, kulshrax, ikostia, rmcelroy
Reviewed By: rmcelroy
Subscribers: rmcelroy, net-systems-diffs@, yogeshwer, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D4427729
Signature: t1:4427729:1484831476:17b478a5e867dfc3f85402588c381bf8b1831107
2017-01-19 23:52:54 +03:00
|
|
|
"""String. Return the diff approval status for a given hg rev
|
2016-08-05 21:33:36 +03:00
|
|
|
"""
|
2016-01-11 21:30:13 +03:00
|
|
|
diffnum = getdiffnum(repo, ctx)
|
2017-07-19 22:34:46 +03:00
|
|
|
if diffnum is None:
|
|
|
|
return None
|
|
|
|
populateresponseforphab(repo, diffnum)
|
|
|
|
|
|
|
|
result = getdiffstatus(repo, diffnum)[0]
|
|
|
|
if isinstance(result, dict) and "status" in result:
|
|
|
|
return result.get("status")
|
|
|
|
else:
|
|
|
|
return "Error"
|
2016-08-05 21:33:36 +03:00
|
|
|
|
|
|
|
"""
|
2017-03-25 01:22:31 +03:00
|
|
|
in order to determine whether the local changeset is in sync with the
|
2016-09-21 17:45:25 +03:00
|
|
|
remote one we compare the hash of the current changeset with the one we
|
2016-08-05 21:33:36 +03:00
|
|
|
get from the remote (phabricator) repo. There are three different cases
|
|
|
|
and we deal with them seperately.
|
|
|
|
1) If this is the first revision in a diff: We look at the count field and
|
2016-09-21 17:45:25 +03:00
|
|
|
understand that this is the first changeset, so we compare the hash we get
|
|
|
|
from remote repo with the predessesor's hash from the local changeset. The
|
|
|
|
reason for that is the D number is ammended on the changeset after it is
|
2016-08-05 21:33:36 +03:00
|
|
|
sent to phabricator.
|
|
|
|
2) If this is the last revision, i.e. it is alread committed: Then we
|
|
|
|
don't say anything. All good.
|
|
|
|
3) If this is a middle revision: Then we compare the hashes as regular.
|
|
|
|
"""
|
templates: fix help messages for template keywords
Summary:
Many of the template keywords in our extensions were being registered
incorrectly, causing their help output to be rendered incorrectly in the
"hg help templates" output. The ones in smartlog.py were particularly bad, as
most of them showed only their description, without displaying the name of the
template. In smartlog.py only singlepublicsuccessor was being displayed
correctly, because it's docstring explicitly included it's own name at the
start.
This fixes all of our extensions to consistently use the
registrar.templatekeyword() decorator to register the keywords. This decorator
automatically prefixes the help message with the keyword name. The
mercurial/extensions.py code will explicitly check to see if an extension
contains an "templatekeyword" attribute, and if so it will register any
keywords contained in this registry after calling extsetup().
Test Plan:
Added new unit tests to check the output of "hg help templates" for the
affected keywords.
Reviewers: #sourcecontrol, kulshrax, ikostia, rmcelroy
Reviewed By: rmcelroy
Subscribers: rmcelroy, net-systems-diffs@, yogeshwer, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D4427729
Signature: t1:4427729:1484831476:17b478a5e867dfc3f85402588c381bf8b1831107
2017-01-19 23:52:54 +03:00
|
|
|
@templatekeyword('syncstatus')
|
2016-08-05 21:33:36 +03:00
|
|
|
def showsyncstatus(repo, ctx, templ, **args):
|
templates: fix help messages for template keywords
Summary:
Many of the template keywords in our extensions were being registered
incorrectly, causing their help output to be rendered incorrectly in the
"hg help templates" output. The ones in smartlog.py were particularly bad, as
most of them showed only their description, without displaying the name of the
template. In smartlog.py only singlepublicsuccessor was being displayed
correctly, because it's docstring explicitly included it's own name at the
start.
This fixes all of our extensions to consistently use the
registrar.templatekeyword() decorator to register the keywords. This decorator
automatically prefixes the help message with the keyword name. The
mercurial/extensions.py code will explicitly check to see if an extension
contains an "templatekeyword" attribute, and if so it will register any
keywords contained in this registry after calling extsetup().
Test Plan:
Added new unit tests to check the output of "hg help templates" for the
affected keywords.
Reviewers: #sourcecontrol, kulshrax, ikostia, rmcelroy
Reviewed By: rmcelroy
Subscribers: rmcelroy, net-systems-diffs@, yogeshwer, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D4427729
Signature: t1:4427729:1484831476:17b478a5e867dfc3f85402588c381bf8b1831107
2017-01-19 23:52:54 +03:00
|
|
|
"""String. Return whether the local revision is in sync
|
2016-08-05 21:33:36 +03:00
|
|
|
with the remote (phabricator) revision
|
|
|
|
"""
|
2017-07-19 22:34:46 +03:00
|
|
|
diffnum = getdiffnum(repo, ctx)
|
|
|
|
if diffnum is None:
|
|
|
|
return None
|
|
|
|
|
2017-07-19 22:34:46 +03:00
|
|
|
populateresponseforphab(repo, diffnum)
|
2017-07-19 22:34:46 +03:00
|
|
|
results = getdiffstatus(repo, diffnum)
|
|
|
|
try:
|
|
|
|
result = results[0]
|
|
|
|
remote = result["hash"]
|
|
|
|
status = result["status"]
|
|
|
|
count = int(result["count"])
|
|
|
|
except (IndexError, KeyError, ValueError, TypeError):
|
|
|
|
# We got no result back, or it did not contain all required fields
|
|
|
|
return "Error"
|
2016-08-05 21:33:36 +03:00
|
|
|
|
|
|
|
local = ctx.hex()
|
2017-07-19 22:34:46 +03:00
|
|
|
if local == remote:
|
|
|
|
return "sync"
|
|
|
|
elif count == 1:
|
2017-12-14 21:28:30 +03:00
|
|
|
precursors = list(obsutil.allpredecessors(repo.obsstore, [ctx.node()]))
|
2017-07-19 22:34:46 +03:00
|
|
|
hashes = [repo.unfiltered()[h].hex() for h in precursors]
|
|
|
|
# hashes[0] is the current
|
|
|
|
# hashes[1] is the previous
|
|
|
|
if len(hashes) > 1 and hashes[1] == remote:
|
|
|
|
return "sync"
|
2016-08-05 21:33:36 +03:00
|
|
|
else:
|
2017-07-19 22:34:46 +03:00
|
|
|
return "unsync"
|
|
|
|
elif status == "Committed":
|
|
|
|
return "committed"
|
|
|
|
else:
|
|
|
|
return "unsync"
|
2016-01-11 21:30:13 +03:00
|
|
|
|
|
|
|
def getdiffnum(repo, ctx):
|
2016-04-27 19:50:13 +03:00
|
|
|
return diffprops.parserevfromcommitmsg(ctx.description())
|
2015-11-10 00:24:13 +03:00
|
|
|
|
2017-07-19 22:34:46 +03:00
|
|
|
class PeekaheadRevsetIter(object):
|
|
|
|
"""
|
|
|
|
PeekaheadRevsetIter is a helper class that wraps a revision set iterator,
|
|
|
|
and allows the phabstatus code to peek ahead in the list as the logging
|
|
|
|
code is iterating through it.
|
|
|
|
|
|
|
|
The main logging code uses the normal iterator interface (next()) to
|
|
|
|
iterate through this revision set.
|
|
|
|
|
|
|
|
The phabstatus code will call peekahead() to peek ahead in the list, so it
|
|
|
|
can query information for multiple revisions at once, rather than only
|
|
|
|
processing them one at a time as the logging code requests them.
|
|
|
|
"""
|
|
|
|
def __init__(self, revs, chunksize=30):
|
|
|
|
self.mainiter = iter(revs)
|
|
|
|
# done is set to true once mainiter has thrown StopIteration
|
|
|
|
self.done = False
|
|
|
|
|
|
|
|
# chunk is the peekahead chunk we have returned from peekahead().
|
|
|
|
self.chunk = list()
|
|
|
|
# chunk_idx represents how far into self.chunk() the main iteration
|
|
|
|
# code has seen via the next() API.
|
|
|
|
self.chunk_idx = 0
|
|
|
|
self.chunksize = chunksize
|
|
|
|
|
|
|
|
def next(self):
|
|
|
|
if self.chunk_idx < len(self.chunk):
|
|
|
|
# We still have data remaining in the peekahead chunk to return
|
|
|
|
result = self.chunk[self.chunk_idx]
|
|
|
|
self.chunk_idx += 1
|
|
|
|
if self.chunk_idx >= len(self.chunk):
|
|
|
|
self.chunk = list()
|
|
|
|
self.chunk_idx = 0
|
|
|
|
return result
|
|
|
|
|
|
|
|
if self.done:
|
|
|
|
raise StopIteration()
|
|
|
|
|
|
|
|
try:
|
|
|
|
return next(self.mainiter)
|
|
|
|
except StopIteration:
|
|
|
|
self.done = True
|
|
|
|
raise
|
|
|
|
|
|
|
|
def peekahead(self, chunksize=None):
|
|
|
|
chunksize = chunksize or self.chunksize
|
|
|
|
while len(self.chunk) < chunksize and not self.done:
|
|
|
|
try:
|
|
|
|
self.chunk.append(next(self.mainiter))
|
|
|
|
except StopIteration:
|
|
|
|
self.done = True
|
|
|
|
|
|
|
|
return self.chunk
|
|
|
|
|
|
|
|
def _getlogrevs(orig, repo, pats, opts):
|
|
|
|
# Call the original function
|
|
|
|
revs, expr, filematcher = orig(repo, pats, opts)
|
|
|
|
|
|
|
|
# Wrap the revs result so that iter(revs) returns a PeekaheadRevsetIter()
|
|
|
|
# the first time it is invoked, and sets repo._phabstatusrevs so that the
|
|
|
|
# phabstatus code will be able to peek ahead at the revs to be logged.
|
|
|
|
orig_type = revs.__class__
|
|
|
|
class wrapped_class(type(revs)):
|
|
|
|
def __iter__(self):
|
|
|
|
# The first time __iter__() is called, return a
|
|
|
|
# PeekaheadRevsetIter(), and assign it to repo._phabstatusrevs
|
|
|
|
revs.__class__ = orig_type
|
|
|
|
# By default, peek ahead 30 revisions at a time
|
|
|
|
peekahead = repo.ui.configint('phabstatus', 'logpeekahead', 30)
|
|
|
|
repo._phabstatusrevs = PeekaheadRevsetIter(revs, peekahead)
|
|
|
|
return repo._phabstatusrevs
|
|
|
|
|
|
|
|
_is_phabstatus_wrapped = True
|
|
|
|
|
|
|
|
if not hgutil.safehasattr(revs, '_is_phabstatus_wrapped'):
|
|
|
|
revs.__class__ = wrapped_class
|
|
|
|
|
|
|
|
return revs, expr, filematcher
|
|
|
|
|
|
|
|
class PeekaheadList(object):
|
|
|
|
"""
|
|
|
|
PeekaheadList exposes peekahead() and done just like PeekaheadRevsetIter,
|
|
|
|
but wraps a simple list instead of a revset generator. peekahead() returns
|
|
|
|
the full list.
|
|
|
|
"""
|
|
|
|
def __init__(self, revs):
|
|
|
|
self.revs = revs
|
|
|
|
self.done = False
|
|
|
|
|
|
|
|
def peekahead(self):
|
|
|
|
self.done = True
|
|
|
|
return self.revs
|
|
|
|
|
|
|
|
def _getsmartlogdag(orig, ui, repo, revs, *args):
|
|
|
|
# smartlog just uses a plain list for its revisions, and not an
|
|
|
|
# abstractsmartset type. We just save a copy of it.
|
|
|
|
repo._phabstatusrevs = PeekaheadList(revs)
|
|
|
|
return orig(ui, repo, revs, *args)
|
2015-11-10 00:24:13 +03:00
|
|
|
|
|
|
|
def extsetup(ui):
|
2017-07-19 22:34:46 +03:00
|
|
|
# Wrap the APIs used to get the revisions for "hg log" so we
|
|
|
|
# can peekahead into the rev list and query phabricator for multiple diffs
|
|
|
|
# at once.
|
|
|
|
extensions.wrapfunction(cmdutil, 'getlogrevs', _getlogrevs)
|
|
|
|
extensions.wrapfunction(cmdutil, 'getgraphlogrevs', _getlogrevs)
|
|
|
|
|
|
|
|
# Also wrap the APIs used by smartlog
|
2017-07-06 19:38:14 +03:00
|
|
|
def _smartlogloaded(loaded):
|
|
|
|
smartlog = None
|
|
|
|
try:
|
|
|
|
smartlog = extensions.find('smartlog')
|
|
|
|
except KeyError:
|
|
|
|
pass
|
|
|
|
if smartlog:
|
2017-07-19 22:34:46 +03:00
|
|
|
extensions.wrapfunction(smartlog, 'getdag', _getsmartlogdag)
|
2017-07-06 19:38:14 +03:00
|
|
|
|
|
|
|
extensions.afterloaded('smartlog', _smartlogloaded)
|