def test_get_readme_url(self): github_urls = [ "https://github.com/FreeCAD/FreeCAD", ] gitlab_urls = [ "https://gitlab.com/freecad/FreeCAD", "https://framagit.org/freecad/FreeCAD", "https://salsa.debian.org/science-team/freecad", "https://unknown.location/and/path", ] # GitHub and Gitlab have two different schemes for file URLs: unrecognized URLs are # presumed to be local instances of a GitLab server. Note that in neither case does this # take into account the redirects that are used to actually fetch the data. for url in github_urls: branch = "branchname" expected_result = f"{url}/raw/{branch}/README.md" repo = Addon("Test Repo", url, Addon.Status.NOT_INSTALLED, branch) actual_result = get_readme_url(repo) self.assertEqual(actual_result, expected_result) for url in gitlab_urls: branch = "branchname" expected_result = f"{url}/-/raw/{branch}/README.md" repo = Addon("Test Repo", url, Addon.Status.NOT_INSTALLED, branch) actual_result = get_readme_url(repo) self.assertEqual(actual_result, expected_result)
def run(self): self.progressbar_show.emit(True) self.info_label.emit( translate("AddonsInstaller", "Retrieving description...")) if len(self.repos[self.idx]) == 4: desc = self.repos[self.idx][3] else: u = None url = self.repos[self.idx][1] self.info_label.emit( translate("AddonsInstaller", "Retrieving info from") + " " + str(url)) desc = "" regex = utils.get_readme_regex(url) if regex: # extract readme from html via regex readmeurl = utils.get_readme_html_url(url) if not readmeurl: print("Debug: README not found for", url) u = utils.urlopen(readmeurl) if not u: print("Debug: README not found at", readmeurl) u = utils.urlopen(readmeurl) if u: p = u.read() if sys.version_info.major >= 3 and isinstance(p, bytes): p = p.decode("utf-8") u.close() readme = re.findall(regex, p, flags=re.MULTILINE | re.DOTALL) if readme: desc = readme[0] else: print("Debug: README not found at", readmeurl) else: # convert raw markdown using lib readmeurl = utils.get_readme_url(url) if not readmeurl: print("Debug: README not found for", url) u = utils.urlopen(readmeurl) if u: p = u.read() if sys.version_info.major >= 3 and isinstance(p, bytes): p = p.decode("utf-8") u.close() desc = utils.fix_relative_links( p, readmeurl.rsplit("/README.md")[0]) if not NOMARKDOWN and have_markdown: desc = markdown.markdown(desc, extensions=["md_in_html"]) else: message = """ <div style="width: 100%; text-align:center;background: #91bbe0;"> <strong style="color: #FFFFFF;"> """ message += translate("AddonsInstaller", "Raw markdown displayed") message += "</strong><br/><br/>" message += translate( "AddonsInstaller", "Python Markdown library is missing.") message += "<br/></div><hr/><pre>" + desc + "</pre>" desc = message else: print("Debug: README not found at", readmeurl) if desc == "": # fall back to the description text u = utils.urlopen(url) if not u: self.progressbar_show.emit(False) self.stop = True return p = u.read() if sys.version_info.major >= 3 and isinstance(p, bytes): p = p.decode("utf-8") u.close() descregex = utils.get_desc_regex(url) if descregex: desc = re.findall(descregex, p) if desc: desc = desc[0] if not desc: desc = "Unable to retrieve addon description" self.repos[self.idx].append(desc) self.addon_repos.emit(self.repos) # Addon is installed so lets check if it has an update if self.repos[self.idx][2] == 1: upd = False # checking for updates if not NOGIT and have_git: repo = self.repos[self.idx] clonedir = FreeCAD.getUserAppDataDir( ) + os.sep + "Mod" + os.sep + repo[0] if os.path.exists(clonedir): if not os.path.exists(clonedir + os.sep + ".git"): # Repair addon installed with raw download bare_repo = git.Repo.clone_from(repo[1], clonedir + os.sep + ".git", bare=True) try: with bare_repo.config_writer() as cw: cw.set("core", "bare", False) except AttributeError: FreeCAD.Console.PrintWarning( translate( "AddonsInstaller", "Outdated GitPython detected, " "consider upgrading with pip.") + "\n") cw = bare_repo.config_writer() cw.set("core", "bare", False) del cw repo = git.Repo(clonedir) repo.head.reset("--hard") gitrepo = git.Git(clonedir) gitrepo.fetch() if "git pull" in gitrepo.status(): upd = True # If there is an update pending, lets user know via the UI if upd: message = """ <div style="width: 100%;text-align: center;background: #75AFFD;"> <br/> <strong style="background: #397FF7;color: #FFFFFF;"> """ message += translate("AddonsInstaller", "An update is available for this addon.") message += "</strong><br/></div><hr/>" + desc + '<br/><br/>Addon repository: <a href="' message += self.repos[self.idx][1] + '">' + self.repos[ self.idx][1] + "</a>" # mark as already installed AND already checked for updates AND update is available self.repos[self.idx][2] = 3 # If there isn't, indicate that this addon is already installed else: message = """ <div style="width: 100%;text-align: center;background: #C1FEB2;"> <br/> <strong style="background: #00B629;color: #FFFFFF;"> """ message += translate("AddonsInstaller", "This addon is already installed.") message += "</strong><br/></div><hr/>" + desc message += '<br/><br/>Addon repository: <a href="' message += self.repos[self.idx][1] + '">' + self.repos[ self.idx][1] + "</a>" self.repos[self.idx][ 2] = 2 # mark as already installed AND already checked for updates # Let the user know the install path for this addon message += "<br/>" + translate("AddonInstaller", "Installed location") + ": " message += FreeCAD.getUserAppDataDir( ) + os.sep + "Mod" + os.sep + self.repos[self.idx][0] self.addon_repos.emit(self.repos) elif self.repos[self.idx][2] == 2: message = """ <div style="width: 100%;text-align: center;background: #C1FEB2;"> <br/> <strong style="background: #00B629;color: #FFFFFF;"> """ message += translate("AddonsInstaller", "This addon is already installed.") message += "</strong><br></div><hr/>" + desc message += '<br/><br/>Addon repository: <a href="' message += self.repos[self.idx][1] + '">' + self.repos[ self.idx][1] + "</a>" message += "<br/>" + translate("AddonInstaller", "Installed location") + ": " message += FreeCAD.getUserAppDataDir( ) + os.sep + "Mod" + os.sep + self.repos[self.idx][0] elif self.repos[self.idx][2] == 3: message = """ <div style="width: 100%;text-align: center;background: #75AFFD;"> <br/> <strong style="background: #397FF7;color: #FFFFFF;"> """ message += translate("AddonsInstaller", "An update is available for this addon.") message += "</strong><br/></div><hr/>" + desc + '<br/><br/>Addon repository: <a href="' message += self.repos[self.idx][1] + '">' + self.repos[ self.idx][1] + "</a>" message += "<br/>" + translate("AddonInstaller", "Installed location") + ": " message += FreeCAD.getUserAppDataDir( ) + os.sep + "Mod" + os.sep + self.repos[self.idx][0] else: message = desc + '<br/><br/>Addon repository: <a href="' message += self.repos[self.idx][1] + '">' + self.repos[ self.idx][1] + '</a>' # If the Addon is obsolete, let the user know through the Addon UI if self.repos[self.idx][0] in obsolete: message = """ <div style="width: 100%; text-align:center; background: #FFB3B3;"> <strong style="color: #FFFFFF; background: #FF0000;"> """ message += translate( "AddonsInstaller", "This addon is marked as obsolete") + "</strong><br/><br/>" message += translate( "AddonsInstaller", "This usually means it is no longer maintained, " "and some more advanced addon in this list " "provides the same functionality.") + "<br/></div><hr/>" + desc # If the Addon is Python 2 only, let the user know through the Addon UI if self.repos[self.idx][0] in py2only: message = """ <div style="width: 100%; text-align:center; background: #ffe9b3;"> <strong style="color: #FFFFFF; background: #ff8000;"> """ message += translate("AddonsInstaller", "This addon is marked as Python 2 Only" ) + "</strong><br/><br/>" message += translate( "AddonsInstaller", "This workbench may no longer be maintained and " "installing it on a Python 3 system will more than " "likely result in errors at startup or while in use.") message += "<br/></div><hr/>" + desc self.info_label.emit(message) self.progressbar_show.emit(False) self.mustLoadImages = True label = self.loadImages(message, self.repos[self.idx][1], self.repos[self.idx][0]) if label: self.info_label.emit(label) self.stop = True