| #!/usr/bin/env python |
| # |
| # $Id$ |
| # |
| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| # |
| # |
| |
| """Usage: l10n-report.py [OPTION...] |
| |
| Send the l10n translation status report to an email address. If the |
| email address is not specified, print in stdout. |
| |
| Options: |
| |
| -h, --help Show this help message. |
| |
| -m, --to-email-id Send the l10n translation status report to this |
| email address. |
| """ |
| |
| import sys |
| import getopt |
| import os |
| import re |
| import subprocess |
| |
| FROM_ADDRESS = "Subversion Translation Status <noreply@subversion.apache.org>" |
| LIST_ADDRESS = "dev@subversion.apache.org" |
| SUBJECT_TEMPLATE = "[l10n] Translation status report for %s r%s" |
| MAIL_THREAD_ID = '<translation_status_report_for_%s@subversion.apache.org>' |
| |
| def _rev(): |
| dollar = "$Revision$" |
| return int(re.findall('[0-9]+', dollar)[0]); |
| |
| def usage_and_exit(errmsg=None): |
| """Print a usage message, plus an ERRMSG (if provided), then exit. |
| If ERRMSG is provided, the usage message is printed to stderr and |
| the script exits with a non-zero error code. Otherwise, the usage |
| message goes to stdout, and the script exits with a zero |
| errorcode.""" |
| if errmsg is None: |
| stream = sys.stdout |
| else: |
| stream = sys.stderr |
| stream.write("%s\n" % __doc__) |
| stream.flush() |
| if errmsg: |
| stream.write("\nError: %s\n" % errmsg) |
| stream.flush() |
| sys.exit(2) |
| sys.exit(0) |
| |
| |
| class l10nReport: |
| def __init__(self, to_email_id=""): |
| self.to_email_id = to_email_id |
| self.from_email_id = "<%s>" % LIST_ADDRESS |
| |
| def safe_command(self, cmd_and_args, cmd_in=""): |
| [stdout, stderr] = subprocess.Popen(cmd_and_args, \ |
| stdin=subprocess.PIPE, \ |
| stdout=subprocess.PIPE, \ |
| stderr=subprocess.PIPE).communicate(input=cmd_in) |
| return stdout, stderr |
| |
| def match(self, pattern, string): |
| if isinstance(pattern, basestring): |
| pattern = re.compile(pattern) |
| match = re.compile(pattern).search(string) |
| if match and match.groups(): |
| return match.group(1) |
| else: |
| return None |
| |
| def get_msgattribs(self, file): |
| msgout = self.safe_command(['msgattrib', '--translated', file])[0] |
| grepout = self.safe_command(['grep', '-E', '^msgid *"'], msgout)[0] |
| sedout = self.safe_command(['sed', '1d'], grepout)[0] |
| trans = self.safe_command(['wc', '-l'], sedout)[0] |
| |
| msgout = self.safe_command(['msgattrib', '--untranslated', file])[0] |
| grepout = self.safe_command(['grep', '-E', '^msgid *"'], msgout)[0] |
| sedout = self.safe_command(['sed', '1d'], grepout)[0] |
| untrans = self.safe_command(['wc', '-l'], sedout)[0] |
| |
| msgout = self.safe_command(['msgattrib', '--only-fuzzy', file])[0] |
| grepout = self.safe_command(['grep', '-E', '^msgid *"'], msgout)[0] |
| sedout = self.safe_command(['sed', '1d'], grepout)[0] |
| fuzzy = self.safe_command(['wc', '-l'], sedout)[0] |
| |
| msgout = self.safe_command(['msgattrib', '--only-obsolete', file])[0] |
| grepout = self.safe_command(['grep', '-E', '^#~ msgid *"'], msgout)[0] |
| obsolete = self.safe_command(['wc', '-l'], grepout)[0] |
| |
| return int(trans), int(untrans), int(fuzzy), int(obsolete) |
| |
| def pre_l10n_report(self): |
| # svn revert --recursive subversion/po |
| cmd = ['svn', 'revert', '--recursive', 'subversion/po'] |
| stderr = self.safe_command(cmd)[1] |
| if stderr: |
| sys.stderr.write("\nError: %s\n" % stderr) |
| sys.stderr.flush() |
| sys.exit(0) |
| |
| # svn update |
| cmd = ['svn', 'update'] |
| stderr = self.safe_command(cmd)[1] |
| if stderr: |
| sys.stderr.write("\nError: %s\n" % stderr) |
| sys.stderr.flush() |
| sys.exit(0) |
| |
| # tools/po/po-update.sh |
| cmd = ['sh', 'tools/po/po-update.sh'] |
| self.safe_command(cmd) |
| |
| |
| def bar_graph(nominal_length, trans, untrans, fuzzy, obsolete): |
| """Format the given four counts into a bar graph string in which the |
| total length of the bars representing the TRANS, UNTRANS and FUZZY |
| counts is NOMINAL_LENGTH characters, and the bar representing the |
| OBSOLETE count extends beyond that.""" |
| |
| total_count = trans + untrans + fuzzy # don't include 'obsolete' |
| accum_bar = 0 |
| accum_count = 0 |
| s = '' |
| for count, letter in [(trans, '+'), (untrans, 'U'), (fuzzy, '~'), |
| (obsolete, 'o')]: |
| accum_count += count |
| new_bar_end = nominal_length * accum_count / total_count |
| s += letter * (new_bar_end - accum_bar) |
| accum_bar = new_bar_end |
| return s |
| |
| |
| def main(): |
| # Parse the command-line options and arguments. |
| try: |
| opts, args = getopt.gnu_getopt(sys.argv[1:], "hm:", |
| ["help", |
| "to-email-id=", |
| ]) |
| except getopt.GetoptError as msg: |
| usage_and_exit(msg) |
| |
| to_email_id = None |
| for opt, arg in opts: |
| if opt in ("-h", "--help"): |
| usage_and_exit() |
| elif opt in ("-m", "--to-email-id"): |
| to_email_id = arg |
| |
| l10n = l10nReport() |
| os.chdir("%s/../.." % os.path.dirname(os.path.abspath(sys.argv[0]))) |
| l10n.pre_l10n_report() |
| [info_out, info_err] = l10n.safe_command(['svn', 'info']) |
| if info_err: |
| sys.stderr.write("\nError: %s\n" % info_err) |
| sys.stderr.flush() |
| sys.exit(0) |
| |
| po_dir = 'subversion/po' |
| branch_name = l10n.match('URL:.*/asf/subversion/(\S+)', info_out) |
| [info_out, info_err] = l10n.safe_command(['svnversion', po_dir]) |
| if info_err: |
| sys.stderr.write("\nError: %s\n" % info_err) |
| sys.stderr.flush() |
| sys.exit(0) |
| |
| wc_version = re.sub('[MS]', '', info_out.strip()) |
| title = "Translation status report for %s@r%s" % \ |
| (branch_name, wc_version) |
| |
| os.chdir(po_dir) |
| files = sorted(os.listdir('.')) |
| format_head = "\n%6s %7s %7s %7s %7s" % ("lang", "trans", "untrans", |
| "fuzzy", "obs") |
| format_line = "--------------------------------------" |
| print("\n%s\n%s\n%s" % (title, format_head, format_line)) |
| |
| body = "" |
| po_pattern = re.compile('(.*).po$') |
| for file in files: |
| lang = l10n.match(po_pattern, file) |
| if not lang: |
| continue |
| [trans, untrans, fuzzy, obsolete] = l10n.get_msgattribs(file) |
| po_format = "%6s %7d %7d %7d %7d" %\ |
| (lang, trans, untrans, fuzzy, obsolete) |
| po_format += " " + bar_graph(30, trans, untrans, fuzzy, obsolete) |
| body += "%s\n" % po_format |
| print(po_format) |
| |
| if to_email_id: |
| import smtplib |
| # Ensure compatibility of the email module all the way to Python 2.3 |
| try: |
| from email.message import Message |
| except ImportError: |
| from email.Message import Message |
| |
| msg = Message() |
| msg["From"] = FROM_ADDRESS |
| msg["To"] = to_email_id |
| msg["Subject"] = SUBJECT_TEMPLATE % (branch_name, wc_version) |
| msg["X-Mailer"] = "l10n-report.py r%s" % _rev() |
| msg["Reply-To"] = LIST_ADDRESS |
| msg["Mail-Followup-To"] = LIST_ADDRESS |
| msg["In-Reply-To"] = MAIL_THREAD_ID % (branch_name.replace('/', '_')) |
| msg["References"] = msg["In-Reply-To"] |
| |
| # http://www.iana.org/assignments/auto-submitted-keywords/auto-submitted-keywords.xhtml |
| msg["Auto-Submitted"] = 'auto-generated' |
| |
| msg.set_type("text/plain") |
| msg.set_payload("\n".join((title, format_head, format_line, body))) |
| |
| server = smtplib.SMTP('localhost') |
| server.sendmail("From: " + FROM_ADDRESS, |
| "To: " + to_email_id, |
| msg.as_string()) |
| print("The report is sent to '%s' email id." % to_email_id) |
| else: |
| print("\nYou have not passed '-m' option, so email is not sent.") |
| |
| if __name__ == "__main__": |
| main() |