Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #17628 -- Extended makemessages command to also ignore director…

…ies when walking, not only when looking for files. Thanks, Claude Paroz.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17441 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit c6065545ef127ef244defd520b2bb1afe3a5c153 1 parent 62dc16d
Jannis Leidel authored
73  django/core/management/commands/makemessages.py
@@ -7,6 +7,7 @@
7 7
 from optparse import make_option
8 8
 from subprocess import PIPE, Popen
9 9
 
  10
+import django
10 11
 from django.core.management.base import CommandError, NoArgsCommand
11 12
 from django.utils.text import get_text_list
12 13
 from django.utils.jslex import prepare_js_for_gettext
@@ -44,11 +45,23 @@ def _popen(cmd):
44 45
     p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE, close_fds=os.name != 'nt', universal_newlines=True)
45 46
     return p.communicate()
46 47
 
47  
-def walk(root, topdown=True, onerror=None, followlinks=False):
  48
+def walk(root, topdown=True, onerror=None, followlinks=False,
  49
+         ignore_patterns=[], verbosity=0, stdout=sys.stdout):
48 50
     """
49 51
     A version of os.walk that can follow symlinks for Python < 2.6
50 52
     """
  53
+    dir_suffix = '%s*' % os.sep
  54
+    norm_patterns = map(lambda p: p.endswith(dir_suffix)
  55
+                        and p[:-len(dir_suffix)] or p, ignore_patterns)
51 56
     for dirpath, dirnames, filenames in os.walk(root, topdown, onerror):
  57
+        remove_dirs = []
  58
+        for dirname in dirnames:
  59
+            if is_ignored(os.path.normpath(os.path.join(dirpath, dirname)), norm_patterns):
  60
+                remove_dirs.append(dirname)
  61
+        for dirname in remove_dirs:
  62
+            dirnames.remove(dirname)
  63
+            if verbosity > 1:
  64
+                stdout.write('ignoring directory %s\n' % dirname)
52 65
         yield (dirpath, dirnames, filenames)
53 66
         if followlinks:
54 67
             for d in dirnames:
@@ -66,29 +79,29 @@ def is_ignored(path, ignore_patterns):
66 79
             return True
67 80
     return False
68 81
 
69  
-def find_files(root, ignore_patterns, verbosity, symlinks=False):
  82
+def find_files(root, ignore_patterns, verbosity, stdout=sys.stdout, symlinks=False):
70 83
     """
71 84
     Helper function to get all files in the given root.
72 85
     """
73 86
     all_files = []
74  
-    for (dirpath, dirnames, filenames) in walk(".", followlinks=symlinks):
75  
-        for f in filenames:
76  
-            norm_filepath = os.path.normpath(os.path.join(dirpath, f))
  87
+    for (dirpath, dirnames, filenames) in walk(".", followlinks=symlinks,
  88
+            ignore_patterns=ignore_patterns, verbosity=verbosity, stdout=stdout):
  89
+        for filename in filenames:
  90
+            norm_filepath = os.path.normpath(os.path.join(dirpath, filename))
77 91
             if is_ignored(norm_filepath, ignore_patterns):
78 92
                 if verbosity > 1:
79  
-                    sys.stdout.write('ignoring file %s in %s\n' % (f, dirpath))
  93
+                    stdout.write('ignoring file %s in %s\n' % (f, dirpath))
80 94
             else:
81  
-                all_files.extend([(dirpath, f)])
  95
+                all_files.extend([(dirpath, filename)])
82 96
     all_files.sort()
83 97
     return all_files
84 98
 
85  
-def copy_plural_forms(msgs, locale, domain, verbosity):
  99
+def copy_plural_forms(msgs, locale, domain, verbosity, stdout=sys.stdout):
86 100
     """
87 101
     Copies plural forms header contents from a Django catalog of locale to
88 102
     the msgs string, inserting it at the right place. msgs should be the
89 103
     contents of a newly created .po file.
90 104
     """
91  
-    import django
92 105
     django_dir = os.path.normpath(os.path.join(os.path.dirname(django.__file__)))
93 106
     if domain == 'djangojs':
94 107
         domains = ('djangojs', 'django')
@@ -100,7 +113,7 @@ def copy_plural_forms(msgs, locale, domain, verbosity):
100 113
             m = plural_forms_re.search(open(django_po, 'rU').read())
101 114
             if m:
102 115
                 if verbosity > 1:
103  
-                    sys.stderr.write("copying plural forms: %s\n" % m.group('value'))
  116
+                    stdout.write("copying plural forms: %s\n" % m.group('value'))
104 117
                 lines = []
105 118
                 seen = False
106 119
                 for line in msgs.split('\n'):
@@ -132,8 +145,8 @@ def write_pot_file(potfile, msgs, file, work_file, is_templatized):
132 145
     finally:
133 146
         f.close()
134 147
 
135  
-def process_file(file, dirpath, potfile, domain, verbosity, extensions, wrap,
136  
-        location):
  148
+def process_file(file, dirpath, potfile, domain, verbosity,
  149
+                 extensions, wrap, location, stdout=sys.stdout):
137 150
     """
138 151
     Extract translatable literals from :param file: for :param domain:
139 152
     creating or updating the :param potfile: POT file.
@@ -144,7 +157,7 @@ def process_file(file, dirpath, potfile, domain, verbosity, extensions, wrap,
144 157
     from django.utils.translation import templatize
145 158
 
146 159
     if verbosity > 1:
147  
-        sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
  160
+        stdout.write('processing file %s in %s\n' % (file, dirpath))
148 161
     _, file_ext = os.path.splitext(file)
149 162
     if domain == 'djangojs' and file_ext in extensions:
150 163
         is_templatized = True
@@ -162,10 +175,8 @@ def process_file(file, dirpath, potfile, domain, verbosity, extensions, wrap,
162 175
             'xgettext -d %s -L C %s %s --keyword=gettext_noop '
163 176
             '--keyword=gettext_lazy --keyword=ngettext_lazy:1,2 '
164 177
             '--keyword=pgettext:1c,2 --keyword=npgettext:1c,2,3 '
165  
-            '--from-code UTF-8 --add-comments=Translators -o - "%s"' % (
166  
-                domain, wrap, location, work_file
167  
-            )
168  
-        )
  178
+            '--from-code UTF-8 --add-comments=Translators -o - "%s"' %
  179
+            (domain, wrap, location, work_file))
169 180
     elif domain == 'django' and (file_ext == '.py' or file_ext in extensions):
170 181
         thefile = file
171 182
         orig_file = os.path.join(dirpath, file)
@@ -187,9 +198,8 @@ def process_file(file, dirpath, potfile, domain, verbosity, extensions, wrap,
187 198
             '--keyword=ungettext_lazy:1,2 --keyword=pgettext:1c,2 '
188 199
             '--keyword=npgettext:1c,2,3 --keyword=pgettext_lazy:1c,2 '
189 200
             '--keyword=npgettext_lazy:1c,2,3 --from-code UTF-8 '
190  
-            '--add-comments=Translators -o - "%s"' % (
191  
-                domain, wrap, location, work_file)
192  
-        )
  201
+            '--add-comments=Translators -o - "%s"' %
  202
+            (domain, wrap, location, work_file))
193 203
     else:
194 204
         return
195 205
     msgs, errors = _popen(cmd)
@@ -206,8 +216,8 @@ def process_file(file, dirpath, potfile, domain, verbosity, extensions, wrap,
206 216
     if is_templatized:
207 217
         os.unlink(work_file)
208 218
 
209  
-def write_po_file(pofile, potfile, domain, locale, verbosity,
210  
-        copy_pforms, wrap, location, no_obsolete):
  219
+def write_po_file(pofile, potfile, domain, locale, verbosity, stdout,
  220
+                  copy_pforms, wrap, location, no_obsolete):
211 221
     """
212 222
     Creates of updates the :param pofile: PO file for :param domain: and :param
213 223
     locale:.  Uses contents of the existing :param potfile:.
@@ -232,7 +242,7 @@ def write_po_file(pofile, potfile, domain, locale, verbosity,
232 242
             raise CommandError(
233 243
                 "errors happened while running msgmerge\n%s" % errors)
234 244
     elif copy_pforms:
235  
-        msgs = copy_plural_forms(msgs, locale, domain, verbosity)
  245
+        msgs = copy_plural_forms(msgs, locale, domain, verbosity, stdout)
236 246
     msgs = msgs.replace(
237 247
         "#. #-#-#-#-#  %s.pot (PACKAGE VERSION)  #-#-#-#-#\n" % domain, "")
238 248
     f = open(pofile, 'wb')
@@ -250,7 +260,7 @@ def write_po_file(pofile, potfile, domain, locale, verbosity,
250 260
 
251 261
 def make_messages(locale=None, domain='django', verbosity=1, all=False,
252 262
         extensions=None, symlinks=False, ignore_patterns=None, no_wrap=False,
253  
-        no_location=False, no_obsolete=False):
  263
+        no_location=False, no_obsolete=False, stdout=sys.stdout):
254 264
     """
255 265
     Uses the ``locale/`` directory from the Django SVN tree or an
256 266
     application/project to process all files with translatable literals for
@@ -312,7 +322,7 @@ def make_messages(locale=None, domain='django', verbosity=1, all=False,
312 322
 
313 323
     for locale in locales:
314 324
         if verbosity > 0:
315  
-            print "processing language", locale
  325
+            stdout.write("processing language %s" % locale)
316 326
         basedir = os.path.join(localedir, locale, 'LC_MESSAGES')
317 327
         if not os.path.isdir(basedir):
318 328
             os.makedirs(basedir)
@@ -324,12 +334,12 @@ def make_messages(locale=None, domain='django', verbosity=1, all=False,
324 334
             os.unlink(potfile)
325 335
 
326 336
         for dirpath, file in find_files(".", ignore_patterns, verbosity,
327  
-                symlinks=symlinks):
  337
+                stdout, symlinks=symlinks):
328 338
             process_file(file, dirpath, potfile, domain, verbosity, extensions,
329  
-                    wrap, location)
  339
+                    wrap, location, stdout)
330 340
 
331 341
         if os.path.exists(potfile):
332  
-            write_po_file(pofile, potfile, domain, locale, verbosity,
  342
+            write_po_file(pofile, potfile, domain, locale, verbosity, stdout,
333 343
                     not invoked_for_django, wrap, location, no_obsolete)
334 344
 
335 345
 
@@ -357,7 +367,7 @@ class Command(NoArgsCommand):
357 367
         make_option('--no-obsolete', action='store_true', dest='no_obsolete',
358 368
             default=False, help="Remove obsolete message strings"),
359 369
     )
360  
-    help = ( "Runs over the entire source tree of the current directory and "
  370
+    help = ("Runs over the entire source tree of the current directory and "
361 371
 "pulls out all strings marked for translation. It creates (or updates) a message "
362 372
 "file in the conf/locale (in the django tree) or locale (for projects and "
363 373
 "applications) directory.\n\nYou must run this command with one of either the "
@@ -386,7 +396,8 @@ def handle_noargs(self, *args, **options):
386 396
             extensions = handle_extensions(extensions or ['html', 'txt'])
387 397
 
388 398
         if verbosity > 1:
389  
-            sys.stdout.write('examining files with the extensions: %s\n'
  399
+            self.stdout.write('examining files with the extensions: %s\n'
390 400
                              % get_text_list(list(extensions), 'and'))
391 401
 
392  
-        make_messages(locale, domain, verbosity, process_all, extensions, symlinks, ignore_patterns, no_wrap, no_location, no_obsolete)
  402
+        make_messages(locale, domain, verbosity, process_all, extensions,
  403
+            symlinks, ignore_patterns, no_wrap, no_location, no_obsolete, self.stdout)
7  tests/regressiontests/i18n/commands/extraction.py
@@ -4,6 +4,7 @@
4 4
 import os
5 5
 import re
6 6
 import shutil
  7
+from StringIO import StringIO
7 8
 
8 9
 from django.core import management
9 10
 from django.test import TestCase
@@ -177,7 +178,11 @@ class IgnoredExtractorTests(ExtractorTests):
177 178
     def test_ignore_option(self):
178 179
         os.chdir(self.test_dir)
179 180
         pattern1 = os.path.join('ignore_dir', '*')
180  
-        management.call_command('makemessages', locale=LOCALE, verbosity=0, ignore_patterns=[pattern1])
  181
+        stdout = StringIO()
  182
+        management.call_command('makemessages', locale=LOCALE, verbosity=2,
  183
+            ignore_patterns=[pattern1], stdout=stdout)
  184
+        data = stdout.getvalue()
  185
+        self.assertTrue("ignoring directory ignore_dir" in data)
181 186
         self.assertTrue(os.path.exists(self.PO_FILE))
182 187
         with open(self.PO_FILE, 'r') as fp:
183 188
             po_contents = fp.read()

0 notes on commit c606554

Please sign in to comment.
Something went wrong with that request. Please try again.