>From ed7b3d9bb825644533235fcc636134bc8bc368f2 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Wed, 3 Aug 2022 14:27:51 +0200 Subject: [PATCH 03/12] gnulib-tool.py: Avoid errors when writing to a VFAT file system, part 2. * pygnulib/constants.py (movefile): New function. * pygnulib/*.py: Use it instead of shutil. --- ChangeLog | 4 ++++ pygnulib/GLFileSystem.py | 11 ++++++----- pygnulib/GLImport.py | 5 +++-- pygnulib/GLTestDir.py | 5 +++-- pygnulib/constants.py | 13 +++++++++++++ 5 files changed, 29 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index fe8225b5df..aeec6717fc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2022-08-03 Bruno Haible + gnulib-tool.py: Avoid errors when writing to a VFAT file system, part 2. + * pygnulib/constants.py (movefile): New function. + * pygnulib/*.py: Use it instead of shutil. + gnulib-tool.py: Avoid errors when writing to a VFAT file system. * pygnulib/constants.py (copyfile, copyfile2): New functions. * gnulib-tool.py: Use them instead of shutil. diff --git a/pygnulib/GLFileSystem.py b/pygnulib/GLFileSystem.py index 5368f3c1b8..1f7a9f2343 100644 --- a/pygnulib/GLFileSystem.py +++ b/pygnulib/GLFileSystem.py @@ -43,6 +43,7 @@ __copyright__ = constants.__copyright__ DIRS = constants.DIRS joinpath = constants.joinpath copyfile = constants.copyfile +movefile = constants.movefile isdir = os.path.isdir isfile = os.path.isfile @@ -266,7 +267,7 @@ class GLFileAssistant(object): lookedup, joinpath(destdir, rewritten)) else: # if any of these conditions is not met try: # Try to move file - shutil.move(tmpfile, joinpath(destdir, rewritten)) + movefile(tmpfile, joinpath(destdir, rewritten)) except Exception as error: raise GLError(17, original) else: # if self.config['dryrun'] @@ -308,7 +309,7 @@ class GLFileAssistant(object): if isfile(backuppath): os.remove(backuppath) try: # Try to replace the given file - shutil.move(basepath, backuppath) + movefile(basepath, backuppath) except Exception as error: raise GLError(17, original) if self.filesystem.shouldLink(original, lookedup) == CopyAction.Symlink \ @@ -405,8 +406,8 @@ class GLFileAssistant(object): if not self.config['dryrun']: if isfile(backuppath): os.remove(backuppath) - shutil.move(basepath, backuppath) - shutil.move(tmpfile, basepath) + movefile(basepath, backuppath) + movefile(tmpfile, basepath) else: # if self.config['dryrun'] os.remove(tmpfile) else: # if not isfile(basepath) @@ -414,7 +415,7 @@ class GLFileAssistant(object): if not self.config['dryrun']: if isfile(basepath): os.remove(basepath) - shutil.move(tmpfile, basepath) + movefile(tmpfile, basepath) else: # if self.config['dryrun'] os.remove(tmpfile) result = tuple([basename, backupname, result_flag]) diff --git a/pygnulib/GLImport.py b/pygnulib/GLImport.py index cbee0c4f33..046cf4745d 100644 --- a/pygnulib/GLImport.py +++ b/pygnulib/GLImport.py @@ -53,6 +53,7 @@ compiler = constants.compiler joinpath = constants.joinpath cleaner = constants.cleaner copyfile2 = constants.copyfile2 +movefile = constants.movefile isabs = os.path.isabs isdir = os.path.isdir isfile = os.path.isfile @@ -1043,7 +1044,7 @@ AC_DEFUN([%s_FILE_LIST], [\n''' % macro_prefix try: # Try to move file if os.path.exists(backup): os.remove(backup) - shutil.move(path, '%s~' % path) + movefile(path, '%s~' % path) except Exception as error: raise GLError(14, file) else: # if self.config['dryrun'] @@ -1143,7 +1144,7 @@ AC_DEFUN([%s_FILE_LIST], [\n''' % macro_prefix tmpfile = self.assistant.tmpfilename(joinpath(pobase, file)) path = joinpath('build-aux', 'po', file) lookedup, flag = filesystem.lookup(path) - shutil.move(lookedup, tmpfile) + movefile(lookedup, tmpfile) basename = joinpath(pobase, file) filename, backup, flag = self.assistant.super_update( basename, tmpfile) diff --git a/pygnulib/GLTestDir.py b/pygnulib/GLTestDir.py index c230fbc744..9065e462fa 100644 --- a/pygnulib/GLTestDir.py +++ b/pygnulib/GLTestDir.py @@ -54,6 +54,7 @@ TESTS = constants.TESTS compiler = constants.compiler joinpath = constants.joinpath copyfile = constants.copyfile +movefile = constants.movefile isdir = os.path.isdir isfile = os.path.isfile normpath = os.path.normpath @@ -658,7 +659,7 @@ class GLTestDir(object): dest = src[:-1] if isfile(dest): os.remove(dest) - shutil.move(src, dest) + movefile(src, dest) # libtoolize if libtool: args = [UTILS['libtoolize'], '--copy'] @@ -692,7 +693,7 @@ class GLTestDir(object): dest = src[:-1] if isfile(dest): os.remove(dest) - shutil.move(src, dest) + movefile(src, dest) # aclocal args = [UTILS['aclocal'], '-I', joinpath('..', m4base)] constants.execute(args, verbose) diff --git a/pygnulib/constants.py b/pygnulib/constants.py index cf6f05eb98..34c17aec46 100644 --- a/pygnulib/constants.py +++ b/pygnulib/constants.py @@ -325,6 +325,19 @@ def copyfile2(src, dest): pass +def movefile(src, dest): + '''Move/rename file src to file dest. Like shutil.move, but gracefully + handle common errors.''' + try: + shutil.move(src, dest) + except PermissionError: + # shutil.move invokes os.rename, catches the resulting OSError for + # errno=EXDEV, attempts a copy instead, and encounters a PermissionError + # while doing that. + copyfile2(src, dest) + os.remove(src) + + def link_relative(src, dest): '''Like ln -s, except that src is given relative to the current directory (or absolute), not given relative to the directory of dest.''' -- 2.34.1