mirror of
https://github.com/ankitects/anki.git
synced 2025-11-09 14:17:13 -05:00
Implement add-on conflict handling via manifests "conflicts" value
Only enabled for locally installed packages for now
This commit is contained in:
parent
8fceccf4b7
commit
512be4fc2c
1 changed files with 60 additions and 4 deletions
|
|
@ -5,6 +5,7 @@ import io
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
import zipfile
|
import zipfile
|
||||||
|
from collections import defaultdict
|
||||||
import markdown
|
import markdown
|
||||||
from send2trash import send2trash
|
from send2trash import send2trash
|
||||||
|
|
||||||
|
|
@ -26,7 +27,8 @@ class AddonManager:
|
||||||
_manifest_schema = {
|
_manifest_schema = {
|
||||||
"package": {"type": str, "req": True, "meta": False},
|
"package": {"type": str, "req": True, "meta": False},
|
||||||
"name": {"type": str, "req": True, "meta": True},
|
"name": {"type": str, "req": True, "meta": True},
|
||||||
"mod": {"type": int, "req": False, "meta": True}
|
"mod": {"type": int, "req": False, "meta": True},
|
||||||
|
"conflicts": {"type": list, "req": False, "meta": True}
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, mw):
|
def __init__(self, mw):
|
||||||
|
|
@ -97,14 +99,61 @@ When loading '%(name)s':
|
||||||
with open(path, "w", encoding="utf8") as f:
|
with open(path, "w", encoding="utf8") as f:
|
||||||
json.dump(meta, f)
|
json.dump(meta, f)
|
||||||
|
|
||||||
def toggleEnabled(self, dir):
|
def isEnabled(self, dir):
|
||||||
meta = self.addonMeta(dir)
|
meta = self.addonMeta(dir)
|
||||||
meta['disabled'] = not meta.get("disabled")
|
return not meta.get('disabled')
|
||||||
|
|
||||||
|
def toggleEnabled(self, dir, enable=None):
|
||||||
|
meta = self.addonMeta(dir)
|
||||||
|
enabled = enable if enable is not None else meta.get("disabled")
|
||||||
|
if enabled is True and not self._checkConflicts(dir):
|
||||||
|
return False
|
||||||
|
meta['disabled'] = not enabled
|
||||||
self.writeAddonMeta(dir, meta)
|
self.writeAddonMeta(dir, meta)
|
||||||
|
|
||||||
def addonName(self, dir):
|
def addonName(self, dir):
|
||||||
return self.addonMeta(dir).get("name", dir)
|
return self.addonMeta(dir).get("name", dir)
|
||||||
|
|
||||||
|
# Conflict resolution
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
def addonConflicts(self, dir):
|
||||||
|
return self.addonMeta(dir).get("conflicts", [])
|
||||||
|
|
||||||
|
def allAddonConflicts(self):
|
||||||
|
all_conflicts = defaultdict(list)
|
||||||
|
for dir in self.allAddons():
|
||||||
|
if not self.isEnabled(dir):
|
||||||
|
continue
|
||||||
|
conflicts = self.addonConflicts(dir)
|
||||||
|
for other_dir in conflicts:
|
||||||
|
all_conflicts[other_dir].append(dir)
|
||||||
|
return all_conflicts
|
||||||
|
|
||||||
|
def _checkConflicts(self, dir, name=None, conflicts=None):
|
||||||
|
name = name or self.addonName(dir)
|
||||||
|
conflicts = conflicts or self.addonConflicts(dir)
|
||||||
|
|
||||||
|
installed = self.allAddons()
|
||||||
|
found = [d for d in conflicts if d in installed and self.isEnabled(d)]
|
||||||
|
found.extend(self.allAddonConflicts().get(dir, []))
|
||||||
|
if not found:
|
||||||
|
return True
|
||||||
|
|
||||||
|
addons = "\n".join(self.addonName(f) for f in found)
|
||||||
|
ret = askUser(_("""\
|
||||||
|
The following add-on(s) are incompatible with %(name)s \
|
||||||
|
and will have to be disabled to proceed:\n\n%(found)s\n\n\
|
||||||
|
Are you sure you want to continue?"""
|
||||||
|
% dict(name=name, found=addons)))
|
||||||
|
if not ret:
|
||||||
|
return False
|
||||||
|
|
||||||
|
for package in found:
|
||||||
|
self.toggleEnabled(package, enable=False)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
# Installing and deleting add-ons
|
# Installing and deleting add-ons
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
|
|
@ -138,6 +187,9 @@ When loading '%(name)s':
|
||||||
if not manifest:
|
if not manifest:
|
||||||
return False, "manifest"
|
return False, "manifest"
|
||||||
package = manifest["package"]
|
package = manifest["package"]
|
||||||
|
conflicts = manifest.get("conflicts", [])
|
||||||
|
if not self._checkConflicts(package, manifest["name"], conflicts):
|
||||||
|
return False, "conflicts"
|
||||||
meta = self.addonMeta(package)
|
meta = self.addonMeta(package)
|
||||||
self._install(package, zfile)
|
self._install(package, zfile)
|
||||||
|
|
||||||
|
|
@ -185,7 +237,9 @@ When loading '%(name)s':
|
||||||
base = os.path.basename(path)
|
base = os.path.basename(path)
|
||||||
ret = self.install(path)
|
ret = self.install(path)
|
||||||
if ret[0] is False:
|
if ret[0] is False:
|
||||||
if ret[1] == "zip":
|
if ret[1] == "conflicts":
|
||||||
|
continue
|
||||||
|
elif ret[1] == "zip":
|
||||||
msg = _("Corrupt add-on file.")
|
msg = _("Corrupt add-on file.")
|
||||||
elif ret[1] == "manifest":
|
elif ret[1] == "manifest":
|
||||||
msg = _("Invalid add-on manifest.")
|
msg = _("Invalid add-on manifest.")
|
||||||
|
|
@ -215,6 +269,8 @@ When loading '%(name)s':
|
||||||
manifest={"package": str(n), "name": name,
|
manifest={"package": str(n), "name": name,
|
||||||
"mod": intTime()})
|
"mod": intTime()})
|
||||||
if ret[0] is False:
|
if ret[0] is False:
|
||||||
|
if ret[1] == "conflicts":
|
||||||
|
continue
|
||||||
if ret[1] == "zip":
|
if ret[1] == "zip":
|
||||||
showWarning(_("The download was corrupt. Please try again."))
|
showWarning(_("The download was corrupt. Please try again."))
|
||||||
elif ret[1] == "manifest":
|
elif ret[1] == "manifest":
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue