##// END OF EJS Templates
largefiles: avoid printing messages while transplanting by "_lfstatuswriters"...
FUJIWARA Katsunori -
r23275:fae708cb default
parent child Browse files
Show More
@@ -1,1300 +1,1295 b''
1 1 # Copyright 2009-2010 Gregory P. Ward
2 2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
3 3 # Copyright 2010-2011 Fog Creek Software
4 4 # Copyright 2010-2011 Unity Technologies
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 '''Overridden Mercurial commands and functions for the largefiles extension'''
10 10
11 11 import os
12 12 import copy
13 13
14 14 from mercurial import hg, util, cmdutil, scmutil, match as match_, \
15 15 archival, pathutil, revset
16 16 from mercurial.i18n import _
17 17 from mercurial.node import hex
18 18
19 19 import lfutil
20 20 import lfcommands
21 21 import basestore
22 22
23 23 # -- Utility functions: commonly/repeatedly needed functionality ---------------
24 24
25 25 def installnormalfilesmatchfn(manifest):
26 26 '''installmatchfn with a matchfn that ignores all largefiles'''
27 27 def overridematch(ctx, pats=[], opts={}, globbed=False,
28 28 default='relpath'):
29 29 match = oldmatch(ctx, pats, opts, globbed, default)
30 30 m = copy.copy(match)
31 31 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
32 32 manifest)
33 33 m._files = filter(notlfile, m._files)
34 34 m._fmap = set(m._files)
35 35 m._always = False
36 36 origmatchfn = m.matchfn
37 37 m.matchfn = lambda f: notlfile(f) and origmatchfn(f)
38 38 return m
39 39 oldmatch = installmatchfn(overridematch)
40 40
41 41 def installmatchfn(f):
42 42 '''monkey patch the scmutil module with a custom match function.
43 43 Warning: it is monkey patching the _module_ on runtime! Not thread safe!'''
44 44 oldmatch = scmutil.match
45 45 setattr(f, 'oldmatch', oldmatch)
46 46 scmutil.match = f
47 47 return oldmatch
48 48
49 49 def restorematchfn():
50 50 '''restores scmutil.match to what it was before installmatchfn
51 51 was called. no-op if scmutil.match is its original function.
52 52
53 53 Note that n calls to installmatchfn will require n calls to
54 54 restore matchfn to reverse'''
55 55 scmutil.match = getattr(scmutil.match, 'oldmatch')
56 56
57 57 def installmatchandpatsfn(f):
58 58 oldmatchandpats = scmutil.matchandpats
59 59 setattr(f, 'oldmatchandpats', oldmatchandpats)
60 60 scmutil.matchandpats = f
61 61 return oldmatchandpats
62 62
63 63 def restorematchandpatsfn():
64 64 '''restores scmutil.matchandpats to what it was before
65 65 installmatchandpatsfn was called. No-op if scmutil.matchandpats
66 66 is its original function.
67 67
68 68 Note that n calls to installmatchandpatsfn will require n calls
69 69 to restore matchfn to reverse'''
70 70 scmutil.matchandpats = getattr(scmutil.matchandpats, 'oldmatchandpats',
71 71 scmutil.matchandpats)
72 72
73 73 def addlargefiles(ui, repo, *pats, **opts):
74 74 large = opts.pop('large', None)
75 75 lfsize = lfutil.getminsize(
76 76 ui, lfutil.islfilesrepo(repo), opts.pop('lfsize', None))
77 77
78 78 lfmatcher = None
79 79 if lfutil.islfilesrepo(repo):
80 80 lfpats = ui.configlist(lfutil.longname, 'patterns', default=[])
81 81 if lfpats:
82 82 lfmatcher = match_.match(repo.root, '', list(lfpats))
83 83
84 84 lfnames = []
85 85 m = scmutil.match(repo[None], pats, opts)
86 86 m.bad = lambda x, y: None
87 87 wctx = repo[None]
88 88 for f in repo.walk(m):
89 89 exact = m.exact(f)
90 90 lfile = lfutil.standin(f) in wctx
91 91 nfile = f in wctx
92 92 exists = lfile or nfile
93 93
94 94 # Don't warn the user when they attempt to add a normal tracked file.
95 95 # The normal add code will do that for us.
96 96 if exact and exists:
97 97 if lfile:
98 98 ui.warn(_('%s already a largefile\n') % f)
99 99 continue
100 100
101 101 if (exact or not exists) and not lfutil.isstandin(f):
102 102 wfile = repo.wjoin(f)
103 103
104 104 # In case the file was removed previously, but not committed
105 105 # (issue3507)
106 106 if not os.path.exists(wfile):
107 107 continue
108 108
109 109 abovemin = (lfsize and
110 110 os.lstat(wfile).st_size >= lfsize * 1024 * 1024)
111 111 if large or abovemin or (lfmatcher and lfmatcher(f)):
112 112 lfnames.append(f)
113 113 if ui.verbose or not exact:
114 114 ui.status(_('adding %s as a largefile\n') % m.rel(f))
115 115
116 116 bad = []
117 117
118 118 # Need to lock, otherwise there could be a race condition between
119 119 # when standins are created and added to the repo.
120 120 wlock = repo.wlock()
121 121 try:
122 122 if not opts.get('dry_run'):
123 123 standins = []
124 124 lfdirstate = lfutil.openlfdirstate(ui, repo)
125 125 for f in lfnames:
126 126 standinname = lfutil.standin(f)
127 127 lfutil.writestandin(repo, standinname, hash='',
128 128 executable=lfutil.getexecutable(repo.wjoin(f)))
129 129 standins.append(standinname)
130 130 if lfdirstate[f] == 'r':
131 131 lfdirstate.normallookup(f)
132 132 else:
133 133 lfdirstate.add(f)
134 134 lfdirstate.write()
135 135 bad += [lfutil.splitstandin(f)
136 136 for f in repo[None].add(standins)
137 137 if f in m.files()]
138 138 finally:
139 139 wlock.release()
140 140 return bad
141 141
142 142 def removelargefiles(ui, repo, isaddremove, *pats, **opts):
143 143 after = opts.get('after')
144 144 if not pats and not after:
145 145 raise util.Abort(_('no files specified'))
146 146 m = scmutil.match(repo[None], pats, opts)
147 147 try:
148 148 repo.lfstatus = True
149 149 s = repo.status(match=m, clean=True)
150 150 finally:
151 151 repo.lfstatus = False
152 152 manifest = repo[None].manifest()
153 153 modified, added, deleted, clean = [[f for f in list
154 154 if lfutil.standin(f) in manifest]
155 155 for list in (s.modified, s.added,
156 156 s.deleted, s.clean)]
157 157
158 158 def warn(files, msg):
159 159 for f in files:
160 160 ui.warn(msg % m.rel(f))
161 161 return int(len(files) > 0)
162 162
163 163 result = 0
164 164
165 165 if after:
166 166 remove = deleted
167 167 result = warn(modified + added + clean,
168 168 _('not removing %s: file still exists\n'))
169 169 else:
170 170 remove = deleted + clean
171 171 result = warn(modified, _('not removing %s: file is modified (use -f'
172 172 ' to force removal)\n'))
173 173 result = warn(added, _('not removing %s: file has been marked for add'
174 174 ' (use forget to undo)\n')) or result
175 175
176 176 for f in sorted(remove):
177 177 if ui.verbose or not m.exact(f):
178 178 ui.status(_('removing %s\n') % m.rel(f))
179 179
180 180 # Need to lock because standin files are deleted then removed from the
181 181 # repository and we could race in-between.
182 182 wlock = repo.wlock()
183 183 try:
184 184 lfdirstate = lfutil.openlfdirstate(ui, repo)
185 185 for f in remove:
186 186 if not after:
187 187 # If this is being called by addremove, notify the user that we
188 188 # are removing the file.
189 189 if isaddremove:
190 190 ui.status(_('removing %s\n') % f)
191 191 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
192 192 lfdirstate.remove(f)
193 193 lfdirstate.write()
194 194 remove = [lfutil.standin(f) for f in remove]
195 195 # If this is being called by addremove, let the original addremove
196 196 # function handle this.
197 197 if not isaddremove:
198 198 for f in remove:
199 199 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
200 200 repo[None].forget(remove)
201 201 finally:
202 202 wlock.release()
203 203
204 204 return result
205 205
206 206 # For overriding mercurial.hgweb.webcommands so that largefiles will
207 207 # appear at their right place in the manifests.
208 208 def decodepath(orig, path):
209 209 return lfutil.splitstandin(path) or path
210 210
211 211 # -- Wrappers: modify existing commands --------------------------------
212 212
213 213 # Add works by going through the files that the user wanted to add and
214 214 # checking if they should be added as largefiles. Then it makes a new
215 215 # matcher which matches only the normal files and runs the original
216 216 # version of add.
217 217 def overrideadd(orig, ui, repo, *pats, **opts):
218 218 normal = opts.pop('normal')
219 219 if normal:
220 220 if opts.get('large'):
221 221 raise util.Abort(_('--normal cannot be used with --large'))
222 222 return orig(ui, repo, *pats, **opts)
223 223 bad = addlargefiles(ui, repo, *pats, **opts)
224 224 installnormalfilesmatchfn(repo[None].manifest())
225 225 result = orig(ui, repo, *pats, **opts)
226 226 restorematchfn()
227 227
228 228 return (result == 1 or bad) and 1 or 0
229 229
230 230 def overrideremove(orig, ui, repo, *pats, **opts):
231 231 installnormalfilesmatchfn(repo[None].manifest())
232 232 result = orig(ui, repo, *pats, **opts)
233 233 restorematchfn()
234 234 return removelargefiles(ui, repo, False, *pats, **opts) or result
235 235
236 236 def overridestatusfn(orig, repo, rev2, **opts):
237 237 try:
238 238 repo._repo.lfstatus = True
239 239 return orig(repo, rev2, **opts)
240 240 finally:
241 241 repo._repo.lfstatus = False
242 242
243 243 def overridestatus(orig, ui, repo, *pats, **opts):
244 244 try:
245 245 repo.lfstatus = True
246 246 return orig(ui, repo, *pats, **opts)
247 247 finally:
248 248 repo.lfstatus = False
249 249
250 250 def overridedirty(orig, repo, ignoreupdate=False):
251 251 try:
252 252 repo._repo.lfstatus = True
253 253 return orig(repo, ignoreupdate)
254 254 finally:
255 255 repo._repo.lfstatus = False
256 256
257 257 def overridelog(orig, ui, repo, *pats, **opts):
258 258 def overridematchandpats(ctx, pats=[], opts={}, globbed=False,
259 259 default='relpath'):
260 260 """Matcher that merges root directory with .hglf, suitable for log.
261 261 It is still possible to match .hglf directly.
262 262 For any listed files run log on the standin too.
263 263 matchfn tries both the given filename and with .hglf stripped.
264 264 """
265 265 matchandpats = oldmatchandpats(ctx, pats, opts, globbed, default)
266 266 m, p = copy.copy(matchandpats)
267 267
268 268 if m.always():
269 269 # We want to match everything anyway, so there's no benefit trying
270 270 # to add standins.
271 271 return matchandpats
272 272
273 273 pats = set(p)
274 274 # TODO: handling of patterns in both cases below
275 275 if m._cwd:
276 276 if os.path.isabs(m._cwd):
277 277 # TODO: handle largefile magic when invoked from other cwd
278 278 return matchandpats
279 279 back = (m._cwd.count('/') + 1) * '../'
280 280 pats.update(back + lfutil.standin(m._cwd + '/' + f) for f in p)
281 281 else:
282 282 pats.update(lfutil.standin(f) for f in p)
283 283
284 284 for i in range(0, len(m._files)):
285 285 standin = lfutil.standin(m._files[i])
286 286 if standin in repo[ctx.node()]:
287 287 m._files[i] = standin
288 288 elif m._files[i] not in repo[ctx.node()]:
289 289 m._files.append(standin)
290 290 pats.add(standin)
291 291
292 292 m._fmap = set(m._files)
293 293 m._always = False
294 294 origmatchfn = m.matchfn
295 295 def lfmatchfn(f):
296 296 lf = lfutil.splitstandin(f)
297 297 if lf is not None and origmatchfn(lf):
298 298 return True
299 299 r = origmatchfn(f)
300 300 return r
301 301 m.matchfn = lfmatchfn
302 302
303 303 return m, pats
304 304
305 305 # For hg log --patch, the match object is used in two different senses:
306 306 # (1) to determine what revisions should be printed out, and
307 307 # (2) to determine what files to print out diffs for.
308 308 # The magic matchandpats override should be used for case (1) but not for
309 309 # case (2).
310 310 def overridemakelogfilematcher(repo, pats, opts):
311 311 pctx = repo[None]
312 312 match, pats = oldmatchandpats(pctx, pats, opts)
313 313 return lambda rev: match
314 314
315 315 oldmatchandpats = installmatchandpatsfn(overridematchandpats)
316 316 oldmakelogfilematcher = cmdutil._makenofollowlogfilematcher
317 317 setattr(cmdutil, '_makenofollowlogfilematcher', overridemakelogfilematcher)
318 318
319 319 try:
320 320 return orig(ui, repo, *pats, **opts)
321 321 finally:
322 322 restorematchandpatsfn()
323 323 setattr(cmdutil, '_makenofollowlogfilematcher', oldmakelogfilematcher)
324 324
325 325 def overrideverify(orig, ui, repo, *pats, **opts):
326 326 large = opts.pop('large', False)
327 327 all = opts.pop('lfa', False)
328 328 contents = opts.pop('lfc', False)
329 329
330 330 result = orig(ui, repo, *pats, **opts)
331 331 if large or all or contents:
332 332 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
333 333 return result
334 334
335 335 def overridedebugstate(orig, ui, repo, *pats, **opts):
336 336 large = opts.pop('large', False)
337 337 if large:
338 338 class fakerepo(object):
339 339 dirstate = lfutil.openlfdirstate(ui, repo)
340 340 orig(ui, fakerepo, *pats, **opts)
341 341 else:
342 342 orig(ui, repo, *pats, **opts)
343 343
344 344 # Override needs to refresh standins so that update's normal merge
345 345 # will go through properly. Then the other update hook (overriding repo.update)
346 346 # will get the new files. Filemerge is also overridden so that the merge
347 347 # will merge standins correctly.
348 348 def overrideupdate(orig, ui, repo, *pats, **opts):
349 349 # Need to lock between the standins getting updated and their
350 350 # largefiles getting updated
351 351 wlock = repo.wlock()
352 352 try:
353 353 if opts['check']:
354 354 lfdirstate = lfutil.openlfdirstate(ui, repo)
355 355 unsure, s = lfdirstate.status(
356 356 match_.always(repo.root, repo.getcwd()),
357 357 [], False, False, False)
358 358
359 359 mod = len(s.modified) > 0
360 360 for lfile in unsure:
361 361 standin = lfutil.standin(lfile)
362 362 if repo['.'][standin].data().strip() != \
363 363 lfutil.hashfile(repo.wjoin(lfile)):
364 364 mod = True
365 365 else:
366 366 lfdirstate.normal(lfile)
367 367 lfdirstate.write()
368 368 if mod:
369 369 raise util.Abort(_('uncommitted changes'))
370 370 return orig(ui, repo, *pats, **opts)
371 371 finally:
372 372 wlock.release()
373 373
374 374 # Before starting the manifest merge, merge.updates will call
375 375 # _checkunknown to check if there are any files in the merged-in
376 376 # changeset that collide with unknown files in the working copy.
377 377 #
378 378 # The largefiles are seen as unknown, so this prevents us from merging
379 379 # in a file 'foo' if we already have a largefile with the same name.
380 380 #
381 381 # The overridden function filters the unknown files by removing any
382 382 # largefiles. This makes the merge proceed and we can then handle this
383 383 # case further in the overridden manifestmerge function below.
384 384 def overridecheckunknownfile(origfn, repo, wctx, mctx, f):
385 385 if lfutil.standin(repo.dirstate.normalize(f)) in wctx:
386 386 return False
387 387 return origfn(repo, wctx, mctx, f)
388 388
389 389 # The manifest merge handles conflicts on the manifest level. We want
390 390 # to handle changes in largefile-ness of files at this level too.
391 391 #
392 392 # The strategy is to run the original manifestmerge and then process
393 393 # the action list it outputs. There are two cases we need to deal with:
394 394 #
395 395 # 1. Normal file in p1, largefile in p2. Here the largefile is
396 396 # detected via its standin file, which will enter the working copy
397 397 # with a "get" action. It is not "merge" since the standin is all
398 398 # Mercurial is concerned with at this level -- the link to the
399 399 # existing normal file is not relevant here.
400 400 #
401 401 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
402 402 # since the largefile will be present in the working copy and
403 403 # different from the normal file in p2. Mercurial therefore
404 404 # triggers a merge action.
405 405 #
406 406 # In both cases, we prompt the user and emit new actions to either
407 407 # remove the standin (if the normal file was kept) or to remove the
408 408 # normal file and get the standin (if the largefile was kept). The
409 409 # default prompt answer is to use the largefile version since it was
410 410 # presumably changed on purpose.
411 411 #
412 412 # Finally, the merge.applyupdates function will then take care of
413 413 # writing the files into the working copy and lfcommands.updatelfiles
414 414 # will update the largefiles.
415 415 def overridecalculateupdates(origfn, repo, p1, p2, pas, branchmerge, force,
416 416 partial, acceptremote, followcopies):
417 417 overwrite = force and not branchmerge
418 418 actions = origfn(repo, p1, p2, pas, branchmerge, force, partial,
419 419 acceptremote, followcopies)
420 420
421 421 if overwrite:
422 422 return actions
423 423
424 424 removes = set(a[0] for a in actions['r'])
425 425
426 426 newglist = []
427 427 lfmr = [] # LargeFiles: Mark as Removed
428 428 for action in actions['g']:
429 429 f, args, msg = action
430 430 splitstandin = f and lfutil.splitstandin(f)
431 431 if (splitstandin is not None and
432 432 splitstandin in p1 and splitstandin not in removes):
433 433 # Case 1: normal file in the working copy, largefile in
434 434 # the second parent
435 435 lfile = splitstandin
436 436 standin = f
437 437 msg = _('remote turned local normal file %s into a largefile\n'
438 438 'use (l)argefile or keep (n)ormal file?'
439 439 '$$ &Largefile $$ &Normal file') % lfile
440 440 if repo.ui.promptchoice(msg, 0) == 0:
441 441 actions['r'].append((lfile, None, msg))
442 442 newglist.append((standin, (p2.flags(standin),), msg))
443 443 else:
444 444 actions['r'].append((standin, None, msg))
445 445 elif lfutil.standin(f) in p1 and lfutil.standin(f) not in removes:
446 446 # Case 2: largefile in the working copy, normal file in
447 447 # the second parent
448 448 standin = lfutil.standin(f)
449 449 lfile = f
450 450 msg = _('remote turned local largefile %s into a normal file\n'
451 451 'keep (l)argefile or use (n)ormal file?'
452 452 '$$ &Largefile $$ &Normal file') % lfile
453 453 if repo.ui.promptchoice(msg, 0) == 0:
454 454 if branchmerge:
455 455 # largefile can be restored from standin safely
456 456 actions['r'].append((lfile, None, msg))
457 457 else:
458 458 # "lfile" should be marked as "removed" without
459 459 # removal of itself
460 460 lfmr.append((lfile, None, msg))
461 461
462 462 # linear-merge should treat this largefile as 're-added'
463 463 actions['a'].append((standin, None, msg))
464 464 else:
465 465 actions['r'].append((standin, None, msg))
466 466 newglist.append((lfile, (p2.flags(lfile),), msg))
467 467 else:
468 468 newglist.append(action)
469 469
470 470 newglist.sort()
471 471 actions['g'] = newglist
472 472 if lfmr:
473 473 lfmr.sort()
474 474 actions['lfmr'] = lfmr
475 475
476 476 return actions
477 477
478 478 def mergerecordupdates(orig, repo, actions, branchmerge):
479 479 if 'lfmr' in actions:
480 480 # this should be executed before 'orig', to execute 'remove'
481 481 # before all other actions
482 482 for lfile, args, msg in actions['lfmr']:
483 483 repo.dirstate.remove(lfile)
484 484
485 485 return orig(repo, actions, branchmerge)
486 486
487 487
488 488 # Override filemerge to prompt the user about how they wish to merge
489 489 # largefiles. This will handle identical edits without prompting the user.
490 490 def overridefilemerge(origfn, repo, mynode, orig, fcd, fco, fca, labels=None):
491 491 if not lfutil.isstandin(orig):
492 492 return origfn(repo, mynode, orig, fcd, fco, fca, labels=labels)
493 493
494 494 ahash = fca.data().strip().lower()
495 495 dhash = fcd.data().strip().lower()
496 496 ohash = fco.data().strip().lower()
497 497 if (ohash != ahash and
498 498 ohash != dhash and
499 499 (dhash == ahash or
500 500 repo.ui.promptchoice(
501 501 _('largefile %s has a merge conflict\nancestor was %s\n'
502 502 'keep (l)ocal %s or\ntake (o)ther %s?'
503 503 '$$ &Local $$ &Other') %
504 504 (lfutil.splitstandin(orig), ahash, dhash, ohash),
505 505 0) == 1)):
506 506 repo.wwrite(fcd.path(), fco.data(), fco.flags())
507 507 return 0
508 508
509 509 # Copy first changes the matchers to match standins instead of
510 510 # largefiles. Then it overrides util.copyfile in that function it
511 511 # checks if the destination largefile already exists. It also keeps a
512 512 # list of copied files so that the largefiles can be copied and the
513 513 # dirstate updated.
514 514 def overridecopy(orig, ui, repo, pats, opts, rename=False):
515 515 # doesn't remove largefile on rename
516 516 if len(pats) < 2:
517 517 # this isn't legal, let the original function deal with it
518 518 return orig(ui, repo, pats, opts, rename)
519 519
520 520 def makestandin(relpath):
521 521 path = pathutil.canonpath(repo.root, repo.getcwd(), relpath)
522 522 return os.path.join(repo.wjoin(lfutil.standin(path)))
523 523
524 524 fullpats = scmutil.expandpats(pats)
525 525 dest = fullpats[-1]
526 526
527 527 if os.path.isdir(dest):
528 528 if not os.path.isdir(makestandin(dest)):
529 529 os.makedirs(makestandin(dest))
530 530 # This could copy both lfiles and normal files in one command,
531 531 # but we don't want to do that. First replace their matcher to
532 532 # only match normal files and run it, then replace it to just
533 533 # match largefiles and run it again.
534 534 nonormalfiles = False
535 535 nolfiles = False
536 536 installnormalfilesmatchfn(repo[None].manifest())
537 537 try:
538 538 try:
539 539 result = orig(ui, repo, pats, opts, rename)
540 540 except util.Abort, e:
541 541 if str(e) != _('no files to copy'):
542 542 raise e
543 543 else:
544 544 nonormalfiles = True
545 545 result = 0
546 546 finally:
547 547 restorematchfn()
548 548
549 549 # The first rename can cause our current working directory to be removed.
550 550 # In that case there is nothing left to copy/rename so just quit.
551 551 try:
552 552 repo.getcwd()
553 553 except OSError:
554 554 return result
555 555
556 556 try:
557 557 try:
558 558 # When we call orig below it creates the standins but we don't add
559 559 # them to the dir state until later so lock during that time.
560 560 wlock = repo.wlock()
561 561
562 562 manifest = repo[None].manifest()
563 563 def overridematch(ctx, pats=[], opts={}, globbed=False,
564 564 default='relpath'):
565 565 newpats = []
566 566 # The patterns were previously mangled to add the standin
567 567 # directory; we need to remove that now
568 568 for pat in pats:
569 569 if match_.patkind(pat) is None and lfutil.shortname in pat:
570 570 newpats.append(pat.replace(lfutil.shortname, ''))
571 571 else:
572 572 newpats.append(pat)
573 573 match = oldmatch(ctx, newpats, opts, globbed, default)
574 574 m = copy.copy(match)
575 575 lfile = lambda f: lfutil.standin(f) in manifest
576 576 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
577 577 m._fmap = set(m._files)
578 578 origmatchfn = m.matchfn
579 579 m.matchfn = lambda f: (lfutil.isstandin(f) and
580 580 (f in manifest) and
581 581 origmatchfn(lfutil.splitstandin(f)) or
582 582 None)
583 583 return m
584 584 oldmatch = installmatchfn(overridematch)
585 585 listpats = []
586 586 for pat in pats:
587 587 if match_.patkind(pat) is not None:
588 588 listpats.append(pat)
589 589 else:
590 590 listpats.append(makestandin(pat))
591 591
592 592 try:
593 593 origcopyfile = util.copyfile
594 594 copiedfiles = []
595 595 def overridecopyfile(src, dest):
596 596 if (lfutil.shortname in src and
597 597 dest.startswith(repo.wjoin(lfutil.shortname))):
598 598 destlfile = dest.replace(lfutil.shortname, '')
599 599 if not opts['force'] and os.path.exists(destlfile):
600 600 raise IOError('',
601 601 _('destination largefile already exists'))
602 602 copiedfiles.append((src, dest))
603 603 origcopyfile(src, dest)
604 604
605 605 util.copyfile = overridecopyfile
606 606 result += orig(ui, repo, listpats, opts, rename)
607 607 finally:
608 608 util.copyfile = origcopyfile
609 609
610 610 lfdirstate = lfutil.openlfdirstate(ui, repo)
611 611 for (src, dest) in copiedfiles:
612 612 if (lfutil.shortname in src and
613 613 dest.startswith(repo.wjoin(lfutil.shortname))):
614 614 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
615 615 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
616 616 destlfiledir = os.path.dirname(repo.wjoin(destlfile)) or '.'
617 617 if not os.path.isdir(destlfiledir):
618 618 os.makedirs(destlfiledir)
619 619 if rename:
620 620 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
621 621
622 622 # The file is gone, but this deletes any empty parent
623 623 # directories as a side-effect.
624 624 util.unlinkpath(repo.wjoin(srclfile), True)
625 625 lfdirstate.remove(srclfile)
626 626 else:
627 627 util.copyfile(repo.wjoin(srclfile),
628 628 repo.wjoin(destlfile))
629 629
630 630 lfdirstate.add(destlfile)
631 631 lfdirstate.write()
632 632 except util.Abort, e:
633 633 if str(e) != _('no files to copy'):
634 634 raise e
635 635 else:
636 636 nolfiles = True
637 637 finally:
638 638 restorematchfn()
639 639 wlock.release()
640 640
641 641 if nolfiles and nonormalfiles:
642 642 raise util.Abort(_('no files to copy'))
643 643
644 644 return result
645 645
646 646 # When the user calls revert, we have to be careful to not revert any
647 647 # changes to other largefiles accidentally. This means we have to keep
648 648 # track of the largefiles that are being reverted so we only pull down
649 649 # the necessary largefiles.
650 650 #
651 651 # Standins are only updated (to match the hash of largefiles) before
652 652 # commits. Update the standins then run the original revert, changing
653 653 # the matcher to hit standins instead of largefiles. Based on the
654 654 # resulting standins update the largefiles.
655 655 def overriderevert(orig, ui, repo, *pats, **opts):
656 656 # Because we put the standins in a bad state (by updating them)
657 657 # and then return them to a correct state we need to lock to
658 658 # prevent others from changing them in their incorrect state.
659 659 wlock = repo.wlock()
660 660 try:
661 661 lfdirstate = lfutil.openlfdirstate(ui, repo)
662 662 s = lfutil.lfdirstatestatus(lfdirstate, repo)
663 663 lfdirstate.write()
664 664 for lfile in s.modified:
665 665 lfutil.updatestandin(repo, lfutil.standin(lfile))
666 666 for lfile in s.deleted:
667 667 if (os.path.exists(repo.wjoin(lfutil.standin(lfile)))):
668 668 os.unlink(repo.wjoin(lfutil.standin(lfile)))
669 669
670 670 oldstandins = lfutil.getstandinsstate(repo)
671 671
672 672 def overridematch(ctx, pats=[], opts={}, globbed=False,
673 673 default='relpath'):
674 674 match = oldmatch(ctx, pats, opts, globbed, default)
675 675 m = copy.copy(match)
676 676 def tostandin(f):
677 677 if lfutil.standin(f) in ctx:
678 678 return lfutil.standin(f)
679 679 elif lfutil.standin(f) in repo[None]:
680 680 return None
681 681 return f
682 682 m._files = [tostandin(f) for f in m._files]
683 683 m._files = [f for f in m._files if f is not None]
684 684 m._fmap = set(m._files)
685 685 origmatchfn = m.matchfn
686 686 def matchfn(f):
687 687 if lfutil.isstandin(f):
688 688 return (origmatchfn(lfutil.splitstandin(f)) and
689 689 (f in repo[None] or f in ctx))
690 690 return origmatchfn(f)
691 691 m.matchfn = matchfn
692 692 return m
693 693 oldmatch = installmatchfn(overridematch)
694 694 try:
695 695 orig(ui, repo, *pats, **opts)
696 696 finally:
697 697 restorematchfn()
698 698
699 699 newstandins = lfutil.getstandinsstate(repo)
700 700 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
701 701 # lfdirstate should be 'normallookup'-ed for updated files,
702 702 # because reverting doesn't touch dirstate for 'normal' files
703 703 # when target revision is explicitly specified: in such case,
704 704 # 'n' and valid timestamp in dirstate doesn't ensure 'clean'
705 705 # of target (standin) file.
706 706 lfcommands.updatelfiles(ui, repo, filelist, printmessage=False,
707 707 normallookup=True)
708 708
709 709 finally:
710 710 wlock.release()
711 711
712 712 # after pulling changesets, we need to take some extra care to get
713 713 # largefiles updated remotely
714 714 def overridepull(orig, ui, repo, source=None, **opts):
715 715 revsprepull = len(repo)
716 716 if not source:
717 717 source = 'default'
718 718 repo.lfpullsource = source
719 719 result = orig(ui, repo, source, **opts)
720 720 revspostpull = len(repo)
721 721 lfrevs = opts.get('lfrev', [])
722 722 if opts.get('all_largefiles'):
723 723 lfrevs.append('pulled()')
724 724 if lfrevs and revspostpull > revsprepull:
725 725 numcached = 0
726 726 repo.firstpulled = revsprepull # for pulled() revset expression
727 727 try:
728 728 for rev in scmutil.revrange(repo, lfrevs):
729 729 ui.note(_('pulling largefiles for revision %s\n') % rev)
730 730 (cached, missing) = lfcommands.cachelfiles(ui, repo, rev)
731 731 numcached += len(cached)
732 732 finally:
733 733 del repo.firstpulled
734 734 ui.status(_("%d largefiles cached\n") % numcached)
735 735 return result
736 736
737 737 def pulledrevsetsymbol(repo, subset, x):
738 738 """``pulled()``
739 739 Changesets that just has been pulled.
740 740
741 741 Only available with largefiles from pull --lfrev expressions.
742 742
743 743 .. container:: verbose
744 744
745 745 Some examples:
746 746
747 747 - pull largefiles for all new changesets::
748 748
749 749 hg pull -lfrev "pulled()"
750 750
751 751 - pull largefiles for all new branch heads::
752 752
753 753 hg pull -lfrev "head(pulled()) and not closed()"
754 754
755 755 """
756 756
757 757 try:
758 758 firstpulled = repo.firstpulled
759 759 except AttributeError:
760 760 raise util.Abort(_("pulled() only available in --lfrev"))
761 761 return revset.baseset([r for r in subset if r >= firstpulled])
762 762
763 763 def overrideclone(orig, ui, source, dest=None, **opts):
764 764 d = dest
765 765 if d is None:
766 766 d = hg.defaultdest(source)
767 767 if opts.get('all_largefiles') and not hg.islocal(d):
768 768 raise util.Abort(_(
769 769 '--all-largefiles is incompatible with non-local destination %s') %
770 770 d)
771 771
772 772 return orig(ui, source, dest, **opts)
773 773
774 774 def hgclone(orig, ui, opts, *args, **kwargs):
775 775 result = orig(ui, opts, *args, **kwargs)
776 776
777 777 if result is not None:
778 778 sourcerepo, destrepo = result
779 779 repo = destrepo.local()
780 780
781 781 # Caching is implicitly limited to 'rev' option, since the dest repo was
782 782 # truncated at that point. The user may expect a download count with
783 783 # this option, so attempt whether or not this is a largefile repo.
784 784 if opts.get('all_largefiles'):
785 785 success, missing = lfcommands.downloadlfiles(ui, repo, None)
786 786
787 787 if missing != 0:
788 788 return None
789 789
790 790 return result
791 791
792 792 def overriderebase(orig, ui, repo, **opts):
793 793 resuming = opts.get('continue')
794 794 repo._lfcommithooks.append(lfutil.automatedcommithook(resuming))
795 795 repo._lfstatuswriters.append(lambda *msg, **opts: None)
796 796 try:
797 797 return orig(ui, repo, **opts)
798 798 finally:
799 799 repo._lfstatuswriters.pop()
800 800 repo._lfcommithooks.pop()
801 801
802 802 def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None,
803 803 prefix=None, mtime=None, subrepos=None):
804 804 # No need to lock because we are only reading history and
805 805 # largefile caches, neither of which are modified.
806 806 lfcommands.cachelfiles(repo.ui, repo, node)
807 807
808 808 if kind not in archival.archivers:
809 809 raise util.Abort(_("unknown archive type '%s'") % kind)
810 810
811 811 ctx = repo[node]
812 812
813 813 if kind == 'files':
814 814 if prefix:
815 815 raise util.Abort(
816 816 _('cannot give prefix when archiving to files'))
817 817 else:
818 818 prefix = archival.tidyprefix(dest, kind, prefix)
819 819
820 820 def write(name, mode, islink, getdata):
821 821 if matchfn and not matchfn(name):
822 822 return
823 823 data = getdata()
824 824 if decode:
825 825 data = repo.wwritedata(name, data)
826 826 archiver.addfile(prefix + name, mode, islink, data)
827 827
828 828 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
829 829
830 830 if repo.ui.configbool("ui", "archivemeta", True):
831 831 def metadata():
832 832 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
833 833 hex(repo.changelog.node(0)), hex(node), ctx.branch())
834 834
835 835 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
836 836 if repo.tagtype(t) == 'global')
837 837 if not tags:
838 838 repo.ui.pushbuffer()
839 839 opts = {'template': '{latesttag}\n{latesttagdistance}',
840 840 'style': '', 'patch': None, 'git': None}
841 841 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
842 842 ltags, dist = repo.ui.popbuffer().split('\n')
843 843 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
844 844 tags += 'latesttagdistance: %s\n' % dist
845 845
846 846 return base + tags
847 847
848 848 write('.hg_archival.txt', 0644, False, metadata)
849 849
850 850 for f in ctx:
851 851 ff = ctx.flags(f)
852 852 getdata = ctx[f].data
853 853 if lfutil.isstandin(f):
854 854 path = lfutil.findfile(repo, getdata().strip())
855 855 if path is None:
856 856 raise util.Abort(
857 857 _('largefile %s not found in repo store or system cache')
858 858 % lfutil.splitstandin(f))
859 859 f = lfutil.splitstandin(f)
860 860
861 861 def getdatafn():
862 862 fd = None
863 863 try:
864 864 fd = open(path, 'rb')
865 865 return fd.read()
866 866 finally:
867 867 if fd:
868 868 fd.close()
869 869
870 870 getdata = getdatafn
871 871 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
872 872
873 873 if subrepos:
874 874 for subpath in sorted(ctx.substate):
875 875 sub = ctx.sub(subpath)
876 876 submatch = match_.narrowmatcher(subpath, matchfn)
877 877 sub.archive(repo.ui, archiver, prefix, submatch)
878 878
879 879 archiver.done()
880 880
881 881 def hgsubrepoarchive(orig, repo, ui, archiver, prefix, match=None):
882 882 repo._get(repo._state + ('hg',))
883 883 rev = repo._state[1]
884 884 ctx = repo._repo[rev]
885 885
886 886 lfcommands.cachelfiles(ui, repo._repo, ctx.node())
887 887
888 888 def write(name, mode, islink, getdata):
889 889 # At this point, the standin has been replaced with the largefile name,
890 890 # so the normal matcher works here without the lfutil variants.
891 891 if match and not match(f):
892 892 return
893 893 data = getdata()
894 894
895 895 archiver.addfile(prefix + repo._path + '/' + name, mode, islink, data)
896 896
897 897 for f in ctx:
898 898 ff = ctx.flags(f)
899 899 getdata = ctx[f].data
900 900 if lfutil.isstandin(f):
901 901 path = lfutil.findfile(repo._repo, getdata().strip())
902 902 if path is None:
903 903 raise util.Abort(
904 904 _('largefile %s not found in repo store or system cache')
905 905 % lfutil.splitstandin(f))
906 906 f = lfutil.splitstandin(f)
907 907
908 908 def getdatafn():
909 909 fd = None
910 910 try:
911 911 fd = open(os.path.join(prefix, path), 'rb')
912 912 return fd.read()
913 913 finally:
914 914 if fd:
915 915 fd.close()
916 916
917 917 getdata = getdatafn
918 918
919 919 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
920 920
921 921 for subpath in sorted(ctx.substate):
922 922 sub = ctx.sub(subpath)
923 923 submatch = match_.narrowmatcher(subpath, match)
924 924 sub.archive(ui, archiver, os.path.join(prefix, repo._path) + '/',
925 925 submatch)
926 926
927 927 # If a largefile is modified, the change is not reflected in its
928 928 # standin until a commit. cmdutil.bailifchanged() raises an exception
929 929 # if the repo has uncommitted changes. Wrap it to also check if
930 930 # largefiles were changed. This is used by bisect and backout.
931 931 def overridebailifchanged(orig, repo):
932 932 orig(repo)
933 933 repo.lfstatus = True
934 934 s = repo.status()
935 935 repo.lfstatus = False
936 936 if s.modified or s.added or s.removed or s.deleted:
937 937 raise util.Abort(_('uncommitted changes'))
938 938
939 939 # Fetch doesn't use cmdutil.bailifchanged so override it to add the check
940 940 def overridefetch(orig, ui, repo, *pats, **opts):
941 941 repo.lfstatus = True
942 942 s = repo.status()
943 943 repo.lfstatus = False
944 944 if s.modified or s.added or s.removed or s.deleted:
945 945 raise util.Abort(_('uncommitted changes'))
946 946 return orig(ui, repo, *pats, **opts)
947 947
948 948 def overrideforget(orig, ui, repo, *pats, **opts):
949 949 installnormalfilesmatchfn(repo[None].manifest())
950 950 result = orig(ui, repo, *pats, **opts)
951 951 restorematchfn()
952 952 m = scmutil.match(repo[None], pats, opts)
953 953
954 954 try:
955 955 repo.lfstatus = True
956 956 s = repo.status(match=m, clean=True)
957 957 finally:
958 958 repo.lfstatus = False
959 959 forget = sorted(s.modified + s.added + s.deleted + s.clean)
960 960 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
961 961
962 962 for f in forget:
963 963 if lfutil.standin(f) not in repo.dirstate and not \
964 964 os.path.isdir(m.rel(lfutil.standin(f))):
965 965 ui.warn(_('not removing %s: file is already untracked\n')
966 966 % m.rel(f))
967 967 result = 1
968 968
969 969 for f in forget:
970 970 if ui.verbose or not m.exact(f):
971 971 ui.status(_('removing %s\n') % m.rel(f))
972 972
973 973 # Need to lock because standin files are deleted then removed from the
974 974 # repository and we could race in-between.
975 975 wlock = repo.wlock()
976 976 try:
977 977 lfdirstate = lfutil.openlfdirstate(ui, repo)
978 978 for f in forget:
979 979 if lfdirstate[f] == 'a':
980 980 lfdirstate.drop(f)
981 981 else:
982 982 lfdirstate.remove(f)
983 983 lfdirstate.write()
984 984 standins = [lfutil.standin(f) for f in forget]
985 985 for f in standins:
986 986 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
987 987 repo[None].forget(standins)
988 988 finally:
989 989 wlock.release()
990 990
991 991 return result
992 992
993 993 def _getoutgoings(repo, other, missing, addfunc):
994 994 """get pairs of filename and largefile hash in outgoing revisions
995 995 in 'missing'.
996 996
997 997 largefiles already existing on 'other' repository are ignored.
998 998
999 999 'addfunc' is invoked with each unique pairs of filename and
1000 1000 largefile hash value.
1001 1001 """
1002 1002 knowns = set()
1003 1003 lfhashes = set()
1004 1004 def dedup(fn, lfhash):
1005 1005 k = (fn, lfhash)
1006 1006 if k not in knowns:
1007 1007 knowns.add(k)
1008 1008 lfhashes.add(lfhash)
1009 1009 lfutil.getlfilestoupload(repo, missing, dedup)
1010 1010 if lfhashes:
1011 1011 lfexists = basestore._openstore(repo, other).exists(lfhashes)
1012 1012 for fn, lfhash in knowns:
1013 1013 if not lfexists[lfhash]: # lfhash doesn't exist on "other"
1014 1014 addfunc(fn, lfhash)
1015 1015
1016 1016 def outgoinghook(ui, repo, other, opts, missing):
1017 1017 if opts.pop('large', None):
1018 1018 lfhashes = set()
1019 1019 if ui.debugflag:
1020 1020 toupload = {}
1021 1021 def addfunc(fn, lfhash):
1022 1022 if fn not in toupload:
1023 1023 toupload[fn] = []
1024 1024 toupload[fn].append(lfhash)
1025 1025 lfhashes.add(lfhash)
1026 1026 def showhashes(fn):
1027 1027 for lfhash in sorted(toupload[fn]):
1028 1028 ui.debug(' %s\n' % (lfhash))
1029 1029 else:
1030 1030 toupload = set()
1031 1031 def addfunc(fn, lfhash):
1032 1032 toupload.add(fn)
1033 1033 lfhashes.add(lfhash)
1034 1034 def showhashes(fn):
1035 1035 pass
1036 1036 _getoutgoings(repo, other, missing, addfunc)
1037 1037
1038 1038 if not toupload:
1039 1039 ui.status(_('largefiles: no files to upload\n'))
1040 1040 else:
1041 1041 ui.status(_('largefiles to upload (%d entities):\n')
1042 1042 % (len(lfhashes)))
1043 1043 for file in sorted(toupload):
1044 1044 ui.status(lfutil.splitstandin(file) + '\n')
1045 1045 showhashes(file)
1046 1046 ui.status('\n')
1047 1047
1048 1048 def summaryremotehook(ui, repo, opts, changes):
1049 1049 largeopt = opts.get('large', False)
1050 1050 if changes is None:
1051 1051 if largeopt:
1052 1052 return (False, True) # only outgoing check is needed
1053 1053 else:
1054 1054 return (False, False)
1055 1055 elif largeopt:
1056 1056 url, branch, peer, outgoing = changes[1]
1057 1057 if peer is None:
1058 1058 # i18n: column positioning for "hg summary"
1059 1059 ui.status(_('largefiles: (no remote repo)\n'))
1060 1060 return
1061 1061
1062 1062 toupload = set()
1063 1063 lfhashes = set()
1064 1064 def addfunc(fn, lfhash):
1065 1065 toupload.add(fn)
1066 1066 lfhashes.add(lfhash)
1067 1067 _getoutgoings(repo, peer, outgoing.missing, addfunc)
1068 1068
1069 1069 if not toupload:
1070 1070 # i18n: column positioning for "hg summary"
1071 1071 ui.status(_('largefiles: (no files to upload)\n'))
1072 1072 else:
1073 1073 # i18n: column positioning for "hg summary"
1074 1074 ui.status(_('largefiles: %d entities for %d files to upload\n')
1075 1075 % (len(lfhashes), len(toupload)))
1076 1076
1077 1077 def overridesummary(orig, ui, repo, *pats, **opts):
1078 1078 try:
1079 1079 repo.lfstatus = True
1080 1080 orig(ui, repo, *pats, **opts)
1081 1081 finally:
1082 1082 repo.lfstatus = False
1083 1083
1084 1084 def scmutiladdremove(orig, repo, pats=[], opts={}, dry_run=None,
1085 1085 similarity=None):
1086 1086 if not lfutil.islfilesrepo(repo):
1087 1087 return orig(repo, pats, opts, dry_run, similarity)
1088 1088 # Get the list of missing largefiles so we can remove them
1089 1089 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1090 1090 unsure, s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [],
1091 1091 False, False, False)
1092 1092
1093 1093 # Call into the normal remove code, but the removing of the standin, we want
1094 1094 # to have handled by original addremove. Monkey patching here makes sure
1095 1095 # we don't remove the standin in the largefiles code, preventing a very
1096 1096 # confused state later.
1097 1097 if s.deleted:
1098 1098 m = [repo.wjoin(f) for f in s.deleted]
1099 1099 removelargefiles(repo.ui, repo, True, *m, **opts)
1100 1100 # Call into the normal add code, and any files that *should* be added as
1101 1101 # largefiles will be
1102 1102 addlargefiles(repo.ui, repo, *pats, **opts)
1103 1103 # Now that we've handled largefiles, hand off to the original addremove
1104 1104 # function to take care of the rest. Make sure it doesn't do anything with
1105 1105 # largefiles by installing a matcher that will ignore them.
1106 1106 installnormalfilesmatchfn(repo[None].manifest())
1107 1107 result = orig(repo, pats, opts, dry_run, similarity)
1108 1108 restorematchfn()
1109 1109 return result
1110 1110
1111 1111 # Calling purge with --all will cause the largefiles to be deleted.
1112 1112 # Override repo.status to prevent this from happening.
1113 1113 def overridepurge(orig, ui, repo, *dirs, **opts):
1114 1114 # XXX large file status is buggy when used on repo proxy.
1115 1115 # XXX this needs to be investigate.
1116 1116 repo = repo.unfiltered()
1117 1117 oldstatus = repo.status
1118 1118 def overridestatus(node1='.', node2=None, match=None, ignored=False,
1119 1119 clean=False, unknown=False, listsubrepos=False):
1120 1120 r = oldstatus(node1, node2, match, ignored, clean, unknown,
1121 1121 listsubrepos)
1122 1122 lfdirstate = lfutil.openlfdirstate(ui, repo)
1123 1123 unknown = [f for f in r.unknown if lfdirstate[f] == '?']
1124 1124 ignored = [f for f in r.ignored if lfdirstate[f] == '?']
1125 1125 return scmutil.status(r.modified, r.added, r.removed, r.deleted,
1126 1126 unknown, ignored, r.clean)
1127 1127 repo.status = overridestatus
1128 1128 orig(ui, repo, *dirs, **opts)
1129 1129 repo.status = oldstatus
1130 1130 def overriderollback(orig, ui, repo, **opts):
1131 1131 wlock = repo.wlock()
1132 1132 try:
1133 1133 before = repo.dirstate.parents()
1134 1134 orphans = set(f for f in repo.dirstate
1135 1135 if lfutil.isstandin(f) and repo.dirstate[f] != 'r')
1136 1136 result = orig(ui, repo, **opts)
1137 1137 after = repo.dirstate.parents()
1138 1138 if before == after:
1139 1139 return result # no need to restore standins
1140 1140
1141 1141 pctx = repo['.']
1142 1142 for f in repo.dirstate:
1143 1143 if lfutil.isstandin(f):
1144 1144 orphans.discard(f)
1145 1145 if repo.dirstate[f] == 'r':
1146 1146 repo.wvfs.unlinkpath(f, ignoremissing=True)
1147 1147 elif f in pctx:
1148 1148 fctx = pctx[f]
1149 1149 repo.wwrite(f, fctx.data(), fctx.flags())
1150 1150 else:
1151 1151 # content of standin is not so important in 'a',
1152 1152 # 'm' or 'n' (coming from the 2nd parent) cases
1153 1153 lfutil.writestandin(repo, f, '', False)
1154 1154 for standin in orphans:
1155 1155 repo.wvfs.unlinkpath(standin, ignoremissing=True)
1156 1156
1157 1157 lfdirstate = lfutil.openlfdirstate(ui, repo)
1158 1158 orphans = set(lfdirstate)
1159 1159 lfiles = lfutil.listlfiles(repo)
1160 1160 for file in lfiles:
1161 1161 lfutil.synclfdirstate(repo, lfdirstate, file, True)
1162 1162 orphans.discard(file)
1163 1163 for lfile in orphans:
1164 1164 lfdirstate.drop(lfile)
1165 1165 lfdirstate.write()
1166 1166 finally:
1167 1167 wlock.release()
1168 1168 return result
1169 1169
1170 1170 def overridetransplant(orig, ui, repo, *revs, **opts):
1171 1171 resuming = opts.get('continue')
1172 1172 repo._lfcommithooks.append(lfutil.automatedcommithook(resuming))
1173 repo._lfstatuswriters.append(lambda *msg, **opts: None)
1173 1174 try:
1174 repo._istransplanting = True
1175 1175 result = orig(ui, repo, *revs, **opts)
1176 1176 finally:
1177 repo._istransplanting = False
1177 repo._lfstatuswriters.pop()
1178 1178 repo._lfcommithooks.pop()
1179 1179 return result
1180 1180
1181 1181 def overridecat(orig, ui, repo, file1, *pats, **opts):
1182 1182 ctx = scmutil.revsingle(repo, opts.get('rev'))
1183 1183 err = 1
1184 1184 notbad = set()
1185 1185 m = scmutil.match(ctx, (file1,) + pats, opts)
1186 1186 origmatchfn = m.matchfn
1187 1187 def lfmatchfn(f):
1188 1188 if origmatchfn(f):
1189 1189 return True
1190 1190 lf = lfutil.splitstandin(f)
1191 1191 if lf is None:
1192 1192 return False
1193 1193 notbad.add(lf)
1194 1194 return origmatchfn(lf)
1195 1195 m.matchfn = lfmatchfn
1196 1196 origbadfn = m.bad
1197 1197 def lfbadfn(f, msg):
1198 1198 if not f in notbad:
1199 1199 origbadfn(f, msg)
1200 1200 m.bad = lfbadfn
1201 1201 for f in ctx.walk(m):
1202 1202 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1203 1203 pathname=f)
1204 1204 lf = lfutil.splitstandin(f)
1205 1205 if lf is None or origmatchfn(f):
1206 1206 # duplicating unreachable code from commands.cat
1207 1207 data = ctx[f].data()
1208 1208 if opts.get('decode'):
1209 1209 data = repo.wwritedata(f, data)
1210 1210 fp.write(data)
1211 1211 else:
1212 1212 hash = lfutil.readstandin(repo, lf, ctx.rev())
1213 1213 if not lfutil.inusercache(repo.ui, hash):
1214 1214 store = basestore._openstore(repo)
1215 1215 success, missing = store.get([(lf, hash)])
1216 1216 if len(success) != 1:
1217 1217 raise util.Abort(
1218 1218 _('largefile %s is not in cache and could not be '
1219 1219 'downloaded') % lf)
1220 1220 path = lfutil.usercachepath(repo.ui, hash)
1221 1221 fpin = open(path, "rb")
1222 1222 for chunk in util.filechunkiter(fpin, 128 * 1024):
1223 1223 fp.write(chunk)
1224 1224 fpin.close()
1225 1225 fp.close()
1226 1226 err = 0
1227 1227 return err
1228 1228
1229 1229 def mercurialsinkbefore(orig, sink):
1230 1230 sink.repo._isconverting = True
1231 1231 orig(sink)
1232 1232
1233 1233 def mercurialsinkafter(orig, sink):
1234 1234 sink.repo._isconverting = False
1235 1235 orig(sink)
1236 1236
1237 1237 def mergeupdate(orig, repo, node, branchmerge, force, partial,
1238 1238 *args, **kwargs):
1239 1239 wlock = repo.wlock()
1240 1240 try:
1241 1241 # branch | | |
1242 1242 # merge | force | partial | action
1243 1243 # -------+-------+---------+--------------
1244 1244 # x | x | x | linear-merge
1245 1245 # o | x | x | branch-merge
1246 1246 # x | o | x | overwrite (as clean update)
1247 1247 # o | o | x | force-branch-merge (*1)
1248 1248 # x | x | o | (*)
1249 1249 # o | x | o | (*)
1250 1250 # x | o | o | overwrite (as revert)
1251 1251 # o | o | o | (*)
1252 1252 #
1253 1253 # (*) don't care
1254 1254 # (*1) deprecated, but used internally (e.g: "rebase --collapse")
1255 1255
1256 1256 linearmerge = not branchmerge and not force and not partial
1257 1257
1258 1258 if linearmerge or (branchmerge and force and not partial):
1259 1259 # update standins for linear-merge or force-branch-merge,
1260 1260 # because largefiles in the working directory may be modified
1261 1261 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1262 1262 unsure, s = lfdirstate.status(match_.always(repo.root,
1263 1263 repo.getcwd()),
1264 1264 [], False, False, False)
1265 1265 for lfile in unsure + s.modified + s.added:
1266 1266 lfutil.updatestandin(repo, lfutil.standin(lfile))
1267 1267
1268 1268 if linearmerge:
1269 1269 # Only call updatelfiles on the standins that have changed
1270 1270 # to save time
1271 1271 oldstandins = lfutil.getstandinsstate(repo)
1272 1272
1273 1273 result = orig(repo, node, branchmerge, force, partial, *args, **kwargs)
1274 1274
1275 1275 filelist = None
1276 1276 if linearmerge:
1277 1277 newstandins = lfutil.getstandinsstate(repo)
1278 1278 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
1279 1279
1280 printmessage = None
1281 if getattr(repo, "_istransplanting", False):
1282 # suppress status message while automated committing
1283 printmessage = False
1284 1280 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1285 printmessage=printmessage,
1286 1281 normallookup=partial)
1287 1282
1288 1283 return result
1289 1284 finally:
1290 1285 wlock.release()
1291 1286
1292 1287 def scmutilmarktouched(orig, repo, files, *args, **kwargs):
1293 1288 result = orig(repo, files, *args, **kwargs)
1294 1289
1295 1290 filelist = [lfutil.splitstandin(f) for f in files if lfutil.isstandin(f)]
1296 1291 if filelist:
1297 1292 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1298 1293 printmessage=False, normallookup=True)
1299 1294
1300 1295 return result
General Comments 0
You need to be logged in to leave comments. Login now