comparison hgext/narrow/narrowcommands.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 40f78072fda9
children 687b865b95ad
comparison
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
28 repoview, 28 repoview,
29 sparse, 29 sparse,
30 util, 30 util,
31 wireprototypes, 31 wireprototypes,
32 ) 32 )
33 from mercurial.interfaces import ( 33 from mercurial.interfaces import repository
34 repository,
35 )
36 34
37 table = {} 35 table = {}
38 command = registrar.command(table) 36 command = registrar.command(table)
39 37
38
40 def setup(): 39 def setup():
41 """Wraps user-facing mercurial commands with narrow-aware versions.""" 40 """Wraps user-facing mercurial commands with narrow-aware versions."""
42 41
43 entry = extensions.wrapcommand(commands.table, 'clone', clonenarrowcmd) 42 entry = extensions.wrapcommand(commands.table, 'clone', clonenarrowcmd)
44 entry[1].append(('', 'narrow', None, 43 entry[1].append(
45 _("create a narrow clone of select files"))) 44 ('', 'narrow', None, _("create a narrow clone of select files"))
46 entry[1].append(('', 'depth', '', 45 )
47 _("limit the history fetched by distance from heads"))) 46 entry[1].append(
48 entry[1].append(('', 'narrowspec', '', 47 ('', 'depth', '', _("limit the history fetched by distance from heads"))
49 _("read narrowspecs from file"))) 48 )
49 entry[1].append(('', 'narrowspec', '', _("read narrowspecs from file")))
50 # TODO(durin42): unify sparse/narrow --include/--exclude logic a bit 50 # TODO(durin42): unify sparse/narrow --include/--exclude logic a bit
51 if 'sparse' not in extensions.enabled(): 51 if 'sparse' not in extensions.enabled():
52 entry[1].append(('', 'include', [],
53 _("specifically fetch this file/directory")))
54 entry[1].append( 52 entry[1].append(
55 ('', 'exclude', [], 53 ('', 'include', [], _("specifically fetch this file/directory"))
56 _("do not fetch this file/directory, even if included"))) 54 )
55 entry[1].append(
56 (
57 '',
58 'exclude',
59 [],
60 _("do not fetch this file/directory, even if included"),
61 )
62 )
57 63
58 entry = extensions.wrapcommand(commands.table, 'pull', pullnarrowcmd) 64 entry = extensions.wrapcommand(commands.table, 'pull', pullnarrowcmd)
59 entry[1].append(('', 'depth', '', 65 entry[1].append(
60 _("limit the history fetched by distance from heads"))) 66 ('', 'depth', '', _("limit the history fetched by distance from heads"))
67 )
61 68
62 extensions.wrapcommand(commands.table, 'archive', archivenarrowcmd) 69 extensions.wrapcommand(commands.table, 'archive', archivenarrowcmd)
70
63 71
64 def clonenarrowcmd(orig, ui, repo, *args, **opts): 72 def clonenarrowcmd(orig, ui, repo, *args, **opts):
65 """Wraps clone command, so 'hg clone' first wraps localrepo.clone().""" 73 """Wraps clone command, so 'hg clone' first wraps localrepo.clone()."""
66 opts = pycompat.byteskwargs(opts) 74 opts = pycompat.byteskwargs(opts)
67 wrappedextraprepare = util.nullcontextmanager() 75 wrappedextraprepare = util.nullcontextmanager()
71 filepath = os.path.join(encoding.getcwd(), narrowspecfile) 79 filepath = os.path.join(encoding.getcwd(), narrowspecfile)
72 ui.status(_("reading narrowspec from '%s'\n") % filepath) 80 ui.status(_("reading narrowspec from '%s'\n") % filepath)
73 try: 81 try:
74 fdata = util.readfile(filepath) 82 fdata = util.readfile(filepath)
75 except IOError as inst: 83 except IOError as inst:
76 raise error.Abort(_("cannot read narrowspecs from '%s': %s") % 84 raise error.Abort(
77 (filepath, encoding.strtolocal(inst.strerror))) 85 _("cannot read narrowspecs from '%s': %s")
86 % (filepath, encoding.strtolocal(inst.strerror))
87 )
78 88
79 includes, excludes, profiles = sparse.parseconfig(ui, fdata, 'narrow') 89 includes, excludes, profiles = sparse.parseconfig(ui, fdata, 'narrow')
80 if profiles: 90 if profiles:
81 raise error.Abort(_("cannot specify other files using '%include' in" 91 raise error.Abort(
82 " narrowspec")) 92 _(
93 "cannot specify other files using '%include' in"
94 " narrowspec"
95 )
96 )
83 97
84 narrowspec.validatepatterns(includes) 98 narrowspec.validatepatterns(includes)
85 narrowspec.validatepatterns(excludes) 99 narrowspec.validatepatterns(excludes)
86 100
87 # narrowspec is passed so we should assume that user wants narrow clone 101 # narrowspec is passed so we should assume that user wants narrow clone
88 opts['narrow'] = True 102 opts['narrow'] = True
89 opts['include'].extend(includes) 103 opts['include'].extend(includes)
90 opts['exclude'].extend(excludes) 104 opts['exclude'].extend(excludes)
91 105
92 if opts['narrow']: 106 if opts['narrow']:
107
93 def pullbundle2extraprepare_widen(orig, pullop, kwargs): 108 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
94 orig(pullop, kwargs) 109 orig(pullop, kwargs)
95 110
96 if opts.get('depth'): 111 if opts.get('depth'):
97 kwargs['depth'] = opts['depth'] 112 kwargs['depth'] = opts['depth']
98 wrappedextraprepare = extensions.wrappedfunction(exchange, 113
99 '_pullbundle2extraprepare', pullbundle2extraprepare_widen) 114 wrappedextraprepare = extensions.wrappedfunction(
115 exchange, '_pullbundle2extraprepare', pullbundle2extraprepare_widen
116 )
100 117
101 with wrappedextraprepare: 118 with wrappedextraprepare:
102 return orig(ui, repo, *args, **pycompat.strkwargs(opts)) 119 return orig(ui, repo, *args, **pycompat.strkwargs(opts))
120
103 121
104 def pullnarrowcmd(orig, ui, repo, *args, **opts): 122 def pullnarrowcmd(orig, ui, repo, *args, **opts):
105 """Wraps pull command to allow modifying narrow spec.""" 123 """Wraps pull command to allow modifying narrow spec."""
106 wrappedextraprepare = util.nullcontextmanager() 124 wrappedextraprepare = util.nullcontextmanager()
107 if repository.NARROW_REQUIREMENT in repo.requirements: 125 if repository.NARROW_REQUIREMENT in repo.requirements:
108 126
109 def pullbundle2extraprepare_widen(orig, pullop, kwargs): 127 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
110 orig(pullop, kwargs) 128 orig(pullop, kwargs)
111 if opts.get(r'depth'): 129 if opts.get(r'depth'):
112 kwargs['depth'] = opts[r'depth'] 130 kwargs['depth'] = opts[r'depth']
113 wrappedextraprepare = extensions.wrappedfunction(exchange, 131
114 '_pullbundle2extraprepare', pullbundle2extraprepare_widen) 132 wrappedextraprepare = extensions.wrappedfunction(
133 exchange, '_pullbundle2extraprepare', pullbundle2extraprepare_widen
134 )
115 135
116 with wrappedextraprepare: 136 with wrappedextraprepare:
117 return orig(ui, repo, *args, **opts) 137 return orig(ui, repo, *args, **opts)
138
118 139
119 def archivenarrowcmd(orig, ui, repo, *args, **opts): 140 def archivenarrowcmd(orig, ui, repo, *args, **opts):
120 """Wraps archive command to narrow the default includes.""" 141 """Wraps archive command to narrow the default includes."""
121 if repository.NARROW_REQUIREMENT in repo.requirements: 142 if repository.NARROW_REQUIREMENT in repo.requirements:
122 repo_includes, repo_excludes = repo.narrowpats 143 repo_includes, repo_excludes = repo.narrowpats
123 includes = set(opts.get(r'include', [])) 144 includes = set(opts.get(r'include', []))
124 excludes = set(opts.get(r'exclude', [])) 145 excludes = set(opts.get(r'exclude', []))
125 includes, excludes, unused_invalid = narrowspec.restrictpatterns( 146 includes, excludes, unused_invalid = narrowspec.restrictpatterns(
126 includes, excludes, repo_includes, repo_excludes) 147 includes, excludes, repo_includes, repo_excludes
148 )
127 if includes: 149 if includes:
128 opts[r'include'] = includes 150 opts[r'include'] = includes
129 if excludes: 151 if excludes:
130 opts[r'exclude'] = excludes 152 opts[r'exclude'] = excludes
131 return orig(ui, repo, *args, **opts) 153 return orig(ui, repo, *args, **opts)
154
132 155
133 def pullbundle2extraprepare(orig, pullop, kwargs): 156 def pullbundle2extraprepare(orig, pullop, kwargs):
134 repo = pullop.repo 157 repo = pullop.repo
135 if repository.NARROW_REQUIREMENT not in repo.requirements: 158 if repository.NARROW_REQUIREMENT not in repo.requirements:
136 return orig(pullop, kwargs) 159 return orig(pullop, kwargs)
147 if exclude: 170 if exclude:
148 kwargs['excludepats'] = exclude 171 kwargs['excludepats'] = exclude
149 # calculate known nodes only in ellipses cases because in non-ellipses cases 172 # calculate known nodes only in ellipses cases because in non-ellipses cases
150 # we have all the nodes 173 # we have all the nodes
151 if wireprototypes.ELLIPSESCAP1 in pullop.remote.capabilities(): 174 if wireprototypes.ELLIPSESCAP1 in pullop.remote.capabilities():
152 kwargs['known'] = [node.hex(ctx.node()) for ctx in 175 kwargs['known'] = [
153 repo.set('::%ln', pullop.common) 176 node.hex(ctx.node())
154 if ctx.node() != node.nullid] 177 for ctx in repo.set('::%ln', pullop.common)
178 if ctx.node() != node.nullid
179 ]
155 if not kwargs['known']: 180 if not kwargs['known']:
156 # Mercurial serializes an empty list as '' and deserializes it as 181 # Mercurial serializes an empty list as '' and deserializes it as
157 # [''], so delete it instead to avoid handling the empty string on 182 # [''], so delete it instead to avoid handling the empty string on
158 # the server. 183 # the server.
159 del kwargs['known'] 184 del kwargs['known']
160 185
161 extensions.wrapfunction(exchange,'_pullbundle2extraprepare', 186
162 pullbundle2extraprepare) 187 extensions.wrapfunction(
163 188 exchange, '_pullbundle2extraprepare', pullbundle2extraprepare
164 def _narrow(ui, repo, remote, commoninc, oldincludes, oldexcludes, 189 )
165 newincludes, newexcludes, force): 190
191
192 def _narrow(
193 ui,
194 repo,
195 remote,
196 commoninc,
197 oldincludes,
198 oldexcludes,
199 newincludes,
200 newexcludes,
201 force,
202 ):
166 oldmatch = narrowspec.match(repo.root, oldincludes, oldexcludes) 203 oldmatch = narrowspec.match(repo.root, oldincludes, oldexcludes)
167 newmatch = narrowspec.match(repo.root, newincludes, newexcludes) 204 newmatch = narrowspec.match(repo.root, newincludes, newexcludes)
168 205
169 # This is essentially doing "hg outgoing" to find all local-only 206 # This is essentially doing "hg outgoing" to find all local-only
170 # commits. We will then check that the local-only commits don't 207 # commits. We will then check that the local-only commits don't
171 # have any changes to files that will be untracked. 208 # have any changes to files that will be untracked.
172 unfi = repo.unfiltered() 209 unfi = repo.unfiltered()
173 outgoing = discovery.findcommonoutgoing(unfi, remote, 210 outgoing = discovery.findcommonoutgoing(unfi, remote, commoninc=commoninc)
174 commoninc=commoninc)
175 ui.status(_('looking for local changes to affected paths\n')) 211 ui.status(_('looking for local changes to affected paths\n'))
176 localnodes = [] 212 localnodes = []
177 for n in itertools.chain(outgoing.missing, outgoing.excluded): 213 for n in itertools.chain(outgoing.missing, outgoing.excluded):
178 if any(oldmatch(f) and not newmatch(f) for f in unfi[n].files()): 214 if any(oldmatch(f) and not newmatch(f) for f in unfi[n].files()):
179 localnodes.append(n) 215 localnodes.append(n)
180 revstostrip = unfi.revs('descendants(%ln)', localnodes) 216 revstostrip = unfi.revs('descendants(%ln)', localnodes)
181 hiddenrevs = repoview.filterrevs(repo, 'visible') 217 hiddenrevs = repoview.filterrevs(repo, 'visible')
182 visibletostrip = list(repo.changelog.node(r) 218 visibletostrip = list(
183 for r in (revstostrip - hiddenrevs)) 219 repo.changelog.node(r) for r in (revstostrip - hiddenrevs)
220 )
184 if visibletostrip: 221 if visibletostrip:
185 ui.status(_('The following changeset(s) or their ancestors have ' 222 ui.status(
186 'local changes not on the remote:\n')) 223 _(
224 'The following changeset(s) or their ancestors have '
225 'local changes not on the remote:\n'
226 )
227 )
187 maxnodes = 10 228 maxnodes = 10
188 if ui.verbose or len(visibletostrip) <= maxnodes: 229 if ui.verbose or len(visibletostrip) <= maxnodes:
189 for n in visibletostrip: 230 for n in visibletostrip:
190 ui.status('%s\n' % node.short(n)) 231 ui.status('%s\n' % node.short(n))
191 else: 232 else:
192 for n in visibletostrip[:maxnodes]: 233 for n in visibletostrip[:maxnodes]:
193 ui.status('%s\n' % node.short(n)) 234 ui.status('%s\n' % node.short(n))
194 ui.status(_('...and %d more, use --verbose to list all\n') % 235 ui.status(
195 (len(visibletostrip) - maxnodes)) 236 _('...and %d more, use --verbose to list all\n')
237 % (len(visibletostrip) - maxnodes)
238 )
196 if not force: 239 if not force:
197 raise error.Abort(_('local changes found'), 240 raise error.Abort(
198 hint=_('use --force-delete-local-changes to ' 241 _('local changes found'),
199 'ignore')) 242 hint=_('use --force-delete-local-changes to ' 'ignore'),
243 )
200 244
201 with ui.uninterruptible(): 245 with ui.uninterruptible():
202 if revstostrip: 246 if revstostrip:
203 tostrip = [unfi.changelog.node(r) for r in revstostrip] 247 tostrip = [unfi.changelog.node(r) for r in revstostrip]
204 if repo['.'].node() in tostrip: 248 if repo['.'].node() in tostrip:
205 # stripping working copy, so move to a different commit first 249 # stripping working copy, so move to a different commit first
206 urev = max(repo.revs('(::%n) - %ln + null', 250 urev = max(
207 repo['.'].node(), visibletostrip)) 251 repo.revs(
252 '(::%n) - %ln + null', repo['.'].node(), visibletostrip
253 )
254 )
208 hg.clean(repo, urev) 255 hg.clean(repo, urev)
209 overrides = {('devel', 'strip-obsmarkers'): False} 256 overrides = {('devel', 'strip-obsmarkers'): False}
210 with ui.configoverride(overrides, 'narrow'): 257 with ui.configoverride(overrides, 'narrow'):
211 repair.strip(ui, unfi, tostrip, topic='narrow') 258 repair.strip(ui, unfi, tostrip, topic='narrow')
212 259
245 narrowspec.updateworkingcopy(repo, assumeclean=True) 292 narrowspec.updateworkingcopy(repo, assumeclean=True)
246 narrowspec.copytoworkingcopy(repo) 293 narrowspec.copytoworkingcopy(repo)
247 294
248 repo.destroyed() 295 repo.destroyed()
249 296
250 def _widen(ui, repo, remote, commoninc, oldincludes, oldexcludes, 297
251 newincludes, newexcludes): 298 def _widen(
299 ui,
300 repo,
301 remote,
302 commoninc,
303 oldincludes,
304 oldexcludes,
305 newincludes,
306 newexcludes,
307 ):
252 # for now we assume that if a server has ellipses enabled, we will be 308 # for now we assume that if a server has ellipses enabled, we will be
253 # exchanging ellipses nodes. In future we should add ellipses as a client 309 # exchanging ellipses nodes. In future we should add ellipses as a client
254 # side requirement (maybe) to distinguish a client is shallow or not and 310 # side requirement (maybe) to distinguish a client is shallow or not and
255 # then send that information to server whether we want ellipses or not. 311 # then send that information to server whether we want ellipses or not.
256 # Theoretically a non-ellipses repo should be able to use narrow 312 # Theoretically a non-ellipses repo should be able to use narrow
257 # functionality from an ellipses enabled server 313 # functionality from an ellipses enabled server
258 remotecap = remote.capabilities() 314 remotecap = remote.capabilities()
259 ellipsesremote = any(cap in remotecap 315 ellipsesremote = any(
260 for cap in wireprototypes.SUPPORTED_ELLIPSESCAP) 316 cap in remotecap for cap in wireprototypes.SUPPORTED_ELLIPSESCAP
317 )
261 318
262 # check whether we are talking to a server which supports old version of 319 # check whether we are talking to a server which supports old version of
263 # ellipses capabilities 320 # ellipses capabilities
264 isoldellipses = (ellipsesremote and wireprototypes.ELLIPSESCAP1 in 321 isoldellipses = (
265 remotecap and wireprototypes.ELLIPSESCAP not in remotecap) 322 ellipsesremote
323 and wireprototypes.ELLIPSESCAP1 in remotecap
324 and wireprototypes.ELLIPSESCAP not in remotecap
325 )
266 326
267 def pullbundle2extraprepare_widen(orig, pullop, kwargs): 327 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
268 orig(pullop, kwargs) 328 orig(pullop, kwargs)
269 # The old{in,ex}cludepats have already been set by orig() 329 # The old{in,ex}cludepats have already been set by orig()
270 kwargs['includepats'] = newincludes 330 kwargs['includepats'] = newincludes
271 kwargs['excludepats'] = newexcludes 331 kwargs['excludepats'] = newexcludes
272 wrappedextraprepare = extensions.wrappedfunction(exchange, 332
273 '_pullbundle2extraprepare', pullbundle2extraprepare_widen) 333 wrappedextraprepare = extensions.wrappedfunction(
334 exchange, '_pullbundle2extraprepare', pullbundle2extraprepare_widen
335 )
274 336
275 # define a function that narrowbundle2 can call after creating the 337 # define a function that narrowbundle2 can call after creating the
276 # backup bundle, but before applying the bundle from the server 338 # backup bundle, but before applying the bundle from the server
277 def setnewnarrowpats(): 339 def setnewnarrowpats():
278 repo.setnarrowpats(newincludes, newexcludes) 340 repo.setnarrowpats(newincludes, newexcludes)
341
279 repo.setnewnarrowpats = setnewnarrowpats 342 repo.setnewnarrowpats = setnewnarrowpats
280 # silence the devel-warning of applying an empty changegroup 343 # silence the devel-warning of applying an empty changegroup
281 overrides = {('devel', 'all-warnings'): False} 344 overrides = {('devel', 'all-warnings'): False}
282 345
283 common = commoninc[0] 346 common = commoninc[0]
291 with wrappedextraprepare: 354 with wrappedextraprepare:
292 exchange.pull(repo, remote, heads=common) 355 exchange.pull(repo, remote, heads=common)
293 else: 356 else:
294 known = [] 357 known = []
295 if ellipsesremote: 358 if ellipsesremote:
296 known = [ctx.node() for ctx in 359 known = [
297 repo.set('::%ln', common) 360 ctx.node()
298 if ctx.node() != node.nullid] 361 for ctx in repo.set('::%ln', common)
362 if ctx.node() != node.nullid
363 ]
299 with remote.commandexecutor() as e: 364 with remote.commandexecutor() as e:
300 bundle = e.callcommand('narrow_widen', { 365 bundle = e.callcommand(
301 'oldincludes': oldincludes, 366 'narrow_widen',
302 'oldexcludes': oldexcludes, 367 {
303 'newincludes': newincludes, 368 'oldincludes': oldincludes,
304 'newexcludes': newexcludes, 369 'oldexcludes': oldexcludes,
305 'cgversion': '03', 370 'newincludes': newincludes,
306 'commonheads': common, 371 'newexcludes': newexcludes,
307 'known': known, 372 'cgversion': '03',
308 'ellipses': ellipsesremote, 373 'commonheads': common,
309 }).result() 374 'known': known,
375 'ellipses': ellipsesremote,
376 },
377 ).result()
310 378
311 trmanager = exchange.transactionmanager(repo, 'widen', remote.url()) 379 trmanager = exchange.transactionmanager(repo, 'widen', remote.url())
312 with trmanager, repo.ui.configoverride(overrides, 'widen'): 380 with trmanager, repo.ui.configoverride(overrides, 'widen'):
313 op = bundle2.bundleoperation(repo, trmanager.transaction, 381 op = bundle2.bundleoperation(
314 source='widen') 382 repo, trmanager.transaction, source='widen'
383 )
315 # TODO: we should catch error.Abort here 384 # TODO: we should catch error.Abort here
316 bundle2.processbundle(repo, bundle, op=op) 385 bundle2.processbundle(repo, bundle, op=op)
317 386
318 if ellipsesremote: 387 if ellipsesremote:
319 with ds.parentchange(): 388 with ds.parentchange():
322 with repo.transaction('widening'): 391 with repo.transaction('widening'):
323 repo.setnewnarrowpats() 392 repo.setnewnarrowpats()
324 narrowspec.updateworkingcopy(repo) 393 narrowspec.updateworkingcopy(repo)
325 narrowspec.copytoworkingcopy(repo) 394 narrowspec.copytoworkingcopy(repo)
326 395
396
327 # TODO(rdamazio): Make new matcher format and update description 397 # TODO(rdamazio): Make new matcher format and update description
328 @command('tracked', 398 @command(
329 [('', 'addinclude', [], _('new paths to include')), 399 'tracked',
330 ('', 'removeinclude', [], _('old paths to no longer include')), 400 [
331 ('', 'auto-remove-includes', False, 401 ('', 'addinclude', [], _('new paths to include')),
332 _('automatically choose unused includes to remove')), 402 ('', 'removeinclude', [], _('old paths to no longer include')),
333 ('', 'addexclude', [], _('new paths to exclude')), 403 (
334 ('', 'import-rules', '', _('import narrowspecs from a file')), 404 '',
335 ('', 'removeexclude', [], _('old paths to no longer exclude')), 405 'auto-remove-includes',
336 ('', 'clear', False, _('whether to replace the existing narrowspec')), 406 False,
337 ('', 'force-delete-local-changes', False, 407 _('automatically choose unused includes to remove'),
338 _('forces deletion of local changes when narrowing')), 408 ),
339 ('', 'update-working-copy', False, 409 ('', 'addexclude', [], _('new paths to exclude')),
340 _('update working copy when the store has changed')), 410 ('', 'import-rules', '', _('import narrowspecs from a file')),
341 ] + commands.remoteopts, 411 ('', 'removeexclude', [], _('old paths to no longer exclude')),
412 ('', 'clear', False, _('whether to replace the existing narrowspec')),
413 (
414 '',
415 'force-delete-local-changes',
416 False,
417 _('forces deletion of local changes when narrowing'),
418 ),
419 (
420 '',
421 'update-working-copy',
422 False,
423 _('update working copy when the store has changed'),
424 ),
425 ]
426 + commands.remoteopts,
342 _('[OPTIONS]... [REMOTE]'), 427 _('[OPTIONS]... [REMOTE]'),
343 inferrepo=True) 428 inferrepo=True,
429 )
344 def trackedcmd(ui, repo, remotepath=None, *pats, **opts): 430 def trackedcmd(ui, repo, remotepath=None, *pats, **opts):
345 """show or change the current narrowspec 431 """show or change the current narrowspec
346 432
347 With no argument, shows the current narrowspec entries, one per line. Each 433 With no argument, shows the current narrowspec entries, one per line. Each
348 line will be prefixed with 'I' or 'X' for included or excluded patterns, 434 line will be prefixed with 'I' or 'X' for included or excluded patterns,
374 add --addinclude, --addexclude rules in bulk. Like the other include and 460 add --addinclude, --addexclude rules in bulk. Like the other include and
375 exclude switches, the changes are applied immediately. 461 exclude switches, the changes are applied immediately.
376 """ 462 """
377 opts = pycompat.byteskwargs(opts) 463 opts = pycompat.byteskwargs(opts)
378 if repository.NARROW_REQUIREMENT not in repo.requirements: 464 if repository.NARROW_REQUIREMENT not in repo.requirements:
379 raise error.Abort(_('the tracked command is only supported on ' 465 raise error.Abort(
380 'repositories cloned with --narrow')) 466 _(
467 'the tracked command is only supported on '
468 'repositories cloned with --narrow'
469 )
470 )
381 471
382 # Before supporting, decide whether it "hg tracked --clear" should mean 472 # Before supporting, decide whether it "hg tracked --clear" should mean
383 # tracking no paths or all paths. 473 # tracking no paths or all paths.
384 if opts['clear']: 474 if opts['clear']:
385 raise error.Abort(_('the --clear option is not yet supported')) 475 raise error.Abort(_('the --clear option is not yet supported'))
389 if newrules: 479 if newrules:
390 try: 480 try:
391 filepath = os.path.join(encoding.getcwd(), newrules) 481 filepath = os.path.join(encoding.getcwd(), newrules)
392 fdata = util.readfile(filepath) 482 fdata = util.readfile(filepath)
393 except IOError as inst: 483 except IOError as inst:
394 raise error.Abort(_("cannot read narrowspecs from '%s': %s") % 484 raise error.Abort(
395 (filepath, encoding.strtolocal(inst.strerror))) 485 _("cannot read narrowspecs from '%s': %s")
396 includepats, excludepats, profiles = sparse.parseconfig(ui, fdata, 486 % (filepath, encoding.strtolocal(inst.strerror))
397 'narrow') 487 )
488 includepats, excludepats, profiles = sparse.parseconfig(
489 ui, fdata, 'narrow'
490 )
398 if profiles: 491 if profiles:
399 raise error.Abort(_("including other spec files using '%include' " 492 raise error.Abort(
400 "is not supported in narrowspec")) 493 _(
494 "including other spec files using '%include' "
495 "is not supported in narrowspec"
496 )
497 )
401 opts['addinclude'].extend(includepats) 498 opts['addinclude'].extend(includepats)
402 opts['addexclude'].extend(excludepats) 499 opts['addexclude'].extend(excludepats)
403 500
404 addedincludes = narrowspec.parsepatterns(opts['addinclude']) 501 addedincludes = narrowspec.parsepatterns(opts['addinclude'])
405 removedincludes = narrowspec.parsepatterns(opts['removeinclude']) 502 removedincludes = narrowspec.parsepatterns(opts['removeinclude'])
406 addedexcludes = narrowspec.parsepatterns(opts['addexclude']) 503 addedexcludes = narrowspec.parsepatterns(opts['addexclude'])
407 removedexcludes = narrowspec.parsepatterns(opts['removeexclude']) 504 removedexcludes = narrowspec.parsepatterns(opts['removeexclude'])
408 autoremoveincludes = opts['auto_remove_includes'] 505 autoremoveincludes = opts['auto_remove_includes']
409 506
410 update_working_copy = opts['update_working_copy'] 507 update_working_copy = opts['update_working_copy']
411 only_show = not (addedincludes or removedincludes or addedexcludes or 508 only_show = not (
412 removedexcludes or newrules or autoremoveincludes or 509 addedincludes
413 update_working_copy) 510 or removedincludes
511 or addedexcludes
512 or removedexcludes
513 or newrules
514 or autoremoveincludes
515 or update_working_copy
516 )
414 517
415 oldincludes, oldexcludes = repo.narrowpats 518 oldincludes, oldexcludes = repo.narrowpats
416 519
417 # filter the user passed additions and deletions into actual additions and 520 # filter the user passed additions and deletions into actual additions and
418 # deletions of excludes and includes 521 # deletions of excludes and includes
467 raise error.Abort(_("server does not support narrow clones")) 570 raise error.Abort(_("server does not support narrow clones"))
468 571
469 commoninc = discovery.findcommonincoming(repo, remote) 572 commoninc = discovery.findcommonincoming(repo, remote)
470 573
471 if autoremoveincludes: 574 if autoremoveincludes:
472 outgoing = discovery.findcommonoutgoing(repo, remote, 575 outgoing = discovery.findcommonoutgoing(
473 commoninc=commoninc) 576 repo, remote, commoninc=commoninc
577 )
474 ui.status(_('looking for unused includes to remove\n')) 578 ui.status(_('looking for unused includes to remove\n'))
475 localfiles = set() 579 localfiles = set()
476 for n in itertools.chain(outgoing.missing, outgoing.excluded): 580 for n in itertools.chain(outgoing.missing, outgoing.excluded):
477 localfiles.update(repo[n].files()) 581 localfiles.update(repo[n].files())
478 suggestedremovals = [] 582 suggestedremovals = []
481 if not any(match(f) for f in localfiles): 585 if not any(match(f) for f in localfiles):
482 suggestedremovals.append(include) 586 suggestedremovals.append(include)
483 if suggestedremovals: 587 if suggestedremovals:
484 for s in suggestedremovals: 588 for s in suggestedremovals:
485 ui.status('%s\n' % s) 589 ui.status('%s\n' % s)
486 if (ui.promptchoice(_('remove these unused includes (yn)?' 590 if (
487 '$$ &Yes $$ &No')) == 0): 591 ui.promptchoice(
592 _('remove these unused includes (yn)?' '$$ &Yes $$ &No')
593 )
594 == 0
595 ):
488 removedincludes.update(suggestedremovals) 596 removedincludes.update(suggestedremovals)
489 narrowing = True 597 narrowing = True
490 else: 598 else:
491 ui.status(_('found no unused includes\n')) 599 ui.status(_('found no unused includes\n'))
492 600
493 if narrowing: 601 if narrowing:
494 newincludes = oldincludes - removedincludes 602 newincludes = oldincludes - removedincludes
495 newexcludes = oldexcludes | addedexcludes 603 newexcludes = oldexcludes | addedexcludes
496 _narrow(ui, repo, remote, commoninc, oldincludes, oldexcludes, 604 _narrow(
497 newincludes, newexcludes, 605 ui,
498 opts['force_delete_local_changes']) 606 repo,
607 remote,
608 commoninc,
609 oldincludes,
610 oldexcludes,
611 newincludes,
612 newexcludes,
613 opts['force_delete_local_changes'],
614 )
499 # _narrow() updated the narrowspec and _widen() below needs to 615 # _narrow() updated the narrowspec and _widen() below needs to
500 # use the updated values as its base (otherwise removed includes 616 # use the updated values as its base (otherwise removed includes
501 # and addedexcludes will be lost in the resulting narrowspec) 617 # and addedexcludes will be lost in the resulting narrowspec)
502 oldincludes = newincludes 618 oldincludes = newincludes
503 oldexcludes = newexcludes 619 oldexcludes = newexcludes
504 620
505 if widening: 621 if widening:
506 newincludes = oldincludes | addedincludes 622 newincludes = oldincludes | addedincludes
507 newexcludes = oldexcludes - removedexcludes 623 newexcludes = oldexcludes - removedexcludes
508 _widen(ui, repo, remote, commoninc, oldincludes, oldexcludes, 624 _widen(
509 newincludes, newexcludes) 625 ui,
626 repo,
627 remote,
628 commoninc,
629 oldincludes,
630 oldexcludes,
631 newincludes,
632 newexcludes,
633 )
510 634
511 return 0 635 return 0