Changeset 3f4083dafa13…
Parent 35d64ba16cb6…
by Benjamin Pollack <benjamin@fogcreek.com>
Changes to 31 files · Browse files at 3f4083dafa13 Showing diff from parent 35d64ba16cb6 Diff from another changeset...
@@ -20,8 +20,8 @@ version.
'''
-from mercurial import commands
-from mercurial import wireproto
+from mercurial import commands, localrepo, wireproto
+from mercurial.hgweb import hgweb_mod
import bfsetup
import bfcommands
@@ -39,8 +39,22 @@ wireproto.commands['getbfile'] = (bfproto.getbfile, 'sha')
wireproto.commands['statbfile'] = (bfproto.statbfile, 'sha')
wireproto.commands['capabilities'] = (bfproto.capabilities, '')
+ wireproto.commands['heads'] = (bfproto.heads, '')
+
+ # make putbfile behave the same as push and {get,stat}bfile behave the same
+ # as pull w.r.t. permissions checks
+ hgweb_mod.perms['putbfile'] = 'push'
+ hgweb_mod.perms['getbfile'] = 'pull'
+ hgweb_mod.perms['statbfile'] = 'pull'
+
+ # the hello wireproto command uses wireproto.capabilities, so it won't see
+ # our bfilestore capability unless we replace the actual function as well.
+ # we also need to save the existing function for local use.
+ # this is really ugly.
+ # however, the alternative would be to parse hello's output and rewrite the
+ # capabilities line.
+ bfproto.capabilities_orig = wireproto.capabilities
+ wireproto.capabilities = bfproto.capabilities
wireproto.dispatch = bfproto.dispatch
- wireproto.wirerepository.putbfile = bfproto.wirerepo_putbfile
- wireproto.wirerepository.getbfile = bfproto.wirerepo_getbfile
- wireproto.wirerepository.statbfile = bfproto.wirerepo_statbfile
+ localrepo.localrepository.supported |= set(['kbfiles'])
|
|
@@ -9,6 +9,7 @@ from mercurial.i18n import _
import bfutil
+import remotestore
class StoreError(Exception):
'''Raised when there is a problem getting files from or putting
@@ -61,14 +62,16 @@
at = 0
for filename, hash in files:
- ui.progress(_('getting kbfiles'), at, unit='kbfile', total=len(files))
+ ui.progress(_('getting kbfiles'), at, unit='kbfile',
+ total=len(files))
at += 1
ui.note(_('getting %s\n') % filename)
outfilename = self.repo.wjoin(filename)
destdir = os.path.dirname(outfilename)
util.makedirs(destdir)
if not os.path.isdir(destdir):
- self.abort(error.RepoError(_('cannot create dest directory %s') % destdir))
+ self.abort(error.RepoError(_('cannot create dest directory %s')
+ % destdir))
# No need to pass mode='wb' to fdopen(), since mkstemp() already
# opened the file in binary mode.
@@ -95,7 +98,8 @@ if os.path.exists(outfilename): # for windows
os.remove(outfilename)
os.rename(tmpfilename, outfilename)
- bfutil.copytocache(self.repo, self.repo['.'].node(), filename, True)
+ bfutil.copytocache(self.repo, self.repo['.'].node(), filename,
+ True)
success.append((filename, hhash))
ui.progress(_('getting bfiles'), None)
@@ -147,12 +151,13 @@ '''
raise NotImplementedError('abstract method')
-import localstore, httpstore
+import localstore, kilnstore, wirestore
_storeprovider = {
- 'file': (localstore, 'localstore'),
- 'http': (httpstore, 'httpstore'),
- 'https': (httpstore, 'httpstore'),
+ 'file': [(localstore, 'localstore')],
+ 'http': [(wirestore, 'wirestore'), (kilnstore, 'kilnstore')],
+ 'https': [(wirestore, 'wirestore'), (kilnstore, 'kilnstore')],
+ 'ssh': [(wirestore, 'wirestore')],
}
_scheme_re = re.compile(r'^([a-zA-Z0-9+-.]+)://')
@@ -160,22 +165,24 @@# During clone this function is passed the src's ui object
# but it needs the dest's ui object so it can read out of
# the config file. Use repo.ui instead.
-def _openstore(repo, path=None, put=False):
+def _openstore(repo, remote=None, put=False):
ui = repo.ui
- if not path:
- path = getattr(repo, 'bfpullsource', None)
- if not path:
- path = ui.expandpath('default-push', 'default')
- # If 'default-push' and 'default' can't be expanded
- # they are just returned. In that case fail with an informative
- # error message
- if path in ('default-push', 'default'):
- path = ''
+
+ if not remote:
+ path = getattr(repo, 'bfpullsource', None) or \
+ ui.expandpath('default-push', 'default')
+ # If 'default-push' and 'default' can't be expanded
+ # they are just returned. In that case use the empty string which
+ # use the filescheme.
+ if path == 'default-push' or path == 'default':
+ path = ''
+ remote = repo
+ else:
+ remote = hg.peer(repo, {}, path)
# The path could be a scheme so use Mercurial's normal functionality
# to resolve the scheme to a repository and use its path
- if path:
- path = hg.repository(ui, path).path
+ path = hasattr(remote, 'url') and remote.url() or remote.path
match = _scheme_re.match(path)
if not match: # regular filesystem path
@@ -184,9 +191,15 @@ scheme = match.group(1)
try:
- mod, klass = _storeprovider[scheme]
+ storeproviders = _storeprovider[scheme]
except KeyError:
raise util.Abort(_('unsupported URL scheme %r') % scheme)
- klass = getattr(mod, klass)
- return klass(ui, repo, path)
+ for (mod, klass) in storeproviders:
+ klass = getattr(mod, klass)
+ try:
+ return klass(ui, repo, remote)
+ except remotestore.storeprotonotcapable:
+ pass
+
+ raise util.Abort(_('%s does not appear to be a bfile store'), path)
|
|
|
@@ -6,7 +6,8 @@ from mercurial import util, match as match_, hg, node, context, error
from mercurial.i18n import _
-import bfutil, basestore
+import bfutil
+import basestore
# -- Commands ----------------------------------------------------------
@@ -32,7 +33,8 @@ try:
size = int(size)
except ValueError:
- raise util.Abort(_('bfiles.size must be integer, was %s\n') % size)
+ raise util.Abort(_('bfiles.size must be integer, was %s\n') % \
+ size)
except TypeError:
raise util.Abort(_('size must be specified'))
@@ -67,7 +69,8 @@ # is to simply walk the changelog, using changelog.nodesbewteen().
# Take a look at mercurial/revlog.py:639 for more details.
# Use a generator instead of a list to decrease memory usage
- ctxs = (rsrc[ctx] for ctx in rsrc.changelog.nodesbetween(None, rsrc.heads())[0])
+ ctxs = (rsrc[ctx] for ctx in rsrc.changelog.nodesbetween(None,
+ rsrc.heads())[0])
revmap = {node.nullid: node.nullid}
if tobfile:
bfiles = set()
@@ -83,9 +86,10 @@
bfiletohash = {}
for ctx in ctxs:
- ui.progress(_('converting revisions'), ctx.rev(), unit=_('revision'), total=rsrc['tip'].rev())
+ ui.progress(_('converting revisions'), ctx.rev(),
+ unit=_('revision'), total=rsrc['tip'].rev())
_bfconvert_addchangeset(rsrc, rdst, ctx, revmap,
- bfiles, normalfiles, matcher, size, bfiletohash)
+ bfiles, normalfiles, matcher, size, bfiletohash)
ui.progress(_('converting revisions'), None)
if os.path.exists(rdst.wjoin(bfutil.shortname)):
@@ -101,7 +105,8 @@
else:
for ctx in ctxs:
- ui.progress(_('converting revisions'), ctx.rev(), unit=_('revision'), total=rsrc['tip'].rev())
+ ui.progress(_('converting revisions'), ctx.rev(),
+ unit=_('revision'), total=rsrc['tip'].rev())
_addchangeset(ui, rsrc, rdst, ctx, revmap)
ui.progress(_('converting revisions'), None)
@@ -152,8 +157,12 @@ path = bfutil.findfile(rsrc, hash)
### TODO: What if the file is not cached?
data = ''
- with open(path, 'rb') as fd:
+ fd = None
+ try:
+ fd = open(path, 'rb')
data = fd.read()
+ finally:
+ if fd: fd.close()
return context.memfilectx(f, data, 'l' in fctx.flags(),
'x' in fctx.flags(), renamed)
else:
@@ -169,7 +178,8 @@ newdata = []
for line in data.splitlines():
id, name = line.split(' ', 1)
- newdata.append('%s %s\n' % (node.hex(revmap[node.bin(id)]), name))
+ newdata.append('%s %s\n' % (node.hex(revmap[node.bin(id)]),
+ name))
data = ''.join(newdata)
return context.memfilectx(f, data, 'l' in fctx.flags(),
'x' in fctx.flags(), renamed)
@@ -187,7 +197,8 @@ rdst.dirstate.setparents(ret)
revmap[ctx.node()] = rdst.changelog.tip()
-def _bfconvert_addchangeset(rsrc, rdst, ctx, revmap, bfiles, normalfiles, matcher, size, bfiletohash):
+def _bfconvert_addchangeset(rsrc, rdst, ctx, revmap, bfiles, normalfiles,
+ matcher, size, bfiletohash):
# Convert src parents to dst parents
parents = []
for p in ctx.parents():
@@ -224,7 +235,8 @@ isbfile |= renamedbfile
if 'l' in fctx.flags():
if renamedbfile:
- raise util.Abort(_('Renamed/copied bfile %s becomes symlink') % f)
+ raise util.Abort(
+ _('Renamed/copied bfile %s becomes symlink') % f)
isbfile = False
if isbfile:
bfiles.add(f)
@@ -246,11 +258,16 @@ m.update(ctx[f].data())
hash = m.hexdigest()
if f not in bfiletohash or bfiletohash[f] != hash:
- with open(fullpath, 'wb') as fd:
+ try:
+ fd = open(fullpath, 'wb')
fd.write(ctx[f].data())
+ finally:
+ if fd:
+ fd.close()
executable = 'x' in ctx[f].flags()
os.chmod(fullpath, bfutil.getmode(executable))
- bfutil.writestandin(rdst, bfutil.standin(f), hash, executable)
+ bfutil.writestandin(rdst, bfutil.standin(f), hash,
+ executable)
bfiletohash[f] = hash
else:
# normal file
@@ -271,7 +288,8 @@ # doesn't change after rename or copy
renamed = bfutil.standin(renamed[0])
- return context.memfilectx(f, bfiletohash[srcfname], 'l' in fctx.flags(),
+ return context.memfilectx(f, bfiletohash[srcfname], 'l' in
+ fctx.flags(),
'x' in fctx.flags(), renamed)
else:
try:
@@ -287,7 +305,8 @@ newdata = []
for line in data.splitlines():
id, name = line.split(' ', 1)
- newdata.append('%s %s\n' % (node.hex(revmap[node.bin(id)]), name))
+ newdata.append('%s %s\n' % (node.hex(revmap[node.bin(id)]),
+ name))
data = ''.join(newdata)
return context.memfilectx(f, data, 'l' in fctx.flags(),
'x' in fctx.flags(), renamed)
@@ -317,15 +336,12 @@def uploadbfiles(ui, rsrc, rdst, files):
'''upload big files to the central store'''
- if not files:
+ # Don't upload locally. All bfiles are in the system wide cache
+ # so the other repo can just get them from there.
+ if not files or rdst.local():
return
- # Don't upload locally. All bfiles are in the system wide cache
- # so the other repo can just get them from there.
- if not rdst.path.startswith('http'):
- return
-
- store = basestore._openstore(rsrc, rdst.path, put=True)
+ store = basestore._openstore(rsrc, rdst, put=True)
at = 0
for hash in files:
@@ -348,7 +364,8 @@ matches the revision ID). With --all, check every changeset in
this repository.'''
if all:
- # Pass a list to the function rather than an iterator because we know a list will work.
+ # Pass a list to the function rather than an iterator because we know a
+ # list will work.
revs = range(len(repo))
else:
revs = ['.']
@@ -360,24 +377,28 @@ wlock = repo.wlock()
try:
bfdirstate = bfutil.openbfdirstate(ui, repo)
- s = bfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False, False, False)
- (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
+ s = bfdirstate.status(match_.always(repo.root, repo.getcwd()), [],
+ False, False, False)
+ unsure, modified, added, removed, missing, unknown, ignored, clean = s
bfiles = bfutil.listbfiles(repo)
toget = []
at = 0
updated = 0
for bfile in bfiles:
- if filelist == None or bfile in filelist:
+ if filelist is None or bfile in filelist:
if not os.path.exists(repo.wjoin(bfutil.standin(bfile))):
bfdirstate.remove(bfile)
continue
- if os.path.exists(repo.wjoin(bfutil.standin(os.path.join(bfile + '.orig')))):
- shutil.copyfile(repo.wjoin(bfile), repo.wjoin(bfile + '.orig'))
+ if os.path.exists(repo.wjoin(bfutil.standin(os.path.join(bfile\
+ + '.orig')))):
+ shutil.copyfile(repo.wjoin(bfile), repo.wjoin(bfile + \
+ '.orig'))
at += 1
expectedhash = repo[None][bfutil.standin(bfile)].data().strip()
mode = os.stat(repo.wjoin(bfutil.standin(bfile))).st_mode
- if not os.path.exists(repo.wjoin(bfile)) or expectedhash != bfutil.hashfile(repo.wjoin(bfile)):
+ if not os.path.exists(repo.wjoin(bfile)) or expectedhash != \
+ bfutil.hashfile(repo.wjoin(bfile)):
path = bfutil.findfile(repo, expectedhash)
if path is None:
toget.append((bfile, expectedhash))
@@ -388,19 +409,24 @@ updated += 1
if bfutil.standin(bfile) not in repo['.']:
bfdirstate.add(bfutil.unixpath(bfile))
- elif expectedhash == repo['.'][bfutil.standin(bfile)].data().strip():
+ elif expectedhash == repo['.'][bfutil.standin(bfile)] \
+ .data().strip():
bfdirstate.normal(bfutil.unixpath(bfile))
else:
- bfutil.dirstate_normaldirty(bfdirstate, bfutil.unixpath(bfile))
- elif os.path.exists(repo.wjoin(bfile)) and mode != os.stat(repo.wjoin(bfile)).st_mode:
+ bfutil.dirstate_normaldirty(bfdirstate,
+ bfutil.unixpath(bfile))
+ elif os.path.exists(repo.wjoin(bfile)) and mode != \
+ os.stat(repo.wjoin(bfile)).st_mode:
os.chmod(repo.wjoin(bfile), mode)
updated += 1
if bfutil.standin(bfile) not in repo['.']:
bfdirstate.add(bfutil.unixpath(bfile))
- elif expectedhash == repo['.'][bfutil.standin(bfile)].data().strip():
+ elif expectedhash == \
+ repo['.'][bfutil.standin(bfile)].data().strip():
bfdirstate.normal(bfutil.unixpath(bfile))
else:
- bfutil.dirstate_normaldirty(bfdirstate, bfutil.unixpath(bfile))
+ bfutil.dirstate_normaldirty(bfdirstate,
+ bfutil.unixpath(bfile))
if toget:
store = basestore._openstore(repo)
@@ -417,7 +443,8 @@ elif hash == repo['.'][bfutil.standin(filename)].data().strip():
bfdirstate.normal(bfutil.unixpath(filename))
else:
- bfutil.dirstate_normaldirty(bfdirstate, bfutil.unixpath(filename))
+ bfutil.dirstate_normaldirty(bfdirstate,
+ bfutil.unixpath(filename))
removed = 0
for bfile in bfdirstate:
@@ -453,8 +480,9 @@ wlock = repo.wlock()
try:
bfdirstate = bfutil.openbfdirstate(ui, repo)
- s = bfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False, False, False)
- (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
+ s = bfdirstate.status(match_.always(repo.root, repo.getcwd()), [],
+ False, False, False)
+ unsure, modified, added, removed, missing, unknown, ignored, clean = s
bfiles = bfutil.listbfiles(repo)
toget = []
@@ -468,14 +496,16 @@
for bfile in bfiles:
at += 1
- if os.path.exists(repo.wjoin(bfile)) and not os.path.exists(repo.wjoin(bfutil.standin(bfile))):
+ if os.path.exists(repo.wjoin(bfile)) and not \
+ os.path.exists(repo.wjoin(bfutil.standin(bfile))):
os.unlink(repo.wjoin(bfile))
removed += 1
bfdirstate.forget(bfutil.unixpath(bfile))
continue
expectedhash = repo[None][bfutil.standin(bfile)].data().strip()
mode = os.stat(repo.wjoin(bfutil.standin(bfile))).st_mode
- if not os.path.exists(repo.wjoin(bfile)) or expectedhash != bfutil.hashfile(repo.wjoin(bfile)):
+ if not os.path.exists(repo.wjoin(bfile)) or expectedhash != \
+ bfutil.hashfile(repo.wjoin(bfile)):
path = bfutil.findfile(repo, expectedhash)
if not path:
toget.append((bfile, expectedhash))
@@ -485,7 +515,8 @@ os.chmod(repo.wjoin(bfile), mode)
updated += 1
bfdirstate.normal(bfutil.unixpath(bfile))
- elif os.path.exists(repo.wjoin(bfile)) and mode != os.stat(repo.wjoin(bfile)).st_mode:
+ elif os.path.exists(repo.wjoin(bfile)) and mode != \
+ os.stat(repo.wjoin(bfile)).st_mode:
os.chmod(repo.wjoin(bfile), mode)
updated += 1
bfdirstate.normal(bfutil.unixpath(bfile))
@@ -520,7 +551,8 @@
bfdirstate.write()
if printed:
- ui.status(_('%d big files updated, %d removed\n') % (updated, removed))
+ ui.status(_('%d big files updated, %d removed\n') % (updated,
+ removed))
finally:
wlock.release()
@@ -529,8 +561,10 @@
cmdtable = {
'kbfconvert': (bfconvert,
- [('s', 'size', 0, 'All files over this size '
- '(in megabytes) will be considered bfiles. This can also be specified in your hgrc as [bfiles].size.'),
- ('','tonormal',False, 'Convert from a bfiles repo to a normal repo')],
+ [('s', 'size', 0, 'All files over this size (in megabytes) '
+ 'will be considered bfiles. This can also be specified in '
+ 'your hgrc as [bfiles].size.'),
+ ('','tonormal',False,
+ 'Convert from a bfiles repo to a normal repo')],
_('hg kbfconvert SOURCE DEST [FILE ...]')),
}
|
|
@@ -1,57 +1,151 @@ - import tempfile, shutil, os
+import os
+import shutil
+import tempfile
+import urllib2
from mercurial.i18n import _
-from mercurial import wireproto, error, util
+from mercurial import error, httprepo, util, wireproto
-import bfutil, bfsetup
+import bfsetup
+import bfutil
+
+_heads_prefix = 'kbfiles\n'
def putbfile(repo, proto, sha):
- fd, tempname = tempfile.mkstemp(prefix='hg-putbfile-')
- with os.fdopen(fd, 'wb+') as fp:
- proto.getfile(fp)
- bfutil.copytocacheabsolute(repo, tempname, sha)
- return ''
+ """putbfile puts a bfile into a repository's local cache and into the
+ system cache."""
+ f = None
+ proto.redirect()
+ try:
+ try:
+ f = tempfile.NamedTemporaryFile(mode='wb+', prefix='hg-putbfile-')
+ proto.getfile(f)
+ f.seek(0)
+ if sha != bfutil.hexsha1(f):
+ return wireproto.pushres(1)
+ bfutil.copytocacheabsolute(repo, f.name, sha)
+ except IOError:
+ repo.ui.warn(
+ _('error: could not put received data into bfile store'))
+ return wireproto.pushres(1)
+ finally:
+ if f:
+ f.close()
+
+ return wireproto.pushres(0)
def getbfile(repo, proto, sha):
+ """getbfile retrieves a bfile from the repository-local cache or system
+ cache."""
filename = bfutil.findfile(repo, sha)
if not filename:
raise util.Abort(_('requested bfile %s not present in cache') % sha)
f = open(filename, 'rb')
- return wireproto.streamres(f)
+ length = os.fstat(f.fileno())[6]
+ # since we can't set an HTTP content-length header here, and mercurial core
+ # provides no way to give the length of a streamres (and reading the entire
+ # file into RAM would be ill-advised), we just send the length on the first
+ # line of the response, like the ssh proto does for string responses.
+ def generator():
+ yield '%d\n' % length
+ for chunk in f:
+ yield chunk
+ return wireproto.streamres(generator())
-# '0' for OK, '1' for invalid checksum, '2' for missing
def statbfile(repo, proto, sha):
+ """statbfile sends '2\n' if the bfile is missing, '1\n' if it has a
+ mismatched checksum, or '0\n' if it is in good condition"""
filename = bfutil.findfile(repo, sha)
if not filename:
return '2\n'
- with open(filename, 'rb') as f:
- return '0\n' if bfutil.hexsha1(f) == sha else '1\n'
+ fd = None
+ try:
+ fd = open(filename, 'rb')
+ return bfutil.hexsha1(fd) == sha and '0\n' or '1\n'
+ finally:
+ if fd:
+ fd.close()
-def wirerepo_putbfile(self, sha, fd):
- return self._callstream("putbfile", data=fd, sha=sha, headers={'content-type':'application/mercurial-0.1'})
+def wirereposetup(ui, repo):
+ class kbfileswirerepository(repo.__class__):
+ def putbfile(self, sha, fd):
+ # unfortunately, httprepository._callpush tries to convert its
+ # input file-like into a bundle before sending it, so we can't use
+ # it ...
+ if issubclass(self.__class__, httprepo.httprepository):
+ try:
+ return int(self._call('putbfile', data=fd, sha=sha,
+ headers={'content-type':'application/mercurial-0.1'}))
+ except (ValueError, urllib2.HTTPError):
+ return 1
+ # ... but we can't use sshrepository._call because the data=
+ # argument won't get sent, and _callpush does exactly what we want
+ # in this case: send the data straight through
+ else:
+ try:
+ ret, output = self._callpush("putbfile", fd, sha=sha,
+ headers={'content-type':'application/mercurial-0.1'})
+ if ret == "":
+ raise error.ResponseError(_('putbfile failed:'),
+ output)
+ return int(ret)
+ except IOError:
+ return 1
+ except ValueError:
+ raise error.ResponseError(
+ _('putbfile failed (unexpected response):'), ret)
-def wirerepo_getbfile(self, sha):
- return self._callstream("getbfile", sha=sha)
+ def getbfile(self, sha):
+ stream = self._callstream("getbfile", sha=sha)
+ length = stream.readline()
+ try:
+ length = int(length)
+ except ValueError:
+ self._abort(error.ResponseError(_("unexpected response:"), l))
+ return (length, stream)
-def wirerepo_statbfile(self, sha):
- try:
- return int(self._call("statbfile", sha=sha))
- except:
- return 2
- # if the server returns something that's not an integer followed by a
- # newline, it's not kbfiles-capable, so obviously it doesn't have the
- # bfile; any other exception means _something_ went wrong, so tell the
- # caller the bfile is missing
+ def statbfile(self, sha):
+ try:
+ return int(self._call("statbfile", sha=sha))
+ except (ValueError, urllib2.HTTPError):
+ # if the server returns anything but an integer followed by a
+ # newline, newline, it's not speaking our language; if we get
+ # an HTTP error, we can't be sure the bfile is present; either
+ # way, consider it missing
+ return 2
+ @wireproto.batchable
+ def heads(self):
+ f = wireproto.future()
+ yield {}, f
+ d = f.value
+ if d[:len(_heads_prefix)] == _heads_prefix:
+ d = d[len(_heads_prefix):]
+ try:
+ yield wireproto.decodelist(d[:-1])
+ except ValueError:
+ self._abort(error.ResponseError(_("unexpected response:"), d))
+ repo.__class__ = kbfileswirerepository
+
+# wrap dispatch to check for and remove the kbfiles argument so commands with
+# fixed argument lists don't complain
def dispatch(repo, proto, command):
func, spec = wireproto.commands[command]
args = proto.getargs(spec)
+
+ # remove the kbfiles argument and ignore it: it still needs to be sent
+ # to avoid breaking compatibility with older versions of the extension,
+ # but it is unused in current versions
if len(args) > 0 and isinstance(args[-1], dict):
- if bfutil.listbfiles(repo) and command in affectedcommands and not args[-1].pop('kbfiles'):
- return '0\n'
+ args[-1].pop('kbfiles', None)
+
return func(repo, proto, *args)
+# advertise the bfilestore=serve capability
def capabilities(repo, proto):
- return wireproto.capabilities(repo, proto) + ' bfilestore=serve'
+ return capabilities_orig(repo, proto) + ' bfilestore=serve'
-affectedcommands = [ 'changegroup', 'changegroupsubset', 'getbundle', 'unbundle', 'stream_out', 'pushkey' ]
+def heads(repo, proto):
+ if bfutil.iskbfilesrepo(repo):
+ return _heads_prefix + wireproto.heads(repo, proto)
+ return wireproto.heads(repo, proto)
|
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
|
@@ -0,0 +1,45 @@ + '''HTTP-based store for Kiln.'''
+
+import urllib2
+
+from mercurial import util, url as url_
+
+import bfutil
+import remotestore
+
+class kilnstore(remotestore.remotestore):
+ def __init__(self, ui, repo, remote):
+ self.baseurl = bfutil.urljoin(remote.url(), 'bfile')
+ try:
+ # Mercurial >= 1.9
+ self.baseurl, authinfo = util.url(self.baseurl).authinfo()
+ except AttributeError:
+ # Mercurial <= 1.8
+ self.baseurl, authinfo = url_.getauthinfo(self.baseurl)
+ self.opener = url_.opener(repo.ui, authinfo)
+ super(kilnstore, self).__init__(ui, repo, remote.url())
+
+ def _put(self, hash, fd):
+ try:
+ req = urllib2.Request(bfutil.urljoin(self.baseurl, hash), fd)
+ resp = self.opener.open(req)
+ return self._stat(hash) and 1 or 0
+ except urllib2.HTTPError, e:
+ return 1
+
+ def _get(self, hash):
+ req = urllib2.Request(bfutil.urljoin(self.baseurl, hash))
+ return (None, self.opener.open(req))
+
+ # '0' for OK, '1' for invalid checksum, '2' for missing
+ def _stat(self, hash):
+ try:
+ req = urllib2.Request(bfutil.urljoin(self.baseurl, hash))
+ req.add_header('SHA1-Request', hash)
+ return int(hash != \
+ self.opener.open(req).info().getheader('Content-SHA1'))
+ except urllib2.HTTPError, e:
+ if e.code == 404:
+ return 2
+ else:
+ raise
|
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
@@ -12,7 +12,7 @@
DEFAULTRC = {
'extensions': [('kbfiles', kilntest.KBFILESPATH),
- ('rebase', '')],
+ ('rebase', '')],
'kilnbfiles': [('systemcache', os.path.join(os.getcwd(), 'bfilesstore')),],
}
|
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
@@ -1,6 +1,6 @@ #!/usr/bin/env python
-# Test that kbfconvert handles tags properly
+# Test that kbfconvert handles tags properly
import os
import common
|
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
Loading...