Skip to content

Commit

Permalink
gnulib-tool.py: Add a new GLFileTable class.
Browse files Browse the repository at this point in the history
* pygnulib/GLFileTable.py: New file. Define the GLFileTable class with
five attributes which can be individually typed.
* pygnulib/GLTestDir.py (GLTestDir.execute): Use the GLFileTable class.
* pygnulib/GLImport.py (GLImport.gnulib_comp, GLImport.prepare)
(GLImport.execute): Likewise. Update type hints and doc strings.
  • Loading branch information
collinfunk committed Apr 24, 2024
1 parent b993ed7 commit 962397d
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 62 deletions.
9 changes: 9 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
2024-04-24 Collin Funk <[email protected]>

gnulib-tool.py: Add a new GLFileTable class.
* pygnulib/GLFileTable.py: New file. Define the GLFileTable class with
five attributes which can be individually typed.
* pygnulib/GLTestDir.py (GLTestDir.execute): Use the GLFileTable class.
* pygnulib/GLImport.py (GLImport.gnulib_comp, GLImport.prepare)
(GLImport.execute): Likewise. Update type hints and doc strings.

2024-04-24 Paul Eggert <[email protected]>

largefile: port to C++
Expand Down
36 changes: 36 additions & 0 deletions pygnulib/GLFileTable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# 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


class GLFileTable:
'''The GLFileTable class stores file information for the duration of the
operation being executed.'''

all_files: list[str]
old_files: list[tuple[str, str]]
new_files: list[tuple[str, str]]
added_files: list[str]
removed_files: list[str]

def __init__(self, all_files: list[str]) -> None:
'''Create a GLFileTable with initialized fields.
- all_files, a list of all files being operated on.'''
self.all_files = all_files
self.old_files = []
self.new_files = []
self.added_files = []
self.removed_files = []
102 changes: 48 additions & 54 deletions pygnulib/GLImport.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
from .GLFileSystem import GLFileAssistant
from .GLMakefileTable import GLMakefileTable
from .GLEmiter import GLEmiter
from .GLFileTable import GLFileTable


#===============================================================================
Expand Down Expand Up @@ -588,17 +589,17 @@ def gnulib_cache(self) -> str:
emit += 'gl_VC_FILES([%s])\n' % str(vc_files).lower()
return emit

def gnulib_comp(self, filetable: dict[str, list[str]], gentests: bool) -> str:
def gnulib_comp(self, filetable: GLFileTable, gentests: bool) -> str:
'''Emit the contents of generated $m4base/gnulib-comp.m4 file.
GLConfig: destdir, localpath, tests, sourcebase, m4base, pobase, docbase,
testsbase, conddeps, libtool, macro_prefix, podomain, vc_files.
filetable is a dictionary with a category used as a key to access
a list of files.
filetable is a GLFileTable containing file information for this
import.
gentests is True if a tests Makefile.am is being generated, False
otherwise.'''
if type(filetable) is not dict:
raise TypeError(f'filetable should be a dict, not {type(filetable).__name__}')
if type(filetable) is not GLFileTable:
raise TypeError(f'filetable should be a GLFileTable, not {type(filetable).__name__}')
if type(gentests) is not bool:
raise TypeError(f'gentests should be a bool, not {type(gentests).__name__}')
emit = ''
Expand Down Expand Up @@ -655,7 +656,8 @@ def gnulib_comp(self, filetable: dict[str, list[str]], gentests: bool) -> str:
# _AC_LIBOBJ_ALLOCA, invoked from AC_FUNC_ALLOCA.
# All the m4_pushdef/m4_popdef logic in func_emit_initmacro_start/_end
# does not help to avoid this error.
newfile_set = {x[1] for x in filetable['new']}
newfile_set = { pair[1]
for pair in filetable.new_files }
if 'lib/alloca.c' in newfile_set:
emit += ' AC_CONFIG_LIBOBJ_DIR([%s])\n' % sourcebase
elif 'tests=lib/alloca.c' in newfile_set:
Expand Down Expand Up @@ -726,7 +728,7 @@ def gnulib_comp(self, filetable: dict[str, list[str]], gentests: bool) -> str:
# This macro records the list of files which have been installed by
# gnulib-tool and may be removed by future gnulib-tool invocations.
AC_DEFUN([%s_FILE_LIST], [\n''' % macro_prefix
emit += ' %s\n' % '\n '.join(filetable['all'])
emit += ' %s\n' % '\n '.join(filetable.all_files)
emit += '])\n'
return emit

Expand Down Expand Up @@ -802,7 +804,7 @@ def _update_ignorelist_(self, directory: str, ignore: str, files_added: list[str
else: # if self.config['dryrun']
print('Create %s' % srcpath)

def prepare(self) -> tuple[dict[str, list[str]], dict[str, tuple[re.Pattern, str] | None]]:
def prepare(self) -> tuple[GLFileTable, dict[str, tuple[re.Pattern, str] | None]]:
'''Perform preperations before GLImport.execute().
Returns a filetable and the transformers passed to GLFileAssistant().'''
destdir = self.config['destdir']
Expand Down Expand Up @@ -963,29 +965,21 @@ def prepare(self) -> tuple[dict[str, list[str]], dict[str, tuple[re.Pattern, str
# representing the files after this gnulib-tool invocation.

# Prepare the filetable.
filetable = dict()
filetable['all'] = sorted(set(filelist))
filetable['old'] = \
sorted(set(old_table), key=lambda pair: pair[0])
filetable['new'] = \
sorted(set(new_table), key=lambda pair: pair[0])
filetable['added'] = []
filetable['removed'] = []
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])

# Return the result.
result = tuple([filetable, transformers])
return result

def execute(self, filetable: dict[str, list[str]], transformers: dict[str, tuple[re.Pattern, str] | None]) -> None:
def execute(self, filetable: GLFileTable, transformers: dict[str, tuple[re.Pattern, str] | None]) -> None:
'''Perform operations on the lists of files, which are given in a special
format except filelist argument. Such lists of files can be created using
GLImport.prepare() function.'''
if type(filetable) is not dict:
raise TypeError('filetable must be a dict, not %s'
if type(filetable) is not GLFileTable:
raise TypeError('filetable must be a GLFileTable, not %s'
% type(filetable).__name__)
for key in ['all', 'old', 'new', 'added', 'removed']:
if key not in filetable:
raise KeyError('filetable must contain key %s' % repr(key))
destdir = self.config['destdir']
auxdir = self.config['auxdir']
sourcebase = self.config['sourcebase']
Expand All @@ -1004,7 +998,7 @@ def execute(self, filetable: dict[str, list[str]], transformers: dict[str, tuple

# Determine whether to put anything into $testsbase.
testsfiles = [ file
for file in filetable['all']
for file in filetable.all_files
if file.startswith('tests/') or file.startswith('tests=lib/') ]
gentests = len(testsfiles) > 0

Expand All @@ -1013,14 +1007,14 @@ def execute(self, filetable: dict[str, list[str]], transformers: dict[str, tuple
if pobase:
dirs.append(pobase)
if [ file
for file in filetable['all']
for file in filetable.all_files
if file.startswith('doc/') ]:
dirs.append(docbase)
if gentests:
dirs.append(testsbase)
dirs.append(auxdir)
dirs += sorted([ os.path.dirname(pair[0])
for pair in filetable['new'] ])
for pair in filetable.new_files ])
dirs = [ os.path.join(destdir, d)
for d in dirs ]
for directory in dirs:
Expand All @@ -1037,17 +1031,17 @@ def execute(self, filetable: dict[str, list[str]], transformers: dict[str, tuple
# Create GLFileAssistant instance to process files.
assistant = GLFileAssistant(self.config, transformers)

# Set of rewritten-file-names from filetable['old'].
# Set of rewritten-file-names from filetable.old_files.
old_rewritten_files = { pair[0]
for pair in filetable['old'] }
# Set of rewritten-file-names from filetable['new'].
for pair in filetable.old_files }
# Set of rewritten-file-names from filetable.new_files.
new_rewritten_files = { pair[0]
for pair in filetable['new'] }
for pair in filetable.new_files }

# Files which are in filetable['old'] and not in filetable['new'].
# They will be removed and added to filetable['removed'] list.
# Files which are in filetable.old_files and not in filetable.new_files.
# They will be removed and added to filetable.removed_files list.
pairs = [ pair
for pair in filetable['old']
for pair in filetable.old_files
if pair[0] not in new_rewritten_files ]
pairs = sorted(set(pairs), key=lambda pair: pair[0])
files = sorted(set(pair[0] for pair in pairs))
Expand All @@ -1065,13 +1059,13 @@ def execute(self, filetable: dict[str, list[str]], transformers: dict[str, tuple
raise GLError(14, file) from exc
else: # if self.config['dryrun']
print('Remove file %s (backup in %s~)' % (path, path))
filetable['removed'].append(file)
filetable.removed_files.append(file)

# Files which are in filetable['new'] and not in filetable['old'].
# They will be added/updated and added to filetable['added'] list.
# Files which are in filetable.new_files and not in filetable.old_files.
# They will be added/updated and added to filetable.added_files list.
already_present = False
pairs = [ pair
for pair in filetable['new']
for pair in filetable.new_files
if pair[0] not in old_rewritten_files ]
pairs = sorted(set(pairs))
for pair in pairs:
Expand All @@ -1081,11 +1075,11 @@ def execute(self, filetable: dict[str, list[str]], transformers: dict[str, tuple
assistant.setRewritten(rewritten)
assistant.add_or_update(already_present)

# Files which are in filetable['new'] and in filetable['old'].
# They will be added/updated and added to filetable['added'] list.
# Files which are in filetable.new_files and in filetable.old_files.
# They will be added/updated and added to filetable.added_files list.
already_present = True
pairs = [ pair
for pair in filetable['new']
for pair in filetable.new_files
if pair[0] in old_rewritten_files ]
pairs = sorted(set(pairs))
for pair in pairs:
Expand All @@ -1095,9 +1089,9 @@ def execute(self, filetable: dict[str, list[str]], transformers: dict[str, tuple
assistant.setRewritten(rewritten)
assistant.add_or_update(already_present)

# Add files which were added to the list of filetable['added'].
filetable['added'] += assistant.getFiles()
filetable['added'] = sorted(set(filetable['added']))
# Add files which were added to the list of filetable.added_files.
filetable.added_files += assistant.getFiles()
filetable.added_files = sorted(set(filetable.added_files))

# Default the source makefile name to Makefile.am.
if makefile_name:
Expand Down Expand Up @@ -1153,7 +1147,7 @@ def execute(self, filetable: dict[str, list[str]], transformers: dict[str, tuple
print('Creating %s' % filename)
else: # if self.config['dryrun']:
print('Create %s' % filename)
filetable['added'].append(filename)
filetable.added_files.append(filename)
if os.path.isfile(tmpfile):
os.remove(tmpfile)

Expand All @@ -1174,15 +1168,15 @@ def execute(self, filetable: dict[str, list[str]], transformers: dict[str, tuple
print('Creating %s' % filename)
else: # if self.config['dryrun']:
print('Create %s' % filename)
filetable['added'].append(filename)
filetable.added_files.append(filename)
if os.path.isfile(tmpfile):
os.remove(tmpfile)

# Create po makefile parameterization, part 2.
basename = joinpath(pobase, 'POTFILES.in')
tmpfile = assistant.tmpfilename(basename)
with open(tmpfile, mode='w', newline='\n', encoding='utf-8') as file:
file.write(self.emitter.po_POTFILES_in(filetable['all']))
file.write(self.emitter.po_POTFILES_in(filetable.all_files))
basename = joinpath(pobase, 'POTFILES.in')
filename, backup, flag = assistant.super_update(basename, tmpfile)
if flag == 1:
Expand All @@ -1195,7 +1189,7 @@ def execute(self, filetable: dict[str, list[str]], transformers: dict[str, tuple
print('Creating %s' % filename)
else: # if self.config['dryrun']:
print('Create %s' % filename)
filetable['added'].append(filename)
filetable.added_files.append(filename)
if os.path.isfile(tmpfile):
os.remove(tmpfile)

Expand Down Expand Up @@ -1225,7 +1219,7 @@ def execute(self, filetable: dict[str, list[str]], transformers: dict[str, tuple
print('Updating %s (backup in %s)' % (filename, backup))
elif flag == 2:
print('Creating %s' % filename)
filetable['added'].append(filename)
filetable.added_files.append(filename)
if os.path.isfile(tmpfile):
os.remove(tmpfile)
else: # if not self.config['dryrun']
Expand Down Expand Up @@ -1310,7 +1304,7 @@ def execute(self, filetable: dict[str, list[str]], transformers: dict[str, tuple
print('Creating %s' % filename)
else: # if self.config['dryrun']:
print('Create %s' % filename)
filetable['added'].append(filename)
filetable.added_files.append(filename)
if os.path.isfile(tmpfile):
os.remove(tmpfile)

Expand All @@ -1334,21 +1328,21 @@ def execute(self, filetable: dict[str, list[str]], transformers: dict[str, tuple
print('Creating %s' % filename)
else: # if self.config['dryrun']:
print('Create %s' % filename)
filetable['added'].append(filename)
filetable.added_files.append(filename)
if os.path.isfile(tmpfile):
os.remove(tmpfile)

if vc_files != False:
# Update the .cvsignore and .gitignore files.
ignorelist = []
# Treat gnulib-comp.m4 like an added file, even if it already existed.
filetable['added'].append(joinpath(m4base, 'gnulib-comp.m4'))
filetable['added'] = sorted(set(filetable['added']))
filetable['removed'] = sorted(set(filetable['removed']))
for file in filetable['added']:
filetable.added_files.append(joinpath(m4base, 'gnulib-comp.m4'))
filetable.added_files = sorted(set(filetable.added_files))
filetable.removed_files = sorted(set(filetable.removed_files))
for file in filetable.added_files:
directory, basename = os.path.split(file)
ignorelist.append(tuple([directory, '|A|', basename]))
for file in filetable['removed']:
for file in filetable.removed_files:
directory, basename = os.path.split(file)
ignorelist.append(tuple([directory, '|R|', basename]))
# Sort ignorelist by directory.
Expand Down
18 changes: 10 additions & 8 deletions pygnulib/GLTestDir.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
from .GLFileSystem import GLFileAssistant
from .GLMakefileTable import GLMakefileTable
from .GLEmiter import GLEmiter
from .GLFileTable import GLFileTable


def _patch_test_driver() -> None:
Expand Down Expand Up @@ -336,23 +337,24 @@ def execute(self) -> None:

# Add files for which the copy in gnulib is newer than the one that
# "automake --add-missing --copy" would provide.
filelist += ['build-aux/config.guess', 'build-aux/config.sub']
filelist = sorted(set(filelist))
filelist = sorted(set(filelist + ['build-aux/config.guess', 'build-aux/config.sub']))

# Setup the file table.
filetable = GLFileTable(filelist)

# Create directories.
directories = [ joinpath(self.testdir, os.path.dirname(file))
for file in self.rewrite_files(filelist) ]
for file in self.rewrite_files(filetable.all_files) ]
directories = sorted(set(directories))
for directory in directories:
if not os.path.isdir(directory):
os.makedirs(directory)

# Copy files or make symbolic links or hard links.
filetable = []
for src in filelist:
for src in filetable.all_files:
dest = self.rewrite_files([src])[-1]
filetable.append(tuple([dest, src]))
for row in filetable:
filetable.new_files.append(tuple([dest, src]))
for row in filetable.new_files:
src = row[1]
dest = row[0]
destpath = joinpath(self.testdir, dest)
Expand Down Expand Up @@ -395,7 +397,7 @@ def execute(self) -> None:
destfile = joinpath(directory, 'Makefile.am')
emit = '## Process this file with automake to produce Makefile.in.\n\n'
emit += 'EXTRA_DIST =\n'
for file in filelist:
for file in filetable.all_files:
if file.startswith('m4/'):
file = substart('m4/', '', file)
emit += 'EXTRA_DIST += %s\n' % file
Expand Down

0 comments on commit 962397d

Please sign in to comment.