comparison hgext/lfs/wrapper.py @ 38178:3790efb388ca stable

lfs: bypass wrapped functions when reposetup() hasn't been called (issue5902) There are only a handful of methods that access repo attributes that are applied in reposetup(). The `diff` test covers all of the commands that call scmutil.prefetchfiles(). Along the way, I saw that adding files and upgrading the repo format were also problems (also tested here). I don't think running `hg serve` through the commandserver is sane, but I conditionalized both the capabilities and the wsgirequest handler because it's trivially correct. It doesn't look like there has ever been a caller of candownload(), so there's no test for that path. The upload case isn't testable, because uploadblobs() bails if there are no pointers. The requirement should be added any time pointers are introduced, and that would force the extension to be loaded specifically for the repo. This covers `debuglfsupload`, the pre-push hook (which isn't set until the repo is promoted to LFS), and uploadblobsfromrevs(), which can be called by other extensions. I think readfromstore() and writetostore() are only reachable as a flag processor for revlog.REVIDX_EXTSTORED, and a requirement is added as soon as that is seen, so I don't think those are a problem.
author Matt Harbison <matt_harbison@yahoo.com>
date Thu, 31 May 2018 09:19:09 -0400
parents 7269b87f817c
children 37e56607cbb9
comparison
equal deleted inserted replaced
38040:a3b4ccbec269 38178:3790efb388ca
35 return versions 35 return versions
36 36
37 def _capabilities(orig, repo, proto): 37 def _capabilities(orig, repo, proto):
38 '''Wrap server command to announce lfs server capability''' 38 '''Wrap server command to announce lfs server capability'''
39 caps = orig(repo, proto) 39 caps = orig(repo, proto)
40 # XXX: change to 'lfs=serve' when separate git server isn't required? 40 if util.safehasattr(repo.svfs, 'lfslocalblobstore'):
41 caps.append('lfs') 41 # XXX: change to 'lfs=serve' when separate git server isn't required?
42 caps.append('lfs')
42 return caps 43 return caps
43 44
44 def bypasscheckhash(self, text): 45 def bypasscheckhash(self, text):
45 return False 46 return False
46 47
116 return bool(flags & revlog.REVIDX_EXTSTORED) 117 return bool(flags & revlog.REVIDX_EXTSTORED)
117 118
118 def filelogaddrevision(orig, self, text, transaction, link, p1, p2, 119 def filelogaddrevision(orig, self, text, transaction, link, p1, p2,
119 cachedelta=None, node=None, 120 cachedelta=None, node=None,
120 flags=revlog.REVIDX_DEFAULT_FLAGS, **kwds): 121 flags=revlog.REVIDX_DEFAULT_FLAGS, **kwds):
121 textlen = len(text) 122 # The matcher isn't available if reposetup() wasn't called.
122 # exclude hg rename meta from file size 123 lfstrack = self.opener.options.get('lfstrack')
123 meta, offset = revlog.parsemeta(text) 124
124 if offset: 125 if lfstrack:
125 textlen -= offset 126 textlen = len(text)
126 127 # exclude hg rename meta from file size
127 lfstrack = self.opener.options['lfstrack'] 128 meta, offset = revlog.parsemeta(text)
128 129 if offset:
129 if lfstrack(self.filename, textlen): 130 textlen -= offset
130 flags |= revlog.REVIDX_EXTSTORED 131
132 if lfstrack(self.filename, textlen):
133 flags |= revlog.REVIDX_EXTSTORED
131 134
132 return orig(self, text, transaction, link, p1, p2, cachedelta=cachedelta, 135 return orig(self, text, transaction, link, p1, p2, cachedelta=cachedelta,
133 node=node, flags=flags, **kwds) 136 node=node, flags=flags, **kwds)
134 137
135 def filelogrenamed(orig, self, node): 138 def filelogrenamed(orig, self, node):
245 destrepo.vfs.append('hgrc', util.tonativeeol('\n[extensions]\nlfs=\n')) 248 destrepo.vfs.append('hgrc', util.tonativeeol('\n[extensions]\nlfs=\n'))
246 249
247 def _prefetchfiles(repo, revs, match): 250 def _prefetchfiles(repo, revs, match):
248 """Ensure that required LFS blobs are present, fetching them as a group if 251 """Ensure that required LFS blobs are present, fetching them as a group if
249 needed.""" 252 needed."""
253 if not util.safehasattr(repo.svfs, 'lfslocalblobstore'):
254 return
255
250 pointers = [] 256 pointers = []
251 oids = set() 257 oids = set()
252 localstore = repo.svfs.lfslocalblobstore 258 localstore = repo.svfs.lfslocalblobstore
253 259
254 for rev in revs: 260 for rev in revs:
264 # Recalculating the repo store here allows 'paths.default' that is set 270 # Recalculating the repo store here allows 'paths.default' that is set
265 # on the repo by a clone command to be used for the update. 271 # on the repo by a clone command to be used for the update.
266 blobstore.remote(repo).readbatch(pointers, localstore) 272 blobstore.remote(repo).readbatch(pointers, localstore)
267 273
268 def _canskipupload(repo): 274 def _canskipupload(repo):
275 # Skip if this hasn't been passed to reposetup()
276 if not util.safehasattr(repo.svfs, 'lfsremoteblobstore'):
277 return True
278
269 # if remotestore is a null store, upload is a no-op and can be skipped 279 # if remotestore is a null store, upload is a no-op and can be skipped
270 return isinstance(repo.svfs.lfsremoteblobstore, blobstore._nullremote) 280 return isinstance(repo.svfs.lfsremoteblobstore, blobstore._nullremote)
271 281
272 def candownload(repo): 282 def candownload(repo):
283 # Skip if this hasn't been passed to reposetup()
284 if not util.safehasattr(repo.svfs, 'lfsremoteblobstore'):
285 return False
286
273 # if remotestore is a null store, downloads will lead to nothing 287 # if remotestore is a null store, downloads will lead to nothing
274 return not isinstance(repo.svfs.lfsremoteblobstore, blobstore._nullremote) 288 return not isinstance(repo.svfs.lfsremoteblobstore, blobstore._nullremote)
275 289
276 def uploadblobsfromrevs(repo, revs): 290 def uploadblobsfromrevs(repo, revs):
277 '''upload lfs blobs introduced by revs 291 '''upload lfs blobs introduced by revs
387 remoteblob.writebatch(pointers, repo.svfs.lfslocalblobstore) 401 remoteblob.writebatch(pointers, repo.svfs.lfslocalblobstore)
388 402
389 def upgradefinishdatamigration(orig, ui, srcrepo, dstrepo, requirements): 403 def upgradefinishdatamigration(orig, ui, srcrepo, dstrepo, requirements):
390 orig(ui, srcrepo, dstrepo, requirements) 404 orig(ui, srcrepo, dstrepo, requirements)
391 405
392 srclfsvfs = srcrepo.svfs.lfslocalblobstore.vfs 406 # Skip if this hasn't been passed to reposetup()
393 dstlfsvfs = dstrepo.svfs.lfslocalblobstore.vfs 407 if (util.safehasattr(srcrepo.svfs, 'lfslocalblobstore') and
394 408 util.safehasattr(dstrepo.svfs, 'lfslocalblobstore')):
395 for dirpath, dirs, files in srclfsvfs.walk(): 409 srclfsvfs = srcrepo.svfs.lfslocalblobstore.vfs
396 for oid in files: 410 dstlfsvfs = dstrepo.svfs.lfslocalblobstore.vfs
397 ui.write(_('copying lfs blob %s\n') % oid) 411
398 lfutil.link(srclfsvfs.join(oid), dstlfsvfs.join(oid)) 412 for dirpath, dirs, files in srclfsvfs.walk():
413 for oid in files:
414 ui.write(_('copying lfs blob %s\n') % oid)
415 lfutil.link(srclfsvfs.join(oid), dstlfsvfs.join(oid))
399 416
400 def upgraderequirements(orig, repo): 417 def upgraderequirements(orig, repo):
401 reqs = orig(repo) 418 reqs = orig(repo)
402 if 'lfs' in repo.requirements: 419 if 'lfs' in repo.requirements:
403 reqs.add('lfs') 420 reqs.add('lfs')