From 95bf6837719533b5621faf57753bf99778995e5f Mon Sep 17 00:00:00 2001 From: Bernhard Reiter Date: Fri, 11 Jun 2021 16:50:00 +0200 Subject: [PATCH] Add contrib script to resolve conflicts Asks the user when two iCalender objects conflict during a sync, which one to take. --- .../resolve_interactively.py | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100755 contrib/conflict_resolution/resolve_interactively.py diff --git a/contrib/conflict_resolution/resolve_interactively.py b/contrib/conflict_resolution/resolve_interactively.py new file mode 100755 index 0000000..09e06ff --- /dev/null +++ b/contrib/conflict_resolution/resolve_interactively.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +"""Ask user to resolve a vdirsyncer sync conflict interactively. + +Needs a way to ask the user. +The use of https://apps.kde.org/kdialog/ for GNU/Linix is hardcoded. + +Depends on python>3.5 and KDialog. + +Usage: + Ensure the file executable and use it in the vdirsyncer.conf file, e.g. + + conflict_resolution = ["command", "/home/bern/vdirsyncer/resolve_interactively.py"] + +This file is Free Software under the following license: +SPDX-License-Identifier: Apache-2.0 +SPDX-FileCopyrightText: 2021 Intevation GmbH +Author: +""" +from pathlib import Path +import re +import subprocess +import sys + +KDIALOG = "/usr/bin/kdialog" + +SUMMARY_PATTERN = re.compile("^(SUMMARY:.*)$", re.MULTILINE) + +def get_summary(icalendar_text:str): + """Get the first SUMMARY: line from an iCalendar text. + + Do not care about the line being continued. + """ + match = re.search(SUMMARY_PATTERN, icalendar_text) + return match[1] + + +def main(ical1_filename, ical2_filename): + ical1 = ical1_filename.read_text() + ical2 = ical2_filename.read_text() + + additional_args = ["--yes-label", "take first"] # return code == 0 + additional_args += ["--no-label", "take second"] # return code == 1 + additional_args += ["--cancel-label", "do not resolve"] # return code == 2 + + r = subprocess.run(args = [ + KDIALOG, + "--warningyesnocancel", + "There was a sync conflict, do you prefer the first entry: \n" + + get_summary(ical1) + "...\n(full contents: " + str(ical1_filename) + + " )\n\nor the second entry: \n" + + get_summary(ical2) + "...\n(full contents: " + str(ical2_filename) + + " )?" + ] + additional_args) + + if r.returncode == 2: + # cancel was pressed + return # shall lead to items not changed, because not copied + + if r.returncode == 0: + # we want to take the first item, so overwrite the second + ical2_filename.write_text(ical1) + else: # r.returncode == 1, we want the second item, so overwrite the first + ical1_filename.write_text(ical2) + +if len(sys.argv) != 3: + sys.stdout.write(__doc__) +else: + main(Path(sys.argv[1]), Path(sys.argv[2]))