mirror of
https://github.com/facebook/sapling.git
synced 2024-10-07 07:17:55 +03:00
infinitepush: bookmarks remote-list
Summary: Add an option to list remote and scratch bookmarks by pattern. Only very simple pattern is allowed: either the literal string or a prefix (like 'scratch/stash/*'). It was made intentionally to make sure that pattern requests are fast in mysql. Mysql tests will be added to the integration tests Test Plan: Run `test-infinitepush-*` Reviewers: mitrandir, andrasbelo, durham Reviewed By: durham Subscribers: mjpieters, #sourcecontrol Differential Revision: https://phabricator.intern.facebook.com/D4074409 Tasks: 12479677 Signature: t1:4074409:1477500968:e91cd2505d61a2f1db30c7f00cdcfc949e433507
This commit is contained in:
parent
6086c2f0cb
commit
005a9ace91
@ -167,6 +167,16 @@ def clientextsetup(ui):
|
||||
('', 'bundle-store', None,
|
||||
_('force push to go to bundle store (EXPERIMENTAL)')))
|
||||
|
||||
bookcmd = extensions.wrapcommand(commands.table, 'bookmarks', exbookmarks)
|
||||
bookcmd[1].append(
|
||||
('', 'list-remote', '',
|
||||
'list remote bookmarks. '
|
||||
'Use \'*\' to find all bookmarks with the same prefix',
|
||||
'PATTERN'))
|
||||
bookcmd[1].append(
|
||||
('', 'remote-path', '',
|
||||
'name of the remote path to list the bookmarks'))
|
||||
|
||||
wrapcommand(commands.table, 'pull', _pull)
|
||||
|
||||
wrapfunction(discovery, 'checkheads', _checkheads)
|
||||
@ -182,6 +192,32 @@ def clientextsetup(ui):
|
||||
partorder.insert(
|
||||
index, partorder.pop(partorder.index(scratchbranchparttype)))
|
||||
|
||||
def _showbookmarks(ui, bookmarks, **opts):
|
||||
# Copy-paste from commands.py
|
||||
fm = ui.formatter('bookmarks', opts)
|
||||
for bmark, n in sorted(bookmarks.iteritems()):
|
||||
fm.startitem()
|
||||
if not ui.quiet:
|
||||
fm.plain(' ')
|
||||
fm.write('bookmark', '%s', bmark)
|
||||
pad = ' ' * (25 - encoding.colwidth(bmark))
|
||||
fm.condwrite(not ui.quiet, 'node', pad + ' %s', n)
|
||||
fm.plain('\n')
|
||||
fm.end()
|
||||
|
||||
def exbookmarks(orig, ui, repo, *names, **opts):
|
||||
pattern = opts.get('list_remote')
|
||||
if pattern:
|
||||
remotepath = opts.get('remote_path')
|
||||
path = ui.paths.getpath(remotepath or None, default=('default'))
|
||||
destpath = path.pushloc or path.loc
|
||||
other = hg.peer(repo, opts, destpath)
|
||||
fetchedbookmarks = other.listkeyspatterns('bookmarks',
|
||||
patterns=[pattern])
|
||||
_showbookmarks(ui, fetchedbookmarks, **opts)
|
||||
return
|
||||
return orig(ui, repo, *names, **opts)
|
||||
|
||||
def _checkheads(orig, pushop):
|
||||
if pushop.ui.configbool(experimental, configscratchpush, False):
|
||||
return
|
||||
@ -196,20 +232,15 @@ def localrepolistkeys(orig, self, namespace, patterns=None):
|
||||
if namespace == 'bookmarks' and patterns:
|
||||
index = self.bundlestore.index
|
||||
results = {}
|
||||
patterns = set(patterns)
|
||||
# TODO(stash): this function has a limitation:
|
||||
# patterns are not actually patterns, just simple string comparison
|
||||
for bookmark in patterns:
|
||||
if _scratchbranchmatcher(bookmark):
|
||||
# TODO(stash): use `getbookmarks()` method
|
||||
node = index.getnode(bookmark)
|
||||
if node:
|
||||
results[bookmark] = node
|
||||
|
||||
bookmarks = orig(self, namespace)
|
||||
for bookmark, node in bookmarks.items():
|
||||
if bookmark in patterns:
|
||||
results[bookmark] = node
|
||||
for pattern in patterns:
|
||||
results.update(index.getbookmarks(pattern))
|
||||
if pattern.endswith('*'):
|
||||
pattern = 're:^' + pattern[:-1] + '.*'
|
||||
kind, pat, matcher = util.stringmatcher(pattern)
|
||||
for bookmark, node in bookmarks.items():
|
||||
if matcher(bookmark):
|
||||
results[bookmark] = node
|
||||
return results
|
||||
else:
|
||||
return orig(self, namespace)
|
||||
|
@ -4,6 +4,8 @@ from indexapi import (
|
||||
indexapi,
|
||||
)
|
||||
|
||||
from mercurial import util
|
||||
|
||||
class fileindexapi(indexapi):
|
||||
def __init__(self, repo):
|
||||
super(fileindexapi, self).__init__()
|
||||
@ -36,6 +38,20 @@ class fileindexapi(indexapi):
|
||||
bookmarkpath = os.path.join(self._bookmarkmap, bookmark)
|
||||
return self._read(bookmarkpath)
|
||||
|
||||
def getbookmarks(self, query):
|
||||
result = {}
|
||||
if query.endswith('*'):
|
||||
query = 're:^' + query[:-1] + '.*'
|
||||
kind, pat, matcher = util.stringmatcher(query)
|
||||
prefixlen = len(self._bookmarkmap) + 1
|
||||
for dirpath, _, books in self._repo.vfs.walk(self._bookmarkmap):
|
||||
for book in books:
|
||||
bookmark = os.path.join(dirpath, book)[prefixlen:]
|
||||
if not matcher(bookmark):
|
||||
continue
|
||||
result[bookmark] = self._read(os.path.join(dirpath, book))
|
||||
return result
|
||||
|
||||
def _write(self, path, value):
|
||||
vfs = self._repo.vfs
|
||||
dirname = vfs.dirname(path)
|
||||
|
@ -176,9 +176,31 @@ class sqlindexapi(indexapi):
|
||||
if len(result) != 1 or len(result[0]) != 1:
|
||||
self.log.info("No matching bookmark")
|
||||
return None
|
||||
bookmark = result[0][0]
|
||||
self.log.info("Found node %r" % bookmark)
|
||||
return bookmark
|
||||
node = result[0][0]
|
||||
self.log.info("Found node %r" % node)
|
||||
return node
|
||||
|
||||
def getbookmarks(self, query):
|
||||
if not self._connected:
|
||||
self.sqlconnect()
|
||||
self.log.info(
|
||||
"QUERY BOOKMARKS reponame: %r query: %r" % (self.reponame, query))
|
||||
query = query.replace('_', '\\_')
|
||||
query = query.replace('%', '\\%')
|
||||
if query.endswith('*'):
|
||||
query = query[:-1] + '%'
|
||||
self.sqlcursor.execute(
|
||||
"SELECT bookmark, node from bookmarkstonode WHERE "
|
||||
"reponame = %s AND bookmark LIKE %s",
|
||||
params=(self.reponame, query))
|
||||
result = self.sqlcursor.fetchall()
|
||||
bookmarks = {}
|
||||
for row in result:
|
||||
if len(row) != 2:
|
||||
self.log.info("Bad row returned: %s" % row)
|
||||
continue
|
||||
bookmarks[row[0]] = row[1]
|
||||
return bookmarks
|
||||
|
||||
class CustomConverter(mysql.connector.conversion.MySQLConverter):
|
||||
"""Ensure that all values being returned are returned as python string
|
||||
|
@ -398,3 +398,35 @@ Use --force because this push creates new head
|
||||
|/
|
||||
o initialcommit public
|
||||
|
||||
$ hg book --list-remote scratch/*
|
||||
scratch/anotherbranch 1de1d7d92f8965260391d0513fe8a8d5973d3042
|
||||
scratch/mybranch 8872775dd97a750e1533dc1fbbca665644b32547
|
||||
$ hg book --list-remote scratch/my
|
||||
$ hg book --list-remote scratch/my*
|
||||
scratch/mybranch 8872775dd97a750e1533dc1fbbca665644b32547
|
||||
$ hg book --list-remote scratch/my* -T json
|
||||
[
|
||||
{
|
||||
"bookmark": "scratch/mybranch",
|
||||
"node": "8872775dd97a750e1533dc1fbbca665644b32547"
|
||||
}
|
||||
]
|
||||
$ cd ../repo
|
||||
$ hg book scratch/serversidebook
|
||||
$ hg book serversidebook
|
||||
$ cd ../client
|
||||
$ hg book --list-remote scratch/* -T json
|
||||
[
|
||||
{
|
||||
"bookmark": "scratch/anotherbranch",
|
||||
"node": "1de1d7d92f8965260391d0513fe8a8d5973d3042"
|
||||
},
|
||||
{
|
||||
"bookmark": "scratch/mybranch",
|
||||
"node": "8872775dd97a750e1533dc1fbbca665644b32547"
|
||||
},
|
||||
{
|
||||
"bookmark": "scratch/serversidebook",
|
||||
"node": "0000000000000000000000000000000000000000"
|
||||
}
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user