##// END OF EJS Templates
py3: use byteskwargs in sparse.py...
Gregory Szorc -
r35193:d8d06a93 default
parent child Browse files
Show More
@@ -1,337 +1,339 b''
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 from __future__ import absolute_import
74 from __future__ import absolute_import
75
75
76 from mercurial.i18n import _
76 from mercurial.i18n import _
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 hg,
83 hg,
84 match as matchmod,
84 match as matchmod,
85 pycompat,
85 registrar,
86 registrar,
86 sparse,
87 sparse,
87 util,
88 util,
88 )
89 )
89
90
90 # 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
91 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
92 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
92 # 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
93 # leave the attribute unspecified.
94 # leave the attribute unspecified.
94 testedwith = 'ships-with-hg-core'
95 testedwith = 'ships-with-hg-core'
95
96
96 cmdtable = {}
97 cmdtable = {}
97 command = registrar.command(cmdtable)
98 command = registrar.command(cmdtable)
98
99
99 def extsetup(ui):
100 def extsetup(ui):
100 sparse.enabled = True
101 sparse.enabled = True
101
102
102 _setupclone(ui)
103 _setupclone(ui)
103 _setuplog(ui)
104 _setuplog(ui)
104 _setupadd(ui)
105 _setupadd(ui)
105 _setupdirstate(ui)
106 _setupdirstate(ui)
106
107
107 def replacefilecache(cls, propname, replacement):
108 def replacefilecache(cls, propname, replacement):
108 """Replace a filecache property with a new class. This allows changing the
109 """Replace a filecache property with a new class. This allows changing the
109 cache invalidation condition."""
110 cache invalidation condition."""
110 origcls = cls
111 origcls = cls
111 assert callable(replacement)
112 assert callable(replacement)
112 while cls is not object:
113 while cls is not object:
113 if propname in cls.__dict__:
114 if propname in cls.__dict__:
114 orig = cls.__dict__[propname]
115 orig = cls.__dict__[propname]
115 setattr(cls, propname, replacement(orig))
116 setattr(cls, propname, replacement(orig))
116 break
117 break
117 cls = cls.__bases__[0]
118 cls = cls.__bases__[0]
118
119
119 if cls is object:
120 if cls is object:
120 raise AttributeError(_("type '%s' has no property '%s'") % (origcls,
121 raise AttributeError(_("type '%s' has no property '%s'") % (origcls,
121 propname))
122 propname))
122
123
123 def _setuplog(ui):
124 def _setuplog(ui):
124 entry = commands.table['^log|history']
125 entry = commands.table['^log|history']
125 entry[1].append(('', 'sparse', None,
126 entry[1].append(('', 'sparse', None,
126 "limit to changesets affecting the sparse checkout"))
127 "limit to changesets affecting the sparse checkout"))
127
128
128 def _logrevs(orig, repo, opts):
129 def _logrevs(orig, repo, opts):
129 revs = orig(repo, opts)
130 revs = orig(repo, opts)
130 if opts.get('sparse'):
131 if opts.get('sparse'):
131 sparsematch = sparse.matcher(repo)
132 sparsematch = sparse.matcher(repo)
132 def ctxmatch(rev):
133 def ctxmatch(rev):
133 ctx = repo[rev]
134 ctx = repo[rev]
134 return any(f for f in ctx.files() if sparsematch(f))
135 return any(f for f in ctx.files() if sparsematch(f))
135 revs = revs.filter(ctxmatch)
136 revs = revs.filter(ctxmatch)
136 return revs
137 return revs
137 extensions.wrapfunction(cmdutil, '_logrevs', _logrevs)
138 extensions.wrapfunction(cmdutil, '_logrevs', _logrevs)
138
139
139 def _clonesparsecmd(orig, ui, repo, *args, **opts):
140 def _clonesparsecmd(orig, ui, repo, *args, **opts):
140 include_pat = opts.get('include')
141 include_pat = opts.get('include')
141 exclude_pat = opts.get('exclude')
142 exclude_pat = opts.get('exclude')
142 enableprofile_pat = opts.get('enable_profile')
143 enableprofile_pat = opts.get('enable_profile')
143 include = exclude = enableprofile = False
144 include = exclude = enableprofile = False
144 if include_pat:
145 if include_pat:
145 pat = include_pat
146 pat = include_pat
146 include = True
147 include = True
147 if exclude_pat:
148 if exclude_pat:
148 pat = exclude_pat
149 pat = exclude_pat
149 exclude = True
150 exclude = True
150 if enableprofile_pat:
151 if enableprofile_pat:
151 pat = enableprofile_pat
152 pat = enableprofile_pat
152 enableprofile = True
153 enableprofile = True
153 if sum([include, exclude, enableprofile]) > 1:
154 if sum([include, exclude, enableprofile]) > 1:
154 raise error.Abort(_("too many flags specified."))
155 raise error.Abort(_("too many flags specified."))
155 if include or exclude or enableprofile:
156 if include or exclude or enableprofile:
156 def clonesparse(orig, self, node, overwrite, *args, **kwargs):
157 def clonesparse(orig, self, node, overwrite, *args, **kwargs):
157 sparse.updateconfig(self.unfiltered(), pat, {}, include=include,
158 sparse.updateconfig(self.unfiltered(), pat, {}, include=include,
158 exclude=exclude, enableprofile=enableprofile,
159 exclude=exclude, enableprofile=enableprofile,
159 usereporootpaths=True)
160 usereporootpaths=True)
160 return orig(self, node, overwrite, *args, **kwargs)
161 return orig(self, node, overwrite, *args, **kwargs)
161 extensions.wrapfunction(hg, 'updaterepo', clonesparse)
162 extensions.wrapfunction(hg, 'updaterepo', clonesparse)
162 return orig(ui, repo, *args, **opts)
163 return orig(ui, repo, *args, **opts)
163
164
164 def _setupclone(ui):
165 def _setupclone(ui):
165 entry = commands.table['^clone']
166 entry = commands.table['^clone']
166 entry[1].append(('', 'enable-profile', [],
167 entry[1].append(('', 'enable-profile', [],
167 'enable a sparse profile'))
168 'enable a sparse profile'))
168 entry[1].append(('', 'include', [],
169 entry[1].append(('', 'include', [],
169 'include sparse pattern'))
170 'include sparse pattern'))
170 entry[1].append(('', 'exclude', [],
171 entry[1].append(('', 'exclude', [],
171 'exclude sparse pattern'))
172 'exclude sparse pattern'))
172 extensions.wrapcommand(commands.table, 'clone', _clonesparsecmd)
173 extensions.wrapcommand(commands.table, 'clone', _clonesparsecmd)
173
174
174 def _setupadd(ui):
175 def _setupadd(ui):
175 entry = commands.table['^add']
176 entry = commands.table['^add']
176 entry[1].append(('s', 'sparse', None,
177 entry[1].append(('s', 'sparse', None,
177 'also include directories of added files in sparse config'))
178 'also include directories of added files in sparse config'))
178
179
179 def _add(orig, ui, repo, *pats, **opts):
180 def _add(orig, ui, repo, *pats, **opts):
180 if opts.get('sparse'):
181 if opts.get('sparse'):
181 dirs = set()
182 dirs = set()
182 for pat in pats:
183 for pat in pats:
183 dirname, basename = util.split(pat)
184 dirname, basename = util.split(pat)
184 dirs.add(dirname)
185 dirs.add(dirname)
185 sparse.updateconfig(repo, list(dirs), opts, include=True)
186 sparse.updateconfig(repo, list(dirs), opts, include=True)
186 return orig(ui, repo, *pats, **opts)
187 return orig(ui, repo, *pats, **opts)
187
188
188 extensions.wrapcommand(commands.table, 'add', _add)
189 extensions.wrapcommand(commands.table, 'add', _add)
189
190
190 def _setupdirstate(ui):
191 def _setupdirstate(ui):
191 """Modify the dirstate to prevent stat'ing excluded files,
192 """Modify the dirstate to prevent stat'ing excluded files,
192 and to prevent modifications to files outside the checkout.
193 and to prevent modifications to files outside the checkout.
193 """
194 """
194
195
195 def walk(orig, self, match, subrepos, unknown, ignored, full=True):
196 def walk(orig, self, match, subrepos, unknown, ignored, full=True):
196 match = matchmod.intersectmatchers(match, self._sparsematcher)
197 match = matchmod.intersectmatchers(match, self._sparsematcher)
197 return orig(self, match, subrepos, unknown, ignored, full)
198 return orig(self, match, subrepos, unknown, ignored, full)
198
199
199 extensions.wrapfunction(dirstate.dirstate, 'walk', walk)
200 extensions.wrapfunction(dirstate.dirstate, 'walk', walk)
200
201
201 # dirstate.rebuild should not add non-matching files
202 # dirstate.rebuild should not add non-matching files
202 def _rebuild(orig, self, parent, allfiles, changedfiles=None):
203 def _rebuild(orig, self, parent, allfiles, changedfiles=None):
203 matcher = self._sparsematcher
204 matcher = self._sparsematcher
204 if not matcher.always():
205 if not matcher.always():
205 allfiles = allfiles.matches(matcher)
206 allfiles = allfiles.matches(matcher)
206 if changedfiles:
207 if changedfiles:
207 changedfiles = [f for f in changedfiles if matcher(f)]
208 changedfiles = [f for f in changedfiles if matcher(f)]
208
209
209 if changedfiles is not None:
210 if changedfiles is not None:
210 # In _rebuild, these files will be deleted from the dirstate
211 # In _rebuild, these files will be deleted from the dirstate
211 # when they are not found to be in allfiles
212 # when they are not found to be in allfiles
212 dirstatefilestoremove = set(f for f in self if not matcher(f))
213 dirstatefilestoremove = set(f for f in self if not matcher(f))
213 changedfiles = dirstatefilestoremove.union(changedfiles)
214 changedfiles = dirstatefilestoremove.union(changedfiles)
214
215
215 return orig(self, parent, allfiles, changedfiles)
216 return orig(self, parent, allfiles, changedfiles)
216 extensions.wrapfunction(dirstate.dirstate, 'rebuild', _rebuild)
217 extensions.wrapfunction(dirstate.dirstate, 'rebuild', _rebuild)
217
218
218 # Prevent adding files that are outside the sparse checkout
219 # Prevent adding files that are outside the sparse checkout
219 editfuncs = ['normal', 'add', 'normallookup', 'copy', 'remove', 'merge']
220 editfuncs = ['normal', 'add', 'normallookup', 'copy', 'remove', 'merge']
220 hint = _('include file with `hg debugsparse --include <pattern>` or use ' +
221 hint = _('include file with `hg debugsparse --include <pattern>` or use ' +
221 '`hg add -s <file>` to include file directory while adding')
222 '`hg add -s <file>` to include file directory while adding')
222 for func in editfuncs:
223 for func in editfuncs:
223 def _wrapper(orig, self, *args):
224 def _wrapper(orig, self, *args):
224 sparsematch = self._sparsematcher
225 sparsematch = self._sparsematcher
225 if not sparsematch.always():
226 if not sparsematch.always():
226 for f in args:
227 for f in args:
227 if (f is not None and not sparsematch(f) and
228 if (f is not None and not sparsematch(f) and
228 f not in self):
229 f not in self):
229 raise error.Abort(_("cannot add '%s' - it is outside "
230 raise error.Abort(_("cannot add '%s' - it is outside "
230 "the sparse checkout") % f,
231 "the sparse checkout") % f,
231 hint=hint)
232 hint=hint)
232 return orig(self, *args)
233 return orig(self, *args)
233 extensions.wrapfunction(dirstate.dirstate, func, _wrapper)
234 extensions.wrapfunction(dirstate.dirstate, func, _wrapper)
234
235
235 @command('^debugsparse', [
236 @command('^debugsparse', [
236 ('I', 'include', False, _('include files in the sparse checkout')),
237 ('I', 'include', False, _('include files in the sparse checkout')),
237 ('X', 'exclude', False, _('exclude files in the sparse checkout')),
238 ('X', 'exclude', False, _('exclude files in the sparse checkout')),
238 ('d', 'delete', False, _('delete an include/exclude rule')),
239 ('d', 'delete', False, _('delete an include/exclude rule')),
239 ('f', 'force', False, _('allow changing rules even with pending changes')),
240 ('f', 'force', False, _('allow changing rules even with pending changes')),
240 ('', 'enable-profile', False, _('enables the specified profile')),
241 ('', 'enable-profile', False, _('enables the specified profile')),
241 ('', 'disable-profile', False, _('disables the specified profile')),
242 ('', 'disable-profile', False, _('disables the specified profile')),
242 ('', 'import-rules', False, _('imports rules from a file')),
243 ('', 'import-rules', False, _('imports rules from a file')),
243 ('', 'clear-rules', False, _('clears local include/exclude rules')),
244 ('', 'clear-rules', False, _('clears local include/exclude rules')),
244 ('', 'refresh', False, _('updates the working after sparseness changes')),
245 ('', 'refresh', False, _('updates the working after sparseness changes')),
245 ('', 'reset', False, _('makes the repo full again')),
246 ('', 'reset', False, _('makes the repo full again')),
246 ] + commands.templateopts,
247 ] + commands.templateopts,
247 _('[--OPTION] PATTERN...'))
248 _('[--OPTION] PATTERN...'))
248 def debugsparse(ui, repo, *pats, **opts):
249 def debugsparse(ui, repo, *pats, **opts):
249 """make the current checkout sparse, or edit the existing checkout
250 """make the current checkout sparse, or edit the existing checkout
250
251
251 The sparse command is used to make the current checkout sparse.
252 The sparse command is used to make the current checkout sparse.
252 This means files that don't meet the sparse condition will not be
253 This means files that don't meet the sparse condition will not be
253 written to disk, or show up in any working copy operations. It does
254 written to disk, or show up in any working copy operations. It does
254 not affect files in history in any way.
255 not affect files in history in any way.
255
256
256 Passing no arguments prints the currently applied sparse rules.
257 Passing no arguments prints the currently applied sparse rules.
257
258
258 --include and --exclude are used to add and remove files from the sparse
259 --include and --exclude are used to add and remove files from the sparse
259 checkout. The effects of adding an include or exclude rule are applied
260 checkout. The effects of adding an include or exclude rule are applied
260 immediately. If applying the new rule would cause a file with pending
261 immediately. If applying the new rule would cause a file with pending
261 changes to be added or removed, the command will fail. Pass --force to
262 changes to be added or removed, the command will fail. Pass --force to
262 force a rule change even with pending changes (the changes on disk will
263 force a rule change even with pending changes (the changes on disk will
263 be preserved).
264 be preserved).
264
265
265 --delete removes an existing include/exclude rule. The effects are
266 --delete removes an existing include/exclude rule. The effects are
266 immediate.
267 immediate.
267
268
268 --refresh refreshes the files on disk based on the sparse rules. This is
269 --refresh refreshes the files on disk based on the sparse rules. This is
269 only necessary if .hg/sparse was changed by hand.
270 only necessary if .hg/sparse was changed by hand.
270
271
271 --enable-profile and --disable-profile accept a path to a .hgsparse file.
272 --enable-profile and --disable-profile accept a path to a .hgsparse file.
272 This allows defining sparse checkouts and tracking them inside the
273 This allows defining sparse checkouts and tracking them inside the
273 repository. This is useful for defining commonly used sparse checkouts for
274 repository. This is useful for defining commonly used sparse checkouts for
274 many people to use. As the profile definition changes over time, the sparse
275 many people to use. As the profile definition changes over time, the sparse
275 checkout will automatically be updated appropriately, depending on which
276 checkout will automatically be updated appropriately, depending on which
276 changeset is checked out. Changes to .hgsparse are not applied until they
277 changeset is checked out. Changes to .hgsparse are not applied until they
277 have been committed.
278 have been committed.
278
279
279 --import-rules accepts a path to a file containing rules in the .hgsparse
280 --import-rules accepts a path to a file containing rules in the .hgsparse
280 format, allowing you to add --include, --exclude and --enable-profile rules
281 format, allowing you to add --include, --exclude and --enable-profile rules
281 in bulk. Like the --include, --exclude and --enable-profile switches, the
282 in bulk. Like the --include, --exclude and --enable-profile switches, the
282 changes are applied immediately.
283 changes are applied immediately.
283
284
284 --clear-rules removes all local include and exclude rules, while leaving
285 --clear-rules removes all local include and exclude rules, while leaving
285 any enabled profiles in place.
286 any enabled profiles in place.
286
287
287 Returns 0 if editing the sparse checkout succeeds.
288 Returns 0 if editing the sparse checkout succeeds.
288 """
289 """
290 opts = pycompat.byteskwargs(opts)
289 include = opts.get('include')
291 include = opts.get('include')
290 exclude = opts.get('exclude')
292 exclude = opts.get('exclude')
291 force = opts.get('force')
293 force = opts.get('force')
292 enableprofile = opts.get('enable_profile')
294 enableprofile = opts.get('enable_profile')
293 disableprofile = opts.get('disable_profile')
295 disableprofile = opts.get('disable_profile')
294 importrules = opts.get('import_rules')
296 importrules = opts.get('import_rules')
295 clearrules = opts.get('clear_rules')
297 clearrules = opts.get('clear_rules')
296 delete = opts.get('delete')
298 delete = opts.get('delete')
297 refresh = opts.get('refresh')
299 refresh = opts.get('refresh')
298 reset = opts.get('reset')
300 reset = opts.get('reset')
299 count = sum([include, exclude, enableprofile, disableprofile, delete,
301 count = sum([include, exclude, enableprofile, disableprofile, delete,
300 importrules, refresh, clearrules, reset])
302 importrules, refresh, clearrules, reset])
301 if count > 1:
303 if count > 1:
302 raise error.Abort(_("too many flags specified"))
304 raise error.Abort(_("too many flags specified"))
303
305
304 if count == 0:
306 if count == 0:
305 if repo.vfs.exists('sparse'):
307 if repo.vfs.exists('sparse'):
306 ui.status(repo.vfs.read("sparse") + "\n")
308 ui.status(repo.vfs.read("sparse") + "\n")
307 temporaryincludes = sparse.readtemporaryincludes(repo)
309 temporaryincludes = sparse.readtemporaryincludes(repo)
308 if temporaryincludes:
310 if temporaryincludes:
309 ui.status(_("Temporarily Included Files (for merge/rebase):\n"))
311 ui.status(_("Temporarily Included Files (for merge/rebase):\n"))
310 ui.status(("\n".join(temporaryincludes) + "\n"))
312 ui.status(("\n".join(temporaryincludes) + "\n"))
311 else:
313 else:
312 ui.status(_('repo is not sparse\n'))
314 ui.status(_('repo is not sparse\n'))
313 return
315 return
314
316
315 if include or exclude or delete or reset or enableprofile or disableprofile:
317 if include or exclude or delete or reset or enableprofile or disableprofile:
316 sparse.updateconfig(repo, pats, opts, include=include, exclude=exclude,
318 sparse.updateconfig(repo, pats, opts, include=include, exclude=exclude,
317 reset=reset, delete=delete,
319 reset=reset, delete=delete,
318 enableprofile=enableprofile,
320 enableprofile=enableprofile,
319 disableprofile=disableprofile, force=force)
321 disableprofile=disableprofile, force=force)
320
322
321 if importrules:
323 if importrules:
322 sparse.importfromfiles(repo, opts, pats, force=force)
324 sparse.importfromfiles(repo, opts, pats, force=force)
323
325
324 if clearrules:
326 if clearrules:
325 sparse.clearrules(repo, force=force)
327 sparse.clearrules(repo, force=force)
326
328
327 if refresh:
329 if refresh:
328 try:
330 try:
329 wlock = repo.wlock()
331 wlock = repo.wlock()
330 fcounts = map(
332 fcounts = map(
331 len,
333 len,
332 sparse.refreshwdir(repo, repo.status(), sparse.matcher(repo),
334 sparse.refreshwdir(repo, repo.status(), sparse.matcher(repo),
333 force=force))
335 force=force))
334 sparse.printchanges(ui, opts, added=fcounts[0], dropped=fcounts[1],
336 sparse.printchanges(ui, opts, added=fcounts[0], dropped=fcounts[1],
335 conflicting=fcounts[2])
337 conflicting=fcounts[2])
336 finally:
338 finally:
337 wlock.release()
339 wlock.release()
General Comments 0
You need to be logged in to leave comments. Login now