#!/usr/bin/python # Copyright (c) 2011 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """Creates a directory with with the unpacked contents of the remoting webapp. The directory will contain a copy-of or a link-to to all remoting webapp resources. This includes HTML/JS and any plugin binaries. The script also massages resulting files appropriately with host plugin data. Finally, a zip archive for all of the above is produced. """ # Python 2.5 compatibility from __future__ import with_statement import os import platform import re import shutil import subprocess import sys import time import zipfile def findAndReplace(filepath, findString, replaceString): """Does a search and replace on the contents of a file.""" oldFilename = os.path.basename(filepath) + '.old' oldFilepath = os.path.join(os.path.dirname(filepath), oldFilename) os.rename(filepath, oldFilepath) with open(oldFilepath) as input: with open(filepath, 'w') as output: for s in input: output.write(s.replace(findString, replaceString)) os.remove(oldFilepath) def createZip(zip_path, directory): """Creates a zipfile at zip_path for the given directory.""" zipfile_base = os.path.splitext(os.path.basename(zip_path))[0] zip = zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) for (root, dirs, files) in os.walk(directory): for f in files: full_path = os.path.join(root, f) rel_path = os.path.relpath(full_path, directory) zip.write(full_path, os.path.join(zipfile_base, rel_path)) zip.close() def buildWebApp(buildtype, mimetype, destination, zip_path, plugin, files, locales): """Does the main work of building the webapp directory and zipfile. Args: buildtype: the type of build ("Official" or "Dev") mimetype: A string with mimetype of plugin. destination: A string with path to directory where the webapp will be written. zipfile: A string with path to the zipfile to create containing the contents of |destination|. plugin: A string with path to the binary plugin for this webapp. files: An array of strings listing the paths for resources to include in this webapp. locales: An array of strings listing locales, which are copied, along with their directory structure from the _locales directory down. """ # Ensure a fresh directory. try: shutil.rmtree(destination) except OSError: if os.path.exists(destination): raise else: pass os.mkdir(destination, 0775) # Use symlinks on linux and mac for faster compile/edit cycle. # # On Windows Vista platform.system() can return 'Microsoft' with some # versions of Python, see http://bugs.python.org/issue1082 # should_symlink = platform.system() not in ['Windows', 'Microsoft'] # # TODO(ajwong): Pending decision on http://crbug.com/27185 we may not be # able to load symlinked resources. should_symlink = False # Copy all the files. for current_file in files: destination_file = os.path.join(destination, os.path.basename(current_file)) destination_dir = os.path.dirname(destination_file) if not os.path.exists(destination_dir): os.makedirs(destination_dir, 0775) if should_symlink: # TODO(ajwong): Detect if we're vista or higher. Then use win32file # to create a symlink in that case. targetname = os.path.relpath(os.path.realpath(current_file), os.path.realpath(destination_file)) os.symlink(targetname, destination_file) else: shutil.copy2(current_file, destination_file) # Copy all the locales, preserving directory structure destination_locales = os.path.join(destination, "_locales") os.mkdir(destination_locales , 0775) chromium_locale_dir = "/_locales/" chrome_locale_dir = "/_locales.official/" for current_locale in locales: pos = current_locale.find(chromium_locale_dir) locale_len = len(chromium_locale_dir) if (pos == -1): pos = current_locale.find(chrome_locale_dir) locale_len = len(chrome_locale_dir) if (pos == -1): raise "Missing locales directory in " + current_locale subtree = current_locale[pos+locale_len:] pos = subtree.find("/") if (pos == -1): raise "Malformed locale: " + current_locale locale_id = subtree[:pos] messages = subtree[pos+1:] destination_dir = os.path.join(destination_locales, locale_id) destination_file = os.path.join(destination_dir, messages) os.mkdir(destination_dir, 0775) shutil.copy2(current_locale, destination_file) # Create fake plugin files to appease the manifest checker. # It requires that if there is a plugin listed in the manifest that # there be a file in the plugin with that name. names = [ 'remoting_host_plugin.dll', # Windows 'remoting_host_plugin.plugin', # Mac 'libremoting_host_plugin.ia32.so', # Linux 32 'libremoting_host_plugin.x64.so' # Linux 64 ] pluginName = os.path.basename(plugin) for name in names: if name != pluginName: path = os.path.join(destination, name) f = open(path, 'w') f.write("placeholder for %s" % (name)) f.close() # Copy the plugin. pluginName = os.path.basename(plugin) newPluginPath = os.path.join(destination, pluginName) if os.path.isdir(plugin): # On Mac we have a directory. shutil.copytree(plugin, newPluginPath) else: shutil.copy2(plugin, newPluginPath) # Strip the linux build. if ((platform.system() == 'Linux') and (buildtype == 'Official')): subprocess.call(["strip", newPluginPath]) # Add unique build numbers to manifest version. # For now, this is based on the system clock (seconds since 1/1/1970), since # a previous attempt (based on build/utils/lastchange.py) was failing on Mac. # TODO(lambroslambrou): Use the SVN revision number or an incrementing build # number (http://crbug.com/90110). timestamp = int(time.time()) # Version string must be 1-4 numbers separated by dots, with each number # between 0 and 0xffff. version1 = timestamp / 0x10000 version2 = timestamp % 0x10000 findAndReplace(os.path.join(destination, 'manifest.json'), 'UNIQUE_VERSION', '%d.%d' % (version1, version2)) # Now massage files with our mimetype. findAndReplace(os.path.join(destination, 'plugin_settings.js'), 'HOST_PLUGIN_MIMETYPE', mimetype) # Make the zipfile. createZip(zip_path, destination) def main(): if len(sys.argv) < 6: print ('Usage: build-webapp.py ' '<build-type> <mime-type> <dst> <zip-path> <plugin> ' '<other files...> --locales <locales...>') sys.exit(1) reading_locales = False files = [] locales = [] for arg in sys.argv[6:]: if arg == "--locales": reading_locales = True; elif reading_locales: locales.append(arg) else: files.append(arg) buildWebApp(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5], files, locales) if __name__ == '__main__': main()