public inbox for cygwin-apps-cvs@sourceware.org
help / color / mirror / Atom feed
* [calm - Cygwin server-side packaging maintenance script] branch master, updated. 20200401-34-g4f7df6c
@ 2020-05-29 12:54 Jon TURNEY
  0 siblings, 0 replies; only message in thread
From: Jon TURNEY @ 2020-05-29 12:54 UTC (permalink / raw)
  To: cygwin-apps-cvs




https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/calm.git;h=4f7df6cac9c32c6b2357b245d0b9c4069369f5a3

commit 4f7df6cac9c32c6b2357b245d0b9c4069369f5a3
Author: Jon Turney <jon.turney@dronecode.org.uk>
Date:   Thu May 28 15:06:04 2020 +0100

    Allow maintainers to suppress informative-only mail
    
    If the !email file contains a line saying 'quiet', the log output will
    not be mailed if the log only contains INFO severity messages.

https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/calm.git;h=2e66e6c8d57f6c637ce2cd896a5fe1b8a713e9a7

commit 2e66e6c8d57f6c637ce2cd896a5fe1b8a713e9a7
Author: Jon Turney <jon.turney@dronecode.org.uk>
Date:   Thu May 28 13:50:05 2020 +0100

    Move static methods out of Maintainers class
    
    We're not writing C++, they are still scoped to the module namespace, so
    making them @staticmethod just makes using them require more verbiage.

https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/calm.git;h=23c99abfb263c41f3d386ae392e78a4d00d84b7b

commit 23c99abfb263c41f3d386ae392e78a4d00d84b7b
Author: Jon Turney <jon.turney@dronecode.org.uk>
Date:   Wed May 27 15:20:23 2020 +0100

    Ignore extra whitespace in cygwin-pkg-maint file

https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/calm.git;h=5c406d9fd9d815d8b6869474146a2754bfcd5157

commit 5c406d9fd9d815d8b6869474146a2754bfcd5157
Author: Jon Turney <jon.turney@dronecode.org.uk>
Date:   Tue May 26 20:36:19 2020 +0100

    Try to send email to Bcc: list, even if To: is empty
    
    Also log sendmail exit status

https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/calm.git;h=b155c6f4a5ac611f109ee814d348a282b006478c

commit b155c6f4a5ac611f109ee814d348a282b006478c
Author: Jon Turney <jon.turney@dronecode.org.uk>
Date:   Wed May 27 13:58:13 2020 +0100

    Log an error if maintainer doesn't have an email address


Diff:
---
 calm/buffering_smtp_handler.py |   4 +-
 calm/calm.py                   |   9 +-
 calm/compare-arches            |   4 +-
 calm/maintainers.py            | 216 +++++++++++++++++++++--------------------
 calm/mkgitoliteconf.py         |   4 +-
 calm/mkmaintdir                |   4 +-
 calm/package.py                |   8 +-
 calm/pkg2html.py               |   4 +-
 test/test_calm.py              |   6 +-
 9 files changed, 133 insertions(+), 126 deletions(-)

diff --git a/calm/buffering_smtp_handler.py b/calm/buffering_smtp_handler.py
index fcc5290..c826d34 100644
--- a/calm/buffering_smtp_handler.py
+++ b/calm/buffering_smtp_handler.py
@@ -84,12 +84,12 @@ class BufferingSMTPHandler(logging.handlers.BufferingHandler):
                 print('-' * 40)
                 print(msg)
                 print('-' * 40)
-            elif len(self.toaddrs) > 0:
+            else:
                 with subprocess.Popen(['/usr/sbin/sendmail', '-t', '-oi', '-f', self.fromaddr], stdin=subprocess.PIPE) as p:
                     p.communicate(m.as_bytes())
+                    logging.debug('sendmail: msgid %s, exit status %d' % (m['Message-Id'], p.returncode))
 
             self.buffer = []
-            logging.debug('sent mail with msgid %s' % (m['Message-Id']))
 
     def shouldFlush(self, record):
         # the capacity we pass to BufferingHandler is irrelevant since we
diff --git a/calm/calm.py b/calm/calm.py
index dc5df16..88ebdd7 100755
--- a/calm/calm.py
+++ b/calm/calm.py
@@ -131,17 +131,18 @@ def process_relarea(args):
 
 def process_uploads(args, state):
     # read maintainer list
-    mlist = maintainers.Maintainer.read(args, getattr(args, 'orphanmaint', None))
+    mlist = maintainers.read(args, getattr(args, 'orphanmaint', None))
 
     # make the list of all packages
-    all_packages = maintainers.Maintainer.all_packages(mlist)
+    all_packages = maintainers.all_packages(mlist)
 
     # for each maintainer
     for name in sorted(mlist.keys()):
         m = mlist[name]
 
         # also send a mail to each maintainer about their packages
-        with mail_logs(args.email, toaddrs=m.email, subject='%s for %s' % (state.subject, name), thresholdLevel=logging.INFO) as maint_email:  # noqa: F841
+        threshold = logging.WARNING if m.quiet else logging.INFO
+        with mail_logs(args.email, toaddrs=m.email, subject='%s for %s' % (state.subject, name), thresholdLevel=threshold, retainLevel=logging.INFO) as maint_email:  # noqa: F841
 
             # for each arch and noarch
             scan_result = {}
@@ -260,7 +261,7 @@ def process_uploads(args, state):
             irk.irk("calm %s" % msg)
 
     # record updated reminder times for maintainers
-    maintainers.Maintainer.update_reminder_times(mlist)
+    maintainers.update_reminder_times(mlist)
 
     return state.packages
 
diff --git a/calm/compare-arches b/calm/compare-arches
index 37e1861..4e2dd19 100755
--- a/calm/compare-arches
+++ b/calm/compare-arches
@@ -91,8 +91,8 @@ def main(args):
         print("%s is only in arch %s" % (p, [a for a in exists if exists[a]]))
 
     # are there any packages which have a maintainer, but don't exist?
-    mlist = maintainers.Maintainer.read(args, getattr(args, 'orphanmaint', None))
-    all_packages = maintainers.Maintainer.all_packages(mlist)
+    mlist = maintainers.read(args, getattr(args, 'orphanmaint', None))
+    all_packages = maintainers.all_packages(mlist)
 
     for p in sorted(all_packages):
         if p not in union:
diff --git a/calm/maintainers.py b/calm/maintainers.py
index 7ffc12b..9d7bdee 100644
--- a/calm/maintainers.py
+++ b/calm/maintainers.py
@@ -65,6 +65,7 @@ class Maintainer(object):
         self.name = name
         self.email = email
         self.pkgs = pkgs
+        self.quiet = False
 
         # the mtime of this file records the timestamp
         reminder_file = os.path.join(self.homedir(), '!reminder-timestamp')
@@ -102,122 +103,127 @@ class Maintainer(object):
         mlist.setdefault(name, Maintainer(name))
         return mlist[name]
 
-    # add maintainers which have existing directories
-    @classmethod
-    def add_directories(self, mlist, homedirs):
-        self._homedirs = homedirs
-
-        for n in os.listdir(homedirs):
-            if not os.path.isdir(os.path.join(homedirs, n)):
-                continue
-
-            m = Maintainer._find(mlist, n)
-
-            for e in ['!email', '!mail']:
-                email = os.path.join(homedirs, m.name, e)
-                if os.path.isfile(email):
-                    with open(email) as f:
-                        for l in f:
-                            # one address per line, ignore blank and comment lines
-                            if l.startswith('#'):
-                                continue
-                            l = l.strip()
-                            if l:
-                                m.email.append(l)
-
-        return mlist
-
-    # add maintainers from the package maintainers list, with the packages they
-    # maintain
-    @staticmethod
-    def add_packages(mlist, pkglist, orphanMaint=None):
-        with open(pkglist) as f:
-            for (i, l) in enumerate(f):
-                l = l.rstrip()
-
-                # match lines of the form '<package> <maintainer(s)|status>'
-                match = re.match(r'^(\S+)\s+(.+)$', l)
-                if match:
-                    pkg = match.group(1)
-                    rest = match.group(2)
-
-                    # does rest starts with a status in all caps?
-                    status_match = re.match(r'^([A-Z]+)\b.*$', rest)
-                    if status_match:
-                        status = status_match.group(1)
-
-                        # ignore packages marked as 'OBSOLETE'
-                        if status == 'OBSOLETE':
-                            continue
 
-                        # orphaned packages get the default maintainer if we
-                        # have one, otherwise they are assigned to 'ORPHANED'
-                        elif status == 'ORPHANED':
-                            if orphanMaint is not None:
-                                m = orphanMaint
-                            else:
-                                m = status
+# add maintainers which have existing directories
+def add_directories(mlist, homedirs):
+    Maintainer._homedirs = homedirs
 
-                            # also add any previous maintainer(s) listed
-                            prevm = re.match(r'^ORPHANED\s\((.*)\)', rest)
-                            if prevm:
-                                m = m + '/' + prevm.group(1)
+    for n in os.listdir(homedirs):
+        if not os.path.isdir(os.path.join(homedirs, n)):
+            continue
 
-                        else:
-                            logging.error("unknown package status '%s' in line %s:%d: '%s'" % (status, pkglist, i, l))
+        m = Maintainer._find(mlist, n)
+
+        # !mail is the deprecated historical alternative
+        for e in ['!email', '!mail']:
+            email = os.path.join(homedirs, m.name, e)
+            if os.path.isfile(email):
+                with open(email) as f:
+                    for l in f:
+                        # one address per line, ignore blank and comment lines
+                        if l.startswith('#'):
                             continue
+                        l = l.strip()
+                        if l.lower() == 'quiet':
+                            m.quiet = True
+                        elif l:
+                            m.email.append(l)
+        if not m.email:
+            logging.error("no email address known for maintainer '%s'" % (m.name))
+
+    return mlist
+
+
+# add maintainers from the package maintainers list, with the packages they
+# maintain
+def add_packages(mlist, pkglist, orphanMaint=None):
+    with open(pkglist) as f:
+        for (i, l) in enumerate(f):
+            l = l.rstrip()
+
+            # match lines of the form '<package> <maintainer(s)|status>'
+            match = re.match(r'^(\S+)\s+(.+)$', l)
+            if match:
+                pkg = match.group(1)
+                rest = match.group(2)
+
+                # does rest starts with a status in all caps?
+                status_match = re.match(r'^([A-Z]+)\b.*$', rest)
+                if status_match:
+                    status = status_match.group(1)
+
+                    # ignore packages marked as 'OBSOLETE'
+                    if status == 'OBSOLETE':
+                        continue
+
+                    # orphaned packages get the default maintainer if we
+                    # have one, otherwise they are assigned to 'ORPHANED'
+                    elif status == 'ORPHANED':
+                        if orphanMaint is not None:
+                            m = orphanMaint
+                        else:
+                            m = status
+
+                        # also add any previous maintainer(s) listed
+                        prevm = re.match(r'^ORPHANED\s\((.*)\)', rest)
+                        if prevm:
+                            m = m + '/' + prevm.group(1)
                     else:
-                        m = rest
-
-                    # joint maintainers are separated by '/'
-                    for name in m.split('/'):
-
-                        # is the maintainer name ascii?
-                        #
-                        # (despite containing spaces, think of these as an account
-                        # name, rather than a display name)
-                        try:
-                            name.encode('ascii')
-                        except UnicodeError:
-                            logging.error("non-ascii maintainer name '%s' in line %s:%d, skipped" % (rest, pkglist, i))
-                            continue
+                        logging.error("unknown package status '%s' in line %s:%d: '%s'" % (status, pkglist, i, l))
+                        continue
+                else:
+                    m = rest
 
-                        m = Maintainer._find(mlist, name)
-                        m.pkgs.append(pkg)
+                # joint maintainers are separated by '/'
+                for name in m.split('/'):
+                    name = name.strip()
 
-                else:
-                    logging.error("unrecognized line in %s:%d: '%s'" % (pkglist, i, l))
+                    # is the maintainer name ascii?
+                    #
+                    # (despite containing spaces, think of these as an account
+                    # name, rather than a display name)
+                    try:
+                        name.encode('ascii')
+                    except UnicodeError:
+                        logging.error("non-ascii maintainer name '%s' in line %s:%d, skipped" % (rest, pkglist, i))
+                        continue
 
-        return mlist
+                    m = Maintainer._find(mlist, name)
+                    m.pkgs.append(pkg)
 
-    # create maintainer list
-    @staticmethod
-    def read(args, orphanmaint=None):
-        mlist = {}
-        mlist = Maintainer.add_directories(mlist, args.homedir)
-        mlist = Maintainer.add_packages(mlist, args.pkglist, orphanmaint)
+            else:
+                logging.error("unrecognized line in %s:%d: '%s'" % (pkglist, i, l))
 
-        return mlist
+    return mlist
 
-    # invert to a per-package list of maintainers
-    @staticmethod
-    def invert(mlist):
-        _pkgs = defaultdict(list)
-        # for each maintainer
-        for m in mlist.values():
-            # for each package
-            for p in m.pkgs:
-                # add the maintainer name
-                _pkgs[p].append(m.name)
 
-        return _pkgs
+# create maintainer list
+def read(args, orphanmaint=None):
+    mlist = {}
+    mlist = add_directories(mlist, args.homedir)
+    mlist = add_packages(mlist, args.pkglist, orphanmaint)
 
-    @staticmethod
-    def update_reminder_times(mlist):
-        for m in mlist.values():
-            m._update_reminder_time()
+    return mlist
 
-    # a list of all packages
-    @staticmethod
-    def all_packages(mlist):
-        return list(itertools.chain.from_iterable(mlist[m].pkgs for m in mlist))
+
+# invert to a per-package list of maintainers
+def invert(mlist):
+    _pkgs = defaultdict(list)
+    # for each maintainer
+    for m in mlist.values():
+        # for each package
+        for p in m.pkgs:
+            # add the maintainer name
+            _pkgs[p].append(m.name)
+
+    return _pkgs
+
+
+def update_reminder_times(mlist):
+    for m in mlist.values():
+        m._update_reminder_time()
+
+
+# a list of all packages
+def all_packages(mlist):
+    return list(itertools.chain.from_iterable(mlist[m].pkgs for m in mlist))
diff --git a/calm/mkgitoliteconf.py b/calm/mkgitoliteconf.py
index 39c185c..0e12c6e 100755
--- a/calm/mkgitoliteconf.py
+++ b/calm/mkgitoliteconf.py
@@ -51,10 +51,10 @@ def transform_username(name):
 def do_main(args):
     # read maintainer list
     mlist = {}
-    mlist = maintainers.Maintainer.add_packages(mlist, args.pkglist, getattr(args, 'orphanmaint', None))
+    mlist = maintainers.add_packages(mlist, args.pkglist, getattr(args, 'orphanmaint', None))
 
     # make the list of all packages
-    maintainers.Maintainer.all_packages(mlist)
+    maintainers.all_packages(mlist)
 
     # invert to a per-package list of maintainers
     pkgs = defaultdict(list)
diff --git a/calm/mkmaintdir b/calm/mkmaintdir
index 2023ae6..88c385a 100755
--- a/calm/mkmaintdir
+++ b/calm/mkmaintdir
@@ -71,8 +71,8 @@ def main(args):
 
     # create maintainer list
     mlist = {}
-    mlist = maintainers.Maintainer.add_directories(mlist, args.homedir)
-    mlist = maintainers.Maintainer.add_packages(mlist, args.pkglist, args.orphanmaint)
+    mlist = maintainers.add_directories(mlist, args.homedir)
+    mlist = maintainers.add_packages(mlist, args.pkglist, args.orphanmaint)
 
     # create or suggest removal for each maintainer directory
     for name in sorted(mlist.keys()):
diff --git a/calm/package.py b/calm/package.py
index 66d03df..3ad4252 100755
--- a/calm/package.py
+++ b/calm/package.py
@@ -915,10 +915,10 @@ def validate_package_maintainers(args, packages):
 
     # read maintainer list
     mlist = {}
-    mlist = maintainers.Maintainer.add_packages(mlist, args.pkglist)
+    mlist = maintainers.add_packages(mlist, args.pkglist)
 
     # make the list of all packages
-    all_packages = maintainers.Maintainer.all_packages(mlist)
+    all_packages = maintainers.all_packages(mlist)
 
     # validate that all packages are in the package list
     for p in sorted(packages):
@@ -1165,8 +1165,8 @@ def write_repo_json(args, packages, f):
     for arch in packages:
         package_list.update(packages[arch])
 
-    mlist = maintainers.Maintainer.read(args, None)
-    pkg_maintainers = maintainers.Maintainer.invert(mlist)
+    mlist = maintainers.read(args, None)
+    pkg_maintainers = maintainers.invert(mlist)
 
     pl = []
     for pn in sorted(package_list):
diff --git a/calm/pkg2html.py b/calm/pkg2html.py
index f554f39..3750e81 100755
--- a/calm/pkg2html.py
+++ b/calm/pkg2html.py
@@ -135,8 +135,8 @@ def update_package_listings(args, packages):
     summaries = os.path.join(args.htdocs, 'summary')
     ensure_dir_exists(args, summaries)
 
-    mlist = maintainers.Maintainer.read(args, None)
-    pkg_maintainers = maintainers.Maintainer.invert(mlist)
+    mlist = maintainers.read(args, None)
+    pkg_maintainers = maintainers.invert(mlist)
 
     toremove = glob.glob(os.path.join(summaries, '*'))
 
diff --git a/test/test_calm.py b/test/test_calm.py
index 17aeb86..8c926bf 100755
--- a/test/test_calm.py
+++ b/test/test_calm.py
@@ -306,8 +306,8 @@ class CalmTest(unittest.TestCase):
         self.maxDiff = None
 
         mlist = {}
-        mlist = maintainers.Maintainer.add_directories(mlist, 'testdata/homes')
-        mlist = maintainers.Maintainer.add_packages(mlist, 'testdata/pkglist/cygwin-pkg-maint', None)
+        mlist = maintainers.add_directories(mlist, 'testdata/homes')
+        mlist = maintainers.add_packages(mlist, 'testdata/pkglist/cygwin-pkg-maint', None)
 
         compare_with_expected_file(self, 'testdata/pkglist', mlist)
 
@@ -329,7 +329,7 @@ class CalmTest(unittest.TestCase):
         pkglist = ['after-ready', 'not-ready', 'testpackage', 'testpackage2']
 
         mlist = {}
-        mlist = maintainers.Maintainer.add_directories(mlist, 'testdata/homes')
+        mlist = maintainers.add_directories(mlist, 'testdata/homes')
         m = mlist['Blooey McFooey']
         m.pkgs.extend(pkglist + ['not-on-package-list'])
 



^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2020-05-29 12:54 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-05-29 12:54 [calm - Cygwin server-side packaging maintenance script] branch master, updated. 20200401-34-g4f7df6c Jon TURNEY

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).