Repository: qutebrowser/qutebrowser

Issue:
spawn --userscript --ouput creates a race condition between the userscript and the new output tab.
```
Version info

qutebrowser v1.1.1
Git commit: ddf170eca-dirty (2018-01-30 22:25:41 -0500)
Backend: QtWebEngine (Chromium 56.0.2924.122)

CPython: 3.6.4
Qt: 5.9.2
PyQt: 5.9.2

sip: 4.19.6
colorama: 0.3.7
pypeg2: 2.15
jinja2: 2.10
pygments: 2.2.0
yaml: 3.12
cssutils: no
attr: 17.4.0
PyQt5.QtWebEngineWidgets: yes
PyQt5.QtWebKitWidgets: yes
pdf.js: no
sqlite: 3.22.0
QtNetwork SSL: OpenSSL 1.0.2n  7 Dec 2017

Style: QFusionStyle
Platform: Linux-4.14.0-3-amd64-x86_64-with-debian-buster-sid, 64bit
Linux distribution: Debian GNU/Linux buster/sid (debian)
Frozen: False
Imported from /home/marc/src/qutebrowser/qutebrowser
Qt library executable path: /usr/lib/x86_64-linux-gnu/qt5/libexec, data path: /usr/share/qt5

Paths:
cache: /home/marc/.cache/qutebrowser
config: /home/marc/.config/qutebrowser
data: /home/marc/.local/share/qutebrowser
runtime: /run/user/1000/qutebrowser

Uptime: 0:01:54
```

QUTE_URL does not get defined in the userscript environment. Also, the output tab results are empty or show the *previous* run results.


Discussion:
That's actually also a problem with e.g. `:spawn -o bash -c "sleep 1; echo foo"`. The page should only open after the process finished.
Currently I don't see anything in the code that waits for the script to finish before opening the output tab.
Right, there isn't, that's why there is this issue :wink:

Resolving patch:
diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py
--- a/qutebrowser/browser/commands.py
+++ b/qutebrowser/browser/commands.py
@@ -1217,10 +1217,19 @@ def spawn(self, cmdline, userscript=False, verbose=False,
 
         log.procs.debug("Executing {} with args {}, userscript={}".format(
             cmd, args, userscript))
+
+        @pyqtSlot()
+        def _on_proc_finished():
+            if output:
+                tb = objreg.get('tabbed-browser', scope='window',
+                                window='last-focused')
+                tb.openurl(QUrl('qute://spawn-output'), newtab=True)
+
         if userscript:
             def _selection_callback(s):
                 try:
-                    self._run_userscript(s, cmd, args, verbose)
+                    runner = self._run_userscript(s, cmd, args, verbose)
+                    runner.finished.connect(_on_proc_finished)
                 except cmdexc.CommandError as e:
                     message.error(str(e))
 
@@ -1239,11 +1248,7 @@ def _selection_callback(s):
                 proc.start_detached(cmd, args)
             else:
                 proc.start(cmd, args)
-
-        if output:
-            tabbed_browser = objreg.get('tabbed-browser', scope='window',
-                                        window='last-focused')
-            tabbed_browser.openurl(QUrl('qute://spawn-output'), newtab=True)
+            proc.finished.connect(_on_proc_finished)
 
     @cmdutils.register(instance='command-dispatcher', scope='window')
     def home(self):
@@ -1284,10 +1289,11 @@ def _run_userscript(self, selection, cmd, args, verbose):
             env['QUTE_URL'] = url.toString(QUrl.FullyEncoded)
 
         try:
-            userscripts.run_async(tab, cmd, *args, win_id=self._win_id,
-                                  env=env, verbose=verbose)
+            runner = userscripts.run_async(
+                tab, cmd, *args, win_id=self._win_id, env=env, verbose=verbose)
         except userscripts.Error as e:
             raise cmdexc.CommandError(e)
+        return runner
 
     @cmdutils.register(instance='command-dispatcher', scope='window')
     def quickmark_save(self):
diff --git a/qutebrowser/browser/network/proxy.py b/qutebrowser/browser/network/proxy.py
--- a/qutebrowser/browser/network/proxy.py
+++ b/qutebrowser/browser/network/proxy.py
@@ -1,6 +1,6 @@
 # vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
 
-# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
 #
 # This file is part of qutebrowser.
 #
diff --git a/qutebrowser/commands/userscripts.py b/qutebrowser/commands/userscripts.py
--- a/qutebrowser/commands/userscripts.py
+++ b/qutebrowser/commands/userscripts.py
@@ -446,3 +446,4 @@ def run_async(tab, cmd, *args, win_id, env, verbose=False):
     runner.prepare_run(cmd_path, *args, env=env, verbose=verbose)
     tab.dump_async(runner.store_html)
     tab.dump_async(runner.store_text, plain=True)
+    return runner


Test patch: