##// END OF EJS Templates
largefiles: fix addremove when no largefiles are specified
Na'Tosha Bard -
r15967:295f8aea stable
parent child Browse files
Show More
@@ -1,956 +1,957
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
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 override_match(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 orig_matchfn = m.matchfn
38 38 m.matchfn = lambda f: notlfile(f) and orig_matchfn(f) or None
39 39 return m
40 40 oldmatch = installmatchfn(override_match)
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 add_largefiles(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:
85 85 abovemin = (lfsize and
86 86 os.lstat(repo.wjoin(f)).st_size >= lfsize * 1024 * 1024)
87 87 if large or abovemin or (lfmatcher and lfmatcher(f)):
88 88 lfnames.append(f)
89 89 if ui.verbose or not exact:
90 90 ui.status(_('adding %s as a largefile\n') % m.rel(f))
91 91
92 92 bad = []
93 93 standins = []
94 94
95 95 # Need to lock, otherwise there could be a race condition between
96 96 # when standins are created and added to the repo.
97 97 wlock = repo.wlock()
98 98 try:
99 99 if not opts.get('dry_run'):
100 100 lfdirstate = lfutil.openlfdirstate(ui, repo)
101 101 for f in lfnames:
102 102 standinname = lfutil.standin(f)
103 103 lfutil.writestandin(repo, standinname, hash='',
104 104 executable=lfutil.getexecutable(repo.wjoin(f)))
105 105 standins.append(standinname)
106 106 if lfdirstate[f] == 'r':
107 107 lfdirstate.normallookup(f)
108 108 else:
109 109 lfdirstate.add(f)
110 110 lfdirstate.write()
111 111 bad += [lfutil.splitstandin(f)
112 112 for f in lfutil.repo_add(repo, standins)
113 113 if f in m.files()]
114 114 finally:
115 115 wlock.release()
116 116 return bad
117 117
118 118 def remove_largefiles(ui, repo, *pats, **opts):
119 119 after = opts.get('after')
120 120 if not pats and not after:
121 121 raise util.Abort(_('no files specified'))
122 122 m = scmutil.match(repo[None], pats, opts)
123 123 try:
124 124 repo.lfstatus = True
125 125 s = repo.status(match=m, clean=True)
126 126 finally:
127 127 repo.lfstatus = False
128 128 manifest = repo[None].manifest()
129 129 modified, added, deleted, clean = [[f for f in list
130 130 if lfutil.standin(f) in manifest]
131 131 for list in [s[0], s[1], s[3], s[6]]]
132 132
133 133 def warn(files, reason):
134 134 for f in files:
135 135 ui.warn(_('not removing %s: %s (use forget to undo)\n')
136 136 % (m.rel(f), reason))
137 137
138 138 if after:
139 139 remove, forget = deleted, []
140 140 warn(modified + added + clean, _('file still exists'))
141 141 else:
142 142 remove, forget = deleted + clean, []
143 143 warn(modified, _('file is modified'))
144 144 warn(added, _('file has been marked for add'))
145 145
146 146 for f in sorted(remove + forget):
147 147 if ui.verbose or not m.exact(f):
148 148 ui.status(_('removing %s\n') % m.rel(f))
149 149
150 150 # Need to lock because standin files are deleted then removed from the
151 151 # repository and we could race inbetween.
152 152 wlock = repo.wlock()
153 153 try:
154 154 lfdirstate = lfutil.openlfdirstate(ui, repo)
155 155 for f in remove:
156 156 if not after:
157 157 # If this is being called by addremove, notify the user that we
158 158 # are removing the file.
159 159 if getattr(repo, "_isaddremove", False):
160 160 ui.status(_('removing %s\n' % f))
161 161 if os.path.exists(repo.wjoin(f)):
162 162 util.unlinkpath(repo.wjoin(f))
163 163 lfdirstate.remove(f)
164 164 lfdirstate.write()
165 165 forget = [lfutil.standin(f) for f in forget]
166 166 remove = [lfutil.standin(f) for f in remove]
167 167 lfutil.repo_forget(repo, forget)
168 168 # If this is being called by addremove, let the original addremove
169 169 # function handle this.
170 170 if not getattr(repo, "_isaddremove", False):
171 171 lfutil.repo_remove(repo, remove, unlink=True)
172 172 finally:
173 173 wlock.release()
174 174
175 175 # -- Wrappers: modify existing commands --------------------------------
176 176
177 177 # Add works by going through the files that the user wanted to add and
178 178 # checking if they should be added as largefiles. Then it makes a new
179 179 # matcher which matches only the normal files and runs the original
180 180 # version of add.
181 181 def override_add(orig, ui, repo, *pats, **opts):
182 182 normal = opts.pop('normal')
183 183 if normal:
184 184 if opts.get('large'):
185 185 raise util.Abort(_('--normal cannot be used with --large'))
186 186 return orig(ui, repo, *pats, **opts)
187 187 bad = add_largefiles(ui, repo, *pats, **opts)
188 188 installnormalfilesmatchfn(repo[None].manifest())
189 189 result = orig(ui, repo, *pats, **opts)
190 190 restorematchfn()
191 191
192 192 return (result == 1 or bad) and 1 or 0
193 193
194 194 def override_remove(orig, ui, repo, *pats, **opts):
195 195 installnormalfilesmatchfn(repo[None].manifest())
196 196 orig(ui, repo, *pats, **opts)
197 197 restorematchfn()
198 198 remove_largefiles(ui, repo, *pats, **opts)
199 199
200 200 def override_status(orig, ui, repo, *pats, **opts):
201 201 try:
202 202 repo.lfstatus = True
203 203 return orig(ui, repo, *pats, **opts)
204 204 finally:
205 205 repo.lfstatus = False
206 206
207 207 def override_log(orig, ui, repo, *pats, **opts):
208 208 try:
209 209 repo.lfstatus = True
210 210 orig(ui, repo, *pats, **opts)
211 211 finally:
212 212 repo.lfstatus = False
213 213
214 214 def override_verify(orig, ui, repo, *pats, **opts):
215 215 large = opts.pop('large', False)
216 216 all = opts.pop('lfa', False)
217 217 contents = opts.pop('lfc', False)
218 218
219 219 result = orig(ui, repo, *pats, **opts)
220 220 if large:
221 221 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
222 222 return result
223 223
224 224 # Override needs to refresh standins so that update's normal merge
225 225 # will go through properly. Then the other update hook (overriding repo.update)
226 226 # will get the new files. Filemerge is also overriden so that the merge
227 227 # will merge standins correctly.
228 228 def override_update(orig, ui, repo, *pats, **opts):
229 229 lfdirstate = lfutil.openlfdirstate(ui, repo)
230 230 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
231 231 False, False)
232 232 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
233 233
234 234 # Need to lock between the standins getting updated and their
235 235 # largefiles getting updated
236 236 wlock = repo.wlock()
237 237 try:
238 238 if opts['check']:
239 239 mod = len(modified) > 0
240 240 for lfile in unsure:
241 241 standin = lfutil.standin(lfile)
242 242 if repo['.'][standin].data().strip() != \
243 243 lfutil.hashfile(repo.wjoin(lfile)):
244 244 mod = True
245 245 else:
246 246 lfdirstate.normal(lfile)
247 247 lfdirstate.write()
248 248 if mod:
249 249 raise util.Abort(_('uncommitted local changes'))
250 250 # XXX handle removed differently
251 251 if not opts['clean']:
252 252 for lfile in unsure + modified + added:
253 253 lfutil.updatestandin(repo, lfutil.standin(lfile))
254 254 finally:
255 255 wlock.release()
256 256 return orig(ui, repo, *pats, **opts)
257 257
258 258 # Before starting the manifest merge, merge.updates will call
259 259 # _checkunknown to check if there are any files in the merged-in
260 260 # changeset that collide with unknown files in the working copy.
261 261 #
262 262 # The largefiles are seen as unknown, so this prevents us from merging
263 263 # in a file 'foo' if we already have a largefile with the same name.
264 264 #
265 265 # The overridden function filters the unknown files by removing any
266 266 # largefiles. This makes the merge proceed and we can then handle this
267 267 # case further in the overridden manifestmerge function below.
268 268 def override_checkunknown(origfn, wctx, mctx, folding):
269 269 origunknown = wctx.unknown()
270 270 wctx._unknown = filter(lambda f: lfutil.standin(f) not in wctx, origunknown)
271 271 try:
272 272 return origfn(wctx, mctx, folding)
273 273 finally:
274 274 wctx._unknown = origunknown
275 275
276 276 # The manifest merge handles conflicts on the manifest level. We want
277 277 # to handle changes in largefile-ness of files at this level too.
278 278 #
279 279 # The strategy is to run the original manifestmerge and then process
280 280 # the action list it outputs. There are two cases we need to deal with:
281 281 #
282 282 # 1. Normal file in p1, largefile in p2. Here the largefile is
283 283 # detected via its standin file, which will enter the working copy
284 284 # with a "get" action. It is not "merge" since the standin is all
285 285 # Mercurial is concerned with at this level -- the link to the
286 286 # existing normal file is not relevant here.
287 287 #
288 288 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
289 289 # since the largefile will be present in the working copy and
290 290 # different from the normal file in p2. Mercurial therefore
291 291 # triggers a merge action.
292 292 #
293 293 # In both cases, we prompt the user and emit new actions to either
294 294 # remove the standin (if the normal file was kept) or to remove the
295 295 # normal file and get the standin (if the largefile was kept). The
296 296 # default prompt answer is to use the largefile version since it was
297 297 # presumably changed on purpose.
298 298 #
299 299 # Finally, the merge.applyupdates function will then take care of
300 300 # writing the files into the working copy and lfcommands.updatelfiles
301 301 # will update the largefiles.
302 302 def override_manifestmerge(origfn, repo, p1, p2, pa, overwrite, partial):
303 303 actions = origfn(repo, p1, p2, pa, overwrite, partial)
304 304 processed = []
305 305
306 306 for action in actions:
307 307 if overwrite:
308 308 processed.append(action)
309 309 continue
310 310 f, m = action[:2]
311 311
312 312 choices = (_('&Largefile'), _('&Normal file'))
313 313 if m == "g" and lfutil.splitstandin(f) in p1 and f in p2:
314 314 # Case 1: normal file in the working copy, largefile in
315 315 # the second parent
316 316 lfile = lfutil.splitstandin(f)
317 317 standin = f
318 318 msg = _('%s has been turned into a largefile\n'
319 319 'use (l)argefile or keep as (n)ormal file?') % lfile
320 320 if repo.ui.promptchoice(msg, choices, 0) == 0:
321 321 processed.append((lfile, "r"))
322 322 processed.append((standin, "g", p2.flags(standin)))
323 323 else:
324 324 processed.append((standin, "r"))
325 325 elif m == "m" and lfutil.standin(f) in p1 and f in p2:
326 326 # Case 2: largefile in the working copy, normal file in
327 327 # the second parent
328 328 standin = lfutil.standin(f)
329 329 lfile = f
330 330 msg = _('%s has been turned into a normal file\n'
331 331 'keep as (l)argefile or use (n)ormal file?') % lfile
332 332 if repo.ui.promptchoice(msg, choices, 0) == 0:
333 333 processed.append((lfile, "r"))
334 334 else:
335 335 processed.append((standin, "r"))
336 336 processed.append((lfile, "g", p2.flags(lfile)))
337 337 else:
338 338 processed.append(action)
339 339
340 340 return processed
341 341
342 342 # Override filemerge to prompt the user about how they wish to merge
343 343 # largefiles. This will handle identical edits, and copy/rename +
344 344 # edit without prompting the user.
345 345 def override_filemerge(origfn, repo, mynode, orig, fcd, fco, fca):
346 346 # Use better variable names here. Because this is a wrapper we cannot
347 347 # change the variable names in the function declaration.
348 348 fcdest, fcother, fcancestor = fcd, fco, fca
349 349 if not lfutil.isstandin(orig):
350 350 return origfn(repo, mynode, orig, fcdest, fcother, fcancestor)
351 351 else:
352 352 if not fcother.cmp(fcdest): # files identical?
353 353 return None
354 354
355 355 # backwards, use working dir parent as ancestor
356 356 if fcancestor == fcother:
357 357 fcancestor = fcdest.parents()[0]
358 358
359 359 if orig != fcother.path():
360 360 repo.ui.status(_('merging %s and %s to %s\n')
361 361 % (lfutil.splitstandin(orig),
362 362 lfutil.splitstandin(fcother.path()),
363 363 lfutil.splitstandin(fcdest.path())))
364 364 else:
365 365 repo.ui.status(_('merging %s\n')
366 366 % lfutil.splitstandin(fcdest.path()))
367 367
368 368 if fcancestor.path() != fcother.path() and fcother.data() == \
369 369 fcancestor.data():
370 370 return 0
371 371 if fcancestor.path() != fcdest.path() and fcdest.data() == \
372 372 fcancestor.data():
373 373 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
374 374 return 0
375 375
376 376 if repo.ui.promptchoice(_('largefile %s has a merge conflict\n'
377 377 'keep (l)ocal or take (o)ther?') %
378 378 lfutil.splitstandin(orig),
379 379 (_('&Local'), _('&Other')), 0) == 0:
380 380 return 0
381 381 else:
382 382 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
383 383 return 0
384 384
385 385 # Copy first changes the matchers to match standins instead of
386 386 # largefiles. Then it overrides util.copyfile in that function it
387 387 # checks if the destination largefile already exists. It also keeps a
388 388 # list of copied files so that the largefiles can be copied and the
389 389 # dirstate updated.
390 390 def override_copy(orig, ui, repo, pats, opts, rename=False):
391 391 # doesn't remove largefile on rename
392 392 if len(pats) < 2:
393 393 # this isn't legal, let the original function deal with it
394 394 return orig(ui, repo, pats, opts, rename)
395 395
396 396 def makestandin(relpath):
397 397 path = scmutil.canonpath(repo.root, repo.getcwd(), relpath)
398 398 return os.path.join(repo.wjoin(lfutil.standin(path)))
399 399
400 400 fullpats = scmutil.expandpats(pats)
401 401 dest = fullpats[-1]
402 402
403 403 if os.path.isdir(dest):
404 404 if not os.path.isdir(makestandin(dest)):
405 405 os.makedirs(makestandin(dest))
406 406 # This could copy both lfiles and normal files in one command,
407 407 # but we don't want to do that. First replace their matcher to
408 408 # only match normal files and run it, then replace it to just
409 409 # match largefiles and run it again.
410 410 nonormalfiles = False
411 411 nolfiles = False
412 412 try:
413 413 try:
414 414 installnormalfilesmatchfn(repo[None].manifest())
415 415 result = orig(ui, repo, pats, opts, rename)
416 416 except util.Abort, e:
417 417 if str(e) != 'no files to copy':
418 418 raise e
419 419 else:
420 420 nonormalfiles = True
421 421 result = 0
422 422 finally:
423 423 restorematchfn()
424 424
425 425 # The first rename can cause our current working directory to be removed.
426 426 # In that case there is nothing left to copy/rename so just quit.
427 427 try:
428 428 repo.getcwd()
429 429 except OSError:
430 430 return result
431 431
432 432 try:
433 433 try:
434 434 # When we call orig below it creates the standins but we don't add them
435 435 # to the dir state until later so lock during that time.
436 436 wlock = repo.wlock()
437 437
438 438 manifest = repo[None].manifest()
439 439 oldmatch = None # for the closure
440 440 def override_match(ctx, pats=[], opts={}, globbed=False,
441 441 default='relpath'):
442 442 newpats = []
443 443 # The patterns were previously mangled to add the standin
444 444 # directory; we need to remove that now
445 445 for pat in pats:
446 446 if match_.patkind(pat) is None and lfutil.shortname in pat:
447 447 newpats.append(pat.replace(lfutil.shortname, ''))
448 448 else:
449 449 newpats.append(pat)
450 450 match = oldmatch(ctx, newpats, opts, globbed, default)
451 451 m = copy.copy(match)
452 452 lfile = lambda f: lfutil.standin(f) in manifest
453 453 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
454 454 m._fmap = set(m._files)
455 455 orig_matchfn = m.matchfn
456 456 m.matchfn = lambda f: (lfutil.isstandin(f) and
457 457 lfile(lfutil.splitstandin(f)) and
458 458 orig_matchfn(lfutil.splitstandin(f)) or
459 459 None)
460 460 return m
461 461 oldmatch = installmatchfn(override_match)
462 462 listpats = []
463 463 for pat in pats:
464 464 if match_.patkind(pat) is not None:
465 465 listpats.append(pat)
466 466 else:
467 467 listpats.append(makestandin(pat))
468 468
469 469 try:
470 470 origcopyfile = util.copyfile
471 471 copiedfiles = []
472 472 def override_copyfile(src, dest):
473 473 if (lfutil.shortname in src and
474 474 dest.startswith(repo.wjoin(lfutil.shortname))):
475 475 destlfile = dest.replace(lfutil.shortname, '')
476 476 if not opts['force'] and os.path.exists(destlfile):
477 477 raise IOError('',
478 478 _('destination largefile already exists'))
479 479 copiedfiles.append((src, dest))
480 480 origcopyfile(src, dest)
481 481
482 482 util.copyfile = override_copyfile
483 483 result += orig(ui, repo, listpats, opts, rename)
484 484 finally:
485 485 util.copyfile = origcopyfile
486 486
487 487 lfdirstate = lfutil.openlfdirstate(ui, repo)
488 488 for (src, dest) in copiedfiles:
489 489 if (lfutil.shortname in src and
490 490 dest.startswith(repo.wjoin(lfutil.shortname))):
491 491 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
492 492 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
493 493 destlfiledir = os.path.dirname(destlfile) or '.'
494 494 if not os.path.isdir(destlfiledir):
495 495 os.makedirs(destlfiledir)
496 496 if rename:
497 497 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
498 498 lfdirstate.remove(srclfile)
499 499 else:
500 500 util.copyfile(srclfile, destlfile)
501 501 lfdirstate.add(destlfile)
502 502 lfdirstate.write()
503 503 except util.Abort, e:
504 504 if str(e) != 'no files to copy':
505 505 raise e
506 506 else:
507 507 nolfiles = True
508 508 finally:
509 509 restorematchfn()
510 510 wlock.release()
511 511
512 512 if nolfiles and nonormalfiles:
513 513 raise util.Abort(_('no files to copy'))
514 514
515 515 return result
516 516
517 517 # When the user calls revert, we have to be careful to not revert any
518 518 # changes to other largefiles accidentally. This means we have to keep
519 519 # track of the largefiles that are being reverted so we only pull down
520 520 # the necessary largefiles.
521 521 #
522 522 # Standins are only updated (to match the hash of largefiles) before
523 523 # commits. Update the standins then run the original revert, changing
524 524 # the matcher to hit standins instead of largefiles. Based on the
525 525 # resulting standins update the largefiles. Then return the standins
526 526 # to their proper state
527 527 def override_revert(orig, ui, repo, *pats, **opts):
528 528 # Because we put the standins in a bad state (by updating them)
529 529 # and then return them to a correct state we need to lock to
530 530 # prevent others from changing them in their incorrect state.
531 531 wlock = repo.wlock()
532 532 try:
533 533 lfdirstate = lfutil.openlfdirstate(ui, repo)
534 534 (modified, added, removed, missing, unknown, ignored, clean) = \
535 535 lfutil.lfdirstate_status(lfdirstate, repo, repo['.'].rev())
536 536 for lfile in modified:
537 537 lfutil.updatestandin(repo, lfutil.standin(lfile))
538 538
539 539 try:
540 540 ctx = repo[opts.get('rev')]
541 541 oldmatch = None # for the closure
542 542 def override_match(ctx, pats=[], opts={}, globbed=False,
543 543 default='relpath'):
544 544 match = oldmatch(ctx, pats, opts, globbed, default)
545 545 m = copy.copy(match)
546 546 def tostandin(f):
547 547 if lfutil.standin(f) in ctx or lfutil.standin(f) in ctx:
548 548 return lfutil.standin(f)
549 549 elif lfutil.standin(f) in repo[None]:
550 550 return None
551 551 return f
552 552 m._files = [tostandin(f) for f in m._files]
553 553 m._files = [f for f in m._files if f is not None]
554 554 m._fmap = set(m._files)
555 555 orig_matchfn = m.matchfn
556 556 def matchfn(f):
557 557 if lfutil.isstandin(f):
558 558 # We need to keep track of what largefiles are being
559 559 # matched so we know which ones to update later --
560 560 # otherwise we accidentally revert changes to other
561 561 # largefiles. This is repo-specific, so duckpunch the
562 562 # repo object to keep the list of largefiles for us
563 563 # later.
564 564 if orig_matchfn(lfutil.splitstandin(f)) and \
565 565 (f in repo[None] or f in ctx):
566 566 lfileslist = getattr(repo, '_lfilestoupdate', [])
567 567 lfileslist.append(lfutil.splitstandin(f))
568 568 repo._lfilestoupdate = lfileslist
569 569 return True
570 570 else:
571 571 return False
572 572 return orig_matchfn(f)
573 573 m.matchfn = matchfn
574 574 return m
575 575 oldmatch = installmatchfn(override_match)
576 576 scmutil.match
577 577 matches = override_match(repo[None], pats, opts)
578 578 orig(ui, repo, *pats, **opts)
579 579 finally:
580 580 restorematchfn()
581 581 lfileslist = getattr(repo, '_lfilestoupdate', [])
582 582 lfcommands.updatelfiles(ui, repo, filelist=lfileslist,
583 583 printmessage=False)
584 584
585 585 # empty out the largefiles list so we start fresh next time
586 586 repo._lfilestoupdate = []
587 587 for lfile in modified:
588 588 if lfile in lfileslist:
589 589 if os.path.exists(repo.wjoin(lfutil.standin(lfile))) and lfile\
590 590 in repo['.']:
591 591 lfutil.writestandin(repo, lfutil.standin(lfile),
592 592 repo['.'][lfile].data().strip(),
593 593 'x' in repo['.'][lfile].flags())
594 594 lfdirstate = lfutil.openlfdirstate(ui, repo)
595 595 for lfile in added:
596 596 standin = lfutil.standin(lfile)
597 597 if standin not in ctx and (standin in matches or opts.get('all')):
598 598 if lfile in lfdirstate:
599 599 lfdirstate.drop(lfile)
600 600 util.unlinkpath(repo.wjoin(standin))
601 601 lfdirstate.write()
602 602 finally:
603 603 wlock.release()
604 604
605 605 def hg_update(orig, repo, node):
606 606 result = orig(repo, node)
607 607 lfcommands.updatelfiles(repo.ui, repo)
608 608 return result
609 609
610 610 def hg_clean(orig, repo, node, show_stats=True):
611 611 result = orig(repo, node, show_stats)
612 612 lfcommands.updatelfiles(repo.ui, repo)
613 613 return result
614 614
615 615 def hg_merge(orig, repo, node, force=None, remind=True):
616 616 # Mark the repo as being in the middle of a merge, so that
617 617 # updatelfiles() will know that it needs to trust the standins in
618 618 # the working copy, not in the standins in the current node
619 619 repo._ismerging = True
620 620 try:
621 621 result = orig(repo, node, force, remind)
622 622 lfcommands.updatelfiles(repo.ui, repo)
623 623 finally:
624 624 repo._ismerging = False
625 625 return result
626 626
627 627 # When we rebase a repository with remotely changed largefiles, we need to
628 628 # take some extra care so that the largefiles are correctly updated in the
629 629 # working copy
630 630 def override_pull(orig, ui, repo, source=None, **opts):
631 631 if opts.get('rebase', False):
632 632 repo._isrebasing = True
633 633 try:
634 634 if opts.get('update'):
635 635 del opts['update']
636 636 ui.debug('--update and --rebase are not compatible, ignoring '
637 637 'the update flag\n')
638 638 del opts['rebase']
639 639 cmdutil.bailifchanged(repo)
640 640 revsprepull = len(repo)
641 641 origpostincoming = commands.postincoming
642 642 def _dummy(*args, **kwargs):
643 643 pass
644 644 commands.postincoming = _dummy
645 645 repo.lfpullsource = source
646 646 if not source:
647 647 source = 'default'
648 648 try:
649 649 result = commands.pull(ui, repo, source, **opts)
650 650 finally:
651 651 commands.postincoming = origpostincoming
652 652 revspostpull = len(repo)
653 653 if revspostpull > revsprepull:
654 654 result = result or rebase.rebase(ui, repo)
655 655 finally:
656 656 repo._isrebasing = False
657 657 else:
658 658 repo.lfpullsource = source
659 659 if not source:
660 660 source = 'default'
661 661 result = orig(ui, repo, source, **opts)
662 662 # If we do not have the new largefiles for any new heads we pulled, we
663 663 # will run into a problem later if we try to merge or rebase with one of
664 664 # these heads, so cache the largefiles now direclty into the system
665 665 # cache.
666 666 ui.status(_("caching new largefiles\n"))
667 667 numcached = 0
668 668 branches = repo.branchmap()
669 669 for branch in branches:
670 670 heads = repo.branchheads(branch)
671 671 for head in heads:
672 672 (cached, missing) = lfcommands.cachelfiles(ui, repo, head)
673 673 numcached += len(cached)
674 674 ui.status(_("%d largefiles cached\n" % numcached))
675 675 return result
676 676
677 677 def override_rebase(orig, ui, repo, **opts):
678 678 repo._isrebasing = True
679 679 try:
680 680 orig(ui, repo, **opts)
681 681 finally:
682 682 repo._isrebasing = False
683 683
684 684 def override_archive(orig, repo, dest, node, kind, decode=True, matchfn=None,
685 685 prefix=None, mtime=None, subrepos=None):
686 686 # No need to lock because we are only reading history and
687 687 # largefile caches, neither of which are modified.
688 688 lfcommands.cachelfiles(repo.ui, repo, node)
689 689
690 690 if kind not in archival.archivers:
691 691 raise util.Abort(_("unknown archive type '%s'") % kind)
692 692
693 693 ctx = repo[node]
694 694
695 695 if kind == 'files':
696 696 if prefix:
697 697 raise util.Abort(
698 698 _('cannot give prefix when archiving to files'))
699 699 else:
700 700 prefix = archival.tidyprefix(dest, kind, prefix)
701 701
702 702 def write(name, mode, islink, getdata):
703 703 if matchfn and not matchfn(name):
704 704 return
705 705 data = getdata()
706 706 if decode:
707 707 data = repo.wwritedata(name, data)
708 708 archiver.addfile(prefix + name, mode, islink, data)
709 709
710 710 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
711 711
712 712 if repo.ui.configbool("ui", "archivemeta", True):
713 713 def metadata():
714 714 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
715 715 hex(repo.changelog.node(0)), hex(node), ctx.branch())
716 716
717 717 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
718 718 if repo.tagtype(t) == 'global')
719 719 if not tags:
720 720 repo.ui.pushbuffer()
721 721 opts = {'template': '{latesttag}\n{latesttagdistance}',
722 722 'style': '', 'patch': None, 'git': None}
723 723 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
724 724 ltags, dist = repo.ui.popbuffer().split('\n')
725 725 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
726 726 tags += 'latesttagdistance: %s\n' % dist
727 727
728 728 return base + tags
729 729
730 730 write('.hg_archival.txt', 0644, False, metadata)
731 731
732 732 for f in ctx:
733 733 ff = ctx.flags(f)
734 734 getdata = ctx[f].data
735 735 if lfutil.isstandin(f):
736 736 path = lfutil.findfile(repo, getdata().strip())
737 737 if path is None:
738 738 raise util.Abort(
739 739 _('largefile %s not found in repo store or system cache')
740 740 % lfutil.splitstandin(f))
741 741 f = lfutil.splitstandin(f)
742 742
743 743 def getdatafn():
744 744 fd = None
745 745 try:
746 746 fd = open(path, 'rb')
747 747 return fd.read()
748 748 finally:
749 749 if fd:
750 750 fd.close()
751 751
752 752 getdata = getdatafn
753 753 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
754 754
755 755 if subrepos:
756 756 for subpath in ctx.substate:
757 757 sub = ctx.sub(subpath)
758 758 sub.archive(repo.ui, archiver, prefix)
759 759
760 760 archiver.done()
761 761
762 762 # If a largefile is modified, the change is not reflected in its
763 763 # standin until a commit. cmdutil.bailifchanged() raises an exception
764 764 # if the repo has uncommitted changes. Wrap it to also check if
765 765 # largefiles were changed. This is used by bisect and backout.
766 766 def override_bailifchanged(orig, repo):
767 767 orig(repo)
768 768 repo.lfstatus = True
769 769 modified, added, removed, deleted = repo.status()[:4]
770 770 repo.lfstatus = False
771 771 if modified or added or removed or deleted:
772 772 raise util.Abort(_('outstanding uncommitted changes'))
773 773
774 774 # Fetch doesn't use cmdutil.bail_if_changed so override it to add the check
775 775 def override_fetch(orig, ui, repo, *pats, **opts):
776 776 repo.lfstatus = True
777 777 modified, added, removed, deleted = repo.status()[:4]
778 778 repo.lfstatus = False
779 779 if modified or added or removed or deleted:
780 780 raise util.Abort(_('outstanding uncommitted changes'))
781 781 return orig(ui, repo, *pats, **opts)
782 782
783 783 def override_forget(orig, ui, repo, *pats, **opts):
784 784 installnormalfilesmatchfn(repo[None].manifest())
785 785 orig(ui, repo, *pats, **opts)
786 786 restorematchfn()
787 787 m = scmutil.match(repo[None], pats, opts)
788 788
789 789 try:
790 790 repo.lfstatus = True
791 791 s = repo.status(match=m, clean=True)
792 792 finally:
793 793 repo.lfstatus = False
794 794 forget = sorted(s[0] + s[1] + s[3] + s[6])
795 795 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
796 796
797 797 for f in forget:
798 798 if lfutil.standin(f) not in repo.dirstate and not \
799 799 os.path.isdir(m.rel(lfutil.standin(f))):
800 800 ui.warn(_('not removing %s: file is already untracked\n')
801 801 % m.rel(f))
802 802
803 803 for f in forget:
804 804 if ui.verbose or not m.exact(f):
805 805 ui.status(_('removing %s\n') % m.rel(f))
806 806
807 807 # Need to lock because standin files are deleted then removed from the
808 808 # repository and we could race inbetween.
809 809 wlock = repo.wlock()
810 810 try:
811 811 lfdirstate = lfutil.openlfdirstate(ui, repo)
812 812 for f in forget:
813 813 if lfdirstate[f] == 'a':
814 814 lfdirstate.drop(f)
815 815 else:
816 816 lfdirstate.remove(f)
817 817 lfdirstate.write()
818 818 lfutil.repo_remove(repo, [lfutil.standin(f) for f in forget],
819 819 unlink=True)
820 820 finally:
821 821 wlock.release()
822 822
823 823 def getoutgoinglfiles(ui, repo, dest=None, **opts):
824 824 dest = ui.expandpath(dest or 'default-push', dest or 'default')
825 825 dest, branches = hg.parseurl(dest, opts.get('branch'))
826 826 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
827 827 if revs:
828 828 revs = [repo.lookup(rev) for rev in revs]
829 829
830 830 remoteui = hg.remoteui
831 831
832 832 try:
833 833 remote = hg.repository(remoteui(repo, opts), dest)
834 834 except error.RepoError:
835 835 return None
836 836 o = lfutil.findoutgoing(repo, remote, False)
837 837 if not o:
838 838 return None
839 839 o = repo.changelog.nodesbetween(o, revs)[0]
840 840 if opts.get('newest_first'):
841 841 o.reverse()
842 842
843 843 toupload = set()
844 844 for n in o:
845 845 parents = [p for p in repo.changelog.parents(n) if p != node.nullid]
846 846 ctx = repo[n]
847 847 files = set(ctx.files())
848 848 if len(parents) == 2:
849 849 mc = ctx.manifest()
850 850 mp1 = ctx.parents()[0].manifest()
851 851 mp2 = ctx.parents()[1].manifest()
852 852 for f in mp1:
853 853 if f not in mc:
854 854 files.add(f)
855 855 for f in mp2:
856 856 if f not in mc:
857 857 files.add(f)
858 858 for f in mc:
859 859 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None):
860 860 files.add(f)
861 861 toupload = toupload.union(
862 862 set([f for f in files if lfutil.isstandin(f) and f in ctx]))
863 863 return toupload
864 864
865 865 def override_outgoing(orig, ui, repo, dest=None, **opts):
866 866 orig(ui, repo, dest, **opts)
867 867
868 868 if opts.pop('large', None):
869 869 toupload = getoutgoinglfiles(ui, repo, dest, **opts)
870 870 if toupload is None:
871 871 ui.status(_('largefiles: No remote repo\n'))
872 872 else:
873 873 ui.status(_('largefiles to upload:\n'))
874 874 for file in toupload:
875 875 ui.status(lfutil.splitstandin(file) + '\n')
876 876 ui.status('\n')
877 877
878 878 def override_summary(orig, ui, repo, *pats, **opts):
879 879 try:
880 880 repo.lfstatus = True
881 881 orig(ui, repo, *pats, **opts)
882 882 finally:
883 883 repo.lfstatus = False
884 884
885 885 if opts.pop('large', None):
886 886 toupload = getoutgoinglfiles(ui, repo, None, **opts)
887 887 if toupload is None:
888 888 ui.status(_('largefiles: No remote repo\n'))
889 889 else:
890 890 ui.status(_('largefiles: %d to upload\n') % len(toupload))
891 891
892 892 def override_addremove(orig, ui, repo, *pats, **opts):
893 893 # Get the list of missing largefiles so we can remove them
894 894 lfdirstate = lfutil.openlfdirstate(ui, repo)
895 895 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
896 896 False, False)
897 897 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
898 898
899 899 # Call into the normal remove code, but the removing of the standin, we want
900 900 # to have handled by original addremove. Monkey patching here makes sure
901 901 # we don't remove the standin in the largefiles code, preventing a very
902 902 # confused state later.
903 repo._isaddremove = True
904 remove_largefiles(ui, repo, *missing, **opts)
905 repo._isaddremove = False
903 if missing:
904 repo._isaddremove = True
905 remove_largefiles(ui, repo, *missing, **opts)
906 repo._isaddremove = False
906 907 # Call into the normal add code, and any files that *should* be added as
907 908 # largefiles will be
908 909 add_largefiles(ui, repo, *pats, **opts)
909 910 # Now that we've handled largefiles, hand off to the original addremove
910 911 # function to take care of the rest. Make sure it doesn't do anything with
911 912 # largefiles by installing a matcher that will ignore them.
912 913 installnormalfilesmatchfn(repo[None].manifest())
913 914 result = orig(ui, repo, *pats, **opts)
914 915 restorematchfn()
915 916 return result
916 917
917 918 # Calling purge with --all will cause the largefiles to be deleted.
918 919 # Override repo.status to prevent this from happening.
919 920 def override_purge(orig, ui, repo, *dirs, **opts):
920 921 oldstatus = repo.status
921 922 def override_status(node1='.', node2=None, match=None, ignored=False,
922 923 clean=False, unknown=False, listsubrepos=False):
923 924 r = oldstatus(node1, node2, match, ignored, clean, unknown,
924 925 listsubrepos)
925 926 lfdirstate = lfutil.openlfdirstate(ui, repo)
926 927 modified, added, removed, deleted, unknown, ignored, clean = r
927 928 unknown = [f for f in unknown if lfdirstate[f] == '?']
928 929 ignored = [f for f in ignored if lfdirstate[f] == '?']
929 930 return modified, added, removed, deleted, unknown, ignored, clean
930 931 repo.status = override_status
931 932 orig(ui, repo, *dirs, **opts)
932 933 repo.status = oldstatus
933 934
934 935 def override_rollback(orig, ui, repo, **opts):
935 936 result = orig(ui, repo, **opts)
936 937 merge.update(repo, node=None, branchmerge=False, force=True,
937 938 partial=lfutil.isstandin)
938 939 wlock = repo.wlock()
939 940 try:
940 941 lfdirstate = lfutil.openlfdirstate(ui, repo)
941 942 lfiles = lfutil.listlfiles(repo)
942 943 oldlfiles = lfutil.listlfiles(repo, repo[None].parents()[0].rev())
943 944 for file in lfiles:
944 945 if file in oldlfiles:
945 946 lfdirstate.normallookup(file)
946 947 else:
947 948 lfdirstate.add(file)
948 949 lfdirstate.write()
949 950 finally:
950 951 wlock.release()
951 952 return result
952 953
953 954 def override_transplant(orig, ui, repo, *revs, **opts):
954 955 result = orig(ui, repo, *revs, **opts)
955 956 lfcommands.updatelfiles(repo.ui, repo)
956 957 return result
General Comments 0
You need to be logged in to leave comments. Login now