rusty-git 0.3.0__cp312-abi3-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rusty_git/__init__.py +76 -0
- rusty_git/_rusty_git.pyd +0 -0
- rusty_git/_rusty_git.pyi +195 -0
- rusty_git-0.3.0.dist-info/METADATA +227 -0
- rusty_git-0.3.0.dist-info/RECORD +6 -0
- rusty_git-0.3.0.dist-info/WHEEL +4 -0
rusty_git/__init__.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""High-speed pure Rust Git engine for the ``dev-m`` suite.
|
|
2
|
+
|
|
3
|
+
This package is a thin Python shell around the compiled PyO3 extension
|
|
4
|
+
``rusty_git._rusty_git``. Everything public is re-exported here so callers
|
|
5
|
+
never need to know about the private module name::
|
|
6
|
+
|
|
7
|
+
import rusty_git
|
|
8
|
+
|
|
9
|
+
info = await rusty_git.get_commit("/srv/repos/app.git", "HEAD")
|
|
10
|
+
|
|
11
|
+
Layering
|
|
12
|
+
--------
|
|
13
|
+
* ``inspect`` — read paths (commits, refs, blobs, diffs) via ``gix``.
|
|
14
|
+
* ``merge`` — 3-way merge / conflict detection via ``git2`` (libgit2).
|
|
15
|
+
* ``protocol`` — in-process Smart-HTTP packet-line framing.
|
|
16
|
+
* ``upload`` — ``git-upload-pack``: advertisement, negotiation, pack stream.
|
|
17
|
+
* ``receive`` — ``git-receive-pack``: pack ingest and ref updates.
|
|
18
|
+
|
|
19
|
+
The ``CommitInfo``, ``DiffHunk``, ``MergeResult``, ``UploadResult`` and
|
|
20
|
+
``PushResult`` names are ``TypedDict`` declarations in ``_rusty_git.pyi`` only —
|
|
21
|
+
they describe the shape of the dicts the engine returns, and have no runtime
|
|
22
|
+
presence, so they are not re-exported here. Use them under ``TYPE_CHECKING``
|
|
23
|
+
for annotations.
|
|
24
|
+
|
|
25
|
+
Concurrency
|
|
26
|
+
-----------
|
|
27
|
+
Every callable is ``async``. The blocking Git work runs on a Tokio worker
|
|
28
|
+
thread with the GIL released, so the event loop (Granian/Tokio or
|
|
29
|
+
Uvicorn/uvloop) is never stalled.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
from ._rusty_git import (
|
|
33
|
+
GitError,
|
|
34
|
+
GitObjectError,
|
|
35
|
+
GitProtocolError,
|
|
36
|
+
GitRepositoryError,
|
|
37
|
+
__runtime__,
|
|
38
|
+
__rust_version__,
|
|
39
|
+
__version__,
|
|
40
|
+
advertise,
|
|
41
|
+
capabilities,
|
|
42
|
+
compare_refs,
|
|
43
|
+
create_commit,
|
|
44
|
+
encode_pkt_line,
|
|
45
|
+
execute_merge,
|
|
46
|
+
get_commit,
|
|
47
|
+
get_tree_blob,
|
|
48
|
+
init_bare_repository,
|
|
49
|
+
list_branches,
|
|
50
|
+
receive_pack,
|
|
51
|
+
sync,
|
|
52
|
+
upload_pack,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
__all__ = [
|
|
56
|
+
"GitError",
|
|
57
|
+
"GitObjectError",
|
|
58
|
+
"GitProtocolError",
|
|
59
|
+
"GitRepositoryError",
|
|
60
|
+
"__runtime__",
|
|
61
|
+
"__rust_version__",
|
|
62
|
+
"__version__",
|
|
63
|
+
"advertise",
|
|
64
|
+
"capabilities",
|
|
65
|
+
"compare_refs",
|
|
66
|
+
"create_commit",
|
|
67
|
+
"encode_pkt_line",
|
|
68
|
+
"execute_merge",
|
|
69
|
+
"get_commit",
|
|
70
|
+
"get_tree_blob",
|
|
71
|
+
"init_bare_repository",
|
|
72
|
+
"list_branches",
|
|
73
|
+
"receive_pack",
|
|
74
|
+
"sync",
|
|
75
|
+
"upload_pack",
|
|
76
|
+
]
|
rusty_git/_rusty_git.pyd
ADDED
|
Binary file
|
rusty_git/_rusty_git.pyi
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"""Type stubs for the compiled ``rusty_git._rusty_git`` extension module.
|
|
2
|
+
|
|
3
|
+
These are the source of truth for the async surface. Every callable is a
|
|
4
|
+
coroutine: the underlying blocking Git work happens on a Tokio worker thread
|
|
5
|
+
with the GIL released. The public package ``rusty_git`` re-exports all of this,
|
|
6
|
+
so application code can import from ``rusty_git`` directly.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import TypedDict
|
|
10
|
+
|
|
11
|
+
__version__: str
|
|
12
|
+
__rust_version__: str
|
|
13
|
+
__runtime__: str
|
|
14
|
+
|
|
15
|
+
class GitError(Exception):
|
|
16
|
+
"""Base class for every rusty-git failure."""
|
|
17
|
+
|
|
18
|
+
class GitRepositoryError(GitError):
|
|
19
|
+
"""Repository could not be opened, created, or mutated."""
|
|
20
|
+
|
|
21
|
+
class GitObjectError(GitError):
|
|
22
|
+
"""A commit, tree, blob, or diff could not be resolved."""
|
|
23
|
+
|
|
24
|
+
class GitProtocolError(GitError):
|
|
25
|
+
"""Smart-HTTP packet-line negotiation failed."""
|
|
26
|
+
|
|
27
|
+
class CommitInfo(TypedDict):
|
|
28
|
+
sha: str
|
|
29
|
+
author_name: str
|
|
30
|
+
author_email: str
|
|
31
|
+
committer_name: str
|
|
32
|
+
committer_email: str
|
|
33
|
+
message: str
|
|
34
|
+
timestamp: str
|
|
35
|
+
timestamp_epoch: int
|
|
36
|
+
timezone_offset: int
|
|
37
|
+
committer_timestamp: str
|
|
38
|
+
committer_timestamp_epoch: int
|
|
39
|
+
committer_timezone_offset: int
|
|
40
|
+
parent_shas: list[str]
|
|
41
|
+
|
|
42
|
+
class DiffHunk(TypedDict):
|
|
43
|
+
old_path: str
|
|
44
|
+
new_path: str
|
|
45
|
+
old_mode: int
|
|
46
|
+
new_mode: int
|
|
47
|
+
old_start: int
|
|
48
|
+
old_lines: int
|
|
49
|
+
new_start: int
|
|
50
|
+
new_lines: int
|
|
51
|
+
content: str
|
|
52
|
+
is_binary: bool
|
|
53
|
+
|
|
54
|
+
class MergeResult(TypedDict):
|
|
55
|
+
status: str
|
|
56
|
+
commit_sha: str | None
|
|
57
|
+
conflicts: list[str] | None
|
|
58
|
+
|
|
59
|
+
class UploadResult(TypedDict):
|
|
60
|
+
body: bytes
|
|
61
|
+
object_count: int
|
|
62
|
+
used_have: str | None
|
|
63
|
+
side_band: bool
|
|
64
|
+
|
|
65
|
+
class PushResult(TypedDict):
|
|
66
|
+
indexed_objects: int
|
|
67
|
+
updated_refs: list[str]
|
|
68
|
+
|
|
69
|
+
class CommitCreateResult(TypedDict):
|
|
70
|
+
commit_sha: str
|
|
71
|
+
tree_sha: str
|
|
72
|
+
parent_shas: list[str]
|
|
73
|
+
branch: str
|
|
74
|
+
|
|
75
|
+
async def init_bare_repository(path: str) -> str:
|
|
76
|
+
"""Create a bare repository at *path*; returns the normalised path."""
|
|
77
|
+
|
|
78
|
+
async def get_commit(repo_path: str, sha: str) -> CommitInfo:
|
|
79
|
+
"""Resolve *sha* (or any revision) to full commit metadata."""
|
|
80
|
+
|
|
81
|
+
async def list_branches(repo_path: str) -> list[str]:
|
|
82
|
+
"""Return the sorted local branch names."""
|
|
83
|
+
|
|
84
|
+
async def get_tree_blob(repo_path: str, ref_name: str, file_path: str) -> bytes | None:
|
|
85
|
+
"""Return raw file bytes, or ``None`` when the path does not exist."""
|
|
86
|
+
|
|
87
|
+
async def compare_refs(repo_path: str, base_ref: str, head_ref: str) -> list[DiffHunk]:
|
|
88
|
+
"""Return unified-diff hunks between two refs."""
|
|
89
|
+
|
|
90
|
+
async def create_commit(
|
|
91
|
+
repo_path: str,
|
|
92
|
+
branch: str,
|
|
93
|
+
files: dict[str, bytes | None],
|
|
94
|
+
message: str,
|
|
95
|
+
author_name: str | None = None,
|
|
96
|
+
author_email: str | None = None,
|
|
97
|
+
expected_sha: str | None = None,
|
|
98
|
+
force: bool = False,
|
|
99
|
+
) -> CommitCreateResult:
|
|
100
|
+
"""Create a commit atomically on *branch* with the provided *files* mapping.
|
|
101
|
+
|
|
102
|
+
*files* maps relative paths to `bytes` (create/update) or `None` (delete).
|
|
103
|
+
Supports initial root commits, consequent commits, and optimistic concurrency
|
|
104
|
+
control (`expected_sha` / force-with-lease).
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
async def execute_merge(
|
|
108
|
+
repo_path: str,
|
|
109
|
+
base_ref: str,
|
|
110
|
+
head_ref: str,
|
|
111
|
+
author_name: str | None = None,
|
|
112
|
+
author_email: str | None = None,
|
|
113
|
+
commit_message: str | None = None,
|
|
114
|
+
) -> MergeResult:
|
|
115
|
+
"""3-way merge *head_ref* into *base_ref*."""
|
|
116
|
+
|
|
117
|
+
def capabilities() -> list[str]:
|
|
118
|
+
"""Return the Git protocols this engine can serve in-process."""
|
|
119
|
+
|
|
120
|
+
async def advertise(repo_path: str, service: str) -> bytes:
|
|
121
|
+
"""Return the smart-HTTP ref advertisement for *service*.
|
|
122
|
+
|
|
123
|
+
*service* must be ``"git-upload-pack"`` or ``"git-receive-pack"``. The
|
|
124
|
+
result is the complete HTTP response body, including the
|
|
125
|
+
``# service=...`` prefix line.
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
async def upload_pack(repo_path: str, body: bytes) -> UploadResult:
|
|
129
|
+
"""Serve a ``git-upload-pack`` request body.
|
|
130
|
+
|
|
131
|
+
Returns the response body (``NAK``/``ACK`` plus the pkt-line-framed pack),
|
|
132
|
+
ready to send verbatim as an HTTP response.
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
async def receive_pack(
|
|
136
|
+
repo_path: str,
|
|
137
|
+
body: bytes,
|
|
138
|
+
author_name: str | None = None,
|
|
139
|
+
author_email: str | None = None,
|
|
140
|
+
) -> PushResult:
|
|
141
|
+
"""Serve a ``git-receive-pack`` request body.
|
|
142
|
+
|
|
143
|
+
Ingests the inbound pack, then moves refs. Objects are made durable before
|
|
144
|
+
any ref names them, so a failure never leaves a repository that ``git fsck``
|
|
145
|
+
rejects.
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
def encode_pkt_line(payload: bytes) -> bytes:
|
|
149
|
+
"""Frame *payload* as a Git pkt-line.
|
|
150
|
+
|
|
151
|
+
Raises :class:`GitProtocolError` when the payload exceeds
|
|
152
|
+
:data:`MAX_PKT_PAYLOAD` and cannot fit in a single frame.
|
|
153
|
+
"""
|
|
154
|
+
|
|
155
|
+
class _SyncModule:
|
|
156
|
+
"""Synchronous interface releasing the Python GIL directly on calling thread."""
|
|
157
|
+
|
|
158
|
+
def init_bare_repository(self, path: str) -> str: ...
|
|
159
|
+
def get_commit(self, repo_path: str, sha: str) -> CommitInfo: ...
|
|
160
|
+
def list_branches(self, repo_path: str) -> list[str]: ...
|
|
161
|
+
def get_tree_blob(self, repo_path: str, ref_name: str, file_path: str) -> bytes | None: ...
|
|
162
|
+
def compare_refs(self, repo_path: str, base_ref: str, head_ref: str) -> list[DiffHunk]: ...
|
|
163
|
+
def create_commit(
|
|
164
|
+
self,
|
|
165
|
+
repo_path: str,
|
|
166
|
+
branch: str,
|
|
167
|
+
files: dict[str, bytes | None],
|
|
168
|
+
message: str,
|
|
169
|
+
author_name: str | None = None,
|
|
170
|
+
author_email: str | None = None,
|
|
171
|
+
expected_sha: str | None = None,
|
|
172
|
+
force: bool = False,
|
|
173
|
+
) -> CommitCreateResult: ...
|
|
174
|
+
def execute_merge(
|
|
175
|
+
self,
|
|
176
|
+
repo_path: str,
|
|
177
|
+
base_ref: str,
|
|
178
|
+
head_ref: str,
|
|
179
|
+
author_name: str | None = None,
|
|
180
|
+
author_email: str | None = None,
|
|
181
|
+
commit_message: str | None = None,
|
|
182
|
+
) -> MergeResult: ...
|
|
183
|
+
def capabilities(self) -> list[str]: ...
|
|
184
|
+
def encode_pkt_line(self, payload: bytes) -> bytes: ...
|
|
185
|
+
def advertise(self, repo_path: str, service: str) -> bytes: ...
|
|
186
|
+
def upload_pack(self, repo_path: str, body: bytes) -> UploadResult: ...
|
|
187
|
+
def receive_pack(
|
|
188
|
+
self,
|
|
189
|
+
repo_path: str,
|
|
190
|
+
body: bytes,
|
|
191
|
+
author_name: str | None = None,
|
|
192
|
+
author_email: str | None = None,
|
|
193
|
+
) -> PushResult: ...
|
|
194
|
+
|
|
195
|
+
sync: _SyncModule
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: rusty-git
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: High-speed pure Rust Git engine (gix + git2) for Python
|
|
5
|
+
Classifier: Programming Language :: Rust
|
|
6
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
11
|
+
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
12
|
+
Requires-Python: >=3.12
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
# rusty-git
|
|
16
|
+
|
|
17
|
+
[](https://gitlab.com/framework-m/rusty-git/-/pipelines)
|
|
18
|
+
[](https://pypi.org/project/rusty-git/)
|
|
19
|
+
[](https://opensource.org/licenses/Apache-2.0)
|
|
20
|
+
|
|
21
|
+
**High-speed pure Rust Git engine (`gix` + `git2`) compiled via PyO3 with both native `async` (Tokio) and GIL-released `sync` APIs.**
|
|
22
|
+
|
|
23
|
+
`rusty-git` provides in-process Git operations with **zero OS subprocess forks** and **statically-compiled native wheels** (no dynamic `libgit2.so` dependencies required).
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install rusty-git
|
|
31
|
+
# or with uv:
|
|
32
|
+
uv add rusty-git
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Quickstart: 100% In-Process Demo (Zero Subprocesses)
|
|
38
|
+
|
|
39
|
+
Copy-paste this into `example.py` to test immediately in any environment:
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
import asyncio
|
|
43
|
+
import os
|
|
44
|
+
import tempfile
|
|
45
|
+
import rusty_git
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
async def main():
|
|
49
|
+
with tempfile.TemporaryDirectory() as tmp_dir:
|
|
50
|
+
repo_path = os.path.join(tmp_dir, "demo.git")
|
|
51
|
+
|
|
52
|
+
# 1. Initialize a bare repository in-process (ZERO subprocesses)
|
|
53
|
+
await rusty_git.init_bare_repository(repo_path)
|
|
54
|
+
|
|
55
|
+
# 2. Create the initial root commit in-process
|
|
56
|
+
res = await rusty_git.create_commit(
|
|
57
|
+
repo_path,
|
|
58
|
+
branch="main",
|
|
59
|
+
files={
|
|
60
|
+
"README.md": b"# Hello from rusty-git!\n",
|
|
61
|
+
"src/main.py": b"print('Hello World')\n",
|
|
62
|
+
},
|
|
63
|
+
message="Initial commit",
|
|
64
|
+
author_name="Alice",
|
|
65
|
+
author_email="alice@example.com",
|
|
66
|
+
)
|
|
67
|
+
print("Root Commit SHA:", res["commit_sha"])
|
|
68
|
+
|
|
69
|
+
# 3. Inspect commit in-process
|
|
70
|
+
commit = await rusty_git.get_commit(repo_path, "HEAD")
|
|
71
|
+
print(f"Author: {commit['author_name']} <{commit['author_email']}>")
|
|
72
|
+
print(f"Message: {commit['message']}")
|
|
73
|
+
|
|
74
|
+
# 4. Read tree blob without disk checkout
|
|
75
|
+
blob = await rusty_git.get_tree_blob(repo_path, "HEAD", "README.md")
|
|
76
|
+
print("Blob Content:", blob.decode("utf-8").strip())
|
|
77
|
+
|
|
78
|
+
# 5. List branches
|
|
79
|
+
branches = await rusty_git.list_branches(repo_path)
|
|
80
|
+
print("Branches:", branches)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
asyncio.run(main())
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Dual-Color Usage: Async & Sync
|
|
89
|
+
|
|
90
|
+
### 1. Asynchronous API (Default - for Litestar, FastAPI, Granian, Uvicorn)
|
|
91
|
+
|
|
92
|
+
All blocking Git I/O is offloaded to a Tokio multi-threaded worker pool, releasing the Python GIL:
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
import asyncio
|
|
96
|
+
import rusty_git
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
async def main():
|
|
100
|
+
repo_path = "/path/to/your/repo"
|
|
101
|
+
|
|
102
|
+
# 1. Inspect commits
|
|
103
|
+
commit = await rusty_git.get_commit(repo_path, "HEAD")
|
|
104
|
+
print(commit["sha"], commit["message"], commit["author_name"])
|
|
105
|
+
|
|
106
|
+
# 2. Read tree blobs without disk checkout
|
|
107
|
+
readme = await rusty_git.get_tree_blob(repo_path, "main", "README.md")
|
|
108
|
+
print(readme.decode("utf-8"))
|
|
109
|
+
|
|
110
|
+
# 3. Fast unified diffs
|
|
111
|
+
hunks = await rusty_git.compare_refs(repo_path, "main~1", "main")
|
|
112
|
+
for hunk in hunks:
|
|
113
|
+
print(hunk["new_path"], hunk["content"])
|
|
114
|
+
|
|
115
|
+
# 4. 3-Way Merge
|
|
116
|
+
result = await rusty_git.execute_merge(
|
|
117
|
+
repo_path,
|
|
118
|
+
base_ref="main",
|
|
119
|
+
head_ref="feature",
|
|
120
|
+
author_name="Automated Merge",
|
|
121
|
+
author_email="bot@example.com",
|
|
122
|
+
)
|
|
123
|
+
if result["status"] == "merged":
|
|
124
|
+
print("Merged Commit SHA:", result["commit_sha"])
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
asyncio.run(main())
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
### 2. Synchronous API (`rusty_git.sync` - for CLI tools, Celery, scripts)
|
|
133
|
+
|
|
134
|
+
Direct execution on the calling thread with the Python GIL cleanly released (`py.detach`):
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
import rusty_git
|
|
138
|
+
|
|
139
|
+
# Read commit synchronously
|
|
140
|
+
commit = rusty_git.sync.get_commit("/path/to/repo.git", "HEAD")
|
|
141
|
+
print(commit["sha"], commit["author_name"])
|
|
142
|
+
|
|
143
|
+
# List branches synchronously
|
|
144
|
+
branches = rusty_git.sync.list_branches("/path/to/repo.git")
|
|
145
|
+
print("Branches:", branches)
|
|
146
|
+
|
|
147
|
+
# Read file directly from commit tree
|
|
148
|
+
blob = rusty_git.sync.get_tree_blob("/path/to/repo.git", "HEAD", "pyproject.toml")
|
|
149
|
+
|
|
150
|
+
# Create a commit directly on any branch (new or existing)
|
|
151
|
+
res = rusty_git.sync.create_commit(
|
|
152
|
+
"/path/to/repo.git",
|
|
153
|
+
branch="feature-x",
|
|
154
|
+
files={"hello.txt": b"Hello world!\n"},
|
|
155
|
+
message="feat: add hello.txt",
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
# 3-Way Merge synchronously
|
|
159
|
+
result = rusty_git.sync.execute_merge(
|
|
160
|
+
"/path/to/repo.git",
|
|
161
|
+
"main",
|
|
162
|
+
"feature",
|
|
163
|
+
author_name="Merge Bot",
|
|
164
|
+
author_email="bot@example.com",
|
|
165
|
+
)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Architectural Note: Forges & Branch Management
|
|
171
|
+
|
|
172
|
+
`rusty-git` is designed for high-performance server-side forges and tools operating on **bare repositories**:
|
|
173
|
+
|
|
174
|
+
* **Creating branches with commits**: Passing any branch name to `create_commit(...)` will create or advance that branch atomically.
|
|
175
|
+
* **Creating a branch without a commit**: Git branches are simply ref pointers. To create a branch pointing to an existing commit without a new commit, your application or CLI can write the commit SHA directly to `refs/heads/<branch_name>`.
|
|
176
|
+
* **Switching active branch (`HEAD`)**: In a bare repo or CLI, switching the symbolic reference is done by writing `ref: refs/heads/<branch_name>\n` to the `HEAD` file.
|
|
177
|
+
|
|
178
|
+
### Engine Architecture: Pure `gix` vs. `git2` Wire Streaming
|
|
179
|
+
|
|
180
|
+
`rusty-git` intentionally separates user-facing operations from network pack streaming:
|
|
181
|
+
|
|
182
|
+
* **100% Pure `gix` Core (WebAssembly / Pyodide Ready)**: `commit` (atomic in-memory trees & commits), `inspect` (refs, tree blobs, histogram unified diffs), and `merge` (3-way ORT tree merge) run entirely on pure-Rust `gix`. They require zero C headers and run in browsers and Pyodide.
|
|
183
|
+
* **Wire Protocol Pack Streaming (`git2`)**: Ingesting thin packs (`git push`) and streaming sliding-window delta packs (`git clone`/`git fetch`) use `libgit2`'s battle-tested pack engine. Once `gix-pack` high-level streaming pack generation reaches full maturity, these remaining wire endpoints will transition to `gix`, completing the journey to 100% pure Rust.
|
|
184
|
+
|
|
185
|
+
This keeps `rusty-git` focused entirely on performance-critical operations without unnecessary file-I/O wrapper overhead.
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Smart-HTTP Protocol Wire Support
|
|
190
|
+
|
|
191
|
+
`rusty-git` can drive Git HTTP and SSH protocol negotiation completely in-process:
|
|
192
|
+
|
|
193
|
+
> **Note on Transport & Auth (SSH / TLS):** `rusty-git` operates directly on request/response byte streams rather than managing sockets. Transport encryption and authentication (SSH keys via `asyncssh`/OpenSSH, or TLS/mTLS client certs via Nginx/Caddy/HTTPX) happen cleanly at the transport layer before passing payloads to `rusty-git`.
|
|
194
|
+
|
|
195
|
+
```python
|
|
196
|
+
import rusty_git
|
|
197
|
+
|
|
198
|
+
# Ref advertisement for git-upload-pack (git clone / fetch)
|
|
199
|
+
advert = await rusty_git.advertise("/srv/repos/myorg/backend.git", "git-upload-pack")
|
|
200
|
+
|
|
201
|
+
# Handle pack negotiation and streaming
|
|
202
|
+
upload_res = await rusty_git.upload_pack("/srv/repos/myorg/backend.git", request_body)
|
|
203
|
+
|
|
204
|
+
# Ingest inbound git push packfile atomically
|
|
205
|
+
push_res = await rusty_git.receive_pack("/srv/repos/myorg/backend.git", push_body)
|
|
206
|
+
print("Updated Refs:", push_res["updated_refs"])
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Development & Testing
|
|
212
|
+
|
|
213
|
+
### Rust Tests
|
|
214
|
+
```bash
|
|
215
|
+
cargo test
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Python Integration Tests
|
|
219
|
+
```bash
|
|
220
|
+
uv run pytest
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## License
|
|
226
|
+
|
|
227
|
+
Apache-2.0 © Framework M Contributors
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
rusty_git-0.3.0.dist-info/METADATA,sha256=nIa-NBENxvSy4vRBBnFoaQxudrTNCJkX1wFnTKx50Ps,7761
|
|
2
|
+
rusty_git-0.3.0.dist-info/WHEEL,sha256=rQOyhw13PhAFR9Q0_tF356_RmdK837INftPr-lyfJnE,98
|
|
3
|
+
rusty_git/_rusty_git.pyi,sha256=XOXipEiRsQhoRJ1-TTCIB_xzAzaqmIHwIw0QcrlKh4Y,6103
|
|
4
|
+
rusty_git/_rusty_git.pyd,sha256=6m3WHuSQfdzhRqAx4LNWH55mS_dR9KfHUxhwcvmr59c,13860352
|
|
5
|
+
rusty_git/__init__.py,sha256=pozmSzjh30xmhYQSkNU-Sik9y9QMeMK5Sv5ReavFeb4,2086
|
|
6
|
+
rusty_git-0.3.0.dist-info/RECORD,,
|