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

Side by Side Diff: dart/editor/build/promote.py

Issue 68633002: Version 1.0.0.2 (Closed) Base URL: http://dart.googlecode.com/svn/trunk/
Patch Set: Created 7 years, 1 month 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 | « dart/editor/build/build.py ('k') | dart/samples/dartiverse_search/bin/server.dart » ('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 # 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 and google storage cleanup tools. 7 # Dart Editor promote tools.
8 8
9 import gsutil
10 import imp 9 import imp
11 import optparse 10 import optparse
12 import os 11 import os
13 import subprocess 12 import subprocess
14 import sys 13 import sys
15 import urllib 14 import urllib
16 15
17 from os.path import join 16 from os.path import join
18 17
19 CONTINUOUS = 'gs://dart-editor-archive-continuous'
20 TRUNK = 'gs://dart-editor-archive-trunk'
21 TESTING = 'gs://dart-editor-archive-testing'
22 INTEGRATION = 'gs://dart-editor-archive-integration'
23 RELEASE = 'gs://dart-editor-archive-release'
24 INTERNAL = 'gs://dart-editor-archive-internal'
25
26 DART_PATH = os.path.abspath(os.path.join(__file__, '..', '..', '..')) 18 DART_PATH = os.path.abspath(os.path.join(__file__, '..', '..', '..'))
27 BOT_UTILS = os.path.abspath(os.path.join( 19 BOT_UTILS = os.path.abspath(os.path.join(
28 DART_PATH, 'tools', 'bots', 'bot_utils.py')) 20 DART_PATH, 'tools', 'bots', 'bot_utils.py'))
29 21
30 bot_utils = imp.load_source('bot_utils', BOT_UTILS) 22 bot_utils = imp.load_source('bot_utils', BOT_UTILS)
31 23
32 def _BuildOptions(): 24 def BuildOptions():
33 """Setup the argument processing for this program. 25 usage = """usage: %prog promote [options]
26 where:
27 promote - Will promote builds from raw/signed locations to release
28 locations.
34 29
35 Returns: 30 Example: Promote revision r29962 on dev channel:
36 the OptionParser to process the CLI 31 python editor/build/promote.py promote --channel=dev --revision=29962
37 """ 32 """
38 usage = """usage: %prog [options] cleanup|promote
39 where:
40 cleanup will cleanup the Google storage continuous bucket
41 promote will promote code between different stages
42
43 Examples:
44 cleanup saving the last 150 revisions
45 python gsTool.py cleanup --keepcount=150
46
47 promote revision 567 from trunk to integration
48 python gsTool.py promote --trunk --revision=567"""
49
50 33
51 result = optparse.OptionParser(usage=usage) 34 result = optparse.OptionParser(usage=usage)
52 result.set_default('gsbucketuri', 'gs://dart-editor-archive-continuous') 35
53 result.set_default('keepcount', 1000) 36 group = optparse.OptionGroup(
54 result.set_default('dryrun', False) 37 result, 'Promote', 'options used to promote code')
55 result.set_default('continuous', False) 38 group.add_option(
56 result.set_default('trunk', False) 39 '--revision', help='The svn revision to promote', action='store')
57 result.set_default('integration', False) 40 group.add_option(
58 result.set_default('testing', False) 41 '--channel', type='string', help='Channel to promote.', default=None)
59 group = optparse.OptionGroup(result, 'Cleanup',
60 'options used to cleanup Google Storage')
61 group.add_option('--keepcount',
62 type='int',
63 help='Numer of Builds to keep.',
64 action='store')
65 result.add_option_group(group) 42 result.add_option_group(group)
66 43
67 group = optparse.OptionGroup(result, 'Promote',
68 'options used to promote code')
69 group.add_option('--revision',
70 help='The svn revision to promote',
71 action='store')
72 group.add_option('--continuous',
73 help='Promote from continuous',
74 action='store_true')
75 group.add_option('--trunk',
76 help='Promote from trunk',
77 action='store_true')
78 group.add_option('--internal',
79 help='Promote from trunk to internal',
80 action='store_true')
81 group.add_option('--integration',
82 help='Promote from integration',
83 action='store_true')
84 group.add_option('--channel', type='string',
85 help='Promote from this channel',
86 default=None)
87 result.add_option_group(group)
88
89 result.add_option('--gsbucketuri',
90 help='Dart Continuous Google Storage bucket URI.',
91 action='store')
92 result.add_option('--gsutilloc',
93 help='location of gsutil the program',
94 action='store')
95 result.add_option('--dryrun', help='don\'t do anything that would change'
96 ' Google Storage',
97 action='store_true')
98 result.add_option('--testing', help='user test bucket in '
99 ' Google Storage',
100 action='store_true')
101
102 return result 44 return result
103 45
104 46
105 def main(): 47 def main():
106 """Main entry point for Google Storage Tools.""" 48 parser = BuildOptions()
107
108 parser = _BuildOptions()
109 (options, args) = parser.parse_args() 49 (options, args) = parser.parse_args()
110 50
111 if not args: 51 def die(msg):
112 print 'At least one command must be specified' 52 print msg
113 parser.print_help() 53 parser.print_help()
114 sys.exit(1) 54 sys.exit(1)
115 55
56 if not args:
57 die('At least one command must be specified')
58
116 if args[0] == 'promote': 59 if args[0] == 'promote':
117 command = 'promote' 60 command = 'promote'
118 if options.revision is None: 61 if options.revision is None:
119 print 'You must specify a --revision to specify which revision to promote' 62 die('You must specify a --revision to specify which revision to promote')
120 parser.print_help()
121 sys.exit(3)
122 63
123 # Make sure revision is a valid integer 64 # Make sure revision is a valid integer
124 try: 65 try:
125 _ = int(options.revision) 66 _ = int(options.revision)
126 except: 67 except:
127 print 'You must supply a valid integer argument to --revision to promote' 68 die('You must supply a valid integer argument to --revision to promote')
128 parser.print_help()
129 sys.exit(3)
130 69
131 # Make sure options.channel is a valid channel if given 70 # Make sure options.channel is a valid
132 if options.channel: 71 if not options.channel:
133 if options.channel not in bot_utils.Channel.ALL_CHANNELS: 72 die('Specify --channel=be/dev/stable')
134 print 'You must supply a valid channel to --channel to promote' 73 if options.channel not in bot_utils.Channel.ALL_CHANNELS:
135 parser.print_help() 74 die('You must supply a valid channel to --channel to promote')
136 sys.exit(3) 75 else:
76 die('Invalid command specified: {0}. See help below'.format(args[0]))
137 77
138 if not (options.continuous or options.integration or 78 if command == 'promote':
139 options.testing or options.trunk or options.internal or 79 _PromoteDartArchiveBuild(options.channel, options.revision)
140 options.channel):
141 print ('Specify --continuous, --integration, --testing, --trunk or '
142 '--channel=be/dev/stable')
143 parser.print_help()
144 sys.exit(4)
145 if options.continuous and options.integration:
146 print 'continuous and integration can not be specified at the same time'
147 parser.print_help()
148 sys.exit(5)
149 if (options.continuous or options.integration) and options.testing:
150 print """Warning --continuous or --integration and --testing are
151 specified. The --testing flag will take precedence and all data will
152 go to the testing bucket {0}""".format(TESTING)
153 elif args[0] == 'cleanup':
154 command = 'cleanup'
155 if options.keepcount is None:
156 print 'You must specify --keepcount'
157 parser.print_help()
158 sys.exit(6)
159 else:
160 print 'Invalid command specified: {0}. See help below'.format(args[0])
161 parser.print_help()
162 sys.exit(2)
163
164 gsu = gsutil.GsUtil(options.dryrun, options.gsutilloc)
165 if options.testing:
166 bucket_from = CONTINUOUS
167 bucket_to = TESTING
168 print """The --testing attribute is specified. All data will go to the
169 testing bucket {0}. Press enter to continue""".format(TESTING)
170 raw_input('Press Enter to continue')
171 elif options.continuous:
172 bucket_from = CONTINUOUS
173 bucket_to = INTEGRATION
174 elif options.trunk:
175 bucket_from = TRUNK
176 bucket_to = INTEGRATION
177 elif options.integration:
178 bucket_from = INTEGRATION
179 bucket_to = RELEASE
180 elif options.internal:
181 bucket_from = TRUNK
182 bucket_to = INTERNAL
183
184 if command == 'cleanup':
185 #if the testing flag is set remove the date from the testing bucket
186 if options.testing:
187 bucket = TESTING
188 #otherwise use the value passed as --gsbucketuri
189 else:
190 bucket = options.gsbucketuri
191 version_dirs = _ReadBucket(gsu, '{0}/{1}'.format(bucket, '[0-9]*'))
192 _RemoveElements(gsu, bucket, version_dirs, options.keepcount)
193 elif command == 'promote':
194 if options.channel:
195 _PromoteDartArchiveBuild(options.channel, options.revision)
196 else:
197 _PromoteBuild(options.revision, bucket_from, bucket_to)
198 _UpdateDocs()
199 80
200 81
201 def _UpdateDocs(): 82 def UpdateDocs():
202 try: 83 try:
203 print 'Updating docs' 84 print 'Updating docs'
204 url = "http://api.dartlang.org/docs/releases/latest/?force_reload=true" 85 url = "http://api.dartlang.org/docs/releases/latest/?force_reload=true"
205 f = urllib.urlopen(url) 86 f = urllib.urlopen(url)
206 f.read() 87 f.read()
207 print 'Successfully updated api docs' 88 print 'Successfully updated api docs'
208 except Exception as e: 89 except Exception as e:
209 print 'Could not update api docs, please manually update them' 90 print 'Could not update api docs, please manually update them'
210 print 'Failed with: %s' % e 91 print 'Failed with: %s' % e
211 92
212 def _ReadBucket(gsu, bucket):
213 """Read the contents of a Google Storage Bucket.
214
215 Args:
216 gsu: the location of the gsutil program
217 bucket: the bucket to read the contents of
218
219 Returns:
220 a list of bucket entries excluding all entries starting with "latest"
221 """
222 _PrintSeparator('_ReadBucket({0}, {1})'.format(gsu, bucket))
223 elements = []
224 items = gsu.ReadBucket(bucket)
225 for item in items:
226 dirpaths = item.split('/')
227 if len(dirpaths) >= 3:
228 dirname = dirpaths[3]
229 if dirname != 'latest':
230 try:
231 dirnum = int(dirname)
232 if not dirnum in elements:
233 elements.append(dirnum)
234 except ValueError:
235 pass
236
237 return elements
238
239
240 def _RemoveElements(gsu, bucket, version_dirs, keepcount):
241 """Remove the selected elements from Google Storage.
242
243 Args:
244 gsu: the gsutil program to run
245 bucket: the bucket to remove the dirs from
246 version_dirs: the dictionary of elements to remove keyed by
247 svn version number
248 keepcount: the number of elements to keep
249 """
250 _PrintSeparator('_RemoveElements({0}, version_dirs,'
251 ' {1}'.format(gsu, keepcount))
252 version_dirs_size = len(version_dirs)
253 delete_count = version_dirs_size - keepcount
254 if delete_count > 0:
255 count = 0
256 version_dirs.sort()
257 for gs_dir in version_dirs:
258 if count < delete_count:
259 gsu.RemoveAll('{0}/{1}/*'.format(bucket, gs_dir))
260 else:
261 print 'version {0}/{1} will be saved'.format(bucket, gs_dir)
262 count += 1
263 else:
264 print ('nothing to delete because that are only {0} elemens in the list'
265 ' and the keep count is set to {0}').format(len(version_dirs),
266 keepcount)
267
268
269 def _PromoteBuild(revision, from_bucket, to_bucket):
270 """Promote a build from one bucket to another.
271
272 Args:
273 revision: the revision to promote
274 from_bucket: the bucket to promote from
275 to_bucket: the bucket to promote to
276 """
277
278 # print the gsutil version
279 _Gsutil(['version'])
280
281 src = '%s/%s/' % (from_bucket, revision)
282 srcVersion = src + 'VERSION'
283
284 # copy from continuous/1234 to trunk/1234
285 dest = '%s/%s/' % (to_bucket, revision)
286 destUpdate = dest + 'eclipse-update/'
287 print 'copying: %s -> %s' % (src, dest)
288 _Gsutil(['cp', '-a', 'public-read', srcVersion, destUpdate + 'features/'])
289 _Gsutil(['cp', '-a', 'public-read', srcVersion, destUpdate + 'plugins/'])
290 _Gsutil(['cp', '-r', '-a', 'public-read', src + '*', dest])
291
292 # copy from continuous/1234 to trunk/latest
293 dest = '%s/%s/' % (to_bucket, 'latest')
294 destUpdate = dest + 'eclipse-update/'
295 print 'copying: %s -> %s' % (src, dest)
296 _Gsutil(['cp', '-a', 'public-read', srcVersion, destUpdate + 'features/'])
297 _Gsutil(['cp', '-a', 'public-read', srcVersion, destUpdate + 'plugins/'])
298 _Gsutil(['cp', '-r', '-a', 'public-read', src + '*', dest])
299 93
300 def _PromoteDartArchiveBuild(channel, revision): 94 def _PromoteDartArchiveBuild(channel, revision):
301 # These namer objects will be used to create GCS object URIs. For the 95 # These namer objects will be used to create GCS object URIs. For the
302 # structure we use, please see tools/bots/bot_utils.py:GCSNamer 96 # structure we use, please see tools/bots/bot_utils.py:GCSNamer
303 raw_namer = bot_utils.GCSNamer(channel, bot_utils.ReleaseType.RAW) 97 raw_namer = bot_utils.GCSNamer(channel, bot_utils.ReleaseType.RAW)
304 signed_namer = bot_utils.GCSNamer(channel, bot_utils.ReleaseType.SIGNED) 98 signed_namer = bot_utils.GCSNamer(channel, bot_utils.ReleaseType.SIGNED)
305 release_namer = bot_utils.GCSNamer(channel, bot_utils.ReleaseType.RELEASE) 99 release_namer = bot_utils.GCSNamer(channel, bot_utils.ReleaseType.RELEASE)
306 100
307 def promote(to_revision): 101 def promote(to_revision):
308 def safety_check_on_gs_path(gs_path, revision, channel): 102 def safety_check_on_gs_path(gs_path, revision, channel):
309 if not ((revision == 'latest' or int(revision) > 0) 103 if not ((revision == 'latest' or int(revision) > 0)
310 and len(channel) > 0 104 and len(channel) > 0
311 and ('%s' % revision) in gs_path 105 and ('%s' % revision) in gs_path
312 and channel in gs_path): 106 and channel in gs_path):
313 raise Exception( 107 raise Exception(
314 "InternalError: Sanity check failed on GS URI: %s" % gs_path) 108 "InternalError: Sanity check failed on GS URI: %s" % gs_path)
315 109
316 def remove_gs_directory(gs_path): 110 def remove_gs_directory(gs_path):
317 safety_check_on_gs_path(gs_path, to_revision, channel) 111 safety_check_on_gs_path(gs_path, to_revision, channel)
318 _Gsutil(['-m', 'rm', '-R', '-f', gs_path]) 112 Gsutil(['-m', 'rm', '-R', '-f', gs_path])
319 113
320 # Copy VERSION file. 114 # Copy VERSION file.
321 from_loc = raw_namer.version_filepath(revision) 115 from_loc = raw_namer.version_filepath(revision)
322 to_loc = release_namer.version_filepath(to_revision) 116 to_loc = release_namer.version_filepath(to_revision)
323 _Gsutil(['cp', '-a', 'public-read', from_loc, to_loc]) 117 Gsutil(['cp', '-a', 'public-read', from_loc, to_loc])
324 118
325 # Copy sdk directory. 119 # Copy sdk directory.
326 from_loc = raw_namer.sdk_directory(revision) 120 from_loc = raw_namer.sdk_directory(revision)
327 to_loc = release_namer.sdk_directory(to_revision) 121 to_loc = release_namer.sdk_directory(to_revision)
328 remove_gs_directory(to_loc) 122 remove_gs_directory(to_loc)
329 _Gsutil(['-m', 'cp', '-a', 'public-read', '-R', from_loc, to_loc]) 123 Gsutil(['-m', 'cp', '-a', 'public-read', '-R', from_loc, to_loc])
330 124
331 # Copy eclipse update directory. 125 # Copy eclipse update directory.
332 from_loc = raw_namer.editor_eclipse_update_directory(revision) 126 from_loc = raw_namer.editor_eclipse_update_directory(revision)
333 to_loc = release_namer.editor_eclipse_update_directory(to_revision) 127 to_loc = release_namer.editor_eclipse_update_directory(to_revision)
334 remove_gs_directory(to_loc) 128 remove_gs_directory(to_loc)
335 _Gsutil(['-m', 'cp', '-a', 'public-read', '-R', from_loc, to_loc]) 129 Gsutil(['-m', 'cp', '-a', 'public-read', '-R', from_loc, to_loc])
336 130
337 # Copy api-docs zipfile. 131 # Copy api-docs zipfile.
338 from_loc = raw_namer.apidocs_zipfilepath(revision) 132 from_loc = raw_namer.apidocs_zipfilepath(revision)
339 to_loc = release_namer.apidocs_zipfilepath(to_revision) 133 to_loc = release_namer.apidocs_zipfilepath(to_revision)
340 _Gsutil(['-m', 'cp', '-a', 'public-read', from_loc, to_loc]) 134 Gsutil(['-m', 'cp', '-a', 'public-read', from_loc, to_loc])
341 135
342 # Copy dartium directory. 136 # Copy dartium directory.
343 from_loc = raw_namer.dartium_directory(revision) 137 from_loc = raw_namer.dartium_directory(revision)
344 to_loc = release_namer.dartium_directory(to_revision) 138 to_loc = release_namer.dartium_directory(to_revision)
345 remove_gs_directory(to_loc) 139 remove_gs_directory(to_loc)
346 _Gsutil(['-m', 'cp', '-a', 'public-read', '-R', from_loc, to_loc]) 140 Gsutil(['-m', 'cp', '-a', 'public-read', '-R', from_loc, to_loc])
347 141
348 # Copy editor zip files. 142 # Copy editor zip files.
349 target_editor_dir = release_namer.editor_directory(to_revision) 143 target_editor_dir = release_namer.editor_directory(to_revision)
350 remove_gs_directory(target_editor_dir) 144 remove_gs_directory(target_editor_dir)
351 for system in ['windows', 'macos', 'linux']: 145 for system in ['windows', 'macos', 'linux']:
352 for arch in ['ia32', 'x64']: 146 for arch in ['ia32', 'x64']:
353 from_namer = raw_namer 147 from_namer = raw_namer
354 # We have signed versions of the editor for windows and macos. 148 # We have signed versions of the editor for windows and macos.
355 if system == 'windows' or system == 'macos': 149 if system == 'windows' or system == 'macos':
356 from_namer = signed_namer 150 from_namer = signed_namer
357 from_loc = from_namer.editor_zipfilepath(revision, system, arch) 151 from_loc = from_namer.editor_zipfilepath(revision, system, arch)
358 to_loc = release_namer.editor_zipfilepath(to_revision, system, arch) 152 to_loc = release_namer.editor_zipfilepath(to_revision, system, arch)
359 _Gsutil(['cp', '-a', 'public-read', from_loc, to_loc]) 153 Gsutil(['cp', '-a', 'public-read', from_loc, to_loc])
360 _Gsutil(['cp', '-a', 'public-read', from_loc + '.md5sum', 154 Gsutil(['cp', '-a', 'public-read', from_loc + '.md5sum',
361 to_loc + '.md5sum']) 155 to_loc + '.md5sum'])
362 156
157 # Copy signed editor installers for macos/windows.
158 for system, extension in [('windows', 'msi'), ('macos', 'dmg')]:
159 for arch in ['ia32', 'x64']:
160 from_loc = signed_namer.editor_installer_filepath(
161 revision, system, arch, extension)
162 to_loc = release_namer.editor_installer_filepath(
163 to_revision, system, arch, extension)
164 Gsutil(['cp', '-a', 'public-read', from_loc, to_loc])
165
363 promote(revision) 166 promote(revision)
364 promote('latest') 167 promote('latest')
365 168
366 def _PrintSeparator(text): 169 def Gsutil(cmd):
367 print '================================'
368 print '== %s' % text
369
370
371 def _PrintFailure(text):
372 print '*****************************'
373 print '** %s' % text
374 print '*****************************'
375
376
377 def _Gsutil(cmd):
378 gsutilTool = join(DART_PATH, 'third_party', 'gsutil', 'gsutil') 170 gsutilTool = join(DART_PATH, 'third_party', 'gsutil', 'gsutil')
379 return _ExecuteCommand([sys.executable, gsutilTool] + cmd) 171 bot_utils.run([sys.executable, gsutilTool] + cmd)
380
381
382 def _ExecuteCommand(cmd, directory=None):
383 """Execute the given command."""
384 if directory is not None:
385 cwd = os.getcwd()
386 os.chdir(directory)
387 subprocess.call(cmd, env=os.environ)
388 if directory is not None:
389 os.chdir(cwd)
390 172
391 173
392 if __name__ == '__main__': 174 if __name__ == '__main__':
393 sys.exit(main()) 175 sys.exit(main())
OLDNEW
« no previous file with comments | « dart/editor/build/build.py ('k') | dart/samples/dartiverse_search/bin/server.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698