15f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// found in the LICENSE file.
45f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)package org.chromium.closure.compiler;
65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import com.google.common.collect.Lists;
86e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)import com.google.javascript.jscomp.ChromePassConfig;
95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import com.google.javascript.jscomp.CommandLineRunner;
105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import com.google.javascript.jscomp.CompilerOptions;
115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import org.kohsuke.args4j.CmdLineException;
135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import org.kohsuke.args4j.CmdLineParser;
145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import org.kohsuke.args4j.Option;
155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import java.io.BufferedReader;
175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import java.io.ByteArrayOutputStream;
185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import java.io.FileInputStream;
195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import java.io.IOException;
205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import java.io.InputStreamReader;
215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import java.io.PrintStream;
225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import java.util.ArrayList;
235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import java.util.Collections;
245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import java.util.List;
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import java.util.concurrent.Callable;
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import java.util.concurrent.ExecutorService;
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import java.util.concurrent.Executors;
285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import java.util.concurrent.Future;
295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import java.util.regex.Matcher;
305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import java.util.regex.Pattern;
315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)/**
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * Prepares and executes several instances of the closure compiler.
345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) */
355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)public class Runner {
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    protected final Flags flags = new Flags();
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    private final PrintStream err;
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    private boolean isConfigValid;
395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    public Runner(String[] args, PrintStream err) {
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        this.err = err;
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        List<String> argList = processArgs(args);
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        CmdLineParser parser = new CmdLineParser(flags);
445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        isConfigValid = true;
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        try {
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            parser.parseArgument(argList.toArray(new String[] {}));
475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if (flags.compilerArgsFile == null) {
485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                isConfigValid = false;
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            }
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        } catch (CmdLineException e) {
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            err.println(e.getMessage());
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            isConfigValid = false;
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (!isConfigValid) {
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            parser.printUsage(err);
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    private List<String> processArgs(String[] args) {
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        Pattern argPattern = Pattern.compile("(--[a-zA-Z_]+)=(.*)");
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        Pattern quotesPattern = Pattern.compile("^['\"](.*)['\"]$");
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        List<String> processedArgs = Lists.newArrayList();
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        for (String arg : args) {
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            Matcher matcher = argPattern.matcher(arg);
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if (matcher.matches()) {
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                processedArgs.add(matcher.group(1));
695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                String value = matcher.group(2);
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                Matcher quotesMatcher = quotesPattern.matcher(value);
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                if (quotesMatcher.matches()) {
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    processedArgs.add(quotesMatcher.group(1));
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                } else {
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    processedArgs.add(value);
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                }
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            } else {
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                processedArgs.add(arg);
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            }
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return processedArgs;
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    private boolean shouldRunCompiler() {
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return isConfigValid;
875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    protected void logError(String message, Exception e) {
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        err.println("ERROR: " + message);
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (e != null) {
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            e.printStackTrace(err);
935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    private void run() {
975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        List<CompilerInstanceDescriptor> descriptors = getDescriptors();
985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (descriptors == null) {
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return;
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        ExecutorService executor = Executors.newFixedThreadPool(
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                Math.min(descriptors.size(), Runtime.getRuntime().availableProcessors() / 2 + 1));
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        try {
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            runWithExecutor(descriptors, executor);
1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        } finally {
1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            executor.shutdown();
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }
1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    private void runWithExecutor(
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            List<CompilerInstanceDescriptor> descriptors, ExecutorService executor) {
1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        List<Future<CompilerRunner>> futures = new ArrayList<>(descriptors.size());
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        for (CompilerInstanceDescriptor descriptor : descriptors) {
1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            CompilerRunner task = new CompilerRunner(descriptor, new ByteArrayOutputStream(512));
1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            futures.add(executor.submit(task));
1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        for (Future<CompilerRunner> future : futures) {
1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            try {
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                CompilerRunner task = future.get();
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                task.errStream.flush();
1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                //System.err.println("@@ START_MODULE:" + task.descriptor.moduleName + " @@");
1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                System.err.println(task.errStream.toString("UTF-8"));
1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                //System.err.println("@@ END_MODULE @@");
1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                if (task.result != 0) {
1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    System.exit(task.result);
1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                }
1315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            } catch (Exception e) {
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                System.err.println("ERROR: " + e.getMessage());
1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                System.exit(1);
1345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            }
1355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }
1365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        System.exit(0);
1375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    private List<CompilerInstanceDescriptor> getDescriptors() {
1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        List<CompilerInstanceDescriptor> result = new ArrayList<>();
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        try (BufferedReader reader = new BufferedReader(
1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                new InputStreamReader(
1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                        new FileInputStream(flags.compilerArgsFile), "UTF-8"))) {
1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            int lineIndex = 0;
1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            while (true) {
1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                ++lineIndex;
1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                String line = reader.readLine();
1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                if (line == null) {
1495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    break;
1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                }
1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                if (line.length() == 0) {
1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    continue;
1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                }
1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                String[] moduleAndArgs = line.split(" +", 2);
1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                if (moduleAndArgs.length != 2) {
1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    logError(String.format(
1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            "Line %d does not contain module name and compiler arguments",
1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            lineIndex), null);
1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    continue;
1605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                }
1615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                result.add(new CompilerInstanceDescriptor(moduleAndArgs[0], moduleAndArgs[1]));
1625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            }
1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        } catch (IOException e) {
1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            logError("Failed to read compiler arguments file", e);
1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return null;
1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }
1675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return result;
1695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
1705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    public static void main(String[] args) {
1725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        Runner runner = new Runner(args, System.err);
1735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (runner.shouldRunCompiler()) {
1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            runner.run();
1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        } else {
1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            System.exit(-1);
1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }
1785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
1795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    private static class LocalCommandLineRunner extends CommandLineRunner {
1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        protected LocalCommandLineRunner(String[] args, PrintStream out, PrintStream err) {
1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            super(args, out, err);
1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }
1845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        @Override
1865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        protected CompilerOptions createOptions() {
1875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            CompilerOptions options = super.createOptions();
1885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            options.setIdeMode(true);
1895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            options.setExtraAnnotationNames(Collections.singletonList("suppressReceiverCheck"));
1905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return options;
1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }
1925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        @Override
1945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        protected void setRunOptions(CompilerOptions options)
1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                throws FlagUsageException, IOException {
1965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            super.setRunOptions(options);
1975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            options.setCodingConvention(new ChromeCodingConvention());
1986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)            getCompiler().setPassConfig(new ChromePassConfig(options));
1995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }
2005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        int execute() {
2025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            int result = 0;
2035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            int runs = 1;
2045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            try {
2055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                for (int i = 0; i < runs && result == 0; i++) {
2065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    result = doRun();
2075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                }
2085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            } catch (Throwable t) {
2095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                t.printStackTrace();
2105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                result = -2;
2115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            }
2125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return result;
2135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }
2145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
2155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    private static class CompilerRunner implements Callable<CompilerRunner> {
2175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        private final CompilerInstanceDescriptor descriptor;
2185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        private final ByteArrayOutputStream errStream;
2195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        private int result;
2205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        public CompilerRunner(
2225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                CompilerInstanceDescriptor descriptor, ByteArrayOutputStream errStream) {
2235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            this.descriptor = descriptor;
2245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            this.errStream = errStream;
2255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }
2265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        @Override
2285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        public CompilerRunner call() throws Exception {
2295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            PrintStream errPrintStream = new PrintStream(errStream, false, "UTF-8");
2305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            LocalCommandLineRunner runner =
2315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    new LocalCommandLineRunner(prepareArgs(), System.out, errPrintStream);
2325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if (!runner.shouldRunCompiler()) {
2335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                this.result = -1;
2345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            }
2355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            this.result = runner.execute();
2365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return this;
2375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }
2385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        private String[] prepareArgs() {
2405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            // FIXME: This does not support quoted arguments.
2415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return descriptor.commandLine.split(" +");
2425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }
2435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
2445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    private static class Flags {
2465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        @Option(name = "--compiler-args-file",
2475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                usage = "Full path to file containing compiler arguments (one line per instance)")
2485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        private String compilerArgsFile = null;
2495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
2505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    private static class CompilerInstanceDescriptor {
2525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        private final String moduleName;
2535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        private final String commandLine;
2545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        public CompilerInstanceDescriptor(String moduleName, String commandLine) {
2565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            this.moduleName = moduleName;
2575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            this.commandLine = commandLine;
2585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }
2595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
2605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
261