Mercurial > mozilla > hg > dogfood
annotate 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 |
rev | line source |
---|---|
1 | 1 #!/usr/bin/env python |
2 | |
0 | 3 """ |
1 | 4 dogdish |
7
65d0a1153864
a stub that sorta does something
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
5 https://bugzilla.mozilla.org/show_bug.cgi?id=800118 |
0 | 6 """ |
7 | |
12
234c2427e52b
beginnings of a scan function
Jeff Hammel <jhammel@mozilla.com>
parents:
11
diff
changeset
|
8 import fnmatch |
14 | 9 import hashlib |
8 | 10 import os |
4 | 11 import sys |
0 | 12 from urlparse import urlparse |
4 | 13 from webob import Request |
0 | 14 from webob import Response, exc |
11 | 15 from ConfigParser import RawConfigParser as ConfigParser |
0 | 16 |
8 | 17 here = os.path.dirname(os.path.abspath(__file__)) |
18 | |
11 | 19 |
20 class Application(object): | |
21 """class for storing application.ini data""" | |
22 | |
23 def __init__(self, filename): | |
24 """ | |
25 - filename : path to an application.ini file | |
26 """ | |
14 | 27 config = ConfigParser() |
28 config.read(filename) | |
29 self.build_id = config.get('App', 'BuildID') | |
30 self.version = config.get('App', 'Version') | |
11 | 31 |
32 ### request handlers | |
33 | |
0 | 34 class Handler(object): |
9 | 35 """abstract handler object for a request""" |
1 | 36 |
14 | 37 def __init__(self, app, request): |
38 self.app = app | |
0 | 39 self.request = request |
40 self.application_path = urlparse(request.application_url)[2] | |
41 | |
42 def link(self, path=(), permanant=False): | |
43 if isinstance(path, basestring): | |
44 path = [ path ] | |
45 path = [ i.strip('/') for i in path ] | |
46 if permanant: | |
47 application_url = [ self.request.application_url ] | |
48 else: | |
49 application_url = [ self.application_path ] | |
50 path = application_url + path | |
51 return '/'.join(path) | |
52 | |
53 def redirect(self, location): | |
54 raise exc.HTTPSeeOther(location=location) | |
55 | |
56 class Get(Handler): | |
9 | 57 """handle GET requests""" |
0 | 58 |
9 | 59 # template for response body |
0 | 60 body = """<?xml version="1.0"?> |
61 <updates> | |
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"> | |
14 | 63 <patch type="complete" URL="http://update.boot2gecko.org/nightly/%(update)s%(query)s" hashFunction="SHA512" hashValue="%(hash)s" size="%(size)s"/> |
0 | 64 </update> |
65 </updates>""" | |
66 | |
9 | 67 ### methods for request handler |
68 | |
0 | 69 @classmethod |
70 def match(cls, request): | |
71 return request.method == 'GET' | |
72 | |
73 def __call__(self): | |
14 | 74 |
75 update_path = os.path.join(self.app.directory, self.app.current_update) | |
7
65d0a1153864
a stub that sorta does something
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
76 body = self.body |
65d0a1153864
a stub that sorta does something
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
77 query = {} |
65d0a1153864
a stub that sorta does something
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
78 dogfood_id = self.request.GET.get('dogfood_id') |
65d0a1153864
a stub that sorta does something
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
79 if dogfood_id: |
12
234c2427e52b
beginnings of a scan function
Jeff Hammel <jhammel@mozilla.com>
parents:
11
diff
changeset
|
80 query['dogfooding_prerelease_id'] = dogfood_id |
14 | 81 application = self.app.updates[self.app.current_update] |
82 query['build_id'] = application.build_id | |
83 query['version'] = application.version | |
7
65d0a1153864
a stub that sorta does something
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
84 |
65d0a1153864
a stub that sorta does something
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
85 # build query string |
65d0a1153864
a stub that sorta does something
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
86 if query: |
14 | 87 query = '?' + '&'.join(['%s=%s' % (key, value) for key, value in query.items()]) |
7
65d0a1153864
a stub that sorta does something
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
88 else: |
65d0a1153864
a stub that sorta does something
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
89 query = '' |
65d0a1153864
a stub that sorta does something
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
90 |
14 | 91 # compute the hash |
92 with file(update_path) as f: | |
93 sha512 = hashlib.sha512(f.read()).hexdigest() | |
94 | |
12
234c2427e52b
beginnings of a scan function
Jeff Hammel <jhammel@mozilla.com>
parents:
11
diff
changeset
|
95 # template variables |
14 | 96 variables = dict(update=self.app.current_update, |
97 size=os.path.getsize(update_path), | |
98 hash=sha512, | |
99 query=query) | |
12
234c2427e52b
beginnings of a scan function
Jeff Hammel <jhammel@mozilla.com>
parents:
11
diff
changeset
|
100 |
1 | 101 return Response(content_type='text/xml', |
12
234c2427e52b
beginnings of a scan function
Jeff Hammel <jhammel@mozilla.com>
parents:
11
diff
changeset
|
102 body=body % variables) |
0 | 103 |
104 class Dispatcher(object): | |
9 | 105 """web application""" |
106 | |
0 | 107 |
108 ### class level variables | |
8 | 109 defaults = {'directory': here} |
0 | 110 |
111 def __init__(self, **kw): | |
11 | 112 |
113 # set defaults | |
0 | 114 for key in self.defaults: |
115 setattr(self, key, kw.get(key, self.defaults[key])) | |
116 self.handlers = [ Get ] | |
14 | 117 |
118 # cache | |
11 | 119 self.updates = {} |
120 self.current_update = None | |
13
71f9f68986b5
directory scanning + caching
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
121 self.current_stamp = '0000-00-00_000000' |
14 | 122 self.cached_response = None |
0 | 123 |
11 | 124 # scan directory |
125 self.scan() | |
14 | 126 assert self.current_update # ensure there is at least one update |
11 | 127 |
0 | 128 def __call__(self, environ, start_response): |
11 | 129 """WSGI application""" |
130 | |
0 | 131 request = Request(environ) |
14 | 132 new = self.scan() |
133 if (not new) and (self.cached_response is not None): | |
134 return self.cached_response(environ, start_response) | |
0 | 135 for h in self.handlers: |
136 if h.match(request): | |
14 | 137 handler = h(self, request) |
138 res = handler() | |
139 self.cached_response = res | |
0 | 140 break |
141 else: | |
14 | 142 res = exc.HTTPNotFound() |
143 | |
0 | 144 return res(environ, start_response) |
145 | |
11 | 146 def scan(self): |
14 | 147 """ |
148 scan the directory for updates | |
149 returns True if new updates are found, False otherwise | |
150 """ | |
13
71f9f68986b5
directory scanning + caching
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
151 prefix = 'b2g_update_' |
71f9f68986b5
directory scanning + caching
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
152 suffix = '.mar' |
12
234c2427e52b
beginnings of a scan function
Jeff Hammel <jhammel@mozilla.com>
parents:
11
diff
changeset
|
153 contents = [i for i in os.listdir(self.directory) |
13
71f9f68986b5
directory scanning + caching
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
154 if i.startswith(prefix) and i.endswith(suffix)] |
12
234c2427e52b
beginnings of a scan function
Jeff Hammel <jhammel@mozilla.com>
parents:
11
diff
changeset
|
155 contents = set(contents) |
234c2427e52b
beginnings of a scan function
Jeff Hammel <jhammel@mozilla.com>
parents:
11
diff
changeset
|
156 new = contents.difference(self.updates.keys()) |
234c2427e52b
beginnings of a scan function
Jeff Hammel <jhammel@mozilla.com>
parents:
11
diff
changeset
|
157 if not new: |
234c2427e52b
beginnings of a scan function
Jeff Hammel <jhammel@mozilla.com>
parents:
11
diff
changeset
|
158 # directory contents unchanged from cached values |
14 | 159 return False |
11 | 160 |
13
71f9f68986b5
directory scanning + caching
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
161 for update in new: |
71f9f68986b5
directory scanning + caching
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
162 stamp = update[len(prefix):-len(suffix)] |
71f9f68986b5
directory scanning + caching
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
163 application_ini = 'application_%s.ini' % stamp |
71f9f68986b5
directory scanning + caching
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
164 application_ini = os.path.join(self.directory, application_ini) |
71f9f68986b5
directory scanning + caching
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
165 assert os.path.exists(application_ini) |
71f9f68986b5
directory scanning + caching
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
166 self.updates[update] = Application(application_ini) |
71f9f68986b5
directory scanning + caching
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
167 if stamp > self.current_stamp: |
71f9f68986b5
directory scanning + caching
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
168 self.current_update = update |
71f9f68986b5
directory scanning + caching
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
169 self.current_stamp = stamp |
71f9f68986b5
directory scanning + caching
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
170 |
14 | 171 # TODO: could remove old files from the cache if not found in contents |
172 | |
173 return True | |
174 | |
0 | 175 def main(args=sys.argv[1:]): |
176 """CLI entry point""" | |
177 | |
11 | 178 # imports for CLI |
0 | 179 import optparse |
180 from wsgiref import simple_server | |
181 | |
11 | 182 # parse CLI options |
0 | 183 parser = optparse.OptionParser() |
184 parser.add_option('-p', '--port', dest='port', | |
185 default=8080, type='int', | |
186 help="port to serve on") | |
11 | 187 parser.add_option('-d', '--directory', dest='directory', |
188 default=os.getcwd(), | |
189 help="directory of update files") | |
0 | 190 options, args = parser.parse_args() |
191 | |
11 | 192 # create the app |
193 app = Dispatcher(directory=options.directory) | |
0 | 194 |
11 | 195 # serve the app |
7
65d0a1153864
a stub that sorta does something
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
196 print "http://localhost:%s/" % options.port |
0 | 197 server = simple_server.make_server(host='0.0.0.0', port=options.port, app=app) |
198 server.serve_forever() | |
199 | |
200 if __name__ == '__main__': | |
201 main() |