Addon Manager: Bugfixes and cleanup of refactor

This commit is contained in:
Chris Hennes
2021-10-28 09:14:50 -05:00
parent fa8cac06f4
commit ba3d921f3f
5 changed files with 140 additions and 84 deletions

View File

@@ -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()

View File

@@ -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

View File

@@ -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

View File

@@ -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):

View File

@@ -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
# @}
# @}