/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.devtools.treeshaker;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.io.Resources;
import com.google.devtools.j2objc.util.SourceVersion;
import com.google.devtools.j2objc.util.Version;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.util.List;
import java.util.Properties;
class Options {
private static final String XBOOTCLASSPATH = "-Xbootclasspath:";
private static String usageMessage;
private static String helpMessage;
private static File publicRootSetFile = null;
static {
// Load string resources.
URL propertiesUrl = Resources.getResource(TreeShaker.class, "TreeShaker.properties");
Properties properties = new Properties();
try {
properties.load(propertiesUrl.openStream());
} catch (IOException e) {
System.err.println("unable to access tool properties: " + e);
System.exit(1);
}
usageMessage = properties.getProperty("usage-message");
Preconditions.checkNotNull(usageMessage);
helpMessage = properties.getProperty("help-message");
Preconditions.checkNotNull(helpMessage);
}
private String sourcepath;
private String classpath;
private String bootclasspath;
private List<String> sourceFiles = Lists.newArrayList();
private String fileEncoding = System.getProperty("file.encoding", "UTF-8");
private boolean treatWarningsAsErrors = false;
// The default source version number if not passed with -source is determined from the system
// properties of the running java version after parsing the argument list.
private SourceVersion sourceVersion = null;
public List<String> getSourceFiles() {
return sourceFiles;
}
public void setSourceFiles(List<String> files) {
this.sourceFiles = files;
}
public String getSourcepath() {
return sourcepath;
}
public String getClasspath() {
return classpath;
}
public void setClasspath(String classpath) {
this.classpath = classpath;
}
public String getBootclasspath() {
return bootclasspath != null ? bootclasspath : System.getProperty("sun.boot.class.path");
}
public boolean treatWarningsAsErrors() {
return treatWarningsAsErrors;
}
private void addManifest(String manifestFile) throws IOException {
BufferedReader in = new BufferedReader(new FileReader(new File(manifestFile)));
try {
for (String line = in.readLine(); line != null; line = in.readLine()) {
if (!Strings.isNullOrEmpty(line)) {
sourceFiles.add(line.trim());
}
}
} finally {
in.close();
}
}
public String fileEncoding() {
return fileEncoding;
}
public SourceVersion sourceVersion() {
if (sourceVersion == null) {
// Pull source version from system properties if it is not passed with -source flag.
sourceVersion = SourceVersion.parse(System.getProperty("java.version").substring(0, 3));
}
return sourceVersion;
}
@VisibleForTesting
void setSourceVersion(SourceVersion sv) {
sourceVersion = sv;
}
public static void usage(String invalidUseMsg) {
System.err.println("tree_shaker: " + invalidUseMsg);
System.err.println(usageMessage);
System.exit(1);
}
public static void help(boolean errorExit) {
System.err.println(helpMessage);
// javac exits with 2, but any non-zero value works.
System.exit(errorExit ? 2 : 0);
}
public static void version() {
System.err.println("tree_shaker " + Version.jarVersion(Options.class));
System.exit(0);
}
public static Options parse(String[] args) throws IOException {
Options options = new Options();
int nArg = 0;
while (nArg < args.length) {
String arg = args[nArg];
if (arg.equals("-sourcepath")) {
if (++nArg == args.length) {
usage("-sourcepath requires an argument");
}
options.sourcepath = args[nArg];
} else if (arg.equals("-classpath")) {
if (++nArg == args.length) {
usage("-classpath requires an argument");
}
options.classpath = args[nArg];
} else if (arg.equals("--sourcefilelist") || arg.equals("-s")) {
if (++nArg == args.length) {
usage("--sourcefilelist requires an argument");
}
options.addManifest(args[nArg]);
} else if (arg.equals("--tree-shaker-roots")) {
if (++nArg == args.length) {
usage("--tree-shaker-roots");
}
publicRootSetFile = new File(args[nArg]);
//TODO(malvania): Enable the bootclasspath option when we have a class file AST
// parser that can use class jars.
} else if (arg.startsWith(XBOOTCLASSPATH)) {
options.bootclasspath = arg.substring(XBOOTCLASSPATH.length());
} else if (arg.equals("-encoding")) {
if (++nArg == args.length) {
usage("-encoding requires an argument");
}
options.fileEncoding = args[nArg];
} else if (arg.equals("-source")) {
if (++nArg == args.length) {
usage("-source requires an argument");
}
try {
options.sourceVersion = SourceVersion.parse(args[nArg]);
} catch (IllegalArgumentException e) {
usage("invalid source release: " + args[nArg]);
}
} else if (arg.equals("-version")) {
version();
} else if (arg.equals("-Werror")) {
options.treatWarningsAsErrors = true;
} else if (arg.startsWith("-h") || arg.equals("--help")) {
help(false);
} else if (arg.startsWith("-")) {
usage("invalid flag: " + arg);
} else {
break;
}
++nArg;
}
while (nArg < args.length) {
options.sourceFiles.add(args[nArg++]);
}
if (options.sourceFiles.isEmpty()) {
usage("no source files");
}
return options;
}
public File getPublicRootSetFile() {
return publicRootSetFile;
}
}