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