##// END OF EJS Templates
narrowcommands: more byteskwargs cleanup...
Augie Fackler -
r36184:ccf7ae11 default
parent child Browse files
Show More
@@ -1,404 +1,405
1 # narrowcommands.py - command modifications for narrowhg extension
1 # narrowcommands.py - command modifications for narrowhg extension
2 #
2 #
3 # Copyright 2017 Google, Inc.
3 # Copyright 2017 Google, Inc.
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7 from __future__ import absolute_import
7 from __future__ import absolute_import
8
8
9 import itertools
9 import itertools
10
10
11 from mercurial.i18n import _
11 from mercurial.i18n import _
12 from mercurial import (
12 from mercurial import (
13 cmdutil,
13 cmdutil,
14 commands,
14 commands,
15 discovery,
15 discovery,
16 error,
16 error,
17 exchange,
17 exchange,
18 extensions,
18 extensions,
19 hg,
19 hg,
20 merge,
20 merge,
21 narrowspec,
21 narrowspec,
22 node,
22 node,
23 pycompat,
23 pycompat,
24 registrar,
24 registrar,
25 repair,
25 repair,
26 repoview,
26 repoview,
27 util,
27 util,
28 )
28 )
29
29
30 from . import (
30 from . import (
31 narrowbundle2,
31 narrowbundle2,
32 narrowrepo,
32 narrowrepo,
33 )
33 )
34
34
35 table = {}
35 table = {}
36 command = registrar.command(table)
36 command = registrar.command(table)
37
37
38 def setup():
38 def setup():
39 """Wraps user-facing mercurial commands with narrow-aware versions."""
39 """Wraps user-facing mercurial commands with narrow-aware versions."""
40
40
41 entry = extensions.wrapcommand(commands.table, 'clone', clonenarrowcmd)
41 entry = extensions.wrapcommand(commands.table, 'clone', clonenarrowcmd)
42 entry[1].append(('', 'narrow', None,
42 entry[1].append(('', 'narrow', None,
43 _("create a narrow clone of select files")))
43 _("create a narrow clone of select files")))
44 entry[1].append(('', 'depth', '',
44 entry[1].append(('', 'depth', '',
45 _("limit the history fetched by distance from heads")))
45 _("limit the history fetched by distance from heads")))
46 # TODO(durin42): unify sparse/narrow --include/--exclude logic a bit
46 # TODO(durin42): unify sparse/narrow --include/--exclude logic a bit
47 if 'sparse' not in extensions.enabled():
47 if 'sparse' not in extensions.enabled():
48 entry[1].append(('', 'include', [],
48 entry[1].append(('', 'include', [],
49 _("specifically fetch this file/directory")))
49 _("specifically fetch this file/directory")))
50 entry[1].append(
50 entry[1].append(
51 ('', 'exclude', [],
51 ('', 'exclude', [],
52 _("do not fetch this file/directory, even if included")))
52 _("do not fetch this file/directory, even if included")))
53
53
54 entry = extensions.wrapcommand(commands.table, 'pull', pullnarrowcmd)
54 entry = extensions.wrapcommand(commands.table, 'pull', pullnarrowcmd)
55 entry[1].append(('', 'depth', '',
55 entry[1].append(('', 'depth', '',
56 _("limit the history fetched by distance from heads")))
56 _("limit the history fetched by distance from heads")))
57
57
58 extensions.wrapcommand(commands.table, 'archive', archivenarrowcmd)
58 extensions.wrapcommand(commands.table, 'archive', archivenarrowcmd)
59
59
60 def expandpull(pullop, includepats, excludepats):
60 def expandpull(pullop, includepats, excludepats):
61 if not narrowspec.needsexpansion(includepats):
61 if not narrowspec.needsexpansion(includepats):
62 return includepats, excludepats
62 return includepats, excludepats
63
63
64 heads = pullop.heads or pullop.rheads
64 heads = pullop.heads or pullop.rheads
65 includepats, excludepats = pullop.remote.expandnarrow(
65 includepats, excludepats = pullop.remote.expandnarrow(
66 includepats, excludepats, heads)
66 includepats, excludepats, heads)
67 pullop.repo.ui.debug('Expanded narrowspec to inc=%s, exc=%s\n' % (
67 pullop.repo.ui.debug('Expanded narrowspec to inc=%s, exc=%s\n' % (
68 includepats, excludepats))
68 includepats, excludepats))
69 return set(includepats), set(excludepats)
69 return set(includepats), set(excludepats)
70
70
71 def clonenarrowcmd(orig, ui, repo, *args, **opts):
71 def clonenarrowcmd(orig, ui, repo, *args, **opts):
72 """Wraps clone command, so 'hg clone' first wraps localrepo.clone()."""
72 """Wraps clone command, so 'hg clone' first wraps localrepo.clone()."""
73 opts = pycompat.byteskwargs(opts)
73 opts = pycompat.byteskwargs(opts)
74 wrappedextraprepare = util.nullcontextmanager()
74 wrappedextraprepare = util.nullcontextmanager()
75 opts_narrow = opts['narrow']
75 opts_narrow = opts['narrow']
76 if opts_narrow:
76 if opts_narrow:
77 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
77 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
78 # Create narrow spec patterns from clone flags
78 # Create narrow spec patterns from clone flags
79 includepats = narrowspec.parsepatterns(opts['include'])
79 includepats = narrowspec.parsepatterns(opts['include'])
80 excludepats = narrowspec.parsepatterns(opts['exclude'])
80 excludepats = narrowspec.parsepatterns(opts['exclude'])
81
81
82 # If necessary, ask the server to expand the narrowspec.
82 # If necessary, ask the server to expand the narrowspec.
83 includepats, excludepats = expandpull(
83 includepats, excludepats = expandpull(
84 pullop, includepats, excludepats)
84 pullop, includepats, excludepats)
85
85
86 if not includepats and excludepats:
86 if not includepats and excludepats:
87 # If nothing was included, we assume the user meant to include
87 # If nothing was included, we assume the user meant to include
88 # everything, except what they asked to exclude.
88 # everything, except what they asked to exclude.
89 includepats = {'path:.'}
89 includepats = {'path:.'}
90
90
91 narrowspec.save(pullop.repo, includepats, excludepats)
91 narrowspec.save(pullop.repo, includepats, excludepats)
92
92
93 # This will populate 'includepats' etc with the values from the
93 # This will populate 'includepats' etc with the values from the
94 # narrowspec we just saved.
94 # narrowspec we just saved.
95 orig(pullop, kwargs)
95 orig(pullop, kwargs)
96
96
97 if opts.get('depth'):
97 if opts.get('depth'):
98 kwargs['depth'] = opts['depth']
98 kwargs['depth'] = opts['depth']
99 wrappedextraprepare = extensions.wrappedfunction(exchange,
99 wrappedextraprepare = extensions.wrappedfunction(exchange,
100 '_pullbundle2extraprepare', pullbundle2extraprepare_widen)
100 '_pullbundle2extraprepare', pullbundle2extraprepare_widen)
101
101
102 def pullnarrow(orig, repo, *args, **kwargs):
102 def pullnarrow(orig, repo, *args, **kwargs):
103 narrowrepo.wraprepo(repo.unfiltered(), opts_narrow)
103 narrowrepo.wraprepo(repo.unfiltered(), opts_narrow)
104 if isinstance(repo, repoview.repoview):
104 if isinstance(repo, repoview.repoview):
105 repo.__class__.__bases__ = (repo.__class__.__bases__[0],
105 repo.__class__.__bases__ = (repo.__class__.__bases__[0],
106 repo.unfiltered().__class__)
106 repo.unfiltered().__class__)
107 if opts_narrow:
107 if opts_narrow:
108 repo.requirements.add(narrowrepo.REQUIREMENT)
108 repo.requirements.add(narrowrepo.REQUIREMENT)
109 repo._writerequirements()
109 repo._writerequirements()
110
110
111 return orig(repo, *args, **kwargs)
111 return orig(repo, *args, **kwargs)
112
112
113 wrappedpull = extensions.wrappedfunction(exchange, 'pull', pullnarrow)
113 wrappedpull = extensions.wrappedfunction(exchange, 'pull', pullnarrow)
114
114
115 with wrappedextraprepare, wrappedpull:
115 with wrappedextraprepare, wrappedpull:
116 return orig(ui, repo, *args, **pycompat.strkwargs(opts))
116 return orig(ui, repo, *args, **pycompat.strkwargs(opts))
117
117
118 def pullnarrowcmd(orig, ui, repo, *args, **opts):
118 def pullnarrowcmd(orig, ui, repo, *args, **opts):
119 """Wraps pull command to allow modifying narrow spec."""
119 """Wraps pull command to allow modifying narrow spec."""
120 wrappedextraprepare = util.nullcontextmanager()
120 wrappedextraprepare = util.nullcontextmanager()
121 if narrowrepo.REQUIREMENT in repo.requirements:
121 if narrowrepo.REQUIREMENT in repo.requirements:
122
122
123 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
123 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
124 orig(pullop, kwargs)
124 orig(pullop, kwargs)
125 if opts.get('depth'):
125 if opts.get('depth'):
126 kwargs['depth'] = opts['depth']
126 kwargs['depth'] = opts['depth']
127 wrappedextraprepare = extensions.wrappedfunction(exchange,
127 wrappedextraprepare = extensions.wrappedfunction(exchange,
128 '_pullbundle2extraprepare', pullbundle2extraprepare_widen)
128 '_pullbundle2extraprepare', pullbundle2extraprepare_widen)
129
129
130 with wrappedextraprepare:
130 with wrappedextraprepare:
131 return orig(ui, repo, *args, **opts)
131 return orig(ui, repo, *args, **opts)
132
132
133 def archivenarrowcmd(orig, ui, repo, *args, **opts):
133 def archivenarrowcmd(orig, ui, repo, *args, **opts):
134 """Wraps archive command to narrow the default includes."""
134 """Wraps archive command to narrow the default includes."""
135 if narrowrepo.REQUIREMENT in repo.requirements:
135 if narrowrepo.REQUIREMENT in repo.requirements:
136 repo_includes, repo_excludes = repo.narrowpats
136 repo_includes, repo_excludes = repo.narrowpats
137 includes = set(opts.get('include', []))
137 includes = set(opts.get('include', []))
138 excludes = set(opts.get('exclude', []))
138 excludes = set(opts.get('exclude', []))
139 includes, excludes, unused_invalid = narrowspec.restrictpatterns(
139 includes, excludes, unused_invalid = narrowspec.restrictpatterns(
140 includes, excludes, repo_includes, repo_excludes)
140 includes, excludes, repo_includes, repo_excludes)
141 if includes:
141 if includes:
142 opts['include'] = includes
142 opts['include'] = includes
143 if excludes:
143 if excludes:
144 opts['exclude'] = excludes
144 opts['exclude'] = excludes
145 return orig(ui, repo, *args, **opts)
145 return orig(ui, repo, *args, **opts)
146
146
147 def pullbundle2extraprepare(orig, pullop, kwargs):
147 def pullbundle2extraprepare(orig, pullop, kwargs):
148 repo = pullop.repo
148 repo = pullop.repo
149 if narrowrepo.REQUIREMENT not in repo.requirements:
149 if narrowrepo.REQUIREMENT not in repo.requirements:
150 return orig(pullop, kwargs)
150 return orig(pullop, kwargs)
151
151
152 if narrowbundle2.NARROWCAP not in pullop.remotebundle2caps:
152 if narrowbundle2.NARROWCAP not in pullop.remotebundle2caps:
153 raise error.Abort(_("server doesn't support narrow clones"))
153 raise error.Abort(_("server doesn't support narrow clones"))
154 orig(pullop, kwargs)
154 orig(pullop, kwargs)
155 kwargs['narrow'] = True
155 kwargs['narrow'] = True
156 include, exclude = repo.narrowpats
156 include, exclude = repo.narrowpats
157 kwargs['oldincludepats'] = include
157 kwargs['oldincludepats'] = include
158 kwargs['oldexcludepats'] = exclude
158 kwargs['oldexcludepats'] = exclude
159 kwargs['includepats'] = include
159 kwargs['includepats'] = include
160 kwargs['excludepats'] = exclude
160 kwargs['excludepats'] = exclude
161 kwargs['known'] = [node.hex(ctx.node()) for ctx in
161 kwargs['known'] = [node.hex(ctx.node()) for ctx in
162 repo.set('::%ln', pullop.common)
162 repo.set('::%ln', pullop.common)
163 if ctx.node() != node.nullid]
163 if ctx.node() != node.nullid]
164 if not kwargs['known']:
164 if not kwargs['known']:
165 # Mercurial serialized an empty list as '' and deserializes it as
165 # Mercurial serialized an empty list as '' and deserializes it as
166 # [''], so delete it instead to avoid handling the empty string on the
166 # [''], so delete it instead to avoid handling the empty string on the
167 # server.
167 # server.
168 del kwargs['known']
168 del kwargs['known']
169
169
170 extensions.wrapfunction(exchange,'_pullbundle2extraprepare',
170 extensions.wrapfunction(exchange,'_pullbundle2extraprepare',
171 pullbundle2extraprepare)
171 pullbundle2extraprepare)
172
172
173 def _narrow(ui, repo, remote, commoninc, oldincludes, oldexcludes,
173 def _narrow(ui, repo, remote, commoninc, oldincludes, oldexcludes,
174 newincludes, newexcludes, force):
174 newincludes, newexcludes, force):
175 oldmatch = narrowspec.match(repo.root, oldincludes, oldexcludes)
175 oldmatch = narrowspec.match(repo.root, oldincludes, oldexcludes)
176 newmatch = narrowspec.match(repo.root, newincludes, newexcludes)
176 newmatch = narrowspec.match(repo.root, newincludes, newexcludes)
177
177
178 # This is essentially doing "hg outgoing" to find all local-only
178 # This is essentially doing "hg outgoing" to find all local-only
179 # commits. We will then check that the local-only commits don't
179 # commits. We will then check that the local-only commits don't
180 # have any changes to files that will be untracked.
180 # have any changes to files that will be untracked.
181 unfi = repo.unfiltered()
181 unfi = repo.unfiltered()
182 outgoing = discovery.findcommonoutgoing(unfi, remote,
182 outgoing = discovery.findcommonoutgoing(unfi, remote,
183 commoninc=commoninc)
183 commoninc=commoninc)
184 ui.status(_('looking for local changes to affected paths\n'))
184 ui.status(_('looking for local changes to affected paths\n'))
185 localnodes = []
185 localnodes = []
186 for n in itertools.chain(outgoing.missing, outgoing.excluded):
186 for n in itertools.chain(outgoing.missing, outgoing.excluded):
187 if any(oldmatch(f) and not newmatch(f) for f in unfi[n].files()):
187 if any(oldmatch(f) and not newmatch(f) for f in unfi[n].files()):
188 localnodes.append(n)
188 localnodes.append(n)
189 revstostrip = unfi.revs('descendants(%ln)', localnodes)
189 revstostrip = unfi.revs('descendants(%ln)', localnodes)
190 hiddenrevs = repoview.filterrevs(repo, 'visible')
190 hiddenrevs = repoview.filterrevs(repo, 'visible')
191 visibletostrip = list(repo.changelog.node(r)
191 visibletostrip = list(repo.changelog.node(r)
192 for r in (revstostrip - hiddenrevs))
192 for r in (revstostrip - hiddenrevs))
193 if visibletostrip:
193 if visibletostrip:
194 ui.status(_('The following changeset(s) or their ancestors have '
194 ui.status(_('The following changeset(s) or their ancestors have '
195 'local changes not on the remote:\n'))
195 'local changes not on the remote:\n'))
196 maxnodes = 10
196 maxnodes = 10
197 if ui.verbose or len(visibletostrip) <= maxnodes:
197 if ui.verbose or len(visibletostrip) <= maxnodes:
198 for n in visibletostrip:
198 for n in visibletostrip:
199 ui.status('%s\n' % node.short(n))
199 ui.status('%s\n' % node.short(n))
200 else:
200 else:
201 for n in visibletostrip[:maxnodes]:
201 for n in visibletostrip[:maxnodes]:
202 ui.status('%s\n' % node.short(n))
202 ui.status('%s\n' % node.short(n))
203 ui.status(_('...and %d more, use --verbose to list all\n') %
203 ui.status(_('...and %d more, use --verbose to list all\n') %
204 (len(visibletostrip) - maxnodes))
204 (len(visibletostrip) - maxnodes))
205 if not force:
205 if not force:
206 raise error.Abort(_('local changes found'),
206 raise error.Abort(_('local changes found'),
207 hint=_('use --force-delete-local-changes to '
207 hint=_('use --force-delete-local-changes to '
208 'ignore'))
208 'ignore'))
209
209
210 if revstostrip:
210 if revstostrip:
211 tostrip = [unfi.changelog.node(r) for r in revstostrip]
211 tostrip = [unfi.changelog.node(r) for r in revstostrip]
212 if repo['.'].node() in tostrip:
212 if repo['.'].node() in tostrip:
213 # stripping working copy, so move to a different commit first
213 # stripping working copy, so move to a different commit first
214 urev = max(repo.revs('(::%n) - %ln + null',
214 urev = max(repo.revs('(::%n) - %ln + null',
215 repo['.'].node(), visibletostrip))
215 repo['.'].node(), visibletostrip))
216 hg.clean(repo, urev)
216 hg.clean(repo, urev)
217 repair.strip(ui, unfi, tostrip, topic='narrow')
217 repair.strip(ui, unfi, tostrip, topic='narrow')
218
218
219 todelete = []
219 todelete = []
220 for f, f2, size in repo.store.datafiles():
220 for f, f2, size in repo.store.datafiles():
221 if f.startswith('data/'):
221 if f.startswith('data/'):
222 file = f[5:-2]
222 file = f[5:-2]
223 if not newmatch(file):
223 if not newmatch(file):
224 todelete.append(f)
224 todelete.append(f)
225 elif f.startswith('meta/'):
225 elif f.startswith('meta/'):
226 dir = f[5:-13]
226 dir = f[5:-13]
227 dirs = ['.'] + sorted(util.dirs({dir})) + [dir]
227 dirs = ['.'] + sorted(util.dirs({dir})) + [dir]
228 include = True
228 include = True
229 for d in dirs:
229 for d in dirs:
230 visit = newmatch.visitdir(d)
230 visit = newmatch.visitdir(d)
231 if not visit:
231 if not visit:
232 include = False
232 include = False
233 break
233 break
234 if visit == 'all':
234 if visit == 'all':
235 break
235 break
236 if not include:
236 if not include:
237 todelete.append(f)
237 todelete.append(f)
238
238
239 repo.destroying()
239 repo.destroying()
240
240
241 with repo.transaction("narrowing"):
241 with repo.transaction("narrowing"):
242 for f in todelete:
242 for f in todelete:
243 ui.status(_('deleting %s\n') % f)
243 ui.status(_('deleting %s\n') % f)
244 util.unlinkpath(repo.svfs.join(f))
244 util.unlinkpath(repo.svfs.join(f))
245 repo.store.markremoved(f)
245 repo.store.markremoved(f)
246
246
247 for f in repo.dirstate:
247 for f in repo.dirstate:
248 if not newmatch(f):
248 if not newmatch(f):
249 repo.dirstate.drop(f)
249 repo.dirstate.drop(f)
250 repo.wvfs.unlinkpath(f)
250 repo.wvfs.unlinkpath(f)
251 repo.setnarrowpats(newincludes, newexcludes)
251 repo.setnarrowpats(newincludes, newexcludes)
252
252
253 repo.destroyed()
253 repo.destroyed()
254
254
255 def _widen(ui, repo, remote, commoninc, newincludes, newexcludes):
255 def _widen(ui, repo, remote, commoninc, newincludes, newexcludes):
256 newmatch = narrowspec.match(repo.root, newincludes, newexcludes)
256 newmatch = narrowspec.match(repo.root, newincludes, newexcludes)
257
257
258 # TODO(martinvonz): Get expansion working with widening/narrowing.
258 # TODO(martinvonz): Get expansion working with widening/narrowing.
259 if narrowspec.needsexpansion(newincludes):
259 if narrowspec.needsexpansion(newincludes):
260 raise error.Abort('Expansion not yet supported on pull')
260 raise error.Abort('Expansion not yet supported on pull')
261
261
262 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
262 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
263 orig(pullop, kwargs)
263 orig(pullop, kwargs)
264 # The old{in,ex}cludepats have already been set by orig()
264 # The old{in,ex}cludepats have already been set by orig()
265 kwargs['includepats'] = newincludes
265 kwargs['includepats'] = newincludes
266 kwargs['excludepats'] = newexcludes
266 kwargs['excludepats'] = newexcludes
267 wrappedextraprepare = extensions.wrappedfunction(exchange,
267 wrappedextraprepare = extensions.wrappedfunction(exchange,
268 '_pullbundle2extraprepare', pullbundle2extraprepare_widen)
268 '_pullbundle2extraprepare', pullbundle2extraprepare_widen)
269
269
270 # define a function that narrowbundle2 can call after creating the
270 # define a function that narrowbundle2 can call after creating the
271 # backup bundle, but before applying the bundle from the server
271 # backup bundle, but before applying the bundle from the server
272 def setnewnarrowpats():
272 def setnewnarrowpats():
273 repo.setnarrowpats(newincludes, newexcludes)
273 repo.setnarrowpats(newincludes, newexcludes)
274 repo.setnewnarrowpats = setnewnarrowpats
274 repo.setnewnarrowpats = setnewnarrowpats
275
275
276 ds = repo.dirstate
276 ds = repo.dirstate
277 p1, p2 = ds.p1(), ds.p2()
277 p1, p2 = ds.p1(), ds.p2()
278 with ds.parentchange():
278 with ds.parentchange():
279 ds.setparents(node.nullid, node.nullid)
279 ds.setparents(node.nullid, node.nullid)
280 common = commoninc[0]
280 common = commoninc[0]
281 with wrappedextraprepare:
281 with wrappedextraprepare:
282 exchange.pull(repo, remote, heads=common)
282 exchange.pull(repo, remote, heads=common)
283 with ds.parentchange():
283 with ds.parentchange():
284 ds.setparents(p1, p2)
284 ds.setparents(p1, p2)
285
285
286 actions = {k: [] for k in 'a am f g cd dc r dm dg m e k p pr'.split()}
286 actions = {k: [] for k in 'a am f g cd dc r dm dg m e k p pr'.split()}
287 addgaction = actions['g'].append
287 addgaction = actions['g'].append
288
288
289 mf = repo['.'].manifest().matches(newmatch)
289 mf = repo['.'].manifest().matches(newmatch)
290 for f, fn in mf.iteritems():
290 for f, fn in mf.iteritems():
291 if f not in repo.dirstate:
291 if f not in repo.dirstate:
292 addgaction((f, (mf.flags(f), False),
292 addgaction((f, (mf.flags(f), False),
293 "add from widened narrow clone"))
293 "add from widened narrow clone"))
294
294
295 merge.applyupdates(repo, actions, wctx=repo[None],
295 merge.applyupdates(repo, actions, wctx=repo[None],
296 mctx=repo['.'], overwrite=False)
296 mctx=repo['.'], overwrite=False)
297 merge.recordupdates(repo, actions, branchmerge=False)
297 merge.recordupdates(repo, actions, branchmerge=False)
298
298
299 # TODO(rdamazio): Make new matcher format and update description
299 # TODO(rdamazio): Make new matcher format and update description
300 @command('tracked',
300 @command('tracked',
301 [('', 'addinclude', [], _('new paths to include')),
301 [('', 'addinclude', [], _('new paths to include')),
302 ('', 'removeinclude', [], _('old paths to no longer include')),
302 ('', 'removeinclude', [], _('old paths to no longer include')),
303 ('', 'addexclude', [], _('new paths to exclude')),
303 ('', 'addexclude', [], _('new paths to exclude')),
304 ('', 'removeexclude', [], _('old paths to no longer exclude')),
304 ('', 'removeexclude', [], _('old paths to no longer exclude')),
305 ('', 'clear', False, _('whether to replace the existing narrowspec')),
305 ('', 'clear', False, _('whether to replace the existing narrowspec')),
306 ('', 'force-delete-local-changes', False,
306 ('', 'force-delete-local-changes', False,
307 _('forces deletion of local changes when narrowing')),
307 _('forces deletion of local changes when narrowing')),
308 ] + commands.remoteopts,
308 ] + commands.remoteopts,
309 _('[OPTIONS]... [REMOTE]'),
309 _('[OPTIONS]... [REMOTE]'),
310 inferrepo=True)
310 inferrepo=True)
311 def trackedcmd(ui, repo, remotepath=None, *pats, **opts):
311 def trackedcmd(ui, repo, remotepath=None, *pats, **opts):
312 """show or change the current narrowspec
312 """show or change the current narrowspec
313
313
314 With no argument, shows the current narrowspec entries, one per line. Each
314 With no argument, shows the current narrowspec entries, one per line. Each
315 line will be prefixed with 'I' or 'X' for included or excluded patterns,
315 line will be prefixed with 'I' or 'X' for included or excluded patterns,
316 respectively.
316 respectively.
317
317
318 The narrowspec is comprised of expressions to match remote files and/or
318 The narrowspec is comprised of expressions to match remote files and/or
319 directories that should be pulled into your client.
319 directories that should be pulled into your client.
320 The narrowspec has *include* and *exclude* expressions, with excludes always
320 The narrowspec has *include* and *exclude* expressions, with excludes always
321 trumping includes: that is, if a file matches an exclude expression, it will
321 trumping includes: that is, if a file matches an exclude expression, it will
322 be excluded even if it also matches an include expression.
322 be excluded even if it also matches an include expression.
323 Excluding files that were never included has no effect.
323 Excluding files that were never included has no effect.
324
324
325 Each included or excluded entry is in the format described by
325 Each included or excluded entry is in the format described by
326 'hg help patterns'.
326 'hg help patterns'.
327
327
328 The options allow you to add or remove included and excluded expressions.
328 The options allow you to add or remove included and excluded expressions.
329
329
330 If --clear is specified, then all previous includes and excludes are DROPPED
330 If --clear is specified, then all previous includes and excludes are DROPPED
331 and replaced by the new ones specified to --addinclude and --addexclude.
331 and replaced by the new ones specified to --addinclude and --addexclude.
332 If --clear is specified without any further options, the narrowspec will be
332 If --clear is specified without any further options, the narrowspec will be
333 empty and will not match any files.
333 empty and will not match any files.
334 """
334 """
335 opts = pycompat.byteskwargs(opts)
335 if narrowrepo.REQUIREMENT not in repo.requirements:
336 if narrowrepo.REQUIREMENT not in repo.requirements:
336 ui.warn(_('The narrow command is only supported on respositories cloned'
337 ui.warn(_('The narrow command is only supported on respositories cloned'
337 ' with --narrow.\n'))
338 ' with --narrow.\n'))
338 return 1
339 return 1
339
340
340 # Before supporting, decide whether it "hg tracked --clear" should mean
341 # Before supporting, decide whether it "hg tracked --clear" should mean
341 # tracking no paths or all paths.
342 # tracking no paths or all paths.
342 if opts['clear']:
343 if opts['clear']:
343 ui.warn(_('The --clear option is not yet supported.\n'))
344 ui.warn(_('The --clear option is not yet supported.\n'))
344 return 1
345 return 1
345
346
346 if narrowspec.needsexpansion(opts['addinclude'] + opts['addexclude']):
347 if narrowspec.needsexpansion(opts['addinclude'] + opts['addexclude']):
347 raise error.Abort('Expansion not yet supported on widen/narrow')
348 raise error.Abort('Expansion not yet supported on widen/narrow')
348
349
349 addedincludes = narrowspec.parsepatterns(opts['addinclude'])
350 addedincludes = narrowspec.parsepatterns(opts['addinclude'])
350 removedincludes = narrowspec.parsepatterns(opts['removeinclude'])
351 removedincludes = narrowspec.parsepatterns(opts['removeinclude'])
351 addedexcludes = narrowspec.parsepatterns(opts['addexclude'])
352 addedexcludes = narrowspec.parsepatterns(opts['addexclude'])
352 removedexcludes = narrowspec.parsepatterns(opts['removeexclude'])
353 removedexcludes = narrowspec.parsepatterns(opts['removeexclude'])
353 widening = addedincludes or removedexcludes
354 widening = addedincludes or removedexcludes
354 narrowing = removedincludes or addedexcludes
355 narrowing = removedincludes or addedexcludes
355 only_show = not widening and not narrowing
356 only_show = not widening and not narrowing
356
357
357 # Only print the current narrowspec.
358 # Only print the current narrowspec.
358 if only_show:
359 if only_show:
359 include, exclude = repo.narrowpats
360 include, exclude = repo.narrowpats
360
361
361 ui.pager('tracked')
362 ui.pager('tracked')
362 fm = ui.formatter('narrow', opts)
363 fm = ui.formatter('narrow', opts)
363 for i in sorted(include):
364 for i in sorted(include):
364 fm.startitem()
365 fm.startitem()
365 fm.write('status', '%s ', 'I', label='narrow.included')
366 fm.write('status', '%s ', 'I', label='narrow.included')
366 fm.write('pat', '%s\n', i, label='narrow.included')
367 fm.write('pat', '%s\n', i, label='narrow.included')
367 for i in sorted(exclude):
368 for i in sorted(exclude):
368 fm.startitem()
369 fm.startitem()
369 fm.write('status', '%s ', 'X', label='narrow.excluded')
370 fm.write('status', '%s ', 'X', label='narrow.excluded')
370 fm.write('pat', '%s\n', i, label='narrow.excluded')
371 fm.write('pat', '%s\n', i, label='narrow.excluded')
371 fm.end()
372 fm.end()
372 return 0
373 return 0
373
374
374 with repo.wlock(), repo.lock():
375 with repo.wlock(), repo.lock():
375 cmdutil.bailifchanged(repo)
376 cmdutil.bailifchanged(repo)
376
377
377 # Find the revisions we have in common with the remote. These will
378 # Find the revisions we have in common with the remote. These will
378 # be used for finding local-only changes for narrowing. They will
379 # be used for finding local-only changes for narrowing. They will
379 # also define the set of revisions to update for widening.
380 # also define the set of revisions to update for widening.
380 remotepath = ui.expandpath(remotepath or 'default')
381 remotepath = ui.expandpath(remotepath or 'default')
381 url, branches = hg.parseurl(remotepath)
382 url, branches = hg.parseurl(remotepath)
382 ui.status(_('comparing with %s\n') % util.hidepassword(url))
383 ui.status(_('comparing with %s\n') % util.hidepassword(url))
383 remote = hg.peer(repo, opts, url)
384 remote = hg.peer(repo, opts, url)
384 commoninc = discovery.findcommonincoming(repo, remote)
385 commoninc = discovery.findcommonincoming(repo, remote)
385
386
386 oldincludes, oldexcludes = repo.narrowpats
387 oldincludes, oldexcludes = repo.narrowpats
387 if narrowing:
388 if narrowing:
388 newincludes = oldincludes - removedincludes
389 newincludes = oldincludes - removedincludes
389 newexcludes = oldexcludes | addedexcludes
390 newexcludes = oldexcludes | addedexcludes
390 _narrow(ui, repo, remote, commoninc, oldincludes, oldexcludes,
391 _narrow(ui, repo, remote, commoninc, oldincludes, oldexcludes,
391 newincludes, newexcludes,
392 newincludes, newexcludes,
392 opts['force_delete_local_changes'])
393 opts['force_delete_local_changes'])
393 # _narrow() updated the narrowspec and _widen() below needs to
394 # _narrow() updated the narrowspec and _widen() below needs to
394 # use the updated values as its base (otherwise removed includes
395 # use the updated values as its base (otherwise removed includes
395 # and addedexcludes will be lost in the resulting narrowspec)
396 # and addedexcludes will be lost in the resulting narrowspec)
396 oldincludes = newincludes
397 oldincludes = newincludes
397 oldexcludes = newexcludes
398 oldexcludes = newexcludes
398
399
399 if widening:
400 if widening:
400 newincludes = oldincludes | addedincludes
401 newincludes = oldincludes | addedincludes
401 newexcludes = oldexcludes - removedexcludes
402 newexcludes = oldexcludes - removedexcludes
402 _widen(ui, repo, remote, commoninc, newincludes, newexcludes)
403 _widen(ui, repo, remote, commoninc, newincludes, newexcludes)
403
404
404 return 0
405 return 0
General Comments 0
You need to be logged in to leave comments. Login now