| OLD | NEW |
| (Empty) | |
| 1 #!/usr/bin/env python |
| 2 # |
| 3 # Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 4 # for details. All rights reserved. Use of this source code is governed by a |
| 5 # BSD-style license that can be found in the LICENSE file. |
| 6 |
| 7 import hashlib |
| 8 import imp |
| 9 import optparse |
| 10 import os |
| 11 import subprocess |
| 12 import sys |
| 13 |
| 14 DART_DIR = os.path.dirname(os.path.dirname(__file__)) |
| 15 GSUTIL = os.path.join(DART_DIR, 'third_party', 'gsutil', 'gsutil') |
| 16 BOT_UTILS = os.path.join(DART_DIR, 'tools', 'bots', 'bot_utils.py') |
| 17 BASENAME_PATTERN = 'darteditor-%(system)s-%(bits)s' |
| 18 FILENAME_PATTERN = BASENAME_PATTERN + '.zip' |
| 19 BUCKET_PATTERN = ( |
| 20 'gs://dart-editor-archive-trunk/%(revision)s/' + FILENAME_PATTERN) |
| 21 |
| 22 DRY_RUN = False |
| 23 |
| 24 bot_utils = imp.load_source('bot_utils', BOT_UTILS) |
| 25 |
| 26 class ChangedWorkingDirectory(object): |
| 27 def __init__(self, working_directory): |
| 28 self._working_directory = working_directory |
| 29 |
| 30 def __enter__(self): |
| 31 self._old_cwd = os.getcwd() |
| 32 print "Enter directory = ", self._working_directory |
| 33 if not DRY_RUN: |
| 34 os.chdir(self._working_directory) |
| 35 |
| 36 def __exit__(self, *_): |
| 37 print "Enter directory = ", self._old_cwd |
| 38 os.chdir(self._old_cwd) |
| 39 |
| 40 def GetOptionsParser(): |
| 41 parser = optparse.OptionParser("usage: %prog [options]") |
| 42 parser.add_option("--scratch-dir", |
| 43 help="Scratch directory to use.") |
| 44 parser.add_option("--revision", type="int", |
| 45 help="Revision we want to sign.") |
| 46 parser.add_option("--channel", type="string", |
| 47 default=None, |
| 48 help="Channel we want to sign.") |
| 49 parser.add_option("--dry-run", action="store_true", dest="dry_run", |
| 50 default=False, |
| 51 help="Do a dry run and do not execute any commands.") |
| 52 parser.add_option("--prepare", action="store_true", dest="prepare", |
| 53 default=False, |
| 54 help="Prepare the .exe/.zip files to sign.") |
| 55 parser.add_option("--deploy", action="store_true", dest="deploy", |
| 56 default=False, |
| 57 help="Pack the signed .exe/.zip files and deploy.") |
| 58 return parser |
| 59 |
| 60 def die(msg, withOptions=True): |
| 61 print msg |
| 62 if withOptions: |
| 63 GetOptionsParser().print_usage() |
| 64 sys.exit(1) |
| 65 |
| 66 def run(command): |
| 67 """We use run() instead of builtin python methods, because not all |
| 68 functionality can easily be done by python and we can support --dry-run""" |
| 69 |
| 70 print "Running: ", command |
| 71 if not DRY_RUN: |
| 72 process = subprocess.Popen(command, |
| 73 stdout=subprocess.PIPE, |
| 74 stderr=subprocess.PIPE) |
| 75 (stdout, stderr) = process.communicate() |
| 76 if process.returncode != 0: |
| 77 print "DEBUG: failed to run command '%s'" % command |
| 78 print "DEBUG: stdout = ", stdout |
| 79 print "DEBUG: stderr = ", stderr |
| 80 print "DEBUG: returncode = ", process.returncode |
| 81 raise OSError(process.returncode) |
| 82 |
| 83 def clean_directory(directory): |
| 84 if os.path.exists(directory): |
| 85 run(['rm', '-r', directory]) |
| 86 run(['mkdir', '-p', directory]) |
| 87 |
| 88 def rm_tree(directory): |
| 89 if os.path.exists(directory): |
| 90 run(['rm', '-r', directory]) |
| 91 |
| 92 def copy_tree(from_dir, to_dir): |
| 93 if os.path.exists(to_dir): |
| 94 run(['rm', '-r', to_dir]) |
| 95 run(['cp', '-Rp', from_dir, to_dir]) |
| 96 |
| 97 def copy_file(from_file, to_file): |
| 98 if os.path.exists(to_file): |
| 99 run(['rm', to_file]) |
| 100 run(['cp', '-p', from_file, to_file]) |
| 101 |
| 102 def copy_and_zip(from_dir, to_dir): |
| 103 rm_tree(to_dir) |
| 104 copy_tree(from_dir, to_dir) |
| 105 |
| 106 dirname = os.path.basename(to_dir) |
| 107 with ChangedWorkingDirectory(os.path.dirname(to_dir)): |
| 108 run(['zip', '-r9', dirname + '.zip', dirname]) |
| 109 |
| 110 def unzip_and_copy(extracted_zipfiledir, to_dir): |
| 111 rm_tree(extracted_zipfiledir) |
| 112 run(['unzip', extracted_zipfiledir + '.zip', '-d', |
| 113 os.path.dirname(extracted_zipfiledir)]) |
| 114 rm_tree(to_dir) |
| 115 copy_tree(extracted_zipfiledir, to_dir) |
| 116 |
| 117 def download_from_old_location(config, destination): |
| 118 bucket = BUCKET_PATTERN % config |
| 119 run([GSUTIL, 'cp', bucket, destination]) |
| 120 |
| 121 def upload_to_old_location(config, source_zip): |
| 122 if not DRY_RUN: |
| 123 bot_utils.CreateChecksumFile( |
| 124 source_zip, mangled_filename=os.path.basename(source_zip)) |
| 125 md5_zip_file = source_zip + '.md5sum' |
| 126 |
| 127 bucket = BUCKET_PATTERN % config |
| 128 run([GSUTIL, 'cp', source_zip, bucket]) |
| 129 run([GSUTIL, 'cp', md5_zip_file, bucket + '.md5sum']) |
| 130 run([GSUTIL, 'setacl', 'public-read', bucket]) |
| 131 run([GSUTIL, 'setacl', 'public-read', bucket + '.md5sum']) |
| 132 |
| 133 def download_from_new_location(channel, config, destination): |
| 134 namer = bot_utils.GCSNamer(channel, |
| 135 bot_utils.ReleaseType.RAW) |
| 136 bucket = namer.editor_zipfilepath(config['revision'], config['system'], |
| 137 config['bits']) |
| 138 run([GSUTIL, 'cp', bucket, destination]) |
| 139 |
| 140 def upload_to_new_location(channel, config, source_zip): |
| 141 namer = bot_utils.GCSNamer(channel, |
| 142 bot_utils.ReleaseType.SIGNED) |
| 143 zipfilename = namer.editor_zipfilename(config['system'], config['bits']) |
| 144 bucket = namer.editor_zipfilepath(config['revision'], config['system'], |
| 145 config['bits']) |
| 146 |
| 147 if not DRY_RUN: |
| 148 bot_utils.CreateChecksumFile(source_zip, mangled_filename=zipfilename) |
| 149 md5_zip_file = source_zip + '.md5sum' |
| 150 |
| 151 run([GSUTIL, 'cp', source_zip, bucket]) |
| 152 run([GSUTIL, 'cp', md5_zip_file, bucket + '.md5sum']) |
| 153 run([GSUTIL, 'setacl', 'public-read', bucket]) |
| 154 run([GSUTIL, 'setacl', 'public-read', bucket + '.md5sum']) |
| 155 |
| 156 def main(): |
| 157 if sys.platform != 'linux2': |
| 158 print "This script was only tested on linux. Please run it on linux!" |
| 159 sys.exit(1) |
| 160 |
| 161 parser = GetOptionsParser() |
| 162 (options, args) = parser.parse_args() |
| 163 |
| 164 if not options.scratch_dir: |
| 165 die("No scratch directory given.") |
| 166 if not options.revision: |
| 167 die("No revision given.") |
| 168 if not options.prepare and not options.deploy: |
| 169 die("No prepare/deploy parameter given.") |
| 170 if options.prepare and options.deploy: |
| 171 die("Can't have prepare and deploy parameters at the same time.") |
| 172 if len(args) > 0: |
| 173 die("Invalid additional arguments: %s." % args) |
| 174 |
| 175 if options.channel: |
| 176 assert options.channel in bot_utils.Channel.ALL_CHANNELS |
| 177 |
| 178 global DRY_RUN |
| 179 DRY_RUN = options.dry_run |
| 180 |
| 181 downloads_dir = os.path.join(options.scratch_dir, 'downloads') |
| 182 presign_dir = os.path.join(options.scratch_dir, 'presign') |
| 183 postsign_dir = os.path.join(options.scratch_dir, 'postsign') |
| 184 uploads_dir = os.path.join(options.scratch_dir, 'uploads') |
| 185 |
| 186 if options.prepare: |
| 187 # Clean all directories |
| 188 clean_directory(downloads_dir) |
| 189 clean_directory(presign_dir) |
| 190 clean_directory(postsign_dir) |
| 191 clean_directory(uploads_dir) |
| 192 elif options.deploy: |
| 193 clean_directory(uploads_dir) |
| 194 |
| 195 # These are the locations where we can find the *.app folders and *.exe files |
| 196 # and the names we use inside the scratch directory. |
| 197 locations = { |
| 198 'macos' : { |
| 199 'editor' : os.path.join('dart', 'DartEditor.app'), |
| 200 'chrome' : os.path.join('dart', 'chromium', 'Chromium.app'), |
| 201 'content_shell' : os.path.join('dart', 'chromium', |
| 202 'Content Shell.app'), |
| 203 |
| 204 'editor_scratch' : 'DartEditor%(bits)s.app', |
| 205 'chrome_scratch' : 'Chromium%(bits)s.app', |
| 206 'content_shell_scratch' : 'ContentShell%(bits)s.app', |
| 207 |
| 208 'zip' : True, |
| 209 }, |
| 210 'win32' : { |
| 211 'editor' : os.path.join('dart', 'DartEditor.exe'), |
| 212 'chrome' : os.path.join('dart', 'chromium', 'chrome.exe'), |
| 213 'content_shell' : os.path.join('dart', 'chromium', |
| 214 'content_shell.exe'), |
| 215 |
| 216 'editor_scratch' : 'DartEditor%(bits)s.exe', |
| 217 'chrome_scratch' : 'chromium%(bits)s.exe', |
| 218 'content_shell_scratch' : 'content_shell%(bits)s.exe', |
| 219 |
| 220 'zip' : False, |
| 221 }, |
| 222 } |
| 223 |
| 224 # Desitination of zip files we download |
| 225 for system in ('macos', 'win32'): |
| 226 for bits in ('32', '64'): |
| 227 config = { |
| 228 'revision' : options.revision, |
| 229 'system' : system, |
| 230 'bits' : bits, |
| 231 } |
| 232 |
| 233 destination = os.path.join(downloads_dir, FILENAME_PATTERN % config) |
| 234 destination_dir = os.path.join(downloads_dir, BASENAME_PATTERN % config) |
| 235 |
| 236 deploy = os.path.join(uploads_dir, FILENAME_PATTERN % config) |
| 237 deploy_dir = os.path.join(uploads_dir, BASENAME_PATTERN % config) |
| 238 |
| 239 if options.prepare: |
| 240 # Download *.zip files from GCS buckets |
| 241 if options.channel: |
| 242 download_from_new_location(options.channel, config, destination) |
| 243 else: |
| 244 download_from_old_location(config, destination) |
| 245 |
| 246 run(['unzip', destination, '-d', destination_dir]) |
| 247 |
| 248 for name in ['editor', 'chrome', 'content_shell']: |
| 249 from_path = os.path.join(destination_dir, locations[system][name]) |
| 250 to_path = os.path.join( |
| 251 presign_dir, locations[system]['%s_scratch' % name] % config) |
| 252 |
| 253 if locations[system]['zip']: |
| 254 # We copy a .app directory directory and zip it |
| 255 copy_and_zip(from_path, to_path) |
| 256 else: |
| 257 # We copy an .exe file |
| 258 copy_file(from_path, to_path) |
| 259 elif options.deploy: |
| 260 copy_tree(destination_dir, deploy_dir) |
| 261 |
| 262 for name in ['editor', 'chrome', 'content_shell']: |
| 263 from_path = os.path.join( |
| 264 postsign_dir, locations[system]['%s_scratch' % name] % config) |
| 265 to_path = os.path.join(deploy_dir, locations[system][name]) |
| 266 |
| 267 if locations[system]['zip']: |
| 268 # We unzip a zip file and copy the resulting signed .app directory |
| 269 unzip_and_copy(from_path, to_path) |
| 270 else: |
| 271 # We copy the signed .exe file |
| 272 copy_file(from_path, to_path) |
| 273 |
| 274 deploy_zip_file = os.path.abspath(deploy) |
| 275 with ChangedWorkingDirectory(deploy_dir): |
| 276 run(['zip', '-r9', deploy_zip_file, 'dart']) |
| 277 |
| 278 # Upload *.zip/*.zip.md5sum and set 'public-read' ACL |
| 279 if options.channel: |
| 280 upload_to_new_location(options.channel, config, deploy_zip_file) |
| 281 else: |
| 282 upload_to_old_location(config, deploy_zip_file) |
| 283 |
| 284 if __name__ == '__main__': |
| 285 main() |
| 286 |
| OLD | NEW |