Addon Manager: Bug fixes and license cleanup
This commit is contained in:
@@ -223,12 +223,16 @@ class Addon:
|
||||
@property
|
||||
def license(self):
|
||||
if not self._cached_license:
|
||||
self._cached_license = "UNLICENSED"
|
||||
if self.metadata and self.metadata.license:
|
||||
self._cached_license = self.metadata.license
|
||||
elif self.stats and self.stats.license:
|
||||
self._cached_license = self.stats.license
|
||||
elif self.macro and self.macro.license:
|
||||
self._cached_license = self.macro.license
|
||||
elif self.macro:
|
||||
if self.macro.license:
|
||||
self._cached_license = self.macro.license
|
||||
elif self.macro.on_wiki:
|
||||
self._cached_license = "CC-BY-3.0"
|
||||
return self._cached_license
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -550,8 +550,9 @@ class CommandAddonManager:
|
||||
)
|
||||
self.startup()
|
||||
|
||||
# Recaching implies checking for updates, regardless of the user's autocheck option
|
||||
self.startup_sequence.remove(self.check_updates)
|
||||
# Re-caching implies checking for updates, regardless of the user's autocheck option
|
||||
if self.check_updates in self.startup_sequence:
|
||||
self.startup_sequence.remove(self.check_updates)
|
||||
self.startup_sequence.append(self.force_check_updates)
|
||||
|
||||
def on_package_updated(self, repo: Addon) -> None:
|
||||
|
||||
@@ -391,7 +391,8 @@ if HAVE_QTNETWORK:
|
||||
def __synchronous_process_completion(
|
||||
self, index: int, code: int, data: QtCore.QByteArray
|
||||
) -> None:
|
||||
"""Check the return status of a completed process, and handle its returned data (if any)."""
|
||||
"""Check the return status of a completed process, and handle its returned data (if
|
||||
any)."""
|
||||
with self.synchronous_lock:
|
||||
if index in self.synchronous_complete:
|
||||
if code == 200:
|
||||
@@ -406,7 +407,8 @@ if HAVE_QTNETWORK:
|
||||
)
|
||||
self.synchronous_complete[index] = True
|
||||
|
||||
def __create_get_request(self, url: str, timeout_ms: int) -> QtNetwork.QNetworkRequest:
|
||||
@staticmethod
|
||||
def __create_get_request(url: str, timeout_ms: int) -> QtNetwork.QNetworkRequest:
|
||||
"""Construct a network request to a given URL"""
|
||||
request = QtNetwork.QNetworkRequest(QtCore.QUrl(url))
|
||||
request.setAttribute(
|
||||
@@ -560,21 +562,20 @@ if HAVE_QTNETWORK:
|
||||
# This can happen during a cancellation operation: silently do nothing
|
||||
return
|
||||
|
||||
if reply.error() == QtNetwork.QNetworkReply.NetworkError.OperationCanceledError:
|
||||
# Silently do nothing
|
||||
return
|
||||
|
||||
index = None
|
||||
for key, value in self.replies.items():
|
||||
if reply == value:
|
||||
index = key
|
||||
break
|
||||
if index is None:
|
||||
print(f"Lost net request for {reply.url()}")
|
||||
return
|
||||
|
||||
response_code = reply.attribute(QtNetwork.QNetworkRequest.HttpStatusCodeAttribute)
|
||||
self.queue.task_done()
|
||||
if response_code == 301: # Permanently moved -- this is a redirect, bail out
|
||||
return
|
||||
if reply.error() != QtNetwork.QNetworkReply.NetworkError.OperationCanceledError:
|
||||
# It this was not a timeout, make sure we mark the queue task done
|
||||
self.queue.task_done()
|
||||
if reply.error() == QtNetwork.QNetworkReply.NetworkError.NoError:
|
||||
if index in self.monitored_connections:
|
||||
# Make sure to read any remaining data
|
||||
|
||||
@@ -75,6 +75,8 @@ class SPDXLicenseManager:
|
||||
def is_osi_approved(self, spdx_id: str) -> bool:
|
||||
"""Check to see if the license is OSI-approved, according to the SPDX database. Returns
|
||||
False if the license is not in the database, or is not marked as "isOsiApproved"."""
|
||||
if spdx_id == "UNLICENSED" or spdx_id == "UNLICENCED" or spdx_id.startswith("SEE LIC"):
|
||||
return False
|
||||
if spdx_id not in self.license_data:
|
||||
fci.Console.PrintWarning(
|
||||
f"WARNING: License ID {spdx_id} is not in the SPDX license "
|
||||
@@ -89,6 +91,8 @@ class SPDXLicenseManager:
|
||||
def is_fsf_libre(self, spdx_id: str) -> bool:
|
||||
"""Check to see if the license is FSF Free/Libre, according to the SPDX database. Returns
|
||||
False if the license is not in the database, or is not marked as "isFsfLibre"."""
|
||||
if spdx_id == "UNLICENSED" or spdx_id == "UNLICENCED" or spdx_id.startswith("SEE LIC"):
|
||||
return False
|
||||
if spdx_id not in self.license_data:
|
||||
fci.Console.PrintWarning(
|
||||
f"WARNING: License ID {spdx_id} is not in the SPDX license "
|
||||
@@ -100,6 +104,10 @@ class SPDXLicenseManager:
|
||||
)
|
||||
|
||||
def name(self, spdx_id: str) -> str:
|
||||
if spdx_id == "UNLICENSED":
|
||||
return "All rights reserved"
|
||||
if spdx_id.startswith("SEE LIC"): # "SEE LICENSE IN" or "SEE LICENCE IN"
|
||||
return f"Custom license: {spdx_id}"
|
||||
if spdx_id not in self.license_data:
|
||||
return ""
|
||||
return self.license_data[spdx_id]["name"]
|
||||
@@ -145,21 +153,24 @@ class SPDXLicenseManager:
|
||||
.replace("GPL2", "GPL-2")
|
||||
.replace("GPL3", "GPL-3")
|
||||
)
|
||||
if self.name(normed):
|
||||
or_later = ""
|
||||
if normed.endswith("+"):
|
||||
normed = normed[:-1]
|
||||
or_later = "-or-later"
|
||||
if self.name(normed + or_later):
|
||||
fci.Console.PrintLog(f"found valid SPDX license ID {normed}\n")
|
||||
return normed
|
||||
return normed + or_later
|
||||
# If it still doesn't match, try some other things
|
||||
while "--" in normed:
|
||||
normed = license_string.replace("--", "-")
|
||||
normed = normed.replace("--", "-")
|
||||
|
||||
if self.name(normed):
|
||||
if self.name(normed + or_later):
|
||||
fci.Console.PrintLog(f"found valid SPDX license ID {normed}\n")
|
||||
return normed
|
||||
if not normed.endswith(".0"):
|
||||
normed += ".0"
|
||||
if self.name(normed):
|
||||
return normed + or_later
|
||||
normed += ".0"
|
||||
if self.name(normed + or_later):
|
||||
fci.Console.PrintLog(f"found valid SPDX license ID {normed}\n")
|
||||
return normed
|
||||
return normed + or_later
|
||||
fci.Console.PrintLog(f"failed to normalize (typo in ID or invalid version number??)\n")
|
||||
return license_string # We failed to normalize this one
|
||||
|
||||
|
||||
@@ -160,9 +160,6 @@ class Macro:
|
||||
code = self._fetch_raw_code(p)
|
||||
if not code:
|
||||
code = self._read_code_from_wiki(p)
|
||||
if not self.license:
|
||||
# The default license on the wiki is CC-BY-3.0 (which is non-Libre and not OSI-approved)
|
||||
self.license = "CC-BY-3.0"
|
||||
if not code:
|
||||
self._console.PrintWarning(
|
||||
translate("AddonsInstaller", "Unable to fetch the code of this macro.") + "\n"
|
||||
|
||||
@@ -380,7 +380,7 @@ def blocking_get(url: str, method=None) -> bytes:
|
||||
p = b""
|
||||
if fci.FreeCADGui and method is None or method == "networkmanager":
|
||||
NetworkManager.InitializeNetworkManager()
|
||||
p = NetworkManager.AM_NETWORK_MANAGER.blocking_get(url)
|
||||
p = NetworkManager.AM_NETWORK_MANAGER.blocking_get(url, 10000) # 10 second timeout
|
||||
if p:
|
||||
try:
|
||||
p = p.data()
|
||||
|
||||
@@ -87,7 +87,7 @@ class UpdateMetadataCacheWorker(QtCore.QThread):
|
||||
current_thread = QtCore.QThread.currentThread()
|
||||
|
||||
for repo in self.repos:
|
||||
if repo.url and utils.recognized_git_location(repo):
|
||||
if not repo.macro and repo.url and utils.recognized_git_location(repo):
|
||||
# package.xml
|
||||
index = NetworkManager.AM_NETWORK_MANAGER.submit_unmonitored_get(
|
||||
utils.construct_git_url(repo, "package.xml")
|
||||
@@ -120,7 +120,6 @@ class UpdateMetadataCacheWorker(QtCore.QThread):
|
||||
|
||||
while self.requests:
|
||||
if current_thread.isInterruptionRequested():
|
||||
NetworkManager.AM_NETWORK_MANAGER.completed.disconnect(self.download_completed)
|
||||
for request in self.requests:
|
||||
NetworkManager.AM_NETWORK_MANAGER.abort(request)
|
||||
return
|
||||
|
||||
@@ -93,7 +93,7 @@ class CreateAddonListWorker(QtCore.QThread):
|
||||
def _get_freecad_addon_repo_data(self):
|
||||
# update info lists
|
||||
p = NetworkManager.AM_NETWORK_MANAGER.blocking_get(
|
||||
"https://raw.githubusercontent.com/FreeCAD/FreeCAD-addons/master/addonflags.json"
|
||||
"https://raw.githubusercontent.com/FreeCAD/FreeCAD-addons/master/addonflags.json", 5000
|
||||
)
|
||||
if p:
|
||||
p = p.data().decode("utf8")
|
||||
@@ -203,7 +203,7 @@ class CreateAddonListWorker(QtCore.QThread):
|
||||
def _get_official_addons(self):
|
||||
# querying official addons
|
||||
p = NetworkManager.AM_NETWORK_MANAGER.blocking_get(
|
||||
"https://raw.githubusercontent.com/FreeCAD/FreeCAD-addons/master/.gitmodules"
|
||||
"https://raw.githubusercontent.com/FreeCAD/FreeCAD-addons/master/.gitmodules", 5000
|
||||
)
|
||||
if not p:
|
||||
return
|
||||
@@ -369,7 +369,7 @@ class CreateAddonListWorker(QtCore.QThread):
|
||||
"""
|
||||
|
||||
p = NetworkManager.AM_NETWORK_MANAGER.blocking_get(
|
||||
"https://wiki.freecad.org/Macros_recipes"
|
||||
"https://wiki.freecad.org/Macros_recipes", 5000
|
||||
)
|
||||
if not p:
|
||||
# The Qt Python translation extractor doesn't support splitting this string (yet)
|
||||
|
||||
Reference in New Issue
Block a user