sapling/hgext/fbamend/hiddenoverride.py
Durham Goode 8103079702 imports: import from hgext instead of hgext3rd
The only reason these worked is because they were in the system python path.
Which means the in-repo code wasn't actually being tested.
2018-01-09 15:23:52 -08:00

131 lines
4.4 KiB
Python

# hiddenoverride.py - lightweight hidden-ness override
#
# Copyright 2017 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.
from __future__ import absolute_import
from hgext import extutil
from mercurial.node import short
from mercurial import (
dispatch,
error,
extensions,
obsolete,
repoview,
scmutil,
util,
)
def uisetup(ui):
extensions.wrapfunction(repoview, 'pinnedrevs', pinnedrevs)
extensions.wrapfunction(dispatch, 'runcommand', runcommand)
extensions.wrapfunction(obsolete, 'createmarkers', createmarkers)
extensions.wrapfunction(scmutil, 'cleanupnodes', cleanupnodes)
def pinnedrevs(orig, repo):
revs = orig(repo)
nodemap = repo.changelog.nodemap
pinnednodes = set(loadpinnednodes(repo))
tounpin = getattr(repo, '_tounpinnodes', set())
pinnednodes -= tounpin
revs.update(nodemap[n] for n in pinnednodes)
return revs
def loadpinnednodes(repo):
"""yield pinned nodes that are obsoleted and should be visible"""
if repo is None or not repo.local():
return
# the "pinned nodes" file name is "obsinhibit" for compatibility reason
content = repo.svfs.tryread('obsinhibit') or ''
unfi = repo.unfiltered()
nodemap = unfi.changelog.nodemap
offset = 0
result = []
while True:
node = content[offset:offset + 20]
if not node:
break
if node in nodemap:
result.append(node)
offset += 20
return result
def shouldpinnodes(repo):
"""get nodes that should be pinned: working parent + bookmarks for now"""
result = set()
if repo and repo.local():
# working copy parent
try:
wnode = repo.vfs('dirstate').read(20)
result.add(wnode)
except Exception:
pass
# bookmarks
result.update(repo.unfiltered()._bookmarks.values())
return result
def savepinnednodes(repo, newpin, newunpin, fullargs):
# take a narrowed lock so it does not affect repo lock
with extutil.flock(repo.svfs.join('obsinhibit.lock'), 'save pinned nodes'):
orignodes = loadpinnednodes(repo)
nodes = set(orignodes)
nodes |= set(newpin)
nodes -= set(newunpin)
with util.atomictempfile(repo.svfs.join('obsinhibit')) as f:
f.write(''.join(nodes))
desc = lambda s: [short(n) for n in s]
repo.ui.log('pinnednodes', 'pinnednodes: %r newpin=%r newunpin=%r '
'before=%r after=%r\n', fullargs, desc(newpin),
desc(newunpin), desc(orignodes), desc(nodes))
def runcommand(orig, lui, repo, cmd, fullargs, *args):
# return directly for non-repo command
if not repo:
return orig(lui, repo, cmd, fullargs, *args)
shouldpinbefore = shouldpinnodes(repo) | set(loadpinnednodes(repo))
result = orig(lui, repo, cmd, fullargs, *args)
# after a command completes, make sure working copy parent and all
# bookmarks get "pinned".
newpin = shouldpinnodes(repo) - shouldpinbefore
newunpin = getattr(repo.unfiltered(), '_tounpinnodes', set())
# filter newpin by obsolte - ex. if newpin is on a non-obsoleted commit,
# ignore it.
if newpin:
unfi = repo.unfiltered()
obsoleted = unfi.revs('obsolete()')
nodemap = unfi.changelog.nodemap
newpin = set(n for n in newpin
if n in nodemap and nodemap[n] in obsoleted)
# only do a write if something has changed
if newpin or newunpin:
savepinnednodes(repo, newpin, newunpin, fullargs)
return result
def createmarkers(orig, repo, rels, *args, **kwargs):
# this is a way to unpin revs - precursors are unpinned
# note: hg debugobsolete does not call this function
unfi = repo.unfiltered()
tounpin = getattr(unfi, '_tounpinnodes', set())
for r in rels:
try:
tounpin.add(r[0].node())
except error.RepoLookupError:
pass
unfi._tounpinnodes = tounpin
return orig(repo, rels, *args, **kwargs)
def cleanupnodes(orig, repo, mapping, *args, **kwargs):
# this catches cases where cleanupnodes is called but createmarkers is not
# called. unpin nodes from mapping
unfi = repo.unfiltered()
tounpin = getattr(unfi, '_tounpinnodes', set())
tounpin.update(mapping)
unfi._tounpinnodes = tounpin
return orig(repo, mapping, *args, **kwargs)