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