|
2 | 2 | import time
|
3 | 3 | import json
|
4 | 4 | import redis
|
| 5 | +import logging |
5 | 6 | import threading
|
6 | 7 | import subprocess
|
7 | 8 | from git import Repo
|
8 | 9 | from ..graph import Graph
|
9 | 10 | from .git_graph import GitGraph
|
10 | 11 | from typing import List, Optional
|
11 | 12 |
|
| 13 | +# Configure logging |
| 14 | +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') |
| 15 | + |
12 | 16 | monitor_thread = None
|
13 | 17 | replica_process = None
|
14 | 18 | monitor_exit_event = threading.Event()
|
15 | 19 |
|
| 20 | +def GitRepoName(repo_name): |
| 21 | + return "{" + repo_name + "}_git" |
| 22 | + |
16 | 23 | # setup replication to the master
|
17 | 24 | def setup_replication():
|
18 | 25 | global replica_process
|
@@ -108,8 +115,10 @@ def build_commit_graph(path: str, ignore_list: Optional[List[str]] = []) -> GitG
|
108 | 115 | repo = Repo(path)
|
109 | 116 |
|
110 | 117 | repo_name = os.path.split(os.path.normpath(path))[-1]
|
111 |
| - g = Graph(repo_name) |
112 |
| - git_graph = GitGraph('{' + repo_name + '}' + '_git') |
| 118 | + |
| 119 | + # Clone graph into a temporary graph |
| 120 | + g = Graph(repo_name).clone(repo_name + "_tmp") |
| 121 | + git_graph = GitGraph(GitRepoName(repo_name)) |
113 | 122 |
|
114 | 123 | #setup_replication()
|
115 | 124 |
|
@@ -194,46 +203,111 @@ def build_commit_graph(path: str, ignore_list: Optional[List[str]] = []) -> GitG
|
194 | 203 | #stop_monitor_effects()
|
195 | 204 | #teardown_replica()
|
196 | 205 |
|
197 |
| - return git_graph |
| 206 | + # Delete temporaty graph |
| 207 | + g.delete() |
198 | 208 |
|
199 |
| -def switch_commit(repo: str, to: str): |
200 |
| - """switch graph state from its current commit to given commit""" |
| 209 | + return git_graph |
201 | 210 |
|
| 211 | +def switch_commit(repo: str, to: str) -> dict[str, dict[str, list]]: |
| 212 | + """ |
| 213 | + Switches the state of a graph repository from its current commit to the given commit. |
| 214 | +
|
| 215 | + This function handles switching between two git commits for a graph-based repository. |
| 216 | + It identifies the changes (additions, deletions, modifications) in nodes and edges between |
| 217 | + the current commit and the target commit and then applies the necessary transitions. |
| 218 | +
|
| 219 | + Args: |
| 220 | + repo (str): The name of the graph repository to switch commits. |
| 221 | + to (str): The target commit hash to switch the graph to. |
| 222 | +
|
| 223 | + Returns: |
| 224 | + dict: A dictionary containing the changes made during the commit switch, organized by: |
| 225 | + - 'deletions': { |
| 226 | + 'nodes': List of node IDs deleted, |
| 227 | + 'edges': List of edge IDs deleted |
| 228 | + }, |
| 229 | + - 'additions': { |
| 230 | + 'nodes': List of new Node objects added, |
| 231 | + 'edges': List of new Edge objects added |
| 232 | + }, |
| 233 | + - 'modifications': { |
| 234 | + 'nodes': List of modified Node objects, |
| 235 | + 'edges': List of modified Edge objects |
| 236 | + } |
| 237 | + """ |
| 238 | + |
| 239 | + # Validate input arguments |
| 240 | + if not repo or not isinstance(repo, str): |
| 241 | + raise ValueError("Invalid repository name") |
| 242 | + |
| 243 | + if not to or not isinstance(to, str): |
| 244 | + raise ValueError("Invalid desired commit value") |
| 245 | + |
| 246 | + # Initialize return value to an empty change set |
| 247 | + change_set = { |
| 248 | + 'deletions': { |
| 249 | + 'nodes': [], |
| 250 | + 'edges': [] |
| 251 | + }, |
| 252 | + 'additions': { |
| 253 | + 'nodes': [], |
| 254 | + 'edges': [], |
| 255 | + }, |
| 256 | + 'modifications': { |
| 257 | + 'nodes': [], |
| 258 | + 'edges': [] |
| 259 | + } |
| 260 | + } |
| 261 | + |
| 262 | + # Initialize the graph and GitGraph objects |
202 | 263 | g = Graph(repo)
|
203 |
| - git_graph = GitGraph('{' + repo + '}' + 'git') |
| 264 | + git_graph = GitGraph(GitRepoName(repo)) |
204 | 265 |
|
205 |
| - # Get the graph's current commit |
| 266 | + # Get the current commit hash of the graph |
206 | 267 | current_hash = g.get_graph_commit()
|
| 268 | + logging.info(f"Current graph commit: {current_hash}") |
207 | 269 |
|
208 |
| - # Find path from current commit to desired commit |
| 270 | + if current_hash == to: |
| 271 | + # No change remain at the current commit |
| 272 | + return change_set |
| 273 | + |
| 274 | + # Find the path between the current commit and the desired commit |
209 | 275 | commits = git_graph.get_commits([current_hash, to])
|
210 | 276 |
|
| 277 | + # Ensure both current and target commits are present |
211 | 278 | if len(commits) != 2:
|
212 |
| - print("missing commits") |
213 |
| - return |
| 279 | + logging.error("Missing commits. Unable to proceed.") |
| 280 | + raise ValueError("Commits not found") |
214 | 281 |
|
215 |
| - # determine relation between commits |
216 |
| - current_commit = commits[0] if commits[0]['hash'] == current_hash else commits[1] |
217 |
| - new_commit = commits[0] if commits[0]['hash'] == to else commits[1] |
| 282 | + # Identify the current and new commits based on their hashes |
| 283 | + current_commit, new_commit = (commits if commits[0]['hash'] == current_hash else reversed(commits)) |
218 | 284 |
|
| 285 | + # Determine the direction of the switch (forward or backward in commit history) |
219 | 286 | if current_commit['date'] > new_commit['date']:
|
220 |
| - print("moving backwared") |
221 |
| - queries, params = git_graph.get_parent_transition(current_commit['hash'], new_commit['hash']) |
| 287 | + logging.info(f"Moving backward from {current_commit['hash']} to {new_commit['hash']}") |
| 288 | + # Get the transitions (queries and parameters) for moving backward |
| 289 | + queries, params = git_graph.get_parent_transitions(current_commit['hash'], new_commit['hash']) |
222 | 290 | else:
|
223 |
| - print("moving forwards") |
224 |
| - queries, params = git_graph.get_child_transition(current_commit['hash'], new_commit['hash']) |
225 |
| - |
226 |
| - # Apply transitions |
227 |
| - for i in range(0, len(queries)): |
228 |
| - q = queries[i] |
229 |
| - p = json.loads(params[i]) |
230 |
| - print(f"query: {q}") |
231 |
| - print(f"params: {p}") |
232 |
| - |
233 |
| - g.rerun_query(q, p) |
234 |
| - |
235 |
| - # update graph's commit |
| 291 | + logging.info(f"Moving forward from {current_commit['hash']} to {new_commit['hash']}") |
| 292 | + # Get the transitions (queries and parameters) for moving forward |
| 293 | + queries, params = git_graph.get_child_transitions(current_commit['hash'], new_commit['hash']) |
| 294 | + |
| 295 | + # Apply each transition query with its respective parameters |
| 296 | + for q, p in zip(queries, params): |
| 297 | + p = json.loads(p) |
| 298 | + logging.debug(f"Executing query: {q} with params: {p}") |
| 299 | + |
| 300 | + # Rerun the query with parameters on the graph |
| 301 | + res = g.rerun_query(q, p) |
| 302 | + if "DELETE" in q: |
| 303 | + deleted_nodes = res.result_set[0][0] |
| 304 | + change_set['deletions']['nodes'] += deleted_nodes |
| 305 | + |
| 306 | + # Update the graph's commit to the new target commit |
236 | 307 | g.set_graph_commit(to)
|
| 308 | + logging.info(f"Graph commit updated to {to}") |
| 309 | + |
| 310 | + return change_set |
237 | 311 |
|
238 | 312 | if __name__ == "__main__":
|
239 | 313 | build_commit_graph("/Users/roilipman/Dev/FalkorDB")
|
|
0 commit comments