Mercurial > public > mercurial-scm > hg
comparison mercurial/sparse.py @ 43076:2372284d9457
formatting: blacken the codebase
This is using my patch to black
(https://github.com/psf/black/pull/826) so we don't un-wrap collection
literals.
Done with:
hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S
# skip-blame mass-reformatting only
# no-check-commit reformats foo_bar functions
Differential Revision: https://phab.mercurial-scm.org/D6971
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:45:02 -0400 |
parents | 87a34c767384 |
children | 687b865b95ad |
comparison
equal
deleted
inserted
replaced
43075:57875cf423c9 | 43076:2372284d9457 |
---|---|
28 # Whether sparse features are enabled. This variable is intended to be | 28 # Whether sparse features are enabled. This variable is intended to be |
29 # temporary to facilitate porting sparse to core. It should eventually be | 29 # temporary to facilitate porting sparse to core. It should eventually be |
30 # a per-repo option, possibly a repo requirement. | 30 # a per-repo option, possibly a repo requirement. |
31 enabled = False | 31 enabled = False |
32 | 32 |
33 | |
33 def parseconfig(ui, raw, action): | 34 def parseconfig(ui, raw, action): |
34 """Parse sparse config file content. | 35 """Parse sparse config file content. |
35 | 36 |
36 action is the command which is trigerring this read, can be narrow, sparse | 37 action is the command which is trigerring this read, can be narrow, sparse |
37 | 38 |
53 if line: | 54 if line: |
54 profiles.add(line) | 55 profiles.add(line) |
55 elif line == '[include]': | 56 elif line == '[include]': |
56 if havesection and current != includes: | 57 if havesection and current != includes: |
57 # TODO pass filename into this API so we can report it. | 58 # TODO pass filename into this API so we can report it. |
58 raise error.Abort(_('%(action)s config cannot have includes ' | 59 raise error.Abort( |
59 'after excludes') % {'action': action}) | 60 _( |
61 '%(action)s config cannot have includes ' | |
62 'after excludes' | |
63 ) | |
64 % {'action': action} | |
65 ) | |
60 havesection = True | 66 havesection = True |
61 current = includes | 67 current = includes |
62 continue | 68 continue |
63 elif line == '[exclude]': | 69 elif line == '[exclude]': |
64 havesection = True | 70 havesection = True |
65 current = excludes | 71 current = excludes |
66 elif line: | 72 elif line: |
67 if current is None: | 73 if current is None: |
68 raise error.Abort(_('%(action)s config entry outside of ' | 74 raise error.Abort( |
69 'section: %(line)s') | 75 _('%(action)s config entry outside of ' 'section: %(line)s') |
70 % {'action': action, 'line': line}, | 76 % {'action': action, 'line': line}, |
71 hint=_('add an [include] or [exclude] line ' | 77 hint=_( |
72 'to declare the entry type')) | 78 'add an [include] or [exclude] line ' |
79 'to declare the entry type' | |
80 ), | |
81 ) | |
73 | 82 |
74 if line.strip().startswith('/'): | 83 if line.strip().startswith('/'): |
75 ui.warn(_('warning: %(action)s profile cannot use' | 84 ui.warn( |
76 ' paths starting with /, ignoring %(line)s\n') | 85 _( |
77 % {'action': action, 'line': line}) | 86 'warning: %(action)s profile cannot use' |
87 ' paths starting with /, ignoring %(line)s\n' | |
88 ) | |
89 % {'action': action, 'line': line} | |
90 ) | |
78 continue | 91 continue |
79 current.add(line) | 92 current.add(line) |
80 | 93 |
81 return includes, excludes, profiles | 94 return includes, excludes, profiles |
95 | |
82 | 96 |
83 # Exists as separate function to facilitate monkeypatching. | 97 # Exists as separate function to facilitate monkeypatching. |
84 def readprofile(repo, profile, changeid): | 98 def readprofile(repo, profile, changeid): |
85 """Resolve the raw content of a sparse profile file.""" | 99 """Resolve the raw content of a sparse profile file.""" |
86 # TODO add some kind of cache here because this incurs a manifest | 100 # TODO add some kind of cache here because this incurs a manifest |
87 # resolve and can be slow. | 101 # resolve and can be slow. |
88 return repo.filectx(profile, changeid=changeid).data() | 102 return repo.filectx(profile, changeid=changeid).data() |
89 | 103 |
104 | |
90 def patternsforrev(repo, rev): | 105 def patternsforrev(repo, rev): |
91 """Obtain sparse checkout patterns for the given rev. | 106 """Obtain sparse checkout patterns for the given rev. |
92 | 107 |
93 Returns a tuple of iterables representing includes, excludes, and | 108 Returns a tuple of iterables representing includes, excludes, and |
94 patterns. | 109 patterns. |
100 raw = repo.vfs.tryread('sparse') | 115 raw = repo.vfs.tryread('sparse') |
101 if not raw: | 116 if not raw: |
102 return set(), set(), set() | 117 return set(), set(), set() |
103 | 118 |
104 if rev is None: | 119 if rev is None: |
105 raise error.Abort(_('cannot parse sparse patterns from working ' | 120 raise error.Abort( |
106 'directory')) | 121 _('cannot parse sparse patterns from working ' 'directory') |
122 ) | |
107 | 123 |
108 includes, excludes, profiles = parseconfig(repo.ui, raw, 'sparse') | 124 includes, excludes, profiles = parseconfig(repo.ui, raw, 'sparse') |
109 ctx = repo[rev] | 125 ctx = repo[rev] |
110 | 126 |
111 if profiles: | 127 if profiles: |
120 try: | 136 try: |
121 raw = readprofile(repo, profile, rev) | 137 raw = readprofile(repo, profile, rev) |
122 except error.ManifestLookupError: | 138 except error.ManifestLookupError: |
123 msg = ( | 139 msg = ( |
124 "warning: sparse profile '%s' not found " | 140 "warning: sparse profile '%s' not found " |
125 "in rev %s - ignoring it\n" % (profile, ctx)) | 141 "in rev %s - ignoring it\n" % (profile, ctx) |
142 ) | |
126 # experimental config: sparse.missingwarning | 143 # experimental config: sparse.missingwarning |
127 if repo.ui.configbool( | 144 if repo.ui.configbool('sparse', 'missingwarning'): |
128 'sparse', 'missingwarning'): | |
129 repo.ui.warn(msg) | 145 repo.ui.warn(msg) |
130 else: | 146 else: |
131 repo.ui.debug(msg) | 147 repo.ui.debug(msg) |
132 continue | 148 continue |
133 | 149 |
141 if includes: | 157 if includes: |
142 includes.add('.hg*') | 158 includes.add('.hg*') |
143 | 159 |
144 return includes, excludes, profiles | 160 return includes, excludes, profiles |
145 | 161 |
162 | |
146 def activeconfig(repo): | 163 def activeconfig(repo): |
147 """Determine the active sparse config rules. | 164 """Determine the active sparse config rules. |
148 | 165 |
149 Rules are constructed by reading the current sparse config and bringing in | 166 Rules are constructed by reading the current sparse config and bringing in |
150 referenced profiles from parents of the working directory. | 167 referenced profiles from parents of the working directory. |
151 """ | 168 """ |
152 revs = [repo.changelog.rev(node) for node in | 169 revs = [ |
153 repo.dirstate.parents() if node != nullid] | 170 repo.changelog.rev(node) |
171 for node in repo.dirstate.parents() | |
172 if node != nullid | |
173 ] | |
154 | 174 |
155 allincludes = set() | 175 allincludes = set() |
156 allexcludes = set() | 176 allexcludes = set() |
157 allprofiles = set() | 177 allprofiles = set() |
158 | 178 |
162 allexcludes |= excludes | 182 allexcludes |= excludes |
163 allprofiles |= profiles | 183 allprofiles |= profiles |
164 | 184 |
165 return allincludes, allexcludes, allprofiles | 185 return allincludes, allexcludes, allprofiles |
166 | 186 |
187 | |
167 def configsignature(repo, includetemp=True): | 188 def configsignature(repo, includetemp=True): |
168 """Obtain the signature string for the current sparse configuration. | 189 """Obtain the signature string for the current sparse configuration. |
169 | 190 |
170 This is used to construct a cache key for matchers. | 191 This is used to construct a cache key for matchers. |
171 """ | 192 """ |
186 raw = repo.vfs.tryread('tempsparse') | 207 raw = repo.vfs.tryread('tempsparse') |
187 tempsignature = hex(hashlib.sha1(raw).digest()) | 208 tempsignature = hex(hashlib.sha1(raw).digest()) |
188 cache['tempsignature'] = tempsignature | 209 cache['tempsignature'] = tempsignature |
189 | 210 |
190 return '%s %s' % (signature, tempsignature) | 211 return '%s %s' % (signature, tempsignature) |
212 | |
191 | 213 |
192 def writeconfig(repo, includes, excludes, profiles): | 214 def writeconfig(repo, includes, excludes, profiles): |
193 """Write the sparse config file given a sparse configuration.""" | 215 """Write the sparse config file given a sparse configuration.""" |
194 with repo.vfs('sparse', 'wb') as fh: | 216 with repo.vfs('sparse', 'wb') as fh: |
195 for p in sorted(profiles): | 217 for p in sorted(profiles): |
207 fh.write(e) | 229 fh.write(e) |
208 fh.write('\n') | 230 fh.write('\n') |
209 | 231 |
210 repo._sparsesignaturecache.clear() | 232 repo._sparsesignaturecache.clear() |
211 | 233 |
234 | |
212 def readtemporaryincludes(repo): | 235 def readtemporaryincludes(repo): |
213 raw = repo.vfs.tryread('tempsparse') | 236 raw = repo.vfs.tryread('tempsparse') |
214 if not raw: | 237 if not raw: |
215 return set() | 238 return set() |
216 | 239 |
217 return set(raw.split('\n')) | 240 return set(raw.split('\n')) |
218 | 241 |
242 | |
219 def writetemporaryincludes(repo, includes): | 243 def writetemporaryincludes(repo, includes): |
220 repo.vfs.write('tempsparse', '\n'.join(sorted(includes))) | 244 repo.vfs.write('tempsparse', '\n'.join(sorted(includes))) |
221 repo._sparsesignaturecache.clear() | 245 repo._sparsesignaturecache.clear() |
246 | |
222 | 247 |
223 def addtemporaryincludes(repo, additional): | 248 def addtemporaryincludes(repo, additional): |
224 includes = readtemporaryincludes(repo) | 249 includes = readtemporaryincludes(repo) |
225 for i in additional: | 250 for i in additional: |
226 includes.add(i) | 251 includes.add(i) |
227 writetemporaryincludes(repo, includes) | 252 writetemporaryincludes(repo, includes) |
253 | |
228 | 254 |
229 def prunetemporaryincludes(repo): | 255 def prunetemporaryincludes(repo): |
230 if not enabled or not repo.vfs.exists('tempsparse'): | 256 if not enabled or not repo.vfs.exists('tempsparse'): |
231 return | 257 return |
232 | 258 |
246 actions.append((file, None, message)) | 272 actions.append((file, None, message)) |
247 dropped.append(file) | 273 dropped.append(file) |
248 | 274 |
249 typeactions = mergemod.emptyactions() | 275 typeactions = mergemod.emptyactions() |
250 typeactions['r'] = actions | 276 typeactions['r'] = actions |
251 mergemod.applyupdates(repo, typeactions, repo[None], repo['.'], False, | 277 mergemod.applyupdates( |
252 wantfiledata=False) | 278 repo, typeactions, repo[None], repo['.'], False, wantfiledata=False |
279 ) | |
253 | 280 |
254 # Fix dirstate | 281 # Fix dirstate |
255 for file in dropped: | 282 for file in dropped: |
256 dirstate.drop(file) | 283 dirstate.drop(file) |
257 | 284 |
258 repo.vfs.unlink('tempsparse') | 285 repo.vfs.unlink('tempsparse') |
259 repo._sparsesignaturecache.clear() | 286 repo._sparsesignaturecache.clear() |
260 msg = _('cleaned up %d temporarily added file(s) from the ' | 287 msg = _( |
261 'sparse checkout\n') | 288 'cleaned up %d temporarily added file(s) from the ' 'sparse checkout\n' |
289 ) | |
262 repo.ui.status(msg % len(tempincludes)) | 290 repo.ui.status(msg % len(tempincludes)) |
291 | |
263 | 292 |
264 def forceincludematcher(matcher, includes): | 293 def forceincludematcher(matcher, includes): |
265 """Returns a matcher that returns true for any of the forced includes | 294 """Returns a matcher that returns true for any of the forced includes |
266 before testing against the actual matcher.""" | 295 before testing against the actual matcher.""" |
267 kindpats = [('path', include, '') for include in includes] | 296 kindpats = [('path', include, '') for include in includes] |
268 includematcher = matchmod.includematcher('', kindpats) | 297 includematcher = matchmod.includematcher('', kindpats) |
269 return matchmod.unionmatcher([includematcher, matcher]) | 298 return matchmod.unionmatcher([includematcher, matcher]) |
270 | 299 |
300 | |
271 def matcher(repo, revs=None, includetemp=True): | 301 def matcher(repo, revs=None, includetemp=True): |
272 """Obtain a matcher for sparse working directories for the given revs. | 302 """Obtain a matcher for sparse working directories for the given revs. |
273 | 303 |
274 If multiple revisions are specified, the matcher is the union of all | 304 If multiple revisions are specified, the matcher is the union of all |
275 revs. | 305 revs. |
279 # If sparse isn't enabled, sparse matcher matches everything. | 309 # If sparse isn't enabled, sparse matcher matches everything. |
280 if not enabled: | 310 if not enabled: |
281 return matchmod.always() | 311 return matchmod.always() |
282 | 312 |
283 if not revs or revs == [None]: | 313 if not revs or revs == [None]: |
284 revs = [repo.changelog.rev(node) | 314 revs = [ |
285 for node in repo.dirstate.parents() if node != nullid] | 315 repo.changelog.rev(node) |
316 for node in repo.dirstate.parents() | |
317 if node != nullid | |
318 ] | |
286 | 319 |
287 signature = configsignature(repo, includetemp=includetemp) | 320 signature = configsignature(repo, includetemp=includetemp) |
288 | 321 |
289 key = '%s %s' % (signature, ' '.join(map(pycompat.bytestr, revs))) | 322 key = '%s %s' % (signature, ' '.join(map(pycompat.bytestr, revs))) |
290 | 323 |
296 for rev in revs: | 329 for rev in revs: |
297 try: | 330 try: |
298 includes, excludes, profiles = patternsforrev(repo, rev) | 331 includes, excludes, profiles = patternsforrev(repo, rev) |
299 | 332 |
300 if includes or excludes: | 333 if includes or excludes: |
301 matcher = matchmod.match(repo.root, '', [], | 334 matcher = matchmod.match( |
302 include=includes, exclude=excludes, | 335 repo.root, |
303 default='relpath') | 336 '', |
337 [], | |
338 include=includes, | |
339 exclude=excludes, | |
340 default='relpath', | |
341 ) | |
304 matchers.append(matcher) | 342 matchers.append(matcher) |
305 except IOError: | 343 except IOError: |
306 pass | 344 pass |
307 | 345 |
308 if not matchers: | 346 if not matchers: |
317 result = forceincludematcher(result, tempincludes) | 355 result = forceincludematcher(result, tempincludes) |
318 | 356 |
319 repo._sparsematchercache[key] = result | 357 repo._sparsematchercache[key] = result |
320 | 358 |
321 return result | 359 return result |
360 | |
322 | 361 |
323 def filterupdatesactions(repo, wctx, mctx, branchmerge, actions): | 362 def filterupdatesactions(repo, wctx, mctx, branchmerge, actions): |
324 """Filter updates to only lay out files that match the sparse rules.""" | 363 """Filter updates to only lay out files that match the sparse rules.""" |
325 if not enabled: | 364 if not enabled: |
326 return actions | 365 return actions |
365 f1, f2, fa, move, anc = args | 404 f1, f2, fa, move, anc = args |
366 if not sparsematch(f1): | 405 if not sparsematch(f1): |
367 temporaryfiles.append(f1) | 406 temporaryfiles.append(f1) |
368 | 407 |
369 if len(temporaryfiles) > 0: | 408 if len(temporaryfiles) > 0: |
370 repo.ui.status(_('temporarily included %d file(s) in the sparse ' | 409 repo.ui.status( |
371 'checkout for merging\n') % len(temporaryfiles)) | 410 _( |
411 'temporarily included %d file(s) in the sparse ' | |
412 'checkout for merging\n' | |
413 ) | |
414 % len(temporaryfiles) | |
415 ) | |
372 addtemporaryincludes(repo, temporaryfiles) | 416 addtemporaryincludes(repo, temporaryfiles) |
373 | 417 |
374 # Add the new files to the working copy so they can be merged, etc | 418 # Add the new files to the working copy so they can be merged, etc |
375 actions = [] | 419 actions = [] |
376 message = 'temporarily adding to sparse checkout' | 420 message = 'temporarily adding to sparse checkout' |
380 fctx = repo[None][file] | 424 fctx = repo[None][file] |
381 actions.append((file, (fctx.flags(), False), message)) | 425 actions.append((file, (fctx.flags(), False), message)) |
382 | 426 |
383 typeactions = mergemod.emptyactions() | 427 typeactions = mergemod.emptyactions() |
384 typeactions['g'] = actions | 428 typeactions['g'] = actions |
385 mergemod.applyupdates(repo, typeactions, repo[None], repo['.'], | 429 mergemod.applyupdates( |
386 False, wantfiledata=False) | 430 repo, typeactions, repo[None], repo['.'], False, wantfiledata=False |
431 ) | |
387 | 432 |
388 dirstate = repo.dirstate | 433 dirstate = repo.dirstate |
389 for file, flags, msg in actions: | 434 for file, flags, msg in actions: |
390 dirstate.normal(file) | 435 dirstate.normal(file) |
391 | 436 |
405 elif old and not new: | 450 elif old and not new: |
406 prunedactions[file] = ('r', [], '') | 451 prunedactions[file] = ('r', [], '') |
407 | 452 |
408 return prunedactions | 453 return prunedactions |
409 | 454 |
455 | |
410 def refreshwdir(repo, origstatus, origsparsematch, force=False): | 456 def refreshwdir(repo, origstatus, origsparsematch, force=False): |
411 """Refreshes working directory by taking sparse config into account. | 457 """Refreshes working directory by taking sparse config into account. |
412 | 458 |
413 The old status and sparse matcher is compared against the current sparse | 459 The old status and sparse matcher is compared against the current sparse |
414 matcher. | 460 matcher. |
428 if not sparsematch(f): | 474 if not sparsematch(f): |
429 repo.ui.warn(_("pending changes to '%s'\n") % f) | 475 repo.ui.warn(_("pending changes to '%s'\n") % f) |
430 abort = not force | 476 abort = not force |
431 | 477 |
432 if abort: | 478 if abort: |
433 raise error.Abort(_('could not update sparseness due to pending ' | 479 raise error.Abort( |
434 'changes')) | 480 _('could not update sparseness due to pending ' 'changes') |
481 ) | |
435 | 482 |
436 # Calculate actions | 483 # Calculate actions |
437 dirstate = repo.dirstate | 484 dirstate = repo.dirstate |
438 ctx = repo['.'] | 485 ctx = repo['.'] |
439 added = [] | 486 added = [] |
468 abort = False | 515 abort = False |
469 for file in lookup: | 516 for file in lookup: |
470 repo.ui.warn(_("pending changes to '%s'\n") % file) | 517 repo.ui.warn(_("pending changes to '%s'\n") % file) |
471 abort = not force | 518 abort = not force |
472 if abort: | 519 if abort: |
473 raise error.Abort(_('cannot change sparseness due to pending ' | 520 raise error.Abort( |
474 'changes (delete the files or use ' | 521 _( |
475 '--force to bring them back dirty)')) | 522 'cannot change sparseness due to pending ' |
523 'changes (delete the files or use ' | |
524 '--force to bring them back dirty)' | |
525 ) | |
526 ) | |
476 | 527 |
477 # Check for files that were only in the dirstate. | 528 # Check for files that were only in the dirstate. |
478 for file, state in dirstate.iteritems(): | 529 for file, state in dirstate.iteritems(): |
479 if not file in files: | 530 if not file in files: |
480 old = origsparsematch(file) | 531 old = origsparsematch(file) |
485 # Apply changes to disk | 536 # Apply changes to disk |
486 typeactions = mergemod.emptyactions() | 537 typeactions = mergemod.emptyactions() |
487 for f, (m, args, msg) in actions.iteritems(): | 538 for f, (m, args, msg) in actions.iteritems(): |
488 typeactions[m].append((f, args, msg)) | 539 typeactions[m].append((f, args, msg)) |
489 | 540 |
490 mergemod.applyupdates(repo, typeactions, repo[None], repo['.'], False, | 541 mergemod.applyupdates( |
491 wantfiledata=False) | 542 repo, typeactions, repo[None], repo['.'], False, wantfiledata=False |
543 ) | |
492 | 544 |
493 # Fix dirstate | 545 # Fix dirstate |
494 for file in added: | 546 for file in added: |
495 dirstate.normal(file) | 547 dirstate.normal(file) |
496 | 548 |
500 for file in lookup: | 552 for file in lookup: |
501 # File exists on disk, and we're bringing it back in an unknown state. | 553 # File exists on disk, and we're bringing it back in an unknown state. |
502 dirstate.normallookup(file) | 554 dirstate.normallookup(file) |
503 | 555 |
504 return added, dropped, lookup | 556 return added, dropped, lookup |
557 | |
505 | 558 |
506 def aftercommit(repo, node): | 559 def aftercommit(repo, node): |
507 """Perform actions after a working directory commit.""" | 560 """Perform actions after a working directory commit.""" |
508 # This function is called unconditionally, even if sparse isn't | 561 # This function is called unconditionally, even if sparse isn't |
509 # enabled. | 562 # enabled. |
517 origsparsematch = matcher(repo) | 570 origsparsematch = matcher(repo) |
518 refreshwdir(repo, origstatus, origsparsematch, force=True) | 571 refreshwdir(repo, origstatus, origsparsematch, force=True) |
519 | 572 |
520 prunetemporaryincludes(repo) | 573 prunetemporaryincludes(repo) |
521 | 574 |
522 def _updateconfigandrefreshwdir(repo, includes, excludes, profiles, | 575 |
523 force=False, removing=False): | 576 def _updateconfigandrefreshwdir( |
577 repo, includes, excludes, profiles, force=False, removing=False | |
578 ): | |
524 """Update the sparse config and working directory state.""" | 579 """Update the sparse config and working directory state.""" |
525 raw = repo.vfs.tryread('sparse') | 580 raw = repo.vfs.tryread('sparse') |
526 oldincludes, oldexcludes, oldprofiles = parseconfig(repo.ui, raw, 'sparse') | 581 oldincludes, oldexcludes, oldprofiles = parseconfig(repo.ui, raw, 'sparse') |
527 | 582 |
528 oldstatus = repo.status() | 583 oldstatus = repo.status() |
553 repo.requirements |= oldrequires | 608 repo.requirements |= oldrequires |
554 scmutil.writerequires(repo.vfs, repo.requirements) | 609 scmutil.writerequires(repo.vfs, repo.requirements) |
555 writeconfig(repo, oldincludes, oldexcludes, oldprofiles) | 610 writeconfig(repo, oldincludes, oldexcludes, oldprofiles) |
556 raise | 611 raise |
557 | 612 |
613 | |
558 def clearrules(repo, force=False): | 614 def clearrules(repo, force=False): |
559 """Clears include/exclude rules from the sparse config. | 615 """Clears include/exclude rules from the sparse config. |
560 | 616 |
561 The remaining sparse config only has profiles, if defined. The working | 617 The remaining sparse config only has profiles, if defined. The working |
562 directory is refreshed, as needed. | 618 directory is refreshed, as needed. |
567 | 623 |
568 if not includes and not excludes: | 624 if not includes and not excludes: |
569 return | 625 return |
570 | 626 |
571 _updateconfigandrefreshwdir(repo, set(), set(), profiles, force=force) | 627 _updateconfigandrefreshwdir(repo, set(), set(), profiles, force=force) |
628 | |
572 | 629 |
573 def importfromfiles(repo, opts, paths, force=False): | 630 def importfromfiles(repo, opts, paths, force=False): |
574 """Import sparse config rules from files. | 631 """Import sparse config rules from files. |
575 | 632 |
576 The updated sparse config is written out and the working directory | 633 The updated sparse config is written out and the working directory |
587 changed = False | 644 changed = False |
588 for p in paths: | 645 for p in paths: |
589 with util.posixfile(util.expandpath(p), mode='rb') as fh: | 646 with util.posixfile(util.expandpath(p), mode='rb') as fh: |
590 raw = fh.read() | 647 raw = fh.read() |
591 | 648 |
592 iincludes, iexcludes, iprofiles = parseconfig(repo.ui, raw, | 649 iincludes, iexcludes, iprofiles = parseconfig( |
593 'sparse') | 650 repo.ui, raw, 'sparse' |
651 ) | |
594 oldsize = len(includes) + len(excludes) + len(profiles) | 652 oldsize = len(includes) + len(excludes) + len(profiles) |
595 includes.update(iincludes - aincludes) | 653 includes.update(iincludes - aincludes) |
596 excludes.update(iexcludes - aexcludes) | 654 excludes.update(iexcludes - aexcludes) |
597 profiles.update(iprofiles - aprofiles) | 655 profiles.update(iprofiles - aprofiles) |
598 if len(includes) + len(excludes) + len(profiles) > oldsize: | 656 if len(includes) + len(excludes) + len(profiles) > oldsize: |
604 if changed: | 662 if changed: |
605 profilecount = len(profiles - aprofiles) | 663 profilecount = len(profiles - aprofiles) |
606 includecount = len(includes - aincludes) | 664 includecount = len(includes - aincludes) |
607 excludecount = len(excludes - aexcludes) | 665 excludecount = len(excludes - aexcludes) |
608 | 666 |
609 fcounts = map(len, _updateconfigandrefreshwdir( | 667 fcounts = map( |
610 repo, includes, excludes, profiles, force=force)) | 668 len, |
611 | 669 _updateconfigandrefreshwdir( |
612 printchanges(repo.ui, opts, profilecount, includecount, excludecount, | 670 repo, includes, excludes, profiles, force=force |
613 *fcounts) | 671 ), |
614 | 672 ) |
615 def updateconfig(repo, pats, opts, include=False, exclude=False, reset=False, | 673 |
616 delete=False, enableprofile=False, disableprofile=False, | 674 printchanges( |
617 force=False, usereporootpaths=False): | 675 repo.ui, opts, profilecount, includecount, excludecount, *fcounts |
676 ) | |
677 | |
678 | |
679 def updateconfig( | |
680 repo, | |
681 pats, | |
682 opts, | |
683 include=False, | |
684 exclude=False, | |
685 reset=False, | |
686 delete=False, | |
687 enableprofile=False, | |
688 disableprofile=False, | |
689 force=False, | |
690 usereporootpaths=False, | |
691 ): | |
618 """Perform a sparse config update. | 692 """Perform a sparse config update. |
619 | 693 |
620 Only one of the actions may be performed. | 694 Only one of the actions may be performed. |
621 | 695 |
622 The new config is written out and a working directory refresh is performed. | 696 The new config is written out and a working directory refresh is performed. |
623 """ | 697 """ |
624 with repo.wlock(): | 698 with repo.wlock(): |
625 raw = repo.vfs.tryread('sparse') | 699 raw = repo.vfs.tryread('sparse') |
626 oldinclude, oldexclude, oldprofiles = parseconfig(repo.ui, raw, | 700 oldinclude, oldexclude, oldprofiles = parseconfig( |
627 'sparse') | 701 repo.ui, raw, 'sparse' |
702 ) | |
628 | 703 |
629 if reset: | 704 if reset: |
630 newinclude = set() | 705 newinclude = set() |
631 newexclude = set() | 706 newexclude = set() |
632 newprofiles = set() | 707 newprofiles = set() |
643 root, cwd = repo.root, repo.getcwd() | 718 root, cwd = repo.root, repo.getcwd() |
644 abspats = [] | 719 abspats = [] |
645 for kindpat in pats: | 720 for kindpat in pats: |
646 kind, pat = matchmod._patsplit(kindpat, None) | 721 kind, pat = matchmod._patsplit(kindpat, None) |
647 if kind in matchmod.cwdrelativepatternkinds or kind is None: | 722 if kind in matchmod.cwdrelativepatternkinds or kind is None: |
648 ap = ((kind + ':' if kind else '') + | 723 ap = (kind + ':' if kind else '') + pathutil.canonpath( |
649 pathutil.canonpath(root, cwd, pat)) | 724 root, cwd, pat |
725 ) | |
650 abspats.append(ap) | 726 abspats.append(ap) |
651 else: | 727 else: |
652 abspats.append(kindpat) | 728 abspats.append(kindpat) |
653 pats = abspats | 729 pats = abspats |
654 | 730 |
662 newprofiles.difference_update(pats) | 738 newprofiles.difference_update(pats) |
663 elif delete: | 739 elif delete: |
664 newinclude.difference_update(pats) | 740 newinclude.difference_update(pats) |
665 newexclude.difference_update(pats) | 741 newexclude.difference_update(pats) |
666 | 742 |
667 profilecount = (len(newprofiles - oldprofiles) - | 743 profilecount = len(newprofiles - oldprofiles) - len( |
668 len(oldprofiles - newprofiles)) | 744 oldprofiles - newprofiles |
669 includecount = (len(newinclude - oldinclude) - | 745 ) |
670 len(oldinclude - newinclude)) | 746 includecount = len(newinclude - oldinclude) - len( |
671 excludecount = (len(newexclude - oldexclude) - | 747 oldinclude - newinclude |
672 len(oldexclude - newexclude)) | 748 ) |
673 | 749 excludecount = len(newexclude - oldexclude) - len( |
674 fcounts = map(len, _updateconfigandrefreshwdir( | 750 oldexclude - newexclude |
675 repo, newinclude, newexclude, newprofiles, force=force, | 751 ) |
676 removing=reset)) | 752 |
677 | 753 fcounts = map( |
678 printchanges(repo.ui, opts, profilecount, includecount, | 754 len, |
679 excludecount, *fcounts) | 755 _updateconfigandrefreshwdir( |
680 | 756 repo, |
681 def printchanges(ui, opts, profilecount=0, includecount=0, excludecount=0, | 757 newinclude, |
682 added=0, dropped=0, conflicting=0): | 758 newexclude, |
759 newprofiles, | |
760 force=force, | |
761 removing=reset, | |
762 ), | |
763 ) | |
764 | |
765 printchanges( | |
766 repo.ui, opts, profilecount, includecount, excludecount, *fcounts | |
767 ) | |
768 | |
769 | |
770 def printchanges( | |
771 ui, | |
772 opts, | |
773 profilecount=0, | |
774 includecount=0, | |
775 excludecount=0, | |
776 added=0, | |
777 dropped=0, | |
778 conflicting=0, | |
779 ): | |
683 """Print output summarizing sparse config changes.""" | 780 """Print output summarizing sparse config changes.""" |
684 with ui.formatter('sparse', opts) as fm: | 781 with ui.formatter('sparse', opts) as fm: |
685 fm.startitem() | 782 fm.startitem() |
686 fm.condwrite(ui.verbose, 'profiles_added', _('Profiles changed: %d\n'), | 783 fm.condwrite( |
687 profilecount) | 784 ui.verbose, |
688 fm.condwrite(ui.verbose, 'include_rules_added', | 785 'profiles_added', |
689 _('Include rules changed: %d\n'), includecount) | 786 _('Profiles changed: %d\n'), |
690 fm.condwrite(ui.verbose, 'exclude_rules_added', | 787 profilecount, |
691 _('Exclude rules changed: %d\n'), excludecount) | 788 ) |
789 fm.condwrite( | |
790 ui.verbose, | |
791 'include_rules_added', | |
792 _('Include rules changed: %d\n'), | |
793 includecount, | |
794 ) | |
795 fm.condwrite( | |
796 ui.verbose, | |
797 'exclude_rules_added', | |
798 _('Exclude rules changed: %d\n'), | |
799 excludecount, | |
800 ) | |
692 | 801 |
693 # In 'plain' verbose mode, mergemod.applyupdates already outputs what | 802 # In 'plain' verbose mode, mergemod.applyupdates already outputs what |
694 # files are added or removed outside of the templating formatter | 803 # files are added or removed outside of the templating formatter |
695 # framework. No point in repeating ourselves in that case. | 804 # framework. No point in repeating ourselves in that case. |
696 if not fm.isplain(): | 805 if not fm.isplain(): |
697 fm.condwrite(ui.verbose, 'files_added', _('Files added: %d\n'), | 806 fm.condwrite( |
698 added) | 807 ui.verbose, 'files_added', _('Files added: %d\n'), added |
699 fm.condwrite(ui.verbose, 'files_dropped', _('Files dropped: %d\n'), | 808 ) |
700 dropped) | 809 fm.condwrite( |
701 fm.condwrite(ui.verbose, 'files_conflicting', | 810 ui.verbose, 'files_dropped', _('Files dropped: %d\n'), dropped |
702 _('Files conflicting: %d\n'), conflicting) | 811 ) |
812 fm.condwrite( | |
813 ui.verbose, | |
814 'files_conflicting', | |
815 _('Files conflicting: %d\n'), | |
816 conflicting, | |
817 ) |