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