##// END OF EJS Templates
largefiles: hide .hglf/ prefix for largefiles in hgweb...
Martin Geisler -
r16449:874a680a default
parent child Browse files
Show More
@@ -1,975 +1,980 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 # -- Utility functions: commonly/repeatedly needed functionality ---------------
24 24
25 25 def installnormalfilesmatchfn(manifest):
26 26 '''overrides scmutil.match so that the matcher it returns will ignore all
27 27 largefiles'''
28 28 oldmatch = None # for the closure
29 29 def overridematch(ctx, pats=[], opts={}, globbed=False,
30 30 default='relpath'):
31 31 match = oldmatch(ctx, pats, opts, globbed, default)
32 32 m = copy.copy(match)
33 33 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
34 34 manifest)
35 35 m._files = filter(notlfile, m._files)
36 36 m._fmap = set(m._files)
37 37 origmatchfn = m.matchfn
38 38 m.matchfn = lambda f: notlfile(f) and origmatchfn(f) or None
39 39 return m
40 40 oldmatch = installmatchfn(overridematch)
41 41
42 42 def installmatchfn(f):
43 43 oldmatch = scmutil.match
44 44 setattr(f, 'oldmatch', oldmatch)
45 45 scmutil.match = f
46 46 return oldmatch
47 47
48 48 def restorematchfn():
49 49 '''restores scmutil.match to what it was before installnormalfilesmatchfn
50 50 was called. no-op if scmutil.match is its original function.
51 51
52 52 Note that n calls to installnormalfilesmatchfn will require n calls to
53 53 restore matchfn to reverse'''
54 54 scmutil.match = getattr(scmutil.match, 'oldmatch', scmutil.match)
55 55
56 56 def addlargefiles(ui, repo, *pats, **opts):
57 57 large = opts.pop('large', None)
58 58 lfsize = lfutil.getminsize(
59 59 ui, lfutil.islfilesrepo(repo), opts.pop('lfsize', None))
60 60
61 61 lfmatcher = None
62 62 if lfutil.islfilesrepo(repo):
63 63 lfpats = ui.configlist(lfutil.longname, 'patterns', default=[])
64 64 if lfpats:
65 65 lfmatcher = match_.match(repo.root, '', list(lfpats))
66 66
67 67 lfnames = []
68 68 m = scmutil.match(repo[None], pats, opts)
69 69 m.bad = lambda x, y: None
70 70 wctx = repo[None]
71 71 for f in repo.walk(m):
72 72 exact = m.exact(f)
73 73 lfile = lfutil.standin(f) in wctx
74 74 nfile = f in wctx
75 75 exists = lfile or nfile
76 76
77 77 # Don't warn the user when they attempt to add a normal tracked file.
78 78 # The normal add code will do that for us.
79 79 if exact and exists:
80 80 if lfile:
81 81 ui.warn(_('%s already a largefile\n') % f)
82 82 continue
83 83
84 84 if exact or not exists:
85 85 abovemin = (lfsize and
86 86 os.lstat(repo.wjoin(f)).st_size >= lfsize * 1024 * 1024)
87 87 if large or abovemin or (lfmatcher and lfmatcher(f)):
88 88 lfnames.append(f)
89 89 if ui.verbose or not exact:
90 90 ui.status(_('adding %s as a largefile\n') % m.rel(f))
91 91
92 92 bad = []
93 93 standins = []
94 94
95 95 # Need to lock, otherwise there could be a race condition between
96 96 # when standins are created and added to the repo.
97 97 wlock = repo.wlock()
98 98 try:
99 99 if not opts.get('dry_run'):
100 100 lfdirstate = lfutil.openlfdirstate(ui, repo)
101 101 for f in lfnames:
102 102 standinname = lfutil.standin(f)
103 103 lfutil.writestandin(repo, standinname, hash='',
104 104 executable=lfutil.getexecutable(repo.wjoin(f)))
105 105 standins.append(standinname)
106 106 if lfdirstate[f] == 'r':
107 107 lfdirstate.normallookup(f)
108 108 else:
109 109 lfdirstate.add(f)
110 110 lfdirstate.write()
111 111 bad += [lfutil.splitstandin(f)
112 112 for f in lfutil.repoadd(repo, standins)
113 113 if f in m.files()]
114 114 finally:
115 115 wlock.release()
116 116 return bad
117 117
118 118 def removelargefiles(ui, repo, *pats, **opts):
119 119 after = opts.get('after')
120 120 if not pats and not after:
121 121 raise util.Abort(_('no files specified'))
122 122 m = scmutil.match(repo[None], pats, opts)
123 123 try:
124 124 repo.lfstatus = True
125 125 s = repo.status(match=m, clean=True)
126 126 finally:
127 127 repo.lfstatus = False
128 128 manifest = repo[None].manifest()
129 129 modified, added, deleted, clean = [[f for f in list
130 130 if lfutil.standin(f) in manifest]
131 131 for list in [s[0], s[1], s[3], s[6]]]
132 132
133 133 def warn(files, reason):
134 134 for f in files:
135 135 ui.warn(_('not removing %s: %s (use forget to undo)\n')
136 136 % (m.rel(f), reason))
137 137
138 138 if after:
139 139 remove, forget = deleted, []
140 140 warn(modified + added + clean, _('file still exists'))
141 141 else:
142 142 remove, forget = deleted + clean, []
143 143 warn(modified, _('file is modified'))
144 144 warn(added, _('file has been marked for add'))
145 145
146 146 for f in sorted(remove + forget):
147 147 if ui.verbose or not m.exact(f):
148 148 ui.status(_('removing %s\n') % m.rel(f))
149 149
150 150 # Need to lock because standin files are deleted then removed from the
151 151 # repository and we could race inbetween.
152 152 wlock = repo.wlock()
153 153 try:
154 154 lfdirstate = lfutil.openlfdirstate(ui, repo)
155 155 for f in remove:
156 156 if not after:
157 157 # If this is being called by addremove, notify the user that we
158 158 # are removing the file.
159 159 if getattr(repo, "_isaddremove", False):
160 160 ui.status(_('removing %s\n') % f)
161 161 if os.path.exists(repo.wjoin(f)):
162 162 util.unlinkpath(repo.wjoin(f))
163 163 lfdirstate.remove(f)
164 164 lfdirstate.write()
165 165 forget = [lfutil.standin(f) for f in forget]
166 166 remove = [lfutil.standin(f) for f in remove]
167 167 lfutil.repoforget(repo, forget)
168 168 # If this is being called by addremove, let the original addremove
169 169 # function handle this.
170 170 if not getattr(repo, "_isaddremove", False):
171 171 lfutil.reporemove(repo, remove, unlink=True)
172 172 finally:
173 173 wlock.release()
174 174
175 # For overriding mercurial.hgweb.webcommands so that largefiles will
176 # appear at their right place in the manifests.
177 def decodepath(orig, path):
178 return lfutil.splitstandin(path) or path
179
175 180 # -- Wrappers: modify existing commands --------------------------------
176 181
177 182 # Add works by going through the files that the user wanted to add and
178 183 # checking if they should be added as largefiles. Then it makes a new
179 184 # matcher which matches only the normal files and runs the original
180 185 # version of add.
181 186 def overrideadd(orig, ui, repo, *pats, **opts):
182 187 normal = opts.pop('normal')
183 188 if normal:
184 189 if opts.get('large'):
185 190 raise util.Abort(_('--normal cannot be used with --large'))
186 191 return orig(ui, repo, *pats, **opts)
187 192 bad = addlargefiles(ui, repo, *pats, **opts)
188 193 installnormalfilesmatchfn(repo[None].manifest())
189 194 result = orig(ui, repo, *pats, **opts)
190 195 restorematchfn()
191 196
192 197 return (result == 1 or bad) and 1 or 0
193 198
194 199 def overrideremove(orig, ui, repo, *pats, **opts):
195 200 installnormalfilesmatchfn(repo[None].manifest())
196 201 orig(ui, repo, *pats, **opts)
197 202 restorematchfn()
198 203 removelargefiles(ui, repo, *pats, **opts)
199 204
200 205 def overridestatus(orig, ui, repo, *pats, **opts):
201 206 try:
202 207 repo.lfstatus = True
203 208 return orig(ui, repo, *pats, **opts)
204 209 finally:
205 210 repo.lfstatus = False
206 211
207 212 def overridelog(orig, ui, repo, *pats, **opts):
208 213 try:
209 214 repo.lfstatus = True
210 215 orig(ui, repo, *pats, **opts)
211 216 finally:
212 217 repo.lfstatus = False
213 218
214 219 def overrideverify(orig, ui, repo, *pats, **opts):
215 220 large = opts.pop('large', False)
216 221 all = opts.pop('lfa', False)
217 222 contents = opts.pop('lfc', False)
218 223
219 224 result = orig(ui, repo, *pats, **opts)
220 225 if large:
221 226 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
222 227 return result
223 228
224 229 # Override needs to refresh standins so that update's normal merge
225 230 # will go through properly. Then the other update hook (overriding repo.update)
226 231 # will get the new files. Filemerge is also overriden so that the merge
227 232 # will merge standins correctly.
228 233 def overrideupdate(orig, ui, repo, *pats, **opts):
229 234 lfdirstate = lfutil.openlfdirstate(ui, repo)
230 235 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
231 236 False, False)
232 237 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
233 238
234 239 # Need to lock between the standins getting updated and their
235 240 # largefiles getting updated
236 241 wlock = repo.wlock()
237 242 try:
238 243 if opts['check']:
239 244 mod = len(modified) > 0
240 245 for lfile in unsure:
241 246 standin = lfutil.standin(lfile)
242 247 if repo['.'][standin].data().strip() != \
243 248 lfutil.hashfile(repo.wjoin(lfile)):
244 249 mod = True
245 250 else:
246 251 lfdirstate.normal(lfile)
247 252 lfdirstate.write()
248 253 if mod:
249 254 raise util.Abort(_('uncommitted local changes'))
250 255 # XXX handle removed differently
251 256 if not opts['clean']:
252 257 for lfile in unsure + modified + added:
253 258 lfutil.updatestandin(repo, lfutil.standin(lfile))
254 259 finally:
255 260 wlock.release()
256 261 return orig(ui, repo, *pats, **opts)
257 262
258 263 # Before starting the manifest merge, merge.updates will call
259 264 # _checkunknown to check if there are any files in the merged-in
260 265 # changeset that collide with unknown files in the working copy.
261 266 #
262 267 # The largefiles are seen as unknown, so this prevents us from merging
263 268 # in a file 'foo' if we already have a largefile with the same name.
264 269 #
265 270 # The overridden function filters the unknown files by removing any
266 271 # largefiles. This makes the merge proceed and we can then handle this
267 272 # case further in the overridden manifestmerge function below.
268 273 def overridecheckunknownfile(origfn, repo, wctx, mctx, f):
269 274 if lfutil.standin(f) in wctx:
270 275 return False
271 276 return origfn(repo, wctx, mctx, f)
272 277
273 278 # The manifest merge handles conflicts on the manifest level. We want
274 279 # to handle changes in largefile-ness of files at this level too.
275 280 #
276 281 # The strategy is to run the original manifestmerge and then process
277 282 # the action list it outputs. There are two cases we need to deal with:
278 283 #
279 284 # 1. Normal file in p1, largefile in p2. Here the largefile is
280 285 # detected via its standin file, which will enter the working copy
281 286 # with a "get" action. It is not "merge" since the standin is all
282 287 # Mercurial is concerned with at this level -- the link to the
283 288 # existing normal file is not relevant here.
284 289 #
285 290 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
286 291 # since the largefile will be present in the working copy and
287 292 # different from the normal file in p2. Mercurial therefore
288 293 # triggers a merge action.
289 294 #
290 295 # In both cases, we prompt the user and emit new actions to either
291 296 # remove the standin (if the normal file was kept) or to remove the
292 297 # normal file and get the standin (if the largefile was kept). The
293 298 # default prompt answer is to use the largefile version since it was
294 299 # presumably changed on purpose.
295 300 #
296 301 # Finally, the merge.applyupdates function will then take care of
297 302 # writing the files into the working copy and lfcommands.updatelfiles
298 303 # will update the largefiles.
299 304 def overridemanifestmerge(origfn, repo, p1, p2, pa, overwrite, partial):
300 305 actions = origfn(repo, p1, p2, pa, overwrite, partial)
301 306 processed = []
302 307
303 308 for action in actions:
304 309 if overwrite:
305 310 processed.append(action)
306 311 continue
307 312 f, m = action[:2]
308 313
309 314 choices = (_('&Largefile'), _('&Normal file'))
310 315 if m == "g" and lfutil.splitstandin(f) in p1 and f in p2:
311 316 # Case 1: normal file in the working copy, largefile in
312 317 # the second parent
313 318 lfile = lfutil.splitstandin(f)
314 319 standin = f
315 320 msg = _('%s has been turned into a largefile\n'
316 321 'use (l)argefile or keep as (n)ormal file?') % lfile
317 322 if repo.ui.promptchoice(msg, choices, 0) == 0:
318 323 processed.append((lfile, "r"))
319 324 processed.append((standin, "g", p2.flags(standin)))
320 325 else:
321 326 processed.append((standin, "r"))
322 327 elif m == "g" and lfutil.standin(f) in p1 and f in p2:
323 328 # Case 2: largefile in the working copy, normal file in
324 329 # the second parent
325 330 standin = lfutil.standin(f)
326 331 lfile = f
327 332 msg = _('%s has been turned into a normal file\n'
328 333 'keep as (l)argefile or use (n)ormal file?') % lfile
329 334 if repo.ui.promptchoice(msg, choices, 0) == 0:
330 335 processed.append((lfile, "r"))
331 336 else:
332 337 processed.append((standin, "r"))
333 338 processed.append((lfile, "g", p2.flags(lfile)))
334 339 else:
335 340 processed.append(action)
336 341
337 342 return processed
338 343
339 344 # Override filemerge to prompt the user about how they wish to merge
340 345 # largefiles. This will handle identical edits, and copy/rename +
341 346 # edit without prompting the user.
342 347 def overridefilemerge(origfn, repo, mynode, orig, fcd, fco, fca):
343 348 # Use better variable names here. Because this is a wrapper we cannot
344 349 # change the variable names in the function declaration.
345 350 fcdest, fcother, fcancestor = fcd, fco, fca
346 351 if not lfutil.isstandin(orig):
347 352 return origfn(repo, mynode, orig, fcdest, fcother, fcancestor)
348 353 else:
349 354 if not fcother.cmp(fcdest): # files identical?
350 355 return None
351 356
352 357 # backwards, use working dir parent as ancestor
353 358 if fcancestor == fcother:
354 359 fcancestor = fcdest.parents()[0]
355 360
356 361 if orig != fcother.path():
357 362 repo.ui.status(_('merging %s and %s to %s\n')
358 363 % (lfutil.splitstandin(orig),
359 364 lfutil.splitstandin(fcother.path()),
360 365 lfutil.splitstandin(fcdest.path())))
361 366 else:
362 367 repo.ui.status(_('merging %s\n')
363 368 % lfutil.splitstandin(fcdest.path()))
364 369
365 370 if fcancestor.path() != fcother.path() and fcother.data() == \
366 371 fcancestor.data():
367 372 return 0
368 373 if fcancestor.path() != fcdest.path() and fcdest.data() == \
369 374 fcancestor.data():
370 375 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
371 376 return 0
372 377
373 378 if repo.ui.promptchoice(_('largefile %s has a merge conflict\n'
374 379 'keep (l)ocal or take (o)ther?') %
375 380 lfutil.splitstandin(orig),
376 381 (_('&Local'), _('&Other')), 0) == 0:
377 382 return 0
378 383 else:
379 384 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
380 385 return 0
381 386
382 387 # Copy first changes the matchers to match standins instead of
383 388 # largefiles. Then it overrides util.copyfile in that function it
384 389 # checks if the destination largefile already exists. It also keeps a
385 390 # list of copied files so that the largefiles can be copied and the
386 391 # dirstate updated.
387 392 def overridecopy(orig, ui, repo, pats, opts, rename=False):
388 393 # doesn't remove largefile on rename
389 394 if len(pats) < 2:
390 395 # this isn't legal, let the original function deal with it
391 396 return orig(ui, repo, pats, opts, rename)
392 397
393 398 def makestandin(relpath):
394 399 path = scmutil.canonpath(repo.root, repo.getcwd(), relpath)
395 400 return os.path.join(repo.wjoin(lfutil.standin(path)))
396 401
397 402 fullpats = scmutil.expandpats(pats)
398 403 dest = fullpats[-1]
399 404
400 405 if os.path.isdir(dest):
401 406 if not os.path.isdir(makestandin(dest)):
402 407 os.makedirs(makestandin(dest))
403 408 # This could copy both lfiles and normal files in one command,
404 409 # but we don't want to do that. First replace their matcher to
405 410 # only match normal files and run it, then replace it to just
406 411 # match largefiles and run it again.
407 412 nonormalfiles = False
408 413 nolfiles = False
409 414 try:
410 415 try:
411 416 installnormalfilesmatchfn(repo[None].manifest())
412 417 result = orig(ui, repo, pats, opts, rename)
413 418 except util.Abort, e:
414 419 if str(e) != 'no files to copy':
415 420 raise e
416 421 else:
417 422 nonormalfiles = True
418 423 result = 0
419 424 finally:
420 425 restorematchfn()
421 426
422 427 # The first rename can cause our current working directory to be removed.
423 428 # In that case there is nothing left to copy/rename so just quit.
424 429 try:
425 430 repo.getcwd()
426 431 except OSError:
427 432 return result
428 433
429 434 try:
430 435 try:
431 436 # When we call orig below it creates the standins but we don't add
432 437 # them to the dir state until later so lock during that time.
433 438 wlock = repo.wlock()
434 439
435 440 manifest = repo[None].manifest()
436 441 oldmatch = None # for the closure
437 442 def overridematch(ctx, pats=[], opts={}, globbed=False,
438 443 default='relpath'):
439 444 newpats = []
440 445 # The patterns were previously mangled to add the standin
441 446 # directory; we need to remove that now
442 447 for pat in pats:
443 448 if match_.patkind(pat) is None and lfutil.shortname in pat:
444 449 newpats.append(pat.replace(lfutil.shortname, ''))
445 450 else:
446 451 newpats.append(pat)
447 452 match = oldmatch(ctx, newpats, opts, globbed, default)
448 453 m = copy.copy(match)
449 454 lfile = lambda f: lfutil.standin(f) in manifest
450 455 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
451 456 m._fmap = set(m._files)
452 457 origmatchfn = m.matchfn
453 458 m.matchfn = lambda f: (lfutil.isstandin(f) and
454 459 (f in manifest) and
455 460 origmatchfn(lfutil.splitstandin(f)) or
456 461 None)
457 462 return m
458 463 oldmatch = installmatchfn(overridematch)
459 464 listpats = []
460 465 for pat in pats:
461 466 if match_.patkind(pat) is not None:
462 467 listpats.append(pat)
463 468 else:
464 469 listpats.append(makestandin(pat))
465 470
466 471 try:
467 472 origcopyfile = util.copyfile
468 473 copiedfiles = []
469 474 def overridecopyfile(src, dest):
470 475 if (lfutil.shortname in src and
471 476 dest.startswith(repo.wjoin(lfutil.shortname))):
472 477 destlfile = dest.replace(lfutil.shortname, '')
473 478 if not opts['force'] and os.path.exists(destlfile):
474 479 raise IOError('',
475 480 _('destination largefile already exists'))
476 481 copiedfiles.append((src, dest))
477 482 origcopyfile(src, dest)
478 483
479 484 util.copyfile = overridecopyfile
480 485 result += orig(ui, repo, listpats, opts, rename)
481 486 finally:
482 487 util.copyfile = origcopyfile
483 488
484 489 lfdirstate = lfutil.openlfdirstate(ui, repo)
485 490 for (src, dest) in copiedfiles:
486 491 if (lfutil.shortname in src and
487 492 dest.startswith(repo.wjoin(lfutil.shortname))):
488 493 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
489 494 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
490 495 destlfiledir = os.path.dirname(destlfile) or '.'
491 496 if not os.path.isdir(destlfiledir):
492 497 os.makedirs(destlfiledir)
493 498 if rename:
494 499 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
495 500 lfdirstate.remove(srclfile)
496 501 else:
497 502 util.copyfile(srclfile, destlfile)
498 503 lfdirstate.add(destlfile)
499 504 lfdirstate.write()
500 505 except util.Abort, e:
501 506 if str(e) != 'no files to copy':
502 507 raise e
503 508 else:
504 509 nolfiles = True
505 510 finally:
506 511 restorematchfn()
507 512 wlock.release()
508 513
509 514 if nolfiles and nonormalfiles:
510 515 raise util.Abort(_('no files to copy'))
511 516
512 517 return result
513 518
514 519 # When the user calls revert, we have to be careful to not revert any
515 520 # changes to other largefiles accidentally. This means we have to keep
516 521 # track of the largefiles that are being reverted so we only pull down
517 522 # the necessary largefiles.
518 523 #
519 524 # Standins are only updated (to match the hash of largefiles) before
520 525 # commits. Update the standins then run the original revert, changing
521 526 # the matcher to hit standins instead of largefiles. Based on the
522 527 # resulting standins update the largefiles. Then return the standins
523 528 # to their proper state
524 529 def overriderevert(orig, ui, repo, *pats, **opts):
525 530 # Because we put the standins in a bad state (by updating them)
526 531 # and then return them to a correct state we need to lock to
527 532 # prevent others from changing them in their incorrect state.
528 533 wlock = repo.wlock()
529 534 try:
530 535 lfdirstate = lfutil.openlfdirstate(ui, repo)
531 536 (modified, added, removed, missing, unknown, ignored, clean) = \
532 537 lfutil.lfdirstatestatus(lfdirstate, repo, repo['.'].rev())
533 538 for lfile in modified:
534 539 lfutil.updatestandin(repo, lfutil.standin(lfile))
535 540 for lfile in missing:
536 541 os.unlink(repo.wjoin(lfutil.standin(lfile)))
537 542
538 543 try:
539 544 ctx = repo[opts.get('rev')]
540 545 oldmatch = None # for the closure
541 546 def overridematch(ctx, pats=[], opts={}, globbed=False,
542 547 default='relpath'):
543 548 match = oldmatch(ctx, pats, opts, globbed, default)
544 549 m = copy.copy(match)
545 550 def tostandin(f):
546 551 if lfutil.standin(f) in ctx:
547 552 return lfutil.standin(f)
548 553 elif lfutil.standin(f) in repo[None]:
549 554 return None
550 555 return f
551 556 m._files = [tostandin(f) for f in m._files]
552 557 m._files = [f for f in m._files if f is not None]
553 558 m._fmap = set(m._files)
554 559 origmatchfn = m.matchfn
555 560 def matchfn(f):
556 561 if lfutil.isstandin(f):
557 562 # We need to keep track of what largefiles are being
558 563 # matched so we know which ones to update later --
559 564 # otherwise we accidentally revert changes to other
560 565 # largefiles. This is repo-specific, so duckpunch the
561 566 # repo object to keep the list of largefiles for us
562 567 # later.
563 568 if origmatchfn(lfutil.splitstandin(f)) and \
564 569 (f in repo[None] or f in ctx):
565 570 lfileslist = getattr(repo, '_lfilestoupdate', [])
566 571 lfileslist.append(lfutil.splitstandin(f))
567 572 repo._lfilestoupdate = lfileslist
568 573 return True
569 574 else:
570 575 return False
571 576 return origmatchfn(f)
572 577 m.matchfn = matchfn
573 578 return m
574 579 oldmatch = installmatchfn(overridematch)
575 580 scmutil.match
576 581 matches = overridematch(repo[None], pats, opts)
577 582 orig(ui, repo, *pats, **opts)
578 583 finally:
579 584 restorematchfn()
580 585 lfileslist = getattr(repo, '_lfilestoupdate', [])
581 586 lfcommands.updatelfiles(ui, repo, filelist=lfileslist,
582 587 printmessage=False)
583 588
584 589 # empty out the largefiles list so we start fresh next time
585 590 repo._lfilestoupdate = []
586 591 for lfile in modified:
587 592 if lfile in lfileslist:
588 593 if os.path.exists(repo.wjoin(lfutil.standin(lfile))) and lfile\
589 594 in repo['.']:
590 595 lfutil.writestandin(repo, lfutil.standin(lfile),
591 596 repo['.'][lfile].data().strip(),
592 597 'x' in repo['.'][lfile].flags())
593 598 lfdirstate = lfutil.openlfdirstate(ui, repo)
594 599 for lfile in added:
595 600 standin = lfutil.standin(lfile)
596 601 if standin not in ctx and (standin in matches or opts.get('all')):
597 602 if lfile in lfdirstate:
598 603 lfdirstate.drop(lfile)
599 604 util.unlinkpath(repo.wjoin(standin))
600 605 lfdirstate.write()
601 606 finally:
602 607 wlock.release()
603 608
604 609 def hgupdate(orig, repo, node):
605 610 # Only call updatelfiles the standins that have changed to save time
606 611 oldstandins = lfutil.getstandinsstate(repo)
607 612 result = orig(repo, node)
608 613 newstandins = lfutil.getstandinsstate(repo)
609 614 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
610 615 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist, printmessage=True)
611 616 return result
612 617
613 618 def hgclean(orig, repo, node, show_stats=True):
614 619 result = orig(repo, node, show_stats)
615 620 lfcommands.updatelfiles(repo.ui, repo)
616 621 return result
617 622
618 623 def hgmerge(orig, repo, node, force=None, remind=True):
619 624 # Mark the repo as being in the middle of a merge, so that
620 625 # updatelfiles() will know that it needs to trust the standins in
621 626 # the working copy, not in the standins in the current node
622 627 repo._ismerging = True
623 628 try:
624 629 result = orig(repo, node, force, remind)
625 630 lfcommands.updatelfiles(repo.ui, repo)
626 631 finally:
627 632 repo._ismerging = False
628 633 return result
629 634
630 635 # When we rebase a repository with remotely changed largefiles, we need to
631 636 # take some extra care so that the largefiles are correctly updated in the
632 637 # working copy
633 638 def overridepull(orig, ui, repo, source=None, **opts):
634 639 if opts.get('rebase', False):
635 640 repo._isrebasing = True
636 641 try:
637 642 if opts.get('update'):
638 643 del opts['update']
639 644 ui.debug('--update and --rebase are not compatible, ignoring '
640 645 'the update flag\n')
641 646 del opts['rebase']
642 647 cmdutil.bailifchanged(repo)
643 648 revsprepull = len(repo)
644 649 origpostincoming = commands.postincoming
645 650 def _dummy(*args, **kwargs):
646 651 pass
647 652 commands.postincoming = _dummy
648 653 repo.lfpullsource = source
649 654 if not source:
650 655 source = 'default'
651 656 try:
652 657 result = commands.pull(ui, repo, source, **opts)
653 658 finally:
654 659 commands.postincoming = origpostincoming
655 660 revspostpull = len(repo)
656 661 if revspostpull > revsprepull:
657 662 result = result or rebase.rebase(ui, repo)
658 663 finally:
659 664 repo._isrebasing = False
660 665 else:
661 666 repo.lfpullsource = source
662 667 if not source:
663 668 source = 'default'
664 669 oldheads = lfutil.getcurrentheads(repo)
665 670 result = orig(ui, repo, source, **opts)
666 671 # If we do not have the new largefiles for any new heads we pulled, we
667 672 # will run into a problem later if we try to merge or rebase with one of
668 673 # these heads, so cache the largefiles now direclty into the system
669 674 # cache.
670 675 ui.status(_("caching new largefiles\n"))
671 676 numcached = 0
672 677 heads = lfutil.getcurrentheads(repo)
673 678 newheads = set(heads).difference(set(oldheads))
674 679 for head in newheads:
675 680 (cached, missing) = lfcommands.cachelfiles(ui, repo, head)
676 681 numcached += len(cached)
677 682 ui.status(_("%d largefiles cached\n") % numcached)
678 683 return result
679 684
680 685 def overriderebase(orig, ui, repo, **opts):
681 686 repo._isrebasing = True
682 687 try:
683 688 orig(ui, repo, **opts)
684 689 finally:
685 690 repo._isrebasing = False
686 691
687 692 def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None,
688 693 prefix=None, mtime=None, subrepos=None):
689 694 # No need to lock because we are only reading history and
690 695 # largefile caches, neither of which are modified.
691 696 lfcommands.cachelfiles(repo.ui, repo, node)
692 697
693 698 if kind not in archival.archivers:
694 699 raise util.Abort(_("unknown archive type '%s'") % kind)
695 700
696 701 ctx = repo[node]
697 702
698 703 if kind == 'files':
699 704 if prefix:
700 705 raise util.Abort(
701 706 _('cannot give prefix when archiving to files'))
702 707 else:
703 708 prefix = archival.tidyprefix(dest, kind, prefix)
704 709
705 710 def write(name, mode, islink, getdata):
706 711 if matchfn and not matchfn(name):
707 712 return
708 713 data = getdata()
709 714 if decode:
710 715 data = repo.wwritedata(name, data)
711 716 archiver.addfile(prefix + name, mode, islink, data)
712 717
713 718 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
714 719
715 720 if repo.ui.configbool("ui", "archivemeta", True):
716 721 def metadata():
717 722 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
718 723 hex(repo.changelog.node(0)), hex(node), ctx.branch())
719 724
720 725 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
721 726 if repo.tagtype(t) == 'global')
722 727 if not tags:
723 728 repo.ui.pushbuffer()
724 729 opts = {'template': '{latesttag}\n{latesttagdistance}',
725 730 'style': '', 'patch': None, 'git': None}
726 731 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
727 732 ltags, dist = repo.ui.popbuffer().split('\n')
728 733 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
729 734 tags += 'latesttagdistance: %s\n' % dist
730 735
731 736 return base + tags
732 737
733 738 write('.hg_archival.txt', 0644, False, metadata)
734 739
735 740 for f in ctx:
736 741 ff = ctx.flags(f)
737 742 getdata = ctx[f].data
738 743 if lfutil.isstandin(f):
739 744 path = lfutil.findfile(repo, getdata().strip())
740 745 if path is None:
741 746 raise util.Abort(
742 747 _('largefile %s not found in repo store or system cache')
743 748 % lfutil.splitstandin(f))
744 749 f = lfutil.splitstandin(f)
745 750
746 751 def getdatafn():
747 752 fd = None
748 753 try:
749 754 fd = open(path, 'rb')
750 755 return fd.read()
751 756 finally:
752 757 if fd:
753 758 fd.close()
754 759
755 760 getdata = getdatafn
756 761 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
757 762
758 763 if subrepos:
759 764 for subpath in ctx.substate:
760 765 sub = ctx.sub(subpath)
761 766 sub.archive(repo.ui, archiver, prefix)
762 767
763 768 archiver.done()
764 769
765 770 # If a largefile is modified, the change is not reflected in its
766 771 # standin until a commit. cmdutil.bailifchanged() raises an exception
767 772 # if the repo has uncommitted changes. Wrap it to also check if
768 773 # largefiles were changed. This is used by bisect and backout.
769 774 def overridebailifchanged(orig, repo):
770 775 orig(repo)
771 776 repo.lfstatus = True
772 777 modified, added, removed, deleted = repo.status()[:4]
773 778 repo.lfstatus = False
774 779 if modified or added or removed or deleted:
775 780 raise util.Abort(_('outstanding uncommitted changes'))
776 781
777 782 # Fetch doesn't use cmdutil.bailifchanged so override it to add the check
778 783 def overridefetch(orig, ui, repo, *pats, **opts):
779 784 repo.lfstatus = True
780 785 modified, added, removed, deleted = repo.status()[:4]
781 786 repo.lfstatus = False
782 787 if modified or added or removed or deleted:
783 788 raise util.Abort(_('outstanding uncommitted changes'))
784 789 return orig(ui, repo, *pats, **opts)
785 790
786 791 def overrideforget(orig, ui, repo, *pats, **opts):
787 792 installnormalfilesmatchfn(repo[None].manifest())
788 793 orig(ui, repo, *pats, **opts)
789 794 restorematchfn()
790 795 m = scmutil.match(repo[None], pats, opts)
791 796
792 797 try:
793 798 repo.lfstatus = True
794 799 s = repo.status(match=m, clean=True)
795 800 finally:
796 801 repo.lfstatus = False
797 802 forget = sorted(s[0] + s[1] + s[3] + s[6])
798 803 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
799 804
800 805 for f in forget:
801 806 if lfutil.standin(f) not in repo.dirstate and not \
802 807 os.path.isdir(m.rel(lfutil.standin(f))):
803 808 ui.warn(_('not removing %s: file is already untracked\n')
804 809 % m.rel(f))
805 810
806 811 for f in forget:
807 812 if ui.verbose or not m.exact(f):
808 813 ui.status(_('removing %s\n') % m.rel(f))
809 814
810 815 # Need to lock because standin files are deleted then removed from the
811 816 # repository and we could race inbetween.
812 817 wlock = repo.wlock()
813 818 try:
814 819 lfdirstate = lfutil.openlfdirstate(ui, repo)
815 820 for f in forget:
816 821 if lfdirstate[f] == 'a':
817 822 lfdirstate.drop(f)
818 823 else:
819 824 lfdirstate.remove(f)
820 825 lfdirstate.write()
821 826 lfutil.reporemove(repo, [lfutil.standin(f) for f in forget],
822 827 unlink=True)
823 828 finally:
824 829 wlock.release()
825 830
826 831 def getoutgoinglfiles(ui, repo, dest=None, **opts):
827 832 dest = ui.expandpath(dest or 'default-push', dest or 'default')
828 833 dest, branches = hg.parseurl(dest, opts.get('branch'))
829 834 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
830 835 if revs:
831 836 revs = [repo.lookup(rev) for rev in revs]
832 837
833 838 remoteui = hg.remoteui
834 839
835 840 try:
836 841 remote = hg.repository(remoteui(repo, opts), dest)
837 842 except error.RepoError:
838 843 return None
839 844 o = lfutil.findoutgoing(repo, remote, False)
840 845 if not o:
841 846 return None
842 847 o = repo.changelog.nodesbetween(o, revs)[0]
843 848 if opts.get('newest_first'):
844 849 o.reverse()
845 850
846 851 toupload = set()
847 852 for n in o:
848 853 parents = [p for p in repo.changelog.parents(n) if p != node.nullid]
849 854 ctx = repo[n]
850 855 files = set(ctx.files())
851 856 if len(parents) == 2:
852 857 mc = ctx.manifest()
853 858 mp1 = ctx.parents()[0].manifest()
854 859 mp2 = ctx.parents()[1].manifest()
855 860 for f in mp1:
856 861 if f not in mc:
857 862 files.add(f)
858 863 for f in mp2:
859 864 if f not in mc:
860 865 files.add(f)
861 866 for f in mc:
862 867 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None):
863 868 files.add(f)
864 869 toupload = toupload.union(
865 870 set([f for f in files if lfutil.isstandin(f) and f in ctx]))
866 871 return toupload
867 872
868 873 def overrideoutgoing(orig, ui, repo, dest=None, **opts):
869 874 orig(ui, repo, dest, **opts)
870 875
871 876 if opts.pop('large', None):
872 877 toupload = getoutgoinglfiles(ui, repo, dest, **opts)
873 878 if toupload is None:
874 879 ui.status(_('largefiles: No remote repo\n'))
875 880 else:
876 881 ui.status(_('largefiles to upload:\n'))
877 882 for file in toupload:
878 883 ui.status(lfutil.splitstandin(file) + '\n')
879 884 ui.status('\n')
880 885
881 886 def overridesummary(orig, ui, repo, *pats, **opts):
882 887 try:
883 888 repo.lfstatus = True
884 889 orig(ui, repo, *pats, **opts)
885 890 finally:
886 891 repo.lfstatus = False
887 892
888 893 if opts.pop('large', None):
889 894 toupload = getoutgoinglfiles(ui, repo, None, **opts)
890 895 if toupload is None:
891 896 ui.status(_('largefiles: No remote repo\n'))
892 897 else:
893 898 ui.status(_('largefiles: %d to upload\n') % len(toupload))
894 899
895 900 def overrideaddremove(orig, ui, repo, *pats, **opts):
896 901 # Get the list of missing largefiles so we can remove them
897 902 lfdirstate = lfutil.openlfdirstate(ui, repo)
898 903 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
899 904 False, False)
900 905 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
901 906
902 907 # Call into the normal remove code, but the removing of the standin, we want
903 908 # to have handled by original addremove. Monkey patching here makes sure
904 909 # we don't remove the standin in the largefiles code, preventing a very
905 910 # confused state later.
906 911 if missing:
907 912 repo._isaddremove = True
908 913 removelargefiles(ui, repo, *missing, **opts)
909 914 repo._isaddremove = False
910 915 # Call into the normal add code, and any files that *should* be added as
911 916 # largefiles will be
912 917 addlargefiles(ui, repo, *pats, **opts)
913 918 # Now that we've handled largefiles, hand off to the original addremove
914 919 # function to take care of the rest. Make sure it doesn't do anything with
915 920 # largefiles by installing a matcher that will ignore them.
916 921 installnormalfilesmatchfn(repo[None].manifest())
917 922 result = orig(ui, repo, *pats, **opts)
918 923 restorematchfn()
919 924 return result
920 925
921 926 # Calling purge with --all will cause the largefiles to be deleted.
922 927 # Override repo.status to prevent this from happening.
923 928 def overridepurge(orig, ui, repo, *dirs, **opts):
924 929 oldstatus = repo.status
925 930 def overridestatus(node1='.', node2=None, match=None, ignored=False,
926 931 clean=False, unknown=False, listsubrepos=False):
927 932 r = oldstatus(node1, node2, match, ignored, clean, unknown,
928 933 listsubrepos)
929 934 lfdirstate = lfutil.openlfdirstate(ui, repo)
930 935 modified, added, removed, deleted, unknown, ignored, clean = r
931 936 unknown = [f for f in unknown if lfdirstate[f] == '?']
932 937 ignored = [f for f in ignored if lfdirstate[f] == '?']
933 938 return modified, added, removed, deleted, unknown, ignored, clean
934 939 repo.status = overridestatus
935 940 orig(ui, repo, *dirs, **opts)
936 941 repo.status = oldstatus
937 942
938 943 def overriderollback(orig, ui, repo, **opts):
939 944 result = orig(ui, repo, **opts)
940 945 merge.update(repo, node=None, branchmerge=False, force=True,
941 946 partial=lfutil.isstandin)
942 947 wlock = repo.wlock()
943 948 try:
944 949 lfdirstate = lfutil.openlfdirstate(ui, repo)
945 950 lfiles = lfutil.listlfiles(repo)
946 951 oldlfiles = lfutil.listlfiles(repo, repo[None].parents()[0].rev())
947 952 for file in lfiles:
948 953 if file in oldlfiles:
949 954 lfdirstate.normallookup(file)
950 955 else:
951 956 lfdirstate.add(file)
952 957 lfdirstate.write()
953 958 finally:
954 959 wlock.release()
955 960 return result
956 961
957 962 def overridetransplant(orig, ui, repo, *revs, **opts):
958 963 try:
959 964 oldstandins = lfutil.getstandinsstate(repo)
960 965 repo._istransplanting = True
961 966 result = orig(ui, repo, *revs, **opts)
962 967 newstandins = lfutil.getstandinsstate(repo)
963 968 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
964 969 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
965 970 printmessage=True)
966 971 finally:
967 972 repo._istransplanting = False
968 973 return result
969 974
970 975 def overridecat(orig, ui, repo, file1, *pats, **opts):
971 976 rev = opts.get('rev')
972 977 if not lfutil.standin(file1) in repo[rev]:
973 978 result = orig(ui, repo, file1, *pats, **opts)
974 979 return result
975 980 return lfcommands.catlfile(repo, file1, opts.get('rev'), opts.get('output'))
@@ -1,145 +1,147 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 extension: uisetup'''
10 10
11 11 from mercurial import archival, cmdutil, commands, extensions, filemerge, hg, \
12 12 httprepo, localrepo, merge, sshrepo, sshserver, wireproto
13 13 from mercurial.i18n import _
14 from mercurial.hgweb import hgweb_mod, protocol
14 from mercurial.hgweb import hgweb_mod, protocol, webcommands
15 15
16 16 import overrides
17 17 import proto
18 18
19 19 def uisetup(ui):
20 20 # Disable auto-status for some commands which assume that all
21 21 # files in the result are under Mercurial's control
22 22
23 23 entry = extensions.wrapcommand(commands.table, 'add',
24 24 overrides.overrideadd)
25 25 addopt = [('', 'large', None, _('add as largefile')),
26 26 ('', 'normal', None, _('add as normal file')),
27 27 ('', 'lfsize', '', _('add all files above this size '
28 28 '(in megabytes) as largefiles '
29 29 '(default: 10)'))]
30 30 entry[1].extend(addopt)
31 31
32 32 entry = extensions.wrapcommand(commands.table, 'addremove',
33 33 overrides.overrideaddremove)
34 34 entry = extensions.wrapcommand(commands.table, 'remove',
35 35 overrides.overrideremove)
36 36 entry = extensions.wrapcommand(commands.table, 'forget',
37 37 overrides.overrideforget)
38 38 entry = extensions.wrapcommand(commands.table, 'status',
39 39 overrides.overridestatus)
40 40 entry = extensions.wrapcommand(commands.table, 'log',
41 41 overrides.overridelog)
42 42 entry = extensions.wrapcommand(commands.table, 'rollback',
43 43 overrides.overriderollback)
44 44 entry = extensions.wrapcommand(commands.table, 'verify',
45 45 overrides.overrideverify)
46 46
47 47 verifyopt = [('', 'large', None, _('verify largefiles')),
48 48 ('', 'lfa', None,
49 49 _('verify all revisions of largefiles not just current')),
50 50 ('', 'lfc', None,
51 51 _('verify largefile contents not just existence'))]
52 52 entry[1].extend(verifyopt)
53 53
54 54 entry = extensions.wrapcommand(commands.table, 'outgoing',
55 55 overrides.overrideoutgoing)
56 56 outgoingopt = [('', 'large', None, _('display outgoing largefiles'))]
57 57 entry[1].extend(outgoingopt)
58 58 entry = extensions.wrapcommand(commands.table, 'summary',
59 59 overrides.overridesummary)
60 60 summaryopt = [('', 'large', None, _('display outgoing largefiles'))]
61 61 entry[1].extend(summaryopt)
62 62
63 63 entry = extensions.wrapcommand(commands.table, 'update',
64 64 overrides.overrideupdate)
65 65 entry = extensions.wrapcommand(commands.table, 'pull',
66 66 overrides.overridepull)
67 67 entry = extensions.wrapcommand(commands.table, 'cat',
68 68 overrides.overridecat)
69 69 entry = extensions.wrapfunction(merge, '_checkunknownfile',
70 70 overrides.overridecheckunknownfile)
71 71 entry = extensions.wrapfunction(merge, 'manifestmerge',
72 72 overrides.overridemanifestmerge)
73 73 entry = extensions.wrapfunction(filemerge, 'filemerge',
74 74 overrides.overridefilemerge)
75 75 entry = extensions.wrapfunction(cmdutil, 'copy',
76 76 overrides.overridecopy)
77 77
78 78 # Backout calls revert so we need to override both the command and the
79 79 # function
80 80 entry = extensions.wrapcommand(commands.table, 'revert',
81 81 overrides.overriderevert)
82 82 entry = extensions.wrapfunction(commands, 'revert',
83 83 overrides.overriderevert)
84 84
85 85 # clone uses hg._update instead of hg.update even though they are the
86 86 # same function... so wrap both of them)
87 87 extensions.wrapfunction(hg, 'update', overrides.hgupdate)
88 88 extensions.wrapfunction(hg, '_update', overrides.hgupdate)
89 89 extensions.wrapfunction(hg, 'clean', overrides.hgclean)
90 90 extensions.wrapfunction(hg, 'merge', overrides.hgmerge)
91 91
92 92 extensions.wrapfunction(archival, 'archive', overrides.overridearchive)
93 93 extensions.wrapfunction(cmdutil, 'bailifchanged',
94 94 overrides.overridebailifchanged)
95 95
96 96 # create the new wireproto commands ...
97 97 wireproto.commands['putlfile'] = (proto.putlfile, 'sha')
98 98 wireproto.commands['getlfile'] = (proto.getlfile, 'sha')
99 99 wireproto.commands['statlfile'] = (proto.statlfile, 'sha')
100 100
101 101 # ... and wrap some existing ones
102 102 wireproto.commands['capabilities'] = (proto.capabilities, '')
103 103 wireproto.commands['heads'] = (proto.heads, '')
104 104 wireproto.commands['lheads'] = (wireproto.heads, '')
105 105
106 106 # make putlfile behave the same as push and {get,stat}lfile behave
107 107 # the same as pull w.r.t. permissions checks
108 108 hgweb_mod.perms['putlfile'] = 'push'
109 109 hgweb_mod.perms['getlfile'] = 'pull'
110 110 hgweb_mod.perms['statlfile'] = 'pull'
111 111
112 extensions.wrapfunction(webcommands, 'decodepath', overrides.decodepath)
113
112 114 # the hello wireproto command uses wireproto.capabilities, so it won't see
113 115 # our largefiles capability unless we replace the actual function as well.
114 116 proto.capabilitiesorig = wireproto.capabilities
115 117 wireproto.capabilities = proto.capabilities
116 118
117 119 # these let us reject non-largefiles clients and make them display
118 120 # our error messages
119 121 protocol.webproto.refuseclient = proto.webprotorefuseclient
120 122 sshserver.sshserver.refuseclient = proto.sshprotorefuseclient
121 123
122 124 # can't do this in reposetup because it needs to have happened before
123 125 # wirerepo.__init__ is called
124 126 proto.ssholdcallstream = sshrepo.sshrepository._callstream
125 127 proto.httpoldcallstream = httprepo.httprepository._callstream
126 128 sshrepo.sshrepository._callstream = proto.sshrepocallstream
127 129 httprepo.httprepository._callstream = proto.httprepocallstream
128 130
129 131 # don't die on seeing a repo with the largefiles requirement
130 132 localrepo.localrepository.supported |= set(['largefiles'])
131 133
132 134 # override some extensions' stuff as well
133 135 for name, module in extensions.extensions():
134 136 if name == 'fetch':
135 137 extensions.wrapcommand(getattr(module, 'cmdtable'), 'fetch',
136 138 overrides.overridefetch)
137 139 if name == 'purge':
138 140 extensions.wrapcommand(getattr(module, 'cmdtable'), 'purge',
139 141 overrides.overridepurge)
140 142 if name == 'rebase':
141 143 extensions.wrapcommand(getattr(module, 'cmdtable'), 'rebase',
142 144 overrides.overriderebase)
143 145 if name == 'transplant':
144 146 extensions.wrapcommand(getattr(module, 'cmdtable'), 'transplant',
145 147 overrides.overridetransplant)
@@ -1,1031 +1,1054 b''
1 1 $ "$TESTDIR/hghave" symlink unix-permissions serve || exit 80
2 2 $ USERCACHE=`pwd`/cache; export USERCACHE
3 3 $ mkdir -p ${USERCACHE}
4 4 $ cat >> $HGRCPATH <<EOF
5 5 > [extensions]
6 6 > largefiles=
7 7 > purge=
8 8 > rebase=
9 9 > transplant=
10 10 > [phases]
11 11 > publish=False
12 12 > [largefiles]
13 13 > minsize=2
14 14 > patterns=glob:**.dat
15 15 > usercache=${USERCACHE}
16 16 > [hooks]
17 17 > precommit=echo "Invoking status precommit hook"; hg status
18 18 > EOF
19 19
20 20 Create the repo with a couple of revisions of both large and normal
21 21 files, testing that status correctly shows largefiles and that summary output
22 22 is correct.
23 23
24 24 $ hg init a
25 25 $ cd a
26 26 $ mkdir sub
27 27 $ echo normal1 > normal1
28 28 $ echo normal2 > sub/normal2
29 29 $ echo large1 > large1
30 30 $ echo large2 > sub/large2
31 31 $ hg add normal1 sub/normal2
32 32 $ hg add --large large1 sub/large2
33 33 $ hg commit -m "add files"
34 34 Invoking status precommit hook
35 35 A large1
36 36 A normal1
37 37 A sub/large2
38 38 A sub/normal2
39 39 $ echo normal11 > normal1
40 40 $ echo normal22 > sub/normal2
41 41 $ echo large11 > large1
42 42 $ echo large22 > sub/large2
43 43 $ hg commit -m "edit files"
44 44 Invoking status precommit hook
45 45 M large1
46 46 M normal1
47 47 M sub/large2
48 48 M sub/normal2
49 49 $ hg sum --large
50 50 parent: 1:ce8896473775 tip
51 51 edit files
52 52 branch: default
53 53 commit: (clean)
54 54 update: (current)
55 55 largefiles: No remote repo
56 56
57 57 Commit preserved largefile contents.
58 58
59 59 $ cat normal1
60 60 normal11
61 61 $ cat large1
62 62 large11
63 63 $ cat sub/normal2
64 64 normal22
65 65 $ cat sub/large2
66 66 large22
67 67
68 68 Remove both largefiles and normal files.
69 69
70 70 $ hg remove normal1 large1
71 71 $ hg status large1
72 72 R large1
73 73 $ hg commit -m "remove files"
74 74 Invoking status precommit hook
75 75 R large1
76 76 R normal1
77 77 $ ls
78 78 sub
79 79 $ echo "testlargefile" > large1-test
80 80 $ hg add --large large1-test
81 81 $ hg st
82 82 A large1-test
83 83 $ hg rm large1-test
84 84 not removing large1-test: file has been marked for add (use forget to undo)
85 85 $ hg st
86 86 A large1-test
87 87 $ hg forget large1-test
88 88 $ hg st
89 89 ? large1-test
90 90 $ rm large1-test
91 91
92 92 Copy both largefiles and normal files (testing that status output is correct).
93 93
94 94 $ hg cp sub/normal2 normal1
95 95 $ hg cp sub/large2 large1
96 96 $ hg commit -m "copy files"
97 97 Invoking status precommit hook
98 98 A large1
99 99 A normal1
100 100 $ cat normal1
101 101 normal22
102 102 $ cat large1
103 103 large22
104 104
105 105 Test moving largefiles and verify that normal files are also unaffected.
106 106
107 107 $ hg mv normal1 normal3
108 108 $ hg mv large1 large3
109 109 $ hg mv sub/normal2 sub/normal4
110 110 $ hg mv sub/large2 sub/large4
111 111 $ hg commit -m "move files"
112 112 Invoking status precommit hook
113 113 A large3
114 114 A normal3
115 115 A sub/large4
116 116 A sub/normal4
117 117 R large1
118 118 R normal1
119 119 R sub/large2
120 120 R sub/normal2
121 121 $ cat normal3
122 122 normal22
123 123 $ cat large3
124 124 large22
125 125 $ cat sub/normal4
126 126 normal22
127 127 $ cat sub/large4
128 128 large22
129 129
130 Test display of largefiles in hgweb
131
132 $ hg serve -d -p $HGPORT --pid-file ../hg.pid
133 $ cat ../hg.pid >> $DAEMON_PIDS
134 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/file/tip/?style=raw'
135 200 Script output follows
136
137
138 drwxr-xr-x sub
139 -rw-r--r-- 41 large3
140 -rw-r--r-- 9 normal3
141
142
143 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/file/tip/sub/?style=raw'
144 200 Script output follows
145
146
147 -rw-r--r-- 41 large4
148 -rw-r--r-- 9 normal4
149
150
151 $ "$TESTDIR/killdaemons.py"
152
130 153 Test archiving the various revisions. These hit corner cases known with
131 154 archiving.
132 155
133 156 $ hg archive -r 0 ../archive0
134 157 $ hg archive -r 1 ../archive1
135 158 $ hg archive -r 2 ../archive2
136 159 $ hg archive -r 3 ../archive3
137 160 $ hg archive -r 4 ../archive4
138 161 $ cd ../archive0
139 162 $ cat normal1
140 163 normal1
141 164 $ cat large1
142 165 large1
143 166 $ cat sub/normal2
144 167 normal2
145 168 $ cat sub/large2
146 169 large2
147 170 $ cd ../archive1
148 171 $ cat normal1
149 172 normal11
150 173 $ cat large1
151 174 large11
152 175 $ cat sub/normal2
153 176 normal22
154 177 $ cat sub/large2
155 178 large22
156 179 $ cd ../archive2
157 180 $ ls
158 181 sub
159 182 $ cat sub/normal2
160 183 normal22
161 184 $ cat sub/large2
162 185 large22
163 186 $ cd ../archive3
164 187 $ cat normal1
165 188 normal22
166 189 $ cat large1
167 190 large22
168 191 $ cat sub/normal2
169 192 normal22
170 193 $ cat sub/large2
171 194 large22
172 195 $ cd ../archive4
173 196 $ cat normal3
174 197 normal22
175 198 $ cat large3
176 199 large22
177 200 $ cat sub/normal4
178 201 normal22
179 202 $ cat sub/large4
180 203 large22
181 204
182 205 Commit corner case: specify files to commit.
183 206
184 207 $ cd ../a
185 208 $ echo normal3 > normal3
186 209 $ echo large3 > large3
187 210 $ echo normal4 > sub/normal4
188 211 $ echo large4 > sub/large4
189 212 $ hg commit normal3 large3 sub/normal4 sub/large4 -m "edit files again"
190 213 Invoking status precommit hook
191 214 M large3
192 215 M normal3
193 216 M sub/large4
194 217 M sub/normal4
195 218 $ cat normal3
196 219 normal3
197 220 $ cat large3
198 221 large3
199 222 $ cat sub/normal4
200 223 normal4
201 224 $ cat sub/large4
202 225 large4
203 226
204 227 One more commit corner case: commit from a subdirectory.
205 228
206 229 $ cd ../a
207 230 $ echo normal33 > normal3
208 231 $ echo large33 > large3
209 232 $ echo normal44 > sub/normal4
210 233 $ echo large44 > sub/large4
211 234 $ cd sub
212 235 $ hg commit -m "edit files yet again"
213 236 Invoking status precommit hook
214 237 M large3
215 238 M normal3
216 239 M sub/large4
217 240 M sub/normal4
218 241 $ cat ../normal3
219 242 normal33
220 243 $ cat ../large3
221 244 large33
222 245 $ cat normal4
223 246 normal44
224 247 $ cat large4
225 248 large44
226 249
227 250 Committing standins is not allowed.
228 251
229 252 $ cd ..
230 253 $ echo large3 > large3
231 254 $ hg commit .hglf/large3 -m "try to commit standin"
232 255 abort: file ".hglf/large3" is a largefile standin
233 256 (commit the largefile itself instead)
234 257 [255]
235 258
236 259 Corner cases for adding largefiles.
237 260
238 261 $ echo large5 > large5
239 262 $ hg add --large large5
240 263 $ hg add --large large5
241 264 large5 already a largefile
242 265 $ mkdir sub2
243 266 $ echo large6 > sub2/large6
244 267 $ echo large7 > sub2/large7
245 268 $ hg add --large sub2
246 269 adding sub2/large6 as a largefile (glob)
247 270 adding sub2/large7 as a largefile (glob)
248 271 $ hg st
249 272 M large3
250 273 A large5
251 274 A sub2/large6
252 275 A sub2/large7
253 276
254 277 Test "hg status" with combination of 'file pattern' and 'directory
255 278 pattern' for largefiles:
256 279
257 280 $ hg status sub2/large6 sub2
258 281 A sub2/large6
259 282 A sub2/large7
260 283
261 284 Config settings (pattern **.dat, minsize 2 MB) are respected.
262 285
263 286 $ echo testdata > test.dat
264 287 $ dd bs=1k count=2k if=/dev/zero of=reallylarge > /dev/null 2> /dev/null
265 288 $ hg add
266 289 adding reallylarge as a largefile
267 290 adding test.dat as a largefile
268 291
269 292 Test that minsize and --lfsize handle float values;
270 293 also tests that --lfsize overrides largefiles.minsize.
271 294 (0.250 MB = 256 kB = 262144 B)
272 295
273 296 $ dd if=/dev/zero of=ratherlarge bs=1024 count=256 > /dev/null 2> /dev/null
274 297 $ dd if=/dev/zero of=medium bs=1024 count=128 > /dev/null 2> /dev/null
275 298 $ hg --config largefiles.minsize=.25 add
276 299 adding ratherlarge as a largefile
277 300 adding medium
278 301 $ hg forget medium
279 302 $ hg --config largefiles.minsize=.25 add --lfsize=.125
280 303 adding medium as a largefile
281 304 $ dd if=/dev/zero of=notlarge bs=1024 count=127 > /dev/null 2> /dev/null
282 305 $ hg --config largefiles.minsize=.25 add --lfsize=.125
283 306 adding notlarge
284 307 $ hg forget notlarge
285 308
286 309 Test forget on largefiles.
287 310
288 311 $ hg forget large3 large5 test.dat reallylarge ratherlarge medium
289 312 $ hg commit -m "add/edit more largefiles"
290 313 Invoking status precommit hook
291 314 A sub2/large6
292 315 A sub2/large7
293 316 R large3
294 317 ? large5
295 318 ? medium
296 319 ? notlarge
297 320 ? ratherlarge
298 321 ? reallylarge
299 322 ? test.dat
300 323 $ hg st
301 324 ? large3
302 325 ? large5
303 326 ? medium
304 327 ? notlarge
305 328 ? ratherlarge
306 329 ? reallylarge
307 330 ? test.dat
308 331
309 332 Purge with largefiles: verify that largefiles are still in the working
310 333 dir after a purge.
311 334
312 335 $ hg purge --all
313 336 $ cat sub/large4
314 337 large44
315 338 $ cat sub2/large6
316 339 large6
317 340 $ cat sub2/large7
318 341 large7
319 342
320 343 Test addremove: verify that files that should be added as largfiles are added as
321 344 such and that already-existing largfiles are not added as normal files by
322 345 accident.
323 346
324 347 $ rm normal3
325 348 $ rm sub/large4
326 349 $ echo "testing addremove with patterns" > testaddremove.dat
327 350 $ echo "normaladdremove" > normaladdremove
328 351 $ hg addremove
329 352 removing sub/large4
330 353 adding testaddremove.dat as a largefile
331 354 removing normal3
332 355 adding normaladdremove
333 356
334 357 Clone a largefiles repo.
335 358
336 359 $ hg clone . ../b
337 360 updating to branch default
338 361 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
339 362 getting changed largefiles
340 363 3 largefiles updated, 0 removed
341 364 $ cd ../b
342 365 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
343 366 7:daea875e9014 add/edit more largefiles
344 367 6:4355d653f84f edit files yet again
345 368 5:9d5af5072dbd edit files again
346 369 4:74c02385b94c move files
347 370 3:9e8fbc4bce62 copy files
348 371 2:51a0ae4d5864 remove files
349 372 1:ce8896473775 edit files
350 373 0:30d30fe6a5be add files
351 374 $ cat normal3
352 375 normal33
353 376 $ cat sub/normal4
354 377 normal44
355 378 $ cat sub/large4
356 379 large44
357 380 $ cat sub2/large6
358 381 large6
359 382 $ cat sub2/large7
360 383 large7
361 384 $ cd ..
362 385 $ hg clone a -r 3 c
363 386 adding changesets
364 387 adding manifests
365 388 adding file changes
366 389 added 4 changesets with 10 changes to 4 files
367 390 updating to branch default
368 391 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
369 392 getting changed largefiles
370 393 2 largefiles updated, 0 removed
371 394 $ cd c
372 395 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
373 396 3:9e8fbc4bce62 copy files
374 397 2:51a0ae4d5864 remove files
375 398 1:ce8896473775 edit files
376 399 0:30d30fe6a5be add files
377 400 $ cat normal1
378 401 normal22
379 402 $ cat large1
380 403 large22
381 404 $ cat sub/normal2
382 405 normal22
383 406 $ cat sub/large2
384 407 large22
385 408
386 409 Old revisions of a clone have correct largefiles content (this also
387 410 tests update).
388 411
389 412 $ hg update -r 1
390 413 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
391 414 getting changed largefiles
392 415 1 largefiles updated, 0 removed
393 416 $ cat large1
394 417 large11
395 418 $ cat sub/large2
396 419 large22
397 420
398 421 Rebasing between two repositories does not revert largefiles to old
399 422 revisions (this was a very bad bug that took a lot of work to fix).
400 423
401 424 $ cd ..
402 425 $ hg clone a d
403 426 updating to branch default
404 427 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
405 428 getting changed largefiles
406 429 3 largefiles updated, 0 removed
407 430 $ cd b
408 431 $ echo large4-modified > sub/large4
409 432 $ echo normal3-modified > normal3
410 433 $ hg commit -m "modify normal file and largefile in repo b"
411 434 Invoking status precommit hook
412 435 M normal3
413 436 M sub/large4
414 437 $ cd ../d
415 438 $ echo large6-modified > sub2/large6
416 439 $ echo normal4-modified > sub/normal4
417 440 $ hg commit -m "modify normal file largefile in repo d"
418 441 Invoking status precommit hook
419 442 M sub/normal4
420 443 M sub2/large6
421 444 $ cd ..
422 445 $ hg clone d e
423 446 updating to branch default
424 447 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
425 448 getting changed largefiles
426 449 3 largefiles updated, 0 removed
427 450 $ cd d
428 451 $ hg pull --rebase ../b
429 452 pulling from ../b
430 453 searching for changes
431 454 adding changesets
432 455 adding manifests
433 456 adding file changes
434 457 added 1 changesets with 2 changes to 2 files (+1 heads)
435 458 Invoking status precommit hook
436 459 M sub/normal4
437 460 M sub2/large6
438 461 saved backup bundle to $TESTTMP/d/.hg/strip-backup/f574fb32bb45-backup.hg
439 462 nothing to rebase
440 463 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
441 464 9:598410d3eb9a modify normal file largefile in repo d
442 465 8:a381d2c8c80e modify normal file and largefile in repo b
443 466 7:daea875e9014 add/edit more largefiles
444 467 6:4355d653f84f edit files yet again
445 468 5:9d5af5072dbd edit files again
446 469 4:74c02385b94c move files
447 470 3:9e8fbc4bce62 copy files
448 471 2:51a0ae4d5864 remove files
449 472 1:ce8896473775 edit files
450 473 0:30d30fe6a5be add files
451 474 $ cat normal3
452 475 normal3-modified
453 476 $ cat sub/normal4
454 477 normal4-modified
455 478 $ cat sub/large4
456 479 large4-modified
457 480 $ cat sub2/large6
458 481 large6-modified
459 482 $ cat sub2/large7
460 483 large7
461 484 $ cd ../e
462 485 $ hg pull ../b
463 486 pulling from ../b
464 487 searching for changes
465 488 adding changesets
466 489 adding manifests
467 490 adding file changes
468 491 added 1 changesets with 2 changes to 2 files (+1 heads)
469 492 (run 'hg heads' to see heads, 'hg merge' to merge)
470 493 caching new largefiles
471 494 0 largefiles cached
472 495 $ hg rebase
473 496 Invoking status precommit hook
474 497 M sub/normal4
475 498 M sub2/large6
476 499 saved backup bundle to $TESTTMP/e/.hg/strip-backup/f574fb32bb45-backup.hg
477 500 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
478 501 9:598410d3eb9a modify normal file largefile in repo d
479 502 8:a381d2c8c80e modify normal file and largefile in repo b
480 503 7:daea875e9014 add/edit more largefiles
481 504 6:4355d653f84f edit files yet again
482 505 5:9d5af5072dbd edit files again
483 506 4:74c02385b94c move files
484 507 3:9e8fbc4bce62 copy files
485 508 2:51a0ae4d5864 remove files
486 509 1:ce8896473775 edit files
487 510 0:30d30fe6a5be add files
488 511 $ cat normal3
489 512 normal3-modified
490 513 $ cat sub/normal4
491 514 normal4-modified
492 515 $ cat sub/large4
493 516 large4-modified
494 517 $ cat sub2/large6
495 518 large6-modified
496 519 $ cat sub2/large7
497 520 large7
498 521
499 522 Rollback on largefiles.
500 523
501 524 $ echo large4-modified-again > sub/large4
502 525 $ hg commit -m "Modify large4 again"
503 526 Invoking status precommit hook
504 527 M sub/large4
505 528 $ hg rollback
506 529 repository tip rolled back to revision 9 (undo commit)
507 530 working directory now based on revision 9
508 531 $ hg st
509 532 M sub/large4
510 533 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
511 534 9:598410d3eb9a modify normal file largefile in repo d
512 535 8:a381d2c8c80e modify normal file and largefile in repo b
513 536 7:daea875e9014 add/edit more largefiles
514 537 6:4355d653f84f edit files yet again
515 538 5:9d5af5072dbd edit files again
516 539 4:74c02385b94c move files
517 540 3:9e8fbc4bce62 copy files
518 541 2:51a0ae4d5864 remove files
519 542 1:ce8896473775 edit files
520 543 0:30d30fe6a5be add files
521 544 $ cat sub/large4
522 545 large4-modified-again
523 546
524 547 "update --check" refuses to update with uncommitted changes.
525 548 $ hg update --check 8
526 549 abort: uncommitted local changes
527 550 [255]
528 551
529 552 "update --clean" leaves correct largefiles in working copy.
530 553
531 554 $ hg update --clean
532 555 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
533 556 getting changed largefiles
534 557 1 largefiles updated, 0 removed
535 558 $ cat normal3
536 559 normal3-modified
537 560 $ cat sub/normal4
538 561 normal4-modified
539 562 $ cat sub/large4
540 563 large4-modified
541 564 $ cat sub2/large6
542 565 large6-modified
543 566 $ cat sub2/large7
544 567 large7
545 568
546 569 Now "update check" is happy.
547 570 $ hg update --check 8
548 571 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
549 572 getting changed largefiles
550 573 1 largefiles updated, 0 removed
551 574 $ hg update --check
552 575 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
553 576 getting changed largefiles
554 577 1 largefiles updated, 0 removed
555 578
556 579 Test removing empty largefiles directories on update
557 580 $ test -d sub2 && echo "sub2 exists"
558 581 sub2 exists
559 582 $ hg update -q null
560 583 $ test -d sub2 && echo "error: sub2 should not exist anymore"
561 584 [1]
562 585 $ hg update -q
563 586
564 587 Test hg remove removes empty largefiles directories
565 588 $ test -d sub2 && echo "sub2 exists"
566 589 sub2 exists
567 590 $ hg remove sub2/*
568 591 $ test -d sub2 && echo "error: sub2 should not exist anymore"
569 592 [1]
570 593 $ hg revert sub2/large6 sub2/large7
571 594
572 595 "revert" works on largefiles (and normal files too).
573 596 $ echo hack3 >> normal3
574 597 $ echo hack4 >> sub/normal4
575 598 $ echo hack4 >> sub/large4
576 599 $ rm sub2/large6
577 600 $ hg revert sub2/large6
578 601 $ hg rm sub2/large6
579 602 $ echo new >> sub2/large8
580 603 $ hg add --large sub2/large8
581 604 # XXX we don't really want to report that we're reverting the standin;
582 605 # that's just an implementation detail. But I don't see an obvious fix. ;-(
583 606 $ hg revert sub
584 607 reverting .hglf/sub/large4 (glob)
585 608 reverting sub/normal4 (glob)
586 609 $ hg status
587 610 M normal3
588 611 A sub2/large8
589 612 R sub2/large6
590 613 ? sub/large4.orig
591 614 ? sub/normal4.orig
592 615 $ cat sub/normal4
593 616 normal4-modified
594 617 $ cat sub/large4
595 618 large4-modified
596 619 $ hg revert -a --no-backup
597 620 undeleting .hglf/sub2/large6 (glob)
598 621 forgetting .hglf/sub2/large8 (glob)
599 622 reverting normal3
600 623 $ hg status
601 624 ? sub/large4.orig
602 625 ? sub/normal4.orig
603 626 ? sub2/large8
604 627 $ cat normal3
605 628 normal3-modified
606 629 $ cat sub2/large6
607 630 large6-modified
608 631 $ rm sub/*.orig sub2/large8
609 632
610 633 revert some files to an older revision
611 634 $ hg revert --no-backup -r 8 sub2
612 635 reverting .hglf/sub2/large6 (glob)
613 636 $ cat sub2/large6
614 637 large6
615 638 $ hg revert --no-backup sub2
616 639 reverting .hglf/sub2/large6 (glob)
617 640 $ hg status
618 641
619 642 "verify --large" actually verifies largefiles
620 643
621 644 $ hg verify --large
622 645 checking changesets
623 646 checking manifests
624 647 crosschecking files in changesets and manifests
625 648 checking files
626 649 10 files, 10 changesets, 28 total revisions
627 650 searching 1 changesets for largefiles
628 651 verified existence of 3 revisions of 3 largefiles
629 652
630 653 Merging does not revert to old versions of largefiles and also check
631 654 that merging after having pulled from a non-default remote works
632 655 correctly.
633 656
634 657 $ cd ..
635 658 $ hg clone -r 7 e temp
636 659 adding changesets
637 660 adding manifests
638 661 adding file changes
639 662 added 8 changesets with 24 changes to 10 files
640 663 updating to branch default
641 664 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
642 665 getting changed largefiles
643 666 3 largefiles updated, 0 removed
644 667 $ hg clone temp f
645 668 updating to branch default
646 669 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
647 670 getting changed largefiles
648 671 3 largefiles updated, 0 removed
649 672 # Delete the largefiles in the largefiles system cache so that we have an
650 673 # opportunity to test that caching after a pull works.
651 674 $ rm ${USERCACHE}/*
652 675 $ cd f
653 676 $ echo "large4-merge-test" > sub/large4
654 677 $ hg commit -m "Modify large4 to test merge"
655 678 Invoking status precommit hook
656 679 M sub/large4
657 680 $ hg pull ../e
658 681 pulling from ../e
659 682 searching for changes
660 683 adding changesets
661 684 adding manifests
662 685 adding file changes
663 686 added 2 changesets with 4 changes to 4 files (+1 heads)
664 687 (run 'hg heads' to see heads, 'hg merge' to merge)
665 688 caching new largefiles
666 689 2 largefiles cached
667 690 $ hg merge
668 691 merging sub/large4
669 692 largefile sub/large4 has a merge conflict
670 693 keep (l)ocal or take (o)ther? l
671 694 3 files updated, 1 files merged, 0 files removed, 0 files unresolved
672 695 (branch merge, don't forget to commit)
673 696 getting changed largefiles
674 697 1 largefiles updated, 0 removed
675 698 $ hg commit -m "Merge repos e and f"
676 699 Invoking status precommit hook
677 700 M normal3
678 701 M sub/normal4
679 702 M sub2/large6
680 703 $ cat normal3
681 704 normal3-modified
682 705 $ cat sub/normal4
683 706 normal4-modified
684 707 $ cat sub/large4
685 708 large4-merge-test
686 709 $ cat sub2/large6
687 710 large6-modified
688 711 $ cat sub2/large7
689 712 large7
690 713
691 714 Test status after merging with a branch that introduces a new largefile:
692 715
693 716 $ echo large > large
694 717 $ hg add --large large
695 718 $ hg commit -m 'add largefile'
696 719 Invoking status precommit hook
697 720 A large
698 721 $ hg update -q ".^"
699 722 $ echo change >> normal3
700 723 $ hg commit -m 'some change'
701 724 Invoking status precommit hook
702 725 M normal3
703 726 created new head
704 727 $ hg merge
705 728 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
706 729 (branch merge, don't forget to commit)
707 730 getting changed largefiles
708 731 1 largefiles updated, 0 removed
709 732 $ hg status
710 733 M large
711 734
712 735 Test that a normal file and a largefile with the same name and path cannot
713 736 coexist.
714 737
715 738 $ rm sub2/large7
716 739 $ echo "largeasnormal" > sub2/large7
717 740 $ hg add sub2/large7
718 741 sub2/large7 already a largefile
719 742
720 743 Test that transplanting a largefile change works correctly.
721 744
722 745 $ cd ..
723 746 $ hg clone -r 8 d g
724 747 adding changesets
725 748 adding manifests
726 749 adding file changes
727 750 added 9 changesets with 26 changes to 10 files
728 751 updating to branch default
729 752 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
730 753 getting changed largefiles
731 754 3 largefiles updated, 0 removed
732 755 $ cd g
733 756 $ hg transplant -s ../d 598410d3eb9a
734 757 searching for changes
735 758 searching for changes
736 759 adding changesets
737 760 adding manifests
738 761 adding file changes
739 762 added 1 changesets with 2 changes to 2 files
740 763 getting changed largefiles
741 764 1 largefiles updated, 0 removed
742 765 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
743 766 9:598410d3eb9a modify normal file largefile in repo d
744 767 8:a381d2c8c80e modify normal file and largefile in repo b
745 768 7:daea875e9014 add/edit more largefiles
746 769 6:4355d653f84f edit files yet again
747 770 5:9d5af5072dbd edit files again
748 771 4:74c02385b94c move files
749 772 3:9e8fbc4bce62 copy files
750 773 2:51a0ae4d5864 remove files
751 774 1:ce8896473775 edit files
752 775 0:30d30fe6a5be add files
753 776 $ cat normal3
754 777 normal3-modified
755 778 $ cat sub/normal4
756 779 normal4-modified
757 780 $ cat sub/large4
758 781 large4-modified
759 782 $ cat sub2/large6
760 783 large6-modified
761 784 $ cat sub2/large7
762 785 large7
763 786
764 787 Cat a largefile
765 788 $ hg cat normal3
766 789 normal3-modified
767 790 $ hg cat sub/large4
768 791 large4-modified
769 792 $ rm ${USERCACHE}/*
770 793 $ hg cat -r a381d2c8c80e -o cat.out sub/large4
771 794 $ cat cat.out
772 795 large4-modified
773 796 $ rm cat.out
774 797 $ hg cat -r a381d2c8c80e normal3
775 798 normal3-modified
776 799
777 800 Test that renaming a largefile results in correct output for status
778 801
779 802 $ hg rename sub/large4 large4-renamed
780 803 $ hg commit -m "test rename output"
781 804 Invoking status precommit hook
782 805 A large4-renamed
783 806 R sub/large4
784 807 $ cat large4-renamed
785 808 large4-modified
786 809 $ cd sub2
787 810 $ hg rename large6 large6-renamed
788 811 $ hg st
789 812 A sub2/large6-renamed
790 813 R sub2/large6
791 814 $ cd ..
792 815
793 816 Test --normal flag
794 817
795 818 $ dd if=/dev/urandom bs=2k count=11k > new-largefile 2> /dev/null
796 819 $ hg add --normal --large new-largefile
797 820 abort: --normal cannot be used with --large
798 821 [255]
799 822 $ hg add --normal new-largefile
800 823 new-largefile: up to 69 MB of RAM may be required to manage this file
801 824 (use 'hg revert new-largefile' to cancel the pending addition)
802 825 $ cd ..
803 826
804 827 vanilla clients not locked out from largefiles servers on vanilla repos
805 828 $ mkdir r1
806 829 $ cd r1
807 830 $ hg init
808 831 $ echo c1 > f1
809 832 $ hg add f1
810 833 $ hg commit -m "m1"
811 834 Invoking status precommit hook
812 835 A f1
813 836 $ cd ..
814 837 $ hg serve -R r1 -d -p $HGPORT --pid-file hg.pid
815 838 $ cat hg.pid >> $DAEMON_PIDS
816 839 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT r2
817 840 requesting all changes
818 841 adding changesets
819 842 adding manifests
820 843 adding file changes
821 844 added 1 changesets with 1 changes to 1 files
822 845 updating to branch default
823 846 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
824 847
825 848 largefiles clients still work with vanilla servers
826 849 $ hg --config extensions.largefiles=! serve -R r1 -d -p $HGPORT1 --pid-file hg.pid
827 850 $ cat hg.pid >> $DAEMON_PIDS
828 851 $ hg clone http://localhost:$HGPORT1 r3
829 852 requesting all changes
830 853 adding changesets
831 854 adding manifests
832 855 adding file changes
833 856 added 1 changesets with 1 changes to 1 files
834 857 updating to branch default
835 858 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
836 859
837 860 vanilla clients locked out from largefiles http repos
838 861 $ mkdir r4
839 862 $ cd r4
840 863 $ hg init
841 864 $ echo c1 > f1
842 865 $ hg add --large f1
843 866 $ hg commit -m "m1"
844 867 Invoking status precommit hook
845 868 A f1
846 869 $ cd ..
847 870 $ hg serve -R r4 -d -p $HGPORT2 --pid-file hg.pid
848 871 $ cat hg.pid >> $DAEMON_PIDS
849 872 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT2 r5
850 873 abort: remote error:
851 874
852 875 This repository uses the largefiles extension.
853 876
854 877 Please enable it in your Mercurial config file.
855 878 [255]
856 879
857 880 used all HGPORTs, kill all daemons
858 881 $ "$TESTDIR/killdaemons.py"
859 882
860 883 vanilla clients locked out from largefiles ssh repos
861 884 $ hg --config extensions.largefiles=! clone -e 'python "$TESTDIR/dummyssh"' ssh://user@dummy/r4 r5
862 885 abort: remote error:
863 886
864 887 This repository uses the largefiles extension.
865 888
866 889 Please enable it in your Mercurial config file.
867 890 [255]
868 891
869 892 largefiles clients refuse to push largefiles repos to vanilla servers
870 893 $ mkdir r6
871 894 $ cd r6
872 895 $ hg init
873 896 $ echo c1 > f1
874 897 $ hg add f1
875 898 $ hg commit -m "m1"
876 899 Invoking status precommit hook
877 900 A f1
878 901 $ cat >> .hg/hgrc <<!
879 902 > [web]
880 903 > push_ssl = false
881 904 > allow_push = *
882 905 > !
883 906 $ cd ..
884 907 $ hg clone r6 r7
885 908 updating to branch default
886 909 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
887 910 $ cd r7
888 911 $ echo c2 > f2
889 912 $ hg add --large f2
890 913 $ hg commit -m "m2"
891 914 Invoking status precommit hook
892 915 A f2
893 916 $ hg --config extensions.largefiles=! -R ../r6 serve -d -p $HGPORT --pid-file ../hg.pid
894 917 $ cat ../hg.pid >> $DAEMON_PIDS
895 918 $ hg push http://localhost:$HGPORT
896 919 pushing to http://localhost:$HGPORT/
897 920 searching for changes
898 921 abort: http://localhost:$HGPORT/ does not appear to be a largefile store
899 922 [255]
900 923 $ cd ..
901 924
902 925 putlfile errors are shown (issue3123)
903 926 Corrupt the cached largefile in r7
904 927 $ echo corruption > $USERCACHE/4cdac4d8b084d0b599525cf732437fb337d422a8
905 928 $ hg init empty
906 929 $ hg serve -R empty -d -p $HGPORT1 --pid-file hg.pid \
907 930 > --config 'web.allow_push=*' --config web.push_ssl=False
908 931 $ cat hg.pid >> $DAEMON_PIDS
909 932 $ hg push -R r7 http://localhost:$HGPORT1
910 933 pushing to http://localhost:$HGPORT1/
911 934 searching for changes
912 935 remote: largefiles: failed to put 4cdac4d8b084d0b599525cf732437fb337d422a8 into store: largefile contents do not match hash
913 936 abort: remotestore: could not put $TESTTMP/r7/.hg/largefiles/4cdac4d8b084d0b599525cf732437fb337d422a8 to remote store http://localhost:$HGPORT1/
914 937 [255]
915 938 $ rm -rf empty
916 939
917 940 Clone a local repository owned by another user
918 941 We have to simulate that here by setting $HOME and removing write permissions
919 942 $ ORIGHOME="$HOME"
920 943 $ mkdir alice
921 944 $ HOME="`pwd`/alice"
922 945 $ cd alice
923 946 $ hg init pubrepo
924 947 $ cd pubrepo
925 948 $ dd if=/dev/urandom bs=1k count=11k > a-large-file 2> /dev/null
926 949 $ hg add --large a-large-file
927 950 $ hg commit -m "Add a large file"
928 951 Invoking status precommit hook
929 952 A a-large-file
930 953 $ cd ..
931 954 $ chmod -R a-w pubrepo
932 955 $ cd ..
933 956 $ mkdir bob
934 957 $ HOME="`pwd`/bob"
935 958 $ cd bob
936 959 $ hg clone --pull ../alice/pubrepo pubrepo
937 960 requesting all changes
938 961 adding changesets
939 962 adding manifests
940 963 adding file changes
941 964 added 1 changesets with 1 changes to 1 files
942 965 updating to branch default
943 966 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
944 967 getting changed largefiles
945 968 1 largefiles updated, 0 removed
946 969 $ cd ..
947 970 $ chmod -R u+w alice/pubrepo
948 971 $ HOME="$ORIGHOME"
949 972
950 973 Symlink to a large largefile should behave the same as a symlink to a normal file
951 974 $ hg init largesymlink
952 975 $ cd largesymlink
953 976 $ dd if=/dev/zero bs=1k count=10k of=largefile 2>/dev/null
954 977 $ hg add --large largefile
955 978 $ hg commit -m "commit a large file"
956 979 Invoking status precommit hook
957 980 A largefile
958 981 $ ln -s largefile largelink
959 982 $ hg add largelink
960 983 $ hg commit -m "commit a large symlink"
961 984 Invoking status precommit hook
962 985 A largelink
963 986 $ rm -f largelink
964 987 $ hg up >/dev/null
965 988 $ test -f largelink
966 989 [1]
967 990 $ test -L largelink
968 991 [1]
969 992 $ rm -f largelink # make next part of the test independent of the previous
970 993 $ hg up -C >/dev/null
971 994 $ test -f largelink
972 995 $ test -L largelink
973 996 $ cd ..
974 997
975 998 test for pattern matching on 'hg status':
976 999 to boost performance, largefiles checks whether specified patterns are
977 1000 related to largefiles in working directory (NOT to STANDIN) or not.
978 1001
979 1002 $ hg init statusmatch
980 1003 $ cd statusmatch
981 1004
982 1005 $ mkdir -p a/b/c/d
983 1006 $ echo normal > a/b/c/d/e.normal.txt
984 1007 $ hg add a/b/c/d/e.normal.txt
985 1008 $ echo large > a/b/c/d/e.large.txt
986 1009 $ hg add --large a/b/c/d/e.large.txt
987 1010 $ mkdir -p a/b/c/x
988 1011 $ echo normal > a/b/c/x/y.normal.txt
989 1012 $ hg add a/b/c/x/y.normal.txt
990 1013 $ hg commit -m 'add files'
991 1014 Invoking status precommit hook
992 1015 A a/b/c/d/e.large.txt
993 1016 A a/b/c/d/e.normal.txt
994 1017 A a/b/c/x/y.normal.txt
995 1018
996 1019 (1) no pattern: no performance boost
997 1020 $ hg status -A
998 1021 C a/b/c/d/e.large.txt
999 1022 C a/b/c/d/e.normal.txt
1000 1023 C a/b/c/x/y.normal.txt
1001 1024
1002 1025 (2) pattern not related to largefiles: performance boost
1003 1026 $ hg status -A a/b/c/x
1004 1027 C a/b/c/x/y.normal.txt
1005 1028
1006 1029 (3) pattern related to largefiles: no performance boost
1007 1030 $ hg status -A a/b/c/d
1008 1031 C a/b/c/d/e.large.txt
1009 1032 C a/b/c/d/e.normal.txt
1010 1033
1011 1034 (4) pattern related to STANDIN (not to largefiles): performance boost
1012 1035 $ hg status -A .hglf/a
1013 1036 C .hglf/a/b/c/d/e.large.txt
1014 1037
1015 1038 (5) mixed case: no performance boost
1016 1039 $ hg status -A a/b/c/x a/b/c/d
1017 1040 C a/b/c/d/e.large.txt
1018 1041 C a/b/c/d/e.normal.txt
1019 1042 C a/b/c/x/y.normal.txt
1020 1043
1021 1044 verify that largefiles doesn't break filesets
1022 1045
1023 1046 $ hg log --rev . --exclude "set:binary()"
1024 1047 changeset: 0:41bd42f10efa
1025 1048 tag: tip
1026 1049 user: test
1027 1050 date: Thu Jan 01 00:00:00 1970 +0000
1028 1051 summary: add files
1029 1052
1030 1053
1031 1054 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now