| 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() |