bug-gnulib@gnu.org mirror (unofficial)
 help / color / mirror / Atom feed
From: Bruno Haible <bruno@clisp.org>
To: bug-gnulib@gnu.org
Subject: gnulib-tool.py: Refactor directory tree removals
Date: Sat, 13 Apr 2024 12:17:58 +0200	[thread overview]
Message-ID: <8092948.IHYaepM4ed@nimes> (raw)

There are two ways to remove a directory tree: via 'rm -rf' and through
shutil.rmtree. The former is ca. 10% faster on average. Also, it is more
likely to include platform-specific optimizations. So, let's use it.


2024-04-13  Bruno Haible  <bruno@clisp.org>

	gnulib-tool.py: Refactor directory tree removals.
	* pygnulib/constants.py (rmtree): New function.
	* pygnulib/GLImport.py (GLImport.execute): Use it instead of calling
	'rm -rf' directly or shutil.rmtree.
	* pygnulib/GLTestDir.py (GLTestDir.execute, GLMegaTestDir.execute):
	Likewise.
	* pygnulib/main.py (main): Likewise.

diff --git a/gnulib-tool.py.TODO b/gnulib-tool.py.TODO
index 368c0addac..1eada15429 100644
--- a/gnulib-tool.py.TODO
+++ b/gnulib-tool.py.TODO
@@ -10,7 +10,6 @@ Optimize:
 
 Various other refactorings, as deemed useful:
   - Use an enum for 'all', 'old', 'new', 'added', 'removed' in GLImport.py.
-  - sp.call(['rm', '-rf' ...]) versus shutil.rmtree ?
   - go through all the open() and codecs.open() calls and turn them into
         with open(file_name, 'r', newline='\n', encoding='utf-8') as file:
     or
diff --git a/pygnulib/GLImport.py b/pygnulib/GLImport.py
index d45cf6b3ba..3d694a7919 100644
--- a/pygnulib/GLImport.py
+++ b/pygnulib/GLImport.py
@@ -1466,4 +1466,4 @@ in <library>_a_LDFLAGS or <library>_la_LDFLAGS when linking a library.''')
             position_early_after = 'AC_PROG_CC'
         print('  - invoke %s_EARLY in %s, right after %s,' % (macro_prefix, configure_ac, position_early_after))
         print('  - invoke %s_INIT in %s.' % (macro_prefix, configure_ac))
-        sp.call(['rm', '-rf', self.config['tempdir']], shell=False)
+        constants.rmtree(self.config['tempdir'])
diff --git a/pygnulib/GLTestDir.py b/pygnulib/GLTestDir.py
index 5fd4197e52..be61d58b52 100644
--- a/pygnulib/GLTestDir.py
+++ b/pygnulib/GLTestDir.py
@@ -23,7 +23,6 @@ import re
 import sys
 import codecs
 import subprocess as sp
-import shutil
 from pathlib import Path
 from . import constants
 from .enums import CopyAction
@@ -709,7 +708,7 @@ class GLTestDir:
         # automake
         args = [UTILS['automake'], '--add-missing', '--copy']
         constants.execute(args, verbose)
-        shutil.rmtree('autom4te.cache')
+        constants.rmtree('autom4te.cache')
         os.chdir(DIRS['cwd'])
         if inctests and not single_configure:
             # Do not use "${AUTORECONF} --force --install", because it may invoke
@@ -744,7 +743,7 @@ class GLTestDir:
             # automake
             args = [UTILS['automake'], '--add-missing', '--copy']
             constants.execute(args, verbose)
-            shutil.rmtree('autom4te.cache')
+            constants.rmtree('autom4te.cache')
             os.chdir(DIRS['cwd'])
 
         # Need to run configure and make once, to create built files that are to be
@@ -879,7 +878,7 @@ class GLTestDir:
         if isfile(joinpath('build-aux', 'test-driver')):
             _patch_test_driver()
         os.chdir(DIRS['cwd'])
-        sp.call(['rm', '-rf', self.config['tempdir']], shell=False)
+        constants.rmtree(self.config['tempdir'])
 
 
 #===============================================================================
@@ -1036,8 +1035,8 @@ class GLMegaTestDir:
         constants.execute(args, verbose)
         args = [UTILS['automake'], '--add-missing', '--copy']
         constants.execute(args, verbose)
-        shutil.rmtree('autom4te.cache')
+        constants.rmtree('autom4te.cache')
         if isfile(joinpath('build-aux', 'test-driver')):
             _patch_test_driver()
         os.chdir(DIRS['cwd'])
-        sp.call(['rm', '-rf', self.config['tempdir']], shell=False)
+        constants.rmtree(self.config['tempdir'])
diff --git a/pygnulib/constants.py b/pygnulib/constants.py
index dc1297d529..f307ffa6b1 100644
--- a/pygnulib/constants.py
+++ b/pygnulib/constants.py
@@ -454,6 +454,20 @@ def hardlink(src: str, dest: str) -> None:
         ensure_writable(dest)
 
 
+def rmtree(dest: str) -> None:
+    '''Removes the file or directory tree at dest, if it exists.'''
+    # These two implementations are nearly equivalent.
+    # Speed: 'rm -rf' can be a little faster.
+    # Exceptions: shutil.rmtree raises Python exceptions, e.g. PermissionError.
+    if True:
+        sp.run(['rm', '-rf', dest], shell=False)
+    else:
+        try:
+            shutil.rmtree(dest)
+        except FileNotFoundError:
+            pass
+
+
 def filter_filelist(separator: str, filelist: str, prefix: str, suffix: str,
                     removed_prefix: str, removed_suffix: str,
                     added_prefix: str = '', added_suffix: str = '') -> str:
diff --git a/pygnulib/main.py b/pygnulib/main.py
index 4b64305049..471f4b9fb9 100644
--- a/pygnulib/main.py
+++ b/pygnulib/main.py
@@ -1120,7 +1120,7 @@ def main() -> None:
             sys.stderr.write(message)
             sys.exit(1)
         os.chdir('../..')
-        sp.call(['rm', '-rf', destdir], shell=False)
+        constants.rmtree(destdir)
 
     elif mode == 'megatest':
         if not destdir:
@@ -1150,7 +1150,7 @@ def main() -> None:
             sys.stderr.write(message)
             sys.exit(1)
         os.chdir('../..')
-        sp.call(['rm', '-rf', destdir], shell=False)
+        constants.rmtree(destdir)
 
     elif mode == 'extract-description':
         modulesystem = GLModuleSystem(config)





             reply	other threads:[~2024-04-13 10:18 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-04-13 10:17 Bruno Haible [this message]
2024-04-13 10:39 ` gnulib-tool.py: Refactor directory tree removals Collin Funk
2024-04-13 11:02   ` Bruno Haible

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://lists.gnu.org/mailman/listinfo/bug-gnulib

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=8092948.IHYaepM4ed@nimes \
    --to=bruno@clisp.org \
    --cc=bug-gnulib@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).