##// END OF EJS Templates
i18n: fix "% inside _()" problem
FUJIWARA Katsunori -
r21096:a45ed365 default
parent child Browse files
Show More
@@ -1,1136 +1,1136 b''
1 1 # Copyright 2009-2010 Gregory P. Ward
2 2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
3 3 # Copyright 2010-2011 Fog Creek Software
4 4 # Copyright 2010-2011 Unity Technologies
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 '''Overridden Mercurial commands and functions for the largefiles extension'''
10 10
11 11 import os
12 12 import copy
13 13
14 14 from mercurial import hg, commands, util, cmdutil, scmutil, match as match_, \
15 15 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 582 # resulting standins update the largefiles.
583 583 def overriderevert(orig, ui, repo, *pats, **opts):
584 584 # Because we put the standins in a bad state (by updating them)
585 585 # and then return them to a correct state we need to lock to
586 586 # prevent others from changing them in their incorrect state.
587 587 wlock = repo.wlock()
588 588 try:
589 589 lfdirstate = lfutil.openlfdirstate(ui, repo)
590 590 (modified, added, removed, missing, unknown, ignored, clean) = \
591 591 lfutil.lfdirstatestatus(lfdirstate, repo, repo['.'].rev())
592 592 lfdirstate.write()
593 593 for lfile in modified:
594 594 lfutil.updatestandin(repo, lfutil.standin(lfile))
595 595 for lfile in missing:
596 596 if (os.path.exists(repo.wjoin(lfutil.standin(lfile)))):
597 597 os.unlink(repo.wjoin(lfutil.standin(lfile)))
598 598
599 599 oldstandins = lfutil.getstandinsstate(repo)
600 600
601 601 def overridematch(ctx, pats=[], opts={}, globbed=False,
602 602 default='relpath'):
603 603 match = oldmatch(ctx, pats, opts, globbed, default)
604 604 m = copy.copy(match)
605 605 def tostandin(f):
606 606 if lfutil.standin(f) in ctx:
607 607 return lfutil.standin(f)
608 608 elif lfutil.standin(f) in repo[None]:
609 609 return None
610 610 return f
611 611 m._files = [tostandin(f) for f in m._files]
612 612 m._files = [f for f in m._files if f is not None]
613 613 m._fmap = set(m._files)
614 614 m._always = False
615 615 origmatchfn = m.matchfn
616 616 def matchfn(f):
617 617 if lfutil.isstandin(f):
618 618 return (origmatchfn(lfutil.splitstandin(f)) and
619 619 (f in repo[None] or f in ctx))
620 620 return origmatchfn(f)
621 621 m.matchfn = matchfn
622 622 return m
623 623 oldmatch = installmatchfn(overridematch)
624 624 try:
625 625 orig(ui, repo, *pats, **opts)
626 626 finally:
627 627 restorematchfn()
628 628
629 629 newstandins = lfutil.getstandinsstate(repo)
630 630 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
631 631 lfcommands.updatelfiles(ui, repo, filelist, printmessage=False)
632 632
633 633 finally:
634 634 wlock.release()
635 635
636 636 def hgupdaterepo(orig, repo, node, overwrite):
637 637 if not overwrite:
638 638 # Only call updatelfiles on the standins that have changed to save time
639 639 oldstandins = lfutil.getstandinsstate(repo)
640 640
641 641 result = orig(repo, node, overwrite)
642 642
643 643 filelist = None
644 644 if not overwrite:
645 645 newstandins = lfutil.getstandinsstate(repo)
646 646 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
647 647 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist)
648 648 return result
649 649
650 650 def hgmerge(orig, repo, node, force=None, remind=True):
651 651 result = orig(repo, node, force, remind)
652 652 lfcommands.updatelfiles(repo.ui, repo)
653 653 return result
654 654
655 655 # When we rebase a repository with remotely changed largefiles, we need to
656 656 # take some extra care so that the largefiles are correctly updated in the
657 657 # working copy
658 658 def overridepull(orig, ui, repo, source=None, **opts):
659 659 revsprepull = len(repo)
660 660 if not source:
661 661 source = 'default'
662 662 repo.lfpullsource = source
663 663 if opts.get('rebase', False):
664 664 repo._isrebasing = True
665 665 try:
666 666 if opts.get('update'):
667 667 del opts['update']
668 668 ui.debug('--update and --rebase are not compatible, ignoring '
669 669 'the update flag\n')
670 670 del opts['rebase']
671 671 origpostincoming = commands.postincoming
672 672 def _dummy(*args, **kwargs):
673 673 pass
674 674 commands.postincoming = _dummy
675 675 try:
676 676 result = commands.pull(ui, repo, source, **opts)
677 677 finally:
678 678 commands.postincoming = origpostincoming
679 679 revspostpull = len(repo)
680 680 if revspostpull > revsprepull:
681 681 result = result or rebase.rebase(ui, repo)
682 682 finally:
683 683 repo._isrebasing = False
684 684 else:
685 685 result = orig(ui, repo, source, **opts)
686 686 revspostpull = len(repo)
687 687 lfrevs = opts.get('lfrev', [])
688 688 if opts.get('all_largefiles'):
689 689 lfrevs.append('pulled()')
690 690 if lfrevs and revspostpull > revsprepull:
691 691 numcached = 0
692 692 repo.firstpulled = revsprepull # for pulled() revset expression
693 693 try:
694 694 for rev in scmutil.revrange(repo, lfrevs):
695 695 ui.note(_('pulling largefiles for revision %s\n') % rev)
696 696 (cached, missing) = lfcommands.cachelfiles(ui, repo, rev)
697 697 numcached += len(cached)
698 698 finally:
699 699 del repo.firstpulled
700 700 ui.status(_("%d largefiles cached\n") % numcached)
701 701 return result
702 702
703 703 def pulledrevsetsymbol(repo, subset, x):
704 704 """``pulled()``
705 705 Changesets that just has been pulled.
706 706
707 707 Only available with largefiles from pull --lfrev expressions.
708 708
709 709 .. container:: verbose
710 710
711 711 Some examples:
712 712
713 713 - pull largefiles for all new changesets::
714 714
715 715 hg pull -lfrev "pulled()"
716 716
717 717 - pull largefiles for all new branch heads::
718 718
719 719 hg pull -lfrev "head(pulled()) and not closed()"
720 720
721 721 """
722 722
723 723 try:
724 724 firstpulled = repo.firstpulled
725 725 except AttributeError:
726 726 raise util.Abort(_("pulled() only available in --lfrev"))
727 727 return revset.baseset([r for r in subset if r >= firstpulled])
728 728
729 729 def overrideclone(orig, ui, source, dest=None, **opts):
730 730 d = dest
731 731 if d is None:
732 732 d = hg.defaultdest(source)
733 733 if opts.get('all_largefiles') and not hg.islocal(d):
734 734 raise util.Abort(_(
735 '--all-largefiles is incompatible with non-local destination %s' %
736 d))
735 '--all-largefiles is incompatible with non-local destination %s') %
736 d)
737 737
738 738 return orig(ui, source, dest, **opts)
739 739
740 740 def hgclone(orig, ui, opts, *args, **kwargs):
741 741 result = orig(ui, opts, *args, **kwargs)
742 742
743 743 if result is not None:
744 744 sourcerepo, destrepo = result
745 745 repo = destrepo.local()
746 746
747 747 # Caching is implicitly limited to 'rev' option, since the dest repo was
748 748 # truncated at that point. The user may expect a download count with
749 749 # this option, so attempt whether or not this is a largefile repo.
750 750 if opts.get('all_largefiles'):
751 751 success, missing = lfcommands.downloadlfiles(ui, repo, None)
752 752
753 753 if missing != 0:
754 754 return None
755 755
756 756 return result
757 757
758 758 def overriderebase(orig, ui, repo, **opts):
759 759 repo._isrebasing = True
760 760 try:
761 761 return orig(ui, repo, **opts)
762 762 finally:
763 763 repo._isrebasing = False
764 764
765 765 def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None,
766 766 prefix=None, mtime=None, subrepos=None):
767 767 # No need to lock because we are only reading history and
768 768 # largefile caches, neither of which are modified.
769 769 lfcommands.cachelfiles(repo.ui, repo, node)
770 770
771 771 if kind not in archival.archivers:
772 772 raise util.Abort(_("unknown archive type '%s'") % kind)
773 773
774 774 ctx = repo[node]
775 775
776 776 if kind == 'files':
777 777 if prefix:
778 778 raise util.Abort(
779 779 _('cannot give prefix when archiving to files'))
780 780 else:
781 781 prefix = archival.tidyprefix(dest, kind, prefix)
782 782
783 783 def write(name, mode, islink, getdata):
784 784 if matchfn and not matchfn(name):
785 785 return
786 786 data = getdata()
787 787 if decode:
788 788 data = repo.wwritedata(name, data)
789 789 archiver.addfile(prefix + name, mode, islink, data)
790 790
791 791 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
792 792
793 793 if repo.ui.configbool("ui", "archivemeta", True):
794 794 def metadata():
795 795 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
796 796 hex(repo.changelog.node(0)), hex(node), ctx.branch())
797 797
798 798 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
799 799 if repo.tagtype(t) == 'global')
800 800 if not tags:
801 801 repo.ui.pushbuffer()
802 802 opts = {'template': '{latesttag}\n{latesttagdistance}',
803 803 'style': '', 'patch': None, 'git': None}
804 804 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
805 805 ltags, dist = repo.ui.popbuffer().split('\n')
806 806 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
807 807 tags += 'latesttagdistance: %s\n' % dist
808 808
809 809 return base + tags
810 810
811 811 write('.hg_archival.txt', 0644, False, metadata)
812 812
813 813 for f in ctx:
814 814 ff = ctx.flags(f)
815 815 getdata = ctx[f].data
816 816 if lfutil.isstandin(f):
817 817 path = lfutil.findfile(repo, getdata().strip())
818 818 if path is None:
819 819 raise util.Abort(
820 820 _('largefile %s not found in repo store or system cache')
821 821 % lfutil.splitstandin(f))
822 822 f = lfutil.splitstandin(f)
823 823
824 824 def getdatafn():
825 825 fd = None
826 826 try:
827 827 fd = open(path, 'rb')
828 828 return fd.read()
829 829 finally:
830 830 if fd:
831 831 fd.close()
832 832
833 833 getdata = getdatafn
834 834 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
835 835
836 836 if subrepos:
837 837 for subpath in sorted(ctx.substate):
838 838 sub = ctx.sub(subpath)
839 839 submatch = match_.narrowmatcher(subpath, matchfn)
840 840 sub.archive(repo.ui, archiver, prefix, submatch)
841 841
842 842 archiver.done()
843 843
844 844 def hgsubrepoarchive(orig, repo, ui, archiver, prefix, match=None):
845 845 repo._get(repo._state + ('hg',))
846 846 rev = repo._state[1]
847 847 ctx = repo._repo[rev]
848 848
849 849 lfcommands.cachelfiles(ui, repo._repo, ctx.node())
850 850
851 851 def write(name, mode, islink, getdata):
852 852 # At this point, the standin has been replaced with the largefile name,
853 853 # so the normal matcher works here without the lfutil variants.
854 854 if match and not match(f):
855 855 return
856 856 data = getdata()
857 857
858 858 archiver.addfile(prefix + repo._path + '/' + name, mode, islink, data)
859 859
860 860 for f in ctx:
861 861 ff = ctx.flags(f)
862 862 getdata = ctx[f].data
863 863 if lfutil.isstandin(f):
864 864 path = lfutil.findfile(repo._repo, getdata().strip())
865 865 if path is None:
866 866 raise util.Abort(
867 867 _('largefile %s not found in repo store or system cache')
868 868 % lfutil.splitstandin(f))
869 869 f = lfutil.splitstandin(f)
870 870
871 871 def getdatafn():
872 872 fd = None
873 873 try:
874 874 fd = open(os.path.join(prefix, path), 'rb')
875 875 return fd.read()
876 876 finally:
877 877 if fd:
878 878 fd.close()
879 879
880 880 getdata = getdatafn
881 881
882 882 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
883 883
884 884 for subpath in sorted(ctx.substate):
885 885 sub = ctx.sub(subpath)
886 886 submatch = match_.narrowmatcher(subpath, match)
887 887 sub.archive(ui, archiver, os.path.join(prefix, repo._path) + '/',
888 888 submatch)
889 889
890 890 # If a largefile is modified, the change is not reflected in its
891 891 # standin until a commit. cmdutil.bailifchanged() raises an exception
892 892 # if the repo has uncommitted changes. Wrap it to also check if
893 893 # largefiles were changed. This is used by bisect and backout.
894 894 def overridebailifchanged(orig, repo):
895 895 orig(repo)
896 896 repo.lfstatus = True
897 897 modified, added, removed, deleted = repo.status()[:4]
898 898 repo.lfstatus = False
899 899 if modified or added or removed or deleted:
900 900 raise util.Abort(_('uncommitted changes'))
901 901
902 902 # Fetch doesn't use cmdutil.bailifchanged so override it to add the check
903 903 def overridefetch(orig, ui, repo, *pats, **opts):
904 904 repo.lfstatus = True
905 905 modified, added, removed, deleted = repo.status()[:4]
906 906 repo.lfstatus = False
907 907 if modified or added or removed or deleted:
908 908 raise util.Abort(_('uncommitted changes'))
909 909 return orig(ui, repo, *pats, **opts)
910 910
911 911 def overrideforget(orig, ui, repo, *pats, **opts):
912 912 installnormalfilesmatchfn(repo[None].manifest())
913 913 result = orig(ui, repo, *pats, **opts)
914 914 restorematchfn()
915 915 m = scmutil.match(repo[None], pats, opts)
916 916
917 917 try:
918 918 repo.lfstatus = True
919 919 s = repo.status(match=m, clean=True)
920 920 finally:
921 921 repo.lfstatus = False
922 922 forget = sorted(s[0] + s[1] + s[3] + s[6])
923 923 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
924 924
925 925 for f in forget:
926 926 if lfutil.standin(f) not in repo.dirstate and not \
927 927 os.path.isdir(m.rel(lfutil.standin(f))):
928 928 ui.warn(_('not removing %s: file is already untracked\n')
929 929 % m.rel(f))
930 930 result = 1
931 931
932 932 for f in forget:
933 933 if ui.verbose or not m.exact(f):
934 934 ui.status(_('removing %s\n') % m.rel(f))
935 935
936 936 # Need to lock because standin files are deleted then removed from the
937 937 # repository and we could race in-between.
938 938 wlock = repo.wlock()
939 939 try:
940 940 lfdirstate = lfutil.openlfdirstate(ui, repo)
941 941 for f in forget:
942 942 if lfdirstate[f] == 'a':
943 943 lfdirstate.drop(f)
944 944 else:
945 945 lfdirstate.remove(f)
946 946 lfdirstate.write()
947 947 standins = [lfutil.standin(f) for f in forget]
948 948 for f in standins:
949 949 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
950 950 repo[None].forget(standins)
951 951 finally:
952 952 wlock.release()
953 953
954 954 return result
955 955
956 956 def outgoinghook(ui, repo, other, opts, missing):
957 957 if opts.pop('large', None):
958 958 toupload = set()
959 959 lfutil.getlfilestoupload(repo, missing,
960 960 lambda fn, lfhash: toupload.add(fn))
961 961 if not toupload:
962 962 ui.status(_('largefiles: no files to upload\n'))
963 963 else:
964 964 ui.status(_('largefiles to upload:\n'))
965 965 for file in sorted(toupload):
966 966 ui.status(lfutil.splitstandin(file) + '\n')
967 967 ui.status('\n')
968 968
969 969 def summaryremotehook(ui, repo, opts, changes):
970 970 largeopt = opts.get('large', False)
971 971 if changes is None:
972 972 if largeopt:
973 973 return (False, True) # only outgoing check is needed
974 974 else:
975 975 return (False, False)
976 976 elif largeopt:
977 977 url, branch, peer, outgoing = changes[1]
978 978 if peer is None:
979 979 # i18n: column positioning for "hg summary"
980 980 ui.status(_('largefiles: (no remote repo)\n'))
981 981 return
982 982
983 983 toupload = set()
984 984 lfutil.getlfilestoupload(repo, outgoing.missing,
985 985 lambda fn, lfhash: toupload.add(fn))
986 986 if not toupload:
987 987 # i18n: column positioning for "hg summary"
988 988 ui.status(_('largefiles: (no files to upload)\n'))
989 989 else:
990 990 # i18n: column positioning for "hg summary"
991 991 ui.status(_('largefiles: %d to upload\n') % len(toupload))
992 992
993 993 def overridesummary(orig, ui, repo, *pats, **opts):
994 994 try:
995 995 repo.lfstatus = True
996 996 orig(ui, repo, *pats, **opts)
997 997 finally:
998 998 repo.lfstatus = False
999 999
1000 1000 def scmutiladdremove(orig, repo, pats=[], opts={}, dry_run=None,
1001 1001 similarity=None):
1002 1002 if not lfutil.islfilesrepo(repo):
1003 1003 return orig(repo, pats, opts, dry_run, similarity)
1004 1004 # Get the list of missing largefiles so we can remove them
1005 1005 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1006 1006 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
1007 1007 False, False)
1008 1008 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
1009 1009
1010 1010 # Call into the normal remove code, but the removing of the standin, we want
1011 1011 # to have handled by original addremove. Monkey patching here makes sure
1012 1012 # we don't remove the standin in the largefiles code, preventing a very
1013 1013 # confused state later.
1014 1014 if missing:
1015 1015 m = [repo.wjoin(f) for f in missing]
1016 1016 repo._isaddremove = True
1017 1017 removelargefiles(repo.ui, repo, *m, **opts)
1018 1018 repo._isaddremove = False
1019 1019 # Call into the normal add code, and any files that *should* be added as
1020 1020 # largefiles will be
1021 1021 addlargefiles(repo.ui, repo, *pats, **opts)
1022 1022 # Now that we've handled largefiles, hand off to the original addremove
1023 1023 # function to take care of the rest. Make sure it doesn't do anything with
1024 1024 # largefiles by installing a matcher that will ignore them.
1025 1025 installnormalfilesmatchfn(repo[None].manifest())
1026 1026 result = orig(repo, pats, opts, dry_run, similarity)
1027 1027 restorematchfn()
1028 1028 return result
1029 1029
1030 1030 # Calling purge with --all will cause the largefiles to be deleted.
1031 1031 # Override repo.status to prevent this from happening.
1032 1032 def overridepurge(orig, ui, repo, *dirs, **opts):
1033 1033 # XXX large file status is buggy when used on repo proxy.
1034 1034 # XXX this needs to be investigate.
1035 1035 repo = repo.unfiltered()
1036 1036 oldstatus = repo.status
1037 1037 def overridestatus(node1='.', node2=None, match=None, ignored=False,
1038 1038 clean=False, unknown=False, listsubrepos=False):
1039 1039 r = oldstatus(node1, node2, match, ignored, clean, unknown,
1040 1040 listsubrepos)
1041 1041 lfdirstate = lfutil.openlfdirstate(ui, repo)
1042 1042 modified, added, removed, deleted, unknown, ignored, clean = r
1043 1043 unknown = [f for f in unknown if lfdirstate[f] == '?']
1044 1044 ignored = [f for f in ignored if lfdirstate[f] == '?']
1045 1045 return modified, added, removed, deleted, unknown, ignored, clean
1046 1046 repo.status = overridestatus
1047 1047 orig(ui, repo, *dirs, **opts)
1048 1048 repo.status = oldstatus
1049 1049
1050 1050 def overriderollback(orig, ui, repo, **opts):
1051 1051 result = orig(ui, repo, **opts)
1052 1052 merge.update(repo, node=None, branchmerge=False, force=True,
1053 1053 partial=lfutil.isstandin)
1054 1054 wlock = repo.wlock()
1055 1055 try:
1056 1056 lfdirstate = lfutil.openlfdirstate(ui, repo)
1057 1057 lfiles = lfutil.listlfiles(repo)
1058 1058 oldlfiles = lfutil.listlfiles(repo, repo[None].parents()[0].rev())
1059 1059 for file in lfiles:
1060 1060 if file in oldlfiles:
1061 1061 lfdirstate.normallookup(file)
1062 1062 else:
1063 1063 lfdirstate.add(file)
1064 1064 lfdirstate.write()
1065 1065 finally:
1066 1066 wlock.release()
1067 1067 return result
1068 1068
1069 1069 def overridetransplant(orig, ui, repo, *revs, **opts):
1070 1070 try:
1071 1071 oldstandins = lfutil.getstandinsstate(repo)
1072 1072 repo._istransplanting = True
1073 1073 result = orig(ui, repo, *revs, **opts)
1074 1074 newstandins = lfutil.getstandinsstate(repo)
1075 1075 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
1076 1076 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1077 1077 printmessage=True)
1078 1078 finally:
1079 1079 repo._istransplanting = False
1080 1080 return result
1081 1081
1082 1082 def overridecat(orig, ui, repo, file1, *pats, **opts):
1083 1083 ctx = scmutil.revsingle(repo, opts.get('rev'))
1084 1084 err = 1
1085 1085 notbad = set()
1086 1086 m = scmutil.match(ctx, (file1,) + pats, opts)
1087 1087 origmatchfn = m.matchfn
1088 1088 def lfmatchfn(f):
1089 1089 if origmatchfn(f):
1090 1090 return True
1091 1091 lf = lfutil.splitstandin(f)
1092 1092 if lf is None:
1093 1093 return False
1094 1094 notbad.add(lf)
1095 1095 return origmatchfn(lf)
1096 1096 m.matchfn = lfmatchfn
1097 1097 origbadfn = m.bad
1098 1098 def lfbadfn(f, msg):
1099 1099 if not f in notbad:
1100 1100 origbadfn(f, msg)
1101 1101 m.bad = lfbadfn
1102 1102 for f in ctx.walk(m):
1103 1103 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1104 1104 pathname=f)
1105 1105 lf = lfutil.splitstandin(f)
1106 1106 if lf is None or origmatchfn(f):
1107 1107 # duplicating unreachable code from commands.cat
1108 1108 data = ctx[f].data()
1109 1109 if opts.get('decode'):
1110 1110 data = repo.wwritedata(f, data)
1111 1111 fp.write(data)
1112 1112 else:
1113 1113 hash = lfutil.readstandin(repo, lf, ctx.rev())
1114 1114 if not lfutil.inusercache(repo.ui, hash):
1115 1115 store = basestore._openstore(repo)
1116 1116 success, missing = store.get([(lf, hash)])
1117 1117 if len(success) != 1:
1118 1118 raise util.Abort(
1119 1119 _('largefile %s is not in cache and could not be '
1120 1120 'downloaded') % lf)
1121 1121 path = lfutil.usercachepath(repo.ui, hash)
1122 1122 fpin = open(path, "rb")
1123 1123 for chunk in util.filechunkiter(fpin, 128 * 1024):
1124 1124 fp.write(chunk)
1125 1125 fpin.close()
1126 1126 fp.close()
1127 1127 err = 0
1128 1128 return err
1129 1129
1130 1130 def mercurialsinkbefore(orig, sink):
1131 1131 sink.repo._isconverting = True
1132 1132 orig(sink)
1133 1133
1134 1134 def mercurialsinkafter(orig, sink):
1135 1135 sink.repo._isconverting = False
1136 1136 orig(sink)
General Comments 0
You need to be logged in to leave comments. Login now