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