1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/python/mozbuild/mozpack/packager/l10n.py Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,174 @@ 1.4 +# This Source Code Form is subject to the terms of the Mozilla Public 1.5 +# License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 +# file, You can obtain one at http://mozilla.org/MPL/2.0/. 1.7 + 1.8 +''' 1.9 +Replace localized parts of a packaged directory with data from a langpack 1.10 +directory. 1.11 +''' 1.12 + 1.13 +import os 1.14 +import mozpack.path 1.15 +from mozpack.packager.formats import ( 1.16 + FlatFormatter, 1.17 + JarFormatter, 1.18 + OmniJarFormatter, 1.19 +) 1.20 +from mozpack.packager import SimplePackager 1.21 +from mozpack.files import ManifestFile 1.22 +from mozpack.copier import ( 1.23 + FileCopier, 1.24 + Jarrer, 1.25 +) 1.26 +from mozpack.chrome.manifest import ( 1.27 + ManifestLocale, 1.28 + ManifestEntryWithRelPath, 1.29 + is_manifest, 1.30 + ManifestChrome, 1.31 + Manifest, 1.32 +) 1.33 +from mozpack.errors import errors 1.34 +from mozpack.packager.unpack import UnpackFinder 1.35 +from createprecomplete import generate_precomplete 1.36 + 1.37 + 1.38 +class LocaleManifestFinder(object): 1.39 + def __init__(self, finder): 1.40 + # Read all manifest entries 1.41 + manifests = dict((p, m) for p, m in finder.find('**/*.manifest') 1.42 + if is_manifest(p)) 1.43 + assert all(isinstance(m, ManifestFile) 1.44 + for m in manifests.itervalues()) 1.45 + self.entries = [e for m in manifests.itervalues() 1.46 + for e in m if e.localized] 1.47 + # Find unique locales used in these manifest entries. 1.48 + self.locales = list(set(e.id for e in self.entries 1.49 + if isinstance(e, ManifestLocale))) 1.50 + # Find all paths whose manifest are included by no other manifest. 1.51 + includes = set(mozpack.path.join(e.base, e.relpath) 1.52 + for m in manifests.itervalues() 1.53 + for e in m if isinstance(e, Manifest)) 1.54 + self.bases = [mozpack.path.dirname(p) 1.55 + for p in set(manifests.keys()) - includes] 1.56 + 1.57 + 1.58 +def _repack(app_finder, l10n_finder, copier, formatter, non_chrome=set()): 1.59 + app = LocaleManifestFinder(app_finder) 1.60 + l10n = LocaleManifestFinder(l10n_finder) 1.61 + 1.62 + # The code further below assumes there's only one locale replaced with 1.63 + # another one. 1.64 + if len(app.locales) > 1 or len(l10n.locales) > 1: 1.65 + errors.fatal("Multiple locales aren't supported") 1.66 + locale = app.locales[0] 1.67 + l10n_locale = l10n.locales[0] 1.68 + 1.69 + # For each base directory, store what path a locale chrome package name 1.70 + # corresponds to. 1.71 + # e.g., for the following entry under app/chrome: 1.72 + # locale foo en-US path/to/files 1.73 + # keep track that the locale path for foo in app is 1.74 + # app/chrome/path/to/files. 1.75 + l10n_paths = {} 1.76 + for e in l10n.entries: 1.77 + if isinstance(e, ManifestChrome): 1.78 + base = mozpack.path.basedir(e.path, app.bases) 1.79 + l10n_paths.setdefault(base, {}) 1.80 + l10n_paths[base][e.name] = e.path 1.81 + 1.82 + # For chrome and non chrome files or directories, store what langpack path 1.83 + # corresponds to a package path. 1.84 + paths = dict((e.path, 1.85 + l10n_paths[mozpack.path.basedir(e.path, app.bases)][e.name]) 1.86 + for e in app.entries 1.87 + if isinstance(e, ManifestEntryWithRelPath)) 1.88 + 1.89 + for pattern in non_chrome: 1.90 + for base in app.bases: 1.91 + path = mozpack.path.join(base, pattern) 1.92 + left = set(p for p, f in app_finder.find(path)) 1.93 + right = set(p for p, f in l10n_finder.find(path)) 1.94 + for p in right: 1.95 + paths[p] = p 1.96 + for p in left - right: 1.97 + paths[p] = None 1.98 + 1.99 + # Create a new package, with non localized bits coming from the original 1.100 + # package, and localized bits coming from the langpack. 1.101 + packager = SimplePackager(formatter) 1.102 + for p, f in app_finder: 1.103 + if is_manifest(p): 1.104 + # Remove localized manifest entries. 1.105 + for e in [e for e in f if e.localized]: 1.106 + f.remove(e) 1.107 + # If the path is one that needs a locale replacement, use the 1.108 + # corresponding file from the langpack. 1.109 + path = None 1.110 + if p in paths: 1.111 + path = paths[p] 1.112 + if not path: 1.113 + continue 1.114 + else: 1.115 + base = mozpack.path.basedir(p, paths.keys()) 1.116 + if base: 1.117 + subpath = mozpack.path.relpath(p, base) 1.118 + path = mozpack.path.normpath(mozpack.path.join(paths[base], 1.119 + subpath)) 1.120 + if path: 1.121 + files = [f for p, f in l10n_finder.find(path)] 1.122 + if not len(files): 1.123 + if base not in non_chrome: 1.124 + errors.error("Missing file: %s" % 1.125 + os.path.join(l10n_finder.base, path)) 1.126 + else: 1.127 + packager.add(path, files[0]) 1.128 + else: 1.129 + packager.add(p, f) 1.130 + 1.131 + # Add localized manifest entries from the langpack. 1.132 + l10n_manifests = [] 1.133 + for base in set(e.base for e in l10n.entries): 1.134 + m = ManifestFile(base, [e for e in l10n.entries if e.base == base]) 1.135 + path = mozpack.path.join(base, 'chrome.%s.manifest' % l10n_locale) 1.136 + l10n_manifests.append((path, m)) 1.137 + bases = packager.get_bases() 1.138 + for path, m in l10n_manifests: 1.139 + base = mozpack.path.basedir(path, bases) 1.140 + packager.add(path, m) 1.141 + # Add a "manifest $path" entry in the top manifest under that base. 1.142 + m = ManifestFile(base) 1.143 + m.add(Manifest(base, mozpack.path.relpath(path, base))) 1.144 + packager.add(mozpack.path.join(base, 'chrome.manifest'), m) 1.145 + 1.146 + packager.close() 1.147 + 1.148 + # Add any remaining non chrome files. 1.149 + for pattern in non_chrome: 1.150 + for base in bases: 1.151 + for p, f in l10n_finder.find(mozpack.path.join(base, pattern)): 1.152 + if not formatter.contains(p): 1.153 + formatter.add(p, f) 1.154 + 1.155 + # Transplant jar preloading information. 1.156 + for path, log in app_finder.jarlogs.iteritems(): 1.157 + assert isinstance(copier[path], Jarrer) 1.158 + copier[path].preload([l.replace(locale, l10n_locale) for l in log]) 1.159 + 1.160 + 1.161 +def repack(source, l10n, non_resources=[], non_chrome=set()): 1.162 + app_finder = UnpackFinder(source) 1.163 + l10n_finder = UnpackFinder(l10n) 1.164 + copier = FileCopier() 1.165 + if app_finder.kind == 'flat': 1.166 + formatter = FlatFormatter(copier) 1.167 + elif app_finder.kind == 'jar': 1.168 + formatter = JarFormatter(copier, optimize=app_finder.optimizedjars) 1.169 + elif app_finder.kind == 'omni': 1.170 + formatter = OmniJarFormatter(copier, app_finder.omnijar, 1.171 + optimize=app_finder.optimizedjars, 1.172 + non_resources=non_resources) 1.173 + 1.174 + with errors.accumulate(): 1.175 + _repack(app_finder, l10n_finder, copier, formatter, non_chrome) 1.176 + copier.copy(source, skip_if_older=False) 1.177 + generate_precomplete(source)