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