##// END OF EJS Templates
largefiles: avoid redundant "updatelfiles" invocation in "overridetransplant"...
FUJIWARA Katsunori -
r23273:236c978b default
parent child Browse files
Show More
@@ -1,576 +1,585 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 '''largefiles utility code: must not import other modules in this package.'''
10 10
11 11 import os
12 12 import platform
13 13 import shutil
14 14 import stat
15 15 import copy
16 16
17 17 from mercurial import dirstate, httpconnection, match as match_, util, scmutil
18 18 from mercurial.i18n import _
19 19 from mercurial import node
20 20
21 21 shortname = '.hglf'
22 22 shortnameslash = shortname + '/'
23 23 longname = 'largefiles'
24 24
25 25
26 26 # -- Private worker functions ------------------------------------------
27 27
28 28 def getminsize(ui, assumelfiles, opt, default=10):
29 29 lfsize = opt
30 30 if not lfsize and assumelfiles:
31 31 lfsize = ui.config(longname, 'minsize', default=default)
32 32 if lfsize:
33 33 try:
34 34 lfsize = float(lfsize)
35 35 except ValueError:
36 36 raise util.Abort(_('largefiles: size must be number (not %s)\n')
37 37 % lfsize)
38 38 if lfsize is None:
39 39 raise util.Abort(_('minimum size for largefiles must be specified'))
40 40 return lfsize
41 41
42 42 def link(src, dest):
43 43 util.makedirs(os.path.dirname(dest))
44 44 try:
45 45 util.oslink(src, dest)
46 46 except OSError:
47 47 # if hardlinks fail, fallback on atomic copy
48 48 dst = util.atomictempfile(dest)
49 49 for chunk in util.filechunkiter(open(src, 'rb')):
50 50 dst.write(chunk)
51 51 dst.close()
52 52 os.chmod(dest, os.stat(src).st_mode)
53 53
54 54 def usercachepath(ui, hash):
55 55 path = ui.configpath(longname, 'usercache', None)
56 56 if path:
57 57 path = os.path.join(path, hash)
58 58 else:
59 59 if os.name == 'nt':
60 60 appdata = os.getenv('LOCALAPPDATA', os.getenv('APPDATA'))
61 61 if appdata:
62 62 path = os.path.join(appdata, longname, hash)
63 63 elif platform.system() == 'Darwin':
64 64 home = os.getenv('HOME')
65 65 if home:
66 66 path = os.path.join(home, 'Library', 'Caches',
67 67 longname, hash)
68 68 elif os.name == 'posix':
69 69 path = os.getenv('XDG_CACHE_HOME')
70 70 if path:
71 71 path = os.path.join(path, longname, hash)
72 72 else:
73 73 home = os.getenv('HOME')
74 74 if home:
75 75 path = os.path.join(home, '.cache', longname, hash)
76 76 else:
77 77 raise util.Abort(_('unknown operating system: %s\n') % os.name)
78 78 return path
79 79
80 80 def inusercache(ui, hash):
81 81 path = usercachepath(ui, hash)
82 82 return path and os.path.exists(path)
83 83
84 84 def findfile(repo, hash):
85 85 if instore(repo, hash):
86 86 repo.ui.note(_('found %s in store\n') % hash)
87 87 return storepath(repo, hash)
88 88 elif inusercache(repo.ui, hash):
89 89 repo.ui.note(_('found %s in system cache\n') % hash)
90 90 path = storepath(repo, hash)
91 91 link(usercachepath(repo.ui, hash), path)
92 92 return path
93 93 return None
94 94
95 95 class largefilesdirstate(dirstate.dirstate):
96 96 def __getitem__(self, key):
97 97 return super(largefilesdirstate, self).__getitem__(unixpath(key))
98 98 def normal(self, f):
99 99 return super(largefilesdirstate, self).normal(unixpath(f))
100 100 def remove(self, f):
101 101 return super(largefilesdirstate, self).remove(unixpath(f))
102 102 def add(self, f):
103 103 return super(largefilesdirstate, self).add(unixpath(f))
104 104 def drop(self, f):
105 105 return super(largefilesdirstate, self).drop(unixpath(f))
106 106 def forget(self, f):
107 107 return super(largefilesdirstate, self).forget(unixpath(f))
108 108 def normallookup(self, f):
109 109 return super(largefilesdirstate, self).normallookup(unixpath(f))
110 110 def _ignore(self, f):
111 111 return False
112 112
113 113 def openlfdirstate(ui, repo, create=True):
114 114 '''
115 115 Return a dirstate object that tracks largefiles: i.e. its root is
116 116 the repo root, but it is saved in .hg/largefiles/dirstate.
117 117 '''
118 118 lfstoredir = repo.join(longname)
119 119 opener = scmutil.opener(lfstoredir)
120 120 lfdirstate = largefilesdirstate(opener, ui, repo.root,
121 121 repo.dirstate._validate)
122 122
123 123 # If the largefiles dirstate does not exist, populate and create
124 124 # it. This ensures that we create it on the first meaningful
125 125 # largefiles operation in a new clone.
126 126 if create and not os.path.exists(os.path.join(lfstoredir, 'dirstate')):
127 127 matcher = getstandinmatcher(repo)
128 128 standins = repo.dirstate.walk(matcher, [], False, False)
129 129
130 130 if len(standins) > 0:
131 131 util.makedirs(lfstoredir)
132 132
133 133 for standin in standins:
134 134 lfile = splitstandin(standin)
135 135 lfdirstate.normallookup(lfile)
136 136 return lfdirstate
137 137
138 138 def lfdirstatestatus(lfdirstate, repo):
139 139 wctx = repo['.']
140 140 match = match_.always(repo.root, repo.getcwd())
141 141 unsure, s = lfdirstate.status(match, [], False, False, False)
142 142 modified, clean = s.modified, s.clean
143 143 for lfile in unsure:
144 144 try:
145 145 fctx = wctx[standin(lfile)]
146 146 except LookupError:
147 147 fctx = None
148 148 if not fctx or fctx.data().strip() != hashfile(repo.wjoin(lfile)):
149 149 modified.append(lfile)
150 150 else:
151 151 clean.append(lfile)
152 152 lfdirstate.normal(lfile)
153 153 return s
154 154
155 155 def listlfiles(repo, rev=None, matcher=None):
156 156 '''return a list of largefiles in the working copy or the
157 157 specified changeset'''
158 158
159 159 if matcher is None:
160 160 matcher = getstandinmatcher(repo)
161 161
162 162 # ignore unknown files in working directory
163 163 return [splitstandin(f)
164 164 for f in repo[rev].walk(matcher)
165 165 if rev is not None or repo.dirstate[f] != '?']
166 166
167 167 def instore(repo, hash):
168 168 return os.path.exists(storepath(repo, hash))
169 169
170 170 def storepath(repo, hash):
171 171 return repo.join(os.path.join(longname, hash))
172 172
173 173 def copyfromcache(repo, hash, filename):
174 174 '''Copy the specified largefile from the repo or system cache to
175 175 filename in the repository. Return true on success or false if the
176 176 file was not found in either cache (which should not happened:
177 177 this is meant to be called only after ensuring that the needed
178 178 largefile exists in the cache).'''
179 179 path = findfile(repo, hash)
180 180 if path is None:
181 181 return False
182 182 util.makedirs(os.path.dirname(repo.wjoin(filename)))
183 183 # The write may fail before the file is fully written, but we
184 184 # don't use atomic writes in the working copy.
185 185 shutil.copy(path, repo.wjoin(filename))
186 186 return True
187 187
188 188 def copytostore(repo, rev, file, uploaded=False):
189 189 hash = readstandin(repo, file, rev)
190 190 if instore(repo, hash):
191 191 return
192 192 copytostoreabsolute(repo, repo.wjoin(file), hash)
193 193
194 194 def copyalltostore(repo, node):
195 195 '''Copy all largefiles in a given revision to the store'''
196 196
197 197 ctx = repo[node]
198 198 for filename in ctx.files():
199 199 if isstandin(filename) and filename in ctx.manifest():
200 200 realfile = splitstandin(filename)
201 201 copytostore(repo, ctx.node(), realfile)
202 202
203 203
204 204 def copytostoreabsolute(repo, file, hash):
205 205 if inusercache(repo.ui, hash):
206 206 link(usercachepath(repo.ui, hash), storepath(repo, hash))
207 207 elif not getattr(repo, "_isconverting", False):
208 208 util.makedirs(os.path.dirname(storepath(repo, hash)))
209 209 dst = util.atomictempfile(storepath(repo, hash),
210 210 createmode=repo.store.createmode)
211 211 for chunk in util.filechunkiter(open(file, 'rb')):
212 212 dst.write(chunk)
213 213 dst.close()
214 214 linktousercache(repo, hash)
215 215
216 216 def linktousercache(repo, hash):
217 217 path = usercachepath(repo.ui, hash)
218 218 if path:
219 219 link(storepath(repo, hash), path)
220 220
221 221 def getstandinmatcher(repo, pats=[], opts={}):
222 222 '''Return a match object that applies pats to the standin directory'''
223 223 standindir = repo.wjoin(shortname)
224 224 if pats:
225 225 pats = [os.path.join(standindir, pat) for pat in pats]
226 226 else:
227 227 # no patterns: relative to repo root
228 228 pats = [standindir]
229 229 # no warnings about missing files or directories
230 230 match = scmutil.match(repo[None], pats, opts)
231 231 match.bad = lambda f, msg: None
232 232 return match
233 233
234 234 def composestandinmatcher(repo, rmatcher):
235 235 '''Return a matcher that accepts standins corresponding to the
236 236 files accepted by rmatcher. Pass the list of files in the matcher
237 237 as the paths specified by the user.'''
238 238 smatcher = getstandinmatcher(repo, rmatcher.files())
239 239 isstandin = smatcher.matchfn
240 240 def composedmatchfn(f):
241 241 return isstandin(f) and rmatcher.matchfn(splitstandin(f))
242 242 smatcher.matchfn = composedmatchfn
243 243
244 244 return smatcher
245 245
246 246 def standin(filename):
247 247 '''Return the repo-relative path to the standin for the specified big
248 248 file.'''
249 249 # Notes:
250 250 # 1) Some callers want an absolute path, but for instance addlargefiles
251 251 # needs it repo-relative so it can be passed to repo[None].add(). So
252 252 # leave it up to the caller to use repo.wjoin() to get an absolute path.
253 253 # 2) Join with '/' because that's what dirstate always uses, even on
254 254 # Windows. Change existing separator to '/' first in case we are
255 255 # passed filenames from an external source (like the command line).
256 256 return shortnameslash + util.pconvert(filename)
257 257
258 258 def isstandin(filename):
259 259 '''Return true if filename is a big file standin. filename must be
260 260 in Mercurial's internal form (slash-separated).'''
261 261 return filename.startswith(shortnameslash)
262 262
263 263 def splitstandin(filename):
264 264 # Split on / because that's what dirstate always uses, even on Windows.
265 265 # Change local separator to / first just in case we are passed filenames
266 266 # from an external source (like the command line).
267 267 bits = util.pconvert(filename).split('/', 1)
268 268 if len(bits) == 2 and bits[0] == shortname:
269 269 return bits[1]
270 270 else:
271 271 return None
272 272
273 273 def updatestandin(repo, standin):
274 274 file = repo.wjoin(splitstandin(standin))
275 275 if os.path.exists(file):
276 276 hash = hashfile(file)
277 277 executable = getexecutable(file)
278 278 writestandin(repo, standin, hash, executable)
279 279
280 280 def readstandin(repo, filename, node=None):
281 281 '''read hex hash from standin for filename at given node, or working
282 282 directory if no node is given'''
283 283 return repo[node][standin(filename)].data().strip()
284 284
285 285 def writestandin(repo, standin, hash, executable):
286 286 '''write hash to <repo.root>/<standin>'''
287 287 repo.wwrite(standin, hash + '\n', executable and 'x' or '')
288 288
289 289 def copyandhash(instream, outfile):
290 290 '''Read bytes from instream (iterable) and write them to outfile,
291 291 computing the SHA-1 hash of the data along the way. Return the hash.'''
292 292 hasher = util.sha1('')
293 293 for data in instream:
294 294 hasher.update(data)
295 295 outfile.write(data)
296 296 return hasher.hexdigest()
297 297
298 298 def hashrepofile(repo, file):
299 299 return hashfile(repo.wjoin(file))
300 300
301 301 def hashfile(file):
302 302 if not os.path.exists(file):
303 303 return ''
304 304 hasher = util.sha1('')
305 305 fd = open(file, 'rb')
306 306 for data in util.filechunkiter(fd, 128 * 1024):
307 307 hasher.update(data)
308 308 fd.close()
309 309 return hasher.hexdigest()
310 310
311 311 def getexecutable(filename):
312 312 mode = os.stat(filename).st_mode
313 313 return ((mode & stat.S_IXUSR) and
314 314 (mode & stat.S_IXGRP) and
315 315 (mode & stat.S_IXOTH))
316 316
317 317 def urljoin(first, second, *arg):
318 318 def join(left, right):
319 319 if not left.endswith('/'):
320 320 left += '/'
321 321 if right.startswith('/'):
322 322 right = right[1:]
323 323 return left + right
324 324
325 325 url = join(first, second)
326 326 for a in arg:
327 327 url = join(url, a)
328 328 return url
329 329
330 330 def hexsha1(data):
331 331 """hexsha1 returns the hex-encoded sha1 sum of the data in the file-like
332 332 object data"""
333 333 h = util.sha1()
334 334 for chunk in util.filechunkiter(data):
335 335 h.update(chunk)
336 336 return h.hexdigest()
337 337
338 338 def httpsendfile(ui, filename):
339 339 return httpconnection.httpsendfile(ui, filename, 'rb')
340 340
341 341 def unixpath(path):
342 342 '''Return a version of path normalized for use with the lfdirstate.'''
343 343 return util.pconvert(os.path.normpath(path))
344 344
345 345 def islfilesrepo(repo):
346 346 if ('largefiles' in repo.requirements and
347 347 util.any(shortnameslash in f[0] for f in repo.store.datafiles())):
348 348 return True
349 349
350 350 return util.any(openlfdirstate(repo.ui, repo, False))
351 351
352 352 class storeprotonotcapable(Exception):
353 353 def __init__(self, storetypes):
354 354 self.storetypes = storetypes
355 355
356 356 def getstandinsstate(repo):
357 357 standins = []
358 358 matcher = getstandinmatcher(repo)
359 359 for standin in repo.dirstate.walk(matcher, [], False, False):
360 360 lfile = splitstandin(standin)
361 361 try:
362 362 hash = readstandin(repo, lfile)
363 363 except IOError:
364 364 hash = None
365 365 standins.append((lfile, hash))
366 366 return standins
367 367
368 368 def synclfdirstate(repo, lfdirstate, lfile, normallookup):
369 369 lfstandin = standin(lfile)
370 370 if lfstandin in repo.dirstate:
371 371 stat = repo.dirstate._map[lfstandin]
372 372 state, mtime = stat[0], stat[3]
373 373 else:
374 374 state, mtime = '?', -1
375 375 if state == 'n':
376 376 if normallookup or mtime < 0:
377 377 # state 'n' doesn't ensure 'clean' in this case
378 378 lfdirstate.normallookup(lfile)
379 379 else:
380 380 lfdirstate.normal(lfile)
381 381 elif state == 'm':
382 382 lfdirstate.normallookup(lfile)
383 383 elif state == 'r':
384 384 lfdirstate.remove(lfile)
385 385 elif state == 'a':
386 386 lfdirstate.add(lfile)
387 387 elif state == '?':
388 388 lfdirstate.drop(lfile)
389 389
390 390 def markcommitted(orig, ctx, node):
391 391 repo = ctx._repo
392 392
393 393 orig(node)
394 394
395 # ATTENTION: "ctx.files()" may differ from "repo[node].files()"
396 # because files coming from the 2nd parent are omitted in the latter.
397 #
398 # The former should be used to get targets of "synclfdirstate",
399 # because such files:
400 # - are marked as "a" by "patch.patch()" (e.g. via transplant), and
401 # - have to be marked as "n" after commit, but
402 # - aren't listed in "repo[node].files()"
403
395 404 lfdirstate = openlfdirstate(repo.ui, repo)
396 405 for f in ctx.files():
397 406 if isstandin(f):
398 407 lfile = splitstandin(f)
399 408 synclfdirstate(repo, lfdirstate, lfile, False)
400 409 lfdirstate.write()
401 410
402 411 def getlfilestoupdate(oldstandins, newstandins):
403 412 changedstandins = set(oldstandins).symmetric_difference(set(newstandins))
404 413 filelist = []
405 414 for f in changedstandins:
406 415 if f[0] not in filelist:
407 416 filelist.append(f[0])
408 417 return filelist
409 418
410 419 def getlfilestoupload(repo, missing, addfunc):
411 420 for n in missing:
412 421 parents = [p for p in repo.changelog.parents(n) if p != node.nullid]
413 422 ctx = repo[n]
414 423 files = set(ctx.files())
415 424 if len(parents) == 2:
416 425 mc = ctx.manifest()
417 426 mp1 = ctx.parents()[0].manifest()
418 427 mp2 = ctx.parents()[1].manifest()
419 428 for f in mp1:
420 429 if f not in mc:
421 430 files.add(f)
422 431 for f in mp2:
423 432 if f not in mc:
424 433 files.add(f)
425 434 for f in mc:
426 435 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None):
427 436 files.add(f)
428 437 for fn in files:
429 438 if isstandin(fn) and fn in ctx:
430 439 addfunc(fn, ctx[fn].data().strip())
431 440
432 441 def updatestandinsbymatch(repo, match):
433 442 '''Update standins in the working directory according to specified match
434 443
435 444 This returns (possibly modified) ``match`` object to be used for
436 445 subsequent commit process.
437 446 '''
438 447
439 448 ui = repo.ui
440 449
441 450 # Case 0: Automated committing
442 451 #
443 452 # While automated committing (like rebase, transplant
444 453 # and so on), this code path is used to avoid:
445 454 # (1) updating standins, because standins should
446 455 # be already updated at this point
447 456 # (2) aborting when standins are matched by "match",
448 457 # because automated committing may specify them directly
449 458 #
450 459 if getattr(repo, "_istransplanting", False):
451 460 return match
452 461
453 462 # Case 1: user calls commit with no specific files or
454 463 # include/exclude patterns: refresh and commit all files that
455 464 # are "dirty".
456 465 if match is None or match.always():
457 466 # Spend a bit of time here to get a list of files we know
458 467 # are modified so we can compare only against those.
459 468 # It can cost a lot of time (several seconds)
460 469 # otherwise to update all standins if the largefiles are
461 470 # large.
462 471 lfdirstate = openlfdirstate(ui, repo)
463 472 dirtymatch = match_.always(repo.root, repo.getcwd())
464 473 unsure, s = lfdirstate.status(dirtymatch, [], False, False,
465 474 False)
466 475 modifiedfiles = unsure + s.modified + s.added + s.removed
467 476 lfiles = listlfiles(repo)
468 477 # this only loops through largefiles that exist (not
469 478 # removed/renamed)
470 479 for lfile in lfiles:
471 480 if lfile in modifiedfiles:
472 481 if os.path.exists(
473 482 repo.wjoin(standin(lfile))):
474 483 # this handles the case where a rebase is being
475 484 # performed and the working copy is not updated
476 485 # yet.
477 486 if os.path.exists(repo.wjoin(lfile)):
478 487 updatestandin(repo,
479 488 standin(lfile))
480 489
481 490 return match
482 491
483 492 lfiles = listlfiles(repo)
484 493 match._files = repo._subdirlfs(match.files(), lfiles)
485 494
486 495 # Case 2: user calls commit with specified patterns: refresh
487 496 # any matching big files.
488 497 smatcher = composestandinmatcher(repo, match)
489 498 standins = repo.dirstate.walk(smatcher, [], False, False)
490 499
491 500 # No matching big files: get out of the way and pass control to
492 501 # the usual commit() method.
493 502 if not standins:
494 503 return match
495 504
496 505 # Refresh all matching big files. It's possible that the
497 506 # commit will end up failing, in which case the big files will
498 507 # stay refreshed. No harm done: the user modified them and
499 508 # asked to commit them, so sooner or later we're going to
500 509 # refresh the standins. Might as well leave them refreshed.
501 510 lfdirstate = openlfdirstate(ui, repo)
502 511 for fstandin in standins:
503 512 lfile = splitstandin(fstandin)
504 513 if lfdirstate[lfile] != 'r':
505 514 updatestandin(repo, fstandin)
506 515
507 516 # Cook up a new matcher that only matches regular files or
508 517 # standins corresponding to the big files requested by the
509 518 # user. Have to modify _files to prevent commit() from
510 519 # complaining "not tracked" for big files.
511 520 match = copy.copy(match)
512 521 origmatchfn = match.matchfn
513 522
514 523 # Check both the list of largefiles and the list of
515 524 # standins because if a largefile was removed, it
516 525 # won't be in the list of largefiles at this point
517 526 match._files += sorted(standins)
518 527
519 528 actualfiles = []
520 529 for f in match._files:
521 530 fstandin = standin(f)
522 531
523 532 # ignore known largefiles and standins
524 533 if f in lfiles or fstandin in standins:
525 534 continue
526 535
527 536 actualfiles.append(f)
528 537 match._files = actualfiles
529 538
530 539 def matchfn(f):
531 540 if origmatchfn(f):
532 541 return f not in lfiles
533 542 else:
534 543 return f in standins
535 544
536 545 match.matchfn = matchfn
537 546
538 547 return match
539 548
540 549 class automatedcommithook(object):
541 550 '''Statefull hook to update standins at the 1st commit of resuming
542 551
543 552 For efficiency, updating standins in the working directory should
544 553 be avoided while automated committing (like rebase, transplant and
545 554 so on), because they should be updated before committing.
546 555
547 556 But the 1st commit of resuming automated committing (e.g. ``rebase
548 557 --continue``) should update them, because largefiles may be
549 558 modified manually.
550 559 '''
551 560 def __init__(self, resuming):
552 561 self.resuming = resuming
553 562
554 563 def __call__(self, repo, match):
555 564 if self.resuming:
556 565 self.resuming = False # avoids updating at subsequent commits
557 566 return updatestandinsbymatch(repo, match)
558 567 else:
559 568 return match
560 569
561 570 def getstatuswriter(ui, repo, forcibly=None):
562 571 '''Return the function to write largefiles specific status out
563 572
564 573 If ``forcibly`` is ``None``, this returns the last element of
565 574 ``repo._lfupdatereporters`` as "default" writer function.
566 575
567 576 Otherwise, this returns the function to always write out (or
568 577 ignore if ``not forcibly``) status.
569 578 '''
570 579 if forcibly is None:
571 580 return repo._lfstatuswriters[-1]
572 581 else:
573 582 if forcibly:
574 583 return ui.status # forcibly WRITE OUT
575 584 else:
576 585 return lambda *msg, **opts: None # forcibly IGNORE
@@ -1,1302 +1,1297 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, util, cmdutil, scmutil, match as match_, \
15 15 archival, pathutil, revset
16 16 from mercurial.i18n import _
17 17 from mercurial.node import hex
18 18
19 19 import lfutil
20 20 import lfcommands
21 21 import basestore
22 22
23 23 # -- Utility functions: commonly/repeatedly needed functionality ---------------
24 24
25 25 def installnormalfilesmatchfn(manifest):
26 26 '''installmatchfn with a matchfn that ignores all largefiles'''
27 27 def overridematch(ctx, pats=[], opts={}, globbed=False,
28 28 default='relpath'):
29 29 match = oldmatch(ctx, pats, opts, globbed, default)
30 30 m = copy.copy(match)
31 31 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
32 32 manifest)
33 33 m._files = filter(notlfile, m._files)
34 34 m._fmap = set(m._files)
35 35 m._always = False
36 36 origmatchfn = m.matchfn
37 37 m.matchfn = lambda f: notlfile(f) and origmatchfn(f)
38 38 return m
39 39 oldmatch = installmatchfn(overridematch)
40 40
41 41 def installmatchfn(f):
42 42 '''monkey patch the scmutil module with a custom match function.
43 43 Warning: it is monkey patching the _module_ on runtime! Not thread safe!'''
44 44 oldmatch = scmutil.match
45 45 setattr(f, 'oldmatch', oldmatch)
46 46 scmutil.match = f
47 47 return oldmatch
48 48
49 49 def restorematchfn():
50 50 '''restores scmutil.match to what it was before installmatchfn
51 51 was called. no-op if scmutil.match is its original function.
52 52
53 53 Note that n calls to installmatchfn will require n calls to
54 54 restore matchfn to reverse'''
55 55 scmutil.match = getattr(scmutil.match, 'oldmatch')
56 56
57 57 def installmatchandpatsfn(f):
58 58 oldmatchandpats = scmutil.matchandpats
59 59 setattr(f, 'oldmatchandpats', oldmatchandpats)
60 60 scmutil.matchandpats = f
61 61 return oldmatchandpats
62 62
63 63 def restorematchandpatsfn():
64 64 '''restores scmutil.matchandpats to what it was before
65 65 installmatchandpatsfn was called. No-op if scmutil.matchandpats
66 66 is its original function.
67 67
68 68 Note that n calls to installmatchandpatsfn will require n calls
69 69 to restore matchfn to reverse'''
70 70 scmutil.matchandpats = getattr(scmutil.matchandpats, 'oldmatchandpats',
71 71 scmutil.matchandpats)
72 72
73 73 def addlargefiles(ui, repo, *pats, **opts):
74 74 large = opts.pop('large', None)
75 75 lfsize = lfutil.getminsize(
76 76 ui, lfutil.islfilesrepo(repo), opts.pop('lfsize', None))
77 77
78 78 lfmatcher = None
79 79 if lfutil.islfilesrepo(repo):
80 80 lfpats = ui.configlist(lfutil.longname, 'patterns', default=[])
81 81 if lfpats:
82 82 lfmatcher = match_.match(repo.root, '', list(lfpats))
83 83
84 84 lfnames = []
85 85 m = scmutil.match(repo[None], pats, opts)
86 86 m.bad = lambda x, y: None
87 87 wctx = repo[None]
88 88 for f in repo.walk(m):
89 89 exact = m.exact(f)
90 90 lfile = lfutil.standin(f) in wctx
91 91 nfile = f in wctx
92 92 exists = lfile or nfile
93 93
94 94 # Don't warn the user when they attempt to add a normal tracked file.
95 95 # The normal add code will do that for us.
96 96 if exact and exists:
97 97 if lfile:
98 98 ui.warn(_('%s already a largefile\n') % f)
99 99 continue
100 100
101 101 if (exact or not exists) and not lfutil.isstandin(f):
102 102 wfile = repo.wjoin(f)
103 103
104 104 # In case the file was removed previously, but not committed
105 105 # (issue3507)
106 106 if not os.path.exists(wfile):
107 107 continue
108 108
109 109 abovemin = (lfsize and
110 110 os.lstat(wfile).st_size >= lfsize * 1024 * 1024)
111 111 if large or abovemin or (lfmatcher and lfmatcher(f)):
112 112 lfnames.append(f)
113 113 if ui.verbose or not exact:
114 114 ui.status(_('adding %s as a largefile\n') % m.rel(f))
115 115
116 116 bad = []
117 117
118 118 # Need to lock, otherwise there could be a race condition between
119 119 # when standins are created and added to the repo.
120 120 wlock = repo.wlock()
121 121 try:
122 122 if not opts.get('dry_run'):
123 123 standins = []
124 124 lfdirstate = lfutil.openlfdirstate(ui, repo)
125 125 for f in lfnames:
126 126 standinname = lfutil.standin(f)
127 127 lfutil.writestandin(repo, standinname, hash='',
128 128 executable=lfutil.getexecutable(repo.wjoin(f)))
129 129 standins.append(standinname)
130 130 if lfdirstate[f] == 'r':
131 131 lfdirstate.normallookup(f)
132 132 else:
133 133 lfdirstate.add(f)
134 134 lfdirstate.write()
135 135 bad += [lfutil.splitstandin(f)
136 136 for f in repo[None].add(standins)
137 137 if f in m.files()]
138 138 finally:
139 139 wlock.release()
140 140 return bad
141 141
142 142 def removelargefiles(ui, repo, isaddremove, *pats, **opts):
143 143 after = opts.get('after')
144 144 if not pats and not after:
145 145 raise util.Abort(_('no files specified'))
146 146 m = scmutil.match(repo[None], pats, opts)
147 147 try:
148 148 repo.lfstatus = True
149 149 s = repo.status(match=m, clean=True)
150 150 finally:
151 151 repo.lfstatus = False
152 152 manifest = repo[None].manifest()
153 153 modified, added, deleted, clean = [[f for f in list
154 154 if lfutil.standin(f) in manifest]
155 155 for list in (s.modified, s.added,
156 156 s.deleted, s.clean)]
157 157
158 158 def warn(files, msg):
159 159 for f in files:
160 160 ui.warn(msg % m.rel(f))
161 161 return int(len(files) > 0)
162 162
163 163 result = 0
164 164
165 165 if after:
166 166 remove = deleted
167 167 result = warn(modified + added + clean,
168 168 _('not removing %s: file still exists\n'))
169 169 else:
170 170 remove = deleted + clean
171 171 result = warn(modified, _('not removing %s: file is modified (use -f'
172 172 ' to force removal)\n'))
173 173 result = warn(added, _('not removing %s: file has been marked for add'
174 174 ' (use forget to undo)\n')) or result
175 175
176 176 for f in sorted(remove):
177 177 if ui.verbose or not m.exact(f):
178 178 ui.status(_('removing %s\n') % m.rel(f))
179 179
180 180 # Need to lock because standin files are deleted then removed from the
181 181 # repository and we could race in-between.
182 182 wlock = repo.wlock()
183 183 try:
184 184 lfdirstate = lfutil.openlfdirstate(ui, repo)
185 185 for f in remove:
186 186 if not after:
187 187 # If this is being called by addremove, notify the user that we
188 188 # are removing the file.
189 189 if isaddremove:
190 190 ui.status(_('removing %s\n') % f)
191 191 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
192 192 lfdirstate.remove(f)
193 193 lfdirstate.write()
194 194 remove = [lfutil.standin(f) for f in remove]
195 195 # If this is being called by addremove, let the original addremove
196 196 # function handle this.
197 197 if not isaddremove:
198 198 for f in remove:
199 199 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
200 200 repo[None].forget(remove)
201 201 finally:
202 202 wlock.release()
203 203
204 204 return result
205 205
206 206 # For overriding mercurial.hgweb.webcommands so that largefiles will
207 207 # appear at their right place in the manifests.
208 208 def decodepath(orig, path):
209 209 return lfutil.splitstandin(path) or path
210 210
211 211 # -- Wrappers: modify existing commands --------------------------------
212 212
213 213 # Add works by going through the files that the user wanted to add and
214 214 # checking if they should be added as largefiles. Then it makes a new
215 215 # matcher which matches only the normal files and runs the original
216 216 # version of add.
217 217 def overrideadd(orig, ui, repo, *pats, **opts):
218 218 normal = opts.pop('normal')
219 219 if normal:
220 220 if opts.get('large'):
221 221 raise util.Abort(_('--normal cannot be used with --large'))
222 222 return orig(ui, repo, *pats, **opts)
223 223 bad = addlargefiles(ui, repo, *pats, **opts)
224 224 installnormalfilesmatchfn(repo[None].manifest())
225 225 result = orig(ui, repo, *pats, **opts)
226 226 restorematchfn()
227 227
228 228 return (result == 1 or bad) and 1 or 0
229 229
230 230 def overrideremove(orig, ui, repo, *pats, **opts):
231 231 installnormalfilesmatchfn(repo[None].manifest())
232 232 result = orig(ui, repo, *pats, **opts)
233 233 restorematchfn()
234 234 return removelargefiles(ui, repo, False, *pats, **opts) or result
235 235
236 236 def overridestatusfn(orig, repo, rev2, **opts):
237 237 try:
238 238 repo._repo.lfstatus = True
239 239 return orig(repo, rev2, **opts)
240 240 finally:
241 241 repo._repo.lfstatus = False
242 242
243 243 def overridestatus(orig, ui, repo, *pats, **opts):
244 244 try:
245 245 repo.lfstatus = True
246 246 return orig(ui, repo, *pats, **opts)
247 247 finally:
248 248 repo.lfstatus = False
249 249
250 250 def overridedirty(orig, repo, ignoreupdate=False):
251 251 try:
252 252 repo._repo.lfstatus = True
253 253 return orig(repo, ignoreupdate)
254 254 finally:
255 255 repo._repo.lfstatus = False
256 256
257 257 def overridelog(orig, ui, repo, *pats, **opts):
258 258 def overridematchandpats(ctx, pats=[], opts={}, globbed=False,
259 259 default='relpath'):
260 260 """Matcher that merges root directory with .hglf, suitable for log.
261 261 It is still possible to match .hglf directly.
262 262 For any listed files run log on the standin too.
263 263 matchfn tries both the given filename and with .hglf stripped.
264 264 """
265 265 matchandpats = oldmatchandpats(ctx, pats, opts, globbed, default)
266 266 m, p = copy.copy(matchandpats)
267 267
268 268 if m.always():
269 269 # We want to match everything anyway, so there's no benefit trying
270 270 # to add standins.
271 271 return matchandpats
272 272
273 273 pats = set(p)
274 274 # TODO: handling of patterns in both cases below
275 275 if m._cwd:
276 276 if os.path.isabs(m._cwd):
277 277 # TODO: handle largefile magic when invoked from other cwd
278 278 return matchandpats
279 279 back = (m._cwd.count('/') + 1) * '../'
280 280 pats.update(back + lfutil.standin(m._cwd + '/' + f) for f in p)
281 281 else:
282 282 pats.update(lfutil.standin(f) for f in p)
283 283
284 284 for i in range(0, len(m._files)):
285 285 standin = lfutil.standin(m._files[i])
286 286 if standin in repo[ctx.node()]:
287 287 m._files[i] = standin
288 288 elif m._files[i] not in repo[ctx.node()]:
289 289 m._files.append(standin)
290 290 pats.add(standin)
291 291
292 292 m._fmap = set(m._files)
293 293 m._always = False
294 294 origmatchfn = m.matchfn
295 295 def lfmatchfn(f):
296 296 lf = lfutil.splitstandin(f)
297 297 if lf is not None and origmatchfn(lf):
298 298 return True
299 299 r = origmatchfn(f)
300 300 return r
301 301 m.matchfn = lfmatchfn
302 302
303 303 return m, pats
304 304
305 305 # For hg log --patch, the match object is used in two different senses:
306 306 # (1) to determine what revisions should be printed out, and
307 307 # (2) to determine what files to print out diffs for.
308 308 # The magic matchandpats override should be used for case (1) but not for
309 309 # case (2).
310 310 def overridemakelogfilematcher(repo, pats, opts):
311 311 pctx = repo[None]
312 312 match, pats = oldmatchandpats(pctx, pats, opts)
313 313 return lambda rev: match
314 314
315 315 oldmatchandpats = installmatchandpatsfn(overridematchandpats)
316 316 oldmakelogfilematcher = cmdutil._makenofollowlogfilematcher
317 317 setattr(cmdutil, '_makenofollowlogfilematcher', overridemakelogfilematcher)
318 318
319 319 try:
320 320 return orig(ui, repo, *pats, **opts)
321 321 finally:
322 322 restorematchandpatsfn()
323 323 setattr(cmdutil, '_makenofollowlogfilematcher', oldmakelogfilematcher)
324 324
325 325 def overrideverify(orig, ui, repo, *pats, **opts):
326 326 large = opts.pop('large', False)
327 327 all = opts.pop('lfa', False)
328 328 contents = opts.pop('lfc', False)
329 329
330 330 result = orig(ui, repo, *pats, **opts)
331 331 if large or all or contents:
332 332 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
333 333 return result
334 334
335 335 def overridedebugstate(orig, ui, repo, *pats, **opts):
336 336 large = opts.pop('large', False)
337 337 if large:
338 338 class fakerepo(object):
339 339 dirstate = lfutil.openlfdirstate(ui, repo)
340 340 orig(ui, fakerepo, *pats, **opts)
341 341 else:
342 342 orig(ui, repo, *pats, **opts)
343 343
344 344 # Override needs to refresh standins so that update's normal merge
345 345 # will go through properly. Then the other update hook (overriding repo.update)
346 346 # will get the new files. Filemerge is also overridden so that the merge
347 347 # will merge standins correctly.
348 348 def overrideupdate(orig, ui, repo, *pats, **opts):
349 349 # Need to lock between the standins getting updated and their
350 350 # largefiles getting updated
351 351 wlock = repo.wlock()
352 352 try:
353 353 if opts['check']:
354 354 lfdirstate = lfutil.openlfdirstate(ui, repo)
355 355 unsure, s = lfdirstate.status(
356 356 match_.always(repo.root, repo.getcwd()),
357 357 [], False, False, False)
358 358
359 359 mod = len(s.modified) > 0
360 360 for lfile in unsure:
361 361 standin = lfutil.standin(lfile)
362 362 if repo['.'][standin].data().strip() != \
363 363 lfutil.hashfile(repo.wjoin(lfile)):
364 364 mod = True
365 365 else:
366 366 lfdirstate.normal(lfile)
367 367 lfdirstate.write()
368 368 if mod:
369 369 raise util.Abort(_('uncommitted changes'))
370 370 return orig(ui, repo, *pats, **opts)
371 371 finally:
372 372 wlock.release()
373 373
374 374 # Before starting the manifest merge, merge.updates will call
375 375 # _checkunknown to check if there are any files in the merged-in
376 376 # changeset that collide with unknown files in the working copy.
377 377 #
378 378 # The largefiles are seen as unknown, so this prevents us from merging
379 379 # in a file 'foo' if we already have a largefile with the same name.
380 380 #
381 381 # The overridden function filters the unknown files by removing any
382 382 # largefiles. This makes the merge proceed and we can then handle this
383 383 # case further in the overridden manifestmerge function below.
384 384 def overridecheckunknownfile(origfn, repo, wctx, mctx, f):
385 385 if lfutil.standin(repo.dirstate.normalize(f)) in wctx:
386 386 return False
387 387 return origfn(repo, wctx, mctx, f)
388 388
389 389 # The manifest merge handles conflicts on the manifest level. We want
390 390 # to handle changes in largefile-ness of files at this level too.
391 391 #
392 392 # The strategy is to run the original manifestmerge and then process
393 393 # the action list it outputs. There are two cases we need to deal with:
394 394 #
395 395 # 1. Normal file in p1, largefile in p2. Here the largefile is
396 396 # detected via its standin file, which will enter the working copy
397 397 # with a "get" action. It is not "merge" since the standin is all
398 398 # Mercurial is concerned with at this level -- the link to the
399 399 # existing normal file is not relevant here.
400 400 #
401 401 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
402 402 # since the largefile will be present in the working copy and
403 403 # different from the normal file in p2. Mercurial therefore
404 404 # triggers a merge action.
405 405 #
406 406 # In both cases, we prompt the user and emit new actions to either
407 407 # remove the standin (if the normal file was kept) or to remove the
408 408 # normal file and get the standin (if the largefile was kept). The
409 409 # default prompt answer is to use the largefile version since it was
410 410 # presumably changed on purpose.
411 411 #
412 412 # Finally, the merge.applyupdates function will then take care of
413 413 # writing the files into the working copy and lfcommands.updatelfiles
414 414 # will update the largefiles.
415 415 def overridecalculateupdates(origfn, repo, p1, p2, pas, branchmerge, force,
416 416 partial, acceptremote, followcopies):
417 417 overwrite = force and not branchmerge
418 418 actions = origfn(repo, p1, p2, pas, branchmerge, force, partial,
419 419 acceptremote, followcopies)
420 420
421 421 if overwrite:
422 422 return actions
423 423
424 424 removes = set(a[0] for a in actions['r'])
425 425
426 426 newglist = []
427 427 lfmr = [] # LargeFiles: Mark as Removed
428 428 for action in actions['g']:
429 429 f, args, msg = action
430 430 splitstandin = f and lfutil.splitstandin(f)
431 431 if (splitstandin is not None and
432 432 splitstandin in p1 and splitstandin not in removes):
433 433 # Case 1: normal file in the working copy, largefile in
434 434 # the second parent
435 435 lfile = splitstandin
436 436 standin = f
437 437 msg = _('remote turned local normal file %s into a largefile\n'
438 438 'use (l)argefile or keep (n)ormal file?'
439 439 '$$ &Largefile $$ &Normal file') % lfile
440 440 if repo.ui.promptchoice(msg, 0) == 0:
441 441 actions['r'].append((lfile, None, msg))
442 442 newglist.append((standin, (p2.flags(standin),), msg))
443 443 else:
444 444 actions['r'].append((standin, None, msg))
445 445 elif lfutil.standin(f) in p1 and lfutil.standin(f) not in removes:
446 446 # Case 2: largefile in the working copy, normal file in
447 447 # the second parent
448 448 standin = lfutil.standin(f)
449 449 lfile = f
450 450 msg = _('remote turned local largefile %s into a normal file\n'
451 451 'keep (l)argefile or use (n)ormal file?'
452 452 '$$ &Largefile $$ &Normal file') % lfile
453 453 if repo.ui.promptchoice(msg, 0) == 0:
454 454 if branchmerge:
455 455 # largefile can be restored from standin safely
456 456 actions['r'].append((lfile, None, msg))
457 457 else:
458 458 # "lfile" should be marked as "removed" without
459 459 # removal of itself
460 460 lfmr.append((lfile, None, msg))
461 461
462 462 # linear-merge should treat this largefile as 're-added'
463 463 actions['a'].append((standin, None, msg))
464 464 else:
465 465 actions['r'].append((standin, None, msg))
466 466 newglist.append((lfile, (p2.flags(lfile),), msg))
467 467 else:
468 468 newglist.append(action)
469 469
470 470 newglist.sort()
471 471 actions['g'] = newglist
472 472 if lfmr:
473 473 lfmr.sort()
474 474 actions['lfmr'] = lfmr
475 475
476 476 return actions
477 477
478 478 def mergerecordupdates(orig, repo, actions, branchmerge):
479 479 if 'lfmr' in actions:
480 480 # this should be executed before 'orig', to execute 'remove'
481 481 # before all other actions
482 482 for lfile, args, msg in actions['lfmr']:
483 483 repo.dirstate.remove(lfile)
484 484
485 485 return orig(repo, actions, branchmerge)
486 486
487 487
488 488 # Override filemerge to prompt the user about how they wish to merge
489 489 # largefiles. This will handle identical edits without prompting the user.
490 490 def overridefilemerge(origfn, repo, mynode, orig, fcd, fco, fca, labels=None):
491 491 if not lfutil.isstandin(orig):
492 492 return origfn(repo, mynode, orig, fcd, fco, fca, labels=labels)
493 493
494 494 ahash = fca.data().strip().lower()
495 495 dhash = fcd.data().strip().lower()
496 496 ohash = fco.data().strip().lower()
497 497 if (ohash != ahash and
498 498 ohash != dhash and
499 499 (dhash == ahash or
500 500 repo.ui.promptchoice(
501 501 _('largefile %s has a merge conflict\nancestor was %s\n'
502 502 'keep (l)ocal %s or\ntake (o)ther %s?'
503 503 '$$ &Local $$ &Other') %
504 504 (lfutil.splitstandin(orig), ahash, dhash, ohash),
505 505 0) == 1)):
506 506 repo.wwrite(fcd.path(), fco.data(), fco.flags())
507 507 return 0
508 508
509 509 # Copy first changes the matchers to match standins instead of
510 510 # largefiles. Then it overrides util.copyfile in that function it
511 511 # checks if the destination largefile already exists. It also keeps a
512 512 # list of copied files so that the largefiles can be copied and the
513 513 # dirstate updated.
514 514 def overridecopy(orig, ui, repo, pats, opts, rename=False):
515 515 # doesn't remove largefile on rename
516 516 if len(pats) < 2:
517 517 # this isn't legal, let the original function deal with it
518 518 return orig(ui, repo, pats, opts, rename)
519 519
520 520 def makestandin(relpath):
521 521 path = pathutil.canonpath(repo.root, repo.getcwd(), relpath)
522 522 return os.path.join(repo.wjoin(lfutil.standin(path)))
523 523
524 524 fullpats = scmutil.expandpats(pats)
525 525 dest = fullpats[-1]
526 526
527 527 if os.path.isdir(dest):
528 528 if not os.path.isdir(makestandin(dest)):
529 529 os.makedirs(makestandin(dest))
530 530 # This could copy both lfiles and normal files in one command,
531 531 # but we don't want to do that. First replace their matcher to
532 532 # only match normal files and run it, then replace it to just
533 533 # match largefiles and run it again.
534 534 nonormalfiles = False
535 535 nolfiles = False
536 536 installnormalfilesmatchfn(repo[None].manifest())
537 537 try:
538 538 try:
539 539 result = orig(ui, repo, pats, opts, rename)
540 540 except util.Abort, e:
541 541 if str(e) != _('no files to copy'):
542 542 raise e
543 543 else:
544 544 nonormalfiles = True
545 545 result = 0
546 546 finally:
547 547 restorematchfn()
548 548
549 549 # The first rename can cause our current working directory to be removed.
550 550 # In that case there is nothing left to copy/rename so just quit.
551 551 try:
552 552 repo.getcwd()
553 553 except OSError:
554 554 return result
555 555
556 556 try:
557 557 try:
558 558 # When we call orig below it creates the standins but we don't add
559 559 # them to the dir state until later so lock during that time.
560 560 wlock = repo.wlock()
561 561
562 562 manifest = repo[None].manifest()
563 563 def overridematch(ctx, pats=[], opts={}, globbed=False,
564 564 default='relpath'):
565 565 newpats = []
566 566 # The patterns were previously mangled to add the standin
567 567 # directory; we need to remove that now
568 568 for pat in pats:
569 569 if match_.patkind(pat) is None and lfutil.shortname in pat:
570 570 newpats.append(pat.replace(lfutil.shortname, ''))
571 571 else:
572 572 newpats.append(pat)
573 573 match = oldmatch(ctx, newpats, opts, globbed, default)
574 574 m = copy.copy(match)
575 575 lfile = lambda f: lfutil.standin(f) in manifest
576 576 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
577 577 m._fmap = set(m._files)
578 578 origmatchfn = m.matchfn
579 579 m.matchfn = lambda f: (lfutil.isstandin(f) and
580 580 (f in manifest) and
581 581 origmatchfn(lfutil.splitstandin(f)) or
582 582 None)
583 583 return m
584 584 oldmatch = installmatchfn(overridematch)
585 585 listpats = []
586 586 for pat in pats:
587 587 if match_.patkind(pat) is not None:
588 588 listpats.append(pat)
589 589 else:
590 590 listpats.append(makestandin(pat))
591 591
592 592 try:
593 593 origcopyfile = util.copyfile
594 594 copiedfiles = []
595 595 def overridecopyfile(src, dest):
596 596 if (lfutil.shortname in src and
597 597 dest.startswith(repo.wjoin(lfutil.shortname))):
598 598 destlfile = dest.replace(lfutil.shortname, '')
599 599 if not opts['force'] and os.path.exists(destlfile):
600 600 raise IOError('',
601 601 _('destination largefile already exists'))
602 602 copiedfiles.append((src, dest))
603 603 origcopyfile(src, dest)
604 604
605 605 util.copyfile = overridecopyfile
606 606 result += orig(ui, repo, listpats, opts, rename)
607 607 finally:
608 608 util.copyfile = origcopyfile
609 609
610 610 lfdirstate = lfutil.openlfdirstate(ui, repo)
611 611 for (src, dest) in copiedfiles:
612 612 if (lfutil.shortname in src and
613 613 dest.startswith(repo.wjoin(lfutil.shortname))):
614 614 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
615 615 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
616 616 destlfiledir = os.path.dirname(repo.wjoin(destlfile)) or '.'
617 617 if not os.path.isdir(destlfiledir):
618 618 os.makedirs(destlfiledir)
619 619 if rename:
620 620 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
621 621
622 622 # The file is gone, but this deletes any empty parent
623 623 # directories as a side-effect.
624 624 util.unlinkpath(repo.wjoin(srclfile), True)
625 625 lfdirstate.remove(srclfile)
626 626 else:
627 627 util.copyfile(repo.wjoin(srclfile),
628 628 repo.wjoin(destlfile))
629 629
630 630 lfdirstate.add(destlfile)
631 631 lfdirstate.write()
632 632 except util.Abort, e:
633 633 if str(e) != _('no files to copy'):
634 634 raise e
635 635 else:
636 636 nolfiles = True
637 637 finally:
638 638 restorematchfn()
639 639 wlock.release()
640 640
641 641 if nolfiles and nonormalfiles:
642 642 raise util.Abort(_('no files to copy'))
643 643
644 644 return result
645 645
646 646 # When the user calls revert, we have to be careful to not revert any
647 647 # changes to other largefiles accidentally. This means we have to keep
648 648 # track of the largefiles that are being reverted so we only pull down
649 649 # the necessary largefiles.
650 650 #
651 651 # Standins are only updated (to match the hash of largefiles) before
652 652 # commits. Update the standins then run the original revert, changing
653 653 # the matcher to hit standins instead of largefiles. Based on the
654 654 # resulting standins update the largefiles.
655 655 def overriderevert(orig, ui, repo, *pats, **opts):
656 656 # Because we put the standins in a bad state (by updating them)
657 657 # and then return them to a correct state we need to lock to
658 658 # prevent others from changing them in their incorrect state.
659 659 wlock = repo.wlock()
660 660 try:
661 661 lfdirstate = lfutil.openlfdirstate(ui, repo)
662 662 s = lfutil.lfdirstatestatus(lfdirstate, repo)
663 663 lfdirstate.write()
664 664 for lfile in s.modified:
665 665 lfutil.updatestandin(repo, lfutil.standin(lfile))
666 666 for lfile in s.deleted:
667 667 if (os.path.exists(repo.wjoin(lfutil.standin(lfile)))):
668 668 os.unlink(repo.wjoin(lfutil.standin(lfile)))
669 669
670 670 oldstandins = lfutil.getstandinsstate(repo)
671 671
672 672 def overridematch(ctx, pats=[], opts={}, globbed=False,
673 673 default='relpath'):
674 674 match = oldmatch(ctx, pats, opts, globbed, default)
675 675 m = copy.copy(match)
676 676 def tostandin(f):
677 677 if lfutil.standin(f) in ctx:
678 678 return lfutil.standin(f)
679 679 elif lfutil.standin(f) in repo[None]:
680 680 return None
681 681 return f
682 682 m._files = [tostandin(f) for f in m._files]
683 683 m._files = [f for f in m._files if f is not None]
684 684 m._fmap = set(m._files)
685 685 origmatchfn = m.matchfn
686 686 def matchfn(f):
687 687 if lfutil.isstandin(f):
688 688 return (origmatchfn(lfutil.splitstandin(f)) and
689 689 (f in repo[None] or f in ctx))
690 690 return origmatchfn(f)
691 691 m.matchfn = matchfn
692 692 return m
693 693 oldmatch = installmatchfn(overridematch)
694 694 try:
695 695 orig(ui, repo, *pats, **opts)
696 696 finally:
697 697 restorematchfn()
698 698
699 699 newstandins = lfutil.getstandinsstate(repo)
700 700 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
701 701 # lfdirstate should be 'normallookup'-ed for updated files,
702 702 # because reverting doesn't touch dirstate for 'normal' files
703 703 # when target revision is explicitly specified: in such case,
704 704 # 'n' and valid timestamp in dirstate doesn't ensure 'clean'
705 705 # of target (standin) file.
706 706 lfcommands.updatelfiles(ui, repo, filelist, printmessage=False,
707 707 normallookup=True)
708 708
709 709 finally:
710 710 wlock.release()
711 711
712 712 # after pulling changesets, we need to take some extra care to get
713 713 # largefiles updated remotely
714 714 def overridepull(orig, ui, repo, source=None, **opts):
715 715 revsprepull = len(repo)
716 716 if not source:
717 717 source = 'default'
718 718 repo.lfpullsource = source
719 719 result = orig(ui, repo, source, **opts)
720 720 revspostpull = len(repo)
721 721 lfrevs = opts.get('lfrev', [])
722 722 if opts.get('all_largefiles'):
723 723 lfrevs.append('pulled()')
724 724 if lfrevs and revspostpull > revsprepull:
725 725 numcached = 0
726 726 repo.firstpulled = revsprepull # for pulled() revset expression
727 727 try:
728 728 for rev in scmutil.revrange(repo, lfrevs):
729 729 ui.note(_('pulling largefiles for revision %s\n') % rev)
730 730 (cached, missing) = lfcommands.cachelfiles(ui, repo, rev)
731 731 numcached += len(cached)
732 732 finally:
733 733 del repo.firstpulled
734 734 ui.status(_("%d largefiles cached\n") % numcached)
735 735 return result
736 736
737 737 def pulledrevsetsymbol(repo, subset, x):
738 738 """``pulled()``
739 739 Changesets that just has been pulled.
740 740
741 741 Only available with largefiles from pull --lfrev expressions.
742 742
743 743 .. container:: verbose
744 744
745 745 Some examples:
746 746
747 747 - pull largefiles for all new changesets::
748 748
749 749 hg pull -lfrev "pulled()"
750 750
751 751 - pull largefiles for all new branch heads::
752 752
753 753 hg pull -lfrev "head(pulled()) and not closed()"
754 754
755 755 """
756 756
757 757 try:
758 758 firstpulled = repo.firstpulled
759 759 except AttributeError:
760 760 raise util.Abort(_("pulled() only available in --lfrev"))
761 761 return revset.baseset([r for r in subset if r >= firstpulled])
762 762
763 763 def overrideclone(orig, ui, source, dest=None, **opts):
764 764 d = dest
765 765 if d is None:
766 766 d = hg.defaultdest(source)
767 767 if opts.get('all_largefiles') and not hg.islocal(d):
768 768 raise util.Abort(_(
769 769 '--all-largefiles is incompatible with non-local destination %s') %
770 770 d)
771 771
772 772 return orig(ui, source, dest, **opts)
773 773
774 774 def hgclone(orig, ui, opts, *args, **kwargs):
775 775 result = orig(ui, opts, *args, **kwargs)
776 776
777 777 if result is not None:
778 778 sourcerepo, destrepo = result
779 779 repo = destrepo.local()
780 780
781 781 # Caching is implicitly limited to 'rev' option, since the dest repo was
782 782 # truncated at that point. The user may expect a download count with
783 783 # this option, so attempt whether or not this is a largefile repo.
784 784 if opts.get('all_largefiles'):
785 785 success, missing = lfcommands.downloadlfiles(ui, repo, None)
786 786
787 787 if missing != 0:
788 788 return None
789 789
790 790 return result
791 791
792 792 def overriderebase(orig, ui, repo, **opts):
793 793 resuming = opts.get('continue')
794 794 repo._lfcommithooks.append(lfutil.automatedcommithook(resuming))
795 795 repo._lfstatuswriters.append(lambda *msg, **opts: None)
796 796 try:
797 797 return orig(ui, repo, **opts)
798 798 finally:
799 799 repo._lfstatuswriters.pop()
800 800 repo._lfcommithooks.pop()
801 801
802 802 def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None,
803 803 prefix=None, mtime=None, subrepos=None):
804 804 # No need to lock because we are only reading history and
805 805 # largefile caches, neither of which are modified.
806 806 lfcommands.cachelfiles(repo.ui, repo, node)
807 807
808 808 if kind not in archival.archivers:
809 809 raise util.Abort(_("unknown archive type '%s'") % kind)
810 810
811 811 ctx = repo[node]
812 812
813 813 if kind == 'files':
814 814 if prefix:
815 815 raise util.Abort(
816 816 _('cannot give prefix when archiving to files'))
817 817 else:
818 818 prefix = archival.tidyprefix(dest, kind, prefix)
819 819
820 820 def write(name, mode, islink, getdata):
821 821 if matchfn and not matchfn(name):
822 822 return
823 823 data = getdata()
824 824 if decode:
825 825 data = repo.wwritedata(name, data)
826 826 archiver.addfile(prefix + name, mode, islink, data)
827 827
828 828 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
829 829
830 830 if repo.ui.configbool("ui", "archivemeta", True):
831 831 def metadata():
832 832 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
833 833 hex(repo.changelog.node(0)), hex(node), ctx.branch())
834 834
835 835 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
836 836 if repo.tagtype(t) == 'global')
837 837 if not tags:
838 838 repo.ui.pushbuffer()
839 839 opts = {'template': '{latesttag}\n{latesttagdistance}',
840 840 'style': '', 'patch': None, 'git': None}
841 841 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
842 842 ltags, dist = repo.ui.popbuffer().split('\n')
843 843 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
844 844 tags += 'latesttagdistance: %s\n' % dist
845 845
846 846 return base + tags
847 847
848 848 write('.hg_archival.txt', 0644, False, metadata)
849 849
850 850 for f in ctx:
851 851 ff = ctx.flags(f)
852 852 getdata = ctx[f].data
853 853 if lfutil.isstandin(f):
854 854 path = lfutil.findfile(repo, getdata().strip())
855 855 if path is None:
856 856 raise util.Abort(
857 857 _('largefile %s not found in repo store or system cache')
858 858 % lfutil.splitstandin(f))
859 859 f = lfutil.splitstandin(f)
860 860
861 861 def getdatafn():
862 862 fd = None
863 863 try:
864 864 fd = open(path, 'rb')
865 865 return fd.read()
866 866 finally:
867 867 if fd:
868 868 fd.close()
869 869
870 870 getdata = getdatafn
871 871 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
872 872
873 873 if subrepos:
874 874 for subpath in sorted(ctx.substate):
875 875 sub = ctx.sub(subpath)
876 876 submatch = match_.narrowmatcher(subpath, matchfn)
877 877 sub.archive(repo.ui, archiver, prefix, submatch)
878 878
879 879 archiver.done()
880 880
881 881 def hgsubrepoarchive(orig, repo, ui, archiver, prefix, match=None):
882 882 repo._get(repo._state + ('hg',))
883 883 rev = repo._state[1]
884 884 ctx = repo._repo[rev]
885 885
886 886 lfcommands.cachelfiles(ui, repo._repo, ctx.node())
887 887
888 888 def write(name, mode, islink, getdata):
889 889 # At this point, the standin has been replaced with the largefile name,
890 890 # so the normal matcher works here without the lfutil variants.
891 891 if match and not match(f):
892 892 return
893 893 data = getdata()
894 894
895 895 archiver.addfile(prefix + repo._path + '/' + name, mode, islink, data)
896 896
897 897 for f in ctx:
898 898 ff = ctx.flags(f)
899 899 getdata = ctx[f].data
900 900 if lfutil.isstandin(f):
901 901 path = lfutil.findfile(repo._repo, getdata().strip())
902 902 if path is None:
903 903 raise util.Abort(
904 904 _('largefile %s not found in repo store or system cache')
905 905 % lfutil.splitstandin(f))
906 906 f = lfutil.splitstandin(f)
907 907
908 908 def getdatafn():
909 909 fd = None
910 910 try:
911 911 fd = open(os.path.join(prefix, path), 'rb')
912 912 return fd.read()
913 913 finally:
914 914 if fd:
915 915 fd.close()
916 916
917 917 getdata = getdatafn
918 918
919 919 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
920 920
921 921 for subpath in sorted(ctx.substate):
922 922 sub = ctx.sub(subpath)
923 923 submatch = match_.narrowmatcher(subpath, match)
924 924 sub.archive(ui, archiver, os.path.join(prefix, repo._path) + '/',
925 925 submatch)
926 926
927 927 # If a largefile is modified, the change is not reflected in its
928 928 # standin until a commit. cmdutil.bailifchanged() raises an exception
929 929 # if the repo has uncommitted changes. Wrap it to also check if
930 930 # largefiles were changed. This is used by bisect and backout.
931 931 def overridebailifchanged(orig, repo):
932 932 orig(repo)
933 933 repo.lfstatus = True
934 934 s = repo.status()
935 935 repo.lfstatus = False
936 936 if s.modified or s.added or s.removed or s.deleted:
937 937 raise util.Abort(_('uncommitted changes'))
938 938
939 939 # Fetch doesn't use cmdutil.bailifchanged so override it to add the check
940 940 def overridefetch(orig, ui, repo, *pats, **opts):
941 941 repo.lfstatus = True
942 942 s = repo.status()
943 943 repo.lfstatus = False
944 944 if s.modified or s.added or s.removed or s.deleted:
945 945 raise util.Abort(_('uncommitted changes'))
946 946 return orig(ui, repo, *pats, **opts)
947 947
948 948 def overrideforget(orig, ui, repo, *pats, **opts):
949 949 installnormalfilesmatchfn(repo[None].manifest())
950 950 result = orig(ui, repo, *pats, **opts)
951 951 restorematchfn()
952 952 m = scmutil.match(repo[None], pats, opts)
953 953
954 954 try:
955 955 repo.lfstatus = True
956 956 s = repo.status(match=m, clean=True)
957 957 finally:
958 958 repo.lfstatus = False
959 959 forget = sorted(s.modified + s.added + s.deleted + s.clean)
960 960 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
961 961
962 962 for f in forget:
963 963 if lfutil.standin(f) not in repo.dirstate and not \
964 964 os.path.isdir(m.rel(lfutil.standin(f))):
965 965 ui.warn(_('not removing %s: file is already untracked\n')
966 966 % m.rel(f))
967 967 result = 1
968 968
969 969 for f in forget:
970 970 if ui.verbose or not m.exact(f):
971 971 ui.status(_('removing %s\n') % m.rel(f))
972 972
973 973 # Need to lock because standin files are deleted then removed from the
974 974 # repository and we could race in-between.
975 975 wlock = repo.wlock()
976 976 try:
977 977 lfdirstate = lfutil.openlfdirstate(ui, repo)
978 978 for f in forget:
979 979 if lfdirstate[f] == 'a':
980 980 lfdirstate.drop(f)
981 981 else:
982 982 lfdirstate.remove(f)
983 983 lfdirstate.write()
984 984 standins = [lfutil.standin(f) for f in forget]
985 985 for f in standins:
986 986 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
987 987 repo[None].forget(standins)
988 988 finally:
989 989 wlock.release()
990 990
991 991 return result
992 992
993 993 def _getoutgoings(repo, other, missing, addfunc):
994 994 """get pairs of filename and largefile hash in outgoing revisions
995 995 in 'missing'.
996 996
997 997 largefiles already existing on 'other' repository are ignored.
998 998
999 999 'addfunc' is invoked with each unique pairs of filename and
1000 1000 largefile hash value.
1001 1001 """
1002 1002 knowns = set()
1003 1003 lfhashes = set()
1004 1004 def dedup(fn, lfhash):
1005 1005 k = (fn, lfhash)
1006 1006 if k not in knowns:
1007 1007 knowns.add(k)
1008 1008 lfhashes.add(lfhash)
1009 1009 lfutil.getlfilestoupload(repo, missing, dedup)
1010 1010 if lfhashes:
1011 1011 lfexists = basestore._openstore(repo, other).exists(lfhashes)
1012 1012 for fn, lfhash in knowns:
1013 1013 if not lfexists[lfhash]: # lfhash doesn't exist on "other"
1014 1014 addfunc(fn, lfhash)
1015 1015
1016 1016 def outgoinghook(ui, repo, other, opts, missing):
1017 1017 if opts.pop('large', None):
1018 1018 lfhashes = set()
1019 1019 if ui.debugflag:
1020 1020 toupload = {}
1021 1021 def addfunc(fn, lfhash):
1022 1022 if fn not in toupload:
1023 1023 toupload[fn] = []
1024 1024 toupload[fn].append(lfhash)
1025 1025 lfhashes.add(lfhash)
1026 1026 def showhashes(fn):
1027 1027 for lfhash in sorted(toupload[fn]):
1028 1028 ui.debug(' %s\n' % (lfhash))
1029 1029 else:
1030 1030 toupload = set()
1031 1031 def addfunc(fn, lfhash):
1032 1032 toupload.add(fn)
1033 1033 lfhashes.add(lfhash)
1034 1034 def showhashes(fn):
1035 1035 pass
1036 1036 _getoutgoings(repo, other, missing, addfunc)
1037 1037
1038 1038 if not toupload:
1039 1039 ui.status(_('largefiles: no files to upload\n'))
1040 1040 else:
1041 1041 ui.status(_('largefiles to upload (%d entities):\n')
1042 1042 % (len(lfhashes)))
1043 1043 for file in sorted(toupload):
1044 1044 ui.status(lfutil.splitstandin(file) + '\n')
1045 1045 showhashes(file)
1046 1046 ui.status('\n')
1047 1047
1048 1048 def summaryremotehook(ui, repo, opts, changes):
1049 1049 largeopt = opts.get('large', False)
1050 1050 if changes is None:
1051 1051 if largeopt:
1052 1052 return (False, True) # only outgoing check is needed
1053 1053 else:
1054 1054 return (False, False)
1055 1055 elif largeopt:
1056 1056 url, branch, peer, outgoing = changes[1]
1057 1057 if peer is None:
1058 1058 # i18n: column positioning for "hg summary"
1059 1059 ui.status(_('largefiles: (no remote repo)\n'))
1060 1060 return
1061 1061
1062 1062 toupload = set()
1063 1063 lfhashes = set()
1064 1064 def addfunc(fn, lfhash):
1065 1065 toupload.add(fn)
1066 1066 lfhashes.add(lfhash)
1067 1067 _getoutgoings(repo, peer, outgoing.missing, addfunc)
1068 1068
1069 1069 if not toupload:
1070 1070 # i18n: column positioning for "hg summary"
1071 1071 ui.status(_('largefiles: (no files to upload)\n'))
1072 1072 else:
1073 1073 # i18n: column positioning for "hg summary"
1074 1074 ui.status(_('largefiles: %d entities for %d files to upload\n')
1075 1075 % (len(lfhashes), len(toupload)))
1076 1076
1077 1077 def overridesummary(orig, ui, repo, *pats, **opts):
1078 1078 try:
1079 1079 repo.lfstatus = True
1080 1080 orig(ui, repo, *pats, **opts)
1081 1081 finally:
1082 1082 repo.lfstatus = False
1083 1083
1084 1084 def scmutiladdremove(orig, repo, pats=[], opts={}, dry_run=None,
1085 1085 similarity=None):
1086 1086 if not lfutil.islfilesrepo(repo):
1087 1087 return orig(repo, pats, opts, dry_run, similarity)
1088 1088 # Get the list of missing largefiles so we can remove them
1089 1089 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1090 1090 unsure, s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [],
1091 1091 False, False, False)
1092 1092
1093 1093 # Call into the normal remove code, but the removing of the standin, we want
1094 1094 # to have handled by original addremove. Monkey patching here makes sure
1095 1095 # we don't remove the standin in the largefiles code, preventing a very
1096 1096 # confused state later.
1097 1097 if s.deleted:
1098 1098 m = [repo.wjoin(f) for f in s.deleted]
1099 1099 removelargefiles(repo.ui, repo, True, *m, **opts)
1100 1100 # Call into the normal add code, and any files that *should* be added as
1101 1101 # largefiles will be
1102 1102 addlargefiles(repo.ui, repo, *pats, **opts)
1103 1103 # Now that we've handled largefiles, hand off to the original addremove
1104 1104 # function to take care of the rest. Make sure it doesn't do anything with
1105 1105 # largefiles by installing a matcher that will ignore them.
1106 1106 installnormalfilesmatchfn(repo[None].manifest())
1107 1107 result = orig(repo, pats, opts, dry_run, similarity)
1108 1108 restorematchfn()
1109 1109 return result
1110 1110
1111 1111 # Calling purge with --all will cause the largefiles to be deleted.
1112 1112 # Override repo.status to prevent this from happening.
1113 1113 def overridepurge(orig, ui, repo, *dirs, **opts):
1114 1114 # XXX large file status is buggy when used on repo proxy.
1115 1115 # XXX this needs to be investigate.
1116 1116 repo = repo.unfiltered()
1117 1117 oldstatus = repo.status
1118 1118 def overridestatus(node1='.', node2=None, match=None, ignored=False,
1119 1119 clean=False, unknown=False, listsubrepos=False):
1120 1120 r = oldstatus(node1, node2, match, ignored, clean, unknown,
1121 1121 listsubrepos)
1122 1122 lfdirstate = lfutil.openlfdirstate(ui, repo)
1123 1123 unknown = [f for f in r.unknown if lfdirstate[f] == '?']
1124 1124 ignored = [f for f in r.ignored if lfdirstate[f] == '?']
1125 1125 return scmutil.status(r.modified, r.added, r.removed, r.deleted,
1126 1126 unknown, ignored, r.clean)
1127 1127 repo.status = overridestatus
1128 1128 orig(ui, repo, *dirs, **opts)
1129 1129 repo.status = oldstatus
1130 1130 def overriderollback(orig, ui, repo, **opts):
1131 1131 wlock = repo.wlock()
1132 1132 try:
1133 1133 before = repo.dirstate.parents()
1134 1134 orphans = set(f for f in repo.dirstate
1135 1135 if lfutil.isstandin(f) and repo.dirstate[f] != 'r')
1136 1136 result = orig(ui, repo, **opts)
1137 1137 after = repo.dirstate.parents()
1138 1138 if before == after:
1139 1139 return result # no need to restore standins
1140 1140
1141 1141 pctx = repo['.']
1142 1142 for f in repo.dirstate:
1143 1143 if lfutil.isstandin(f):
1144 1144 orphans.discard(f)
1145 1145 if repo.dirstate[f] == 'r':
1146 1146 repo.wvfs.unlinkpath(f, ignoremissing=True)
1147 1147 elif f in pctx:
1148 1148 fctx = pctx[f]
1149 1149 repo.wwrite(f, fctx.data(), fctx.flags())
1150 1150 else:
1151 1151 # content of standin is not so important in 'a',
1152 1152 # 'm' or 'n' (coming from the 2nd parent) cases
1153 1153 lfutil.writestandin(repo, f, '', False)
1154 1154 for standin in orphans:
1155 1155 repo.wvfs.unlinkpath(standin, ignoremissing=True)
1156 1156
1157 1157 lfdirstate = lfutil.openlfdirstate(ui, repo)
1158 1158 orphans = set(lfdirstate)
1159 1159 lfiles = lfutil.listlfiles(repo)
1160 1160 for file in lfiles:
1161 1161 lfutil.synclfdirstate(repo, lfdirstate, file, True)
1162 1162 orphans.discard(file)
1163 1163 for lfile in orphans:
1164 1164 lfdirstate.drop(lfile)
1165 1165 lfdirstate.write()
1166 1166 finally:
1167 1167 wlock.release()
1168 1168 return result
1169 1169
1170 1170 def overridetransplant(orig, ui, repo, *revs, **opts):
1171 1171 try:
1172 oldstandins = lfutil.getstandinsstate(repo)
1173 1172 repo._istransplanting = True
1174 1173 result = orig(ui, repo, *revs, **opts)
1175 newstandins = lfutil.getstandinsstate(repo)
1176 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
1177 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1178 printmessage=True)
1179 1174 finally:
1180 1175 repo._istransplanting = False
1181 1176 return result
1182 1177
1183 1178 def overridecat(orig, ui, repo, file1, *pats, **opts):
1184 1179 ctx = scmutil.revsingle(repo, opts.get('rev'))
1185 1180 err = 1
1186 1181 notbad = set()
1187 1182 m = scmutil.match(ctx, (file1,) + pats, opts)
1188 1183 origmatchfn = m.matchfn
1189 1184 def lfmatchfn(f):
1190 1185 if origmatchfn(f):
1191 1186 return True
1192 1187 lf = lfutil.splitstandin(f)
1193 1188 if lf is None:
1194 1189 return False
1195 1190 notbad.add(lf)
1196 1191 return origmatchfn(lf)
1197 1192 m.matchfn = lfmatchfn
1198 1193 origbadfn = m.bad
1199 1194 def lfbadfn(f, msg):
1200 1195 if not f in notbad:
1201 1196 origbadfn(f, msg)
1202 1197 m.bad = lfbadfn
1203 1198 for f in ctx.walk(m):
1204 1199 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1205 1200 pathname=f)
1206 1201 lf = lfutil.splitstandin(f)
1207 1202 if lf is None or origmatchfn(f):
1208 1203 # duplicating unreachable code from commands.cat
1209 1204 data = ctx[f].data()
1210 1205 if opts.get('decode'):
1211 1206 data = repo.wwritedata(f, data)
1212 1207 fp.write(data)
1213 1208 else:
1214 1209 hash = lfutil.readstandin(repo, lf, ctx.rev())
1215 1210 if not lfutil.inusercache(repo.ui, hash):
1216 1211 store = basestore._openstore(repo)
1217 1212 success, missing = store.get([(lf, hash)])
1218 1213 if len(success) != 1:
1219 1214 raise util.Abort(
1220 1215 _('largefile %s is not in cache and could not be '
1221 1216 'downloaded') % lf)
1222 1217 path = lfutil.usercachepath(repo.ui, hash)
1223 1218 fpin = open(path, "rb")
1224 1219 for chunk in util.filechunkiter(fpin, 128 * 1024):
1225 1220 fp.write(chunk)
1226 1221 fpin.close()
1227 1222 fp.close()
1228 1223 err = 0
1229 1224 return err
1230 1225
1231 1226 def mercurialsinkbefore(orig, sink):
1232 1227 sink.repo._isconverting = True
1233 1228 orig(sink)
1234 1229
1235 1230 def mercurialsinkafter(orig, sink):
1236 1231 sink.repo._isconverting = False
1237 1232 orig(sink)
1238 1233
1239 1234 def mergeupdate(orig, repo, node, branchmerge, force, partial,
1240 1235 *args, **kwargs):
1241 1236 wlock = repo.wlock()
1242 1237 try:
1243 1238 # branch | | |
1244 1239 # merge | force | partial | action
1245 1240 # -------+-------+---------+--------------
1246 1241 # x | x | x | linear-merge
1247 1242 # o | x | x | branch-merge
1248 1243 # x | o | x | overwrite (as clean update)
1249 1244 # o | o | x | force-branch-merge (*1)
1250 1245 # x | x | o | (*)
1251 1246 # o | x | o | (*)
1252 1247 # x | o | o | overwrite (as revert)
1253 1248 # o | o | o | (*)
1254 1249 #
1255 1250 # (*) don't care
1256 1251 # (*1) deprecated, but used internally (e.g: "rebase --collapse")
1257 1252
1258 1253 linearmerge = not branchmerge and not force and not partial
1259 1254
1260 1255 if linearmerge or (branchmerge and force and not partial):
1261 1256 # update standins for linear-merge or force-branch-merge,
1262 1257 # because largefiles in the working directory may be modified
1263 1258 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1264 1259 unsure, s = lfdirstate.status(match_.always(repo.root,
1265 1260 repo.getcwd()),
1266 1261 [], False, False, False)
1267 1262 for lfile in unsure + s.modified + s.added:
1268 1263 lfutil.updatestandin(repo, lfutil.standin(lfile))
1269 1264
1270 1265 if linearmerge:
1271 1266 # Only call updatelfiles on the standins that have changed
1272 1267 # to save time
1273 1268 oldstandins = lfutil.getstandinsstate(repo)
1274 1269
1275 1270 result = orig(repo, node, branchmerge, force, partial, *args, **kwargs)
1276 1271
1277 1272 filelist = None
1278 1273 if linearmerge:
1279 1274 newstandins = lfutil.getstandinsstate(repo)
1280 1275 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
1281 1276
1282 1277 printmessage = None
1283 1278 if getattr(repo, "_istransplanting", False):
1284 1279 # suppress status message while automated committing
1285 1280 printmessage = False
1286 1281 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1287 1282 printmessage=printmessage,
1288 1283 normallookup=partial)
1289 1284
1290 1285 return result
1291 1286 finally:
1292 1287 wlock.release()
1293 1288
1294 1289 def scmutilmarktouched(orig, repo, files, *args, **kwargs):
1295 1290 result = orig(repo, files, *args, **kwargs)
1296 1291
1297 1292 filelist = [lfutil.splitstandin(f) for f in files if lfutil.isstandin(f)]
1298 1293 if filelist:
1299 1294 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1300 1295 printmessage=False, normallookup=True)
1301 1296
1302 1297 return result
@@ -1,1823 +1,1821 b''
1 1 This file used to contains all largefile tests.
2 2 Do not add any new tests in this file as it his already far too long to run.
3 3
4 4 It contains all the testing of the basic concepts of large file in a single block.
5 5
6 6 $ USERCACHE="$TESTTMP/cache"; export USERCACHE
7 7 $ mkdir "${USERCACHE}"
8 8 $ cat >> $HGRCPATH <<EOF
9 9 > [extensions]
10 10 > largefiles=
11 11 > purge=
12 12 > rebase=
13 13 > transplant=
14 14 > [phases]
15 15 > publish=False
16 16 > [largefiles]
17 17 > minsize=2
18 18 > patterns=glob:**.dat
19 19 > usercache=${USERCACHE}
20 20 > [hooks]
21 21 > precommit=sh -c "echo \\"Invoking status precommit hook\\"; hg status"
22 22 > EOF
23 23
24 24 Create the repo with a couple of revisions of both large and normal
25 25 files.
26 26 Test status and dirstate of largefiles and that summary output is correct.
27 27
28 28 $ hg init a
29 29 $ cd a
30 30 $ mkdir sub
31 31 $ echo normal1 > normal1
32 32 $ echo normal2 > sub/normal2
33 33 $ echo large1 > large1
34 34 $ echo large2 > sub/large2
35 35 $ hg add normal1 sub/normal2
36 36 $ hg add --large large1 sub/large2
37 37 $ hg commit -m "add files"
38 38 Invoking status precommit hook
39 39 A large1
40 40 A normal1
41 41 A sub/large2
42 42 A sub/normal2
43 43 $ touch large1 sub/large2
44 44 $ sleep 1
45 45 $ hg st
46 46 $ hg debugstate --nodates
47 47 n 644 41 .hglf/large1
48 48 n 644 41 .hglf/sub/large2
49 49 n 644 8 normal1
50 50 n 644 8 sub/normal2
51 51 $ hg debugstate --large --nodates
52 52 n 644 7 large1
53 53 n 644 7 sub/large2
54 54 $ echo normal11 > normal1
55 55 $ echo normal22 > sub/normal2
56 56 $ echo large11 > large1
57 57 $ echo large22 > sub/large2
58 58 $ hg commit -m "edit files"
59 59 Invoking status precommit hook
60 60 M large1
61 61 M normal1
62 62 M sub/large2
63 63 M sub/normal2
64 64 $ hg sum --large
65 65 parent: 1:ce8896473775 tip
66 66 edit files
67 67 branch: default
68 68 commit: (clean)
69 69 update: (current)
70 70 largefiles: (no remote repo)
71 71
72 72 Commit preserved largefile contents.
73 73
74 74 $ cat normal1
75 75 normal11
76 76 $ cat large1
77 77 large11
78 78 $ cat sub/normal2
79 79 normal22
80 80 $ cat sub/large2
81 81 large22
82 82
83 83 Test status, subdir and unknown files
84 84
85 85 $ echo unknown > sub/unknown
86 86 $ hg st --all
87 87 ? sub/unknown
88 88 C large1
89 89 C normal1
90 90 C sub/large2
91 91 C sub/normal2
92 92 $ hg st --all sub
93 93 ? sub/unknown
94 94 C sub/large2
95 95 C sub/normal2
96 96 $ rm sub/unknown
97 97
98 98 Test messages and exit codes for remove warning cases
99 99
100 100 $ hg remove -A large1
101 101 not removing large1: file still exists
102 102 [1]
103 103 $ echo 'modified' > large1
104 104 $ hg remove large1
105 105 not removing large1: file is modified (use -f to force removal)
106 106 [1]
107 107 $ echo 'new' > normalnew
108 108 $ hg add normalnew
109 109 $ echo 'new' > largenew
110 110 $ hg add --large normalnew
111 111 normalnew already tracked!
112 112 $ hg remove normalnew largenew
113 113 not removing largenew: file is untracked
114 114 not removing normalnew: file has been marked for add (use forget to undo)
115 115 [1]
116 116 $ rm normalnew largenew
117 117 $ hg up -Cq
118 118
119 119 Remove both largefiles and normal files.
120 120
121 121 $ hg remove normal1 large1
122 122 $ hg status large1
123 123 R large1
124 124 $ hg commit -m "remove files"
125 125 Invoking status precommit hook
126 126 R large1
127 127 R normal1
128 128 $ ls
129 129 sub
130 130 $ echo "testlargefile" > large1-test
131 131 $ hg add --large large1-test
132 132 $ hg st
133 133 A large1-test
134 134 $ hg rm large1-test
135 135 not removing large1-test: file has been marked for add (use forget to undo)
136 136 [1]
137 137 $ hg st
138 138 A large1-test
139 139 $ hg forget large1-test
140 140 $ hg st
141 141 ? large1-test
142 142 $ hg remove large1-test
143 143 not removing large1-test: file is untracked
144 144 [1]
145 145 $ hg forget large1-test
146 146 not removing large1-test: file is already untracked
147 147 [1]
148 148 $ rm large1-test
149 149
150 150 Copy both largefiles and normal files (testing that status output is correct).
151 151
152 152 $ hg cp sub/normal2 normal1
153 153 $ hg cp sub/large2 large1
154 154 $ hg commit -m "copy files"
155 155 Invoking status precommit hook
156 156 A large1
157 157 A normal1
158 158 $ cat normal1
159 159 normal22
160 160 $ cat large1
161 161 large22
162 162
163 163 Test moving largefiles and verify that normal files are also unaffected.
164 164
165 165 $ hg mv normal1 normal3
166 166 $ hg mv large1 large3
167 167 $ hg mv sub/normal2 sub/normal4
168 168 $ hg mv sub/large2 sub/large4
169 169 $ hg commit -m "move files"
170 170 Invoking status precommit hook
171 171 A large3
172 172 A normal3
173 173 A sub/large4
174 174 A sub/normal4
175 175 R large1
176 176 R normal1
177 177 R sub/large2
178 178 R sub/normal2
179 179 $ cat normal3
180 180 normal22
181 181 $ cat large3
182 182 large22
183 183 $ cat sub/normal4
184 184 normal22
185 185 $ cat sub/large4
186 186 large22
187 187
188 188
189 189 #if serve
190 190 Test display of largefiles in hgweb
191 191
192 192 $ hg serve -d -p $HGPORT --pid-file ../hg.pid
193 193 $ cat ../hg.pid >> $DAEMON_PIDS
194 194 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/tip/?style=raw'
195 195 200 Script output follows
196 196
197 197
198 198 drwxr-xr-x sub
199 199 -rw-r--r-- 41 large3
200 200 -rw-r--r-- 9 normal3
201 201
202 202
203 203 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/tip/sub/?style=raw'
204 204 200 Script output follows
205 205
206 206
207 207 -rw-r--r-- 41 large4
208 208 -rw-r--r-- 9 normal4
209 209
210 210
211 211 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
212 212 #endif
213 213
214 214 Test archiving the various revisions. These hit corner cases known with
215 215 archiving.
216 216
217 217 $ hg archive -r 0 ../archive0
218 218 $ hg archive -r 1 ../archive1
219 219 $ hg archive -r 2 ../archive2
220 220 $ hg archive -r 3 ../archive3
221 221 $ hg archive -r 4 ../archive4
222 222 $ cd ../archive0
223 223 $ cat normal1
224 224 normal1
225 225 $ cat large1
226 226 large1
227 227 $ cat sub/normal2
228 228 normal2
229 229 $ cat sub/large2
230 230 large2
231 231 $ cd ../archive1
232 232 $ cat normal1
233 233 normal11
234 234 $ cat large1
235 235 large11
236 236 $ cat sub/normal2
237 237 normal22
238 238 $ cat sub/large2
239 239 large22
240 240 $ cd ../archive2
241 241 $ ls
242 242 sub
243 243 $ cat sub/normal2
244 244 normal22
245 245 $ cat sub/large2
246 246 large22
247 247 $ cd ../archive3
248 248 $ cat normal1
249 249 normal22
250 250 $ cat large1
251 251 large22
252 252 $ cat sub/normal2
253 253 normal22
254 254 $ cat sub/large2
255 255 large22
256 256 $ cd ../archive4
257 257 $ cat normal3
258 258 normal22
259 259 $ cat large3
260 260 large22
261 261 $ cat sub/normal4
262 262 normal22
263 263 $ cat sub/large4
264 264 large22
265 265
266 266 Commit corner case: specify files to commit.
267 267
268 268 $ cd ../a
269 269 $ echo normal3 > normal3
270 270 $ echo large3 > large3
271 271 $ echo normal4 > sub/normal4
272 272 $ echo large4 > sub/large4
273 273 $ hg commit normal3 large3 sub/normal4 sub/large4 -m "edit files again"
274 274 Invoking status precommit hook
275 275 M large3
276 276 M normal3
277 277 M sub/large4
278 278 M sub/normal4
279 279 $ cat normal3
280 280 normal3
281 281 $ cat large3
282 282 large3
283 283 $ cat sub/normal4
284 284 normal4
285 285 $ cat sub/large4
286 286 large4
287 287
288 288 One more commit corner case: commit from a subdirectory.
289 289
290 290 $ cd ../a
291 291 $ echo normal33 > normal3
292 292 $ echo large33 > large3
293 293 $ echo normal44 > sub/normal4
294 294 $ echo large44 > sub/large4
295 295 $ cd sub
296 296 $ hg commit -m "edit files yet again"
297 297 Invoking status precommit hook
298 298 M large3
299 299 M normal3
300 300 M sub/large4
301 301 M sub/normal4
302 302 $ cat ../normal3
303 303 normal33
304 304 $ cat ../large3
305 305 large33
306 306 $ cat normal4
307 307 normal44
308 308 $ cat large4
309 309 large44
310 310
311 311 Committing standins is not allowed.
312 312
313 313 $ cd ..
314 314 $ echo large3 > large3
315 315 $ hg commit .hglf/large3 -m "try to commit standin"
316 316 abort: file ".hglf/large3" is a largefile standin
317 317 (commit the largefile itself instead)
318 318 [255]
319 319
320 320 Corner cases for adding largefiles.
321 321
322 322 $ echo large5 > large5
323 323 $ hg add --large large5
324 324 $ hg add --large large5
325 325 large5 already a largefile
326 326 $ mkdir sub2
327 327 $ echo large6 > sub2/large6
328 328 $ echo large7 > sub2/large7
329 329 $ hg add --large sub2
330 330 adding sub2/large6 as a largefile (glob)
331 331 adding sub2/large7 as a largefile (glob)
332 332 $ hg st
333 333 M large3
334 334 A large5
335 335 A sub2/large6
336 336 A sub2/large7
337 337
338 338 Committing directories containing only largefiles.
339 339
340 340 $ mkdir -p z/y/x/m
341 341 $ touch z/y/x/m/large1
342 342 $ touch z/y/x/large2
343 343 $ hg add --large z/y/x/m/large1 z/y/x/large2
344 344 $ hg commit -m "Subdir with directory only containing largefiles" z
345 345 Invoking status precommit hook
346 346 M large3
347 347 A large5
348 348 A sub2/large6
349 349 A sub2/large7
350 350 A z/y/x/large2
351 351 A z/y/x/m/large1
352 352
353 353 (and a bit of log testing)
354 354
355 355 $ hg log -T '{rev}\n' z/y/x/m/large1
356 356 7
357 357 $ hg log -T '{rev}\n' z/y/x/m # with only a largefile
358 358 7
359 359
360 360 $ hg rollback --quiet
361 361 $ touch z/y/x/m/normal
362 362 $ hg add z/y/x/m/normal
363 363 $ hg commit -m "Subdir with mixed contents" z
364 364 Invoking status precommit hook
365 365 M large3
366 366 A large5
367 367 A sub2/large6
368 368 A sub2/large7
369 369 A z/y/x/large2
370 370 A z/y/x/m/large1
371 371 A z/y/x/m/normal
372 372 $ hg st
373 373 M large3
374 374 A large5
375 375 A sub2/large6
376 376 A sub2/large7
377 377 $ hg rollback --quiet
378 378 $ hg revert z/y/x/large2 z/y/x/m/large1
379 379 $ rm z/y/x/large2 z/y/x/m/large1
380 380 $ hg commit -m "Subdir with normal contents" z
381 381 Invoking status precommit hook
382 382 M large3
383 383 A large5
384 384 A sub2/large6
385 385 A sub2/large7
386 386 A z/y/x/m/normal
387 387 $ hg st
388 388 M large3
389 389 A large5
390 390 A sub2/large6
391 391 A sub2/large7
392 392 $ hg rollback --quiet
393 393 $ hg revert --quiet z
394 394 $ hg commit -m "Empty subdir" z
395 395 abort: z: no match under directory!
396 396 [255]
397 397 $ rm -rf z
398 398 $ hg ci -m "standin" .hglf
399 399 abort: file ".hglf" is a largefile standin
400 400 (commit the largefile itself instead)
401 401 [255]
402 402
403 403 Test "hg status" with combination of 'file pattern' and 'directory
404 404 pattern' for largefiles:
405 405
406 406 $ hg status sub2/large6 sub2
407 407 A sub2/large6
408 408 A sub2/large7
409 409
410 410 Config settings (pattern **.dat, minsize 2 MB) are respected.
411 411
412 412 $ echo testdata > test.dat
413 413 $ dd bs=1k count=2k if=/dev/zero of=reallylarge > /dev/null 2> /dev/null
414 414 $ hg add
415 415 adding reallylarge as a largefile
416 416 adding test.dat as a largefile
417 417
418 418 Test that minsize and --lfsize handle float values;
419 419 also tests that --lfsize overrides largefiles.minsize.
420 420 (0.250 MB = 256 kB = 262144 B)
421 421
422 422 $ dd if=/dev/zero of=ratherlarge bs=1024 count=256 > /dev/null 2> /dev/null
423 423 $ dd if=/dev/zero of=medium bs=1024 count=128 > /dev/null 2> /dev/null
424 424 $ hg --config largefiles.minsize=.25 add
425 425 adding ratherlarge as a largefile
426 426 adding medium
427 427 $ hg forget medium
428 428 $ hg --config largefiles.minsize=.25 add --lfsize=.125
429 429 adding medium as a largefile
430 430 $ dd if=/dev/zero of=notlarge bs=1024 count=127 > /dev/null 2> /dev/null
431 431 $ hg --config largefiles.minsize=.25 add --lfsize=.125
432 432 adding notlarge
433 433 $ hg forget notlarge
434 434
435 435 Test forget on largefiles.
436 436
437 437 $ hg forget large3 large5 test.dat reallylarge ratherlarge medium
438 438 $ hg commit -m "add/edit more largefiles"
439 439 Invoking status precommit hook
440 440 A sub2/large6
441 441 A sub2/large7
442 442 R large3
443 443 ? large5
444 444 ? medium
445 445 ? notlarge
446 446 ? ratherlarge
447 447 ? reallylarge
448 448 ? test.dat
449 449 $ hg st
450 450 ? large3
451 451 ? large5
452 452 ? medium
453 453 ? notlarge
454 454 ? ratherlarge
455 455 ? reallylarge
456 456 ? test.dat
457 457
458 458 Purge with largefiles: verify that largefiles are still in the working
459 459 dir after a purge.
460 460
461 461 $ hg purge --all
462 462 $ cat sub/large4
463 463 large44
464 464 $ cat sub2/large6
465 465 large6
466 466 $ cat sub2/large7
467 467 large7
468 468
469 469 Test addremove: verify that files that should be added as largefiles are added as
470 470 such and that already-existing largefiles are not added as normal files by
471 471 accident.
472 472
473 473 $ rm normal3
474 474 $ rm sub/large4
475 475 $ echo "testing addremove with patterns" > testaddremove.dat
476 476 $ echo "normaladdremove" > normaladdremove
477 477 $ hg addremove
478 478 removing sub/large4
479 479 adding testaddremove.dat as a largefile
480 480 removing normal3
481 481 adding normaladdremove
482 482
483 483 Test addremove with -R
484 484
485 485 $ hg up -C
486 486 getting changed largefiles
487 487 1 largefiles updated, 0 removed
488 488 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
489 489 $ rm normal3
490 490 $ rm sub/large4
491 491 $ echo "testing addremove with patterns" > testaddremove.dat
492 492 $ echo "normaladdremove" > normaladdremove
493 493 $ cd ..
494 494 $ hg -R a addremove
495 495 removing sub/large4
496 496 adding a/testaddremove.dat as a largefile (glob)
497 497 removing normal3
498 498 adding normaladdremove
499 499 $ cd a
500 500
501 501 Test 3364
502 502 $ hg clone . ../addrm
503 503 updating to branch default
504 504 getting changed largefiles
505 505 3 largefiles updated, 0 removed
506 506 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
507 507 $ cd ../addrm
508 508 $ cat >> .hg/hgrc <<EOF
509 509 > [hooks]
510 510 > post-commit.stat=sh -c "echo \\"Invoking status postcommit hook\\"; hg status -A"
511 511 > EOF
512 512 $ touch foo
513 513 $ hg add --large foo
514 514 $ hg ci -m "add foo"
515 515 Invoking status precommit hook
516 516 A foo
517 517 Invoking status postcommit hook
518 518 C foo
519 519 C normal3
520 520 C sub/large4
521 521 C sub/normal4
522 522 C sub2/large6
523 523 C sub2/large7
524 524 $ rm foo
525 525 $ hg st
526 526 ! foo
527 527 hmm.. no precommit invoked, but there is a postcommit??
528 528 $ hg ci -m "will not checkin"
529 529 nothing changed
530 530 Invoking status postcommit hook
531 531 ! foo
532 532 C normal3
533 533 C sub/large4
534 534 C sub/normal4
535 535 C sub2/large6
536 536 C sub2/large7
537 537 [1]
538 538 $ hg addremove
539 539 removing foo
540 540 $ hg st
541 541 R foo
542 542 $ hg ci -m "used to say nothing changed"
543 543 Invoking status precommit hook
544 544 R foo
545 545 Invoking status postcommit hook
546 546 C normal3
547 547 C sub/large4
548 548 C sub/normal4
549 549 C sub2/large6
550 550 C sub2/large7
551 551 $ hg st
552 552
553 553 Test 3507 (both normal files and largefiles were a problem)
554 554
555 555 $ touch normal
556 556 $ touch large
557 557 $ hg add normal
558 558 $ hg add --large large
559 559 $ hg ci -m "added"
560 560 Invoking status precommit hook
561 561 A large
562 562 A normal
563 563 Invoking status postcommit hook
564 564 C large
565 565 C normal
566 566 C normal3
567 567 C sub/large4
568 568 C sub/normal4
569 569 C sub2/large6
570 570 C sub2/large7
571 571 $ hg remove normal
572 572 $ hg addremove --traceback
573 573 $ hg ci -m "addremoved normal"
574 574 Invoking status precommit hook
575 575 R normal
576 576 Invoking status postcommit hook
577 577 C large
578 578 C normal3
579 579 C sub/large4
580 580 C sub/normal4
581 581 C sub2/large6
582 582 C sub2/large7
583 583 $ hg up -C '.^'
584 584 getting changed largefiles
585 585 0 largefiles updated, 0 removed
586 586 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
587 587 $ hg remove large
588 588 $ hg addremove --traceback
589 589 $ hg ci -m "removed large"
590 590 Invoking status precommit hook
591 591 R large
592 592 created new head
593 593 Invoking status postcommit hook
594 594 C normal
595 595 C normal3
596 596 C sub/large4
597 597 C sub/normal4
598 598 C sub2/large6
599 599 C sub2/large7
600 600
601 601 Test commit -A (issue3542)
602 602 $ echo large8 > large8
603 603 $ hg add --large large8
604 604 $ hg ci -Am 'this used to add large8 as normal and commit both'
605 605 Invoking status precommit hook
606 606 A large8
607 607 Invoking status postcommit hook
608 608 C large8
609 609 C normal
610 610 C normal3
611 611 C sub/large4
612 612 C sub/normal4
613 613 C sub2/large6
614 614 C sub2/large7
615 615 $ rm large8
616 616 $ hg ci -Am 'this used to not notice the rm'
617 617 removing large8
618 618 Invoking status precommit hook
619 619 R large8
620 620 Invoking status postcommit hook
621 621 C normal
622 622 C normal3
623 623 C sub/large4
624 624 C sub/normal4
625 625 C sub2/large6
626 626 C sub2/large7
627 627
628 628 Test that a standin can't be added as a large file
629 629
630 630 $ touch large
631 631 $ hg add --large large
632 632 $ hg ci -m "add"
633 633 Invoking status precommit hook
634 634 A large
635 635 Invoking status postcommit hook
636 636 C large
637 637 C normal
638 638 C normal3
639 639 C sub/large4
640 640 C sub/normal4
641 641 C sub2/large6
642 642 C sub2/large7
643 643 $ hg remove large
644 644 $ touch large
645 645 $ hg addremove --config largefiles.patterns=**large --traceback
646 646 adding large as a largefile
647 647
648 648 Test that outgoing --large works (with revsets too)
649 649 $ hg outgoing --rev '.^' --large
650 650 comparing with $TESTTMP/a (glob)
651 651 searching for changes
652 652 changeset: 8:c02fd3b77ec4
653 653 user: test
654 654 date: Thu Jan 01 00:00:00 1970 +0000
655 655 summary: add foo
656 656
657 657 changeset: 9:289dd08c9bbb
658 658 user: test
659 659 date: Thu Jan 01 00:00:00 1970 +0000
660 660 summary: used to say nothing changed
661 661
662 662 changeset: 10:34f23ac6ac12
663 663 user: test
664 664 date: Thu Jan 01 00:00:00 1970 +0000
665 665 summary: added
666 666
667 667 changeset: 12:710c1b2f523c
668 668 parent: 10:34f23ac6ac12
669 669 user: test
670 670 date: Thu Jan 01 00:00:00 1970 +0000
671 671 summary: removed large
672 672
673 673 changeset: 13:0a3e75774479
674 674 user: test
675 675 date: Thu Jan 01 00:00:00 1970 +0000
676 676 summary: this used to add large8 as normal and commit both
677 677
678 678 changeset: 14:84f3d378175c
679 679 user: test
680 680 date: Thu Jan 01 00:00:00 1970 +0000
681 681 summary: this used to not notice the rm
682 682
683 683 largefiles to upload (1 entities):
684 684 large8
685 685
686 686 $ cd ../a
687 687
688 688 Clone a largefiles repo.
689 689
690 690 $ hg clone . ../b
691 691 updating to branch default
692 692 getting changed largefiles
693 693 3 largefiles updated, 0 removed
694 694 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
695 695 $ cd ../b
696 696 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
697 697 7:daea875e9014 add/edit more largefiles
698 698 6:4355d653f84f edit files yet again
699 699 5:9d5af5072dbd edit files again
700 700 4:74c02385b94c move files
701 701 3:9e8fbc4bce62 copy files
702 702 2:51a0ae4d5864 remove files
703 703 1:ce8896473775 edit files
704 704 0:30d30fe6a5be add files
705 705 $ cat normal3
706 706 normal33
707 707
708 708 Test graph log
709 709
710 710 $ hg log -G --template '{rev}:{node|short} {desc|firstline}\n'
711 711 @ 7:daea875e9014 add/edit more largefiles
712 712 |
713 713 o 6:4355d653f84f edit files yet again
714 714 |
715 715 o 5:9d5af5072dbd edit files again
716 716 |
717 717 o 4:74c02385b94c move files
718 718 |
719 719 o 3:9e8fbc4bce62 copy files
720 720 |
721 721 o 2:51a0ae4d5864 remove files
722 722 |
723 723 o 1:ce8896473775 edit files
724 724 |
725 725 o 0:30d30fe6a5be add files
726 726
727 727
728 728 Test log with --patch
729 729
730 730 $ hg log --patch -r 6::7
731 731 changeset: 6:4355d653f84f
732 732 user: test
733 733 date: Thu Jan 01 00:00:00 1970 +0000
734 734 summary: edit files yet again
735 735
736 736 diff -r 9d5af5072dbd -r 4355d653f84f .hglf/large3
737 737 --- a/.hglf/large3 Thu Jan 01 00:00:00 1970 +0000
738 738 +++ b/.hglf/large3 Thu Jan 01 00:00:00 1970 +0000
739 739 @@ -1,1 +1,1 @@
740 740 -baaf12afde9d8d67f25dab6dced0d2bf77dba47c
741 741 +7838695e10da2bb75ac1156565f40a2595fa2fa0
742 742 diff -r 9d5af5072dbd -r 4355d653f84f .hglf/sub/large4
743 743 --- a/.hglf/sub/large4 Thu Jan 01 00:00:00 1970 +0000
744 744 +++ b/.hglf/sub/large4 Thu Jan 01 00:00:00 1970 +0000
745 745 @@ -1,1 +1,1 @@
746 746 -aeb2210d19f02886dde00dac279729a48471e2f9
747 747 +971fb41e78fea4f8e0ba5244784239371cb00591
748 748 diff -r 9d5af5072dbd -r 4355d653f84f normal3
749 749 --- a/normal3 Thu Jan 01 00:00:00 1970 +0000
750 750 +++ b/normal3 Thu Jan 01 00:00:00 1970 +0000
751 751 @@ -1,1 +1,1 @@
752 752 -normal3
753 753 +normal33
754 754 diff -r 9d5af5072dbd -r 4355d653f84f sub/normal4
755 755 --- a/sub/normal4 Thu Jan 01 00:00:00 1970 +0000
756 756 +++ b/sub/normal4 Thu Jan 01 00:00:00 1970 +0000
757 757 @@ -1,1 +1,1 @@
758 758 -normal4
759 759 +normal44
760 760
761 761 changeset: 7:daea875e9014
762 762 tag: tip
763 763 user: test
764 764 date: Thu Jan 01 00:00:00 1970 +0000
765 765 summary: add/edit more largefiles
766 766
767 767 diff -r 4355d653f84f -r daea875e9014 .hglf/large3
768 768 --- a/.hglf/large3 Thu Jan 01 00:00:00 1970 +0000
769 769 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
770 770 @@ -1,1 +0,0 @@
771 771 -7838695e10da2bb75ac1156565f40a2595fa2fa0
772 772 diff -r 4355d653f84f -r daea875e9014 .hglf/sub2/large6
773 773 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
774 774 +++ b/.hglf/sub2/large6 Thu Jan 01 00:00:00 1970 +0000
775 775 @@ -0,0 +1,1 @@
776 776 +0d6d75887db61b2c7e6c74b5dd8fc6ad50c0cc30
777 777 diff -r 4355d653f84f -r daea875e9014 .hglf/sub2/large7
778 778 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
779 779 +++ b/.hglf/sub2/large7 Thu Jan 01 00:00:00 1970 +0000
780 780 @@ -0,0 +1,1 @@
781 781 +bb3151689acb10f0c3125c560d5e63df914bc1af
782 782
783 783
784 784 $ hg log --patch -r 6::7 sub/
785 785 changeset: 6:4355d653f84f
786 786 user: test
787 787 date: Thu Jan 01 00:00:00 1970 +0000
788 788 summary: edit files yet again
789 789
790 790 diff -r 9d5af5072dbd -r 4355d653f84f .hglf/sub/large4
791 791 --- a/.hglf/sub/large4 Thu Jan 01 00:00:00 1970 +0000
792 792 +++ b/.hglf/sub/large4 Thu Jan 01 00:00:00 1970 +0000
793 793 @@ -1,1 +1,1 @@
794 794 -aeb2210d19f02886dde00dac279729a48471e2f9
795 795 +971fb41e78fea4f8e0ba5244784239371cb00591
796 796 diff -r 9d5af5072dbd -r 4355d653f84f sub/normal4
797 797 --- a/sub/normal4 Thu Jan 01 00:00:00 1970 +0000
798 798 +++ b/sub/normal4 Thu Jan 01 00:00:00 1970 +0000
799 799 @@ -1,1 +1,1 @@
800 800 -normal4
801 801 +normal44
802 802
803 803
804 804 log with both --follow and --patch
805 805
806 806 $ hg log --follow --patch --limit 2
807 807 changeset: 7:daea875e9014
808 808 tag: tip
809 809 user: test
810 810 date: Thu Jan 01 00:00:00 1970 +0000
811 811 summary: add/edit more largefiles
812 812
813 813 diff -r 4355d653f84f -r daea875e9014 .hglf/large3
814 814 --- a/.hglf/large3 Thu Jan 01 00:00:00 1970 +0000
815 815 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
816 816 @@ -1,1 +0,0 @@
817 817 -7838695e10da2bb75ac1156565f40a2595fa2fa0
818 818 diff -r 4355d653f84f -r daea875e9014 .hglf/sub2/large6
819 819 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
820 820 +++ b/.hglf/sub2/large6 Thu Jan 01 00:00:00 1970 +0000
821 821 @@ -0,0 +1,1 @@
822 822 +0d6d75887db61b2c7e6c74b5dd8fc6ad50c0cc30
823 823 diff -r 4355d653f84f -r daea875e9014 .hglf/sub2/large7
824 824 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
825 825 +++ b/.hglf/sub2/large7 Thu Jan 01 00:00:00 1970 +0000
826 826 @@ -0,0 +1,1 @@
827 827 +bb3151689acb10f0c3125c560d5e63df914bc1af
828 828
829 829 changeset: 6:4355d653f84f
830 830 user: test
831 831 date: Thu Jan 01 00:00:00 1970 +0000
832 832 summary: edit files yet again
833 833
834 834 diff -r 9d5af5072dbd -r 4355d653f84f .hglf/large3
835 835 --- a/.hglf/large3 Thu Jan 01 00:00:00 1970 +0000
836 836 +++ b/.hglf/large3 Thu Jan 01 00:00:00 1970 +0000
837 837 @@ -1,1 +1,1 @@
838 838 -baaf12afde9d8d67f25dab6dced0d2bf77dba47c
839 839 +7838695e10da2bb75ac1156565f40a2595fa2fa0
840 840 diff -r 9d5af5072dbd -r 4355d653f84f .hglf/sub/large4
841 841 --- a/.hglf/sub/large4 Thu Jan 01 00:00:00 1970 +0000
842 842 +++ b/.hglf/sub/large4 Thu Jan 01 00:00:00 1970 +0000
843 843 @@ -1,1 +1,1 @@
844 844 -aeb2210d19f02886dde00dac279729a48471e2f9
845 845 +971fb41e78fea4f8e0ba5244784239371cb00591
846 846 diff -r 9d5af5072dbd -r 4355d653f84f normal3
847 847 --- a/normal3 Thu Jan 01 00:00:00 1970 +0000
848 848 +++ b/normal3 Thu Jan 01 00:00:00 1970 +0000
849 849 @@ -1,1 +1,1 @@
850 850 -normal3
851 851 +normal33
852 852 diff -r 9d5af5072dbd -r 4355d653f84f sub/normal4
853 853 --- a/sub/normal4 Thu Jan 01 00:00:00 1970 +0000
854 854 +++ b/sub/normal4 Thu Jan 01 00:00:00 1970 +0000
855 855 @@ -1,1 +1,1 @@
856 856 -normal4
857 857 +normal44
858 858
859 859 $ hg log --follow --patch sub/large4
860 860 changeset: 6:4355d653f84f
861 861 user: test
862 862 date: Thu Jan 01 00:00:00 1970 +0000
863 863 summary: edit files yet again
864 864
865 865 diff -r 9d5af5072dbd -r 4355d653f84f .hglf/sub/large4
866 866 --- a/.hglf/sub/large4 Thu Jan 01 00:00:00 1970 +0000
867 867 +++ b/.hglf/sub/large4 Thu Jan 01 00:00:00 1970 +0000
868 868 @@ -1,1 +1,1 @@
869 869 -aeb2210d19f02886dde00dac279729a48471e2f9
870 870 +971fb41e78fea4f8e0ba5244784239371cb00591
871 871
872 872 changeset: 5:9d5af5072dbd
873 873 user: test
874 874 date: Thu Jan 01 00:00:00 1970 +0000
875 875 summary: edit files again
876 876
877 877 diff -r 74c02385b94c -r 9d5af5072dbd .hglf/sub/large4
878 878 --- a/.hglf/sub/large4 Thu Jan 01 00:00:00 1970 +0000
879 879 +++ b/.hglf/sub/large4 Thu Jan 01 00:00:00 1970 +0000
880 880 @@ -1,1 +1,1 @@
881 881 -eb7338044dc27f9bc59b8dd5a246b065ead7a9c4
882 882 +aeb2210d19f02886dde00dac279729a48471e2f9
883 883
884 884 changeset: 4:74c02385b94c
885 885 user: test
886 886 date: Thu Jan 01 00:00:00 1970 +0000
887 887 summary: move files
888 888
889 889 diff -r 9e8fbc4bce62 -r 74c02385b94c .hglf/sub/large4
890 890 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
891 891 +++ b/.hglf/sub/large4 Thu Jan 01 00:00:00 1970 +0000
892 892 @@ -0,0 +1,1 @@
893 893 +eb7338044dc27f9bc59b8dd5a246b065ead7a9c4
894 894
895 895 changeset: 1:ce8896473775
896 896 user: test
897 897 date: Thu Jan 01 00:00:00 1970 +0000
898 898 summary: edit files
899 899
900 900 diff -r 30d30fe6a5be -r ce8896473775 .hglf/sub/large2
901 901 --- a/.hglf/sub/large2 Thu Jan 01 00:00:00 1970 +0000
902 902 +++ b/.hglf/sub/large2 Thu Jan 01 00:00:00 1970 +0000
903 903 @@ -1,1 +1,1 @@
904 904 -1deebade43c8c498a3c8daddac0244dc55d1331d
905 905 +eb7338044dc27f9bc59b8dd5a246b065ead7a9c4
906 906
907 907 changeset: 0:30d30fe6a5be
908 908 user: test
909 909 date: Thu Jan 01 00:00:00 1970 +0000
910 910 summary: add files
911 911
912 912 diff -r 000000000000 -r 30d30fe6a5be .hglf/sub/large2
913 913 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
914 914 +++ b/.hglf/sub/large2 Thu Jan 01 00:00:00 1970 +0000
915 915 @@ -0,0 +1,1 @@
916 916 +1deebade43c8c498a3c8daddac0244dc55d1331d
917 917
918 918 $ cat sub/normal4
919 919 normal44
920 920 $ cat sub/large4
921 921 large44
922 922 $ cat sub2/large6
923 923 large6
924 924 $ cat sub2/large7
925 925 large7
926 926 $ hg log -qf sub2/large7
927 927 7:daea875e9014
928 928 $ hg log -Gqf sub2/large7
929 929 @ 7:daea875e9014
930 930 |
931 931 $ cd ..
932 932
933 933 Test log from outside repo
934 934
935 935 $ hg log b/sub -T '{rev}:{node|short} {desc|firstline}\n'
936 936 6:4355d653f84f edit files yet again
937 937 5:9d5af5072dbd edit files again
938 938 4:74c02385b94c move files
939 939 1:ce8896473775 edit files
940 940 0:30d30fe6a5be add files
941 941
942 942 Test clone at revision
943 943
944 944 $ hg clone a -r 3 c
945 945 adding changesets
946 946 adding manifests
947 947 adding file changes
948 948 added 4 changesets with 10 changes to 4 files
949 949 updating to branch default
950 950 getting changed largefiles
951 951 2 largefiles updated, 0 removed
952 952 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
953 953 $ cd c
954 954 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
955 955 3:9e8fbc4bce62 copy files
956 956 2:51a0ae4d5864 remove files
957 957 1:ce8896473775 edit files
958 958 0:30d30fe6a5be add files
959 959 $ cat normal1
960 960 normal22
961 961 $ cat large1
962 962 large22
963 963 $ cat sub/normal2
964 964 normal22
965 965 $ cat sub/large2
966 966 large22
967 967
968 968 Old revisions of a clone have correct largefiles content (this also
969 969 tests update).
970 970
971 971 $ hg update -r 1
972 972 getting changed largefiles
973 973 1 largefiles updated, 0 removed
974 974 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
975 975 $ cat large1
976 976 large11
977 977 $ cat sub/large2
978 978 large22
979 979 $ cd ..
980 980
981 981 Test cloning with --all-largefiles flag
982 982
983 983 $ rm "${USERCACHE}"/*
984 984 $ hg clone --all-largefiles a a-backup
985 985 updating to branch default
986 986 getting changed largefiles
987 987 3 largefiles updated, 0 removed
988 988 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
989 989 8 additional largefiles cached
990 990
991 991 $ rm "${USERCACHE}"/*
992 992 $ hg clone --all-largefiles -u 0 a a-clone0
993 993 updating to branch default
994 994 getting changed largefiles
995 995 2 largefiles updated, 0 removed
996 996 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
997 997 9 additional largefiles cached
998 998 $ hg -R a-clone0 sum
999 999 parent: 0:30d30fe6a5be
1000 1000 add files
1001 1001 branch: default
1002 1002 commit: (clean)
1003 1003 update: 7 new changesets (update)
1004 1004
1005 1005 $ rm "${USERCACHE}"/*
1006 1006 $ hg clone --all-largefiles -u 1 a a-clone1
1007 1007 updating to branch default
1008 1008 getting changed largefiles
1009 1009 2 largefiles updated, 0 removed
1010 1010 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
1011 1011 8 additional largefiles cached
1012 1012 $ hg -R a-clone1 verify --large --lfa --lfc
1013 1013 checking changesets
1014 1014 checking manifests
1015 1015 crosschecking files in changesets and manifests
1016 1016 checking files
1017 1017 10 files, 8 changesets, 24 total revisions
1018 1018 searching 8 changesets for largefiles
1019 1019 verified contents of 13 revisions of 6 largefiles
1020 1020 $ hg -R a-clone1 sum
1021 1021 parent: 1:ce8896473775
1022 1022 edit files
1023 1023 branch: default
1024 1024 commit: (clean)
1025 1025 update: 6 new changesets (update)
1026 1026
1027 1027 $ rm "${USERCACHE}"/*
1028 1028 $ hg clone --all-largefiles -U a a-clone-u
1029 1029 11 additional largefiles cached
1030 1030 $ hg -R a-clone-u sum
1031 1031 parent: -1:000000000000 (no revision checked out)
1032 1032 branch: default
1033 1033 commit: (clean)
1034 1034 update: 8 new changesets (update)
1035 1035
1036 1036 Show computed destination directory:
1037 1037
1038 1038 $ mkdir xyz
1039 1039 $ cd xyz
1040 1040 $ hg clone ../a
1041 1041 destination directory: a
1042 1042 updating to branch default
1043 1043 getting changed largefiles
1044 1044 3 largefiles updated, 0 removed
1045 1045 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1046 1046 $ cd ..
1047 1047
1048 1048 Clone URL without path:
1049 1049
1050 1050 $ hg clone file://
1051 1051 abort: repository / not found!
1052 1052 [255]
1053 1053
1054 1054 Ensure base clone command argument validation
1055 1055
1056 1056 $ hg clone -U -u 0 a a-clone-failure
1057 1057 abort: cannot specify both --noupdate and --updaterev
1058 1058 [255]
1059 1059
1060 1060 $ hg clone --all-largefiles a ssh://localhost/a
1061 1061 abort: --all-largefiles is incompatible with non-local destination ssh://localhost/a
1062 1062 [255]
1063 1063
1064 1064 Test pulling with --all-largefiles flag. Also test that the largefiles are
1065 1065 downloaded from 'default' instead of 'default-push' when no source is specified
1066 1066 (issue3584)
1067 1067
1068 1068 $ rm -Rf a-backup
1069 1069 $ hg clone -r 1 a a-backup
1070 1070 adding changesets
1071 1071 adding manifests
1072 1072 adding file changes
1073 1073 added 2 changesets with 8 changes to 4 files
1074 1074 updating to branch default
1075 1075 getting changed largefiles
1076 1076 2 largefiles updated, 0 removed
1077 1077 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
1078 1078 $ rm "${USERCACHE}"/*
1079 1079 $ cd a-backup
1080 1080 $ hg pull --all-largefiles --config paths.default-push=bogus/path
1081 1081 pulling from $TESTTMP/a (glob)
1082 1082 searching for changes
1083 1083 adding changesets
1084 1084 adding manifests
1085 1085 adding file changes
1086 1086 added 6 changesets with 16 changes to 8 files
1087 1087 (run 'hg update' to get a working copy)
1088 1088 6 largefiles cached
1089 1089
1090 1090 redo pull with --lfrev and check it pulls largefiles for the right revs
1091 1091
1092 1092 $ hg rollback
1093 1093 repository tip rolled back to revision 1 (undo pull)
1094 1094 $ hg pull -v --lfrev 'heads(pulled())+min(pulled())'
1095 1095 pulling from $TESTTMP/a (glob)
1096 1096 searching for changes
1097 1097 all local heads known remotely
1098 1098 6 changesets found
1099 1099 adding changesets
1100 1100 adding manifests
1101 1101 adding file changes
1102 1102 added 6 changesets with 16 changes to 8 files
1103 1103 calling hook changegroup.lfiles: hgext.largefiles.reposetup.checkrequireslfiles
1104 1104 (run 'hg update' to get a working copy)
1105 1105 pulling largefiles for revision 7
1106 1106 found 971fb41e78fea4f8e0ba5244784239371cb00591 in store
1107 1107 found 0d6d75887db61b2c7e6c74b5dd8fc6ad50c0cc30 in store
1108 1108 found bb3151689acb10f0c3125c560d5e63df914bc1af in store
1109 1109 pulling largefiles for revision 2
1110 1110 found eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 in store
1111 1111 0 largefiles cached
1112 1112
1113 1113 lfpull
1114 1114
1115 1115 $ hg lfpull -r : --config largefiles.usercache=usercache-lfpull
1116 1116 2 largefiles cached
1117 1117 $ hg lfpull -v -r 4+2 --config largefiles.usercache=usercache-lfpull
1118 1118 pulling largefiles for revision 4
1119 1119 found eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 in store
1120 1120 found eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 in store
1121 1121 pulling largefiles for revision 2
1122 1122 found eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 in store
1123 1123 0 largefiles cached
1124 1124
1125 1125 $ ls usercache-lfpull/* | sort
1126 1126 usercache-lfpull/1deebade43c8c498a3c8daddac0244dc55d1331d
1127 1127 usercache-lfpull/4669e532d5b2c093a78eca010077e708a071bb64
1128 1128
1129 1129 $ cd ..
1130 1130
1131 1131 Rebasing between two repositories does not revert largefiles to old
1132 1132 revisions (this was a very bad bug that took a lot of work to fix).
1133 1133
1134 1134 $ hg clone a d
1135 1135 updating to branch default
1136 1136 getting changed largefiles
1137 1137 3 largefiles updated, 0 removed
1138 1138 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1139 1139 $ cd b
1140 1140 $ echo large4-modified > sub/large4
1141 1141 $ echo normal3-modified > normal3
1142 1142 $ hg commit -m "modify normal file and largefile in repo b"
1143 1143 Invoking status precommit hook
1144 1144 M normal3
1145 1145 M sub/large4
1146 1146 $ cd ../d
1147 1147 $ echo large6-modified > sub2/large6
1148 1148 $ echo normal4-modified > sub/normal4
1149 1149 $ hg commit -m "modify normal file largefile in repo d"
1150 1150 Invoking status precommit hook
1151 1151 M sub/normal4
1152 1152 M sub2/large6
1153 1153 $ cd ..
1154 1154 $ hg clone d e
1155 1155 updating to branch default
1156 1156 getting changed largefiles
1157 1157 3 largefiles updated, 0 removed
1158 1158 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1159 1159 $ cd d
1160 1160
1161 1161 More rebase testing, but also test that the largefiles are downloaded from
1162 1162 'default-push' when no source is specified (issue3584). (The largefile from the
1163 1163 pulled revision is however not downloaded but found in the local cache.)
1164 1164 Largefiles are fetched for the new pulled revision, not for existing revisions,
1165 1165 rebased or not.
1166 1166
1167 1167 $ [ ! -f .hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928 ]
1168 1168 $ hg pull --rebase --all-largefiles --config paths.default-push=bogus/path --config paths.default=../b
1169 1169 pulling from $TESTTMP/b (glob)
1170 1170 searching for changes
1171 1171 adding changesets
1172 1172 adding manifests
1173 1173 adding file changes
1174 1174 added 1 changesets with 2 changes to 2 files (+1 heads)
1175 1175 0 largefiles cached
1176 1176 Invoking status precommit hook
1177 1177 M sub/normal4
1178 1178 M sub2/large6
1179 1179 saved backup bundle to $TESTTMP/d/.hg/strip-backup/f574fb32bb45-backup.hg (glob)
1180 1180 $ [ -f .hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928 ]
1181 1181 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
1182 1182 9:598410d3eb9a modify normal file largefile in repo d
1183 1183 8:a381d2c8c80e modify normal file and largefile in repo b
1184 1184 7:daea875e9014 add/edit more largefiles
1185 1185 6:4355d653f84f edit files yet again
1186 1186 5:9d5af5072dbd edit files again
1187 1187 4:74c02385b94c move files
1188 1188 3:9e8fbc4bce62 copy files
1189 1189 2:51a0ae4d5864 remove files
1190 1190 1:ce8896473775 edit files
1191 1191 0:30d30fe6a5be add files
1192 1192 $ hg log -G --template '{rev}:{node|short} {desc|firstline}\n'
1193 1193 @ 9:598410d3eb9a modify normal file largefile in repo d
1194 1194 |
1195 1195 o 8:a381d2c8c80e modify normal file and largefile in repo b
1196 1196 |
1197 1197 o 7:daea875e9014 add/edit more largefiles
1198 1198 |
1199 1199 o 6:4355d653f84f edit files yet again
1200 1200 |
1201 1201 o 5:9d5af5072dbd edit files again
1202 1202 |
1203 1203 o 4:74c02385b94c move files
1204 1204 |
1205 1205 o 3:9e8fbc4bce62 copy files
1206 1206 |
1207 1207 o 2:51a0ae4d5864 remove files
1208 1208 |
1209 1209 o 1:ce8896473775 edit files
1210 1210 |
1211 1211 o 0:30d30fe6a5be add files
1212 1212
1213 1213 $ cat normal3
1214 1214 normal3-modified
1215 1215 $ cat sub/normal4
1216 1216 normal4-modified
1217 1217 $ cat sub/large4
1218 1218 large4-modified
1219 1219 $ cat sub2/large6
1220 1220 large6-modified
1221 1221 $ cat sub2/large7
1222 1222 large7
1223 1223 $ cd ../e
1224 1224 $ hg pull ../b
1225 1225 pulling from ../b
1226 1226 searching for changes
1227 1227 adding changesets
1228 1228 adding manifests
1229 1229 adding file changes
1230 1230 added 1 changesets with 2 changes to 2 files (+1 heads)
1231 1231 (run 'hg heads' to see heads, 'hg merge' to merge)
1232 1232 $ hg rebase
1233 1233 Invoking status precommit hook
1234 1234 M sub/normal4
1235 1235 M sub2/large6
1236 1236 saved backup bundle to $TESTTMP/e/.hg/strip-backup/f574fb32bb45-backup.hg (glob)
1237 1237 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
1238 1238 9:598410d3eb9a modify normal file largefile in repo d
1239 1239 8:a381d2c8c80e modify normal file and largefile in repo b
1240 1240 7:daea875e9014 add/edit more largefiles
1241 1241 6:4355d653f84f edit files yet again
1242 1242 5:9d5af5072dbd edit files again
1243 1243 4:74c02385b94c move files
1244 1244 3:9e8fbc4bce62 copy files
1245 1245 2:51a0ae4d5864 remove files
1246 1246 1:ce8896473775 edit files
1247 1247 0:30d30fe6a5be add files
1248 1248 $ cat normal3
1249 1249 normal3-modified
1250 1250 $ cat sub/normal4
1251 1251 normal4-modified
1252 1252 $ cat sub/large4
1253 1253 large4-modified
1254 1254 $ cat sub2/large6
1255 1255 large6-modified
1256 1256 $ cat sub2/large7
1257 1257 large7
1258 1258
1259 1259 Log on largefiles
1260 1260
1261 1261 - same output
1262 1262 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' .hglf/sub/large4
1263 1263 8:a381d2c8c80e modify normal file and largefile in repo b
1264 1264 6:4355d653f84f edit files yet again
1265 1265 5:9d5af5072dbd edit files again
1266 1266 4:74c02385b94c move files
1267 1267 $ hg log -G --template '{rev}:{node|short} {desc|firstline}\n' .hglf/sub/large4
1268 1268 o 8:a381d2c8c80e modify normal file and largefile in repo b
1269 1269 |
1270 1270 o 6:4355d653f84f edit files yet again
1271 1271 |
1272 1272 o 5:9d5af5072dbd edit files again
1273 1273 |
1274 1274 o 4:74c02385b94c move files
1275 1275 |
1276 1276 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' sub/large4
1277 1277 8:a381d2c8c80e modify normal file and largefile in repo b
1278 1278 6:4355d653f84f edit files yet again
1279 1279 5:9d5af5072dbd edit files again
1280 1280 4:74c02385b94c move files
1281 1281 $ hg log -G --template '{rev}:{node|short} {desc|firstline}\n' .hglf/sub/large4
1282 1282 o 8:a381d2c8c80e modify normal file and largefile in repo b
1283 1283 |
1284 1284 o 6:4355d653f84f edit files yet again
1285 1285 |
1286 1286 o 5:9d5af5072dbd edit files again
1287 1287 |
1288 1288 o 4:74c02385b94c move files
1289 1289 |
1290 1290
1291 1291 - .hglf only matches largefiles, without .hglf it matches 9 bco sub/normal
1292 1292 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' .hglf/sub
1293 1293 8:a381d2c8c80e modify normal file and largefile in repo b
1294 1294 6:4355d653f84f edit files yet again
1295 1295 5:9d5af5072dbd edit files again
1296 1296 4:74c02385b94c move files
1297 1297 1:ce8896473775 edit files
1298 1298 0:30d30fe6a5be add files
1299 1299 $ hg log -G --template '{rev}:{node|short} {desc|firstline}\n' .hglf/sub
1300 1300 o 8:a381d2c8c80e modify normal file and largefile in repo b
1301 1301 |
1302 1302 o 6:4355d653f84f edit files yet again
1303 1303 |
1304 1304 o 5:9d5af5072dbd edit files again
1305 1305 |
1306 1306 o 4:74c02385b94c move files
1307 1307 |
1308 1308 o 1:ce8896473775 edit files
1309 1309 |
1310 1310 o 0:30d30fe6a5be add files
1311 1311
1312 1312 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' sub
1313 1313 9:598410d3eb9a modify normal file largefile in repo d
1314 1314 8:a381d2c8c80e modify normal file and largefile in repo b
1315 1315 6:4355d653f84f edit files yet again
1316 1316 5:9d5af5072dbd edit files again
1317 1317 4:74c02385b94c move files
1318 1318 1:ce8896473775 edit files
1319 1319 0:30d30fe6a5be add files
1320 1320 $ hg log -G --template '{rev}:{node|short} {desc|firstline}\n' sub
1321 1321 @ 9:598410d3eb9a modify normal file largefile in repo d
1322 1322 |
1323 1323 o 8:a381d2c8c80e modify normal file and largefile in repo b
1324 1324 |
1325 1325 o 6:4355d653f84f edit files yet again
1326 1326 |
1327 1327 o 5:9d5af5072dbd edit files again
1328 1328 |
1329 1329 o 4:74c02385b94c move files
1330 1330 |
1331 1331 o 1:ce8896473775 edit files
1332 1332 |
1333 1333 o 0:30d30fe6a5be add files
1334 1334
1335 1335 - globbing gives same result
1336 1336 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' 'glob:sub/*'
1337 1337 9:598410d3eb9a modify normal file largefile in repo d
1338 1338 8:a381d2c8c80e modify normal file and largefile in repo b
1339 1339 6:4355d653f84f edit files yet again
1340 1340 5:9d5af5072dbd edit files again
1341 1341 4:74c02385b94c move files
1342 1342 1:ce8896473775 edit files
1343 1343 0:30d30fe6a5be add files
1344 1344 $ hg log -G --template '{rev}:{node|short} {desc|firstline}\n' 'glob:sub/*'
1345 1345 @ 9:598410d3eb9a modify normal file largefile in repo d
1346 1346 |
1347 1347 o 8:a381d2c8c80e modify normal file and largefile in repo b
1348 1348 |
1349 1349 o 6:4355d653f84f edit files yet again
1350 1350 |
1351 1351 o 5:9d5af5072dbd edit files again
1352 1352 |
1353 1353 o 4:74c02385b94c move files
1354 1354 |
1355 1355 o 1:ce8896473775 edit files
1356 1356 |
1357 1357 o 0:30d30fe6a5be add files
1358 1358
1359 1359 Rollback on largefiles.
1360 1360
1361 1361 $ echo large4-modified-again > sub/large4
1362 1362 $ hg commit -m "Modify large4 again"
1363 1363 Invoking status precommit hook
1364 1364 M sub/large4
1365 1365 $ hg rollback
1366 1366 repository tip rolled back to revision 9 (undo commit)
1367 1367 working directory now based on revision 9
1368 1368 $ hg st
1369 1369 M sub/large4
1370 1370 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
1371 1371 9:598410d3eb9a modify normal file largefile in repo d
1372 1372 8:a381d2c8c80e modify normal file and largefile in repo b
1373 1373 7:daea875e9014 add/edit more largefiles
1374 1374 6:4355d653f84f edit files yet again
1375 1375 5:9d5af5072dbd edit files again
1376 1376 4:74c02385b94c move files
1377 1377 3:9e8fbc4bce62 copy files
1378 1378 2:51a0ae4d5864 remove files
1379 1379 1:ce8896473775 edit files
1380 1380 0:30d30fe6a5be add files
1381 1381 $ cat sub/large4
1382 1382 large4-modified-again
1383 1383
1384 1384 "update --check" refuses to update with uncommitted changes.
1385 1385 $ hg update --check 8
1386 1386 abort: uncommitted changes
1387 1387 [255]
1388 1388
1389 1389 "update --clean" leaves correct largefiles in working copy, even when there is
1390 1390 .orig files from revert in .hglf.
1391 1391
1392 1392 $ echo mistake > sub2/large7
1393 1393 $ hg revert sub2/large7
1394 1394 $ cat sub2/large7
1395 1395 large7
1396 1396 $ cat sub2/large7.orig
1397 1397 mistake
1398 1398 $ test ! -f .hglf/sub2/large7.orig
1399 1399
1400 1400 $ hg -q update --clean -r null
1401 1401 $ hg update --clean
1402 1402 getting changed largefiles
1403 1403 3 largefiles updated, 0 removed
1404 1404 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1405 1405 $ cat normal3
1406 1406 normal3-modified
1407 1407 $ cat sub/normal4
1408 1408 normal4-modified
1409 1409 $ cat sub/large4
1410 1410 large4-modified
1411 1411 $ cat sub2/large6
1412 1412 large6-modified
1413 1413 $ cat sub2/large7
1414 1414 large7
1415 1415 $ cat sub2/large7.orig
1416 1416 mistake
1417 1417 $ test ! -f .hglf/sub2/large7.orig
1418 1418
1419 1419 verify that largefile .orig file no longer is overwritten on every update -C:
1420 1420 $ hg update --clean
1421 1421 getting changed largefiles
1422 1422 0 largefiles updated, 0 removed
1423 1423 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1424 1424 $ cat sub2/large7.orig
1425 1425 mistake
1426 1426 $ rm sub2/large7.orig
1427 1427
1428 1428 Now "update check" is happy.
1429 1429 $ hg update --check 8
1430 1430 getting changed largefiles
1431 1431 1 largefiles updated, 0 removed
1432 1432 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1433 1433 $ hg update --check
1434 1434 getting changed largefiles
1435 1435 1 largefiles updated, 0 removed
1436 1436 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1437 1437
1438 1438 Test removing empty largefiles directories on update
1439 1439 $ test -d sub2 && echo "sub2 exists"
1440 1440 sub2 exists
1441 1441 $ hg update -q null
1442 1442 $ test -d sub2 && echo "error: sub2 should not exist anymore"
1443 1443 [1]
1444 1444 $ hg update -q
1445 1445
1446 1446 Test hg remove removes empty largefiles directories
1447 1447 $ test -d sub2 && echo "sub2 exists"
1448 1448 sub2 exists
1449 1449 $ hg remove sub2/*
1450 1450 $ test -d sub2 && echo "error: sub2 should not exist anymore"
1451 1451 [1]
1452 1452 $ hg revert sub2/large6 sub2/large7
1453 1453
1454 1454 "revert" works on largefiles (and normal files too).
1455 1455 $ echo hack3 >> normal3
1456 1456 $ echo hack4 >> sub/normal4
1457 1457 $ echo hack4 >> sub/large4
1458 1458 $ rm sub2/large6
1459 1459 $ hg revert sub2/large6
1460 1460 $ hg rm sub2/large6
1461 1461 $ echo new >> sub2/large8
1462 1462 $ hg add --large sub2/large8
1463 1463 # XXX we don't really want to report that we're reverting the standin;
1464 1464 # that's just an implementation detail. But I don't see an obvious fix. ;-(
1465 1465 $ hg revert sub
1466 1466 reverting .hglf/sub/large4 (glob)
1467 1467 reverting sub/normal4 (glob)
1468 1468 $ hg status
1469 1469 M normal3
1470 1470 A sub2/large8
1471 1471 R sub2/large6
1472 1472 ? sub/large4.orig
1473 1473 ? sub/normal4.orig
1474 1474 $ cat sub/normal4
1475 1475 normal4-modified
1476 1476 $ cat sub/large4
1477 1477 large4-modified
1478 1478 $ hg revert -a --no-backup
1479 1479 undeleting .hglf/sub2/large6 (glob)
1480 1480 forgetting .hglf/sub2/large8 (glob)
1481 1481 reverting normal3
1482 1482 $ hg status
1483 1483 ? sub/large4.orig
1484 1484 ? sub/normal4.orig
1485 1485 ? sub2/large8
1486 1486 $ cat normal3
1487 1487 normal3-modified
1488 1488 $ cat sub2/large6
1489 1489 large6-modified
1490 1490 $ rm sub/*.orig sub2/large8
1491 1491
1492 1492 revert some files to an older revision
1493 1493 $ hg revert --no-backup -r 8 sub2
1494 1494 reverting .hglf/sub2/large6 (glob)
1495 1495 $ cat sub2/large6
1496 1496 large6
1497 1497 $ hg revert --no-backup -C -r '.^' sub2
1498 1498 $ hg revert --no-backup sub2
1499 1499 reverting .hglf/sub2/large6 (glob)
1500 1500 $ hg status
1501 1501
1502 1502 "verify --large" actually verifies largefiles
1503 1503
1504 1504 - Where Do We Come From? What Are We? Where Are We Going?
1505 1505 $ pwd
1506 1506 $TESTTMP/e
1507 1507 $ hg paths
1508 1508 default = $TESTTMP/d (glob)
1509 1509
1510 1510 $ hg verify --large
1511 1511 checking changesets
1512 1512 checking manifests
1513 1513 crosschecking files in changesets and manifests
1514 1514 checking files
1515 1515 10 files, 10 changesets, 28 total revisions
1516 1516 searching 1 changesets for largefiles
1517 1517 verified existence of 3 revisions of 3 largefiles
1518 1518
1519 1519 - introduce missing blob in local store repo and make sure that this is caught:
1520 1520 $ mv $TESTTMP/d/.hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928 .
1521 1521 $ hg verify --large
1522 1522 checking changesets
1523 1523 checking manifests
1524 1524 crosschecking files in changesets and manifests
1525 1525 checking files
1526 1526 10 files, 10 changesets, 28 total revisions
1527 1527 searching 1 changesets for largefiles
1528 1528 changeset 9:598410d3eb9a: sub/large4 references missing $TESTTMP/d/.hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928 (glob)
1529 1529 verified existence of 3 revisions of 3 largefiles
1530 1530 [1]
1531 1531
1532 1532 - introduce corruption and make sure that it is caught when checking content:
1533 1533 $ echo '5 cents' > $TESTTMP/d/.hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928
1534 1534 $ hg verify -q --large --lfc
1535 1535 changeset 9:598410d3eb9a: sub/large4 references corrupted $TESTTMP/d/.hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928 (glob)
1536 1536 [1]
1537 1537
1538 1538 - cleanup
1539 1539 $ mv e166e74c7303192238d60af5a9c4ce9bef0b7928 $TESTTMP/d/.hg/largefiles/
1540 1540
1541 1541 - verifying all revisions will fail because we didn't clone all largefiles to d:
1542 1542 $ echo 'T-shirt' > $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4
1543 1543 $ hg verify -q --lfa --lfc
1544 1544 changeset 0:30d30fe6a5be: large1 references missing $TESTTMP/d/.hg/largefiles/4669e532d5b2c093a78eca010077e708a071bb64 (glob)
1545 1545 changeset 0:30d30fe6a5be: sub/large2 references missing $TESTTMP/d/.hg/largefiles/1deebade43c8c498a3c8daddac0244dc55d1331d (glob)
1546 1546 changeset 1:ce8896473775: large1 references missing $TESTTMP/d/.hg/largefiles/5f78770c0e77ba4287ad6ef3071c9bf9c379742f (glob)
1547 1547 changeset 1:ce8896473775: sub/large2 references corrupted $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 (glob)
1548 1548 changeset 3:9e8fbc4bce62: large1 references corrupted $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 (glob)
1549 1549 changeset 4:74c02385b94c: large3 references corrupted $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 (glob)
1550 1550 changeset 4:74c02385b94c: sub/large4 references corrupted $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 (glob)
1551 1551 changeset 5:9d5af5072dbd: large3 references missing $TESTTMP/d/.hg/largefiles/baaf12afde9d8d67f25dab6dced0d2bf77dba47c (glob)
1552 1552 changeset 5:9d5af5072dbd: sub/large4 references missing $TESTTMP/d/.hg/largefiles/aeb2210d19f02886dde00dac279729a48471e2f9 (glob)
1553 1553 changeset 6:4355d653f84f: large3 references missing $TESTTMP/d/.hg/largefiles/7838695e10da2bb75ac1156565f40a2595fa2fa0 (glob)
1554 1554 [1]
1555 1555
1556 1556 - cleanup
1557 1557 $ rm $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4
1558 1558 $ rm -f .hglf/sub/*.orig
1559 1559
1560 1560 Update to revision with missing largefile - and make sure it really is missing
1561 1561
1562 1562 $ rm ${USERCACHE}/7838695e10da2bb75ac1156565f40a2595fa2fa0
1563 1563 $ hg up -r 6
1564 1564 getting changed largefiles
1565 1565 large3: largefile 7838695e10da2bb75ac1156565f40a2595fa2fa0 not available from file:/*/$TESTTMP/d (glob)
1566 1566 1 largefiles updated, 2 removed
1567 1567 4 files updated, 0 files merged, 2 files removed, 0 files unresolved
1568 1568 $ rm normal3
1569 1569 $ echo >> sub/normal4
1570 1570 $ hg ci -m 'commit with missing files'
1571 1571 Invoking status precommit hook
1572 1572 M sub/normal4
1573 1573 ! large3
1574 1574 ! normal3
1575 1575 created new head
1576 1576 $ hg st
1577 1577 ! large3
1578 1578 ! normal3
1579 1579 $ hg up -r.
1580 1580 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1581 1581 $ hg st
1582 1582 ! large3
1583 1583 ! normal3
1584 1584 $ hg up -Cr.
1585 1585 getting changed largefiles
1586 1586 large3: largefile 7838695e10da2bb75ac1156565f40a2595fa2fa0 not available from file:/*/$TESTTMP/d (glob)
1587 1587 0 largefiles updated, 0 removed
1588 1588 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1589 1589 $ hg st
1590 1590 ! large3
1591 1591 $ hg rollback
1592 1592 repository tip rolled back to revision 9 (undo commit)
1593 1593 working directory now based on revision 6
1594 1594
1595 1595 Merge with revision with missing largefile - and make sure it tries to fetch it.
1596 1596
1597 1597 $ hg up -Cqr null
1598 1598 $ echo f > f
1599 1599 $ hg ci -Am branch
1600 1600 adding f
1601 1601 Invoking status precommit hook
1602 1602 A f
1603 1603 created new head
1604 1604 $ hg merge -r 6
1605 1605 getting changed largefiles
1606 1606 large3: largefile 7838695e10da2bb75ac1156565f40a2595fa2fa0 not available from file:/*/$TESTTMP/d (glob)
1607 1607 1 largefiles updated, 0 removed
1608 1608 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
1609 1609 (branch merge, don't forget to commit)
1610 1610
1611 1611 $ hg rollback -q
1612 1612 $ hg up -Cq
1613 1613
1614 1614 Pulling 0 revisions with --all-largefiles should not fetch for all revisions
1615 1615
1616 1616 $ hg pull --all-largefiles
1617 1617 pulling from $TESTTMP/d (glob)
1618 1618 searching for changes
1619 1619 no changes found
1620 1620
1621 1621 Merging does not revert to old versions of largefiles and also check
1622 1622 that merging after having pulled from a non-default remote works
1623 1623 correctly.
1624 1624
1625 1625 $ cd ..
1626 1626 $ hg clone -r 7 e temp
1627 1627 adding changesets
1628 1628 adding manifests
1629 1629 adding file changes
1630 1630 added 8 changesets with 24 changes to 10 files
1631 1631 updating to branch default
1632 1632 getting changed largefiles
1633 1633 3 largefiles updated, 0 removed
1634 1634 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1635 1635 $ hg clone temp f
1636 1636 updating to branch default
1637 1637 getting changed largefiles
1638 1638 3 largefiles updated, 0 removed
1639 1639 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1640 1640 # Delete the largefiles in the largefiles system cache so that we have an
1641 1641 # opportunity to test that caching after a pull works.
1642 1642 $ rm "${USERCACHE}"/*
1643 1643 $ cd f
1644 1644 $ echo "large4-merge-test" > sub/large4
1645 1645 $ hg commit -m "Modify large4 to test merge"
1646 1646 Invoking status precommit hook
1647 1647 M sub/large4
1648 1648 # Test --cache-largefiles flag
1649 1649 $ hg pull --lfrev 'heads(pulled())' ../e
1650 1650 pulling from ../e
1651 1651 searching for changes
1652 1652 adding changesets
1653 1653 adding manifests
1654 1654 adding file changes
1655 1655 added 2 changesets with 4 changes to 4 files (+1 heads)
1656 1656 (run 'hg heads' to see heads, 'hg merge' to merge)
1657 1657 2 largefiles cached
1658 1658 $ hg merge
1659 1659 largefile sub/large4 has a merge conflict
1660 1660 ancestor was 971fb41e78fea4f8e0ba5244784239371cb00591
1661 1661 keep (l)ocal d846f26643bfa8ec210be40cc93cc6b7ff1128ea or
1662 1662 take (o)ther e166e74c7303192238d60af5a9c4ce9bef0b7928? l
1663 1663 getting changed largefiles
1664 1664 1 largefiles updated, 0 removed
1665 1665 3 files updated, 1 files merged, 0 files removed, 0 files unresolved
1666 1666 (branch merge, don't forget to commit)
1667 1667 $ hg commit -m "Merge repos e and f"
1668 1668 Invoking status precommit hook
1669 1669 M normal3
1670 1670 M sub/normal4
1671 1671 M sub2/large6
1672 1672 $ cat normal3
1673 1673 normal3-modified
1674 1674 $ cat sub/normal4
1675 1675 normal4-modified
1676 1676 $ cat sub/large4
1677 1677 large4-merge-test
1678 1678 $ cat sub2/large6
1679 1679 large6-modified
1680 1680 $ cat sub2/large7
1681 1681 large7
1682 1682
1683 1683 Test status after merging with a branch that introduces a new largefile:
1684 1684
1685 1685 $ echo large > large
1686 1686 $ hg add --large large
1687 1687 $ hg commit -m 'add largefile'
1688 1688 Invoking status precommit hook
1689 1689 A large
1690 1690 $ hg update -q ".^"
1691 1691 $ echo change >> normal3
1692 1692 $ hg commit -m 'some change'
1693 1693 Invoking status precommit hook
1694 1694 M normal3
1695 1695 created new head
1696 1696 $ hg merge
1697 1697 getting changed largefiles
1698 1698 1 largefiles updated, 0 removed
1699 1699 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1700 1700 (branch merge, don't forget to commit)
1701 1701 $ hg status
1702 1702 M large
1703 1703
1704 1704 - make sure update of merge with removed largefiles fails as expected
1705 1705 $ hg rm sub2/large6
1706 1706 $ hg up -r.
1707 1707 abort: outstanding uncommitted merge
1708 1708 [255]
1709 1709
1710 1710 - revert should be able to revert files introduced in a pending merge
1711 1711 $ hg revert --all -r .
1712 1712 removing .hglf/large (glob)
1713 1713 undeleting .hglf/sub2/large6 (glob)
1714 1714
1715 1715 Test that a normal file and a largefile with the same name and path cannot
1716 1716 coexist.
1717 1717
1718 1718 $ rm sub2/large7
1719 1719 $ echo "largeasnormal" > sub2/large7
1720 1720 $ hg add sub2/large7
1721 1721 sub2/large7 already a largefile
1722 1722
1723 1723 Test that transplanting a largefile change works correctly.
1724 1724
1725 1725 $ cd ..
1726 1726 $ hg clone -r 8 d g
1727 1727 adding changesets
1728 1728 adding manifests
1729 1729 adding file changes
1730 1730 added 9 changesets with 26 changes to 10 files
1731 1731 updating to branch default
1732 1732 getting changed largefiles
1733 1733 3 largefiles updated, 0 removed
1734 1734 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1735 1735 $ cd g
1736 1736 $ hg transplant -s ../d 598410d3eb9a
1737 1737 searching for changes
1738 1738 searching for changes
1739 1739 adding changesets
1740 1740 adding manifests
1741 1741 adding file changes
1742 1742 added 1 changesets with 2 changes to 2 files
1743 getting changed largefiles
1744 0 largefiles updated, 0 removed
1745 1743 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
1746 1744 9:598410d3eb9a modify normal file largefile in repo d
1747 1745 8:a381d2c8c80e modify normal file and largefile in repo b
1748 1746 7:daea875e9014 add/edit more largefiles
1749 1747 6:4355d653f84f edit files yet again
1750 1748 5:9d5af5072dbd edit files again
1751 1749 4:74c02385b94c move files
1752 1750 3:9e8fbc4bce62 copy files
1753 1751 2:51a0ae4d5864 remove files
1754 1752 1:ce8896473775 edit files
1755 1753 0:30d30fe6a5be add files
1756 1754 $ cat normal3
1757 1755 normal3-modified
1758 1756 $ cat sub/normal4
1759 1757 normal4-modified
1760 1758 $ cat sub/large4
1761 1759 large4-modified
1762 1760 $ cat sub2/large6
1763 1761 large6-modified
1764 1762 $ cat sub2/large7
1765 1763 large7
1766 1764
1767 1765 Cat a largefile
1768 1766 $ hg cat normal3
1769 1767 normal3-modified
1770 1768 $ hg cat sub/large4
1771 1769 large4-modified
1772 1770 $ rm "${USERCACHE}"/*
1773 1771 $ hg cat -r a381d2c8c80e -o cat.out sub/large4
1774 1772 $ cat cat.out
1775 1773 large4-modified
1776 1774 $ rm cat.out
1777 1775 $ hg cat -r a381d2c8c80e normal3
1778 1776 normal3-modified
1779 1777 $ hg cat -r '.^' normal3
1780 1778 normal3-modified
1781 1779 $ hg cat -r '.^' sub/large4 doesntexist
1782 1780 large4-modified
1783 1781 doesntexist: no such file in rev a381d2c8c80e
1784 1782 $ hg --cwd sub cat -r '.^' large4
1785 1783 large4-modified
1786 1784 $ hg --cwd sub cat -r '.^' ../normal3
1787 1785 normal3-modified
1788 1786 Cat a standin
1789 1787 $ hg cat .hglf/sub/large4
1790 1788 e166e74c7303192238d60af5a9c4ce9bef0b7928
1791 1789 $ hg cat .hglf/normal3
1792 1790 .hglf/normal3: no such file in rev 598410d3eb9a
1793 1791 [1]
1794 1792
1795 1793 Test that renaming a largefile results in correct output for status
1796 1794
1797 1795 $ hg rename sub/large4 large4-renamed
1798 1796 $ hg commit -m "test rename output"
1799 1797 Invoking status precommit hook
1800 1798 A large4-renamed
1801 1799 R sub/large4
1802 1800 $ cat large4-renamed
1803 1801 large4-modified
1804 1802 $ cd sub2
1805 1803 $ hg rename large6 large6-renamed
1806 1804 $ hg st
1807 1805 A sub2/large6-renamed
1808 1806 R sub2/large6
1809 1807 $ cd ..
1810 1808
1811 1809 Test --normal flag
1812 1810
1813 1811 $ dd if=/dev/zero bs=2k count=11k > new-largefile 2> /dev/null
1814 1812 $ hg add --normal --large new-largefile
1815 1813 abort: --normal cannot be used with --large
1816 1814 [255]
1817 1815 $ hg add --normal new-largefile
1818 1816 new-largefile: up to 69 MB of RAM may be required to manage this file
1819 1817 (use 'hg revert new-largefile' to cancel the pending addition)
1820 1818 $ cd ..
1821 1819
1822 1820
1823 1821
General Comments 0
You need to be logged in to leave comments. Login now