##// END OF EJS Templates
largefiles: remove pre-1.7 compatibility code...
Martin Geisler -
r15626:931dc4af default
parent child Browse files
Show More
@@ -1,828 +1,825 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
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 def installnormalfilesmatchfn(manifest):
24 24 '''overrides scmutil.match so that the matcher it returns will ignore all
25 25 largefiles'''
26 26 oldmatch = None # for the closure
27 27 def override_match(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 orig_matchfn = m.matchfn
36 36 m.matchfn = lambda f: notlfile(f) and orig_matchfn(f) or None
37 37 return m
38 38 oldmatch = installmatchfn(override_match)
39 39
40 40 def installmatchfn(f):
41 41 oldmatch = scmutil.match
42 42 setattr(f, 'oldmatch', oldmatch)
43 43 scmutil.match = f
44 44 return oldmatch
45 45
46 46 def restorematchfn():
47 47 '''restores scmutil.match to what it was before installnormalfilesmatchfn
48 48 was called. no-op if scmutil.match is its original function.
49 49
50 50 Note that n calls to installnormalfilesmatchfn will require n calls to
51 51 restore matchfn to reverse'''
52 52 scmutil.match = getattr(scmutil.match, 'oldmatch', scmutil.match)
53 53
54 54 # -- Wrappers: modify existing commands --------------------------------
55 55
56 56 # Add works by going through the files that the user wanted to add and
57 57 # checking if they should be added as largefiles. Then it makes a new
58 58 # matcher which matches only the normal files and runs the original
59 59 # version of add.
60 60 def override_add(orig, ui, repo, *pats, **opts):
61 61 large = opts.pop('large', None)
62 62 lfsize = lfutil.getminsize(
63 63 ui, lfutil.islfilesrepo(repo), opts.pop('lfsize', None))
64 64
65 65 lfmatcher = None
66 66 if os.path.exists(repo.wjoin(lfutil.shortname)):
67 67 lfpats = ui.configlist(lfutil.longname, 'patterns', default=[])
68 68 if lfpats:
69 69 lfmatcher = match_.match(repo.root, '', list(lfpats))
70 70
71 71 lfnames = []
72 72 m = scmutil.match(repo[None], pats, opts)
73 73 m.bad = lambda x, y: None
74 74 wctx = repo[None]
75 75 for f in repo.walk(m):
76 76 exact = m.exact(f)
77 77 lfile = lfutil.standin(f) in wctx
78 78 nfile = f in wctx
79 79 exists = lfile or nfile
80 80
81 81 # Don't warn the user when they attempt to add a normal tracked file.
82 82 # The normal add code will do that for us.
83 83 if exact and exists:
84 84 if lfile:
85 85 ui.warn(_('%s already a largefile\n') % f)
86 86 continue
87 87
88 88 if exact or not exists:
89 89 abovemin = (lfsize and
90 90 os.lstat(repo.wjoin(f)).st_size >= lfsize * 1024 * 1024)
91 91 if large or abovemin or (lfmatcher and lfmatcher(f)):
92 92 lfnames.append(f)
93 93 if ui.verbose or not exact:
94 94 ui.status(_('adding %s as a largefile\n') % m.rel(f))
95 95
96 96 bad = []
97 97 standins = []
98 98
99 99 # Need to lock, otherwise there could be a race condition between
100 100 # when standins are created and added to the repo.
101 101 wlock = repo.wlock()
102 102 try:
103 103 if not opts.get('dry_run'):
104 104 lfdirstate = lfutil.openlfdirstate(ui, repo)
105 105 for f in lfnames:
106 106 standinname = lfutil.standin(f)
107 107 lfutil.writestandin(repo, standinname, hash='',
108 108 executable=lfutil.getexecutable(repo.wjoin(f)))
109 109 standins.append(standinname)
110 110 if lfdirstate[f] == 'r':
111 111 lfdirstate.normallookup(f)
112 112 else:
113 113 lfdirstate.add(f)
114 114 lfdirstate.write()
115 115 bad += [lfutil.splitstandin(f)
116 116 for f in lfutil.repo_add(repo, standins)
117 117 if f in m.files()]
118 118 finally:
119 119 wlock.release()
120 120
121 121 installnormalfilesmatchfn(repo[None].manifest())
122 122 result = orig(ui, repo, *pats, **opts)
123 123 restorematchfn()
124 124
125 125 return (result == 1 or bad) and 1 or 0
126 126
127 127 def override_remove(orig, ui, repo, *pats, **opts):
128 128 manifest = repo[None].manifest()
129 129 installnormalfilesmatchfn(manifest)
130 130 orig(ui, repo, *pats, **opts)
131 131 restorematchfn()
132 132
133 133 after, force = opts.get('after'), opts.get('force')
134 134 if not pats and not after:
135 135 raise util.Abort(_('no files specified'))
136 136 m = scmutil.match(repo[None], pats, opts)
137 137 try:
138 138 repo.lfstatus = True
139 139 s = repo.status(match=m, clean=True)
140 140 finally:
141 141 repo.lfstatus = False
142 142 modified, added, deleted, clean = [[f for f in list
143 143 if lfutil.standin(f) in manifest]
144 144 for list in [s[0], s[1], s[3], s[6]]]
145 145
146 146 def warn(files, reason):
147 147 for f in files:
148 148 ui.warn(_('not removing %s: %s (use -f to force removal)\n')
149 149 % (m.rel(f), reason))
150 150
151 151 if force:
152 152 remove, forget = modified + deleted + clean, added
153 153 elif after:
154 154 remove, forget = deleted, []
155 155 warn(modified + added + clean, _('file still exists'))
156 156 else:
157 157 remove, forget = deleted + clean, []
158 158 warn(modified, _('file is modified'))
159 159 warn(added, _('file has been marked for add'))
160 160
161 161 for f in sorted(remove + forget):
162 162 if ui.verbose or not m.exact(f):
163 163 ui.status(_('removing %s\n') % m.rel(f))
164 164
165 165 # Need to lock because standin files are deleted then removed from the
166 166 # repository and we could race inbetween.
167 167 wlock = repo.wlock()
168 168 try:
169 169 lfdirstate = lfutil.openlfdirstate(ui, repo)
170 170 for f in remove:
171 171 if not after:
172 172 os.unlink(repo.wjoin(f))
173 173 currentdir = os.path.split(f)[0]
174 174 while currentdir and not os.listdir(repo.wjoin(currentdir)):
175 175 os.rmdir(repo.wjoin(currentdir))
176 176 currentdir = os.path.split(currentdir)[0]
177 177 lfdirstate.remove(f)
178 178 lfdirstate.write()
179 179
180 180 forget = [lfutil.standin(f) for f in forget]
181 181 remove = [lfutil.standin(f) for f in remove]
182 182 lfutil.repo_forget(repo, forget)
183 183 lfutil.repo_remove(repo, remove, unlink=True)
184 184 finally:
185 185 wlock.release()
186 186
187 187 def override_status(orig, ui, repo, *pats, **opts):
188 188 try:
189 189 repo.lfstatus = True
190 190 return orig(ui, repo, *pats, **opts)
191 191 finally:
192 192 repo.lfstatus = False
193 193
194 194 def override_log(orig, ui, repo, *pats, **opts):
195 195 try:
196 196 repo.lfstatus = True
197 197 orig(ui, repo, *pats, **opts)
198 198 finally:
199 199 repo.lfstatus = False
200 200
201 201 def override_verify(orig, ui, repo, *pats, **opts):
202 202 large = opts.pop('large', False)
203 203 all = opts.pop('lfa', False)
204 204 contents = opts.pop('lfc', False)
205 205
206 206 result = orig(ui, repo, *pats, **opts)
207 207 if large:
208 208 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
209 209 return result
210 210
211 211 # Override needs to refresh standins so that update's normal merge
212 212 # will go through properly. Then the other update hook (overriding repo.update)
213 213 # will get the new files. Filemerge is also overriden so that the merge
214 214 # will merge standins correctly.
215 215 def override_update(orig, ui, repo, *pats, **opts):
216 216 lfdirstate = lfutil.openlfdirstate(ui, repo)
217 217 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
218 218 False, False)
219 219 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
220 220
221 221 # Need to lock between the standins getting updated and their
222 222 # largefiles getting updated
223 223 wlock = repo.wlock()
224 224 try:
225 225 if opts['check']:
226 226 mod = len(modified) > 0
227 227 for lfile in unsure:
228 228 standin = lfutil.standin(lfile)
229 229 if repo['.'][standin].data().strip() != \
230 230 lfutil.hashfile(repo.wjoin(lfile)):
231 231 mod = True
232 232 else:
233 233 lfdirstate.normal(lfile)
234 234 lfdirstate.write()
235 235 if mod:
236 236 raise util.Abort(_('uncommitted local changes'))
237 237 # XXX handle removed differently
238 238 if not opts['clean']:
239 239 for lfile in unsure + modified + added:
240 240 lfutil.updatestandin(repo, lfutil.standin(lfile))
241 241 finally:
242 242 wlock.release()
243 243 return orig(ui, repo, *pats, **opts)
244 244
245 245 # Override filemerge to prompt the user about how they wish to merge
246 246 # largefiles. This will handle identical edits, and copy/rename +
247 247 # edit without prompting the user.
248 248 def override_filemerge(origfn, repo, mynode, orig, fcd, fco, fca):
249 249 # Use better variable names here. Because this is a wrapper we cannot
250 250 # change the variable names in the function declaration.
251 251 fcdest, fcother, fcancestor = fcd, fco, fca
252 252 if not lfutil.isstandin(orig):
253 253 return origfn(repo, mynode, orig, fcdest, fcother, fcancestor)
254 254 else:
255 255 if not fcother.cmp(fcdest): # files identical?
256 256 return None
257 257
258 258 # backwards, use working dir parent as ancestor
259 259 if fcancestor == fcother:
260 260 fcancestor = fcdest.parents()[0]
261 261
262 262 if orig != fcother.path():
263 263 repo.ui.status(_('merging %s and %s to %s\n')
264 264 % (lfutil.splitstandin(orig),
265 265 lfutil.splitstandin(fcother.path()),
266 266 lfutil.splitstandin(fcdest.path())))
267 267 else:
268 268 repo.ui.status(_('merging %s\n')
269 269 % lfutil.splitstandin(fcdest.path()))
270 270
271 271 if fcancestor.path() != fcother.path() and fcother.data() == \
272 272 fcancestor.data():
273 273 return 0
274 274 if fcancestor.path() != fcdest.path() and fcdest.data() == \
275 275 fcancestor.data():
276 276 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
277 277 return 0
278 278
279 279 if repo.ui.promptchoice(_('largefile %s has a merge conflict\n'
280 280 'keep (l)ocal or take (o)ther?') %
281 281 lfutil.splitstandin(orig),
282 282 (_('&Local'), _('&Other')), 0) == 0:
283 283 return 0
284 284 else:
285 285 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
286 286 return 0
287 287
288 288 # Copy first changes the matchers to match standins instead of
289 289 # largefiles. Then it overrides util.copyfile in that function it
290 290 # checks if the destination largefile already exists. It also keeps a
291 291 # list of copied files so that the largefiles can be copied and the
292 292 # dirstate updated.
293 293 def override_copy(orig, ui, repo, pats, opts, rename=False):
294 294 # doesn't remove largefile on rename
295 295 if len(pats) < 2:
296 296 # this isn't legal, let the original function deal with it
297 297 return orig(ui, repo, pats, opts, rename)
298 298
299 299 def makestandin(relpath):
300 300 path = scmutil.canonpath(repo.root, repo.getcwd(), relpath)
301 301 return os.path.join(repo.wjoin(lfutil.standin(path)))
302 302
303 303 fullpats = scmutil.expandpats(pats)
304 304 dest = fullpats[-1]
305 305
306 306 if os.path.isdir(dest):
307 307 if not os.path.isdir(makestandin(dest)):
308 308 os.makedirs(makestandin(dest))
309 309 # This could copy both lfiles and normal files in one command,
310 310 # but we don't want to do that. First replace their matcher to
311 311 # only match normal files and run it, then replace it to just
312 312 # match largefiles and run it again.
313 313 nonormalfiles = False
314 314 nolfiles = False
315 315 try:
316 316 try:
317 317 installnormalfilesmatchfn(repo[None].manifest())
318 318 result = orig(ui, repo, pats, opts, rename)
319 319 except util.Abort, e:
320 320 if str(e) != 'no files to copy':
321 321 raise e
322 322 else:
323 323 nonormalfiles = True
324 324 result = 0
325 325 finally:
326 326 restorematchfn()
327 327
328 328 # The first rename can cause our current working directory to be removed.
329 329 # In that case there is nothing left to copy/rename so just quit.
330 330 try:
331 331 repo.getcwd()
332 332 except OSError:
333 333 return result
334 334
335 335 try:
336 336 try:
337 337 # When we call orig below it creates the standins but we don't add them
338 338 # to the dir state until later so lock during that time.
339 339 wlock = repo.wlock()
340 340
341 341 manifest = repo[None].manifest()
342 342 oldmatch = None # for the closure
343 343 def override_match(ctx, pats=[], opts={}, globbed=False,
344 344 default='relpath'):
345 345 newpats = []
346 346 # The patterns were previously mangled to add the standin
347 347 # directory; we need to remove that now
348 348 for pat in pats:
349 349 if match_.patkind(pat) is None and lfutil.shortname in pat:
350 350 newpats.append(pat.replace(lfutil.shortname, ''))
351 351 else:
352 352 newpats.append(pat)
353 353 match = oldmatch(ctx, newpats, opts, globbed, default)
354 354 m = copy.copy(match)
355 355 lfile = lambda f: lfutil.standin(f) in manifest
356 356 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
357 357 m._fmap = set(m._files)
358 358 orig_matchfn = m.matchfn
359 359 m.matchfn = lambda f: (lfutil.isstandin(f) and
360 360 lfile(lfutil.splitstandin(f)) and
361 361 orig_matchfn(lfutil.splitstandin(f)) or
362 362 None)
363 363 return m
364 364 oldmatch = installmatchfn(override_match)
365 365 listpats = []
366 366 for pat in pats:
367 367 if match_.patkind(pat) is not None:
368 368 listpats.append(pat)
369 369 else:
370 370 listpats.append(makestandin(pat))
371 371
372 372 try:
373 373 origcopyfile = util.copyfile
374 374 copiedfiles = []
375 375 def override_copyfile(src, dest):
376 376 if (lfutil.shortname in src and
377 377 dest.startswith(repo.wjoin(lfutil.shortname))):
378 378 destlfile = dest.replace(lfutil.shortname, '')
379 379 if not opts['force'] and os.path.exists(destlfile):
380 380 raise IOError('',
381 381 _('destination largefile already exists'))
382 382 copiedfiles.append((src, dest))
383 383 origcopyfile(src, dest)
384 384
385 385 util.copyfile = override_copyfile
386 386 result += orig(ui, repo, listpats, opts, rename)
387 387 finally:
388 388 util.copyfile = origcopyfile
389 389
390 390 lfdirstate = lfutil.openlfdirstate(ui, repo)
391 391 for (src, dest) in copiedfiles:
392 392 if (lfutil.shortname in src and
393 393 dest.startswith(repo.wjoin(lfutil.shortname))):
394 394 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
395 395 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
396 396 destlfiledir = os.path.dirname(destlfile) or '.'
397 397 if not os.path.isdir(destlfiledir):
398 398 os.makedirs(destlfiledir)
399 399 if rename:
400 400 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
401 401 lfdirstate.remove(srclfile)
402 402 else:
403 403 util.copyfile(srclfile, destlfile)
404 404 lfdirstate.add(destlfile)
405 405 lfdirstate.write()
406 406 except util.Abort, e:
407 407 if str(e) != 'no files to copy':
408 408 raise e
409 409 else:
410 410 nolfiles = True
411 411 finally:
412 412 restorematchfn()
413 413 wlock.release()
414 414
415 415 if nolfiles and nonormalfiles:
416 416 raise util.Abort(_('no files to copy'))
417 417
418 418 return result
419 419
420 420 # When the user calls revert, we have to be careful to not revert any
421 421 # changes to other largefiles accidentally. This means we have to keep
422 422 # track of the largefiles that are being reverted so we only pull down
423 423 # the necessary largefiles.
424 424 #
425 425 # Standins are only updated (to match the hash of largefiles) before
426 426 # commits. Update the standins then run the original revert, changing
427 427 # the matcher to hit standins instead of largefiles. Based on the
428 428 # resulting standins update the largefiles. Then return the standins
429 429 # to their proper state
430 430 def override_revert(orig, ui, repo, *pats, **opts):
431 431 # Because we put the standins in a bad state (by updating them)
432 432 # and then return them to a correct state we need to lock to
433 433 # prevent others from changing them in their incorrect state.
434 434 wlock = repo.wlock()
435 435 try:
436 436 lfdirstate = lfutil.openlfdirstate(ui, repo)
437 437 (modified, added, removed, missing, unknown, ignored, clean) = \
438 438 lfutil.lfdirstate_status(lfdirstate, repo, repo['.'].rev())
439 439 for lfile in modified:
440 440 lfutil.updatestandin(repo, lfutil.standin(lfile))
441 441
442 442 try:
443 443 ctx = repo[opts.get('rev')]
444 444 oldmatch = None # for the closure
445 445 def override_match(ctx, pats=[], opts={}, globbed=False,
446 446 default='relpath'):
447 447 match = oldmatch(ctx, pats, opts, globbed, default)
448 448 m = copy.copy(match)
449 449 def tostandin(f):
450 450 if lfutil.standin(f) in ctx or lfutil.standin(f) in ctx:
451 451 return lfutil.standin(f)
452 452 elif lfutil.standin(f) in repo[None]:
453 453 return None
454 454 return f
455 455 m._files = [tostandin(f) for f in m._files]
456 456 m._files = [f for f in m._files if f is not None]
457 457 m._fmap = set(m._files)
458 458 orig_matchfn = m.matchfn
459 459 def matchfn(f):
460 460 if lfutil.isstandin(f):
461 461 # We need to keep track of what largefiles are being
462 462 # matched so we know which ones to update later --
463 463 # otherwise we accidentally revert changes to other
464 464 # largefiles. This is repo-specific, so duckpunch the
465 465 # repo object to keep the list of largefiles for us
466 466 # later.
467 467 if orig_matchfn(lfutil.splitstandin(f)) and \
468 468 (f in repo[None] or f in ctx):
469 469 lfileslist = getattr(repo, '_lfilestoupdate', [])
470 470 lfileslist.append(lfutil.splitstandin(f))
471 471 repo._lfilestoupdate = lfileslist
472 472 return True
473 473 else:
474 474 return False
475 475 return orig_matchfn(f)
476 476 m.matchfn = matchfn
477 477 return m
478 478 oldmatch = installmatchfn(override_match)
479 479 scmutil.match
480 480 matches = override_match(repo[None], pats, opts)
481 481 orig(ui, repo, *pats, **opts)
482 482 finally:
483 483 restorematchfn()
484 484 lfileslist = getattr(repo, '_lfilestoupdate', [])
485 485 lfcommands.updatelfiles(ui, repo, filelist=lfileslist,
486 486 printmessage=False)
487 487
488 488 # empty out the largefiles list so we start fresh next time
489 489 repo._lfilestoupdate = []
490 490 for lfile in modified:
491 491 if lfile in lfileslist:
492 492 if os.path.exists(repo.wjoin(lfutil.standin(lfile))) and lfile\
493 493 in repo['.']:
494 494 lfutil.writestandin(repo, lfutil.standin(lfile),
495 495 repo['.'][lfile].data().strip(),
496 496 'x' in repo['.'][lfile].flags())
497 497 lfdirstate = lfutil.openlfdirstate(ui, repo)
498 498 for lfile in added:
499 499 standin = lfutil.standin(lfile)
500 500 if standin not in ctx and (standin in matches or opts.get('all')):
501 501 if lfile in lfdirstate:
502 502 lfdirstate.drop(lfile)
503 503 util.unlinkpath(repo.wjoin(standin))
504 504 lfdirstate.write()
505 505 finally:
506 506 wlock.release()
507 507
508 508 def hg_update(orig, repo, node):
509 509 result = orig(repo, node)
510 510 # XXX check if it worked first
511 511 lfcommands.updatelfiles(repo.ui, repo)
512 512 return result
513 513
514 514 def hg_clean(orig, repo, node, show_stats=True):
515 515 result = orig(repo, node, show_stats)
516 516 lfcommands.updatelfiles(repo.ui, repo)
517 517 return result
518 518
519 519 def hg_merge(orig, repo, node, force=None, remind=True):
520 520 result = orig(repo, node, force, remind)
521 521 lfcommands.updatelfiles(repo.ui, repo)
522 522 return result
523 523
524 524 # When we rebase a repository with remotely changed largefiles, we need to
525 525 # take some extra care so that the largefiles are correctly updated in the
526 526 # working copy
527 527 def override_pull(orig, ui, repo, source=None, **opts):
528 528 if opts.get('rebase', False):
529 529 repo._isrebasing = True
530 530 try:
531 531 if opts.get('update'):
532 532 del opts['update']
533 533 ui.debug('--update and --rebase are not compatible, ignoring '
534 534 'the update flag\n')
535 535 del opts['rebase']
536 536 cmdutil.bailifchanged(repo)
537 537 revsprepull = len(repo)
538 538 origpostincoming = commands.postincoming
539 539 def _dummy(*args, **kwargs):
540 540 pass
541 541 commands.postincoming = _dummy
542 542 repo.lfpullsource = source
543 543 if not source:
544 544 source = 'default'
545 545 try:
546 546 result = commands.pull(ui, repo, source, **opts)
547 547 finally:
548 548 commands.postincoming = origpostincoming
549 549 revspostpull = len(repo)
550 550 if revspostpull > revsprepull:
551 551 result = result or rebase.rebase(ui, repo)
552 552 finally:
553 553 repo._isrebasing = False
554 554 else:
555 555 repo.lfpullsource = source
556 556 if not source:
557 557 source = 'default'
558 558 result = orig(ui, repo, source, **opts)
559 559 return result
560 560
561 561 def override_rebase(orig, ui, repo, **opts):
562 562 repo._isrebasing = True
563 563 try:
564 564 orig(ui, repo, **opts)
565 565 finally:
566 566 repo._isrebasing = False
567 567
568 568 def override_archive(orig, repo, dest, node, kind, decode=True, matchfn=None,
569 569 prefix=None, mtime=None, subrepos=None):
570 570 # No need to lock because we are only reading history and
571 571 # largefile caches, neither of which are modified.
572 572 lfcommands.cachelfiles(repo.ui, repo, node)
573 573
574 574 if kind not in archival.archivers:
575 575 raise util.Abort(_("unknown archive type '%s'") % kind)
576 576
577 577 ctx = repo[node]
578 578
579 579 if kind == 'files':
580 580 if prefix:
581 581 raise util.Abort(
582 582 _('cannot give prefix when archiving to files'))
583 583 else:
584 584 prefix = archival.tidyprefix(dest, kind, prefix)
585 585
586 586 def write(name, mode, islink, getdata):
587 587 if matchfn and not matchfn(name):
588 588 return
589 589 data = getdata()
590 590 if decode:
591 591 data = repo.wwritedata(name, data)
592 592 archiver.addfile(prefix + name, mode, islink, data)
593 593
594 594 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
595 595
596 596 if repo.ui.configbool("ui", "archivemeta", True):
597 597 def metadata():
598 598 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
599 599 hex(repo.changelog.node(0)), hex(node), ctx.branch())
600 600
601 601 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
602 602 if repo.tagtype(t) == 'global')
603 603 if not tags:
604 604 repo.ui.pushbuffer()
605 605 opts = {'template': '{latesttag}\n{latesttagdistance}',
606 606 'style': '', 'patch': None, 'git': None}
607 607 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
608 608 ltags, dist = repo.ui.popbuffer().split('\n')
609 609 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
610 610 tags += 'latesttagdistance: %s\n' % dist
611 611
612 612 return base + tags
613 613
614 614 write('.hg_archival.txt', 0644, False, metadata)
615 615
616 616 for f in ctx:
617 617 ff = ctx.flags(f)
618 618 getdata = ctx[f].data
619 619 if lfutil.isstandin(f):
620 620 path = lfutil.findfile(repo, getdata().strip())
621 621 f = lfutil.splitstandin(f)
622 622
623 623 def getdatafn():
624 624 fd = None
625 625 try:
626 626 fd = open(path, 'rb')
627 627 return fd.read()
628 628 finally:
629 629 if fd:
630 630 fd.close()
631 631
632 632 getdata = getdatafn
633 633 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
634 634
635 635 if subrepos:
636 636 for subpath in ctx.substate:
637 637 sub = ctx.sub(subpath)
638 try:
639 sub.archive(repo.ui, archiver, prefix)
640 except TypeError:
641 sub.archive(archiver, prefix)
638 sub.archive(repo.ui, archiver, prefix)
642 639
643 640 archiver.done()
644 641
645 642 # If a largefile is modified, the change is not reflected in its
646 643 # standin until a commit. cmdutil.bailifchanged() raises an exception
647 644 # if the repo has uncommitted changes. Wrap it to also check if
648 645 # largefiles were changed. This is used by bisect and backout.
649 646 def override_bailifchanged(orig, repo):
650 647 orig(repo)
651 648 repo.lfstatus = True
652 649 modified, added, removed, deleted = repo.status()[:4]
653 650 repo.lfstatus = False
654 651 if modified or added or removed or deleted:
655 652 raise util.Abort(_('outstanding uncommitted changes'))
656 653
657 654 # Fetch doesn't use cmdutil.bail_if_changed so override it to add the check
658 655 def override_fetch(orig, ui, repo, *pats, **opts):
659 656 repo.lfstatus = True
660 657 modified, added, removed, deleted = repo.status()[:4]
661 658 repo.lfstatus = False
662 659 if modified or added or removed or deleted:
663 660 raise util.Abort(_('outstanding uncommitted changes'))
664 661 return orig(ui, repo, *pats, **opts)
665 662
666 663 def override_forget(orig, ui, repo, *pats, **opts):
667 664 installnormalfilesmatchfn(repo[None].manifest())
668 665 orig(ui, repo, *pats, **opts)
669 666 restorematchfn()
670 667 m = scmutil.match(repo[None], pats, opts)
671 668
672 669 try:
673 670 repo.lfstatus = True
674 671 s = repo.status(match=m, clean=True)
675 672 finally:
676 673 repo.lfstatus = False
677 674 forget = sorted(s[0] + s[1] + s[3] + s[6])
678 675 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
679 676
680 677 for f in forget:
681 678 if lfutil.standin(f) not in repo.dirstate and not \
682 679 os.path.isdir(m.rel(lfutil.standin(f))):
683 680 ui.warn(_('not removing %s: file is already untracked\n')
684 681 % m.rel(f))
685 682
686 683 for f in forget:
687 684 if ui.verbose or not m.exact(f):
688 685 ui.status(_('removing %s\n') % m.rel(f))
689 686
690 687 # Need to lock because standin files are deleted then removed from the
691 688 # repository and we could race inbetween.
692 689 wlock = repo.wlock()
693 690 try:
694 691 lfdirstate = lfutil.openlfdirstate(ui, repo)
695 692 for f in forget:
696 693 if lfdirstate[f] == 'a':
697 694 lfdirstate.drop(f)
698 695 else:
699 696 lfdirstate.remove(f)
700 697 lfdirstate.write()
701 698 lfutil.repo_remove(repo, [lfutil.standin(f) for f in forget],
702 699 unlink=True)
703 700 finally:
704 701 wlock.release()
705 702
706 703 def getoutgoinglfiles(ui, repo, dest=None, **opts):
707 704 dest = ui.expandpath(dest or 'default-push', dest or 'default')
708 705 dest, branches = hg.parseurl(dest, opts.get('branch'))
709 706 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
710 707 if revs:
711 708 revs = [repo.lookup(rev) for rev in revs]
712 709
713 710 remoteui = hg.remoteui
714 711
715 712 try:
716 713 remote = hg.repository(remoteui(repo, opts), dest)
717 714 except error.RepoError:
718 715 return None
719 716 o = lfutil.findoutgoing(repo, remote, False)
720 717 if not o:
721 718 return None
722 719 o = repo.changelog.nodesbetween(o, revs)[0]
723 720 if opts.get('newest_first'):
724 721 o.reverse()
725 722
726 723 toupload = set()
727 724 for n in o:
728 725 parents = [p for p in repo.changelog.parents(n) if p != node.nullid]
729 726 ctx = repo[n]
730 727 files = set(ctx.files())
731 728 if len(parents) == 2:
732 729 mc = ctx.manifest()
733 730 mp1 = ctx.parents()[0].manifest()
734 731 mp2 = ctx.parents()[1].manifest()
735 732 for f in mp1:
736 733 if f not in mc:
737 734 files.add(f)
738 735 for f in mp2:
739 736 if f not in mc:
740 737 files.add(f)
741 738 for f in mc:
742 739 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None):
743 740 files.add(f)
744 741 toupload = toupload.union(
745 742 set([f for f in files if lfutil.isstandin(f) and f in ctx]))
746 743 return toupload
747 744
748 745 def override_outgoing(orig, ui, repo, dest=None, **opts):
749 746 orig(ui, repo, dest, **opts)
750 747
751 748 if opts.pop('large', None):
752 749 toupload = getoutgoinglfiles(ui, repo, dest, **opts)
753 750 if toupload is None:
754 751 ui.status(_('largefiles: No remote repo\n'))
755 752 else:
756 753 ui.status(_('largefiles to upload:\n'))
757 754 for file in toupload:
758 755 ui.status(lfutil.splitstandin(file) + '\n')
759 756 ui.status('\n')
760 757
761 758 def override_summary(orig, ui, repo, *pats, **opts):
762 759 orig(ui, repo, *pats, **opts)
763 760
764 761 if opts.pop('large', None):
765 762 toupload = getoutgoinglfiles(ui, repo, None, **opts)
766 763 if toupload is None:
767 764 ui.status(_('largefiles: No remote repo\n'))
768 765 else:
769 766 ui.status(_('largefiles: %d to upload\n') % len(toupload))
770 767
771 768 def override_addremove(orig, ui, repo, *pats, **opts):
772 769 # Check if the parent or child has largefiles; if so, disallow
773 770 # addremove. If there is a symlink in the manifest then getting
774 771 # the manifest throws an exception: catch it and let addremove
775 772 # deal with it.
776 773 try:
777 774 manifesttip = set(repo['tip'].manifest())
778 775 except util.Abort:
779 776 manifesttip = set()
780 777 try:
781 778 manifestworking = set(repo[None].manifest())
782 779 except util.Abort:
783 780 manifestworking = set()
784 781
785 782 # Manifests are only iterable so turn them into sets then union
786 783 for file in manifesttip.union(manifestworking):
787 784 if file.startswith(lfutil.shortname):
788 785 raise util.Abort(
789 786 _('addremove cannot be run on a repo with largefiles'))
790 787
791 788 return orig(ui, repo, *pats, **opts)
792 789
793 790 # Calling purge with --all will cause the largefiles to be deleted.
794 791 # Override repo.status to prevent this from happening.
795 792 def override_purge(orig, ui, repo, *dirs, **opts):
796 793 oldstatus = repo.status
797 794 def override_status(node1='.', node2=None, match=None, ignored=False,
798 795 clean=False, unknown=False, listsubrepos=False):
799 796 r = oldstatus(node1, node2, match, ignored, clean, unknown,
800 797 listsubrepos)
801 798 lfdirstate = lfutil.openlfdirstate(ui, repo)
802 799 modified, added, removed, deleted, unknown, ignored, clean = r
803 800 unknown = [f for f in unknown if lfdirstate[f] == '?']
804 801 ignored = [f for f in ignored if lfdirstate[f] == '?']
805 802 return modified, added, removed, deleted, unknown, ignored, clean
806 803 repo.status = override_status
807 804 orig(ui, repo, *dirs, **opts)
808 805 repo.status = oldstatus
809 806
810 807 def override_rollback(orig, ui, repo, **opts):
811 808 result = orig(ui, repo, **opts)
812 809 merge.update(repo, node=None, branchmerge=False, force=True,
813 810 partial=lfutil.isstandin)
814 811 lfdirstate = lfutil.openlfdirstate(ui, repo)
815 812 lfiles = lfutil.listlfiles(repo)
816 813 oldlfiles = lfutil.listlfiles(repo, repo[None].parents()[0].rev())
817 814 for file in lfiles:
818 815 if file in oldlfiles:
819 816 lfdirstate.normallookup(file)
820 817 else:
821 818 lfdirstate.add(file)
822 819 lfdirstate.write()
823 820 return result
824 821
825 822 def override_transplant(orig, ui, repo, *revs, **opts):
826 823 result = orig(ui, repo, *revs, **opts)
827 824 lfcommands.updatelfiles(repo.ui, repo)
828 825 return result
@@ -1,433 +1,425 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 '''setup for largefiles repositories: reposetup'''
10 10 import copy
11 11 import types
12 12 import os
13 13 import re
14 14
15 15 from mercurial import context, error, manifest, match as match_, node, util
16 16 from mercurial.i18n import _
17 17
18 18 import lfcommands
19 19 import proto
20 20 import lfutil
21 21
22 22 def reposetup(ui, repo):
23 23 # wire repositories should be given new wireproto functions but not the
24 24 # other largefiles modifications
25 25 if not repo.local():
26 26 return proto.wirereposetup(ui, repo)
27 27
28 28 for name in ('status', 'commitctx', 'commit', 'push'):
29 29 method = getattr(repo, name)
30 30 #if not (isinstance(method, types.MethodType) and
31 31 # method.im_func is repo.__class__.commitctx.im_func):
32 32 if (isinstance(method, types.FunctionType) and
33 33 method.func_name == 'wrap'):
34 34 ui.warn(_('largefiles: repo method %r appears to have already been'
35 35 ' wrapped by another extension: '
36 36 'largefiles may behave incorrectly\n')
37 37 % name)
38 38
39 39 class lfiles_repo(repo.__class__):
40 40 lfstatus = False
41 41 def status_nolfiles(self, *args, **kwargs):
42 42 return super(lfiles_repo, self).status(*args, **kwargs)
43 43
44 44 # When lfstatus is set, return a context that gives the names
45 45 # of largefiles instead of their corresponding standins and
46 46 # identifies the largefiles as always binary, regardless of
47 47 # their actual contents.
48 48 def __getitem__(self, changeid):
49 49 ctx = super(lfiles_repo, self).__getitem__(changeid)
50 50 if self.lfstatus:
51 51 class lfiles_manifestdict(manifest.manifestdict):
52 52 def __contains__(self, filename):
53 53 if super(lfiles_manifestdict,
54 54 self).__contains__(filename):
55 55 return True
56 56 return super(lfiles_manifestdict,
57 57 self).__contains__(lfutil.shortname+'/' + filename)
58 58 class lfiles_ctx(ctx.__class__):
59 59 def files(self):
60 60 filenames = super(lfiles_ctx, self).files()
61 61 return [re.sub('^\\'+lfutil.shortname+'/', '',
62 62 filename) for filename in filenames]
63 63 def manifest(self):
64 64 man1 = super(lfiles_ctx, self).manifest()
65 65 man1.__class__ = lfiles_manifestdict
66 66 return man1
67 67 def filectx(self, path, fileid=None, filelog=None):
68 68 try:
69 69 result = super(lfiles_ctx, self).filectx(path,
70 70 fileid, filelog)
71 71 except error.LookupError:
72 72 # Adding a null character will cause Mercurial to
73 73 # identify this as a binary file.
74 74 result = super(lfiles_ctx, self).filectx(
75 75 lfutil.shortname + '/' + path, fileid,
76 76 filelog)
77 77 olddata = result.data
78 78 result.data = lambda: olddata() + '\0'
79 79 return result
80 80 ctx.__class__ = lfiles_ctx
81 81 return ctx
82 82
83 83 # Figure out the status of big files and insert them into the
84 84 # appropriate list in the result. Also removes standin files
85 85 # from the listing. Revert to the original status if
86 86 # self.lfstatus is False.
87 87 def status(self, node1='.', node2=None, match=None, ignored=False,
88 88 clean=False, unknown=False, listsubrepos=False):
89 89 listignored, listclean, listunknown = ignored, clean, unknown
90 90 if not self.lfstatus:
91 try:
92 return super(lfiles_repo, self).status(node1, node2, match,
93 listignored, listclean, listunknown, listsubrepos)
94 except TypeError:
95 return super(lfiles_repo, self).status(node1, node2, match,
96 listignored, listclean, listunknown)
91 return super(lfiles_repo, self).status(node1, node2, match,
92 listignored, listclean, listunknown, listsubrepos)
97 93 else:
98 94 # some calls in this function rely on the old version of status
99 95 self.lfstatus = False
100 96 if isinstance(node1, context.changectx):
101 97 ctx1 = node1
102 98 else:
103 99 ctx1 = repo[node1]
104 100 if isinstance(node2, context.changectx):
105 101 ctx2 = node2
106 102 else:
107 103 ctx2 = repo[node2]
108 104 working = ctx2.rev() is None
109 105 parentworking = working and ctx1 == self['.']
110 106
111 107 def inctx(file, ctx):
112 108 try:
113 109 if ctx.rev() is None:
114 110 return file in ctx.manifest()
115 111 ctx[file]
116 112 return True
117 113 except KeyError:
118 114 return False
119 115
120 116 if match is None:
121 117 match = match_.always(self.root, self.getcwd())
122 118
123 119 # Create a copy of match that matches standins instead
124 120 # of largefiles.
125 121 def tostandin(file):
126 122 if inctx(lfutil.standin(file), ctx2):
127 123 return lfutil.standin(file)
128 124 return file
129 125
130 126 # Create a function that we can use to override what is
131 127 # normally the ignore matcher. We've already checked
132 128 # for ignored files on the first dirstate walk, and
133 129 # unecessarily re-checking here causes a huge performance
134 130 # hit because lfdirstate only knows about largefiles
135 131 def _ignoreoverride(self):
136 132 return False
137 133
138 134 m = copy.copy(match)
139 135 m._files = [tostandin(f) for f in m._files]
140 136
141 137 # Get ignored files here even if we weren't asked for them; we
142 138 # must use the result here for filtering later
143 try:
144 result = super(lfiles_repo, self).status(node1, node2, m,
145 True, clean, unknown, listsubrepos)
146 except TypeError:
147 result = super(lfiles_repo, self).status(node1, node2, m,
148 True, clean, unknown)
139 result = super(lfiles_repo, self).status(node1, node2, m,
140 True, clean, unknown, listsubrepos)
149 141 if working:
150 142 # hold the wlock while we read largefiles and
151 143 # update the lfdirstate
152 144 wlock = repo.wlock()
153 145 try:
154 146 # Any non-largefiles that were explicitly listed must be
155 147 # taken out or lfdirstate.status will report an error.
156 148 # The status of these files was already computed using
157 149 # super's status.
158 150 lfdirstate = lfutil.openlfdirstate(ui, self)
159 151 # Override lfdirstate's ignore matcher to not do
160 152 # anything
161 153 orig_ignore = lfdirstate._ignore
162 154 lfdirstate._ignore = _ignoreoverride
163 155
164 156 match._files = [f for f in match._files if f in
165 157 lfdirstate]
166 158 # Don't waste time getting the ignored and unknown
167 159 # files again; we already have them
168 160 s = lfdirstate.status(match, [], False,
169 161 listclean, False)
170 162 (unsure, modified, added, removed, missing, unknown,
171 163 ignored, clean) = s
172 164 # Replace the list of ignored and unknown files with
173 165 # the previously caclulated lists, and strip out the
174 166 # largefiles
175 167 lfiles = set(lfdirstate._map)
176 168 ignored = set(result[5]).difference(lfiles)
177 169 unknown = set(result[4]).difference(lfiles)
178 170 if parentworking:
179 171 for lfile in unsure:
180 172 if ctx1[lfutil.standin(lfile)].data().strip() \
181 173 != lfutil.hashfile(self.wjoin(lfile)):
182 174 modified.append(lfile)
183 175 else:
184 176 clean.append(lfile)
185 177 lfdirstate.normal(lfile)
186 178 lfdirstate.write()
187 179 else:
188 180 tocheck = unsure + modified + added + clean
189 181 modified, added, clean = [], [], []
190 182
191 183 for lfile in tocheck:
192 184 standin = lfutil.standin(lfile)
193 185 if inctx(standin, ctx1):
194 186 if ctx1[standin].data().strip() != \
195 187 lfutil.hashfile(self.wjoin(lfile)):
196 188 modified.append(lfile)
197 189 else:
198 190 clean.append(lfile)
199 191 else:
200 192 added.append(lfile)
201 193 # Replace the original ignore function
202 194 lfdirstate._ignore = orig_ignore
203 195 finally:
204 196 wlock.release()
205 197
206 198 for standin in ctx1.manifest():
207 199 if not lfutil.isstandin(standin):
208 200 continue
209 201 lfile = lfutil.splitstandin(standin)
210 202 if not match(lfile):
211 203 continue
212 204 if lfile not in lfdirstate:
213 205 removed.append(lfile)
214 206 # Handle unknown and ignored differently
215 207 lfiles = (modified, added, removed, missing, [], [], clean)
216 208 result = list(result)
217 209 # Unknown files
218 210 unknown = set(unknown).difference(ignored)
219 211 result[4] = [f for f in unknown
220 212 if (repo.dirstate[f] == '?' and
221 213 not lfutil.isstandin(f))]
222 214 # Ignored files were calculated earlier by the dirstate,
223 215 # and we already stripped out the largefiles from the list
224 216 result[5] = ignored
225 217 # combine normal files and largefiles
226 218 normals = [[fn for fn in filelist
227 219 if not lfutil.isstandin(fn)]
228 220 for filelist in result]
229 221 result = [sorted(list1 + list2)
230 222 for (list1, list2) in zip(normals, lfiles)]
231 223 else:
232 224 def toname(f):
233 225 if lfutil.isstandin(f):
234 226 return lfutil.splitstandin(f)
235 227 return f
236 228 result = [[toname(f) for f in items] for items in result]
237 229
238 230 if not listunknown:
239 231 result[4] = []
240 232 if not listignored:
241 233 result[5] = []
242 234 if not listclean:
243 235 result[6] = []
244 236 self.lfstatus = True
245 237 return result
246 238
247 239 # As part of committing, copy all of the largefiles into the
248 240 # cache.
249 241 def commitctx(self, *args, **kwargs):
250 242 node = super(lfiles_repo, self).commitctx(*args, **kwargs)
251 243 ctx = self[node]
252 244 for filename in ctx.files():
253 245 if lfutil.isstandin(filename) and filename in ctx.manifest():
254 246 realfile = lfutil.splitstandin(filename)
255 247 lfutil.copytostore(self, ctx.node(), realfile)
256 248
257 249 return node
258 250
259 251 # Before commit, largefile standins have not had their
260 252 # contents updated to reflect the hash of their largefile.
261 253 # Do that here.
262 254 def commit(self, text="", user=None, date=None, match=None,
263 255 force=False, editor=False, extra={}):
264 256 orig = super(lfiles_repo, self).commit
265 257
266 258 wlock = repo.wlock()
267 259 try:
268 260 if getattr(repo, "_isrebasing", False):
269 261 # We have to take the time to pull down the new
270 262 # largefiles now. Otherwise if we are rebasing,
271 263 # any largefiles that were modified in the
272 264 # destination changesets get overwritten, either
273 265 # by the rebase or in the first commit after the
274 266 # rebase.
275 267 lfcommands.updatelfiles(repo.ui, repo)
276 268 # Case 1: user calls commit with no specific files or
277 269 # include/exclude patterns: refresh and commit all files that
278 270 # are "dirty".
279 271 if ((match is None) or
280 272 (not match.anypats() and not match.files())):
281 273 # Spend a bit of time here to get a list of files we know
282 274 # are modified so we can compare only against those.
283 275 # It can cost a lot of time (several seconds)
284 276 # otherwise to update all standins if the largefiles are
285 277 # large.
286 278 lfdirstate = lfutil.openlfdirstate(ui, self)
287 279 dirtymatch = match_.always(repo.root, repo.getcwd())
288 280 s = lfdirstate.status(dirtymatch, [], False, False, False)
289 281 modifiedfiles = []
290 282 for i in s:
291 283 modifiedfiles.extend(i)
292 284 lfiles = lfutil.listlfiles(self)
293 285 # this only loops through largefiles that exist (not
294 286 # removed/renamed)
295 287 for lfile in lfiles:
296 288 if lfile in modifiedfiles:
297 289 if os.path.exists(self.wjoin(lfutil.standin(lfile))):
298 290 # this handles the case where a rebase is being
299 291 # performed and the working copy is not updated
300 292 # yet.
301 293 if os.path.exists(self.wjoin(lfile)):
302 294 lfutil.updatestandin(self,
303 295 lfutil.standin(lfile))
304 296 lfdirstate.normal(lfile)
305 297 for lfile in lfdirstate:
306 298 if lfile in modifiedfiles:
307 299 if not os.path.exists(
308 300 repo.wjoin(lfutil.standin(lfile))):
309 301 lfdirstate.drop(lfile)
310 302 lfdirstate.write()
311 303
312 304 return orig(text=text, user=user, date=date, match=match,
313 305 force=force, editor=editor, extra=extra)
314 306
315 307 for f in match.files():
316 308 if lfutil.isstandin(f):
317 309 raise util.Abort(
318 310 _('file "%s" is a largefile standin') % f,
319 311 hint=('commit the largefile itself instead'))
320 312
321 313 # Case 2: user calls commit with specified patterns: refresh
322 314 # any matching big files.
323 315 smatcher = lfutil.composestandinmatcher(self, match)
324 316 standins = lfutil.dirstate_walk(self.dirstate, smatcher)
325 317
326 318 # No matching big files: get out of the way and pass control to
327 319 # the usual commit() method.
328 320 if not standins:
329 321 return orig(text=text, user=user, date=date, match=match,
330 322 force=force, editor=editor, extra=extra)
331 323
332 324 # Refresh all matching big files. It's possible that the
333 325 # commit will end up failing, in which case the big files will
334 326 # stay refreshed. No harm done: the user modified them and
335 327 # asked to commit them, so sooner or later we're going to
336 328 # refresh the standins. Might as well leave them refreshed.
337 329 lfdirstate = lfutil.openlfdirstate(ui, self)
338 330 for standin in standins:
339 331 lfile = lfutil.splitstandin(standin)
340 332 if lfdirstate[lfile] <> 'r':
341 333 lfutil.updatestandin(self, standin)
342 334 lfdirstate.normal(lfile)
343 335 else:
344 336 lfdirstate.drop(lfile)
345 337 lfdirstate.write()
346 338
347 339 # Cook up a new matcher that only matches regular files or
348 340 # standins corresponding to the big files requested by the
349 341 # user. Have to modify _files to prevent commit() from
350 342 # complaining "not tracked" for big files.
351 343 lfiles = lfutil.listlfiles(repo)
352 344 match = copy.copy(match)
353 345 orig_matchfn = match.matchfn
354 346
355 347 # Check both the list of largefiles and the list of
356 348 # standins because if a largefile was removed, it
357 349 # won't be in the list of largefiles at this point
358 350 match._files += sorted(standins)
359 351
360 352 actualfiles = []
361 353 for f in match._files:
362 354 fstandin = lfutil.standin(f)
363 355
364 356 # ignore known largefiles and standins
365 357 if f in lfiles or fstandin in standins:
366 358 continue
367 359
368 360 # append directory separator to avoid collisions
369 361 if not fstandin.endswith(os.sep):
370 362 fstandin += os.sep
371 363
372 364 # prevalidate matching standin directories
373 365 if util.any(st for st in match._files
374 366 if st.startswith(fstandin)):
375 367 continue
376 368 actualfiles.append(f)
377 369 match._files = actualfiles
378 370
379 371 def matchfn(f):
380 372 if orig_matchfn(f):
381 373 return f not in lfiles
382 374 else:
383 375 return f in standins
384 376
385 377 match.matchfn = matchfn
386 378 return orig(text=text, user=user, date=date, match=match,
387 379 force=force, editor=editor, extra=extra)
388 380 finally:
389 381 wlock.release()
390 382
391 383 def push(self, remote, force=False, revs=None, newbranch=False):
392 384 o = lfutil.findoutgoing(repo, remote, force)
393 385 if o:
394 386 toupload = set()
395 387 o = repo.changelog.nodesbetween(o, revs)[0]
396 388 for n in o:
397 389 parents = [p for p in repo.changelog.parents(n)
398 390 if p != node.nullid]
399 391 ctx = repo[n]
400 392 files = set(ctx.files())
401 393 if len(parents) == 2:
402 394 mc = ctx.manifest()
403 395 mp1 = ctx.parents()[0].manifest()
404 396 mp2 = ctx.parents()[1].manifest()
405 397 for f in mp1:
406 398 if f not in mc:
407 399 files.add(f)
408 400 for f in mp2:
409 401 if f not in mc:
410 402 files.add(f)
411 403 for f in mc:
412 404 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f,
413 405 None):
414 406 files.add(f)
415 407
416 408 toupload = toupload.union(
417 409 set([ctx[f].data().strip()
418 410 for f in files
419 411 if lfutil.isstandin(f) and f in ctx]))
420 412 lfcommands.uploadlfiles(ui, self, remote, toupload)
421 413 return super(lfiles_repo, self).push(remote, force, revs,
422 414 newbranch)
423 415
424 416 repo.__class__ = lfiles_repo
425 417
426 418 def checkrequireslfiles(ui, repo, **kwargs):
427 419 if 'largefiles' not in repo.requirements and util.any(
428 420 lfutil.shortname+'/' in f[0] for f in repo.store.datafiles()):
429 421 repo.requirements.add('largefiles')
430 422 repo._writerequirements()
431 423
432 424 ui.setconfig('hooks', 'changegroup.lfiles', checkrequireslfiles)
433 425 ui.setconfig('hooks', 'commit.lfiles', checkrequireslfiles)
General Comments 0
You need to be logged in to leave comments. Login now