import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Akram Ben Aissi
*
*/
public class PHPCodeSnifferRulesExtractor {
private static final int SNIFF_DESCRIPTION_POSITION = 1;
private static final int SNIFF_LEVEL_POSITION = 2;
private static final int SNIFF_NAME_POSITION = 3;
private static final String $PHPCS_FILE_ADD_ERROR_OR_WARNING = "\\s*(.*)->add(Warning|Error)\\([^,]*, [^,]*, ([^,]*)(,[^,]*)*\\);";
private static final String $ERROR_DELIMITOR = "\\s*\\$error\\s*=(.*);";
private static final String ROOT_PATH = "D:\\tmp\\phpcs\\CodeSniffer\\Standards\\";
private static final String EXTENSION = "Sniff.php";
private static final String SNIFFS_DIRECTORY = ".Sniffs";
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
String l = " $phpcsFile->addWarning($error, $stackPtr, 'NotAllowed');";
Pattern p = Pattern.compile($PHPCS_FILE_ADD_ERROR_OR_WARNING);
Matcher matcher = p.matcher(l);
matcher.groupCount();
matcher.matches();
// matcher.group(0);
matcher.group(1);
matcher.group(2);
matcher.group(3);
// matcher.group(4);
// matcher.group(5);
String l2 = " $phpcsFile->addError($error, $stackPtr, 'NotAllowedWarning', $data);";
Matcher matcher2 = p.matcher(l);
matcher2 = p.matcher(l2);
matcher.groupCount();
matcher2.matches();
// matcher.group(0);
matcher2.group(1);
matcher2.group(2);
matcher2.group(3);
// matcher2.group(4);
// matcher2.group(5);
List<File> files = getSniffFiles(ROOT_PATH);
List<String> sniffs = extractSniffNames(files);
writeSniffsToFile("d:/tmp/all-phpcs-rules.csv", sniffs);
}
/**
* @param path
* @param sniffs
* @throws IOException
*/
static void writeSniffsToFile(String path, List<String> sniffs) throws IOException {
FileOutputStream stream = new FileOutputStream(path);
OutputStreamWriter streamWriter = new OutputStreamWriter(stream);
BufferedWriter writer = new BufferedWriter(streamWriter);
for (String sniff : sniffs) {
writer.write(sniff);
}
writer.close();
stream.close();
}
/**
* @param files
* @return
* @throws IOException
*/
static List<String> extractSniffNames(List<File> files) throws IOException {
List<String> sniffs = new ArrayList<String>();
String header = "key,priority,category,name,configKey,description\n";
sniffs.add(header);
Pattern descriptionPattern = Pattern.compile($ERROR_DELIMITOR);
Pattern addErrorPattern = Pattern.compile($PHPCS_FILE_ADD_ERROR_OR_WARNING);
for (File file : files) {
FileInputStream inputStream = new FileInputStream(file);
InputStreamReader streamReader = new InputStreamReader(inputStream);
BufferedReader reader = new BufferedReader(streamReader);
String prefix = file.getAbsolutePath().replace(ROOT_PATH, "").replace(EXTENSION, "");
prefix = prefix.replaceAll("\\\\", ".").replace(SNIFFS_DIRECTORY, "");
String line = reader.readLine();
while (line != null) {
Matcher descriptionMatcher = descriptionPattern.matcher(line);
if (descriptionMatcher.matches()) {
String description = clean(descriptionMatcher.group(SNIFF_DESCRIPTION_POSITION));
// On recherche la prochaine occurence de addError ou addWarning
Matcher sniffMatcher = addErrorPattern.matcher(line);
String key = "";
while ((line = reader.readLine()) != null && !sniffMatcher.matches()) {
sniffMatcher = addErrorPattern.matcher(line);
}
if (line != null) {
key = clean(sniffMatcher.group(SNIFF_NAME_POSITION));
}
String name = getName(prefix);
// key,priority,category,name,configKey,description
StringBuilder sniff = new StringBuilder(prefix).append(".").append(key).append(",");
String level = "MAJOR";
sniff.append(level).append(",");
sniff.append("Maintainability").append(",");
sniff.append(name).append(key).append(",");
sniff.append("rulesets/").append(name).append(",");
if ("".equals(description)) {
sniff.append("No description available");
}
sniff.append(description).append("\n");
sniffs.add(sniff.toString());
}
// Sin on est pas arriv� � la fin du fichier on recommence.
if (line != null) {
line = reader.readLine();
}
}
}
return sniffs;
}
/**
* @param prefix
* @return
*/
private static String getName(String prefix) {
String result = prefix.trim();
return result.substring(result.lastIndexOf(".") + 1);
}
private static String clean(String s) {
String result = s.trim();
return result.substring(1, result.length() - 1);
}
/**
* @param ROOT_PATH
* @return a recursively list of all directories contained in path
*/
static List<File> getSniffFiles(String rootPath) {
return getSniffFiles(rootPath, true);
}
/**
* @param ROOT_PATH
* @return a recursively list of all directories contained in path
*/
private static List<File> getSniffFiles(String rootPath, boolean start) {
List<File> files = new ArrayList<File>();
File root = new File(rootPath);
if ( !start && !root.isDirectory()) {
throw new RuntimeException("Path " + rootPath + " is not a directory");
}
for (File child : root.listFiles()) {
if (child.isDirectory()) {
List<File> sniffFiles = directoryContainsOnlySniffs(child);
if (sniffFiles != null) {
files.addAll(sniffFiles);
} else {
files.addAll(getSniffFiles(child.getAbsolutePath(), false));
}
}
}
return files;
}
/**
* @param child
* @return
*/
private static List<File> directoryContainsOnlySniffs(File child) {
List<File> files = new ArrayList<File>();
for (File file : child.listFiles()) {
if (file.isDirectory() || !file.getName().endsWith(EXTENSION)) {
return null;
}
files.add(file);
}
return files;
}
}