| Index: packagerGecko.py | 
| diff --git a/packagerGecko.py b/packagerGecko.py | 
| deleted file mode 100644 | 
| index 0b038d2c05de350381bb4bf132cf598b14f1e094..0000000000000000000000000000000000000000 | 
| --- a/packagerGecko.py | 
| +++ /dev/null | 
| @@ -1,340 +0,0 @@ | 
| -# This Source Code Form is subject to the terms of the Mozilla Public | 
| -# License, v. 2.0. If a copy of the MPL was not distributed with this | 
| -# file, You can obtain one at http://mozilla.org/MPL/2.0/. | 
| - | 
| -import os | 
| -import sys | 
| -import re | 
| -import hashlib | 
| -import base64 | 
| -import urllib | 
| -import json | 
| -import io | 
| -from ConfigParser import SafeConfigParser | 
| -from StringIO import StringIO | 
| -import xml.dom.minidom as minidom | 
| -import buildtools.localeTools as localeTools | 
| - | 
| -import packager | 
| -from packager import readMetadata, getMetadataPath, getDefaultFileName, getBuildVersion, getTemplate, Files | 
| - | 
| -KNOWN_APPS = { | 
| - 'conkeror': '{a79fe89b-6662-4ff4-8e88-09950ad4dfde}', | 
| - 'emusic': 'dlm@emusic.com', | 
| - 'fennec': '{a23983c0-fd0e-11dc-95ff-0800200c9a66}', | 
| - 'fennec2': '{aa3c5121-dab2-40e2-81ca-7ea25febc110}', | 
| - 'firefox': '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}', | 
| - 'midbrowser': '{aa5ca914-c309-495d-91cf-3141bbb04115}', | 
| - 'prism': 'prism@developer.mozilla.org', | 
| - 'seamonkey': '{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}', | 
| - 'songbird': 'songbird@songbirdnest.com', | 
| - 'thunderbird': '{3550f703-e582-4d05-9a08-453d09bdfdc6}', | 
| - 'toolkit': 'toolkit@mozilla.org', | 
| - 'adblockbrowser': '{55aba3ac-94d3-41a8-9e25-5c21fe874539}', | 
| -} | 
| - | 
| -defaultLocale = 'en-US' | 
| - | 
| - | 
| -def getChromeDir(baseDir): | 
| - return os.path.join(baseDir, 'chrome') | 
| - | 
| - | 
| -def getLocalesDir(baseDir): | 
| - return os.path.join(getChromeDir(baseDir), 'locale') | 
| - | 
| - | 
| -def getChromeSubdirs(baseDir, locales): | 
| - result = {} | 
| - chromeDir = getChromeDir(baseDir) | 
| - for subdir in ('content', 'skin'): | 
| - result[subdir] = os.path.join(chromeDir, subdir) | 
| - for locale in locales: | 
| - result['locale/%s' % locale] = os.path.join(chromeDir, 'locale', locale) | 
| - return result | 
| - | 
| - | 
| -def getPackageFiles(params): | 
| - result = { | 
| - 'chrome', 'components', 'modules', 'lib', 'resources', 'webextension', | 
| - 'chrome.manifest', 'icon.png', 'icon64.png' | 
| - } | 
| - | 
| - baseDir = params['baseDir'] | 
| - for file in os.listdir(baseDir): | 
| - if file.endswith('.js') or file.endswith('.xml'): | 
| - result.add(file) | 
| - return result | 
| - | 
| - | 
| -def getIgnoredFiles(params): | 
| - return {'.incomplete', 'meta.properties'} | 
| - | 
| - | 
| -def archive_path(path, baseDir): | 
| - return '/'.join(os.path.split(os.path.relpath(path, baseDir))) | 
| - | 
| - | 
| -def isValidLocale(localesDir, dir, includeIncomplete=False): | 
| - if re.search(r'[^\w\-]', dir): | 
| - return False | 
| - curLocaleDir = os.path.join(localesDir, dir) | 
| - if not os.path.isdir(curLocaleDir): | 
| - return False | 
| - if len(os.listdir(curLocaleDir)) == 0: | 
| - return False | 
| - if not includeIncomplete and os.path.exists(os.path.join(localesDir, dir, '.incomplete')): | 
| - return False | 
| - return True | 
| - | 
| - | 
| -def getLocales(baseDir, includeIncomplete=False): | 
| - global defaultLocale | 
| - localesDir = getLocalesDir(baseDir) | 
| - locales = filter(lambda dir: isValidLocale(localesDir, dir, includeIncomplete), os.listdir(localesDir)) | 
| - locales.sort(key=lambda x: '!' if x == defaultLocale else x) | 
| - return locales | 
| - | 
| - | 
| -def processFile(path, data, params): | 
| - if path.endswith('.manifest') and data.find('{{LOCALE}}') >= 0: | 
| - localesRegExp = re.compile(r'^(.*?){{LOCALE}}(.*?){{LOCALE}}(.*)$', re.M) | 
| - replacement = '\n'.join(map(lambda locale: r'\1%s\2%s\3' % (locale, locale), params['locales'])) | 
| - data = re.sub(localesRegExp, replacement, data) | 
| - | 
| - return data | 
| - | 
| - | 
| -def readLocaleMetadata(baseDir, locales): | 
| - result = {} | 
| - | 
| - # Make sure we always have fallback data even if the default locale isn't part | 
| - # of the build | 
| - locales = list(locales) | 
| - if not defaultLocale in locales: | 
| - locales.append(defaultLocale) | 
| - | 
| - for locale in locales: | 
| - data = SafeConfigParser() | 
| - data.optionxform = str | 
| - try: | 
| - result[locale] = localeTools.readFile(os.path.join(getLocalesDir(baseDir), locale, 'meta.properties')) | 
| - except: | 
| - result[locale] = {} | 
| - return result | 
| - | 
| - | 
| -def getContributors(metadata): | 
| - main = [] | 
| - additional = set() | 
| - if metadata.has_section('contributors'): | 
| - options = metadata.options('contributors') | 
| - options.sort() | 
| - for option in options: | 
| - value = metadata.get('contributors', option) | 
| - if re.search(r'\D', option): | 
| - match = re.search(r'^\s*(\S+)\s+//([^/\s]+)/@(\S+)\s*$', value) | 
| - if not match: | 
| - print >>sys.stderr, 'Warning: unrecognized contributor location "%s"\n' % value | 
| - continue | 
| - baseDir = os.path.dirname(metadata.option_source('contributors', option)) | 
| - parts = match.group(1).split('/') | 
| - dom = minidom.parse(os.path.join(baseDir, *parts)) | 
| - tags = dom.getElementsByTagName(match.group(2)) | 
| - for tag in tags: | 
| - if tag.hasAttribute(match.group(3)): | 
| - for name in re.split(r'\s*,\s*', tag.getAttribute(match.group(3))): | 
| - additional.add(name) | 
| - else: | 
| - main.append(value) | 
| - return main + sorted(additional, key=unicode.lower) | 
| - | 
| - | 
| -def initTranslators(localeMetadata): | 
| - for locale in localeMetadata.itervalues(): | 
| - if 'translator' in locale: | 
| - locale['translators'] = sorted(map(lambda t: t.strip(), locale['translator'].split(',')), key=unicode.lower) | 
| - else: | 
| - locale['translators'] = [] | 
| - | 
| - | 
| -def createManifest(params): | 
| - global KNOWN_APPS, defaultLocale | 
| - template = getTemplate('install.rdf.tmpl', autoEscape=True) | 
| - templateData = dict(params) | 
| - templateData['localeMetadata'] = readLocaleMetadata(params['baseDir'], params['locales']) | 
| - initTranslators(templateData['localeMetadata']) | 
| - templateData['KNOWN_APPS'] = KNOWN_APPS | 
| - templateData['defaultLocale'] = defaultLocale | 
| - return template.render(templateData).encode('utf-8') | 
| - | 
| - | 
| -def importLocales(params, files): | 
| - SECTION = 'import_locales' | 
| - if not params['metadata'].has_section(SECTION): | 
| - return | 
| - | 
| - import localeTools | 
| - | 
| - for locale in params['locales']: | 
| - for item in params['metadata'].items(SECTION): | 
| - path, keys = item | 
| - parts = [locale if p == '*' else p for p in path.split('/')] | 
| - source = os.path.join(os.path.dirname(item.source), *parts) | 
| - if not os.path.exists(source): | 
| - continue | 
| - | 
| - with io.open(source, 'r', encoding='utf-8') as handle: | 
| - data = json.load(handle) | 
| - | 
| - target_name = os.path.splitext(os.path.basename(source))[0] + '.properties' | 
| - target = archive_path(os.path.join(getLocalesDir(params['baseDir']), locale, target_name), params['baseDir']) | 
| - | 
| - files[target] = '' | 
| - for key, value in sorted(data.items()): | 
| - message = value['message'] | 
| - files[target] += localeTools.generateStringEntry(key, message, target).encode('utf-8') | 
| - | 
| - | 
| -def fixupLocales(params, files): | 
| - global defaultLocale | 
| - | 
| - # Read in default locale data, it might not be included in package files | 
| - defaultLocaleDir = os.path.join(getLocalesDir(params['baseDir']), defaultLocale) | 
| - reference_files = Files(getPackageFiles(params), getIgnoredFiles(params)) | 
| - reference_files.read(defaultLocaleDir, archive_path(defaultLocaleDir, params['baseDir'])) | 
| - reference_params = dict(params) | 
| - reference_params['locales'] = [defaultLocale] | 
| - importLocales(reference_params, reference_files) | 
| - | 
| - reference = {} | 
| - for path, data in reference_files.iteritems(): | 
| - filename = path.split('/')[-1] | 
| - data = localeTools.parseString(data.decode('utf-8'), filename) | 
| - if data: | 
| - reference[filename] = data | 
| - | 
| - for locale in params['locales']: | 
| - for file in reference.iterkeys(): | 
| - path = 'chrome/locale/%s/%s' % (locale, file) | 
| - if path in files: | 
| - data = localeTools.parseString(files[path].decode('utf-8'), path) | 
| - for key, value in reference[file].iteritems(): | 
| - if not key in data: | 
| - files[path] += localeTools.generateStringEntry(key, value, path).encode('utf-8') | 
| - else: | 
| - files[path] = reference[file]['_origData'].encode('utf-8') | 
| - | 
| - | 
| -def processJSONFiles(params, files): | 
| - prefix = 'lib/' | 
| - for name, content in files.iteritems(): | 
| - if name.startswith(prefix) and name.endswith('.json'): | 
| - params['jsonRequires'][name[len(prefix):]] = json.loads(content) | 
| - for name in params['jsonRequires'].iterkeys(): | 
| - del files[prefix + name] | 
| - | 
| - | 
| -def addMissingFiles(params, files): | 
| - templateData = { | 
| - 'hasChrome': False, | 
| - 'hasChromeRequires': False, | 
| - 'hasShutdownHandlers': False, | 
| - 'chromeWindows': [], | 
| - 'requires': set(), | 
| - 'jsonRequires': params['jsonRequires'], | 
| - 'metadata': params['metadata'], | 
| - 'hasWebExtension': params['hasWebExtension'], | 
| - 'multicompartment': params['multicompartment'], | 
| - 'applications': dict((v, k) for k, v in KNOWN_APPS.iteritems()), | 
| - } | 
| - | 
| - def checkScript(name): | 
| - content = files[name] | 
| - for match in re.finditer(r'(?:^|\s)require\(\s*"([\w\-]+)"\s*\)', content): | 
| - templateData['requires'].add(match.group(1)) | 
| - if name.startswith('chrome/content/'): | 
| - templateData['hasChromeRequires'] = True | 
| - if not '/' in name or name.startswith('lib/'): | 
| - if re.search(r'(?:^|\s)onShutdown\.', content): | 
| - templateData['hasShutdownHandlers'] = True | 
| - | 
| - for name, content in files.iteritems(): | 
| - if name == 'chrome.manifest': | 
| - templateData['hasChrome'] = True | 
| - elif name.endswith('.js'): | 
| - checkScript(name) | 
| - elif name.endswith('.xul'): | 
| - match = re.search(r'<(?:window|dialog)\s[^>]*\bwindowtype="([^">]+)"', content) | 
| - if match: | 
| - templateData['chromeWindows'].append(match.group(1)) | 
| - | 
| - while True: | 
| - missing = [] | 
| - for module in templateData['requires']: | 
| - moduleFile = 'lib/' + module + '.js' | 
| - if not moduleFile in files: | 
| - import buildtools | 
| - path = os.path.join(buildtools.__path__[0], moduleFile) | 
| - if os.path.exists(path): | 
| - missing.append((path, moduleFile)) | 
| - if not len(missing): | 
| - break | 
| - for path, moduleFile in missing: | 
| - files.read(path, moduleFile) | 
| - checkScript(moduleFile) | 
| - | 
| - template = getTemplate('bootstrap.js.tmpl') | 
| - files['bootstrap.js'] = template.render(templateData).encode('utf-8') | 
| - | 
| - | 
| -def createBuild(baseDir, type='gecko', outFile=None, locales=None, buildNum=None, releaseBuild=False, multicompartment=False): | 
| - if locales == None: | 
| - locales = getLocales(baseDir) | 
| - elif locales == 'all': | 
| - locales = getLocales(baseDir, True) | 
| - | 
| - metadata = readMetadata(baseDir, type) | 
| - version = getBuildVersion(baseDir, metadata, releaseBuild, buildNum) | 
| - | 
| - if outFile == None: | 
| - outFile = getDefaultFileName(metadata, version, 'xpi') | 
| - | 
| - contributors = getContributors(metadata) | 
| - | 
| - params = { | 
| - 'baseDir': baseDir, | 
| - 'locales': locales, | 
| - 'releaseBuild': releaseBuild, | 
| - 'version': version.encode('utf-8'), | 
| - 'metadata': metadata, | 
| - 'contributors': contributors, | 
| - 'multicompartment': multicompartment, | 
| - 'hasWebExtension': os.path.isdir(os.path.join(baseDir, 'webextension')), | 
| - 'jsonRequires': {}, | 
| - } | 
| - | 
| - mapped = metadata.items('mapping') if metadata.has_section('mapping') else [] | 
| - skip = [opt for opt, _ in mapped] + ['chrome'] | 
| - files = Files(getPackageFiles(params), getIgnoredFiles(params), | 
| - process=lambda path, data: processFile(path, data, params)) | 
| - files['install.rdf'] = createManifest(params) | 
| - files.readMappedFiles(mapped) | 
| - files.read(baseDir, skip=skip) | 
| - for name, path in getChromeSubdirs(baseDir, params['locales']).iteritems(): | 
| - if os.path.isdir(path): | 
| - files.read(path, 'chrome/%s' % name, skip=skip) | 
| - importLocales(params, files) | 
| - fixupLocales(params, files) | 
| - processJSONFiles(params, files) | 
| - if not 'bootstrap.js' in files: | 
| - addMissingFiles(params, files) | 
| - if metadata.has_section('preprocess'): | 
| - files.preprocess([f for f, _ in metadata.items('preprocess')]) | 
| - files.zip(outFile, sortKey=lambda x: '!' if x == 'META-INF/zigbert.rsa' else x) | 
| - | 
| - | 
| -def autoInstall(baseDir, type, host, port, multicompartment=False): | 
| - fileBuffer = StringIO() | 
| - createBuild(baseDir, type=type, outFile=fileBuffer, multicompartment=multicompartment) | 
| - urllib.urlopen('http://%s:%s/' % (host, port), data=fileBuffer.getvalue()) |