#!/usr/bin/python # -*- coding: utf-8 -*- import errno import os import subprocess import sys import tempfile import time def get_gradle_command_and_project_mtime(dir): """Find top-project gradlew or fallback to using gradle on sub-project dir. While iterating the paths, also check mtime on build.gradle files""" topdir = dir build_gradle = None gradlew = None mtime = -1 while True: test = os.path.join(topdir, 'build.gradle') if os.path.exists(test): if not build_gradle: build_gradle = test try: m = os.path.getmtime(test) if m > mtime: mtime = m except OSError: pass test = os.path.join(topdir, 'gradlew') if os.path.exists(test): gradlew = test break test = os.path.dirname(topdir) if test == topdir: break topdir = test if gradlew: cmd = [gradlew, '-p', topdir] elif build_gradle: cmd = ['gradle', '-p', os.path.dirname(build_gradle)] else: cmd = ['gradle'] return (cmd, mtime) def filter_source_files(files): """Remove any item not looking like a Java source file.""" return [f for f in files if f.endswith('.java')] def run_javac(encoding, source, target, bootcp, cp, files, output, args, sourcefile, outdir): """Execute javac with the given options.""" command = ['javac'] if encoding: command.extend(['-encoding', encoding]) if source: command.extend(['-source', source]) if target: command.extend(['-target', target]) if bootcp: command.extend(['-bootclasspath', bootcp]) if outdir: command.extend(['-d', outdir]) tmp = [] if output: tmp.append(output) if cp: tmp.extend(cp) if tmp: command.extend(['-cp', ':'.join(tmp)]) else: if cp: command.extend(['-cp', ':'.join(cp)]) if output: command.extend(['-d', output]) command.extend(args) command.append(sourcefile) if outdir: return subprocess.call(command) else: with tempfile.NamedTemporaryFile(mode='w') as f: command.append('@' + f.name) for source in filter_source_files(files): f.write(source) f.write('\n') f.flush() return subprocess.call(command) def file_in_list(needle, files): """Find needle in files and if so, return the list without needle. Otherwise return None.""" for i in range(0, len(files) - 1): if os.path.samefile(needle, files[i]): return files[0:i] + files[i + 1:] return None def figure_out_java_compilation(sessiondir, sourcefile, tempfile): """Get options for Java compilation from gradle project and run javac.""" (cmd, mtime) = get_gradle_command_and_project_mtime( os.path.dirname(sourcefile)) output = None if sessiondir != None: outdir = os.path.join(sessiondir, 'java_output') try: os.mkdir(outdir) except OSError as exc: if exc.errno != errno.EEXIST or not os.path.isdir(outdir): outdir = None pass cachefile = os.path.join(sessiondir, 'gradle_output') try: if os.path.getmtime(cachefile) >= mtime: with open(cachefile, 'r') as f: output = f.read() except (OSError, IOError): pass else: outdir = None if not output: cmd.extend(['-q', 'flycheckAndroidJava']) output = subprocess.check_output(cmd, universal_newlines=True) if sessiondir != None: try: with open(cachefile, 'w') as f: f.write(output) except IOError: pass output = output.split('\n') data = None for line in output: if line == '***': if data: files = file_in_list(sourcefile, data['files']) if files: return run_javac(data['encoding'], data['source'], data['target'], data['bootcp'], data['cp'], files, data['output'], data['args'], tempfile, outdir) data = {} elif data != None: if line.startswith('args='): data['args'] = line[6:-1].split(', ') elif line.startswith('encoding='): data['encoding'] = line[9:] elif line.startswith('bootcp='): data['bootcp'] = line[7:] elif line.startswith('cp='): data['cp'] = line[3:].split(':') elif line.startswith('source='): data['source'] = line[7:] elif line.startswith('target='): data['target'] = line[7:] elif line.startswith('files='): data['files'] = line[6:].split(':') elif line.startswith('output='): data['output'] = line[7:] if data: files = file_in_list(sourcefile, data['files']) if files: return run_javac(data['encoding'], data['source'], data['target'], data['bootcp'], data['cp'], files, data['output'], data['args'], tempfile, outdir) return 0 def main(argv): sessiondir = None if len(sys.argv) == 4: sessiondir = sys.argv[1] sourcefile = sys.argv[2] tempfile = sys.argv[3] elif len(sys.argv) == 3: sourcefile = sys.argv[1] tempfile = sys.argv[2] elif len(sys.argv) == 2: sourcefile = sys.argv[1] tempfile = sourcefile else: return -1 sourcefile = os.path.abspath(sourcefile) return figure_out_java_compilation(sessiondir, sourcefile, tempfile) sys.exit(main(sys.argv))