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