Index: build.py |
=================================================================== |
--- a/build.py |
+++ b/build.py |
@@ -36,22 +36,34 @@ class Command(object): |
pass |
def __call__(self, baseDir, scriptName, opts, args, type): |
return self._handler(baseDir, scriptName, opts, args, type) |
def isSupported(self, type): |
return self._supportedTypes == None or type in self._supportedTypes |
- def addOption(self, description, short=None, long=None, value=None): |
- self._options.append((description, short, long, value)) |
+ def addOption(self, description, short=None, long=None, value=None, types=None): |
+ self._options.append((description, short, long, value, types)) |
- def parseArgs(self, args): |
- shortOptions = map(lambda o: o[1]+':' if o[3] != None else o[1], filter(lambda o: o[1] != None, self._options)) |
- longOptions = map(lambda o: o[2]+'=' if o[3] != None else o[2], filter(lambda o: o[2] != None, self._options)) |
+ def parseArgs(self, type, args): |
+ shortOptions = map( |
+ lambda o: o[1]+':' if o[3] != None else o[1], |
+ filter( |
+ lambda o: o[1] != None and (o[4] == None or type in o[4]), |
+ self._options |
+ ) |
+ ) |
+ longOptions = map( |
+ lambda o: o[2]+'=' if o[3] != None else o[2], |
+ filter( |
+ lambda o: o[2] != None and (o[4] == None or type in o[4]), |
+ self._options |
+ ) |
+ ) |
return getopt(args, ''.join(shortOptions), longOptions) |
commandsList = [] |
commands = {} |
def addCommand(handler, name): |
if isinstance(name, basestring): |
aliases = () |
@@ -102,17 +114,19 @@ For details on a command run: |
'scriptName': scriptName, |
'descriptions': '\n'.join(descriptions) |
} |
else: |
global commands |
command = commands[commandName] |
description = '\n'.join(map(lambda s: '\n'.join(splitByLength(s, 80)), command.description.split('\n'))) |
options = [] |
- for descr, short, long, value in command.options: |
+ for descr, short, long, value, types in command.options: |
+ if types != None and type not in types: |
+ continue |
if short == None: |
shortText = '' |
elif value == None: |
shortText = '-%s' % short |
else: |
shortText = '-%s %s' % (short, value) |
if long == None: |
longText = '' |
@@ -141,41 +155,49 @@ Options: |
def runBuild(baseDir, scriptName, opts, args, type): |
locales = None |
buildNum = None |
multicompartment = False |
releaseBuild = False |
keyFile = None |
limitMetadata = False |
+ experimentalAPI = False |
for option, value in opts: |
if 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 ('-m', '--multi-compartment'): |
multicompartment = True |
elif option in ('-r', '--release'): |
releaseBuild = True |
+ elif option == '--experimental': |
+ experimentalAPI = True |
elif option == '--babelzilla': |
locales = 'all' |
limitMetadata = True |
outFile = args[0] if len(args) > 0 else None |
if type == 'gecko': |
- import buildtools.packager as packager |
+ import buildtools.packagerGecko as packager |
packager.createBuild(baseDir, outFile=outFile, locales=locales, buildNum=buildNum, |
releaseBuild=releaseBuild, keyFile=keyFile, |
limitMetadata=limitMetadata, multicompartment=multicompartment) |
+ elif type == 'chrome': |
+ import buildtools.packagerChrome as packager |
+ packager.createBuild(baseDir, outFile=outFile, buildNum=buildNum, |
+ releaseBuild=releaseBuild, keyFile=keyFile, |
+ experimentalAPI=experimentalAPI) |
elif type == 'kmeleon': |
- import buildtools.packagerKMeleon as packagerKMeleon |
- packagerKMeleon.createBuild(baseDir, outFile=outFile, locales=locales, |
- buildNum=buildNum, releaseBuild=releaseBuild) |
+ import buildtools.packagerKMeleon as packager |
+ packager.createBuild(baseDir, outFile=outFile, locales=locales, |
+ buildNum=buildNum, releaseBuild=releaseBuild) |
def runAutoInstall(baseDir, scriptName, opts, args, type): |
if len(args) == 0: |
print 'Port of the Extension Auto-Installer needs to be specified' |
usage(scriptName, type, 'autoinstall') |
return |
multicompartment = False |
@@ -183,74 +205,116 @@ def runAutoInstall(baseDir, scriptName, |
if option in ('-m', '--multi-compartment'): |
multicompartment = True |
if ':' in args[0]: |
host, port = args[0].rsplit(':', 1) |
else: |
host, port = ('localhost', args[0]) |
- import buildtools.packager as packager |
+ import buildtools.packagerGecko as packager |
packager.autoInstall(baseDir, host, port, multicompartment=multicompartment) |
def setupTranslations(baseDir, scriptName, opts, args, type): |
if len(args) < 1: |
print 'Project key is required to update translation master files.' |
usage(scriptName, type, 'setuptrans') |
return |
key = args[0] |
- import buildtools.packager as packager |
- locales = packager.getLocales(baseDir, True) |
- basename = packager.readMetadata(baseDir).get('general', 'baseName') |
+ if type == 'chrome': |
+ import buildtools.packagerChrome as packager |
+ locales = os.listdir(os.path.join(baseDir, '_locales')) |
+ locales = map(lambda locale: locale.replace('_', '-'), locales) |
+ basename = packager.readMetadata(baseDir).get('general', 'baseName') |
+ else: |
+ import buildtools.packagerGecko as packager |
+ locales = packager.getLocales(baseDir, True) |
+ basename = packager.readMetadata(baseDir).get('general', 'baseName') |
import buildtools.localeTools as localeTools |
- localeTools.setupTranslations(locales, basename, key) |
+ localeTools.setupTranslations(type, locales, basename, key) |
def updateTranslationMaster(baseDir, scriptName, opts, args, type): |
if len(args) < 1: |
print 'Project key is required to update translation master files.' |
usage(scriptName, type, 'translate') |
return |
key = args[0] |
- import buildtools.packager as packager |
- defaultLocaleDir = os.path.join(packager.getLocalesDir(baseDir), packager.defaultLocale) |
- basename = packager.readMetadata(baseDir).get('general', 'baseName') |
+ if type == 'chrome': |
+ import buildtools.packagerChrome as packager |
+ defaultLocaleDir = os.path.join(baseDir, '_locales', packager.defaultLocale) |
+ metadata = packager.readMetadata(baseDir) |
+ basename = metadata.get('general', 'baseName') |
+ else: |
+ import buildtools.packagerGecko as packager |
+ defaultLocaleDir = os.path.join(packager.getLocalesDir(baseDir), packager.defaultLocale) |
+ metadata = packager.readMetadata(baseDir) |
+ basename = metadata.get('general', 'baseName') |
import buildtools.localeTools as localeTools |
- localeTools.updateTranslationMaster(defaultLocaleDir, packager.defaultLocale, basename, key) |
+ localeTools.updateTranslationMaster(type, metadata, defaultLocaleDir, basename, key) |
+ |
+ |
+def uploadTranslations(baseDir, scriptName, opts, args, type): |
+ if len(args) < 1: |
+ print 'Project key is required to upload existing translations.' |
+ usage(scriptName, type, 'uploadtrans') |
+ return |
+ |
+ key = args[0] |
+ |
+ if type == 'chrome': |
+ import buildtools.packagerChrome as packager |
+ localesDir = os.path.join(baseDir, '_locales') |
+ locales = os.listdir(localesDir) |
+ locales = map(lambda locale: (locale.replace('_', '-'), os.path.join(localesDir, locale)), locales) |
+ metadata = packager.readMetadata(baseDir) |
+ basename = metadata.get('general', 'baseName') |
+ else: |
+ import buildtools.packagerGecko as packager |
+ localesDir = packager.getLocalesDir(baseDir) |
+ locales = packager.getLocales(baseDir, True) |
+ locales = map(lambda locale: (locale, os.path.join(localesDir, locale)), locales) |
+ metadata = packager.readMetadata(baseDir) |
+ basename = metadata.get('general', 'baseName') |
+ |
+ import buildtools.localeTools as localeTools |
+ for locale, localeDir in locales: |
+ if locale != packager.defaultLocale: |
+ localeTools.uploadTranslations(type, metadata, localeDir, locale, basename, key) |
def getTranslations(baseDir, scriptName, opts, args, type): |
if len(args) < 1: |
print 'Project key is required to update translation master files.' |
usage(scriptName, type, 'translate') |
return |
key = args[0] |
- import buildtools.packager as packager |
+ import buildtools.packagerGecko as packager |
localesDir = packager.getLocalesDir(baseDir) |
basename = packager.readMetadata(baseDir).get('general', 'baseName') |
import buildtools.localeTools as localeTools |
localeTools.getTranslations(localesDir, packager.defaultLocale, basename, key) |
def showDescriptions(baseDir, scriptName, opts, args, type): |
locales = None |
for option, value in opts: |
if option in ('-l', '--locales'): |
locales = value.split(',') |
- import buildtools.packager as packager |
+ import buildtools.packagerGecko as packager |
if locales == None: |
locales = packager.getLocales(baseDir) |
elif locales == 'all': |
locales = packager.getLocales(baseDir, True) |
data = packager.readLocaleMetadata(baseDir, locales) |
localeCodes = data.keys() |
localeCodes.sort() |
@@ -317,55 +381,76 @@ def runReleaseAutomation(baseDir, script |
if re.search(r'[^\w\.]', version): |
print 'Wrong version number format' |
usage(scriptName, type, 'release') |
return |
if keyFile == None: |
print 'Warning: no key file specified, creating an unsigned release build\n' |
- import buildtools.releaseAutomation as releaseAutomation |
+ import buildtools.releaseAutomationGecko as releaseAutomation |
releaseAutomation.run(baseDir, version, keyFile, downloadsRepo, buildtoolsRepo) |
else: |
- import buildtools.releaseAutomationKMeleon as releaseAutomationKMeleon |
- releaseAutomationKMeleon.run(baseDir, downloadsRepo, buildtoolsRepo) |
+ import buildtools.releaseAutomationKMeleon as releaseAutomation |
+ releaseAutomation.run(baseDir, downloadsRepo, buildtoolsRepo) |
+ |
+def syncLocales(baseDir, scriptName, opts, args, type): |
+ if len(args) == 0: |
+ print 'Please specify the directory of the source Firefox extension as a parameter' |
+ usage(scriptName, type, 'synclocales') |
+ return |
+ sourceDir = args[0] |
+ |
+ import buildtools.localeSyncChrome as localeSync |
+ localeSync.run(baseDir, sourceDir) |
+ |
+def updatePSL(baseDir, scriptName, opts, args, type): |
+ import buildtools.publicSuffixListUpdater as publicSuffixListUpdater |
+ publicSuffixListUpdater.updatePSL(baseDir) |
with addCommand(lambda baseDir, scriptName, opts, args, type: usage(scriptName, type), ('help', '-h', '--help')) as command: |
command.shortDescription = 'Show this message' |
with addCommand(runBuild, 'build') as command: |
command.shortDescription = 'Create a build' |
command.description = 'Creates an extension build with given file name. If output_file is missing a default name will be chosen.' |
command.params = '[options] [output_file]' |
- command.addOption('Only include the given locales (if omitted: all locales not marked as incomplete)', short='l', long='locales', value='l1,l2,l3') |
+ command.addOption('Only include the given locales (if omitted: all locales not marked as incomplete)', short='l', long='locales', value='l1,l2,l3', types=('gecko', 'kmeleon')) |
command.addOption('Use given build number (if omitted the build number will be retrieved from Mercurial)', short='b', long='build', value='num') |
- command.addOption('File containing private key and certificates required to sign the package', short='k', long='key', value='file') |
- command.addOption('Create a build for leak testing', short='m', long='multi-compartment') |
+ command.addOption('File containing private key and certificates required to sign the package', short='k', long='key', value='file', types=('gecko', 'chrome')) |
+ command.addOption('Create a build for leak testing', short='m', long='multi-compartment', types=('gecko')) |
command.addOption('Create a release build', short='r', long='release') |
- command.addOption('Create a build for Babelzilla', long='babelzilla') |
- command.supportedTypes = ('gecko', 'kmeleon') |
+ command.addOption('Enable use of experimental APIs', long='experimental') |
+ command.addOption('Create a build for Babelzilla', long='babelzilla', types=('gecko')) |
+ command.supportedTypes = ('gecko', 'kmeleon', 'chrome') |
with addCommand(runAutoInstall, 'autoinstall') as command: |
command.shortDescription = 'Install extension automatically' |
command.description = 'Will automatically install the extension in a browser running Extension Auto-Installer. If host parameter is omitted assumes that the browser runs on localhost.' |
command.params = '[<host>:]<port>' |
command.addOption('Create a build for leak testing', short='m', long='multi-compartment') |
command.supportedTypes = ('gecko') |
with addCommand(setupTranslations, 'setuptrans') as command: |
command.shortDescription = 'Sets up translation languages' |
command.description = 'Sets up translation languages for the project on crowdin.net.' |
command.params = '[options] project-key' |
- command.supportedTypes = ('gecko') |
+ command.supportedTypes = ('gecko', 'chrome') |
with addCommand(updateTranslationMaster, 'translate') as command: |
command.shortDescription = 'Updates translation master files' |
command.description = 'Updates the translation master files in the project on crowdin.net.' |
command.params = '[options] project-key' |
- command.supportedTypes = ('gecko') |
+ command.supportedTypes = ('gecko', 'chrome') |
+ |
+with addCommand(uploadTranslations, 'uploadtrans') as command: |
+ command.shortDescription = 'Uploads existing translations' |
+ command.description = 'Uploads already existing translations to the project on crowdin.net.' |
+ command.params = '[options] project-key' |
+ command.supportedTypes = ('gecko', 'chrome') |
with addCommand(getTranslations, 'gettranslations') as command: |
command.shortDescription = 'Downloads translation updates' |
command.description = 'Downloads updated translations from crowdin.net.' |
command.params = '[options] project-key' |
command.supportedTypes = ('gecko') |
with addCommand(showDescriptions, 'showdesc') as command: |
@@ -383,21 +468,32 @@ with addCommand(generateDocs, 'docs') as |
command.supportedTypes = ('gecko') |
with addCommand(runReleaseAutomation, 'release') as command: |
command.shortDescription = 'Run release automation' |
command.description = 'Note: If you are not the project owner then you '\ |
'probably don\'t want to run this!\n\n'\ |
'Runs release automation: creates downloads for the new version, tags '\ |
'source code repository as well as downloads and buildtools repository.' |
- command.addOption('File containing private key and certificates required to sign the release', short='k', long='key', value='file') |
+ command.addOption('File containing private key and certificates required to sign the release', short='k', long='key', value='file', types=('gecko')) |
command.addOption('Directory containing downloads repository (if omitted ../downloads is assumed)', short='d', long='downloads', value='dir') |
command.params = '[options] <version>' |
command.supportedTypes = ('gecko', 'kmeleon') |
+with addCommand(syncLocales, 'synclocales') as command: |
+ command.shortDescription = 'Sync locales with a Firefox extension' |
+ command.description = 'Updates locale files with strings from a Firefox extension corresponding to the entries in [locale_sync] metadata section.' |
+ command.params = '<firefox_addon_directory>' |
+ command.supportedTypes = ('chrome') |
+ |
+with addCommand(updatePSL, 'updatepsl') as command: |
+ command.shortDescription = 'Updates Public Suffix List' |
+ command.description = 'Downloads Public Suffix List (see http://publicsuffix.org/) and generates lib/publicSuffixList.js from it.' |
+ command.supportedTypes = ('chrome') |
+ |
def processArgs(baseDir, args, type='gecko'): |
global commands |
scriptName = os.path.basename(args[0]) |
args = args[1:] |
if len(args) == 0: |
args = ['build'] |
print ''' |
@@ -405,17 +501,17 @@ No command given, assuming "build". For |
%s help |
''' % scriptName |
command = args[0] |
if command in commands: |
if commands[command].isSupported(type): |
try: |
- opts, args = commands[command].parseArgs(args[1:]) |
+ opts, args = commands[command].parseArgs(type, args[1:]) |
except GetoptError, e: |
print str(e) |
usage(scriptName, type, command) |
sys.exit(2) |
for option, value in opts: |
if option in ('-h', '--help'): |
usage(scriptName, type, command) |
sys.exit() |