agmem 0.1.1__py3-none-any.whl → 0.1.3__py3-none-any.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.
- {agmem-0.1.1.dist-info → agmem-0.1.3.dist-info}/METADATA +157 -16
- agmem-0.1.3.dist-info/RECORD +105 -0
- memvcs/__init__.py +1 -1
- memvcs/cli.py +45 -31
- memvcs/commands/__init__.py +9 -9
- memvcs/commands/add.py +83 -76
- memvcs/commands/audit.py +59 -0
- memvcs/commands/blame.py +46 -53
- memvcs/commands/branch.py +13 -33
- memvcs/commands/checkout.py +27 -32
- memvcs/commands/clean.py +18 -23
- memvcs/commands/clone.py +11 -1
- memvcs/commands/commit.py +40 -39
- memvcs/commands/daemon.py +109 -76
- memvcs/commands/decay.py +77 -0
- memvcs/commands/diff.py +56 -57
- memvcs/commands/distill.py +90 -0
- memvcs/commands/federated.py +53 -0
- memvcs/commands/fsck.py +86 -61
- memvcs/commands/garden.py +40 -35
- memvcs/commands/gc.py +51 -0
- memvcs/commands/graph.py +41 -48
- memvcs/commands/init.py +16 -24
- memvcs/commands/log.py +25 -40
- memvcs/commands/merge.py +69 -27
- memvcs/commands/pack.py +129 -0
- memvcs/commands/prove.py +66 -0
- memvcs/commands/pull.py +31 -1
- memvcs/commands/push.py +4 -2
- memvcs/commands/recall.py +145 -0
- memvcs/commands/reflog.py +13 -22
- memvcs/commands/remote.py +1 -0
- memvcs/commands/repair.py +66 -0
- memvcs/commands/reset.py +23 -33
- memvcs/commands/resolve.py +130 -0
- memvcs/commands/resurrect.py +82 -0
- memvcs/commands/search.py +3 -4
- memvcs/commands/serve.py +2 -1
- memvcs/commands/show.py +66 -36
- memvcs/commands/stash.py +34 -34
- memvcs/commands/status.py +27 -35
- memvcs/commands/tag.py +23 -47
- memvcs/commands/test.py +30 -44
- memvcs/commands/timeline.py +111 -0
- memvcs/commands/tree.py +26 -27
- memvcs/commands/verify.py +110 -0
- memvcs/commands/when.py +115 -0
- memvcs/core/access_index.py +167 -0
- memvcs/core/audit.py +124 -0
- memvcs/core/config_loader.py +3 -1
- memvcs/core/consistency.py +214 -0
- memvcs/core/crypto_verify.py +280 -0
- memvcs/core/decay.py +185 -0
- memvcs/core/diff.py +158 -143
- memvcs/core/distiller.py +277 -0
- memvcs/core/encryption.py +169 -0
- memvcs/core/federated.py +86 -0
- memvcs/core/gardener.py +176 -145
- memvcs/core/hooks.py +48 -14
- memvcs/core/ipfs_remote.py +39 -0
- memvcs/core/knowledge_graph.py +135 -138
- memvcs/core/llm/__init__.py +10 -0
- memvcs/core/llm/anthropic_provider.py +50 -0
- memvcs/core/llm/base.py +27 -0
- memvcs/core/llm/factory.py +30 -0
- memvcs/core/llm/openai_provider.py +36 -0
- memvcs/core/merge.py +260 -170
- memvcs/core/objects.py +110 -101
- memvcs/core/pack.py +92 -0
- memvcs/core/pii_scanner.py +147 -146
- memvcs/core/privacy_budget.py +63 -0
- memvcs/core/refs.py +132 -115
- memvcs/core/remote.py +38 -0
- memvcs/core/repository.py +254 -164
- memvcs/core/schema.py +155 -113
- memvcs/core/staging.py +60 -65
- memvcs/core/storage/__init__.py +20 -18
- memvcs/core/storage/base.py +74 -70
- memvcs/core/storage/gcs.py +70 -68
- memvcs/core/storage/local.py +42 -40
- memvcs/core/storage/s3.py +105 -110
- memvcs/core/temporal_index.py +121 -0
- memvcs/core/test_runner.py +101 -93
- memvcs/core/trust.py +103 -0
- memvcs/core/vector_store.py +56 -36
- memvcs/core/zk_proofs.py +26 -0
- memvcs/integrations/mcp_server.py +1 -3
- memvcs/integrations/web_ui/server.py +25 -26
- memvcs/retrieval/__init__.py +22 -0
- memvcs/retrieval/base.py +54 -0
- memvcs/retrieval/pack.py +128 -0
- memvcs/retrieval/recaller.py +105 -0
- memvcs/retrieval/strategies.py +314 -0
- memvcs/utils/__init__.py +3 -3
- memvcs/utils/helpers.py +52 -52
- agmem-0.1.1.dist-info/RECORD +0 -67
- {agmem-0.1.1.dist-info → agmem-0.1.3.dist-info}/WHEEL +0 -0
- {agmem-0.1.1.dist-info → agmem-0.1.3.dist-info}/entry_points.txt +0 -0
- {agmem-0.1.1.dist-info → agmem-0.1.3.dist-info}/licenses/LICENSE +0 -0
- {agmem-0.1.1.dist-info → agmem-0.1.3.dist-info}/top_level.txt +0 -0
memvcs/core/diff.py
CHANGED
|
@@ -14,6 +14,7 @@ from .objects import ObjectStore, Commit, Tree, Blob
|
|
|
14
14
|
|
|
15
15
|
class DiffType(Enum):
|
|
16
16
|
"""Types of differences."""
|
|
17
|
+
|
|
17
18
|
ADDED = "added"
|
|
18
19
|
DELETED = "deleted"
|
|
19
20
|
MODIFIED = "modified"
|
|
@@ -23,6 +24,7 @@ class DiffType(Enum):
|
|
|
23
24
|
@dataclass
|
|
24
25
|
class FileDiff:
|
|
25
26
|
"""Difference for a single file."""
|
|
27
|
+
|
|
26
28
|
path: str
|
|
27
29
|
diff_type: DiffType
|
|
28
30
|
old_hash: Optional[str]
|
|
@@ -35,6 +37,7 @@ class FileDiff:
|
|
|
35
37
|
@dataclass
|
|
36
38
|
class TreeDiff:
|
|
37
39
|
"""Difference between two trees."""
|
|
40
|
+
|
|
38
41
|
files: List[FileDiff]
|
|
39
42
|
added_count: int
|
|
40
43
|
deleted_count: int
|
|
@@ -43,67 +46,67 @@ class TreeDiff:
|
|
|
43
46
|
|
|
44
47
|
class DiffEngine:
|
|
45
48
|
"""Engine for computing differences."""
|
|
46
|
-
|
|
49
|
+
|
|
47
50
|
def __init__(self, object_store: ObjectStore):
|
|
48
51
|
self.object_store = object_store
|
|
49
|
-
|
|
52
|
+
|
|
50
53
|
def get_tree_files(self, tree_hash: str) -> Dict[str, str]:
|
|
51
54
|
"""Get all files in a tree with their blob hashes."""
|
|
52
55
|
files = {}
|
|
53
56
|
tree = Tree.load(self.object_store, tree_hash)
|
|
54
|
-
|
|
57
|
+
|
|
55
58
|
if tree:
|
|
56
59
|
for entry in tree.entries:
|
|
57
|
-
path = entry.path +
|
|
60
|
+
path = entry.path + "/" + entry.name if entry.path else entry.name
|
|
58
61
|
files[path] = entry.hash
|
|
59
|
-
|
|
62
|
+
|
|
60
63
|
return files
|
|
61
|
-
|
|
64
|
+
|
|
62
65
|
def get_blob_content(self, hash_id: Optional[str]) -> Optional[str]:
|
|
63
66
|
"""Get blob content as string."""
|
|
64
67
|
if not hash_id:
|
|
65
68
|
return None
|
|
66
|
-
|
|
69
|
+
|
|
67
70
|
blob = Blob.load(self.object_store, hash_id)
|
|
68
71
|
if blob:
|
|
69
|
-
return blob.content.decode(
|
|
72
|
+
return blob.content.decode("utf-8", errors="replace")
|
|
70
73
|
return None
|
|
71
|
-
|
|
72
|
-
def compute_line_diff(
|
|
74
|
+
|
|
75
|
+
def compute_line_diff(
|
|
76
|
+
self, old_content: Optional[str], new_content: Optional[str]
|
|
77
|
+
) -> List[str]:
|
|
73
78
|
"""
|
|
74
79
|
Compute line-by-line diff between two contents.
|
|
75
|
-
|
|
80
|
+
|
|
76
81
|
Returns:
|
|
77
82
|
List of diff lines with +/- prefixes
|
|
78
83
|
"""
|
|
79
|
-
old_lines = (old_content or
|
|
80
|
-
new_lines = (new_content or
|
|
81
|
-
|
|
84
|
+
old_lines = (old_content or "").splitlines(keepends=True)
|
|
85
|
+
new_lines = (new_content or "").splitlines(keepends=True)
|
|
86
|
+
|
|
82
87
|
# Simple diff algorithm (LCS-based would be better)
|
|
83
88
|
diff_lines = []
|
|
84
|
-
|
|
89
|
+
|
|
85
90
|
# Handle empty cases
|
|
86
|
-
if not old_lines or old_lines == [
|
|
91
|
+
if not old_lines or old_lines == [""]:
|
|
87
92
|
for line in new_lines:
|
|
88
|
-
diff_lines.append(f
|
|
93
|
+
diff_lines.append(f"+ {line.rstrip()}")
|
|
89
94
|
return diff_lines
|
|
90
|
-
|
|
91
|
-
if not new_lines or new_lines == [
|
|
95
|
+
|
|
96
|
+
if not new_lines or new_lines == [""]:
|
|
92
97
|
for line in old_lines:
|
|
93
|
-
diff_lines.append(f
|
|
98
|
+
diff_lines.append(f"- {line.rstrip()}")
|
|
94
99
|
return diff_lines
|
|
95
|
-
|
|
100
|
+
|
|
96
101
|
# Use unified diff style
|
|
97
|
-
max_lines = max(len(old_lines), len(new_lines))
|
|
98
|
-
|
|
99
102
|
i, j = 0, 0
|
|
100
103
|
while i < len(old_lines) or j < len(new_lines):
|
|
101
104
|
if i < len(old_lines) and j < len(new_lines):
|
|
102
105
|
old_line = old_lines[i].rstrip()
|
|
103
106
|
new_line = new_lines[j].rstrip()
|
|
104
|
-
|
|
107
|
+
|
|
105
108
|
if old_line == new_line:
|
|
106
|
-
diff_lines.append(f
|
|
109
|
+
diff_lines.append(f" {old_line}")
|
|
107
110
|
i += 1
|
|
108
111
|
j += 1
|
|
109
112
|
else:
|
|
@@ -112,153 +115,158 @@ class DiffEngine:
|
|
|
112
115
|
for k in range(j + 1, min(j + 5, len(new_lines))):
|
|
113
116
|
if new_lines[k].rstrip() == old_line:
|
|
114
117
|
# Lines were added
|
|
115
|
-
for
|
|
116
|
-
diff_lines.append(f
|
|
118
|
+
for idx in range(j, k):
|
|
119
|
+
diff_lines.append(f"+ {new_lines[idx].rstrip()}")
|
|
117
120
|
j = k
|
|
118
121
|
found = True
|
|
119
122
|
break
|
|
120
|
-
|
|
123
|
+
|
|
121
124
|
if not found:
|
|
122
125
|
# Line was removed
|
|
123
|
-
diff_lines.append(f
|
|
126
|
+
diff_lines.append(f"- {old_line}")
|
|
124
127
|
i += 1
|
|
125
128
|
elif i < len(old_lines):
|
|
126
|
-
diff_lines.append(f
|
|
129
|
+
diff_lines.append(f"- {old_lines[i].rstrip()}")
|
|
127
130
|
i += 1
|
|
128
131
|
else:
|
|
129
|
-
diff_lines.append(f
|
|
132
|
+
diff_lines.append(f"+ {new_lines[j].rstrip()}")
|
|
130
133
|
j += 1
|
|
131
|
-
|
|
134
|
+
|
|
132
135
|
return diff_lines
|
|
133
|
-
|
|
136
|
+
|
|
134
137
|
def diff_trees(self, old_tree_hash: Optional[str], new_tree_hash: Optional[str]) -> TreeDiff:
|
|
135
138
|
"""
|
|
136
139
|
Compute diff between two trees.
|
|
137
|
-
|
|
140
|
+
|
|
138
141
|
Args:
|
|
139
142
|
old_tree_hash: Hash of old tree (None for empty)
|
|
140
143
|
new_tree_hash: Hash of new tree (None for empty)
|
|
141
|
-
|
|
144
|
+
|
|
142
145
|
Returns:
|
|
143
146
|
TreeDiff with file differences
|
|
144
147
|
"""
|
|
145
148
|
old_files = self.get_tree_files(old_tree_hash) if old_tree_hash else {}
|
|
146
149
|
new_files = self.get_tree_files(new_tree_hash) if new_tree_hash else {}
|
|
147
|
-
|
|
150
|
+
|
|
148
151
|
all_paths = set(old_files.keys()) | set(new_files.keys())
|
|
149
|
-
|
|
152
|
+
|
|
150
153
|
file_diffs = []
|
|
151
154
|
added = 0
|
|
152
155
|
deleted = 0
|
|
153
156
|
modified = 0
|
|
154
|
-
|
|
157
|
+
|
|
155
158
|
for path in sorted(all_paths):
|
|
156
159
|
old_hash = old_files.get(path)
|
|
157
160
|
new_hash = new_files.get(path)
|
|
158
|
-
|
|
161
|
+
|
|
159
162
|
if not old_hash and new_hash:
|
|
160
163
|
# Added
|
|
161
164
|
new_content = self.get_blob_content(new_hash)
|
|
162
165
|
diff_lines = self.compute_line_diff(None, new_content)
|
|
163
|
-
|
|
164
|
-
file_diffs.append(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
166
|
+
|
|
167
|
+
file_diffs.append(
|
|
168
|
+
FileDiff(
|
|
169
|
+
path=path,
|
|
170
|
+
diff_type=DiffType.ADDED,
|
|
171
|
+
old_hash=None,
|
|
172
|
+
new_hash=new_hash,
|
|
173
|
+
old_content=None,
|
|
174
|
+
new_content=new_content,
|
|
175
|
+
diff_lines=diff_lines,
|
|
176
|
+
)
|
|
177
|
+
)
|
|
173
178
|
added += 1
|
|
174
|
-
|
|
179
|
+
|
|
175
180
|
elif old_hash and not new_hash:
|
|
176
181
|
# Deleted
|
|
177
182
|
old_content = self.get_blob_content(old_hash)
|
|
178
183
|
diff_lines = self.compute_line_diff(old_content, None)
|
|
179
|
-
|
|
180
|
-
file_diffs.append(
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
184
|
+
|
|
185
|
+
file_diffs.append(
|
|
186
|
+
FileDiff(
|
|
187
|
+
path=path,
|
|
188
|
+
diff_type=DiffType.DELETED,
|
|
189
|
+
old_hash=old_hash,
|
|
190
|
+
new_hash=None,
|
|
191
|
+
old_content=old_content,
|
|
192
|
+
new_content=None,
|
|
193
|
+
diff_lines=diff_lines,
|
|
194
|
+
)
|
|
195
|
+
)
|
|
189
196
|
deleted += 1
|
|
190
|
-
|
|
197
|
+
|
|
191
198
|
elif old_hash != new_hash:
|
|
192
199
|
# Modified
|
|
193
200
|
old_content = self.get_blob_content(old_hash)
|
|
194
201
|
new_content = self.get_blob_content(new_hash)
|
|
195
202
|
diff_lines = self.compute_line_diff(old_content, new_content)
|
|
196
|
-
|
|
197
|
-
file_diffs.append(
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
203
|
+
|
|
204
|
+
file_diffs.append(
|
|
205
|
+
FileDiff(
|
|
206
|
+
path=path,
|
|
207
|
+
diff_type=DiffType.MODIFIED,
|
|
208
|
+
old_hash=old_hash,
|
|
209
|
+
new_hash=new_hash,
|
|
210
|
+
old_content=old_content,
|
|
211
|
+
new_content=new_content,
|
|
212
|
+
diff_lines=diff_lines,
|
|
213
|
+
)
|
|
214
|
+
)
|
|
206
215
|
modified += 1
|
|
207
|
-
|
|
216
|
+
|
|
208
217
|
return TreeDiff(
|
|
209
|
-
files=file_diffs,
|
|
210
|
-
added_count=added,
|
|
211
|
-
deleted_count=deleted,
|
|
212
|
-
modified_count=modified
|
|
218
|
+
files=file_diffs, added_count=added, deleted_count=deleted, modified_count=modified
|
|
213
219
|
)
|
|
214
|
-
|
|
215
|
-
def diff_commits(
|
|
220
|
+
|
|
221
|
+
def diff_commits(
|
|
222
|
+
self, old_commit_hash: Optional[str], new_commit_hash: Optional[str]
|
|
223
|
+
) -> TreeDiff:
|
|
216
224
|
"""
|
|
217
225
|
Compute diff between two commits.
|
|
218
|
-
|
|
226
|
+
|
|
219
227
|
Args:
|
|
220
228
|
old_commit_hash: Hash of old commit (None for empty)
|
|
221
229
|
new_commit_hash: Hash of new commit (None for empty)
|
|
222
|
-
|
|
230
|
+
|
|
223
231
|
Returns:
|
|
224
232
|
TreeDiff with file differences
|
|
225
233
|
"""
|
|
226
234
|
old_tree_hash = None
|
|
227
235
|
new_tree_hash = None
|
|
228
|
-
|
|
236
|
+
|
|
229
237
|
if old_commit_hash:
|
|
230
238
|
old_commit = Commit.load(self.object_store, old_commit_hash)
|
|
231
239
|
if old_commit:
|
|
232
240
|
old_tree_hash = old_commit.tree
|
|
233
|
-
|
|
241
|
+
|
|
234
242
|
if new_commit_hash:
|
|
235
243
|
new_commit = Commit.load(self.object_store, new_commit_hash)
|
|
236
244
|
if new_commit:
|
|
237
245
|
new_tree_hash = new_commit.tree
|
|
238
|
-
|
|
246
|
+
|
|
239
247
|
return self.diff_trees(old_tree_hash, new_tree_hash)
|
|
240
|
-
|
|
241
|
-
def format_diff(self, tree_diff: TreeDiff, old_ref: str =
|
|
248
|
+
|
|
249
|
+
def format_diff(self, tree_diff: TreeDiff, old_ref: str = "a", new_ref: str = "b") -> str:
|
|
242
250
|
"""
|
|
243
251
|
Format tree diff as unified diff string.
|
|
244
|
-
|
|
252
|
+
|
|
245
253
|
Args:
|
|
246
254
|
tree_diff: TreeDiff to format
|
|
247
255
|
old_ref: Label for old version
|
|
248
256
|
new_ref: Label for new version
|
|
249
|
-
|
|
257
|
+
|
|
250
258
|
Returns:
|
|
251
259
|
Formatted diff string
|
|
252
260
|
"""
|
|
253
261
|
lines = []
|
|
254
|
-
|
|
262
|
+
|
|
255
263
|
for file_diff in tree_diff.files:
|
|
256
264
|
if file_diff.diff_type == DiffType.UNCHANGED:
|
|
257
265
|
continue
|
|
258
|
-
|
|
266
|
+
|
|
259
267
|
# File header
|
|
260
268
|
lines.append(f"diff --agmem {old_ref}/{file_diff.path} {new_ref}/{file_diff.path}")
|
|
261
|
-
|
|
269
|
+
|
|
262
270
|
if file_diff.diff_type == DiffType.ADDED:
|
|
263
271
|
lines.append(f"new file mode 100644")
|
|
264
272
|
lines.append(f"index 0000000..{file_diff.new_hash[:7]}")
|
|
@@ -273,29 +281,29 @@ class DiffEngine:
|
|
|
273
281
|
lines.append(f"index {file_diff.old_hash[:7]}..{file_diff.new_hash[:7]}")
|
|
274
282
|
lines.append(f"--- {old_ref}/{file_diff.path}")
|
|
275
283
|
lines.append(f"+++ {new_ref}/{file_diff.path}")
|
|
276
|
-
|
|
284
|
+
|
|
277
285
|
# Diff content
|
|
278
286
|
lines.append("@@ -1 +1 @@")
|
|
279
287
|
for diff_line in file_diff.diff_lines:
|
|
280
288
|
lines.append(diff_line)
|
|
281
|
-
|
|
289
|
+
|
|
282
290
|
lines.append("") # Empty line between files
|
|
283
|
-
|
|
291
|
+
|
|
284
292
|
# Summary
|
|
285
293
|
lines.append(f"# {tree_diff.added_count} file(s) added")
|
|
286
294
|
lines.append(f"# {tree_diff.deleted_count} file(s) deleted")
|
|
287
295
|
lines.append(f"# {tree_diff.modified_count} file(s) modified")
|
|
288
|
-
|
|
289
|
-
return
|
|
290
|
-
|
|
296
|
+
|
|
297
|
+
return "\n".join(lines)
|
|
298
|
+
|
|
291
299
|
def diff_working_dir(self, commit_hash: str, working_files: Dict[str, bytes]) -> TreeDiff:
|
|
292
300
|
"""
|
|
293
301
|
Compute diff between a commit and working directory.
|
|
294
|
-
|
|
302
|
+
|
|
295
303
|
Args:
|
|
296
304
|
commit_hash: Commit to compare against
|
|
297
305
|
working_files: Dict mapping paths to file contents
|
|
298
|
-
|
|
306
|
+
|
|
299
307
|
Returns:
|
|
300
308
|
TreeDiff with differences
|
|
301
309
|
"""
|
|
@@ -303,78 +311,85 @@ class DiffEngine:
|
|
|
303
311
|
commit = Commit.load(self.object_store, commit_hash)
|
|
304
312
|
if not commit:
|
|
305
313
|
return TreeDiff(files=[], added_count=0, deleted_count=0, modified_count=0)
|
|
306
|
-
|
|
314
|
+
|
|
307
315
|
commit_files = self.get_tree_files(commit.tree)
|
|
308
|
-
|
|
316
|
+
|
|
309
317
|
file_diffs = []
|
|
310
318
|
added = 0
|
|
311
319
|
deleted = 0
|
|
312
320
|
modified = 0
|
|
313
|
-
|
|
321
|
+
|
|
314
322
|
all_paths = set(commit_files.keys()) | set(working_files.keys())
|
|
315
|
-
|
|
323
|
+
|
|
316
324
|
for path in sorted(all_paths):
|
|
317
325
|
commit_hash_id = commit_files.get(path)
|
|
318
326
|
working_content = working_files.get(path)
|
|
319
|
-
|
|
327
|
+
|
|
320
328
|
# Compute working file hash
|
|
321
329
|
working_hash = None
|
|
322
330
|
if working_content is not None:
|
|
323
331
|
blob = Blob(content=working_content)
|
|
324
332
|
working_hash = blob.store(self.object_store)
|
|
325
|
-
|
|
333
|
+
|
|
326
334
|
if not commit_hash_id and working_hash:
|
|
327
335
|
# Added
|
|
328
|
-
new_content =
|
|
336
|
+
new_content = (
|
|
337
|
+
working_content.decode("utf-8", errors="replace") if working_content else None
|
|
338
|
+
)
|
|
329
339
|
diff_lines = self.compute_line_diff(None, new_content)
|
|
330
|
-
|
|
331
|
-
file_diffs.append(
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
+
|
|
341
|
+
file_diffs.append(
|
|
342
|
+
FileDiff(
|
|
343
|
+
path=path,
|
|
344
|
+
diff_type=DiffType.ADDED,
|
|
345
|
+
old_hash=None,
|
|
346
|
+
new_hash=working_hash,
|
|
347
|
+
old_content=None,
|
|
348
|
+
new_content=new_content,
|
|
349
|
+
diff_lines=diff_lines,
|
|
350
|
+
)
|
|
351
|
+
)
|
|
340
352
|
added += 1
|
|
341
|
-
|
|
353
|
+
|
|
342
354
|
elif commit_hash_id and not working_hash:
|
|
343
355
|
# Deleted
|
|
344
356
|
old_content = self.get_blob_content(commit_hash_id)
|
|
345
357
|
diff_lines = self.compute_line_diff(old_content, None)
|
|
346
|
-
|
|
347
|
-
file_diffs.append(
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
358
|
+
|
|
359
|
+
file_diffs.append(
|
|
360
|
+
FileDiff(
|
|
361
|
+
path=path,
|
|
362
|
+
diff_type=DiffType.DELETED,
|
|
363
|
+
old_hash=commit_hash_id,
|
|
364
|
+
new_hash=None,
|
|
365
|
+
old_content=old_content,
|
|
366
|
+
new_content=None,
|
|
367
|
+
diff_lines=diff_lines,
|
|
368
|
+
)
|
|
369
|
+
)
|
|
356
370
|
deleted += 1
|
|
357
|
-
|
|
371
|
+
|
|
358
372
|
elif commit_hash_id != working_hash:
|
|
359
373
|
# Modified
|
|
360
374
|
old_content = self.get_blob_content(commit_hash_id)
|
|
361
|
-
new_content =
|
|
375
|
+
new_content = (
|
|
376
|
+
working_content.decode("utf-8", errors="replace") if working_content else None
|
|
377
|
+
)
|
|
362
378
|
diff_lines = self.compute_line_diff(old_content, new_content)
|
|
363
|
-
|
|
364
|
-
file_diffs.append(
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
379
|
+
|
|
380
|
+
file_diffs.append(
|
|
381
|
+
FileDiff(
|
|
382
|
+
path=path,
|
|
383
|
+
diff_type=DiffType.MODIFIED,
|
|
384
|
+
old_hash=commit_hash_id,
|
|
385
|
+
new_hash=working_hash,
|
|
386
|
+
old_content=old_content,
|
|
387
|
+
new_content=new_content,
|
|
388
|
+
diff_lines=diff_lines,
|
|
389
|
+
)
|
|
390
|
+
)
|
|
373
391
|
modified += 1
|
|
374
|
-
|
|
392
|
+
|
|
375
393
|
return TreeDiff(
|
|
376
|
-
files=file_diffs,
|
|
377
|
-
added_count=added,
|
|
378
|
-
deleted_count=deleted,
|
|
379
|
-
modified_count=modified
|
|
394
|
+
files=file_diffs, added_count=added, deleted_count=deleted, modified_count=modified
|
|
380
395
|
)
|