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

Side by Side Diff: src/platform/dev/autoupdate.py

Issue 1141001: adds Devserver support for statically serving versioned updates. (Closed)
Patch Set: recommit as workaround for odd git merge behavior Created 10 years, 9 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
« no previous file with comments | « no previous file | src/platform/dev/buildutil.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 The Chromium OS Authors. All rights reserved. 1 # Copyright (c) 2009 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 os 8 import os
9 import web 9 import web
10 10
11 class Autoupdate(BuildObject): 11 class Autoupdate(BuildObject):
12
13 # Basic functionality of handling ChromeOS autoupdate pings 12 # Basic functionality of handling ChromeOS autoupdate pings
14 # and building/serving update images. 13 # and building/serving update images.
15 # TODO(rtc): Clean this code up and write some tests. 14 # TODO(rtc): Clean this code up and write some tests.
16 15
16 def __init__(self, serve_only=None, test_image=False, *args, **kwargs):
17 self.serve_only = serve_only
18 if serve_only:
19 web.debug('Autoupdate in "serve update images only" mode.')
20 self.test_image=test_image
21 super(Autoupdate, self).__init__(*args, **kwargs)
22
17 def GetUpdatePayload(self, hash, size, url): 23 def GetUpdatePayload(self, hash, size, url):
18 payload = """<?xml version="1.0" encoding="UTF-8"?> 24 payload = """<?xml version="1.0" encoding="UTF-8"?>
19 <gupdate xmlns="http://www.google.com/update2/response" protocol="2.0"> 25 <gupdate xmlns="http://www.google.com/update2/response" protocol="2.0">
20 <app appid="{%s}" status="ok"> 26 <app appid="{%s}" status="ok">
21 <ping status="ok"/> 27 <ping status="ok"/>
22 <updatecheck 28 <updatecheck
23 codebase="%s" 29 codebase="%s"
24 hash="%s" 30 hash="%s"
25 needsadmin="false" 31 needsadmin="false"
26 size="%s" 32 size="%s"
27 status="ok"/> 33 status="ok"/>
28 </app> 34 </app>
29 </gupdate> 35 </gupdate>
30 """ 36 """
31 return payload % (self.app_id, url, hash, size) 37 return payload % (self.app_id, url, hash, size)
32 38
33 def GetNoUpdatePayload(self): 39 def GetNoUpdatePayload(self):
34 payload = """<?xml version="1.0" encoding="UTF-8"?> 40 payload = """<?xml version="1.0" encoding="UTF-8"?>
35 <gupdate xmlns="http://www.google.com/update2/response" protocol="2.0"> 41 <gupdate xmlns="http://www.google.com/update2/response" protocol="2.0">
36 <app appid="{%s}" status="ok"> 42 <app appid="{%s}" status="ok">
37 <ping status="ok"/> 43 <ping status="ok"/>
38 <updatecheck status="noupdate"/> 44 <updatecheck status="noupdate"/>
39 </app> 45 </app>
40 </gupdate> 46 </gupdate>
41 """ 47 """
42 return payload % self.app_id 48 return payload % self.app_id
43 49
44 def GetLatestImagePath(self, board_id): 50 def GetLatestImagePath(self, board_id):
45 cmd = "%s/get_latest_image.sh --board %s" % (self.scripts_dir, board_id) 51 cmd = '%s/get_latest_image.sh --board %s' % (self.scripts_dir, board_id)
46 return os.popen(cmd).read().strip() 52 return os.popen(cmd).read().strip()
47 53
48 def GetLatestVersion(self, latest_image_path): 54 def GetLatestVersion(self, latest_image_path):
49 latest_version = latest_image_path.split('/')[-1] 55 latest_version = latest_image_path.split('/')[-1]
50 56
51 # Removes the portage build prefix. 57 # Removes the portage build prefix.
52 latest_version = latest_version.lstrip("g-") 58 latest_version = latest_version.lstrip('g-')
53 return latest_version.split('-')[0] 59 return latest_version.split('-')[0]
54 60
55 def CanUpdate(self, client_version, latest_version): 61 def CanUpdate(self, client_version, latest_version):
56 """ 62 """
57 Returns true iff the latest_version is greater than the client_version. 63 Returns true iff the latest_version is greater than the client_version.
58 """ 64 """
59 client_tokens = client_version.split('.') 65 client_tokens = client_version.split('.')
60 latest_tokens = latest_version.split('.') 66 latest_tokens = latest_version.split('.')
61 web.debug("client version %s latest version %s" \ 67 web.debug('client version %s latest version %s' \
62 % (client_version, latest_version)) 68 % (client_version, latest_version))
63 for i in range(0,4): 69 for i in range(0,4):
64 if int(latest_tokens[i]) == int(client_tokens[i]): 70 if int(latest_tokens[i]) == int(client_tokens[i]):
65 continue 71 continue
66 return int(latest_tokens[i]) > int(client_tokens[i]) 72 return int(latest_tokens[i]) > int(client_tokens[i])
67 return False 73 return False
68 74
69 def BuildUpdateImage(self, image_path): 75 def BuildUpdateImage(self, image_path):
70 image_file = "%s/rootfs.image" % image_path 76 if self.test_image:
71 web.debug("checking image file %s/update.gz" % image_path) 77 image_file = '%s/rootfs_test.image' % image_path
72 if not os.path.exists("%s/update.gz" % image_path): 78 else:
73 mkupdate = "%s/mk_memento_images.sh %s" % (self.scripts_dir, image_file) 79 image_file = '%s/rootfs.image' % image_path
80 update_file = '%s/update.gz' % image_path
81 if (os.path.exists(update_file) and
82 os.path.getmtime(update_file) >= os.path.getmtime(image_file)):
83 web.debug('Found cached update image %s/update.gz' % image_path)
84 else:
85 web.debug('generating update image %s/update.gz' % image_path)
86 mkupdate = '%s/mk_memento_images.sh %s' % (self.scripts_dir, image_file)
74 web.debug(mkupdate) 87 web.debug(mkupdate)
75 err = os.system(mkupdate) 88 err = os.system(mkupdate)
76 if err != 0: 89 if err != 0:
77 web.debug("failed to create update image") 90 web.debug('failed to create update image')
78 return False 91 return False
79 92 if not self.serve_only:
80 web.debug("Found an image, copying it to static") 93 web.debug('Found an image, copying it to static')
81 err = os.system("cp %s/update.gz %s" % (image_path, self.static_dir)) 94 try:
82 if err != 0: 95 shutil.copyfile('%s/update.gz' % image_path, self.static_dir)
83 web.debug("Unable to move update.gz from %s to %s" \ 96 except Exception, e:
84 % (image_path, self.static_dir)) 97 web.debug('Unable to copy update.gz from %s to %s' \
85 return False 98 % (image_path, self.static_dir))
99 return False
86 return True 100 return True
87 101
88 def GetSize(self, update_path): 102 def GetSize(self, update_path):
89 return os.path.getsize(update_path) 103 return os.path.getsize(update_path)
90 104
91 def GetHash(self, update_path): 105 def GetHash(self, update_path):
92 cmd = "cat %s | openssl sha1 -binary | openssl base64 | tr \'\\n\' \' \';" \ 106 update_dir = os.path.dirname(update_path)
93 % update_path 107 if not os.path.exists('%s/cksum' % update_dir):
94 web.debug(cmd) 108 cmd = ('cat %s | openssl sha1 -binary'
95 return os.popen(cmd).read() 109 '| openssl base64 | tr \'\\n\' \' \' | tee %s/cksum' %
110 (update_path, update_dir))
111 web.debug(cmd)
112 return os.popen(cmd).read()
113 else:
114 web.debug('using cached checksum for %s' % update_path)
115 return file('%s/cksum' % update_dir).read()
96 116
97 def HandleUpdatePing(self, data): 117 def HandleUpdatePing(self, data, label=None):
98 update_dom = minidom.parseString(data) 118 update_dom = minidom.parseString(data)
99 root = update_dom.firstChild 119 root = update_dom.firstChild
100 query = root.getElementsByTagName("o:app")[0] 120 query = root.getElementsByTagName('o:app')[0]
101 client_version = query.getAttribute('version') 121 client_version = query.getAttribute('version')
102 board_id = query.hasAttribute('board') and query.getAttribute('board') \ 122 board_id = query.hasAttribute('board') and query.getAttribute('board') \
103 or "x86-generic" 123 or 'x86-generic'
104 latest_image_path = self.GetLatestImagePath(board_id) 124 latest_image_path = self.GetLatestImagePath(board_id)
105 latest_version = self.GetLatestVersion(latest_image_path) 125 latest_version = self.GetLatestVersion(latest_image_path)
106 if client_version != "ForcedUpdate" \ 126 if client_version != 'ForcedUpdate' \
107 and not self.CanUpdate(client_version, latest_version): 127 and not self.CanUpdate(client_version, latest_version):
108 web.debug("no update") 128 web.debug('no update')
109 return self.GetNoUpdatePayload() 129 return self.GetNoUpdatePayload()
130 hostname = web.ctx.host
131 if label:
132 web.debug('Client requested version %s' % label)
133 # Check that matching build exists
134 image_path = '%s/%s' % (self.static_dir, label)
135 if not os.path.exists(image_path):
136 web.debug('%s not found.' % image_path)
137 return self.GetNoUpdatePayload()
138 # Construct a response
139 ok = self.BuildUpdateImage(image_path)
140 if ok != True:
141 web.debug('Failed to build an update image')
142 return self.GetNoUpdatePayload()
143 web.debug('serving update: ')
144 hash = self.GetHash('%s/%s/update.gz' % (self.static_dir, label))
145 size = self.GetSize('%s/%s/update.gz' % (self.static_dir, label))
146 url = 'http://%s/static/archive/%s/update.gz' % (hostname, label)
147 return self.GetUpdatePayload(hash, size, url)
148 web.debug( 'DONE')
149 else:
150 web.debug('update found %s ' % latest_version)
151 ok = self.BuildUpdateImage(latest_image_path)
152 if ok != True:
153 web.debug('Failed to build an update image')
154 return self.GetNoUpdatePayload()
110 155
111 web.debug("update found %s " % latest_version) 156 hash = self.GetHash('%s/update.gz' % self.static_dir)
112 ok = self.BuildUpdateImage(latest_image_path) 157 size = self.GetSize('%s/update.gz' % self.static_dir)
113 if ok != True:
114 web.debug("Failed to build an update image")
115 return self.GetNoUpdatePayload()
116 158
117 hash = self.GetHash("%s/update.gz" % self.static_dir) 159 url = 'http://%s/static/update.gz' % hostname
118 size = self.GetSize("%s/update.gz" % self.static_dir) 160 return self.GetUpdatePayload(hash, size, url)
119 hostname = web.ctx.host
120 url = "http://%s/static/update.gz" % hostname
121 return self.GetUpdatePayload(hash, size, url)
122
OLDNEW
« no previous file with comments | « no previous file | src/platform/dev/buildutil.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698