Mercurial > hg
comparison mercurial/subrepoutil.py @ 43076:2372284d9457
formatting: blacken the codebase
This is using my patch to black
(https://github.com/psf/black/pull/826) so we don't un-wrap collection
literals.
Done with:
hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S
# skip-blame mass-reformatting only
# no-check-commit reformats foo_bar functions
Differential Revision: https://phab.mercurial-scm.org/D6971
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:45:02 -0400 |
parents | f6540aba8e3e |
children | 687b865b95ad |
comparison
equal
deleted
inserted
replaced
43075:57875cf423c9 | 43076:2372284d9457 |
---|---|
19 filemerge, | 19 filemerge, |
20 pathutil, | 20 pathutil, |
21 phases, | 21 phases, |
22 util, | 22 util, |
23 ) | 23 ) |
24 from .utils import ( | 24 from .utils import stringutil |
25 stringutil, | |
26 ) | |
27 | 25 |
28 nullstate = ('', '', 'empty') | 26 nullstate = ('', '', 'empty') |
27 | |
29 | 28 |
30 def state(ctx, ui): | 29 def state(ctx, ui): |
31 """return a state dict, mapping subrepo paths configured in .hgsub | 30 """return a state dict, mapping subrepo paths configured in .hgsub |
32 to tuple: (source from .hgsub, revision from .hgsubstate, kind | 31 to tuple: (source from .hgsub, revision from .hgsubstate, kind |
33 (key in types dict)) | 32 (key in types dict)) |
34 """ | 33 """ |
35 p = config.config() | 34 p = config.config() |
36 repo = ctx.repo() | 35 repo = ctx.repo() |
36 | |
37 def read(f, sections=None, remap=None): | 37 def read(f, sections=None, remap=None): |
38 if f in ctx: | 38 if f in ctx: |
39 try: | 39 try: |
40 data = ctx[f].data() | 40 data = ctx[f].data() |
41 except IOError as err: | 41 except IOError as err: |
42 if err.errno != errno.ENOENT: | 42 if err.errno != errno.ENOENT: |
43 raise | 43 raise |
44 # handle missing subrepo spec files as removed | 44 # handle missing subrepo spec files as removed |
45 ui.warn(_("warning: subrepo spec file \'%s\' not found\n") % | 45 ui.warn( |
46 repo.pathto(f)) | 46 _("warning: subrepo spec file \'%s\' not found\n") |
47 % repo.pathto(f) | |
48 ) | |
47 return | 49 return |
48 p.parse(f, data, sections, remap, read) | 50 p.parse(f, data, sections, remap, read) |
49 else: | 51 else: |
50 raise error.Abort(_("subrepo spec file \'%s\' not found") % | 52 raise error.Abort( |
51 repo.pathto(f)) | 53 _("subrepo spec file \'%s\' not found") % repo.pathto(f) |
54 ) | |
55 | |
52 if '.hgsub' in ctx: | 56 if '.hgsub' in ctx: |
53 read('.hgsub') | 57 read('.hgsub') |
54 | 58 |
55 for path, src in ui.configitems('subpaths'): | 59 for path, src in ui.configitems('subpaths'): |
56 p.set('subpaths', path, src, ui.configsource('subpaths', path)) | 60 p.set('subpaths', path, src, ui.configsource('subpaths', path)) |
63 if not l: | 67 if not l: |
64 continue | 68 continue |
65 try: | 69 try: |
66 revision, path = l.split(" ", 1) | 70 revision, path = l.split(" ", 1) |
67 except ValueError: | 71 except ValueError: |
68 raise error.Abort(_("invalid subrepository revision " | 72 raise error.Abort( |
69 "specifier in \'%s\' line %d") | 73 _( |
70 % (repo.pathto('.hgsubstate'), (i + 1))) | 74 "invalid subrepository revision " |
75 "specifier in \'%s\' line %d" | |
76 ) | |
77 % (repo.pathto('.hgsubstate'), (i + 1)) | |
78 ) | |
71 rev[path] = revision | 79 rev[path] = revision |
72 except IOError as err: | 80 except IOError as err: |
73 if err.errno != errno.ENOENT: | 81 if err.errno != errno.ENOENT: |
74 raise | 82 raise |
75 | 83 |
83 # extra escapes are needed because re.sub string decodes. | 91 # extra escapes are needed because re.sub string decodes. |
84 repl = re.sub(br'\\\\([0-9]+)', br'\\\1', repl) | 92 repl = re.sub(br'\\\\([0-9]+)', br'\\\1', repl) |
85 try: | 93 try: |
86 src = re.sub(pattern, repl, src, 1) | 94 src = re.sub(pattern, repl, src, 1) |
87 except re.error as e: | 95 except re.error as e: |
88 raise error.Abort(_("bad subrepository pattern in %s: %s") | 96 raise error.Abort( |
89 % (p.source('subpaths', pattern), | 97 _("bad subrepository pattern in %s: %s") |
90 stringutil.forcebytestr(e))) | 98 % ( |
99 p.source('subpaths', pattern), | |
100 stringutil.forcebytestr(e), | |
101 ) | |
102 ) | |
91 return src | 103 return src |
92 | 104 |
93 state = {} | 105 state = {} |
94 for path, src in p[''].items(): | 106 for path, src in p[''].items(): |
95 kind = 'hg' | 107 kind = 'hg' |
96 if src.startswith('['): | 108 if src.startswith('['): |
97 if ']' not in src: | 109 if ']' not in src: |
98 raise error.Abort(_('missing ] in subrepository source')) | 110 raise error.Abort(_('missing ] in subrepository source')) |
99 kind, src = src.split(']', 1) | 111 kind, src = src.split(']', 1) |
100 kind = kind[1:] | 112 kind = kind[1:] |
101 src = src.lstrip() # strip any extra whitespace after ']' | 113 src = src.lstrip() # strip any extra whitespace after ']' |
102 | 114 |
103 if not util.url(src).isabs(): | 115 if not util.url(src).isabs(): |
104 parent = _abssource(repo, abort=False) | 116 parent = _abssource(repo, abort=False) |
105 if parent: | 117 if parent: |
106 parent = util.url(parent) | 118 parent = util.url(parent) |
118 src = remap(src) | 130 src = remap(src) |
119 state[util.pconvert(path)] = (src.strip(), rev.get(path, ''), kind) | 131 state[util.pconvert(path)] = (src.strip(), rev.get(path, ''), kind) |
120 | 132 |
121 return state | 133 return state |
122 | 134 |
135 | |
123 def writestate(repo, state): | 136 def writestate(repo, state): |
124 """rewrite .hgsubstate in (outer) repo with these subrepo states""" | 137 """rewrite .hgsubstate in (outer) repo with these subrepo states""" |
125 lines = ['%s %s\n' % (state[s][1], s) for s in sorted(state) | 138 lines = [ |
126 if state[s][1] != nullstate[1]] | 139 '%s %s\n' % (state[s][1], s) |
140 for s in sorted(state) | |
141 if state[s][1] != nullstate[1] | |
142 ] | |
127 repo.wwrite('.hgsubstate', ''.join(lines), '') | 143 repo.wwrite('.hgsubstate', ''.join(lines), '') |
144 | |
128 | 145 |
129 def submerge(repo, wctx, mctx, actx, overwrite, labels=None): | 146 def submerge(repo, wctx, mctx, actx, overwrite, labels=None): |
130 """delegated from merge.applyupdates: merging of .hgsubstate file | 147 """delegated from merge.applyupdates: merging of .hgsubstate file |
131 in working context, merging context and ancestor context""" | 148 in working context, merging context and ancestor context""" |
132 if mctx == actx: # backwards? | 149 if mctx == actx: # backwards? |
133 actx = wctx.p1() | 150 actx = wctx.p1() |
134 s1 = wctx.substate | 151 s1 = wctx.substate |
135 s2 = mctx.substate | 152 s2 = mctx.substate |
136 sa = actx.substate | 153 sa = actx.substate |
137 sm = {} | 154 sm = {} |
144 repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r)) | 161 repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r)) |
145 | 162 |
146 promptssrc = filemerge.partextras(labels) | 163 promptssrc = filemerge.partextras(labels) |
147 for s, l in sorted(s1.iteritems()): | 164 for s, l in sorted(s1.iteritems()): |
148 a = sa.get(s, nullstate) | 165 a = sa.get(s, nullstate) |
149 ld = l # local state with possible dirty flag for compares | 166 ld = l # local state with possible dirty flag for compares |
150 if wctx.sub(s).dirty(): | 167 if wctx.sub(s).dirty(): |
151 ld = (l[0], l[1] + "+") | 168 ld = (l[0], l[1] + "+") |
152 if wctx == actx: # overwrite | 169 if wctx == actx: # overwrite |
153 a = ld | 170 a = ld |
154 | 171 |
155 prompts = promptssrc.copy() | 172 prompts = promptssrc.copy() |
156 prompts['s'] = s | 173 prompts['s'] = s |
157 if s in s2: | 174 if s in s2: |
158 r = s2[s] | 175 r = s2[s] |
159 if ld == r or r == a: # no change or local is newer | 176 if ld == r or r == a: # no change or local is newer |
160 sm[s] = l | 177 sm[s] = l |
161 continue | 178 continue |
162 elif ld == a: # other side changed | 179 elif ld == a: # other side changed |
163 debug(s, "other changed, get", r) | 180 debug(s, "other changed, get", r) |
164 wctx.sub(s).get(r, overwrite) | 181 wctx.sub(s).get(r, overwrite) |
165 sm[s] = r | 182 sm[s] = r |
166 elif ld[0] != r[0]: # sources differ | 183 elif ld[0] != r[0]: # sources differ |
167 prompts['lo'] = l[0] | 184 prompts['lo'] = l[0] |
168 prompts['ro'] = r[0] | 185 prompts['ro'] = r[0] |
169 if repo.ui.promptchoice( | 186 if repo.ui.promptchoice( |
170 _(' subrepository sources for %(s)s differ\n' | 187 _( |
171 'you can use (l)ocal%(l)s source (%(lo)s)' | 188 ' subrepository sources for %(s)s differ\n' |
172 ' or (r)emote%(o)s source (%(ro)s).\n' | 189 'you can use (l)ocal%(l)s source (%(lo)s)' |
173 'what do you want to do?' | 190 ' or (r)emote%(o)s source (%(ro)s).\n' |
174 '$$ &Local $$ &Remote') % prompts, 0): | 191 'what do you want to do?' |
192 '$$ &Local $$ &Remote' | |
193 ) | |
194 % prompts, | |
195 0, | |
196 ): | |
175 debug(s, "prompt changed, get", r) | 197 debug(s, "prompt changed, get", r) |
176 wctx.sub(s).get(r, overwrite) | 198 wctx.sub(s).get(r, overwrite) |
177 sm[s] = r | 199 sm[s] = r |
178 elif ld[1] == a[1]: # local side is unchanged | 200 elif ld[1] == a[1]: # local side is unchanged |
179 debug(s, "other side changed, get", r) | 201 debug(s, "other side changed, get", r) |
180 wctx.sub(s).get(r, overwrite) | 202 wctx.sub(s).get(r, overwrite) |
181 sm[s] = r | 203 sm[s] = r |
182 else: | 204 else: |
183 debug(s, "both sides changed") | 205 debug(s, "both sides changed") |
184 srepo = wctx.sub(s) | 206 srepo = wctx.sub(s) |
185 prompts['sl'] = srepo.shortid(l[1]) | 207 prompts['sl'] = srepo.shortid(l[1]) |
186 prompts['sr'] = srepo.shortid(r[1]) | 208 prompts['sr'] = srepo.shortid(r[1]) |
187 option = repo.ui.promptchoice( | 209 option = repo.ui.promptchoice( |
188 _(' subrepository %(s)s diverged (local revision: %(sl)s, ' | 210 _( |
189 'remote revision: %(sr)s)\n' | 211 ' subrepository %(s)s diverged (local revision: %(sl)s, ' |
190 'you can (m)erge, keep (l)ocal%(l)s or keep ' | 212 'remote revision: %(sr)s)\n' |
191 '(r)emote%(o)s.\n' | 213 'you can (m)erge, keep (l)ocal%(l)s or keep ' |
192 'what do you want to do?' | 214 '(r)emote%(o)s.\n' |
193 '$$ &Merge $$ &Local $$ &Remote') | 215 'what do you want to do?' |
194 % prompts, 0) | 216 '$$ &Merge $$ &Local $$ &Remote' |
217 ) | |
218 % prompts, | |
219 0, | |
220 ) | |
195 if option == 0: | 221 if option == 0: |
196 wctx.sub(s).merge(r) | 222 wctx.sub(s).merge(r) |
197 sm[s] = l | 223 sm[s] = l |
198 debug(s, "merge with", r) | 224 debug(s, "merge with", r) |
199 elif option == 1: | 225 elif option == 1: |
201 debug(s, "keep local subrepo revision", l) | 227 debug(s, "keep local subrepo revision", l) |
202 else: | 228 else: |
203 wctx.sub(s).get(r, overwrite) | 229 wctx.sub(s).get(r, overwrite) |
204 sm[s] = r | 230 sm[s] = r |
205 debug(s, "get remote subrepo revision", r) | 231 debug(s, "get remote subrepo revision", r) |
206 elif ld == a: # remote removed, local unchanged | 232 elif ld == a: # remote removed, local unchanged |
207 debug(s, "remote removed, remove") | 233 debug(s, "remote removed, remove") |
208 wctx.sub(s).remove() | 234 wctx.sub(s).remove() |
209 elif a == nullstate: # not present in remote or ancestor | 235 elif a == nullstate: # not present in remote or ancestor |
210 debug(s, "local added, keep") | 236 debug(s, "local added, keep") |
211 sm[s] = l | 237 sm[s] = l |
212 continue | 238 continue |
213 else: | 239 else: |
214 if repo.ui.promptchoice( | 240 if repo.ui.promptchoice( |
215 _(' local%(l)s changed subrepository %(s)s' | 241 _( |
216 ' which remote%(o)s removed\n' | 242 ' local%(l)s changed subrepository %(s)s' |
217 'use (c)hanged version or (d)elete?' | 243 ' which remote%(o)s removed\n' |
218 '$$ &Changed $$ &Delete') % prompts, 0): | 244 'use (c)hanged version or (d)elete?' |
245 '$$ &Changed $$ &Delete' | |
246 ) | |
247 % prompts, | |
248 0, | |
249 ): | |
219 debug(s, "prompt remove") | 250 debug(s, "prompt remove") |
220 wctx.sub(s).remove() | 251 wctx.sub(s).remove() |
221 | 252 |
222 for s, r in sorted(s2.items()): | 253 for s, r in sorted(s2.items()): |
223 if s in s1: | 254 if s in s1: |
227 mctx.sub(s).get(r) | 258 mctx.sub(s).get(r) |
228 sm[s] = r | 259 sm[s] = r |
229 elif r != sa[s]: | 260 elif r != sa[s]: |
230 prompts = promptssrc.copy() | 261 prompts = promptssrc.copy() |
231 prompts['s'] = s | 262 prompts['s'] = s |
232 if repo.ui.promptchoice( | 263 if ( |
233 _(' remote%(o)s changed subrepository %(s)s' | 264 repo.ui.promptchoice( |
234 ' which local%(l)s removed\n' | 265 _( |
235 'use (c)hanged version or (d)elete?' | 266 ' remote%(o)s changed subrepository %(s)s' |
236 '$$ &Changed $$ &Delete') % prompts, 0) == 0: | 267 ' which local%(l)s removed\n' |
268 'use (c)hanged version or (d)elete?' | |
269 '$$ &Changed $$ &Delete' | |
270 ) | |
271 % prompts, | |
272 0, | |
273 ) | |
274 == 0 | |
275 ): | |
237 debug(s, "prompt recreate", r) | 276 debug(s, "prompt recreate", r) |
238 mctx.sub(s).get(r) | 277 mctx.sub(s).get(r) |
239 sm[s] = r | 278 sm[s] = r |
240 | 279 |
241 # record merged .hgsubstate | 280 # record merged .hgsubstate |
242 writestate(repo, sm) | 281 writestate(repo, sm) |
243 return sm | 282 return sm |
283 | |
244 | 284 |
245 def precommit(ui, wctx, status, match, force=False): | 285 def precommit(ui, wctx, status, match, force=False): |
246 """Calculate .hgsubstate changes that should be applied before committing | 286 """Calculate .hgsubstate changes that should be applied before committing |
247 | 287 |
248 Returns (subs, commitsubs, newstate) where | 288 Returns (subs, commitsubs, newstate) where |
272 if s in oldstate: | 312 if s in oldstate: |
273 newstate[s] = oldstate[s] | 313 newstate[s] = oldstate[s] |
274 continue | 314 continue |
275 if not force: | 315 if not force: |
276 raise error.Abort( | 316 raise error.Abort( |
277 _("commit with new subrepo %s excluded") % s) | 317 _("commit with new subrepo %s excluded") % s |
318 ) | |
278 dirtyreason = wctx.sub(s).dirtyreason(True) | 319 dirtyreason = wctx.sub(s).dirtyreason(True) |
279 if dirtyreason: | 320 if dirtyreason: |
280 if not ui.configbool('ui', 'commitsubrepos'): | 321 if not ui.configbool('ui', 'commitsubrepos'): |
281 raise error.Abort(dirtyreason, | 322 raise error.Abort( |
282 hint=_("use --subrepos for recursive commit")) | 323 dirtyreason, |
324 hint=_("use --subrepos for recursive commit"), | |
325 ) | |
283 subs.append(s) | 326 subs.append(s) |
284 commitsubs.add(s) | 327 commitsubs.add(s) |
285 else: | 328 else: |
286 bs = wctx.sub(s).basestate() | 329 bs = wctx.sub(s).basestate() |
287 newstate[s] = (newstate[s][0], bs, newstate[s][2]) | 330 newstate[s] = (newstate[s][0], bs, newstate[s][2]) |
291 # check for removed subrepos | 334 # check for removed subrepos |
292 for p in wctx.parents(): | 335 for p in wctx.parents(): |
293 r = [s for s in p.substate if s not in newstate] | 336 r = [s for s in p.substate if s not in newstate] |
294 subs += [s for s in r if match(s)] | 337 subs += [s for s in r if match(s)] |
295 if subs: | 338 if subs: |
296 if (not match('.hgsub') and | 339 if not match('.hgsub') and '.hgsub' in ( |
297 '.hgsub' in (wctx.modified() + wctx.added())): | 340 wctx.modified() + wctx.added() |
341 ): | |
298 raise error.Abort(_("can't commit subrepos without .hgsub")) | 342 raise error.Abort(_("can't commit subrepos without .hgsub")) |
299 status.modified.insert(0, '.hgsubstate') | 343 status.modified.insert(0, '.hgsubstate') |
300 | 344 |
301 elif '.hgsub' in status.removed: | 345 elif '.hgsub' in status.removed: |
302 # clean up .hgsubstate when .hgsub is removed | 346 # clean up .hgsubstate when .hgsub is removed |
303 if ('.hgsubstate' in wctx and | 347 if '.hgsubstate' in wctx and '.hgsubstate' not in ( |
304 '.hgsubstate' not in (status.modified + status.added + | 348 status.modified + status.added + status.removed |
305 status.removed)): | 349 ): |
306 status.removed.insert(0, '.hgsubstate') | 350 status.removed.insert(0, '.hgsubstate') |
307 | 351 |
308 return subs, commitsubs, newstate | 352 return subs, commitsubs, newstate |
353 | |
309 | 354 |
310 def reporelpath(repo): | 355 def reporelpath(repo): |
311 """return path to this (sub)repo as seen from outermost repo""" | 356 """return path to this (sub)repo as seen from outermost repo""" |
312 parent = repo | 357 parent = repo |
313 while util.safehasattr(parent, '_subparent'): | 358 while util.safehasattr(parent, '_subparent'): |
314 parent = parent._subparent | 359 parent = parent._subparent |
315 return repo.root[len(pathutil.normasprefix(parent.root)):] | 360 return repo.root[len(pathutil.normasprefix(parent.root)) :] |
361 | |
316 | 362 |
317 def subrelpath(sub): | 363 def subrelpath(sub): |
318 """return path to this subrepo as seen from outermost repo""" | 364 """return path to this subrepo as seen from outermost repo""" |
319 return sub._relpath | 365 return sub._relpath |
366 | |
320 | 367 |
321 def _abssource(repo, push=False, abort=True): | 368 def _abssource(repo, push=False, abort=True): |
322 """return pull/push path of repo - either based on parent repo .hgsub info | 369 """return pull/push path of repo - either based on parent repo .hgsub info |
323 or on the top repo config. Abort or return None if no source found.""" | 370 or on the top repo config. Abort or return None if no source found.""" |
324 if util.safehasattr(repo, '_subparent'): | 371 if util.safehasattr(repo, '_subparent'): |
330 if parent: | 377 if parent: |
331 parent = util.url(util.pconvert(parent)) | 378 parent = util.url(util.pconvert(parent)) |
332 parent.path = posixpath.join(parent.path or '', source.path) | 379 parent.path = posixpath.join(parent.path or '', source.path) |
333 parent.path = posixpath.normpath(parent.path) | 380 parent.path = posixpath.normpath(parent.path) |
334 return bytes(parent) | 381 return bytes(parent) |
335 else: # recursion reached top repo | 382 else: # recursion reached top repo |
336 path = None | 383 path = None |
337 if util.safehasattr(repo, '_subtoppath'): | 384 if util.safehasattr(repo, '_subtoppath'): |
338 path = repo._subtoppath | 385 path = repo._subtoppath |
339 elif push and repo.ui.config('paths', 'default-push'): | 386 elif push and repo.ui.config('paths', 'default-push'): |
340 path = repo.ui.config('paths', 'default-push') | 387 path = repo.ui.config('paths', 'default-push') |
363 return path | 410 return path |
364 | 411 |
365 if abort: | 412 if abort: |
366 raise error.Abort(_("default path for subrepository not found")) | 413 raise error.Abort(_("default path for subrepository not found")) |
367 | 414 |
415 | |
368 def newcommitphase(ui, ctx): | 416 def newcommitphase(ui, ctx): |
369 commitphase = phases.newcommitphase(ui) | 417 commitphase = phases.newcommitphase(ui) |
370 substate = getattr(ctx, "substate", None) | 418 substate = getattr(ctx, "substate", None) |
371 if not substate: | 419 if not substate: |
372 return commitphase | 420 return commitphase |
373 check = ui.config('phases', 'checksubrepos') | 421 check = ui.config('phases', 'checksubrepos') |
374 if check not in ('ignore', 'follow', 'abort'): | 422 if check not in ('ignore', 'follow', 'abort'): |
375 raise error.Abort(_('invalid phases.checksubrepos configuration: %s') | 423 raise error.Abort( |
376 % (check)) | 424 _('invalid phases.checksubrepos configuration: %s') % check |
425 ) | |
377 if check == 'ignore': | 426 if check == 'ignore': |
378 return commitphase | 427 return commitphase |
379 maxphase = phases.public | 428 maxphase = phases.public |
380 maxsub = None | 429 maxsub = None |
381 for s in sorted(substate): | 430 for s in sorted(substate): |
384 if maxphase < subphase: | 433 if maxphase < subphase: |
385 maxphase = subphase | 434 maxphase = subphase |
386 maxsub = s | 435 maxsub = s |
387 if commitphase < maxphase: | 436 if commitphase < maxphase: |
388 if check == 'abort': | 437 if check == 'abort': |
389 raise error.Abort(_("can't commit in %s phase" | 438 raise error.Abort( |
390 " conflicting %s from subrepository %s") % | 439 _( |
391 (phases.phasenames[commitphase], | 440 "can't commit in %s phase" |
392 phases.phasenames[maxphase], maxsub)) | 441 " conflicting %s from subrepository %s" |
393 ui.warn(_("warning: changes are committed in" | 442 ) |
394 " %s phase from subrepository %s\n") % | 443 % ( |
395 (phases.phasenames[maxphase], maxsub)) | 444 phases.phasenames[commitphase], |
445 phases.phasenames[maxphase], | |
446 maxsub, | |
447 ) | |
448 ) | |
449 ui.warn( | |
450 _( | |
451 "warning: changes are committed in" | |
452 " %s phase from subrepository %s\n" | |
453 ) | |
454 % (phases.phasenames[maxphase], maxsub) | |
455 ) | |
396 return maxphase | 456 return maxphase |
397 return commitphase | 457 return commitphase |