##// END OF EJS Templates
narrow: widden the lock context in `tracking`...
marmoute -
r51079:a6ca61fd default
parent child Browse files
Show More
@@ -1,695 +1,695 b''
1 1 # narrowcommands.py - command modifications for narrowhg extension
2 2 #
3 3 # Copyright 2017 Google, Inc.
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 import itertools
9 9 import os
10 10
11 11 from mercurial.i18n import _
12 12 from mercurial.node import (
13 13 hex,
14 14 short,
15 15 )
16 16 from mercurial import (
17 17 bundle2,
18 18 cmdutil,
19 19 commands,
20 20 discovery,
21 21 encoding,
22 22 error,
23 23 exchange,
24 24 extensions,
25 25 hg,
26 26 narrowspec,
27 27 pathutil,
28 28 pycompat,
29 29 registrar,
30 30 repair,
31 31 repoview,
32 32 requirements,
33 33 sparse,
34 34 util,
35 35 wireprototypes,
36 36 )
37 37 from mercurial.utils import (
38 38 urlutil,
39 39 )
40 40
41 41 table = {}
42 42 command = registrar.command(table)
43 43
44 44
45 45 def setup():
46 46 """Wraps user-facing mercurial commands with narrow-aware versions."""
47 47
48 48 entry = extensions.wrapcommand(commands.table, b'clone', clonenarrowcmd)
49 49 entry[1].append(
50 50 (b'', b'narrow', None, _(b"create a narrow clone of select files"))
51 51 )
52 52 entry[1].append(
53 53 (
54 54 b'',
55 55 b'depth',
56 56 b'',
57 57 _(b"limit the history fetched by distance from heads"),
58 58 )
59 59 )
60 60 entry[1].append((b'', b'narrowspec', b'', _(b"read narrowspecs from file")))
61 61 # TODO(durin42): unify sparse/narrow --include/--exclude logic a bit
62 62 if b'sparse' not in extensions.enabled():
63 63 entry[1].append(
64 64 (b'', b'include', [], _(b"specifically fetch this file/directory"))
65 65 )
66 66 entry[1].append(
67 67 (
68 68 b'',
69 69 b'exclude',
70 70 [],
71 71 _(b"do not fetch this file/directory, even if included"),
72 72 )
73 73 )
74 74
75 75 entry = extensions.wrapcommand(commands.table, b'pull', pullnarrowcmd)
76 76 entry[1].append(
77 77 (
78 78 b'',
79 79 b'depth',
80 80 b'',
81 81 _(b"limit the history fetched by distance from heads"),
82 82 )
83 83 )
84 84
85 85 extensions.wrapcommand(commands.table, b'archive', archivenarrowcmd)
86 86
87 87
88 88 def clonenarrowcmd(orig, ui, repo, *args, **opts):
89 89 """Wraps clone command, so 'hg clone' first wraps localrepo.clone()."""
90 90 opts = pycompat.byteskwargs(opts)
91 91 wrappedextraprepare = util.nullcontextmanager()
92 92 narrowspecfile = opts[b'narrowspec']
93 93
94 94 if narrowspecfile:
95 95 filepath = os.path.join(encoding.getcwd(), narrowspecfile)
96 96 ui.status(_(b"reading narrowspec from '%s'\n") % filepath)
97 97 try:
98 98 fdata = util.readfile(filepath)
99 99 except IOError as inst:
100 100 raise error.Abort(
101 101 _(b"cannot read narrowspecs from '%s': %s")
102 102 % (filepath, encoding.strtolocal(inst.strerror))
103 103 )
104 104
105 105 includes, excludes, profiles = sparse.parseconfig(ui, fdata, b'narrow')
106 106 if profiles:
107 107 raise error.ConfigError(
108 108 _(
109 109 b"cannot specify other files using '%include' in"
110 110 b" narrowspec"
111 111 )
112 112 )
113 113
114 114 narrowspec.validatepatterns(includes)
115 115 narrowspec.validatepatterns(excludes)
116 116
117 117 # narrowspec is passed so we should assume that user wants narrow clone
118 118 opts[b'narrow'] = True
119 119 opts[b'include'].extend(includes)
120 120 opts[b'exclude'].extend(excludes)
121 121
122 122 if opts[b'narrow']:
123 123
124 124 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
125 125 orig(pullop, kwargs)
126 126
127 127 if opts.get(b'depth'):
128 128 kwargs[b'depth'] = opts[b'depth']
129 129
130 130 wrappedextraprepare = extensions.wrappedfunction(
131 131 exchange, b'_pullbundle2extraprepare', pullbundle2extraprepare_widen
132 132 )
133 133
134 134 with wrappedextraprepare:
135 135 return orig(ui, repo, *args, **pycompat.strkwargs(opts))
136 136
137 137
138 138 def pullnarrowcmd(orig, ui, repo, *args, **opts):
139 139 """Wraps pull command to allow modifying narrow spec."""
140 140 wrappedextraprepare = util.nullcontextmanager()
141 141 if requirements.NARROW_REQUIREMENT in repo.requirements:
142 142
143 143 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
144 144 orig(pullop, kwargs)
145 145 if opts.get('depth'):
146 146 kwargs[b'depth'] = opts['depth']
147 147
148 148 wrappedextraprepare = extensions.wrappedfunction(
149 149 exchange, b'_pullbundle2extraprepare', pullbundle2extraprepare_widen
150 150 )
151 151
152 152 with wrappedextraprepare:
153 153 return orig(ui, repo, *args, **opts)
154 154
155 155
156 156 def archivenarrowcmd(orig, ui, repo, *args, **opts):
157 157 """Wraps archive command to narrow the default includes."""
158 158 if requirements.NARROW_REQUIREMENT in repo.requirements:
159 159 repo_includes, repo_excludes = repo.narrowpats
160 160 includes = set(opts.get('include', []))
161 161 excludes = set(opts.get('exclude', []))
162 162 includes, excludes, unused_invalid = narrowspec.restrictpatterns(
163 163 includes, excludes, repo_includes, repo_excludes
164 164 )
165 165 if includes:
166 166 opts['include'] = includes
167 167 if excludes:
168 168 opts['exclude'] = excludes
169 169 return orig(ui, repo, *args, **opts)
170 170
171 171
172 172 def pullbundle2extraprepare(orig, pullop, kwargs):
173 173 repo = pullop.repo
174 174 if requirements.NARROW_REQUIREMENT not in repo.requirements:
175 175 return orig(pullop, kwargs)
176 176
177 177 if wireprototypes.NARROWCAP not in pullop.remote.capabilities():
178 178 raise error.Abort(_(b"server does not support narrow clones"))
179 179 orig(pullop, kwargs)
180 180 kwargs[b'narrow'] = True
181 181 include, exclude = repo.narrowpats
182 182 kwargs[b'oldincludepats'] = include
183 183 kwargs[b'oldexcludepats'] = exclude
184 184 if include:
185 185 kwargs[b'includepats'] = include
186 186 if exclude:
187 187 kwargs[b'excludepats'] = exclude
188 188 # calculate known nodes only in ellipses cases because in non-ellipses cases
189 189 # we have all the nodes
190 190 if wireprototypes.ELLIPSESCAP1 in pullop.remote.capabilities():
191 191 kwargs[b'known'] = [
192 192 hex(ctx.node())
193 193 for ctx in repo.set(b'::%ln', pullop.common)
194 194 if ctx.node() != repo.nullid
195 195 ]
196 196 if not kwargs[b'known']:
197 197 # Mercurial serializes an empty list as '' and deserializes it as
198 198 # [''], so delete it instead to avoid handling the empty string on
199 199 # the server.
200 200 del kwargs[b'known']
201 201
202 202
203 203 extensions.wrapfunction(
204 204 exchange, b'_pullbundle2extraprepare', pullbundle2extraprepare
205 205 )
206 206
207 207
208 208 def _narrow(
209 209 ui,
210 210 repo,
211 211 remote,
212 212 commoninc,
213 213 oldincludes,
214 214 oldexcludes,
215 215 newincludes,
216 216 newexcludes,
217 217 force,
218 218 backup,
219 219 ):
220 220 oldmatch = narrowspec.match(repo.root, oldincludes, oldexcludes)
221 221 newmatch = narrowspec.match(repo.root, newincludes, newexcludes)
222 222
223 223 # This is essentially doing "hg outgoing" to find all local-only
224 224 # commits. We will then check that the local-only commits don't
225 225 # have any changes to files that will be untracked.
226 226 unfi = repo.unfiltered()
227 227 outgoing = discovery.findcommonoutgoing(unfi, remote, commoninc=commoninc)
228 228 ui.status(_(b'looking for local changes to affected paths\n'))
229 229 progress = ui.makeprogress(
230 230 topic=_(b'changesets'),
231 231 unit=_(b'changesets'),
232 232 total=len(outgoing.missing) + len(outgoing.excluded),
233 233 )
234 234 localnodes = []
235 235 with progress:
236 236 for n in itertools.chain(outgoing.missing, outgoing.excluded):
237 237 progress.increment()
238 238 if any(oldmatch(f) and not newmatch(f) for f in unfi[n].files()):
239 239 localnodes.append(n)
240 240 revstostrip = unfi.revs(b'descendants(%ln)', localnodes)
241 241 hiddenrevs = repoview.filterrevs(repo, b'visible')
242 242 visibletostrip = list(
243 243 repo.changelog.node(r) for r in (revstostrip - hiddenrevs)
244 244 )
245 245 if visibletostrip:
246 246 ui.status(
247 247 _(
248 248 b'The following changeset(s) or their ancestors have '
249 249 b'local changes not on the remote:\n'
250 250 )
251 251 )
252 252 maxnodes = 10
253 253 if ui.verbose or len(visibletostrip) <= maxnodes:
254 254 for n in visibletostrip:
255 255 ui.status(b'%s\n' % short(n))
256 256 else:
257 257 for n in visibletostrip[:maxnodes]:
258 258 ui.status(b'%s\n' % short(n))
259 259 ui.status(
260 260 _(b'...and %d more, use --verbose to list all\n')
261 261 % (len(visibletostrip) - maxnodes)
262 262 )
263 263 if not force:
264 264 raise error.StateError(
265 265 _(b'local changes found'),
266 266 hint=_(b'use --force-delete-local-changes to ignore'),
267 267 )
268 268
269 269 with ui.uninterruptible():
270 270 if revstostrip:
271 271 tostrip = [unfi.changelog.node(r) for r in revstostrip]
272 272 if repo[b'.'].node() in tostrip:
273 273 # stripping working copy, so move to a different commit first
274 274 urev = max(
275 275 repo.revs(
276 276 b'(::%n) - %ln + null',
277 277 repo[b'.'].node(),
278 278 visibletostrip,
279 279 )
280 280 )
281 281 hg.clean(repo, urev)
282 282 overrides = {(b'devel', b'strip-obsmarkers'): False}
283 283 if backup:
284 284 ui.status(_(b'moving unwanted changesets to backup\n'))
285 285 else:
286 286 ui.status(_(b'deleting unwanted changesets\n'))
287 287 with ui.configoverride(overrides, b'narrow'):
288 288 repair.strip(ui, unfi, tostrip, topic=b'narrow', backup=backup)
289 289
290 290 todelete = []
291 291 for t, f, size in repo.store.datafiles():
292 292 if f.startswith(b'data/'):
293 293 file = f[5:-2]
294 294 if not newmatch(file):
295 295 todelete.append(f)
296 296 elif f.startswith(b'meta/'):
297 297 dir = f[5:-13]
298 298 dirs = sorted(pathutil.dirs({dir})) + [dir]
299 299 include = True
300 300 for d in dirs:
301 301 visit = newmatch.visitdir(d)
302 302 if not visit:
303 303 include = False
304 304 break
305 305 if visit == b'all':
306 306 break
307 307 if not include:
308 308 todelete.append(f)
309 309
310 310 repo.destroying()
311 311
312 312 with repo.transaction(b'narrowing'):
313 313 # Update narrowspec before removing revlogs, so repo won't be
314 314 # corrupt in case of crash
315 315 repo.setnarrowpats(newincludes, newexcludes)
316 316
317 317 for f in todelete:
318 318 ui.status(_(b'deleting %s\n') % f)
319 319 util.unlinkpath(repo.svfs.join(f))
320 320 repo.store.markremoved(f)
321 321
322 322 ui.status(_(b'deleting unwanted files from working copy\n'))
323 323 with repo.dirstate.changing_parents(repo):
324 324 narrowspec.updateworkingcopy(repo, assumeclean=True)
325 325 narrowspec.copytoworkingcopy(repo)
326 326
327 327 repo.destroyed()
328 328
329 329
330 330 def _widen(
331 331 ui,
332 332 repo,
333 333 remote,
334 334 commoninc,
335 335 oldincludes,
336 336 oldexcludes,
337 337 newincludes,
338 338 newexcludes,
339 339 ):
340 340 # for now we assume that if a server has ellipses enabled, we will be
341 341 # exchanging ellipses nodes. In future we should add ellipses as a client
342 342 # side requirement (maybe) to distinguish a client is shallow or not and
343 343 # then send that information to server whether we want ellipses or not.
344 344 # Theoretically a non-ellipses repo should be able to use narrow
345 345 # functionality from an ellipses enabled server
346 346 remotecap = remote.capabilities()
347 347 ellipsesremote = any(
348 348 cap in remotecap for cap in wireprototypes.SUPPORTED_ELLIPSESCAP
349 349 )
350 350
351 351 # check whether we are talking to a server which supports old version of
352 352 # ellipses capabilities
353 353 isoldellipses = (
354 354 ellipsesremote
355 355 and wireprototypes.ELLIPSESCAP1 in remotecap
356 356 and wireprototypes.ELLIPSESCAP not in remotecap
357 357 )
358 358
359 359 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
360 360 orig(pullop, kwargs)
361 361 # The old{in,ex}cludepats have already been set by orig()
362 362 kwargs[b'includepats'] = newincludes
363 363 kwargs[b'excludepats'] = newexcludes
364 364
365 365 wrappedextraprepare = extensions.wrappedfunction(
366 366 exchange, b'_pullbundle2extraprepare', pullbundle2extraprepare_widen
367 367 )
368 368
369 369 # define a function that narrowbundle2 can call after creating the
370 370 # backup bundle, but before applying the bundle from the server
371 371 def setnewnarrowpats():
372 372 repo.setnarrowpats(newincludes, newexcludes)
373 373
374 374 repo.setnewnarrowpats = setnewnarrowpats
375 375 # silence the devel-warning of applying an empty changegroup
376 376 overrides = {(b'devel', b'all-warnings'): False}
377 377
378 378 common = commoninc[0]
379 379 with ui.uninterruptible():
380 380 if ellipsesremote:
381 381 ds = repo.dirstate
382 382 p1, p2 = ds.p1(), ds.p2()
383 383 with ds.changing_parents(repo):
384 384 ds.setparents(repo.nullid, repo.nullid)
385 385 if isoldellipses:
386 386 with wrappedextraprepare:
387 387 exchange.pull(repo, remote, heads=common)
388 388 else:
389 389 known = []
390 390 if ellipsesremote:
391 391 known = [
392 392 ctx.node()
393 393 for ctx in repo.set(b'::%ln', common)
394 394 if ctx.node() != repo.nullid
395 395 ]
396 396 with remote.commandexecutor() as e:
397 397 bundle = e.callcommand(
398 398 b'narrow_widen',
399 399 {
400 400 b'oldincludes': oldincludes,
401 401 b'oldexcludes': oldexcludes,
402 402 b'newincludes': newincludes,
403 403 b'newexcludes': newexcludes,
404 404 b'cgversion': b'03',
405 405 b'commonheads': common,
406 406 b'known': known,
407 407 b'ellipses': ellipsesremote,
408 408 },
409 409 ).result()
410 410
411 411 trmanager = exchange.transactionmanager(
412 412 repo, b'widen', remote.url()
413 413 )
414 414 with trmanager, repo.ui.configoverride(overrides, b'widen'):
415 415 op = bundle2.bundleoperation(
416 416 repo, trmanager.transaction, source=b'widen'
417 417 )
418 418 # TODO: we should catch error.Abort here
419 419 bundle2.processbundle(repo, bundle, op=op, remote=remote)
420 420
421 421 if ellipsesremote:
422 422 with ds.changing_parents(repo):
423 423 ds.setparents(p1, p2)
424 424
425 425 with repo.transaction(b'widening'), repo.dirstate.changing_parents(
426 426 repo
427 427 ):
428 428 repo.setnewnarrowpats()
429 429 narrowspec.updateworkingcopy(repo)
430 430 narrowspec.copytoworkingcopy(repo)
431 431
432 432
433 433 # TODO(rdamazio): Make new matcher format and update description
434 434 @command(
435 435 b'tracked',
436 436 [
437 437 (b'', b'addinclude', [], _(b'new paths to include')),
438 438 (b'', b'removeinclude', [], _(b'old paths to no longer include')),
439 439 (
440 440 b'',
441 441 b'auto-remove-includes',
442 442 False,
443 443 _(b'automatically choose unused includes to remove'),
444 444 ),
445 445 (b'', b'addexclude', [], _(b'new paths to exclude')),
446 446 (b'', b'import-rules', b'', _(b'import narrowspecs from a file')),
447 447 (b'', b'removeexclude', [], _(b'old paths to no longer exclude')),
448 448 (
449 449 b'',
450 450 b'clear',
451 451 False,
452 452 _(b'whether to replace the existing narrowspec'),
453 453 ),
454 454 (
455 455 b'',
456 456 b'force-delete-local-changes',
457 457 False,
458 458 _(b'forces deletion of local changes when narrowing'),
459 459 ),
460 460 (
461 461 b'',
462 462 b'backup',
463 463 True,
464 464 _(b'back up local changes when narrowing'),
465 465 ),
466 466 (
467 467 b'',
468 468 b'update-working-copy',
469 469 False,
470 470 _(b'update working copy when the store has changed'),
471 471 ),
472 472 ]
473 473 + commands.remoteopts,
474 474 _(b'[OPTIONS]... [REMOTE]'),
475 475 inferrepo=True,
476 476 helpcategory=command.CATEGORY_MAINTENANCE,
477 477 )
478 478 def trackedcmd(ui, repo, remotepath=None, *pats, **opts):
479 479 """show or change the current narrowspec
480 480
481 481 With no argument, shows the current narrowspec entries, one per line. Each
482 482 line will be prefixed with 'I' or 'X' for included or excluded patterns,
483 483 respectively.
484 484
485 485 The narrowspec is comprised of expressions to match remote files and/or
486 486 directories that should be pulled into your client.
487 487 The narrowspec has *include* and *exclude* expressions, with excludes always
488 488 trumping includes: that is, if a file matches an exclude expression, it will
489 489 be excluded even if it also matches an include expression.
490 490 Excluding files that were never included has no effect.
491 491
492 492 Each included or excluded entry is in the format described by
493 493 'hg help patterns'.
494 494
495 495 The options allow you to add or remove included and excluded expressions.
496 496
497 497 If --clear is specified, then all previous includes and excludes are DROPPED
498 498 and replaced by the new ones specified to --addinclude and --addexclude.
499 499 If --clear is specified without any further options, the narrowspec will be
500 500 empty and will not match any files.
501 501
502 502 If --auto-remove-includes is specified, then those includes that don't match
503 503 any files modified by currently visible local commits (those not shared by
504 504 the remote) will be added to the set of explicitly specified includes to
505 505 remove.
506 506
507 507 --import-rules accepts a path to a file containing rules, allowing you to
508 508 add --addinclude, --addexclude rules in bulk. Like the other include and
509 509 exclude switches, the changes are applied immediately.
510 510 """
511 511 opts = pycompat.byteskwargs(opts)
512 512 if requirements.NARROW_REQUIREMENT not in repo.requirements:
513 513 raise error.InputError(
514 514 _(
515 515 b'the tracked command is only supported on '
516 516 b'repositories cloned with --narrow'
517 517 )
518 518 )
519 519
520 520 # Before supporting, decide whether it "hg tracked --clear" should mean
521 521 # tracking no paths or all paths.
522 522 if opts[b'clear']:
523 523 raise error.InputError(_(b'the --clear option is not yet supported'))
524 524
525 525 # import rules from a file
526 526 newrules = opts.get(b'import_rules')
527 527 if newrules:
528 528 try:
529 529 filepath = os.path.join(encoding.getcwd(), newrules)
530 530 fdata = util.readfile(filepath)
531 531 except IOError as inst:
532 532 raise error.StorageError(
533 533 _(b"cannot read narrowspecs from '%s': %s")
534 534 % (filepath, encoding.strtolocal(inst.strerror))
535 535 )
536 536 includepats, excludepats, profiles = sparse.parseconfig(
537 537 ui, fdata, b'narrow'
538 538 )
539 539 if profiles:
540 540 raise error.InputError(
541 541 _(
542 542 b"including other spec files using '%include' "
543 543 b"is not supported in narrowspec"
544 544 )
545 545 )
546 546 opts[b'addinclude'].extend(includepats)
547 547 opts[b'addexclude'].extend(excludepats)
548 548
549 549 addedincludes = narrowspec.parsepatterns(opts[b'addinclude'])
550 550 removedincludes = narrowspec.parsepatterns(opts[b'removeinclude'])
551 551 addedexcludes = narrowspec.parsepatterns(opts[b'addexclude'])
552 552 removedexcludes = narrowspec.parsepatterns(opts[b'removeexclude'])
553 553 autoremoveincludes = opts[b'auto_remove_includes']
554 554
555 555 update_working_copy = opts[b'update_working_copy']
556 556 only_show = not (
557 557 addedincludes
558 558 or removedincludes
559 559 or addedexcludes
560 560 or removedexcludes
561 561 or newrules
562 562 or autoremoveincludes
563 563 or update_working_copy
564 564 )
565 565
566 566 # Only print the current narrowspec.
567 567 if only_show:
568 568 oldincludes, oldexcludes = repo.narrowpats
569 569 ui.pager(b'tracked')
570 570 fm = ui.formatter(b'narrow', opts)
571 571 for i in sorted(oldincludes):
572 572 fm.startitem()
573 573 fm.write(b'status', b'%s ', b'I', label=b'narrow.included')
574 574 fm.write(b'pat', b'%s\n', i, label=b'narrow.included')
575 575 for i in sorted(oldexcludes):
576 576 fm.startitem()
577 577 fm.write(b'status', b'%s ', b'X', label=b'narrow.excluded')
578 578 fm.write(b'pat', b'%s\n', i, label=b'narrow.excluded')
579 579 fm.end()
580 580 return 0
581 581
582 oldincludes, oldexcludes = repo.narrowpats
582 with repo.wlock(), repo.lock():
583 oldincludes, oldexcludes = repo.narrowpats
583 584
584 # filter the user passed additions and deletions into actual additions and
585 # deletions of excludes and includes
586 addedincludes -= oldincludes
587 removedincludes &= oldincludes
588 addedexcludes -= oldexcludes
589 removedexcludes &= oldexcludes
585 # filter the user passed additions and deletions into actual additions and
586 # deletions of excludes and includes
587 addedincludes -= oldincludes
588 removedincludes &= oldincludes
589 addedexcludes -= oldexcludes
590 removedexcludes &= oldexcludes
590 591
591 widening = addedincludes or removedexcludes
592 narrowing = removedincludes or addedexcludes
592 widening = addedincludes or removedexcludes
593 narrowing = removedincludes or addedexcludes
593 594
594 if update_working_copy:
595 with repo.wlock(), repo.lock(), repo.transaction(
596 b'narrow-wc'
597 ), repo.dirstate.changing_parents(repo):
598 narrowspec.updateworkingcopy(repo)
599 narrowspec.copytoworkingcopy(repo)
600 return 0
595 if update_working_copy:
596 with repo.transaction(b'narrow-wc'), repo.dirstate.changing_parents(
597 repo
598 ):
599 narrowspec.updateworkingcopy(repo)
600 narrowspec.copytoworkingcopy(repo)
601 return 0
601 602
602 if not (widening or narrowing or autoremoveincludes):
603 ui.status(_(b"nothing to widen or narrow\n"))
604 return 0
603 if not (widening or narrowing or autoremoveincludes):
604 ui.status(_(b"nothing to widen or narrow\n"))
605 return 0
605 606
606 with repo.wlock(), repo.lock():
607 607 cmdutil.bailifchanged(repo)
608 608
609 609 # Find the revisions we have in common with the remote. These will
610 610 # be used for finding local-only changes for narrowing. They will
611 611 # also define the set of revisions to update for widening.
612 612 path = urlutil.get_unique_pull_path_obj(b'tracked', ui, remotepath)
613 613 ui.status(_(b'comparing with %s\n') % urlutil.hidepassword(path.loc))
614 614 remote = hg.peer(repo, opts, path)
615 615
616 616 try:
617 617 # check narrow support before doing anything if widening needs to be
618 618 # performed. In future we should also abort if client is ellipses and
619 619 # server does not support ellipses
620 620 if (
621 621 widening
622 622 and wireprototypes.NARROWCAP not in remote.capabilities()
623 623 ):
624 624 raise error.Abort(_(b"server does not support narrow clones"))
625 625
626 626 commoninc = discovery.findcommonincoming(repo, remote)
627 627
628 628 if autoremoveincludes:
629 629 outgoing = discovery.findcommonoutgoing(
630 630 repo, remote, commoninc=commoninc
631 631 )
632 632 ui.status(_(b'looking for unused includes to remove\n'))
633 633 localfiles = set()
634 634 for n in itertools.chain(outgoing.missing, outgoing.excluded):
635 635 localfiles.update(repo[n].files())
636 636 suggestedremovals = []
637 637 for include in sorted(oldincludes):
638 638 match = narrowspec.match(repo.root, [include], oldexcludes)
639 639 if not any(match(f) for f in localfiles):
640 640 suggestedremovals.append(include)
641 641 if suggestedremovals:
642 642 for s in suggestedremovals:
643 643 ui.status(b'%s\n' % s)
644 644 if (
645 645 ui.promptchoice(
646 646 _(
647 647 b'remove these unused includes (yn)?'
648 648 b'$$ &Yes $$ &No'
649 649 )
650 650 )
651 651 == 0
652 652 ):
653 653 removedincludes.update(suggestedremovals)
654 654 narrowing = True
655 655 else:
656 656 ui.status(_(b'found no unused includes\n'))
657 657
658 658 if narrowing:
659 659 newincludes = oldincludes - removedincludes
660 660 newexcludes = oldexcludes | addedexcludes
661 661 _narrow(
662 662 ui,
663 663 repo,
664 664 remote,
665 665 commoninc,
666 666 oldincludes,
667 667 oldexcludes,
668 668 newincludes,
669 669 newexcludes,
670 670 opts[b'force_delete_local_changes'],
671 671 opts[b'backup'],
672 672 )
673 673 # _narrow() updated the narrowspec and _widen() below needs to
674 674 # use the updated values as its base (otherwise removed includes
675 675 # and addedexcludes will be lost in the resulting narrowspec)
676 676 oldincludes = newincludes
677 677 oldexcludes = newexcludes
678 678
679 679 if widening:
680 680 newincludes = oldincludes | addedincludes
681 681 newexcludes = oldexcludes - removedexcludes
682 682 _widen(
683 683 ui,
684 684 repo,
685 685 remote,
686 686 commoninc,
687 687 oldincludes,
688 688 oldexcludes,
689 689 newincludes,
690 690 newexcludes,
691 691 )
692 692 finally:
693 693 remote.close()
694 694
695 695 return 0
General Comments 0
You need to be logged in to leave comments. Login now