Hi Bruno,
On 4/25/24 1:18 PM, Bruno Haible wrote:
> Yep, that's the right way to do it. Maybe file_name should come first
> (by the usual heuristic that the argument that shows most variation
> comes first)?
Sure, that is fine with me. I think the other way is based on how I
like to write C. Usually I like to place structures (or pointers to
them) first. The best example I can think of off the top of my head
is:
int fprintf (FILE *stream, const char *format, ...);
vs.
int fputs (const char *str, FILE *stream);
I always feel awkward using 'fputs' because of that. But that is a
different language so I can adapt. :)
How does this patch look? I'll wait for you to review it before
pushing any changes.
I ran all tests with Python 3.7 and they pass. I don't think
gnulib-tool --copy-file is tested there though. I tried to use gettext
since I remember autogen.sh does it a few times but I see the
following failure:
$ cd gettext
$ env GNULIB_TOOL_IMPL=sh+py sh -x ./autogen.sh
[...]
Copying file gnulib-lib/exitfail.c
1 out of 1 hunk FAILED -- saving rejects to file /tmp/glDMpS4d/exitfail.h.rej
/home/collin/.local/src/gnulib/gnulib-tool.sh: *** patch file
gnulib-local/lib/exitfail.h.diff didn't apply cleanly
/home/collin/.local/src/gnulib/gnulib-tool.sh: *** Stop.
+ exit 1
I assume that is unrelated to these changes and will be an easy fix
for you. When I remove the diff everything passes with
GNULIB_TOOL_IMPL=sh+py.
Collin
From 95f83aabfcd2cd0624ae85357f7f40f34bb1a01b Mon Sep 17 00:00:00 2001
From: Collin Funk <collin.fu...@gmail.com>
Date: Thu, 25 Apr 2024 15:30:29 -0700
Subject: [PATCH] gnulib-tool.py: Reduce code duplication in file name
transformations.
* pygnulib/functions.py: New file for shared functions between modules.
Add a function based on functions removed from GLImport and GLTestDir.
Accepts a single file name instead of a list.
* pygnulib/GLImport.py (GLImport.prepare): Use the new function.
(GLImport.rewrite_new_files, GLImport.rewrite_old_files): Remove
functions.
* pygnulib/GLTestDir.py (GLTestDir.execute): Use the new function.
(GLTestDir.rewrite_files): Remove functions.
* pygnulib/main.py (main): Remove unused function import. Use the new
function.
---
ChangeLog | 14 +++++++
pygnulib/GLImport.py | 97 +++++--------------------------------------
pygnulib/GLTestDir.py | 55 +++++-------------------
pygnulib/functions.py | 52 +++++++++++++++++++++++
pygnulib/main.py | 17 +-------
5 files changed, 88 insertions(+), 147 deletions(-)
create mode 100644 pygnulib/functions.py
diff --git a/ChangeLog b/ChangeLog
index abefd3bae2..276258b885 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2024-04-25 Collin Funk <collin.fu...@gmail.com>
+
+ gnulib-tool.py: Reduce code duplication in file name transformations.
+ * pygnulib/functions.py: New file for shared functions between modules.
+ Add a function based on functions removed from GLImport and GLTestDir.
+ Accepts a single file name instead of a list.
+ * pygnulib/GLImport.py (GLImport.prepare): Use the new function.
+ (GLImport.rewrite_new_files, GLImport.rewrite_old_files): Remove
+ functions.
+ * pygnulib/GLTestDir.py (GLTestDir.execute): Use the new function.
+ (GLTestDir.rewrite_files): Remove functions.
+ * pygnulib/main.py (main): Remove unused function import. Use the new
+ function.
+
2024-04-25 Bruno Haible <br...@clisp.org>
doc: Remove documentation of IRIX as supported platform.
diff --git a/pygnulib/GLImport.py b/pygnulib/GLImport.py
index cf1ebd10ec..47c0e83555 100644
--- a/pygnulib/GLImport.py
+++ b/pygnulib/GLImport.py
@@ -38,6 +38,7 @@
relativize,
rmtree,
)
+from .functions import rewrite_file_name
from .GLError import GLError
from .GLConfig import GLConfig
from .GLModuleSystem import GLModuleTable
@@ -303,80 +304,6 @@ def __repr__(self) -> str:
result = '<pygnulib.GLImport %s>' % hex(id(self))
return result
- def rewrite_old_files(self, files: list[str]) -> list[str]:
- '''Replace auxdir, docbase, sourcebase, m4base and testsbase from default
- to their version from cached config.'''
- if type(files) is not list:
- raise TypeError('files argument must has list type, not %s'
- % type(files).__name__)
- for file in files:
- if type(file) is not str:
- raise TypeError('each file must be a string instance')
- files = sorted(set(files))
- files = [ '%s%s' % (file, os.path.sep)
- for file in files ]
- auxdir = self.cache['auxdir']
- docbase = self.cache['docbase']
- sourcebase = self.cache['sourcebase']
- m4base = self.cache['m4base']
- testsbase = self.cache['testsbase']
- result = []
- for file in files:
- if file.startswith('build-aux/'):
- path = substart('build-aux/', '%s/' % auxdir, file)
- elif file.startswith('doc/'):
- path = substart('doc/', '%s/' % docbase, file)
- elif file.startswith('lib/'):
- path = substart('lib/', '%s/' % sourcebase, file)
- elif file.startswith('m4/'):
- path = substart('m4/', '%s/' % m4base, file)
- elif file.startswith('tests/'):
- path = substart('tests/', '%s/' % testsbase, file)
- elif file.startswith('tests=lib/'):
- path = substart('tests=lib/', '%s/' % testsbase, file)
- elif file.startswith('top/'):
- path = substart('top/', '', file)
- else: # file is not a special file
- path = file
- result.append(os.path.normpath(path))
- return sorted(set(result))
-
- def rewrite_new_files(self, files: list[str]) -> list[str]:
- '''Replace auxdir, docbase, sourcebase, m4base and testsbase from
- default to their version from config.'''
- if type(files) is not list:
- raise TypeError('files argument must has list type, not %s'
- % type(files).__name__)
- for file in files:
- if type(file) is not str:
- raise TypeError('each file must be a string instance')
- files = sorted(set(files))
- auxdir = self.config['auxdir']
- docbase = self.config['docbase']
- sourcebase = self.config['sourcebase']
- m4base = self.config['m4base']
- testsbase = self.config['testsbase']
- result = []
- for file in files:
- if file.startswith('build-aux/'):
- path = substart('build-aux/', '%s/' % auxdir, file)
- elif file.startswith('doc/'):
- path = substart('doc/', '%s/' % docbase, file)
- elif file.startswith('lib/'):
- path = substart('lib/', '%s/' % sourcebase, file)
- elif file.startswith('m4/'):
- path = substart('m4/', '%s/' % m4base, file)
- elif file.startswith('tests/'):
- path = substart('tests/', '%s/' % testsbase, file)
- elif file.startswith('tests=lib/'):
- path = substart('tests=lib/', '%s/' % testsbase, file)
- elif file.startswith('top/'):
- path = substart('top/', '', file)
- else: # file is not a special file
- path = file
- result.append(os.path.normpath(path))
- return sorted(set(result))
-
def actioncmd(self) -> str:
'''Return command-line invocation comment.'''
modules = self.config.getModules()
@@ -943,31 +870,27 @@ def prepare(self) -> tuple[GLFileTable, dict[str, tuple[re.Pattern, str] | None]
# old_files is the list of files according to the last gnulib-tool invocation.
# new_files is the list of files after this gnulib-tool invocation.
- # Construct tables and transformers.
+ # Construct the transformers.
transformers = dict()
transformers['lib'] = sed_transform_lib_file
transformers['aux'] = sed_transform_build_aux_file
transformers['main'] = sed_transform_main_lib_file
transformers['tests'] = sed_transform_testsrelated_lib_file
- old_table = []
- new_table = []
- for src in old_files:
- dest = self.rewrite_old_files([src])[-1]
- old_table.append(tuple([dest, src]))
- for src in new_files:
- dest = self.rewrite_new_files([src])[-1]
- new_table.append(tuple([dest, src]))
- old_table = sorted(set(old_table))
- new_table = sorted(set(new_table))
+
# old_table is a table with two columns: (rewritten-file-name original-file-name),
# representing the files according to the last gnulib-tool invocation.
+ old_table = { (rewrite_file_name(file_name, self.cache, True), file_name)
+ for file_name in old_files }
+
# new_table is a table with two columns: (rewritten-file-name original-file-name),
# representing the files after this gnulib-tool invocation.
+ new_table = { (rewrite_file_name(file_name, self.config, True), file_name)
+ for file_name in new_files }
# Prepare the filetable.
filetable = GLFileTable(sorted(set(filelist)))
- filetable.old_files = sorted(set(old_table), key=lambda pair: pair[0])
- filetable.new_files = sorted(set(new_table), key=lambda pair: pair[0])
+ filetable.old_files = sorted(old_table, key=lambda pair: pair[0])
+ filetable.new_files = sorted(new_table, key=lambda pair: pair[0])
# Return the result.
result = tuple([filetable, transformers])
diff --git a/pygnulib/GLTestDir.py b/pygnulib/GLTestDir.py
index 0ac2f32f69..8534e19254 100644
--- a/pygnulib/GLTestDir.py
+++ b/pygnulib/GLTestDir.py
@@ -42,6 +42,7 @@
relinverse,
rmtree,
)
+from .functions import rewrite_file_name
from .enums import CopyAction
from .GLError import GLError
from .GLConfig import GLConfig
@@ -122,42 +123,6 @@ def __init__(self, config: GLConfig, testdir: str) -> None:
self.config.resetWitnessCMacro()
self.config.resetVCFiles()
- def rewrite_files(self, files: list[str]) -> list[str]:
- '''Replace auxdir, docbase, sourcebase, m4base and testsbase from
- default to their version from config.'''
- if type(files) is not list:
- raise TypeError('files argument must have list type, not %s'
- % type(files).__name__)
- for file in files:
- if type(file) is not str:
- raise TypeError('each file must be a string instance')
- files = sorted(set(files))
- auxdir = self.config['auxdir']
- docbase = self.config['docbase']
- sourcebase = self.config['sourcebase']
- m4base = self.config['m4base']
- testsbase = self.config['testsbase']
- result = []
- for file in files:
- if file.startswith('build-aux/'):
- path = substart('build-aux/', '%s/' % auxdir, file)
- elif file.startswith('doc/'):
- path = substart('doc/', '%s/' % docbase, file)
- elif file.startswith('lib/'):
- path = substart('lib/', '%s/' % sourcebase, file)
- elif file.startswith('m4/'):
- path = substart('m4/', '%s/' % m4base, file)
- elif file.startswith('tests/'):
- path = substart('tests/', '%s/' % testsbase, file)
- elif file.startswith('tests=lib/'):
- path = substart('tests=lib/', '%s/' % testsbase, file)
- elif file.startswith('top/'):
- path = substart('top/', '', file)
- else: # file is not a special file
- path = file
- result.append(os.path.normpath(path))
- return sorted(set(result))
-
def execute(self) -> None:
'''Create a scratch package with the given modules.'''
auxdir = self.config['auxdir']
@@ -339,24 +304,24 @@ def execute(self) -> None:
# "automake --add-missing --copy" would provide.
filelist = sorted(set(filelist + ['build-aux/config.guess', 'build-aux/config.sub']))
+ # new_table is a table with two columns: (rewritten-file-name original-file-name),
+ # representing the files after this gnulib-tool invocation.
+ new_table = { (rewrite_file_name(file_name, self.config, True), file_name)
+ for file_name in filelist }
+
# Setup the file table.
filetable = GLFileTable(filelist)
+ filetable.new_files = sorted(new_table, key=lambda pair: pair[0])
# Create directories.
- directories = [ joinpath(self.testdir, os.path.dirname(file))
- for file in self.rewrite_files(filetable.all_files) ]
- directories = sorted(set(directories))
+ directories = sorted({ joinpath(self.testdir, os.path.dirname(pair[0]))
+ for pair in filetable.new_files })
for directory in directories:
if not os.path.isdir(directory):
os.makedirs(directory)
# Copy files or make symbolic links or hard links.
- for src in filetable.all_files:
- dest = self.rewrite_files([src])[-1]
- filetable.new_files.append(tuple([dest, src]))
- for row in filetable.new_files:
- src = row[1]
- dest = row[0]
+ for (dest, src) in filetable.new_files:
destpath = joinpath(self.testdir, dest)
if src.startswith('tests=lib/'):
src = substart('tests=lib/', 'lib/', src)
diff --git a/pygnulib/functions.py b/pygnulib/functions.py
new file mode 100644
index 0000000000..9459d9c1f8
--- /dev/null
+++ b/pygnulib/functions.py
@@ -0,0 +1,52 @@
+# Copyright (C) 2002-2024 Free Software Foundation, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+from __future__ import annotations
+
+import os.path
+from .constants import substart
+from .GLConfig import GLConfig
+
+
+def rewrite_file_name(file_name: str, config: GLConfig, also_tests_lib: bool = False) -> str:
+ '''Replace auxdir, docbase, sourcebase, m4base and testsbase from their
+ default to the ones specified in a GLConfig object.
+ - file_name, the file name to transform,
+ - config, the GLConfig storing directory names,
+ - also_tests_lib, True if 'tests=lib/' should be replaced.'''
+ if type(file_name) is not str:
+ raise TypeError(f'file_name must be a str type, not {type(file_name).__name__}')
+ auxdir = config['auxdir']
+ docbase = config['docbase']
+ sourcebase = config['sourcebase']
+ m4base = config['m4base']
+ testsbase = config['testsbase']
+ if file_name.startswith('build-aux/'):
+ result = substart('build-aux/', '%s/' % auxdir, file_name)
+ elif file_name.startswith('doc/'):
+ result = substart('doc/', '%s/' % docbase, file_name)
+ elif file_name.startswith('lib/'):
+ result = substart('lib/', '%s/' % sourcebase, file_name)
+ elif file_name.startswith('m4/'):
+ result = substart('m4/', '%s/' % m4base, file_name)
+ elif file_name.startswith('tests/'):
+ result = substart('tests/', '%s/' % testsbase, file_name)
+ elif also_tests_lib and file_name.startswith('tests=lib/'):
+ result = substart('tests=lib/', '%s/' % testsbase, file_name)
+ elif file_name.startswith('top/'):
+ result = substart('top/', '', file_name)
+ else: # file is not a special file
+ result = file_name
+ return os.path.normpath(result)
diff --git a/pygnulib/main.py b/pygnulib/main.py
index ea781f5a97..3230c45a31 100644
--- a/pygnulib/main.py
+++ b/pygnulib/main.py
@@ -96,12 +96,12 @@
lines_to_multiline,
ensure_writable,
copyfile,
- substart,
force_output,
init_DIRS,
rmtree,
DEFAULT_AUTOCONF_MINVERSION,
)
+from pygnulib.functions import rewrite_file_name
from pygnulib.enums import CopyAction
from pygnulib.GLConfig import GLConfig
from pygnulib.GLError import GLError
@@ -1309,20 +1309,7 @@ def main() -> None:
lookedup, flag = filesystem.lookup(srcpath)
if os.path.isdir(dest):
destdir = dest
- if srcpath.startswith('build-aux/'):
- destpath = substart('build-aux/', '%s/' % auxdir, srcpath)
- elif srcpath.startswith('doc/'):
- destpath = substart('doc/', '%s/' % docbase, srcpath)
- elif srcpath.startswith('lib/'):
- destpath = substart('lib/', '%s/' % sourcebase, srcpath)
- elif srcpath.startswith('m4/'):
- destpath = substart('m4/', '%s/' % m4base, srcpath)
- elif srcpath.startswith('tests/'):
- destpath = substart('tests/', '%s/' % testsbase, srcpath)
- elif srcpath.startswith('top/'):
- destpath = substart('top/', '', srcpath)
- else: # either case
- destpath = srcpath
+ destpath = rewrite_file_name(srcpath, config)
else: # if not os.path.isdir(dest)
destdir = os.path.dirname(dest)
destpath = os.path.basename(dest)
--
2.44.0