diff --git a/cli.py b/cli.py index 048f0561..6a5c7680 100755 --- a/cli.py +++ b/cli.py @@ -22,6 +22,7 @@ def get_changes_count(diff): attrs = ["added", "removed", "updated", "renamed"] return sum([len(diff[attr]) for attr in attrs]) + def pretty_diff(diff): added = diff["added"] removed = diff["removed"] @@ -46,6 +47,13 @@ def pretty_diff(diff): click.secho("\n".join("M " + f["path"] for f in updated), fg="yellow") +def pretty_summary(summary): + for k, v in summary.items(): + click.secho("Details " + k) + click.secho("".join("layer name - " + d["table"] + ": inserted: " + str(d["insert"]) + ", modified: " + + str(d["update"]) + ", deleted: " + str(d["delete"]) + "\n" for d in v['geodiff_summary'] if d["table"] != "gpkg_contents")) + + def _init_client(): url = os.environ.get('MERGIN_URL') auth_token = os.environ.get('MERGIN_AUTH') @@ -122,11 +130,13 @@ def status(): return c = _init_client() - pull_changes, push_changes = c.project_status(os.getcwd()) + pull_changes, push_changes, push_changes_summary = c.project_status(os.getcwd()) click.secho("### Server changes:", fg="magenta") pretty_diff(pull_changes) click.secho("### Local changes:", fg="magenta") pretty_diff(push_changes) + click.secho("### Local changes summary ###") + pretty_summary(push_changes_summary) @cli.command() diff --git a/mergin/client.py b/mergin/client.py index 6dc816cc..01c2931a 100644 --- a/mergin/client.py +++ b/mergin/client.py @@ -321,12 +321,28 @@ def get_push_changes(self): } else: not_updated.append(file) - except (pygeodiff.GeoDiffLibError, pygeodiff.GeoDiffLibConflictError): + except (pygeodiff.GeoDiffLibError, pygeodiff.GeoDiffLibConflictError) as e: pass # we do force update changes['updated'] = [f for f in changes['updated'] if f not in not_updated] return changes + def get_list_of_push_changes(self, push_changes): + changes = {} + for idx, file in enumerate(push_changes["updated"]): + if "diff" in file: + changeset_path = file["diff"]["path"] + changeset = self.fpath_meta(changeset_path) + result_file = self.fpath("change_list" + str(idx), self.meta_dir) + try: + self.geodiff.list_changes_summary(changeset, result_file) + change = open(result_file, "r").read() + changes[file["path"]] = json.loads(change) + os.remove(result_file) + except (pygeodiff.GeoDiffLibError, pygeodiff.GeoDiffLibConflictError): + pass + return changes + def apply_pull_changes(self, changes, temp_dir): """ Apply changes pulled from server. @@ -1085,5 +1101,8 @@ def project_status(self, directory): local_version = mp.metadata["version"] server_info = self.project_info(project_path, since=local_version) pull_changes = mp.get_pull_changes(server_info["files"]) + push_changes = mp.get_push_changes() - return pull_changes, push_changes + push_changes_summary = mp.get_list_of_push_changes(push_changes) + + return pull_changes, push_changes, push_changes_summary diff --git a/mergin/test/test_client.py b/mergin/test/test_client.py index 46a3de3f..eab26ce9 100644 --- a/mergin/test/test_client.py +++ b/mergin/test/test_client.py @@ -12,6 +12,10 @@ TEST_DATA_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'test_data') +def toggle_geodiff(enabled): + os.environ['GEODIFF_ENABLED'] = str(enabled) + + @pytest.fixture(scope='function') def mc(): assert SERVER_URL and SERVER_URL.rstrip('/') != 'https://public.cloudmergin.com' and API_USER and USER_PWD @@ -130,7 +134,7 @@ def test_push_pull_changes(mc, parallel): f.write('Modified') # check changes before applied - pull_changes, push_changes = mc.project_status(project_dir) + pull_changes, push_changes, _ = mc.project_status(project_dir) assert not sum(len(v) for v in pull_changes.values()) assert next((f for f in push_changes['added'] if f['path'] == f_added), None) assert next((f for f in push_changes['removed'] if f['path'] == f_removed), None) @@ -163,7 +167,7 @@ def test_push_pull_changes(mc, parallel): mc.push_project(project_dir_2) # check changes in project_dir_2 before applied - pull_changes, push_changes = mc.project_status(project_dir_2) + pull_changes, push_changes, _ = mc.project_status(project_dir_2) assert next((f for f in pull_changes['added'] if f['path'] == f_added), None) assert next((f for f in pull_changes['removed'] if f['path'] == f_removed), None) assert next((f for f in pull_changes['updated'] if f['path'] == f_updated), None) @@ -211,8 +215,6 @@ def test_ignore_files(mc): @pytest.mark.parametrize("diffs_limit, push_geodiff_enabled, pull_geodiff_enabled", diff_test_scenarios) def test_sync_diff(mc, diffs_limit, push_geodiff_enabled, pull_geodiff_enabled): - def toggle_geodiff(enabled): - os.environ['GEODIFF_ENABLED'] = str(enabled) test_project = f'test_sync_diff_{diffs_limit}_{int(push_geodiff_enabled)}_{int(pull_geodiff_enabled)}' project = API_USER + '/' + test_project @@ -303,3 +305,26 @@ def toggle_geodiff(enabled): assert not mp3.geodiff.has_changes(mp.fpath_meta('diff')) else: assert os.path.exists(mp.fpath('base.gpkg_conflict_copy')) + + +def test_list_of_push_changes(mc): + PUSH_CHANGES_SUMMARY = "{'base.gpkg': {'geodiff_summary': [{'table': 'gpkg_contents', 'insert': 0, 'update': 1, 'delete': 0}, {'table': 'simple', 'insert': 1, 'update': 0, 'delete': 0}]}}" + + test_project = 'test_list_of_push_changes' + project = API_USER + '/' + test_project + project_dir = os.path.join(TMP_DIR, test_project) # primary project dir for updates + + cleanup(mc, project, [project_dir]) + shutil.copytree(TEST_DATA_DIR, project_dir) + toggle_geodiff(True) + mc.create_project(test_project, project_dir) + + f_updated = 'base.gpkg' + mp = MerginProject(project_dir) + + shutil.copy(mp.fpath('inserted_1_A.gpkg'), mp.fpath(f_updated)) + + pull_changes, push_changes, push_changes_summary = mc.project_status(project_dir) + assert str(push_changes_summary) == PUSH_CHANGES_SUMMARY + +