Prompt for non-existing download directories.

Closes #2120
This commit is contained in:
Panagiotis K 2017-10-11 13:40:53 +03:00
parent abbd69f604
commit 0a753915ff
4 changed files with 67 additions and 4 deletions

View File

@ -27,6 +27,7 @@ import collections
import functools import functools
import pathlib import pathlib
import tempfile import tempfile
import errno
import sip import sip
from PyQt5.QtCore import (pyqtSlot, pyqtSignal, Qt, QObject, QModelIndex, from PyQt5.QtCore import (pyqtSlot, pyqtSignal, Qt, QObject, QModelIndex,
@ -137,7 +138,8 @@ def create_full_filename(basename, filename):
encoding = sys.getfilesystemencoding() encoding = sys.getfilesystemencoding()
filename = utils.force_encoding(filename, encoding) filename = utils.force_encoding(filename, encoding)
basename = utils.force_encoding(basename, encoding) basename = utils.force_encoding(basename, encoding)
if os.path.isabs(filename) and os.path.isdir(filename): if os.path.isabs(filename) and (os.path.isdir(filename) or
os.path.join(filename, "") == filename):
# We got an absolute directory from the user, so we save it under # We got an absolute directory from the user, so we save it under
# the default filename in that directory. # the default filename in that directory.
return os.path.join(filename, basename) return os.path.join(filename, basename)
@ -657,11 +659,42 @@ class AbstractDownloadItem(QObject):
self._filename = create_full_filename(self.basename, self._filename = create_full_filename(self.basename,
os.path.expanduser('~')) os.path.expanduser('~'))
dirname = os.path.dirname(self._filename)
if not os.path.exists(dirname):
txt = ("<b>{}</b> does not exist. Create it?".
format(html.escape(
os.path.join(dirname, ""))))
self._ask_create_parent_question("Create directory?", txt,
force_overwrite,
remember_directory)
else:
self._after_create_parent_question(force_overwrite,
remember_directory)
def _after_create_parent_question(self,
force_overwrite, remember_directory):
"""After asking about parent directory.
Args:
force_overwrite: Force overwriting existing files.
remember_directory: If True, remember the directory for future
downloads.
"""
global last_used_directory
try:
os.makedirs(os.path.dirname(self._filename))
except OSError as e:
# Unlikely, but could be created before
# we get a chance to create it.
if e.errno != errno.EEXIST:
raise
self.basename = os.path.basename(self._filename) self.basename = os.path.basename(self._filename)
if remember_directory: if remember_directory:
last_used_directory = os.path.dirname(self._filename) last_used_directory = os.path.dirname(self._filename)
log.downloads.debug("Setting filename to {}".format(filename)) log.downloads.debug("Setting filename to {}".format(self._filename))
if force_overwrite: if force_overwrite:
self._after_set_filename() self._after_set_filename()
elif os.path.isfile(self._filename): elif os.path.isfile(self._filename):

View File

@ -203,6 +203,17 @@ class DownloadItem(downloads.AbstractDownloadItem):
no_action=no_action, cancel_action=no_action, no_action=no_action, cancel_action=no_action,
abort_on=[self.cancelled, self.error]) abort_on=[self.cancelled, self.error])
def _ask_create_parent_question(self, title, msg,
force_overwrite, remember_directory):
no_action = functools.partial(self.cancel, remove_data=False)
message.confirm_async(title=title, text=msg,
yes_action=(lambda:
self._after_create_parent_question(
force_overwrite,
remember_directory)),
no_action=no_action, cancel_action=no_action,
abort_on=[self.cancelled, self.error])
def _set_fileobj(self, fileobj, *, autoclose=True): def _set_fileobj(self, fileobj, *, autoclose=True):
""""Set the file object to write the download to. """"Set the file object to write the download to.

View File

@ -120,6 +120,22 @@ class DownloadItem(downloads.AbstractDownloadItem):
"state {} (not in requested state)!".format( "state {} (not in requested state)!".format(
filename, self, state_name)) filename, self, state_name))
def _ask_create_parent_question(self, title, msg,
force_overwrite, remember_directory):
no_action = functools.partial(self.cancel, remove_data=False)
question = usertypes.Question()
question.title = title
question.text = msg
question.mode = usertypes.PromptMode.yesno
question.answered_yes.connect(lambda:
self._after_create_parent_question(
force_overwrite, remember_directory))
question.answered_no.connect(no_action)
question.cancelled.connect(no_action)
self.cancelled.connect(question.abort)
self.error.connect(question.abort)
message.global_bridge.ask(question, blocking=True)
def _ask_confirm_question(self, title, msg): def _ask_confirm_question(self, title, msg):
no_action = functools.partial(self.cancel, remove_data=False) no_action = functools.partial(self.cancel, remove_data=False)
question = usertypes.Question() question = usertypes.Question()

View File

@ -256,8 +256,11 @@ Feature: Downloading things from a website.
Then the error "Can only download the current page as mhtml." should be shown Then the error "Can only download the current page as mhtml." should be shown
Scenario: :download with a directory which doesn't exist Scenario: :download with a directory which doesn't exist
When I run :download --dest (tmpdir)/downloads/somedir/filename http://localhost:(port)/ When I run :download --dest (tmpdir)/downloads/somedir/filename http://localhost:(port)/data/downloads/download.bin
Then the error "Download error: No such file or directory" should be shown And I wait for "Asking question <qutebrowser.utils.usertypes.Question default=None mode=<PromptMode.yesno: 1> text='<b>*</b> does not exist. Create it?' title='Create directory?'>, *" in the log
And I run :prompt-accept yes
And I wait until the download filename is finished
Then the downloaded file filename should not exist
## mhtml downloads ## mhtml downloads