def url(self): """ Public method to generate the URL for this subscription. @return AdBlock URL for the subscription (QUrl) """ url = QUrl() url.setScheme("abp") url.setPath("subscribe") queryItems = [] queryItems.append(("location", bytes(self.__location).decode())) queryItems.append(("title", self.__title)) if self.__requiresLocation and self.__requiresTitle: queryItems.append(("requiresLocation", self.__requiresLocation)) queryItems.append(("requiresTitle", self.__requiresTitle)) if not self.__enabled: queryItems.append(("enabled", "false")) if self.__lastUpdate.isValid(): queryItems.append(("lastUpdate", self.__lastUpdate.toString(Qt.ISODate))) if qVersion() >= "5.0.0": from PyQt5.QtCore import QUrlQuery query = QUrlQuery() query.setQueryItems(queryItems) url.setQuery(query) else: url.setQueryItems(queryItems) return url
def blocklist_to_url(filename): """Get an example.com-URL with the given filename as path.""" assert not os.path.isabs(filename), filename url = QUrl('http://example.com/') url.setPath('/' + filename) assert url.isValid(), url.errorString() return url
def blocklist_to_url(path): """Get an example.com-URL with the given filename as path.""" assert not path.is_absolute(), path url = QUrl("http://example.com/") url.setPath("/" + str(path)) assert url.isValid(), url.errorString() return url
def url(self): """ Public method to generate the URL for this subscription. @return AdBlock URL for the subscription (QUrl) """ url = QUrl() url.setScheme("abp") url.setPath("subscribe") queryItems = [] queryItems.append(("location", bytes(self.__location).decode())) queryItems.append(("title", self.__title)) if self.__requiresLocation and self.__requiresTitle: queryItems.append(("requiresLocation", self.__requiresLocation)) queryItems.append(("requiresTitle", self.__requiresTitle)) if not self.__enabled: queryItems.append(("enabled", "false")) if self.__lastUpdate.isValid(): queryItems.append( ("lastUpdate", self.__lastUpdate.toString(Qt.ISODate))) if qVersion() >= "5.0.0": from PyQt5.QtCore import QUrlQuery query = QUrlQuery() query.setQueryItems(queryItems) url.setQuery(query) else: url.setQueryItems(queryItems) return url
def _the_compiler_redir(url: QUrl) -> bool: p = url.path().strip('/') res = re.search(r"\w+$", p) if p.startswith('view/') and res: url.setPath(urljoin("/view/raw/", res.group())) return True return False
def blocklist_to_url(filename): """Get an example.com-URL with the given filename as path.""" assert not os.path.isabs(filename), filename url = QUrl("http://example.com/") url.setPath("/" + filename) assert url.isValid(), url.errorString() return url
def open_help(self): url = QUrl() url.setScheme(DefaultConfig.Help.url_scheme) url.setHost(DefaultConfig.Help.host) url.setPath(DefaultConfig.Help.url_path_pattern) # % str(Version.babel)) QDesktopServices.openUrl(url)
def open_help(self): url = QUrl() url.setScheme(DefaultConfig.Help.url_scheme) url.setHost(DefaultConfig.Help.host) url.setPath( DefaultConfig.Help.url_path_pattern) # % str(Version.babel)) QDesktopServices.openUrl(url)
def open_test_suite(self): """ Open a test suite file and loads the test cases from the suite into the tool. There is a chained process flow when you open a test suite: open_test_suite() calls select_target() select_target then calls load_test_cases() Once a test suite is opened, the user may later choose a new target for the same test suite as teh select_target() method call load_test_cases(). """ self.test_case_data_list = [] url = QUrl() # This File Dialog should start in url.setScheme("file") # the test suites folder by default. url.setPath( "%s/../testsuites" %MY_PATH ) # TODO: os.path.join() options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog file_dialog = QFileDialog() file_dialog.setDirectoryUrl(url) self.testsuite_file, _ = file_dialog.getOpenFileName(self,"QFileDialog.getOpenFileName()", "","All Files (*)", options=options) if self.testsuite_file: self.test_suite_label.setText("Test Suite: %s" %self.testsuite_file.split('/')[LAST]) message = "Loaded Test Suite: %s" %self.testsuite_file logger.info(message) # Crate a list of test cases from the test suite file. However, these # test cases are only file names with not path. We'll have to add the path # based on the target selected. try: f = open(self.testsuite_file, 'r') lines = f.readlines() f.close() self.suite_text_area.clear() for line in lines: line = line.strip() self.suite_text_area.append(line) except: message = "Unalbe to read test cases from test suite %s" %self.testsuite_file logger.error(message) self.suite_text_area.setText(message) lines = [] self.test_case_file_list = [] # a list of test case file names with no paths for line in lines: line = line.strip() if len(line) < 1: pass elif line.startswith('#'): pass else: self.test_case_file_list.append(line) self.test_case_count = len(self.test_case_file_list) message = "Found %d test cases in %s" %(self.test_case_count, self.testsuite_file.split('/')[LAST]) logger.info(message) self.status_bar.showMessage(message) # open the select a test target for this suite self.select_target()
def data_for_url(url): """Get the data to show for the given URL. Args: url: The QUrl to show. Return: A (mimetype, data) tuple. """ norm_url = url.adjusted(QUrl.NormalizePathSegments | QUrl.StripTrailingSlash) if norm_url != url: raise Redirect(norm_url) path = url.path() host = url.host() query = urlutils.query_string(url) # A url like "qute:foo" is split as "scheme:path", not "scheme:host". log.misc.debug("url: {}, path: {}, host {}".format( url.toDisplayString(), path, host)) if not path or not host: new_url = QUrl() new_url.setScheme('qute') # When path is absent, e.g. qute://help (with no trailing slash) if host: new_url.setHost(host) # When host is absent, e.g. qute:help else: new_url.setHost(path) new_url.setPath('/') if query: new_url.setQuery(query) if new_url.host(): # path was a valid host raise Redirect(new_url) try: handler = _HANDLERS[host] except KeyError: raise NoHandlerFound(url) try: mimetype, data = handler(url) except OSError as e: # FIXME:qtwebengine how to handle this? raise QuteSchemeOSError(e) except QuteSchemeError as e: raise assert mimetype is not None, url if mimetype == 'text/html' and isinstance(data, str): # We let handlers return HTML as text data = data.encode('utf-8', errors='xmlcharrefreplace') return mimetype, data
def data_for_url(url): """Get the data to show for the given URL. Args: url: The QUrl to show. Return: A (mimetype, data) tuple. """ norm_url = url.adjusted(QUrl.NormalizePathSegments | QUrl.StripTrailingSlash) if norm_url != url: raise Redirect(norm_url) path = url.path() host = url.host() query = urlutils.query_string(url) # A url like "qute:foo" is split as "scheme:path", not "scheme:host". log.misc.debug("url: {}, path: {}, host {}".format(url.toDisplayString(), path, host)) if not path or not host: new_url = QUrl() new_url.setScheme('qute') # When path is absent, e.g. qute://help (with no trailing slash) if host: new_url.setHost(host) # When host is absent, e.g. qute:help else: new_url.setHost(path) new_url.setPath('/') if query: new_url.setQuery(query) if new_url.host(): # path was a valid host raise Redirect(new_url) try: handler = _HANDLERS[host] except KeyError: raise NoHandlerFound(url) try: mimetype, data = handler(url) except OSError as e: # FIXME:qtwebengine how to handle this? raise QuteSchemeOSError(e) except QuteSchemeError as e: raise assert mimetype is not None, url if mimetype == 'text/html' and isinstance(data, str): # We let handlers return HTML as text data = data.encode('utf-8', errors='xmlcharrefreplace') return mimetype, data
def _resource_url(self, path: str) -> str: """Load qutebrowser resource files. Arguments: path: The relative path to the resource. """ assert not posixpath.isabs(path), path url = QUrl('qute://resource') url.setPath('/' + path) urlutils.ensure_valid(url) urlstr = url.toString(QUrl.FullyEncoded) # type: ignore[arg-type] return urlstr
def data_for_url(url: QUrl): """Get the data to show for the given URL. Args: url: The QUrl to show. Return: A (mimetype, data) tuple. """ norm_url = url.adjusted(QUrl.NormalizePathSegments | QUrl.StripTrailingSlash) if norm_url != url: raise Redirect(norm_url) path = url.path() host = url.host() query = urlutils.query_string(url) # A url like "luminos:foo" is split as "scheme:path", not "scheme:host". if not path or not host: new_url = QUrl() new_url.setScheme("luminos") # When path is absent, e.g. luminos://help (with no trailing slash) if host: new_url.setHost(host) # When host is absent, e.g. luminos:help else: new_url.setHost(path) new_url.setPath("/") if query: new_url.setQuery(query) if new_url.host(): # path was a valid host raise Redirect(new_url) try: handler = _HANDLERS[host] except KeyError: raise NotFoundError("No handler found for {}".format( url.toDisplayString())) try: mimetype, data = handler(url) except OSError as e: raise SchemeOSError(e) assert mimetype is not None, url if mimetype == "text/html" and isinstance(data, str): # We let handlers return HTML as text data = data.encode("utf-8", errors="xmlcharrefreplace") return mimetype, data
def config_diff(self, win_id: int, old: bool = False) -> None: """Show all customized options. Args: old: Show difference for the pre-v1.0 files (qutebrowser.conf/keys.conf). """ url = QUrl('qute://configdiff') if old: url.setPath('/old') tabbed_browser = objreg.get('tabbed-browser', scope='window', window=win_id) tabbed_browser.load_url(url, newtab=False)
def load_url(self, url, tab=None): '''Load the given URL in the specified tab, or current tab if tab=None. url is a str, not a QUrl. PDF URLs will be loaded in a new tab, because there doesn't seem to be a way of replacing the BrowserView with a BrowserPDFView. ''' # If there are newlines, remove newlines plus all adjacent whitespace. if '\n' in url: lines = url.split('\n') url = ''.join([ l.strip() for l in lines ]) # Note that tab=0 is a valid argument here. # When testing whether tab is set, be sure to test for None. if is_pdf(url): self.new_tab(url) return qurl = QUrl(url) if not qurl.scheme(): if os.path.exists(url): qurl.setScheme('file') if not os.path.isabs(url): # Is it better to use posixpath.join or os.path.join? # Both work on Linux. qurl.setPath(os.path.normpath(os.path.join(os.getcwd(), url))) else: qurl.setScheme('http') if len(self.browserviews) == 0: self.new_tab() tab = 0 elif tab == None: tab = self.active_tab self.set_tab_text(url[:self.init_tab_name_len], self.browserviews[tab]) if tab == self.active_tab: self.urlbar.setText(url) self.browserviews[tab].load(qurl)
def load_url(self, url, tab=None): """Load the given URL in the specified tab, or current tab if tab=None. url is a str, not a QUrl. PDF URLs will be loaded in a new tab, because there doesn't seem to be a way of replacing the BrowserView with a BrowserPDFView. """ # If there are newlines, remove newlines plus all adjacent whitespace. if '\n' in url: lines = url.split('\n') url = ''.join([ l.strip() for l in lines ]) # Note that tab=0 is a valid argument here. # When testing whether tab is set, be sure to test for None. if is_pdf(url): self.new_tab(url) return qurl = QUrl(url) if not qurl.scheme(): if os.path.exists(url): qurl.setScheme('file') if not os.path.isabs(url): # Is it better to use posixpath.join or os.path.join? # Both work on Linux. qurl.setPath(os.path.normpath(os.path.join(os.getcwd(), url))) else: qurl.setScheme('http') if len(self.browserviews) == 0: self.new_tab() tab = 0 elif tab is None: tab = self.active_tab self.set_tab_text(url[:self.init_tab_name_len], self.browserviews[tab]) if tab == self.active_tab: self.urlbar.setText(url) self.browserviews[tab].load(qurl)
def resource_url(path, qutescheme=False): """Load images from a relative path (to qutebrowser). Arguments: path: The relative path to the image qutescheme: If the logo needs to be served via a qute:// scheme. This is the case when we want to show an error page from there. """ if qutescheme: url = QUrl() url.setScheme('qute') url.setHost('resource') url.setPath('/' + path) qtutils.ensure_valid(url) return url.toString(QUrl.FullyEncoded) else: full_path = utils.resource_filename(path) return QUrl.fromLocalFile(full_path).toString(QUrl.FullyEncoded)
def data_for_url(url): """Get the data to show for the given URL. Args: url: The QUrl to show. Return: A (mimetype, data) tuple. """ path = url.path() host = url.host() # A url like "qute:foo" is split as "scheme:path", not "scheme:host". log.misc.debug("url: {}, path: {}, host {}".format( url.toDisplayString(), path, host)) if path and not host: new_url = QUrl() new_url.setScheme('qute') new_url.setHost(path) new_url.setPath('/') if new_url.host(): # path was a valid host raise Redirect(new_url) try: handler = _HANDLERS[host] except KeyError: raise NoHandlerFound(url) try: mimetype, data = handler(url) except OSError as e: # FIXME:qtwebengine how to handle this? raise QuteSchemeOSError(e) except QuteSchemeError as e: raise assert mimetype is not None, url if mimetype == 'text/html' and isinstance(data, str): # We let handlers return HTML as text data = data.encode('utf-8', errors='xmlcharrefreplace') return mimetype, data
def url(self, player_id): if self.state == GameState.CLOSED: return None url = QUrl() url.setHost("lobby.faforever.com") query = QUrlQuery() query.addQueryItem("map", self.mapname) query.addQueryItem("mod", self.featured_mod) if self.state == GameState.OPEN: url.setScheme("fafgame") url.setPath("/" + str(player_id)) query.addQueryItem("uid", str(self.uid)) else: url.setScheme("faflive") url.setPath("/" + str(self.uid) + "/" + str(player_id) + ".SCFAreplay") url.setQuery(query) return url
def load_html_from_text(self, text): """ Loads html file by constructing the path using a clicked label. :param text: The label text :type text: String """ self.dynamic_help_box.setHtml('') anchor_text = text.replace(' ', '_').lower().replace('-', '_') file_name = 'help' help_path = '{}/{}.html'.format(STATIC_HELP, file_name) if not os.path.isfile(help_path) and not os.path.isdir(STATIC_HELP): help_path = '{}/{}.html'.format(EN_HELP, file_name) help_url = QUrl() help_url.setPath(help_path) self._help_anchor = anchor_text self._help_text = text # allow JavaScript to run self.dynamic_help_box.page().settings().testAttribute( QWebSettings.JavascriptEnabled) self.dynamic_help_box.load(help_url)
def incdec_number(url, incdec): """Find a number in the url and increment or decrement it. Args: url: The current url incdec: Either 'increment' or 'decrement' Return: The new url with the number incremented/decremented. Raises IncDecError if the url contains no number. """ if not url.isValid(): raise InvalidUrlError(url) path = url.path() # Get the last number in a string match = re.match(r'(.*\D|^)(\d+)(.*)', path) if not match: raise IncDecError("No number found in URL!", url) pre, number, post = match.groups() # This should always succeed because we match \d+ val = int(number) if incdec == 'decrement': if val <= 0: raise IncDecError("Can't decrement {}!".format(val), url) val -= 1 elif incdec == 'increment': val += 1 else: raise ValueError("Invalid value {} for indec!".format(incdec)) new_path = ''.join([pre, str(val), post]) # Make a copy of the QUrl so we don't modify the original new_url = QUrl(url) new_url.setPath(new_path) return new_url
def _debian_redir(url: QUrl) -> bool: p = url.path().strip('/') if p.isdigit(): url.setPath(urljoin("/plain/", p)) return True return False
def _hastebin_redir(url: QUrl) -> bool: p = url.path().strip('/') if "raw" not in p: url.setPath(urljoin("/raw/", p)) return True return False
def _pastebin_redir(url: QUrl) -> bool: p = url.path().strip('/') if p.isalnum(): url.setPath(urljoin("/raw/", p)) return True return False
def start(self, fn, noEntries=0): """ Public slot to start the svn log command. @param fn filename to show the log for (string) @param noEntries number of entries to show (integer) """ self.errorGroup.hide() fetchLimit = 10 QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) QApplication.processEvents() self.filename = fn dname, fname = self.vcs.splitPath(fn) opts = self.vcs.options['global'] + self.vcs.options['log'] verbose = "--verbose" in opts self.activateWindow() self.raise_() locker = QMutexLocker(self.vcs.vcsExecutionMutex) cwd = os.getcwd() os.chdir(dname) try: nextRev = 0 fetched = 0 logs = [] limit = noEntries or 9999999 while fetched < limit: flimit = min(fetchLimit, limit - fetched) if fetched == 0: revstart = pysvn.Revision(pysvn.opt_revision_kind.head) else: revstart = pysvn.Revision( pysvn.opt_revision_kind.number, nextRev) allLogs = self.client.log(fname, revision_start=revstart, discover_changed_paths=verbose, limit=flimit + 1, strict_node_history=False) if len(allLogs) <= flimit or self._clientCancelCallback(): logs.extend(allLogs) break else: logs.extend(allLogs[:-1]) nextRev = allLogs[-1]["revision"].number fetched += fetchLimit locker.unlock() self.contents.clear() self.__pegRev = None for log in logs: ver = "{0:d}".format(log["revision"].number) dstr = '<b>{0} {1}</b>'.format(self.revString, ver) if self.__pegRev is None: self.__pegRev = int(ver) try: lv = "{0:d}".format( logs[logs.index(log) + 1]["revision"].number) url = QUrl() url.setScheme("file") url.setPath(self.filename) query = lv + '_' + ver url.setQuery(query) dstr += ' [<a href="{0}" name="{1}">{2}</a>]'.format( url.toString(), query, self.tr('diff to {0}').format(lv) ) except IndexError: pass dstr += '<br />\n' self.contents.insertHtml(dstr) author = log["author"] message = log["message"] if sys.version_info[0] == 2: author = author.decode('utf-8') message = message.decode('utf-8') dstr = self.tr('<i>author: {0}</i><br />\n')\ .format(author) self.contents.insertHtml(dstr) dstr = self.tr('<i>date: {0}</i><br />\n')\ .format(formatTime(log["date"])) self.contents.insertHtml(dstr) self.contents.insertHtml('<br />\n') for line in message.splitlines(): self.contents.insertHtml(Utilities.html_encode(line)) self.contents.insertHtml('<br />\n') if len(log['changed_paths']) > 0: self.contents.insertHtml('<br />\n') for changeInfo in log['changed_paths']: action = changeInfo["action"] path = changeInfo["path"] if sys.version_info[0] == 2: action = action.decode('utf-8') path = path.decode('utf-8') dstr = '{0} {1}'.format(self.flags[action], path) if changeInfo["copyfrom_path"] is not None: copyfrom_path = changeInfo["copyfrom_path"] if sys.version_info[0] == 2: copyfrom_path = copyfrom_path.decode('utf-8') dstr += self.tr( " (copied from {0}, revision {1})")\ .format(copyfrom_path, changeInfo["copyfrom_revision"].number) dstr += '<br />\n' self.contents.insertHtml(dstr) self.contents.insertHtml('<hr /><br />\n') except pysvn.ClientError as e: locker.unlock() self.__showError(e.args[0]) os.chdir(cwd) self.__finish()
def __procFinished(self, exitCode, exitStatus): """ Private slot connected to the finished signal. @param exitCode exit code of the process (integer) @param exitStatus exit status of the process (QProcess.ExitStatus) """ self.inputGroup.setEnabled(False) self.inputGroup.hide() self.contents.clear() lvers = 1 for s in self.buf: rev_match = False if self.rx_rev.exactMatch(s): ver = self.rx_rev.cap(1) author = self.rx_rev.cap(2) date = self.rx_rev.cap(3) # number of lines is ignored rev_match = True elif self.rx_rev2.exactMatch(s): ver = self.rx_rev2.cap(1) author = self.rx_rev2.cap(2) date = self.rx_rev2.cap(3) # number of lines is ignored rev_match = True if rev_match: dstr = '<b>{0} {1}</b>'.format(self.revString, ver) try: lv = self.revisions[lvers] lvers += 1 url = QUrl() url.setScheme("file") url.setPath(self.filename) if qVersion() >= "5.0.0": query = lv + '_' + ver url.setQuery(query) else: query = QByteArray() query.append(lv).append('_').append(ver) url.setEncodedQuery(query) dstr += ' [<a href="{0}" name="{1}">{2}</a>]'.format( url.toString(), query, self.tr('diff to {0}').format(lv), ) except IndexError: pass dstr += '<br />\n' self.contents.insertHtml(dstr) dstr = self.tr('<i>author: {0}</i><br />\n').format(author) self.contents.insertHtml(dstr) dstr = self.tr('<i>date: {0}</i><br />\n').format(date) self.contents.insertHtml(dstr) elif self.rx_sep.exactMatch(s) or self.rx_sep2.exactMatch(s): self.contents.insertHtml('<hr />\n') elif self.rx_flags.exactMatch(s): dstr = self.flags[self.rx_flags.cap(1)] dstr += self.rx_flags.cap(2) dstr += '<br />\n' self.contents.insertHtml(dstr) elif self.rx_changed.exactMatch(s): dstr = '<br />{0}<br />\n'.format(s) self.contents.insertHtml(dstr) else: if s == "": s = self.contents.insertHtml('<br />\n') else: self.contents.insertHtml(Utilities.html_encode(s)) self.contents.insertHtml('<br />\n') tc = self.contents.textCursor() tc.movePosition(QTextCursor.Start) self.contents.setTextCursor(tc) self.contents.ensureCursorVisible()
def subUrl(self, path): """ Joins the gatewayUrl and path to form a new URL """ sub = QUrl(str(self.gatewayUrl)) sub.setPath(path) return sub
def __finish(self): """ Private slot called when the process finished or the user pressed the button. """ self.inputGroup.setEnabled(False) self.inputGroup.hide() self.contents.clear() if not self.logEntries: self.errors.append( self.tr("No log available for '{0}'").format(self.filename)) self.errorGroup.show() return html = "" if self.initialText: for line in self.initialText: html += Utilities.html_encode(line.strip()) html += '<br />\n' html += '{0}<br/>\n'.format(80 * "=") for entry in self.logEntries: fileCopies = {} if entry["file_copies"]: for fentry in entry["file_copies"].split(", "): newName, oldName = fentry[:-1].split(" (") fileCopies[newName] = oldName rev, hexRev = entry["change"].split(":") dstr = '<p><b>{0} {1}</b>'.format(self.revString, entry["change"]) if entry["parents"]: parents = entry["parents"].split() else: parents = self.__getParents(rev) for parent in parents: url = QUrl() url.setScheme("file") url.setPath(self.filename) if qVersion() >= "5.0.0": query = parent.split(":")[0] + '_' + rev url.setQuery(query) else: query = QByteArray() query.append(parent.split(":")[0]).append('_').append(rev) url.setEncodedQuery(query) dstr += ' [<a href="{0}" name="{1}" id="{1}">{2}</a>]'.format( url.toString(), query, self.tr('diff to {0}').format(parent), ) dstr += '<br />\n' html += dstr if "phase" in entry: html += self.tr("Phase: {0}<br />\n")\ .format(entry["phase"]) html += self.tr("Branch: {0}<br />\n")\ .format(entry["branches"]) html += self.tr("Tags: {0}<br />\n").format(entry["tags"]) if "bookmarks" in entry: html += self.tr("Bookmarks: {0}<br />\n")\ .format(entry["bookmarks"]) html += self.tr("Parents: {0}<br />\n")\ .format(entry["parents"]) html += self.tr('<i>Author: {0}</i><br />\n')\ .format(Utilities.html_encode(entry["user"])) date, time = entry["date"].split()[:2] html += self.tr('<i>Date: {0}, {1}</i><br />\n')\ .format(date, time) for line in entry["description"]: html += Utilities.html_encode(line.strip()) html += '<br />\n' if entry["file_adds"]: html += '<br />\n' for f in entry["file_adds"].strip().split(", "): if f in fileCopies: html += self.tr( 'Added {0} (copied from {1})<br />\n')\ .format(Utilities.html_encode(f), Utilities.html_encode(fileCopies[f])) else: html += self.tr('Added {0}<br />\n')\ .format(Utilities.html_encode(f)) if entry["files_mods"]: html += '<br />\n' for f in entry["files_mods"].strip().split(", "): html += self.tr('Modified {0}<br />\n')\ .format(Utilities.html_encode(f)) if entry["file_dels"]: html += '<br />\n' for f in entry["file_dels"].strip().split(", "): html += self.tr('Deleted {0}<br />\n')\ .format(Utilities.html_encode(f)) html += '</p>{0}<br/>\n'.format(60 * "=") self.contents.setHtml(html) tc = self.contents.textCursor() tc.movePosition(QTextCursor.Start) self.contents.setTextCursor(tc) self.contents.ensureCursorVisible()
def start(self, fn, noEntries=0): """ Public slot to start the svn log command. @param fn filename to show the log for (string) @param noEntries number of entries to show (integer) """ self.errorGroup.hide() fetchLimit = 10 QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) QApplication.processEvents() self.filename = fn dname, fname = self.vcs.splitPath(fn) opts = self.vcs.options["global"] + self.vcs.options["log"] verbose = "--verbose" in opts self.activateWindow() self.raise_() locker = QMutexLocker(self.vcs.vcsExecutionMutex) cwd = os.getcwd() os.chdir(dname) try: nextRev = 0 fetched = 0 logs = [] limit = noEntries or 9999999 while fetched < limit: flimit = min(fetchLimit, limit - fetched) if fetched == 0: revstart = pysvn.Revision(pysvn.opt_revision_kind.head) else: revstart = pysvn.Revision(pysvn.opt_revision_kind.number, nextRev) allLogs = self.client.log( fname, revision_start=revstart, discover_changed_paths=verbose, limit=flimit + 1, strict_node_history=False, ) if len(allLogs) <= flimit or self._clientCancelCallback(): logs.extend(allLogs) break else: logs.extend(allLogs[:-1]) nextRev = allLogs[-1]["revision"].number fetched += fetchLimit locker.unlock() self.contents.clear() self.__pegRev = None for log in logs: ver = "{0:d}".format(log["revision"].number) dstr = "<b>{0} {1}</b>".format(self.revString, ver) if self.__pegRev is None: self.__pegRev = int(ver) try: lv = "{0:d}".format(logs[logs.index(log) + 1]["revision"].number) url = QUrl() url.setScheme("file") url.setPath(self.filename) query = lv + "_" + ver url.setQuery(query) dstr += ' [<a href="{0}" name="{1}">{2}</a>]'.format( url.toString(), query, self.tr("diff to {0}").format(lv) ) except IndexError: pass dstr += "<br />\n" self.contents.insertHtml(dstr) author = log["author"] message = log["message"] if sys.version_info[0] == 2: author = author.decode("utf-8") message = message.decode("utf-8") dstr = self.tr("<i>author: {0}</i><br />\n").format(author) self.contents.insertHtml(dstr) dstr = self.tr("<i>date: {0}</i><br />\n").format(formatTime(log["date"])) self.contents.insertHtml(dstr) self.contents.insertHtml("<br />\n") for line in message.splitlines(): self.contents.insertHtml(Utilities.html_encode(line)) self.contents.insertHtml("<br />\n") if len(log["changed_paths"]) > 0: self.contents.insertHtml("<br />\n") for changeInfo in log["changed_paths"]: action = changeInfo["action"] path = changeInfo["path"] if sys.version_info[0] == 2: action = action.decode("utf-8") path = path.decode("utf-8") dstr = "{0} {1}".format(self.flags[action], path) if changeInfo["copyfrom_path"] is not None: copyfrom_path = changeInfo["copyfrom_path"] if sys.version_info[0] == 2: copyfrom_path = copyfrom_path.decode("utf-8") dstr += self.tr(" (copied from {0}, revision {1})").format( copyfrom_path, changeInfo["copyfrom_revision"].number ) dstr += "<br />\n" self.contents.insertHtml(dstr) self.contents.insertHtml("<hr /><br />\n") except pysvn.ClientError as e: locker.unlock() self.__showError(e.args[0]) os.chdir(cwd) self.__finish()
def _construct_Qurl(path): url = QUrl() url.setScheme("file") raw_path = "/" + os.path.dirname(path) + "/" url.setPath(raw_path) return url
def __finish(self): """ Private slot called when the process finished or the user pressed the button. """ self.inputGroup.setEnabled(False) self.inputGroup.hide() self.contents.clear() if not self.logEntries: self.errors.append(self.tr("No log available for '{0}'") .format(self.filename)) self.errorGroup.show() return html = "" if self.initialText: for line in self.initialText: html += Utilities.html_encode(line.strip()) html += '<br />\n' html += '{0}<br/>\n'.format(80 * "=") for entry in self.logEntries: fileCopies = {} if entry["file_copies"]: for fentry in entry["file_copies"].split(", "): newName, oldName = fentry[:-1].split(" (") fileCopies[newName] = oldName rev, hexRev = entry["change"].split(":") dstr = '<p><b>{0} {1}</b>'.format(self.revString, entry["change"]) if entry["parents"]: parents = entry["parents"].split() else: parents = self.__getParents(rev) for parent in parents: url = QUrl() url.setScheme("file") url.setPath(self.filename) if qVersion() >= "5.0.0": query = parent.split(":")[0] + '_' + rev url.setQuery(query) else: query = QByteArray() query.append(parent.split(":")[0]).append('_').append(rev) url.setEncodedQuery(query) dstr += ' [<a href="{0}" name="{1}" id="{1}">{2}</a>]'.format( url.toString(), query, self.tr('diff to {0}').format(parent), ) dstr += '<br />\n' html += dstr if "phase" in entry: html += self.tr("Phase: {0}<br />\n")\ .format(entry["phase"]) html += self.tr("Branch: {0}<br />\n")\ .format(entry["branches"]) html += self.tr("Tags: {0}<br />\n").format(entry["tags"]) if "bookmarks" in entry: html += self.tr("Bookmarks: {0}<br />\n")\ .format(entry["bookmarks"]) html += self.tr("Parents: {0}<br />\n")\ .format(entry["parents"]) html += self.tr('<i>Author: {0}</i><br />\n')\ .format(Utilities.html_encode(entry["user"])) date, time = entry["date"].split()[:2] html += self.tr('<i>Date: {0}, {1}</i><br />\n')\ .format(date, time) for line in entry["description"]: html += Utilities.html_encode(line.strip()) html += '<br />\n' if entry["file_adds"]: html += '<br />\n' for f in entry["file_adds"].strip().split(", "): if f in fileCopies: html += self.tr( 'Added {0} (copied from {1})<br />\n')\ .format(Utilities.html_encode(f), Utilities.html_encode(fileCopies[f])) else: html += self.tr('Added {0}<br />\n')\ .format(Utilities.html_encode(f)) if entry["files_mods"]: html += '<br />\n' for f in entry["files_mods"].strip().split(", "): html += self.tr('Modified {0}<br />\n')\ .format(Utilities.html_encode(f)) if entry["file_dels"]: html += '<br />\n' for f in entry["file_dels"].strip().split(", "): html += self.tr('Deleted {0}<br />\n')\ .format(Utilities.html_encode(f)) html += '</p>{0}<br/>\n'.format(60 * "=") self.contents.setHtml(html) tc = self.contents.textCursor() tc.movePosition(QTextCursor.Start) self.contents.setTextCursor(tc) self.contents.ensureCursorVisible()