diff --git a/src/Mod/AddonManager/Addon.py b/src/Mod/AddonManager/Addon.py
index e67614de85..5289f2752b 100644
--- a/src/Mod/AddonManager/Addon.py
+++ b/src/Mod/AddonManager/Addon.py
@@ -192,6 +192,7 @@ class Addon:
self.macro = None # Bridge to Gaël Écorchard's macro management class
self.updated_timestamp = None
self.installed_version = None
+ self.installed_metadata = None
# Each repo is also a node in a directed dependency graph (referenced by name so
# they can be serialized):
@@ -254,6 +255,8 @@ class Addon:
if os.path.isfile(cached_package_xml_file):
instance.load_metadata_file(cached_package_xml_file)
+ instance._load_installed_metadata()
+
if "requires" in cache_dict:
instance.requires = set(cache_dict["requires"])
instance.blocks = set(cache_dict["blocks"])
@@ -293,6 +296,14 @@ class Addon:
else:
fci.Console.PrintLog(f"Internal error: {file} does not exist")
+ def _load_installed_metadata(self) -> None:
+ # If it is actually installed, there is a SECOND metadata file, in the actual installation,
+ # that may not match the cached one if the Addon has not been updated but the cache has.
+ mod_dir = os.path.join(self.mod_directory, self.name)
+ installed_metadata_path = os.path.join(mod_dir, "package.xml")
+ if os.path.isfile(installed_metadata_path):
+ self.installed_metadata = MetadataReader.from_file(installed_metadata_path)
+
def set_metadata(self, metadata: Metadata) -> None:
"""Set the given metadata object as this object's metadata, updating the
object's display name and package type information to match, as well as
@@ -683,9 +694,7 @@ class Addon:
filename, extension = os.path.splitext(current_file)
if extension == ".py":
wb_classname = self._find_classname_in_file(current_file)
- print(f"Current file: {current_file} ")
if wb_classname:
- print(f"Found name {wb_classname} \n")
return wb_classname
return ""
diff --git a/src/Mod/AddonManager/addonmanager_git.py b/src/Mod/AddonManager/addonmanager_git.py
index 7bbcd542e5..3a63d74619 100644
--- a/src/Mod/AddonManager/addonmanager_git.py
+++ b/src/Mod/AddonManager/addonmanager_git.py
@@ -387,6 +387,30 @@ class GitManager:
result_dict[author]["count"] += 1
return result_dict
+ def migrate_branch(self, local_path: str, old_branch: str, new_branch: str) -> None:
+ """Rename a branch (used when the remote branch name changed). Assumes that "origin"
+ exists."""
+ old_dir = os.getcwd()
+ os.chdir(local_path)
+ try:
+ self._synchronous_call_git(["branch", "-m", old_branch, new_branch])
+ self._synchronous_call_git(["fetch", "origin"])
+ self._synchronous_call_git(["branch", "--unset-upstream"])
+ self._synchronous_call_git(["branch", f"--set-upstream-to=origin/{new_branch}"])
+ self._synchronous_call_git(["pull"])
+ except GitFailed as e:
+ fci.Console.PrintWarning(
+ translate(
+ "AddonsInstaller",
+ "Git branch rename failed with the following message:",
+ )
+ + str(e)
+ + "\n"
+ )
+ os.chdir(old_dir)
+ raise e
+ os.chdir(old_dir)
+
def _find_git(self):
# Find git. In preference order
# A) The value of the GitExecutable user preference
diff --git a/src/Mod/AddonManager/addonmanager_installer.py b/src/Mod/AddonManager/addonmanager_installer.py
index d35a3bc4b9..cd9b2bf9e6 100644
--- a/src/Mod/AddonManager/addonmanager_installer.py
+++ b/src/Mod/AddonManager/addonmanager_installer.py
@@ -40,6 +40,7 @@ from PySide import QtCore
from Addon import Addon
import addonmanager_utilities as utils
+from addonmanager_metadata import get_branch_from_metadata
from addonmanager_git import initialize_git, GitFailed
if FreeCAD.GuiUp:
@@ -281,7 +282,12 @@ class AddonInstaller(QtCore.QObject):
install_path = os.path.join(self.installation_path, self.addon_to_install.name)
try:
if os.path.isdir(install_path):
- self.git_manager.update(install_path)
+ old_branch = get_branch_from_metadata(self.addon_to_install.installed_metadata)
+ new_branch = get_branch_from_metadata(self.addon_to_install.metadata)
+ if old_branch != new_branch:
+ self.git_manager.migrate_branch(install_path, old_branch, new_branch)
+ else:
+ self.git_manager.update(install_path)
else:
self.git_manager.clone(self.addon_to_install.url, install_path)
self.git_manager.checkout(install_path, self.addon_to_install.branch)
diff --git a/src/Mod/AddonManager/addonmanager_metadata.py b/src/Mod/AddonManager/addonmanager_metadata.py
index 115f5f29fe..213b0e2c5e 100644
--- a/src/Mod/AddonManager/addonmanager_metadata.py
+++ b/src/Mod/AddonManager/addonmanager_metadata.py
@@ -234,6 +234,13 @@ def get_first_supported_freecad_version(metadata: Metadata) -> Optional[Version]
return current_earliest
+def get_branch_from_metadata(metadata: Metadata) -> str:
+ for url in metadata.url:
+ if url.type == UrlType.repository:
+ return url.branch
+ return "master" # Legacy default
+
+
class MetadataReader:
"""Read metadata XML data and construct a Metadata object"""
diff --git a/src/Mod/AddonManager/addonmanager_workers_startup.py b/src/Mod/AddonManager/addonmanager_workers_startup.py
index a6a8e986b1..7769216e04 100644
--- a/src/Mod/AddonManager/addonmanager_workers_startup.py
+++ b/src/Mod/AddonManager/addonmanager_workers_startup.py
@@ -43,7 +43,7 @@ from addonmanager_macro import Macro
from Addon import Addon
import NetworkManager
from addonmanager_git import initialize_git, GitFailed
-from addonmanager_metadata import MetadataReader
+from addonmanager_metadata import MetadataReader, get_branch_from_metadata
translate = FreeCAD.Qt.translate
@@ -193,8 +193,8 @@ class CreateAddonListWorker(QtCore.QThread):
repo = Addon(name, addon["url"], state, addon["branch"])
md_file = os.path.join(addondir, "package.xml")
if os.path.isfile(md_file):
- repo.load_metadata_file(md_file)
- repo.installed_version = repo.metadata.version
+ repo.installed_metadata = MetadataReader.from_file(md_file)
+ repo.installed_version = repo.installed_metadata.version
repo.updated_timestamp = os.path.getmtime(md_file)
repo.verify_url_and_branch(addon["url"], addon["branch"])
@@ -236,8 +236,8 @@ class CreateAddonListWorker(QtCore.QThread):
repo = Addon(name, url, state, branch)
md_file = os.path.join(addondir, "package.xml")
if os.path.isfile(md_file):
- repo.load_metadata_file(md_file)
- repo.installed_version = repo.metadata.version
+ repo.installed_metadata = MetadataReader.from_file(md_file)
+ repo.installed_version = repo.installed_metadata.version
repo.updated_timestamp = os.path.getmtime(md_file)
repo.verify_url_and_branch(url, branch)
@@ -453,8 +453,6 @@ class LoadPackagesFromCacheWorker(QtCore.QThread):
if os.path.isfile(repo_metadata_cache_path):
try:
repo.load_metadata_file(repo_metadata_cache_path)
- repo.installed_version = repo.metadata.version
- repo.updated_timestamp = os.path.getmtime(repo_metadata_cache_path)
except Exception as e:
FreeCAD.Console.PrintLog(f"Failed loading {repo_metadata_cache_path}\n")
FreeCAD.Console.PrintLog(str(e) + "\n")
@@ -608,15 +606,36 @@ class UpdateChecker:
)
wb.set_status(Addon.Status.CANNOT_CHECK)
+ def _branch_name_changed(self, package: Addon) -> bool:
+ clone_dir = os.path.join(self.moddir, package.name)
+ installed_metadata_file = os.path.join(clone_dir, "package.xml")
+ if not os.path.isfile(installed_metadata_file):
+ return False
+ try:
+ installed_metadata = MetadataReader.from_file(installed_metadata_file)
+ installed_default_branch = get_branch_from_metadata(installed_metadata)
+ remote_default_branch = get_branch_from_metadata(package.metadata)
+ if installed_default_branch != remote_default_branch:
+ return True
+ except Exception:
+ return False
+ return False
+
def check_package(self, package: Addon) -> None:
"""Given a packaged Addon package, check it for updates. If git is available that is
used. If not, the package's metadata is examined, and if the metadata file has changed
- compared to the installed copy, an update is flagged."""
+ compared to the installed copy, an update is flagged. In addition, a change to the
+ default branch name triggers an update."""
- clonedir = self.moddir + os.sep + package.name
- if os.path.exists(clonedir):
+ clone_dir = self.moddir + os.sep + package.name
+ if os.path.exists(clone_dir):
- # First, try to just do a git-based update, which will give the most accurate results:
+ # First, see if the branch name changed, which automatically triggers an update
+ if self._branch_name_changed(package):
+ package.set_status(Addon.Status.UPDATE_AVAILABLE)
+ return
+
+ # Next, try to just do a git-based update, which will give the most accurate results:
if self.git_manager:
self.check_workbench(package)
if package.status() != Addon.Status.CANNOT_CHECK:
@@ -624,7 +643,7 @@ class UpdateChecker:
return
# If we were unable to do a git-based update, try using the package.xml file instead:
- installed_metadata_file = os.path.join(clonedir, "package.xml")
+ installed_metadata_file = os.path.join(clone_dir, "package.xml")
if not os.path.isfile(installed_metadata_file):
# If there is no package.xml file, then it's because the package author added it
# after the last time the local installation was updated. By definition, then,
@@ -852,6 +871,8 @@ class CacheMacroCodeWorker(QtCore.QThread):
)
with self.lock:
self.failed.append(macro_name)
+ self.repo_queue.task_done()
+ self.counter += 1
class GetMacroDetailsWorker(QtCore.QThread):
diff --git a/src/Mod/AddonManager/manage_python_dependencies.py b/src/Mod/AddonManager/manage_python_dependencies.py
index 4b42cd9298..ccfceddb57 100644
--- a/src/Mod/AddonManager/manage_python_dependencies.py
+++ b/src/Mod/AddonManager/manage_python_dependencies.py
@@ -415,7 +415,6 @@ class PythonPackageManager:
pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Addons")
known_python_versions_string = pref.GetString("KnownPythonVersions", "[]")
known_python_versions = json.loads(known_python_versions_string)
- print(json.dumps(known_python_versions, indent=4))
return known_python_versions
@classmethod
diff --git a/src/Mod/AddonManager/package_details.py b/src/Mod/AddonManager/package_details.py
index 62f8cb665d..b66100ba82 100644
--- a/src/Mod/AddonManager/package_details.py
+++ b/src/Mod/AddonManager/package_details.py
@@ -31,10 +31,14 @@ from PySide import QtCore, QtGui, QtWidgets
import addonmanager_freecad_interface as fci
import addonmanager_utilities as utils
-from addonmanager_metadata import Version, UrlType, get_first_supported_freecad_version
+from addonmanager_metadata import (
+ Version,
+ get_first_supported_freecad_version,
+ get_branch_from_metadata,
+)
from addonmanager_workers_startup import GetMacroDetailsWorker, CheckSingleUpdateWorker
from addonmanager_readme_viewer import ReadmeViewer
-from addonmanager_git import GitManager, NoGitFound, GitFailed
+from addonmanager_git import GitManager, NoGitFound
from Addon import Addon
from change_branch import ChangeBranchDialog
@@ -150,16 +154,30 @@ class PackageDetails(QtWidgets.QWidget):
if status == Addon.Status.UPDATE_AVAILABLE:
if repo.metadata:
- installed_version_string += (
- ""
- + translate(
- "AddonsInstaller",
- "On branch {}, update available to version",
- ).format(repo.branch)
- + " "
- )
- installed_version_string += str(repo.metadata.version)
- installed_version_string += "."
+ name_change = False
+ if repo.installed_metadata:
+ old_branch = get_branch_from_metadata(repo.installed_metadata)
+ new_branch = get_branch_from_metadata(repo.metadata)
+ if old_branch != new_branch:
+ installed_version_string += (
+ ""
+ + translate(
+ "AddonsInstaller",
+ "Currently on branch {}, name changed to {}",
+ ).format(old_branch, new_branch)
+ ) + ". "
+ name_change = True
+ if not name_change:
+ installed_version_string += (
+ ""
+ + translate(
+ "AddonsInstaller",
+ "On branch {}, update available to version",
+ ).format(repo.branch)
+ + " "
+ )
+ installed_version_string += str(repo.metadata.version)
+ installed_version_string += "."
elif repo.macro and repo.macro.version:
installed_version_string += (
"" + translate("AddonsInstaller", "Update available to version") + " "
@@ -364,7 +382,6 @@ class PackageDetails(QtWidgets.QWidget):
# If all four above checks passed, then it's possible for us to switch
# branches, if there are any besides the one we are on: show the button
- print("Showing the button")
self.ui.buttonChangeBranch.show()
def set_disable_button_state(self):
diff --git a/src/Mod/AddonManager/package_list.py b/src/Mod/AddonManager/package_list.py
index d26b4f5489..f6676feaa5 100644
--- a/src/Mod/AddonManager/package_list.py
+++ b/src/Mod/AddonManager/package_list.py
@@ -454,11 +454,14 @@ class PackageListItemDelegate(QtWidgets.QStyledItemDelegate):
installed_version_string = ""
if repo.status() != Addon.Status.NOT_INSTALLED:
- if repo.installed_version:
+ if repo.installed_version or repo.installed_metadata:
installed_version_string = (
"
" + translate("AddonsInstaller", "Installed version") + ": "
)
- installed_version_string += str(repo.installed_version)
+ if repo.installed_metadata:
+ installed_version_string += str(repo.installed_metadata.version)
+ elif repo.installed_version:
+ installed_version_string += str(repo.installed_version)
else:
installed_version_string = "
" + translate("AddonsInstaller", "Unknown version")