##// END OF EJS Templates
largefiles: tiny code clean up...
Michal Sznajder -
r15739:be552854 default
parent child Browse files
Show More
@@ -1,909 +1,909 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 if os.path.exists(repo.wjoin(lfutil.shortname)):
66 if lfutil.islfilesrepo(repo):
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 # Before starting the manifest merge, merge.updates will call
246 246 # _checkunknown to check if there are any files in the merged-in
247 247 # changeset that collide with unknown files in the working copy.
248 248 #
249 249 # The largefiles are seen as unknown, so this prevents us from merging
250 250 # in a file 'foo' if we already have a largefile with the same name.
251 251 #
252 252 # The overridden function filters the unknown files by removing any
253 253 # largefiles. This makes the merge proceed and we can then handle this
254 254 # case further in the overridden manifestmerge function below.
255 255 def override_checkunknown(origfn, wctx, mctx, folding):
256 256 origunknown = wctx.unknown()
257 257 wctx._unknown = filter(lambda f: lfutil.standin(f) not in wctx, origunknown)
258 258 try:
259 259 return origfn(wctx, mctx, folding)
260 260 finally:
261 261 wctx._unknown = origunknown
262 262
263 263 # The manifest merge handles conflicts on the manifest level. We want
264 264 # to handle changes in largefile-ness of files at this level too.
265 265 #
266 266 # The strategy is to run the original manifestmerge and then process
267 267 # the action list it outputs. There are two cases we need to deal with:
268 268 #
269 269 # 1. Normal file in p1, largefile in p2. Here the largefile is
270 270 # detected via its standin file, which will enter the working copy
271 271 # with a "get" action. It is not "merge" since the standin is all
272 272 # Mercurial is concerned with at this level -- the link to the
273 273 # existing normal file is not relevant here.
274 274 #
275 275 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
276 276 # since the largefile will be present in the working copy and
277 277 # different from the normal file in p2. Mercurial therefore
278 278 # triggers a merge action.
279 279 #
280 280 # In both cases, we prompt the user and emit new actions to either
281 281 # remove the standin (if the normal file was kept) or to remove the
282 282 # normal file and get the standin (if the largefile was kept). The
283 283 # default prompt answer is to use the largefile version since it was
284 284 # presumably changed on purpose.
285 285 #
286 286 # Finally, the merge.applyupdates function will then take care of
287 287 # writing the files into the working copy and lfcommands.updatelfiles
288 288 # will update the largefiles.
289 289 def override_manifestmerge(origfn, repo, p1, p2, pa, overwrite, partial):
290 290 actions = origfn(repo, p1, p2, pa, overwrite, partial)
291 291 processed = []
292 292
293 293 for action in actions:
294 294 if overwrite:
295 295 processed.append(action)
296 296 continue
297 297 f, m = action[:2]
298 298
299 299 choices = (_('&Largefile'), _('&Normal file'))
300 300 if m == "g" and lfutil.splitstandin(f) in p1 and f in p2:
301 301 # Case 1: normal file in the working copy, largefile in
302 302 # the second parent
303 303 lfile = lfutil.splitstandin(f)
304 304 standin = f
305 305 msg = _('%s has been turned into a largefile\n'
306 306 'use (l)argefile or keep as (n)ormal file?') % lfile
307 307 if repo.ui.promptchoice(msg, choices, 0) == 0:
308 308 processed.append((lfile, "r"))
309 309 processed.append((standin, "g", p2.flags(standin)))
310 310 else:
311 311 processed.append((standin, "r"))
312 312 elif m == "m" and lfutil.standin(f) in p1 and f in p2:
313 313 # Case 2: largefile in the working copy, normal file in
314 314 # the second parent
315 315 standin = lfutil.standin(f)
316 316 lfile = f
317 317 msg = _('%s has been turned into a normal file\n'
318 318 'keep as (l)argefile or use (n)ormal file?') % lfile
319 319 if repo.ui.promptchoice(msg, choices, 0) == 0:
320 320 processed.append((lfile, "r"))
321 321 else:
322 322 processed.append((standin, "r"))
323 323 processed.append((lfile, "g", p2.flags(lfile)))
324 324 else:
325 325 processed.append(action)
326 326
327 327 return processed
328 328
329 329 # Override filemerge to prompt the user about how they wish to merge
330 330 # largefiles. This will handle identical edits, and copy/rename +
331 331 # edit without prompting the user.
332 332 def override_filemerge(origfn, repo, mynode, orig, fcd, fco, fca):
333 333 # Use better variable names here. Because this is a wrapper we cannot
334 334 # change the variable names in the function declaration.
335 335 fcdest, fcother, fcancestor = fcd, fco, fca
336 336 if not lfutil.isstandin(orig):
337 337 return origfn(repo, mynode, orig, fcdest, fcother, fcancestor)
338 338 else:
339 339 if not fcother.cmp(fcdest): # files identical?
340 340 return None
341 341
342 342 # backwards, use working dir parent as ancestor
343 343 if fcancestor == fcother:
344 344 fcancestor = fcdest.parents()[0]
345 345
346 346 if orig != fcother.path():
347 347 repo.ui.status(_('merging %s and %s to %s\n')
348 348 % (lfutil.splitstandin(orig),
349 349 lfutil.splitstandin(fcother.path()),
350 350 lfutil.splitstandin(fcdest.path())))
351 351 else:
352 352 repo.ui.status(_('merging %s\n')
353 353 % lfutil.splitstandin(fcdest.path()))
354 354
355 355 if fcancestor.path() != fcother.path() and fcother.data() == \
356 356 fcancestor.data():
357 357 return 0
358 358 if fcancestor.path() != fcdest.path() and fcdest.data() == \
359 359 fcancestor.data():
360 360 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
361 361 return 0
362 362
363 363 if repo.ui.promptchoice(_('largefile %s has a merge conflict\n'
364 364 'keep (l)ocal or take (o)ther?') %
365 365 lfutil.splitstandin(orig),
366 366 (_('&Local'), _('&Other')), 0) == 0:
367 367 return 0
368 368 else:
369 369 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
370 370 return 0
371 371
372 372 # Copy first changes the matchers to match standins instead of
373 373 # largefiles. Then it overrides util.copyfile in that function it
374 374 # checks if the destination largefile already exists. It also keeps a
375 375 # list of copied files so that the largefiles can be copied and the
376 376 # dirstate updated.
377 377 def override_copy(orig, ui, repo, pats, opts, rename=False):
378 378 # doesn't remove largefile on rename
379 379 if len(pats) < 2:
380 380 # this isn't legal, let the original function deal with it
381 381 return orig(ui, repo, pats, opts, rename)
382 382
383 383 def makestandin(relpath):
384 384 path = scmutil.canonpath(repo.root, repo.getcwd(), relpath)
385 385 return os.path.join(repo.wjoin(lfutil.standin(path)))
386 386
387 387 fullpats = scmutil.expandpats(pats)
388 388 dest = fullpats[-1]
389 389
390 390 if os.path.isdir(dest):
391 391 if not os.path.isdir(makestandin(dest)):
392 392 os.makedirs(makestandin(dest))
393 393 # This could copy both lfiles and normal files in one command,
394 394 # but we don't want to do that. First replace their matcher to
395 395 # only match normal files and run it, then replace it to just
396 396 # match largefiles and run it again.
397 397 nonormalfiles = False
398 398 nolfiles = False
399 399 try:
400 400 try:
401 401 installnormalfilesmatchfn(repo[None].manifest())
402 402 result = orig(ui, repo, pats, opts, rename)
403 403 except util.Abort, e:
404 404 if str(e) != 'no files to copy':
405 405 raise e
406 406 else:
407 407 nonormalfiles = True
408 408 result = 0
409 409 finally:
410 410 restorematchfn()
411 411
412 412 # The first rename can cause our current working directory to be removed.
413 413 # In that case there is nothing left to copy/rename so just quit.
414 414 try:
415 415 repo.getcwd()
416 416 except OSError:
417 417 return result
418 418
419 419 try:
420 420 try:
421 421 # When we call orig below it creates the standins but we don't add them
422 422 # to the dir state until later so lock during that time.
423 423 wlock = repo.wlock()
424 424
425 425 manifest = repo[None].manifest()
426 426 oldmatch = None # for the closure
427 427 def override_match(ctx, pats=[], opts={}, globbed=False,
428 428 default='relpath'):
429 429 newpats = []
430 430 # The patterns were previously mangled to add the standin
431 431 # directory; we need to remove that now
432 432 for pat in pats:
433 433 if match_.patkind(pat) is None and lfutil.shortname in pat:
434 434 newpats.append(pat.replace(lfutil.shortname, ''))
435 435 else:
436 436 newpats.append(pat)
437 437 match = oldmatch(ctx, newpats, opts, globbed, default)
438 438 m = copy.copy(match)
439 439 lfile = lambda f: lfutil.standin(f) in manifest
440 440 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
441 441 m._fmap = set(m._files)
442 442 orig_matchfn = m.matchfn
443 443 m.matchfn = lambda f: (lfutil.isstandin(f) and
444 444 lfile(lfutil.splitstandin(f)) and
445 445 orig_matchfn(lfutil.splitstandin(f)) or
446 446 None)
447 447 return m
448 448 oldmatch = installmatchfn(override_match)
449 449 listpats = []
450 450 for pat in pats:
451 451 if match_.patkind(pat) is not None:
452 452 listpats.append(pat)
453 453 else:
454 454 listpats.append(makestandin(pat))
455 455
456 456 try:
457 457 origcopyfile = util.copyfile
458 458 copiedfiles = []
459 459 def override_copyfile(src, dest):
460 460 if (lfutil.shortname in src and
461 461 dest.startswith(repo.wjoin(lfutil.shortname))):
462 462 destlfile = dest.replace(lfutil.shortname, '')
463 463 if not opts['force'] and os.path.exists(destlfile):
464 464 raise IOError('',
465 465 _('destination largefile already exists'))
466 466 copiedfiles.append((src, dest))
467 467 origcopyfile(src, dest)
468 468
469 469 util.copyfile = override_copyfile
470 470 result += orig(ui, repo, listpats, opts, rename)
471 471 finally:
472 472 util.copyfile = origcopyfile
473 473
474 474 lfdirstate = lfutil.openlfdirstate(ui, repo)
475 475 for (src, dest) in copiedfiles:
476 476 if (lfutil.shortname in src and
477 477 dest.startswith(repo.wjoin(lfutil.shortname))):
478 478 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
479 479 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
480 480 destlfiledir = os.path.dirname(destlfile) or '.'
481 481 if not os.path.isdir(destlfiledir):
482 482 os.makedirs(destlfiledir)
483 483 if rename:
484 484 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
485 485 lfdirstate.remove(srclfile)
486 486 else:
487 487 util.copyfile(srclfile, destlfile)
488 488 lfdirstate.add(destlfile)
489 489 lfdirstate.write()
490 490 except util.Abort, e:
491 491 if str(e) != 'no files to copy':
492 492 raise e
493 493 else:
494 494 nolfiles = True
495 495 finally:
496 496 restorematchfn()
497 497 wlock.release()
498 498
499 499 if nolfiles and nonormalfiles:
500 500 raise util.Abort(_('no files to copy'))
501 501
502 502 return result
503 503
504 504 # When the user calls revert, we have to be careful to not revert any
505 505 # changes to other largefiles accidentally. This means we have to keep
506 506 # track of the largefiles that are being reverted so we only pull down
507 507 # the necessary largefiles.
508 508 #
509 509 # Standins are only updated (to match the hash of largefiles) before
510 510 # commits. Update the standins then run the original revert, changing
511 511 # the matcher to hit standins instead of largefiles. Based on the
512 512 # resulting standins update the largefiles. Then return the standins
513 513 # to their proper state
514 514 def override_revert(orig, ui, repo, *pats, **opts):
515 515 # Because we put the standins in a bad state (by updating them)
516 516 # and then return them to a correct state we need to lock to
517 517 # prevent others from changing them in their incorrect state.
518 518 wlock = repo.wlock()
519 519 try:
520 520 lfdirstate = lfutil.openlfdirstate(ui, repo)
521 521 (modified, added, removed, missing, unknown, ignored, clean) = \
522 522 lfutil.lfdirstate_status(lfdirstate, repo, repo['.'].rev())
523 523 for lfile in modified:
524 524 lfutil.updatestandin(repo, lfutil.standin(lfile))
525 525
526 526 try:
527 527 ctx = repo[opts.get('rev')]
528 528 oldmatch = None # for the closure
529 529 def override_match(ctx, pats=[], opts={}, globbed=False,
530 530 default='relpath'):
531 531 match = oldmatch(ctx, pats, opts, globbed, default)
532 532 m = copy.copy(match)
533 533 def tostandin(f):
534 534 if lfutil.standin(f) in ctx or lfutil.standin(f) in ctx:
535 535 return lfutil.standin(f)
536 536 elif lfutil.standin(f) in repo[None]:
537 537 return None
538 538 return f
539 539 m._files = [tostandin(f) for f in m._files]
540 540 m._files = [f for f in m._files if f is not None]
541 541 m._fmap = set(m._files)
542 542 orig_matchfn = m.matchfn
543 543 def matchfn(f):
544 544 if lfutil.isstandin(f):
545 545 # We need to keep track of what largefiles are being
546 546 # matched so we know which ones to update later --
547 547 # otherwise we accidentally revert changes to other
548 548 # largefiles. This is repo-specific, so duckpunch the
549 549 # repo object to keep the list of largefiles for us
550 550 # later.
551 551 if orig_matchfn(lfutil.splitstandin(f)) and \
552 552 (f in repo[None] or f in ctx):
553 553 lfileslist = getattr(repo, '_lfilestoupdate', [])
554 554 lfileslist.append(lfutil.splitstandin(f))
555 555 repo._lfilestoupdate = lfileslist
556 556 return True
557 557 else:
558 558 return False
559 559 return orig_matchfn(f)
560 560 m.matchfn = matchfn
561 561 return m
562 562 oldmatch = installmatchfn(override_match)
563 563 scmutil.match
564 564 matches = override_match(repo[None], pats, opts)
565 565 orig(ui, repo, *pats, **opts)
566 566 finally:
567 567 restorematchfn()
568 568 lfileslist = getattr(repo, '_lfilestoupdate', [])
569 569 lfcommands.updatelfiles(ui, repo, filelist=lfileslist,
570 570 printmessage=False)
571 571
572 572 # empty out the largefiles list so we start fresh next time
573 573 repo._lfilestoupdate = []
574 574 for lfile in modified:
575 575 if lfile in lfileslist:
576 576 if os.path.exists(repo.wjoin(lfutil.standin(lfile))) and lfile\
577 577 in repo['.']:
578 578 lfutil.writestandin(repo, lfutil.standin(lfile),
579 579 repo['.'][lfile].data().strip(),
580 580 'x' in repo['.'][lfile].flags())
581 581 lfdirstate = lfutil.openlfdirstate(ui, repo)
582 582 for lfile in added:
583 583 standin = lfutil.standin(lfile)
584 584 if standin not in ctx and (standin in matches or opts.get('all')):
585 585 if lfile in lfdirstate:
586 586 lfdirstate.drop(lfile)
587 587 util.unlinkpath(repo.wjoin(standin))
588 588 lfdirstate.write()
589 589 finally:
590 590 wlock.release()
591 591
592 592 def hg_update(orig, repo, node):
593 593 result = orig(repo, node)
594 594 # XXX check if it worked first
595 595 lfcommands.updatelfiles(repo.ui, repo)
596 596 return result
597 597
598 598 def hg_clean(orig, repo, node, show_stats=True):
599 599 result = orig(repo, node, show_stats)
600 600 lfcommands.updatelfiles(repo.ui, repo)
601 601 return result
602 602
603 603 def hg_merge(orig, repo, node, force=None, remind=True):
604 604 result = orig(repo, node, force, remind)
605 605 lfcommands.updatelfiles(repo.ui, repo)
606 606 return result
607 607
608 608 # When we rebase a repository with remotely changed largefiles, we need to
609 609 # take some extra care so that the largefiles are correctly updated in the
610 610 # working copy
611 611 def override_pull(orig, ui, repo, source=None, **opts):
612 612 if opts.get('rebase', False):
613 613 repo._isrebasing = True
614 614 try:
615 615 if opts.get('update'):
616 616 del opts['update']
617 617 ui.debug('--update and --rebase are not compatible, ignoring '
618 618 'the update flag\n')
619 619 del opts['rebase']
620 620 cmdutil.bailifchanged(repo)
621 621 revsprepull = len(repo)
622 622 origpostincoming = commands.postincoming
623 623 def _dummy(*args, **kwargs):
624 624 pass
625 625 commands.postincoming = _dummy
626 626 repo.lfpullsource = source
627 627 if not source:
628 628 source = 'default'
629 629 try:
630 630 result = commands.pull(ui, repo, source, **opts)
631 631 finally:
632 632 commands.postincoming = origpostincoming
633 633 revspostpull = len(repo)
634 634 if revspostpull > revsprepull:
635 635 result = result or rebase.rebase(ui, repo)
636 636 finally:
637 637 repo._isrebasing = False
638 638 else:
639 639 repo.lfpullsource = source
640 640 if not source:
641 641 source = 'default'
642 642 result = orig(ui, repo, source, **opts)
643 643 return result
644 644
645 645 def override_rebase(orig, ui, repo, **opts):
646 646 repo._isrebasing = True
647 647 try:
648 648 orig(ui, repo, **opts)
649 649 finally:
650 650 repo._isrebasing = False
651 651
652 652 def override_archive(orig, repo, dest, node, kind, decode=True, matchfn=None,
653 653 prefix=None, mtime=None, subrepos=None):
654 654 # No need to lock because we are only reading history and
655 655 # largefile caches, neither of which are modified.
656 656 lfcommands.cachelfiles(repo.ui, repo, node)
657 657
658 658 if kind not in archival.archivers:
659 659 raise util.Abort(_("unknown archive type '%s'") % kind)
660 660
661 661 ctx = repo[node]
662 662
663 663 if kind == 'files':
664 664 if prefix:
665 665 raise util.Abort(
666 666 _('cannot give prefix when archiving to files'))
667 667 else:
668 668 prefix = archival.tidyprefix(dest, kind, prefix)
669 669
670 670 def write(name, mode, islink, getdata):
671 671 if matchfn and not matchfn(name):
672 672 return
673 673 data = getdata()
674 674 if decode:
675 675 data = repo.wwritedata(name, data)
676 676 archiver.addfile(prefix + name, mode, islink, data)
677 677
678 678 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
679 679
680 680 if repo.ui.configbool("ui", "archivemeta", True):
681 681 def metadata():
682 682 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
683 683 hex(repo.changelog.node(0)), hex(node), ctx.branch())
684 684
685 685 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
686 686 if repo.tagtype(t) == 'global')
687 687 if not tags:
688 688 repo.ui.pushbuffer()
689 689 opts = {'template': '{latesttag}\n{latesttagdistance}',
690 690 'style': '', 'patch': None, 'git': None}
691 691 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
692 692 ltags, dist = repo.ui.popbuffer().split('\n')
693 693 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
694 694 tags += 'latesttagdistance: %s\n' % dist
695 695
696 696 return base + tags
697 697
698 698 write('.hg_archival.txt', 0644, False, metadata)
699 699
700 700 for f in ctx:
701 701 ff = ctx.flags(f)
702 702 getdata = ctx[f].data
703 703 if lfutil.isstandin(f):
704 704 path = lfutil.findfile(repo, getdata().strip())
705 705 f = lfutil.splitstandin(f)
706 706
707 707 def getdatafn():
708 708 fd = None
709 709 try:
710 710 fd = open(path, 'rb')
711 711 return fd.read()
712 712 finally:
713 713 if fd:
714 714 fd.close()
715 715
716 716 getdata = getdatafn
717 717 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
718 718
719 719 if subrepos:
720 720 for subpath in ctx.substate:
721 721 sub = ctx.sub(subpath)
722 722 sub.archive(repo.ui, archiver, prefix)
723 723
724 724 archiver.done()
725 725
726 726 # If a largefile is modified, the change is not reflected in its
727 727 # standin until a commit. cmdutil.bailifchanged() raises an exception
728 728 # if the repo has uncommitted changes. Wrap it to also check if
729 729 # largefiles were changed. This is used by bisect and backout.
730 730 def override_bailifchanged(orig, repo):
731 731 orig(repo)
732 732 repo.lfstatus = True
733 733 modified, added, removed, deleted = repo.status()[:4]
734 734 repo.lfstatus = False
735 735 if modified or added or removed or deleted:
736 736 raise util.Abort(_('outstanding uncommitted changes'))
737 737
738 738 # Fetch doesn't use cmdutil.bail_if_changed so override it to add the check
739 739 def override_fetch(orig, ui, repo, *pats, **opts):
740 740 repo.lfstatus = True
741 741 modified, added, removed, deleted = repo.status()[:4]
742 742 repo.lfstatus = False
743 743 if modified or added or removed or deleted:
744 744 raise util.Abort(_('outstanding uncommitted changes'))
745 745 return orig(ui, repo, *pats, **opts)
746 746
747 747 def override_forget(orig, ui, repo, *pats, **opts):
748 748 installnormalfilesmatchfn(repo[None].manifest())
749 749 orig(ui, repo, *pats, **opts)
750 750 restorematchfn()
751 751 m = scmutil.match(repo[None], pats, opts)
752 752
753 753 try:
754 754 repo.lfstatus = True
755 755 s = repo.status(match=m, clean=True)
756 756 finally:
757 757 repo.lfstatus = False
758 758 forget = sorted(s[0] + s[1] + s[3] + s[6])
759 759 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
760 760
761 761 for f in forget:
762 762 if lfutil.standin(f) not in repo.dirstate and not \
763 763 os.path.isdir(m.rel(lfutil.standin(f))):
764 764 ui.warn(_('not removing %s: file is already untracked\n')
765 765 % m.rel(f))
766 766
767 767 for f in forget:
768 768 if ui.verbose or not m.exact(f):
769 769 ui.status(_('removing %s\n') % m.rel(f))
770 770
771 771 # Need to lock because standin files are deleted then removed from the
772 772 # repository and we could race inbetween.
773 773 wlock = repo.wlock()
774 774 try:
775 775 lfdirstate = lfutil.openlfdirstate(ui, repo)
776 776 for f in forget:
777 777 if lfdirstate[f] == 'a':
778 778 lfdirstate.drop(f)
779 779 else:
780 780 lfdirstate.remove(f)
781 781 lfdirstate.write()
782 782 lfutil.repo_remove(repo, [lfutil.standin(f) for f in forget],
783 783 unlink=True)
784 784 finally:
785 785 wlock.release()
786 786
787 787 def getoutgoinglfiles(ui, repo, dest=None, **opts):
788 788 dest = ui.expandpath(dest or 'default-push', dest or 'default')
789 789 dest, branches = hg.parseurl(dest, opts.get('branch'))
790 790 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
791 791 if revs:
792 792 revs = [repo.lookup(rev) for rev in revs]
793 793
794 794 remoteui = hg.remoteui
795 795
796 796 try:
797 797 remote = hg.repository(remoteui(repo, opts), dest)
798 798 except error.RepoError:
799 799 return None
800 800 o = lfutil.findoutgoing(repo, remote, False)
801 801 if not o:
802 802 return None
803 803 o = repo.changelog.nodesbetween(o, revs)[0]
804 804 if opts.get('newest_first'):
805 805 o.reverse()
806 806
807 807 toupload = set()
808 808 for n in o:
809 809 parents = [p for p in repo.changelog.parents(n) if p != node.nullid]
810 810 ctx = repo[n]
811 811 files = set(ctx.files())
812 812 if len(parents) == 2:
813 813 mc = ctx.manifest()
814 814 mp1 = ctx.parents()[0].manifest()
815 815 mp2 = ctx.parents()[1].manifest()
816 816 for f in mp1:
817 817 if f not in mc:
818 818 files.add(f)
819 819 for f in mp2:
820 820 if f not in mc:
821 821 files.add(f)
822 822 for f in mc:
823 823 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None):
824 824 files.add(f)
825 825 toupload = toupload.union(
826 826 set([f for f in files if lfutil.isstandin(f) and f in ctx]))
827 827 return toupload
828 828
829 829 def override_outgoing(orig, ui, repo, dest=None, **opts):
830 830 orig(ui, repo, dest, **opts)
831 831
832 832 if opts.pop('large', None):
833 833 toupload = getoutgoinglfiles(ui, repo, dest, **opts)
834 834 if toupload is None:
835 835 ui.status(_('largefiles: No remote repo\n'))
836 836 else:
837 837 ui.status(_('largefiles to upload:\n'))
838 838 for file in toupload:
839 839 ui.status(lfutil.splitstandin(file) + '\n')
840 840 ui.status('\n')
841 841
842 842 def override_summary(orig, ui, repo, *pats, **opts):
843 843 orig(ui, repo, *pats, **opts)
844 844
845 845 if opts.pop('large', None):
846 846 toupload = getoutgoinglfiles(ui, repo, None, **opts)
847 847 if toupload is None:
848 848 ui.status(_('largefiles: No remote repo\n'))
849 849 else:
850 850 ui.status(_('largefiles: %d to upload\n') % len(toupload))
851 851
852 852 def override_addremove(orig, ui, repo, *pats, **opts):
853 853 # Check if the parent or child has largefiles; if so, disallow
854 854 # addremove. If there is a symlink in the manifest then getting
855 855 # the manifest throws an exception: catch it and let addremove
856 856 # deal with it.
857 857 try:
858 858 manifesttip = set(repo['tip'].manifest())
859 859 except util.Abort:
860 860 manifesttip = set()
861 861 try:
862 862 manifestworking = set(repo[None].manifest())
863 863 except util.Abort:
864 864 manifestworking = set()
865 865
866 866 # Manifests are only iterable so turn them into sets then union
867 867 for file in manifesttip.union(manifestworking):
868 868 if file.startswith(lfutil.shortname):
869 869 raise util.Abort(
870 870 _('addremove cannot be run on a repo with largefiles'))
871 871
872 872 return orig(ui, repo, *pats, **opts)
873 873
874 874 # Calling purge with --all will cause the largefiles to be deleted.
875 875 # Override repo.status to prevent this from happening.
876 876 def override_purge(orig, ui, repo, *dirs, **opts):
877 877 oldstatus = repo.status
878 878 def override_status(node1='.', node2=None, match=None, ignored=False,
879 879 clean=False, unknown=False, listsubrepos=False):
880 880 r = oldstatus(node1, node2, match, ignored, clean, unknown,
881 881 listsubrepos)
882 882 lfdirstate = lfutil.openlfdirstate(ui, repo)
883 883 modified, added, removed, deleted, unknown, ignored, clean = r
884 884 unknown = [f for f in unknown if lfdirstate[f] == '?']
885 885 ignored = [f for f in ignored if lfdirstate[f] == '?']
886 886 return modified, added, removed, deleted, unknown, ignored, clean
887 887 repo.status = override_status
888 888 orig(ui, repo, *dirs, **opts)
889 889 repo.status = oldstatus
890 890
891 891 def override_rollback(orig, ui, repo, **opts):
892 892 result = orig(ui, repo, **opts)
893 893 merge.update(repo, node=None, branchmerge=False, force=True,
894 894 partial=lfutil.isstandin)
895 895 lfdirstate = lfutil.openlfdirstate(ui, repo)
896 896 lfiles = lfutil.listlfiles(repo)
897 897 oldlfiles = lfutil.listlfiles(repo, repo[None].parents()[0].rev())
898 898 for file in lfiles:
899 899 if file in oldlfiles:
900 900 lfdirstate.normallookup(file)
901 901 else:
902 902 lfdirstate.add(file)
903 903 lfdirstate.write()
904 904 return result
905 905
906 906 def override_transplant(orig, ui, repo, *revs, **opts):
907 907 result = orig(ui, repo, *revs, **opts)
908 908 lfcommands.updatelfiles(repo.ui, repo)
909 909 return result
General Comments 0
You need to be logged in to leave comments. Login now