mirror of
https://github.com/facebook/sapling.git
synced 2024-10-11 17:27:53 +03:00
b55f9db1f0
Summary: The changes from commit cloud sync are supposed to be applied in-memory and committed with cloudsync-transaction to the disk. For example, for bookmarks the changes first are applied to the existing dict of bookmarks and with the transaction are being written to the disk into the `bookmarks` file. Ideally I need to have similar thing for remote bookmarks. However, the current implementation provides of remotenames only read-only store with only possibilty to change something on the disk (`remotenames` file) and upload it to memory. We're planning to rewrite the whole extension at some point, but currently to move forward I added a new method to the store, which will apply changes to the `remotenames` file and reload the remotenames store. It's not transactional and uses existing function `saveremotenames`, which I refactored a little bit, so it could apply changes for multiple remotes at the same time. I also removed deletion of `remotedistance` file as it is deprecated and not used a long time. Reviewed By: markbt Differential Revision: D15921983 fbshipit-source-id: d6b2638db689c0c1b66a6291fc9f0f2c9dac978c
131 lines
4.4 KiB
Python
131 lines
4.4 KiB
Python
# Copyright 2016-2019 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.
|
|
|
|
import json
|
|
import struct
|
|
|
|
from edenscm.mercurial import error, extensions, node as nodemod
|
|
from edenscm.mercurial.i18n import _
|
|
|
|
|
|
def remotebookmarksenabled(ui):
|
|
return "remotenames" in extensions._extensions and ui.configbool(
|
|
"remotenames", "bookmarks"
|
|
)
|
|
|
|
|
|
def readremotebookmarks(ui, repo, other):
|
|
if remotebookmarksenabled(ui):
|
|
remotenamesext = extensions.find("remotenames")
|
|
remotepath = remotenamesext.activepath(repo.ui, other)
|
|
result = {}
|
|
# Let's refresh remotenames to make sure we have it up to date
|
|
# Seems that `repo.names['remotebookmarks']` may return stale bookmarks
|
|
# and it results in deleting scratch bookmarks. Our best guess how to
|
|
# fix it is to use `clearnames()`
|
|
repo._remotenames.clearnames()
|
|
for remotebookmark in repo.names["remotebookmarks"].listnames(repo):
|
|
path, bookname = remotenamesext.splitremotename(remotebookmark)
|
|
if path == remotepath and repo._scratchbranchmatcher.match(bookname):
|
|
nodes = repo.names["remotebookmarks"].nodes(repo, remotebookmark)
|
|
if nodes:
|
|
result[bookname] = nodemod.hex(nodes[0])
|
|
return result
|
|
else:
|
|
return {}
|
|
|
|
|
|
def saveremotebookmarks(repo, newbookmarks, remote):
|
|
remotenamesext = extensions.find("remotenames")
|
|
remotepath = remotenamesext.activepath(repo.ui, remote)
|
|
bookmarks = {}
|
|
remotenames = remotenamesext.readremotenames(repo)
|
|
for hexnode, nametype, remote, rname in remotenames:
|
|
if remote != remotepath:
|
|
continue
|
|
if nametype == "bookmarks":
|
|
if rname in newbookmarks:
|
|
# It's possible if we have a normal bookmark that matches
|
|
# scratch branch pattern. In this case just use the current
|
|
# bookmark node
|
|
del newbookmarks[rname]
|
|
bookmarks[rname] = hexnode
|
|
|
|
for bookmark, hexnode in newbookmarks.iteritems():
|
|
bookmarks[bookmark] = hexnode
|
|
remotenamesext.saveremotenames(repo, {remotepath: bookmarks})
|
|
|
|
|
|
def savelocalbookmarks(repo, bookmarks):
|
|
if not bookmarks:
|
|
return
|
|
with repo.wlock(), repo.lock(), repo.transaction("bookmark") as tr:
|
|
changes = []
|
|
for scratchbook, node in bookmarks.iteritems():
|
|
changectx = repo[node]
|
|
changes.append((scratchbook, changectx.node()))
|
|
repo._bookmarks.applychanges(repo, tr, changes)
|
|
|
|
|
|
def deleteremotebookmarks(ui, repo, path, names):
|
|
"""Prune remote names by removing the bookmarks we don't want anymore,
|
|
then writing the result back to disk
|
|
"""
|
|
remotenamesext = extensions.find("remotenames")
|
|
|
|
# remotename format is:
|
|
# (node, nametype ("bookmarks"), remote, name)
|
|
nametype_idx = 1
|
|
remote_idx = 2
|
|
name_idx = 3
|
|
remotenames = [
|
|
remotename
|
|
for remotename in remotenamesext.readremotenames(repo)
|
|
if remotename[remote_idx] == path
|
|
]
|
|
remote_bm_names = [
|
|
remotename[name_idx]
|
|
for remotename in remotenames
|
|
if remotename[nametype_idx] == "bookmarks"
|
|
]
|
|
|
|
for name in names:
|
|
if name not in remote_bm_names:
|
|
raise error.Abort(
|
|
_("infinitepush bookmark '{}' does not exist " "in path '{}'").format(
|
|
name, path
|
|
)
|
|
)
|
|
|
|
bookmarks = {}
|
|
for node, nametype, remote, name in remotenames:
|
|
if nametype == "bookmarks" and name not in names:
|
|
bookmarks[name] = node
|
|
|
|
remotenamesext.saveremotenames(repo, {path: bookmarks})
|
|
|
|
|
|
def encodebookmarks(bookmarks):
|
|
encoded = {}
|
|
for bookmark, node in bookmarks.iteritems():
|
|
encoded[bookmark] = node
|
|
dumped = json.dumps(encoded)
|
|
result = struct.pack(">i", len(dumped)) + dumped
|
|
return result
|
|
|
|
|
|
def decodebookmarks(stream):
|
|
sizeofjsonsize = struct.calcsize(">i")
|
|
size = struct.unpack(">i", stream.read(sizeofjsonsize))[0]
|
|
unicodedict = json.loads(stream.read(size))
|
|
# python json module always returns unicode strings. We need to convert
|
|
# it back to bytes string
|
|
result = {}
|
|
for bookmark, node in unicodedict.iteritems():
|
|
bookmark = bookmark.encode("ascii")
|
|
node = node.encode("ascii")
|
|
result[bookmark] = node
|
|
return result
|