Hello community, here is the log from the commit of package lcurse for openSUSE:Factory checked in at 2017-02-02 15:41:04 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/lcurse (Old) and /work/SRC/openSUSE:Factory/.lcurse.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "lcurse" Changes: -------- --- /work/SRC/openSUSE:Factory/lcurse/lcurse.changes 2017-01-25 23:17:10.406532440 +0100 +++ /work/SRC/openSUSE:Factory/.lcurse.new/lcurse.changes 2017-02-03 17:46:53.702621616 +0100 @@ -1,0 +2,25 @@ +Tue Jan 10 05:07:42 UTC 2017 - [email protected] + +- Update to version 0.1.3: + * quote urls before try to open it. fixes problems with urls with whitespaces in it. e.g. Recount + * General cleanups. No code logic changes intended. + * Fix NameError from commit ddb630a + * Curse layout has changed, update selector. + * Avoid BeautifulSoup warning. + * Fix quoting issues for issue #47. + +------------------------------------------------------------------- +Thu Oct 20 20:25:08 UTC 2016 - [email protected] + +- Update to version 0.1.2: + * added force update of addon functionality + +------------------------------------------------------------------- +Fri Oct 14 02:46:40 UTC 2016 - [email protected] + +- Update to version 0.1.1: + * Add lcurse.desktop file for packaging use. + * Remove extraneous percent signs from progress text. +- Removed package desktop file since accepted upstream. + +------------------------------------------------------------------- Old: ---- lcurse-0.1.0.tar.xz lcurse.desktop New: ---- lcurse-0.1.3.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ lcurse.spec ++++++ --- /var/tmp/diff_new_pack.1eXrEf/_old 2017-02-03 17:46:54.050572366 +0100 +++ /var/tmp/diff_new_pack.1eXrEf/_new 2017-02-03 17:46:54.050572366 +0100 @@ -17,14 +17,13 @@ Name: lcurse -Version: 0.1.0 +Version: 0.1.3 Release: 0 Summary: Python script to have a "curse" compatible client for linux License: Unlicense Group: Amusements/Games/Other Url: https://github.com/ephraim/lcurse Source0: %{name}-%{version}.tar.xz -Source1: %{name}.desktop BuildRequires: hicolor-icon-theme BuildRequires: update-desktop-files Requires: python3-beautifulsoup4 @@ -46,7 +45,7 @@ %install # install desktop file and icon -install -D -m 0644 %{SOURCE1} %{buildroot}%{_datadir}/applications/%{name}.desktop +install -D -m 0644 media/lcurse.desktop %{buildroot}%{_datadir}/applications/%{name}.desktop install -D -m 0644 media/icon.png %{buildroot}%{_datadir}/pixmaps/%{name}.png %suse_update_desktop_file %{buildroot}%{_datadir}/applications/%{name}.desktop ++++++ _service ++++++ --- /var/tmp/diff_new_pack.1eXrEf/_old 2017-02-03 17:46:54.082567837 +0100 +++ /var/tmp/diff_new_pack.1eXrEf/_new 2017-02-03 17:46:54.086567271 +0100 @@ -1,7 +1,7 @@ <services> <service name="tar_scm" mode="disabled"> - <param name="versionformat">0.1.0</param> - <param name="revision">9cc9bfb138bd8816863e7fc700296f01f2468c14</param> + <param name="versionformat">0.1.3</param> + <param name="revision">e5248cad9eb6860a776a5104169ac9331a0ea90e</param> <param name="url">https://github.com/ephraim/lcurse.git</param> <param name="scm">git</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.1eXrEf/_old 2017-02-03 17:46:54.098565572 +0100 +++ /var/tmp/diff_new_pack.1eXrEf/_new 2017-02-03 17:46:54.102565006 +0100 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/ephraim/lcurse.git</param> - <param name="changesrevision">a810d66da2e2ff02e9428168ed504901e6cb759c</param> + <param name="changesrevision">a5fb9e21c274ed3245a4344715e7daa5942c19c1</param> </service> </servicedata> ++++++ lcurse-0.1.0.tar.xz -> lcurse-0.1.3.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lcurse-0.1.0/media/lcurse.desktop new/lcurse-0.1.3/media/lcurse.desktop --- old/lcurse-0.1.0/media/lcurse.desktop 1970-01-01 01:00:00.000000000 +0100 +++ new/lcurse-0.1.3/media/lcurse.desktop 2017-01-08 13:34:35.000000000 +0100 @@ -0,0 +1,9 @@ +#!/usr/bin/env xdg-open +[Desktop Entry] +Name=lcurse +GenericName=WoW Addon Manager +Comment=Python script to have a "curse" compatible client for linux +Exec=lcurse %u +Type=Application +Icon=lcurse +Categories=Game;RolePlaying; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lcurse-0.1.0/modules/addaddondlg.py new/lcurse-0.1.3/modules/addaddondlg.py --- old/lcurse-0.1.0/modules/addaddondlg.py 2016-08-23 20:48:12.000000000 +0200 +++ new/lcurse-0.1.3/modules/addaddondlg.py 2017-01-08 13:34:35.000000000 +0100 @@ -13,7 +13,7 @@ btnBox.rejected.connect(self.reject) box.addWidget(btnBox) self.show() - if len(availableAddons) > 0: + if availableAddons: self.completer = Qt.QCompleter([addon[0] for addon in availableAddons], self) self.completer.setFilterMode(Qt.Qt.MatchContains) self.completer.setCaseSensitivity(Qt.Qt.CaseInsensitive) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lcurse-0.1.0/modules/application.py new/lcurse-0.1.3/modules/application.py --- old/lcurse-0.1.0/modules/application.py 2016-08-23 20:48:12.000000000 +0200 +++ new/lcurse-0.1.3/modules/application.py 2017-01-08 13:34:35.000000000 +0100 @@ -6,8 +6,8 @@ import os import re from shutil import rmtree -from urllib.parse import urlparse import urllib +from urllib.parse import urlparse, quote as urlquote from urllib.request import build_opener, HTTPCookieProcessor, HTTPError from http import cookiejar from bs4 import BeautifulSoup @@ -108,6 +108,11 @@ actionRemove.setStatusTip(self.tr("Remove currently selected addon")) actionRemove.triggered.connect(self.removeAddon) + actionForceUpdate = Qt.QAction(self.tr("Force update addon"), self) + actionForceUpdate.setShortcut("Ctrl+F") + actionForceUpdate.setStatusTip(self.tr("Force update of currently selected addon")) + actionForceUpdate.triggered.connect(self.forceUpdateAddon) + menuAddons = menubar.addMenu(self.tr("Addons")) menuAddons.addAction(actionCheckAll) menuAddons.addAction(actionCheck) @@ -117,6 +122,7 @@ menuAddons.addSeparator() menuAddons.addAction(actionAdd) menuAddons.addAction(actionRemove) + menuAddons.addAction(actionForceUpdate) toolbar = self.addToolBar(self.tr("Addons")) toolbar.addAction(actionUpdateAll) toolbar.addAction(actionAdd) @@ -124,6 +130,7 @@ self.addAction(actionCheck) self.addAction(actionUpdateAll) self.addAction(actionUpdate) + self.addAction(actionForceUpdate) actionCatalogUpdate = Qt.QAction(self.tr("Update Catalog"), self) actionCatalogUpdate.setStatusTip(self.tr("Retrieve a list of available addons")) @@ -189,29 +196,29 @@ while line != "": line = line.strip() m = curse_title_re.match(line) - if m != None: + if m: name = m.group(1) line = f.readline() continue if name == "": m = title_re.match(line) - if m != None: + if m: name = m.group(1) line = f.readline() continue m = curse_version_re.match(line) - if m != None: + if m: version = m.group(1) line = f.readline() continue if version == "": m = version_re.match(line) - if m != None: + if m: version = m.group(1) line = f.readline() continue m = curse_re.match(line) - if m != None: + if m: curseId = m.group(1) line = f.readline() continue @@ -221,10 +228,10 @@ curseId = self.removeStupidStuff(curseId) uri = "http://mods.curse.com/addons/wow/{}".format(name.lower().replace(" ", "-")) - if curseId != "": + if curseId: uri = "http://mods.curse.com/addons/wow/{}".format(curseId) - if name == "" or version == "": + if not name or not version: print("not enough informations found for addon in toc: {}".format(toc)) return ["", "", ""] @@ -244,7 +251,7 @@ continue (name, uri, version) = tmp row = self.addonList.rowCount() - if len(self.addonList.findItems(name, Qt.Qt.MatchExactly)) == 0: + if not self.addonList.findItems(name, Qt.Qt.MatchExactly): self.addonList.setRowCount(row + 1) self.insertAddon(row, name, uri, version, False) self.addonList.resizeColumnsToContents() @@ -273,20 +280,19 @@ if os.path.exists(self.addonsFile): with open(self.addonsFile) as f: addons = json.load(f) - if addons != None: - self.addonList.setRowCount(len(addons)) - for (row, addon) in enumerate(addons): - self.addonList.setItem(row, 0, Qt.QTableWidgetItem(addon["name"])) - self.addonList.setItem(row, 1, Qt.QTableWidgetItem(addon["uri"])) - self.addonList.setItem(row, 2, Qt.QTableWidgetItem(addon["version"])) - allowBeta = False - if "allowbeta" in addon: - allowBeta = addon["allowbeta"] - allowBetaItem = Qt.QTableWidgetItem() - allowBetaItem.setCheckState(Qt.Qt.Checked if allowBeta else Qt.Qt.Unchecked) - self.addonList.setItem(row, 3, allowBetaItem) - self.addonList.resizeColumnsToContents() - self.adjustSize() + if not addons: + return + self.addonList.setRowCount(len(addons)) + for (row, addon) in enumerate(addons): + self.addonList.setItem(row, 0, Qt.QTableWidgetItem(addon["name"])) + self.addonList.setItem(row, 1, Qt.QTableWidgetItem(addon["uri"])) + self.addonList.setItem(row, 2, Qt.QTableWidgetItem(addon["version"])) + allowBeta = addon.get("allowbeta", False) + allowBetaItem = Qt.QTableWidgetItem() + allowBetaItem.setCheckState(Qt.Qt.Checked if allowBeta else Qt.Qt.Unchecked) + self.addonList.setItem(row, 3, allowBetaItem) + self.addonList.resizeColumnsToContents() + self.adjustSize() def saveAddons(self): addons = [] @@ -305,42 +311,47 @@ def addAddon(self): addAddonDlg = addaddondlg.AddAddonDlg(self, self.availableAddons) result = addAddonDlg.exec_() - if result == Qt.QDialog.Accepted: - name = "" - nameOrUrl = addAddonDlg.getText() - pieces = urlparse(nameOrUrl) - if pieces.scheme != "" or pieces.netloc != "": - url = str(nameOrUrl) - if "curse.com" in url: + if result != Qt.QDialog.Accepted: + return + name = "" + nameOrUrl = addAddonDlg.getText() + pieces = urlparse(nameOrUrl) + if pieces.scheme or pieces.netloc: + url = str(nameOrUrl) + if "curse.com" in url: + try: + print("retrieving addon informations") + response = opener.open(urlparse(urlquote(url, ':/')).geturl()) + soup = BeautifulSoup(response.read(), "lxml") try: - print("retrieving addon informations") - response = opener.open(url) - soup = BeautifulSoup(response.read()) - captions = soup.select(".caption span span span") + captions = soup.select("#project-overview header h2") name = captions[0].string - except HTTPError as e: - print(e) - elif url.endswith(".git"): - name = os.path.basename(url)[:-4] - else: - name = nameOrUrl - try: - for item in self.availableAddons: - if item[0] == name: - url = item[1] - except IndexError: - print("can't handle: " + name) - name = "" - - if name != "": - newrow = self.addonList.rowCount() - self.addonList.insertRow(newrow) - self.addonList.setItem(newrow, 0, Qt.QTableWidgetItem(name)) - self.addonList.setItem(newrow, 1, Qt.QTableWidgetItem(url)) - self.addonList.setItem(newrow, 2, Qt.QTableWidgetItem("")) - allowBetaItem = Qt.QTableWidgetItem() - allowBetaItem.setCheckState(Qt.Qt.Unchecked) - self.addonList.setItem(newrow, 3, allowBetaItem) + except: + print("Curse.com layout has changed.") + pass + except HTTPError as e: + print(e) + elif url.endswith(".git"): + name = os.path.basename(url)[:-4] + else: + name = nameOrUrl + try: + for item in self.availableAddons: + if item[0] == name: + url = item[1] + except IndexError: + print("can't handle: " + name) + name = "" + + if name: + newrow = self.addonList.rowCount() + self.addonList.insertRow(newrow) + self.addonList.setItem(newrow, 0, Qt.QTableWidgetItem(name)) + self.addonList.setItem(newrow, 1, Qt.QTableWidgetItem(url)) + self.addonList.setItem(newrow, 2, Qt.QTableWidgetItem("")) + allowBetaItem = Qt.QTableWidgetItem() + allowBetaItem.setCheckState(Qt.Qt.Unchecked) + self.addonList.setItem(newrow, 3, allowBetaItem) def removeAddon(self): row = self.addonList.currentRow() @@ -349,64 +360,65 @@ str(self.tr("Do you really want to remove the following addon?\n{}")).format( str(self.addonList.item(row, 0).text())), Qt.QMessageBox.Yes, Qt.QMessageBox.No) - if answer == Qt.QMessageBox.Yes: - settings = Qt.QSettings() - parent = "{}/Interface/AddOns".format(str(settings.value(defines.WOW_FOLDER_KEY, defines.WOW_FOLDER_DEFAULT))) - contents = os.listdir(parent) - addonName = str(self.addonList.item(row, 0).text()) - deleted = False - deleted_addons = [] - potential_deletions = [] + if answer != Qt.QMessageBox.Yes: + return + settings = Qt.QSettings() + parent = "{}/Interface/AddOns".format(str(settings.value(defines.WOW_FOLDER_KEY, defines.WOW_FOLDER_DEFAULT))) + contents = os.listdir(parent) + addonName = str(self.addonList.item(row, 0).text()) + deleted = False + deleted_addons = [] + potential_deletions = [] + for item in contents: + itemDir = "{}/{}".format(parent, item) + if os.path.isdir(itemDir) and not item.lower().startswith("blizzard_"): + toc = "{}/{}.toc".format(itemDir, item) + if os.path.exists(toc): + tmp = self.extractAddonMetadataFromTOC(toc) + if tmp[0] == addonName: + rmtree(itemDir) + deleted_addons.append(item) + deleted = True + + self.addonList.removeRow(row) + + if not deleted: + Qt.QMessageBox.question(self, "No addons removed", + str(self.tr("No addons matching \"{}\" found.\nThe addon might already be removed, or could be going under a different name.\nManual deletion may be required.")).format(addonName), + Qt.QMessageBox.Ok) + else: + potential = False for item in contents: itemDir = "{}/{}".format(parent, item) if os.path.isdir(itemDir) and not item.lower().startswith("blizzard_"): toc = "{}/{}.toc".format(itemDir, item) if os.path.exists(toc): tmp = self.extractAddonMetadataFromTOC(toc) - if tmp[0] == addonName: - rmtree(itemDir) - deleted_addons.append(item) - deleted = True - - self.addonList.removeRow(row) - - if not deleted: - Qt.QMessageBox.question(self, "No addons removed", - str(self.tr("No addons matching \"{}\" found.\nThe addon might already be removed, or could be going under a different name.\nManual deletion may be required.")).format(addonName), - Qt.QMessageBox.Ok) - else: - potential = False - for item in contents: - itemDir = "{}/{}".format(parent, item) - if os.path.isdir(itemDir) and not item.lower().startswith("blizzard_"): - toc = "{}/{}.toc".format(itemDir, item) - if os.path.exists(toc): - tmp = self.extractAddonMetadataFromTOC(toc) - for d in deleted_addons: - deletions = list(filter(None, re.split("[_, \-!?:]+", d))) - for word in deletions: - if re.search(word, tmp[0]) != None: - potential_deletions.append(item) - potential = True - break - if potential: + for d in deleted_addons: + deletions = list(filter(None, re.split("[_, \-!?:]+", d))) + for word in deletions: + if re.search(word, tmp[0]): + potential_deletions.append(item) + potential = True break - if potential: - to_delete = '\n'.join(potential_deletions) - removal = Qt.QMessageBox.question(self, "Potential deletion candidates found", - str(self.tr("Remove the following addons as well?\n{}")).format(to_delete), - Qt.QMessageBox.Yes, Qt.QMessageBox.No) - if removal == Qt.QMessageBox.Yes: - for p in potential_deletions: - all_rows = self.addonList.rowCount() - for n in range(0, all_rows): - name = str(self.addonList.item(n, 0).text()) - if p == name: - self.addonList.removeRow(n) - break - rmtree("{}/{}".format(parent, p)) + if potential: + break + if potential: + to_delete = '\n'.join(potential_deletions) + removal = Qt.QMessageBox.question(self, "Potential deletion candidates found", + str(self.tr("Remove the following addons as well?\n{}")).format(to_delete), + Qt.QMessageBox.Yes, Qt.QMessageBox.No) + if removal == Qt.QMessageBox.Yes: + for p in potential_deletions: + all_rows = self.addonList.rowCount() + for n in range(0, all_rows): + name = str(self.addonList.item(n, 0).text()) + if p == name: + self.addonList.removeRow(n) + break + rmtree("{}/{}".format(parent, p)) - self.saveAddons() + self.saveAddons() def setRowColor(self, row, color): self.addonList.item(row, 0).setBackground(color) @@ -417,7 +429,7 @@ if result: self.setRowColor(addon[0], Qt.Qt.yellow) self.addonList.item(addon[0], 0).setData(Qt.Qt.UserRole, data) - elif data == None: + elif data is None: self.setRowColor(addon[0], Qt.Qt.red) else: self.setRowColor(addon[0], Qt.Qt.white) @@ -455,15 +467,21 @@ self.addonList.item(addon[0], 0).setData(Qt.Qt.UserRole, None) self.setRowColor(addon[0], Qt.Qt.green) + def forceUpdateAddon(self): + row = self.addonList.currentRow() + print("enforcing update of {:s}".format(self.addonList.item(row, 0).text())) + self.addonList.item(row, 2).setText("") + self.updateAddon() + def updateAddon(self): row = self.addonList.currentRow() addons = [] data = self.addonList.item(row, 0).data(Qt.Qt.UserRole) - if data == None: + if not data: self.checkAddonForUpdate() data = self.addonList.item(row, 0).data(Qt.Qt.UserRole) - if data == None: + if not data: return name = self.addonList.item(row, 0).text() @@ -472,7 +490,7 @@ allowBeta = bool(self.addonList.item(row, 3).checkState() == Qt.Qt.Checked) addons.append((row, name, uri, version, allowBeta, data)) - if len(addons): + if addons: updateDlg = waitdlg.UpdateDlg(self, addons) updateDlg.updateFinished.connect(self.onUpdateFinished) updateDlg.exec_() @@ -490,7 +508,7 @@ allowBeta = bool(self.addonList.item(row, 3).checkState() == Qt.Qt.Checked) addons.append((row, name, uri, version, allowBeta, data)) - if len(addons): + if addons: updateDlg = waitdlg.UpdateDlg(self, addons) updateDlg.updateFinished.connect(self.onUpdateFinished) updateDlg.exec_() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lcurse-0.1.0/modules/preferences.py new/lcurse-0.1.3/modules/preferences.py --- old/lcurse-0.1.0/modules/preferences.py 2016-08-23 20:48:12.000000000 +0200 +++ new/lcurse-0.1.3/modules/preferences.py 2017-01-08 13:34:35.000000000 +0100 @@ -45,9 +45,9 @@ Qt.QFileDialog.ShowDirsOnly | Qt.QFileDialog.DontResolveSymlinks) - if selectedDir != "": - dir = Qt.QDir("{}/Interface/AddOns".format(selectedDir)) - if dir.exists(): + if selectedDir: + directory = Qt.QDir("{}/Interface/AddOns".format(selectedDir)) + if directory.exists(): self.wowInstallFolder.setText(selectedDir) else: Qt.QMessageBox.warning(self, self.tr("Not Wow-Folder"), self.tr( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lcurse-0.1.0/modules/waitdlg.py new/lcurse-0.1.3/modules/waitdlg.py --- old/lcurse-0.1.0/modules/waitdlg.py 2016-08-23 20:48:12.000000000 +0200 +++ new/lcurse-0.1.3/modules/waitdlg.py 2017-01-08 13:34:35.000000000 +0100 @@ -1,5 +1,6 @@ from PyQt5 import Qt from bs4 import BeautifulSoup +import urllib.parse from urllib.request import build_opener, HTTPCookieProcessor, HTTPError from http import cookiejar import zipfile @@ -24,7 +25,7 @@ # Retry 5 times while count < maxcount: try: - response = opener.open(str(url)) + response = opener.open(urllib.parse.urlparse(urllib.parse.quote(url, ':/?=')).geturl()) return response @@ -154,10 +155,10 @@ if self.addon[4]: possibleValues = re.compile("^[12]$") lis = soup.findAll("td", attrs={"data-sort-value": possibleValues}) - if len(lis) > 0: + if lis: versionIdx = 0 version = lis[versionIdx].parent.contents[0].contents[0].string - if len(lis) > 1 and pattern.search(version) != None and pattern.sub("", version) == \ + if len(lis) > 1 and pattern.search(version) and pattern.sub("", version) == \ lis[1].parent.contents[0].contents[0].string: versionIdx = 1 version = lis[versionIdx].parent.contents[0].contents[0].string @@ -180,7 +181,7 @@ elif self.addon[2].endswith(".git"): result = self.needsUpdateGit() - if result != None: + if result: self.checkFinished.emit(self.addon, result[0], result[1]) else: self.checkFinished.emit(self.addon, False, False) @@ -305,7 +306,7 @@ def onProgress(self, foundAddons): value = self.progress.value() + 1 self.progress.setValue(value) - self.progress.setFormat(self.tr("%%p%% - found Addons: {}").format(foundAddons)) + self.progress.setFormat(self.tr("%p% - found Addons: {}").format(foundAddons)) @Qt.pyqtSlot(Qt.QVariant) def onUpdateCatalogFinished(self, addons): @@ -330,11 +331,14 @@ def retrievePartialListOfAddons(self, page): response = OpenWithRetry("http://www.curse.com/addons/wow?page={}".format(page)) soup = BeautifulSoup(response.read(), "lxml") + # Curse returns a soft-500 + if soup.find_all("h2", string="Error"): + print("Server-side error while getting addon list.") lastpage = 1 if page == 1: pager = soup.select("ul.b-pagination-list.paging-list.j-tablesorter-pager.j-listing-pagination li") - if len(pager) > 0: + if pager: lastpage = int(pager[len(pager) - 2].contents[0].contents[0]) links = soup.select("li .title h4 a") # li .title h4 a")
