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