Addon Manager: Allow .py filenames
Also improve macro removal.
This commit is contained in:
committed by
Chris Hennes
parent
0ef7f3d0d8
commit
bcb60d7d7e
@@ -24,7 +24,7 @@
|
||||
""" Contains the classes to manage Addon installation: intended as a stable API, safe for external
|
||||
code to call and to rely upon existing. See classes AddonInstaller and MacroInstaller for details.
|
||||
"""
|
||||
|
||||
import json
|
||||
from datetime import datetime, timezone
|
||||
from enum import IntEnum, auto
|
||||
import os
|
||||
@@ -503,16 +503,34 @@ class MacroInstaller(QtCore.QObject):
|
||||
self.finished.emit()
|
||||
return False
|
||||
|
||||
# If it succeeded, move all of the files to the macro install location
|
||||
# If it succeeded, move all the files to the macro install location,
|
||||
# keeping a list of all the files we installed, so they can be removed later
|
||||
# if this macro is uninstalled.
|
||||
manifest = []
|
||||
for item in os.listdir(temp_dir):
|
||||
src = os.path.join(temp_dir, item)
|
||||
dst = os.path.join(self.installation_path, item)
|
||||
shutil.move(src, dst)
|
||||
manifest.append(dst)
|
||||
self._write_installation_manifest(manifest)
|
||||
self.success.emit(self.addon_to_install)
|
||||
self.addon_to_install.set_status(Addon.Status.NO_UPDATE_AVAILABLE)
|
||||
self.finished.emit()
|
||||
return True
|
||||
|
||||
def _write_installation_manifest(self, manifest):
|
||||
manifest_file = os.path.join(
|
||||
self.installation_path, self.addon_to_install.macro.filename + ".manifest"
|
||||
)
|
||||
try:
|
||||
with open(manifest_file, "w", encoding="utf-8") as f:
|
||||
f.write(json.dumps(manifest, indent=" "))
|
||||
except OSError as e:
|
||||
FreeCAD.Console.PrintWarning(
|
||||
translate("AddonsInstaller", "Failed to create installation manifest " "file:\n")
|
||||
)
|
||||
FreeCAD.Console.PrintWarning(manifest_file)
|
||||
|
||||
@classmethod
|
||||
def _validate_object(cls, addon: object):
|
||||
"""Make sure this object provides an attribute called "macro" with a method called
|
||||
|
||||
@@ -69,6 +69,7 @@ class Macro:
|
||||
self.version = ""
|
||||
self.date = ""
|
||||
self.src_filename = ""
|
||||
self.filename_from_url = ""
|
||||
self.author = ""
|
||||
self.icon = ""
|
||||
self.icon_source = None
|
||||
@@ -104,6 +105,8 @@ class Macro:
|
||||
"""The filename of this macro"""
|
||||
if self.on_git:
|
||||
return os.path.basename(self.src_filename)
|
||||
elif self.filename_from_url:
|
||||
return self.filename_from_url
|
||||
return (self.name + ".FCMacro").replace(" ", "_")
|
||||
|
||||
def is_installed(self):
|
||||
@@ -211,8 +214,14 @@ class Macro:
|
||||
)
|
||||
return None
|
||||
code = u2.decode("utf8")
|
||||
self._set_filename_from_url(self.raw_code_url)
|
||||
return code
|
||||
|
||||
def _set_filename_from_url(self, url: str):
|
||||
lhs, slash, rhs = url.rpartition("/")
|
||||
if rhs.endswith(".py") or rhs.lower().endswith(".fcmacro"):
|
||||
self.filename_from_url = rhs
|
||||
|
||||
@staticmethod
|
||||
def _read_code_from_wiki(p: str) -> Optional[str]:
|
||||
code = re.findall(r"<pre>(.*?)</pre>", p.replace("\n", "--endl--"))
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
""" Contains the classes to manage Addon removal: intended as a stable API, safe for
|
||||
external code to call and to rely upon existing. See classes AddonUninstaller and
|
||||
MacroUninstaller for details."""
|
||||
|
||||
import json
|
||||
import os
|
||||
from typing import List
|
||||
|
||||
@@ -228,7 +228,10 @@ class MacroUninstaller(QObject):
|
||||
directories = set()
|
||||
for f in self._get_files_to_remove():
|
||||
normed = os.path.normpath(f)
|
||||
full_path = os.path.join(self.installation_location, normed)
|
||||
if os.path.isabs(normed):
|
||||
full_path = normed
|
||||
else:
|
||||
full_path = os.path.join(self.installation_location, normed)
|
||||
if "/" in f:
|
||||
directories.add(os.path.dirname(full_path))
|
||||
try:
|
||||
@@ -246,6 +249,10 @@ class MacroUninstaller(QObject):
|
||||
+ str(e)
|
||||
)
|
||||
success = False
|
||||
except Exception:
|
||||
# Generic catch-all, just in case (because failure to catch an exception
|
||||
# here can break things pretty badly)
|
||||
success = False
|
||||
|
||||
self._cleanup_directories(directories)
|
||||
|
||||
@@ -256,8 +263,17 @@ class MacroUninstaller(QObject):
|
||||
self.addon_to_remove.set_status(Addon.Status.NOT_INSTALLED)
|
||||
self.finished.emit()
|
||||
|
||||
def _get_files_to_remove(self) -> List[os.PathLike]:
|
||||
def _get_files_to_remove(self) -> List[str]:
|
||||
"""Get the list of files that should be removed"""
|
||||
manifest_file = os.path.join(
|
||||
self.installation_location, self.addon_to_remove.macro.filename + ".manifest"
|
||||
)
|
||||
if os.path.exists(manifest_file):
|
||||
with open(manifest_file, "r", encoding="utf-8") as f:
|
||||
manifest_data = f.read()
|
||||
manifest = json.loads(manifest_data)
|
||||
manifest.append(manifest_file) # Remove the manifest itself as well
|
||||
return manifest
|
||||
files_to_remove = [self.addon_to_remove.macro.filename]
|
||||
if self.addon_to_remove.macro.icon:
|
||||
files_to_remove.append(self.addon_to_remove.macro.icon)
|
||||
|
||||
Reference in New Issue
Block a user