]> Savannah Git Hosting - gnulib.git/commitdiff
gnulib-tool.py: Make --extract-dependents quick again.
authorCollin Funk <collin.funk1@gmail.com>
Thu, 5 Dec 2024 02:49:45 +0000 (18:49 -0800)
committerCollin Funk <collin.funk1@gmail.com>
Thu, 5 Dec 2024 02:49:45 +0000 (18:49 -0800)
Suggested by Bruno Haible in:
<https://lists.gnu.org/archive/html/bug-gnulib/2024-12/msg00012.html>.

* pygnulib/GLModuleSystem.py (GLModule.getDependents): Add an optional
argument to use the implementation before yesterdays change.
* pygnulib/main.py (mode == 'extract-dependents'): Add the optional
argument to call of GLModule.getDependents.

ChangeLog
pygnulib/GLModuleSystem.py
pygnulib/main.py

index bc5f2b5f29f78febafae77f5d2ada495c2e6d9a6..c783488d2159e611540c1d0c9dca8e7601f3a61d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2024-12-04  Collin Funk  <collin.funk1@gmail.com>
+
+       gnulib-tool.py: Make --extract-dependents quick again.
+       Suggested by Bruno Haible in:
+       <https://lists.gnu.org/archive/html/bug-gnulib/2024-12/msg00012.html>.
+       * pygnulib/GLModuleSystem.py (GLModule.getDependents): Add an optional
+       argument to use the implementation before yesterdays change.
+       * pygnulib/main.py (mode == 'extract-dependents'): Add the optional
+       argument to call of GLModule.getDependents.
+
 2024-12-04  Bruno Haible  <bruno@clisp.org>
 
        bison-i18n: Ensure BISON_LOCALEDIR_c expands to a C string.
index 7d68b712e015919a64bc47b71f8c251ffa19dd31..dda1cc36936f10575d1662aeb97637ad7fc5c50d 100644 (file)
@@ -588,11 +588,58 @@ class GLModule:
             self.cache['dependents'] = result
         return self.cache['dependents']
 
-    def getDependents(self) -> list[GLModule]:
+    def getDependents(self, top_level: bool | None = True) -> list[GLModule]:
         '''Return list of dependents (a.k.a. "reverse dependencies"),
         as a list of GLModule objects.
-        GLConfig: localpath.'''
-        return self._getDependents()
+        GLConfig: localpath. Arguments are:
+        - top_level: Optional argument, to use an optimized version from main().'''
+        # Only use optimized version, below if called from the main().
+        if not top_level:
+            return self._getDependents()
+        localpath = self.config['localpath']
+        # Find a set of module candidates quickly.
+        # Convert the module name to a POSIX basic regex.
+        # Needs to handle . [ \ * ^ $.
+        regex = self.name.replace('\\', '\\\\').replace('[', '\\[').replace('^', '\\^')
+        regex = re.compile(r'([.*$])').sub(r'[\1]', regex)
+        line_regex = '^' + regex
+        # We can't add a '$' to line_regex, because that would fail to match
+        # lines that denote conditional dependencies. We could invoke grep
+        # twice, once to search for  line_regex + '$'  and once to search
+        # for   line_regex + [ <TAB>]  but that would be twice as slow.
+        # Read module candidates from gnulib root directory.
+        command = "find modules -type f -print | xargs -n 100 grep -l %s /dev/null | sed -e 's,^modules/,,'" % shlex.quote(line_regex)
+        result = sp.run(command, shell=True, cwd=DIRS['root'], capture_output=True).stdout.decode('utf-8')
+        if localpath != None and len(localpath) > 0:
+            command = "find modules -type f -print | xargs -n 100 grep -l %s /dev/null | sed -e 's,^modules/,,' -e 's,\\.diff$,,'" % shlex.quote(line_regex)
+            for localdir in localpath:
+                result += sp.run(command, shell=True, cwd=localdir, capture_output=True).stdout.decode('utf-8')
+        listing = [ line
+                    for line in result.split('\n')
+                    if line.strip() ]
+        # Remove modules/ prefix from each file name.
+        pattern = re.compile(r'^modules/')
+        listing = [ pattern.sub('', line)
+                    for line in listing ]
+        # Filter out undesired file names.
+        listing = [ line
+                    for line in listing
+                    if self.modulesystem.file_is_module(line) ]
+        # ${module}-tests implicitly depends on ${module}, if both exist.
+        if self.isNonTests():
+            implicit_dependent = self.name+'-tests'
+            if self.modulesystem.exists(implicit_dependent):
+                listing.append(implicit_dependent)
+        candidates = sorted(set(listing))
+        result = []
+        for name in candidates:
+            module = self.modulesystem.find(name)
+            if module:  # Ignore module candidates that don't actually exist.
+                if self in module.getDependenciesWithoutConditions():
+                    result.append(module)
+        self.cache['dependents'] = result
+        return self.cache['dependents']
+
 
     def getDependentsRecursively(self) -> set[GLModule]:
         '''Return a list of recursive dependents of this module,
index f6aa9d47eaa7ff79119f7159a27e97e9ef26a287..d70b566269765efa876e8c717b46ffef1d467255 100644 (file)
@@ -1289,7 +1289,7 @@ def main(temp_directory: str) -> None:
         for name in modules:
             module = modulesystem.find(name)
             if module:
-                dependents = module.getDependents()
+                dependents = module.getDependents(top_level=True)
                 dependents_names = sorted([ m.name
                                             for m in dependents ])
                 sys.stdout.write(lines_to_multiline(dependents_names))