| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # | 2 # |
| 3 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 5 # BSD-style license that can be found in the LICENSE file. |
| 6 | 6 |
| 7 # Dart Editor promote tools. | 7 # Dart Editor promote tools. |
| 8 | 8 |
| 9 import imp | 9 import imp |
| 10 import optparse | 10 import optparse |
| 11 import os | 11 import os |
| 12 import subprocess | 12 import subprocess |
| 13 import sys | 13 import sys |
| 14 import time | 14 import time |
| 15 import urllib | 15 import urllib |
| 16 import bots.bot_utils as bot_utils | 16 import bots.bot_utils as bot_utils |
| 17 | 17 |
| 18 from os.path import join | 18 from os.path import join |
| 19 | 19 |
| 20 DART_PATH = os.path.abspath(os.path.join(__file__, '..', '..')) | 20 DART_PATH = os.path.abspath(os.path.join(__file__, '..', '..')) |
| 21 DRY_RUN = False |
| 21 | 22 |
| 22 def BuildOptions(): | 23 def BuildOptions(): |
| 23 usage = """usage: %prog promote [options] | 24 usage = """usage: %prog promote [options] |
| 24 where: | 25 where: |
| 25 promote - Will promote builds from raw/signed locations to release | 26 promote - Will promote builds from raw/signed locations to release |
| 26 locations. | 27 locations. |
| 27 | 28 |
| 28 Example: Promote revision r29962 on dev channel: | 29 Example: Promote revision r29962 on dev channel: |
| 29 python editor/build/promote.py promote --channel=dev --revision=29962 | 30 python editor/build/promote.py promote --channel=dev --revision=29962 |
| 30 """ | 31 """ |
| 31 | 32 |
| 32 result = optparse.OptionParser(usage=usage) | 33 result = optparse.OptionParser(usage=usage) |
| 33 | 34 |
| 34 group = optparse.OptionGroup( | 35 group = optparse.OptionGroup( |
| 35 result, 'Promote', 'options used to promote code') | 36 result, 'Promote', 'options used to promote code') |
| 36 group.add_option( | 37 group.add_option( |
| 37 '--revision', help='The svn revision to promote', action='store') | 38 '--revision', help='The svn revision to promote', action='store') |
| 38 group.add_option( | 39 group.add_option( |
| 39 '--channel', type='string', help='Channel to promote.', default=None) | 40 '--channel', type='string', help='Channel to promote.', default=None) |
| 41 group.add_option("--dry", help='Dry run', default=False, action="store_true") |
| 40 result.add_option_group(group) | 42 result.add_option_group(group) |
| 41 | 43 |
| 42 return result | 44 return result |
| 43 | 45 |
| 44 | 46 |
| 45 def main(): | 47 def main(): |
| 46 parser = BuildOptions() | 48 parser = BuildOptions() |
| 47 (options, args) = parser.parse_args() | 49 (options, args) = parser.parse_args() |
| 48 | 50 |
| 49 def die(msg): | 51 def die(msg): |
| (...skipping 16 matching lines...) Expand all Loading... |
| 66 die('You must supply a valid integer argument to --revision to promote') | 68 die('You must supply a valid integer argument to --revision to promote') |
| 67 | 69 |
| 68 # Make sure options.channel is a valid | 70 # Make sure options.channel is a valid |
| 69 if not options.channel: | 71 if not options.channel: |
| 70 die('Specify --channel=be/dev/stable') | 72 die('Specify --channel=be/dev/stable') |
| 71 if options.channel not in bot_utils.Channel.ALL_CHANNELS: | 73 if options.channel not in bot_utils.Channel.ALL_CHANNELS: |
| 72 die('You must supply a valid channel to --channel to promote') | 74 die('You must supply a valid channel to --channel to promote') |
| 73 else: | 75 else: |
| 74 die('Invalid command specified: {0}. See help below'.format(args[0])) | 76 die('Invalid command specified: {0}. See help below'.format(args[0])) |
| 75 | 77 |
| 78 if options.dry: |
| 79 global DRY_RUN |
| 80 DRY_RUN = True |
| 76 if command == 'promote': | 81 if command == 'promote': |
| 77 _PromoteDartArchiveBuild(options.channel, options.revision) | 82 _PromoteDartArchiveBuild(options.channel, options.revision) |
| 78 | 83 |
| 79 | 84 |
| 80 def UpdateDocs(): | 85 def UpdateDocs(): |
| 81 try: | 86 try: |
| 82 print 'Updating docs' | 87 print 'Updating docs' |
| 83 url = "http://api.dartlang.org/docs/releases/latest/?force_reload=true" | 88 url = "http://api.dartlang.org/docs/releases/latest/?force_reload=true" |
| 84 f = urllib.urlopen(url) | 89 f = urllib.urlopen(url) |
| 85 f.read() | 90 f.read() |
| (...skipping 20 matching lines...) Expand all Loading... |
| 106 "InternalError: Sanity check failed on GS URI: %s" % gs_path) | 111 "InternalError: Sanity check failed on GS URI: %s" % gs_path) |
| 107 | 112 |
| 108 # Google cloud storage has read-after-write, read-after-update, | 113 # Google cloud storage has read-after-write, read-after-update, |
| 109 # and read-after-delete consistency, but not list after delete consistency. | 114 # and read-after-delete consistency, but not list after delete consistency. |
| 110 # Because gsutil uses list to figure out if it should do the unix styly | 115 # Because gsutil uses list to figure out if it should do the unix styly |
| 111 # copy to or copy into, this means that if the directory is reported as | 116 # copy to or copy into, this means that if the directory is reported as |
| 112 # still being there (after it has been deleted) gsutil will copy | 117 # still being there (after it has been deleted) gsutil will copy |
| 113 # into the directory instead of to the directory. | 118 # into the directory instead of to the directory. |
| 114 def wait_for_delete_to_be_consistent_with_list(gs_path): | 119 def wait_for_delete_to_be_consistent_with_list(gs_path): |
| 115 while True: | 120 while True: |
| 121 if DRY_RUN: |
| 122 break |
| 116 (_, _, exit_code) = Gsutil(['ls', gs_path], throw_on_error=False) | 123 (_, _, exit_code) = Gsutil(['ls', gs_path], throw_on_error=False) |
| 117 # gsutil will exit 1 if the "directory" does not exist | 124 # gsutil will exit 1 if the "directory" does not exist |
| 118 if exit_code != 0: | 125 if exit_code != 0: |
| 119 break | 126 break |
| 120 time.sleep(1) | 127 time.sleep(1) |
| 121 | 128 |
| 122 def remove_gs_directory(gs_path): | 129 def remove_gs_directory(gs_path): |
| 123 safety_check_on_gs_path(gs_path, to_revision, channel) | 130 safety_check_on_gs_path(gs_path, to_revision, channel) |
| 124 Gsutil(['-m', 'rm', '-R', '-f', gs_path]) | 131 Gsutil(['-m', 'rm', '-R', '-f', gs_path]) |
| 125 wait_for_delete_to_be_consistent_with_list(gs_path) | 132 wait_for_delete_to_be_consistent_with_list(gs_path) |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 158 from_loc = raw_namer.version_filepath(revision) | 165 from_loc = raw_namer.version_filepath(revision) |
| 159 to_loc = release_namer.version_filepath(to_revision) | 166 to_loc = release_namer.version_filepath(to_revision) |
| 160 Gsutil(['cp', '-a', 'public-read', from_loc, to_loc]) | 167 Gsutil(['cp', '-a', 'public-read', from_loc, to_loc]) |
| 161 | 168 |
| 162 | 169 |
| 163 promote(revision) | 170 promote(revision) |
| 164 promote('latest') | 171 promote('latest') |
| 165 | 172 |
| 166 def Gsutil(cmd, throw_on_error=True): | 173 def Gsutil(cmd, throw_on_error=True): |
| 167 gsutilTool = join(DART_PATH, 'third_party', 'gsutil', 'gsutil') | 174 gsutilTool = join(DART_PATH, 'third_party', 'gsutil', 'gsutil') |
| 168 return bot_utils.run([sys.executable, gsutilTool] + cmd, | 175 command = [sys.executable, gsutilTool] + cmd |
| 169 throw_on_error=throw_on_error) | 176 if DRY_RUN: |
| 177 print "DRY runnning: %s" % command |
| 178 return |
| 179 return bot_utils.run(command, throw_on_error=throw_on_error) |
| 170 | 180 |
| 171 | 181 |
| 172 if __name__ == '__main__': | 182 if __name__ == '__main__': |
| 173 sys.exit(main()) | 183 sys.exit(main()) |
| OLD | NEW |