| Index: remoting/host/installer/build-installer-archive.py
|
| ===================================================================
|
| --- remoting/host/installer/build-installer-archive.py (revision 133640)
|
| +++ remoting/host/installer/build-installer-archive.py (working copy)
|
| @@ -17,6 +17,7 @@
|
|
|
| import os
|
| import shutil
|
| +import subprocess
|
| import sys
|
| import zipfile
|
|
|
| @@ -37,6 +38,22 @@
|
| os.makedirs(dir, 0775)
|
|
|
|
|
| +def buildDefDictionary(definitions):
|
| + """Builds the definition dictionary from the VARIABLE=value array.
|
| +
|
| + Args:
|
| + defs: Array of variable definitions: 'VARIABLE=value'.
|
| +
|
| + Returns:
|
| + Dictionary with the definitions.
|
| + """
|
| + defs = {}
|
| + for d in definitions:
|
| + (key, val) = d.split('=')
|
| + defs[key] = val
|
| + return defs
|
| +
|
| +
|
| def createZip(zip_path, directory):
|
| """Creates a zipfile at zip_path for the given directory.
|
|
|
| @@ -54,7 +71,7 @@
|
| zip.close()
|
|
|
|
|
| -def copyFileIntoArchive(src_file, out_dir, files_root, dst_file):
|
| +def copyFileIntoArchive(src_file, out_dir, files_root, dst_file, defs):
|
| """Copies the src_file into the out_dir, preserving the directory structure.
|
|
|
| Args:
|
| @@ -63,6 +80,7 @@
|
| files_root: Path prefix which is stripped of dst_file before appending
|
| it to the out_dir.
|
| dst_file: Relative path (and filename) where src_file should be copied.
|
| + defs: Dictionary of variable definitions.
|
| """
|
| root_len = len(files_root)
|
| local_file_path = dst_file[root_len:]
|
| @@ -70,9 +88,37 @@
|
| dst_dir = os.path.dirname(full_dst_file)
|
| if not os.path.exists(dst_dir):
|
| os.makedirs(dst_dir, 0775)
|
| - shutil.copy2(src_file, full_dst_file)
|
|
|
| + (base, ext) = os.path.splitext(src_file)
|
| + if ext == '.app':
|
| + shutil.copytree(src_file, full_dst_file)
|
| + elif ext in ['.sh', '.packproj', '.plist']:
|
| + copyFileWithDefs(src_file, full_dst_file, defs)
|
| + else:
|
| + shutil.copy2(src_file, full_dst_file)
|
|
|
| +
|
| +def copyFileWithDefs(src_file, dst_file, defs):
|
| + """Copies from src_file to dst_file, performing variable substitution.
|
| +
|
| + Any @@variables@@ in the source are replaced with
|
| + file with the out_dir, preserving the directory structure.
|
| +
|
| + Args:
|
| + src_file: Full or relative path to source file to copy.
|
| + dst_file: Relative path (and filename) where src_file should be copied.
|
| + defs: Dictionary of variable definitions.
|
| + """
|
| + data = open(src_file, 'r').read()
|
| + for key, val in defs.iteritems():
|
| + try:
|
| + data = data.replace('@@' + key + '@@', val)
|
| + except TypeError:
|
| + print repr(key), repr(val)
|
| + open(dst_file, 'w').write(data)
|
| + shutil.copystat(src_file, dst_file)
|
| +
|
| +
|
| def copyZipIntoArchive(out_dir, files_root, zip_file):
|
| """Expands the zip_file into the out_dir, preserving the directory structure.
|
|
|
| @@ -82,32 +128,28 @@
|
| it to the out_dir.
|
| zip_file: Relative path (and filename) to the zip file.
|
| """
|
| + base_zip_name = os.path.basename(zip_file)
|
| +
|
| + # We don't use the 'zipfile' module here because it doesn't restore all the
|
| + # file permissions correctly. We use the 'unzip' command manually.
|
| + old_dir = os.getcwd();
|
| + os.chdir(os.path.dirname(zip_file))
|
| + subprocess.call(['unzip', '-qq', '-o', base_zip_name])
|
| + os.chdir(old_dir)
|
| +
|
| # Unzip into correct dir in out_dir.
|
| - zip_archive = zipfile.ZipFile(zip_file, 'r')
|
| root_len = len(files_root)
|
| relative_zip_path = zip_file[root_len:]
|
| out_zip_path = os.path.join(out_dir, relative_zip_path)
|
| out_zip_dir = os.path.dirname(out_zip_path)
|
| - if not os.path.exists(out_zip_dir):
|
| - os.makedirs(out_zip_dir, 0775)
|
|
|
| - # Ideally, we'd simply do:
|
| - # zip_archive.extractall(out_zip_dir)
|
| - # but http://bugs.python.org/issue4710 bites us because the some 'bots (like
|
| - # mac_rel) are still running Python 2.6.
|
| - # See http://stackoverflow.com/questions/639962/unzipping-directory-structure-with-python
|
| - # for workarounds.
|
| - # TODO(garykac): Remove this once all bots are > 2.6.
|
| - for f in zip_archive.namelist():
|
| - if f.endswith('/'):
|
| - if not os.path.exists(f):
|
| - os.makedirs(os.path.join(out_zip_dir, f))
|
| - else:
|
| - zip_archive.extract(f, out_zip_dir)
|
| + (src_dir, ignore1) = os.path.splitext(zip_file)
|
| + (base_dir_name, ignore2) = os.path.splitext(base_zip_name)
|
| + shutil.copytree(src_dir, os.path.join(out_zip_dir, base_dir_name))
|
|
|
|
|
| def buildHostArchive(temp_dir, zip_path, source_files_root, source_files,
|
| - gen_files, gen_files_dst):
|
| + gen_files, gen_files_dst, defs):
|
| """Builds a zip archive with the files needed to build the installer.
|
|
|
| Args:
|
| @@ -119,6 +161,7 @@
|
| gen_files: Full path to binaries to add to archive.
|
| gen_files_dst: Relative path of where to add binary files in archive.
|
| This array needs to parallel |binaries_src|.
|
| + defs: Dictionary of variable definitions.
|
| """
|
| cleanDir(temp_dir)
|
|
|
| @@ -128,28 +171,33 @@
|
| if ext == '.zip':
|
| copyZipIntoArchive(temp_dir, source_files_root, file)
|
| else:
|
| - copyFileIntoArchive(file, temp_dir, source_files_root, file)
|
| + copyFileIntoArchive(file, temp_dir, source_files_root, file, defs)
|
|
|
| for bs, bd in zip(gen_files, gen_files_dst):
|
| - copyFileIntoArchive(bs, temp_dir, '', bd)
|
| + copyFileIntoArchive(bs, temp_dir, '', bd, {})
|
|
|
| createZip(zip_path, temp_dir)
|
|
|
|
|
| +def error(msg):
|
| + sys.stderr.write('ERROR: %s' % msg)
|
| + sys.exit(1)
|
| +
|
| def usage():
|
| """Display basic usage information."""
|
| print ('Usage: %s\n'
|
| ' <temp-dir> <zip-path> <files-root-dir>\n'
|
| ' --source-files <list of source files...>\n'
|
| ' --generated-files <list of generated target files...>\n'
|
| - ' --generated-files-dst <dst for each generated file...>'
|
| + ' --generated-files-dst <dst for each generated file...>\n'
|
| + ' --defs <list of VARIABLE=value definitions...>'
|
| ) % sys.argv[0]
|
|
|
|
|
| def main():
|
| if len(sys.argv) < 3:
|
| usage()
|
| - return 1
|
| + error('Too few arguments')
|
|
|
| temp_dir = sys.argv[1]
|
| zip_path = sys.argv[2]
|
| @@ -159,6 +207,7 @@
|
| source_files = []
|
| generated_files = []
|
| generated_files_dst = []
|
| + definitions = []
|
| for arg in sys.argv[4:]:
|
| if arg == '--source-files':
|
| arg_mode = 'files'
|
| @@ -166,6 +215,8 @@
|
| arg_mode = 'gen-src'
|
| elif arg == '--generated-files-dst':
|
| arg_mode = 'gen-dst'
|
| + elif arg == '--defs':
|
| + arg_mode = 'defs'
|
|
|
| elif arg_mode == 'files':
|
| source_files.append(arg)
|
| @@ -173,29 +224,29 @@
|
| generated_files.append(arg)
|
| elif arg_mode == 'gen-dst':
|
| generated_files_dst.append(arg)
|
| + elif arg_mode == 'defs':
|
| + definitions.append(arg)
|
| else:
|
| - print "ERROR: Expected --source-files"
|
| usage()
|
| - return 1
|
| + error('Expected --source-files')
|
|
|
| # Make sure at least one file was specified.
|
| if len(source_files) == 0 and len(generated_files) == 0:
|
| - print "ERROR: At least one input file must be specified."
|
| - return 1
|
| + error('At least one input file must be specified.')
|
|
|
| # Ensure that source_files_root ends with a directory separator.
|
| if source_files_root[-1:] != os.sep:
|
| source_files_root += os.sep
|
|
|
| # Verify that the 2 generated_files arrays have the same number of elements.
|
| - if len(generated_files) < len(generated_files_dst):
|
| - print "ERROR: len(--generated-files) != len(--generated-files-dst)"
|
| - return 1
|
| - while len(generated_files) > len(generated_files_dst):
|
| - generated_files_dst.append('')
|
| + if len(generated_files) != len(generated_files_dst):
|
| + error('len(--generated-files) != len(--generated-files-dst)')
|
|
|
| + defs = buildDefDictionary(definitions)
|
| +
|
| result = buildHostArchive(temp_dir, zip_path, source_files_root,
|
| - source_files, generated_files, generated_files_dst)
|
| + source_files, generated_files, generated_files_dst,
|
| + defs)
|
|
|
| return 0
|
|
|
|
|