It looks like gnulib-tool.py never cleaned up temporary directories
for modes other than the --import, --create-testdir, and related.
Since the --extract-* functions seem less used, hopefully this hasn't
caused too much spam yet.
In gnulib-tool-tests:
$ rm -rf /tmp/glpy*
$ ./test-all.sh
$ find '/tmp' -name 'glpy*' -type d 2> /dev/null | wc -l
54
in gnulib-tool-tests/info-tests:
$ rm -rf /tmp/glpy*
$ ./test-all.sh
$ find '/tmp' -name 'glpy*' -type d 2> /dev/null | wc -l
54
GLImport.__init__() and main() are pretty massive and ideally I would
like to make them a bit easier to read. It seems like a pain to track
down every code path that can lead to 'sys.exit()' or 'exit()' with a
temporary directory still existing.
With that said, GLConfig's are only created in two places. Once in
main() for the lifetime of the program. The other in
GLImport.__init__() to represent 'gnulib-cache.m4'. The one
representing the cache has it's temporary directory removed right
after.
Therefore, we can use tempfile.TemporaryDirectory as a context manager
and let Python cleanup for us [1]:
def main_with_exception_handling() -> None:
try: # Try to execute
- main()
+ with tempfile.TemporaryDirectory() as temporary_directory:
+ main(temporary_directory)
except GLError as error:
errmode = 0 # gnulib-style errors
errno = error.errno
Solves the spam and seems like the best solution for now. I applied
the attached patch doing this.
[1] https://docs.python.org/3/library/tempfile.html#tempfile.TemporaryDirectory
Collin
From 3169fd03dc5c917dbfe3096ec54921ca0e5f7253 Mon Sep 17 00:00:00 2001
From: Collin Funk <collin.fu...@gmail.com>
Date: Thu, 2 May 2024 00:49:58 -0700
Subject: [PATCH] gnulib-tool.py: Don't leave temporary directories on exit.
* pygnulib/main.py (main_with_exception_handling): Use
tempfile.TemporaryDirectory as a context manager so it is removed before
the program exits.
(main): Expect a temporary directory to be passed as an argument.
* pygnulib/GLConfig.py (GLConfig.__init__): Accept an optional temporary
directory parameter instead of creating one.
* pygnulib/GLImport.py (GLImport.__init__): Don't remove the cache's
temporary directory since it doesn't create one anymore.
(GLImport.execute): Don't remove the temporary directory explicitly. It
is handled by the usage of a context manager.
* pygnulib/GLTestDir.py (GLTestDir.execute, GLMegaTestDir.execute):
Likewise.
---
ChangeLog | 16 ++++++++++++++++
pygnulib/GLConfig.py | 4 ++--
pygnulib/GLImport.py | 2 --
pygnulib/GLTestDir.py | 2 --
pygnulib/main.py | 9 +++++----
5 files changed, 23 insertions(+), 10 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index bd2c45d9af..2257857847 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2024-05-02 Collin Funk <collin.fu...@gmail.com>
+
+ gnulib-tool.py: Don't leave temporary directories on exit.
+ * pygnulib/main.py (main_with_exception_handling): Use
+ tempfile.TemporaryDirectory as a context manager so it is removed before
+ the program exits.
+ (main): Expect a temporary directory to be passed as an argument.
+ * pygnulib/GLConfig.py (GLConfig.__init__): Accept an optional temporary
+ directory parameter instead of creating one.
+ * pygnulib/GLImport.py (GLImport.__init__): Don't remove the cache's
+ temporary directory since it doesn't create one anymore.
+ (GLImport.execute): Don't remove the temporary directory explicitly. It
+ is handled by the usage of a context manager.
+ * pygnulib/GLTestDir.py (GLTestDir.execute, GLMegaTestDir.execute):
+ Likewise.
+
2024-05-01 Collin Funk <collin.fu...@gmail.com>
gnulib-tool.py: Quote file names passed to 'patch'.
diff --git a/pygnulib/GLConfig.py b/pygnulib/GLConfig.py
index 92aa49d700..b8a7fc5b0b 100644
--- a/pygnulib/GLConfig.py
+++ b/pygnulib/GLConfig.py
@@ -20,7 +20,6 @@
#===============================================================================
import os
import copy
-import tempfile
from typing import Any
from .constants import (
MODES,
@@ -44,6 +43,7 @@ class GLConfig:
table: dict[str, Any]
def __init__(self,
+ tempdir: str | None = None,
destdir: str | None = None,
localpath: list[str] | None = None,
auxdir: str | None = None,
@@ -82,7 +82,7 @@ def __init__(self,
errors: bool | None = None) -> None:
'''Create new GLConfig instance.'''
self.table = dict()
- self.table['tempdir'] = tempfile.mkdtemp(prefix='glpy')
+ self.table['tempdir'] = tempdir
# Check and store the attributes.
# Remove trailing slashes from the directory names. This is necessary
# for m4base (to avoid an error in func_import) and optional for the
diff --git a/pygnulib/GLImport.py b/pygnulib/GLImport.py
index 833e186b8f..a11da0e63d 100644
--- a/pygnulib/GLImport.py
+++ b/pygnulib/GLImport.py
@@ -92,7 +92,6 @@ def __init__(self, config: GLConfig, mode: int) -> None:
# self.cache is the configuration extracted from some files on the
# file system: configure.{ac,in}, gnulib-cache.m4, gnulib-comp.m4.
self.cache = GLConfig()
- os.rmdir(self.cache['tempdir'])
# Read configure.{ac,in}.
with open(self.config.getAutoconfFile(), mode='r', newline='\n', encoding='utf-8') as file:
@@ -1390,4 +1389,3 @@ def execute(self, filetable: GLFileTable, transformers: dict[str, tuple[re.Patte
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))
- rmtree(self.config['tempdir'])
diff --git a/pygnulib/GLTestDir.py b/pygnulib/GLTestDir.py
index 2d4c684248..d3b819bd0d 100644
--- a/pygnulib/GLTestDir.py
+++ b/pygnulib/GLTestDir.py
@@ -840,7 +840,6 @@ def execute(self) -> None:
if os.path.isfile(joinpath('build-aux', 'test-driver')):
_patch_test_driver()
os.chdir(DIRS['cwd'])
- rmtree(self.config['tempdir'])
#===============================================================================
@@ -1003,4 +1002,3 @@ def execute(self) -> None:
if os.path.isfile(joinpath('build-aux', 'test-driver')):
_patch_test_driver()
os.chdir(DIRS['cwd'])
- rmtree(self.config['tempdir'])
diff --git a/pygnulib/main.py b/pygnulib/main.py
index 3230c45a31..d429a2c47e 100644
--- a/pygnulib/main.py
+++ b/pygnulib/main.py
@@ -84,7 +84,7 @@
import argparse
import subprocess as sp
import shlex
-from tempfile import mktemp
+import tempfile
from pygnulib.constants import (
APP,
DIRS,
@@ -117,7 +117,7 @@
#===============================================================================
# Define main part
#===============================================================================
-def main() -> None:
+def main(temp_directory: str) -> None:
info = GLInfo()
parser = argparse.ArgumentParser(
prog=APP['name'],
@@ -815,6 +815,7 @@ def main() -> None:
# Create pygnulib configuration.
config = GLConfig(
+ tempdir=temp_directory,
destdir=destdir,
localpath=localpath,
m4base=m4base,
@@ -853,7 +854,6 @@ def main() -> None:
modulesystem = GLModuleSystem(config)
listing = modulesystem.list()
result = lines_to_multiline(listing)
- os.rmdir(config['tempdir'])
print(result, end='')
elif mode == 'find':
@@ -1364,7 +1364,8 @@ def main() -> None:
def main_with_exception_handling() -> None:
try: # Try to execute
- main()
+ with tempfile.TemporaryDirectory() as temporary_directory:
+ main(temporary_directory)
except GLError as error:
errmode = 0 # gnulib-style errors
errno = error.errno
--
2.44.0