Clean up standarddir handling #2.

We already attempted this in c5a2039da4, but
having the directories as module attributes means they'll be created on start
(rather than when they're actually used), and it'd also be impossible to change
them after init for some reason in the future.

To still have a nice short API, we simply change the attributes to functions.
This commit is contained in:
Florian Bruhin 2015-02-26 07:01:22 +01:00
parent 8078068552
commit fcbd69e209
13 changed files with 79 additions and 69 deletions

View File

@ -225,7 +225,7 @@ class Application(QApplication):
def _handle_segfault(self): def _handle_segfault(self):
"""Handle a segfault from a previous run.""" """Handle a segfault from a previous run."""
logname = os.path.join(standarddir.data, 'crash.log') logname = os.path.join(standarddir.data(), 'crash.log')
try: try:
# First check if an old logfile exists. # First check if an old logfile exists.
if os.path.exists(logname): if os.path.exists(logname):
@ -249,7 +249,7 @@ class Application(QApplication):
def _init_crashlogfile(self): def _init_crashlogfile(self):
"""Start a new logfile and redirect faulthandler to it.""" """Start a new logfile and redirect faulthandler to it."""
logname = os.path.join(standarddir.data, 'crash.log') logname = os.path.join(standarddir.data(), 'crash.log')
try: try:
self._crashlogfile = open(logname, 'w', encoding='ascii') self._crashlogfile = open(logname, 'w', encoding='ascii')
except OSError: except OSError:

View File

@ -92,7 +92,7 @@ class HostBlocker:
self.blocked_hosts = set() self.blocked_hosts = set()
self._in_progress = [] self._in_progress = []
self._done_count = 0 self._done_count = 0
self._hosts_file = os.path.join(standarddir.data, 'blocked-hosts') self._hosts_file = os.path.join(standarddir.data(), 'blocked-hosts')
objreg.get('config').changed.connect(self.on_config_changed) objreg.get('config').changed.connect(self.on_config_changed)
def read_hosts(self): def read_hosts(self):

View File

@ -33,7 +33,7 @@ class DiskCache(QNetworkDiskCache):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
self.setCacheDirectory(os.path.join(standarddir.cache, 'http')) self.setCacheDirectory(os.path.join(standarddir.cache(), 'http'))
self.setMaximumCacheSize(config.get('storage', 'cache-size')) self.setMaximumCacheSize(config.get('storage', 'cache-size'))
objreg.get('config').changed.connect(self.cache_size_changed) objreg.get('config').changed.connect(self.cache_size_changed)

View File

@ -70,8 +70,8 @@ class CookieJar(RAMCookieJar):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
self._linecp = lineparser.LineConfigParser(standarddir.data, 'cookies', self._linecp = lineparser.LineConfigParser(
binary=True, parent=self) standarddir.data(), 'cookies', binary=True, parent=self)
cookies = [] cookies = []
for line in self._linecp: for line in self._linecp:
cookies += QNetworkCookie.parseCookies(line) cookies += QNetworkCookie.parseCookies(line)

View File

@ -417,7 +417,7 @@ class DownloadItem(QObject):
# save it under that filename in the default directory. # save it under that filename in the default directory.
download_dir = config.get('storage', 'download-directory') download_dir = config.get('storage', 'download-directory')
if download_dir is None: if download_dir is None:
download_dir = standarddir.download download_dir = standarddir.download()
self._filename = os.path.join(download_dir, filename) self._filename = os.path.join(download_dir, filename)
self.basename = filename self.basename = filename
log.downloads.debug("Setting filename to {}".format(filename)) log.downloads.debug("Setting filename to {}".format(filename))

View File

@ -64,8 +64,8 @@ class WebHistory(QWebHistoryInterface):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
self._linecp = lineparser.LineConfigParser(standarddir.data, 'history', self._linecp = lineparser.LineConfigParser(
parent=self) standarddir.data(), 'history', parent=self)
self._history = [HistoryEntry.from_str(e) for e in self._linecp.data] self._history = [HistoryEntry.from_str(e) for e in self._linecp.data]
objreg.get('save-manager').add_saveable('history', self.save, objreg.get('save-manager').add_saveable('history', self.save,
self.changed) self.changed)

View File

@ -53,7 +53,7 @@ class QuickmarkManager(QObject):
self.marks = collections.OrderedDict() self.marks = collections.OrderedDict()
self._linecp = lineparser.LineConfigParser( self._linecp = lineparser.LineConfigParser(
standarddir.config, 'quickmarks', parent=self) standarddir.config(), 'quickmarks', parent=self)
for line in self._linecp: for line in self._linecp:
try: try:
key, url = line.rsplit(maxsplit=1) key, url = line.rsplit(maxsplit=1)
@ -61,7 +61,7 @@ class QuickmarkManager(QObject):
message.error(0, "Invalid quickmark '{}'".format(line)) message.error(0, "Invalid quickmark '{}'".format(line))
else: else:
self.marks[key] = url self.marks[key] = url
filename = os.path.join(standarddir.config, 'quickmarks') filename = os.path.join(standarddir.config(), 'quickmarks')
objreg.get('save-manager').add_saveable('quickmark-manager', self.save, objreg.get('save-manager').add_saveable('quickmark-manager', self.save,
self.changed, self.changed,
filename=filename) filename=filename)

View File

@ -185,7 +185,7 @@ class _POSIXUserscriptRunner(_BaseUserscriptRunner):
# os.mkfifo will raise an exception anyways when the path doesn't # os.mkfifo will raise an exception anyways when the path doesn't
# exist, it shouldn't be a big issue. # exist, it shouldn't be a big issue.
self._filepath = tempfile.mktemp(prefix='qutebrowser-userscript-', self._filepath = tempfile.mktemp(prefix='qutebrowser-userscript-',
dir=standarddir.runtime) dir=standarddir.runtime())
os.mkfifo(self._filepath) # pylint: disable=no-member os.mkfifo(self._filepath) # pylint: disable=no-member
except OSError as e: except OSError as e:
message.error(self._win_id, "Error while creating FIFO: {}".format( message.error(self._win_id, "Error while creating FIFO: {}".format(

View File

@ -117,7 +117,8 @@ def _init_main_config():
"""Initialize the main config.""" """Initialize the main config."""
try: try:
app = objreg.get('app') app = objreg.get('app')
config_obj = ConfigManager(standarddir.config, 'qutebrowser.conf', app) config_obj = ConfigManager(standarddir.config(), 'qutebrowser.conf',
app)
except (configexc.Error, configparser.Error, UnicodeDecodeError) as e: except (configexc.Error, configparser.Error, UnicodeDecodeError) as e:
log.init.exception(e) log.init.exception(e)
errstr = "Error while reading config:" errstr = "Error while reading config:"
@ -134,8 +135,8 @@ def _init_main_config():
sys.exit(1) sys.exit(1)
else: else:
objreg.register('config', config_obj) objreg.register('config', config_obj)
if standarddir.config is not None: if standarddir.config() is not None:
filename = os.path.join(standarddir.config, 'qutebrowser.conf') filename = os.path.join(standarddir.config(), 'qutebrowser.conf')
save_manager = objreg.get('save-manager') save_manager = objreg.get('save-manager')
save_manager.add_saveable( save_manager.add_saveable(
'config', config_obj.save, config_obj.changed, 'config', config_obj.save, config_obj.changed,
@ -152,7 +153,7 @@ def _init_main_config():
def _init_key_config(): def _init_key_config():
"""Initialize the key config.""" """Initialize the key config."""
try: try:
key_config = keyconf.KeyConfigParser(standarddir.config, 'keys.conf') key_config = keyconf.KeyConfigParser(standarddir.config(), 'keys.conf')
except (keyconf.KeyConfigError, UnicodeDecodeError) as e: except (keyconf.KeyConfigError, UnicodeDecodeError) as e:
log.init.exception(e) log.init.exception(e)
errstr = "Error while reading key config:\n" errstr = "Error while reading key config:\n"
@ -166,9 +167,9 @@ def _init_key_config():
sys.exit(1) sys.exit(1)
else: else:
objreg.register('key-config', key_config) objreg.register('key-config', key_config)
if standarddir.config is not None: if standarddir.config() is not None:
save_manager = objreg.get('save-manager') save_manager = objreg.get('save-manager')
filename = os.path.join(standarddir.config, 'keys.conf') filename = os.path.join(standarddir.config(), 'keys.conf')
save_manager.add_saveable( save_manager.add_saveable(
'key-config', key_config.save, key_config.changed, 'key-config', key_config.save, key_config.changed,
config_opt=('general', 'auto-save-config'), filename=filename) config_opt=('general', 'auto-save-config'), filename=filename)
@ -177,13 +178,13 @@ def _init_key_config():
def _init_misc(): def _init_misc():
"""Initialize misc. config-related files.""" """Initialize misc. config-related files."""
save_manager = objreg.get('save-manager') save_manager = objreg.get('save-manager')
state_config = ini.ReadWriteConfigParser(standarddir.data, 'state') state_config = ini.ReadWriteConfigParser(standarddir.data(), 'state')
objreg.register('state-config', state_config) objreg.register('state-config', state_config)
save_manager.add_saveable('state-config', state_config.save) save_manager.add_saveable('state-config', state_config.save)
# We need to import this here because lineparser needs config. # We need to import this here because lineparser needs config.
from qutebrowser.config.parsers import line from qutebrowser.config.parsers import line
command_history = line.LineConfigParser(standarddir.data, 'cmd-history', command_history = line.LineConfigParser(standarddir.data(), 'cmd-history',
('completion', 'history-length'), ('completion', 'history-length'),
parent=objreg.get('config')) parent=objreg.get('config'))
objreg.register('command-history', command_history) objreg.register('command-history', command_history)
@ -197,10 +198,10 @@ def _init_misc():
# This fixes one of the corruption issues here: # This fixes one of the corruption issues here:
# https://github.com/The-Compiler/qutebrowser/issues/515 # https://github.com/The-Compiler/qutebrowser/issues/515
if standarddir.config is None: if standarddir.config() is None:
path = os.devnull path = os.devnull
else: else:
path = os.path.join(standarddir.config, 'qsettings') path = os.path.join(standarddir.config(), 'qsettings')
for fmt in (QSettings.NativeFormat, QSettings.IniFormat): for fmt in (QSettings.NativeFormat, QSettings.IniFormat):
QSettings.setPath(fmt, QSettings.UserScope, path) QSettings.setPath(fmt, QSettings.UserScope, path)

View File

@ -194,13 +194,13 @@ def _set_setting(typ, arg, default=UNSET, value=UNSET):
def init(): def init():
"""Initialize the global QWebSettings.""" """Initialize the global QWebSettings."""
QWebSettings.setIconDatabasePath(standarddir.cache) QWebSettings.setIconDatabasePath(standarddir.cache())
QWebSettings.setOfflineWebApplicationCachePath( QWebSettings.setOfflineWebApplicationCachePath(
os.path.join(standarddir.cache, 'application-cache')) os.path.join(standarddir.cache(), 'application-cache'))
QWebSettings.globalSettings().setLocalStoragePath( QWebSettings.globalSettings().setLocalStoragePath(
os.path.join(standarddir.data, 'local-storage')) os.path.join(standarddir.data(), 'local-storage'))
QWebSettings.setOfflineStoragePath( QWebSettings.setOfflineStoragePath(
os.path.join(standarddir.data, 'offline-storage')) os.path.join(standarddir.data(), 'offline-storage'))
global settings global settings
settings = QWebSettings.globalSettings() settings = QWebSettings.globalSettings()

View File

@ -64,7 +64,7 @@ class SessionManager(QObject):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
self._base_path = os.path.join(standarddir.data, 'sessions') self._base_path = os.path.join(standarddir.data(), 'sessions')
self._last_window_session = None self._last_window_session = None
if not os.path.exists(self._base_path): if not os.path.exists(self._base_path):
os.mkdir(self._base_path) os.mkdir(self._base_path)

View File

@ -32,7 +32,7 @@ from qutebrowser.test import helpers, qApp
class GetStandardDirLinuxTests(unittest.TestCase): class GetStandardDirLinuxTests(unittest.TestCase):
"""Tests for standarddir.get under Linux. """Tests for standarddir under Linux.
Attributes: Attributes:
temp_dir: A temporary directory. temp_dir: A temporary directory.
@ -50,7 +50,7 @@ class GetStandardDirLinuxTests(unittest.TestCase):
with helpers.environ_set_temp({'XDG_DATA_HOME': self.temp_dir}): with helpers.environ_set_temp({'XDG_DATA_HOME': self.temp_dir}):
standarddir.init(None) standarddir.init(None)
expected = os.path.join(self.temp_dir, 'qutebrowser') expected = os.path.join(self.temp_dir, 'qutebrowser')
self.assertEqual(standarddir.data, expected) self.assertEqual(standarddir.data(), expected)
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux") @unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
def test_config_explicit(self): def test_config_explicit(self):
@ -58,7 +58,7 @@ class GetStandardDirLinuxTests(unittest.TestCase):
with helpers.environ_set_temp({'XDG_CONFIG_HOME': self.temp_dir}): with helpers.environ_set_temp({'XDG_CONFIG_HOME': self.temp_dir}):
standarddir.init(None) standarddir.init(None)
expected = os.path.join(self.temp_dir, 'qutebrowser') expected = os.path.join(self.temp_dir, 'qutebrowser')
self.assertEqual(standarddir.config, expected) self.assertEqual(standarddir.config(), expected)
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux") @unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
def test_cache_explicit(self): def test_cache_explicit(self):
@ -66,7 +66,7 @@ class GetStandardDirLinuxTests(unittest.TestCase):
with helpers.environ_set_temp({'XDG_CACHE_HOME': self.temp_dir}): with helpers.environ_set_temp({'XDG_CACHE_HOME': self.temp_dir}):
standarddir.init(None) standarddir.init(None)
expected = os.path.join(self.temp_dir, 'qutebrowser') expected = os.path.join(self.temp_dir, 'qutebrowser')
self.assertEqual(standarddir.cache, expected) self.assertEqual(standarddir.cache(), expected)
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux") @unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
def test_data(self): def test_data(self):
@ -76,7 +76,7 @@ class GetStandardDirLinuxTests(unittest.TestCase):
standarddir.init(None) standarddir.init(None)
expected = os.path.join(self.temp_dir, '.local', 'share', expected = os.path.join(self.temp_dir, '.local', 'share',
'qutebrowser') 'qutebrowser')
self.assertEqual(standarddir.data, expected) self.assertEqual(standarddir.data(), expected)
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux") @unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
def test_config(self): def test_config(self):
@ -85,7 +85,7 @@ class GetStandardDirLinuxTests(unittest.TestCase):
with helpers.environ_set_temp(env): with helpers.environ_set_temp(env):
standarddir.init(None) standarddir.init(None)
expected = os.path.join(self.temp_dir, '.config', 'qutebrowser') expected = os.path.join(self.temp_dir, '.config', 'qutebrowser')
self.assertEqual(standarddir.config, expected) self.assertEqual(standarddir.config(), expected)
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux") @unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
def test_cache(self): def test_cache(self):
@ -94,7 +94,7 @@ class GetStandardDirLinuxTests(unittest.TestCase):
with helpers.environ_set_temp(env): with helpers.environ_set_temp(env):
standarddir.init(None) standarddir.init(None)
expected = os.path.join(self.temp_dir, '.cache', 'qutebrowser') expected = os.path.join(self.temp_dir, '.cache', 'qutebrowser')
self.assertEqual(standarddir.cache, expected) self.assertEqual(standarddir.cache(), expected)
def tearDown(self): def tearDown(self):
qApp.setApplicationName(self.old_name) qApp.setApplicationName(self.old_name)
@ -103,7 +103,7 @@ class GetStandardDirLinuxTests(unittest.TestCase):
class GetStandardDirWindowsTests(unittest.TestCase): class GetStandardDirWindowsTests(unittest.TestCase):
"""Tests for standarddir.get under Windows. """Tests for standarddir under Windows.
Attributes: Attributes:
old_name: The old applicationName. old_name: The old applicationName.
@ -121,18 +121,18 @@ class GetStandardDirWindowsTests(unittest.TestCase):
@unittest.skipUnless(sys.platform.startswith("win"), "requires Windows") @unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")
def test_data(self): def test_data(self):
"""Test data dir.""" """Test data dir."""
self.assertEqual(standarddir.data.split(os.sep)[-2:], self.assertEqual(standarddir.data().split(os.sep)[-2:],
['qutebrowser_test', 'data'], standarddir.data) ['qutebrowser_test', 'data'], standarddir.data())
@unittest.skipUnless(sys.platform.startswith("win"), "requires Windows") @unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")
def test_config(self): def test_config(self):
"""Test config dir.""" """Test config dir."""
self.assertEqual(standarddir.config.split(os.sep)[-1], self.assertEqual(standarddir.config().split(os.sep)[-1],
'qutebrowser_test', 'qutebrowser_test',
standarddir.config) standarddir.config())
@unittest.skipUnless(sys.platform.startswith("win"), "requires Windows") @unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")
def test_cache(self): def test_cache(self):
"""Test cache dir.""" """Test cache dir."""
self.assertEqual(standarddir.cache.split(os.sep)[-2:], self.assertEqual(standarddir.cache().split(os.sep)[-2:],
['qutebrowser_test', 'cache'], standarddir.cache) ['qutebrowser_test', 'cache'], standarddir.cache())

View File

@ -27,11 +27,33 @@ from PyQt5.QtCore import QCoreApplication, QStandardPaths
from qutebrowser.utils import log, qtutils from qutebrowser.utils import log, qtutils
config = None # The argparse namespace passed to init()
data = None _args = None
cache = None
download = None
runtime = None def config():
"""Convenience function to get the config location."""
return _get(QStandardPaths.ConfigLocation)
def data():
"""Convenience function to get the data location."""
return _get(QStandardPaths.DataLocation)
def cache():
"""Convenience function to get the cache location."""
return _get(QStandardPaths.CacheLocation)
def download():
"""Convenience function to get the download location."""
return _get(QStandardPaths.DownloadLocation)
def runtime():
"""Convenience function to get the runtime location."""
return _get(QStandardPaths.RuntimeLocation)
def _writable_location(typ): def _writable_location(typ):
@ -75,16 +97,14 @@ def _from_args(typ, args):
return (True, arg_value) return (True, arg_value)
def _get(typ, args=None): def _get(typ):
"""Get the directory where files of the given type should be written to. """Get the directory where files of the given type should be written to.
Args: Args:
typ: A member of the QStandardPaths::StandardLocation enum, typ: A member of the QStandardPaths::StandardLocation enum,
see http://qt-project.org/doc/qt-5/qstandardpaths.html#StandardLocation-enum see http://qt-project.org/doc/qt-5/qstandardpaths.html#StandardLocation-enum
args: An argparse namespace which could be used to override the
locations.
""" """
overridden, path = _from_args(typ, args) overridden, path = _from_args(typ, _args)
if not overridden: if not overridden:
path = _writable_location(typ) path = _writable_location(typ)
appname = QCoreApplication.instance().applicationName() appname = QCoreApplication.instance().applicationName()
@ -101,6 +121,11 @@ def _get(typ, args=None):
QStandardPaths.ConfigLocation) QStandardPaths.ConfigLocation)
if data_path == config_path: if data_path == config_path:
path = os.path.join(path, 'data') path = os.path.join(path, 'data')
# From the XDG basedir spec:
# If, when attempting to write a file, the destination directory is
# non-existant an attempt should be made to create it with permission
# 0700. If the destination directory exists already the permissions
# should not be changed.
if path is not None and not os.path.exists(path): if path is not None and not os.path.exists(path):
os.makedirs(path, 0o700) os.makedirs(path, 0o700)
return path return path
@ -108,26 +133,10 @@ def _get(typ, args=None):
def init(args): def init(args):
"""Initialize all standard dirs.""" """Initialize all standard dirs."""
global config, data, cache, download, runtime global _args
config = _get(QStandardPaths.ConfigLocation, args) _args = args
data = _get(QStandardPaths.DataLocation, args)
cache = _get(QStandardPaths.CacheLocation, args)
download = _get(QStandardPaths.DownloadLocation, args)
runtime = _get(QStandardPaths.RuntimeLocation, args)
# From the XDG basedir spec:
# If, when attempting to write a file, the destination directory is
# non-existant an attempt should be made to create it with permission
# 0700. If the destination directory exists already the permissions
# should not be changed.
#
# This is slightly wrong according to the standard as we ensure these paths
# exists while initializing, not when writing the file - but practicality
# beats purity.
for path in (config, data, cache):
if path is not None and not os.path.exists(path):
os.makedirs(path, 0o700)
# http://www.brynosaurus.com/cachedir/spec.html # http://www.brynosaurus.com/cachedir/spec.html
cachedir_tag = os.path.join(cache, 'CACHEDIR.TAG') cachedir_tag = os.path.join(cache(), 'CACHEDIR.TAG')
if not os.path.exists(cachedir_tag): if not os.path.exists(cachedir_tag):
try: try:
with open(cachedir_tag, 'w', encoding='utf-8') as f: with open(cachedir_tag, 'w', encoding='utf-8') as f: