Skip to content

Commit 3dd6637

Browse files
authored
Merge pull request #282 from MerginMaps/pull-initial
Initial version of v2 pull integration + project info v2
2 parents f326179 + 37692a8 commit 3dd6637

File tree

9 files changed

+1325
-325
lines changed

9 files changed

+1325
-325
lines changed

mergin/client.py

Lines changed: 105 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@
2020
from enum import Enum
2121
from typing import Optional, Type, Union
2222

23+
from .models import (
24+
ProjectDelta,
25+
ProjectDeltaItemDiff,
26+
ProjectDeltaChange,
27+
ProjectInfo,
28+
ProjectFile,
29+
ProjectWorkspace,
30+
)
31+
2332
from .common import (
2433
SYNC_ATTEMPT_WAIT,
2534
SYNC_ATTEMPTS,
@@ -732,6 +741,89 @@ def project_info(self, project_path_or_id, since=None, version=None):
732741
resp = self.get("/v1/project/{}".format(project_path_or_id), params)
733742
return json.load(resp)
734743

744+
def project_info_v2(self, project_id: str, files_at_version=None) -> ProjectInfo:
745+
"""
746+
Fetch info about project.
747+
748+
:param project_id: Project's id
749+
:type project_id: String
750+
:param files_at_version: Version to track files at given version
751+
:type files_at_version: String
752+
"""
753+
self.check_v2_project_info_support()
754+
755+
params = {}
756+
if files_at_version:
757+
params = {"files_at_version": files_at_version}
758+
resp = self.get(f"/v2/projects/{project_id}", params)
759+
resp_json = json.load(resp)
760+
project_workspace = resp_json.get("workspace")
761+
return ProjectInfo(
762+
id=resp_json.get("id"),
763+
name=resp_json.get("name"),
764+
created_at=resp_json.get("created_at"),
765+
updated_at=resp_json.get("updated_at"),
766+
version=resp_json.get("version"),
767+
public=resp_json.get("public"),
768+
role=resp_json.get("role"),
769+
size=resp_json.get("size"),
770+
workspace=ProjectWorkspace(
771+
id=project_workspace.get("id"),
772+
name=project_workspace.get("name"),
773+
),
774+
files=[
775+
ProjectFile(
776+
checksum=f.get("checksum"),
777+
mtime=f.get("mtime"),
778+
path=f.get("path"),
779+
size=f.get("size"),
780+
)
781+
for f in resp_json.get("files", [])
782+
],
783+
)
784+
785+
def get_project_delta(self, project_id: str, since: str, to: typing.Optional[str] = None) -> ProjectDelta:
786+
"""
787+
Fetch info about project delta since given version.
788+
789+
:param project_id: Project's id
790+
:type project_id: String
791+
:param since: Version to track history of files from
792+
:type since: String (e.g. v1)
793+
:param to: Optional version to track history of files to, if not given latest version is used
794+
:type to: String (e.g. v2)
795+
"""
796+
# If it is not enabled on the server, raise error
797+
if not self.server_features().get("v2_pull_enabled", False):
798+
raise ClientError("Project delta is not supported by the server")
799+
800+
params = {"since": since}
801+
if to:
802+
params["to"] = to
803+
resp = self.get(f"/v2/projects/{project_id}/delta", params)
804+
resp_parsed = json.load(resp)
805+
return ProjectDelta(
806+
to_version=resp_parsed.get("to_version"),
807+
changes=[
808+
ProjectDeltaChange(
809+
path=item["path"],
810+
size=item.get("size"),
811+
checksum=item.get("checksum"),
812+
version=item.get("version"),
813+
type=item.get("change"),
814+
diffs=(
815+
[
816+
ProjectDeltaItemDiff(
817+
id=diff.get("id"),
818+
)
819+
for diff in item.get("diffs", [])
820+
]
821+
),
822+
)
823+
for item in resp_parsed.get("items", [])
824+
],
825+
)
826+
735827
def paginated_project_versions(self, project_path, page, per_page=100, descending=False):
736828
"""
737829
Get records of project's versions (history) using calculated pagination.
@@ -822,11 +914,11 @@ def download_project(self, project_path, directory, version=None):
822914
:param project_path: Project's full name (<namespace>/<name>)
823915
:type project_path: String
824916
825-
:param version: Project version to download, e.g. v42
826-
:type version: String
827-
828917
:param directory: Target directory
829918
:type directory: String
919+
920+
:param version: Project version to download, e.g. v42
921+
:type version: String
830922
"""
831923
job = download_project_async(self, project_path, directory, version)
832924
download_project_wait(job)
@@ -1070,7 +1162,7 @@ def project_status(self, directory):
10701162
mp = MerginProject(directory)
10711163
server_info = self.project_info(mp.project_full_name(), since=mp.version())
10721164

1073-
pull_changes = mp.get_pull_changes(server_info["files"])
1165+
pull_changes = mp.get_pull_changes(server_info.get("files", []), server_info.get("version"))
10741166

10751167
push_changes = mp.get_push_changes()
10761168
push_changes_summary = mp.get_list_of_push_changes(push_changes)
@@ -1341,13 +1433,21 @@ def check_collaborators_members_support(self):
13411433
if not is_version_acceptable(self.server_version(), f"{min_version}"):
13421434
raise NotImplementedError(f"This needs server at version {min_version} or later")
13431435

1436+
def check_v2_project_info_support(self):
1437+
"""
1438+
Check if the server is compatible with v2 endpoint for project info
1439+
"""
1440+
min_version = "2025.8.2"
1441+
if not is_version_acceptable(self.server_version(), f"{min_version}"):
1442+
raise NotImplementedError(f"This needs server at version {min_version} or later")
1443+
13441444
def create_user(
13451445
self,
13461446
email: str,
13471447
password: str,
13481448
workspace_id: int,
13491449
workspace_role: Union[str, WorkspaceRole],
1350-
username: str = None,
1450+
username: Optional[str] = None,
13511451
notify_user: bool = False,
13521452
) -> dict:
13531453
"""

0 commit comments

Comments
 (0)