blob: 2abc08db829d8e8d23015fe64c8326fdc563a188 [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You 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 org.apache.royale.linter;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.io.IOUtils;
import org.apache.royale.compiler.clients.problems.CompilerProblemCategorizer;
import org.apache.royale.compiler.clients.problems.ProblemFormatter;
import org.apache.royale.compiler.clients.problems.ProblemPrinter;
import org.apache.royale.compiler.clients.problems.ProblemQuery;
import org.apache.royale.compiler.clients.problems.WorkspaceProblemFormatter;
import org.apache.royale.compiler.common.VersionInfo;
import org.apache.royale.compiler.config.ConfigurationPathResolver;
import org.apache.royale.compiler.filespecs.FileSpecification;
import org.apache.royale.compiler.internal.config.localization.LocalizationManager;
import org.apache.royale.compiler.internal.workspaces.Workspace;
import org.apache.royale.compiler.problems.ConfigurationProblem;
import org.apache.royale.compiler.problems.ICompilerProblem;
import org.apache.royale.compiler.problems.UnexpectedExceptionProblem;
import org.apache.royale.linter.config.CommandLineConfigurator;
import org.apache.royale.linter.config.Configuration;
import org.apache.royale.linter.config.ConfigurationBuffer;
import org.apache.royale.linter.config.ConfigurationValue;
import org.apache.royale.linter.config.Configurator;
import org.apache.royale.linter.config.ILinterSettingsConstants;
import org.apache.royale.utils.FilenameNormalization;
/**
* Lints .as and .mxml source files.
*/
public class LINTER {
private static final String DEFAULT_VAR = "files";
private static final String L10N_CONFIG_PREFIX = "org.apache.royale.compiler.internal.config.configuration";
static enum ExitCode {
SUCCESS(0), PRINT_HELP(1), FAILED_WITH_ERRORS(2), FAILED_WITH_EXCEPTIONS(3), FAILED_WITH_CONFIG_PROBLEMS(4);
ExitCode(int code) {
this.code = code;
}
final int code;
int getCode() {
return code;
}
}
/**
* Java program entry point.
*
* @param args command line arguments
*/
public static void main(final String[] args) {
LINTER formatter = new LINTER();
int exitCode = formatter.execute(args);
System.exit(exitCode);
}
public LINTER() {
}
private ProblemQuery problemQuery;
private List<File> inputFiles = new ArrayList<File>();
private Configuration configuration;
private ConfigurationBuffer configBuffer;
private LinterSettings settings = new LinterSettings();
public int execute(String[] args) {
ExitCode exitCode = ExitCode.SUCCESS;
problemQuery = new ProblemQuery();
problemQuery.setShowWarnings(false);
try {
boolean continueLinting = configure(args, problemQuery);
if (continueLinting) {
for (File inputFile : inputFiles) {
String filePath = FilenameNormalization.normalize(inputFile.getAbsolutePath());
FileSpecification fileSpec = new FileSpecification(filePath);
String fileText = IOUtils.toString(fileSpec.createReader());
lintFileText(filePath, fileText, problemQuery.getProblems());
}
} else if (problemQuery.hasFilteredProblems()) {
exitCode = ExitCode.FAILED_WITH_CONFIG_PROBLEMS;
} else {
exitCode = ExitCode.PRINT_HELP;
}
} catch (Exception e) {
problemQuery.add(new UnexpectedExceptionProblem(e));
System.err.println(e.getMessage());
exitCode = ExitCode.FAILED_WITH_EXCEPTIONS;
} finally {
if (problemQuery.hasFilteredProblems()) {
final Workspace workspace = new Workspace();
final CompilerProblemCategorizer categorizer = new CompilerProblemCategorizer();
final ProblemFormatter formatter = new WorkspaceProblemFormatter(workspace, categorizer);
final ProblemPrinter printer = new ProblemPrinter(formatter);
printer.printProblems(problemQuery.getFilteredProblems());
}
}
return exitCode.getCode();
}
/**
* Get the start up message that contains the program name with the copyright
* notice.
*
* @return The startup message.
*/
protected String getStartMessage() {
// This message should not be localized.
String message = "Apache Royale ActionScript Linter (aslint)\n" + VersionInfo.buildMessage()
+ "\n";
return message;
}
/**
* Get my program name.
*
* @return always "aslint".
*/
protected String getProgramName() {
return "aslint";
}
/**
* Print detailed help information if -help is provided.
*/
private void processHelp(final List<ConfigurationValue> helpVar) {
final Set<String> keywords = new LinkedHashSet<String>();
if (helpVar != null) {
for (final ConfigurationValue val : helpVar) {
for (final Object element : val.getArgs()) {
String keyword = (String) element;
while (keyword.startsWith("-"))
keyword = keyword.substring(1);
keywords.add(keyword);
}
}
}
if (keywords.size() == 0)
keywords.add("help");
final String usages = CommandLineConfigurator.usage(getProgramName(), DEFAULT_VAR, configBuffer, keywords,
LocalizationManager.get(), L10N_CONFIG_PREFIX);
System.out.println(getStartMessage());
System.out.println(usages);
}
private boolean configure(String[] args, ProblemQuery problems) {
try {
Configurator configurator = new Configurator();
ConfigurationPathResolver resolver = new ConfigurationPathResolver(System.getProperty("user.dir"));
configurator.setConfigurationPathResolver(resolver);
configurator.setConfiguration(args, ILinterSettingsConstants.FILES);
configuration = configurator.getConfiguration();
configBuffer = configurator.getConfigurationBuffer();
problems.addAll(configurator.getConfigurationProblems());
if (configBuffer.getVar("version") != null) {
System.out.println(VersionInfo.buildMessage());
return false;
}
// // Print help if "-help" is present.
final List<ConfigurationValue> helpVar = configBuffer.getVar("help");
if (helpVar != null || (args.length == 0 && configuration.getFiles().size() == 0)) {
processHelp(helpVar);
return false;
}
if (problems.hasErrors()) {
return false;
}
settings = LinterUtils.configurationToLinterSettings(configuration);
if (settings.rules.size() == 0) {
ICompilerProblem problem = new ConfigurationProblem(null, -1, -1, -1, -1, "No linter rules were specified");
problems.add(problem);
return false;
}
for (String filePath : configuration.getFiles()) {
File inputFile = new File(filePath);
if (!inputFile.exists()) {
ICompilerProblem problem = new ConfigurationProblem(null, -1, -1, -1, -1, "Input file does not exist: " + filePath);
problems.add(problem);
return false;
}
if (inputFile.isDirectory()) {
addDirectory(inputFile);
} else {
inputFiles.add(inputFile);
}
}
if (inputFiles.size() == 0) {
ICompilerProblem problem = new ConfigurationProblem(null, -1, -1, -1, -1, "Missing input file(s)");
problems.add(problem);
return false;
}
return true;
} catch (Exception e) {
e.printStackTrace(System.err);
final ICompilerProblem problem = new ConfigurationProblem(null, -1, -1, -1, -1, e.getMessage());
problems.add(problem);
return false;
}
}
private void addDirectory(File inputFile) {
for (File file : inputFile.listFiles()) {
String fileName = file.getName();
if (fileName.startsWith(".")) {
continue;
}
if (file.isDirectory()) {
addDirectory(file);
} else if (fileName.endsWith(".as") || fileName.endsWith(".mxml")) {
inputFiles.add(file);
}
}
}
public void lintFile(File file, Collection<ICompilerProblem> problems) throws IOException {
String filePath = FilenameNormalization.normalize(file.getAbsolutePath());
FileSpecification fileSpec = new FileSpecification(filePath);
String fileText = IOUtils.toString(fileSpec.createReader());
lintFileText(filePath, fileText, problems);
}
public void lintFileText(String filePath, String text, Collection<ICompilerProblem> problems) {
filePath = FilenameNormalization.normalize(filePath);
if (filePath.endsWith(".mxml")) {
lintMXMLTextInternal(filePath, text, problems);
} else {
lintAS3TextInternal(filePath, text, problems);
}
}
public void lintActionScriptText(String text, Collection<ICompilerProblem> problems) {
String filePath = FilenameNormalization.normalize("stdin.as");
lintAS3TextInternal(filePath, text, problems);
}
public void lintMXMLText(String text, Collection<ICompilerProblem> problems) {
String filePath = FilenameNormalization.normalize("stdin.mxml");
lintMXMLTextInternal(filePath, text, problems);
}
private void lintAS3TextInternal(String filePath, String text, Collection<ICompilerProblem> problems) {
ASLinter linter = new ASLinter(settings);
linter.lint(filePath, text, problems);
}
private void lintMXMLTextInternal(String filePath, String text, Collection<ICompilerProblem> problems) {
MXMLLinter linter = new MXMLLinter(settings);
linter.lint(filePath, text, problems);
}
}