parent
aab5411317
commit
54131e9d3e
@ -47,6 +47,9 @@ show it.
|
||||
*--cachedir* 'CACHEDIR'::
|
||||
Set cache directory (empty for no cache storage).
|
||||
|
||||
*--basedir* 'BASEDIR'::
|
||||
Base directory for all storage. Other --*dir arguments are ignored if this is given.
|
||||
|
||||
*-V*, *--version*::
|
||||
Show version and quit.
|
||||
|
||||
|
@ -84,11 +84,11 @@ def run(args):
|
||||
objreg.register('signal-handler', signal_handler)
|
||||
|
||||
try:
|
||||
sent = ipc.send_to_running_instance(args.command)
|
||||
sent = ipc.send_to_running_instance(args)
|
||||
if sent:
|
||||
sys.exit(0)
|
||||
log.init.debug("Starting IPC server...")
|
||||
server = ipc.IPCServer(qApp)
|
||||
server = ipc.IPCServer(args, qApp)
|
||||
objreg.register('ipc-server', server)
|
||||
server.got_args.connect(lambda args, cwd:
|
||||
process_pos_args(args, cwd=cwd, via_ipc=True))
|
||||
@ -96,7 +96,7 @@ def run(args):
|
||||
# This could be a race condition...
|
||||
log.init.debug("Got AddressInUseError, trying again.")
|
||||
time.sleep(500)
|
||||
sent = ipc.send_to_running_instance(args.command)
|
||||
sent = ipc.send_to_running_instance(args)
|
||||
if sent:
|
||||
sys.exit(0)
|
||||
else:
|
||||
@ -199,7 +199,7 @@ def _process_args(args):
|
||||
|
||||
process_pos_args(args.command)
|
||||
_open_startpage()
|
||||
_open_quickstart()
|
||||
_open_quickstart(args)
|
||||
|
||||
|
||||
def _load_session(name):
|
||||
@ -303,8 +303,15 @@ def _open_startpage(win_id=None):
|
||||
tabbed_browser.tabopen(url)
|
||||
|
||||
|
||||
def _open_quickstart():
|
||||
"""Open quickstart if it's the first start."""
|
||||
def _open_quickstart(args):
|
||||
"""Open quickstart if it's the first start.
|
||||
|
||||
Args:
|
||||
args: The argparse namespace.
|
||||
"""
|
||||
if args.datadir is not None or args.basedir is not None:
|
||||
# With --datadir or --basedir given, don't open quickstart.
|
||||
return
|
||||
state_config = objreg.get('state-config')
|
||||
try:
|
||||
quickstart_done = state_config['general']['quickstart-done'] == '1'
|
||||
|
@ -23,6 +23,7 @@ import os
|
||||
import json
|
||||
import getpass
|
||||
import binascii
|
||||
import hashlib
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject
|
||||
from PyQt5.QtNetwork import QLocalSocket, QLocalServer, QAbstractSocket
|
||||
@ -31,12 +32,20 @@ from PyQt5.QtWidgets import QMessageBox
|
||||
from qutebrowser.utils import log, usertypes
|
||||
|
||||
|
||||
SOCKETNAME = 'qutebrowser-{}'.format(getpass.getuser())
|
||||
CONNECT_TIMEOUT = 100
|
||||
WRITE_TIMEOUT = 1000
|
||||
READ_TIMEOUT = 5000
|
||||
|
||||
|
||||
def _get_socketname(args):
|
||||
"""Get a socketname to use."""
|
||||
parts = ['qutebrowser', getpass.getuser()]
|
||||
if args.basedir is not None:
|
||||
md5 = hashlib.md5(args.basedir.encode('utf-8'))
|
||||
parts.append(md5.hexdigest())
|
||||
return '-'.join(parts)
|
||||
|
||||
|
||||
class Error(Exception):
|
||||
|
||||
"""Exception raised when there was a problem with IPC."""
|
||||
@ -80,6 +89,7 @@ class IPCServer(QObject):
|
||||
_timer: A timer to handle timeouts.
|
||||
_server: A QLocalServer to accept new connections.
|
||||
_socket: The QLocalSocket we're currently connected to.
|
||||
_socketname: The socketname to use.
|
||||
|
||||
Signals:
|
||||
got_args: Emitted when there was an IPC connection and arguments were
|
||||
@ -88,16 +98,22 @@ class IPCServer(QObject):
|
||||
|
||||
got_args = pyqtSignal(list, str)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
"""Start the IPC server and listen to commands."""
|
||||
def __init__(self, args, parent=None):
|
||||
"""Start the IPC server and listen to commands.
|
||||
|
||||
Args:
|
||||
args: The argparse namespace.
|
||||
parent: The parent to be used.
|
||||
"""
|
||||
super().__init__(parent)
|
||||
self.ignored = False
|
||||
self._socketname = _get_socketname(args)
|
||||
self._remove_server()
|
||||
self._timer = usertypes.Timer(self, 'ipc-timeout')
|
||||
self._timer.setInterval(READ_TIMEOUT)
|
||||
self._timer.timeout.connect(self.on_timeout)
|
||||
self._server = QLocalServer(self)
|
||||
ok = self._server.listen(SOCKETNAME)
|
||||
ok = self._server.listen(self._socketname)
|
||||
if not ok:
|
||||
if self._server.serverError() == QAbstractSocket.AddressInUseError:
|
||||
raise AddressInUseError(self._server)
|
||||
@ -108,9 +124,10 @@ class IPCServer(QObject):
|
||||
|
||||
def _remove_server(self):
|
||||
"""Remove an existing server."""
|
||||
ok = QLocalServer.removeServer(SOCKETNAME)
|
||||
ok = QLocalServer.removeServer(self._socketname)
|
||||
if not ok:
|
||||
raise Error("Error while removing server {}!".format(SOCKETNAME))
|
||||
raise Error("Error while removing server {}!".format(
|
||||
self._socketname))
|
||||
|
||||
@pyqtSlot(int)
|
||||
def on_error(self, error):
|
||||
@ -223,23 +240,23 @@ def _socket_error(action, socket):
|
||||
action, socket.errorString(), socket.error()))
|
||||
|
||||
|
||||
def send_to_running_instance(cmdlist):
|
||||
def send_to_running_instance(args):
|
||||
"""Try to send a commandline to a running instance.
|
||||
|
||||
Blocks for CONNECT_TIMEOUT ms.
|
||||
|
||||
Args:
|
||||
cmdlist: A list to send (URLs/commands)
|
||||
args: The argparse namespace.
|
||||
|
||||
Return:
|
||||
True if connecting was successful, False if no connection was made.
|
||||
"""
|
||||
socket = QLocalSocket()
|
||||
socket.connectToServer(SOCKETNAME)
|
||||
socket.connectToServer(_get_socketname(args))
|
||||
connected = socket.waitForConnected(100)
|
||||
if connected:
|
||||
log.ipc.info("Opening in existing instance")
|
||||
json_data = {'args': cmdlist}
|
||||
json_data = {'args': args.command}
|
||||
try:
|
||||
cwd = os.getcwd()
|
||||
except OSError:
|
||||
|
@ -52,6 +52,8 @@ def get_argparser():
|
||||
"no data storage).")
|
||||
parser.add_argument('--cachedir', help="Set cache directory (empty for "
|
||||
"no cache storage).")
|
||||
parser.add_argument('--basedir', help="Base directory for all storage. "
|
||||
"Other --*dir arguments are ignored if this is given.")
|
||||
parser.add_argument('-V', '--version', help="Show version and quit.",
|
||||
action='store_true')
|
||||
parser.add_argument('-s', '--set', help="Set a temporary setting for "
|
||||
|
@ -84,8 +84,22 @@ def _from_args(typ, args):
|
||||
QStandardPaths.DataLocation: 'datadir',
|
||||
QStandardPaths.CacheLocation: 'cachedir',
|
||||
}
|
||||
basedir_suffix = {
|
||||
QStandardPaths.ConfigLocation: 'config',
|
||||
QStandardPaths.DataLocation: 'data',
|
||||
QStandardPaths.CacheLocation: 'cache',
|
||||
QStandardPaths.DownloadLocation: 'download',
|
||||
QStandardPaths.RuntimeLocation: 'runtime',
|
||||
}
|
||||
|
||||
if args is None:
|
||||
return (False, None)
|
||||
|
||||
if getattr(args, 'basedir', None) is not None:
|
||||
basedir = args.basedir
|
||||
suffix = basedir_suffix[typ]
|
||||
return (True, os.path.join(basedir, suffix))
|
||||
|
||||
try:
|
||||
argname = typ_to_argparse_arg[typ]
|
||||
except KeyError:
|
||||
|
@ -154,3 +154,13 @@ class TestArguments:
|
||||
datadir=testcase.arg)
|
||||
standarddir.init(args)
|
||||
assert standarddir.data() == testcase.expected
|
||||
|
||||
@pytest.mark.parametrize('typ', ['config', 'data', 'cache', 'download',
|
||||
'runtime'])
|
||||
def test_basedir(self, tmpdir, typ):
|
||||
"""Test --basedir."""
|
||||
expected = str(tmpdir / typ)
|
||||
args = types.SimpleNamespace(basedir=str(tmpdir))
|
||||
standarddir.init(args)
|
||||
func = getattr(standarddir, typ)
|
||||
assert func() == expected
|
||||
|
Loading…
Reference in New Issue
Block a user