Mercurial > hg-git-serve
comparison src/hgext3rd/hggit_serve/_http.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 | f630d9904ea7 |
| children |
comparison
equal
deleted
inserted
replaced
| 12:f630d9904ea7 | 13:00bdfac5416c |
|---|---|
| 14 from . import _export as xp | 14 from . import _export as xp |
| 15 | 15 |
| 16 if t.TYPE_CHECKING: | 16 if t.TYPE_CHECKING: |
| 17 import mercurial.hgweb.hgweb_mod_inner as web_inner | 17 import mercurial.hgweb.hgweb_mod_inner as web_inner |
| 18 import mercurial.hgweb.request as hgreq | 18 import mercurial.hgweb.request as hgreq |
| 19 import mercurial.interfaces.repository as hgrepo | |
| 20 import mercurial.ui as hgui | 19 import mercurial.ui as hgui |
| 21 | 20 |
| 22 PermissionCheck = t.Callable[ | 21 PermissionCheck = t.Callable[ |
| 23 [web_inner.requestcontext, hgreq.parsedrequest, bytes], | 22 [web_inner.requestcontext, hgreq.parsedrequest, bytes], |
| 24 None, | 23 None, |
| 37 fixed = { | 36 fixed = { |
| 38 k: v | 37 k: v |
| 39 for (k, v) in request.rawenv.items() | 38 for (k, v) in request.rawenv.items() |
| 40 if isinstance(v, bytes) and _CGI_VAR.match(k) | 39 if isinstance(v, bytes) and _CGI_VAR.match(k) |
| 41 } | 40 } |
| 41 repo = req_ctx.repo | |
| 42 assert xp.is_gitty(repo) | |
| 42 fixed.update( | 43 fixed.update( |
| 43 { | 44 { |
| 44 b'GIT_HTTP_EXPORT_ALL': b'yes', | 45 b'GIT_HTTP_EXPORT_ALL': b'yes', |
| 45 b'GIT_PROJECT_ROOT': req_ctx.repo.path, | 46 b'GIT_PROJECT_ROOT': repo.githandler.gitdir, |
| 46 b'PATH_INFO': b'/git/' + request.dispatchpath, | 47 b'PATH_INFO': b'/' + request.dispatchpath, |
| 47 # Since Mercurial is taking care of authorization checking, | 48 # Since Mercurial is taking care of authorization checking, |
| 48 # we tell Git to always allow push. | 49 # we tell Git to always allow push. |
| 49 b'GIT_CONFIG_COUNT': b'1', | 50 b'GIT_CONFIG_COUNT': b'1', |
| 50 b'GIT_CONFIG_KEY_0': b'http.receivepack', | 51 b'GIT_CONFIG_KEY_0': b'http.receivepack', |
| 51 b'GIT_CONFIG_VALUE_0': b'true', | 52 b'GIT_CONFIG_VALUE_0': b'true', |
| 99 response: hgreq.wsgiresponse, | 100 response: hgreq.wsgiresponse, |
| 100 check_permission: PermissionCheck, | 101 check_permission: PermissionCheck, |
| 101 ) -> bool: | 102 ) -> bool: |
| 102 """Intercepts requests from Git, if needed.""" | 103 """Intercepts requests from Git, if needed.""" |
| 103 perm = _git_service_permission(request) | 104 perm = _git_service_permission(request) |
| 104 repo: hgrepo.IRepo = req_ctx.repo | 105 repo = req_ctx.repo |
| 105 if not perm or not xp.is_gitty(repo): | 106 if not perm or not xp.is_gitty(repo): |
| 106 # We only handle Git requests to Gitty repos. | 107 # We only handle Git requests to Gitty repos. |
| 107 return original(req_ctx, request, response, check_permission) | 108 return original(req_ctx, request, response, check_permission) |
| 108 | 109 |
| 109 # Permission workaround: Mercurial requires POSTs for push, | 110 # Permission workaround: Mercurial requires POSTs for push, |
| 153 bs = shutil.COPY_BUFSIZE # type: ignore[attr-defined] | 154 bs = shutil.COPY_BUFSIZE # type: ignore[attr-defined] |
| 154 while more := rest.read(bs): | 155 while more := rest.read(bs): |
| 155 yield more | 156 yield more |
| 156 if perm == xp.PUSH: | 157 if perm == xp.PUSH: |
| 157 # If we pushed, we need to import any new refs back into Mercurial. | 158 # If we pushed, we need to import any new refs back into Mercurial. |
| 158 xp.importing_enter(repo) | 159 xp.import_all(repo, b'git-http-push') |
| 159 try: | |
| 160 gh = repo.githandler | |
| 161 gh.import_git_objects( | |
| 162 b'git-push', remote_names=(), refs=gh.git.refs.as_dict() | |
| 163 ) | |
| 164 finally: | |
| 165 xp.importing_exit(repo) | |
| 166 | 160 |
| 167 response.setbodygen(write_the_rest()) | 161 response.setbodygen(write_the_rest()) |
| 168 response.sendresponse() | 162 response.sendresponse() |
| 169 return True | 163 return True |
| 170 | 164 |
