Permalink
Browse files

Rewrite userscripts to work with async dumping

  • Loading branch information...
The-Compiler committed Jul 5, 2016
1 parent e917f05 commit 86acf3b973c85380317c543d35fd9219d5df32ef
@@ -1033,14 +1033,13 @@ def _run_userscript(self, cmd, *args, verbose=False):
if idx != -1:
env['QUTE_TITLE'] = self._tabbed_browser.page_title(idx)
webview = self._tabbed_browser.currentWidget()
if webview is None:
tab = self._tabbed_browser.currentWidget()
if tab is None:
mainframe = None
else:
if webview.caret.has_selection():
env['QUTE_SELECTED_TEXT'] = webview.caret.selection()
env['QUTE_SELECTED_HTML'] = webview.caret.selection(html=True)
mainframe = webview.page().mainFrame()
if tab.caret.has_selection():
env['QUTE_SELECTED_TEXT'] = tab.caret.selection()
env['QUTE_SELECTED_HTML'] = tab.caret.selection(html=True)
try:
url = self._tabbed_browser.current_url()
@@ -1049,9 +1048,8 @@ def _run_userscript(self, cmd, *args, verbose=False):
else:
env['QUTE_URL'] = url.toString(QUrl.FullyEncoded)
env.update(userscripts.store_source(mainframe))
userscripts.run(cmd, *args, win_id=self._win_id, env=env,
verbose=verbose)
userscripts.run_async(tab, cmd, *args, win_id=self._win_id, env=env,
verbose=verbose)
@cmdutils.register(instance='command-dispatcher', scope='window')
def quickmark_save(self):
@@ -84,6 +84,7 @@ class HintContext:
args: Custom arguments for userscript/spawn
rapid: Whether to do rapid hinting.
mainframe: The main QWebFrame where we started hinting in.
tab: The WebTab object we started hinting in.
group: The group of web elements to hint.
"""
@@ -98,6 +99,7 @@ def __init__(self):
self.destroyed_frames = []
self.args = []
self.mainframe = None
self.tab = None
self.group = None
def get_args(self, urlstr):
@@ -569,7 +571,6 @@ def _call_userscript(self, elem, context):
"""
cmd = context.args[0]
args = context.args[1:]
frame = context.mainframe
env = {
'QUTE_MODE': 'hints',
'QUTE_SELECTED_TEXT': str(elem),
@@ -578,8 +579,9 @@ def _call_userscript(self, elem, context):
url = self._resolve_url(elem, context.baseurl)
if url is not None:
env['QUTE_URL'] = url.toString(QUrl.FullyEncoded)
env.update(userscripts.store_source(frame))
userscripts.run(cmd, *args, win_id=self._win_id, env=env)
userscripts.run_async(context.tab, cmd, *args, win_id=self._win_id,
env=env)
def _spawn(self, url, context):
"""Spawn a simple command from a hint.
@@ -837,6 +839,7 @@ def start(self, rapid=False, group=webelem.Group.all, target=Target.normal,
self._check_args(target, *args)
self._context = HintContext()
self._context.tab = tab
self._context.target = target
self._context.rapid = rapid
try:
@@ -85,6 +85,10 @@ class _BaseUserscriptRunner(QObject):
_proc: The GUIProcess which is being executed.
_win_id: The window ID this runner is associated with.
_cleaned_up: Whether temporary files were cleaned up.
_text_stored: Set when the page text was stored async.
_html_stored: Set when the page html was stored async.
_args: Arguments to pass to _run_process.
_kwargs: Keyword arguments to pass to _run_process.
Signals:
got_cmd: Emitted when a new command arrived and should be executed.
@@ -100,9 +104,41 @@ def __init__(self, win_id, parent=None):
self._win_id = win_id
self._filepath = None
self._proc = None
self._env = None
def _run_process(self, cmd, *args, env, verbose):
self._env = {}
self._text_stored = False
self._html_stored = False
self._args = None
self._kwargs = None
def store_text(self, text):
"""Called as callback when the text is ready from the web backend."""
with tempfile.NamedTemporaryFile(mode='w', encoding='utf-8',
suffix='.txt',
delete=False) as txt_file:
txt_file.write(text)
self._env['QUTE_TEXT'] = txt_file.name
self._text_stored = True
log.procs.debug("Text stored from webview")
if self._text_stored and self._html_stored:
log.procs.debug("Both text/HTML stored, kicking off userscript!")
self._run_process(*self._args, **self._kwargs)
def store_html(self, html):
"""Called as callback when the html is ready from the web backend."""
with tempfile.NamedTemporaryFile(mode='w', encoding='utf-8',
suffix='.html',
delete=False) as html_file:
html_file.write(html)
self._env['QUTE_HTML'] = html_file.name
self._html_stored = True
log.procs.debug("HTML stored from webview")
if self._text_stored and self._html_stored:
log.procs.debug("Both text/HTML stored, kicking off userscript!")
self._run_process(*self._args, **self._kwargs)
def _run_process(self, cmd, *args, env=None, verbose=False):
"""Start the given command.
Args:
@@ -111,7 +147,7 @@ def _run_process(self, cmd, *args, env, verbose):
env: A dictionary of environment variables to add.
verbose: Show notifications when the command started/exited.
"""
self._env = {'QUTE_FIFO': self._filepath}
self._env['QUTE_FIFO'] = self._filepath
if env is not None:
self._env.update(env)
self._proc = guiprocess.GUIProcess(self._win_id, 'userscript',
@@ -143,18 +179,19 @@ def _cleanup(self):
fn, e))
self._filepath = None
self._proc = None
self._env = None
self._env = {}
self._text_stored = False
self._html_stored = False
def run(self, cmd, *args, env=None, verbose=False):
"""Run the userscript given.
def prepare_run(self, *args, **kwargs):
"""Prepare ruinning the userscript given.
Needs to be overridden by subclasses.
The script will actually run after store_text and store_html have been
called.
Args:
cmd: The command to be started.
*args: The arguments to hand to the command
env: A dictionary of environment variables to add.
verbose: Show notifications when the command started/exited.
Passed to _run_process.
"""
raise NotImplementedError
@@ -189,7 +226,10 @@ def __init__(self, win_id, parent=None):
super().__init__(win_id, parent)
self._reader = None
def run(self, cmd, *args, env=None, verbose=False):
def prepare_run(self, *args, **kwargs):
self._args = args
self._kwargs = kwargs
try:
# tempfile.mktemp is deprecated and discouraged, but we use it here
# to create a FIFO since the only other alternative would be to
@@ -208,8 +248,6 @@ def run(self, cmd, *args, env=None, verbose=False):
self._reader = _QtFIFOReader(self._filepath)
self._reader.got_line.connect(self.got_cmd)
self._run_process(cmd, *args, env=env, verbose=verbose)
@pyqtSlot()
def on_proc_finished(self):
self._cleanup()
@@ -279,14 +317,16 @@ def on_proc_finished(self):
"""Read back the commands when the process finished."""
self._cleanup()
def run(self, cmd, *args, env=None, verbose=False):
def prepare_run(self, *args, **kwargs):
self._args = args
self._kwargs = kwargs
try:
self._oshandle, self._filepath = tempfile.mkstemp(text=True)
except OSError as e:
message.error(self._win_id, "Error while creating tempfile: "
"{}".format(e))
return
self._run_process(cmd, *args, env=env, verbose=verbose)
class _DummyUserscriptRunner(QObject):
@@ -306,7 +346,7 @@ def __init__(self, win_id, parent=None):
# pylint: disable=unused-argument
super().__init__(parent)
def run(self, cmd, *args, env=None, verbose=False):
def prepare_run(self, *args, **kwargs):
"""Print an error as userscripts are not supported."""
# pylint: disable=unused-argument,unused-variable
self.finished.emit()
@@ -324,41 +364,11 @@ def run(self, cmd, *args, env=None, verbose=False):
UserscriptRunner = _DummyUserscriptRunner
def store_source(frame):
"""Store HTML/plaintext in files.
This writes files containing the HTML/plaintext source of the page, and
returns a dict with the paths as QUTE_HTML/QUTE_TEXT.
Args:
frame: The QWebFrame to get the info from, or None to do nothing.
Return:
A dictionary with the needed environment variables.
Warning:
The caller is responsible to delete the files after using them!
"""
if frame is None:
return {}
env = {}
with tempfile.NamedTemporaryFile(mode='w', encoding='utf-8',
suffix='.html',
delete=False) as html_file:
html_file.write(frame.toHtml())
env['QUTE_HTML'] = html_file.name
with tempfile.NamedTemporaryFile(mode='w', encoding='utf-8',
suffix='.txt',
delete=False) as txt_file:
txt_file.write(frame.toPlainText())
env['QUTE_TEXT'] = txt_file.name
return env
def run(cmd, *args, win_id, env, verbose=False):
def run_async(tab, cmd, *args, win_id, env, verbose=False):
"""Convenience method to run a userscript.
Args:
tab: The WebKitTab/WebEngineTab to get the source from.
cmd: The userscript binary to run.
*args: The arguments to pass to the userscript.
win_id: The window id the userscript is executed in.
@@ -388,6 +398,9 @@ def run(cmd, *args, win_id, env, verbose=False):
"userscripts", cmd)
log.misc.debug("Userscript to run: {}".format(cmd_path))
runner.run(cmd_path, *args, env=env, verbose=verbose)
runner.finished.connect(commandrunner.deleteLater)
runner.finished.connect(runner.deleteLater)
runner.prepare_run(cmd_path, *args, env=env, verbose=verbose)
tab.dump_async(runner.store_html)
tab.dump_async(runner.store_text, plain=True)
Oops, something went wrong.

0 comments on commit 86acf3b

Please sign in to comment.