python/mozbuild/mozpack/packager/l10n.py

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

     1 # This Source Code Form is subject to the terms of the Mozilla Public
     2 # License, v. 2.0. If a copy of the MPL was not distributed with this
     3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
     5 '''
     6 Replace localized parts of a packaged directory with data from a langpack
     7 directory.
     8 '''
    10 import os
    11 import mozpack.path
    12 from mozpack.packager.formats import (
    13     FlatFormatter,
    14     JarFormatter,
    15     OmniJarFormatter,
    16 )
    17 from mozpack.packager import SimplePackager
    18 from mozpack.files import ManifestFile
    19 from mozpack.copier import (
    20     FileCopier,
    21     Jarrer,
    22 )
    23 from mozpack.chrome.manifest import (
    24     ManifestLocale,
    25     ManifestEntryWithRelPath,
    26     is_manifest,
    27     ManifestChrome,
    28     Manifest,
    29 )
    30 from mozpack.errors import errors
    31 from mozpack.packager.unpack import UnpackFinder
    32 from createprecomplete import generate_precomplete
    35 class LocaleManifestFinder(object):
    36     def __init__(self, finder):
    37         # Read all manifest entries
    38         manifests = dict((p, m) for p, m in finder.find('**/*.manifest')
    39                          if is_manifest(p))
    40         assert all(isinstance(m, ManifestFile)
    41                    for m in manifests.itervalues())
    42         self.entries = [e for m in manifests.itervalues()
    43                         for e in m if e.localized]
    44         # Find unique locales used in these manifest entries.
    45         self.locales = list(set(e.id for e in self.entries
    46                                 if isinstance(e, ManifestLocale)))
    47         # Find all paths whose manifest are included by no other manifest.
    48         includes = set(mozpack.path.join(e.base, e.relpath)
    49                        for m in manifests.itervalues()
    50                        for e in m if isinstance(e, Manifest))
    51         self.bases = [mozpack.path.dirname(p)
    52                       for p in set(manifests.keys()) - includes]
    55 def _repack(app_finder, l10n_finder, copier, formatter, non_chrome=set()):
    56     app = LocaleManifestFinder(app_finder)
    57     l10n = LocaleManifestFinder(l10n_finder)
    59     # The code further below assumes there's only one locale replaced with
    60     # another one.
    61     if len(app.locales) > 1 or len(l10n.locales) > 1:
    62         errors.fatal("Multiple locales aren't supported")
    63     locale = app.locales[0]
    64     l10n_locale = l10n.locales[0]
    66     # For each base directory, store what path a locale chrome package name
    67     # corresponds to.
    68     # e.g., for the following entry under app/chrome:
    69     #     locale foo en-US path/to/files
    70     # keep track that the locale path for foo in app is
    71     # app/chrome/path/to/files.
    72     l10n_paths = {}
    73     for e in l10n.entries:
    74         if isinstance(e, ManifestChrome):
    75             base = mozpack.path.basedir(e.path, app.bases)
    76             l10n_paths.setdefault(base, {})
    77             l10n_paths[base][e.name] = e.path
    79     # For chrome and non chrome files or directories, store what langpack path
    80     # corresponds to a package path.
    81     paths = dict((e.path,
    82                   l10n_paths[mozpack.path.basedir(e.path, app.bases)][e.name])
    83                  for e in app.entries
    84                  if isinstance(e, ManifestEntryWithRelPath))
    86     for pattern in non_chrome:
    87         for base in app.bases:
    88             path = mozpack.path.join(base, pattern)
    89             left = set(p for p, f in app_finder.find(path))
    90             right = set(p for p, f in l10n_finder.find(path))
    91             for p in right:
    92                 paths[p] = p
    93             for p in left - right:
    94                 paths[p] = None
    96     # Create a new package, with non localized bits coming from the original
    97     # package, and localized bits coming from the langpack.
    98     packager = SimplePackager(formatter)
    99     for p, f in app_finder:
   100         if is_manifest(p):
   101             # Remove localized manifest entries.
   102             for e in [e for e in f if e.localized]:
   103                 f.remove(e)
   104         # If the path is one that needs a locale replacement, use the
   105         # corresponding file from the langpack.
   106         path = None
   107         if p in paths:
   108             path = paths[p]
   109             if not path:
   110                 continue
   111         else:
   112             base = mozpack.path.basedir(p, paths.keys())
   113             if base:
   114                 subpath = mozpack.path.relpath(p, base)
   115                 path = mozpack.path.normpath(mozpack.path.join(paths[base],
   116                                                                subpath))
   117         if path:
   118             files = [f for p, f in l10n_finder.find(path)]
   119             if not len(files):
   120                 if base not in non_chrome:
   121                     errors.error("Missing file: %s" %
   122                                  os.path.join(l10n_finder.base, path))
   123             else:
   124                 packager.add(path, files[0])
   125         else:
   126             packager.add(p, f)
   128     # Add localized manifest entries from the langpack.
   129     l10n_manifests = []
   130     for base in set(e.base for e in l10n.entries):
   131         m = ManifestFile(base, [e for e in l10n.entries if e.base == base])
   132         path = mozpack.path.join(base, 'chrome.%s.manifest' % l10n_locale)
   133         l10n_manifests.append((path, m))
   134     bases = packager.get_bases()
   135     for path, m in l10n_manifests:
   136         base = mozpack.path.basedir(path, bases)
   137         packager.add(path, m)
   138         # Add a "manifest $path" entry in the top manifest under that base.
   139         m = ManifestFile(base)
   140         m.add(Manifest(base, mozpack.path.relpath(path, base)))
   141         packager.add(mozpack.path.join(base, 'chrome.manifest'), m)
   143     packager.close()
   145     # Add any remaining non chrome files.
   146     for pattern in non_chrome:
   147         for base in bases:
   148             for p, f in l10n_finder.find(mozpack.path.join(base, pattern)):
   149                 if not formatter.contains(p):
   150                     formatter.add(p, f)
   152     # Transplant jar preloading information.
   153     for path, log in app_finder.jarlogs.iteritems():
   154         assert isinstance(copier[path], Jarrer)
   155         copier[path].preload([l.replace(locale, l10n_locale) for l in log])
   158 def repack(source, l10n, non_resources=[], non_chrome=set()):
   159     app_finder = UnpackFinder(source)
   160     l10n_finder = UnpackFinder(l10n)
   161     copier = FileCopier()
   162     if app_finder.kind == 'flat':
   163         formatter = FlatFormatter(copier)
   164     elif app_finder.kind == 'jar':
   165         formatter = JarFormatter(copier, optimize=app_finder.optimizedjars)
   166     elif app_finder.kind == 'omni':
   167         formatter = OmniJarFormatter(copier, app_finder.omnijar,
   168                                      optimize=app_finder.optimizedjars,
   169                                      non_resources=non_resources)
   171     with errors.accumulate():
   172         _repack(app_finder, l10n_finder, copier, formatter, non_chrome)
   173     copier.copy(source, skip_if_older=False)
   174     generate_precomplete(source)

mercurial