python/mozbuild/mozpack/packager/l10n.py

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

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

mercurial