package application;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.vladsch.flexmark.html2md.converter.FlexmarkHtmlConverter;
import de.lcag.common.HashTable;
import de.lcag.common.Table.TableColumn;
import routines.LcagFileTools;
import routines.LcagLogger;
public class CommentExtractor {
private static final String BUGFIX_COMMAND = "BUGFIX_"; // Fix of a Agile Defect in Trackspace
private static final String STORY_COMMAND = "BUGFIX_"; // User Story in Trackspace to implement
private static final String HOW_TO_COMMAND = "HOWTO_";
private static final String DOCUMENT_FLOW_COMMAND = "FLOW_";
private static final String TODO_COMMAND = "TODO_";
private static final String[] COMMAD_LIST = new String[] { HOW_TO_COMMAND, DOCUMENT_FLOW_COMMAND, TODO_COMMAND,
BUGFIX_COMMAND, STORY_COMMAND };
private static final String COL_TYPE = "Type";
private static final String COL_ID = "Id";
private static final String COL_KIND = "Kind";
private static final String COL_STEP = "StepNo";
private static final String COL_DESC = "Description;style=width: 85%";
private static final String COL_FILE = "File";
private static final String COL_LINE_NO = "LineNo";
public static final String JAVA_CODE_BASE_PATH = "/workspace/ebx_lufthansa/ebx_lufthansa-lib/src/main/java/com/lufthansa/ebx";
public static final String SQL_CODE_BASE_PATH = "/workspace/ebx_lufthansa/ebx_lufthansa-resources/src/main/sql";
public static final String XSD_CODE_BASE_PATH = "/workspace/MDM-Datamodel";
public static final String JAVA_CODE_BASE_FULLPATH = "V:/EBX" + JAVA_CODE_BASE_PATH;
public static final String SQL_CODE_BASE_FULLPATH = "V:/EBX" + SQL_CODE_BASE_PATH;
public static final String XSD_CODE_BASE_FULLPATH = "V:/EBX" + XSD_CODE_BASE_PATH;
public static final String CODE_BASE_GITHUB_DIR = "https://dev.azure.com/LCAGDevOps/MDM/_git/EBX?path=%s&version=GB%s&line=%d&lineEnd=%d&lineStartColumn=1&lineEndColumn=1&lineStyle=plain&_a=contents";
public static final String DOC_FILE = "V:/EBX/workspace/ebx_lufthansa/ebx_lufthansa-lib/HowToImplement";
private static HashTable resultTable = new HashTable(COL_TYPE, COL_ID, COL_KIND, COL_STEP, COL_DESC, COL_FILE,
COL_LINE_NO);
private static String gitBranchName = "main";
private static LcagLogger logger = LcagLogger.getLogger(CommentExtractor.class);
public static void main(String[] args) {
String rootDirPath;
logger.setJavaLogLevel(LcagLogger.LOG_TRACE);
if (args.length < 1) {
rootDirPath = JAVA_CODE_BASE_FULLPATH;
logger.info("Using default Root directory to scan code: %s", rootDirPath);
} else {
rootDirPath = args[0];
}
try {
gitBranchName = getCurrentGitBranch();
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
resultTable.setName("MDM EBX Coding HowTo");
try {
extractCodeExamples(rootDirPath);
TableColumn sortedResults = resultTable.sort(COL_ID, COL_STEP);
String txt = resultTable.asCSV(sortedResults);
String fileName = DOC_FILE + ".csv";
LcagFileTools.writeTextFile(fileName, txt);
writeHtmlFile(sortedResults);
System.out.println(String.format("Saved Code examples to file: %s", DOC_FILE));
} catch (IOException e) {
logger.error("Error reading file: %s", e.getMessage());
}
}
private static void writeHtmlFile(TableColumn sortedResults) throws IOException {
String fileName = DOC_FILE + ".html";
for (int i = 0; i < resultTable.lenght(); i++) {
int lineNo = (int) resultTable.getCellValue(i, COL_LINE_NO);
String colId = (String) resultTable.getCellValue(i, COL_ID);
String filePath = (String) resultTable.getCellValue(i, COL_FILE);
String gitURL = String.format(CODE_BASE_GITHUB_DIR, filePath, gitBranchName, lineNo, lineNo + 1);
String lineNoURL = String.format("%d", gitURL, lineNo);
if (filePath.endsWith(".java")) {
filePath = filePath.substring(JAVA_CODE_BASE_PATH.length() + 1);
} else if (filePath.endsWith(".sql")) {
filePath = filePath.substring(SQL_CODE_BASE_PATH.length() + 1);
} else if (filePath.endsWith(".xsd")) {
filePath = filePath.substring(XSD_CODE_BASE_PATH.length() + 1);
}
resultTable.setCellValue(i, COL_FILE, filePath);
resultTable.setCellValue(i, COL_LINE_NO, lineNoURL);
String kind = (String) resultTable.getCellValue(i, COL_KIND);
if (kind.equals("Title")) {
String disc = String.format("%s", (String) resultTable.getCellValue(i, COL_DESC));
resultTable.setCellValue(i, COL_DESC, disc);
// For BUGFIX or STORY: Add link into trackspace:
String digits = colId.replaceAll(".*[BS](\\d+).*", "$1"); // Extract digits after 'B'
if (!Objects.equals(colId, digits)) {
String htmlLink = "" + colId + "";
resultTable.setCellValue(i, COL_ID, htmlLink);
}
}
}
String txt = resultTable.asHTML(sortedResults);
LcagFileTools.writeTextFile(fileName, txt);
String md = FlexmarkHtmlConverter.builder().build().convert(txt);
String mdFileName = DOC_FILE + ".md";
LcagFileTools.writeTextFile(mdFileName, md);
}
public static String getCurrentGitBranch() throws IOException, InterruptedException {
Process process = Runtime.getRuntime().exec("git rev-parse --abbrev-ref HEAD");
process.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
return reader.readLine();
}
private static void extractCodeExamples(String pRootDirPath) throws IOException {
List fileList = LcagFileTools.findFilesWithExtension(pRootDirPath, ".java");
final List sqlFileList = LcagFileTools.findFilesWithExtension(SQL_CODE_BASE_FULLPATH, ".sql");
final List xsdFileList = LcagFileTools.findFilesWithExtension(XSD_CODE_BASE_FULLPATH, ".xsd");
fileList.addAll(xsdFileList);
fileList.addAll(sqlFileList);
for (File javaFile : fileList) {
String filename = javaFile.getName();
BufferedReader reader = new BufferedReader(new FileReader(javaFile));
StringBuilder currentComment = new StringBuilder();
boolean inMultilineComment = false;
boolean inSingleLineComment = false;
String line;
int lineNo = 0;
int commentStartLineNo = 0;
logger.trace("Processing file %s...", filename);
while ((line = reader.readLine()) != null) {
lineNo += 1;
line = line.trim();
final boolean singleLineComment = line.startsWith("//") /* java */ || line.startsWith("--") /* SQL */;
if (!inMultilineComment && singleLineComment) {
final String comment = line.substring(2).trim();
inSingleLineComment = true;
} else if (line.startsWith("/*") /* java */ || line.startsWith("") /* xml */ )) {
String comment = line.endsWith("*/") ? line.substring(0, line.length() - 2)
: line.substring(0, line.length() - 3);
if (isFirstLineInComment) {
comment = currentComment.toString().trim();
comment = comment.endsWith("*/") ? comment.substring(0, comment.length() - 2)
: comment.substring(0, comment.length() - 3);
} else {
currentComment.append(" ").append(comment.trim());
comment = currentComment.toString().trim();
}
parseComment(comment, javaFile, lineNo);
inMultilineComment = false;
commentStartLineNo = 0;
currentComment.setLength(0);
} else if (inMultilineComment && !isFirstLineInComment) {
if (line.startsWith("*"))
line = line.substring(1).trim();
currentComment.append(" ").append(line);
}
}
reader.close();
}
}
private static void parseComment(String pComment, File pInFile, int pLineNo) {
String command = null;
String type = null;
String regEx = String.join("|", COMMAD_LIST);
Pattern pattern = Pattern.compile(regEx);
Matcher matcher = pattern.matcher(pComment);
List cmdList = new ArrayList<>();
List startPositionList = new ArrayList<>();
while (matcher.find()) {
final int start = matcher.start();
String cmd = matcher.group();
cmdList.add(cmd);
startPositionList.add(start);
}
if (cmdList.isEmpty())
return;
for (int n = 0; n < cmdList.size(); n++) {
String cmd = cmdList.get(n);
int start = startPositionList.get(n);
int end = 0;
if (n == cmdList.size() - 1) {
end = pComment.length();
} else {
String nextCmd = (String) cmdList.get(n + 1);
end = startPositionList.get(n + 1);
}
start += cmd.length();
command = pComment.substring(start, end);
// FIXME: Problem if comment text also includes "_"
command = command.replace("_", ";");
command = command.replaceFirst(":", ";");
List split = new ArrayList<>(Arrays.asList(command.split(";")));
if (split.size() < 2) {
logger.warn("Unexpected HowTo format '%s', should be '%s H: [Title:|.] ",
pComment, cmd);
return;
}
type = cmd.substring(0, cmd.length() - 1);
String id = split.remove(0);
String kind = split.remove(0).trim();
String descr = String.join(" ", split).trim();
String absoluteSourceCodeFilePath = pInFile.getAbsolutePath();
absoluteSourceCodeFilePath = absoluteSourceCodeFilePath.replace("\\", "/");
absoluteSourceCodeFilePath = absoluteSourceCodeFilePath.replaceFirst("V:/EBX", "");
String stepNoStr = "00";
if (!"Title".equals(kind)) {
stepNoStr = kind.replace("Step", "");
kind = "Step";
}
int rowNo = resultTable.newRow();
resultTable.setCellValue(rowNo, COL_TYPE, type);
resultTable.setCellValue(rowNo, COL_ID, id);
resultTable.setCellValue(rowNo, COL_KIND, kind);
resultTable.setCellValue(rowNo, COL_STEP, stepNoStr);
resultTable.setCellValue(rowNo, COL_FILE, absoluteSourceCodeFilePath);
resultTable.setCellValue(rowNo, COL_LINE_NO, pLineNo);
resultTable.setCellValue(rowNo, COL_DESC, descr);
}
}
}