def run(self):
        current_thread = QtCore.QThread.currentThread()

        for repo in self.repos:
            if 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")
                )
                self.requests[index] = (
                    repo,
                    UpdateMetadataCacheWorker.RequestType.PACKAGE_XML,
                )
                self.total_requests += 1

                # metadata.txt
                index = NetworkManager.AM_NETWORK_MANAGER.submit_unmonitored_get(
                    utils.construct_git_url(repo, "metadata.txt")
                )
                self.requests[index] = (
                    repo,
                    UpdateMetadataCacheWorker.RequestType.METADATA_TXT,
                )
                self.total_requests += 1

                # requirements.txt
                index = NetworkManager.AM_NETWORK_MANAGER.submit_unmonitored_get(
                    utils.construct_git_url(repo, "requirements.txt")
                )
                self.requests[index] = (
                    repo,
                    UpdateMetadataCacheWorker.RequestType.REQUIREMENTS_TXT,
                )
                self.total_requests += 1

        while self.requests:
            if current_thread.isInterruptionRequested():
                NetworkManager.AM_NETWORK_MANAGER.completed.disconnect(
                    self.download_completed
                )
                for request in self.requests.keys():
                    NetworkManager.AM_NETWORK_MANAGER.abort(request)
                return
            # 50 ms maximum between checks for interruption
            QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 50)

        # This set contains one copy of each of the repos that got some kind of data in
        # this process. For those repos, tell the main Addon Manager code that it needs
        # to update its copy of the repo, and redraw its information.
        for repo in self.updated_repos:
            self.package_updated.emit(repo)
Esempio n. 2
0
    def __init__(self, name: str, url: str, status: UpdateStatus, branch: str):
        self.name = name.strip()
        self.display_name = self.name
        self.url = url.strip()
        self.branch = branch.strip()
        self.update_status = status
        self.python2 = False
        self.obsolete = False
        self.rejected = False
        self.repo_type = AddonManagerRepo.RepoType.WORKBENCH
        self.description = None
        from addonmanager_utilities import construct_git_url

        self.metadata_url = ("" if not self.url else construct_git_url(
            self, "package.xml"))
        self.metadata = None
        self.icon = None
        self.cached_icon_filename = ""
        self.macro = None  # Bridge to Gaël Écorchard's macro management class
        self.updated_timestamp = None
        self.installed_version = None

        # Each repo is also a node in a directed dependency graph (referenced by name so
        # they cen be serialized):
        self.requires: Set[str] = set()
        self.blocks: Set[str] = set()

        # And maintains a list of required and optional Python dependencies
        self.python_requires: Set[str] = set()
        self.python_optional: Set[str] = set()
Esempio n. 3
0
    def __init__(self, name: str, url: str, status: Status, branch: str):
        self.name = name.strip()
        self.display_name = self.name
        self.url = url.strip()
        self.branch = branch.strip()
        self.python2 = False
        self.obsolete = False
        self.rejected = False
        self.repo_type = Addon.Kind.WORKBENCH
        self.description = None
        self.tags = set()  # Just a cache, loaded from Metadata

        # To prevent multiple threads from running git actions on this repo at the same time
        self.git_lock = Lock()

        # To prevent multiple threads from accessing the status at the same time
        self.status_lock = Lock()
        self.set_status(status)

        from addonmanager_utilities import construct_git_url

        # The url should never end in ".git", so strip it if it's there
        parsed_url = urlparse(self.url)
        if parsed_url.path.endswith(".git"):
            self.url = (parsed_url.scheme + "://" + parsed_url.netloc +
                        parsed_url.path[:-4])
            if parsed_url.query:
                self.url += "?" + parsed_url.query
            if parsed_url.fragment:
                self.url += "#" + parsed_url.fragment

        if utils.recognized_git_location(self):
            self.metadata_url = construct_git_url(self, "package.xml")
        else:
            self.metadata_url = None
        self.metadata = None
        self.icon = None
        self.cached_icon_filename = ""
        self.macro = None  # Bridge to Gaël Écorchard's macro management class
        self.updated_timestamp = None
        self.installed_version = None

        # Each repo is also a node in a directed dependency graph (referenced by name so
        # they cen be serialized):
        self.requires: Set[str] = set()
        self.blocks: Set[str] = set()

        # And maintains a list of required and optional Python dependencies from metadata.txt
        self.python_requires: Set[str] = set()
        self.python_optional: Set[str] = set()
Esempio n. 4
0
    def __init__(self, name: str, url: str, status: UpdateStatus, branch: str):
        self.name = name.strip()
        self.display_name = self.name
        self.url = url.strip()
        self.branch = branch.strip()
        self.update_status = status
        self.repo_type = AddonManagerRepo.RepoType.WORKBENCH
        self.description = None
        from addonmanager_utilities import construct_git_url

        self.metadata_url = ("" if not self.url else construct_git_url(
            self, "package.xml"))
        self.metadata = None
        self.icon = None
        self.cached_icon_filename = ""
        self.macro = None  # Bridge to Gaël Écorchard's macro management class
        self.updated_timestamp = None
        self.installed_version = None
    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)
        if not os.path.exists(package_cache_directory):
            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.data())
        metadata = FreeCAD.Metadata(new_xml_file)
        self.repo.metadata = metadata
        self.repo.repo_type = AddonManagerRepo.RepoType.PACKAGE
        icon = metadata.Icon

        if not icon:
            # If there is no icon set for the entire package, see if there are
            # any workbenches, which are required to have icons, and grab the first
            # one we find:
            content = self.repo.metadata.Content
            if "workbench" in content:
                wb = content["workbench"][0]
                if wb.Icon:
                    if wb.Subdirectory:
                        subdir = wb.Subdirectory
                    else:
                        subdir = wb.Name
                    self.repo.Icon = subdir + wb.Icon
                    icon = self.repo.Icon

        icon_url = utils.construct_git_url(self.repo, icon)
        icon_stream = utils.urlopen(icon_url)
        if icon and icon_stream and icon_url:
            icon_data = icon_stream.read()
            cache_file = self.repo.get_cached_icon_filename()
            with open(cache_file, "wb") as icon_file:
                icon_file.write(icon_data)
                self.repo.cached_icon_filename = cache_file
        self.updated.emit(self.repo)
    def process_package_xml(self, repo: Addon, data: QtCore.QByteArray):
        """Process the package.xml metadata file"""
        repo.repo_type = Addon.Kind.PACKAGE  # By definition
        package_cache_directory = os.path.join(self.store, repo.name)
        if not os.path.exists(package_cache_directory):
            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(data.data())
        metadata = FreeCAD.Metadata(new_xml_file)
        repo.metadata = metadata
        self.status_message.emit(
            translate("AddonsInstaller", "Downloaded package.xml for {}").format(
                repo.name
            )
        )

        # Grab a new copy of the icon as well: we couldn't enqueue this earlier because
        # we didn't know the path to it, which is stored in the package.xml file.
        icon = metadata.Icon
        if not icon:
            # If there is no icon set for the entire package, see if there are
            # any workbenches, which are required to have icons, and grab the first
            # one we find:
            content = repo.metadata.Content
            if "workbench" in content:
                wb = content["workbench"][0]
                if wb.Icon:
                    if wb.Subdirectory:
                        subdir = wb.Subdirectory
                    else:
                        subdir = wb.Name
                    repo.Icon = subdir + wb.Icon
                    icon = repo.Icon

        icon_url = utils.construct_git_url(repo, icon)
        index = NetworkManager.AM_NETWORK_MANAGER.submit_unmonitored_get(icon_url)
        self.requests[index] = (repo, UpdateMetadataCacheWorker.RequestType.ICON)
        self.total_requests += 1
 def __init__(self, parent, repo: AddonManagerRepo):
     super().__init__(parent, utils.construct_git_url(repo, "metadata.txt"))
     self.repo = repo