
fr.inria.coming.main.ComingMain Maven / Gradle / Ivy
package fr.inria.coming.main;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.log4j.Logger;
import fr.inria.coming.changeminer.analyzer.commitAnalyzer.FineGrainDifftAnalyzer;
import fr.inria.coming.changeminer.analyzer.commitAnalyzer.HunkDifftAnalyzer;
import fr.inria.coming.changeminer.analyzer.instancedetector.PatternInstanceAnalyzer;
import fr.inria.coming.changeminer.analyzer.instancedetector.SpreadPatternInstanceAnalyzer;
import fr.inria.coming.changeminer.analyzer.patternspecification.ChangePatternSpecification;
import fr.inria.coming.changeminer.analyzer.patternspecification.PatternAction;
import fr.inria.coming.changeminer.analyzer.patternspecification.PatternEntity;
import fr.inria.coming.changeminer.entity.ActionType;
import fr.inria.coming.changeminer.entity.EntityTypeSpoon;
import fr.inria.coming.changeminer.entity.FinalResult;
import fr.inria.coming.changeminer.util.PatternXMLParser;
import fr.inria.coming.codefeatures.FeatureAnalyzer;
import fr.inria.coming.codefeatures.P4JFeatureAnalyzer;
import fr.inria.coming.core.engine.Analyzer;
import fr.inria.coming.core.engine.RevisionNavigationExperiment;
import fr.inria.coming.core.engine.callback.IntermediateResultProcessorCallback;
import fr.inria.coming.core.engine.files.FileNavigationExperiment;
import fr.inria.coming.core.engine.filespair.FilesPairNavigation;
import fr.inria.coming.core.engine.git.GITRepositoryInspector;
import fr.inria.coming.core.entities.interfaces.IFilter;
import fr.inria.coming.core.entities.interfaces.IOutput;
import fr.inria.coming.core.entities.output.FeaturesOutput;
import fr.inria.coming.core.entities.output.JSonChangeFrequencyOutput;
import fr.inria.coming.core.entities.output.JSonPatternInstanceOutput;
import fr.inria.coming.core.entities.output.NullOutput;
import fr.inria.coming.core.entities.output.StdOutput;
import fr.inria.coming.core.extensionpoints.PlugInLoader;
import fr.inria.coming.core.extensionpoints.changepattern.PatternFileParser;
import fr.inria.coming.core.filter.commitmessage.BugfixKeywordsFilter;
import fr.inria.coming.core.filter.commitmessage.KeyWordsMessageFilter;
import fr.inria.coming.core.filter.diff.NbHunkFilter;
import fr.inria.coming.core.filter.files.CommitSizeFilter;
import fr.inria.coming.core.filter.files.ContainTestFilterFilter;
import fr.inria.coming.repairability.JSONRepairabilityOutput;
import fr.inria.coming.repairability.RepairTools;
import fr.inria.coming.repairability.RepairabilityAnalyzer;
/**
* @author Matias Martinez, [email protected]
*/
public class ComingMain {
static Logger logm = Logger.getLogger(FineGrainDifftAnalyzer.class.getName());
static Options options = new Options();
CommandLineParser parser = new BasicParser();
static {
options.addOption(
Option.builder("location").argName("path").hasArg().desc("analyse the content in \'path\'").build());
options.addOption(Option.builder("mode").argName("mineinstance | diff | features").hasArg()
.desc("the mode of execution of the analysis").build());
options.addOption(Option.builder("input").argName("git(default) | files | filespair | repairability").hasArg()
.desc("format of the content present in the given -path. git implies that the path is a git repository. files implies the path contains .patch files ")
.build());
options.addOption(Option.builder("output").argName("path").hasArg()
.desc("dump the output of the analysis in the given path").build());
options.addOption(Option.builder("outputprocessor").argName("classname").hasArg()
.desc("output processors for result").build());
// Pattern mining
options.addOption(Option.builder("pattern").argName("path").hasArg()
.desc("path of the pattern file to be used when the -mode is \'mineinstance\'").build());
options.addOption(Option.builder("patternparser").argName("classname").hasArg()
.desc("parser to be used for parsing the file specified -pattern. Default is XML").build());
options.addOption("entitytype", true, "entity type to be mine");
options.addOption("entityvalue", true, "the value of the entity mentioned in -entitytype");
options.addOption(Option.builder("action").argName("INS | DEL | UPD | MOV | PER | ANY").hasArg()
.desc("tye of action to be mined").build());
options.addOption("parenttype", true, "parent type of the nodes to be considered");
options.addOption("parentlevel", true,
"numbers of AST node where the parent is located. 1 implies immediate parent");
options.addOption("hunkanalysis", true, "include analysis of hunks");
options.addOption("showactions", false, "show all actions");
options.addOption("showentities", false, "show all entities");
// Revision filter
options.addOption("filter", true, "name of the filter");
options.addOption("filtervalue", true, "values of the filter mentioned in -filter");
// In case of git
options.addOption(Option.builder("branch").argName("branch name").hasArg()
.desc("In case of -input=\'git\', use this branch name. Default is master.").build());
options.addOption("message", true, "comming message");
options.addOption("parameters", true, "Parameters, divided by " + File.pathSeparator);
// repairability module parameter
options.addOption(Option.builder("repairtool").argName(RepairTools.getCLISupportString()).hasArg().desc(
"If -mode=repairability, this option specifies which repair tools should we consider in our analysis. "
+ "Can be a list separated by " + File.pathSeparator)
.build());
options.addOption(Option.builder("processcomments").argName("true | false").hasArg()
.desc("Indicates if Coming considers code comments (inline, block, JavaDoc)").build());
}
public static void main(String[] args) {
ComingMain cmain = new ComingMain();
cmain.run(args);
}
RevisionNavigationExperiment> navigatorEngine = null;
@SuppressWarnings("rawtypes")
public FinalResult run(String[] args) {
boolean created = createEngine(args);
if (!created)
return null;
if (args.length == 0) {
help();
return null;
}
return start();
}
public FinalResult start() {
if (navigatorEngine == null)
throw new IllegalAccessError("error: initialize the engine first");
FinalResult result = navigatorEngine.analyze();
return result;
}
public boolean createEngine(String[] args) {
ComingProperties.reset();
CommandLine cmd = null;
this.navigatorEngine = null;
try {
cmd = parser.parse(options, args);
} catch (Exception e) {
logm.error("Error parsing command: " + e.getMessage());
// System.out.println("Error: " + e.getMessage());
help();
return false;
}
if (cmd.hasOption("help")) {
help();
return false;
}
if (cmd.hasOption("showactions")) {
System.out.println("---");
System.out.println("Actions available: ");
for (ActionType a : ActionType.values()) {
System.out.println(a);
}
System.out.println("---");
return false;
}
if (cmd.hasOption("showentities")) {
System.out.println("---");
System.out.println("Entities Type Available:");
System.out.println("---");
for (EntityTypeSpoon et : EntityTypeSpoon.values()) {
System.out.println(et);
}
System.out.println("---");
return false;
}
for (Option option : cmd.getOptions()) {
if (cmd.hasOption(option.getOpt())) {
String value = cmd.getOptionValue(option.getOpt());
ComingProperties.properties.setProperty(option.getOpt(), value);
}
}
if (cmd.hasOption("parameters")) {
String[] pars = cmd.getOptionValue("parameters").split(":");
if (pars.length % 2 != 0) {
throw new RuntimeException("The number of input parameters must be even.");
}
for (int i = 0; i < pars.length; i = i + 2) {
String key = pars[i];
String value = pars[i + 1];
ComingProperties.properties.setProperty(key, value);
}
}
String mode = ComingProperties.getProperty("mode");
String input = ComingProperties.getProperty("input");
// CONFIGURATION:
loadInput(input);
loadModelAnalyzers(mode);
loadFilters();
loadOutput();
return true;
}
private void loadFilters() {
List newFilters = createFilters();
if (newFilters != null && !newFilters.isEmpty()) {
if (navigatorEngine.getFilters() == null)
navigatorEngine.setFilters(newFilters);
else {
navigatorEngine.getFilters().addAll(newFilters);
}
}
}
private void loadOutput() {
String outputs = ComingProperties.getProperty("outputprocessor");
if (outputs == null) {
if (Boolean.valueOf(System.getProperty("executed_by_travis"))) {
navigatorEngine.getOutputProcessors().add(0, new NullOutput());
System.out.println("****EXECUTED_BY_TRAVIS****");
} else {
navigatorEngine.getOutputProcessors().add(0, new StdOutput());
System.out.println("**NOT_EXECUTED_BY_TRAVIS**");
}
} else {
loadOutputProcessors(outputs);
}
}
private void loadInput(String input) {
if (input == null || input.equals("git")) {
navigatorEngine = new GITRepositoryInspector();
} else if (input.equals("files")) {
navigatorEngine = new FileNavigationExperiment();
} else if (input.equals("filespair")) {
navigatorEngine = new FilesPairNavigation();
} else {
// extension point
navigatorEngine = loadInputEngine(input);
}
}
private void loadModelAnalyzers(String modes) {
String[] modesp = modes.split(":");
for (String mode : modesp) {
if ("diff".equals(mode)) {
navigatorEngine.getAnalyzers().clear();
navigatorEngine.getAnalyzers().add(new FineGrainDifftAnalyzer());
navigatorEngine.getOutputProcessors().add(new JSonChangeFrequencyOutput());
} else if ("mineinstance".equals(mode)) {
navigatorEngine.getAnalyzers().clear();
navigatorEngine.getAnalyzers().add(new FineGrainDifftAnalyzer());
List patterns = loadPattern();
// Determine instance matcher
if (ComingProperties.getPropertyBoolean("spreadPattern"))
navigatorEngine.getAnalyzers().add(new SpreadPatternInstanceAnalyzer(patterns));
else
// default
navigatorEngine.getAnalyzers().add(new PatternInstanceAnalyzer(patterns));
// By default JSON output of pattern instances
navigatorEngine.getOutputProcessors().add(new JSonPatternInstanceOutput());
} else if ("features".equals(mode)) {
navigatorEngine.getAnalyzers().clear();
navigatorEngine.getAnalyzers().add(new FineGrainDifftAnalyzer());
navigatorEngine.getAnalyzers().add(new FeatureAnalyzer());
navigatorEngine.getOutputProcessors().add(new FeaturesOutput());
} else if ("repairability".equals(mode)) {
navigatorEngine.getAnalyzers().clear();
navigatorEngine.getAnalyzers().add(new FineGrainDifftAnalyzer());
// prepares patterns required for PatternInstanceAnalyzer
RepairTools repairTools = new RepairTools();
List patterns = repairTools.getPatterns();
navigatorEngine.getAnalyzers().add(new PatternInstanceAnalyzer(patterns));
navigatorEngine.getAnalyzers().add(new RepairabilityAnalyzer());
navigatorEngine.getOutputProcessors().add(new JSONRepairabilityOutput());
} else {
// LOAD Analyzers from command
loadAnalyzersFromCommand(mode);
}
}
if (ComingProperties.getPropertyBoolean("hunkanalysis")) {
navigatorEngine.getAnalyzers().add(0, new HunkDifftAnalyzer());
}
}
private void loadAnalyzersFromCommand(String mode) {
try {
Object analyzerLoaded = PlugInLoader.loadPlugin(mode, Analyzer.class);
if (analyzerLoaded != null) {
navigatorEngine.getAnalyzers().add((Analyzer) analyzerLoaded);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void loadOutputProcessors(String output) {
String[] outputs = output.split(":");
for (String singlefoutput : outputs) {
try {
if (singlefoutput.equals("changefrequency")) {
navigatorEngine.getOutputProcessors().add(new JSonChangeFrequencyOutput());
} else {
Object outLoaded = PlugInLoader.loadPlugin(singlefoutput, IOutput.class);
if (outLoaded != null) {
navigatorEngine.getOutputProcessors().add((IOutput) outLoaded);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private RevisionNavigationExperiment> loadInputEngine(String input) {
Object loaded;
try {
loaded = PlugInLoader.loadPlugin(input, RevisionNavigationExperiment.class);
if (loaded != null) {
return (RevisionNavigationExperiment>) loaded;
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("We could not load input: " + input);
return null;
}
private List createFilters() {
List filters = new ArrayList();
String filterProperty = ComingProperties.getProperty("filter");
if (filterProperty == null || filterProperty.isEmpty())
return filters;
String[] filter = filterProperty.split(":");
for (String singlefilter : filter) {
if ("bugfix".equals(singlefilter)) {
filters.add(new BugfixKeywordsFilter());
} else if ("keywords".equals(singlefilter)) {
filters.add(new KeyWordsMessageFilter(ComingProperties.getProperty("filtervalue")));
} else if ("numberhunks".equals(singlefilter))
filters.add(new NbHunkFilter());
else if ("maxfiles".equals(singlefilter))
filters.add(new CommitSizeFilter());
else if ("withtest".equals(singlefilter))
filters.add(new ContainTestFilterFilter());
else {
IFilter filterLoaded = loadFilter(singlefilter);
if (filterLoaded != null) {
filters.add(filterLoaded);
}
}
}
return filters;
}
private IFilter loadFilter(String singlefilter) {
try {
Object filter = PlugInLoader.loadPlugin(singlefilter, IFilter.class);
if (filter != null) {
return (IFilter) filter;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private List loadPattern() {
String patternProperty = ComingProperties.getProperty("pattern");
List patternsFound = new ArrayList();
if (patternProperty != null) {
String[] patterns = patternProperty.split(File.pathSeparator);
// Load pattern from file
for (String pattern : patterns) {
File fl = new File(pattern);
if (fl.exists()) {
PatternFileParser patternParser = loadPatternParser();
ChangePatternSpecification patternParsed = patternParser.parse(fl);
patternsFound.add(patternParsed);
} else {
logm.error("The pattern file given as input does not exist " + fl.getAbsolutePath());
}
}
} else {
// Simple pattern
String actionProperty = ComingProperties.getProperty("action");
String entityTypeProperty = ComingProperties.getProperty("entitytype");
String entityValueProperty = ComingProperties.getProperty("entityvalue");
String parentTypeProperty = ComingProperties.getProperty("parenttype");
Integer parentlevelProperty = ComingProperties.getPropertyInteger("parentlevel");
ActionType at = ActionType.valueOf(actionProperty);
if (at != null && (entityTypeProperty != null || entityValueProperty != null)) {
ChangePatternSpecification cpattern = new ChangePatternSpecification();
PatternEntity affectedEntity = new PatternEntity(entityTypeProperty, entityValueProperty);
PatternAction pa = new PatternAction(affectedEntity, at);
if (parentTypeProperty != null) {
PatternEntity parentEntity = new PatternEntity(parentTypeProperty);
affectedEntity.setParent(parentEntity, parentlevelProperty);
}
cpattern.addChange(pa);
patternsFound.add(cpattern);
} else {
throw new IllegalAccessError("The pattern is not well specified: missing entitytype or entityvalue");
}
}
if (patternsFound.isEmpty()) {
throw new IllegalAccessError("Any valid pattern file in " + patternProperty);
}
return patternsFound;
}
public PatternFileParser loadPatternParser() {
String parser = ComingProperties.getProperty("patternparser");
if (parser == null || parser.equals("xmlparser")) {
return new PatternXMLParser();
} else {
try {
Object parserFile = PlugInLoader.loadPlugin(parser, PatternFileParser.class);
if (parserFile != null) {
return (PatternFileParser) parserFile;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
private static void help() {
HelpFormatter formater = new HelpFormatter();
formater.setWidth(500);
formater.printHelp("Main", options);
logm.info("More options and default values at 'config-coming.properties' file");
}
public RevisionNavigationExperiment> getExperiment() {
return navigatorEngine;
}
public void setExperiment(RevisionNavigationExperiment> experiment) {
this.navigatorEngine = experiment;
}
public void registerIntermediateCallback(IntermediateResultProcessorCallback callback) {
if (this.navigatorEngine == null)
throw new IllegalStateException("Please, initialize the engine first");
this.navigatorEngine.setIntermediateCallback(callback);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy