#! /usr/bin/env python
import os
import sys
import shutil
import platform
import tempfile
import zipfile
from optparse import OptionParser
import subprocess
try:
from hashlib import sha1 as sha
except ImportError:
from sha import sha
usage = """
This command creates a Firefox XPI installer for the Panda3D Firefox
plugin. Also see make_installer.py.
%prog [opts]"""
parser = OptionParser(usage = usage)
parser.add_option('-v', '--version', dest = 'version',
help = 'The product version',
default = None)
parser.add_option('-i', '--plugin_root', dest = 'plugin_root',
help = 'The root of a directory hierarchy in which the Firefox plugins for various platforms can be found, to build a Firefox xpi file. This is normally the same as the staging directory populated by the -i parameter to ppackage. This directory should contain a directory called "plugin", which contains in turn a number of directories named for the platform, by the Panda plugin convention, e.g. linux_i386, osx_ppc, and so on. Each platform directory should contain a Firefox plugin, e.g. nppanda3d.so.')
parser.add_option('', '--host_url', dest = 'host_url',
help = "The URL at which plugin_root will be hosted. This is used to construct the update URL for the xpi file. This is required if you specify --plugin_root.")
(options, args) = parser.parse_args()
this_dir = os.path.split(sys.argv[0])[0]
assert options.version, "A version number must be supplied!"
assert options.plugin_root, "The plugin_root must be supplied!"
assert options.host_url, "The host_url must be supplied!"
# A mapping of Panda's platform strings to Firefox's equivalent
# strings.
# I'm leaving out the Linux platforms for now. I think there is too
# much variance between distro's for this to be reliable; we'll make
# each Linux user install their distro-specific plugin instead of
# going through this mechanism.
FirefoxPlatformMap = {
'win32' : 'WINNT_x86-msvc',
'win_i386' : 'WINNT_x86-msvc',
'win_amd64' : 'WINNT_x86_64-msvc',
# 'linux_i386' : 'Linux_x86-gcc3',
# 'linux_amd64' : 'Linux_x86_64-gcc3',
# 'linux_ppc' : 'Linux_ppc-gcc3',
'osx_i386' : 'Darwin_x86-gcc3',
'osx_amd64' : 'Darwin_x86_64-gcc3',
'osx_ppc' : 'Darwin_ppc-gcc3',
'freebsd_i386' : 'FreeBSD_x86-gcc3',
'freebsd_amd64' : 'FreeBSD_x86_64-gcc3',
}
##############################################################################
#
# This install.rdf file is used when building a Firefox XPI file.
#
##############################################################################
install_rdf = """
%(package_id)s
true
Panda3D Game Engine Plug-In
Runs 3-D games and interactive applets
%(version)s
{ec8030f7-c20a-464f-9b0e-13a3a9e97384}
3.0
*
http://www.panda3d.org/
%(host_url)s/plugin/firefox/update.rdf
"""
##############################################################################
#
# This update.rdf file is used when building a Firefox XPI file.
#
##############################################################################
update_rdf = """
%(version)s
{ec8030f7-c20a-464f-9b0e-13a3a9e97384}
3.0
*
%(host_url)s/plugin/firefox/nppanda3d.xpi
sha1:%(xpi_hash)s
"""
def makeXpiFile():
""" Creates a Firefox XPI file, based on the various platform
version files. """
if not options.host_url:
print "Cannot generate xpi file without --host-url."
sys.exit(1)
print "Generating xpi file"
root = options.plugin_root
if os.path.isdir(os.path.join(root, 'plugin')):
root = os.path.join(root, 'plugin')
xpi = zipfile.ZipFile('nppanda3d.xpi', 'w')
package_id = 'runtime@panda3d.org' #TODO: maybe more customizable?
tempFile = tempfile.mktemp('.txt', 'p3d_')
rdf = open(tempFile, 'w')
rdf.write(install_rdf % {
'package_id' : package_id,
'version' : options.version,
'host_url' : options.host_url,
})
rdf.close()
xpi.write(tempFile, 'install.rdf')
os.unlink(tempFile)
subdirs = os.listdir(root)
for subdir in subdirs:
platform = FirefoxPlatformMap.get(subdir, None)
path = os.path.join(root, subdir)
if platform and os.path.isdir(path):
if subdir in ['win32', 'osx_i386']:
pluginsXpiDir = 'plugins'
else:
# Create the XPI directory platform//plugins
pluginsXpiDir = 'platform/%s/plugins' % (platform)
# Copy the Firefox plugin into this directory.
if subdir.startswith('win32'):
pluginFilename = 'nppanda3d.dll'
elif subdir.startswith('osx'):
pluginFilename = 'nppanda3d.plugin'
else:
pluginFilename = 'nppanda3d.so'
addZipTree(xpi, os.path.join(path, pluginFilename),
pluginsXpiDir + '/' + pluginFilename)
xpi.close()
# Now that we've generated the xpi file, get its hash.
data = open('nppanda3d.xpi', 'rb').read()
xpi_hash = sha(data).hexdigest()
# And now we can generate the update.rdf file.
update = open('update.rdf', 'w')
update.write(update_rdf % {
'package_id' : package_id,
'version' : options.version,
'host_url' : options.host_url,
'xpi_hash' : xpi_hash,
})
update.close()
def addZipTree(zip, sourceFile, zipName):
""" Adds the sourceFile to the zip archive at the indicated name.
If it is a directory, recursively adds all nested files as
well. """
if os.path.isdir(sourceFile):
subdirs = os.listdir(sourceFile)
for subdir in subdirs:
addZipTree(zip, os.path.join(sourceFile, subdir),
zipName + '/' + subdir)
else:
# Not a directory, just add the file.
zip.write(sourceFile, zipName)
makeXpiFile()