OLD | NEW |
---|---|
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 | 2 |
3 # Copyright (c) 2009-2010 The Chromium OS Authors. All rights reserved. | 3 # Copyright (c) 2009-2010 The Chromium OS Authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
7 """A CherryPy-based webserver to host images and build packages.""" | 7 """A CherryPy-based webserver to host images and build packages.""" |
8 | 8 |
9 import cherrypy | 9 import cherrypy |
10 import optparse | 10 import optparse |
11 import os | 11 import os |
12 import subprocess | |
12 import sys | 13 import sys |
13 | 14 |
14 import autoupdate | 15 import autoupdate |
15 | 16 |
16 CACHED_ENTRIES=12 | 17 CACHED_ENTRIES=12 |
17 | 18 |
18 # Sets up global to share between classes. | 19 # Sets up global to share between classes. |
19 global updater | 20 global updater |
20 updater = None | 21 updater = None |
21 | 22 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
62 if image_dir != os.readlink('static/archive'): | 63 if image_dir != os.readlink('static/archive'): |
63 cherrypy.log('removing stale symlink to %s' % image_dir, 'DEVSERVER') | 64 cherrypy.log('removing stale symlink to %s' % image_dir, 'DEVSERVER') |
64 os.unlink('static/archive') | 65 os.unlink('static/archive') |
65 os.symlink(image_dir, 'static/archive') | 66 os.symlink(image_dir, 'static/archive') |
66 else: | 67 else: |
67 os.symlink(image_dir, 'static/archive') | 68 os.symlink(image_dir, 'static/archive') |
68 cherrypy.log('archive dir: %s ready to be used to serve images.' % image_dir, | 69 cherrypy.log('archive dir: %s ready to be used to serve images.' % image_dir, |
69 'DEVSERVER') | 70 'DEVSERVER') |
70 | 71 |
71 | 72 |
72 class DevServerRoot: | 73 def _OutputOf(command): |
74 """Runs command, a list of arguments beginning with an executable. | |
75 | |
76 If the executable begins with "scripts/", the path is adjusted to | |
77 the scripts directory of this chroot. | |
78 | |
79 Args: | |
80 A list of arguments, beginning with the executable | |
81 Returns: | |
82 A list of lines returned by the command | |
83 """ | |
84 | |
sosa
2011/01/14 23:03:54
Don't need this extra line
rochberg
2011/01/15 06:16:48
Done.
| |
85 scripts = 'scripts/' | |
86 if command[0].find(scripts) == 0: | |
87 command[0] = command[0].replace(scripts, '../../' + scripts) | |
88 cherrypy.log('Executing: ' + ' '.join(command), 'BUILD') | |
89 output_blob = subprocess.Popen(command, | |
90 stdout=subprocess.PIPE).communicate()[0] | |
91 return [line.rstrip() for line in output_blob.split('\n')] | |
92 | |
sosa
2011/01/14 23:03:54
2 lines between top level defs
| |
93 def _IsIn(needle, haystack_list): | |
sosa
2011/01/14 23:03:54
Isn't this equivalent to needle in haystick_list?
rochberg
2011/01/15 06:16:48
The way the code is structured now, the relevant t
| |
94 for line in haystack_list: | |
95 if needle in line: | |
96 return True | |
97 return False | |
98 | |
sosa
2011/01/14 23:03:54
2 lines between top level defs
rochberg
2011/01/15 06:16:48
Done.
| |
99 class Builder(object): | |
sosa
2011/01/14 23:03:54
Should probably move this into its own module.
rochberg
2011/01/15 06:16:48
Done.
| |
100 def _ShouldBeWorkedOn(self, board, pkg): | |
101 """Is pkg a package that could be worked on, but is not?""" | |
102 if _IsIn(pkg, _OutputOf([ | |
103 'scripts/cros_workon', '--board=' + board, 'list'])): | |
104 return False | |
105 | |
106 # If it's in the list of possible workon targets, we should be working on it | |
107 return _IsIn(pkg, _OutputOf([ | |
108 'scripts/cros_workon', '--board=' + board, 'list', '--all'])) | |
109 | |
110 def SetError(self, text): | |
111 cherrypy.response.status = 500 | |
112 cherrypy.log(text, 'BUILD') | |
113 return text | |
114 | |
115 def Build(self, board, pkg, additional_args): | |
116 cherrypy.log('Additional build request arguments: '+ str(additional_args), | |
117 'BUILD') | |
118 | |
119 original_use = os.environ.get('USE', '') | |
120 if 'use' in additional_args: | |
121 os.environ['USE'] = original_use + ' ' + additional_args['use'] | |
122 cherrypy.log("USE flags modified to " + os.environ['USE'], 'BUILD') | |
123 | |
124 try: | |
125 if (self._ShouldBeWorkedOn(board, pkg) and | |
126 not additional_args.get('accept_stable')): | |
127 return self.SetError( | |
128 'Package is not cros_workon\'d on the devserver machine.\n' | |
129 'Either start working on the package or pass --accept_stable ' | |
130 'to gmerge') | |
131 | |
132 rc = subprocess.call(['emerge-%s' % board, pkg]) | |
133 if rc != 0: | |
134 return self.SetError('Could not emerge ' + pkg) | |
135 | |
136 cherrypy.log('ecleaning %s' % pkg, 'BUILD') | |
137 rc = subprocess.call(['eclean-' + board, '-d', 'packages']) | |
138 if rc != 0: | |
139 return self.SetError('eclean failed') | |
140 | |
141 cherrypy.log('eclean complete %s' % pkg, 'BUILD') | |
142 return 'Success\n' | |
143 | |
144 except OSError, e: | |
145 return self.SetError('Could not execute build command: ' + str(e)) | |
146 | |
147 finally: | |
148 os.environ['USE'] = original_use | |
149 | |
150 | |
151 class DevServerRoot(object): | |
73 """The Root Class for the Dev Server. | 152 """The Root Class for the Dev Server. |
74 | 153 |
75 CherryPy works as follows: | 154 CherryPy works as follows: |
76 For each method in this class, cherrpy interprets root/path | 155 For each method in this class, cherrpy interprets root/path |
77 as a call to an instance of DevServerRoot->method_name. For example, | 156 as a call to an instance of DevServerRoot->method_name. For example, |
78 a call to http://myhost/build will call build. CherryPy automatically | 157 a call to http://myhost/build will call build. CherryPy automatically |
79 parses http args and places them as keyword arguments in each method. | 158 parses http args and places them as keyword arguments in each method. |
80 For paths http://myhost/update/dir1/dir2, you can use *args so that | 159 For paths http://myhost/update/dir1/dir2, you can use *args so that |
81 cherrypy uses the update method and puts the extra paths in args. | 160 cherrypy uses the update method and puts the extra paths in args. |
82 """ | 161 """ |
83 | 162 |
84 def build(self, board, pkg): | 163 def __init__(self): |
164 self._builder = Builder() | |
165 | |
166 def build(self, board, pkg, **kwargs): | |
85 """Builds the package specified.""" | 167 """Builds the package specified.""" |
86 cherrypy.log('emerging %s' % pkg, 'BUILD') | 168 return self._builder.Build(board, pkg, kwargs) |
87 emerge_command = 'emerge-%s %s' % (board, pkg) | |
88 err = os.system(emerge_command) | |
89 if err != 0: | |
90 raise Exception('failed to execute %s' % emerge_command) | |
91 eclean_command = 'eclean-%s -d packages' % board | |
92 err = os.system(eclean_command) | |
93 if err != 0: | |
94 raise Exception('failed to execute %s' % emerge_command) | |
95 | 169 |
96 def index(self): | 170 def index(self): |
97 return 'Welcome to the Dev Server!' | 171 return 'Welcome to the Dev Server!' |
98 | 172 |
99 def update(self, *args): | 173 def update(self, *args): |
100 label = '/'.join(args) | 174 label = '/'.join(args) |
101 body_length = int(cherrypy.request.headers['Content-Length']) | 175 body_length = int(cherrypy.request.headers['Content-Length']) |
102 data = cherrypy.request.rfile.read(body_length) | 176 data = cherrypy.request.rfile.read(body_length) |
103 return updater.HandleUpdatePing(data, label) | 177 return updater.HandleUpdatePing(data, label) |
104 | 178 |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
208 # We don't run the dev server with this option. | 282 # We don't run the dev server with this option. |
209 if options.validate_factory_config: | 283 if options.validate_factory_config: |
210 sys.exit(0) | 284 sys.exit(0) |
211 elif options.pregenerate_update: | 285 elif options.pregenerate_update: |
212 if not updater.PreGenerateUpdate(): | 286 if not updater.PreGenerateUpdate(): |
213 sys.exit(1) | 287 sys.exit(1) |
214 | 288 |
215 # If the command line requested after setup, it's time to do it. | 289 # If the command line requested after setup, it's time to do it. |
216 if not options.exit: | 290 if not options.exit: |
217 cherrypy.quickstart(DevServerRoot(), config=_GetConfig(options)) | 291 cherrypy.quickstart(DevServerRoot(), config=_GetConfig(options)) |
OLD | NEW |