1#!/usr/bin/env python3 2 3from __future__ import print_function 4from __future__ import division 5from __future__ import absolute_import 6 7import common 8import sys, os, shutil, optparse, logging 9import six 10 11from autotest_lib.client.common_lib import error, utils 12from autotest_lib.client.common_lib import logging_config, logging_manager 13 14 15""" 16Compile All Autotest GWT Clients Living in autotest/frontend/client/src 17""" 18 19 20 21_AUTOTEST_DIR = common.autotest_dir 22_DEFAULT_GWT_DIRS = ['/usr/local/lib/gwt', '/opt/google-web-toolkit'] 23_DEFAULT_APP_DIR = os.path.join(_AUTOTEST_DIR, 'frontend/client') 24_DEFAULT_INSTALL_DIR = os.path.join(_DEFAULT_APP_DIR, 'www') 25_TMP_COMPILE_DIR = _DEFAULT_INSTALL_DIR + '.new' 26 27_COMPILE_LINE = ('java -Xmx512M %(extra_args)s ' 28 '-cp "%(app_dir)s/src:%(app_dir)s/bin:%(gwt_dir)s/gwt-user.jar' 29 ':%(gwt_dir)s/gwt-dev.jar" -Djava.awt.headless=true ' 30 'com.google.gwt.dev.Compiler -war "%(compile_dir)s" ' 31 '%(project_client)s') 32 33class CompileClientsLoggingConfig(logging_config.LoggingConfig): 34 def configure_logging(self, results_dir=None, verbose=False): 35 super(CompileClientsLoggingConfig, self).configure_logging( 36 use_console=True, 37 verbose=verbose) 38 39def enumerate_projects(): 40 """List projects in _DEFAULT_APP_DIR.""" 41 src_path = os.path.join(_DEFAULT_APP_DIR, 'src') 42 projects = {} 43 for project in os.listdir(src_path): 44 projects[project] = [] 45 project_path = os.path.join(src_path, project) 46 for file in os.listdir(project_path): 47 if file.endswith('.gwt.xml'): 48 projects[project].append(file[:-8]) 49 return projects 50 51 52def find_gwt_dir(): 53 """See if GWT is installed in site-packages or in the system, 54 site-packages is favored over a system install or a /usr/local install. 55 """ 56 site_gwt = os.path.join(_AUTOTEST_DIR, 'site-packages', 'gwt') 57 gwt_dirs = [site_gwt] + _DEFAULT_GWT_DIRS 58 59 for gwt_dir in gwt_dirs: 60 if os.path.isdir(gwt_dir): 61 return gwt_dir 62 logging.error('Unable to find GWT. ' 63 'You can use utils/build_externals.py to install it.') 64 sys.exit(1) 65 66 67def install_completed_client(compiled_dir, project_client): 68 """Remove old client directory if it exists, move installed client to the 69 old directory and move newly compield client to the installed client 70 dir. 71 @param compiled_dir: Where the new client was compiled 72 @param project_client: project.client pair e.g. autotest.AfeClient 73 @returns True if installation was successful or False if it failed 74 """ 75 tmp_client_dir = os.path.join(_TMP_COMPILE_DIR, project_client) 76 install_dir = os.path.join(_DEFAULT_INSTALL_DIR, project_client) 77 old_install_dir = os.path.join(_DEFAULT_INSTALL_DIR, 78 project_client + '.old') 79 if not os.path.exists(_DEFAULT_INSTALL_DIR): 80 os.mkdir(_DEFAULT_INSTALL_DIR) 81 82 if os.path.isdir(tmp_client_dir): 83 if os.path.isdir(old_install_dir): 84 shutil.rmtree(old_install_dir) 85 if os.path.isdir(install_dir): 86 os.rename(install_dir, old_install_dir) 87 try: 88 os.rename(tmp_client_dir, install_dir) 89 return True 90 except Exception as err: 91 # If we can't rename the client raise an exception 92 # and put the old client back 93 shutil.rmtree(install_dir) 94 shutil.copytree(old_install_dir, install_dir) 95 logging.error('Copying old client: %s', err) 96 else: 97 logging.error('Compiled directory is gone, something went wrong') 98 99 return False 100 101 102def compile_and_install_client(project_client, extra_args='', 103 install_client=True): 104 """Compile the client into a temporary directory, if successful 105 call install_completed_client to install the new client. 106 @param project_client: project.client pair e.g. autotest.AfeClient 107 @param install_client: Boolean, if True install the clients 108 @return True if install and compile was successful False if it failed 109 """ 110 java_args = {} 111 java_args['compile_dir'] = _TMP_COMPILE_DIR 112 java_args['app_dir'] = _DEFAULT_APP_DIR 113 java_args['gwt_dir'] = find_gwt_dir() 114 java_args['extra_args'] = extra_args 115 java_args['project_client'] = project_client 116 cmd = _COMPILE_LINE % java_args 117 118 logging.info('Compiling client %s', project_client) 119 try: 120 utils.run(cmd, verbose=True) 121 if install_client: 122 return install_completed_client(java_args['compile_dir'], 123 project_client) 124 return True 125 except error.CmdError: 126 logging.error('Error compiling %s, leaving old client', project_client) 127 128 return False 129 130 131def compile_all_projects(extra_args=''): 132 """Compile all projects available as defined by enumerate_projects. 133 @returns list of failed client installations 134 """ 135 failed_clients = [] 136 for project,clients in six.iteritems(enumerate_projects()): 137 for client in clients: 138 project_client = '%s.%s' % (project, client) 139 if not compile_and_install_client(project_client, extra_args): 140 failed_clients.append(project_client) 141 142 return failed_clients 143 144 145def print_projects(): 146 logging.info('Projects that can be compiled:') 147 for project,clients in six.iteritems(enumerate_projects()): 148 for client in clients: 149 logging.info('%s.%s', project, client) 150 151 152def main(): 153 logging_manager.configure_logging(CompileClientsLoggingConfig(), 154 verbose=True) 155 parser = optparse.OptionParser() 156 parser.add_option('-l', '--list-projects', 157 action='store_true', dest='list_projects', 158 default=False, 159 help='List all projects and clients that can be compiled') 160 parser.add_option('-a', '--compile-all', 161 action='store_true', dest='compile_all', 162 default=False, 163 help='Compile all available projects and clients') 164 parser.add_option('-c', '--compile', 165 dest='compile_list', action='store', 166 help='List of clients to compiled (e.g. -c "x.X c.C")') 167 parser.add_option('-e', '--extra-args', 168 dest='extra_args', action='store', 169 default='', 170 help='Extra arguments to pass to java') 171 parser.add_option('-d', '--no-install', dest='install_client', 172 action='store_false', default=True, 173 help='Do not install the clients just compile them') 174 options, args = parser.parse_args() 175 176 if len(sys.argv) < 2: 177 parser.print_help() 178 sys.exit(0) 179 elif options.list_projects: 180 print_projects() 181 sys.exit(0) 182 elif options.compile_all and options.compile_list: 183 logging.error('Options -c and -a are mutually exclusive') 184 parser.print_help() 185 sys.exit(1) 186 187 failed_clients = [] 188 if options.compile_all: 189 failed_clients = compile_all_projects(options.extra_args) 190 elif options.compile_list: 191 for client in options.compile_list.split(): 192 if not compile_and_install_client(client, options.extra_args, 193 options.install_client): 194 failed_clients.append(client) 195 196 if os.path.exists(_TMP_COMPILE_DIR): 197 shutil.rmtree(_TMP_COMPILE_DIR) 198 199 if failed_clients: 200 logging.error('The following clients failed: %s', 201 '\n'.join(failed_clients)) 202 sys.exit(1) 203 204 205if __name__ == '__main__': 206 main() 207