Create a compile script for our GWT clients. There are now 4 different bash
scripts to compile GWT clients. This has become unmaintainable and is a problem
when other scripts need to compile clients 
* automatically enumerate clients available
* Quick compile all
* Compile individual clients
* Do not replace current client if compile fails
* Move current client to an old directory for a backup of a known working client

Signed-off-by: Scott Zawalski <scottz@google.com>



git-svn-id: http://test.kernel.org/svn/autotest/trunk@3853 592f7852-d20e-0410-864c-8624ca9c26a4
diff --git a/utils/compile_gwt_clients.py b/utils/compile_gwt_clients.py
new file mode 100644
index 0000000..ca9d64b
--- /dev/null
+++ b/utils/compile_gwt_clients.py
@@ -0,0 +1,188 @@
+#!/usr/bin/python
+import sys, os, shutil, errno, optparse
+import common
+from autotest_lib.client.common_lib import error, utils
+"""
+Compile All Autotest GWT Clients Living in autotest/frontend/client/src
+"""
+
+_AUTOTEST_DIR = common.autotest_dir
+_DEFAULT_GWT_DIR = '/usr/local/lib/gwt'
+_DEFAULT_APP_DIR = os.path.join(_AUTOTEST_DIR, 'frontend/client')
+_DEFAULT_INSTALL_DIR = os.path.join(_DEFAULT_APP_DIR, 'www')
+_TMP_COMPILE_DIR = _DEFAULT_INSTALL_DIR + '.new'
+
+_COMPILE_LINE = ('java  -Xmx512M '
+                 '-cp "%(app_dir)s/src:%(app_dir)s/bin:%(gwt_dir)s/gwt-user.jar'
+                 ':%(gwt_dir)s/gwt-dev-linux.jar" '
+                 '-Djava.awt.headless=true com.google.gwt.dev.Compiler '
+                 '-war "%(compile_dir)s" %(extra_args)s %(project_client)s')
+
+
+def enumerate_projects():
+    """List projects in _DEFAULT_APP_DIR."""
+    src_path = os.path.join(_DEFAULT_APP_DIR, 'src')
+    projects = {}
+    for project in os.listdir(src_path):
+        projects[project] = []
+        project_path = os.path.join(src_path, project)
+        for file in os.listdir(project_path):
+            if file.endswith('.gwt.xml'):
+                projects[project].append(file[:-8])
+    return projects
+
+
+def find_gwt_dir():
+    """See if GWT is installed in site-packages or in the system,
+       site-packages is favored over a system install.
+    """
+    site_gwt = os.path.join(_AUTOTEST_DIR, 'site-packages', 'gwt')
+
+    if os.path.isdir(site_gwt):
+        return site_gwt
+
+    if not os.path.isdir(_DEFAULT_GWT_DIR):
+        print 'Error: Unable to find GWT, is GWT installed?\n'
+        sys.exit(1)
+
+    return _DEFAULT_GWT_DIR
+
+
+def install_completed_client(compiled_dir, project_client):
+    """Remove old client directory if it exists,  move installed client to the
+       old directory and move newly compield client to the installed client
+       dir.
+       @param compiled_dir: Where the new client was compiled
+       @param project_client: project.client pair e.g. autotest.AfeClient
+       @returns True if installation was successful or False if it failed
+    """
+    tmp_client_dir = os.path.join(_TMP_COMPILE_DIR, project_client)
+    install_dir = os.path.join(_DEFAULT_INSTALL_DIR, project_client)
+    old_install_dir = os.path.join(_DEFAULT_INSTALL_DIR,
+                                   project_client + '.old')
+    if not os.path.exists(_DEFAULT_INSTALL_DIR):
+        os.mkdir(_DEFAULT_INSTALL_DIR)
+
+    if os.path.isdir(tmp_client_dir):
+        if os.path.isdir(old_install_dir):
+            shutil.rmtree(old_install_dir)
+        if os.path.isdir(install_dir):
+            os.rename(install_dir, old_install_dir)
+        try:
+            os.rename(tmp_client_dir, install_dir)
+            return True
+        except Exception, err:
+            # If we can't rename the client raise an exception
+            # and put the old client back
+            shutil.rmtree(install_dir)
+            shutil.copytree(old_install_dir, install_dir)
+            print 'Error: copying old client:', err
+    else:
+        print 'Error: Compiled directory is gone, something went wrong'
+
+    return False
+
+
+def compile_and_install_client(project_client, extra_args='',
+                               install_client=True):
+    """Compile the client into a temporary directory, if successful
+       call install_completed_client to install the new client.
+       @param project_client: project.client pair e.g. autotest.AfeClient
+       @param install_client: Boolean, if True install the clients
+       @return True if install and compile was successful False if it failed
+    """
+    java_args = {}
+    java_args['compile_dir'] = _TMP_COMPILE_DIR
+    java_args['app_dir'] = _DEFAULT_APP_DIR
+    java_args['gwt_dir'] = find_gwt_dir()
+    java_args['extra_args'] = extra_args
+    java_args['project_client'] = project_client
+    cmd = _COMPILE_LINE % java_args
+
+    print 'Compiling client %s' % project_client
+    try:
+        utils.run(cmd, verbose=True)
+        if not install_client:
+            return install_completed_client(java_args['compile_dir'],
+                                            project_client)
+        return True
+    except error.CmdError:
+        print 'Error compiling %s, leaving old client' % project_client
+
+    return False
+
+
+def compile_all_projects(projects, extra_args=''):
+    """Compile all projects available as defined by enumerate_projects.
+       @returns list of failed client installations
+    """
+    failed_clients = []
+    for project,clients in enumerate_projects().iteritems():
+        for client in clients:
+            project_client = '%s.%s' % (project, client)
+            if not compile_and_install_client(project_client, extra_args):
+                failed_clients.append(project_client)
+
+    return failed_clients
+
+
+def print_projects():
+    print 'Projects that can be compiled:'
+    for project,clients in enumerate_projects().iteritems():
+        for client in clients:
+            print '%s.%s' % (project, client)
+
+
+def main():
+    parser = optparse.OptionParser()
+    parser.add_option('-l', '--list-projects',
+                      action='store_true', dest='list_projects',
+                      default=False,
+                      help='List all projects and clients that can be compiled')
+    parser.add_option('-a', '--compile-all',
+                      action='store_true', dest='compile_all',
+                     default=False,
+                     help='Compile all available projects and clients')
+    parser.add_option('-c', '--compile',
+                      dest='compile_list', action='store',
+                      help='List of clients to compiled (e.g. -c "x.X c.C")')
+    parser.add_option('-e', '--extra-args',
+                      dest='extra_args', action='store',
+                      default='',
+                      help='Extra arguments to pass to java')
+    parser.add_option('-d', '--no-install', dest='no_install',
+                      action='store_true', default=False,
+                      help='Do not install the clients just compile them')
+    options, args = parser.parse_args()
+
+    if len(sys.argv) < 2:
+        parser.print_help()
+        sys.exit(0)
+    elif options.list_projects:
+        print_projects()
+        sys.exit(0)
+    elif options.compile_all and options.compile_list:
+        print '-c and -a are mutually exclusive'
+        parser.print_help()
+        sys.exit(1)
+
+    failed_clients = []
+    if options.compile_all:
+        failed_clients = compile_all_projects(options.extra_args)
+    elif options.compile_list:
+        for client in options.compile_list.split():
+            if not compile_and_install_client(client, options.extra_args,
+                                              options.no_install):
+                failed_clients.append(client)
+
+    if os.path.exists(_TMP_COMPILE_DIR):
+        shutil.rmtree(_TMP_COMPILE_DIR)
+
+    if failed_clients:
+        print ('Error: The following clients failed: %s'
+               % '\n'.join(failed_clients))
+        sys.exit(1)
+
+
+if __name__ == '__main__':
+    main()