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