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. |
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 |
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 |
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 |
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() |
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 ) |