logexchange.py
168 lines
| 4.9 KiB
| text/x-python
|
PythonLexer
/ mercurial / logexchange.py
Pulkit Goyal
|
r35348 | # logexchange.py | ||
# | ||||
# Copyright 2017 Augie Fackler <raf@durin42.com> | ||||
# Copyright 2017 Sean Farley <sean@farley.io> | ||||
# | ||||
# This software may be used and distributed according to the terms of the | ||||
# GNU General Public License version 2 or any later version. | ||||
Matt Harbison
|
r52756 | from __future__ import annotations | ||
Pulkit Goyal
|
r35348 | |||
from .node import hex | ||||
from . import ( | ||||
Pulkit Goyal
|
r36076 | util, | ||
Pulkit Goyal
|
r35348 | vfs as vfsmod, | ||
) | ||||
r47669 | from .utils import ( | |||
urlutil, | ||||
) | ||||
Pulkit Goyal
|
r35348 | |||
# directory name in .hg/ in which remotenames files will be present | ||||
Augie Fackler
|
r43347 | remotenamedir = b'logexchange' | ||
Pulkit Goyal
|
r35348 | |||
Augie Fackler
|
r43346 | |||
Pulkit Goyal
|
r35348 | def readremotenamefile(repo, filename): | ||
""" | ||||
reads a file from .hg/logexchange/ directory and yields it's content | ||||
filename: the file to be read | ||||
yield a tuple (node, remotepath, name) | ||||
""" | ||||
vfs = vfsmod.vfs(repo.vfs.join(remotenamedir)) | ||||
if not vfs.exists(filename): | ||||
return | ||||
f = vfs(filename) | ||||
lineno = 0 | ||||
for line in f: | ||||
line = line.strip() | ||||
if not line: | ||||
continue | ||||
# contains the version number | ||||
if lineno == 0: | ||||
lineno += 1 | ||||
try: | ||||
Augie Fackler
|
r43347 | node, remote, rname = line.split(b'\0') | ||
Pulkit Goyal
|
r35348 | yield node, remote, rname | ||
except ValueError: | ||||
pass | ||||
f.close() | ||||
Augie Fackler
|
r43346 | |||
Pulkit Goyal
|
r35348 | def readremotenames(repo): | ||
""" | ||||
read the details about the remotenames stored in .hg/logexchange/ and | ||||
yields a tuple (node, remotepath, name). It does not yields information | ||||
about whether an entry yielded is branch or bookmark. To get that | ||||
information, call the respective functions. | ||||
""" | ||||
Augie Fackler
|
r43347 | for bmentry in readremotenamefile(repo, b'bookmarks'): | ||
Pulkit Goyal
|
r35348 | yield bmentry | ||
Augie Fackler
|
r43347 | for branchentry in readremotenamefile(repo, b'branches'): | ||
Pulkit Goyal
|
r35348 | yield branchentry | ||
Augie Fackler
|
r43346 | |||
Pulkit Goyal
|
r35348 | def writeremotenamefile(repo, remotepath, names, nametype): | ||
vfs = vfsmod.vfs(repo.vfs.join(remotenamedir)) | ||||
Augie Fackler
|
r43347 | f = vfs(nametype, b'w', atomictemp=True) | ||
Pulkit Goyal
|
r35348 | # write the storage version info on top of file | ||
# version '0' represents the very initial version of the storage format | ||||
Augie Fackler
|
r43347 | f.write(b'0\n\n') | ||
Pulkit Goyal
|
r35348 | |||
olddata = set(readremotenamefile(repo, nametype)) | ||||
# re-save the data from a different remote than this one. | ||||
for node, oldpath, rname in sorted(olddata): | ||||
if oldpath != remotepath: | ||||
Augie Fackler
|
r43347 | f.write(b'%s\0%s\0%s\n' % (node, oldpath, rname)) | ||
Pulkit Goyal
|
r35348 | |||
Gregory Szorc
|
r49768 | for name, node in sorted(names.items()): | ||
Augie Fackler
|
r43347 | if nametype == b"branches": | ||
Pulkit Goyal
|
r35348 | for n in node: | ||
Augie Fackler
|
r43347 | f.write(b'%s\0%s\0%s\n' % (n, remotepath, name)) | ||
elif nametype == b"bookmarks": | ||||
Pulkit Goyal
|
r35348 | if node: | ||
Augie Fackler
|
r43347 | f.write(b'%s\0%s\0%s\n' % (node, remotepath, name)) | ||
Pulkit Goyal
|
r35348 | |||
f.close() | ||||
Augie Fackler
|
r43346 | |||
Pulkit Goyal
|
r35348 | def saveremotenames(repo, remotepath, branches=None, bookmarks=None): | ||
""" | ||||
save remotenames i.e. remotebookmarks and remotebranches in their | ||||
respective files under ".hg/logexchange/" directory. | ||||
""" | ||||
wlock = repo.wlock() | ||||
try: | ||||
if bookmarks: | ||||
Augie Fackler
|
r43347 | writeremotenamefile(repo, remotepath, bookmarks, b'bookmarks') | ||
Pulkit Goyal
|
r35348 | if branches: | ||
Augie Fackler
|
r43347 | writeremotenamefile(repo, remotepath, branches, b'branches') | ||
Pulkit Goyal
|
r35348 | finally: | ||
wlock.release() | ||||
Augie Fackler
|
r43346 | |||
Pulkit Goyal
|
r36076 | def activepath(repo, remote): | ||
"""returns remote path""" | ||||
# is the remote a local peer | ||||
local = remote.local() | ||||
# determine the remote path from the repo, if possible; else just | ||||
# use the string given to us | ||||
rpath = remote | ||||
if local: | ||||
Matt Harbison
|
r40471 | rpath = util.pconvert(remote._repo.root) | ||
Pulkit Goyal
|
r37383 | elif not isinstance(remote, bytes): | ||
r50655 | rpath = remote.url() | |||
Pulkit Goyal
|
r36076 | |||
# represent the remotepath with user defined path name if exists | ||||
Augie Fackler
|
r43347 | for path, url in repo.ui.configitems(b'paths'): | ||
Pulkit Goyal
|
r36076 | # remove auth info from user defined url | ||
r47669 | noauthurl = urlutil.removeauth(url) | |||
Matt Harbison
|
r40471 | |||
# Standardize on unix style paths, otherwise some {remotenames} end up | ||||
# being an absolute path on Windows. | ||||
url = util.pconvert(bytes(url)) | ||||
noauthurl = util.pconvert(noauthurl) | ||||
Pulkit Goyal
|
r38001 | if url == rpath or noauthurl == rpath: | ||
Pulkit Goyal
|
r36076 | rpath = path | ||
break | ||||
return rpath | ||||
Augie Fackler
|
r43346 | |||
Pulkit Goyal
|
r35348 | def pullremotenames(localrepo, remoterepo): | ||
""" | ||||
pulls bookmarks and branches information of the remote repo during a | ||||
pull or clone operation. | ||||
localrepo is our local repository | ||||
remoterepo is the peer instance | ||||
""" | ||||
Pulkit Goyal
|
r36076 | remotepath = activepath(localrepo, remoterepo) | ||
Gregory Szorc
|
r37657 | |||
with remoterepo.commandexecutor() as e: | ||||
Augie Fackler
|
r43346 | bookmarks = e.callcommand( | ||
Augie Fackler
|
r46554 | b'listkeys', | ||
{ | ||||
b'namespace': b'bookmarks', | ||||
}, | ||||
Augie Fackler
|
r43346 | ).result() | ||
Gregory Szorc
|
r37657 | |||
Pulkit Goyal
|
r35348 | # on a push, we don't want to keep obsolete heads since | ||
# they won't show up as heads on the next pull, so we | ||||
# remove them here otherwise we would require the user | ||||
# to issue a pull to refresh the storage | ||||
bmap = {} | ||||
repo = localrepo.unfiltered() | ||||
Gregory Szorc
|
r37657 | |||
with remoterepo.commandexecutor() as e: | ||||
Augie Fackler
|
r43347 | branchmap = e.callcommand(b'branchmap', {}).result() | ||
Gregory Szorc
|
r37657 | |||
Gregory Szorc
|
r49768 | for branch, nodes in branchmap.items(): | ||
Pulkit Goyal
|
r35348 | bmap[branch] = [] | ||
for node in nodes: | ||||
if node in repo and not repo[node].obsolete(): | ||||
bmap[branch].append(hex(node)) | ||||
saveremotenames(localrepo, remotepath, bmap, bookmarks) | ||||