Handle file renames that only change case on case-insensitive file-systems

This commit is contained in:
Kovid Goyal 2013-11-30 12:51:25 +05:30
parent b5218ca772
commit 510a6bac6e
3 changed files with 16 additions and 4 deletions

View File

@ -214,12 +214,13 @@ class Container(object): # {{{
should be done once, in bulk. ''' should be done once, in bulk. '''
if current_name in self.names_that_must_not_be_changed: if current_name in self.names_that_must_not_be_changed:
raise ValueError('Renaming of %s is not allowed' % current_name) raise ValueError('Renaming of %s is not allowed' % current_name)
if self.exists(new_name): if self.exists(new_name) and (new_name == current_name or new_name.lower() != current_name.lower()):
raise ValueError('Cannot rename %s to %s as %s already exists' % (self.opf_name, new_name, new_name)) # The destination exists and does not differ from the current name only by case
raise ValueError('Cannot rename %s to %s as %s already exists' % (current_name, new_name, new_name))
new_path = self.name_to_abspath(new_name) new_path = self.name_to_abspath(new_name)
base = os.path.dirname(new_path) base = os.path.dirname(new_path)
if os.path.isfile(base): if os.path.isfile(base):
raise ValueError('Cannot rename %s to %s as %s is a file' % (self.opf_name, new_name, base)) raise ValueError('Cannot rename %s to %s as %s is a file' % (current_name, new_name, base))
if not os.path.exists(base): if not os.path.exists(base):
os.makedirs(base) os.makedirs(base)
old_path = parent_dir = self.name_to_abspath(current_name) old_path = parent_dir = self.name_to_abspath(current_name)

View File

@ -109,6 +109,9 @@ def rename_files(container, file_map):
raise ValueError('Circular rename detected. The files %s are both rename targets and destinations' % ', '.join(overlap)) raise ValueError('Circular rename detected. The files %s are both rename targets and destinations' % ', '.join(overlap))
for name, dest in file_map.iteritems(): for name, dest in file_map.iteritems():
if container.exists(dest): if container.exists(dest):
if name != dest and name.lower() == dest.lower():
# A case change on an OS with a case insensitive file-system.
continue
raise ValueError('Cannot rename {0} to {1} as {1} already exists'.format(name, dest)) raise ValueError('Cannot rename {0} to {1} as {1} already exists'.format(name, dest))
if len(tuple(file_map.itervalues())) != len(set(file_map.itervalues())): if len(tuple(file_map.itervalues())) != len(set(file_map.itervalues())):
raise ValueError('Cannot rename, the set of destination files contains duplicates') raise ValueError('Cannot rename, the set of destination files contains duplicates')

View File

@ -149,7 +149,10 @@ class ContainerTests(BaseTest):
# Test renaming of font files # Test renaming of font files
c = new_container() c = new_container()
rename_files(c, {'LiberationMono-Regular.ttf': 'fonts/LiberationMono Regular.ttf'}) fname = 'LiberationMono-Regular.ttf'
if fname not in c.name_path_map:
fname = fname.lower() # On OS X the font file name is lowercased for some reason (maybe on windows too)
rename_files(c, {fname: 'fonts/LiberationMono Regular.ttf'})
self.check_links(c) self.check_links(c)
# Test renaming of text files # Test renaming of text files
@ -157,6 +160,11 @@ class ContainerTests(BaseTest):
rename_files(c, {'index_split_000.html':'text/page one fällen.html', 'index_split_001.html':'text/page two fällen.html'}) rename_files(c, {'index_split_000.html':'text/page one fällen.html', 'index_split_001.html':'text/page two fällen.html'})
self.check_links(c) self.check_links(c)
# Test rename with only case change
c = new_container()
rename_files(c, {'index_split_000.html':'Index_split_000.html'})
self.check_links(c)
# self.run_external_tools(c, gvim=True) # self.run_external_tools(c, gvim=True)
def test_file_add(self): def test_file_add(self):