15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""Generates .msi from a .zip archive or an unpacked directory.
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)The structure of the input archive or directory should look like this:
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  +- archive.zip
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     +- archive
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        +- parameters.json
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)The name of the archive and the top level directory in the archive must match.
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)When an unpacked directory is used as the input "archive.zip/archive" should
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)be passed via the command line.
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)'parameters.json' specifies the parameters to be passed to candle/light and
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)must have the following structure:
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "defines": { "name": "value" },
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "extensions": [ "WixFirewallExtension.dll" ],
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "switches": [ '-nologo' ],
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "source": "chromoting.wxs",
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "bind_path": "files",
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "sign": [ ... ],
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "candle": { ... },
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "light": { ... }
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"source" specifies the name of the input .wxs relative to
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "archive.zip/archive".
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"bind_path" specifies the path where to look for binary files referenced by
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    .wxs relative to "archive.zip/archive".
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)This script is used for both building Chromoting Host installation during
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Chromuim build and for signing Chromoting Host installation later. There are two
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)copies of this script because of that:
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  - one in Chromium tree at src/remoting/tools/zip2msi.py.
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  - another one next to the signing scripts.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)The copies of the script can be out of sync so make sure that a newer version is
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)compatible with the older ones when updating the script.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import copy
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import json
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from optparse import OptionParser
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import re
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import subprocess
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import zipfile
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def UnpackZip(target, source):
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Unpacks |source| archive to |target| directory."""
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  target = os.path.normpath(target)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  archive = zipfile.ZipFile(source, 'r')
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for f in archive.namelist():
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    target_file = os.path.normpath(os.path.join(target, f))
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Sanity check to make sure .zip uses relative paths.
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if os.path.commonprefix([target_file, target]) != target:
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print "Failed to unpack '%s': '%s' is not under '%s'" % (
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          source, target_file, target)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 1
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Create intermediate directories.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    target_dir = os.path.dirname(target_file)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not os.path.exists(target_dir):
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      os.makedirs(target_dir)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    archive.extract(f, target)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def Merge(left, right):
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Merges two values.
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Raises:
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TypeError: |left| and |right| cannot be merged.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    - if both |left| and |right| are dictionaries, they are merged recursively.
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    - if both |left| and |right| are lists, the result is a list containing
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        elements from both lists.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    - if both |left| and |right| are simple value, |right| is returned.
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    - |TypeError| exception is raised if a dictionary or a list are merged with
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        a non-dictionary or non-list correspondingly.
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if isinstance(left, dict):
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if isinstance(right, dict):
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      retval = copy.copy(left)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for key, value in right.iteritems():
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if key in retval:
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          retval[key] = Merge(retval[key], value)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else:
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          retval[key] = value
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return retval
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise TypeError('Error: merging a dictionary and non-dictionary value')
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  elif isinstance(left, list):
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if isinstance(right, list):
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return left + right
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise TypeError('Error: merging a list and non-list value')
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if isinstance(right, dict):
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise TypeError('Error: merging a dictionary and non-dictionary value')
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif isinstance(right, list):
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise TypeError('Error: merging a dictionary and non-dictionary value')
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return right
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)quote_matcher_regex = re.compile(r'\s|"')
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)quote_replacer_regex = re.compile(r'(\\*)"')
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def QuoteArgument(arg):
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Escapes a Windows command-line argument.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  So that the Win32 CommandLineToArgv function will turn the escaped result back
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  into the original string.
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  See http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ("Parsing C++ Command-Line Arguments") to understand why we have to do
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      arg: the string to be escaped.
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      the escaped string.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _Replace(match):
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # For a literal quote, CommandLineToArgv requires an odd number of
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # backslashes preceding it, and it produces half as many literal backslashes
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # (rounded down). So we need to produce 2n+1 backslashes.
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 2 * match.group(1) + '\\"'
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if re.search(quote_matcher_regex, arg):
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Escape all quotes so that they are interpreted literally.
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    arg = quote_replacer_regex.sub(_Replace, arg)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Now add unescaped quotes so that any whitespace is interpreted literally.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '"' + arg + '"'
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return arg
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def GenerateCommandLine(tool, source, dest, parameters):
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Generates the command line for |tool|."""
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Merge/apply tool-specific parameters
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params = copy.copy(parameters)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if tool in parameters:
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    params = Merge(params, params[tool])
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wix_path = os.path.normpath(params.get('wix_path', ''))
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switches = [os.path.join(wix_path, tool), '-nologo']
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Append the list of defines and extensions to the command line switches.
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for name, value in params.get('defines', {}).iteritems():
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switches.append('-d%s=%s' % (name, value))
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for ext in params.get('extensions', []):
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switches += ('-ext', os.path.join(wix_path, ext))
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Append raw switches
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switches += params.get('switches', [])
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Append the input and output files
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switches += ('-out', dest, source)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Generate the actual command line
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  #return ' '.join(map(QuoteArgument, switches))
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return switches
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def Run(args):
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Runs a command interpreting the passed |args| as a command line."""
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  command = ' '.join(map(QuoteArgument, args))
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  popen = subprocess.Popen(
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out, _ = popen.communicate()
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if popen.returncode:
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print command
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for line in out.splitlines():
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print line
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print '%s returned %d' % (args[0], popen.returncode)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return popen.returncode
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def GenerateMsi(target, source, parameters):
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Generates .msi from the installation files prepared by Chromium build."""
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parameters['basename'] = os.path.splitext(os.path.basename(source))[0]
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # The script can handle both forms of input a directory with unpacked files or
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # a ZIP archive with the same files. In the latter case the archive should be
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # unpacked to the intermediate directory.
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  source_dir = None
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if os.path.isdir(source):
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Just use unpacked files from the supplied directory.
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    source_dir = source
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Unpack .zip
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rc = UnpackZip(parameters['intermediate_dir'], source)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if rc != 0:
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return rc
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    source_dir = '%(intermediate_dir)s\\%(basename)s' % parameters
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Read parameters from 'parameters.json'.
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  f = open(os.path.join(source_dir, 'parameters.json'))
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parameters = Merge(json.load(f), parameters)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  f.close()
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if 'source' not in parameters:
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print 'The source .wxs is not specified'
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if 'bind_path' not in parameters:
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print 'The binding path is not specified'
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wxs = os.path.join(source_dir, parameters['source'])
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  #  Add the binding path to the light-specific parameters.
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bind_path = os.path.join(source_dir, parameters['bind_path'])
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parameters = Merge(parameters, {'light': {'switches': ['-b', bind_path]}})
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
230116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  target_arch = parameters['target_arch']
231116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if target_arch == 'ia32':
232116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    arch_param = 'x86'
233116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  elif target_arch == 'x64':
234116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    arch_param = 'x64'
235116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  else:
236116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    print 'Invalid target_arch parameter value'
237116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return 1
238116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
239116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  # Add the architecture to candle-specific parameters.
240116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  parameters = Merge(
241116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      parameters, {'candle': {'switches': ['-arch', arch_param]}})
242116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Run candle and light to generate the installation.
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wixobj = '%(intermediate_dir)s\\%(basename)s.wixobj' % parameters
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args = GenerateCommandLine('candle', wxs, wixobj, parameters)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rc = Run(args)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if rc:
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return rc
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args = GenerateCommandLine('light', wixobj, target, parameters)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rc = Run(args)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if rc:
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return rc
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def main():
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  usage = 'Usage: zip2msi [options] <input.zip> <output.msi>'
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser = OptionParser(usage=usage)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser.add_option('--intermediate_dir', dest='intermediate_dir', default='.')
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser.add_option('--wix_path', dest='wix_path', default='.')
263116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  parser.add_option('--target_arch', dest='target_arch', default='x86')
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  options, args = parser.parse_args()
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if len(args) != 2:
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.error('two positional arguments expected')
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GenerateMsi(args[1], args[0], dict(options.__dict__))
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__':
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sys.exit(main())
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
273