##// END OF EJS Templates
largefiles: simplify revert - use getstandinsstate like other commands do
Mads Kiilerich -
r21094:4643bfec default
parent child Browse files
Show More
@@ -1,1166 +1,1137
1 1 # Copyright 2009-2010 Gregory P. Ward
2 2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
3 3 # Copyright 2010-2011 Fog Creek Software
4 4 # Copyright 2010-2011 Unity Technologies
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 '''Overridden Mercurial commands and functions for the largefiles extension'''
10 10
11 11 import os
12 12 import copy
13 13
14 14 from mercurial import hg, commands, util, cmdutil, scmutil, match as match_, \
15 15 archival, merge, pathutil, revset
16 16 from mercurial.i18n import _
17 17 from mercurial.node import hex
18 18 from hgext import rebase
19 19
20 20 import lfutil
21 21 import lfcommands
22 22 import basestore
23 23
24 24 # -- Utility functions: commonly/repeatedly needed functionality ---------------
25 25
26 26 def installnormalfilesmatchfn(manifest):
27 27 '''installmatchfn with a matchfn that ignores all largefiles'''
28 28 def overridematch(ctx, pats=[], opts={}, globbed=False,
29 29 default='relpath'):
30 30 match = oldmatch(ctx, pats, opts, globbed, default)
31 31 m = copy.copy(match)
32 32 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
33 33 manifest)
34 34 m._files = filter(notlfile, m._files)
35 35 m._fmap = set(m._files)
36 36 m._always = False
37 37 origmatchfn = m.matchfn
38 38 m.matchfn = lambda f: notlfile(f) and origmatchfn(f) or None
39 39 return m
40 40 oldmatch = installmatchfn(overridematch)
41 41
42 42 def installmatchfn(f):
43 43 '''monkey patch the scmutil module with a custom match function.
44 44 Warning: it is monkey patching the _module_ on runtime! Not thread safe!'''
45 45 oldmatch = scmutil.match
46 46 setattr(f, 'oldmatch', oldmatch)
47 47 scmutil.match = f
48 48 return oldmatch
49 49
50 50 def restorematchfn():
51 51 '''restores scmutil.match to what it was before installmatchfn
52 52 was called. no-op if scmutil.match is its original function.
53 53
54 54 Note that n calls to installmatchfn will require n calls to
55 55 restore matchfn to reverse'''
56 56 scmutil.match = getattr(scmutil.match, 'oldmatch')
57 57
58 58 def addlargefiles(ui, repo, *pats, **opts):
59 59 large = opts.pop('large', None)
60 60 lfsize = lfutil.getminsize(
61 61 ui, lfutil.islfilesrepo(repo), opts.pop('lfsize', None))
62 62
63 63 lfmatcher = None
64 64 if lfutil.islfilesrepo(repo):
65 65 lfpats = ui.configlist(lfutil.longname, 'patterns', default=[])
66 66 if lfpats:
67 67 lfmatcher = match_.match(repo.root, '', list(lfpats))
68 68
69 69 lfnames = []
70 70 m = scmutil.match(repo[None], pats, opts)
71 71 m.bad = lambda x, y: None
72 72 wctx = repo[None]
73 73 for f in repo.walk(m):
74 74 exact = m.exact(f)
75 75 lfile = lfutil.standin(f) in wctx
76 76 nfile = f in wctx
77 77 exists = lfile or nfile
78 78
79 79 # Don't warn the user when they attempt to add a normal tracked file.
80 80 # The normal add code will do that for us.
81 81 if exact and exists:
82 82 if lfile:
83 83 ui.warn(_('%s already a largefile\n') % f)
84 84 continue
85 85
86 86 if (exact or not exists) and not lfutil.isstandin(f):
87 87 wfile = repo.wjoin(f)
88 88
89 89 # In case the file was removed previously, but not committed
90 90 # (issue3507)
91 91 if not os.path.exists(wfile):
92 92 continue
93 93
94 94 abovemin = (lfsize and
95 95 os.lstat(wfile).st_size >= lfsize * 1024 * 1024)
96 96 if large or abovemin or (lfmatcher and lfmatcher(f)):
97 97 lfnames.append(f)
98 98 if ui.verbose or not exact:
99 99 ui.status(_('adding %s as a largefile\n') % m.rel(f))
100 100
101 101 bad = []
102 102 standins = []
103 103
104 104 # Need to lock, otherwise there could be a race condition between
105 105 # when standins are created and added to the repo.
106 106 wlock = repo.wlock()
107 107 try:
108 108 if not opts.get('dry_run'):
109 109 lfdirstate = lfutil.openlfdirstate(ui, repo)
110 110 for f in lfnames:
111 111 standinname = lfutil.standin(f)
112 112 lfutil.writestandin(repo, standinname, hash='',
113 113 executable=lfutil.getexecutable(repo.wjoin(f)))
114 114 standins.append(standinname)
115 115 if lfdirstate[f] == 'r':
116 116 lfdirstate.normallookup(f)
117 117 else:
118 118 lfdirstate.add(f)
119 119 lfdirstate.write()
120 120 bad += [lfutil.splitstandin(f)
121 121 for f in repo[None].add(standins)
122 122 if f in m.files()]
123 123 finally:
124 124 wlock.release()
125 125 return bad
126 126
127 127 def removelargefiles(ui, repo, *pats, **opts):
128 128 after = opts.get('after')
129 129 if not pats and not after:
130 130 raise util.Abort(_('no files specified'))
131 131 m = scmutil.match(repo[None], pats, opts)
132 132 try:
133 133 repo.lfstatus = True
134 134 s = repo.status(match=m, clean=True)
135 135 finally:
136 136 repo.lfstatus = False
137 137 manifest = repo[None].manifest()
138 138 modified, added, deleted, clean = [[f for f in list
139 139 if lfutil.standin(f) in manifest]
140 140 for list in [s[0], s[1], s[3], s[6]]]
141 141
142 142 def warn(files, msg):
143 143 for f in files:
144 144 ui.warn(msg % m.rel(f))
145 145 return int(len(files) > 0)
146 146
147 147 result = 0
148 148
149 149 if after:
150 150 remove, forget = deleted, []
151 151 result = warn(modified + added + clean,
152 152 _('not removing %s: file still exists\n'))
153 153 else:
154 154 remove, forget = deleted + clean, []
155 155 result = warn(modified, _('not removing %s: file is modified (use -f'
156 156 ' to force removal)\n'))
157 157 result = warn(added, _('not removing %s: file has been marked for add'
158 158 ' (use forget to undo)\n')) or result
159 159
160 160 for f in sorted(remove + forget):
161 161 if ui.verbose or not m.exact(f):
162 162 ui.status(_('removing %s\n') % m.rel(f))
163 163
164 164 # Need to lock because standin files are deleted then removed from the
165 165 # repository and we could race in-between.
166 166 wlock = repo.wlock()
167 167 try:
168 168 lfdirstate = lfutil.openlfdirstate(ui, repo)
169 169 for f in remove:
170 170 if not after:
171 171 # If this is being called by addremove, notify the user that we
172 172 # are removing the file.
173 173 if getattr(repo, "_isaddremove", False):
174 174 ui.status(_('removing %s\n') % f)
175 175 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
176 176 lfdirstate.remove(f)
177 177 lfdirstate.write()
178 178 forget = [lfutil.standin(f) for f in forget]
179 179 remove = [lfutil.standin(f) for f in remove]
180 180 repo[None].forget(forget)
181 181 # If this is being called by addremove, let the original addremove
182 182 # function handle this.
183 183 if not getattr(repo, "_isaddremove", False):
184 184 for f in remove:
185 185 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
186 186 repo[None].forget(remove)
187 187 finally:
188 188 wlock.release()
189 189
190 190 return result
191 191
192 192 # For overriding mercurial.hgweb.webcommands so that largefiles will
193 193 # appear at their right place in the manifests.
194 194 def decodepath(orig, path):
195 195 return lfutil.splitstandin(path) or path
196 196
197 197 # -- Wrappers: modify existing commands --------------------------------
198 198
199 199 # Add works by going through the files that the user wanted to add and
200 200 # checking if they should be added as largefiles. Then it makes a new
201 201 # matcher which matches only the normal files and runs the original
202 202 # version of add.
203 203 def overrideadd(orig, ui, repo, *pats, **opts):
204 204 normal = opts.pop('normal')
205 205 if normal:
206 206 if opts.get('large'):
207 207 raise util.Abort(_('--normal cannot be used with --large'))
208 208 return orig(ui, repo, *pats, **opts)
209 209 bad = addlargefiles(ui, repo, *pats, **opts)
210 210 installnormalfilesmatchfn(repo[None].manifest())
211 211 result = orig(ui, repo, *pats, **opts)
212 212 restorematchfn()
213 213
214 214 return (result == 1 or bad) and 1 or 0
215 215
216 216 def overrideremove(orig, ui, repo, *pats, **opts):
217 217 installnormalfilesmatchfn(repo[None].manifest())
218 218 result = orig(ui, repo, *pats, **opts)
219 219 restorematchfn()
220 220 return removelargefiles(ui, repo, *pats, **opts) or result
221 221
222 222 def overridestatusfn(orig, repo, rev2, **opts):
223 223 try:
224 224 repo._repo.lfstatus = True
225 225 return orig(repo, rev2, **opts)
226 226 finally:
227 227 repo._repo.lfstatus = False
228 228
229 229 def overridestatus(orig, ui, repo, *pats, **opts):
230 230 try:
231 231 repo.lfstatus = True
232 232 return orig(ui, repo, *pats, **opts)
233 233 finally:
234 234 repo.lfstatus = False
235 235
236 236 def overridedirty(orig, repo, ignoreupdate=False):
237 237 try:
238 238 repo._repo.lfstatus = True
239 239 return orig(repo, ignoreupdate)
240 240 finally:
241 241 repo._repo.lfstatus = False
242 242
243 243 def overridelog(orig, ui, repo, *pats, **opts):
244 244 def overridematch(ctx, pats=[], opts={}, globbed=False,
245 245 default='relpath'):
246 246 """Matcher that merges root directory with .hglf, suitable for log.
247 247 It is still possible to match .hglf directly.
248 248 For any listed files run log on the standin too.
249 249 matchfn tries both the given filename and with .hglf stripped.
250 250 """
251 251 match = oldmatch(ctx, pats, opts, globbed, default)
252 252 m = copy.copy(match)
253 253 for i in range(0, len(m._files)):
254 254 standin = lfutil.standin(m._files[i])
255 255 if standin in repo[ctx.node()]:
256 256 m._files[i] = standin
257 257 m._fmap = set(m._files)
258 258 m._always = False
259 259 origmatchfn = m.matchfn
260 260 def lfmatchfn(f):
261 261 lf = lfutil.splitstandin(f)
262 262 if lf is not None and origmatchfn(lf):
263 263 return True
264 264 r = origmatchfn(f)
265 265 return r
266 266 m.matchfn = lfmatchfn
267 267 return m
268 268 oldmatch = installmatchfn(overridematch)
269 269 try:
270 270 repo.lfstatus = True
271 271 return orig(ui, repo, *pats, **opts)
272 272 finally:
273 273 repo.lfstatus = False
274 274 restorematchfn()
275 275
276 276 def overrideverify(orig, ui, repo, *pats, **opts):
277 277 large = opts.pop('large', False)
278 278 all = opts.pop('lfa', False)
279 279 contents = opts.pop('lfc', False)
280 280
281 281 result = orig(ui, repo, *pats, **opts)
282 282 if large or all or contents:
283 283 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
284 284 return result
285 285
286 286 def overridedebugstate(orig, ui, repo, *pats, **opts):
287 287 large = opts.pop('large', False)
288 288 if large:
289 289 class fakerepo(object):
290 290 dirstate = lfutil.openlfdirstate(ui, repo)
291 291 orig(ui, fakerepo, *pats, **opts)
292 292 else:
293 293 orig(ui, repo, *pats, **opts)
294 294
295 295 # Override needs to refresh standins so that update's normal merge
296 296 # will go through properly. Then the other update hook (overriding repo.update)
297 297 # will get the new files. Filemerge is also overridden so that the merge
298 298 # will merge standins correctly.
299 299 def overrideupdate(orig, ui, repo, *pats, **opts):
300 300 # Need to lock between the standins getting updated and their
301 301 # largefiles getting updated
302 302 wlock = repo.wlock()
303 303 try:
304 304 lfdirstate = lfutil.openlfdirstate(ui, repo)
305 305 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()),
306 306 [], False, False, False)
307 307 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
308 308
309 309 if opts['check']:
310 310 mod = len(modified) > 0
311 311 for lfile in unsure:
312 312 standin = lfutil.standin(lfile)
313 313 if repo['.'][standin].data().strip() != \
314 314 lfutil.hashfile(repo.wjoin(lfile)):
315 315 mod = True
316 316 else:
317 317 lfdirstate.normal(lfile)
318 318 lfdirstate.write()
319 319 if mod:
320 320 raise util.Abort(_('uncommitted changes'))
321 321 # XXX handle removed differently
322 322 if not opts['clean']:
323 323 for lfile in unsure + modified + added:
324 324 lfutil.updatestandin(repo, lfutil.standin(lfile))
325 325 return orig(ui, repo, *pats, **opts)
326 326 finally:
327 327 wlock.release()
328 328
329 329 # Before starting the manifest merge, merge.updates will call
330 330 # _checkunknown to check if there are any files in the merged-in
331 331 # changeset that collide with unknown files in the working copy.
332 332 #
333 333 # The largefiles are seen as unknown, so this prevents us from merging
334 334 # in a file 'foo' if we already have a largefile with the same name.
335 335 #
336 336 # The overridden function filters the unknown files by removing any
337 337 # largefiles. This makes the merge proceed and we can then handle this
338 338 # case further in the overridden manifestmerge function below.
339 339 def overridecheckunknownfile(origfn, repo, wctx, mctx, f):
340 340 if lfutil.standin(repo.dirstate.normalize(f)) in wctx:
341 341 return False
342 342 return origfn(repo, wctx, mctx, f)
343 343
344 344 # The manifest merge handles conflicts on the manifest level. We want
345 345 # to handle changes in largefile-ness of files at this level too.
346 346 #
347 347 # The strategy is to run the original manifestmerge and then process
348 348 # the action list it outputs. There are two cases we need to deal with:
349 349 #
350 350 # 1. Normal file in p1, largefile in p2. Here the largefile is
351 351 # detected via its standin file, which will enter the working copy
352 352 # with a "get" action. It is not "merge" since the standin is all
353 353 # Mercurial is concerned with at this level -- the link to the
354 354 # existing normal file is not relevant here.
355 355 #
356 356 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
357 357 # since the largefile will be present in the working copy and
358 358 # different from the normal file in p2. Mercurial therefore
359 359 # triggers a merge action.
360 360 #
361 361 # In both cases, we prompt the user and emit new actions to either
362 362 # remove the standin (if the normal file was kept) or to remove the
363 363 # normal file and get the standin (if the largefile was kept). The
364 364 # default prompt answer is to use the largefile version since it was
365 365 # presumably changed on purpose.
366 366 #
367 367 # Finally, the merge.applyupdates function will then take care of
368 368 # writing the files into the working copy and lfcommands.updatelfiles
369 369 # will update the largefiles.
370 370 def overridecalculateupdates(origfn, repo, p1, p2, pas, branchmerge, force,
371 371 partial, acceptremote, followcopies):
372 372 overwrite = force and not branchmerge
373 373 actions = origfn(repo, p1, p2, pas, branchmerge, force, partial,
374 374 acceptremote, followcopies)
375 375
376 376 if overwrite:
377 377 return actions
378 378
379 379 removes = set(a[0] for a in actions if a[1] == 'r')
380 380 processed = []
381 381
382 382 for action in actions:
383 383 f, m, args, msg = action
384 384
385 385 splitstandin = f and lfutil.splitstandin(f)
386 386 if (m == "g" and splitstandin is not None and
387 387 splitstandin in p1 and splitstandin not in removes):
388 388 # Case 1: normal file in the working copy, largefile in
389 389 # the second parent
390 390 lfile = splitstandin
391 391 standin = f
392 392 msg = _('remote turned local normal file %s into a largefile\n'
393 393 'use (l)argefile or keep (n)ormal file?'
394 394 '$$ &Largefile $$ &Normal file') % lfile
395 395 if repo.ui.promptchoice(msg, 0) == 0:
396 396 processed.append((lfile, "r", None, msg))
397 397 processed.append((standin, "g", (p2.flags(standin),), msg))
398 398 else:
399 399 processed.append((standin, "r", None, msg))
400 400 elif (m == "g" and
401 401 lfutil.standin(f) in p1 and lfutil.standin(f) not in removes):
402 402 # Case 2: largefile in the working copy, normal file in
403 403 # the second parent
404 404 standin = lfutil.standin(f)
405 405 lfile = f
406 406 msg = _('remote turned local largefile %s into a normal file\n'
407 407 'keep (l)argefile or use (n)ormal file?'
408 408 '$$ &Largefile $$ &Normal file') % lfile
409 409 if repo.ui.promptchoice(msg, 0) == 0:
410 410 processed.append((lfile, "r", None, msg))
411 411 else:
412 412 processed.append((standin, "r", None, msg))
413 413 processed.append((lfile, "g", (p2.flags(lfile),), msg))
414 414 else:
415 415 processed.append(action)
416 416
417 417 return processed
418 418
419 419 # Override filemerge to prompt the user about how they wish to merge
420 420 # largefiles. This will handle identical edits without prompting the user.
421 421 def overridefilemerge(origfn, repo, mynode, orig, fcd, fco, fca):
422 422 if not lfutil.isstandin(orig):
423 423 return origfn(repo, mynode, orig, fcd, fco, fca)
424 424
425 425 ahash = fca.data().strip().lower()
426 426 dhash = fcd.data().strip().lower()
427 427 ohash = fco.data().strip().lower()
428 428 if (ohash != ahash and
429 429 ohash != dhash and
430 430 (dhash == ahash or
431 431 repo.ui.promptchoice(
432 432 _('largefile %s has a merge conflict\nancestor was %s\n'
433 433 'keep (l)ocal %s or\ntake (o)ther %s?'
434 434 '$$ &Local $$ &Other') %
435 435 (lfutil.splitstandin(orig), ahash, dhash, ohash),
436 436 0) == 1)):
437 437 repo.wwrite(fcd.path(), fco.data(), fco.flags())
438 438 return 0
439 439
440 440 # Copy first changes the matchers to match standins instead of
441 441 # largefiles. Then it overrides util.copyfile in that function it
442 442 # checks if the destination largefile already exists. It also keeps a
443 443 # list of copied files so that the largefiles can be copied and the
444 444 # dirstate updated.
445 445 def overridecopy(orig, ui, repo, pats, opts, rename=False):
446 446 # doesn't remove largefile on rename
447 447 if len(pats) < 2:
448 448 # this isn't legal, let the original function deal with it
449 449 return orig(ui, repo, pats, opts, rename)
450 450
451 451 def makestandin(relpath):
452 452 path = pathutil.canonpath(repo.root, repo.getcwd(), relpath)
453 453 return os.path.join(repo.wjoin(lfutil.standin(path)))
454 454
455 455 fullpats = scmutil.expandpats(pats)
456 456 dest = fullpats[-1]
457 457
458 458 if os.path.isdir(dest):
459 459 if not os.path.isdir(makestandin(dest)):
460 460 os.makedirs(makestandin(dest))
461 461 # This could copy both lfiles and normal files in one command,
462 462 # but we don't want to do that. First replace their matcher to
463 463 # only match normal files and run it, then replace it to just
464 464 # match largefiles and run it again.
465 465 nonormalfiles = False
466 466 nolfiles = False
467 467 installnormalfilesmatchfn(repo[None].manifest())
468 468 try:
469 469 try:
470 470 result = orig(ui, repo, pats, opts, rename)
471 471 except util.Abort, e:
472 472 if str(e) != _('no files to copy'):
473 473 raise e
474 474 else:
475 475 nonormalfiles = True
476 476 result = 0
477 477 finally:
478 478 restorematchfn()
479 479
480 480 # The first rename can cause our current working directory to be removed.
481 481 # In that case there is nothing left to copy/rename so just quit.
482 482 try:
483 483 repo.getcwd()
484 484 except OSError:
485 485 return result
486 486
487 487 try:
488 488 try:
489 489 # When we call orig below it creates the standins but we don't add
490 490 # them to the dir state until later so lock during that time.
491 491 wlock = repo.wlock()
492 492
493 493 manifest = repo[None].manifest()
494 494 def overridematch(ctx, pats=[], opts={}, globbed=False,
495 495 default='relpath'):
496 496 newpats = []
497 497 # The patterns were previously mangled to add the standin
498 498 # directory; we need to remove that now
499 499 for pat in pats:
500 500 if match_.patkind(pat) is None and lfutil.shortname in pat:
501 501 newpats.append(pat.replace(lfutil.shortname, ''))
502 502 else:
503 503 newpats.append(pat)
504 504 match = oldmatch(ctx, newpats, opts, globbed, default)
505 505 m = copy.copy(match)
506 506 lfile = lambda f: lfutil.standin(f) in manifest
507 507 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
508 508 m._fmap = set(m._files)
509 509 m._always = False
510 510 origmatchfn = m.matchfn
511 511 m.matchfn = lambda f: (lfutil.isstandin(f) and
512 512 (f in manifest) and
513 513 origmatchfn(lfutil.splitstandin(f)) or
514 514 None)
515 515 return m
516 516 oldmatch = installmatchfn(overridematch)
517 517 listpats = []
518 518 for pat in pats:
519 519 if match_.patkind(pat) is not None:
520 520 listpats.append(pat)
521 521 else:
522 522 listpats.append(makestandin(pat))
523 523
524 524 try:
525 525 origcopyfile = util.copyfile
526 526 copiedfiles = []
527 527 def overridecopyfile(src, dest):
528 528 if (lfutil.shortname in src and
529 529 dest.startswith(repo.wjoin(lfutil.shortname))):
530 530 destlfile = dest.replace(lfutil.shortname, '')
531 531 if not opts['force'] and os.path.exists(destlfile):
532 532 raise IOError('',
533 533 _('destination largefile already exists'))
534 534 copiedfiles.append((src, dest))
535 535 origcopyfile(src, dest)
536 536
537 537 util.copyfile = overridecopyfile
538 538 result += orig(ui, repo, listpats, opts, rename)
539 539 finally:
540 540 util.copyfile = origcopyfile
541 541
542 542 lfdirstate = lfutil.openlfdirstate(ui, repo)
543 543 for (src, dest) in copiedfiles:
544 544 if (lfutil.shortname in src and
545 545 dest.startswith(repo.wjoin(lfutil.shortname))):
546 546 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
547 547 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
548 548 destlfiledir = os.path.dirname(repo.wjoin(destlfile)) or '.'
549 549 if not os.path.isdir(destlfiledir):
550 550 os.makedirs(destlfiledir)
551 551 if rename:
552 552 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
553 553 lfdirstate.remove(srclfile)
554 554 else:
555 555 util.copyfile(repo.wjoin(srclfile),
556 556 repo.wjoin(destlfile))
557 557
558 558 lfdirstate.add(destlfile)
559 559 lfdirstate.write()
560 560 except util.Abort, e:
561 561 if str(e) != _('no files to copy'):
562 562 raise e
563 563 else:
564 564 nolfiles = True
565 565 finally:
566 566 restorematchfn()
567 567 wlock.release()
568 568
569 569 if nolfiles and nonormalfiles:
570 570 raise util.Abort(_('no files to copy'))
571 571
572 572 return result
573 573
574 574 # When the user calls revert, we have to be careful to not revert any
575 575 # changes to other largefiles accidentally. This means we have to keep
576 576 # track of the largefiles that are being reverted so we only pull down
577 577 # the necessary largefiles.
578 578 #
579 579 # Standins are only updated (to match the hash of largefiles) before
580 580 # commits. Update the standins then run the original revert, changing
581 581 # the matcher to hit standins instead of largefiles. Based on the
582 # resulting standins update the largefiles. Then return the standins
583 # to their proper state
582 # resulting standins update the largefiles.
584 583 def overriderevert(orig, ui, repo, *pats, **opts):
585 584 # Because we put the standins in a bad state (by updating them)
586 585 # and then return them to a correct state we need to lock to
587 586 # prevent others from changing them in their incorrect state.
588 587 wlock = repo.wlock()
589 588 try:
590 589 lfdirstate = lfutil.openlfdirstate(ui, repo)
591 590 (modified, added, removed, missing, unknown, ignored, clean) = \
592 591 lfutil.lfdirstatestatus(lfdirstate, repo, repo['.'].rev())
593 592 lfdirstate.write()
594 593 for lfile in modified:
595 594 lfutil.updatestandin(repo, lfutil.standin(lfile))
596 595 for lfile in missing:
597 596 if (os.path.exists(repo.wjoin(lfutil.standin(lfile)))):
598 597 os.unlink(repo.wjoin(lfutil.standin(lfile)))
599 598
599 oldstandins = lfutil.getstandinsstate(repo)
600
600 601 try:
601 ctx = scmutil.revsingle(repo, opts.get('rev'))
602 602 def overridematch(ctx, pats=[], opts={}, globbed=False,
603 603 default='relpath'):
604 604 match = oldmatch(ctx, pats, opts, globbed, default)
605 605 m = copy.copy(match)
606 606 def tostandin(f):
607 607 if lfutil.standin(f) in ctx:
608 608 return lfutil.standin(f)
609 609 elif lfutil.standin(f) in repo[None]:
610 610 return None
611 611 return f
612 612 m._files = [tostandin(f) for f in m._files]
613 613 m._files = [f for f in m._files if f is not None]
614 614 m._fmap = set(m._files)
615 615 m._always = False
616 616 origmatchfn = m.matchfn
617 617 def matchfn(f):
618 618 if lfutil.isstandin(f):
619 # We need to keep track of what largefiles are being
620 # matched so we know which ones to update later --
621 # otherwise we accidentally revert changes to other
622 # largefiles. This is repo-specific, so duckpunch the
623 # repo object to keep the list of largefiles for us
624 # later.
625 if origmatchfn(lfutil.splitstandin(f)) and \
626 (f in repo[None] or f in ctx):
627 lfileslist = getattr(repo, '_lfilestoupdate', [])
628 lfileslist.append(lfutil.splitstandin(f))
629 repo._lfilestoupdate = lfileslist
630 return True
631 else:
632 return False
619 return (origmatchfn(lfutil.splitstandin(f)) and
620 (f in repo[None] or f in ctx))
633 621 return origmatchfn(f)
634 622 m.matchfn = matchfn
635 623 return m
636 624 oldmatch = installmatchfn(overridematch)
637 scmutil.match
638 matches = overridematch(repo[None], pats, opts)
625 overridematch(repo[None], pats, opts)
639 626 orig(ui, repo, *pats, **opts)
640 627 finally:
641 628 restorematchfn()
642 lfileslist = getattr(repo, '_lfilestoupdate', [])
643 lfcommands.updatelfiles(ui, repo, filelist=lfileslist,
644 printmessage=False)
645 629
646 # empty out the largefiles list so we start fresh next time
647 repo._lfilestoupdate = []
648 for lfile in modified:
649 if lfile in lfileslist:
650 if os.path.exists(repo.wjoin(lfutil.standin(lfile))) and lfile\
651 in repo['.']:
652 lfutil.writestandin(repo, lfutil.standin(lfile),
653 repo['.'][lfile].data().strip(),
654 'x' in repo['.'][lfile].flags())
655 lfdirstate = lfutil.openlfdirstate(ui, repo)
656 for lfile in added:
657 standin = lfutil.standin(lfile)
658 if standin not in ctx and (standin in matches or opts.get('all')):
659 if lfile in lfdirstate:
660 lfdirstate.drop(lfile)
661 util.unlinkpath(repo.wjoin(standin))
662 lfdirstate.write()
630 newstandins = lfutil.getstandinsstate(repo)
631 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
632 lfcommands.updatelfiles(ui, repo, filelist, printmessage=False)
633
663 634 finally:
664 635 wlock.release()
665 636
666 637 def hgupdaterepo(orig, repo, node, overwrite):
667 638 if not overwrite:
668 639 # Only call updatelfiles on the standins that have changed to save time
669 640 oldstandins = lfutil.getstandinsstate(repo)
670 641
671 642 result = orig(repo, node, overwrite)
672 643
673 644 filelist = None
674 645 if not overwrite:
675 646 newstandins = lfutil.getstandinsstate(repo)
676 647 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
677 648 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist)
678 649 return result
679 650
680 651 def hgmerge(orig, repo, node, force=None, remind=True):
681 652 result = orig(repo, node, force, remind)
682 653 lfcommands.updatelfiles(repo.ui, repo)
683 654 return result
684 655
685 656 # When we rebase a repository with remotely changed largefiles, we need to
686 657 # take some extra care so that the largefiles are correctly updated in the
687 658 # working copy
688 659 def overridepull(orig, ui, repo, source=None, **opts):
689 660 revsprepull = len(repo)
690 661 if not source:
691 662 source = 'default'
692 663 repo.lfpullsource = source
693 664 if opts.get('rebase', False):
694 665 repo._isrebasing = True
695 666 try:
696 667 if opts.get('update'):
697 668 del opts['update']
698 669 ui.debug('--update and --rebase are not compatible, ignoring '
699 670 'the update flag\n')
700 671 del opts['rebase']
701 672 origpostincoming = commands.postincoming
702 673 def _dummy(*args, **kwargs):
703 674 pass
704 675 commands.postincoming = _dummy
705 676 try:
706 677 result = commands.pull(ui, repo, source, **opts)
707 678 finally:
708 679 commands.postincoming = origpostincoming
709 680 revspostpull = len(repo)
710 681 if revspostpull > revsprepull:
711 682 result = result or rebase.rebase(ui, repo)
712 683 finally:
713 684 repo._isrebasing = False
714 685 else:
715 686 result = orig(ui, repo, source, **opts)
716 687 revspostpull = len(repo)
717 688 lfrevs = opts.get('lfrev', [])
718 689 if opts.get('all_largefiles'):
719 690 lfrevs.append('pulled()')
720 691 if lfrevs and revspostpull > revsprepull:
721 692 numcached = 0
722 693 repo.firstpulled = revsprepull # for pulled() revset expression
723 694 try:
724 695 for rev in scmutil.revrange(repo, lfrevs):
725 696 ui.note(_('pulling largefiles for revision %s\n') % rev)
726 697 (cached, missing) = lfcommands.cachelfiles(ui, repo, rev)
727 698 numcached += len(cached)
728 699 finally:
729 700 del repo.firstpulled
730 701 ui.status(_("%d largefiles cached\n") % numcached)
731 702 return result
732 703
733 704 def pulledrevsetsymbol(repo, subset, x):
734 705 """``pulled()``
735 706 Changesets that just has been pulled.
736 707
737 708 Only available with largefiles from pull --lfrev expressions.
738 709
739 710 .. container:: verbose
740 711
741 712 Some examples:
742 713
743 714 - pull largefiles for all new changesets::
744 715
745 716 hg pull -lfrev "pulled()"
746 717
747 718 - pull largefiles for all new branch heads::
748 719
749 720 hg pull -lfrev "head(pulled()) and not closed()"
750 721
751 722 """
752 723
753 724 try:
754 725 firstpulled = repo.firstpulled
755 726 except AttributeError:
756 727 raise util.Abort(_("pulled() only available in --lfrev"))
757 728 return revset.baseset([r for r in subset if r >= firstpulled])
758 729
759 730 def overrideclone(orig, ui, source, dest=None, **opts):
760 731 d = dest
761 732 if d is None:
762 733 d = hg.defaultdest(source)
763 734 if opts.get('all_largefiles') and not hg.islocal(d):
764 735 raise util.Abort(_(
765 736 '--all-largefiles is incompatible with non-local destination %s' %
766 737 d))
767 738
768 739 return orig(ui, source, dest, **opts)
769 740
770 741 def hgclone(orig, ui, opts, *args, **kwargs):
771 742 result = orig(ui, opts, *args, **kwargs)
772 743
773 744 if result is not None:
774 745 sourcerepo, destrepo = result
775 746 repo = destrepo.local()
776 747
777 748 # Caching is implicitly limited to 'rev' option, since the dest repo was
778 749 # truncated at that point. The user may expect a download count with
779 750 # this option, so attempt whether or not this is a largefile repo.
780 751 if opts.get('all_largefiles'):
781 752 success, missing = lfcommands.downloadlfiles(ui, repo, None)
782 753
783 754 if missing != 0:
784 755 return None
785 756
786 757 return result
787 758
788 759 def overriderebase(orig, ui, repo, **opts):
789 760 repo._isrebasing = True
790 761 try:
791 762 return orig(ui, repo, **opts)
792 763 finally:
793 764 repo._isrebasing = False
794 765
795 766 def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None,
796 767 prefix=None, mtime=None, subrepos=None):
797 768 # No need to lock because we are only reading history and
798 769 # largefile caches, neither of which are modified.
799 770 lfcommands.cachelfiles(repo.ui, repo, node)
800 771
801 772 if kind not in archival.archivers:
802 773 raise util.Abort(_("unknown archive type '%s'") % kind)
803 774
804 775 ctx = repo[node]
805 776
806 777 if kind == 'files':
807 778 if prefix:
808 779 raise util.Abort(
809 780 _('cannot give prefix when archiving to files'))
810 781 else:
811 782 prefix = archival.tidyprefix(dest, kind, prefix)
812 783
813 784 def write(name, mode, islink, getdata):
814 785 if matchfn and not matchfn(name):
815 786 return
816 787 data = getdata()
817 788 if decode:
818 789 data = repo.wwritedata(name, data)
819 790 archiver.addfile(prefix + name, mode, islink, data)
820 791
821 792 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
822 793
823 794 if repo.ui.configbool("ui", "archivemeta", True):
824 795 def metadata():
825 796 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
826 797 hex(repo.changelog.node(0)), hex(node), ctx.branch())
827 798
828 799 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
829 800 if repo.tagtype(t) == 'global')
830 801 if not tags:
831 802 repo.ui.pushbuffer()
832 803 opts = {'template': '{latesttag}\n{latesttagdistance}',
833 804 'style': '', 'patch': None, 'git': None}
834 805 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
835 806 ltags, dist = repo.ui.popbuffer().split('\n')
836 807 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
837 808 tags += 'latesttagdistance: %s\n' % dist
838 809
839 810 return base + tags
840 811
841 812 write('.hg_archival.txt', 0644, False, metadata)
842 813
843 814 for f in ctx:
844 815 ff = ctx.flags(f)
845 816 getdata = ctx[f].data
846 817 if lfutil.isstandin(f):
847 818 path = lfutil.findfile(repo, getdata().strip())
848 819 if path is None:
849 820 raise util.Abort(
850 821 _('largefile %s not found in repo store or system cache')
851 822 % lfutil.splitstandin(f))
852 823 f = lfutil.splitstandin(f)
853 824
854 825 def getdatafn():
855 826 fd = None
856 827 try:
857 828 fd = open(path, 'rb')
858 829 return fd.read()
859 830 finally:
860 831 if fd:
861 832 fd.close()
862 833
863 834 getdata = getdatafn
864 835 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
865 836
866 837 if subrepos:
867 838 for subpath in sorted(ctx.substate):
868 839 sub = ctx.sub(subpath)
869 840 submatch = match_.narrowmatcher(subpath, matchfn)
870 841 sub.archive(repo.ui, archiver, prefix, submatch)
871 842
872 843 archiver.done()
873 844
874 845 def hgsubrepoarchive(orig, repo, ui, archiver, prefix, match=None):
875 846 repo._get(repo._state + ('hg',))
876 847 rev = repo._state[1]
877 848 ctx = repo._repo[rev]
878 849
879 850 lfcommands.cachelfiles(ui, repo._repo, ctx.node())
880 851
881 852 def write(name, mode, islink, getdata):
882 853 # At this point, the standin has been replaced with the largefile name,
883 854 # so the normal matcher works here without the lfutil variants.
884 855 if match and not match(f):
885 856 return
886 857 data = getdata()
887 858
888 859 archiver.addfile(prefix + repo._path + '/' + name, mode, islink, data)
889 860
890 861 for f in ctx:
891 862 ff = ctx.flags(f)
892 863 getdata = ctx[f].data
893 864 if lfutil.isstandin(f):
894 865 path = lfutil.findfile(repo._repo, getdata().strip())
895 866 if path is None:
896 867 raise util.Abort(
897 868 _('largefile %s not found in repo store or system cache')
898 869 % lfutil.splitstandin(f))
899 870 f = lfutil.splitstandin(f)
900 871
901 872 def getdatafn():
902 873 fd = None
903 874 try:
904 875 fd = open(os.path.join(prefix, path), 'rb')
905 876 return fd.read()
906 877 finally:
907 878 if fd:
908 879 fd.close()
909 880
910 881 getdata = getdatafn
911 882
912 883 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
913 884
914 885 for subpath in sorted(ctx.substate):
915 886 sub = ctx.sub(subpath)
916 887 submatch = match_.narrowmatcher(subpath, match)
917 888 sub.archive(ui, archiver, os.path.join(prefix, repo._path) + '/',
918 889 submatch)
919 890
920 891 # If a largefile is modified, the change is not reflected in its
921 892 # standin until a commit. cmdutil.bailifchanged() raises an exception
922 893 # if the repo has uncommitted changes. Wrap it to also check if
923 894 # largefiles were changed. This is used by bisect and backout.
924 895 def overridebailifchanged(orig, repo):
925 896 orig(repo)
926 897 repo.lfstatus = True
927 898 modified, added, removed, deleted = repo.status()[:4]
928 899 repo.lfstatus = False
929 900 if modified or added or removed or deleted:
930 901 raise util.Abort(_('uncommitted changes'))
931 902
932 903 # Fetch doesn't use cmdutil.bailifchanged so override it to add the check
933 904 def overridefetch(orig, ui, repo, *pats, **opts):
934 905 repo.lfstatus = True
935 906 modified, added, removed, deleted = repo.status()[:4]
936 907 repo.lfstatus = False
937 908 if modified or added or removed or deleted:
938 909 raise util.Abort(_('uncommitted changes'))
939 910 return orig(ui, repo, *pats, **opts)
940 911
941 912 def overrideforget(orig, ui, repo, *pats, **opts):
942 913 installnormalfilesmatchfn(repo[None].manifest())
943 914 result = orig(ui, repo, *pats, **opts)
944 915 restorematchfn()
945 916 m = scmutil.match(repo[None], pats, opts)
946 917
947 918 try:
948 919 repo.lfstatus = True
949 920 s = repo.status(match=m, clean=True)
950 921 finally:
951 922 repo.lfstatus = False
952 923 forget = sorted(s[0] + s[1] + s[3] + s[6])
953 924 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
954 925
955 926 for f in forget:
956 927 if lfutil.standin(f) not in repo.dirstate and not \
957 928 os.path.isdir(m.rel(lfutil.standin(f))):
958 929 ui.warn(_('not removing %s: file is already untracked\n')
959 930 % m.rel(f))
960 931 result = 1
961 932
962 933 for f in forget:
963 934 if ui.verbose or not m.exact(f):
964 935 ui.status(_('removing %s\n') % m.rel(f))
965 936
966 937 # Need to lock because standin files are deleted then removed from the
967 938 # repository and we could race in-between.
968 939 wlock = repo.wlock()
969 940 try:
970 941 lfdirstate = lfutil.openlfdirstate(ui, repo)
971 942 for f in forget:
972 943 if lfdirstate[f] == 'a':
973 944 lfdirstate.drop(f)
974 945 else:
975 946 lfdirstate.remove(f)
976 947 lfdirstate.write()
977 948 standins = [lfutil.standin(f) for f in forget]
978 949 for f in standins:
979 950 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
980 951 repo[None].forget(standins)
981 952 finally:
982 953 wlock.release()
983 954
984 955 return result
985 956
986 957 def outgoinghook(ui, repo, other, opts, missing):
987 958 if opts.pop('large', None):
988 959 toupload = set()
989 960 lfutil.getlfilestoupload(repo, missing,
990 961 lambda fn, lfhash: toupload.add(fn))
991 962 if not toupload:
992 963 ui.status(_('largefiles: no files to upload\n'))
993 964 else:
994 965 ui.status(_('largefiles to upload:\n'))
995 966 for file in sorted(toupload):
996 967 ui.status(lfutil.splitstandin(file) + '\n')
997 968 ui.status('\n')
998 969
999 970 def summaryremotehook(ui, repo, opts, changes):
1000 971 largeopt = opts.get('large', False)
1001 972 if changes is None:
1002 973 if largeopt:
1003 974 return (False, True) # only outgoing check is needed
1004 975 else:
1005 976 return (False, False)
1006 977 elif largeopt:
1007 978 url, branch, peer, outgoing = changes[1]
1008 979 if peer is None:
1009 980 # i18n: column positioning for "hg summary"
1010 981 ui.status(_('largefiles: (no remote repo)\n'))
1011 982 return
1012 983
1013 984 toupload = set()
1014 985 lfutil.getlfilestoupload(repo, outgoing.missing,
1015 986 lambda fn, lfhash: toupload.add(fn))
1016 987 if not toupload:
1017 988 # i18n: column positioning for "hg summary"
1018 989 ui.status(_('largefiles: (no files to upload)\n'))
1019 990 else:
1020 991 # i18n: column positioning for "hg summary"
1021 992 ui.status(_('largefiles: %d to upload\n') % len(toupload))
1022 993
1023 994 def overridesummary(orig, ui, repo, *pats, **opts):
1024 995 try:
1025 996 repo.lfstatus = True
1026 997 orig(ui, repo, *pats, **opts)
1027 998 finally:
1028 999 repo.lfstatus = False
1029 1000
1030 1001 def scmutiladdremove(orig, repo, pats=[], opts={}, dry_run=None,
1031 1002 similarity=None):
1032 1003 if not lfutil.islfilesrepo(repo):
1033 1004 return orig(repo, pats, opts, dry_run, similarity)
1034 1005 # Get the list of missing largefiles so we can remove them
1035 1006 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1036 1007 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
1037 1008 False, False)
1038 1009 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
1039 1010
1040 1011 # Call into the normal remove code, but the removing of the standin, we want
1041 1012 # to have handled by original addremove. Monkey patching here makes sure
1042 1013 # we don't remove the standin in the largefiles code, preventing a very
1043 1014 # confused state later.
1044 1015 if missing:
1045 1016 m = [repo.wjoin(f) for f in missing]
1046 1017 repo._isaddremove = True
1047 1018 removelargefiles(repo.ui, repo, *m, **opts)
1048 1019 repo._isaddremove = False
1049 1020 # Call into the normal add code, and any files that *should* be added as
1050 1021 # largefiles will be
1051 1022 addlargefiles(repo.ui, repo, *pats, **opts)
1052 1023 # Now that we've handled largefiles, hand off to the original addremove
1053 1024 # function to take care of the rest. Make sure it doesn't do anything with
1054 1025 # largefiles by installing a matcher that will ignore them.
1055 1026 installnormalfilesmatchfn(repo[None].manifest())
1056 1027 result = orig(repo, pats, opts, dry_run, similarity)
1057 1028 restorematchfn()
1058 1029 return result
1059 1030
1060 1031 # Calling purge with --all will cause the largefiles to be deleted.
1061 1032 # Override repo.status to prevent this from happening.
1062 1033 def overridepurge(orig, ui, repo, *dirs, **opts):
1063 1034 # XXX large file status is buggy when used on repo proxy.
1064 1035 # XXX this needs to be investigate.
1065 1036 repo = repo.unfiltered()
1066 1037 oldstatus = repo.status
1067 1038 def overridestatus(node1='.', node2=None, match=None, ignored=False,
1068 1039 clean=False, unknown=False, listsubrepos=False):
1069 1040 r = oldstatus(node1, node2, match, ignored, clean, unknown,
1070 1041 listsubrepos)
1071 1042 lfdirstate = lfutil.openlfdirstate(ui, repo)
1072 1043 modified, added, removed, deleted, unknown, ignored, clean = r
1073 1044 unknown = [f for f in unknown if lfdirstate[f] == '?']
1074 1045 ignored = [f for f in ignored if lfdirstate[f] == '?']
1075 1046 return modified, added, removed, deleted, unknown, ignored, clean
1076 1047 repo.status = overridestatus
1077 1048 orig(ui, repo, *dirs, **opts)
1078 1049 repo.status = oldstatus
1079 1050
1080 1051 def overriderollback(orig, ui, repo, **opts):
1081 1052 result = orig(ui, repo, **opts)
1082 1053 merge.update(repo, node=None, branchmerge=False, force=True,
1083 1054 partial=lfutil.isstandin)
1084 1055 wlock = repo.wlock()
1085 1056 try:
1086 1057 lfdirstate = lfutil.openlfdirstate(ui, repo)
1087 1058 lfiles = lfutil.listlfiles(repo)
1088 1059 oldlfiles = lfutil.listlfiles(repo, repo[None].parents()[0].rev())
1089 1060 for file in lfiles:
1090 1061 if file in oldlfiles:
1091 1062 lfdirstate.normallookup(file)
1092 1063 else:
1093 1064 lfdirstate.add(file)
1094 1065 lfdirstate.write()
1095 1066 finally:
1096 1067 wlock.release()
1097 1068 return result
1098 1069
1099 1070 def overridetransplant(orig, ui, repo, *revs, **opts):
1100 1071 try:
1101 1072 oldstandins = lfutil.getstandinsstate(repo)
1102 1073 repo._istransplanting = True
1103 1074 result = orig(ui, repo, *revs, **opts)
1104 1075 newstandins = lfutil.getstandinsstate(repo)
1105 1076 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
1106 1077 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1107 1078 printmessage=True)
1108 1079 finally:
1109 1080 repo._istransplanting = False
1110 1081 return result
1111 1082
1112 1083 def overridecat(orig, ui, repo, file1, *pats, **opts):
1113 1084 ctx = scmutil.revsingle(repo, opts.get('rev'))
1114 1085 err = 1
1115 1086 notbad = set()
1116 1087 m = scmutil.match(ctx, (file1,) + pats, opts)
1117 1088 origmatchfn = m.matchfn
1118 1089 def lfmatchfn(f):
1119 1090 if origmatchfn(f):
1120 1091 return True
1121 1092 lf = lfutil.splitstandin(f)
1122 1093 if lf is None:
1123 1094 return False
1124 1095 notbad.add(lf)
1125 1096 return origmatchfn(lf)
1126 1097 m.matchfn = lfmatchfn
1127 1098 origbadfn = m.bad
1128 1099 def lfbadfn(f, msg):
1129 1100 if not f in notbad:
1130 1101 origbadfn(f, msg)
1131 1102 m.bad = lfbadfn
1132 1103 for f in ctx.walk(m):
1133 1104 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1134 1105 pathname=f)
1135 1106 lf = lfutil.splitstandin(f)
1136 1107 if lf is None or origmatchfn(f):
1137 1108 # duplicating unreachable code from commands.cat
1138 1109 data = ctx[f].data()
1139 1110 if opts.get('decode'):
1140 1111 data = repo.wwritedata(f, data)
1141 1112 fp.write(data)
1142 1113 else:
1143 1114 hash = lfutil.readstandin(repo, lf, ctx.rev())
1144 1115 if not lfutil.inusercache(repo.ui, hash):
1145 1116 store = basestore._openstore(repo)
1146 1117 success, missing = store.get([(lf, hash)])
1147 1118 if len(success) != 1:
1148 1119 raise util.Abort(
1149 1120 _('largefile %s is not in cache and could not be '
1150 1121 'downloaded') % lf)
1151 1122 path = lfutil.usercachepath(repo.ui, hash)
1152 1123 fpin = open(path, "rb")
1153 1124 for chunk in util.filechunkiter(fpin, 128 * 1024):
1154 1125 fp.write(chunk)
1155 1126 fpin.close()
1156 1127 fp.close()
1157 1128 err = 0
1158 1129 return err
1159 1130
1160 1131 def mercurialsinkbefore(orig, sink):
1161 1132 sink.repo._isconverting = True
1162 1133 orig(sink)
1163 1134
1164 1135 def mercurialsinkafter(orig, sink):
1165 1136 sink.repo._isconverting = False
1166 1137 orig(sink)
General Comments 0
You need to be logged in to leave comments. Login now