cmdline/tool/src/org/netbeans/modules/jackpot30/cmdline/Main.java
author jlahoda
Sun, 12 Feb 2017 10:11:52 +0100
changeset 1041 b03a880d538e
parent 1016 02ad9fe4588c
permissions -rw-r--r--
Adding ability to run (custom) tests.
jlahoda@480
     1
/*
jlahoda@480
     2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
jlahoda@480
     3
 *
jlahoda@717
     4
 * Copyright 2010-2011 Sun Microsystems, Inc. All rights reserved.
jlahoda@480
     5
 *
jlahoda@480
     6
 * The contents of this file are subject to the terms of either the GNU
jlahoda@480
     7
 * General Public License Version 2 only ("GPL") or the Common
jlahoda@480
     8
 * Development and Distribution License("CDDL") (collectively, the
jlahoda@480
     9
 * "License"). You may not use this file except in compliance with the
jlahoda@480
    10
 * License. You can obtain a copy of the License at
jlahoda@480
    11
 * http://www.netbeans.org/cddl-gplv2.html
jlahoda@480
    12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
jlahoda@480
    13
 * specific language governing permissions and limitations under the
jlahoda@480
    14
 * License.  When distributing the software, include this License Header
jlahoda@480
    15
 * Notice in each file and include the License file at
jlahoda@480
    16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
jlahoda@480
    17
 * particular file as subject to the "Classpath" exception as provided
jlahoda@480
    18
 * by Sun in the GPL Version 2 section of the License file that
jlahoda@480
    19
 * accompanied this code. If applicable, add the following below the
jlahoda@480
    20
 * License Header, with the fields enclosed by brackets [] replaced by
jlahoda@480
    21
 * your own identifying information:
jlahoda@480
    22
 * "Portions Copyrighted [year] [name of copyright owner]"
jlahoda@480
    23
 *
jlahoda@480
    24
 * If you wish your version of this file to be governed by only the CDDL
jlahoda@480
    25
 * or only the GPL Version 2, indicate your decision by adding
jlahoda@480
    26
 * "[Contributor] elects to include this software in this distribution
jlahoda@480
    27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
jlahoda@480
    28
 * single choice of license, a recipient has the option to distribute
jlahoda@480
    29
 * your version of this file under either the CDDL, the GPL Version 2 or
jlahoda@480
    30
 * to extend the choice of license to its licensees as provided above.
jlahoda@480
    31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
jlahoda@480
    32
 * Version 2 license, then the option applies only if the new code is
jlahoda@480
    33
 * made subject to such option by the copyright holder.
jlahoda@480
    34
 *
jlahoda@480
    35
 * Contributor(s):
jlahoda@480
    36
 *
jlahoda@717
    37
 * Portions Copyrighted 2010-2011 Sun Microsystems, Inc.
jlahoda@480
    38
 */
jlahoda@480
    39
jlahoda@480
    40
package org.netbeans.modules.jackpot30.cmdline;
jlahoda@480
    41
jlahoda@800
    42
import java.awt.BorderLayout;
jlahoda@800
    43
import java.awt.event.ActionEvent;
jlahoda@800
    44
import java.awt.event.ActionListener;
jlahoda@543
    45
import java.io.BufferedWriter;
jlahoda@480
    46
import java.io.File;
jlahoda@493
    47
import java.io.FileOutputStream;
jlahoda@480
    48
import java.io.IOException;
jlahoda@543
    49
import java.io.OutputStreamWriter;
jlahoda@494
    50
import java.io.PrintStream;
jlahoda@543
    51
import java.io.Writer;
jlahoda@800
    52
import java.lang.reflect.InvocationTargetException;
jlahoda@480
    53
import java.net.URL;
jlahoda@480
    54
import java.util.ArrayList;
jlahoda@740
    55
import java.util.Arrays;
jlahoda@480
    56
import java.util.Collection;
jlahoda@1041
    57
import java.util.Collections;
jlahoda@709
    58
import java.util.HashMap;
jlahoda@1015
    59
import java.util.HashSet;
jlahoda@505
    60
import java.util.Iterator;
jlahoda@480
    61
import java.util.LinkedList;
jlahoda@480
    62
import java.util.List;
jlahoda@709
    63
import java.util.Map;
jlahoda@480
    64
import java.util.Map.Entry;
jlahoda@480
    65
import java.util.Set;
jlahoda@480
    66
import java.util.TreeSet;
jlahoda@480
    67
import java.util.concurrent.atomic.AtomicBoolean;
jlahoda@493
    68
import java.util.logging.Level;
jlahoda@493
    69
import java.util.logging.Logger;
jlahoda@1013
    70
import java.util.prefs.AbstractPreferences;
jlahoda@800
    71
import java.util.prefs.BackingStoreException;
jlahoda@505
    72
import java.util.prefs.Preferences;
jlahoda@480
    73
import java.util.regex.Pattern;
jlahoda@800
    74
import javax.swing.JCheckBox;
jlahoda@800
    75
import javax.swing.JDialog;
jlahoda@800
    76
import javax.swing.JOptionPane;
jlahoda@800
    77
import javax.swing.JPanel;
jlahoda@800
    78
import javax.swing.SwingUtilities;
jlahoda@480
    79
import javax.swing.event.ChangeListener;
jlahoda@480
    80
import joptsimple.ArgumentAcceptingOptionSpec;
jlahoda@480
    81
import joptsimple.OptionException;
jlahoda@480
    82
import joptsimple.OptionParser;
jlahoda@480
    83
import joptsimple.OptionSet;
jlahoda@480
    84
import org.netbeans.api.java.classpath.ClassPath;
jlahoda@922
    85
import org.netbeans.api.java.classpath.GlobalPathRegistry;
jlahoda@503
    86
import org.netbeans.api.java.source.CompilationController;
jlahoda@480
    87
import org.netbeans.api.java.source.ModificationResult;
jlahoda@480
    88
import org.netbeans.core.startup.MainLookup;
jlahoda@1010
    89
import org.netbeans.modules.jackpot30.cmdline.lib.Utils;
jlahoda@795
    90
import org.netbeans.modules.jackpot30.ui.settings.XMLHintPreferences;
jlahoda@1041
    91
import org.netbeans.modules.java.hints.declarative.DeclarativeHintRegistry;
jlahoda@1041
    92
import org.netbeans.modules.java.hints.declarative.test.TestParser;
jlahoda@1041
    93
import org.netbeans.modules.java.hints.declarative.test.TestParser.TestCase;
jlahoda@1041
    94
import org.netbeans.modules.java.hints.declarative.test.TestPerformer;
jlahoda@889
    95
import org.netbeans.modules.java.hints.jackpot.spi.PatternConvertor;
jlahoda@740
    96
import org.netbeans.modules.java.hints.providers.spi.HintDescription;
jlahoda@740
    97
import org.netbeans.modules.java.hints.providers.spi.HintMetadata;
jlahoda@740
    98
import org.netbeans.modules.java.hints.spiimpl.MessageImpl;
jlahoda@740
    99
import org.netbeans.modules.java.hints.spiimpl.RulesManager;
jlahoda@740
   100
import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch;
jlahoda@740
   101
import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.BatchResult;
jlahoda@740
   102
import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.Folder;
jlahoda@740
   103
import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.Resource;
jlahoda@740
   104
import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.VerifiedSpansCallBack;
jlahoda@740
   105
import org.netbeans.modules.java.hints.spiimpl.batch.BatchUtilities;
jlahoda@740
   106
import org.netbeans.modules.java.hints.spiimpl.batch.ProgressHandleWrapper;
jlahoda@740
   107
import org.netbeans.modules.java.hints.spiimpl.batch.ProgressHandleWrapper.ProgressHandleAbstraction;
jlahoda@740
   108
import org.netbeans.modules.java.hints.spiimpl.batch.Scopes;
jlahoda@800
   109
import org.netbeans.modules.java.hints.spiimpl.options.HintsPanel;
jlahoda@740
   110
import org.netbeans.modules.java.hints.spiimpl.options.HintsSettings;
jlahoda@800
   111
import org.netbeans.modules.java.hints.spiimpl.refactoring.Utilities.ClassPathBasedHintWrapper;
jlahoda@480
   112
import org.netbeans.modules.java.source.parsing.JavaPathRecognizer;
jlahoda@480
   113
import org.netbeans.modules.parsing.impl.indexing.CacheFolder;
jlahoda@480
   114
import org.netbeans.modules.parsing.impl.indexing.RepositoryUpdater;
jlahoda@503
   115
import org.netbeans.spi.editor.hints.ErrorDescription;
jlahoda@1041
   116
import org.netbeans.spi.editor.hints.ErrorDescriptionFactory;
jlahoda@1041
   117
import org.netbeans.spi.editor.hints.Fix;
jlahoda@1011
   118
import org.netbeans.spi.editor.hints.Severity;
jlahoda@480
   119
import org.netbeans.spi.java.classpath.ClassPathProvider;
jlahoda@480
   120
import org.netbeans.spi.java.classpath.support.ClassPathSupport;
jlahoda@740
   121
import org.netbeans.spi.java.hints.Hint.Kind;
jlahoda@480
   122
import org.netbeans.spi.java.queries.SourceLevelQueryImplementation2;
jlahoda@480
   123
import org.openide.filesystems.FileObject;
jlahoda@480
   124
import org.openide.filesystems.FileStateInvalidException;
jlahoda@480
   125
import org.openide.filesystems.FileUtil;
jlahoda@800
   126
import org.openide.util.Exceptions;
jlahoda@480
   127
import org.openide.util.Lookup;
jlahoda@1015
   128
import org.openide.util.Pair;
jlahoda@480
   129
import org.openide.util.RequestProcessor;
jlahoda@480
   130
import org.openide.util.lookup.Lookups;
jlahoda@480
   131
import org.openide.util.lookup.ProxyLookup;
jlahoda@480
   132
import org.openide.util.lookup.ServiceProvider;
jlahoda@480
   133
jlahoda@480
   134
/**
jlahoda@480
   135
 *
jlahoda@480
   136
 * @author lahvac
jlahoda@480
   137
 */
jlahoda@480
   138
public class Main {
jlahoda@480
   139
jlahoda@795
   140
    private static final String OPTION_APPLY = "apply";
jlahoda@503
   141
    private static final String OPTION_NO_APPLY = "no-apply";
jlahoda@1011
   142
    private static final String OPTION_FAIL_ON_WARNINGS = "fail-on-warnings";
jlahoda@1041
   143
    private static final String RUN_TESTS = "run-tests";
jlahoda@766
   144
    private static final String SOURCE_LEVEL_DEFAULT = "1.7";
jlahoda@766
   145
    private static final String ACCEPTABLE_SOURCE_LEVEL_PATTERN = "(1\\.)?[2-9][0-9]*";
jlahoda@503
   146
    
jlahoda@480
   147
    public static void main(String... args) throws IOException, ClassNotFoundException {
jlahoda@480
   148
        System.exit(compile(args));
jlahoda@480
   149
    }
jlahoda@480
   150
jlahoda@480
   151
    public static int compile(String... args) throws IOException, ClassNotFoundException {
jlahoda@480
   152
        System.setProperty("netbeans.user", "/tmp/tmp-foo");
jlahoda@922
   153
jlahoda@480
   154
        OptionParser parser = new OptionParser();
jlahoda@480
   155
//        ArgumentAcceptingOptionSpec<File> projects = parser.accepts("project", "project(s) to refactor").withRequiredArg().withValuesSeparatedBy(File.pathSeparatorChar).ofType(File.class);
jlahoda@1013
   156
        GroupOptions globalGroupOptions = setupGroupParser(parser);
jlahoda@707
   157
        ArgumentAcceptingOptionSpec<File> cache = parser.accepts("cache", "a cache directory to store working data").withRequiredArg().ofType(File.class);
jlahoda@493
   158
        ArgumentAcceptingOptionSpec<File> out = parser.accepts("out", "output diff").withRequiredArg().ofType(File.class);
jlahoda@795
   159
        ArgumentAcceptingOptionSpec<File> configFile = parser.accepts("config-file", "configuration file").withRequiredArg().ofType(File.class);
jlahoda@480
   160
        ArgumentAcceptingOptionSpec<String> hint = parser.accepts("hint", "hint name").withRequiredArg().ofType(String.class);
jlahoda@505
   161
        ArgumentAcceptingOptionSpec<String> config = parser.accepts("config", "configurations").withRequiredArg().ofType(String.class);
jlahoda@889
   162
        ArgumentAcceptingOptionSpec<File> hintFile = parser.accepts("hint-file", "file with rules that should be performed").withRequiredArg().ofType(File.class);
jlahoda@1013
   163
        ArgumentAcceptingOptionSpec<String> group = parser.accepts("group", "specify roots to process alongside with their classpath").withRequiredArg().ofType(String.class);
jlahoda@480
   164
jlahoda@480
   165
        parser.accepts("list", "list all known hints");
jlahoda@494
   166
        parser.accepts("progress", "show progress");
jlahoda@494
   167
        parser.accepts("debug", "enable debugging loggers");
jlahoda@480
   168
        parser.accepts("help", "prints this help");
jlahoda@503
   169
        parser.accepts(OPTION_NO_APPLY, "do not apply changes - only print locations were the hint would be applied");
jlahoda@795
   170
        parser.accepts(OPTION_APPLY, "apply changes");
jlahoda@800
   171
        parser.accepts("show-gui", "show configuration dialog");
jlahoda@1011
   172
        parser.accepts(OPTION_FAIL_ON_WARNINGS, "fail when warnings are detected");
jlahoda@1041
   173
        parser.accepts(RUN_TESTS, "run tests for declarative rules that were used");
jlahoda@480
   174
jlahoda@480
   175
        OptionSet parsed;
jlahoda@480
   176
jlahoda@480
   177
        try {
jlahoda@480
   178
            parsed = parser.parse(args);
jlahoda@480
   179
        } catch (OptionException ex) {
jlahoda@480
   180
            System.err.println(ex.getLocalizedMessage());
jlahoda@480
   181
            parser.printHelpOn(System.out);
jlahoda@480
   182
            return 1;
jlahoda@480
   183
        }
jlahoda@480
   184
jlahoda@985
   185
        if (!parsed.has("debug")) {
jlahoda@985
   186
            prepareLoggers();
jlahoda@985
   187
        }
jlahoda@985
   188
jlahoda@480
   189
        if (parsed.has("help")) {
jlahoda@480
   190
            parser.printHelpOn(System.out);
jlahoda@480
   191
            return 0;
jlahoda@480
   192
        }
jlahoda@480
   193
jlahoda@922
   194
        List<FileObject> roots = new ArrayList<FileObject>();
jlahoda@922
   195
        List<Folder> rootFolders = new ArrayList<Folder>();
jlahoda@922
   196
jlahoda@922
   197
        for (String sr : parsed.nonOptionArguments()) {
jlahoda@922
   198
            File r = new File(sr);
jlahoda@922
   199
            FileObject root = FileUtil.toFileObject(r);
jlahoda@922
   200
jlahoda@922
   201
            if (root != null) {
jlahoda@922
   202
                roots.add(root);
jlahoda@922
   203
                rootFolders.add(new Folder(root));
jlahoda@922
   204
            }
jlahoda@922
   205
        }
jlahoda@922
   206
jlahoda@1015
   207
        final List<RootConfiguration> groups = new ArrayList<>();
jlahoda@1015
   208
jlahoda@1015
   209
        groups.add(new RootConfiguration(parsed, globalGroupOptions));
jlahoda@1015
   210
jlahoda@1015
   211
        for (String groupValue : parsed.valuesOf(group)) {
jlahoda@1015
   212
            OptionParser groupParser = new OptionParser();
jlahoda@1015
   213
            GroupOptions groupOptions = setupGroupParser(groupParser);
jlahoda@1015
   214
            OptionSet parsedGroup = groupParser.parse(splitGroupArg(groupValue));
jlahoda@1015
   215
jlahoda@1015
   216
            groups.add(new RootConfiguration(parsedGroup, groupOptions));
jlahoda@1015
   217
        }
jlahoda@922
   218
jlahoda@800
   219
        if (parsed.has("show-gui")) {
jlahoda@800
   220
            if (parsed.has(configFile)) {
jlahoda@800
   221
                final File settingsFile = parsed.valueOf(configFile);
jlahoda@800
   222
                try {
jlahoda@800
   223
                    SwingUtilities.invokeAndWait(new Runnable() {
jlahoda@800
   224
                        @Override public void run() {
jlahoda@800
   225
                            try {
jlahoda@1015
   226
                                Pair<ClassPath, ClassPath> sourceAndBinaryCP = jointSourceAndBinaryCP(groups);
jlahoda@1015
   227
                                showGUICustomizer(settingsFile, sourceAndBinaryCP.second(), sourceAndBinaryCP.first());
jlahoda@800
   228
                            } catch (IOException ex) {
jlahoda@800
   229
                                Exceptions.printStackTrace(ex);
jlahoda@800
   230
                            } catch (BackingStoreException ex) {
jlahoda@800
   231
                                Exceptions.printStackTrace(ex);
jlahoda@800
   232
                            }
jlahoda@800
   233
                        }
jlahoda@800
   234
                    });
jlahoda@800
   235
                } catch (InterruptedException ex) {
jlahoda@800
   236
                    Exceptions.printStackTrace(ex);
jlahoda@800
   237
                } catch (InvocationTargetException ex) {
jlahoda@800
   238
                    Exceptions.printStackTrace(ex);
jlahoda@800
   239
                }
jlahoda@800
   240
jlahoda@800
   241
                return 0;
jlahoda@800
   242
            } else {
jlahoda@800
   243
                System.err.println("show-gui requires config-file");
jlahoda@800
   244
                return 1;
jlahoda@800
   245
            }
jlahoda@800
   246
        }
jlahoda@800
   247
jlahoda@480
   248
        File cacheDir = parsed.valueOf(cache);
jlahoda@480
   249
        boolean deleteCacheDir = false;
jlahoda@480
   250
jlahoda@480
   251
        try {
jlahoda@480
   252
            if (cacheDir == null) {
jlahoda@480
   253
                cacheDir = File.createTempFile("jackpot", "cache");
jlahoda@480
   254
                cacheDir.delete();
jlahoda@480
   255
                if (!(deleteCacheDir = cacheDir.mkdirs())) {
jlahoda@480
   256
                    System.err.println("cannot create temporary cache");
jlahoda@480
   257
                    return 1;
jlahoda@480
   258
                }
jlahoda@480
   259
            }
jlahoda@480
   260
jlahoda@480
   261
            if (cacheDir.isFile()) {
jlahoda@480
   262
                System.err.println("cache directory exists and is a file");
jlahoda@480
   263
                return 1;
jlahoda@480
   264
            }
jlahoda@480
   265
jlahoda@480
   266
            String[] cacheDirContent = cacheDir.list();
jlahoda@480
   267
jlahoda@480
   268
            if (cacheDirContent != null && cacheDirContent.length > 0 && !new File(cacheDir, "segments").exists()) {
jlahoda@480
   269
                System.err.println("cache directory is not empty, but was not created by this tool");
jlahoda@480
   270
                return 1;
jlahoda@480
   271
            }
jlahoda@480
   272
jlahoda@480
   273
            cacheDir.mkdirs();
jlahoda@480
   274
jlahoda@480
   275
            CacheFolder.setCacheFolder(FileUtil.toFileObject(FileUtil.normalizeFile(cacheDir)));
jlahoda@480
   276
jlahoda@480
   277
            org.netbeans.api.project.ui.OpenProjects.getDefault().getOpenProjects();
jlahoda@480
   278
            RepositoryUpdater.getDefault().start(false);
jlahoda@480
   279
jlahoda@709
   280
            if (parsed.has("list")) {
jlahoda@1015
   281
                Pair<ClassPath, ClassPath> sourceAndBinaryCP = jointSourceAndBinaryCP(groups);
jlahoda@1015
   282
                printHints(sourceAndBinaryCP.first(),
jlahoda@1015
   283
                           sourceAndBinaryCP.second());
jlahoda@709
   284
                return 0;
jlahoda@709
   285
            }
jlahoda@709
   286
jlahoda@1015
   287
            int totalGroups = 0;
jlahoda@1015
   288
jlahoda@1015
   289
            for (RootConfiguration groupConfig : groups) {
jlahoda@1015
   290
                if (!groupConfig.rootFolders.isEmpty()) totalGroups++;
jlahoda@1015
   291
            }
jlahoda@1015
   292
jlahoda@1013
   293
            ProgressHandleWrapper progress = parsed.has("progress") ? new ProgressHandleWrapper(new ConsoleProgressHandleAbstraction(), ProgressHandleWrapper.prepareParts(totalGroups)) : new ProgressHandleWrapper(1);
jlahoda@1013
   294
jlahoda@952
   295
            Preferences hintSettingsPreferences;
jlahoda@795
   296
            boolean apply;
jlahoda@1013
   297
            boolean runDeclarative;
jlahoda@1041
   298
            boolean runDeclarativeTests;
jlahoda@795
   299
jlahoda@795
   300
            if (parsed.has(configFile)) {
jlahoda@1013
   301
                Preferences settingsFromConfigFile;
jlahoda@795
   302
                settingsFromConfigFile = XMLHintPreferences.from(parsed.valueOf(configFile));
jlahoda@1013
   303
                hintSettingsPreferences = settingsFromConfigFile.node("settings");
jlahoda@795
   304
                apply = settingsFromConfigFile.getBoolean("apply", false);
jlahoda@1013
   305
                runDeclarative = settingsFromConfigFile.getBoolean("runDeclarative", true);
jlahoda@1041
   306
                runDeclarativeTests = settingsFromConfigFile.getBoolean("runDeclarativeTests", false);
jlahoda@1013
   307
                if (parsed.has(hint)) {
jlahoda@889
   308
                    System.err.println("cannot specify --hint and --config-file together");
jlahoda@795
   309
                    return 1;
jlahoda@1013
   310
                } else if (parsed.has(hintFile)) {
jlahoda@889
   311
                    System.err.println("cannot specify --hint-file and --config-file together");
jlahoda@889
   312
                    return 1;
jlahoda@889
   313
                }
jlahoda@707
   314
            } else {
jlahoda@1013
   315
                hintSettingsPreferences = null;
jlahoda@1013
   316
                apply = false;
jlahoda@1013
   317
                runDeclarative = true;
jlahoda@1041
   318
                runDeclarativeTests = parsed.has(RUN_TESTS);
jlahoda@480
   319
            }
jlahoda@480
   320
jlahoda@707
   321
            if (parsed.has(config) && !parsed.has(hint)) {
jlahoda@707
   322
                System.err.println("--config cannot specified when no hint is specified");
jlahoda@707
   323
                return 1;
jlahoda@707
   324
            }
jlahoda@707
   325
jlahoda@795
   326
            if (parsed.has(OPTION_NO_APPLY)) {
jlahoda@795
   327
                apply = false;
jlahoda@795
   328
            } else if (parsed.has(OPTION_APPLY)) {
jlahoda@795
   329
                apply = true;
jlahoda@795
   330
            }
jlahoda@1013
   331
jlahoda@1013
   332
            GroupResult result = GroupResult.NOTHING_TO_DO;
jlahoda@1013
   333
jlahoda@1013
   334
            try (Writer outS = parsed.has(out) ? new BufferedWriter(new OutputStreamWriter(new FileOutputStream(parsed.valueOf(out)))) : null) {
jlahoda@1041
   335
                GlobalConfiguration globalConfig = new GlobalConfiguration(hintSettingsPreferences, apply, runDeclarative, runDeclarativeTests, parsed.valueOf(hint), parsed.valueOf(hintFile), outS, parsed.has(OPTION_FAIL_ON_WARNINGS));
jlahoda@1013
   336
jlahoda@1015
   337
                for (RootConfiguration groupConfig : groups) {
jlahoda@1015
   338
                    result = result.join(handleGroup(groupConfig, progress, globalConfig, parsed.valuesOf(config)));
jlahoda@1013
   339
                }
jlahoda@1013
   340
            }
jlahoda@1013
   341
jlahoda@1013
   342
            progress.finish();
jlahoda@1013
   343
jlahoda@1013
   344
            if (result == GroupResult.NOTHING_TO_DO) {
jlahoda@1013
   345
                System.err.println("no source roots to work on");
jlahoda@876
   346
                return 1;
jlahoda@876
   347
            }
jlahoda@876
   348
jlahoda@1016
   349
            if (result == GroupResult.NO_HINTS_FOUND) {
jlahoda@1016
   350
                System.err.println("no hints specified");
jlahoda@1016
   351
                return 1;
jlahoda@1016
   352
            }
jlahoda@1016
   353
jlahoda@1013
   354
            return result == GroupResult.SUCCESS ? 0 : 1;
jlahoda@996
   355
        } catch (Throwable e) {
jlahoda@996
   356
            e.printStackTrace();
jlahoda@996
   357
            throw new IllegalStateException(e);
jlahoda@480
   358
        } finally {
jlahoda@480
   359
            if (deleteCacheDir) {
jlahoda@480
   360
                FileObject cacheDirFO = FileUtil.toFileObject(cacheDir);
jlahoda@480
   361
jlahoda@480
   362
                if (cacheDirFO != null) {
jlahoda@480
   363
                    //TODO: would be better to do j.i.File.delete():
jlahoda@480
   364
                    cacheDirFO.delete();
jlahoda@480
   365
                }
jlahoda@480
   366
            }
jlahoda@480
   367
        }
jlahoda@480
   368
    }
jlahoda@480
   369
jlahoda@1015
   370
    private static Pair<ClassPath, ClassPath> jointSourceAndBinaryCP(List<RootConfiguration> groups) {
jlahoda@1015
   371
        Set<FileObject> sourceRoots = new HashSet<>();
jlahoda@1015
   372
        Set<FileObject> binaryRoots = new HashSet<>();
jlahoda@1015
   373
        for (RootConfiguration groupConfig : groups) {
jlahoda@1015
   374
            sourceRoots.addAll(Arrays.asList(groupConfig.sourceCP.getRoots()));
jlahoda@1015
   375
            binaryRoots.addAll(Arrays.asList(groupConfig.binaryCP.getRoots()));
jlahoda@1015
   376
        }
jlahoda@1015
   377
        return Pair.of(ClassPathSupport.createClassPath(sourceRoots.toArray(new FileObject[0])),
jlahoda@1015
   378
                       ClassPathSupport.createClassPath(binaryRoots.toArray(new FileObject[0])));
jlahoda@1015
   379
    }
jlahoda@1015
   380
jlahoda@1013
   381
    private static GroupOptions setupGroupParser(OptionParser parser) {
jlahoda@1013
   382
        return new GroupOptions(parser.accepts("classpath", "classpath").withRequiredArg().withValuesSeparatedBy(File.pathSeparatorChar).ofType(File.class),
jlahoda@1013
   383
                                parser.accepts("bootclasspath", "bootclasspath").withRequiredArg().withValuesSeparatedBy(File.pathSeparatorChar).ofType(File.class),
jlahoda@1013
   384
                                parser.accepts("sourcepath", "sourcepath").withRequiredArg().withValuesSeparatedBy(File.pathSeparatorChar).ofType(File.class),
jlahoda@1013
   385
                                parser.accepts("source", "source level").withRequiredArg().ofType(String.class).defaultsTo(SOURCE_LEVEL_DEFAULT));
jlahoda@1013
   386
    }
jlahoda@1013
   387
jlahoda@1013
   388
    private static final class GroupOptions {
jlahoda@1013
   389
        private final ArgumentAcceptingOptionSpec<File> classpath;
jlahoda@1013
   390
        private final ArgumentAcceptingOptionSpec<File> bootclasspath;
jlahoda@1013
   391
        private final ArgumentAcceptingOptionSpec<File> sourcepath;
jlahoda@1013
   392
        private final ArgumentAcceptingOptionSpec<String> source;
jlahoda@1013
   393
jlahoda@1013
   394
        public GroupOptions(ArgumentAcceptingOptionSpec<File> classpath, ArgumentAcceptingOptionSpec<File> bootclasspath, ArgumentAcceptingOptionSpec<File> sourcepath, ArgumentAcceptingOptionSpec<String> source) {
jlahoda@1013
   395
            this.classpath = classpath;
jlahoda@1013
   396
            this.bootclasspath = bootclasspath;
jlahoda@1013
   397
            this.sourcepath = sourcepath;
jlahoda@1013
   398
            this.source = source;
jlahoda@1013
   399
        }
jlahoda@1013
   400
jlahoda@1013
   401
    }
jlahoda@1013
   402
jlahoda@737
   403
    private static Map<HintMetadata, Collection<? extends HintDescription>> listHints(ClassPath sourceFrom, ClassPath binaryFrom) {
jlahoda@709
   404
        Map<HintMetadata, Collection<? extends HintDescription>> result = new HashMap<HintMetadata, Collection<? extends HintDescription>>();
jlahoda@709
   405
jlahoda@740
   406
        for (Entry<HintMetadata, ? extends Collection<? extends HintDescription>> entry: RulesManager.getInstance().readHints(null, Arrays.asList(sourceFrom, binaryFrom), null).entrySet()) {
jlahoda@709
   407
            result.put(entry.getKey(), entry.getValue());
jlahoda@709
   408
        }
jlahoda@709
   409
jlahoda@709
   410
        return result;
jlahoda@709
   411
    }
jlahoda@1013
   412
jlahoda@1015
   413
    private static GroupResult handleGroup(RootConfiguration rootConfiguration, ProgressHandleWrapper w, GlobalConfiguration globalConfig, List<String> config) throws IOException {
jlahoda@1013
   414
        Iterable<? extends HintDescription> hints;
jlahoda@1013
   415
jlahoda@1013
   416
        if (rootConfiguration.rootFolders.isEmpty()) {
jlahoda@1013
   417
            return GroupResult.NOTHING_TO_DO;
jlahoda@1013
   418
        }
jlahoda@1013
   419
jlahoda@1041
   420
        WarningsAndErrors wae = new WarningsAndErrors();
jlahoda@1041
   421
jlahoda@1015
   422
        ProgressHandleWrapper progress = w.startNextPartWithEmbedding(1);
jlahoda@1013
   423
        Preferences settings = globalConfig.configurationPreferences != null ? globalConfig.configurationPreferences : new MemoryPreferences();
jlahoda@1013
   424
        HintsSettings hintSettings = HintsSettings.createPreferencesBasedHintsSettings(settings, false, null);
jlahoda@1013
   425
jlahoda@1013
   426
        if (globalConfig.hint != null) {
jlahoda@1013
   427
            hints = findHints(rootConfiguration.sourceCP, rootConfiguration.binaryCP, globalConfig.hint, hintSettings);
jlahoda@1013
   428
        } else if (globalConfig.hintFile != null) {
jlahoda@1013
   429
            FileObject hintFileFO = FileUtil.toFileObject(globalConfig.hintFile);
jlahoda@1013
   430
            assert hintFileFO != null;
jlahoda@1013
   431
            hints = PatternConvertor.create(hintFileFO.asText());
jlahoda@1013
   432
            for (HintDescription hd : hints) {
jlahoda@1013
   433
                hintSettings.setEnabled(hd.getMetadata(), true);
jlahoda@1013
   434
            }
jlahoda@1013
   435
        } else {
jlahoda@1013
   436
            hints = readHints(rootConfiguration.sourceCP, rootConfiguration.binaryCP, hintSettings, settings, globalConfig.runDeclarative);
jlahoda@1041
   437
            if (globalConfig.runDeclarativeTests) {
jlahoda@1041
   438
                Set<String> enabledHints = new HashSet<>();
jlahoda@1041
   439
                for (HintDescription desc : hints) {
jlahoda@1041
   440
                    enabledHints.add(desc.getMetadata().id);
jlahoda@1041
   441
                }
jlahoda@1041
   442
                ClassPath combined = ClassPathSupport.createProxyClassPath(rootConfiguration.sourceCP, rootConfiguration.binaryCP);
jlahoda@1041
   443
                Map<FileObject, FileObject> testFiles = new HashMap<>();
jlahoda@1041
   444
                for (FileObject upgrade : combined.findAllResources("META-INF/upgrade")) {
jlahoda@1041
   445
                    for (FileObject c : upgrade.getChildren()) {
jlahoda@1041
   446
                        if (c.getExt().equals("test")) {
jlahoda@1041
   447
                            FileObject hintFile = FileUtil.findBrother(c, "hint");
jlahoda@1041
   448
jlahoda@1041
   449
                            for (HintMetadata hm : DeclarativeHintRegistry.parseHintFile(hintFile).keySet()) {
jlahoda@1041
   450
                                if (enabledHints.contains(hm.id)) {
jlahoda@1041
   451
                                    testFiles.put(c, hintFile);
jlahoda@1041
   452
                                    break;
jlahoda@1041
   453
                                }
jlahoda@1041
   454
                            }
jlahoda@1041
   455
                        }
jlahoda@1041
   456
                    }
jlahoda@1041
   457
                }
jlahoda@1041
   458
                for (Entry<FileObject, FileObject> e : testFiles.entrySet()) {
jlahoda@1041
   459
                    TestCase[] testCases = TestParser.parse(e.getKey().asText()); //XXX: encoding
jlahoda@1041
   460
                    try {
jlahoda@1041
   461
                        Map<TestCase, Collection<String>> testResult = TestPerformer.performTest(e.getValue(), e.getKey(), testCases, new AtomicBoolean());
jlahoda@1041
   462
                        for (TestCase tc : testCases) {
jlahoda@1041
   463
                            List<String> expected = Arrays.asList(tc.getResults());
jlahoda@1041
   464
                            List<String> actual = new ArrayList<>(testResult.get(tc));
jlahoda@1041
   465
                            if (!expected.equals(actual)) {
jlahoda@1041
   466
                                int pos = tc.getTestCaseStart();
jlahoda@1041
   467
                                String id = "test-failure";
jlahoda@1041
   468
                                ErrorDescription ed = ErrorDescriptionFactory.createErrorDescription(id, Severity.ERROR, "Actual results did not match the expected test results. Actual results: " + expected, null, ErrorDescriptionFactory.lazyListForFixes(Collections.<Fix>emptyList()), e.getKey(), pos, pos);
jlahoda@1041
   469
                                print(ed, wae, Collections.singletonMap(id, id));
jlahoda@1041
   470
                            }
jlahoda@1041
   471
                        }
jlahoda@1041
   472
                    } catch (Exception ex) {
jlahoda@1041
   473
                        ex.printStackTrace();
jlahoda@1041
   474
                    }
jlahoda@1041
   475
                }
jlahoda@1041
   476
            }
jlahoda@1013
   477
        }
jlahoda@1013
   478
jlahoda@1013
   479
        if (config != null && !config.isEmpty()) {
jlahoda@1013
   480
            Iterator<? extends HintDescription> hit = hints.iterator();
jlahoda@1013
   481
            HintDescription hd = hit.next();
jlahoda@1013
   482
jlahoda@1013
   483
            if (hit.hasNext()) {
jlahoda@1013
   484
                System.err.println("--config cannot specified when more than one hint is specified");
jlahoda@1013
   485
jlahoda@1013
   486
                return GroupResult.FAILURE;
jlahoda@1013
   487
            }
jlahoda@1013
   488
jlahoda@1013
   489
            Preferences prefs = hintSettings.getHintPreferences(hd.getMetadata());
jlahoda@1013
   490
jlahoda@1013
   491
            boolean stop = false;
jlahoda@1013
   492
jlahoda@1013
   493
            for (String c : config) {
jlahoda@1013
   494
                int assign = c.indexOf('=');
jlahoda@1013
   495
jlahoda@1013
   496
                if (assign == (-1)) {
jlahoda@1013
   497
                    System.err.println("configuration option is missing '=' (" + c + ")");
jlahoda@1013
   498
                    stop = true;
jlahoda@1013
   499
                    continue;
jlahoda@1013
   500
                }
jlahoda@1013
   501
jlahoda@1013
   502
                prefs.put(c.substring(0, assign), c.substring(assign + 1));
jlahoda@1013
   503
            }
jlahoda@1013
   504
jlahoda@1013
   505
            if (stop) {
jlahoda@1013
   506
                return GroupResult.FAILURE;
jlahoda@1013
   507
            }
jlahoda@1013
   508
        }
jlahoda@1013
   509
jlahoda@1015
   510
        String sourceLevel = rootConfiguration.sourceLevel;
jlahoda@1013
   511
jlahoda@1013
   512
        if (!Pattern.compile(ACCEPTABLE_SOURCE_LEVEL_PATTERN).matcher(sourceLevel).matches()) {
jlahoda@1013
   513
            System.err.println("unrecognized source level specification: " + sourceLevel);
jlahoda@1013
   514
            return GroupResult.FAILURE;
jlahoda@1013
   515
        }
jlahoda@1013
   516
jlahoda@1013
   517
        if (globalConfig.apply && !hints.iterator().hasNext()) {
jlahoda@1016
   518
            return GroupResult.NO_HINTS_FOUND;
jlahoda@1013
   519
        }
jlahoda@1013
   520
jlahoda@1013
   521
        Object[] register2Lookup = new Object[] {
jlahoda@1013
   522
            new ClassPathProviderImpl(rootConfiguration.bootCP, rootConfiguration.compileCP, rootConfiguration.sourceCP),
jlahoda@1013
   523
            new JavaPathRecognizer(),
jlahoda@1013
   524
            new SourceLevelQueryImpl(rootConfiguration.sourceCP, sourceLevel)
jlahoda@1013
   525
        };
jlahoda@1013
   526
jlahoda@1013
   527
        try {
jlahoda@1013
   528
            for (Object toRegister : register2Lookup) {
jlahoda@1013
   529
                MainLookup.register(toRegister);
jlahoda@1013
   530
            }
jlahoda@1013
   531
jlahoda@1013
   532
            if (globalConfig.apply) {
jlahoda@1013
   533
                apply(hints, rootConfiguration.rootFolders.toArray(new Folder[0]), progress, hintSettings, globalConfig.out);
jlahoda@1013
   534
jlahoda@1041
   535
                return GroupResult.SUCCESS; //TODO: WarningsAndErrors?
jlahoda@1013
   536
            } else {
jlahoda@1013
   537
                findOccurrences(hints, rootConfiguration.rootFolders.toArray(new Folder[0]), progress, hintSettings, wae);
jlahoda@1013
   538
jlahoda@1013
   539
                if (wae.errors != 0 || (wae.warnings != 0 && globalConfig.failOnWarnings)) {
jlahoda@1013
   540
                    return GroupResult.FAILURE;
jlahoda@1013
   541
                } else {
jlahoda@1013
   542
                    return GroupResult.SUCCESS;
jlahoda@1013
   543
                }
jlahoda@1013
   544
            }
jlahoda@1013
   545
        } finally {
jlahoda@1013
   546
            for (Object toUnRegister : register2Lookup) {
jlahoda@1013
   547
                MainLookup.unregister(toUnRegister);
jlahoda@1013
   548
            }
jlahoda@1013
   549
        }
jlahoda@1013
   550
    }
jlahoda@1013
   551
jlahoda@1013
   552
    private static class MemoryPreferences extends AbstractPreferences {
jlahoda@1013
   553
jlahoda@1013
   554
        private final Map<String, String> values = new HashMap<>();
jlahoda@1013
   555
        private final Map<String, MemoryPreferences> nodes = new HashMap<>();
jlahoda@1013
   556
jlahoda@1013
   557
        public MemoryPreferences() {
jlahoda@1013
   558
            this(null, "");
jlahoda@1013
   559
        }
jlahoda@1013
   560
jlahoda@1013
   561
        public MemoryPreferences(MemoryPreferences parent, String name) {
jlahoda@1013
   562
            super(parent, name);
jlahoda@1013
   563
        }
jlahoda@1013
   564
        @Override
jlahoda@1013
   565
        protected void putSpi(String key, String value) {
jlahoda@1013
   566
            values.put(key, value);
jlahoda@1013
   567
        }
jlahoda@1013
   568
jlahoda@1013
   569
        @Override
jlahoda@1013
   570
        protected String getSpi(String key) {
jlahoda@1013
   571
            return values.get(key);
jlahoda@1013
   572
        }
jlahoda@1013
   573
jlahoda@1013
   574
        @Override
jlahoda@1013
   575
        protected void removeSpi(String key) {
jlahoda@1013
   576
            values.remove(key);
jlahoda@1013
   577
        }
jlahoda@1013
   578
jlahoda@1013
   579
        @Override
jlahoda@1013
   580
        protected void removeNodeSpi() throws BackingStoreException {
jlahoda@1013
   581
            ((MemoryPreferences) parent()).nodes.remove(name());
jlahoda@1013
   582
        }
jlahoda@1013
   583
jlahoda@1013
   584
        @Override
jlahoda@1013
   585
        protected String[] keysSpi() throws BackingStoreException {
jlahoda@1013
   586
            return values.keySet().toArray(new String[0]);
jlahoda@1013
   587
        }
jlahoda@1013
   588
jlahoda@1013
   589
        @Override
jlahoda@1013
   590
        protected String[] childrenNamesSpi() throws BackingStoreException {
jlahoda@1013
   591
            return nodes.keySet().toArray(new String[0]);
jlahoda@1013
   592
        }
jlahoda@1013
   593
jlahoda@1013
   594
        @Override
jlahoda@1013
   595
        protected AbstractPreferences childSpi(String name) {
jlahoda@1013
   596
            MemoryPreferences result = nodes.get(name);
jlahoda@1013
   597
jlahoda@1013
   598
            if (result == null) {
jlahoda@1013
   599
                nodes.put(name, result = new MemoryPreferences(this, name));
jlahoda@1013
   600
            }
jlahoda@1013
   601
jlahoda@1013
   602
            return result;
jlahoda@1013
   603
        }
jlahoda@1013
   604
jlahoda@1013
   605
        @Override
jlahoda@1013
   606
        protected void syncSpi() throws BackingStoreException {
jlahoda@1013
   607
        }
jlahoda@1013
   608
jlahoda@1013
   609
        @Override
jlahoda@1013
   610
        protected void flushSpi() throws BackingStoreException {
jlahoda@1013
   611
        }
jlahoda@1013
   612
    }
jlahoda@1013
   613
jlahoda@1013
   614
    private enum GroupResult {
jlahoda@1013
   615
        NOTHING_TO_DO {
jlahoda@1013
   616
            @Override
jlahoda@1013
   617
            public GroupResult join(GroupResult other) {
jlahoda@1013
   618
                return other;
jlahoda@1013
   619
            }
jlahoda@1013
   620
        },
jlahoda@1016
   621
        NO_HINTS_FOUND {
jlahoda@1016
   622
            @Override
jlahoda@1016
   623
            public GroupResult join(GroupResult other) {
jlahoda@1016
   624
                if (other == NOTHING_TO_DO) return this;
jlahoda@1016
   625
                return other;
jlahoda@1016
   626
            }
jlahoda@1016
   627
        },
jlahoda@1013
   628
        SUCCESS {
jlahoda@1013
   629
            @Override
jlahoda@1013
   630
            public GroupResult join(GroupResult other) {
jlahoda@1013
   631
                if (other == FAILURE) return other;
jlahoda@1013
   632
                return this;
jlahoda@1013
   633
            }
jlahoda@1013
   634
        },
jlahoda@1013
   635
        FAILURE {
jlahoda@1013
   636
            @Override
jlahoda@1013
   637
            public GroupResult join(GroupResult other) {
jlahoda@1013
   638
                return this;
jlahoda@1013
   639
            }
jlahoda@1013
   640
        };
jlahoda@1013
   641
jlahoda@1013
   642
        public abstract GroupResult join(GroupResult other);
jlahoda@1013
   643
    }
jlahoda@709
   644
    
jlahoda@952
   645
    private static Iterable<? extends HintDescription> findHints(ClassPath sourceFrom, ClassPath binaryFrom, String name, HintsSettings toEnableIn) {
jlahoda@480
   646
        List<HintDescription> descs = new LinkedList<HintDescription>();
jlahoda@480
   647
jlahoda@737
   648
        for (Entry<HintMetadata, Collection<? extends HintDescription>> e : listHints(sourceFrom, binaryFrom).entrySet()) {
jlahoda@480
   649
            if (e.getKey().displayName.equals(name)) {
jlahoda@480
   650
                descs.addAll(e.getValue());
jlahoda@952
   651
                toEnableIn.setEnabled(e.getKey(), true);
jlahoda@480
   652
            }
jlahoda@480
   653
        }
jlahoda@480
   654
jlahoda@480
   655
        return descs;
jlahoda@480
   656
    }
jlahoda@480
   657
jlahoda@952
   658
    private static Iterable<? extends HintDescription> allHints(ClassPath sourceFrom, ClassPath binaryFrom, HintsSettings toEnableIn) {
jlahoda@707
   659
        List<HintDescription> descs = new LinkedList<HintDescription>();
jlahoda@707
   660
jlahoda@737
   661
        for (Entry<HintMetadata, Collection<? extends HintDescription>> e : listHints(sourceFrom, binaryFrom).entrySet()) {
jlahoda@740
   662
            if (e.getKey().kind != Kind.INSPECTION) continue;
jlahoda@707
   663
            if (!e.getKey().enabled) continue;
jlahoda@707
   664
            descs.addAll(e.getValue());
jlahoda@952
   665
            toEnableIn.setEnabled(e.getKey(), true);
jlahoda@795
   666
        }
jlahoda@795
   667
jlahoda@795
   668
        return descs;
jlahoda@795
   669
    }
jlahoda@795
   670
jlahoda@952
   671
    private static Iterable<? extends HintDescription> readHints(ClassPath sourceFrom, ClassPath binaryFrom, HintsSettings toEnableIn, Preferences toEnableInPreferencesHack, boolean declarativeEnabledByDefault) {
jlahoda@795
   672
        Map<HintMetadata, ? extends Collection<? extends HintDescription>> hardcoded = RulesManager.getInstance().readHints(null, Arrays.<ClassPath>asList(), null);
jlahoda@922
   673
        Map<HintMetadata, ? extends Collection<? extends HintDescription>> all = RulesManager.getInstance().readHints(null, Arrays.asList(sourceFrom, binaryFrom), null);
jlahoda@795
   674
        List<HintDescription> descs = new LinkedList<HintDescription>();
jlahoda@795
   675
jlahoda@795
   676
        for (Entry<HintMetadata, ? extends Collection<? extends HintDescription>> entry: all.entrySet()) {
jlahoda@795
   677
            if (hardcoded.containsKey(entry.getKey())) {
jlahoda@952
   678
                if (toEnableIn.isEnabled(entry.getKey())) {
jlahoda@795
   679
                    descs.addAll(entry.getValue());
jlahoda@795
   680
                }
jlahoda@795
   681
            } else {
jlahoda@952
   682
                if (/*XXX: hack*/toEnableInPreferencesHack.node(entry.getKey().id).getBoolean("enabled", declarativeEnabledByDefault)) {
jlahoda@922
   683
                    descs.addAll(entry.getValue());
jlahoda@922
   684
                }
jlahoda@795
   685
            }
jlahoda@707
   686
        }
jlahoda@707
   687
jlahoda@707
   688
        return descs;
jlahoda@707
   689
    }
jlahoda@707
   690
jlahoda@494
   691
    private static final Logger TOP_LOGGER = Logger.getLogger("");
jlahoda@494
   692
jlahoda@494
   693
    private static void prepareLoggers() {
jlahoda@494
   694
        TOP_LOGGER.setLevel(Level.OFF);
jlahoda@767
   695
        System.setProperty("RepositoryUpdate.increasedLogLevel", "OFF");
jlahoda@494
   696
    }
jlahoda@494
   697
    
jlahoda@1011
   698
    private static void findOccurrences(Iterable<? extends HintDescription> descs, Folder[] sourceRoot, ProgressHandleWrapper progress, HintsSettings settings, final WarningsAndErrors wae) throws IOException {
jlahoda@1010
   699
        final Map<String, String> id2DisplayName = Utils.computeId2DisplayName(descs);
jlahoda@503
   700
        ProgressHandleWrapper w = progress.startNextPartWithEmbedding(1, 1);
jlahoda@952
   701
        BatchResult occurrences = BatchSearch.findOccurrences(descs, Scopes.specifiedFoldersScope(sourceRoot), w, settings);
jlahoda@503
   702
jlahoda@503
   703
        List<MessageImpl> problems = new LinkedList<MessageImpl>();
jlahoda@1013
   704
        BatchSearch.getVerifiedSpans(occurrences, w, new VerifiedSpansCallBack() {
jlahoda@503
   705
            @Override public void groupStarted() {}
jlahoda@503
   706
            @Override public boolean spansVerified(CompilationController wc, Resource r, Collection<? extends ErrorDescription> hints) throws Exception {
jlahoda@503
   707
                for (ErrorDescription ed : hints) {
jlahoda@1011
   708
                    print(ed, wae, id2DisplayName);
jlahoda@503
   709
                }
jlahoda@503
   710
                return true;
jlahoda@503
   711
            }
jlahoda@503
   712
            @Override public void groupFinished() {}
jlahoda@503
   713
            @Override public void cannotVerifySpan(Resource r) {
jlahoda@503
   714
                //TODO: ignored - what to do?
jlahoda@503
   715
            }
jlahoda@712
   716
        }, problems, new AtomicBoolean());
jlahoda@503
   717
    }
jlahoda@503
   718
jlahoda@1011
   719
    private static void print(ErrorDescription error, WarningsAndErrors wae, Map<String, String> id2DisplayName) throws IOException {
jlahoda@503
   720
        int lineNumber = error.getRange().getBegin().getLine();
jlahoda@503
   721
        String line = error.getFile().asLines().get(lineNumber);
jlahoda@503
   722
        int column = error.getRange().getBegin().getColumn();
jlahoda@503
   723
        StringBuilder b = new StringBuilder();
jlahoda@503
   724
jlahoda@503
   725
        for (int i = 0; i < column; i++) {
jlahoda@503
   726
            if (Character.isWhitespace(line.charAt(i))) {
jlahoda@503
   727
                b.append(line.charAt(i));
jlahoda@503
   728
            } else {
jlahoda@503
   729
                b.append(' ');
jlahoda@503
   730
            }
jlahoda@503
   731
        }
jlahoda@503
   732
jlahoda@503
   733
        b.append('^');
jlahoda@503
   734
jlahoda@1010
   735
        String idDisplayName = Utils.categoryName(error.getId(), id2DisplayName);
jlahoda@1011
   736
        String severity;
jlahoda@1011
   737
        if (error.getSeverity() == Severity.ERROR) {
jlahoda@1011
   738
            severity = "error";
jlahoda@1011
   739
            wae.errors++;
jlahoda@1011
   740
        } else {
jlahoda@1011
   741
            severity = "warning";
jlahoda@1011
   742
            wae.warnings++;
jlahoda@1011
   743
        }
jlahoda@1011
   744
        System.out.println(FileUtil.getFileDisplayName(error.getFile()) + ":" + (lineNumber + 1) + ": " + severity + ": " + idDisplayName + error.getDescription());
jlahoda@503
   745
        System.out.println(line);
jlahoda@503
   746
        System.out.println(b);
jlahoda@503
   747
    }
jlahoda@503
   748
jlahoda@1013
   749
    private static void apply(Iterable<? extends HintDescription> descs, Folder[] sourceRoot, ProgressHandleWrapper progress, HintsSettings settings, Writer out) throws IOException {
jlahoda@503
   750
        ProgressHandleWrapper w = progress.startNextPartWithEmbedding(1, 1);
jlahoda@952
   751
        BatchResult occurrences = BatchSearch.findOccurrences(descs, Scopes.specifiedFoldersScope(sourceRoot), w, settings);
jlahoda@480
   752
jlahoda@480
   753
        List<MessageImpl> problems = new LinkedList<MessageImpl>();
jlahoda@480
   754
        Collection<ModificationResult> diffs = BatchUtilities.applyFixes(occurrences, w, new AtomicBoolean(), problems);
jlahoda@480
   755
jlahoda@493
   756
        if (out != null) {
jlahoda@1013
   757
            for (ModificationResult mr : diffs) {
jlahoda@1013
   758
                org.netbeans.modules.jackpot30.indexing.batch.BatchUtilities.exportDiff(mr, null, out);
jlahoda@493
   759
            }
jlahoda@493
   760
        } else {
jlahoda@493
   761
            for (ModificationResult mr : diffs) {
jlahoda@493
   762
                mr.commit();
jlahoda@493
   763
            }
jlahoda@480
   764
        }
jlahoda@480
   765
    }
jlahoda@480
   766
jlahoda@737
   767
    private static void printHints(ClassPath sourceFrom, ClassPath binaryFrom) throws IOException {
jlahoda@480
   768
        Set<String> hints = new TreeSet<String>();
jlahoda@480
   769
jlahoda@737
   770
        for (Entry<HintMetadata, Collection<? extends HintDescription>> e : listHints(sourceFrom, binaryFrom).entrySet()) {
jlahoda@480
   771
            hints.add(e.getKey().displayName);
jlahoda@480
   772
        }
jlahoda@480
   773
jlahoda@480
   774
        for (String h : hints) {
jlahoda@480
   775
            System.out.println(h);
jlahoda@480
   776
        }
jlahoda@480
   777
    }
jlahoda@480
   778
jlahoda@480
   779
    private static ClassPath createDefaultBootClassPath() throws IOException {
jlahoda@480
   780
        try {
jlahoda@480
   781
            String cp = System.getProperty("sun.boot.class.path");
jlahoda@480
   782
            List<URL> urls = new ArrayList<URL>();
jlahoda@480
   783
            String[] paths = cp.split(Pattern.quote(System.getProperty("path.separator")));
jlahoda@480
   784
jlahoda@480
   785
            for (String path : paths) {
jlahoda@480
   786
                File f = new File(path);
jlahoda@480
   787
jlahoda@480
   788
                if (!f.canRead())
jlahoda@480
   789
                    continue;
jlahoda@480
   790
jlahoda@480
   791
                FileObject fo = FileUtil.toFileObject(FileUtil.normalizeFile(f));
jlahoda@480
   792
jlahoda@480
   793
                if (FileUtil.isArchiveFile(fo)) {
jlahoda@480
   794
                    fo = FileUtil.getArchiveRoot(fo);
jlahoda@480
   795
                }
jlahoda@480
   796
jlahoda@480
   797
                if (fo != null) {
jlahoda@480
   798
                    urls.add(fo.getURL());
jlahoda@480
   799
                }
jlahoda@480
   800
            }
jlahoda@480
   801
jlahoda@480
   802
            return ClassPathSupport.createClassPath(urls.toArray(new URL[0]));
jlahoda@480
   803
        } catch (FileStateInvalidException e) {
jlahoda@480
   804
            throw e;
jlahoda@480
   805
        }
jlahoda@480
   806
    }
jlahoda@480
   807
jlahoda@480
   808
    private static ClassPath createClassPath(Iterable<? extends File> roots, ClassPath def) {
jlahoda@480
   809
        if (roots == null) return def;
jlahoda@480
   810
jlahoda@480
   811
        List<URL> rootURLs = new ArrayList<URL>();
jlahoda@480
   812
jlahoda@480
   813
        for (File r : roots) {
jlahoda@480
   814
            rootURLs.add(FileUtil.urlForArchiveOrDir(r));
jlahoda@480
   815
        }
jlahoda@480
   816
jlahoda@480
   817
        return ClassPathSupport.createClassPath(rootURLs.toArray(new URL[0]));
jlahoda@480
   818
    }
jlahoda@480
   819
jlahoda@922
   820
    private static void showGUICustomizer(File settingsFile, ClassPath binaryCP, ClassPath sourceCP) throws IOException, BackingStoreException {
jlahoda@922
   821
        GlobalPathRegistry.getDefault().register(ClassPath.COMPILE, new ClassPath[] {binaryCP});
jlahoda@922
   822
        GlobalPathRegistry.getDefault().register(ClassPath.SOURCE, new ClassPath[] {sourceCP});
jlahoda@922
   823
        ClassPathBasedHintWrapper hints = new ClassPathBasedHintWrapper();
jlahoda@922
   824
        final Preferences p = XMLHintPreferences.from(settingsFile);
jlahoda@976
   825
        JPanel hintPanel = new HintsPanel(p.node("settings"), hints, true);
jlahoda@922
   826
        final JCheckBox runDeclarativeHints = new JCheckBox("Always Run Declarative Rules");
jlahoda@800
   827
jlahoda@922
   828
        runDeclarativeHints.setToolTipText("Always run the declarative rules found on classpath? (Only those selected above will be run when unchecked.)");
jlahoda@800
   829
        runDeclarativeHints.setSelected(p.getBoolean("runDeclarative", true));
jlahoda@800
   830
        runDeclarativeHints.addActionListener(new ActionListener() {
jlahoda@800
   831
            @Override public void actionPerformed(ActionEvent e) {
jlahoda@800
   832
                p.putBoolean("runDeclarative", runDeclarativeHints.isSelected());
jlahoda@800
   833
            }
jlahoda@800
   834
        });
jlahoda@800
   835
jlahoda@800
   836
        JPanel customizer = new JPanel(new BorderLayout());
jlahoda@800
   837
jlahoda@800
   838
        customizer.add(hintPanel, BorderLayout.CENTER);
jlahoda@800
   839
        customizer.add(runDeclarativeHints, BorderLayout.SOUTH);
jlahoda@800
   840
        JOptionPane jop = new JOptionPane(customizer, JOptionPane.PLAIN_MESSAGE);
jlahoda@800
   841
        JDialog dialog = jop.createDialog("Select Hints");
jlahoda@800
   842
jlahoda@800
   843
        jop.selectInitialValue();
jlahoda@800
   844
        dialog.setVisible(true);
jlahoda@800
   845
        dialog.dispose();
jlahoda@800
   846
jlahoda@800
   847
        Object result = jop.getValue();
jlahoda@800
   848
jlahoda@800
   849
        if (result.equals(JOptionPane.OK_OPTION)) {
jlahoda@800
   850
            p.flush();
jlahoda@800
   851
        }
jlahoda@800
   852
    }
jlahoda@800
   853
jlahoda@1013
   854
    static String[] splitGroupArg(String arg) {
jlahoda@1013
   855
        List<String> result = new ArrayList<>();
jlahoda@1013
   856
        StringBuilder currentPart = new StringBuilder();
jlahoda@1013
   857
jlahoda@1013
   858
        for (int i = 0; i < arg.length(); i++) {
jlahoda@1013
   859
            switch (arg.charAt(i)) {
jlahoda@1013
   860
                case '\\':
jlahoda@1013
   861
                    if (++i < arg.length()) {
jlahoda@1013
   862
                        currentPart.append(arg.charAt(i));
jlahoda@1013
   863
                    }
jlahoda@1013
   864
                    break;
jlahoda@1013
   865
                case ' ':
jlahoda@1013
   866
                    if (currentPart.length() > 0) {
jlahoda@1013
   867
                        result.add(currentPart.toString());
jlahoda@1013
   868
                        currentPart.delete(0, currentPart.length());
jlahoda@1013
   869
                    }
jlahoda@1013
   870
                    break;
jlahoda@1013
   871
                default:
jlahoda@1013
   872
                    currentPart.append(arg.charAt(i));
jlahoda@1013
   873
                    break;
jlahoda@1013
   874
            }
jlahoda@1013
   875
        }
jlahoda@1013
   876
jlahoda@1013
   877
        if (currentPart.length() > 0) {
jlahoda@1013
   878
            result.add(currentPart.toString());
jlahoda@1013
   879
        }
jlahoda@1013
   880
jlahoda@1013
   881
        return result.toArray(new String[0]);
jlahoda@1013
   882
    }
jlahoda@1013
   883
jlahoda@1011
   884
    private static final class WarningsAndErrors {
jlahoda@1011
   885
        private int warnings;
jlahoda@1011
   886
        private int errors;
jlahoda@1011
   887
    }
jlahoda@1011
   888
jlahoda@1013
   889
    private static final class RootConfiguration {
jlahoda@1013
   890
        private final List<Folder> rootFolders;
jlahoda@1013
   891
        private final ClassPath bootCP;
jlahoda@1013
   892
        private final ClassPath compileCP;
jlahoda@1013
   893
        private final ClassPath sourceCP;
jlahoda@1013
   894
        private final ClassPath binaryCP;
jlahoda@1015
   895
        private final String    sourceLevel;
jlahoda@1013
   896
jlahoda@1013
   897
        public RootConfiguration(OptionSet parsed, GroupOptions groupOptions) throws IOException {
jlahoda@1013
   898
            this.rootFolders = new ArrayList<>();
jlahoda@1013
   899
jlahoda@1013
   900
            List<FileObject> roots = new ArrayList<>();
jlahoda@1013
   901
jlahoda@1013
   902
            for (String sr : parsed.nonOptionArguments()) {
jlahoda@1013
   903
                File r = new File(sr);
jlahoda@1013
   904
                FileObject root = FileUtil.toFileObject(r);
jlahoda@1013
   905
jlahoda@1013
   906
                if (root != null) {
jlahoda@1013
   907
                    roots.add(root);
jlahoda@1013
   908
                    rootFolders.add(new Folder(root));
jlahoda@1013
   909
                }
jlahoda@1013
   910
            }
jlahoda@1013
   911
jlahoda@1013
   912
            this.bootCP = createClassPath(parsed.has(groupOptions.bootclasspath) ? parsed.valuesOf(groupOptions.bootclasspath) : null, createDefaultBootClassPath());
jlahoda@1013
   913
            this.compileCP = createClassPath(parsed.has(groupOptions.classpath) ? parsed.valuesOf(groupOptions.classpath) : null, ClassPath.EMPTY);
jlahoda@1013
   914
            this.sourceCP = createClassPath(parsed.has(groupOptions.sourcepath) ? parsed.valuesOf(groupOptions.sourcepath) : null, ClassPathSupport.createClassPath(roots.toArray(new FileObject[0])));
jlahoda@1013
   915
            this.binaryCP = ClassPathSupport.createProxyClassPath(bootCP, compileCP);
jlahoda@1015
   916
            this.sourceLevel = parsed.valueOf(groupOptions.source);
jlahoda@1013
   917
        }
jlahoda@1013
   918
jlahoda@1013
   919
    }
jlahoda@1013
   920
jlahoda@1013
   921
    private static final class GlobalConfiguration {
jlahoda@1013
   922
        private final Preferences configurationPreferences;
jlahoda@1013
   923
        private final boolean apply;
jlahoda@1013
   924
        private final boolean runDeclarative;
jlahoda@1041
   925
        private final boolean runDeclarativeTests;
jlahoda@1013
   926
        private final String hint;
jlahoda@1013
   927
        private final File hintFile;
jlahoda@1013
   928
        private final Writer out;
jlahoda@1013
   929
        private final boolean failOnWarnings;
jlahoda@1013
   930
jlahoda@1041
   931
        public GlobalConfiguration(Preferences configurationPreferences, boolean apply, boolean runDeclarative, boolean runDeclarativeTests, String hint, File hintFile, Writer out, boolean failOnWarnings) {
jlahoda@1013
   932
            this.configurationPreferences = configurationPreferences;
jlahoda@1013
   933
            this.apply = apply;
jlahoda@1013
   934
            this.runDeclarative = runDeclarative;
jlahoda@1041
   935
            this.runDeclarativeTests = runDeclarativeTests;
jlahoda@1013
   936
            this.hint = hint;
jlahoda@1013
   937
            this.hintFile = hintFile;
jlahoda@1013
   938
            this.out = out;
jlahoda@1013
   939
            this.failOnWarnings = failOnWarnings;
jlahoda@1013
   940
        }
jlahoda@1013
   941
jlahoda@1013
   942
    }
jlahoda@1013
   943
jlahoda@480
   944
    @ServiceProvider(service=Lookup.class)
jlahoda@480
   945
    public static final class LookupProviderImpl extends ProxyLookup {
jlahoda@480
   946
jlahoda@480
   947
        public LookupProviderImpl() {
jlahoda@480
   948
            super(Lookups.forPath("Services/AntBasedProjectTypes"));
jlahoda@480
   949
        }
jlahoda@480
   950
    }
jlahoda@480
   951
jlahoda@480
   952
    public static final class ClassPathProviderImpl implements ClassPathProvider {
jlahoda@480
   953
        private final ClassPath boot;
jlahoda@480
   954
        private final ClassPath compile;
jlahoda@480
   955
        private final ClassPath source;
jlahoda@480
   956
jlahoda@480
   957
        public ClassPathProviderImpl(ClassPath boot, ClassPath compile, ClassPath source) {
jlahoda@480
   958
            this.boot = boot;
jlahoda@480
   959
            this.compile = compile;
jlahoda@480
   960
            this.source = source;
jlahoda@480
   961
        }
jlahoda@480
   962
jlahoda@480
   963
        @Override
jlahoda@480
   964
        public ClassPath findClassPath(FileObject file, String type) {
jlahoda@480
   965
            if (source.findOwnerRoot(file) != null) {
jlahoda@480
   966
                if (ClassPath.BOOT.equals(type)) {
jlahoda@480
   967
                    return boot;
jlahoda@480
   968
                } else if (ClassPath.COMPILE.equals(type)) {
jlahoda@480
   969
                    return compile;
jlahoda@480
   970
                } else  if (ClassPath.SOURCE.equals(type)) {
jlahoda@480
   971
                    return source;
jlahoda@480
   972
                }
jlahoda@480
   973
            }
jlahoda@480
   974
jlahoda@480
   975
            return null;
jlahoda@480
   976
        }
jlahoda@480
   977
    }
jlahoda@480
   978
jlahoda@480
   979
    public static final class SourceLevelQueryImpl implements SourceLevelQueryImplementation2 {
jlahoda@480
   980
        private final ClassPath sourceCP;
jlahoda@480
   981
        private final Result sourceLevel;
jlahoda@480
   982
jlahoda@480
   983
        public SourceLevelQueryImpl(ClassPath sourceCP, final String sourceLevel) {
jlahoda@480
   984
            this.sourceCP = sourceCP;
jlahoda@480
   985
            this.sourceLevel = new Result() {
jlahoda@480
   986
                @Override public String getSourceLevel() {
jlahoda@480
   987
                    return sourceLevel;
jlahoda@480
   988
                }
jlahoda@480
   989
                @Override public void addChangeListener(ChangeListener listener) {}
jlahoda@480
   990
                @Override public void removeChangeListener(ChangeListener listener) {}
jlahoda@480
   991
            };
jlahoda@480
   992
        }
jlahoda@480
   993
jlahoda@480
   994
        @Override
jlahoda@480
   995
        public Result getSourceLevel(FileObject javaFile) {
jlahoda@480
   996
            if (sourceCP.findOwnerRoot(javaFile) != null) {
jlahoda@480
   997
                return sourceLevel;
jlahoda@480
   998
            } else {
jlahoda@480
   999
                return null;
jlahoda@480
  1000
            }
jlahoda@480
  1001
        }
jlahoda@480
  1002
jlahoda@480
  1003
    }
jlahoda@480
  1004
jlahoda@480
  1005
    private static final class ConsoleProgressHandleAbstraction implements ProgressHandleAbstraction {
jlahoda@480
  1006
jlahoda@1015
  1007
        private final int width = 80 - 2;
jlahoda@480
  1008
jlahoda@480
  1009
        private int total = -1;
jlahoda@480
  1010
        private int current = 0;
jlahoda@480
  1011
jlahoda@494
  1012
        public ConsoleProgressHandleAbstraction() {
jlahoda@480
  1013
        }
jlahoda@480
  1014
jlahoda@480
  1015
        @Override
jlahoda@480
  1016
        public synchronized void start(int totalWork) {
jlahoda@480
  1017
            if (total != (-1)) throw new UnsupportedOperationException();
jlahoda@480
  1018
            total = totalWork;
jlahoda@480
  1019
            update();
jlahoda@480
  1020
        }
jlahoda@480
  1021
jlahoda@480
  1022
        @Override
jlahoda@480
  1023
        public synchronized void progress(int currentWorkDone) {
jlahoda@480
  1024
            current = currentWorkDone;
jlahoda@480
  1025
            update();
jlahoda@480
  1026
        }
jlahoda@480
  1027
jlahoda@480
  1028
        @Override
jlahoda@480
  1029
        public void progress(String message) {
jlahoda@480
  1030
        }
jlahoda@480
  1031
jlahoda@480
  1032
        @Override
jlahoda@1015
  1033
        public synchronized void finish() {
jlahoda@1015
  1034
            current = total;
jlahoda@1015
  1035
            RequestProcessor.getDefault().post(new Runnable() {
jlahoda@1015
  1036
                @Override
jlahoda@1015
  1037
                public void run() {
jlahoda@1015
  1038
                    doUpdate(false);
jlahoda@1015
  1039
                    System.out.println();
jlahoda@1015
  1040
                }
jlahoda@1015
  1041
            });
jlahoda@480
  1042
        }
jlahoda@480
  1043
jlahoda@480
  1044
        private void update() {
jlahoda@480
  1045
            RequestProcessor.getDefault().post(new Runnable() {
jlahoda@480
  1046
                @Override
jlahoda@480
  1047
                public void run() {
jlahoda@1015
  1048
                    doUpdate(true);
jlahoda@480
  1049
                }
jlahoda@480
  1050
            });
jlahoda@480
  1051
        }
jlahoda@480
  1052
jlahoda@480
  1053
        private int currentShownDone = -1;
jlahoda@480
  1054
jlahoda@1015
  1055
        private void doUpdate(boolean moveCaret) {
jlahoda@480
  1056
            int done;
jlahoda@480
  1057
jlahoda@480
  1058
            synchronized(this) {
jlahoda@1015
  1059
                done = (int) ((((double) width) / total) * current);
jlahoda@480
  1060
jlahoda@480
  1061
                if (done == currentShownDone) {
jlahoda@480
  1062
                    return;
jlahoda@480
  1063
                }
jlahoda@480
  1064
jlahoda@480
  1065
                currentShownDone = done;
jlahoda@480
  1066
            }
jlahoda@480
  1067
            
jlahoda@494
  1068
            int todo = width - done;
jlahoda@494
  1069
            PrintStream pw = System.out;
jlahoda@480
  1070
jlahoda@480
  1071
            pw.print("[");
jlahoda@480
  1072
jlahoda@480
  1073
jlahoda@480
  1074
            while (done-- > 0) {
jlahoda@480
  1075
                pw.print("=");
jlahoda@480
  1076
            }
jlahoda@480
  1077
jlahoda@480
  1078
            while (todo-- > 0) {
jlahoda@480
  1079
                pw.print(" ");
jlahoda@480
  1080
            }
jlahoda@480
  1081
jlahoda@1015
  1082
            pw.print("]");
jlahoda@1015
  1083
jlahoda@1015
  1084
            if (moveCaret)
jlahoda@1015
  1085
                pw.print("\r");
jlahoda@480
  1086
        }
jlahoda@480
  1087
jlahoda@480
  1088
    }
jlahoda@480
  1089
jlahoda@480
  1090
}