##// END OF EJS Templates
largefiles: getstandinmatcher should not depend on existence of directories...
largefiles: getstandinmatcher should not depend on existence of directories Looking for a (potentially empty) directory was not reliable - both because it is a reasonable assumption that empty directories can be removed and because it wasn't created in all cases ... such as when pulling to an existing repository.

File last commit:

r18574:4db9e31a default
r18724:894a5897 stable
Show More
basestore.py
192 lines | 6.8 KiB | text/x-python | PythonLexer
various
hgext: add largefiles extension...
r15168 # Copyright 2009-2010 Gregory P. Ward
# Copyright 2009-2010 Intelerad Medical Systems Incorporated
# Copyright 2010-2011 Fog Creek Software
# Copyright 2010-2011 Unity Technologies
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
Greg Ward
largefiles: improve comments, internal docstrings...
r15252 '''base class for store implementations and store-related utility code'''
various
hgext: add largefiles extension...
r15168
import binascii
import re
from mercurial import util, node, hg
from mercurial.i18n import _
import lfutil
class StoreError(Exception):
'''Raised when there is a problem getting files from or putting
files to a central store.'''
def __init__(self, filename, hash, url, detail):
self.filename = filename
self.hash = hash
self.url = url
self.detail = detail
def longmessage(self):
Wagner Bruna
largefiles: enhance error message to make it more i18n-friendly
r18461 return (_("error getting id %s from url %s for file %s: %s\n") %
Mads Kiilerich
largefiles: cleanup of warnings on errors getting largefiles...
r18155 (self.hash, self.url, self.filename, self.detail))
various
hgext: add largefiles extension...
r15168
def __str__(self):
return "%s: %s" % (self.url, self.detail)
class basestore(object):
def __init__(self, ui, repo, url):
self.ui = ui
self.repo = repo
self.url = url
def put(self, source, hash):
'''Put source file into the store under <filename>/<hash>.'''
raise NotImplementedError('abstract method')
Na'Tosha Bard
largefiles: batch statlfile requests when pushing a largefiles repo (issue3386)...
r17127 def exists(self, hashes):
'''Check to see if the store contains the given hashes.'''
various
hgext: add largefiles extension...
r15168 raise NotImplementedError('abstract method')
def get(self, files):
'''Get the specified largefiles from the store and write to local
files under repo.root. files is a list of (filename, hash)
Mads Kiilerich
fix trivial spelling errors
r17424 tuples. Return (success, missing), lists of files successfully
various
hgext: add largefiles extension...
r15168 downloaded and those not found in the store. success is a list
of (filename, hash) tuples; missing is a list of filenames that
we could not get. (The detailed error message will already have
been presented to the user, so missing is just supplied as a
summary.)'''
success = []
missing = []
ui = self.ui
at = 0
for filename, hash in files:
ui.progress(_('getting largefiles'), at, unit='lfile',
total=len(files))
at += 1
ui.note(_('getting %s:%s\n') % (filename, hash))
Benjamin Pollack
largefiles: rename functions and methods to match desired behavior...
r15316 storefilename = lfutil.storepath(self.repo, hash)
Mads Kiilerich
largefiles: don't allow corruption to propagate after detection...
r18483 tmpfile = util.atomictempfile(storefilename + '.tmp',
Martin Geisler
largefiles: respect store.createmode in basestore.get...
r16154 createmode=self.repo.store.createmode)
various
hgext: add largefiles extension...
r15168
try:
hhash = binascii.hexlify(self._getfile(tmpfile, filename, hash))
except StoreError, err:
ui.warn(err.longmessage())
hhash = ""
Mads Kiilerich
largefiles: don't allow corruption to propagate after detection...
r18483 tmpfile.close() # has probably already been closed!
various
hgext: add largefiles extension...
r15168
if hhash != hash:
if hhash != "":
ui.warn(_('%s: data corruption (expected %s, got %s)\n')
% (filename, hash, hhash))
Mads Kiilerich
largefiles: don't allow corruption to propagate after detection...
r18483 util.unlink(storefilename + '.tmp')
various
hgext: add largefiles extension...
r15168 missing.append(filename)
continue
Mads Kiilerich
largefiles: don't allow corruption to propagate after detection...
r18483 util.rename(storefilename + '.tmp', storefilename)
Benjamin Pollack
largefiles: rename functions and methods to match desired behavior...
r15316 lfutil.linktousercache(self.repo, hash)
various
hgext: add largefiles extension...
r15168 success.append((filename, hhash))
ui.progress(_('getting largefiles'), None)
return (success, missing)
def verify(self, revs, contents=False):
'''Verify the existence (and, optionally, contents) of every big
file revision referenced by every changeset in revs.
Return 0 if all is well, non-zero on any errors.'''
write = self.ui.write
failed = False
write(_('searching %d changesets for largefiles\n') % len(revs))
verified = set() # set of (filename, filenode) tuples
for rev in revs:
cctx = self.repo[rev]
cset = "%d:%s" % (cctx.rev(), node.short(cctx.node()))
Mads Kiilerich
largefiles: verify all files in each revision and report errors in any revision...
r18486 for standin in cctx:
if self._verifyfile(cctx, cset, contents, standin, verified):
failed = True
various
hgext: add largefiles extension...
r15168
Na'Tosha Bard
largefiles: remove use of underscores that breaks coding convention
r16247 numrevs = len(verified)
numlfiles = len(set([fname for (fname, fnode) in verified]))
various
hgext: add largefiles extension...
r15168 if contents:
write(_('verified contents of %d revisions of %d largefiles\n')
Na'Tosha Bard
largefiles: remove use of underscores that breaks coding convention
r16247 % (numrevs, numlfiles))
various
hgext: add largefiles extension...
r15168 else:
write(_('verified existence of %d revisions of %d largefiles\n')
Na'Tosha Bard
largefiles: remove use of underscores that breaks coding convention
r16247 % (numrevs, numlfiles))
various
hgext: add largefiles extension...
r15168
return int(failed)
def _getfile(self, tmpfile, filename, hash):
'''Fetch one revision of one file from the store and write it
to tmpfile. Compute the hash of the file on-the-fly as it
downloads and return the binary hash. Close tmpfile. Raise
StoreError if unable to download the file (e.g. it does not
exist in the store).'''
raise NotImplementedError('abstract method')
def _verifyfile(self, cctx, cset, contents, standin, verified):
'''Perform the actual verification of a file in the store.
'''
raise NotImplementedError('abstract method')
import localstore, wirestore
_storeprovider = {
'file': [localstore.localstore],
'http': [wirestore.wirestore],
'https': [wirestore.wirestore],
'ssh': [wirestore.wirestore],
}
_scheme_re = re.compile(r'^([a-zA-Z0-9+-.]+)://')
# 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, remote=None, put=False):
ui = repo.ui
if not remote:
Na'Tosha Bard
largefiles: fix caching largefiles from an aliased repo (issue3212)
r15943 lfpullsource = getattr(repo, 'lfpullsource', None)
if lfpullsource:
path = ui.expandpath(lfpullsource)
else:
path = ui.expandpath('default-push', 'default')
Greg Ward
largefiles: improve comments, internal docstrings...
r15252
# ui.expandpath() leaves 'default-push' and 'default' alone if
# they cannot be expanded: fallback to the empty string,
# meaning the current directory.
various
hgext: add largefiles extension...
r15168 if path == 'default-push' or path == 'default':
path = ''
remote = repo
else:
Mads Kiilerich
largefiles: allow use of urls with #revision...
r18489 path, _branches = hg.parseurl(path)
various
hgext: add largefiles extension...
r15168 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
Matt Mackall
largefile: fix up hasattr usage
r15169 path = util.safehasattr(remote, 'url') and remote.url() or remote.path
various
hgext: add largefiles extension...
r15168
match = _scheme_re.match(path)
if not match: # regular filesystem path
scheme = 'file'
else:
scheme = match.group(1)
try:
storeproviders = _storeprovider[scheme]
except KeyError:
raise util.Abort(_('unsupported URL scheme %r') % scheme)
Na'Tosha Bard
largefiles: remove use of underscores that breaks coding convention
r16247 for classobj in storeproviders:
various
hgext: add largefiles extension...
r15168 try:
Na'Tosha Bard
largefiles: remove use of underscores that breaks coding convention
r16247 return classobj(ui, repo, remote)
various
hgext: add largefiles extension...
r15168 except lfutil.storeprotonotcapable:
pass
Hao Lian
largefiles: string formatting typo in basestore._openstore where comma is used instead of modulo
r15302 raise util.Abort(_('%s does not appear to be a largefile store') % path)