Remove support for importing pre-v1.0.0 history
This commit is contained in:
parent
ec774379bd
commit
d4f16f88b6
@ -185,8 +185,6 @@ def init(args, crash_handler):
|
|||||||
QDesktopServices.setUrlHandler('https', open_desktopservices_url)
|
QDesktopServices.setUrlHandler('https', open_desktopservices_url)
|
||||||
QDesktopServices.setUrlHandler('qute', open_desktopservices_url)
|
QDesktopServices.setUrlHandler('qute', open_desktopservices_url)
|
||||||
|
|
||||||
objreg.get('web-history').import_txt()
|
|
||||||
|
|
||||||
log.init.debug("Init done!")
|
log.init.debug("Init done!")
|
||||||
crash_handler.raise_crashdlg()
|
crash_handler.raise_crashdlg()
|
||||||
|
|
||||||
|
@ -338,108 +338,6 @@ class WebHistory(sql.SqlTable):
|
|||||||
'last_atime': atime
|
'last_atime': atime
|
||||||
}, replace=True)
|
}, replace=True)
|
||||||
|
|
||||||
def _parse_entry(self, line):
|
|
||||||
"""Parse a history line like '12345 http://example.com title'."""
|
|
||||||
if not line or line.startswith('#'):
|
|
||||||
return None
|
|
||||||
data = line.split(maxsplit=2)
|
|
||||||
if len(data) == 2:
|
|
||||||
atime, url = data
|
|
||||||
title = ""
|
|
||||||
elif len(data) == 3:
|
|
||||||
atime, url, title = data
|
|
||||||
else:
|
|
||||||
raise ValueError("2 or 3 fields expected")
|
|
||||||
|
|
||||||
# http://xn--pple-43d.com/ with
|
|
||||||
# https://bugreports.qt.io/browse/QTBUG-60364
|
|
||||||
if url in ['http://.com/', 'https://.com/',
|
|
||||||
'http://www..com/', 'https://www..com/']:
|
|
||||||
return None
|
|
||||||
|
|
||||||
url = QUrl(url)
|
|
||||||
if not url.isValid():
|
|
||||||
raise ValueError("Invalid URL: {}".format(url.errorString()))
|
|
||||||
|
|
||||||
# https://github.com/qutebrowser/qutebrowser/issues/2646
|
|
||||||
if url.scheme() == 'data':
|
|
||||||
return None
|
|
||||||
|
|
||||||
# https://github.com/qutebrowser/qutebrowser/issues/670
|
|
||||||
atime = atime.lstrip('\0')
|
|
||||||
|
|
||||||
if '-' in atime:
|
|
||||||
atime, flags = atime.split('-')
|
|
||||||
else:
|
|
||||||
flags = ''
|
|
||||||
|
|
||||||
if not set(flags).issubset('r'):
|
|
||||||
raise ValueError("Invalid flags {!r}".format(flags))
|
|
||||||
|
|
||||||
redirect = 'r' in flags
|
|
||||||
return (url, title, int(atime), redirect)
|
|
||||||
|
|
||||||
def import_txt(self):
|
|
||||||
"""Import a history text file into sqlite if it exists.
|
|
||||||
|
|
||||||
In older versions of qutebrowser, history was stored in a text format.
|
|
||||||
This converts that file into the new sqlite format and moves it to a
|
|
||||||
backup location.
|
|
||||||
"""
|
|
||||||
path = os.path.join(standarddir.data(), 'history')
|
|
||||||
if not os.path.isfile(path):
|
|
||||||
return
|
|
||||||
|
|
||||||
def action():
|
|
||||||
"""Actually run the import."""
|
|
||||||
with debug.log_time(log.init, 'Import old history file to sqlite'):
|
|
||||||
try:
|
|
||||||
self._read(path)
|
|
||||||
except ValueError as ex:
|
|
||||||
message.error('Failed to import history: {}'.format(ex))
|
|
||||||
else:
|
|
||||||
self._write_backup(path)
|
|
||||||
|
|
||||||
# delay to give message time to appear before locking down for import
|
|
||||||
message.info('Converting {} to sqlite...'.format(path))
|
|
||||||
QTimer.singleShot(100, action)
|
|
||||||
|
|
||||||
def _read(self, path):
|
|
||||||
"""Import a text file into the sql database."""
|
|
||||||
with open(path, 'r', encoding='utf-8') as f:
|
|
||||||
data = {'url': [], 'title': [], 'atime': [], 'redirect': []}
|
|
||||||
completion_data = {'url': [], 'title': [], 'last_atime': []}
|
|
||||||
for (i, line) in enumerate(f):
|
|
||||||
try:
|
|
||||||
parsed = self._parse_entry(line.strip())
|
|
||||||
if parsed is None:
|
|
||||||
continue
|
|
||||||
url, title, atime, redirect = parsed
|
|
||||||
data['url'].append(self._format_url(url))
|
|
||||||
data['title'].append(title)
|
|
||||||
data['atime'].append(atime)
|
|
||||||
data['redirect'].append(redirect)
|
|
||||||
if not redirect:
|
|
||||||
completion_data['url'].append(
|
|
||||||
self._format_completion_url(url))
|
|
||||||
completion_data['title'].append(title)
|
|
||||||
completion_data['last_atime'].append(atime)
|
|
||||||
except ValueError as ex:
|
|
||||||
raise ValueError('Failed to parse line #{} of {}: "{}"'
|
|
||||||
.format(i, path, ex))
|
|
||||||
self.insert_batch(data)
|
|
||||||
self.completion.insert_batch(completion_data, replace=True)
|
|
||||||
|
|
||||||
def _write_backup(self, path):
|
|
||||||
bak = path + '.bak'
|
|
||||||
message.info('History import complete. Appending {} to {}'
|
|
||||||
.format(path, bak))
|
|
||||||
with open(path, 'r', encoding='utf-8') as infile:
|
|
||||||
with open(bak, 'a', encoding='utf-8') as outfile:
|
|
||||||
for line in infile:
|
|
||||||
outfile.write('\n' + line)
|
|
||||||
os.remove(path)
|
|
||||||
|
|
||||||
def _format_url(self, url):
|
def _format_url(self, url):
|
||||||
return url.toString(QUrl.RemovePassword | QUrl.FullyEncoded)
|
return url.toString(QUrl.RemovePassword | QUrl.FullyEncoded)
|
||||||
|
|
||||||
|
@ -323,99 +323,6 @@ class TestInit:
|
|||||||
assert default_interface is None
|
assert default_interface is None
|
||||||
|
|
||||||
|
|
||||||
class TestImport:
|
|
||||||
|
|
||||||
def test_import_txt(self, hist, data_tmpdir, monkeypatch, stubs):
|
|
||||||
monkeypatch.setattr(history, 'QTimer', stubs.InstaTimer)
|
|
||||||
histfile = data_tmpdir / 'history'
|
|
||||||
# empty line is deliberate, to test skipping empty lines
|
|
||||||
histfile.write('''12345 http://example.com/ title
|
|
||||||
12346 http://qutebrowser.org/
|
|
||||||
67890 http://example.com/path
|
|
||||||
|
|
||||||
68891-r http://example.com/path/other ''')
|
|
||||||
|
|
||||||
hist.import_txt()
|
|
||||||
|
|
||||||
assert list(hist) == [
|
|
||||||
('http://example.com/', 'title', 12345, False),
|
|
||||||
('http://qutebrowser.org/', '', 12346, False),
|
|
||||||
('http://example.com/path', '', 67890, False),
|
|
||||||
('http://example.com/path/other', '', 68891, True)
|
|
||||||
]
|
|
||||||
|
|
||||||
assert not histfile.exists()
|
|
||||||
assert (data_tmpdir / 'history.bak').exists()
|
|
||||||
|
|
||||||
def test_existing_backup(self, hist, data_tmpdir, monkeypatch, stubs):
|
|
||||||
monkeypatch.setattr(history, 'QTimer', stubs.InstaTimer)
|
|
||||||
histfile = data_tmpdir / 'history'
|
|
||||||
bakfile = data_tmpdir / 'history.bak'
|
|
||||||
histfile.write('12345 http://example.com/ title')
|
|
||||||
bakfile.write('12346 http://qutebrowser.org/')
|
|
||||||
|
|
||||||
hist.import_txt()
|
|
||||||
|
|
||||||
assert list(hist) == [('http://example.com/', 'title', 12345, False)]
|
|
||||||
|
|
||||||
assert not histfile.exists()
|
|
||||||
assert bakfile.read().split('\n') == ['12346 http://qutebrowser.org/',
|
|
||||||
'12345 http://example.com/ title']
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('line', [
|
|
||||||
'',
|
|
||||||
'#12345 http://example.com/commented',
|
|
||||||
|
|
||||||
# https://bugreports.qt.io/browse/QTBUG-60364
|
|
||||||
'12345 http://.com/',
|
|
||||||
'12345 https://.com/',
|
|
||||||
'12345 http://www..com/',
|
|
||||||
'12345 https://www..com/',
|
|
||||||
|
|
||||||
# issue #2646
|
|
||||||
('12345 data:text/html;'
|
|
||||||
'charset=UTF-8,%3C%21DOCTYPE%20html%20PUBLIC%20%22-'),
|
|
||||||
])
|
|
||||||
def test_skip(self, hist, data_tmpdir, monkeypatch, stubs, line):
|
|
||||||
"""import_txt should skip certain lines silently."""
|
|
||||||
monkeypatch.setattr(history, 'QTimer', stubs.InstaTimer)
|
|
||||||
histfile = data_tmpdir / 'history'
|
|
||||||
histfile.write(line)
|
|
||||||
|
|
||||||
hist.import_txt()
|
|
||||||
|
|
||||||
assert not histfile.exists()
|
|
||||||
assert not len(hist)
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('line', [
|
|
||||||
'xyz http://example.com/bad-timestamp',
|
|
||||||
'12345',
|
|
||||||
'http://example.com/no-timestamp',
|
|
||||||
'68891-r-r http://example.com/double-flag',
|
|
||||||
'68891-x http://example.com/bad-flag',
|
|
||||||
'68891 http://.com',
|
|
||||||
])
|
|
||||||
def test_invalid(self, hist, data_tmpdir, monkeypatch, stubs, caplog,
|
|
||||||
line):
|
|
||||||
"""import_txt should fail on certain lines."""
|
|
||||||
monkeypatch.setattr(history, 'QTimer', stubs.InstaTimer)
|
|
||||||
histfile = data_tmpdir / 'history'
|
|
||||||
histfile.write(line)
|
|
||||||
|
|
||||||
with caplog.at_level(logging.ERROR):
|
|
||||||
hist.import_txt()
|
|
||||||
|
|
||||||
assert any(rec.msg.startswith("Failed to import history:")
|
|
||||||
for rec in caplog.records)
|
|
||||||
|
|
||||||
assert histfile.exists()
|
|
||||||
|
|
||||||
def test_nonexistent(self, hist, data_tmpdir, monkeypatch, stubs):
|
|
||||||
"""import_txt should do nothing if the history file doesn't exist."""
|
|
||||||
monkeypatch.setattr(history, 'QTimer', stubs.InstaTimer)
|
|
||||||
hist.import_txt()
|
|
||||||
|
|
||||||
|
|
||||||
class TestDump:
|
class TestDump:
|
||||||
|
|
||||||
def test_debug_dump_history(self, hist, tmpdir):
|
def test_debug_dump_history(self, hist, tmpdir):
|
||||||
|
Loading…
Reference in New Issue
Block a user