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