##// END OF EJS Templates
sparse: drop the useless wrapping of `dirstate.set_untracked`...
marmoute -
r50253:05da1f16 default
parent child Browse files
Show More
@@ -1,430 +1,429
1 # sparse.py - allow sparse checkouts of the working directory
1 # sparse.py - allow sparse checkouts of the working directory
2 #
2 #
3 # Copyright 2014 Facebook, Inc.
3 # Copyright 2014 Facebook, 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
7
8 """allow sparse checkouts of the working directory (EXPERIMENTAL)
8 """allow sparse checkouts of the working directory (EXPERIMENTAL)
9
9
10 (This extension is not yet protected by backwards compatibility
10 (This extension is not yet protected by backwards compatibility
11 guarantees. Any aspect may break in future releases until this
11 guarantees. Any aspect may break in future releases until this
12 notice is removed.)
12 notice is removed.)
13
13
14 This extension allows the working directory to only consist of a
14 This extension allows the working directory to only consist of a
15 subset of files for the revision. This allows specific files or
15 subset of files for the revision. This allows specific files or
16 directories to be explicitly included or excluded. Many repository
16 directories to be explicitly included or excluded. Many repository
17 operations have performance proportional to the number of files in
17 operations have performance proportional to the number of files in
18 the working directory. So only realizing a subset of files in the
18 the working directory. So only realizing a subset of files in the
19 working directory can improve performance.
19 working directory can improve performance.
20
20
21 Sparse Config Files
21 Sparse Config Files
22 -------------------
22 -------------------
23
23
24 The set of files that are part of a sparse checkout are defined by
24 The set of files that are part of a sparse checkout are defined by
25 a sparse config file. The file defines 3 things: includes (files to
25 a sparse config file. The file defines 3 things: includes (files to
26 include in the sparse checkout), excludes (files to exclude from the
26 include in the sparse checkout), excludes (files to exclude from the
27 sparse checkout), and profiles (links to other config files).
27 sparse checkout), and profiles (links to other config files).
28
28
29 The file format is newline delimited. Empty lines and lines beginning
29 The file format is newline delimited. Empty lines and lines beginning
30 with ``#`` are ignored.
30 with ``#`` are ignored.
31
31
32 Lines beginning with ``%include `` denote another sparse config file
32 Lines beginning with ``%include `` denote another sparse config file
33 to include. e.g. ``%include tests.sparse``. The filename is relative
33 to include. e.g. ``%include tests.sparse``. The filename is relative
34 to the repository root.
34 to the repository root.
35
35
36 The special lines ``[include]`` and ``[exclude]`` denote the section
36 The special lines ``[include]`` and ``[exclude]`` denote the section
37 for includes and excludes that follow, respectively. It is illegal to
37 for includes and excludes that follow, respectively. It is illegal to
38 have ``[include]`` after ``[exclude]``.
38 have ``[include]`` after ``[exclude]``.
39
39
40 Non-special lines resemble file patterns to be added to either includes
40 Non-special lines resemble file patterns to be added to either includes
41 or excludes. The syntax of these lines is documented by :hg:`help patterns`.
41 or excludes. The syntax of these lines is documented by :hg:`help patterns`.
42 Patterns are interpreted as ``glob:`` by default and match against the
42 Patterns are interpreted as ``glob:`` by default and match against the
43 root of the repository.
43 root of the repository.
44
44
45 Exclusion patterns take precedence over inclusion patterns. So even
45 Exclusion patterns take precedence over inclusion patterns. So even
46 if a file is explicitly included, an ``[exclude]`` entry can remove it.
46 if a file is explicitly included, an ``[exclude]`` entry can remove it.
47
47
48 For example, say you have a repository with 3 directories, ``frontend/``,
48 For example, say you have a repository with 3 directories, ``frontend/``,
49 ``backend/``, and ``tools/``. ``frontend/`` and ``backend/`` correspond
49 ``backend/``, and ``tools/``. ``frontend/`` and ``backend/`` correspond
50 to different projects and it is uncommon for someone working on one
50 to different projects and it is uncommon for someone working on one
51 to need the files for the other. But ``tools/`` contains files shared
51 to need the files for the other. But ``tools/`` contains files shared
52 between both projects. Your sparse config files may resemble::
52 between both projects. Your sparse config files may resemble::
53
53
54 # frontend.sparse
54 # frontend.sparse
55 frontend/**
55 frontend/**
56 tools/**
56 tools/**
57
57
58 # backend.sparse
58 # backend.sparse
59 backend/**
59 backend/**
60 tools/**
60 tools/**
61
61
62 Say the backend grows in size. Or there's a directory with thousands
62 Say the backend grows in size. Or there's a directory with thousands
63 of files you wish to exclude. You can modify the profile to exclude
63 of files you wish to exclude. You can modify the profile to exclude
64 certain files::
64 certain files::
65
65
66 [include]
66 [include]
67 backend/**
67 backend/**
68 tools/**
68 tools/**
69
69
70 [exclude]
70 [exclude]
71 tools/tests/**
71 tools/tests/**
72 """
72 """
73
73
74
74
75 from mercurial.i18n import _
75 from mercurial.i18n import _
76 from mercurial.pycompat import setattr
76 from mercurial.pycompat import setattr
77 from mercurial import (
77 from mercurial import (
78 cmdutil,
78 cmdutil,
79 commands,
79 commands,
80 dirstate,
80 dirstate,
81 error,
81 error,
82 extensions,
82 extensions,
83 logcmdutil,
83 logcmdutil,
84 merge as mergemod,
84 merge as mergemod,
85 pycompat,
85 pycompat,
86 registrar,
86 registrar,
87 sparse,
87 sparse,
88 util,
88 util,
89 )
89 )
90
90
91 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
91 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
92 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
92 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
93 # be specifying the version(s) of Mercurial they are tested with, or
93 # be specifying the version(s) of Mercurial they are tested with, or
94 # leave the attribute unspecified.
94 # leave the attribute unspecified.
95 testedwith = b'ships-with-hg-core'
95 testedwith = b'ships-with-hg-core'
96
96
97 cmdtable = {}
97 cmdtable = {}
98 command = registrar.command(cmdtable)
98 command = registrar.command(cmdtable)
99
99
100
100
101 def extsetup(ui):
101 def extsetup(ui):
102 sparse.enabled = True
102 sparse.enabled = True
103
103
104 _setupclone(ui)
104 _setupclone(ui)
105 _setuplog(ui)
105 _setuplog(ui)
106 _setupadd(ui)
106 _setupadd(ui)
107 _setupdirstate(ui)
107 _setupdirstate(ui)
108
108
109
109
110 def replacefilecache(cls, propname, replacement):
110 def replacefilecache(cls, propname, replacement):
111 """Replace a filecache property with a new class. This allows changing the
111 """Replace a filecache property with a new class. This allows changing the
112 cache invalidation condition."""
112 cache invalidation condition."""
113 origcls = cls
113 origcls = cls
114 assert callable(replacement)
114 assert callable(replacement)
115 while cls is not object:
115 while cls is not object:
116 if propname in cls.__dict__:
116 if propname in cls.__dict__:
117 orig = cls.__dict__[propname]
117 orig = cls.__dict__[propname]
118 setattr(cls, propname, replacement(orig))
118 setattr(cls, propname, replacement(orig))
119 break
119 break
120 cls = cls.__bases__[0]
120 cls = cls.__bases__[0]
121
121
122 if cls is object:
122 if cls is object:
123 raise AttributeError(
123 raise AttributeError(
124 _(b"type '%s' has no property '%s'") % (origcls, propname)
124 _(b"type '%s' has no property '%s'") % (origcls, propname)
125 )
125 )
126
126
127
127
128 def _setuplog(ui):
128 def _setuplog(ui):
129 entry = commands.table[b'log|history']
129 entry = commands.table[b'log|history']
130 entry[1].append(
130 entry[1].append(
131 (
131 (
132 b'',
132 b'',
133 b'sparse',
133 b'sparse',
134 None,
134 None,
135 b"limit to changesets affecting the sparse checkout",
135 b"limit to changesets affecting the sparse checkout",
136 )
136 )
137 )
137 )
138
138
139 def _initialrevs(orig, repo, wopts):
139 def _initialrevs(orig, repo, wopts):
140 revs = orig(repo, wopts)
140 revs = orig(repo, wopts)
141 if wopts.opts.get(b'sparse'):
141 if wopts.opts.get(b'sparse'):
142 sparsematch = sparse.matcher(repo)
142 sparsematch = sparse.matcher(repo)
143
143
144 def ctxmatch(rev):
144 def ctxmatch(rev):
145 ctx = repo[rev]
145 ctx = repo[rev]
146 return any(f for f in ctx.files() if sparsematch(f))
146 return any(f for f in ctx.files() if sparsematch(f))
147
147
148 revs = revs.filter(ctxmatch)
148 revs = revs.filter(ctxmatch)
149 return revs
149 return revs
150
150
151 extensions.wrapfunction(logcmdutil, b'_initialrevs', _initialrevs)
151 extensions.wrapfunction(logcmdutil, b'_initialrevs', _initialrevs)
152
152
153
153
154 def _clonesparsecmd(orig, ui, repo, *args, **opts):
154 def _clonesparsecmd(orig, ui, repo, *args, **opts):
155 include = opts.get('include')
155 include = opts.get('include')
156 exclude = opts.get('exclude')
156 exclude = opts.get('exclude')
157 enableprofile = opts.get('enable_profile')
157 enableprofile = opts.get('enable_profile')
158 narrow_pat = opts.get('narrow')
158 narrow_pat = opts.get('narrow')
159
159
160 # if --narrow is passed, it means they are includes and excludes for narrow
160 # if --narrow is passed, it means they are includes and excludes for narrow
161 # clone
161 # clone
162 if not narrow_pat and (include or exclude or enableprofile):
162 if not narrow_pat and (include or exclude or enableprofile):
163
163
164 def clonesparse(orig, ctx, *args, **kwargs):
164 def clonesparse(orig, ctx, *args, **kwargs):
165 sparse.updateconfig(
165 sparse.updateconfig(
166 ctx.repo().unfiltered(),
166 ctx.repo().unfiltered(),
167 {},
167 {},
168 include=include,
168 include=include,
169 exclude=exclude,
169 exclude=exclude,
170 enableprofile=enableprofile,
170 enableprofile=enableprofile,
171 usereporootpaths=True,
171 usereporootpaths=True,
172 )
172 )
173 return orig(ctx, *args, **kwargs)
173 return orig(ctx, *args, **kwargs)
174
174
175 extensions.wrapfunction(mergemod, b'update', clonesparse)
175 extensions.wrapfunction(mergemod, b'update', clonesparse)
176 return orig(ui, repo, *args, **opts)
176 return orig(ui, repo, *args, **opts)
177
177
178
178
179 def _setupclone(ui):
179 def _setupclone(ui):
180 entry = commands.table[b'clone']
180 entry = commands.table[b'clone']
181 entry[1].append((b'', b'enable-profile', [], b'enable a sparse profile'))
181 entry[1].append((b'', b'enable-profile', [], b'enable a sparse profile'))
182 entry[1].append((b'', b'include', [], b'include sparse pattern'))
182 entry[1].append((b'', b'include', [], b'include sparse pattern'))
183 entry[1].append((b'', b'exclude', [], b'exclude sparse pattern'))
183 entry[1].append((b'', b'exclude', [], b'exclude sparse pattern'))
184 extensions.wrapcommand(commands.table, b'clone', _clonesparsecmd)
184 extensions.wrapcommand(commands.table, b'clone', _clonesparsecmd)
185
185
186
186
187 def _setupadd(ui):
187 def _setupadd(ui):
188 entry = commands.table[b'add']
188 entry = commands.table[b'add']
189 entry[1].append(
189 entry[1].append(
190 (
190 (
191 b's',
191 b's',
192 b'sparse',
192 b'sparse',
193 None,
193 None,
194 b'also include directories of added files in sparse config',
194 b'also include directories of added files in sparse config',
195 )
195 )
196 )
196 )
197
197
198 def _add(orig, ui, repo, *pats, **opts):
198 def _add(orig, ui, repo, *pats, **opts):
199 if opts.get('sparse'):
199 if opts.get('sparse'):
200 dirs = set()
200 dirs = set()
201 for pat in pats:
201 for pat in pats:
202 dirname, basename = util.split(pat)
202 dirname, basename = util.split(pat)
203 dirs.add(dirname)
203 dirs.add(dirname)
204 sparse.updateconfig(repo, opts, include=list(dirs))
204 sparse.updateconfig(repo, opts, include=list(dirs))
205 return orig(ui, repo, *pats, **opts)
205 return orig(ui, repo, *pats, **opts)
206
206
207 extensions.wrapcommand(commands.table, b'add', _add)
207 extensions.wrapcommand(commands.table, b'add', _add)
208
208
209
209
210 def _setupdirstate(ui):
210 def _setupdirstate(ui):
211 """Modify the dirstate to prevent stat'ing excluded files,
211 """Modify the dirstate to prevent stat'ing excluded files,
212 and to prevent modifications to files outside the checkout.
212 and to prevent modifications to files outside the checkout.
213 """
213 """
214
214
215 # Prevent adding files that are outside the sparse checkout
215 # Prevent adding files that are outside the sparse checkout
216 editfuncs = [
216 editfuncs = [
217 b'set_tracked',
217 b'set_tracked',
218 b'set_untracked',
219 b'copy',
218 b'copy',
220 ]
219 ]
221 hint = _(
220 hint = _(
222 b'include file with `hg debugsparse --include <pattern>` or use '
221 b'include file with `hg debugsparse --include <pattern>` or use '
223 + b'`hg add -s <file>` to include file directory while adding'
222 + b'`hg add -s <file>` to include file directory while adding'
224 )
223 )
225 for func in editfuncs:
224 for func in editfuncs:
226
225
227 def _wrapper(orig, self, *args, **kwargs):
226 def _wrapper(orig, self, *args, **kwargs):
228 sparsematch = self._sparsematcher
227 sparsematch = self._sparsematcher
229 if sparsematch is not None and not sparsematch.always():
228 if sparsematch is not None and not sparsematch.always():
230 for f in args:
229 for f in args:
231 if f is not None and not sparsematch(f) and f not in self:
230 if f is not None and not sparsematch(f) and f not in self:
232 raise error.Abort(
231 raise error.Abort(
233 _(
232 _(
234 b"cannot add '%s' - it is outside "
233 b"cannot add '%s' - it is outside "
235 b"the sparse checkout"
234 b"the sparse checkout"
236 )
235 )
237 % f,
236 % f,
238 hint=hint,
237 hint=hint,
239 )
238 )
240 return orig(self, *args, **kwargs)
239 return orig(self, *args, **kwargs)
241
240
242 extensions.wrapfunction(dirstate.dirstate, func, _wrapper)
241 extensions.wrapfunction(dirstate.dirstate, func, _wrapper)
243
242
244
243
245 @command(
244 @command(
246 b'debugsparse',
245 b'debugsparse',
247 [
246 [
248 (
247 (
249 b'I',
248 b'I',
250 b'include',
249 b'include',
251 [],
250 [],
252 _(b'include files in the sparse checkout'),
251 _(b'include files in the sparse checkout'),
253 _(b'PATTERN'),
252 _(b'PATTERN'),
254 ),
253 ),
255 (
254 (
256 b'X',
255 b'X',
257 b'exclude',
256 b'exclude',
258 [],
257 [],
259 _(b'exclude files in the sparse checkout'),
258 _(b'exclude files in the sparse checkout'),
260 _(b'PATTERN'),
259 _(b'PATTERN'),
261 ),
260 ),
262 (
261 (
263 b'd',
262 b'd',
264 b'delete',
263 b'delete',
265 [],
264 [],
266 _(b'delete an include/exclude rule'),
265 _(b'delete an include/exclude rule'),
267 _(b'PATTERN'),
266 _(b'PATTERN'),
268 ),
267 ),
269 (
268 (
270 b'f',
269 b'f',
271 b'force',
270 b'force',
272 False,
271 False,
273 _(b'allow changing rules even with pending changes'),
272 _(b'allow changing rules even with pending changes'),
274 ),
273 ),
275 (
274 (
276 b'',
275 b'',
277 b'enable-profile',
276 b'enable-profile',
278 [],
277 [],
279 _(b'enables the specified profile'),
278 _(b'enables the specified profile'),
280 _(b'PATTERN'),
279 _(b'PATTERN'),
281 ),
280 ),
282 (
281 (
283 b'',
282 b'',
284 b'disable-profile',
283 b'disable-profile',
285 [],
284 [],
286 _(b'disables the specified profile'),
285 _(b'disables the specified profile'),
287 _(b'PATTERN'),
286 _(b'PATTERN'),
288 ),
287 ),
289 (
288 (
290 b'',
289 b'',
291 b'import-rules',
290 b'import-rules',
292 [],
291 [],
293 _(b'imports rules from a file'),
292 _(b'imports rules from a file'),
294 _(b'PATTERN'),
293 _(b'PATTERN'),
295 ),
294 ),
296 (b'', b'clear-rules', False, _(b'clears local include/exclude rules')),
295 (b'', b'clear-rules', False, _(b'clears local include/exclude rules')),
297 (
296 (
298 b'',
297 b'',
299 b'refresh',
298 b'refresh',
300 False,
299 False,
301 _(b'updates the working after sparseness changes'),
300 _(b'updates the working after sparseness changes'),
302 ),
301 ),
303 (b'', b'reset', False, _(b'makes the repo full again')),
302 (b'', b'reset', False, _(b'makes the repo full again')),
304 ]
303 ]
305 + commands.templateopts,
304 + commands.templateopts,
306 _(b'[--OPTION]'),
305 _(b'[--OPTION]'),
307 helpbasic=True,
306 helpbasic=True,
308 )
307 )
309 def debugsparse(ui, repo, **opts):
308 def debugsparse(ui, repo, **opts):
310 """make the current checkout sparse, or edit the existing checkout
309 """make the current checkout sparse, or edit the existing checkout
311
310
312 The sparse command is used to make the current checkout sparse.
311 The sparse command is used to make the current checkout sparse.
313 This means files that don't meet the sparse condition will not be
312 This means files that don't meet the sparse condition will not be
314 written to disk, or show up in any working copy operations. It does
313 written to disk, or show up in any working copy operations. It does
315 not affect files in history in any way.
314 not affect files in history in any way.
316
315
317 Passing no arguments prints the currently applied sparse rules.
316 Passing no arguments prints the currently applied sparse rules.
318
317
319 --include and --exclude are used to add and remove files from the sparse
318 --include and --exclude are used to add and remove files from the sparse
320 checkout. The effects of adding an include or exclude rule are applied
319 checkout. The effects of adding an include or exclude rule are applied
321 immediately. If applying the new rule would cause a file with pending
320 immediately. If applying the new rule would cause a file with pending
322 changes to be added or removed, the command will fail. Pass --force to
321 changes to be added or removed, the command will fail. Pass --force to
323 force a rule change even with pending changes (the changes on disk will
322 force a rule change even with pending changes (the changes on disk will
324 be preserved).
323 be preserved).
325
324
326 --delete removes an existing include/exclude rule. The effects are
325 --delete removes an existing include/exclude rule. The effects are
327 immediate.
326 immediate.
328
327
329 --refresh refreshes the files on disk based on the sparse rules. This is
328 --refresh refreshes the files on disk based on the sparse rules. This is
330 only necessary if .hg/sparse was changed by hand.
329 only necessary if .hg/sparse was changed by hand.
331
330
332 --enable-profile and --disable-profile accept a path to a .hgsparse file.
331 --enable-profile and --disable-profile accept a path to a .hgsparse file.
333 This allows defining sparse checkouts and tracking them inside the
332 This allows defining sparse checkouts and tracking them inside the
334 repository. This is useful for defining commonly used sparse checkouts for
333 repository. This is useful for defining commonly used sparse checkouts for
335 many people to use. As the profile definition changes over time, the sparse
334 many people to use. As the profile definition changes over time, the sparse
336 checkout will automatically be updated appropriately, depending on which
335 checkout will automatically be updated appropriately, depending on which
337 changeset is checked out. Changes to .hgsparse are not applied until they
336 changeset is checked out. Changes to .hgsparse are not applied until they
338 have been committed.
337 have been committed.
339
338
340 --import-rules accepts a path to a file containing rules in the .hgsparse
339 --import-rules accepts a path to a file containing rules in the .hgsparse
341 format, allowing you to add --include, --exclude and --enable-profile rules
340 format, allowing you to add --include, --exclude and --enable-profile rules
342 in bulk. Like the --include, --exclude and --enable-profile switches, the
341 in bulk. Like the --include, --exclude and --enable-profile switches, the
343 changes are applied immediately.
342 changes are applied immediately.
344
343
345 --clear-rules removes all local include and exclude rules, while leaving
344 --clear-rules removes all local include and exclude rules, while leaving
346 any enabled profiles in place.
345 any enabled profiles in place.
347
346
348 Returns 0 if editing the sparse checkout succeeds.
347 Returns 0 if editing the sparse checkout succeeds.
349 """
348 """
350 opts = pycompat.byteskwargs(opts)
349 opts = pycompat.byteskwargs(opts)
351 include = opts.get(b'include')
350 include = opts.get(b'include')
352 exclude = opts.get(b'exclude')
351 exclude = opts.get(b'exclude')
353 force = opts.get(b'force')
352 force = opts.get(b'force')
354 enableprofile = opts.get(b'enable_profile')
353 enableprofile = opts.get(b'enable_profile')
355 disableprofile = opts.get(b'disable_profile')
354 disableprofile = opts.get(b'disable_profile')
356 importrules = opts.get(b'import_rules')
355 importrules = opts.get(b'import_rules')
357 clearrules = opts.get(b'clear_rules')
356 clearrules = opts.get(b'clear_rules')
358 delete = opts.get(b'delete')
357 delete = opts.get(b'delete')
359 refresh = opts.get(b'refresh')
358 refresh = opts.get(b'refresh')
360 reset = opts.get(b'reset')
359 reset = opts.get(b'reset')
361 action = cmdutil.check_at_most_one_arg(
360 action = cmdutil.check_at_most_one_arg(
362 opts, b'import_rules', b'clear_rules', b'refresh'
361 opts, b'import_rules', b'clear_rules', b'refresh'
363 )
362 )
364 updateconfig = bool(
363 updateconfig = bool(
365 include or exclude or delete or reset or enableprofile or disableprofile
364 include or exclude or delete or reset or enableprofile or disableprofile
366 )
365 )
367 count = sum([updateconfig, bool(action)])
366 count = sum([updateconfig, bool(action)])
368 if count > 1:
367 if count > 1:
369 raise error.Abort(_(b"too many flags specified"))
368 raise error.Abort(_(b"too many flags specified"))
370
369
371 # enable sparse on repo even if the requirements is missing.
370 # enable sparse on repo even if the requirements is missing.
372 repo._has_sparse = True
371 repo._has_sparse = True
373
372
374 if count == 0:
373 if count == 0:
375 if repo.vfs.exists(b'sparse'):
374 if repo.vfs.exists(b'sparse'):
376 ui.status(repo.vfs.read(b"sparse") + b"\n")
375 ui.status(repo.vfs.read(b"sparse") + b"\n")
377 temporaryincludes = sparse.readtemporaryincludes(repo)
376 temporaryincludes = sparse.readtemporaryincludes(repo)
378 if temporaryincludes:
377 if temporaryincludes:
379 ui.status(
378 ui.status(
380 _(b"Temporarily Included Files (for merge/rebase):\n")
379 _(b"Temporarily Included Files (for merge/rebase):\n")
381 )
380 )
382 ui.status((b"\n".join(temporaryincludes) + b"\n"))
381 ui.status((b"\n".join(temporaryincludes) + b"\n"))
383 return
382 return
384 else:
383 else:
385 raise error.Abort(
384 raise error.Abort(
386 _(
385 _(
387 b'the debugsparse command is only supported on'
386 b'the debugsparse command is only supported on'
388 b' sparse repositories'
387 b' sparse repositories'
389 )
388 )
390 )
389 )
391
390
392 if updateconfig:
391 if updateconfig:
393 sparse.updateconfig(
392 sparse.updateconfig(
394 repo,
393 repo,
395 opts,
394 opts,
396 include=include,
395 include=include,
397 exclude=exclude,
396 exclude=exclude,
398 reset=reset,
397 reset=reset,
399 delete=delete,
398 delete=delete,
400 enableprofile=enableprofile,
399 enableprofile=enableprofile,
401 disableprofile=disableprofile,
400 disableprofile=disableprofile,
402 force=force,
401 force=force,
403 )
402 )
404
403
405 if importrules:
404 if importrules:
406 sparse.importfromfiles(repo, opts, importrules, force=force)
405 sparse.importfromfiles(repo, opts, importrules, force=force)
407
406
408 if clearrules:
407 if clearrules:
409 sparse.clearrules(repo, force=force)
408 sparse.clearrules(repo, force=force)
410
409
411 if refresh:
410 if refresh:
412 try:
411 try:
413 wlock = repo.wlock()
412 wlock = repo.wlock()
414 fcounts = map(
413 fcounts = map(
415 len,
414 len,
416 sparse.refreshwdir(
415 sparse.refreshwdir(
417 repo, repo.status(), sparse.matcher(repo), force=force
416 repo, repo.status(), sparse.matcher(repo), force=force
418 ),
417 ),
419 )
418 )
420 sparse.printchanges(
419 sparse.printchanges(
421 ui,
420 ui,
422 opts,
421 opts,
423 added=fcounts[0],
422 added=fcounts[0],
424 dropped=fcounts[1],
423 dropped=fcounts[1],
425 conflicting=fcounts[2],
424 conflicting=fcounts[2],
426 )
425 )
427 finally:
426 finally:
428 wlock.release()
427 wlock.release()
429
428
430 del repo._has_sparse
429 del repo._has_sparse
General Comments 0
You need to be logged in to leave comments. Login now