Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(577)

Side by Side Diff: remoting/host/installer/build-installer-archive.py

Issue 10197005: [Chromoting] Sign, brand and version the me2me_host (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | remoting/host/installer/mac/ChromeRemoteDesktop.packproj » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Creates a zip archive for the Chrome Remote Desktop Host installer. 6 """Creates a zip archive for the Chrome Remote Desktop Host installer.
7 7
8 This script builds a zip file that contains all the files needed to build an 8 This script builds a zip file that contains all the files needed to build an
9 installer for Chrome Remote Desktop Host. 9 installer for Chrome Remote Desktop Host.
10 10
11 This zip archive is then used by the signing bots to: 11 This zip archive is then used by the signing bots to:
12 (1) Sign the binaries 12 (1) Sign the binaries
13 (2) Build the final installer 13 (2) Build the final installer
14 14
15 TODO(garykac) We should consider merging this with build-webapp.py. 15 TODO(garykac) We should consider merging this with build-webapp.py.
16 """ 16 """
17 17
18 import os 18 import os
19 import shutil 19 import shutil
20 import subprocess
20 import sys 21 import sys
21 import zipfile 22 import zipfile
22 23
23 24
24 def cleanDir(dir): 25 def cleanDir(dir):
25 """Deletes and recreates the dir to make sure it is clean. 26 """Deletes and recreates the dir to make sure it is clean.
26 27
27 Args: 28 Args:
28 dir: The directory to clean. 29 dir: The directory to clean.
29 """ 30 """
30 try: 31 try:
31 shutil.rmtree(dir) 32 shutil.rmtree(dir)
32 except OSError: 33 except OSError:
33 if os.path.exists(dir): 34 if os.path.exists(dir):
34 raise 35 raise
35 else: 36 else:
36 pass 37 pass
37 os.makedirs(dir, 0775) 38 os.makedirs(dir, 0775)
38 39
39 40
41 def buildDefDictionary(definitions):
42 """Builds the definition dictionary from the VARIABLE=value array.
43
44 Args:
45 defs: Array of variable definitions: 'VARIABLE=value'.
46
47 Returns:
48 Dictionary with the definitions.
49 """
50 defs = {}
51 for d in definitions:
52 (key, val) = d.split('=')
53 defs[key] = val
54 return defs
55
56
40 def createZip(zip_path, directory): 57 def createZip(zip_path, directory):
41 """Creates a zipfile at zip_path for the given directory. 58 """Creates a zipfile at zip_path for the given directory.
42 59
43 Args: 60 Args:
44 zip_path: Path to zip file to create. 61 zip_path: Path to zip file to create.
45 directory: Directory with contents to archive. 62 directory: Directory with contents to archive.
46 """ 63 """
47 zipfile_base = os.path.splitext(os.path.basename(zip_path))[0] 64 zipfile_base = os.path.splitext(os.path.basename(zip_path))[0]
48 zip = zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) 65 zip = zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED)
49 for (root, dirs, files) in os.walk(directory): 66 for (root, dirs, files) in os.walk(directory):
50 for f in files: 67 for f in files:
51 full_path = os.path.join(root, f) 68 full_path = os.path.join(root, f)
52 rel_path = os.path.relpath(full_path, directory) 69 rel_path = os.path.relpath(full_path, directory)
53 zip.write(full_path, os.path.join(zipfile_base, rel_path)) 70 zip.write(full_path, os.path.join(zipfile_base, rel_path))
54 zip.close() 71 zip.close()
55 72
56 73
57 def copyFileIntoArchive(src_file, out_dir, files_root, dst_file): 74 def copyFileIntoArchive(src_file, out_dir, files_root, dst_file, defs):
58 """Copies the src_file into the out_dir, preserving the directory structure. 75 """Copies the src_file into the out_dir, preserving the directory structure.
59 76
60 Args: 77 Args:
61 src_file: Full or relative path to source file to copy. 78 src_file: Full or relative path to source file to copy.
62 out_dir: Target directory where files are copied. 79 out_dir: Target directory where files are copied.
63 files_root: Path prefix which is stripped of dst_file before appending 80 files_root: Path prefix which is stripped of dst_file before appending
64 it to the out_dir. 81 it to the out_dir.
65 dst_file: Relative path (and filename) where src_file should be copied. 82 dst_file: Relative path (and filename) where src_file should be copied.
83 defs: Dictionary of variable definitions.
66 """ 84 """
67 root_len = len(files_root) 85 root_len = len(files_root)
68 local_file_path = dst_file[root_len:] 86 local_file_path = dst_file[root_len:]
69 full_dst_file = os.path.join(out_dir, local_file_path) 87 full_dst_file = os.path.join(out_dir, local_file_path)
70 dst_dir = os.path.dirname(full_dst_file) 88 dst_dir = os.path.dirname(full_dst_file)
71 if not os.path.exists(dst_dir): 89 if not os.path.exists(dst_dir):
72 os.makedirs(dst_dir, 0775) 90 os.makedirs(dst_dir, 0775)
73 shutil.copy2(src_file, full_dst_file) 91
92 (base, ext) = os.path.splitext(src_file)
93 if ext == '.app':
94 shutil.copytree(src_file, full_dst_file)
95 elif ext in ['.sh', '.packproj', '.plist']:
96 copyFileWithDefs(src_file, full_dst_file, defs)
97 else:
98 shutil.copy2(src_file, full_dst_file)
99
100
101 def copyFileWithDefs(src_file, dst_file, defs):
102 """Copies from src_file to dst_file, performing variable substitution.
103
104 Any @@variables@@ in the source are replaced with
105 file with the out_dir, preserving the directory structure.
106
107 Args:
108 src_file: Full or relative path to source file to copy.
109 dst_file: Relative path (and filename) where src_file should be copied.
110 defs: Dictionary of variable definitions.
111 """
112 data = open(src_file, 'r').read()
113 for key, val in defs.iteritems():
114 try:
115 data = data.replace('@@' + key + '@@', val)
116 except TypeError:
117 print repr(key), repr(val)
118 open(dst_file, 'w').write(data)
119 shutil.copystat(src_file, dst_file)
74 120
75 121
76 def copyZipIntoArchive(out_dir, files_root, zip_file): 122 def copyZipIntoArchive(out_dir, files_root, zip_file):
77 """Expands the zip_file into the out_dir, preserving the directory structure. 123 """Expands the zip_file into the out_dir, preserving the directory structure.
78 124
79 Args: 125 Args:
80 out_dir: Target directory where unzipped files are copied. 126 out_dir: Target directory where unzipped files are copied.
81 files_root: Path prefix which is stripped of zip_file before appending 127 files_root: Path prefix which is stripped of zip_file before appending
82 it to the out_dir. 128 it to the out_dir.
83 zip_file: Relative path (and filename) to the zip file. 129 zip_file: Relative path (and filename) to the zip file.
84 """ 130 """
131 base_zip_name = os.path.basename(zip_file)
132
133 # We don't use the 'zipfile' module here because it doesn't restore all the
134 # file permissions correctly. We use the 'unzip' command manually.
135 old_dir = os.getcwd();
136 os.chdir(os.path.dirname(zip_file))
137 subprocess.call(['unzip', '-qq', '-o', base_zip_name])
138 os.chdir(old_dir)
139
85 # Unzip into correct dir in out_dir. 140 # Unzip into correct dir in out_dir.
86 zip_archive = zipfile.ZipFile(zip_file, 'r')
87 root_len = len(files_root) 141 root_len = len(files_root)
88 relative_zip_path = zip_file[root_len:] 142 relative_zip_path = zip_file[root_len:]
89 out_zip_path = os.path.join(out_dir, relative_zip_path) 143 out_zip_path = os.path.join(out_dir, relative_zip_path)
90 out_zip_dir = os.path.dirname(out_zip_path) 144 out_zip_dir = os.path.dirname(out_zip_path)
91 if not os.path.exists(out_zip_dir):
92 os.makedirs(out_zip_dir, 0775)
93 145
94 # Ideally, we'd simply do: 146 (src_dir, ignore1) = os.path.splitext(zip_file)
95 # zip_archive.extractall(out_zip_dir) 147 (base_dir_name, ignore2) = os.path.splitext(base_zip_name)
96 # but http://bugs.python.org/issue4710 bites us because the some 'bots (like 148 shutil.copytree(src_dir, os.path.join(out_zip_dir, base_dir_name))
97 # mac_rel) are still running Python 2.6.
98 # See http://stackoverflow.com/questions/639962/unzipping-directory-structure- with-python
99 # for workarounds.
100 # TODO(garykac): Remove this once all bots are > 2.6.
101 for f in zip_archive.namelist():
102 if f.endswith('/'):
103 if not os.path.exists(f):
104 os.makedirs(os.path.join(out_zip_dir, f))
105 else:
106 zip_archive.extract(f, out_zip_dir)
107 149
108 150
109 def buildHostArchive(temp_dir, zip_path, source_files_root, source_files, 151 def buildHostArchive(temp_dir, zip_path, source_files_root, source_files,
110 gen_files, gen_files_dst): 152 gen_files, gen_files_dst, defs):
111 """Builds a zip archive with the files needed to build the installer. 153 """Builds a zip archive with the files needed to build the installer.
112 154
113 Args: 155 Args:
114 temp_dir: Temporary dir used to build up the contents for the archive. 156 temp_dir: Temporary dir used to build up the contents for the archive.
115 zip_path: Full path to the zip file to create. 157 zip_path: Full path to the zip file to create.
116 source_files_root: Path prefix to strip off |files| when adding to archive. 158 source_files_root: Path prefix to strip off |files| when adding to archive.
117 source_files: The array of files to add to archive. The path structure is 159 source_files: The array of files to add to archive. The path structure is
118 preserved (except for the |files_root| prefix). 160 preserved (except for the |files_root| prefix).
119 gen_files: Full path to binaries to add to archive. 161 gen_files: Full path to binaries to add to archive.
120 gen_files_dst: Relative path of where to add binary files in archive. 162 gen_files_dst: Relative path of where to add binary files in archive.
121 This array needs to parallel |binaries_src|. 163 This array needs to parallel |binaries_src|.
164 defs: Dictionary of variable definitions.
122 """ 165 """
123 cleanDir(temp_dir) 166 cleanDir(temp_dir)
124 167
125 for file in source_files: 168 for file in source_files:
126 base_file = os.path.basename(file) 169 base_file = os.path.basename(file)
127 (base, ext) = os.path.splitext(file) 170 (base, ext) = os.path.splitext(file)
128 if ext == '.zip': 171 if ext == '.zip':
129 copyZipIntoArchive(temp_dir, source_files_root, file) 172 copyZipIntoArchive(temp_dir, source_files_root, file)
130 else: 173 else:
131 copyFileIntoArchive(file, temp_dir, source_files_root, file) 174 copyFileIntoArchive(file, temp_dir, source_files_root, file, defs)
132 175
133 for bs, bd in zip(gen_files, gen_files_dst): 176 for bs, bd in zip(gen_files, gen_files_dst):
134 copyFileIntoArchive(bs, temp_dir, '', bd) 177 copyFileIntoArchive(bs, temp_dir, '', bd, {})
135 178
136 createZip(zip_path, temp_dir) 179 createZip(zip_path, temp_dir)
137 180
138 181
182 def error(msg):
183 sys.stderr.write('ERROR: %s' % msg)
184 sys.exit(1)
185
139 def usage(): 186 def usage():
140 """Display basic usage information.""" 187 """Display basic usage information."""
141 print ('Usage: %s\n' 188 print ('Usage: %s\n'
142 ' <temp-dir> <zip-path> <files-root-dir>\n' 189 ' <temp-dir> <zip-path> <files-root-dir>\n'
143 ' --source-files <list of source files...>\n' 190 ' --source-files <list of source files...>\n'
144 ' --generated-files <list of generated target files...>\n' 191 ' --generated-files <list of generated target files...>\n'
145 ' --generated-files-dst <dst for each generated file...>' 192 ' --generated-files-dst <dst for each generated file...>\n'
193 ' --defs <list of VARIABLE=value definitions...>'
146 ) % sys.argv[0] 194 ) % sys.argv[0]
147 195
148 196
149 def main(): 197 def main():
150 if len(sys.argv) < 3: 198 if len(sys.argv) < 3:
151 usage() 199 usage()
152 return 1 200 error('Too few arguments')
153 201
154 temp_dir = sys.argv[1] 202 temp_dir = sys.argv[1]
155 zip_path = sys.argv[2] 203 zip_path = sys.argv[2]
156 source_files_root = sys.argv[3] 204 source_files_root = sys.argv[3]
157 205
158 arg_mode = '' 206 arg_mode = ''
159 source_files = [] 207 source_files = []
160 generated_files = [] 208 generated_files = []
161 generated_files_dst = [] 209 generated_files_dst = []
210 definitions = []
162 for arg in sys.argv[4:]: 211 for arg in sys.argv[4:]:
163 if arg == '--source-files': 212 if arg == '--source-files':
164 arg_mode = 'files' 213 arg_mode = 'files'
165 elif arg == '--generated-files': 214 elif arg == '--generated-files':
166 arg_mode = 'gen-src' 215 arg_mode = 'gen-src'
167 elif arg == '--generated-files-dst': 216 elif arg == '--generated-files-dst':
168 arg_mode = 'gen-dst' 217 arg_mode = 'gen-dst'
218 elif arg == '--defs':
219 arg_mode = 'defs'
169 220
170 elif arg_mode == 'files': 221 elif arg_mode == 'files':
171 source_files.append(arg) 222 source_files.append(arg)
172 elif arg_mode == 'gen-src': 223 elif arg_mode == 'gen-src':
173 generated_files.append(arg) 224 generated_files.append(arg)
174 elif arg_mode == 'gen-dst': 225 elif arg_mode == 'gen-dst':
175 generated_files_dst.append(arg) 226 generated_files_dst.append(arg)
227 elif arg_mode == 'defs':
228 definitions.append(arg)
176 else: 229 else:
177 print "ERROR: Expected --source-files"
178 usage() 230 usage()
179 return 1 231 error('Expected --source-files')
180 232
181 # Make sure at least one file was specified. 233 # Make sure at least one file was specified.
182 if len(source_files) == 0 and len(generated_files) == 0: 234 if len(source_files) == 0 and len(generated_files) == 0:
183 print "ERROR: At least one input file must be specified." 235 error('At least one input file must be specified.')
184 return 1
185 236
186 # Ensure that source_files_root ends with a directory separator. 237 # Ensure that source_files_root ends with a directory separator.
187 if source_files_root[-1:] != os.sep: 238 if source_files_root[-1:] != os.sep:
188 source_files_root += os.sep 239 source_files_root += os.sep
189 240
190 # Verify that the 2 generated_files arrays have the same number of elements. 241 # Verify that the 2 generated_files arrays have the same number of elements.
191 if len(generated_files) < len(generated_files_dst): 242 if len(generated_files) != len(generated_files_dst):
192 print "ERROR: len(--generated-files) != len(--generated-files-dst)" 243 error('len(--generated-files) != len(--generated-files-dst)')
193 return 1 244
194 while len(generated_files) > len(generated_files_dst): 245 defs = buildDefDictionary(definitions)
195 generated_files_dst.append('')
196 246
197 result = buildHostArchive(temp_dir, zip_path, source_files_root, 247 result = buildHostArchive(temp_dir, zip_path, source_files_root,
198 source_files, generated_files, generated_files_dst) 248 source_files, generated_files, generated_files_dst,
249 defs)
199 250
200 return 0 251 return 0
201 252
202 if __name__ == '__main__': 253 if __name__ == '__main__':
203 sys.exit(main()) 254 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | remoting/host/installer/mac/ChromeRemoteDesktop.packproj » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698