67 ] |
67 ] |
68 |
68 |
69 Substate = Dict[bytes, Tuple[bytes, bytes, bytes]] |
69 Substate = Dict[bytes, Tuple[bytes, bytes, bytes]] |
70 |
70 |
71 |
71 |
72 def state(ctx, ui): |
72 def state(ctx: "context.changectx", ui: "uimod.ui") -> Substate: |
73 # type: (context.changectx, uimod.ui) -> Substate |
|
74 """return a state dict, mapping subrepo paths configured in .hgsub |
73 """return a state dict, mapping subrepo paths configured in .hgsub |
75 to tuple: (source from .hgsub, revision from .hgsubstate, kind |
74 to tuple: (source from .hgsub, revision from .hgsubstate, kind |
76 (key in types dict)) |
75 (key in types dict)) |
77 """ |
76 """ |
78 p = config.config() |
77 p = config.config() |
120 ) |
119 ) |
121 rev[path] = revision |
120 rev[path] = revision |
122 except FileNotFoundError: |
121 except FileNotFoundError: |
123 pass |
122 pass |
124 |
123 |
125 def remap(src): |
124 def remap(src: bytes) -> bytes: |
126 # type: (bytes) -> bytes |
|
127 for pattern, repl in p.items(b'subpaths'): |
125 for pattern, repl in p.items(b'subpaths'): |
128 # Turn r'C:\foo\bar' into r'C:\\foo\\bar' since re.sub |
126 # Turn r'C:\foo\bar' into r'C:\\foo\\bar' since re.sub |
129 # does a string decode. |
127 # does a string decode. |
130 repl = stringutil.escapestr(repl) |
128 repl = stringutil.escapestr(repl) |
131 # However, we still want to allow back references to go |
129 # However, we still want to allow back references to go |
173 state[util.pconvert(path)] = (src.strip(), rev.get(path, b''), kind) |
171 state[util.pconvert(path)] = (src.strip(), rev.get(path, b''), kind) |
174 |
172 |
175 return state |
173 return state |
176 |
174 |
177 |
175 |
178 def writestate(repo, state): |
176 def writestate(repo: "localrepo.localrepository", state: Substate) -> None: |
179 # type: (localrepo.localrepository, Substate) -> None |
|
180 """rewrite .hgsubstate in (outer) repo with these subrepo states""" |
177 """rewrite .hgsubstate in (outer) repo with these subrepo states""" |
181 lines = [ |
178 lines = [ |
182 b'%s %s\n' % (state[s][1], s) |
179 b'%s %s\n' % (state[s][1], s) |
183 for s in sorted(state) |
180 for s in sorted(state) |
184 if state[s][1] != nullstate[1] |
181 if state[s][1] != nullstate[1] |
185 ] |
182 ] |
186 repo.wwrite(b'.hgsubstate', b''.join(lines), b'') |
183 repo.wwrite(b'.hgsubstate', b''.join(lines), b'') |
187 |
184 |
188 |
185 |
189 def submerge(repo, wctx, mctx, actx, overwrite, labels=None): |
186 def submerge( |
190 # type: (localrepo.localrepository, context.workingctx, context.changectx, context.changectx, bool, Optional[Any]) -> Substate |
187 repo: "localrepo.localrepository", |
|
188 wctx: "context.workingctx", |
|
189 mctx: "context.changectx", |
|
190 actx: "context.changectx", |
|
191 overwrite: bool, |
|
192 labels: Optional[Any] = None, |
|
193 ) -> Substate: |
191 # TODO: type the `labels` arg |
194 # TODO: type the `labels` arg |
192 """delegated from merge.applyupdates: merging of .hgsubstate file |
195 """delegated from merge.applyupdates: merging of .hgsubstate file |
193 in working context, merging context and ancestor context""" |
196 in working context, merging context and ancestor context""" |
194 if mctx == actx: # backwards? |
197 if mctx == actx: # backwards? |
195 actx = wctx.p1() |
198 actx = wctx.p1() |
325 # record merged .hgsubstate |
328 # record merged .hgsubstate |
326 writestate(repo, sm) |
329 writestate(repo, sm) |
327 return sm |
330 return sm |
328 |
331 |
329 |
332 |
330 def precommit(ui, wctx, status, match, force=False): |
333 def precommit( |
331 # type: (uimod.ui, context.workingcommitctx, scmutil.status, matchmod.basematcher, bool) -> Tuple[List[bytes], Set[bytes], Substate] |
334 ui: "uimod.ui", |
|
335 wctx: "context.workingcommitctx", |
|
336 status: "scmutil.status", |
|
337 match: "matchmod.basematcher", |
|
338 force: bool = False, |
|
339 ) -> Tuple[List[bytes], Set[bytes], Substate]: |
332 """Calculate .hgsubstate changes that should be applied before committing |
340 """Calculate .hgsubstate changes that should be applied before committing |
333 |
341 |
334 Returns (subs, commitsubs, newstate) where |
342 Returns (subs, commitsubs, newstate) where |
335 - subs: changed subrepos (including dirty ones) |
343 - subs: changed subrepos (including dirty ones) |
336 - commitsubs: dirty subrepos which the caller needs to commit recursively |
344 - commitsubs: dirty subrepos which the caller needs to commit recursively |
414 chunks.reverse() |
422 chunks.reverse() |
415 path = posixpath.join(*chunks) |
423 path = posixpath.join(*chunks) |
416 return posixpath.normpath(path) |
424 return posixpath.normpath(path) |
417 |
425 |
418 |
426 |
419 def reporelpath(repo): |
427 def reporelpath(repo: "localrepo.localrepository") -> bytes: |
420 # type: (localrepo.localrepository) -> bytes |
|
421 """return path to this (sub)repo as seen from outermost repo""" |
428 """return path to this (sub)repo as seen from outermost repo""" |
422 parent = repo |
429 parent = repo |
423 while hasattr(parent, '_subparent'): |
430 while hasattr(parent, '_subparent'): |
424 parent = parent._subparent |
431 parent = parent._subparent |
425 return repo.root[len(pathutil.normasprefix(parent.root)) :] |
432 return repo.root[len(pathutil.normasprefix(parent.root)) :] |
426 |
433 |
427 |
434 |
428 def subrelpath(sub): |
435 def subrelpath(sub: "subrepo.abstractsubrepo") -> bytes: |
429 # type: (subrepo.abstractsubrepo) -> bytes |
|
430 """return path to this subrepo as seen from outermost repo""" |
436 """return path to this subrepo as seen from outermost repo""" |
431 return sub._relpath |
437 return sub._relpath |
432 |
438 |
433 |
439 |
434 def _abssource(repo, push=False, abort=True): |
440 def _abssource( |
435 # type: (localrepo.localrepository, bool, bool) -> Optional[bytes] |
441 repo: "localrepo.localrepository", |
|
442 push: bool = False, |
|
443 abort: bool = True, |
|
444 ) -> Optional[bytes]: |
436 """return pull/push path of repo - either based on parent repo .hgsub info |
445 """return pull/push path of repo - either based on parent repo .hgsub info |
437 or on the top repo config. Abort or return None if no source found.""" |
446 or on the top repo config. Abort or return None if no source found.""" |
438 if hasattr(repo, '_subparent'): |
447 if hasattr(repo, '_subparent'): |
439 source = urlutil.url(repo._subsource) |
448 source = urlutil.url(repo._subsource) |
440 if source.isabs(): |
449 if source.isabs(): |
478 |
487 |
479 if abort: |
488 if abort: |
480 raise error.Abort(_(b"default path for subrepository not found")) |
489 raise error.Abort(_(b"default path for subrepository not found")) |
481 |
490 |
482 |
491 |
483 def newcommitphase(ui, ctx): |
492 def newcommitphase(ui: "uimod.ui", ctx: "context.changectx") -> int: |
484 # type: (uimod.ui, context.changectx) -> int |
|
485 commitphase = phases.newcommitphase(ui) |
493 commitphase = phases.newcommitphase(ui) |
486 substate = getattr(ctx, "substate", None) |
494 substate = getattr(ctx, "substate", None) |
487 if not substate: |
495 if not substate: |
488 return commitphase |
496 return commitphase |
489 check = ui.config(b'phases', b'checksubrepos') |
497 check = ui.config(b'phases', b'checksubrepos') |