comparison hgext/largefiles/overrides.py @ 43076:2372284d9457

formatting: blacken the codebase This is using my patch to black (https://github.com/psf/black/pull/826) so we don't un-wrap collection literals. Done with: hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S # skip-blame mass-reformatting only # no-check-commit reformats foo_bar functions Differential Revision: https://phab.mercurial-scm.org/D6971
author Augie Fackler <augie@google.com>
date Sun, 06 Oct 2019 09:45:02 -0400
parents 749ef8c31187
children 687b865b95ad
comparison
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
12 import copy 12 import copy
13 import os 13 import os
14 14
15 from mercurial.i18n import _ 15 from mercurial.i18n import _
16 16
17 from mercurial.hgweb import ( 17 from mercurial.hgweb import webcommands
18 webcommands,
19 )
20 18
21 from mercurial import ( 19 from mercurial import (
22 archival, 20 archival,
23 cmdutil, 21 cmdutil,
24 copies as copiesmod, 22 copies as copiesmod,
49 47
50 eh = exthelper.exthelper() 48 eh = exthelper.exthelper()
51 49
52 # -- Utility functions: commonly/repeatedly needed functionality --------------- 50 # -- Utility functions: commonly/repeatedly needed functionality ---------------
53 51
52
54 def composelargefilematcher(match, manifest): 53 def composelargefilematcher(match, manifest):
55 '''create a matcher that matches only the largefiles in the original 54 '''create a matcher that matches only the largefiles in the original
56 matcher''' 55 matcher'''
57 m = copy.copy(match) 56 m = copy.copy(match)
58 lfile = lambda f: lfutil.standin(f) in manifest 57 lfile = lambda f: lfutil.standin(f) in manifest
61 m.always = lambda: False 60 m.always = lambda: False
62 origmatchfn = m.matchfn 61 origmatchfn = m.matchfn
63 m.matchfn = lambda f: lfile(f) and origmatchfn(f) 62 m.matchfn = lambda f: lfile(f) and origmatchfn(f)
64 return m 63 return m
65 64
65
66 def composenormalfilematcher(match, manifest, exclude=None): 66 def composenormalfilematcher(match, manifest, exclude=None):
67 excluded = set() 67 excluded = set()
68 if exclude is not None: 68 if exclude is not None:
69 excluded.update(exclude) 69 excluded.update(exclude)
70 70
71 m = copy.copy(match) 71 m = copy.copy(match)
72 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in 72 notlfile = lambda f: not (
73 manifest or f in excluded) 73 lfutil.isstandin(f) or lfutil.standin(f) in manifest or f in excluded
74 )
74 m._files = [lf for lf in m._files if notlfile(lf)] 75 m._files = [lf for lf in m._files if notlfile(lf)]
75 m._fileset = set(m._files) 76 m._fileset = set(m._files)
76 m.always = lambda: False 77 m.always = lambda: False
77 origmatchfn = m.matchfn 78 origmatchfn = m.matchfn
78 m.matchfn = lambda f: notlfile(f) and origmatchfn(f) 79 m.matchfn = lambda f: notlfile(f) and origmatchfn(f)
79 return m 80 return m
80 81
82
81 def addlargefiles(ui, repo, isaddremove, matcher, uipathfn, **opts): 83 def addlargefiles(ui, repo, isaddremove, matcher, uipathfn, **opts):
82 large = opts.get(r'large') 84 large = opts.get(r'large')
83 lfsize = lfutil.getminsize( 85 lfsize = lfutil.getminsize(
84 ui, lfutil.islfilesrepo(repo), opts.get(r'lfsize')) 86 ui, lfutil.islfilesrepo(repo), opts.get(r'lfsize')
87 )
85 88
86 lfmatcher = None 89 lfmatcher = None
87 if lfutil.islfilesrepo(repo): 90 if lfutil.islfilesrepo(repo):
88 lfpats = ui.configlist(lfutil.longname, 'patterns') 91 lfpats = ui.configlist(lfutil.longname, 'patterns')
89 if lfpats: 92 if lfpats:
110 # In case the file was removed previously, but not committed 113 # In case the file was removed previously, but not committed
111 # (issue3507) 114 # (issue3507)
112 if not repo.wvfs.exists(f): 115 if not repo.wvfs.exists(f):
113 continue 116 continue
114 117
115 abovemin = (lfsize and 118 abovemin = (
116 repo.wvfs.lstat(f).st_size >= lfsize * 1024 * 1024) 119 lfsize and repo.wvfs.lstat(f).st_size >= lfsize * 1024 * 1024
120 )
117 if large or abovemin or (lfmatcher and lfmatcher(f)): 121 if large or abovemin or (lfmatcher and lfmatcher(f)):
118 lfnames.append(f) 122 lfnames.append(f)
119 if ui.verbose or not exact: 123 if ui.verbose or not exact:
120 ui.status(_('adding %s as a largefile\n') % uipathfn(f)) 124 ui.status(_('adding %s as a largefile\n') % uipathfn(f))
121 125
127 if not opts.get(r'dry_run'): 131 if not opts.get(r'dry_run'):
128 standins = [] 132 standins = []
129 lfdirstate = lfutil.openlfdirstate(ui, repo) 133 lfdirstate = lfutil.openlfdirstate(ui, repo)
130 for f in lfnames: 134 for f in lfnames:
131 standinname = lfutil.standin(f) 135 standinname = lfutil.standin(f)
132 lfutil.writestandin(repo, standinname, hash='', 136 lfutil.writestandin(
133 executable=lfutil.getexecutable(repo.wjoin(f))) 137 repo,
138 standinname,
139 hash='',
140 executable=lfutil.getexecutable(repo.wjoin(f)),
141 )
134 standins.append(standinname) 142 standins.append(standinname)
135 if lfdirstate[f] == 'r': 143 if lfdirstate[f] == 'r':
136 lfdirstate.normallookup(f) 144 lfdirstate.normallookup(f)
137 else: 145 else:
138 lfdirstate.add(f) 146 lfdirstate.add(f)
139 lfdirstate.write() 147 lfdirstate.write()
140 bad += [lfutil.splitstandin(f) 148 bad += [
141 for f in repo[None].add(standins) 149 lfutil.splitstandin(f)
142 if f in m.files()] 150 for f in repo[None].add(standins)
151 if f in m.files()
152 ]
143 153
144 added = [f for f in lfnames if f not in bad] 154 added = [f for f in lfnames if f not in bad]
145 return added, bad 155 return added, bad
156
146 157
147 def removelargefiles(ui, repo, isaddremove, matcher, uipathfn, dryrun, **opts): 158 def removelargefiles(ui, repo, isaddremove, matcher, uipathfn, dryrun, **opts):
148 after = opts.get(r'after') 159 after = opts.get(r'after')
149 m = composelargefilematcher(matcher, repo[None].manifest()) 160 m = composelargefilematcher(matcher, repo[None].manifest())
150 try: 161 try:
151 repo.lfstatus = True 162 repo.lfstatus = True
152 s = repo.status(match=m, clean=not isaddremove) 163 s = repo.status(match=m, clean=not isaddremove)
153 finally: 164 finally:
154 repo.lfstatus = False 165 repo.lfstatus = False
155 manifest = repo[None].manifest() 166 manifest = repo[None].manifest()
156 modified, added, deleted, clean = [[f for f in list 167 modified, added, deleted, clean = [
157 if lfutil.standin(f) in manifest] 168 [f for f in list if lfutil.standin(f) in manifest]
158 for list in (s.modified, s.added, 169 for list in (s.modified, s.added, s.deleted, s.clean)
159 s.deleted, s.clean)] 170 ]
160 171
161 def warn(files, msg): 172 def warn(files, msg):
162 for f in files: 173 for f in files:
163 ui.warn(msg % uipathfn(f)) 174 ui.warn(msg % uipathfn(f))
164 return int(len(files) > 0) 175 return int(len(files) > 0)
165 176
166 if after: 177 if after:
167 remove = deleted 178 remove = deleted
168 result = warn(modified + added + clean, 179 result = warn(
169 _('not removing %s: file still exists\n')) 180 modified + added + clean, _('not removing %s: file still exists\n')
181 )
170 else: 182 else:
171 remove = deleted + clean 183 remove = deleted + clean
172 result = warn(modified, _('not removing %s: file is modified (use -f' 184 result = warn(
173 ' to force removal)\n')) 185 modified,
174 result = warn(added, _('not removing %s: file has been marked for add' 186 _(
175 ' (use forget to undo)\n')) or result 187 'not removing %s: file is modified (use -f'
188 ' to force removal)\n'
189 ),
190 )
191 result = (
192 warn(
193 added,
194 _(
195 'not removing %s: file has been marked for add'
196 ' (use forget to undo)\n'
197 ),
198 )
199 or result
200 )
176 201
177 # Need to lock because standin files are deleted then removed from the 202 # Need to lock because standin files are deleted then removed from the
178 # repository and we could race in-between. 203 # repository and we could race in-between.
179 with repo.wlock(): 204 with repo.wlock():
180 lfdirstate = lfutil.openlfdirstate(ui, repo) 205 lfdirstate = lfutil.openlfdirstate(ui, repo)
196 for f in remove: 221 for f in remove:
197 repo.wvfs.unlinkpath(f, ignoremissing=True) 222 repo.wvfs.unlinkpath(f, ignoremissing=True)
198 repo[None].forget(remove) 223 repo[None].forget(remove)
199 224
200 for f in remove: 225 for f in remove:
201 lfutil.synclfdirstate(repo, lfdirstate, lfutil.splitstandin(f), 226 lfutil.synclfdirstate(
202 False) 227 repo, lfdirstate, lfutil.splitstandin(f), False
228 )
203 229
204 lfdirstate.write() 230 lfdirstate.write()
205 231
206 return result 232 return result
233
207 234
208 # For overriding mercurial.hgweb.webcommands so that largefiles will 235 # For overriding mercurial.hgweb.webcommands so that largefiles will
209 # appear at their right place in the manifests. 236 # appear at their right place in the manifests.
210 @eh.wrapfunction(webcommands, 'decodepath') 237 @eh.wrapfunction(webcommands, 'decodepath')
211 def decodepath(orig, path): 238 def decodepath(orig, path):
212 return lfutil.splitstandin(path) or path 239 return lfutil.splitstandin(path) or path
213 240
241
214 # -- Wrappers: modify existing commands -------------------------------- 242 # -- Wrappers: modify existing commands --------------------------------
215 243
216 @eh.wrapcommand('add', 244
217 opts=[('', 'large', None, _('add as largefile')), 245 @eh.wrapcommand(
218 ('', 'normal', None, _('add as normal file')), 246 'add',
219 ('', 'lfsize', '', _('add all files above this size (in megabytes) ' 247 opts=[
220 'as largefiles (default: 10)'))]) 248 ('', 'large', None, _('add as largefile')),
249 ('', 'normal', None, _('add as normal file')),
250 (
251 '',
252 'lfsize',
253 '',
254 _(
255 'add all files above this size (in megabytes) '
256 'as largefiles (default: 10)'
257 ),
258 ),
259 ],
260 )
221 def overrideadd(orig, ui, repo, *pats, **opts): 261 def overrideadd(orig, ui, repo, *pats, **opts):
222 if opts.get(r'normal') and opts.get(r'large'): 262 if opts.get(r'normal') and opts.get(r'large'):
223 raise error.Abort(_('--normal cannot be used with --large')) 263 raise error.Abort(_('--normal cannot be used with --large'))
224 return orig(ui, repo, *pats, **opts) 264 return orig(ui, repo, *pats, **opts)
265
225 266
226 @eh.wrapfunction(cmdutil, 'add') 267 @eh.wrapfunction(cmdutil, 'add')
227 def cmdutiladd(orig, ui, repo, matcher, prefix, uipathfn, explicitonly, **opts): 268 def cmdutiladd(orig, ui, repo, matcher, prefix, uipathfn, explicitonly, **opts):
228 # The --normal flag short circuits this override 269 # The --normal flag short circuits this override
229 if opts.get(r'normal'): 270 if opts.get(r'normal'):
230 return orig(ui, repo, matcher, prefix, uipathfn, explicitonly, **opts) 271 return orig(ui, repo, matcher, prefix, uipathfn, explicitonly, **opts)
231 272
232 ladded, lbad = addlargefiles(ui, repo, False, matcher, uipathfn, **opts) 273 ladded, lbad = addlargefiles(ui, repo, False, matcher, uipathfn, **opts)
233 normalmatcher = composenormalfilematcher(matcher, repo[None].manifest(), 274 normalmatcher = composenormalfilematcher(
234 ladded) 275 matcher, repo[None].manifest(), ladded
276 )
235 bad = orig(ui, repo, normalmatcher, prefix, uipathfn, explicitonly, **opts) 277 bad = orig(ui, repo, normalmatcher, prefix, uipathfn, explicitonly, **opts)
236 278
237 bad.extend(f for f in lbad) 279 bad.extend(f for f in lbad)
238 return bad 280 return bad
239 281
282
240 @eh.wrapfunction(cmdutil, 'remove') 283 @eh.wrapfunction(cmdutil, 'remove')
241 def cmdutilremove(orig, ui, repo, matcher, prefix, uipathfn, after, force, 284 def cmdutilremove(
242 subrepos, dryrun): 285 orig, ui, repo, matcher, prefix, uipathfn, after, force, subrepos, dryrun
286 ):
243 normalmatcher = composenormalfilematcher(matcher, repo[None].manifest()) 287 normalmatcher = composenormalfilematcher(matcher, repo[None].manifest())
244 result = orig(ui, repo, normalmatcher, prefix, uipathfn, after, force, 288 result = orig(
245 subrepos, dryrun) 289 ui,
246 return removelargefiles(ui, repo, False, matcher, uipathfn, dryrun, 290 repo,
247 after=after, force=force) or result 291 normalmatcher,
292 prefix,
293 uipathfn,
294 after,
295 force,
296 subrepos,
297 dryrun,
298 )
299 return (
300 removelargefiles(
301 ui, repo, False, matcher, uipathfn, dryrun, after=after, force=force
302 )
303 or result
304 )
305
248 306
249 @eh.wrapfunction(subrepo.hgsubrepo, 'status') 307 @eh.wrapfunction(subrepo.hgsubrepo, 'status')
250 def overridestatusfn(orig, repo, rev2, **opts): 308 def overridestatusfn(orig, repo, rev2, **opts):
251 try: 309 try:
252 repo._repo.lfstatus = True 310 repo._repo.lfstatus = True
253 return orig(repo, rev2, **opts) 311 return orig(repo, rev2, **opts)
254 finally: 312 finally:
255 repo._repo.lfstatus = False 313 repo._repo.lfstatus = False
256 314
315
257 @eh.wrapcommand('status') 316 @eh.wrapcommand('status')
258 def overridestatus(orig, ui, repo, *pats, **opts): 317 def overridestatus(orig, ui, repo, *pats, **opts):
259 try: 318 try:
260 repo.lfstatus = True 319 repo.lfstatus = True
261 return orig(ui, repo, *pats, **opts) 320 return orig(ui, repo, *pats, **opts)
262 finally: 321 finally:
263 repo.lfstatus = False 322 repo.lfstatus = False
264 323
324
265 @eh.wrapfunction(subrepo.hgsubrepo, 'dirty') 325 @eh.wrapfunction(subrepo.hgsubrepo, 'dirty')
266 def overridedirty(orig, repo, ignoreupdate=False, missing=False): 326 def overridedirty(orig, repo, ignoreupdate=False, missing=False):
267 try: 327 try:
268 repo._repo.lfstatus = True 328 repo._repo.lfstatus = True
269 return orig(repo, ignoreupdate=ignoreupdate, missing=missing) 329 return orig(repo, ignoreupdate=ignoreupdate, missing=missing)
270 finally: 330 finally:
271 repo._repo.lfstatus = False 331 repo._repo.lfstatus = False
272 332
333
273 @eh.wrapcommand('log') 334 @eh.wrapcommand('log')
274 def overridelog(orig, ui, repo, *pats, **opts): 335 def overridelog(orig, ui, repo, *pats, **opts):
275 def overridematchandpats(orig, ctx, pats=(), opts=None, globbed=False, 336 def overridematchandpats(
276 default='relpath', badfn=None): 337 orig,
338 ctx,
339 pats=(),
340 opts=None,
341 globbed=False,
342 default='relpath',
343 badfn=None,
344 ):
277 """Matcher that merges root directory with .hglf, suitable for log. 345 """Matcher that merges root directory with .hglf, suitable for log.
278 It is still possible to match .hglf directly. 346 It is still possible to match .hglf directly.
279 For any listed files run log on the standin too. 347 For any listed files run log on the standin too.
280 matchfn tries both the given filename and with .hglf stripped. 348 matchfn tries both the given filename and with .hglf stripped.
281 """ 349 """
302 return tostandin(kindpat[1]) 370 return tostandin(kindpat[1])
303 371
304 cwd = repo.getcwd() 372 cwd = repo.getcwd()
305 if cwd: 373 if cwd:
306 hglf = lfutil.shortname 374 hglf = lfutil.shortname
307 back = util.pconvert(repo.pathto(hglf)[:-len(hglf)]) 375 back = util.pconvert(repo.pathto(hglf)[: -len(hglf)])
308 376
309 def tostandin(f): 377 def tostandin(f):
310 # The file may already be a standin, so truncate the back 378 # The file may already be a standin, so truncate the back
311 # prefix and test before mangling it. This avoids turning 379 # prefix and test before mangling it. This avoids turning
312 # 'glob:../.hglf/foo*' into 'glob:../.hglf/../.hglf/foo*'. 380 # 'glob:../.hglf/foo*' into 'glob:../.hglf/../.hglf/foo*'.
313 if f.startswith(back) and lfutil.splitstandin(f[len(back):]): 381 if f.startswith(back) and lfutil.splitstandin(f[len(back) :]):
314 return f 382 return f
315 383
316 # An absolute path is from outside the repo, so truncate the 384 # An absolute path is from outside the repo, so truncate the
317 # path to the root before building the standin. Otherwise cwd 385 # path to the root before building the standin. Otherwise cwd
318 # is somewhere in the repo, relative to root, and needs to be 386 # is somewhere in the repo, relative to root, and needs to be
319 # prepended before building the standin. 387 # prepended before building the standin.
320 if os.path.isabs(cwd): 388 if os.path.isabs(cwd):
321 f = f[len(back):] 389 f = f[len(back) :]
322 else: 390 else:
323 f = cwd + '/' + f 391 f = cwd + '/' + f
324 return back + lfutil.standin(f) 392 return back + lfutil.standin(f)
393
325 else: 394 else:
395
326 def tostandin(f): 396 def tostandin(f):
327 if lfutil.isstandin(f): 397 if lfutil.isstandin(f):
328 return f 398 return f
329 return lfutil.standin(f) 399 return lfutil.standin(f)
400
330 pats.update(fixpats(f, tostandin) for f in p) 401 pats.update(fixpats(f, tostandin) for f in p)
331 402
332 for i in range(0, len(m._files)): 403 for i in range(0, len(m._files)):
333 # Don't add '.hglf' to m.files, since that is already covered by '.' 404 # Don't add '.hglf' to m.files, since that is already covered by '.'
334 if m._files[i] == '.': 405 if m._files[i] == '.':
344 m._files.append(standin) 415 m._files.append(standin)
345 416
346 m._fileset = set(m._files) 417 m._fileset = set(m._files)
347 m.always = lambda: False 418 m.always = lambda: False
348 origmatchfn = m.matchfn 419 origmatchfn = m.matchfn
420
349 def lfmatchfn(f): 421 def lfmatchfn(f):
350 lf = lfutil.splitstandin(f) 422 lf = lfutil.splitstandin(f)
351 if lf is not None and origmatchfn(lf): 423 if lf is not None and origmatchfn(lf):
352 return True 424 return True
353 r = origmatchfn(f) 425 r = origmatchfn(f)
354 return r 426 return r
427
355 m.matchfn = lfmatchfn 428 m.matchfn = lfmatchfn
356 429
357 ui.debug('updated patterns: %s\n' % ', '.join(sorted(pats))) 430 ui.debug('updated patterns: %s\n' % ', '.join(sorted(pats)))
358 return m, pats 431 return m, pats
359 432
361 # (1) to determine what revisions should be printed out, and 434 # (1) to determine what revisions should be printed out, and
362 # (2) to determine what files to print out diffs for. 435 # (2) to determine what files to print out diffs for.
363 # The magic matchandpats override should be used for case (1) but not for 436 # The magic matchandpats override should be used for case (1) but not for
364 # case (2). 437 # case (2).
365 oldmatchandpats = scmutil.matchandpats 438 oldmatchandpats = scmutil.matchandpats
439
366 def overridemakefilematcher(orig, repo, pats, opts, badfn=None): 440 def overridemakefilematcher(orig, repo, pats, opts, badfn=None):
367 wctx = repo[None] 441 wctx = repo[None]
368 match, pats = oldmatchandpats(wctx, pats, opts, badfn=badfn) 442 match, pats = oldmatchandpats(wctx, pats, opts, badfn=badfn)
369 return lambda ctx: match 443 return lambda ctx: match
370 444
371 wrappedmatchandpats = extensions.wrappedfunction(scmutil, 'matchandpats', 445 wrappedmatchandpats = extensions.wrappedfunction(
372 overridematchandpats) 446 scmutil, 'matchandpats', overridematchandpats
447 )
373 wrappedmakefilematcher = extensions.wrappedfunction( 448 wrappedmakefilematcher = extensions.wrappedfunction(
374 logcmdutil, '_makenofollowfilematcher', overridemakefilematcher) 449 logcmdutil, '_makenofollowfilematcher', overridemakefilematcher
450 )
375 with wrappedmatchandpats, wrappedmakefilematcher: 451 with wrappedmatchandpats, wrappedmakefilematcher:
376 return orig(ui, repo, *pats, **opts) 452 return orig(ui, repo, *pats, **opts)
377 453
378 @eh.wrapcommand('verify', 454
379 opts=[('', 'large', None, 455 @eh.wrapcommand(
380 _('verify that all largefiles in current revision exists')), 456 'verify',
381 ('', 'lfa', None, 457 opts=[
382 _('verify largefiles in all revisions, not just current')), 458 (
383 ('', 'lfc', None, 459 '',
384 _('verify local largefile contents, not just existence'))]) 460 'large',
461 None,
462 _('verify that all largefiles in current revision exists'),
463 ),
464 (
465 '',
466 'lfa',
467 None,
468 _('verify largefiles in all revisions, not just current'),
469 ),
470 (
471 '',
472 'lfc',
473 None,
474 _('verify local largefile contents, not just existence'),
475 ),
476 ],
477 )
385 def overrideverify(orig, ui, repo, *pats, **opts): 478 def overrideverify(orig, ui, repo, *pats, **opts):
386 large = opts.pop(r'large', False) 479 large = opts.pop(r'large', False)
387 all = opts.pop(r'lfa', False) 480 all = opts.pop(r'lfa', False)
388 contents = opts.pop(r'lfc', False) 481 contents = opts.pop(r'lfc', False)
389 482
390 result = orig(ui, repo, *pats, **opts) 483 result = orig(ui, repo, *pats, **opts)
391 if large or all or contents: 484 if large or all or contents:
392 result = result or lfcommands.verifylfiles(ui, repo, all, contents) 485 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
393 return result 486 return result
394 487
395 @eh.wrapcommand('debugstate', 488
396 opts=[('', 'large', None, _('display largefiles dirstate'))]) 489 @eh.wrapcommand(
490 'debugstate', opts=[('', 'large', None, _('display largefiles dirstate'))]
491 )
397 def overridedebugstate(orig, ui, repo, *pats, **opts): 492 def overridedebugstate(orig, ui, repo, *pats, **opts):
398 large = opts.pop(r'large', False) 493 large = opts.pop(r'large', False)
399 if large: 494 if large:
495
400 class fakerepo(object): 496 class fakerepo(object):
401 dirstate = lfutil.openlfdirstate(ui, repo) 497 dirstate = lfutil.openlfdirstate(ui, repo)
498
402 orig(ui, fakerepo, *pats, **opts) 499 orig(ui, fakerepo, *pats, **opts)
403 else: 500 else:
404 orig(ui, repo, *pats, **opts) 501 orig(ui, repo, *pats, **opts)
502
405 503
406 # Before starting the manifest merge, merge.updates will call 504 # Before starting the manifest merge, merge.updates will call
407 # _checkunknownfile to check if there are any files in the merged-in 505 # _checkunknownfile to check if there are any files in the merged-in
408 # changeset that collide with unknown files in the working copy. 506 # changeset that collide with unknown files in the working copy.
409 # 507 #
416 @eh.wrapfunction(merge, '_checkunknownfile') 514 @eh.wrapfunction(merge, '_checkunknownfile')
417 def overridecheckunknownfile(origfn, repo, wctx, mctx, f, f2=None): 515 def overridecheckunknownfile(origfn, repo, wctx, mctx, f, f2=None):
418 if lfutil.standin(repo.dirstate.normalize(f)) in wctx: 516 if lfutil.standin(repo.dirstate.normalize(f)) in wctx:
419 return False 517 return False
420 return origfn(repo, wctx, mctx, f, f2) 518 return origfn(repo, wctx, mctx, f, f2)
519
421 520
422 # The manifest merge handles conflicts on the manifest level. We want 521 # The manifest merge handles conflicts on the manifest level. We want
423 # to handle changes in largefile-ness of files at this level too. 522 # to handle changes in largefile-ness of files at this level too.
424 # 523 #
425 # The strategy is to run the original calculateupdates and then process 524 # The strategy is to run the original calculateupdates and then process
444 # 543 #
445 # Finally, the merge.applyupdates function will then take care of 544 # Finally, the merge.applyupdates function will then take care of
446 # writing the files into the working copy and lfcommands.updatelfiles 545 # writing the files into the working copy and lfcommands.updatelfiles
447 # will update the largefiles. 546 # will update the largefiles.
448 @eh.wrapfunction(merge, 'calculateupdates') 547 @eh.wrapfunction(merge, 'calculateupdates')
449 def overridecalculateupdates(origfn, repo, p1, p2, pas, branchmerge, force, 548 def overridecalculateupdates(
450 acceptremote, *args, **kwargs): 549 origfn, repo, p1, p2, pas, branchmerge, force, acceptremote, *args, **kwargs
550 ):
451 overwrite = force and not branchmerge 551 overwrite = force and not branchmerge
452 actions, diverge, renamedelete = origfn( 552 actions, diverge, renamedelete = origfn(
453 repo, p1, p2, pas, branchmerge, force, acceptremote, *args, **kwargs) 553 repo, p1, p2, pas, branchmerge, force, acceptremote, *args, **kwargs
554 )
454 555
455 if overwrite: 556 if overwrite:
456 return actions, diverge, renamedelete 557 return actions, diverge, renamedelete
457 558
458 # Convert to dictionary with filename as key and action as value. 559 # Convert to dictionary with filename as key and action as value.
472 if sm == 'dc': 573 if sm == 'dc':
473 f1, f2, fa, move, anc = sargs 574 f1, f2, fa, move, anc = sargs
474 sargs = (p2[f2].flags(), False) 575 sargs = (p2[f2].flags(), False)
475 # Case 1: normal file in the working copy, largefile in 576 # Case 1: normal file in the working copy, largefile in
476 # the second parent 577 # the second parent
477 usermsg = _('remote turned local normal file %s into a largefile\n' 578 usermsg = (
478 'use (l)argefile or keep (n)ormal file?' 579 _(
479 '$$ &Largefile $$ &Normal file') % lfile 580 'remote turned local normal file %s into a largefile\n'
480 if repo.ui.promptchoice(usermsg, 0) == 0: # pick remote largefile 581 'use (l)argefile or keep (n)ormal file?'
582 '$$ &Largefile $$ &Normal file'
583 )
584 % lfile
585 )
586 if repo.ui.promptchoice(usermsg, 0) == 0: # pick remote largefile
481 actions[lfile] = ('r', None, 'replaced by standin') 587 actions[lfile] = ('r', None, 'replaced by standin')
482 actions[standin] = ('g', sargs, 'replaces standin') 588 actions[standin] = ('g', sargs, 'replaces standin')
483 else: # keep local normal file 589 else: # keep local normal file
484 actions[lfile] = ('k', None, 'replaces standin') 590 actions[lfile] = ('k', None, 'replaces standin')
485 if branchmerge: 591 if branchmerge:
486 actions[standin] = ('k', None, 'replaced by non-standin') 592 actions[standin] = ('k', None, 'replaced by non-standin')
487 else: 593 else:
488 actions[standin] = ('r', None, 'replaced by non-standin') 594 actions[standin] = ('r', None, 'replaced by non-standin')
490 if lm == 'dc': 596 if lm == 'dc':
491 f1, f2, fa, move, anc = largs 597 f1, f2, fa, move, anc = largs
492 largs = (p2[f2].flags(), False) 598 largs = (p2[f2].flags(), False)
493 # Case 2: largefile in the working copy, normal file in 599 # Case 2: largefile in the working copy, normal file in
494 # the second parent 600 # the second parent
495 usermsg = _('remote turned local largefile %s into a normal file\n' 601 usermsg = (
602 _(
603 'remote turned local largefile %s into a normal file\n'
496 'keep (l)argefile or use (n)ormal file?' 604 'keep (l)argefile or use (n)ormal file?'
497 '$$ &Largefile $$ &Normal file') % lfile 605 '$$ &Largefile $$ &Normal file'
498 if repo.ui.promptchoice(usermsg, 0) == 0: # keep local largefile 606 )
607 % lfile
608 )
609 if repo.ui.promptchoice(usermsg, 0) == 0: # keep local largefile
499 if branchmerge: 610 if branchmerge:
500 # largefile can be restored from standin safely 611 # largefile can be restored from standin safely
501 actions[lfile] = ('k', None, 'replaced by standin') 612 actions[lfile] = ('k', None, 'replaced by standin')
502 actions[standin] = ('k', None, 'replaces standin') 613 actions[standin] = ('k', None, 'replaces standin')
503 else: 614 else:
504 # "lfile" should be marked as "removed" without 615 # "lfile" should be marked as "removed" without
505 # removal of itself 616 # removal of itself
506 actions[lfile] = ('lfmr', None, 617 actions[lfile] = (
507 'forget non-standin largefile') 618 'lfmr',
619 None,
620 'forget non-standin largefile',
621 )
508 622
509 # linear-merge should treat this largefile as 're-added' 623 # linear-merge should treat this largefile as 're-added'
510 actions[standin] = ('a', None, 'keep standin') 624 actions[standin] = ('a', None, 'keep standin')
511 else: # pick remote normal file 625 else: # pick remote normal file
512 actions[lfile] = ('g', largs, 'replaces standin') 626 actions[lfile] = ('g', largs, 'replaces standin')
513 actions[standin] = ('r', None, 'replaced by non-standin') 627 actions[standin] = ('r', None, 'replaced by non-standin')
514 628
515 return actions, diverge, renamedelete 629 return actions, diverge, renamedelete
630
516 631
517 @eh.wrapfunction(merge, 'recordupdates') 632 @eh.wrapfunction(merge, 'recordupdates')
518 def mergerecordupdates(orig, repo, actions, branchmerge, getfiledata): 633 def mergerecordupdates(orig, repo, actions, branchmerge, getfiledata):
519 if 'lfmr' in actions: 634 if 'lfmr' in actions:
520 lfdirstate = lfutil.openlfdirstate(repo.ui, repo) 635 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
526 lfdirstate.add(lfile) 641 lfdirstate.add(lfile)
527 lfdirstate.write() 642 lfdirstate.write()
528 643
529 return orig(repo, actions, branchmerge, getfiledata) 644 return orig(repo, actions, branchmerge, getfiledata)
530 645
646
531 # Override filemerge to prompt the user about how they wish to merge 647 # Override filemerge to prompt the user about how they wish to merge
532 # largefiles. This will handle identical edits without prompting the user. 648 # largefiles. This will handle identical edits without prompting the user.
533 @eh.wrapfunction(filemerge, '_filemerge') 649 @eh.wrapfunction(filemerge, '_filemerge')
534 def overridefilemerge(origfn, premerge, repo, wctx, mynode, orig, fcd, fco, fca, 650 def overridefilemerge(
535 labels=None): 651 origfn, premerge, repo, wctx, mynode, orig, fcd, fco, fca, labels=None
652 ):
536 if not lfutil.isstandin(orig) or fcd.isabsent() or fco.isabsent(): 653 if not lfutil.isstandin(orig) or fcd.isabsent() or fco.isabsent():
537 return origfn(premerge, repo, wctx, mynode, orig, fcd, fco, fca, 654 return origfn(
538 labels=labels) 655 premerge, repo, wctx, mynode, orig, fcd, fco, fca, labels=labels
656 )
539 657
540 ahash = lfutil.readasstandin(fca).lower() 658 ahash = lfutil.readasstandin(fca).lower()
541 dhash = lfutil.readasstandin(fcd).lower() 659 dhash = lfutil.readasstandin(fcd).lower()
542 ohash = lfutil.readasstandin(fco).lower() 660 ohash = lfutil.readasstandin(fco).lower()
543 if (ohash != ahash and 661 if (
544 ohash != dhash and 662 ohash != ahash
545 (dhash == ahash or 663 and ohash != dhash
546 repo.ui.promptchoice( 664 and (
547 _('largefile %s has a merge conflict\nancestor was %s\n' 665 dhash == ahash
548 'you can keep (l)ocal %s or take (o)ther %s.\n' 666 or repo.ui.promptchoice(
549 'what do you want to do?' 667 _(
550 '$$ &Local $$ &Other') % 668 'largefile %s has a merge conflict\nancestor was %s\n'
551 (lfutil.splitstandin(orig), ahash, dhash, ohash), 669 'you can keep (l)ocal %s or take (o)ther %s.\n'
552 0) == 1)): 670 'what do you want to do?'
671 '$$ &Local $$ &Other'
672 )
673 % (lfutil.splitstandin(orig), ahash, dhash, ohash),
674 0,
675 )
676 == 1
677 )
678 ):
553 repo.wwrite(fcd.path(), fco.data(), fco.flags()) 679 repo.wwrite(fcd.path(), fco.data(), fco.flags())
554 return True, 0, False 680 return True, 0, False
681
555 682
556 @eh.wrapfunction(copiesmod, 'pathcopies') 683 @eh.wrapfunction(copiesmod, 'pathcopies')
557 def copiespathcopies(orig, ctx1, ctx2, match=None): 684 def copiespathcopies(orig, ctx1, ctx2, match=None):
558 copies = orig(ctx1, ctx2, match=match) 685 copies = orig(ctx1, ctx2, match=match)
559 updated = {} 686 updated = {}
560 687
561 for k, v in copies.iteritems(): 688 for k, v in copies.iteritems():
562 updated[lfutil.splitstandin(k) or k] = lfutil.splitstandin(v) or v 689 updated[lfutil.splitstandin(k) or k] = lfutil.splitstandin(v) or v
563 690
564 return updated 691 return updated
692
565 693
566 # Copy first changes the matchers to match standins instead of 694 # Copy first changes the matchers to match standins instead of
567 # largefiles. Then it overrides util.copyfile in that function it 695 # largefiles. Then it overrides util.copyfile in that function it
568 # checks if the destination largefile already exists. It also keeps a 696 # checks if the destination largefile already exists. It also keeps a
569 # list of copied files so that the largefiles can be copied and the 697 # list of copied files so that the largefiles can be copied and the
580 # only match normal files and run it, then replace it to just 708 # only match normal files and run it, then replace it to just
581 # match largefiles and run it again. 709 # match largefiles and run it again.
582 nonormalfiles = False 710 nonormalfiles = False
583 nolfiles = False 711 nolfiles = False
584 manifest = repo[None].manifest() 712 manifest = repo[None].manifest()
585 def normalfilesmatchfn(orig, ctx, pats=(), opts=None, globbed=False, 713
586 default='relpath', badfn=None): 714 def normalfilesmatchfn(
715 orig,
716 ctx,
717 pats=(),
718 opts=None,
719 globbed=False,
720 default='relpath',
721 badfn=None,
722 ):
587 if opts is None: 723 if opts is None:
588 opts = {} 724 opts = {}
589 match = orig(ctx, pats, opts, globbed, default, badfn=badfn) 725 match = orig(ctx, pats, opts, globbed, default, badfn=badfn)
590 return composenormalfilematcher(match, manifest) 726 return composenormalfilematcher(match, manifest)
727
591 with extensions.wrappedfunction(scmutil, 'match', normalfilesmatchfn): 728 with extensions.wrappedfunction(scmutil, 'match', normalfilesmatchfn):
592 try: 729 try:
593 result = orig(ui, repo, pats, opts, rename) 730 result = orig(ui, repo, pats, opts, rename)
594 except error.Abort as e: 731 except error.Abort as e:
595 if pycompat.bytestr(e) != _('no files to copy'): 732 if pycompat.bytestr(e) != _('no files to copy'):
620 # When we call orig below it creates the standins but we don't add 757 # When we call orig below it creates the standins but we don't add
621 # them to the dir state until later so lock during that time. 758 # them to the dir state until later so lock during that time.
622 wlock = repo.wlock() 759 wlock = repo.wlock()
623 760
624 manifest = repo[None].manifest() 761 manifest = repo[None].manifest()
625 def overridematch(orig, ctx, pats=(), opts=None, globbed=False, 762
626 default='relpath', badfn=None): 763 def overridematch(
764 orig,
765 ctx,
766 pats=(),
767 opts=None,
768 globbed=False,
769 default='relpath',
770 badfn=None,
771 ):
627 if opts is None: 772 if opts is None:
628 opts = {} 773 opts = {}
629 newpats = [] 774 newpats = []
630 # The patterns were previously mangled to add the standin 775 # The patterns were previously mangled to add the standin
631 # directory; we need to remove that now 776 # directory; we need to remove that now
638 m = copy.copy(match) 783 m = copy.copy(match)
639 lfile = lambda f: lfutil.standin(f) in manifest 784 lfile = lambda f: lfutil.standin(f) in manifest
640 m._files = [lfutil.standin(f) for f in m._files if lfile(f)] 785 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
641 m._fileset = set(m._files) 786 m._fileset = set(m._files)
642 origmatchfn = m.matchfn 787 origmatchfn = m.matchfn
788
643 def matchfn(f): 789 def matchfn(f):
644 lfile = lfutil.splitstandin(f) 790 lfile = lfutil.splitstandin(f)
645 return (lfile is not None and 791 return (
646 (f in manifest) and 792 lfile is not None
647 origmatchfn(lfile) or 793 and (f in manifest)
648 None) 794 and origmatchfn(lfile)
795 or None
796 )
797
649 m.matchfn = matchfn 798 m.matchfn = matchfn
650 return m 799 return m
800
651 listpats = [] 801 listpats = []
652 for pat in pats: 802 for pat in pats:
653 if matchmod.patkind(pat) is not None: 803 if matchmod.patkind(pat) is not None:
654 listpats.append(pat) 804 listpats.append(pat)
655 else: 805 else:
656 listpats.append(makestandin(pat)) 806 listpats.append(makestandin(pat))
657 807
658 copiedfiles = [] 808 copiedfiles = []
809
659 def overridecopyfile(orig, src, dest, *args, **kwargs): 810 def overridecopyfile(orig, src, dest, *args, **kwargs):
660 if (lfutil.shortname in src and 811 if lfutil.shortname in src and dest.startswith(
661 dest.startswith(repo.wjoin(lfutil.shortname))): 812 repo.wjoin(lfutil.shortname)
813 ):
662 destlfile = dest.replace(lfutil.shortname, '') 814 destlfile = dest.replace(lfutil.shortname, '')
663 if not opts['force'] and os.path.exists(destlfile): 815 if not opts['force'] and os.path.exists(destlfile):
664 raise IOError('', 816 raise IOError('', _('destination largefile already exists'))
665 _('destination largefile already exists'))
666 copiedfiles.append((src, dest)) 817 copiedfiles.append((src, dest))
667 orig(src, dest, *args, **kwargs) 818 orig(src, dest, *args, **kwargs)
819
668 with extensions.wrappedfunction(util, 'copyfile', overridecopyfile): 820 with extensions.wrappedfunction(util, 'copyfile', overridecopyfile):
669 with extensions.wrappedfunction(scmutil, 'match', overridematch): 821 with extensions.wrappedfunction(scmutil, 'match', overridematch):
670 result += orig(ui, repo, listpats, opts, rename) 822 result += orig(ui, repo, listpats, opts, rename)
671 823
672 lfdirstate = lfutil.openlfdirstate(ui, repo) 824 lfdirstate = lfutil.openlfdirstate(ui, repo)
673 for (src, dest) in copiedfiles: 825 for (src, dest) in copiedfiles:
674 if (lfutil.shortname in src and 826 if lfutil.shortname in src and dest.startswith(
675 dest.startswith(repo.wjoin(lfutil.shortname))): 827 repo.wjoin(lfutil.shortname)
828 ):
676 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '') 829 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
677 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '') 830 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
678 destlfiledir = repo.wvfs.dirname(repo.wjoin(destlfile)) or '.' 831 destlfiledir = repo.wvfs.dirname(repo.wjoin(destlfile)) or '.'
679 if not os.path.isdir(destlfiledir): 832 if not os.path.isdir(destlfiledir):
680 os.makedirs(destlfiledir) 833 os.makedirs(destlfiledir)
684 # The file is gone, but this deletes any empty parent 837 # The file is gone, but this deletes any empty parent
685 # directories as a side-effect. 838 # directories as a side-effect.
686 repo.wvfs.unlinkpath(srclfile, ignoremissing=True) 839 repo.wvfs.unlinkpath(srclfile, ignoremissing=True)
687 lfdirstate.remove(srclfile) 840 lfdirstate.remove(srclfile)
688 else: 841 else:
689 util.copyfile(repo.wjoin(srclfile), 842 util.copyfile(repo.wjoin(srclfile), repo.wjoin(destlfile))
690 repo.wjoin(destlfile))
691 843
692 lfdirstate.add(destlfile) 844 lfdirstate.add(destlfile)
693 lfdirstate.write() 845 lfdirstate.write()
694 except error.Abort as e: 846 except error.Abort as e:
695 if pycompat.bytestr(e) != _('no files to copy'): 847 if pycompat.bytestr(e) != _('no files to copy'):
701 853
702 if nolfiles and nonormalfiles: 854 if nolfiles and nonormalfiles:
703 raise error.Abort(_('no files to copy')) 855 raise error.Abort(_('no files to copy'))
704 856
705 return result 857 return result
858
706 859
707 # When the user calls revert, we have to be careful to not revert any 860 # When the user calls revert, we have to be careful to not revert any
708 # changes to other largefiles accidentally. This means we have to keep 861 # changes to other largefiles accidentally. This means we have to keep
709 # track of the largefiles that are being reverted so we only pull down 862 # track of the largefiles that are being reverted so we only pull down
710 # the necessary largefiles. 863 # the necessary largefiles.
724 lfdirstate.write() 877 lfdirstate.write()
725 for lfile in s.modified: 878 for lfile in s.modified:
726 lfutil.updatestandin(repo, lfile, lfutil.standin(lfile)) 879 lfutil.updatestandin(repo, lfile, lfutil.standin(lfile))
727 for lfile in s.deleted: 880 for lfile in s.deleted:
728 fstandin = lfutil.standin(lfile) 881 fstandin = lfutil.standin(lfile)
729 if (repo.wvfs.exists(fstandin)): 882 if repo.wvfs.exists(fstandin):
730 repo.wvfs.unlink(fstandin) 883 repo.wvfs.unlink(fstandin)
731 884
732 oldstandins = lfutil.getstandinsstate(repo) 885 oldstandins = lfutil.getstandinsstate(repo)
733 886
734 def overridematch(orig, mctx, pats=(), opts=None, globbed=False, 887 def overridematch(
735 default='relpath', badfn=None): 888 orig,
889 mctx,
890 pats=(),
891 opts=None,
892 globbed=False,
893 default='relpath',
894 badfn=None,
895 ):
736 if opts is None: 896 if opts is None:
737 opts = {} 897 opts = {}
738 match = orig(mctx, pats, opts, globbed, default, badfn=badfn) 898 match = orig(mctx, pats, opts, globbed, default, badfn=badfn)
739 m = copy.copy(match) 899 m = copy.copy(match)
740 900
741 # revert supports recursing into subrepos, and though largefiles 901 # revert supports recursing into subrepos, and though largefiles
742 # currently doesn't work correctly in that case, this match is 902 # currently doesn't work correctly in that case, this match is
743 # called, so the lfdirstate above may not be the correct one for 903 # called, so the lfdirstate above may not be the correct one for
744 # this invocation of match. 904 # this invocation of match.
745 lfdirstate = lfutil.openlfdirstate(mctx.repo().ui, mctx.repo(), 905 lfdirstate = lfutil.openlfdirstate(
746 False) 906 mctx.repo().ui, mctx.repo(), False
907 )
747 908
748 wctx = repo[None] 909 wctx = repo[None]
749 matchfiles = [] 910 matchfiles = []
750 for f in m._files: 911 for f in m._files:
751 standin = lfutil.standin(f) 912 standin = lfutil.standin(f)
756 else: 917 else:
757 matchfiles.append(f) 918 matchfiles.append(f)
758 m._files = matchfiles 919 m._files = matchfiles
759 m._fileset = set(m._files) 920 m._fileset = set(m._files)
760 origmatchfn = m.matchfn 921 origmatchfn = m.matchfn
922
761 def matchfn(f): 923 def matchfn(f):
762 lfile = lfutil.splitstandin(f) 924 lfile = lfutil.splitstandin(f)
763 if lfile is not None: 925 if lfile is not None:
764 return (origmatchfn(lfile) and 926 return origmatchfn(lfile) and (f in ctx or f in mctx)
765 (f in ctx or f in mctx))
766 return origmatchfn(f) 927 return origmatchfn(f)
928
767 m.matchfn = matchfn 929 m.matchfn = matchfn
768 return m 930 return m
931
769 with extensions.wrappedfunction(scmutil, 'match', overridematch): 932 with extensions.wrappedfunction(scmutil, 'match', overridematch):
770 orig(ui, repo, ctx, parents, *pats, **opts) 933 orig(ui, repo, ctx, parents, *pats, **opts)
771 934
772 newstandins = lfutil.getstandinsstate(repo) 935 newstandins = lfutil.getstandinsstate(repo)
773 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins) 936 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
774 # lfdirstate should be 'normallookup'-ed for updated files, 937 # lfdirstate should be 'normallookup'-ed for updated files,
775 # because reverting doesn't touch dirstate for 'normal' files 938 # because reverting doesn't touch dirstate for 'normal' files
776 # when target revision is explicitly specified: in such case, 939 # when target revision is explicitly specified: in such case,
777 # 'n' and valid timestamp in dirstate doesn't ensure 'clean' 940 # 'n' and valid timestamp in dirstate doesn't ensure 'clean'
778 # of target (standin) file. 941 # of target (standin) file.
779 lfcommands.updatelfiles(ui, repo, filelist, printmessage=False, 942 lfcommands.updatelfiles(
780 normallookup=True) 943 ui, repo, filelist, printmessage=False, normallookup=True
944 )
945
781 946
782 # after pulling changesets, we need to take some extra care to get 947 # after pulling changesets, we need to take some extra care to get
783 # largefiles updated remotely 948 # largefiles updated remotely
784 @eh.wrapcommand('pull', 949 @eh.wrapcommand(
785 opts=[('', 'all-largefiles', None, 950 'pull',
786 _('download all pulled versions of largefiles (DEPRECATED)')), 951 opts=[
787 ('', 'lfrev', [], 952 (
788 _('download largefiles for these revisions'), _('REV'))]) 953 '',
954 'all-largefiles',
955 None,
956 _('download all pulled versions of largefiles (DEPRECATED)'),
957 ),
958 (
959 '',
960 'lfrev',
961 [],
962 _('download largefiles for these revisions'),
963 _('REV'),
964 ),
965 ],
966 )
789 def overridepull(orig, ui, repo, source=None, **opts): 967 def overridepull(orig, ui, repo, source=None, **opts):
790 revsprepull = len(repo) 968 revsprepull = len(repo)
791 if not source: 969 if not source:
792 source = 'default' 970 source = 'default'
793 repo.lfpullsource = source 971 repo.lfpullsource = source
796 lfrevs = opts.get(r'lfrev', []) 974 lfrevs = opts.get(r'lfrev', [])
797 if opts.get(r'all_largefiles'): 975 if opts.get(r'all_largefiles'):
798 lfrevs.append('pulled()') 976 lfrevs.append('pulled()')
799 if lfrevs and revspostpull > revsprepull: 977 if lfrevs and revspostpull > revsprepull:
800 numcached = 0 978 numcached = 0
801 repo.firstpulled = revsprepull # for pulled() revset expression 979 repo.firstpulled = revsprepull # for pulled() revset expression
802 try: 980 try:
803 for rev in scmutil.revrange(repo, lfrevs): 981 for rev in scmutil.revrange(repo, lfrevs):
804 ui.note(_('pulling largefiles for revision %d\n') % rev) 982 ui.note(_('pulling largefiles for revision %d\n') % rev)
805 (cached, missing) = lfcommands.cachelfiles(ui, repo, rev) 983 (cached, missing) = lfcommands.cachelfiles(ui, repo, rev)
806 numcached += len(cached) 984 numcached += len(cached)
807 finally: 985 finally:
808 del repo.firstpulled 986 del repo.firstpulled
809 ui.status(_("%d largefiles cached\n") % numcached) 987 ui.status(_("%d largefiles cached\n") % numcached)
810 return result 988 return result
811 989
812 @eh.wrapcommand('push', 990
813 opts=[('', 'lfrev', [], 991 @eh.wrapcommand(
814 _('upload largefiles for these revisions'), _('REV'))]) 992 'push',
993 opts=[
994 ('', 'lfrev', [], _('upload largefiles for these revisions'), _('REV'))
995 ],
996 )
815 def overridepush(orig, ui, repo, *args, **kwargs): 997 def overridepush(orig, ui, repo, *args, **kwargs):
816 """Override push command and store --lfrev parameters in opargs""" 998 """Override push command and store --lfrev parameters in opargs"""
817 lfrevs = kwargs.pop(r'lfrev', None) 999 lfrevs = kwargs.pop(r'lfrev', None)
818 if lfrevs: 1000 if lfrevs:
819 opargs = kwargs.setdefault(r'opargs', {}) 1001 opargs = kwargs.setdefault(r'opargs', {})
820 opargs['lfrevs'] = scmutil.revrange(repo, lfrevs) 1002 opargs['lfrevs'] = scmutil.revrange(repo, lfrevs)
821 return orig(ui, repo, *args, **kwargs) 1003 return orig(ui, repo, *args, **kwargs)
822 1004
1005
823 @eh.wrapfunction(exchange, 'pushoperation') 1006 @eh.wrapfunction(exchange, 'pushoperation')
824 def exchangepushoperation(orig, *args, **kwargs): 1007 def exchangepushoperation(orig, *args, **kwargs):
825 """Override pushoperation constructor and store lfrevs parameter""" 1008 """Override pushoperation constructor and store lfrevs parameter"""
826 lfrevs = kwargs.pop(r'lfrevs', None) 1009 lfrevs = kwargs.pop(r'lfrevs', None)
827 pushop = orig(*args, **kwargs) 1010 pushop = orig(*args, **kwargs)
828 pushop.lfrevs = lfrevs 1011 pushop.lfrevs = lfrevs
829 return pushop 1012 return pushop
830 1013
1014
831 @eh.revsetpredicate('pulled()') 1015 @eh.revsetpredicate('pulled()')
832 def pulledrevsetsymbol(repo, subset, x): 1016 def pulledrevsetsymbol(repo, subset, x):
833 """Changesets that just has been pulled. 1017 """Changesets that just has been pulled.
834 1018
835 Only available with largefiles from pull --lfrev expressions. 1019 Only available with largefiles from pull --lfrev expressions.
852 firstpulled = repo.firstpulled 1036 firstpulled = repo.firstpulled
853 except AttributeError: 1037 except AttributeError:
854 raise error.Abort(_("pulled() only available in --lfrev")) 1038 raise error.Abort(_("pulled() only available in --lfrev"))
855 return smartset.baseset([r for r in subset if r >= firstpulled]) 1039 return smartset.baseset([r for r in subset if r >= firstpulled])
856 1040
857 @eh.wrapcommand('clone', 1041
858 opts=[('', 'all-largefiles', None, 1042 @eh.wrapcommand(
859 _('download all versions of all largefiles'))]) 1043 'clone',
1044 opts=[
1045 (
1046 '',
1047 'all-largefiles',
1048 None,
1049 _('download all versions of all largefiles'),
1050 )
1051 ],
1052 )
860 def overrideclone(orig, ui, source, dest=None, **opts): 1053 def overrideclone(orig, ui, source, dest=None, **opts):
861 d = dest 1054 d = dest
862 if d is None: 1055 if d is None:
863 d = hg.defaultdest(source) 1056 d = hg.defaultdest(source)
864 if opts.get(r'all_largefiles') and not hg.islocal(d): 1057 if opts.get(r'all_largefiles') and not hg.islocal(d):
865 raise error.Abort(_( 1058 raise error.Abort(
866 '--all-largefiles is incompatible with non-local destination %s') % 1059 _('--all-largefiles is incompatible with non-local destination %s')
867 d) 1060 % d
1061 )
868 1062
869 return orig(ui, source, dest, **opts) 1063 return orig(ui, source, dest, **opts)
1064
870 1065
871 @eh.wrapfunction(hg, 'clone') 1066 @eh.wrapfunction(hg, 'clone')
872 def hgclone(orig, ui, opts, *args, **kwargs): 1067 def hgclone(orig, ui, opts, *args, **kwargs):
873 result = orig(ui, opts, *args, **kwargs) 1068 result = orig(ui, opts, *args, **kwargs)
874 1069
890 1085
891 if missing != 0: 1086 if missing != 0:
892 return None 1087 return None
893 1088
894 return result 1089 return result
1090
895 1091
896 @eh.wrapcommand('rebase', extension='rebase') 1092 @eh.wrapcommand('rebase', extension='rebase')
897 def overriderebase(orig, ui, repo, **opts): 1093 def overriderebase(orig, ui, repo, **opts):
898 if not util.safehasattr(repo, '_largefilesenabled'): 1094 if not util.safehasattr(repo, '_largefilesenabled'):
899 return orig(ui, repo, **opts) 1095 return orig(ui, repo, **opts)
905 return orig(ui, repo, **opts) 1101 return orig(ui, repo, **opts)
906 finally: 1102 finally:
907 repo._lfstatuswriters.pop() 1103 repo._lfstatuswriters.pop()
908 repo._lfcommithooks.pop() 1104 repo._lfcommithooks.pop()
909 1105
1106
910 @eh.wrapcommand('archive') 1107 @eh.wrapcommand('archive')
911 def overridearchivecmd(orig, ui, repo, dest, **opts): 1108 def overridearchivecmd(orig, ui, repo, dest, **opts):
912 repo.unfiltered().lfstatus = True 1109 repo.unfiltered().lfstatus = True
913 1110
914 try: 1111 try:
915 return orig(ui, repo.unfiltered(), dest, **opts) 1112 return orig(ui, repo.unfiltered(), dest, **opts)
916 finally: 1113 finally:
917 repo.unfiltered().lfstatus = False 1114 repo.unfiltered().lfstatus = False
918 1115
1116
919 @eh.wrapfunction(webcommands, 'archive') 1117 @eh.wrapfunction(webcommands, 'archive')
920 def hgwebarchive(orig, web): 1118 def hgwebarchive(orig, web):
921 web.repo.lfstatus = True 1119 web.repo.lfstatus = True
922 1120
923 try: 1121 try:
924 return orig(web) 1122 return orig(web)
925 finally: 1123 finally:
926 web.repo.lfstatus = False 1124 web.repo.lfstatus = False
927 1125
1126
928 @eh.wrapfunction(archival, 'archive') 1127 @eh.wrapfunction(archival, 'archive')
929 def overridearchive(orig, repo, dest, node, kind, decode=True, match=None, 1128 def overridearchive(
930 prefix='', mtime=None, subrepos=None): 1129 orig,
1130 repo,
1131 dest,
1132 node,
1133 kind,
1134 decode=True,
1135 match=None,
1136 prefix='',
1137 mtime=None,
1138 subrepos=None,
1139 ):
931 # For some reason setting repo.lfstatus in hgwebarchive only changes the 1140 # For some reason setting repo.lfstatus in hgwebarchive only changes the
932 # unfiltered repo's attr, so check that as well. 1141 # unfiltered repo's attr, so check that as well.
933 if not repo.lfstatus and not repo.unfiltered().lfstatus: 1142 if not repo.lfstatus and not repo.unfiltered().lfstatus:
934 return orig(repo, dest, node, kind, decode, match, prefix, mtime, 1143 return orig(
935 subrepos) 1144 repo, dest, node, kind, decode, match, prefix, mtime, subrepos
1145 )
936 1146
937 # No need to lock because we are only reading history and 1147 # No need to lock because we are only reading history and
938 # largefile caches, neither of which are modified. 1148 # largefile caches, neither of which are modified.
939 if node is not None: 1149 if node is not None:
940 lfcommands.cachelfiles(repo.ui, repo, node) 1150 lfcommands.cachelfiles(repo.ui, repo, node)
944 1154
945 ctx = repo[node] 1155 ctx = repo[node]
946 1156
947 if kind == 'files': 1157 if kind == 'files':
948 if prefix: 1158 if prefix:
949 raise error.Abort( 1159 raise error.Abort(_('cannot give prefix when archiving to files'))
950 _('cannot give prefix when archiving to files'))
951 else: 1160 else:
952 prefix = archival.tidyprefix(dest, kind, prefix) 1161 prefix = archival.tidyprefix(dest, kind, prefix)
953 1162
954 def write(name, mode, islink, getdata): 1163 def write(name, mode, islink, getdata):
955 if match and not match(name): 1164 if match and not match(name):
960 archiver.addfile(prefix + name, mode, islink, data) 1169 archiver.addfile(prefix + name, mode, islink, data)
961 1170
962 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0]) 1171 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
963 1172
964 if repo.ui.configbool("ui", "archivemeta"): 1173 if repo.ui.configbool("ui", "archivemeta"):
965 write('.hg_archival.txt', 0o644, False, 1174 write(
966 lambda: archival.buildmetadata(ctx)) 1175 '.hg_archival.txt',
1176 0o644,
1177 False,
1178 lambda: archival.buildmetadata(ctx),
1179 )
967 1180
968 for f in ctx: 1181 for f in ctx:
969 ff = ctx.flags(f) 1182 ff = ctx.flags(f)
970 getdata = ctx[f].data 1183 getdata = ctx[f].data
971 lfile = lfutil.splitstandin(f) 1184 lfile = lfutil.splitstandin(f)
973 if node is not None: 1186 if node is not None:
974 path = lfutil.findfile(repo, getdata().strip()) 1187 path = lfutil.findfile(repo, getdata().strip())
975 1188
976 if path is None: 1189 if path is None:
977 raise error.Abort( 1190 raise error.Abort(
978 _('largefile %s not found in repo store or system cache') 1191 _(
979 % lfile) 1192 'largefile %s not found in repo store or system cache'
1193 )
1194 % lfile
1195 )
980 else: 1196 else:
981 path = lfile 1197 path = lfile
982 1198
983 f = lfile 1199 f = lfile
984 1200
992 subprefix = prefix + subpath + '/' 1208 subprefix = prefix + subpath + '/'
993 sub._repo.lfstatus = True 1209 sub._repo.lfstatus = True
994 sub.archive(archiver, subprefix, submatch) 1210 sub.archive(archiver, subprefix, submatch)
995 1211
996 archiver.done() 1212 archiver.done()
1213
997 1214
998 @eh.wrapfunction(subrepo.hgsubrepo, 'archive') 1215 @eh.wrapfunction(subrepo.hgsubrepo, 'archive')
999 def hgsubrepoarchive(orig, repo, archiver, prefix, match=None, decode=True): 1216 def hgsubrepoarchive(orig, repo, archiver, prefix, match=None, decode=True):
1000 lfenabled = util.safehasattr(repo._repo, '_largefilesenabled') 1217 lfenabled = util.safehasattr(repo._repo, '_largefilesenabled')
1001 if not lfenabled or not repo._repo.lfstatus: 1218 if not lfenabled or not repo._repo.lfstatus:
1027 if ctx.node() is not None: 1244 if ctx.node() is not None:
1028 path = lfutil.findfile(repo._repo, getdata().strip()) 1245 path = lfutil.findfile(repo._repo, getdata().strip())
1029 1246
1030 if path is None: 1247 if path is None:
1031 raise error.Abort( 1248 raise error.Abort(
1032 _('largefile %s not found in repo store or system cache') 1249 _(
1033 % lfile) 1250 'largefile %s not found in repo store or system cache'
1251 )
1252 % lfile
1253 )
1034 else: 1254 else:
1035 path = lfile 1255 path = lfile
1036 1256
1037 f = lfile 1257 f = lfile
1038 1258
1044 sub = ctx.workingsub(subpath) 1264 sub = ctx.workingsub(subpath)
1045 submatch = matchmod.subdirmatcher(subpath, match) 1265 submatch = matchmod.subdirmatcher(subpath, match)
1046 subprefix = prefix + subpath + '/' 1266 subprefix = prefix + subpath + '/'
1047 sub._repo.lfstatus = True 1267 sub._repo.lfstatus = True
1048 sub.archive(archiver, subprefix, submatch, decode) 1268 sub.archive(archiver, subprefix, submatch, decode)
1269
1049 1270
1050 # If a largefile is modified, the change is not reflected in its 1271 # If a largefile is modified, the change is not reflected in its
1051 # standin until a commit. cmdutil.bailifchanged() raises an exception 1272 # standin until a commit. cmdutil.bailifchanged() raises an exception
1052 # if the repo has uncommitted changes. Wrap it to also check if 1273 # if the repo has uncommitted changes. Wrap it to also check if
1053 # largefiles were changed. This is used by bisect, backout and fetch. 1274 # largefiles were changed. This is used by bisect, backout and fetch.
1058 s = repo.status() 1279 s = repo.status()
1059 repo.lfstatus = False 1280 repo.lfstatus = False
1060 if s.modified or s.added or s.removed or s.deleted: 1281 if s.modified or s.added or s.removed or s.deleted:
1061 raise error.Abort(_('uncommitted changes')) 1282 raise error.Abort(_('uncommitted changes'))
1062 1283
1284
1063 @eh.wrapfunction(cmdutil, 'postcommitstatus') 1285 @eh.wrapfunction(cmdutil, 'postcommitstatus')
1064 def postcommitstatus(orig, repo, *args, **kwargs): 1286 def postcommitstatus(orig, repo, *args, **kwargs):
1065 repo.lfstatus = True 1287 repo.lfstatus = True
1066 try: 1288 try:
1067 return orig(repo, *args, **kwargs) 1289 return orig(repo, *args, **kwargs)
1068 finally: 1290 finally:
1069 repo.lfstatus = False 1291 repo.lfstatus = False
1070 1292
1293
1071 @eh.wrapfunction(cmdutil, 'forget') 1294 @eh.wrapfunction(cmdutil, 'forget')
1072 def cmdutilforget(orig, ui, repo, match, prefix, uipathfn, explicitonly, dryrun, 1295 def cmdutilforget(
1073 interactive): 1296 orig, ui, repo, match, prefix, uipathfn, explicitonly, dryrun, interactive
1297 ):
1074 normalmatcher = composenormalfilematcher(match, repo[None].manifest()) 1298 normalmatcher = composenormalfilematcher(match, repo[None].manifest())
1075 bad, forgot = orig(ui, repo, normalmatcher, prefix, uipathfn, explicitonly, 1299 bad, forgot = orig(
1076 dryrun, interactive) 1300 ui,
1301 repo,
1302 normalmatcher,
1303 prefix,
1304 uipathfn,
1305 explicitonly,
1306 dryrun,
1307 interactive,
1308 )
1077 m = composelargefilematcher(match, repo[None].manifest()) 1309 m = composelargefilematcher(match, repo[None].manifest())
1078 1310
1079 try: 1311 try:
1080 repo.lfstatus = True 1312 repo.lfstatus = True
1081 s = repo.status(match=m, clean=True) 1313 s = repo.status(match=m, clean=True)
1086 forget = [f for f in forget if lfutil.standin(f) in manifest] 1318 forget = [f for f in forget if lfutil.standin(f) in manifest]
1087 1319
1088 for f in forget: 1320 for f in forget:
1089 fstandin = lfutil.standin(f) 1321 fstandin = lfutil.standin(f)
1090 if fstandin not in repo.dirstate and not repo.wvfs.isdir(fstandin): 1322 if fstandin not in repo.dirstate and not repo.wvfs.isdir(fstandin):
1091 ui.warn(_('not removing %s: file is already untracked\n') 1323 ui.warn(
1092 % uipathfn(f)) 1324 _('not removing %s: file is already untracked\n') % uipathfn(f)
1325 )
1093 bad.append(f) 1326 bad.append(f)
1094 1327
1095 for f in forget: 1328 for f in forget:
1096 if ui.verbose or not m.exact(f): 1329 if ui.verbose or not m.exact(f):
1097 ui.status(_('removing %s\n') % uipathfn(f)) 1330 ui.status(_('removing %s\n') % uipathfn(f))
1113 1346
1114 bad.extend(f for f in rejected if f in m.files()) 1347 bad.extend(f for f in rejected if f in m.files())
1115 forgot.extend(f for f in forget if f not in rejected) 1348 forgot.extend(f for f in forget if f not in rejected)
1116 return bad, forgot 1349 return bad, forgot
1117 1350
1351
1118 def _getoutgoings(repo, other, missing, addfunc): 1352 def _getoutgoings(repo, other, missing, addfunc):
1119 """get pairs of filename and largefile hash in outgoing revisions 1353 """get pairs of filename and largefile hash in outgoing revisions
1120 in 'missing'. 1354 in 'missing'.
1121 1355
1122 largefiles already existing on 'other' repository are ignored. 1356 largefiles already existing on 'other' repository are ignored.
1124 'addfunc' is invoked with each unique pairs of filename and 1358 'addfunc' is invoked with each unique pairs of filename and
1125 largefile hash value. 1359 largefile hash value.
1126 """ 1360 """
1127 knowns = set() 1361 knowns = set()
1128 lfhashes = set() 1362 lfhashes = set()
1363
1129 def dedup(fn, lfhash): 1364 def dedup(fn, lfhash):
1130 k = (fn, lfhash) 1365 k = (fn, lfhash)
1131 if k not in knowns: 1366 if k not in knowns:
1132 knowns.add(k) 1367 knowns.add(k)
1133 lfhashes.add(lfhash) 1368 lfhashes.add(lfhash)
1369
1134 lfutil.getlfilestoupload(repo, missing, dedup) 1370 lfutil.getlfilestoupload(repo, missing, dedup)
1135 if lfhashes: 1371 if lfhashes:
1136 lfexists = storefactory.openstore(repo, other).exists(lfhashes) 1372 lfexists = storefactory.openstore(repo, other).exists(lfhashes)
1137 for fn, lfhash in knowns: 1373 for fn, lfhash in knowns:
1138 if not lfexists[lfhash]: # lfhash doesn't exist on "other" 1374 if not lfexists[lfhash]: # lfhash doesn't exist on "other"
1139 addfunc(fn, lfhash) 1375 addfunc(fn, lfhash)
1376
1140 1377
1141 def outgoinghook(ui, repo, other, opts, missing): 1378 def outgoinghook(ui, repo, other, opts, missing):
1142 if opts.pop('large', None): 1379 if opts.pop('large', None):
1143 lfhashes = set() 1380 lfhashes = set()
1144 if ui.debugflag: 1381 if ui.debugflag:
1145 toupload = {} 1382 toupload = {}
1383
1146 def addfunc(fn, lfhash): 1384 def addfunc(fn, lfhash):
1147 if fn not in toupload: 1385 if fn not in toupload:
1148 toupload[fn] = [] 1386 toupload[fn] = []
1149 toupload[fn].append(lfhash) 1387 toupload[fn].append(lfhash)
1150 lfhashes.add(lfhash) 1388 lfhashes.add(lfhash)
1389
1151 def showhashes(fn): 1390 def showhashes(fn):
1152 for lfhash in sorted(toupload[fn]): 1391 for lfhash in sorted(toupload[fn]):
1153 ui.debug(' %s\n' % (lfhash)) 1392 ui.debug(' %s\n' % lfhash)
1393
1154 else: 1394 else:
1155 toupload = set() 1395 toupload = set()
1396
1156 def addfunc(fn, lfhash): 1397 def addfunc(fn, lfhash):
1157 toupload.add(fn) 1398 toupload.add(fn)
1158 lfhashes.add(lfhash) 1399 lfhashes.add(lfhash)
1400
1159 def showhashes(fn): 1401 def showhashes(fn):
1160 pass 1402 pass
1403
1161 _getoutgoings(repo, other, missing, addfunc) 1404 _getoutgoings(repo, other, missing, addfunc)
1162 1405
1163 if not toupload: 1406 if not toupload:
1164 ui.status(_('largefiles: no files to upload\n')) 1407 ui.status(_('largefiles: no files to upload\n'))
1165 else: 1408 else:
1166 ui.status(_('largefiles to upload (%d entities):\n') 1409 ui.status(
1167 % (len(lfhashes))) 1410 _('largefiles to upload (%d entities):\n') % (len(lfhashes))
1411 )
1168 for file in sorted(toupload): 1412 for file in sorted(toupload):
1169 ui.status(lfutil.splitstandin(file) + '\n') 1413 ui.status(lfutil.splitstandin(file) + '\n')
1170 showhashes(file) 1414 showhashes(file)
1171 ui.status('\n') 1415 ui.status('\n')
1172 1416
1173 @eh.wrapcommand('outgoing', 1417
1174 opts=[('', 'large', None, _('display outgoing largefiles'))]) 1418 @eh.wrapcommand(
1419 'outgoing', opts=[('', 'large', None, _('display outgoing largefiles'))]
1420 )
1175 def _outgoingcmd(orig, *args, **kwargs): 1421 def _outgoingcmd(orig, *args, **kwargs):
1176 # Nothing to do here other than add the extra help option- the hook above 1422 # Nothing to do here other than add the extra help option- the hook above
1177 # processes it. 1423 # processes it.
1178 return orig(*args, **kwargs) 1424 return orig(*args, **kwargs)
1179 1425
1426
1180 def summaryremotehook(ui, repo, opts, changes): 1427 def summaryremotehook(ui, repo, opts, changes):
1181 largeopt = opts.get('large', False) 1428 largeopt = opts.get('large', False)
1182 if changes is None: 1429 if changes is None:
1183 if largeopt: 1430 if largeopt:
1184 return (False, True) # only outgoing check is needed 1431 return (False, True) # only outgoing check is needed
1185 else: 1432 else:
1186 return (False, False) 1433 return (False, False)
1187 elif largeopt: 1434 elif largeopt:
1188 url, branch, peer, outgoing = changes[1] 1435 url, branch, peer, outgoing = changes[1]
1189 if peer is None: 1436 if peer is None:
1191 ui.status(_('largefiles: (no remote repo)\n')) 1438 ui.status(_('largefiles: (no remote repo)\n'))
1192 return 1439 return
1193 1440
1194 toupload = set() 1441 toupload = set()
1195 lfhashes = set() 1442 lfhashes = set()
1443
1196 def addfunc(fn, lfhash): 1444 def addfunc(fn, lfhash):
1197 toupload.add(fn) 1445 toupload.add(fn)
1198 lfhashes.add(lfhash) 1446 lfhashes.add(lfhash)
1447
1199 _getoutgoings(repo, peer, outgoing.missing, addfunc) 1448 _getoutgoings(repo, peer, outgoing.missing, addfunc)
1200 1449
1201 if not toupload: 1450 if not toupload:
1202 # i18n: column positioning for "hg summary" 1451 # i18n: column positioning for "hg summary"
1203 ui.status(_('largefiles: (no files to upload)\n')) 1452 ui.status(_('largefiles: (no files to upload)\n'))
1204 else: 1453 else:
1205 # i18n: column positioning for "hg summary" 1454 # i18n: column positioning for "hg summary"
1206 ui.status(_('largefiles: %d entities for %d files to upload\n') 1455 ui.status(
1207 % (len(lfhashes), len(toupload))) 1456 _('largefiles: %d entities for %d files to upload\n')
1208 1457 % (len(lfhashes), len(toupload))
1209 @eh.wrapcommand('summary', 1458 )
1210 opts=[('', 'large', None, _('display outgoing largefiles'))]) 1459
1460
1461 @eh.wrapcommand(
1462 'summary', opts=[('', 'large', None, _('display outgoing largefiles'))]
1463 )
1211 def overridesummary(orig, ui, repo, *pats, **opts): 1464 def overridesummary(orig, ui, repo, *pats, **opts):
1212 try: 1465 try:
1213 repo.lfstatus = True 1466 repo.lfstatus = True
1214 orig(ui, repo, *pats, **opts) 1467 orig(ui, repo, *pats, **opts)
1215 finally: 1468 finally:
1216 repo.lfstatus = False 1469 repo.lfstatus = False
1470
1217 1471
1218 @eh.wrapfunction(scmutil, 'addremove') 1472 @eh.wrapfunction(scmutil, 'addremove')
1219 def scmutiladdremove(orig, repo, matcher, prefix, uipathfn, opts=None): 1473 def scmutiladdremove(orig, repo, matcher, prefix, uipathfn, opts=None):
1220 if opts is None: 1474 if opts is None:
1221 opts = {} 1475 opts = {}
1222 if not lfutil.islfilesrepo(repo): 1476 if not lfutil.islfilesrepo(repo):
1223 return orig(repo, matcher, prefix, uipathfn, opts) 1477 return orig(repo, matcher, prefix, uipathfn, opts)
1224 # Get the list of missing largefiles so we can remove them 1478 # Get the list of missing largefiles so we can remove them
1225 lfdirstate = lfutil.openlfdirstate(repo.ui, repo) 1479 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1226 unsure, s = lfdirstate.status(matchmod.always(), subrepos=[], 1480 unsure, s = lfdirstate.status(
1227 ignored=False, clean=False, unknown=False) 1481 matchmod.always(),
1482 subrepos=[],
1483 ignored=False,
1484 clean=False,
1485 unknown=False,
1486 )
1228 1487
1229 # Call into the normal remove code, but the removing of the standin, we want 1488 # Call into the normal remove code, but the removing of the standin, we want
1230 # to have handled by original addremove. Monkey patching here makes sure 1489 # to have handled by original addremove. Monkey patching here makes sure
1231 # we don't remove the standin in the largefiles code, preventing a very 1490 # we don't remove the standin in the largefiles code, preventing a very
1232 # confused state later. 1491 # confused state later.
1238 # or not the file name is printed, and how. Simply limit the original 1497 # or not the file name is printed, and how. Simply limit the original
1239 # matches to those in the deleted status list. 1498 # matches to those in the deleted status list.
1240 matchfn = m.matchfn 1499 matchfn = m.matchfn
1241 m.matchfn = lambda f: f in s.deleted and matchfn(f) 1500 m.matchfn = lambda f: f in s.deleted and matchfn(f)
1242 1501
1243 removelargefiles(repo.ui, repo, True, m, uipathfn, opts.get('dry_run'), 1502 removelargefiles(
1244 **pycompat.strkwargs(opts)) 1503 repo.ui,
1504 repo,
1505 True,
1506 m,
1507 uipathfn,
1508 opts.get('dry_run'),
1509 **pycompat.strkwargs(opts)
1510 )
1245 # Call into the normal add code, and any files that *should* be added as 1511 # Call into the normal add code, and any files that *should* be added as
1246 # largefiles will be 1512 # largefiles will be
1247 added, bad = addlargefiles(repo.ui, repo, True, matcher, uipathfn, 1513 added, bad = addlargefiles(
1248 **pycompat.strkwargs(opts)) 1514 repo.ui, repo, True, matcher, uipathfn, **pycompat.strkwargs(opts)
1515 )
1249 # Now that we've handled largefiles, hand off to the original addremove 1516 # Now that we've handled largefiles, hand off to the original addremove
1250 # function to take care of the rest. Make sure it doesn't do anything with 1517 # function to take care of the rest. Make sure it doesn't do anything with
1251 # largefiles by passing a matcher that will ignore them. 1518 # largefiles by passing a matcher that will ignore them.
1252 matcher = composenormalfilematcher(matcher, repo[None].manifest(), added) 1519 matcher = composenormalfilematcher(matcher, repo[None].manifest(), added)
1253 return orig(repo, matcher, prefix, uipathfn, opts) 1520 return orig(repo, matcher, prefix, uipathfn, opts)
1521
1254 1522
1255 # Calling purge with --all will cause the largefiles to be deleted. 1523 # Calling purge with --all will cause the largefiles to be deleted.
1256 # Override repo.status to prevent this from happening. 1524 # Override repo.status to prevent this from happening.
1257 @eh.wrapcommand('purge', extension='purge') 1525 @eh.wrapcommand('purge', extension='purge')
1258 def overridepurge(orig, ui, repo, *dirs, **opts): 1526 def overridepurge(orig, ui, repo, *dirs, **opts):
1265 # 1533 #
1266 # As a work around we use an unfiltered repo here. We should do something 1534 # As a work around we use an unfiltered repo here. We should do something
1267 # cleaner instead. 1535 # cleaner instead.
1268 repo = repo.unfiltered() 1536 repo = repo.unfiltered()
1269 oldstatus = repo.status 1537 oldstatus = repo.status
1270 def overridestatus(node1='.', node2=None, match=None, ignored=False, 1538
1271 clean=False, unknown=False, listsubrepos=False): 1539 def overridestatus(
1272 r = oldstatus(node1, node2, match, ignored, clean, unknown, 1540 node1='.',
1273 listsubrepos) 1541 node2=None,
1542 match=None,
1543 ignored=False,
1544 clean=False,
1545 unknown=False,
1546 listsubrepos=False,
1547 ):
1548 r = oldstatus(
1549 node1, node2, match, ignored, clean, unknown, listsubrepos
1550 )
1274 lfdirstate = lfutil.openlfdirstate(ui, repo) 1551 lfdirstate = lfutil.openlfdirstate(ui, repo)
1275 unknown = [f for f in r.unknown if lfdirstate[f] == '?'] 1552 unknown = [f for f in r.unknown if lfdirstate[f] == '?']
1276 ignored = [f for f in r.ignored if lfdirstate[f] == '?'] 1553 ignored = [f for f in r.ignored if lfdirstate[f] == '?']
1277 return scmutil.status(r.modified, r.added, r.removed, r.deleted, 1554 return scmutil.status(
1278 unknown, ignored, r.clean) 1555 r.modified, r.added, r.removed, r.deleted, unknown, ignored, r.clean
1556 )
1557
1279 repo.status = overridestatus 1558 repo.status = overridestatus
1280 orig(ui, repo, *dirs, **opts) 1559 orig(ui, repo, *dirs, **opts)
1281 repo.status = oldstatus 1560 repo.status = oldstatus
1561
1282 1562
1283 @eh.wrapcommand('rollback') 1563 @eh.wrapcommand('rollback')
1284 def overriderollback(orig, ui, repo, **opts): 1564 def overriderollback(orig, ui, repo, **opts):
1285 with repo.wlock(): 1565 with repo.wlock():
1286 before = repo.dirstate.parents() 1566 before = repo.dirstate.parents()
1287 orphans = set(f for f in repo.dirstate 1567 orphans = set(
1288 if lfutil.isstandin(f) and repo.dirstate[f] != 'r') 1568 f
1569 for f in repo.dirstate
1570 if lfutil.isstandin(f) and repo.dirstate[f] != 'r'
1571 )
1289 result = orig(ui, repo, **opts) 1572 result = orig(ui, repo, **opts)
1290 after = repo.dirstate.parents() 1573 after = repo.dirstate.parents()
1291 if before == after: 1574 if before == after:
1292 return result # no need to restore standins 1575 return result # no need to restore standins
1293 1576
1294 pctx = repo['.'] 1577 pctx = repo['.']
1295 for f in repo.dirstate: 1578 for f in repo.dirstate:
1296 if lfutil.isstandin(f): 1579 if lfutil.isstandin(f):
1297 orphans.discard(f) 1580 orphans.discard(f)
1316 for lfile in orphans: 1599 for lfile in orphans:
1317 lfdirstate.drop(lfile) 1600 lfdirstate.drop(lfile)
1318 lfdirstate.write() 1601 lfdirstate.write()
1319 return result 1602 return result
1320 1603
1604
1321 @eh.wrapcommand('transplant', extension='transplant') 1605 @eh.wrapcommand('transplant', extension='transplant')
1322 def overridetransplant(orig, ui, repo, *revs, **opts): 1606 def overridetransplant(orig, ui, repo, *revs, **opts):
1323 resuming = opts.get(r'continue') 1607 resuming = opts.get(r'continue')
1324 repo._lfcommithooks.append(lfutil.automatedcommithook(resuming)) 1608 repo._lfcommithooks.append(lfutil.automatedcommithook(resuming))
1325 repo._lfstatuswriters.append(lambda *msg, **opts: None) 1609 repo._lfstatuswriters.append(lambda *msg, **opts: None)
1328 finally: 1612 finally:
1329 repo._lfstatuswriters.pop() 1613 repo._lfstatuswriters.pop()
1330 repo._lfcommithooks.pop() 1614 repo._lfcommithooks.pop()
1331 return result 1615 return result
1332 1616
1617
1333 @eh.wrapcommand('cat') 1618 @eh.wrapcommand('cat')
1334 def overridecat(orig, ui, repo, file1, *pats, **opts): 1619 def overridecat(orig, ui, repo, file1, *pats, **opts):
1335 opts = pycompat.byteskwargs(opts) 1620 opts = pycompat.byteskwargs(opts)
1336 ctx = scmutil.revsingle(repo, opts.get('rev')) 1621 ctx = scmutil.revsingle(repo, opts.get('rev'))
1337 err = 1 1622 err = 1
1338 notbad = set() 1623 notbad = set()
1339 m = scmutil.match(ctx, (file1,) + pats, opts) 1624 m = scmutil.match(ctx, (file1,) + pats, opts)
1340 origmatchfn = m.matchfn 1625 origmatchfn = m.matchfn
1626
1341 def lfmatchfn(f): 1627 def lfmatchfn(f):
1342 if origmatchfn(f): 1628 if origmatchfn(f):
1343 return True 1629 return True
1344 lf = lfutil.splitstandin(f) 1630 lf = lfutil.splitstandin(f)
1345 if lf is None: 1631 if lf is None:
1346 return False 1632 return False
1347 notbad.add(lf) 1633 notbad.add(lf)
1348 return origmatchfn(lf) 1634 return origmatchfn(lf)
1635
1349 m.matchfn = lfmatchfn 1636 m.matchfn = lfmatchfn
1350 origbadfn = m.bad 1637 origbadfn = m.bad
1638
1351 def lfbadfn(f, msg): 1639 def lfbadfn(f, msg):
1352 if not f in notbad: 1640 if not f in notbad:
1353 origbadfn(f, msg) 1641 origbadfn(f, msg)
1642
1354 m.bad = lfbadfn 1643 m.bad = lfbadfn
1355 1644
1356 origvisitdirfn = m.visitdir 1645 origvisitdirfn = m.visitdir
1646
1357 def lfvisitdirfn(dir): 1647 def lfvisitdirfn(dir):
1358 if dir == lfutil.shortname: 1648 if dir == lfutil.shortname:
1359 return True 1649 return True
1360 ret = origvisitdirfn(dir) 1650 ret = origvisitdirfn(dir)
1361 if ret: 1651 if ret:
1362 return ret 1652 return ret
1363 lf = lfutil.splitstandin(dir) 1653 lf = lfutil.splitstandin(dir)
1364 if lf is None: 1654 if lf is None:
1365 return False 1655 return False
1366 return origvisitdirfn(lf) 1656 return origvisitdirfn(lf)
1657
1367 m.visitdir = lfvisitdirfn 1658 m.visitdir = lfvisitdirfn
1368 1659
1369 for f in ctx.walk(m): 1660 for f in ctx.walk(m):
1370 with cmdutil.makefileobj(ctx, opts.get('output'), pathname=f) as fp: 1661 with cmdutil.makefileobj(ctx, opts.get('output'), pathname=f) as fp:
1371 lf = lfutil.splitstandin(f) 1662 lf = lfutil.splitstandin(f)
1380 if not lfutil.inusercache(repo.ui, hash): 1671 if not lfutil.inusercache(repo.ui, hash):
1381 store = storefactory.openstore(repo) 1672 store = storefactory.openstore(repo)
1382 success, missing = store.get([(lf, hash)]) 1673 success, missing = store.get([(lf, hash)])
1383 if len(success) != 1: 1674 if len(success) != 1:
1384 raise error.Abort( 1675 raise error.Abort(
1385 _('largefile %s is not in cache and could not be ' 1676 _(
1386 'downloaded') % lf) 1677 'largefile %s is not in cache and could not be '
1678 'downloaded'
1679 )
1680 % lf
1681 )
1387 path = lfutil.usercachepath(repo.ui, hash) 1682 path = lfutil.usercachepath(repo.ui, hash)
1388 with open(path, "rb") as fpin: 1683 with open(path, "rb") as fpin:
1389 for chunk in util.filechunkiter(fpin): 1684 for chunk in util.filechunkiter(fpin):
1390 fp.write(chunk) 1685 fp.write(chunk)
1391 err = 0 1686 err = 0
1392 return err 1687 return err
1393 1688
1689
1394 @eh.wrapfunction(merge, 'update') 1690 @eh.wrapfunction(merge, 'update')
1395 def mergeupdate(orig, repo, node, branchmerge, force, 1691 def mergeupdate(orig, repo, node, branchmerge, force, *args, **kwargs):
1396 *args, **kwargs):
1397 matcher = kwargs.get(r'matcher', None) 1692 matcher = kwargs.get(r'matcher', None)
1398 # note if this is a partial update 1693 # note if this is a partial update
1399 partial = matcher and not matcher.always() 1694 partial = matcher and not matcher.always()
1400 with repo.wlock(): 1695 with repo.wlock():
1401 # branch | | | 1696 # branch | | |
1412 # 1707 #
1413 # (*) don't care 1708 # (*) don't care
1414 # (*1) deprecated, but used internally (e.g: "rebase --collapse") 1709 # (*1) deprecated, but used internally (e.g: "rebase --collapse")
1415 1710
1416 lfdirstate = lfutil.openlfdirstate(repo.ui, repo) 1711 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1417 unsure, s = lfdirstate.status(matchmod.always(), subrepos=[], 1712 unsure, s = lfdirstate.status(
1418 ignored=False, clean=True, unknown=False) 1713 matchmod.always(),
1714 subrepos=[],
1715 ignored=False,
1716 clean=True,
1717 unknown=False,
1718 )
1419 oldclean = set(s.clean) 1719 oldclean = set(s.clean)
1420 pctx = repo['.'] 1720 pctx = repo['.']
1421 dctx = repo[node] 1721 dctx = repo[node]
1422 for lfile in unsure + s.modified: 1722 for lfile in unsure + s.modified:
1423 lfileabs = repo.wvfs.join(lfile) 1723 lfileabs = repo.wvfs.join(lfile)
1424 if not repo.wvfs.exists(lfileabs): 1724 if not repo.wvfs.exists(lfileabs):
1425 continue 1725 continue
1426 lfhash = lfutil.hashfile(lfileabs) 1726 lfhash = lfutil.hashfile(lfileabs)
1427 standin = lfutil.standin(lfile) 1727 standin = lfutil.standin(lfile)
1428 lfutil.writestandin(repo, standin, lfhash, 1728 lfutil.writestandin(
1429 lfutil.getexecutable(lfileabs)) 1729 repo, standin, lfhash, lfutil.getexecutable(lfileabs)
1430 if (standin in pctx and 1730 )
1431 lfhash == lfutil.readasstandin(pctx[standin])): 1731 if standin in pctx and lfhash == lfutil.readasstandin(
1732 pctx[standin]
1733 ):
1432 oldclean.add(lfile) 1734 oldclean.add(lfile)
1433 for lfile in s.added: 1735 for lfile in s.added:
1434 fstandin = lfutil.standin(lfile) 1736 fstandin = lfutil.standin(lfile)
1435 if fstandin not in dctx: 1737 if fstandin not in dctx:
1436 # in this case, content of standin file is meaningless 1738 # in this case, content of standin file is meaningless
1460 lfdirstate.write() 1762 lfdirstate.write()
1461 1763
1462 if branchmerge or force or partial: 1764 if branchmerge or force or partial:
1463 filelist.extend(s.deleted + s.removed) 1765 filelist.extend(s.deleted + s.removed)
1464 1766
1465 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist, 1767 lfcommands.updatelfiles(
1466 normallookup=partial) 1768 repo.ui, repo, filelist=filelist, normallookup=partial
1769 )
1467 1770
1468 return result 1771 return result
1772
1469 1773
1470 @eh.wrapfunction(scmutil, 'marktouched') 1774 @eh.wrapfunction(scmutil, 'marktouched')
1471 def scmutilmarktouched(orig, repo, files, *args, **kwargs): 1775 def scmutilmarktouched(orig, repo, files, *args, **kwargs):
1472 result = orig(repo, files, *args, **kwargs) 1776 result = orig(repo, files, *args, **kwargs)
1473 1777
1475 for f in files: 1779 for f in files:
1476 lf = lfutil.splitstandin(f) 1780 lf = lfutil.splitstandin(f)
1477 if lf is not None: 1781 if lf is not None:
1478 filelist.append(lf) 1782 filelist.append(lf)
1479 if filelist: 1783 if filelist:
1480 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist, 1784 lfcommands.updatelfiles(
1481 printmessage=False, normallookup=True) 1785 repo.ui,
1786 repo,
1787 filelist=filelist,
1788 printmessage=False,
1789 normallookup=True,
1790 )
1482 1791
1483 return result 1792 return result
1793
1484 1794
1485 @eh.wrapfunction(upgrade, 'preservedrequirements') 1795 @eh.wrapfunction(upgrade, 'preservedrequirements')
1486 @eh.wrapfunction(upgrade, 'supporteddestrequirements') 1796 @eh.wrapfunction(upgrade, 'supporteddestrequirements')
1487 def upgraderequirements(orig, repo): 1797 def upgraderequirements(orig, repo):
1488 reqs = orig(repo) 1798 reqs = orig(repo)
1489 if 'largefiles' in repo.requirements: 1799 if 'largefiles' in repo.requirements:
1490 reqs.add('largefiles') 1800 reqs.add('largefiles')
1491 return reqs 1801 return reqs
1492 1802
1803
1493 _lfscheme = 'largefile://' 1804 _lfscheme = 'largefile://'
1805
1494 1806
1495 @eh.wrapfunction(urlmod, 'open') 1807 @eh.wrapfunction(urlmod, 'open')
1496 def openlargefile(orig, ui, url_, data=None): 1808 def openlargefile(orig, ui, url_, data=None):
1497 if url_.startswith(_lfscheme): 1809 if url_.startswith(_lfscheme):
1498 if data: 1810 if data:
1499 msg = "cannot use data on a 'largefile://' url" 1811 msg = "cannot use data on a 'largefile://' url"
1500 raise error.ProgrammingError(msg) 1812 raise error.ProgrammingError(msg)
1501 lfid = url_[len(_lfscheme):] 1813 lfid = url_[len(_lfscheme) :]
1502 return storefactory.getlfile(ui, lfid) 1814 return storefactory.getlfile(ui, lfid)
1503 else: 1815 else:
1504 return orig(ui, url_, data=data) 1816 return orig(ui, url_, data=data)