Mercurial > hg-git-serve
comparison src/hgext3rd/hggit_serve/_ssh.py @ 13:00bdfac5416c
Create Git SSH commands and add some documentation. Also cleanup.
- Adds git-upload-pack and git-receive-pack as hg subcommands,
to be run on the server side by git push/pull.
- Starts on documentation.
- Cleans up a lot of stuff.
| author | Paul Fisher <paul@pfish.zone> |
|---|---|
| date | Thu, 19 Feb 2026 01:13:56 -0500 |
| parents | |
| children | b65d5922b8ee |
comparison
equal
deleted
inserted
replaced
| 12:f630d9904ea7 | 13:00bdfac5416c |
|---|---|
| 1 from __future__ import annotations | |
| 2 | |
| 3 import subprocess | |
| 4 import typing as t | |
| 5 | |
| 6 from mercurial import error as hgerr | |
| 7 from mercurial import registrar | |
| 8 | |
| 9 from . import _export as xp | |
| 10 | |
| 11 if t.TYPE_CHECKING: | |
| 12 import mercurial.interfaces.repository as hgrepo | |
| 13 import mercurial.ui as hgui | |
| 14 | |
| 15 cmdtable: dict[bytes, object] = {} | |
| 16 _command = registrar.command(cmdtable) | |
| 17 | |
| 18 | |
| 19 def _not_git() -> hgerr.StateError: | |
| 20 return hgerr.StateError( | |
| 21 b'Git is not enabled for this repository.', | |
| 22 hint=b'The server administrator should enable the ``hggit`` extension ' | |
| 23 b'and run ``hg git-export`` to enable Git access.', | |
| 24 ) | |
| 25 | |
| 26 | |
| 27 def _maybe(flag: bytes, include: bool) -> tuple[bytes, ...]: | |
| 28 return (flag,) if include else () | |
| 29 | |
| 30 | |
| 31 @_command( | |
| 32 b'git-upload-pack', | |
| 33 [ | |
| 34 *( | |
| 35 (b'', opt, False, b'flag passed to git upload-pack') | |
| 36 for opt in ( | |
| 37 b'strict', | |
| 38 b'no-strict', | |
| 39 b'stateless-rpc', | |
| 40 b'advertise-refs', | |
| 41 ) | |
| 42 ), | |
| 43 (b'', b'timeout', -1, b'flag passed to git upload-pack'), | |
| 44 ], | |
| 45 helpcategory=b'import', | |
| 46 intents=(b'readonly',), | |
| 47 ) | |
| 48 def _git_upload_pack( | |
| 49 ui: hgui.ui, | |
| 50 repo: hgrepo.IRepo, | |
| 51 *, | |
| 52 strict: bool, | |
| 53 no_strict: bool, | |
| 54 stateless_rpc: bool, | |
| 55 advertise_refs: bool, | |
| 56 timeout: int, | |
| 57 ) -> int: | |
| 58 """Server-side handler for ``git pull``/``git clone``.""" | |
| 59 if not xp.is_gitty(repo): | |
| 60 raise _not_git() | |
| 61 timeout_flag = ( | |
| 62 (b'--timeout=' + str(timeout).encode(),) if timeout != -1 else () | |
| 63 ) | |
| 64 upload_pack = ui.configlist( | |
| 65 b'hggit-serve', b'upload-pack', default=(b'git', b'upload-pack') | |
| 66 ) | |
| 67 return subprocess.call( | |
| 68 ( | |
| 69 *upload_pack, | |
| 70 *_maybe(b'--strict', strict), | |
| 71 *_maybe(b'--no-strict', no_strict), | |
| 72 *_maybe(b'--stateless-rpc', stateless_rpc), | |
| 73 *_maybe(b'--advertise_refs', advertise_refs), | |
| 74 *timeout_flag, | |
| 75 repo.githandler.gitdir, | |
| 76 ), | |
| 77 close_fds=True, | |
| 78 ) | |
| 79 | |
| 80 | |
| 81 @_command( | |
| 82 b'git-receive-pack', | |
| 83 [ | |
| 84 (b'', b'skip-connectivity-check', False, b'passed to git receive-pack'), | |
| 85 ], | |
| 86 helpcategory=b'import', | |
| 87 ) | |
| 88 def _git_receive_pack( | |
| 89 ui: hgui.ui, repo: hgrepo.IRepo, *, skip_connectivity_check: bool | |
| 90 ) -> int: | |
| 91 """Server-side handler for ``git push``.""" | |
| 92 if not xp.is_gitty(repo): | |
| 93 raise _not_git() | |
| 94 receive_pack = ui.configlist( | |
| 95 b'hggit-serve', b'receive-pack', default=(b'git', b'receive-pack') | |
| 96 ) | |
| 97 try: | |
| 98 subprocess.check_call( | |
| 99 ( | |
| 100 *receive_pack, | |
| 101 *_maybe(b'--skip-connectivity-check', skip_connectivity_check), | |
| 102 repo.githandler.gitdir, | |
| 103 ), | |
| 104 close_fds=True, | |
| 105 ) | |
| 106 except subprocess.CalledProcessError as cpe: | |
| 107 return cpe.returncode | |
| 108 xp.import_all(repo, b'git-receive-pack') | |
| 109 return 0 | |
| 110 | |
| 111 | |
| 112 __all__ = ('cmdtable',) |
