>From dbc9a4b304185e2cb0d9f425866f71161c9a1255 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Wed, 3 Aug 2022 11:27:21 +0200 Subject: [PATCH 02/12] 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. * pygnulib/*.py: Likewise. --- ChangeLog | 5 +++++ gnulib-tool.py | 3 ++- pygnulib/GLFileSystem.py | 7 ++++--- pygnulib/GLImport.py | 3 ++- pygnulib/GLTestDir.py | 5 +++-- pygnulib/constants.py | 22 ++++++++++++++++++++++ 6 files changed, 38 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index 419ea2fbd5..fe8225b5df 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2022-08-03 Bruno Haible + 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. + * pygnulib/*.py: Likewise. + gnulib-tool.py: Fix typo. * pygnulib/GLImport.py (GLImport.__init__): Use the relative auxdir as second, not as first argument of joinpath. diff --git a/gnulib-tool.py b/gnulib-tool.py index 302aaf3405..2ac522aa05 100755 --- a/gnulib-tool.py +++ b/gnulib-tool.py @@ -54,6 +54,7 @@ MODES = constants.MODES TESTS = constants.TESTS compiler = constants.compiler joinpath = constants.joinpath +copyfile = constants.copyfile isabs = os.path.isabs isdir = os.path.isdir isfile = os.path.isfile @@ -959,7 +960,7 @@ def main(): # Copy the file. assistant = classes.GLFileAssistant(config) tmpfile = assistant.tmpfilename(destpath) - shutil.copy(lookedup, tmpfile) + copyfile(lookedup, tmpfile) assistant.setOriginal(srcpath) assistant.config.setDestDir(destdir) assistant.setRewritten(destpath) diff --git a/pygnulib/GLFileSystem.py b/pygnulib/GLFileSystem.py index dfb1bb903f..5368f3c1b8 100644 --- a/pygnulib/GLFileSystem.py +++ b/pygnulib/GLFileSystem.py @@ -42,6 +42,7 @@ __copyright__ = constants.__copyright__ #=============================================================================== DIRS = constants.DIRS joinpath = constants.joinpath +copyfile = constants.copyfile isdir = os.path.isdir isfile = os.path.isfile @@ -118,7 +119,7 @@ class GLFileSystem(object): pass # Skip errors if directory exists if isfile(tempFile): os.remove(tempFile) - shutil.copy(lookedupFile, tempFile) + copyfile(lookedupFile, tempFile) for diff_in_localdir in reversed(lookedupPatches): command = 'patch -s "%s" < "%s" >&2' % (tempFile, diff_in_localdir) try: # Try to apply patch @@ -317,7 +318,7 @@ class GLFileAssistant(object): try: # Try to move file if os.path.exists(basepath): os.remove(basepath) - shutil.copy(tmpfile, rewritten) + copyfile(tmpfile, rewritten) except Exception as error: raise GLError(17, original) else: # if self.config['dryrun'] @@ -352,7 +353,7 @@ class GLFileAssistant(object): sed_transform_testsrelated_lib_file = self.transformers.get( 'tests', '') try: # Try to copy lookedup file to tmpfile - shutil.copy(lookedup, tmpfile) + copyfile(lookedup, tmpfile) except Exception as error: raise GLError(15, lookedup) # Don't process binary files with sed. diff --git a/pygnulib/GLImport.py b/pygnulib/GLImport.py index 5009917e76..cbee0c4f33 100644 --- a/pygnulib/GLImport.py +++ b/pygnulib/GLImport.py @@ -52,6 +52,7 @@ TESTS = constants.TESTS compiler = constants.compiler joinpath = constants.joinpath cleaner = constants.cleaner +copyfile2 = constants.copyfile2 isabs = os.path.isabs isdir = os.path.isdir isfile = os.path.isfile @@ -734,7 +735,7 @@ AC_DEFUN([%s_FILE_LIST], [\n''' % macro_prefix if not self.config['dryrun']: print('Updating %s (backup in %s)' % (srcpath, backupname)) - shutil.copy2(srcpath, backupname) + copyfile2(srcpath, backupname) result = '' with codecs.open(srcpath, 'ab', 'UTF-8') as file: file.write(destdata) diff --git a/pygnulib/GLTestDir.py b/pygnulib/GLTestDir.py index 36aa5d2117..c230fbc744 100644 --- a/pygnulib/GLTestDir.py +++ b/pygnulib/GLTestDir.py @@ -53,6 +53,7 @@ UTILS = constants.UTILS TESTS = constants.TESTS compiler = constants.compiler joinpath = constants.joinpath +copyfile = constants.copyfile isdir = os.path.isdir isfile = os.path.isfile normpath = os.path.normpath @@ -333,12 +334,12 @@ class GLTestDir(object): if isfile(destpath): os.remove(destpath) if flag: - shutil.copy(lookedup, destpath) + copyfile(lookedup, destpath) else: # if not flag if self.filesystem.shouldLink(src, lookedup) == CopyAction.Symlink: constants.link_relative(lookedup, destpath) else: - shutil.copy(lookedup, destpath) + copyfile(lookedup, destpath) # Create $sourcebase/Makefile.am. for_test = True diff --git a/pygnulib/constants.py b/pygnulib/constants.py index 91a2958eb3..cf6f05eb98 100644 --- a/pygnulib/constants.py +++ b/pygnulib/constants.py @@ -23,6 +23,7 @@ import re import os import sys import platform +import shutil import tempfile import subprocess as sp import __main__ as interpreter @@ -303,6 +304,27 @@ def relconcat(dir1, dir2): return os.path.normpath(os.path.join(dir1, dir2)) +def copyfile(src, dest): + '''Copy file src to file dest. Like shutil.copy, but ignore errors e.g. on + VFAT file systems.''' + shutil.copyfile(src, dest) + try: + shutil.copymode(src, dest) + except PermissionError: + pass + + +def copyfile2(src, dest): + '''Copy file src to file dest, preserving modification time. Like + shutil.copy2, but ignore errors e.g. on VFAT file systems. This function + is to be used for backup files.''' + shutil.copyfile(src, dest) + try: + shutil.copystat(src, dest) + except PermissionError: + pass + + 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