annotate src/git_serve/__init__.py @ 6:7113e0ac3662

fix refs on git-export; clean up how gitserve export works.
author Paul Fisher <paul@pfish.zone>
date Sun, 15 Feb 2026 01:31:53 -0500
parents c43ce246240b
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
1 from __future__ import annotations
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
2
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
3 import binascii
0
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
4 import email.parser
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
5 import email.policy
3
189f4a0bc653 don't try to pass bytes to pathlib.Path
Paul Fisher <paul@pfish.zone>
parents: 2
diff changeset
6 import os.path
0
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
7 import re
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
8 import shutil
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
9 import subprocess
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
10 import typing as t
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
11
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
12 import dulwich.refs
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
13 import mercurial.error as hgerr
0
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
14 from mercurial import extensions
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
15 from mercurial import registrar
0
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
16 from mercurial import wireprotoserver
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
17
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
18 if t.TYPE_CHECKING:
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
19 import hggit.git_handler
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
20 import mercurial.hgweb.hgweb_mod_inner as web_inner
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
21 import mercurial.hgweb.request as hgreq
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
22 import mercurial.interfaces.repository as hgrepo
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
23 import mercurial.ui as hgui
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
24
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
25 class GittyRepo(hgrepo.IRepo, t.Protocol):
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
26 githandler: hggit.git_handler.GitHandler
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
27
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
28 PermissionCheck = t.Callable[
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
29 [web_inner.requestcontext, hgreq.parsedrequest, bytes],
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
30 None,
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
31 ]
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
32 GitPrelude = t.Sequence[bytes | str | os.PathLike]
0
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
33
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
34
4
5ad58438318a Fix issue where sometimes reads would be cut off.
Paul Fisher <paul@pfish.zone>
parents: 3
diff changeset
35 def _is_gitty(repo: hgrepo.IRepo) -> t.TypeGuard[GittyRepo]:
5ad58438318a Fix issue where sometimes reads would be cut off.
Paul Fisher <paul@pfish.zone>
parents: 3
diff changeset
36 """Ensures that we have hg-git installed and active."""
5ad58438318a Fix issue where sometimes reads would be cut off.
Paul Fisher <paul@pfish.zone>
parents: 3
diff changeset
37 return hasattr(repo, 'githandler')
5ad58438318a Fix issue where sometimes reads would be cut off.
Paul Fisher <paul@pfish.zone>
parents: 3
diff changeset
38
5ad58438318a Fix issue where sometimes reads would be cut off.
Paul Fisher <paul@pfish.zone>
parents: 3
diff changeset
39
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
40 _CGI_VAR = re.compile(rb'[A-Z0-9_]+$')
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
41 """Environment variables that we need to pass to git-as-cgi."""
0
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
42
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
43
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
44 def _build_git_environ(
0
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
45 req_ctx: web_inner.requestcontext,
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
46 request: hgreq.parsedrequest,
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
47 ) -> dict[bytes, bytes]:
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
48 """Builds the environment to be sent to Git to serve HTTP."""
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
49 fixed = {
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
50 k: v
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
51 for (k, v) in request.rawenv.items()
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
52 if isinstance(v, bytes) and _CGI_VAR.match(k)
0
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
53 }
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
54 fixed[b'GIT_HTTP_EXPORT_ALL'] = b'yes'
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
55 fixed[b'GIT_PROJECT_ROOT'] = req_ctx.repo.path
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
56 fixed[b'PATH_INFO'] = b'/git/' + request.dispatchpath
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
57 return fixed
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
58
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
59
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
60 def _parse_cgi_response(
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
61 output: t.IO[bytes],
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
62 ) -> tuple[bytes, dict[bytes, bytes], t.IO[bytes]]:
4
5ad58438318a Fix issue where sometimes reads would be cut off.
Paul Fisher <paul@pfish.zone>
parents: 3
diff changeset
63 """Parses a CGI response into a status, headers, and everyhting else."""
0
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
64 parser = email.parser.BytesFeedParser(policy=email.policy.HTTP)
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
65 while line := output.readline():
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
66 if not line.rstrip(b'\r\n'):
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
67 # We've reached the end of the headers.
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
68 # Leave the rest in the output for later.
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
69 break
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
70 parser.feed(line)
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
71 msg = parser.close()
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
72 status = msg.get('Status', '200 OK I guess').encode('utf-8')
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
73 del msg['Status'] # this won't raise an exception
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
74 byte_headers = {
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
75 k.encode('utf-8'): v.encode('utf-8') for (k, v) in msg.items()
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
76 }
0
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
77 return status, byte_headers, output
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
78
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
79
4
5ad58438318a Fix issue where sometimes reads would be cut off.
Paul Fisher <paul@pfish.zone>
parents: 3
diff changeset
80 def _handle_git_protocol(
0
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
81 original: t.Callable[..., bool],
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
82 req_ctx: web_inner.requestcontext,
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
83 request: hgreq.parsedrequest,
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
84 response: hgreq.wsgiresponse,
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
85 check_permission: PermissionCheck,
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
86 ) -> bool:
4
5ad58438318a Fix issue where sometimes reads would be cut off.
Paul Fisher <paul@pfish.zone>
parents: 3
diff changeset
87 """Intercepts requests from Git, if needed."""
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
88 repo = req_ctx.repo
4
5ad58438318a Fix issue where sometimes reads would be cut off.
Paul Fisher <paul@pfish.zone>
parents: 3
diff changeset
89 if not _is_gitty(repo) or b'git-protocol' not in request.headers:
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
90 # We only handle Git requests; everything else is normal.
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
91 return original(req_ctx, request, response, check_permission)
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
92 check_permission(req_ctx, request, b'pull')
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
93 # If a request is git, we assume we should be the one handling it.
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
94 cgi_env = _build_git_environ(req_ctx, request)
5
c43ce246240b Really fix content-length for real for serious.
Paul Fisher <paul@pfish.zone>
parents: 4
diff changeset
95 content_length_hdr = request.headers.get(b'content-length', b'0')
c43ce246240b Really fix content-length for real for serious.
Paul Fisher <paul@pfish.zone>
parents: 4
diff changeset
96 try:
c43ce246240b Really fix content-length for real for serious.
Paul Fisher <paul@pfish.zone>
parents: 4
diff changeset
97 content_length = int(content_length_hdr)
c43ce246240b Really fix content-length for real for serious.
Paul Fisher <paul@pfish.zone>
parents: 4
diff changeset
98 except ValueError as ve:
c43ce246240b Really fix content-length for real for serious.
Paul Fisher <paul@pfish.zone>
parents: 4
diff changeset
99 raise hgerr.InputError(
c43ce246240b Really fix content-length for real for serious.
Paul Fisher <paul@pfish.zone>
parents: 4
diff changeset
100 f'Invalid content-length {content_length!r}'.encode()
c43ce246240b Really fix content-length for real for serious.
Paul Fisher <paul@pfish.zone>
parents: 4
diff changeset
101 ) from ve
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
102 http_backend = req_ctx.repo.ui.configlist(
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
103 b'git-serve', b'http-backend', default=(b'git', b'http-backend')
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
104 )
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
105 call = subprocess.Popen(
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
106 http_backend,
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
107 close_fds=True,
4
5ad58438318a Fix issue where sometimes reads would be cut off.
Paul Fisher <paul@pfish.zone>
parents: 3
diff changeset
108 stdin=subprocess.PIPE,
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
109 stdout=subprocess.PIPE,
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
110 stderr=subprocess.DEVNULL,
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
111 env=cgi_env,
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
112 text=False,
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
113 )
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
114 assert call.stdout
4
5ad58438318a Fix issue where sometimes reads would be cut off.
Paul Fisher <paul@pfish.zone>
parents: 3
diff changeset
115 assert call.stdin
5ad58438318a Fix issue where sometimes reads would be cut off.
Paul Fisher <paul@pfish.zone>
parents: 3
diff changeset
116 # Git will not start writing output until stdin is fully closed.
5ad58438318a Fix issue where sometimes reads would be cut off.
Paul Fisher <paul@pfish.zone>
parents: 3
diff changeset
117 with call.stdin:
5
c43ce246240b Really fix content-length for real for serious.
Paul Fisher <paul@pfish.zone>
parents: 4
diff changeset
118 if content_length:
c43ce246240b Really fix content-length for real for serious.
Paul Fisher <paul@pfish.zone>
parents: 4
diff changeset
119 shutil.copyfileobj(
c43ce246240b Really fix content-length for real for serious.
Paul Fisher <paul@pfish.zone>
parents: 4
diff changeset
120 request.bodyfh, call.stdin, length=content_length
c43ce246240b Really fix content-length for real for serious.
Paul Fisher <paul@pfish.zone>
parents: 4
diff changeset
121 )
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
122
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
123 status, headers, rest = _parse_cgi_response(call.stdout)
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
124 response.status = status
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
125 for k, v in headers.items():
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
126 response.headers[k] = v
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
127
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
128 def write_the_rest():
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
129 with call, rest:
4
5ad58438318a Fix issue where sometimes reads would be cut off.
Paul Fisher <paul@pfish.zone>
parents: 3
diff changeset
130 while more := rest.read(1024 * 1024):
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
131 yield more
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
132
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
133 response.setbodygen(write_the_rest())
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
134 response.sendresponse()
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
135 return True
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
136
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
137
4
5ad58438318a Fix issue where sometimes reads would be cut off.
Paul Fisher <paul@pfish.zone>
parents: 3
diff changeset
138 def _clean_all_refs(refs: dulwich.refs.RefsContainer) -> None:
5ad58438318a Fix issue where sometimes reads would be cut off.
Paul Fisher <paul@pfish.zone>
parents: 3
diff changeset
139 """Removes all refs from the Git repository."""
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
140 for ref in refs.allkeys():
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
141 refs.remove_if_equals(ref, None)
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
142
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
143
6
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
144 def _set_head(ui: hgui.ui, repo: GittyRepo, at_name: bytes) -> None:
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
145 """Creates a HEAD reference in Git referring to the current HEAD."""
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
146 # By default, we use '@', since that's what will be auto checked out.
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
147 current = b'@'
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
148 if current not in repo._bookmarks:
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
149 current = repo._bookmarks.active or current
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
150
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
151 # We'll be moving this (possibly fake) bookmark into Git.
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
152 git_current = current
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
153 if current == b'@':
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
154 # @ is a special keyword in Git, so we can't use it as a bookmark.
6
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
155 git_current = at_name
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
156 git_branch = dulwich.refs.LOCAL_BRANCH_PREFIX + git_current
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
157 if not dulwich.refs.check_ref_format(git_branch):
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
158 # We can't export this ref to Git. Give up.
6
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
159 ui.warn(f'{git_branch!r} is not a valid branch name for Git.'.encode())
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
160 return
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
161 try:
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
162 # Maybe this is a real bookmark?
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
163 hgsha = repo._bookmarks[current]
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
164 except KeyError:
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
165 # Not a real bookmark. Assume we want the tip of the current branch.
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
166 branch = repo.dirstate.branch()
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
167 try:
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
168 tip = repo.branchtip(branch)
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
169 except hgerr.RepoLookupError:
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
170 # This branch somehow doesn't exist???
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
171 ui.warn(f"{branch} doesn't seem to exist?".encode())
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
172 return
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
173 hgsha = binascii.hexlify(tip)
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
174 gitsha = repo.githandler.map_git_get(hgsha)
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
175 if not gitsha:
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
176 # No Git SHA to match this Hg sha. Give up.
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
177 ui.warn(f'revision {hgsha} was not exported to Git'.encode())
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
178 return
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
179 refs = repo.githandler.git.refs
6
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
180 refs.add_packed_refs({git_branch: gitsha})
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
181 refs.set_symbolic_ref(b'HEAD', git_branch)
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
182
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
183
6
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
184 def fix_refs_hook(ui: hgui.ui, repo: hgrepo.IRepo, **__: object) -> None:
4
5ad58438318a Fix issue where sometimes reads would be cut off.
Paul Fisher <paul@pfish.zone>
parents: 3
diff changeset
185 """Exports to Git and sets up for serving."""
6
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
186 if not _is_gitty(repo):
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
187 return
6
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
188 _fix_refs(ui, repo)
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
189
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
190
6
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
191 def _fix_refs(ui: hgui.ui, repo: GittyRepo) -> None:
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
192 """After a git export, fix up the refs."""
4
5ad58438318a Fix issue where sometimes reads would be cut off.
Paul Fisher <paul@pfish.zone>
parents: 3
diff changeset
193 _clean_all_refs(repo.githandler.git.refs)
6
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
194 repo.githandler.export_hg_tags()
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
195 repo.githandler.update_references()
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
196 default_branch_name = ui.config(
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
197 b'hggit-serve', b'default-branch', b'default'
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
198 )
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
199 _set_head(ui, repo, default_branch_name)
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
200
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
201
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
202 def export_hook(ui: hgui.ui, repo: hgrepo.IRepo, **__: object) -> None:
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
203 if not _is_gitty(repo):
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
204 return
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
205 auto_export = ui.config(b'hggit-serve', b'auto-export')
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
206 if auto_export == b'never':
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
207 return
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
208 if auto_export == b'always' or os.path.isdir(repo.githandler.gitdir):
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
209 repo.githandler.export_commits()
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
210 _fix_refs(ui, repo)
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
211
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
212
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
213 # Interfacing with Mercurial
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
214
6
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
215 __version__ = '0.1.4'
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
216 testedwith = b'7.1 7.2'
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
217
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
218 cmdtable: dict[bytes, object] = {}
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
219
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
220 command = registrar.command(cmdtable)
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
221
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
222
0
c1dc9d21fa57 First cut at serving hg repos with git.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
223 def uisetup(_: hgui.ui) -> None:
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
224 extensions.wrapfunction(
4
5ad58438318a Fix issue where sometimes reads would be cut off.
Paul Fisher <paul@pfish.zone>
parents: 3
diff changeset
225 wireprotoserver, 'handlewsgirequest', _handle_git_protocol
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
226 )
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
227
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
228
6
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
229 def uipopulate(ui: hgui.ui) -> None:
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
230 ui.setconfig(
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
231 b'hooks', b'post-git-export.__gitserve_add_tag__', fix_refs_hook
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
232 )
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
233 ui.setconfig(b'hooks', b'txnclose.__gitserve_export__', export_hook)
1
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
234
a39dd69b8972 Create a more-or-less real package and make it work (?)
Paul Fisher <paul@pfish.zone>
parents: 0
diff changeset
235
6
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
236 __all__ = (
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
237 '__version__',
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
238 'cmdtable',
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
239 'command',
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
240 'testedwith',
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
241 'uipopulate',
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
242 'uisetup',
7113e0ac3662 fix refs on git-export; clean up how gitserve export works.
Paul Fisher <paul@pfish.zone>
parents: 5
diff changeset
243 )