Chromium Code Reviews| 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 |