Mercurial > mozilla > hg > dogfood
comparison dogdish/dispatcher.py @ 14:cffb6f681b59
things seem to work
author | Jeff Hammel <jhammel@mozilla.com> |
---|---|
date | Wed, 17 Oct 2012 13:26:22 -0700 |
parents | 71f9f68986b5 |
children | fc5b842de4e9 |
comparison
equal
deleted
inserted
replaced
13:71f9f68986b5 | 14:cffb6f681b59 |
---|---|
4 dogdish | 4 dogdish |
5 https://bugzilla.mozilla.org/show_bug.cgi?id=800118 | 5 https://bugzilla.mozilla.org/show_bug.cgi?id=800118 |
6 """ | 6 """ |
7 | 7 |
8 import fnmatch | 8 import fnmatch |
9 import hashlib | |
9 import os | 10 import os |
10 import sys | 11 import sys |
11 from urlparse import urlparse | 12 from urlparse import urlparse |
12 from webob import Request | 13 from webob import Request |
13 from webob import Response, exc | 14 from webob import Response, exc |
21 | 22 |
22 def __init__(self, filename): | 23 def __init__(self, filename): |
23 """ | 24 """ |
24 - filename : path to an application.ini file | 25 - filename : path to an application.ini file |
25 """ | 26 """ |
27 config = ConfigParser() | |
28 config.read(filename) | |
29 self.build_id = config.get('App', 'BuildID') | |
30 self.version = config.get('App', 'Version') | |
26 | 31 |
27 ### request handlers | 32 ### request handlers |
28 | 33 |
29 class Handler(object): | 34 class Handler(object): |
30 """abstract handler object for a request""" | 35 """abstract handler object for a request""" |
31 | 36 |
32 def __init__(self, request): | 37 def __init__(self, app, request): |
38 self.app = app | |
33 self.request = request | 39 self.request = request |
34 self.application_path = urlparse(request.application_url)[2] | 40 self.application_path = urlparse(request.application_url)[2] |
35 | 41 |
36 def link(self, path=(), permanant=False): | 42 def link(self, path=(), permanant=False): |
37 if isinstance(path, basestring): | 43 if isinstance(path, basestring): |
52 | 58 |
53 # template for response body | 59 # template for response body |
54 body = """<?xml version="1.0"?> | 60 body = """<?xml version="1.0"?> |
55 <updates> | 61 <updates> |
56 <update type="minor" appVersion="19.0a1" version="19.0a1" extensionVersion="19.0a1" buildID="20121010114416" licenseURL="http://www.mozilla.com/test/sample-eula.html" detailsURL="http://www.mozilla.com/test/sample-details.html"> | 62 <update type="minor" appVersion="19.0a1" version="19.0a1" extensionVersion="19.0a1" buildID="20121010114416" licenseURL="http://www.mozilla.com/test/sample-eula.html" detailsURL="http://www.mozilla.com/test/sample-details.html"> |
57 <patch type="complete" URL="http://update.boot2gecko.org/nightly/b2g_update_2012-10-10_114416.mar%(query)s" hashFunction="SHA512" hashValue="84edb1f53891cf983bc0f6066d31492f43e2d063aaceb05e1c51876f4fde81635afeb7ce3203dee6f65dd59be0cae5c73c49093b625c99acd4118000ad72dda8" size="42924805"/> | 63 <patch type="complete" URL="http://update.boot2gecko.org/nightly/%(update)s%(query)s" hashFunction="SHA512" hashValue="%(hash)s" size="%(size)s"/> |
58 </update> | 64 </update> |
59 </updates>""" | 65 </updates>""" |
60 | 66 |
61 ### methods for request handler | 67 ### methods for request handler |
62 | 68 |
63 @classmethod | 69 @classmethod |
64 def match(cls, request): | 70 def match(cls, request): |
65 return request.method == 'GET' | 71 return request.method == 'GET' |
66 | 72 |
67 def __call__(self): | 73 def __call__(self): |
74 | |
75 update_path = os.path.join(self.app.directory, self.app.current_update) | |
68 body = self.body | 76 body = self.body |
69 query = {} | 77 query = {} |
70 dogfood_id = self.request.GET.get('dogfood_id') | 78 dogfood_id = self.request.GET.get('dogfood_id') |
71 if dogfood_id: | 79 if dogfood_id: |
72 query['dogfooding_prerelease_id'] = dogfood_id | 80 query['dogfooding_prerelease_id'] = dogfood_id |
81 application = self.app.updates[self.app.current_update] | |
82 query['build_id'] = application.build_id | |
83 query['version'] = application.version | |
73 | 84 |
74 # build query string | 85 # build query string |
75 if query: | 86 if query: |
76 query = '?' + '&'.join(['%s=%s' % (key, value) for key, value in query.items()]) | 87 query = '?' + '&'.join(['%s=%s' % (key, value) for key, value in query.items()]) |
77 else: | 88 else: |
78 query = '' | 89 query = '' |
79 | 90 |
91 # compute the hash | |
92 with file(update_path) as f: | |
93 sha512 = hashlib.sha512(f.read()).hexdigest() | |
94 | |
80 # template variables | 95 # template variables |
81 variables = dict(query=query) | 96 variables = dict(update=self.app.current_update, |
97 size=os.path.getsize(update_path), | |
98 hash=sha512, | |
99 query=query) | |
82 | 100 |
83 return Response(content_type='text/xml', | 101 return Response(content_type='text/xml', |
84 body=body % variables) | 102 body=body % variables) |
85 | 103 |
86 class Dispatcher(object): | 104 class Dispatcher(object): |
94 | 112 |
95 # set defaults | 113 # set defaults |
96 for key in self.defaults: | 114 for key in self.defaults: |
97 setattr(self, key, kw.get(key, self.defaults[key])) | 115 setattr(self, key, kw.get(key, self.defaults[key])) |
98 self.handlers = [ Get ] | 116 self.handlers = [ Get ] |
117 | |
118 # cache | |
99 self.updates = {} | 119 self.updates = {} |
100 self.current_update = None | 120 self.current_update = None |
101 self.current_stamp = '0000-00-00_000000' | 121 self.current_stamp = '0000-00-00_000000' |
122 self.cached_response = None | |
102 | 123 |
103 # scan directory | 124 # scan directory |
104 self.scan() | 125 self.scan() |
126 assert self.current_update # ensure there is at least one update | |
105 | 127 |
106 def __call__(self, environ, start_response): | 128 def __call__(self, environ, start_response): |
107 """WSGI application""" | 129 """WSGI application""" |
108 | 130 |
109 request = Request(environ) | 131 request = Request(environ) |
132 new = self.scan() | |
133 if (not new) and (self.cached_response is not None): | |
134 return self.cached_response(environ, start_response) | |
110 for h in self.handlers: | 135 for h in self.handlers: |
111 if h.match(request): | 136 if h.match(request): |
112 handler = h(request) | 137 handler = h(self, request) |
138 res = handler() | |
139 self.cached_response = res | |
113 break | 140 break |
114 else: | 141 else: |
115 handler = exc.HTTPNotFound | 142 res = exc.HTTPNotFound() |
116 res = handler() | 143 |
117 return res(environ, start_response) | 144 return res(environ, start_response) |
118 | 145 |
119 def scan(self): | 146 def scan(self): |
120 """scan the directory for updates""" | 147 """ |
148 scan the directory for updates | |
149 returns True if new updates are found, False otherwise | |
150 """ | |
121 prefix = 'b2g_update_' | 151 prefix = 'b2g_update_' |
122 suffix = '.mar' | 152 suffix = '.mar' |
123 contents = [i for i in os.listdir(self.directory) | 153 contents = [i for i in os.listdir(self.directory) |
124 if i.startswith(prefix) and i.endswith(suffix)] | 154 if i.startswith(prefix) and i.endswith(suffix)] |
125 contents = set(contents) | 155 contents = set(contents) |
126 new = contents.difference(self.updates.keys()) | 156 new = contents.difference(self.updates.keys()) |
127 if not new: | 157 if not new: |
128 # directory contents unchanged from cached values | 158 # directory contents unchanged from cached values |
129 return | 159 return False |
130 | 160 |
131 for update in new: | 161 for update in new: |
132 stamp = update[len(prefix):-len(suffix)] | 162 stamp = update[len(prefix):-len(suffix)] |
133 application_ini = 'application_%s.ini' % stamp | 163 application_ini = 'application_%s.ini' % stamp |
134 application_ini = os.path.join(self.directory, application_ini) | 164 application_ini = os.path.join(self.directory, application_ini) |
136 self.updates[update] = Application(application_ini) | 166 self.updates[update] = Application(application_ini) |
137 if stamp > self.current_stamp: | 167 if stamp > self.current_stamp: |
138 self.current_update = update | 168 self.current_update = update |
139 self.current_stamp = stamp | 169 self.current_stamp = stamp |
140 | 170 |
171 # TODO: could remove old files from the cache if not found in contents | |
172 | |
173 return True | |
174 | |
141 def main(args=sys.argv[1:]): | 175 def main(args=sys.argv[1:]): |
142 """CLI entry point""" | 176 """CLI entry point""" |
143 | 177 |
144 # imports for CLI | 178 # imports for CLI |
145 import optparse | 179 import optparse |