| OLD | NEW |
| (Empty) |
| 1 #!/usr/bin/env python | |
| 2 # | |
| 3 # Copyright (c) 2012, 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 # Dart Editor promote tools. | |
| 8 | |
| 9 import imp | |
| 10 import optparse | |
| 11 import os | |
| 12 import subprocess | |
| 13 import sys | |
| 14 import time | |
| 15 import urllib | |
| 16 | |
| 17 from os.path import join | |
| 18 | |
| 19 DART_PATH = os.path.abspath(os.path.join(__file__, '..', '..', '..')) | |
| 20 BOT_UTILS = os.path.abspath(os.path.join( | |
| 21 DART_PATH, 'tools', 'bots', 'bot_utils.py')) | |
| 22 | |
| 23 bot_utils = imp.load_source('bot_utils', BOT_UTILS) | |
| 24 | |
| 25 def BuildOptions(): | |
| 26 usage = """usage: %prog promote [options] | |
| 27 where: | |
| 28 promote - Will promote builds from raw/signed locations to release | |
| 29 locations. | |
| 30 | |
| 31 Example: Promote revision r29962 on dev channel: | |
| 32 python editor/build/promote.py promote --channel=dev --revision=29962 | |
| 33 """ | |
| 34 | |
| 35 result = optparse.OptionParser(usage=usage) | |
| 36 | |
| 37 group = optparse.OptionGroup( | |
| 38 result, 'Promote', 'options used to promote code') | |
| 39 group.add_option( | |
| 40 '--revision', help='The svn revision to promote', action='store') | |
| 41 group.add_option( | |
| 42 '--channel', type='string', help='Channel to promote.', default=None) | |
| 43 result.add_option_group(group) | |
| 44 | |
| 45 return result | |
| 46 | |
| 47 | |
| 48 def main(): | |
| 49 parser = BuildOptions() | |
| 50 (options, args) = parser.parse_args() | |
| 51 | |
| 52 def die(msg): | |
| 53 print msg | |
| 54 parser.print_help() | |
| 55 sys.exit(1) | |
| 56 | |
| 57 if not args: | |
| 58 die('At least one command must be specified') | |
| 59 | |
| 60 if args[0] == 'promote': | |
| 61 command = 'promote' | |
| 62 if options.revision is None: | |
| 63 die('You must specify a --revision to specify which revision to promote') | |
| 64 | |
| 65 # Make sure revision is a valid integer | |
| 66 try: | |
| 67 _ = int(options.revision) | |
| 68 except: | |
| 69 die('You must supply a valid integer argument to --revision to promote') | |
| 70 | |
| 71 # Make sure options.channel is a valid | |
| 72 if not options.channel: | |
| 73 die('Specify --channel=be/dev/stable') | |
| 74 if options.channel not in bot_utils.Channel.ALL_CHANNELS: | |
| 75 die('You must supply a valid channel to --channel to promote') | |
| 76 else: | |
| 77 die('Invalid command specified: {0}. See help below'.format(args[0])) | |
| 78 | |
| 79 if command == 'promote': | |
| 80 _PromoteDartArchiveBuild(options.channel, options.revision) | |
| 81 | |
| 82 | |
| 83 def UpdateDocs(): | |
| 84 try: | |
| 85 print 'Updating docs' | |
| 86 url = "http://api.dartlang.org/docs/releases/latest/?force_reload=true" | |
| 87 f = urllib.urlopen(url) | |
| 88 f.read() | |
| 89 print 'Successfully updated api docs' | |
| 90 except Exception as e: | |
| 91 print 'Could not update api docs, please manually update them' | |
| 92 print 'Failed with: %s' % e | |
| 93 | |
| 94 | |
| 95 def _PromoteDartArchiveBuild(channel, revision): | |
| 96 # These namer objects will be used to create GCS object URIs. For the | |
| 97 # structure we use, please see tools/bots/bot_utils.py:GCSNamer | |
| 98 raw_namer = bot_utils.GCSNamer(channel, bot_utils.ReleaseType.RAW) | |
| 99 signed_namer = bot_utils.GCSNamer(channel, bot_utils.ReleaseType.SIGNED) | |
| 100 release_namer = bot_utils.GCSNamer(channel, bot_utils.ReleaseType.RELEASE) | |
| 101 | |
| 102 def promote(to_revision): | |
| 103 def safety_check_on_gs_path(gs_path, revision, channel): | |
| 104 if not ((revision == 'latest' or int(revision) > 0) | |
| 105 and len(channel) > 0 | |
| 106 and ('%s' % revision) in gs_path | |
| 107 and channel in gs_path): | |
| 108 raise Exception( | |
| 109 "InternalError: Sanity check failed on GS URI: %s" % gs_path) | |
| 110 | |
| 111 # Google cloud storage has read-after-write, read-after-update, | |
| 112 # and read-after-delete consistency, but not list after delete consistency. | |
| 113 # Because gsutil uses list to figure out if it should do the unix styly | |
| 114 # copy to or copy into, this means that if the directory is reported as | |
| 115 # still being there (after it has been deleted) gsutil will copy | |
| 116 # into the directory instead of to the directory. | |
| 117 def wait_for_delete_to_be_consistent_with_list(gs_path): | |
| 118 while True: | |
| 119 (_, _, exit_code) = Gsutil(['ls', gs_path], throw_on_error=False) | |
| 120 # gsutil will exit 1 if the "directory" does not exist | |
| 121 if exit_code != 0: | |
| 122 break | |
| 123 time.sleep(1) | |
| 124 | |
| 125 def remove_gs_directory(gs_path): | |
| 126 safety_check_on_gs_path(gs_path, to_revision, channel) | |
| 127 Gsutil(['-m', 'rm', '-R', '-f', gs_path]) | |
| 128 wait_for_delete_to_be_consistent_with_list(gs_path) | |
| 129 | |
| 130 # Copy sdk directory. | |
| 131 from_loc = raw_namer.sdk_directory(revision) | |
| 132 to_loc = release_namer.sdk_directory(to_revision) | |
| 133 remove_gs_directory(to_loc) | |
| 134 Gsutil(['-m', 'cp', '-a', 'public-read', '-R', from_loc, to_loc]) | |
| 135 | |
| 136 # Copy eclipse update directory. | |
| 137 from_loc = raw_namer.editor_eclipse_update_directory(revision) | |
| 138 to_loc = release_namer.editor_eclipse_update_directory(to_revision) | |
| 139 remove_gs_directory(to_loc) | |
| 140 Gsutil(['-m', 'cp', '-a', 'public-read', '-R', from_loc, to_loc]) | |
| 141 | |
| 142 # Copy api-docs zipfile. | |
| 143 from_loc = raw_namer.apidocs_zipfilepath(revision) | |
| 144 to_loc = release_namer.apidocs_zipfilepath(to_revision) | |
| 145 Gsutil(['-m', 'cp', '-a', 'public-read', from_loc, to_loc]) | |
| 146 | |
| 147 # Copy dartium directory. | |
| 148 from_loc = raw_namer.dartium_directory(revision) | |
| 149 to_loc = release_namer.dartium_directory(to_revision) | |
| 150 remove_gs_directory(to_loc) | |
| 151 Gsutil(['-m', 'cp', '-a', 'public-read', '-R', from_loc, to_loc]) | |
| 152 | |
| 153 # Copy wheezy linux deb and src packages. | |
| 154 from_loc = raw_namer.linux_packages_directory(revision, 'debian_wheezy') | |
| 155 to_loc = release_namer.linux_packages_directory(to_revision, | |
| 156 'debian_wheezy') | |
| 157 remove_gs_directory(to_loc) | |
| 158 Gsutil(['-m', 'cp', '-a', 'public-read', '-R', from_loc, to_loc]) | |
| 159 | |
| 160 # Copy VERSION file. | |
| 161 from_loc = raw_namer.version_filepath(revision) | |
| 162 to_loc = release_namer.version_filepath(to_revision) | |
| 163 Gsutil(['cp', '-a', 'public-read', from_loc, to_loc]) | |
| 164 | |
| 165 | |
| 166 promote(revision) | |
| 167 promote('latest') | |
| 168 | |
| 169 def Gsutil(cmd, throw_on_error=True): | |
| 170 gsutilTool = join(DART_PATH, 'third_party', 'gsutil', 'gsutil') | |
| 171 return bot_utils.run([sys.executable, gsutilTool] + cmd, | |
| 172 throw_on_error=throw_on_error) | |
| 173 | |
| 174 | |
| 175 if __name__ == '__main__': | |
| 176 sys.exit(main()) | |
| OLD | NEW |