100 This function should be used to validate internal data structures |
104 This function should be used to validate internal data structures |
101 and patterns that are loaded from sources that use the internal, |
105 and patterns that are loaded from sources that use the internal, |
102 prefixed pattern representation (but can't necessarily be fully trusted). |
106 prefixed pattern representation (but can't necessarily be fully trusted). |
103 """ |
107 """ |
104 if not isinstance(pats, set): |
108 if not isinstance(pats, set): |
105 raise error.ProgrammingError('narrow patterns should be a set; ' |
109 raise error.ProgrammingError( |
106 'got %r' % pats) |
110 'narrow patterns should be a set; ' 'got %r' % pats |
|
111 ) |
107 |
112 |
108 for pat in pats: |
113 for pat in pats: |
109 if not pat.startswith(VALID_PREFIXES): |
114 if not pat.startswith(VALID_PREFIXES): |
110 # Use a Mercurial exception because this can happen due to user |
115 # Use a Mercurial exception because this can happen due to user |
111 # bugs (e.g. manually updating spec file). |
116 # bugs (e.g. manually updating spec file). |
112 raise error.Abort(_('invalid prefix on narrow pattern: %s') % pat, |
117 raise error.Abort( |
113 hint=_('narrow patterns must begin with one of ' |
118 _('invalid prefix on narrow pattern: %s') % pat, |
114 'the following: %s') % |
119 hint=_( |
115 ', '.join(VALID_PREFIXES)) |
120 'narrow patterns must begin with one of ' |
|
121 'the following: %s' |
|
122 ) |
|
123 % ', '.join(VALID_PREFIXES), |
|
124 ) |
|
125 |
116 |
126 |
117 def format(includes, excludes): |
127 def format(includes, excludes): |
118 output = '[include]\n' |
128 output = '[include]\n' |
119 for i in sorted(includes - excludes): |
129 for i in sorted(includes - excludes): |
120 output += i + '\n' |
130 output += i + '\n' |
121 output += '[exclude]\n' |
131 output += '[exclude]\n' |
122 for e in sorted(excludes): |
132 for e in sorted(excludes): |
123 output += e + '\n' |
133 output += e + '\n' |
124 return output |
134 return output |
125 |
135 |
|
136 |
126 def match(root, include=None, exclude=None): |
137 def match(root, include=None, exclude=None): |
127 if not include: |
138 if not include: |
128 # Passing empty include and empty exclude to matchmod.match() |
139 # Passing empty include and empty exclude to matchmod.match() |
129 # gives a matcher that matches everything, so explicitly use |
140 # gives a matcher that matches everything, so explicitly use |
130 # the nevermatcher. |
141 # the nevermatcher. |
131 return matchmod.never() |
142 return matchmod.never() |
132 return matchmod.match(root, '', [], include=include or [], |
143 return matchmod.match( |
133 exclude=exclude or []) |
144 root, '', [], include=include or [], exclude=exclude or [] |
|
145 ) |
|
146 |
134 |
147 |
135 def parseconfig(ui, spec): |
148 def parseconfig(ui, spec): |
136 # maybe we should care about the profiles returned too |
149 # maybe we should care about the profiles returned too |
137 includepats, excludepats, profiles = sparse.parseconfig(ui, spec, 'narrow') |
150 includepats, excludepats, profiles = sparse.parseconfig(ui, spec, 'narrow') |
138 if profiles: |
151 if profiles: |
139 raise error.Abort(_("including other spec files using '%include' is not" |
152 raise error.Abort( |
140 " supported in narrowspec")) |
153 _( |
|
154 "including other spec files using '%include' is not" |
|
155 " supported in narrowspec" |
|
156 ) |
|
157 ) |
141 |
158 |
142 validatepatterns(includepats) |
159 validatepatterns(includepats) |
143 validatepatterns(excludepats) |
160 validatepatterns(excludepats) |
144 |
161 |
145 return includepats, excludepats |
162 return includepats, excludepats |
|
163 |
146 |
164 |
147 def load(repo): |
165 def load(repo): |
148 # Treat "narrowspec does not exist" the same as "narrowspec file exists |
166 # Treat "narrowspec does not exist" the same as "narrowspec file exists |
149 # and is empty". |
167 # and is empty". |
150 spec = repo.svfs.tryread(FILENAME) |
168 spec = repo.svfs.tryread(FILENAME) |
151 return parseconfig(repo.ui, spec) |
169 return parseconfig(repo.ui, spec) |
152 |
170 |
|
171 |
153 def save(repo, includepats, excludepats): |
172 def save(repo, includepats, excludepats): |
154 validatepatterns(includepats) |
173 validatepatterns(includepats) |
155 validatepatterns(excludepats) |
174 validatepatterns(excludepats) |
156 spec = format(includepats, excludepats) |
175 spec = format(includepats, excludepats) |
157 repo.svfs.write(FILENAME, spec) |
176 repo.svfs.write(FILENAME, spec) |
158 |
177 |
|
178 |
159 def copytoworkingcopy(repo): |
179 def copytoworkingcopy(repo): |
160 spec = repo.svfs.read(FILENAME) |
180 spec = repo.svfs.read(FILENAME) |
161 repo.vfs.write(DIRSTATE_FILENAME, spec) |
181 repo.vfs.write(DIRSTATE_FILENAME, spec) |
162 |
182 |
|
183 |
163 def savebackup(repo, backupname): |
184 def savebackup(repo, backupname): |
164 if repository.NARROW_REQUIREMENT not in repo.requirements: |
185 if repository.NARROW_REQUIREMENT not in repo.requirements: |
165 return |
186 return |
166 svfs = repo.svfs |
187 svfs = repo.svfs |
167 svfs.tryunlink(backupname) |
188 svfs.tryunlink(backupname) |
168 util.copyfile(svfs.join(FILENAME), svfs.join(backupname), hardlink=True) |
189 util.copyfile(svfs.join(FILENAME), svfs.join(backupname), hardlink=True) |
169 |
190 |
|
191 |
170 def restorebackup(repo, backupname): |
192 def restorebackup(repo, backupname): |
171 if repository.NARROW_REQUIREMENT not in repo.requirements: |
193 if repository.NARROW_REQUIREMENT not in repo.requirements: |
172 return |
194 return |
173 util.rename(repo.svfs.join(backupname), repo.svfs.join(FILENAME)) |
195 util.rename(repo.svfs.join(backupname), repo.svfs.join(FILENAME)) |
|
196 |
174 |
197 |
175 def savewcbackup(repo, backupname): |
198 def savewcbackup(repo, backupname): |
176 if repository.NARROW_REQUIREMENT not in repo.requirements: |
199 if repository.NARROW_REQUIREMENT not in repo.requirements: |
177 return |
200 return |
178 vfs = repo.vfs |
201 vfs = repo.vfs |
179 vfs.tryunlink(backupname) |
202 vfs.tryunlink(backupname) |
180 # It may not exist in old repos |
203 # It may not exist in old repos |
181 if vfs.exists(DIRSTATE_FILENAME): |
204 if vfs.exists(DIRSTATE_FILENAME): |
182 util.copyfile(vfs.join(DIRSTATE_FILENAME), vfs.join(backupname), |
205 util.copyfile( |
183 hardlink=True) |
206 vfs.join(DIRSTATE_FILENAME), vfs.join(backupname), hardlink=True |
|
207 ) |
|
208 |
184 |
209 |
185 def restorewcbackup(repo, backupname): |
210 def restorewcbackup(repo, backupname): |
186 if repository.NARROW_REQUIREMENT not in repo.requirements: |
211 if repository.NARROW_REQUIREMENT not in repo.requirements: |
187 return |
212 return |
188 # It may not exist in old repos |
213 # It may not exist in old repos |
189 if repo.vfs.exists(backupname): |
214 if repo.vfs.exists(backupname): |
190 util.rename(repo.vfs.join(backupname), repo.vfs.join(DIRSTATE_FILENAME)) |
215 util.rename(repo.vfs.join(backupname), repo.vfs.join(DIRSTATE_FILENAME)) |
191 |
216 |
|
217 |
192 def clearwcbackup(repo, backupname): |
218 def clearwcbackup(repo, backupname): |
193 if repository.NARROW_REQUIREMENT not in repo.requirements: |
219 if repository.NARROW_REQUIREMENT not in repo.requirements: |
194 return |
220 return |
195 repo.vfs.tryunlink(backupname) |
221 repo.vfs.tryunlink(backupname) |
|
222 |
196 |
223 |
197 def restrictpatterns(req_includes, req_excludes, repo_includes, repo_excludes): |
224 def restrictpatterns(req_includes, req_excludes, repo_includes, repo_excludes): |
198 r""" Restricts the patterns according to repo settings, |
225 r""" Restricts the patterns according to repo settings, |
199 results in a logical AND operation |
226 results in a logical AND operation |
200 |
227 |
245 res_includes = set(res_includes) |
272 res_includes = set(res_includes) |
246 else: |
273 else: |
247 res_includes = set(req_includes) |
274 res_includes = set(req_includes) |
248 return res_includes, res_excludes, invalid_includes |
275 return res_includes, res_excludes, invalid_includes |
249 |
276 |
|
277 |
250 # These two are extracted for extensions (specifically for Google's CitC file |
278 # These two are extracted for extensions (specifically for Google's CitC file |
251 # system) |
279 # system) |
252 def _deletecleanfiles(repo, files): |
280 def _deletecleanfiles(repo, files): |
253 for f in files: |
281 for f in files: |
254 repo.wvfs.unlinkpath(f) |
282 repo.wvfs.unlinkpath(f) |
|
283 |
255 |
284 |
256 def _writeaddedfiles(repo, pctx, files): |
285 def _writeaddedfiles(repo, pctx, files): |
257 actions = merge.emptyactions() |
286 actions = merge.emptyactions() |
258 addgaction = actions[merge.ACTION_GET].append |
287 addgaction = actions[merge.ACTION_GET].append |
259 mf = repo['.'].manifest() |
288 mf = repo['.'].manifest() |
260 for f in files: |
289 for f in files: |
261 if not repo.wvfs.exists(f): |
290 if not repo.wvfs.exists(f): |
262 addgaction((f, (mf.flags(f), False), "narrowspec updated")) |
291 addgaction((f, (mf.flags(f), False), "narrowspec updated")) |
263 merge.applyupdates(repo, actions, wctx=repo[None], |
292 merge.applyupdates( |
264 mctx=repo['.'], overwrite=False, wantfiledata=False) |
293 repo, |
|
294 actions, |
|
295 wctx=repo[None], |
|
296 mctx=repo['.'], |
|
297 overwrite=False, |
|
298 wantfiledata=False, |
|
299 ) |
|
300 |
265 |
301 |
266 def checkworkingcopynarrowspec(repo): |
302 def checkworkingcopynarrowspec(repo): |
267 # Avoid infinite recursion when updating the working copy |
303 # Avoid infinite recursion when updating the working copy |
268 if getattr(repo, '_updatingnarrowspec', False): |
304 if getattr(repo, '_updatingnarrowspec', False): |
269 return |
305 return |
270 storespec = repo.svfs.tryread(FILENAME) |
306 storespec = repo.svfs.tryread(FILENAME) |
271 wcspec = repo.vfs.tryread(DIRSTATE_FILENAME) |
307 wcspec = repo.vfs.tryread(DIRSTATE_FILENAME) |
272 if wcspec != storespec: |
308 if wcspec != storespec: |
273 raise error.Abort(_("working copy's narrowspec is stale"), |
309 raise error.Abort( |
274 hint=_("run 'hg tracked --update-working-copy'")) |
310 _("working copy's narrowspec is stale"), |
|
311 hint=_("run 'hg tracked --update-working-copy'"), |
|
312 ) |
|
313 |
275 |
314 |
276 def updateworkingcopy(repo, assumeclean=False): |
315 def updateworkingcopy(repo, assumeclean=False): |
277 """updates the working copy and dirstate from the store narrowspec |
316 """updates the working copy and dirstate from the store narrowspec |
278 |
317 |
279 When assumeclean=True, files that are not known to be clean will also |
318 When assumeclean=True, files that are not known to be clean will also |