Options.java revision 2593:035b01d356ee
1/*
2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.tools.sjavac.options;
27
28import java.nio.file.Path;
29import java.util.ArrayList;
30import java.util.Arrays;
31import java.util.Collection;
32import java.util.HashMap;
33import java.util.List;
34import java.util.Map;
35import java.util.Set;
36import java.util.HashSet;
37
38import com.sun.tools.sjavac.Transformer;
39
40/**
41 * Instances of this class represent values for sjavac command line options.
42 *
43 *  <p><b>This is NOT part of any supported API.
44 *  If you write code that depends on this, you do so at your own risk.
45 *  This code and its internal interfaces are subject to change or
46 *  deletion without notice.</b>
47 */
48public class Options {
49
50    // Output directories
51    private Path destDir, genSrcDir, headerDir, stateDir;
52
53    // Input directories
54    private List<SourceLocation> sources = new ArrayList<>();
55    private List<SourceLocation> sourceSearchPaths = new ArrayList<>();
56    private List<SourceLocation> classSearchPaths = new ArrayList<>();
57    private List<SourceLocation> moduleSearchPaths = new ArrayList<>();
58
59    private String logLevel = "info";
60
61    private Set<String> permitted_artifacts = new HashSet<>();
62    private boolean permitUnidentifiedArtifacts = false;
63    private boolean permitSourcesInDefaultPackage = false;
64
65    private Path sourceReferenceList;
66    private int numCores = 4;
67    private String implicitPolicy = "none";
68    private List<String> javacArgs = new ArrayList<>();
69
70    private Map<String, Transformer> trRules = new HashMap<>();
71
72    private boolean startServer = false;
73
74    // Server configuration string
75    private String serverConf;
76
77    /** Get the policy for implicit classes */
78    public String getImplicitPolicy() {
79        return implicitPolicy;
80    }
81
82    /** Get the path for generated sources (or null if no such path is set) */
83    public Path getGenSrcDir() {
84        return genSrcDir;
85    }
86
87    /** Get the path for the destination directory */
88    public Path getDestDir() {
89        return destDir;
90    }
91
92    /** Get the path for the header directory (or null if no such path is set) */
93    public Path getHeaderDir() {
94        return headerDir;
95    }
96
97    /** Get the path for the state directory, defaults to destDir. */
98    public Path getStateDir() {
99        return stateDir != null ? stateDir : destDir;
100    }
101
102    /** Get all source locations for files to be compiled */
103    public List<SourceLocation> getSources() {
104        return sources;
105    }
106
107    /**
108     * Get all paths to search for classes in .java format. (Java-files in
109     * found here should not be compiled.
110     */
111    public List<SourceLocation> getSourceSearchPaths() {
112        return sourceSearchPaths;
113    }
114
115    /** Get all paths to search for classes in. */
116    public List<SourceLocation> getClassSearchPath() {
117        return classSearchPaths;
118    }
119
120    /** Get all paths to search for modules in. */
121    public List<SourceLocation> getModuleSearchPaths() {
122        return moduleSearchPaths;
123    }
124
125    /** Get the log level. */
126    public String getLogLevel() {
127        return logLevel;
128    }
129
130    /** Returns true iff the artifact is permitted in the output dir. */
131    public boolean isUnidentifiedArtifactPermitted(String f) {
132        return permitted_artifacts.contains(f);
133    }
134
135    /** Returns true iff artifacts in the output directories should be kept,
136     * even if they would not be generated in a clean build. */
137    public boolean areUnidentifiedArtifactsPermitted() {
138        return permitUnidentifiedArtifacts;
139    }
140
141    /** Returns true iff sources in the default package should be permitted. */
142    public boolean isDefaultPackagePermitted() {
143        return permitSourcesInDefaultPackage;
144    }
145
146    /** Get the path to the list of reference sources (or null if none is set) */
147    public Path getSourceReferenceList() {
148        return sourceReferenceList;
149    }
150
151    /** Get the number of cores to be used by sjavac */
152    public int getNumCores() {
153        return numCores;
154    }
155
156    /** Returns all arguments relevant to javac but irrelevant to sjavac. */
157    public List<String> getJavacArgs() {
158        return javacArgs;
159    }
160
161    /**
162     * Get a map which maps suffixes to transformers (for example
163     * ".java" -> CompileJavaPackages)
164     */
165    public Map<String, Transformer> getTranslationRules() {
166        return trRules;
167    }
168
169    /** Return true iff a new server should be started */
170    public boolean startServerFlag() {
171        return startServer;
172    }
173
174    /** Return the server configuration string. */
175    public String getServerConf() {
176        return serverConf;
177    }
178
179    /**
180     * Parses the given argument array and returns a corresponding Options
181     * instance.
182     */
183    public static Options parseArgs(String... args) {
184        Options options = new Options();
185        options.new ArgDecoderOptionHelper().traverse(args);
186        return options;
187    }
188
189    /** Returns true iff a .java file is among the javac arguments */
190    public boolean isJavaFilesAmongJavacArgs() {
191        for (String javacArg : javacArgs)
192            if (javacArg.endsWith(".java"))
193                return true;
194        return false;
195    }
196
197    /**
198     * Returns a string representation of the options that affect the result of
199     * the compilation. (Used for saving the state of the options used in a
200     * previous compile.)
201     */
202    public String getStateArgsString() {
203
204        // Local utility class for collecting the arguments
205        class StateArgs {
206
207            private List<String> args = new ArrayList<>();
208
209            void addArg(Option opt) {
210                args.add(opt.arg);
211            }
212
213            void addArg(Option opt, Object val) {
214                addArg(opt);
215                args.add(val.toString());
216            }
217
218            void addSourceLocations(Option opt, List<SourceLocation> locs) {
219                for (SourceLocation sl : locs) {
220                    for (String pkg : sl.includes) addArg(Option.I, pkg);
221                    for (String pkg : sl.excludes) addArg(Option.X, pkg);
222                    for (String f : sl.excludedFiles) addArg(Option.XF, f);
223                    for (String f : sl.includedFiles) addArg(Option.IF, f);
224                    addArg(opt, sl.getPath());
225                }
226            }
227
228            String getResult() {
229                String result = "";
230                for (String s : args)
231                    result += s + " ";
232                return result.trim();
233            }
234
235            public void addAll(Collection<String> toAdd) {
236                args.addAll(toAdd);
237            }
238        }
239
240        StateArgs args = new StateArgs();
241
242        // Directories
243        if (genSrcDir != null)
244            args.addArg(Option.S, genSrcDir.normalize());
245
246        if (headerDir != null)
247            args.addArg(Option.H, headerDir.normalize());
248
249        if (destDir != null)
250            args.addArg(Option.D, destDir.normalize());
251
252        if (stateDir != null)
253            args.addArg(Option.STATE_DIR, stateDir.normalize());
254
255        // Source roots
256        args.addSourceLocations(Option.SRC, sources);
257        args.addSourceLocations(Option.SOURCEPATH, sourceSearchPaths);
258        args.addSourceLocations(Option.CLASSPATH,  classSearchPaths);
259        args.addSourceLocations(Option.MODULEPATH, moduleSearchPaths);
260
261        // Boolean options
262        if (permitSourcesInDefaultPackage)
263            args.addArg(Option.PERMIT_SOURCES_WITHOUT_PACKAGE);
264
265        for (String f : permitted_artifacts) {
266            args.addArg(Option.PERMIT_ARTIFACT, f);
267        }
268
269        if (permitUnidentifiedArtifacts)
270            args.addArg(Option.PERMIT_UNIDENTIFIED_ARTIFACTS);
271
272        // Translation rules
273        for (Map.Entry<String, Transformer> tr : trRules.entrySet()) {
274            String val = tr.getKey() + "=" + tr.getValue().getClass().getName();
275            args.addArg(Option.TR, val);
276        }
277
278        // Javac args
279        args.addAll(javacArgs);
280
281        return args.getResult();
282    }
283
284
285    /** Extract the arguments to be passed on to javac. */
286    public String[] prepJavacArgs() {
287        List<String> args = new ArrayList<>();
288
289        // Output directories
290        args.add("-d");
291        args.add(destDir.toString());
292
293        if (getGenSrcDir() != null) {
294            args.add("-s");
295            args.add(genSrcDir.toString());
296        }
297
298        if (headerDir != null) {
299            args.add("-h");
300            args.add(headerDir.toString());
301        }
302
303        // Prep sourcepath
304        List<SourceLocation> sourcepath = new ArrayList<>();
305        sourcepath.addAll(sources);
306        sourcepath.addAll(sourceSearchPaths);
307        if (sourcepath.size() > 0) {
308            args.add("-sourcepath");
309            args.add(concatenateSourceLocations(sourcepath));
310        }
311
312        // Prep classpath
313        if (classSearchPaths.size() > 0) {
314            args.add("-classpath");
315            args.add(concatenateSourceLocations(classSearchPaths));
316        }
317
318        // This can't be anything but 'none'. Enforced by sjavac main method.
319        args.add("-implicit:" + implicitPolicy);
320
321        // Append javac-options (i.e. pass through options not recognized by
322        // sjavac to javac.)
323        args.addAll(javacArgs);
324
325        return args.toArray(new String[args.size()]);
326    }
327
328    // Helper method to join a list of source locations separated by
329    // File.pathSeparator
330    private static String concatenateSourceLocations(List<SourceLocation> locs) {
331        String s = "";
332        for (SourceLocation loc : locs)
333            s += (s.isEmpty() ? "" : java.io.File.pathSeparator) + loc.getPath();
334        return s;
335    }
336
337    // OptionHelper that records the traversed options in this Options instance.
338    private class ArgDecoderOptionHelper extends OptionHelper {
339
340        List<String> includes, excludes, includeFiles, excludeFiles;
341        {
342            resetFilters();
343        }
344
345        boolean headerProvided = false;
346        boolean genSrcProvided = false;
347        boolean stateProvided = false;
348
349        @Override
350        public void reportError(String msg) {
351            throw new IllegalArgumentException(msg);
352        }
353
354        @Override
355        public void sourceRoots(List<Path> paths) {
356            sources.addAll(createSourceLocations(paths));
357        }
358
359        @Override
360        public void exclude(String exclPattern) {
361            excludes.add(exclPattern);
362        }
363
364        @Override
365        public void include(String inclPattern) {
366            includes.add(inclPattern);
367        }
368
369        @Override
370        public void excludeFile(String exclFilePattern) {
371            excludeFiles.add(exclFilePattern);
372        }
373
374        @Override
375        public void includeFile(String inclFilePattern) {
376            includeFiles.add(inclFilePattern);
377        }
378
379        @Override
380        public void addTransformer(String suffix, Transformer tr) {
381            if (trRules.containsKey(suffix)) {
382                reportError("More than one transformer specified for " +
383                            "suffix " + suffix + ".");
384                return;
385            }
386            trRules.put(suffix, tr);
387        }
388
389        @Override
390        public void sourcepath(List<Path> paths) {
391            sourceSearchPaths.addAll(createSourceLocations(paths));
392        }
393
394        @Override
395        public void modulepath(List<Path> paths) {
396            moduleSearchPaths.addAll(createSourceLocations(paths));
397        }
398
399        @Override
400        public void classpath(List<Path> paths) {
401            classSearchPaths.addAll(createSourceLocations(paths));
402        }
403
404        @Override
405        public void numCores(int n) {
406            numCores = n;
407        }
408
409        @Override
410        public void logLevel(String level) {
411            logLevel = level;
412        }
413
414        @Override
415        public void compareFoundSources(Path referenceList) {
416            sourceReferenceList = referenceList;
417        }
418
419        @Override
420        public void permitArtifact(String f) {
421            permitted_artifacts.add(f);
422        }
423
424        @Override
425        public void permitUnidentifiedArtifacts() {
426            permitUnidentifiedArtifacts = true;
427        }
428
429        @Override
430        public void permitDefaultPackage() {
431            permitSourcesInDefaultPackage = true;
432        }
433
434        @Override
435        public void serverConf(String conf) {
436            if (serverConf != null)
437                reportError("Can not specify more than one server configuration.");
438            else
439                serverConf = conf;
440        }
441
442        @Override
443        public void implicit(String policy) {
444            implicitPolicy = policy;
445        }
446
447        @Override
448        public void startServerConf(String conf) {
449            if (serverConf != null)
450                reportError("Can not specify more than one server configuration.");
451            else {
452                startServer = true;
453                serverConf = conf;
454            }
455        }
456
457        @Override
458        public void javacArg(String... arg) {
459            javacArgs.addAll(Arrays.asList(arg));
460        }
461
462        @Override
463        public void destDir(Path dir) {
464            if (destDir != null) {
465                reportError("Destination directory already specified.");
466                return;
467            }
468            destDir = dir.toAbsolutePath();
469        }
470
471        @Override
472        public void generatedSourcesDir(Path dir) {
473            if (genSrcProvided) {
474                reportError("Directory for generated sources already specified.");
475                return;
476            }
477            genSrcProvided = true;
478            genSrcDir = dir.toAbsolutePath();
479        }
480
481        @Override
482        public void headerDir(Path dir) {
483            if (headerProvided) {
484                reportError("Header directory already specified.");
485                return;
486            }
487            headerProvided = true;
488            headerDir = dir.toAbsolutePath();
489        }
490
491        @Override
492        public void stateDir(Path dir) {
493            if (stateProvided) {
494                reportError("State directory already specified.");
495                return;
496            }
497            stateProvided = true;
498            stateDir = dir.toAbsolutePath();
499        }
500
501        private List<SourceLocation> createSourceLocations(List<Path> paths) {
502            List<SourceLocation> result = new ArrayList<>();
503            for (Path path : paths) {
504                result.add(new SourceLocation(
505                        path,
506                        includes,
507                        excludes,
508                        includeFiles,
509                        excludeFiles));
510            }
511            resetFilters();
512            return result;
513        }
514
515        private void resetFilters() {
516            includes = new ArrayList<>();
517            excludes = new ArrayList<>();
518            includeFiles = new ArrayList<>();
519            excludeFiles = new ArrayList<>();
520        }
521    }
522
523}
524