changeset 7395:312d52305583

- issue2551190 - Allow roundup-admin reindex to work in batches. Running: roundup-admin -i ... reindex issue:1-1000 will reindex the first 1000 issues while reporting any missing issues in the range. Also completion progress is reported when indexing a specific class. Note this require a chnge that makes an invalid command like: reindex issue23f to error with no such class issue23f. It used to reindex issue23 which I consider a bug. Updates to man page admin_guide.py. Tests added.
author John Rouillard <rouilj@ieee.org>
date Wed, 24 May 2023 12:13:05 -0400
parents 731b697295c5
children bb7752f6e1cd
files CHANGES.txt doc/admin_guide.txt roundup/admin.py share/man/man1/roundup-admin.1 test/test_admin.py
diffstat 5 files changed, 124 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES.txt	Wed May 24 11:48:04 2023 -0400
+++ b/CHANGES.txt	Wed May 24 12:13:05 2023 -0400
@@ -150,6 +150,11 @@
   Myers, config settings and docs by John Rouillard.)
 - roundup-admin genconfig does not need a tracker home to run. (John
   Rouillard)
+- issue2551190 - Allow roundup-admin reindex to work in
+  batches. Running roundup-admin -i ... reindex issue:1-1000 will
+  reindex the first 1000 issues while reporting any missing issues
+  in the range. Also completion progress is reported when indexing a
+  specific class.
 
 2022-07-13 2.2.0
 
--- a/doc/admin_guide.txt	Wed May 24 11:48:04 2023 -0400
+++ b/doc/admin_guide.txt	Wed May 24 12:13:05 2023 -0400
@@ -1242,13 +1242,13 @@
 
  Options:
   -i instance home  -- specify the issue tracker "home directory" to administer
-  -u                -- the user[:password] to use for commands
+  -u                -- the user[:password] to use for commands (default admin)
   -d                -- print full designators not just class id numbers
   -c                -- when outputting lists of data, comma-separate them.
-               Same as '-S ","'.
+                       Same as '-S ","'.
   -S <string>       -- when outputting lists of data, string-separate them
   -s                -- when outputting lists of data, space-separate them.
-               Same as '-S " "'.
+                       Same as '-S " "'.
   -V                -- be verbose when importing
   -v                -- report Roundup and Python versions (and quit)
 
@@ -1280,13 +1280,13 @@
   migrate
   pack period | date
   perftest [mode] [arguments]*
-  pragma setting=value
-  reindex [classname|designator]*
+  pragma setting=value | 'list'
+  reindex [classname|classname:#-#|designator]*
   restore designator[,designator]*
   retire designator[,designator]*
   rollback
   security [Role name]
-  set items property=value property=value ...
+  set items property=value [property=value ...]
   specification classname
   table classname [property[,property]*]
   templates [trace_search]
--- a/roundup/admin.py	Wed May 24 11:48:04 2023 -0400
+++ b/roundup/admin.py	Wed May 24 12:13:05 2023 -0400
@@ -803,6 +803,7 @@
         Generate a new tracker config file (ini style) with default
         values in <filename>.
         """
+        import pdb; pdb.set_trace()
         if len(args) < 1:
             raise UsageError(_('Not enough arguments supplied'))
 
@@ -1530,18 +1531,28 @@
 
         self.settings[setting] = value
 
-    designator_re = re.compile('([A-Za-z]+)([0-9]+)')
+    designator_re = re.compile('([A-Za-z]+)([0-9]+)$')
+    designator_rng = re.compile('([A-Za-z]+):([0-9]+)-([0-9]+)$')
 
-    def do_reindex(self, args, desre=designator_re):
-        ''"""Usage: reindex [classname|designator]*
+    def do_reindex(self, args, desre=designator_re, desrng=designator_rng):
+        ''"""Usage: reindex [classname|classname:#-#|designator]*
         Re-generate a tracker's search indexes.
 
         This will re-generate the search indexes for a tracker.
         This will typically happen automatically.
+
+        You can incrementally reindex using an argument like:
+
+            reindex issue:23-1000
+
+        to reindex issue class items 23-1000. Missing items
+        are reported but do not stop indexing of the range.
         """
+        from roundup import support
         if args:
             for arg in args:
                 m = desre.match(arg)
+                r = desrng.match(arg)
                 if m:
                     cl = self.get_class(m.group(1))
                     try:
@@ -1549,9 +1560,21 @@
                     except IndexError:
                         raise UsageError(_('no such item "%(designator)s"') % {
                             'designator': arg})
+                elif r:
+                    cl = self.get_class(r.group(1))
+                    for item in support.Progress(
+                            'Reindexing %s' % r.group(1),
+                            range(int(r.group(2)), int(r.group(3)))):
+                        try:
+                            cl.index(str(item))
+                        except IndexError:
+                            print(_('no such item "%(class)s%(id)s"') % {
+                            'class': r.group(1),
+                            'id': item})
+                            
                 else:
-                    cl = self.get_class(arg)
-                    self.db.reindex(arg)
+                    cl = self.get_class(arg)  # Bad class raises UsageError
+                    self.db.reindex(arg, show_progress=True)
         else:
             self.db.reindex(show_progress=True)
         return 0
--- a/share/man/man1/roundup-admin.1	Wed May 24 11:48:04 2023 -0400
+++ b/share/man/man1/roundup-admin.1	Wed May 24 12:13:05 2023 -0400
@@ -220,8 +220,11 @@
 will show all settings and their current values. If verbose
 is enabled hidden settings and descriptions will be shown.
 .TP
-\fBreindex\fP \fI[classname|designator]*\fP
-This will re-generate the search indexes for a tracker.
+\fBreindex\fP \fI[classname|classname:#-#|designator]*\fP This will
+re-generate the search indexes for a tracker. You can specify a
+specific item (or items) (e.g. issue23), range(s) of items
+(e.g. issue:1-1000), class(es) (e.g. issue) or reindex all items in
+the database if no arguments are supplied.
 .TP
 \fBrestore\fP \fIdesignator[,designator]*\fP
 Restore the retired node specified by designator.
--- a/test/test_admin.py	Wed May 24 11:48:04 2023 -0400
+++ b/test/test_admin.py	Wed May 24 12:13:05 2023 -0400
@@ -1035,6 +1035,86 @@
         # -----
         AdminTool.my_input = orig_input
 
+    def testReindex(self):
+        ''' Note the tests will fail if you run this under pdb.
+            the context managers capture the pdb prompts and this screws
+            up the stdout strings with (pdb) prefixed to the line.
+        '''
+        self.install_init()
+
+        # create an issue
+        self.admin=AdminTool()
+        sys.argv=['main', '-i', self.dirname, 'create', 'issue',
+                  'title="foo bar"', 'assignedto=admin' ]
+        ret = self.admin.main()
+
+        # reindex everything
+        self.admin=AdminTool()
+        with captured_output() as (out, err):
+            sys.argv=['main', '-i', self.dirname, 'reindex']
+            ret = self.admin.main()
+        out = out.getvalue().strip()
+        print(len(out))
+        print(repr(out))
+        # make sure priority is being reindexed
+        self.assertIn('Reindex priority 40%', out)
+
+
+        # reindex whole class
+        self.admin=AdminTool()
+        with captured_output() as (out, err):
+            sys.argv=['main', '-i', self.dirname, 'reindex', 'issue']
+            ret = self.admin.main()
+
+        out = out.getvalue().strip()
+        print(len(out))
+        print(repr(out))
+        self.assertEqual(out,
+                         'Reindex issue  0%                                                          \rReindex issue 100%                                                         \rReindex issue done')
+        self.assertEqual(len(out), 170)
+
+        # reindex one item
+        self.admin=AdminTool()
+        with captured_output() as (out, err):
+            sys.argv=['main', '-i', self.dirname, 'reindex', 'issue1']
+            ret = self.admin.main()
+
+        out = out.getvalue().strip()
+        print(len(out))
+        print(repr(out))
+        # no output when reindexing just one item
+        self.assertEqual(out, '')
+
+        # reindex range
+        self.admin=AdminTool()
+        with captured_output() as (out, err):
+            sys.argv=['main', '-i', self.dirname, 'reindex', 'issue:1-4']
+            ret = self.admin.main()
+
+        out = out.getvalue().strip()
+        print(repr(out))
+        self.assertIn('no such item "issue3"', out)
+
+        # reindex bad class
+        self.admin=AdminTool()
+        with captured_output() as (out, err):
+            sys.argv=['main', '-i', self.dirname, 'reindex', 'issue1-4']
+            ret = self.admin.main()
+
+        out = out.getvalue().strip()
+        print(repr(out))
+        self.assertIn('Error: no such class "issue1-4"', out)
+
+        # reindex bad item
+        self.admin=AdminTool()
+        with captured_output() as (out, err):
+            sys.argv=['main', '-i', self.dirname, 'reindex', 'issue14']
+            ret = self.admin.main()
+
+        out = out.getvalue().strip()
+        print(repr(out))
+        self.assertIn('Error: no such item "issue14"', out)
+
     def disabletestHelpInitopts(self):
 
         ''' Note the tests will fail if you run this under pdb.

Roundup Issue Tracker: http://roundup-tracker.org/