mirror of
https://github.com/facebook/sapling.git
synced 2024-10-07 15:27:13 +03:00
8793c18b01
Summary: This creates a revlog implementation that stores all of it's data as key/value pairs remotely. Each revlog entry is stored as "p1 + p2 + text" and is cached in the fileserverclient.cachepath path. Any entries that are local only are stored in .hg/store/localdata. The fileserverclient is used to fetch any remote entries that are not in the cache. Future commits will add support for adding revisions, adding groups from a bundle, and creating groups for a bundle. Mercurial currently uses '.hgtags' in a special way, so I've hardcoded a hack there for now. Test Plan: N/A Reviewers: bryano, sid0, mpm, dschleimer Differential Revision: https://phabricator.fb.com/D802534 Task ID: 2370049
115 lines
3.1 KiB
Python
115 lines
3.1 KiB
Python
# remoterevlog.py - revlog implementation where the content is stored remotely
|
|
#
|
|
# Copyright 2013 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 fileserverclient
|
|
import collections, os
|
|
from mercurial.node import bin, hex, nullid, nullrev
|
|
from mercurial import revlog, mdiff, bundle
|
|
|
|
def _readfile(path):
|
|
f = open(path, "r")
|
|
try:
|
|
return f.read()
|
|
finally:
|
|
f.close()
|
|
|
|
def _writefile(path, content):
|
|
f = open(path, "w")
|
|
try:
|
|
f.write(content)
|
|
finally:
|
|
f.close()
|
|
|
|
class remoterevlog(object):
|
|
"""A partial implementation of the revlog api where the revision contents
|
|
are stored remotely on a server. It differs from normal revlogs in that it
|
|
doesn't have rev numbers.
|
|
"""
|
|
def __init__(self, opener, path):
|
|
self.opener = opener
|
|
self.filename = path[5:-2]
|
|
self.localpath = os.path.join(opener.vfs.base, 'localdata')
|
|
|
|
if not os.path.exists(self.localpath):
|
|
os.makedirs(self.localpath)
|
|
|
|
def __len__(self):
|
|
# hack
|
|
if self.filename == '.hgtags':
|
|
return 0
|
|
|
|
raise Exception("len not supported")
|
|
|
|
def parents(self, node):
|
|
if node == nullid:
|
|
return nullid, nullid
|
|
raw = self._read(hex(node))
|
|
return raw[:20], raw[20:40]
|
|
|
|
def rawsize(self, node):
|
|
return len(self.revision(node))
|
|
size = rawsize
|
|
|
|
def cmp(self, node, text):
|
|
p1, p2 = self.parents(node)
|
|
return revlog.hash(text, p1, p2) != node
|
|
|
|
def revdiff(self, node1, node2):
|
|
return mdiff.textdiff(self.revision(node1),
|
|
self.revision(node2))
|
|
|
|
def lookup(self, node):
|
|
if len(node) == 40:
|
|
node = bin(node)
|
|
if len(node) != 20:
|
|
raise LookupError(node, self.filename, _('invalid lookup input'))
|
|
|
|
return node
|
|
|
|
def revision(self, node):
|
|
if node == nullid:
|
|
return ""
|
|
if len(node) != 20:
|
|
raise LookupError(node, self.filename, _('invalid revision input'))
|
|
|
|
raw = self._read(hex(node))
|
|
return raw[40:]
|
|
|
|
def _read(self, id):
|
|
cachepath = os.path.join(fileserverclient.client.cachepath, id)
|
|
if os.path.exists(cachepath):
|
|
return _readfile(cachepath)
|
|
|
|
result = self._localread(id)
|
|
if result != None:
|
|
return result
|
|
|
|
result = self._remoteread(id)
|
|
|
|
if result == None:
|
|
raise LookupError(id, self.filename, _('no node'))
|
|
|
|
return result
|
|
|
|
def _localread(self, id):
|
|
localpath = os.path.join(self.localpath, id)
|
|
if os.path.exists(localpath):
|
|
return _readfile(localpath)
|
|
|
|
return None
|
|
|
|
def _remoteread(self, id):
|
|
fileserverclient.prefetch(self.opener.vfs.base, [(self.filename, id)])
|
|
|
|
cachepath = os.path.join(fileserverclient.client.cachepath, id)
|
|
if os.path.exists(cachepath):
|
|
return _readfile(cachepath)
|
|
|
|
return None
|
|
|
|
def strip(self, minlink, transaction):
|
|
pass |