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