[Pkg-mozext-commits] [adblock-plus] 145/464: Added new build scripts, functionality of replace create_xpi.pl, make_devbuild.pl and make_babelzilla_build.pl is already implemented
David Prévot
taffit at moszumanska.debian.org
Tue Jul 22 20:44:11 UTC 2014
This is an automated email from the git hooks/post-receive script.
taffit pushed a commit to branch master
in repository adblock-plus.
commit 40aa2969ec3f8ed9bab64f675cf06e9d658c521d
Author: Wladimir Palant <trev at adblockplus.org>
Date: Fri May 13 16:27:22 2011 +0200
Added new build scripts, functionality of replace create_xpi.pl, make_devbuild.pl and make_babelzilla_build.pl is already implemented
---
__init__.py | 0
build.py | 62 ++++++++++++
install.rdf.tmpl | 92 +++++++++++++++++
localeTools.py | 65 ++++++++++++
packager.py | 302 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 521 insertions(+)
diff --git a/__init__.py b/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/build.py b/build.py
new file mode 100644
index 0000000..5eb6a4a
--- /dev/null
+++ b/build.py
@@ -0,0 +1,62 @@
+# coding: utf-8
+
+# The contents of this file are subject to the Mozilla Public License
+# Version 1.1 (the "License"); you may not use this file except in
+# compliance with the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+
+import os, sys
+from getopt import getopt, GetoptError
+import buildtools.packager as packager
+
+def usage():
+ print '''Usage: %s [output_file]
+
+Options:
+ -h --help Print this message and exit
+ -l l1,l2,l3 --locales=l1,l2,l3 Only include the given locales (if omitted:
+ all locales not marked as incomplete)
+ -b num --build=num Use given build number (if omitted the build
+ number will be retrieved from Mercurial)
+ -k file --key=file File containing private key and certificates
+ required to sign the package
+ -r --release Create a release build
+ --babelzilla Create a build for Babelzilla
+''' % os.path.basename(sys.argv[0])
+
+def processArgs(baseDir, args):
+ try:
+ opts, args = getopt(sys.argv[1:], 'hl:b:k:r', ['help', 'locales', 'build=', 'key=', 'release', 'babelzilla'])
+ except GetoptError, e:
+ print str(e)
+ usage()
+ sys.exit(2)
+
+ locales = None
+ buildNum = None
+ releaseBuild = False
+ keyFile = None
+ limitMetadata = False
+ for option, value in opts:
+ if option in ('-h', '--help'):
+ usage()
+ sys.exit()
+ elif option in ('-l', '--locales'):
+ locales = value.split(',')
+ elif option in ('-b', '--build'):
+ buildNum = int(value)
+ elif option in ('-k', '--key'):
+ keyFile = value
+ elif option in ('-r', '--release'):
+ releaseBuild = True
+ elif option == '--babelzilla':
+ locales = 'all'
+ limitMetadata = True
+
+ outFile = None
+ if len(args) >= 1:
+ outFile = args[0]
+
+ packager.createBuild(baseDir, outFile=outFile, locales=locales, buildNum=buildNum,
+ releaseBuild=releaseBuild, keyFile=keyFile,
+ limitMetadata=limitMetadata)
diff --git a/install.rdf.tmpl b/install.rdf.tmpl
new file mode 100644
index 0000000..63a6602
--- /dev/null
+++ b/install.rdf.tmpl
@@ -0,0 +1,92 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>{{metadata.get('general', 'id')}}</em:id>
+ <em:version>{{version}}</em:version>
+ <em:name>{{localeMetadata[defaultLocale].name}}</em:name>
+ <em:description>{{localeMetadata[defaultLocale].description}}</em:description>
+ <em:creator>{{metadata.get('general', 'author')}}</em:creator>
+ <em:homepageURL>{{metadata.get('homepage', 'default')}}</em:homepageURL>
+ <em:type>2</em:type>
+
+ {%- if not releaseBuild or metadata.has_option('general', 'updateURL') %}
+ <em:updateURL>
+ {{- metadata.get('general', 'updateURL') if releaseBuild else 'https://adblockplus.org/devbuilds/%s/update.rdf' % metadata.get('general', 'basename') -}}
+ {{- '?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%¤tAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%' -}}
+ </em:updateURL>
+ {%- endif %}
+
+ {%- if metadata.has_option('general', 'icon') %}
+ <em:iconURL>{{metadata.get('general', 'icon')}}</em:iconURL>
+ {%- endif %}
+
+ {%- if metadata.has_option('general', 'about') %}
+ <em:aboutURL>{{metadata.get('general', 'about')}}</em:aboutURL>
+ {%- endif %}
+
+ {%- if metadata.has_option('general', 'options') %}
+ <em:optionsURL>{{metadata.get('general', 'options')}}</em:optionsURL>
+ {%- endif %}
+
+ {%- if metadata.has_section('contributors') %}
+ {%- for option in metadata.options('contributors')|sort %}
+ <em:contributor>{{metadata.get('contributors', option)}}</em:contributor>
+ {%- endfor %}
+ {%- endif %}
+
+ {%- for translator in localeMetadata|translators %}
+ <em:translator>{{translator}}</em:translator>
+ {%- endfor %}
+
+ {%- if not limitMetadata %}
+ {%- for localeCode in localeMetadata.keys()|sort %}
+ {%- set locale = localeMetadata[localeCode] %}
+ <em:localized>
+ <Description>
+ <em:locale>{{localeCode}}</em:locale>
+ <em:name>
+ {%- if 'name' in locale -%}
+ {{locale.name}}
+ {%- else -%}
+ {{localeMetadata[defaultLocale].name}}
+ {%- endif -%}
+ </em:name>
+ <em:description>
+ {%- if 'description' in locale -%}
+ {{locale.description}}
+ {%- else -%}
+ {{localeMetadata[defaultLocale].description}}
+ {%- endif -%}
+ </em:description>
+ <em:creator>{{metadata.get('general', 'author')}}</em:creator>
+ <em:homepageURL>
+ {%- if metadata.has_option('homepage', localeCode) -%}
+ {{- metadata.get('homepage', localeCode) -}}
+ {%- elif metadata.has_option('homepage', localeCode.split('-')[0]) -%}
+ {{- metadata.get('homepage', localeCode.split('-')[0]) -}}
+ {%- else -%}
+ {{- metadata.get('homepage', 'default') -}}
+ {%- endif -%}
+ </em:homepageURL>
+ </Description>
+ </em:localized>
+ {%- endfor %}
+ {%- endif %}
+
+ {%- for appName in metadata.options('compat')|sort %}
+ {%- if appName in KNOWN_APPS %}
+ <em:targetApplication>
+ <Description>
+ <!-- {{appName}} -->
+ <em:id>{{KNOWN_APPS[appName]}}</em:id>
+ <em:minVersion>{{metadata.get('compat', appName).split('/')[0]}}</em:minVersion>
+ <em:maxVersion>{{metadata.get('compat', appName).split('/')[1]}}</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+ {%- endif %}
+ {%- endfor %}
+ </Description>
+</RDF>
diff --git a/localeTools.py b/localeTools.py
new file mode 100644
index 0000000..ee0aaa7
--- /dev/null
+++ b/localeTools.py
@@ -0,0 +1,65 @@
+# coding: utf-8
+
+# The contents of this file are subject to the Mozilla Public License
+# Version 1.1 (the "License"); you may not use this file except in
+# compliance with the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+
+import re, sys, codecs, cgi
+from StringIO import StringIO
+from ConfigParser import SafeConfigParser
+from xml.parsers.expat import ParserCreate, XML_PARAM_ENTITY_PARSING_ALWAYS
+
+def parseDTDString(data, path):
+ result = {}
+ parser = ParserCreate()
+ parser.UseForeignDTD(True)
+
+ def ExternalEntityRefHandler(context, base, systemId, publicId):
+ subparser = parser.ExternalEntityParserCreate(context, 'utf-8')
+ subparser.Parse(data.encode('utf-8'), True)
+ return 1
+
+ def EntityDeclHandler(entityName, is_parameter_entity, value, base, systemId, publicId, notationName):
+ result[entityName] = value
+
+ parser.UseForeignDTD(True)
+ parser.SetParamEntityParsing(XML_PARAM_ENTITY_PARSING_ALWAYS)
+ parser.ExternalEntityRefHandler = ExternalEntityRefHandler
+ parser.EntityDeclHandler = EntityDeclHandler
+ parser.Parse('<!DOCTYPE root SYSTEM "foo"><root/>', True)
+ result['_origData'] = data
+ return result
+
+def parsePropertiesString(data, path):
+ result = {}
+ for line in data.splitlines():
+ if re.search(r'^\s*[#!]', line):
+ continue
+ elif '=' in line:
+ key, value = line.split('=', 1)
+ result[key] = value
+ elif re.search(r'\S', line):
+ print >>sys.stderr, 'Unrecognized data in file %s: %s' % (path, line)
+ result['_origData'] = data
+ return result
+
+def parseString(data, path):
+ if path.endswith('.dtd'):
+ return parseDTDString(data, path)
+ elif path.endswith('.properties'):
+ return parsePropertiesString(data, path)
+ else:
+ return None
+
+def readFile(path):
+ fileHandle = codecs.open(path, 'rb', encoding='utf-8')
+ data = fileHandle.read()
+ fileHandle.close()
+ return parseString(data, path)
+
+def generateStringEntry(key, value, path):
+ if path.endswith('.dtd'):
+ return '<!ENTITY %s "%s">\n' % (cgi.escape(key, True), cgi.escape(value, True))
+ else:
+ return '%s=%s\n' % (key, value)
diff --git a/packager.py b/packager.py
new file mode 100644
index 0000000..d557f80
--- /dev/null
+++ b/packager.py
@@ -0,0 +1,302 @@
+# coding: utf-8
+
+# The contents of this file are subject to the Mozilla Public License
+# Version 1.1 (the "License"); you may not use this file except in
+# compliance with the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+
+import os, re, subprocess, jinja2, buildtools, codecs, hashlib, base64
+from ConfigParser import SafeConfigParser
+from StringIO import StringIO
+from zipfile import ZipFile, ZIP_STORED, ZIP_DEFLATED
+import buildtools.localeTools as localeTools
+
+KNOWN_APPS = {
+ 'conkeror': '{a79fe89b-6662-4ff4-8e88-09950ad4dfde}',
+ 'emusic': 'dlm at emusic.com',
+ 'fennec': '{a23983c0-fd0e-11dc-95ff-0800200c9a66}',
+ 'firefox': '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}',
+ 'midbrowser': '{aa5ca914-c309-495d-91cf-3141bbb04115}',
+ 'prism': 'prism at developer.mozilla.org',
+ 'seamonkey': '{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}',
+ 'songbird': 'songbird at songbirdnest.com',
+ 'thunderbird': '{3550f703-e582-4d05-9a08-453d09bdfdc6}',
+ 'toolkit': 'toolkit at mozilla.org',
+}
+
+defaultLocale = 'en-US'
+
+def getDefaultFileName(baseDir, metadata, version):
+ return os.path.join(baseDir, '%s-%s.xpi' % (metadata.get('general', 'baseName'), version))
+
+def getMetadataPath(baseDir):
+ return os.path.join(baseDir, 'metadata')
+
+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 getXPIFiles(baseDir):
+ return [os.path.join(baseDir, file) for file in ('components', 'modules', 'defaults', 'bootstrap.js', 'chrome.manifest', 'icon.png', 'icon64.png')]
+
+def getIgnoredFiles(params):
+ result = ['tests', 'mochitest', '.incomplete', 'meta.properties']
+ if params['releaseBuild']:
+ result.append('TimeLine.jsm')
+ return result
+
+def isValidLocale(localesDir, dir, includeIncomplete=False):
+ if re.search(r'[^\w\-]', dir):
+ return False
+ if not os.path.isdir(os.path.join(localesDir, dir)):
+ 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 getBuildNum(baseDir):
+ (result, dummy) = subprocess.Popen(['hg', 'id', '-n'], stdout=subprocess.PIPE).communicate()
+ return re.sub(r'\W', '', result)
+
+def readMetadata(baseDir):
+ metadata = SafeConfigParser()
+ file = codecs.open(getMetadataPath(baseDir), 'rb', encoding='utf-8')
+ metadata.readfp(file)
+ file.close()
+ return metadata
+
+def processFile(path, data, params):
+ if not re.search(r'\.(manifest|xul|jsm?|xml|xhtml|rdf|dtd|properties|css)$', path):
+ return data
+
+ data = re.sub(r'\r', '', data)
+ data = data.replace('{{BUILD}}', params['buildNum'])
+ data = data.replace('{{VERSION}}', params['version'])
+
+ whitespaceRegExp = re.compile(r'^( )+', re.M)
+ data = re.sub(whitespaceRegExp, lambda match: '\t' * (len(match.group(0)) / 2), data)
+
+ 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)
+
+ if params['releaseBuild'] and path.endswith('.jsm'):
+ # Remove timeline calls from release builds
+ timelineRegExp1 = re.compile(r'^.*\b[tT]imeLine\.(\w+)\(.*', re.M)
+ timelineRegExp2 = re.compile(r'^.*Cu\.import\([^()]*\bTimeLine\.jsm\"\).*', re.M)
+ data = re.sub(timelineRegExp1, '', data)
+ data = re.sub(timelineRegExp2, '', 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()
+ try:
+ result[locale] = localeTools.readFile(os.path.join(getLocalesDir(baseDir), locale, 'meta.properties'))
+ except:
+ result[locale] = {}
+ return result
+
+def getTranslators(localeMetadata):
+ translators = {}
+ for locale in localeMetadata.itervalues():
+ if 'translator' in locale:
+ for translator in locale['translator'].split(','):
+ translator = translator.strip()
+ if translator:
+ translators[translator] = True
+ result = translators.keys()
+ result.sort()
+ return result
+
+def createManifest(baseDir, params):
+ global KNOWN_APPS, defaultLocale
+ env = jinja2.Environment(loader=jinja2.FileSystemLoader(buildtools.__path__[0]), autoescape=True, extensions=['jinja2.ext.autoescape'])
+ env.filters['translators'] = getTranslators
+ template = env.get_template('install.rdf.tmpl')
+ templateData = dict(params)
+ templateData['localeMetadata'] = readLocaleMetadata(baseDir, params['locales'])
+ templateData['KNOWN_APPS'] = KNOWN_APPS
+ templateData['defaultLocale'] = defaultLocale
+ return template.render(templateData).encode('utf-8')
+
+def readFile(files, params, path, name):
+ ignoredFiles = getIgnoredFiles(params)
+ if os.path.isdir(path):
+ for file in os.listdir(path):
+ if file in ignoredFiles:
+ continue
+ readFile(files, params, os.path.join(path, file), '%s/%s' % (name, file))
+ else:
+ file = open(path, 'rb')
+ data = processFile(path, file.read(), params)
+ file.close()
+ files[name] = data
+
+def fixupLocales(baseDir, files, params):
+ global defaultLocale
+
+ # Read in default locale data, it might not be included in files
+ defaultLocaleDir = os.path.join(getLocalesDir(baseDir), defaultLocale)
+ reference = {}
+ ignoredFiles = getIgnoredFiles(params)
+ for file in os.listdir(defaultLocaleDir):
+ path = os.path.join(defaultLocaleDir, file)
+ if file in ignoredFiles or not os.path.isfile(path):
+ continue
+ data = localeTools.readFile(path)
+ if data:
+ reference[file] = data
+
+ for locale in params['locales']:
+ for file in reference.iterkeys():
+ path = '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 createChromeJar(baseDir, params):
+ files = {}
+ for name, path in getChromeSubdirs(baseDir, params['locales']).iteritems():
+ if os.path.isdir(path):
+ readFile(files, params, path, name)
+ if not params['limitMetadata']:
+ fixupLocales(baseDir, files, params)
+
+ data = StringIO()
+ jar = ZipFile(data, 'w', ZIP_STORED)
+ for name, value in files.iteritems():
+ jar.writestr(name, value)
+ jar.close()
+ return data.getvalue()
+
+def readXPIFiles(baseDir, params, files):
+ for path in getXPIFiles(baseDir):
+ if os.path.exists(path):
+ readFile(files, params, path, os.path.basename(path))
+
+def signFiles(files, keyFile):
+ import M2Crypto
+ manifest = []
+ signature = []
+
+ def getDigest(data):
+ md5 = hashlib.md5()
+ md5.update(data)
+ sha1 = hashlib.sha1()
+ sha1.update(data)
+ return 'Digest-Algorithms: MD5 SHA1\nMD5-Digest: %s\nSHA1-Digest: %s\n' % (base64.b64encode(md5.digest()), base64.b64encode(sha1.digest()))
+
+ def addSection(manifestData, signaturePrefix):
+ manifest.append(manifestData)
+ signatureData = ''
+ if signaturePrefix:
+ signatureData += signaturePrefix
+ signatureData += getDigest(manifestData)
+ signature.append(signatureData)
+
+ addSection('Manifest-Version: 1.0\n', 'Signature-Version: 1.0\n')
+ fileNames = files.keys()
+ fileNames.sort()
+ for fileName in fileNames:
+ addSection('Name: %s\n%s' % (fileName, getDigest(files[fileName])), 'Name: %s\n' % fileName)
+ files['META-INF/manifest.mf'] = '\n'.join(manifest)
+ files['META-INF/zigbert.sf'] = '\n'.join(signature)
+
+ keyHandle = open(keyFile, 'rb')
+ keyData = keyHandle.read()
+ keyHandle.close()
+ stack = M2Crypto.X509.X509_Stack()
+ first = True
+ for match in re.finditer(r'-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----', keyData, re.S):
+ if first:
+ # Skip first certificate
+ first = False
+ else:
+ stack.push(M2Crypto.X509.load_cert_string(match.group(0)))
+
+ mime = M2Crypto.SMIME.SMIME()
+ mime.load_key(keyFile)
+ mime.set_x509_stack(stack)
+ signature = mime.sign(M2Crypto.BIO.MemoryBuffer(files['META-INF/zigbert.sf'].encode('utf-8')), M2Crypto.SMIME.PKCS7_DETACHED | M2Crypto.SMIME.PKCS7_BINARY)
+
+ buffer = M2Crypto.BIO.MemoryBuffer()
+ signature.write_der(buffer)
+ files['META-INF/zigbert.rsa'] = buffer.read()
+
+def writeXPI(files, outFile):
+ zip = ZipFile(outFile, 'w', ZIP_DEFLATED)
+ names = files.keys()
+ names.sort(key=lambda x: '!' if x == 'META-INF/zigbert.rsa' else x)
+ for name in names:
+ zip.writestr(name, files[name])
+ zip.close()
+
+def createBuild(baseDir, outFile=None, locales=None, buildNum=None, releaseBuild=False, keyFile=None, limitMetadata=False):
+ if buildNum == None:
+ buildNum = getBuildNum(baseDir)
+ if locales == None:
+ locales = getLocales(baseDir)
+ elif locales == 'all':
+ locales = getLocales(baseDir, True)
+
+ metadata = readMetadata(baseDir)
+ version = metadata.get('general', 'version')
+ if not releaseBuild:
+ version += '.' + buildNum
+
+ if limitMetadata:
+ for option in metadata.options('compat'):
+ if not option in ('firefox', 'thunderbird', 'seamonkey'):
+ metadata.remove_option('compat', option)
+
+ if outFile == None:
+ outFile = getDefaultFileName(baseDir, metadata, version)
+
+ params = {
+ 'locales': locales,
+ 'releaseBuild': releaseBuild,
+ 'buildNum': buildNum,
+ 'version': version.encode('utf-8'),
+ 'metadata': metadata,
+ 'limitMetadata': limitMetadata,
+ }
+ files = {}
+ files['install.rdf'] = createManifest(baseDir, params)
+ files['chrome/%s.jar' % metadata.get('general', 'baseName')] = createChromeJar(baseDir, params)
+ readXPIFiles(baseDir, params, files)
+ if keyFile:
+ signFiles(files, keyFile)
+ writeXPI(files, outFile)
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mozext/adblock-plus.git
More information about the Pkg-mozext-commits
mailing list