#!/usr/bin/python # moz-grab-langpacks - A script to grab langpacks for Mozilla products # # Copyright (C) 2011 Red Hat, Inc. # Author(s): Christopher Aillon # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. See http://www.gnu.org/copyleft/gpl.html for # the full text of the license. import argparse import pyrpkg import os import sys import subprocess import glob import shutil import datetime import tempfile from xml.parsers import expat def parse_cmdline(): parser = argparse.ArgumentParser(description = 'Mozilla Langpack Grabber', prog = 'moz-grab-langpacks') parser.add_argument('-a', '--app', default=None, nargs=2, metavar=('APP', 'VERSION'), help='Specify an app name and version. Required if the current working directory is not a fedora package directory') parser.add_argument('-b', '--build-number', type=int, default=0, help='Specify the build number to grab langpacks for, useful for guessing the XPI URL if it is not passed.') parser.add_argument('-u', '--url', default=None, help='DEPRECATED: Specify a URL to download langpacks from') parser.add_argument('--bz2', action='store_true', help='If passed, creates a tar.bz2 instead of tar.xz') return parser.parse_args() def find_appversion(): try: fedpkg = pyfedpkg.PackageModule(os.getcwd(), None) return (fedpkg.module, fedpkg.ver) except pyfedpkg.FedpkgError, e: makeverrel = ['make', 'verrel'] nvr = subprocess.check_output(makeverrel, stderr=None) nvrlist = nvr.split('-') count = len(nvrlist) version = nvrlist[count - 2] # Get rid of the release, and the version, so we're left with the name nvrlist.pop(count - 1) nvrlist.pop(count - 2) appname = '-'.join(nvrlist) return (appname, version) def guess_seamonkey_xpi_url(app, version, build_number): if build_number > 0: url = "ftp://ftp.mozilla.org/pub/mozilla.org/seamonkey/nightly/%s-candidates/build%d/langpack/" % (version, build_number) else: url = "ftp://ftp.mozilla.org/pub/mozilla.org/seamonkey/releases/%s/langpack/" % version return url def guess_xpi_url(app, version, build_number): if app == "seamonkey": return guess_seamonkey_xpi_url(app, version, build_number) if build_number > 0: url = "ftp://ftp.mozilla.org/pub/mozilla.org/%s/nightly/%s-candidates/build%d/linux-i686/xpi/" % (app, version, build_number) else: url = "ftp://ftp.mozilla.org/pub/mozilla.org/%s/releases/%s/linux-i686/xpi/" % (app, version) return url class LangpackXPIParser: LANGPACK_ERROR_UNKNOWN = -1 LANGPACK_OK = 0 LANGPACK_ERROR_XMLDECL = 1 LANGPACK_ERROR_US_ENGLISH = 2 def __init__(self, xpi): self._xpi = xpi self._error = self.LANGPACK_OK self._parser = expat.ParserCreate() self._parser.XmlDeclHandler = self._xml_handler self._parser.StartElementHandler = self._elem_handler self._haveXMLDeclaration = False def _extract_langpack(self): self._tmpdir = tempfile.mkdtemp() unzipcmd = ['unzip', '-qq', '-d', self._tmpdir, self._xpi] subprocess.call(unzipcmd) def _xml_handler(self, version, encoding, standalone): self._haveXMLDeclaration = True def _elem_handler(self, name, attrs): if name == "Description" and "em:name" in attrs: if attrs["em:name"] == "English (US) Language Pack": self._error = self.LANGPACK_ERROR_US_ENGLISH def parse(self): try: self._extract_langpack() installRDF = "%s/install.rdf" % self._tmpdir self._file = open(installRDF, 'r') self._parser.ParseFile(self._file) if not self._haveXMLDeclaration: self._error = self.LANGPACK_ERROR_XMLDECL except expat.ExpatError, e: self._error = self.LANGPACK_ERROR_UNKNOWN self._file.close() return self._error def destroy(self): shutil.rmtree(self._tmpdir) def create_langpack_tarball(app, version, url, use_xz=True): cwd = os.getcwd() tempdir = tempfile.mkdtemp() os.chdir(tempdir) langpackdir="%s-langpacks" % app os.mkdir(langpackdir) os.chdir(langpackdir) # Gotta catch em all! print 'Downloading .xpi files...' acclist = '??.xpi,???.xpi,??-??.xpi,*.langpack.xpi' rejlist = 'en-US.xpi,*en-US.langpack.xpi' wgetcmd = ['wget', '--quiet', '-r', '-nd', '-np', '--accept', acclist, '--reject', rejlist, url] subprocess.call(wgetcmd) # But we don't gotta keep em all print 'Checking validity of .xpi files...' readme = open('README', 'w') readme.write('Generated by moz-grab-langpacks\n\n') xpis = glob.glob('*.xpi') xpis.sort() for xpi in xpis: parser = LangpackXPIParser(xpi) rv = parser.parse() parser.destroy() if rv == LangpackXPIParser.LANGPACK_OK: readme.write('%s ACCEPTED\n' % xpi) elif rv == LangpackXPIParser.LANGPACK_ERROR_XMLDECL: readme.write('%s REJECTED because the first node is not an XML Declaration\n' % xpi) elif rv == LangpackXPIParser.LANGPACK_ERROR_US_ENGLISH: readme.write('%s REJECTED because it claims to be US English\n' % xpi) else: readme.write('%s REJECTED: Unknown Error\n' % xpi) if rv != LangpackXPIParser.LANGPACK_OK: os.remove(xpi) readme.close() # Tar them up print 'Creating tarball...' os.chdir(tempdir) if use_xz: suffix = 'xz' tarflags = '-cJf' else: suffix = 'bz2' tarflags = '-cjf' now = datetime.datetime.now().strftime("%Y%m%d") tarballname = '%s-langpacks-%s-%s.tar.%s' % (app, version, now, suffix) tarcmd = ['tar', tarflags, tarballname, langpackdir ] subprocess.call(tarcmd) shutil.move(tarballname, cwd) print "Created %s" % tarballname os.chdir(cwd) shutil.rmtree(tempdir) if __name__ == '__main__': args = parse_cmdline() if not args.app: try: args.app = find_appversion() except: print "Error: Re-run this script from a fedora package directory.\n" \ "Alternatively, you can pass --app on the command line." sys.exit(1) (app, version) = args.app if app not in ('firefox', 'thunderbird', 'seamonkey'): print "Error: App name must be one of 'firefox', 'thunderbird', 'seamonkey'" sys.exit(1) if not args.url: args.url = guess_xpi_url(app, version, args.build_number) use_xz = not args.bz2 create_langpack_tarball(app, version, args.url, use_xz) sys.exit(0)