##// END OF EJS Templates
largefiles: fix largefiles+subrepo update (issue3752)...
Benoit Boissinot -
r18459:c9db897d stable
parent child Browse files
Show More
@@ -1,1163 +1,1163 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, discovery
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) and not lfutil.isstandin(f):
85 85 wfile = repo.wjoin(f)
86 86
87 87 # In case the file was removed previously, but not committed
88 88 # (issue3507)
89 89 if not os.path.exists(wfile):
90 90 continue
91 91
92 92 abovemin = (lfsize and
93 93 os.lstat(wfile).st_size >= lfsize * 1024 * 1024)
94 94 if large or abovemin or (lfmatcher and lfmatcher(f)):
95 95 lfnames.append(f)
96 96 if ui.verbose or not exact:
97 97 ui.status(_('adding %s as a largefile\n') % m.rel(f))
98 98
99 99 bad = []
100 100 standins = []
101 101
102 102 # Need to lock, otherwise there could be a race condition between
103 103 # when standins are created and added to the repo.
104 104 wlock = repo.wlock()
105 105 try:
106 106 if not opts.get('dry_run'):
107 107 lfdirstate = lfutil.openlfdirstate(ui, repo)
108 108 for f in lfnames:
109 109 standinname = lfutil.standin(f)
110 110 lfutil.writestandin(repo, standinname, hash='',
111 111 executable=lfutil.getexecutable(repo.wjoin(f)))
112 112 standins.append(standinname)
113 113 if lfdirstate[f] == 'r':
114 114 lfdirstate.normallookup(f)
115 115 else:
116 116 lfdirstate.add(f)
117 117 lfdirstate.write()
118 118 bad += [lfutil.splitstandin(f)
119 119 for f in repo[None].add(standins)
120 120 if f in m.files()]
121 121 finally:
122 122 wlock.release()
123 123 return bad
124 124
125 125 def removelargefiles(ui, repo, *pats, **opts):
126 126 after = opts.get('after')
127 127 if not pats and not after:
128 128 raise util.Abort(_('no files specified'))
129 129 m = scmutil.match(repo[None], pats, opts)
130 130 try:
131 131 repo.lfstatus = True
132 132 s = repo.status(match=m, clean=True)
133 133 finally:
134 134 repo.lfstatus = False
135 135 manifest = repo[None].manifest()
136 136 modified, added, deleted, clean = [[f for f in list
137 137 if lfutil.standin(f) in manifest]
138 138 for list in [s[0], s[1], s[3], s[6]]]
139 139
140 140 def warn(files, msg):
141 141 for f in files:
142 142 ui.warn(msg % m.rel(f))
143 143 return int(len(files) > 0)
144 144
145 145 result = 0
146 146
147 147 if after:
148 148 remove, forget = deleted, []
149 149 result = warn(modified + added + clean,
150 150 _('not removing %s: file still exists\n'))
151 151 else:
152 152 remove, forget = deleted + clean, []
153 153 result = warn(modified, _('not removing %s: file is modified (use -f'
154 154 ' to force removal)\n'))
155 155 result = warn(added, _('not removing %s: file has been marked for add'
156 156 ' (use forget to undo)\n')) or result
157 157
158 158 for f in sorted(remove + forget):
159 159 if ui.verbose or not m.exact(f):
160 160 ui.status(_('removing %s\n') % m.rel(f))
161 161
162 162 # Need to lock because standin files are deleted then removed from the
163 163 # repository and we could race in-between.
164 164 wlock = repo.wlock()
165 165 try:
166 166 lfdirstate = lfutil.openlfdirstate(ui, repo)
167 167 for f in remove:
168 168 if not after:
169 169 # If this is being called by addremove, notify the user that we
170 170 # are removing the file.
171 171 if getattr(repo, "_isaddremove", False):
172 172 ui.status(_('removing %s\n') % f)
173 173 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
174 174 lfdirstate.remove(f)
175 175 lfdirstate.write()
176 176 forget = [lfutil.standin(f) for f in forget]
177 177 remove = [lfutil.standin(f) for f in remove]
178 178 repo[None].forget(forget)
179 179 # If this is being called by addremove, let the original addremove
180 180 # function handle this.
181 181 if not getattr(repo, "_isaddremove", False):
182 182 for f in remove:
183 183 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
184 184 repo[None].forget(remove)
185 185 finally:
186 186 wlock.release()
187 187
188 188 return result
189 189
190 190 # For overriding mercurial.hgweb.webcommands so that largefiles will
191 191 # appear at their right place in the manifests.
192 192 def decodepath(orig, path):
193 193 return lfutil.splitstandin(path) or path
194 194
195 195 # -- Wrappers: modify existing commands --------------------------------
196 196
197 197 # Add works by going through the files that the user wanted to add and
198 198 # checking if they should be added as largefiles. Then it makes a new
199 199 # matcher which matches only the normal files and runs the original
200 200 # version of add.
201 201 def overrideadd(orig, ui, repo, *pats, **opts):
202 202 normal = opts.pop('normal')
203 203 if normal:
204 204 if opts.get('large'):
205 205 raise util.Abort(_('--normal cannot be used with --large'))
206 206 return orig(ui, repo, *pats, **opts)
207 207 bad = addlargefiles(ui, repo, *pats, **opts)
208 208 installnormalfilesmatchfn(repo[None].manifest())
209 209 result = orig(ui, repo, *pats, **opts)
210 210 restorematchfn()
211 211
212 212 return (result == 1 or bad) and 1 or 0
213 213
214 214 def overrideremove(orig, ui, repo, *pats, **opts):
215 215 installnormalfilesmatchfn(repo[None].manifest())
216 216 result = orig(ui, repo, *pats, **opts)
217 217 restorematchfn()
218 218 return removelargefiles(ui, repo, *pats, **opts) or result
219 219
220 220 def overridestatusfn(orig, repo, rev2, **opts):
221 221 try:
222 222 repo._repo.lfstatus = True
223 223 return orig(repo, rev2, **opts)
224 224 finally:
225 225 repo._repo.lfstatus = False
226 226
227 227 def overridestatus(orig, ui, repo, *pats, **opts):
228 228 try:
229 229 repo.lfstatus = True
230 230 return orig(ui, repo, *pats, **opts)
231 231 finally:
232 232 repo.lfstatus = False
233 233
234 234 def overridedirty(orig, repo, ignoreupdate=False):
235 235 try:
236 236 repo._repo.lfstatus = True
237 237 return orig(repo, ignoreupdate)
238 238 finally:
239 239 repo._repo.lfstatus = False
240 240
241 241 def overridelog(orig, ui, repo, *pats, **opts):
242 242 def overridematch(ctx, pats=[], opts={}, globbed=False,
243 243 default='relpath'):
244 244 """Matcher that merges root directory with .hglf, suitable for log.
245 245 It is still possible to match .hglf directly.
246 246 For any listed files run log on the standin too.
247 247 matchfn tries both the given filename and with .hglf stripped.
248 248 """
249 249 match = oldmatch(ctx, pats, opts, globbed, default)
250 250 m = copy.copy(match)
251 251 standins = [lfutil.standin(f) for f in m._files]
252 252 m._files.extend(standins)
253 253 m._fmap = set(m._files)
254 254 origmatchfn = m.matchfn
255 255 def lfmatchfn(f):
256 256 lf = lfutil.splitstandin(f)
257 257 if lf is not None and origmatchfn(lf):
258 258 return True
259 259 r = origmatchfn(f)
260 260 return r
261 261 m.matchfn = lfmatchfn
262 262 return m
263 263 oldmatch = installmatchfn(overridematch)
264 264 try:
265 265 repo.lfstatus = True
266 266 return orig(ui, repo, *pats, **opts)
267 267 finally:
268 268 repo.lfstatus = False
269 269 restorematchfn()
270 270
271 271 def overrideverify(orig, ui, repo, *pats, **opts):
272 272 large = opts.pop('large', False)
273 273 all = opts.pop('lfa', False)
274 274 contents = opts.pop('lfc', False)
275 275
276 276 result = orig(ui, repo, *pats, **opts)
277 277 if large:
278 278 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
279 279 return result
280 280
281 281 def overridedebugstate(orig, ui, repo, *pats, **opts):
282 282 large = opts.pop('large', False)
283 283 if large:
284 284 lfcommands.debugdirstate(ui, repo)
285 285 else:
286 286 orig(ui, repo, *pats, **opts)
287 287
288 288 # Override needs to refresh standins so that update's normal merge
289 289 # will go through properly. Then the other update hook (overriding repo.update)
290 290 # will get the new files. Filemerge is also overridden so that the merge
291 291 # will merge standins correctly.
292 292 def overrideupdate(orig, ui, repo, *pats, **opts):
293 293 lfdirstate = lfutil.openlfdirstate(ui, repo)
294 294 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
295 295 False, False)
296 296 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
297 297
298 298 # Need to lock between the standins getting updated and their
299 299 # largefiles getting updated
300 300 wlock = repo.wlock()
301 301 try:
302 302 if opts['check']:
303 303 mod = len(modified) > 0
304 304 for lfile in unsure:
305 305 standin = lfutil.standin(lfile)
306 306 if repo['.'][standin].data().strip() != \
307 307 lfutil.hashfile(repo.wjoin(lfile)):
308 308 mod = True
309 309 else:
310 310 lfdirstate.normal(lfile)
311 311 lfdirstate.write()
312 312 if mod:
313 313 raise util.Abort(_('uncommitted local changes'))
314 314 # XXX handle removed differently
315 315 if not opts['clean']:
316 316 for lfile in unsure + modified + added:
317 317 lfutil.updatestandin(repo, lfutil.standin(lfile))
318 318 finally:
319 319 wlock.release()
320 320 return orig(ui, repo, *pats, **opts)
321 321
322 322 # Before starting the manifest merge, merge.updates will call
323 323 # _checkunknown to check if there are any files in the merged-in
324 324 # changeset that collide with unknown files in the working copy.
325 325 #
326 326 # The largefiles are seen as unknown, so this prevents us from merging
327 327 # in a file 'foo' if we already have a largefile with the same name.
328 328 #
329 329 # The overridden function filters the unknown files by removing any
330 330 # largefiles. This makes the merge proceed and we can then handle this
331 331 # case further in the overridden manifestmerge function below.
332 332 def overridecheckunknownfile(origfn, repo, wctx, mctx, f):
333 333 if lfutil.standin(f) in wctx:
334 334 return False
335 335 return origfn(repo, wctx, mctx, f)
336 336
337 337 # The manifest merge handles conflicts on the manifest level. We want
338 338 # to handle changes in largefile-ness of files at this level too.
339 339 #
340 340 # The strategy is to run the original manifestmerge and then process
341 341 # the action list it outputs. There are two cases we need to deal with:
342 342 #
343 343 # 1. Normal file in p1, largefile in p2. Here the largefile is
344 344 # detected via its standin file, which will enter the working copy
345 345 # with a "get" action. It is not "merge" since the standin is all
346 346 # Mercurial is concerned with at this level -- the link to the
347 347 # existing normal file is not relevant here.
348 348 #
349 349 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
350 350 # since the largefile will be present in the working copy and
351 351 # different from the normal file in p2. Mercurial therefore
352 352 # triggers a merge action.
353 353 #
354 354 # In both cases, we prompt the user and emit new actions to either
355 355 # remove the standin (if the normal file was kept) or to remove the
356 356 # normal file and get the standin (if the largefile was kept). The
357 357 # default prompt answer is to use the largefile version since it was
358 358 # presumably changed on purpose.
359 359 #
360 360 # Finally, the merge.applyupdates function will then take care of
361 361 # writing the files into the working copy and lfcommands.updatelfiles
362 362 # will update the largefiles.
363 363 def overridemanifestmerge(origfn, repo, p1, p2, pa, overwrite, partial):
364 364 actions = origfn(repo, p1, p2, pa, overwrite, partial)
365 365 processed = []
366 366
367 367 for action in actions:
368 368 if overwrite:
369 369 processed.append(action)
370 370 continue
371 371 f, m = action[:2]
372 372
373 373 choices = (_('&Largefile'), _('&Normal file'))
374 374 if m == "g" and lfutil.splitstandin(f) in p1 and f in p2:
375 375 # Case 1: normal file in the working copy, largefile in
376 376 # the second parent
377 377 lfile = lfutil.splitstandin(f)
378 378 standin = f
379 379 msg = _('%s has been turned into a largefile\n'
380 380 'use (l)argefile or keep as (n)ormal file?') % lfile
381 381 if repo.ui.promptchoice(msg, choices, 0) == 0:
382 382 processed.append((lfile, "r"))
383 383 processed.append((standin, "g", p2.flags(standin)))
384 384 else:
385 385 processed.append((standin, "r"))
386 386 elif m == "g" and lfutil.standin(f) in p1 and f in p2:
387 387 # Case 2: largefile in the working copy, normal file in
388 388 # the second parent
389 389 standin = lfutil.standin(f)
390 390 lfile = f
391 391 msg = _('%s has been turned into a normal file\n'
392 392 'keep as (l)argefile or use (n)ormal file?') % lfile
393 393 if repo.ui.promptchoice(msg, choices, 0) == 0:
394 394 processed.append((lfile, "r"))
395 395 else:
396 396 processed.append((standin, "r"))
397 397 processed.append((lfile, "g", p2.flags(lfile)))
398 398 else:
399 399 processed.append(action)
400 400
401 401 return processed
402 402
403 403 # Override filemerge to prompt the user about how they wish to merge
404 404 # largefiles. This will handle identical edits, and copy/rename +
405 405 # edit without prompting the user.
406 406 def overridefilemerge(origfn, repo, mynode, orig, fcd, fco, fca):
407 407 # Use better variable names here. Because this is a wrapper we cannot
408 408 # change the variable names in the function declaration.
409 409 fcdest, fcother, fcancestor = fcd, fco, fca
410 410 if not lfutil.isstandin(orig):
411 411 return origfn(repo, mynode, orig, fcdest, fcother, fcancestor)
412 412 else:
413 413 if not fcother.cmp(fcdest): # files identical?
414 414 return None
415 415
416 416 # backwards, use working dir parent as ancestor
417 417 if fcancestor == fcother:
418 418 fcancestor = fcdest.parents()[0]
419 419
420 420 if orig != fcother.path():
421 421 repo.ui.status(_('merging %s and %s to %s\n')
422 422 % (lfutil.splitstandin(orig),
423 423 lfutil.splitstandin(fcother.path()),
424 424 lfutil.splitstandin(fcdest.path())))
425 425 else:
426 426 repo.ui.status(_('merging %s\n')
427 427 % lfutil.splitstandin(fcdest.path()))
428 428
429 429 if fcancestor.path() != fcother.path() and fcother.data() == \
430 430 fcancestor.data():
431 431 return 0
432 432 if fcancestor.path() != fcdest.path() and fcdest.data() == \
433 433 fcancestor.data():
434 434 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
435 435 return 0
436 436
437 437 if repo.ui.promptchoice(_('largefile %s has a merge conflict\n'
438 438 'keep (l)ocal or take (o)ther?') %
439 439 lfutil.splitstandin(orig),
440 440 (_('&Local'), _('&Other')), 0) == 0:
441 441 return 0
442 442 else:
443 443 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
444 444 return 0
445 445
446 446 # Copy first changes the matchers to match standins instead of
447 447 # largefiles. Then it overrides util.copyfile in that function it
448 448 # checks if the destination largefile already exists. It also keeps a
449 449 # list of copied files so that the largefiles can be copied and the
450 450 # dirstate updated.
451 451 def overridecopy(orig, ui, repo, pats, opts, rename=False):
452 452 # doesn't remove largefile on rename
453 453 if len(pats) < 2:
454 454 # this isn't legal, let the original function deal with it
455 455 return orig(ui, repo, pats, opts, rename)
456 456
457 457 def makestandin(relpath):
458 458 path = scmutil.canonpath(repo.root, repo.getcwd(), relpath)
459 459 return os.path.join(repo.wjoin(lfutil.standin(path)))
460 460
461 461 fullpats = scmutil.expandpats(pats)
462 462 dest = fullpats[-1]
463 463
464 464 if os.path.isdir(dest):
465 465 if not os.path.isdir(makestandin(dest)):
466 466 os.makedirs(makestandin(dest))
467 467 # This could copy both lfiles and normal files in one command,
468 468 # but we don't want to do that. First replace their matcher to
469 469 # only match normal files and run it, then replace it to just
470 470 # match largefiles and run it again.
471 471 nonormalfiles = False
472 472 nolfiles = False
473 473 try:
474 474 try:
475 475 installnormalfilesmatchfn(repo[None].manifest())
476 476 result = orig(ui, repo, pats, opts, rename)
477 477 except util.Abort, e:
478 478 if str(e) != _('no files to copy'):
479 479 raise e
480 480 else:
481 481 nonormalfiles = True
482 482 result = 0
483 483 finally:
484 484 restorematchfn()
485 485
486 486 # The first rename can cause our current working directory to be removed.
487 487 # In that case there is nothing left to copy/rename so just quit.
488 488 try:
489 489 repo.getcwd()
490 490 except OSError:
491 491 return result
492 492
493 493 try:
494 494 try:
495 495 # When we call orig below it creates the standins but we don't add
496 496 # them to the dir state until later so lock during that time.
497 497 wlock = repo.wlock()
498 498
499 499 manifest = repo[None].manifest()
500 500 oldmatch = None # for the closure
501 501 def overridematch(ctx, pats=[], opts={}, globbed=False,
502 502 default='relpath'):
503 503 newpats = []
504 504 # The patterns were previously mangled to add the standin
505 505 # directory; we need to remove that now
506 506 for pat in pats:
507 507 if match_.patkind(pat) is None and lfutil.shortname in pat:
508 508 newpats.append(pat.replace(lfutil.shortname, ''))
509 509 else:
510 510 newpats.append(pat)
511 511 match = oldmatch(ctx, newpats, opts, globbed, default)
512 512 m = copy.copy(match)
513 513 lfile = lambda f: lfutil.standin(f) in manifest
514 514 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
515 515 m._fmap = set(m._files)
516 516 origmatchfn = m.matchfn
517 517 m.matchfn = lambda f: (lfutil.isstandin(f) and
518 518 (f in manifest) and
519 519 origmatchfn(lfutil.splitstandin(f)) or
520 520 None)
521 521 return m
522 522 oldmatch = installmatchfn(overridematch)
523 523 listpats = []
524 524 for pat in pats:
525 525 if match_.patkind(pat) is not None:
526 526 listpats.append(pat)
527 527 else:
528 528 listpats.append(makestandin(pat))
529 529
530 530 try:
531 531 origcopyfile = util.copyfile
532 532 copiedfiles = []
533 533 def overridecopyfile(src, dest):
534 534 if (lfutil.shortname in src and
535 535 dest.startswith(repo.wjoin(lfutil.shortname))):
536 536 destlfile = dest.replace(lfutil.shortname, '')
537 537 if not opts['force'] and os.path.exists(destlfile):
538 538 raise IOError('',
539 539 _('destination largefile already exists'))
540 540 copiedfiles.append((src, dest))
541 541 origcopyfile(src, dest)
542 542
543 543 util.copyfile = overridecopyfile
544 544 result += orig(ui, repo, listpats, opts, rename)
545 545 finally:
546 546 util.copyfile = origcopyfile
547 547
548 548 lfdirstate = lfutil.openlfdirstate(ui, repo)
549 549 for (src, dest) in copiedfiles:
550 550 if (lfutil.shortname in src and
551 551 dest.startswith(repo.wjoin(lfutil.shortname))):
552 552 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
553 553 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
554 554 destlfiledir = os.path.dirname(repo.wjoin(destlfile)) or '.'
555 555 if not os.path.isdir(destlfiledir):
556 556 os.makedirs(destlfiledir)
557 557 if rename:
558 558 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
559 559 lfdirstate.remove(srclfile)
560 560 else:
561 561 util.copyfile(repo.wjoin(srclfile),
562 562 repo.wjoin(destlfile))
563 563
564 564 lfdirstate.add(destlfile)
565 565 lfdirstate.write()
566 566 except util.Abort, e:
567 567 if str(e) != _('no files to copy'):
568 568 raise e
569 569 else:
570 570 nolfiles = True
571 571 finally:
572 572 restorematchfn()
573 573 wlock.release()
574 574
575 575 if nolfiles and nonormalfiles:
576 576 raise util.Abort(_('no files to copy'))
577 577
578 578 return result
579 579
580 580 # When the user calls revert, we have to be careful to not revert any
581 581 # changes to other largefiles accidentally. This means we have to keep
582 582 # track of the largefiles that are being reverted so we only pull down
583 583 # the necessary largefiles.
584 584 #
585 585 # Standins are only updated (to match the hash of largefiles) before
586 586 # commits. Update the standins then run the original revert, changing
587 587 # the matcher to hit standins instead of largefiles. Based on the
588 588 # resulting standins update the largefiles. Then return the standins
589 589 # to their proper state
590 590 def overriderevert(orig, ui, repo, *pats, **opts):
591 591 # Because we put the standins in a bad state (by updating them)
592 592 # and then return them to a correct state we need to lock to
593 593 # prevent others from changing them in their incorrect state.
594 594 wlock = repo.wlock()
595 595 try:
596 596 lfdirstate = lfutil.openlfdirstate(ui, repo)
597 597 (modified, added, removed, missing, unknown, ignored, clean) = \
598 598 lfutil.lfdirstatestatus(lfdirstate, repo, repo['.'].rev())
599 599 lfdirstate.write()
600 600 for lfile in modified:
601 601 lfutil.updatestandin(repo, lfutil.standin(lfile))
602 602 for lfile in missing:
603 603 if (os.path.exists(repo.wjoin(lfutil.standin(lfile)))):
604 604 os.unlink(repo.wjoin(lfutil.standin(lfile)))
605 605
606 606 try:
607 607 ctx = scmutil.revsingle(repo, opts.get('rev'))
608 608 oldmatch = None # for the closure
609 609 def overridematch(ctx, pats=[], opts={}, globbed=False,
610 610 default='relpath'):
611 611 match = oldmatch(ctx, pats, opts, globbed, default)
612 612 m = copy.copy(match)
613 613 def tostandin(f):
614 614 if lfutil.standin(f) in ctx:
615 615 return lfutil.standin(f)
616 616 elif lfutil.standin(f) in repo[None]:
617 617 return None
618 618 return f
619 619 m._files = [tostandin(f) for f in m._files]
620 620 m._files = [f for f in m._files if f is not None]
621 621 m._fmap = set(m._files)
622 622 origmatchfn = m.matchfn
623 623 def matchfn(f):
624 624 if lfutil.isstandin(f):
625 625 # We need to keep track of what largefiles are being
626 626 # matched so we know which ones to update later --
627 627 # otherwise we accidentally revert changes to other
628 628 # largefiles. This is repo-specific, so duckpunch the
629 629 # repo object to keep the list of largefiles for us
630 630 # later.
631 631 if origmatchfn(lfutil.splitstandin(f)) and \
632 632 (f in repo[None] or f in ctx):
633 633 lfileslist = getattr(repo, '_lfilestoupdate', [])
634 634 lfileslist.append(lfutil.splitstandin(f))
635 635 repo._lfilestoupdate = lfileslist
636 636 return True
637 637 else:
638 638 return False
639 639 return origmatchfn(f)
640 640 m.matchfn = matchfn
641 641 return m
642 642 oldmatch = installmatchfn(overridematch)
643 643 scmutil.match
644 644 matches = overridematch(repo[None], pats, opts)
645 645 orig(ui, repo, *pats, **opts)
646 646 finally:
647 647 restorematchfn()
648 648 lfileslist = getattr(repo, '_lfilestoupdate', [])
649 649 lfcommands.updatelfiles(ui, repo, filelist=lfileslist,
650 650 printmessage=False)
651 651
652 652 # empty out the largefiles list so we start fresh next time
653 653 repo._lfilestoupdate = []
654 654 for lfile in modified:
655 655 if lfile in lfileslist:
656 656 if os.path.exists(repo.wjoin(lfutil.standin(lfile))) and lfile\
657 657 in repo['.']:
658 658 lfutil.writestandin(repo, lfutil.standin(lfile),
659 659 repo['.'][lfile].data().strip(),
660 660 'x' in repo['.'][lfile].flags())
661 661 lfdirstate = lfutil.openlfdirstate(ui, repo)
662 662 for lfile in added:
663 663 standin = lfutil.standin(lfile)
664 664 if standin not in ctx and (standin in matches or opts.get('all')):
665 665 if lfile in lfdirstate:
666 666 lfdirstate.drop(lfile)
667 667 util.unlinkpath(repo.wjoin(standin))
668 668 lfdirstate.write()
669 669 finally:
670 670 wlock.release()
671 671
672 def hgupdate(orig, repo, node):
673 # Only call updatelfiles the standins that have changed to save time
674 oldstandins = lfutil.getstandinsstate(repo)
675 result = orig(repo, node)
676 newstandins = lfutil.getstandinsstate(repo)
677 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
678 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist, printmessage=True)
679 return result
672 def hgupdaterepo(orig, repo, node, overwrite):
673 if not overwrite:
674 # Only call updatelfiles on the standins that have changed to save time
675 oldstandins = lfutil.getstandinsstate(repo)
680 676
681 def hgclean(orig, repo, node, show_stats=True):
682 result = orig(repo, node, show_stats)
683 lfcommands.updatelfiles(repo.ui, repo)
677 result = orig(repo, node, overwrite)
678
679 filelist = None
680 if not overwrite:
681 newstandins = lfutil.getstandinsstate(repo)
682 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
683 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist)
684 684 return result
685 685
686 686 def hgmerge(orig, repo, node, force=None, remind=True):
687 687 # Mark the repo as being in the middle of a merge, so that
688 688 # updatelfiles() will know that it needs to trust the standins in
689 689 # the working copy, not in the standins in the current node
690 690 repo._ismerging = True
691 691 try:
692 692 result = orig(repo, node, force, remind)
693 693 lfcommands.updatelfiles(repo.ui, repo)
694 694 finally:
695 695 repo._ismerging = False
696 696 return result
697 697
698 698 # When we rebase a repository with remotely changed largefiles, we need to
699 699 # take some extra care so that the largefiles are correctly updated in the
700 700 # working copy
701 701 def overridepull(orig, ui, repo, source=None, **opts):
702 702 revsprepull = len(repo)
703 703 if opts.get('rebase', False):
704 704 repo._isrebasing = True
705 705 try:
706 706 if opts.get('update'):
707 707 del opts['update']
708 708 ui.debug('--update and --rebase are not compatible, ignoring '
709 709 'the update flag\n')
710 710 del opts['rebase']
711 711 cmdutil.bailifchanged(repo)
712 712 origpostincoming = commands.postincoming
713 713 def _dummy(*args, **kwargs):
714 714 pass
715 715 commands.postincoming = _dummy
716 716 if not source:
717 717 source = 'default'
718 718 repo.lfpullsource = source
719 719 try:
720 720 result = commands.pull(ui, repo, source, **opts)
721 721 finally:
722 722 commands.postincoming = origpostincoming
723 723 revspostpull = len(repo)
724 724 if revspostpull > revsprepull:
725 725 result = result or rebase.rebase(ui, repo)
726 726 finally:
727 727 repo._isrebasing = False
728 728 else:
729 729 if not source:
730 730 source = 'default'
731 731 repo.lfpullsource = source
732 732 oldheads = lfutil.getcurrentheads(repo)
733 733 result = orig(ui, repo, source, **opts)
734 734 # If we do not have the new largefiles for any new heads we pulled, we
735 735 # will run into a problem later if we try to merge or rebase with one of
736 736 # these heads, so cache the largefiles now directly into the system
737 737 # cache.
738 738 ui.status(_("caching new largefiles\n"))
739 739 numcached = 0
740 740 heads = lfutil.getcurrentheads(repo)
741 741 newheads = set(heads).difference(set(oldheads))
742 742 for head in newheads:
743 743 (cached, missing) = lfcommands.cachelfiles(ui, repo, head)
744 744 numcached += len(cached)
745 745 ui.status(_("%d largefiles cached\n") % numcached)
746 746 if opts.get('all_largefiles'):
747 747 revspostpull = len(repo)
748 748 revs = []
749 749 for rev in xrange(revsprepull + 1, revspostpull):
750 750 revs.append(repo[rev].rev())
751 751 lfcommands.downloadlfiles(ui, repo, revs)
752 752 return result
753 753
754 754 def overrideclone(orig, ui, source, dest=None, **opts):
755 755 d = dest
756 756 if d is None:
757 757 d = hg.defaultdest(source)
758 758 if opts.get('all_largefiles') and not hg.islocal(d):
759 759 raise util.Abort(_(
760 760 '--all-largefiles is incompatible with non-local destination %s' %
761 761 d))
762 762
763 763 return orig(ui, source, dest, **opts)
764 764
765 765 def hgclone(orig, ui, opts, *args, **kwargs):
766 766 result = orig(ui, opts, *args, **kwargs)
767 767
768 768 if result is not None:
769 769 sourcerepo, destrepo = result
770 770 repo = destrepo.local()
771 771
772 772 # The .hglf directory must exist for the standin matcher to match
773 773 # anything (which listlfiles uses for each rev), and .hg/largefiles is
774 774 # assumed to exist by the code that caches the downloaded file. These
775 775 # directories exist if clone updated to any rev. (If the repo does not
776 776 # have largefiles, download never gets to the point of needing
777 777 # .hg/largefiles, and the standin matcher won't match anything anyway.)
778 778 if 'largefiles' in repo.requirements:
779 779 if opts.get('noupdate'):
780 780 util.makedirs(repo.wjoin(lfutil.shortname))
781 781 util.makedirs(repo.join(lfutil.longname))
782 782
783 783 # Caching is implicitly limited to 'rev' option, since the dest repo was
784 784 # truncated at that point. The user may expect a download count with
785 785 # this option, so attempt whether or not this is a largefile repo.
786 786 if opts.get('all_largefiles'):
787 787 success, missing = lfcommands.downloadlfiles(ui, repo, None)
788 788
789 789 if missing != 0:
790 790 return None
791 791
792 792 return result
793 793
794 794 def overriderebase(orig, ui, repo, **opts):
795 795 repo._isrebasing = True
796 796 try:
797 797 return orig(ui, repo, **opts)
798 798 finally:
799 799 repo._isrebasing = False
800 800
801 801 def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None,
802 802 prefix=None, mtime=None, subrepos=None):
803 803 # No need to lock because we are only reading history and
804 804 # largefile caches, neither of which are modified.
805 805 lfcommands.cachelfiles(repo.ui, repo, node)
806 806
807 807 if kind not in archival.archivers:
808 808 raise util.Abort(_("unknown archive type '%s'") % kind)
809 809
810 810 ctx = repo[node]
811 811
812 812 if kind == 'files':
813 813 if prefix:
814 814 raise util.Abort(
815 815 _('cannot give prefix when archiving to files'))
816 816 else:
817 817 prefix = archival.tidyprefix(dest, kind, prefix)
818 818
819 819 def write(name, mode, islink, getdata):
820 820 if matchfn and not matchfn(name):
821 821 return
822 822 data = getdata()
823 823 if decode:
824 824 data = repo.wwritedata(name, data)
825 825 archiver.addfile(prefix + name, mode, islink, data)
826 826
827 827 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
828 828
829 829 if repo.ui.configbool("ui", "archivemeta", True):
830 830 def metadata():
831 831 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
832 832 hex(repo.changelog.node(0)), hex(node), ctx.branch())
833 833
834 834 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
835 835 if repo.tagtype(t) == 'global')
836 836 if not tags:
837 837 repo.ui.pushbuffer()
838 838 opts = {'template': '{latesttag}\n{latesttagdistance}',
839 839 'style': '', 'patch': None, 'git': None}
840 840 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
841 841 ltags, dist = repo.ui.popbuffer().split('\n')
842 842 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
843 843 tags += 'latesttagdistance: %s\n' % dist
844 844
845 845 return base + tags
846 846
847 847 write('.hg_archival.txt', 0644, False, metadata)
848 848
849 849 for f in ctx:
850 850 ff = ctx.flags(f)
851 851 getdata = ctx[f].data
852 852 if lfutil.isstandin(f):
853 853 path = lfutil.findfile(repo, getdata().strip())
854 854 if path is None:
855 855 raise util.Abort(
856 856 _('largefile %s not found in repo store or system cache')
857 857 % lfutil.splitstandin(f))
858 858 f = lfutil.splitstandin(f)
859 859
860 860 def getdatafn():
861 861 fd = None
862 862 try:
863 863 fd = open(path, 'rb')
864 864 return fd.read()
865 865 finally:
866 866 if fd:
867 867 fd.close()
868 868
869 869 getdata = getdatafn
870 870 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
871 871
872 872 if subrepos:
873 873 for subpath in sorted(ctx.substate):
874 874 sub = ctx.sub(subpath)
875 875 submatch = match_.narrowmatcher(subpath, matchfn)
876 876 sub.archive(repo.ui, archiver, prefix, submatch)
877 877
878 878 archiver.done()
879 879
880 880 def hgsubrepoarchive(orig, repo, ui, archiver, prefix, match=None):
881 881 repo._get(repo._state + ('hg',))
882 882 rev = repo._state[1]
883 883 ctx = repo._repo[rev]
884 884
885 885 lfcommands.cachelfiles(ui, repo._repo, ctx.node())
886 886
887 887 def write(name, mode, islink, getdata):
888 888 # At this point, the standin has been replaced with the largefile name,
889 889 # so the normal matcher works here without the lfutil variants.
890 890 if match and not match(f):
891 891 return
892 892 data = getdata()
893 893
894 894 archiver.addfile(prefix + repo._path + '/' + name, mode, islink, data)
895 895
896 896 for f in ctx:
897 897 ff = ctx.flags(f)
898 898 getdata = ctx[f].data
899 899 if lfutil.isstandin(f):
900 900 path = lfutil.findfile(repo._repo, getdata().strip())
901 901 if path is None:
902 902 raise util.Abort(
903 903 _('largefile %s not found in repo store or system cache')
904 904 % lfutil.splitstandin(f))
905 905 f = lfutil.splitstandin(f)
906 906
907 907 def getdatafn():
908 908 fd = None
909 909 try:
910 910 fd = open(os.path.join(prefix, path), 'rb')
911 911 return fd.read()
912 912 finally:
913 913 if fd:
914 914 fd.close()
915 915
916 916 getdata = getdatafn
917 917
918 918 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
919 919
920 920 for subpath in sorted(ctx.substate):
921 921 sub = ctx.sub(subpath)
922 922 submatch = match_.narrowmatcher(subpath, match)
923 923 sub.archive(ui, archiver, os.path.join(prefix, repo._path) + '/',
924 924 submatch)
925 925
926 926 # If a largefile is modified, the change is not reflected in its
927 927 # standin until a commit. cmdutil.bailifchanged() raises an exception
928 928 # if the repo has uncommitted changes. Wrap it to also check if
929 929 # largefiles were changed. This is used by bisect and backout.
930 930 def overridebailifchanged(orig, repo):
931 931 orig(repo)
932 932 repo.lfstatus = True
933 933 modified, added, removed, deleted = repo.status()[:4]
934 934 repo.lfstatus = False
935 935 if modified or added or removed or deleted:
936 936 raise util.Abort(_('outstanding uncommitted changes'))
937 937
938 938 # Fetch doesn't use cmdutil.bailifchanged so override it to add the check
939 939 def overridefetch(orig, ui, repo, *pats, **opts):
940 940 repo.lfstatus = True
941 941 modified, added, removed, deleted = repo.status()[:4]
942 942 repo.lfstatus = False
943 943 if modified or added or removed or deleted:
944 944 raise util.Abort(_('outstanding uncommitted changes'))
945 945 return orig(ui, repo, *pats, **opts)
946 946
947 947 def overrideforget(orig, ui, repo, *pats, **opts):
948 948 installnormalfilesmatchfn(repo[None].manifest())
949 949 result = orig(ui, repo, *pats, **opts)
950 950 restorematchfn()
951 951 m = scmutil.match(repo[None], pats, opts)
952 952
953 953 try:
954 954 repo.lfstatus = True
955 955 s = repo.status(match=m, clean=True)
956 956 finally:
957 957 repo.lfstatus = False
958 958 forget = sorted(s[0] + s[1] + s[3] + s[6])
959 959 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
960 960
961 961 for f in forget:
962 962 if lfutil.standin(f) not in repo.dirstate and not \
963 963 os.path.isdir(m.rel(lfutil.standin(f))):
964 964 ui.warn(_('not removing %s: file is already untracked\n')
965 965 % m.rel(f))
966 966 result = 1
967 967
968 968 for f in forget:
969 969 if ui.verbose or not m.exact(f):
970 970 ui.status(_('removing %s\n') % m.rel(f))
971 971
972 972 # Need to lock because standin files are deleted then removed from the
973 973 # repository and we could race in-between.
974 974 wlock = repo.wlock()
975 975 try:
976 976 lfdirstate = lfutil.openlfdirstate(ui, repo)
977 977 for f in forget:
978 978 if lfdirstate[f] == 'a':
979 979 lfdirstate.drop(f)
980 980 else:
981 981 lfdirstate.remove(f)
982 982 lfdirstate.write()
983 983 standins = [lfutil.standin(f) for f in forget]
984 984 for f in standins:
985 985 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
986 986 repo[None].forget(standins)
987 987 finally:
988 988 wlock.release()
989 989
990 990 return result
991 991
992 992 def getoutgoinglfiles(ui, repo, dest=None, **opts):
993 993 dest = ui.expandpath(dest or 'default-push', dest or 'default')
994 994 dest, branches = hg.parseurl(dest, opts.get('branch'))
995 995 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
996 996 if revs:
997 997 revs = [repo.lookup(rev) for rev in scmutil.revrange(repo, revs)]
998 998
999 999 try:
1000 1000 remote = hg.peer(repo, opts, dest)
1001 1001 except error.RepoError:
1002 1002 return None
1003 1003 outgoing = discovery.findcommonoutgoing(repo, remote.peer(), force=False)
1004 1004 if not outgoing.missing:
1005 1005 return outgoing.missing
1006 1006 o = repo.changelog.nodesbetween(outgoing.missing, revs)[0]
1007 1007 if opts.get('newest_first'):
1008 1008 o.reverse()
1009 1009
1010 1010 toupload = set()
1011 1011 for n in o:
1012 1012 parents = [p for p in repo.changelog.parents(n) if p != node.nullid]
1013 1013 ctx = repo[n]
1014 1014 files = set(ctx.files())
1015 1015 if len(parents) == 2:
1016 1016 mc = ctx.manifest()
1017 1017 mp1 = ctx.parents()[0].manifest()
1018 1018 mp2 = ctx.parents()[1].manifest()
1019 1019 for f in mp1:
1020 1020 if f not in mc:
1021 1021 files.add(f)
1022 1022 for f in mp2:
1023 1023 if f not in mc:
1024 1024 files.add(f)
1025 1025 for f in mc:
1026 1026 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None):
1027 1027 files.add(f)
1028 1028 toupload = toupload.union(
1029 1029 set([f for f in files if lfutil.isstandin(f) and f in ctx]))
1030 1030 return sorted(toupload)
1031 1031
1032 1032 def overrideoutgoing(orig, ui, repo, dest=None, **opts):
1033 1033 result = orig(ui, repo, dest, **opts)
1034 1034
1035 1035 if opts.pop('large', None):
1036 1036 toupload = getoutgoinglfiles(ui, repo, dest, **opts)
1037 1037 if toupload is None:
1038 1038 ui.status(_('largefiles: No remote repo\n'))
1039 1039 elif not toupload:
1040 1040 ui.status(_('largefiles: no files to upload\n'))
1041 1041 else:
1042 1042 ui.status(_('largefiles to upload:\n'))
1043 1043 for file in toupload:
1044 1044 ui.status(lfutil.splitstandin(file) + '\n')
1045 1045 ui.status('\n')
1046 1046
1047 1047 return result
1048 1048
1049 1049 def overridesummary(orig, ui, repo, *pats, **opts):
1050 1050 try:
1051 1051 repo.lfstatus = True
1052 1052 orig(ui, repo, *pats, **opts)
1053 1053 finally:
1054 1054 repo.lfstatus = False
1055 1055
1056 1056 if opts.pop('large', None):
1057 1057 toupload = getoutgoinglfiles(ui, repo, None, **opts)
1058 1058 if toupload is None:
1059 1059 # i18n: column positioning for "hg summary"
1060 1060 ui.status(_('largefiles: (no remote repo)\n'))
1061 1061 elif not toupload:
1062 1062 # i18n: column positioning for "hg summary"
1063 1063 ui.status(_('largefiles: (no files to upload)\n'))
1064 1064 else:
1065 1065 # i18n: column positioning for "hg summary"
1066 1066 ui.status(_('largefiles: %d to upload\n') % len(toupload))
1067 1067
1068 1068 def scmutiladdremove(orig, repo, pats=[], opts={}, dry_run=None,
1069 1069 similarity=None):
1070 1070 if not lfutil.islfilesrepo(repo):
1071 1071 return orig(repo, pats, opts, dry_run, similarity)
1072 1072 # Get the list of missing largefiles so we can remove them
1073 1073 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1074 1074 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
1075 1075 False, False)
1076 1076 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
1077 1077
1078 1078 # Call into the normal remove code, but the removing of the standin, we want
1079 1079 # to have handled by original addremove. Monkey patching here makes sure
1080 1080 # we don't remove the standin in the largefiles code, preventing a very
1081 1081 # confused state later.
1082 1082 if missing:
1083 1083 m = [repo.wjoin(f) for f in missing]
1084 1084 repo._isaddremove = True
1085 1085 removelargefiles(repo.ui, repo, *m, **opts)
1086 1086 repo._isaddremove = False
1087 1087 # Call into the normal add code, and any files that *should* be added as
1088 1088 # largefiles will be
1089 1089 addlargefiles(repo.ui, repo, *pats, **opts)
1090 1090 # Now that we've handled largefiles, hand off to the original addremove
1091 1091 # function to take care of the rest. Make sure it doesn't do anything with
1092 1092 # largefiles by installing a matcher that will ignore them.
1093 1093 installnormalfilesmatchfn(repo[None].manifest())
1094 1094 result = orig(repo, pats, opts, dry_run, similarity)
1095 1095 restorematchfn()
1096 1096 return result
1097 1097
1098 1098 # Calling purge with --all will cause the largefiles to be deleted.
1099 1099 # Override repo.status to prevent this from happening.
1100 1100 def overridepurge(orig, ui, repo, *dirs, **opts):
1101 1101 # XXX large file status is buggy when used on repo proxy.
1102 1102 # XXX this needs to be investigate.
1103 1103 repo = repo.unfiltered()
1104 1104 oldstatus = repo.status
1105 1105 def overridestatus(node1='.', node2=None, match=None, ignored=False,
1106 1106 clean=False, unknown=False, listsubrepos=False):
1107 1107 r = oldstatus(node1, node2, match, ignored, clean, unknown,
1108 1108 listsubrepos)
1109 1109 lfdirstate = lfutil.openlfdirstate(ui, repo)
1110 1110 modified, added, removed, deleted, unknown, ignored, clean = r
1111 1111 unknown = [f for f in unknown if lfdirstate[f] == '?']
1112 1112 ignored = [f for f in ignored if lfdirstate[f] == '?']
1113 1113 return modified, added, removed, deleted, unknown, ignored, clean
1114 1114 repo.status = overridestatus
1115 1115 orig(ui, repo, *dirs, **opts)
1116 1116 repo.status = oldstatus
1117 1117
1118 1118 def overriderollback(orig, ui, repo, **opts):
1119 1119 result = orig(ui, repo, **opts)
1120 1120 merge.update(repo, node=None, branchmerge=False, force=True,
1121 1121 partial=lfutil.isstandin)
1122 1122 wlock = repo.wlock()
1123 1123 try:
1124 1124 lfdirstate = lfutil.openlfdirstate(ui, repo)
1125 1125 lfiles = lfutil.listlfiles(repo)
1126 1126 oldlfiles = lfutil.listlfiles(repo, repo[None].parents()[0].rev())
1127 1127 for file in lfiles:
1128 1128 if file in oldlfiles:
1129 1129 lfdirstate.normallookup(file)
1130 1130 else:
1131 1131 lfdirstate.add(file)
1132 1132 lfdirstate.write()
1133 1133 finally:
1134 1134 wlock.release()
1135 1135 return result
1136 1136
1137 1137 def overridetransplant(orig, ui, repo, *revs, **opts):
1138 1138 try:
1139 1139 oldstandins = lfutil.getstandinsstate(repo)
1140 1140 repo._istransplanting = True
1141 1141 result = orig(ui, repo, *revs, **opts)
1142 1142 newstandins = lfutil.getstandinsstate(repo)
1143 1143 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
1144 1144 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1145 1145 printmessage=True)
1146 1146 finally:
1147 1147 repo._istransplanting = False
1148 1148 return result
1149 1149
1150 1150 def overridecat(orig, ui, repo, file1, *pats, **opts):
1151 1151 ctx = scmutil.revsingle(repo, opts.get('rev'))
1152 1152 if not lfutil.standin(file1) in ctx:
1153 1153 result = orig(ui, repo, file1, *pats, **opts)
1154 1154 return result
1155 1155 return lfcommands.catlfile(repo, file1, ctx.rev(), opts.get('output'))
1156 1156
1157 1157 def mercurialsinkbefore(orig, sink):
1158 1158 sink.repo._isconverting = True
1159 1159 orig(sink)
1160 1160
1161 1161 def mercurialsinkafter(orig, sink):
1162 1162 sink.repo._isconverting = False
1163 1163 orig(sink)
@@ -1,177 +1,173 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 httppeer, localrepo, merge, scmutil, sshpeer, wireproto
13 13 from mercurial.i18n import _
14 14 from mercurial.hgweb import hgweb_mod, webcommands
15 15 from mercurial.subrepo import hgsubrepo
16 16
17 17 import overrides
18 18 import proto
19 19
20 20 def uisetup(ui):
21 21 # Disable auto-status for some commands which assume that all
22 22 # files in the result are under Mercurial's control
23 23
24 24 entry = extensions.wrapcommand(commands.table, 'add',
25 25 overrides.overrideadd)
26 26 addopt = [('', 'large', None, _('add as largefile')),
27 27 ('', 'normal', None, _('add as normal file')),
28 28 ('', 'lfsize', '', _('add all files above this size '
29 29 '(in megabytes) as largefiles '
30 30 '(default: 10)'))]
31 31 entry[1].extend(addopt)
32 32
33 33 # The scmutil function is called both by the (trivial) addremove command,
34 34 # and in the process of handling commit -A (issue3542)
35 35 entry = extensions.wrapfunction(scmutil, 'addremove',
36 36 overrides.scmutiladdremove)
37 37 entry = extensions.wrapcommand(commands.table, 'remove',
38 38 overrides.overrideremove)
39 39 entry = extensions.wrapcommand(commands.table, 'forget',
40 40 overrides.overrideforget)
41 41
42 42 # Subrepos call status function
43 43 entry = extensions.wrapcommand(commands.table, 'status',
44 44 overrides.overridestatus)
45 45 entry = extensions.wrapfunction(hgsubrepo, 'status',
46 46 overrides.overridestatusfn)
47 47
48 48 entry = extensions.wrapcommand(commands.table, 'log',
49 49 overrides.overridelog)
50 50 entry = extensions.wrapcommand(commands.table, 'rollback',
51 51 overrides.overriderollback)
52 52 entry = extensions.wrapcommand(commands.table, 'verify',
53 53 overrides.overrideverify)
54 54
55 55 verifyopt = [('', 'large', None, _('verify largefiles')),
56 56 ('', 'lfa', None,
57 57 _('verify all revisions of largefiles not just current')),
58 58 ('', 'lfc', None,
59 59 _('verify largefile contents not just existence'))]
60 60 entry[1].extend(verifyopt)
61 61
62 62 entry = extensions.wrapcommand(commands.table, 'debugstate',
63 63 overrides.overridedebugstate)
64 64 debugstateopt = [('', 'large', None, _('display largefiles dirstate'))]
65 65 entry[1].extend(debugstateopt)
66 66
67 67 entry = extensions.wrapcommand(commands.table, 'outgoing',
68 68 overrides.overrideoutgoing)
69 69 outgoingopt = [('', 'large', None, _('display outgoing largefiles'))]
70 70 entry[1].extend(outgoingopt)
71 71 entry = extensions.wrapcommand(commands.table, 'summary',
72 72 overrides.overridesummary)
73 73 summaryopt = [('', 'large', None, _('display outgoing largefiles'))]
74 74 entry[1].extend(summaryopt)
75 75
76 76 entry = extensions.wrapcommand(commands.table, 'update',
77 77 overrides.overrideupdate)
78 78 entry = extensions.wrapcommand(commands.table, 'pull',
79 79 overrides.overridepull)
80 80 pullopt = [('', 'all-largefiles', None,
81 81 _('download all pulled versions of largefiles'))]
82 82 entry[1].extend(pullopt)
83 83 entry = extensions.wrapcommand(commands.table, 'clone',
84 84 overrides.overrideclone)
85 85 cloneopt = [('', 'all-largefiles', None,
86 86 _('download all versions of all largefiles'))]
87 87 entry[1].extend(cloneopt)
88 88 entry = extensions.wrapfunction(hg, 'clone', overrides.hgclone)
89 89
90 90 entry = extensions.wrapcommand(commands.table, 'cat',
91 91 overrides.overridecat)
92 92 entry = extensions.wrapfunction(merge, '_checkunknownfile',
93 93 overrides.overridecheckunknownfile)
94 94 entry = extensions.wrapfunction(merge, 'manifestmerge',
95 95 overrides.overridemanifestmerge)
96 96 entry = extensions.wrapfunction(filemerge, 'filemerge',
97 97 overrides.overridefilemerge)
98 98 entry = extensions.wrapfunction(cmdutil, 'copy',
99 99 overrides.overridecopy)
100 100
101 101 # Summary calls dirty on the subrepos
102 102 entry = extensions.wrapfunction(hgsubrepo, 'dirty',
103 103 overrides.overridedirty)
104 104
105 105 # Backout calls revert so we need to override both the command and the
106 106 # function
107 107 entry = extensions.wrapcommand(commands.table, 'revert',
108 108 overrides.overriderevert)
109 109 entry = extensions.wrapfunction(commands, 'revert',
110 110 overrides.overriderevert)
111 111
112 # clone uses hg._update instead of hg.update even though they are the
113 # same function... so wrap both of them)
114 extensions.wrapfunction(hg, 'update', overrides.hgupdate)
115 extensions.wrapfunction(hg, '_update', overrides.hgupdate)
116 extensions.wrapfunction(hg, 'clean', overrides.hgclean)
112 extensions.wrapfunction(hg, 'updaterepo', overrides.hgupdaterepo)
117 113 extensions.wrapfunction(hg, 'merge', overrides.hgmerge)
118 114
119 115 extensions.wrapfunction(archival, 'archive', overrides.overridearchive)
120 116 extensions.wrapfunction(hgsubrepo, 'archive', overrides.hgsubrepoarchive)
121 117 extensions.wrapfunction(cmdutil, 'bailifchanged',
122 118 overrides.overridebailifchanged)
123 119
124 120 # create the new wireproto commands ...
125 121 wireproto.commands['putlfile'] = (proto.putlfile, 'sha')
126 122 wireproto.commands['getlfile'] = (proto.getlfile, 'sha')
127 123 wireproto.commands['statlfile'] = (proto.statlfile, 'sha')
128 124
129 125 # ... and wrap some existing ones
130 126 wireproto.commands['capabilities'] = (proto.capabilities, '')
131 127 wireproto.commands['heads'] = (proto.heads, '')
132 128 wireproto.commands['lheads'] = (wireproto.heads, '')
133 129
134 130 # make putlfile behave the same as push and {get,stat}lfile behave
135 131 # the same as pull w.r.t. permissions checks
136 132 hgweb_mod.perms['putlfile'] = 'push'
137 133 hgweb_mod.perms['getlfile'] = 'pull'
138 134 hgweb_mod.perms['statlfile'] = 'pull'
139 135
140 136 extensions.wrapfunction(webcommands, 'decodepath', overrides.decodepath)
141 137
142 138 # the hello wireproto command uses wireproto.capabilities, so it won't see
143 139 # our largefiles capability unless we replace the actual function as well.
144 140 proto.capabilitiesorig = wireproto.capabilities
145 141 wireproto.capabilities = proto.capabilities
146 142
147 143 # can't do this in reposetup because it needs to have happened before
148 144 # wirerepo.__init__ is called
149 145 proto.ssholdcallstream = sshpeer.sshpeer._callstream
150 146 proto.httpoldcallstream = httppeer.httppeer._callstream
151 147 sshpeer.sshpeer._callstream = proto.sshrepocallstream
152 148 httppeer.httppeer._callstream = proto.httprepocallstream
153 149
154 150 # don't die on seeing a repo with the largefiles requirement
155 151 localrepo.localrepository.supported |= set(['largefiles'])
156 152
157 153 # override some extensions' stuff as well
158 154 for name, module in extensions.extensions():
159 155 if name == 'fetch':
160 156 extensions.wrapcommand(getattr(module, 'cmdtable'), 'fetch',
161 157 overrides.overridefetch)
162 158 if name == 'purge':
163 159 extensions.wrapcommand(getattr(module, 'cmdtable'), 'purge',
164 160 overrides.overridepurge)
165 161 if name == 'rebase':
166 162 extensions.wrapcommand(getattr(module, 'cmdtable'), 'rebase',
167 163 overrides.overriderebase)
168 164 if name == 'transplant':
169 165 extensions.wrapcommand(getattr(module, 'cmdtable'), 'transplant',
170 166 overrides.overridetransplant)
171 167 if name == 'convert':
172 168 convcmd = getattr(module, 'convcmd')
173 169 hgsink = getattr(convcmd, 'mercurial_sink')
174 170 extensions.wrapfunction(hgsink, 'before',
175 171 overrides.mercurialsinkbefore)
176 172 extensions.wrapfunction(hgsink, 'after',
177 173 overrides.mercurialsinkafter)
@@ -1,110 +1,110 b''
1 1
2 2 $ echo "[extensions]" >> $HGRCPATH
3 3 $ echo "largefiles =" >> $HGRCPATH
4 4
5 5 Create the repository outside $HOME since largefiles write to
6 6 $HOME/.cache/largefiles.
7 7
8 8 $ hg init test
9 9 $ cd test
10 10 $ echo "root" > root
11 11 $ hg add root
12 12 $ hg commit -m "Root commit"
13 13
14 14 $ echo "large" > foo
15 15 $ hg add --large foo
16 16 $ hg commit -m "Add foo as a largefile"
17 17
18 18 $ hg update -r 0
19 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
20 19 getting changed largefiles
21 20 0 largefiles updated, 1 removed
21 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
22 22
23 23 $ echo "normal" > foo
24 24 $ hg add foo
25 25 $ hg commit -m "Add foo as normal file"
26 26 created new head
27 27
28 28 Normal file in the working copy, keeping the normal version:
29 29
30 30 $ echo "n" | hg merge --config ui.interactive=Yes
31 31 foo has been turned into a largefile
32 32 use (l)argefile or keep as (n)ormal file? 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
33 33 (branch merge, don't forget to commit)
34 34
35 35 $ hg status
36 36 $ cat foo
37 37 normal
38 38
39 39 Normal file in the working copy, keeping the largefile version:
40 40
41 41 $ hg update -q -C
42 42 $ echo "l" | hg merge --config ui.interactive=Yes
43 43 foo has been turned into a largefile
44 44 use (l)argefile or keep as (n)ormal file? 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
45 45 (branch merge, don't forget to commit)
46 46 getting changed largefiles
47 47 1 largefiles updated, 0 removed
48 48
49 49 $ hg status
50 50 M foo
51 51
52 52 $ hg diff --nodates
53 53 diff -r fa129ab6b5a7 .hglf/foo
54 54 --- /dev/null
55 55 +++ b/.hglf/foo
56 56 @@ -0,0 +1,1 @@
57 57 +7f7097b041ccf68cc5561e9600da4655d21c6d18
58 58 diff -r fa129ab6b5a7 foo
59 59 --- a/foo
60 60 +++ /dev/null
61 61 @@ -1,1 +0,0 @@
62 62 -normal
63 63
64 64 $ cat foo
65 65 large
66 66
67 67 Largefile in the working copy, keeping the normal version:
68 68
69 69 $ hg update -q -C -r 1
70 70 $ echo "n" | hg merge --config ui.interactive=Yes
71 71 foo has been turned into a normal file
72 72 keep as (l)argefile or use (n)ormal file? 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
73 73 (branch merge, don't forget to commit)
74 74 getting changed largefiles
75 75 0 largefiles updated, 0 removed
76 76
77 77 $ hg status
78 78 M foo
79 79
80 80 $ hg diff --nodates
81 81 diff -r ff521236428a .hglf/foo
82 82 --- a/.hglf/foo
83 83 +++ /dev/null
84 84 @@ -1,1 +0,0 @@
85 85 -7f7097b041ccf68cc5561e9600da4655d21c6d18
86 86 diff -r ff521236428a foo
87 87 --- /dev/null
88 88 +++ b/foo
89 89 @@ -0,0 +1,1 @@
90 90 +normal
91 91
92 92 $ cat foo
93 93 normal
94 94
95 95 Largefile in the working copy, keeping the largefile version:
96 96
97 97 $ hg update -q -C -r 1
98 98 $ echo "l" | hg merge --config ui.interactive=Yes
99 99 foo has been turned into a normal file
100 100 keep as (l)argefile or use (n)ormal file? 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
101 101 (branch merge, don't forget to commit)
102 102 getting changed largefiles
103 103 1 largefiles updated, 0 removed
104 104
105 105 $ hg status
106 106
107 107 $ cat foo
108 108 large
109 109
110 110 $ cd ..
@@ -1,123 +1,123 b''
1 1 Create user cache directory
2 2
3 3 $ USERCACHE=`pwd`/cache; export USERCACHE
4 4 $ cat <<EOF >> ${HGRCPATH}
5 5 > [extensions]
6 6 > hgext.largefiles=
7 7 > [largefiles]
8 8 > usercache=${USERCACHE}
9 9 > EOF
10 10 $ mkdir -p ${USERCACHE}
11 11
12 12 Create source repo, and commit adding largefile.
13 13
14 14 $ hg init src
15 15 $ cd src
16 16 $ echo large > large
17 17 $ hg add --large large
18 18 $ hg commit -m 'add largefile'
19 19 $ cd ..
20 20
21 21 Discard all cached largefiles in USERCACHE
22 22
23 23 $ rm -rf ${USERCACHE}
24 24
25 25 Create mirror repo, and pull from source without largefile:
26 26 "pull" is used instead of "clone" for suppression of (1) updating to
27 27 tip (= cahcing largefile from source repo), and (2) recording source
28 28 repo as "default" path in .hg/hgrc.
29 29
30 30 $ hg init mirror
31 31 $ cd mirror
32 32 $ hg pull ../src
33 33 pulling from ../src
34 34 requesting all changes
35 35 adding changesets
36 36 adding manifests
37 37 adding file changes
38 38 added 1 changesets with 1 changes to 1 files
39 39 (run 'hg update' to get a working copy)
40 40 caching new largefiles
41 41 0 largefiles cached
42 42
43 43 Update working directory to "tip", which requires largefile("large"),
44 44 but there is no cache file for it. So, hg must treat it as
45 45 "missing"(!) file.
46 46
47 47 $ hg update
48 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
49 48 getting changed largefiles
50 49 error getting 7f7097b041ccf68cc5561e9600da4655d21c6d18 from file:$TESTTMP/mirror for large: can't get file locally (glob)
51 50 0 largefiles updated, 0 removed
51 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
52 52 $ hg status
53 53 ! large
54 54
55 55 Update working directory to null: this cleanup .hg/largefiles/dirstate
56 56
57 57 $ hg update null
58 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
59 58 getting changed largefiles
60 59 0 largefiles updated, 0 removed
60 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
61 61
62 62 Update working directory to tip, again.
63 63
64 64 $ hg update
65 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
66 65 getting changed largefiles
67 66 error getting 7f7097b041ccf68cc5561e9600da4655d21c6d18 from file:$TESTTMP/mirror for large: can't get file locally (glob)
68 67 0 largefiles updated, 0 removed
68 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
69 69 $ hg status
70 70 ! large
71 71 $ cd ..
72 72
73 73 #if unix-permissions
74 74
75 75 Portable way to print file permissions:
76 76
77 77 $ cat > ls-l.py <<EOF
78 78 > #!/usr/bin/env python
79 79 > import sys, os
80 80 > path = sys.argv[1]
81 81 > print '%03o' % (os.lstat(path).st_mode & 0777)
82 82 > EOF
83 83 $ chmod +x ls-l.py
84 84
85 85 Test that files in .hg/largefiles inherit mode from .hg/store, not
86 86 from file in working copy:
87 87
88 88 $ cd src
89 89 $ chmod 750 .hg/store
90 90 $ chmod 660 large
91 91 $ echo change >> large
92 92 $ hg commit -m change
93 93 $ ../ls-l.py .hg/largefiles/e151b474069de4ca6898f67ce2f2a7263adf8fea
94 94 640
95 95
96 96 Test permission of with files in .hg/largefiles created by update:
97 97
98 98 $ cd ../mirror
99 99 $ rm -r "$USERCACHE" .hg/largefiles # avoid links
100 100 $ chmod 750 .hg/store
101 101 $ hg pull ../src --update -q
102 102 $ ../ls-l.py .hg/largefiles/e151b474069de4ca6898f67ce2f2a7263adf8fea
103 103 640
104 104
105 105 Test permission of files created by push:
106 106
107 107 $ hg serve -R ../src -d -p $HGPORT --pid-file hg.pid \
108 108 > --config "web.allow_push=*" --config web.push_ssl=no
109 109 $ cat hg.pid >> $DAEMON_PIDS
110 110
111 111 $ echo change >> large
112 112 $ hg commit -m change
113 113
114 114 $ rm -r "$USERCACHE"
115 115
116 116 $ hg push -q http://localhost:$HGPORT/
117 117
118 118 $ ../ls-l.py ../src/.hg/largefiles/b734e14a0971e370408ab9bce8d56d8485e368a9
119 119 640
120 120
121 121 $ cd ..
122 122
123 123 #endif
@@ -1,67 +1,66 b''
1 1 Test how largefiles abort in case the disk runs full
2 2
3 3 $ cat > criple.py <<EOF
4 4 > import os, errno, shutil
5 5 > from mercurial import util
6 6 > #
7 7 > # this makes the original largefiles code abort:
8 8 > def copyfileobj(fsrc, fdst, length=16*1024):
9 9 > fdst.write(fsrc.read(4))
10 10 > raise IOError(errno.ENOSPC, os.strerror(errno.ENOSPC))
11 11 > shutil.copyfileobj = copyfileobj
12 12 > #
13 13 > # this makes the rewritten code abort:
14 14 > def filechunkiter(f, size=65536, limit=None):
15 15 > yield f.read(4)
16 16 > raise IOError(errno.ENOSPC, os.strerror(errno.ENOSPC))
17 17 > util.filechunkiter = filechunkiter
18 18 > #
19 19 > def oslink(src, dest):
20 20 > raise OSError("no hardlinks, try copying instead")
21 21 > util.oslink = oslink
22 22 > EOF
23 23
24 24 $ echo "[extensions]" >> $HGRCPATH
25 25 $ echo "largefiles =" >> $HGRCPATH
26 26
27 27 $ hg init alice
28 28 $ cd alice
29 29 $ echo "this is a very big file" > big
30 30 $ hg add --large big
31 31 $ hg commit --config extensions.criple=$TESTTMP/criple.py -m big
32 32 abort: No space left on device
33 33 [255]
34 34
35 35 The largefile is not created in .hg/largefiles:
36 36
37 37 $ ls .hg/largefiles
38 38 dirstate
39 39
40 40 The user cache is not even created:
41 41
42 42 >>> import os; os.path.exists("$HOME/.cache/largefiles/")
43 43 False
44 44
45 45 Make the commit with space on the device:
46 46
47 47 $ hg commit -m big
48 48
49 49 Now make a clone with a full disk, and make sure lfutil.link function
50 50 makes copies instead of hardlinks:
51 51
52 52 $ cd ..
53 53 $ hg --config extensions.criple=$TESTTMP/criple.py clone --pull alice bob
54 54 requesting all changes
55 55 adding changesets
56 56 adding manifests
57 57 adding file changes
58 58 added 1 changesets with 1 changes to 1 files
59 59 updating to branch default
60 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
61 60 getting changed largefiles
62 61 abort: No space left on device
63 62 [255]
64 63
65 64 The largefile is not created in .hg/largefiles:
66 65
67 66 $ ls bob/.hg/largefiles
@@ -1,1904 +1,1929 b''
1 1 $ USERCACHE="$TESTTMP/cache"; export USERCACHE
2 2 $ mkdir "${USERCACHE}"
3 3 $ cat >> $HGRCPATH <<EOF
4 4 > [extensions]
5 5 > largefiles=
6 6 > purge=
7 7 > rebase=
8 8 > transplant=
9 9 > [phases]
10 10 > publish=False
11 11 > [largefiles]
12 12 > minsize=2
13 13 > patterns=glob:**.dat
14 14 > usercache=${USERCACHE}
15 15 > [hooks]
16 16 > precommit=sh -c "echo \\"Invoking status precommit hook\\"; hg status"
17 17 > EOF
18 18
19 19 Create the repo with a couple of revisions of both large and normal
20 20 files.
21 21 Test status and dirstate of largefiles and that summary output is correct.
22 22
23 23 $ hg init a
24 24 $ cd a
25 25 $ mkdir sub
26 26 $ echo normal1 > normal1
27 27 $ echo normal2 > sub/normal2
28 28 $ echo large1 > large1
29 29 $ echo large2 > sub/large2
30 30 $ hg add normal1 sub/normal2
31 31 $ hg add --large large1 sub/large2
32 32 $ hg commit -m "add files"
33 33 Invoking status precommit hook
34 34 A large1
35 35 A normal1
36 36 A sub/large2
37 37 A sub/normal2
38 38 $ touch large1 sub/large2
39 39 $ sleep 1
40 40 $ hg st
41 41 $ hg debugstate --nodates
42 42 n 644 41 .hglf/large1
43 43 n 644 41 .hglf/sub/large2
44 44 n 644 8 normal1
45 45 n 644 8 sub/normal2
46 46 $ hg debugstate --large
47 47 n 644 7 large1
48 48 n 644 7 sub/large2
49 49 $ echo normal11 > normal1
50 50 $ echo normal22 > sub/normal2
51 51 $ echo large11 > large1
52 52 $ echo large22 > sub/large2
53 53 $ hg commit -m "edit files"
54 54 Invoking status precommit hook
55 55 M large1
56 56 M normal1
57 57 M sub/large2
58 58 M sub/normal2
59 59 $ hg sum --large
60 60 parent: 1:ce8896473775 tip
61 61 edit files
62 62 branch: default
63 63 commit: (clean)
64 64 update: (current)
65 65 largefiles: (no remote repo)
66 66
67 67 Commit preserved largefile contents.
68 68
69 69 $ cat normal1
70 70 normal11
71 71 $ cat large1
72 72 large11
73 73 $ cat sub/normal2
74 74 normal22
75 75 $ cat sub/large2
76 76 large22
77 77
78 78 Test status, subdir and unknown files
79 79
80 80 $ echo unknown > sub/unknown
81 81 $ hg st --all
82 82 ? sub/unknown
83 83 C large1
84 84 C normal1
85 85 C sub/large2
86 86 C sub/normal2
87 87 $ hg st --all sub
88 88 ? sub/unknown
89 89 C sub/large2
90 90 C sub/normal2
91 91 $ rm sub/unknown
92 92
93 93 Test messages and exit codes for remove warning cases
94 94
95 95 $ hg remove -A large1
96 96 not removing large1: file still exists
97 97 [1]
98 98 $ echo 'modified' > large1
99 99 $ hg remove large1
100 100 not removing large1: file is modified (use -f to force removal)
101 101 [1]
102 102 $ echo 'new' > normalnew
103 103 $ hg add normalnew
104 104 $ echo 'new' > largenew
105 105 $ hg add --large normalnew
106 106 normalnew already tracked!
107 107 $ hg remove normalnew largenew
108 108 not removing largenew: file is untracked
109 109 not removing normalnew: file has been marked for add (use forget to undo)
110 110 [1]
111 111 $ rm normalnew largenew
112 112 $ hg up -Cq
113 113
114 114 Remove both largefiles and normal files.
115 115
116 116 $ hg remove normal1 large1
117 117 $ hg status large1
118 118 R large1
119 119 $ hg commit -m "remove files"
120 120 Invoking status precommit hook
121 121 R large1
122 122 R normal1
123 123 $ ls
124 124 sub
125 125 $ echo "testlargefile" > large1-test
126 126 $ hg add --large large1-test
127 127 $ hg st
128 128 A large1-test
129 129 $ hg rm large1-test
130 130 not removing large1-test: file has been marked for add (use forget to undo)
131 131 [1]
132 132 $ hg st
133 133 A large1-test
134 134 $ hg forget large1-test
135 135 $ hg st
136 136 ? large1-test
137 137 $ hg remove large1-test
138 138 not removing large1-test: file is untracked
139 139 [1]
140 140 $ hg forget large1-test
141 141 not removing large1-test: file is already untracked
142 142 [1]
143 143 $ rm large1-test
144 144
145 145 Copy both largefiles and normal files (testing that status output is correct).
146 146
147 147 $ hg cp sub/normal2 normal1
148 148 $ hg cp sub/large2 large1
149 149 $ hg commit -m "copy files"
150 150 Invoking status precommit hook
151 151 A large1
152 152 A normal1
153 153 $ cat normal1
154 154 normal22
155 155 $ cat large1
156 156 large22
157 157
158 158 Test moving largefiles and verify that normal files are also unaffected.
159 159
160 160 $ hg mv normal1 normal3
161 161 $ hg mv large1 large3
162 162 $ hg mv sub/normal2 sub/normal4
163 163 $ hg mv sub/large2 sub/large4
164 164 $ hg commit -m "move files"
165 165 Invoking status precommit hook
166 166 A large3
167 167 A normal3
168 168 A sub/large4
169 169 A sub/normal4
170 170 R large1
171 171 R normal1
172 172 R sub/large2
173 173 R sub/normal2
174 174 $ cat normal3
175 175 normal22
176 176 $ cat large3
177 177 large22
178 178 $ cat sub/normal4
179 179 normal22
180 180 $ cat sub/large4
181 181 large22
182 182
183 183 Test copies and moves from a directory other than root (issue3516)
184 184
185 185 $ cd ..
186 186 $ hg init lf_cpmv
187 187 $ cd lf_cpmv
188 188 $ mkdir dira
189 189 $ mkdir dira/dirb
190 190 $ touch dira/dirb/largefile
191 191 $ hg add --large dira/dirb/largefile
192 192 $ hg commit -m "added"
193 193 Invoking status precommit hook
194 194 A dira/dirb/largefile
195 195 $ cd dira
196 196 $ hg cp dirb/largefile foo/largefile
197 197 $ hg ci -m "deep copy"
198 198 Invoking status precommit hook
199 199 A dira/foo/largefile
200 200 $ find . | sort
201 201 .
202 202 ./dirb
203 203 ./dirb/largefile
204 204 ./foo
205 205 ./foo/largefile
206 206 $ hg mv foo/largefile baz/largefile
207 207 $ hg ci -m "moved"
208 208 Invoking status precommit hook
209 209 A dira/baz/largefile
210 210 R dira/foo/largefile
211 211 $ find . | sort
212 212 .
213 213 ./baz
214 214 ./baz/largefile
215 215 ./dirb
216 216 ./dirb/largefile
217 217 ./foo
218 218 $ cd ../../a
219 219
220 220 #if serve
221 221 Test display of largefiles in hgweb
222 222
223 223 $ hg serve -d -p $HGPORT --pid-file ../hg.pid
224 224 $ cat ../hg.pid >> $DAEMON_PIDS
225 225 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/tip/?style=raw'
226 226 200 Script output follows
227 227
228 228
229 229 drwxr-xr-x sub
230 230 -rw-r--r-- 41 large3
231 231 -rw-r--r-- 9 normal3
232 232
233 233
234 234 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/tip/sub/?style=raw'
235 235 200 Script output follows
236 236
237 237
238 238 -rw-r--r-- 41 large4
239 239 -rw-r--r-- 9 normal4
240 240
241 241
242 242 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
243 243 #endif
244 244
245 245 Test archiving the various revisions. These hit corner cases known with
246 246 archiving.
247 247
248 248 $ hg archive -r 0 ../archive0
249 249 $ hg archive -r 1 ../archive1
250 250 $ hg archive -r 2 ../archive2
251 251 $ hg archive -r 3 ../archive3
252 252 $ hg archive -r 4 ../archive4
253 253 $ cd ../archive0
254 254 $ cat normal1
255 255 normal1
256 256 $ cat large1
257 257 large1
258 258 $ cat sub/normal2
259 259 normal2
260 260 $ cat sub/large2
261 261 large2
262 262 $ cd ../archive1
263 263 $ cat normal1
264 264 normal11
265 265 $ cat large1
266 266 large11
267 267 $ cat sub/normal2
268 268 normal22
269 269 $ cat sub/large2
270 270 large22
271 271 $ cd ../archive2
272 272 $ ls
273 273 sub
274 274 $ cat sub/normal2
275 275 normal22
276 276 $ cat sub/large2
277 277 large22
278 278 $ cd ../archive3
279 279 $ cat normal1
280 280 normal22
281 281 $ cat large1
282 282 large22
283 283 $ cat sub/normal2
284 284 normal22
285 285 $ cat sub/large2
286 286 large22
287 287 $ cd ../archive4
288 288 $ cat normal3
289 289 normal22
290 290 $ cat large3
291 291 large22
292 292 $ cat sub/normal4
293 293 normal22
294 294 $ cat sub/large4
295 295 large22
296 296
297 297 Commit corner case: specify files to commit.
298 298
299 299 $ cd ../a
300 300 $ echo normal3 > normal3
301 301 $ echo large3 > large3
302 302 $ echo normal4 > sub/normal4
303 303 $ echo large4 > sub/large4
304 304 $ hg commit normal3 large3 sub/normal4 sub/large4 -m "edit files again"
305 305 Invoking status precommit hook
306 306 M large3
307 307 M normal3
308 308 M sub/large4
309 309 M sub/normal4
310 310 $ cat normal3
311 311 normal3
312 312 $ cat large3
313 313 large3
314 314 $ cat sub/normal4
315 315 normal4
316 316 $ cat sub/large4
317 317 large4
318 318
319 319 One more commit corner case: commit from a subdirectory.
320 320
321 321 $ cd ../a
322 322 $ echo normal33 > normal3
323 323 $ echo large33 > large3
324 324 $ echo normal44 > sub/normal4
325 325 $ echo large44 > sub/large4
326 326 $ cd sub
327 327 $ hg commit -m "edit files yet again"
328 328 Invoking status precommit hook
329 329 M large3
330 330 M normal3
331 331 M sub/large4
332 332 M sub/normal4
333 333 $ cat ../normal3
334 334 normal33
335 335 $ cat ../large3
336 336 large33
337 337 $ cat normal4
338 338 normal44
339 339 $ cat large4
340 340 large44
341 341
342 342 Committing standins is not allowed.
343 343
344 344 $ cd ..
345 345 $ echo large3 > large3
346 346 $ hg commit .hglf/large3 -m "try to commit standin"
347 347 abort: file ".hglf/large3" is a largefile standin
348 348 (commit the largefile itself instead)
349 349 [255]
350 350
351 351 Corner cases for adding largefiles.
352 352
353 353 $ echo large5 > large5
354 354 $ hg add --large large5
355 355 $ hg add --large large5
356 356 large5 already a largefile
357 357 $ mkdir sub2
358 358 $ echo large6 > sub2/large6
359 359 $ echo large7 > sub2/large7
360 360 $ hg add --large sub2
361 361 adding sub2/large6 as a largefile (glob)
362 362 adding sub2/large7 as a largefile (glob)
363 363 $ hg st
364 364 M large3
365 365 A large5
366 366 A sub2/large6
367 367 A sub2/large7
368 368
369 369 Committing directories containing only largefiles.
370 370
371 371 $ mkdir -p z/y/x/m
372 372 $ touch z/y/x/m/large1
373 373 $ touch z/y/x/large2
374 374 $ hg add --large z/y/x/m/large1 z/y/x/large2
375 375 $ hg commit -m "Subdir with directory only containing largefiles" z
376 376 Invoking status precommit hook
377 377 M large3
378 378 A large5
379 379 A sub2/large6
380 380 A sub2/large7
381 381 A z/y/x/large2
382 382 A z/y/x/m/large1
383 383 $ hg rollback --quiet
384 384 $ touch z/y/x/m/normal
385 385 $ hg add z/y/x/m/normal
386 386 $ hg commit -m "Subdir with mixed contents" z
387 387 Invoking status precommit hook
388 388 M large3
389 389 A large5
390 390 A sub2/large6
391 391 A sub2/large7
392 392 A z/y/x/large2
393 393 A z/y/x/m/large1
394 394 A z/y/x/m/normal
395 395 $ hg st
396 396 M large3
397 397 A large5
398 398 A sub2/large6
399 399 A sub2/large7
400 400 $ hg rollback --quiet
401 401 $ hg revert z/y/x/large2 z/y/x/m/large1
402 402 $ rm z/y/x/large2 z/y/x/m/large1
403 403 $ hg commit -m "Subdir with normal contents" z
404 404 Invoking status precommit hook
405 405 M large3
406 406 A large5
407 407 A sub2/large6
408 408 A sub2/large7
409 409 A z/y/x/m/normal
410 410 $ hg st
411 411 M large3
412 412 A large5
413 413 A sub2/large6
414 414 A sub2/large7
415 415 $ hg rollback --quiet
416 416 $ hg revert --quiet z
417 417 $ hg commit -m "Empty subdir" z
418 418 abort: z: no match under directory!
419 419 [255]
420 420 $ rm -rf z
421 421 $ hg ci -m "standin" .hglf
422 422 abort: file ".hglf" is a largefile standin
423 423 (commit the largefile itself instead)
424 424 [255]
425 425
426 426 Test "hg status" with combination of 'file pattern' and 'directory
427 427 pattern' for largefiles:
428 428
429 429 $ hg status sub2/large6 sub2
430 430 A sub2/large6
431 431 A sub2/large7
432 432
433 433 Config settings (pattern **.dat, minsize 2 MB) are respected.
434 434
435 435 $ echo testdata > test.dat
436 436 $ dd bs=1k count=2k if=/dev/zero of=reallylarge > /dev/null 2> /dev/null
437 437 $ hg add
438 438 adding reallylarge as a largefile
439 439 adding test.dat as a largefile
440 440
441 441 Test that minsize and --lfsize handle float values;
442 442 also tests that --lfsize overrides largefiles.minsize.
443 443 (0.250 MB = 256 kB = 262144 B)
444 444
445 445 $ dd if=/dev/zero of=ratherlarge bs=1024 count=256 > /dev/null 2> /dev/null
446 446 $ dd if=/dev/zero of=medium bs=1024 count=128 > /dev/null 2> /dev/null
447 447 $ hg --config largefiles.minsize=.25 add
448 448 adding ratherlarge as a largefile
449 449 adding medium
450 450 $ hg forget medium
451 451 $ hg --config largefiles.minsize=.25 add --lfsize=.125
452 452 adding medium as a largefile
453 453 $ dd if=/dev/zero of=notlarge bs=1024 count=127 > /dev/null 2> /dev/null
454 454 $ hg --config largefiles.minsize=.25 add --lfsize=.125
455 455 adding notlarge
456 456 $ hg forget notlarge
457 457
458 458 Test forget on largefiles.
459 459
460 460 $ hg forget large3 large5 test.dat reallylarge ratherlarge medium
461 461 $ hg commit -m "add/edit more largefiles"
462 462 Invoking status precommit hook
463 463 A sub2/large6
464 464 A sub2/large7
465 465 R large3
466 466 ? large5
467 467 ? medium
468 468 ? notlarge
469 469 ? ratherlarge
470 470 ? reallylarge
471 471 ? test.dat
472 472 $ hg st
473 473 ? large3
474 474 ? large5
475 475 ? medium
476 476 ? notlarge
477 477 ? ratherlarge
478 478 ? reallylarge
479 479 ? test.dat
480 480
481 481 Purge with largefiles: verify that largefiles are still in the working
482 482 dir after a purge.
483 483
484 484 $ hg purge --all
485 485 $ cat sub/large4
486 486 large44
487 487 $ cat sub2/large6
488 488 large6
489 489 $ cat sub2/large7
490 490 large7
491 491
492 492 Test addremove: verify that files that should be added as largfiles are added as
493 493 such and that already-existing largfiles are not added as normal files by
494 494 accident.
495 495
496 496 $ rm normal3
497 497 $ rm sub/large4
498 498 $ echo "testing addremove with patterns" > testaddremove.dat
499 499 $ echo "normaladdremove" > normaladdremove
500 500 $ hg addremove
501 501 removing sub/large4
502 502 adding testaddremove.dat as a largefile
503 503 removing normal3
504 504 adding normaladdremove
505 505
506 506 Test addremove with -R
507 507
508 508 $ hg up -C
509 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
510 509 getting changed largefiles
511 510 1 largefiles updated, 0 removed
511 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
512 512 $ rm normal3
513 513 $ rm sub/large4
514 514 $ echo "testing addremove with patterns" > testaddremove.dat
515 515 $ echo "normaladdremove" > normaladdremove
516 516 $ cd ..
517 517 $ hg -R a addremove
518 518 removing sub/large4
519 519 adding a/testaddremove.dat as a largefile (glob)
520 520 removing normal3
521 521 adding normaladdremove
522 522 $ cd a
523 523
524 524 Test 3364
525 525 $ hg clone . ../addrm
526 526 updating to branch default
527 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
528 527 getting changed largefiles
529 528 3 largefiles updated, 0 removed
529 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
530 530 $ cd ../addrm
531 531 $ cat >> .hg/hgrc <<EOF
532 532 > [hooks]
533 533 > post-commit.stat=sh -c "echo \\"Invoking status postcommit hook\\"; hg status -A"
534 534 > EOF
535 535 $ touch foo
536 536 $ hg add --large foo
537 537 $ hg ci -m "add foo"
538 538 Invoking status precommit hook
539 539 A foo
540 540 Invoking status postcommit hook
541 541 C foo
542 542 C normal3
543 543 C sub/large4
544 544 C sub/normal4
545 545 C sub2/large6
546 546 C sub2/large7
547 547 $ rm foo
548 548 $ hg st
549 549 ! foo
550 550 hmm.. no precommit invoked, but there is a postcommit??
551 551 $ hg ci -m "will not checkin"
552 552 nothing changed
553 553 Invoking status postcommit hook
554 554 ! foo
555 555 C normal3
556 556 C sub/large4
557 557 C sub/normal4
558 558 C sub2/large6
559 559 C sub2/large7
560 560 [1]
561 561 $ hg addremove
562 562 removing foo
563 563 $ hg st
564 564 R foo
565 565 $ hg ci -m "used to say nothing changed"
566 566 Invoking status precommit hook
567 567 R foo
568 568 Invoking status postcommit hook
569 569 C normal3
570 570 C sub/large4
571 571 C sub/normal4
572 572 C sub2/large6
573 573 C sub2/large7
574 574 $ hg st
575 575
576 576 Test 3507 (both normal files and largefiles were a problem)
577 577
578 578 $ touch normal
579 579 $ touch large
580 580 $ hg add normal
581 581 $ hg add --large large
582 582 $ hg ci -m "added"
583 583 Invoking status precommit hook
584 584 A large
585 585 A normal
586 586 Invoking status postcommit hook
587 587 C large
588 588 C normal
589 589 C normal3
590 590 C sub/large4
591 591 C sub/normal4
592 592 C sub2/large6
593 593 C sub2/large7
594 594 $ hg remove normal
595 595 $ hg addremove --traceback
596 596 $ hg ci -m "addremoved normal"
597 597 Invoking status precommit hook
598 598 R normal
599 599 Invoking status postcommit hook
600 600 C large
601 601 C normal3
602 602 C sub/large4
603 603 C sub/normal4
604 604 C sub2/large6
605 605 C sub2/large7
606 606 $ hg up -C '.^'
607 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
608 607 getting changed largefiles
609 608 0 largefiles updated, 0 removed
609 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
610 610 $ hg remove large
611 611 $ hg addremove --traceback
612 612 $ hg ci -m "removed large"
613 613 Invoking status precommit hook
614 614 R large
615 615 created new head
616 616 Invoking status postcommit hook
617 617 C normal
618 618 C normal3
619 619 C sub/large4
620 620 C sub/normal4
621 621 C sub2/large6
622 622 C sub2/large7
623 623
624 624 Test commit -A (issue 3542)
625 625 $ echo large8 > large8
626 626 $ hg add --large large8
627 627 $ hg ci -Am 'this used to add large8 as normal and commit both'
628 628 Invoking status precommit hook
629 629 A large8
630 630 Invoking status postcommit hook
631 631 C large8
632 632 C normal
633 633 C normal3
634 634 C sub/large4
635 635 C sub/normal4
636 636 C sub2/large6
637 637 C sub2/large7
638 638 $ rm large8
639 639 $ hg ci -Am 'this used to not notice the rm'
640 640 removing large8
641 641 Invoking status precommit hook
642 642 R large8
643 643 Invoking status postcommit hook
644 644 C normal
645 645 C normal3
646 646 C sub/large4
647 647 C sub/normal4
648 648 C sub2/large6
649 649 C sub2/large7
650 650
651 651 Test that a standin can't be added as a large file
652 652
653 653 $ touch large
654 654 $ hg add --large large
655 655 $ hg ci -m "add"
656 656 Invoking status precommit hook
657 657 A large
658 658 Invoking status postcommit hook
659 659 C large
660 660 C normal
661 661 C normal3
662 662 C sub/large4
663 663 C sub/normal4
664 664 C sub2/large6
665 665 C sub2/large7
666 666 $ hg remove large
667 667 $ touch large
668 668 $ hg addremove --config largefiles.patterns=**large --traceback
669 669 adding large as a largefile
670 670
671 671 Test that outgoing --large works (with revsets too)
672 672 $ hg outgoing --rev '.^' --large
673 673 comparing with $TESTTMP/a (glob)
674 674 searching for changes
675 675 changeset: 8:c02fd3b77ec4
676 676 user: test
677 677 date: Thu Jan 01 00:00:00 1970 +0000
678 678 summary: add foo
679 679
680 680 changeset: 9:289dd08c9bbb
681 681 user: test
682 682 date: Thu Jan 01 00:00:00 1970 +0000
683 683 summary: used to say nothing changed
684 684
685 685 changeset: 10:34f23ac6ac12
686 686 user: test
687 687 date: Thu Jan 01 00:00:00 1970 +0000
688 688 summary: added
689 689
690 690 changeset: 12:710c1b2f523c
691 691 parent: 10:34f23ac6ac12
692 692 user: test
693 693 date: Thu Jan 01 00:00:00 1970 +0000
694 694 summary: removed large
695 695
696 696 changeset: 13:0a3e75774479
697 697 user: test
698 698 date: Thu Jan 01 00:00:00 1970 +0000
699 699 summary: this used to add large8 as normal and commit both
700 700
701 701 changeset: 14:84f3d378175c
702 702 user: test
703 703 date: Thu Jan 01 00:00:00 1970 +0000
704 704 summary: this used to not notice the rm
705 705
706 706 searching for changes
707 707 largefiles to upload:
708 708 foo
709 709 large
710 710 large8
711 711
712 712 $ cd ../a
713 713
714 714 Clone a largefiles repo.
715 715
716 716 $ hg clone . ../b
717 717 updating to branch default
718 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
719 718 getting changed largefiles
720 719 3 largefiles updated, 0 removed
720 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
721 721 $ cd ../b
722 722 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
723 723 7:daea875e9014 add/edit more largefiles
724 724 6:4355d653f84f edit files yet again
725 725 5:9d5af5072dbd edit files again
726 726 4:74c02385b94c move files
727 727 3:9e8fbc4bce62 copy files
728 728 2:51a0ae4d5864 remove files
729 729 1:ce8896473775 edit files
730 730 0:30d30fe6a5be add files
731 731 $ cat normal3
732 732 normal33
733 733 $ cat sub/normal4
734 734 normal44
735 735 $ cat sub/large4
736 736 large44
737 737 $ cat sub2/large6
738 738 large6
739 739 $ cat sub2/large7
740 740 large7
741 741 $ cd ..
742 742 $ hg clone a -r 3 c
743 743 adding changesets
744 744 adding manifests
745 745 adding file changes
746 746 added 4 changesets with 10 changes to 4 files
747 747 updating to branch default
748 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
749 748 getting changed largefiles
750 749 2 largefiles updated, 0 removed
750 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
751 751 $ cd c
752 752 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
753 753 3:9e8fbc4bce62 copy files
754 754 2:51a0ae4d5864 remove files
755 755 1:ce8896473775 edit files
756 756 0:30d30fe6a5be add files
757 757 $ cat normal1
758 758 normal22
759 759 $ cat large1
760 760 large22
761 761 $ cat sub/normal2
762 762 normal22
763 763 $ cat sub/large2
764 764 large22
765 765
766 766 Old revisions of a clone have correct largefiles content (this also
767 767 tests update).
768 768
769 769 $ hg update -r 1
770 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
771 770 getting changed largefiles
772 771 1 largefiles updated, 0 removed
772 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
773 773 $ cat large1
774 774 large11
775 775 $ cat sub/large2
776 776 large22
777 777 $ cd ..
778 778
779 779 Test cloning with --all-largefiles flag
780 780
781 781 $ rm "${USERCACHE}"/*
782 782 $ hg clone --all-largefiles a a-backup
783 783 updating to branch default
784 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
785 784 getting changed largefiles
786 785 3 largefiles updated, 0 removed
786 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
787 787 8 additional largefiles cached
788 788
789 789 $ rm "${USERCACHE}"/*
790 790 $ hg clone --all-largefiles -u 0 a a-clone0
791 791 updating to branch default
792 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
793 792 getting changed largefiles
794 793 2 largefiles updated, 0 removed
794 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
795 795 9 additional largefiles cached
796 796 $ hg -R a-clone0 sum
797 797 parent: 0:30d30fe6a5be
798 798 add files
799 799 branch: default
800 800 commit: (clean)
801 801 update: 7 new changesets (update)
802 802
803 803 $ rm "${USERCACHE}"/*
804 804 $ hg clone --all-largefiles -u 1 a a-clone1
805 805 updating to branch default
806 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
807 806 getting changed largefiles
808 807 2 largefiles updated, 0 removed
808 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
809 809 8 additional largefiles cached
810 810 $ hg -R a-clone1 sum
811 811 parent: 1:ce8896473775
812 812 edit files
813 813 branch: default
814 814 commit: (clean)
815 815 update: 6 new changesets (update)
816 816
817 817 $ rm "${USERCACHE}"/*
818 818 $ hg clone --all-largefiles -U a a-clone-u
819 819 11 additional largefiles cached
820 820 $ hg -R a-clone-u sum
821 821 parent: -1:000000000000 (no revision checked out)
822 822 branch: default
823 823 commit: (clean)
824 824 update: 8 new changesets (update)
825 825
826 826 $ mkdir xyz
827 827 $ cd xyz
828 828 $ hg clone ../a
829 829 destination directory: a
830 830 updating to branch default
831 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
832 831 getting changed largefiles
833 832 3 largefiles updated, 0 removed
833 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
834 834 $ cd ..
835 835
836 836 Ensure base clone command argument validation
837 837
838 838 $ hg clone -U -u 0 a a-clone-failure
839 839 abort: cannot specify both --noupdate and --updaterev
840 840 [255]
841 841
842 842 $ hg clone --all-largefiles a ssh://localhost/a
843 843 abort: --all-largefiles is incompatible with non-local destination ssh://localhost/a
844 844 [255]
845 845
846 846 Test pulling with --all-largefiles flag. Also test that the largefiles are
847 847 downloaded from 'default' instead of 'default-push' when no source is specified
848 848 (issue3584)
849 849
850 850 $ rm -Rf a-backup
851 851 $ hg clone -r 1 a a-backup
852 852 adding changesets
853 853 adding manifests
854 854 adding file changes
855 855 added 2 changesets with 8 changes to 4 files
856 856 updating to branch default
857 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
858 857 getting changed largefiles
859 858 2 largefiles updated, 0 removed
859 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
860 860 $ rm "${USERCACHE}"/*
861 861 $ cd a-backup
862 862 $ hg pull --all-largefiles --config paths.default-push=bogus/path
863 863 pulling from $TESTTMP/a (glob)
864 864 searching for changes
865 865 adding changesets
866 866 adding manifests
867 867 adding file changes
868 868 added 6 changesets with 16 changes to 8 files
869 869 (run 'hg update' to get a working copy)
870 870 caching new largefiles
871 871 3 largefiles cached
872 872 3 additional largefiles cached
873 873 $ cd ..
874 874
875 875 Rebasing between two repositories does not revert largefiles to old
876 876 revisions (this was a very bad bug that took a lot of work to fix).
877 877
878 878 $ hg clone a d
879 879 updating to branch default
880 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
881 880 getting changed largefiles
882 881 3 largefiles updated, 0 removed
882 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
883 883 $ cd b
884 884 $ echo large4-modified > sub/large4
885 885 $ echo normal3-modified > normal3
886 886 $ hg commit -m "modify normal file and largefile in repo b"
887 887 Invoking status precommit hook
888 888 M normal3
889 889 M sub/large4
890 890 $ cd ../d
891 891 $ echo large6-modified > sub2/large6
892 892 $ echo normal4-modified > sub/normal4
893 893 $ hg commit -m "modify normal file largefile in repo d"
894 894 Invoking status precommit hook
895 895 M sub/normal4
896 896 M sub2/large6
897 897 $ cd ..
898 898 $ hg clone d e
899 899 updating to branch default
900 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
901 900 getting changed largefiles
902 901 3 largefiles updated, 0 removed
902 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
903 903 $ cd d
904 904
905 905 More rebase testing, but also test that the largefiles are downloaded from
906 906 'default' instead of 'default-push' when no source is specified (issue3584).
907 907 The error messages go away if repo 'b' is created with --all-largefiles.
908 908 $ hg pull --rebase --all-largefiles --config paths.default-push=bogus/path --config paths.default=../b
909 909 pulling from $TESTTMP/b (glob)
910 910 searching for changes
911 911 adding changesets
912 912 adding manifests
913 913 adding file changes
914 914 added 1 changesets with 2 changes to 2 files (+1 heads)
915 915 Invoking status precommit hook
916 916 M sub/normal4
917 917 M sub2/large6
918 918 saved backup bundle to $TESTTMP/d/.hg/strip-backup/f574fb32bb45-backup.hg (glob)
919 919 error getting eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 from file:$TESTTMP/b for large3: can't get file locally (glob)
920 920 error getting eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 from file:$TESTTMP/b for sub/large4: can't get file locally (glob)
921 921 error getting eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 from file:$TESTTMP/b for large1: can't get file locally (glob)
922 922 error getting eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 from file:$TESTTMP/b for sub/large2: can't get file locally (glob)
923 923 error getting eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 from file:$TESTTMP/b for sub/large2: can't get file locally (glob)
924 924 error getting 5f78770c0e77ba4287ad6ef3071c9bf9c379742f from file:$TESTTMP/b for large1: can't get file locally (glob)
925 925 error getting eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 from file:$TESTTMP/b for sub/large2: can't get file locally (glob)
926 926 error getting 4669e532d5b2c093a78eca010077e708a071bb64 from file:$TESTTMP/b for large1: can't get file locally (glob)
927 927 error getting 1deebade43c8c498a3c8daddac0244dc55d1331d from file:$TESTTMP/b for sub/large2: can't get file locally (glob)
928 928 0 additional largefiles cached
929 929 9 largefiles failed to download
930 930 nothing to rebase
931 931 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
932 932 9:598410d3eb9a modify normal file largefile in repo d
933 933 8:a381d2c8c80e modify normal file and largefile in repo b
934 934 7:daea875e9014 add/edit more largefiles
935 935 6:4355d653f84f edit files yet again
936 936 5:9d5af5072dbd edit files again
937 937 4:74c02385b94c move files
938 938 3:9e8fbc4bce62 copy files
939 939 2:51a0ae4d5864 remove files
940 940 1:ce8896473775 edit files
941 941 0:30d30fe6a5be add files
942 942 $ cat normal3
943 943 normal3-modified
944 944 $ cat sub/normal4
945 945 normal4-modified
946 946 $ cat sub/large4
947 947 large4-modified
948 948 $ cat sub2/large6
949 949 large6-modified
950 950 $ cat sub2/large7
951 951 large7
952 952 $ cd ../e
953 953 $ hg pull ../b
954 954 pulling from ../b
955 955 searching for changes
956 956 adding changesets
957 957 adding manifests
958 958 adding file changes
959 959 added 1 changesets with 2 changes to 2 files (+1 heads)
960 960 (run 'hg heads' to see heads, 'hg merge' to merge)
961 961 caching new largefiles
962 962 0 largefiles cached
963 963 $ hg rebase
964 964 Invoking status precommit hook
965 965 M sub/normal4
966 966 M sub2/large6
967 967 saved backup bundle to $TESTTMP/e/.hg/strip-backup/f574fb32bb45-backup.hg (glob)
968 968 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
969 969 9:598410d3eb9a modify normal file largefile in repo d
970 970 8:a381d2c8c80e modify normal file and largefile in repo b
971 971 7:daea875e9014 add/edit more largefiles
972 972 6:4355d653f84f edit files yet again
973 973 5:9d5af5072dbd edit files again
974 974 4:74c02385b94c move files
975 975 3:9e8fbc4bce62 copy files
976 976 2:51a0ae4d5864 remove files
977 977 1:ce8896473775 edit files
978 978 0:30d30fe6a5be add files
979 979 $ cat normal3
980 980 normal3-modified
981 981 $ cat sub/normal4
982 982 normal4-modified
983 983 $ cat sub/large4
984 984 large4-modified
985 985 $ cat sub2/large6
986 986 large6-modified
987 987 $ cat sub2/large7
988 988 large7
989 989
990 990 Log on largefiles
991 991
992 992 - same output
993 993 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' .hglf/sub/large4
994 994 8:a381d2c8c80e modify normal file and largefile in repo b
995 995 6:4355d653f84f edit files yet again
996 996 5:9d5af5072dbd edit files again
997 997 4:74c02385b94c move files
998 998 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' sub/large4
999 999 8:a381d2c8c80e modify normal file and largefile in repo b
1000 1000 6:4355d653f84f edit files yet again
1001 1001 5:9d5af5072dbd edit files again
1002 1002 4:74c02385b94c move files
1003 1003
1004 1004 - .hglf only matches largefiles, without .hglf it matches 9 bco sub/normal
1005 1005 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' .hglf/sub
1006 1006 8:a381d2c8c80e modify normal file and largefile in repo b
1007 1007 6:4355d653f84f edit files yet again
1008 1008 5:9d5af5072dbd edit files again
1009 1009 4:74c02385b94c move files
1010 1010 1:ce8896473775 edit files
1011 1011 0:30d30fe6a5be add files
1012 1012 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' sub
1013 1013 9:598410d3eb9a modify normal file largefile in repo d
1014 1014 8:a381d2c8c80e modify normal file and largefile in repo b
1015 1015 6:4355d653f84f edit files yet again
1016 1016 5:9d5af5072dbd edit files again
1017 1017 4:74c02385b94c move files
1018 1018 1:ce8896473775 edit files
1019 1019 0:30d30fe6a5be add files
1020 1020
1021 1021 - globbing gives same result
1022 1022 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' 'glob:sub/*'
1023 1023 9:598410d3eb9a modify normal file largefile in repo d
1024 1024 8:a381d2c8c80e modify normal file and largefile in repo b
1025 1025 6:4355d653f84f edit files yet again
1026 1026 5:9d5af5072dbd edit files again
1027 1027 4:74c02385b94c move files
1028 1028 1:ce8896473775 edit files
1029 1029 0:30d30fe6a5be add files
1030 1030
1031 1031 Rollback on largefiles.
1032 1032
1033 1033 $ echo large4-modified-again > sub/large4
1034 1034 $ hg commit -m "Modify large4 again"
1035 1035 Invoking status precommit hook
1036 1036 M sub/large4
1037 1037 $ hg rollback
1038 1038 repository tip rolled back to revision 9 (undo commit)
1039 1039 working directory now based on revision 9
1040 1040 $ hg st
1041 1041 M sub/large4
1042 1042 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
1043 1043 9:598410d3eb9a modify normal file largefile in repo d
1044 1044 8:a381d2c8c80e modify normal file and largefile in repo b
1045 1045 7:daea875e9014 add/edit more largefiles
1046 1046 6:4355d653f84f edit files yet again
1047 1047 5:9d5af5072dbd edit files again
1048 1048 4:74c02385b94c move files
1049 1049 3:9e8fbc4bce62 copy files
1050 1050 2:51a0ae4d5864 remove files
1051 1051 1:ce8896473775 edit files
1052 1052 0:30d30fe6a5be add files
1053 1053 $ cat sub/large4
1054 1054 large4-modified-again
1055 1055
1056 1056 "update --check" refuses to update with uncommitted changes.
1057 1057 $ hg update --check 8
1058 1058 abort: uncommitted local changes
1059 1059 [255]
1060 1060
1061 1061 "update --clean" leaves correct largefiles in working copy, even when there is
1062 1062 .orig files from revert in .hglf.
1063 1063
1064 1064 $ echo mistake > sub2/large7
1065 1065 $ hg revert sub2/large7
1066 1066 $ hg -q update --clean -r null
1067 1067 $ hg update --clean
1068 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1069 1068 getting changed largefiles
1070 1069 3 largefiles updated, 0 removed
1070 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1071 1071 $ cat normal3
1072 1072 normal3-modified
1073 1073 $ cat sub/normal4
1074 1074 normal4-modified
1075 1075 $ cat sub/large4
1076 1076 large4-modified
1077 1077 $ cat sub2/large6
1078 1078 large6-modified
1079 1079 $ cat sub2/large7
1080 1080 large7
1081 1081 $ cat sub2/large7.orig
1082 1082 mistake
1083 1083 $ cat .hglf/sub2/large7.orig
1084 1084 9dbfb2c79b1c40981b258c3efa1b10b03f18ad31
1085 1085
1086 1086 demonstrate misfeature: .orig file is overwritten on every update -C,
1087 1087 also when clean:
1088 1088 $ hg update --clean
1089 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1090 1089 getting changed largefiles
1091 1090 0 largefiles updated, 0 removed
1091 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1092 1092 $ cat sub2/large7.orig
1093 1093 large7
1094 1094 $ rm sub2/large7.orig .hglf/sub2/large7.orig
1095 1095
1096 1096 Now "update check" is happy.
1097 1097 $ hg update --check 8
1098 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1099 1098 getting changed largefiles
1100 1099 1 largefiles updated, 0 removed
1100 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1101 1101 $ hg update --check
1102 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1103 1102 getting changed largefiles
1104 1103 1 largefiles updated, 0 removed
1104 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1105 1105
1106 1106 Test removing empty largefiles directories on update
1107 1107 $ test -d sub2 && echo "sub2 exists"
1108 1108 sub2 exists
1109 1109 $ hg update -q null
1110 1110 $ test -d sub2 && echo "error: sub2 should not exist anymore"
1111 1111 [1]
1112 1112 $ hg update -q
1113 1113
1114 1114 Test hg remove removes empty largefiles directories
1115 1115 $ test -d sub2 && echo "sub2 exists"
1116 1116 sub2 exists
1117 1117 $ hg remove sub2/*
1118 1118 $ test -d sub2 && echo "error: sub2 should not exist anymore"
1119 1119 [1]
1120 1120 $ hg revert sub2/large6 sub2/large7
1121 1121
1122 1122 "revert" works on largefiles (and normal files too).
1123 1123 $ echo hack3 >> normal3
1124 1124 $ echo hack4 >> sub/normal4
1125 1125 $ echo hack4 >> sub/large4
1126 1126 $ rm sub2/large6
1127 1127 $ hg revert sub2/large6
1128 1128 $ hg rm sub2/large6
1129 1129 $ echo new >> sub2/large8
1130 1130 $ hg add --large sub2/large8
1131 1131 # XXX we don't really want to report that we're reverting the standin;
1132 1132 # that's just an implementation detail. But I don't see an obvious fix. ;-(
1133 1133 $ hg revert sub
1134 1134 reverting .hglf/sub/large4 (glob)
1135 1135 reverting sub/normal4 (glob)
1136 1136 $ hg status
1137 1137 M normal3
1138 1138 A sub2/large8
1139 1139 R sub2/large6
1140 1140 ? sub/large4.orig
1141 1141 ? sub/normal4.orig
1142 1142 $ cat sub/normal4
1143 1143 normal4-modified
1144 1144 $ cat sub/large4
1145 1145 large4-modified
1146 1146 $ hg revert -a --no-backup
1147 1147 undeleting .hglf/sub2/large6 (glob)
1148 1148 forgetting .hglf/sub2/large8 (glob)
1149 1149 reverting normal3
1150 1150 $ hg status
1151 1151 ? sub/large4.orig
1152 1152 ? sub/normal4.orig
1153 1153 ? sub2/large8
1154 1154 $ cat normal3
1155 1155 normal3-modified
1156 1156 $ cat sub2/large6
1157 1157 large6-modified
1158 1158 $ rm sub/*.orig sub2/large8
1159 1159
1160 1160 revert some files to an older revision
1161 1161 $ hg revert --no-backup -r 8 sub2
1162 1162 reverting .hglf/sub2/large6 (glob)
1163 1163 $ cat sub2/large6
1164 1164 large6
1165 1165 $ hg revert --no-backup -C -r '.^' sub2
1166 1166 reverting .hglf/sub2/large6 (glob)
1167 1167 $ hg revert --no-backup sub2
1168 1168 reverting .hglf/sub2/large6 (glob)
1169 1169 $ hg status
1170 1170
1171 1171 "verify --large" actually verifies largefiles
1172 1172
1173 1173 $ hg verify --large
1174 1174 checking changesets
1175 1175 checking manifests
1176 1176 crosschecking files in changesets and manifests
1177 1177 checking files
1178 1178 10 files, 10 changesets, 28 total revisions
1179 1179 searching 1 changesets for largefiles
1180 1180 verified existence of 3 revisions of 3 largefiles
1181 1181
1182 1182 Merging does not revert to old versions of largefiles and also check
1183 1183 that merging after having pulled from a non-default remote works
1184 1184 correctly.
1185 1185
1186 1186 $ cd ..
1187 1187 $ hg clone -r 7 e temp
1188 1188 adding changesets
1189 1189 adding manifests
1190 1190 adding file changes
1191 1191 added 8 changesets with 24 changes to 10 files
1192 1192 updating to branch default
1193 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1194 1193 getting changed largefiles
1195 1194 3 largefiles updated, 0 removed
1195 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1196 1196 $ hg clone temp f
1197 1197 updating to branch default
1198 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1199 1198 getting changed largefiles
1200 1199 3 largefiles updated, 0 removed
1200 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1201 1201 # Delete the largefiles in the largefiles system cache so that we have an
1202 1202 # opportunity to test that caching after a pull works.
1203 1203 $ rm "${USERCACHE}"/*
1204 1204 $ cd f
1205 1205 $ echo "large4-merge-test" > sub/large4
1206 1206 $ hg commit -m "Modify large4 to test merge"
1207 1207 Invoking status precommit hook
1208 1208 M sub/large4
1209 1209 $ hg pull ../e
1210 1210 pulling from ../e
1211 1211 searching for changes
1212 1212 adding changesets
1213 1213 adding manifests
1214 1214 adding file changes
1215 1215 added 2 changesets with 4 changes to 4 files (+1 heads)
1216 1216 (run 'hg heads' to see heads, 'hg merge' to merge)
1217 1217 caching new largefiles
1218 1218 2 largefiles cached
1219 1219 $ hg merge
1220 1220 merging sub/large4
1221 1221 largefile sub/large4 has a merge conflict
1222 1222 keep (l)ocal or take (o)ther? l
1223 1223 3 files updated, 1 files merged, 0 files removed, 0 files unresolved
1224 1224 (branch merge, don't forget to commit)
1225 1225 getting changed largefiles
1226 1226 1 largefiles updated, 0 removed
1227 1227 $ hg commit -m "Merge repos e and f"
1228 1228 Invoking status precommit hook
1229 1229 M normal3
1230 1230 M sub/normal4
1231 1231 M sub2/large6
1232 1232 $ cat normal3
1233 1233 normal3-modified
1234 1234 $ cat sub/normal4
1235 1235 normal4-modified
1236 1236 $ cat sub/large4
1237 1237 large4-merge-test
1238 1238 $ cat sub2/large6
1239 1239 large6-modified
1240 1240 $ cat sub2/large7
1241 1241 large7
1242 1242
1243 1243 Test status after merging with a branch that introduces a new largefile:
1244 1244
1245 1245 $ echo large > large
1246 1246 $ hg add --large large
1247 1247 $ hg commit -m 'add largefile'
1248 1248 Invoking status precommit hook
1249 1249 A large
1250 1250 $ hg update -q ".^"
1251 1251 $ echo change >> normal3
1252 1252 $ hg commit -m 'some change'
1253 1253 Invoking status precommit hook
1254 1254 M normal3
1255 1255 created new head
1256 1256 $ hg merge
1257 1257 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1258 1258 (branch merge, don't forget to commit)
1259 1259 getting changed largefiles
1260 1260 1 largefiles updated, 0 removed
1261 1261 $ hg status
1262 1262 M large
1263 1263
1264 1264 - make sure update of merge with removed largefiles fails as expected
1265 1265 $ hg rm sub2/large6
1266 1266 $ hg up -r.
1267 1267 abort: outstanding uncommitted merges
1268 1268 [255]
1269 1269
1270 1270 - revert should be able to revert files introduced in a pending merge
1271 1271 $ hg revert --all -r .
1272 1272 removing .hglf/large
1273 1273 undeleting .hglf/sub2/large6
1274 1274
1275 1275 Test that a normal file and a largefile with the same name and path cannot
1276 1276 coexist.
1277 1277
1278 1278 $ rm sub2/large7
1279 1279 $ echo "largeasnormal" > sub2/large7
1280 1280 $ hg add sub2/large7
1281 1281 sub2/large7 already a largefile
1282 1282
1283 1283 Test that transplanting a largefile change works correctly.
1284 1284
1285 1285 $ cd ..
1286 1286 $ hg clone -r 8 d g
1287 1287 adding changesets
1288 1288 adding manifests
1289 1289 adding file changes
1290 1290 added 9 changesets with 26 changes to 10 files
1291 1291 updating to branch default
1292 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1293 1292 getting changed largefiles
1294 1293 3 largefiles updated, 0 removed
1294 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1295 1295 $ cd g
1296 1296 $ hg transplant -s ../d 598410d3eb9a
1297 1297 searching for changes
1298 1298 searching for changes
1299 1299 adding changesets
1300 1300 adding manifests
1301 1301 adding file changes
1302 1302 added 1 changesets with 2 changes to 2 files
1303 1303 getting changed largefiles
1304 1304 1 largefiles updated, 0 removed
1305 1305 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
1306 1306 9:598410d3eb9a modify normal file largefile in repo d
1307 1307 8:a381d2c8c80e modify normal file and largefile in repo b
1308 1308 7:daea875e9014 add/edit more largefiles
1309 1309 6:4355d653f84f edit files yet again
1310 1310 5:9d5af5072dbd edit files again
1311 1311 4:74c02385b94c move files
1312 1312 3:9e8fbc4bce62 copy files
1313 1313 2:51a0ae4d5864 remove files
1314 1314 1:ce8896473775 edit files
1315 1315 0:30d30fe6a5be add files
1316 1316 $ cat normal3
1317 1317 normal3-modified
1318 1318 $ cat sub/normal4
1319 1319 normal4-modified
1320 1320 $ cat sub/large4
1321 1321 large4-modified
1322 1322 $ cat sub2/large6
1323 1323 large6-modified
1324 1324 $ cat sub2/large7
1325 1325 large7
1326 1326
1327 1327 Cat a largefile
1328 1328 $ hg cat normal3
1329 1329 normal3-modified
1330 1330 $ hg cat sub/large4
1331 1331 large4-modified
1332 1332 $ rm "${USERCACHE}"/*
1333 1333 $ hg cat -r a381d2c8c80e -o cat.out sub/large4
1334 1334 $ cat cat.out
1335 1335 large4-modified
1336 1336 $ rm cat.out
1337 1337 $ hg cat -r a381d2c8c80e normal3
1338 1338 normal3-modified
1339 1339 $ hg cat -r '.^' normal3
1340 1340 normal3-modified
1341 1341 $ hg cat -r '.^' sub/large4
1342 1342 large4-modified
1343 1343
1344 1344 Test that renaming a largefile results in correct output for status
1345 1345
1346 1346 $ hg rename sub/large4 large4-renamed
1347 1347 $ hg commit -m "test rename output"
1348 1348 Invoking status precommit hook
1349 1349 A large4-renamed
1350 1350 R sub/large4
1351 1351 $ cat large4-renamed
1352 1352 large4-modified
1353 1353 $ cd sub2
1354 1354 $ hg rename large6 large6-renamed
1355 1355 $ hg st
1356 1356 A sub2/large6-renamed
1357 1357 R sub2/large6
1358 1358 $ cd ..
1359 1359
1360 1360 Test --normal flag
1361 1361
1362 1362 $ dd if=/dev/zero bs=2k count=11k > new-largefile 2> /dev/null
1363 1363 $ hg add --normal --large new-largefile
1364 1364 abort: --normal cannot be used with --large
1365 1365 [255]
1366 1366 $ hg add --normal new-largefile
1367 1367 new-largefile: up to 69 MB of RAM may be required to manage this file
1368 1368 (use 'hg revert new-largefile' to cancel the pending addition)
1369 1369 $ cd ..
1370 1370
1371 1371 #if serve
1372 1372 vanilla clients not locked out from largefiles servers on vanilla repos
1373 1373 $ mkdir r1
1374 1374 $ cd r1
1375 1375 $ hg init
1376 1376 $ echo c1 > f1
1377 1377 $ hg add f1
1378 1378 $ hg commit -m "m1"
1379 1379 Invoking status precommit hook
1380 1380 A f1
1381 1381 $ cd ..
1382 1382 $ hg serve -R r1 -d -p $HGPORT --pid-file hg.pid
1383 1383 $ cat hg.pid >> $DAEMON_PIDS
1384 1384 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT r2
1385 1385 requesting all changes
1386 1386 adding changesets
1387 1387 adding manifests
1388 1388 adding file changes
1389 1389 added 1 changesets with 1 changes to 1 files
1390 1390 updating to branch default
1391 1391 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1392 1392
1393 1393 largefiles clients still work with vanilla servers
1394 1394 $ hg --config extensions.largefiles=! serve -R r1 -d -p $HGPORT1 --pid-file hg.pid
1395 1395 $ cat hg.pid >> $DAEMON_PIDS
1396 1396 $ hg clone http://localhost:$HGPORT1 r3
1397 1397 requesting all changes
1398 1398 adding changesets
1399 1399 adding manifests
1400 1400 adding file changes
1401 1401 added 1 changesets with 1 changes to 1 files
1402 1402 updating to branch default
1403 1403 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1404 1404 #endif
1405 1405
1406 1406
1407 1407 vanilla clients locked out from largefiles http repos
1408 1408 $ mkdir r4
1409 1409 $ cd r4
1410 1410 $ hg init
1411 1411 $ echo c1 > f1
1412 1412 $ hg add --large f1
1413 1413 $ hg commit -m "m1"
1414 1414 Invoking status precommit hook
1415 1415 A f1
1416 1416 $ cd ..
1417 1417
1418 1418 largefiles can be pushed locally (issue3583)
1419 1419 $ hg init dest
1420 1420 $ cd r4
1421 1421 $ hg outgoing ../dest
1422 1422 comparing with ../dest
1423 1423 searching for changes
1424 1424 changeset: 0:639881c12b4c
1425 1425 tag: tip
1426 1426 user: test
1427 1427 date: Thu Jan 01 00:00:00 1970 +0000
1428 1428 summary: m1
1429 1429
1430 1430 $ hg push ../dest
1431 1431 pushing to ../dest
1432 1432 searching for changes
1433 1433 searching for changes
1434 1434 adding changesets
1435 1435 adding manifests
1436 1436 adding file changes
1437 1437 added 1 changesets with 1 changes to 1 files
1438 1438
1439 1439 exit code with nothing outgoing (issue3611)
1440 1440 $ hg outgoing ../dest
1441 1441 comparing with ../dest
1442 1442 searching for changes
1443 1443 no changes found
1444 1444 [1]
1445 1445 $ cd ..
1446 1446
1447 1447 #if serve
1448 1448 $ hg serve -R r4 -d -p $HGPORT2 --pid-file hg.pid
1449 1449 $ cat hg.pid >> $DAEMON_PIDS
1450 1450 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT2 r5
1451 1451 abort: remote error:
1452 1452
1453 1453 This repository uses the largefiles extension.
1454 1454
1455 1455 Please enable it in your Mercurial config file.
1456 1456 [255]
1457 1457
1458 1458 used all HGPORTs, kill all daemons
1459 1459 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1460 1460 #endif
1461 1461
1462 1462 vanilla clients locked out from largefiles ssh repos
1463 1463 $ hg --config extensions.largefiles=! clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/r4 r5
1464 1464 abort: remote error:
1465 1465
1466 1466 This repository uses the largefiles extension.
1467 1467
1468 1468 Please enable it in your Mercurial config file.
1469 1469 [255]
1470 1470
1471 1471 #if serve
1472 1472
1473 1473 largefiles clients refuse to push largefiles repos to vanilla servers
1474 1474 $ mkdir r6
1475 1475 $ cd r6
1476 1476 $ hg init
1477 1477 $ echo c1 > f1
1478 1478 $ hg add f1
1479 1479 $ hg commit -m "m1"
1480 1480 Invoking status precommit hook
1481 1481 A f1
1482 1482 $ cat >> .hg/hgrc <<!
1483 1483 > [web]
1484 1484 > push_ssl = false
1485 1485 > allow_push = *
1486 1486 > !
1487 1487 $ cd ..
1488 1488 $ hg clone r6 r7
1489 1489 updating to branch default
1490 1490 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1491 1491 $ cd r7
1492 1492 $ echo c2 > f2
1493 1493 $ hg add --large f2
1494 1494 $ hg commit -m "m2"
1495 1495 Invoking status precommit hook
1496 1496 A f2
1497 1497 $ hg --config extensions.largefiles=! -R ../r6 serve -d -p $HGPORT --pid-file ../hg.pid
1498 1498 $ cat ../hg.pid >> $DAEMON_PIDS
1499 1499 $ hg push http://localhost:$HGPORT
1500 1500 pushing to http://localhost:$HGPORT/
1501 1501 searching for changes
1502 1502 abort: http://localhost:$HGPORT/ does not appear to be a largefile store
1503 1503 [255]
1504 1504 $ cd ..
1505 1505
1506 1506 putlfile errors are shown (issue3123)
1507 1507 Corrupt the cached largefile in r7 and in the usercache (required for testing on vfat)
1508 1508 $ echo corruption > "$TESTTMP/r7/.hg/largefiles/4cdac4d8b084d0b599525cf732437fb337d422a8"
1509 1509 $ echo corruption > "$USERCACHE/4cdac4d8b084d0b599525cf732437fb337d422a8"
1510 1510 $ hg init empty
1511 1511 $ hg serve -R empty -d -p $HGPORT1 --pid-file hg.pid \
1512 1512 > --config 'web.allow_push=*' --config web.push_ssl=False
1513 1513 $ cat hg.pid >> $DAEMON_PIDS
1514 1514 $ hg push -R r7 http://localhost:$HGPORT1
1515 1515 pushing to http://localhost:$HGPORT1/
1516 1516 searching for changes
1517 1517 remote: largefiles: failed to put 4cdac4d8b084d0b599525cf732437fb337d422a8 into store: largefile contents do not match hash
1518 1518 abort: remotestore: could not put $TESTTMP/r7/.hg/largefiles/4cdac4d8b084d0b599525cf732437fb337d422a8 to remote store http://localhost:$HGPORT1/ (glob)
1519 1519 [255]
1520 1520 $ rm -rf empty
1521 1521
1522 1522 Push a largefiles repository to a served empty repository
1523 1523 $ hg init r8
1524 1524 $ echo c3 > r8/f1
1525 1525 $ hg add --large r8/f1 -R r8
1526 1526 $ hg commit -m "m1" -R r8
1527 1527 Invoking status precommit hook
1528 1528 A f1
1529 1529 $ hg init empty
1530 1530 $ hg serve -R empty -d -p $HGPORT2 --pid-file hg.pid \
1531 1531 > --config 'web.allow_push=*' --config web.push_ssl=False
1532 1532 $ cat hg.pid >> $DAEMON_PIDS
1533 1533 $ rm "${USERCACHE}"/*
1534 1534 $ hg push -R r8 http://localhost:$HGPORT2
1535 1535 pushing to http://localhost:$HGPORT2/
1536 1536 searching for changes
1537 1537 searching for changes
1538 1538 remote: adding changesets
1539 1539 remote: adding manifests
1540 1540 remote: adding file changes
1541 1541 remote: added 1 changesets with 1 changes to 1 files
1542 1542
1543 1543 Clone over http, with largefiles being pulled on update, not on clone.
1544 1544
1545 1545 $ hg clone -q http://localhost:$HGPORT2/ http-clone -U
1546 1546
1547 1547 $ hg -R http-clone --debug up --config largefiles.usercache=http-clone-usercache
1548 1548 resolving manifests
1549 1549 overwrite: False, partial: False
1550 1550 ancestor: 000000000000, local: 000000000000+, remote: cf03e5bb9936
1551 1551 .hglf/f1: remote created -> g
1552 1552 updating: .hglf/f1 1/1 files (100.00%)
1553 1553 getting .hglf/f1
1554 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1555 1554 getting changed largefiles
1556 1555 using http://localhost:$HGPORT2/
1557 1556 sending capabilities command
1558 1557 getting largefiles: 0/1 lfile (0.00%)
1559 1558 getting f1:02a439e5c31c526465ab1a0ca1f431f76b827b90
1560 1559 sending batch command
1561 1560 sending getlfile command
1562 1561 found 02a439e5c31c526465ab1a0ca1f431f76b827b90 in store
1563 1562 1 largefiles updated, 0 removed
1563 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1564 1564
1565 1565 $ ls http-clone-usercache/*
1566 1566 http-clone-usercache/02a439e5c31c526465ab1a0ca1f431f76b827b90
1567 1567
1568 1568 $ rm -rf empty http-clone http-clone-usercache
1569 1569
1570 1570 used all HGPORTs, kill all daemons
1571 1571 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1572 1572
1573 1573 #endif
1574 1574
1575 1575
1576 1576 #if unix-permissions
1577 1577
1578 1578 Clone a local repository owned by another user
1579 1579 We have to simulate that here by setting $HOME and removing write permissions
1580 1580 $ ORIGHOME="$HOME"
1581 1581 $ mkdir alice
1582 1582 $ HOME="`pwd`/alice"
1583 1583 $ cd alice
1584 1584 $ hg init pubrepo
1585 1585 $ cd pubrepo
1586 1586 $ dd if=/dev/zero bs=1k count=11k > a-large-file 2> /dev/null
1587 1587 $ hg add --large a-large-file
1588 1588 $ hg commit -m "Add a large file"
1589 1589 Invoking status precommit hook
1590 1590 A a-large-file
1591 1591 $ cd ..
1592 1592 $ chmod -R a-w pubrepo
1593 1593 $ cd ..
1594 1594 $ mkdir bob
1595 1595 $ HOME="`pwd`/bob"
1596 1596 $ cd bob
1597 1597 $ hg clone --pull ../alice/pubrepo pubrepo
1598 1598 requesting all changes
1599 1599 adding changesets
1600 1600 adding manifests
1601 1601 adding file changes
1602 1602 added 1 changesets with 1 changes to 1 files
1603 1603 updating to branch default
1604 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1605 1604 getting changed largefiles
1606 1605 1 largefiles updated, 0 removed
1606 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1607 1607 $ cd ..
1608 1608 $ chmod -R u+w alice/pubrepo
1609 1609 $ HOME="$ORIGHOME"
1610 1610
1611 1611 #endif
1612 1612
1613 1613 #if symlink
1614 1614
1615 1615 Symlink to a large largefile should behave the same as a symlink to a normal file
1616 1616 $ hg init largesymlink
1617 1617 $ cd largesymlink
1618 1618 $ dd if=/dev/zero bs=1k count=10k of=largefile 2>/dev/null
1619 1619 $ hg add --large largefile
1620 1620 $ hg commit -m "commit a large file"
1621 1621 Invoking status precommit hook
1622 1622 A largefile
1623 1623 $ ln -s largefile largelink
1624 1624 $ hg add largelink
1625 1625 $ hg commit -m "commit a large symlink"
1626 1626 Invoking status precommit hook
1627 1627 A largelink
1628 1628 $ rm -f largelink
1629 1629 $ hg up >/dev/null
1630 1630 $ test -f largelink
1631 1631 [1]
1632 1632 $ test -L largelink
1633 1633 [1]
1634 1634 $ rm -f largelink # make next part of the test independent of the previous
1635 1635 $ hg up -C >/dev/null
1636 1636 $ test -f largelink
1637 1637 $ test -L largelink
1638 1638 $ cd ..
1639 1639
1640 1640 #endif
1641 1641
1642 1642 test for pattern matching on 'hg status':
1643 1643 to boost performance, largefiles checks whether specified patterns are
1644 1644 related to largefiles in working directory (NOT to STANDIN) or not.
1645 1645
1646 1646 $ hg init statusmatch
1647 1647 $ cd statusmatch
1648 1648
1649 1649 $ mkdir -p a/b/c/d
1650 1650 $ echo normal > a/b/c/d/e.normal.txt
1651 1651 $ hg add a/b/c/d/e.normal.txt
1652 1652 $ echo large > a/b/c/d/e.large.txt
1653 1653 $ hg add --large a/b/c/d/e.large.txt
1654 1654 $ mkdir -p a/b/c/x
1655 1655 $ echo normal > a/b/c/x/y.normal.txt
1656 1656 $ hg add a/b/c/x/y.normal.txt
1657 1657 $ hg commit -m 'add files'
1658 1658 Invoking status precommit hook
1659 1659 A a/b/c/d/e.large.txt
1660 1660 A a/b/c/d/e.normal.txt
1661 1661 A a/b/c/x/y.normal.txt
1662 1662
1663 1663 (1) no pattern: no performance boost
1664 1664 $ hg status -A
1665 1665 C a/b/c/d/e.large.txt
1666 1666 C a/b/c/d/e.normal.txt
1667 1667 C a/b/c/x/y.normal.txt
1668 1668
1669 1669 (2) pattern not related to largefiles: performance boost
1670 1670 $ hg status -A a/b/c/x
1671 1671 C a/b/c/x/y.normal.txt
1672 1672
1673 1673 (3) pattern related to largefiles: no performance boost
1674 1674 $ hg status -A a/b/c/d
1675 1675 C a/b/c/d/e.large.txt
1676 1676 C a/b/c/d/e.normal.txt
1677 1677
1678 1678 (4) pattern related to STANDIN (not to largefiles): performance boost
1679 1679 $ hg status -A .hglf/a
1680 1680 C .hglf/a/b/c/d/e.large.txt
1681 1681
1682 1682 (5) mixed case: no performance boost
1683 1683 $ hg status -A a/b/c/x a/b/c/d
1684 1684 C a/b/c/d/e.large.txt
1685 1685 C a/b/c/d/e.normal.txt
1686 1686 C a/b/c/x/y.normal.txt
1687 1687
1688 1688 verify that largefiles doesn't break filesets
1689 1689
1690 1690 $ hg log --rev . --exclude "set:binary()"
1691 1691 changeset: 0:41bd42f10efa
1692 1692 tag: tip
1693 1693 user: test
1694 1694 date: Thu Jan 01 00:00:00 1970 +0000
1695 1695 summary: add files
1696 1696
1697 1697 verify that large files in subrepos handled properly
1698 1698 $ hg init subrepo
1699 1699 $ echo "subrepo = subrepo" > .hgsub
1700 1700 $ hg add .hgsub
1701 1701 $ hg ci -m "add subrepo"
1702 1702 Invoking status precommit hook
1703 1703 A .hgsub
1704 1704 ? .hgsubstate
1705 1705 $ echo "rev 1" > subrepo/large.txt
1706 1706 $ hg -R subrepo add --large subrepo/large.txt
1707 1707 $ hg sum
1708 1708 parent: 1:8ee150ea2e9c tip
1709 1709 add subrepo
1710 1710 branch: default
1711 1711 commit: 1 subrepos
1712 1712 update: (current)
1713 1713 $ hg st
1714 1714 $ hg st -S
1715 1715 A subrepo/large.txt
1716 1716 $ hg ci -S -m "commit top repo"
1717 1717 committing subrepository subrepo
1718 1718 Invoking status precommit hook
1719 1719 A large.txt
1720 1720 Invoking status precommit hook
1721 1721 M .hgsubstate
1722 1722 # No differences
1723 1723 $ hg st -S
1724 1724 $ hg sum
1725 1725 parent: 2:ce4cd0c527a6 tip
1726 1726 commit top repo
1727 1727 branch: default
1728 1728 commit: (clean)
1729 1729 update: (current)
1730 1730 $ echo "rev 2" > subrepo/large.txt
1731 1731 $ hg st -S
1732 1732 M subrepo/large.txt
1733 1733 $ hg sum
1734 1734 parent: 2:ce4cd0c527a6 tip
1735 1735 commit top repo
1736 1736 branch: default
1737 1737 commit: 1 subrepos
1738 1738 update: (current)
1739 1739 $ hg ci -m "this commit should fail without -S"
1740 1740 abort: uncommitted changes in subrepo subrepo
1741 1741 (use --subrepos for recursive commit)
1742 1742 [255]
1743 1743
1744 1744 Add a normal file to the subrepo, then test archiving
1745 1745
1746 1746 $ echo 'normal file' > subrepo/normal.txt
1747 1747 $ hg -R subrepo add subrepo/normal.txt
1748 1748
1749 1749 Lock in subrepo, otherwise the change isn't archived
1750 1750
1751 1751 $ hg ci -S -m "add normal file to top level"
1752 1752 committing subrepository subrepo
1753 1753 Invoking status precommit hook
1754 1754 M large.txt
1755 1755 A normal.txt
1756 1756 Invoking status precommit hook
1757 1757 M .hgsubstate
1758 $ hg archive -S lf_subrepo_archive
1759 $ find lf_subrepo_archive | sort
1760 lf_subrepo_archive
1761 lf_subrepo_archive/.hg_archival.txt
1762 lf_subrepo_archive/.hgsub
1763 lf_subrepo_archive/.hgsubstate
1764 lf_subrepo_archive/a
1765 lf_subrepo_archive/a/b
1766 lf_subrepo_archive/a/b/c
1767 lf_subrepo_archive/a/b/c/d
1768 lf_subrepo_archive/a/b/c/d/e.large.txt
1769 lf_subrepo_archive/a/b/c/d/e.normal.txt
1770 lf_subrepo_archive/a/b/c/x
1771 lf_subrepo_archive/a/b/c/x/y.normal.txt
1772 lf_subrepo_archive/subrepo
1773 lf_subrepo_archive/subrepo/large.txt
1774 lf_subrepo_archive/subrepo/normal.txt
1758 $ hg archive -S ../lf_subrepo_archive
1759 $ find ../lf_subrepo_archive | sort
1760 ../lf_subrepo_archive
1761 ../lf_subrepo_archive/.hg_archival.txt
1762 ../lf_subrepo_archive/.hgsub
1763 ../lf_subrepo_archive/.hgsubstate
1764 ../lf_subrepo_archive/a
1765 ../lf_subrepo_archive/a/b
1766 ../lf_subrepo_archive/a/b/c
1767 ../lf_subrepo_archive/a/b/c/d
1768 ../lf_subrepo_archive/a/b/c/d/e.large.txt
1769 ../lf_subrepo_archive/a/b/c/d/e.normal.txt
1770 ../lf_subrepo_archive/a/b/c/x
1771 ../lf_subrepo_archive/a/b/c/x/y.normal.txt
1772 ../lf_subrepo_archive/subrepo
1773 ../lf_subrepo_archive/subrepo/large.txt
1774 ../lf_subrepo_archive/subrepo/normal.txt
1775
1776 Test update with subrepos.
1777
1778 $ hg update 0
1779 getting changed largefiles
1780 0 largefiles updated, 1 removed
1781 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
1782 $ hg status -S
1783 $ hg update tip
1784 getting changed largefiles
1785 1 largefiles updated, 0 removed
1786 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1787 $ hg status -S
1788 # modify a large file
1789 $ echo "modified" > subrepo/large.txt
1790 $ hg st -S
1791 M subrepo/large.txt
1792 # update -C should revert the change.
1793 $ hg update -C
1794 getting changed largefiles
1795 1 largefiles updated, 0 removed
1796 getting changed largefiles
1797 0 largefiles updated, 0 removed
1798 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1799 $ hg status -S
1775 1800
1776 1801 Test archiving a revision that references a subrepo that is not yet
1777 1802 cloned (see test-subrepo-recursion.t):
1778 1803
1779 1804 $ hg clone -U . ../empty
1780 1805 $ cd ../empty
1781 1806 $ hg archive --subrepos -r tip ../archive.tar.gz
1782 1807 cloning subrepo subrepo from $TESTTMP/statusmatch/subrepo
1783 1808 $ cd ..
1784 1809
1785 1810 Test that addremove picks up largefiles prior to the initial commit (issue3541)
1786 1811
1787 1812 $ hg init addrm2
1788 1813 $ cd addrm2
1789 1814 $ touch large.dat
1790 1815 $ touch large2.dat
1791 1816 $ touch normal
1792 1817 $ hg add --large large.dat
1793 1818 $ hg addremove -v
1794 1819 adding large2.dat as a largefile
1795 1820 adding normal
1796 1821
1797 1822 Test that forgetting all largefiles reverts to islfilesrepo() == False
1798 1823 (addremove will add *.dat as normal files now)
1799 1824 $ hg forget large.dat
1800 1825 $ hg forget large2.dat
1801 1826 $ hg addremove -v
1802 1827 adding large.dat
1803 1828 adding large2.dat
1804 1829
1805 1830 Test commit's addremove option prior to the first commit
1806 1831 $ hg forget large.dat
1807 1832 $ hg forget large2.dat
1808 1833 $ hg add --large large.dat
1809 1834 $ hg ci -Am "commit"
1810 1835 adding large2.dat as a largefile
1811 1836 Invoking status precommit hook
1812 1837 A large.dat
1813 1838 A large2.dat
1814 1839 A normal
1815 1840 $ find .hglf | sort
1816 1841 .hglf
1817 1842 .hglf/large.dat
1818 1843 .hglf/large2.dat
1819 1844
1820 1845 $ cd ..
1821 1846
1822 1847 issue3651: summary/outgoing with largefiles shows "no remote repo"
1823 1848 unexpectedly
1824 1849
1825 1850 $ mkdir issue3651
1826 1851 $ cd issue3651
1827 1852
1828 1853 $ hg init src
1829 1854 $ echo a > src/a
1830 1855 $ hg -R src add --large src/a
1831 1856 $ hg -R src commit -m '#0'
1832 1857 Invoking status precommit hook
1833 1858 A a
1834 1859
1835 1860 check messages when no remote repository is specified:
1836 1861 "no remote repo" route for "hg outgoing --large" is not tested here,
1837 1862 because it can't be reproduced easily.
1838 1863
1839 1864 $ hg init clone1
1840 1865 $ hg -R clone1 -q pull src
1841 1866 $ hg -R clone1 -q update
1842 1867 $ hg -R clone1 paths | grep default
1843 1868 [1]
1844 1869
1845 1870 $ hg -R clone1 summary --large
1846 1871 parent: 0:fc0bd45326d3 tip
1847 1872 #0
1848 1873 branch: default
1849 1874 commit: (clean)
1850 1875 update: (current)
1851 1876 largefiles: (no remote repo)
1852 1877
1853 1878 check messages when there is no files to upload:
1854 1879
1855 1880 $ hg -q clone src clone2
1856 1881 $ hg -R clone2 paths | grep default
1857 1882 default = $TESTTMP/issue3651/src (glob)
1858 1883
1859 1884 $ hg -R clone2 summary --large
1860 1885 parent: 0:fc0bd45326d3 tip
1861 1886 #0
1862 1887 branch: default
1863 1888 commit: (clean)
1864 1889 update: (current)
1865 1890 searching for changes
1866 1891 largefiles: (no files to upload)
1867 1892 $ hg -R clone2 outgoing --large
1868 1893 comparing with $TESTTMP/issue3651/src (glob)
1869 1894 searching for changes
1870 1895 no changes found
1871 1896 searching for changes
1872 1897 largefiles: no files to upload
1873 1898 [1]
1874 1899
1875 1900 check messages when there are files to upload:
1876 1901
1877 1902 $ echo b > clone2/b
1878 1903 $ hg -R clone2 add --large clone2/b
1879 1904 $ hg -R clone2 commit -m '#1'
1880 1905 Invoking status precommit hook
1881 1906 A b
1882 1907 $ hg -R clone2 summary --large
1883 1908 parent: 1:1acbe71ce432 tip
1884 1909 #1
1885 1910 branch: default
1886 1911 commit: (clean)
1887 1912 update: (current)
1888 1913 searching for changes
1889 1914 largefiles: 1 to upload
1890 1915 $ hg -R clone2 outgoing --large
1891 1916 comparing with $TESTTMP/issue3651/src (glob)
1892 1917 searching for changes
1893 1918 changeset: 1:1acbe71ce432
1894 1919 tag: tip
1895 1920 user: test
1896 1921 date: Thu Jan 01 00:00:00 1970 +0000
1897 1922 summary: #1
1898 1923
1899 1924 searching for changes
1900 1925 largefiles to upload:
1901 1926 b
1902 1927
1903 1928
1904 1929 $ cd ..
@@ -1,356 +1,356 b''
1 1 $ USERCACHE="$TESTTMP/cache"; export USERCACHE
2 2 $ mkdir "${USERCACHE}"
3 3 $ cat >> $HGRCPATH <<EOF
4 4 > [extensions]
5 5 > largefiles =
6 6 > share =
7 7 > graphlog =
8 8 > mq =
9 9 > convert =
10 10 > [largefiles]
11 11 > minsize = 0.5
12 12 > patterns = **.other
13 13 > **.dat
14 14 > usercache=${USERCACHE}
15 15 > EOF
16 16
17 17 "lfconvert" works
18 18 $ hg init bigfile-repo
19 19 $ cd bigfile-repo
20 20 $ cat >> .hg/hgrc <<EOF
21 21 > [extensions]
22 22 > largefiles = !
23 23 > EOF
24 24 $ mkdir sub
25 25 $ dd if=/dev/zero bs=1k count=256 > large 2> /dev/null
26 26 $ dd if=/dev/zero bs=1k count=256 > large2 2> /dev/null
27 27 $ echo normal > normal1
28 28 $ echo alsonormal > sub/normal2
29 29 $ dd if=/dev/zero bs=1k count=10 > sub/maybelarge.dat 2> /dev/null
30 30 $ hg addremove
31 31 adding large
32 32 adding large2
33 33 adding normal1
34 34 adding sub/maybelarge.dat
35 35 adding sub/normal2
36 36 $ hg commit -m"add large, normal1" large normal1
37 37 $ hg commit -m"add sub/*" sub
38 38
39 39 Test tag parsing
40 40 $ cat >> .hgtags <<EOF
41 41 > IncorrectlyFormattedTag!
42 42 > invalidhash sometag
43 43 > 0123456789abcdef anothertag
44 44 > EOF
45 45 $ hg add .hgtags
46 46 $ hg commit -m"add large2" large2 .hgtags
47 47
48 48 Test link+rename largefile codepath
49 49 $ [ -d .hg/largefiles ] && echo fail || echo pass
50 50 pass
51 51 $ cd ..
52 52 $ hg lfconvert --size 0.2 bigfile-repo largefiles-repo
53 53 initializing destination largefiles-repo
54 54 skipping incorrectly formatted tag IncorrectlyFormattedTag!
55 55 skipping incorrectly formatted id invalidhash
56 56 no mapping for id 0123456789abcdef
57 57 #if symlink
58 58 $ hg --cwd bigfile-repo rename large2 large3
59 59 $ ln -sf large bigfile-repo/large3
60 60 $ hg --cwd bigfile-repo commit -m"make large2 a symlink" large2 large3
61 61 $ hg lfconvert --size 0.2 bigfile-repo largefiles-repo-symlink
62 62 initializing destination largefiles-repo-symlink
63 63 skipping incorrectly formatted tag IncorrectlyFormattedTag!
64 64 skipping incorrectly formatted id invalidhash
65 65 no mapping for id 0123456789abcdef
66 66 abort: renamed/copied largefile large3 becomes symlink
67 67 [255]
68 68 #endif
69 69 $ cd bigfile-repo
70 70 $ hg strip --no-backup 2
71 71 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
72 72 $ cd ..
73 73 $ rm -rf largefiles-repo largefiles-repo-symlink
74 74
75 75 $ hg lfconvert --size 0.2 bigfile-repo largefiles-repo
76 76 initializing destination largefiles-repo
77 77
78 78 "lfconvert" converts content correctly
79 79 $ cd largefiles-repo
80 80 $ hg up
81 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
82 81 getting changed largefiles
83 82 2 largefiles updated, 0 removed
83 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
84 84 $ hg locate
85 85 .hglf/large
86 86 .hglf/sub/maybelarge.dat
87 87 normal1
88 88 sub/normal2
89 89 $ cat normal1
90 90 normal
91 91 $ cat sub/normal2
92 92 alsonormal
93 93 $ "$TESTDIR/md5sum.py" large sub/maybelarge.dat
94 94 ec87a838931d4d5d2e94a04644788a55 large
95 95 1276481102f218c981e0324180bafd9f sub/maybelarge.dat
96 96
97 97 "lfconvert" adds 'largefiles' to .hg/requires.
98 98 $ cat .hg/requires
99 99 dotencode
100 100 fncache
101 101 largefiles
102 102 revlogv1
103 103 store
104 104
105 105 "lfconvert" includes a newline at the end of the standin files.
106 106 $ cat .hglf/large .hglf/sub/maybelarge.dat
107 107 2e000fa7e85759c7f4c254d4d9c33ef481e459a7
108 108 34e163be8e43c5631d8b92e9c43ab0bf0fa62b9c
109 109 $ cd ..
110 110
111 111 add some changesets to rename/remove/merge
112 112 $ cd bigfile-repo
113 113 $ hg mv -q sub stuff
114 114 $ hg commit -m"rename sub/ to stuff/"
115 115 $ hg update -q 1
116 116 $ echo blah >> normal3
117 117 $ echo blah >> sub/normal2
118 118 $ echo blah >> sub/maybelarge.dat
119 119 $ "$TESTDIR/md5sum.py" sub/maybelarge.dat
120 120 1dd0b99ff80e19cff409702a1d3f5e15 sub/maybelarge.dat
121 121 $ hg commit -A -m"add normal3, modify sub/*"
122 122 adding normal3
123 123 created new head
124 124 $ hg rm large normal3
125 125 $ hg commit -q -m"remove large, normal3"
126 126 $ hg merge
127 127 merging sub/maybelarge.dat and stuff/maybelarge.dat to stuff/maybelarge.dat
128 128 warning: $TESTTMP/bigfile-repo/stuff/maybelarge.dat looks like a binary file. (glob)
129 129 merging stuff/maybelarge.dat incomplete! (edit conflicts, then use 'hg resolve --mark')
130 130 merging sub/normal2 and stuff/normal2 to stuff/normal2
131 131 0 files updated, 1 files merged, 0 files removed, 1 files unresolved
132 132 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
133 133 [1]
134 134 $ hg cat -r . sub/maybelarge.dat > stuff/maybelarge.dat
135 135 $ hg resolve -m stuff/maybelarge.dat
136 136 $ hg commit -m"merge"
137 137 $ hg glog --template "{rev}:{node|short} {desc|firstline}\n"
138 138 @ 5:4884f215abda merge
139 139 |\
140 140 | o 4:7285f817b77e remove large, normal3
141 141 | |
142 142 | o 3:67e3892e3534 add normal3, modify sub/*
143 143 | |
144 144 o | 2:c96c8beb5d56 rename sub/ to stuff/
145 145 |/
146 146 o 1:020c65d24e11 add sub/*
147 147 |
148 148 o 0:117b8328f97a add large, normal1
149 149
150 150 $ cd ..
151 151
152 152 lfconvert with rename, merge, and remove
153 153 $ rm -rf largefiles-repo
154 154 $ hg lfconvert --size 0.2 bigfile-repo largefiles-repo
155 155 initializing destination largefiles-repo
156 156 $ cd largefiles-repo
157 157 $ hg glog --template "{rev}:{node|short} {desc|firstline}\n"
158 158 o 5:8e05f5f2b77e merge
159 159 |\
160 160 | o 4:a5a02de7a8e4 remove large, normal3
161 161 | |
162 162 | o 3:55759520c76f add normal3, modify sub/*
163 163 | |
164 164 o | 2:261ad3f3f037 rename sub/ to stuff/
165 165 |/
166 166 o 1:334e5237836d add sub/*
167 167 |
168 168 o 0:d4892ec57ce2 add large, normal1
169 169
170 170 $ hg locate -r 2
171 171 .hglf/large
172 172 .hglf/stuff/maybelarge.dat
173 173 normal1
174 174 stuff/normal2
175 175 $ hg locate -r 3
176 176 .hglf/large
177 177 .hglf/sub/maybelarge.dat
178 178 normal1
179 179 normal3
180 180 sub/normal2
181 181 $ hg locate -r 4
182 182 .hglf/sub/maybelarge.dat
183 183 normal1
184 184 sub/normal2
185 185 $ hg locate -r 5
186 186 .hglf/stuff/maybelarge.dat
187 187 normal1
188 188 stuff/normal2
189 189 $ hg update
190 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
191 190 getting changed largefiles
192 191 1 largefiles updated, 0 removed
192 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
193 193 $ cat stuff/normal2
194 194 alsonormal
195 195 blah
196 196 $ "$TESTDIR/md5sum.py" stuff/maybelarge.dat
197 197 1dd0b99ff80e19cff409702a1d3f5e15 stuff/maybelarge.dat
198 198 $ cat .hglf/stuff/maybelarge.dat
199 199 76236b6a2c6102826c61af4297dd738fb3b1de38
200 200 $ cd ..
201 201
202 202 "lfconvert" error cases
203 203 $ hg lfconvert http://localhost/foo foo
204 204 abort: http://localhost/foo is not a local Mercurial repo
205 205 [255]
206 206 $ hg lfconvert foo ssh://localhost/foo
207 207 abort: ssh://localhost/foo is not a local Mercurial repo
208 208 [255]
209 209 $ hg lfconvert nosuchrepo foo
210 210 abort: repository nosuchrepo not found!
211 211 [255]
212 212 $ hg share -q -U bigfile-repo shared
213 213 $ printf 'bogus' > shared/.hg/sharedpath
214 214 $ hg lfconvert shared foo
215 215 abort: .hg/sharedpath points to nonexistent directory $TESTTMP/bogus! (glob)
216 216 [255]
217 217 $ hg lfconvert bigfile-repo largefiles-repo
218 218 initializing destination largefiles-repo
219 219 abort: repository largefiles-repo already exists!
220 220 [255]
221 221
222 222 add another largefile to the new largefiles repo
223 223 $ cd largefiles-repo
224 224 $ dd if=/dev/zero bs=1k count=1k > anotherlarge 2> /dev/null
225 225 $ hg add --lfsize=1 anotherlarge
226 226 $ hg commit -m "add anotherlarge (should be a largefile)"
227 227 $ cat .hglf/anotherlarge
228 228 3b71f43ff30f4b15b5cd85dd9e95ebc7e84eb5a3
229 229 $ cd ..
230 230
231 231 round-trip: converting back to a normal (non-largefiles) repo with
232 232 "lfconvert --to-normal" should give the same as ../bigfile-repo
233 233 $ cd largefiles-repo
234 234 $ hg lfconvert --to-normal . ../normal-repo
235 235 initializing destination ../normal-repo
236 236 $ cd ../normal-repo
237 237 $ cat >> .hg/hgrc <<EOF
238 238 > [extensions]
239 239 > largefiles = !
240 240 > EOF
241 241
242 242 # Hmmm: the changeset ID for rev 5 is different from the original
243 243 # normal repo (../bigfile-repo), because the changelog filelist
244 244 # differs between the two incarnations of rev 5: this repo includes
245 245 # 'large' in the list, but ../bigfile-repo does not. Since rev 5
246 246 # removes 'large' relative to the first parent in both repos, it seems
247 247 # to me that lfconvert is doing a *better* job than
248 248 # "hg remove" + "hg merge" + "hg commit".
249 249 # $ hg -R ../bigfile-repo debugdata -c 5
250 250 # $ hg debugdata -c 5
251 251 $ hg glog --template "{rev}:{node|short} {desc|firstline}\n"
252 252 o 6:1635824e6f59 add anotherlarge (should be a largefile)
253 253 |
254 254 o 5:7215f8deeaaf merge
255 255 |\
256 256 | o 4:7285f817b77e remove large, normal3
257 257 | |
258 258 | o 3:67e3892e3534 add normal3, modify sub/*
259 259 | |
260 260 o | 2:c96c8beb5d56 rename sub/ to stuff/
261 261 |/
262 262 o 1:020c65d24e11 add sub/*
263 263 |
264 264 o 0:117b8328f97a add large, normal1
265 265
266 266 $ hg update
267 267 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
268 268 $ hg locate
269 269 anotherlarge
270 270 normal1
271 271 stuff/maybelarge.dat
272 272 stuff/normal2
273 273 $ [ -d .hg/largefiles ] && echo fail || echo pass
274 274 pass
275 275
276 276 $ cd ..
277 277
278 278 Clearing the usercache ensures that commitctx doesn't try to cache largefiles
279 279 from the working dir on a convert.
280 280 $ rm "${USERCACHE}"/*
281 281 $ hg convert largefiles-repo
282 282 assuming destination largefiles-repo-hg
283 283 initializing destination largefiles-repo-hg repository
284 284 scanning source...
285 285 sorting...
286 286 converting...
287 287 6 add large, normal1
288 288 5 add sub/*
289 289 4 rename sub/ to stuff/
290 290 3 add normal3, modify sub/*
291 291 2 remove large, normal3
292 292 1 merge
293 293 0 add anotherlarge (should be a largefile)
294 294
295 295 $ hg -R largefiles-repo-hg glog --template "{rev}:{node|short} {desc|firstline}\n"
296 296 o 6:17126745edfd add anotherlarge (should be a largefile)
297 297 |
298 298 o 5:9cc5aa7204f0 merge
299 299 |\
300 300 | o 4:a5a02de7a8e4 remove large, normal3
301 301 | |
302 302 | o 3:55759520c76f add normal3, modify sub/*
303 303 | |
304 304 o | 2:261ad3f3f037 rename sub/ to stuff/
305 305 |/
306 306 o 1:334e5237836d add sub/*
307 307 |
308 308 o 0:d4892ec57ce2 add large, normal1
309 309
310 310 Verify will fail (for now) if the usercache is purged before converting, since
311 311 largefiles are not cached in the converted repo's local store by the conversion
312 312 process.
313 313 $ hg -R largefiles-repo-hg verify --large --lfa
314 314 checking changesets
315 315 checking manifests
316 316 crosschecking files in changesets and manifests
317 317 checking files
318 318 8 files, 7 changesets, 12 total revisions
319 319 searching 7 changesets for largefiles
320 320 changeset 0:d4892ec57ce2: large missing
321 321 (looked for hash 2e000fa7e85759c7f4c254d4d9c33ef481e459a7)
322 322 changeset 1:334e5237836d: sub/maybelarge.dat missing
323 323 (looked for hash 34e163be8e43c5631d8b92e9c43ab0bf0fa62b9c)
324 324 changeset 2:261ad3f3f037: stuff/maybelarge.dat missing
325 325 (looked for hash 34e163be8e43c5631d8b92e9c43ab0bf0fa62b9c)
326 326 changeset 3:55759520c76f: sub/maybelarge.dat missing
327 327 (looked for hash 76236b6a2c6102826c61af4297dd738fb3b1de38)
328 328 changeset 5:9cc5aa7204f0: stuff/maybelarge.dat missing
329 329 (looked for hash 76236b6a2c6102826c61af4297dd738fb3b1de38)
330 330 changeset 6:17126745edfd: anotherlarge missing
331 331 (looked for hash 3b71f43ff30f4b15b5cd85dd9e95ebc7e84eb5a3)
332 332 verified existence of 6 revisions of 4 largefiles
333 333 [1]
334 334 $ hg -R largefiles-repo-hg showconfig paths
335 335
336 336
337 337 Avoid a traceback if a largefile isn't available (issue3519)
338 338
339 339 Ensure the largefile can be cached in the source if necessary
340 340 $ hg clone -U largefiles-repo issue3519
341 341 $ rm -f "${USERCACHE}"/*
342 342 $ hg lfconvert --to-normal issue3519 normalized3519
343 343 initializing destination normalized3519
344 344
345 345 Ensure the abort message is useful if a largefile is entirely unavailable
346 346 $ rm -rf normalized3519
347 347 $ rm "${USERCACHE}"/*
348 348 $ rm issue3519/.hg/largefiles/*
349 349 $ rm largefiles-repo/.hg/largefiles/*
350 350 $ hg lfconvert --to-normal issue3519 normalized3519
351 351 initializing destination normalized3519
352 352 error getting 2e000fa7e85759c7f4c254d4d9c33ef481e459a7 from file:$TESTTMP/largefiles-repo for large: can't get file locally (glob)
353 353 abort: missing largefile 'large' from revision d4892ec57ce212905215fad1d9018f56b99202ad
354 354 [255]
355 355
356 356
General Comments 0
You need to be logged in to leave comments. Login now