This script does a simple check for gettext usage in Python, C, and glade files, along with a check for the intltool output for desktop files, and reports whether files that use gettext are missing from POTFILES.in. --- tests/Makefile.am | 2 ++ tests/gettext/gettext_potfiles.py | 63 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100755 tests/gettext/gettext_potfiles.py
diff --git a/tests/Makefile.am b/tests/Makefile.am index 9074543..3d7f22d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -47,6 +47,7 @@ dist_check_SCRIPTS = glade/accelerators/check_accelerators.py \ pylint/pylint-one.sh \ testenv.sh \ gettext/gettext_warnings.sh \ + gettext/gettext_potfiles.py \ storage/run_storage_tests.py \ $(srcdir)/storage/cases/*.py \ $(srcdir)/*_tests/*.py @@ -54,6 +55,7 @@ dist_check_SCRIPTS = glade/accelerators/check_accelerators.py \ TESTS = nosetests.sh \ pylint/runpylint.sh \ gettext/gettext_warnings.sh \ + gettext/gettext_potfiles.py \ storage/run_storage_tests.py \ glade/accelerators/run_check_accelerators.sh \ glade/pw_visibility/run_check_pw_visibility.sh diff --git a/tests/gettext/gettext_potfiles.py b/tests/gettext/gettext_potfiles.py new file mode 100755 index 0000000..b8626a5 --- /dev/null +++ b/tests/gettext/gettext_potfiles.py @@ -0,0 +1,63 @@ +#!/usr/bin/python + +import os, sys, subprocess + +# The xpath in this file is simple enough that Python's built-in +# ElementTree can handle it, so we don't need lxml here +import xml.etree.ElementTree as ET + +if "top_srcdir" not in os.environ: + sys.stderr.write("$top_srcdir must be defined in the test environment\n") + # This return code tells the automake test driver that the test setup failed + os._exit(99) + +success = True + +def check_potfiles(checklist, dirname, names): + global success + + potcheckfiles = [] + + # Skip the .git directory + if ".git" in names: + names.remove(".git") + + # Strip the "./" component from the path name + dirname = os.path.relpath(dirname, ".") + + for checkfile in (os.path.join(dirname, name) for name in names): + if checkfile.endswith(".py"): + # Check whether the file imports the i18n module + if subprocess.call(["grep", "-q", "^from pyanaconda.i18n import", checkfile]) == 0: + potcheckfiles.append(checkfile) + elif checkfile.endswith(".c"): + # Check whether the file includes intl.h + if subprocess.call(["grep", "-q", "#include .intl\.h.", checkfile]) == 0: + potcheckfiles.append(checkfile) + elif checkfile.endswith(".glade"): + # Look for a "translatable=yes" attribute + if ET.parse(checkfile).findall(".//*[@translatable='yes']"): + potcheckfiles.append(checkfile) + elif checkfile.endswith(".desktop.in"): + # These are handled by intltool, make sure the .h version is present + potcheckfiles.append(checkfile + ".h") + + for checkfile in potcheckfiles: + if checkfile not in checklist: + sys.stderr.write("%s not in POTFILES.in\n" % checkfile) + success = False + +# Read in POTFILES.in, skip comments and blank lines +POTFILES = [] +with open(os.path.join(os.environ["top_srcdir"], "po", "POTFILES.in")) as f: + for line in (line.strip() for line in f): + if not line or line.startswith("#"): + continue + POTFILES.append(line) + +# Walk the source tree and look for files with translatable strings +os.chdir(os.environ["top_srcdir"]) +os.path.walk(".", check_potfiles, POTFILES) + +if not success: + os._exit(1)
Fixed a format-string warning in errors.py now that gettext is picking it up. --- po/POTFILES.in | 10 ++++++++++ pyanaconda/errors.py | 6 +++--- 2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/po/POTFILES.in b/po/POTFILES.in index af263f9..d62c5b8 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -4,6 +4,9 @@ # Main anaconda source files pyanaconda/bootloader.py pyanaconda/constants.py +pyanaconda/constants_text.py +pyanaconda/errors.py +pyanaconda/exception.py pyanaconda/image.py pyanaconda/install.py pyanaconda/installclass.py @@ -14,6 +17,8 @@ pyanaconda/network.py pyanaconda/product.py pyanaconda/regexes.py pyanaconda/rescue.py +pyanaconda/text.py +pyanaconda/users.py pyanaconda/vnc.py
# Install class definitions @@ -25,6 +30,7 @@ pyanaconda/packaging/__init__.py pyanaconda/packaging/livepayload.py pyanaconda/packaging/tarpayload.py pyanaconda/packaging/yumpayload.py +pyanaconda/packaging/dnfpayload.py
# Interfaces pyanaconda/ui/common.py @@ -45,8 +51,10 @@ pyanaconda/ui/tui/spokes/network.py pyanaconda/ui/tui/spokes/password.py pyanaconda/ui/tui/spokes/storage.py pyanaconda/ui/tui/spokes/time_spoke.py +pyanaconda/ui/tui/spokes/shell_spoke.py pyanaconda/ui/tui/spokes/source.py pyanaconda/ui/tui/spokes/software.py +pyanaconda/ui/tui/spokes/user.py pyanaconda/ui/tui/spokes/warnings.py pyanaconda/ui/tui/spokes/progress.py pyanaconda/ui/tui/spokes/__init__.py @@ -74,8 +82,10 @@ pyanaconda/ui/gui/spokes/source.py pyanaconda/ui/gui/spokes/storage.py pyanaconda/ui/gui/spokes/user.py pyanaconda/ui/gui/spokes/welcome.py +pyanaconda/ui/gui/spokes/advstorage/iscsi.py pyanaconda/ui/gui/spokes/lib/accordion.py pyanaconda/ui/gui/spokes/lib/cart.py +pyanaconda/ui/gui/spokes/lib/detailederror.py pyanaconda/ui/gui/spokes/lib/passphrase.py pyanaconda/ui/gui/spokes/lib/refresh.py pyanaconda/ui/gui/spokes/lib/resize.py diff --git a/pyanaconda/errors.py b/pyanaconda/errors.py index cea7141..1a4e055 100644 --- a/pyanaconda/errors.py +++ b/pyanaconda/errors.py @@ -200,9 +200,9 @@ class ErrorHandler(object): lineno = args[0] details = args[1] message = _("There was an error running the kickstart script at line " - "%s. This is a fatal error and installation will be " - "aborted. The details of this error are:\n\n%s") % \ - (lineno, details) + "%(lineno)s. This is a fatal error and installation will be " + "aborted. The details of this error are:\n\n%(details)s") % \ + {"lineno": lineno, "details" : details} self.ui.showError(message) return ERROR_RAISE
- for checkfile in potcheckfiles:
if checkfile not in checklist:
sys.stderr.write("%s not in POTFILES.in\n" % checkfile)
success = False
If you ever expected these lists to be large, set operations would likely be faster. But I don't particularly care.
ACK to these two.
- Chris
On 12/06/2013 09:34 AM, Chris Lumens wrote:
- for checkfile in potcheckfiles:
if checkfile not in checklist:
sys.stderr.write("%s not in POTFILES.in\n" % checkfile)
success = False
If you ever expected these lists to be large, set operations would likely be faster. But I don't particularly care.
Ah jeez. The whole reason I did it in python instead of shell was to speed up that part, so at least I got halfway there. How about I convert POTFILES to a set when I pass it to os.path.walk, and instead of the block above I do something like:
difference = set(potcheckfiles) - checklist for missing in difference: sys.stderr.write("%s not in POTFILES.in\n" % missing) success = False
ACK to these two.
- Chris
anaconda-patches mailing list anaconda-patches@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/anaconda-patches
- for checkfile in potcheckfiles:
if checkfile not in checklist:
sys.stderr.write("%s not in POTFILES.in\n" % checkfile)
success = False
If you ever expected these lists to be large, set operations would likely be faster. But I don't particularly care.
Ah jeez. The whole reason I did it in python instead of shell was to speed up that part, so at least I got halfway there. How about I convert POTFILES to a set when I pass it to os.path.walk, and instead of the block above I do something like:
The internet thinks that sets are way faster for testing membership, but lists are faster for iteration. You're doing both, so who knows! Whoo!
difference = set(potcheckfiles) - checklist for missing in difference: sys.stderr.write("%s not in POTFILES.in\n" % missing) success = False
But yes, this is what I was thinking.
- Chris
anaconda-patches@lists.fedorahosted.org