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

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
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 else:
96 copyFileWithDefs(src_file, full_dst_file, defs)
alexeypa (please no reviews) 2012/04/24 16:06:19 This means that copyFileWithDefs could be used for
garykac 2012/04/24 19:48:21 Done.
97
98
99 def copyFileWithDefs(src_file, dst_file, defs):
100 """Copies from src_file to dst_file, performing variable substitution.
101
102 Any @@variables@@ in the source are replaced with
103 file with the out_dir, preserving the directory structure.
104
105 Args:
106 src_file: Full or relative path to source file to copy.
107 out_dir: Target directory where files are copied.
alexeypa (please no reviews) 2012/04/24 16:06:19 nit: This function does not have |out_dir| and |fi
garykac 2012/04/24 19:48:21 Done.
108 files_root: Path prefix which is stripped of dst_file before appending
109 it to the out_dir.
110 dst_file: Relative path (and filename) where src_file should be copied.
111 defs: Dictionary of variable definitions.
112 """
113 data = open(src_file, 'r').read()
114 for key, val in defs.iteritems():
115 try:
116 data = data.replace('@@' + key + '@@', val)
117 except TypeError:
118 print repr(key), repr(val)
119 open(dst_file, 'w').write(data)
120 shutil.copystat(src_file, dst_file)
121 #shutil.copy2(src_file, dst_file)
alexeypa (please no reviews) 2012/04/24 16:06:19 nit: Remove the commented out code.
garykac 2012/04/24 19:48:21 Done.
74 122
75 123
76 def copyZipIntoArchive(out_dir, files_root, zip_file): 124 def copyZipIntoArchive(out_dir, files_root, zip_file):
77 """Expands the zip_file into the out_dir, preserving the directory structure. 125 """Expands the zip_file into the out_dir, preserving the directory structure.
78 126
79 Args: 127 Args:
80 out_dir: Target directory where unzipped files are copied. 128 out_dir: Target directory where unzipped files are copied.
81 files_root: Path prefix which is stripped of zip_file before appending 129 files_root: Path prefix which is stripped of zip_file before appending
82 it to the out_dir. 130 it to the out_dir.
83 zip_file: Relative path (and filename) to the zip file. 131 zip_file: Relative path (and filename) to the zip file.
84 """ 132 """
133 base_zip_name = os.path.basename(zip_file)
134
135 # We don't use the 'zipfile' module here because it doesn't restore all the
136 # file permissions correctly. We use the 'unzip' command manually.
alexeypa (please no reviews) 2012/04/24 16:06:19 This does not seem to be cross-platform. I believe
garykac 2012/04/24 19:48:21 Per our discussion, I'll followup this cl with one
137 old_dir = os.getcwd();
138 os.chdir(os.path.dirname(zip_file))
139 subprocess.call(['unzip', '-qq', '-o', base_zip_name])
140 os.chdir(old_dir)
141
85 # Unzip into correct dir in out_dir. 142 # Unzip into correct dir in out_dir.
86 zip_archive = zipfile.ZipFile(zip_file, 'r')
87 root_len = len(files_root) 143 root_len = len(files_root)
88 relative_zip_path = zip_file[root_len:] 144 relative_zip_path = zip_file[root_len:]
89 out_zip_path = os.path.join(out_dir, relative_zip_path) 145 out_zip_path = os.path.join(out_dir, relative_zip_path)
90 out_zip_dir = os.path.dirname(out_zip_path) 146 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 147
94 # Ideally, we'd simply do: 148 (src_dir, ignore1) = os.path.splitext(zip_file)
95 # zip_archive.extractall(out_zip_dir) 149 (base_dir_name, ignore2) = os.path.splitext(base_zip_name)
96 # but http://bugs.python.org/issue4710 bites us because the some 'bots (like 150 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 151
108 152
109 def buildHostArchive(temp_dir, zip_path, source_files_root, source_files, 153 def buildHostArchive(temp_dir, zip_path, source_files_root, source_files,
110 gen_files, gen_files_dst): 154 gen_files, gen_files_dst, defs):
111 """Builds a zip archive with the files needed to build the installer. 155 """Builds a zip archive with the files needed to build the installer.
112 156
113 Args: 157 Args:
114 temp_dir: Temporary dir used to build up the contents for the archive. 158 temp_dir: Temporary dir used to build up the contents for the archive.
115 zip_path: Full path to the zip file to create. 159 zip_path: Full path to the zip file to create.
116 source_files_root: Path prefix to strip off |files| when adding to archive. 160 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 161 source_files: The array of files to add to archive. The path structure is
118 preserved (except for the |files_root| prefix). 162 preserved (except for the |files_root| prefix).
119 gen_files: Full path to binaries to add to archive. 163 gen_files: Full path to binaries to add to archive.
120 gen_files_dst: Relative path of where to add binary files in archive. 164 gen_files_dst: Relative path of where to add binary files in archive.
121 This array needs to parallel |binaries_src|. 165 This array needs to parallel |binaries_src|.
166 defs: Dictionary of variable definitions.
122 """ 167 """
123 cleanDir(temp_dir) 168 cleanDir(temp_dir)
124 169
125 for file in source_files: 170 for file in source_files:
126 base_file = os.path.basename(file) 171 base_file = os.path.basename(file)
127 (base, ext) = os.path.splitext(file) 172 (base, ext) = os.path.splitext(file)
128 if ext == '.zip': 173 if ext == '.zip':
alexeypa (please no reviews) 2012/04/24 16:06:19 nit: The logic here can be: if .zip: copyZipIntoA
garykac 2012/04/24 19:48:21 I like that, but I'll do that in a follow-up cl si
129 copyZipIntoArchive(temp_dir, source_files_root, file) 174 copyZipIntoArchive(temp_dir, source_files_root, file)
130 else: 175 else:
131 copyFileIntoArchive(file, temp_dir, source_files_root, file) 176 copyFileIntoArchive(file, temp_dir, source_files_root, file, defs)
132 177
133 for bs, bd in zip(gen_files, gen_files_dst): 178 for bs, bd in zip(gen_files, gen_files_dst):
134 copyFileIntoArchive(bs, temp_dir, '', bd) 179 copyFileIntoArchive(bs, temp_dir, '', bd, {})
135 180
136 createZip(zip_path, temp_dir) 181 createZip(zip_path, temp_dir)
137 182
138 183
184 def error(msg):
185 sys.stderr.write('ERROR: %s' % msg)
186 sys.exit(1)
187
139 def usage(): 188 def usage():
140 """Display basic usage information.""" 189 """Display basic usage information."""
141 print ('Usage: %s\n' 190 print ('Usage: %s\n'
142 ' <temp-dir> <zip-path> <files-root-dir>\n' 191 ' <temp-dir> <zip-path> <files-root-dir>\n'
143 ' --source-files <list of source files...>\n' 192 ' --source-files <list of source files...>\n'
144 ' --generated-files <list of generated target files...>\n' 193 ' --generated-files <list of generated target files...>\n'
145 ' --generated-files-dst <dst for each generated file...>' 194 ' --generated-files-dst <dst for each generated file...>\n'
195 ' --defs <list of VARIABLE=value definitions...>'
146 ) % sys.argv[0] 196 ) % sys.argv[0]
147 197
148 198
149 def main(): 199 def main():
150 if len(sys.argv) < 3: 200 if len(sys.argv) < 3:
151 usage() 201 usage()
152 return 1 202 error('Too few arguments')
153 203
154 temp_dir = sys.argv[1] 204 temp_dir = sys.argv[1]
155 zip_path = sys.argv[2] 205 zip_path = sys.argv[2]
156 source_files_root = sys.argv[3] 206 source_files_root = sys.argv[3]
157 207
158 arg_mode = '' 208 arg_mode = ''
159 source_files = [] 209 source_files = []
160 generated_files = [] 210 generated_files = []
161 generated_files_dst = [] 211 generated_files_dst = []
212 definitions = []
162 for arg in sys.argv[4:]: 213 for arg in sys.argv[4:]:
163 if arg == '--source-files': 214 if arg == '--source-files':
164 arg_mode = 'files' 215 arg_mode = 'files'
165 elif arg == '--generated-files': 216 elif arg == '--generated-files':
166 arg_mode = 'gen-src' 217 arg_mode = 'gen-src'
167 elif arg == '--generated-files-dst': 218 elif arg == '--generated-files-dst':
168 arg_mode = 'gen-dst' 219 arg_mode = 'gen-dst'
220 elif arg == '--defs':
221 arg_mode = 'defs'
169 222
170 elif arg_mode == 'files': 223 elif arg_mode == 'files':
171 source_files.append(arg) 224 source_files.append(arg)
172 elif arg_mode == 'gen-src': 225 elif arg_mode == 'gen-src':
173 generated_files.append(arg) 226 generated_files.append(arg)
174 elif arg_mode == 'gen-dst': 227 elif arg_mode == 'gen-dst':
175 generated_files_dst.append(arg) 228 generated_files_dst.append(arg)
229 elif arg_mode == 'defs':
230 definitions.append(arg)
176 else: 231 else:
177 print "ERROR: Expected --source-files"
178 usage() 232 usage()
179 return 1 233 error('Expected --source-files')
180 234
181 # Make sure at least one file was specified. 235 # Make sure at least one file was specified.
182 if len(source_files) == 0 and len(generated_files) == 0: 236 if len(source_files) == 0 and len(generated_files) == 0:
183 print "ERROR: At least one input file must be specified." 237 error('At least one input file must be specified.')
184 return 1
185 238
186 # Ensure that source_files_root ends with a directory separator. 239 # Ensure that source_files_root ends with a directory separator.
187 if source_files_root[-1:] != os.sep: 240 if source_files_root[-1:] != os.sep:
188 source_files_root += os.sep 241 source_files_root += os.sep
189 242
190 # Verify that the 2 generated_files arrays have the same number of elements. 243 # Verify that the 2 generated_files arrays have the same number of elements.
191 if len(generated_files) < len(generated_files_dst): 244 if len(generated_files) != len(generated_files_dst):
192 print "ERROR: len(--generated-files) != len(--generated-files-dst)" 245 error('len(--generated-files) != len(--generated-files-dst)')
193 return 1 246
194 while len(generated_files) > len(generated_files_dst): 247 defs = buildDefDictionary(definitions)
195 generated_files_dst.append('')
196 248
197 result = buildHostArchive(temp_dir, zip_path, source_files_root, 249 result = buildHostArchive(temp_dir, zip_path, source_files_root,
198 source_files, generated_files, generated_files_dst) 250 source_files, generated_files, generated_files_dst,
251 defs)
199 252
200 return 0 253 return 0
201 254
202 if __name__ == '__main__': 255 if __name__ == '__main__':
203 sys.exit(main()) 256 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | remoting/host/installer/mac/ChromeRemoteDesktop.packproj » ('j') | remoting/remoting.gyp » ('J')

Powered by Google App Engine
This is Rietveld 408576698