Save to disk: When saving to a single directory, handle the case of the save to disk template containing path separators inside template expression correctly. Fixes #821912 (save only epub on disc using one folder file-name-error)

This commit is contained in:
Kovid Goyal 2011-08-06 12:32:02 -06:00
commit dc58208164
3 changed files with 33 additions and 11 deletions

View File

@ -50,7 +50,7 @@ class SaveToDiskAction(InterfaceAction):
cm('single format', _('Save only %s format to disk')%
prefs['output_format'].upper(),
triggered=partial(self.save_single_format_to_disk, False))
cm('fingle dir and format',
cm('single dir and format',
_('Save only %s format to disk in a single directory')%
prefs['output_format'].upper(),
triggered=partial(self.save_single_fmt_to_single_dir, False))
@ -115,10 +115,7 @@ class SaveToDiskAction(InterfaceAction):
opts.save_cover = False
opts.write_opf = False
opts.template = opts.send_template
if single_dir:
opts.template = opts.template.split('/')[-1].strip()
if not opts.template:
opts.template = '{title} - {authors}'
opts.single_dir = single_dir
self._saver = Saver(self.gui, self.gui.library_view.model().db,
Dispatcher(self._books_saved), rows, path, opts,
spare_server=self.gui.spare_server)

View File

@ -121,6 +121,9 @@ def config(defaults=None):
help=_('Convert paths to lowercase.'))
x('replace_whitespace', default=False,
help=_('Replace whitespace with underscores.'))
x('single_dir', default=False,
help=_('Save into a single directory, ignoring the template'
' directory structure'))
return c
def preprocess_template(template):
@ -131,7 +134,7 @@ def preprocess_template(template):
template = template.decode(preferred_encoding, 'replace')
return template
class SafeFormat(TemplateFormatter):
class Formatter(TemplateFormatter):
'''
Provides a format function that substitutes '' for any missing value
'''
@ -165,7 +168,7 @@ class SafeFormat(TemplateFormatter):
def get_components(template, mi, id, timefmt='%b %Y', length=250,
sanitize_func=ascii_filename, replace_whitespace=False,
to_lowercase=False):
to_lowercase=False, safe_format=True):
tsorder = tweaks['save_template_title_series_sorting']
format_args = FORMAT_ARGS.copy()
@ -225,8 +228,11 @@ def get_components(template, mi, id, timefmt='%b %Y', length=250,
format_args[key] = unicode(format_args[key])
else:
format_args[key] = ''
components = SafeFormat().safe_format(template, format_args,
if safe_format:
components = Formatter().safe_format(template, format_args,
'G_C-EXCEPTION!', mi)
else:
components = Formatter().unsafe_format(template, format_args, mi)
components = [x.strip() for x in components.split('/')]
components = [sanitize_func(x) for x in components if x]
if not components:
@ -283,10 +289,20 @@ def do_save_book_to_disk(id_, mi, cover, plugboards,
if not formats:
return True, id_, mi.title
try:
components = get_components(opts.template, mi, id_, opts.timefmt, length,
ascii_filename if opts.asciiize else sanitize_file_name_unicode,
to_lowercase=opts.to_lowercase,
replace_whitespace=opts.replace_whitespace)
replace_whitespace=opts.replace_whitespace, safe_format=False)
except Exception, e:
raise ValueError(_('Failed to calculate path for '
'save to disk. Template: %s\n'
'Error: %s'%(opts.template, e)))
if opts.single_dir:
components = components[-1:]
if not components:
raise ValueError(_('Template evaluation resulted in no'
' path components. Template: %s')%opts.template)
base_path = os.path.join(root, *components)
base_name = os.path.basename(base_path)
dirpath = os.path.dirname(base_path)

View File

@ -310,7 +310,16 @@ class TemplateFormatter(string.Formatter):
ans = string.Formatter.vformat(self, fmt, args, kwargs)
return self.compress_spaces.sub(' ', ans).strip()
########## a formatter guaranteed not to throw and exception ############
########## a formatter that throws exceptions ############
def unsafe_format(self, fmt, kwargs, book):
self.kwargs = kwargs
self.book = book
self.composite_values = {}
self.locals = {}
return self.vformat(fmt, [], kwargs).strip()
########## a formatter guaranteed not to throw an exception ############
def safe_format(self, fmt, kwargs, error_value, book):
self.kwargs = kwargs