Addon Manager: Bugfixes and cleanup of refactor
This commit is contained in:
@@ -73,6 +73,8 @@ class CommandAddonManager:
|
||||
"showmacro_worker", "macro_worker", "install_worker",
|
||||
"update_metadata_cache_worker", "update_all_worker"]
|
||||
|
||||
lock = threading.Lock()
|
||||
|
||||
def GetResources(self) -> Dict[str,str]:
|
||||
return {"Pixmap": "AddonManager",
|
||||
"MenuText": QT_TRANSLATE_NOOP("Std_AddonMgr", "&Addon manager"),
|
||||
@@ -113,6 +115,7 @@ class CommandAddonManager:
|
||||
# cleanup the leftovers from previous runs
|
||||
self.macro_repo_dir = tempfile.mkdtemp()
|
||||
self.packages_with_updates = []
|
||||
self.startup_sequence = []
|
||||
self.addon_removed = False
|
||||
self.cleanup_workers()
|
||||
|
||||
@@ -189,30 +192,25 @@ class CommandAddonManager:
|
||||
self.dialog.move(mw.frameGeometry().topLeft() + mw.rect().center() - self.dialog.rect().center())
|
||||
|
||||
# set info for the progress bar:
|
||||
self.number_of_progress_regions = 4
|
||||
self.current_progress_region = 0
|
||||
self.dialog.progressBar.setMaximum (100)
|
||||
|
||||
# populate the table
|
||||
self.populate_packages_table()
|
||||
# begin populating the table in a set of sub-threads
|
||||
self.startup()
|
||||
|
||||
# set the label text to start with
|
||||
self.show_information(translate("AddonInstaller", "Loading addon information"))
|
||||
self.show_information(translate("AddonsInstaller", "Loading addon information"))
|
||||
|
||||
# rock 'n roll!!!
|
||||
self.dialog.exec_()
|
||||
|
||||
def cleanup_workers(self) -> None:
|
||||
""" Ensure that no workers are running by explicitly asking them to stop, and terminating them if they don't """
|
||||
def cleanup_workers(self, wait=False) -> None:
|
||||
""" Ensure that no workers are running by explicitly asking them to stop and waiting for them until they do """
|
||||
for worker in self.workers:
|
||||
if hasattr(self, worker):
|
||||
thread = getattr(self, worker)
|
||||
if thread:
|
||||
if not thread.isFinished():
|
||||
thread.requestInterruption()
|
||||
thread.wait(QtCore.QDeadlineTimer(250))
|
||||
if not thread.isFinished():
|
||||
thread.terminate() # Highly undesirable, hopefully the thread obeyed the request to interrupt
|
||||
thread.wait()
|
||||
|
||||
def wait_on_other_workers(self) -> None:
|
||||
@@ -235,6 +233,7 @@ class CommandAddonManager:
|
||||
|
||||
# ensure all threads are finished before closing
|
||||
oktoclose = True
|
||||
self.startup_sequence = []
|
||||
for worker in self.workers:
|
||||
if hasattr(self, worker):
|
||||
thread = getattr(self, worker)
|
||||
@@ -248,10 +247,7 @@ class CommandAddonManager:
|
||||
if hasattr(self, worker):
|
||||
thread = getattr(self, worker)
|
||||
if thread:
|
||||
thread.wait(QtCore.QDeadlineTimer(50)) # 50ms to wrap up whatever loop iteration it was on
|
||||
if not thread.isFinished():
|
||||
thread.terminate() # Highly undesirable, hopefully the thread obeyed the request to interrupt
|
||||
thread.wait()
|
||||
thread.wait()
|
||||
|
||||
# all threads have finished
|
||||
if oktoclose:
|
||||
@@ -284,7 +280,7 @@ class CommandAddonManager:
|
||||
FreeCAD.Console.PrintWarning("Could not terminate sub-threads in Addon Manager.\n")
|
||||
self.cleanup_workers()
|
||||
|
||||
def populate_packages_table(self) -> None:
|
||||
def startup(self) -> None:
|
||||
""" Downloads the available packages listings and populates the table
|
||||
|
||||
This proceeds in four stages: first, the main GitHub repository is queried for a list of possible
|
||||
@@ -305,13 +301,36 @@ class CommandAddonManager:
|
||||
|
||||
"""
|
||||
|
||||
# Each function in this list is expected to launch a thread and connect its completion signal
|
||||
# to self.do_next_startup_phase
|
||||
self.startup_sequence = [self.populate_packages_table,
|
||||
self.populate_macros,
|
||||
self.update_metadata_cache,
|
||||
self.check_updates]
|
||||
self.current_progress_region = 0
|
||||
self.number_of_progress_regions = len(self.startup_sequence)
|
||||
self.do_next_startup_phase()
|
||||
|
||||
def do_next_startup_phase(self) -> None:
|
||||
""" Pop the top item in self.startup_sequence off the list and run it """
|
||||
|
||||
if (len(self.startup_sequence) > 0):
|
||||
phase_runner = self.startup_sequence.pop(0)
|
||||
self.current_progress_region += 1
|
||||
phase_runner()
|
||||
else:
|
||||
self.hide_progress_widgets()
|
||||
self.dialog.tablePackages.setEnabled(True)
|
||||
self.dialog.lineEditFilter.setFocus()
|
||||
|
||||
def populate_packages_table(self) -> None:
|
||||
self.item_model.clear()
|
||||
self.current_progress_region += 1
|
||||
self.update_worker = UpdateWorker()
|
||||
self.update_worker.status_message.connect(self.show_information)
|
||||
self.update_worker.addon_repo.connect(self.add_addon_repo)
|
||||
self.update_progress_bar(10,100)
|
||||
self.update_worker.done.connect(self.populate_macros) # Link to step 2
|
||||
self.update_worker.done.connect(self.do_next_startup_phase) # Link to step 2
|
||||
self.update_worker.start()
|
||||
|
||||
def populate_macros(self) -> None:
|
||||
@@ -320,8 +339,7 @@ class CommandAddonManager:
|
||||
self.macro_worker.status_message_signal.connect(self.show_information)
|
||||
self.macro_worker.progress_made.connect(self.update_progress_bar)
|
||||
self.macro_worker.add_macro_signal.connect(self.add_addon_repo)
|
||||
self.macro_worker.done.connect(self.update_metadata_cache) # Link to step 3
|
||||
self.macro_worker.done.connect(lambda : self.dialog.tablePackages.setEnabled(True))
|
||||
self.macro_worker.done.connect(self.do_next_startup_phase) # Link to step 3
|
||||
self.macro_worker.start()
|
||||
|
||||
def update_metadata_cache(self) -> None:
|
||||
@@ -330,23 +348,24 @@ class CommandAddonManager:
|
||||
if pref.GetBool("AutoFetchMetadata", True):
|
||||
self.update_metadata_cache_worker = UpdateMetadataCacheWorker(self.item_model.repos)
|
||||
self.update_metadata_cache_worker.status_message.connect(self.show_information)
|
||||
self.update_metadata_cache_worker.done.connect(self.check_updates) # Link to step 4
|
||||
self.update_metadata_cache_worker.done.connect(self.do_next_startup_phase) # Link to step 4
|
||||
self.update_metadata_cache_worker.progress_made.connect(self.update_progress_bar)
|
||||
self.update_metadata_cache_worker.package_updated.connect(self.on_package_updated)
|
||||
self.update_metadata_cache_worker.start()
|
||||
else:
|
||||
self.check_updates()
|
||||
self.do_next_startup_phase()
|
||||
|
||||
def on_package_updated(self, repo:AddonManagerRepo) -> None:
|
||||
"""Called when the named package has either new metadata or a new icon (or both)"""
|
||||
|
||||
cache_path = os.path.join(FreeCAD.getUserAppDataDir(), "AddonManager", "PackageMetadata", repo.name)
|
||||
icon_filename = repo.metadata.Icon
|
||||
icon_path = os.path.join(cache_path, icon_filename)
|
||||
if os.path.isfile(icon_path):
|
||||
addonicon = QtGui.QIcon(icon_path)
|
||||
repo.icon = addonicon
|
||||
self.item_model.reload_item(repo)
|
||||
with self.lock:
|
||||
cache_path = os.path.join(FreeCAD.getUserAppDataDir(), "AddonManager", "PackageMetadata", repo.name)
|
||||
icon_filename = repo.metadata.Icon
|
||||
icon_path = os.path.join(cache_path, icon_filename)
|
||||
if os.path.isfile(icon_path):
|
||||
addonicon = QtGui.QIcon(icon_path)
|
||||
repo.icon = addonicon
|
||||
self.item_model.reload_item(repo)
|
||||
|
||||
|
||||
def check_updates(self) -> None:
|
||||
@@ -356,16 +375,18 @@ class CommandAddonManager:
|
||||
pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Addons")
|
||||
autocheck = pref.GetBool("AutoCheck", False)
|
||||
if not autocheck:
|
||||
self.do_next_startup_phase()
|
||||
return
|
||||
if not self.packages_with_updates:
|
||||
if hasattr(self, "check_worker"):
|
||||
thread = self.check_worker
|
||||
if thread:
|
||||
if not thread.isFinished():
|
||||
self.do_next_startup_phase()
|
||||
return
|
||||
self.dialog.buttonUpdateAll.setText(translate("AddonsInstaller", "Checking for updates..."))
|
||||
self.check_worker = CheckWorkbenchesForUpdatesWorker(self.item_model.repos)
|
||||
self.check_worker.done.connect(self.hide_progress_widgets)
|
||||
self.check_worker.done.connect(self.do_next_startup_phase)
|
||||
self.check_worker.progress_made.connect(self.update_progress_bar)
|
||||
self.check_worker.update_status.connect(self.status_updated)
|
||||
self.check_worker.start()
|
||||
@@ -440,9 +461,9 @@ class CommandAddonManager:
|
||||
if not current.isValid():
|
||||
self.selected_repo = None
|
||||
return
|
||||
|
||||
source_selection = self.item_filter.mapToSource (current)
|
||||
self.selected_repo = self.item_model.repos[source_selection.row()]
|
||||
self.dialog.description.clear()
|
||||
if self.selected_repo.repo_type == AddonManagerRepo.RepoType.MACRO:
|
||||
self.show_macro(self.selected_repo)
|
||||
self.dialog.buttonExecute.show()
|
||||
@@ -832,11 +853,11 @@ class CommandAddonManager:
|
||||
if text_filter:
|
||||
test_regex = QtCore.QRegularExpression(text_filter)
|
||||
if test_regex.isValid():
|
||||
self.dialog.labelFilterValidity.setToolTip(translate("AddonInstaller","Filter is valid"))
|
||||
self.dialog.labelFilterValidity.setToolTip(translate("AddonsInstaller","Filter is valid"))
|
||||
icon = QtGui.QIcon.fromTheme("ok", QtGui.QIcon(":/icons/edit_OK.svg"))
|
||||
self.dialog.labelFilterValidity.setPixmap(icon.pixmap(16,16))
|
||||
else:
|
||||
self.dialog.labelFilterValidity.setToolTip(translate("AddonInstaller","Filter regular expression is invalid"))
|
||||
self.dialog.labelFilterValidity.setToolTip(translate("AddonsInstaller","Filter regular expression is invalid"))
|
||||
icon = QtGui.QIcon.fromTheme("cancel", QtGui.QIcon(":/icons/edit_Cancel.svg"))
|
||||
self.dialog.labelFilterValidity.setPixmap(icon.pixmap(16,16))
|
||||
self.dialog.labelFilterValidity.show()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#***************************************************************************
|
||||
#* *
|
||||
#* Copyright (c) 2021 Chris Hennes <chennes@pioneerlibrarysystem.org> *
|
||||
@@ -45,6 +44,9 @@ class AddonManagerRepo:
|
||||
elif self.value == 3:
|
||||
return "Package"
|
||||
|
||||
def __int__(self) -> int :
|
||||
return self.value
|
||||
|
||||
class UpdateStatus(Enum):
|
||||
NOT_INSTALLED = 0
|
||||
UNCHECKED = 1
|
||||
@@ -161,4 +163,4 @@ class AddonManagerRepo:
|
||||
store = os.path.join(FreeCAD.getUserAppDataDir(), "AddonManager", "PackageMetadata")
|
||||
self.cached_icon_filename = os.path.join(store, self.name, "cached_icon"+file_extension)
|
||||
|
||||
return self.cached_icon_filename
|
||||
return self.cached_icon_filename
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#***************************************************************************
|
||||
#* *
|
||||
#* Copyright (c) 2021 Chris Hennes <chennes@pioneerlibrarysystem.org> *
|
||||
@@ -23,7 +22,6 @@
|
||||
|
||||
import FreeCAD
|
||||
|
||||
import git
|
||||
import tempfile
|
||||
import os
|
||||
import hashlib
|
||||
@@ -67,6 +65,7 @@ class MetadataDownloadWorker(QObject):
|
||||
self.fetch_task = network_manager.get(self.request)
|
||||
self.fetch_task.finished.connect(self.resolve_fetch)
|
||||
self.fetch_task.redirected.connect(self.on_redirect)
|
||||
self.fetch_task.sslErrors.connect(self.on_ssl_error)
|
||||
|
||||
def abort(self):
|
||||
self.fetch_task.abort()
|
||||
@@ -75,6 +74,12 @@ class MetadataDownloadWorker(QObject):
|
||||
# For now just blindly follow all redirects
|
||||
self.fetch_task.redirectAllowed.emit()
|
||||
|
||||
def on_ssl_error(self, reply, errors):
|
||||
FreeCAD.Console.PrintWarning(f"Error with encrypted connection:\n")
|
||||
FreeCAD.Console.PrintWarning(reply)
|
||||
for error in errors:
|
||||
FreeCAD.Console.PrintWarning(error)
|
||||
|
||||
def resolve_fetch(self):
|
||||
"Called when the data fetch completed, either with an error, or if it found the metadata file"
|
||||
if self.fetch_task.error() == QtNetwork.QNetworkReply.NetworkError.NoError:
|
||||
@@ -104,11 +109,15 @@ class MetadataDownloadWorker(QObject):
|
||||
# There is no local copy yet, so we definitely have to update
|
||||
# the cache
|
||||
self.update_local_copy(new_xml)
|
||||
elif self.fetch_task.error() == QtNetwork.QNetworkReply.NetworkError.ContentNotFoundError:
|
||||
pass
|
||||
else:
|
||||
FreeCAD.Console.PrintWarning(f"Failed to connect to {self.url}:\n {self.fetch_task.error()}\n")
|
||||
|
||||
def update_local_copy(self, new_xml):
|
||||
# We have to update the local copy of the metadata file and re-download
|
||||
# the icon file
|
||||
|
||||
|
||||
name = self.repo.name
|
||||
repo_url = self.repo.url
|
||||
package_cache_directory = os.path.join(self.store, name)
|
||||
@@ -116,7 +125,7 @@ class MetadataDownloadWorker(QObject):
|
||||
os.makedirs(package_cache_directory)
|
||||
new_xml_file = os.path.join(package_cache_directory, "package.xml")
|
||||
with open(new_xml_file, "wb") as f:
|
||||
f.write(new_xml)
|
||||
f.write(new_xml.data())
|
||||
metadata = FreeCAD.Metadata(new_xml_file)
|
||||
self.repo.metadata = metadata
|
||||
self.repo.repo_type = AddonManagerRepo.RepoType.PACKAGE
|
||||
|
||||
@@ -203,10 +203,13 @@ def construct_git_url(repo, filename):
|
||||
parsed_url = urlparse(repo.url)
|
||||
if parsed_url.netloc == "github.com" or parsed_url.netloc == "framagit.com":
|
||||
return f"{repo.url}/raw/{repo.branch}/{filename}"
|
||||
elif parsed_url.netloc == "gitlab.com" or parsed_url.netloc == "salsa.debian.org":
|
||||
elif parsed_url.netloc == "gitlab.com":
|
||||
return f"{repo.url}/-/raw/{repo.branch}/{filename}"
|
||||
elif parsed_url.netloc == "salsa.debian.org":
|
||||
# e.g. https://salsa.debian.org/joha2/pyrate/-/raw/master/package.xml
|
||||
return f"{repo.url}/-/raw/{repo.branch}/{filename}"
|
||||
else:
|
||||
FreeCAD.Console.PrintLog("Debug: addonmanager_utilities.construct_git_url: Unknown git host:", parsed_url.netloc)
|
||||
FreeCAD.Console.PrintLog("Debug: addonmanager_utilities.construct_git_url: Unknown git host:" + parsed_url.netloc)
|
||||
return None
|
||||
|
||||
def get_readme_url(repo):
|
||||
|
||||
@@ -163,20 +163,6 @@ class UpdateWorker(QtCore.QThread):
|
||||
self.addon_repo.emit(cached_package)
|
||||
package_names.append(name)
|
||||
|
||||
u = utils.urlopen("https://raw.githubusercontent.com/FreeCAD/FreeCAD-addons/master/.gitmodules")
|
||||
if not u:
|
||||
self.done.emit()
|
||||
self.stop = True
|
||||
return
|
||||
p = u.read()
|
||||
if isinstance(p, bytes):
|
||||
p = p.decode("utf-8")
|
||||
u.close()
|
||||
p = re.findall((r'(?m)\[submodule\s*"(?P<name>.*)"\]\s*'
|
||||
r"path\s*=\s*(?P<path>.+)\s*"
|
||||
r"url\s*=\s*(?P<url>https?://.*)\s*"
|
||||
r"(branch\s*=\s*(?P<branch>.*)\s*)?"), p)
|
||||
|
||||
# querying custom addons
|
||||
addon_list = (FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Addons")
|
||||
.GetString("CustomRepositories", "").split("\n"))
|
||||
@@ -207,6 +193,19 @@ class UpdateWorker(QtCore.QThread):
|
||||
self.addon_repo.emit(AddonManagerRepo(name, addon["url"], state, addon["branch"]))
|
||||
|
||||
# querying official addons
|
||||
u = utils.urlopen("https://raw.githubusercontent.com/FreeCAD/FreeCAD-addons/master/.gitmodules")
|
||||
if not u:
|
||||
self.done.emit()
|
||||
self.stop = True
|
||||
return
|
||||
p = u.read()
|
||||
if isinstance(p, bytes):
|
||||
p = p.decode("utf-8")
|
||||
u.close()
|
||||
p = re.findall((r'(?m)\[submodule\s*"(?P<name>.*)"\]\s*'
|
||||
r"path\s*=\s*(?P<path>.+)\s*"
|
||||
r"url\s*=\s*(?P<url>https?://.*)\s*"
|
||||
r"(branch\s*=\s*(?P<branch>.*)\s*)?"), p)
|
||||
for name, path, url, _, branch in p:
|
||||
if self.current_thread.isInterruptionRequested():
|
||||
return
|
||||
@@ -233,7 +232,9 @@ class UpdateWorker(QtCore.QThread):
|
||||
class CheckWorkbenchesForUpdatesWorker(QtCore.QThread):
|
||||
"""This worker checks for available updates for all workbenches"""
|
||||
|
||||
update_status = QtCore.Signal(AddonManagerRepo, AddonManagerRepo.UpdateStatus)
|
||||
# Emitting an Enum fails on Ubuntu 20.04, so use an int instead
|
||||
#update_status = QtCore.Signal(AddonManagerRepo, AddonManagerRepo.UpdateStatus)
|
||||
update_status = QtCore.Signal(AddonManagerRepo, int)
|
||||
progress_made = QtCore.Signal(int, int)
|
||||
done = QtCore.Signal()
|
||||
|
||||
@@ -245,6 +246,7 @@ class CheckWorkbenchesForUpdatesWorker(QtCore.QThread):
|
||||
def run(self):
|
||||
|
||||
if NOGIT or not have_git:
|
||||
self.done.emit()
|
||||
self.stop = True
|
||||
return
|
||||
self.current_thread = QtCore.QThread.currentThread()
|
||||
@@ -271,6 +273,8 @@ class CheckWorkbenchesForUpdatesWorker(QtCore.QThread):
|
||||
self.done.emit()
|
||||
|
||||
def check_workbench(self, wb):
|
||||
if not have_git or NOGIT:
|
||||
return
|
||||
clonedir = self.moddir + os.sep + wb.name
|
||||
if os.path.exists(clonedir):
|
||||
# mark as already installed AND already checked for updates
|
||||
@@ -399,7 +403,7 @@ class FillMacroListWorker(QtCore.QThread):
|
||||
https://github.com/FreeCAD/FreeCAD-macros.git
|
||||
"""
|
||||
|
||||
if not have_git:
|
||||
if not have_git or NOGIT:
|
||||
self.status_message_signal.emit("GitPython not installed! Cannot retrieve macros from Git")
|
||||
FreeCAD.Console.PrintWarning(translate("AddonsInstaller",
|
||||
"GitPython not installed! Cannot retrieve macros from git") + "\n")
|
||||
@@ -558,6 +562,8 @@ class ShowWorker(QtCore.QThread):
|
||||
if not desc:
|
||||
desc = "Unable to retrieve addon description"
|
||||
self.repo.description = desc
|
||||
if QtCore.QThread.currentThread().isInterruptionRequested():
|
||||
return
|
||||
self.addon_repos.emit(self.repo)
|
||||
# Addon is installed so lets check if it has an update
|
||||
if self.repo.update_status == AddonManagerRepo.UpdateStatus.UPDATE_AVAILABLE:
|
||||
@@ -610,8 +616,10 @@ class ShowWorker(QtCore.QThread):
|
||||
message += self.repo.url + '">' + self.repo.url + "</a>"
|
||||
self.repo.update_status = AddonManagerRepo.UpdateStatus.NO_UPDATE_AVAILABLE
|
||||
# Let the user know the install path for this addon
|
||||
message += "<br/>" + translate("AddonInstaller", "Installed location") + ": "
|
||||
message += "<br/>" + translate("AddonsInstaller", "Installed location") + ": "
|
||||
message += FreeCAD.getUserAppDataDir() + os.sep + "Mod" + os.sep + self.repo.name
|
||||
if QtCore.QThread.currentThread().isInterruptionRequested():
|
||||
return
|
||||
self.addon_repos.emit(self.repo)
|
||||
elif self.repo.update_status == AddonManagerRepo.UpdateStatus.PENDING_RESTART:
|
||||
message = """
|
||||
@@ -622,7 +630,7 @@ class ShowWorker(QtCore.QThread):
|
||||
message += translate("AddonsInstaller", "This addon has been updated, a restart is now required before it can be used.")
|
||||
message += "</strong><br/></div><hr/>" + desc + '<br/><br/>Addon repository: <a href="'
|
||||
message += self.repo.url + '">' + self.repo.url + "</a>"
|
||||
message += "<br/>" + translate("AddonInstaller", "Installed location") + ": "
|
||||
message += "<br/>" + translate("AddonsInstaller", "Installed location") + ": "
|
||||
message += FreeCAD.getUserAppDataDir() + os.sep + "Mod" + os.sep + self.repo.name
|
||||
elif self.repo.update_status == AddonManagerRepo.UpdateStatus.NO_UPDATE_AVAILABLE:
|
||||
message = """
|
||||
@@ -634,7 +642,7 @@ class ShowWorker(QtCore.QThread):
|
||||
message += "</strong><br></div><hr/>" + desc
|
||||
message += '<br/><br/>Addon repository: <a href="'
|
||||
message += self.repo.url + '">' + self.repo.url + "</a>"
|
||||
message += "<br/>" + translate("AddonInstaller", "Installed location") + ": "
|
||||
message += "<br/>" + translate("AddonsInstaller", "Installed location") + ": "
|
||||
message += FreeCAD.getUserAppDataDir() + os.sep + "Mod" + os.sep + self.repo.name
|
||||
elif self.repo.update_status == AddonManagerRepo.UpdateStatus.UPDATE_AVAILABLE:
|
||||
message = """
|
||||
@@ -645,7 +653,7 @@ class ShowWorker(QtCore.QThread):
|
||||
message += translate("AddonsInstaller", "An update is available for this addon.")
|
||||
message += "</strong><br/></div><hr/>" + desc + '<br/><br/>Addon repository: <a href="'
|
||||
message += self.repo.url + '">' + self.repo.url + "</a>"
|
||||
message += "<br/>" + translate("AddonInstaller", "Installed location") + ": "
|
||||
message += "<br/>" + translate("AddonsInstaller", "Installed location") + ": "
|
||||
message += FreeCAD.getUserAppDataDir() + os.sep + "Mod" + os.sep + self.repo.name
|
||||
else:
|
||||
message = desc + '<br/><br/>Addon repository: <a href="'
|
||||
@@ -676,11 +684,15 @@ class ShowWorker(QtCore.QThread):
|
||||
"likely result in errors at startup or while in use.")
|
||||
message += "<br/></div><hr/>" + desc
|
||||
|
||||
if QtCore.QThread.currentThread().isInterruptionRequested():
|
||||
return
|
||||
self.description_updated.emit(message)
|
||||
self.mustLoadImages = True
|
||||
label = self.loadImages(message, self.repo.url, self.repo.name)
|
||||
if label:
|
||||
self.description_updated.emit(label)
|
||||
if QtCore.QThread.currentThread().isInterruptionRequested():
|
||||
return
|
||||
self.done.emit()
|
||||
self.stop = True
|
||||
|
||||
@@ -703,6 +715,8 @@ class ShowWorker(QtCore.QThread):
|
||||
if not os.path.exists(store):
|
||||
os.makedirs(store)
|
||||
for path in imagepaths:
|
||||
if QtCore.QThread.currentThread().isInterruptionRequested():
|
||||
return
|
||||
if QtCore.QThread.currentThread().isInterruptionRequested():
|
||||
return message
|
||||
if not self.mustLoadImages:
|
||||
@@ -725,7 +739,7 @@ class ShowWorker(QtCore.QThread):
|
||||
imagedata = u.read()
|
||||
u.close()
|
||||
except Exception:
|
||||
FreeCAD.Console.PrintLog("AddonManager: Debug: Error retrieving image from", path)
|
||||
FreeCAD.Console.PrintLog("AddonManager: Debug: Error retrieving image from " + path)
|
||||
else:
|
||||
try:
|
||||
f = open(storename, "wb")
|
||||
@@ -779,6 +793,8 @@ class GetMacroDetailsWorker(QtCore.QThread):
|
||||
else:
|
||||
already_installed_msg = ""
|
||||
message = (already_installed_msg + "<h1>" + self.macro.name + "</h1>" + self.macro.desc + "<br/><br/>Macro location: <a href=\"" + self.macro.url + "\">" + self.macro.url + "</a>")
|
||||
if QtCore.QThread.currentThread().isInterruptionRequested():
|
||||
return
|
||||
self.description_updated.emit(message)
|
||||
self.done.emit()
|
||||
self.stop = True
|
||||
@@ -796,7 +812,7 @@ class InstallWorkbenchWorker(QtCore.QThread):
|
||||
|
||||
QtCore.QThread.__init__(self)
|
||||
self.repo = repo
|
||||
if have_git:
|
||||
if have_git and not NOGIT:
|
||||
self.git_progress = GitProgressMonitor()
|
||||
# TODO: What is wrong with these?
|
||||
#self.git_progress.progress_made.connect(self.progress_made.emit)
|
||||
@@ -808,7 +824,7 @@ class InstallWorkbenchWorker(QtCore.QThread):
|
||||
if not self.repo:
|
||||
return
|
||||
|
||||
if not have_git:
|
||||
if not have_git or NOGIT:
|
||||
FreeCAD.Console.PrintWarning(translate("AddonsInstaller",
|
||||
"GitPython not found. Using ZIP file download instead.") + "\n")
|
||||
if not have_zip:
|
||||
@@ -823,7 +839,7 @@ class InstallWorkbenchWorker(QtCore.QThread):
|
||||
os.makedirs(moddir)
|
||||
target_dir = moddir + os.sep + self.repo.name
|
||||
|
||||
if have_git:
|
||||
if have_git and not NOGIT:
|
||||
self.run_git(target_dir)
|
||||
else:
|
||||
self.run_zip(target_dir)
|
||||
@@ -832,6 +848,12 @@ class InstallWorkbenchWorker(QtCore.QThread):
|
||||
|
||||
def run_git(self, clonedir:str) -> None:
|
||||
|
||||
if NOGIT or not have_git:
|
||||
FreeCAD.Console.PrintWarning(translate("AddonsInstaller",
|
||||
"No Git Python installed, skipping git operations") + "\n")
|
||||
return
|
||||
|
||||
|
||||
if os.path.exists(clonedir):
|
||||
self.run_git_update(clonedir)
|
||||
else:
|
||||
@@ -1049,7 +1071,7 @@ class CheckSingleWorker(QtCore.QThread):
|
||||
|
||||
def run(self):
|
||||
|
||||
if not have_git:
|
||||
if not have_git or NOGIT:
|
||||
return
|
||||
FreeCAD.Console.PrintLog("Checking for available updates of the " + self.name + " addon\n")
|
||||
addondir = os.path.join(FreeCAD.getUserAppDataDir(), "Mod", self.name)
|
||||
@@ -1098,8 +1120,6 @@ class UpdateMetadataCacheWorker(QtCore.QThread):
|
||||
self.counter = UpdateMetadataCacheWorker.AtomicCounter()
|
||||
|
||||
def run(self):
|
||||
if not have_git:
|
||||
return
|
||||
current_thread = QtCore.QThread.currentThread()
|
||||
self.num_downloads_required = len(self.repos)
|
||||
self.progress_made.emit(0, self.num_downloads_required)
|
||||
@@ -1117,10 +1137,11 @@ class UpdateMetadataCacheWorker(QtCore.QThread):
|
||||
|
||||
self.downloaders = []
|
||||
for repo in self.repos:
|
||||
downloader = MetadataDownloadWorker(None, repo, self.index)
|
||||
downloader.start_fetch(download_queue)
|
||||
downloader.updated.connect(self.on_updated)
|
||||
self.downloaders.append(downloader)
|
||||
if repo.metadata_url:
|
||||
downloader = MetadataDownloadWorker(None, repo, self.index)
|
||||
downloader.start_fetch(download_queue)
|
||||
downloader.updated.connect(self.on_updated)
|
||||
self.downloaders.append(downloader)
|
||||
|
||||
# Run a local event loop until we've processed all of the downloads:
|
||||
# this is local
|
||||
@@ -1128,7 +1149,7 @@ class UpdateMetadataCacheWorker(QtCore.QThread):
|
||||
ui_updater = QtCore.QTimer()
|
||||
ui_updater.timeout.connect(self.send_ui_update)
|
||||
ui_updater.start(100) # Send an update back to the main thread every 100ms
|
||||
self.num_downloads_required = len(self.repos)
|
||||
self.num_downloads_required = len(self.downloaders)
|
||||
self.num_downloads_completed = UpdateMetadataCacheWorker.AtomicCounter()
|
||||
while True:
|
||||
if current_thread.isInterruptionRequested():
|
||||
@@ -1139,7 +1160,6 @@ class UpdateMetadataCacheWorker(QtCore.QThread):
|
||||
break
|
||||
|
||||
if current_thread.isInterruptionRequested():
|
||||
FreeCAD.Console.PrintMessage("Bailing out of downloads")
|
||||
return
|
||||
|
||||
# Update and serialize the updated index, overwriting whatever was
|
||||
@@ -1168,20 +1188,21 @@ class UpdateMetadataCacheWorker(QtCore.QThread):
|
||||
self.progress_made.emit(self.num_downloads_completed.get(), self.num_downloads_required)
|
||||
|
||||
|
||||
class GitProgressMonitor(git.RemoteProgress):
|
||||
""" An object that receives git progress updates and transforms them into Qt signals """
|
||||
if have_git and not NOGIT:
|
||||
class GitProgressMonitor(git.RemoteProgress):
|
||||
""" An object that receives git progress updates and transforms them into Qt signals """
|
||||
|
||||
progress_made = QtCore.Signal(int, int)
|
||||
info_message = QtCore.Signal(str)
|
||||
progress_made = QtCore.Signal(int, int)
|
||||
info_message = QtCore.Signal(str)
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def update(self, op_code: int, cur_count: Union[str, float], max_count: Union[str, float, None]=None, message: str='') -> None:
|
||||
if max_count:
|
||||
self.progress_made.emit(int(cur_count), int(max_count))
|
||||
if message:
|
||||
self.info_message.emit(message)
|
||||
def update(self, op_code: int, cur_count: Union[str, float], max_count: Union[str, float, None]=None, message: str='') -> None:
|
||||
if max_count:
|
||||
self.progress_made.emit(int(cur_count), int(max_count))
|
||||
if message:
|
||||
self.info_message.emit(message)
|
||||
|
||||
|
||||
class UpdateAllWorker(QtCore.QThread):
|
||||
@@ -1291,4 +1312,4 @@ class UpdateSingleWorker(QtCore.QThread):
|
||||
if not worker.isRunning():
|
||||
break
|
||||
|
||||
# @}
|
||||
# @}
|
||||
|
||||
Reference in New Issue
Block a user