Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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 | import os |
michael@0 | 6 | import zipfile |
michael@0 | 7 | import simplejson as json |
michael@0 | 8 | from cuddlefish.util import filter_filenames, filter_dirnames |
michael@0 | 9 | |
michael@0 | 10 | class HarnessOptionAlreadyDefinedError(Exception): |
michael@0 | 11 | """You cannot use --harness-option on keys that already exist in |
michael@0 | 12 | harness-options.json""" |
michael@0 | 13 | |
michael@0 | 14 | ZIPSEP = "/" # always use "/" in zipfiles |
michael@0 | 15 | |
michael@0 | 16 | def make_zipfile_path(localroot, localpath): |
michael@0 | 17 | return ZIPSEP.join(localpath[len(localroot)+1:].split(os.sep)) |
michael@0 | 18 | |
michael@0 | 19 | def mkzipdir(zf, path): |
michael@0 | 20 | dirinfo = zipfile.ZipInfo(path) |
michael@0 | 21 | dirinfo.external_attr = int("040755", 8) << 16L |
michael@0 | 22 | zf.writestr(dirinfo, "") |
michael@0 | 23 | |
michael@0 | 24 | def build_xpi(template_root_dir, manifest, xpi_path, |
michael@0 | 25 | harness_options, limit_to=None, extra_harness_options={}, |
michael@0 | 26 | bundle_sdk=True, pkgdir=""): |
michael@0 | 27 | IGNORED_FILES = [".hgignore", ".DS_Store", "install.rdf", |
michael@0 | 28 | "application.ini", xpi_path] |
michael@0 | 29 | |
michael@0 | 30 | files_to_copy = {} # maps zipfile path to local-disk abspath |
michael@0 | 31 | dirs_to_create = set() # zipfile paths, no trailing slash |
michael@0 | 32 | |
michael@0 | 33 | zf = zipfile.ZipFile(xpi_path, "w", zipfile.ZIP_DEFLATED) |
michael@0 | 34 | |
michael@0 | 35 | open('.install.rdf', 'w').write(str(manifest)) |
michael@0 | 36 | zf.write('.install.rdf', 'install.rdf') |
michael@0 | 37 | os.remove('.install.rdf') |
michael@0 | 38 | |
michael@0 | 39 | # Handle add-on icon |
michael@0 | 40 | if 'icon' in harness_options: |
michael@0 | 41 | zf.write(str(harness_options['icon']), 'icon.png') |
michael@0 | 42 | del harness_options['icon'] |
michael@0 | 43 | |
michael@0 | 44 | if 'icon64' in harness_options: |
michael@0 | 45 | zf.write(str(harness_options['icon64']), 'icon64.png') |
michael@0 | 46 | del harness_options['icon64'] |
michael@0 | 47 | |
michael@0 | 48 | # chrome.manifest |
michael@0 | 49 | if os.path.isfile(os.path.join(pkgdir, 'chrome.manifest')): |
michael@0 | 50 | files_to_copy['chrome.manifest'] = os.path.join(pkgdir, 'chrome.manifest') |
michael@0 | 51 | |
michael@0 | 52 | # chrome folder (would contain content, skin, and locale folders typically) |
michael@0 | 53 | folder = 'chrome' |
michael@0 | 54 | if os.path.exists(os.path.join(pkgdir, folder)): |
michael@0 | 55 | dirs_to_create.add('chrome') |
michael@0 | 56 | # cp -r folder |
michael@0 | 57 | abs_dirname = os.path.join(pkgdir, folder) |
michael@0 | 58 | for dirpath, dirnames, filenames in os.walk(abs_dirname): |
michael@0 | 59 | goodfiles = list(filter_filenames(filenames, IGNORED_FILES)) |
michael@0 | 60 | dirnames[:] = filter_dirnames(dirnames) |
michael@0 | 61 | for dirname in dirnames: |
michael@0 | 62 | arcpath = make_zipfile_path(template_root_dir, |
michael@0 | 63 | os.path.join(dirpath, dirname)) |
michael@0 | 64 | dirs_to_create.add(arcpath) |
michael@0 | 65 | for filename in goodfiles: |
michael@0 | 66 | abspath = os.path.join(dirpath, filename) |
michael@0 | 67 | arcpath = ZIPSEP.join( |
michael@0 | 68 | [folder, |
michael@0 | 69 | make_zipfile_path(abs_dirname, os.path.join(dirpath, filename)), |
michael@0 | 70 | ]) |
michael@0 | 71 | files_to_copy[str(arcpath)] = str(abspath) |
michael@0 | 72 | |
michael@0 | 73 | # Handle simple-prefs |
michael@0 | 74 | if 'preferences' in harness_options: |
michael@0 | 75 | from options_xul import parse_options, validate_prefs |
michael@0 | 76 | |
michael@0 | 77 | validate_prefs(harness_options["preferences"]) |
michael@0 | 78 | |
michael@0 | 79 | opts_xul = parse_options(harness_options["preferences"], |
michael@0 | 80 | harness_options["jetpackID"], |
michael@0 | 81 | harness_options["preferencesBranch"]) |
michael@0 | 82 | open('.options.xul', 'wb').write(opts_xul.encode("utf-8")) |
michael@0 | 83 | zf.write('.options.xul', 'options.xul') |
michael@0 | 84 | os.remove('.options.xul') |
michael@0 | 85 | |
michael@0 | 86 | from options_defaults import parse_options_defaults |
michael@0 | 87 | prefs_js = parse_options_defaults(harness_options["preferences"], |
michael@0 | 88 | harness_options["preferencesBranch"]) |
michael@0 | 89 | open('.prefs.js', 'wb').write(prefs_js.encode("utf-8")) |
michael@0 | 90 | |
michael@0 | 91 | else: |
michael@0 | 92 | open('.prefs.js', 'wb').write("") |
michael@0 | 93 | |
michael@0 | 94 | zf.write('.prefs.js', 'defaults/preferences/prefs.js') |
michael@0 | 95 | os.remove('.prefs.js') |
michael@0 | 96 | |
michael@0 | 97 | |
michael@0 | 98 | for dirpath, dirnames, filenames in os.walk(template_root_dir): |
michael@0 | 99 | filenames = list(filter_filenames(filenames, IGNORED_FILES)) |
michael@0 | 100 | dirnames[:] = filter_dirnames(dirnames) |
michael@0 | 101 | for dirname in dirnames: |
michael@0 | 102 | arcpath = make_zipfile_path(template_root_dir, |
michael@0 | 103 | os.path.join(dirpath, dirname)) |
michael@0 | 104 | dirs_to_create.add(arcpath) |
michael@0 | 105 | for filename in filenames: |
michael@0 | 106 | abspath = os.path.join(dirpath, filename) |
michael@0 | 107 | arcpath = make_zipfile_path(template_root_dir, abspath) |
michael@0 | 108 | files_to_copy[arcpath] = abspath |
michael@0 | 109 | |
michael@0 | 110 | # `packages` attribute contains a dictionnary of dictionnary |
michael@0 | 111 | # of all packages sections directories |
michael@0 | 112 | for packageName in harness_options['packages']: |
michael@0 | 113 | base_arcpath = ZIPSEP.join(['resources', packageName]) |
michael@0 | 114 | # Eventually strip sdk files. We need to do that in addition to the |
michael@0 | 115 | # whilelist as the whitelist is only used for `cfx xpi`: |
michael@0 | 116 | if not bundle_sdk and packageName == 'addon-sdk': |
michael@0 | 117 | continue |
michael@0 | 118 | # Always write the top directory, even if it contains no files, since |
michael@0 | 119 | # the harness will try to access it. |
michael@0 | 120 | dirs_to_create.add(base_arcpath) |
michael@0 | 121 | for sectionName in harness_options['packages'][packageName]: |
michael@0 | 122 | abs_dirname = harness_options['packages'][packageName][sectionName] |
michael@0 | 123 | base_arcpath = ZIPSEP.join(['resources', packageName, sectionName]) |
michael@0 | 124 | # Always write the top directory, even if it contains no files, since |
michael@0 | 125 | # the harness will try to access it. |
michael@0 | 126 | dirs_to_create.add(base_arcpath) |
michael@0 | 127 | # cp -r stuff from abs_dirname/ into ZIP/resources/RESOURCEBASE/ |
michael@0 | 128 | for dirpath, dirnames, filenames in os.walk(abs_dirname): |
michael@0 | 129 | goodfiles = list(filter_filenames(filenames, IGNORED_FILES)) |
michael@0 | 130 | dirnames[:] = filter_dirnames(dirnames) |
michael@0 | 131 | for filename in goodfiles: |
michael@0 | 132 | abspath = os.path.join(dirpath, filename) |
michael@0 | 133 | if limit_to is not None and abspath not in limit_to: |
michael@0 | 134 | continue # strip unused files |
michael@0 | 135 | arcpath = ZIPSEP.join( |
michael@0 | 136 | ['resources', |
michael@0 | 137 | packageName, |
michael@0 | 138 | sectionName, |
michael@0 | 139 | make_zipfile_path(abs_dirname, |
michael@0 | 140 | os.path.join(dirpath, filename)), |
michael@0 | 141 | ]) |
michael@0 | 142 | files_to_copy[str(arcpath)] = str(abspath) |
michael@0 | 143 | del harness_options['packages'] |
michael@0 | 144 | |
michael@0 | 145 | locales_json_data = {"locales": []} |
michael@0 | 146 | mkzipdir(zf, "locale/") |
michael@0 | 147 | for language in sorted(harness_options['locale']): |
michael@0 | 148 | locales_json_data["locales"].append(language) |
michael@0 | 149 | locale = harness_options['locale'][language] |
michael@0 | 150 | # Be carefull about strings, we need to always ensure working with UTF-8 |
michael@0 | 151 | jsonStr = json.dumps(locale, indent=1, sort_keys=True, ensure_ascii=False) |
michael@0 | 152 | info = zipfile.ZipInfo('locale/' + language + '.json') |
michael@0 | 153 | info.external_attr = 0644 << 16L |
michael@0 | 154 | zf.writestr(info, jsonStr.encode( "utf-8" )) |
michael@0 | 155 | del harness_options['locale'] |
michael@0 | 156 | |
michael@0 | 157 | jsonStr = json.dumps(locales_json_data, ensure_ascii=True) +"\n" |
michael@0 | 158 | info = zipfile.ZipInfo('locales.json') |
michael@0 | 159 | info.external_attr = 0644 << 16L |
michael@0 | 160 | zf.writestr(info, jsonStr.encode("utf-8")) |
michael@0 | 161 | |
michael@0 | 162 | # now figure out which directories we need: all retained files parents |
michael@0 | 163 | for arcpath in files_to_copy: |
michael@0 | 164 | bits = arcpath.split("/") |
michael@0 | 165 | for i in range(1,len(bits)): |
michael@0 | 166 | parentpath = ZIPSEP.join(bits[0:i]) |
michael@0 | 167 | dirs_to_create.add(parentpath) |
michael@0 | 168 | |
michael@0 | 169 | # Create zipfile in alphabetical order, with each directory before its |
michael@0 | 170 | # files |
michael@0 | 171 | for name in sorted(dirs_to_create.union(set(files_to_copy))): |
michael@0 | 172 | if name in dirs_to_create: |
michael@0 | 173 | mkzipdir(zf, name+"/") |
michael@0 | 174 | if name in files_to_copy: |
michael@0 | 175 | zf.write(files_to_copy[name], name) |
michael@0 | 176 | |
michael@0 | 177 | # Add extra harness options |
michael@0 | 178 | harness_options = harness_options.copy() |
michael@0 | 179 | for key,value in extra_harness_options.items(): |
michael@0 | 180 | if key in harness_options: |
michael@0 | 181 | msg = "Can't use --harness-option for existing key '%s'" % key |
michael@0 | 182 | raise HarnessOptionAlreadyDefinedError(msg) |
michael@0 | 183 | harness_options[key] = value |
michael@0 | 184 | |
michael@0 | 185 | # Write harness-options.json |
michael@0 | 186 | open('.options.json', 'w').write(json.dumps(harness_options, indent=1, |
michael@0 | 187 | sort_keys=True)) |
michael@0 | 188 | zf.write('.options.json', 'harness-options.json') |
michael@0 | 189 | os.remove('.options.json') |
michael@0 | 190 | |
michael@0 | 191 | zf.close() |