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

Side by Side Diff: autoupdate.py

Issue 6362008: Refactor devserver to print out relative paths to the update file (Closed) Base URL: http://git.chromium.org/git/dev-util.git@master
Patch Set: Fix refactoring bug introducing before push Created 9 years, 11 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
« no previous file with comments | « no previous file | devserver.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2009-2010 The Chromium OS Authors. All rights reserved. 1 # Copyright (c) 2009-2010 The Chromium OS Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 from buildutil import BuildObject 5 from buildutil import BuildObject
6 from xml.dom import minidom 6 from xml.dom import minidom
7 7
8 import cherrypy 8 import cherrypy
9 import os 9 import os
10 import shutil 10 import shutil
11 import subprocess 11 import subprocess
12 import time 12 import time
13 import urlparse 13 import urlparse
14 14
15 15
16 def _LogMessage(message): 16 def _LogMessage(message):
17 cherrypy.log(message, 'UPDATE') 17 cherrypy.log(message, 'UPDATE')
18 18
19 UPDATE_FILE='update.gz' 19 UPDATE_FILE = 'update.gz'
20 STATEFUL_FILE='stateful.tgz' 20 STATEFUL_FILE = 'stateful.tgz'
21 CACHE_DIR = 'cache'
21 22
22 23
23 def _ChangeUrlPort(url, new_port): 24 def _ChangeUrlPort(url, new_port):
24 """Return the URL passed in with a different port""" 25 """Return the URL passed in with a different port"""
25 scheme, netloc, path, query, fragment = urlparse.urlsplit(url) 26 scheme, netloc, path, query, fragment = urlparse.urlsplit(url)
26 host_port = netloc.split(':') 27 host_port = netloc.split(':')
27 28
28 if len(host_port) == 1: 29 if len(host_port) == 1:
29 host_port.append(new_port) 30 host_port.append(new_port)
30 else: 31 else:
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
75 76
76 self.client_prefix = client_prefix 77 self.client_prefix = client_prefix
77 self.forced_image = forced_image 78 self.forced_image = forced_image
78 self.forced_payload = forced_payload 79 self.forced_payload = forced_payload
79 self.src_image = src_image 80 self.src_image = src_image
80 self.proxy_port = proxy_port 81 self.proxy_port = proxy_port
81 self.vm = vm 82 self.vm = vm
82 self.board = board 83 self.board = board
83 self.copy_to_static_root = copy_to_static_root 84 self.copy_to_static_root = copy_to_static_root
84 85
85 # Track update pregeneration, so we don't recopy if not needed. 86 # Path to pre-generated file.
86 self.pregenerated = False 87 self.pregenerated_path = None
87 88
88 def _GetSecondsSinceMidnight(self): 89 def _GetSecondsSinceMidnight(self):
89 """Returns the seconds since midnight as a decimal value.""" 90 """Returns the seconds since midnight as a decimal value."""
90 now = time.localtime() 91 now = time.localtime()
91 return now[3] * 3600 + now[4] * 60 + now[5] 92 return now[3] * 3600 + now[4] * 60 + now[5]
92 93
93 def _GetDefaultBoardID(self): 94 def _GetDefaultBoardID(self):
94 """Returns the default board id stored in .default_board.""" 95 """Returns the default board id stored in .default_board."""
95 board_file = '%s/.default_board' % (self.scripts_dir) 96 board_file = '%s/.default_board' % (self.scripts_dir)
96 try: 97 try:
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
245 if self.vm: 246 if self.vm:
246 patch_kernel_flag = '' 247 patch_kernel_flag = ''
247 248
248 mkupdate_command = ( 249 mkupdate_command = (
249 '%s/cros_generate_update_payload --image="%s" --output="%s" ' 250 '%s/cros_generate_update_payload --image="%s" --output="%s" '
250 '%s --noold_style --src_image="%s"' % ( 251 '%s --noold_style --src_image="%s"' % (
251 self.scripts_dir, image_path, update_path, patch_kernel_flag, 252 self.scripts_dir, image_path, update_path, patch_kernel_flag,
252 src_image)) 253 src_image))
253 _LogMessage(mkupdate_command) 254 _LogMessage(mkupdate_command)
254 if os.system(mkupdate_command) != 0: 255 if os.system(mkupdate_command) != 0:
255 _LogMessage('Failed to create base update file') 256 _LogMessage('Failed to create update payload')
256 return None 257 return None
257 258
258 return UPDATE_FILE 259 return UPDATE_FILE
259 260
260 def GenerateStatefulFile(self, image_path, output_dir): 261 def GenerateStatefulFile(self, image_path, output_dir):
261 """Generates a stateful update payload given a full path to an image. 262 """Generates a stateful update payload given a full path to an image.
262 263
263 Args: 264 Args:
264 image_path: Full path to image. 265 image_path: Full path to image.
265 Returns: 266 Returns:
(...skipping 11 matching lines...) Expand all
277 return STATEFUL_FILE 278 return STATEFUL_FILE
278 279
279 def FindCachedUpdateImageSubDir(self, src_image, dest_image): 280 def FindCachedUpdateImageSubDir(self, src_image, dest_image):
280 """Find directory to store a cached update. 281 """Find directory to store a cached update.
281 282
282 Given one, or two images for an update, this finds which 283 Given one, or two images for an update, this finds which
283 cache directory should hold the update files, even if they don't exist 284 cache directory should hold the update files, even if they don't exist
284 yet. The directory will be inside static_image_dir, and of the form: 285 yet. The directory will be inside static_image_dir, and of the form:
285 286
286 Non-delta updates: 287 Non-delta updates:
287 cache/12345678 288 CACHE_DIR/12345678
288 289
289 Delta updates: 290 Delta updates:
290 cache/12345678_12345678 291 CACHE_DIR/12345678_12345678
291 """ 292 """
292 # If there is no src, we only have an image file, check image for changes 293 # If there is no src, we only have an image file, check image for changes
293 if not src_image: 294 if not src_image:
294 return os.path.join('cache', self._GetMd5(dest_image)) 295 return os.path.join(CACHE_DIR, self._GetMd5(dest_image))
295 296
296 # If we have src and dest, we are a delta, and check both for changes 297 # If we have src and dest, we are a delta, and check both for changes
297 return os.path.join('cache', 298 return os.path.join(CACHE_DIR,
298 "%s_%s" % (self._GetMd5(src_image), 299 "%s_%s" % (self._GetMd5(src_image),
299 self._GetMd5(dest_image))) 300 self._GetMd5(dest_image)))
300 301
301 def GenerateUpdateImage(self, image_path, output_dir): 302 def GenerateUpdateImage(self, image_path, output_dir):
302 """Force generates an update payload based on the given image_path. 303 """Force generates an update payload based on the given image_path.
303 304
304 Args: 305 Args:
305 src_image: image we are updating from (Null/empty for non-delta) 306 src_image: image we are updating from (Null/empty for non-delta)
306 image_path: full path to the image. 307 image_path: full path to the image.
307 output_dir: the directory to write the update payloads in 308 output_dir: the directory to write the update payloads in
308 Returns: 309 Returns:
309 update payload name relative to output_dir 310 update payload name relative to output_dir
310 """ 311 """
311 update_file = None 312 update_file = None
312 stateful_update_file = None 313 stateful_update_file = None
313 314
314 # Actually do the generation 315 # Actually do the generation
315 _LogMessage('Generating update for image %s' % image_path) 316 _LogMessage('Generating update for image %s' % image_path)
316 update_file = self.GenerateUpdateFile(self.src_image, 317 update_file = self.GenerateUpdateFile(self.src_image,
317 image_path, 318 image_path,
318 output_dir) 319 output_dir)
319 320
320 if update_file: 321 if update_file:
321 stateful_update_file = self.GenerateStatefulFile(image_path, 322 stateful_update_file = self.GenerateStatefulFile(image_path,
322 output_dir) 323 output_dir)
323 324
324 if update_file and stateful_update_file: 325 if update_file and stateful_update_file:
325 return update_file 326 return update_file
326 327 else:
327 _LogMessage('Failed to generate update') 328 _LogMessage('Failed to generate update.')
328 329 return None
329 # Cleanup incomplete files, if they exist
330 if update_file and os.path.exists(update_file):
331 os.remove(update_file)
332
333 return None
334 330
335 def GenerateUpdateImageWithCache(self, image_path, static_image_dir): 331 def GenerateUpdateImageWithCache(self, image_path, static_image_dir):
336 """Force generates an update payload based on the given image_path. 332 """Force generates an update payload based on the given image_path.
337 333
338 Args: 334 Args:
339 image_path: full path to the image. 335 image_path: full path to the image.
340 static_image_dir: the directory to move images to after generating. 336 static_image_dir: the directory to move images to after generating.
341 Returns: 337 Returns:
342 update filename (not directory) relative to static_image_dir on success, 338 update filename (not directory) relative to static_image_dir on success,
343 or None 339 or None.
344 """ 340 """
345 _LogMessage('Generating update for src %s image %s' % (self.src_image, 341 _LogMessage('Generating update for src %s image %s' % (self.src_image,
346 image_path)) 342 image_path))
347 343
348 # If it was pregenerated, don't regenerate 344 # If it was pregenerated_path, don't regenerate
349 if self.pregenerated: 345 if self.pregenerated_path:
350 return UPDATE_FILE 346 return self.pregenerated_path
351 347
352 # Which sub_dir of static_image_dir should hold our cached update image 348 # Which sub_dir of static_image_dir should hold our cached update image
353 cache_sub_dir = self.FindCachedUpdateImageSubDir(self.src_image, image_path) 349 cache_sub_dir = self.FindCachedUpdateImageSubDir(self.src_image, image_path)
354 _LogMessage('Caching in sub_dir "%s"' % cache_sub_dir) 350 _LogMessage('Caching in sub_dir "%s"' % cache_sub_dir)
355 351
352 update_path = os.path.join(cache_sub_dir, UPDATE_FILE)
353
356 # The cached payloads exist in a cache dir 354 # The cached payloads exist in a cache dir
357 cache_update_payload = os.path.join(static_image_dir, 355 cache_update_payload = os.path.join(static_image_dir,
358 cache_sub_dir, 356 update_path)
359 UPDATE_FILE)
360 cache_stateful_payload = os.path.join(static_image_dir, 357 cache_stateful_payload = os.path.join(static_image_dir,
361 cache_sub_dir, 358 cache_sub_dir,
362 STATEFUL_FILE) 359 STATEFUL_FILE)
363 360
364 # The final results exist directly in static 361 # Check to see if this cache directory is valid.
365 update_payload = os.path.join(static_image_dir, 362 if not os.path.exists(cache_update_payload) or not os.path.exists(
366 UPDATE_FILE) 363 cache_stateful_payload):
367 stateful_payload = os.path.join(static_image_dir, 364 full_cache_dir = os.path.join(static_image_dir, cache_sub_dir)
368 STATEFUL_FILE) 365 # Clean up stale state.
366 os.system('rm -rf "%s"' % full_cache_dir)
367 os.makedirs(full_cache_dir)
368 return_path = self.GenerateUpdateImage(image_path,
369 full_cache_dir)
369 370
370 # If there isn't a cached payload, make one 371 # Clean up cache dir since it's not valid.
371 if not os.path.exists(cache_update_payload): 372 if not return_path:
372 full_cache_dir = os.path.join(static_image_dir, cache_sub_dir) 373 os.system('rm -rf "%s"' % full_cache_dir)
374 return None
375 else:
376 assert (return_path == update_path,
377 'Returned path %s not equal to %s' % (return_path, update_path))
373 378
374 # Create the directory for the cache values 379 self.pregenerated_path = update_path
375 if not os.path.exists(full_cache_dir):
376 os.makedirs(full_cache_dir)
377
378 result = self.GenerateUpdateImage(image_path,
379 full_cache_dir)
380
381 if not result:
382 # Clean up cache dir if it's not valid
383 os.system("rm -rf %s" % os.path.join(static_image_dir, cache_sub_dir))
384 return None
385 380
386 # Generation complete, copy if requested. 381 # Generation complete, copy if requested.
387 if self.copy_to_static_root: 382 if self.copy_to_static_root:
383 # The final results exist directly in static
384 update_payload = os.path.join(static_image_dir,
385 UPDATE_FILE)
386 stateful_payload = os.path.join(static_image_dir,
387 STATEFUL_FILE)
388 self._Copy(cache_update_payload, update_payload) 388 self._Copy(cache_update_payload, update_payload)
389 self._Copy(cache_stateful_payload, stateful_payload) 389 self._Copy(cache_stateful_payload, stateful_payload)
390 390 return UPDATE_FILE
391 # Return just the filename in static_image_dir. 391 else:
392 return UPDATE_FILE 392 return self.pregenerated_path
393 393
394 def GenerateLatestUpdateImage(self, board_id, client_version, 394 def GenerateLatestUpdateImage(self, board_id, client_version,
395 static_image_dir): 395 static_image_dir):
396 """Generates an update using the latest image that has been built. 396 """Generates an update using the latest image that has been built.
397 397
398 This will only generate an update if the newest update is newer than that 398 This will only generate an update if the newest update is newer than that
399 on the client or client_version is 'ForcedUpdate'. 399 on the client or client_version is 'ForcedUpdate'.
400 400
401 Args: 401 Args:
402 board_id: Name of the board. 402 board_id: Name of the board.
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
521 Returns: 521 Returns:
522 file name relative to static_image_dir on success. 522 file name relative to static_image_dir on success.
523 """ 523 """
524 dest_path = os.path.join(static_image_dir, UPDATE_FILE) 524 dest_path = os.path.join(static_image_dir, UPDATE_FILE)
525 dest_stateful = os.path.join(static_image_dir, STATEFUL_FILE) 525 dest_stateful = os.path.join(static_image_dir, STATEFUL_FILE)
526 526
527 if self.forced_payload: 527 if self.forced_payload:
528 # If the forced payload is not already in our static_image_dir, 528 # If the forced payload is not already in our static_image_dir,
529 # copy it there. 529 # copy it there.
530 src_path = os.path.abspath(self.forced_payload) 530 src_path = os.path.abspath(self.forced_payload)
531
532 src_stateful = os.path.join(os.path.dirname(src_path), 531 src_stateful = os.path.join(os.path.dirname(src_path),
533 STATEFUL_FILE) 532 STATEFUL_FILE)
534 533
535 # Only copy the files if the source directory is different from dest. 534 # Only copy the files if the source directory is different from dest.
536 if os.path.dirname(src_path) != os.path.abspath(static_image_dir): 535 if os.path.dirname(src_path) != os.path.abspath(static_image_dir):
537 self._Copy(src_path, dest_path) 536 self._Copy(src_path, dest_path)
538 537
539 # The stateful payload is optional. 538 # The stateful payload is optional.
540 if os.path.exists(src_stateful): 539 if os.path.exists(src_stateful):
541 self._Copy(src_stateful, dest_stateful) 540 self._Copy(src_stateful, dest_stateful)
(...skipping 18 matching lines...) Expand all
560 _LogMessage('WARN: %s not found. Expected for dev and test builds.' % 559 _LogMessage('WARN: %s not found. Expected for dev and test builds.' %
561 STATEFUL_FILE) 560 STATEFUL_FILE)
562 561
563 return UPDATE_FILE 562 return UPDATE_FILE
564 else: 563 else:
565 if board_id: 564 if board_id:
566 return self.GenerateLatestUpdateImage(board_id, 565 return self.GenerateLatestUpdateImage(board_id,
567 client_version, 566 client_version,
568 static_image_dir) 567 static_image_dir)
569 568
570 _LogMessage('You must set --board for pre-generating latest update.') 569 _LogMessage('Failed to genereate update. '
570 'You must set --board when pre-generating latest update.')
571 return None 571 return None
572 572
573 def PreGenerateUpdate(self): 573 def PreGenerateUpdate(self):
574 """Pre-generates an update. Returns True on success. 574 """Pre-generates an update and prints out the relative path it.
575
576 Returns relative path of the update on success.
575 """ 577 """
576 # Does not work with factory config. 578 # Does not work with factory config.
577 assert(not self.factory_config) 579 assert(not self.factory_config)
578 _LogMessage('Pre-generating the update payload.') 580 _LogMessage('Pre-generating the update payload.')
579 # Does not work with labels so just use static dir. 581 # Does not work with labels so just use static dir.
580 if self.GenerateUpdatePayloadForNonFactory(self.board, '0.0.0.0', 582 pregenerated_update = self.GenerateUpdatePayloadForNonFactory(
581 self.static_dir): 583 self.board, '0.0.0.0', self.static_dir)
582 _LogMessage('Pre-generated update successfully.') 584 if pregenerated_update:
583 self.pregenerated = True 585 print 'PREGENERATED_UPDATE=%s' % pregenerated_update
584 return True 586
585 else: 587 return pregenerated_update
586 _LogMessage('Failed to pre-generate update.')
587 return False
588 588
589 def HandleUpdatePing(self, data, label=None): 589 def HandleUpdatePing(self, data, label=None):
590 """Handles an update ping from an update client. 590 """Handles an update ping from an update client.
591 591
592 Args: 592 Args:
593 data: xml blob from client. 593 data: xml blob from client.
594 label: optional label for the update. 594 label: optional label for the update.
595 Returns: 595 Returns:
596 Update payload message for client. 596 Update payload message for client.
597 """ 597 """
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
657 is_delta_format = self._IsDeltaFormatFile(filename) 657 is_delta_format = self._IsDeltaFormatFile(filename)
658 if label: 658 if label:
659 url = '%s/%s/%s' % (static_urlbase, label, payload_path) 659 url = '%s/%s/%s' % (static_urlbase, label, payload_path)
660 else: 660 else:
661 url = '%s/%s' % (static_urlbase, payload_path) 661 url = '%s/%s' % (static_urlbase, payload_path)
662 662
663 _LogMessage('Responding to client to use url %s to get image.' % url) 663 _LogMessage('Responding to client to use url %s to get image.' % url)
664 return self.GetUpdatePayload(hash, sha256, size, url, is_delta_format) 664 return self.GetUpdatePayload(hash, sha256, size, url, is_delta_format)
665 else: 665 else:
666 return self.GetNoUpdatePayload() 666 return self.GetNoUpdatePayload()
OLDNEW
« no previous file with comments | « no previous file | devserver.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698